 contrib/file_fdw/file_fdw.c             |   4 +-
 contrib/postgres_fdw/postgres_fdw.c     |  16 ++--
 doc/src/sgml/fdwhandler.sgml            |  11 +--
 src/backend/commands/explain.c          |   2 +-
 src/backend/executor/nodeModifyTable.c  |   2 +-
 src/backend/nodes/Makefile              |   2 +-
 src/backend/nodes/copyfuncs.c           |  28 +++++++
 src/backend/nodes/equalfuncs.c          |  28 +++++++
 src/backend/nodes/extensible.c          |  88 ++++++++++++++++++++++
 src/backend/nodes/outfuncs.c            |  42 +++++++++++
 src/backend/nodes/readfuncs.c           |  39 ++++++++++
 src/backend/optimizer/plan/createplan.c |   6 +-
 src/backend/optimizer/util/pathnode.c   |   2 +-
 src/include/foreign/fdwapi.h            |   6 +-
 src/include/nodes/extensible.h          | 129 ++++++++++++++++++++++++++++++++
 src/include/nodes/nodes.h               |  12 +++
 src/include/nodes/plannodes.h           |   4 +-
 src/include/nodes/relation.h            |   4 +-
 src/include/optimizer/pathnode.h        |   2 +-
 src/include/optimizer/planmain.h        |   2 +-
 20 files changed, 398 insertions(+), 31 deletions(-)

diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c
index f13316b..b648991 100644
--- a/contrib/file_fdw/file_fdw.c
+++ b/contrib/file_fdw/file_fdw.c
@@ -527,7 +527,7 @@ fileGetForeignPaths(PlannerInfo *root,
 									 NIL,		/* no pathkeys */
 									 NULL,		/* no outer rel either */
 									 NULL,		/* no extra plan */
-									 coptions));
+									 (Node *)coptions));
 
 	/*
 	 * If data file was sorted, and we knew it somehow, we could insert
@@ -622,7 +622,7 @@ fileBeginForeignScan(ForeignScanState *node, int eflags)
 				   &filename, &options);
 
 	/* Add any options from the plan (currently only convert_selectively) */
-	options = list_concat(options, plan->fdw_private);
+	options = list_concat(options, (List *)plan->fdw_private);
 
 	/*
 	 * Create CopyState from FDW options.  We always acquire all columns, so
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index d5a2af9..36b407d 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -731,7 +731,7 @@ postgresGetForeignPaths(PlannerInfo *root,
 								   NIL, /* no pathkeys */
 								   NULL,		/* no outer rel either */
 								   NULL,		/* no extra plan */
-								   NIL);		/* no fdw_private list */
+								   NULL);		/* no fdw_private */
 	add_path(baserel, (Path *) path);
 
 	useful_pathkeys_list = get_useful_pathkeys_for_relation(root, baserel);
@@ -756,7 +756,7 @@ postgresGetForeignPaths(PlannerInfo *root,
 										 useful_pathkeys,
 										 NULL,
 										 NULL,
-										 NIL));
+										 NULL));
 	}
 
 	/*
@@ -924,7 +924,7 @@ postgresGetForeignPaths(PlannerInfo *root,
 									   NIL,		/* no pathkeys */
 									   param_info->ppi_req_outer,
 									   NULL,
-									   NIL);	/* no fdw_private list */
+									   NULL);	/* no fdw_private */
 		add_path(baserel, (Path *) path);
 	}
 }
@@ -1027,7 +1027,7 @@ postgresGetForeignPlan(PlannerInfo *root,
 							local_exprs,
 							scan_relid,
 							params_list,
-							fdw_private,
+							(Node *)fdw_private,
 							NIL,	/* no custom tlist */
 							remote_exprs,
 							outer_plan);
@@ -1086,11 +1086,11 @@ postgresBeginForeignScan(ForeignScanState *node, int eflags)
 	fsstate->cursor_exists = false;
 
 	/* Get private info created by planner functions. */
-	fsstate->query = strVal(list_nth(fsplan->fdw_private,
+	fsstate->query = strVal(list_nth((List *)fsplan->fdw_private,
 									 FdwScanPrivateSelectSql));
-	fsstate->retrieved_attrs = (List *) list_nth(fsplan->fdw_private,
+	fsstate->retrieved_attrs = (List *) list_nth((List *)fsplan->fdw_private,
 											   FdwScanPrivateRetrievedAttrs);
-	fsstate->fetch_size = intVal(list_nth(fsplan->fdw_private,
+	fsstate->fetch_size = intVal(list_nth((List *)fsplan->fdw_private,
 										  FdwScanPrivateFetchSize));
 
 	/* Create contexts for batches of tuples and per-tuple temp workspace. */
@@ -1836,7 +1836,7 @@ postgresExplainForeignScan(ForeignScanState *node, ExplainState *es)
 
 	if (es->verbose)
 	{
-		fdw_private = ((ForeignScan *) node->ss.ps.plan)->fdw_private;
+		fdw_private = (List *)((ForeignScan *) node->ss.ps.plan)->fdw_private;
 		sql = strVal(list_nth(fdw_private, FdwScanPrivateSelectSql));
 		ExplainPropertyText("Remote SQL", sql, es);
 	}
diff --git a/doc/src/sgml/fdwhandler.sgml b/doc/src/sgml/fdwhandler.sgml
index ffbd1e3..0707f68 100644
--- a/doc/src/sgml/fdwhandler.sgml
+++ b/doc/src/sgml/fdwhandler.sgml
@@ -415,7 +415,7 @@ AddForeignUpdateTargets (Query *parsetree,
 
     <para>
 <programlisting>
-List *
+Node *
 PlanForeignModify (PlannerInfo *root,
                    ModifyTable *plan,
                    Index resultRelation,
@@ -425,8 +425,9 @@ PlanForeignModify (PlannerInfo *root,
      Perform any additional planning actions needed for an insert, update, or
      delete on a foreign table.  This function generates the FDW-private
      information that will be attached to the <structname>ModifyTable</> plan
-     node that performs the update action.  This private information must
-     have the form of a <literal>List</>, and will be delivered to
+     node that performs the update action.  This private information must be
+     a node type which support <function>copyObject</> and other node
+     operations, like <literal>List</>, then it will be delivered to
      <function>BeginForeignModify</> during the execution stage.
     </para>
 
@@ -457,7 +458,7 @@ PlanForeignModify (PlannerInfo *root,
 void
 BeginForeignModify (ModifyTableState *mtstate,
                     ResultRelInfo *rinfo,
-                    List *fdw_private,
+                    Node *fdw_private,
                     int subplan_index,
                     int eflags);
 </programlisting>
@@ -844,7 +845,7 @@ ExplainForeignScan (ForeignScanState *node,
 void
 ExplainForeignModify (ModifyTableState *mtstate,
                       ResultRelInfo *rinfo,
-                      List *fdw_private,
+                      Node *fdw_private,
                       int subplan_index,
                       struct ExplainState *es);
 </programlisting>
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index ee13136..32e701f 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -2626,7 +2626,7 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
 		/* Give FDW a chance */
 		if (fdwroutine && fdwroutine->ExplainForeignModify != NULL)
 		{
-			List	   *fdw_private = (List *) list_nth(node->fdwPrivLists, j);
+			Node	   *fdw_private = list_nth(node->fdwPrivLists, j);
 
 			fdwroutine->ExplainForeignModify(mtstate,
 											 resultRelInfo,
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 27051e8..0faa54a 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1586,7 +1586,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 		if (resultRelInfo->ri_FdwRoutine != NULL &&
 			resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
 		{
-			List	   *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
+			Node	   *fdw_private = list_nth(node->fdwPrivLists, i);
 
 			resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
 															 resultRelInfo,
diff --git a/src/backend/nodes/Makefile b/src/backend/nodes/Makefile
index fe2e460..01ba748 100644
--- a/src/backend/nodes/Makefile
+++ b/src/backend/nodes/Makefile
@@ -14,6 +14,6 @@ include $(top_builddir)/src/Makefile.global
 
 OBJS = nodeFuncs.o nodes.o list.o bitmapset.o tidbitmap.o \
        copyfuncs.o equalfuncs.o makefuncs.o \
-       outfuncs.o readfuncs.o print.o read.o params.o value.o
+       outfuncs.o readfuncs.o print.o read.o params.o value.o extensible.o
 
 include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index e54d174..4ce767a 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -23,6 +23,7 @@
 #include "postgres.h"
 
 #include "miscadmin.h"
+#include "nodes/extensible.h"
 #include "nodes/plannodes.h"
 #include "nodes/relation.h"
 #include "utils/datum.h"
@@ -4166,6 +4167,26 @@ _copyList(const List *from)
 }
 
 /* ****************************************************************
+ *					extensible.h copy functions
+ * ****************************************************************
+ */
+static ExtensibleNode *
+_copyExtensibleNode(const ExtensibleNode *from)
+{
+	ExtensibleNode	   *newnode;
+	const ExtensibleNodeMethods *methods
+		= GetExtensibleNodeMethods(from->extnodename);
+
+	newnode = (ExtensibleNode *) newNode(methods->node_size,
+										 T_ExtensibleNode);
+	COPY_STRING_FIELD(extnodename);
+	/* copy the private fields defined by extensions */
+	methods->nodeCopy(newnode, from);
+
+	return newnode;
+}
+
+/* ****************************************************************
  *					value.h copy functions
  * ****************************************************************
  */
@@ -4545,6 +4566,13 @@ copyObject(const void *from)
 			break;
 
 			/*
+			 * EXTENSIBLE NODES
+			 */
+		case T_ExtensibleNode:
+			retval = _copyExtensibleNode(from);
+			break;
+
+			/*
 			 * PARSE NODES
 			 */
 		case T_Query:
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 08ccc0d..1ac9233 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -29,6 +29,7 @@
 
 #include "postgres.h"
 
+#include "nodes/extensible.h"
 #include "nodes/relation.h"
 #include "utils/datum.h"
 
@@ -871,6 +872,26 @@ _equalPlaceHolderInfo(const PlaceHolderInfo *a, const PlaceHolderInfo *b)
 	return true;
 }
 
+/*
+ * Stuff from extensible.h
+ */
+static bool
+_equalExtensibleNode(const ExtensibleNode *a, const ExtensibleNode *b)
+{
+	const ExtensibleNodeMethods  *methods;
+
+	COMPARE_STRING_FIELD(extnodename);
+	/*
+	 * At this point, both of nodes have same extnodename, so it shall pull
+	 * same callback collection of ExtensibleNode. No need to pull both.
+	 */
+	methods = GetExtensibleNodeMethods(a->extnodename);
+	/* compare the private fields defined by extensions */
+	if (!methods->nodeEqual(a, b))
+		return false;
+
+	return true;
+}
 
 /*
  * Stuff from parsenodes.h
@@ -2874,6 +2895,13 @@ equal(const void *a, const void *b)
 			break;
 
 			/*
+			 * EXTENSIBLE NODES
+			 */
+		case T_ExtensibleNode:
+			retval = _equalExtensibleNode(a, b);
+			break;
+
+			/*
 			 * PARSE NODES
 			 */
 		case T_Query:
diff --git a/src/backend/nodes/extensible.c b/src/backend/nodes/extensible.c
new file mode 100644
index 0000000..5af3c8c
--- /dev/null
+++ b/src/backend/nodes/extensible.c
@@ -0,0 +1,88 @@
+/*-------------------------------------------------------------------------
+ *
+ * extensible.c
+ *    Routines to manage ExtensibleNode structure
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *    src/backend/nodes/extensible.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "nodes/extensible.h"
+#include "utils/hsearch.h"
+
+/*
+ * Extensible node support - We allow extensions to define own structure that
+ * embedds ExtensibleNode and some private variables.
+ * These structure also have to support serialization / deserialization using
+ * node functions. A collection of in ExtensibleNodeMethods callbacks enable
+ * to handle private fields also, not only well known portion.
+ */
+static HTAB		   *extensible_node_methods = NULL;
+
+typedef struct
+{
+	char		extnodename[NAMEDATALEN];
+	const ExtensibleNodeMethods *methods;
+} ExtensibleNodeEntry;
+
+void
+RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *methods)
+{
+	ExtensibleNodeEntry *entry;
+	bool	found;
+
+	if (!extensible_node_methods)
+	{
+		HASHCTL	ctl;
+
+		memset(&ctl, 0, sizeof(HASHCTL));
+        ctl.keysize = NAMEDATALEN;
+        ctl.entrysize = sizeof(const ExtensibleNodeEntry);
+        extensible_node_methods = hash_create("Extensible Node Methods",
+											  100, &ctl, HASH_ELEM);
+	}
+
+	if (strlen(methods->extnodename) >= NAMEDATALEN)
+		ereport(ERROR,
+				(errcode(ERRCODE_NAME_TOO_LONG),
+				 errmsg("ExtensibleNodeMethods \"%s\" name too long",
+						methods->extnodename)));
+
+	entry = (ExtensibleNodeEntry *) hash_search(extensible_node_methods,
+												methods->extnodename,
+												HASH_ENTER, &found);
+	if (found)
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("ExtensibleNodeMethods \"%s\" already exists",
+						methods->extnodename)));
+	/* setup entry */
+	entry->methods = methods;
+}
+
+const ExtensibleNodeMethods *
+GetExtensibleNodeMethods(const char *extnodename)
+{
+	ExtensibleNodeEntry *entry = NULL;
+
+	if (extensible_node_methods)
+	{
+		entry = (ExtensibleNodeEntry *) hash_search(extensible_node_methods,
+													extnodename,
+													HASH_FIND, NULL);
+	}
+
+	if (!entry)
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_OBJECT),
+				 errmsg("ExtensibleNodeMethods \"%s\" was not registered",
+						extnodename)));
+	return entry->methods;
+}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 3e1c3e6..33414ce 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -26,6 +26,7 @@
 #include <ctype.h>
 
 #include "lib/stringinfo.h"
+#include "nodes/extensible.h"
 #include "nodes/plannodes.h"
 #include "nodes/relation.h"
 #include "utils/datum.h"
@@ -140,6 +141,15 @@ _outToken(StringInfo str, const char *s)
 	}
 }
 
+/*
+ * outToken - entrypoint for extensions
+ */
+void
+outToken(StringInfo str, const char *s)
+{
+	_outToken(str, s);
+}
+
 static void
 _outList(StringInfo str, const List *node)
 {
@@ -197,6 +207,15 @@ _outBitmapset(StringInfo str, const Bitmapset *bms)
 }
 
 /*
+ * outBitmapset - entrypoint for extensions
+ */
+void
+outBitmapset(StringInfo str, const Bitmapset *bms)
+{
+	_outBitmapset(str, bms);
+}
+
+/*
  * Print the value of a Datum given its type.
  */
 static void
@@ -2114,6 +2133,25 @@ _outPlannerParamItem(StringInfo str, const PlannerParamItem *node)
 
 /*****************************************************************************
  *
+ *	Stuff from extensible.h
+ *
+ *****************************************************************************/
+
+static void
+_outExtensibleNode(StringInfo str, const ExtensibleNode *node)
+{
+	const ExtensibleNodeMethods  *methods
+		= GetExtensibleNodeMethods(node->extnodename);
+
+	WRITE_NODE_TYPE("EXTENSIBLENODE");
+
+	WRITE_STRING_FIELD(extnodename);
+	/* serialize the private fields defined by extensions */
+	methods->nodeOut(str, node);
+}
+
+/*****************************************************************************
+ *
  *	Stuff from parsenodes.h.
  *
  *****************************************************************************/
@@ -3367,6 +3405,10 @@ _outNode(StringInfo str, const void *obj)
 				_outPlannerParamItem(str, obj);
 				break;
 
+			case T_ExtensibleNode:
+				_outExtensibleNode(str, obj);
+				break;
+
 			case T_CreateStmt:
 				_outCreateStmt(str, obj);
 				break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index e4d41ee..59aa8bd 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -29,6 +29,7 @@
 #include <math.h>
 
 #include "fmgr.h"
+#include "nodes/extensible.h"
 #include "nodes/parsenodes.h"
 #include "nodes/plannodes.h"
 #include "nodes/readfuncs.h"
@@ -218,6 +219,14 @@ _readBitmapset(void)
 	return result;
 }
 
+/*
+ * readBitmapset - entrypoint for extensions
+ */
+Bitmapset *
+readBitmapset(void)
+{
+	return _readBitmapset();
+}
 
 /*
  * _readQuery
@@ -2220,6 +2229,34 @@ _readAlternativeSubPlan(void)
 }
 
 /*
+ * _readExtensibleNode
+ */
+static ExtensibleNode *
+_readExtensibleNode(void)
+{
+	const ExtensibleNodeMethods *methods;
+	ExtensibleNode *local_node;
+	const char	   *extnodename;
+	READ_TEMP_LOCALS();
+
+	token = pg_strtok(&length);		/* skip: extnodename */
+	token = pg_strtok(&length);		/* get extnodename */
+
+	extnodename = nullable_string(token, length);
+	if (!extnodename)
+		elog(ERROR, "extnodename has to be supplied");
+	methods = GetExtensibleNodeMethods(extnodename);
+
+	local_node = (ExtensibleNode *) newNode(methods->node_size,
+											T_ExtensibleNode);
+	local_node->extnodename = extnodename;
+	/* deserialize the private fields defined by extensions */
+	methods->nodeRead(local_node);
+
+	READ_DONE();
+}
+
+/*
  * parseNodeString
  *
  * Given a character string representing a node tree, parseNodeString creates
@@ -2447,6 +2484,8 @@ parseNodeString(void)
 		return_value = _readSubPlan();
 	else if (MATCH("ALTERNATIVESUBPLAN", 18))
 		return_value = _readAlternativeSubPlan();
+	else if (MATCH("EXTENSIBLENODE", 14))
+		return_value = _readExtensibleNode();
 	else
 	{
 		elog(ERROR, "badly formatted node string \"%.32s\"...", token);
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 6e0db08..80e5017 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -3778,7 +3778,7 @@ make_foreignscan(List *qptlist,
 				 List *qpqual,
 				 Index scanrelid,
 				 List *fdw_exprs,
-				 List *fdw_private,
+				 Node *fdw_private,
 				 List *fdw_scan_tlist,
 				 List *fdw_recheck_quals,
 				 Plan *outer_plan)
@@ -5154,7 +5154,7 @@ make_modifytable(PlannerInfo *root,
 	{
 		Index		rti = lfirst_int(lc);
 		FdwRoutine *fdwroutine;
-		List	   *fdw_private;
+		Node	   *fdw_private;
 
 		/*
 		 * If possible, we want to get the FdwRoutine from our RelOptInfo for
@@ -5185,7 +5185,7 @@ make_modifytable(PlannerInfo *root,
 			fdwroutine->PlanForeignModify != NULL)
 			fdw_private = fdwroutine->PlanForeignModify(root, node, rti, i);
 		else
-			fdw_private = NIL;
+			fdw_private = NULL;
 		fdw_private_list = lappend(fdw_private_list, fdw_private);
 		i++;
 	}
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 1097a18..2dc7505 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1800,7 +1800,7 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
 						List *pathkeys,
 						Relids required_outer,
 						Path *fdw_outerpath,
-						List *fdw_private)
+						Node *fdw_private)
 {
 	ForeignPath *pathnode = makeNode(ForeignPath);
 
diff --git a/src/include/foreign/fdwapi.h b/src/include/foreign/fdwapi.h
index 9fafab0..3457ca1 100644
--- a/src/include/foreign/fdwapi.h
+++ b/src/include/foreign/fdwapi.h
@@ -63,14 +63,14 @@ typedef void (*AddForeignUpdateTargets_function) (Query *parsetree,
 												   RangeTblEntry *target_rte,
 												   Relation target_relation);
 
-typedef List *(*PlanForeignModify_function) (PlannerInfo *root,
+typedef Node *(*PlanForeignModify_function) (PlannerInfo *root,
 														 ModifyTable *plan,
 														 Index resultRelation,
 														 int subplan_index);
 
 typedef void (*BeginForeignModify_function) (ModifyTableState *mtstate,
 														 ResultRelInfo *rinfo,
-														 List *fdw_private,
+														 Node *fdw_private,
 														 int subplan_index,
 														 int eflags);
 
@@ -107,7 +107,7 @@ typedef void (*ExplainForeignScan_function) (ForeignScanState *node,
 
 typedef void (*ExplainForeignModify_function) (ModifyTableState *mtstate,
 														ResultRelInfo *rinfo,
-														   List *fdw_private,
+														   Node *fdw_private,
 														   int subplan_index,
 													struct ExplainState *es);
 
diff --git a/src/include/nodes/extensible.h b/src/include/nodes/extensible.h
new file mode 100644
index 0000000..b94ff7a
--- /dev/null
+++ b/src/include/nodes/extensible.h
@@ -0,0 +1,129 @@
+/*-------------------------------------------------------------------------
+ *
+ * extensible.h
+ *    Definitions for extensible node type
+ *
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/nodes/extensible.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef EXTENSIBLE_H
+#define EXTENSIBLE_H
+
+#include "nodes/nodes.h"
+
+/*
+ * ExtensibleNode - base structure of self-defined custom node type
+ *
+ * Extensions often need to manage its private data on interactions between
+ * the core backend and extensions, like foreign-data wrapper or custom scan
+ * provider.
+ * ExtensibleNode allows extension to define its own data structure under the
+ * compliance of node operations (copy, equal, out and read).
+ * In a typical use scenario, we expects ExtensibleNode is embedded in
+ * a larger self-defined structure, with identifier of ExtensibleNodeMethods.
+ * ExtensibleNodeMethods is a collection of callbacks for node operations,
+ * and registered with a unique identifier preliminarily; usually, on the
+ * time of _PG_init().
+ * Below is an example of a larger self-defined structure that embeds the
+ * ExtensibleNode, in addition to the private variables.
+ *
+ *   typedef struct myPrivateData
+ *   {
+ *       ExtensibleNode extnode;
+ *       char          *foo_name;   // private
+ *       int            var_index;  // private
+ *       int            baz_value;  // private
+ *   } myPrivateData;
+ *
+ * This structure contains three private variables, but core backend does not
+ * know anything about it. So, it is responsibility of the callback functions
+ * of ExtensibleNodeMethods that shall be defined and registered by the
+ * extension.
+ *
+ * ExtensibleNodeMethods provides an infrastructure to coordinate between
+ * the core backend and extension to handle these private fields properly.
+ *
+ * Extensions who want to use larger structures has to register a statically
+ * allocated ExtensibleNodeMethods, likely at the time of _PG_init(), using
+ * RegisterExtensibleNodeMethods(), with a unique name.
+ * The registered ExtensibleNodeMethods contains the following fields and
+ * callbacks. It is role of extension to implement them properly.
+ *
+ * const char *extnodename
+ * ------------------------
+ * This field is a unique name of the ExtensibleNodeMethods. It shouldn't
+ * be duplicated to others.
+ *
+ * Size     node_size
+ * -------------------
+ * This field introduces size of the larger structure including private
+ * fileds, to be allocated on its creation time. We don't support variable-
+ * length fields in this schema. If needed, allocate a separated array
+ * individually.
+ *
+ * void     (*nodeCopy)(ExtensibleNode *newnode, const ExtensibleNode *oldnode)
+ * ----------------------------------------------------------------------------
+ * This callback supplies a newly allocated node and the original; both of
+ * them are relevant to ths ExtensibleNodeMethods. Extension has to make
+ * copy of the private fields
+ * The portion of the well known node embedded in the private larger structure
+ * is already processed by the copyfunc.c, so all extension has to copy is
+ * its private fields.
+ *
+ * bool     (*nodeEqual)(const ExtensibleNode *a, const ExtensibleNode *b)
+ * -----------------------------------------------------------------------
+ * This callback supplies two node objects that is relevant to same extensible
+ * node methods. The portion of the well known node embedded in the private
+ * larger structure is already checked, so all all extension has to compare is
+ * its private fields.
+ *
+ * void     (*nodeOut)(StringInfo str, const ExtensibleNode *node)
+ * ---------------------------------------------------------------
+ * This callback serializes the supplied node object onto the StringInfo
+ * buffer. The portion of the well known node embedded in the private larger
+ * structure is already serialized (written out), so all extension has to
+ * write is its private fields.
+ * The written text form has to follow the manner in outfuncs.c, and also
+ * has to be reproducible using the 'nodeRead' callback below.
+ *
+ * void     (*nodeRead)(ExtensibleNode *node)
+ * ------------------------------------------
+ * This callback de-serializes the supplied node object according to the
+ * extra tokens that reflect the private fields written by the above 'nodeOut'
+ * callback. The portion of the well known node embedded in the private larger
+ * structure is already de-serialized (read in), so all extension has to
+ * reconstruct from the upcoming tokens is its private fields.
+ * Extension can fetch next token using pg_strtok() from the current input
+ * stream, then reconstruct the private fields according to the manner in
+ * readfuncs.c.
+ */
+struct ExtensibleNode;
+
+typedef struct ExtensibleNodeMethods
+{
+	const char *extnodename;
+	Size		node_size;
+	void	  (*nodeCopy)(struct ExtensibleNode *newnode,
+						  const struct ExtensibleNode *oldnode);
+	bool	  (*nodeEqual)(const struct ExtensibleNode *a,
+						   const struct ExtensibleNode *b);
+	void	  (*nodeOut)(struct StringInfoData *str,
+						 const struct ExtensibleNode *node);
+	void	  (*nodeRead)(struct ExtensibleNode *node);
+} ExtensibleNodeMethods;
+
+typedef struct ExtensibleNode
+{
+	NodeTag		type;
+	const char *extnodename;	/* identifier of ExtensibleNodeMethods */
+} ExtensibleNode;
+
+extern void RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *method);
+extern const ExtensibleNodeMethods *GetExtensibleNodeMethods(const char *name);
+
+#endif	/* EXTENSIBLE_H */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index cf09db4..c407fa2 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -276,6 +276,11 @@ typedef enum NodeTag
 	T_OidList,
 
 	/*
+	 * TAGS FOR EXTENSIBLE NODES (extensible.h)
+	 */
+	T_ExtensibleNode,
+
+	/*
 	 * TAGS FOR STATEMENT NODES (mostly in parsenodes.h)
 	 */
 	T_Query = 700,
@@ -527,10 +532,17 @@ extern PGDLLIMPORT Node *newNodeMacroHolder;
  */
 extern char *nodeToString(const void *obj);
 
+struct Bitmapset;		/* not to include bitmapset.h here */
+struct StringInfoData;	/* not to include stringinfo.h here */
+extern void outToken(struct StringInfoData *str, const char *s);
+extern void outBitmapset(struct StringInfoData *str,
+						 const struct Bitmapset *bms);
+
 /*
  * nodes/{readfuncs.c,read.c}
  */
 extern void *stringToNode(char *str);
+extern struct Bitmapset *readBitmapset(void);
 
 /*
  * nodes/copyfuncs.c
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index ae224cf..3a0b788 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -533,7 +533,7 @@ typedef struct ForeignScan
 	Scan		scan;
 	Oid			fs_server;		/* OID of foreign server */
 	List	   *fdw_exprs;		/* expressions that FDW may evaluate */
-	List	   *fdw_private;	/* private data for FDW */
+	Node	   *fdw_private;	/* private data for FDW */
 	List	   *fdw_scan_tlist; /* optional tlist describing scan tuple */
 	List	   *fdw_recheck_quals;	/* original quals not in scan.plan.qual */
 	Bitmapset  *fs_relids;		/* RTIs generated by this scan */
@@ -571,7 +571,7 @@ typedef struct CustomScan
 	uint32		flags;			/* mask of CUSTOMPATH_* flags, see relation.h */
 	List	   *custom_plans;	/* list of Plan nodes, if any */
 	List	   *custom_exprs;	/* expressions that custom code may evaluate */
-	List	   *custom_private; /* private data for custom code */
+	Node	   *custom_private; /* private data for custom code */
 	List	   *custom_scan_tlist;		/* optional tlist describing scan
 										 * tuple */
 	Bitmapset  *custom_relids;	/* RTIs generated by this scan */
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 96198ae..acdaec1 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -924,7 +924,7 @@ typedef struct ForeignPath
 {
 	Path		path;
 	Path	   *fdw_outerpath;
-	List	   *fdw_private;
+	Node	   *fdw_private;
 } ForeignPath;
 
 /*
@@ -968,7 +968,7 @@ typedef struct CustomPath
 	Path		path;
 	uint32		flags;			/* mask of CUSTOMPATH_* flags, see above */
 	List	   *custom_paths;	/* list of child Path nodes, if any */
-	List	   *custom_private;
+	Node	   *custom_private;
 	const CustomPathMethods *methods;
 } CustomPath;
 
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index f479981..65a86a2 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -89,7 +89,7 @@ extern ForeignPath *create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
 						List *pathkeys,
 						Relids required_outer,
 						Path *fdw_outerpath,
-						List *fdw_private);
+						Node *fdw_private);
 
 extern Relids calc_nestloop_required_outer(Path *outer_path, Path *inner_path);
 extern Relids calc_non_nestloop_required_outer(Path *outer_path, Path *inner_path);
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index eaa642b..7ad8ea2 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.h
@@ -53,7 +53,7 @@ extern Plan *create_plan(PlannerInfo *root, Path *best_path);
 extern SubqueryScan *make_subqueryscan(List *qptlist, List *qpqual,
 				  Index scanrelid, Plan *subplan);
 extern ForeignScan *make_foreignscan(List *qptlist, List *qpqual,
-				 Index scanrelid, List *fdw_exprs, List *fdw_private,
+				 Index scanrelid, List *fdw_exprs, Node *fdw_private,
 				 List *fdw_scan_tlist, List *fdw_recheck_quals,
 				 Plan *outer_plan);
 extern Append *make_append(List *appendplans, List *tlist);
