1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-14 18:42:34 +03:00

Support window functions a la SQL:2008.

Hitoshi Harada, with some kibitzing from Heikki and Tom.
This commit is contained in:
Tom Lane
2008-12-28 18:54:01 +00:00
parent 38e9348282
commit 95b07bc7f5
92 changed files with 6720 additions and 321 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.209 2008/12/18 18:20:34 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.210 2008/12/28 18:53:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -63,7 +63,7 @@ static void unknown_attribute(ParseState *pstate, Node *relref, char *attname,
Node *
ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
bool agg_star, bool agg_distinct, bool func_variadic,
bool is_column, int location)
WindowDef *over, bool is_column, int location)
{
Oid rettype;
Oid funcid;
@ -131,8 +131,8 @@ 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.
*/
if (nargs == 1 && !agg_star && !agg_distinct && !func_variadic &&
list_length(funcname) == 1)
if (nargs == 1 && !agg_star && !agg_distinct && over == NULL &&
!func_variadic && list_length(funcname) == 1)
{
Oid argtype = actual_arg_types[0];
@ -196,8 +196,15 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
errmsg("DISTINCT specified, but %s is not an aggregate function",
NameListToString(funcname)),
parser_errposition(pstate, location)));
if (over)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("OVER specified, but %s is not a window function nor an aggregate function",
NameListToString(funcname)),
parser_errposition(pstate, location)));
}
else if (fdresult != FUNCDETAIL_AGGREGATE)
else if (!(fdresult == FUNCDETAIL_AGGREGATE ||
fdresult == FUNCDETAIL_WINDOWFUNC))
{
/*
* Oops. Time to die.
@ -317,7 +324,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
retval = (Node *) funcexpr;
}
else
else if (fdresult == FUNCDETAIL_AGGREGATE && !over)
{
/* aggregate function */
Aggref *aggref = makeNode(Aggref);
@ -340,16 +347,69 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
NameListToString(funcname)),
parser_errposition(pstate, location)));
/* parse_agg.c does additional aggregate-specific processing */
transformAggregateCall(pstate, aggref);
retval = (Node *) aggref;
if (retset)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("aggregates cannot return sets"),
parser_errposition(pstate, location)));
/* parse_agg.c does additional aggregate-specific processing */
transformAggregateCall(pstate, aggref);
retval = (Node *) aggref;
}
else
{
/* window function */
WindowFunc *wfunc = makeNode(WindowFunc);
/*
* True window functions must be called with a window definition.
*/
if (!over)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("window function call requires an OVER clause"),
parser_errposition(pstate, location)));
wfunc->winfnoid = funcid;
wfunc->wintype = rettype;
wfunc->args = fargs;
/* winref will be set by transformWindowFuncCall */
wfunc->winstar = agg_star;
wfunc->winagg = (fdresult == FUNCDETAIL_AGGREGATE);
wfunc->location = location;
/*
* agg_star is allowed for aggregate functions but distinct isn't
*/
if (agg_distinct)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("DISTINCT is not implemented for window functions"),
parser_errposition(pstate, location)));
/*
* Reject attempt to call a parameterless aggregate without (*)
* syntax. This is mere pedantry but some folks insisted ...
*/
if (wfunc->winagg && fargs == NIL && !agg_star)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("%s(*) must be used to call a parameterless aggregate function",
NameListToString(funcname)),
parser_errposition(pstate, location)));
if (retset)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("window functions cannot return sets"),
parser_errposition(pstate, location)));
/* parse_agg.c does additional window-func-specific processing */
transformWindowFuncCall(pstate, wfunc, over);
retval = (Node *) wfunc;
}
return retval;
@ -948,7 +1008,12 @@ func_get_detail(List *funcname,
else
*argdefaults = NIL;
}
result = pform->proisagg ? FUNCDETAIL_AGGREGATE : FUNCDETAIL_NORMAL;
if (pform->proisagg)
result = FUNCDETAIL_AGGREGATE;
else if (pform->proiswindow)
result = FUNCDETAIL_WINDOWFUNC;
else
result = FUNCDETAIL_NORMAL;
ReleaseSysCache(ftup);
return result;
}