diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/gram.y | 113 | ||||
-rw-r--r-- | src/backend/parser/keywords.c | 6 | ||||
-rw-r--r-- | src/backend/parser/parse_agg.c | 23 | ||||
-rw-r--r-- | src/backend/parser/parse_clause.c | 5 |
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); |