pgsql-v9.4-custom-scan.part-1.v10.patch
application/octet-stream
Filename: pgsql-v9.4-custom-scan.part-1.v10.patch
Type: application/octet-stream
Part: 1
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v9
| File | + | − |
|---|---|---|
| doc/src/sgml/custom-plan.sgml | 315 | 0 |
| doc/src/sgml/filelist.sgml | 1 | 0 |
| doc/src/sgml/postgres.sgml | 1 | 0 |
| src/backend/commands/explain.c | 43 | 2 |
| src/backend/executor/execAmi.c | 23 | 0 |
| src/backend/executor/execProcnode.c | 15 | 0 |
| src/backend/executor/Makefile | 1 | 1 |
| src/backend/executor/nodeCustom.c | 73 | 0 |
| src/backend/nodes/copyfuncs.c | 42 | 0 |
| src/backend/nodes/outfuncs.c | 40 | 0 |
| src/backend/optimizer/path/allpaths.c | 11 | 23 |
| src/backend/optimizer/path/joinpath.c | 16 | 0 |
| src/backend/optimizer/plan/createplan.c | 35 | 20 |
| src/backend/optimizer/plan/setrefs.c | 19 | 3 |
| src/backend/optimizer/plan/subselect.c | 75 | 53 |
| src/backend/utils/adt/ruleutils.c | 56 | 0 |
| src/include/commands/explain.h | 1 | 0 |
| src/include/executor/nodeCustom.h | 30 | 0 |
| src/include/nodes/execnodes.h | 12 | 0 |
| src/include/nodes/nodes.h | 6 | 0 |
| src/include/nodes/plannodes.h | 77 | 0 |
| src/include/nodes/relation.h | 29 | 0 |
| src/include/optimizer/paths.h | 17 | 0 |
| src/include/optimizer/planmain.h | 11 | 0 |
| src/include/optimizer/subselect.h | 7 | 0 |
doc/src/sgml/custom-plan.sgml | 315 ++++++++++++++++++++++++++++++++
doc/src/sgml/filelist.sgml | 1 +
doc/src/sgml/postgres.sgml | 1 +
src/backend/commands/explain.c | 45 ++++-
src/backend/executor/Makefile | 2 +-
src/backend/executor/execAmi.c | 23 +++
src/backend/executor/execProcnode.c | 15 ++
src/backend/executor/nodeCustom.c | 73 ++++++++
src/backend/nodes/copyfuncs.c | 42 +++++
src/backend/nodes/outfuncs.c | 40 ++++
src/backend/optimizer/path/allpaths.c | 34 ++--
src/backend/optimizer/path/joinpath.c | 16 ++
src/backend/optimizer/plan/createplan.c | 55 ++++--
src/backend/optimizer/plan/setrefs.c | 22 ++-
src/backend/optimizer/plan/subselect.c | 128 +++++++------
src/backend/utils/adt/ruleutils.c | 56 ++++++
src/include/commands/explain.h | 1 +
src/include/executor/nodeCustom.h | 30 +++
src/include/nodes/execnodes.h | 12 ++
src/include/nodes/nodes.h | 6 +
src/include/nodes/plannodes.h | 77 ++++++++
src/include/nodes/relation.h | 29 +++
src/include/optimizer/paths.h | 17 ++
src/include/optimizer/planmain.h | 11 ++
src/include/optimizer/subselect.h | 7 +
25 files changed, 956 insertions(+), 102 deletions(-)
diff --git a/doc/src/sgml/custom-plan.sgml b/doc/src/sgml/custom-plan.sgml
new file mode 100644
index 0000000..8d456f9
--- /dev/null
+++ b/doc/src/sgml/custom-plan.sgml
@@ -0,0 +1,315 @@
+<!-- doc/src/sgml/custom-plan.sgml -->
+
+<chapter id="custom-plan">
+ <title>Writing A Custom Plan Provider</title>
+
+ <indexterm zone="custom-plan">
+ <primary>custom plan</primary>
+ <secondary>handler for</secondary>
+ </indexterm>
+ <para>
+ The custom-plan interface enables extensions to implement its custom
+ behavior, instead of built-in plan node, according to the cost based
+ optimizer manner.
+ Its key component is <literal>CustomPlan</> node that has usual
+ <literal>Plan</> field and a table of function-pointers; that performs
+ like methods of base class in object oriented programming language,
+ thus <literal>CustomPlan</> node works as a polymorphism plan / execution
+ node.
+ The core backend does not assume anything about behavior of this node
+ type, thus, note that it is responsibility of the custom-plan provider
+ to work its custom node as if the built-in plan / execution node being
+ replaced.
+ </para>
+ <para>
+ Overall steps to use this custom-plan interface is below.
+ </para>
+ <para>
+ Custom-plan provider can add <literal>CustomPath</> on a particular
+ relation scan using <literal>add_scan_path_hook</> or a particular
+ relations join using <literal>add_join_path_hook</>.
+ Then, the planner chooses the cheapest path towards a particular
+ scan or join in the built-in and custom paths.
+ So, <literal>CustomPath</> node has to have proper cost estimation
+ for right plan selection, no need to say.
+ </para>
+ <para>
+ Usually, custom-plan provider extends <literal>CustomPath</> type
+ to have its private fields, like:
+<programlisting>
+typedef struct {
+ CustomPath cpath;
+ :
+ List *somethin_private;
+ :
+} YourOwnCustomPath;
+</programlisting>
+ You can also extend <literal>CustomPlan</> and <literal>CustomPlanState</>
+ type with similar manner.
+ </para>
+ <para>
+ <literal>CustomPathMethods</> is table of function-pointers
+ for <literal>CustomPath</>, and <literal>CustomPlanMethods</> is
+ table of function-pointers for <literal>CustomPlan</> and
+ <literal>CustomPlanState</>.
+ Extension has to implement the functions according to the specification
+ in the next section.
+ </para>
+
+ <sect1 id="custom-plan-spec">
+ <title>Specification of Custom Plan Interface</title>
+ <sect2 id="custom-scan-register">
+ <title>Registration of custom-plan path</title>
+ <para>
+ The first task of custom-plan provide is to add <literal>CustomPath</>
+ towards a particular relation scan or relations join.
+ Right now, only scan and join are supported by planner thus cost-based
+ optimization shall be applied, however, other kind of nodes (like sort,
+ aggregate and so on...) are not supported.
+ </para>
+ <para>
+<programlisting>
+typedef void (*add_scan_path_hook_type)(PlannerInfo *root,
+ RelOptInfo *baserel,
+ RangeTblEntry *rte);
+extern PGDLLIMPORT add_scan_path_hook_type add_scan_path_hook;
+</programlisting>
+ Custom-plan provider can add its custom-path using
+ <literal>add_scan_path_hook</> to provide alternative way to scan
+ the relation being specified.
+ </para>
+ <para>
+<programlisting>
+typedef void (*add_join_path_hook_type)(PlannerInfo *root,
+ RelOptInfo *joinrel,
+ RelOptInfo *outerrel,
+ RelOptInfo *innerrel,
+ JoinType jointype,
+ SpecialJoinInfo *sjinfo,
+ List *restrictlist,
+ Relids param_source_rels,
+ Relids extra_lateral_rels);
+extern PGDLLIMPORT add_join_path_hook_type add_join_path_hook;
+</programlisting>
+ Also, custom-plan provider can add its custom-path using
+ <literal>add_join_path_hook</> to provide alternative way to join
+ two relations (note that both or either of relations are also joined
+ relations, not only base relations) being specified.
+ </para>
+ </sect2>
+
+ <sect2 id="custom-path-methods">
+ <title>Methods of CustomPath</title>
+ <para>
+ This section introduces the method functions of <literal>CustomPath</>.
+ </para>
+ <para>
+<programlisting>
+CustomPlan *
+CreateCustomPlan(PlannerInfo *root,
+ CustomPath *custom_path);
+</programlisting>
+ This method pupolates a node object that (at least) extends
+ <literal>CustomPlan</> data type, according to the supplied
+ <literal>CustomPath</>.
+ If this custom-plan support mark-and-restore position, its
+ node tag should be <literal>CustomPlanMarkPos</>, instead of
+ <literal>CustomPlan</>.
+ </para>
+ <para>
+<programlisting>
+void
+TextOutCustomPath(StringInfo str, Node *node);
+</programlisting>
+ This method is needed to support <literal>nodeToString</> for your
+ custom path type to dump its private fields also.
+ The message format has to follow the manner in <filename>outfuncs.c</>.
+ </para>
+ </sect2>
+ <sect2 id="custom-plan-methods">
+ <title>Methods of CustomPlan</title>
+ <para>
+ This section introduces the method functions of <literal>CustomPlan</>.
+ </para>
+ <para>
+<programlisting>
+void
+SetCustomPlanRef(PlannerInfo *root,
+ CustomPlan *custom_plan,
+ int rtoffset);
+</programlisting>
+ This method requires custom-plan provides to adjust <literal>Var</> node
+ references in the supplied <literal>CustomPlan</> node.
+ Usually, it shall be shifted by <literal>rtoffset</>, or replaced by
+ <literal>INNER_VAR</> or <literal>OUTER_VAR</> if it references either
+ left or right subplan.
+ </para>
+ <para>
+<programlisting>
+bool
+SupportBackwardScan(CustomPlan *custom_plan);
+</programlisting>
+ This optional method informs the core backend whether this custom-plan
+ supports backward scan capability, or not.
+ If this method is implemented and returns <literal>true</>, it means
+ this custom-plan node supports backward scan. Elsewhere, it is not
+ available.
+ </para>
+ <para>
+<programlisting>
+void
+FinalizeCustomPlan(PlannerInfo *root,
+ CustomPlan *custom_plan,
+ Bitmapset **paramids,
+ Bitmapset **valid_params,
+ Bitmapset **scan_params);
+</programlisting>
+ This optional method informs the core backend which query parameters
+ are referenced in this custom-plan node, in addition to the ones
+ considered in the <literal>targetlist</> and <literal>qual</> fields
+ of the base <literal>Plan</> node.
+ If parameters are found in the private data field managed by custom-
+ plan provider, it needs to update the supplied bitmapset as expected
+ in the <literal>finalize_plan()</>.
+ </para>
+ <para>
+<programlisting>
+CustomPlanState *
+BeginCustomPlan(CustomPlan *custom_plan,
+ EState *estate,
+ int eflags);
+</programlisting>
+ This method populates a <literal>CustomPlanState</> object according to
+ the supplied <literal>CustomPlan</>, and initializes execution of this
+ custom-plan node, first of all.
+ </para>
+ <para>
+<programlisting>
+TupleTableSlot *
+ExecCustomPlan(CustomPlanState *cpstate);
+</programlisting>
+ It fetches one tuple from this custom-plan node. This custom-plan node
+ has to set a valid tuple on the <literal>ps_ResultTupleSlot</> and
+ return if any, or returns <literal>NULL</> to inform the upper node
+ it already reached end of the scan.
+ </para>
+ <para>
+<programlisting>
+Node *
+MultiExecCustomPlan(CustomPlanState *cpstate);
+</programlisting>
+ Unlike <literal>ExecCustomPlan</>, it allows upper node to fetch
+ multiple tuples, however, you need to pay attention the data format
+ and the way to return it because it fully depends on the type of
+ upper node.
+ </para>
+ <para>
+<programlisting>
+void
+EndCustomPlan(CustomPlanState *cpstate);
+</programlisting>
+ It ends the execution of this custom-plan node, and releases the
+ resources being allocated. Usually, it is not important to release
+ memory in the per execution memory context, so custom-plan provider
+ should be responsible to its own resources regardless of the framework.
+ </para>
+ <para>
+<programlisting>
+void
+ReScanCustomPlan(CustomPlanState *cpstate);
+</programlisting>
+ It restarts the current scan from the beginning.
+ Note that parameters of the scan depends on may change values,
+ so rewinded scan does not need to return exactly identical tuples.
+ </para>
+ <para>
+<programlisting>
+void
+MarkPosCustomPlan(CustomPlanState *cpstate);
+</programlisting>
+ It is optional, but should be implemented if <literal>CustomPlanMarkPos</>
+ was applied, instead of <literal>CustomPlan</>.
+ It saves the current position of the custom-plan on somewhere private
+ state, to restore the position later.
+ </para>
+ <para>
+<programlisting>
+void
+RestrPosCustomPlan(CustomPlanState *cpstate);
+</programlisting>
+ It is optional, but should be implemented if <literal>CustomPlanMarkPos</>
+ was applied, instead of <literal>CustomPlan</>.
+ It restores the current position of the custom-plan from the private
+ information being saved somewhere at <literal>MarkPosCustomPlan</>.
+ </para>
+ <para>
+<programlisting>
+void
+ExplainCustomPlanTargetRel(CustomPlanState *cpstate,
+ ExplainState *es);
+</programlisting>
+ It shows the target relation, if this custom-plan node replaced
+ a particular relation scan. Because of implementation reason, this
+ method is separated from the <literal>ExplainCustomPlan</>.
+ </para>
+ <para>
+<programlisting>
+void
+ExplainCustomPlan(CustomPlanState *cpstate,
+ List *ancestors,
+ ExplainState *es);
+</programlisting>
+ It put properties of this custom-plan node into the supplied
+ <literal>ExplainState</> according to the usual <command>EXPLAIN</>
+ manner.
+ </para>
+ <para>
+<programlisting>
+Bitmapset *
+GetRelidsCustomPlan(CustomPlanState *cpstate);
+</programlisting>
+ It returns a set of range-table indexes being scanned by this custom-
+ plan node. In case of multiple relations are underlying, it is not
+ always singleton bitmap.
+ </para>
+ <para>
+<programlisting>
+Node *
+GetSpecialCustomVar(CustomPlanState *cpstate,
+ Var *varnode);
+</programlisting>
+ This optional method returns an expression node to be referenced by
+ the supplied <literal>varnode</> that has special <literal>varno</>
+ (<literal>INNER_VAR</>, <literal>OUTER_VAR</> or <literal>INDEX_VAR</>).
+ <command>EXPLAIN</> command shows column name being referenced in the
+ targetlist or qualifiers of plan nodes. If a var node has special
+ <literal>varno</>, it recursively walks down the underlying subplan to
+ ensure the actual expression referenced by this special varno.
+ In case when a custom-plan node replaced a join node but does not have
+ underlying sub-plan on the left- and right-tree, it is unavailable to
+ use a usual logic, so custom-plan provider has to implement this method
+ to inform the core backend the expression node being referenced by
+ the supplied <literal>varnode</> that has special <literal>varno</>.
+ If this method is not implemented or returns <literal>NULL</>,
+ the core backend solves the special varnode reference as usual.
+ </para>
+ <para>
+<programlisting>
+void
+TextOutCustomPlan(StringInfo str, const CustomPlan *node);
+</programlisting>
+ This method is needed to support <literal>nodeToString</> for your
+ custom plan type to dump its private fields also.
+ The message format has to follow the manner in <filename>outfuncs.c</>.
+ </para>
+ <para>
+<programlisting>
+CustomPlan *
+CopyCustomPlan(const CustomPlan *from);
+</programlisting>
+ This methos is needed to support <literal>copyObject</> for your
+ custom plan type to copy its private fields also.
+ </para>
+ </sect2>
+ </sect1>
+</chapter>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index 0e863ee..33f964e 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -91,6 +91,7 @@
<!ENTITY nls SYSTEM "nls.sgml">
<!ENTITY plhandler SYSTEM "plhandler.sgml">
<!ENTITY fdwhandler SYSTEM "fdwhandler.sgml">
+<!ENTITY custom-plan SYSTEM "custom-plan.sgml">
<!ENTITY protocol SYSTEM "protocol.sgml">
<!ENTITY sources SYSTEM "sources.sgml">
<!ENTITY storage SYSTEM "storage.sgml">
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index b47bf52..45e9d32 100644
--- a/doc/src/sgml/postgres.sgml
+++ b/doc/src/sgml/postgres.sgml
@@ -241,6 +241,7 @@
&nls;
&plhandler;
&fdwhandler;
+ &custom-plan;
&geqo;
&indexam;
&gist;
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 08f3167..ff9fc7b 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -19,6 +19,7 @@
#include "commands/defrem.h"
#include "commands/prepare.h"
#include "executor/hashjoin.h"
+#include "executor/nodeCustom.h"
#include "foreign/fdwapi.h"
#include "optimizer/clauses.h"
#include "parser/parsetree.h"
@@ -51,7 +52,6 @@ static void ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es,
static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
ExplainState *es);
static double elapsed_time(instr_time *starttime);
-static void ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used);
static void ExplainPreScanMemberNodes(List *plans, PlanState **planstates,
Bitmapset **rels_used);
static void ExplainPreScanSubPlans(List *plans, Bitmapset **rels_used);
@@ -700,7 +700,7 @@ elapsed_time(instr_time *starttime)
* This ensures that we don't confusingly assign un-suffixed aliases to RTEs
* that never appear in the EXPLAIN output (such as inheritance parents).
*/
-static void
+void
ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
{
Plan *plan = planstate->plan;
@@ -721,6 +721,16 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
*rels_used = bms_add_member(*rels_used,
((Scan *) plan)->scanrelid);
break;
+ case T_CustomPlan:
+ case T_CustomPlanMarkPos:
+ {
+ CustomPlanState *cpstate = (CustomPlanState *)planstate;
+ Bitmapset *temp
+ = cpstate->methods->GetRelidsCustomPlan(cpstate);
+
+ *rels_used = bms_union(*rels_used, temp);
+ }
+ break;
case T_ModifyTable:
/* cf ExplainModifyTarget */
*rels_used = bms_add_member(*rels_used,
@@ -847,6 +857,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
const char *sname; /* node type name for non-text output */
const char *strategy = NULL;
const char *operation = NULL;
+ const char *custom_name = NULL;
int save_indent = es->indent;
bool haschildren;
@@ -935,6 +946,14 @@ ExplainNode(PlanState *planstate, List *ancestors,
case T_ForeignScan:
pname = sname = "Foreign Scan";
break;
+ case T_CustomPlan:
+ sname = "Custom";
+ custom_name = ((CustomPlan *) plan)->methods->CustomName;
+ if (custom_name != NULL)
+ pname = psprintf("Custom (%s)", custom_name);
+ else
+ pname = sname;
+ break;
case T_Material:
pname = sname = "Materialize";
break;
@@ -1036,6 +1055,8 @@ ExplainNode(PlanState *planstate, List *ancestors,
ExplainPropertyText("Parent Relationship", relationship, es);
if (plan_name)
ExplainPropertyText("Subplan Name", plan_name, es);
+ if (custom_name)
+ ExplainPropertyText("Custom", custom_name, es);
}
switch (nodeTag(plan))
@@ -1051,6 +1072,14 @@ ExplainNode(PlanState *planstate, List *ancestors,
case T_ForeignScan:
ExplainScanTarget((Scan *) plan, es);
break;
+ case T_CustomPlan:
+ {
+ CustomPlanState *cps = (CustomPlanState *)planstate;
+
+ if (cps->methods->ExplainCustomPlanTargetRel)
+ cps->methods->ExplainCustomPlanTargetRel(cps, es);
+ }
+ break;
case T_IndexScan:
{
IndexScan *indexscan = (IndexScan *) plan;
@@ -1347,6 +1376,18 @@ ExplainNode(PlanState *planstate, List *ancestors,
planstate, es);
show_foreignscan_info((ForeignScanState *) planstate, es);
break;
+ case T_CustomPlan:
+ show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
+ if (plan->qual)
+ show_instrumentation_count("Rows Removed by Filter", 1,
+ planstate, es);
+ if (((CustomPlanState *) planstate)->methods->ExplainCustomPlan)
+ {
+ CustomPlanState *cpstate = (CustomPlanState *) planstate;
+
+ cpstate->methods->ExplainCustomPlan(cpstate, ancestors, es);
+ }
+ break;
case T_NestLoop:
show_upper_qual(((NestLoop *) plan)->join.joinqual,
"Join Filter", planstate, ancestors, es);
diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile
index 6081b56..4dece5a 100644
--- a/src/backend/executor/Makefile
+++ b/src/backend/executor/Makefile
@@ -15,7 +15,7 @@ include $(top_builddir)/src/Makefile.global
OBJS = execAmi.o execCurrent.o execGrouping.o execJunk.o execMain.o \
execProcnode.o execQual.o execScan.o execTuples.o \
execUtils.o functions.o instrument.o nodeAppend.o nodeAgg.o \
- nodeBitmapAnd.o nodeBitmapOr.o \
+ nodeBitmapAnd.o nodeBitmapOr.o nodeCustom.o \
nodeBitmapHeapscan.o nodeBitmapIndexscan.o nodeHash.o \
nodeHashjoin.o nodeIndexscan.o nodeIndexonlyscan.o \
nodeLimit.o nodeLockRows.o \
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index 8c01a63..47e7a3c 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -21,6 +21,7 @@
#include "executor/nodeBitmapIndexscan.h"
#include "executor/nodeBitmapOr.h"
#include "executor/nodeCtescan.h"
+#include "executor/nodeCustom.h"
#include "executor/nodeForeignscan.h"
#include "executor/nodeFunctionscan.h"
#include "executor/nodeGroup.h"
@@ -197,6 +198,10 @@ ExecReScan(PlanState *node)
ExecReScanForeignScan((ForeignScanState *) node);
break;
+ case T_CustomPlanState:
+ ExecReScanCustomPlan((CustomPlanState *) node);
+ break;
+
case T_NestLoopState:
ExecReScanNestLoop((NestLoopState *) node);
break;
@@ -291,6 +296,10 @@ ExecMarkPos(PlanState *node)
ExecValuesMarkPos((ValuesScanState *) node);
break;
+ case T_CustomPlanState:
+ ExecCustomMarkPos((CustomPlanState *) node);
+ break;
+
case T_MaterialState:
ExecMaterialMarkPos((MaterialState *) node);
break;
@@ -348,6 +357,10 @@ ExecRestrPos(PlanState *node)
ExecValuesRestrPos((ValuesScanState *) node);
break;
+ case T_CustomPlanState:
+ ExecCustomRestrPos((CustomPlanState *) node);
+ break;
+
case T_MaterialState:
ExecMaterialRestrPos((MaterialState *) node);
break;
@@ -390,6 +403,7 @@ ExecSupportsMarkRestore(NodeTag plantype)
case T_ValuesScan:
case T_Material:
case T_Sort:
+ case T_CustomPlanMarkPos:
return true;
case T_Result:
@@ -465,6 +479,15 @@ ExecSupportsBackwardScan(Plan *node)
return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan) &&
TargetListSupportsBackwardScan(node->targetlist);
+ case T_CustomPlan:
+ {
+ CustomPlan *cplan = (CustomPlan *) node;
+
+ if (cplan->methods->SupportBackwardScan)
+ return cplan->methods->SupportBackwardScan(cplan);
+ }
+ return false;
+
case T_Material:
case T_Sort:
/* these don't evaluate tlist */
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index c5ecd18..5aa117b 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -85,6 +85,7 @@
#include "executor/nodeBitmapIndexscan.h"
#include "executor/nodeBitmapOr.h"
#include "executor/nodeCtescan.h"
+#include "executor/nodeCustom.h"
#include "executor/nodeForeignscan.h"
#include "executor/nodeFunctionscan.h"
#include "executor/nodeGroup.h"
@@ -244,6 +245,12 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
estate, eflags);
break;
+ case T_CustomPlan:
+ case T_CustomPlanMarkPos:
+ result = (PlanState *) ExecInitCustomPlan((CustomPlan *) node,
+ estate, eflags);
+ break;
+
/*
* join nodes
*/
@@ -442,6 +449,10 @@ ExecProcNode(PlanState *node)
result = ExecForeignScan((ForeignScanState *) node);
break;
+ case T_CustomPlanState:
+ result = ExecCustomPlan((CustomPlanState *) node);
+ break;
+
/*
* join nodes
*/
@@ -678,6 +689,10 @@ ExecEndNode(PlanState *node)
ExecEndForeignScan((ForeignScanState *) node);
break;
+ case T_CustomPlanState:
+ ExecEndCustomPlan((CustomPlanState *) node);
+ break;
+
/*
* join nodes
*/
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
new file mode 100644
index 0000000..e3c8f58
--- /dev/null
+++ b/src/backend/executor/nodeCustom.c
@@ -0,0 +1,73 @@
+/* ------------------------------------------------------------------------
+ *
+ * nodeCustom.c
+ * Routines to handle execution of custom plan node
+ *
+ * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * ------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "executor/executor.h"
+#include "executor/nodeCustom.h"
+#include "nodes/execnodes.h"
+#include "nodes/plannodes.h"
+#include "parser/parsetree.h"
+#include "utils/hsearch.h"
+#include "utils/memutils.h"
+#include "utils/rel.h"
+
+CustomPlanState *
+ExecInitCustomPlan(CustomPlan *custom_plan, EState *estate, int eflags)
+{
+ CustomPlanState *cpstate
+ = custom_plan->methods->BeginCustomPlan(custom_plan, estate, eflags);
+
+ Assert(IsA(cpstate, CustomPlanState));
+
+ return cpstate;
+}
+
+TupleTableSlot *
+ExecCustomPlan(CustomPlanState *cpstate)
+{
+ Assert(cpstate->methods->ExecCustomPlan != NULL);
+ return cpstate->methods->ExecCustomPlan(cpstate);
+}
+
+Node *
+MultiExecCustomPlan(CustomPlanState *cpstate)
+{
+ Assert(cpstate->methods->MultiExecCustomPlan != NULL);
+ return cpstate->methods->MultiExecCustomPlan(cpstate);
+}
+
+void
+ExecEndCustomPlan(CustomPlanState *cpstate)
+{
+ Assert(cpstate->methods->EndCustomPlan != NULL);
+ cpstate->methods->EndCustomPlan(cpstate);
+}
+
+void
+ExecReScanCustomPlan(CustomPlanState *cpstate)
+{
+ Assert(cpstate->methods->ReScanCustomPlan != NULL);
+ cpstate->methods->ReScanCustomPlan(cpstate);
+}
+
+void
+ExecCustomMarkPos(CustomPlanState *cpstate)
+{
+ Assert(cpstate->methods->MarkPosCustomPlan != NULL);
+ cpstate->methods->MarkPosCustomPlan(cpstate);
+}
+
+void
+ExecCustomRestrPos(CustomPlanState *cpstate)
+{
+ Assert(cpstate->methods->RestrPosCustomPlan != NULL);
+ cpstate->methods->RestrPosCustomPlan(cpstate);
+}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index c89d808..18505cd 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -598,6 +598,42 @@ _copyForeignScan(const ForeignScan *from)
}
/*
+ * _copyCustomPlan
+ */
+static CustomPlan *
+_copyCustomPlan(const CustomPlan *from)
+{
+ CustomPlan *newnode = from->methods->CopyCustomPlan(from);
+
+ Assert(IsA(newnode, CustomPlan));
+ return newnode;
+}
+
+/*
+ * _copyCustomPlanMarkPos
+ */
+static CustomPlanMarkPos *
+_copyCustomPlanMarkPos(const CustomPlanMarkPos *from)
+{
+ CustomPlanMarkPos *newnode = from->methods->CopyCustomPlan(from);
+
+ Assert(IsA(newnode, CustomPlanMarkPos));
+ return newnode;
+}
+
+/* copy common part of CustomPlan */
+void
+CopyCustomPlanCommon(const Node *__from, Node *__newnode)
+{
+ CustomPlan *from = (CustomPlan *) __from;
+ CustomPlan *newnode = (CustomPlan *) __newnode;
+
+ ((Node *) newnode)->type = nodeTag(from);
+ CopyPlanFields((const Plan *) from, (Plan *) newnode);
+ COPY_SCALAR_FIELD(methods);
+}
+
+/*
* CopyJoinFields
*
* This function copies the fields of the Join node. It is used by
@@ -3983,6 +4019,12 @@ copyObject(const void *from)
case T_ForeignScan:
retval = _copyForeignScan(from);
break;
+ case T_CustomPlan:
+ retval = _copyCustomPlan(from);
+ break;
+ case T_CustomPlanMarkPos:
+ retval = _copyCustomPlanMarkPos(from);
+ break;
case T_Join:
retval = _copyJoin(from);
break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index bfb4b9f..8a93bc5 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -563,6 +563,27 @@ _outForeignScan(StringInfo str, const ForeignScan *node)
WRITE_BOOL_FIELD(fsSystemCol);
}
+/* dump common part of CustomPlan structure */
+static void
+_outCustomPlan(StringInfo str, const CustomPlan *node)
+{
+ WRITE_NODE_TYPE("CUSTOMPLAN");
+ _outPlanInfo(str, (const Plan *) node);
+ appendStringInfo(str, " :methods");
+ _outToken(str, node->methods->CustomName);
+ node->methods->TextOutCustomPlan(str, node);
+}
+
+static void
+_outCustomPlanMarkPos(StringInfo str, const CustomPlanMarkPos *node)
+{
+ WRITE_NODE_TYPE("CUSTOMPLANMARKPOS");
+ _outPlanInfo(str, (const Plan *) node);
+ appendStringInfo(str, " :methods");
+ _outToken(str, node->methods->CustomName);
+ node->methods->TextOutCustomPlan(str, node);
+}
+
static void
_outJoin(StringInfo str, const Join *node)
{
@@ -1581,6 +1602,16 @@ _outForeignPath(StringInfo str, const ForeignPath *node)
}
static void
+_outCustomPath(StringInfo str, const CustomPath *node)
+{
+ WRITE_NODE_TYPE("CUSTOMPATH");
+ _outPathInfo(str, (const Path *) node);
+ appendStringInfo(str, " :methods");
+ _outToken(str, node->methods->CustomName);
+ node->methods->TextOutCustomPath(str, (Node *)node);
+}
+
+static void
_outAppendPath(StringInfo str, const AppendPath *node)
{
WRITE_NODE_TYPE("APPENDPATH");
@@ -2828,6 +2859,12 @@ _outNode(StringInfo str, const void *obj)
case T_ForeignScan:
_outForeignScan(str, obj);
break;
+ case T_CustomPlan:
+ _outCustomPlan(str, obj);
+ break;
+ case T_CustomPlanMarkPos:
+ _outCustomPlanMarkPos(str, obj);
+ break;
case T_Join:
_outJoin(str, obj);
break;
@@ -3036,6 +3073,9 @@ _outNode(StringInfo str, const void *obj)
case T_ForeignPath:
_outForeignPath(str, obj);
break;
+ case T_CustomPath:
+ _outCustomPath(str, obj);
+ break;
case T_AppendPath:
_outAppendPath(str, obj);
break;
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 03be7b1..6c1ea7e 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -47,6 +47,8 @@ int geqo_threshold;
/* Hook for plugins to replace standard_join_search() */
join_search_hook_type join_search_hook = NULL;
+/* Hook for plugins to add custom scan paths */
+add_scan_path_hook_type add_scan_path_hook = NULL;
static void set_base_rel_sizes(PlannerInfo *root);
static void set_base_rel_pathlists(PlannerInfo *root);
@@ -323,7 +325,7 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
}
break;
case RTE_SUBQUERY:
- /* Subquery --- fully handled during set_rel_size */
+ /* Subquery --- path was added during set_rel_size */
break;
case RTE_FUNCTION:
/* RangeFunction */
@@ -334,12 +336,19 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
set_values_pathlist(root, rel, rte);
break;
case RTE_CTE:
- /* CTE reference --- fully handled during set_rel_size */
+ /* CTE reference --- path was added during set_rel_size */
break;
default:
elog(ERROR, "unexpected rtekind: %d", (int) rel->rtekind);
break;
}
+
+ /* Also, consider custom plans */
+ if (add_scan_path_hook)
+ (*add_scan_path_hook)(root, rel, rte);
+
+ /* Select cheapest path */
+ set_cheapest(rel);
}
#ifdef OPTIMIZER_DEBUG
@@ -388,9 +397,6 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
/* Consider TID scans */
create_tidscan_paths(root, rel);
-
- /* Now find the cheapest of the paths for this rel */
- set_cheapest(rel);
}
/*
@@ -416,9 +422,6 @@ set_foreign_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
{
/* Call the FDW's GetForeignPaths function to generate path(s) */
rel->fdwroutine->GetForeignPaths(root, rel, rte->relid);
-
- /* Select cheapest path */
- set_cheapest(rel);
}
/*
@@ -1235,9 +1238,6 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
/* Generate appropriate path */
add_path(rel, create_subqueryscan_path(root, rel, pathkeys, required_outer));
-
- /* Select cheapest path (pretty easy in this case...) */
- set_cheapest(rel);
}
/*
@@ -1306,9 +1306,6 @@ set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
/* Generate appropriate path */
add_path(rel, create_functionscan_path(root, rel,
pathkeys, required_outer));
-
- /* Select cheapest path (pretty easy in this case...) */
- set_cheapest(rel);
}
/*
@@ -1329,9 +1326,6 @@ set_values_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
/* Generate appropriate path */
add_path(rel, create_valuesscan_path(root, rel, required_outer));
-
- /* Select cheapest path (pretty easy in this case...) */
- set_cheapest(rel);
}
/*
@@ -1398,9 +1392,6 @@ set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
/* Generate appropriate path */
add_path(rel, create_ctescan_path(root, rel, required_outer));
-
- /* Select cheapest path (pretty easy in this case...) */
- set_cheapest(rel);
}
/*
@@ -1451,9 +1442,6 @@ set_worktable_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
/* Generate appropriate path */
add_path(rel, create_worktablescan_path(root, rel, required_outer));
-
- /* Select cheapest path (pretty easy in this case...) */
- set_cheapest(rel);
}
/*
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index a996116..2fb6678 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -21,6 +21,8 @@
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
+/* Hook for plugins to add custom join paths */
+add_join_path_hook_type add_join_path_hook = NULL;
#define PATH_PARAM_BY_REL(path, rel) \
((path)->param_info && bms_overlap(PATH_REQ_OUTER(path), (rel)->relids))
@@ -259,6 +261,20 @@ add_paths_to_joinrel(PlannerInfo *root,
restrictlist, jointype,
sjinfo, &semifactors,
param_source_rels, extra_lateral_rels);
+
+ /*
+ * 5. Also consider paths being provided with custom execution provider.
+ */
+ if (add_join_path_hook)
+ (*add_join_path_hook)(root,
+ joinrel,
+ outerrel,
+ innerrel,
+ jointype,
+ sjinfo,
+ restrictlist,
+ param_source_rels,
+ extra_lateral_rels);
}
/*
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 184d37a..055a818 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -42,11 +42,7 @@
#include "utils/lsyscache.h"
-static Plan *create_plan_recurse(PlannerInfo *root, Path *best_path);
static Plan *create_scan_plan(PlannerInfo *root, Path *best_path);
-static List *build_path_tlist(PlannerInfo *root, Path *path);
-static bool use_physical_tlist(PlannerInfo *root, RelOptInfo *rel);
-static void disuse_physical_tlist(PlannerInfo *root, Plan *plan, Path *path);
static Plan *create_gating_plan(PlannerInfo *root, Plan *plan, List *quals);
static Plan *create_join_plan(PlannerInfo *root, JoinPath *best_path);
static Plan *create_append_plan(PlannerInfo *root, AppendPath *best_path);
@@ -77,23 +73,20 @@ static WorkTableScan *create_worktablescan_plan(PlannerInfo *root, Path *best_pa
List *tlist, List *scan_clauses);
static ForeignScan *create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
List *tlist, List *scan_clauses);
+static CustomPlan *create_custom_plan(PlannerInfo *root,
+ CustomPath *best_path);
static NestLoop *create_nestloop_plan(PlannerInfo *root, NestPath *best_path,
Plan *outer_plan, Plan *inner_plan);
static MergeJoin *create_mergejoin_plan(PlannerInfo *root, MergePath *best_path,
Plan *outer_plan, Plan *inner_plan);
static HashJoin *create_hashjoin_plan(PlannerInfo *root, HashPath *best_path,
Plan *outer_plan, Plan *inner_plan);
-static Node *replace_nestloop_params(PlannerInfo *root, Node *expr);
static Node *replace_nestloop_params_mutator(Node *node, PlannerInfo *root);
static void process_subquery_nestloop_params(PlannerInfo *root,
List *subplan_params);
static List *fix_indexqual_references(PlannerInfo *root, IndexPath *index_path);
static List *fix_indexorderby_references(PlannerInfo *root, IndexPath *index_path);
static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index, int indexcol);
-static List *get_switched_clauses(List *clauses, Relids outerrelids);
-static List *order_qual_clauses(PlannerInfo *root, List *clauses);
-static void copy_path_costsize(Plan *dest, Path *src);
-static void copy_plan_costsize(Plan *dest, Plan *src);
static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
Oid indexid, List *indexqual, List *indexqualorig,
@@ -215,7 +208,7 @@ create_plan(PlannerInfo *root, Path *best_path)
* create_plan_recurse
* Recursive guts of create_plan().
*/
-static Plan *
+Plan *
create_plan_recurse(PlannerInfo *root, Path *best_path)
{
Plan *plan;
@@ -261,6 +254,9 @@ create_plan_recurse(PlannerInfo *root, Path *best_path)
plan = create_unique_plan(root,
(UniquePath *) best_path);
break;
+ case T_CustomPlan:
+ plan = (Plan *) create_custom_plan(root, (CustomPath *) best_path);
+ break;
default:
elog(ERROR, "unrecognized node type: %d",
(int) best_path->pathtype);
@@ -430,7 +426,7 @@ create_scan_plan(PlannerInfo *root, Path *best_path)
/*
* Build a target list (ie, a list of TargetEntry) for the Path's output.
*/
-static List *
+List *
build_path_tlist(PlannerInfo *root, Path *path)
{
RelOptInfo *rel = path->parent;
@@ -466,7 +462,7 @@ build_path_tlist(PlannerInfo *root, Path *path)
* Decide whether to use a tlist matching relation structure,
* rather than only those Vars actually referenced.
*/
-static bool
+bool
use_physical_tlist(PlannerInfo *root, RelOptInfo *rel)
{
int i;
@@ -526,7 +522,7 @@ use_physical_tlist(PlannerInfo *root, RelOptInfo *rel)
* undo the decision made by use_physical_tlist(). Currently, Hash, Sort,
* and Material nodes want this, so they don't have to store useless columns.
*/
-static void
+void
disuse_physical_tlist(PlannerInfo *root, Plan *plan, Path *path)
{
/* Only need to undo it for path types handled by create_scan_plan() */
@@ -569,7 +565,7 @@ disuse_physical_tlist(PlannerInfo *root, Plan *plan, Path *path)
* in most cases we have only a very bad idea of the probability of the gating
* qual being true.
*/
-static Plan *
+Plan *
create_gating_plan(PlannerInfo *root, Plan *plan, List *quals)
{
List *pseudoconstants;
@@ -1072,6 +1068,26 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
return plan;
}
+/*
+ * create_custom_plan
+ * Returns a custom-scan plan for the base relation scanned by 'best_path'
+ * with restriction clauses 'scan_clauses' and targetlist 'tlist'.
+ */
+static CustomPlan *
+create_custom_plan(PlannerInfo *root, CustomPath *best_path)
+{
+ CustomPlan *cplan;
+
+ /* Populate CustomPlan according to the CustomPath */
+ Assert(best_path->methods->CreateCustomPlan != NULL);
+ cplan = best_path->methods->CreateCustomPlan(root, best_path);
+ Assert(IsA(cplan, CustomPlan) || IsA(cplan, CustomPlanMarkPos));
+
+ /* Copy cost data from Path to Plan; no need to make callback do this */
+ copy_path_costsize(&cplan->plan, &best_path->path);
+
+ return cplan;
+}
/*****************************************************************************
*
@@ -2006,7 +2022,6 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
return scan_plan;
}
-
/*****************************************************************************
*
* JOIN METHODS
@@ -2540,7 +2555,7 @@ create_hashjoin_plan(PlannerInfo *root,
* root->curOuterRels are replaced by Params, and entries are added to
* root->curOuterParams if not already present.
*/
-static Node *
+Node *
replace_nestloop_params(PlannerInfo *root, Node *expr)
{
/* No setup needed for tree walk, so away we go */
@@ -3023,7 +3038,7 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index, int indexcol)
* touched; a modified list is returned. We do, however, set the transient
* outer_is_left field in each RestrictInfo to show which side was which.
*/
-static List *
+List *
get_switched_clauses(List *clauses, Relids outerrelids)
{
List *t_list = NIL;
@@ -3089,7 +3104,7 @@ get_switched_clauses(List *clauses, Relids outerrelids)
* instead of bare clauses. It's OK because we only sort by cost, but
* a cost/selectivity combination would likely do the wrong thing.
*/
-static List *
+List *
order_qual_clauses(PlannerInfo *root, List *clauses)
{
typedef struct
@@ -3156,7 +3171,7 @@ order_qual_clauses(PlannerInfo *root, List *clauses)
* Copy cost and size info from a Path node to the Plan node created from it.
* The executor usually won't use this info, but it's needed by EXPLAIN.
*/
-static void
+void
copy_path_costsize(Plan *dest, Path *src)
{
if (src)
@@ -3179,7 +3194,7 @@ copy_path_costsize(Plan *dest, Path *src)
* Copy cost and size info from a lower plan node to an inserted node.
* (Most callers alter the info after copying it.)
*/
-static void
+void
copy_plan_costsize(Plan *dest, Plan *src)
{
if (src)
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 46affe7..738d47c 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -17,6 +17,7 @@
#include "access/transam.h"
#include "catalog/pg_type.h"
+#include "executor/nodeCustom.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/pathnode.h"
@@ -86,7 +87,6 @@ static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing);
static void flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte);
static bool flatten_rtes_walker(Node *node, PlannerGlobal *glob);
static void add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte);
-static Plan *set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset);
static Plan *set_indexonlyscan_references(PlannerInfo *root,
IndexOnlyScan *plan,
int rtoffset);
@@ -419,7 +419,7 @@ add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte)
/*
* set_plan_refs: recurse through the Plan nodes of a single subquery level
*/
-static Plan *
+Plan *
set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
{
ListCell *l;
@@ -576,6 +576,22 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
}
break;
+ case T_CustomPlan:
+ case T_CustomPlanMarkPos:
+ {
+ CustomPlan *cplan = (CustomPlan *) plan;
+
+ /*
+ * Extension is responsible to handle set-reference
+ * correctly.
+ */
+ Assert(cplan->methods->SetCustomPlanRef != NULL);
+ cplan->methods->SetCustomPlanRef(root,
+ cplan,
+ rtoffset);
+ }
+ break;
+
case T_NestLoop:
case T_MergeJoin:
case T_HashJoin:
@@ -1057,7 +1073,7 @@ copyVar(Var *var)
* We assume it's okay to update opcode info in-place. So this could possibly
* scribble on the planner's input data structures, but it's OK.
*/
-static void
+void
fix_expr_common(PlannerInfo *root, Node *node)
{
/* We assume callers won't call us on a NULL pointer */
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index a3f3583..6b0c762 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -75,12 +75,8 @@ static Query *convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect,
static Node *replace_correlation_vars_mutator(Node *node, PlannerInfo *root);
static Node *process_sublinks_mutator(Node *node,
process_sublinks_context *context);
-static Bitmapset *finalize_plan(PlannerInfo *root,
- Plan *plan,
- Bitmapset *valid_params,
- Bitmapset *scan_params);
-static bool finalize_primnode(Node *node, finalize_primnode_context *context);
-
+static bool finalize_primnode_walker(Node *node,
+ finalize_primnode_context *context);
/*
* Select a PARAM_EXEC number to identify the given Var as a parameter for
@@ -2045,7 +2041,7 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan, bool attach_initplans)
* The return value is the computed allParam set for the given Plan node.
* This is just an internal notational convenience.
*/
-static Bitmapset *
+Bitmapset *
finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
Bitmapset *scan_params)
{
@@ -2070,15 +2066,15 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
*/
/* Find params in targetlist and qual */
- finalize_primnode((Node *) plan->targetlist, &context);
- finalize_primnode((Node *) plan->qual, &context);
+ finalize_primnode_walker((Node *) plan->targetlist, &context);
+ finalize_primnode_walker((Node *) plan->qual, &context);
/* Check additional node-type-specific fields */
switch (nodeTag(plan))
{
case T_Result:
- finalize_primnode(((Result *) plan)->resconstantqual,
- &context);
+ finalize_primnode_walker(((Result *) plan)->resconstantqual,
+ &context);
break;
case T_SeqScan:
@@ -2086,10 +2082,10 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
break;
case T_IndexScan:
- finalize_primnode((Node *) ((IndexScan *) plan)->indexqual,
- &context);
- finalize_primnode((Node *) ((IndexScan *) plan)->indexorderby,
- &context);
+ finalize_primnode_walker((Node *)((IndexScan *)plan)->indexqual,
+ &context);
+ finalize_primnode_walker((Node *)((IndexScan *)plan)->indexorderby,
+ &context);
/*
* we need not look at indexqualorig, since it will have the same
@@ -2100,10 +2096,10 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
break;
case T_IndexOnlyScan:
- finalize_primnode((Node *) ((IndexOnlyScan *) plan)->indexqual,
- &context);
- finalize_primnode((Node *) ((IndexOnlyScan *) plan)->indexorderby,
- &context);
+ finalize_primnode_walker((Node *)((IndexOnlyScan *) plan)->indexqual,
+ &context);
+ finalize_primnode_walker((Node *) ((IndexOnlyScan *) plan)->indexorderby,
+ &context);
/*
* we need not look at indextlist, since it cannot contain Params.
@@ -2112,8 +2108,8 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
break;
case T_BitmapIndexScan:
- finalize_primnode((Node *) ((BitmapIndexScan *) plan)->indexqual,
- &context);
+ finalize_primnode_walker((Node *) ((BitmapIndexScan *) plan)->indexqual,
+ &context);
/*
* we need not look at indexqualorig, since it will have the same
@@ -2122,14 +2118,14 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
break;
case T_BitmapHeapScan:
- finalize_primnode((Node *) ((BitmapHeapScan *) plan)->bitmapqualorig,
- &context);
+ finalize_primnode_walker((Node *) ((BitmapHeapScan *) plan)->bitmapqualorig,
+ &context);
context.paramids = bms_add_members(context.paramids, scan_params);
break;
case T_TidScan:
- finalize_primnode((Node *) ((TidScan *) plan)->tidquals,
- &context);
+ finalize_primnode_walker((Node *) ((TidScan *) plan)->tidquals,
+ &context);
context.paramids = bms_add_members(context.paramids, scan_params);
break;
@@ -2167,7 +2163,7 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
funccontext = context;
funccontext.paramids = NULL;
- finalize_primnode(rtfunc->funcexpr, &funccontext);
+ finalize_primnode_walker(rtfunc->funcexpr, &funccontext);
/* remember results for execution */
rtfunc->funcparams = funccontext.paramids;
@@ -2183,8 +2179,8 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
break;
case T_ValuesScan:
- finalize_primnode((Node *) ((ValuesScan *) plan)->values_lists,
- &context);
+ finalize_primnode_walker((Node *) ((ValuesScan *) plan)->values_lists,
+ &context);
context.paramids = bms_add_members(context.paramids, scan_params);
break;
@@ -2231,11 +2227,24 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
break;
case T_ForeignScan:
- finalize_primnode((Node *) ((ForeignScan *) plan)->fdw_exprs,
- &context);
+ finalize_primnode_walker((Node *)((ForeignScan *) plan)->fdw_exprs,
+ &context);
context.paramids = bms_add_members(context.paramids, scan_params);
break;
+ case T_CustomPlan:
+ {
+ CustomPlan *cplan = (CustomPlan *) plan;
+
+ if (cplan->methods->FinalizeCustomPlan)
+ cplan->methods->FinalizeCustomPlan(root,
+ cplan,
+ &context.paramids,
+ &valid_params,
+ &scan_params);
+ }
+ break;
+
case T_ModifyTable:
{
ModifyTable *mtplan = (ModifyTable *) plan;
@@ -2247,8 +2256,8 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
locally_added_param);
scan_params = bms_add_member(bms_copy(scan_params),
locally_added_param);
- finalize_primnode((Node *) mtplan->returningLists,
- &context);
+ finalize_primnode_walker((Node *) mtplan->returningLists,
+ &context);
foreach(l, mtplan->plans)
{
context.paramids =
@@ -2329,8 +2338,8 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
{
ListCell *l;
- finalize_primnode((Node *) ((Join *) plan)->joinqual,
- &context);
+ finalize_primnode_walker((Node *) ((Join *) plan)->joinqual,
+ &context);
/* collect set of params that will be passed to right child */
foreach(l, ((NestLoop *) plan)->nestParams)
{
@@ -2343,24 +2352,24 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
break;
case T_MergeJoin:
- finalize_primnode((Node *) ((Join *) plan)->joinqual,
- &context);
- finalize_primnode((Node *) ((MergeJoin *) plan)->mergeclauses,
- &context);
+ finalize_primnode_walker((Node *) ((Join *) plan)->joinqual,
+ &context);
+ finalize_primnode_walker((Node *) ((MergeJoin *) plan)->mergeclauses,
+ &context);
break;
case T_HashJoin:
- finalize_primnode((Node *) ((Join *) plan)->joinqual,
- &context);
- finalize_primnode((Node *) ((HashJoin *) plan)->hashclauses,
+ finalize_primnode_walker((Node *) ((Join *) plan)->joinqual,
+ &context);
+ finalize_primnode_walker((Node *) ((HashJoin *) plan)->hashclauses,
&context);
break;
case T_Limit:
- finalize_primnode(((Limit *) plan)->limitOffset,
- &context);
- finalize_primnode(((Limit *) plan)->limitCount,
- &context);
+ finalize_primnode_walker(((Limit *) plan)->limitOffset,
+ &context);
+ finalize_primnode_walker(((Limit *) plan)->limitCount,
+ &context);
break;
case T_RecursiveUnion:
@@ -2381,10 +2390,10 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
break;
case T_WindowAgg:
- finalize_primnode(((WindowAgg *) plan)->startOffset,
- &context);
- finalize_primnode(((WindowAgg *) plan)->endOffset,
- &context);
+ finalize_primnode_walker(((WindowAgg *) plan)->startOffset,
+ &context);
+ finalize_primnode_walker(((WindowAgg *) plan)->endOffset,
+ &context);
break;
case T_Hash:
@@ -2473,8 +2482,21 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
* finalize_primnode: add IDs of all PARAM_EXEC params appearing in the given
* expression tree to the result set.
*/
+Bitmapset *
+finalize_primnode(PlannerInfo *root, Node *node, Bitmapset *paramids)
+{
+ finalize_primnode_context context;
+
+ context.root = root;
+ context.paramids = paramids;
+
+ finalize_primnode_walker(node, &context);
+
+ return context.paramids;
+}
+
static bool
-finalize_primnode(Node *node, finalize_primnode_context *context)
+finalize_primnode_walker(Node *node, finalize_primnode_context *context)
{
if (node == NULL)
return false;
@@ -2496,7 +2518,7 @@ finalize_primnode(Node *node, finalize_primnode_context *context)
Bitmapset *subparamids;
/* Recurse into the testexpr, but not into the Plan */
- finalize_primnode(subplan->testexpr, context);
+ finalize_primnode_walker(subplan->testexpr, context);
/*
* Remove any param IDs of output parameters of the subplan that were
@@ -2513,7 +2535,7 @@ finalize_primnode(Node *node, finalize_primnode_context *context)
}
/* Also examine args list */
- finalize_primnode((Node *) subplan->args, context);
+ finalize_primnode_walker((Node *) subplan->args, context);
/*
* Add params needed by the subplan to paramids, but excluding those
@@ -2528,7 +2550,7 @@ finalize_primnode(Node *node, finalize_primnode_context *context)
return false; /* no more to do here */
}
- return expression_tree_walker(node, finalize_primnode,
+ return expression_tree_walker(node, finalize_primnode_walker,
(void *) context);
}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 566b4c9..1c57352 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -5292,6 +5292,25 @@ get_utility_query_def(Query *query, deparse_context *context)
}
}
+/*
+ * GetSpecialCustomVar
+ *
+ * Utility routine to call optional GetSpecialCustomVar method of
+ * CustomPlanState
+ */
+static Node *
+GetSpecialCustomVar(PlanState *ps, Var *varnode)
+{
+ CustomPlanState *cps = (CustomPlanState *) ps;
+
+ Assert(IsA(ps, CustomPlanState));
+ Assert(IS_SPECIAL_VARNO(varnode->varno));
+
+ if (cps->methods->GetSpecialCustomVar)
+ return (Node *)cps->methods->GetSpecialCustomVar(cps, varnode);
+
+ return NULL;
+}
/*
* Display a Var appropriately.
@@ -5323,6 +5342,7 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
deparse_columns *colinfo;
char *refname;
char *attname;
+ Node *expr;
/* Find appropriate nesting depth */
netlevelsup = var->varlevelsup + levelsup;
@@ -5345,6 +5365,22 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
colinfo = deparse_columns_fetch(var->varno, dpns);
attnum = var->varattno;
}
+ else if (IS_SPECIAL_VARNO(var->varno) &&
+ IsA(dpns->planstate, CustomPlanState) &&
+ (expr = GetSpecialCustomVar(dpns->planstate, var)) != NULL)
+ {
+ /*
+ * Force parentheses because our caller probably assumed a Var is a
+ * simple expression.
+ */
+ if (!IsA(expr, Var))
+ appendStringInfoChar(buf, '(');
+ get_rule_expr((Node *) expr, context, true);
+ if (!IsA(expr, Var))
+ appendStringInfoChar(buf, ')');
+
+ return NULL;
+ }
else if (var->varno == OUTER_VAR && dpns->outer_tlist)
{
TargetEntry *tle;
@@ -5633,6 +5669,26 @@ get_name_for_var_field(Var *var, int fieldno,
rte = rt_fetch(var->varno, dpns->rtable);
attnum = var->varattno;
}
+ else if (IS_SPECIAL_VARNO(var->varno) &&
+ IsA(dpns->planstate, CustomPlanState) &&
+ (expr = GetSpecialCustomVar(dpns->planstate, var)) != NULL)
+ {
+ StringInfo saved = context->buf;
+ StringInfoData temp;
+
+ initStringInfo(&temp);
+ context->buf = &temp;
+
+ if (!IsA(expr, Var))
+ appendStringInfoChar(context->buf, '(');
+ get_rule_expr((Node *) expr, context, true);
+ if (!IsA(expr, Var))
+ appendStringInfoChar(context->buf, ')');
+
+ context->buf = saved;
+
+ return temp.data;
+ }
else if (var->varno == OUTER_VAR && dpns->outer_tlist)
{
TargetEntry *tle;
diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h
index 3488be3..f914696 100644
--- a/src/include/commands/explain.h
+++ b/src/include/commands/explain.h
@@ -54,6 +54,7 @@ extern PGDLLIMPORT ExplainOneQuery_hook_type ExplainOneQuery_hook;
typedef const char *(*explain_get_index_name_hook_type) (Oid indexId);
extern PGDLLIMPORT explain_get_index_name_hook_type explain_get_index_name_hook;
+extern void ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used);
extern void ExplainQuery(ExplainStmt *stmt, const char *queryString,
ParamListInfo params, DestReceiver *dest);
diff --git a/src/include/executor/nodeCustom.h b/src/include/executor/nodeCustom.h
new file mode 100644
index 0000000..e6e049e
--- /dev/null
+++ b/src/include/executor/nodeCustom.h
@@ -0,0 +1,30 @@
+/* ------------------------------------------------------------------------
+ *
+ * nodeCustom.h
+ *
+ * prototypes for CustomScan nodes
+ *
+ * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * ------------------------------------------------------------------------
+ */
+#ifndef NODECUSTOM_H
+#define NODECUSTOM_H
+#include "nodes/plannodes.h"
+#include "nodes/execnodes.h"
+
+/*
+ * General executor code
+ */
+extern CustomPlanState *ExecInitCustomPlan(CustomPlan *custom_plan,
+ EState *estate, int eflags);
+extern TupleTableSlot *ExecCustomPlan(CustomPlanState *cpstate);
+extern Node *MultiExecCustomPlan(CustomPlanState *cpstate);
+extern void ExecEndCustomPlan(CustomPlanState *cpstate);
+
+extern void ExecReScanCustomPlan(CustomPlanState *cpstate);
+extern void ExecCustomMarkPos(CustomPlanState *cpstate);
+extern void ExecCustomRestrPos(CustomPlanState *cpstate);
+
+#endif /* NODECUSTOM_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index a301a08..8af5bf2 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1501,6 +1501,18 @@ typedef struct ForeignScanState
void *fdw_state; /* foreign-data wrapper can keep state here */
} ForeignScanState;
+/* ----------------
+ * CustomPlanState information
+ *
+ * CustomPlan nodes are used to execute custom code within executor.
+ * ----------------
+ */
+typedef struct CustomPlanState
+{
+ PlanState ps;
+ const CustomPlanMethods *methods;
+} CustomPlanState;
+
/* ----------------------------------------------------------------
* Join State Information
* ----------------------------------------------------------------
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 5b8df59..f4a1246 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -62,6 +62,8 @@ typedef enum NodeTag
T_CteScan,
T_WorkTableScan,
T_ForeignScan,
+ T_CustomPlan,
+ T_CustomPlanMarkPos,
T_Join,
T_NestLoop,
T_MergeJoin,
@@ -107,6 +109,7 @@ typedef enum NodeTag
T_CteScanState,
T_WorkTableScanState,
T_ForeignScanState,
+ T_CustomPlanState,
T_JoinState,
T_NestLoopState,
T_MergeJoinState,
@@ -224,6 +227,7 @@ typedef enum NodeTag
T_HashPath,
T_TidPath,
T_ForeignPath,
+ T_CustomPath,
T_AppendPath,
T_MergeAppendPath,
T_ResultPath,
@@ -513,6 +517,8 @@ extern void *stringToNode(char *str);
*/
extern void *copyObject(const void *obj);
+extern void CopyCustomPlanCommon(const Node *from, Node *newnode);
+
/*
* nodes/equalfuncs.c
*/
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 38c039c..7468d4c 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -15,8 +15,10 @@
#define PLANNODES_H
#include "access/sdir.h"
+#include "lib/stringinfo.h"
#include "nodes/bitmapset.h"
#include "nodes/primnodes.h"
+#include "nodes/relation.h"
/* ----------------------------------------------------------------
@@ -479,6 +481,81 @@ typedef struct ForeignScan
bool fsSystemCol; /* true if any "system column" is needed */
} ForeignScan;
+/* ----------------
+ * CustomPlan node
+ * ----------------
+ */
+struct CustomPlanMethods;
+
+typedef struct CustomPlan
+{
+ Plan plan;
+ const struct CustomPlanMethods *methods;
+} CustomPlan;
+
+/* almost same to CustomPlan, but support MarkPos/RestorePos */
+typedef CustomPlan CustomPlanMarkPos;
+
+/* not to include execnodes.h here */
+typedef struct CustomPlanState CustomPlanState;
+typedef struct EState EState;
+typedef struct ExplainState ExplainState;
+typedef struct TupleTableSlot TupleTableSlot;
+
+typedef void (*SetCustomPlanRef_function)(PlannerInfo *root,
+ CustomPlan *custom_plan,
+ int rtoffset);
+typedef bool (*SupportCustomBackwardScan_function)(CustomPlan *custom_plan);
+typedef void (*FinalizeCustomPlan_function)(PlannerInfo *root,
+ CustomPlan *custom_plan,
+ Bitmapset **paramids,
+ Bitmapset **valid_params,
+ Bitmapset **scan_params);
+typedef CustomPlanState *(*BeginCustomPlan_function)(CustomPlan *custom_plan,
+ EState *estate,
+ int eflags);
+typedef TupleTableSlot *(*ExecCustomPlan_function)(CustomPlanState *cpstate);
+typedef Node *(*MultiExecCustomPlan_function)(CustomPlanState *cpstate);
+typedef void (*EndCustomPlan_function)(CustomPlanState *cpstate);
+typedef void (*ReScanCustomPlan_function)(CustomPlanState *cpstate);
+typedef void (*MarkPosCustomPlan_function)(CustomPlanState *cpstate);
+typedef void (*RestrPosCustomPlan_function)(CustomPlanState *cpstate);
+typedef void (*ExplainCustomPlanTargetRel_function)(CustomPlanState *cpstate,
+ ExplainState *es);
+typedef void (*ExplainCustomPlan_function)(CustomPlanState *cpstate,
+ List *ancestors,
+ ExplainState *es);
+typedef Bitmapset *(*GetRelidsCustomPlan_function)(CustomPlanState *cpstate);
+typedef Node *(*GetSpecialCustomVar_function)(CustomPlanState *cpstate,
+ Var *varnode);
+typedef void (*TextOutCustomPlan_function)(StringInfo str,
+ const CustomPlan *node);
+typedef CustomPlan *(*CopyCustomPlan_function)(const CustomPlan *from);
+
+typedef struct CustomPlanMethods
+{
+ const char *CustomName;
+ /* callbacks for the planner stage */
+ SetCustomPlanRef_function SetCustomPlanRef;
+ SupportCustomBackwardScan_function SupportBackwardScan;
+ FinalizeCustomPlan_function FinalizeCustomPlan;
+ /* callbacks for the executor stage */
+ BeginCustomPlan_function BeginCustomPlan;
+ ExecCustomPlan_function ExecCustomPlan;
+ MultiExecCustomPlan_function MultiExecCustomPlan;
+ EndCustomPlan_function EndCustomPlan;
+ ReScanCustomPlan_function ReScanCustomPlan;
+ MarkPosCustomPlan_function MarkPosCustomPlan;
+ RestrPosCustomPlan_function RestrPosCustomPlan;
+ /* callbacks for EXPLAIN */
+ ExplainCustomPlanTargetRel_function ExplainCustomPlanTargetRel;
+ ExplainCustomPlan_function ExplainCustomPlan;
+ GetRelidsCustomPlan_function GetRelidsCustomPlan;
+ GetSpecialCustomVar_function GetSpecialCustomVar;
+ /* callbacks for general node management */
+ TextOutCustomPlan_function TextOutCustomPlan;
+ CopyCustomPlan_function CopyCustomPlan;
+} CustomPlanMethods;
/*
* ==========
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index c607b36..cbbf1e0 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -15,6 +15,7 @@
#define RELATION_H
#include "access/sdir.h"
+#include "lib/stringinfo.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h"
#include "storage/block.h"
@@ -878,6 +879,34 @@ typedef struct ForeignPath
} ForeignPath;
/*
+ * CustomPath represents a scan using custom logic
+ *
+ * custom_flags is a set of CUSTOM_* bits to control its behavior.
+ * custom_methods is a set of function pointers that are declared in
+ * CustomPathMethods structure; extension has to set up correctly.
+ */
+struct CustomPathMethods;
+
+typedef struct CustomPath
+{
+ Path path;
+ const struct CustomPathMethods *methods;
+} CustomPath;
+
+typedef struct CustomPlan CustomPlan;
+
+typedef CustomPlan *(*CreateCustomPlan_function)(PlannerInfo *root,
+ CustomPath *custom_path);
+typedef void (*TextOutCustomPath_function)(StringInfo str, Node *node);
+
+typedef struct CustomPathMethods
+{
+ const char *CustomName;
+ CreateCustomPlan_function CreateCustomPlan;
+ TextOutCustomPath_function TextOutCustomPath;
+} CustomPathMethods;
+
+/*
* AppendPath represents an Append plan, ie, successive execution of
* several member plans.
*
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 9b22fda..3047d3d 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -29,6 +29,23 @@ typedef RelOptInfo *(*join_search_hook_type) (PlannerInfo *root,
List *initial_rels);
extern PGDLLIMPORT join_search_hook_type join_search_hook;
+/* Hook for plugins to add custom scan path, in addition to default ones */
+typedef void (*add_scan_path_hook_type)(PlannerInfo *root,
+ RelOptInfo *baserel,
+ RangeTblEntry *rte);
+extern PGDLLIMPORT add_scan_path_hook_type add_scan_path_hook;
+
+/* Hook for plugins to add custom join path, in addition to default ones */
+typedef void (*add_join_path_hook_type)(PlannerInfo *root,
+ RelOptInfo *joinrel,
+ RelOptInfo *outerrel,
+ RelOptInfo *innerrel,
+ JoinType jointype,
+ SpecialJoinInfo *sjinfo,
+ List *restrictlist,
+ Relids param_source_rels,
+ Relids extra_lateral_rels);
+extern PGDLLIMPORT add_join_path_hook_type add_join_path_hook;
extern RelOptInfo *make_one_rel(PlannerInfo *root, List *joinlist);
extern RelOptInfo *standard_join_search(PlannerInfo *root, int levels_needed,
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index 8bdb7db..bc3ca63 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.h
@@ -41,6 +41,10 @@ extern Plan *optimize_minmax_aggregates(PlannerInfo *root, List *tlist,
* prototypes for plan/createplan.c
*/
extern Plan *create_plan(PlannerInfo *root, Path *best_path);
+extern Plan *create_plan_recurse(PlannerInfo *root, Path *best_path);
+extern List *build_path_tlist(PlannerInfo *root, Path *path);
+extern bool use_physical_tlist(PlannerInfo *root, RelOptInfo *rel);
+extern void disuse_physical_tlist(PlannerInfo *root, Plan *plan, Path *path);
extern SubqueryScan *make_subqueryscan(List *qptlist, List *qpqual,
Index scanrelid, Plan *subplan);
extern ForeignScan *make_foreignscan(List *qptlist, List *qpqual,
@@ -86,6 +90,11 @@ extern ModifyTable *make_modifytable(PlannerInfo *root,
List *withCheckOptionLists, List *returningLists,
List *rowMarks, int epqParam);
extern bool is_projection_capable_plan(Plan *plan);
+extern List *order_qual_clauses(PlannerInfo *root, List *clauses);
+extern List *get_switched_clauses(List *clauses, Relids outerrelids);
+extern void copy_path_costsize(Plan *dest, Path *src);
+extern void copy_plan_costsize(Plan *dest, Plan *src);
+extern Node *replace_nestloop_params(PlannerInfo *root, Node *expr);
/*
* prototypes for plan/initsplan.c
@@ -127,6 +136,8 @@ extern List *remove_useless_joins(PlannerInfo *root, List *joinlist);
* prototypes for plan/setrefs.c
*/
extern Plan *set_plan_references(PlannerInfo *root, Plan *plan);
+extern Plan *set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset);
+extern void fix_expr_common(PlannerInfo *root, Node *node);
extern void fix_opfuncids(Node *node);
extern void set_opfuncid(OpExpr *opexpr);
extern void set_sa_opfuncid(ScalarArrayOpExpr *opexpr);
diff --git a/src/include/optimizer/subselect.h b/src/include/optimizer/subselect.h
index 5607e98..138b60b 100644
--- a/src/include/optimizer/subselect.h
+++ b/src/include/optimizer/subselect.h
@@ -29,6 +29,13 @@ extern void SS_finalize_plan(PlannerInfo *root, Plan *plan,
bool attach_initplans);
extern Param *SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
Oid resulttype, int32 resulttypmod, Oid resultcollation);
+extern Bitmapset *finalize_plan(PlannerInfo *root,
+ Plan *plan,
+ Bitmapset *valid_params,
+ Bitmapset *scan_params);
+extern Bitmapset *finalize_primnode(PlannerInfo *root,
+ Node *node,
+ Bitmapset *paramids);
extern Param *assign_nestloop_param_var(PlannerInfo *root, Var *var);
extern Param *assign_nestloop_param_placeholdervar(PlannerInfo *root,
PlaceHolderVar *phv);