diff options
Diffstat (limited to 'src/backend/parser/parse_func.c')
-rw-r--r-- | src/backend/parser/parse_func.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 61af484feeb..56c9a4293df 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -25,6 +25,7 @@ #include "parser/parse_agg.h" #include "parser/parse_clause.h" #include "parser/parse_coerce.h" +#include "parser/parse_expr.h" #include "parser/parse_func.h" #include "parser/parse_relation.h" #include "parser/parse_target.h" @@ -625,6 +626,10 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, exprLocation((Node *) llast(fargs))))); } + /* if it returns a set, check that's OK */ + if (retset) + check_srf_call_placement(pstate, location); + /* build the appropriate output structure */ if (fdresult == FUNCDETAIL_NORMAL) { @@ -2040,3 +2045,146 @@ LookupAggNameTypeNames(List *aggname, List *argtypes, bool noError) return oid; } + + +/* + * check_srf_call_placement + * Verify that a set-returning function is called in a valid place, + * and throw a nice error if not. + * + * A side-effect is to set pstate->p_hasTargetSRFs true if appropriate. + */ +void +check_srf_call_placement(ParseState *pstate, int location) +{ + const char *err; + bool errkind; + + /* + * Check to see if the set-returning function is in an invalid place + * within the query. Basically, we don't allow SRFs anywhere except in + * the targetlist (which includes GROUP BY/ORDER BY expressions), VALUES, + * and functions in FROM. + * + * For brevity we support two schemes for reporting an error here: set + * "err" to a custom message, or set "errkind" true if the error context + * is sufficiently identified by what ParseExprKindName will return, *and* + * what it will return is just a SQL keyword. (Otherwise, use a custom + * message to avoid creating translation problems.) + */ + err = NULL; + errkind = false; + switch (pstate->p_expr_kind) + { + case EXPR_KIND_NONE: + Assert(false); /* can't happen */ + break; + case EXPR_KIND_OTHER: + /* Accept SRF here; caller must throw error if wanted */ + break; + case EXPR_KIND_JOIN_ON: + case EXPR_KIND_JOIN_USING: + err = _("set-returning functions are not allowed in JOIN conditions"); + break; + case EXPR_KIND_FROM_SUBSELECT: + /* can't get here, but just in case, throw an error */ + errkind = true; + break; + case EXPR_KIND_FROM_FUNCTION: + /* okay ... but we can't check nesting here */ + break; + case EXPR_KIND_WHERE: + errkind = true; + break; + case EXPR_KIND_POLICY: + err = _("set-returning functions are not allowed in policy expressions"); + break; + case EXPR_KIND_HAVING: + errkind = true; + break; + case EXPR_KIND_FILTER: + errkind = true; + break; + case EXPR_KIND_WINDOW_PARTITION: + case EXPR_KIND_WINDOW_ORDER: + /* okay, these are effectively GROUP BY/ORDER BY */ + pstate->p_hasTargetSRFs = true; + break; + case EXPR_KIND_WINDOW_FRAME_RANGE: + case EXPR_KIND_WINDOW_FRAME_ROWS: + err = _("set-returning functions are not allowed in window definitions"); + break; + case EXPR_KIND_SELECT_TARGET: + case EXPR_KIND_INSERT_TARGET: + /* okay */ + pstate->p_hasTargetSRFs = true; + break; + case EXPR_KIND_UPDATE_SOURCE: + case EXPR_KIND_UPDATE_TARGET: + /* disallowed because it would be ambiguous what to do */ + errkind = true; + break; + case EXPR_KIND_GROUP_BY: + case EXPR_KIND_ORDER_BY: + /* okay */ + pstate->p_hasTargetSRFs = true; + break; + case EXPR_KIND_DISTINCT_ON: + /* okay */ + pstate->p_hasTargetSRFs = true; + break; + case EXPR_KIND_LIMIT: + case EXPR_KIND_OFFSET: + errkind = true; + break; + case EXPR_KIND_RETURNING: + errkind = true; + break; + case EXPR_KIND_VALUES: + /* okay */ + break; + case EXPR_KIND_CHECK_CONSTRAINT: + case EXPR_KIND_DOMAIN_CHECK: + err = _("set-returning functions are not allowed in check constraints"); + break; + case EXPR_KIND_COLUMN_DEFAULT: + case EXPR_KIND_FUNCTION_DEFAULT: + err = _("set-returning functions are not allowed in DEFAULT expressions"); + break; + case EXPR_KIND_INDEX_EXPRESSION: + err = _("set-returning functions are not allowed in index expressions"); + break; + case EXPR_KIND_INDEX_PREDICATE: + err = _("set-returning functions are not allowed in index predicates"); + break; + case EXPR_KIND_ALTER_COL_TRANSFORM: + err = _("set-returning functions are not allowed in transform expressions"); + break; + case EXPR_KIND_EXECUTE_PARAMETER: + err = _("set-returning functions are not allowed in EXECUTE parameters"); + break; + case EXPR_KIND_TRIGGER_WHEN: + err = _("set-returning functions are not allowed in trigger WHEN conditions"); + break; + + /* + * There is intentionally no default: case here, so that the + * compiler will warn if we add a new ParseExprKind without + * extending this switch. If we do see an unrecognized value at + * runtime, the behavior will be the same as for EXPR_KIND_OTHER, + * which is sane anyway. + */ + } + if (err) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg_internal("%s", err), + parser_errposition(pstate, location))); + if (errkind) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + /* translator: %s is name of a SQL construct, eg GROUP BY */ + errmsg("set-returning functions are not allowed in %s", + ParseExprKindName(pstate->p_expr_kind)), + parser_errposition(pstate, location))); +} |