 doc/src/sgml/custom-plan.sgml           | 359 ++++++++++++++++++++++++++++++++
 doc/src/sgml/filelist.sgml              |   1 +
 doc/src/sgml/postgres.sgml              |   1 +
 src/backend/commands/explain.c          |  25 +++
 src/backend/executor/Makefile           |   2 +-
 src/backend/executor/execAmi.c          |  38 +++-
 src/backend/executor/execProcnode.c     |  14 ++
 src/backend/executor/nodeCustom.c       | 127 +++++++++++
 src/backend/nodes/copyfuncs.c           |  26 +++
 src/backend/nodes/outfuncs.c            |  15 ++
 src/backend/optimizer/path/costsize.c   |   2 +-
 src/backend/optimizer/plan/createplan.c |   3 +-
 src/backend/optimizer/plan/setrefs.c    |  26 ++-
 src/backend/optimizer/plan/subselect.c  |  21 ++
 src/backend/utils/adt/ruleutils.c       |  70 +++++++
 src/include/executor/executor.h         |   3 +-
 src/include/executor/nodeCustom.h       |  30 +++
 src/include/nodes/execnodes.h           |  40 ++++
 src/include/nodes/nodes.h               |   1 +
 src/include/nodes/plannodes.h           |  20 ++
 src/include/optimizer/planmain.h        |   3 +
 21 files changed, 817 insertions(+), 10 deletions(-)

diff --git a/doc/src/sgml/custom-plan.sgml b/doc/src/sgml/custom-plan.sgml
new file mode 100644
index 0000000..fc4b187
--- /dev/null
+++ b/doc/src/sgml/custom-plan.sgml
@@ -0,0 +1,359 @@
+<!-- doc/src/sgml/custom_plan.sgml -->
+
+<chapter id="custom-plan">
+ <title>Writing A Custom Plan Provider</title>
+ <indexterm zone="custom-plan">
+  <primary>custom plan provider</primary>
+  <secondary>handler for</secondary>
+ </indexterm>
+
+ <para>
+  PostgreSQL has various kind of built-in plan nodes that implement
+  a particular portion to process the supplied SQL queries.
+  For example, SeqScan node implements full table scan, HashJoin node
+  implements tables join using a hash table and so on.
+ </para>
+ <para>
+  The custom-plan interface allows extensions to provide alternative
+  query execution paths, in addition to the built-in ones. Query planner
+  will choose the cheapest path towards a particular relation(s) scan or
+  join in all the proposed ones by built-in and extensions.
+  Once a proposed custom plan got picked up, callback functions associated
+  with the node shall be called and extension will get control to process
+  the task. We call a set of callback functions associated with a certain
+  custom node the custom-path, custom-plan or custom-scan depending on
+  the things it provides; just "provider" in short.
+ </para>
+
+ <sect1 id="custom-plan-overall-steps">
+  <title>Custom Plan Overall Steps</title>
+  <para>
+   A custom-path provider shall be registered by
+   <literal>register_custom_path_provider</> that takes a pointer of
+   <literal>CustomPathMethods</> table which also holds some function
+   pointers.
+   It is usually installed on <literal>_PG_init()</> of extension
+   when either of preload configuration or <xref linkend="sql-load">
+   command loads the extension of the provider.
+  </para>
+  <para>
+   Onec a provider gets registered, the built-in query planner calls
+   back <literal>CreateCustomScanPath</> to ask whether the provider
+   can offer an alternative path to scan the referenced relation, or
+   not.
+   If it is available to provide, this callback will construct
+   <literal>CustomPath</> with cost estimation.
+   Then, query planner compares the alternative paths with built-in
+   paths based on the estimated cost, then the cheapest one shall be
+   chosen.
+  </para>
+  <para>
+   Usually, a provider may need some private fields to store something
+   valuable properties for the path. In this case, extension can extends
+   the <literal>CustomPath</> structure using a new data structure
+   definition that takes <literal>CustomPath</> on the head then followed
+   by private fields.
+<programlisting>
+typedef struct MySpecialPath
+{
+    CustomPath  cpath;
+    List       *some_list;
+    Bitmapset  *some_bitmap;
+       :
+} MySpecialPath;
+</programlisting>
+   The above example shows a structure delivered from <literal>CustomPath</>
+   with some private fields.
+   We assume such kind of manner, like as object oriented language doing,
+   to inject private fields of the provider on other nodes like
+   <literal>CustomScan</>.
+  </para>
+  <para>
+   Once a <literal>CustomPath</> got chosen, its callback shall be kicked
+   to populate <literal>CustomScan</> (or its inheritance) node; that is
+   the only available node type, right now. It consists of a part of query
+   plan tree, instead of the built-in nodes.
+   In the same manner, the <literal>CustomScan</> node populates
+   a <literal>CustomScanState</> (or its inheritance) node; that manages   
+   execution-time status of the custom-scan node and a set of callbacks.
+  </para>
+ </sect1>
+
+ <sect1 id="custom-path-callbacks">
+  <title>Custom Path Callbacks</title>
+  <para>
+   This section introduces callback functions of <structname>CustomPath</>
+   structure; defined in the <structname>CustomPathMethods</>, and
+   related flags.
+  </para>
+  <para>
+<programlisting>
+void
+CreateCustomScanPath(PlannerInfo *root,
+                     RelOptInfo *baserel,
+                     RangeTblEntry *rte);
+</programlisting>
+   As mentioned above, it construct <structname>CustomPath</> (or inherited
+   data type) node if it is available to provide an alternative scan path
+   on the supplied relation and qualifiers; that shall be informed using
+   <literal>RelOptInfo</> argument.
+   The constructed <structname>CustomPath</> node shall be added to
+   candidate path of the relation using <literal>add_path</>.
+  </para>
+  <para>
+<programlisting>
+Plan *
+PlanCustomPath(PlannerInfo *root,
+               RelOptInfo *rel,
+               CustomPath *best_path,
+               List *tlist,
+               List *clauses);
+</programlisting>
+   It populates a <struct>CustomScan</> or its inheritance node
+   according to the supplied <structname>CustomPath</> node which was
+   constructed on the custom path handler function then chosen by the
+   query planner.
+   This callback has to allocate a <struct>CustomScan</> node because
+   only provider can know exact size to be allocated if it is extended
+   to have private fields.
+   This callback is assumed to allocate the <struct>CustomScan</> node
+   with <structname>CustomPlanMethods</> callbacks table, then initialize
+   common plan-node fields and arbitrary private fields.
+  </para>
+
+  <para>
+<programlisting>
+void
+TextOutCustomPath(StringInfo str, const CustomPath *node);
+</programlisting>
+   It makes a text representation of custom path node. If provider extends
+   <structname>CustomPath</> data type, it shall to put private fields on
+   the supplied <literal>StringInfo</> with text form.
+   Note that common fields in <structname>CustomPath</> are handled by
+   backend, so extension needs to do nothing special.
+  </para>
+
+  <para>
+   <literal>CustomPath</> structure can have flags that informs capability
+   of this custom-path to the query planner. Every flags can be combined
+   with OR-operation, then set to <literal>flags</> field.
+   The value of <literal>flags</> should be unchanged across node
+   population, because the plan tree is constructed based on the properties
+   being preliminary configured.
+  </para>
+  <para>
+   <literal>CUSTOMPATH_SUPPORT_BACKWARD_SCAN</> informs the planner
+   this custom-path supports backward scan.
+   <literal>CUSTOMPATH_SUPPORT_MARK_RESTORE</> informs the planner
+   this custom-path supports mark and restore position.
+  </para>
+ </sect1>
+
+ <sect1 id="custom-scan-callbacks">
+  <title>Custom Scan Callbacks</title>
+  <para>
+   This section introduces callback functions of <structname>CustomScan</>
+   structure; defined in the <structname>CustomScanMethods</>.
+  </para>
+
+  <para>
+<programlisting>
+void
+SetCustomScanRef(PlannerInfo *root,
+                 CustomScan *cscan,
+                 int rtoffset);
+</programlisting>
+   It adjusts <literal>varno</> and <literal>varattno</> of var-nodes in
+   the expression tree chained from <structname>CustomScan</> node
+   (including private fields in the inherited data type).
+   In case of usual relation scan, <literal>rtoffset</> shall be added to
+   <literal>varno</> of var-nodes and <literal>scanrelid</> of plan node,
+   then <function>fix_scan_expr</> shall be called on expression nodes to
+   track plan dependency.
+  </para>
+
+  <para>
+<programlisting>
+void
+FinalizeCustomScan(PlannerInfo *root,
+                   CustomScan *cscan,
+                   bool (*finalize_primnode)(),
+                   void *finalize_context);
+</programlisting>
+   It is an optional callback, which applies <literal>finalize_primenode</>
+   on the expression nodes of private fields because only provider knows
+   what private fields are expression node to be finalized.
+   Note that backend applies <literal>finalize_primenode</> on
+   the <literal>tlist</> and <literal>qual</> of the base plan node,
+   so provider shall do nothing special, if it has no private expression
+   node. Also, it handles recursive stuff on the <literal>lefttree</> and
+   <literal>righttree</>, so it does not need to handle recursive walks.
+  </para>
+
+  <para>
+<programlisting>
+Node *
+CreateCustomScanState(CustomScan *cscan);
+</programlisting>
+   It populates a <structname>CustomScanState</> (or its inheritance)
+   node according to the supplied <structname>CustomScan</> node that was
+   preliminary constructed on the beginning of query executor.
+   Only provider can know exact size of the node to be allocated, this
+   callback allocate a <structname>CustomScanState</> node
+   with <structfield>CustomExecMethods</> callbacks table and arbitrary
+   private fields.
+  </para>
+  <para>
+   Note that main purpose of this callback is allocation of
+   <literal>CustomScanState</> node, not initialization of individual
+   fields because it shall be handled on the <structfield>BeginCustomPlan</>
+   callback to be invoked next to the common usual initialization.
+  </para>
+
+  <para>
+<programlisting>
+void
+TextOutCustomScan(StringInfo str,
+                  const CustomScan *node);
+</programlisting>
+   It makes a text representation of custom-scan node. If provider extends
+   <structfield>CustomScan</> data type, it shall put private fields on
+   the supplied <literal>StringInfo</> with text form.
+   Note that common fields within <structname>CustomPlan</> are handled
+   by the backend, so extension needs to do nothing special.
+  </para>
+
+  <para>
+<programlisting>
+CustomScan *
+CopyCustomScan(const CustomScan *from);
+</programlisting>
+   It duplicate every private fields of the inheritance of
+   <literal>CustomScan</> onto a newly allocated node.
+   In case when provider extends <literal>CustomScan</> node, only provider
+   can know exact size to be allocated and existence of the private fields.
+   So, it shall be responsible for node allocation and copy of private fields,
+   although the backend copies the fields of
+   <literal>CustomScan</>.
+  </para>
+ </sect1>
+
+ <sect1 id="custom-exec-callbacks">
+  <title>Custom Executor Callbacks</title>
+  <para>
+   This section introduces callback functions of <structname>CustomPlanState</>
+   structure; defined in the <structname>CustomExecMethods</>.
+  </para>
+  <para>
+<programlisting>
+void
+BeginCustomScan(CustomScanState *node,
+                EState *estate,
+                int eflags);
+</programlisting>
+   It begins execution of custom-scan. This callback is invoked during
+   executor startup to initialize the supplied <literal>CustomScanState</>
+   that was constructed on the <literal>CreateCustomScanState</> above.
+   The provider shall have initialization of its private fields and common
+   fields within <literal>CustomScanState</> if needed, because the backend
+   code already applies some fundamental initializations.
+  </para>
+
+  <para>
+<programlisting>
+TupleTableSlot *
+ExecCustomScan(CustomScanState *node);
+</programlisting>
+   It fetches one row from the custom-plan node, returning it in a tuple
+   table slot (<literal>ps_ResultTupleSlot</> of <literal>PlanState</>
+   shall be used) or <literal>NULL</> if no more rows are available.
+   The tuple table slot infrastructure allows either a physical or virtual
+   tuple to be returned; in most cases the latter choice is preferable from
+   a performance standpoint.
+   The rows being returned have to match the tuple-descriptor of the
+   <structname>PlanState</>
+  </para>
+  <para>
+   Note that this call is under a short-lived memory context that will be
+   reset for each invocation. So, it may be a good choice to switch
+   <literal>es_query_cxt</> of the <structname>EState</>, to acquire
+   memory in per-scan duration.
+  </para>
+
+  <para>
+<programlisting>
+void
+EndCustomScan(CustomScanState *node);
+</programlisting>
+   It ends the execution of custom-scan and release any resources held by
+   this node. If provider acquired resources that is not released
+   automatically at end of executor, it is responsibility of the provider.
+  </para>
+
+  <para>
+<programlisting>
+void
+ReScanCustomScan(CustomScanState *node);
+</programlisting>
+   It restarts the scan from the beginning.  Note that any parameters
+   the scan depends on may have changed value, so the new scan does not
+   necessarily return exactly the same rows.
+  </para>
+
+  <para>
+<programlisting>
+void *
+MarkPosCustomScan(CustomScanState *node);
+</programlisting>
+   It is an optional callback if <literal>CUSTOMPATH_SUPPORT_MARK_RESTORE</>
+   is set on the <literal>flags</>. Elsewhere, it should put <literal>NULL</>
+   on the callback table because never called.
+   It saves current scan position on somewhere in private fields of
+   <structname>CustomScanState</> (or its inheritance), to restore
+   the position later.
+  </para>
+
+  <para>
+<programlisting>
+void *
+RestrPosCustomScan(CustomScanState *node);
+</programlisting>
+   It is an optional callback if <literal>CUSTOMPATH_SUPPORT_MARK_RESTORE</>
+   is set on the <literal>flags</>. Elsewhere, it should put <literal>NULL</>
+   on the callback table because never called.
+   It restores the previous scan position saved by
+   the <structname>MarkPosCustomScan</> above.
+  </para>
+
+  <para>
+<programlisting>
+void
+ExplainCustomScan(CustomScanState *node,
+                  List *ancestors,
+                  ExplainState *es);
+</programlisting>
+   It is an optional callback, to show custom-scan specific explain output.
+  </para>
+
+  <para>
+<programlisting>
+Node   *
+GetSpecialCustomVar(CustomPlanState *node,
+                    Var *varnode,
+                    PlanState **child_ps);
+</programlisting>
+   It is an optional callback, to solve references to special varno on
+   the <literal>CustomScanState</> when <command>EXPLAIN</> needs the
+   text form of the column actually referenced.
+   In case when provider adjusted <literal>varno</> of varnodes on
+   the expression tree to use special varnos (<literal>INNER_VAR</>,
+   <literal>OUTER_VAR</> or <literal>INDEX_VAR</>), provider has
+   to inform the backend which column is mapped on the underlying plan-state.
+  </para>
+  <para>
+   This callback is expected to return <literal>Var</> node to reference
+   an actual variable on the underlying <structname>PlanState</> that shall
+   be set on the <literal>child_ps</> argument for recursive walking down.
+  </para>
+ </sect1>
+</chapter>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index 5902f97..8d20594 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -92,6 +92,7 @@
 <!ENTITY nls        SYSTEM "nls.sgml">
 <!ENTITY plhandler  SYSTEM "plhandler.sgml">
 <!ENTITY fdwhandler SYSTEM "fdwhandler.sgml">
+<!ENTITY custom-plan SYSTEM "custom-plan.sgml">
 <!ENTITY logicaldecoding SYSTEM "logicaldecoding.sgml">
 <!ENTITY protocol   SYSTEM "protocol.sgml">
 <!ENTITY sources    SYSTEM "sources.sgml">
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index 9bde108..5f415c6 100644
--- a/doc/src/sgml/postgres.sgml
+++ b/doc/src/sgml/postgres.sgml
@@ -242,6 +242,7 @@
   &nls;
   &plhandler;
   &fdwhandler;
+  &custom-plan;
   &geqo;
   &indexam;
   &gist;
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 3fcc1dd..99aa0f0 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -724,6 +724,7 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
 		case T_CteScan:
 		case T_WorkTableScan:
 		case T_ForeignScan:
+		case T_CustomScan:
 			*rels_used = bms_add_member(*rels_used,
 										((Scan *) plan)->scanrelid);
 			break;
@@ -853,6 +854,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;
 
@@ -941,6 +943,14 @@ ExplainNode(PlanState *planstate, List *ancestors,
 		case T_ForeignScan:
 			pname = sname = "Foreign Scan";
 			break;
+		case T_CustomScan:
+			sname = "Custom Scan";
+			custom_name = ((CustomScan *) plan)->methods->CustomName;
+			if (custom_name)
+				pname = psprintf("Custom Scan (%s)", custom_name);
+			else
+				pname = sname;
+			break;
 		case T_Material:
 			pname = sname = "Materialize";
 			break;
@@ -1042,6 +1052,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 Plan Provider", custom_name, es);
 	}
 
 	switch (nodeTag(plan))
@@ -1055,6 +1067,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
 		case T_CteScan:
 		case T_WorkTableScan:
 		case T_ForeignScan:
+		case T_CustomScan:
 			ExplainScanTarget((Scan *) plan, es);
 			break;
 		case T_IndexScan:
@@ -1358,6 +1371,18 @@ ExplainNode(PlanState *planstate, List *ancestors,
 										   planstate, es);
 			show_foreignscan_info((ForeignScanState *) planstate, es);
 			break;
+		case T_CustomScan:
+			{
+				CustomScanState *css = (CustomScanState *) planstate;
+
+				show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
+				if (plan->qual)
+					show_instrumentation_count("Rows Removed by Filter", 1,
+											   planstate, es);
+				if (css->methods->ExplainCustomScan)
+					css->methods->ExplainCustomScan(css, 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..af707b0 100644
--- a/src/backend/executor/Makefile
+++ b/src/backend/executor/Makefile
@@ -16,7 +16,7 @@ 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 \
-       nodeBitmapHeapscan.o nodeBitmapIndexscan.o nodeHash.o \
+       nodeBitmapHeapscan.o nodeBitmapIndexscan.o nodeCustom.o nodeHash.o \
        nodeHashjoin.o nodeIndexscan.o nodeIndexonlyscan.o \
        nodeLimit.o nodeLockRows.o \
        nodeMaterial.o nodeMergeAppend.o nodeMergejoin.o nodeModifyTable.o \
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index 640964c..b14e08c 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"
@@ -49,6 +50,7 @@
 #include "executor/nodeWindowAgg.h"
 #include "executor/nodeWorktablescan.h"
 #include "nodes/nodeFuncs.h"
+#include "nodes/relation.h"
 #include "utils/rel.h"
 #include "utils/syscache.h"
 
@@ -197,6 +199,10 @@ ExecReScan(PlanState *node)
 			ExecReScanForeignScan((ForeignScanState *) node);
 			break;
 
+		case T_CustomScanState:
+			ExecReScanCustomScan((CustomScanState *) node);
+			break;
+
 		case T_NestLoopState:
 			ExecReScanNestLoop((NestLoopState *) node);
 			break;
@@ -291,6 +297,10 @@ ExecMarkPos(PlanState *node)
 			ExecValuesMarkPos((ValuesScanState *) node);
 			break;
 
+		case T_CustomScanState:
+			ExecCustomMarkPos((CustomScanState *) node);
+			break;
+
 		case T_MaterialState:
 			ExecMaterialMarkPos((MaterialState *) node);
 			break;
@@ -348,6 +358,10 @@ ExecRestrPos(PlanState *node)
 			ExecValuesRestrPos((ValuesScanState *) node);
 			break;
 
+		case T_CustomScanState:
+			ExecCustomRestrPos((CustomScanState *) node);
+			break;
+
 		case T_MaterialState:
 			ExecMaterialRestrPos((MaterialState *) node);
 			break;
@@ -379,9 +393,9 @@ ExecRestrPos(PlanState *node)
  * and valuesscan support is actually useless code at present.)
  */
 bool
-ExecSupportsMarkRestore(NodeTag plantype)
+ExecSupportsMarkRestore(Path *pathnode)
 {
-	switch (plantype)
+	switch (pathnode->pathtype)
 	{
 		case T_SeqScan:
 		case T_IndexScan:
@@ -403,6 +417,16 @@ ExecSupportsMarkRestore(NodeTag plantype)
 			 */
 			return false;
 
+		case T_CustomScan:
+			{
+				CustomPath *cpath = (CustomPath *) pathnode;
+
+				Assert(IsA(cpath, CustomPath));
+				if (cpath->flags & CUSTOMPATH_SUPPORT_MARK_RESTORE)
+					return true;
+			}
+			break;
+
 		default:
 			break;
 	}
@@ -465,6 +489,16 @@ ExecSupportsBackwardScan(Plan *node)
 			return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan) &&
 				TargetListSupportsBackwardScan(node->targetlist);
 
+		case T_CustomScan:
+			{
+				uint32	flags = ((CustomScan *) node)->flags;
+
+				if (TargetListSupportsBackwardScan(node->targetlist) &&
+					(flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN) != 0)
+					return true;
+			}
+			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 c0189eb..e27c062 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,11 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
 													   estate, eflags);
 			break;
 
+		case T_CustomScan:
+			result = (PlanState *) ExecInitCustomScan((CustomScan *) node,
+													  estate, eflags);
+			break;
+
 			/*
 			 * join nodes
 			 */
@@ -442,6 +448,10 @@ ExecProcNode(PlanState *node)
 			result = ExecForeignScan((ForeignScanState *) node);
 			break;
 
+		case T_CustomScanState:
+			result = ExecCustomScan((CustomScanState *) node);
+			break;
+
 			/*
 			 * join nodes
 			 */
@@ -678,6 +688,10 @@ ExecEndNode(PlanState *node)
 			ExecEndForeignScan((ForeignScanState *) node);
 			break;
 
+		case T_CustomScanState:
+			ExecEndCustomScan((CustomScanState *) node);
+			break;
+
 			/*
 			 * join nodes
 			 */
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
new file mode 100644
index 0000000..a8155d7
--- /dev/null
+++ b/src/backend/executor/nodeCustom.c
@@ -0,0 +1,127 @@
+/* ------------------------------------------------------------------------
+ *
+ * nodeCustom.c
+ *		Routines to handle execution of custom scan node
+ *
+ * Portions Copyright (c) 1996-2014, 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"
+
+CustomScanState *
+ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
+{
+	CustomScanState    *css;
+	Relation			scan_rel;
+
+	/* populate a CustomScanState according to the CustomScan */
+	css = (CustomScanState *)cscan->methods->CreateCustomScanState(cscan);
+	Assert(IsA(css, CustomScanState));
+
+	/* fill up fields of ScanState */
+	css->ss.ps.plan = &cscan->scan.plan;
+	css->ss.ps.state = estate;
+
+	/* create expression context for node */
+	ExecAssignExprContext(estate, &css->ss.ps);
+	css->ss.ps.ps_TupFromTlist = false;
+
+	/* initialize child expressions */
+	css->ss.ps.targetlist = (List *)
+		ExecInitExpr((Expr *) cscan->scan.plan.targetlist,
+					 (PlanState *) css);
+	css->ss.ps.qual = (List *)
+		ExecInitExpr((Expr *) cscan->scan.plan.qual,
+					 (PlanState *) css);
+
+	/* initialization of result tuple slot  */
+	ExecInitResultTupleSlot(estate, &css->ss.ps);
+	ExecAssignResultTypeFromTL(&css->ss.ps);
+
+	/*
+	 * Also, initialization of relation scan stuff if custom-scan
+	 * node intends to run on a particular plain relation.
+	 * Elsewhere, custom-scan provider should be responsible to put
+	 * proper initialization of scan tuple-slot and projection info
+	 * by itself.
+	 */
+	scan_rel = ExecOpenScanRelation(estate, cscan->scan.scanrelid, eflags);
+	css->ss.ss_currentRelation = scan_rel;
+	css->ss.ss_currentScanDesc = NULL;	/* set by provider on demand */
+	ExecInitScanTupleSlot(estate, &css->ss);
+	ExecAssignScanType(&css->ss, RelationGetDescr(scan_rel));
+	ExecAssignScanProjectionInfo(&css->ss);
+
+	/*
+	 * The callback of custom-scan provider applies the final initialization
+	 * of the custom-scan-state node according to its logic.
+	 */
+	css->methods->BeginCustomScan(css, estate, eflags);
+
+	return css;
+}
+
+TupleTableSlot *
+ExecCustomScan(CustomScanState *node)
+{
+	Assert(node->methods->ExecCustomScan != NULL);
+	return node->methods->ExecCustomScan(node);
+}
+
+void
+ExecEndCustomScan(CustomScanState *node)
+{
+	Assert(node->methods->EndCustomScan != NULL);
+	node->methods->EndCustomScan(node);
+
+	/* Free the exprcontext */
+	ExecFreeExprContext(&node->ss.ps);
+
+	/* Clean out the tuple table */
+	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+	if (node->ss.ss_ScanTupleSlot)
+		ExecClearTuple(node->ss.ss_ScanTupleSlot);
+
+	/* Close the heap relation */
+	ExecCloseScanRelation(node->ss.ss_currentRelation);
+}
+
+void
+ExecReScanCustomScan(CustomScanState *node)
+{
+	Assert(node->methods->ReScanCustomScan != NULL);
+	node->methods->ReScanCustomScan(node);
+}
+
+void
+ExecCustomMarkPos(CustomScanState *node)
+{
+	if (!node->methods->MarkPosCustomScan)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("custom-scan \"%s\" does not support MarkPos",
+						node->methods->CustomName)));
+	node->methods->MarkPosCustomScan(node);
+}
+
+void
+ExecCustomRestrPos(CustomScanState *node)
+{
+	if (!node->methods->RestrPosCustomScan)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("custom-scan \"%s\" does not support MarkPos",
+						node->methods->CustomName)));
+	node->methods->RestrPosCustomScan(node);
+}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 21b070a..3e03cd8 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -598,6 +598,29 @@ _copyForeignScan(const ForeignScan *from)
 }
 
 /*
+ * _copyCustomScan
+ */
+static CustomScan *
+_copyCustomScan(const CustomScan *from)
+{
+	CustomScan		   *newnode;
+
+	newnode = from->methods->CopyCustomScan(from);
+	Assert(nodeTag(newnode) == nodeTag(from));
+
+	CopyScanFields((const Scan *) from, (Scan *) newnode);
+	COPY_SCALAR_FIELD(flags);
+	/*
+	 * NOTE: The method field of CustomScan is required to be a pointer
+	 * to a static table of callback functions. So, we don't copy the
+	 * table itself, just reference the original one.
+	 */
+	COPY_SCALAR_FIELD(methods);
+
+	return newnode;
+}
+
+/*
  * CopyJoinFields
  *
  *		This function copies the fields of the Join node.  It is used by
@@ -4042,6 +4065,9 @@ copyObject(const void *from)
 		case T_ForeignScan:
 			retval = _copyForeignScan(from);
 			break;
+		case T_CustomScan:
+			retval = _copyCustomScan(from);
+			break;
 		case T_Join:
 			retval = _copyJoin(from);
 			break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index d6da32c..cdf1e7e 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -564,6 +564,18 @@ _outForeignScan(StringInfo str, const ForeignScan *node)
 }
 
 static void
+_outCustomScan(StringInfo str, const CustomScan *node)
+{
+	WRITE_NODE_TYPE("CUSTOMSCAN");
+
+	_outScanInfo(str, (const Scan *) node);
+	WRITE_UINT_FIELD(flags);
+	appendStringInfo(str, " :methods");
+	_outToken(str, node->methods->CustomName);
+	node->methods->TextOutCustomScan(str, node);
+}
+
+static void
 _outJoin(StringInfo str, const Join *node)
 {
 	WRITE_NODE_TYPE("JOIN");
@@ -2866,6 +2878,9 @@ _outNode(StringInfo str, const void *obj)
 			case T_ForeignScan:
 				_outForeignScan(str, obj);
 				break;
+			case T_CustomScan:
+				_outCustomScan(str, obj);
+				break;
 			case T_Join:
 				_outJoin(str, obj);
 				break;
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 0cdb790..659daa2 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -2266,7 +2266,7 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path,
 	 * it off does not entitle us to deliver an invalid plan.
 	 */
 	else if (innersortkeys == NIL &&
-			 !ExecSupportsMarkRestore(inner_path->pathtype))
+			 !ExecSupportsMarkRestore(inner_path))
 		path->materialize_inner = true;
 
 	/*
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 189f7ef..23a26d2 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -86,7 +86,6 @@ 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);
@@ -2613,7 +2612,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 */
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 9ddc8ad..5589de8 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -94,7 +94,6 @@ static Plan *set_subqueryscan_references(PlannerInfo *root,
 							SubqueryScan *plan,
 							int rtoffset);
 static bool trivial_subqueryscan(SubqueryScan *plan);
-static Node *fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset);
 static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
 static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context);
 static void set_join_references(PlannerInfo *root, Join *join, int rtoffset);
@@ -579,6 +578,27 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 			}
 			break;
 
+		case T_CustomScan:
+			{
+				CustomScan *cscan = (CustomScan *) plan;
+
+				cscan->scan.scanrelid += rtoffset;
+				cscan->scan.plan.targetlist =
+					fix_scan_list(root, cscan->scan.plan.targetlist, rtoffset);
+				cscan->scan.plan.qual =
+					fix_scan_list(root, cscan->scan.plan.qual, rtoffset);
+				/*
+				 * The core implementation applies the routine to fixup
+				 * varno on the target-list and scan qualifier.
+				 * If custom-scan has additional expression nodes on its
+				 * private fields, it has to apply same fixup on them.
+				 * Elsewhere, custom-plan provider skip this callback.
+				 */
+				if (cscan->methods->SetCustomScanRef)
+					cscan->methods->SetCustomScanRef(root, cscan, rtoffset);
+			}
+			break;
+
 		case T_NestLoop:
 		case T_MergeJoin:
 		case T_HashJoin:
@@ -1063,7 +1083,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 */
@@ -1161,7 +1181,7 @@ fix_param_node(PlannerInfo *root, Param *p)
  * looking up operator opcode info for OpExpr and related nodes,
  * and adding OIDs from regclass Const nodes into root->glob->relationOids.
  */
-static Node *
+Node *
 fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset)
 {
 	fix_scan_expr_context context;
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 3e7dc85..4200ec0 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -2283,6 +2283,27 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
 			context.paramids = bms_add_members(context.paramids, scan_params);
 			break;
 
+		case T_CustomScan:
+			{
+				CustomScan *custom_scan = (CustomScan *) plan;
+
+				context.paramids = bms_add_members(context.paramids,
+												   scan_params);
+				/*
+				 * custom-scan provider is responsible to apply
+				 * finalize_primnode() on the expression node of
+				 * its private fields, but no need to apply it
+				 * on the tlist and qual of Plan node because it
+				 * is already done above.
+				 */
+				if (custom_scan->methods->FinalizeCustomScan)
+					custom_scan->methods->FinalizeCustomScan(root,
+															 custom_scan,
+															 finalize_primnode,
+															 (void *)&context);
+			}
+			break;
+
 		case T_ModifyTable:
 			{
 				ModifyTable *mtplan = (ModifyTable *) plan;
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 24ade6c..5aa334c 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -5493,6 +5493,26 @@ get_utility_query_def(Query *query, deparse_context *context)
 	}
 }
 
+/*
+ * GetSpecialCustomVar
+ *
+ * It provides a way to solve a special varnode being managed by custom-
+ * scan provider. The callback informs the backend an expression tree
+ * which was replaced by a special varnode.
+ */
+static Node *
+GetSpecialCustomVar(CustomScanState *css, Var *varnode, PlanState **child_ps)
+{
+	Assert(IsA(css, CustomScanState));
+	Assert(IS_SPECIAL_VARNO(varnode->varno));
+
+	if (!css->methods->GetSpecialCustomVar)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("%s does not support special varno reference",
+						css->methods->CustomName)));
+	return (Node *)css->methods->GetSpecialCustomVar(css, varnode, child_ps);
+}
 
 /*
  * Display a Var appropriately.
@@ -5522,6 +5542,8 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
 	int			netlevelsup;
 	deparse_namespace *dpns;
 	deparse_columns *colinfo;
+	PlanState  *child_ps = NULL;
+	Node	   *expr;
 	char	   *refname;
 	char	   *attname;
 
@@ -5546,6 +5568,29 @@ 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, CustomScanState) &&
+			 (expr = GetSpecialCustomVar((CustomScanState *) dpns->planstate,
+										 var, &child_ps)) != NULL)
+	{
+		deparse_namespace	save_dpns;
+
+		if (child_ps)
+			push_child_plan(dpns, child_ps, &save_dpns);
+		/*
+		 * 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, ')');
+
+		if (child_ps)
+			pop_child_plan(dpns, &save_dpns);
+		return NULL;
+	}
 	else if (var->varno == OUTER_VAR && dpns->outer_tlist)
 	{
 		TargetEntry *tle;
@@ -5760,6 +5805,7 @@ get_name_for_var_field(Var *var, int fieldno,
 	AttrNumber	attnum;
 	int			netlevelsup;
 	deparse_namespace *dpns;
+	PlanState  *child_ps = NULL;
 	TupleDesc	tupleDesc;
 	Node	   *expr;
 
@@ -5834,6 +5880,30 @@ 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, CustomScanState) &&
+			 (expr = GetSpecialCustomVar((CustomScanState *) dpns->planstate,
+										 var, &child_ps)) != NULL)
+	{
+		StringInfo		saved = context->buf;
+		StringInfoData	temp;
+		deparse_namespace save_dpns;
+
+		initStringInfo(&temp);
+		context->buf = &temp;
+
+		if (child_ps)
+			push_child_plan(dpns, child_ps, &save_dpns);
+		if (!IsA(expr, Var))
+			appendStringInfoChar(context->buf, '(');
+		get_rule_expr((Node *) expr, context, true);
+		if (!IsA(expr, Var))
+			appendStringInfoChar(context->buf, ')');
+		if (child_ps)
+			pop_child_plan(dpns, &save_dpns);
+		context->buf = saved;
+		return temp.data;
+	}
 	else if (var->varno == OUTER_VAR && dpns->outer_tlist)
 	{
 		TargetEntry *tle;
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index d167b49..a44b4cd 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -16,6 +16,7 @@
 
 #include "executor/execdesc.h"
 #include "nodes/parsenodes.h"
+#include "nodes/relation.h"
 #include "utils/lockwaitpolicy.h"
 
 
@@ -103,7 +104,7 @@ extern PGDLLIMPORT ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook;
 extern void ExecReScan(PlanState *node);
 extern void ExecMarkPos(PlanState *node);
 extern void ExecRestrPos(PlanState *node);
-extern bool ExecSupportsMarkRestore(NodeTag plantype);
+extern bool ExecSupportsMarkRestore(Path *pathnode);
 extern bool ExecSupportsBackwardScan(Plan *node);
 extern bool ExecMaterializesOutput(NodeTag plantype);
 
diff --git a/src/include/executor/nodeCustom.h b/src/include/executor/nodeCustom.h
new file mode 100644
index 0000000..1736d48
--- /dev/null
+++ b/src/include/executor/nodeCustom.h
@@ -0,0 +1,30 @@
+/* ------------------------------------------------------------------------
+ *
+ * nodeCustom.h
+ *
+ * prototypes for CustomScan nodes
+ *
+ * Portions Copyright (c) 1996-2014, 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 CustomScanState *ExecInitCustomScan(CustomScan *custom_scan,
+										   EState *estate, int eflags);
+extern TupleTableSlot *ExecCustomScan(CustomScanState *node);
+extern Node *MultiExecCustomScan(CustomScanState *node);
+extern void ExecEndCustomScan(CustomScanState *node);
+
+extern void ExecReScanCustomScan(CustomScanState *node);
+extern void ExecCustomMarkPos(CustomScanState *node);
+extern void ExecCustomRestrPos(CustomScanState *node);
+
+#endif	/* NODECUSTOM_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 39d2c10..b72e605 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -19,6 +19,7 @@
 #include "executor/instrument.h"
 #include "nodes/params.h"
 #include "nodes/plannodes.h"
+#include "nodes/relation.h"
 #include "utils/reltrigger.h"
 #include "utils/sortsupport.h"
 #include "utils/tuplestore.h"
@@ -1504,6 +1505,45 @@ typedef struct ForeignScanState
 	void	   *fdw_state;		/* foreign-data wrapper can keep state here */
 } ForeignScanState;
 
+/* ----------------
+ * CustomScanState information
+ *
+ *		CustomScan nodes are used to execute custom code within executor.
+ * ----------------
+ */
+struct CustomExecMethods;
+struct ExplainState;	/* to avoid to include explain.h here */
+
+typedef struct CustomScanState
+{
+	ScanState	ss;
+	uint32		flags;	/* mask of CUSTOMPATH_* flags defined in relation.h*/
+	const struct CustomExecMethods *methods;
+} CustomScanState;
+
+typedef struct CustomExecMethods
+{
+	const char     *CustomName;
+
+	/* EXECUTOR methods */
+	void    (*BeginCustomScan)(CustomScanState *node,
+							   EState *estate,
+							   int eflags);
+	TupleTableSlot *(*ExecCustomScan)(CustomScanState *node);
+	void	(*EndCustomScan)(CustomScanState *node);
+	void	(*ReScanCustomScan)(CustomScanState *node);
+	void	(*MarkPosCustomScan)(CustomScanState *node);
+	void	(*RestrPosCustomScan)(CustomScanState *node);
+
+	/* EXPLAIN support */
+	void    (*ExplainCustomScan)(CustomScanState *node,
+								 List *ancestors,
+								 struct ExplainState *es);
+	Node   *(*GetSpecialCustomVar)(CustomScanState *node,
+								   Var *varnode,
+								   PlanState **child_ps);
+} CustomExecMethods;
+
 /* ----------------------------------------------------------------
  *				 Join State Information
  * ----------------------------------------------------------------
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 6584a2c..bc71fea 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -108,6 +108,7 @@ typedef enum NodeTag
 	T_CteScanState,
 	T_WorkTableScanState,
 	T_ForeignScanState,
+	T_CustomScanState,
 	T_JoinState,
 	T_NestLoopState,
 	T_MergeJoinState,
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index db02323..9dbb91c 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"
 #include "utils/lockwaitpolicy.h"
 
 
@@ -487,12 +489,30 @@ typedef struct ForeignScan
  *     CustomScan node
  * ----------------
  */
+struct CustomScanMethods;
+
 typedef struct CustomScan
 {
 	Scan		scan;
 	uint32		flags;	/* mask of CUSTOMPATH_* flags defined in relation.h */
+	struct CustomScanMethods *methods;
 } CustomScan;
 
+typedef struct CustomScanMethods
+{
+	const char *CustomName;
+	void	   (*SetCustomScanRef)(struct PlannerInfo *root,
+								   CustomScan *cscan,
+								   int rtoffset);
+	void	   (*FinalizeCustomScan)(struct PlannerInfo *root,
+									 CustomScan *cscan,
+									 bool (*finalize_primnode)(),
+									 void *finalize_context);
+	Node	  *(*CreateCustomScanState)(CustomScan *cscan);
+	void	   (*TextOutCustomScan)(StringInfo str, const CustomScan *node);
+	CustomScan *(*CopyCustomScan)(const CustomScan *from);
+} CustomScanMethods;
+
 /*
  * ==========
  * Join nodes
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index 3fdc2cb..c97c577 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.h
@@ -86,6 +86,7 @@ extern ModifyTable *make_modifytable(PlannerInfo *root,
 				 List *withCheckOptionLists, List *returningLists,
 				 List *rowMarks, int epqParam);
 extern bool is_projection_capable_plan(Plan *plan);
+extern Node *replace_nestloop_params(PlannerInfo *root, Node *expr);
 
 /*
  * prototypes for plan/initsplan.c
@@ -130,6 +131,8 @@ extern bool query_is_distinct_for(Query *query, List *colnos, List *opids);
  */
 extern Plan *set_plan_references(PlannerInfo *root, Plan *plan);
 extern void fix_opfuncids(Node *node);
+extern Node *fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset);
+extern void fix_expr_common(PlannerInfo *root, Node *node);
 extern void set_opfuncid(OpExpr *opexpr);
 extern void set_sa_opfuncid(ScalarArrayOpExpr *opexpr);
 extern void record_plan_function_dependency(PlannerInfo *root, Oid funcid);
