diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 30f398069703c16fbade444311cc123b7eff38a8..88eaca0bea082f5e800d08402d7468c5c2b6b578 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -3031,16 +3031,27 @@ <entry>Owner of the foreign-data wrapper</entry> </row> + <row> + <entry><structfield>fdwhandler</structfield></entry> + <entry><type>oid</type></entry> + <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry> + <entry> + References a handler function that is responsible for + supplying execution routines for the foreign-data wrapper. + Zero if no handler is provided + </entry> + </row> + <row> <entry><structfield>fdwvalidator</structfield></entry> <entry><type>oid</type></entry> <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry> <entry> References a validator function that is responsible for - checking the validity of the generic options given to the - foreign-data wrapper, as well as to foreign servers and user + checking the validity of the options given to the + foreign-data wrapper, as well as options for foreign servers and user mappings using the foreign-data wrapper. Zero if no validator - is provided. + is provided </entry> </row> @@ -3079,8 +3090,8 @@ <para> The catalog <structname>pg_foreign_server</structname> stores - foreign server definitions. A foreign server describes the - connection to a remote server, managing external data. Foreign + foreign server definitions. A foreign server describes a source + of external data, such as a remote server. Foreign servers are accessed via foreign-data wrappers. </para> @@ -3116,7 +3127,7 @@ <entry><structfield>srvfdw</structfield></entry> <entry><type>oid</type></entry> <entry><literal><link linkend="catalog-pg-foreign-data-wrapper"><structname>pg_foreign_data_wrapper</structname></link>.oid</literal></entry> - <entry>The OID of the foreign-data wrapper of this foreign server</entry> + <entry>OID of the foreign-data wrapper of this foreign server</entry> </row> <row> @@ -3167,9 +3178,12 @@ </indexterm> <para> - The catalog <structname>pg_foreign_table</structname> contains part - of the information about foreign tables. - The rest is mostly in <structname>pg_class</structname>. + The catalog <structname>pg_foreign_table</structname> contains + auxiliary information about foreign tables. A foreign table is + primarily represented by a <structname>pg_class</structname> entry, + just like a regular table. Its <structname>pg_foreign_table</structname> + entry contains the information that is pertinent only to foreign tables + and not any other kind of relation. </para> <table> @@ -3190,14 +3204,14 @@ <entry><structfield>ftrelid</structfield></entry> <entry><type>oid</type></entry> <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry> - <entry>The OID of the <structname>pg_class</> entry for this foreign table</entry> + <entry>OID of the <structname>pg_class</> entry for this foreign table</entry> </row> <row> <entry><structfield>ftserver</structfield></entry> <entry><type>oid</type></entry> <entry><literal><link linkend="catalog-pg-foreign-server"><structname>pg_foreign_server</structname></link>.oid</literal></entry> - <entry>The OID of the foreign server for this foreign table</entry> + <entry>OID of the foreign server for this foreign table</entry> </row> <row> @@ -3205,7 +3219,7 @@ <entry><type>text[]</type></entry> <entry></entry> <entry> - Foreign table options, as <quote>keyword=value</> strings. + Foreign table options, as <quote>keyword=value</> strings </entry> </row> </tbody> diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 253b7578985eaab013bfafd7046da1d9e5d556b2..b8f6e238f0b547e3cbebd5569a8a3ccd58024140 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -4431,6 +4431,10 @@ SELECT * FROM pg_attribute <primary>language_handler</primary> </indexterm> + <indexterm zone="datatype-pseudo"> + <primary>fdw_handler</primary> + </indexterm> + <indexterm zone="datatype-pseudo"> <primary>cstring</primary> </indexterm> @@ -4513,6 +4517,11 @@ SELECT * FROM pg_attribute <entry>A procedural language call handler is declared to return <type>language_handler</>.</entry> </row> + <row> + <entry><type>fdw_handler</></entry> + <entry>A foreign-data wrapper handler is declared to return <type>fdw_handler</>.</entry> + </row> + <row> <entry><type>record</></entry> <entry>Identifies a function returning an unspecified row type.</entry> diff --git a/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml b/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml index 4e9e8a2e28a323557c2da07ce1c50eda0f0f64c4..af56ed7561ddfeac66951f3874bfea18da3cff19 100644 --- a/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml +++ b/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml @@ -22,7 +22,8 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> ALTER FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable> - [ VALIDATOR <replaceable class="parameter">valfunction</replaceable> | NO VALIDATOR ] + [ HANDLER <replaceable class="parameter">handler_function</replaceable> | NO HANDLER ] + [ VALIDATOR <replaceable class="parameter">validator_function</replaceable> | NO VALIDATOR ] [ OPTIONS ( [ ADD | SET | DROP ] <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ]) ] ALTER FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable> OWNER TO <replaceable>new_owner</replaceable> </synopsis> @@ -34,7 +35,7 @@ ALTER FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable> OWN <para> <command>ALTER FOREIGN DATA WRAPPER</command> changes the definition of a foreign-data wrapper. The first form of the - command changes the library or the generic options of the + command changes the support functions or the generic options of the foreign-data wrapper (at least one clause is required). The second form changes the owner of the foreign-data wrapper. </para> @@ -59,10 +60,33 @@ ALTER FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable> OWN </varlistentry> <varlistentry> - <term><literal>VALIDATOR <replaceable class="parameter">valfunction</replaceable></literal></term> + <term><literal>HANDLER <replaceable class="parameter">handler_function</replaceable></literal></term> <listitem> <para> - Specifies a new foreign-data wrapper validator function. + Specifies a new handler function for the foreign-data wrapper. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>NO HANDLER</literal></term> + <listitem> + <para> + This is used to specify that the foreign-data wrapper should no + longer have a handler function. + </para> + <para> + Note that foreign tables that use a foreign-data wrapper with no + handler cannot be accessed. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>VALIDATOR <replaceable class="parameter">validator_function</replaceable></literal></term> + <listitem> + <para> + Specifies a new validator function for the foreign-data wrapper. </para> <para> @@ -94,7 +118,7 @@ ALTER FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable> OWN specify the action to be performed. <literal>ADD</> is assumed if no operation is explicitly specified. Option names must be unique; names and values are also validated using the foreign - data wrapper library. + data wrapper's validator function, if any. </para> </listitem> </varlistentry> @@ -126,9 +150,8 @@ ALTER FOREIGN DATA WRAPPER dbi VALIDATOR bob.myvalidator; <para> <command>ALTER FOREIGN DATA WRAPPER</command> conforms to ISO/IEC - 9075-9 (SQL/MED). The standard does not specify the <literal> - VALIDATOR</literal> and <literal>OWNER TO</> variants of the - command. + 9075-9 (SQL/MED), except that the <literal>HANDLER</literal>, + <literal>VALIDATOR</> and <literal>OWNER TO</> clauses are extensions. </para> </refsect1> diff --git a/doc/src/sgml/ref/create_foreign_data_wrapper.sgml b/doc/src/sgml/ref/create_foreign_data_wrapper.sgml index f626d56665b25722987107b8c6effb6ca0657de1..711f32b118b31d5c4b04c100d0d23c6939f1bdb9 100644 --- a/doc/src/sgml/ref/create_foreign_data_wrapper.sgml +++ b/doc/src/sgml/ref/create_foreign_data_wrapper.sgml @@ -22,7 +22,8 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> CREATE FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable> - [ VALIDATOR <replaceable class="parameter">valfunction</replaceable> | NO VALIDATOR ] + [ HANDLER <replaceable class="parameter">handler_function</replaceable> | NO HANDLER ] + [ VALIDATOR <replaceable class="parameter">validator_function</replaceable> | NO VALIDATOR ] [ OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [, ... ] ) ] </synopsis> </refsynopsisdiv> @@ -59,13 +60,32 @@ CREATE FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable> </varlistentry> <varlistentry> - <term><literal>VALIDATOR <replaceable class="parameter">valfunction</replaceable></literal></term> + <term><literal>HANDLER <replaceable class="parameter">handler_function</replaceable></literal></term> <listitem> <para> - <replaceable class="parameter">valfunction</replaceable> is the + <replaceable class="parameter">handler_function</replaceable> is the + name of a previously registered function that will be called to + retrieve the execution functions for foreign tables. + The handler function must take no arguments, and + its return type must be <type>fdw_handler</type>. + </para> + + <para> + It is possible to create a foreign-data wrapper with no handler + function, but foreign tables using such a wrapper can only be declared, + not accessed. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>VALIDATOR <replaceable class="parameter">validator_function</replaceable></literal></term> + <listitem> + <para> + <replaceable class="parameter">validator_function</replaceable> is the name of a previously registered function that will be called to check the generic options given to the foreign-data wrapper, as - well as to foreign servers and user mappings using the + well as options for foreign servers and user mappings using the foreign-data wrapper. If no validator function or <literal>NO VALIDATOR</literal> is specified, then options will not be checked at creation time. (Foreign-data wrappers will possibly @@ -75,8 +95,8 @@ CREATE FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable> contain the array of options as stored in the system catalogs, and one of type <type>oid</type>, which will be the OID of the system catalog containing the options. The return type is ignored; - the function should indicate invalid options using the - <function>ereport()</function> function. + the function should report invalid options using the + <function>ereport(ERROR)</function> function. </para> </listitem> </varlistentry> @@ -87,8 +107,8 @@ CREATE FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable> <para> This clause specifies options for the new foreign-data wrapper. The allowed option names and values are specific to each foreign - data wrapper and are validated using the foreign-data wrapper - library. Option names must be unique. + data wrapper and are validated using the foreign-data wrapper's + validator function. Option names must be unique. </para> </listitem> </varlistentry> @@ -122,17 +142,17 @@ CREATE FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable> <title>Examples</title> <para> - Create a foreign-data wrapper <literal>dummy</>: + Create a useless foreign-data wrapper <literal>dummy</>: <programlisting> CREATE FOREIGN DATA WRAPPER dummy; </programlisting> </para> <para> - Create a foreign-data wrapper <literal>postgresql</> with - validator function <literal>postgresql_fdw_validator</>: + Create a foreign-data wrapper <literal>file</> with + handler function <literal>file_fdw_handler</>: <programlisting> -CREATE FOREIGN DATA WRAPPER postgresql VALIDATOR postgresql_fdw_validator; +CREATE FOREIGN DATA WRAPPER file HANDLER file_fdw_handler; </programlisting> </para> @@ -151,10 +171,10 @@ CREATE FOREIGN DATA WRAPPER mywrapper <para> <command>CREATE FOREIGN DATA WRAPPER</command> conforms to ISO/IEC - 9075-9 (SQL/MED), with the exception that - the <literal>VALIDATOR</literal> clause is an extension and the + 9075-9 (SQL/MED), with the exception that the <literal>HANDLER</literal> + and <literal>VALIDATOR</literal> clauses are extensions and the standard clauses <literal>LIBRARY</literal> and <literal>LANGUAGE</literal> - are not yet implemented in PostgreSQL. + are not implemented in PostgreSQL. </para> <para> diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index a2b5358e16fe7e9daf178fcd4f9d2b2115a9360c..acd40c1f4e9edc3a12644efc8f90c85b88806e2c 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -165,7 +165,7 @@ transformGenericOptions(Oid catalogId, result = optionListToArray(resultOptions); - if (fdwvalidator) + if (OidIsValid(fdwvalidator) && DatumGetPointer(result) != NULL) OidFunctionCall2(fdwvalidator, result, ObjectIdGetDatum(catalogId)); return result; @@ -246,8 +246,9 @@ AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId) newOwnerId); } - heap_close(rel, NoLock); heap_freetuple(tup); + + heap_close(rel, RowExclusiveLock); } @@ -308,25 +309,98 @@ AlterForeignServerOwner(const char *name, Oid newOwnerId) newOwnerId); } - heap_close(rel, NoLock); heap_freetuple(tup); + + heap_close(rel, RowExclusiveLock); } +/* + * Convert a handler function name passed from the parser to an Oid. + */ +static Oid +lookup_fdw_handler_func(DefElem *handler) +{ + Oid handlerOid; + + if (handler == NULL || handler->arg == NULL) + return InvalidOid; + + /* handlers have no arguments */ + handlerOid = LookupFuncName((List *) handler->arg, 0, NULL, false); + + /* check that handler has correct return type */ + if (get_func_rettype(handlerOid) != FDW_HANDLEROID) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("function %s must return type \"fdw_handler\"", + NameListToString((List *) handler->arg)))); + + return handlerOid; +} + /* * Convert a validator function name passed from the parser to an Oid. */ static Oid -lookup_fdw_validator_func(List *validator) +lookup_fdw_validator_func(DefElem *validator) { Oid funcargtypes[2]; + if (validator == NULL || validator->arg == NULL) + return InvalidOid; + + /* validators take text[], oid */ funcargtypes[0] = TEXTARRAYOID; funcargtypes[1] = OIDOID; - return LookupFuncName(validator, 2, funcargtypes, false); - /* return value is ignored, so we don't check the type */ + + return LookupFuncName((List *) validator->arg, 2, funcargtypes, false); + /* validator's return value is ignored, so we don't check the type */ } +/* + * Process function options of CREATE/ALTER FDW + */ +static void +parse_func_options(List *func_options, + bool *handler_given, Oid *fdwhandler, + bool *validator_given, Oid *fdwvalidator) +{ + ListCell *cell; + + *handler_given = false; + *validator_given = false; + /* return InvalidOid if not given */ + *fdwhandler = InvalidOid; + *fdwvalidator = InvalidOid; + + foreach(cell, func_options) + { + DefElem *def = (DefElem *) lfirst(cell); + + if (strcmp(def->defname, "handler") == 0) + { + if (*handler_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + *handler_given = true; + *fdwhandler = lookup_fdw_handler_func(def); + } + else if (strcmp(def->defname, "validator") == 0) + { + if (*validator_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + *validator_given = true; + *fdwvalidator = lookup_fdw_validator_func(def); + } + else + elog(ERROR, "option \"%s\" not recognized", + def->defname); + } +} /* * Create a foreign-data wrapper @@ -339,6 +413,9 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) bool nulls[Natts_pg_foreign_data_wrapper]; HeapTuple tuple; Oid fdwId; + bool handler_given; + bool validator_given; + Oid fdwhandler; Oid fdwvalidator; Datum fdwoptions; Oid ownerId; @@ -377,12 +454,13 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) DirectFunctionCall1(namein, CStringGetDatum(stmt->fdwname)); values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId); - if (stmt->validator) - fdwvalidator = lookup_fdw_validator_func(stmt->validator); - else - fdwvalidator = InvalidOid; + /* Lookup handler and validator functions, if given */ + parse_func_options(stmt->func_options, + &handler_given, &fdwhandler, + &validator_given, &fdwvalidator); - values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = fdwvalidator; + values[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler); + values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator); nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true; @@ -408,7 +486,15 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) myself.objectId = fdwId; myself.objectSubId = 0; - if (fdwvalidator) + if (OidIsValid(fdwhandler)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = fdwhandler; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + if (OidIsValid(fdwvalidator)) { referenced.classId = ProcedureRelationId; referenced.objectId = fdwvalidator; @@ -425,7 +511,7 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) InvokeObjectAccessHook(OAT_POST_CREATE, ForeignDataWrapperRelationId, fdwId, 0); - heap_close(rel, NoLock); + heap_close(rel, RowExclusiveLock); } @@ -437,12 +523,16 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt) { Relation rel; HeapTuple tp; + Form_pg_foreign_data_wrapper fdwForm; Datum repl_val[Natts_pg_foreign_data_wrapper]; bool repl_null[Natts_pg_foreign_data_wrapper]; bool repl_repl[Natts_pg_foreign_data_wrapper]; Oid fdwId; bool isnull; Datum datum; + bool handler_given; + bool validator_given; + Oid fdwhandler; Oid fdwvalidator; /* Must be super user */ @@ -461,15 +551,32 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt) (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("foreign-data wrapper \"%s\" does not exist", stmt->fdwname))); + fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp); fdwId = HeapTupleGetOid(tp); memset(repl_val, 0, sizeof(repl_val)); memset(repl_null, false, sizeof(repl_null)); memset(repl_repl, false, sizeof(repl_repl)); - if (stmt->change_validator) + parse_func_options(stmt->func_options, + &handler_given, &fdwhandler, + &validator_given, &fdwvalidator); + + if (handler_given) + { + repl_val[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler); + repl_repl[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = true; + + /* + * It could be that the behavior of accessing foreign table changes + * with the new handler. Warn about this. + */ + ereport(WARNING, + (errmsg("changing the foreign-data wrapper handler can change behavior of existing foreign tables"))); + } + + if (validator_given) { - fdwvalidator = stmt->validator ? lookup_fdw_validator_func(stmt->validator) : InvalidOid; repl_val[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator); repl_repl[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = true; @@ -477,26 +584,21 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt) * It could be that the options for the FDW, SERVER and USER MAPPING * are no longer valid with the new validator. Warn about this. */ - if (stmt->validator) + if (OidIsValid(fdwvalidator)) ereport(WARNING, - (errmsg("changing the foreign-data wrapper validator can cause " - "the options for dependent objects to become invalid"))); + (errmsg("changing the foreign-data wrapper validator can cause " + "the options for dependent objects to become invalid"))); } else { /* * Validator is not changed, but we need it for validating options. */ - datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, - tp, - Anum_pg_foreign_data_wrapper_fdwvalidator, - &isnull); - Assert(!isnull); - fdwvalidator = DatumGetObjectId(datum); + fdwvalidator = fdwForm->fdwvalidator; } /* - * Options specified, validate and update. + * If options specified, validate and update. */ if (stmt->options) { @@ -532,8 +634,46 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt) simple_heap_update(rel, &tp->t_self, tp); CatalogUpdateIndexes(rel, tp); - heap_close(rel, RowExclusiveLock); heap_freetuple(tp); + + /* Update function dependencies if we changed them */ + if (handler_given || validator_given) + { + ObjectAddress myself; + ObjectAddress referenced; + + /* + * Flush all existing dependency records of this FDW on functions; + * we assume there can be none other than the ones we are fixing. + */ + deleteDependencyRecordsForClass(ForeignDataWrapperRelationId, + fdwId, + ProcedureRelationId, + DEPENDENCY_NORMAL); + + /* And build new ones. */ + myself.classId = ForeignDataWrapperRelationId; + myself.objectId = fdwId; + myself.objectSubId = 0; + + if (OidIsValid(fdwhandler)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = fdwhandler; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + if (OidIsValid(fdwvalidator)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = fdwvalidator; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + } + + heap_close(rel, RowExclusiveLock); } @@ -712,7 +852,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt) /* Post creation hook for new foreign server */ InvokeObjectAccessHook(OAT_POST_CREATE, ForeignServerRelationId, srvId, 0); - heap_close(rel, NoLock); + heap_close(rel, RowExclusiveLock); } @@ -804,8 +944,9 @@ AlterForeignServer(AlterForeignServerStmt *stmt) simple_heap_update(rel, &tp->t_self, tp); CatalogUpdateIndexes(rel, tp); - heap_close(rel, RowExclusiveLock); heap_freetuple(tp); + + heap_close(rel, RowExclusiveLock); } @@ -991,7 +1132,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt) /* Post creation hook for new user mapping */ InvokeObjectAccessHook(OAT_POST_CREATE, UserMappingRelationId, umId, 0); - heap_close(rel, NoLock); + heap_close(rel, RowExclusiveLock); } @@ -1076,8 +1217,9 @@ AlterUserMapping(AlterUserMappingStmt *stmt) simple_heap_update(rel, &tp->t_self, tp); CatalogUpdateIndexes(rel, tp); - heap_close(rel, RowExclusiveLock); heap_freetuple(tp); + + heap_close(rel, RowExclusiveLock); } @@ -1184,7 +1326,6 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid) Datum values[Natts_pg_foreign_table]; bool nulls[Natts_pg_foreign_table]; HeapTuple tuple; - Oid ftId; AclResult aclresult; ObjectAddress myself; ObjectAddress referenced; @@ -1237,9 +1378,7 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid) tuple = heap_form_tuple(ftrel->rd_att, values, nulls); - /* pg_foreign_table don't have OID */ - ftId = simple_heap_insert(ftrel, tuple); - + simple_heap_insert(ftrel, tuple); CatalogUpdateIndexes(ftrel, tuple); heap_freetuple(tuple); @@ -1254,5 +1393,5 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid) referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); - heap_close(ftrel, NoLock); + heap_close(ftrel, RowExclusiveLock); } diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c index 9a0f847f93ccfe3b6b43f4bdac0238763051fe50..6e391025ffa6f522f3ae645c20d1602557464a6b 100644 --- a/src/backend/foreign/foreign.c +++ b/src/backend/foreign/foreign.c @@ -58,6 +58,7 @@ GetForeignDataWrapper(Oid fdwid) fdw->fdwid = fdwid; fdw->owner = fdwform->fdwowner; fdw->fdwname = pstrdup(NameStr(fdwform->fdwname)); + fdw->fdwhandler = fdwform->fdwhandler; fdw->fdwvalidator = fdwform->fdwvalidator; /* Extract the options */ diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 57d580208102c116323ffd9ff74dcba21fcd3ecc..9a8a97c4bec1eef854df3815ca7ba6260fa4683c 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3282,7 +3282,7 @@ _copyCreateFdwStmt(CreateFdwStmt *from) CreateFdwStmt *newnode = makeNode(CreateFdwStmt); COPY_STRING_FIELD(fdwname); - COPY_NODE_FIELD(validator); + COPY_NODE_FIELD(func_options); COPY_NODE_FIELD(options); return newnode; @@ -3294,8 +3294,7 @@ _copyAlterFdwStmt(AlterFdwStmt *from) AlterFdwStmt *newnode = makeNode(AlterFdwStmt); COPY_STRING_FIELD(fdwname); - COPY_NODE_FIELD(validator); - COPY_SCALAR_FIELD(change_validator); + COPY_NODE_FIELD(func_options); COPY_NODE_FIELD(options); return newnode; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index f57cf99ba2c1f473cbef55c7c46f78765ceb1ae3..dd332f19f00d91baec544229a6b98772028a9f5b 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1679,7 +1679,7 @@ static bool _equalCreateFdwStmt(CreateFdwStmt *a, CreateFdwStmt *b) { COMPARE_STRING_FIELD(fdwname); - COMPARE_NODE_FIELD(validator); + COMPARE_NODE_FIELD(func_options); COMPARE_NODE_FIELD(options); return true; @@ -1689,8 +1689,7 @@ static bool _equalAlterFdwStmt(AlterFdwStmt *a, AlterFdwStmt *b) { COMPARE_STRING_FIELD(fdwname); - COMPARE_NODE_FIELD(validator); - COMPARE_SCALAR_FIELD(change_validator); + COMPARE_NODE_FIELD(func_options); COMPARE_NODE_FIELD(options); return true; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 077a10532eb7fb86a466e252bea3df403a03ff75..c6811a11bd141b44eb84716fa0e2108d9bc30b3e 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -309,6 +309,9 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_ create_generic_options alter_generic_options relation_expr_list dostmt_opt_list +%type <list> opt_fdw_options fdw_options +%type <defelt> fdw_option + %type <range> OptTempTableName %type <into> into_clause create_as_target @@ -3505,20 +3508,37 @@ AlterExtensionContentsStmt: /***************************************************************************** * * QUERY: - * CREATE FOREIGN DATA WRAPPER name [ VALIDATOR name ] + * CREATE FOREIGN DATA WRAPPER name options * *****************************************************************************/ -CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name opt_validator create_generic_options +CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name opt_fdw_options create_generic_options { CreateFdwStmt *n = makeNode(CreateFdwStmt); n->fdwname = $5; - n->validator = $6; + n->func_options = $6; n->options = $7; $$ = (Node *) n; } ; +fdw_option: + HANDLER handler_name { $$ = makeDefElem("handler", (Node *)$2); } + | NO HANDLER { $$ = makeDefElem("handler", NULL); } + | VALIDATOR handler_name { $$ = makeDefElem("validator", (Node *)$2); } + | NO VALIDATOR { $$ = makeDefElem("validator", NULL); } + ; + +fdw_options: + fdw_option { $$ = list_make1($1); } + | fdw_options fdw_option { $$ = lappend($1, $2); } + ; + +opt_fdw_options: + fdw_options { $$ = $1; } + | /*EMPTY*/ { $$ = NIL; } + ; + /***************************************************************************** * * QUERY : @@ -3547,32 +3567,24 @@ DropFdwStmt: DROP FOREIGN DATA_P WRAPPER name opt_drop_behavior /***************************************************************************** * * QUERY : - * ALTER FOREIGN DATA WRAPPER name + * ALTER FOREIGN DATA WRAPPER name options * ****************************************************************************/ -AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name validator_clause alter_generic_options +AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name opt_fdw_options alter_generic_options { AlterFdwStmt *n = makeNode(AlterFdwStmt); n->fdwname = $5; - n->validator = $6; - n->change_validator = true; + n->func_options = $6; n->options = $7; $$ = (Node *) n; } - | ALTER FOREIGN DATA_P WRAPPER name validator_clause + | ALTER FOREIGN DATA_P WRAPPER name fdw_options { AlterFdwStmt *n = makeNode(AlterFdwStmt); n->fdwname = $5; - n->validator = $6; - n->change_validator = true; - $$ = (Node *) n; - } - | ALTER FOREIGN DATA_P WRAPPER name alter_generic_options - { - AlterFdwStmt *n = makeNode(AlterFdwStmt); - n->fdwname = $5; - n->options = $6; + n->func_options = $6; + n->options = NIL; $$ = (Node *) n; } ; diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c index 2be0696f6093890fffdb4cd49d9b6bc487c1bfab..d9329f834287b7472688c80417a37934a4668abb 100644 --- a/src/backend/utils/adt/pseudotypes.c +++ b/src/backend/utils/adt/pseudotypes.c @@ -267,6 +267,33 @@ language_handler_out(PG_FUNCTION_ARGS) } +/* + * fdw_handler_in - input routine for pseudo-type FDW_HANDLER. + */ +Datum +fdw_handler_in(PG_FUNCTION_ARGS) +{ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot accept a value of type fdw_handler"))); + + PG_RETURN_VOID(); /* keep compiler quiet */ +} + +/* + * fdw_handler_out - output routine for pseudo-type FDW_HANDLER. + */ +Datum +fdw_handler_out(PG_FUNCTION_ARGS) +{ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot display a value of type fdw_handler"))); + + PG_RETURN_VOID(); /* keep compiler quiet */ +} + + /* * internal_in - input routine for pseudo-type INTERNAL. */ diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 60609b6b3593a038afc09366ad05ef8e4c0bd3f5..a9fa3357e795db484dbf2e6124dc97ea7e5593d2 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -6260,6 +6260,7 @@ getForeignDataWrappers(int *numForeignDataWrappers) int i_oid; int i_fdwname; int i_rolname; + int i_fdwhandler; int i_fdwvalidator; int i_fdwacl; int i_fdwoptions; @@ -6274,13 +6275,30 @@ getForeignDataWrappers(int *numForeignDataWrappers) /* Make sure we are in proper schema */ selectSourceSchema("pg_catalog"); - appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, " - "(%s fdwowner) AS rolname, fdwvalidator::pg_catalog.regproc, fdwacl," - "array_to_string(ARRAY(" - " SELECT option_name || ' ' || quote_literal(option_value) " - " FROM pg_options_to_table(fdwoptions)), ', ') AS fdwoptions " - "FROM pg_foreign_data_wrapper", - username_subquery); + if (g_fout->remoteVersion >= 90100) + { + appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, " + "(%s fdwowner) AS rolname, " + "fdwhandler::pg_catalog.regproc, " + "fdwvalidator::pg_catalog.regproc, fdwacl, " + "array_to_string(ARRAY(" + " SELECT option_name || ' ' || quote_literal(option_value) " + " FROM pg_options_to_table(fdwoptions)), ', ') AS fdwoptions " + "FROM pg_foreign_data_wrapper", + username_subquery); + } + else + { + appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, " + "(%s fdwowner) AS rolname, " + "'-' AS fdwhandler, " + "fdwvalidator::pg_catalog.regproc, fdwacl, " + "array_to_string(ARRAY(" + " SELECT option_name || ' ' || quote_literal(option_value) " + " FROM pg_options_to_table(fdwoptions)), ', ') AS fdwoptions " + "FROM pg_foreign_data_wrapper", + username_subquery); + } res = PQexec(g_conn, query->data); check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK); @@ -6294,6 +6312,7 @@ getForeignDataWrappers(int *numForeignDataWrappers) i_oid = PQfnumber(res, "oid"); i_fdwname = PQfnumber(res, "fdwname"); i_rolname = PQfnumber(res, "rolname"); + i_fdwhandler = PQfnumber(res, "fdwhandler"); i_fdwvalidator = PQfnumber(res, "fdwvalidator"); i_fdwacl = PQfnumber(res, "fdwacl"); i_fdwoptions = PQfnumber(res, "fdwoptions"); @@ -6307,11 +6326,11 @@ getForeignDataWrappers(int *numForeignDataWrappers) fdwinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_fdwname)); fdwinfo[i].dobj.namespace = NULL; fdwinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname)); + fdwinfo[i].fdwhandler = strdup(PQgetvalue(res, i, i_fdwhandler)); fdwinfo[i].fdwvalidator = strdup(PQgetvalue(res, i, i_fdwvalidator)); fdwinfo[i].fdwoptions = strdup(PQgetvalue(res, i, i_fdwoptions)); fdwinfo[i].fdwacl = strdup(PQgetvalue(res, i, i_fdwacl)); - /* Decide whether we want to dump it */ selectDumpableObject(&(fdwinfo[i].dobj)); } @@ -10929,11 +10948,13 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo) appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s", qfdwname); - if (fdwinfo->fdwvalidator && strcmp(fdwinfo->fdwvalidator, "-") != 0) - appendPQExpBuffer(q, " VALIDATOR %s", - fdwinfo->fdwvalidator); + if (strcmp(fdwinfo->fdwhandler, "-") != 0) + appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler); + + if (strcmp(fdwinfo->fdwvalidator, "-") != 0) + appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator); - if (fdwinfo->fdwoptions && strlen(fdwinfo->fdwoptions) > 0) + if (strlen(fdwinfo->fdwoptions) > 0) appendPQExpBuffer(q, " OPTIONS (%s)", fdwinfo->fdwoptions); appendPQExpBuffer(q, ";\n"); diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 3c02af44b1329b33a55ad1ad977a1785c1458029..94b7a6bf928a343d02478f48d09d754c9382db6f 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -440,6 +440,7 @@ typedef struct _fdwInfo { DumpableObject dobj; char *rolname; + char *fdwhandler; char *fdwvalidator; char *fdwoptions; char *fdwacl; diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 735eef786b4d911b6565248d8197175ef79098b1..94396b191062bdc05fa272c19c250ebfe5cf23a0 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -3562,10 +3562,15 @@ listForeignDataWrappers(const char *pattern, bool verbose) initPQExpBuffer(&buf); printfPQExpBuffer(&buf, "SELECT fdwname AS \"%s\",\n" - " pg_catalog.pg_get_userbyid(fdwowner) AS \"%s\",\n" - " fdwvalidator::pg_catalog.regproc AS \"%s\"", + " pg_catalog.pg_get_userbyid(fdwowner) AS \"%s\",\n", gettext_noop("Name"), - gettext_noop("Owner"), + gettext_noop("Owner")); + if (pset.sversion >= 90100) + appendPQExpBuffer(&buf, + " fdwhandler::pg_catalog.regproc AS \"%s\",\n", + gettext_noop("Handler")); + appendPQExpBuffer(&buf, + " fdwvalidator::pg_catalog.regproc AS \"%s\"", gettext_noop("Validator")); if (verbose) diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 1a7be47fab8609def269011a120b1a2a3e431540..989138169a922f76317362a99f8e33231eee6940 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201102181 +#define CATALOG_VERSION_NO 201102191 #endif diff --git a/src/include/catalog/pg_foreign_data_wrapper.h b/src/include/catalog/pg_foreign_data_wrapper.h index a83556df151e62dddf50064afb58707e43c1cb12..10afb370fd79f2b2d942a09ad197216c59cca721 100644 --- a/src/include/catalog/pg_foreign_data_wrapper.h +++ b/src/include/catalog/pg_foreign_data_wrapper.h @@ -32,7 +32,8 @@ CATALOG(pg_foreign_data_wrapper,2328) { NameData fdwname; /* foreign-data wrapper name */ Oid fdwowner; /* FDW owner */ - Oid fdwvalidator; /* optional validation function */ + Oid fdwhandler; /* handler function, or 0 if none */ + Oid fdwvalidator; /* option validation function, or 0 if none */ /* VARIABLE LENGTH FIELDS start here. */ @@ -52,11 +53,12 @@ typedef FormData_pg_foreign_data_wrapper *Form_pg_foreign_data_wrapper; * ---------------- */ -#define Natts_pg_foreign_data_wrapper 5 +#define Natts_pg_foreign_data_wrapper 6 #define Anum_pg_foreign_data_wrapper_fdwname 1 #define Anum_pg_foreign_data_wrapper_fdwowner 2 -#define Anum_pg_foreign_data_wrapper_fdwvalidator 3 -#define Anum_pg_foreign_data_wrapper_fdwacl 4 -#define Anum_pg_foreign_data_wrapper_fdwoptions 5 +#define Anum_pg_foreign_data_wrapper_fdwhandler 3 +#define Anum_pg_foreign_data_wrapper_fdwvalidator 4 +#define Anum_pg_foreign_data_wrapper_fdwacl 5 +#define Anum_pg_foreign_data_wrapper_fdwoptions 6 #endif /* PG_FOREIGN_DATA_WRAPPER_H */ diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index b3458ed56eb5ae7e51a0cb5a56293bb4b25e240a..08949853f190d3190f6ed8afcd5e947581e926d6 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -3913,6 +3913,10 @@ DATA(insert OID = 2777 ( anynonarray_in PGNSP PGUID 12 1 0 0 f f f t f i 1 0 27 DESCR("I/O"); DATA(insert OID = 2778 ( anynonarray_out PGNSP PGUID 12 1 0 0 f f f t f i 1 0 2275 "2776" _null_ _null_ _null_ _null_ anynonarray_out _null_ _null_ _null_ )); DESCR("I/O"); +DATA(insert OID = 3116 ( fdw_handler_in PGNSP PGUID 12 1 0 0 f f f f f i 1 0 3115 "2275" _null_ _null_ _null_ _null_ fdw_handler_in _null_ _null_ _null_ )); +DESCR("I/O"); +DATA(insert OID = 3117 ( fdw_handler_out PGNSP PGUID 12 1 0 0 f f f t f i 1 0 2275 "3115" _null_ _null_ _null_ _null_ fdw_handler_out _null_ _null_ _null_ )); +DESCR("I/O"); /* cryptographic */ DATA(insert OID = 2311 ( md5 PGNSP PGUID 12 1 0 0 f f f t f i 1 0 25 "25" _null_ _null_ _null_ _null_ md5_text _null_ _null_ _null_ )); diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index d82078ec0bad915974b077e8feba4515698d7121..0f7312e495d4c74accecf4825060638ea159000b 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -631,6 +631,8 @@ DATA(insert OID = 2776 ( anynonarray PGNSP PGUID 4 t p P f t \054 0 0 0 anynona #define ANYNONARRAYOID 2776 DATA(insert OID = 3500 ( anyenum PGNSP PGUID 4 t p P f t \054 0 0 0 anyenum_in anyenum_out - - - - - i p f 0 -1 0 0 _null_ _null_ )); #define ANYENUMOID 3500 +DATA(insert OID = 3115 ( fdw_handler PGNSP PGUID 4 t p P f t \054 0 0 0 fdw_handler_in fdw_handler_out - - - - - i p f 0 -1 0 0 _null_ _null_ )); +#define FDW_HANDLEROID 3115 /* diff --git a/src/include/foreign/foreign.h b/src/include/foreign/foreign.h index 2d1495cfe133e079d1ee03500c7c335c367bbd8d..2cf0eaa09cc8c6515002dbe732e9a26df0878051 100644 --- a/src/include/foreign/foreign.h +++ b/src/include/foreign/foreign.h @@ -37,7 +37,8 @@ typedef struct ForeignDataWrapper Oid fdwid; /* FDW Oid */ Oid owner; /* FDW owner user Oid */ char *fdwname; /* Name of the FDW */ - Oid fdwvalidator; + Oid fdwhandler; /* Oid of handler function, or 0 */ + Oid fdwvalidator; /* Oid of validator function, or 0 */ List *options; /* fdwoptions as DefElem list */ } ForeignDataWrapper; diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 8aaa8c1d2f7f322c20c67b457cdb5eea87c7417d..63a61e3da248b2a1677d35eb56ff2b82b9c53b64 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1574,7 +1574,7 @@ typedef struct CreateFdwStmt { NodeTag type; char *fdwname; /* foreign-data wrapper name */ - List *validator; /* optional validator function (qual. name) */ + List *func_options; /* HANDLER/VALIDATOR options */ List *options; /* generic options to FDW */ } CreateFdwStmt; @@ -1582,8 +1582,7 @@ typedef struct AlterFdwStmt { NodeTag type; char *fdwname; /* foreign-data wrapper name */ - List *validator; /* optional validator function (qual. name) */ - bool change_validator; + List *func_options; /* HANDLER/VALIDATOR options */ List *options; /* generic options to FDW */ } AlterFdwStmt; diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 277aec414c38100546ca1a488213fef66568f76f..8392be6208a89666ecd55121e401fcd496389c90 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -508,6 +508,8 @@ extern Datum trigger_in(PG_FUNCTION_ARGS); extern Datum trigger_out(PG_FUNCTION_ARGS); extern Datum language_handler_in(PG_FUNCTION_ARGS); extern Datum language_handler_out(PG_FUNCTION_ARGS); +extern Datum fdw_handler_in(PG_FUNCTION_ARGS); +extern Datum fdw_handler_out(PG_FUNCTION_ARGS); extern Datum internal_in(PG_FUNCTION_ARGS); extern Datum internal_out(PG_FUNCTION_ARGS); extern Datum opaque_in(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out index d6c650be14d0488ffc0260e73e45a8a45e513425..780098c2373548bdcb049b2e40c7fdf837e4aca1 100644 --- a/src/test/regress/expected/foreign_data.out +++ b/src/test/regress/expected/foreign_data.out @@ -16,11 +16,11 @@ CREATE ROLE unprivileged_role; CREATE FOREIGN DATA WRAPPER dummy; CREATE FOREIGN DATA WRAPPER postgresql VALIDATOR postgresql_fdw_validator; -- At this point we should have 2 built-in wrappers and no servers. -SELECT fdwname, fdwvalidator::regproc, fdwoptions FROM pg_foreign_data_wrapper ORDER BY 1, 2, 3; - fdwname | fdwvalidator | fdwoptions -------------+--------------------------+------------ - dummy | - | - postgresql | postgresql_fdw_validator | +SELECT fdwname, fdwhandler::regproc, fdwvalidator::regproc, fdwoptions FROM pg_foreign_data_wrapper ORDER BY 1, 2, 3; + fdwname | fdwhandler | fdwvalidator | fdwoptions +------------+------------+--------------------------+------------ + dummy | - | - | + postgresql | - | postgresql_fdw_validator | (2 rows) SELECT srvname, srvoptions FROM pg_foreign_server; @@ -38,12 +38,12 @@ CREATE FOREIGN DATA WRAPPER foo VALIDATOR bar; -- ERROR ERROR: function bar(text[], oid) does not exist CREATE FOREIGN DATA WRAPPER foo; \dew - List of foreign-data wrappers - Name | Owner | Validator -------------+-------------------+-------------------------- - dummy | foreign_data_user | - - foo | foreign_data_user | - - postgresql | foreign_data_user | postgresql_fdw_validator + List of foreign-data wrappers + Name | Owner | Handler | Validator +------------+-------------------+---------+-------------------------- + dummy | foreign_data_user | - | - + foo | foreign_data_user | - | - + postgresql | foreign_data_user | - | postgresql_fdw_validator (3 rows) CREATE FOREIGN DATA WRAPPER foo; -- duplicate @@ -51,12 +51,12 @@ ERROR: foreign-data wrapper "foo" already exists DROP FOREIGN DATA WRAPPER foo; CREATE FOREIGN DATA WRAPPER foo OPTIONS (testing '1'); \dew+ - List of foreign-data wrappers - Name | Owner | Validator | Access privileges | Options -------------+-------------------+--------------------------+-------------------+------------- - dummy | foreign_data_user | - | | - foo | foreign_data_user | - | | {testing=1} - postgresql | foreign_data_user | postgresql_fdw_validator | | + List of foreign-data wrappers + Name | Owner | Handler | Validator | Access privileges | Options +------------+-------------------+---------+--------------------------+-------------------+------------- + dummy | foreign_data_user | - | - | | + foo | foreign_data_user | - | - | | {testing=1} + postgresql | foreign_data_user | - | postgresql_fdw_validator | | (3 rows) DROP FOREIGN DATA WRAPPER foo; @@ -64,12 +64,12 @@ CREATE FOREIGN DATA WRAPPER foo OPTIONS (testing '1', testing '2'); -- ERROR ERROR: option "testing" provided more than once CREATE FOREIGN DATA WRAPPER foo OPTIONS (testing '1', another '2'); \dew+ - List of foreign-data wrappers - Name | Owner | Validator | Access privileges | Options -------------+-------------------+--------------------------+-------------------+----------------------- - dummy | foreign_data_user | - | | - foo | foreign_data_user | - | | {testing=1,another=2} - postgresql | foreign_data_user | postgresql_fdw_validator | | + List of foreign-data wrappers + Name | Owner | Handler | Validator | Access privileges | Options +------------+-------------------+---------+--------------------------+-------------------+----------------------- + dummy | foreign_data_user | - | - | | + foo | foreign_data_user | - | - | | {testing=1,another=2} + postgresql | foreign_data_user | - | postgresql_fdw_validator | | (3 rows) DROP FOREIGN DATA WRAPPER foo; @@ -80,12 +80,12 @@ HINT: Must be superuser to create a foreign-data wrapper. RESET ROLE; CREATE FOREIGN DATA WRAPPER foo VALIDATOR postgresql_fdw_validator; \dew+ - List of foreign-data wrappers - Name | Owner | Validator | Access privileges | Options -------------+-------------------+--------------------------+-------------------+--------- - dummy | foreign_data_user | - | | - foo | foreign_data_user | postgresql_fdw_validator | | - postgresql | foreign_data_user | postgresql_fdw_validator | | + List of foreign-data wrappers + Name | Owner | Handler | Validator | Access privileges | Options +------------+-------------------+---------+--------------------------+-------------------+--------- + dummy | foreign_data_user | - | - | | + foo | foreign_data_user | - | postgresql_fdw_validator | | + postgresql | foreign_data_user | - | postgresql_fdw_validator | | (3 rows) -- ALTER FOREIGN DATA WRAPPER @@ -97,12 +97,12 @@ ALTER FOREIGN DATA WRAPPER foo VALIDATOR bar; -- ERROR ERROR: function bar(text[], oid) does not exist ALTER FOREIGN DATA WRAPPER foo NO VALIDATOR; \dew+ - List of foreign-data wrappers - Name | Owner | Validator | Access privileges | Options -------------+-------------------+--------------------------+-------------------+--------- - dummy | foreign_data_user | - | | - foo | foreign_data_user | - | | - postgresql | foreign_data_user | postgresql_fdw_validator | | + List of foreign-data wrappers + Name | Owner | Handler | Validator | Access privileges | Options +------------+-------------------+---------+--------------------------+-------------------+--------- + dummy | foreign_data_user | - | - | | + foo | foreign_data_user | - | - | | + postgresql | foreign_data_user | - | postgresql_fdw_validator | | (3 rows) ALTER FOREIGN DATA WRAPPER foo OPTIONS (a '1', b '2'); @@ -112,34 +112,34 @@ ALTER FOREIGN DATA WRAPPER foo OPTIONS (DROP c); -- ERROR ERROR: option "c" not found ALTER FOREIGN DATA WRAPPER foo OPTIONS (ADD x '1', DROP x); \dew+ - List of foreign-data wrappers - Name | Owner | Validator | Access privileges | Options -------------+-------------------+--------------------------+-------------------+----------- - dummy | foreign_data_user | - | | - foo | foreign_data_user | - | | {a=1,b=2} - postgresql | foreign_data_user | postgresql_fdw_validator | | + List of foreign-data wrappers + Name | Owner | Handler | Validator | Access privileges | Options +------------+-------------------+---------+--------------------------+-------------------+----------- + dummy | foreign_data_user | - | - | | + foo | foreign_data_user | - | - | | {a=1,b=2} + postgresql | foreign_data_user | - | postgresql_fdw_validator | | (3 rows) ALTER FOREIGN DATA WRAPPER foo OPTIONS (DROP a, SET b '3', ADD c '4'); \dew+ - List of foreign-data wrappers - Name | Owner | Validator | Access privileges | Options -------------+-------------------+--------------------------+-------------------+----------- - dummy | foreign_data_user | - | | - foo | foreign_data_user | - | | {b=3,c=4} - postgresql | foreign_data_user | postgresql_fdw_validator | | + List of foreign-data wrappers + Name | Owner | Handler | Validator | Access privileges | Options +------------+-------------------+---------+--------------------------+-------------------+----------- + dummy | foreign_data_user | - | - | | + foo | foreign_data_user | - | - | | {b=3,c=4} + postgresql | foreign_data_user | - | postgresql_fdw_validator | | (3 rows) ALTER FOREIGN DATA WRAPPER foo OPTIONS (a '2'); ALTER FOREIGN DATA WRAPPER foo OPTIONS (b '4'); -- ERROR ERROR: option "b" provided more than once \dew+ - List of foreign-data wrappers - Name | Owner | Validator | Access privileges | Options -------------+-------------------+--------------------------+-------------------+--------------- - dummy | foreign_data_user | - | | - foo | foreign_data_user | - | | {b=3,c=4,a=2} - postgresql | foreign_data_user | postgresql_fdw_validator | | + List of foreign-data wrappers + Name | Owner | Handler | Validator | Access privileges | Options +------------+-------------------+---------+--------------------------+-------------------+--------------- + dummy | foreign_data_user | - | - | | + foo | foreign_data_user | - | - | | {b=3,c=4,a=2} + postgresql | foreign_data_user | - | postgresql_fdw_validator | | (3 rows) SET ROLE regress_test_role; @@ -149,12 +149,12 @@ HINT: Must be superuser to alter a foreign-data wrapper. SET ROLE regress_test_role_super; ALTER FOREIGN DATA WRAPPER foo OPTIONS (ADD d '5'); \dew+ - List of foreign-data wrappers - Name | Owner | Validator | Access privileges | Options -------------+-------------------+--------------------------+-------------------+------------------- - dummy | foreign_data_user | - | | - foo | foreign_data_user | - | | {b=3,c=4,a=2,d=5} - postgresql | foreign_data_user | postgresql_fdw_validator | | + List of foreign-data wrappers + Name | Owner | Handler | Validator | Access privileges | Options +------------+-------------------+---------+--------------------------+-------------------+------------------- + dummy | foreign_data_user | - | - | | + foo | foreign_data_user | - | - | | {b=3,c=4,a=2,d=5} + postgresql | foreign_data_user | - | postgresql_fdw_validator | | (3 rows) ALTER FOREIGN DATA WRAPPER foo OWNER TO regress_test_role; -- ERROR @@ -168,12 +168,12 @@ ERROR: permission denied to alter foreign-data wrapper "foo" HINT: Must be superuser to alter a foreign-data wrapper. RESET ROLE; \dew+ - List of foreign-data wrappers - Name | Owner | Validator | Access privileges | Options -------------+-------------------------+--------------------------+-------------------+------------------- - dummy | foreign_data_user | - | | - foo | regress_test_role_super | - | | {b=3,c=4,a=2,d=5} - postgresql | foreign_data_user | postgresql_fdw_validator | | + List of foreign-data wrappers + Name | Owner | Handler | Validator | Access privileges | Options +------------+-------------------------+---------+--------------------------+-------------------+------------------- + dummy | foreign_data_user | - | - | | + foo | regress_test_role_super | - | - | | {b=3,c=4,a=2,d=5} + postgresql | foreign_data_user | - | postgresql_fdw_validator | | (3 rows) -- DROP FOREIGN DATA WRAPPER @@ -182,12 +182,12 @@ ERROR: foreign-data wrapper "nonexistent" does not exist DROP FOREIGN DATA WRAPPER IF EXISTS nonexistent; NOTICE: foreign-data wrapper "nonexistent" does not exist, skipping \dew+ - List of foreign-data wrappers - Name | Owner | Validator | Access privileges | Options -------------+-------------------------+--------------------------+-------------------+------------------- - dummy | foreign_data_user | - | | - foo | regress_test_role_super | - | | {b=3,c=4,a=2,d=5} - postgresql | foreign_data_user | postgresql_fdw_validator | | + List of foreign-data wrappers + Name | Owner | Handler | Validator | Access privileges | Options +------------+-------------------------+---------+--------------------------+-------------------+------------------- + dummy | foreign_data_user | - | - | | + foo | regress_test_role_super | - | - | | {b=3,c=4,a=2,d=5} + postgresql | foreign_data_user | - | postgresql_fdw_validator | | (3 rows) DROP ROLE regress_test_role_super; -- ERROR @@ -202,23 +202,23 @@ ALTER ROLE regress_test_role_super SUPERUSER; DROP FOREIGN DATA WRAPPER foo; DROP ROLE regress_test_role_super; \dew+ - List of foreign-data wrappers - Name | Owner | Validator | Access privileges | Options -------------+-------------------+--------------------------+-------------------+--------- - dummy | foreign_data_user | - | | - postgresql | foreign_data_user | postgresql_fdw_validator | | + List of foreign-data wrappers + Name | Owner | Handler | Validator | Access privileges | Options +------------+-------------------+---------+--------------------------+-------------------+--------- + dummy | foreign_data_user | - | - | | + postgresql | foreign_data_user | - | postgresql_fdw_validator | | (2 rows) CREATE FOREIGN DATA WRAPPER foo; CREATE SERVER s1 FOREIGN DATA WRAPPER foo; CREATE USER MAPPING FOR current_user SERVER s1; \dew+ - List of foreign-data wrappers - Name | Owner | Validator | Access privileges | Options -------------+-------------------+--------------------------+-------------------+--------- - dummy | foreign_data_user | - | | - foo | foreign_data_user | - | | - postgresql | foreign_data_user | postgresql_fdw_validator | | + List of foreign-data wrappers + Name | Owner | Handler | Validator | Access privileges | Options +------------+-------------------+---------+--------------------------+-------------------+--------- + dummy | foreign_data_user | - | - | | + foo | foreign_data_user | - | - | | + postgresql | foreign_data_user | - | postgresql_fdw_validator | | (3 rows) \des+ @@ -250,11 +250,11 @@ NOTICE: drop cascades to 2 other objects DETAIL: drop cascades to server s1 drop cascades to user mapping for foreign_data_user \dew+ - List of foreign-data wrappers - Name | Owner | Validator | Access privileges | Options -------------+-------------------+--------------------------+-------------------+--------- - dummy | foreign_data_user | - | | - postgresql | foreign_data_user | postgresql_fdw_validator | | + List of foreign-data wrappers + Name | Owner | Handler | Validator | Access privileges | Options +------------+-------------------+---------+--------------------------+-------------------+--------- + dummy | foreign_data_user | - | - | | + postgresql | foreign_data_user | - | postgresql_fdw_validator | | (2 rows) \des+ @@ -669,6 +669,10 @@ Has OIDs: no CREATE INDEX id_ft1_c2 ON ft1 (c2); -- ERROR ERROR: "ft1" is not a table +SELECT * FROM ft1; -- ERROR +ERROR: foreign table scans are not yet supported +EXPLAIN SELECT * FROM ft1; -- ERROR +ERROR: foreign table scans are not yet supported -- ALTER FOREIGN TABLE COMMENT ON FOREIGN TABLE ft1 IS 'foreign table'; COMMENT ON FOREIGN TABLE ft1 IS NULL; @@ -1105,9 +1109,9 @@ NOTICE: drop cascades to server sc \c DROP ROLE foreign_data_user; -- At this point we should have no wrappers, no servers, and no mappings. -SELECT fdwname, fdwvalidator, fdwoptions FROM pg_foreign_data_wrapper; - fdwname | fdwvalidator | fdwoptions ----------+--------------+------------ +SELECT fdwname, fdwhandler, fdwvalidator, fdwoptions FROM pg_foreign_data_wrapper; + fdwname | fdwhandler | fdwvalidator | fdwoptions +---------+------------+--------------+------------ (0 rows) SELECT srvname, srvoptions FROM pg_foreign_server; diff --git a/src/test/regress/sql/foreign_data.sql b/src/test/regress/sql/foreign_data.sql index 86b698a1b616420946138a08d84b4c81a8642a7e..3f3978590319583ca9fe173160c287d3655fdc87 100644 --- a/src/test/regress/sql/foreign_data.sql +++ b/src/test/regress/sql/foreign_data.sql @@ -24,7 +24,7 @@ CREATE FOREIGN DATA WRAPPER dummy; CREATE FOREIGN DATA WRAPPER postgresql VALIDATOR postgresql_fdw_validator; -- At this point we should have 2 built-in wrappers and no servers. -SELECT fdwname, fdwvalidator::regproc, fdwoptions FROM pg_foreign_data_wrapper ORDER BY 1, 2, 3; +SELECT fdwname, fdwhandler::regproc, fdwvalidator::regproc, fdwoptions FROM pg_foreign_data_wrapper ORDER BY 1, 2, 3; SELECT srvname, srvoptions FROM pg_foreign_server; SELECT * FROM pg_user_mapping; @@ -271,6 +271,8 @@ COMMENT ON COLUMN ft1.c1 IS 'ft1.c1'; \d+ ft1 \det+ CREATE INDEX id_ft1_c2 ON ft1 (c2); -- ERROR +SELECT * FROM ft1; -- ERROR +EXPLAIN SELECT * FROM ft1; -- ERROR -- ALTER FOREIGN TABLE COMMENT ON FOREIGN TABLE ft1 IS 'foreign table'; @@ -453,6 +455,6 @@ DROP FOREIGN DATA WRAPPER dummy CASCADE; DROP ROLE foreign_data_user; -- At this point we should have no wrappers, no servers, and no mappings. -SELECT fdwname, fdwvalidator, fdwoptions FROM pg_foreign_data_wrapper; +SELECT fdwname, fdwhandler, fdwvalidator, fdwoptions FROM pg_foreign_data_wrapper; SELECT srvname, srvoptions FROM pg_foreign_server; SELECT * FROM pg_user_mapping;