mirror of
https://github.com/postgres/postgres.git
synced 2025-11-19 13:42:17 +03:00
Fix some new issues with planning of PlaceHolderVars.
In the wake of commita16ef313f, we need to deal with more cases involving PlaceHolderVars in NestLoopParams than we did before. For one thing,a16ef313fwas incorrect to suppose that we could rely on the required-outer relids of the lefthand path to decide placement of nestloop-parameter PHVs. As Richard Guo argued at the time, we must look at the required-outer relids of the join path itself. For another, we have to apply replace_nestloop_params() to such a PHV's expression, in case it contains references to values that will be supplied from NestLoopParams of higher-level nestloops. For another, we need to be more careful about the phnullingrels of the PHV than we were being. identify_current_nestloop_params only bothered to ensure that the phnullingrels didn't contain "too many" relids, but now it has to be exact, because setrefs.c will apply both NRM_SUBSET and NRM_SUPERSET checks in different places. We can compute the correct relids by determining the set of outer joins that should be able to null the PHV and then subtracting whatever's been applied at or below this join. Do the same for plain Vars, too. (This should make it possible to use NRM_EQUAL to process nestloop params in setrefs.c, but I won't risk making such a change in v18 now.) Lastly, if a nestloop parameter PHV was pulled up out of a subquery and it contains a subquery that was originally pushed down from this query level, then that will still be represented as a SubLink, because SS_process_sublinks won't recurse into outer PHVs, so it didn't get transformed during expression preprocessing in the subquery. We can substitute the version of the PHV's expression appearing in its PlaceHolderInfo to ensure that that preprocessing has happened. (Seems like this processing sequence could stand to be redesigned, but again, late in v18 development is not the time for that.) It's not very clear to me why the old have_dangerous_phv join-order restriction prevented us from seeing the last three of these problems. But given the lack of field complaints, it must have done so. Reported-by: Alexander Lakhin <exclusion@gmail.com> Author: Tom Lane <tgl@sss.pgh.pa.us> Discussion: https://postgr.es/m/18953-1c9883a9d4afeb30@postgresql.org
This commit is contained in:
@@ -545,3 +545,43 @@ contain_placeholder_references_walker(Node *node,
|
||||
return expression_tree_walker(node, contain_placeholder_references_walker,
|
||||
context);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the set of outer-join relids that can null a placeholder.
|
||||
*
|
||||
* This is analogous to RelOptInfo.nulling_relids for Vars, but we compute it
|
||||
* on-the-fly rather than saving it somewhere. Currently the value is needed
|
||||
* at most once per query, so there's little value in doing otherwise. If it
|
||||
* ever gains more widespread use, perhaps we should cache the result in
|
||||
* PlaceHolderInfo.
|
||||
*/
|
||||
Relids
|
||||
get_placeholder_nulling_relids(PlannerInfo *root, PlaceHolderInfo *phinfo)
|
||||
{
|
||||
Relids result = NULL;
|
||||
int relid = -1;
|
||||
|
||||
/*
|
||||
* Form the union of all potential nulling OJs for each baserel included
|
||||
* in ph_eval_at.
|
||||
*/
|
||||
while ((relid = bms_next_member(phinfo->ph_eval_at, relid)) > 0)
|
||||
{
|
||||
RelOptInfo *rel = root->simple_rel_array[relid];
|
||||
|
||||
/* ignore the RTE_GROUP RTE */
|
||||
if (relid == root->group_rtindex)
|
||||
continue;
|
||||
|
||||
if (rel == NULL) /* must be an outer join */
|
||||
{
|
||||
Assert(bms_is_member(relid, root->outer_join_rels));
|
||||
continue;
|
||||
}
|
||||
result = bms_add_members(result, rel->nulling_relids);
|
||||
}
|
||||
|
||||
/* Now remove any OJs already included in ph_eval_at, and we're done. */
|
||||
result = bms_del_members(result, phinfo->ph_eval_at);
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user