CustomScan support on readfuncs.c

Started by Kouhei Kaigaiover 10 years ago21 messages
#1Kouhei Kaigai
kaigai@ak.jp.nec.com
1 attachment(s)

Hi,

I tried to define two additional callbacks to support CustomScan
on readfuncs.c.

First of all, we need to pay attention how to treat output of
TextOutCustomScan when additional text output is generated.
Only custom-scan provider knows what shall be displayed, so
all we can do is invoke a new callback: TextReadCustomScan().
Because private fields shall be displayed next to the common
field of CustomScan, this callback is invoked once pg_strtok
pointer reached to the last field of CustomScan. Then, custom
scan provider allocates CustomScan or a structure embedding
CustomScan; only CSP knows exact size to be allocated.
It can fetch some tokens using pg_strtok and reconstruct its
private fields, but no need to restore the common field because
it shall be done by _readCustomScan.
If no callbacks are defined, _readCustomScan allocates
a CustomScan object and read only known fields.

Then, let's look back a bit. Next issue is how to reproduce
the "methods" pointer from the text representation.
I try to lookup the methods table using a pair of library
and symbol name; probably, it is a straightforward way.
The "methods" field is put earlier than all private fields
generated by TextOutCustomScan, so it should be reconstructable
prior to TextReadCustomScan.
To support this feature, I had to add an interface contract
that requires extensions to put library and symbol name on
CustomScanMethods table.
Although INIT_CUSTOM_SCAN_METHODS() macro can set up these
fields, author of extension needs to pay attention.

In addition to these enhancement, a new NodeCopyCustomScan
callback eliminates a restriction; custom-scan provider
cannot define its own structure that embeds CustomScan.
Only CSP knows exact size of the structure, this callback
is intended to allocate a new one and copy the private fields,
but no need to copy the common fields.

These three callbacks (one existing, two new) will make
CustomScan node copyObject, nodeToString and stringToNode
aware.

I also noticed that some static functions are valuable for
extensions, to avoid reinvention of same routines.
How about to expose these functions?
- _outToken
- _outBitmapset
- nullable_string
- _readBitmapset

The attached patch is conceptual, just compilable but not
tested yet. I'll try to make a test case soon, however,
it makes sense to get feedbacks earlier even if it is
based on the concept design.

Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>

Attachments:

custom-scan-on-readfuncs.v1.patchapplication/octet-stream; name=custom-scan-on-readfuncs.v1.patchDownload
 doc/src/sgml/custom-scan.sgml  | 53 +++++++++++++++++++++++++++++++++-----
 src/backend/nodes/copyfuncs.c  | 16 +++++++++++-
 src/backend/nodes/outfuncs.c   |  8 +++++-
 src/backend/nodes/readfuncs.c  | 58 ++++++++++++++++++++++++++++++++++++++++++
 src/backend/utils/fmgr/dfmgr.c | 21 +++++++++++++++
 src/include/fmgr.h             |  1 +
 src/include/nodes/plannodes.h  | 23 ++++++++++++++---
 7 files changed, 168 insertions(+), 12 deletions(-)

diff --git a/doc/src/sgml/custom-scan.sgml b/doc/src/sgml/custom-scan.sgml
index a229326..867b47e 100644
--- a/doc/src/sgml/custom-scan.sgml
+++ b/doc/src/sgml/custom-scan.sgml
@@ -195,11 +195,22 @@ 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</>, so so all the data stored within
+   the <quote>custom</> fields must consist of nodes that that function
+   can handle.
+   Furthermore, custom scan providers have to implement <quote>optional</>
+   callbacks if it defines substitute a larger structure that embeds
+   a <structname>CustomScan</> for the structure itself.
+  </para>
+
+  <para>
+   Also note that symbol name of the <structname>CustomScanMethods</> table
+   has to be visible to linker, because <function>stringToNode</>
+   reconstructs the <structfield>methods</> pointer using a pair of library
+   and symbol name. <function>INIT_CUSTOM_SCAN_METHODS</> initializes the
+   relevant fields, and expects custom-scan provider uses this macro on
+   <function>_PG_init</> timing.
   </para>
 
   <sect2 id="custom-scan-plan-callbacks">
@@ -228,8 +239,38 @@ void (*TextOutCustomScan) (StringInfo str,
     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.
+    there is usually not much need for this callback, unless custom-scan
+    provider does not embed its 
+   </para>
+
+   <para>
+<programlisting>
+struct 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>
+struct 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/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 62355aa..05d23aa 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -637,7 +637,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 c91273c..7ed8118 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -599,8 +599,14 @@ _outCustomScan(StringInfo str, const CustomScan *node)
 	WRITE_NODE_FIELD(custom_private);
 	WRITE_NODE_FIELD(custom_scan_tlist);
 	WRITE_BITMAPSET_FIELD(custom_relids);
+
+	/* Dump library and symbol name instead of raw pointer */
 	appendStringInfoString(str, " :methods ");
-	_outToken(str, node->methods->CustomName);
+	_outToken(str, node->methods->methods_library_name);
+	appendStringInfoChar(str, ' ');
+	_outToken(str, node->methods->methods_symbol_name);
+
+	/* Also, private fields if any */
 	if (node->methods->TextOutCustomScan)
 		node->methods->TextOutCustomScan(str, node);
 }
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index ef88209..81449a2 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -28,6 +28,7 @@
 
 #include <math.h>
 
+#include "fmgr.h"
 #include "nodes/parsenodes.h"
 #include "nodes/plannodes.h"
 #include "nodes/readfuncs.h"
@@ -1849,6 +1850,61 @@ _readForeignScan(void)
 }
 
 /*
+ * _readCustomScan
+ */
+static CustomScan *
+_readCustomScan(void)
+{
+	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);
+	READ_NODE_FIELD(custom_plans);
+	READ_NODE_FIELD(custom_exprs);
+	READ_NODE_FIELD(custom_private);
+	READ_NODE_FIELD(custom_scan_tlist);
+	READ_BITMAPSET_FIELD(custom_relids);
+
+	/*
+	 * Reconstruction of methods using library and symbol name
+	 */
+	token = pg_strtok(&length);		/* skip methods: */
+	token = pg_strtok(&length);		/* methods_library_name */
+	library_name = nullable_string(token, length);
+	token = pg_strtok(&length);		/* methods_symbol_name */
+	symbol_name = nullable_string(token, length);
+
+	methods = (const CustomScanMethods *)
+		load_external_function(library_name, symbol_name, true, NULL);
+	Assert(strcmp(methods->methods_library_name, library_name) == 0 &&
+		   strcmp(methods->methods_symbol_name, symbol_name) == 0);
+
+	/*
+	 * Then, read private fields if any. Elsewhere, just construct
+	 * a usual CustomScan node.
+	 */
+	if (!methods->TextReadCustomScan)
+		local_node = makeNode(CustomScan);
+	else
+	{
+		local_node = methods->TextReadCustomScan();
+		Assert(IsA(local_node, CustomScan));
+	}
+	/* move the common field of CustomScan */
+	memcpy(local_node, &local_temp, offsetof(CustomScan, methods));
+	local_node->methods = methods;
+
+	READ_DONE();
+}
+
+/*
  * ReadCommonJoin
  *	Assign the basic stuff of all nodes that inherit from Join
  */
@@ -2388,6 +2444,8 @@ parseNodeString(void)
 		return_value = _readWorkTableScan();
 	else if (MATCH("FOREIGNSCAN", 11))
 		return_value = _readForeignScan();
+	else if (MATCH("CUSTOMSCAN", 10))
+		return_value = _readCustomScan();
 	else if (MATCH("JOIN", 4))
 		return_value = _readJoin();
 	else if (MATCH("NESTLOOP", 8))
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index cd3db87..f343cfc 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -80,6 +80,8 @@ static char *find_in_dynamic_libpath(const char *basename);
 /* Magic structure that module needs to match to be accepted */
 static const Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA;
 
+/* Library filename on which PG_init() is currently processed */
+static const *current_library_filename = NULL;
 
 /*
  * Load the specified dynamic-link library file, and look for a function
@@ -277,8 +279,16 @@ internal_load_library(const char *libname)
 		 */
 		PG_init = (PG_init_t) pg_dlsym(file_scanner->handle, "_PG_init");
 		if (PG_init)
+		{
+			const char *saved_library_name = current_library_filename;
+
+			current_library_filename = file_scanner->filename;
+
 			(*PG_init) ();
 
+			current_library_filename = saved_library_name;
+		}
+
 		/* OK to link it into list */
 		if (file_list == NULL)
 			file_list = file_scanner;
@@ -291,6 +301,17 @@ internal_load_library(const char *libname)
 }
 
 /*
+ * Inform extensions their own filename, at the time of PG_init()
+ */
+const char *
+get_current_library_filename(void)
+{
+	if (!current_library_filename)
+		elog(ERROR, "Not in the context of _PG_init");
+	return current_library_filename;
+}
+
+/*
  * Report a suitable error for an incompatible magic block.
  */
 static void
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index 808d142..116ca4d 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -645,6 +645,7 @@ extern void **find_rendezvous_variable(const char *varName);
 extern Size EstimateLibraryStateSpace(void);
 extern void SerializeLibraryState(Size maxsize, char *start_address);
 extern void RestoreLibraryState(char *start_address);
+extern const char *get_current_library_filename(void);
 
 /*
  * Support for aggregate functions
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index cc259f1..4c64b51 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -535,24 +535,39 @@ 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;
 
 typedef struct CustomScanMethods
 {
+	/* to be set by INIT_CUSTOM_SCAN_METHODS */
 	const char *CustomName;
+	const char *methods_library_name;
+	const char *methods_symbol_name;
 
 	/* Create execution state (CustomScanState) from a CustomScan plan node */
 	Node	   *(*CreateCustomScanState) (struct CustomScan *cscan);
-	/* Optional: print custom_xxx fields in some special way */
+	/* Optional: print private fields in some special way */
 	void		(*TextOutCustomScan) (StringInfo str,
 											  const struct CustomScan *node);
+	/* Optional: read and construct the private fields above */
+	struct CustomScan *(*TextReadCustomScan)(void);
+	/* Optional: copy the original including private fields */
+	struct CustomScan *(*NodeCopyCustomScan)(const struct CustomScan *from);
 } CustomScanMethods;
 
+#define INIT_CUSTOM_SCAN_METHODS(methods, name)							\
+	do {																\
+		methods.CustomName = (name);									\
+		methods.methods_library_name = get_current_library_filename();	\
+		methods.methods_symbol_name = #methods;							\
+	} while(0)
+
 typedef struct CustomScan
 {
 	Scan		scan;
#2Amit Kapila
amit.kapila16@gmail.com
In reply to: Kouhei Kaigai (#1)
Re: CustomScan support on readfuncs.c

On Fri, Sep 25, 2015 at 6:49 AM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

Hi,

I tried to define two additional callbacks to support CustomScan
on readfuncs.c.

First of all, we need to pay attention how to treat output of
TextOutCustomScan when additional text output is generated.
Only custom-scan provider knows what shall be displayed, so
all we can do is invoke a new callback: TextReadCustomScan().
Because private fields shall be displayed next to the common
field of CustomScan, this callback is invoked once pg_strtok
pointer reached to the last field of CustomScan. Then, custom
scan provider allocates CustomScan or a structure embedding
CustomScan; only CSP knows exact size to be allocated.
It can fetch some tokens using pg_strtok and reconstruct its
private fields, but no need to restore the common field because
it shall be done by _readCustomScan.

So will the specification of TextReadCustomScan() and
TextOutCustomScan() ensures that they don't access the common
fields (like custom_private or others) of CustomScan?
If they change/overwrite them in some way, then I think _readCustomScan()
won't work because it doesn't take into account that common fields could
have been updated by TextReadCustomScan().

With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#3Kouhei Kaigai
kaigai@ak.jp.nec.com
In reply to: Amit Kapila (#2)
Re: CustomScan support on readfuncs.c

On Fri, Sep 25, 2015 at 6:49 AM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

Hi,

I tried to define two additional callbacks to support CustomScan
on readfuncs.c.

First of all, we need to pay attention how to treat output of
TextOutCustomScan when additional text output is generated.
Only custom-scan provider knows what shall be displayed, so
all we can do is invoke a new callback: TextReadCustomScan().
Because private fields shall be displayed next to the common
field of CustomScan, this callback is invoked once pg_strtok
pointer reached to the last field of CustomScan. Then, custom
scan provider allocates CustomScan or a structure embedding
CustomScan; only CSP knows exact size to be allocated.
It can fetch some tokens using pg_strtok and reconstruct its
private fields, but no need to restore the common field because
it shall be done by _readCustomScan.

So will the specification of TextReadCustomScan() and
TextOutCustomScan() ensures that they don't access the common
fields (like custom_private or others) of CustomScan?
If they change/overwrite them in some way, then I think _readCustomScan()
won't work because it doesn't take into account that common fields could
have been updated by TextReadCustomScan().

Yes. Even if callback of TextReadCustomScan() wants to change or
overwrite, then it is eventually overwritten by the core.
If we allow custom-scan provide to adjust common fields of CustomScan,
it is a change of interface role because the relevant callbacks (TextOut,
TextRead and NodeCopy) are expected to perform faithfully according to
the supplied node.
If extension really wants to adjust plan-node, probably, something like
plan_tree_mutator() should be the place to do.

Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Robert Haas
robertmhaas@gmail.com
In reply to: Kouhei Kaigai (#1)
Re: CustomScan support on readfuncs.c

On Thu, Sep 24, 2015 at 9:19 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

Then, let's look back a bit. Next issue is how to reproduce
the "methods" pointer from the text representation.
I try to lookup the methods table using a pair of library
and symbol name; probably, it is a straightforward way.
The "methods" field is put earlier than all private fields
generated by TextOutCustomScan, so it should be reconstructable
prior to TextReadCustomScan.
To support this feature, I had to add an interface contract
that requires extensions to put library and symbol name on
CustomScanMethods table.
Although INIT_CUSTOM_SCAN_METHODS() macro can set up these
fields, author of extension needs to pay attention.

In addition to these enhancement, a new NodeCopyCustomScan
callback eliminates a restriction; custom-scan provider
cannot define its own structure that embeds CustomScan.
Only CSP knows exact size of the structure, this callback
is intended to allocate a new one and copy the private fields,
but no need to copy the common fields.

These three callbacks (one existing, two new) will make
CustomScan node copyObject, nodeToString and stringToNode
aware.

Instead of doing this:

+    /* Dump library and symbol name instead of raw pointer */
     appendStringInfoString(str, " :methods ");
-    _outToken(str, node->methods->CustomName);
+    _outToken(str, node->methods->methods_library_name);
+    appendStringInfoChar(str, ' ');
+    _outToken(str, node->methods->methods_symbol_name);

Suppose we just make library_name and symbol_name fields in the node
itself, that are dumped and loaded like any others.

Would that be better?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#5Kouhei Kaigai
kaigai@ak.jp.nec.com
In reply to: Robert Haas (#4)
Re: CustomScan support on readfuncs.c

-----Original Message-----
From: pgsql-hackers-owner@postgresql.org
[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Robert Haas
Sent: Tuesday, September 29, 2015 12:08 AM
To: Kaigai Kouhei(海外 浩平)
Cc: Amit Kapila; Andres Freund; pgsql-hackers
Subject: Re: [HACKERS] CustomScan support on readfuncs.c

On Thu, Sep 24, 2015 at 9:19 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

Then, let's look back a bit. Next issue is how to reproduce
the "methods" pointer from the text representation.
I try to lookup the methods table using a pair of library
and symbol name; probably, it is a straightforward way.
The "methods" field is put earlier than all private fields
generated by TextOutCustomScan, so it should be reconstructable
prior to TextReadCustomScan.
To support this feature, I had to add an interface contract
that requires extensions to put library and symbol name on
CustomScanMethods table.
Although INIT_CUSTOM_SCAN_METHODS() macro can set up these
fields, author of extension needs to pay attention.

In addition to these enhancement, a new NodeCopyCustomScan
callback eliminates a restriction; custom-scan provider
cannot define its own structure that embeds CustomScan.
Only CSP knows exact size of the structure, this callback
is intended to allocate a new one and copy the private fields,
but no need to copy the common fields.

These three callbacks (one existing, two new) will make
CustomScan node copyObject, nodeToString and stringToNode
aware.

Instead of doing this:

+    /* Dump library and symbol name instead of raw pointer */
appendStringInfoString(str, " :methods ");
-    _outToken(str, node->methods->CustomName);
+    _outToken(str, node->methods->methods_library_name);
+    appendStringInfoChar(str, ' ');
+    _outToken(str, node->methods->methods_symbol_name);

Suppose we just make library_name and symbol_name fields in the node
itself, that are dumped and loaded like any others.

Would that be better?

I have no preference here.

Even if we dump library_name/symbol_name as if field in CustomScan,
not CustomScanMethods, in a similar way, we cannot use WRITE_STRING_FIELD
here, because its 'fldname' assumes these members are direct field of
CustomScan.

/* Write a character-string (possibly NULL) field */
#define WRITE_STRING_FIELD(fldname) \
(appendStringInfo(str, " :" CppAsString(fldname) " "), \
_outToken(str, node->fldname))

One other question I have. Do we have a portable way to lookup
a pair of library and symbol by address?
Glibc has dladdr() functions that returns these information,
however, manpage warned it is not defined by POSIX.
If we would be able to have any portable way, it may make the
interface simpler.

Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Robert Haas
robertmhaas@gmail.com
In reply to: Kouhei Kaigai (#5)
Re: CustomScan support on readfuncs.c

On Mon, Sep 28, 2015 at 8:31 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

Instead of doing this:

+    /* Dump library and symbol name instead of raw pointer */
appendStringInfoString(str, " :methods ");
-    _outToken(str, node->methods->CustomName);
+    _outToken(str, node->methods->methods_library_name);
+    appendStringInfoChar(str, ' ');
+    _outToken(str, node->methods->methods_symbol_name);

Suppose we just make library_name and symbol_name fields in the node
itself, that are dumped and loaded like any others.

Would that be better?

I have no preference here.

Even if we dump library_name/symbol_name as if field in CustomScan,
not CustomScanMethods, in a similar way, we cannot use WRITE_STRING_FIELD
here, because its 'fldname' assumes these members are direct field of
CustomScan.

/* Write a character-string (possibly NULL) field */
#define WRITE_STRING_FIELD(fldname) \
(appendStringInfo(str, " :" CppAsString(fldname) " "), \
_outToken(str, node->fldname))

Well that's exactly what I was suggesting: making them a direct field
of CustomScan.

One other question I have. Do we have a portable way to lookup
a pair of library and symbol by address?
Glibc has dladdr() functions that returns these information,
however, manpage warned it is not defined by POSIX.
If we would be able to have any portable way, it may make the
interface simpler.

Yes: load_external_function.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#7Kouhei Kaigai
kaigai@ak.jp.nec.com
In reply to: Robert Haas (#6)
Re: CustomScan support on readfuncs.c

On Mon, Sep 28, 2015 at 8:31 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

Instead of doing this:

+    /* Dump library and symbol name instead of raw pointer */
appendStringInfoString(str, " :methods ");
-    _outToken(str, node->methods->CustomName);
+    _outToken(str, node->methods->methods_library_name);
+    appendStringInfoChar(str, ' ');
+    _outToken(str, node->methods->methods_symbol_name);

Suppose we just make library_name and symbol_name fields in the node
itself, that are dumped and loaded like any others.

Would that be better?

I have no preference here.

Even if we dump library_name/symbol_name as if field in CustomScan,
not CustomScanMethods, in a similar way, we cannot use WRITE_STRING_FIELD
here, because its 'fldname' assumes these members are direct field of
CustomScan.

/* Write a character-string (possibly NULL) field */
#define WRITE_STRING_FIELD(fldname) \
(appendStringInfo(str, " :" CppAsString(fldname) " "), \
_outToken(str, node->fldname))

Well that's exactly what I was suggesting: making them a direct field
of CustomScan.

Let me confirm. Are you suggesting to have library_name/symbol_name
in CustomScan, not CustomScanMethods?
I prefer these fields are in CustomScanMethods because we don't need
to setup them again once PG_init set up these symbols. CustomScan has
to be created every time when it is chosen by planner.

One other question I have. Do we have a portable way to lookup
a pair of library and symbol by address?
Glibc has dladdr() functions that returns these information,
however, manpage warned it is not defined by POSIX.
If we would be able to have any portable way, it may make the
interface simpler.

Yes: load_external_function.

It looks up an address by a pair of library and symbol name....
What I'm looking for is a portable function that looks up a pair
of library and symbol name by an address, like dladdr() of glibc.
I don't know whether other *nix or windows have these infrastructure.

Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#8Robert Haas
robertmhaas@gmail.com
In reply to: Kouhei Kaigai (#7)
Re: CustomScan support on readfuncs.c

On Tue, Sep 29, 2015 at 6:19 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

On Mon, Sep 28, 2015 at 8:31 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

Instead of doing this:

+    /* Dump library and symbol name instead of raw pointer */
appendStringInfoString(str, " :methods ");
-    _outToken(str, node->methods->CustomName);
+    _outToken(str, node->methods->methods_library_name);
+    appendStringInfoChar(str, ' ');
+    _outToken(str, node->methods->methods_symbol_name);

Suppose we just make library_name and symbol_name fields in the node
itself, that are dumped and loaded like any others.

Would that be better?

I have no preference here.

Even if we dump library_name/symbol_name as if field in CustomScan,
not CustomScanMethods, in a similar way, we cannot use WRITE_STRING_FIELD
here, because its 'fldname' assumes these members are direct field of
CustomScan.

/* Write a character-string (possibly NULL) field */
#define WRITE_STRING_FIELD(fldname) \
(appendStringInfo(str, " :" CppAsString(fldname) " "), \
_outToken(str, node->fldname))

Well that's exactly what I was suggesting: making them a direct field
of CustomScan.

Let me confirm. Are you suggesting to have library_name/symbol_name
in CustomScan, not CustomScanMethods?
I prefer these fields are in CustomScanMethods because we don't need
to setup them again once PG_init set up these symbols. CustomScan has
to be created every time when it is chosen by planner.

True. But that doesn't cost much. I'm not sure it's better, so if
you don't like it, don't worry about it.

One other question I have. Do we have a portable way to lookup
a pair of library and symbol by address?
Glibc has dladdr() functions that returns these information,
however, manpage warned it is not defined by POSIX.
If we would be able to have any portable way, it may make the
interface simpler.

Yes: load_external_function.

It looks up an address by a pair of library and symbol name....
What I'm looking for is a portable function that looks up a pair
of library and symbol name by an address, like dladdr() of glibc.
I don't know whether other *nix or windows have these infrastructure.

No, that doesn't exist, and the chances of us trying add that
infrastructure for this feature are nil.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Kouhei Kaigai
kaigai@ak.jp.nec.com
In reply to: Robert Haas (#8)
Re: CustomScan support on readfuncs.c

-----Original Message-----
From: Robert Haas [mailto:robertmhaas@gmail.com]
Sent: Saturday, October 03, 2015 5:44 AM
To: Kaigai Kouhei(海外 浩平)
Cc: Amit Kapila; Andres Freund; pgsql-hackers
Subject: ##freemail## Re: [HACKERS] CustomScan support on readfuncs.c

On Tue, Sep 29, 2015 at 6:19 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

On Mon, Sep 28, 2015 at 8:31 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

Instead of doing this:

+    /* Dump library and symbol name instead of raw pointer */
appendStringInfoString(str, " :methods ");
-    _outToken(str, node->methods->CustomName);
+    _outToken(str, node->methods->methods_library_name);
+    appendStringInfoChar(str, ' ');
+    _outToken(str, node->methods->methods_symbol_name);

Suppose we just make library_name and symbol_name fields in the node
itself, that are dumped and loaded like any others.

Would that be better?

I have no preference here.

Even if we dump library_name/symbol_name as if field in CustomScan,
not CustomScanMethods, in a similar way, we cannot use WRITE_STRING_FIELD
here, because its 'fldname' assumes these members are direct field of
CustomScan.

/* Write a character-string (possibly NULL) field */
#define WRITE_STRING_FIELD(fldname) \
(appendStringInfo(str, " :" CppAsString(fldname) " "), \
_outToken(str, node->fldname))

Well that's exactly what I was suggesting: making them a direct field
of CustomScan.

Let me confirm. Are you suggesting to have library_name/symbol_name
in CustomScan, not CustomScanMethods?
I prefer these fields are in CustomScanMethods because we don't need
to setup them again once PG_init set up these symbols. CustomScan has
to be created every time when it is chosen by planner.

True. But that doesn't cost much. I'm not sure it's better, so if
you don't like it, don't worry about it.

Yep, I like library_name and symbol_name are in CustomScanMethods
because the table of callbacks and its identifiers are not separable

One other question I have. Do we have a portable way to lookup
a pair of library and symbol by address?
Glibc has dladdr() functions that returns these information,
however, manpage warned it is not defined by POSIX.
If we would be able to have any portable way, it may make the
interface simpler.

Yes: load_external_function.

It looks up an address by a pair of library and symbol name....
What I'm looking for is a portable function that looks up a pair
of library and symbol name by an address, like dladdr() of glibc.
I don't know whether other *nix or windows have these infrastructure.

No, that doesn't exist, and the chances of us trying add that
infrastructure for this feature are nil.

OK, probably, it is the only way to expect extension put correct
values on the pair of library and symbol names.

I try to check whether the current patch workable with this direction
using my extension. Please wait for a few days.

Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#10Kouhei Kaigai
kaigai@ak.jp.nec.com
In reply to: Kouhei Kaigai (#9)
2 attachment(s)
Re: CustomScan support on readfuncs.c

On Tue, Sep 29, 2015 at 6:19 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

On Mon, Sep 28, 2015 at 8:31 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

Instead of doing this:

+    /* Dump library and symbol name instead of raw pointer */
appendStringInfoString(str, " :methods ");
-    _outToken(str, node->methods->CustomName);
+    _outToken(str, node->methods->methods_library_name);
+    appendStringInfoChar(str, ' ');
+    _outToken(str, node->methods->methods_symbol_name);

Suppose we just make library_name and symbol_name fields in the node
itself, that are dumped and loaded like any others.

Would that be better?

I have no preference here.

Even if we dump library_name/symbol_name as if field in CustomScan,
not CustomScanMethods, in a similar way, we cannot use WRITE_STRING_FIELD
here, because its 'fldname' assumes these members are direct field of
CustomScan.

/* Write a character-string (possibly NULL) field */
#define WRITE_STRING_FIELD(fldname) \
(appendStringInfo(str, " :" CppAsString(fldname) " "), \
_outToken(str, node->fldname))

Well that's exactly what I was suggesting: making them a direct field
of CustomScan.

Let me confirm. Are you suggesting to have library_name/symbol_name
in CustomScan, not CustomScanMethods?
I prefer these fields are in CustomScanMethods because we don't need
to setup them again once PG_init set up these symbols. CustomScan has
to be created every time when it is chosen by planner.

True. But that doesn't cost much. I'm not sure it's better, so if
you don't like it, don't worry about it.

Yep, I like library_name and symbol_name are in CustomScanMethods
because the table of callbacks and its identifiers are not separable

One other question I have. Do we have a portable way to lookup
a pair of library and symbol by address?
Glibc has dladdr() functions that returns these information,
however, manpage warned it is not defined by POSIX.
If we would be able to have any portable way, it may make the
interface simpler.

Yes: load_external_function.

It looks up an address by a pair of library and symbol name....
What I'm looking for is a portable function that looks up a pair
of library and symbol name by an address, like dladdr() of glibc.
I don't know whether other *nix or windows have these infrastructure.

No, that doesn't exist, and the chances of us trying add that
infrastructure for this feature are nil.

OK, probably, it is the only way to expect extension put correct
values on the pair of library and symbol names.

I try to check whether the current patch workable with this direction
using my extension. Please wait for a few days.

Sorry for my late.

I confirmed that CustomScan support of readfuncs.c works fine using the
attached patch for the PG-Strom tree. It worked as expected - duplication,
serialization and deserialization by:
plan_dup = stringToNode(nodeToString(copyObject(plan_orig)))

So, the custom-scan-on-readfuncs.v1.path itself is good for me.

In addition, I felt the following functions are useful for extensions.
* _outToken()
* _outBitmapset()
* _readBitmapset()

Do we have none-static version of above functions?
If nothing, extension has to implement them by itself, more or less.

Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>

Attachments:

custom-scan-on-readfuncs.v1.patchapplication/octet-stream; name=custom-scan-on-readfuncs.v1.patchDownload
 doc/src/sgml/custom-scan.sgml  | 53 +++++++++++++++++++++++++++++++++-----
 src/backend/nodes/copyfuncs.c  | 16 +++++++++++-
 src/backend/nodes/outfuncs.c   |  8 +++++-
 src/backend/nodes/readfuncs.c  | 58 ++++++++++++++++++++++++++++++++++++++++++
 src/backend/utils/fmgr/dfmgr.c | 21 +++++++++++++++
 src/include/fmgr.h             |  1 +
 src/include/nodes/plannodes.h  | 23 ++++++++++++++---
 7 files changed, 168 insertions(+), 12 deletions(-)

diff --git a/doc/src/sgml/custom-scan.sgml b/doc/src/sgml/custom-scan.sgml
index a229326..867b47e 100644
--- a/doc/src/sgml/custom-scan.sgml
+++ b/doc/src/sgml/custom-scan.sgml
@@ -195,11 +195,22 @@ 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</>, so so all the data stored within
+   the <quote>custom</> fields must consist of nodes that that function
+   can handle.
+   Furthermore, custom scan providers have to implement <quote>optional</>
+   callbacks if it defines substitute a larger structure that embeds
+   a <structname>CustomScan</> for the structure itself.
+  </para>
+
+  <para>
+   Also note that symbol name of the <structname>CustomScanMethods</> table
+   has to be visible to linker, because <function>stringToNode</>
+   reconstructs the <structfield>methods</> pointer using a pair of library
+   and symbol name. <function>INIT_CUSTOM_SCAN_METHODS</> initializes the
+   relevant fields, and expects custom-scan provider uses this macro on
+   <function>_PG_init</> timing.
   </para>
 
   <sect2 id="custom-scan-plan-callbacks">
@@ -228,8 +239,38 @@ void (*TextOutCustomScan) (StringInfo str,
     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.
+    there is usually not much need for this callback, unless custom-scan
+    provider does not embed its 
+   </para>
+
+   <para>
+<programlisting>
+struct 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>
+struct 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/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 62355aa..05d23aa 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -637,7 +637,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 c91273c..7ed8118 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -599,8 +599,14 @@ _outCustomScan(StringInfo str, const CustomScan *node)
 	WRITE_NODE_FIELD(custom_private);
 	WRITE_NODE_FIELD(custom_scan_tlist);
 	WRITE_BITMAPSET_FIELD(custom_relids);
+
+	/* Dump library and symbol name instead of raw pointer */
 	appendStringInfoString(str, " :methods ");
-	_outToken(str, node->methods->CustomName);
+	_outToken(str, node->methods->methods_library_name);
+	appendStringInfoChar(str, ' ');
+	_outToken(str, node->methods->methods_symbol_name);
+
+	/* Also, private fields if any */
 	if (node->methods->TextOutCustomScan)
 		node->methods->TextOutCustomScan(str, node);
 }
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index ef88209..81449a2 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -28,6 +28,7 @@
 
 #include <math.h>
 
+#include "fmgr.h"
 #include "nodes/parsenodes.h"
 #include "nodes/plannodes.h"
 #include "nodes/readfuncs.h"
@@ -1849,6 +1850,61 @@ _readForeignScan(void)
 }
 
 /*
+ * _readCustomScan
+ */
+static CustomScan *
+_readCustomScan(void)
+{
+	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);
+	READ_NODE_FIELD(custom_plans);
+	READ_NODE_FIELD(custom_exprs);
+	READ_NODE_FIELD(custom_private);
+	READ_NODE_FIELD(custom_scan_tlist);
+	READ_BITMAPSET_FIELD(custom_relids);
+
+	/*
+	 * Reconstruction of methods using library and symbol name
+	 */
+	token = pg_strtok(&length);		/* skip methods: */
+	token = pg_strtok(&length);		/* methods_library_name */
+	library_name = nullable_string(token, length);
+	token = pg_strtok(&length);		/* methods_symbol_name */
+	symbol_name = nullable_string(token, length);
+
+	methods = (const CustomScanMethods *)
+		load_external_function(library_name, symbol_name, true, NULL);
+	Assert(strcmp(methods->methods_library_name, library_name) == 0 &&
+		   strcmp(methods->methods_symbol_name, symbol_name) == 0);
+
+	/*
+	 * Then, read private fields if any. Elsewhere, just construct
+	 * a usual CustomScan node.
+	 */
+	if (!methods->TextReadCustomScan)
+		local_node = makeNode(CustomScan);
+	else
+	{
+		local_node = methods->TextReadCustomScan();
+		Assert(IsA(local_node, CustomScan));
+	}
+	/* move the common field of CustomScan */
+	memcpy(local_node, &local_temp, offsetof(CustomScan, methods));
+	local_node->methods = methods;
+
+	READ_DONE();
+}
+
+/*
  * ReadCommonJoin
  *	Assign the basic stuff of all nodes that inherit from Join
  */
@@ -2388,6 +2444,8 @@ parseNodeString(void)
 		return_value = _readWorkTableScan();
 	else if (MATCH("FOREIGNSCAN", 11))
 		return_value = _readForeignScan();
+	else if (MATCH("CUSTOMSCAN", 10))
+		return_value = _readCustomScan();
 	else if (MATCH("JOIN", 4))
 		return_value = _readJoin();
 	else if (MATCH("NESTLOOP", 8))
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index cd3db87..f343cfc 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -80,6 +80,8 @@ static char *find_in_dynamic_libpath(const char *basename);
 /* Magic structure that module needs to match to be accepted */
 static const Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA;
 
+/* Library filename on which PG_init() is currently processed */
+static const *current_library_filename = NULL;
 
 /*
  * Load the specified dynamic-link library file, and look for a function
@@ -277,8 +279,16 @@ internal_load_library(const char *libname)
 		 */
 		PG_init = (PG_init_t) pg_dlsym(file_scanner->handle, "_PG_init");
 		if (PG_init)
+		{
+			const char *saved_library_name = current_library_filename;
+
+			current_library_filename = file_scanner->filename;
+
 			(*PG_init) ();
 
+			current_library_filename = saved_library_name;
+		}
+
 		/* OK to link it into list */
 		if (file_list == NULL)
 			file_list = file_scanner;
@@ -291,6 +301,17 @@ internal_load_library(const char *libname)
 }
 
 /*
+ * Inform extensions their own filename, at the time of PG_init()
+ */
+const char *
+get_current_library_filename(void)
+{
+	if (!current_library_filename)
+		elog(ERROR, "Not in the context of _PG_init");
+	return current_library_filename;
+}
+
+/*
  * Report a suitable error for an incompatible magic block.
  */
 static void
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index 808d142..116ca4d 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -645,6 +645,7 @@ extern void **find_rendezvous_variable(const char *varName);
 extern Size EstimateLibraryStateSpace(void);
 extern void SerializeLibraryState(Size maxsize, char *start_address);
 extern void RestoreLibraryState(char *start_address);
+extern const char *get_current_library_filename(void);
 
 /*
  * Support for aggregate functions
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index cc259f1..4c64b51 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -535,24 +535,39 @@ 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;
 
 typedef struct CustomScanMethods
 {
+	/* to be set by INIT_CUSTOM_SCAN_METHODS */
 	const char *CustomName;
+	const char *methods_library_name;
+	const char *methods_symbol_name;
 
 	/* Create execution state (CustomScanState) from a CustomScan plan node */
 	Node	   *(*CreateCustomScanState) (struct CustomScan *cscan);
-	/* Optional: print custom_xxx fields in some special way */
+	/* Optional: print private fields in some special way */
 	void		(*TextOutCustomScan) (StringInfo str,
 											  const struct CustomScan *node);
+	/* Optional: read and construct the private fields above */
+	struct CustomScan *(*TextReadCustomScan)(void);
+	/* Optional: copy the original including private fields */
+	struct CustomScan *(*NodeCopyCustomScan)(const struct CustomScan *from);
 } CustomScanMethods;
 
+#define INIT_CUSTOM_SCAN_METHODS(methods, name)							\
+	do {																\
+		methods.CustomName = (name);									\
+		methods.methods_library_name = get_current_library_filename();	\
+		methods.methods_symbol_name = #methods;							\
+	} while(0)
+
 typedef struct CustomScan
 {
 	Scan		scan;
test-customscan-readfuncs.patchapplication/octet-stream; name=test-customscan-readfuncs.patchDownload
 src/cuda_control.c |  24 +-------
 src/gpuscan.c      | 167 ++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 148 insertions(+), 43 deletions(-)

diff --git a/src/cuda_control.c b/src/cuda_control.c
index 4d29591..de5e3a3 100644
--- a/src/cuda_control.c
+++ b/src/cuda_control.c
@@ -1372,7 +1372,7 @@ launch_pending_tasks(GpuTaskState *gts)
  *
  */
 static bool
-__waitfor_ready_tasks(GpuTaskState *gts)
+waitfor_ready_tasks(GpuTaskState *gts)
 {
 	bool	retry_next = true;
 	bool	wait_latch = true;
@@ -1459,28 +1459,6 @@ __waitfor_ready_tasks(GpuTaskState *gts)
 	return retry_next;
 }
 
-static bool
-waitfor_ready_tasks(GpuTaskState *gts)
-{
-	bool	save_set_latch_on_sigusr1 = set_latch_on_sigusr1;
-	bool	status;
-
-	set_latch_on_sigusr1 = true;
-	PG_TRY();
-	{
-		status = __waitfor_ready_tasks(gts);
-	}
-	PG_CATCH();
-	{
-		set_latch_on_sigusr1 = save_set_latch_on_sigusr1;
-		PG_RE_THROW();
-	}
-	PG_END_TRY();
-	set_latch_on_sigusr1 = save_set_latch_on_sigusr1;
-
-	return status;
-}
-
 /*
  * gpucontext_health_check
  *
diff --git a/src/gpuscan.c b/src/gpuscan.c
index 7fb11a7..5a8e633 100644
--- a/src/gpuscan.c
+++ b/src/gpuscan.c
@@ -19,6 +19,7 @@
 #include "access/xact.h"
 #include "catalog/pg_namespace.h"
 #include "miscadmin.h"
+#include "nodes/readfuncs.h"
 #include "optimizer/cost.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
@@ -35,9 +36,9 @@
 
 static set_rel_pathlist_hook_type	set_rel_pathlist_next;
 static CustomPathMethods		gpuscan_path_methods;
-static CustomScanMethods		gpuscan_plan_methods;
+CustomScanMethods				gpuscan_plan_methods;
 static PGStromExecMethods		gpuscan_exec_methods;
-static CustomScanMethods		bulkscan_plan_methods;
+CustomScanMethods				bulkscan_plan_methods;
 static PGStromExecMethods		bulkscan_exec_methods;
 static bool						enable_gpuscan;
 
@@ -61,6 +62,15 @@ typedef struct {
 	List	   *dev_quals;		/* qualifiers to be run on device */
 } GpuScanInfo;
 
+typedef struct {
+	CustomScan	cscan;
+	char	   *kern_source;
+	int32		extra_flags;
+	List	   *used_params;
+	List	   *used_vars;
+	List	   *dev_quals;
+} GpuScanPlan;
+
 static inline void
 form_gpuscan_info(CustomScan *cscan, GpuScanInfo *gscan_info)
 {
@@ -502,7 +512,7 @@ create_gpuscan_plan(PlannerInfo *root,
 					List *clauses,
 					List *custom_children)
 {
-	CustomScan	   *cscan;
+	GpuScanPlan	   *gscan;
 	GpuScanInfo		gs_info;
 	List		   *host_quals = NIL;
 	List		   *dev_quals = NIL;
@@ -543,23 +553,29 @@ create_gpuscan_plan(PlannerInfo *root,
 	/*
 	 * Construction of GpuScanPlan node; on top of CustomPlan node
 	 */
-	cscan = makeNode(CustomScan);
-	cscan->scan.plan.targetlist = tlist;
-	cscan->scan.plan.qual = host_quals;
-	cscan->scan.plan.lefttree = NULL;
-	cscan->scan.plan.righttree = NULL;
-	cscan->scan.scanrelid = rel->relid;
-
-	gs_info.kern_source = kern_source;
-	gs_info.extra_flags = context.extra_flags | DEVKERNEL_NEEDS_GPUSCAN;
-	gs_info.used_params = context.used_params;
-	gs_info.used_vars = context.used_vars;
-	gs_info.dev_quals = dev_quals;
-	form_gpuscan_info(cscan, &gs_info);
-	cscan->flags = best_path->flags;
-	cscan->methods = &gpuscan_plan_methods;
-
-	return &cscan->scan.plan;
+	gscan = palloc0(sizeof(GpuScanPlan));
+	NodeSetTag(gscan, T_CustomScan);
+
+	gscan->cscan.scan.plan.targetlist = tlist;
+	gscan->cscan.scan.plan.qual = host_quals;
+	gscan->cscan.scan.plan.lefttree = NULL;
+	gscan->cscan.scan.plan.righttree = NULL;
+	gscan->cscan.scan.scanrelid = rel->relid;
+	gscan->kern_source = kern_source;
+	gscan->extra_flags = context.extra_flags | DEVKERNEL_NEEDS_GPUSCAN;
+	gscan->used_vars = context.used_vars;
+	gscan->dev_quals = dev_quals;
+	gscan->cscan.flags = best_path->flags;
+	gscan->cscan.methods = &gpuscan_plan_methods;
+
+	gs_info.kern_source = gscan->kern_source;
+	gs_info.extra_flags = gscan->extra_flags;
+	gs_info.used_params = gscan->used_params;
+	gs_info.used_vars = gscan->used_vars;
+	gs_info.dev_quals = gscan->dev_quals;
+	form_gpuscan_info(&gscan->cscan, &gs_info);
+
+	return &gscan->cscan.scan.plan;
 }
 
 /*
@@ -639,6 +655,100 @@ gpuscan_create_scan_state(CustomScan *cscan)
 	return (Node *) gss;
 }
 
+/* copy and paste from outfuncs.c */
+static void
+_outToken(StringInfo str, const char *s)
+{
+	if (s == NULL || *s == '\0')
+	{
+		appendStringInfoString(str, "<>");
+		return;
+	}
+
+	/*
+	 * Look for characters or patterns that are treated specially by read.c
+	 * (either in pg_strtok() or in nodeRead()), and therefore need a
+	 * protective backslash.
+	 */
+	/* These characters only need to be quoted at the start of the string */
+	if (*s == '<' ||
+		*s == '\"' ||
+		isdigit((unsigned char) *s) ||
+		((*s == '+' || *s == '-') &&
+		 (isdigit((unsigned char) s[1]) || s[1] == '.')))
+		appendStringInfoChar(str, '\\');
+	while (*s)
+	{
+		/* These chars must be backslashed anywhere in the string */
+		if (*s == ' ' || *s == '\n' || *s == '\t' ||
+			*s == '(' || *s == ')' || *s == '{' || *s == '}' ||
+			*s == '\\')
+			appendStringInfoChar(str, '\\');
+		appendStringInfoChar(str, *s++);
+	}
+}
+
+static void
+gpuscan_textout(StringInfo str, const CustomScan *node)
+{
+	GpuScanPlan	   *gscan = (GpuScanPlan *) node;
+
+	appendStringInfo(str, " :kern_source ");
+	_outToken(str, gscan->kern_source);
+	appendStringInfo(str, " :extra_flags %u", gscan->extra_flags);
+	appendStringInfo(str, " :used_params %s",
+					 nodeToString(gscan->used_params));
+	appendStringInfo(str, " :used_vars %s",
+					 nodeToString(gscan->used_vars));
+	appendStringInfo(str, " :dev_quals %s",
+					 nodeToString(gscan->dev_quals));
+}
+
+static CustomScan *
+gpuscan_textread(void)
+{
+	GpuScanPlan	   *gscan = palloc0(sizeof(GpuScanPlan));
+	char		   *token;
+	int				length;
+
+	NodeSetTag(gscan, T_CustomScan);
+	/* kern_source */
+	token = pg_strtok(&length);
+	token = pg_strtok(&length);
+	gscan->kern_source = (length > 0 ? debackslash(token, length) : NULL);
+	/* extra_flags */
+	token = pg_strtok(&length);
+	token = pg_strtok(&length);
+	gscan->extra_flags = (cl_uint)strtoul(token, NULL, 10);
+	/* used_params */
+	token = pg_strtok(&length);
+	gscan->used_params = nodeRead(NULL, 0);
+	/* used_vars */
+	token = pg_strtok(&length);
+	gscan->used_vars = nodeRead(NULL, 0);
+	/* dev_quals */
+	token = pg_strtok(&length);
+	gscan->dev_quals = nodeRead(NULL, 0);
+
+	return &gscan->cscan;
+}
+
+static CustomScan *
+gpuscan_nodecopy(const CustomScan *__from)
+{
+	GpuScanPlan	   *from = (GpuScanPlan *) __from;
+	GpuScanPlan	   *to = palloc0(sizeof(GpuScanPlan));
+
+	NodeSetTag(to, T_CustomScan);
+	to->kern_source = (from->kern_source ? pstrdup(from->kern_source) : NULL);
+	to->extra_flags = from->extra_flags;
+	to->used_params = copyObject(from->used_params);
+	to->used_vars = copyObject(from->used_vars);
+	to->dev_quals = copyObject(from->dev_quals);
+
+	return &to->cscan;
+}
+
 static void
 gpuscan_begin(CustomScanState *node, EState *estate, int eflags)
 {
@@ -646,6 +756,15 @@ gpuscan_begin(CustomScanState *node, EState *estate, int eflags)
 	GpuContext	   *gcontext = NULL;
 	GpuScanState   *gss = (GpuScanState *) node;
 	GpuScanInfo	   *gs_info = deform_gpuscan_info(node->ss.ps.plan);
+	CustomScan	   *dplan;
+	char		   *str_1;
+	char		   *str_2;
+
+	dplan = stringToNode(nodeToString(copyObject(node->ss.ps.plan)));
+	str_1 = nodeToString(node->ss.ps.plan);
+	str_2 = nodeToString(dplan);
+	elog(INFO, "str_1 => %s", str_1);
+	elog(INFO, "str_2 => %s", str_2);
 
 	/* gpuscan should not have inner/outer plan right now */
 	Assert(outerPlan(node) == NULL);
@@ -969,10 +1088,18 @@ pgstrom_init_gpuscan(void)
 	memset(&gpuscan_plan_methods, 0, sizeof(gpuscan_plan_methods));
 	gpuscan_plan_methods.CustomName			= "GpuScan";
 	gpuscan_plan_methods.CreateCustomScanState = gpuscan_create_scan_state;
+	gpuscan_plan_methods.TextOutCustomScan	= gpuscan_textout;
+	gpuscan_plan_methods.TextReadCustomScan	= gpuscan_textread;
+	gpuscan_plan_methods.NodeCopyCustomScan	= gpuscan_nodecopy;
+	INIT_CUSTOM_SCAN_METHODS(gpuscan_plan_methods, "GpuScan");
 
 	memset(&bulkscan_plan_methods, 0, sizeof(bulkscan_plan_methods));
 	bulkscan_plan_methods.CustomName		= "BulkScan";
 	bulkscan_plan_methods.CreateCustomScanState = gpuscan_create_scan_state;
+	bulkscan_plan_methods.TextOutCustomScan	= gpuscan_textout;
+	bulkscan_plan_methods.TextReadCustomScan= gpuscan_textread;
+	bulkscan_plan_methods.NodeCopyCustomScan= gpuscan_nodecopy;
+	INIT_CUSTOM_SCAN_METHODS(bulkscan_plan_methods, "GpuScan");
 
 	/* setup exec methods */
 	memset(&gpuscan_exec_methods, 0, sizeof(gpuscan_exec_methods));
#11Robert Haas
robertmhaas@gmail.com
In reply to: Kouhei Kaigai (#10)
Re: CustomScan support on readfuncs.c

On Wed, Nov 4, 2015 at 10:13 AM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

Sorry for my late.

I confirmed that CustomScan support of readfuncs.c works fine using the
attached patch for the PG-Strom tree. It worked as expected - duplication,
serialization and deserialization by:
plan_dup = stringToNode(nodeToString(copyObject(plan_orig)))

So, the custom-scan-on-readfuncs.v1.path itself is good for me.

I don't think this is is what we want. In particular, I like this:

    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</>, so so all the data stored within
+   the <quote>custom</> fields must consist of nodes that that function
+   can handle.
+   Furthermore, custom scan providers have to implement <quote>optional</>
+   callbacks if it defines substitute a larger structure that embeds
+   a <structname>CustomScan</> for the structure itself.
+  </para>

The purposes of this patch is supposedly to add readfuncs.c support to
custom scans - I agree with that goal. This documentation change is
talking about something else, namely using a CustomScan as the fist
field in a larger structure. I'm not sure I agree with that goal, and
in any case it seems like it ought to be a separate patch. This patch
would be a lot smaller if it weren't trying to make that change too.

I also don't think that this patch ought to introduce
get_current_library_filename(). There are other cases - e.g. for
launching background workers - where such a thing could be used, but
we haven't introduced it up until now. It isn't a requirement to get
readfuncs support working.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#12Kouhei Kaigai
kaigai@ak.jp.nec.com
In reply to: Robert Haas (#11)
Re: CustomScan support on readfuncs.c

On Wed, Nov 4, 2015 at 10:13 AM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

Sorry for my late.

I confirmed that CustomScan support of readfuncs.c works fine using the
attached patch for the PG-Strom tree. It worked as expected - duplication,
serialization and deserialization by:
plan_dup = stringToNode(nodeToString(copyObject(plan_orig)))

So, the custom-scan-on-readfuncs.v1.path itself is good for me.

I don't think this is is what we want. In particular, I like this:

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</>, so so all the data stored within
+   the <quote>custom</> fields must consist of nodes that that function
+   can handle.
+   Furthermore, custom scan providers have to implement <quote>optional</>
+   callbacks if it defines substitute a larger structure that embeds
+   a <structname>CustomScan</> for the structure itself.
+  </para>

The purposes of this patch is supposedly to add readfuncs.c support to
custom scans - I agree with that goal. This documentation change is
talking about something else, namely using a CustomScan as the fist
field in a larger structure. I'm not sure I agree with that goal, and
in any case it seems like it ought to be a separate patch. This patch
would be a lot smaller if it weren't trying to make that change too.

Hmm. I might mix up two individual discussions here.
OK, I'll cut off the minimum portion for readfuncs.c support.
The other portion - to use a CustomScan as the first field in a larger
structure - shall be submitted as a separate one.

I also don't think that this patch ought to introduce
get_current_library_filename(). There are other cases - e.g. for
launching background workers - where such a thing could be used, but
we haven't introduced it up until now. It isn't a requirement to get
readfuncs support working.

Even though it isn't a minimum requirement (because extension can put
arbitrary cstring here), it can tell reasonably reliable pathname for
extensions if backend tracks filename of the library to be loaded.

Extension knows its name; its Makefile can embed module name somewhere,
for example. However, we cannot ensure use always install the modules
under the $libdir. Even if "$libdir/pg_strom" is expected, we have no
mechanism to prohibit users to install them under the "$libdir/buggy"
directory. In this case, "pg_strom" is not a right name to solve the
library path.

Even though glibc has dladdr(3) to know the filename that contains the
target symbol, it is not a portable way. So, I thought it is the best
way to inform extension by the core, on _PG_init() time where all the
extension get control once on loading.

Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#13Kouhei Kaigai
kaigai@ak.jp.nec.com
In reply to: Kouhei Kaigai (#9)
2 attachment(s)
Re: CustomScan support on readfuncs.c

-----Original Message-----
From: Kaigai Kouhei(海外 浩平)
Sent: Friday, November 06, 2015 11:23 AM
To: 'Robert Haas'
Cc: Amit Kapila; Andres Freund; pgsql-hackers
Subject: RE: [HACKERS] CustomScan support on readfuncs.c

On Wed, Nov 4, 2015 at 10:13 AM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

Sorry for my late.

I confirmed that CustomScan support of readfuncs.c works fine using the
attached patch for the PG-Strom tree. It worked as expected - duplication,
serialization and deserialization by:
plan_dup = stringToNode(nodeToString(copyObject(plan_orig)))

So, the custom-scan-on-readfuncs.v1.path itself is good for me.

I don't think this is is what we want. In particular, I like this:

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</>, so so all the data stored within
+   the <quote>custom</> fields must consist of nodes that that function
+   can handle.
+   Furthermore, custom scan providers have to implement <quote>optional</>
+   callbacks if it defines substitute a larger structure that embeds
+   a <structname>CustomScan</> for the structure itself.
+  </para>

The purposes of this patch is supposedly to add readfuncs.c support to
custom scans - I agree with that goal. This documentation change is
talking about something else, namely using a CustomScan as the fist
field in a larger structure. I'm not sure I agree with that goal, and
in any case it seems like it ought to be a separate patch. This patch
would be a lot smaller if it weren't trying to make that change too.

Hmm. I might mix up two individual discussions here.
OK, I'll cut off the minimum portion for readfuncs.c support.
The other portion - to use a CustomScan as the first field in a larger
structure - shall be submitted as a separate one.

I also don't think that this patch ought to introduce
get_current_library_filename(). There are other cases - e.g. for
launching background workers - where such a thing could be used, but
we haven't introduced it up until now. It isn't a requirement to get
readfuncs support working.

Even though it isn't a minimum requirement (because extension can put
arbitrary cstring here), it can tell reasonably reliable pathname for
extensions if backend tracks filename of the library to be loaded.

Extension knows its name; its Makefile can embed module name somewhere,
for example. However, we cannot ensure use always install the modules
under the $libdir. Even if "$libdir/pg_strom" is expected, we have no
mechanism to prohibit users to install them under the "$libdir/buggy"
directory. In this case, "pg_strom" is not a right name to solve the
library path.

Even though glibc has dladdr(3) to know the filename that contains the
target symbol, it is not a portable way. So, I thought it is the best
way to inform extension by the core, on _PG_init() time where all the
extension get control once on loading.

I tried to split the previous version into two portions.

- custom-scan-on-readfuncs.v2.patch
It allows to serialize/deserialize CustomScan node as discussed upthread.
Regarding of get_current_library_filename(), I keep this feature as
the previous version right now, because I have no good alternatives.

In this patch, the role of TextReadCustomScan callback is to clean out
any tokens generated by TextOutCustomScan. The CustomScan node itself
can be reconstructed with common portion because we expect custom_exprs
and custom_private have objects which are safe to copyObject().

- custom-scan-on-copyfuncs.v2.patch
This is the portion that supports a larger structure with CustomScan
on its head.
The role of TextReadCustomScan is changed. It reconstruct the private
structure that contains CustomScan by palloc(), and fill-up its private
fields by tokens read. The common field of CustomScan shall be filled
up by the core.
One other callback I added is NodeCopyCustomScan; that enables extension
to allocate a structure larger than CustomScan and fill-up its private
fields.
Anyway, I'll have further discussion for 2nd patch in another thread.

Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>

Attachments:

custom-scan-on-copyfuncs.v2.patchapplication/octet-stream; name=custom-scan-on-copyfuncs.v2.patchDownload
 doc/src/sgml/custom-scan.sgml | 25 +++++++++++++++++++++----
 src/backend/nodes/copyfuncs.c | 16 +++++++++++++++-
 src/backend/nodes/readfuncs.c | 22 +++++++++++++++++-----
 src/include/nodes/plannodes.h | 11 +++++++----
 4 files changed, 60 insertions(+), 14 deletions(-)

diff --git a/doc/src/sgml/custom-scan.sgml b/doc/src/sgml/custom-scan.sgml
index af0dd56..21a9ace 100644
--- a/doc/src/sgml/custom-scan.sgml
+++ b/doc/src/sgml/custom-scan.sgml
@@ -197,9 +197,11 @@ typedef struct CustomScan
    Plan trees must be able to be duplicated using <function>copyObject</>,
    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 clean out these tokens.
+   <function>TextReadCustomScan</> to reconstruct the private structure.
   </para>
   <para>
    Like any other fields, <structfield>methods</> pointer of the
@@ -251,16 +253,31 @@ void (*TextOutCustomScan) (StringInfo str,
 
    <para>
 <programlisting>
-void (*TextReadCustomScan)(CustomScan *node);
+CustomScan *(*TextReadCustomScan)(void);
 </programlisting>
-    Reads the private fields of supplied <structname>CustomScan</> node
-    generated by <function>TextOutCustomScan</> callback.
+    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/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index c176ff9..ba58f3f 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -661,7 +661,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/readfuncs.c b/src/backend/nodes/readfuncs.c
index 8e6e3d6..8e99703 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1812,11 +1812,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,11 +1845,20 @@ _readCustomScan(void)
 	local_node->methods = methods;
 
 	/*
-	 * Read custom fields if any. Number of tokens has to be equivalent
-	 * to the output of TextOutCustomScan
+	 * 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)
-		methods->TextReadCustomScan(local_node);
+	if (!methods->TextReadCustomScan)
+		local_node = makeNode(CustomScan);
+	else
+	{
+		local_node = methods->TextReadCustomScan();
+		Assert(IsA(local_node, CustomScan));
+	}
+	/* move the common field of CustomScan */
+	memcpy(local_node, &local_temp, offsetof(CustomScan, methods));
+	local_node->methods = methods;
 
 	READ_DONE();
 }
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index b3f90fb..908c029 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -542,9 +542,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,7 +563,9 @@ typedef struct CustomScanMethods
 	void		(*TextOutCustomScan) (StringInfo str,
 											  const struct CustomScan *node);
 	/* Optional: read the private fields printed in special way */
-	void		(*TextReadCustomScan) (struct CustomScan *cscan);
+	struct CustomScan *(*TextReadCustomScan)(void);
+	/* Optional: copy the original including private fields */
+	struct CustomScan *(*NodeCopyCustomScan)(const struct CustomScan *from);
 } CustomScanMethods;
 
 #define INIT_CUSTOM_SCAN_METHODS(methods, name)							\
custom-scan-on-readfuncs.v2.patchapplication/octet-stream; name=custom-scan-on-readfuncs.v2.patchDownload
 doc/src/sgml/custom-scan.sgml  | 41 +++++++++++++++++++++++++++++++-----
 src/backend/nodes/outfuncs.c   |  8 ++++++-
 src/backend/nodes/readfuncs.c  | 48 ++++++++++++++++++++++++++++++++++++++++++
 src/backend/utils/fmgr/dfmgr.c | 21 ++++++++++++++++++
 src/include/fmgr.h             |  1 +
 src/include/nodes/plannodes.h  | 14 +++++++++++-
 6 files changed, 126 insertions(+), 7 deletions(-)

diff --git a/doc/src/sgml/custom-scan.sgml b/doc/src/sgml/custom-scan.sgml
index a229326..af0dd56 100644
--- a/doc/src/sgml/custom-scan.sgml
+++ b/doc/src/sgml/custom-scan.sgml
@@ -195,11 +195,29 @@ 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</>.
+   Thus, if custom scan provider implements <function>TextOutCustomScan</>
+   to dump its private fields its own way, it also has responsibility of
+   <function>TextReadCustomScan</> to clean out these tokens.
+  </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">
@@ -230,6 +248,19 @@ void (*TextOutCustomScan) (StringInfo str,
     structure, including the substructure of the <quote>custom</> fields,
     there is usually not much need for this callback.
    </para>
+
+   <para>
+<programlisting>
+void (*TextReadCustomScan)(CustomScan *node);
+</programlisting>
+    Reads the private fields of supplied <structname>CustomScan</> node
+    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>
   </sect2>
  </sect1>
 
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 3e75cd1..775ac95 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -612,8 +612,14 @@ _outCustomScan(StringInfo str, const CustomScan *node)
 	WRITE_NODE_FIELD(custom_private);
 	WRITE_NODE_FIELD(custom_scan_tlist);
 	WRITE_BITMAPSET_FIELD(custom_relids);
+
+	/* Dump library and symbol name instead of raw pointer */
 	appendStringInfoString(str, " :methods ");
-	_outToken(str, node->methods->CustomName);
+	_outToken(str, node->methods->methods_library_name);
+	appendStringInfoChar(str, ' ');
+	_outToken(str, node->methods->methods_symbol_name);
+
+	/* Also, private fields if any */
 	if (node->methods->TextOutCustomScan)
 		node->methods->TextOutCustomScan(str, node);
 }
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 94ba6dc..8e6e3d6 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -28,6 +28,7 @@
 
 #include <math.h>
 
+#include "fmgr.h"
 #include "nodes/parsenodes.h"
 #include "nodes/plannodes.h"
 #include "nodes/readfuncs.h"
@@ -1806,6 +1807,51 @@ _readForeignScan(void)
 }
 
 /*
+ * _readCustomScan
+ */
+static CustomScan *
+_readCustomScan(void)
+{
+	READ_LOCALS(CustomScan);
+	char	   *library_name;
+	char	   *symbol_name;
+	const CustomScanMethods *methods;
+
+	ReadCommonScan(&local_node->scan);
+
+	READ_UINT_FIELD(flags);
+	READ_NODE_FIELD(custom_plans);
+	READ_NODE_FIELD(custom_exprs);
+	READ_NODE_FIELD(custom_private);
+	READ_NODE_FIELD(custom_scan_tlist);
+	READ_BITMAPSET_FIELD(custom_relids);
+
+	/*
+	 * Reconstruction of methods using library and symbol name
+	 */
+	token = pg_strtok(&length);		/* skip methods: */
+	token = pg_strtok(&length);		/* methods_library_name */
+	library_name = nullable_string(token, length);
+	token = pg_strtok(&length);		/* methods_symbol_name */
+	symbol_name = nullable_string(token, length);
+
+	methods = (const CustomScanMethods *)
+		load_external_function(library_name, symbol_name, true, NULL);
+	Assert(strcmp(methods->methods_library_name, library_name) == 0 &&
+		   strcmp(methods->methods_symbol_name, symbol_name) == 0);
+	local_node->methods = methods;
+
+	/*
+	 * Read custom fields if any. Number of tokens has to be equivalent
+	 * to the output of TextOutCustomScan
+	 */
+	if (methods->TextReadCustomScan)
+		methods->TextReadCustomScan(local_node);
+
+	READ_DONE();
+}
+
+/*
  * ReadCommonJoin
  *	Assign the basic stuff of all nodes that inherit from Join
  */
@@ -2361,6 +2407,8 @@ parseNodeString(void)
 		return_value = _readWorkTableScan();
 	else if (MATCH("FOREIGNSCAN", 11))
 		return_value = _readForeignScan();
+	else if (MATCH("CUSTOMSCAN", 10))
+		return_value = _readCustomScan();
 	else if (MATCH("JOIN", 4))
 		return_value = _readJoin();
 	else if (MATCH("NESTLOOP", 8))
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index cd3db87..f343cfc 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -80,6 +80,8 @@ static char *find_in_dynamic_libpath(const char *basename);
 /* Magic structure that module needs to match to be accepted */
 static const Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA;
 
+/* Library filename on which PG_init() is currently processed */
+static const *current_library_filename = NULL;
 
 /*
  * Load the specified dynamic-link library file, and look for a function
@@ -277,8 +279,16 @@ internal_load_library(const char *libname)
 		 */
 		PG_init = (PG_init_t) pg_dlsym(file_scanner->handle, "_PG_init");
 		if (PG_init)
+		{
+			const char *saved_library_name = current_library_filename;
+
+			current_library_filename = file_scanner->filename;
+
 			(*PG_init) ();
 
+			current_library_filename = saved_library_name;
+		}
+
 		/* OK to link it into list */
 		if (file_list == NULL)
 			file_list = file_scanner;
@@ -291,6 +301,17 @@ internal_load_library(const char *libname)
 }
 
 /*
+ * Inform extensions their own filename, at the time of PG_init()
+ */
+const char *
+get_current_library_filename(void)
+{
+	if (!current_library_filename)
+		elog(ERROR, "Not in the context of _PG_init");
+	return current_library_filename;
+}
+
+/*
  * Report a suitable error for an incompatible magic block.
  */
 static void
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index 808d142..116ca4d 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -645,6 +645,7 @@ extern void **find_rendezvous_variable(const char *varName);
 extern Size EstimateLibraryStateSpace(void);
 extern void SerializeLibraryState(Size maxsize, char *start_address);
 extern void RestoreLibraryState(char *start_address);
+extern const char *get_current_library_filename(void);
 
 /*
  * Support for aggregate functions
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 6b28c8e..b3f90fb 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -551,15 +551,27 @@ struct CustomScan;
 
 typedef struct CustomScanMethods
 {
+	/* to be set by INIT_CUSTOM_SCAN_METHODS */
 	const char *CustomName;
+	const char *methods_library_name;
+	const char *methods_symbol_name;
 
 	/* Create execution state (CustomScanState) from a CustomScan plan node */
 	Node	   *(*CreateCustomScanState) (struct CustomScan *cscan);
-	/* Optional: print custom_xxx fields in some special way */
+	/* 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 */
+	void		(*TextReadCustomScan) (struct CustomScan *cscan);
 } CustomScanMethods;
 
+#define INIT_CUSTOM_SCAN_METHODS(methods, name)							\
+	do {																\
+		methods.CustomName = (name);									\
+		methods.methods_library_name = get_current_library_filename();	\
+		methods.methods_symbol_name = #methods;							\
+	} while(0)
+
 typedef struct CustomScan
 {
 	Scan		scan;
#14Robert Haas
robertmhaas@gmail.com
In reply to: Kouhei Kaigai (#13)
Re: CustomScan support on readfuncs.c

On Fri, Nov 6, 2015 at 2:02 AM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

I tried to split the previous version into two portions.

- custom-scan-on-readfuncs.v2.patch
It allows to serialize/deserialize CustomScan node as discussed upthread.
Regarding of get_current_library_filename(), I keep this feature as
the previous version right now, because I have no good alternatives.

Why can't the library just pass its name as a constant string?

In this patch, the role of TextReadCustomScan callback is to clean out
any tokens generated by TextOutCustomScan. The CustomScan node itself
can be reconstructed with common portion because we expect custom_exprs
and custom_private have objects which are safe to copyObject().

Some of the documentation changes for the embed-the-struct changes are
still present in the readfuncs patch.

Rather than adding TextReadCustomScan, I think we should rip
TextOutputCustomScan out. It seems like a useless appendage.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#15Kouhei Kaigai
kaigai@ak.jp.nec.com
In reply to: Robert Haas (#14)
Re: CustomScan support on readfuncs.c

-----Original Message-----
From: pgsql-hackers-owner@postgresql.org
[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Robert Haas
Sent: Saturday, November 07, 2015 1:42 AM
To: Kaigai Kouhei(海外 浩平)
Cc: Amit Kapila; Andres Freund; pgsql-hackers
Subject: Re: [HACKERS] CustomScan support on readfuncs.c

On Fri, Nov 6, 2015 at 2:02 AM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

I tried to split the previous version into two portions.

- custom-scan-on-readfuncs.v2.patch
It allows to serialize/deserialize CustomScan node as discussed upthread.
Regarding of get_current_library_filename(), I keep this feature as
the previous version right now, because I have no good alternatives.

Why can't the library just pass its name as a constant string?

Are you suggesting to pass the object name on software build time?
If so, it may load incorrect libraries when DBA renamed its filename.
At least, PostgreSQL cannot prevent DBA to rename library filenames
even if they try to deploy "pg_strom.so", "pg_strom.20151106.so" and
"pg_strom.20151030_bug.so" on same directory.

I don't know portable way to get library name on run-time, so, all we
can use are environment specific.
- dladdr(3) : specific to glibc
- /proc/<PID>/maps : specific to Linux

Thus, I thought the backend assist is the most reasonable way here.

In this patch, the role of TextReadCustomScan callback is to clean out
any tokens generated by TextOutCustomScan. The CustomScan node itself
can be reconstructed with common portion because we expect custom_exprs
and custom_private have objects which are safe to copyObject().

Some of the documentation changes for the embed-the-struct changes are
still present in the readfuncs patch.

Rather than adding TextReadCustomScan, I think we should rip
TextOutputCustomScan out. It seems like a useless appendage.

OK, I'll once remove TextOut, then add it later.

Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#16Robert Haas
robertmhaas@gmail.com
In reply to: Kouhei Kaigai (#15)
Re: CustomScan support on readfuncs.c

On Sat, Nov 7, 2015 at 6:38 AM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

Are you suggesting to pass the object name on software build time?

Yes. That's what test_shm_mq and worker_spi already do:

sprintf(worker.bgw_library_name, "test_shm_mq");

If so, it may load incorrect libraries when DBA renamed its filename.
At least, PostgreSQL cannot prevent DBA to rename library filenames
even if they try to deploy "pg_strom.so", "pg_strom.20151106.so" and
"pg_strom.20151030_bug.so" on same directory.

I agree. But that's not a new problem that needs to be solved by this
patch. It already exists - see above.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#17Kouhei Kaigai
kaigai@ak.jp.nec.com
In reply to: Robert Haas (#16)
1 attachment(s)
Re: CustomScan support on readfuncs.c

On Sat, Nov 7, 2015 at 6:38 AM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

Are you suggesting to pass the object name on software build time?

Yes. That's what test_shm_mq and worker_spi already do:

sprintf(worker.bgw_library_name, "test_shm_mq");

OK, I ripped out the portion around dfmgr.c.

If so, it may load incorrect libraries when DBA renamed its filename.
At least, PostgreSQL cannot prevent DBA to rename library filenames
even if they try to deploy "pg_strom.so", "pg_strom.20151106.so" and
"pg_strom.20151030_bug.so" on same directory.

I agree. But that's not a new problem that needs to be solved by this
patch. It already exists - see above.

It still may be a potential problem, even though a corner case.
I'll try to implement an internal API to know "what is my name".

The attached main patch (custom-scan-on-readfuncs.v3.patch) once
removes TextOutCustomScan, thus all the serialized tokens become
known to the core backend, and add _readCustomScan() at readfuncs.c.
It deserializes CustomScan nodes from cstring tokens, especially,
reloads the pointer of CustomScanMethods tables using a pair of
library name and symbol name.
Thus, it also requires custom scan providers to keep the methods
table visible from external objects.

Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>

Attachments:

custom-scan-on-readfuncs.v3.patchapplication/octet-stream; name=custom-scan-on-readfuncs.v3.patchDownload
 doc/src/sgml/custom-scan.sgml | 16 +++-------------
 src/backend/nodes/outfuncs.c  |  7 ++++---
 src/backend/nodes/readfuncs.c | 41 +++++++++++++++++++++++++++++++++++++++++
 src/include/nodes/plannodes.h |  5 ++---
 4 files changed, 50 insertions(+), 19 deletions(-)

diff --git a/doc/src/sgml/custom-scan.sgml b/doc/src/sgml/custom-scan.sgml
index a229326..d042adb 100644
--- a/doc/src/sgml/custom-scan.sgml
+++ b/doc/src/sgml/custom-scan.sgml
@@ -83,7 +83,9 @@ typedef struct CustomPath
     print the custom path will work as designed.  <structfield>methods</> must
     point to a (usually statically allocated) object implementing the required
     custom path methods, of which there are currently only two, as 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>
@@ -218,18 +220,6 @@ 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>
   </sect2>
  </sect1>
 
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 3e75cd1..af6674c 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -612,10 +612,11 @@ _outCustomScan(StringInfo str, const CustomScan *node)
 	WRITE_NODE_FIELD(custom_private);
 	WRITE_NODE_FIELD(custom_scan_tlist);
 	WRITE_BITMAPSET_FIELD(custom_relids);
+	/* Dump library and symbol name instead of raw pointer */
 	appendStringInfoString(str, " :methods ");
-	_outToken(str, node->methods->CustomName);
-	if (node->methods->TextOutCustomScan)
-		node->methods->TextOutCustomScan(str, node);
+	_outToken(str, node->methods->methodsLibraryName);
+	appendStringInfoChar(str, ' ');
+	_outToken(str, node->methods->methodsSymbolName);
 }
 
 static void
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 94ba6dc..d143dac 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -28,6 +28,7 @@
 
 #include <math.h>
 
+#include "fmgr.h"
 #include "nodes/parsenodes.h"
 #include "nodes/plannodes.h"
 #include "nodes/readfuncs.h"
@@ -1806,6 +1807,44 @@ _readForeignScan(void)
 }
 
 /*
+ * _readCustomScan
+ */
+static CustomScan *
+_readCustomScan(void)
+{
+	READ_LOCALS(CustomScan);
+	char	   *library_name;
+	char	   *symbol_name;
+	const CustomScanMethods *methods;
+
+	ReadCommonScan(&local_node->scan);
+
+	READ_UINT_FIELD(flags);
+	READ_NODE_FIELD(custom_plans);
+	READ_NODE_FIELD(custom_exprs);
+	READ_NODE_FIELD(custom_private);
+	READ_NODE_FIELD(custom_scan_tlist);
+	READ_BITMAPSET_FIELD(custom_relids);
+
+	/*
+	 * Reconstruction of methods using library and symbol name
+	 */
+	token = pg_strtok(&length);		/* skip methods: */
+	token = pg_strtok(&length);		/* methodsLibraryName */
+	library_name = nullable_string(token, length);
+	token = pg_strtok(&length);		/* methodsSymbolName */
+	symbol_name = nullable_string(token, length);
+
+	methods = (const CustomScanMethods *)
+		load_external_function(library_name, symbol_name, true, NULL);
+	Assert(strcmp(methods->methodsLibraryName, library_name) == 0 &&
+		   strcmp(methods->methodsSymbolName, symbol_name) == 0);
+	local_node->methods = methods;
+
+	READ_DONE();
+}
+
+/*
  * ReadCommonJoin
  *	Assign the basic stuff of all nodes that inherit from Join
  */
@@ -2361,6 +2400,8 @@ parseNodeString(void)
 		return_value = _readWorkTableScan();
 	else if (MATCH("FOREIGNSCAN", 11))
 		return_value = _readForeignScan();
+	else if (MATCH("CUSTOMSCAN", 10))
+		return_value = _readCustomScan();
 	else if (MATCH("JOIN", 4))
 		return_value = _readJoin();
 	else if (MATCH("NESTLOOP", 8))
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 6b28c8e..5ecc2d1 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -552,12 +552,11 @@ struct CustomScan;
 typedef struct CustomScanMethods
 {
 	const char *CustomName;
+	const char *methodsLibraryName;
+	const char *methodsSymbolName;
 
 	/* Create execution state (CustomScanState) from a CustomScan plan node */
 	Node	   *(*CreateCustomScanState) (struct CustomScan *cscan);
-	/* Optional: print custom_xxx fields in some special way */
-	void		(*TextOutCustomScan) (StringInfo str,
-											  const struct CustomScan *node);
 } CustomScanMethods;
 
 typedef struct CustomScan
#18Robert Haas
robertmhaas@gmail.com
In reply to: Kouhei Kaigai (#17)
Re: CustomScan support on readfuncs.c

On Mon, Nov 9, 2015 at 9:46 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

The attached main patch (custom-scan-on-readfuncs.v3.patch) once
removes TextOutCustomScan, thus all the serialized tokens become
known to the core backend, and add _readCustomScan() at readfuncs.c.
It deserializes CustomScan nodes from cstring tokens, especially,
reloads the pointer of CustomScanMethods tables using a pair of
library name and symbol name.
Thus, it also requires custom scan providers to keep the methods
table visible from external objects.

Committed with some kibitzing.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#19Kouhei Kaigai
kaigai@ak.jp.nec.com
In reply to: Robert Haas (#18)
Re: CustomScan support on readfuncs.c

On Mon, Nov 9, 2015 at 9:46 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

The attached main patch (custom-scan-on-readfuncs.v3.patch) once
removes TextOutCustomScan, thus all the serialized tokens become
known to the core backend, and add _readCustomScan() at readfuncs.c.
It deserializes CustomScan nodes from cstring tokens, especially,
reloads the pointer of CustomScanMethods tables using a pair of
library name and symbol name.
Thus, it also requires custom scan providers to keep the methods
table visible from external objects.

Committed with some kibitzing.

Thanks,

How do we deal with TextOutCustomScan in the v9.5 tree?
I think we ought to remove this callback also prior to v9.5 release.
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#20Robert Haas
robertmhaas@gmail.com
In reply to: Kouhei Kaigai (#19)
Re: CustomScan support on readfuncs.c

On Thu, Nov 12, 2015 at 7:59 AM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

On Mon, Nov 9, 2015 at 9:46 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

The attached main patch (custom-scan-on-readfuncs.v3.patch) once
removes TextOutCustomScan, thus all the serialized tokens become
known to the core backend, and add _readCustomScan() at readfuncs.c.
It deserializes CustomScan nodes from cstring tokens, especially,
reloads the pointer of CustomScanMethods tables using a pair of
library name and symbol name.
Thus, it also requires custom scan providers to keep the methods
table visible from external objects.

Committed with some kibitzing.

Thanks,

How do we deal with TextOutCustomScan in the v9.5 tree?
I think we ought to remove this callback also prior to v9.5 release.

I'll do that if there's a clear consensus in favor. I wasn't sure it
really made sense so close to release.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#21Kouhei Kaigai
kaigai@ak.jp.nec.com
In reply to: Robert Haas (#20)
Re: CustomScan support on readfuncs.c

On Thu, Nov 12, 2015 at 7:59 AM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

On Mon, Nov 9, 2015 at 9:46 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:

The attached main patch (custom-scan-on-readfuncs.v3.patch) once
removes TextOutCustomScan, thus all the serialized tokens become
known to the core backend, and add _readCustomScan() at readfuncs.c.
It deserializes CustomScan nodes from cstring tokens, especially,
reloads the pointer of CustomScanMethods tables using a pair of
library name and symbol name.
Thus, it also requires custom scan providers to keep the methods
table visible from external objects.

Committed with some kibitzing.

Thanks,

How do we deal with TextOutCustomScan in the v9.5 tree?
I think we ought to remove this callback also prior to v9.5 release.

I'll do that if there's a clear consensus in favor. I wasn't sure it
really made sense so close to release.

Unless we don't reach a consensus in the "CustomScan in a larger
structure" thread, TextOutCustomScan callback becomes obsoleted in
the v9.6 release.

So, I think this callback shall be dropped once.
Let's wait for a few days for other persons' opinion?

Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers