Удалить или создать базу данных из хранимой процедуры в PostgreSQL

У меня есть функция, которая выглядит так:

BEGIN
  DROP DATABASE IF EXISTS db_1;
END;

Я получаю следующую ошибку:

ОШИБКА: DROP DATABASE не может быть запущена из функции или строки с несколькими командами.

Разве нельзя удалить базу данных из хранимой процедуры в PostgreSQL? Я использую plpgsql.


person Rudecles    schedule 06.03.2013    source источник
comment
Вы можете сделать это из другой базы данных   -  person Houari    schedule 07.03.2013
comment
Вы можете попробовать dblink подключиться к любой базе данных в этом кластере (кроме той, которую вы хотите удалить) и выполнить DROP DATABASE IF EXISTS db_1; из dblink.   -  person Ihor Romanchenko    schedule 07.03.2013
comment
Я считаю, что сообщение об ошибке довольно ясное.   -  person Milen A. Radev    schedule 07.03.2013


Ответы (2)


Сообщение об ошибке так же ясно, как и руководство по этому вопросу. :

DROP DATABASE не может выполняться внутри блока транзакции.

Функция plgpsql автоматически окружается блоком транзакции. Короче говоря: вы не можете сделать это - напрямую. Есть ли конкретная причина, по которой вы не можете просто вызвать команду DDL?

DROP database $mydb;

Вы можете обойти эти ограничения с помощью дополнительного модуля dblink как @ - предложил Игорь. Вам необходимо установить его один раз для каждой базы данных - той, в которой вы вызываете функции dblink, а не той (другой), в которой вы выполняете команды.
Позволяет вам написать функцию, используя _ 3_ вот так:

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() предотвращает возможную SQL-инъекцию.

Вызов:

SELECT f_drop_db('mydb');

В случае успеха вы увидите:

УДАЛИТЬ БАЗУ ДАННЫХ

Строка подключения может даже указывать на ту же базу данных, в которой запущен ваш сеанс. Команда выполняется вне блока транзакции, что имеет два последствия:

  • Откатить нельзя.
  • Он позволяет вам вызывать DROP DATABASE «через прокси» из функции.

Вы можете создать FOREIGN DATA WRAPPER и FOREIGN SERVER для хранения соединения и упрощения вызова:

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

Использование базы данных обслуживания по умолчанию postgres, что было бы очевидным выбором. Но возможен любой дб.

Упрощенная функция, использующая это:

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$;
person Erwin Brandstetter    schedule 07.03.2013

вы не можете сделать это из процедуры, потому что drop database не может быть выполнен внутри транзакции, а хранимая процедура рассматривается как сама транзакция. (См. справочник)

А как насчет dropdb?

person Houari    schedule 06.03.2013
comment
Делаю с другого дб. SP находится в db_2, и я запускаю его оттуда. Попробую из postgres - person Rudecles; 07.03.2013
comment
Очевидно, что это не основная проблема. Вы прочитали сообщение об ошибке? - person Erwin Brandstetter; 07.03.2013