diff options
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r-- | src/backend/commands/tablecmds.c | 164 |
1 files changed, 136 insertions, 28 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index d22db6e45b1..f3331c69040 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.189 2006/07/02 01:58:36 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.190 2006/07/02 02:23:19 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -62,7 +62,6 @@ #include "utils/relcache.h" #include "utils/syscache.h" - /* * ON COMMIT action list */ @@ -196,6 +195,7 @@ static void ATRewriteTables(List **wqueue); static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap); static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel); static void ATSimplePermissions(Relation rel, bool allowView); +static void ATSimplePermissionsRelationOrIndex(Relation rel); static void ATSimpleRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse); static void ATOneLevelRecursion(List **wqueue, Relation rel, @@ -248,6 +248,7 @@ static void ATExecDropCluster(Relation rel); static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename); static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace); +static void ATExecSetOptions(Relation rel, List *newOptions); static void ATExecEnableDisableTrigger(Relation rel, char *trigname, bool enable, bool skip_system); static void ATExecAddInherits(Relation rel, RangeVar *parent); @@ -285,6 +286,7 @@ DefineRelation(CreateStmt *stmt, char relkind) ListCell *listptr; int i; AttrNumber attnum; + ArrayType *options; /* * Truncate relname to appropriate length (probably a waste of time, as @@ -366,7 +368,7 @@ DefineRelation(CreateStmt *stmt, char relkind) */ descriptor = BuildDescForRelation(schema); - localHasOids = interpretOidsOption(stmt->hasoids); + localHasOids = interpretOidsOption(stmt->options); descriptor->tdhasoid = (localHasOids || parentOidCount > 0); if (old_constraints != NIL) @@ -426,6 +428,7 @@ DefineRelation(CreateStmt *stmt, char relkind) } } + options = OptionBuild(NULL, stmt->options); relationId = heap_create_with_catalog(relname, namespaceId, tablespaceId, @@ -437,7 +440,10 @@ DefineRelation(CreateStmt *stmt, char relkind) localHasOids, parentOidCount, stmt->oncommit, - allowSystemTableMods); + allowSystemTableMods, + options); + if (options) + pfree(options); StoreCatalogInheritance(relationId, inheritOids); @@ -2092,10 +2098,17 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_DROP; break; case AT_SetTableSpace: /* SET TABLESPACE */ + ATSimplePermissionsRelationOrIndex(rel); /* This command never recurses */ ATPrepSetTableSpace(tab, rel, cmd->name); pass = AT_PASS_MISC; /* doesn't actually matter */ break; + case AT_SetOptions: /* SET (...) */ + ATSimplePermissionsRelationOrIndex(rel); + /* This command never recurses */ + /* No command-specific prep needed */ + pass = AT_PASS_MISC; + break; case AT_EnableTrig: /* ENABLE TRIGGER variants */ case AT_EnableTrigAll: case AT_EnableTrigUser: @@ -2266,6 +2279,9 @@ ATExecCmd(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd) * Nothing to do here; Phase 3 does the work */ break; + case AT_SetOptions: /* SET (...) */ + ATExecSetOptions(rel, (List *) cmd->def); + break; case AT_EnableTrig: /* ENABLE TRIGGER name */ ATExecEnableDisableTrigger(rel, cmd->name, true, false); break; @@ -2777,6 +2793,35 @@ ATSimplePermissions(Relation rel, bool allowView) } /* + * ATSimplePermissionsRelationOrIndex + * + * - Ensure that it is a relation or an index + * - Ensure this user is the owner + * - Ensure that it is not a system table + */ +static void +ATSimplePermissionsRelationOrIndex(Relation rel) +{ + if (rel->rd_rel->relkind != RELKIND_RELATION && + rel->rd_rel->relkind != RELKIND_INDEX) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a table or index", + RelationGetRelationName(rel)))); + + /* Permissions checks */ + if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + RelationGetRelationName(rel)); + + if (!allowSystemTableMods && IsSystemRelation(rel)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied: \"%s\" is a system catalog", + RelationGetRelationName(rel)))); +} + +/* * ATSimpleRecursion * * Simple table recursion sufficient for most ALTER TABLE operations. @@ -3804,6 +3849,7 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel, stmt->indexParams, /* parameters */ (Expr *) stmt->whereClause, stmt->rangetable, + stmt->options, stmt->unique, stmt->primary, stmt->isconstraint, @@ -5690,28 +5736,6 @@ ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename) Oid tablespaceId; AclResult aclresult; - /* - * We do our own permission checking because we want to allow this on - * indexes. - */ - if (rel->rd_rel->relkind != RELKIND_RELATION && - rel->rd_rel->relkind != RELKIND_INDEX) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a table or index", - RelationGetRelationName(rel)))); - - /* Permissions checks */ - if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(rel)); - - if (!allowSystemTableMods && IsSystemRelation(rel)) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied: \"%s\" is a system catalog", - RelationGetRelationName(rel)))); - /* Check that the tablespace exists */ tablespaceId = get_tablespace_oid(tablespacename); if (!OidIsValid(tablespaceId)) @@ -5733,6 +5757,89 @@ ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename) } /* + * ALTER TABLE/INDEX SET (...) + */ +static void +ATExecSetOptions(Relation rel, List *newOptions) +{ + Oid relid; + Relation pgclass; + HeapTuple tuple; + Datum datum; + bool isnull; + ArrayType *mergedOptions; + bytea *options; + + if (list_length(newOptions) == 0) + return; /* do nothing */ + + relid = RelationGetRelid(rel); + pgclass = heap_open(RelationRelationId, RowExclusiveLock); + tuple = SearchSysCache(RELOID, + ObjectIdGetDatum(relid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", relid); + + datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions, &isnull); + + mergedOptions = OptionBuild( + isnull ? NULL : DatumGetArrayTypeP(datum), newOptions); + + switch (rel->rd_rel->relkind) + { + case RELKIND_RELATION: + case RELKIND_TOASTVALUE: + options = heap_option(rel->rd_rel->relkind, mergedOptions); + break; + case RELKIND_INDEX: + options = index_option(rel->rd_am->amoption, mergedOptions); + break; + default: + elog(ERROR, "unexpected RELKIND=%c", rel->rd_rel->relkind); + options = NULL; /* keep compiler quiet */ + break; + } + + if (rel->rd_options != options) + { + HeapTuple newtuple; + Datum repl_val[Natts_pg_class]; + char repl_null[Natts_pg_class]; + char repl_repl[Natts_pg_class]; + + /* XXX: This is not necessarily required. */ + if (rel->rd_options) + pfree(rel->rd_options); + rel->rd_options = options; + + memset(repl_repl, ' ', sizeof(repl_repl)); + memset(repl_null, ' ', sizeof(repl_null)); + repl_repl[Anum_pg_class_reloptions - 1] = 'r'; + + if (mergedOptions) + repl_val[Anum_pg_class_reloptions - 1] = + PointerGetDatum(mergedOptions); + else + repl_null[Anum_pg_class_reloptions - 1] = 'n'; + + newtuple = heap_modifytuple(tuple, RelationGetDescr(pgclass), + repl_val, repl_null, repl_repl); + + simple_heap_update(pgclass, &newtuple->t_self, newtuple); + CatalogUpdateIndexes(pgclass, newtuple); + + heap_freetuple(newtuple); + } + + if (mergedOptions) + pfree(mergedOptions); + + ReleaseSysCache(tuple); + heap_close(pgclass, RowExclusiveLock); +} + +/* * Execute ALTER TABLE SET TABLESPACE for cases where there is no tuple * rewriting to be done, so we just want to copy the data as fast as possible. */ @@ -6553,7 +6660,8 @@ AlterTableCreateToastTable(Oid relOid, bool silent) true, 0, ONCOMMIT_NOOP, - true); + true, + NULL); /* make the toast relation visible, else index creation will fail */ CommandCounterIncrement(); @@ -6587,7 +6695,7 @@ AlterTableCreateToastTable(Oid relOid, bool silent) indexInfo, BTREE_AM_OID, rel->rd_rel->reltablespace, - classObjectId, + classObjectId, NIL, true, true, false, true, false); /* |