1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-28 18:48:04 +03:00

Implement an API to let foreign-data wrappers actually be functional.

This commit provides the core code and documentation needed.  A contrib
module test case will follow shortly.

Shigeru Hanada, Jan Urbanski, Heikki Linnakangas
This commit is contained in:
Tom Lane
2011-02-20 00:17:18 -05:00
parent d5813488a4
commit bb74240794
39 changed files with 1202 additions and 62 deletions

View File

@@ -16,8 +16,10 @@
#include "catalog/namespace.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
#include "catalog/pg_foreign_table.h"
#include "catalog/pg_type.h"
#include "catalog/pg_user_mapping.h"
#include "foreign/fdwapi.h"
#include "foreign/foreign.h"
#include "funcapi.h"
#include "miscadmin.h"
@@ -54,19 +56,22 @@ GetForeignDataWrapper(Oid fdwid)
fdwform = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp);
fdw = palloc(sizeof(ForeignDataWrapper));
fdw = (ForeignDataWrapper *) palloc(sizeof(ForeignDataWrapper));
fdw->fdwid = fdwid;
fdw->owner = fdwform->fdwowner;
fdw->fdwname = pstrdup(NameStr(fdwform->fdwname));
fdw->fdwhandler = fdwform->fdwhandler;
fdw->fdwvalidator = fdwform->fdwvalidator;
/* Extract the options */
/* Extract the fdwoptions */
datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
tp,
Anum_pg_foreign_data_wrapper_fdwoptions,
&isnull);
fdw->options = untransformRelOptions(datum);
if (isnull)
fdw->options = NIL;
else
fdw->options = untransformRelOptions(datum);
ReleaseSysCache(tp);
@@ -88,7 +93,8 @@ GetForeignDataWrapperOidByName(const char *fdwname, bool missing_ok)
if (!OidIsValid(fdwId) && !missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("foreign-data wrapper \"%s\" does not exist", fdwname)));
errmsg("foreign-data wrapper \"%s\" does not exist",
fdwname)));
return fdwId;
}
@@ -103,7 +109,7 @@ GetForeignDataWrapperByName(const char *fdwname, bool missing_ok)
{
Oid fdwId = GetForeignDataWrapperOidByName(fdwname, missing_ok);
if (!OidIsValid(fdwId) && missing_ok)
if (!OidIsValid(fdwId))
return NULL;
return GetForeignDataWrapper(fdwId);
@@ -129,7 +135,7 @@ GetForeignServer(Oid serverid)
serverform = (Form_pg_foreign_server) GETSTRUCT(tp);
server = palloc(sizeof(ForeignServer));
server = (ForeignServer *) palloc(sizeof(ForeignServer));
server->serverid = serverid;
server->servername = pstrdup(NameStr(serverform->srvname));
server->owner = serverform->srvowner;
@@ -154,9 +160,10 @@ GetForeignServer(Oid serverid)
tp,
Anum_pg_foreign_server_srvoptions,
&isnull);
/* untransformRelOptions does exactly what we want - avoid duplication */
server->options = untransformRelOptions(datum);
if (isnull)
server->options = NIL;
else
server->options = untransformRelOptions(datum);
ReleaseSysCache(tp);
@@ -191,7 +198,7 @@ GetForeignServerByName(const char *srvname, bool missing_ok)
{
Oid serverid = GetForeignServerOidByName(srvname, missing_ok);
if (!OidIsValid(serverid) && missing_ok)
if (!OidIsValid(serverid))
return NULL;
return GetForeignServer(serverid);
@@ -233,16 +240,19 @@ GetUserMapping(Oid userid, Oid serverid)
umform = (Form_pg_user_mapping) GETSTRUCT(tp);
um = (UserMapping *) palloc(sizeof(UserMapping));
um->userid = userid;
um->serverid = serverid;
/* 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);
if (isnull)
um->options = NIL;
else
um->options = untransformRelOptions(datum);
ReleaseSysCache(tp);
@@ -250,6 +260,116 @@ GetUserMapping(Oid userid, Oid serverid)
}
/*
* GetForeignTable - look up the foreign table definition by relation oid.
*/
ForeignTable *
GetForeignTable(Oid relid)
{
Form_pg_foreign_table tableform;
ForeignTable *ft;
HeapTuple tp;
Datum datum;
bool isnull;
tp = SearchSysCache1(FOREIGNTABLEREL, ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for foreign table %u", relid);
tableform = (Form_pg_foreign_table) GETSTRUCT(tp);
ft = (ForeignTable *) palloc(sizeof(ForeignTable));
ft->relid = relid;
ft->serverid = tableform->ftserver;
/* Extract the ftoptions */
datum = SysCacheGetAttr(FOREIGNTABLEREL,
tp,
Anum_pg_foreign_table_ftoptions,
&isnull);
if (isnull)
ft->options = NIL;
else
ft->options = untransformRelOptions(datum);
ReleaseSysCache(tp);
return ft;
}
/*
* GetFdwRoutine - call the specified foreign-data wrapper handler routine
* to get its FdwRoutine struct.
*/
FdwRoutine *
GetFdwRoutine(Oid fdwhandler)
{
Datum datum;
FdwRoutine *routine;
datum = OidFunctionCall0(fdwhandler);
routine = (FdwRoutine *) DatumGetPointer(datum);
if (routine == NULL || !IsA(routine, FdwRoutine))
elog(ERROR, "foreign-data wrapper handler function %u did not return an FdwRoutine struct",
fdwhandler);
return routine;
}
/*
* GetFdwRoutineByRelId - look up the handler of the foreign-data wrapper
* for the given foreign table, and retrieve its FdwRoutine struct.
*/
FdwRoutine *
GetFdwRoutineByRelId(Oid relid)
{
HeapTuple tp;
Form_pg_foreign_data_wrapper fdwform;
Form_pg_foreign_server serverform;
Form_pg_foreign_table tableform;
Oid serverid;
Oid fdwid;
Oid fdwhandler;
/* Get server OID for the foreign table. */
tp = SearchSysCache1(FOREIGNTABLEREL, ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for foreign table %u", relid);
tableform = (Form_pg_foreign_table) GETSTRUCT(tp);
serverid = tableform->ftserver;
ReleaseSysCache(tp);
/* Get foreign-data wrapper OID for the server. */
tp = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for foreign server %u", serverid);
serverform = (Form_pg_foreign_server) GETSTRUCT(tp);
fdwid = serverform->srvfdw;
ReleaseSysCache(tp);
/* Get handler function OID for the FDW. */
tp = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwid);
fdwform = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp);
fdwhandler = fdwform->fdwhandler;
/* Complain if FDW has been set to NO HANDLER. */
if (!OidIsValid(fdwhandler))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("foreign-data wrapper \"%s\" has no handler",
NameStr(fdwform->fdwname))));
ReleaseSysCache(tp);
/* And finally, call the handler function. */
return GetFdwRoutine(fdwhandler);
}
/*
* deflist_to_tuplestore - Helper function to convert DefElem list to
* tuplestore usable in SRF.
@@ -261,7 +381,7 @@ deflist_to_tuplestore(ReturnSetInfo *rsinfo, List *options)
TupleDesc tupdesc;
Tuplestorestate *tupstore;
Datum values[2];
bool nulls[2] = {0};
bool nulls[2];
MemoryContext per_query_ctx;
MemoryContext oldcontext;
@@ -294,6 +414,7 @@ deflist_to_tuplestore(ReturnSetInfo *rsinfo, List *options)
values[0] = CStringGetTextDatum(def->defname);
values[1] = CStringGetTextDatum(((Value *) def->arg)->val.str);
nulls[0] = nulls[1] = false;
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
}
@@ -313,7 +434,8 @@ pg_options_to_table(PG_FUNCTION_ARGS)
{
Datum array = PG_GETARG_DATUM(0);
deflist_to_tuplestore((ReturnSetInfo *) fcinfo->resultinfo, untransformRelOptions(array));
deflist_to_tuplestore((ReturnSetInfo *) fcinfo->resultinfo,
untransformRelOptions(array));
return (Datum) 0;
}
@@ -407,7 +529,8 @@ postgresql_fdw_validator(PG_FUNCTION_ARGS)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("invalid option \"%s\"", def->defname),
errhint("Valid options in this context are: %s", buf.data)));
errhint("Valid options in this context are: %s",
buf.data)));
PG_RETURN_BOOL(false);
}