|
| 1 | +# External Dependencies |
| 2 | + |
| 3 | +PL/Rust supports the use of external dependencies. By default, this is unrestricted even when PL/Rust is used as a |
| 4 | +Trusted Language Handler, allowing user functions to specify any desired dependency. |
| 5 | + |
| 6 | +For instance: |
| 7 | + |
| 8 | +```sql |
| 9 | +CREATE OR REPLACE FUNCTION randint() RETURNS bigint LANGUAGE plrust AS $$ |
| 10 | +[dependencies] |
| 11 | +rand = "0.8" |
| 12 | + |
| 13 | +[code] |
| 14 | +use rand::Rng; |
| 15 | +Ok(Some(rand::thread_rng().gen())) |
| 16 | +$$; |
| 17 | +``` |
| 18 | + |
| 19 | +It is recommended that administrators create a dependency allow-list file and specify its path in `postgresql.conf` using |
| 20 | +the `plrust.allowed_dependencies` setting. |
| 21 | + |
| 22 | +To disable external dependencies completely, create a zero-byte file or point the configuration to `/dev/null`. |
| 23 | + |
| 24 | +## The Allow-List File |
| 25 | + |
| 26 | +The dependency allow-list is a TOML file. Its format mirrors that of the `[dependencies]` section in a standard |
| 27 | +`Cargo.toml`, albeit with certain requirements on the version strings. |
| 28 | + |
| 29 | +### The Format |
| 30 | + |
| 31 | +The file consists of `dependency_name = version_requirement` pairs, where `version_requirement` can adopt several forms. |
| 32 | +It can be a quoted string such as `"=1.2.3"`, a TOML table like `{ version = "=1.2.3", features = ["a", "b", "c"] }`, or |
| 33 | +an array of either, such as `[ "=1.2.3", { version = "=1.2.3" }, ">=4, <5"`. |
| 34 | + |
| 35 | +Here is a valid allow-list file for reference: |
| 36 | + |
| 37 | +```toml |
| 38 | +rand = ">=0.8, <0.9" |
| 39 | +bitvec = [">=1, <2", "=0.2", { version = "1.0.1", features = [ "alloc" ], default-features = false }] |
| 40 | +``` |
| 41 | + |
| 42 | +This added flexibility empowers administrators to specify the exact crate version and its associated features and properties. |
| 43 | + |
| 44 | +When a `LANGUAGE plrust` function designates a dependency and version, the largest (presumably most recent) matching |
| 45 | +version from the allow-list is used. |
| 46 | + |
| 47 | +### Version Requirement Format |
| 48 | + |
| 49 | +PL/Rust employs Cargo's interpretation of semver to manage dependency versions, but it requires each version requirement |
| 50 | +to be an exact value like `=1.2.3`, a bounded range such as `>=1, <2`, or a bare wildcard (`*`). |
| 51 | + |
| 52 | +For example, these are valid version requirement values: |
| 53 | + |
| 54 | +```toml |
| 55 | +rand = "=0.8.5" |
| 56 | +serde = ">=1.0.151, <1.1" |
| 57 | +bitvec = "*" |
| 58 | +``` |
| 59 | + |
| 60 | +These, however, are not: |
| 61 | + |
| 62 | +```toml |
| 63 | +rand = "0.8.5" |
| 64 | +serde = ">1.1" |
| 65 | +``` |
| 66 | + |
| 67 | +The `cargo` tool may select a slightly different version based on the specification. However, with exact and bounded |
| 68 | +values, `cargo`'s choices are limited to the versions that administrators allow. |
| 69 | + |
| 70 | +The bare wildcard pattern (`*`) is acceptable and has a unique interpretation within a user `LANGUAGE plrust` function. |
| 71 | + |
| 72 | +### Using a Dependency |
| 73 | + |
| 74 | +As shown above, a `LANGUAGE plrust` function can include a `[dependencies]` section. Authors should specify exact versions |
| 75 | +for each dependency. PL/Rust will match this exact version with an entry in the allow-list. |
| 76 | + |
| 77 | +If a function requests a version in the `1.2.3` format and it matches an entry on the allow-list, PL/Rust will revise |
| 78 | +it to an exact version, i.e., `=1.2.3`. |
| 79 | + |
| 80 | +If the allow-list merely contains a wildcard version: |
| 81 | + |
| 82 | +```toml |
| 83 | +rand = "*" |
| 84 | +``` |
| 85 | + |
| 86 | +... and the user function asks for a specific version, such as `0.8.5`, PL/Rust will utilize that exact version. |
| 87 | + |
| 88 | +Conversely, if the allow-list specifies one or more particular version requirements... |
| 89 | + |
| 90 | +```toml |
| 91 | +rand = [ "0.8.5", "0.6" ] |
| 92 | +``` |
| 93 | + |
| 94 | +... and the PL/Rust function requests a wildcard (i.e., `rand = "*"`), PL/Rust will select the largest version requirement |
| 95 | +from the allow-list. In this case, it would be `0.8.5`. |
| 96 | + |
| 97 | +### Working with Crate Features |
| 98 | + |
| 99 | +When a user function employs a crate from the allow-list, the allow-list controls the permitted set of dependency properties |
| 100 | +such as `features` and `default-features` for each version. Users cannot override these. They can specify them, but the |
| 101 | +specifications must match exactly with the allow-list. |
| 102 | + |
| 103 | +This control enables administrators to dictate the usage of dependencies. |
| 104 | + |
| 105 | +For instance, this would be acceptable for a user function: |
| 106 | + |
| 107 | +```sql |
| 108 | +CREATE OR REPLACE FUNCTION randint(seed bigint) RETURNS bigint STRICT LANGUAGE plrust AS $$ |
| 109 | +[dependencies] |
| 110 | +rand = { version = "*", features = [ "small_rng" ], default-features = false } |
| 111 | + |
| 112 | +[code] |
| 113 | +use rand::rngs::SmallRng; |
| 114 | +use rand::SeedableRng; |
| 115 | +use rand::RngCore; |
| 116 | + |
| 117 | +let mut rng = SmallRng::seed_from_u64(seed as _); |
| 118 | +Ok(Some(rng.next_u64() as _)) |
| 119 | +$$; |
| 120 | +``` |
| 121 | + |
| 122 | +Provided that the allow-list includes the following: |
| 123 | + |
| 124 | +```toml |
| 125 | +rand = { version = "=0.8.5", features = [ "small_rng" ], default-features = false } |
| 126 | +``` |
| 127 | + |
| 128 | +Note that the user function could omit the dependency features since the allow-list declares them: |
| 129 | + |
| 130 | +```sql |
| 131 | +CREATE OR REPLACE FUNCTION randint(seed bigint) RETURNS bigint STRICT LANGUAGE plrust AS $$ |
| 132 | +[dependencies] |
| 133 | +rand = "*" |
| 134 | + |
| 135 | +[code] |
| 136 | +use rand::rngs::SmallRng; |
| 137 | +use rand::SeedableRng; |
| 138 | +use rand::RngCore; |
| 139 | + |
| 140 | +let mut rng = SmallRng::seed_from_u64(seed as _); |
| 141 | +Ok(Some(rng.next_u64() as _)) |
| 142 | +$$; |
| 143 | +``` |
| 144 | + |
| 145 | +### Operational Notes |
| 146 | + |
| 147 | +- The dependency allow-list file path must be set in `plrust.allowed_dependencies` GUC value in `postgresql.conf`. |
| 148 | +- The file must be readable by the user that runs Postgres backend connections. Typically, this user is named `postgres`. |
| 149 | +- Every time a `CREATE FUNCTION ... LANGUAGE plrust` statement is executed, the file is read, parsed, and validated. This arrangement allows administrators to edit it without needing to restart the Postgres cluster. |
0 commit comments