PL/Rust Functions
PL/Rust functions are created with the standard
CREATE FUNCTION
syntax and LANGUAGE plrust
.
This section provides examples how to create a variety
of function using PL/Rust.
The basic function structure is shown in the following example.
CREATE FUNCTION funcname (argument-list)
RETURNS return-type
-- function attributes can go here
AS $$
# PL/Rust function body goes here
$$ LANGUAGE plrust;
The body of the function is ordinary
Rust code. When the CREATE FUNCTION
is ran the Rust code is
complied using the pgrx
framework.
This compile process can take a bit of time.
The compile time required is one reason anonymous blocks (DO
blocks)
are not supported at this time.
The syntax of the CREATE FUNCTION
command requires the function
body to be written as a string constant. It is usually most convenient
to use dollar quoting ($$
, see Section 4.1.2.4)
for the string constant. If you choose to use escape string syntax
E''
, you must double any single quote marks (') and
backslashes () used in the body of the function (see
Section 4.1.2.1).
Basic PL/Rust Example
The following example creates a basic plrust
function named
plrust.one()
to simply returns the integer 1
.
CREATE OR REPLACE FUNCTION plrust.one()
RETURNS INT
LANGUAGE plrust
AS
$$
Ok(Some(1))
$$
;
Function with parameters
The following example creates a function named plrust.strlen
that accepts one parameter named val
. The function returns a BIGINT
representing the length of the text in val
. The variable names
defined in the function definition can be used directly in the Rust
code within the function's body.
CREATE OR REPLACE FUNCTION plrust.strlen(val TEXT)
RETURNS BIGINT
LANGUAGE plrust
AS $$
Ok(Some(val.unwrap().len() as i64))
$$;
Using the strlen()
function works as expected.
SELECT plrust.strlen('Hello, PL/Rust');
┌────────┐
│ strlen │
╞════════╡
│ 14 │
└────────┘
The plrust.strlen
function above used unwrap()
to parse the
text variable. Changing the function definition to include STRICT
avoids the need to use unwrap()
. The following version
of plrust.strlen
works the same as above.
CREATE OR REPLACE FUNCTION plrust.strlen(val TEXT)
RETURNS BIGINT
LANGUAGE plrust STRICT
AS $$
Ok(Some(val.len() as i64))
$$;
Functions with anonymous parameters not allowed
PL/Rust functions with parameters require named parameters.
This is different from functions written in other languages,
such as SQL where strlen(TEXT, INT)
allows the use of
$1
and $2
within the function body.
https://www.postgresql.org/docs/current/sql-createfunction.html
The succinct reason anonymous parameters are not allowed is because "It does not align with Rust." Requiring named parameters keeps functionality simple, direct and obvious.
One of the reasons people use Rust is because of the quality of the compiler's feedback on incorrect code. Allowing anonymous parameters would ultimately require transforming the code in a way that would either result in potentially garbled error messages, or arbitrarily restricting what sets of identifiers can be used. Simply requiring identifiers skips all of that.
Calculations
PL/Rust functions can performance calculations, such as converting distance values from feet to miles.
CREATE OR REPLACE FUNCTION plrust.distance_feet_to_miles(feet FLOAT)
RETURNS FLOAT
LANGUAGE plrust STRICT
AS $$
Ok(Some(feet / 5280.0))
$$;
Using the function.
SELECT plrust.distance_feet_to_miles(10000);
┌────────────────────────┐
│ distance_feet_to_miles │
╞════════════════════════╡
│ 1.893939393939394 │
└────────────────────────┘
Use dependencies
One of the powerful features of plrust
is its ability to define dependencies
in the function. The following examples use the
faker_rand
crate
in functions to generate fake text data.
The random_first_name()
function returns a random first name using the
en_us
locale.
CREATE OR REPLACE FUNCTION plrust.random_slogan() RETURNS TEXT
LANGUAGE plrust AS $$
[dependencies]
faker_rand = "0.1"
rand = "0.8"
[code]
use faker_rand::en_us::company::Slogan;
Ok(Some(rand::random::<Slogan>().to_string()))
$$;
SELECT plrust.random_slogan();
┌─────────────────────────────┐
│ random_slogan │
╞═════════════════════════════╡
│ Ergonomic composite schemas │
└─────────────────────────────┘
CREATE OR REPLACE FUNCTION plrust.random_company_name(locale TEXT)
RETURNS TEXT
LANGUAGE plrust STRICT
AS $$
[dependencies]
faker_rand = "0.1"
rand = "0.8"
[code]
match locale {
"en_us" => {
use faker_rand::en_us::company::CompanyName;
Ok(Some(rand::random::<CompanyName>().to_string()))
}
"fr_fr" => {
use faker_rand::fr_fr::company::CompanyName;
Ok(Some(rand::random::<CompanyName>().to_string()))
}
_ => panic!("Unsupported locale. Use en_us or fr_fr")
}
$$;
SELECT plrust.random_company_name('en_us') AS en_us,
plrust.random_company_name('fr_fr') AS fr_fr;
┌────────────┬───────────────┐
│ en_us │ fr_fr │
╞════════════╪═══════════════╡
│ Furman Inc │ Élisabeth SEM │
└────────────┴───────────────┘