Commit bb16dc49 authored by Tom Lane's avatar Tom Lane

Modify the definition of window-function PARTITION BY and ORDER BY clauses

so that their elements are always taken as simple expressions over the
query's input columns.  It originally seemed like a good idea to make them
act exactly like GROUP BY and ORDER BY, right down to the SQL92-era behavior
of accepting output column names or numbers.  However, that was not such a
great idea, for two reasons:

1. It permits circular references, as exhibited in bug #5018: the output
column could be the one containing the window function itself.  (We actually
had a regression test case illustrating this, but nobody thought twice about
how confusing that would be.)

2. It doesn't seem like a good idea for, eg, "lead(foo) OVER (ORDER BY foo)"
to potentially use two completely different meanings for "foo".

Accordingly, narrow down the behavior of window clauses to use only the
SQL99-compliant interpretation that the expressions are simple expressions.
parent f065b17d
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.123 2009/08/18 23:40:20 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.124 2009/08/27 20:08:02 tgl Exp $
PostgreSQL documentation
-->
......@@ -595,17 +595,24 @@ WINDOW <replaceable class="parameter">window_name</replaceable> AS ( <replaceabl
<para>
The elements of the <literal>PARTITION BY</> list are interpreted in
the same fashion as elements of a
<xref linkend="sql-groupby" endterm="sql-groupby-title">, and
the elements of the <literal>ORDER BY</> list are interpreted in the
same fashion as elements of an
<xref linkend="sql-orderby" endterm="sql-orderby-title">.
The only difference is that these expressions can contain aggregate
much the same fashion as elements of a
<xref linkend="sql-groupby" endterm="sql-groupby-title">, except that
they are always simple expressions and never the name or number of an
output column.
Another difference is that these expressions can contain aggregate
function calls, which are not allowed in a regular <literal>GROUP BY</>
clause. They are allowed here because windowing occurs after grouping
and aggregation.
</para>
<para>
Similarly, the elements of the <literal>ORDER BY</> list are interpreted
in much the same fashion as elements of an
<xref linkend="sql-orderby" endterm="sql-orderby-title">, except that
the expressions are always taken as simple expressions and never the name
or number of an output column.
</para>
<para>
The optional <replaceable class="parameter">frame_clause</> defines
the <firstterm>window frame</> for window functions that depend on the
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/syntax.sgml,v 1.133 2009/06/17 21:58:49 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/syntax.sgml,v 1.134 2009/08/27 20:08:02 tgl Exp $ -->
<chapter id="sql-syntax">
<title>SQL Syntax</title>
......@@ -1619,7 +1619,9 @@ ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
expression that does not itself contain window function calls.
The <literal>PARTITION BY</> and <literal>ORDER BY</> lists have
essentially the same syntax and semantics as <literal>GROUP BY</>
and <literal>ORDER BY</> clauses of the whole query.
and <literal>ORDER BY</> clauses of the whole query, except that their
expressions are always just expressions and cannot be output-column
names or numbers.
<replaceable>window_name</replaceable> is a reference to a named window
specification defined in the query's <literal>WINDOW</literal> clause.
Named window specifications are usually referenced with just
......
......@@ -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.389 2009/06/11 14:48:59 momjian Exp $
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.390 2009/08/27 20:08:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -825,13 +825,14 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
qry->sortClause = transformSortClause(pstate,
stmt->sortClause,
&qry->targetList,
true /* fix unknowns */ );
true /* fix unknowns */,
false /* not window function */);
qry->groupClause = transformGroupClause(pstate,
stmt->groupClause,
&qry->targetList,
qry->sortClause,
false);
false /* not window function */);
if (stmt->distinctClause == NIL)
{
......@@ -1039,7 +1040,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
qry->sortClause = transformSortClause(pstate,
stmt->sortClause,
&qry->targetList,
true /* fix unknowns */ );
true /* fix unknowns */,
false /* not window function */);
qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset,
"OFFSET");
......@@ -1291,7 +1293,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
qry->sortClause = transformSortClause(pstate,
sortClause,
&qry->targetList,
false /* no unknowns expected */ );
false /* no unknowns expected */,
false /* not window function */);
pstate->p_rtable = list_truncate(pstate->p_rtable, sv_rtable_length);
pstate->p_relnamespace = sv_relnamespace;
......
This diff is collapsed.
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/parser/parse_clause.h,v 1.55 2009/06/11 14:49:11 momjian Exp $
* $PostgreSQL: pgsql/src/include/parser/parse_clause.h,v 1.56 2009/08/27 20:08:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -28,9 +28,9 @@ extern Node *transformLimitClause(ParseState *pstate, Node *clause,
const char *constructName);
extern List *transformGroupClause(ParseState *pstate, List *grouplist,
List **targetlist, List *sortClause,
bool isPartition);
bool isWindowFunc);
extern List *transformSortClause(ParseState *pstate, List *orderlist,
List **targetlist, bool resolveUnknown);
List **targetlist, bool resolveUnknown, bool isWindowFunc);
extern List *transformWindowDefinitions(ParseState *pstate,
List *windowdefs,
......
......@@ -741,11 +741,11 @@ SELECT rank() OVER (ORDER BY length('abc'));
1
(1 row)
-- but this draws an error: "ORDER BY 1" means order by first SELECT column
SELECT rank() OVER (ORDER BY 1);
-- can't order by another window function
SELECT rank() OVER (ORDER BY rank() OVER (ORDER BY random()));
ERROR: window functions not allowed in window definition
LINE 1: SELECT rank() OVER (ORDER BY 1);
^
LINE 1: SELECT rank() OVER (ORDER BY rank() OVER (ORDER BY random())...
^
-- some other errors
SELECT * FROM empsalary WHERE row_number() OVER (ORDER BY salary) < 10;
ERROR: window functions not allowed in WHERE clause
......
......@@ -167,8 +167,8 @@ SELECT count(*) OVER (PARTITION BY four) FROM (SELECT * FROM tenk1 UNION ALL SEL
-- ordering by a non-integer constant is allowed
SELECT rank() OVER (ORDER BY length('abc'));
-- but this draws an error: "ORDER BY 1" means order by first SELECT column
SELECT rank() OVER (ORDER BY 1);
-- can't order by another window function
SELECT rank() OVER (ORDER BY rank() OVER (ORDER BY random()));
-- some other errors
SELECT * FROM empsalary WHERE row_number() OVER (ORDER BY salary) < 10;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment