aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_utilcmd.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2012-08-10 11:35:33 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2012-08-10 11:36:15 -0400
commiteaccfded98a9c677d3a2e849c1747ec90e8596a6 (patch)
treec341448f69a2e67484de7a0a43e12848c20eb414 /src/backend/parser/parse_utilcmd.c
parentb3055ab4fb5839a872bfe354b2b5ac31e6903ed6 (diff)
downloadpostgresql-eaccfded98a9c677d3a2e849c1747ec90e8596a6.tar.gz
postgresql-eaccfded98a9c677d3a2e849c1747ec90e8596a6.zip
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
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.)
Diffstat (limited to 'src/backend/parser/parse_utilcmd.c')
-rw-r--r--src/backend/parser/parse_utilcmd.c29
1 files changed, 14 insertions, 15 deletions
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index c22c6ed21f7..accda01f457 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -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