diff options
author | Peter Eisentraut <peter_e@gmx.net> | 2009-02-24 10:06:36 +0000 |
---|---|---|
committer | Peter Eisentraut <peter_e@gmx.net> | 2009-02-24 10:06:36 +0000 |
commit | 7babccb91504fd4a958ff778547af1a8cbc1f8f2 (patch) | |
tree | ce41105b1add6e2c61ae7acc8e3ee6c2175a41af /src/backend/foreign/foreign.c | |
parent | f73bed308a8ccaea9082634f417966f7beb71614 (diff) | |
download | postgresql-7babccb91504fd4a958ff778547af1a8cbc1f8f2.tar.gz postgresql-7babccb91504fd4a958ff778547af1a8cbc1f8f2.zip |
Add the possibility to specify an explicit validator function for foreign-data
wrappers (similar to procedural languages). This way we don't need to retain
the nearly empty libraries, and we are more free in how to implement the
wrapper API in the future.
Diffstat (limited to 'src/backend/foreign/foreign.c')
-rw-r--r-- | src/backend/foreign/foreign.c | 165 |
1 files changed, 100 insertions, 65 deletions
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c index b5b502cc032..3ec42506777 100644 --- a/src/backend/foreign/foreign.c +++ b/src/backend/foreign/foreign.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/foreign/foreign.c,v 1.2 2009/01/01 17:23:42 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/foreign/foreign.c,v 1.3 2009/02/24 10:06:32 petere Exp $ * *------------------------------------------------------------------------- */ @@ -31,66 +31,12 @@ extern Datum pg_options_to_table(PG_FUNCTION_ARGS); +extern Datum postgresql_fdw_validator(PG_FUNCTION_ARGS); -/* list of currently loaded foreign-data wrapper interfaces */ -static List *loaded_fdw_interfaces = NIL; - - -/* - * GetForeignDataWrapperLibrary - return the named FDW library. If it - * is already loaded, use that. Otherwise allocate, initialize, and - * store in cache. - */ -ForeignDataWrapperLibrary * -GetForeignDataWrapperLibrary(const char *libname) -{ - MemoryContext oldcontext; - void *libhandle = NULL; - ForeignDataWrapperLibrary *fdwl = NULL; - ListCell *cell; - - /* See if we have the FDW library is already loaded */ - foreach (cell, loaded_fdw_interfaces) - { - fdwl = lfirst(cell); - if (strcmp(fdwl->libname, libname) == 0) - return fdwl; - } - - /* - * We don't have it yet, so load and add. Attempt a load_file() - * first to filter out any missing or unloadable libraries. - */ - load_file(libname, false); - - oldcontext = MemoryContextSwitchTo(TopMemoryContext); - - fdwl = palloc(sizeof(*fdwl)); - fdwl->libname = pstrdup(libname); - loaded_fdw_interfaces = lappend(loaded_fdw_interfaces, fdwl); - - MemoryContextSwitchTo(oldcontext); - - /* - * Now look up the foreign data wrapper functions. - */ -#define LOOKUP_FUNCTION(name) \ - (void *)(libhandle ? \ - lookup_external_function(libhandle, name) \ - : load_external_function(fdwl->libname, name, false, &libhandle)) - - fdwl->validateOptionList = LOOKUP_FUNCTION("_pg_validateOptionList"); - - return fdwl; -} - /* * GetForeignDataWrapper - look up the foreign-data wrapper by OID. - * - * Here we also deal with loading the FDW library and looking up the - * actual functions. */ ForeignDataWrapper * GetForeignDataWrapper(Oid fdwid) @@ -114,15 +60,7 @@ GetForeignDataWrapper(Oid fdwid) fdw->fdwid = fdwid; fdw->owner = fdwform->fdwowner; fdw->fdwname = pstrdup(NameStr(fdwform->fdwname)); - - /* Extract library name */ - datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, - tp, - Anum_pg_foreign_data_wrapper_fdwlibrary, - &isnull); - fdw->fdwlibrary = pstrdup(TextDatumGetCString(datum)); - - fdw->lib = GetForeignDataWrapperLibrary(fdw->fdwlibrary); + fdw->fdwvalidator = fdwform->fdwvalidator; /* Extract the options */ datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, @@ -387,3 +325,100 @@ pg_options_to_table(PG_FUNCTION_ARGS) return (Datum) 0; } + + +/* + * Describes the valid options for postgresql FDW, server, and user mapping. + */ +struct ConnectionOption { + const char *optname; + Oid optcontext; /* Oid of catalog in which option may appear */ +}; + +/* + * Copied from fe-connect.c PQconninfoOptions. + * + * The list is small - don't bother with bsearch if it stays so. + */ +static struct ConnectionOption libpq_conninfo_options[] = { + { "authtype", ForeignServerRelationId }, + { "service", ForeignServerRelationId }, + { "user", UserMappingRelationId }, + { "password", UserMappingRelationId }, + { "connect_timeout", ForeignServerRelationId }, + { "dbname", ForeignServerRelationId }, + { "host", ForeignServerRelationId }, + { "hostaddr", ForeignServerRelationId }, + { "port", ForeignServerRelationId }, + { "tty", ForeignServerRelationId }, + { "options", ForeignServerRelationId }, + { "requiressl", ForeignServerRelationId }, + { "sslmode", ForeignServerRelationId }, + { "gsslib", ForeignServerRelationId }, + { NULL, InvalidOid } +}; + + +/* + * Check if the provided option is one of libpq conninfo options. + * context is the Oid of the catalog the option came from, or 0 if we + * don't care. + */ +static bool +is_conninfo_option(const char *option, Oid context) +{ + struct ConnectionOption *opt; + + for (opt = libpq_conninfo_options; opt->optname; opt++) + if ((context == opt->optcontext || context == InvalidOid) && strcmp(opt->optname, option) == 0) + return true; + return false; +} + + +/* + * Validate the generic option given to SERVER or USER MAPPING. + * Raise an ERROR if the option or its value is considered + * invalid. + * + * Valid server options are all libpq conninfo options except + * user and password -- these may only appear in USER MAPPING options. + */ +Datum +postgresql_fdw_validator(PG_FUNCTION_ARGS) +{ + List* options_list = untransformRelOptions(PG_GETARG_DATUM(0)); + Oid catalog = PG_GETARG_OID(1); + + ListCell *cell; + + foreach (cell, options_list) + { + DefElem *def = lfirst(cell); + + if (!is_conninfo_option(def->defname, catalog)) + { + struct ConnectionOption *opt; + StringInfoData buf; + + /* + * Unknown option specified, complain about it. Provide a hint + * with list of valid options for the object. + */ + initStringInfo(&buf); + for (opt = libpq_conninfo_options; opt->optname; opt++) + if (catalog == InvalidOid || catalog == opt->optcontext) + appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "", + opt->optname); + + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("invalid option \"%s\"", def->defname), + errhint("Valid options in this context are: %s", buf.data))); + + PG_RETURN_BOOL(false); + } + } + + PG_RETURN_BOOL(true); +} |