Reworks of CustomScan serialization/deserialization
Hello,
I'd like to adjust a few of custom-scan interface prior to v9.6 freeze.
The major point is serialization/deserialization mechanism.
Now, extension has to give LibraryName and SymbolName to reproduce
same CustomScanMethods on the background worker process side. Indeed,
it is sufficient information to pull the table of function pointers.
On the other hands, we now have different mechanism to wrap private
information - extensible node. It requires extensions to register its
ExtensibleNodeMethods identified by name, usually, on _PG_init() time.
It is also reasonable way to reproduce same objects on background
worker side.
However, mixture of two different ways is not good. My preference is
what extensible-node is doing rather than what custom-scan is currently
doing.
The attached patch allows extension to register CustomScanMethods once,
then readFunc.c can pull this table by CustomName in string form.
The minor one is header file location of CustomXXXXMethods declaration.
These are currently declared at relation.h, plannodes.h and execnodes.h.
These files are very primitive, so we put these lines:
struct ParallelContext; /* avoid including parallel.h here */
struct shm_toc; /* avoid including shm_toc.h here */
struct ExplainState; /* avoid including explain.h here */
to avoid inclusion of other headers here.
It seems to me CustomXXXXMethods shall be moved to somewhere appropriate,
like fdwapi.h for FDW. If we put "struct CustomXXXXMethods;" on these
primitive header files instead, it will work.
I'm not 100% certain whether "nodes/custom-apis.h" is the best location,
but somewhere we can put these declarations rather than the primitive
header files might be needed.
Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>
Attachments:
pgsql-v9.6-custom-scan-serialization-reworks.1.patchapplication/octet-stream; name=pgsql-v9.6-custom-scan-serialization-reworks.1.patchDownload
src/backend/commands/explain.c | 1 +
src/backend/nodes/Makefile | 3 +-
src/backend/nodes/copyfuncs.c | 1 +
src/backend/nodes/custom-apis.c | 83 +++++++++++++++++++++++++++++++
src/backend/nodes/outfuncs.c | 7 ++-
src/backend/nodes/readfuncs.c | 20 +++-----
src/backend/optimizer/plan/createplan.c | 1 +
src/include/executor/nodeCustom.h | 1 +
src/include/nodes/custom-apis.h | 87 +++++++++++++++++++++++++++++++++
src/include/nodes/execnodes.h | 35 +------------
src/include/nodes/plannodes.h | 14 +-----
src/include/nodes/relation.h | 19 +------
12 files changed, 191 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index ee13136..abe2a88 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -21,6 +21,7 @@
#include "commands/prepare.h"
#include "executor/hashjoin.h"
#include "foreign/fdwapi.h"
+#include "nodes/custom-apis.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
diff --git a/src/backend/nodes/Makefile b/src/backend/nodes/Makefile
index 0b1e98c..1eb1ed3 100644
--- a/src/backend/nodes/Makefile
+++ b/src/backend/nodes/Makefile
@@ -14,6 +14,7 @@ include $(top_builddir)/src/Makefile.global
OBJS = nodeFuncs.o nodes.o list.o bitmapset.o tidbitmap.o \
copyfuncs.o equalfuncs.o extensible.o makefuncs.o \
- outfuncs.o readfuncs.o print.o read.o params.o value.o
+ outfuncs.o readfuncs.o print.o read.o params.o value.o custom-apis.o
+
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index a9e9cc3..4a0e7c8 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -23,6 +23,7 @@
#include "postgres.h"
#include "miscadmin.h"
+#include "nodes/custom-apis.h"
#include "nodes/extensible.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
diff --git a/src/backend/nodes/custom-apis.c b/src/backend/nodes/custom-apis.c
new file mode 100644
index 0000000..2fab644
--- /dev/null
+++ b/src/backend/nodes/custom-apis.c
@@ -0,0 +1,83 @@
+/*-------------------------------------------------------------------------
+ *
+ * custom-apis.c
+ * Support for custom-path/scan/exec node types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * src/backend/nodes/custom-apis.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "nodes/custom-apis.h"
+#include "utils/hsearch.h"
+
+static HTAB *custom_scan_methods = NULL;
+
+typedef struct
+{
+ char CustomName[CUSTOM_NAME_MAX_LEN];
+ const CustomScanMethods *methods;
+} CustomScanMethodsEntry;
+
+/*
+ * Register a new custom scan methods
+ */
+void
+RegisterCustomScanMethods(const CustomScanMethods *methods)
+{
+ CustomScanMethodsEntry *entry;
+ bool found;
+
+ if (custom_scan_methods == NULL)
+ {
+ HASHCTL ctl;
+
+ memset(&ctl, 0, sizeof(HASHCTL));
+ ctl.keysize = CUSTOM_NAME_MAX_LEN;
+ ctl.entrysize = sizeof(CustomScanMethodsEntry);
+ custom_scan_methods = hash_create("Custom Scan Methods",
+ 100, &ctl, HASH_ELEM);
+ }
+
+ Assert(strlen(methods->CustomName) <= CUSTOM_NAME_MAX_LEN);
+
+ entry = (CustomScanMethodsEntry *) hash_search(custom_scan_methods,
+ methods->CustomName,
+ HASH_ENTER, &found);
+ if (found)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("CustomScanMethods \"%s\" already exists",
+ methods->CustomName)));
+
+ entry->methods = methods;
+}
+
+/*
+ * Get the methods for a given name of CustomScanMethods
+ */
+const CustomScanMethods *
+GetCustomScanMethods(const char *CustomName, bool missing_ok)
+{
+ CustomScanMethodsEntry *entry = NULL;
+
+ if (custom_scan_methods != NULL)
+ entry = (CustomScanMethodsEntry *) hash_search(custom_scan_methods,
+ CustomName,
+ HASH_FIND, NULL);
+ if (!entry)
+ {
+ if (missing_ok)
+ return NULL;
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("CustomScanMethods \"%s\" was not registered",
+ CustomName)));
+ }
+ return entry->methods;
+}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 85acce8..5c65b8f 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -26,6 +26,7 @@
#include <ctype.h>
#include "lib/stringinfo.h"
+#include "nodes/custom-apis.h"
#include "nodes/extensible.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
@@ -630,11 +631,9 @@ _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 */
+ /* CustomName is a key to lookup CustomScanMethods */
appendStringInfoString(str, " :methods ");
- _outToken(str, node->methods->LibraryName);
- appendStringInfoChar(str, ' ');
- _outToken(str, node->methods->SymbolName);
+ _outToken(str, node->methods->CustomName);
}
static void
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index e6e6f29..3ea00a4 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -29,6 +29,7 @@
#include <math.h>
#include "fmgr.h"
+#include "nodes/custom-apis.h"
#include "nodes/extensible.h"
#include "nodes/parsenodes.h"
#include "nodes/plannodes.h"
@@ -1824,8 +1825,7 @@ static CustomScan *
_readCustomScan(void)
{
READ_LOCALS(CustomScan);
- char *library_name;
- char *symbol_name;
+ char *custom_name;
const CustomScanMethods *methods;
ReadCommonScan(&local_node->scan);
@@ -1837,19 +1837,11 @@ _readCustomScan(void)
READ_NODE_FIELD(custom_scan_tlist);
READ_BITMAPSET_FIELD(custom_relids);
- /*
- * Reconstruction of methods using library and symbol name
- */
+ /* Lookup CustomScanMethods by CustomName */
token = pg_strtok(&length); /* skip methods: */
- token = pg_strtok(&length); /* LibraryName */
- library_name = nullable_string(token, length);
- token = pg_strtok(&length); /* SymbolName */
- symbol_name = nullable_string(token, length);
-
- methods = (const CustomScanMethods *)
- load_external_function(library_name, symbol_name, true, NULL);
- Assert(strcmp(methods->LibraryName, library_name) == 0 &&
- strcmp(methods->SymbolName, symbol_name) == 0);
+ token = pg_strtok(&length); /* CustomName */
+ custom_name = nullable_string(token, length);
+ methods = GetCustomScanMethods(custom_name, false);
local_node->methods = methods;
READ_DONE();
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 198b06b..79d0294 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -24,6 +24,7 @@
#include "catalog/pg_class.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
+#include "nodes/custom-apis.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
diff --git a/src/include/executor/nodeCustom.h b/src/include/executor/nodeCustom.h
index 410a3ad..154056c 100644
--- a/src/include/executor/nodeCustom.h
+++ b/src/include/executor/nodeCustom.h
@@ -13,6 +13,7 @@
#define NODECUSTOM_H
#include "access/parallel.h"
+#include "nodes/custom-apis.h"
#include "nodes/execnodes.h"
/*
diff --git a/src/include/nodes/custom-apis.h b/src/include/nodes/custom-apis.h
new file mode 100644
index 0000000..ce9c15f
--- /dev/null
+++ b/src/include/nodes/custom-apis.h
@@ -0,0 +1,87 @@
+/*-------------------------------------------------------------------------
+ *
+ * custom-apis.h
+ * Definitions for custom-path/scan/exec-methods
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef CUSTOM_APIS_H
+#define CUSTOM_APIS_H
+
+#include "access/parallel.h"
+#include "commands/explain.h"
+#include "nodes/execnodes.h"
+#include "nodes/plannodes.h"
+#include "nodes/relation.h"
+
+/*
+ * Flags definitions
+ */
+#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN 0x0001
+#define CUSTOMPATH_SUPPORT_MARK_RESTORE 0x0002
+
+
+#define CUSTOM_NAME_MAX_LEN 64
+
+typedef struct CustomPathMethods
+{
+ const char *CustomName;
+
+ /* Convert Path to a Plan */
+ struct Plan *(*PlanCustomPath) (PlannerInfo *root,
+ RelOptInfo *rel,
+ struct CustomPath *best_path,
+ List *tlist,
+ List *clauses,
+ List *custom_plans);
+} CustomPathMethods;
+
+
+typedef struct CustomScanMethods
+{
+ const char *CustomName;
+
+ /* Create execution state (CustomScanState) from a CustomScan plan node */
+ Node *(*CreateCustomScanState) (CustomScan *cscan);
+} CustomScanMethods;
+
+
+typedef struct CustomExecMethods
+{
+ const char *CustomName;
+
+ /* Executor methods: mark/restore are optional, the rest are required */
+ void (*BeginCustomScan) (CustomScanState *node,
+ EState *estate,
+ int eflags);
+ TupleTableSlot *(*ExecCustomScan) (CustomScanState *node);
+ void (*EndCustomScan) (CustomScanState *node);
+ void (*ReScanCustomScan) (CustomScanState *node);
+ void (*MarkPosCustomScan) (CustomScanState *node);
+ void (*RestrPosCustomScan) (CustomScanState *node);
+ /* Optional: parallel execution support */
+ Size (*EstimateDSMCustomScan) (CustomScanState *node,
+ ParallelContext *pcxt);
+ void (*InitializeDSMCustomScan) (CustomScanState *node,
+ ParallelContext *pcxt,
+ void *coordinate);
+ void (*InitializeWorkerCustomScan) (CustomScanState *node,
+ shm_toc *toc,
+ void *coordinate);
+ /* Optional: print additional information in EXPLAIN */
+ void (*ExplainCustomScan) (CustomScanState *node,
+ List *ancestors,
+ ExplainState *es);
+} CustomExecMethods;
+
+/*
+ * Serialization/Deserialization Support
+ */
+extern void RegisterCustomScanMethods(const CustomScanMethods *methods);
+extern const CustomScanMethods *GetCustomScanMethods(const char *CustomName,
+ bool missing_ok);
+
+#endif /* CUSTOM_APIS_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 064a050..cfcd8348 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1604,38 +1604,7 @@ typedef struct ForeignScanState
* the BeginCustomScan method.
* ----------------
*/
-struct ParallelContext; /* avoid including parallel.h here */
-struct shm_toc; /* avoid including shm_toc.h here */
-struct ExplainState; /* avoid including explain.h here */
-struct CustomScanState;
-
-typedef struct CustomExecMethods
-{
- const char *CustomName;
-
- /* Executor methods: mark/restore are optional, the rest are required */
- void (*BeginCustomScan) (struct CustomScanState *node,
- EState *estate,
- int eflags);
- TupleTableSlot *(*ExecCustomScan) (struct CustomScanState *node);
- void (*EndCustomScan) (struct CustomScanState *node);
- void (*ReScanCustomScan) (struct CustomScanState *node);
- void (*MarkPosCustomScan) (struct CustomScanState *node);
- void (*RestrPosCustomScan) (struct CustomScanState *node);
- /* Optional: parallel execution support */
- Size (*EstimateDSMCustomScan) (struct CustomScanState *node,
- struct ParallelContext *pcxt);
- void (*InitializeDSMCustomScan) (struct CustomScanState *node,
- struct ParallelContext *pcxt,
- void *coordinate);
- void (*InitializeWorkerCustomScan) (struct CustomScanState *node,
- struct shm_toc *toc,
- void *coordinate);
- /* Optional: print additional information in EXPLAIN */
- void (*ExplainCustomScan) (struct CustomScanState *node,
- List *ancestors,
- struct ExplainState *es);
-} CustomExecMethods;
+struct CustomExecMethods;
typedef struct CustomScanState
{
@@ -1643,7 +1612,7 @@ typedef struct CustomScanState
uint32 flags; /* mask of CUSTOMPATH_* flags, see relation.h */
List *custom_ps; /* list of child PlanState nodes, if any */
Size pscan_len; /* size of parallel coordination information */
- const CustomExecMethods *methods;
+ const struct CustomExecMethods *methods;
} CustomScanState;
/* ----------------------------------------------------------------
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index ae224cf..21e4a45 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -553,17 +553,7 @@ typedef struct ForeignScan
* a larger struct will not work.
* ----------------
*/
-struct CustomScan;
-
-typedef struct CustomScanMethods
-{
- const char *CustomName;
- const char *LibraryName;
- const char *SymbolName;
-
- /* Create execution state (CustomScanState) from a CustomScan plan node */
- Node *(*CreateCustomScanState) (struct CustomScan *cscan);
-} CustomScanMethods;
+struct CustomScanMethods;
typedef struct CustomScan
{
@@ -575,7 +565,7 @@ typedef struct CustomScan
List *custom_scan_tlist; /* optional tlist describing scan
* tuple */
Bitmapset *custom_relids; /* RTIs generated by this scan */
- const CustomScanMethods *methods;
+ const struct CustomScanMethods *methods;
} CustomScan;
/*
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index af8cb6b..c64f5fa 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -972,23 +972,8 @@ typedef struct ForeignPath
* FDW case, we provide a "custom_private" field in CustomPath; providers
* may prefer to use that rather than define another struct type.
*/
-struct CustomPath;
-#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN 0x0001
-#define CUSTOMPATH_SUPPORT_MARK_RESTORE 0x0002
-
-typedef struct CustomPathMethods
-{
- const char *CustomName;
-
- /* Convert Path to a Plan */
- struct Plan *(*PlanCustomPath) (PlannerInfo *root,
- RelOptInfo *rel,
- struct CustomPath *best_path,
- List *tlist,
- List *clauses,
- List *custom_plans);
-} CustomPathMethods;
+struct CustomPathMethods;
typedef struct CustomPath
{
@@ -996,7 +981,7 @@ typedef struct CustomPath
uint32 flags; /* mask of CUSTOMPATH_* flags, see above */
List *custom_paths; /* list of child Path nodes, if any */
List *custom_private;
- const CustomPathMethods *methods;
+ const struct CustomPathMethods *methods;
} CustomPath;
/*
Hi,
On 29/02/16 13:07, Kouhei Kaigai wrote:
I'd like to adjust a few of custom-scan interface prior to v9.6 freeze.
The major point is serialization/deserialization mechanism.
Now, extension has to give LibraryName and SymbolName to reproduce
same CustomScanMethods on the background worker process side. Indeed,
it is sufficient information to pull the table of function pointers.On the other hands, we now have different mechanism to wrap private
information - extensible node. It requires extensions to register its
ExtensibleNodeMethods identified by name, usually, on _PG_init() time.
It is also reasonable way to reproduce same objects on background
worker side.However, mixture of two different ways is not good. My preference is
what extensible-node is doing rather than what custom-scan is currently
doing.
The attached patch allows extension to register CustomScanMethods once,
then readFunc.c can pull this table by CustomName in string form.
Agreed, but this will break compatibility right?
I'm not 100% certain whether "nodes/custom-apis.h" is the best location,
but somewhere we can put these declarations rather than the primitive
header files might be needed.
custom-apis.c does not sound like right name to me, maybe it can be just
custom.c but custom.h might be bit too generic, maybe custom_node.h
I am not sure I like the fact that we have this EXTNODENAME_MAX_LEN and
now the CUSTOM_NAME_MAX_LEN with the same length and also they are both
same lenght as NAMEDATALEN I wonder if this shouldn't be somehow
squished to less defines.
Also in RegisterCustomScanMethods
+ Assert(strlen(methods->CustomName) <= CUSTOM_NAME_MAX_LEN);
Shouldn't this be actually "if" with ereport() considering this is
public API and extensions can pass anything there? (for that matter same
is true for RegisterExtensibleNodeMethods but that's already committed).
Other than that this seems like straight conversion to same basic
template as extensible nodes so I think it's ok.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 29/02/16 13:07, Kouhei Kaigai wrote:
I'd like to adjust a few of custom-scan interface prior to v9.6 freeze.
The major point is serialization/deserialization mechanism.
Now, extension has to give LibraryName and SymbolName to reproduce
same CustomScanMethods on the background worker process side. Indeed,
it is sufficient information to pull the table of function pointers.On the other hands, we now have different mechanism to wrap private
information - extensible node. It requires extensions to register its
ExtensibleNodeMethods identified by name, usually, on _PG_init() time.
It is also reasonable way to reproduce same objects on background
worker side.However, mixture of two different ways is not good. My preference is
what extensible-node is doing rather than what custom-scan is currently
doing.
The attached patch allows extension to register CustomScanMethods once,
then readFunc.c can pull this table by CustomName in string form.Agreed, but this will break compatibility right?
The manner to pass a pair of library-name and symbol-name is a new feature
in v9.6, not in v9.5, so it is now the last chance to fix up the interface
requirement.
I'm not 100% certain whether "nodes/custom-apis.h" is the best location,
but somewhere we can put these declarations rather than the primitive
header files might be needed.custom-apis.c does not sound like right name to me, maybe it can be just
custom.c but custom.h might be bit too generic, maybe custom_node.h
OK, custom_node.h may be better.
I am not sure I like the fact that we have this EXTNODENAME_MAX_LEN and
now the CUSTOM_NAME_MAX_LEN with the same length and also they are both
same lenght as NAMEDATALEN I wonder if this shouldn't be somehow
squished to less defines.
Hmm. I just followed the manner in extensible.c, because this label was
initially NAMEDATALEN, then Robert changed it with EXTNODENAME_MAX_LEN.
I guess he avoid to apply same label on different entities - NAMEDATALEN
is a limitation for NameData type, but identifier of extensible-node and
custom-scan node are not restricted by.
Also in RegisterCustomScanMethods
+ Assert(strlen(methods->CustomName) <= CUSTOM_NAME_MAX_LEN);Shouldn't this be actually "if" with ereport() considering this is
public API and extensions can pass anything there? (for that matter same
is true for RegisterExtensibleNodeMethods but that's already committed).
Hmm. I don't have clear answer which is better. The reason why I put
Assert() here is that only c-binary extension uses this interface, thus,
author will fix up the problem of too long name prior to its release.
Of course, if-with-ereport() also informs extension author the name is
too long.
One downside of Assert() may be, it makes oversight if --enable-cassert
was not specified.
Other than that this seems like straight conversion to same basic
template as extensible nodes so I think it's ok.
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
On 10/03/16 02:18, Kouhei Kaigai wrote:
I am not sure I like the fact that we have this EXTNODENAME_MAX_LEN and
now the CUSTOM_NAME_MAX_LEN with the same length and also they are both
same lenght as NAMEDATALEN I wonder if this shouldn't be somehow
squished to less defines.Hmm. I just followed the manner in extensible.c, because this label was
initially NAMEDATALEN, then Robert changed it with EXTNODENAME_MAX_LEN.
I guess he avoid to apply same label on different entities - NAMEDATALEN
is a limitation for NameData type, but identifier of extensible-node and
custom-scan node are not restricted by.
Makes sense.
Also in RegisterCustomScanMethods
+ Assert(strlen(methods->CustomName) <= CUSTOM_NAME_MAX_LEN);Shouldn't this be actually "if" with ereport() considering this is
public API and extensions can pass anything there? (for that matter same
is true for RegisterExtensibleNodeMethods but that's already committed).Hmm. I don't have clear answer which is better. The reason why I put
Assert() here is that only c-binary extension uses this interface, thus,
author will fix up the problem of too long name prior to its release.
Of course, if-with-ereport() also informs extension author the name is
too long.
One downside of Assert() may be, it makes oversight if --enable-cassert
was not specified.
Well that's exactly my problem, this should IMHO throw error even
without --enable-cassert. It's not like it's some performance sensitive
API where if would be big problem, ensuring correctness of the input is
more imporant here IMHO.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
-----Original Message-----
From: pgsql-hackers-owner@postgresql.org
[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Petr Jelinek
Sent: Thursday, March 10, 2016 11:01 AM
To: Kaigai Kouhei(海外 浩平); pgsql-hackers@postgresql.org
Subject: Re: [HACKERS] Reworks of CustomScan serialization/deserializationOn 10/03/16 02:18, Kouhei Kaigai wrote:
I am not sure I like the fact that we have this EXTNODENAME_MAX_LEN and
now the CUSTOM_NAME_MAX_LEN with the same length and also they are both
same lenght as NAMEDATALEN I wonder if this shouldn't be somehow
squished to less defines.Hmm. I just followed the manner in extensible.c, because this label was
initially NAMEDATALEN, then Robert changed it with EXTNODENAME_MAX_LEN.
I guess he avoid to apply same label on different entities - NAMEDATALEN
is a limitation for NameData type, but identifier of extensible-node and
custom-scan node are not restricted by.Makes sense.
Also in RegisterCustomScanMethods
+ Assert(strlen(methods->CustomName) <= CUSTOM_NAME_MAX_LEN);Shouldn't this be actually "if" with ereport() considering this is
public API and extensions can pass anything there? (for that matter same
is true for RegisterExtensibleNodeMethods but that's already committed).Hmm. I don't have clear answer which is better. The reason why I put
Assert() here is that only c-binary extension uses this interface, thus,
author will fix up the problem of too long name prior to its release.
Of course, if-with-ereport() also informs extension author the name is
too long.
One downside of Assert() may be, it makes oversight if --enable-cassert
was not specified.Well that's exactly my problem, this should IMHO throw error even
without --enable-cassert. It's not like it's some performance sensitive
API where if would be big problem, ensuring correctness of the input is
more imporant here IMHO.
We may need to fix up RegisterExtensibleNodeMethods() first.
Also, length limitation is (EXTNODENAME_MAX_LEN-1) because the last byte
is consumed by '\0' character. In fact, hash, match and keycopy function
of HTAB for string keys deal with the first (keysize - 1) bytes.
So, strkey(extnodename) == EXTNODENAME_MAX_LEN is not legal.
Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>
Attachments:
pgsql-v9.6-extensible-namelen-check-by-ereport.patchapplication/octet-stream; name=pgsql-v9.6-extensible-namelen-check-by-ereport.patchDownload
src/backend/nodes/extensible.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/backend/nodes/extensible.c b/src/backend/nodes/extensible.c
index e78a12b..87c6f1b 100644
--- a/src/backend/nodes/extensible.c
+++ b/src/backend/nodes/extensible.c
@@ -51,7 +51,10 @@ RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *methods)
100, &ctl, HASH_ELEM);
}
- Assert(strlen(methods->extnodename) <= EXTNODENAME_MAX_LEN);
+ if (strlen(methods->extnodename) >= EXTNODENAME_MAX_LEN)
+ ereport(ERROR,
+ (errcode(ERRCODE_NAME_TOO_LONG),
+ errmsg("name of extensible node too long")));
entry = (ExtensibleNodeEntry *) hash_search(extensible_node_methods,
methods->extnodename,
On 10/03/16 08:08, Kouhei Kaigai wrote:
Also in RegisterCustomScanMethods
+ Assert(strlen(methods->CustomName) <= CUSTOM_NAME_MAX_LEN);Shouldn't this be actually "if" with ereport() considering this is
public API and extensions can pass anything there? (for that matter same
is true for RegisterExtensibleNodeMethods but that's already committed).Hmm. I don't have clear answer which is better. The reason why I put
Assert() here is that only c-binary extension uses this interface, thus,
author will fix up the problem of too long name prior to its release.
Of course, if-with-ereport() also informs extension author the name is
too long.
One downside of Assert() may be, it makes oversight if --enable-cassert
was not specified.Well that's exactly my problem, this should IMHO throw error even
without --enable-cassert. It's not like it's some performance sensitive
API where if would be big problem, ensuring correctness of the input is
more imporant here IMHO.We may need to fix up RegisterExtensibleNodeMethods() first.
Also, length limitation is (EXTNODENAME_MAX_LEN-1) because the last byte
is consumed by '\0' character. In fact, hash, match and keycopy function
of HTAB for string keys deal with the first (keysize - 1) bytes.
So, strkey(extnodename) == EXTNODENAME_MAX_LEN is not legal.
Yes, my thoughts as well but that can be separate tiny patch that does
not have to affect this one. In my opinion if we fixed this one it would
be otherwise ready to go in, and I definitely prefer this approach to
the previous one.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
-----Original Message-----
From: pgsql-hackers-owner@postgresql.org
[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Petr Jelinek
Sent: Friday, March 11, 2016 12:27 AM
To: Kaigai Kouhei(海外 浩平); pgsql-hackers@postgresql.org
Subject: Re: [HACKERS] Reworks of CustomScan serialization/deserializationOn 10/03/16 08:08, Kouhei Kaigai wrote:
Also in RegisterCustomScanMethods
+ Assert(strlen(methods->CustomName) <= CUSTOM_NAME_MAX_LEN);Shouldn't this be actually "if" with ereport() considering this is
public API and extensions can pass anything there? (for that matter same
is true for RegisterExtensibleNodeMethods but that's already committed).Hmm. I don't have clear answer which is better. The reason why I put
Assert() here is that only c-binary extension uses this interface, thus,
author will fix up the problem of too long name prior to its release.
Of course, if-with-ereport() also informs extension author the name is
too long.
One downside of Assert() may be, it makes oversight if --enable-cassert
was not specified.Well that's exactly my problem, this should IMHO throw error even
without --enable-cassert. It's not like it's some performance sensitive
API where if would be big problem, ensuring correctness of the input is
more imporant here IMHO.We may need to fix up RegisterExtensibleNodeMethods() first.
Also, length limitation is (EXTNODENAME_MAX_LEN-1) because the last byte
is consumed by '\0' character. In fact, hash, match and keycopy function
of HTAB for string keys deal with the first (keysize - 1) bytes.
So, strkey(extnodename) == EXTNODENAME_MAX_LEN is not legal.Yes, my thoughts as well but that can be separate tiny patch that does
not have to affect this one. In my opinion if we fixed this one it would
be otherwise ready to go in, and I definitely prefer this approach to
the previous one.
OK, I split the previous small patch into two tiny patches.
The one is bugfix around max length of the extnodename.
The other replaces Assert() by ereport() according to the upthread discussion.
Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>
Attachments:
pgsql-v9.6-fix-extnodename-max-len.patchapplication/octet-stream; name=pgsql-v9.6-fix-extnodename-max-len.patchDownload
src/backend/nodes/extensible.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/backend/nodes/extensible.c b/src/backend/nodes/extensible.c
index e78a12b..6035cf8 100644
--- a/src/backend/nodes/extensible.c
+++ b/src/backend/nodes/extensible.c
@@ -51,7 +51,7 @@ RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *methods)
100, &ctl, HASH_ELEM);
}
- Assert(strlen(methods->extnodename) <= EXTNODENAME_MAX_LEN);
+ Assert(strlen(methods->extnodename) < EXTNODENAME_MAX_LEN);
entry = (ExtensibleNodeEntry *) hash_search(extensible_node_methods,
methods->extnodename,
pgsql-v9.6-replace-assert-by-ereport-on-register-extnode.patchapplication/octet-stream; name=pgsql-v9.6-replace-assert-by-ereport-on-register-extnode.patchDownload
src/backend/nodes/extensible.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/backend/nodes/extensible.c b/src/backend/nodes/extensible.c
index 6035cf8..87c6f1b 100644
--- a/src/backend/nodes/extensible.c
+++ b/src/backend/nodes/extensible.c
@@ -51,7 +51,10 @@ RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *methods)
100, &ctl, HASH_ELEM);
}
- Assert(strlen(methods->extnodename) < EXTNODENAME_MAX_LEN);
+ if (strlen(methods->extnodename) >= EXTNODENAME_MAX_LEN)
+ ereport(ERROR,
+ (errcode(ERRCODE_NAME_TOO_LONG),
+ errmsg("name of extensible node too long")));
entry = (ExtensibleNodeEntry *) hash_search(extensible_node_methods,
methods->extnodename,
On 14/03/16 02:53, Kouhei Kaigai wrote:
-----Original Message-----
From: pgsql-hackers-owner@postgresql.org
[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Petr Jelinek
Sent: Friday, March 11, 2016 12:27 AM
To: Kaigai Kouhei(海外 浩平); pgsql-hackers@postgresql.org
Subject: Re: [HACKERS] Reworks of CustomScan serialization/deserializationOn 10/03/16 08:08, Kouhei Kaigai wrote:
Also in RegisterCustomScanMethods
+ Assert(strlen(methods->CustomName) <= CUSTOM_NAME_MAX_LEN);Shouldn't this be actually "if" with ereport() considering this is
public API and extensions can pass anything there? (for that matter same
is true for RegisterExtensibleNodeMethods but that's already committed).Hmm. I don't have clear answer which is better. The reason why I put
Assert() here is that only c-binary extension uses this interface, thus,
author will fix up the problem of too long name prior to its release.
Of course, if-with-ereport() also informs extension author the name is
too long.
One downside of Assert() may be, it makes oversight if --enable-cassert
was not specified.Well that's exactly my problem, this should IMHO throw error even
without --enable-cassert. It's not like it's some performance sensitive
API where if would be big problem, ensuring correctness of the input is
more imporant here IMHO.We may need to fix up RegisterExtensibleNodeMethods() first.
Also, length limitation is (EXTNODENAME_MAX_LEN-1) because the last byte
is consumed by '\0' character. In fact, hash, match and keycopy function
of HTAB for string keys deal with the first (keysize - 1) bytes.
So, strkey(extnodename) == EXTNODENAME_MAX_LEN is not legal.Yes, my thoughts as well but that can be separate tiny patch that does
not have to affect this one. In my opinion if we fixed this one it would
be otherwise ready to go in, and I definitely prefer this approach to
the previous one.OK, I split the previous small patch into two tiny patches.
The one is bugfix around max length of the extnodename.
The other replaces Assert() by ereport() according to the upthread discussion.
Okay, it's somewhat akin to hairsplitting but works for me. Do you plan
to do same thing with the CustomScan patch itself as well?.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 14/03/16 02:53, Kouhei Kaigai wrote:
-----Original Message-----
From: pgsql-hackers-owner@postgresql.org
[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Petr Jelinek
Sent: Friday, March 11, 2016 12:27 AM
To: Kaigai Kouhei(海外 浩平); pgsql-hackers@postgresql.org
Subject: Re: [HACKERS] Reworks of CustomScan serialization/deserializationOn 10/03/16 08:08, Kouhei Kaigai wrote:
Also in RegisterCustomScanMethods
+ Assert(strlen(methods->CustomName) <= CUSTOM_NAME_MAX_LEN);Shouldn't this be actually "if" with ereport() considering this is
public API and extensions can pass anything there? (for that matter same
is true for RegisterExtensibleNodeMethods but that's already committed).Hmm. I don't have clear answer which is better. The reason why I put
Assert() here is that only c-binary extension uses this interface, thus,
author will fix up the problem of too long name prior to its release.
Of course, if-with-ereport() also informs extension author the name is
too long.
One downside of Assert() may be, it makes oversight if --enable-cassert
was not specified.Well that's exactly my problem, this should IMHO throw error even
without --enable-cassert. It's not like it's some performance sensitive
API where if would be big problem, ensuring correctness of the input is
more imporant here IMHO.We may need to fix up RegisterExtensibleNodeMethods() first.
Also, length limitation is (EXTNODENAME_MAX_LEN-1) because the last byte
is consumed by '\0' character. In fact, hash, match and keycopy function
of HTAB for string keys deal with the first (keysize - 1) bytes.
So, strkey(extnodename) == EXTNODENAME_MAX_LEN is not legal.Yes, my thoughts as well but that can be separate tiny patch that does
not have to affect this one. In my opinion if we fixed this one it would
be otherwise ready to go in, and I definitely prefer this approach to
the previous one.OK, I split the previous small patch into two tiny patches.
The one is bugfix around max length of the extnodename.
The other replaces Assert() by ereport() according to the upthread discussion.Okay, it's somewhat akin to hairsplitting but works for me. Do you plan
to do same thing with the CustomScan patch itself as well?.
Yes. I'll fixup the patch to follow the same manner.
--
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
On Sun, Mar 13, 2016 at 9:53 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:
OK, I split the previous small patch into two tiny patches.
The one is bugfix around max length of the extnodename.
The other replaces Assert() by ereport() according to the upthread discussion.
Committed, except that (1) I replaced ereport() with elog(), because I
can't see making translators care about this message; and (2) I
reworded the error message a bit.
--
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
On Sun, Mar 13, 2016 at 9:53 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:
OK, I split the previous small patch into two tiny patches.
The one is bugfix around max length of the extnodename.
The other replaces Assert() by ereport() according to the upthread discussion.Committed, except that (1) I replaced ereport() with elog(), because I
can't see making translators care about this message; and (2) I
reworded the error message a bit.
Thanks, and I got the point why ereport() is suggested for the error
message that may be visible to users, instead of elog().
--
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
Import Notes
Resolved by subject fallback
Petr,
The attached patch is the revised one that follows the new extensible-
node routine.
It is almost same the previous version except for:
- custom-apis.[ch] was renamed to custom-node.[ch]
- check for the length of custom-scan-method name followed
the manner of RegisterExtensibleNodeMethods()
Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>
Show quoted text
-----Original Message-----
From: Robert Haas [mailto:robertmhaas@gmail.com]
Sent: Tuesday, March 15, 2016 2:54 AM
To: Kaigai Kouhei(海外 浩平)
Cc: Petr Jelinek; pgsql-hackers@postgresql.org
Subject: ##freemail## Re: [HACKERS] Reworks of CustomScan
serialization/deserializationOn Sun, Mar 13, 2016 at 9:53 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:
OK, I split the previous small patch into two tiny patches.
The one is bugfix around max length of the extnodename.
The other replaces Assert() by ereport() according to the upthread discussion.Committed, except that (1) I replaced ereport() with elog(), because I
can't see making translators care about this message; and (2) I
reworded the error message a bit.--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Attachments:
pgsql-v9.6-custom-scan-serialization-reworks.2.patchapplication/octet-stream; name=pgsql-v9.6-custom-scan-serialization-reworks.2.patchDownload
src/backend/commands/explain.c | 1 +
src/backend/nodes/Makefile | 3 +-
src/backend/nodes/copyfuncs.c | 1 +
src/backend/nodes/custom-node.c | 84 +++++++++++++++++++++++++++++++
src/backend/nodes/outfuncs.c | 7 ++-
src/backend/nodes/readfuncs.c | 20 +++-----
src/backend/optimizer/plan/createplan.c | 1 +
src/include/executor/nodeCustom.h | 1 +
src/include/nodes/custom-node.h | 87 +++++++++++++++++++++++++++++++++
src/include/nodes/execnodes.h | 35 +------------
src/include/nodes/plannodes.h | 14 +-----
src/include/nodes/relation.h | 19 +------
12 files changed, 192 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 9cd3127..4e0a50c 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -21,6 +21,7 @@
#include "commands/prepare.h"
#include "executor/hashjoin.h"
#include "foreign/fdwapi.h"
+#include "nodes/custom-node.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
diff --git a/src/backend/nodes/Makefile b/src/backend/nodes/Makefile
index 0b1e98c..89f0268 100644
--- a/src/backend/nodes/Makefile
+++ b/src/backend/nodes/Makefile
@@ -14,6 +14,7 @@ include $(top_builddir)/src/Makefile.global
OBJS = nodeFuncs.o nodes.o list.o bitmapset.o tidbitmap.o \
copyfuncs.o equalfuncs.o extensible.o makefuncs.o \
- outfuncs.o readfuncs.o print.o read.o params.o value.o
+ outfuncs.o readfuncs.o print.o read.o params.o value.o custom-node.o
+
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index df7c2fa..007b358 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -23,6 +23,7 @@
#include "postgres.h"
#include "miscadmin.h"
+#include "nodes/custom-node.h"
#include "nodes/extensible.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
diff --git a/src/backend/nodes/custom-node.c b/src/backend/nodes/custom-node.c
new file mode 100644
index 0000000..067a831
--- /dev/null
+++ b/src/backend/nodes/custom-node.c
@@ -0,0 +1,84 @@
+/*-------------------------------------------------------------------------
+ *
+ * custom-node.c
+ * Support for custom-path/scan/exec node types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * src/backend/nodes/custom-node.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "nodes/custom-node.h"
+#include "utils/hsearch.h"
+
+static HTAB *custom_scan_methods = NULL;
+
+typedef struct
+{
+ char CustomName[CUSTOM_NAME_MAX_LEN];
+ const CustomScanMethods *methods;
+} CustomScanMethodsEntry;
+
+/*
+ * Register a new custom scan methods
+ */
+void
+RegisterCustomScanMethods(const CustomScanMethods *methods)
+{
+ CustomScanMethodsEntry *entry;
+ bool found;
+
+ if (custom_scan_methods == NULL)
+ {
+ HASHCTL ctl;
+
+ memset(&ctl, 0, sizeof(HASHCTL));
+ ctl.keysize = CUSTOM_NAME_MAX_LEN;
+ ctl.entrysize = sizeof(CustomScanMethodsEntry);
+ custom_scan_methods = hash_create("Custom Scan Methods",
+ 100, &ctl, HASH_ELEM);
+ }
+
+ if (strlen(methods->CustomName) >= CUSTOM_NAME_MAX_LEN)
+ elog(ERROR, "CustomScanMethods name is too long");
+
+ entry = (CustomScanMethodsEntry *) hash_search(custom_scan_methods,
+ methods->CustomName,
+ HASH_ENTER, &found);
+ if (found)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("CustomScanMethods \"%s\" already exists",
+ methods->CustomName)));
+
+ entry->methods = methods;
+}
+
+/*
+ * Get the methods for a given name of CustomScanMethods
+ */
+const CustomScanMethods *
+GetCustomScanMethods(const char *CustomName, bool missing_ok)
+{
+ CustomScanMethodsEntry *entry = NULL;
+
+ if (custom_scan_methods != NULL)
+ entry = (CustomScanMethodsEntry *) hash_search(custom_scan_methods,
+ CustomName,
+ HASH_FIND, NULL);
+ if (!entry)
+ {
+ if (missing_ok)
+ return NULL;
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("CustomScanMethods \"%s\" was not registered",
+ CustomName)));
+ }
+ return entry->methods;
+}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 548a3b9..7d8c95a 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -26,6 +26,7 @@
#include <ctype.h>
#include "lib/stringinfo.h"
+#include "nodes/custom-node.h"
#include "nodes/extensible.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
@@ -630,11 +631,9 @@ _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 */
+ /* CustomName is a key to lookup CustomScanMethods */
appendStringInfoString(str, " :methods ");
- _outToken(str, node->methods->LibraryName);
- appendStringInfoChar(str, ' ');
- _outToken(str, node->methods->SymbolName);
+ _outToken(str, node->methods->CustomName);
}
static void
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index a2c2243..e745f75 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -29,6 +29,7 @@
#include <math.h>
#include "fmgr.h"
+#include "nodes/custom-node.h"
#include "nodes/extensible.h"
#include "nodes/parsenodes.h"
#include "nodes/plannodes.h"
@@ -1824,8 +1825,7 @@ static CustomScan *
_readCustomScan(void)
{
READ_LOCALS(CustomScan);
- char *library_name;
- char *symbol_name;
+ char *custom_name;
const CustomScanMethods *methods;
ReadCommonScan(&local_node->scan);
@@ -1837,19 +1837,11 @@ _readCustomScan(void)
READ_NODE_FIELD(custom_scan_tlist);
READ_BITMAPSET_FIELD(custom_relids);
- /*
- * Reconstruction of methods using library and symbol name
- */
+ /* Lookup CustomScanMethods by CustomName */
token = pg_strtok(&length); /* skip methods: */
- token = pg_strtok(&length); /* LibraryName */
- library_name = nullable_string(token, length);
- token = pg_strtok(&length); /* SymbolName */
- symbol_name = nullable_string(token, length);
-
- methods = (const CustomScanMethods *)
- load_external_function(library_name, symbol_name, true, NULL);
- Assert(strcmp(methods->LibraryName, library_name) == 0 &&
- strcmp(methods->SymbolName, symbol_name) == 0);
+ token = pg_strtok(&length); /* CustomName */
+ custom_name = nullable_string(token, length);
+ methods = GetCustomScanMethods(custom_name, false);
local_node->methods = methods;
READ_DONE();
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index e37bdfd..068c6ed 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -24,6 +24,7 @@
#include "catalog/pg_class.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
+#include "nodes/custom-node.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
diff --git a/src/include/executor/nodeCustom.h b/src/include/executor/nodeCustom.h
index 410a3ad..08effc9 100644
--- a/src/include/executor/nodeCustom.h
+++ b/src/include/executor/nodeCustom.h
@@ -13,6 +13,7 @@
#define NODECUSTOM_H
#include "access/parallel.h"
+#include "nodes/custom-node.h"
#include "nodes/execnodes.h"
/*
diff --git a/src/include/nodes/custom-node.h b/src/include/nodes/custom-node.h
new file mode 100644
index 0000000..3b6f48c
--- /dev/null
+++ b/src/include/nodes/custom-node.h
@@ -0,0 +1,87 @@
+/*-------------------------------------------------------------------------
+ *
+ * custom-node.h
+ * Definitions for custom-path/scan/exec-methods
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef CUSTOM_APIS_H
+#define CUSTOM_APIS_H
+
+#include "access/parallel.h"
+#include "commands/explain.h"
+#include "nodes/execnodes.h"
+#include "nodes/plannodes.h"
+#include "nodes/relation.h"
+
+/*
+ * Flags definitions
+ */
+#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN 0x0001
+#define CUSTOMPATH_SUPPORT_MARK_RESTORE 0x0002
+
+
+#define CUSTOM_NAME_MAX_LEN 64
+
+typedef struct CustomPathMethods
+{
+ const char *CustomName;
+
+ /* Convert Path to a Plan */
+ struct Plan *(*PlanCustomPath) (PlannerInfo *root,
+ RelOptInfo *rel,
+ struct CustomPath *best_path,
+ List *tlist,
+ List *clauses,
+ List *custom_plans);
+} CustomPathMethods;
+
+
+typedef struct CustomScanMethods
+{
+ const char *CustomName;
+
+ /* Create execution state (CustomScanState) from a CustomScan plan node */
+ Node *(*CreateCustomScanState) (CustomScan *cscan);
+} CustomScanMethods;
+
+
+typedef struct CustomExecMethods
+{
+ const char *CustomName;
+
+ /* Executor methods: mark/restore are optional, the rest are required */
+ void (*BeginCustomScan) (CustomScanState *node,
+ EState *estate,
+ int eflags);
+ TupleTableSlot *(*ExecCustomScan) (CustomScanState *node);
+ void (*EndCustomScan) (CustomScanState *node);
+ void (*ReScanCustomScan) (CustomScanState *node);
+ void (*MarkPosCustomScan) (CustomScanState *node);
+ void (*RestrPosCustomScan) (CustomScanState *node);
+ /* Optional: parallel execution support */
+ Size (*EstimateDSMCustomScan) (CustomScanState *node,
+ ParallelContext *pcxt);
+ void (*InitializeDSMCustomScan) (CustomScanState *node,
+ ParallelContext *pcxt,
+ void *coordinate);
+ void (*InitializeWorkerCustomScan) (CustomScanState *node,
+ shm_toc *toc,
+ void *coordinate);
+ /* Optional: print additional information in EXPLAIN */
+ void (*ExplainCustomScan) (CustomScanState *node,
+ List *ancestors,
+ ExplainState *es);
+} CustomExecMethods;
+
+/*
+ * Serialization/Deserialization Support
+ */
+extern void RegisterCustomScanMethods(const CustomScanMethods *methods);
+extern const CustomScanMethods *GetCustomScanMethods(const char *CustomName,
+ bool missing_ok);
+
+#endif /* CUSTOM_APIS_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index d35ec81..20a8741 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1604,38 +1604,7 @@ typedef struct ForeignScanState
* the BeginCustomScan method.
* ----------------
*/
-struct ParallelContext; /* avoid including parallel.h here */
-struct shm_toc; /* avoid including shm_toc.h here */
-struct ExplainState; /* avoid including explain.h here */
-struct CustomScanState;
-
-typedef struct CustomExecMethods
-{
- const char *CustomName;
-
- /* Executor methods: mark/restore are optional, the rest are required */
- void (*BeginCustomScan) (struct CustomScanState *node,
- EState *estate,
- int eflags);
- TupleTableSlot *(*ExecCustomScan) (struct CustomScanState *node);
- void (*EndCustomScan) (struct CustomScanState *node);
- void (*ReScanCustomScan) (struct CustomScanState *node);
- void (*MarkPosCustomScan) (struct CustomScanState *node);
- void (*RestrPosCustomScan) (struct CustomScanState *node);
- /* Optional: parallel execution support */
- Size (*EstimateDSMCustomScan) (struct CustomScanState *node,
- struct ParallelContext *pcxt);
- void (*InitializeDSMCustomScan) (struct CustomScanState *node,
- struct ParallelContext *pcxt,
- void *coordinate);
- void (*InitializeWorkerCustomScan) (struct CustomScanState *node,
- struct shm_toc *toc,
- void *coordinate);
- /* Optional: print additional information in EXPLAIN */
- void (*ExplainCustomScan) (struct CustomScanState *node,
- List *ancestors,
- struct ExplainState *es);
-} CustomExecMethods;
+struct CustomExecMethods;
typedef struct CustomScanState
{
@@ -1643,7 +1612,7 @@ typedef struct CustomScanState
uint32 flags; /* mask of CUSTOMPATH_* flags, see relation.h */
List *custom_ps; /* list of child PlanState nodes, if any */
Size pscan_len; /* size of parallel coordination information */
- const CustomExecMethods *methods;
+ const struct CustomExecMethods *methods;
} CustomScanState;
/* ----------------------------------------------------------------
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 5961f2c..bace977 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -553,17 +553,7 @@ typedef struct ForeignScan
* a larger struct will not work.
* ----------------
*/
-struct CustomScan;
-
-typedef struct CustomScanMethods
-{
- const char *CustomName;
- const char *LibraryName;
- const char *SymbolName;
-
- /* Create execution state (CustomScanState) from a CustomScan plan node */
- Node *(*CreateCustomScanState) (struct CustomScan *cscan);
-} CustomScanMethods;
+struct CustomScanMethods;
typedef struct CustomScan
{
@@ -575,7 +565,7 @@ typedef struct CustomScan
List *custom_scan_tlist; /* optional tlist describing scan
* tuple */
Bitmapset *custom_relids; /* RTIs generated by this scan */
- const CustomScanMethods *methods;
+ const struct CustomScanMethods *methods;
} CustomScan;
/*
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 5032696..e678f6f 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -1030,23 +1030,8 @@ typedef struct ForeignPath
* FDW case, we provide a "custom_private" field in CustomPath; providers
* may prefer to use that rather than define another struct type.
*/
-struct CustomPath;
-#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN 0x0001
-#define CUSTOMPATH_SUPPORT_MARK_RESTORE 0x0002
-
-typedef struct CustomPathMethods
-{
- const char *CustomName;
-
- /* Convert Path to a Plan */
- struct Plan *(*PlanCustomPath) (PlannerInfo *root,
- RelOptInfo *rel,
- struct CustomPath *best_path,
- List *tlist,
- List *clauses,
- List *custom_plans);
-} CustomPathMethods;
+struct CustomPathMethods;
typedef struct CustomPath
{
@@ -1054,7 +1039,7 @@ typedef struct CustomPath
uint32 flags; /* mask of CUSTOMPATH_* flags, see above */
List *custom_paths; /* list of child Path nodes, if any */
List *custom_private;
- const CustomPathMethods *methods;
+ const struct CustomPathMethods *methods;
} CustomPath;
/*
Import Notes
Resolved by subject fallback
On 15/03/16 05:03, Kouhei Kaigai wrote:
Petr,
The attached patch is the revised one that follows the new extensible-
node routine.It is almost same the previous version except for:
- custom-apis.[ch] was renamed to custom-node.[ch]
- check for the length of custom-scan-method name followed
the manner of RegisterExtensibleNodeMethods()
Hi,
looks good, only nitpick I have is that it probably should be
custom_node.h with underscore given that we use underscore everywhere
(except for libpq and for some reason atomic ops).
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
-----Original Message-----
From: pgsql-hackers-owner@postgresql.org
[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Petr Jelinek
Sent: Thursday, March 17, 2016 5:06 PM
To: Kaigai Kouhei(海外 浩平)
Cc: Robert Haas; pgsql-hackers@postgresql.org
Subject: Re: [HACKERS] Reworks of CustomScan serialization/deserializationOn 15/03/16 05:03, Kouhei Kaigai wrote:
Petr,
The attached patch is the revised one that follows the new extensible-
node routine.It is almost same the previous version except for:
- custom-apis.[ch] was renamed to custom-node.[ch]
- check for the length of custom-scan-method name followed
the manner of RegisterExtensibleNodeMethods()Hi,
looks good, only nitpick I have is that it probably should be
custom_node.h with underscore given that we use underscore everywhere
(except for libpq and for some reason atomic ops).
Sorry for my response late.
The attached patch just renamed custom-node.[ch] by custom_node.[ch].
Other portions are not changed from the previous revison.
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
On 23/03/16 08:34, Kouhei Kaigai wrote:
-----Original Message-----
From: pgsql-hackers-owner@postgresql.org
[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Petr Jelinek
Sent: Thursday, March 17, 2016 5:06 PM
To: Kaigai Kouhei(海外 浩平)
Cc: Robert Haas; pgsql-hackers@postgresql.org
Subject: Re: [HACKERS] Reworks of CustomScan serialization/deserializationOn 15/03/16 05:03, Kouhei Kaigai wrote:
Petr,
The attached patch is the revised one that follows the new extensible-
node routine.It is almost same the previous version except for:
- custom-apis.[ch] was renamed to custom-node.[ch]
- check for the length of custom-scan-method name followed
the manner of RegisterExtensibleNodeMethods()Hi,
looks good, only nitpick I have is that it probably should be
custom_node.h with underscore given that we use underscore everywhere
(except for libpq and for some reason atomic ops).Sorry for my response late.
The attached patch just renamed custom-node.[ch] by custom_node.[ch].
Other portions are not changed from the previous revison.
Forgot to attach?
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 15/03/16 05:03, Kouhei Kaigai wrote:
Petr,
The attached patch is the revised one that follows the new extensible-
node routine.It is almost same the previous version except for:
- custom-apis.[ch] was renamed to custom-node.[ch]
- check for the length of custom-scan-method name followed
the manner of RegisterExtensibleNodeMethods()Hi,
looks good, only nitpick I have is that it probably should be
custom_node.h with underscore given that we use underscore everywhere
(except for libpq and for some reason atomic ops).Sorry for my response late.
The attached patch just renamed custom-node.[ch] by custom_node.[ch].
Other portions are not changed from the previous revison.Forgot to attach?
Yes.... Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>
Attachments:
pgsql-v9.6-custom-scan-serialization-reworks.3.patchapplication/octet-stream; name=pgsql-v9.6-custom-scan-serialization-reworks.3.patchDownload
src/backend/commands/explain.c | 1 +
src/backend/nodes/Makefile | 3 +-
src/backend/nodes/copyfuncs.c | 1 +
src/backend/nodes/custom_node.c | 84 +++++++++++++++++++++++++++++++
src/backend/nodes/outfuncs.c | 7 ++-
src/backend/nodes/readfuncs.c | 20 +++-----
src/backend/optimizer/plan/createplan.c | 1 +
src/include/executor/nodeCustom.h | 1 +
src/include/nodes/custom_node.h | 87 +++++++++++++++++++++++++++++++++
src/include/nodes/execnodes.h | 35 +------------
src/include/nodes/plannodes.h | 14 +-----
src/include/nodes/relation.h | 19 +------
12 files changed, 192 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 787b0b9..8959f0f 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -21,6 +21,7 @@
#include "commands/prepare.h"
#include "executor/hashjoin.h"
#include "foreign/fdwapi.h"
+#include "nodes/custom_node.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
diff --git a/src/backend/nodes/Makefile b/src/backend/nodes/Makefile
index 0b1e98c..6219d92 100644
--- a/src/backend/nodes/Makefile
+++ b/src/backend/nodes/Makefile
@@ -14,6 +14,7 @@ include $(top_builddir)/src/Makefile.global
OBJS = nodeFuncs.o nodes.o list.o bitmapset.o tidbitmap.o \
copyfuncs.o equalfuncs.o extensible.o makefuncs.o \
- outfuncs.o readfuncs.o print.o read.o params.o value.o
+ outfuncs.o readfuncs.o print.o read.o params.o value.o custom_node.o
+
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 6b5d1d6..0a734d9 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -23,6 +23,7 @@
#include "postgres.h"
#include "miscadmin.h"
+#include "nodes/custom_node.h"
#include "nodes/extensible.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
diff --git a/src/backend/nodes/custom_node.c b/src/backend/nodes/custom_node.c
new file mode 100644
index 0000000..5c425a2
--- /dev/null
+++ b/src/backend/nodes/custom_node.c
@@ -0,0 +1,84 @@
+/*-------------------------------------------------------------------------
+ *
+ * custom_node.c
+ * Support for custom-path/scan/exec node types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * src/backend/nodes/custom_node.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "nodes/custom_node.h"
+#include "utils/hsearch.h"
+
+static HTAB *custom_scan_methods = NULL;
+
+typedef struct
+{
+ char CustomName[CUSTOM_NAME_MAX_LEN];
+ const CustomScanMethods *methods;
+} CustomScanMethodsEntry;
+
+/*
+ * Register a new custom scan methods
+ */
+void
+RegisterCustomScanMethods(const CustomScanMethods *methods)
+{
+ CustomScanMethodsEntry *entry;
+ bool found;
+
+ if (custom_scan_methods == NULL)
+ {
+ HASHCTL ctl;
+
+ memset(&ctl, 0, sizeof(HASHCTL));
+ ctl.keysize = CUSTOM_NAME_MAX_LEN;
+ ctl.entrysize = sizeof(CustomScanMethodsEntry);
+ custom_scan_methods = hash_create("Custom Scan Methods",
+ 100, &ctl, HASH_ELEM);
+ }
+
+ if (strlen(methods->CustomName) >= CUSTOM_NAME_MAX_LEN)
+ elog(ERROR, "CustomScanMethods name is too long");
+
+ entry = (CustomScanMethodsEntry *) hash_search(custom_scan_methods,
+ methods->CustomName,
+ HASH_ENTER, &found);
+ if (found)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("CustomScanMethods \"%s\" already exists",
+ methods->CustomName)));
+
+ entry->methods = methods;
+}
+
+/*
+ * Get the methods for a given name of CustomScanMethods
+ */
+const CustomScanMethods *
+GetCustomScanMethods(const char *CustomName, bool missing_ok)
+{
+ CustomScanMethodsEntry *entry = NULL;
+
+ if (custom_scan_methods != NULL)
+ entry = (CustomScanMethodsEntry *) hash_search(custom_scan_methods,
+ CustomName,
+ HASH_FIND, NULL);
+ if (!entry)
+ {
+ if (missing_ok)
+ return NULL;
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("CustomScanMethods \"%s\" was not registered",
+ CustomName)));
+ }
+ return entry->methods;
+}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 32d03f7..67cb89e 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -26,6 +26,7 @@
#include <ctype.h>
#include "lib/stringinfo.h"
+#include "nodes/custom_node.h"
#include "nodes/extensible.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
@@ -632,11 +633,9 @@ _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 */
+ /* CustomName is a key to lookup CustomScanMethods */
appendStringInfoString(str, " :methods ");
- _outToken(str, node->methods->LibraryName);
- appendStringInfoChar(str, ' ');
- _outToken(str, node->methods->SymbolName);
+ _outToken(str, node->methods->CustomName);
}
static void
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 6db0492..6b1e927 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -29,6 +29,7 @@
#include <math.h>
#include "fmgr.h"
+#include "nodes/custom_node.h"
#include "nodes/extensible.h"
#include "nodes/parsenodes.h"
#include "nodes/plannodes.h"
@@ -1827,8 +1828,7 @@ static CustomScan *
_readCustomScan(void)
{
READ_LOCALS(CustomScan);
- char *library_name;
- char *symbol_name;
+ char *custom_name;
const CustomScanMethods *methods;
ReadCommonScan(&local_node->scan);
@@ -1840,19 +1840,11 @@ _readCustomScan(void)
READ_NODE_FIELD(custom_scan_tlist);
READ_BITMAPSET_FIELD(custom_relids);
- /*
- * Reconstruction of methods using library and symbol name
- */
+ /* Lookup CustomScanMethods by CustomName */
token = pg_strtok(&length); /* skip methods: */
- token = pg_strtok(&length); /* LibraryName */
- library_name = nullable_string(token, length);
- token = pg_strtok(&length); /* SymbolName */
- symbol_name = nullable_string(token, length);
-
- methods = (const CustomScanMethods *)
- load_external_function(library_name, symbol_name, true, NULL);
- Assert(strcmp(methods->LibraryName, library_name) == 0 &&
- strcmp(methods->SymbolName, symbol_name) == 0);
+ token = pg_strtok(&length); /* CustomName */
+ custom_name = nullable_string(token, length);
+ methods = GetCustomScanMethods(custom_name, false);
local_node->methods = methods;
READ_DONE();
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index d159a17..da295c9 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -24,6 +24,7 @@
#include "catalog/pg_class.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
+#include "nodes/custom_node.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
diff --git a/src/include/executor/nodeCustom.h b/src/include/executor/nodeCustom.h
index 410a3ad..9bcd935 100644
--- a/src/include/executor/nodeCustom.h
+++ b/src/include/executor/nodeCustom.h
@@ -13,6 +13,7 @@
#define NODECUSTOM_H
#include "access/parallel.h"
+#include "nodes/custom_node.h"
#include "nodes/execnodes.h"
/*
diff --git a/src/include/nodes/custom_node.h b/src/include/nodes/custom_node.h
new file mode 100644
index 0000000..3b6f48c
--- /dev/null
+++ b/src/include/nodes/custom_node.h
@@ -0,0 +1,87 @@
+/*-------------------------------------------------------------------------
+ *
+ * custom-node.h
+ * Definitions for custom-path/scan/exec-methods
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef CUSTOM_APIS_H
+#define CUSTOM_APIS_H
+
+#include "access/parallel.h"
+#include "commands/explain.h"
+#include "nodes/execnodes.h"
+#include "nodes/plannodes.h"
+#include "nodes/relation.h"
+
+/*
+ * Flags definitions
+ */
+#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN 0x0001
+#define CUSTOMPATH_SUPPORT_MARK_RESTORE 0x0002
+
+
+#define CUSTOM_NAME_MAX_LEN 64
+
+typedef struct CustomPathMethods
+{
+ const char *CustomName;
+
+ /* Convert Path to a Plan */
+ struct Plan *(*PlanCustomPath) (PlannerInfo *root,
+ RelOptInfo *rel,
+ struct CustomPath *best_path,
+ List *tlist,
+ List *clauses,
+ List *custom_plans);
+} CustomPathMethods;
+
+
+typedef struct CustomScanMethods
+{
+ const char *CustomName;
+
+ /* Create execution state (CustomScanState) from a CustomScan plan node */
+ Node *(*CreateCustomScanState) (CustomScan *cscan);
+} CustomScanMethods;
+
+
+typedef struct CustomExecMethods
+{
+ const char *CustomName;
+
+ /* Executor methods: mark/restore are optional, the rest are required */
+ void (*BeginCustomScan) (CustomScanState *node,
+ EState *estate,
+ int eflags);
+ TupleTableSlot *(*ExecCustomScan) (CustomScanState *node);
+ void (*EndCustomScan) (CustomScanState *node);
+ void (*ReScanCustomScan) (CustomScanState *node);
+ void (*MarkPosCustomScan) (CustomScanState *node);
+ void (*RestrPosCustomScan) (CustomScanState *node);
+ /* Optional: parallel execution support */
+ Size (*EstimateDSMCustomScan) (CustomScanState *node,
+ ParallelContext *pcxt);
+ void (*InitializeDSMCustomScan) (CustomScanState *node,
+ ParallelContext *pcxt,
+ void *coordinate);
+ void (*InitializeWorkerCustomScan) (CustomScanState *node,
+ shm_toc *toc,
+ void *coordinate);
+ /* Optional: print additional information in EXPLAIN */
+ void (*ExplainCustomScan) (CustomScanState *node,
+ List *ancestors,
+ ExplainState *es);
+} CustomExecMethods;
+
+/*
+ * Serialization/Deserialization Support
+ */
+extern void RegisterCustomScanMethods(const CustomScanMethods *methods);
+extern const CustomScanMethods *GetCustomScanMethods(const char *CustomName,
+ bool missing_ok);
+
+#endif /* CUSTOM_APIS_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 0113e5c..bf2a09b 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1606,38 +1606,7 @@ typedef struct ForeignScanState
* the BeginCustomScan method.
* ----------------
*/
-struct ParallelContext; /* avoid including parallel.h here */
-struct shm_toc; /* avoid including shm_toc.h here */
-struct ExplainState; /* avoid including explain.h here */
-struct CustomScanState;
-
-typedef struct CustomExecMethods
-{
- const char *CustomName;
-
- /* Executor methods: mark/restore are optional, the rest are required */
- void (*BeginCustomScan) (struct CustomScanState *node,
- EState *estate,
- int eflags);
- TupleTableSlot *(*ExecCustomScan) (struct CustomScanState *node);
- void (*EndCustomScan) (struct CustomScanState *node);
- void (*ReScanCustomScan) (struct CustomScanState *node);
- void (*MarkPosCustomScan) (struct CustomScanState *node);
- void (*RestrPosCustomScan) (struct CustomScanState *node);
- /* Optional: parallel execution support */
- Size (*EstimateDSMCustomScan) (struct CustomScanState *node,
- struct ParallelContext *pcxt);
- void (*InitializeDSMCustomScan) (struct CustomScanState *node,
- struct ParallelContext *pcxt,
- void *coordinate);
- void (*InitializeWorkerCustomScan) (struct CustomScanState *node,
- struct shm_toc *toc,
- void *coordinate);
- /* Optional: print additional information in EXPLAIN */
- void (*ExplainCustomScan) (struct CustomScanState *node,
- List *ancestors,
- struct ExplainState *es);
-} CustomExecMethods;
+struct CustomExecMethods;
typedef struct CustomScanState
{
@@ -1645,7 +1614,7 @@ typedef struct CustomScanState
uint32 flags; /* mask of CUSTOMPATH_* flags, see relation.h */
List *custom_ps; /* list of child PlanState nodes, if any */
Size pscan_len; /* size of parallel coordination information */
- const CustomExecMethods *methods;
+ const struct CustomExecMethods *methods;
} CustomScanState;
/* ----------------------------------------------------------------
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 00b1d35..465d72f 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -555,17 +555,7 @@ typedef struct ForeignScan
* a larger struct will not work.
* ----------------
*/
-struct CustomScan;
-
-typedef struct CustomScanMethods
-{
- const char *CustomName;
- const char *LibraryName;
- const char *SymbolName;
-
- /* Create execution state (CustomScanState) from a CustomScan plan node */
- Node *(*CreateCustomScanState) (struct CustomScan *cscan);
-} CustomScanMethods;
+struct CustomScanMethods;
typedef struct CustomScan
{
@@ -577,7 +567,7 @@ typedef struct CustomScan
List *custom_scan_tlist; /* optional tlist describing scan
* tuple */
Bitmapset *custom_relids; /* RTIs generated by this scan */
- const CustomScanMethods *methods;
+ const struct CustomScanMethods *methods;
} CustomScan;
/*
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index ee7007a..32f04b2 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -1030,23 +1030,8 @@ typedef struct ForeignPath
* FDW case, we provide a "custom_private" field in CustomPath; providers
* may prefer to use that rather than define another struct type.
*/
-struct CustomPath;
-#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN 0x0001
-#define CUSTOMPATH_SUPPORT_MARK_RESTORE 0x0002
-
-typedef struct CustomPathMethods
-{
- const char *CustomName;
-
- /* Convert Path to a Plan */
- struct Plan *(*PlanCustomPath) (PlannerInfo *root,
- RelOptInfo *rel,
- struct CustomPath *best_path,
- List *tlist,
- List *clauses,
- List *custom_plans);
-} CustomPathMethods;
+struct CustomPathMethods;
typedef struct CustomPath
{
@@ -1054,7 +1039,7 @@ typedef struct CustomPath
uint32 flags; /* mask of CUSTOMPATH_* flags, see above */
List *custom_paths; /* list of child Path nodes, if any */
List *custom_private;
- const CustomPathMethods *methods;
+ const struct CustomPathMethods *methods;
} CustomPath;
/*
On 23/03/16 09:14, Kouhei Kaigai wrote:
On 15/03/16 05:03, Kouhei Kaigai wrote:
Petr,
The attached patch is the revised one that follows the new extensible-
node routine.It is almost same the previous version except for:
- custom-apis.[ch] was renamed to custom-node.[ch]
- check for the length of custom-scan-method name followed
the manner of RegisterExtensibleNodeMethods()Hi,
looks good, only nitpick I have is that it probably should be
custom_node.h with underscore given that we use underscore everywhere
(except for libpq and for some reason atomic ops).Sorry for my response late.
The attached patch just renamed custom-node.[ch] by custom_node.[ch].
Other portions are not changed from the previous revison.Forgot to attach?
Yes.... Thanks,
Ok, I am happy with it, marked it as ready for committer (it was marked
as committed although it wasn't committed).
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Mar 23, 2016 at 1:36 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
Ok, I am happy with it, marked it as ready for committer (it was marked as
committed although it wasn't committed).
Thanks for fixing the status. I had forgotten about this thread.
I can't really endorse the naming conventions here. I mean, we've got
the main extensible nodes stuff in extensible.h, and then we've got
this stuff in custom_node.h (BTW, there is a leftover reference to
custom-node.h). There's no hint in the naming that this relates to
scans, and why is it extensible in one place and custom in another?
I'm not quite sure how to clean this up. At a minimum, I think we
should standardize on "custom_scan.h" instead of "custom_node.h". I
think that would be clearer. But I'm wondering if we should bite the
bullet and rename everything from "custom" to "extensible" and declare
it all in "extensible.h".
src/backend/nodes/custom_node.c:45: indent with spaces.
+ }
--
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
-----Original Message-----
From: pgsql-hackers-owner@postgresql.org
[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Robert Haas
Sent: Friday, March 25, 2016 12:27 AM
To: Petr Jelinek
Cc: Kaigai Kouhei(海外 浩平); pgsql-hackers@postgresql.org
Subject: Re: [HACKERS] Reworks of CustomScan serialization/deserializationOn Wed, Mar 23, 2016 at 1:36 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
Ok, I am happy with it, marked it as ready for committer (it was marked as
committed although it wasn't committed).Thanks for fixing the status. I had forgotten about this thread.
I can't really endorse the naming conventions here. I mean, we've got
the main extensible nodes stuff in extensible.h, and then we've got
this stuff in custom_node.h (BTW, there is a leftover reference to
custom-node.h). There's no hint in the naming that this relates to
scans, and why is it extensible in one place and custom in another?I'm not quite sure how to clean this up. At a minimum, I think we
should standardize on "custom_scan.h" instead of "custom_node.h". I
think that would be clearer. But I'm wondering if we should bite the
bullet and rename everything from "custom" to "extensible" and declare
it all in "extensible.h".
I don't have a strong reason to keep these stuff in separate files.
Both stuffs covers similar features and amount of code are enough small.
So, the attached v4 just merged custom-node.[ch] stuff into extensible.
Once we put similar routines closely, it may be better to consolidate
these routines.
As long as EXTNODENAME_MAX_LEN == CUSTOM_NAME_MAX_LEN, both features
have identical structure layout, so it is easy to call an internal
common function to register or find out a table of callbacks according
to the function actually called by other modules.
I'm inclined to think to replace EXTNODENAME_MAX_LEN and
CUSTOM_NAME_MAX_LEN by NAMEDATALEN again, to fit structure layout.
src/backend/nodes/custom_node.c:45: indent with spaces.
+ }
Oops, thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>
Attachments:
pgsql-v9.6-custom-scan-serialization-reworks.4.patchapplication/octet-stream; name=pgsql-v9.6-custom-scan-serialization-reworks.4.patchDownload
src/backend/commands/explain.c | 1 +
src/backend/nodes/extensible.c | 69 +++++++++++++++++++++++++
src/backend/nodes/outfuncs.c | 6 +--
src/backend/nodes/readfuncs.c | 19 ++-----
src/backend/optimizer/plan/createplan.c | 1 +
src/include/executor/nodeCustom.h | 1 +
src/include/nodes/execnodes.h | 35 +------------
src/include/nodes/extensible.h | 91 ++++++++++++++++++++++++++++++++-
src/include/nodes/plannodes.h | 14 +----
src/include/nodes/relation.h | 19 +------
10 files changed, 174 insertions(+), 82 deletions(-)
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 787b0b9..09c2304 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -21,6 +21,7 @@
#include "commands/prepare.h"
#include "executor/hashjoin.h"
#include "foreign/fdwapi.h"
+#include "nodes/extensible.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
diff --git a/src/backend/nodes/extensible.c b/src/backend/nodes/extensible.c
index 2473b65..2931208 100644
--- a/src/backend/nodes/extensible.c
+++ b/src/backend/nodes/extensible.c
@@ -23,6 +23,7 @@
#include "nodes/extensible.h"
#include "utils/hsearch.h"
+/* for registration of extensible node */
static HTAB *extensible_node_methods = NULL;
typedef struct
@@ -31,6 +32,15 @@ typedef struct
const ExtensibleNodeMethods *methods;
} ExtensibleNodeEntry;
+/* for registration of custom-scan methods */
+static HTAB *custom_scan_methods = NULL;
+
+typedef struct
+{
+ char CustomName[CUSTOM_NAME_MAX_LEN];
+ const CustomScanMethods *methods;
+} CustomScanMethodsEntry;
+
/*
* Register a new type of extensible node.
*/
@@ -91,3 +101,62 @@ GetExtensibleNodeMethods(const char *extnodename, bool missing_ok)
return entry->methods;
}
+
+/*
+ * Register a new custom scan methods
+ */
+void
+RegisterCustomScanMethods(const CustomScanMethods *methods)
+{
+ CustomScanMethodsEntry *entry;
+ bool found;
+
+ if (custom_scan_methods == NULL)
+ {
+ HASHCTL ctl;
+
+ memset(&ctl, 0, sizeof(HASHCTL));
+ ctl.keysize = CUSTOM_NAME_MAX_LEN;
+ ctl.entrysize = sizeof(CustomScanMethodsEntry);
+ custom_scan_methods = hash_create("Custom Scan Methods",
+ 100, &ctl, HASH_ELEM);
+ }
+
+ if (strlen(methods->CustomName) >= CUSTOM_NAME_MAX_LEN)
+ elog(ERROR, "CustomScanMethods name is too long");
+
+ entry = (CustomScanMethodsEntry *) hash_search(custom_scan_methods,
+ methods->CustomName,
+ HASH_ENTER, &found);
+ if (found)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("CustomScanMethods \"%s\" already exists",
+ methods->CustomName)));
+
+ entry->methods = methods;
+}
+
+/*
+ * Get the methods for a given name of CustomScanMethods
+ */
+const CustomScanMethods *
+GetCustomScanMethods(const char *CustomName, bool missing_ok)
+{
+ CustomScanMethodsEntry *entry = NULL;
+
+ if (custom_scan_methods != NULL)
+ entry = (CustomScanMethodsEntry *) hash_search(custom_scan_methods,
+ CustomName,
+ HASH_FIND, NULL);
+ if (!entry)
+ {
+ if (missing_ok)
+ return NULL;
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("CustomScanMethods \"%s\" was not registered",
+ CustomName)));
+ }
+ return entry->methods;
+}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 32d03f7..83abaa6 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -632,11 +632,9 @@ _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 */
+ /* CustomName is a key to lookup CustomScanMethods */
appendStringInfoString(str, " :methods ");
- _outToken(str, node->methods->LibraryName);
- appendStringInfoChar(str, ' ');
- _outToken(str, node->methods->SymbolName);
+ _outToken(str, node->methods->CustomName);
}
static void
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 6db0492..cb0752a 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1827,8 +1827,7 @@ static CustomScan *
_readCustomScan(void)
{
READ_LOCALS(CustomScan);
- char *library_name;
- char *symbol_name;
+ char *custom_name;
const CustomScanMethods *methods;
ReadCommonScan(&local_node->scan);
@@ -1840,19 +1839,11 @@ _readCustomScan(void)
READ_NODE_FIELD(custom_scan_tlist);
READ_BITMAPSET_FIELD(custom_relids);
- /*
- * Reconstruction of methods using library and symbol name
- */
+ /* Lookup CustomScanMethods by CustomName */
token = pg_strtok(&length); /* skip methods: */
- token = pg_strtok(&length); /* LibraryName */
- library_name = nullable_string(token, length);
- token = pg_strtok(&length); /* SymbolName */
- symbol_name = nullable_string(token, length);
-
- methods = (const CustomScanMethods *)
- load_external_function(library_name, symbol_name, true, NULL);
- Assert(strcmp(methods->LibraryName, library_name) == 0 &&
- strcmp(methods->SymbolName, symbol_name) == 0);
+ token = pg_strtok(&length); /* CustomName */
+ custom_name = nullable_string(token, length);
+ methods = GetCustomScanMethods(custom_name, false);
local_node->methods = methods;
READ_DONE();
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index d159a17..e4bc14a 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -24,6 +24,7 @@
#include "catalog/pg_class.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
+#include "nodes/extensible.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
diff --git a/src/include/executor/nodeCustom.h b/src/include/executor/nodeCustom.h
index 410a3ad..9d0b393 100644
--- a/src/include/executor/nodeCustom.h
+++ b/src/include/executor/nodeCustom.h
@@ -14,6 +14,7 @@
#include "access/parallel.h"
#include "nodes/execnodes.h"
+#include "nodes/extensible.h"
/*
* General executor code
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 0113e5c..bf2a09b 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1606,38 +1606,7 @@ typedef struct ForeignScanState
* the BeginCustomScan method.
* ----------------
*/
-struct ParallelContext; /* avoid including parallel.h here */
-struct shm_toc; /* avoid including shm_toc.h here */
-struct ExplainState; /* avoid including explain.h here */
-struct CustomScanState;
-
-typedef struct CustomExecMethods
-{
- const char *CustomName;
-
- /* Executor methods: mark/restore are optional, the rest are required */
- void (*BeginCustomScan) (struct CustomScanState *node,
- EState *estate,
- int eflags);
- TupleTableSlot *(*ExecCustomScan) (struct CustomScanState *node);
- void (*EndCustomScan) (struct CustomScanState *node);
- void (*ReScanCustomScan) (struct CustomScanState *node);
- void (*MarkPosCustomScan) (struct CustomScanState *node);
- void (*RestrPosCustomScan) (struct CustomScanState *node);
- /* Optional: parallel execution support */
- Size (*EstimateDSMCustomScan) (struct CustomScanState *node,
- struct ParallelContext *pcxt);
- void (*InitializeDSMCustomScan) (struct CustomScanState *node,
- struct ParallelContext *pcxt,
- void *coordinate);
- void (*InitializeWorkerCustomScan) (struct CustomScanState *node,
- struct shm_toc *toc,
- void *coordinate);
- /* Optional: print additional information in EXPLAIN */
- void (*ExplainCustomScan) (struct CustomScanState *node,
- List *ancestors,
- struct ExplainState *es);
-} CustomExecMethods;
+struct CustomExecMethods;
typedef struct CustomScanState
{
@@ -1645,7 +1614,7 @@ typedef struct CustomScanState
uint32 flags; /* mask of CUSTOMPATH_* flags, see relation.h */
List *custom_ps; /* list of child PlanState nodes, if any */
Size pscan_len; /* size of parallel coordination information */
- const CustomExecMethods *methods;
+ const struct CustomExecMethods *methods;
} CustomScanState;
/* ----------------------------------------------------------------
diff --git a/src/include/nodes/extensible.h b/src/include/nodes/extensible.h
index 96ae7bc..605833f 100644
--- a/src/include/nodes/extensible.h
+++ b/src/include/nodes/extensible.h
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* extensible.h
- * Definitions for extensible node type
+ * Definitions for extensible node type and custom-xxx-methods
*
*
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
@@ -14,7 +14,11 @@
#ifndef EXTENSIBLE_H
#define EXTENSIBLE_H
-#include "nodes/nodes.h"
+#include "access/parallel.h"
+#include "commands/explain.h"
+#include "nodes/execnodes.h"
+#include "nodes/plannodes.h"
+#include "nodes/relation.h"
#define EXTNODENAME_MAX_LEN 64
@@ -69,4 +73,87 @@ extern void RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *method);
extern const ExtensibleNodeMethods *GetExtensibleNodeMethods(const char *name,
bool missing_ok);
+/*
+ * Definition of Custom(Path|Scan|Exec)Methods.
+ *
+ * The following structures are callback definition for each relavant custom-
+ * node types.
+ * Right now, only CustomScan node can be serialized/deserialized using
+ * nodeToString/stringToNode. So, extension that performs as a custom-scan
+ * provider has to support reconstruction of 'methods' of CustomScanMethods
+ * pointer on background worker processes.
+ * As ExtensibleNode type doing above, extension registers CustomExecMethods
+ * identified by CustomName preliminary. A serialized CustomScan contains
+ * the name of CustomExecMethods, then it shall be referenced on the background
+ * worker side later.
+ *
+ * Custom-scan provider may also have to support serialization/deserialization
+ * on CustomPath and CustomScanState in the future release, but not now.
+ */
+#define CUSTOM_NAME_MAX_LEN 64
+
+/*
+ * Flags definitions
+ */
+#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN 0x0001
+#define CUSTOMPATH_SUPPORT_MARK_RESTORE 0x0002
+
+typedef struct CustomPathMethods
+{
+ const char *CustomName;
+
+ /* Convert Path to a Plan */
+ struct Plan *(*PlanCustomPath) (PlannerInfo *root,
+ RelOptInfo *rel,
+ struct CustomPath *best_path,
+ List *tlist,
+ List *clauses,
+ List *custom_plans);
+} CustomPathMethods;
+
+
+typedef struct CustomScanMethods
+{
+ const char *CustomName;
+
+ /* Create execution state (CustomScanState) from a CustomScan plan node */
+ Node *(*CreateCustomScanState) (CustomScan *cscan);
+} CustomScanMethods;
+
+
+typedef struct CustomExecMethods
+{
+ const char *CustomName;
+
+ /* Executor methods: mark/restore are optional, the rest are required */
+ void (*BeginCustomScan) (CustomScanState *node,
+ EState *estate,
+ int eflags);
+ TupleTableSlot *(*ExecCustomScan) (CustomScanState *node);
+ void (*EndCustomScan) (CustomScanState *node);
+ void (*ReScanCustomScan) (CustomScanState *node);
+ void (*MarkPosCustomScan) (CustomScanState *node);
+ void (*RestrPosCustomScan) (CustomScanState *node);
+ /* Optional: parallel execution support */
+ Size (*EstimateDSMCustomScan) (CustomScanState *node,
+ ParallelContext *pcxt);
+ void (*InitializeDSMCustomScan) (CustomScanState *node,
+ ParallelContext *pcxt,
+ void *coordinate);
+ void (*InitializeWorkerCustomScan) (CustomScanState *node,
+ shm_toc *toc,
+ void *coordinate);
+ /* Optional: print additional information in EXPLAIN */
+ void (*ExplainCustomScan) (CustomScanState *node,
+ List *ancestors,
+ ExplainState *es);
+} CustomExecMethods;
+
+/*
+ * Serialization/Deserialization Support of CustomScan
+ */
+extern void RegisterCustomScanMethods(const CustomScanMethods *methods);
+extern const CustomScanMethods *GetCustomScanMethods(const char *CustomName,
+ bool missing_ok);
+
#endif /* EXTENSIBLE_H */
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 00b1d35..465d72f 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -555,17 +555,7 @@ typedef struct ForeignScan
* a larger struct will not work.
* ----------------
*/
-struct CustomScan;
-
-typedef struct CustomScanMethods
-{
- const char *CustomName;
- const char *LibraryName;
- const char *SymbolName;
-
- /* Create execution state (CustomScanState) from a CustomScan plan node */
- Node *(*CreateCustomScanState) (struct CustomScan *cscan);
-} CustomScanMethods;
+struct CustomScanMethods;
typedef struct CustomScan
{
@@ -577,7 +567,7 @@ typedef struct CustomScan
List *custom_scan_tlist; /* optional tlist describing scan
* tuple */
Bitmapset *custom_relids; /* RTIs generated by this scan */
- const CustomScanMethods *methods;
+ const struct CustomScanMethods *methods;
} CustomScan;
/*
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index ee7007a..32f04b2 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -1030,23 +1030,8 @@ typedef struct ForeignPath
* FDW case, we provide a "custom_private" field in CustomPath; providers
* may prefer to use that rather than define another struct type.
*/
-struct CustomPath;
-#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN 0x0001
-#define CUSTOMPATH_SUPPORT_MARK_RESTORE 0x0002
-
-typedef struct CustomPathMethods
-{
- const char *CustomName;
-
- /* Convert Path to a Plan */
- struct Plan *(*PlanCustomPath) (PlannerInfo *root,
- RelOptInfo *rel,
- struct CustomPath *best_path,
- List *tlist,
- List *clauses,
- List *custom_plans);
-} CustomPathMethods;
+struct CustomPathMethods;
typedef struct CustomPath
{
@@ -1054,7 +1039,7 @@ typedef struct CustomPath
uint32 flags; /* mask of CUSTOMPATH_* flags, see above */
List *custom_paths; /* list of child Path nodes, if any */
List *custom_private;
- const CustomPathMethods *methods;
+ const struct CustomPathMethods *methods;
} CustomPath;
/*
On Mon, Mar 28, 2016 at 9:36 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:
I don't have a strong reason to keep these stuff in separate files.
Both stuffs covers similar features and amount of code are enough small.
So, the attached v4 just merged custom-node.[ch] stuff into extensible.Once we put similar routines closely, it may be better to consolidate
these routines.
As long as EXTNODENAME_MAX_LEN == CUSTOM_NAME_MAX_LEN, both features
have identical structure layout, so it is easy to call an internal
common function to register or find out a table of callbacks according
to the function actually called by other modules.I'm inclined to think to replace EXTNODENAME_MAX_LEN and
CUSTOM_NAME_MAX_LEN by NAMEDATALEN again, to fit structure layout.
I don't think that we need both EXTNODENAME_MAX_LEN and
CUSTOM_NAME_MAX_LEN; we can use EXTNODENAME_MAX_LEN for both. I'm
opposed to using NAMEDATALEN for anything unrelated to the size of a
Name. If it's not being stored in a catalog, it doesn't need to care.
--
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
-----Original Message-----
From: pgsql-hackers-owner@postgresql.org
[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Robert Haas
Sent: Tuesday, March 29, 2016 10:54 AM
To: Kaigai Kouhei(海外 浩平)
Cc: Petr Jelinek; pgsql-hackers@postgresql.org
Subject: Re: [HACKERS] Reworks of CustomScan serialization/deserializationOn Mon, Mar 28, 2016 at 9:36 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:
I don't have a strong reason to keep these stuff in separate files.
Both stuffs covers similar features and amount of code are enough small.
So, the attached v4 just merged custom-node.[ch] stuff into extensible.Once we put similar routines closely, it may be better to consolidate
these routines.
As long as EXTNODENAME_MAX_LEN == CUSTOM_NAME_MAX_LEN, both features
have identical structure layout, so it is easy to call an internal
common function to register or find out a table of callbacks according
to the function actually called by other modules.I'm inclined to think to replace EXTNODENAME_MAX_LEN and
CUSTOM_NAME_MAX_LEN by NAMEDATALEN again, to fit structure layout.I don't think that we need both EXTNODENAME_MAX_LEN and
CUSTOM_NAME_MAX_LEN; we can use EXTNODENAME_MAX_LEN for both. I'm
opposed to using NAMEDATALEN for anything unrelated to the size of a
Name. If it's not being stored in a catalog, it doesn't need to care.
OK, I adjusted the v4 patch to use EXTNODENAME_MAX_LEN for both.
The structure of hash entry was revised as follows, then registered via
an internal common function: RegisterExtensibleNodeEntry, and found out
via also an internal common function: GetExtensibleNodeEntry.
typedef struct
{
char extnodename[EXTNODENAME_MAX_LEN];
const void *extnodemethods;
} ExtensibleNodeEntry;
ExtensibleNodeMethods and CustomScanMethods shall be stored in
'extensible_node_methods' and 'custom_scan_methods' separatedly.
The entrypoint functions calls above internal common functions with
appropriate HTAB variable.
It will be re-usable if we would have further extensible nodes in the
future versions.
Thanks,
--
NEC Business Creation Division / PG-Strom Project
KaiGai Kohei <kaigai@ak.jp.nec.com>
Attachments:
pgsql-v9.6-custom-scan-serialization-reworks.5.patchapplication/octet-stream; name=pgsql-v9.6-custom-scan-serialization-reworks.5.patchDownload
src/backend/commands/explain.c | 1 +
src/backend/nodes/extensible.c | 88 ++++++++++++++++++++++++-------
src/backend/nodes/outfuncs.c | 6 +--
src/backend/nodes/readfuncs.c | 19 ++-----
src/backend/optimizer/plan/createplan.c | 1 +
src/include/executor/nodeCustom.h | 1 +
src/include/nodes/execnodes.h | 35 +------------
src/include/nodes/extensible.h | 91 ++++++++++++++++++++++++++++++++-
src/include/nodes/plannodes.h | 14 +----
src/include/nodes/relation.h | 19 +------
10 files changed, 174 insertions(+), 101 deletions(-)
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 787b0b9..09c2304 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -21,6 +21,7 @@
#include "commands/prepare.h"
#include "executor/hashjoin.h"
#include "foreign/fdwapi.h"
+#include "nodes/extensible.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
diff --git a/src/backend/nodes/extensible.c b/src/backend/nodes/extensible.c
index 2473b65..d61be58 100644
--- a/src/backend/nodes/extensible.c
+++ b/src/backend/nodes/extensible.c
@@ -24,61 +24,87 @@
#include "utils/hsearch.h"
static HTAB *extensible_node_methods = NULL;
+static HTAB *custom_scan_methods = NULL;
typedef struct
{
char extnodename[EXTNODENAME_MAX_LEN];
- const ExtensibleNodeMethods *methods;
+ const void *extnodemethods;
} ExtensibleNodeEntry;
/*
- * Register a new type of extensible node.
+ * An internal function to register a new callback structure
*/
-void
-RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *methods)
+static void
+RegisterExtensibleNodeEntry(HTAB **p_htable, const char *htable_label,
+ const char *extnodename,
+ const void *extnodemethods)
{
ExtensibleNodeEntry *entry;
bool found;
- if (extensible_node_methods == NULL)
+ if (*p_htable == NULL)
{
HASHCTL ctl;
memset(&ctl, 0, sizeof(HASHCTL));
ctl.keysize = EXTNODENAME_MAX_LEN;
ctl.entrysize = sizeof(ExtensibleNodeEntry);
- extensible_node_methods = hash_create("Extensible Node Methods",
- 100, &ctl, HASH_ELEM);
+
+ *p_htable = hash_create(htable_label, 100, &ctl, HASH_ELEM);
}
- if (strlen(methods->extnodename) >= EXTNODENAME_MAX_LEN)
+ if (strlen(extnodename) >= EXTNODENAME_MAX_LEN)
elog(ERROR, "extensible node name is too long");
- entry = (ExtensibleNodeEntry *) hash_search(extensible_node_methods,
- methods->extnodename,
+ entry = (ExtensibleNodeEntry *) hash_search(*p_htable,
+ extnodename,
HASH_ENTER, &found);
if (found)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("extensible node type \"%s\" already exists",
- methods->extnodename)));
+ extnodename)));
- entry->methods = methods;
+ entry->extnodemethods = extnodemethods;
}
/*
- * Get the methods for a given type of extensible node.
+ * Register a new type of extensible node.
*/
-const ExtensibleNodeMethods *
-GetExtensibleNodeMethods(const char *extnodename, bool missing_ok)
+void
+RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *methods)
+{
+ RegisterExtensibleNodeEntry(&extensible_node_methods,
+ "Extensible Node Methods",
+ methods->extnodename,
+ methods);
+}
+
+/*
+ * Register a new type of custom scan node
+ */
+void
+RegisterCustomScanMethods(const CustomScanMethods *methods)
+{
+ RegisterExtensibleNodeEntry(&custom_scan_methods,
+ "Custom Scan Methods",
+ methods->CustomName,
+ methods);
+}
+
+/*
+ * An internal routine to get an ExtensibleNodeEntry by the given identifier
+ */
+static const void *
+GetExtensibleNodeEntry(HTAB *htable, const char *extnodename, bool missing_ok)
{
ExtensibleNodeEntry *entry = NULL;
- if (extensible_node_methods != NULL)
- entry = (ExtensibleNodeEntry *) hash_search(extensible_node_methods,
+ if (htable != NULL)
+ entry = (ExtensibleNodeEntry *) hash_search(htable,
extnodename,
HASH_FIND, NULL);
-
if (!entry)
{
if (missing_ok)
@@ -89,5 +115,29 @@ GetExtensibleNodeMethods(const char *extnodename, bool missing_ok)
extnodename)));
}
- return entry->methods;
+ return entry->extnodemethods;
+}
+
+/*
+ * Get the methods for a given type of extensible node.
+ */
+const ExtensibleNodeMethods *
+GetExtensibleNodeMethods(const char *extnodename, bool missing_ok)
+{
+ return (const ExtensibleNodeMethods *)
+ GetExtensibleNodeEntry(extensible_node_methods,
+ extnodename,
+ missing_ok);
+}
+
+/*
+ * Get the methods for a given name of CustomScanMethods
+ */
+const CustomScanMethods *
+GetCustomScanMethods(const char *CustomName, bool missing_ok)
+{
+ return (const CustomScanMethods *)
+ GetExtensibleNodeEntry(custom_scan_methods,
+ CustomName,
+ missing_ok);
}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 32d03f7..83abaa6 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -632,11 +632,9 @@ _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 */
+ /* CustomName is a key to lookup CustomScanMethods */
appendStringInfoString(str, " :methods ");
- _outToken(str, node->methods->LibraryName);
- appendStringInfoChar(str, ' ');
- _outToken(str, node->methods->SymbolName);
+ _outToken(str, node->methods->CustomName);
}
static void
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 6db0492..cb0752a 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1827,8 +1827,7 @@ static CustomScan *
_readCustomScan(void)
{
READ_LOCALS(CustomScan);
- char *library_name;
- char *symbol_name;
+ char *custom_name;
const CustomScanMethods *methods;
ReadCommonScan(&local_node->scan);
@@ -1840,19 +1839,11 @@ _readCustomScan(void)
READ_NODE_FIELD(custom_scan_tlist);
READ_BITMAPSET_FIELD(custom_relids);
- /*
- * Reconstruction of methods using library and symbol name
- */
+ /* Lookup CustomScanMethods by CustomName */
token = pg_strtok(&length); /* skip methods: */
- token = pg_strtok(&length); /* LibraryName */
- library_name = nullable_string(token, length);
- token = pg_strtok(&length); /* SymbolName */
- symbol_name = nullable_string(token, length);
-
- methods = (const CustomScanMethods *)
- load_external_function(library_name, symbol_name, true, NULL);
- Assert(strcmp(methods->LibraryName, library_name) == 0 &&
- strcmp(methods->SymbolName, symbol_name) == 0);
+ token = pg_strtok(&length); /* CustomName */
+ custom_name = nullable_string(token, length);
+ methods = GetCustomScanMethods(custom_name, false);
local_node->methods = methods;
READ_DONE();
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index d159a17..e4bc14a 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -24,6 +24,7 @@
#include "catalog/pg_class.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
+#include "nodes/extensible.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
diff --git a/src/include/executor/nodeCustom.h b/src/include/executor/nodeCustom.h
index 410a3ad..9d0b393 100644
--- a/src/include/executor/nodeCustom.h
+++ b/src/include/executor/nodeCustom.h
@@ -14,6 +14,7 @@
#include "access/parallel.h"
#include "nodes/execnodes.h"
+#include "nodes/extensible.h"
/*
* General executor code
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 0113e5c..bf2a09b 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1606,38 +1606,7 @@ typedef struct ForeignScanState
* the BeginCustomScan method.
* ----------------
*/
-struct ParallelContext; /* avoid including parallel.h here */
-struct shm_toc; /* avoid including shm_toc.h here */
-struct ExplainState; /* avoid including explain.h here */
-struct CustomScanState;
-
-typedef struct CustomExecMethods
-{
- const char *CustomName;
-
- /* Executor methods: mark/restore are optional, the rest are required */
- void (*BeginCustomScan) (struct CustomScanState *node,
- EState *estate,
- int eflags);
- TupleTableSlot *(*ExecCustomScan) (struct CustomScanState *node);
- void (*EndCustomScan) (struct CustomScanState *node);
- void (*ReScanCustomScan) (struct CustomScanState *node);
- void (*MarkPosCustomScan) (struct CustomScanState *node);
- void (*RestrPosCustomScan) (struct CustomScanState *node);
- /* Optional: parallel execution support */
- Size (*EstimateDSMCustomScan) (struct CustomScanState *node,
- struct ParallelContext *pcxt);
- void (*InitializeDSMCustomScan) (struct CustomScanState *node,
- struct ParallelContext *pcxt,
- void *coordinate);
- void (*InitializeWorkerCustomScan) (struct CustomScanState *node,
- struct shm_toc *toc,
- void *coordinate);
- /* Optional: print additional information in EXPLAIN */
- void (*ExplainCustomScan) (struct CustomScanState *node,
- List *ancestors,
- struct ExplainState *es);
-} CustomExecMethods;
+struct CustomExecMethods;
typedef struct CustomScanState
{
@@ -1645,7 +1614,7 @@ typedef struct CustomScanState
uint32 flags; /* mask of CUSTOMPATH_* flags, see relation.h */
List *custom_ps; /* list of child PlanState nodes, if any */
Size pscan_len; /* size of parallel coordination information */
- const CustomExecMethods *methods;
+ const struct CustomExecMethods *methods;
} CustomScanState;
/* ----------------------------------------------------------------
diff --git a/src/include/nodes/extensible.h b/src/include/nodes/extensible.h
index 96ae7bc..4371e35 100644
--- a/src/include/nodes/extensible.h
+++ b/src/include/nodes/extensible.h
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* extensible.h
- * Definitions for extensible node type
+ * Definitions for extensible node type and custom-xxx-methods
*
*
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
@@ -14,8 +14,13 @@
#ifndef EXTENSIBLE_H
#define EXTENSIBLE_H
-#include "nodes/nodes.h"
+#include "access/parallel.h"
+#include "commands/explain.h"
+#include "nodes/execnodes.h"
+#include "nodes/plannodes.h"
+#include "nodes/relation.h"
+/* length of the identifier of callbacks structure */
#define EXTNODENAME_MAX_LEN 64
/*
@@ -69,4 +74,86 @@ extern void RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *method);
extern const ExtensibleNodeMethods *GetExtensibleNodeMethods(const char *name,
bool missing_ok);
+/*
+ * Definition of Custom(Path|Scan|Exec)Methods.
+ *
+ * The following structures are callback definition for each relavant custom-
+ * node types.
+ * Right now, only CustomScan node can be serialized/deserialized using
+ * nodeToString/stringToNode. So, extension that performs as a custom-scan
+ * provider has to support reconstruction of 'methods' of CustomScanMethods
+ * pointer on background worker processes.
+ * As ExtensibleNode type doing above, extension registers CustomExecMethods
+ * identified by CustomName preliminary. A serialized CustomScan contains
+ * the name of CustomExecMethods, then it shall be referenced on the background
+ * worker side later.
+ *
+ * Custom-scan provider may also have to support serialization/deserialization
+ * on CustomPath and CustomScanState in the future release, but not now.
+ */
+
+/*
+ * Flags definitions
+ */
+#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN 0x0001
+#define CUSTOMPATH_SUPPORT_MARK_RESTORE 0x0002
+
+typedef struct CustomPathMethods
+{
+ const char *CustomName;
+
+ /* Convert Path to a Plan */
+ struct Plan *(*PlanCustomPath) (PlannerInfo *root,
+ RelOptInfo *rel,
+ struct CustomPath *best_path,
+ List *tlist,
+ List *clauses,
+ List *custom_plans);
+} CustomPathMethods;
+
+
+typedef struct CustomScanMethods
+{
+ const char *CustomName;
+
+ /* Create execution state (CustomScanState) from a CustomScan plan node */
+ Node *(*CreateCustomScanState) (CustomScan *cscan);
+} CustomScanMethods;
+
+
+typedef struct CustomExecMethods
+{
+ const char *CustomName;
+
+ /* Executor methods: mark/restore are optional, the rest are required */
+ void (*BeginCustomScan) (CustomScanState *node,
+ EState *estate,
+ int eflags);
+ TupleTableSlot *(*ExecCustomScan) (CustomScanState *node);
+ void (*EndCustomScan) (CustomScanState *node);
+ void (*ReScanCustomScan) (CustomScanState *node);
+ void (*MarkPosCustomScan) (CustomScanState *node);
+ void (*RestrPosCustomScan) (CustomScanState *node);
+ /* Optional: parallel execution support */
+ Size (*EstimateDSMCustomScan) (CustomScanState *node,
+ ParallelContext *pcxt);
+ void (*InitializeDSMCustomScan) (CustomScanState *node,
+ ParallelContext *pcxt,
+ void *coordinate);
+ void (*InitializeWorkerCustomScan) (CustomScanState *node,
+ shm_toc *toc,
+ void *coordinate);
+ /* Optional: print additional information in EXPLAIN */
+ void (*ExplainCustomScan) (CustomScanState *node,
+ List *ancestors,
+ ExplainState *es);
+} CustomExecMethods;
+
+/*
+ * Serialization/Deserialization Support of CustomScan
+ */
+extern void RegisterCustomScanMethods(const CustomScanMethods *methods);
+extern const CustomScanMethods *GetCustomScanMethods(const char *CustomName,
+ bool missing_ok);
+
#endif /* EXTENSIBLE_H */
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 00b1d35..465d72f 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -555,17 +555,7 @@ typedef struct ForeignScan
* a larger struct will not work.
* ----------------
*/
-struct CustomScan;
-
-typedef struct CustomScanMethods
-{
- const char *CustomName;
- const char *LibraryName;
- const char *SymbolName;
-
- /* Create execution state (CustomScanState) from a CustomScan plan node */
- Node *(*CreateCustomScanState) (struct CustomScan *cscan);
-} CustomScanMethods;
+struct CustomScanMethods;
typedef struct CustomScan
{
@@ -577,7 +567,7 @@ typedef struct CustomScan
List *custom_scan_tlist; /* optional tlist describing scan
* tuple */
Bitmapset *custom_relids; /* RTIs generated by this scan */
- const CustomScanMethods *methods;
+ const struct CustomScanMethods *methods;
} CustomScan;
/*
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index ee7007a..32f04b2 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -1030,23 +1030,8 @@ typedef struct ForeignPath
* FDW case, we provide a "custom_private" field in CustomPath; providers
* may prefer to use that rather than define another struct type.
*/
-struct CustomPath;
-#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN 0x0001
-#define CUSTOMPATH_SUPPORT_MARK_RESTORE 0x0002
-
-typedef struct CustomPathMethods
-{
- const char *CustomName;
-
- /* Convert Path to a Plan */
- struct Plan *(*PlanCustomPath) (PlannerInfo *root,
- RelOptInfo *rel,
- struct CustomPath *best_path,
- List *tlist,
- List *clauses,
- List *custom_plans);
-} CustomPathMethods;
+struct CustomPathMethods;
typedef struct CustomPath
{
@@ -1054,7 +1039,7 @@ typedef struct CustomPath
uint32 flags; /* mask of CUSTOMPATH_* flags, see above */
List *custom_paths; /* list of child Path nodes, if any */
List *custom_private;
- const CustomPathMethods *methods;
+ const struct CustomPathMethods *methods;
} CustomPath;
/*
On Mon, Mar 28, 2016 at 11:00 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:
-----Original Message-----
From: pgsql-hackers-owner@postgresql.org
[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Robert Haas
Sent: Tuesday, March 29, 2016 10:54 AM
To: Kaigai Kouhei(海外 浩平)
Cc: Petr Jelinek; pgsql-hackers@postgresql.org
Subject: Re: [HACKERS] Reworks of CustomScan serialization/deserializationOn Mon, Mar 28, 2016 at 9:36 PM, Kouhei Kaigai <kaigai@ak.jp.nec.com> wrote:
I don't have a strong reason to keep these stuff in separate files.
Both stuffs covers similar features and amount of code are enough small.
So, the attached v4 just merged custom-node.[ch] stuff into extensible.Once we put similar routines closely, it may be better to consolidate
these routines.
As long as EXTNODENAME_MAX_LEN == CUSTOM_NAME_MAX_LEN, both features
have identical structure layout, so it is easy to call an internal
common function to register or find out a table of callbacks according
to the function actually called by other modules.I'm inclined to think to replace EXTNODENAME_MAX_LEN and
CUSTOM_NAME_MAX_LEN by NAMEDATALEN again, to fit structure layout.I don't think that we need both EXTNODENAME_MAX_LEN and
CUSTOM_NAME_MAX_LEN; we can use EXTNODENAME_MAX_LEN for both. I'm
opposed to using NAMEDATALEN for anything unrelated to the size of a
Name. If it's not being stored in a catalog, it doesn't need to care.OK, I adjusted the v4 patch to use EXTNODENAME_MAX_LEN for both.
The structure of hash entry was revised as follows, then registered via
an internal common function: RegisterExtensibleNodeEntry, and found out
via also an internal common function: GetExtensibleNodeEntry.typedef struct
{
char extnodename[EXTNODENAME_MAX_LEN];
const void *extnodemethods;
} ExtensibleNodeEntry;ExtensibleNodeMethods and CustomScanMethods shall be stored in
'extensible_node_methods' and 'custom_scan_methods' separatedly.
The entrypoint functions calls above internal common functions with
appropriate HTAB variable.It will be re-usable if we would have further extensible nodes in the
future versions.
Committed with a bit of wordsmithing.
--
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