diff --git a/ast/ast.go b/ast/ast.go index e9c023be..c123d13a 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -176,6 +176,24 @@ func (ExprArg) isArg() {} func (IntervalArg) isArg() {} func (SequenceArg) isArg() {} +// NullHandlingModifier represents IGNORE/RESPECT NULLS of aggregate function calls +type NullHandlingModifier interface { + Node + isNullHandlingModifier() +} + +func (IgnoreNulls) isNullHandlingModifier() {} +func (RespectNulls) isNullHandlingModifier() {} + +// HavingModifier represents HAVING clause of aggregate function calls. +type HavingModifier interface { + Node + isHavingModifier() +} + +func (HavingMax) isHavingModifier() {} +func (HavingMin) isHavingModifier() {} + // InCondition is right-side value of IN operator. type InCondition interface { Node @@ -989,17 +1007,26 @@ type IndexExpr struct { // CallExpr is function call expression node. // -// {{.Func | sql}}({{if .Distinct}}DISTINCT{{end}} {{.Args | sqlJoin ", "}}{{if len(.Args) > 0 && len(.NamedArgs) > 0}}, {{end}}{{.NamedArgs || sqlJoin ", "}}) +// {{.Func | sql}}( +// {{if .Distinct}}DISTINCT{{end}} +// {{.Args | sqlJoin ", "}} +// {{if len(.Args) > 0 && len(.NamedArgs) > 0}}, {{end}} +// {{.NamedArgs | sqlJoin ", "}} +// {{.NullHandling | sqlOpt}} +// {{.Having | sqlOpt}} +// ) type CallExpr struct { // pos = Func.pos // end = Rparen + 1 Rparen token.Pos // position of ")" - Func *Ident - Distinct bool - Args []Arg - NamedArgs []*NamedArg + Func *Ident + Distinct bool + Args []Arg + NamedArgs []*NamedArg + NullHandling NullHandlingModifier // optional + Having HavingModifier // optional } // ExprArg is argument of the generic function call. @@ -1048,6 +1075,50 @@ type NamedArg struct { Value Expr } +// IgnoreNulls represents IGNORE NULLS of aggregate function calls. +// +// IGNORE NULLS +type IgnoreNulls struct { + // pos = Ignore + // end = Nulls + 5 + + Ignore token.Pos + Nulls token.Pos +} + +// RespectNulls represents RESPECT NULLS of aggregate function calls +// +// RESPECT NULLS +type RespectNulls struct { + // pos = Respect + // end = Nulls + 5 + + Respect token.Pos + Nulls token.Pos +} + +// HavingMax represents HAVING MAX of aggregate function calls. +// +// HAVING MAX {{Expr | sql}} +type HavingMax struct { + // pos = Having + // end = Expr.end + + Having token.Pos + Expr Expr +} + +// HavingMin represents HAVING MIN of aggregate function calls. +// +// HAVING MIN {{Expr | sql}} +type HavingMin struct { + // pos = Having + // end = Expr.end + + Having token.Pos + Expr Expr +} + // CountStarExpr is node just for COUNT(*). // // COUNT(*) diff --git a/ast/pos.go b/ast/pos.go index 3a17aef2..f8d86cd4 100644 --- a/ast/pos.go +++ b/ast/pos.go @@ -367,6 +367,18 @@ func (s *SequenceArg) End() token.Pos { return s.Expr.End() } func (n *NamedArg) Pos() token.Pos { return n.Name.Pos() } func (n *NamedArg) End() token.Pos { return n.Value.End() } +func (i *IgnoreNulls) Pos() token.Pos { return i.Ignore } +func (i *IgnoreNulls) End() token.Pos { return i.Nulls + 5 } + +func (r *RespectNulls) Pos() token.Pos { return r.Respect } +func (r *RespectNulls) End() token.Pos { return r.Nulls + 5 } + +func (h *HavingMax) Pos() token.Pos { return h.Having } +func (h *HavingMax) End() token.Pos { return h.Expr.End() } + +func (h *HavingMin) Pos() token.Pos { return h.Having } +func (h *HavingMin) End() token.Pos { return h.Expr.End() } + func (c *CountStarExpr) Pos() token.Pos { return c.Count } func (c *CountStarExpr) End() token.Pos { return c.Rparen + 1 } diff --git a/ast/sql.go b/ast/sql.go index 2b93cfa5..2bdcb60a 100644 --- a/ast/sql.go +++ b/ast/sql.go @@ -506,11 +506,21 @@ func (c *CallExpr) SQL() string { sqlJoin(c.Args, ", ") + strOpt(len(c.Args) > 0 && len(c.NamedArgs) > 0, ", ") + sqlJoin(c.NamedArgs, ", ") + + sqlOpt(" ", c.NullHandling, "") + + sqlOpt(" ", c.Having, "") + ")" } func (n *NamedArg) SQL() string { return n.Name.SQL() + " => " + n.Value.SQL() } +func (i *IgnoreNulls) SQL() string { return "IGNORE NULLS" } + +func (r *RespectNulls) SQL() string { return "RESPECT NULLS" } + +func (h *HavingMax) SQL() string { return "HAVING MAX " + h.Expr.SQL() } + +func (h *HavingMin) SQL() string { return "HAVING MIN " + h.Expr.SQL() } + func (s *ExprArg) SQL() string { return s.Expr.SQL() } diff --git a/parser.go b/parser.go index 41f947db..fc592644 100644 --- a/parser.go +++ b/parser.go @@ -1492,15 +1492,21 @@ func (p *Parser) parseCall(id token.Token) ast.Expr { p.nextToken() } + nullHandling := p.tryParseNullHandlingModifier() + having := p.tryParseHavingModifier() + rparen := p.expect(")").Pos return &ast.CallExpr{ - Rparen: rparen, - Func: fn, - Distinct: distinct, - Args: args, - NamedArgs: namedArgs, + Rparen: rparen, + Func: fn, + Distinct: distinct, + Args: args, + NamedArgs: namedArgs, + NullHandling: nullHandling, + Having: having, } } + func (p *Parser) lookaheadNamedArg() bool { lexer := p.Lexer.Clone() defer func() { @@ -1574,6 +1580,58 @@ func (p *Parser) parseExprArg() *ast.ExprArg { } } +func (p *Parser) tryParseHavingModifier() ast.HavingModifier { + if p.Token.Kind != "HAVING" { + return nil + } + + having := p.expect("HAVING").Pos + + switch { + case p.Token.IsKeywordLike("MIN"): + p.nextToken() + expr := p.parseExpr() + + return &ast.HavingMin{ + Having: having, + Expr: expr, + } + case p.Token.IsKeywordLike("MAX"): + p.nextToken() + expr := p.parseExpr() + + return &ast.HavingMax{ + Having: having, + Expr: expr, + } + default: + panic(p.errorfAtToken(&p.Token, `expect MIN or MAX, but: %v`, p.Token.Kind)) + } +} + +func (p *Parser) tryParseNullHandlingModifier() ast.NullHandlingModifier { + switch p.Token.Kind { + case "IGNORE": + ignore := p.expect("IGNORE").Pos + nulls := p.expect("NULLS").Pos + + return &ast.IgnoreNulls{ + Ignore: ignore, + Nulls: nulls, + } + case "RESPECT": + respect := p.expect("RESPECT").Pos + nulls := p.expect("NULLS").Pos + + return &ast.RespectNulls{ + Respect: respect, + Nulls: nulls, + } + default: + return nil + } +} + func (p *Parser) parseCaseExpr() *ast.CaseExpr { pos := p.expect("CASE").Pos var expr ast.Expr diff --git a/testdata/input/query/aggregate_function_calls.sql b/testdata/input/query/aggregate_function_calls.sql new file mode 100644 index 00000000..b921739e --- /dev/null +++ b/testdata/input/query/aggregate_function_calls.sql @@ -0,0 +1,6 @@ +SELECT + ARRAY_AGG(inches HAVING MAX year), + ARRAY_AGG(inches HAVING MIN year), + ARRAY_AGG(inches IGNORE NULLS), + ARRAY_AGG(inches RESPECT NULLS), + ARRAY_AGG(inches RESPECT NULLS HAVING MAX year), diff --git a/testdata/result/ddl/alter_table_add_column_with_if_expression.sql.txt b/testdata/result/ddl/alter_table_add_column_with_if_expression.sql.txt index 6c00d732..be16d697 100644 --- a/testdata/result/ddl/alter_table_add_column_with_if_expression.sql.txt +++ b/testdata/result/ddl/alter_table_add_column_with_if_expression.sql.txt @@ -99,7 +99,9 @@ ALTER TABLE foo ADD COLUMN expired_at TIMESTAMP AS (IF (status != "OPEN" AND sta }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, &ast.ExprArg{ @@ -108,7 +110,9 @@ ALTER TABLE foo ADD COLUMN expired_at TIMESTAMP AS (IF (status != "OPEN" AND sta }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, Options: (*ast.Options)(nil), diff --git a/testdata/result/ddl/create_table.sql.txt b/testdata/result/ddl/create_table.sql.txt index 523952f9..6ae97cc4 100644 --- a/testdata/result/ddl/create_table.sql.txt +++ b/testdata/result/ddl/create_table.sql.txt @@ -144,7 +144,9 @@ create table foo ( }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, Options: (*ast.Options)(nil), @@ -187,9 +189,11 @@ create table foo ( NameEnd: 546, Name: "current_timestamp", }, - Distinct: false, - Args: []ast.Arg(nil), - NamedArgs: []*ast.NamedArg(nil), + Distinct: false, + Args: []ast.Arg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, GeneratedExpr: (*ast.GeneratedColumnExpr)(nil), diff --git a/testdata/result/ddl/create_table_with_sequence_function.sql.txt b/testdata/result/ddl/create_table_with_sequence_function.sql.txt index 5025a256..f2b827cb 100644 --- a/testdata/result/ddl/create_table_with_sequence_function.sql.txt +++ b/testdata/result/ddl/create_table_with_sequence_function.sql.txt @@ -50,7 +50,9 @@ CREATE TABLE foo }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, GeneratedExpr: (*ast.GeneratedColumnExpr)(nil), diff --git a/testdata/result/dml/insert_with_sequence_function.sql.txt b/testdata/result/dml/insert_with_sequence_function.sql.txt index 2424b7a2..7f5a4b8d 100644 --- a/testdata/result/dml/insert_with_sequence_function.sql.txt +++ b/testdata/result/dml/insert_with_sequence_function.sql.txt @@ -45,7 +45,9 @@ INSERT INTO foo(bar) VALUES (GET_NEXT_SEQUENCE_VALUE(SEQUENCE my_sequence)) }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, }, diff --git a/testdata/result/query/aggregate_function_calls.sql.txt b/testdata/result/query/aggregate_function_calls.sql.txt new file mode 100644 index 00000000..9e2ad6c2 --- /dev/null +++ b/testdata/result/query/aggregate_function_calls.sql.txt @@ -0,0 +1,174 @@ +--- aggregate_function_calls.sql +SELECT + ARRAY_AGG(inches HAVING MAX year), + ARRAY_AGG(inches HAVING MIN year), + ARRAY_AGG(inches IGNORE NULLS), + ARRAY_AGG(inches RESPECT NULLS), + ARRAY_AGG(inches RESPECT NULLS HAVING MAX year), + +--- AST +&ast.QueryStatement{ + Hint: (*ast.Hint)(nil), + With: (*ast.With)(nil), + Query: &ast.Select{ + Select: 0, + Distinct: false, + As: nil, + Results: []ast.SelectItem{ + &ast.ExprSelectItem{ + Expr: &ast.CallExpr{ + Rparen: 43, + Func: &ast.Ident{ + NamePos: 11, + NameEnd: 20, + Name: "ARRAY_AGG", + }, + Distinct: false, + Args: []ast.Arg{ + &ast.ExprArg{ + Expr: &ast.Ident{ + NamePos: 21, + NameEnd: 27, + Name: "inches", + }, + }, + }, + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: &ast.HavingMax{ + Having: 28, + Expr: &ast.Ident{ + NamePos: 39, + NameEnd: 43, + Name: "year", + }, + }, + }, + }, + &ast.ExprSelectItem{ + Expr: &ast.CallExpr{ + Rparen: 82, + Func: &ast.Ident{ + NamePos: 50, + NameEnd: 59, + Name: "ARRAY_AGG", + }, + Distinct: false, + Args: []ast.Arg{ + &ast.ExprArg{ + Expr: &ast.Ident{ + NamePos: 60, + NameEnd: 66, + Name: "inches", + }, + }, + }, + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: &ast.HavingMin{ + Having: 67, + Expr: &ast.Ident{ + NamePos: 78, + NameEnd: 82, + Name: "year", + }, + }, + }, + }, + &ast.ExprSelectItem{ + Expr: &ast.CallExpr{ + Rparen: 118, + Func: &ast.Ident{ + NamePos: 89, + NameEnd: 98, + Name: "ARRAY_AGG", + }, + Distinct: false, + Args: []ast.Arg{ + &ast.ExprArg{ + Expr: &ast.Ident{ + NamePos: 99, + NameEnd: 105, + Name: "inches", + }, + }, + }, + NamedArgs: []*ast.NamedArg(nil), + NullHandling: &ast.IgnoreNulls{ + Ignore: 106, + Nulls: 113, + }, + Having: nil, + }, + }, + &ast.ExprSelectItem{ + Expr: &ast.CallExpr{ + Rparen: 155, + Func: &ast.Ident{ + NamePos: 125, + NameEnd: 134, + Name: "ARRAY_AGG", + }, + Distinct: false, + Args: []ast.Arg{ + &ast.ExprArg{ + Expr: &ast.Ident{ + NamePos: 135, + NameEnd: 141, + Name: "inches", + }, + }, + }, + NamedArgs: []*ast.NamedArg(nil), + NullHandling: &ast.RespectNulls{ + Respect: 142, + Nulls: 150, + }, + Having: nil, + }, + }, + &ast.ExprSelectItem{ + Expr: &ast.CallExpr{ + Rparen: 208, + Func: &ast.Ident{ + NamePos: 162, + NameEnd: 171, + Name: "ARRAY_AGG", + }, + Distinct: false, + Args: []ast.Arg{ + &ast.ExprArg{ + Expr: &ast.Ident{ + NamePos: 172, + NameEnd: 178, + Name: "inches", + }, + }, + }, + NamedArgs: []*ast.NamedArg(nil), + NullHandling: &ast.RespectNulls{ + Respect: 179, + Nulls: 187, + }, + Having: &ast.HavingMax{ + Having: 193, + Expr: &ast.Ident{ + NamePos: 204, + NameEnd: 208, + Name: "year", + }, + }, + }, + }, + }, + From: (*ast.From)(nil), + Where: (*ast.Where)(nil), + GroupBy: (*ast.GroupBy)(nil), + Having: (*ast.Having)(nil), + OrderBy: (*ast.OrderBy)(nil), + Limit: (*ast.Limit)(nil), + }, +} + +--- SQL +SELECT ARRAY_AGG(inches HAVING MAX year), ARRAY_AGG(inches HAVING MIN year), ARRAY_AGG(inches IGNORE NULLS), ARRAY_AGG(inches RESPECT NULLS), ARRAY_AGG(inches RESPECT NULLS HAVING MAX year) diff --git a/testdata/result/query/select_call_with_named_expr.sql.txt b/testdata/result/query/select_call_with_named_expr.sql.txt index 347e5130..78d1d157 100644 --- a/testdata/result/query/select_call_with_named_expr.sql.txt +++ b/testdata/result/query/select_call_with_named_expr.sql.txt @@ -137,6 +137,8 @@ WHERE a.SingerId = 1 AND SEARCH(a.DescriptionTokens, 'classic albums', enhance_q }, }, }, + NullHandling: nil, + Having: nil, }, }, }, diff --git a/testdata/result/query/select_count_distinct.sql.txt b/testdata/result/query/select_count_distinct.sql.txt index 4cb7d986..76755e4a 100644 --- a/testdata/result/query/select_count_distinct.sql.txt +++ b/testdata/result/query/select_count_distinct.sql.txt @@ -27,7 +27,9 @@ select count(distinct x) from foo }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, }, diff --git a/testdata/result/query/select_expr.sql.txt b/testdata/result/query/select_expr.sql.txt index eeb46ce1..e6c89c30 100644 --- a/testdata/result/query/select_expr.sql.txt +++ b/testdata/result/query/select_expr.sql.txt @@ -617,7 +617,9 @@ select 1 + 2, 1 - 2, }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, &ast.ExprSelectItem{ @@ -655,7 +657,9 @@ select 1 + 2, 1 - 2, }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, &ast.ExprSelectItem{ @@ -899,7 +903,9 @@ select 1 + 2, 1 - 2, }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, Right: &ast.IntLiteral{ ValuePos: 790, diff --git a/testdata/result/query/select_literals_all.sql.txt b/testdata/result/query/select_literals_all.sql.txt index b8556bb4..3e35cc34 100644 --- a/testdata/result/query/select_literals_all.sql.txt +++ b/testdata/result/query/select_literals_all.sql.txt @@ -504,7 +504,9 @@ lines''', }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, &ast.ExprSelectItem{ @@ -555,7 +557,9 @@ lines''', }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, &ast.ExprSelectItem{ diff --git a/testdata/result/query/select_literals_date.sql.txt b/testdata/result/query/select_literals_date.sql.txt index 1ccd8fb4..fd6b3596 100644 --- a/testdata/result/query/select_literals_date.sql.txt +++ b/testdata/result/query/select_literals_date.sql.txt @@ -48,7 +48,9 @@ SELECT }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, &ast.ExprSelectItem{ @@ -109,7 +111,9 @@ SELECT }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, &ast.ExprSelectItem{ @@ -140,7 +144,9 @@ SELECT }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, As: &ast.AsAlias{ As: -1, @@ -169,7 +175,9 @@ SELECT }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, As: &ast.AsAlias{ As: -1, diff --git a/testdata/result/query/select_with_sequence_function.sql.txt b/testdata/result/query/select_with_sequence_function.sql.txt index 1abdadb4..491d47f0 100644 --- a/testdata/result/query/select_with_sequence_function.sql.txt +++ b/testdata/result/query/select_with_sequence_function.sql.txt @@ -29,7 +29,9 @@ SELECT GET_NEXT_SEQUENCE_VALUE(SEQUENCE my_sequence) as next_id }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, As: &ast.AsAlias{ As: -1, diff --git a/testdata/result/statement/aggregate_function_calls.sql.txt b/testdata/result/statement/aggregate_function_calls.sql.txt new file mode 100644 index 00000000..9e2ad6c2 --- /dev/null +++ b/testdata/result/statement/aggregate_function_calls.sql.txt @@ -0,0 +1,174 @@ +--- aggregate_function_calls.sql +SELECT + ARRAY_AGG(inches HAVING MAX year), + ARRAY_AGG(inches HAVING MIN year), + ARRAY_AGG(inches IGNORE NULLS), + ARRAY_AGG(inches RESPECT NULLS), + ARRAY_AGG(inches RESPECT NULLS HAVING MAX year), + +--- AST +&ast.QueryStatement{ + Hint: (*ast.Hint)(nil), + With: (*ast.With)(nil), + Query: &ast.Select{ + Select: 0, + Distinct: false, + As: nil, + Results: []ast.SelectItem{ + &ast.ExprSelectItem{ + Expr: &ast.CallExpr{ + Rparen: 43, + Func: &ast.Ident{ + NamePos: 11, + NameEnd: 20, + Name: "ARRAY_AGG", + }, + Distinct: false, + Args: []ast.Arg{ + &ast.ExprArg{ + Expr: &ast.Ident{ + NamePos: 21, + NameEnd: 27, + Name: "inches", + }, + }, + }, + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: &ast.HavingMax{ + Having: 28, + Expr: &ast.Ident{ + NamePos: 39, + NameEnd: 43, + Name: "year", + }, + }, + }, + }, + &ast.ExprSelectItem{ + Expr: &ast.CallExpr{ + Rparen: 82, + Func: &ast.Ident{ + NamePos: 50, + NameEnd: 59, + Name: "ARRAY_AGG", + }, + Distinct: false, + Args: []ast.Arg{ + &ast.ExprArg{ + Expr: &ast.Ident{ + NamePos: 60, + NameEnd: 66, + Name: "inches", + }, + }, + }, + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: &ast.HavingMin{ + Having: 67, + Expr: &ast.Ident{ + NamePos: 78, + NameEnd: 82, + Name: "year", + }, + }, + }, + }, + &ast.ExprSelectItem{ + Expr: &ast.CallExpr{ + Rparen: 118, + Func: &ast.Ident{ + NamePos: 89, + NameEnd: 98, + Name: "ARRAY_AGG", + }, + Distinct: false, + Args: []ast.Arg{ + &ast.ExprArg{ + Expr: &ast.Ident{ + NamePos: 99, + NameEnd: 105, + Name: "inches", + }, + }, + }, + NamedArgs: []*ast.NamedArg(nil), + NullHandling: &ast.IgnoreNulls{ + Ignore: 106, + Nulls: 113, + }, + Having: nil, + }, + }, + &ast.ExprSelectItem{ + Expr: &ast.CallExpr{ + Rparen: 155, + Func: &ast.Ident{ + NamePos: 125, + NameEnd: 134, + Name: "ARRAY_AGG", + }, + Distinct: false, + Args: []ast.Arg{ + &ast.ExprArg{ + Expr: &ast.Ident{ + NamePos: 135, + NameEnd: 141, + Name: "inches", + }, + }, + }, + NamedArgs: []*ast.NamedArg(nil), + NullHandling: &ast.RespectNulls{ + Respect: 142, + Nulls: 150, + }, + Having: nil, + }, + }, + &ast.ExprSelectItem{ + Expr: &ast.CallExpr{ + Rparen: 208, + Func: &ast.Ident{ + NamePos: 162, + NameEnd: 171, + Name: "ARRAY_AGG", + }, + Distinct: false, + Args: []ast.Arg{ + &ast.ExprArg{ + Expr: &ast.Ident{ + NamePos: 172, + NameEnd: 178, + Name: "inches", + }, + }, + }, + NamedArgs: []*ast.NamedArg(nil), + NullHandling: &ast.RespectNulls{ + Respect: 179, + Nulls: 187, + }, + Having: &ast.HavingMax{ + Having: 193, + Expr: &ast.Ident{ + NamePos: 204, + NameEnd: 208, + Name: "year", + }, + }, + }, + }, + }, + From: (*ast.From)(nil), + Where: (*ast.Where)(nil), + GroupBy: (*ast.GroupBy)(nil), + Having: (*ast.Having)(nil), + OrderBy: (*ast.OrderBy)(nil), + Limit: (*ast.Limit)(nil), + }, +} + +--- SQL +SELECT ARRAY_AGG(inches HAVING MAX year), ARRAY_AGG(inches HAVING MIN year), ARRAY_AGG(inches IGNORE NULLS), ARRAY_AGG(inches RESPECT NULLS), ARRAY_AGG(inches RESPECT NULLS HAVING MAX year) diff --git a/testdata/result/statement/alter_table_add_column_with_if_expression.sql.txt b/testdata/result/statement/alter_table_add_column_with_if_expression.sql.txt index 6c00d732..be16d697 100644 --- a/testdata/result/statement/alter_table_add_column_with_if_expression.sql.txt +++ b/testdata/result/statement/alter_table_add_column_with_if_expression.sql.txt @@ -99,7 +99,9 @@ ALTER TABLE foo ADD COLUMN expired_at TIMESTAMP AS (IF (status != "OPEN" AND sta }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, &ast.ExprArg{ @@ -108,7 +110,9 @@ ALTER TABLE foo ADD COLUMN expired_at TIMESTAMP AS (IF (status != "OPEN" AND sta }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, Options: (*ast.Options)(nil), diff --git a/testdata/result/statement/create_table.sql.txt b/testdata/result/statement/create_table.sql.txt index 523952f9..6ae97cc4 100644 --- a/testdata/result/statement/create_table.sql.txt +++ b/testdata/result/statement/create_table.sql.txt @@ -144,7 +144,9 @@ create table foo ( }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, Options: (*ast.Options)(nil), @@ -187,9 +189,11 @@ create table foo ( NameEnd: 546, Name: "current_timestamp", }, - Distinct: false, - Args: []ast.Arg(nil), - NamedArgs: []*ast.NamedArg(nil), + Distinct: false, + Args: []ast.Arg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, GeneratedExpr: (*ast.GeneratedColumnExpr)(nil), diff --git a/testdata/result/statement/create_table_with_sequence_function.sql.txt b/testdata/result/statement/create_table_with_sequence_function.sql.txt index 5025a256..f2b827cb 100644 --- a/testdata/result/statement/create_table_with_sequence_function.sql.txt +++ b/testdata/result/statement/create_table_with_sequence_function.sql.txt @@ -50,7 +50,9 @@ CREATE TABLE foo }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, GeneratedExpr: (*ast.GeneratedColumnExpr)(nil), diff --git a/testdata/result/statement/insert_with_sequence_function.sql.txt b/testdata/result/statement/insert_with_sequence_function.sql.txt index 2424b7a2..7f5a4b8d 100644 --- a/testdata/result/statement/insert_with_sequence_function.sql.txt +++ b/testdata/result/statement/insert_with_sequence_function.sql.txt @@ -45,7 +45,9 @@ INSERT INTO foo(bar) VALUES (GET_NEXT_SEQUENCE_VALUE(SEQUENCE my_sequence)) }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, }, diff --git a/testdata/result/statement/select_call_with_named_expr.sql.txt b/testdata/result/statement/select_call_with_named_expr.sql.txt index 347e5130..78d1d157 100644 --- a/testdata/result/statement/select_call_with_named_expr.sql.txt +++ b/testdata/result/statement/select_call_with_named_expr.sql.txt @@ -137,6 +137,8 @@ WHERE a.SingerId = 1 AND SEARCH(a.DescriptionTokens, 'classic albums', enhance_q }, }, }, + NullHandling: nil, + Having: nil, }, }, }, diff --git a/testdata/result/statement/select_count_distinct.sql.txt b/testdata/result/statement/select_count_distinct.sql.txt index 4cb7d986..76755e4a 100644 --- a/testdata/result/statement/select_count_distinct.sql.txt +++ b/testdata/result/statement/select_count_distinct.sql.txt @@ -27,7 +27,9 @@ select count(distinct x) from foo }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, }, diff --git a/testdata/result/statement/select_expr.sql.txt b/testdata/result/statement/select_expr.sql.txt index eeb46ce1..e6c89c30 100644 --- a/testdata/result/statement/select_expr.sql.txt +++ b/testdata/result/statement/select_expr.sql.txt @@ -617,7 +617,9 @@ select 1 + 2, 1 - 2, }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, &ast.ExprSelectItem{ @@ -655,7 +657,9 @@ select 1 + 2, 1 - 2, }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, &ast.ExprSelectItem{ @@ -899,7 +903,9 @@ select 1 + 2, 1 - 2, }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, Right: &ast.IntLiteral{ ValuePos: 790, diff --git a/testdata/result/statement/select_literals_all.sql.txt b/testdata/result/statement/select_literals_all.sql.txt index b8556bb4..3e35cc34 100644 --- a/testdata/result/statement/select_literals_all.sql.txt +++ b/testdata/result/statement/select_literals_all.sql.txt @@ -504,7 +504,9 @@ lines''', }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, &ast.ExprSelectItem{ @@ -555,7 +557,9 @@ lines''', }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, &ast.ExprSelectItem{ diff --git a/testdata/result/statement/select_literals_date.sql.txt b/testdata/result/statement/select_literals_date.sql.txt index 1ccd8fb4..fd6b3596 100644 --- a/testdata/result/statement/select_literals_date.sql.txt +++ b/testdata/result/statement/select_literals_date.sql.txt @@ -48,7 +48,9 @@ SELECT }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, &ast.ExprSelectItem{ @@ -109,7 +111,9 @@ SELECT }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, }, &ast.ExprSelectItem{ @@ -140,7 +144,9 @@ SELECT }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, As: &ast.AsAlias{ As: -1, @@ -169,7 +175,9 @@ SELECT }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, As: &ast.AsAlias{ As: -1, diff --git a/testdata/result/statement/select_with_sequence_function.sql.txt b/testdata/result/statement/select_with_sequence_function.sql.txt index 1abdadb4..491d47f0 100644 --- a/testdata/result/statement/select_with_sequence_function.sql.txt +++ b/testdata/result/statement/select_with_sequence_function.sql.txt @@ -29,7 +29,9 @@ SELECT GET_NEXT_SEQUENCE_VALUE(SEQUENCE my_sequence) as next_id }, }, }, - NamedArgs: []*ast.NamedArg(nil), + NamedArgs: []*ast.NamedArg(nil), + NullHandling: nil, + Having: nil, }, As: &ast.AsAlias{ As: -1,