aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/gram.y113
-rw-r--r--src/backend/parser/keywords.c6
-rw-r--r--src/backend/parser/parse_agg.c23
-rw-r--r--src/backend/parser/parse_clause.c5
4 files changed, 120 insertions, 27 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 59b7ada7b43..34dc40a1056 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.648 2008/12/28 18:53:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.649 2008/12/31 00:08:36 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -406,6 +406,7 @@ static TypeName *TableFuncTypeName(List *columns);
%type <list> window_clause window_definition_list opt_partition_clause
%type <windef> window_definition over_clause window_specification
%type <str> opt_existing_window_name
+%type <ival> opt_frame_clause frame_extent frame_bound
/*
@@ -439,7 +440,7 @@ static TypeName *TableFuncTypeName(List *columns);
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EXCEPT
EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
- FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
+ FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOLLOWING FOR FORCE FOREIGN FORWARD
FREEZE FROM FULL FUNCTION
GLOBAL GRANT GRANTED GREATEST GROUP_P
@@ -469,14 +470,14 @@ static TypeName *TableFuncTypeName(List *columns);
ORDER OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER
PARSER PARTIAL PARTITION PASSWORD PLACING PLANS POSITION
- PRECISION PRESERVE PREPARE PREPARED PRIMARY
+ PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
PRIOR PRIVILEGES PROCEDURAL PROCEDURE
QUOTE
- READ REAL REASSIGN RECHECK RECURSIVE REFERENCES REINDEX RELATIVE_P RELEASE
- RENAME REPEATABLE REPLACE REPLICA RESET RESTART RESTRICT RETURNING RETURNS
- REVOKE RIGHT ROLE ROLLBACK ROW ROWS RULE
+ RANGE READ REAL REASSIGN RECHECK RECURSIVE REFERENCES REINDEX
+ RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART
+ RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROW ROWS RULE
SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE
SERIALIZABLE SERVER SESSION SESSION_USER SET SETOF SHARE
@@ -488,7 +489,7 @@ static TypeName *TableFuncTypeName(List *columns);
TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
TRUNCATE TRUSTED TYPE_P
- UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
+ UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
UPDATE USER USING
VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING
@@ -533,10 +534,12 @@ static TypeName *TableFuncTypeName(List *columns);
* between POSTFIXOP and Op. We can safely assign the same priority to
* various unreserved keywords as needed to resolve ambiguities (this can't
* have any bad effects since obviously the keywords will still behave the
- * same as if they weren't keywords). We need to do this for PARTITION
- * to support opt_existing_window_name.
+ * same as if they weren't keywords). We need to do this for PARTITION,
+ * RANGE, ROWS to support opt_existing_window_name; and for RANGE, ROWS
+ * so that they can follow a_expr without creating
+ * postfix-operator problems.
*/
-%nonassoc IDENT PARTITION
+%nonassoc IDENT PARTITION RANGE ROWS
%left Op OPERATOR /* multi-character ops and user-defined operators */
%nonassoc NOTNULL
%nonassoc ISNULL
@@ -9235,10 +9238,11 @@ over_clause: OVER window_specification
| OVER ColId
{
WindowDef *n = makeNode(WindowDef);
- n->name = NULL;
- n->refname = $2;
+ n->name = $2;
+ n->refname = NULL;
n->partitionClause = NIL;
n->orderClause = NIL;
+ n->frameOptions = FRAMEOPTION_DEFAULTS;
n->location = @2;
$$ = n;
}
@@ -9247,13 +9251,14 @@ over_clause: OVER window_specification
;
window_specification: '(' opt_existing_window_name opt_partition_clause
- opt_sort_clause ')'
+ opt_sort_clause opt_frame_clause ')'
{
WindowDef *n = makeNode(WindowDef);
n->name = NULL;
n->refname = $2;
n->partitionClause = $3;
n->orderClause = $4;
+ n->frameOptions = $5;
n->location = @1;
$$ = n;
}
@@ -9268,7 +9273,6 @@ window_specification: '(' opt_existing_window_name opt_partition_clause
* that the shift/reduce conflict is resolved in favor of reducing the rule.
* These keywords are thus precluded from being an existing_window_name but
* are not reserved for any other purpose.
- * (RANGE/ROWS are not an issue as of 8.4 for lack of frame_clause support.)
*/
opt_existing_window_name: ColId { $$ = $1; }
| /*EMPTY*/ %prec Op { $$ = NULL; }
@@ -9279,6 +9283,83 @@ opt_partition_clause: PARTITION BY expr_list { $$ = $3; }
;
/*
+ * This is only a subset of the full SQL:2008 frame_clause grammar.
+ * We don't support <expression> PRECEDING, <expression> FOLLOWING,
+ * nor <window frame exclusion> yet.
+ */
+opt_frame_clause:
+ RANGE frame_extent
+ {
+ $$ = FRAMEOPTION_NONDEFAULT | FRAMEOPTION_RANGE | $2;
+ }
+ | ROWS frame_extent
+ {
+ $$ = FRAMEOPTION_NONDEFAULT | FRAMEOPTION_ROWS | $2;
+ }
+ | /*EMPTY*/
+ { $$ = FRAMEOPTION_DEFAULTS; }
+ ;
+
+frame_extent: frame_bound
+ {
+ /* reject invalid cases */
+ if ($1 & FRAMEOPTION_START_UNBOUNDED_FOLLOWING)
+ ereport(ERROR,
+ (errcode(ERRCODE_WINDOWING_ERROR),
+ errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
+ scanner_errposition(@1)));
+ if ($1 & FRAMEOPTION_START_CURRENT_ROW)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("frame start at CURRENT ROW is not implemented"),
+ scanner_errposition(@1)));
+ $$ = $1 | FRAMEOPTION_END_CURRENT_ROW;
+ }
+ | BETWEEN frame_bound AND frame_bound
+ {
+ /* reject invalid cases */
+ if ($2 & FRAMEOPTION_START_UNBOUNDED_FOLLOWING)
+ ereport(ERROR,
+ (errcode(ERRCODE_WINDOWING_ERROR),
+ errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
+ scanner_errposition(@2)));
+ if ($2 & FRAMEOPTION_START_CURRENT_ROW)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("frame start at CURRENT ROW is not implemented"),
+ scanner_errposition(@2)));
+ if ($4 & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
+ ereport(ERROR,
+ (errcode(ERRCODE_WINDOWING_ERROR),
+ errmsg("frame end cannot be UNBOUNDED PRECEDING"),
+ scanner_errposition(@4)));
+ /* shift converts START_ options to END_ options */
+ $$ = FRAMEOPTION_BETWEEN | $2 | ($4 << 1);
+ }
+ ;
+
+/*
+ * This is used for both frame start and frame end, with output set up on
+ * the assumption it's frame start; the frame_extent productions must reject
+ * invalid cases.
+ */
+frame_bound:
+ UNBOUNDED PRECEDING
+ {
+ $$ = FRAMEOPTION_START_UNBOUNDED_PRECEDING;
+ }
+ | UNBOUNDED FOLLOWING
+ {
+ $$ = FRAMEOPTION_START_UNBOUNDED_FOLLOWING;
+ }
+ | CURRENT_P ROW
+ {
+ $$ = FRAMEOPTION_START_CURRENT_ROW;
+ }
+ ;
+
+
+/*
* Supporting nonterminals for expressions.
*/
@@ -10012,6 +10093,7 @@ unreserved_keyword:
| EXTERNAL
| FAMILY
| FIRST_P
+ | FOLLOWING
| FORCE
| FORWARD
| FUNCTION
@@ -10086,6 +10168,7 @@ unreserved_keyword:
| PARTITION
| PASSWORD
| PLANS
+ | PRECEDING
| PREPARE
| PREPARED
| PRESERVE
@@ -10094,6 +10177,7 @@ unreserved_keyword:
| PROCEDURAL
| PROCEDURE
| QUOTE
+ | RANGE
| READ
| REASSIGN
| RECHECK
@@ -10151,6 +10235,7 @@ unreserved_keyword:
| TRUNCATE
| TRUSTED
| TYPE_P
+ | UNBOUNDED
| UNCOMMITTED
| UNENCRYPTED
| UNKNOWN
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index c3ad852258b..730974b94d8 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.207 2008/12/28 18:53:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.208 2008/12/31 00:08:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -172,6 +172,7 @@ const ScanKeyword ScanKeywords[] = {
{"fetch", FETCH, RESERVED_KEYWORD},
{"first", FIRST_P, UNRESERVED_KEYWORD},
{"float", FLOAT_P, COL_NAME_KEYWORD},
+ {"following", FOLLOWING, UNRESERVED_KEYWORD},
{"for", FOR, RESERVED_KEYWORD},
{"force", FORCE, UNRESERVED_KEYWORD},
{"foreign", FOREIGN, RESERVED_KEYWORD},
@@ -299,6 +300,7 @@ const ScanKeyword ScanKeywords[] = {
{"placing", PLACING, RESERVED_KEYWORD},
{"plans", PLANS, UNRESERVED_KEYWORD},
{"position", POSITION, COL_NAME_KEYWORD},
+ {"preceding", PRECEDING, UNRESERVED_KEYWORD},
{"precision", PRECISION, COL_NAME_KEYWORD},
{"prepare", PREPARE, UNRESERVED_KEYWORD},
{"prepared", PREPARED, UNRESERVED_KEYWORD},
@@ -309,6 +311,7 @@ const ScanKeyword ScanKeywords[] = {
{"procedural", PROCEDURAL, UNRESERVED_KEYWORD},
{"procedure", PROCEDURE, UNRESERVED_KEYWORD},
{"quote", QUOTE, UNRESERVED_KEYWORD},
+ {"range", RANGE, UNRESERVED_KEYWORD},
{"read", READ, UNRESERVED_KEYWORD},
{"real", REAL, COL_NAME_KEYWORD},
{"reassign", REASSIGN, UNRESERVED_KEYWORD},
@@ -388,6 +391,7 @@ const ScanKeyword ScanKeywords[] = {
{"truncate", TRUNCATE, UNRESERVED_KEYWORD},
{"trusted", TRUSTED, UNRESERVED_KEYWORD},
{"type", TYPE_P, UNRESERVED_KEYWORD},
+ {"unbounded", UNBOUNDED, UNRESERVED_KEYWORD},
{"uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD},
{"unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD},
{"union", UNION, RESERVED_KEYWORD},
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 6dba470e39f..23913c62914 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.85 2008/12/28 18:53:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.86 2008/12/31 00:08:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -123,25 +123,27 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc,
locate_windowfunc((Node *) wfunc->args))));
/*
- * If the OVER clause just specifies a reference name, find that
+ * 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 list if no luck.
*/
- Assert(!windef->name);
- if (windef->refname &&
- windef->partitionClause == NIL &&
- windef->orderClause == NIL)
+ if (windef->name)
{
Index winref = 0;
ListCell *lc;
+ Assert(windef->refname == NULL &&
+ windef->partitionClause == NIL &&
+ windef->orderClause == NIL &&
+ windef->frameOptions == FRAMEOPTION_DEFAULTS);
+
foreach(lc, pstate->p_windowdefs)
{
WindowDef *refwin = (WindowDef *) lfirst(lc);
winref++;
- if (refwin->name && strcmp(refwin->name, windef->refname) == 0)
+ if (refwin->name && strcmp(refwin->name, windef->name) == 0)
{
wfunc->winref = winref;
break;
@@ -150,7 +152,7 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc,
if (lc == NULL) /* didn't find it? */
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("window \"%s\" does not exist", windef->refname),
+ errmsg("window \"%s\" does not exist", windef->name),
parser_errposition(pstate, windef->location)));
}
else
@@ -164,14 +166,15 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc,
winref++;
if (refwin->refname && windef->refname &&
- strcmp(refwin->name, windef->refname) == 0)
+ strcmp(refwin->refname, windef->refname) == 0)
/* matched on refname */ ;
else if (!refwin->refname && !windef->refname)
/* matched, no refname */ ;
else
continue;
if (equal(refwin->partitionClause, windef->partitionClause) &&
- equal(refwin->orderClause, windef->orderClause))
+ equal(refwin->orderClause, windef->orderClause) &&
+ refwin->frameOptions == windef->frameOptions)
{
/* found a duplicate window specification */
wfunc->winref = winref;
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index df30361f0a5..247d54d8782 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.182 2008/12/28 18:53:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.183 2008/12/31 00:08:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1554,7 +1554,7 @@ transformWindowDefinitions(ParseState *pstate,
* Per spec, a windowdef that references a previous one copies the
* previous partition clause (and mustn't specify its own). It can
* specify its own ordering clause. but only if the previous one
- * had none.
+ * had none. It always specifies its own framing clause.
*/
if (refwc)
{
@@ -1592,6 +1592,7 @@ transformWindowDefinitions(ParseState *pstate,
wc->orderClause = orderClause;
wc->copiedOrder = false;
}
+ wc->frameOptions = windef->frameOptions;
wc->winref = winref;
result = lappend(result, wc);