PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Supprimer ou créer une base de données à partir d'une procédure stockée dans PostgreSQL

Le message d'erreur est juste un s clair comme le manuel sur ceci :

Une fonction plgpsql est automatiquement entourée d'un bloc de transaction. Le long et le court:vous ne pouvez pas le faire - directement. Y a-t-il une raison particulière pour laquelle vous ne pouvez pas simplement appeler la commande DDL ?

DROP database $mydb;

Vous pouvez contourner ces restrictions avec le module supplémentaire dblink comme @Igor suggéré. Vous devez l'installer une fois par base de données - celle où vous appelez les fonctions dblink, pas celle dans laquelle vous exécutez des commandes.
Vous permet d'écrire une fonction en utilisant
dblink_exec() comme ceci :

CREATE OR REPLACE FUNCTION f_drop_db(text)
  RETURNS text LANGUAGE sql AS
$func$
SELECT dblink_exec('port=5432 dbname=postgres'
                  ,'DROP DATABASE ' || quote_ident($1))
$func$;

quote_ident() empêche une éventuelle injection SQL.

Appel :

SELECT f_drop_db('mydb');

En cas de succès, vous voyez :

La chaîne de connexion peut même pointer vers la même base de données dans laquelle votre session s'exécute. La commande s'exécute en dehors d'un bloc de transaction, ce qui a deux conséquences :

  • Il ne peut pas être annulé.
  • Il vous permet d'appeler DROP DATABASE "au moyen d'un proxy" à partir d'une fonction.

Vous pouvez créer un FOREIGN DATA WRAPPER et un FOREIGN SERVER pour mémoriser une connexion et simplifier l'appel :

CREATE FOREIGN DATA WRAPPER postgresql VALIDATOR postgresql_fdw_validator;

CREATE SERVER your_fdw_name_here FOREIGN DATA WRAPPER postgresql
OPTIONS (hostaddr '12.34.56.78', port '5432', dbname 'postgres');

Utilisation de la base de données de maintenance par défaut postgres , ce qui serait un choix évident. Mais n'importe quelle base de données est possible.

Fonction simplifiée utilisant cela :

CREATE OR REPLACE FUNCTION f_drop_db(text)
  RETURNS text LANGUAGE sql AS
$func$
SELECT dblink_exec('your_fdw_name_here', 'DROP DATABASE ' || quote_ident($1))
$func$;