summaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/analyze.c138
-rw-r--r--src/backend/parser/parse_agg.c540
-rw-r--r--src/backend/parser/parse_clause.c202
-rw-r--r--src/backend/parser/parse_expr.c274
-rw-r--r--src/backend/parser/parse_node.c4
-rw-r--r--src/backend/parser/parse_target.c77
-rw-r--r--src/backend/parser/parse_utilcmd.c29
7 files changed, 829 insertions, 435 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 93ef724ffff..6c3d89a14f6 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -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);
@@ -1949,24 +1921,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;
}
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 5854f81005d..d1d835b8007 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -20,6 +20,7 @@
#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"
@@ -28,6 +29,14 @@
typedef struct
{
ParseState *pstate;
+ int min_varlevel;
+ int min_agglevel;
+ int sublevels_up;
+} check_agg_arguments_context;
+
+typedef struct
+{
+ ParseState *pstate;
Query *qry;
List *groupClauses;
bool have_non_var_grouping;
@@ -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,12 +429,15 @@ 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"),
@@ -221,6 +445,121 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc,
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
* properties of the OVER clause, and make a new entry in the p_windowdefs
@@ -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,97 +751,12 @@ 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
* that are not listed in the groupClauses list and are not within
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index d354baf42fa..ee40b5547ee 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -41,17 +41,6 @@
/* 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;
@@ -458,6 +448,14 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
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
* don't need save/restore logic here.)
@@ -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;
@@ -534,25 +534,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.
*/
rte = addRangeTableEntryForFunction(pstate, funcname, funcexpr,
@@ -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;
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 385f8e767e4..e9267c56fc5 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -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";
+}
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 80dbdd19e48..6aaeae76b0a 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -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),
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index ccd97fc845d..053b3a0dad1 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -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;
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