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