diff --git a/doc/src/sgml/ref/create_schema.sgml b/doc/src/sgml/ref/create_schema.sgml index 930d876..70aeec3 100644 --- a/doc/src/sgml/ref/create_schema.sgml +++ b/doc/src/sgml/ref/create_schema.sgml @@ -21,8 +21,8 @@ PostgreSQL documentation -CREATE SCHEMA schema_name [ AUTHORIZATION user_name ] [ schema_element [ ... ] ] -CREATE SCHEMA AUTHORIZATION user_name [ schema_element [ ... ] ] +CREATE SCHEMA [ IF NOT EXISTS ] schema_name [ AUTHORIZATION user_name ] [ schema_element [ ... ] ] +CREATE SCHEMA [ IF NOT EXISTS ] AUTHORIZATION user_name [ schema_element [ ... ] ] @@ -62,6 +62,16 @@ CREATE SCHEMA AUTHORIZATION user_name + IF NOT EXISTS + + + Do not throw an error if a schema with the same name already exists. + A notice is issued in this case. + + + + + schema_name diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index 8512cdb..e359a9c 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -1374,6 +1374,7 @@ CreateExtension(CreateExtensionStmt *stmt) csstmt->schemaname = schemaName; csstmt->authid = NULL; /* will be created by current user */ csstmt->schemaElts = NIL; + csstmt->if_not_exists = false; CreateSchemaCommand(csstmt, NULL); /* diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c index 4974025..f8a6c15 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -49,6 +49,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) Oid saved_uid; int save_sec_context; AclResult aclresult; + bool if_not_exists = stmt->if_not_exists; GetUserIdAndSecContext(&saved_uid, &save_sec_context); @@ -93,6 +94,15 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) SetUserIdAndSecContext(owner_uid, save_sec_context | SECURITY_LOCAL_USERID_CHANGE); + /* If schema already exists, skip */ + if (OidIsValid(get_namespace_oid(schemaName, true)) && if_not_exists) { + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_SCHEMA), + errmsg("schema \"%s\" already exists, skipping", + schemaName))); + return; + } + /* Create the schema's namespace */ namespaceId = NamespaceCreate(schemaName, owner_uid, false); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 71d5323..3c51c96 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3600,6 +3600,7 @@ _copyCreateSchemaStmt(const CreateSchemaStmt *from) COPY_STRING_FIELD(schemaname); COPY_STRING_FIELD(authid); COPY_NODE_FIELD(schemaElts); + COPY_SCALAR_FIELD(if_not_exists); return newnode; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index d690ca7..12c4538 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1901,6 +1901,7 @@ _equalCreateSchemaStmt(const CreateSchemaStmt *a, const CreateSchemaStmt *b) COMPARE_STRING_FIELD(schemaname); COMPARE_STRING_FIELD(authid); COMPARE_NODE_FIELD(schemaElts); + COMPARE_SCALAR_FIELD(if_not_exists); return true; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 90ea1f9..487cf9e 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -1169,8 +1169,23 @@ CreateSchemaStmt: n->schemaname = $5; n->authid = $5; n->schemaElts = $6; + n->if_not_exists = false; $$ = (Node *)n; } + | CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleId OptSchemaEltList + { + CreateSchemaStmt *n = makeNode(CreateSchemaStmt); + /* One can omit the schema name or the authorization id. */ + if ($6 != NULL) + n->schemaname = $6; + else + n->schemaname = $8; + n->authid = $8; + n->schemaElts = $9; + n->if_not_exists = true; + $$ = (Node *)n; + } + | CREATE SCHEMA ColId OptSchemaEltList { CreateSchemaStmt *n = makeNode(CreateSchemaStmt); @@ -1178,8 +1193,20 @@ CreateSchemaStmt: n->schemaname = $3; n->authid = NULL; n->schemaElts = $4; + n->if_not_exists = false; $$ = (Node *)n; } + | CREATE SCHEMA IF_P NOT EXISTS ColId OptSchemaEltList + { + CreateSchemaStmt *n = makeNode(CreateSchemaStmt); + /* ...but not both */ + n->schemaname = $6; + n->authid = NULL; + n->schemaElts = $7; + n->if_not_exists = true; + $$ = (Node *)n; + } + ; OptSchemaName: diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index f433166..b2abdb1 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1157,6 +1157,7 @@ typedef struct CreateSchemaStmt char *schemaname; /* the name of the schema to create */ char *authid; /* the owner of the created schema */ List *schemaElts; /* schema components (list of parsenodes) */ + bool if_not_exists; /* just do nothing if schema already exists? */ } CreateSchemaStmt; typedef enum DropBehavior diff --git a/src/test/regress/expected/namespace.out b/src/test/regress/expected/namespace.out index 7c26da5..9ec5b4f 100644 --- a/src/test/regress/expected/namespace.out +++ b/src/test/regress/expected/namespace.out @@ -9,6 +9,11 @@ CREATE SCHEMA test_schema_1 a serial, b int UNIQUE ); +-- verify if schema already exists +CREATE SCHEMA test_schema_1; +ERROR: schema "test_schema_1" already exists +CREATE SCHEMA IF NOT EXISTS test_schema_1; +NOTICE: schema "test_schema_1" already exists, skipping -- verify that the objects were created SELECT COUNT(*) FROM pg_class WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'test_schema_1'); diff --git a/src/test/regress/sql/namespace.sql b/src/test/regress/sql/namespace.sql index 919f72a..b776b3e 100644 --- a/src/test/regress/sql/namespace.sql +++ b/src/test/regress/sql/namespace.sql @@ -13,6 +13,9 @@ CREATE SCHEMA test_schema_1 b int UNIQUE ); +-- verify if schema already exists +CREATE SCHEMA test_schema_1; +CREATE SCHEMA IF NOT EXISTS test_schema_1; -- verify that the objects were created SELECT COUNT(*) FROM pg_class WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'test_schema_1');