 src/backend/nodes/outfuncs.c            |  14 +++++
 src/backend/optimizer/path/allpaths.c   |   3 +
 src/backend/optimizer/plan/createplan.c | 100 ++++++++++++++++++++++++++++++++
 src/backend/optimizer/util/pathnode.c   |  50 ++++++++++++++++
 src/include/nodes/nodes.h               |   2 +
 src/include/nodes/plannodes.h           |   9 +++
 src/include/nodes/relation.h            |  37 ++++++++++++
 src/include/optimizer/pathnode.h        |   9 +++
 8 files changed, 224 insertions(+)

diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index e686a6c..29a12bd 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1582,6 +1582,17 @@ _outForeignPath(StringInfo str, const ForeignPath *node)
 }
 
 static void
+_outCustomPath(StringInfo str, const CustomPath *node)
+{
+	WRITE_NODE_TYPE("CUSTOMPATH");
+	_outPathInfo(str, (const Path *) node);
+	WRITE_UINT_FIELD(flags);
+	appendStringInfo(str, " :methods");
+	_outToken(str, node->methods->CustomName);
+	node->methods->TextOutCustomPath(str, node);
+}
+
+static void
 _outAppendPath(StringInfo str, const AppendPath *node)
 {
 	WRITE_NODE_TYPE("APPENDPATH");
@@ -3059,6 +3070,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 c81efe9..8b42e36 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -402,6 +402,9 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
 	/* Consider TID scans */
 	create_tidscan_paths(root, rel);
 
+	/* Consider custom scans, if any */
+	create_customscan_paths(root, rel, rte);
+
 	/* Now find the cheapest of the paths for this rel */
 	set_cheapest(rel);
 }
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 4b641a2..8f73674 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -77,6 +77,7 @@ 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 Plan *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,
@@ -261,6 +262,9 @@ create_plan_recurse(PlannerInfo *root, Path *best_path)
 			plan = create_unique_plan(root,
 									  (UniquePath *) best_path);
 			break;
+		case T_CustomScan:
+			plan = create_custom_plan(root, (CustomPath *) best_path);
+			break;
 		default:
 			elog(ERROR, "unrecognized node type: %d",
 				 (int) best_path->pathtype);
@@ -1072,6 +1076,102 @@ 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 'clauses' and targetlist 'tlist'.
+ */
+static Plan *
+create_custom_plan(PlannerInfo *root, CustomPath *best_path)
+{
+	Plan		   *custom_plan;
+	RelOptInfo	   *rel = best_path->path.parent;
+	List		   *tlist;
+	List		   *clauses;
+
+	/* CustomPath node is assumed to populate CustomScan node */
+	Assert(best_path->path.pathtype == T_CustomScan);
+
+	/*
+	 * Right now, all we can support is CustomScan node which is associated
+	 * with a particular base relation.
+	 */
+	Assert(rel && rel->reloptkind == RELOPT_BASEREL);
+
+	/*
+	 * We prefer to generate a tlist containing all the var-nodes
+	 * in order, for cheaper projection cost, if available.
+	 * use_physical_tlist() makes a centralized decision, then
+	 * build up a tlist from the physical structure of the target
+	 * relation.
+	 */
+	if (use_physical_tlist(root, rel))
+		tlist = build_physical_tlist(root, rel);
+	else
+		tlist = build_path_tlist(root, &best_path->path);
+
+	/*
+	 * Extract the relevant restriction clauses from the parent relation.
+	 * The executor must apply all these restrictions during the scan,
+	 * except for pseudoconstants which we'll take care of below.
+	 */
+	clauses = rel->baserestrictinfo;	
+
+	/*
+     * If this is a parameterized scan, we also need to enforce all
+	 * the join clauses available from the outer relation(s).
+	 */
+	if (best_path->path.param_info)
+		clauses = list_concat(list_copy(clauses),
+							  best_path->path.param_info->ppi_clauses);
+
+	/*
+	 * Sort clauses into the best execution order, although custom-scan
+	 * provider can reorder them again.
+	 */
+	clauses = order_qual_clauses(root, clauses);
+
+	/*
+	 * Replace outer-relation variables with nestloop params.
+	 * Note that any other clauses which is managed by extension
+	 * itself has to be handled in InitCustomPlan() method, as
+	 * built-in code doing.
+	 */
+	if (best_path->path.param_info)
+		clauses = (List *)replace_nestloop_params(root, (Node *)clauses);
+
+	/*
+	 * Create a CustomScan (or its inheritance) node according to
+	 * the supplied CustomPath.
+	 */
+	custom_plan = best_path->methods->PlanCustomPath(root,
+													 rel,
+													 best_path,
+													 tlist,
+													 clauses);
+
+	/* additional sanity checks */
+	Assert(nodeTag(custom_plan) == best_path->path.pathtype);
+
+	if (IsA(custom_plan, CustomScan))
+	{
+		Index	scanrelid = ((CustomScan *)custom_plan)->scan.scanrelid;
+
+		if (scanrelid != rel->relid)
+			elog(ERROR, "Bug? CustomScan tried to scan incorrect relation");
+	}
+	else
+		elog(ERROR, "unexpected node: %d", (int)nodeTag(custom_plan));
+
+	/*
+	 * Copy cost data from Path to Plan; no need to make custom-plan
+	 * providers do this
+	 */
+	copy_path_costsize(custom_plan, &best_path->path);
+
+	return custom_plan;
+}
 
 /*****************************************************************************
  *
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 319e8b2..2ca0a18 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -27,6 +27,7 @@
 #include "optimizer/var.h"
 #include "parser/parsetree.h"
 #include "utils/lsyscache.h"
+#include "utils/memutils.h"
 #include "utils/selfuncs.h"
 
 
@@ -1926,3 +1927,52 @@ reparameterize_path(PlannerInfo *root, Path *path,
 	}
 	return NULL;
 }
+
+/*****************************************************************************
+ *     creation of custom-plan paths
+ *****************************************************************************/
+
+static List	   *custom_path_providers = NIL;
+
+/*
+ * register_custom_path_provider
+ *
+ * It registers a table of callback functions that implements a custom-path
+ * provider. The callback functions are expected to construct CustomPath node
+ * that provides an alternative logic to scan a relation (and so on in the
+ * future version), if extension can do.
+ * Note that the supplied CustomPathMethods is expected to locate on static
+ * memory area, so we don't copy individual fields here.
+ */
+void
+register_custom_path_provider(CustomPathMethods *cpp_methods)
+{
+	MemoryContext	oldcxt;
+
+	oldcxt = MemoryContextSwitchTo(TopMemoryContext);
+	custom_path_providers = lappend(custom_path_providers, cpp_methods);
+	MemoryContextSwitchTo(oldcxt);
+}
+
+/*
+ * create_customscan_paths
+ *
+ * It calls back extension's entrypoint whether it can add alternative
+ * scan paths being extended from the CustomPath type.
+ * If any, the callback will add one or more paths using add_path().
+ */
+void
+create_customscan_paths(PlannerInfo *root,
+						RelOptInfo *baserel,
+						RangeTblEntry *rte)
+{
+	ListCell	   *cell;
+
+	foreach (cell, custom_path_providers)
+	{
+		const CustomPathMethods *cpp_methods = lfirst(cell);
+
+		if (cpp_methods->CreateCustomScanPath)
+			cpp_methods->CreateCustomScanPath(root, baserel, rte);
+	}
+}
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index a031b88..6376784 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -62,6 +62,7 @@ typedef enum NodeTag
 	T_CteScan,
 	T_WorkTableScan,
 	T_ForeignScan,
+	T_CustomScan,
 	T_Join,
 	T_NestLoop,
 	T_MergeJoin,
@@ -224,6 +225,7 @@ typedef enum NodeTag
 	T_HashPath,
 	T_TidPath,
 	T_ForeignPath,
+	T_CustomPath,
 	T_AppendPath,
 	T_MergeAppendPath,
 	T_ResultPath,
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 3b9c683..c62d219 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -479,6 +479,15 @@ typedef struct ForeignScan
 	bool		fsSystemCol;	/* true if any "system column" is needed */
 } ForeignScan;
 
+/* ----------------
+ *     CustomScan node
+ * ----------------
+ */
+typedef struct CustomScan
+{
+	Scan		scan;
+	uint32		flags;	/* mask of CUSTOMPATH_* flags defined in relation.h */
+} CustomScan;
 
 /*
  * ==========
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index dacbe9c..e03c4d0 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"
@@ -881,6 +882,42 @@ typedef struct ForeignPath
 } ForeignPath;
 
 /*
+ * CustomPath represents a scan using custom logic
+ *
+ * Extension (that performs as custom-plan provider) can adds an alternative
+ * path using its custom type being delivered from CustomPath.
+ * They can store their private data on the extra fields of their custom
+ * object. A set of common methods are represented as function pointers in
+ * CustomPathMethods structure; extension has to set up then correctly.
+ */
+struct CustomPathMethods;
+struct Plan;		/* not to include plannodes.h here */
+
+#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN	0x0001
+#define CUSTOMPATH_SUPPORT_MARK_RESTORE		0x0002
+
+typedef struct CustomPath
+{
+	Path        path;
+	uint32		flags;
+	const struct CustomPathMethods *methods;
+} CustomPath;
+
+typedef struct CustomPathMethods
+{
+	const char *CustomName;
+	void	(*CreateCustomScanPath)(PlannerInfo *root,
+									RelOptInfo *baserel,
+									RangeTblEntry *rte);
+	struct Plan	*(*PlanCustomPath)(PlannerInfo *root,
+								   RelOptInfo *rel,
+								   CustomPath *best_path,
+								   List *tlist,
+								   List *clauses);
+	void    (*TextOutCustomPath)(StringInfo str, const CustomPath *node);
+} CustomPathMethods;
+
+/*
  * AppendPath represents an Append plan, ie, successive execution of
  * several member plans.
  *
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index a0bcc82..8d75020 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -129,6 +129,15 @@ extern Path *reparameterize_path(PlannerInfo *root, Path *path,
 					double loop_count);
 
 /*
+ * Interface definition of custom-scan providers
+ */
+extern void register_custom_path_provider(CustomPathMethods *cpp_methods);
+
+extern void create_customscan_paths(PlannerInfo *root,
+									RelOptInfo *baserel,
+									RangeTblEntry *rte);
+
+/*
  * prototypes for relnode.c
  */
 extern void setup_simple_rel_arrays(PlannerInfo *root);
