summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorTom Lane2013-11-08 16:36:57 +0000
committerTom Lane2013-11-08 16:36:57 +0000
commitb97ee66cc1f9319f7b457e7d8a78aab711da2dda (patch)
tree1465238f3cb92cb804164579f3904dbfbaf98de5 /src/test
parent060b22a99a67e01aa097f1a21d2123f166ccdb15 (diff)
Make contain_volatile_functions/contain_mutable_functions look into SubLinks.
This change prevents us from doing inappropriate subquery flattening in cases such as dangerous functions hidden inside a sub-SELECT in the targetlist of another sub-SELECT. That could result in unexpected behavior due to multiple evaluations of a volatile function, as in a recent complaint from Etienne Dube. It's been questionable from the very beginning whether these functions should look into subqueries (as noted in their comments), and this case seems to provide proof that they should. Because the new code only descends into SubLinks, not SubPlans or InitPlans, the change only affects the planner's behavior during prepjointree processing and not later on --- for example, you can still get it to use a volatile function in an indexqual if you wrap the function in (SELECT ...). That's a historical behavior, for sure, but it's reasonable given that the executor's evaluation rules for subplans don't depend on whether there are volatile functions inside them. In any case, we need to constrain the behavioral change as narrowly as we can to make this reasonable to back-patch.
Diffstat (limited to 'src/test')
-rw-r--r--src/test/regress/expected/subselect.out64
-rw-r--r--src/test/regress/sql/subselect.sql16
2 files changed, 80 insertions, 0 deletions
diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out
index 8bda3039d68..1baf3d3e23e 100644
--- a/src/test/regress/expected/subselect.out
+++ b/src/test/regress/expected/subselect.out
@@ -636,3 +636,67 @@ where a.thousand = b.thousand
----------
(0 rows)
+--
+-- Check that nested sub-selects are not pulled up if they contain volatiles
+--
+explain (verbose, costs off)
+ select x, x from
+ (select (select now()) as x from (values(1),(2)) v(y)) ss;
+ QUERY PLAN
+---------------------------
+ Values Scan on "*VALUES*"
+ Output: $0, $1
+ InitPlan 1 (returns $0)
+ -> Result
+ Output: now()
+ InitPlan 2 (returns $1)
+ -> Result
+ Output: now()
+(8 rows)
+
+explain (verbose, costs off)
+ select x, x from
+ (select (select random()) as x from (values(1),(2)) v(y)) ss;
+ QUERY PLAN
+----------------------------------
+ Subquery Scan on ss
+ Output: ss.x, ss.x
+ -> Values Scan on "*VALUES*"
+ Output: $0
+ InitPlan 1 (returns $0)
+ -> Result
+ Output: random()
+(7 rows)
+
+explain (verbose, costs off)
+ select x, x from
+ (select (select now() where y=y) as x from (values(1),(2)) v(y)) ss;
+ QUERY PLAN
+----------------------------------------------------------------------
+ Values Scan on "*VALUES*"
+ Output: (SubPlan 1), (SubPlan 2)
+ SubPlan 1
+ -> Result
+ Output: now()
+ One-Time Filter: ("*VALUES*".column1 = "*VALUES*".column1)
+ SubPlan 2
+ -> Result
+ Output: now()
+ One-Time Filter: ("*VALUES*".column1 = "*VALUES*".column1)
+(10 rows)
+
+explain (verbose, costs off)
+ select x, x from
+ (select (select random() where y=y) as x from (values(1),(2)) v(y)) ss;
+ QUERY PLAN
+----------------------------------------------------------------------------
+ Subquery Scan on ss
+ Output: ss.x, ss.x
+ -> Values Scan on "*VALUES*"
+ Output: (SubPlan 1)
+ SubPlan 1
+ -> Result
+ Output: random()
+ One-Time Filter: ("*VALUES*".column1 = "*VALUES*".column1)
+(8 rows)
+
diff --git a/src/test/regress/sql/subselect.sql b/src/test/regress/sql/subselect.sql
index 8a55474b54a..0795d435346 100644
--- a/src/test/regress/sql/subselect.sql
+++ b/src/test/regress/sql/subselect.sql
@@ -389,3 +389,19 @@ where a.thousand = b.thousand
and exists ( select 1 from tenk1 c where b.hundred = c.hundred
and not exists ( select 1 from tenk1 d
where a.thousand = d.thousand ) );
+
+--
+-- Check that nested sub-selects are not pulled up if they contain volatiles
+--
+explain (verbose, costs off)
+ select x, x from
+ (select (select now()) as x from (values(1),(2)) v(y)) ss;
+explain (verbose, costs off)
+ select x, x from
+ (select (select random()) as x from (values(1),(2)) v(y)) ss;
+explain (verbose, costs off)
+ select x, x from
+ (select (select now() where y=y) as x from (values(1),(2)) v(y)) ss;
+explain (verbose, costs off)
+ select x, x from
+ (select (select random() where y=y) as x from (values(1),(2)) v(y)) ss;