diff --git a/parser/ast.go b/parser/ast.go index daf1ad9..a919849 100644 --- a/parser/ast.go +++ b/parser/ast.go @@ -4810,6 +4810,7 @@ func (l *LimitByClause) Accept(visitor ASTVisitor) error { type WindowExpr struct { LeftParenPos Pos RightParenPos Pos + WindowName *Ident PartitionBy *PartitionByClause OrderBy *OrderByClause Frame *WindowFrameClause @@ -4826,6 +4827,11 @@ func (w *WindowExpr) End() Pos { func (w *WindowExpr) Accept(visitor ASTVisitor) error { visitor.Enter(w) defer visitor.Leave(w) + if w.WindowName != nil { + if err := w.WindowName.Accept(visitor); err != nil { + return err + } + } if w.PartitionBy != nil { if err := w.PartitionBy.Accept(visitor); err != nil { return err diff --git a/parser/format.go b/parser/format.go index a2946a3..d6b11aa 100644 --- a/parser/format.go +++ b/parser/format.go @@ -2755,7 +2755,14 @@ func (w *WindowClause) FormatSQL(formatter *Formatter) { func (w *WindowExpr) FormatSQL(formatter *Formatter) { formatter.WriteByte('(') hasPart := false + if w.WindowName != nil { + formatter.WriteExpr(w.WindowName) + hasPart = true + } if w.PartitionBy != nil { + if hasPart { + formatter.WriteByte(whitespace) + } formatter.WriteExpr(w.PartitionBy) hasPart = true } diff --git a/parser/parser_query.go b/parser/parser_query.go index 55d5eaf..682bfe2 100644 --- a/parser/parser_query.go +++ b/parser/parser_query.go @@ -824,6 +824,14 @@ func (p *Parser) parseWindowCondition(pos Pos) (*WindowExpr, error) { if err := p.expectTokenKind(TokenKindLParen); err != nil { return nil, err } + var windowName *Ident + if p.canParseWindowNameInParens() { + var err error + windowName, err = p.parseIdent() + if err != nil { + return nil, err + } + } partitionBy, err := p.tryParsePartitionByClause(pos) if err != nil { return nil, err @@ -843,12 +851,41 @@ func (p *Parser) parseWindowCondition(pos Pos) (*WindowExpr, error) { return &WindowExpr{ LeftParenPos: pos, RightParenPos: rightParenPos, + WindowName: windowName, PartitionBy: partitionBy, OrderBy: orderBy, Frame: frame, }, nil } +func (p *Parser) canParseWindowNameInParens() bool { + if !p.matchTokenKind(TokenKindIdent) { + return false + } + if !p.matchTokenKind(TokenKindKeyword) { + return true + } + + savedState := p.lexer.saveState() + defer p.lexer.restoreState(savedState) + + switch { + case p.matchKeyword(KeywordPartition), p.matchKeyword(KeywordOrder): + _ = p.lexer.consumeToken() + return !p.matchKeyword(KeywordBy) + case p.matchKeyword(KeywordRows), p.matchKeyword(KeywordRange): + _ = p.lexer.consumeToken() + return !p.matchKeyword(KeywordBetween) && + !p.matchKeyword(KeywordCurrent) && + !p.matchKeyword(KeywordUnbounded) && + !p.matchTokenKind(TokenKindInt) && + !p.matchTokenKind(TokenKindLBrace) && + !p.matchKeyword(KeywordInterval) + default: + return true + } +} + func (p *Parser) parseWindowClause(pos Pos) (*WindowClause, error) { if err := p.expectKeyword(KeywordWindow); err != nil { return nil, err diff --git a/parser/testdata/ddl/output/create_materialized_view_with_empty_table_schema.sql.golden.json b/parser/testdata/ddl/output/create_materialized_view_with_empty_table_schema.sql.golden.json index 8e5f63b..8564946 100644 --- a/parser/testdata/ddl/output/create_materialized_view_with_empty_table_schema.sql.golden.json +++ b/parser/testdata/ddl/output/create_materialized_view_with_empty_table_schema.sql.golden.json @@ -307,6 +307,7 @@ "OverExpr": { "LeftParenPos": 306, "RightParenPos": 347, + "WindowName": null, "PartitionBy": { "PartitionPos": 306, "Expr": { diff --git a/parser/testdata/query/format/beautify/select_window_keyword_name_in_parens.sql b/parser/testdata/query/format/beautify/select_window_keyword_name_in_parens.sql new file mode 100644 index 0000000..022ad7e --- /dev/null +++ b/parser/testdata/query/format/beautify/select_window_keyword_name_in_parens.sql @@ -0,0 +1,13 @@ +-- Origin SQL: +SELECT sum(x) OVER (order) AS sum_over_order +FROM t +WINDOW order AS (PARTITION BY team ORDER BY ts); + + +-- Beautify SQL: +SELECT + sum(x) OVER (order) AS sum_over_order +FROM + t +WINDOW order AS (PARTITION BY team ORDER BY + ts); diff --git a/parser/testdata/query/format/beautify/select_window_named_in_parens.sql b/parser/testdata/query/format/beautify/select_window_named_in_parens.sql new file mode 100644 index 0000000..2236aa5 --- /dev/null +++ b/parser/testdata/query/format/beautify/select_window_named_in_parens.sql @@ -0,0 +1,13 @@ +-- Origin SQL: +SELECT sum(x) OVER (w) AS sum_over_w +FROM t +WINDOW w AS (PARTITION BY y ORDER BY x); + + +-- Beautify SQL: +SELECT + sum(x) OVER (w) AS sum_over_w +FROM + t +WINDOW w AS (PARTITION BY y ORDER BY + x); diff --git a/parser/testdata/query/format/beautify/select_window_named_reference_extensions.sql b/parser/testdata/query/format/beautify/select_window_named_reference_extensions.sql new file mode 100644 index 0000000..2924426 --- /dev/null +++ b/parser/testdata/query/format/beautify/select_window_named_reference_extensions.sql @@ -0,0 +1,17 @@ +-- Origin SQL: +SELECT sum(x) OVER (w1 ORDER BY ts ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS rolling_sum, + avg(x) OVER (w2) AS avg_over_w2 +FROM t +WINDOW w1 AS (PARTITION BY team), + w2 AS (w1 ORDER BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW); + + +-- Beautify SQL: +SELECT + sum(x) OVER (w1 ORDER BY + ts ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS rolling_sum, + avg(x) OVER (w2) AS avg_over_w2 +FROM + t +WINDOW w1 AS (PARTITION BY team), w2 AS (w1 ORDER BY + ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW); diff --git a/parser/testdata/query/format/select_window_keyword_name_in_parens.sql b/parser/testdata/query/format/select_window_keyword_name_in_parens.sql new file mode 100644 index 0000000..9f8592d --- /dev/null +++ b/parser/testdata/query/format/select_window_keyword_name_in_parens.sql @@ -0,0 +1,8 @@ +-- Origin SQL: +SELECT sum(x) OVER (order) AS sum_over_order +FROM t +WINDOW order AS (PARTITION BY team ORDER BY ts); + + +-- Format SQL: +SELECT sum(x) OVER (order) AS sum_over_order FROM t WINDOW order AS (PARTITION BY team ORDER BY ts); diff --git a/parser/testdata/query/format/select_window_named_in_parens.sql b/parser/testdata/query/format/select_window_named_in_parens.sql new file mode 100644 index 0000000..b587f06 --- /dev/null +++ b/parser/testdata/query/format/select_window_named_in_parens.sql @@ -0,0 +1,8 @@ +-- Origin SQL: +SELECT sum(x) OVER (w) AS sum_over_w +FROM t +WINDOW w AS (PARTITION BY y ORDER BY x); + + +-- Format SQL: +SELECT sum(x) OVER (w) AS sum_over_w FROM t WINDOW w AS (PARTITION BY y ORDER BY x); diff --git a/parser/testdata/query/format/select_window_named_reference_extensions.sql b/parser/testdata/query/format/select_window_named_reference_extensions.sql new file mode 100644 index 0000000..75e19db --- /dev/null +++ b/parser/testdata/query/format/select_window_named_reference_extensions.sql @@ -0,0 +1,10 @@ +-- Origin SQL: +SELECT sum(x) OVER (w1 ORDER BY ts ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS rolling_sum, + avg(x) OVER (w2) AS avg_over_w2 +FROM t +WINDOW w1 AS (PARTITION BY team), + w2 AS (w1 ORDER BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW); + + +-- Format SQL: +SELECT sum(x) OVER (w1 ORDER BY ts ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS rolling_sum, avg(x) OVER (w2) AS avg_over_w2 FROM t WINDOW w1 AS (PARTITION BY team), w2 AS (w1 ORDER BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW); diff --git a/parser/testdata/query/output/create_window_view.sql.golden.json b/parser/testdata/query/output/create_window_view.sql.golden.json index 8f8101c..fdca53d 100644 --- a/parser/testdata/query/output/create_window_view.sql.golden.json +++ b/parser/testdata/query/output/create_window_view.sql.golden.json @@ -87,6 +87,7 @@ "OverExpr": { "LeftParenPos": 105, "RightParenPos": 238, + "WindowName": null, "PartitionBy": { "PartitionPos": 105, "Expr": { diff --git a/parser/testdata/query/output/select_simple.sql.golden.json b/parser/testdata/query/output/select_simple.sql.golden.json index 6a0d071..514213d 100644 --- a/parser/testdata/query/output/select_simple.sql.golden.json +++ b/parser/testdata/query/output/select_simple.sql.golden.json @@ -89,6 +89,7 @@ "OverExpr": { "LeftParenPos": 57, "RightParenPos": 89, + "WindowName": null, "PartitionBy": { "PartitionPos": 57, "Expr": { diff --git a/parser/testdata/query/output/select_window_comprehensive.sql.golden.json b/parser/testdata/query/output/select_window_comprehensive.sql.golden.json index 07a6702..d455d5c 100644 --- a/parser/testdata/query/output/select_window_comprehensive.sql.golden.json +++ b/parser/testdata/query/output/select_window_comprehensive.sql.golden.json @@ -42,6 +42,7 @@ "OverExpr": { "LeftParenPos": 212, "RightParenPos": 272, + "WindowName": null, "PartitionBy": null, "OrderBy": { "OrderPos": 213, @@ -124,6 +125,7 @@ "OverExpr": { "LeftParenPos": 356, "RightParenPos": 424, + "WindowName": null, "PartitionBy": { "PartitionPos": 356, "Expr": { @@ -356,6 +358,7 @@ "OverExpr": { "LeftParenPos": 965, "RightParenPos": 983, + "WindowName": null, "PartitionBy": null, "OrderBy": null, "Frame": { @@ -417,6 +420,7 @@ "OverExpr": { "LeftParenPos": 1105, "RightParenPos": 1154, + "WindowName": null, "PartitionBy": null, "OrderBy": null, "Frame": { @@ -481,6 +485,7 @@ "OverExpr": { "LeftParenPos": 1259, "RightParenPos": 1300, + "WindowName": null, "PartitionBy": null, "OrderBy": null, "Frame": { @@ -556,6 +561,7 @@ "OverExpr": { "LeftParenPos": 1392, "RightParenPos": 1435, + "WindowName": null, "PartitionBy": null, "OrderBy": null, "Frame": { @@ -625,6 +631,7 @@ "OverExpr": { "LeftParenPos": 1528, "RightParenPos": 1578, + "WindowName": null, "PartitionBy": null, "OrderBy": null, "Frame": { @@ -679,6 +686,7 @@ "OverExpr": { "LeftParenPos": 1708, "RightParenPos": 1734, + "WindowName": null, "PartitionBy": { "PartitionPos": 1708, "Expr": { @@ -753,6 +761,7 @@ "OverExpr": { "LeftParenPos": 1832, "RightParenPos": 1858, + "WindowName": null, "PartitionBy": { "PartitionPos": 1832, "Expr": { @@ -827,6 +836,7 @@ "OverExpr": { "LeftParenPos": 1969, "RightParenPos": 1995, + "WindowName": null, "PartitionBy": { "PartitionPos": 1969, "Expr": { @@ -911,6 +921,7 @@ "OverExpr": { "LeftParenPos": 2124, "RightParenPos": 2207, + "WindowName": null, "PartitionBy": { "PartitionPos": 2124, "Expr": { @@ -1012,6 +1023,7 @@ "OverExpr": { "LeftParenPos": 2273, "RightParenPos": 2356, + "WindowName": null, "PartitionBy": { "PartitionPos": 2273, "Expr": { @@ -1122,6 +1134,7 @@ "OverExpr": { "LeftParenPos": 2403, "RightParenPos": 2429, + "WindowName": null, "PartitionBy": { "PartitionPos": 2403, "Expr": { @@ -1215,6 +1228,7 @@ "OverExpr": { "LeftParenPos": 2533, "RightParenPos": 2559, + "WindowName": null, "PartitionBy": { "PartitionPos": 2533, "Expr": { @@ -1289,6 +1303,7 @@ "OverExpr": { "LeftParenPos": 2666, "RightParenPos": 2692, + "WindowName": null, "PartitionBy": { "PartitionPos": 2666, "Expr": { @@ -1504,6 +1519,7 @@ "OverExpr": { "LeftParenPos": 3300, "RightParenPos": 3355, + "WindowName": null, "PartitionBy": { "PartitionPos": 3300, "Expr": { @@ -1618,6 +1634,7 @@ "OverExpr": { "LeftParenPos": 3440, "RightParenPos": 3533, + "WindowName": null, "PartitionBy": { "PartitionPos": 3440, "Expr": { @@ -1739,6 +1756,7 @@ "OverExpr": { "LeftParenPos": 3629, "RightParenPos": 3732, + "WindowName": null, "PartitionBy": { "PartitionPos": 3629, "Expr": { @@ -1875,6 +1893,7 @@ "OverExpr": { "LeftParenPos": 3779, "RightParenPos": 3859, + "WindowName": null, "PartitionBy": null, "OrderBy": { "OrderPos": 3780, @@ -1987,6 +2006,7 @@ "Expr": { "LeftParenPos": 3917, "RightParenPos": 3928, + "WindowName": null, "PartitionBy": null, "OrderBy": { "OrderPos": 3918, @@ -2021,6 +2041,7 @@ "Expr": { "LeftParenPos": 3944, "RightParenPos": 4019, + "WindowName": null, "PartitionBy": { "PartitionPos": 3944, "Expr": { @@ -2089,6 +2110,7 @@ "Expr": { "LeftParenPos": 4035, "RightParenPos": 4102, + "WindowName": null, "PartitionBy": { "PartitionPos": 4035, "Expr": { @@ -2162,6 +2184,7 @@ "Expr": { "LeftParenPos": 4118, "RightParenPos": 4194, + "WindowName": null, "PartitionBy": { "PartitionPos": 4118, "Expr": { diff --git a/parser/testdata/query/output/select_window_cte.sql.golden.json b/parser/testdata/query/output/select_window_cte.sql.golden.json index c272655..a0b579d 100644 --- a/parser/testdata/query/output/select_window_cte.sql.golden.json +++ b/parser/testdata/query/output/select_window_cte.sql.golden.json @@ -270,6 +270,7 @@ "OverExpr": { "LeftParenPos": 364, "RightParenPos": 413, + "WindowName": null, "PartitionBy": { "PartitionPos": 364, "Expr": { @@ -448,6 +449,7 @@ "OverExpr": { "LeftParenPos": 541, "RightParenPos": 667, + "WindowName": null, "PartitionBy": { "PartitionPos": 541, "Expr": { diff --git a/parser/testdata/query/output/select_window_keyword_name_in_parens.sql.golden.json b/parser/testdata/query/output/select_window_keyword_name_in_parens.sql.golden.json new file mode 100644 index 0000000..a76f64d --- /dev/null +++ b/parser/testdata/query/output/select_window_keyword_name_in_parens.sql.golden.json @@ -0,0 +1,161 @@ +[ + { + "SelectPos": 0, + "StatementEnd": 98, + "With": null, + "Top": null, + "HasDistinct": false, + "DistinctOn": null, + "SelectItems": [ + { + "Expr": { + "Function": { + "Name": { + "Name": "sum", + "QuoteType": 1, + "NamePos": 7, + "NameEnd": 10 + }, + "Params": { + "LeftParenPos": 10, + "RightParenPos": 12, + "Items": { + "ListPos": 11, + "ListEnd": 12, + "HasDistinct": false, + "Items": [ + { + "Expr": { + "Name": "x", + "QuoteType": 1, + "NamePos": 11, + "NameEnd": 12 + }, + "Alias": null + } + ] + }, + "ColumnArgList": null + } + }, + "OverPos": 14, + "OverExpr": { + "LeftParenPos": 19, + "RightParenPos": 25, + "WindowName": { + "Name": "order", + "QuoteType": 1, + "NamePos": 20, + "NameEnd": 25 + }, + "PartitionBy": null, + "OrderBy": null, + "Frame": null + } + }, + "Modifiers": [], + "Alias": { + "Name": "sum_over_order", + "QuoteType": 1, + "NamePos": 30, + "NameEnd": 44 + } + } + ], + "From": { + "FromPos": 45, + "Expr": { + "Table": { + "TablePos": 50, + "TableEnd": 51, + "Alias": null, + "Expr": { + "Database": null, + "Table": { + "Name": "t", + "QuoteType": 1, + "NamePos": 50, + "NameEnd": 51 + } + }, + "HasFinal": false + }, + "StatementEnd": 51, + "SampleRatio": null, + "HasFinal": false + } + }, + "Window": { + "WindowPos": 52, + "EndPos": 98, + "Windows": [ + { + "Name": { + "Name": "order", + "QuoteType": 1, + "NamePos": 59, + "NameEnd": 64 + }, + "AsPos": 65, + "Expr": { + "LeftParenPos": 68, + "RightParenPos": 98, + "WindowName": null, + "PartitionBy": { + "PartitionPos": 68, + "Expr": { + "ListPos": 82, + "ListEnd": 86, + "HasDistinct": false, + "Items": [ + { + "Expr": { + "Name": "team", + "QuoteType": 1, + "NamePos": 82, + "NameEnd": 86 + }, + "Alias": null + } + ] + } + }, + "OrderBy": { + "OrderPos": 87, + "ListEnd": 98, + "Items": [ + { + "OrderPos": 87, + "Expr": { + "Name": "ts", + "QuoteType": 1, + "NamePos": 96, + "NameEnd": 98 + }, + "Alias": null, + "Direction": "", + "Fill": null + } + ], + "Interpolate": null + }, + "Frame": null + } + } + ] + }, + "Prewhere": null, + "Where": null, + "GroupBy": null, + "WithTotal": false, + "Having": null, + "OrderBy": null, + "LimitBy": null, + "Limit": null, + "Settings": null, + "Format": null, + "UnionAll": null, + "UnionDistinct": null, + "Except": null + } +] \ No newline at end of file diff --git a/parser/testdata/query/output/select_window_named_in_parens.sql.golden.json b/parser/testdata/query/output/select_window_named_in_parens.sql.golden.json new file mode 100644 index 0000000..a01de52 --- /dev/null +++ b/parser/testdata/query/output/select_window_named_in_parens.sql.golden.json @@ -0,0 +1,161 @@ +[ + { + "SelectPos": 0, + "StatementEnd": 82, + "With": null, + "Top": null, + "HasDistinct": false, + "DistinctOn": null, + "SelectItems": [ + { + "Expr": { + "Function": { + "Name": { + "Name": "sum", + "QuoteType": 1, + "NamePos": 7, + "NameEnd": 10 + }, + "Params": { + "LeftParenPos": 10, + "RightParenPos": 12, + "Items": { + "ListPos": 11, + "ListEnd": 12, + "HasDistinct": false, + "Items": [ + { + "Expr": { + "Name": "x", + "QuoteType": 1, + "NamePos": 11, + "NameEnd": 12 + }, + "Alias": null + } + ] + }, + "ColumnArgList": null + } + }, + "OverPos": 14, + "OverExpr": { + "LeftParenPos": 19, + "RightParenPos": 21, + "WindowName": { + "Name": "w", + "QuoteType": 1, + "NamePos": 20, + "NameEnd": 21 + }, + "PartitionBy": null, + "OrderBy": null, + "Frame": null + } + }, + "Modifiers": [], + "Alias": { + "Name": "sum_over_w", + "QuoteType": 1, + "NamePos": 26, + "NameEnd": 36 + } + } + ], + "From": { + "FromPos": 37, + "Expr": { + "Table": { + "TablePos": 42, + "TableEnd": 43, + "Alias": null, + "Expr": { + "Database": null, + "Table": { + "Name": "t", + "QuoteType": 1, + "NamePos": 42, + "NameEnd": 43 + } + }, + "HasFinal": false + }, + "StatementEnd": 43, + "SampleRatio": null, + "HasFinal": false + } + }, + "Window": { + "WindowPos": 44, + "EndPos": 82, + "Windows": [ + { + "Name": { + "Name": "w", + "QuoteType": 1, + "NamePos": 51, + "NameEnd": 52 + }, + "AsPos": 53, + "Expr": { + "LeftParenPos": 56, + "RightParenPos": 82, + "WindowName": null, + "PartitionBy": { + "PartitionPos": 56, + "Expr": { + "ListPos": 70, + "ListEnd": 71, + "HasDistinct": false, + "Items": [ + { + "Expr": { + "Name": "y", + "QuoteType": 1, + "NamePos": 70, + "NameEnd": 71 + }, + "Alias": null + } + ] + } + }, + "OrderBy": { + "OrderPos": 72, + "ListEnd": 82, + "Items": [ + { + "OrderPos": 72, + "Expr": { + "Name": "x", + "QuoteType": 1, + "NamePos": 81, + "NameEnd": 82 + }, + "Alias": null, + "Direction": "", + "Fill": null + } + ], + "Interpolate": null + }, + "Frame": null + } + } + ] + }, + "Prewhere": null, + "Where": null, + "GroupBy": null, + "WithTotal": false, + "Having": null, + "OrderBy": null, + "LimitBy": null, + "Limit": null, + "Settings": null, + "Format": null, + "UnionAll": null, + "UnionDistinct": null, + "Except": null + } +] \ No newline at end of file diff --git a/parser/testdata/query/output/select_window_named_reference_extensions.sql.golden.json b/parser/testdata/query/output/select_window_named_reference_extensions.sql.golden.json new file mode 100644 index 0000000..351f896 --- /dev/null +++ b/parser/testdata/query/output/select_window_named_reference_extensions.sql.golden.json @@ -0,0 +1,292 @@ +[ + { + "SelectPos": 0, + "StatementEnd": 303, + "With": null, + "Top": null, + "HasDistinct": false, + "DistinctOn": null, + "SelectItems": [ + { + "Expr": { + "Function": { + "Name": { + "Name": "sum", + "QuoteType": 1, + "NamePos": 7, + "NameEnd": 10 + }, + "Params": { + "LeftParenPos": 10, + "RightParenPos": 12, + "Items": { + "ListPos": 11, + "ListEnd": 12, + "HasDistinct": false, + "Items": [ + { + "Expr": { + "Name": "x", + "QuoteType": 1, + "NamePos": 11, + "NameEnd": 12 + }, + "Alias": null + } + ] + }, + "ColumnArgList": null + } + }, + "OverPos": 14, + "OverExpr": { + "LeftParenPos": 19, + "RightParenPos": 75, + "WindowName": { + "Name": "w1", + "QuoteType": 1, + "NamePos": 20, + "NameEnd": 22 + }, + "PartitionBy": null, + "OrderBy": { + "OrderPos": 23, + "ListEnd": 34, + "Items": [ + { + "OrderPos": 23, + "Expr": { + "Name": "ts", + "QuoteType": 1, + "NamePos": 32, + "NameEnd": 34 + }, + "Alias": null, + "Direction": "", + "Fill": null + } + ], + "Interpolate": null + }, + "Frame": { + "FramePos": 35, + "Type": "ROWS", + "Extend": { + "Expr": null, + "Between": { + "Number": { + "NumPos": 48, + "NumEnd": 49, + "Literal": "1", + "Base": 10 + }, + "EndPos": 59, + "Direction": "PRECEDING" + }, + "AndPos": 60, + "And": { + "CurrentPos": 64, + "RowEnd": 76 + } + } + } + } + }, + "Modifiers": [], + "Alias": { + "Name": "rolling_sum", + "QuoteType": 1, + "NamePos": 80, + "NameEnd": 91 + } + }, + { + "Expr": { + "Function": { + "Name": { + "Name": "avg", + "QuoteType": 1, + "NamePos": 100, + "NameEnd": 103 + }, + "Params": { + "LeftParenPos": 103, + "RightParenPos": 105, + "Items": { + "ListPos": 104, + "ListEnd": 105, + "HasDistinct": false, + "Items": [ + { + "Expr": { + "Name": "x", + "QuoteType": 1, + "NamePos": 104, + "NameEnd": 105 + }, + "Alias": null + } + ] + }, + "ColumnArgList": null + } + }, + "OverPos": 107, + "OverExpr": { + "LeftParenPos": 112, + "RightParenPos": 115, + "WindowName": { + "Name": "w2", + "QuoteType": 1, + "NamePos": 113, + "NameEnd": 115 + }, + "PartitionBy": null, + "OrderBy": null, + "Frame": null + } + }, + "Modifiers": [], + "Alias": { + "Name": "avg_over_w2", + "QuoteType": 1, + "NamePos": 173, + "NameEnd": 184 + } + } + ], + "From": { + "FromPos": 185, + "Expr": { + "Table": { + "TablePos": 190, + "TableEnd": 191, + "Alias": null, + "Expr": { + "Database": null, + "Table": { + "Name": "t", + "QuoteType": 1, + "NamePos": 190, + "NameEnd": 191 + } + }, + "HasFinal": false + }, + "StatementEnd": 191, + "SampleRatio": null, + "HasFinal": false + } + }, + "Window": { + "WindowPos": 192, + "EndPos": 303, + "Windows": [ + { + "Name": { + "Name": "w1", + "QuoteType": 1, + "NamePos": 199, + "NameEnd": 201 + }, + "AsPos": 202, + "Expr": { + "LeftParenPos": 205, + "RightParenPos": 223, + "WindowName": null, + "PartitionBy": { + "PartitionPos": 205, + "Expr": { + "ListPos": 219, + "ListEnd": 223, + "HasDistinct": false, + "Items": [ + { + "Expr": { + "Name": "team", + "QuoteType": 1, + "NamePos": 219, + "NameEnd": 223 + }, + "Alias": null + } + ] + } + }, + "OrderBy": null, + "Frame": null + } + }, + { + "Name": { + "Name": "w2", + "QuoteType": 1, + "NamePos": 233, + "NameEnd": 235 + }, + "AsPos": 236, + "Expr": { + "LeftParenPos": 239, + "RightParenPos": 303, + "WindowName": { + "Name": "w1", + "QuoteType": 1, + "NamePos": 240, + "NameEnd": 242 + }, + "PartitionBy": null, + "OrderBy": { + "OrderPos": 243, + "ListEnd": 254, + "Items": [ + { + "OrderPos": 243, + "Expr": { + "Name": "ts", + "QuoteType": 1, + "NamePos": 252, + "NameEnd": 254 + }, + "Alias": null, + "Direction": "", + "Fill": null + } + ], + "Interpolate": null + }, + "Frame": { + "FramePos": 255, + "Type": "ROWS", + "Extend": { + "Expr": null, + "Between": { + "UnboundedPos": 268, + "UnboundedEnd": 0, + "Direction": "PRECEDING" + }, + "AndPos": 288, + "And": { + "CurrentPos": 292, + "RowEnd": 304 + } + } + } + } + } + ] + }, + "Prewhere": null, + "Where": null, + "GroupBy": null, + "WithTotal": false, + "Having": null, + "OrderBy": null, + "LimitBy": null, + "Limit": null, + "Settings": null, + "Format": null, + "UnionAll": null, + "UnionDistinct": null, + "Except": null + } +] \ No newline at end of file diff --git a/parser/testdata/query/output/select_window_params.sql.golden.json b/parser/testdata/query/output/select_window_params.sql.golden.json index 1b0e3f7..bf16b7a 100644 --- a/parser/testdata/query/output/select_window_params.sql.golden.json +++ b/parser/testdata/query/output/select_window_params.sql.golden.json @@ -42,6 +42,7 @@ "OverExpr": { "LeftParenPos": 119, "RightParenPos": 184, + "WindowName": null, "PartitionBy": null, "OrderBy": { "OrderPos": 120, @@ -141,6 +142,7 @@ "OverExpr": { "LeftParenPos": 242, "RightParenPos": 305, + "WindowName": null, "PartitionBy": null, "OrderBy": { "OrderPos": 243, @@ -240,6 +242,7 @@ "OverExpr": { "LeftParenPos": 365, "RightParenPos": 454, + "WindowName": null, "PartitionBy": null, "OrderBy": { "OrderPos": 366, @@ -357,6 +360,7 @@ "OverExpr": { "LeftParenPos": 484, "RightParenPos": 521, + "WindowName": null, "PartitionBy": null, "OrderBy": null, "Frame": { diff --git a/parser/testdata/query/output/select_with_window_function.sql.golden.json b/parser/testdata/query/output/select_with_window_function.sql.golden.json index 2a11ee3..f9f31c0 100644 --- a/parser/testdata/query/output/select_with_window_function.sql.golden.json +++ b/parser/testdata/query/output/select_with_window_function.sql.golden.json @@ -147,6 +147,7 @@ "OverExpr": { "LeftParenPos": 218, "RightParenPos": 327, + "WindowName": null, "PartitionBy": { "PartitionPos": 218, "Expr": { @@ -304,6 +305,7 @@ "Expr": { "LeftParenPos": 399, "RightParenPos": 508, + "WindowName": null, "PartitionBy": { "PartitionPos": 399, "Expr": { diff --git a/parser/testdata/query/select_window_keyword_name_in_parens.sql b/parser/testdata/query/select_window_keyword_name_in_parens.sql new file mode 100644 index 0000000..57d06cf --- /dev/null +++ b/parser/testdata/query/select_window_keyword_name_in_parens.sql @@ -0,0 +1,3 @@ +SELECT sum(x) OVER (order) AS sum_over_order +FROM t +WINDOW order AS (PARTITION BY team ORDER BY ts); diff --git a/parser/testdata/query/select_window_named_in_parens.sql b/parser/testdata/query/select_window_named_in_parens.sql new file mode 100644 index 0000000..a0b2f7a --- /dev/null +++ b/parser/testdata/query/select_window_named_in_parens.sql @@ -0,0 +1,3 @@ +SELECT sum(x) OVER (w) AS sum_over_w +FROM t +WINDOW w AS (PARTITION BY y ORDER BY x); diff --git a/parser/testdata/query/select_window_named_reference_extensions.sql b/parser/testdata/query/select_window_named_reference_extensions.sql new file mode 100644 index 0000000..2780076 --- /dev/null +++ b/parser/testdata/query/select_window_named_reference_extensions.sql @@ -0,0 +1,5 @@ +SELECT sum(x) OVER (w1 ORDER BY ts ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS rolling_sum, + avg(x) OVER (w2) AS avg_over_w2 +FROM t +WINDOW w1 AS (PARTITION BY team), + w2 AS (w1 ORDER BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW); diff --git a/parser/walk.go b/parser/walk.go index a942fb9..f04e110 100644 --- a/parser/walk.go +++ b/parser/walk.go @@ -389,6 +389,9 @@ func Walk(node Expr, fn WalkFunc) bool { } } case *WindowExpr: + if !Walk(n.WindowName, fn) { + return false + } if !Walk(n.PartitionBy, fn) { return false }