summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2009-02-24 10:06:36 +0000
committerPeter Eisentraut <peter_e@gmx.net>2009-02-24 10:06:36 +0000
commit7babccb91504fd4a958ff778547af1a8cbc1f8f2 (patch)
treece41105b1add6e2c61ae7acc8e3ee6c2175a41af /src/backend
parentf73bed308a8ccaea9082634f417966f7beb71614 (diff)
downloadpostgresql-7babccb91504fd4a958ff778547af1a8cbc1f8f2.tar.gz
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')
-rw-r--r--src/backend/catalog/information_schema.sql5
-rw-r--r--src/backend/commands/foreigncmds.c103
-rw-r--r--src/backend/foreign/Makefile10
-rw-r--r--src/backend/foreign/dummy/Makefile27
-rw-r--r--src/backend/foreign/dummy/dummy_fdw.c24
-rw-r--r--src/backend/foreign/foreign.c165
-rw-r--r--src/backend/foreign/postgresql/Makefile27
-rw-r--r--src/backend/foreign/postgresql/postgresql_fdw.c123
-rw-r--r--src/backend/nodes/copyfuncs.c7
-rw-r--r--src/backend/nodes/equalfuncs.c7
-rw-r--r--src/backend/parser/gram.y40
-rw-r--r--src/backend/parser/keywords.c3
12 files changed, 200 insertions, 341 deletions
diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
index 4206e9eaf5..80132e27ea 100644
--- a/src/backend/catalog/information_schema.sql
+++ b/src/backend/catalog/information_schema.sql
@@ -4,7 +4,7 @@
*
* Copyright (c) 2003-2009, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.52 2009/02/14 20:48:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.53 2009/02/24 10:06:32 petere Exp $
*/
/*
@@ -2428,7 +2428,6 @@ CREATE VIEW _pg_foreign_data_wrappers AS
CAST(current_database() AS sql_identifier) AS foreign_data_wrapper_catalog,
CAST(fdwname AS sql_identifier) AS foreign_data_wrapper_name,
CAST(u.rolname AS sql_identifier) AS authorization_identifier,
- CAST(fdwlibrary AS character_data) AS library_name,
CAST('c' AS character_data) AS foreign_data_wrapper_language
FROM pg_foreign_data_wrapper w, pg_authid u
WHERE u.oid = w.fdwowner
@@ -2458,7 +2457,7 @@ CREATE VIEW foreign_data_wrappers AS
SELECT foreign_data_wrapper_catalog,
foreign_data_wrapper_name,
authorization_identifier,
- library_name,
+ CAST(NULL AS character_data) AS library_name,
foreign_data_wrapper_language
FROM _pg_foreign_data_wrappers w;
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 0967001aa3..24052556a4 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/foreigncmds.c,v 1.5 2009/01/20 09:10:20 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/foreigncmds.c,v 1.6 2009/02/24 10:06:32 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,11 +20,13 @@
#include "catalog/indexing.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
+#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "catalog/pg_user_mapping.h"
#include "commands/defrem.h"
#include "foreign/foreign.h"
#include "miscadmin.h"
+#include "parser/parse_func.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
@@ -90,10 +92,11 @@ transformGenericOptions(Datum oldOptions,
List *optionDefList,
GenericOptionFlags flags,
ForeignDataWrapper *fdw,
- OptionListValidatorFunc validateOptionList)
+ Oid fdwvalidator)
{
List *resultOptions = untransformRelOptions(oldOptions);
ListCell *optcell;
+ Datum result;
foreach(optcell, optionDefList)
{
@@ -157,10 +160,12 @@ transformGenericOptions(Datum oldOptions,
}
}
- if (validateOptionList)
- validateOptionList(fdw, flags, resultOptions);
+ result = optionListToArray(resultOptions);
- return optionListToArray(resultOptions);
+ if (fdwvalidator)
+ OidFunctionCall2(fdwvalidator, result, 0);
+
+ return result;
}
@@ -310,6 +315,21 @@ 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)
+{
+ Oid funcargtypes[2];
+
+ funcargtypes[0] = TEXTARRAYOID;
+ funcargtypes[1] = OIDOID;
+ return LookupFuncName(validator, 2, funcargtypes, false);
+ /* return value is ignored, so we don't check the type */
+}
+
+
+/*
* Create a foreign-data wrapper
*/
void
@@ -320,9 +340,9 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
bool nulls[Natts_pg_foreign_data_wrapper];
HeapTuple tuple;
Oid fdwId;
+ Oid fdwvalidator;
Datum fdwoptions;
Oid ownerId;
- ForeignDataWrapperLibrary *fdwlib;
/* Must be super user */
if (!superuser())
@@ -355,18 +375,19 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
values[Anum_pg_foreign_data_wrapper_fdwname - 1] =
DirectFunctionCall1(namein, CStringGetDatum(stmt->fdwname));
values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId);
- values[Anum_pg_foreign_data_wrapper_fdwlibrary - 1] = CStringGetTextDatum(stmt->library);
- nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
- /*
- * See if the FDW library loads at all. We also might want to use it
- * later for validating the options.
- */
- fdwlib = GetForeignDataWrapperLibrary(stmt->library);
+ if (stmt->validator)
+ fdwvalidator = lookup_fdw_validator_func(stmt->validator);
+ else
+ fdwvalidator = InvalidOid;
+
+ values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = fdwvalidator;
+
+ nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
fdwoptions = transformGenericOptions(PointerGetDatum(NULL), stmt->options,
FdwOpt, NULL,
- fdwlib->validateOptionList);
+ fdwvalidator);
if (PointerIsValid(DatumGetPointer(fdwoptions)))
values[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = fdwoptions;
@@ -380,6 +401,21 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
heap_freetuple(tuple);
+ if (fdwvalidator)
+ {
+ ObjectAddress myself;
+ ObjectAddress referenced;
+
+ myself.classId = ForeignDataWrapperRelationId;
+ myself.objectId = fdwId;
+ myself.objectSubId = 0;
+
+ referenced.classId = ProcedureRelationId;
+ referenced.objectId = fdwvalidator;
+ referenced.objectSubId = 0;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+ }
+
recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId);
heap_close(rel, NoLock);
@@ -400,7 +436,7 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
Oid fdwId;
bool isnull;
Datum datum;
- ForeignDataWrapperLibrary *fdwlib;
+ Oid fdwvalidator;
/* Must be super user */
if (!superuser())
@@ -425,36 +461,33 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
memset(repl_null, false, sizeof(repl_null));
memset(repl_repl, false, sizeof(repl_repl));
- if (stmt->library)
+ if (stmt->change_validator)
{
- /*
- * New library specified -- load to see if valid.
- */
- fdwlib = GetForeignDataWrapperLibrary(stmt->library);
-
- repl_val[Anum_pg_foreign_data_wrapper_fdwlibrary - 1] = CStringGetTextDatum(stmt->library);
- repl_repl[Anum_pg_foreign_data_wrapper_fdwlibrary - 1] = true;
+ 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;
/*
* It could be that the options for the FDW, SERVER and USER MAPPING
- * are no longer valid with the new library. Warn about this.
+ * are no longer valid with the new validator. Warn about this.
*/
- ereport(WARNING,
- (errmsg("changing the foreign-data wrapper library can cause "
- "the options for dependent objects to become invalid")));
+ if (stmt->validator)
+ ereport(WARNING,
+ (errmsg("changing the foreign-data wrapper validator can cause "
+ "the options for dependent objects to become invalid")));
}
else
{
/*
- * No LIBRARY clause specified, but we need to load it for validating
+ * Validator is not changed, but we need it for validating
* options.
*/
datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
tp,
- Anum_pg_foreign_data_wrapper_fdwlibrary,
+ Anum_pg_foreign_data_wrapper_fdwvalidator,
&isnull);
Assert(!isnull);
- fdwlib = GetForeignDataWrapperLibrary(TextDatumGetCString(datum));
+ fdwvalidator = DatumGetObjectId(datum);
}
/*
@@ -472,7 +505,7 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
/* Transform the options */
datum = transformGenericOptions(datum, stmt->options, FdwOpt,
- NULL, fdwlib->validateOptionList);
+ NULL, fdwvalidator);
if (PointerIsValid(DatumGetPointer(datum)))
repl_val[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = datum;
@@ -640,7 +673,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt)
/* Add server options */
srvoptions = transformGenericOptions(PointerGetDatum(NULL), stmt->options,
ServerOpt, fdw,
- fdw->lib->validateOptionList);
+ fdw->fdwvalidator);
if (PointerIsValid(DatumGetPointer(srvoptions)))
values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions;
@@ -738,7 +771,7 @@ AlterForeignServer(AlterForeignServerStmt *stmt)
/* Prepare the options array */
datum = transformGenericOptions(datum, stmt->options, ServerOpt,
- fdw, fdw->lib->validateOptionList);
+ fdw, fdw->fdwvalidator);
if (PointerIsValid(DatumGetPointer(datum)))
repl_val[Anum_pg_foreign_server_srvoptions - 1] = datum;
@@ -910,7 +943,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
/* Add user options */
useoptions = transformGenericOptions(PointerGetDatum(NULL), stmt->options,
UserMappingOpt,
- fdw, fdw->lib->validateOptionList);
+ fdw, fdw->fdwvalidator);
if (PointerIsValid(DatumGetPointer(useoptions)))
values[Anum_pg_user_mapping_umoptions - 1] = useoptions;
@@ -1005,7 +1038,7 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
/* Prepare the options array */
datum = transformGenericOptions(datum, stmt->options, UserMappingOpt,
- fdw, fdw->lib->validateOptionList);
+ fdw, fdw->fdwvalidator);
if (PointerIsValid(DatumGetPointer(datum)))
repl_val[Anum_pg_user_mapping_umoptions - 1] = datum;
diff --git a/src/backend/foreign/Makefile b/src/backend/foreign/Makefile
index b3cc209c16..dff0c77540 100644
--- a/src/backend/foreign/Makefile
+++ b/src/backend/foreign/Makefile
@@ -4,7 +4,7 @@
# Makefile for foreign
#
# IDENTIFICATION
-# $PostgreSQL: pgsql/src/backend/foreign/Makefile,v 1.1 2008/12/19 16:25:17 petere Exp $
+# $PostgreSQL: pgsql/src/backend/foreign/Makefile,v 1.2 2009/02/24 10:06:32 petere Exp $
#
#-------------------------------------------------------------------------
@@ -15,11 +15,3 @@ include $(top_builddir)/src/Makefile.global
OBJS= foreign.o
include $(top_srcdir)/src/backend/common.mk
-
-FDW = dummy postgresql
-
-$(addsuffix -fdw,all install installdirs uninstall distprep):
- for dir in $(FDW); do $(MAKE) -C $$dir `echo $@ | sed 's/-fdw$$//'` || exit; done
-
-clean distclean maintainer-clean:
- for dir in $(FDW); do $(MAKE) -C $$dir $@ || exit; done
diff --git a/src/backend/foreign/dummy/Makefile b/src/backend/foreign/dummy/Makefile
deleted file mode 100644
index 8a05ada019..0000000000
--- a/src/backend/foreign/dummy/Makefile
+++ /dev/null
@@ -1,27 +0,0 @@
-#-------------------------------------------------------------------------
-#
-# Makefile--
-# Makefile for dummy foreign-data wrapper
-#
-# IDENTIFICATION
-# $PostgreSQL: pgsql/src/backend/foreign/dummy/Makefile,v 1.1 2008/12/19 16:25:17 petere Exp $
-#
-#-------------------------------------------------------------------------
-
-subdir = src/backend/foreign/dummy
-top_builddir = ../../../..
-include $(top_builddir)/src/Makefile.global
-
-NAME = dummy_fdw
-OBJS = dummy_fdw.o
-
-include $(top_srcdir)/src/Makefile.shlib
-
-all: all-shared-lib
-
-install: all install-lib
-
-installdirs: installdirs-lib
-
-clean distclean maintainer-clean: clean-lib
- rm -f $(OBJS)
diff --git a/src/backend/foreign/dummy/dummy_fdw.c b/src/backend/foreign/dummy/dummy_fdw.c
deleted file mode 100644
index a89d68e0ae..0000000000
--- a/src/backend/foreign/dummy/dummy_fdw.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * dummy_fdw.c
- * "dummy" foreign-data wrapper
- *
- * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/foreign/dummy/dummy_fdw.c,v 1.2 2009/01/01 17:23:42 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "fmgr.h"
-#include "foreign/foreign.h"
-
-PG_MODULE_MAGIC;
-
-/*
- * This looks like a complete waste right now, but it is useful for
- * testing, and will become more interesting as more parts of the
- * interface are implemented.
- */
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c
index b5b502cc03..3ec4250677 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);
+}
diff --git a/src/backend/foreign/postgresql/Makefile b/src/backend/foreign/postgresql/Makefile
deleted file mode 100644
index 40ed90f8d7..0000000000
--- a/src/backend/foreign/postgresql/Makefile
+++ /dev/null
@@ -1,27 +0,0 @@
-#-------------------------------------------------------------------------
-#
-# Makefile--
-# Makefile for postgresql foreign-data wrapper
-#
-# IDENTIFICATION
-# $PostgreSQL: pgsql/src/backend/foreign/postgresql/Makefile,v 1.1 2008/12/19 16:25:17 petere Exp $
-#
-#-------------------------------------------------------------------------
-
-subdir = src/backend/foreign/postgresql
-top_builddir = ../../../..
-include $(top_builddir)/src/Makefile.global
-
-NAME = postgresql_fdw
-OBJS = postgresql_fdw.o
-
-include $(top_srcdir)/src/Makefile.shlib
-
-all: all-shared-lib
-
-install: all install-lib
-
-installdirs: installdirs-lib
-
-clean distclean maintainer-clean: clean-lib
- rm -f $(OBJS)
diff --git a/src/backend/foreign/postgresql/postgresql_fdw.c b/src/backend/foreign/postgresql/postgresql_fdw.c
deleted file mode 100644
index 3fb4d2f863..0000000000
--- a/src/backend/foreign/postgresql/postgresql_fdw.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * postgresql_fdw.c
- * foreign-data wrapper for postgresql (libpq) connections.
- *
- * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/foreign/postgresql/postgresql_fdw.c,v 1.2 2009/01/01 17:23:42 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "fmgr.h"
-#include "lib/stringinfo.h"
-#include "nodes/value.h"
-#include "nodes/parsenodes.h"
-#include "nodes/makefuncs.h"
-#include "foreign/foreign.h"
-
-PG_MODULE_MAGIC;
-
-
-/*
- * Describes the valid options for postgresql FDW, server and user mapping.
- */
-typedef struct ConnectionOptions {
- const char *optname; /* Option name */
- GenericOptionFlags optflags; /* Option usage bitmap */
-} ConnectionOptions;
-
-/*
- * Copied from fe-connect.c PQconninfoOptions.
- *
- * The list is small - don't bother with bsearch if it stays so.
- */
-static ConnectionOptions libpq_conninfo_options[] = {
- { "authtype", ServerOpt },
- { "service", ServerOpt },
- { "user", UserMappingOpt },
- { "password", UserMappingOpt },
- { "connect_timeout", ServerOpt },
- { "dbname", ServerOpt },
- { "host", ServerOpt },
- { "hostaddr", ServerOpt },
- { "port", ServerOpt },
- { "tty", ServerOpt },
- { "options", ServerOpt },
- { "requiressl", ServerOpt },
- { "sslmode", ServerOpt },
- { "gsslib", ServerOpt },
- { NULL, InvalidOpt }
-};
-
-void _PG_fini(void);
-
-
-/*
- * Check if the provided option is one of libpq conninfo options.
- * We look at only options with matching flags.
- */
-static bool
-is_conninfo_option(const char *option, GenericOptionFlags flags)
-{
- ConnectionOptions *opt;
-
- for (opt = libpq_conninfo_options; opt->optname != NULL; opt++)
- if (flags & opt->optflags && 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.
- */
-void
-_pg_validateOptionList(ForeignDataWrapper *fdw, GenericOptionFlags flags,
- List *options)
-{
- ListCell *cell;
-
- foreach (cell, options)
- {
- DefElem *def = lfirst(cell);
-
- if (!is_conninfo_option(def->defname, flags))
- {
- ConnectionOptions *opt;
- StringInfoData buf;
- const char *objtype;
-
- /*
- * 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 != NULL; opt++)
- if (flags & opt->optflags)
- appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "",
- opt->optname);
-
- if (flags & ServerOpt)
- objtype = "server";
- else if (flags & UserMappingOpt)
- objtype = "user mapping";
- else if (flags & FdwOpt)
- objtype = "foreign-data wrapper";
- else
- objtype = "???";
-
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("invalid option \"%s\" to %s", def->defname, objtype),
- errhint("valid %s options are: %s", objtype, buf.data)));
- }
- }
-}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index bc4232bdc8..2175e0c0fc 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.423 2009/02/06 23:43:23 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.424 2009/02/24 10:06:32 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2994,7 +2994,7 @@ _copyCreateFdwStmt(CreateFdwStmt *from)
CreateFdwStmt *newnode = makeNode(CreateFdwStmt);
COPY_STRING_FIELD(fdwname);
- COPY_STRING_FIELD(library);
+ COPY_NODE_FIELD(validator);
COPY_NODE_FIELD(options);
return newnode;
@@ -3006,7 +3006,8 @@ _copyAlterFdwStmt(AlterFdwStmt *from)
AlterFdwStmt *newnode = makeNode(AlterFdwStmt);
COPY_STRING_FIELD(fdwname);
- COPY_STRING_FIELD(library);
+ COPY_NODE_FIELD(validator);
+ COPY_SCALAR_FIELD(change_validator);
COPY_NODE_FIELD(options);
return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 2b8b542e74..4d905dc945 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -22,7 +22,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.347 2009/02/02 19:31:39 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.348 2009/02/24 10:06:32 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1548,7 +1548,7 @@ static bool
_equalCreateFdwStmt(CreateFdwStmt *a, CreateFdwStmt *b)
{
COMPARE_STRING_FIELD(fdwname);
- COMPARE_STRING_FIELD(library);
+ COMPARE_NODE_FIELD(validator);
COMPARE_NODE_FIELD(options);
return true;
@@ -1558,7 +1558,8 @@ static bool
_equalAlterFdwStmt(AlterFdwStmt *a, AlterFdwStmt *b)
{
COMPARE_STRING_FIELD(fdwname);
- COMPARE_STRING_FIELD(library);
+ COMPARE_NODE_FIELD(validator);
+ COMPARE_SCALAR_FIELD(change_validator);
COMPARE_NODE_FIELD(options);
return true;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 6688324e05..3dadbcffde 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.658 2009/02/11 21:11:16 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.659 2009/02/24 10:06:33 petere Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -254,7 +254,7 @@ static TypeName *TableFuncTypeName(List *columns);
index_name name file_name cluster_index_specification
%type <list> func_name handler_name qual_Op qual_all_Op subquery_Op
- opt_class opt_validator
+ opt_class opt_validator validator_clause
%type <range> qualified_name OptConstrFromTable
@@ -469,7 +469,7 @@ static TypeName *TableFuncTypeName(List *columns);
KEY
LANCOMPILER LANGUAGE LARGE_P LAST_P LEADING LEAST LEFT LEVEL
- LIBRARY LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
+ LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
LOCK_P LOGIN_P
MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
@@ -2724,8 +2724,13 @@ handler_name:
| name attrs { $$ = lcons(makeString($1), $2); }
;
-opt_validator:
+validator_clause:
VALIDATOR handler_name { $$ = $2; }
+ | NO VALIDATOR { $$ = NIL; }
+ ;
+
+opt_validator:
+ validator_clause { $$ = $1; }
| /*EMPTY*/ { $$ = NIL; }
;
@@ -2808,23 +2813,17 @@ DropTableSpaceStmt: DROP TABLESPACE name
/*****************************************************************************
*
* QUERY:
- * CREATE FOREIGN DATA WRAPPER name LIBRARY 'library_name' LANGUAGE C
+ * CREATE FOREIGN DATA WRAPPER name [ VALIDATOR name ]
*
*****************************************************************************/
-CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name LIBRARY Sconst LANGUAGE ColId create_generic_options
+CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name opt_validator create_generic_options
{
CreateFdwStmt *n = makeNode(CreateFdwStmt);
n->fdwname = $5;
- n->library = $7;
- n->options = $10;
+ n->validator = $6;
+ n->options = $7;
$$ = (Node *) n;
-
- if (pg_strcasecmp($9, "C") != 0)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("language for foreign-data wrapper must be C"),
- scanner_errposition(@9)));
}
;
@@ -2860,19 +2859,21 @@ DropFdwStmt: DROP FOREIGN DATA_P WRAPPER name opt_drop_behavior
*
****************************************************************************/
-AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name LIBRARY Sconst alter_generic_options
+AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name validator_clause alter_generic_options
{
AlterFdwStmt *n = makeNode(AlterFdwStmt);
n->fdwname = $5;
- n->library = $7;
- n->options = $8;
+ n->validator = $6;
+ n->change_validator = true;
+ n->options = $7;
$$ = (Node *) n;
}
- | ALTER FOREIGN DATA_P WRAPPER name LIBRARY Sconst
+ | ALTER FOREIGN DATA_P WRAPPER name validator_clause
{
AlterFdwStmt *n = makeNode(AlterFdwStmt);
n->fdwname = $5;
- n->library = $7;
+ n->validator = $6;
+ n->change_validator = true;
$$ = (Node *) n;
}
| ALTER FOREIGN DATA_P WRAPPER name alter_generic_options
@@ -10231,7 +10232,6 @@ unreserved_keyword:
| INVOKER
| ISOLATION
| KEY
- | LIBRARY
| LANCOMPILER
| LANGUAGE
| LARGE_P
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index 3f3388e7fe..48218df9c4 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.209 2009/01/01 17:23:45 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.210 2009/02/24 10:06:33 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -230,7 +230,6 @@ const ScanKeyword ScanKeywords[] = {
{"least", LEAST, COL_NAME_KEYWORD},
{"left", LEFT, TYPE_FUNC_NAME_KEYWORD},
{"level", LEVEL, UNRESERVED_KEYWORD},
- {"library", LIBRARY, UNRESERVED_KEYWORD},
{"like", LIKE, TYPE_FUNC_NAME_KEYWORD},
{"limit", LIMIT, RESERVED_KEYWORD},
{"listen", LISTEN, UNRESERVED_KEYWORD},