 src/backend/nodes/outfuncs.c            | 14 +++++++
 src/backend/optimizer/path/allpaths.c   |  3 ++
 src/backend/optimizer/plan/createplan.c | 32 ++++++++++++++++
 src/backend/optimizer/util/pathnode.c   | 68 +++++++++++++++++++++++++++++++++
 src/include/nodes/nodes.h               |  2 +
 src/include/nodes/relation.h            | 30 +++++++++++++++
 src/include/optimizer/pathnode.h        | 26 +++++++++++++
 7 files changed, 175 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..d5b0fb3 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,34 @@ 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 Plan *
+create_custom_plan(PlannerInfo *root, CustomPath *best_path)
+{
+	Plan		   *custom_plan;
+
+	/*
+	 * Create a CustomScan (or its inheritance) according to
+	 * the supplied CustomPath.
+	 */
+	Assert(best_path->path.pathtype == T_CustomScan);
+	custom_plan = (Plan *)
+		best_path->methods->CreateCustomPlan(root, best_path);
+	Assert(nodeTag(custom_plan) == best_path->path.pathtype);
+
+	/*
+	 * 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..b723bdd 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,70 @@ reparameterize_path(PlannerInfo *root, Path *path,
 	}
 	return NULL;
 }
+
+/*****************************************************************************
+ *     creation of custom-plan paths
+ *****************************************************************************/
+typedef struct
+{
+	const char	   *cpp_name;
+	uint32			cpp_class;
+	add_custom_path_type cpp_callback;
+} custom_path_provider_info;
+
+static List	   *custom_path_providers = NIL;
+
+/*
+ * register_custom_path_provider
+ *
+ * It registers an entrypoint of custom-path providers.
+ * The callback function is expected to construct CustomPath node to run
+ * alternative logic instead of the existing node, if extension can do.
+ */
+void
+register_custom_path_provider(const char *cpp_name,
+							  int cpp_class,
+							  add_custom_path_type callback)
+{
+	custom_path_provider_info *cpp_info;
+	MemoryContext		oldcxt;
+
+	oldcxt = MemoryContextSwitchTo(TopMemoryContext);
+	cpp_info = palloc(sizeof(custom_path_provider_info));
+	cpp_info->cpp_name = pstrdup(cpp_name);
+	cpp_info->cpp_class = cpp_class;
+	cpp_info->cpp_callback = callback;
+
+	custom_path_providers = lappend(custom_path_providers, cpp_info);
+
+	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)
+{
+	customScanArg	sarg;
+	ListCell	   *cell;
+
+	sarg.cpp_class = CUSTOM_PATH_CLASS_SCAN;
+	sarg.root = root;
+	sarg.baserel = baserel;
+	sarg.rte = rte;
+
+	foreach (cell, custom_path_providers)
+	{
+		custom_path_provider_info  *cpp_info = lfirst(cell);
+
+		if (cpp_info->cpp_class == CUSTOM_PATH_CLASS_SCAN)
+			cpp_info->cpp_callback(&sarg);
+	}
+}
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/relation.h b/src/include/nodes/relation.h
index dacbe9c..188cc54 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,35 @@ 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;
+
+#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;
+	Node   *(*CreateCustomPlan)(PlannerInfo *root,
+								CustomPath *best_path);
+	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..b6c6284 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -129,6 +129,32 @@ extern Path *reparameterize_path(PlannerInfo *root, Path *path,
 					double loop_count);
 
 /*
+ * Interface definition of custom-scan providers
+ */
+#define CUSTOM_PATH_CLASS_SCAN		's'
+/* XXX - Other custom class paths shall be added in the later version */
+
+/*
+ * customScanArg - A set of arguments for relation scan.
+ */
+typedef struct {
+	int				cpp_class;	/* = CUSTOM_PATH_CLASS_SCAN */
+	PlannerInfo	   *root;
+	RelOptInfo	   *baserel;
+	RangeTblEntry  *rte;
+} customScanArg;
+
+typedef void (*add_custom_path_type)(void *arg);
+
+extern void register_custom_path_provider(const char *cpp_name,
+										  int cpp_class,
+										  add_custom_path_type callback);
+
+extern void create_customscan_paths(PlannerInfo *root,
+									RelOptInfo *baserel,
+									RangeTblEntry *rte);
+
+/*
  * prototypes for relnode.c
  */
 extern void setup_simple_rel_arrays(PlannerInfo *root);
