 doc/src/sgml/custom-scan.sgml | 42 ++++++++++++++++++++++++++++--------------
 src/backend/nodes/copyfuncs.c | 17 ++++++++++++++++-
 src/backend/nodes/outfuncs.c  |  5 +++++
 src/include/nodes/plannodes.h | 13 ++++++++-----
 4 files changed, 57 insertions(+), 20 deletions(-)

diff --git a/doc/src/sgml/custom-scan.sgml b/doc/src/sgml/custom-scan.sgml
index a229326..507586b 100644
--- a/doc/src/sgml/custom-scan.sgml
+++ b/doc/src/sgml/custom-scan.sgml
@@ -183,7 +183,9 @@ typedef struct CustomScan
     this scan is replacing a join, it will have only one member.
     <structfield>methods</> must point to a (usually statically allocated)
     object implementing the required custom scan methods, which are further
-    detailed below.
+    detailed below. Also note that this field shall be serialized using
+    a pair of library name and symbol name, thus, method variable has to
+    be resolvable by linker.
   </para>
 
   <para>
@@ -194,12 +196,11 @@ typedef struct CustomScan
   </para>
 
   <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</>.
+   Plan tree has to be copied using <function>copyObject</> and written
+   using <function>nodeToString</>. In case when custom scan provider defines
+   its own structure that embeds <structname>CustomScan</> on the head,
+   for better private field handling, it has to implement the relevant and
+   optional callbacks.
   </para>
 
   <sect2 id="custom-scan-plan-callbacks">
@@ -221,14 +222,27 @@ Node *(*CreateCustomScanState) (CustomScan *cscan);
 
    <para>
 <programlisting>
-void (*TextOutCustomScan) (StringInfo str,
-                           const CustomScan *node);
+void (*TextOutCustomScan) (StringInfo str, const CustomScan *cscan);
 </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.
+    Generate extra output when <function>nodeToString</> is invoked towards
+    the custom scan node. This callback is optional, however, custom scan
+    provider has to implement if it defines larger structure that embeds
+    <structname>CustomScan</> on the head, to save own private fields.
+    In this case, all the callback has to dump are private fields because
+    the core backend dumps knows fields in <structname>CustomScan</>.
+   </para>
+
+   <para>
+<programlisting>
+CustomScan *(*NodeCopyCustomScan) (const CustomScan *from);
+</programlisting>
+    Allocate a larger structure that embeds <structname>CustomScan</> then
+    copies its private fields from the original node.
+    This callback is optional, however, custom scan provider has to
+    implement if it defines its own structure instead of bare
+    <structname>CustomScan</>.
+    All this callback has to care about is its private fields. The known
+    fields in <structname>CustomScan</> shall be copied by the core backend.
    </para>
   </sect2>
  </sect1>
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index e19fee4..53c7d90 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -637,7 +637,22 @@ _copyForeignScan(const ForeignScan *from)
 static CustomScan *
 _copyCustomScan(const CustomScan *from)
 {
-	CustomScan *newnode = makeNode(CustomScan);
+	const CustomScanMethods *methods = from->methods;
+	CustomScan	   *newnode;
+
+	/*
+	 * In case when custom scan provider defines a larger structure that
+	 * deploys CustomScan at the head, only custom scan provider knows
+	 * exact size of the new node to be allocated, so we ask them to
+	 * allocate the new node and copy private fields we don't know.
+	 */
+	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 b39c772..4877ccf 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -599,6 +599,11 @@ _outCustomScan(StringInfo str, const CustomScan *node)
 	WRITE_BITMAPSET_FIELD(custom_relids);
 	appendStringInfoString(str, " :methods ");
 	_outToken(str, node->methods->CustomName);
+	/*
+	 * Custom scan provider can/must dump out private fields, if it defines
+	 * a larger structure to save its private fields. It also has to be
+	 * reconstructable using relevant TextReadCustomScan callback.
+	 */
 	if (node->methods->TextOutCustomScan)
 		node->methods->TextOutCustomScan(str, node);
 }
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 7a6a3fe..27ad64b 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -539,9 +539,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 tree can be copied and written with usual node functions.
+ * If custom scan provider defines a larger structure that embeds CustomScan
+ * at the head, it *must* provide relevant callbacks to support copyObject
+ * and nodeToString.
  * ----------------
  */
 struct CustomScan;
@@ -552,9 +553,11 @@ typedef struct CustomScanMethods
 
 	/* Create execution state (CustomScanState) from a CustomScan plan node */
 	Node	   *(*CreateCustomScanState) (struct CustomScan *cscan);
-	/* Optional: print custom_xxx fields in some special way */
+	/* Optional: output private field if structure is extended */
 	void		(*TextOutCustomScan) (StringInfo str,
-											  const struct CustomScan *node);
+									  const struct CustomScan *cscan);
+	/* Optional: duplicate CustomScan node if any additional private fields */
+	struct CustomScan *(*NodeCopyCustomScan) (const struct CustomScan *from);
 } CustomScanMethods;
 
 typedef struct CustomScan
