aboutsummaryrefslogtreecommitdiff
path: root/src/backend/foreign/foreign.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/foreign/foreign.c')
-rw-r--r--src/backend/foreign/foreign.c389
1 files changed, 389 insertions, 0 deletions
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c
new file mode 100644
index 00000000000..2fdb84ac1b4
--- /dev/null
+++ b/src/backend/foreign/foreign.c
@@ -0,0 +1,389 @@
+/*-------------------------------------------------------------------------
+ *
+ * foreign.c
+ * support for foreign-data wrappers, servers and user mappings.
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/foreign/foreign.c,v 1.1 2008/12/19 16:25:17 petere Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/reloptions.h"
+#include "catalog/namespace.h"
+#include "catalog/pg_foreign_data_wrapper.h"
+#include "catalog/pg_foreign_server.h"
+#include "catalog/pg_type.h"
+#include "catalog/pg_user_mapping.h"
+#include "foreign/foreign.h"
+#include "funcapi.h"
+#include "miscadmin.h"
+#include "nodes/parsenodes.h"
+#include "utils/acl.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+#include "utils/memutils.h"
+#include "utils/syscache.h"
+
+
+extern Datum pg_options_to_table(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)
+{
+ Form_pg_foreign_data_wrapper fdwform;
+ ForeignDataWrapper *fdw;
+ Datum datum;
+ HeapTuple tp;
+ bool isnull;
+
+ tp = SearchSysCache(FOREIGNDATAWRAPPEROID,
+ ObjectIdGetDatum(fdwid),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwid);
+
+ fdwform = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp);
+
+ fdw = palloc(sizeof(ForeignDataWrapper));
+ 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);
+
+ /* Extract the options */
+ datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
+ tp,
+ Anum_pg_foreign_data_wrapper_fdwoptions,
+ &isnull);
+ fdw->options = untransformRelOptions(datum);
+
+ ReleaseSysCache(tp);
+
+ return fdw;
+}
+
+
+/*
+ * GetForeignDataWrapperOidByName - look up the foreign-data wrapper
+ * OID by name.
+ */
+Oid
+GetForeignDataWrapperOidByName(const char *fdwname, bool missing_ok)
+{
+ Oid fdwId;
+
+ fdwId = GetSysCacheOid(FOREIGNDATAWRAPPERNAME,
+ CStringGetDatum(fdwname),
+ 0, 0, 0);
+
+ if (!OidIsValid(fdwId) && !missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("foreign-data wrapper \"%s\" does not exist", fdwname)));
+
+ return fdwId;
+}
+
+
+/*
+ * GetForeignDataWrapperByName - look up the foreign-data wrapper
+ * definition by name.
+ */
+ForeignDataWrapper *
+GetForeignDataWrapperByName(const char *fdwname, bool missing_ok)
+{
+ Oid fdwId = GetForeignDataWrapperOidByName(fdwname, missing_ok);
+
+ if (!OidIsValid(fdwId) && missing_ok)
+ return NULL;
+
+ return GetForeignDataWrapper(fdwId);
+}
+
+
+/*
+ * GetForeignServer - look up the foreign server definition.
+ */
+ForeignServer *
+GetForeignServer(Oid serverid)
+{
+ Form_pg_foreign_server serverform;
+ ForeignServer *server;
+ HeapTuple tp;
+ Datum datum;
+ bool isnull;
+
+ tp = SearchSysCache(FOREIGNSERVEROID,
+ ObjectIdGetDatum(serverid),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for foreign server %u", serverid);
+
+ serverform = (Form_pg_foreign_server) GETSTRUCT(tp);
+
+ server = palloc(sizeof(ForeignServer));
+ server->serverid = serverid;
+ server->servername = pstrdup(NameStr(serverform->srvname));
+ server->owner = serverform->srvowner;
+ server->fdwid = serverform->srvfdw;
+
+ /* Extract server type */
+ datum = SysCacheGetAttr(FOREIGNSERVEROID,
+ tp,
+ Anum_pg_foreign_server_srvtype,
+ &isnull);
+ server->servertype = isnull ? NULL : pstrdup(TextDatumGetCString(datum));
+
+ /* Extract server version */
+ datum = SysCacheGetAttr(FOREIGNSERVEROID,
+ tp,
+ Anum_pg_foreign_server_srvversion,
+ &isnull);
+ server->serverversion = isnull ? NULL : pstrdup(TextDatumGetCString(datum));
+
+ /* Extract the srvoptions */
+ datum = SysCacheGetAttr(FOREIGNSERVEROID,
+ tp,
+ Anum_pg_foreign_server_srvoptions,
+ &isnull);
+
+ /* untransformRelOptions does exactly what we want - avoid duplication */
+ server->options = untransformRelOptions(datum);
+
+ ReleaseSysCache(tp);
+
+ return server;
+}
+
+
+/*
+ * GetForeignServerByName - look up the foreign server oid by name.
+ */
+Oid
+GetForeignServerOidByName(const char *srvname, bool missing_ok)
+{
+ Oid serverid;
+
+ serverid = GetSysCacheOid(FOREIGNSERVERNAME,
+ CStringGetDatum(srvname),
+ 0, 0, 0);
+
+ if (!OidIsValid(serverid) && !missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("server \"%s\" does not exist", srvname)));
+
+ return serverid;
+}
+
+
+/*
+ * GetForeignServerByName - look up the foreign server definition by name.
+ */
+ForeignServer *
+GetForeignServerByName(const char *srvname, bool missing_ok)
+{
+ Oid serverid = GetForeignServerOidByName(srvname, missing_ok);
+
+ if (!OidIsValid(serverid) && missing_ok)
+ return NULL;
+
+ return GetForeignServer(serverid);
+}
+
+
+/*
+ * GetUserMapping - look up the user mapping.
+ *
+ * If no mapping is found for the supplied user, we also look for
+ * PUBLIC mappings (userid == InvalidOid).
+ */
+UserMapping *
+GetUserMapping(Oid userid, Oid serverid)
+{
+ Form_pg_user_mapping umform;
+ Datum datum;
+ HeapTuple tp;
+ bool isnull;
+ UserMapping *um;
+
+ tp = SearchSysCache(USERMAPPINGUSERSERVER,
+ ObjectIdGetDatum(userid),
+ ObjectIdGetDatum(serverid),
+ 0, 0);
+
+ if (!HeapTupleIsValid(tp))
+ {
+ /* Not found for the specific user -- try PUBLIC */
+ tp = SearchSysCache(USERMAPPINGUSERSERVER,
+ ObjectIdGetDatum(InvalidOid),
+ ObjectIdGetDatum(serverid),
+ 0, 0);
+ }
+
+ if (!HeapTupleIsValid(tp))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("user mapping not found for \"%s\"",
+ MappingUserName(userid))));
+
+ umform = (Form_pg_user_mapping) GETSTRUCT(tp);
+
+ /* Extract the umoptions */
+ datum = SysCacheGetAttr(USERMAPPINGUSERSERVER,
+ tp,
+ Anum_pg_user_mapping_umoptions,
+ &isnull);
+
+ um = palloc(sizeof(UserMapping));
+ um->userid = userid;
+ um->serverid = serverid;
+ um->options = untransformRelOptions(datum);
+
+ ReleaseSysCache(tp);
+
+ return um;
+}
+
+
+/*
+ * deflist_to_tuplestore - Helper function to convert DefElem list to
+ * tuplestore usable in SRF.
+ */
+static void
+deflist_to_tuplestore(ReturnSetInfo *rsinfo, List *options)
+{
+ ListCell *cell;
+ TupleDesc tupdesc;
+ Tuplestorestate *tupstore;
+ Datum values[2];
+ bool nulls[2] = { 0 };
+ MemoryContext per_query_ctx;
+ MemoryContext oldcontext;
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not allowed in this context")));
+
+ per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
+ oldcontext = MemoryContextSwitchTo(per_query_ctx);
+
+ /*
+ * Now prepare the result set.
+ */
+ tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+ tupstore = tuplestore_begin_heap(true, false, work_mem);
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+
+ foreach (cell, options)
+ {
+ DefElem *def = lfirst(cell);
+
+ values[0] = CStringGetTextDatum(def->defname);
+ values[1] = CStringGetTextDatum(((Value *)def->arg)->val.str);
+ tuplestore_putvalues(tupstore, tupdesc, values, nulls);
+ }
+
+ /* clean up and return the tuplestore */
+ tuplestore_donestoring(tupstore);
+
+ MemoryContextSwitchTo(oldcontext);
+}
+
+
+/*
+ * Convert options array to name/value table. Useful for information
+ * schema and pg_dump.
+ */
+Datum
+pg_options_to_table(PG_FUNCTION_ARGS)
+{
+ Datum array = PG_GETARG_DATUM(0);
+
+ deflist_to_tuplestore((ReturnSetInfo *) fcinfo->resultinfo, untransformRelOptions(array));
+
+ return (Datum) 0;
+}