diff options
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r-- | src/backend/commands/tablecmds.c | 357 |
1 files changed, 231 insertions, 126 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 97a9725df75..03dfd2e7fa6 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -398,8 +398,7 @@ static void ATRewriteTables(AlterTableStmt *parsetree, AlterTableUtilityContext *context); static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode); static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel); -static void ATSimplePermissions(Relation rel, int allowed_targets); -static void ATWrongRelkindError(Relation rel, int allowed_targets); +static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets); static void ATSimpleRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context); @@ -3394,8 +3393,9 @@ renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing) relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a table, view, materialized view, composite type, index, or foreign table", - NameStr(classform->relname)))); + errmsg("cannot rename columns of relation \"%s\"", + NameStr(classform->relname)), + errdetail_relkind_not_supported(relkind))); /* * permissions checking. only the owner of a class can change its schema. @@ -4422,7 +4422,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, switch (cmd->subtype) { case AT_AddColumn: /* ADD COLUMN */ - ATSimplePermissions(rel, + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE); ATPrepAddColumn(wqueue, rel, recurse, recursing, false, cmd, lockmode, context); @@ -4430,7 +4430,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_ADD_COL; break; case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */ - ATSimplePermissions(rel, ATT_VIEW); + ATSimplePermissions(cmd->subtype, rel, ATT_VIEW); ATPrepAddColumn(wqueue, rel, recurse, recursing, true, cmd, lockmode, context); /* Recursion occurs during execution phase */ @@ -4444,7 +4444,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, * substitutes default values into INSERTs before it expands * rules. */ - ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE); ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context); /* No command-specific prep needed */ pass = cmd->def ? AT_PASS_ADD_OTHERCONSTR : AT_PASS_DROP; @@ -4452,77 +4452,77 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, case AT_CookedColumnDefault: /* add a pre-cooked default */ /* This is currently used only in CREATE TABLE */ /* (so the permission check really isn't necessary) */ - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE); /* This command never recurses */ pass = AT_PASS_ADD_OTHERCONSTR; break; case AT_AddIdentity: - ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE); /* This command never recurses */ pass = AT_PASS_ADD_OTHERCONSTR; break; case AT_SetIdentity: - ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE); /* This command never recurses */ /* This should run after AddIdentity, so do it in MISC pass */ pass = AT_PASS_MISC; break; case AT_DropIdentity: - ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE); /* This command never recurses */ pass = AT_PASS_DROP; break; case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */ - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE); ATPrepDropNotNull(rel, recurse, recursing); ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context); pass = AT_PASS_DROP; break; case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */ - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE); /* Need command-specific recursion decision */ ATPrepSetNotNull(wqueue, rel, cmd, recurse, recursing, lockmode, context); pass = AT_PASS_COL_ATTRS; break; case AT_CheckNotNull: /* check column is already marked NOT NULL */ - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE); ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context); /* No command-specific prep needed */ pass = AT_PASS_COL_ATTRS; break; case AT_DropExpression: /* ALTER COLUMN DROP EXPRESSION */ - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE); ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context); ATPrepDropExpression(rel, cmd, recurse, recursing, lockmode); pass = AT_PASS_DROP; break; case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */ - ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE); ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context); /* No command-specific prep needed */ pass = AT_PASS_MISC; break; case AT_SetOptions: /* ALTER COLUMN SET ( options ) */ case AT_ResetOptions: /* ALTER COLUMN RESET ( options ) */ - ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_FOREIGN_TABLE); /* This command never recurses */ pass = AT_PASS_MISC; break; case AT_SetStorage: /* ALTER COLUMN SET STORAGE */ - ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE); ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context); /* No command-specific prep needed */ pass = AT_PASS_MISC; break; case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */ - ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW); /* This command never recurses */ /* No command-specific prep needed */ pass = AT_PASS_MISC; break; case AT_DropColumn: /* DROP COLUMN */ - ATSimplePermissions(rel, + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE); ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd, lockmode, context); @@ -4530,13 +4530,13 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_DROP; break; case AT_AddIndex: /* ADD INDEX */ - ATSimplePermissions(rel, ATT_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE); /* This command never recurses */ /* No command-specific prep needed */ pass = AT_PASS_ADD_INDEX; break; case AT_AddConstraint: /* ADD CONSTRAINT */ - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE); /* Recursion occurs during execution phase */ /* No command-specific prep needed except saving recurse flag */ if (recurse) @@ -4544,13 +4544,13 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_ADD_CONSTR; break; case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */ - ATSimplePermissions(rel, ATT_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE); /* This command never recurses */ /* No command-specific prep needed */ pass = AT_PASS_ADD_INDEXCONSTR; break; case AT_DropConstraint: /* DROP CONSTRAINT */ - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE); ATCheckPartitionsNotInUse(rel, lockmode); /* Other recursion occurs during execution phase */ /* No command-specific prep needed except saving recurse flag */ @@ -4559,7 +4559,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_DROP; break; case AT_AlterColumnType: /* ALTER COLUMN TYPE */ - ATSimplePermissions(rel, + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE); /* See comments for ATPrepAlterColumnType */ cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, recurse, lockmode, @@ -4571,7 +4571,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_ALTER_TYPE; break; case AT_AlterColumnGenericOptions: - ATSimplePermissions(rel, ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_FOREIGN_TABLE); /* This command never recurses */ /* No command-specific prep needed */ pass = AT_PASS_MISC; @@ -4583,13 +4583,13 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, break; case AT_ClusterOn: /* CLUSTER ON */ case AT_DropCluster: /* SET WITHOUT CLUSTER */ - ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW); /* These commands never recurse */ /* No command-specific prep needed */ pass = AT_PASS_MISC; break; case AT_SetLogged: /* SET LOGGED */ - ATSimplePermissions(rel, ATT_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE); if (tab->chgPersistence) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -4604,7 +4604,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_MISC; break; case AT_SetUnLogged: /* SET UNLOGGED */ - ATSimplePermissions(rel, ATT_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE); if (tab->chgPersistence) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -4619,11 +4619,11 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_MISC; break; case AT_DropOids: /* SET WITHOUT OIDS */ - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE); pass = AT_PASS_DROP; break; case AT_SetTableSpace: /* SET TABLESPACE */ - ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX); /* This command never recurses */ ATPrepSetTableSpace(tab, rel, cmd->name, lockmode); @@ -4632,30 +4632,30 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, case AT_SetRelOptions: /* SET (...) */ case AT_ResetRelOptions: /* RESET (...) */ case AT_ReplaceRelOptions: /* reset them all, then set just these */ - ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX); /* This command never recurses */ /* No command-specific prep needed */ pass = AT_PASS_MISC; break; case AT_AddInherit: /* INHERIT */ - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE); /* This command never recurses */ ATPrepAddInherit(rel); pass = AT_PASS_MISC; break; case AT_DropInherit: /* NO INHERIT */ - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE); /* This command never recurses */ /* No command-specific prep needed */ pass = AT_PASS_MISC; break; case AT_AlterConstraint: /* ALTER CONSTRAINT */ - ATSimplePermissions(rel, ATT_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE); /* Recursion occurs during execution phase */ pass = AT_PASS_MISC; break; case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */ - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE); /* Recursion occurs during execution phase */ /* No command-specific prep needed except saving recurse flag */ if (recurse) @@ -4663,7 +4663,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_MISC; break; case AT_ReplicaIdentity: /* REPLICA IDENTITY ... */ - ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW); pass = AT_PASS_MISC; /* This command never recurses */ /* No command-specific prep needed */ @@ -4676,7 +4676,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, case AT_DisableTrig: /* DISABLE TRIGGER variants */ case AT_DisableTrigAll: case AT_DisableTrigUser: - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE); if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context); pass = AT_PASS_MISC; @@ -4691,28 +4691,28 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, case AT_DisableRowSecurity: case AT_ForceRowSecurity: case AT_NoForceRowSecurity: - ATSimplePermissions(rel, ATT_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE); /* These commands never recurse */ /* No command-specific prep needed */ pass = AT_PASS_MISC; break; case AT_GenericOptions: - ATSimplePermissions(rel, ATT_FOREIGN_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_FOREIGN_TABLE); /* No command-specific prep needed */ pass = AT_PASS_MISC; break; case AT_AttachPartition: - ATSimplePermissions(rel, ATT_TABLE | ATT_PARTITIONED_INDEX); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_PARTITIONED_INDEX); /* No command-specific prep needed */ pass = AT_PASS_MISC; break; case AT_DetachPartition: - ATSimplePermissions(rel, ATT_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE); /* No command-specific prep needed */ pass = AT_PASS_MISC; break; case AT_DetachPartitionFinalize: - ATSimplePermissions(rel, ATT_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE); /* No command-specific prep needed */ pass = AT_PASS_MISC; break; @@ -5941,6 +5941,145 @@ ATGetQueueEntry(List **wqueue, Relation rel) return tab; } +static const char * +alter_table_type_to_string(AlterTableType cmdtype) +{ + switch (cmdtype) + { + case AT_AddColumn: + case AT_AddColumnRecurse: + case AT_AddColumnToView: + return "ADD COLUMN"; + case AT_ColumnDefault: + case AT_CookedColumnDefault: + return "ALTER COLUMN ... SET DEFAULT"; + case AT_DropNotNull: + return "ALTER COLUMN ... DROP NOT NULL"; + case AT_SetNotNull: + return "ALTER COLUMN ... SET NOT NULL"; + case AT_DropExpression: + return "ALTER COLUMN ... DROP EXPRESSION"; + case AT_CheckNotNull: + return NULL; /* not real grammar */ + case AT_SetStatistics: + return "ALTER COLUMN ... SET STATISTICS"; + case AT_SetOptions: + return "ALTER COLUMN ... SET"; + case AT_ResetOptions: + return "ALTER COLUMN ... RESET"; + case AT_SetStorage: + return "ALTER COLUMN ... SET STORAGE"; + case AT_SetCompression: + return "ALTER COLUMN ... SET COMPRESSION"; + case AT_DropColumn: + case AT_DropColumnRecurse: + return "DROP COLUMN"; + case AT_AddIndex: + case AT_ReAddIndex: + return NULL; /* not real grammar */ + case AT_AddConstraint: + case AT_AddConstraintRecurse: + case AT_ReAddConstraint: + case AT_ReAddDomainConstraint: + case AT_AddIndexConstraint: + return "ADD CONSTRAINT"; + case AT_AlterConstraint: + return "ALTER CONSTRAINT"; + case AT_ValidateConstraint: + case AT_ValidateConstraintRecurse: + return "VALIDATE CONSTRAINT"; + case AT_DropConstraint: + case AT_DropConstraintRecurse: + return "DROP CONSTRAINT"; + case AT_ReAddComment: + return NULL; /* not real grammar */ + case AT_AlterColumnType: + return "ALTER COLUMN ... SET DATA TYPE"; + case AT_AlterColumnGenericOptions: + return "ALTER COLUMN ... OPTIONS"; + case AT_ChangeOwner: + return "OWNER TO"; + case AT_ClusterOn: + return "CLUSTER ON"; + case AT_DropCluster: + return "SET WITHOUT CLUSTER"; + case AT_SetLogged: + return "SET LOGGED"; + case AT_SetUnLogged: + return "SET UNLOGGED"; + case AT_DropOids: + return "SET WITHOUT OIDS"; + case AT_SetTableSpace: + return "SET TABLESPACE"; + case AT_SetRelOptions: + return "SET"; + case AT_ResetRelOptions: + return "RESET"; + case AT_ReplaceRelOptions: + return NULL; /* not real grammar */ + case AT_EnableTrig: + return "ENABLE TRIGGER"; + case AT_EnableAlwaysTrig: + return "ENABLE ALWAYS TRIGGER"; + case AT_EnableReplicaTrig: + return "ENABLE REPLICA TRIGGER"; + case AT_DisableTrig: + return "DISABLE TRIGGER"; + case AT_EnableTrigAll: + return "ENABLE TRIGGER ALL"; + case AT_DisableTrigAll: + return "DISABLE TRIGGER ALL"; + case AT_EnableTrigUser: + return "ENABLE TRIGGER USER"; + case AT_DisableTrigUser: + return "DISABLE TRIGGER USER"; + case AT_EnableRule: + return "ENABLE RULE"; + case AT_EnableAlwaysRule: + return "ENABLE ALWAYS RULE"; + case AT_EnableReplicaRule: + return "ENABLE REPLICA RULE"; + case AT_DisableRule: + return "DISABLE RULE"; + case AT_AddInherit: + return "INHERIT"; + case AT_DropInherit: + return "NO INHERIT"; + case AT_AddOf: + return "OF"; + case AT_DropOf: + return "NOT OF"; + case AT_ReplicaIdentity: + return "REPLICA IDENTITY"; + case AT_EnableRowSecurity: + return "ENABLE ROW SECURITY"; + case AT_DisableRowSecurity: + return "DISABLE ROW SECURITY"; + case AT_ForceRowSecurity: + return "FORCE ROW SECURITY"; + case AT_NoForceRowSecurity: + return "NO FORCE ROW SECURITY"; + case AT_GenericOptions: + return "OPTIONS"; + case AT_AttachPartition: + return "ATTACH PARTITION"; + case AT_DetachPartition: + return "DETACH PARTITION"; + case AT_DetachPartitionFinalize: + return "DETACH PARTITION ... FINALIZE"; + case AT_AddIdentity: + return "ALTER COLUMN ... ADD IDENTITY"; + case AT_SetIdentity: + return "ALTER COLUMN ... SET"; + case AT_DropIdentity: + return "ALTER COLUMN ... DROP IDENTITY"; + case AT_ReAddStatistics: + return NULL; /* not real grammar */ + } + + return NULL; +} + /* * ATSimplePermissions * @@ -5949,7 +6088,7 @@ ATGetQueueEntry(List **wqueue, Relation rel) * - Ensure that it is not a system table */ static void -ATSimplePermissions(Relation rel, int allowed_targets) +ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets) { int actual_target; @@ -5984,7 +6123,21 @@ ATSimplePermissions(Relation rel, int allowed_targets) /* Wrong target type? */ if ((actual_target & allowed_targets) == 0) - ATWrongRelkindError(rel, allowed_targets); + { + const char *action_str = alter_table_type_to_string(cmdtype); + + if (action_str) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + /* translator: %s is a group of some SQL keywords */ + errmsg("ALTER action %s cannot be performed on relation \"%s\"", + action_str, RelationGetRelationName(rel)), + errdetail_relkind_not_supported(rel->rd_rel->relkind))); + else + /* internal error? */ + elog(ERROR, "invalid ALTER action attempted on relation \"%s\"", + RelationGetRelationName(rel)); + } /* Permissions checks */ if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId())) @@ -5999,66 +6152,6 @@ ATSimplePermissions(Relation rel, int allowed_targets) } /* - * ATWrongRelkindError - * - * Throw an error when a relation has been determined to be of the wrong - * type. - */ -static void -ATWrongRelkindError(Relation rel, int allowed_targets) -{ - char *msg; - - switch (allowed_targets) - { - case ATT_TABLE: - msg = _("\"%s\" is not a table"); - break; - case ATT_TABLE | ATT_VIEW: - msg = _("\"%s\" is not a table or view"); - break; - case ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE: - msg = _("\"%s\" is not a table, view, or foreign table"); - break; - case ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX: - msg = _("\"%s\" is not a table, view, materialized view, or index"); - break; - case ATT_TABLE | ATT_MATVIEW: - msg = _("\"%s\" is not a table or materialized view"); - break; - case ATT_TABLE | ATT_MATVIEW | ATT_INDEX: - msg = _("\"%s\" is not a table, materialized view, or index"); - break; - case ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE: - msg = _("\"%s\" is not a table, materialized view, or foreign table"); - break; - case ATT_TABLE | ATT_FOREIGN_TABLE: - msg = _("\"%s\" is not a table or foreign table"); - break; - case ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE: - msg = _("\"%s\" is not a table, composite type, or foreign table"); - break; - case ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_FOREIGN_TABLE: - msg = _("\"%s\" is not a table, materialized view, index, or foreign table"); - break; - case ATT_VIEW: - msg = _("\"%s\" is not a view"); - break; - case ATT_FOREIGN_TABLE: - msg = _("\"%s\" is not a foreign table"); - break; - default: - /* shouldn't get here, add all necessary cases above */ - msg = _("\"%s\" is of the wrong type"); - break; - } - - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg(msg, RelationGetRelationName(rel)))); -} - -/* * ATSimpleRecursion * * Simple table recursion sufficient for most ALTER TABLE operations. @@ -6452,7 +6545,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, /* At top level, permission check was done in ATPrepCmd, else do it */ if (recursing) - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions((*cmd)->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE); if (rel->rd_rel->relispartition && !recursing) ereport(ERROR, @@ -8186,7 +8279,7 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, /* At top level, permission check was done in ATPrepCmd, else do it */ if (recursing) - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(AT_DropColumn, rel, ATT_TABLE | ATT_FOREIGN_TABLE); /* Initialize addrs on the first invocation */ Assert(!recursing || addrs != NULL); @@ -8670,7 +8763,7 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, /* At top level, permission check was done in ATPrepCmd, else do it */ if (recursing) - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(AT_AddConstraint, rel, ATT_TABLE | ATT_FOREIGN_TABLE); /* * Call AddRelationNewConstraints to do the work, making sure it works on @@ -11286,7 +11379,7 @@ ATExecDropConstraint(Relation rel, const char *constrName, /* At top level, permission check was done in ATPrepCmd, else do it */ if (recursing) - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(AT_DropConstraint, rel, ATT_TABLE | ATT_FOREIGN_TABLE); conrel = table_open(ConstraintRelationId, RowExclusiveLock); @@ -13205,8 +13298,9 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock default: ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a table, view, sequence, or foreign table", - NameStr(tuple_class->relname)))); + errmsg("cannot change owner of relation \"%s\"", + NameStr(tuple_class->relname)), + errdetail_relkind_not_supported(tuple_class->relkind))); } /* @@ -13621,8 +13715,9 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, default: ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a table, view, materialized view, index, or TOAST table", - RelationGetRelationName(rel)))); + errmsg("cannot set options for relation \"%s\"", + RelationGetRelationName(rel)), + errdetail_relkind_not_supported(rel->rd_rel->relkind))); break; } @@ -14176,7 +14271,7 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode) * Must be owner of both parent and child -- child was checked by * ATSimplePermissions call in ATPrepCmd */ - ATSimplePermissions(parent_rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(AT_AddInherit, parent_rel, ATT_TABLE | ATT_FOREIGN_TABLE); /* Permanent rels cannot inherit from temporary ones */ if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP && @@ -16505,17 +16600,27 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, * Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved * to a different schema, such as indexes and TOAST tables. */ - if (IsA(stmt, AlterObjectSchemaStmt) && - relkind != RELKIND_RELATION && - relkind != RELKIND_VIEW && - relkind != RELKIND_MATVIEW && - relkind != RELKIND_SEQUENCE && - relkind != RELKIND_FOREIGN_TABLE && - relkind != RELKIND_PARTITIONED_TABLE) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a table, view, materialized view, sequence, or foreign table", - rv->relname))); + if (IsA(stmt, AlterObjectSchemaStmt)) + { + if (relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot change schema of index \"%s\"", + rv->relname), + errhint("Change the schema of the table instead."))); + else if (relkind == RELKIND_COMPOSITE_TYPE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot change schema of composite type \"%s\"", + rv->relname), + errhint("Use ALTER TYPE instead."))); + else if (relkind == RELKIND_TOASTVALUE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot change schema of TOAST table \"%s\"", + rv->relname), + errhint("Change the schema of the table instead."))); + } ReleaseSysCache(tuple); } @@ -17077,7 +17182,7 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd, * Must be owner of both parent and source table -- parent was checked by * ATSimplePermissions call in ATPrepCmd */ - ATSimplePermissions(attachrel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(AT_AttachPartition, attachrel, ATT_TABLE | ATT_FOREIGN_TABLE); /* A partition can only have one parent */ if (attachrel->rd_rel->relispartition) |