aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_agg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_agg.c')
-rw-r--r--src/backend/parser/parse_agg.c42
1 files changed, 27 insertions, 15 deletions
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index d85f64c7abc..e2645462d57 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.83 2008/09/01 20:42:44 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.84 2008/10/04 21:56:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -102,6 +102,7 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
bool have_non_var_grouping;
ListCell *l;
bool hasJoinRTEs;
+ bool hasSelfRefRTEs;
PlannerInfo *root;
Node *clause;
@@ -109,6 +110,21 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
Assert(pstate->p_hasAggs || qry->groupClause || qry->havingQual);
/*
+ * Scan the range table to see if there are JOIN or self-reference CTE
+ * entries. We'll need this info below.
+ */
+ hasJoinRTEs = hasSelfRefRTEs = false;
+ foreach(l, pstate->p_rtable)
+ {
+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
+
+ if (rte->rtekind == RTE_JOIN)
+ hasJoinRTEs = true;
+ else if (rte->rtekind == RTE_CTE && rte->self_reference)
+ hasSelfRefRTEs = true;
+ }
+
+ /*
* Aggregates must never appear in WHERE or JOIN/ON clauses.
*
* (Note this check should appear first to deliver an appropriate error
@@ -157,20 +173,6 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
* underlying vars, so that aliased and unaliased vars will be correctly
* taken as equal. We can skip the expense of doing this if no rangetable
* entries are RTE_JOIN kind.
- */
- hasJoinRTEs = false;
- foreach(l, pstate->p_rtable)
- {
- RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
-
- if (rte->rtekind == RTE_JOIN)
- {
- hasJoinRTEs = true;
- break;
- }
- }
-
- /*
* We use the planner's flatten_join_alias_vars routine to do the
* flattening; it wants a PlannerInfo root node, which fortunately can be
* mostly dummy.
@@ -217,6 +219,16 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
clause = flatten_join_alias_vars(root, clause);
check_ungrouped_columns(clause, pstate,
groupClauses, have_non_var_grouping);
+
+ /*
+ * Per spec, aggregates can't appear in a recursive term.
+ */
+ if (pstate->p_hasAggs && hasSelfRefRTEs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_RECURSION),
+ errmsg("aggregates not allowed in a recursive query's recursive term"),
+ parser_errposition(pstate,
+ locate_agg_of_level((Node *) qry, 0))));
}