summaryrefslogtreecommitdiff
path: root/src/include/parser
diff options
context:
space:
mode:
authorTom Lane2017-06-14 03:46:39 +0000
committerTom Lane2017-06-14 03:46:39 +0000
commit0436f6bde8848b7135f19dd7f8548b8c2ae89a34 (patch)
tree1c5a41e86292abb39ea1d33ea1d301a72e4f850e /src/include/parser
parent39da0f709db4d9f16f46be56ae401df72aab93c0 (diff)
Disallow set-returning functions inside CASE or COALESCE.
When we reimplemented SRFs in commit 69f4b9c85, our initial choice was to allow the behavior to vary from historical practice in cases where a SRF call appeared within a conditional-execution construct (currently, only CASE or COALESCE). But that was controversial to begin with, and subsequent discussion has resulted in a consensus that it's better to throw an error instead of executing the query differently from before, so long as we can provide a reasonably clear error message and a way to rewrite the query. Hence, add a parser mechanism to allow detection of such cases during parse analysis. The mechanism just requires storing, in the ParseState, a pointer to the set-returning FuncExpr or OpExpr most recently emitted by parse analysis. Then the parsing functions for CASE and COALESCE can detect the presence of a SRF in their arguments by noting whether this pointer changes while analyzing their arguments. Furthermore, if it does, it provides a suitable error cursor location for the complaint. (This means that if there's more than one SRF in the arguments, the error will point at the last one to be analyzed not the first. While connoisseurs of parsing behavior might find that odd, it's unlikely the average user would ever notice.) While at it, we can also provide more specific error messages than before about some pre-existing restrictions, such as no-SRFs-within-aggregates. Also, reject at parse time cases where a NULLIF or IS DISTINCT FROM construct would need to return a set. We've never supported that, but the restriction is depended on in more subtle ways now, so it seems wise to detect it at the start. Also, provide some documentation about how to rewrite a SRF-within-CASE query using a custom wrapper SRF. It turns out that the information_schema.user_mapping_options view contained an instance of exactly the behavior we're now forbidding; but rewriting it makes it more clear and safer too. initdb forced because of user_mapping_options change. Patch by me, with error message suggestions from Alvaro Herrera and Andres Freund, pursuant to a complaint from Regina Obe. Discussion: https://postgr.es/m/000001d2d5de$d8d66170$8a832450$@pcorp.us
Diffstat (limited to 'src/include/parser')
-rw-r--r--src/include/parser/parse_func.h5
-rw-r--r--src/include/parser/parse_node.h5
-rw-r--r--src/include/parser/parse_oper.h2
3 files changed, 9 insertions, 3 deletions
diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h
index 5be1812242a..68572e9d2a9 100644
--- a/src/include/parser/parse_func.h
+++ b/src/include/parser/parse_func.h
@@ -31,7 +31,7 @@ typedef enum
extern Node *ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
- FuncCall *fn, int location);
+ Node *last_srf, FuncCall *fn, int location);
extern FuncDetailCode func_get_detail(List *funcname,
List *fargs, List *fargnames,
@@ -67,6 +67,7 @@ extern Oid LookupFuncWithArgs(ObjectWithArgs *func,
extern Oid LookupAggWithArgs(ObjectWithArgs *agg,
bool noError);
-extern void check_srf_call_placement(ParseState *pstate, int location);
+extern void check_srf_call_placement(ParseState *pstate, Node *last_srf,
+ int location);
#endif /* PARSE_FUNC_H */
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index 0b54840e295..6a3507f3b14 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -157,6 +157,9 @@ typedef Node *(*CoerceParamHook) (ParseState *pstate, Param *param,
* p_hasAggs, p_hasWindowFuncs, etc: true if we've found any of the indicated
* constructs in the query.
*
+ * p_last_srf: the set-returning FuncExpr or OpExpr most recently found in
+ * the query, or NULL if none.
+ *
* p_pre_columnref_hook, etc: optional parser hook functions for modifying the
* interpretation of ColumnRefs and ParamRefs.
*
@@ -199,6 +202,8 @@ struct ParseState
bool p_hasSubLinks;
bool p_hasModifyingCTE;
+ Node *p_last_srf; /* most recent set-returning func/op found */
+
/*
* Optional hook functions for parser callbacks. These are null unless
* set up by the caller of make_parsestate.
diff --git a/src/include/parser/parse_oper.h b/src/include/parser/parse_oper.h
index d783b37f0f5..ab3c4aa62f6 100644
--- a/src/include/parser/parse_oper.h
+++ b/src/include/parser/parse_oper.h
@@ -59,7 +59,7 @@ extern Oid oprfuncid(Operator op);
/* Build expression tree for an operator invocation */
extern Expr *make_op(ParseState *pstate, List *opname,
- Node *ltree, Node *rtree, int location);
+ Node *ltree, Node *rtree, Node *last_srf, int location);
extern Expr *make_scalar_array_op(ParseState *pstate, List *opname,
bool useOr,
Node *ltree, Node *rtree, int location);