Commit 4fcf4845 authored by Tom Lane's avatar Tom Lane

Get rid of the planner's LateralJoinInfo data structure.

I originally modeled this data structure on SpecialJoinInfo, but after
commit acfcd45c 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.
parent ed8bec91
...@@ -2066,20 +2066,6 @@ _copySpecialJoinInfo(const SpecialJoinInfo *from) ...@@ -2066,20 +2066,6 @@ _copySpecialJoinInfo(const SpecialJoinInfo *from)
return newnode; return newnode;
} }
/*
* _copyLateralJoinInfo
*/
static LateralJoinInfo *
_copyLateralJoinInfo(const LateralJoinInfo *from)
{
LateralJoinInfo *newnode = makeNode(LateralJoinInfo);
COPY_BITMAPSET_FIELD(lateral_lhs);
COPY_BITMAPSET_FIELD(lateral_rhs);
return newnode;
}
/* /*
* _copyAppendRelInfo * _copyAppendRelInfo
*/ */
...@@ -4519,9 +4505,6 @@ copyObject(const void *from) ...@@ -4519,9 +4505,6 @@ copyObject(const void *from)
case T_SpecialJoinInfo: case T_SpecialJoinInfo:
retval = _copySpecialJoinInfo(from); retval = _copySpecialJoinInfo(from);
break; break;
case T_LateralJoinInfo:
retval = _copyLateralJoinInfo(from);
break;
case T_AppendRelInfo: case T_AppendRelInfo:
retval = _copyAppendRelInfo(from); retval = _copyAppendRelInfo(from);
break; break;
......
...@@ -845,15 +845,6 @@ _equalSpecialJoinInfo(const SpecialJoinInfo *a, const SpecialJoinInfo *b) ...@@ -845,15 +845,6 @@ _equalSpecialJoinInfo(const SpecialJoinInfo *a, const SpecialJoinInfo *b)
return true; return true;
} }
static bool
_equalLateralJoinInfo(const LateralJoinInfo *a, const LateralJoinInfo *b)
{
COMPARE_BITMAPSET_FIELD(lateral_lhs);
COMPARE_BITMAPSET_FIELD(lateral_rhs);
return true;
}
static bool static bool
_equalAppendRelInfo(const AppendRelInfo *a, const AppendRelInfo *b) _equalAppendRelInfo(const AppendRelInfo *a, const AppendRelInfo *b)
{ {
...@@ -2860,9 +2851,6 @@ equal(const void *a, const void *b) ...@@ -2860,9 +2851,6 @@ equal(const void *a, const void *b)
case T_SpecialJoinInfo: case T_SpecialJoinInfo:
retval = _equalSpecialJoinInfo(a, b); retval = _equalSpecialJoinInfo(a, b);
break; break;
case T_LateralJoinInfo:
retval = _equalLateralJoinInfo(a, b);
break;
case T_AppendRelInfo: case T_AppendRelInfo:
retval = _equalAppendRelInfo(a, b); retval = _equalAppendRelInfo(a, b);
break; break;
......
...@@ -1847,7 +1847,6 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node) ...@@ -1847,7 +1847,6 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node)
WRITE_NODE_FIELD(right_join_clauses); WRITE_NODE_FIELD(right_join_clauses);
WRITE_NODE_FIELD(full_join_clauses); WRITE_NODE_FIELD(full_join_clauses);
WRITE_NODE_FIELD(join_info_list); WRITE_NODE_FIELD(join_info_list);
WRITE_NODE_FIELD(lateral_info_list);
WRITE_NODE_FIELD(append_rel_list); WRITE_NODE_FIELD(append_rel_list);
WRITE_NODE_FIELD(rowMarks); WRITE_NODE_FIELD(rowMarks);
WRITE_NODE_FIELD(placeholder_list); WRITE_NODE_FIELD(placeholder_list);
...@@ -1892,6 +1891,7 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node) ...@@ -1892,6 +1891,7 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node)
WRITE_NODE_FIELD(cheapest_total_path); WRITE_NODE_FIELD(cheapest_total_path);
WRITE_NODE_FIELD(cheapest_unique_path); WRITE_NODE_FIELD(cheapest_unique_path);
WRITE_NODE_FIELD(cheapest_parameterized_paths); WRITE_NODE_FIELD(cheapest_parameterized_paths);
WRITE_BITMAPSET_FIELD(direct_lateral_relids);
WRITE_BITMAPSET_FIELD(lateral_relids); WRITE_BITMAPSET_FIELD(lateral_relids);
WRITE_UINT_FIELD(relid); WRITE_UINT_FIELD(relid);
WRITE_OID_FIELD(reltablespace); WRITE_OID_FIELD(reltablespace);
...@@ -2056,15 +2056,6 @@ _outSpecialJoinInfo(StringInfo str, const SpecialJoinInfo *node) ...@@ -2056,15 +2056,6 @@ _outSpecialJoinInfo(StringInfo str, const SpecialJoinInfo *node)
WRITE_NODE_FIELD(semi_rhs_exprs); WRITE_NODE_FIELD(semi_rhs_exprs);
} }
static void
_outLateralJoinInfo(StringInfo str, const LateralJoinInfo *node)
{
WRITE_NODE_TYPE("LATERALJOININFO");
WRITE_BITMAPSET_FIELD(lateral_lhs);
WRITE_BITMAPSET_FIELD(lateral_rhs);
}
static void static void
_outAppendRelInfo(StringInfo str, const AppendRelInfo *node) _outAppendRelInfo(StringInfo str, const AppendRelInfo *node)
{ {
...@@ -3355,9 +3346,6 @@ _outNode(StringInfo str, const void *obj) ...@@ -3355,9 +3346,6 @@ _outNode(StringInfo str, const void *obj)
case T_SpecialJoinInfo: case T_SpecialJoinInfo:
_outSpecialJoinInfo(str, obj); _outSpecialJoinInfo(str, obj);
break; break;
case T_LateralJoinInfo:
_outLateralJoinInfo(str, obj);
break;
case T_AppendRelInfo: case T_AppendRelInfo:
_outAppendRelInfo(str, obj); _outAppendRelInfo(str, obj);
break; break;
......
...@@ -231,7 +231,7 @@ join_search_one_level(PlannerInfo *root, int level) ...@@ -231,7 +231,7 @@ join_search_one_level(PlannerInfo *root, int level)
*/ */
if (joinrels[level] == NIL && if (joinrels[level] == NIL &&
root->join_info_list == NIL && root->join_info_list == NIL &&
root->lateral_info_list == NIL) !root->hasLateralRTEs)
elog(ERROR, "failed to build any %d-way joins", level); elog(ERROR, "failed to build any %d-way joins", level);
} }
} }
...@@ -559,15 +559,7 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2, ...@@ -559,15 +559,7 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
match_sjinfo->jointype == JOIN_FULL)) match_sjinfo->jointype == JOIN_FULL))
return false; /* not implementable as nestloop */ return false; /* not implementable as nestloop */
/* check there is a direct reference from rel2 to rel1 */ /* check there is a direct reference from rel2 to rel1 */
foreach(l, root->lateral_info_list) if (!bms_overlap(rel1->relids, rel2->direct_lateral_relids))
{
LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(l);
if (bms_is_subset(ljinfo->lateral_rhs, rel2->relids) &&
bms_is_subset(ljinfo->lateral_lhs, rel1->relids))
break;
}
if (l == NULL)
return false; /* only indirect refs, so reject */ return false; /* only indirect refs, so reject */
/* check we won't have a dangerous PHV */ /* check we won't have a dangerous PHV */
if (have_dangerous_phv(root, rel1->relids, rel2->lateral_relids)) if (have_dangerous_phv(root, rel1->relids, rel2->lateral_relids))
...@@ -582,15 +574,7 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2, ...@@ -582,15 +574,7 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
match_sjinfo->jointype == JOIN_FULL)) match_sjinfo->jointype == JOIN_FULL))
return false; /* not implementable as nestloop */ return false; /* not implementable as nestloop */
/* check there is a direct reference from rel1 to rel2 */ /* check there is a direct reference from rel1 to rel2 */
foreach(l, root->lateral_info_list) if (!bms_overlap(rel2->relids, rel1->direct_lateral_relids))
{
LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(l);
if (bms_is_subset(ljinfo->lateral_rhs, rel1->relids) &&
bms_is_subset(ljinfo->lateral_lhs, rel2->relids))
break;
}
if (l == NULL)
return false; /* only indirect refs, so reject */ return false; /* only indirect refs, so reject */
/* check we won't have a dangerous PHV */ /* check we won't have a dangerous PHV */
if (have_dangerous_phv(root, rel2->relids, rel1->lateral_relids)) if (have_dangerous_phv(root, rel2->relids, rel1->lateral_relids))
...@@ -922,17 +906,9 @@ have_join_order_restriction(PlannerInfo *root, ...@@ -922,17 +906,9 @@ have_join_order_restriction(PlannerInfo *root,
* If either side has a direct lateral reference to the other, attempt the * If either side has a direct lateral reference to the other, attempt the
* join regardless of outer-join considerations. * join regardless of outer-join considerations.
*/ */
foreach(l, root->lateral_info_list) if (bms_overlap(rel1->relids, rel2->direct_lateral_relids) ||
{ bms_overlap(rel2->relids, rel1->direct_lateral_relids))
LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(l); return true;
if (bms_is_subset(ljinfo->lateral_rhs, rel2->relids) &&
bms_overlap(ljinfo->lateral_lhs, rel1->relids))
return true;
if (bms_is_subset(ljinfo->lateral_rhs, rel1->relids) &&
bms_overlap(ljinfo->lateral_lhs, rel2->relids))
return true;
}
/* /*
* Likewise, if both rels are needed to compute some PlaceHolderVar, * Likewise, if both rels are needed to compute some PlaceHolderVar,
......
...@@ -439,9 +439,6 @@ remove_rel_from_query(PlannerInfo *root, int relid, Relids joinrelids) ...@@ -439,9 +439,6 @@ remove_rel_from_query(PlannerInfo *root, int relid, Relids joinrelids)
sjinfo->syn_righthand = bms_del_member(sjinfo->syn_righthand, relid); sjinfo->syn_righthand = bms_del_member(sjinfo->syn_righthand, relid);
} }
/* There shouldn't be any LATERAL info to translate, as yet */
Assert(root->lateral_info_list == NIL);
/* /*
* Likewise remove references from PlaceHolderVar data structures, * Likewise remove references from PlaceHolderVar data structures,
* removing any no-longer-needed placeholders entirely. * removing any no-longer-needed placeholders entirely.
......
...@@ -47,7 +47,6 @@ typedef struct PostponedQual ...@@ -47,7 +47,6 @@ typedef struct PostponedQual
static void extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, static void extract_lateral_references(PlannerInfo *root, RelOptInfo *brel,
Index rtindex); Index rtindex);
static void add_lateral_info(PlannerInfo *root, Relids lhs, Relids rhs);
static List *deconstruct_recurse(PlannerInfo *root, Node *jtnode, static List *deconstruct_recurse(PlannerInfo *root, Node *jtnode,
bool below_outer_join, bool below_outer_join,
Relids *qualscope, Relids *inner_join_rels, Relids *qualscope, Relids *inner_join_rels,
...@@ -382,11 +381,8 @@ extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex) ...@@ -382,11 +381,8 @@ extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex)
/* /*
* create_lateral_join_info * create_lateral_join_info
* For each unflattened LATERAL subquery, create LateralJoinInfo(s) and add * Fill in the per-base-relation direct_lateral_relids, lateral_relids
* them to root->lateral_info_list, and fill in the per-rel lateral_relids * and lateral_referencers sets.
* and lateral_referencers sets. Also generate LateralJoinInfo(s) to
* represent any lateral references within PlaceHolderVars (this part deals
* with the effects of flattened LATERAL subqueries).
* *
* This has to run after deconstruct_jointree, because we need to know the * This has to run after deconstruct_jointree, because we need to know the
* final ph_eval_at values for PlaceHolderVars. * final ph_eval_at values for PlaceHolderVars.
...@@ -394,6 +390,7 @@ extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex) ...@@ -394,6 +390,7 @@ extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex)
void void
create_lateral_join_info(PlannerInfo *root) create_lateral_join_info(PlannerInfo *root)
{ {
bool found_laterals = false;
Index rti; Index rti;
ListCell *lc; ListCell *lc;
...@@ -430,8 +427,7 @@ create_lateral_join_info(PlannerInfo *root) ...@@ -430,8 +427,7 @@ create_lateral_join_info(PlannerInfo *root)
{ {
Var *var = (Var *) node; Var *var = (Var *) node;
add_lateral_info(root, bms_make_singleton(var->varno), found_laterals = true;
brel->relids);
lateral_relids = bms_add_member(lateral_relids, lateral_relids = bms_add_member(lateral_relids,
var->varno); var->varno);
} }
...@@ -441,7 +437,7 @@ create_lateral_join_info(PlannerInfo *root) ...@@ -441,7 +437,7 @@ create_lateral_join_info(PlannerInfo *root)
PlaceHolderInfo *phinfo = find_placeholder_info(root, phv, PlaceHolderInfo *phinfo = find_placeholder_info(root, phv,
false); false);
add_lateral_info(root, phinfo->ph_eval_at, brel->relids); found_laterals = true;
lateral_relids = bms_add_members(lateral_relids, lateral_relids = bms_add_members(lateral_relids,
phinfo->ph_eval_at); phinfo->ph_eval_at);
} }
...@@ -449,69 +445,54 @@ create_lateral_join_info(PlannerInfo *root) ...@@ -449,69 +445,54 @@ create_lateral_join_info(PlannerInfo *root)
Assert(false); Assert(false);
} }
/* We now have all the direct lateral refs from this rel */ /* We now have all the simple lateral refs from this rel */
brel->lateral_relids = lateral_relids; brel->direct_lateral_relids = lateral_relids;
brel->lateral_relids = bms_copy(lateral_relids);
} }
/* /*
* Now check for lateral references within PlaceHolderVars, and make * Now check for lateral references within PlaceHolderVars, and mark their
* LateralJoinInfos describing each such reference. Unlike references in * eval_at rels as having lateral references to the source rels.
* unflattened LATERAL RTEs, the referencing location could be a join.
* *
* For a PHV that is due to be evaluated at a join, we mark each of the * For a PHV that is due to be evaluated at a baserel, mark its source(s)
* join's member baserels as having the PHV's lateral references too. Even * as direct lateral dependencies of the baserel (adding onto the ones
* though the baserels could be scanned without considering those lateral * recorded above). If it's due to be evaluated at a join, mark its
* refs, we will never be able to form the join except as a path * source(s) as indirect lateral dependencies of each baserel in the join,
* parameterized by the lateral refs, so there is no point in considering * ie put them into lateral_relids but not direct_lateral_relids. This is
* unparameterized paths for the baserels; and we mustn't try to join any * appropriate because we can't put any such baserel on the outside of a
* of those baserels to the lateral refs too soon, either. * join to one of the PHV's lateral dependencies, but on the other hand we
* also can't yet join it directly to the dependency.
*/ */
foreach(lc, root->placeholder_list) foreach(lc, root->placeholder_list)
{ {
PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc); PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);
Relids eval_at = phinfo->ph_eval_at; Relids eval_at = phinfo->ph_eval_at;
int varno;
if (phinfo->ph_lateral != NULL) if (phinfo->ph_lateral == NULL)
{ continue; /* PHV is uninteresting if no lateral refs */
List *vars = pull_var_clause((Node *) phinfo->ph_var->phexpr,
PVC_RECURSE_AGGREGATES,
PVC_INCLUDE_PLACEHOLDERS);
ListCell *lc2;
int ev_at;
foreach(lc2, vars)
{
Node *node = (Node *) lfirst(lc2);
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (!bms_is_member(var->varno, eval_at))
add_lateral_info(root,
bms_make_singleton(var->varno),
eval_at);
}
else if (IsA(node, PlaceHolderVar))
{
PlaceHolderVar *other_phv = (PlaceHolderVar *) node;
PlaceHolderInfo *other_phi;
other_phi = find_placeholder_info(root, other_phv,
false);
if (!bms_is_subset(other_phi->ph_eval_at, eval_at))
add_lateral_info(root, other_phi->ph_eval_at, eval_at);
}
else
Assert(false);
}
list_free(vars); found_laterals = true;
ev_at = -1; if (bms_get_singleton_member(eval_at, &varno))
while ((ev_at = bms_next_member(eval_at, ev_at)) >= 0) {
/* Evaluation site is a baserel */
RelOptInfo *brel = find_base_rel(root, varno);
brel->direct_lateral_relids =
bms_add_members(brel->direct_lateral_relids,
phinfo->ph_lateral);
brel->lateral_relids =
bms_add_members(brel->lateral_relids,
phinfo->ph_lateral);
}
else
{
/* Evaluation site is a join */
varno = -1;
while ((varno = bms_next_member(eval_at, varno)) >= 0)
{ {
RelOptInfo *brel = find_base_rel(root, ev_at); RelOptInfo *brel = find_base_rel(root, varno);
brel->lateral_relids = bms_add_members(brel->lateral_relids, brel->lateral_relids = bms_add_members(brel->lateral_relids,
phinfo->ph_lateral); phinfo->ph_lateral);
...@@ -519,17 +500,22 @@ create_lateral_join_info(PlannerInfo *root) ...@@ -519,17 +500,22 @@ create_lateral_join_info(PlannerInfo *root)
} }
} }
/* If we found no lateral references, we're done. */ /*
if (root->lateral_info_list == NIL) * If we found no actual lateral references, we're done; but reset the
* hasLateralRTEs flag to avoid useless work later.
*/
if (!found_laterals)
{
root->hasLateralRTEs = false;
return; return;
}
/* /*
* At this point the lateral_relids sets represent only direct lateral * Calculate the transitive closure of the lateral_relids sets, so that
* references. Replace them by their transitive closure, so that they * they describe both direct and indirect lateral references. If relation
* describe both direct and indirect lateral references. If relation X * X references Y laterally, and Y references Z laterally, then we will
* references Y laterally, and Y references Z laterally, then we will have * have to scan X on the inside of a nestloop with Z, so for all intents
* to scan X on the inside of a nestloop with Z, so for all intents and * and purposes X is laterally dependent on Z too.
* purposes X is laterally dependent on Z too.
* *
* This code is essentially Warshall's algorithm for transitive closure. * This code is essentially Warshall's algorithm for transitive closure.
* The outer loop considers each baserel, and propagates its lateral * The outer loop considers each baserel, and propagates its lateral
...@@ -632,6 +618,8 @@ create_lateral_join_info(PlannerInfo *root) ...@@ -632,6 +618,8 @@ create_lateral_join_info(PlannerInfo *root)
continue; continue;
childrel = root->simple_rel_array[appinfo->child_relid]; childrel = root->simple_rel_array[appinfo->child_relid];
Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL); Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
Assert(childrel->direct_lateral_relids == NULL);
childrel->direct_lateral_relids = brel->direct_lateral_relids;
Assert(childrel->lateral_relids == NULL); Assert(childrel->lateral_relids == NULL);
childrel->lateral_relids = brel->lateral_relids; childrel->lateral_relids = brel->lateral_relids;
Assert(childrel->lateral_referencers == NULL); Assert(childrel->lateral_referencers == NULL);
...@@ -641,46 +629,6 @@ create_lateral_join_info(PlannerInfo *root) ...@@ -641,46 +629,6 @@ create_lateral_join_info(PlannerInfo *root)
} }
} }
/*
* add_lateral_info
* Add a LateralJoinInfo to root->lateral_info_list, if needed
*
* We suppress redundant list entries. The passed Relids are copied if saved.
*/
static void
add_lateral_info(PlannerInfo *root, Relids lhs, Relids rhs)
{
LateralJoinInfo *ljinfo;
ListCell *lc;
/* Sanity-check the input */
Assert(!bms_is_empty(lhs));
Assert(!bms_is_empty(rhs));
Assert(!bms_overlap(lhs, rhs));
/*
* The input is redundant if it has the same RHS and an LHS that is a
* subset of an existing entry's. If an existing entry has the same RHS
* and an LHS that is a subset of the new one, it's redundant, but we
* don't trouble to get rid of it. The only case that is really worth
* worrying about is identical entries, and we handle that well enough
* with this simple logic.
*/
foreach(lc, root->lateral_info_list)
{
ljinfo = (LateralJoinInfo *) lfirst(lc);
if (bms_equal(rhs, ljinfo->lateral_rhs) &&
bms_is_subset(lhs, ljinfo->lateral_lhs))
return;
}
/* Not there, so make a new entry */
ljinfo = makeNode(LateralJoinInfo);
ljinfo->lateral_lhs = bms_copy(lhs);
ljinfo->lateral_rhs = bms_copy(rhs);
root->lateral_info_list = lappend(root->lateral_info_list, ljinfo);
}
/***************************************************************************** /*****************************************************************************
* *
......
...@@ -433,9 +433,8 @@ build_minmax_path(PlannerInfo *root, MinMaxAggInfo *mminfo, ...@@ -433,9 +433,8 @@ build_minmax_path(PlannerInfo *root, MinMaxAggInfo *mminfo,
subroot->plan_params = NIL; subroot->plan_params = NIL;
subroot->outer_params = NULL; subroot->outer_params = NULL;
subroot->init_plans = NIL; subroot->init_plans = NIL;
/* There shouldn't be any OJ or LATERAL info to translate, as yet */ /* There shouldn't be any OJ info to translate, as yet */
Assert(subroot->join_info_list == NIL); Assert(subroot->join_info_list == NIL);
Assert(subroot->lateral_info_list == NIL);
/* and we haven't created PlaceHolderInfos, either */ /* and we haven't created PlaceHolderInfos, either */
Assert(subroot->placeholder_list == NIL); Assert(subroot->placeholder_list == NIL);
......
...@@ -114,7 +114,6 @@ query_planner(PlannerInfo *root, List *tlist, ...@@ -114,7 +114,6 @@ query_planner(PlannerInfo *root, List *tlist,
root->right_join_clauses = NIL; root->right_join_clauses = NIL;
root->full_join_clauses = NIL; root->full_join_clauses = NIL;
root->join_info_list = NIL; root->join_info_list = NIL;
root->lateral_info_list = NIL;
root->placeholder_list = NIL; root->placeholder_list = NIL;
root->initial_rels = NIL; root->initial_rels = NIL;
...@@ -201,9 +200,8 @@ query_planner(PlannerInfo *root, List *tlist, ...@@ -201,9 +200,8 @@ query_planner(PlannerInfo *root, List *tlist,
add_placeholders_to_base_rels(root); add_placeholders_to_base_rels(root);
/* /*
* Create the LateralJoinInfo list now that we have finalized * Construct the lateral reference sets now that we have finalized
* PlaceHolderVar eval levels and made any necessary additions to the * PlaceHolderVar eval levels.
* lateral_vars lists for lateral references within PlaceHolderVars.
*/ */
create_lateral_join_info(root); create_lateral_join_info(root);
......
...@@ -1132,9 +1132,8 @@ inheritance_planner(PlannerInfo *root) ...@@ -1132,9 +1132,8 @@ inheritance_planner(PlannerInfo *root)
} }
} }
/* There shouldn't be any OJ or LATERAL info to translate, as yet */ /* There shouldn't be any OJ info to translate, as yet */
Assert(subroot.join_info_list == NIL); Assert(subroot.join_info_list == NIL);
Assert(subroot.lateral_info_list == NIL);
/* and we haven't created PlaceHolderInfos, either */ /* and we haven't created PlaceHolderInfos, either */
Assert(subroot.placeholder_list == NIL); Assert(subroot.placeholder_list == NIL);
/* hack to mark target relation as an inheritance partition */ /* hack to mark target relation as an inheritance partition */
......
...@@ -1150,14 +1150,11 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, ...@@ -1150,14 +1150,11 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
subroot->append_rel_list); subroot->append_rel_list);
/* /*
* We don't have to do the equivalent bookkeeping for outer-join or * We don't have to do the equivalent bookkeeping for outer-join info,
* LATERAL info, because that hasn't been set up yet. placeholder_list * because that hasn't been set up yet. placeholder_list likewise.
* likewise.
*/ */
Assert(root->join_info_list == NIL); Assert(root->join_info_list == NIL);
Assert(subroot->join_info_list == NIL); Assert(subroot->join_info_list == NIL);
Assert(root->lateral_info_list == NIL);
Assert(subroot->lateral_info_list == NIL);
Assert(root->placeholder_list == NIL); Assert(root->placeholder_list == NIL);
Assert(subroot->placeholder_list == NIL); Assert(subroot->placeholder_list == NIL);
...@@ -1642,7 +1639,6 @@ pull_up_simple_values(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte) ...@@ -1642,7 +1639,6 @@ pull_up_simple_values(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
Assert(root->append_rel_list == NIL); Assert(root->append_rel_list == NIL);
Assert(list_length(parse->rtable) == 1); Assert(list_length(parse->rtable) == 1);
Assert(root->join_info_list == NIL); Assert(root->join_info_list == NIL);
Assert(root->lateral_info_list == NIL);
Assert(root->placeholder_list == NIL); Assert(root->placeholder_list == NIL);
/* /*
...@@ -2839,7 +2835,6 @@ substitute_multiple_relids_walker(Node *node, ...@@ -2839,7 +2835,6 @@ substitute_multiple_relids_walker(Node *node,
} }
/* Shouldn't need to handle planner auxiliary nodes here */ /* Shouldn't need to handle planner auxiliary nodes here */
Assert(!IsA(node, SpecialJoinInfo)); Assert(!IsA(node, SpecialJoinInfo));
Assert(!IsA(node, LateralJoinInfo));
Assert(!IsA(node, AppendRelInfo)); Assert(!IsA(node, AppendRelInfo));
Assert(!IsA(node, PlaceHolderInfo)); Assert(!IsA(node, PlaceHolderInfo));
Assert(!IsA(node, MinMaxAggInfo)); Assert(!IsA(node, MinMaxAggInfo));
......
...@@ -1786,7 +1786,6 @@ adjust_appendrel_attrs_mutator(Node *node, ...@@ -1786,7 +1786,6 @@ adjust_appendrel_attrs_mutator(Node *node,
} }
/* Shouldn't need to handle planner auxiliary nodes here */ /* Shouldn't need to handle planner auxiliary nodes here */
Assert(!IsA(node, SpecialJoinInfo)); Assert(!IsA(node, SpecialJoinInfo));
Assert(!IsA(node, LateralJoinInfo));
Assert(!IsA(node, AppendRelInfo)); Assert(!IsA(node, AppendRelInfo));
Assert(!IsA(node, PlaceHolderInfo)); Assert(!IsA(node, PlaceHolderInfo));
Assert(!IsA(node, MinMaxAggInfo)); Assert(!IsA(node, MinMaxAggInfo));
......
...@@ -363,12 +363,10 @@ fix_placeholder_input_needed_levels(PlannerInfo *root) ...@@ -363,12 +363,10 @@ fix_placeholder_input_needed_levels(PlannerInfo *root)
/* /*
* add_placeholders_to_base_rels * add_placeholders_to_base_rels
* Add any required PlaceHolderVars to base rels' targetlists, and * Add any required PlaceHolderVars to base rels' targetlists.
* update lateral_vars lists for lateral references contained in them.
* *
* If any placeholder can be computed at a base rel and is needed above it, * If any placeholder can be computed at a base rel and is needed above it,
* add it to that rel's targetlist, and add any lateral references it requires * add it to that rel's targetlist. This might look like it could be merged
* to the rel's lateral_vars list. This might look like it could be merged
* with fix_placeholder_input_needed_levels, but it must be separate because * with fix_placeholder_input_needed_levels, but it must be separate because
* join removal happens in between, and can change the ph_eval_at sets. There * join removal happens in between, and can change the ph_eval_at sets. There
* is essentially the same logic in add_placeholders_to_joinrel, but we can't * is essentially the same logic in add_placeholders_to_joinrel, but we can't
...@@ -385,58 +383,22 @@ add_placeholders_to_base_rels(PlannerInfo *root) ...@@ -385,58 +383,22 @@ add_placeholders_to_base_rels(PlannerInfo *root)
Relids eval_at = phinfo->ph_eval_at; Relids eval_at = phinfo->ph_eval_at;
int varno; int varno;
if (bms_get_singleton_member(eval_at, &varno)) if (bms_get_singleton_member(eval_at, &varno) &&
bms_nonempty_difference(phinfo->ph_needed, eval_at))
{ {
RelOptInfo *rel = find_base_rel(root, varno); RelOptInfo *rel = find_base_rel(root, varno);
/* add it to reltargetlist if needed above the rel scan level */ rel->reltargetlist = lappend(rel->reltargetlist,
if (bms_nonempty_difference(phinfo->ph_needed, eval_at)) copyObject(phinfo->ph_var));
rel->reltargetlist = lappend(rel->reltargetlist,
copyObject(phinfo->ph_var));
/* if there are lateral refs in it, add them to lateral_vars */
if (phinfo->ph_lateral != NULL)
{
List *vars = pull_var_clause((Node *) phinfo->ph_var->phexpr,
PVC_RECURSE_AGGREGATES,
PVC_INCLUDE_PLACEHOLDERS);
ListCell *lc2;
foreach(lc2, vars)
{
Node *node = (Node *) lfirst(lc2);
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varno != varno)
rel->lateral_vars = lappend(rel->lateral_vars,
var);
}
else if (IsA(node, PlaceHolderVar))
{
PlaceHolderVar *other_phv = (PlaceHolderVar *) node;
PlaceHolderInfo *other_phi;
other_phi = find_placeholder_info(root, other_phv,
false);
if (!bms_is_subset(other_phi->ph_eval_at, eval_at))
rel->lateral_vars = lappend(rel->lateral_vars,
other_phv);
}
else
Assert(false);
}
list_free(vars);
}
} }
} }
} }
/* /*
* add_placeholders_to_joinrel * add_placeholders_to_joinrel
* Add any required PlaceHolderVars to a join rel's targetlist. * Add any required PlaceHolderVars to a join rel's targetlist;
* and if they contain lateral references, add those references to the
* joinrel's direct_lateral_relids.
* *
* A join rel should emit a PlaceHolderVar if (a) the PHV is needed above * A join rel should emit a PlaceHolderVar if (a) the PHV is needed above
* this join level and (b) the PHV can be computed at or below this level. * this join level and (b) the PHV can be computed at or below this level.
...@@ -463,6 +425,10 @@ add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel) ...@@ -463,6 +425,10 @@ add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel)
joinrel->reltargetlist = lappend(joinrel->reltargetlist, joinrel->reltargetlist = lappend(joinrel->reltargetlist,
phinfo->ph_var); phinfo->ph_var);
joinrel->width += phinfo->ph_width; joinrel->width += phinfo->ph_width;
/* Adjust joinrel's direct_lateral_relids as needed */
joinrel->direct_lateral_relids =
bms_add_members(joinrel->direct_lateral_relids,
phinfo->ph_lateral);
} }
} }
} }
......
...@@ -111,6 +111,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) ...@@ -111,6 +111,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
rel->cheapest_total_path = NULL; rel->cheapest_total_path = NULL;
rel->cheapest_unique_path = NULL; rel->cheapest_unique_path = NULL;
rel->cheapest_parameterized_paths = NIL; rel->cheapest_parameterized_paths = NIL;
rel->direct_lateral_relids = NULL;
rel->lateral_relids = NULL; rel->lateral_relids = NULL;
rel->relid = relid; rel->relid = relid;
rel->rtekind = rte->rtekind; rel->rtekind = rte->rtekind;
...@@ -373,6 +374,10 @@ build_join_rel(PlannerInfo *root, ...@@ -373,6 +374,10 @@ build_join_rel(PlannerInfo *root,
joinrel->cheapest_total_path = NULL; joinrel->cheapest_total_path = NULL;
joinrel->cheapest_unique_path = NULL; joinrel->cheapest_unique_path = NULL;
joinrel->cheapest_parameterized_paths = NIL; joinrel->cheapest_parameterized_paths = NIL;
/* init direct_lateral_relids from children; we'll finish it up below */
joinrel->direct_lateral_relids =
bms_union(outer_rel->direct_lateral_relids,
inner_rel->direct_lateral_relids);
joinrel->lateral_relids = min_join_parameterization(root, joinrel->relids, joinrel->lateral_relids = min_join_parameterization(root, joinrel->relids,
outer_rel, inner_rel); outer_rel, inner_rel);
joinrel->relid = 0; /* indicates not a baserel */ joinrel->relid = 0; /* indicates not a baserel */
...@@ -422,6 +427,18 @@ build_join_rel(PlannerInfo *root, ...@@ -422,6 +427,18 @@ build_join_rel(PlannerInfo *root,
build_joinrel_tlist(root, joinrel, inner_rel); build_joinrel_tlist(root, joinrel, inner_rel);
add_placeholders_to_joinrel(root, joinrel); add_placeholders_to_joinrel(root, joinrel);
/*
* add_placeholders_to_joinrel also took care of adding the ph_lateral
* sets of any PlaceHolderVars computed here to direct_lateral_relids, so
* now we can finish computing that. This is much like the computation of
* the transitively-closed lateral_relids in min_join_parameterization,
* except that here we *do* have to consider the added PHVs.
*/
joinrel->direct_lateral_relids =
bms_del_members(joinrel->direct_lateral_relids, joinrel->relids);
if (bms_is_empty(joinrel->direct_lateral_relids))
joinrel->direct_lateral_relids = NULL;
/* /*
* Construct restrict and join clause lists for the new joinrel. (The * Construct restrict and join clause lists for the new joinrel. (The
* caller might or might not need the restrictlist, but I need it anyway * caller might or might not need the restrictlist, but I need it anyway
......
...@@ -782,7 +782,6 @@ flatten_join_alias_vars_mutator(Node *node, ...@@ -782,7 +782,6 @@ flatten_join_alias_vars_mutator(Node *node,
Assert(!IsA(node, SubPlan)); Assert(!IsA(node, SubPlan));
/* Shouldn't need to handle these planner auxiliary nodes here */ /* Shouldn't need to handle these planner auxiliary nodes here */
Assert(!IsA(node, SpecialJoinInfo)); Assert(!IsA(node, SpecialJoinInfo));
Assert(!IsA(node, LateralJoinInfo));
Assert(!IsA(node, PlaceHolderInfo)); Assert(!IsA(node, PlaceHolderInfo));
Assert(!IsA(node, MinMaxAggInfo)); Assert(!IsA(node, MinMaxAggInfo));
......
...@@ -402,7 +402,6 @@ OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context) ...@@ -402,7 +402,6 @@ OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
/* Shouldn't need to handle other planner auxiliary nodes here */ /* Shouldn't need to handle other planner auxiliary nodes here */
Assert(!IsA(node, PlanRowMark)); Assert(!IsA(node, PlanRowMark));
Assert(!IsA(node, SpecialJoinInfo)); Assert(!IsA(node, SpecialJoinInfo));
Assert(!IsA(node, LateralJoinInfo));
Assert(!IsA(node, PlaceHolderInfo)); Assert(!IsA(node, PlaceHolderInfo));
Assert(!IsA(node, MinMaxAggInfo)); Assert(!IsA(node, MinMaxAggInfo));
...@@ -586,7 +585,6 @@ ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context) ...@@ -586,7 +585,6 @@ ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
} }
/* Shouldn't need to handle other planner auxiliary nodes here */ /* Shouldn't need to handle other planner auxiliary nodes here */
Assert(!IsA(node, SpecialJoinInfo)); Assert(!IsA(node, SpecialJoinInfo));
Assert(!IsA(node, LateralJoinInfo));
Assert(!IsA(node, PlaceHolderInfo)); Assert(!IsA(node, PlaceHolderInfo));
Assert(!IsA(node, MinMaxAggInfo)); Assert(!IsA(node, MinMaxAggInfo));
...@@ -868,7 +866,6 @@ rangeTableEntry_used_walker(Node *node, ...@@ -868,7 +866,6 @@ rangeTableEntry_used_walker(Node *node,
Assert(!IsA(node, PlaceHolderVar)); Assert(!IsA(node, PlaceHolderVar));
Assert(!IsA(node, PlanRowMark)); Assert(!IsA(node, PlanRowMark));
Assert(!IsA(node, SpecialJoinInfo)); Assert(!IsA(node, SpecialJoinInfo));
Assert(!IsA(node, LateralJoinInfo));
Assert(!IsA(node, AppendRelInfo)); Assert(!IsA(node, AppendRelInfo));
Assert(!IsA(node, PlaceHolderInfo)); Assert(!IsA(node, PlaceHolderInfo));
Assert(!IsA(node, MinMaxAggInfo)); Assert(!IsA(node, MinMaxAggInfo));
......
...@@ -247,7 +247,6 @@ typedef enum NodeTag ...@@ -247,7 +247,6 @@ typedef enum NodeTag
T_RestrictInfo, T_RestrictInfo,
T_PlaceHolderVar, T_PlaceHolderVar,
T_SpecialJoinInfo, T_SpecialJoinInfo,
T_LateralJoinInfo,
T_AppendRelInfo, T_AppendRelInfo,
T_PlaceHolderInfo, T_PlaceHolderInfo,
T_MinMaxAggInfo, T_MinMaxAggInfo,
......
...@@ -226,8 +226,6 @@ typedef struct PlannerInfo ...@@ -226,8 +226,6 @@ typedef struct PlannerInfo
List *join_info_list; /* list of SpecialJoinInfos */ List *join_info_list; /* list of SpecialJoinInfos */
List *lateral_info_list; /* list of LateralJoinInfos */
List *append_rel_list; /* list of AppendRelInfos */ List *append_rel_list; /* list of AppendRelInfos */
List *rowMarks; /* list of PlanRowMarks */ List *rowMarks; /* list of PlanRowMarks */
...@@ -357,6 +355,7 @@ typedef struct PlannerInfo ...@@ -357,6 +355,7 @@ typedef struct PlannerInfo
* (no duplicates) output from relation; NULL if not yet requested * (no duplicates) output from relation; NULL if not yet requested
* cheapest_parameterized_paths - best paths for their parameterizations; * cheapest_parameterized_paths - best paths for their parameterizations;
* always includes cheapest_total_path, even if that's unparameterized * always includes cheapest_total_path, even if that's unparameterized
* direct_lateral_relids - rels this rel has direct LATERAL references to
* lateral_relids - required outer rels for LATERAL, as a Relids set * lateral_relids - required outer rels for LATERAL, as a Relids set
* (includes both direct and indirect lateral references) * (includes both direct and indirect lateral references)
* *
...@@ -466,6 +465,7 @@ typedef struct RelOptInfo ...@@ -466,6 +465,7 @@ typedef struct RelOptInfo
/* parameterization information needed for both base rels and join rels */ /* parameterization information needed for both base rels and join rels */
/* (see also lateral_vars and lateral_referencers) */ /* (see also lateral_vars and lateral_referencers) */
Relids direct_lateral_relids; /* rels directly laterally referenced */
Relids lateral_relids; /* minimum parameterization of rel */ Relids lateral_relids; /* minimum parameterization of rel */
/* information about a base rel (not set for join rels!) */ /* information about a base rel (not set for join rels!) */
...@@ -1461,43 +1461,6 @@ typedef struct SpecialJoinInfo ...@@ -1461,43 +1461,6 @@ typedef struct SpecialJoinInfo
List *semi_rhs_exprs; /* righthand-side expressions of these ops */ List *semi_rhs_exprs; /* righthand-side expressions of these ops */
} SpecialJoinInfo; } SpecialJoinInfo;
/*
* "Lateral join" info.
*
* Lateral references constrain the join order in a way that's somewhat like
* outer joins, though different in detail. We construct a LateralJoinInfo
* for each lateral cross-reference, placing them in the PlannerInfo node's
* lateral_info_list.
*
* For unflattened LATERAL RTEs, we generate LateralJoinInfo(s) in which
* lateral_rhs is the relid of the LATERAL baserel, and lateral_lhs is a set
* of relids of baserels it references, all of which must be present on the
* LHS to compute a parameter needed by the RHS. Typically, lateral_lhs is
* a singleton, but it can include multiple rels if the RHS references a
* PlaceHolderVar with a multi-rel ph_eval_at level. We disallow joining to
* only part of the LHS in such cases, since that would result in a join tree
* with no convenient place to compute the PHV.
*
* When an appendrel contains lateral references (eg "LATERAL (SELECT x.col1
* UNION ALL SELECT y.col2)"), the LateralJoinInfos reference the parent
* baserel not the member otherrels, since it is the parent relid that is
* considered for joining purposes.
*
* If any LATERAL RTEs were flattened into the parent query, it is possible
* that the query now contains PlaceHolderVars containing lateral references,
* representing expressions that need to be evaluated at particular spots in
* the jointree but contain lateral references to Vars from elsewhere. These
* give rise to LateralJoinInfos in which lateral_rhs is the evaluation point
* of a PlaceHolderVar and lateral_lhs is the set of lateral rels it needs.
*/
typedef struct LateralJoinInfo
{
NodeTag type;
Relids lateral_lhs; /* rels needed to compute a lateral value */
Relids lateral_rhs; /* rel where lateral value is needed */
} LateralJoinInfo;
/* /*
* Append-relation info. * Append-relation info.
* *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment