From c5946bc1fe9132763e7b6b6293b015b585076e27 Mon Sep 17 00:00:00 2001 From: li_jianqiu <295949552@qq.com> Date: Mon, 1 Aug 2022 17:18:39 +0800 Subject: [PATCH] =?UTF-8?q?CREATE=20DATABASE=E7=AD=89=E4=B8=89=E7=A7=8D?= =?UTF-8?q?=E8=AF=AD=E6=B3=95=E5=85=BC=E5=AE=B9IF=20NOT=20EXISTS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/src/sgml/ref/alter_user.sgmlin | 2 +- doc/src/sgml/ref/create_database.sgmlin | 2 +- doc/src/sgml/ref/create_schema.sgmlin | 2 +- src/common/backend/nodes/copyfuncs.cpp | 3 ++ src/common/backend/nodes/equalfuncs.cpp | 3 ++ src/common/backend/parser/gram.y | 33 +++++++++++++++++++ .../optimizer/commands/dbcommands.cpp | 10 ++++-- .../optimizer/commands/schemacmds.cpp | 8 +++++ src/gausskernel/optimizer/commands/user.cpp | 12 +++++-- src/include/nodes/parsenodes.h | 1 + src/include/nodes/parsenodes_common.h | 2 ++ .../regress/expected/test_if_not_exists.out | 28 ++++++++++++++++ src/test/regress/parallel_schedule0 | 2 +- src/test/regress/sql/test_if_not_exists.sql | 22 +++++++++++++ 14 files changed, 121 insertions(+), 9 deletions(-) create mode 100644 src/test/regress/expected/test_if_not_exists.out create mode 100644 src/test/regress/sql/test_if_not_exists.sql diff --git a/doc/src/sgml/ref/alter_user.sgmlin b/doc/src/sgml/ref/alter_user.sgmlin index 533950ea4..a04190382 100755 --- a/doc/src/sgml/ref/alter_user.sgmlin +++ b/doc/src/sgml/ref/alter_user.sgmlin @@ -10,7 +10,7 @@ -ALTER USER user_name [ [ WITH ] option [ ... ] ]; +ALTER USER [ IF EXISTS ] user_name [ [ WITH ] option [ ... ] ]; ALTER USER user_name RENAME TO new_name; ALTER USER user_name [ IN DATABASE database_name ] diff --git a/doc/src/sgml/ref/create_database.sgmlin b/doc/src/sgml/ref/create_database.sgmlin index 6ec6f2d2a..0b9d4e98e 100644 --- a/doc/src/sgml/ref/create_database.sgmlin +++ b/doc/src/sgml/ref/create_database.sgmlin @@ -10,7 +10,7 @@ -CREATE DATABASE database_name +CREATE DATABASE [ IF NOT EXISTS ] database_name [ [ WITH ] {[ OWNER [=] user_name ]| [ TEMPLATE [=] template ]| [ ENCODING [=] encoding ]| diff --git a/doc/src/sgml/ref/create_schema.sgmlin b/doc/src/sgml/ref/create_schema.sgmlin index 418548546..b674c318e 100644 --- a/doc/src/sgml/ref/create_schema.sgmlin +++ b/doc/src/sgml/ref/create_schema.sgmlin @@ -10,7 +10,7 @@ -CREATE SCHEMA schema_name +CREATE SCHEMA [ IF NOT EXISTS ] schema_name [ AUTHORIZATION user_name ] [WITH BLOCKCHAIN] [ schema_element [ ... ] ]; diff --git a/src/common/backend/nodes/copyfuncs.cpp b/src/common/backend/nodes/copyfuncs.cpp index 064ca29df..8d5511f9c 100644 --- a/src/common/backend/nodes/copyfuncs.cpp +++ b/src/common/backend/nodes/copyfuncs.cpp @@ -5458,6 +5458,7 @@ static CreatedbStmt* _copyCreatedbStmt(const CreatedbStmt* from) CreatedbStmt* newnode = makeNode(CreatedbStmt); COPY_STRING_FIELD(dbname); + COPY_SCALAR_FIELD(missing_ok); COPY_NODE_FIELD(options); return newnode; @@ -6037,6 +6038,7 @@ static AlterRoleStmt* _copyAlterRoleStmt(const AlterRoleStmt* from) AlterRoleStmt* newnode = makeNode(AlterRoleStmt); COPY_STRING_FIELD(role); + COPY_SCALAR_FIELD(missing_ok); COPY_NODE_FIELD(options); COPY_SCALAR_FIELD(action); COPY_SCALAR_FIELD(lockstatus); @@ -6111,6 +6113,7 @@ static CreateSchemaStmt* _copyCreateSchemaStmt(const CreateSchemaStmt* from) CreateSchemaStmt* newnode = makeNode(CreateSchemaStmt); COPY_STRING_FIELD(schemaname); + COPY_SCALAR_FIELD(missing_ok); COPY_STRING_FIELD(authid); COPY_SCALAR_FIELD(hasBlockChain); COPY_NODE_FIELD(schemaElts); diff --git a/src/common/backend/nodes/equalfuncs.cpp b/src/common/backend/nodes/equalfuncs.cpp index 2f2e6d896..7eafcd637 100644 --- a/src/common/backend/nodes/equalfuncs.cpp +++ b/src/common/backend/nodes/equalfuncs.cpp @@ -1660,6 +1660,7 @@ static bool _equalAlterOpFamilyStmt(const AlterOpFamilyStmt* a, const AlterOpFam static bool _equalCreatedbStmt(const CreatedbStmt* a, const CreatedbStmt* b) { COMPARE_STRING_FIELD(dbname); + COMPARE_SCALAR_FIELD(missing_ok); COMPARE_NODE_FIELD(options); return true; @@ -2138,6 +2139,7 @@ static bool _equalCreateRoleStmt(const CreateRoleStmt* a, const CreateRoleStmt* static bool _equalAlterRoleStmt(const AlterRoleStmt* a, const AlterRoleStmt* b) { COMPARE_STRING_FIELD(role); + COMPARE_SCALAR_FIELD(missing_ok); COMPARE_NODE_FIELD(options); COMPARE_SCALAR_FIELD(action); COMPARE_SCALAR_FIELD(lockstatus); @@ -2196,6 +2198,7 @@ static bool _equalReindexStmt(const ReindexStmt* a, const ReindexStmt* b) static bool _equalCreateSchemaStmt(const CreateSchemaStmt* a, const CreateSchemaStmt* b) { COMPARE_STRING_FIELD(schemaname); + COMPARE_SCALAR_FIELD(missing_ok); COMPARE_STRING_FIELD(authid); COMPARE_SCALAR_FIELD(hasBlockChain); COMPARE_NODE_FIELD(schemaElts); diff --git a/src/common/backend/parser/gram.y b/src/common/backend/parser/gram.y index 0227edb69..523e0214e 100644 --- a/src/common/backend/parser/gram.y +++ b/src/common/backend/parser/gram.y @@ -1626,12 +1626,23 @@ AlterUserStmt: ALTER USER RoleId opt_with AlterOptRoleList { AlterRoleStmt *n = makeNode(AlterRoleStmt); + n->missing_ok = FALSE; n->role = $3; n->action = +1; /* add, if there are members */ n->options = $5; n->lockstatus = DO_NOTHING; $$ = (Node *)n; } + | ALTER USER IF_P EXISTS RoleId opt_with AlterOptRoleList + { + AlterRoleStmt *n = makeNode(AlterRoleStmt); + n->missing_ok = TRUE; + n->role = $5; + n->action = +1; /* add, if there are members */ + n->options = $7; + n->lockstatus = DO_NOTHING; + $$ = (Node *)n; + } | ALTER USER RoleId opt_with ACCOUNT LOCK_P { AlterRoleStmt *n = makeNode(AlterRoleStmt); @@ -1886,6 +1897,7 @@ CreateSchemaStmt: | CREATE SCHEMA ColId OptBlockchainWith OptSchemaEltList { CreateSchemaStmt *n = makeNode(CreateSchemaStmt); + n->missing_ok = FALSE; /* ...but not both */ n->schemaname = $3; n->authid = NULL; @@ -1893,6 +1905,17 @@ CreateSchemaStmt: n->schemaElts = $5; $$ = (Node *)n; } + | CREATE SCHEMA IF_P NOT EXISTS ColId OptBlockchainWith OptSchemaEltList + { + CreateSchemaStmt *n = makeNode(CreateSchemaStmt); + n->missing_ok = TRUE; + /* ...but not both */ + n->schemaname = $6; + n->authid = NULL; + n->hasBlockChain = $7; + n->schemaElts = $8; + $$ = (Node *)n; + } ; OptSchemaName: @@ -15718,9 +15741,19 @@ CreatedbStmt: CreatedbStmt *n = makeNode(CreatedbStmt); IsValidIdent($3); n->dbname = $3; + n->missing_ok = FALSE; n->options = $5; $$ = (Node *)n; } + | CREATE DATABASE IF_P NOT EXISTS database_name opt_with createdb_opt_list + { + CreatedbStmt *n = makeNode(CreatedbStmt); + IsValidIdent($6); + n->dbname = $6; + n->missing_ok = TRUE; + n->options = $8; + $$ = (Node *)n; + } ; createdb_opt_list: diff --git a/src/gausskernel/optimizer/commands/dbcommands.cpp b/src/gausskernel/optimizer/commands/dbcommands.cpp index 71d7c48ce..9154fb0db 100644 --- a/src/gausskernel/optimizer/commands/dbcommands.cpp +++ b/src/gausskernel/optimizer/commands/dbcommands.cpp @@ -473,8 +473,14 @@ void createdb(const CreatedbStmt* stmt) * message than "unique index violation". There's a race condition but * we're willing to accept the less friendly message in that case. */ - if (OidIsValid(get_database_oid(dbname, true))) - ereport(ERROR, (errcode(ERRCODE_DUPLICATE_DATABASE), errmsg("database \"%s\" already exists", dbname))); + if (OidIsValid(get_database_oid(dbname, true))) { + if (stmt->missing_ok) { + ereport(NOTICE, (errmsg("database \"%s\" already exists, skipping", dbname))); + return; + } else { + ereport(ERROR, (errcode(ERRCODE_DUPLICATE_DATABASE), errmsg("database \"%s\" already exists", dbname))); + } + } /* * The source DB can't have any active backends, except this one diff --git a/src/gausskernel/optimizer/commands/schemacmds.cpp b/src/gausskernel/optimizer/commands/schemacmds.cpp index 0f04c3ff5..84c609cef 100644 --- a/src/gausskernel/optimizer/commands/schemacmds.cpp +++ b/src/gausskernel/optimizer/commands/schemacmds.cpp @@ -174,6 +174,14 @@ void CreateSchemaCommand(CreateSchemaStmt* stmt, const char* queryString) if (saved_uid != owner_uid) SetUserIdAndSecContext(owner_uid, (uint32)save_sec_context | SECURITY_LOCAL_USERID_CHANGE); + /* make sure there is no existing namespace of same name */ + if (stmt->missing_ok) { + if (SearchSysCacheExists1(NAMESPACENAME, PointerGetDatum(schemaName))) { + ereport(NOTICE, (errmsg("schema \"%s\" already exists,skipping", schemaName))); + return; + } + } + /* Create the schema's namespace */ namespaceId = NamespaceCreate(schemaName, owner_uid, false, hasBlockChain); diff --git a/src/gausskernel/optimizer/commands/user.cpp b/src/gausskernel/optimizer/commands/user.cpp index 634d0976d..bca56d8d9 100755 --- a/src/gausskernel/optimizer/commands/user.cpp +++ b/src/gausskernel/optimizer/commands/user.cpp @@ -2075,10 +2075,16 @@ void AlterRole(AlterRoleStmt* stmt) str_reset(password); str_reset(replPasswd); - if (!have_createrole_privilege()) + if (!have_createrole_privilege()) { ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied."))); - else - ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("role \"%s\" does not exist", stmt->role))); + } else { + if (stmt->missing_ok) { + ereport(NOTICE, (errmsg("role \"%s\" does not exist, skipping", stmt->role))); + return; + } else { + ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("role \"%s\" does not exist", stmt->role))); + } + } } roleid = HeapTupleGetOid(tuple); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 7cbda2254..14fce1c70 100755 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1507,6 +1507,7 @@ typedef struct LoadStmt { typedef struct CreatedbStmt { NodeTag type; char* dbname; /* name of database to create */ + bool missing_ok; /* skip error if db is missing? */ List* options; /* List of DefElem nodes */ } CreatedbStmt; diff --git a/src/include/nodes/parsenodes_common.h b/src/include/nodes/parsenodes_common.h index deb840aa2..f95a13476 100644 --- a/src/include/nodes/parsenodes_common.h +++ b/src/include/nodes/parsenodes_common.h @@ -131,6 +131,7 @@ typedef struct DropStmt { typedef struct AlterRoleStmt { NodeTag type; char* role; /* role name */ + bool missing_ok; /* skip error if a role is missing? */ List* options; /* List of DefElem nodes */ int action; /* +1 = add members, -1 = drop members */ RoleLockType lockstatus; @@ -710,6 +711,7 @@ typedef enum TempType { typedef struct CreateSchemaStmt { NodeTag type; + bool missing_ok; /* just do nothing if it already exists? */ char *schemaname; /* the name of the schema to create */ char *authid; /* the owner of the created schema */ bool hasBlockChain; /* whether this schema has blockchain */ diff --git a/src/test/regress/expected/test_if_not_exists.out b/src/test/regress/expected/test_if_not_exists.out new file mode 100644 index 000000000..36f86ec25 --- /dev/null +++ b/src/test/regress/expected/test_if_not_exists.out @@ -0,0 +1,28 @@ +create database db_testa; +create database if not exists db_testa; +NOTICE: database "db_testa" already exists, skipping +create database db_testa; +ERROR: database "db_testa" already exists +create database if not exists db_testb; +drop database if exists db_testa; +drop database if exists db_testb; + + +create user test_user with password 'Abcd.123'; +ALTER USER IF EXISTS test_user IDENTIFIED BY 'Abcd.1234'; +ALTER USER test_user IDENTIFIED BY 'Abcd.12345'; +ALTER USER IF EXISTS test_user2 IDENTIFIED BY 'Abcd.1234'; +NOTICE: role "test_user2" does not exist, skipping +ALTER USER test_user2 IDENTIFIED BY 'Abcd.1234'; +ERROR: role "test_user2" does not exist +DROP USER test_user; + +CREATE SCHEMA sch_name; +CREATE SCHEMA IF NOT EXISTS sch_name; +NOTICE: schema "sch_name" already exists,skipping +CREATE SCHEMA IF NOT EXISTS sch_name2; +CREATE SCHEMA sch_name2; +ERROR: schema "sch_name2" already exists +drop SCHEMA sch_name; +drop SCHEMA sch_name2; + diff --git a/src/test/regress/parallel_schedule0 b/src/test/regress/parallel_schedule0 index 3243a63cd..aa7ad1d26 100644 --- a/src/test/regress/parallel_schedule0 +++ b/src/test/regress/parallel_schedule0 @@ -557,7 +557,7 @@ test: copyselect copy_error_log copy_support_transform copy_from_support_paralle # Another group of parallel tests # ---------- test: create_function_3 vacuum -test: drop_if_exists +test: drop_if_exists test_if_not_exists #test: constraints #test: errors subplan_base diff --git a/src/test/regress/sql/test_if_not_exists.sql b/src/test/regress/sql/test_if_not_exists.sql new file mode 100644 index 000000000..c8f5ca268 --- /dev/null +++ b/src/test/regress/sql/test_if_not_exists.sql @@ -0,0 +1,22 @@ +create database db_testa; +create database if not exists db_testa; +create database db_testa; +create database if not exists db_testb; +drop database if exists db_testa; +drop database if exists db_testb; + + +create user test_user with password 'Abcd.123'; +ALTER USER IF EXISTS test_user IDENTIFIED BY 'Abcd.1234'; +ALTER USER test_user IDENTIFIED BY 'Abcd.12345'; +ALTER USER IF EXISTS test_user2 IDENTIFIED BY 'Abcd.1234'; +ALTER USER test_user2 IDENTIFIED BY 'Abcd.1234'; +DROP USER test_user; + +CREATE SCHEMA sch_name; +CREATE SCHEMA IF NOT EXISTS sch_name; +CREATE SCHEMA IF NOT EXISTS sch_name2; +CREATE SCHEMA sch_name2; +drop SCHEMA sch_name; +drop SCHEMA sch_name2; +