PostgreSQL не підтримує IF NOT EXISTS
для CREATE DATABASE
заяви. Він підтримується лише в CREATE SCHEMA
. Більше того, CREATE DATABASE
не може бути видано транзакцією, тому воно не може бути в DO
блоці з вилученням виключень.
Коли CREATE SCHEMA IF NOT EXISTS
випущено і схема вже існує, то виникає повідомлення (не помилка) з подвійною інформацією про об'єкт.
Для вирішення цих проблем вам потрібно використовувати dblink
розширення, яке відкриває нове підключення до сервера баз даних та виконувати запит без укладання транзакцій. Ви можете повторно використовувати параметри з'єднання, подаючи порожню рядок.
Нижче наведено PL/pgSQL
код, який повністю імітує CREATE DATABASE IF NOT EXISTS
таку саму поведінку, як у CREATE SCHEMA IF NOT EXISTS
. Він викликає CREATE DATABASE
через dblink
, duplicate_database
виключення catch (який видається, коли база даних вже існує) і перетворює його в повідомлення з поширенням errcode
. Повідомлення рядка додається , skipping
так само, як це робиться CREATE SCHEMA IF NOT EXISTS
.
CREATE EXTENSION IF NOT EXISTS dblink;
DO $$
BEGIN
PERFORM dblink_exec('', 'CREATE DATABASE testdb');
EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
END
$$;
Це рішення не має жодних умов перегонів, як в інших відповідях, де база даних може бути створена зовнішнім процесом (або іншим екземпляром того ж сценарію) між перевіркою наявності бази даних та її власним створенням.
Більше того, коли CREATE DATABASE
помилки з іншою помилкою, ніж база даних вже існує, ця помилка поширюється як помилка, а не мовчки відкидається. Є лише улов на duplicate_database
помилку. Тож воно справді поводиться як IF NOT EXISTS
слід.
Ви можете ввести цей код у власну функцію, зателефонувати йому безпосередньо або з транзакції. Просто відкат (відновлення випалої бази даних) не буде працювати.
Тестовий вихід (викликається два рази через DO, а потім безпосередньо):
$ sudo -u postgres psql
psql (9.6.12)
Type "help" for help.
postgres=# \set ON_ERROR_STOP on
postgres=# \set VERBOSITY verbose
postgres=#
postgres=# CREATE EXTENSION IF NOT EXISTS dblink;
CREATE EXTENSION
postgres=# DO $$
postgres$# BEGIN
postgres$# PERFORM dblink_exec('', 'CREATE DATABASE testdb');
postgres$# EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
DO
postgres=#
postgres=# CREATE EXTENSION IF NOT EXISTS dblink;
NOTICE: 42710: extension "dblink" already exists, skipping
LOCATION: CreateExtension, extension.c:1539
CREATE EXTENSION
postgres=# DO $$
postgres$# BEGIN
postgres$# PERFORM dblink_exec('', 'CREATE DATABASE testdb');
postgres$# EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
NOTICE: 42P04: database "testdb" already exists, skipping
LOCATION: exec_stmt_raise, pl_exec.c:3165
DO
postgres=#
postgres=# CREATE DATABASE testdb;
ERROR: 42P04: database "testdb" already exists
LOCATION: createdb, dbcommands.c:467
dblink_connect
.