diff options
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/tablecmds.c | 66 | ||||
-rw-r--r-- | src/backend/commands/view.c | 26 |
2 files changed, 69 insertions, 23 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 8473c9e7f44..4953def029b 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -366,7 +366,9 @@ static void ATExecDropCluster(Relation rel, LOCKMODE lockmode); static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename, LOCKMODE lockmode); static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode); -static void ATExecSetRelOptions(Relation rel, List *defList, bool isReset, LOCKMODE lockmode); +static void ATExecSetRelOptions(Relation rel, List *defList, + AlterTableType operation, + LOCKMODE lockmode); static void ATExecEnableDisableTrigger(Relation rel, char *trigname, char fires_when, bool skip_system, LOCKMODE lockmode); static void ATExecEnableDisableRule(Relation rel, char *rulename, @@ -2866,6 +2868,7 @@ AlterTableGetLockLevel(List *cmds) case AT_DropCluster: case AT_SetRelOptions: case AT_ResetRelOptions: + case AT_ReplaceRelOptions: case AT_SetOptions: case AT_ResetOptions: case AT_SetStorage: @@ -3094,8 +3097,9 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_MISC; /* doesn't actually matter */ break; case AT_SetRelOptions: /* SET (...) */ - case AT_ResetRelOptions: /* RESET (...) */ - ATSimplePermissions(rel, ATT_TABLE | ATT_INDEX); + case AT_ResetRelOptions: /* RESET (...) */ + case AT_ReplaceRelOptions: /* reset them all, then set just these */ + ATSimplePermissions(rel, ATT_TABLE | ATT_INDEX | ATT_VIEW); /* This command never recurses */ /* No command-specific prep needed */ pass = AT_PASS_MISC; @@ -3338,12 +3342,10 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, */ break; case AT_SetRelOptions: /* SET (...) */ - ATExecSetRelOptions(rel, (List *) cmd->def, false, lockmode); - break; case AT_ResetRelOptions: /* RESET (...) */ - ATExecSetRelOptions(rel, (List *) cmd->def, true, lockmode); + case AT_ReplaceRelOptions: /* replace entire option list */ + ATExecSetRelOptions(rel, (List *) cmd->def, cmd->subtype, lockmode); break; - case AT_EnableTrig: /* ENABLE TRIGGER name */ ATExecEnableDisableTrigger(rel, cmd->name, TRIGGER_FIRES_ON_ORIGIN, false, lockmode); @@ -8271,10 +8273,11 @@ ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename, L } /* - * ALTER TABLE/INDEX SET (...) or RESET (...) + * Set, reset, or replace reloptions. */ static void -ATExecSetRelOptions(Relation rel, List *defList, bool isReset, LOCKMODE lockmode) +ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, + LOCKMODE lockmode) { Oid relid; Relation pgclass; @@ -8288,28 +8291,44 @@ ATExecSetRelOptions(Relation rel, List *defList, bool isReset, LOCKMODE lockmode bool repl_repl[Natts_pg_class]; static char *validnsps[] = HEAP_RELOPT_NAMESPACES; - if (defList == NIL) + if (defList == NIL && operation != AT_ReplaceRelOptions) return; /* nothing to do */ pgclass = heap_open(RelationRelationId, RowExclusiveLock); - /* Get the old reloptions */ + /* Fetch heap tuple */ relid = RelationGetRelid(rel); tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for relation %u", relid); - datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions, &isnull); + if (operation == AT_ReplaceRelOptions) + { + /* + * If we're supposed to replace the reloptions list, we just pretend + * there were none before. + */ + datum = (Datum) 0; + isnull = true; + } + else + { + /* Get the old reloptions */ + datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions, + &isnull); + } /* Generate new proposed reloptions (text array) */ newOptions = transformRelOptions(isnull ? (Datum) 0 : datum, - defList, NULL, validnsps, false, isReset); + defList, NULL, validnsps, false, + operation == AT_ResetRelOptions); /* Validate */ switch (rel->rd_rel->relkind) { case RELKIND_RELATION: case RELKIND_TOASTVALUE: + case RELKIND_VIEW: (void) heap_reloptions(rel->rd_rel->relkind, newOptions, true); break; case RELKIND_INDEX: @@ -8357,15 +8376,30 @@ ATExecSetRelOptions(Relation rel, List *defList, bool isReset, LOCKMODE lockmode toastrel = heap_open(toastid, lockmode); - /* Get the old reloptions */ + /* Fetch heap tuple */ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(toastid)); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for relation %u", toastid); - datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions, &isnull); + if (operation == AT_ReplaceRelOptions) + { + /* + * If we're supposed to replace the reloptions list, we just + * pretend there were none before. + */ + datum = (Datum) 0; + isnull = true; + } + else + { + /* Get the old reloptions */ + datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions, + &isnull); + } newOptions = transformRelOptions(isnull ? (Datum) 0 : datum, - defList, "toast", validnsps, false, isReset); + defList, "toast", validnsps, false, + operation == AT_ResetRelOptions); (void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true); diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index b2381996586..3edcd33eaf4 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -32,6 +32,7 @@ #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/rel.h" +#include "utils/syscache.h" static void checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc); @@ -98,7 +99,7 @@ isViewOnTempTable_walker(Node *node, void *context) */ static Oid DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace, - Oid namespaceId) + Oid namespaceId, List *options) { Oid viewOid; CreateStmt *createStmt = makeNode(CreateStmt); @@ -166,6 +167,8 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace, { Relation rel; TupleDesc descriptor; + List *atcmds = NIL; + AlterTableCmd *atcmd; /* * Yes. Get exclusive lock on the existing view ... @@ -204,20 +207,26 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace, checkViewTupleDesc(descriptor, rel->rd_att); /* + * The new options list replaces the existing options list, even + * if it's empty. + */ + atcmd = makeNode(AlterTableCmd); + atcmd->subtype = AT_ReplaceRelOptions; + atcmd->def = (Node *) options; + atcmds = lappend(atcmds, atcmd); + + /* * If new attributes have been added, we must add pg_attribute entries * for them. It is convenient (although overkill) to use the ALTER * TABLE ADD COLUMN infrastructure for this. */ if (list_length(attrList) > rel->rd_att->natts) { - List *atcmds = NIL; ListCell *c; int skip = rel->rd_att->natts; foreach(c, attrList) { - AlterTableCmd *atcmd; - if (skip > 0) { skip--; @@ -228,9 +237,11 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace, atcmd->def = (Node *) lfirst(c); atcmds = lappend(atcmds, atcmd); } - AlterTableInternal(viewOid, atcmds, true); } + /* OK, let's do it. */ + AlterTableInternal(viewOid, atcmds, true); + /* * Seems okay, so return the OID of the pre-existing view. */ @@ -250,7 +261,8 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace, createStmt->tableElts = attrList; createStmt->inhRelations = NIL; createStmt->constraints = NIL; - createStmt->options = list_make1(defWithOids(false)); + createStmt->options = options; + createStmt->options = lappend(options, defWithOids(false)); createStmt->oncommit = ONCOMMIT_NOOP; createStmt->tablespacename = NULL; createStmt->if_not_exists = false; @@ -513,7 +525,7 @@ DefineView(ViewStmt *stmt, const char *queryString) * aborted. */ viewOid = DefineVirtualRelation(view, viewParse->targetList, - stmt->replace, namespaceId); + stmt->replace, namespaceId, stmt->options); /* * The relation we have just created is not visible to any other commands |