mirror of
https://github.com/postgres/postgres.git
synced 2025-06-16 06:01:02 +03:00
Allow per-column foreign data wrapper options.
Shigeru Hanada, with fairly minor editing by me.
This commit is contained in:
@ -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
|
||||
|
Reference in New Issue
Block a user