mirror of
https://github.com/postgres/postgres.git
synced 2025-11-19 13:42:17 +03:00
Do assorted mop-up in the planner.
Remove RestrictInfo.nullable_relids, along with a good deal of infrastructure that calculated it. One use-case for it was in join_clause_is_movable_to, but we can now replace that usage with a check to see if the clause's relids include any outer join that can null the target relation. The other use-case was in join_clause_is_movable_into, but that test can just be dropped entirely now that the clause's relids include outer joins. Furthermore, join_clause_is_movable_into should now be accurate enough that it will accept anything returned by generate_join_implied_equalities, so we can restore the Assert that was diked out in commit95f4e59c3. Remove the outerjoin_delayed mechanism. We needed this before to prevent quals from getting evaluated below outer joins that should null some of their vars. Now that we consider varnullingrels while placing quals, that's taken care of automatically, so throw the whole thing away. Teach remove_useless_result_rtes to also remove useless FromExprs. Having done that, the delay_upper_joins flag serves no purpose any more and we can remove it, largely reverting11086f2f2. Use constant TRUE for "dummy" clauses when throwing back outer joins. This improves on a hack I introduced in commit6a6522529. If we have a left-join clause l.x = r.y, and a WHERE clause l.x = constant, we generate r.y = constant and then don't really have a need for the join clause. But we must throw the join clause back anyway after marking it redundant, so that the join search heuristics won't think this is a clauseless join and avoid it. That was a kluge introduced under time pressure, and after looking at it I thought of a better way: let's just introduce constant-TRUE "join clauses" instead, and get rid of them at the end. This improves the generated plans for such cases by not having to test a redundant join clause. We can also get rid of the ugly hack used to mark such clauses as redundant for selectivity estimation. Patch by me; thanks to Richard Guo for review. Discussion: https://postgr.es/m/830269.1656693747@sss.pgh.pa.us
This commit is contained in:
@@ -134,7 +134,6 @@ find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv)
|
||||
phinfo->ph_eval_at = bms_copy(phv->phrels);
|
||||
Assert(!bms_is_empty(phinfo->ph_eval_at));
|
||||
}
|
||||
/* ph_eval_at may change later, see update_placeholder_eval_levels */
|
||||
phinfo->ph_needed = NULL; /* initially it's unused */
|
||||
/* for the moment, estimate width using just the datatype info */
|
||||
phinfo->ph_width = get_typavgwidth(exprType((Node *) phv->phexpr),
|
||||
@@ -284,102 +283,6 @@ find_placeholders_in_expr(PlannerInfo *root, Node *expr)
|
||||
list_free(vars);
|
||||
}
|
||||
|
||||
/*
|
||||
* update_placeholder_eval_levels
|
||||
* Adjust the target evaluation levels for placeholders
|
||||
*
|
||||
* The initial eval_at level set by find_placeholder_info was the set of
|
||||
* rels used in the placeholder's expression (or the whole subselect below
|
||||
* the placeholder's syntactic location, if the expr is variable-free).
|
||||
* If the query contains any outer joins that can null any of those rels,
|
||||
* we must delay evaluation to above those joins.
|
||||
*
|
||||
* We repeat this operation each time we add another outer join to
|
||||
* root->join_info_list. It's somewhat annoying to have to do that, but
|
||||
* since we don't have very much information on the placeholders' locations,
|
||||
* it's hard to avoid. Each placeholder's eval_at level must be correct
|
||||
* by the time it starts to figure in outer-join delay decisions for higher
|
||||
* outer joins.
|
||||
*
|
||||
* In future we might want to put additional policy/heuristics here to
|
||||
* try to determine an optimal evaluation level. The current rules will
|
||||
* result in evaluation at the lowest possible level. However, pushing a
|
||||
* placeholder eval up the tree is likely to further constrain evaluation
|
||||
* order for outer joins, so it could easily be counterproductive; and we
|
||||
* don't have enough information at this point to make an intelligent choice.
|
||||
*/
|
||||
void
|
||||
update_placeholder_eval_levels(PlannerInfo *root, SpecialJoinInfo *new_sjinfo)
|
||||
{
|
||||
ListCell *lc1;
|
||||
|
||||
foreach(lc1, root->placeholder_list)
|
||||
{
|
||||
PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc1);
|
||||
Relids syn_level = phinfo->ph_var->phrels;
|
||||
Relids eval_at;
|
||||
bool found_some;
|
||||
ListCell *lc2;
|
||||
|
||||
/*
|
||||
* We don't need to do any work on this placeholder unless the
|
||||
* newly-added outer join is syntactically beneath its location.
|
||||
*/
|
||||
if (!bms_is_subset(new_sjinfo->syn_lefthand, syn_level) ||
|
||||
!bms_is_subset(new_sjinfo->syn_righthand, syn_level))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Check for delays due to lower outer joins. This is the same logic
|
||||
* as in check_outerjoin_delay in initsplan.c, except that we don't
|
||||
* have anything to do with the delay_upper_joins flags; delay of
|
||||
* upper outer joins will be handled later, based on the eval_at
|
||||
* values we compute now.
|
||||
*/
|
||||
eval_at = phinfo->ph_eval_at;
|
||||
|
||||
do
|
||||
{
|
||||
found_some = false;
|
||||
foreach(lc2, root->join_info_list)
|
||||
{
|
||||
SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc2);
|
||||
|
||||
/* disregard joins not within the PHV's sub-select */
|
||||
if (!bms_is_subset(sjinfo->syn_lefthand, syn_level) ||
|
||||
!bms_is_subset(sjinfo->syn_righthand, syn_level))
|
||||
continue;
|
||||
|
||||
/* do we reference any nullable rels of this OJ? */
|
||||
if (bms_overlap(eval_at, sjinfo->min_righthand) ||
|
||||
(sjinfo->jointype == JOIN_FULL &&
|
||||
bms_overlap(eval_at, sjinfo->min_lefthand)))
|
||||
{
|
||||
/* yes; have we included all its rels in eval_at? */
|
||||
if (!bms_is_subset(sjinfo->min_lefthand, eval_at) ||
|
||||
!bms_is_subset(sjinfo->min_righthand, eval_at))
|
||||
{
|
||||
/* no, so add them in */
|
||||
eval_at = bms_add_members(eval_at,
|
||||
sjinfo->min_lefthand);
|
||||
eval_at = bms_add_members(eval_at,
|
||||
sjinfo->min_righthand);
|
||||
if (sjinfo->ojrelid)
|
||||
eval_at = bms_add_member(eval_at, sjinfo->ojrelid);
|
||||
/* we'll need another iteration */
|
||||
found_some = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (found_some);
|
||||
|
||||
/* Can't move the PHV's eval_at level to above its syntactic level */
|
||||
Assert(bms_is_subset(eval_at, syn_level));
|
||||
|
||||
phinfo->ph_eval_at = eval_at;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fix_placeholder_input_needed_levels
|
||||
* Adjust the "needed at" levels for placeholder inputs
|
||||
|
||||
Reference in New Issue
Block a user