case T_CteScan:
case T_WorkTableScan:
case T_ForeignScan:
+ case T_CustomScan:
*rels_used = bms_add_member(*rels_used,
((Scan *) plan)->scanrelid);
break;
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;
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;
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))
case T_CteScan:
case T_WorkTableScan:
case T_ForeignScan:
+ case T_CustomScan:
ExplainScanTarget((Scan *) plan, es);
break;
case T_IndexScan:
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);
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 \
#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"
#include "executor/nodeWindowAgg.h"
#include "executor/nodeWorktablescan.h"
#include "nodes/nodeFuncs.h"
+#include "nodes/relation.h"
#include "utils/rel.h"
#include "utils/syscache.h"
ExecReScanForeignScan((ForeignScanState *) node);
break;
+ case T_CustomScanState:
+ ExecReScanCustomScan((CustomScanState *) node);
+ break;
+
case T_NestLoopState:
ExecReScanNestLoop((NestLoopState *) node);
break;
ExecValuesMarkPos((ValuesScanState *) node);
break;
+ case T_CustomScanState:
+ ExecCustomMarkPos((CustomScanState *) node);
+ break;
+
case T_MaterialState:
ExecMaterialMarkPos((MaterialState *) node);
break;
ExecValuesRestrPos((ValuesScanState *) node);
break;
+ case T_CustomScanState:
+ ExecCustomRestrPos((CustomScanState *) node);
+ break;
+
case T_MaterialState:
ExecMaterialRestrPos((MaterialState *) node);
break;
* 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:
*/
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;
}
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 */
#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"
estate, eflags);
break;
+ case T_CustomScan:
+ result = (PlanState *) ExecInitCustomScan((CustomScan *) node,
+ estate, eflags);
+ break;
+
/*
* join nodes
*/
result = ExecForeignScan((ForeignScanState *) node);
break;
+ case T_CustomScanState:
+ result = ExecCustomScan((CustomScanState *) node);
+ break;
+
/*
* join nodes
*/
ExecEndForeignScan((ForeignScanState *) node);
break;
+ case T_CustomScanState:
+ ExecEndCustomScan((CustomScanState *) node);
+ break;
+
/*
* join nodes
*/
--- /dev/null
+/* ------------------------------------------------------------------------
+ *
+ * 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);
+
+ /* 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);
+
+ /* tuple table initialization */
+ ExecInitScanTupleSlot(estate, &css->ss);
+ ExecInitResultTupleSlot(estate, &css->ss.ps);
+
+ /* initialize scan relation */
+ scan_rel = ExecOpenScanRelation(estate, cscan->scan.scanrelid, eflags);
+ css->ss.ss_currentRelation = scan_rel;
+ css->ss.ss_currentScanDesc = NULL; /* set by provider */
+ ExecAssignScanType(&css->ss, RelationGetDescr(scan_rel));
+
+ css->ss.ps.ps_TupFromTlist = false;
+
+ /*
+ * Initialize result tuple type and projection info.
+ */
+ ExecAssignResultTypeFromTL(&css->ss.ps);
+ 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);
+}
return newnode;
}
+/*
+ * _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
*
case T_ForeignScan:
retval = _copyForeignScan(from);
break;
+ case T_CustomScan:
+ retval = _copyCustomScan(from);
+ break;
case T_Join:
retval = _copyJoin(from);
break;
WRITE_BOOL_FIELD(fsSystemCol);
}
+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_FIELD(fdw_private);
}
+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)
{
case T_ForeignScan:
_outForeignScan(str, obj);
break;
+ case T_CustomScan:
+ _outCustomScan(str, obj);
+ break;
case T_Join:
_outJoin(str, obj);
break;
case T_ForeignPath:
_outForeignPath(str, obj);
break;
+ case T_CustomPath:
+ _outCustomPath(str, obj);
+ break;
case T_AppendPath:
_outAppendPath(str, obj);
break;
/* 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);
}
* 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;
/*
List *tlist, List *scan_clauses);
static ForeignScan *create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
List *tlist, List *scan_clauses);
+static Plan *create_customscan_plan(PlannerInfo *root,
+ CustomPath *best_path,
+ List *tlist, List *scan_clauses);
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);
case T_CteScan:
case T_WorkTableScan:
case T_ForeignScan:
+ case T_CustomScan:
plan = create_scan_plan(root, best_path);
break;
case T_HashJoin:
scan_clauses);
break;
+ case T_CustomScan:
+ plan = create_customscan_plan(root,
+ (CustomPath *) best_path,
+ tlist,
+ scan_clauses);
+ break;
+
default:
elog(ERROR, "unrecognized node type: %d",
(int) best_path->pathtype);
return plan;
}
+/*
+ * create_custom_plan
+ *
+ * Transform a CustomPath into a Plan.
+ */
+static Plan *
+create_customscan_plan(PlannerInfo *root, CustomPath *best_path,
+ List *tlist, List *scan_clauses)
+{
+ Plan *plan;
+ RelOptInfo *rel = best_path->path.parent;
+
+ /*
+ * Right now, all we can support is CustomScan node which is associated
+ * with a particular base relation to be scanned.
+ */
+ Assert(rel && rel->reloptkind == RELOPT_BASEREL);
+
+ /*
+ * Sort clauses into the best execution order, although custom-scan
+ * provider can reorder them again.
+ */
+ scan_clauses = order_qual_clauses(root, scan_clauses);
+
+ /*
+ * Create a CustomScan (or its inheritance) node according to
+ * the supplied CustomPath.
+ */
+ plan = best_path->methods->PlanCustomPath(root, rel, best_path, tlist,
+ scan_clauses);
+
+ /*
+ * NOTE: unlike create_foreignscan_plan(), it is responsibility of
+ * the custom plan provider to replace outer-relation variables
+ * with nestloop params, because we cannot know how many expression
+ * trees are held in the private fields.
+ */
+
+ /*
+ * Copy cost data from Path to Plan; no need to make custom-plan
+ * providers do this
+ */
+ copy_path_costsize(plan, &best_path->path);
+
+ return plan;
+}
/*****************************************************************************
*
* 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 */
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);
}
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.
+ * Otherwise, the custom-plan provider can skip this callback.
+ */
+ if (cscan->methods->SetCustomScanRef)
+ cscan->methods->SetCustomScanRef(root, cscan, rtoffset);
+ }
+ break;
+
case T_NestLoop:
case T_MergeJoin:
case T_HashJoin:
* 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 */
* 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;
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;
#include "optimizer/var.h"
#include "parser/parsetree.h"
#include "utils/lsyscache.h"
+#include "utils/memutils.h"
#include "utils/selfuncs.h"
}
return NULL;
}
+
+/*****************************************************************************
+ * creation of custom-plan paths
+ *****************************************************************************/
+
+static List *custom_path_providers = NIL;
+
+/*
+ * register_custom_path_provider
+ *
+ * Register a table of callback functions which implements a custom-path
+ * provider. This allows extension to provide additional (hopefully faster)
+ * methods of scanning a relation.
+ */
+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
+ *
+ * Invoke custom path provider callbacks. If the callback determines that
+ * the custom-path provider can handle this relation, it can 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);
+ }
+}
}
}
+/*
+ * GetSpecialCustomVar
+ *
+ * If a custom-scan provider uses a special varnode, this function will be
+ * called when deparsing; it should return an Expr node to be reversed-listed
+ * in lieu of the special Var.
+ */
+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.
int netlevelsup;
deparse_namespace *dpns;
deparse_columns *colinfo;
+ PlanState *child_ps = NULL;
+ Node *expr;
char *refname;
char *attname;
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;
AttrNumber attnum;
int netlevelsup;
deparse_namespace *dpns;
+ PlanState *child_ps = NULL;
TupleDesc tupleDesc;
Node *expr;
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;
#include "executor/execdesc.h"
#include "nodes/parsenodes.h"
+#include "nodes/relation.h"
#include "utils/lockwaitpolicy.h"
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);
--- /dev/null
+/* ------------------------------------------------------------------------
+ *
+ * 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 */
#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"
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
* ----------------------------------------------------------------
T_CteScan,
T_WorkTableScan,
T_ForeignScan,
+ T_CustomScan,
T_Join,
T_NestLoop,
T_MergeJoin,
T_CteScanState,
T_WorkTableScanState,
T_ForeignScanState,
+ T_CustomScanState,
T_JoinState,
T_NestLoopState,
T_MergeJoinState,
T_HashPath,
T_TidPath,
T_ForeignPath,
+ T_CustomPath,
T_AppendPath,
T_MergeAppendPath,
T_ResultPath,
#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"
bool fsSystemCol; /* true if any "system column" is needed */
} 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;
/*
* ==========
#define RELATION_H
#include "access/sdir.h"
+#include "lib/stringinfo.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h"
#include "storage/block.h"
List *fdw_private;
} ForeignPath;
+/*
+ * CustomPath represents a scan by some out-of-core extension.
+ *
+ * We provide a set of hooks here - which the provider must take care to
+ * set up correctly - to allow extensions to supply their own methods of
+ * scanning a relation. For example, a provider might provide GPU
+ * acceleration, a cache-based scan, or some other kind of logic we haven't
+ * dreamed up yet.
+ *
+ * Core code should avoid assuming that the CustomPath is only as large as
+ * the structure declared here; providers are expected to make it the first
+ * element in a larger structure.
+ */
+
+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.
Relids required_outer,
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
*/
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
*/
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);