mirror of
https://github.com/postgres/postgres.git
synced 2025-07-09 22:41:56 +03:00
Support ORDER BY within aggregate function calls, at long last providing a
non-kluge method for controlling the order in which values are fed to an aggregate function. At the same time eliminate the old implementation restriction that DISTINCT was only supported for single-argument aggregates. Possibly release-notable behavioral change: formerly, agg(DISTINCT x) dropped null values of x unconditionally. Now, it does so only if the agg transition function is strict; otherwise nulls are treated as DISTINCT normally would, ie, you get one copy. Andrew Gierth, reviewed by Hitoshi Harada
This commit is contained in:
@ -17,7 +17,7 @@
|
||||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.396 2009/10/31 01:41:31 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.397 2009/12/15 17:57:47 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -828,13 +828,13 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
stmt->sortClause,
|
||||
&qry->targetList,
|
||||
true /* fix unknowns */,
|
||||
false /* not window function */);
|
||||
false /* allow SQL92 rules */);
|
||||
|
||||
qry->groupClause = transformGroupClause(pstate,
|
||||
stmt->groupClause,
|
||||
&qry->targetList,
|
||||
qry->sortClause,
|
||||
false /* not window function */);
|
||||
false /* allow SQL92 rules */);
|
||||
|
||||
if (stmt->distinctClause == NIL)
|
||||
{
|
||||
@ -846,7 +846,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
/* We had SELECT DISTINCT */
|
||||
qry->distinctClause = transformDistinctClause(pstate,
|
||||
&qry->targetList,
|
||||
qry->sortClause);
|
||||
qry->sortClause,
|
||||
false);
|
||||
qry->hasDistinctOn = false;
|
||||
}
|
||||
else
|
||||
@ -1044,7 +1045,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
|
||||
stmt->sortClause,
|
||||
&qry->targetList,
|
||||
true /* fix unknowns */,
|
||||
false /* not window function */);
|
||||
false /* allow SQL92 rules */);
|
||||
|
||||
qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset,
|
||||
"OFFSET");
|
||||
@ -1298,7 +1299,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
sortClause,
|
||||
&qry->targetList,
|
||||
false /* no unknowns expected */,
|
||||
false /* not window function */);
|
||||
false /* allow SQL92 rules */);
|
||||
|
||||
pstate->p_rtable = list_truncate(pstate->p_rtable, sv_rtable_length);
|
||||
pstate->p_relnamespace = sv_relnamespace;
|
||||
|
@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.696 2009/12/11 03:34:55 itagaki Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.697 2009/12/15 17:57:47 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -8651,6 +8651,7 @@ a_expr: c_expr { $$ = $1; }
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("timezone");
|
||||
n->args = list_make2($5, $1);
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -8711,6 +8712,7 @@ a_expr: c_expr { $$ = $1; }
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("like_escape");
|
||||
n->args = list_make2($3, $5);
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -8725,6 +8727,7 @@ a_expr: c_expr { $$ = $1; }
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("like_escape");
|
||||
n->args = list_make2($4, $6);
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -8739,6 +8742,7 @@ a_expr: c_expr { $$ = $1; }
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("like_escape");
|
||||
n->args = list_make2($3, $5);
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -8753,6 +8757,7 @@ a_expr: c_expr { $$ = $1; }
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("like_escape");
|
||||
n->args = list_make2($4, $6);
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -8766,6 +8771,7 @@ a_expr: c_expr { $$ = $1; }
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("similar_escape");
|
||||
n->args = list_make2($4, makeNullAConst(-1));
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -8778,6 +8784,7 @@ a_expr: c_expr { $$ = $1; }
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("similar_escape");
|
||||
n->args = list_make2($4, $6);
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -8790,6 +8797,7 @@ a_expr: c_expr { $$ = $1; }
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("similar_escape");
|
||||
n->args = list_make2($5, makeNullAConst(-1));
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -8802,6 +8810,7 @@ a_expr: c_expr { $$ = $1; }
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("similar_escape");
|
||||
n->args = list_make2($5, $7);
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9220,6 +9229,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = $1;
|
||||
n->args = NIL;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9232,6 +9242,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = $1;
|
||||
n->args = $3;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9244,6 +9255,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = $1;
|
||||
n->args = list_make1($4);
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = TRUE;
|
||||
@ -9256,6 +9268,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = $1;
|
||||
n->args = lappend($3, $6);
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = TRUE;
|
||||
@ -9263,11 +9276,25 @@ func_expr: func_name '(' ')' over_clause
|
||||
n->location = @1;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| func_name '(' ALL func_arg_list ')' over_clause
|
||||
| func_name '(' func_arg_list sort_clause ')' over_clause
|
||||
{
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = $1;
|
||||
n->args = $3;
|
||||
n->agg_order = $4;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
n->over = $6;
|
||||
n->location = @1;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| func_name '(' ALL func_arg_list opt_sort_clause ')' over_clause
|
||||
{
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = $1;
|
||||
n->args = $4;
|
||||
n->agg_order = $5;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
/* Ideally we'd mark the FuncCall node to indicate
|
||||
@ -9275,19 +9302,20 @@ func_expr: func_name '(' ')' over_clause
|
||||
* for that in FuncCall at the moment.
|
||||
*/
|
||||
n->func_variadic = FALSE;
|
||||
n->over = $6;
|
||||
n->over = $7;
|
||||
n->location = @1;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| func_name '(' DISTINCT func_arg_list ')' over_clause
|
||||
| func_name '(' DISTINCT func_arg_list opt_sort_clause ')' over_clause
|
||||
{
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = $1;
|
||||
n->args = $4;
|
||||
n->agg_order = $5;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = TRUE;
|
||||
n->func_variadic = FALSE;
|
||||
n->over = $6;
|
||||
n->over = $7;
|
||||
n->location = @1;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
@ -9306,6 +9334,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = $1;
|
||||
n->args = NIL;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = TRUE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9366,6 +9395,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("now");
|
||||
n->args = NIL;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9437,6 +9467,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("current_user");
|
||||
n->args = NIL;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9449,6 +9480,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("current_user");
|
||||
n->args = NIL;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9461,6 +9493,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("session_user");
|
||||
n->args = NIL;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9473,6 +9506,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("current_user");
|
||||
n->args = NIL;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9485,6 +9519,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("current_database");
|
||||
n->args = NIL;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9497,6 +9532,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("current_schema");
|
||||
n->args = NIL;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9511,6 +9547,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("date_part");
|
||||
n->args = $3;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9528,6 +9565,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("overlay");
|
||||
n->args = $3;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9541,6 +9579,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("position");
|
||||
n->args = $3;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9556,6 +9595,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("substring");
|
||||
n->args = $3;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9577,6 +9617,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
*/
|
||||
n->funcname = SystemFuncName(((Value *)llast($5->names))->val.str);
|
||||
n->args = list_make1($3);
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9592,6 +9633,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("btrim");
|
||||
n->args = $4;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9604,6 +9646,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("ltrim");
|
||||
n->args = $4;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9616,6 +9659,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("rtrim");
|
||||
n->args = $4;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -9628,6 +9672,7 @@ func_expr: func_name '(' ')' over_clause
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("btrim");
|
||||
n->args = $3;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
@ -11252,6 +11297,7 @@ makeOverlaps(List *largs, List *rargs, int location, core_yyscan_t yyscanner)
|
||||
errmsg("wrong number of parameters on right side of OVERLAPS expression"),
|
||||
parser_errposition(location)));
|
||||
n->args = list_concat(largs, rargs);
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.88 2009/06/11 14:49:00 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.89 2009/12/15 17:57:47 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -19,8 +19,10 @@
|
||||
#include "optimizer/tlist.h"
|
||||
#include "optimizer/var.h"
|
||||
#include "parser/parse_agg.h"
|
||||
#include "parser/parse_clause.h"
|
||||
#include "parser/parsetree.h"
|
||||
#include "rewrite/rewriteManip.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/lsyscache.h"
|
||||
|
||||
|
||||
@ -43,15 +45,97 @@ static bool check_ungrouped_columns_walker(Node *node,
|
||||
* Finish initial transformation of an aggregate call
|
||||
*
|
||||
* parse_func.c has recognized the function as an aggregate, and has set
|
||||
* up all the fields of the Aggref except agglevelsup. Here we must
|
||||
* determine which query level the aggregate actually belongs to, set
|
||||
* agglevelsup accordingly, and mark p_hasAggs true in the corresponding
|
||||
* up all the fields of the Aggref except aggdistinct and agglevelsup.
|
||||
* However, the args list is just bare expressions, and the aggorder list
|
||||
* hasn't been transformed at all.
|
||||
*
|
||||
* Here we convert the args list into a targetlist by inserting TargetEntry
|
||||
* nodes, and then transform the aggorder and agg_distinct specifications to
|
||||
* produce lists of SortGroupClause nodes. (That might also result in adding
|
||||
* resjunk expressions to the targetlist.)
|
||||
*
|
||||
* We must also determine which query level the aggregate actually belongs to,
|
||||
* set agglevelsup accordingly, and mark p_hasAggs true in the corresponding
|
||||
* pstate level.
|
||||
*/
|
||||
void
|
||||
transformAggregateCall(ParseState *pstate, Aggref *agg)
|
||||
transformAggregateCall(ParseState *pstate, Aggref *agg, bool agg_distinct)
|
||||
{
|
||||
List *tlist;
|
||||
List *torder;
|
||||
List *tdistinct = NIL;
|
||||
AttrNumber attno;
|
||||
int save_next_resno;
|
||||
int min_varlevel;
|
||||
ListCell *lc;
|
||||
|
||||
/*
|
||||
* Transform the plain list of Exprs into a targetlist. We don't bother
|
||||
* to assign column names to the entries.
|
||||
*/
|
||||
tlist = NIL;
|
||||
attno = 1;
|
||||
foreach(lc, agg->args)
|
||||
{
|
||||
Expr *arg = (Expr *) lfirst(lc);
|
||||
TargetEntry *tle = makeTargetEntry(arg, attno++, NULL, false);
|
||||
|
||||
tlist = lappend(tlist, tle);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have an ORDER BY, transform it. This will add columns to the
|
||||
* tlist if they appear in ORDER BY but weren't already in the arg list.
|
||||
* They will be marked resjunk = true so we can tell them apart from
|
||||
* regular aggregate arguments later.
|
||||
*
|
||||
* We need to mess with p_next_resno since it will be used to number any
|
||||
* new targetlist entries.
|
||||
*/
|
||||
save_next_resno = pstate->p_next_resno;
|
||||
pstate->p_next_resno = attno;
|
||||
|
||||
torder = transformSortClause(pstate,
|
||||
agg->aggorder,
|
||||
&tlist,
|
||||
true /* fix unknowns */,
|
||||
true /* force SQL99 rules */);
|
||||
|
||||
/*
|
||||
* If we have DISTINCT, transform that to produce a distinctList.
|
||||
*/
|
||||
if (agg_distinct)
|
||||
{
|
||||
tdistinct = transformDistinctClause(pstate, &tlist, torder, true);
|
||||
|
||||
/*
|
||||
* Remove this check if executor support for hashed distinct for
|
||||
* aggregates is ever added.
|
||||
*/
|
||||
foreach(lc, tdistinct)
|
||||
{
|
||||
SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
|
||||
|
||||
if (!OidIsValid(sortcl->sortop))
|
||||
{
|
||||
Node *expr = get_sortgroupclause_expr(sortcl, tlist);
|
||||
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
||||
errmsg("could not identify an ordering operator for type %s",
|
||||
format_type_be(exprType(expr))),
|
||||
errdetail("Aggregates with DISTINCT must be able to sort their inputs."),
|
||||
parser_errposition(pstate, exprLocation(expr))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the Aggref with the transformation results */
|
||||
agg->args = tlist;
|
||||
agg->aggorder = torder;
|
||||
agg->aggdistinct = tdistinct;
|
||||
|
||||
pstate->p_next_resno = save_next_resno;
|
||||
|
||||
/*
|
||||
* The aggregate's level is the same as the level of the lowest-level
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.193 2009/10/27 17:11:18 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.194 2009/12/15 17:57:47 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1440,7 +1440,7 @@ findTargetlistEntrySQL99(ParseState *pstate, Node *node, List **tlist)
|
||||
List *
|
||||
transformGroupClause(ParseState *pstate, List *grouplist,
|
||||
List **targetlist, List *sortClause,
|
||||
bool isWindowFunc)
|
||||
bool useSQL99)
|
||||
{
|
||||
List *result = NIL;
|
||||
ListCell *gl;
|
||||
@ -1451,7 +1451,7 @@ transformGroupClause(ParseState *pstate, List *grouplist,
|
||||
TargetEntry *tle;
|
||||
bool found = false;
|
||||
|
||||
if (isWindowFunc)
|
||||
if (useSQL99)
|
||||
tle = findTargetlistEntrySQL99(pstate, gexpr, targetlist);
|
||||
else
|
||||
tle = findTargetlistEntrySQL92(pstate, gexpr, targetlist,
|
||||
@ -1510,15 +1510,15 @@ transformGroupClause(ParseState *pstate, List *grouplist,
|
||||
* ORDER BY items will be added to the targetlist (as resjunk columns)
|
||||
* if not already present, so the targetlist must be passed by reference.
|
||||
*
|
||||
* This is also used for window ORDER BY clauses (which act almost the
|
||||
* same, but are always interpreted per SQL99 rules).
|
||||
* This is also used for window and aggregate ORDER BY clauses (which act
|
||||
* almost the same, but are always interpreted per SQL99 rules).
|
||||
*/
|
||||
List *
|
||||
transformSortClause(ParseState *pstate,
|
||||
List *orderlist,
|
||||
List **targetlist,
|
||||
bool resolveUnknown,
|
||||
bool isWindowFunc)
|
||||
bool useSQL99)
|
||||
{
|
||||
List *sortlist = NIL;
|
||||
ListCell *olitem;
|
||||
@ -1528,7 +1528,7 @@ transformSortClause(ParseState *pstate,
|
||||
SortBy *sortby = (SortBy *) lfirst(olitem);
|
||||
TargetEntry *tle;
|
||||
|
||||
if (isWindowFunc)
|
||||
if (useSQL99)
|
||||
tle = findTargetlistEntrySQL99(pstate, sortby->node, targetlist);
|
||||
else
|
||||
tle = findTargetlistEntrySQL92(pstate, sortby->node, targetlist,
|
||||
@ -1598,12 +1598,12 @@ transformWindowDefinitions(ParseState *pstate,
|
||||
windef->orderClause,
|
||||
targetlist,
|
||||
true /* fix unknowns */,
|
||||
true /* window function */);
|
||||
true /* force SQL99 rules */);
|
||||
partitionClause = transformGroupClause(pstate,
|
||||
windef->partitionClause,
|
||||
targetlist,
|
||||
orderClause,
|
||||
true /* window function */);
|
||||
true /* force SQL99 rules */);
|
||||
|
||||
/*
|
||||
* And prepare the new WindowClause.
|
||||
@ -1684,10 +1684,14 @@ transformWindowDefinitions(ParseState *pstate,
|
||||
* and allows the user to choose the equality semantics used by DISTINCT,
|
||||
* should she be working with a datatype that has more than one equality
|
||||
* operator.
|
||||
*
|
||||
* is_agg is true if we are transforming an aggregate(DISTINCT ...)
|
||||
* function call. This does not affect any behavior, only the phrasing
|
||||
* of error messages.
|
||||
*/
|
||||
List *
|
||||
transformDistinctClause(ParseState *pstate,
|
||||
List **targetlist, List *sortClause)
|
||||
List **targetlist, List *sortClause, bool is_agg)
|
||||
{
|
||||
List *result = NIL;
|
||||
ListCell *slitem;
|
||||
@ -1716,6 +1720,8 @@ transformDistinctClause(ParseState *pstate,
|
||||
if (tle->resjunk)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
||||
is_agg ?
|
||||
errmsg("in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list") :
|
||||
errmsg("for SELECT DISTINCT, ORDER BY expressions must appear in select list"),
|
||||
parser_errposition(pstate,
|
||||
exprLocation((Node *) tle->expr))));
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.250 2009/11/13 19:48:20 heikki Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.251 2009/12/15 17:57:47 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -431,7 +431,7 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection)
|
||||
newresult = ParseFuncOrColumn(pstate,
|
||||
list_make1(n),
|
||||
list_make1(result),
|
||||
false, false, false,
|
||||
NIL, false, false, false,
|
||||
NULL, true, location);
|
||||
if (newresult == NULL)
|
||||
unknown_attribute(pstate, result, strVal(n), location);
|
||||
@ -598,7 +598,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
|
||||
node = ParseFuncOrColumn(pstate,
|
||||
list_make1(makeString(colname)),
|
||||
list_make1(node),
|
||||
false, false, false,
|
||||
NIL, false, false, false,
|
||||
NULL, true, cref->location);
|
||||
}
|
||||
break;
|
||||
@ -643,7 +643,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
|
||||
node = ParseFuncOrColumn(pstate,
|
||||
list_make1(makeString(colname)),
|
||||
list_make1(node),
|
||||
false, false, false,
|
||||
NIL, false, false, false,
|
||||
NULL, true, cref->location);
|
||||
}
|
||||
break;
|
||||
@ -701,7 +701,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
|
||||
node = ParseFuncOrColumn(pstate,
|
||||
list_make1(makeString(colname)),
|
||||
list_make1(node),
|
||||
false, false, false,
|
||||
NIL, false, false, false,
|
||||
NULL, true, cref->location);
|
||||
}
|
||||
break;
|
||||
@ -1221,6 +1221,7 @@ transformFuncCall(ParseState *pstate, FuncCall *fn)
|
||||
return ParseFuncOrColumn(pstate,
|
||||
fn->funcname,
|
||||
targs,
|
||||
fn->agg_order,
|
||||
fn->agg_star,
|
||||
fn->agg_distinct,
|
||||
fn->func_variadic,
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.218 2009/10/31 01:41:31 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.219 2009/12/15 17:57:47 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -55,10 +55,12 @@ static Node *ParseComplexProjection(ParseState *pstate, char *funcname,
|
||||
* reporting a no-such-function error.
|
||||
*
|
||||
* The argument expressions (in fargs) must have been transformed already.
|
||||
* But the agg_order expressions, if any, have not been.
|
||||
*/
|
||||
Node *
|
||||
ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
||||
bool agg_star, bool agg_distinct, bool func_variadic,
|
||||
List *agg_order, bool agg_star, bool agg_distinct,
|
||||
bool func_variadic,
|
||||
WindowDef *over, bool is_column, int location)
|
||||
{
|
||||
Oid rettype;
|
||||
@ -170,8 +172,9 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
||||
* the "function call" could be a projection. We also check that there
|
||||
* wasn't any aggregate or variadic decoration, nor an argument name.
|
||||
*/
|
||||
if (nargs == 1 && !agg_star && !agg_distinct && over == NULL &&
|
||||
!func_variadic && argnames == NIL && list_length(funcname) == 1)
|
||||
if (nargs == 1 && agg_order == NIL && !agg_star && !agg_distinct &&
|
||||
over == NULL && !func_variadic && argnames == NIL &&
|
||||
list_length(funcname) == 1)
|
||||
{
|
||||
Oid argtype = actual_arg_types[0];
|
||||
|
||||
@ -240,6 +243,12 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
||||
errmsg("DISTINCT specified, but %s is not an aggregate function",
|
||||
NameListToString(funcname)),
|
||||
parser_errposition(pstate, location)));
|
||||
if (agg_order != NIL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("ORDER BY specified, but %s is not an aggregate function",
|
||||
NameListToString(funcname)),
|
||||
parser_errposition(pstate, location)));
|
||||
if (over)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
@ -372,9 +381,12 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
||||
|
||||
aggref->aggfnoid = funcid;
|
||||
aggref->aggtype = rettype;
|
||||
/* args and aggorder will be modified by transformAggregateCall */
|
||||
aggref->args = fargs;
|
||||
aggref->aggorder = agg_order;
|
||||
/* aggdistinct will be set by transformAggregateCall */
|
||||
aggref->aggstar = agg_star;
|
||||
aggref->aggdistinct = agg_distinct;
|
||||
/* agglevelsup will be set by transformAggregateCall */
|
||||
aggref->location = location;
|
||||
|
||||
/*
|
||||
@ -407,7 +419,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
||||
parser_errposition(pstate, location)));
|
||||
|
||||
/* parse_agg.c does additional aggregate-specific processing */
|
||||
transformAggregateCall(pstate, aggref);
|
||||
transformAggregateCall(pstate, aggref, agg_distinct);
|
||||
|
||||
retval = (Node *) aggref;
|
||||
}
|
||||
@ -453,6 +465,15 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
||||
NameListToString(funcname)),
|
||||
parser_errposition(pstate, location)));
|
||||
|
||||
/*
|
||||
* ordered aggs not allowed in windows yet
|
||||
*/
|
||||
if (agg_order != NIL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("aggregate ORDER BY is not implemented for window functions"),
|
||||
parser_errposition(pstate, location)));
|
||||
|
||||
if (retset)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
|
@ -19,7 +19,7 @@
|
||||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.31 2009/12/07 05:22:22 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.32 2009/12/15 17:57:47 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -388,6 +388,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
|
||||
funccallnode = makeNode(FuncCall);
|
||||
funccallnode->funcname = SystemFuncName("nextval");
|
||||
funccallnode->args = list_make1(castnode);
|
||||
funccallnode->agg_order = NIL;
|
||||
funccallnode->agg_star = false;
|
||||
funccallnode->agg_distinct = false;
|
||||
funccallnode->func_variadic = false;
|
||||
|
Reference in New Issue
Block a user