mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Fix a PlaceHolderVar-related oversight in star-schema planning patch.
In commit b514a7460d
, I changed the planner
so that it would allow nestloop paths to remain partially parameterized,
ie the inner relation might need parameters from both the current outer
relation and some upper-level outer relation. That's fine so long as we're
talking about distinct parameters; but the patch also allowed creation of
nestloop paths for cases where the inner relation's parameter was a
PlaceHolderVar whose eval_at set included the current outer relation and
some upper-level one. That does *not* work.
In principle we could allow such a PlaceHolderVar to be evaluated at the
lower join node using values passed down from the upper relation along with
values from the join's own outer relation. However, nodeNestloop.c only
supports simple Vars not arbitrary expressions as nestloop parameters.
createplan.c is also a few bricks shy of being able to handle such cases;
it misplaces the PlaceHolderVar parameters in the plan tree, which is why
the visible symptoms of this bug are "plan should not reference subplan's
variable" and "failed to assign all NestLoopParams to plan nodes" planner
errors.
Adding the necessary complexity to make this work doesn't seem like it
would be repaid in significantly better plans, because in cases where such
a PHV exists, there is probably a corresponding join order constraint that
would allow a good plan to be found without using the star-schema exception.
Furthermore, adding complexity to nodeNestloop.c would create a run-time
penalty even for plans where this whole consideration is irrelevant.
So let's just reject such paths instead.
Per fuzz testing by Andreas Seltenreich; the added regression test is based
on his example query. Back-patch to 9.2, like the previous patch.
This commit is contained in:
@ -2949,6 +2949,57 @@ where thousand = a.q1 and tenthous = b.q1 and a.q2 = 1 and b.q2 = 2;
|
||||
Index Cond: ((thousand = a.q1) AND (tenthous = b.q1))
|
||||
(8 rows)
|
||||
|
||||
--
|
||||
-- test a corner case in which we shouldn't apply the star-schema optimization
|
||||
--
|
||||
explain (costs off)
|
||||
select t1.unique2, t1.stringu1, t2.unique1, t2.stringu2 from
|
||||
tenk1 t1
|
||||
inner join int4_tbl i1
|
||||
left join (select v1.x2, v2.y1, 11 AS d1
|
||||
from (values(1,0)) v1(x1,x2)
|
||||
left join (values(3,1)) v2(y1,y2)
|
||||
on v1.x1 = v2.y2) subq1
|
||||
on (i1.f1 = subq1.x2)
|
||||
on (t1.unique2 = subq1.d1)
|
||||
left join tenk1 t2
|
||||
on (subq1.y1 = t2.unique1)
|
||||
where t1.unique2 < 42 and t1.stringu1 > t2.stringu2;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------
|
||||
Nested Loop
|
||||
Join Filter: (t1.stringu1 > t2.stringu2)
|
||||
-> Nested Loop
|
||||
Join Filter: ((0) = i1.f1)
|
||||
-> Nested Loop
|
||||
-> Nested Loop
|
||||
Join Filter: ((1) = (1))
|
||||
-> Result
|
||||
-> Result
|
||||
-> Index Scan using tenk1_unique2 on tenk1 t1
|
||||
Index Cond: ((unique2 = (11)) AND (unique2 < 42))
|
||||
-> Seq Scan on int4_tbl i1
|
||||
-> Index Scan using tenk1_unique1 on tenk1 t2
|
||||
Index Cond: (unique1 = (3))
|
||||
(14 rows)
|
||||
|
||||
select t1.unique2, t1.stringu1, t2.unique1, t2.stringu2 from
|
||||
tenk1 t1
|
||||
inner join int4_tbl i1
|
||||
left join (select v1.x2, v2.y1, 11 AS d1
|
||||
from (values(1,0)) v1(x1,x2)
|
||||
left join (values(3,1)) v2(y1,y2)
|
||||
on v1.x1 = v2.y2) subq1
|
||||
on (i1.f1 = subq1.x2)
|
||||
on (t1.unique2 = subq1.d1)
|
||||
left join tenk1 t2
|
||||
on (subq1.y1 = t2.unique1)
|
||||
where t1.unique2 < 42 and t1.stringu1 > t2.stringu2;
|
||||
unique2 | stringu1 | unique1 | stringu2
|
||||
---------+----------+---------+----------
|
||||
11 | WFAAAA | 3 | LKIAAA
|
||||
(1 row)
|
||||
|
||||
--
|
||||
-- test extraction of restriction OR clauses from join OR clause
|
||||
-- (we used to only do this for indexable clauses)
|
||||
|
@ -843,6 +843,37 @@ select * from
|
||||
tenk1, int8_tbl a, int8_tbl b
|
||||
where thousand = a.q1 and tenthous = b.q1 and a.q2 = 1 and b.q2 = 2;
|
||||
|
||||
--
|
||||
-- test a corner case in which we shouldn't apply the star-schema optimization
|
||||
--
|
||||
|
||||
explain (costs off)
|
||||
select t1.unique2, t1.stringu1, t2.unique1, t2.stringu2 from
|
||||
tenk1 t1
|
||||
inner join int4_tbl i1
|
||||
left join (select v1.x2, v2.y1, 11 AS d1
|
||||
from (values(1,0)) v1(x1,x2)
|
||||
left join (values(3,1)) v2(y1,y2)
|
||||
on v1.x1 = v2.y2) subq1
|
||||
on (i1.f1 = subq1.x2)
|
||||
on (t1.unique2 = subq1.d1)
|
||||
left join tenk1 t2
|
||||
on (subq1.y1 = t2.unique1)
|
||||
where t1.unique2 < 42 and t1.stringu1 > t2.stringu2;
|
||||
|
||||
select t1.unique2, t1.stringu1, t2.unique1, t2.stringu2 from
|
||||
tenk1 t1
|
||||
inner join int4_tbl i1
|
||||
left join (select v1.x2, v2.y1, 11 AS d1
|
||||
from (values(1,0)) v1(x1,x2)
|
||||
left join (values(3,1)) v2(y1,y2)
|
||||
on v1.x1 = v2.y2) subq1
|
||||
on (i1.f1 = subq1.x2)
|
||||
on (t1.unique2 = subq1.d1)
|
||||
left join tenk1 t2
|
||||
on (subq1.y1 = t2.unique1)
|
||||
where t1.unique2 < 42 and t1.stringu1 > t2.stringu2;
|
||||
|
||||
--
|
||||
-- test extraction of restriction OR clauses from join OR clause
|
||||
-- (we used to only do this for indexable clauses)
|
||||
|
Reference in New Issue
Block a user