Skip to content

Commit dc45188

Browse files
committed
Get rid of the planner's LateralJoinInfo data structure.
I originally modeled this data structure on SpecialJoinInfo, but after commit acfcd45 that looks like a pretty poor decision. All we really need is relid sets identifying laterally-referenced rels; and most of the time, what we want to know about includes indirect lateral references, a case the LateralJoinInfo data was unsuited to compute with any efficiency. The previous commit redefined RelOptInfo.lateral_relids as the transitive closure of lateral references, so that it easily supports checking indirect references. For the places where we really do want just direct references, add a new RelOptInfo field direct_lateral_relids, which is easily set up as a copy of lateral_relids before we perform the transitive closure calculation. Then we can just drop lateral_info_list and LateralJoinInfo and the supporting code. This makes the planner's handling of lateral references noticeably more efficient, and shorter too. Such a change can't be back-patched into stable branches for fear of breaking extensions that might be looking at the planner's data structures; but it seems not too late to push it into 9.5, so I've done so.
1 parent 12a54c8 commit dc45188

File tree

17 files changed

+100
-289
lines changed

17 files changed

+100
-289
lines changed

src/backend/nodes/copyfuncs.c

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,20 +2041,6 @@ _copySpecialJoinInfo(const SpecialJoinInfo *from)
20412041
return newnode;
20422042
}
20432043

2044-
/*
2045-
* _copyLateralJoinInfo
2046-
*/
2047-
static LateralJoinInfo *
2048-
_copyLateralJoinInfo(const LateralJoinInfo *from)
2049-
{
2050-
LateralJoinInfo *newnode = makeNode(LateralJoinInfo);
2051-
2052-
COPY_BITMAPSET_FIELD(lateral_lhs);
2053-
COPY_BITMAPSET_FIELD(lateral_rhs);
2054-
2055-
return newnode;
2056-
}
2057-
20582044
/*
20592045
* _copyAppendRelInfo
20602046
*/
@@ -4479,9 +4465,6 @@ copyObject(const void *from)
44794465
case T_SpecialJoinInfo:
44804466
retval = _copySpecialJoinInfo(from);
44814467
break;
4482-
case T_LateralJoinInfo:
4483-
retval = _copyLateralJoinInfo(from);
4484-
break;
44854468
case T_AppendRelInfo:
44864469
retval = _copyAppendRelInfo(from);
44874470
break;

src/backend/nodes/equalfuncs.c

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -845,15 +845,6 @@ _equalSpecialJoinInfo(const SpecialJoinInfo *a, const SpecialJoinInfo *b)
845845
return true;
846846
}
847847

848-
static bool
849-
_equalLateralJoinInfo(const LateralJoinInfo *a, const LateralJoinInfo *b)
850-
{
851-
COMPARE_BITMAPSET_FIELD(lateral_lhs);
852-
COMPARE_BITMAPSET_FIELD(lateral_rhs);
853-
854-
return true;
855-
}
856-
857848
static bool
858849
_equalAppendRelInfo(const AppendRelInfo *a, const AppendRelInfo *b)
859850
{
@@ -2850,9 +2841,6 @@ equal(const void *a, const void *b)
28502841
case T_SpecialJoinInfo:
28512842
retval = _equalSpecialJoinInfo(a, b);
28522843
break;
2853-
case T_LateralJoinInfo:
2854-
retval = _equalLateralJoinInfo(a, b);
2855-
break;
28562844
case T_AppendRelInfo:
28572845
retval = _equalAppendRelInfo(a, b);
28582846
break;

src/backend/nodes/outfuncs.c

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1814,7 +1814,6 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node)
18141814
WRITE_NODE_FIELD(right_join_clauses);
18151815
WRITE_NODE_FIELD(full_join_clauses);
18161816
WRITE_NODE_FIELD(join_info_list);
1817-
WRITE_NODE_FIELD(lateral_info_list);
18181817
WRITE_NODE_FIELD(append_rel_list);
18191818
WRITE_NODE_FIELD(rowMarks);
18201819
WRITE_NODE_FIELD(placeholder_list);
@@ -1858,6 +1857,7 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node)
18581857
WRITE_NODE_FIELD(cheapest_total_path);
18591858
WRITE_NODE_FIELD(cheapest_unique_path);
18601859
WRITE_NODE_FIELD(cheapest_parameterized_paths);
1860+
WRITE_BITMAPSET_FIELD(direct_lateral_relids);
18611861
WRITE_BITMAPSET_FIELD(lateral_relids);
18621862
WRITE_UINT_FIELD(relid);
18631863
WRITE_OID_FIELD(reltablespace);
@@ -2022,15 +2022,6 @@ _outSpecialJoinInfo(StringInfo str, const SpecialJoinInfo *node)
20222022
WRITE_NODE_FIELD(semi_rhs_exprs);
20232023
}
20242024

2025-
static void
2026-
_outLateralJoinInfo(StringInfo str, const LateralJoinInfo *node)
2027-
{
2028-
WRITE_NODE_TYPE("LATERALJOININFO");
2029-
2030-
WRITE_BITMAPSET_FIELD(lateral_lhs);
2031-
WRITE_BITMAPSET_FIELD(lateral_rhs);
2032-
}
2033-
20342025
static void
20352026
_outAppendRelInfo(StringInfo str, const AppendRelInfo *node)
20362027
{
@@ -3315,9 +3306,6 @@ _outNode(StringInfo str, const void *obj)
33153306
case T_SpecialJoinInfo:
33163307
_outSpecialJoinInfo(str, obj);
33173308
break;
3318-
case T_LateralJoinInfo:
3319-
_outLateralJoinInfo(str, obj);
3320-
break;
33213309
case T_AppendRelInfo:
33223310
_outAppendRelInfo(str, obj);
33233311
break;

src/backend/optimizer/path/joinrels.c

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ join_search_one_level(PlannerInfo *root, int level)
231231
*/
232232
if (joinrels[level] == NIL &&
233233
root->join_info_list == NIL &&
234-
root->lateral_info_list == NIL)
234+
!root->hasLateralRTEs)
235235
elog(ERROR, "failed to build any %d-way joins", level);
236236
}
237237
}
@@ -559,15 +559,7 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
559559
match_sjinfo->jointype == JOIN_FULL))
560560
return false; /* not implementable as nestloop */
561561
/* check there is a direct reference from rel2 to rel1 */
562-
foreach(l, root->lateral_info_list)
563-
{
564-
LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(l);
565-
566-
if (bms_is_subset(ljinfo->lateral_rhs, rel2->relids) &&
567-
bms_is_subset(ljinfo->lateral_lhs, rel1->relids))
568-
break;
569-
}
570-
if (l == NULL)
562+
if (!bms_overlap(rel1->relids, rel2->direct_lateral_relids))
571563
return false; /* only indirect refs, so reject */
572564
/* check we won't have a dangerous PHV */
573565
if (have_dangerous_phv(root, rel1->relids, rel2->lateral_relids))
@@ -582,15 +574,7 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
582574
match_sjinfo->jointype == JOIN_FULL))
583575
return false; /* not implementable as nestloop */
584576
/* check there is a direct reference from rel1 to rel2 */
585-
foreach(l, root->lateral_info_list)
586-
{
587-
LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(l);
588-
589-
if (bms_is_subset(ljinfo->lateral_rhs, rel1->relids) &&
590-
bms_is_subset(ljinfo->lateral_lhs, rel2->relids))
591-
break;
592-
}
593-
if (l == NULL)
577+
if (!bms_overlap(rel2->relids, rel1->direct_lateral_relids))
594578
return false; /* only indirect refs, so reject */
595579
/* check we won't have a dangerous PHV */
596580
if (have_dangerous_phv(root, rel2->relids, rel1->lateral_relids))
@@ -922,17 +906,9 @@ have_join_order_restriction(PlannerInfo *root,
922906
* If either side has a direct lateral reference to the other, attempt the
923907
* join regardless of outer-join considerations.
924908
*/
925-
foreach(l, root->lateral_info_list)
926-
{
927-
LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(l);
928-
929-
if (bms_is_subset(ljinfo->lateral_rhs, rel2->relids) &&
930-
bms_overlap(ljinfo->lateral_lhs, rel1->relids))
931-
return true;
932-
if (bms_is_subset(ljinfo->lateral_rhs, rel1->relids) &&
933-
bms_overlap(ljinfo->lateral_lhs, rel2->relids))
934-
return true;
935-
}
909+
if (bms_overlap(rel1->relids, rel2->direct_lateral_relids) ||
910+
bms_overlap(rel2->relids, rel1->direct_lateral_relids))
911+
return true;
936912

937913
/*
938914
* Likewise, if both rels are needed to compute some PlaceHolderVar,

src/backend/optimizer/plan/analyzejoins.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -439,9 +439,6 @@ remove_rel_from_query(PlannerInfo *root, int relid, Relids joinrelids)
439439
sjinfo->syn_righthand = bms_del_member(sjinfo->syn_righthand, relid);
440440
}
441441

442-
/* There shouldn't be any LATERAL info to translate, as yet */
443-
Assert(root->lateral_info_list == NIL);
444-
445442
/*
446443
* Likewise remove references from PlaceHolderVar data structures,
447444
* removing any no-longer-needed placeholders entirely.

0 commit comments

Comments
 (0)