Skip to content

Commit 4477704

Browse files
committed
Rearrange CustomScan API.
Make it work more like FDW plans do: instead of assuming that there are expressions in a CustomScan plan node that the core code doesn't know about, insist that all subexpressions that need planner attention be in a "custom_exprs" list in the Plan representation. (Of course, the custom plugin can break the list apart again at executor initialization.) This lets us revert the parts of the patch that exposed setrefs.c and subselect.c processing to the outside world. Also revert the GetSpecialCustomVar stuff in ruleutils.c; that concept may work in future, but it's far from fully baked right now.
1 parent c2ea228 commit 4477704

File tree

11 files changed

+108
-163
lines changed

11 files changed

+108
-163
lines changed

src/backend/nodes/copyfuncs.c

+14-7
Original file line numberDiff line numberDiff line change
@@ -603,17 +603,24 @@ _copyForeignScan(const ForeignScan *from)
603603
static CustomScan *
604604
_copyCustomScan(const CustomScan *from)
605605
{
606-
CustomScan *newnode;
607-
608-
newnode = from->methods->CopyCustomScan(from);
609-
Assert(nodeTag(newnode) == nodeTag(from));
606+
CustomScan *newnode = makeNode(CustomScan);
610607

608+
/*
609+
* copy node superclass fields
610+
*/
611611
CopyScanFields((const Scan *) from, (Scan *) newnode);
612+
613+
/*
614+
* copy remainder of node
615+
*/
612616
COPY_SCALAR_FIELD(flags);
617+
COPY_NODE_FIELD(custom_exprs);
618+
COPY_NODE_FIELD(custom_private);
619+
613620
/*
614-
* NOTE: The method field of CustomScan is required to be a pointer
615-
* to a static table of callback functions. So, we don't copy the
616-
* table itself, just reference the original one.
621+
* NOTE: The method field of CustomScan is required to be a pointer to a
622+
* static table of callback functions. So we don't copy the table itself,
623+
* just reference the original one.
617624
*/
618625
COPY_SCALAR_FIELD(methods);
619626

src/backend/nodes/outfuncs.c

+12-4
Original file line numberDiff line numberDiff line change
@@ -569,10 +569,14 @@ _outCustomScan(StringInfo str, const CustomScan *node)
569569
WRITE_NODE_TYPE("CUSTOMSCAN");
570570

571571
_outScanInfo(str, (const Scan *) node);
572+
572573
WRITE_UINT_FIELD(flags);
573-
appendStringInfo(str, " :methods");
574+
WRITE_NODE_FIELD(custom_exprs);
575+
WRITE_NODE_FIELD(custom_private);
576+
appendStringInfoString(str, " :methods ");
574577
_outToken(str, node->methods->CustomName);
575-
node->methods->TextOutCustomScan(str, node);
578+
if (node->methods->TextOutCustomScan)
579+
node->methods->TextOutCustomScan(str, node);
576580
}
577581

578582
static void
@@ -1600,11 +1604,15 @@ static void
16001604
_outCustomPath(StringInfo str, const CustomPath *node)
16011605
{
16021606
WRITE_NODE_TYPE("CUSTOMPATH");
1607+
16031608
_outPathInfo(str, (const Path *) node);
1609+
16041610
WRITE_UINT_FIELD(flags);
1605-
appendStringInfo(str, " :methods");
1611+
WRITE_NODE_FIELD(custom_private);
1612+
appendStringInfoString(str, " :methods ");
16061613
_outToken(str, node->methods->CustomName);
1607-
node->methods->TextOutCustomPath(str, node);
1614+
if (node->methods->TextOutCustomPath)
1615+
node->methods->TextOutCustomPath(str, node);
16081616
}
16091617

16101618
static void

src/backend/optimizer/plan/createplan.c

+31-18
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static WorkTableScan *create_worktablescan_plan(PlannerInfo *root, Path *best_pa
7777
List *tlist, List *scan_clauses);
7878
static ForeignScan *create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
7979
List *tlist, List *scan_clauses);
80-
static Plan *create_customscan_plan(PlannerInfo *root,
80+
static CustomScan *create_customscan_plan(PlannerInfo *root,
8181
CustomPath *best_path,
8282
List *tlist, List *scan_clauses);
8383
static NestLoop *create_nestloop_plan(PlannerInfo *root, NestPath *best_path,
@@ -86,6 +86,7 @@ static MergeJoin *create_mergejoin_plan(PlannerInfo *root, MergePath *best_path,
8686
Plan *outer_plan, Plan *inner_plan);
8787
static HashJoin *create_hashjoin_plan(PlannerInfo *root, HashPath *best_path,
8888
Plan *outer_plan, Plan *inner_plan);
89+
static Node *replace_nestloop_params(PlannerInfo *root, Node *expr);
8990
static Node *replace_nestloop_params_mutator(Node *node, PlannerInfo *root);
9091
static void process_subquery_nestloop_params(PlannerInfo *root,
9192
List *subplan_params);
@@ -413,10 +414,10 @@ create_scan_plan(PlannerInfo *root, Path *best_path)
413414
break;
414415

415416
case T_CustomScan:
416-
plan = create_customscan_plan(root,
417-
(CustomPath *) best_path,
418-
tlist,
419-
scan_clauses);
417+
plan = (Plan *) create_customscan_plan(root,
418+
(CustomPath *) best_path,
419+
tlist,
420+
scan_clauses);
420421
break;
421422

422423
default:
@@ -2022,11 +2023,11 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
20222023
*
20232024
* Transform a CustomPath into a Plan.
20242025
*/
2025-
static Plan *
2026+
static CustomScan *
20262027
create_customscan_plan(PlannerInfo *root, CustomPath *best_path,
20272028
List *tlist, List *scan_clauses)
20282029
{
2029-
Plan *plan;
2030+
CustomScan *cplan;
20302031
RelOptInfo *rel = best_path->path.parent;
20312032

20322033
/*
@@ -2045,23 +2046,35 @@ create_customscan_plan(PlannerInfo *root, CustomPath *best_path,
20452046
* Invoke custom plan provider to create the Plan node represented by the
20462047
* CustomPath.
20472048
*/
2048-
plan = best_path->methods->PlanCustomPath(root, rel, best_path, tlist,
2049-
scan_clauses);
2049+
cplan = (CustomScan *) best_path->methods->PlanCustomPath(root,
2050+
rel,
2051+
best_path,
2052+
tlist,
2053+
scan_clauses);
2054+
Assert(IsA(cplan, CustomScan));
20502055

20512056
/*
2052-
* NOTE: unlike create_foreignscan_plan(), it is the responsibility of the
2053-
* custom plan provider to replace outer-relation variables with nestloop
2054-
* params, because we cannot know what expression trees may be held in
2055-
* private fields.
2057+
* Copy cost data from Path to Plan; no need to make custom-plan providers
2058+
* do this
20562059
*/
2060+
copy_path_costsize(&cplan->scan.plan, &best_path->path);
20572061

20582062
/*
2059-
* Copy cost data from Path to Plan; no need to make custom-plan providers
2060-
* do this
2063+
* Replace any outer-relation variables with nestloop params in the qual
2064+
* and custom_exprs expressions. We do this last so that the custom-plan
2065+
* provider doesn't have to be involved. (Note that parts of custom_exprs
2066+
* could have come from join clauses, so doing this beforehand on the
2067+
* scan_clauses wouldn't work.)
20612068
*/
2062-
copy_path_costsize(plan, &best_path->path);
2069+
if (best_path->path.param_info)
2070+
{
2071+
cplan->scan.plan.qual = (List *)
2072+
replace_nestloop_params(root, (Node *) cplan->scan.plan.qual);
2073+
cplan->custom_exprs = (List *)
2074+
replace_nestloop_params(root, (Node *) cplan->custom_exprs);
2075+
}
20632076

2064-
return plan;
2077+
return cplan;
20652078
}
20662079

20672080

@@ -2598,7 +2611,7 @@ create_hashjoin_plan(PlannerInfo *root,
25982611
* root->curOuterRels are replaced by Params, and entries are added to
25992612
* root->curOuterParams if not already present.
26002613
*/
2601-
Node *
2614+
static Node *
26022615
replace_nestloop_params(PlannerInfo *root, Node *expr)
26032616
{
26042617
/* No setup needed for tree walk, so away we go */

src/backend/optimizer/plan/setrefs.c

+10-17
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ static Plan *set_subqueryscan_references(PlannerInfo *root,
9494
SubqueryScan *plan,
9595
int rtoffset);
9696
static bool trivial_subqueryscan(SubqueryScan *plan);
97+
static Node *fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset);
9798
static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
9899
static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context);
99100
static void set_join_references(PlannerInfo *root, Join *join, int rtoffset);
@@ -580,23 +581,15 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
580581

581582
case T_CustomScan:
582583
{
583-
CustomScan *cscan = (CustomScan *) plan;
584+
CustomScan *splan = (CustomScan *) plan;
584585

585-
cscan->scan.scanrelid += rtoffset;
586-
cscan->scan.plan.targetlist =
587-
fix_scan_list(root, cscan->scan.plan.targetlist, rtoffset);
588-
cscan->scan.plan.qual =
589-
fix_scan_list(root, cscan->scan.plan.qual, rtoffset);
590-
591-
/*
592-
* The core implementation applies the routine to fixup varno
593-
* on the target-list and scan qualifier. If custom-scan has
594-
* additional expression nodes on its private fields, it has
595-
* to apply same fixup on them. Otherwise, the custom-plan
596-
* provider can skip this callback.
597-
*/
598-
if (cscan->methods->SetCustomScanRef)
599-
cscan->methods->SetCustomScanRef(root, cscan, rtoffset);
586+
splan->scan.scanrelid += rtoffset;
587+
splan->scan.plan.targetlist =
588+
fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
589+
splan->scan.plan.qual =
590+
fix_scan_list(root, splan->scan.plan.qual, rtoffset);
591+
splan->custom_exprs =
592+
fix_scan_list(root, splan->custom_exprs, rtoffset);
600593
}
601594
break;
602595

@@ -1182,7 +1175,7 @@ fix_param_node(PlannerInfo *root, Param *p)
11821175
* looking up operator opcode info for OpExpr and related nodes,
11831176
* and adding OIDs from regclass Const nodes into root->glob->relationOids.
11841177
*/
1185-
Node *
1178+
static Node *
11861179
fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset)
11871180
{
11881181
fix_scan_expr_context context;

src/backend/optimizer/plan/subselect.c

+3-18
Original file line numberDiff line numberDiff line change
@@ -2284,24 +2284,9 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
22842284
break;
22852285

22862286
case T_CustomScan:
2287-
{
2288-
CustomScan *custom_scan = (CustomScan *) plan;
2289-
2290-
context.paramids = bms_add_members(context.paramids,
2291-
scan_params);
2292-
/*
2293-
* custom-scan provider is responsible to apply
2294-
* finalize_primnode() on the expression node of
2295-
* its private fields, but no need to apply it
2296-
* on the tlist and qual of Plan node because it
2297-
* is already done above.
2298-
*/
2299-
if (custom_scan->methods->FinalizeCustomScan)
2300-
custom_scan->methods->FinalizeCustomScan(root,
2301-
custom_scan,
2302-
finalize_primnode,
2303-
(void *)&context);
2304-
}
2287+
finalize_primnode((Node *) ((CustomScan *) plan)->custom_exprs,
2288+
&context);
2289+
context.paramids = bms_add_members(context.paramids, scan_params);
23052290
break;
23062291

23072292
case T_ModifyTable:

src/backend/utils/adt/ruleutils.c

-70
Original file line numberDiff line numberDiff line change
@@ -5493,26 +5493,6 @@ get_utility_query_def(Query *query, deparse_context *context)
54935493
}
54945494
}
54955495

5496-
/*
5497-
* GetSpecialCustomVar
5498-
*
5499-
* If a custom-scan provider uses a special varnode, this function will be
5500-
* called when deparsing; it should return an Expr node to be reversed-listed
5501-
* in lieu of the special Var.
5502-
*/
5503-
static Node *
5504-
GetSpecialCustomVar(CustomScanState *css, Var *varnode, PlanState **child_ps)
5505-
{
5506-
Assert(IsA(css, CustomScanState));
5507-
Assert(IS_SPECIAL_VARNO(varnode->varno));
5508-
5509-
if (!css->methods->GetSpecialCustomVar)
5510-
ereport(ERROR,
5511-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5512-
errmsg("%s does not support special varno reference",
5513-
css->methods->CustomName)));
5514-
return (Node *) css->methods->GetSpecialCustomVar(css, varnode, child_ps);
5515-
}
55165496

55175497
/*
55185498
* Display a Var appropriately.
@@ -5542,8 +5522,6 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
55425522
int netlevelsup;
55435523
deparse_namespace *dpns;
55445524
deparse_columns *colinfo;
5545-
PlanState *child_ps = NULL;
5546-
Node *expr;
55475525
char *refname;
55485526
char *attname;
55495527

@@ -5568,29 +5546,6 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
55685546
colinfo = deparse_columns_fetch(var->varno, dpns);
55695547
attnum = var->varattno;
55705548
}
5571-
else if (IS_SPECIAL_VARNO(var->varno) &&
5572-
IsA(dpns->planstate, CustomScanState) &&
5573-
(expr = GetSpecialCustomVar((CustomScanState *) dpns->planstate,
5574-
var, &child_ps)) != NULL)
5575-
{
5576-
deparse_namespace save_dpns;
5577-
5578-
if (child_ps)
5579-
push_child_plan(dpns, child_ps, &save_dpns);
5580-
/*
5581-
* Force parentheses because our caller probably assumed a Var is a
5582-
* simple expression.
5583-
*/
5584-
if (!IsA(expr, Var))
5585-
appendStringInfoChar(buf, '(');
5586-
get_rule_expr((Node *) expr, context, true);
5587-
if (!IsA(expr, Var))
5588-
appendStringInfoChar(buf, ')');
5589-
5590-
if (child_ps)
5591-
pop_child_plan(dpns, &save_dpns);
5592-
return NULL;
5593-
}
55945549
else if (var->varno == OUTER_VAR && dpns->outer_tlist)
55955550
{
55965551
TargetEntry *tle;
@@ -5805,7 +5760,6 @@ get_name_for_var_field(Var *var, int fieldno,
58055760
AttrNumber attnum;
58065761
int netlevelsup;
58075762
deparse_namespace *dpns;
5808-
PlanState *child_ps = NULL;
58095763
TupleDesc tupleDesc;
58105764
Node *expr;
58115765

@@ -5880,30 +5834,6 @@ get_name_for_var_field(Var *var, int fieldno,
58805834
rte = rt_fetch(var->varno, dpns->rtable);
58815835
attnum = var->varattno;
58825836
}
5883-
else if (IS_SPECIAL_VARNO(var->varno) &&
5884-
IsA(dpns->planstate, CustomScanState) &&
5885-
(expr = GetSpecialCustomVar((CustomScanState *) dpns->planstate,
5886-
var, &child_ps)) != NULL)
5887-
{
5888-
StringInfo saved = context->buf;
5889-
StringInfoData temp;
5890-
deparse_namespace save_dpns;
5891-
5892-
initStringInfo(&temp);
5893-
context->buf = &temp;
5894-
5895-
if (child_ps)
5896-
push_child_plan(dpns, child_ps, &save_dpns);
5897-
if (!IsA(expr, Var))
5898-
appendStringInfoChar(context->buf, '(');
5899-
get_rule_expr((Node *) expr, context, true);
5900-
if (!IsA(expr, Var))
5901-
appendStringInfoChar(context->buf, ')');
5902-
if (child_ps)
5903-
pop_child_plan(dpns, &save_dpns);
5904-
context->buf = saved;
5905-
return temp.data;
5906-
}
59075837
else if (var->varno == OUTER_VAR && dpns->outer_tlist)
59085838
{
59095839
TargetEntry *tle;

src/include/executor/nodeCustom.h

-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
extern CustomScanState *ExecInitCustomScan(CustomScan *custom_scan,
2121
EState *estate, int eflags);
2222
extern TupleTableSlot *ExecCustomScan(CustomScanState *node);
23-
extern Node *MultiExecCustomScan(CustomScanState *node);
2423
extern void ExecEndCustomScan(CustomScanState *node);
2524

2625
extern void ExecReScanCustomScan(CustomScanState *node);

src/include/nodes/execnodes.h

+10-6
Original file line numberDiff line numberDiff line change
@@ -1503,9 +1503,16 @@ typedef struct ForeignScanState
15031503
} ForeignScanState;
15041504

15051505
/* ----------------
1506-
* CustomScanState information
1506+
* CustomScanState information
15071507
*
15081508
* CustomScan nodes are used to execute custom code within executor.
1509+
*
1510+
* Core code must avoid assuming that the CustomScanState is only as large as
1511+
* the structure declared here; providers are allowed to make it the first
1512+
* element in a larger structure, and typically would need to do so. The
1513+
* struct is actually allocated by the CreateCustomScanState method associated
1514+
* with the plan node. Any additional fields can be initialized there, or in
1515+
* the BeginCustomScan method.
15091516
* ----------------
15101517
*/
15111518
struct ExplainState; /* avoid including explain.h here */
@@ -1515,7 +1522,7 @@ typedef struct CustomExecMethods
15151522
{
15161523
const char *CustomName;
15171524

1518-
/* EXECUTOR methods */
1525+
/* Executor methods: mark/restore are optional, the rest are required */
15191526
void (*BeginCustomScan) (struct CustomScanState *node,
15201527
EState *estate,
15211528
int eflags);
@@ -1525,13 +1532,10 @@ typedef struct CustomExecMethods
15251532
void (*MarkPosCustomScan) (struct CustomScanState *node);
15261533
void (*RestrPosCustomScan) (struct CustomScanState *node);
15271534

1528-
/* EXPLAIN support */
1535+
/* Optional: print additional information in EXPLAIN */
15291536
void (*ExplainCustomScan) (struct CustomScanState *node,
15301537
List *ancestors,
15311538
struct ExplainState *es);
1532-
Node *(*GetSpecialCustomVar) (struct CustomScanState *node,
1533-
Var *varnode,
1534-
PlanState **child_ps);
15351539
} CustomExecMethods;
15361540

15371541
typedef struct CustomScanState

0 commit comments

Comments
 (0)