mirror of
https://github.com/postgres/postgres.git
synced 2025-07-31 22:04:40 +03:00
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.
This commit is contained in:
@ -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
|
||||
|
@ -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)
|
@ -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.
|
||||
*/
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user