Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b474871

Browse files
committed
Improve the error message given for modifying a window with frame clause.
For rather inscrutable reasons, SQL:2008 disallows copying-and-modifying a window definition that has any explicit framing clause. The error message we gave for this only made sense if the referencing window definition itself contains an explicit framing clause, which it might well not. Moreover, in the context of an OVER clause it's not exactly obvious that "OVER (windowname)" implies copy-and-modify while "OVER windowname" does not. This has led to multiple complaints, eg bug #5199 from Iliya Krapchatov. Change to a hopefully more intelligible error message, and in the case where we have just "OVER (windowname)", add a HINT suggesting that omitting the parentheses will fix it. Also improve the related documentation. Back-patch to all supported branches.
1 parent 5b6ee03 commit b474871

File tree

2 files changed

+36
-16
lines changed

2 files changed

+36
-16
lines changed

doc/src/sgml/syntax.sgml

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1709,10 +1709,10 @@ SELECT string_agg(a ORDER BY a, ',') FROM table; -- incorrect
17091709
The syntax of a window function call is one of the following:
17101710

17111711
<synopsis>
1712-
<replaceable>function_name</replaceable> (<optional><replaceable>expression</replaceable> <optional>, <replaceable>expression</replaceable> ... </optional></optional>) OVER ( <replaceable class="parameter">window_definition</replaceable> )
17131712
<replaceable>function_name</replaceable> (<optional><replaceable>expression</replaceable> <optional>, <replaceable>expression</replaceable> ... </optional></optional>) OVER <replaceable>window_name</replaceable>
1714-
<replaceable>function_name</replaceable> ( * ) OVER ( <replaceable class="parameter">window_definition</replaceable> )
1713+
<replaceable>function_name</replaceable> (<optional><replaceable>expression</replaceable> <optional>, <replaceable>expression</replaceable> ... </optional></optional>) OVER ( <replaceable class="parameter">window_definition</replaceable> )
17151714
<replaceable>function_name</replaceable> ( * ) OVER <replaceable>window_name</replaceable>
1715+
<replaceable>function_name</replaceable> ( * ) OVER ( <replaceable class="parameter">window_definition</replaceable> )
17161716
</synopsis>
17171717
where <replaceable class="parameter">window_definition</replaceable>
17181718
has the syntax
@@ -1747,15 +1747,14 @@ UNBOUNDED FOLLOWING
17471747
<para>
17481748
<replaceable>window_name</replaceable> is a reference to a named window
17491749
specification defined in the query's <literal>WINDOW</literal> clause.
1750-
Named window specifications are usually referenced with just
1751-
<literal>OVER</> <replaceable>window_name</replaceable>, but it is
1752-
also possible to write a window name inside the parentheses and then
1753-
optionally supply an ordering clause and/or frame clause (the referenced
1754-
window must lack these clauses, if they are supplied here).
1755-
This latter syntax follows the same rules as modifying an existing
1756-
window name within the <literal>WINDOW</literal> clause; see the
1757-
<xref linkend="sql-select"> reference
1758-
page for details.
1750+
Alternatively, a full <replaceable>window_definition</replaceable> can
1751+
be given within parentheses, using the same syntax as for defining a
1752+
named window in the <literal>WINDOW</literal> clause; see the
1753+
<xref linkend="sql-select"> reference page for details. It's worth
1754+
pointing out that <literal>OVER wname</> is not exactly equivalent to
1755+
<literal>OVER (wname)</>; the latter implies copying and modifying the
1756+
window definition, and will be rejected if the referenced window
1757+
specification includes a frame clause.
17591758
</para>
17601759

17611760
<para>

src/backend/parser/parse_clause.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,11 +1736,16 @@ transformWindowDefinitions(ParseState *pstate,
17361736
/*
17371737
* Per spec, a windowdef that references a previous one copies the
17381738
* previous partition clause (and mustn't specify its own). It can
1739-
* specify its own ordering clause. but only if the previous one had
1739+
* specify its own ordering clause, but only if the previous one had
17401740
* none. It always specifies its own frame clause, and the previous
1741-
* one must not have a frame clause. (Yeah, it's bizarre that each of
1741+
* one must not have a frame clause. Yeah, it's bizarre that each of
17421742
* these cases works differently, but SQL:2008 says so; see 7.11
1743-
* <window clause> syntax rule 10 and general rule 1.)
1743+
* <window clause> syntax rule 10 and general rule 1. The frame
1744+
* clause rule is especially bizarre because it makes "OVER foo"
1745+
* different from "OVER (foo)", and requires the latter to throw an
1746+
* error if foo has a nondefault frame clause. Well, ours not to
1747+
* reason why, but we do go out of our way to throw a useful error
1748+
* message for such cases.
17441749
*/
17451750
if (refwc)
17461751
{
@@ -1779,11 +1784,27 @@ transformWindowDefinitions(ParseState *pstate,
17791784
wc->copiedOrder = false;
17801785
}
17811786
if (refwc && refwc->frameOptions != FRAMEOPTION_DEFAULTS)
1787+
{
1788+
/*
1789+
* Use this message if this is a WINDOW clause, or if it's an OVER
1790+
* clause that includes ORDER BY or framing clauses. (We already
1791+
* rejected PARTITION BY above, so no need to check that.)
1792+
*/
1793+
if (windef->name ||
1794+
orderClause || windef->frameOptions != FRAMEOPTION_DEFAULTS)
1795+
ereport(ERROR,
1796+
(errcode(ERRCODE_WINDOWING_ERROR),
1797+
errmsg("cannot copy window \"%s\" because it has a frame clause",
1798+
windef->refname),
1799+
parser_errposition(pstate, windef->location)));
1800+
/* Else this clause is just OVER (foo), so say this: */
17821801
ereport(ERROR,
17831802
(errcode(ERRCODE_WINDOWING_ERROR),
1784-
errmsg("cannot override frame clause of window \"%s\"",
1785-
windef->refname),
1803+
errmsg("cannot copy window \"%s\" because it has a frame clause",
1804+
windef->refname),
1805+
errhint("Omit the parentheses in this OVER clause."),
17861806
parser_errposition(pstate, windef->location)));
1807+
}
17871808
wc->frameOptions = windef->frameOptions;
17881809
/* Process frame offset expressions */
17891810
wc->startOffset = transformFrameOffset(pstate, wc->frameOptions,

0 commit comments

Comments
 (0)