mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Fix placement of initPlans when forcibly materializing a subplan.
If we forcibly place a Material node atop a finished subplan, we need
to move any initPlans attached to the subplan up to the Material node,
in order to keep SS_finalize_plan() happy. I'd figured this out in
commit 7b67a0a49
for the case of materializing a cursor plan, but out of
an abundance of caution, I put the initPlan movement hack at the call
site for that case, rather than inside materialize_finished_plan().
That was the wrong thing, because it turns out to also be necessary for
the only other caller of materialize_finished_plan(), ie subselect.c.
We lacked any test cases that exposed the mistake, but bug#14524 from
Wei Congrui shows that it's possible to get an initPlan reference into
the top tlist in that case too, and then SS_finalize_plan() complains.
Hence, move the hack into materialize_finished_plan().
In HEAD, also relocate some recently-added tests in subselect.sql, which
I'd unthinkingly dropped into the middle of a sequence of related tests.
Report: https://postgr.es/m/20170202060020.1400.89021@wrigleys.postgresql.org
This commit is contained in:
@ -5704,6 +5704,16 @@ materialize_finished_plan(Plan *subplan)
|
|||||||
|
|
||||||
matplan = (Plan *) make_material(subplan);
|
matplan = (Plan *) make_material(subplan);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX horrid kluge: if there are any initPlans attached to the subplan,
|
||||||
|
* move them up to the Material node, which is now effectively the top
|
||||||
|
* plan node in its query level. This prevents failure in
|
||||||
|
* SS_finalize_plan(), which see for comments. We don't bother adjusting
|
||||||
|
* the subplan's cost estimate for this.
|
||||||
|
*/
|
||||||
|
matplan->initPlan = subplan->initPlan;
|
||||||
|
subplan->initPlan = NIL;
|
||||||
|
|
||||||
/* Set cost data */
|
/* Set cost data */
|
||||||
cost_material(&matpath,
|
cost_material(&matpath,
|
||||||
subplan->startup_cost,
|
subplan->startup_cost,
|
||||||
|
@ -316,21 +316,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
|
|||||||
if (cursorOptions & CURSOR_OPT_SCROLL)
|
if (cursorOptions & CURSOR_OPT_SCROLL)
|
||||||
{
|
{
|
||||||
if (!ExecSupportsBackwardScan(top_plan))
|
if (!ExecSupportsBackwardScan(top_plan))
|
||||||
{
|
top_plan = materialize_finished_plan(top_plan);
|
||||||
Plan *sub_plan = top_plan;
|
|
||||||
|
|
||||||
top_plan = materialize_finished_plan(sub_plan);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX horrid kluge: if there are any initPlans attached to the
|
|
||||||
* formerly-top plan node, move them up to the Material node. This
|
|
||||||
* prevents failure in SS_finalize_plan, which see for comments.
|
|
||||||
* We don't bother adjusting the sub_plan's cost estimate for
|
|
||||||
* this.
|
|
||||||
*/
|
|
||||||
top_plan->initPlan = sub_plan->initPlan;
|
|
||||||
sub_plan->initPlan = NIL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -196,6 +196,31 @@ SELECT '' AS five, f1 AS "Correlated Field"
|
|||||||
| 3
|
| 3
|
||||||
(5 rows)
|
(5 rows)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Use some existing tables in the regression test
|
||||||
|
--
|
||||||
|
SELECT '' AS eight, ss.f1 AS "Correlated Field", ss.f3 AS "Second Field"
|
||||||
|
FROM SUBSELECT_TBL ss
|
||||||
|
WHERE f1 NOT IN (SELECT f1+1 FROM INT4_TBL
|
||||||
|
WHERE f1 != ss.f1 AND f1 < 2147483647);
|
||||||
|
eight | Correlated Field | Second Field
|
||||||
|
-------+------------------+--------------
|
||||||
|
| 2 | 4
|
||||||
|
| 3 | 5
|
||||||
|
| 2 | 2
|
||||||
|
| 3 | 3
|
||||||
|
| 6 | 8
|
||||||
|
| 8 |
|
||||||
|
(6 rows)
|
||||||
|
|
||||||
|
select q1, float8(count(*)) / (select count(*) from int8_tbl)
|
||||||
|
from int8_tbl group by q1 order by q1;
|
||||||
|
q1 | ?column?
|
||||||
|
------------------+----------
|
||||||
|
123 | 0.4
|
||||||
|
4567890123456789 | 0.6
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
-- Unspecified-type literals in output columns should resolve as text
|
-- Unspecified-type literals in output columns should resolve as text
|
||||||
SELECT *, pg_typeof(f1) FROM
|
SELECT *, pg_typeof(f1) FROM
|
||||||
(SELECT 'foo' AS f1 FROM generate_series(1,3)) ss ORDER BY 1;
|
(SELECT 'foo' AS f1 FROM generate_series(1,3)) ss ORDER BY 1;
|
||||||
@ -227,30 +252,28 @@ explain verbose select '42' union all select 43;
|
|||||||
Output: 43
|
Output: 43
|
||||||
(5 rows)
|
(5 rows)
|
||||||
|
|
||||||
--
|
-- check materialization of an initplan reference (bug #14524)
|
||||||
-- Use some existing tables in the regression test
|
explain (verbose, costs off)
|
||||||
--
|
select 1 = all (select (select 1));
|
||||||
SELECT '' AS eight, ss.f1 AS "Correlated Field", ss.f3 AS "Second Field"
|
QUERY PLAN
|
||||||
FROM SUBSELECT_TBL ss
|
-----------------------------------
|
||||||
WHERE f1 NOT IN (SELECT f1+1 FROM INT4_TBL
|
Result
|
||||||
WHERE f1 != ss.f1 AND f1 < 2147483647);
|
Output: (SubPlan 2)
|
||||||
eight | Correlated Field | Second Field
|
SubPlan 2
|
||||||
-------+------------------+--------------
|
-> Materialize
|
||||||
| 2 | 4
|
Output: ($0)
|
||||||
| 3 | 5
|
InitPlan 1 (returns $0)
|
||||||
| 2 | 2
|
-> Result
|
||||||
| 3 | 3
|
Output: 1
|
||||||
| 6 | 8
|
-> Result
|
||||||
| 8 |
|
Output: $0
|
||||||
(6 rows)
|
(10 rows)
|
||||||
|
|
||||||
select q1, float8(count(*)) / (select count(*) from int8_tbl)
|
select 1 = all (select (select 1));
|
||||||
from int8_tbl group by q1 order by q1;
|
?column?
|
||||||
q1 | ?column?
|
----------
|
||||||
------------------+----------
|
t
|
||||||
123 | 0.4
|
(1 row)
|
||||||
4567890123456789 | 0.6
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Check EXISTS simplification with LIMIT
|
-- Check EXISTS simplification with LIMIT
|
||||||
|
@ -80,16 +80,6 @@ SELECT '' AS five, f1 AS "Correlated Field"
|
|||||||
WHERE (f1, f2) IN (SELECT f2, CAST(f3 AS int4) FROM SUBSELECT_TBL
|
WHERE (f1, f2) IN (SELECT f2, CAST(f3 AS int4) FROM SUBSELECT_TBL
|
||||||
WHERE f3 IS NOT NULL);
|
WHERE f3 IS NOT NULL);
|
||||||
|
|
||||||
-- Unspecified-type literals in output columns should resolve as text
|
|
||||||
|
|
||||||
SELECT *, pg_typeof(f1) FROM
|
|
||||||
(SELECT 'foo' AS f1 FROM generate_series(1,3)) ss ORDER BY 1;
|
|
||||||
|
|
||||||
-- ... unless there's context to suggest differently
|
|
||||||
|
|
||||||
explain verbose select '42' union all select '43';
|
|
||||||
explain verbose select '42' union all select 43;
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Use some existing tables in the regression test
|
-- Use some existing tables in the regression test
|
||||||
--
|
--
|
||||||
@ -102,6 +92,21 @@ SELECT '' AS eight, ss.f1 AS "Correlated Field", ss.f3 AS "Second Field"
|
|||||||
select q1, float8(count(*)) / (select count(*) from int8_tbl)
|
select q1, float8(count(*)) / (select count(*) from int8_tbl)
|
||||||
from int8_tbl group by q1 order by q1;
|
from int8_tbl group by q1 order by q1;
|
||||||
|
|
||||||
|
-- Unspecified-type literals in output columns should resolve as text
|
||||||
|
|
||||||
|
SELECT *, pg_typeof(f1) FROM
|
||||||
|
(SELECT 'foo' AS f1 FROM generate_series(1,3)) ss ORDER BY 1;
|
||||||
|
|
||||||
|
-- ... unless there's context to suggest differently
|
||||||
|
|
||||||
|
explain verbose select '42' union all select '43';
|
||||||
|
explain verbose select '42' union all select 43;
|
||||||
|
|
||||||
|
-- check materialization of an initplan reference (bug #14524)
|
||||||
|
explain (verbose, costs off)
|
||||||
|
select 1 = all (select (select 1));
|
||||||
|
select 1 = all (select (select 1));
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Check EXISTS simplification with LIMIT
|
-- Check EXISTS simplification with LIMIT
|
||||||
--
|
--
|
||||||
|
Reference in New Issue
Block a user