Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite4e60e7

Browse files
committed
Fix handling of PlaceHolderVars in nestloop parameter management.
If we use a PlaceHolderVar from the outer relation in an inner indexscan,we need to reference the PlaceHolderVar as such as the value to be passedin from the outer relation. The previous code effectively tried toreconstruct the PHV from its component expression, which doesn't work since(a) the Vars therein aren't necessarily bubbled up far enough, and (b) itwould be the wrong semantics anyway because of the possibility that the PHVis supposed to have gone to null at some point before the current join.Point (a) led to "variable not found in subplan target list" plannererrors, but point (b) would have led to silently wrong answers.Per report from Roger Niederland.
1 parent5cd7b68 commite4e60e7

File tree

9 files changed

+208
-19
lines changed

9 files changed

+208
-19
lines changed

‎src/backend/executor/nodeNestloop.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ ExecNestLoop(NestLoopState *node)
148148

149149
prm=&(econtext->ecxt_param_exec_vals[paramno]);
150150
/* Param value should be an OUTER var */
151+
Assert(IsA(nlp->paramval,Var));
151152
Assert(nlp->paramval->varno==OUTER);
152153
Assert(nlp->paramval->varattno>0);
153154
prm->value=slot_getattr(outerTupleSlot,

‎src/backend/optimizer/plan/createplan.c

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include"optimizer/clauses.h"
2828
#include"optimizer/cost.h"
2929
#include"optimizer/paths.h"
30+
#include"optimizer/placeholder.h"
3031
#include"optimizer/plancat.h"
3132
#include"optimizer/planmain.h"
3233
#include"optimizer/predtest.h"
@@ -1886,7 +1887,20 @@ create_nestloop_plan(PlannerInfo *root,
18861887
NestLoopParam*nlp= (NestLoopParam*)lfirst(cell);
18871888

18881889
next=lnext(cell);
1889-
if (bms_is_member(nlp->paramval->varno,outerrelids))
1890+
if (IsA(nlp->paramval,Var)&&
1891+
bms_is_member(nlp->paramval->varno,outerrelids))
1892+
{
1893+
root->curOuterParams=list_delete_cell(root->curOuterParams,
1894+
cell,prev);
1895+
nestParams=lappend(nestParams,nlp);
1896+
}
1897+
elseif (IsA(nlp->paramval,PlaceHolderVar)&&
1898+
bms_overlap(((PlaceHolderVar*)nlp->paramval)->phrels,
1899+
outerrelids)&&
1900+
bms_is_subset(find_placeholder_info(root,
1901+
(PlaceHolderVar*)nlp->paramval,
1902+
false)->ph_eval_at,
1903+
outerrelids))
18901904
{
18911905
root->curOuterParams=list_delete_cell(root->curOuterParams,
18921906
cell,prev);
@@ -2314,11 +2328,12 @@ create_hashjoin_plan(PlannerInfo *root,
23142328

23152329
/*
23162330
* replace_nestloop_params
2317-
* Replace outer-relation Vars in the given expression with nestloop Params
2331+
* Replace outer-relation Vars and PlaceHolderVars in the given expression
2332+
* with nestloop Params
23182333
*
2319-
* All Vars belonging to the relation(s) identified by root->curOuterRels
2320-
* are replaced by Params, and entries are added to root->curOuterParams if
2321-
* not already present.
2334+
* All Varsand PlaceHolderVarsbelonging to the relation(s) identified by
2335+
*root->curOuterRelsare replaced by Params, and entries are added to
2336+
*root->curOuterParams ifnot already present.
23222337
*/
23232338
staticNode*
23242339
replace_nestloop_params(PlannerInfo*root,Node*expr)
@@ -2345,7 +2360,7 @@ replace_nestloop_params_mutator(Node *node, PlannerInfo *root)
23452360
if (!bms_is_member(var->varno,root->curOuterRels))
23462361
returnnode;
23472362
/* Create a Param representing the Var */
2348-
param=assign_nestloop_param(root,var);
2363+
param=assign_nestloop_param_var(root,var);
23492364
/* Is this param already listed in root->curOuterParams? */
23502365
foreach(lc,root->curOuterParams)
23512366
{
@@ -2365,6 +2380,48 @@ replace_nestloop_params_mutator(Node *node, PlannerInfo *root)
23652380
/* And return the replacement Param */
23662381
return (Node*)param;
23672382
}
2383+
if (IsA(node,PlaceHolderVar))
2384+
{
2385+
PlaceHolderVar*phv= (PlaceHolderVar*)node;
2386+
Param*param;
2387+
NestLoopParam*nlp;
2388+
ListCell*lc;
2389+
2390+
/* Upper-level PlaceHolderVars should be long gone at this point */
2391+
Assert(phv->phlevelsup==0);
2392+
2393+
/*
2394+
* If not to be replaced, just return the PlaceHolderVar unmodified.
2395+
* We use bms_overlap as a cheap/quick test to see if the PHV might
2396+
* be evaluated in the outer rels, and then grab its PlaceHolderInfo
2397+
* to tell for sure.
2398+
*/
2399+
if (!bms_overlap(phv->phrels,root->curOuterRels))
2400+
returnnode;
2401+
if (!bms_is_subset(find_placeholder_info(root,phv, false)->ph_eval_at,
2402+
root->curOuterRels))
2403+
returnnode;
2404+
/* Create a Param representing the PlaceHolderVar */
2405+
param=assign_nestloop_param_placeholdervar(root,phv);
2406+
/* Is this param already listed in root->curOuterParams? */
2407+
foreach(lc,root->curOuterParams)
2408+
{
2409+
nlp= (NestLoopParam*)lfirst(lc);
2410+
if (nlp->paramno==param->paramid)
2411+
{
2412+
Assert(equal(phv,nlp->paramval));
2413+
/* Present, so we can just return the Param */
2414+
return (Node*)param;
2415+
}
2416+
}
2417+
/* No, so add it */
2418+
nlp=makeNode(NestLoopParam);
2419+
nlp->paramno=param->paramid;
2420+
nlp->paramval= (Var*)phv;
2421+
root->curOuterParams=lappend(root->curOuterParams,nlp);
2422+
/* And return the replacement Param */
2423+
return (Node*)param;
2424+
}
23682425
returnexpression_tree_mutator(node,
23692426
replace_nestloop_params_mutator,
23702427
(void*)root);
@@ -2377,7 +2434,7 @@ replace_nestloop_params_mutator(Node *node, PlannerInfo *root)
23772434
*
23782435
* We have four tasks here:
23792436
** Remove RestrictInfo nodes from the input clauses.
2380-
** Replace any outer-relation Var nodes with nestloop Params.
2437+
** Replace any outer-relation Varor PHVnodes with nestloop Params.
23812438
* (XXX eventually, that responsibility should go elsewhere?)
23822439
** Index keys must be represented by Var nodes with varattno set to the
23832440
* index's attribute number, not the attribute number in the original rel.

‎src/backend/optimizer/plan/setrefs.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,10 @@ set_join_references(PlannerGlobal *glob, Join *join, int rtoffset)
10191019
(Node*)nlp->paramval,
10201020
outer_itlist,
10211021
rtoffset);
1022+
/* Check we replaced any PlaceHolderVar with simple Var */
1023+
if (!(IsA(nlp->paramval,Var)&&
1024+
nlp->paramval->varno==OUTER))
1025+
elog(ERROR,"NestLoopParam was not reduced to a simple Var");
10221026
}
10231027
}
10241028
elseif (IsA(join,MergeJoin))

‎src/backend/optimizer/plan/subselect.c

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ replace_outer_var(PlannerInfo *root, Var *var)
172172
* the Var to be local to the current query level.
173173
*/
174174
Param*
175-
assign_nestloop_param(PlannerInfo*root,Var*var)
175+
assign_nestloop_param_var(PlannerInfo*root,Var*var)
176176
{
177177
Param*retval;
178178
inti;
@@ -192,6 +192,65 @@ assign_nestloop_param(PlannerInfo *root, Var *var)
192192
returnretval;
193193
}
194194

195+
/*
196+
* Generate a Param node to replace the given PlaceHolderVar, which will be
197+
* supplied from an upper NestLoop join node.
198+
*
199+
* This is just like assign_nestloop_param_var, except for PlaceHolderVars.
200+
*/
201+
Param*
202+
assign_nestloop_param_placeholdervar(PlannerInfo*root,PlaceHolderVar*phv)
203+
{
204+
Param*retval;
205+
ListCell*ppl;
206+
PlannerParamItem*pitem;
207+
Indexabslevel;
208+
inti;
209+
210+
Assert(phv->phlevelsup==0);
211+
abslevel=root->query_level;
212+
213+
/* If there's already a paramlist entry for this same PHV, just use it */
214+
/* We assume comparing the PHIDs is sufficient */
215+
i=0;
216+
foreach(ppl,root->glob->paramlist)
217+
{
218+
pitem= (PlannerParamItem*)lfirst(ppl);
219+
if (pitem->abslevel==abslevel&&IsA(pitem->item,PlaceHolderVar))
220+
{
221+
PlaceHolderVar*pphv= (PlaceHolderVar*)pitem->item;
222+
223+
if (pphv->phid==phv->phid)
224+
break;
225+
}
226+
i++;
227+
}
228+
229+
if (ppl==NULL)
230+
{
231+
/* Nope, so make a new one */
232+
phv= (PlaceHolderVar*)copyObject(phv);
233+
234+
pitem=makeNode(PlannerParamItem);
235+
pitem->item= (Node*)phv;
236+
pitem->abslevel=abslevel;
237+
238+
root->glob->paramlist=lappend(root->glob->paramlist,pitem);
239+
240+
/* i is already the correct list index for the new item */
241+
}
242+
243+
retval=makeNode(Param);
244+
retval->paramkind=PARAM_EXEC;
245+
retval->paramid=i;
246+
retval->paramtype=exprType((Node*)phv->phexpr);
247+
retval->paramtypmod=exprTypmod((Node*)phv->phexpr);
248+
retval->paramcollid=exprCollation((Node*)phv->phexpr);
249+
retval->location=-1;
250+
251+
returnretval;
252+
}
253+
195254
/*
196255
* Generate a Param node to replace the given Aggref
197256
* which is expected to have agglevelsup > 0 (ie, it is not local).

‎src/include/nodes/plannodes.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,9 @@ typedef struct Join
488488
* The nestParams list identifies any executor Params that must be passed
489489
* into execution of the inner subplan carrying values from the current row
490490
* of the outer subplan. Currently we restrict these values to be simple
491-
* Vars, but perhaps someday that'd be worth relaxing.
491+
* Vars, but perhaps someday that'd be worth relaxing. (Note: during plan
492+
* creation, the paramval can actually be a PlaceHolderVar expression; but it
493+
* must be a Var with varno OUTER_VAR by the time it gets to the executor.)
492494
* ----------------
493495
*/
494496
typedefstructNestLoop

‎src/include/nodes/relation.h

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,13 +1432,16 @@ typedef struct MinMaxAggInfo
14321432
*
14331433
* Each paramlist item shows the absolute query level it is associated with,
14341434
* where the outermost query is level 1 and nested subqueries have higher
1435-
* numbers. The item the parameter slot represents can be one ofthree kinds:
1435+
* numbers. The item the parameter slot represents can be one offour kinds:
14361436
*
14371437
* A Var: the slot represents a variable of that level that must be passed
14381438
* down because subqueries have outer references to it, or must be passed
14391439
* from a NestLoop node of that level to its inner scan. The varlevelsup
14401440
* value in the Var will always be zero.
14411441
*
1442+
* A PlaceHolderVar: this works much like the Var case. It is currently
1443+
* only needed for NestLoop parameters, not outer references.
1444+
*
14421445
* An Aggref (with an expression tree representing its argument): the slot
14431446
* represents an aggregate expression that is an outer reference for some
14441447
* subquery. The Aggref itself has agglevelsup = 0, and its argument tree
@@ -1448,20 +1451,20 @@ typedef struct MinMaxAggInfo
14481451
* for that subplan). The absolute level shown for such items corresponds
14491452
* to the parent query of the subplan.
14501453
*
1451-
* Note: we detect duplicate Varparametersandcoalesce them into one slot,
1452-
* but we do not bother to do this for Aggrefs, and it would be incorrect
1453-
* to do so for Param slots. Duplicate detection is actually *necessary*
1454-
*in the case ofNestLoop parameters since it serves to match up the usage
1455-
* of a Param (in the inner scan) with the assignment of the value (in the
1456-
* NestLoop node).This might result in the same PARAM_EXEC slot being used
1457-
* by multiple NestLoop nodes or SubPlan nodes, but no harm is done since
1454+
* Note: we detect duplicate Var andPlaceHolderVar parameters and coalesce
1455+
*them into one slot,but we do not bother to do this for Aggrefs, and it
1456+
*would be incorrectto do so for Param slots. Duplicate detection is
1457+
*actually *necessary* forNestLoop parameters since it serves to match up
1458+
*the usageof a Param (in the inner scan) with the assignment of the value
1459+
*(in theNestLoop node).This might result in the same PARAM_EXEC slot being
1460+
*usedby multiple NestLoop nodes or SubPlan nodes, but no harm is done since
14581461
* the same value would be assigned anyway.
14591462
*/
14601463
typedefstructPlannerParamItem
14611464
{
14621465
NodeTagtype;
14631466

1464-
Node*item;/* the Var, Aggref, or Param */
1467+
Node*item;/* the Var,PlaceHolderVar,Aggref, or Param */
14651468
Indexabslevel;/* its absolute query level */
14661469
}PlannerParamItem;
14671470

‎src/include/optimizer/subselect.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ extern void SS_finalize_plan(PlannerInfo *root, Plan *plan,
2929
boolattach_initplans);
3030
externParam*SS_make_initplan_from_plan(PlannerInfo*root,Plan*plan,
3131
Oidresulttype,int32resulttypmod,Oidresultcollation);
32-
externParam*assign_nestloop_param(PlannerInfo*root,Var*var);
32+
externParam*assign_nestloop_param_var(PlannerInfo*root,Var*var);
33+
externParam*assign_nestloop_param_placeholdervar(PlannerInfo*root,
34+
PlaceHolderVar*phv);
3335
externintSS_assign_special_param(PlannerInfo*root);
3436

3537
#endif/* SUBSELECT_H */

‎src/test/regress/expected/join.out

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2129,6 +2129,7 @@ on (x1 = xx1) where (xx2 is not null);
21292129
-- regression test: check for bug with propagation of implied equality
21302130
-- to outside an IN
21312131
--
2132+
analyze tenk1;-- ensure we get consistent plans here
21322133
select count(*) from tenk1 a where unique1 in
21332134
(select unique1 from tenk1 b join tenk1 c using (unique1)
21342135
where b.unique2 = 42);
@@ -2533,6 +2534,43 @@ ON sub1.key1 = sub2.key3;
25332534
1 | 1 | 1 | 1
25342535
(1 row)
25352536

2537+
--
2538+
-- test case where a PlaceHolderVar is used as a nestloop parameter
2539+
--
2540+
EXPLAIN (COSTS OFF)
2541+
SELECT qq, unique1
2542+
FROM
2543+
( SELECT COALESCE(q1, 0) AS qq FROM int8_tbl a ) AS ss1
2544+
FULL OUTER JOIN
2545+
( SELECT COALESCE(q2, -1) AS qq FROM int8_tbl b ) AS ss2
2546+
USING (qq)
2547+
INNER JOIN tenk1 c ON qq = unique2;
2548+
QUERY PLAN
2549+
-------------------------------------------------------------------------------------------------------
2550+
Nested Loop
2551+
-> Hash Full Join
2552+
Hash Cond: (COALESCE(a.q1, 0::bigint) = COALESCE(b.q2, (-1)::bigint))
2553+
-> Seq Scan on int8_tbl a
2554+
-> Hash
2555+
-> Seq Scan on int8_tbl b
2556+
-> Index Scan using tenk1_unique2 on tenk1 c
2557+
Index Cond: (unique2 = COALESCE((COALESCE(a.q1, 0::bigint)), (COALESCE(b.q2, (-1)::bigint))))
2558+
(8 rows)
2559+
2560+
SELECT qq, unique1
2561+
FROM
2562+
( SELECT COALESCE(q1, 0) AS qq FROM int8_tbl a ) AS ss1
2563+
FULL OUTER JOIN
2564+
( SELECT COALESCE(q2, -1) AS qq FROM int8_tbl b ) AS ss2
2565+
USING (qq)
2566+
INNER JOIN tenk1 c ON qq = unique2;
2567+
qq | unique1
2568+
-----+---------
2569+
123 | 4596
2570+
123 | 4596
2571+
456 | 7318
2572+
(3 rows)
2573+
25362574
--
25372575
-- test the corner cases FULL JOIN ON TRUE and FULL JOIN ON FALSE
25382576
--

‎src/test/regress/sql/join.sql

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,8 @@ on (x1 = xx1) where (xx2 is not null);
330330
-- regression test: check for bug with propagation of implied equality
331331
-- to outside an IN
332332
--
333+
analyze tenk1;-- ensure we get consistent plans here
334+
333335
selectcount(*)from tenk1 awhere unique1in
334336
(select unique1from tenk1 bjoin tenk1 c using (unique1)
335337
whereb.unique2=42);
@@ -639,6 +641,27 @@ LEFT JOIN
639641
) sub2
640642
ONsub1.key1=sub2.key3;
641643

644+
--
645+
-- test case where a PlaceHolderVar is used as a nestloop parameter
646+
--
647+
648+
EXPLAIN (COSTS OFF)
649+
SELECT qq, unique1
650+
FROM
651+
(SELECT COALESCE(q1,0)AS qqFROM int8_tbl a )AS ss1
652+
FULL OUTERJOIN
653+
(SELECT COALESCE(q2,-1)AS qqFROM int8_tbl b )AS ss2
654+
USING (qq)
655+
INNER JOIN tenk1 cON qq= unique2;
656+
657+
SELECT qq, unique1
658+
FROM
659+
(SELECT COALESCE(q1,0)AS qqFROM int8_tbl a )AS ss1
660+
FULL OUTERJOIN
661+
(SELECT COALESCE(q2,-1)AS qqFROM int8_tbl b )AS ss2
662+
USING (qq)
663+
INNER JOIN tenk1 cON qq= unique2;
664+
642665
--
643666
-- test the corner cases FULL JOIN ON TRUE and FULL JOIN ON FALSE
644667
--

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp