diff --git a/src/backend/distributed/commands/database.c b/src/backend/distributed/commands/database.c index bcd0999ed..cffac87d4 100644 --- a/src/backend/distributed/commands/database.c +++ b/src/backend/distributed/commands/database.c @@ -632,13 +632,11 @@ List * PreprocessDropDatabaseStmt(Node *node, const char *queryString, ProcessUtilityContext processUtilityContext) { - if (!EnableCreateDatabasePropagation || !ShouldPropagate()) + if (!IsDistributedDropDatabaseCommand(node)) { return NIL; } - EnsurePropagationToCoordinator(); - DropdbStmt *stmt = (DropdbStmt *) node; bool isPostProcess = false; @@ -657,22 +655,78 @@ PreprocessDropDatabaseStmt(Node *node, const char *queryString, return NIL; } + EnsurePropagationToCoordinator(); + SerializeDistributedDDLsOnObjectClassObject(OCLASS_DATABASE, stmt->dbname); - char *dropDatabaseCommand = DeparseTreeNode(node); + OperationId operationId = RegisterOperationNeedingCleanup(); - List *dropDatabaseCommands = list_make3(DISABLE_DDL_PROPAGATION, - (void *) dropDatabaseCommand, - ENABLE_DDL_PROPAGATION); + char *tempDatabaseName = psprintf(TEMP_DATABASE_NAME_FMT, + operationId, GetLocalGroupId()); - /* - * Due to same reason stated in PostprocessCreateDatabaseStmt(), we need to - * use NontransactionalNodeDDLTaskList() to send the DROP DATABASE statement - * to the workers. - */ - List *dropDatabaseDDLJobList = - NontransactionalNodeDDLTaskList(REMOTE_NODES, dropDatabaseCommands); - return dropDatabaseDDLJobList; + UnmarkObjectDistributed(linitial(addresses)); + + char *unmarkObjectDistributedCommand = + psprintf("SELECT pg_catalog.citus_unmark_object_distributed(" + "(SELECT oid FROM pg_class WHERE relname = 'pg_database'), " + "(SELECT oid FROM pg_database WHERE datname = %s), " + "0);", + quote_literal_cstr(tempDatabaseName)); + List *unmarkObjectDistributedCommands = list_make1(unmarkObjectDistributedCommand); + List *unmarkObjectDistributedDDLJobList = + NodeDDLTaskList(REMOTE_NODES, unmarkObjectDistributedCommands); + + char *renameDatabaseCommand = + psprintf("ALTER DATABASE %s RENAME TO %s", + quote_identifier(stmt->dbname), + quote_identifier(tempDatabaseName)); + + int saveNestLevel = NewGUCNestLevel(); + set_config_option("citus.enable_ddl_propagation", "off", + (superuser() ? PGC_SUSET : PGC_USERSET), PGC_S_SESSION, + GUC_ACTION_LOCAL, true, 0, false); + + ExecuteUtilityCommand(renameDatabaseCommand); + + AtEOXact_GUC(true, saveNestLevel); + + List *renameDatabaseCommands = list_make3(DISABLE_DDL_PROPAGATION, + renameDatabaseCommand, + ENABLE_DDL_PROPAGATION); + + List *renameDatabaseDDLJobList = + NodeDDLTaskList(REMOTE_NODES, renameDatabaseCommands); + + List *allNodes = TargetWorkerSetNodeList(ALL_SHARD_NODES, RowShareLock); + WorkerNode *workerNode = NULL; + foreach_ptr(workerNode, allNodes) + { + InsertCleanupRecordInCurrentTransaction( + CLEANUP_OBJECT_DATABASE, + pstrdup(quote_identifier(tempDatabaseName)), + workerNode->groupId, + CLEANUP_DEFERRED_ON_SUCCESS + ); + } + + return list_concat(renameDatabaseDDLJobList, unmarkObjectDistributedDDLJobList); +} + + +bool +IsDistributedDropDatabaseCommand(Node *node) +{ + if (!IsA(node, DropdbStmt)) + { + return false; + } + + if (!EnableCreateDatabasePropagation || !ShouldPropagate()) + { + return false; + } + + return true; } diff --git a/src/backend/distributed/commands/utility_hook.c b/src/backend/distributed/commands/utility_hook.c index 68af4b7b5..c9f9d87f0 100644 --- a/src/backend/distributed/commands/utility_hook.c +++ b/src/backend/distributed/commands/utility_hook.c @@ -115,6 +115,7 @@ static void citus_ProcessUtilityInternal(PlannedStmt *pstmt, struct QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *completionTag); +static bool ShouldSkipPrevProcessUtility(Node *node); static void set_indexsafe_procflags(void); static char * CurrentSearchPath(void); static void IncrementUtilityHookCountersIfNecessary(Node *parsetree); @@ -785,8 +786,11 @@ citus_ProcessUtilityInternal(PlannedStmt *pstmt, PreprocessAlterExtensionCitusStmtForCitusColumnar(parsetree); } - PrevProcessUtility(pstmt, queryString, false, context, - params, queryEnv, dest, completionTag); + if (!ShouldSkipPrevProcessUtility(parsetree)) + { + PrevProcessUtility(pstmt, queryString, false, context, + params, queryEnv, dest, completionTag); + } if (isAlterExtensionUpdateCitusStmt) { @@ -947,6 +951,13 @@ citus_ProcessUtilityInternal(PlannedStmt *pstmt, } +static bool +ShouldSkipPrevProcessUtility(Node *node) +{ + return IsDistributedDropDatabaseCommand(node); +} + + /* * UndistributeDisconnectedCitusLocalTables undistributes citus local tables that * are not connected to any reference tables via their individual foreign key diff --git a/src/backend/distributed/metadata/distobject.c b/src/backend/distributed/metadata/distobject.c index 007d07bdc..15cd6d665 100644 --- a/src/backend/distributed/metadata/distobject.c +++ b/src/backend/distributed/metadata/distobject.c @@ -119,19 +119,6 @@ citus_unmark_object_distributed(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } - if (ObjectExists(&address)) - { - ereport(ERROR, (errmsg("object still exists"), - errdetail("the %s \"%s\" still exists", - getObjectTypeDescription(&address, - - /* missingOk: */ false), - getObjectIdentity(&address, - - /* missingOk: */ false)), - errhint("drop the object via a DROP command"))); - } - UnmarkObjectDistributed(&address); PG_RETURN_VOID(); @@ -457,19 +444,6 @@ UnmarkNodeWideObjectsDistributed(Node *node) UnmarkRolesDistributed(distributedDropRoles); } } - else if (IsA(node, DropdbStmt)) - { - DropdbStmt *stmt = castNode(DropdbStmt, node); - char *dbName = stmt->dbname; - - Oid dbOid = get_database_oid(dbName, stmt->missing_ok); - ObjectAddress *dbObjectAddress = palloc0(sizeof(ObjectAddress)); - ObjectAddressSet(*dbObjectAddress, DatabaseRelationId, dbOid); - if (IsAnyObjectDistributed(list_make1(dbObjectAddress))) - { - UnmarkObjectDistributed(dbObjectAddress); - } - } } diff --git a/src/include/distributed/commands.h b/src/include/distributed/commands.h index de15553e7..e892587f0 100644 --- a/src/include/distributed/commands.h +++ b/src/include/distributed/commands.h @@ -241,6 +241,7 @@ extern List * PreprocessCreateDatabaseStmt(Node *node, const char *queryString, extern List * PostprocessCreateDatabaseStmt(Node *node, const char *queryString); extern List * PreprocessDropDatabaseStmt(Node *node, const char *queryString, ProcessUtilityContext processUtilityContext); +extern bool IsDistributedDropDatabaseCommand(Node *node); extern List * DropDatabaseStmtObjectAddress(Node *node, bool missingOk, bool isPostprocess); extern List * CreateDatabaseStmtObjectAddress(Node *node, bool missingOk,