A mensagem de erro é tão clara quanto o manual nisto:
Uma função plgpsql é cercada por um bloco de transação automaticamente. Em resumo:você não pode fazer isso - diretamente. Existe uma razão específica para que você não possa simplesmente chamar o comando DDL?
DROP database $mydb;
Você pode contornar essas restrições com o módulo adicional dblink como @Igor sugerido. Você precisa instalá-lo uma vez por banco de dados - aquele em que você chama as funções dblink, não a (outra) em que você executa comandos.
Permite que você escreva uma função usando
dblink_exec()
assim: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()
impede possível injeção de SQL. Ligar:
SELECT f_drop_db('mydb');
Sobre o sucesso você vê:
A string de conexão pode até apontar para o mesmo banco de dados em que sua sessão é executada. O comando é executado fora de um bloco de transação, o que tem duas consequências:
- Não pode ser revertido.
- Permite que você chame
DROP DATABASE
"por meio de um proxy" de dentro de uma função.
Você pode criar um
FOREIGN DATA WRAPPER
e um FOREIGN SERVER
para armazenar uma conexão e simplificar a chamada: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');
Usando o banco de dados de manutenção padrão
postgres
, o que seria uma escolha óbvia. Mas qualquer db é possível. Função simplificada fazendo uso disso:
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$;