Co-founder of DALIBO, leading Postgres company in France since 2005
Active member of the French PostgreSQL community
Main developer of the PostgreSQL Anonymizer extension
I discovered Postgres 25 years ago
I discovered Rust last year
In 2018, I started a project called PostgreSQL Anonymizer
Over the years, I wrote more and more C code…
Last year, I rewrote everything in Rust
This is my story :)
More than 1000 known extensions
… almost 250 are active and maintained
Some SQL objects
and/or Procedural Language ( PL ) code
and/or a compiled library
Easy
A great way to share code between several databases
Very stable between major versions
Slow
PL/pgsql | PL/perl | PL/php | PL/Ruby | PL/Java |
PL/Scheme | PL/tcl | PL/Lua | PL/python | PL/haskell |
PL/Rust | PL/dotnet | PL/lolcode | PL/Julia | PL/sh |
PL/XSLT | PL/R | PL/v8 | PL/go | PL/brainfuck |
It’s great
We’re not going to talk about it today :)
Generaly loaded when the instance starts
Fast and Direct access to the internal functions
Very low-level code / No Abstractions
Each new major version will probably break your extension
The dev/test framework (PGXS) is very limited
Absolutely no security barrier => segfaults fest
if the extension crashes, the entire Postgres instance will crash too
if the extension crashes,
the entire Postgres instance will crash too
Safety of PL functions AND Performances of C
High Level Abstractions AND Access to Postgres internals
A modern language AND Stability
A framework that bridges the gap between rust and postgres
You can write Rust extensions without it
But it makes your life easier !
Expose your rust functions as user functions inside postgres
Automatic mapping postgres data types into rust types
… and vice versa
postgres | rust |
---|---|
BYTEA | Vec<u8> or &u8 |
TEXT | String or &str |
INTEGER | i32 |
DATE | pgrx::Date |
DATERANGE | pgrx::Range<pgrx::Date> |
NULL | Option::None |
Derive attributes and macros to export Rust functions in SQL
Rust abstractions over Postgres pointers
(pgBox<T>
)
Helpers to exchange memory with Postgres
Safe access to the Server Programming Interface (SPI)
Any Rust panic!
is translated into a Postgres
ERROR
If the extension crashes
An ERROR event is raised into Postgres
The transaction is cancelled (ROLLBACK)
The current session lives on
The Postgres instances survives
A fully managed development environment ( cargo-pgrx
)
All major versions are supported
An idiomatic Rust Test framework
A very nice development feedback loop
Easy commands to build and ship packages
Project launched by a single company (TCDI
)
Transfered last year to the pgcentral foundation
A friendly Discord channel for beginners
cargo install --locked cargo-pgrx
cargo pgrx init
cargo pgrx new world
cd world
cargo pgrx run
cargo pgrx run
PG_FUNCTION_INFO_V1( hello );
Datum hello( PG_FUNCTION_ARGS ) {
char hello[] = "Hello, ";
text * name;
int hellolen;
int namelen;
text * msg;
name = PG_GETARG_TEXT_P(0);
hellolen = strlen(hello);
namelen = VARSIZE(name) - VARHDRSZ;
msg = (text *)palloc( hellolen + namelen );
SET_VARSIZE(hello, hellolen + namelen + VARHDRSZ );
strncpy( VARDATA(msg), hello, hellolen );
strncpy( VARDATA(msg) + hellolen, VARDATA(name), namelen );
PG_RETURN_TEXT_P( msg );
}
The Canadian
Social Insurance Number (SIN) is composed of
8 digits + 1 control digit
046 454 286
The control digit is computed using the Luhn Formula
luhn("046 454 28") = 6
cargo add luhn3
cargo pgrx run
cargo pgrx test
[...]
test tests::pg_test_luhn_checksum ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out;
finished in 5.26s
cargo pgrx test pg14
fn output(&self, buffer: &mut pgrx::StringInfo) {
use luhn3::decimal::checksum;
let part1 = self.0 / 100000 % 1000;
let part2 = self.0 / 100 % 1000;
let part3 = self.0 % 100;
let part4 = checksum(&self.0.to_string().into_bytes())
.expect("Checksum Failed")
as char;
let val = format!("{part1:03} {part2:03} {part3:02}{part4}");
buffer.push_str(val.as_str());
}
cargo pgrx run
You can also interact with the database engine itself !
A data masking extension for PostgreSQL
I’ll talk about it tomorow at 15h00 in the Postgres devroom (UA2.220)
About 1000 lines of C code
Rewrote everything in a few weeks, without prior knowledge of Rust
There’s some unspoken familiarity between Postgres and Rust
The Rust compiler is dull and rough at the beginning
But once you climbed that learning curse, you’re rewarded
…. pretty much like Postgres :)
Confort of development
Dozens of unit tests => many bugs found along the way
Better performance by rewriting some PL/pgSQL in Rust
Using high level Rust crates ( faker-rs
,
image
)
Stability ( « no more segfaults ! » )
In Rust a variable is never NULL
!
Some Postgres internal macros and some bindings are missing
Handling 2 memory contexts at once
A lot of sections in the code are still
unsafe
Building is very very slow (about 20x slower than C)
No support de Windows at the moment
For advanced features, I still need to read and understand the Postgres C code
Bring back your code close to the data
Define your own types !
Use Postgres as a platform
Rust extensions are a great entrypoint to the Postgres community
PGRX
https://github.com/pgcentralfoundation/pgrx
A 4 hour tutorial
https://daamien.gitlab.io/pgrx-tuto/
Try out PostgreSQL Anonymizer !