fdw_helper_funcs.patch

text/plain

Filename: fdw_helper_funcs.patch
Type: text/plain
Part: 1
Message: Re: WIP: Join push-down for foreign tables

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
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 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 ----
      </para>
  
      <para>
+ <programlisting>
+ char *
+ GetFdwOptionValue(Oid relid, AttrNumber attnum, const char *optname);
+ </programlisting>
+ 
+      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.
+     </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>
  
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);