Allow per-column foreign data wrapper options.
Shigeru Hanada, with fairly minor editing by me.
This commit is contained in:
parent
68cbb9f4e7
commit
c4096c7639
@ -1157,6 +1157,15 @@
|
|||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>attfdwoptions</structfield></entry>
|
||||||
|
<entry><type>text[]</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>
|
||||||
|
Attribute-level foreign data wrapper options, as <quote>keyword=value</> strings
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</table>
|
||||||
|
@ -1018,6 +1018,69 @@
|
|||||||
</table>
|
</table>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="infoschema-column-options">
|
||||||
|
<title><literal>column_options</literal></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The view <literal>column_options</literal> contains all the
|
||||||
|
options defined for foreign table columns in the current database. Only
|
||||||
|
those foreign table columns are shown that the current user has access to
|
||||||
|
(by way of being the owner or having some privilege).
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<title><literal>column_options</literal> Columns</title>
|
||||||
|
|
||||||
|
<tgroup cols="3">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Name</entry>
|
||||||
|
<entry>Data Type</entry>
|
||||||
|
<entry>Description</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry><literal>table_catalog</literal></entry>
|
||||||
|
<entry><type>sql_identifier</type></entry>
|
||||||
|
<entry>Name of the database that contains the foreign table (always the current database)</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><literal>table_schema</literal></entry>
|
||||||
|
<entry><type>sql_identifier</type></entry>
|
||||||
|
<entry>Name of the schema that contains the foreign table</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><literal>table_name</literal></entry>
|
||||||
|
<entry><type>sql_identifier</type></entry>
|
||||||
|
<entry>Name of the foreign table</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><literal>column_name</literal></entry>
|
||||||
|
<entry><type>sql_identifier</type></entry>
|
||||||
|
<entry>Name of the column</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><literal>option_name</literal></entry>
|
||||||
|
<entry><type>sql_identifier</type></entry>
|
||||||
|
<entry>Name of an option</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><literal>option_value</literal></entry>
|
||||||
|
<entry><type>character_data</type></entry>
|
||||||
|
<entry>Value of the option</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="infoschema-column-privileges">
|
<sect1 id="infoschema-column-privileges">
|
||||||
<title><literal>column_privileges</literal></title>
|
<title><literal>column_privileges</literal></title>
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ ALTER FOREIGN TABLE <replaceable class="PARAMETER">name</replaceable>
|
|||||||
DROP [ COLUMN ] [ IF EXISTS ] <replaceable class="PARAMETER">column</replaceable> [ RESTRICT | CASCADE ]
|
DROP [ COLUMN ] [ IF EXISTS ] <replaceable class="PARAMETER">column</replaceable> [ RESTRICT | CASCADE ]
|
||||||
ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">type</replaceable>
|
ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">type</replaceable>
|
||||||
ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> { SET | DROP } NOT NULL
|
ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> { SET | DROP } NOT NULL
|
||||||
|
ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> OPTIONS ( [ ADD | SET | DROP ] <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ])
|
||||||
OWNER TO <replaceable class="PARAMETER">new_owner</replaceable>
|
OWNER TO <replaceable class="PARAMETER">new_owner</replaceable>
|
||||||
OPTIONS ( [ ADD | SET | DROP ] <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ])
|
OPTIONS ( [ ADD | SET | DROP ] <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ])
|
||||||
</synopsis>
|
</synopsis>
|
||||||
@ -125,12 +126,13 @@ ALTER FOREIGN TABLE <replaceable class="PARAMETER">name</replaceable>
|
|||||||
<term><literal>OPTIONS ( [ ADD | SET | DROP ] <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ] )</literal></term>
|
<term><literal>OPTIONS ( [ ADD | SET | DROP ] <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ] )</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Change options for the foreign table.
|
Change options for the foreign table or one of its columns.
|
||||||
<literal>ADD</>, <literal>SET</>, and <literal>DROP</>
|
<literal>ADD</>, <literal>SET</>, and <literal>DROP</>
|
||||||
specify the action to be performed. <literal>ADD</> is assumed
|
specify the action to be performed. <literal>ADD</> is assumed
|
||||||
if no operation is explicitly specified. Option names must be
|
if no operation is explicitly specified. Duplicate option names are not
|
||||||
unique; names and values are also validated using the foreign
|
allowed (although it's OK for a table option and a column option to have
|
||||||
data wrapper library.
|
the same name). Option names and values are also validated using the
|
||||||
|
foreign data wrapper library.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
<synopsis>
|
<synopsis>
|
||||||
CREATE FOREIGN TABLE [ IF NOT EXISTS ] <replaceable class="PARAMETER">table_name</replaceable> ( [
|
CREATE FOREIGN TABLE [ IF NOT EXISTS ] <replaceable class="PARAMETER">table_name</replaceable> ( [
|
||||||
{ <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ NULL | NOT NULL ] }
|
{ <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [, ... ] ) ] [ NULL | NOT NULL ] }
|
||||||
[, ... ]
|
[, ... ]
|
||||||
] )
|
] )
|
||||||
SERVER <replaceable class="parameter">server_name</replaceable>
|
SERVER <replaceable class="parameter">server_name</replaceable>
|
||||||
@ -138,10 +138,12 @@ CREATE FOREIGN TABLE [ IF NOT EXISTS ] <replaceable class="PARAMETER">table_name
|
|||||||
<term><literal>OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [, ...] )</literal></term>
|
<term><literal>OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [, ...] )</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Options to be associated with the new foreign table.
|
Options to be associated with the new foreign table or one of its
|
||||||
|
columns.
|
||||||
The allowed option names and values are specific to each foreign
|
The allowed option names and values are specific to each foreign
|
||||||
data wrapper and are validated using the foreign-data wrapper's
|
data wrapper and are validated using the foreign-data wrapper's
|
||||||
validator function. Option names must be unique.
|
validator function. Duplicate option names are not allowed (although
|
||||||
|
it's OK for a table option and a column option to have the same name).
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@ -891,6 +891,12 @@ testdb=>
|
|||||||
below.)
|
below.)
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For some types of relation, <literal>\d</> shows additional information
|
||||||
|
for each column: column values for sequences, indexed expression for
|
||||||
|
indexes and per-column foreign data wrapper options for foreign tables.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The command form <literal>\d+</literal> is identical, except that
|
The command form <literal>\d+</literal> is identical, except that
|
||||||
more information is displayed: any comments associated with the
|
more information is displayed: any comments associated with the
|
||||||
|
@ -363,7 +363,7 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
|
|||||||
return false;
|
return false;
|
||||||
if (attr1->attcollation != attr2->attcollation)
|
if (attr1->attcollation != attr2->attcollation)
|
||||||
return false;
|
return false;
|
||||||
/* attacl and attoptions are not even present... */
|
/* attacl, attoptions and attfdwoptions are not even present... */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tupdesc1->constr != NULL)
|
if (tupdesc1->constr != NULL)
|
||||||
@ -483,7 +483,7 @@ TupleDescInitEntry(TupleDesc desc,
|
|||||||
att->attisdropped = false;
|
att->attisdropped = false;
|
||||||
att->attislocal = true;
|
att->attislocal = true;
|
||||||
att->attinhcount = 0;
|
att->attinhcount = 0;
|
||||||
/* attacl and attoptions are not present in tupledescs */
|
/* attacl, attoptions and attfdwoptions are not present in tupledescs */
|
||||||
|
|
||||||
tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
|
tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
|
||||||
if (!HeapTupleIsValid(tuple))
|
if (!HeapTupleIsValid(tuple))
|
||||||
|
@ -369,7 +369,8 @@ sub emit_pgattr_row
|
|||||||
attislocal => 't',
|
attislocal => 't',
|
||||||
attinhcount => '0',
|
attinhcount => '0',
|
||||||
attacl => '_null_',
|
attacl => '_null_',
|
||||||
attoptions => '_null_'
|
attoptions => '_null_',
|
||||||
|
attfdwoptions => '_null_'
|
||||||
);
|
);
|
||||||
return {%PGATTR_DEFAULTS, %row};
|
return {%PGATTR_DEFAULTS, %row};
|
||||||
}
|
}
|
||||||
@ -400,6 +401,7 @@ sub emit_schemapg_row
|
|||||||
# Only the fixed-size portions of the descriptors are ever used.
|
# Only the fixed-size portions of the descriptors are ever used.
|
||||||
delete $row->{attacl};
|
delete $row->{attacl};
|
||||||
delete $row->{attoptions};
|
delete $row->{attoptions};
|
||||||
|
delete $row->{attfdwoptions};
|
||||||
|
|
||||||
# Expand booleans from 'f'/'t' to 'false'/'true'.
|
# Expand booleans from 'f'/'t' to 'false'/'true'.
|
||||||
# Some values might be other macros (eg FLOAT4PASSBYVAL), don't change.
|
# Some values might be other macros (eg FLOAT4PASSBYVAL), don't change.
|
||||||
|
@ -126,7 +126,7 @@ static List *insert_ordered_unique_oid(List *list, Oid datum);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The initializers below do not include the attoptions or attacl fields,
|
* The initializers below do not include trailing variable length fields,
|
||||||
* but that's OK - we're never going to reference anything beyond the
|
* but that's OK - we're never going to reference anything beyond the
|
||||||
* fixed-size portion of the structure anyway.
|
* fixed-size portion of the structure anyway.
|
||||||
*/
|
*/
|
||||||
@ -620,6 +620,7 @@ InsertPgAttributeTuple(Relation pg_attribute_rel,
|
|||||||
/* start out with empty permissions and empty options */
|
/* start out with empty permissions and empty options */
|
||||||
nulls[Anum_pg_attribute_attacl - 1] = true;
|
nulls[Anum_pg_attribute_attacl - 1] = true;
|
||||||
nulls[Anum_pg_attribute_attoptions - 1] = true;
|
nulls[Anum_pg_attribute_attoptions - 1] = true;
|
||||||
|
nulls[Anum_pg_attribute_attfdwoptions - 1] = true;
|
||||||
|
|
||||||
tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls);
|
tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls);
|
||||||
|
|
||||||
|
@ -2534,6 +2534,39 @@ GRANT SELECT ON element_types TO PUBLIC;
|
|||||||
|
|
||||||
-- SQL/MED views; these use section numbers from part 9 of the standard.
|
-- SQL/MED views; these use section numbers from part 9 of the standard.
|
||||||
|
|
||||||
|
/* Base view for foreign table columns */
|
||||||
|
CREATE VIEW _pg_foreign_table_columns AS
|
||||||
|
SELECT n.nspname,
|
||||||
|
c.relname,
|
||||||
|
a.attname,
|
||||||
|
a.attfdwoptions
|
||||||
|
FROM pg_foreign_table t, pg_authid u, pg_namespace n, pg_class c,
|
||||||
|
pg_attribute a
|
||||||
|
WHERE u.oid = c.relowner
|
||||||
|
AND (pg_has_role(c.relowner, 'USAGE')
|
||||||
|
OR has_column_privilege(c.oid, a.attnum, 'SELECT, INSERT, UPDATE, REFERENCES'))
|
||||||
|
AND n.oid = c.relnamespace
|
||||||
|
AND c.oid = t.ftrelid
|
||||||
|
AND c.relkind = 'f'
|
||||||
|
AND a.attrelid = c.oid
|
||||||
|
AND a.attnum > 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 24.2
|
||||||
|
* COLUMN_OPTIONS view
|
||||||
|
*/
|
||||||
|
CREATE VIEW column_options AS
|
||||||
|
SELECT CAST(current_database() AS sql_identifier) AS table_catalog,
|
||||||
|
c.nspname AS table_schema,
|
||||||
|
c.relname AS table_name,
|
||||||
|
c.attname AS column_name,
|
||||||
|
CAST((pg_options_to_table(c.attfdwoptions)).option_name AS sql_identifier) AS option_name,
|
||||||
|
CAST((pg_options_to_table(c.attfdwoptions)).option_value AS character_data) AS option_value
|
||||||
|
FROM _pg_foreign_table_columns c;
|
||||||
|
|
||||||
|
GRANT SELECT ON column_options TO PUBLIC;
|
||||||
|
|
||||||
|
|
||||||
/* Base view for foreign-data wrappers */
|
/* Base view for foreign-data wrappers */
|
||||||
CREATE VIEW _pg_foreign_data_wrappers AS
|
CREATE VIEW _pg_foreign_data_wrappers AS
|
||||||
SELECT w.oid,
|
SELECT w.oid,
|
||||||
|
@ -346,6 +346,8 @@ static void ATPrepAlterColumnType(List **wqueue,
|
|||||||
static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
|
static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
|
||||||
static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
|
static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
|
||||||
AlterTableCmd *cmd, LOCKMODE lockmode);
|
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 ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode);
|
||||||
static void ATPostAlterTypeParse(Oid oldId, char *cmd,
|
static void ATPostAlterTypeParse(Oid oldId, char *cmd,
|
||||||
List **wqueue, LOCKMODE lockmode, bool rewrite);
|
List **wqueue, LOCKMODE lockmode, bool rewrite);
|
||||||
@ -2648,6 +2650,7 @@ AlterTableGetLockLevel(List *cmds)
|
|||||||
case AT_DropNotNull: /* may change some SQL plans */
|
case AT_DropNotNull: /* may change some SQL plans */
|
||||||
case AT_SetNotNull:
|
case AT_SetNotNull:
|
||||||
case AT_GenericOptions:
|
case AT_GenericOptions:
|
||||||
|
case AT_AlterColumnGenericOptions:
|
||||||
cmd_lockmode = AccessExclusiveLock;
|
cmd_lockmode = AccessExclusiveLock;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2925,6 +2928,12 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
|
|||||||
ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd, lockmode);
|
ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd, lockmode);
|
||||||
pass = AT_PASS_ALTER_TYPE;
|
pass = AT_PASS_ALTER_TYPE;
|
||||||
break;
|
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 */
|
case AT_ChangeOwner: /* ALTER OWNER */
|
||||||
/* This command never recurses */
|
/* This command never recurses */
|
||||||
/* No command-specific prep needed */
|
/* No command-specific prep needed */
|
||||||
@ -3169,6 +3178,9 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
|||||||
case AT_AlterColumnType: /* ALTER COLUMN TYPE */
|
case AT_AlterColumnType: /* ALTER COLUMN TYPE */
|
||||||
ATExecAlterColumnType(tab, rel, cmd, lockmode);
|
ATExecAlterColumnType(tab, rel, cmd, lockmode);
|
||||||
break;
|
break;
|
||||||
|
case AT_AlterColumnGenericOptions: /* ALTER COLUMN OPTIONS */
|
||||||
|
ATExecAlterColumnGenericOptions(rel, cmd->name, (List *) cmd->def, lockmode);
|
||||||
|
break;
|
||||||
case AT_ChangeOwner: /* ALTER OWNER */
|
case AT_ChangeOwner: /* ALTER OWNER */
|
||||||
ATExecChangeOwner(RelationGetRelid(rel),
|
ATExecChangeOwner(RelationGetRelid(rel),
|
||||||
get_role_oid(cmd->name, false),
|
get_role_oid(cmd->name, false),
|
||||||
@ -7397,6 +7409,100 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
|
|||||||
heap_freetuple(heapTup);
|
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
|
* Cleanup after we've finished all the ALTER TYPE operations for a
|
||||||
* particular relation. We have to drop and recreate all the indexes
|
* particular relation. We have to drop and recreate all the indexes
|
||||||
|
@ -2312,6 +2312,7 @@ _copyColumnDef(ColumnDef *from)
|
|||||||
COPY_NODE_FIELD(collClause);
|
COPY_NODE_FIELD(collClause);
|
||||||
COPY_SCALAR_FIELD(collOid);
|
COPY_SCALAR_FIELD(collOid);
|
||||||
COPY_NODE_FIELD(constraints);
|
COPY_NODE_FIELD(constraints);
|
||||||
|
COPY_NODE_FIELD(fdwoptions);
|
||||||
|
|
||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
@ -2102,6 +2102,7 @@ _outColumnDef(StringInfo str, ColumnDef *node)
|
|||||||
WRITE_NODE_FIELD(collClause);
|
WRITE_NODE_FIELD(collClause);
|
||||||
WRITE_OID_FIELD(collOid);
|
WRITE_OID_FIELD(collOid);
|
||||||
WRITE_NODE_FIELD(constraints);
|
WRITE_NODE_FIELD(constraints);
|
||||||
|
WRITE_NODE_FIELD(fdwoptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1769,6 +1769,15 @@ alter_table_cmd:
|
|||||||
def->raw_default = $8;
|
def->raw_default = $8;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
|
/* ALTER FOREIGN TABLE <name> ALTER [COLUMN] <colname> OPTIONS */
|
||||||
|
| ALTER opt_column ColId alter_generic_options
|
||||||
|
{
|
||||||
|
AlterTableCmd *n = makeNode(AlterTableCmd);
|
||||||
|
n->subtype = AT_AlterColumnGenericOptions;
|
||||||
|
n->name = $3;
|
||||||
|
n->def = (Node *) $4;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
/* ALTER TABLE <name> ADD CONSTRAINT ... */
|
/* ALTER TABLE <name> ADD CONSTRAINT ... */
|
||||||
| ADD_P TableConstraint
|
| ADD_P TableConstraint
|
||||||
{
|
{
|
||||||
@ -2497,7 +2506,7 @@ TypedTableElement:
|
|||||||
| TableConstraint { $$ = $1; }
|
| TableConstraint { $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
columnDef: ColId Typename ColQualList
|
columnDef: ColId Typename create_generic_options ColQualList
|
||||||
{
|
{
|
||||||
ColumnDef *n = makeNode(ColumnDef);
|
ColumnDef *n = makeNode(ColumnDef);
|
||||||
n->colname = $1;
|
n->colname = $1;
|
||||||
@ -2510,7 +2519,8 @@ columnDef: ColId Typename ColQualList
|
|||||||
n->raw_default = NULL;
|
n->raw_default = NULL;
|
||||||
n->cooked_default = NULL;
|
n->cooked_default = NULL;
|
||||||
n->collOid = InvalidOid;
|
n->collOid = InvalidOid;
|
||||||
SplitColQualList($3, &n->constraints, &n->collClause,
|
n->fdwoptions = $3;
|
||||||
|
SplitColQualList($4, &n->constraints, &n->collClause,
|
||||||
yyscanner);
|
yyscanner);
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
|
@ -559,6 +559,31 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate ALTER FOREIGN TABLE ALTER COLUMN statement which adds
|
||||||
|
* per-column foreign data wrapper options for this column.
|
||||||
|
*/
|
||||||
|
if (column->fdwoptions != NIL)
|
||||||
|
{
|
||||||
|
AlterTableStmt *stmt;
|
||||||
|
AlterTableCmd *cmd;
|
||||||
|
|
||||||
|
cmd = makeNode(AlterTableCmd);
|
||||||
|
cmd->subtype = AT_AlterColumnGenericOptions;
|
||||||
|
cmd->name = column->colname;
|
||||||
|
cmd->def = (Node *) column->fdwoptions;
|
||||||
|
cmd->behavior = DROP_RESTRICT;
|
||||||
|
cmd->missing_ok = false;
|
||||||
|
|
||||||
|
stmt = makeNode(AlterTableStmt);
|
||||||
|
stmt->relation = cxt->relation;
|
||||||
|
stmt->cmds = NIL;
|
||||||
|
stmt->relkind = OBJECT_FOREIGN_TABLE;
|
||||||
|
stmt->cmds = lappend(stmt->cmds, cmd);
|
||||||
|
|
||||||
|
cxt->alist = lappend(cxt->alist, stmt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5574,6 +5574,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
int i_attislocal;
|
int i_attislocal;
|
||||||
int i_attoptions;
|
int i_attoptions;
|
||||||
int i_attcollation;
|
int i_attcollation;
|
||||||
|
int i_attfdwoptions;
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
int ntups;
|
int ntups;
|
||||||
bool hasdefaults;
|
bool hasdefaults;
|
||||||
@ -5611,7 +5612,31 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
|
|
||||||
resetPQExpBuffer(q);
|
resetPQExpBuffer(q);
|
||||||
|
|
||||||
if (g_fout->remoteVersion >= 90100)
|
if (g_fout->remoteVersion >= 90200)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* attfdwoptions is new in 9.2.
|
||||||
|
*/
|
||||||
|
appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
|
||||||
|
"a.attstattarget, a.attstorage, t.typstorage, "
|
||||||
|
"a.attnotnull, a.atthasdef, a.attisdropped, "
|
||||||
|
"a.attlen, a.attalign, a.attislocal, "
|
||||||
|
"pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
|
||||||
|
"array_to_string(a.attoptions, ', ') AS attoptions, "
|
||||||
|
"CASE WHEN a.attcollation <> t.typcollation "
|
||||||
|
"THEN a.attcollation ELSE 0 END AS attcollation, "
|
||||||
|
"array_to_string(ARRAY("
|
||||||
|
" SELECT option_name || ' ' || quote_literal(option_value) "
|
||||||
|
" FROM pg_options_to_table(attfdwoptions)), ', ') "
|
||||||
|
" AS attfdwoptions "
|
||||||
|
"FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
|
||||||
|
"ON a.atttypid = t.oid "
|
||||||
|
"WHERE a.attrelid = '%u'::pg_catalog.oid "
|
||||||
|
"AND a.attnum > 0::pg_catalog.int2 "
|
||||||
|
"ORDER BY a.attrelid, a.attnum",
|
||||||
|
tbinfo->dobj.catId.oid);
|
||||||
|
}
|
||||||
|
else if (g_fout->remoteVersion >= 90100)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* attcollation is new in 9.1. Since we only want to dump COLLATE
|
* attcollation is new in 9.1. Since we only want to dump COLLATE
|
||||||
@ -5626,7 +5651,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
"pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
|
"pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
|
||||||
"array_to_string(a.attoptions, ', ') AS attoptions, "
|
"array_to_string(a.attoptions, ', ') AS attoptions, "
|
||||||
"CASE WHEN a.attcollation <> t.typcollation "
|
"CASE WHEN a.attcollation <> t.typcollation "
|
||||||
"THEN a.attcollation ELSE 0 END AS attcollation "
|
"THEN a.attcollation ELSE 0 END AS attcollation, "
|
||||||
|
"NULL AS attfdwoptions "
|
||||||
"FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
|
"FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
|
||||||
"ON a.atttypid = t.oid "
|
"ON a.atttypid = t.oid "
|
||||||
"WHERE a.attrelid = '%u'::pg_catalog.oid "
|
"WHERE a.attrelid = '%u'::pg_catalog.oid "
|
||||||
@ -5643,7 +5669,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
"a.attlen, a.attalign, a.attislocal, "
|
"a.attlen, a.attalign, a.attislocal, "
|
||||||
"pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
|
"pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
|
||||||
"array_to_string(a.attoptions, ', ') AS attoptions, "
|
"array_to_string(a.attoptions, ', ') AS attoptions, "
|
||||||
"0 AS attcollation "
|
"0 AS attcollation, "
|
||||||
|
"NULL AS attfdwoptions "
|
||||||
"FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
|
"FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
|
||||||
"ON a.atttypid = t.oid "
|
"ON a.atttypid = t.oid "
|
||||||
"WHERE a.attrelid = '%u'::pg_catalog.oid "
|
"WHERE a.attrelid = '%u'::pg_catalog.oid "
|
||||||
@ -5659,7 +5686,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
"a.attnotnull, a.atthasdef, a.attisdropped, "
|
"a.attnotnull, a.atthasdef, a.attisdropped, "
|
||||||
"a.attlen, a.attalign, a.attislocal, "
|
"a.attlen, a.attalign, a.attislocal, "
|
||||||
"pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
|
"pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
|
||||||
"'' AS attoptions, 0 AS attcollation "
|
"'' AS attoptions, 0 AS attcollation, "
|
||||||
|
"NULL AS attfdwoptions "
|
||||||
"FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
|
"FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
|
||||||
"ON a.atttypid = t.oid "
|
"ON a.atttypid = t.oid "
|
||||||
"WHERE a.attrelid = '%u'::pg_catalog.oid "
|
"WHERE a.attrelid = '%u'::pg_catalog.oid "
|
||||||
@ -5680,7 +5708,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
"false AS attisdropped, a.attlen, "
|
"false AS attisdropped, a.attlen, "
|
||||||
"a.attalign, false AS attislocal, "
|
"a.attalign, false AS attislocal, "
|
||||||
"format_type(t.oid,a.atttypmod) AS atttypname, "
|
"format_type(t.oid,a.atttypmod) AS atttypname, "
|
||||||
"'' AS attoptions, 0 AS attcollation "
|
"'' AS attoptions, 0 AS attcollation, "
|
||||||
|
"NULL AS attfdwoptions "
|
||||||
"FROM pg_attribute a LEFT JOIN pg_type t "
|
"FROM pg_attribute a LEFT JOIN pg_type t "
|
||||||
"ON a.atttypid = t.oid "
|
"ON a.atttypid = t.oid "
|
||||||
"WHERE a.attrelid = '%u'::oid "
|
"WHERE a.attrelid = '%u'::oid "
|
||||||
@ -5698,7 +5727,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
"attlen, attalign, "
|
"attlen, attalign, "
|
||||||
"false AS attislocal, "
|
"false AS attislocal, "
|
||||||
"(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
|
"(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
|
||||||
"'' AS attoptions, 0 AS attcollation "
|
"'' AS attoptions, 0 AS attcollation, "
|
||||||
|
"NULL AS attfdwoptions "
|
||||||
"FROM pg_attribute a "
|
"FROM pg_attribute a "
|
||||||
"WHERE attrelid = '%u'::oid "
|
"WHERE attrelid = '%u'::oid "
|
||||||
"AND attnum > 0::int2 "
|
"AND attnum > 0::int2 "
|
||||||
@ -5726,6 +5756,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
i_attislocal = PQfnumber(res, "attislocal");
|
i_attislocal = PQfnumber(res, "attislocal");
|
||||||
i_attoptions = PQfnumber(res, "attoptions");
|
i_attoptions = PQfnumber(res, "attoptions");
|
||||||
i_attcollation = PQfnumber(res, "attcollation");
|
i_attcollation = PQfnumber(res, "attcollation");
|
||||||
|
i_attfdwoptions = PQfnumber(res, "attfdwoptions");
|
||||||
|
|
||||||
tbinfo->numatts = ntups;
|
tbinfo->numatts = ntups;
|
||||||
tbinfo->attnames = (char **) malloc(ntups * sizeof(char *));
|
tbinfo->attnames = (char **) malloc(ntups * sizeof(char *));
|
||||||
@ -5742,6 +5773,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *));
|
tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *));
|
||||||
tbinfo->attoptions = (char **) malloc(ntups * sizeof(char *));
|
tbinfo->attoptions = (char **) malloc(ntups * sizeof(char *));
|
||||||
tbinfo->attcollation = (Oid *) malloc(ntups * sizeof(Oid));
|
tbinfo->attcollation = (Oid *) malloc(ntups * sizeof(Oid));
|
||||||
|
tbinfo->attfdwoptions = (char **) malloc(ntups * sizeof(char *));
|
||||||
tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
|
tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
|
||||||
tbinfo->inhAttrDef = (bool *) malloc(ntups * sizeof(bool));
|
tbinfo->inhAttrDef = (bool *) malloc(ntups * sizeof(bool));
|
||||||
tbinfo->inhNotNull = (bool *) malloc(ntups * sizeof(bool));
|
tbinfo->inhNotNull = (bool *) malloc(ntups * sizeof(bool));
|
||||||
@ -5768,6 +5800,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
|
tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
|
||||||
tbinfo->attoptions[j] = strdup(PQgetvalue(res, j, i_attoptions));
|
tbinfo->attoptions[j] = strdup(PQgetvalue(res, j, i_attoptions));
|
||||||
tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
|
tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
|
||||||
|
tbinfo->attfdwoptions[j] = strdup(PQgetvalue(res, j, i_attfdwoptions));
|
||||||
tbinfo->attrdefs[j] = NULL; /* fix below */
|
tbinfo->attrdefs[j] = NULL; /* fix below */
|
||||||
if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
|
if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
|
||||||
hasdefaults = true;
|
hasdefaults = true;
|
||||||
@ -12469,6 +12502,21 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
|
|||||||
appendPQExpBuffer(q, "SET (%s);\n",
|
appendPQExpBuffer(q, "SET (%s);\n",
|
||||||
tbinfo->attoptions[j]);
|
tbinfo->attoptions[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump per-column fdw options.
|
||||||
|
*/
|
||||||
|
if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
|
||||||
|
tbinfo->attfdwoptions[j] &&
|
||||||
|
tbinfo->attfdwoptions[j][0] != '\0')
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
|
||||||
|
fmtId(tbinfo->dobj.name));
|
||||||
|
appendPQExpBuffer(q, "ALTER COLUMN %s ",
|
||||||
|
fmtId(tbinfo->attnames[j]));
|
||||||
|
appendPQExpBuffer(q, "OPTIONS (%s);\n",
|
||||||
|
tbinfo->attfdwoptions[j]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,6 +275,7 @@ typedef struct _tableInfo
|
|||||||
bool *attislocal; /* true if attr has local definition */
|
bool *attislocal; /* true if attr has local definition */
|
||||||
char **attoptions; /* per-attribute options */
|
char **attoptions; /* per-attribute options */
|
||||||
Oid *attcollation; /* per-attribute collation selection */
|
Oid *attcollation; /* per-attribute collation selection */
|
||||||
|
char **attfdwoptions; /* per-attribute fdw options */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: we need to store per-attribute notnull, default, and constraint
|
* Note: we need to store per-attribute notnull, default, and constraint
|
||||||
|
@ -1281,7 +1281,12 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
res = NULL;
|
res = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get column info */
|
/*
|
||||||
|
* Get column info
|
||||||
|
*
|
||||||
|
* You need to modify value of "firstvcol" which willbe defined below if
|
||||||
|
* you are adding column(s) preceding to verbose-only columns.
|
||||||
|
*/
|
||||||
printfPQExpBuffer(&buf, "SELECT a.attname,");
|
printfPQExpBuffer(&buf, "SELECT a.attname,");
|
||||||
appendPQExpBuffer(&buf, "\n pg_catalog.format_type(a.atttypid, a.atttypmod),"
|
appendPQExpBuffer(&buf, "\n pg_catalog.format_type(a.atttypid, a.atttypmod),"
|
||||||
"\n (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)"
|
"\n (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)"
|
||||||
@ -1295,6 +1300,12 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
appendPQExpBuffer(&buf, "\n NULL AS attcollation");
|
appendPQExpBuffer(&buf, "\n NULL AS attcollation");
|
||||||
if (tableinfo.relkind == 'i')
|
if (tableinfo.relkind == 'i')
|
||||||
appendPQExpBuffer(&buf, ",\n pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
|
appendPQExpBuffer(&buf, ",\n pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
|
||||||
|
else
|
||||||
|
appendPQExpBuffer(&buf, ",\n NULL AS indexdef");
|
||||||
|
if (tableinfo.relkind == 'f' && pset.sversion >= 90200)
|
||||||
|
appendPQExpBuffer(&buf, ",\n a.attfdwoptions");
|
||||||
|
else
|
||||||
|
appendPQExpBuffer(&buf, ",\n NULL AS attfdwoptions");
|
||||||
if (verbose)
|
if (verbose)
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(&buf, ",\n a.attstorage");
|
appendPQExpBuffer(&buf, ",\n a.attstorage");
|
||||||
@ -1386,6 +1397,9 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
if (tableinfo.relkind == 'i')
|
if (tableinfo.relkind == 'i')
|
||||||
headers[cols++] = gettext_noop("Definition");
|
headers[cols++] = gettext_noop("Definition");
|
||||||
|
|
||||||
|
if (tableinfo.relkind == 'f' && pset.sversion >= 90200)
|
||||||
|
headers[cols++] = gettext_noop("Options");
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
{
|
{
|
||||||
headers[cols++] = gettext_noop("Storage");
|
headers[cols++] = gettext_noop("Storage");
|
||||||
@ -1471,10 +1485,14 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
if (tableinfo.relkind == 'i')
|
if (tableinfo.relkind == 'i')
|
||||||
printTableAddCell(&cont, PQgetvalue(res, i, 6), false, false);
|
printTableAddCell(&cont, PQgetvalue(res, i, 6), false, false);
|
||||||
|
|
||||||
|
/* FDW options for foreign table column, only for 9.2 or later */
|
||||||
|
if (tableinfo.relkind == 'f' && pset.sversion >= 90200)
|
||||||
|
printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
|
||||||
|
|
||||||
/* Storage and Description */
|
/* Storage and Description */
|
||||||
if (verbose)
|
if (verbose)
|
||||||
{
|
{
|
||||||
int firstvcol = (tableinfo.relkind == 'i' ? 7 : 6);
|
int firstvcol = 8;
|
||||||
char *storage = PQgetvalue(res, i, firstvcol);
|
char *storage = PQgetvalue(res, i, firstvcol);
|
||||||
|
|
||||||
/* these strings are literal in our syntax, so not translated. */
|
/* these strings are literal in our syntax, so not translated. */
|
||||||
|
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 201107201
|
#define CATALOG_VERSION_NO 201108051
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -156,6 +156,9 @@ CATALOG(pg_attribute,1249) BKI_BOOTSTRAP BKI_WITHOUT_OIDS BKI_ROWTYPE_OID(75) BK
|
|||||||
|
|
||||||
/* Column-level options */
|
/* Column-level options */
|
||||||
text attoptions[1];
|
text attoptions[1];
|
||||||
|
|
||||||
|
/* Column-level FDW options */
|
||||||
|
text attfdwoptions[1];
|
||||||
} FormData_pg_attribute;
|
} FormData_pg_attribute;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -179,7 +182,7 @@ typedef FormData_pg_attribute *Form_pg_attribute;
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define Natts_pg_attribute 20
|
#define Natts_pg_attribute 21
|
||||||
#define Anum_pg_attribute_attrelid 1
|
#define Anum_pg_attribute_attrelid 1
|
||||||
#define Anum_pg_attribute_attname 2
|
#define Anum_pg_attribute_attname 2
|
||||||
#define Anum_pg_attribute_atttypid 3
|
#define Anum_pg_attribute_atttypid 3
|
||||||
@ -200,6 +203,7 @@ typedef FormData_pg_attribute *Form_pg_attribute;
|
|||||||
#define Anum_pg_attribute_attcollation 18
|
#define Anum_pg_attribute_attcollation 18
|
||||||
#define Anum_pg_attribute_attacl 19
|
#define Anum_pg_attribute_attacl 19
|
||||||
#define Anum_pg_attribute_attoptions 20
|
#define Anum_pg_attribute_attoptions 20
|
||||||
|
#define Anum_pg_attribute_attfdwoptions 21
|
||||||
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -132,7 +132,7 @@ typedef FormData_pg_class *Form_pg_class;
|
|||||||
/* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
|
/* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
|
||||||
DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f p r 29 0 t f f f f 3 _null_ _null_ ));
|
DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f p r 29 0 t f f f f 3 _null_ _null_ ));
|
||||||
DESCR("");
|
DESCR("");
|
||||||
DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f p r 20 0 f f f f f 3 _null_ _null_ ));
|
DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f p r 21 0 f f f f f 3 _null_ _null_ ));
|
||||||
DESCR("");
|
DESCR("");
|
||||||
DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f p r 26 0 t f f f f 3 _null_ _null_ ));
|
DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f p r 26 0 t f f f f 3 _null_ _null_ ));
|
||||||
DESCR("");
|
DESCR("");
|
||||||
|
@ -500,6 +500,7 @@ typedef struct ColumnDef
|
|||||||
CollateClause *collClause; /* untransformed COLLATE spec, if any */
|
CollateClause *collClause; /* untransformed COLLATE spec, if any */
|
||||||
Oid collOid; /* collation OID (InvalidOid if not set) */
|
Oid collOid; /* collation OID (InvalidOid if not set) */
|
||||||
List *constraints; /* other constraints on column */
|
List *constraints; /* other constraints on column */
|
||||||
|
List *fdwoptions; /* per-column FDW options */
|
||||||
} ColumnDef;
|
} ColumnDef;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1197,6 +1198,7 @@ typedef enum AlterTableType
|
|||||||
AT_DropConstraint, /* drop constraint */
|
AT_DropConstraint, /* drop constraint */
|
||||||
AT_DropConstraintRecurse, /* internal to commands/tablecmds.c */
|
AT_DropConstraintRecurse, /* internal to commands/tablecmds.c */
|
||||||
AT_AlterColumnType, /* alter column type */
|
AT_AlterColumnType, /* alter column type */
|
||||||
|
AT_AlterColumnGenericOptions, /* alter column OPTIONS (...) */
|
||||||
AT_ChangeOwner, /* change owner */
|
AT_ChangeOwner, /* change owner */
|
||||||
AT_ClusterOn, /* CLUSTER ON */
|
AT_ClusterOn, /* CLUSTER ON */
|
||||||
AT_DropCluster, /* SET WITHOUT CLUSTER */
|
AT_DropCluster, /* SET WITHOUT CLUSTER */
|
||||||
|
@ -646,19 +646,19 @@ ERROR: syntax error at or near "WITH OIDS"
|
|||||||
LINE 1: CREATE FOREIGN TABLE ft1 () SERVER sc WITH OIDS;
|
LINE 1: CREATE FOREIGN TABLE ft1 () SERVER sc WITH OIDS;
|
||||||
^
|
^
|
||||||
CREATE FOREIGN TABLE ft1 (
|
CREATE FOREIGN TABLE ft1 (
|
||||||
c1 integer NOT NULL,
|
c1 integer OPTIONS (param1 'val1') NOT NULL,
|
||||||
c2 text,
|
c2 text OPTIONS (param2 'val2', param3 'val3'),
|
||||||
c3 date
|
c3 date
|
||||||
) SERVER sc OPTIONS (delimiter ',', quote '"');
|
) SERVER sc OPTIONS (delimiter ',', quote '"');
|
||||||
COMMENT ON FOREIGN TABLE ft1 IS 'ft1';
|
COMMENT ON FOREIGN TABLE ft1 IS 'ft1';
|
||||||
COMMENT ON COLUMN ft1.c1 IS 'ft1.c1';
|
COMMENT ON COLUMN ft1.c1 IS 'ft1.c1';
|
||||||
\d+ ft1
|
\d+ ft1
|
||||||
Foreign table "public.ft1"
|
Foreign table "public.ft1"
|
||||||
Column | Type | Modifiers | Storage | Description
|
Column | Type | Modifiers | Options | Storage | Description
|
||||||
--------+---------+-----------+----------+-------------
|
--------+---------+-----------+---------------------------+----------+-------------
|
||||||
c1 | integer | not null | plain | ft1.c1
|
c1 | integer | not null | {param1=val1} | plain | ft1.c1
|
||||||
c2 | text | | extended |
|
c2 | text | | {param2=val2,param3=val3} | extended |
|
||||||
c3 | date | | plain |
|
c3 | date | | | plain |
|
||||||
Server: sc
|
Server: sc
|
||||||
Has OIDs: no
|
Has OIDs: no
|
||||||
|
|
||||||
@ -687,7 +687,7 @@ ALTER FOREIGN TABLE ft1 ADD COLUMN c6 integer;
|
|||||||
ALTER FOREIGN TABLE ft1 ADD COLUMN c7 integer NOT NULL;
|
ALTER FOREIGN TABLE ft1 ADD COLUMN c7 integer NOT NULL;
|
||||||
ALTER FOREIGN TABLE ft1 ADD COLUMN c8 integer;
|
ALTER FOREIGN TABLE ft1 ADD COLUMN c8 integer;
|
||||||
ALTER FOREIGN TABLE ft1 ADD COLUMN c9 integer;
|
ALTER FOREIGN TABLE ft1 ADD COLUMN c9 integer;
|
||||||
ALTER FOREIGN TABLE ft1 ADD COLUMN c10 integer;
|
ALTER FOREIGN TABLE ft1 ADD COLUMN c10 integer OPTIONS (p1 'v1');
|
||||||
ALTER FOREIGN TABLE ft1 ALTER COLUMN c4 SET DEFAULT 0; -- ERROR
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN c4 SET DEFAULT 0; -- ERROR
|
||||||
ERROR: "ft1" is not a table or view
|
ERROR: "ft1" is not a table or view
|
||||||
ALTER FOREIGN TABLE ft1 ALTER COLUMN c5 DROP DEFAULT; -- ERROR
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN c5 DROP DEFAULT; -- ERROR
|
||||||
@ -698,6 +698,27 @@ ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10) USING '0'; -- ERROR
|
|||||||
ERROR: "ft1" is not a table
|
ERROR: "ft1" is not a table
|
||||||
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10);
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10);
|
||||||
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE text;
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE text;
|
||||||
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN xmin OPTIONS (ADD p1 'v1'); -- ERROR
|
||||||
|
ERROR: cannot alter system column "xmin"
|
||||||
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN c7 OPTIONS (ADD p1 'v1', ADD p2 'v2'),
|
||||||
|
ALTER COLUMN c8 OPTIONS (ADD p1 'v1', ADD p2 'v2');
|
||||||
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 OPTIONS (SET p2 'V2', DROP p1);
|
||||||
|
\d+ ft1
|
||||||
|
Foreign table "public.ft1"
|
||||||
|
Column | Type | Modifiers | Options | Storage | Description
|
||||||
|
--------+---------+-----------+---------------------------+----------+-------------
|
||||||
|
c1 | integer | not null | {param1=val1} | plain |
|
||||||
|
c2 | text | | {param2=val2,param3=val3} | extended |
|
||||||
|
c3 | date | | | plain |
|
||||||
|
c4 | integer | | | plain |
|
||||||
|
c6 | integer | not null | | plain |
|
||||||
|
c7 | integer | | {p1=v1,p2=v2} | plain |
|
||||||
|
c8 | text | | {p2=V2} | extended |
|
||||||
|
c9 | integer | | | plain |
|
||||||
|
c10 | integer | | {p1=v1} | plain |
|
||||||
|
Server: sc
|
||||||
|
Has OIDs: no
|
||||||
|
|
||||||
-- can't change the column type if it's used elsewhere
|
-- can't change the column type if it's used elsewhere
|
||||||
CREATE TABLE use_ft1_column_type (x ft1);
|
CREATE TABLE use_ft1_column_type (x ft1);
|
||||||
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE integer; -- ERROR
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE integer; -- ERROR
|
||||||
@ -726,17 +747,17 @@ ERROR: relation "ft1" does not exist
|
|||||||
ALTER FOREIGN TABLE foreign_schema.ft1 RENAME c1 TO foreign_column_1;
|
ALTER FOREIGN TABLE foreign_schema.ft1 RENAME c1 TO foreign_column_1;
|
||||||
ALTER FOREIGN TABLE foreign_schema.ft1 RENAME TO foreign_table_1;
|
ALTER FOREIGN TABLE foreign_schema.ft1 RENAME TO foreign_table_1;
|
||||||
\d foreign_schema.foreign_table_1
|
\d foreign_schema.foreign_table_1
|
||||||
Foreign table "foreign_schema.foreign_table_1"
|
Foreign table "foreign_schema.foreign_table_1"
|
||||||
Column | Type | Modifiers
|
Column | Type | Modifiers | Options
|
||||||
------------------+---------+-----------
|
------------------+---------+-----------+---------------------------
|
||||||
foreign_column_1 | integer | not null
|
foreign_column_1 | integer | not null | {param1=val1}
|
||||||
c2 | text |
|
c2 | text | | {param2=val2,param3=val3}
|
||||||
c3 | date |
|
c3 | date | |
|
||||||
c4 | integer |
|
c4 | integer | |
|
||||||
c6 | integer | not null
|
c6 | integer | not null |
|
||||||
c7 | integer |
|
c7 | integer | | {p1=v1,p2=v2}
|
||||||
c8 | text |
|
c8 | text | | {p2=V2}
|
||||||
c10 | integer |
|
c10 | integer | | {p1=v1}
|
||||||
Server: sc
|
Server: sc
|
||||||
|
|
||||||
-- Information schema
|
-- Information schema
|
||||||
|
@ -264,8 +264,8 @@ CREATE FOREIGN TABLE ft1 () SERVER no_server; -- ERROR
|
|||||||
CREATE FOREIGN TABLE ft1 (c1 serial) SERVER sc; -- ERROR
|
CREATE FOREIGN TABLE ft1 (c1 serial) SERVER sc; -- ERROR
|
||||||
CREATE FOREIGN TABLE ft1 () SERVER sc WITH OIDS; -- ERROR
|
CREATE FOREIGN TABLE ft1 () SERVER sc WITH OIDS; -- ERROR
|
||||||
CREATE FOREIGN TABLE ft1 (
|
CREATE FOREIGN TABLE ft1 (
|
||||||
c1 integer NOT NULL,
|
c1 integer OPTIONS (param1 'val1') NOT NULL,
|
||||||
c2 text,
|
c2 text OPTIONS (param2 'val2', param3 'val3'),
|
||||||
c3 date
|
c3 date
|
||||||
) SERVER sc OPTIONS (delimiter ',', quote '"');
|
) SERVER sc OPTIONS (delimiter ',', quote '"');
|
||||||
COMMENT ON FOREIGN TABLE ft1 IS 'ft1';
|
COMMENT ON FOREIGN TABLE ft1 IS 'ft1';
|
||||||
@ -288,7 +288,7 @@ ALTER FOREIGN TABLE ft1 ADD COLUMN c6 integer;
|
|||||||
ALTER FOREIGN TABLE ft1 ADD COLUMN c7 integer NOT NULL;
|
ALTER FOREIGN TABLE ft1 ADD COLUMN c7 integer NOT NULL;
|
||||||
ALTER FOREIGN TABLE ft1 ADD COLUMN c8 integer;
|
ALTER FOREIGN TABLE ft1 ADD COLUMN c8 integer;
|
||||||
ALTER FOREIGN TABLE ft1 ADD COLUMN c9 integer;
|
ALTER FOREIGN TABLE ft1 ADD COLUMN c9 integer;
|
||||||
ALTER FOREIGN TABLE ft1 ADD COLUMN c10 integer;
|
ALTER FOREIGN TABLE ft1 ADD COLUMN c10 integer OPTIONS (p1 'v1');
|
||||||
|
|
||||||
ALTER FOREIGN TABLE ft1 ALTER COLUMN c4 SET DEFAULT 0; -- ERROR
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN c4 SET DEFAULT 0; -- ERROR
|
||||||
ALTER FOREIGN TABLE ft1 ALTER COLUMN c5 DROP DEFAULT; -- ERROR
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN c5 DROP DEFAULT; -- ERROR
|
||||||
@ -297,6 +297,11 @@ ALTER FOREIGN TABLE ft1 ALTER COLUMN c7 DROP NOT NULL;
|
|||||||
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10) USING '0'; -- ERROR
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10) USING '0'; -- ERROR
|
||||||
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10);
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10);
|
||||||
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE text;
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE text;
|
||||||
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN xmin OPTIONS (ADD p1 'v1'); -- ERROR
|
||||||
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN c7 OPTIONS (ADD p1 'v1', ADD p2 'v2'),
|
||||||
|
ALTER COLUMN c8 OPTIONS (ADD p1 'v1', ADD p2 'v2');
|
||||||
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 OPTIONS (SET p2 'V2', DROP p1);
|
||||||
|
\d+ ft1
|
||||||
-- can't change the column type if it's used elsewhere
|
-- can't change the column type if it's used elsewhere
|
||||||
CREATE TABLE use_ft1_column_type (x ft1);
|
CREATE TABLE use_ft1_column_type (x ft1);
|
||||||
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE integer; -- ERROR
|
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE integer; -- ERROR
|
||||||
|
Loading…
x
Reference in New Issue
Block a user