index 4fa73a9d223a731182b3e7da9c8c05ac392a6581..add29f54d09e68b30d1985eec7f0cf490be707d8 100644 (file)
@@ -833,8 +833,8 @@ contain_subplans_walker(Node *node, void *context)
* mistakenly think that something like "WHERE random() < 0.5" can be treated
* as a constant qualification.
*
- * XXX we do not examine sub-selects to see if they contain uses of
- * mutable functions. It's not real clear if that is correct or not...
+ * We will recursively look into Query nodes (i.e., SubLink sub-selects)
+ * but not into SubPlans. See comments for contain_volatile_functions().
*/
bool
contain_mutable_functions(Node *clause)
@@ -931,6 +931,13 @@ contain_mutable_functions_walker(Node *node, void *context)
}
/* else fall through to check args */
}
+ else if (IsA(node, Query))
+ {
+ /* Recurse into subselects */
+ return query_tree_walker((Query *) node,
+ contain_mutable_functions_walker,
+ context, 0);
+ }
return expression_tree_walker(node, contain_mutable_functions_walker,
context);
}
@@ -945,11 +952,18 @@ contain_mutable_functions_walker(Node *node, void *context)
* Recursively search for volatile functions within a clause.
*
* Returns true if any volatile function (or operator implemented by a
- * volatile function) is found. This test prevents invalid conversions
- * of volatile expressions into indexscan quals.
+ * volatile function) is found. This test prevents, for example,
+ * invalid conversions of volatile expressions into indexscan quals.
*
- * XXX we do not examine sub-selects to see if they contain uses of
- * volatile functions. It's not real clear if that is correct or not...
+ * We will recursively look into Query nodes (i.e., SubLink sub-selects)
+ * but not into SubPlans. This is a bit odd, but intentional. If we are
+ * looking at a SubLink, we are probably deciding whether a query tree
+ * transformation is safe, and a contained sub-select should affect that;
+ * for example, duplicating a sub-select containing a volatile function
+ * would be bad. However, once we've got to the stage of having SubPlans,
+ * subsequent planning need not consider volatility within those, since
+ * the executor won't change its evaluation rules for a SubPlan based on
+ * volatility.
*/
bool
contain_volatile_functions(Node *clause)
@@ -1047,6 +1061,13 @@ contain_volatile_functions_walker(Node *node, void *context)
}
/* else fall through to check args */
}
+ else if (IsA(node, Query))
+ {
+ /* Recurse into subselects */
+ return query_tree_walker((Query *) node,
+ contain_volatile_functions_walker,
+ context, 0);
+ }
return expression_tree_walker(node, contain_volatile_functions_walker,
context);
}
index 8bda3039d689d8e3a881b948c3886d3ee5fbf312..1baf3d3e23eecbe00080b6c21984e5b4624565d6 100644 (file)
----------
(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)
+
index 8a55474b54a0ea5699011a47545277154835e40d..0795d4353461a800be54936f898ed6c276417bd9 100644 (file)
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;