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);