From 5893ffa79c03824f34ae3d37f211381fd1c17283 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Fri, 28 Jun 2013 10:18:00 -0400 Subject: [PATCH] Make the OVER keyword unreserved. This results in a slightly less specific error message when OVER is used in a context where we don't accept window functions, but per discussion, it's worth it to get the benefit of not needing to reserve this keyword any more. This same refactoring will also let us avoid reserving some other keywords that we expect to add in upcoming patches (specifically, IGNORE, RESPECT, and FILTER). Troels Nielsen, with minor changes by me --- src/backend/parser/gram.y | 90 ++++++++++++++++++---------- src/include/parser/kwlist.h | 2 +- src/test/regress/expected/window.out | 4 +- 3 files changed, 63 insertions(+), 33 deletions(-) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 5094226750..c41f1b512f 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -401,7 +401,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type columnDef columnOptions %type def_elem reloption_elem old_aggr_elem %type def_arg columnElem where_clause where_or_current_clause - a_expr b_expr c_expr func_expr AexprConst indirection_el + a_expr b_expr c_expr AexprConst indirection_el columnref in_expr having_clause func_table array_expr ExclusionWhereClause %type ExclusionConstraintList ExclusionConstraintElem @@ -481,6 +481,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type document_or_content %type xml_whitespace_option +%type func_application func_expr_common_subexpr +%type func_expr func_expr_windowless %type common_table_expr %type with_clause opt_with_clause %type cte_list @@ -6132,7 +6134,7 @@ index_elem: ColId opt_collate opt_class opt_asc_desc opt_nulls_order $$->ordering = $4; $$->nulls_ordering = $5; } - | func_expr opt_collate opt_class opt_asc_desc opt_nulls_order + | func_expr_windowless opt_collate opt_class opt_asc_desc opt_nulls_order { $$ = makeNode(IndexElem); $$->name = NULL; @@ -9894,8 +9896,7 @@ relation_expr_opt_alias: relation_expr %prec UMINUS } ; - -func_table: func_expr { $$ = $1; } +func_table: func_expr_windowless { $$ = $1; } ; @@ -11079,15 +11080,7 @@ c_expr: columnref { $$ = $1; } } ; -/* - * func_expr is split out from c_expr just so that we have a classification - * for "everything that is a function call or looks like one". This isn't - * very important, but it saves us having to document which variants are - * legal in the backwards-compatible functional-index syntax for CREATE INDEX. - * (Note that many of the special SQL functions wouldn't actually make any - * sense as functional index entries, but we ignore that consideration here.) - */ -func_expr: func_name '(' ')' over_clause +func_application: func_name '(' ')' { FuncCall *n = makeNode(FuncCall); n->funcname = $1; @@ -11096,11 +11089,11 @@ func_expr: func_name '(' ')' over_clause n->agg_star = FALSE; n->agg_distinct = FALSE; n->func_variadic = FALSE; - n->over = $4; + n->over = NULL; n->location = @1; $$ = (Node *)n; } - | func_name '(' func_arg_list ')' over_clause + | func_name '(' func_arg_list ')' { FuncCall *n = makeNode(FuncCall); n->funcname = $1; @@ -11109,11 +11102,11 @@ func_expr: func_name '(' ')' over_clause n->agg_star = FALSE; n->agg_distinct = FALSE; n->func_variadic = FALSE; - n->over = $5; + n->over = NULL; n->location = @1; $$ = (Node *)n; } - | func_name '(' VARIADIC func_arg_expr ')' over_clause + | func_name '(' VARIADIC func_arg_expr ')' { FuncCall *n = makeNode(FuncCall); n->funcname = $1; @@ -11122,11 +11115,11 @@ func_expr: func_name '(' ')' over_clause n->agg_star = FALSE; n->agg_distinct = FALSE; n->func_variadic = TRUE; - n->over = $6; + n->over = NULL; n->location = @1; $$ = (Node *)n; } - | func_name '(' func_arg_list ',' VARIADIC func_arg_expr ')' over_clause + | func_name '(' func_arg_list ',' VARIADIC func_arg_expr ')' { FuncCall *n = makeNode(FuncCall); n->funcname = $1; @@ -11135,11 +11128,11 @@ func_expr: func_name '(' ')' over_clause n->agg_star = FALSE; n->agg_distinct = FALSE; n->func_variadic = TRUE; - n->over = $8; + n->over = NULL; n->location = @1; $$ = (Node *)n; } - | func_name '(' func_arg_list sort_clause ')' over_clause + | func_name '(' func_arg_list sort_clause ')' { FuncCall *n = makeNode(FuncCall); n->funcname = $1; @@ -11148,11 +11141,11 @@ func_expr: func_name '(' ')' over_clause n->agg_star = FALSE; n->agg_distinct = FALSE; n->func_variadic = FALSE; - n->over = $6; + n->over = NULL; n->location = @1; $$ = (Node *)n; } - | func_name '(' ALL func_arg_list opt_sort_clause ')' over_clause + | func_name '(' ALL func_arg_list opt_sort_clause ')' { FuncCall *n = makeNode(FuncCall); n->funcname = $1; @@ -11165,11 +11158,11 @@ func_expr: func_name '(' ')' over_clause * for that in FuncCall at the moment. */ n->func_variadic = FALSE; - n->over = $7; + n->over = NULL; n->location = @1; $$ = (Node *)n; } - | func_name '(' DISTINCT func_arg_list opt_sort_clause ')' over_clause + | func_name '(' DISTINCT func_arg_list opt_sort_clause ')' { FuncCall *n = makeNode(FuncCall); n->funcname = $1; @@ -11178,11 +11171,11 @@ func_expr: func_name '(' ')' over_clause n->agg_star = FALSE; n->agg_distinct = TRUE; n->func_variadic = FALSE; - n->over = $7; + n->over = NULL; n->location = @1; $$ = (Node *)n; } - | func_name '(' '*' ')' over_clause + | func_name '(' '*' ')' { /* * We consider AGGREGATE(*) to invoke a parameterless @@ -11201,11 +11194,48 @@ func_expr: func_name '(' ')' over_clause n->agg_star = TRUE; n->agg_distinct = FALSE; n->func_variadic = FALSE; - n->over = $5; + n->over = NULL; n->location = @1; $$ = (Node *)n; } - | COLLATION FOR '(' a_expr ')' + ; + + +/* + * func_expr and its cousin func_expr_windowless is split out from c_expr just + * so that we have classifications for "everything that is a function call or + * looks like one". This isn't very important, but it saves us having to document + * which variants are legal in the backwards-compatible functional-index syntax + * for CREATE INDEX. + * (Note that many of the special SQL functions wouldn't actually make any + * sense as functional index entries, but we ignore that consideration here.) + */ +func_expr: func_application over_clause + { + FuncCall *n = (FuncCall*)$1; + n->over = $2; + $$ = (Node*)n; + } + | func_expr_common_subexpr + { $$ = $1; } + ; + +/* + * As func_expr but does not accept WINDOW functions directly (they + * can still be contained in arguments for functions etc.) + * Use this when window expressions are not allowed, so to disambiguate + * the grammar. (e.g. in CREATE INDEX) + */ +func_expr_windowless: + func_application { $$ = $1; } + | func_expr_common_subexpr { $$ = $1; } + ; + +/* + * Special expression + */ +func_expr_common_subexpr: + COLLATION FOR '(' a_expr ')' { FuncCall *n = makeNode(FuncCall); n->funcname = SystemFuncName("pg_collation_for"); @@ -12794,6 +12824,7 @@ unreserved_keyword: | OPERATOR | OPTION | OPTIONS + | OVER | OWNED | OWNER | PARSER @@ -12992,7 +13023,6 @@ type_func_name_keyword: | NATURAL | NOTNULL | OUTER_P - | OVER | OVERLAPS | RIGHT | SIMILAR diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 68a13b7a7b..b3d72a9ae3 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -270,7 +270,7 @@ PG_KEYWORD("or", OR, RESERVED_KEYWORD) PG_KEYWORD("order", ORDER, RESERVED_KEYWORD) PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD) PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("over", OVER, TYPE_FUNC_NAME_KEYWORD) +PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD) PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD) PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD) diff --git a/src/test/regress/expected/window.out b/src/test/regress/expected/window.out index 752c7b42ff..ecc1c2c611 100644 --- a/src/test/regress/expected/window.out +++ b/src/test/regress/expected/window.out @@ -989,9 +989,9 @@ ERROR: window functions are not allowed in GROUP BY LINE 1: SELECT rank() OVER (ORDER BY 1), count(*) FROM empsalary GRO... ^ SELECT * FROM rank() OVER (ORDER BY random()); -ERROR: window functions are not allowed in functions in FROM +ERROR: syntax error at or near "ORDER" LINE 1: SELECT * FROM rank() OVER (ORDER BY random()); - ^ + ^ DELETE FROM empsalary WHERE (rank() OVER (ORDER BY random())) > 10; ERROR: window functions are not allowed in WHERE LINE 1: DELETE FROM empsalary WHERE (rank() OVER (ORDER BY random())... -- 2.40.0