Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: RudeclesОтветов: 2

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

BEGIN
  DROP DATABASE IF EXISTS db_1;
END;

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

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

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

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

postgresqlstored-proceduresddlplpgsqldblink

Ответы

Ответ 1 · рейтинг 4 · Erwin Brandstetter

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

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

Ответ 2 · рейтинг 1 · Houari

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

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы