Skip to content

Commit 25b6df1

Browse files
committed
Fix PARAM_EXEC assignment mechanism to be safe in the presence of WITH.
The planner previously assumed that parameter Vars having the same absolute query level, varno, and varattno could safely be assigned the same runtime PARAM_EXEC slot, even though they might be different Vars appearing in different subqueries. This was (probably) safe before the introduction of CTEs, but the lazy-evalution mechanism used for CTEs means that a CTE can be executed during execution of some other subquery, causing the lifespan of Params at the same syntactic nesting level as the CTE to overlap with use of the same slots inside the CTE. In 9.1 we created additional hazards by using the same parameter-assignment technology for nestloop inner scan parameters, but it was broken before that, as illustrated by the added regression test. To fix, restructure the planner's management of PlannerParamItems so that items having different semantic lifespans are kept rigorously separated. This will probably result in complex queries using more runtime PARAM_EXEC slots than before, but the slots are cheap enough that this hardly matters. Also, stop generating PlannerParamItems containing Params for subquery outputs: all we really need to do is reserve the PARAM_EXEC slot number, and that now only takes incrementing a counter. The planning code is simpler and probably faster than before, as well as being more correct. Per report from Vik Reykja. Back-patch of commit 46c508f into all branches that support WITH.
1 parent 83f2584 commit 25b6df1

File tree

9 files changed

+219
-151
lines changed

9 files changed

+219
-151
lines changed

src/backend/nodes/outfuncs.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,7 +1515,6 @@ _outPlannerGlobal(StringInfo str, PlannerGlobal *node)
15151515
WRITE_NODE_TYPE("PLANNERGLOBAL");
15161516

15171517
/* NB: this isn't a complete set of fields */
1518-
WRITE_NODE_FIELD(paramlist);
15191518
WRITE_NODE_FIELD(subplans);
15201519
WRITE_NODE_FIELD(subrtables);
15211520
WRITE_NODE_FIELD(subrowmarks);
@@ -1524,6 +1523,7 @@ _outPlannerGlobal(StringInfo str, PlannerGlobal *node)
15241523
WRITE_NODE_FIELD(finalrowmarks);
15251524
WRITE_NODE_FIELD(relationOids);
15261525
WRITE_NODE_FIELD(invalItems);
1526+
WRITE_INT_FIELD(nParamExec);
15271527
WRITE_UINT_FIELD(lastPHId);
15281528
WRITE_UINT_FIELD(lastRowMarkId);
15291529
WRITE_BOOL_FIELD(transientPlan);
@@ -1538,6 +1538,7 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node)
15381538
WRITE_NODE_FIELD(parse);
15391539
WRITE_NODE_FIELD(glob);
15401540
WRITE_UINT_FIELD(query_level);
1541+
WRITE_NODE_FIELD(plan_params);
15411542
WRITE_NODE_FIELD(join_rel_list);
15421543
WRITE_INT_FIELD(join_cur_level);
15431544
WRITE_NODE_FIELD(resultRelations);
@@ -1764,7 +1765,7 @@ _outPlannerParamItem(StringInfo str, PlannerParamItem *node)
17641765
WRITE_NODE_TYPE("PLANNERPARAMITEM");
17651766

17661767
WRITE_NODE_FIELD(item);
1767-
WRITE_UINT_FIELD(abslevel);
1768+
WRITE_INT_FIELD(paramId);
17681769
}
17691770

17701771
/*****************************************************************************

src/backend/optimizer/path/allpaths.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,9 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
626626
else
627627
tuple_fraction = root->tuple_fraction;
628628

629+
/* plan_params should not be in use in current query level */
630+
Assert(root->plan_params == NIL);
631+
629632
/* Generate the plan for the subquery */
630633
rel->subplan = subquery_planner(root->glob, subquery,
631634
root,
@@ -634,6 +637,13 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
634637
rel->subrtable = subroot->parse->rtable;
635638
rel->subrowmark = subroot->rowMarks;
636639

640+
/*
641+
* Since we don't yet support LATERAL, it should not be possible for the
642+
* sub-query to have requested parameters of this level.
643+
*/
644+
if (root->plan_params)
645+
elog(ERROR, "unexpected outer reference in subquery in FROM");
646+
637647
/* Copy number of output rows from subplan */
638648
rel->tuples = rel->subplan->plan_rows;
639649

src/backend/optimizer/plan/planner.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
155155
glob = makeNode(PlannerGlobal);
156156

157157
glob->boundParams = boundParams;
158-
glob->paramlist = NIL;
159158
glob->subplans = NIL;
160159
glob->subrtables = NIL;
161160
glob->subrowmarks = NIL;
@@ -164,6 +163,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
164163
glob->finalrowmarks = NIL;
165164
glob->relationOids = NIL;
166165
glob->invalItems = NIL;
166+
glob->nParamExec = 0;
167167
glob->lastPHId = 0;
168168
glob->lastRowMarkId = 0;
169169
glob->transientPlan = false;
@@ -250,7 +250,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
250250
result->rowMarks = glob->finalrowmarks;
251251
result->relationOids = glob->relationOids;
252252
result->invalItems = glob->invalItems;
253-
result->nParamExec = list_length(glob->paramlist);
253+
result->nParamExec = glob->nParamExec;
254254

255255
return result;
256256
}
@@ -302,6 +302,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
302302
root->glob = glob;
303303
root->query_level = parent_root ? parent_root->query_level + 1 : 1;
304304
root->parent_root = parent_root;
305+
root->plan_params = NIL;
305306
root->planner_cxt = CurrentMemoryContext;
306307
root->init_plans = NIL;
307308
root->cte_plan_ids = NIL;
@@ -575,7 +576,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
575576
* and attach the initPlans to the top plan node.
576577
*/
577578
if (list_length(glob->subplans) != num_old_subplans ||
578-
root->glob->paramlist != NIL)
579+
root->glob->nParamExec > 0)
579580
SS_finalize_plan(root, plan, true);
580581

581582
/* Return internal info if caller wants it */

0 commit comments

Comments
 (0)