 doc/src/sgml/custom-scan.sgml | 70 +++++++++++++++++++++++++++++++++++++++----
 doc/src/sgml/fdwhandler.sgml  | 64 +++++++++++++++++++++++++++++++++++++++
 src/backend/nodes/copyfuncs.c | 33 ++++++++++++++++++--
 src/backend/nodes/outfuncs.c  | 15 ++++++++++
 src/backend/nodes/readfuncs.c | 38 +++++++++++++++++++++--
 src/include/foreign/fdwapi.h  | 10 +++++++
 src/include/nodes/plannodes.h | 15 ++++++++--
 7 files changed, 233 insertions(+), 12 deletions(-)

diff --git a/doc/src/sgml/custom-scan.sgml b/doc/src/sgml/custom-scan.sgml
index 5bba125..03f1d87 100644
--- a/doc/src/sgml/custom-scan.sgml
+++ b/doc/src/sgml/custom-scan.sgml
@@ -197,11 +197,31 @@ typedef struct CustomScan
 
   <para>
    Plan trees must be able to be duplicated using <function>copyObject</>,
-   so all the data stored within the <quote>custom</> fields must consist of
-   nodes that that function can handle.  Furthermore, custom scan providers
-   cannot substitute a larger structure that embeds
-   a <structname>CustomScan</> for the structure itself, as would be possible
-   for a <structname>CustomPath</> or <structname>CustomScanState</>.
+   serialized using <function>nodeToString</> and deserialized using
+   <function>stringToNode</>.
+   <structname>CustomScan</> can be located on head of larger structure
+   to keep private fields of custom scan provider.
+   Thus, if custom scan provider implements <function>TextOutCustomScan</>
+   to dump its private fields its own way, it also has responsibility of
+   <function>TextReadCustomScan</> to reconstruct the private structure.
+  </para>
+  <para>
+   Like any other fields, <structfield>methods</> pointer of the
+   <structname>CustomScanMethods</> also has to be restored, however,
+   nobody can ensure a particular shared library that contains the custom
+   scan provider is loaded exactly same address, for example, when
+   <structname>CustomScan</> node is deserialized on the background worker
+   under the control of <structname>Gather</>.
+
+   Thus, here is a few additional interface contract. The first one is
+   symbol name of the <structname>CustomScanMethods</> table has to be
+   visible to linker; that means the variable should not be declared as
+   static, because <function>stringToNode</> reconstructs the
+   <structfield>methods</> pointer using a pair of library and symbol
+   name. The second one is, <structname>CustomScanMethods</> table also
+   has to be initialized using <function>INIT_CUSTOM_SCAN_METHODS</>
+   macro on <function>_PG_init</>, to assign exact library and symbol
+   name to be referenced.
   </para>
 
   <sect2 id="custom-scan-plan-callbacks">
@@ -220,6 +240,46 @@ Node *(*CreateCustomScanState) (CustomScan *cscan);
     the <function>BeginCustomScan</> callback will be invoked to give the
     custom scan provider a chance to do whatever else is needed.
    </para>
+
+   <para>
+<programlisting>
+void (*TextOutCustomScan) (StringInfo str,
+                           const CustomScan *node);
+</programlisting>
+    Generate additional output when <function>nodeToString</> is invoked on
+    this custom plan node.  This callback is optional.  Since
+    <function>nodeToString</> will automatically dump all fields in the
+    structure, including the substructure of the <quote>custom</> fields,
+    there is usually not much need for this callback.
+   </para>
+
+   <para>
+<programlisting>
+CustomScan *(*TextReadCustomScan)(void);
+</programlisting>
+    Allocate a <structname>CustomScan</> or larger structure embedding
+    <structname>CustomScan</>, and read its private fields generated by
+    <function>TextOutCustomScan</> callback.
+    This callback is optional, however, must be implemented if custom
+    scan provider makes additional output for support of plan-tree
+    serialization and deserialization.
+    This callback shall be invoked under <function>stringToNode</>
+    context, so <function>pg_strtok</> will give the next token.
+   </para>
+
+   <para>
+<programlisting>
+CustomScan *(*NodeCopyCustomScan)(const struct CustomScan *from);
+</programlisting>
+    Allocate a <structname>CustomScan</> or larger structure embedding
+    <structname>CustomScan</>, and copies its private fields from the
+    original node.
+    This callback is optional, however, must be implemented if custom
+    scan provider extends <structname>CustomScan</> structure to save
+    its private fields for safety of <function>copyObject</>.
+    The common fields are duplicated by the backend, so all extension
+    needs to focus on is its private fields, if exists.
+   </para>
   </sect2>
  </sect1>
 
diff --git a/doc/src/sgml/fdwhandler.sgml b/doc/src/sgml/fdwhandler.sgml
index 1533a6b..bbe798c 100644
--- a/doc/src/sgml/fdwhandler.sgml
+++ b/doc/src/sgml/fdwhandler.sgml
@@ -195,6 +195,70 @@ GetForeignPlan (PlannerInfo *root,
     <para>
 <programlisting>
 void
+TextOutForeignScan(StringInfo str, const ForeignScan *node);
+</programlisting>
+     Write out private fields if FDW-driver defines a larger structure that
+     contains a <structname>ForeignScan</> plan node, and wants to save its
+     private data on the extra area rather than <structfield>fdw_private</>.
+    </para>
+    <para>
+     The core backend already wrote out the known fields of
+     <structname>ForeignScan</> on the supplied <structname>StringInfo</>,
+     then, this callback enables to append some extra private information.
+    </para>
+    <para>
+     This callback is optional, however, it is required to define the
+     relevant <function>TextReadForeignScan</> callback also, to match
+     serialization with deserialization.
+    </para>
+
+    <para>
+<programlisting>
+ForeignScan *
+TextReadForeignScan(const ForeignScan *node);
+</programlisting>
+     Allocates a node then read in private fields if FDW-driver defines
+     a larger structure that contains a <structname>ForeignScan</> plan
+     node, and wants to save its private data on the extra area rather
+     than <structfield>fdw_private</>.
+    </para>
+    <para>
+     The core backend already read in the known fields of
+     <structname>ForeignScan</> from input stream; we can pick up tokens
+     using <function>pg_strtok</> because this callback shall be invoked
+     under the <function>stringToNode</> context.
+    </para>
+    <para>
+     This callback is optional, however, it is required to define the
+     relevant <function>TextOutForeignScan</> callback also, to match
+     serialization with deserialization.
+    </para>
+
+    <para>
+<programlisting>
+ForeignScan *
+NodeCopyForeignScan(const ForeignScan *from);
+</programlisting>
+     Allocates a node object then duplicate private fields if FDW-driver
+     defines a larger structure that contains a <structname>ForeignScan</>
+     plan node, and wants to save its private data on the extra area rather
+     than <structfield>fdw_private</>.
+    </para>
+    <para>
+     The core backend will copy the known fields of <structname>ForeignScan</>,
+     thus, all this function needs to do is allocation of the own larger
+     structure and fill up the private fields.
+    </para>
+    <para>
+     This callback is optional, but should be implemented if FDW-driver
+     wants to save its private fields on the extra field in a larger
+     structure, like <function>TextOutForeignScan</> or
+     <function>TextReadForeignScan</>.
+    </para>
+
+    <para>
+<programlisting>
+void
 BeginForeignScan (ForeignScanState *node,
                   int eflags);
 </programlisting>
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 26264cb..9eb1fd6 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -22,6 +22,7 @@
 
 #include "postgres.h"
 
+#include "foreign/fdwapi.h"
 #include "miscadmin.h"
 #include "nodes/plannodes.h"
 #include "nodes/relation.h"
@@ -635,7 +636,21 @@ _copyWorkTableScan(const WorkTableScan *from)
 static ForeignScan *
 _copyForeignScan(const ForeignScan *from)
 {
-	ForeignScan *newnode = makeNode(ForeignScan);
+	FdwRoutine	*fdwroutine = GetFdwRoutineByServerId(from->fs_server);
+	ForeignScan *newnode;
+
+	/*
+	 * If FDW driver extends ForeignScan node to save extra private fields,
+	 * it is role of the FDW driver to allocate a new node that includes
+	 * the private fields.
+	 */
+	if (!fdwroutine->NodeCopyForeignScan)
+		newnode = makeNode(ForeignScan);
+	else
+	{
+		newnode = fdwroutine->NodeCopyForeignScan(from);
+		Assert(IsA(newnode, ForeignScan));
+	}
 
 	/*
 	 * copy node superclass fields
@@ -662,7 +677,21 @@ _copyForeignScan(const ForeignScan *from)
 static CustomScan *
 _copyCustomScan(const CustomScan *from)
 {
-	CustomScan *newnode = makeNode(CustomScan);
+	const CustomScanMethods *methods = from->methods;
+	CustomScan *newnode;
+
+	/*
+	 * If custom-scan provider extends CustomScan node to save its private
+	 * data, it is role of the provider to allocate a new node that includes
+	 * the private fields.
+	 */
+	if (!methods->NodeCopyCustomScan)
+		newnode = makeNode(CustomScan);
+	else
+	{
+		newnode = methods->NodeCopyCustomScan(from);
+		Assert(IsA(newnode, CustomScan));
+	}
 
 	/*
 	 * copy node superclass fields
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 012c14b..937dc95 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -25,6 +25,7 @@
 
 #include <ctype.h>
 
+#include "foreign/fdwapi.h"
 #include "lib/stringinfo.h"
 #include "nodes/plannodes.h"
 #include "nodes/relation.h"
@@ -587,6 +588,8 @@ _outWorkTableScan(StringInfo str, const WorkTableScan *node)
 static void
 _outForeignScan(StringInfo str, const ForeignScan *node)
 {
+	FdwRoutine *routines = GetFdwRoutineByServerId(node->fs_server);
+
 	WRITE_NODE_TYPE("FOREIGNSCAN");
 
 	_outScanInfo(str, (const Scan *) node);
@@ -598,6 +601,14 @@ _outForeignScan(StringInfo str, const ForeignScan *node)
 	WRITE_NODE_FIELD(fdw_recheck_quals);
 	WRITE_BITMAPSET_FIELD(fs_relids);
 	WRITE_BOOL_FIELD(fsSystemCol);
+
+	/*
+	 * Optional: it allows FDW driver to dump extra private field, if supplied 
+	 * ForeignScan node is located within a larger structure that contains
+	 * various private fields of individual FDW.
+	 */
+	if (routines->TextOutForeignScan)
+		routines->TextOutForeignScan(str, node);
 }
 
 static void
@@ -618,6 +629,10 @@ _outCustomScan(StringInfo str, const CustomScan *node)
 	_outToken(str, node->methods->LibraryName);
 	appendStringInfoChar(str, ' ');
 	_outToken(str, node->methods->SymbolName);
+
+	/* Also, private fields if any */
+	if (node->methods->TextOutCustomScan)
+		node->methods->TextOutCustomScan(str, node);
 }
 
 static void
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 222e2ed..f9a19d8 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -29,6 +29,7 @@
 #include <math.h>
 
 #include "fmgr.h"
+#include "foreign/fdwapi.h"
 #include "nodes/parsenodes.h"
 #include "nodes/plannodes.h"
 #include "nodes/readfuncs.h"
@@ -1792,8 +1793,12 @@ _readWorkTableScan(void)
 static ForeignScan *
 _readForeignScan(void)
 {
-	READ_LOCALS(ForeignScan);
+	READ_TEMP_LOCALS();
+	ForeignScan		local_temp;
+	ForeignScan	   *local_node;
+	FdwRoutine	   *fdwroutine;
 
+	NodeSetTag(local_node, T_ForeignScan);
 	ReadCommonScan(&local_node->scan);
 
 	READ_OID_FIELD(fs_server);
@@ -1804,6 +1809,17 @@ _readForeignScan(void)
 	READ_BITMAPSET_FIELD(fs_relids);
 	READ_BOOL_FIELD(fsSystemCol);
 
+	fdwroutine = GetFdwRoutineByServerId(local_node->fs_server);
+	if (!fdwroutine->TextReadForeignScan)
+		local_node = makeNode(ForeignScan);
+	else
+	{
+		local_node = fdwroutine->TextReadForeignScan(&local_temp);
+		Assert(IsA(local_node, ForeignScan));
+	}
+	/* move the common fields of ForeignScan */
+	memcpy(local_node, &local_temp, sizeof(ForeignScan));
+
 	READ_DONE();
 }
 
@@ -1813,11 +1829,14 @@ _readForeignScan(void)
 static CustomScan *
 _readCustomScan(void)
 {
-	READ_LOCALS(CustomScan);
+	READ_TEMP_LOCALS();
+	CustomScan	local_temp;
+	CustomScan *local_node = &local_temp;
 	char	   *library_name;
 	char	   *symbol_name;
 	const CustomScanMethods *methods;
 
+	NodeSetTag(local_node, T_CustomScan);
 	ReadCommonScan(&local_node->scan);
 
 	READ_UINT_FIELD(flags);
@@ -1842,6 +1861,21 @@ _readCustomScan(void)
 		   strcmp(methods->SymbolName, symbol_name) == 0);
 	local_node->methods = methods;
 
+	/*
+	 * Then, read private data fields and reconstruct a struct that
+	 * contains CustomScan on its head, if any. Elsewhere, construct
+	 * usual CustomScan node.
+	 */
+	if (!methods->TextReadCustomScan)
+		local_node = makeNode(CustomScan);
+	else
+	{
+		local_node = methods->TextReadCustomScan(&local_temp);
+		Assert(IsA(local_node, CustomScan));
+	}
+	/* move the common field of CustomScan */
+	memcpy(local_node, &local_temp, sizeof(CustomScan));
+
 	READ_DONE();
 }
 
diff --git a/src/include/foreign/fdwapi.h b/src/include/foreign/fdwapi.h
index 69b48b4..224d44c 100644
--- a/src/include/foreign/fdwapi.h
+++ b/src/include/foreign/fdwapi.h
@@ -38,6 +38,13 @@ typedef ForeignScan *(*GetForeignPlan_function) (PlannerInfo *root,
 															 List *tlist,
 														 List *scan_clauses);
 
+typedef void (*TextOutForeignScan_function) (StringInfo str,
+											 const ForeignScan *node);
+
+typedef ForeignScan *(*TextReadForeignScan_function) (const ForeignScan *node);
+
+typedef ForeignScan *(*NodeCopyForeignScan_function) (const ForeignScan *from);
+
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,
 													   int eflags);
 
@@ -136,6 +143,9 @@ typedef struct FdwRoutine
 	GetForeignRelSize_function GetForeignRelSize;
 	GetForeignPaths_function GetForeignPaths;
 	GetForeignPlan_function GetForeignPlan;
+	TextOutForeignScan_function TextOutForeignScan;
+	TextReadForeignScan_function TextReadForeignScan;
+	NodeCopyForeignScan_function NodeCopyForeignScan;
 	BeginForeignScan_function BeginForeignScan;
 	IterateForeignScan_function IterateForeignScan;
 	ReScanForeignScan_function ReScanForeignScan;
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 37086c6..18639e6 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -547,9 +547,10 @@ typedef struct ForeignScan
  * custom_private, custom_scan_tlist, and custom_relids fields.  The
  * convention of setting scan.scanrelid to zero for joins applies as well.
  *
- * Note that since Plan trees can be copied, custom scan providers *must*
- * fit all plan data they need into those fields; embedding CustomScan in
- * a larger struct will not work.
+ * Note that Plan trees can be copied, displayed and read using node
+ * functions, thus, custom scan provider *must* support relevant callbacks
+ * if provider wants to embed CustomScan in a larger struct to save private
+ * fields.
  * ----------------
  */
 struct CustomScan;
@@ -562,6 +563,14 @@ typedef struct CustomScanMethods
 
 	/* Create execution state (CustomScanState) from a CustomScan plan node */
 	Node	   *(*CreateCustomScanState) (struct CustomScan *cscan);
+
+	/* Optional: print private fields in some special way */
+	void		(*TextOutCustomScan) (StringInfo str,
+									  const struct CustomScan *node);
+	/* Optional: read the private fields printed in special way */
+	struct CustomScan *(*TextReadCustomScan)(const struct CustomScan *node);
+	/* Optional: copy the original including private fields */
+	struct CustomScan *(*NodeCopyCustomScan)(const struct CustomScan *from);
 } CustomScanMethods;
 
 typedef struct CustomScan
