fdw_helper_v4.patch
text/plain
Filename: fdw_helper_v4.patch
Type: text/plain
Part: 2
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v4
| File | + | − |
|---|---|---|
| contrib/file_fdw/file_fdw.c | 0 | 0 |
| doc/src/sgml/fdwhandler.sgml | 0 | 0 |
| src/backend/foreign/foreign.c | 0 | 0 |
| src/include/foreign/foreign.h | 0 | 0 |
diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c
index 46394a8..a522e36 100644
*** a/contrib/file_fdw/file_fdw.c
--- b/contrib/file_fdw/file_fdw.c
***************
*** 26,32 ****
#include "nodes/makefuncs.h"
#include "optimizer/cost.h"
#include "utils/rel.h"
! #include "utils/syscache.h"
PG_MODULE_MAGIC;
--- 26,32 ----
#include "nodes/makefuncs.h"
#include "optimizer/cost.h"
#include "utils/rel.h"
! #include "utils/lsyscache.h"
PG_MODULE_MAGIC;
*************** get_file_fdw_attribute_options(Oid relid
*** 345,398 ****
/* Retrieve FDW options for all user-defined attributes. */
for (attnum = 1; attnum <= natts; attnum++)
{
! HeapTuple tuple;
! Form_pg_attribute attr;
! Datum datum;
! bool isnull;
/* Skip dropped attributes. */
if (tupleDesc->attrs[attnum - 1]->attisdropped)
continue;
! /*
! * We need the whole pg_attribute tuple not just what is in the
! * tupleDesc, so must do a catalog lookup.
! */
! tuple = SearchSysCache2(ATTNUM,
! RelationGetRelid(rel),
! Int16GetDatum(attnum));
! if (!HeapTupleIsValid(tuple))
! elog(ERROR, "cache lookup failed for attribute %d of relation %u",
! attnum, RelationGetRelid(rel));
! attr = (Form_pg_attribute) GETSTRUCT(tuple);
!
! datum = SysCacheGetAttr(ATTNUM,
! tuple,
! Anum_pg_attribute_attfdwoptions,
! &isnull);
! if (!isnull)
{
! List *options = untransformRelOptions(datum);
! ListCell *lc;
! foreach(lc, options)
{
! DefElem *def = (DefElem *) lfirst(lc);
!
! if (strcmp(def->defname, "force_not_null") == 0)
{
! if (defGetBoolean(def))
! {
! char *attname = pstrdup(NameStr(attr->attname));
! fnncolumns = lappend(fnncolumns, makeString(attname));
! }
}
- /* maybe in future handle other options here */
}
}
-
- ReleaseSysCache(tuple);
}
heap_close(rel, AccessShareLock);
--- 345,373 ----
/* Retrieve FDW options for all user-defined attributes. */
for (attnum = 1; attnum <= natts; attnum++)
{
! List *options;
! ListCell *lc;
/* Skip dropped attributes. */
if (tupleDesc->attrs[attnum - 1]->attisdropped)
continue;
! options = GetForeignColumnOptions(relid, attnum);
! foreach(lc, options)
{
! DefElem *def = (DefElem *) lfirst(lc);
! if (strcmp(def->defname, "force_not_null") == 0)
{
! if (defGetBoolean(def))
{
! char *attname = pstrdup(get_attname(relid, attnum));
! fnncolumns = lappend(fnncolumns, makeString(attname));
}
}
+ /* maybe in future handle other options here */
}
}
heap_close(rel, AccessShareLock);
diff --git a/doc/src/sgml/fdwhandler.sgml b/doc/src/sgml/fdwhandler.sgml
index 76ff243..d809cac 100644
*** a/doc/src/sgml/fdwhandler.sgml
--- b/doc/src/sgml/fdwhandler.sgml
*************** EndForeignScan (ForeignScanState *node);
*** 235,238 ****
--- 235,392 ----
</sect1>
+ <sect1 id="fdw-helpers">
+ <title>Foreign Data Wrapper Helper Functions</title>
+
+ <para>
+ Several helper functions are exported from core so that authors of FDW
+ can get easy access to attributes of FDW-related objects such as FDW
+ options.
+ </para>
+
+ <para>
+ <programlisting>
+ ForeignDataWrapper *
+ GetForeignDataWrapper(Oid fdwid);
+ </programlisting>
+
+ This function returns a <structname>ForeignDataWrapper</structname> object
+ for a foreign-data wrapper with given oid. A
+ <structname>ForeignDataWrapper</structname> object contains oid of the
+ wrapper itself, oid of the owner of the wrapper, name of the wrapper, oid
+ of fdwhandler function, oid of fdwvalidator function, and FDW options in
+ the form of list of <structname>DefElem</structname>.
+ </para>
+
+ <para>
+ <programlisting>
+ ForeignServer *
+ GetForeignServer(Oid serverid);
+ </programlisting>
+
+ This function returns a <structname>ForeignServer</structname> object for
+ a foreign server with given oid. A <structname>ForeignServer</structname>
+ object contains oid of the server, oid of the wrapper for the server, oid
+ of the owner of the server, name of the server, type of the server,
+ version of the server, and FDW options in the form of list of
+ <structname>DefElem</structname>.
+ </para>
+
+ <para>
+ <programlisting>
+ UserMapping *
+ GetUserMapping(Oid userid, Oid serverid);
+ </programlisting>
+
+ This function returns a <structname>UserMapping</structname> object for a
+ user mapping with given oid pair. A <structname>UserMapping</structname>
+ object contains oid of the user, oid of the server, and FDW options in the
+ form of list of <structname>DefElem</structname>.
+ </para>
+
+ <para>
+ <programlisting>
+ ForeignTable *
+ GetForeignTable(Oid relid);
+ </programlisting>
+
+ This function returns a <structname>ForeignTable</structname> object for a
+ foreign table with given oid. A <structname>ForeignTable</structname>
+ object contains oid of the foreign table, oid of the server for the table,
+ and FDW options in the form of list of <structname>DefElem</structname>.
+ </para>
+
+ <para>
+ <programlisting>
+ List *
+ GetForeignTableColumnOptions(Oid relid, AttrNumber attnum);
+ </programlisting>
+
+ This function returns per-column FDW options for a column with given
+ relation oid and attribute number in the form of list of
+ <structname>DefElem</structname>.
+ </para>
+
+ <para>
+ Some object types have name-based functions.
+ </para>
+
+ <para>
+ <programlisting>
+ ForeignDataWrapper *
+ GetForeignDataWrapperByName(const char *name, bool missing_ok);
+ </programlisting>
+
+ This function returns a <structname>ForeignDataWrapper</structname> object
+ for a foreign-data wrapper with given name. If the wrapper is not found,
+ return NULL if missing_ok was true, otherwise raise an error.
+ </para>
+
+ <para>
+ <programlisting>
+ ForeignServer *
+ GetForeignServerByName(const char *name, bool missing_ok);
+ </programlisting>
+
+ This function returns a <structname>ForeignServer</structname> object for
+ a foreign server with given name. If the server is not found, return NULL
+ if missing_ok was true, otherwise raise an error.
+ </para>
+
+ <para>
+ <programlisting>
+ char *
+ GetFdwOptionValue(Oid fdwid, Oid serverid, Oid relid, AttrNumber attnum, const char *optname);
+ </programlisting>
+
+ This function returns a copied string (created in current memory context)
+ of the value of a FDW option with given name which is set on a object with
+ given oid and attribute number. This function ignores catalogs if invalid
+ identifir is given for it.
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ If attnum is <literal>InvalidAttrNumber</literal> or relid is
+ <literal>Invalidoid</literal>, <structname>pg_attribute</structname> is
+ ignored.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If relid is <literal>InvalidOid</literal>,
+ <structname>pg_foreign_table</structname> is ignored.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If both serverid and relid are <literal>InvalidOid</literal>,
+ <structname>pg_foreign_server</structname> is ignored.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If all of fdwid, serverid and relid are <literal>InvalidOid</literal>,
+ <structname>pg_foreign_data_wrapper</structname> is ignored.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ If the option with given name is set in multiple object level, the one in
+ the finest-grained object is used; e.g. priority is given to user mappings
+ over than foreign servers.
+ This function would be useful when you know which option is needed but you
+ don't know where it is set. If you already know the source object, it
+ would be more efficient to use object retrieval functions.
+ </para>
+
+ <para>
+ To use any of these functions, you need to include
+ <filename>foreign/foreign.h</filename> in your source file.
+ </para>
+
+ </sect1>
+
</chapter>
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c
index c4c2a61..8e98f0f 100644
*** a/src/backend/foreign/foreign.c
--- b/src/backend/foreign/foreign.c
*************** GetForeignTable(Oid relid)
*** 248,253 ****
--- 248,378 ----
/*
+ * If an option entry which matches the given name was found in the given
+ * list, returns a copy of arg string, otherwise returns NULL.
+ */
+ static char *
+ get_options_value(List *options, const char *optname)
+ {
+ ListCell *lc;
+
+ /* Find target option from the list. */
+ foreach (lc, options)
+ {
+ DefElem *def = lfirst(lc);
+
+ if (strcmp(def->defname, optname) == 0)
+ return pstrdup(strVal(def->arg));
+ }
+
+ return NULL;
+ }
+
+ /*
+ * Returns a copy of the value of specified option with searching the option
+ * from appropriate catalog. If an option was stored in multiple object
+ * levels, one in the finest-grained object level is used; lookup order is:
+ * 1) pg_attribute (only when both attnum and relid are valid)
+ * 2) pg_foreign_table (only when relid is valid)
+ * 3) pg_user_mapping (only when serverid or relid is valid)
+ * 4) pg_foreign_server (only when serverid or relid is valid)
+ * 5) pg_foreign_data_wrapper (only when fdwid or serverid or relid is valid)
+ * This priority rule would be useful in most cases using FDW options.
+ *
+ * If attnum was InvalidAttrNumber, we don't retrieve FDW optiosn from
+ * pg_attribute.attfdwoptions.
+ */
+ char *
+ GetFdwOptionValue(Oid fdwid, Oid serverid, Oid relid, AttrNumber attnum,
+ const char *optname)
+ {
+ ForeignTable *table = NULL;
+ UserMapping *user = NULL;
+ ForeignServer *server = NULL;
+ ForeignDataWrapper *wrapper = NULL;
+ char *value;
+
+ /* Do we need to search pg_attribute? */
+ if (attnum != InvalidAttrNumber && relid != InvalidOid)
+ {
+ value = get_options_value(GetForeignColumnOptions(relid, attnum),
+ optname);
+ if (value != NULL)
+ return value;
+ }
+
+ /* Do we need to search pg_foreign_table? */
+ if (relid != InvalidOid)
+ {
+ table = GetForeignTable(relid);
+ value = get_options_value(table->options, optname);
+ if (value != NULL)
+ return value;
+
+ serverid = table->serverid;
+ }
+
+ /* Do we need to search pg_user_mapping and pg_foreign_server? */
+ if (serverid != InvalidOid)
+ {
+ user = GetUserMapping(GetOuterUserId(), serverid);
+ value = get_options_value(user->options, optname);
+ if (value != NULL)
+ return value;
+
+ server = GetForeignServer(serverid);
+ value = get_options_value(server->options, optname);
+ if (value != NULL)
+ return value;
+
+ fdwid = server->fdwid;
+ }
+
+ /* Do we need to search pg_foreign_data_wrapper? */
+ if (fdwid != InvalidOid)
+ {
+ wrapper = GetForeignDataWrapper(fdwid);
+ value = get_options_value(wrapper->options, optname);
+ if (value != NULL)
+ return value;
+ }
+
+ return NULL;
+ }
+
+
+ /*
+ * GetForeignColumnOptions - Get attfdwoptions of given relation/attnum as
+ * list of DefElem.
+ */
+ List *
+ GetForeignColumnOptions(Oid relid, AttrNumber attnum)
+ {
+ List *options;
+ HeapTuple tp;
+ Datum datum;
+ bool isnull;
+
+ tp = SearchSysCache2(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for attribute %d of relation %u", attnum, relid);
+ datum = SysCacheGetAttr(ATTNUM,
+ tp,
+ Anum_pg_attribute_attfdwoptions,
+ &isnull);
+ if (isnull)
+ options = NIL;
+ else
+ options = untransformRelOptions(datum);
+
+ ReleaseSysCache(tp);
+
+ return options;
+ }
+
+ /*
* GetFdwRoutine - call the specified foreign-data wrapper handler routine
* to get its FdwRoutine struct.
*/
diff --git a/src/include/foreign/foreign.h b/src/include/foreign/foreign.h
index 191122d..e25b871 100644
*** a/src/include/foreign/foreign.h
--- b/src/include/foreign/foreign.h
*************** extern ForeignDataWrapper *GetForeignDat
*** 75,80 ****
--- 75,83 ----
extern ForeignDataWrapper *GetForeignDataWrapperByName(const char *name,
bool missing_ok);
extern ForeignTable *GetForeignTable(Oid relid);
+ extern char *GetFdwOptionValue(Oid fdwid, Oid serverid, Oid relid,
+ AttrNumber attnum, const char *optname);
+ extern List *GetForeignColumnOptions(Oid relid, AttrNumber attnum);
extern Oid get_foreign_data_wrapper_oid(const char *fdwname, bool missing_ok);
extern Oid get_foreign_server_oid(const char *servername, bool missing_ok);