Eymoutiers, le 20 septembre 2024
Nous lançons ici une nouvelle série d’articles dédiés au développement d’extensions PostgreSQL en général et au framework PGRX en particulier. Chaque article sera conçu comme un mini-atelier avec des rappels théoriques, des objectifs, un exemple concret et des exercices optionnels pour les lectrices et lecteurs qui veulent aller plus loin !
On démarre avec un classique “Hello World” !
Objectifs
Dans cette première partie, nous avons les objectifs suivants:
- Initialiser un environnement de développement PGRX
- Créer une extension minimaliste
- Lancer l’extension dans une instance Postgres
Démarrage
Astuce: On peut éviter d’installer Rust et PGRX de manière permanente sur la machine hôte, pour cela voir directement le chapitre suivant Démarrage avec Docker
Avant toutes choses, nous allons installer le framework PGRX. Pour cela, il faut au préalable mettre en place Rust (par exemple avec l’installateur rustup).
Une fois que Rust
et cargo
sont installés, on lance l’installation
de PGRX et l’initialisation de l’environnement de développement :
cargo install --locked cargo-pgrx
cargo pgrx init
Suivant la puissance de la machine hôte, cette étape peut être longue (5 à 30 minutes). Elle est va également consommer beaucoup d’espace disque (environ 4Go).
Démarrage avec Docker
Ce chapitre remplace le précédent :)
Vous pouvez directement réaliser les exemples ci-dessous en vous connectant à une machine docker préparée spécialement à cet effet :
docker run -it --volume `pwd`:/pgrx daamien/pgrx
Bonjour le monde
On peut maintenant créer une extension nommée world
avec :
cargo pgrx new world
Un nouveau dossier world
vient d’apparaître et contient le
strict nécessaire pour générer une extension Postgres, notamment
un fichier source (src/lib.rs
) qui contient la fonction
suivante hello_world
:
#[pg_extern]
fn hello_world() -> &'static str {
"Hello, world"
}
La fonction retourne une valeur statique de type str
(appelé slice de chaînes
de caractères
) qui représente simplement une suite de caractères UTF-8. Cette
valeur de retour sera automatiquement convertie en type TEXT
pour Postgres.
Grâce à PGRX, tous les types essentiels de Postgres sont automatiquement convertis en type Rust. La liste complète des conversions est disponible ci-dessous :
https://github.com/pgcentralfoundation/pgrx#mapping-of-postgres-types-to-rust
Lancer l’extension
PGRX va maintenant pouvoir lancer une instance Postgres, charger cette nouvelle extension, créer une base de test et ouvrir une session de travail dessus :
cd world
cargo pgrx run
Une fois la compilation effectuée, nous voici connecté⋅es à une instance Postgres ! Nous pouvons directement créer et tester notre nouvelle extension.
world=# CREATE EXTENSION world;
CREATE EXTENSION
world=# SELECT hello_world();
hello_world
--------------
Hello, world
(1 row)
Difficile de faire plus simple, non ?
Ajouter une nouvelle fonction
Dans le fichier world/src/lib.rs
, on peut ajouter autant de nouvelles
fonctions que nécessaire.
Par exemple, créons une fonction qui prend un paramètre en entrée :
#[pg_extern]
fn hello(name: &str) -> String {
format!("Hello, {name}")
}
Note: Par facilité, on utilise ici le type
String
plutot que&str
pour la valeur de retour… Le type String sera également converti en type TEXT pour Postgres
Lançons à nouveau l’extension :
cargo pgrx run
Cette fois, seul le module
world
est recompilé !
Une fois dans la nouvelle session psql ouverte, on recharge l’extension :
world=# DROP EXTENSION world;
world=# CREATE EXTENSION world;
Et la nouvelle fonction est disponible :
world=# SELECT hello('Bob');
hello
------------
Hello, Bob
(1 row)
Écrire la même chose en C ?
En guise de comparaison, voici 2 extensions similaires écrites en langage C :
https://github.com/magnusp/pg_hello/blob/master/pg_hello.c
https://github.com/petr-korobeinikov/postgresql-extension-example/blob/master/hello_ext/hello_ext.c
Pour aller plus loin…
Voici quelques propositions d’activités pour poursuivre la découverte :
-
En utilisant la macro panic!, créer une fonction
hello2()
qui renvoie une erreur si la variablename
est vide. -
En utilisant la commande match, dites “Bonjour” si le nom Pierre et “Hola” si le nom est Diego ou Maya.
Un exemple d’implémentation est disponible sur :
https://gitlab.com/daamien/pgrx-notebook/-/blob/main/world/src/lib.rs
Bilan
En quelques minutes, on a pu créer une extension Postgres pour écrire et tester des fonctions internes.
Si l’on fait la comparaison avec le framework classique de développement d’extensions en C ( PGXS ), on remarque déjà plusieurs avantages clairs :
- La création de l’environnement de développement est automatisée
- La création de nouvelles fonctions est très simple
- Tous les types de base Postgres sont automatiquement convertis
- La manipulation des chaînes de caractères est bien plus souple en Rust
La suite au prochain épisode !
Jusqu’où Rust nous mènera-t-il ? Rendez-vous dans l’épisode #2 pour le savoir !
PS: Cet article a été rédigé sans l’assistance d’une intelligence artificielle.