Skip to content

Commit 9298d2f

Browse files
committed
Fix handling of changed-Param signaling for CteScan plan nodes. We were using
the "cteParam" as a proxy for the possibility that the underlying CTE plan depends on outer-level variables or Params, but that doesn't work very well because it sometimes causes calling subqueries to be treated as SubPlans when they could be InitPlans. This is inefficient and also causes the outright failure exhibited in bug #4902. Instead, leave the cteParam out of it and copy the underlying CTE plan's extParams directly. Per bug #4902 from Marko Tiikkaja.
1 parent f39df96 commit 9298d2f

File tree

3 files changed

+87
-4
lines changed

3 files changed

+87
-4
lines changed

src/backend/optimizer/plan/subselect.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.150 2009/06/11 14:48:59 momjian Exp $
10+
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.151 2009/07/06 02:16:03 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -1916,9 +1916,35 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params)
19161916
break;
19171917

19181918
case T_CteScan:
1919-
context.paramids =
1920-
bms_add_member(context.paramids,
1921-
((CteScan *) plan)->cteParam);
1919+
{
1920+
/*
1921+
* You might think we should add the node's cteParam to
1922+
* paramids, but we shouldn't because that param is just a
1923+
* linkage mechanism for multiple CteScan nodes for the same
1924+
* CTE; it is never used for changed-param signaling. What
1925+
* we have to do instead is to find the referenced CTE plan
1926+
* and incorporate its external paramids, so that the correct
1927+
* things will happen if the CTE references outer-level
1928+
* variables. See test cases for bug #4902.
1929+
*/
1930+
int plan_id = ((CteScan *) plan)->ctePlanId;
1931+
Plan *cteplan;
1932+
1933+
/* so, do this ... */
1934+
if (plan_id < 1 || plan_id > list_length(root->glob->subplans))
1935+
elog(ERROR, "could not find plan for CteScan referencing plan ID %d",
1936+
plan_id);
1937+
cteplan = (Plan *) list_nth(root->glob->subplans, plan_id - 1);
1938+
context.paramids =
1939+
bms_add_members(context.paramids, cteplan->extParam);
1940+
1941+
#ifdef NOT_USED
1942+
/* ... but not this */
1943+
context.paramids =
1944+
bms_add_member(context.paramids,
1945+
((CteScan *) plan)->cteParam);
1946+
#endif
1947+
}
19221948
break;
19231949

19241950
case T_WorkTableScan:

src/test/regress/expected/with.out

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,3 +912,44 @@ ERROR: recursive query "foo" column 1 has type numeric(3,0) in non-recursive te
912912
LINE 2: (SELECT i::numeric(3,0) FROM (VALUES(1),(2)) t(i)
913913
^
914914
HINT: Cast the output of the non-recursive term to the correct type.
915+
--
916+
-- test for bug #4902
917+
--
918+
with cte(foo) as ( values(42) ) values((select foo from cte));
919+
column1
920+
---------
921+
42
922+
(1 row)
923+
924+
with cte(foo) as ( select 42 ) select * from ((select foo from cte)) q;
925+
foo
926+
-----
927+
42
928+
(1 row)
929+
930+
-- test CTE referencing an outer-level variable (to see that changed-parameter
931+
-- signaling still works properly after fixing this bug)
932+
select ( with cte(foo) as ( values(f1) )
933+
select (select foo from cte) )
934+
from int4_tbl;
935+
?column?
936+
-------------
937+
0
938+
123456
939+
-123456
940+
2147483647
941+
-2147483647
942+
(5 rows)
943+
944+
select ( with cte(foo) as ( values(f1) )
945+
values((select foo from cte)) )
946+
from int4_tbl;
947+
?column?
948+
-------------
949+
0
950+
123456
951+
-123456
952+
2147483647
953+
-2147483647
954+
(5 rows)
955+

src/test/regress/sql/with.sql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,3 +469,19 @@ WITH RECURSIVE foo(i) AS
469469
UNION ALL
470470
SELECT (i+1)::numeric(10,0) FROM foo WHERE i < 10)
471471
SELECT * FROM foo;
472+
473+
--
474+
-- test for bug #4902
475+
--
476+
with cte(foo) as ( values(42) ) values((select foo from cte));
477+
with cte(foo) as ( select 42 ) select * from ((select foo from cte)) q;
478+
479+
-- test CTE referencing an outer-level variable (to see that changed-parameter
480+
-- signaling still works properly after fixing this bug)
481+
select ( with cte(foo) as ( values(f1) )
482+
select (select foo from cte) )
483+
from int4_tbl;
484+
485+
select ( with cte(foo) as ( values(f1) )
486+
values((select foo from cte)) )
487+
from int4_tbl;

0 commit comments

Comments
 (0)