Fix order of shutdown processing when CTEs contain inter-references.

We need ExecutorEnd to run the ModifyTable nodes to completion in
reverse order of initialization, not forward order.  Easily done
by constructing the list back-to-front.
This commit is contained in:
Tom Lane 2011-02-25 23:53:34 -05:00
parent 389af95155
commit 000128bc7f
3 changed files with 108 additions and 3 deletions

View File

@ -1147,11 +1147,14 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
* Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
* to estate->es_auxmodifytables so that it will be run to completion by
* ExecPostprocessPlan. (It'd actually work fine to add the primary
* ModifyTable node too, but there's no need.)
* ModifyTable node too, but there's no need.) Note the use of lcons
* not lappend: we need later-initialized ModifyTable nodes to be shut
* down before earlier ones. This ensures that we don't throw away
* RETURNING rows that need to be seen by a later CTE subplan.
*/
if (!mtstate->canSetTag)
estate->es_auxmodifytables = lappend(estate->es_auxmodifytables,
mtstate);
estate->es_auxmodifytables = lcons(mtstate,
estate->es_auxmodifytables);
return mtstate;
}

View File

@ -1543,6 +1543,82 @@ SELECT * FROM y;
-400
(22 rows)
-- check that run to completion happens in proper ordering
TRUNCATE TABLE y;
INSERT INTO y SELECT generate_series(1, 3);
CREATE TEMPORARY TABLE yy (a INTEGER);
WITH RECURSIVE t1 AS (
INSERT INTO y SELECT * FROM y RETURNING *
), t2 AS (
INSERT INTO yy SELECT * FROM t1 RETURNING *
)
SELECT 1;
?column?
----------
1
(1 row)
SELECT * FROM y;
a
---
1
2
3
1
2
3
(6 rows)
SELECT * FROM yy;
a
---
1
2
3
(3 rows)
WITH RECURSIVE t1 AS (
INSERT INTO yy SELECT * FROM t2 RETURNING *
), t2 AS (
INSERT INTO y SELECT * FROM y RETURNING *
)
SELECT 1;
?column?
----------
1
(1 row)
SELECT * FROM y;
a
---
1
2
3
1
2
3
1
2
3
1
2
3
(12 rows)
SELECT * FROM yy;
a
---
1
2
3
1
2
3
1
2
3
(9 rows)
-- triggers
TRUNCATE TABLE y;
INSERT INTO y SELECT generate_series(1, 10);

View File

@ -641,6 +641,32 @@ SELECT * FROM t LIMIT 10;
SELECT * FROM y;
-- check that run to completion happens in proper ordering
TRUNCATE TABLE y;
INSERT INTO y SELECT generate_series(1, 3);
CREATE TEMPORARY TABLE yy (a INTEGER);
WITH RECURSIVE t1 AS (
INSERT INTO y SELECT * FROM y RETURNING *
), t2 AS (
INSERT INTO yy SELECT * FROM t1 RETURNING *
)
SELECT 1;
SELECT * FROM y;
SELECT * FROM yy;
WITH RECURSIVE t1 AS (
INSERT INTO yy SELECT * FROM t2 RETURNING *
), t2 AS (
INSERT INTO y SELECT * FROM y RETURNING *
)
SELECT 1;
SELECT * FROM y;
SELECT * FROM yy;
-- triggers
TRUNCATE TABLE y;