mirror of
https://github.com/postgres/postgres.git
synced 2025-05-03 22:24:49 +03:00
Undo mistaken tightening in join_is_legal().
One of the changes I made in commit 8703059c6b55c427 turns out not to have been such a good idea: we still need the exception in join_is_legal() that allows a join if both inputs already overlap the RHS of the special join we're checking. Otherwise we can miss valid plans, and might indeed fail to find a plan at all, as in recent report from Andreas Seltenreich. That code was added way back in commit c17117649b9ae23d, but I failed to include a regression test case then; my bad. Put it back with a better explanation, and a test this time. The logic does end up a bit different than before though: I now believe it's appropriate to make this check first, thereby allowing such a case whether or not we'd consider the previous SJ(s) to commute with this one. (Presumably, we already decided they did; but it was confusing to have this consideration in the middle of the code that was handling the other case.) Back-patch to all active branches, like the previous patch.
This commit is contained in:
parent
fc0a640230
commit
ec94bc1473
@ -470,11 +470,30 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Otherwise, the proposed join overlaps the RHS but isn't a valid
|
* Otherwise, the proposed join overlaps the RHS but isn't a valid
|
||||||
* implementation of this SJ. It might still be a legal join,
|
* implementation of this SJ. But don't panic quite yet: the RHS
|
||||||
* however, if we're allowed to associate it into the RHS of this
|
* violation might have occurred previously, in one or both input
|
||||||
* SJ. That means this SJ must be a LEFT join (not SEMI or ANTI,
|
* relations, in which case we must have previously decided that
|
||||||
* and certainly not FULL) and the proposed join must not overlap
|
* it was OK to commute some other SJ with this one. If we need
|
||||||
* the LHS.
|
* to perform this join to finish building up the RHS, rejecting
|
||||||
|
* it could lead to not finding any plan at all. (This can occur
|
||||||
|
* because of the heuristics elsewhere in this file that postpone
|
||||||
|
* clauseless joins: we might not consider doing a clauseless join
|
||||||
|
* within the RHS until after we've performed other, validly
|
||||||
|
* commutable SJs with one or both sides of the clauseless join.)
|
||||||
|
* This consideration boils down to the rule that if both inputs
|
||||||
|
* overlap the RHS, we can allow the join --- they are either
|
||||||
|
* fully within the RHS, or represent previously-allowed joins to
|
||||||
|
* rels outside it.
|
||||||
|
*/
|
||||||
|
if (bms_overlap(rel1->relids, sjinfo->min_righthand) &&
|
||||||
|
bms_overlap(rel2->relids, sjinfo->min_righthand))
|
||||||
|
continue; /* assume valid previous violation of RHS */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The proposed join could still be legal, but only if we're
|
||||||
|
* allowed to associate it into the RHS of this SJ. That means
|
||||||
|
* this SJ must be a LEFT join (not SEMI or ANTI, and certainly
|
||||||
|
* not FULL) and the proposed join must not overlap the LHS.
|
||||||
*/
|
*/
|
||||||
if (sjinfo->jointype != JOIN_LEFT ||
|
if (sjinfo->jointype != JOIN_LEFT ||
|
||||||
bms_overlap(joinrelids, sjinfo->min_lefthand))
|
bms_overlap(joinrelids, sjinfo->min_lefthand))
|
||||||
|
@ -3563,6 +3563,52 @@ select t1.* from
|
|||||||
hi de ho neighbor
|
hi de ho neighbor
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
|
explain (verbose, costs off)
|
||||||
|
select * from
|
||||||
|
text_tbl t1
|
||||||
|
inner join int8_tbl i8
|
||||||
|
on i8.q2 = 456
|
||||||
|
right join text_tbl t2
|
||||||
|
on t1.f1 = 'doh!'
|
||||||
|
left join int4_tbl i4
|
||||||
|
on i8.q1 = i4.f1;
|
||||||
|
QUERY PLAN
|
||||||
|
--------------------------------------------------------
|
||||||
|
Nested Loop Left Join
|
||||||
|
Output: t1.f1, i8.q1, i8.q2, t2.f1, i4.f1
|
||||||
|
-> Seq Scan on public.text_tbl t2
|
||||||
|
Output: t2.f1
|
||||||
|
-> Materialize
|
||||||
|
Output: i8.q1, i8.q2, i4.f1, t1.f1
|
||||||
|
-> Nested Loop
|
||||||
|
Output: i8.q1, i8.q2, i4.f1, t1.f1
|
||||||
|
-> Nested Loop Left Join
|
||||||
|
Output: i8.q1, i8.q2, i4.f1
|
||||||
|
Join Filter: (i8.q1 = i4.f1)
|
||||||
|
-> Seq Scan on public.int8_tbl i8
|
||||||
|
Output: i8.q1, i8.q2
|
||||||
|
Filter: (i8.q2 = 456)
|
||||||
|
-> Seq Scan on public.int4_tbl i4
|
||||||
|
Output: i4.f1
|
||||||
|
-> Seq Scan on public.text_tbl t1
|
||||||
|
Output: t1.f1
|
||||||
|
Filter: (t1.f1 = 'doh!'::text)
|
||||||
|
(19 rows)
|
||||||
|
|
||||||
|
select * from
|
||||||
|
text_tbl t1
|
||||||
|
inner join int8_tbl i8
|
||||||
|
on i8.q2 = 456
|
||||||
|
right join text_tbl t2
|
||||||
|
on t1.f1 = 'doh!'
|
||||||
|
left join int4_tbl i4
|
||||||
|
on i8.q1 = i4.f1;
|
||||||
|
f1 | q1 | q2 | f1 | f1
|
||||||
|
------+-----+-----+-------------------+----
|
||||||
|
doh! | 123 | 456 | doh! |
|
||||||
|
doh! | 123 | 456 | hi de ho neighbor |
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- test ability to push constants through outer join clauses
|
-- test ability to push constants through outer join clauses
|
||||||
--
|
--
|
||||||
|
@ -1108,6 +1108,25 @@ select t1.* from
|
|||||||
left join int4_tbl i4
|
left join int4_tbl i4
|
||||||
on (i8.q2 = i4.f1);
|
on (i8.q2 = i4.f1);
|
||||||
|
|
||||||
|
explain (verbose, costs off)
|
||||||
|
select * from
|
||||||
|
text_tbl t1
|
||||||
|
inner join int8_tbl i8
|
||||||
|
on i8.q2 = 456
|
||||||
|
right join text_tbl t2
|
||||||
|
on t1.f1 = 'doh!'
|
||||||
|
left join int4_tbl i4
|
||||||
|
on i8.q1 = i4.f1;
|
||||||
|
|
||||||
|
select * from
|
||||||
|
text_tbl t1
|
||||||
|
inner join int8_tbl i8
|
||||||
|
on i8.q2 = 456
|
||||||
|
right join text_tbl t2
|
||||||
|
on t1.f1 = 'doh!'
|
||||||
|
left join int4_tbl i4
|
||||||
|
on i8.q1 = i4.f1;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- test ability to push constants through outer join clauses
|
-- test ability to push constants through outer join clauses
|
||||||
--
|
--
|
||||||
|
Loading…
x
Reference in New Issue
Block a user