diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c
index 1cf3b3c..4a7ffa6 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 db02d13..43ad6ed 100644
*** a/doc/src/sgml/fdwhandler.sgml
--- b/doc/src/sgml/fdwhandler.sgml
*************** GetForeignTable(Oid relid);
*** 297,302 ****
--- 297,332 ----
+
+ char *
+ GetFdwOptionValue(Oid relid, AttrNumber attnum, const char *optname);
+
+
+ This function returns a copy (created in current memory context) of the
+ value of the given option for the given object (relation or its column).
+ If attnum is InvalidAttrNumber, pg_attribute is ignored.
+ If specified option is set in multiple object level, the one in the
+ finest-grained object is used; e.g. priority is given to user mapping
+ over than a foreign server for the mapping or foreign-data wrapper for the
+ server.
+ This function would be useful when you know which option is needed but you
+ don't know which object(s) have it.
+ If you already know the source object, it would be more efficient to use
+ object retrieval functions.
+
+
+
+
+ List *
+ GetForeignTableColumnOptions(Oid relid, AttrNumber attnum);
+
+
+ This function returns per-column FDW options for a column with given
+ relation oid and attribute number in the form of list of
+ DefElem.
+
+
+
Some object types have name-based functions.
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c
index a7d30a1..df0e373 100644
*** a/src/backend/foreign/foreign.c
--- b/src/backend/foreign/foreign.c
*************** GetForeignTable(Oid relid)
*** 248,253 ****
--- 248,361 ----
/*
+ * 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 attnum != InvalidAttrNumber)
+ * 2) pg_foreign_table
+ * 3) pg_user_mapping
+ * 4) pg_foreign_server
+ * 5) pg_foreign_data_wrapper
+ * 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 relid, AttrNumber attnum, const char *optname)
+ {
+ ForeignTable *table = NULL;
+ UserMapping *user = NULL;
+ ForeignServer *server = NULL;
+ ForeignDataWrapper *wrapper = NULL;
+ char *value;
+
+ /* Do we need to use pg_attribute.attfdwoptions too? */
+ if (attnum != InvalidAttrNumber)
+ {
+ value = get_options_value(GetForeignColumnOptions(relid, attnum),
+ optname);
+ if (value != NULL)
+ return value;
+ }
+
+ table = GetForeignTable(relid);
+ value = get_options_value(table->options, optname);
+ if (value != NULL)
+ return value;
+
+ user = GetUserMapping(GetOuterUserId(), table->serverid);
+ value = get_options_value(user->options, optname);
+ if (value != NULL)
+ return value;
+
+ server = GetForeignServer(table->serverid);
+ value = get_options_value(server->options, optname);
+ if (value != NULL)
+ return value;
+
+ wrapper = GetForeignDataWrapper(server->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 2c436ae..b6c8d5b 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 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);