citus/src/backend/distributed/commands/rename.c

185 lines
5.3 KiB
C

/*-------------------------------------------------------------------------
*
* 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"
#include "utils/lsyscache.h"
/*
* 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.
*/
List *
PreprocessRenameStmt(Node *node, const char *renameCommand,
ProcessUtilityContext processUtilityContext)
{
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;
}
/* check whether we are dealing with a sequence here */
if (get_rel_relkind(objectRelationId) == RELKIND_SEQUENCE)
{
RenameStmt *stmtCopy = copyObject(renameStmt);
stmtCopy->renameType = OBJECT_SEQUENCE;
return PreprocessRenameSequenceStmt((Node *) stmtCopy, renameCommand,
processUtilityContext);
}
/* 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 isCitusRelation = IsCitusTable(tableRelationId);
if (!isCitusRelation)
{
return NIL;
}
/*
* We might ERROR out on some commands, but only for Citus tables.
* That's why this test comes this late in the function.
*/
ErrorIfUnsupportedRenameStmt(renameStmt);
if (renameStmt->renameType == OBJECT_TABLE ||
renameStmt->renameType == OBJECT_FOREIGN_TABLE)
{
SwitchToSequentialAndLocalExecutionIfRelationNameTooLong(tableRelationId,
renameStmt->newname);
}
DDLJob *ddlJob = palloc0(sizeof(DDLJob));
ddlJob->targetRelationId = tableRelationId;
ddlJob->commandString = renameCommand;
ddlJob->taskList = DDLTaskList(tableRelationId, renameCommand);
return list_make1(ddlJob);
}
/*
* ErrorIfUnsupportedRenameStmt 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")));
}
}
/*
* PreprocessRenameAttributeStmt called for RenameStmt's that are targetting an attribute eg.
* type attributes. Based on the relation type the attribute gets renamed it dispatches to
* a specialized implementation if present, otherwise return an empty list for its DDLJobs
*/
List *
PreprocessRenameAttributeStmt(Node *node, const char *queryString,
ProcessUtilityContext processUtilityContext)
{
RenameStmt *stmt = castNode(RenameStmt, node);
Assert(stmt->renameType == OBJECT_ATTRIBUTE);
switch (stmt->relationType)
{
case OBJECT_TYPE:
{
return PreprocessRenameTypeAttributeStmt(node, queryString,
processUtilityContext);
}
default:
{
/* unsupported relation for attribute rename, do nothing */
return NIL;
}
}
}