Enfin une API SQL pour obtenir le DDL d'une base — sans appeler pg_dump
Pendant trente ans, la réponse à la question «Comment obtenir le DDL d'un objet PostgreSQL ?» a toujours été la même : lancer pg_dump -s depuis un shell et passer le résultat à la moulinette. Outils de migration, utilitaires de diff de schéma, ORM qui introspectent une base live — tous ont soit invoqué pg_dump, soit réécrit leur propre logique de parcours des catalogues système. Souvent les deux.
C'est en train de changer. Un commit du 5 avril 2026 (patch principal d'Akshay Joshi, co-auteur Euler Taveira, intégré par Andrew Dunstan) introduit la première brique du programme «Retail DDL» : pg_get_database_ddl(). La promesse : obtenir les instructions DDL d'une base de données directement depuis SQL, sans quitter votre session psql ni votre application Symfony.
Source originale : Christophe Pettus — Retail DDL Arrives, One Function at a Time
Ce que fait pg_get_database_ddl()
La signature de la fonction est la suivante :
pg_get_database_ddl(regdatabase, VARIADIC text[])
Elle retourne un ensemble de lignes contenant les instructions nécessaires pour recréer une base de données :
- Première ligne : le
CREATE DATABASEavec ses paramètres. - Lignes suivantes : les éventuels
ALTER DATABASEcomplémentaires.
Les options sont passées sous forme de paires nom/valeur en paramètres variadiques :
| Option | Type | Effet |
|---|---|---|
pretty |
boolean | Indentation lisible du DDL |
owner |
boolean | Inclure la clause OWNER |
tablespace |
boolean | Inclure la clause TABLESPACE |
Exemple d'appel
-- DDL complet de la base courante, avec owner et tablespace
SELECT *
FROM pg_get_database_ddl(
current_database()::regdatabase,
'pretty', 'true',
'owner', 'true',
'tablespace', 'true'
);
Permissions requises
L'appelant doit disposer du privilège CONNECT sur la base cible. Rien de plus — ce qui la rend utilisable depuis un rôle applicatif dédié sans droits superutilisateur.
-- Vérifier les permissions avant d'appeler
SELECT has_database_privilege(current_user, 'myapp_production', 'CONNECT');
Ce que cette fonction n'est PAS
Avant d'aller plus loin, soyons clairs sur les limites — et elles sont importantes.
pg_get_database_ddl() ne remplace pas pg_dump. Voici pourquoi :
pg_dumpproduit un fichier SQL complet et exécutable, gère les dépendances croisées entre objets, respecte la propriété des extensions, et traite des dizaines de cas limites accumulés en dix ans de production réelle.pg_get_database_ddl()sérialise un seul objet — la base de données elle-même — avec des sémantiques claires pour owner et tablespace, et rien d'autre.
⚠️ Ne substituez pas cette fonction à pg_dump dans un pipeline de backup. Vous perdriez les données, les tables, les indexes, les fonctions, les extensions — tout.
L'idée du programme «Retail DDL» est différente : fournir des fonctions ciblées, objet par objet, pour les cas où appeler pg_dump a toujours été la mauvaise solution malgré l'absence d'alternative propre.
Cas d'usage concrets pour les projets Symfony / Laravel
1. Drift detection en CI/CD
Dans un pipeline GitHub Actions ou GitLab CI, vous pouvez désormais comparer le DDL courant d'une base de staging avec un snapshot de référence stocké dans le dépôt :
# Extraire le DDL courant et le comparer au snapshot
psql $DATABASE_URL -t -c "
SELECT ddl FROM pg_get_database_ddl(
current_database()::regdatabase,
'pretty', 'true', 'owner', 'false', 'tablespace', 'false'
)
" > current_db_ddl.sql
diff snapshots/db_reference.sql current_db_ddl.sql
Si le diff est non vide, le pipeline échoue et alerte l'équipe : la configuration de la base a dérivé par rapport à la référence.
2. Génération automatisée de snapshots de schéma
Dans une commande Symfony (ou une commande Artisan Laravel), vous pouvez générer périodiquement un snapshot de la configuration de chaque base :
// src/Command/DatabaseSnapshotCommand.php (Symfony)
protected function execute(InputInterface $input, OutputInterface $output): int
{
$conn = $this->entityManager->getConnection();
$rows = $conn->fetchAllAssociative("
SELECT ddl
FROM pg_get_database_ddl(
current_database()::regdatabase,
'pretty', 'true',
'owner', 'true',
'tablespace', 'true'
)
");
$ddl = implode("\n", array_column($rows, 'ddl'));
file_put_contents(
sprintf('var/snapshots/db_%s.sql', date('Ymd_His')),
$ddl
);
$output->writeln('<info>Snapshot généré.</info>');
return Command::SUCCESS;
}
3. Architecture multi-tenant
Si votre application gère plusieurs bases de données (un tenant = une base), pg_get_database_ddl() permet d'auditer la configuration de chaque base en une seule requête SQL, sans avoir à orchestrer N appels à pg_dump en shell :
-- Audit multi-tenant : DDL de toutes les bases applicatives
SELECT
datname,
(SELECT string_agg(ddl, E'\n')
FROM pg_get_database_ddl(d.oid, 'owner', 'true')
) AS database_ddl
FROM pg_database d
WHERE datname LIKE 'tenant_%'
ORDER BY datname;
Pattern pratique : combiner Retail DDL et pg_dump
La vraie valeur de pg_get_database_ddl() n'est pas de remplacer pg_dump, mais de compléter les outils existants là où un appel shell était un hack déguisé.
Voici la règle de décision :
| Besoin | Outil recommandé |
|---|---|
| Backup complet avec données | pg_dump |
| Diff de schéma complet (tables, index, fonctions…) | pg_dump -s + diff |
| DDL de la configuration d'une base | pg_get_database_ddl() |
| DDL d'une vue ou d'une fonction | pg_get_viewdef() / pg_get_functiondef() |
| Introspection depuis une app sans accès shell | Fonctions Retail DDL |
La checklist permissions à vérifier avant d'intégrer la fonction :
- Le rôle applicatif a
CONNECTsur la base cible - La version PostgreSQL est ≥ 18 (la fonction est introduite dans PG18)
- Le pipeline ne substitue pas cet appel à un vrai backup
Conclusion
Le programme «Retail DDL» de PostgreSQL est une évolution bienvenue pour tous ceux qui ont un jour écrit un wrapper autour de pg_dump pour extraire le DDL d'un seul objet. pg_get_database_ddl() n'est que la première brique : d'autres fonctions couvrant tables, indexes, séquences et contraintes sont attendues dans les versions suivantes.
Pour les projets Symfony et Laravel en architecture multi-tenant ou avec des pipelines CI/CD stricts sur la configuration PostgreSQL, c'est un outil à intégrer dès la sortie de PostgreSQL 18. Simple, sans dépendance shell, et avec des permissions explicites — exactement ce qu'on attendait.