Il messaggio di errore è chiaro come il manuale su questo:
Una funzione plgpsql è circondata automaticamente da un blocco di transazione. Il lungo e il corto:non puoi farlo direttamente. C'è un motivo particolare per cui non puoi semplicemente chiamare il comando DDL?
DROP database $mydb;
puoi aggirare queste restrizioni con il modulo aggiuntivo dblink
come @Igor suggerito. Devi installarlo una volta per database, quello in cui chiami le funzioni dblink, non l'altro in cui esegui i comandi.
Ti permette di scrivere una funzione usando dblink_exec()
così:
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 la possibile SQL injection.
Chiama:
SELECT f_drop_db('mydb');
In caso di successo vedi:
La stringa di connessione potrebbe anche puntare allo stesso db in cui viene eseguita la sessione. Il comando viene eseguito all'esterno di un blocco di transazione, il che ha due conseguenze:
- Non è possibile eseguire il rollback.
- Ti permette di chiamare
DROP DATABASE
"tramite un proxy" dall'interno di una funzione.
Potresti creare un FOREIGN DATA WRAPPER
e un FOREIGN SERVER
per memorizzare una connessione e semplificare la chiamata:
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');
Utilizzo del db di manutenzione predefinito postgres
, che sarebbe una scelta ovvia. Ma qualsiasi db è possibile.
Funzione semplificata che ne fa uso:
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$;