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

Commit9ff79b9

Browse files
committed
Fix up planner infrastructure to support LATERAL properly.
This patch takes care of a number of problems having to do with failureto choose valid join orders and incorrect handling of lateral referencespulled up from subqueries. Notable changes:* Add a LateralJoinInfo data structure similar to SpecialJoinInfo, torepresent join ordering constraints created by lateral references.(I first considered extending the SpecialJoinInfo structure, but thesemantics are different enough that a separate data structure seemsbetter.) Extend join_is_legal() and related functions to prevent tryingto form unworkable joins, and to ensure that we will consider joins thatsatisfy lateral references even if the joins would be clauseless.* Fill in the infrastructure needed for the last few types of relation scanpaths to support parameterization. We'd have wanted this eventuallyanyway, but it is necessary now because a relation that gets pulled up outof a UNION ALL subquery may acquire a reltargetlist containing lateralreferences, meaning that its paths *have* to be parameterized whether ornot we have any code that can push join quals down into the scan.* Compute data about lateral references early in query_planner(), and savein RelOptInfo nodes, to avoid repetitive calculations later.* Assorted corner-case bug fixes.There's probably still some bugs left, but this is a lot closer to beingreal than it was before.
1 parentde87d47 commit9ff79b9

30 files changed

+817
-182
lines changed

‎src/backend/nodes/copyfuncs.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,6 +1906,20 @@ _copySpecialJoinInfo(const SpecialJoinInfo *from)
19061906
returnnewnode;
19071907
}
19081908

1909+
/*
1910+
* _copyLateralJoinInfo
1911+
*/
1912+
staticLateralJoinInfo*
1913+
_copyLateralJoinInfo(constLateralJoinInfo*from)
1914+
{
1915+
LateralJoinInfo*newnode=makeNode(LateralJoinInfo);
1916+
1917+
COPY_SCALAR_FIELD(lateral_rhs);
1918+
COPY_BITMAPSET_FIELD(lateral_lhs);
1919+
1920+
returnnewnode;
1921+
}
1922+
19091923
/*
19101924
* _copyAppendRelInfo
19111925
*/
@@ -4082,6 +4096,9 @@ copyObject(const void *from)
40824096
caseT_SpecialJoinInfo:
40834097
retval=_copySpecialJoinInfo(from);
40844098
break;
4099+
caseT_LateralJoinInfo:
4100+
retval=_copyLateralJoinInfo(from);
4101+
break;
40854102
caseT_AppendRelInfo:
40864103
retval=_copyAppendRelInfo(from);
40874104
break;

‎src/backend/nodes/equalfuncs.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,15 @@ _equalSpecialJoinInfo(const SpecialJoinInfo *a, const SpecialJoinInfo *b)
862862
return true;
863863
}
864864

865+
staticbool
866+
_equalLateralJoinInfo(constLateralJoinInfo*a,constLateralJoinInfo*b)
867+
{
868+
COMPARE_SCALAR_FIELD(lateral_rhs);
869+
COMPARE_BITMAPSET_FIELD(lateral_lhs);
870+
871+
return true;
872+
}
873+
865874
staticbool
866875
_equalAppendRelInfo(constAppendRelInfo*a,constAppendRelInfo*b)
867876
{
@@ -2646,6 +2655,9 @@ equal(const void *a, const void *b)
26462655
caseT_SpecialJoinInfo:
26472656
retval=_equalSpecialJoinInfo(a,b);
26482657
break;
2658+
caseT_LateralJoinInfo:
2659+
retval=_equalLateralJoinInfo(a,b);
2660+
break;
26492661
caseT_AppendRelInfo:
26502662
retval=_equalAppendRelInfo(a,b);
26512663
break;

‎src/backend/nodes/outfuncs.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,6 +1699,7 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node)
16991699
WRITE_NODE_FIELD(right_join_clauses);
17001700
WRITE_NODE_FIELD(full_join_clauses);
17011701
WRITE_NODE_FIELD(join_info_list);
1702+
WRITE_NODE_FIELD(lateral_info_list);
17021703
WRITE_NODE_FIELD(append_rel_list);
17031704
WRITE_NODE_FIELD(rowMarks);
17041705
WRITE_NODE_FIELD(placeholder_list);
@@ -1713,6 +1714,7 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node)
17131714
WRITE_FLOAT_FIELD(limit_tuples,"%.0f");
17141715
WRITE_BOOL_FIELD(hasInheritedTarget);
17151716
WRITE_BOOL_FIELD(hasJoinRTEs);
1717+
WRITE_BOOL_FIELD(hasLateralRTEs);
17161718
WRITE_BOOL_FIELD(hasHavingQual);
17171719
WRITE_BOOL_FIELD(hasPseudoConstantQuals);
17181720
WRITE_BOOL_FIELD(hasRecursion);
@@ -1743,6 +1745,8 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node)
17431745
WRITE_ENUM_FIELD(rtekind,RTEKind);
17441746
WRITE_INT_FIELD(min_attr);
17451747
WRITE_INT_FIELD(max_attr);
1748+
WRITE_NODE_FIELD(lateral_vars);
1749+
WRITE_BITMAPSET_FIELD(lateral_relids);
17461750
WRITE_NODE_FIELD(indexlist);
17471751
WRITE_UINT_FIELD(pages);
17481752
WRITE_FLOAT_FIELD(tuples,"%.0f");
@@ -1890,6 +1894,15 @@ _outSpecialJoinInfo(StringInfo str, const SpecialJoinInfo *node)
18901894
WRITE_NODE_FIELD(join_quals);
18911895
}
18921896

1897+
staticvoid
1898+
_outLateralJoinInfo(StringInfostr,constLateralJoinInfo*node)
1899+
{
1900+
WRITE_NODE_TYPE("LATERALJOININFO");
1901+
1902+
WRITE_UINT_FIELD(lateral_rhs);
1903+
WRITE_BITMAPSET_FIELD(lateral_lhs);
1904+
}
1905+
18931906
staticvoid
18941907
_outAppendRelInfo(StringInfostr,constAppendRelInfo*node)
18951908
{
@@ -3036,6 +3049,9 @@ _outNode(StringInfo str, const void *obj)
30363049
caseT_SpecialJoinInfo:
30373050
_outSpecialJoinInfo(str,obj);
30383051
break;
3052+
caseT_LateralJoinInfo:
3053+
_outLateralJoinInfo(str,obj);
3054+
break;
30393055
caseT_AppendRelInfo:
30403056
_outAppendRelInfo(str,obj);
30413057
break;

‎src/backend/optimizer/path/allpaths.c

Lines changed: 55 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,9 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
268268
caseRTE_CTE:
269269

270270
/*
271-
* CTEs don't support parameterized paths, so just go ahead
272-
* and build their paths immediately.
271+
* CTEs don't support making a choice between parameterized
272+
* and unparameterized paths, so just go ahead and build their
273+
* paths immediately.
273274
*/
274275
if (rte->self_reference)
275276
set_worktable_pathlist(root,rel,rte);
@@ -376,8 +377,18 @@ set_plain_rel_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
376377
staticvoid
377378
set_plain_rel_pathlist(PlannerInfo*root,RelOptInfo*rel,RangeTblEntry*rte)
378379
{
380+
Relidsrequired_outer;
381+
382+
/*
383+
* We don't support pushing join clauses into the quals of a seqscan, but
384+
* it could still have required parameterization due to LATERAL refs in
385+
* its tlist. (That can only happen if the seqscan is on a relation
386+
* pulled up out of a UNION ALL appendrel.)
387+
*/
388+
required_outer=rel->lateral_relids;
389+
379390
/* Consider sequential scan */
380-
add_path(rel,create_seqscan_path(root,rel,NULL));
391+
add_path(rel,create_seqscan_path(root,rel,required_outer));
381392

382393
/* Consider index scans */
383394
create_index_paths(root,rel);
@@ -536,10 +547,10 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
536547
* CE failed, so finish copying/modifying targetlist and join quals.
537548
*
538549
* Note: the resulting childrel->reltargetlist may contain arbitrary
539-
* expressions, whichnormally would not occur in a reltargetlist.
540-
*That is okay because nothing outside of this routine will look at
541-
*the child rel's reltargetlist.We do have to cope with the case
542-
*while constructing attr_widths estimates below, though.
550+
* expressions, whichotherwise would not occur in a reltargetlist.
551+
*Code that might be looking at an appendrel child must cope with
552+
*such.Note in particular that "arbitrary expression" can include
553+
*"Var belonging to another relation", due to LATERAL references.
543554
*/
544555
childrel->joininfo= (List*)
545556
adjust_appendrel_attrs(root,
@@ -610,7 +621,8 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
610621
intpndx=parentvar->varattno-rel->min_attr;
611622
int32child_width=0;
612623

613-
if (IsA(childvar,Var))
624+
if (IsA(childvar,Var)&&
625+
((Var*)childvar)->varno==childrel->relid)
614626
{
615627
intcndx= ((Var*)childvar)->varattno-childrel->min_attr;
616628

@@ -1054,17 +1066,10 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
10541066

10551067
/*
10561068
* If it's a LATERAL subquery, it might contain some Vars of the current
1057-
* query level, requiring it to be treated as parameterized.
1069+
* query level, requiring it to be treated as parameterized, even though
1070+
* we don't support pushing down join quals into subqueries.
10581071
*/
1059-
if (rte->lateral)
1060-
{
1061-
required_outer=pull_varnos_of_level((Node*)subquery,1);
1062-
/* Enforce convention that empty required_outer is exactly NULL */
1063-
if (bms_is_empty(required_outer))
1064-
required_outer=NULL;
1065-
}
1066-
else
1067-
required_outer=NULL;
1072+
required_outer=rel->lateral_relids;
10681073

10691074
/* We need a workspace for keeping track of set-op type coercions */
10701075
differentTypes= (bool*)
@@ -1175,29 +1180,18 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
11751180
/*
11761181
* set_function_pathlist
11771182
*Build the (single) access path for a function RTE
1178-
*
1179-
* As with subqueries, a function RTE's path might be parameterized due to
1180-
* LATERAL references, but that's inherent in the function expression and
1181-
* not a result of pushing down join quals.
11821183
*/
11831184
staticvoid
11841185
set_function_pathlist(PlannerInfo*root,RelOptInfo*rel,RangeTblEntry*rte)
11851186
{
11861187
Relidsrequired_outer;
11871188

11881189
/*
1189-
* If it's a LATERAL function, it might contain some Vars of the current
1190-
* query level, requiring it to be treated as parameterized.
1190+
* We don't support pushing join clauses into the quals of a function
1191+
* scan, but it could still have required parameterization due to LATERAL
1192+
* refs in the function expression.
11911193
*/
1192-
if (rte->lateral)
1193-
{
1194-
required_outer=pull_varnos_of_level(rte->funcexpr,0);
1195-
/* Enforce convention that empty required_outer is exactly NULL */
1196-
if (bms_is_empty(required_outer))
1197-
required_outer=NULL;
1198-
}
1199-
else
1200-
required_outer=NULL;
1194+
required_outer=rel->lateral_relids;
12011195

12021196
/* Generate appropriate path */
12031197
add_path(rel,create_functionscan_path(root,rel,required_outer));
@@ -1209,29 +1203,18 @@ set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
12091203
/*
12101204
* set_values_pathlist
12111205
*Build the (single) access path for a VALUES RTE
1212-
*
1213-
* As with subqueries, a VALUES RTE's path might be parameterized due to
1214-
* LATERAL references, but that's inherent in the values expressions and
1215-
* not a result of pushing down join quals.
12161206
*/
12171207
staticvoid
12181208
set_values_pathlist(PlannerInfo*root,RelOptInfo*rel,RangeTblEntry*rte)
12191209
{
12201210
Relidsrequired_outer;
12211211

12221212
/*
1223-
* If it's a LATERAL RTE, it might contain some Vars of the current query
1224-
* level, requiring it to be treated as parameterized.
1213+
* We don't support pushing join clauses into the quals of a values scan,
1214+
* but it could still have required parameterization due to LATERAL refs
1215+
* in the values expressions.
12251216
*/
1226-
if (rte->lateral)
1227-
{
1228-
required_outer=pull_varnos_of_level((Node*)rte->values_lists,0);
1229-
/* Enforce convention that empty required_outer is exactly NULL */
1230-
if (bms_is_empty(required_outer))
1231-
required_outer=NULL;
1232-
}
1233-
else
1234-
required_outer=NULL;
1217+
required_outer=rel->lateral_relids;
12351218

12361219
/* Generate appropriate path */
12371220
add_path(rel,create_valuesscan_path(root,rel,required_outer));
@@ -1245,7 +1228,7 @@ set_values_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
12451228
*Build the (single) access path for a non-self-reference CTE RTE
12461229
*
12471230
* There's no need for a separate set_cte_size phase, since we don't
1248-
* support parameterized paths for CTEs.
1231+
* supportjoin-qual-parameterized paths for CTEs.
12491232
*/
12501233
staticvoid
12511234
set_cte_pathlist(PlannerInfo*root,RelOptInfo*rel,RangeTblEntry*rte)
@@ -1256,6 +1239,7 @@ set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
12561239
intndx;
12571240
ListCell*lc;
12581241
intplan_id;
1242+
Relidsrequired_outer;
12591243

12601244
/*
12611245
* Find the referenced CTE, and locate the plan previously made for it.
@@ -1294,8 +1278,16 @@ set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
12941278
/* Mark rel with estimated output rows, width, etc */
12951279
set_cte_size_estimates(root,rel,cteplan);
12961280

1281+
/*
1282+
* We don't support pushing join clauses into the quals of a CTE scan, but
1283+
* it could still have required parameterization due to LATERAL refs in
1284+
* its tlist. (That can only happen if the CTE scan is on a relation
1285+
* pulled up out of a UNION ALL appendrel.)
1286+
*/
1287+
required_outer=rel->lateral_relids;
1288+
12971289
/* Generate appropriate path */
1298-
add_path(rel,create_ctescan_path(root,rel));
1290+
add_path(rel,create_ctescan_path(root,rel,required_outer));
12991291

13001292
/* Select cheapest path (pretty easy in this case...) */
13011293
set_cheapest(rel);
@@ -1306,14 +1298,15 @@ set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
13061298
*Build the (single) access path for a self-reference CTE RTE
13071299
*
13081300
* There's no need for a separate set_worktable_size phase, since we don't
1309-
* support parameterized paths for CTEs.
1301+
* supportjoin-qual-parameterized paths for CTEs.
13101302
*/
13111303
staticvoid
13121304
set_worktable_pathlist(PlannerInfo*root,RelOptInfo*rel,RangeTblEntry*rte)
13131305
{
13141306
Plan*cteplan;
13151307
PlannerInfo*cteroot;
13161308
Indexlevelsup;
1309+
Relidsrequired_outer;
13171310

13181311
/*
13191312
* We need to find the non-recursive term's plan, which is in the plan
@@ -1338,8 +1331,18 @@ set_worktable_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
13381331
/* Mark rel with estimated output rows, width, etc */
13391332
set_cte_size_estimates(root,rel,cteplan);
13401333

1334+
/*
1335+
* We don't support pushing join clauses into the quals of a worktable
1336+
* scan, but it could still have required parameterization due to LATERAL
1337+
* refs in its tlist. (That can only happen if the worktable scan is on a
1338+
* relation pulled up out of a UNION ALL appendrel. I'm not sure this is
1339+
* actually possible given the restrictions on recursive references, but
1340+
* it's easy enough to support.)
1341+
*/
1342+
required_outer=rel->lateral_relids;
1343+
13411344
/* Generate appropriate path */
1342-
add_path(rel,create_worktablescan_path(root,rel));
1345+
add_path(rel,create_worktablescan_path(root,rel,required_outer));
13431346

13441347
/* Select cheapest path (pretty easy in this case...) */
13451348
set_cheapest(rel);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp