]> granicus.if.org Git - postgresql/commitdiff
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 10 Aug 2012 15:35:33 +0000 (11:35 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 10 Aug 2012 15:36:15 +0000 (11:36 -0400)
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree.  To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed.  This allows removal of a large number of ad-hoc
checks scattered around the code base.  The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.

Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.

Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.

In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone.  (I didn't risk actually removing said dead code, though.)

29 files changed:
src/backend/catalog/heap.c
src/backend/commands/functioncmds.c
src/backend/commands/indexcmds.c
src/backend/commands/prepare.c
src/backend/commands/tablecmds.c
src/backend/commands/trigger.c
src/backend/commands/typecmds.c
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/var.c
src/backend/parser/analyze.c
src/backend/parser/parse_agg.c
src/backend/parser/parse_clause.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_node.c
src/backend/parser/parse_target.c
src/backend/parser/parse_utilcmd.c
src/backend/rewrite/rewriteManip.c
src/include/optimizer/var.h
src/include/parser/parse_agg.h
src/include/parser/parse_clause.h
src/include/parser/parse_expr.h
src/include/parser/parse_node.h
src/include/parser/parse_target.h
src/include/rewrite/rewriteManip.h
src/test/regress/expected/aggregates.out
src/test/regress/expected/join.out
src/test/regress/expected/window.out
src/test/regress/expected/with.out
src/test/regress/sql/aggregates.sql

index c91df9003811d1ff24590e88271a3c579c4a52f1..a08830121f68b652fabdfca678f4328350a7ee75 100644 (file)
@@ -2415,10 +2415,11 @@ cookDefault(ParseState *pstate,
        /*
         * Transform raw parsetree to executable expression.
         */
-       expr = transformExpr(pstate, raw_default);
+       expr = transformExpr(pstate, raw_default, EXPR_KIND_COLUMN_DEFAULT);
 
        /*
-        * Make sure default expr does not refer to any vars.
+        * Make sure default expr does not refer to any vars (we need this check
+        * since the pstate includes the target table).
         */
        if (contain_var_clause(expr))
                ereport(ERROR,
@@ -2426,6 +2427,9 @@ cookDefault(ParseState *pstate,
                          errmsg("cannot use column references in default expression")));
 
        /*
+        * transformExpr() should have already rejected subqueries, aggregates,
+        * and window functions, based on the EXPR_KIND_ for a default expression.
+        *
         * It can't return a set either.
         */
        if (expression_returns_set(expr))
@@ -2433,22 +2437,6 @@ cookDefault(ParseState *pstate,
                                (errcode(ERRCODE_DATATYPE_MISMATCH),
                                 errmsg("default expression must not return a set")));
 
-       /*
-        * No subplans or aggregates, either...
-        */
-       if (pstate->p_hasSubLinks)
-               ereport(ERROR,
-                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                errmsg("cannot use subquery in default expression")));
-       if (pstate->p_hasAggs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_GROUPING_ERROR),
-                        errmsg("cannot use aggregate function in default expression")));
-       if (pstate->p_hasWindowFuncs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_WINDOWING_ERROR),
-                                errmsg("cannot use window function in default expression")));
-
        /*
         * Coerce the expression to the correct type and typmod, if given. This
         * should match the parser's processing of non-defaulted expressions ---
@@ -2499,7 +2487,7 @@ cookConstraint(ParseState *pstate,
        /*
         * Transform raw parsetree to executable expression.
         */
-       expr = transformExpr(pstate, raw_constraint);
+       expr = transformExpr(pstate, raw_constraint, EXPR_KIND_CHECK_CONSTRAINT);
 
        /*
         * Make sure it yields a boolean result.
@@ -2512,7 +2500,8 @@ cookConstraint(ParseState *pstate,
        assign_expr_collations(pstate, expr);
 
        /*
-        * Make sure no outside relations are referred to.
+        * Make sure no outside relations are referred to (this is probably dead
+        * code now that add_missing_from is history).
         */
        if (list_length(pstate->p_rtable) != 1)
                ereport(ERROR,
@@ -2520,22 +2509,6 @@ cookConstraint(ParseState *pstate,
                        errmsg("only table \"%s\" can be referenced in check constraint",
                                   relname)));
 
-       /*
-        * No subplans or aggregates, either...
-        */
-       if (pstate->p_hasSubLinks)
-               ereport(ERROR,
-                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                errmsg("cannot use subquery in check constraint")));
-       if (pstate->p_hasAggs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_GROUPING_ERROR),
-                          errmsg("cannot use aggregate function in check constraint")));
-       if (pstate->p_hasWindowFuncs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_WINDOWING_ERROR),
-                                errmsg("cannot use window function in check constraint")));
-
        return expr;
 }
 
index 9ba6dd8fcf19ce500ca80163aed637aa3e11d983..dcadb3dc84a257eb3b3638038f591d8eefd96f98 100644 (file)
@@ -344,12 +344,14 @@ examine_parameter_list(List *parameters, Oid languageOid,
                                                (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                                   errmsg("only input parameters can have default values")));
 
-                       def = transformExpr(pstate, fp->defexpr);
+                       def = transformExpr(pstate, fp->defexpr,
+                                                               EXPR_KIND_FUNCTION_DEFAULT);
                        def = coerce_to_specific_type(pstate, def, toid, "DEFAULT");
                        assign_expr_collations(pstate, def);
 
                        /*
-                        * Make sure no variables are referred to.
+                        * Make sure no variables are referred to (this is probably dead
+                        * code now that add_missing_from is history).
                         */
                        if (list_length(pstate->p_rtable) != 0 ||
                                contain_var_clause(def))
@@ -358,28 +360,18 @@ examine_parameter_list(List *parameters, Oid languageOid,
                                                 errmsg("cannot use table references in parameter default value")));
 
                        /*
+                        * transformExpr() should have already rejected subqueries,
+                        * aggregates, and window functions, based on the EXPR_KIND_ for a
+                        * default expression.
+                        *
                         * It can't return a set either --- but coerce_to_specific_type
                         * already checked that for us.
                         *
-                        * No subplans or aggregates, either...
-                        *
                         * Note: the point of these restrictions is to ensure that an
                         * expression that, on its face, hasn't got subplans, aggregates,
                         * etc cannot suddenly have them after function default arguments
                         * are inserted.
                         */
-                       if (pstate->p_hasSubLinks)
-                               ereport(ERROR,
-                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                 errmsg("cannot use subquery in parameter default value")));
-                       if (pstate->p_hasAggs)
-                               ereport(ERROR,
-                                               (errcode(ERRCODE_GROUPING_ERROR),
-                                                errmsg("cannot use aggregate function in parameter default value")));
-                       if (pstate->p_hasWindowFuncs)
-                               ereport(ERROR,
-                                               (errcode(ERRCODE_WINDOWING_ERROR),
-                                                errmsg("cannot use window function in parameter default value")));
 
                        *parameterDefaults = lappend(*parameterDefaults, def);
                        have_defaults = true;
index a0840d1bf06f89afa669cea0d83476c5925d1f46..f677268609186f3f52921800228657f805f7b089 100644 (file)
@@ -941,17 +941,9 @@ static void
 CheckPredicate(Expr *predicate)
 {
        /*
-        * We don't currently support generation of an actual query plan for a
-        * predicate, only simple scalar expressions; hence these restrictions.
+        * transformExpr() should have already rejected subqueries, aggregates,
+        * and window functions, based on the EXPR_KIND_ for a predicate.
         */
-       if (contain_subplans((Node *) predicate))
-               ereport(ERROR,
-                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                errmsg("cannot use subquery in index predicate")));
-       if (contain_agg_clause((Node *) predicate))
-               ereport(ERROR,
-                               (errcode(ERRCODE_GROUPING_ERROR),
-                                errmsg("cannot use aggregate in index predicate")));
 
        /*
         * A predicate using mutable functions is probably wrong, for the same
@@ -1072,18 +1064,10 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
                                                                                                        expr);
 
                                /*
-                                * We don't currently support generation of an actual query
-                                * plan for an index expression, only simple scalar
-                                * expressions; hence these restrictions.
+                                * transformExpr() should have already rejected subqueries,
+                                * aggregates, and window functions, based on the EXPR_KIND_
+                                * for an index expression.
                                 */
-                               if (contain_subplans(expr))
-                                       ereport(ERROR,
-                                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                                errmsg("cannot use subquery in index expression")));
-                               if (contain_agg_clause(expr))
-                                       ereport(ERROR,
-                                                       (errcode(ERRCODE_GROUPING_ERROR),
-                                                        errmsg("cannot use aggregate function in index expression")));
 
                                /*
                                 * A expression using mutable functions is probably wrong,
index 2d87b1c69078edcf7ee47316ee4d391d3c0f40dc..9f993de6f1a80465631fb1ae041ce415c25f9ca6 100644 (file)
@@ -354,21 +354,7 @@ EvaluateParams(PreparedStatement *pstmt, List *params,
                Oid                     expected_type_id = param_types[i];
                Oid                     given_type_id;
 
-               expr = transformExpr(pstate, expr);
-
-               /* Cannot contain subselects or aggregates */
-               if (pstate->p_hasSubLinks)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                        errmsg("cannot use subquery in EXECUTE parameter")));
-               if (pstate->p_hasAggs)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_GROUPING_ERROR),
-                         errmsg("cannot use aggregate function in EXECUTE parameter")));
-               if (pstate->p_hasWindowFuncs)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_WINDOWING_ERROR),
-                                errmsg("cannot use window function in EXECUTE parameter")));
+               expr = transformExpr(pstate, expr, EXPR_KIND_EXECUTE_PARAMETER);
 
                given_type_id = exprType(expr);
 
index 8e611e8f5cbb4ad7eca1fec94e0903b8915eab53..a69544853fa1b55f648cc110cc079ffc98e962fa 100644 (file)
@@ -7178,27 +7178,14 @@ ATPrepAlterColumnType(List **wqueue,
                                                                                                true);
                        addRTEtoQuery(pstate, rte, false, true, true);
 
-                       transform = transformExpr(pstate, transform);
+                       transform = transformExpr(pstate, transform,
+                                                                         EXPR_KIND_ALTER_COL_TRANSFORM);
 
                        /* It can't return a set */
                        if (expression_returns_set(transform))
                                ereport(ERROR,
                                                (errcode(ERRCODE_DATATYPE_MISMATCH),
                                          errmsg("transform expression must not return a set")));
-
-                       /* No subplans or aggregates, either... */
-                       if (pstate->p_hasSubLinks)
-                               ereport(ERROR,
-                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                        errmsg("cannot use subquery in transform expression")));
-                       if (pstate->p_hasAggs)
-                               ereport(ERROR,
-                                               (errcode(ERRCODE_GROUPING_ERROR),
-                                                errmsg("cannot use aggregate function in transform expression")));
-                       if (pstate->p_hasWindowFuncs)
-                               ereport(ERROR,
-                                               (errcode(ERRCODE_WINDOWING_ERROR),
-                                                errmsg("cannot use window function in transform expression")));
                }
                else
                {
index 5bea202240281665b6f811f74b5b6c2c65148a9e..e7576fc9ea9e5644e956028d558d8453b5e6950b 100644 (file)
@@ -286,26 +286,11 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
                /* Transform expression.  Copy to be sure we don't modify original */
                whenClause = transformWhereClause(pstate,
                                                                                  copyObject(stmt->whenClause),
+                                                                                 EXPR_KIND_TRIGGER_WHEN,
                                                                                  "WHEN");
                /* we have to fix its collations too */
                assign_expr_collations(pstate, whenClause);
 
-               /*
-                * No subplans or aggregates, please
-                */
-               if (pstate->p_hasSubLinks)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                  errmsg("cannot use subquery in trigger WHEN condition")));
-               if (pstate->p_hasAggs)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_GROUPING_ERROR),
-                                        errmsg("cannot use aggregate function in trigger WHEN condition")));
-               if (pstate->p_hasWindowFuncs)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_WINDOWING_ERROR),
-                       errmsg("cannot use window function in trigger WHEN condition")));
-
                /*
                 * Check for disallowed references to OLD/NEW.
                 *
index 353043d581ac78c1bdf4b3972a8ba5dde3754ebf..7fc3ad7e73609c5fcf5c45cd9f2de99a67f5602c 100644 (file)
@@ -2871,7 +2871,7 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
 
        pstate->p_value_substitute = (Node *) domVal;
 
-       expr = transformExpr(pstate, constr->raw_expr);
+       expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
 
        /*
         * Make sure it yields a boolean result.
@@ -2884,38 +2884,15 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
        assign_expr_collations(pstate, expr);
 
        /*
-        * Make sure no outside relations are referred to.
+        * Domains don't allow variables (this is probably dead code now that
+        * add_missing_from is history, but let's be sure).
         */
-       if (list_length(pstate->p_rtable) != 0)
+       if (list_length(pstate->p_rtable) != 0 ||
+               contain_var_clause(expr))
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
                  errmsg("cannot use table references in domain check constraint")));
 
-       /*
-        * Domains don't allow var clauses (this should be redundant with the
-        * above check, but make it anyway)
-        */
-       if (contain_var_clause(expr))
-               ereport(ERROR,
-                               (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
-                 errmsg("cannot use table references in domain check constraint")));
-
-       /*
-        * No subplans or aggregates, either...
-        */
-       if (pstate->p_hasSubLinks)
-               ereport(ERROR,
-                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                errmsg("cannot use subquery in check constraint")));
-       if (pstate->p_hasAggs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_GROUPING_ERROR),
-                          errmsg("cannot use aggregate function in check constraint")));
-       if (pstate->p_hasWindowFuncs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_WINDOWING_ERROR),
-                                errmsg("cannot use window function in check constraint")));
-
        /*
         * Convert to string form for storage.
         */
index c2d36ca38d8d98d2a307cd3d2a5143a9545665ef..c339f132289050941fd5491aaf27e3f02785c433 100644 (file)
@@ -596,7 +596,7 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
 bool
 contain_window_function(Node *clause)
 {
-       return checkExprHasWindowFuncs(clause);
+       return contain_windowfuncs(clause);
 }
 
 /*
index 81332ff1cd183fd101f3ca884fbf406941af7523..1d88a7782030a6bd595833b047a19a98d94a246e 100644 (file)
@@ -52,12 +52,6 @@ typedef struct
        int                     sublevels_up;
 } locate_var_of_level_context;
 
-typedef struct
-{
-       int                     min_varlevel;
-       int                     sublevels_up;
-} find_minimum_var_level_context;
-
 typedef struct
 {
        List       *varlist;
@@ -81,8 +75,6 @@ static bool contain_var_clause_walker(Node *node, void *context);
 static bool contain_vars_of_level_walker(Node *node, int *sublevels_up);
 static bool locate_var_of_level_walker(Node *node,
                                                   locate_var_of_level_context *context);
-static bool find_minimum_var_level_walker(Node *node,
-                                                         find_minimum_var_level_context *context);
 static bool pull_var_clause_walker(Node *node,
                                           pull_var_clause_context *context);
 static Node *flatten_join_alias_vars_mutator(Node *node,
@@ -488,159 +480,6 @@ locate_var_of_level_walker(Node *node,
 }
 
 
-/*
- * find_minimum_var_level
- *       Recursively scan a clause to find the lowest variable level it
- *       contains --- for example, zero is returned if there are any local
- *       variables, one if there are no local variables but there are
- *       one-level-up outer references, etc.  Subqueries are scanned to see
- *       if they possess relevant outer references.  (But any local variables
- *       within subqueries are not relevant.)
- *
- *       -1 is returned if the clause has no variables at all.
- *
- * Will recurse into sublinks. Also, may be invoked directly on a Query.
- */
-int
-find_minimum_var_level(Node *node)
-{
-       find_minimum_var_level_context context;
-
-       context.min_varlevel = -1;      /* signifies nothing found yet */
-       context.sublevels_up = 0;
-
-       (void) query_or_expression_tree_walker(node,
-                                                                                  find_minimum_var_level_walker,
-                                                                                  (void *) &context,
-                                                                                  0);
-
-       return context.min_varlevel;
-}
-
-static bool
-find_minimum_var_level_walker(Node *node,
-                                                         find_minimum_var_level_context *context)
-{
-       if (node == NULL)
-               return false;
-       if (IsA(node, Var))
-       {
-               int                     varlevelsup = ((Var *) node)->varlevelsup;
-
-               /* convert levelsup to frame of reference of original query */
-               varlevelsup -= context->sublevels_up;
-               /* ignore local vars of subqueries */
-               if (varlevelsup >= 0)
-               {
-                       if (context->min_varlevel < 0 ||
-                               context->min_varlevel > varlevelsup)
-                       {
-                               context->min_varlevel = varlevelsup;
-
-                               /*
-                                * As soon as we find a local variable, we can abort the tree
-                                * traversal, since min_varlevel is then certainly 0.
-                                */
-                               if (varlevelsup == 0)
-                                       return true;
-                       }
-               }
-       }
-       if (IsA(node, CurrentOfExpr))
-       {
-               int                     varlevelsup = 0;
-
-               /* convert levelsup to frame of reference of original query */
-               varlevelsup -= context->sublevels_up;
-               /* ignore local vars of subqueries */
-               if (varlevelsup >= 0)
-               {
-                       if (context->min_varlevel < 0 ||
-                               context->min_varlevel > varlevelsup)
-                       {
-                               context->min_varlevel = varlevelsup;
-
-                               /*
-                                * As soon as we find a local variable, we can abort the tree
-                                * traversal, since min_varlevel is then certainly 0.
-                                */
-                               if (varlevelsup == 0)
-                                       return true;
-                       }
-               }
-       }
-
-       /*
-        * An Aggref must be treated like a Var of its level.  Normally we'd get
-        * the same result from looking at the Vars in the aggregate's argument,
-        * but this fails in the case of a Var-less aggregate call (COUNT(*)).
-        */
-       if (IsA(node, Aggref))
-       {
-               int                     agglevelsup = ((Aggref *) node)->agglevelsup;
-
-               /* convert levelsup to frame of reference of original query */
-               agglevelsup -= context->sublevels_up;
-               /* ignore local aggs of subqueries */
-               if (agglevelsup >= 0)
-               {
-                       if (context->min_varlevel < 0 ||
-                               context->min_varlevel > agglevelsup)
-                       {
-                               context->min_varlevel = agglevelsup;
-
-                               /*
-                                * As soon as we find a local aggregate, we can abort the tree
-                                * traversal, since min_varlevel is then certainly 0.
-                                */
-                               if (agglevelsup == 0)
-                                       return true;
-                       }
-               }
-       }
-       /* Likewise, make sure PlaceHolderVar is treated correctly */
-       if (IsA(node, PlaceHolderVar))
-       {
-               int                     phlevelsup = ((PlaceHolderVar *) node)->phlevelsup;
-
-               /* convert levelsup to frame of reference of original query */
-               phlevelsup -= context->sublevels_up;
-               /* ignore local vars of subqueries */
-               if (phlevelsup >= 0)
-               {
-                       if (context->min_varlevel < 0 ||
-                               context->min_varlevel > phlevelsup)
-                       {
-                               context->min_varlevel = phlevelsup;
-
-                               /*
-                                * As soon as we find a local variable, we can abort the tree
-                                * traversal, since min_varlevel is then certainly 0.
-                                */
-                               if (phlevelsup == 0)
-                                       return true;
-                       }
-               }
-       }
-       if (IsA(node, Query))
-       {
-               /* Recurse into subselects */
-               bool            result;
-
-               context->sublevels_up++;
-               result = query_tree_walker((Query *) node,
-                                                                  find_minimum_var_level_walker,
-                                                                  (void *) context,
-                                                                  0);
-               context->sublevels_up--;
-               return result;
-       }
-       return expression_tree_walker(node,
-                                                                 find_minimum_var_level_walker,
-                                                                 (void *) context);
-}
-
-
 /*
  * pull_var_clause
  *       Recursively pulls all Var nodes from an expression clause.
index 93ef724ffff6c51850aca1292e9d6388a0f97a0b..6c3d89a14f6b1f19176864af4a0ea18eebd9f4bd 100644 (file)
@@ -368,7 +368,8 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
         */
        transformFromClause(pstate, stmt->usingClause);
 
-       qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
+       qual = transformWhereClause(pstate, stmt->whereClause,
+                                                               EXPR_KIND_WHERE, "WHERE");
 
        qry->returningList = transformReturningList(pstate, stmt->returningList);
 
@@ -378,8 +379,6 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
 
        qry->hasSubLinks = pstate->p_hasSubLinks;
        qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
-       if (pstate->p_hasWindowFuncs)
-               parseCheckWindowFuncs(pstate, qry);
        qry->hasAggs = pstate->p_hasAggs;
        if (pstate->p_hasAggs)
                parseCheckAggregates(pstate, qry);
@@ -597,7 +596,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
                        List       *sublist = (List *) lfirst(lc);
 
                        /* Do basic expression transformation (same as a ROW() expr) */
-                       sublist = transformExpressionList(pstate, sublist);
+                       sublist = transformExpressionList(pstate, sublist, EXPR_KIND_VALUES);
 
                        /*
                         * All the sublists must be the same length, *after*
@@ -680,16 +679,11 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
        }
        else
        {
-               /*----------
-                * Process INSERT ... VALUES with a single VALUES sublist.
-                * We treat this separately for efficiency and for historical
-                * compatibility --- specifically, allowing table references,
-                * such as
-                *                      INSERT INTO foo VALUES(bar.*)
-                *
-                * The sublist is just computed directly as the Query's targetlist,
-                * with no VALUES RTE.  So it works just like SELECT without FROM.
-                *----------
+               /*
+                * Process INSERT ... VALUES with a single VALUES sublist.  We treat
+                * this case separately for efficiency.  The sublist is just computed
+                * directly as the Query's targetlist, with no VALUES RTE.  So it
+                * works just like a SELECT without any FROM.
                 */
                List       *valuesLists = selectStmt->valuesLists;
 
@@ -698,7 +692,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
 
                /* Do basic expression transformation (same as a ROW() expr) */
                exprList = transformExpressionList(pstate,
-                                                                                  (List *) linitial(valuesLists));
+                                                                                  (List *) linitial(valuesLists),
+                                                                                  EXPR_KIND_VALUES);
 
                /* Prepare row for assignment to target table */
                exprList = transformInsertRow(pstate, exprList,
@@ -758,19 +753,6 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
        qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
 
        qry->hasSubLinks = pstate->p_hasSubLinks;
-       /* aggregates not allowed (but subselects are okay) */
-       if (pstate->p_hasAggs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_GROUPING_ERROR),
-                                errmsg("cannot use aggregate function in VALUES"),
-                                parser_errposition(pstate,
-                                                                       locate_agg_of_level((Node *) qry, 0))));
-       if (pstate->p_hasWindowFuncs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_WINDOWING_ERROR),
-                                errmsg("cannot use window function in VALUES"),
-                                parser_errposition(pstate,
-                                                                       locate_windowfunc((Node *) qry))));
 
        assign_query_collations(pstate, qry);
 
@@ -845,6 +827,7 @@ transformInsertRow(ParseState *pstate, List *exprlist,
                Assert(IsA(col, ResTarget));
 
                expr = transformAssignedExpr(pstate, expr,
+                                                                        EXPR_KIND_INSERT_TARGET,
                                                                         col->name,
                                                                         lfirst_int(attnos),
                                                                         col->indirection,
@@ -945,19 +928,19 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
        transformFromClause(pstate, stmt->fromClause);
 
        /* transform targetlist */
-       qry->targetList = transformTargetList(pstate, stmt->targetList);
+       qry->targetList = transformTargetList(pstate, stmt->targetList,
+                                                                                 EXPR_KIND_SELECT_TARGET);
 
        /* mark column origins */
        markTargetListOrigins(pstate, qry->targetList);
 
        /* transform WHERE */
-       qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
+       qual = transformWhereClause(pstate, stmt->whereClause,
+                                                               EXPR_KIND_WHERE, "WHERE");
 
-       /*
-        * Initial processing of HAVING clause is just like WHERE clause.
-        */
+       /* initial processing of HAVING clause is much like WHERE clause */
        qry->havingQual = transformWhereClause(pstate, stmt->havingClause,
-                                                                                  "HAVING");
+                                                                                  EXPR_KIND_HAVING, "HAVING");
 
        /*
         * Transform sorting/grouping stuff.  Do ORDER BY first because both
@@ -968,6 +951,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
        qry->sortClause = transformSortClause(pstate,
                                                                                  stmt->sortClause,
                                                                                  &qry->targetList,
+                                                                                 EXPR_KIND_ORDER_BY,
                                                                                  true /* fix unknowns */ ,
                                                                                  false /* allow SQL92 rules */ );
 
@@ -975,6 +959,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
                                                                                        stmt->groupClause,
                                                                                        &qry->targetList,
                                                                                        qry->sortClause,
+                                                                                       EXPR_KIND_GROUP_BY,
                                                                                        false /* allow SQL92 rules */ );
 
        if (stmt->distinctClause == NIL)
@@ -1003,9 +988,9 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
 
        /* transform LIMIT */
        qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset,
-                                                                                       "OFFSET");
+                                                                                       EXPR_KIND_OFFSET, "OFFSET");
        qry->limitCount = transformLimitClause(pstate, stmt->limitCount,
-                                                                                  "LIMIT");
+                                                                                  EXPR_KIND_LIMIT, "LIMIT");
 
        /* transform window clauses after we have seen all window functions */
        qry->windowClause = transformWindowDefinitions(pstate,
@@ -1017,8 +1002,6 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
 
        qry->hasSubLinks = pstate->p_hasSubLinks;
        qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
-       if (pstate->p_hasWindowFuncs)
-               parseCheckWindowFuncs(pstate, qry);
        qry->hasAggs = pstate->p_hasAggs;
        if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
                parseCheckAggregates(pstate, qry);
@@ -1090,7 +1073,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
                List       *sublist = (List *) lfirst(lc);
 
                /* Do basic expression transformation (same as a ROW() expr) */
-               sublist = transformExpressionList(pstate, sublist);
+               sublist = transformExpressionList(pstate, sublist, EXPR_KIND_VALUES);
 
                /*
                 * All the sublists must be the same length, *after* transformation
@@ -1217,13 +1200,14 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
        qry->sortClause = transformSortClause(pstate,
                                                                                  stmt->sortClause,
                                                                                  &qry->targetList,
+                                                                                 EXPR_KIND_ORDER_BY,
                                                                                  true /* fix unknowns */ ,
                                                                                  false /* allow SQL92 rules */ );
 
        qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset,
-                                                                                       "OFFSET");
+                                                                                       EXPR_KIND_OFFSET, "OFFSET");
        qry->limitCount = transformLimitClause(pstate, stmt->limitCount,
-                                                                                  "LIMIT");
+                                                                                  EXPR_KIND_LIMIT, "LIMIT");
 
        if (stmt->lockingClause)
                ereport(ERROR,
@@ -1249,19 +1233,6 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
        qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
 
        qry->hasSubLinks = pstate->p_hasSubLinks;
-       /* aggregates not allowed (but subselects are okay) */
-       if (pstate->p_hasAggs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_GROUPING_ERROR),
-                                errmsg("cannot use aggregate function in VALUES"),
-                                parser_errposition(pstate,
-                                                         locate_agg_of_level((Node *) exprsLists, 0))));
-       if (pstate->p_hasWindowFuncs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_WINDOWING_ERROR),
-                                errmsg("cannot use window function in VALUES"),
-                                parser_errposition(pstate,
-                                                                       locate_windowfunc((Node *) exprsLists))));
 
        assign_query_collations(pstate, qry);
 
@@ -1460,6 +1431,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
        qry->sortClause = transformSortClause(pstate,
                                                                                  sortClause,
                                                                                  &qry->targetList,
+                                                                                 EXPR_KIND_ORDER_BY,
                                                                                  false /* no unknowns expected */ ,
                                                                                  false /* allow SQL92 rules */ );
 
@@ -1477,17 +1449,15 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
                                                   exprLocation(list_nth(qry->targetList, tllen)))));
 
        qry->limitOffset = transformLimitClause(pstate, limitOffset,
-                                                                                       "OFFSET");
+                                                                                       EXPR_KIND_OFFSET, "OFFSET");
        qry->limitCount = transformLimitClause(pstate, limitCount,
-                                                                                  "LIMIT");
+                                                                                  EXPR_KIND_LIMIT, "LIMIT");
 
        qry->rtable = pstate->p_rtable;
        qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
 
        qry->hasSubLinks = pstate->p_hasSubLinks;
        qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
-       if (pstate->p_hasWindowFuncs)
-               parseCheckWindowFuncs(pstate, qry);
        qry->hasAggs = pstate->p_hasAggs;
        if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
                parseCheckAggregates(pstate, qry);
@@ -1937,9 +1907,11 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
         */
        transformFromClause(pstate, stmt->fromClause);
 
-       qry->targetList = transformTargetList(pstate, stmt->targetList);
+       qry->targetList = transformTargetList(pstate, stmt->targetList,
+                                                                                 EXPR_KIND_UPDATE_SOURCE);
 
-       qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
+       qual = transformWhereClause(pstate, stmt->whereClause,
+                                                               EXPR_KIND_WHERE, "WHERE");
 
        qry->returningList = transformReturningList(pstate, stmt->returningList);
 
@@ -1948,24 +1920,6 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
 
        qry->hasSubLinks = pstate->p_hasSubLinks;
 
-       /*
-        * Top-level aggregates are simply disallowed in UPDATE, per spec. (From
-        * an implementation point of view, this is forced because the implicit
-        * ctid reference would otherwise be an ungrouped variable.)
-        */
-       if (pstate->p_hasAggs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_GROUPING_ERROR),
-                                errmsg("cannot use aggregate function in UPDATE"),
-                                parser_errposition(pstate,
-                                                                       locate_agg_of_level((Node *) qry, 0))));
-       if (pstate->p_hasWindowFuncs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_WINDOWING_ERROR),
-                                errmsg("cannot use window function in UPDATE"),
-                                parser_errposition(pstate,
-                                                                       locate_windowfunc((Node *) qry))));
-
        /*
         * Now we are done with SELECT-like processing, and can get on with
         * transforming the target list to match the UPDATE target columns.
@@ -2040,8 +1994,6 @@ transformReturningList(ParseState *pstate, List *returningList)
 {
        List       *rlist;
        int                     save_next_resno;
-       bool            save_hasAggs;
-       bool            save_hasWindowFuncs;
 
        if (returningList == NIL)
                return NIL;                             /* nothing to do */
@@ -2054,38 +2006,14 @@ transformReturningList(ParseState *pstate, List *returningList)
        save_next_resno = pstate->p_next_resno;
        pstate->p_next_resno = 1;
 
-       /* save other state so that we can detect disallowed stuff */
-       save_hasAggs = pstate->p_hasAggs;
-       pstate->p_hasAggs = false;
-       save_hasWindowFuncs = pstate->p_hasWindowFuncs;
-       pstate->p_hasWindowFuncs = false;
-
        /* transform RETURNING identically to a SELECT targetlist */
-       rlist = transformTargetList(pstate, returningList);
-
-       /* check for disallowed stuff */
-
-       /* aggregates not allowed (but subselects are okay) */
-       if (pstate->p_hasAggs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_GROUPING_ERROR),
-                                errmsg("cannot use aggregate function in RETURNING"),
-                                parser_errposition(pstate,
-                                                                       locate_agg_of_level((Node *) rlist, 0))));
-       if (pstate->p_hasWindowFuncs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_WINDOWING_ERROR),
-                                errmsg("cannot use window function in RETURNING"),
-                                parser_errposition(pstate,
-                                                                       locate_windowfunc((Node *) rlist))));
+       rlist = transformTargetList(pstate, returningList, EXPR_KIND_RETURNING);
 
        /* mark column origins */
        markTargetListOrigins(pstate, rlist);
 
        /* restore state */
        pstate->p_next_resno = save_next_resno;
-       pstate->p_hasAggs = save_hasAggs;
-       pstate->p_hasWindowFuncs = save_hasWindowFuncs;
 
        return rlist;
 }
index 5854f81005d70837dda5b8cb05225e48a6255b94..d1d835b800754e1293fb29049fcf4e3cda6358db 100644 (file)
 #include "optimizer/tlist.h"
 #include "parser/parse_agg.h"
 #include "parser/parse_clause.h"
+#include "parser/parse_expr.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteManip.h"
 #include "utils/builtins.h"
 
 
+typedef struct
+{
+       ParseState *pstate;
+       int                     min_varlevel;
+       int                     min_agglevel;
+       int                     sublevels_up;
+} check_agg_arguments_context;
+
 typedef struct
 {
        ParseState *pstate;
@@ -35,6 +44,9 @@ typedef struct
        int                     sublevels_up;
 } check_ungrouped_columns_context;
 
+static int     check_agg_arguments(ParseState *pstate, List *args);
+static bool check_agg_arguments_walker(Node *node,
+                                                  check_agg_arguments_context *context);
 static void check_ungrouped_columns(Node *node, ParseState *pstate, Query *qry,
                                                List *groupClauses, bool have_non_var_grouping,
                                                List **func_grouped_rels);
@@ -72,6 +84,8 @@ transformAggregateCall(ParseState *pstate, Aggref *agg,
        int                     save_next_resno;
        int                     min_varlevel;
        ListCell   *lc;
+       const char *err;
+       bool            errkind;
 
        /*
         * Transform the plain list of Exprs into a targetlist.  We don't bother
@@ -102,6 +116,7 @@ transformAggregateCall(ParseState *pstate, Aggref *agg,
        torder = transformSortClause(pstate,
                                                                 aggorder,
                                                                 &tlist,
+                                                                EXPR_KIND_ORDER_BY,
                                                                 true /* fix unknowns */ ,
                                                                 true /* force SQL99 rules */ );
 
@@ -142,55 +157,261 @@ transformAggregateCall(ParseState *pstate, Aggref *agg,
        pstate->p_next_resno = save_next_resno;
 
        /*
-        * The aggregate's level is the same as the level of the lowest-level
-        * variable or aggregate in its arguments; or if it contains no variables
-        * at all, we presume it to be local.
+        * Check the arguments to compute the aggregate's level and detect
+        * improper nesting.
         */
-       min_varlevel = find_minimum_var_level((Node *) agg->args);
+       min_varlevel = check_agg_arguments(pstate, agg->args);
+       agg->agglevelsup = min_varlevel;
+
+       /* Mark the correct pstate level as having aggregates */
+       while (min_varlevel-- > 0)
+               pstate = pstate->parentParseState;
+       pstate->p_hasAggs = true;
 
        /*
-        * An aggregate can't directly contain another aggregate call of the same
-        * level (though outer aggs are okay).  We can skip this check if we
-        * didn't find any local vars or aggs.
+        * Check to see if the aggregate function is in an invalid place within
+        * its aggregation query.
+        *
+        * 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.)
         */
-       if (min_varlevel == 0)
+       err = NULL;
+       errkind = false;
+       switch (pstate->p_expr_kind)
        {
-               if (pstate->p_hasAggs &&
-                       checkExprHasAggs((Node *) agg->args))
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_GROUPING_ERROR),
-                                        errmsg("aggregate function calls cannot be nested"),
-                                        parser_errposition(pstate,
-                                                          locate_agg_of_level((Node *) agg->args, 0))));
-       }
+               case EXPR_KIND_NONE:
+                       Assert(false);          /* can't happen */
+                       break;
+               case EXPR_KIND_OTHER:
+                       /* Accept aggregate here; caller must throw error if wanted */
+                       break;
+               case EXPR_KIND_JOIN_ON:
+               case EXPR_KIND_JOIN_USING:
+                       err = _("aggregate functions are not allowed in JOIN conditions");
+                       break;
+               case EXPR_KIND_FROM_SUBSELECT:
+                       /* Should only be possible in a LATERAL subquery */
+                       Assert(pstate->p_lateral_active);
+                       /* Aggregate scope rules make it worth being explicit here */
+                       err = _("aggregate functions are not allowed in FROM clause of their own query level");
+                       break;
+               case EXPR_KIND_FROM_FUNCTION:
+                       err = _("aggregate functions are not allowed in functions in FROM");
+                       break;
+               case EXPR_KIND_WHERE:
+                       errkind = true;
+                       break;
+               case EXPR_KIND_HAVING:
+                       /* okay */
+                       break;
+               case EXPR_KIND_WINDOW_PARTITION:
+                       /* okay */
+                       break;
+               case EXPR_KIND_WINDOW_ORDER:
+                       /* okay */
+                       break;
+               case EXPR_KIND_WINDOW_FRAME_RANGE:
+                       err = _("aggregate functions are not allowed in window RANGE");
+                       break;
+               case EXPR_KIND_WINDOW_FRAME_ROWS:
+                       err = _("aggregate functions are not allowed in window ROWS");
+                       break;
+               case EXPR_KIND_SELECT_TARGET:
+                       /* okay */
+                       break;
+               case EXPR_KIND_INSERT_TARGET:
+               case EXPR_KIND_UPDATE_SOURCE:
+               case EXPR_KIND_UPDATE_TARGET:
+                       errkind = true;
+                       break;
+               case EXPR_KIND_GROUP_BY:
+                       errkind = true;
+                       break;
+               case EXPR_KIND_ORDER_BY:
+                       /* okay */
+                       break;
+               case EXPR_KIND_DISTINCT_ON:
+                       /* okay */
+                       break;
+               case EXPR_KIND_LIMIT:
+               case EXPR_KIND_OFFSET:
+                       errkind = true;
+                       break;
+               case EXPR_KIND_RETURNING:
+                       errkind = true;
+                       break;
+               case EXPR_KIND_VALUES:
+                       errkind = true;
+                       break;
+               case EXPR_KIND_CHECK_CONSTRAINT:
+               case EXPR_KIND_DOMAIN_CHECK:
+                       err = _("aggregate functions are not allowed in CHECK constraints");
+                       break;
+               case EXPR_KIND_COLUMN_DEFAULT:
+               case EXPR_KIND_FUNCTION_DEFAULT:
+                       err = _("aggregate functions are not allowed in DEFAULT expressions");
+                       break;
+               case EXPR_KIND_INDEX_EXPRESSION:
+                       err = _("aggregate functions are not allowed in index expressions");
+                       break;
+               case EXPR_KIND_INDEX_PREDICATE:
+                       err = _("aggregate functions are not allowed in index predicates");
+                       break;
+               case EXPR_KIND_ALTER_COL_TRANSFORM:
+                       err = _("aggregate functions are not allowed in transform expressions");
+                       break;
+               case EXPR_KIND_EXECUTE_PARAMETER:
+                       err = _("aggregate functions are not allowed in EXECUTE parameters");
+                       break;
+               case EXPR_KIND_TRIGGER_WHEN:
+                       err = _("aggregate functions are not allowed in trigger WHEN conditions");
+                       break;
 
-       /* It can't contain window functions either */
-       if (pstate->p_hasWindowFuncs &&
-               checkExprHasWindowFuncs((Node *) agg->args))
+                       /*
+                        * 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_GROUPING_ERROR),
-                                errmsg("aggregate function calls cannot contain window function calls"),
-                                parser_errposition(pstate,
-                                                                       locate_windowfunc((Node *) agg->args))));
+                                errmsg_internal("%s", err),
+                                parser_errposition(pstate, agg->location)));
+       if (errkind)
+               ereport(ERROR,
+                               (errcode(ERRCODE_GROUPING_ERROR),
+                                /* translator: %s is name of a SQL construct, eg GROUP BY */
+                                errmsg("aggregate functions are not allowed in %s",
+                                               ParseExprKindName(pstate->p_expr_kind)),
+                                parser_errposition(pstate, agg->location)));
+}
 
-       if (min_varlevel < 0)
-               min_varlevel = 0;
-       agg->agglevelsup = min_varlevel;
+/*
+ * check_agg_arguments
+ *       Scan the arguments of an aggregate function to determine the
+ *       aggregate's semantic level (zero is the current select's level,
+ *       one is its parent, etc).
+ *
+ * The aggregate's level is the same as the level of the lowest-level variable
+ * or aggregate in its arguments; or if it contains no variables at all, we
+ * presume it to be local.
+ *
+ * We also take this opportunity to detect any aggregates or window functions
+ * nested within the arguments.  We can throw error immediately if we find
+ * a window function.  Aggregates are a bit trickier because it's only an
+ * error if the inner aggregate is of the same semantic level as the outer,
+ * which we can't know until we finish scanning the arguments.
+ */
+static int
+check_agg_arguments(ParseState *pstate, List *args)
+{
+       int                     agglevel;
+       check_agg_arguments_context context;
 
-       /* Mark the correct pstate as having aggregates */
-       while (min_varlevel-- > 0)
-               pstate = pstate->parentParseState;
-       pstate->p_hasAggs = true;
+       context.pstate = pstate;
+       context.min_varlevel = -1;      /* signifies nothing found yet */
+       context.min_agglevel = -1;
+       context.sublevels_up = 0;
+
+       (void) expression_tree_walker((Node *) args,
+                                                                 check_agg_arguments_walker,
+                                                                 (void *) &context);
+
+       /*
+        * If we found no vars nor aggs at all, it's a level-zero aggregate;
+        * otherwise, its level is the minimum of vars or aggs.
+        */
+       if (context.min_varlevel < 0)
+       {
+               if (context.min_agglevel < 0)
+                       return 0;
+               agglevel = context.min_agglevel;
+       }
+       else if (context.min_agglevel < 0)
+               agglevel = context.min_varlevel;
+       else
+               agglevel = Min(context.min_varlevel, context.min_agglevel);
 
        /*
-        * Complain if we are inside a LATERAL subquery of the aggregation query.
-        * We must be in its FROM clause, so the aggregate is misplaced.
+        * If there's a nested aggregate of the same semantic level, complain.
         */
-       if (pstate->p_lateral_active)
+       if (agglevel == context.min_agglevel)
                ereport(ERROR,
                                (errcode(ERRCODE_GROUPING_ERROR),
-                                errmsg("aggregates not allowed in FROM clause"),
-                                parser_errposition(pstate, agg->location)));
+                                errmsg("aggregate function calls cannot be nested"),
+                                parser_errposition(pstate,
+                                                                       locate_agg_of_level((Node *) args,
+                                                                                                               agglevel))));
+
+       return agglevel;
+}
+
+static bool
+check_agg_arguments_walker(Node *node,
+                                                  check_agg_arguments_context *context)
+{
+       if (node == NULL)
+               return false;
+       if (IsA(node, Var))
+       {
+               int                     varlevelsup = ((Var *) node)->varlevelsup;
+
+               /* convert levelsup to frame of reference of original query */
+               varlevelsup -= context->sublevels_up;
+               /* ignore local vars of subqueries */
+               if (varlevelsup >= 0)
+               {
+                       if (context->min_varlevel < 0 ||
+                               context->min_varlevel > varlevelsup)
+                               context->min_varlevel = varlevelsup;
+               }
+               return false;
+       }
+       if (IsA(node, Aggref))
+       {
+               int                     agglevelsup = ((Aggref *) node)->agglevelsup;
+
+               /* convert levelsup to frame of reference of original query */
+               agglevelsup -= context->sublevels_up;
+               /* ignore local aggs of subqueries */
+               if (agglevelsup >= 0)
+               {
+                       if (context->min_agglevel < 0 ||
+                               context->min_agglevel > agglevelsup)
+                               context->min_agglevel = agglevelsup;
+               }
+               /* no need to examine args of the inner aggregate */
+               return false;
+       }
+       /* We can throw error on sight for a window function */
+       if (IsA(node, WindowFunc))
+               ereport(ERROR,
+                               (errcode(ERRCODE_GROUPING_ERROR),
+                                errmsg("aggregate function calls cannot contain window function calls"),
+                                parser_errposition(context->pstate,
+                                                                       ((WindowFunc *) node)->location)));
+       if (IsA(node, Query))
+       {
+               /* Recurse into subselects */
+               bool            result;
+
+               context->sublevels_up++;
+               result = query_tree_walker((Query *) node,
+                                                                  check_agg_arguments_walker,
+                                                                  (void *) context,
+                                                                  0);
+               context->sublevels_up--;
+               return result;
+       }
+       return expression_tree_walker(node,
+                                                                 check_agg_arguments_walker,
+                                                                 (void *) context);
 }
 
 /*
@@ -208,18 +429,136 @@ void
 transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc,
                                                WindowDef *windef)
 {
+       const char *err;
+       bool            errkind;
+
        /*
         * A window function call can't contain another one (but aggs are OK). XXX
         * is this required by spec, or just an unimplemented feature?
         */
        if (pstate->p_hasWindowFuncs &&
-               checkExprHasWindowFuncs((Node *) wfunc->args))
+               contain_windowfuncs((Node *) wfunc->args))
                ereport(ERROR,
                                (errcode(ERRCODE_WINDOWING_ERROR),
                                 errmsg("window function calls cannot be nested"),
                                 parser_errposition(pstate,
                                                                  locate_windowfunc((Node *) wfunc->args))));
 
+       /*
+        * Check to see if the window function is in an invalid place within the
+        * query.
+        *
+        * 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 window func here; caller must throw error if wanted */
+                       break;
+               case EXPR_KIND_JOIN_ON:
+               case EXPR_KIND_JOIN_USING:
+                       err = _("window 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:
+                       err = _("window functions are not allowed in functions in FROM");
+                       break;
+               case EXPR_KIND_WHERE:
+                       errkind = true;
+                       break;
+               case EXPR_KIND_HAVING:
+                       errkind = true;
+                       break;
+               case EXPR_KIND_WINDOW_PARTITION:
+               case EXPR_KIND_WINDOW_ORDER:
+               case EXPR_KIND_WINDOW_FRAME_RANGE:
+               case EXPR_KIND_WINDOW_FRAME_ROWS:
+                       err = _("window functions are not allowed in window definitions");
+                       break;
+               case EXPR_KIND_SELECT_TARGET:
+                       /* okay */
+                       break;
+               case EXPR_KIND_INSERT_TARGET:
+               case EXPR_KIND_UPDATE_SOURCE:
+               case EXPR_KIND_UPDATE_TARGET:
+                       errkind = true;
+                       break;
+               case EXPR_KIND_GROUP_BY:
+                       errkind = true;
+                       break;
+               case EXPR_KIND_ORDER_BY:
+                       /* okay */
+                       break;
+               case EXPR_KIND_DISTINCT_ON:
+                       /* okay */
+                       break;
+               case EXPR_KIND_LIMIT:
+               case EXPR_KIND_OFFSET:
+                       errkind = true;
+                       break;
+               case EXPR_KIND_RETURNING:
+                       errkind = true;
+                       break;
+               case EXPR_KIND_VALUES:
+                       errkind = true;
+                       break;
+               case EXPR_KIND_CHECK_CONSTRAINT:
+               case EXPR_KIND_DOMAIN_CHECK:
+                       err = _("window functions are not allowed in CHECK constraints");
+                       break;
+               case EXPR_KIND_COLUMN_DEFAULT:
+               case EXPR_KIND_FUNCTION_DEFAULT:
+                       err = _("window functions are not allowed in DEFAULT expressions");
+                       break;
+               case EXPR_KIND_INDEX_EXPRESSION:
+                       err = _("window functions are not allowed in index expressions");
+                       break;
+               case EXPR_KIND_INDEX_PREDICATE:
+                       err = _("window functions are not allowed in index predicates");
+                       break;
+               case EXPR_KIND_ALTER_COL_TRANSFORM:
+                       err = _("window functions are not allowed in transform expressions");
+                       break;
+               case EXPR_KIND_EXECUTE_PARAMETER:
+                       err = _("window functions are not allowed in EXECUTE parameters");
+                       break;
+               case EXPR_KIND_TRIGGER_WHEN:
+                       err = _("window 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_WINDOWING_ERROR),
+                                errmsg_internal("%s", err),
+                                parser_errposition(pstate, wfunc->location)));
+       if (errkind)
+               ereport(ERROR,
+                               (errcode(ERRCODE_WINDOWING_ERROR),
+                                /* translator: %s is name of a SQL construct, eg GROUP BY */
+                                errmsg("window functions are not allowed in %s",
+                                               ParseExprKindName(pstate->p_expr_kind)),
+                                parser_errposition(pstate, wfunc->location)));
+
        /*
         * If the OVER clause just specifies a window name, find that WINDOW
         * clause (which had better be present).  Otherwise, try to match all the
@@ -294,11 +633,14 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc,
 /*
  * parseCheckAggregates
  *     Check for aggregates where they shouldn't be and improper grouping.
+ *     This function should be called after the target list and qualifications
+ *     are finalized.
  *
- *     Ideally this should be done earlier, but it's difficult to distinguish
- *     aggregates from plain functions at the grammar level.  So instead we
- *     check here.  This function should be called after the target list and
- *     qualifications are finalized.
+ *     Misplaced aggregates are now mostly detected in transformAggregateCall,
+ *     but it seems more robust to check for aggregates in recursive queries
+ *     only after everything is finalized.  In any case it's hard to detect
+ *     improper grouping on-the-fly, so we have to make another pass over the
+ *     query for that.
  */
 void
 parseCheckAggregates(ParseState *pstate, Query *qry)
@@ -331,31 +673,8 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
        }
 
        /*
-        * Aggregates must never appear in WHERE or JOIN/ON clauses.
-        *
-        * (Note this check should appear first to deliver an appropriate error
-        * message; otherwise we are likely to complain about some innocent
-        * variable in the target list, which is outright misleading if the
-        * problem is in WHERE.)
-        */
-       if (checkExprHasAggs(qry->jointree->quals))
-               ereport(ERROR,
-                               (errcode(ERRCODE_GROUPING_ERROR),
-                                errmsg("aggregates not allowed in WHERE clause"),
-                                parser_errposition(pstate,
-                                                        locate_agg_of_level(qry->jointree->quals, 0))));
-       if (checkExprHasAggs((Node *) qry->jointree->fromlist))
-               ereport(ERROR,
-                               (errcode(ERRCODE_GROUPING_ERROR),
-                                errmsg("aggregates not allowed in JOIN conditions"),
-                                parser_errposition(pstate,
-                                locate_agg_of_level((Node *) qry->jointree->fromlist, 0))));
-
-       /*
-        * No aggregates allowed in GROUP BY clauses, either.
-        *
-        * While we are at it, build a list of the acceptable GROUP BY expressions
-        * for use by check_ungrouped_columns().
+        * Build a list of the acceptable GROUP BY expressions for use by
+        * check_ungrouped_columns().
         */
        foreach(l, qry->groupClause)
        {
@@ -365,12 +684,6 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
                expr = get_sortgroupclause_expr(grpcl, qry->targetList);
                if (expr == NULL)
                        continue;                       /* probably cannot happen */
-               if (checkExprHasAggs(expr))
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_GROUPING_ERROR),
-                                        errmsg("aggregates not allowed in GROUP BY clause"),
-                                        parser_errposition(pstate,
-                                                                               locate_agg_of_level(expr, 0))));
                groupClauses = lcons(expr, groupClauses);
        }
 
@@ -438,96 +751,11 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
        if (pstate->p_hasAggs && hasSelfRefRTEs)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_RECURSION),
-                                errmsg("aggregate functions not allowed in a recursive query's recursive term"),
+                                errmsg("aggregate functions are not allowed in a recursive query's recursive term"),
                                 parser_errposition(pstate,
                                                                        locate_agg_of_level((Node *) qry, 0))));
 }
 
-/*
- * parseCheckWindowFuncs
- *     Check for window functions where they shouldn't be.
- *
- *     We have to forbid window functions in WHERE, JOIN/ON, HAVING, GROUP BY,
- *     and window specifications.      (Other clauses, such as RETURNING and LIMIT,
- *     have already been checked.)  Transformation of all these clauses must
- *     be completed already.
- */
-void
-parseCheckWindowFuncs(ParseState *pstate, Query *qry)
-{
-       ListCell   *l;
-
-       /* This should only be called if we found window functions */
-       Assert(pstate->p_hasWindowFuncs);
-
-       if (checkExprHasWindowFuncs(qry->jointree->quals))
-               ereport(ERROR,
-                               (errcode(ERRCODE_WINDOWING_ERROR),
-                                errmsg("window functions not allowed in WHERE clause"),
-                                parser_errposition(pstate,
-                                                                 locate_windowfunc(qry->jointree->quals))));
-       if (checkExprHasWindowFuncs((Node *) qry->jointree->fromlist))
-               ereport(ERROR,
-                               (errcode(ERRCODE_WINDOWING_ERROR),
-                                errmsg("window functions not allowed in JOIN conditions"),
-                                parser_errposition(pstate,
-                                         locate_windowfunc((Node *) qry->jointree->fromlist))));
-       if (checkExprHasWindowFuncs(qry->havingQual))
-               ereport(ERROR,
-                               (errcode(ERRCODE_WINDOWING_ERROR),
-                                errmsg("window functions not allowed in HAVING clause"),
-                                parser_errposition(pstate,
-                                                                       locate_windowfunc(qry->havingQual))));
-
-       foreach(l, qry->groupClause)
-       {
-               SortGroupClause *grpcl = (SortGroupClause *) lfirst(l);
-               Node       *expr;
-
-               expr = get_sortgroupclause_expr(grpcl, qry->targetList);
-               if (checkExprHasWindowFuncs(expr))
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_WINDOWING_ERROR),
-                                  errmsg("window functions not allowed in GROUP BY clause"),
-                                        parser_errposition(pstate,
-                                                                               locate_windowfunc(expr))));
-       }
-
-       foreach(l, qry->windowClause)
-       {
-               WindowClause *wc = (WindowClause *) lfirst(l);
-               ListCell   *l2;
-
-               foreach(l2, wc->partitionClause)
-               {
-                       SortGroupClause *grpcl = (SortGroupClause *) lfirst(l2);
-                       Node       *expr;
-
-                       expr = get_sortgroupclause_expr(grpcl, qry->targetList);
-                       if (checkExprHasWindowFuncs(expr))
-                               ereport(ERROR,
-                                               (errcode(ERRCODE_WINDOWING_ERROR),
-                                errmsg("window functions not allowed in window definition"),
-                                                parser_errposition(pstate,
-                                                                                       locate_windowfunc(expr))));
-               }
-               foreach(l2, wc->orderClause)
-               {
-                       SortGroupClause *grpcl = (SortGroupClause *) lfirst(l2);
-                       Node       *expr;
-
-                       expr = get_sortgroupclause_expr(grpcl, qry->targetList);
-                       if (checkExprHasWindowFuncs(expr))
-                               ereport(ERROR,
-                                               (errcode(ERRCODE_WINDOWING_ERROR),
-                                errmsg("window functions not allowed in window definition"),
-                                                parser_errposition(pstate,
-                                                                                       locate_windowfunc(expr))));
-               }
-               /* startOffset and limitOffset were checked in transformFrameOffset */
-       }
-}
-
 /*
  * check_ungrouped_columns -
  *       Scan the given expression tree for ungrouped variables (variables
index d354baf42faefaeb18e8dfcf9e0b0e7e26a16158..ee40b5547eed3a143fe82b8336b84f573921ef19 100644 (file)
 /* Convenience macro for the most common makeNamespaceItem() case */
 #define makeDefaultNSItem(rte) makeNamespaceItem(rte, true, true, false, true)
 
-/* clause types for findTargetlistEntrySQL92 */
-#define ORDER_CLAUSE 0
-#define GROUP_CLAUSE 1
-#define DISTINCT_ON_CLAUSE 2
-
-static const char *const clauseText[] = {
-       "ORDER BY",
-       "GROUP BY",
-       "DISTINCT ON"
-};
-
 static void extractRemainingColumns(List *common_colnames,
                                                List *src_colnames, List *src_colvars,
                                                List **res_colnames, List **res_colvars);
@@ -81,9 +70,9 @@ static void setNamespaceLateralState(List *namespace,
 static void checkExprIsVarFree(ParseState *pstate, Node *n,
                                   const char *constructName);
 static TargetEntry *findTargetlistEntrySQL92(ParseState *pstate, Node *node,
-                                                List **tlist, int clause);
+                                                List **tlist, ParseExprKind exprKind);
 static TargetEntry *findTargetlistEntrySQL99(ParseState *pstate, Node *node,
-                                                List **tlist);
+                                                List **tlist, ParseExprKind exprKind);
 static int get_matching_location(int sortgroupref,
                                          List *sortgrouprefs, List *exprs);
 static List *addTargetToSortList(ParseState *pstate, TargetEntry *tle,
@@ -371,7 +360,7 @@ transformJoinUsingClause(ParseState *pstate,
         * transformJoinOnClause() does.  Just invoke transformExpr() to fix up
         * the operators, and we're done.
         */
-       result = transformExpr(pstate, result);
+       result = transformExpr(pstate, result, EXPR_KIND_JOIN_USING);
 
        result = coerce_to_boolean(pstate, result, "JOIN/USING");
 
@@ -401,7 +390,8 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j, List *namespace)
        save_namespace = pstate->p_namespace;
        pstate->p_namespace = namespace;
 
-       result = transformWhereClause(pstate, j->quals, "JOIN/ON");
+       result = transformWhereClause(pstate, j->quals,
+                                                                 EXPR_KIND_JOIN_ON, "JOIN/ON");
 
        pstate->p_namespace = save_namespace;
 
@@ -457,6 +447,14 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
        if (r->alias == NULL)
                elog(ERROR, "subquery in FROM must have an alias");
 
+       /*
+        * Set p_expr_kind to show this parse level is recursing to a subselect.
+        * We can't be nested within any expression, so don't need save-restore
+        * logic here.
+        */
+       Assert(pstate->p_expr_kind == EXPR_KIND_NONE);
+       pstate->p_expr_kind = EXPR_KIND_FROM_SUBSELECT;
+
        /*
         * If the subselect is LATERAL, make lateral_only names of this level
         * visible to it.  (LATERAL can't nest within a single pstate level, so we
@@ -471,7 +469,9 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
        query = parse_sub_analyze(r->subquery, pstate, NULL,
                                                          isLockedRefname(pstate, r->alias->aliasname));
 
+       /* Restore state */
        pstate->p_lateral_active = false;
+       pstate->p_expr_kind = EXPR_KIND_NONE;
 
        /*
         * Check that we got something reasonable.      Many of these conditions are
@@ -524,7 +524,7 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
        /*
         * Transform the raw expression.
         */
-       funcexpr = transformExpr(pstate, r->funccallnode);
+       funcexpr = transformExpr(pstate, r->funccallnode, EXPR_KIND_FROM_FUNCTION);
 
        pstate->p_lateral_active = false;
 
@@ -533,25 +533,6 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
         */
        assign_expr_collations(pstate, funcexpr);
 
-       /*
-        * Disallow aggregate functions in the expression.      (No reason to postpone
-        * this check until parseCheckAggregates.)
-        */
-       if (pstate->p_hasAggs &&
-               checkExprHasAggs(funcexpr))
-               ereport(ERROR,
-                               (errcode(ERRCODE_GROUPING_ERROR),
-                                errmsg("cannot use aggregate function in function expression in FROM"),
-                                parser_errposition(pstate,
-                                                                       locate_agg_of_level(funcexpr, 0))));
-       if (pstate->p_hasWindowFuncs &&
-               checkExprHasWindowFuncs(funcexpr))
-               ereport(ERROR,
-                               (errcode(ERRCODE_WINDOWING_ERROR),
-                errmsg("cannot use window function in function expression in FROM"),
-                                parser_errposition(pstate,
-                                                                       locate_windowfunc(funcexpr))));
-
        /*
         * OK, build an RTE for the function.
         */
@@ -1182,14 +1163,14 @@ setNamespaceLateralState(List *namespace, bool lateral_only, bool lateral_ok)
  */
 Node *
 transformWhereClause(ParseState *pstate, Node *clause,
-                                        const char *constructName)
+                                        ParseExprKind exprKind, const char *constructName)
 {
        Node       *qual;
 
        if (clause == NULL)
                return NULL;
 
-       qual = transformExpr(pstate, clause);
+       qual = transformExpr(pstate, clause, exprKind);
 
        qual = coerce_to_boolean(pstate, qual, constructName);
 
@@ -1209,18 +1190,18 @@ transformWhereClause(ParseState *pstate, Node *clause,
  */
 Node *
 transformLimitClause(ParseState *pstate, Node *clause,
-                                        const char *constructName)
+                                        ParseExprKind exprKind, const char *constructName)
 {
        Node       *qual;
 
        if (clause == NULL)
                return NULL;
 
-       qual = transformExpr(pstate, clause);
+       qual = transformExpr(pstate, clause, exprKind);
 
        qual = coerce_to_specific_type(pstate, qual, INT8OID, constructName);
 
-       /* LIMIT can't refer to any vars or aggregates of the current query */
+       /* LIMIT can't refer to any variables of the current query */
        checkExprIsVarFree(pstate, qual, constructName);
 
        return qual;
@@ -1229,7 +1210,7 @@ transformLimitClause(ParseState *pstate, Node *clause,
 /*
  * checkExprIsVarFree
  *             Check that given expr has no Vars of the current query level
- *             (and no aggregates or window functions, either).
+ *             (aggregates and window functions should have been rejected already).
  *
  * This is used to check expressions that have to have a consistent value
  * across all rows of the query, such as a LIMIT.  Arguably it should reject
@@ -1251,31 +1232,57 @@ checkExprIsVarFree(ParseState *pstate, Node *n, const char *constructName)
                                 parser_errposition(pstate,
                                                                        locate_var_of_level(n, 0))));
        }
-       if (pstate->p_hasAggs &&
-               checkExprHasAggs(n))
-       {
-               ereport(ERROR,
-                               (errcode(ERRCODE_GROUPING_ERROR),
-               /* translator: %s is name of a SQL construct, eg LIMIT */
-                                errmsg("argument of %s must not contain aggregate functions",
-                                               constructName),
-                                parser_errposition(pstate,
-                                                                       locate_agg_of_level(n, 0))));
-       }
-       if (pstate->p_hasWindowFuncs &&
-               checkExprHasWindowFuncs(n))
+}
+
+
+/*
+ * checkTargetlistEntrySQL92 -
+ *       Validate a targetlist entry found by findTargetlistEntrySQL92
+ *
+ * When we select a pre-existing tlist entry as a result of syntax such
+ * as "GROUP BY 1", we have to make sure it is acceptable for use in the
+ * indicated clause type; transformExpr() will have treated it as a regular
+ * targetlist item.
+ */
+static void
+checkTargetlistEntrySQL92(ParseState *pstate, TargetEntry *tle,
+                                                 ParseExprKind exprKind)
+{
+       switch (exprKind)
        {
-               ereport(ERROR,
-                               (errcode(ERRCODE_WINDOWING_ERROR),
-               /* translator: %s is name of a SQL construct, eg LIMIT */
-                                errmsg("argument of %s must not contain window functions",
-                                               constructName),
-                                parser_errposition(pstate,
-                                                                       locate_windowfunc(n))));
+               case EXPR_KIND_GROUP_BY:
+                       /* reject aggregates and window functions */
+                       if (pstate->p_hasAggs &&
+                               contain_aggs_of_level((Node *) tle->expr, 0))
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_GROUPING_ERROR),
+                                                /* translator: %s is name of a SQL construct, eg GROUP BY */
+                                                errmsg("aggregate functions are not allowed in %s",
+                                                               ParseExprKindName(exprKind)),
+                                                parser_errposition(pstate,
+                                                                                       locate_agg_of_level((Node *) tle->expr, 0))));
+                       if (pstate->p_hasWindowFuncs &&
+                               contain_windowfuncs((Node *) tle->expr))
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_WINDOWING_ERROR),
+                                                /* translator: %s is name of a SQL construct, eg GROUP BY */
+                                                errmsg("window functions are not allowed in %s",
+                                                               ParseExprKindName(exprKind)),
+                                                parser_errposition(pstate,
+                                                                                       locate_windowfunc((Node *) tle->expr))));
+                       break;
+               case EXPR_KIND_ORDER_BY:
+                       /* no extra checks needed */
+                       break;
+               case EXPR_KIND_DISTINCT_ON:
+                       /* no extra checks needed */
+                       break;
+               default:
+                       elog(ERROR, "unexpected exprKind in checkTargetlistEntrySQL92");
+                       break;
        }
 }
 
-
 /*
  *     findTargetlistEntrySQL92 -
  *       Returns the targetlist entry matching the given (untransformed) node.
@@ -1291,11 +1298,11 @@ checkExprIsVarFree(ParseState *pstate, Node *n, const char *constructName)
  *
  * node                the ORDER BY, GROUP BY, or DISTINCT ON expression to be matched
  * tlist       the target list (passed by reference so we can append to it)
- * clause      identifies clause type being processed
+ * exprKind    identifies clause type being processed
  */
 static TargetEntry *
 findTargetlistEntrySQL92(ParseState *pstate, Node *node, List **tlist,
-                                                int clause)
+                                                ParseExprKind exprKind)
 {
        ListCell   *tl;
 
@@ -1344,7 +1351,7 @@ findTargetlistEntrySQL92(ParseState *pstate, Node *node, List **tlist,
                char       *name = strVal(linitial(((ColumnRef *) node)->fields));
                int                     location = ((ColumnRef *) node)->location;
 
-               if (clause == GROUP_CLAUSE)
+               if (exprKind == EXPR_KIND_GROUP_BY)
                {
                        /*
                         * In GROUP BY, we must prefer a match against a FROM-clause
@@ -1386,7 +1393,8 @@ findTargetlistEntrySQL92(ParseState *pstate, Node *node, List **tlist,
                                                        /*------
                                                          translator: first %s is name of a SQL construct, eg ORDER BY */
                                                                         errmsg("%s \"%s\" is ambiguous",
-                                                                                       clauseText[clause], name),
+                                                                                       ParseExprKindName(exprKind),
+                                                                                       name),
                                                                         parser_errposition(pstate, location)));
                                        }
                                        else
@@ -1395,7 +1403,11 @@ findTargetlistEntrySQL92(ParseState *pstate, Node *node, List **tlist,
                                }
                        }
                        if (target_result != NULL)
-                               return target_result;   /* return the first match */
+                       {
+                               /* return the first match, after suitable validation */
+                               checkTargetlistEntrySQL92(pstate, target_result, exprKind);
+                               return target_result;
+                       }
                }
        }
        if (IsA(node, A_Const))
@@ -1410,7 +1422,7 @@ findTargetlistEntrySQL92(ParseState *pstate, Node *node, List **tlist,
                                        (errcode(ERRCODE_SYNTAX_ERROR),
                        /* translator: %s is name of a SQL construct, eg ORDER BY */
                                         errmsg("non-integer constant in %s",
-                                                       clauseText[clause]),
+                                                       ParseExprKindName(exprKind)),
                                         parser_errposition(pstate, location)));
 
                target_pos = intVal(val);
@@ -1421,21 +1433,25 @@ findTargetlistEntrySQL92(ParseState *pstate, Node *node, List **tlist,
                        if (!tle->resjunk)
                        {
                                if (++targetlist_pos == target_pos)
-                                       return tle; /* return the unique match */
+                               {
+                                       /* return the unique match, after suitable validation */
+                                       checkTargetlistEntrySQL92(pstate, tle, exprKind);
+                                       return tle;
+                               }
                        }
                }
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
                /* translator: %s is name of a SQL construct, eg ORDER BY */
                                 errmsg("%s position %d is not in select list",
-                                               clauseText[clause], target_pos),
+                                               ParseExprKindName(exprKind), target_pos),
                                 parser_errposition(pstate, location)));
        }
 
        /*
         * Otherwise, we have an expression, so process it per SQL99 rules.
         */
-       return findTargetlistEntrySQL99(pstate, node, tlist);
+       return findTargetlistEntrySQL99(pstate, node, tlist, exprKind);
 }
 
 /*
@@ -1449,9 +1465,11 @@ findTargetlistEntrySQL92(ParseState *pstate, Node *node, List **tlist,
  *
  * node                the ORDER BY, GROUP BY, etc expression to be matched
  * tlist       the target list (passed by reference so we can append to it)
+ * exprKind    identifies clause type being processed
  */
 static TargetEntry *
-findTargetlistEntrySQL99(ParseState *pstate, Node *node, List **tlist)
+findTargetlistEntrySQL99(ParseState *pstate, Node *node, List **tlist,
+                                                ParseExprKind exprKind)
 {
        TargetEntry *target_result;
        ListCell   *tl;
@@ -1464,7 +1482,7 @@ findTargetlistEntrySQL99(ParseState *pstate, Node *node, List **tlist)
         * resjunk target here, though the SQL92 cases above must ignore resjunk
         * targets.
         */
-       expr = transformExpr(pstate, node);
+       expr = transformExpr(pstate, node, exprKind);
 
        foreach(tl, *tlist)
        {
@@ -1491,7 +1509,8 @@ findTargetlistEntrySQL99(ParseState *pstate, Node *node, List **tlist)
         * end of the target list.      This target is given resjunk = TRUE so that it
         * will not be projected into the final tuple.
         */
-       target_result = transformTargetEntry(pstate, node, expr, NULL, true);
+       target_result = transformTargetEntry(pstate, node, expr, exprKind,
+                                                                                NULL, true);
 
        *tlist = lappend(*tlist, target_result);
 
@@ -1511,7 +1530,7 @@ findTargetlistEntrySQL99(ParseState *pstate, Node *node, List **tlist)
 List *
 transformGroupClause(ParseState *pstate, List *grouplist,
                                         List **targetlist, List *sortClause,
-                                        bool useSQL99)
+                                        ParseExprKind exprKind, bool useSQL99)
 {
        List       *result = NIL;
        ListCell   *gl;
@@ -1523,10 +1542,11 @@ transformGroupClause(ParseState *pstate, List *grouplist,
                bool            found = false;
 
                if (useSQL99)
-                       tle = findTargetlistEntrySQL99(pstate, gexpr, targetlist);
+                       tle = findTargetlistEntrySQL99(pstate, gexpr,
+                                                                                  targetlist, exprKind);
                else
-                       tle = findTargetlistEntrySQL92(pstate, gexpr, targetlist,
-                                                                                  GROUP_CLAUSE);
+                       tle = findTargetlistEntrySQL92(pstate, gexpr,
+                                                                                  targetlist, exprKind);
 
                /* Eliminate duplicates (GROUP BY x, x) */
                if (targetIsInSortList(tle, InvalidOid, result))
@@ -1588,6 +1608,7 @@ List *
 transformSortClause(ParseState *pstate,
                                        List *orderlist,
                                        List **targetlist,
+                                       ParseExprKind exprKind,
                                        bool resolveUnknown,
                                        bool useSQL99)
 {
@@ -1600,10 +1621,11 @@ transformSortClause(ParseState *pstate,
                TargetEntry *tle;
 
                if (useSQL99)
-                       tle = findTargetlistEntrySQL99(pstate, sortby->node, targetlist);
+                       tle = findTargetlistEntrySQL99(pstate, sortby->node,
+                                                                                  targetlist, exprKind);
                else
-                       tle = findTargetlistEntrySQL92(pstate, sortby->node, targetlist,
-                                                                                  ORDER_CLAUSE);
+                       tle = findTargetlistEntrySQL92(pstate, sortby->node,
+                                                                                  targetlist, exprKind);
 
                sortlist = addTargetToSortList(pstate, tle,
                                                                           sortlist, *targetlist, sortby,
@@ -1668,12 +1690,14 @@ transformWindowDefinitions(ParseState *pstate,
                orderClause = transformSortClause(pstate,
                                                                                  windef->orderClause,
                                                                                  targetlist,
+                                                                                 EXPR_KIND_WINDOW_ORDER,
                                                                                  true /* fix unknowns */ ,
                                                                                  true /* force SQL99 rules */ );
                partitionClause = transformGroupClause(pstate,
                                                                                           windef->partitionClause,
                                                                                           targetlist,
                                                                                           orderClause,
+                                                                                          EXPR_KIND_WINDOW_PARTITION,
                                                                                           true /* force SQL99 rules */ );
 
                /*
@@ -1861,7 +1885,7 @@ transformDistinctOnClause(ParseState *pstate, List *distinctlist,
                TargetEntry *tle;
 
                tle = findTargetlistEntrySQL92(pstate, dexpr, targetlist,
-                                                                          DISTINCT_ON_CLAUSE);
+                                                                          EXPR_KIND_DISTINCT_ON);
                sortgroupref = assignSortGroupRef(tle, *targetlist);
                sortgrouprefs = lappend_int(sortgrouprefs, sortgroupref);
        }
@@ -2270,11 +2294,11 @@ transformFrameOffset(ParseState *pstate, int frameOptions, Node *clause)
        if (clause == NULL)
                return NULL;
 
-       /* Transform the raw expression tree */
-       node = transformExpr(pstate, clause);
-
        if (frameOptions & FRAMEOPTION_ROWS)
        {
+               /* Transform the raw expression tree */
+               node = transformExpr(pstate, clause, EXPR_KIND_WINDOW_FRAME_ROWS);
+
                /*
                 * Like LIMIT clause, simply coerce to int8
                 */
@@ -2283,6 +2307,9 @@ transformFrameOffset(ParseState *pstate, int frameOptions, Node *clause)
        }
        else if (frameOptions & FRAMEOPTION_RANGE)
        {
+               /* Transform the raw expression tree */
+               node = transformExpr(pstate, clause, EXPR_KIND_WINDOW_FRAME_RANGE);
+
                /*
                 * this needs a lot of thought to decide how to support in the context
                 * of Postgres' extensible datatype framework
@@ -2292,9 +2319,12 @@ transformFrameOffset(ParseState *pstate, int frameOptions, Node *clause)
                elog(ERROR, "window frame with value offset is not implemented");
        }
        else
+       {
                Assert(false);
+               node = NULL;
+       }
 
-       /* Disallow variables and aggregates in frame offsets */
+       /* Disallow variables in frame offsets */
        checkExprIsVarFree(pstate, node, constructName);
 
        return node;
index 385f8e767e48c2a38403ccc8fe1e134d47ca55ae..e9267c56fc5e9c5b577dbc3ab9c32455405f68dc 100644 (file)
@@ -37,6 +37,7 @@
 
 bool           Transform_null_equals = false;
 
+static Node *transformExprRecurse(ParseState *pstate, Node *expr);
 static Node *transformParamRef(ParseState *pstate, ParamRef *pref);
 static Node *transformAExprOp(ParseState *pstate, A_Expr *a);
 static Node *transformAExprAnd(ParseState *pstate, A_Expr *a);
@@ -100,9 +101,27 @@ static Expr *make_distinct_op(ParseState *pstate, List *opname,
  * input and output of transformExpr; see SubLink for example.
  */
 Node *
-transformExpr(ParseState *pstate, Node *expr)
+transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
 {
-       Node       *result = NULL;
+       Node       *result;
+       ParseExprKind sv_expr_kind;
+
+       /* Save and restore identity of expression type we're parsing */
+       Assert(exprKind != EXPR_KIND_NONE);
+       sv_expr_kind = pstate->p_expr_kind;
+       pstate->p_expr_kind = exprKind;
+
+       result = transformExprRecurse(pstate, expr);
+
+       pstate->p_expr_kind = sv_expr_kind;
+
+       return result;
+}
+
+static Node *
+transformExprRecurse(ParseState *pstate, Node *expr)
+{
+       Node       *result;
 
        if (expr == NULL)
                return NULL;
@@ -133,7 +152,7 @@ transformExpr(ParseState *pstate, Node *expr)
                        {
                                A_Indirection *ind = (A_Indirection *) expr;
 
-                               result = transformExpr(pstate, ind->arg);
+                               result = transformExprRecurse(pstate, ind->arg);
                                result = transformIndirection(pstate, result,
                                                                                          ind->indirection);
                                break;
@@ -230,6 +249,8 @@ transformExpr(ParseState *pstate, Node *expr)
                                                break;
                                        default:
                                                elog(ERROR, "unrecognized A_Expr kind: %d", a->kind);
+                                               result = NULL;          /* keep compiler quiet */
+                                               break;
                                }
                                break;
                        }
@@ -242,7 +263,7 @@ transformExpr(ParseState *pstate, Node *expr)
                        {
                                NamedArgExpr *na = (NamedArgExpr *) expr;
 
-                               na->arg = (Expr *) transformExpr(pstate, (Node *) na->arg);
+                               na->arg = (Expr *) transformExprRecurse(pstate, (Node *) na->arg);
                                result = expr;
                                break;
                        }
@@ -279,7 +300,7 @@ transformExpr(ParseState *pstate, Node *expr)
                        {
                                NullTest   *n = (NullTest *) expr;
 
-                               n->arg = (Expr *) transformExpr(pstate, (Node *) n->arg);
+                               n->arg = (Expr *) transformExprRecurse(pstate, (Node *) n->arg);
                                /* the argument can be any type, so don't coerce it */
                                n->argisrow = type_is_rowtype(exprType((Node *) n->arg));
                                result = expr;
@@ -334,6 +355,7 @@ transformExpr(ParseState *pstate, Node *expr)
                default:
                        /* should not reach here */
                        elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
+                       result = NULL;          /* keep compiler quiet */
                        break;
        }
 
@@ -843,7 +865,7 @@ transformAExprOp(ParseState *pstate, A_Expr *a)
                else
                        n->arg = (Expr *) lexpr;
 
-               result = transformExpr(pstate, (Node *) n);
+               result = transformExprRecurse(pstate, (Node *) n);
        }
        else if (lexpr && IsA(lexpr, RowExpr) &&
                         rexpr && IsA(rexpr, SubLink) &&
@@ -860,14 +882,14 @@ transformAExprOp(ParseState *pstate, A_Expr *a)
                s->testexpr = lexpr;
                s->operName = a->name;
                s->location = a->location;
-               result = transformExpr(pstate, (Node *) s);
+               result = transformExprRecurse(pstate, (Node *) s);
        }
        else if (lexpr && IsA(lexpr, RowExpr) &&
                         rexpr && IsA(rexpr, RowExpr))
        {
                /* "row op row" */
-               lexpr = transformExpr(pstate, lexpr);
-               rexpr = transformExpr(pstate, rexpr);
+               lexpr = transformExprRecurse(pstate, lexpr);
+               rexpr = transformExprRecurse(pstate, rexpr);
                Assert(IsA(lexpr, RowExpr));
                Assert(IsA(rexpr, RowExpr));
 
@@ -880,8 +902,8 @@ transformAExprOp(ParseState *pstate, A_Expr *a)
        else
        {
                /* Ordinary scalar operator */
-               lexpr = transformExpr(pstate, lexpr);
-               rexpr = transformExpr(pstate, rexpr);
+               lexpr = transformExprRecurse(pstate, lexpr);
+               rexpr = transformExprRecurse(pstate, rexpr);
 
                result = (Node *) make_op(pstate,
                                                                  a->name,
@@ -896,8 +918,8 @@ transformAExprOp(ParseState *pstate, A_Expr *a)
 static Node *
 transformAExprAnd(ParseState *pstate, A_Expr *a)
 {
-       Node       *lexpr = transformExpr(pstate, a->lexpr);
-       Node       *rexpr = transformExpr(pstate, a->rexpr);
+       Node       *lexpr = transformExprRecurse(pstate, a->lexpr);
+       Node       *rexpr = transformExprRecurse(pstate, a->rexpr);
 
        lexpr = coerce_to_boolean(pstate, lexpr, "AND");
        rexpr = coerce_to_boolean(pstate, rexpr, "AND");
@@ -910,8 +932,8 @@ transformAExprAnd(ParseState *pstate, A_Expr *a)
 static Node *
 transformAExprOr(ParseState *pstate, A_Expr *a)
 {
-       Node       *lexpr = transformExpr(pstate, a->lexpr);
-       Node       *rexpr = transformExpr(pstate, a->rexpr);
+       Node       *lexpr = transformExprRecurse(pstate, a->lexpr);
+       Node       *rexpr = transformExprRecurse(pstate, a->rexpr);
 
        lexpr = coerce_to_boolean(pstate, lexpr, "OR");
        rexpr = coerce_to_boolean(pstate, rexpr, "OR");
@@ -924,7 +946,7 @@ transformAExprOr(ParseState *pstate, A_Expr *a)
 static Node *
 transformAExprNot(ParseState *pstate, A_Expr *a)
 {
-       Node       *rexpr = transformExpr(pstate, a->rexpr);
+       Node       *rexpr = transformExprRecurse(pstate, a->rexpr);
 
        rexpr = coerce_to_boolean(pstate, rexpr, "NOT");
 
@@ -936,8 +958,8 @@ transformAExprNot(ParseState *pstate, A_Expr *a)
 static Node *
 transformAExprOpAny(ParseState *pstate, A_Expr *a)
 {
-       Node       *lexpr = transformExpr(pstate, a->lexpr);
-       Node       *rexpr = transformExpr(pstate, a->rexpr);
+       Node       *lexpr = transformExprRecurse(pstate, a->lexpr);
+       Node       *rexpr = transformExprRecurse(pstate, a->rexpr);
 
        return (Node *) make_scalar_array_op(pstate,
                                                                                 a->name,
@@ -950,8 +972,8 @@ transformAExprOpAny(ParseState *pstate, A_Expr *a)
 static Node *
 transformAExprOpAll(ParseState *pstate, A_Expr *a)
 {
-       Node       *lexpr = transformExpr(pstate, a->lexpr);
-       Node       *rexpr = transformExpr(pstate, a->rexpr);
+       Node       *lexpr = transformExprRecurse(pstate, a->lexpr);
+       Node       *rexpr = transformExprRecurse(pstate, a->rexpr);
 
        return (Node *) make_scalar_array_op(pstate,
                                                                                 a->name,
@@ -964,8 +986,8 @@ transformAExprOpAll(ParseState *pstate, A_Expr *a)
 static Node *
 transformAExprDistinct(ParseState *pstate, A_Expr *a)
 {
-       Node       *lexpr = transformExpr(pstate, a->lexpr);
-       Node       *rexpr = transformExpr(pstate, a->rexpr);
+       Node       *lexpr = transformExprRecurse(pstate, a->lexpr);
+       Node       *rexpr = transformExprRecurse(pstate, a->rexpr);
 
        if (lexpr && IsA(lexpr, RowExpr) &&
                rexpr && IsA(rexpr, RowExpr))
@@ -990,8 +1012,8 @@ transformAExprDistinct(ParseState *pstate, A_Expr *a)
 static Node *
 transformAExprNullIf(ParseState *pstate, A_Expr *a)
 {
-       Node       *lexpr = transformExpr(pstate, a->lexpr);
-       Node       *rexpr = transformExpr(pstate, a->rexpr);
+       Node       *lexpr = transformExprRecurse(pstate, a->lexpr);
+       Node       *rexpr = transformExprRecurse(pstate, a->rexpr);
        OpExpr     *result;
 
        result = (OpExpr *) make_op(pstate,
@@ -1029,7 +1051,7 @@ transformAExprOf(ParseState *pstate, A_Expr *a)
         * Checking an expression for match to a list of type names. Will result
         * in a boolean constant node.
         */
-       Node       *lexpr = transformExpr(pstate, a->lexpr);
+       Node       *lexpr = transformExprRecurse(pstate, a->lexpr);
        Const      *result;
        ListCell   *telem;
        Oid                     ltype,
@@ -1092,12 +1114,12 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
         * First step: transform all the inputs, and detect whether any are
         * RowExprs or contain Vars.
         */
-       lexpr = transformExpr(pstate, a->lexpr);
+       lexpr = transformExprRecurse(pstate, a->lexpr);
        haveRowExpr = (lexpr && IsA(lexpr, RowExpr));
        rexprs = rvars = rnonvars = NIL;
        foreach(l, (List *) a->rexpr)
        {
-               Node       *rexpr = transformExpr(pstate, lfirst(l));
+               Node       *rexpr = transformExprRecurse(pstate, lfirst(l));
 
                haveRowExpr |= (rexpr && IsA(rexpr, RowExpr));
                rexprs = lappend(rexprs, rexpr);
@@ -1222,8 +1244,8 @@ transformFuncCall(ParseState *pstate, FuncCall *fn)
        targs = NIL;
        foreach(args, fn->args)
        {
-               targs = lappend(targs, transformExpr(pstate,
-                                                                                        (Node *) lfirst(args)));
+               targs = lappend(targs, transformExprRecurse(pstate,
+                                                                                                       (Node *) lfirst(args)));
        }
 
        /* ... and hand off to ParseFuncOrColumn */
@@ -1258,7 +1280,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
        newc = makeNode(CaseExpr);
 
        /* transform the test expression, if any */
-       arg = transformExpr(pstate, (Node *) c->arg);
+       arg = transformExprRecurse(pstate, (Node *) c->arg);
 
        /* generate placeholder for test expression */
        if (arg)
@@ -1311,14 +1333,14 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
                                                                                         warg,
                                                                                         w->location);
                }
-               neww->expr = (Expr *) transformExpr(pstate, warg);
+               neww->expr = (Expr *) transformExprRecurse(pstate, warg);
 
                neww->expr = (Expr *) coerce_to_boolean(pstate,
                                                                                                (Node *) neww->expr,
                                                                                                "CASE/WHEN");
 
                warg = (Node *) w->result;
-               neww->result = (Expr *) transformExpr(pstate, warg);
+               neww->result = (Expr *) transformExprRecurse(pstate, warg);
                neww->location = w->location;
 
                newargs = lappend(newargs, neww);
@@ -1337,7 +1359,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
                n->location = -1;
                defresult = (Node *) n;
        }
-       newc->defresult = (Expr *) transformExpr(pstate, defresult);
+       newc->defresult = (Expr *) transformExprRecurse(pstate, defresult);
 
        /*
         * Note: default result is considered the most significant type in
@@ -1380,12 +1402,92 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
 {
        Node       *result = (Node *) sublink;
        Query      *qtree;
+       const char *err;
 
        /* If we already transformed this node, do nothing */
        if (IsA(sublink->subselect, Query))
                return result;
 
+       /*
+        * Check to see if the sublink is in an invalid place within the query.
+        * We allow sublinks everywhere in SELECT/INSERT/UPDATE/DELETE, but
+        * generally not in utility statements.
+        */
+       err = NULL;
+       switch (pstate->p_expr_kind)
+       {
+               case EXPR_KIND_NONE:
+                       Assert(false);          /* can't happen */
+                       break;
+               case EXPR_KIND_OTHER:
+                       /* Accept sublink here; caller must throw error if wanted */
+                       break;
+               case EXPR_KIND_JOIN_ON:
+               case EXPR_KIND_JOIN_USING:
+               case EXPR_KIND_FROM_SUBSELECT:
+               case EXPR_KIND_FROM_FUNCTION:
+               case EXPR_KIND_WHERE:
+               case EXPR_KIND_HAVING:
+               case EXPR_KIND_WINDOW_PARTITION:
+               case EXPR_KIND_WINDOW_ORDER:
+               case EXPR_KIND_WINDOW_FRAME_RANGE:
+               case EXPR_KIND_WINDOW_FRAME_ROWS:
+               case EXPR_KIND_SELECT_TARGET:
+               case EXPR_KIND_INSERT_TARGET:
+               case EXPR_KIND_UPDATE_SOURCE:
+               case EXPR_KIND_UPDATE_TARGET:
+               case EXPR_KIND_GROUP_BY:
+               case EXPR_KIND_ORDER_BY:
+               case EXPR_KIND_DISTINCT_ON:
+               case EXPR_KIND_LIMIT:
+               case EXPR_KIND_OFFSET:
+               case EXPR_KIND_RETURNING:
+               case EXPR_KIND_VALUES:
+                       /* okay */
+                       break;
+               case EXPR_KIND_CHECK_CONSTRAINT:
+               case EXPR_KIND_DOMAIN_CHECK:
+                       err = _("cannot use subquery in CHECK constraint");
+                       break;
+               case EXPR_KIND_COLUMN_DEFAULT:
+               case EXPR_KIND_FUNCTION_DEFAULT:
+                       err = _("cannot use subquery in DEFAULT expression");
+                       break;
+               case EXPR_KIND_INDEX_EXPRESSION:
+                       err = _("cannot use subquery in index expression");
+                       break;
+               case EXPR_KIND_INDEX_PREDICATE:
+                       err = _("cannot use subquery in index predicate");
+                       break;
+               case EXPR_KIND_ALTER_COL_TRANSFORM:
+                       err = _("cannot use subquery in transform expression");
+                       break;
+               case EXPR_KIND_EXECUTE_PARAMETER:
+                       err = _("cannot use subquery in EXECUTE parameter");
+                       break;
+               case EXPR_KIND_TRIGGER_WHEN:
+                       err = _("cannot use subquery in trigger WHEN condition");
+                       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, sublink->location)));
+
        pstate->p_hasSubLinks = true;
+
+       /*
+        * OK, let's transform the sub-SELECT.
+        */
        qtree = parse_sub_analyze(sublink->subselect, pstate, NULL, false);
 
        /*
@@ -1450,7 +1552,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
                /*
                 * Transform lefthand expression, and convert to a list
                 */
-               lefthand = transformExpr(pstate, sublink->testexpr);
+               lefthand = transformExprRecurse(pstate, sublink->testexpr);
                if (lefthand && IsA(lefthand, RowExpr))
                        left_list = ((RowExpr *) lefthand)->args;
                else
@@ -1557,7 +1659,7 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
                }
                else
                {
-                       newe = transformExpr(pstate, e);
+                       newe = transformExprRecurse(pstate, e);
 
                        /*
                         * Check for sub-array expressions, if we haven't already found
@@ -1679,7 +1781,7 @@ transformRowExpr(ParseState *pstate, RowExpr *r)
        ListCell   *lc;
 
        /* Transform the field expressions */
-       newr->args = transformExpressionList(pstate, r->args);
+       newr->args = transformExpressionList(pstate, r->args, pstate->p_expr_kind);
 
        /* Barring later casting, we consider the type RECORD */
        newr->row_typeid = RECORDOID;
@@ -1712,7 +1814,7 @@ transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c)
                Node       *e = (Node *) lfirst(args);
                Node       *newe;
 
-               newe = transformExpr(pstate, e);
+               newe = transformExprRecurse(pstate, e);
                newargs = lappend(newargs, newe);
        }
 
@@ -1751,7 +1853,7 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
                Node       *e = (Node *) lfirst(args);
                Node       *newe;
 
-               newe = transformExpr(pstate, e);
+               newe = transformExprRecurse(pstate, e);
                newargs = lappend(newargs, newe);
        }
 
@@ -1805,7 +1907,7 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
 
                Assert(IsA(r, ResTarget));
 
-               expr = transformExpr(pstate, r->val);
+               expr = transformExprRecurse(pstate, r->val);
 
                if (r->name)
                        argname = map_sql_identifier_to_xml_name(r->name, false, false);
@@ -1851,7 +1953,7 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
                Node       *e = (Node *) lfirst(lc);
                Node       *newe;
 
-               newe = transformExpr(pstate, e);
+               newe = transformExprRecurse(pstate, e);
                switch (x->op)
                {
                        case IS_XMLCONCAT:
@@ -1914,7 +2016,7 @@ transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
        xexpr = makeNode(XmlExpr);
        xexpr->op = IS_XMLSERIALIZE;
        xexpr->args = list_make1(coerce_to_specific_type(pstate,
-                                                                                        transformExpr(pstate, xs->expr),
+                                                                               transformExprRecurse(pstate, xs->expr),
                                                                                                         XMLOID,
                                                                                                         "XMLSERIALIZE"));
 
@@ -1977,7 +2079,7 @@ transformBooleanTest(ParseState *pstate, BooleanTest *b)
                        clausename = NULL;      /* keep compiler quiet */
        }
 
-       b->arg = (Expr *) transformExpr(pstate, (Node *) b->arg);
+       b->arg = (Expr *) transformExprRecurse(pstate, (Node *) b->arg);
 
        b->arg = (Expr *) coerce_to_boolean(pstate,
                                                                                (Node *) b->arg,
@@ -2082,7 +2184,7 @@ static Node *
 transformTypeCast(ParseState *pstate, TypeCast *tc)
 {
        Node       *result;
-       Node       *expr = transformExpr(pstate, tc->arg);
+       Node       *expr = transformExprRecurse(pstate, tc->arg);
        Oid                     inputType = exprType(expr);
        Oid                     targetType;
        int32           targetTypmod;
@@ -2130,7 +2232,7 @@ transformCollateClause(ParseState *pstate, CollateClause *c)
        Oid                     argtype;
 
        newc = makeNode(CollateExpr);
-       newc->arg = (Expr *) transformExpr(pstate, c->arg);
+       newc->arg = (Expr *) transformExprRecurse(pstate, c->arg);
 
        argtype = exprType((Node *) newc->arg);
 
@@ -2433,3 +2535,87 @@ make_distinct_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
 
        return result;
 }
+
+/*
+ * Produce a string identifying an expression by kind.
+ *
+ * Note: when practical, use a simple SQL keyword for the result.  If that
+ * doesn't work well, check call sites to see whether custom error message
+ * strings are required.
+ */
+const char *
+ParseExprKindName(ParseExprKind exprKind)
+{
+       switch (exprKind)
+       {
+               case EXPR_KIND_NONE:
+                       return "invalid expression context";
+               case EXPR_KIND_OTHER:
+                       return "extension expression";
+               case EXPR_KIND_JOIN_ON:
+                       return "JOIN/ON";
+               case EXPR_KIND_JOIN_USING:
+                       return "JOIN/USING";
+               case EXPR_KIND_FROM_SUBSELECT:
+                       return "sub-SELECT in FROM";
+               case EXPR_KIND_FROM_FUNCTION:
+                       return "function in FROM";
+               case EXPR_KIND_WHERE:
+                       return "WHERE";
+               case EXPR_KIND_HAVING:
+                       return "HAVING";
+               case EXPR_KIND_WINDOW_PARTITION:
+                       return "window PARTITION BY";
+               case EXPR_KIND_WINDOW_ORDER:
+                       return "window ORDER BY";
+               case EXPR_KIND_WINDOW_FRAME_RANGE:
+                       return "window RANGE";
+               case EXPR_KIND_WINDOW_FRAME_ROWS:
+                       return "window ROWS";
+               case EXPR_KIND_SELECT_TARGET:
+                       return "SELECT";
+               case EXPR_KIND_INSERT_TARGET:
+                       return "INSERT";
+               case EXPR_KIND_UPDATE_SOURCE:
+               case EXPR_KIND_UPDATE_TARGET:
+                       return "UPDATE";
+               case EXPR_KIND_GROUP_BY:
+                       return "GROUP BY";
+               case EXPR_KIND_ORDER_BY:
+                       return "ORDER BY";
+               case EXPR_KIND_DISTINCT_ON:
+                       return "DISTINCT ON";
+               case EXPR_KIND_LIMIT:
+                       return "LIMIT";
+               case EXPR_KIND_OFFSET:
+                       return "OFFSET";
+               case EXPR_KIND_RETURNING:
+                       return "RETURNING";
+               case EXPR_KIND_VALUES:
+                       return "VALUES";
+               case EXPR_KIND_CHECK_CONSTRAINT:
+               case EXPR_KIND_DOMAIN_CHECK:
+                       return "CHECK";
+               case EXPR_KIND_COLUMN_DEFAULT:
+               case EXPR_KIND_FUNCTION_DEFAULT:
+                       return "DEFAULT";
+               case EXPR_KIND_INDEX_EXPRESSION:
+                       return "index expression";
+               case EXPR_KIND_INDEX_PREDICATE:
+                       return "index predicate";
+               case EXPR_KIND_ALTER_COL_TRANSFORM:
+                       return "USING";
+               case EXPR_KIND_EXECUTE_PARAMETER:
+                       return "EXECUTE";
+               case EXPR_KIND_TRIGGER_WHEN:
+                       return "WHEN";
+
+                       /*
+                        * 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, we'll fall through to the "unrecognized" return.
+                        */
+       }
+       return "unrecognized expression kind";
+}
index 80dbdd19e48ce39605b5cfdcd88fca8fd592d5e2..6aaeae76b0a68b4988a15524b687ff53f4a50011 100644 (file)
@@ -328,7 +328,7 @@ transformArraySubscripts(ParseState *pstate,
                {
                        if (ai->lidx)
                        {
-                               subexpr = transformExpr(pstate, ai->lidx);
+                               subexpr = transformExpr(pstate, ai->lidx, pstate->p_expr_kind);
                                /* If it's not int4 already, try to coerce */
                                subexpr = coerce_to_target_type(pstate,
                                                                                                subexpr, exprType(subexpr),
@@ -355,7 +355,7 @@ transformArraySubscripts(ParseState *pstate,
                        }
                        lowerIndexpr = lappend(lowerIndexpr, subexpr);
                }
-               subexpr = transformExpr(pstate, ai->uidx);
+               subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
                /* If it's not int4 already, try to coerce */
                subexpr = coerce_to_target_type(pstate,
                                                                                subexpr, exprType(subexpr),
index ccd97fc845d3ae3e980203b94cc52d2852f0ddd1..053b3a0dad1fc0199ab056d30c41f535cb0964b5 100644 (file)
@@ -57,14 +57,14 @@ static Node *transformAssignmentSubscripts(ParseState *pstate,
                                                          Node *rhs,
                                                          int location);
 static List *ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
-                                       bool targetlist);
+                                       bool make_target_entry);
 static List *ExpandAllTables(ParseState *pstate, int location);
 static List *ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind,
-                                         bool targetlist);
+                                         bool make_target_entry, ParseExprKind exprKind);
 static List *ExpandSingleTable(ParseState *pstate, RangeTblEntry *rte,
-                                 int location, bool targetlist);
+                                 int location, bool make_target_entry);
 static List *ExpandRowReference(ParseState *pstate, Node *expr,
-                                  bool targetlist);
+                                  bool make_target_entry);
 static int     FigureColnameInternal(Node *node, char **name);
 
 
@@ -76,6 +76,7 @@ static int    FigureColnameInternal(Node *node, char **name);
  *
  * node                the (untransformed) parse tree for the value expression.
  * expr                the transformed expression, or NULL if caller didn't do it yet.
+ * exprKind    expression kind (EXPR_KIND_SELECT_TARGET, etc)
  * colname     the column name to be assigned, or NULL if none yet set.
  * resjunk     true if the target should be marked resjunk, ie, it is not
  *                     wanted in the final projected tuple.
@@ -84,12 +85,13 @@ TargetEntry *
 transformTargetEntry(ParseState *pstate,
                                         Node *node,
                                         Node *expr,
+                                        ParseExprKind exprKind,
                                         char *colname,
                                         bool resjunk)
 {
        /* Transform the node if caller didn't do it already */
        if (expr == NULL)
-               expr = transformExpr(pstate, node);
+               expr = transformExpr(pstate, node, exprKind);
 
        if (colname == NULL && !resjunk)
        {
@@ -111,11 +113,13 @@ transformTargetEntry(ParseState *pstate,
  * transformTargetList()
  * Turns a list of ResTarget's into a list of TargetEntry's.
  *
- * At this point, we don't care whether we are doing SELECT, INSERT,
- * or UPDATE; we just transform the given expressions (the "val" fields).
+ * At this point, we don't care whether we are doing SELECT, UPDATE,
+ * or RETURNING; we just transform the given expressions (the "val" fields).
+ * However, our subroutines care, so we need the exprKind parameter.
  */
 List *
-transformTargetList(ParseState *pstate, List *targetlist)
+transformTargetList(ParseState *pstate, List *targetlist,
+                                       ParseExprKind exprKind)
 {
        List       *p_target = NIL;
        ListCell   *o_target;
@@ -151,7 +155,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
                                /* It is something.*, expand into multiple items */
                                p_target = list_concat(p_target,
                                                                           ExpandIndirectionStar(pstate, ind,
-                                                                                                                        true));
+                                                                                                                        true, exprKind));
                                continue;
                        }
                }
@@ -163,6 +167,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
                                                   transformTargetEntry(pstate,
                                                                                                res->val,
                                                                                                NULL,
+                                                                                               exprKind,
                                                                                                res->name,
                                                                                                false));
        }
@@ -180,7 +185,8 @@ transformTargetList(ParseState *pstate, List *targetlist)
  * decoration. We use this for ROW() and VALUES() constructs.
  */
 List *
-transformExpressionList(ParseState *pstate, List *exprlist)
+transformExpressionList(ParseState *pstate, List *exprlist,
+                                               ParseExprKind exprKind)
 {
        List       *result = NIL;
        ListCell   *lc;
@@ -216,7 +222,7 @@ transformExpressionList(ParseState *pstate, List *exprlist)
                                /* It is something.*, expand into multiple items */
                                result = list_concat(result,
                                                                         ExpandIndirectionStar(pstate, ind,
-                                                                                                                  false));
+                                                                                                                  false, exprKind));
                                continue;
                        }
                }
@@ -225,7 +231,7 @@ transformExpressionList(ParseState *pstate, List *exprlist)
                 * Not "something.*", so transform as a single expression
                 */
                result = lappend(result,
-                                                transformExpr(pstate, e));
+                                                transformExpr(pstate, e, exprKind));
        }
 
        return result;
@@ -350,6 +356,7 @@ markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
  *
  * pstate              parse state
  * expr                        expression to be modified
+ * exprKind            indicates which type of statement we're dealing with
  * colname             target column name (ie, name of attribute to be assigned to)
  * attrno              target attribute number
  * indirection subscripts/field names for target column, if any
@@ -365,16 +372,27 @@ markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
 Expr *
 transformAssignedExpr(ParseState *pstate,
                                          Expr *expr,
+                                         ParseExprKind exprKind,
                                          char *colname,
                                          int attrno,
                                          List *indirection,
                                          int location)
 {
+       Relation        rd = pstate->p_target_relation;
        Oid                     type_id;                /* type of value provided */
        Oid                     attrtype;               /* type of target column */
        int32           attrtypmod;
        Oid                     attrcollation;  /* collation of target column */
-       Relation        rd = pstate->p_target_relation;
+       ParseExprKind sv_expr_kind;
+
+       /*
+        * Save and restore identity of expression type we're parsing.  We must
+        * set p_expr_kind here because we can parse subscripts without going
+        * through transformExpr().
+        */
+       Assert(exprKind != EXPR_KIND_NONE);
+       sv_expr_kind = pstate->p_expr_kind;
+       pstate->p_expr_kind = exprKind;
 
        Assert(rd != NULL);
        if (attrno <= 0)
@@ -491,6 +509,8 @@ transformAssignedExpr(ParseState *pstate,
                                         parser_errposition(pstate, exprLocation(orig_expr))));
        }
 
+       pstate->p_expr_kind = sv_expr_kind;
+
        return expr;
 }
 
@@ -521,6 +541,7 @@ updateTargetListEntry(ParseState *pstate,
        /* Fix up expression as needed */
        tle->expr = transformAssignedExpr(pstate,
                                                                          tle->expr,
+                                                                         EXPR_KIND_UPDATE_TARGET,
                                                                          colname,
                                                                          attrno,
                                                                          indirection,
@@ -947,7 +968,7 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
  */
 static List *
 ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
-                                       bool targetlist)
+                                       bool make_target_entry)
 {
        List       *fields = cref->fields;
        int                     numnames = list_length(fields);
@@ -960,9 +981,9 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
                 * (e.g., SELECT * FROM emp, dept)
                 *
                 * Since the grammar only accepts bare '*' at top level of SELECT, we
-                * need not handle the targetlist==false case here.
+                * need not handle the make_target_entry==false case here.
                 */
-               Assert(targetlist);
+               Assert(make_target_entry);
                return ExpandAllTables(pstate, cref->location);
        }
        else
@@ -1002,7 +1023,7 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
 
                        node = (*pstate->p_pre_columnref_hook) (pstate, cref);
                        if (node != NULL)
-                               return ExpandRowReference(pstate, node, targetlist);
+                               return ExpandRowReference(pstate, node, make_target_entry);
                }
 
                switch (numnames)
@@ -1065,7 +1086,7 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
                                                         errmsg("column reference \"%s\" is ambiguous",
                                                                        NameListToString(cref->fields)),
                                                         parser_errposition(pstate, cref->location)));
-                               return ExpandRowReference(pstate, node, targetlist);
+                               return ExpandRowReference(pstate, node, make_target_entry);
                        }
                }
 
@@ -1100,7 +1121,7 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
                /*
                 * OK, expand the RTE into fields.
                 */
-               return ExpandSingleTable(pstate, rte, cref->location, targetlist);
+               return ExpandSingleTable(pstate, rte, cref->location, make_target_entry);
        }
 }
 
@@ -1166,10 +1187,12 @@ ExpandAllTables(ParseState *pstate, int location)
  * The code is shared between the case of foo.* at the top level in a SELECT
  * target list (where we want TargetEntry nodes in the result) and foo.* in
  * a ROW() or VALUES() construct (where we want just bare expressions).
+ * For robustness, we use a separate "make_target_entry" flag to control
+ * this rather than relying on exprKind.
  */
 static List *
 ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind,
-                                         bool targetlist)
+                                         bool make_target_entry, ParseExprKind exprKind)
 {
        Node       *expr;
 
@@ -1179,10 +1202,10 @@ ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind,
                                                                         list_length(ind->indirection) - 1);
 
        /* And transform that */
-       expr = transformExpr(pstate, (Node *) ind);
+       expr = transformExpr(pstate, (Node *) ind, exprKind);
 
        /* Expand the rowtype expression into individual fields */
-       return ExpandRowReference(pstate, expr, targetlist);
+       return ExpandRowReference(pstate, expr, make_target_entry);
 }
 
 /*
@@ -1196,14 +1219,14 @@ ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind,
  */
 static List *
 ExpandSingleTable(ParseState *pstate, RangeTblEntry *rte,
-                                 int location, bool targetlist)
+                                 int location, bool make_target_entry)
 {
        int                     sublevels_up;
        int                     rtindex;
 
        rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up);
 
-       if (targetlist)
+       if (make_target_entry)
        {
                /* expandRelAttrs handles permissions marking */
                return expandRelAttrs(pstate, rte, rtindex, sublevels_up,
@@ -1245,7 +1268,7 @@ ExpandSingleTable(ParseState *pstate, RangeTblEntry *rte,
  */
 static List *
 ExpandRowReference(ParseState *pstate, Node *expr,
-                                  bool targetlist)
+                                  bool make_target_entry)
 {
        List       *result = NIL;
        TupleDesc       tupleDesc;
@@ -1268,7 +1291,7 @@ ExpandRowReference(ParseState *pstate, Node *expr,
                RangeTblEntry *rte;
 
                rte = GetRTEByRangeTablePosn(pstate, var->varno, var->varlevelsup);
-               return ExpandSingleTable(pstate, rte, var->location, targetlist);
+               return ExpandSingleTable(pstate, rte, var->location, make_target_entry);
        }
 
        /*
@@ -1313,7 +1336,7 @@ ExpandRowReference(ParseState *pstate, Node *expr,
                /* save attribute's collation for parse_collate.c */
                fselect->resultcollid = att->attcollation;
 
-               if (targetlist)
+               if (make_target_entry)
                {
                        /* add TargetEntry decoration */
                        TargetEntry *te;
index c22c6ed21f76e0846da1d2886e4371501878af2f..accda01f4574d0d5a439fcdf4bc49e6ac16449e5 100644 (file)
@@ -1917,6 +1917,7 @@ transformIndexStmt(IndexStmt *stmt, const char *queryString)
        {
                stmt->whereClause = transformWhereClause(pstate,
                                                                                                 stmt->whereClause,
+                                                                                                EXPR_KIND_INDEX_PREDICATE,
                                                                                                 "WHERE");
                /* we have to fix its collations too */
                assign_expr_collations(pstate, stmt->whereClause);
@@ -1934,15 +1935,20 @@ transformIndexStmt(IndexStmt *stmt, const char *queryString)
                                ielem->indexcolname = FigureIndexColname(ielem->expr);
 
                        /* Now do parse transformation of the expression */
-                       ielem->expr = transformExpr(pstate, ielem->expr);
+                       ielem->expr = transformExpr(pstate, ielem->expr,
+                                                                               EXPR_KIND_INDEX_EXPRESSION);
 
                        /* We have to fix its collations too */
                        assign_expr_collations(pstate, ielem->expr);
 
                        /*
-                        * We check only that the result type is legitimate; this is for
-                        * consistency with what transformWhereClause() checks for the
-                        * predicate.  DefineIndex() will make more checks.
+                        * transformExpr() should have already rejected subqueries,
+                        * aggregates, and window functions, based on the EXPR_KIND_ for
+                        * an index expression.
+                        *
+                        * Also reject expressions returning sets; this is for consistency
+                        * with what transformWhereClause() checks for the predicate.
+                        * DefineIndex() will make more checks.
                         */
                        if (expression_returns_set(ielem->expr))
                                ereport(ERROR,
@@ -1952,7 +1958,8 @@ transformIndexStmt(IndexStmt *stmt, const char *queryString)
        }
 
        /*
-        * Check that only the base rel is mentioned.
+        * Check that only the base rel is mentioned.  (This should be dead code
+        * now that add_missing_from is history.)
         */
        if (list_length(pstate->p_rtable) != 1)
                ereport(ERROR,
@@ -2047,25 +2054,17 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
        /* take care of the where clause */
        *whereClause = transformWhereClause(pstate,
                                                                          (Node *) copyObject(stmt->whereClause),
+                                                                               EXPR_KIND_WHERE,
                                                                                "WHERE");
        /* we have to fix its collations too */
        assign_expr_collations(pstate, *whereClause);
 
+       /* this is probably dead code without add_missing_from: */
        if (list_length(pstate->p_rtable) != 2)         /* naughty, naughty... */
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                 errmsg("rule WHERE condition cannot contain references to other relations")));
 
-       /* aggregates not allowed (but subselects are okay) */
-       if (pstate->p_hasAggs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_GROUPING_ERROR),
-                  errmsg("cannot use aggregate function in rule WHERE condition")));
-       if (pstate->p_hasWindowFuncs)
-               ereport(ERROR,
-                               (errcode(ERRCODE_WINDOWING_ERROR),
-                         errmsg("cannot use window function in rule WHERE condition")));
-
        /*
         * 'instead nothing' rules with a qualification need a query rangetable so
         * the rewrite handler can add the negated rule qualification to the
index 9c778efd1c39849726c775aab55e3bdf3d97487f..5fcf2741988cb450eabaf76b65c471ca8905e97f 100644 (file)
@@ -52,17 +52,6 @@ static Relids offset_relid_set(Relids relids, int offset);
 static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
 
 
-/*
- * checkExprHasAggs -
- *     Check if an expression contains an aggregate function call of the
- *     current query level.
- */
-bool
-checkExprHasAggs(Node *node)
-{
-       return contain_aggs_of_level(node, 0);
-}
-
 /*
  * contain_aggs_of_level -
  *     Check if an expression contains an aggregate function call of a
@@ -185,12 +174,12 @@ locate_agg_of_level_walker(Node *node,
 }
 
 /*
- * checkExprHasWindowFuncs -
+ * contain_windowfuncs -
  *     Check if an expression contains a window function call of the
  *     current query level.
  */
 bool
-checkExprHasWindowFuncs(Node *node)
+contain_windowfuncs(Node *node)
 {
        /*
         * Must be prepared to start with a Query or a bare expression tree; if
@@ -1049,7 +1038,7 @@ AddQual(Query *parsetree, Node *qual)
        /*
         * We had better not have stuck an aggregate into the WHERE clause.
         */
-       Assert(!checkExprHasAggs(copy));
+       Assert(!contain_aggs_of_level(copy, 0));
 
        /*
         * Make sure query is marked correctly if added qual has sublinks. Need
index ec21df3a7e0e1119be5802c7ade25b642e405a42..e3ba3144f367b5875ebfac49b49beffa0d57d08b 100644 (file)
@@ -37,7 +37,6 @@ extern List *pull_vars_of_level(Node *node, int levelsup);
 extern bool contain_var_clause(Node *node);
 extern bool contain_vars_of_level(Node *node, int levelsup);
 extern int     locate_var_of_level(Node *node, int levelsup);
-extern int     find_minimum_var_level(Node *node);
 extern List *pull_var_clause(Node *node, PVCAggregateBehavior aggbehavior,
                                PVCPlaceHolderBehavior phbehavior);
 extern Node *flatten_join_alias_vars(PlannerInfo *root, Node *node);
index b32ee6c2725e9c295e1ac6e40bf115429085df4e..c51fdd81411a00c5912ae3fd14a0167cc164039a 100644 (file)
@@ -22,7 +22,6 @@ extern void transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc,
                                                WindowDef *windef);
 
 extern void parseCheckAggregates(ParseState *pstate, Query *qry);
-extern void parseCheckWindowFuncs(ParseState *pstate, Query *qry);
 
 extern void build_aggregate_fnexprs(Oid *agg_input_types,
                                                int agg_num_inputs,
index fd3fc8f5709692240c0edfee0ac85d1e18d6a12e..5d59ee973c786786cdb11cc5de999d01886e0815 100644 (file)
@@ -23,14 +23,15 @@ extern bool interpretInhOption(InhOption inhOpt);
 extern bool interpretOidsOption(List *defList);
 
 extern Node *transformWhereClause(ParseState *pstate, Node *clause,
-                                        const char *constructName);
+                                        ParseExprKind exprKind, const char *constructName);
 extern Node *transformLimitClause(ParseState *pstate, Node *clause,
-                                        const char *constructName);
+                                        ParseExprKind exprKind, const char *constructName);
 extern List *transformGroupClause(ParseState *pstate, List *grouplist,
                                         List **targetlist, List *sortClause,
-                                        bool useSQL99);
+                                        ParseExprKind exprKind, bool useSQL99);
 extern List *transformSortClause(ParseState *pstate, List *orderlist,
-                                       List **targetlist, bool resolveUnknown, bool useSQL99);
+                                       List **targetlist, ParseExprKind exprKind,
+                                       bool resolveUnknown, bool useSQL99);
 
 extern List *transformWindowDefinitions(ParseState *pstate,
                                                   List *windowdefs,
index cbf281e315ca48b75fffb26dfea4f843df9db742..b9b9c7ee4dd997e96561980068ba15fa55fbed37 100644 (file)
@@ -18,6 +18,8 @@
 /* GUC parameters */
 extern bool Transform_null_equals;
 
-extern Node *transformExpr(ParseState *pstate, Node *expr);
+extern Node *transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind);
+
+extern const char *ParseExprKindName(ParseExprKind exprKind);
 
 #endif   /* PARSE_EXPR_H */
index 200b9744e511ed9b2d3459f3b3d318c2080b0f4f..e3bb35f1308350dc50481eaabb536fc623737b91 100644 (file)
 #include "utils/relcache.h"
 
 
+/*
+ * Expression kinds distinguished by transformExpr().  Many of these are not
+ * semantically distinct so far as expression transformation goes; rather,
+ * we distinguish them so that context-specific error messages can be printed.
+ *
+ * Note: EXPR_KIND_OTHER is not used in the core code, but is left for use
+ * by extension code that might need to call transformExpr().  The core code
+ * will not enforce any context-driven restrictions on EXPR_KIND_OTHER
+ * expressions, so the caller would have to check for sub-selects, aggregates,
+ * and window functions if those need to be disallowed.
+ */
+typedef enum ParseExprKind
+{
+       EXPR_KIND_NONE = 0,                             /* "not in an expression" */
+       EXPR_KIND_OTHER,                                /* reserved for extensions */
+       EXPR_KIND_JOIN_ON,                              /* JOIN ON */
+       EXPR_KIND_JOIN_USING,                   /* JOIN USING */
+       EXPR_KIND_FROM_SUBSELECT,               /* sub-SELECT in FROM clause */
+       EXPR_KIND_FROM_FUNCTION,                /* function in FROM clause */
+       EXPR_KIND_WHERE,                                /* WHERE */
+       EXPR_KIND_HAVING,                               /* HAVING */
+       EXPR_KIND_WINDOW_PARTITION,             /* window definition PARTITION BY */
+       EXPR_KIND_WINDOW_ORDER,                 /* window definition ORDER BY */
+       EXPR_KIND_WINDOW_FRAME_RANGE,   /* window frame clause with RANGE */
+       EXPR_KIND_WINDOW_FRAME_ROWS,    /* window frame clause with ROWS */
+       EXPR_KIND_SELECT_TARGET,                /* SELECT target list item */
+       EXPR_KIND_INSERT_TARGET,                /* INSERT target list item */
+       EXPR_KIND_UPDATE_SOURCE,                /* UPDATE assignment source item */
+       EXPR_KIND_UPDATE_TARGET,                /* UPDATE assignment target item */
+       EXPR_KIND_GROUP_BY,                             /* GROUP BY */
+       EXPR_KIND_ORDER_BY,                             /* ORDER BY */
+       EXPR_KIND_DISTINCT_ON,                  /* DISTINCT ON */
+       EXPR_KIND_LIMIT,                                /* LIMIT */
+       EXPR_KIND_OFFSET,                               /* OFFSET */
+       EXPR_KIND_RETURNING,                    /* RETURNING */
+       EXPR_KIND_VALUES,                               /* VALUES */
+       EXPR_KIND_CHECK_CONSTRAINT,             /* CHECK constraint for a table */
+       EXPR_KIND_DOMAIN_CHECK,                 /* CHECK constraint for a domain */
+       EXPR_KIND_COLUMN_DEFAULT,               /* default value for a table column */
+       EXPR_KIND_FUNCTION_DEFAULT,             /* default parameter value for function */
+       EXPR_KIND_INDEX_EXPRESSION,             /* index expression */
+       EXPR_KIND_INDEX_PREDICATE,              /* index predicate */
+       EXPR_KIND_ALTER_COL_TRANSFORM,  /* transform expr in ALTER COLUMN TYPE */
+       EXPR_KIND_EXECUTE_PARAMETER,    /* parameter value in EXECUTE */
+       EXPR_KIND_TRIGGER_WHEN                  /* WHEN condition in CREATE TRIGGER */
+} ParseExprKind;
+
+
 /*
  * Function signatures for parser hooks
  */
@@ -93,6 +141,7 @@ struct ParseState
        List       *p_future_ctes;      /* common table exprs not yet in namespace */
        CommonTableExpr *p_parent_cte;          /* this query's containing CTE */
        List       *p_windowdefs;       /* raw representations of window clauses */
+       ParseExprKind p_expr_kind;      /* what kind of expression we're parsing */
        int                     p_next_resno;   /* next targetlist resno to assign */
        List       *p_locking_clause;           /* raw FOR UPDATE/FOR SHARE info */
        Node       *p_value_substitute;         /* what to replace VALUE with, if any */
index d274a66b13e4f8aff2c6ce05a4917e41ee468942..e5bbaf4e12e7f061f3884a3c6ffc79af94be4f23 100644 (file)
 #include "parser/parse_node.h"
 
 
-extern List *transformTargetList(ParseState *pstate, List *targetlist);
-extern List *transformExpressionList(ParseState *pstate, List *exprlist);
+extern List *transformTargetList(ParseState *pstate, List *targetlist,
+                                       ParseExprKind exprKind);
+extern List *transformExpressionList(ParseState *pstate, List *exprlist,
+                                               ParseExprKind exprKind);
 extern void markTargetListOrigins(ParseState *pstate, List *targetlist);
 extern TargetEntry *transformTargetEntry(ParseState *pstate,
-                                        Node *node, Node *expr,
+                                        Node *node, Node *expr, ParseExprKind exprKind,
                                         char *colname, bool resjunk);
 extern Expr *transformAssignedExpr(ParseState *pstate, Expr *expr,
+                                         ParseExprKind exprKind,
                                          char *colname,
                                          int attrno,
                                          List *indirection,
index 6f57b37b81443ba1a5b7a450b2cb005b99831187..e13331dcb5e41c8d872f9a65344fedcdfc966318 100644 (file)
@@ -52,9 +52,8 @@ extern void AddInvertedQual(Query *parsetree, Node *qual);
 
 extern bool contain_aggs_of_level(Node *node, int levelsup);
 extern int     locate_agg_of_level(Node *node, int levelsup);
+extern bool contain_windowfuncs(Node *node);
 extern int     locate_windowfunc(Node *node);
-extern bool checkExprHasAggs(Node *node);
-extern bool checkExprHasWindowFuncs(Node *node);
 extern bool checkExprHasSubLink(Node *node);
 
 extern Node *replace_rte_variables(Node *node,
index 5678f066cbf9b07f2d5bc9384e65e92906cc1e42..6ca73a0ed73fc9c2fa18701f17fa34b7f12db131 100644 (file)
@@ -292,7 +292,7 @@ select ten, sum(distinct four) from onek a
 group by ten
 having exists (select 1 from onek b
                where sum(distinct a.four + b.four) = b.four);
-ERROR:  aggregates not allowed in WHERE clause
+ERROR:  aggregate functions are not allowed in WHERE
 LINE 4:                where sum(distinct a.four + b.four) = b.four)...
                              ^
 -- Test handling of sublinks within outer-level aggregates.
@@ -745,6 +745,15 @@ NOTICE:  drop cascades to 3 other objects
 DETAIL:  drop cascades to table minmaxtest1
 drop cascades to table minmaxtest2
 drop cascades to table minmaxtest3
+-- check for correct detection of nested-aggregate errors
+select max(min(unique1)) from tenk1;
+ERROR:  aggregate function calls cannot be nested
+LINE 1: select max(min(unique1)) from tenk1;
+                   ^
+select (select max(min(unique1)) from int8_tbl) from tenk1;
+ERROR:  aggregate function calls cannot be nested
+LINE 1: select (select max(min(unique1)) from int8_tbl) from tenk1;
+                           ^
 --
 -- Test combinations of DISTINCT and/or ORDER BY
 --
index c5b92582b4cf29317ae8e391a6637d1d9c789a9c..5e17432198ec81a53d50943636afbb57edb88b72 100644 (file)
@@ -3143,6 +3143,6 @@ LINE 1: ...m int4_tbl a full join lateral generate_series(0, a.f1) g on...
 DETAIL:  The combining JOIN type must be INNER or LEFT for a LATERAL reference.
 -- LATERAL can be used to put an aggregate into the FROM clause of its query
 select 1 from tenk1 a, lateral (select max(a.unique1) from int4_tbl b) ss;
-ERROR:  aggregates not allowed in FROM clause
+ERROR:  aggregate functions are not allowed in FROM clause of their own query level
 LINE 1: select 1 from tenk1 a, lateral (select max(a.unique1) from i...
                                                ^
index fde375cc9f7052200b44f05fe1b1892a655298e0..777862662556743553473450be7c947dd7271c60 100644 (file)
@@ -958,32 +958,32 @@ SELECT rank() OVER (ORDER BY length('abc'));
 
 -- can't order by another window function
 SELECT rank() OVER (ORDER BY rank() OVER (ORDER BY random()));
-ERROR:  window functions not allowed in window definition
+ERROR:  window functions are not allowed in window definitions
 LINE 1: SELECT rank() OVER (ORDER BY rank() OVER (ORDER BY random())...
                                      ^
 -- some other errors
 SELECT * FROM empsalary WHERE row_number() OVER (ORDER BY salary) < 10;
-ERROR:  window functions not allowed in WHERE clause
+ERROR:  window functions are not allowed in WHERE
 LINE 1: SELECT * FROM empsalary WHERE row_number() OVER (ORDER BY sa...
                                       ^
 SELECT * FROM empsalary INNER JOIN tenk1 ON row_number() OVER (ORDER BY salary) < 10;
-ERROR:  window functions not allowed in JOIN conditions
+ERROR:  window functions are not allowed in JOIN conditions
 LINE 1: SELECT * FROM empsalary INNER JOIN tenk1 ON row_number() OVE...
                                                     ^
 SELECT rank() OVER (ORDER BY 1), count(*) FROM empsalary GROUP BY 1;
-ERROR:  window functions not allowed in GROUP BY clause
+ERROR:  window functions are not allowed in GROUP BY
 LINE 1: SELECT rank() OVER (ORDER BY 1), count(*) FROM empsalary GRO...
                ^
 SELECT * FROM rank() OVER (ORDER BY random());
-ERROR:  cannot use window function in function expression in FROM
+ERROR:  window functions are not allowed in functions in FROM
 LINE 1: SELECT * FROM rank() OVER (ORDER BY random());
                       ^
 DELETE FROM empsalary WHERE (rank() OVER (ORDER BY random())) > 10;
-ERROR:  window functions not allowed in WHERE clause
+ERROR:  window functions are not allowed in WHERE
 LINE 1: DELETE FROM empsalary WHERE (rank() OVER (ORDER BY random())...
                                      ^
 DELETE FROM empsalary RETURNING rank() OVER (ORDER BY random());
-ERROR:  cannot use window function in RETURNING
+ERROR:  window functions are not allowed in RETURNING
 LINE 1: DELETE FROM empsalary RETURNING rank() OVER (ORDER BY random...
                                         ^
 SELECT count(*) OVER w FROM tenk1 WINDOW w AS (ORDER BY unique1), w AS (ORDER BY unique1);
index 0d59ea3fdf97481d6db4bed15fb02609029ddfe8..a491b2ca61f82bee3978a1b2bf262bc646fe91bd 100644 (file)
@@ -937,12 +937,12 @@ LINE 2:                           WHERE n IN (SELECT * FROM x))
 -- aggregate functions
 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT count(*) FROM x)
   SELECT * FROM x;
-ERROR:  aggregate functions not allowed in a recursive query's recursive term
+ERROR:  aggregate functions are not allowed in a recursive query's recursive term
 LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT count(*) F...
                                                           ^
 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT sum(n) FROM x)
   SELECT * FROM x;
-ERROR:  aggregate functions not allowed in a recursive query's recursive term
+ERROR:  aggregate functions are not allowed in a recursive query's recursive term
 LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT sum(n) FRO...
                                                           ^
 -- ORDER BY
index d1c74720d3722cf633b9f063355360689944b1c8..53a2183b3dde54407d37701e48317704213c2377 100644 (file)
@@ -280,6 +280,10 @@ select min(f1), max(f1) from minmaxtest;
 
 drop table minmaxtest cascade;
 
+-- check for correct detection of nested-aggregate errors
+select max(min(unique1)) from tenk1;
+select (select max(min(unique1)) from int8_tbl) from tenk1;
+
 --
 -- Test combinations of DISTINCT and/or ORDER BY
 --