Commit 555494d1 authored by Tom Lane's avatar Tom Lane

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 7b67a0a4 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
parent aa09b9dc
...@@ -5704,6 +5704,16 @@ materialize_finished_plan(Plan *subplan) ...@@ -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) ...@@ -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" ...@@ -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; ...@@ -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" ...@@ -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" ...@@ -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
-- --
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment