/*------------------------------------------------------------------------- * * rename.c * Commands for renaming objects related to distributed tables * * Copyright (c) Citus Data, Inc. * *------------------------------------------------------------------------- */ #include "postgres.h" #include "catalog/index.h" #include "catalog/namespace.h" #include "distributed/commands.h" #include "distributed/commands/utility_hook.h" #include "distributed/metadata_cache.h" #include "nodes/parsenodes.h" /* DistributeObjectOps */ static List * PreprocessRenameStmt(Node *node, const char *renameCommand); static DistributeObjectOps Any_Rename = { .deparse = NULL, .qualify = NULL, .preprocess = PreprocessRenameStmt, .postprocess = NULL, .address = NULL, }; REGISTER_DISTRIBUTED_OPERATION_NESTED(RenameStmt, renameType, OBJECT_TABLE, Any_Rename); REGISTER_DISTRIBUTED_OPERATION_NESTED(RenameStmt, renameType, OBJECT_FOREIGN_TABLE, Any_Rename); REGISTER_DISTRIBUTED_OPERATION_NESTED(RenameStmt, renameType, OBJECT_COLUMN, Any_Rename); REGISTER_DISTRIBUTED_OPERATION_NESTED(RenameStmt, renameType, OBJECT_TABCONSTRAINT, Any_Rename); REGISTER_DISTRIBUTED_OPERATION_NESTED(RenameStmt, renameType, OBJECT_INDEX, Any_Rename); /* * PreprocessRenameStmt first determines whether a given rename statement involves * a distributed table. If so (and if it is supported, i.e. renames a column), * it creates a DDLJob to encapsulate information needed during the worker node * portion of DDL execution before returning that DDLJob in a List. If no dis- * tributed table is involved, this function returns NIL. */ static List * PreprocessRenameStmt(Node *node, const char *renameCommand) { RenameStmt *renameStmt = castNode(RenameStmt, node); Oid objectRelationId = InvalidOid; /* SQL Object OID */ Oid tableRelationId = InvalidOid; /* Relation OID, maybe not the same. */ /* * We only support some of the PostgreSQL supported RENAME statements, and * our list include only renaming table and index (related) objects. */ if (!IsAlterTableRenameStmt(renameStmt) && !IsIndexRenameStmt(renameStmt) && !IsPolicyRenameStmt(renameStmt)) { return NIL; } /* * The lock levels here should be same as the ones taken in * RenameRelation(), renameatt() and RenameConstraint(). However, since all * three statements have identical lock levels, we just use a single statement. */ objectRelationId = RangeVarGetRelid(renameStmt->relation, AccessExclusiveLock, renameStmt->missing_ok); /* * If the table does not exist, don't do anything here to allow PostgreSQL * to throw the appropriate error or notice message later. */ if (!OidIsValid(objectRelationId)) { return NIL; } /* we have no planning to do unless the table is distributed */ switch (renameStmt->renameType) { case OBJECT_TABLE: case OBJECT_FOREIGN_TABLE: case OBJECT_COLUMN: case OBJECT_TABCONSTRAINT: case OBJECT_POLICY: { /* the target object is our tableRelationId. */ tableRelationId = objectRelationId; break; } case OBJECT_INDEX: { /* * here, objRelationId points to the index relation entry, and we * are interested into the entry of the table on which the index is * defined. */ tableRelationId = IndexGetRelation(objectRelationId, false); break; } default: /* * Nodes that are not supported by Citus: we pass-through to the * main PostgreSQL executor. Any Citus-supported RenameStmt * renameType must appear above in the switch, explicitly. */ return NIL; } bool isDistributedRelation = IsDistributedTable(tableRelationId); if (!isDistributedRelation) { return NIL; } /* * We might ERROR out on some commands, but only for Citus tables where * isDistributedRelation is true. That's why this test comes this late in * the function. */ ErrorIfUnsupportedRenameStmt(renameStmt); DDLJob *ddlJob = palloc0(sizeof(DDLJob)); ddlJob->targetRelationId = tableRelationId; ddlJob->concurrentIndexCmd = false; ddlJob->commandString = renameCommand; ddlJob->taskList = DDLTaskList(tableRelationId, renameCommand); return list_make1(ddlJob); } /* * ErrorIfDistributedRenameStmt errors out if the corresponding rename statement * operates on any part of a distributed table other than a column. * * Note: This function handles RenameStmt applied to relations handed by Citus. * At the moment of writing this comment, it could be either tables or indexes. */ void ErrorIfUnsupportedRenameStmt(RenameStmt *renameStmt) { if (IsAlterTableRenameStmt(renameStmt) && renameStmt->renameType == OBJECT_TABCONSTRAINT) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("renaming constraints belonging to distributed tables is " "currently unsupported"))); } }