PostgreSQL no es compatible IF NOT EXISTS
para la CREATE DATABASE
declaración. Solo se admite en CREATE SCHEMA
. Además CREATE DATABASE
, no se puede emitir en transacción, por lo que no puedeDO
bloque con excepción de captura.
Cuando CREATE SCHEMA IF NOT EXISTS
se emite y el esquema ya existe, se genera un aviso (no un error) con información de objeto duplicada.
Para resolver estos problemas, debe usar la dblink
extensión que abre una nueva conexión al servidor de la base de datos y ejecutar la consulta sin ingresar a la transacción. Puede reutilizar los parámetros de conexión proporcionando una cadena vacía.
A continuación se muestra el PL/pgSQL
código que simula completamente CREATE DATABASE IF NOT EXISTS
con el mismo comportamiento que enCREATE SCHEMA IF NOT EXISTS
. Llama a CREATE DATABASE
través de la excepción de dblink
captura duplicate_database
(que se emite cuando la base de datos ya existe) y la convierte en un aviso con propagación errcode
. El mensaje de cadena se ha agregado , skipping
de la misma manera que lo hace 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
$$;
Esta solución no tiene ninguna condición de carrera como en otras respuestas, donde la base de datos puede ser creada por un proceso externo (u otra instancia del mismo script) entre verificar si la base de datos existe y su propia creación.
Además, cuando CREATE DATABASE
falla con otro error que la base de datos ya existe, este error se propaga como error y no se descarta silenciosamente. Solo hay una trampa para el duplicate_database
error. Entonces realmente se comporta como IF NOT EXISTS
debería.
Puede poner este código en su propia función, llamarlo directamente o desde la transacción. Solo la reversión (restaurar la base de datos eliminada) no funcionaría.
Prueba de salida (llamada dos veces a través de DO y luego directamente):
$ 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
.