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