sql >> Base de Datos >  >> RDS >> PostgreSQL

Descartar o crear una base de datos a partir de un procedimiento almacenado en PostgreSQL

El mensaje de error es tan claro como el manual en esto:

Una función plgpsql está rodeada por un bloque de transacción automáticamente. Lo largo y lo corto:no puedes hacer eso, directamente. ¿Hay alguna razón en particular por la que no puedas simplemente llamar al comando DDL?

DROP database $mydb;

Tu puedes eluda estas restricciones con el módulo adicional dblink como @Igor sugirió. Debe instalarlo una vez por base de datos, en la que llama a las funciones dblink, no en la (otra) en la que ejecuta los comandos.
Le permite escribir una función usando
dblink_exec() así:

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() previene una posible inyección SQL.

Llamar:

SELECT f_drop_db('mydb');

En caso de éxito, verá:

La cadena de conexión podría incluso apuntar a la misma base de datos en la que se ejecuta su sesión. El comando se ejecuta fuera de un bloque de transacciones, lo que tiene dos consecuencias:

  • No se puede deshacer.
  • Te permite llamar a DROP DATABASE "a través de un proxy" desde dentro de una función.

Podrías crear un FOREIGN DATA WRAPPER y un FOREIGN SERVER para almacenar una conexión y simplificar la llamada:

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');

Uso de la base de datos de mantenimiento predeterminada postgres , que sería una opción obvia. Pero cualquier base de datos es posible.

Función simplificada haciendo uso de eso:

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$;