diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 50942267500..c41f1b512f6 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 68a13b7a7ba..b3d72a9ae3b 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 752c7b42ff3..ecc1c2c6113 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())...