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 * 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 * to estate->es_auxmodifytables so that it will be run to completion by
* ExecPostprocessPlan. (It'd actually work fine to add the primary * 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) if (!mtstate->canSetTag)
estate->es_auxmodifytables = lappend(estate->es_auxmodifytables, estate->es_auxmodifytables = lcons(mtstate,
mtstate); estate->es_auxmodifytables);
return mtstate; return mtstate;
} }

View File

@ -1543,6 +1543,82 @@ SELECT * FROM y;
-400 -400
(22 rows) (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 -- triggers
TRUNCATE TABLE y; TRUNCATE TABLE y;
INSERT INTO y SELECT generate_series(1, 10); INSERT INTO y SELECT generate_series(1, 10);

View File

@ -641,6 +641,32 @@ SELECT * FROM t LIMIT 10;
SELECT * FROM y; 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 -- triggers
TRUNCATE TABLE y; TRUNCATE TABLE y;