From 0aebead7e3cc39ccdc710f859951f44d7aa0d9c2 Mon Sep 17 00:00:00 2001 From: Shigeru Hanada Date: Mon, 7 Feb 2011 13:55:40 +0900 Subject: [PATCH] Add HANDLER function support to FOREIGN DATA WRAPPER. --- doc/src/sgml/catalogs.sgml | 11 ++ .../sgml/ref/alter_foreign_data_wrapper.sgml | 28 ++- .../sgml/ref/create_foreign_data_wrapper.sgml | 18 +- src/backend/commands/foreigncmds.c | 123 +++++++++++- src/backend/foreign/foreign.c | 1 + src/backend/nodes/copyfuncs.c | 5 +- src/backend/nodes/equalfuncs.c | 5 +- src/backend/parser/gram.y | 42 ++-- src/backend/utils/adt/pseudotypes.c | 26 +++ src/bin/pg_dump/pg_dump.c | 40 +++- src/bin/pg_dump/pg_dump.h | 1 + src/bin/psql/describe.c | 2 + src/include/catalog/pg_foreign_data_wrapper.h | 8 +- src/include/catalog/pg_proc.h | 4 + src/include/catalog/pg_type.h | 2 + src/include/foreign/foreign.h | 1 + src/include/nodes/parsenodes.h | 5 +- src/include/utils/builtins.h | 2 + src/test/regress/expected/foreign_data.out | 180 +++++++++--------- src/test/regress/sql/foreign_data.sql | 4 +- 20 files changed, 369 insertions(+), 139 deletions(-) diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index be132f2eb7..f4cb8857a7 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -2818,6 +2818,17 @@ + + fdwhandler + oid + pg_proc.oid + + References a handler function that is responsible for + supplying foreign-data wrapper routines. + Zero if no handler is provided. + + + fdwacl aclitem[] diff --git a/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml b/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml index 4e9e8a2e28..7e17ef3e23 100644 --- a/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml +++ b/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml @@ -23,6 +23,7 @@ PostgreSQL documentation ALTER FOREIGN DATA WRAPPER name [ VALIDATOR valfunction | NO VALIDATOR ] + [ HANDLER handler | NO HANDLER ] [ OPTIONS ( [ ADD | SET | DROP ] option ['value'] [, ... ]) ] ALTER FOREIGN DATA WRAPPER name OWNER TO new_owner @@ -85,6 +86,29 @@ ALTER FOREIGN DATA WRAPPER name OWN + + HANDLER handler + + + Specifies a new foreign-data wrapper handler function. + + + + + + NO HANDLER + + + This is used to specify that the foreign-data wrapper should no + longer have a handler function. + + + Note that foreign tables which uses a foreign-data wrapper with no + handler can't be used in a SELECT statement. + + + + OPTIONS ( [ ADD | SET | DROP ] option ['value'] [, ... ] ) @@ -127,8 +151,8 @@ ALTER FOREIGN DATA WRAPPER dbi VALIDATOR bob.myvalidator; ALTER FOREIGN DATA WRAPPER conforms to ISO/IEC 9075-9 (SQL/MED). The standard does not specify the - VALIDATOR and OWNER TO variants of the - command. + VALIDATOR, HANDLER and OWNER TO + variants of the command. diff --git a/doc/src/sgml/ref/create_foreign_data_wrapper.sgml b/doc/src/sgml/ref/create_foreign_data_wrapper.sgml index f626d56665..d70321ba77 100644 --- a/doc/src/sgml/ref/create_foreign_data_wrapper.sgml +++ b/doc/src/sgml/ref/create_foreign_data_wrapper.sgml @@ -23,6 +23,7 @@ PostgreSQL documentation CREATE FOREIGN DATA WRAPPER name [ VALIDATOR valfunction | NO VALIDATOR ] + [ HANDLER handler | NO HANDLER ] [ OPTIONS ( option 'value' [, ... ] ) ] @@ -81,6 +82,19 @@ CREATE FOREIGN DATA WRAPPER name + + HANDLER handler + + + handler is the + name of a previously registered function that will be called to + retrieve a set of functions for foreign tables. + The handler function must take no arguments. + The return type must be fdw_handler. + + + + OPTIONS ( option 'value' [, ... ] ) @@ -151,8 +165,8 @@ CREATE FOREIGN DATA WRAPPER mywrapper CREATE FOREIGN DATA WRAPPER conforms to ISO/IEC - 9075-9 (SQL/MED), with the exception that - the VALIDATOR clause is an extension and the + 9075-9 (SQL/MED), with the exception that the VALIDATOR + and HANDLER clauses are extensions and the clauses LIBRARY and LANGUAGE are not yet implemented in PostgreSQL. diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index 3a0ea9a632..e9248f64c0 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -317,16 +317,69 @@ AlterForeignServerOwner(const char *name, Oid newOwnerId) * 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; + funcargtypes[0] = TEXTARRAYOID; funcargtypes[1] = OIDOID; - return LookupFuncName(validator, 2, funcargtypes, false); + return LookupFuncName((List *) validator->arg, 2, funcargtypes, false); /* return value is ignored, so we don't check the type */ } +static Oid +lookup_fdw_handler_func(DefElem *handler) +{ + Oid handlerOid; + + if (handler == NULL || handler->arg == NULL) + return InvalidOid; + + /* check that handler have correct return type */ + handlerOid = LookupFuncName((List *) handler->arg, 0, NULL, false); + 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; +} + +static void +parse_func_options(List *func_options, DefElem **validator, DefElem **handler) +{ + ListCell *cell; + + *validator = NULL; + *handler = NULL; + foreach (cell, func_options) + { + DefElem *def = lfirst(cell); + + if (pg_strcasecmp(def->defname, "validator") == 0) + { + if (*validator) + ereport(ERROR, (errmsg("duplicated VALIDATOR"))); + *validator = def; + } + else if (pg_strcasecmp(def->defname, "handler") == 0) + { + if (*handler) + ereport(ERROR, (errmsg("duplicated HANDLER"))); + *handler = def; + } + else + { + ereport(ERROR, (errmsg("invalid option"))); + } + } +} /* * Create a foreign-data wrapper @@ -339,7 +392,10 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) bool nulls[Natts_pg_foreign_data_wrapper]; HeapTuple tuple; Oid fdwId; + DefElem *defvalidator; + DefElem *defhandler; Oid fdwvalidator; + Oid fdwhandler; Datum fdwoptions; Oid ownerId; @@ -375,12 +431,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; + /* determine which validator to be used (or not used at all) */ + parse_func_options(stmt->func_options, &defvalidator, &defhandler); + fdwvalidator = lookup_fdw_validator_func(defvalidator); + fdwhandler = lookup_fdw_handler_func(defhandler); values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = fdwvalidator; + values[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = fdwhandler; nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true; @@ -416,6 +473,21 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } + if (fdwhandler != InvalidOid) + { + ObjectAddress myself; + ObjectAddress referenced; + + myself.classId = ForeignDataWrapperRelationId; + myself.objectId = fdwId; + myself.objectSubId = 0; + + referenced.classId = ProcedureRelationId; + referenced.objectId = fdwhandler; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId); /* Post creation hook for new foreign data wrapper */ @@ -440,7 +512,10 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt) Oid fdwId; bool isnull; Datum datum; + DefElem *defvalidator; + DefElem *defhandler; Oid fdwvalidator; + Oid fdwhandler; /* Must be super user */ if (!superuser()) @@ -464,9 +539,11 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt) memset(repl_null, false, sizeof(repl_null)); memset(repl_repl, false, sizeof(repl_repl)); - if (stmt->change_validator) + parse_func_options(stmt->func_options, &defvalidator, &defhandler); + + if (defvalidator) { - fdwvalidator = stmt->validator ? lookup_fdw_validator_func(stmt->validator) : InvalidOid; + fdwvalidator = lookup_fdw_validator_func(defvalidator); repl_val[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator); repl_repl[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = true; @@ -474,7 +551,7 @@ 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 (defvalidator->arg) ereport(WARNING, (errmsg("changing the foreign-data wrapper validator can cause " "the options for dependent objects to become invalid"))); @@ -492,6 +569,34 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt) fdwvalidator = DatumGetObjectId(datum); } + if (defhandler) + { + fdwhandler = lookup_fdw_handler_func(defhandler); + 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. + */ + if (defhandler->arg) + ereport(WARNING, + (errmsg("changing the foreign-data wrapper handler would change " + "the behavior of accessing foreign tables"))); + } + else + { + /* + * Validator is not changed, but we need it for validating options. + */ + datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, + tp, + Anum_pg_foreign_data_wrapper_fdwhandler, + &isnull); + Assert(!isnull); + fdwhandler = DatumGetObjectId(datum); + } + /* * Options specified, validate and update. */ diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c index 6cfddf317a..a708efa667 100644 --- a/src/backend/foreign/foreign.c +++ b/src/backend/foreign/foreign.c @@ -60,6 +60,7 @@ GetForeignDataWrapper(Oid fdwid) fdw->owner = fdwform->fdwowner; fdw->fdwname = pstrdup(NameStr(fdwform->fdwname)); fdw->fdwvalidator = fdwform->fdwvalidator; + fdw->fdwhandler = fdwform->fdwhandler; /* Extract the options */ datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 662916d210..33782a5b9e 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3202,7 +3202,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; @@ -3214,8 +3214,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 b7dc450447..26df9acd6b 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1629,7 +1629,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; @@ -1639,8 +1639,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 21782824ca..9e0c148ad4 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -306,6 +306,9 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_ create_generic_options alter_generic_options relation_expr_list dostmt_opt_list +%type opt_func_options func_options +%type fdw_option + %type OptTempTableName %type into_clause create_as_target @@ -3196,16 +3199,33 @@ DropTableSpaceStmt: DROP TABLESPACE name * *****************************************************************************/ -CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name opt_validator create_generic_options +CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name opt_func_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: + VALIDATOR handler_name { $$ = makeDefElem("validator", (Node *)$2); } + | NO VALIDATOR { $$ = makeDefElem("validator", NULL); } + | HANDLER handler_name { $$ = makeDefElem("handler", (Node *)$2); } + | NO HANDLER { $$ = makeDefElem("handler", NULL); } + ; + +func_options: + fdw_option { $$ = list_make1($1); } + | func_options fdw_option { $$ = lappend($1, $2); } + ; + +opt_func_options: + func_options { $$ = $1; } + | /*EMPTY*/ { $$ = NIL; } + ; + /***************************************************************************** * * QUERY : @@ -3238,28 +3258,20 @@ DropFdwStmt: DROP FOREIGN DATA_P WRAPPER name opt_drop_behavior * ****************************************************************************/ -AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name validator_clause alter_generic_options +AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name opt_func_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 func_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 2be0696f60..779844d161 100644 --- a/src/backend/utils/adt/pseudotypes.c +++ b/src/backend/utils/adt/pseudotypes.c @@ -453,3 +453,29 @@ pg_node_tree_send(PG_FUNCTION_ARGS) { return textsend(fcinfo); } + +/* + * 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 */ +} diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index d3eb766288..8baf79f1c6 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -5985,6 +5985,7 @@ getForeignDataWrappers(int *numForeignDataWrappers) int i_fdwname; int i_rolname; int i_fdwvalidator; + int i_fdwhandler; int i_fdwacl; int i_fdwoptions; @@ -5998,13 +5999,27 @@ 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, fdwvalidator::pg_catalog.regproc, " + "fdwhandler::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, 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); @@ -6019,6 +6034,8 @@ getForeignDataWrappers(int *numForeignDataWrappers) i_fdwname = PQfnumber(res, "fdwname"); i_rolname = PQfnumber(res, "rolname"); i_fdwvalidator = PQfnumber(res, "fdwvalidator"); + if (g_fout->remoteVersion >= 90100) + i_fdwhandler = PQfnumber(res, "fdwhandler"); i_fdwacl = PQfnumber(res, "fdwacl"); i_fdwoptions = PQfnumber(res, "fdwoptions"); @@ -6032,6 +6049,10 @@ getForeignDataWrappers(int *numForeignDataWrappers) fdwinfo[i].dobj.namespace = NULL; fdwinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname)); fdwinfo[i].fdwvalidator = strdup(PQgetvalue(res, i, i_fdwvalidator)); + if (g_fout->remoteVersion >= 90100) + fdwinfo[i].fdwhandler = strdup(PQgetvalue(res, i, i_fdwhandler)); + else + fdwinfo[i].fdwhandler = NULL; fdwinfo[i].fdwoptions = strdup(PQgetvalue(res, i, i_fdwoptions)); fdwinfo[i].fdwacl = strdup(PQgetvalue(res, i, i_fdwacl)); @@ -10337,6 +10358,11 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo) appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator); + if (g_fout->remoteVersion >= 90100 && fdwinfo->fdwhandler && + strcmp(fdwinfo->fdwhandler, "-") != 0) + appendPQExpBuffer(q, " HANDLER %s", + fdwinfo->fdwhandler); + if (fdwinfo->fdwoptions && strlen(fdwinfo->fdwoptions) > 0) appendPQExpBuffer(q, " OPTIONS (%s)", fdwinfo->fdwoptions); diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 43fd1ade27..c630a1d06f 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -421,6 +421,7 @@ typedef struct _fdwInfo DumpableObject dobj; char *rolname; char *fdwvalidator; + char *fdwhandler; char *fdwoptions; char *fdwacl; } FdwInfo; diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index ada04de451..57718eb9b7 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -3480,9 +3480,11 @@ listForeignDataWrappers(const char *pattern, bool verbose) printfPQExpBuffer(&buf, "SELECT fdwname AS \"%s\",\n" " pg_catalog.pg_get_userbyid(fdwowner) AS \"%s\",\n" + " fdwhandler::pg_catalog.regproc AS \"%s\",\n" " fdwvalidator::pg_catalog.regproc AS \"%s\"", gettext_noop("Name"), gettext_noop("Owner"), + gettext_noop("Handler"), gettext_noop("Validator")); if (verbose) diff --git a/src/include/catalog/pg_foreign_data_wrapper.h b/src/include/catalog/pg_foreign_data_wrapper.h index a83556df15..971326cdae 100644 --- a/src/include/catalog/pg_foreign_data_wrapper.h +++ b/src/include/catalog/pg_foreign_data_wrapper.h @@ -33,6 +33,7 @@ CATALOG(pg_foreign_data_wrapper,2328) NameData fdwname; /* foreign-data wrapper name */ Oid fdwowner; /* FDW owner */ Oid fdwvalidator; /* optional validation function */ + Oid fdwhandler; /* foreign-data routines function */ /* 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 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 f8b5d4da3d..05fc57c633 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -3899,6 +3899,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 620f7b4612..ee40705160 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -623,6 +623,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 _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 _null_ _null_ )); +#define FDW_HANDLEROID 3115 /* diff --git a/src/include/foreign/foreign.h b/src/include/foreign/foreign.h index f3037a442a..7d80a6a289 100644 --- a/src/include/foreign/foreign.h +++ b/src/include/foreign/foreign.h @@ -38,6 +38,7 @@ typedef struct ForeignDataWrapper Oid owner; /* FDW owner user Oid */ char *fdwname; /* Name of the FDW */ Oid fdwvalidator; + Oid fdwhandler; List *options; /* fdwoptions as DefElem list */ } ForeignDataWrapper; diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index d7d1b0a6fd..583b54cd2f 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1531,7 +1531,7 @@ typedef struct CreateFdwStmt { NodeTag type; char *fdwname; /* foreign-data wrapper name */ - List *validator; /* optional validator function (qual. name) */ + List *func_options; /* VALIDATOR/HANDLER conbination */ List *options; /* generic options to FDW */ } CreateFdwStmt; @@ -1539,8 +1539,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; /* VALIDATOR/HANDLER conbination */ List *options; /* generic options to FDW */ } AlterFdwStmt; diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 4cb6c5c17a..eaaf7d0651 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -518,6 +518,8 @@ extern Datum pg_node_tree_in(PG_FUNCTION_ARGS); extern Datum pg_node_tree_out(PG_FUNCTION_ARGS); extern Datum pg_node_tree_recv(PG_FUNCTION_ARGS); extern Datum pg_node_tree_send(PG_FUNCTION_ARGS); +extern Datum fdw_handler_in(PG_FUNCTION_ARGS); +extern Datum fdw_handler_out(PG_FUNCTION_ARGS); /* regexp.c */ extern Datum nameregexeq(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out index d6c650be14..fe3ce42867 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, fdwvalidator::regproc, fdwhandler::regproc, fdwoptions FROM pg_foreign_data_wrapper ORDER BY 1, 2, 3; + fdwname | fdwvalidator | fdwhandler | 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+ @@ -1105,9 +1105,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, fdwvalidator, fdwhandler, fdwoptions FROM pg_foreign_data_wrapper; + fdwname | fdwvalidator | fdwhandler | 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 86b698a1b6..5f54272234 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, fdwvalidator::regproc, fdwhandler::regproc, fdwoptions FROM pg_foreign_data_wrapper ORDER BY 1, 2, 3; SELECT srvname, srvoptions FROM pg_foreign_server; SELECT * FROM pg_user_mapping; @@ -453,6 +453,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, fdwvalidator, fdwhandler, fdwoptions FROM pg_foreign_data_wrapper; SELECT srvname, srvoptions FROM pg_foreign_server; SELECT * FROM pg_user_mapping; -- 2.30.2