mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
Improve error messages about mismatching relkind
Most error messages about a relkind that was not supported or appropriate for the command was of the pattern "relation \"%s\" is not a table, foreign table, or materialized view" This style can become verbose and tedious to maintain. Moreover, it's not very helpful: If I'm trying to create a comment on a TOAST table, which is not supported, then the information that I could have created a comment on a materialized view is pointless. Instead, write the primary error message shorter and saying more directly that what was attempted is not possible. Then, in the detail message, explain that the operation is not supported for the relkind the object was. To simplify that, add a new function errdetail_relkind_not_supported() that does this. In passing, make use of RELKIND_HAS_STORAGE() where appropriate, instead of listing out the relkinds individually. Reviewed-by: Michael Paquier <michael@paquier.xyz> Reviewed-by: Alvaro Herrera <alvherre@alvh.no-ip.org> Discussion: https://www.postgresql.org/message-id/flat/dc35a398-37d0-75ce-07ea-1dd71d98f8ec@2ndquadrant.com
This commit is contained in:
@ -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()))
|
||||
@ -5998,66 +6151,6 @@ ATSimplePermissions(Relation rel, int allowed_targets)
|
||||
RelationGetRelationName(rel))));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
@ -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)
|
||||
|
Reference in New Issue
Block a user