aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/tablecmds.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2011-08-05 13:24:03 -0400
committerRobert Haas <rhaas@postgresql.org>2011-08-05 13:24:03 -0400
commitc4096c76399ad99dce35cd62f60599ea8748a3dd (patch)
tree01116ffd1816868c388f84afc3b5ecca72b05192 /src/backend/commands/tablecmds.c
parent68cbb9f4e70b7b7ed515b5c63bafbe47d9617bf0 (diff)
downloadpostgresql-c4096c76399ad99dce35cd62f60599ea8748a3dd.tar.gz
postgresql-c4096c76399ad99dce35cd62f60599ea8748a3dd.zip
Allow per-column foreign data wrapper options.
Shigeru Hanada, with fairly minor editing by me.
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r--src/backend/commands/tablecmds.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 82bb756c75e..4509cdab900 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -346,6 +346,8 @@ static void ATPrepAlterColumnType(List **wqueue,
static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
AlterTableCmd *cmd, LOCKMODE lockmode);
+static void ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
+ List *options, LOCKMODE lockmode);
static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode);
static void ATPostAlterTypeParse(Oid oldId, char *cmd,
List **wqueue, LOCKMODE lockmode, bool rewrite);
@@ -2648,6 +2650,7 @@ AlterTableGetLockLevel(List *cmds)
case AT_DropNotNull: /* may change some SQL plans */
case AT_SetNotNull:
case AT_GenericOptions:
+ case AT_AlterColumnGenericOptions:
cmd_lockmode = AccessExclusiveLock;
break;
@@ -2925,6 +2928,12 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd, lockmode);
pass = AT_PASS_ALTER_TYPE;
break;
+ case AT_AlterColumnGenericOptions:
+ ATSimplePermissions(rel, ATT_FOREIGN_TABLE);
+ /* This command never recurses */
+ /* No command-specific prep needed */
+ pass = AT_PASS_MISC;
+ break;
case AT_ChangeOwner: /* ALTER OWNER */
/* This command never recurses */
/* No command-specific prep needed */
@@ -3169,6 +3178,9 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
case AT_AlterColumnType: /* ALTER COLUMN TYPE */
ATExecAlterColumnType(tab, rel, cmd, lockmode);
break;
+ case AT_AlterColumnGenericOptions: /* ALTER COLUMN OPTIONS */
+ ATExecAlterColumnGenericOptions(rel, cmd->name, (List *) cmd->def, lockmode);
+ break;
case AT_ChangeOwner: /* ALTER OWNER */
ATExecChangeOwner(RelationGetRelid(rel),
get_role_oid(cmd->name, false),
@@ -7397,6 +7409,100 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
heap_freetuple(heapTup);
}
+static void
+ATExecAlterColumnGenericOptions(Relation rel,
+ const char *colName,
+ List *options,
+ LOCKMODE lockmode)
+{
+ Relation ftrel;
+ Relation attrel;
+ ForeignServer *server;
+ ForeignDataWrapper *fdw;
+ HeapTuple tuple;
+ HeapTuple newtuple;
+ bool isnull;
+ Datum repl_val[Natts_pg_attribute];
+ bool repl_null[Natts_pg_attribute];
+ bool repl_repl[Natts_pg_attribute];
+ Datum datum;
+ Form_pg_foreign_table fttableform;
+ Form_pg_attribute atttableform;
+
+ if (options == NIL)
+ return;
+
+ /* First, determine FDW validator associated to the foreign table. */
+ ftrel = heap_open(ForeignTableRelationId, AccessShareLock);
+ tuple = SearchSysCache1(FOREIGNTABLEREL, rel->rd_id);
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("foreign table \"%s\" does not exist",
+ RelationGetRelationName(rel))));
+ fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
+ server = GetForeignServer(fttableform->ftserver);
+ fdw = GetForeignDataWrapper(server->fdwid);
+
+ heap_close(ftrel, AccessShareLock);
+ ReleaseSysCache(tuple);
+
+ attrel = heap_open(AttributeRelationId, RowExclusiveLock);
+ tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("column \"%s\" of relation \"%s\" does not exist",
+ colName, RelationGetRelationName(rel))));
+
+ /* Prevent them from altering a system attribute */
+ atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
+ if (atttableform->attnum <= 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot alter system column \"%s\"", colName)));
+
+
+ /* Initialize buffers for new tuple values */
+ memset(repl_val, 0, sizeof(repl_val));
+ memset(repl_null, false, sizeof(repl_null));
+ memset(repl_repl, false, sizeof(repl_repl));
+
+ /* Extract the current options */
+ datum = SysCacheGetAttr(ATTNAME,
+ tuple,
+ Anum_pg_attribute_attfdwoptions,
+ &isnull);
+ if (isnull)
+ datum = PointerGetDatum(NULL);
+
+ /* Transform the options */
+ datum = transformGenericOptions(AttributeRelationId,
+ datum,
+ options,
+ fdw->fdwvalidator);
+
+ if (PointerIsValid(DatumGetPointer(datum)))
+ repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
+ else
+ repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
+
+ repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
+
+ /* Everything looks good - update the tuple */
+
+ newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
+ repl_val, repl_null, repl_repl);
+ ReleaseSysCache(tuple);
+
+ simple_heap_update(attrel, &newtuple->t_self, newtuple);
+ CatalogUpdateIndexes(attrel, newtuple);
+
+ heap_close(attrel, RowExclusiveLock);
+
+ heap_freetuple(newtuple);
+}
+
/*
* Cleanup after we've finished all the ALTER TYPE operations for a
* particular relation. We have to drop and recreate all the indexes