1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-07 00:36:50 +03:00

Fix bogus handling of "postponed" lateral quals.

When pulling a "postponed" qual from a LATERAL subquery up into the quals
of an outer join, we must make sure that the postponed qual is included
in those seen by make_outerjoininfo().  Otherwise we might compute a
too-small min_lefthand or min_righthand for the outer join, leading to
"JOIN qualification cannot refer to other relations" failures from
distribute_qual_to_rels.  Subtler errors in the created plan seem possible,
too, if the extra qual would only affect join ordering constraints.

Per bug #9041 from David Leverton.  Back-patch to 9.3.
This commit is contained in:
Tom Lane
2014-01-30 14:51:19 -05:00
parent e3ec8015d0
commit a4aa854cad
3 changed files with 59 additions and 27 deletions

View File

@ -797,6 +797,7 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
ojscope;
List *leftjoinlist,
*rightjoinlist;
List *my_quals;
SpecialJoinInfo *sjinfo;
ListCell *l;
@ -895,6 +896,32 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
root->nullable_baserels = bms_add_members(root->nullable_baserels,
nullable_rels);
/*
* Try to process any quals postponed by children. If they need
* further postponement, add them to my output postponed_qual_list.
* Quals that can be processed now must be included in my_quals, so
* that they'll be handled properly in make_outerjoininfo.
*/
my_quals = NIL;
foreach(l, child_postponed_quals)
{
PostponedQual *pq = (PostponedQual *) lfirst(l);
if (bms_is_subset(pq->relids, *qualscope))
my_quals = lappend(my_quals, pq->qual);
else
{
/*
* We should not be postponing any quals past an outer join.
* If this Assert fires, pull_up_subqueries() messed up.
*/
Assert(j->jointype == JOIN_INNER);
*postponed_qual_list = lappend(*postponed_qual_list, pq);
}
}
/* list_concat is nondestructive of its second argument */
my_quals = list_concat(my_quals, (List *) j->quals);
/*
* For an OJ, form the SpecialJoinInfo now, because we need the OJ's
* semantic scope (ojscope) to pass to distribute_qual_to_rels. But
@ -910,7 +937,7 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
leftids, rightids,
*inner_join_rels,
j->jointype,
(List *) j->quals);
my_quals);
if (j->jointype == JOIN_SEMI)
ojscope = NULL;
else
@ -923,33 +950,8 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
ojscope = NULL;
}
/*
* Try to process any quals postponed by children. If they need
* further postponement, add them to my output postponed_qual_list.
*/
foreach(l, child_postponed_quals)
{
PostponedQual *pq = (PostponedQual *) lfirst(l);
if (bms_is_subset(pq->relids, *qualscope))
distribute_qual_to_rels(root, pq->qual,
false, below_outer_join, j->jointype,
*qualscope,
ojscope, nonnullable_rels, NULL,
NULL);
else
{
/*
* We should not be postponing any quals past an outer join.
* If this Assert fires, pull_up_subqueries() messed up.
*/
Assert(j->jointype == JOIN_INNER);
*postponed_qual_list = lappend(*postponed_qual_list, pq);
}
}
/* Process the JOIN's qual clauses */
foreach(l, (List *) j->quals)
foreach(l, my_quals)
{
Node *qual = (Node *) lfirst(l);