diff --git a/ast/ast.go b/ast/ast.go index e13a9791..35718abc 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -3165,20 +3165,48 @@ type AlterSearchIndex struct { // // ================================================================================ +// WithAction is WITH ACTION clause in ThenReturn. +// +// WITH ACTION {{.Alias | sqlOpt}} +type WithAction struct { + // pos = With + // end = Alias.end || Action + 6 + + With token.Pos // position of "WITH" keyword + Action token.Pos // position of "ACTION" keyword + + Alias *AsAlias // optional +} + +// ThenReturn is THEN RETURN clause in DML. +// +// THEN RETURN {{.WithAction | sqlOpt}} {{.Items | sqlJoin ", "}} +type ThenReturn struct { + // pos = Then + // end = Items[$].end + + Then token.Pos // position of "THEN" keyword + + WithAction *WithAction // optional + Items []SelectItem +} + // Insert is INSERT statement node. // // INSERT {{if .InsertOrType}}OR .InsertOrType{{end}}INTO {{.TableName | sql}} ({{.Columns | sqlJoin ","}}) {{.Input | sql}} +// {{.ThenReturn | sqlOpt}} type Insert struct { // pos = Insert - // end = Input.end + // end = (ThenReturn ?? Input).end Insert token.Pos // position of "INSERT" keyword InsertOrType InsertOrType - TableName *Ident - Columns []*Ident - Input InsertInput + TableName *Ident + Columns []*Ident + Input InsertInput + ThenReturn *ThenReturn // optional } // ValuesInput is VALUES clause in INSERT. @@ -3231,31 +3259,35 @@ type SubQueryInput struct { // Delete is DELETE statement. // // DELETE FROM {{.TableName | sql}} {{.As | sqlOpt}} {{.Where | sql}} +// {{.ThenReturn | sqlOpt}} type Delete struct { // pos = Delete - // end = Where.end + // end = (ThenReturn ?? Where).end Delete token.Pos // position of "DELETE" keyword - TableName *Ident - As *AsAlias // optional - Where *Where + TableName *Ident + As *AsAlias // optional + Where *Where + ThenReturn *ThenReturn // optional } // Update is UPDATE statement. // // UPDATE {{.TableName | sql}} {{.As | sqlOpt}} // SET {{.Updates | sqlJoin ","}} {{.Where | sql}} +// {{.ThenReturn | sqlOpt}} type Update struct { // pos = Update - // end = Where.end + // end = (ThenReturn ?? Where).end Update token.Pos // position of "UPDATE" keyword - TableName *Ident - As *AsAlias // optional - Updates []*UpdateItem // len(Updates) > 0 - Where *Where + TableName *Ident + As *AsAlias // optional + Updates []*UpdateItem // len(Updates) > 0 + Where *Where + ThenReturn *ThenReturn // optional } // UpdateItem is SET clause items in UPDATE. diff --git a/ast/pos.go b/ast/pos.go index c6cc1f4b..7b7a108c 100644 --- a/ast/pos.go +++ b/ast/pos.go @@ -1590,12 +1590,28 @@ func (a *AlterSearchIndex) End() token.Pos { return nodeEnd(wrapNode(a.IndexAlteration)) } +func (w *WithAction) Pos() token.Pos { + return w.With +} + +func (w *WithAction) End() token.Pos { + return posChoice(nodeEnd(wrapNode(w.Alias)), posAdd(w.Action, 6)) +} + +func (t *ThenReturn) Pos() token.Pos { + return t.Then +} + +func (t *ThenReturn) End() token.Pos { + return nodeEnd(nodeSliceLast(t.Items)) +} + func (i *Insert) Pos() token.Pos { return i.Insert } func (i *Insert) End() token.Pos { - return nodeEnd(wrapNode(i.Input)) + return nodeEnd(nodeChoice(wrapNode(i.ThenReturn), wrapNode(i.Input))) } func (v *ValuesInput) Pos() token.Pos { @@ -1635,7 +1651,7 @@ func (d *Delete) Pos() token.Pos { } func (d *Delete) End() token.Pos { - return nodeEnd(wrapNode(d.Where)) + return nodeEnd(nodeChoice(wrapNode(d.ThenReturn), wrapNode(d.Where))) } func (u *Update) Pos() token.Pos { @@ -1643,7 +1659,7 @@ func (u *Update) Pos() token.Pos { } func (u *Update) End() token.Pos { - return nodeEnd(wrapNode(u.Where)) + return nodeEnd(nodeChoice(wrapNode(u.ThenReturn), wrapNode(u.Where))) } func (u *UpdateItem) Pos() token.Pos { diff --git a/ast/sql.go b/ast/sql.go index fa8caaf2..eedd404a 100644 --- a/ast/sql.go +++ b/ast/sql.go @@ -1385,20 +1385,22 @@ func (a *AlterSearchIndex) SQL() string { // // ================================================================================ +func (w *WithAction) SQL() string { + return "WITH ACTION" + sqlOpt(" ", w.Alias, "") +} + +func (t *ThenReturn) SQL() string { + return "THEN RETURN " + sqlOpt("", t.WithAction, " ") + sqlJoin(t.Items, ", ") +} + func (i *Insert) SQL() string { - sql := "INSERT " - if i.InsertOrType != "" { - sql += "OR " + string(i.InsertOrType) + " " - } - sql += "INTO " + i.TableName.SQL() + " (" - for i, c := range i.Columns { - if i != 0 { - sql += ", " - } - sql += c.SQL() - } - sql += ") " + i.Input.SQL() - return sql + return "INSERT " + + strOpt(i.InsertOrType != "", "OR "+string(i.InsertOrType)+" ") + + "INTO " + i.TableName.SQL() + " (" + + sqlJoin(i.Columns, ", ") + + ") " + + i.Input.SQL() + + sqlOpt(" ", i.ThenReturn, "") } func (v *ValuesInput) SQL() string { @@ -1436,25 +1438,20 @@ func (s *SubQueryInput) SQL() string { } func (d *Delete) SQL() string { - sql := "DELETE FROM " + d.TableName.SQL() - if d.As != nil { - sql += " " + d.As.SQL() - } - sql += " " + d.Where.SQL() - return sql + return "DELETE FROM " + + d.TableName.SQL() + " " + + sqlOpt("", d.As, " ") + + d.Where.SQL() + + sqlOpt(" ", d.ThenReturn, "") } func (u *Update) SQL() string { - sql := "UPDATE " + u.TableName.SQL() - if u.As != nil { - sql += " " + u.As.SQL() - } - sql += " SET " + u.Updates[0].SQL() - for _, item := range u.Updates[1:] { - sql += ", " + item.SQL() - } - sql += " " + u.Where.SQL() - return sql + return "UPDATE " + u.TableName.SQL() + " " + + sqlOpt("", u.As, " ") + + "SET " + + sqlJoin(u.Updates, ", ") + + " " + u.Where.SQL() + + sqlOpt(" ", u.ThenReturn, "") } func (u *UpdateItem) SQL() string { diff --git a/parser.go b/parser.go index 72f17544..40a3d9a6 100644 --- a/parser.go +++ b/parser.go @@ -4124,6 +4124,39 @@ func (p *Parser) parseDML() ast.DML { panic(p.errorfAtToken(id, "expect pseudo keyword: INSERT, DELETE, UPDATE but: %s", id.AsString)) } +func (p *Parser) tryParseWithAction() *ast.WithAction { + if p.Token.Kind != "WITH" { + return nil + } + + with := p.expect("WITH").Pos + action := p.expectKeywordLike("ACTION").Pos + alias := p.tryParseAsAlias(withRequiredAs) + + return &ast.WithAction{ + With: with, + Action: action, + Alias: alias, + } +} + +func (p *Parser) tryParseThenReturn() *ast.ThenReturn { + if p.Token.Kind != "THEN" { + return nil + } + + then := p.expect("THEN").Pos + p.expectKeywordLike("RETURN") + withAction := p.tryParseWithAction() + items := parseCommaSeparatedList(p, p.parseSelectItem) + + return &ast.ThenReturn{ + Then: then, + WithAction: withAction, + Items: items, + } +} + func (p *Parser) parseInsert(pos token.Pos) *ast.Insert { var insertOrType ast.InsertOrType if p.Token.Kind == "OR" { @@ -4165,12 +4198,15 @@ func (p *Parser) parseInsert(pos token.Pos) *ast.Insert { input = p.parseSubQueryInput() } + thenReturn := p.tryParseThenReturn() + return &ast.Insert{ Insert: pos, InsertOrType: insertOrType, TableName: name, Columns: columns, Input: input, + ThenReturn: thenReturn, } } @@ -4238,12 +4274,14 @@ func (p *Parser) parseDelete(pos token.Pos) *ast.Delete { name := p.parseIdent() as := p.tryParseAsAlias(withOptionalAs) where := p.parseWhere() + thenReturn := p.tryParseThenReturn() return &ast.Delete{ - Delete: pos, - TableName: name, - As: as, - Where: where, + Delete: pos, + TableName: name, + As: as, + Where: where, + ThenReturn: thenReturn, } } @@ -4256,13 +4294,15 @@ func (p *Parser) parseUpdate(pos token.Pos) *ast.Update { items := parseCommaSeparatedList(p, p.parseUpdateItem) where := p.parseWhere() + thenReturn := p.tryParseThenReturn() return &ast.Update{ - Update: pos, - TableName: name, - As: as, - Updates: items, - Where: where, + Update: pos, + TableName: name, + As: as, + Updates: items, + Where: where, + ThenReturn: thenReturn, } } diff --git a/testdata/input/dml/delete_then_return.sql b/testdata/input/dml/delete_then_return.sql new file mode 100644 index 00000000..4bbf277e --- /dev/null +++ b/testdata/input/dml/delete_then_return.sql @@ -0,0 +1 @@ +delete foo where foo = 1 and bar = 2 then return * \ No newline at end of file diff --git a/testdata/input/dml/insert_or_update_then_return_with_action_as.sql b/testdata/input/dml/insert_or_update_then_return_with_action_as.sql new file mode 100644 index 00000000..efb81ae3 --- /dev/null +++ b/testdata/input/dml/insert_or_update_then_return_with_action_as.sql @@ -0,0 +1,3 @@ +INSERT OR UPDATE INTO foo +(foo, bar) VALUES (1, 2) +THEN RETURN WITH ACTION AS act * \ No newline at end of file diff --git a/testdata/input/dml/update_then_return_with_action.sql b/testdata/input/dml/update_then_return_with_action.sql new file mode 100644 index 00000000..696d7db4 --- /dev/null +++ b/testdata/input/dml/update_then_return_with_action.sql @@ -0,0 +1 @@ +update foo set foo = bar, bar = foo, baz = DEFAULT where foo = 1 then return with action * \ No newline at end of file diff --git a/testdata/result/dml/delete _from.sql.txt b/testdata/result/dml/delete _from.sql.txt index c9972ae3..29eddeae 100644 --- a/testdata/result/dml/delete _from.sql.txt +++ b/testdata/result/dml/delete _from.sql.txt @@ -43,6 +43,7 @@ delete from foo where foo = 1 and bar = 2 }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/dml/delete.sql.txt b/testdata/result/dml/delete.sql.txt index b5ec82a5..1bf07ded 100644 --- a/testdata/result/dml/delete.sql.txt +++ b/testdata/result/dml/delete.sql.txt @@ -43,6 +43,7 @@ delete foo where foo = 1 and bar = 2 }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/dml/delete_as.sql.txt b/testdata/result/dml/delete_as.sql.txt index 2eee871a..36c330e3 100644 --- a/testdata/result/dml/delete_as.sql.txt +++ b/testdata/result/dml/delete_as.sql.txt @@ -42,6 +42,7 @@ delete foo as F where F.foo = 1 }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/dml/delete_then_return.sql.txt b/testdata/result/dml/delete_then_return.sql.txt new file mode 100644 index 00000000..94b742a1 --- /dev/null +++ b/testdata/result/dml/delete_then_return.sql.txt @@ -0,0 +1,58 @@ +--- delete_then_return.sql +delete foo where foo = 1 and bar = 2 then return * +--- AST +&ast.Delete{ + Delete: 0, + TableName: &ast.Ident{ + NamePos: 7, + NameEnd: 10, + Name: "foo", + }, + As: (*ast.AsAlias)(nil), + Where: &ast.Where{ + Where: 11, + Expr: &ast.BinaryExpr{ + Op: "AND", + Left: &ast.BinaryExpr{ + Op: "=", + Left: &ast.Ident{ + NamePos: 17, + NameEnd: 20, + Name: "foo", + }, + Right: &ast.IntLiteral{ + ValuePos: 23, + ValueEnd: 24, + Base: 10, + Value: "1", + }, + }, + Right: &ast.BinaryExpr{ + Op: "=", + Left: &ast.Ident{ + NamePos: 29, + NameEnd: 32, + Name: "bar", + }, + Right: &ast.IntLiteral{ + ValuePos: 35, + ValueEnd: 36, + Base: 10, + Value: "2", + }, + }, + }, + }, + ThenReturn: &ast.ThenReturn{ + Then: 37, + WithAction: (*ast.WithAction)(nil), + Items: []ast.SelectItem{ + &ast.Star{ + Star: 49, + }, + }, + }, +} + +--- SQL +DELETE FROM foo WHERE foo = 1 AND bar = 2 THEN RETURN * diff --git a/testdata/result/dml/insert_into_values.sql.txt b/testdata/result/dml/insert_into_values.sql.txt index 047a68ed..dc897ce3 100644 --- a/testdata/result/dml/insert_into_values.sql.txt +++ b/testdata/result/dml/insert_into_values.sql.txt @@ -105,6 +105,7 @@ values (1, 2, 3), }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/dml/insert_or_ignore.sql.txt b/testdata/result/dml/insert_or_ignore.sql.txt index 28adbf40..9994ff8e 100644 --- a/testdata/result/dml/insert_or_ignore.sql.txt +++ b/testdata/result/dml/insert_or_ignore.sql.txt @@ -53,6 +53,7 @@ INSERT OR IGNORE INTO foo }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/dml/insert_or_update.sql.txt b/testdata/result/dml/insert_or_update.sql.txt index fbda7b80..a87b61f8 100644 --- a/testdata/result/dml/insert_or_update.sql.txt +++ b/testdata/result/dml/insert_or_update.sql.txt @@ -53,6 +53,7 @@ INSERT OR UPDATE INTO foo }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/dml/insert_or_update_then_return_with_action_as.sql.txt b/testdata/result/dml/insert_or_update_then_return_with_action_as.sql.txt new file mode 100644 index 00000000..ab5e4a6d --- /dev/null +++ b/testdata/result/dml/insert_or_update_then_return_with_action_as.sql.txt @@ -0,0 +1,80 @@ +--- insert_or_update_then_return_with_action_as.sql +INSERT OR UPDATE INTO foo +(foo, bar) VALUES (1, 2) +THEN RETURN WITH ACTION AS act * +--- AST +&ast.Insert{ + Insert: 0, + InsertOrType: "UPDATE", + TableName: &ast.Ident{ + NamePos: 22, + NameEnd: 25, + Name: "foo", + }, + Columns: []*ast.Ident{ + &ast.Ident{ + NamePos: 27, + NameEnd: 30, + Name: "foo", + }, + &ast.Ident{ + NamePos: 32, + NameEnd: 35, + Name: "bar", + }, + }, + Input: &ast.ValuesInput{ + Values: 37, + Rows: []*ast.ValuesRow{ + &ast.ValuesRow{ + Lparen: 44, + Rparen: 49, + Exprs: []*ast.DefaultExpr{ + &ast.DefaultExpr{ + DefaultPos: -1, + Default: false, + Expr: &ast.IntLiteral{ + ValuePos: 45, + ValueEnd: 46, + Base: 10, + Value: "1", + }, + }, + &ast.DefaultExpr{ + DefaultPos: -1, + Default: false, + Expr: &ast.IntLiteral{ + ValuePos: 48, + ValueEnd: 49, + Base: 10, + Value: "2", + }, + }, + }, + }, + }, + }, + ThenReturn: &ast.ThenReturn{ + Then: 51, + WithAction: &ast.WithAction{ + With: 63, + Action: 68, + Alias: &ast.AsAlias{ + As: 75, + Alias: &ast.Ident{ + NamePos: 78, + NameEnd: 81, + Name: "act", + }, + }, + }, + Items: []ast.SelectItem{ + &ast.Star{ + Star: 82, + }, + }, + }, +} + +--- SQL +INSERT OR UPDATE INTO foo (foo, bar) VALUES (1, 2) THEN RETURN WITH ACTION AS act * diff --git a/testdata/result/dml/insert_select.sql.txt b/testdata/result/dml/insert_select.sql.txt index 6afe8c7c..5b3b5590 100644 --- a/testdata/result/dml/insert_select.sql.txt +++ b/testdata/result/dml/insert_select.sql.txt @@ -94,6 +94,7 @@ select * from unnest([(1, 2), (3, 4)]) Limit: (*ast.Limit)(nil), }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/dml/insert_values.sql.txt b/testdata/result/dml/insert_values.sql.txt index 09897f47..aae84cad 100644 --- a/testdata/result/dml/insert_values.sql.txt +++ b/testdata/result/dml/insert_values.sql.txt @@ -105,6 +105,7 @@ values (1, 2, 3), }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/dml/insert_values_default.sql.txt b/testdata/result/dml/insert_values_default.sql.txt index ae7d07c4..2b3b0083 100644 --- a/testdata/result/dml/insert_values_default.sql.txt +++ b/testdata/result/dml/insert_values_default.sql.txt @@ -48,6 +48,7 @@ values (1, default) }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/dml/insert_with_sequence_function.sql.txt b/testdata/result/dml/insert_with_sequence_function.sql.txt index 7f5a4b8d..c78a7cd4 100644 --- a/testdata/result/dml/insert_with_sequence_function.sql.txt +++ b/testdata/result/dml/insert_with_sequence_function.sql.txt @@ -54,6 +54,7 @@ INSERT INTO foo(bar) VALUES (GET_NEXT_SEQUENCE_VALUE(SEQUENCE my_sequence)) }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/dml/update.sql.txt b/testdata/result/dml/update.sql.txt index 8f218958..fcf32946 100644 --- a/testdata/result/dml/update.sql.txt +++ b/testdata/result/dml/update.sql.txt @@ -78,6 +78,7 @@ update foo set foo = bar, bar = foo, baz = DEFAULT where foo = 1 }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/dml/update_as.sql.txt b/testdata/result/dml/update_as.sql.txt index a647ea85..00622578 100644 --- a/testdata/result/dml/update_as.sql.txt +++ b/testdata/result/dml/update_as.sql.txt @@ -84,6 +84,7 @@ update foo as F set F.foo = F.bar + 1 where foo = F.bar }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/dml/update_then_return_with_action.sql.txt b/testdata/result/dml/update_then_return_with_action.sql.txt new file mode 100644 index 00000000..438a476f --- /dev/null +++ b/testdata/result/dml/update_then_return_with_action.sql.txt @@ -0,0 +1,97 @@ +--- update_then_return_with_action.sql +update foo set foo = bar, bar = foo, baz = DEFAULT where foo = 1 then return with action * +--- AST +&ast.Update{ + Update: 0, + TableName: &ast.Ident{ + NamePos: 7, + NameEnd: 10, + Name: "foo", + }, + As: (*ast.AsAlias)(nil), + Updates: []*ast.UpdateItem{ + &ast.UpdateItem{ + Path: []*ast.Ident{ + &ast.Ident{ + NamePos: 15, + NameEnd: 18, + Name: "foo", + }, + }, + DefaultExpr: &ast.DefaultExpr{ + DefaultPos: -1, + Default: false, + Expr: &ast.Ident{ + NamePos: 21, + NameEnd: 24, + Name: "bar", + }, + }, + }, + &ast.UpdateItem{ + Path: []*ast.Ident{ + &ast.Ident{ + NamePos: 26, + NameEnd: 29, + Name: "bar", + }, + }, + DefaultExpr: &ast.DefaultExpr{ + DefaultPos: -1, + Default: false, + Expr: &ast.Ident{ + NamePos: 32, + NameEnd: 35, + Name: "foo", + }, + }, + }, + &ast.UpdateItem{ + Path: []*ast.Ident{ + &ast.Ident{ + NamePos: 37, + NameEnd: 40, + Name: "baz", + }, + }, + DefaultExpr: &ast.DefaultExpr{ + DefaultPos: 43, + Default: true, + Expr: nil, + }, + }, + }, + Where: &ast.Where{ + Where: 51, + Expr: &ast.BinaryExpr{ + Op: "=", + Left: &ast.Ident{ + NamePos: 57, + NameEnd: 60, + Name: "foo", + }, + Right: &ast.IntLiteral{ + ValuePos: 63, + ValueEnd: 64, + Base: 10, + Value: "1", + }, + }, + }, + ThenReturn: &ast.ThenReturn{ + Then: 65, + WithAction: &ast.WithAction{ + With: 77, + Action: 82, + Alias: (*ast.AsAlias)(nil), + }, + Items: []ast.SelectItem{ + &ast.Star{ + Star: 89, + }, + }, + }, +} + +--- SQL +UPDATE foo SET foo = bar, bar = foo, baz = DEFAULT WHERE foo = 1 THEN RETURN WITH ACTION * diff --git a/testdata/result/statement/delete _from.sql.txt b/testdata/result/statement/delete _from.sql.txt index c9972ae3..29eddeae 100644 --- a/testdata/result/statement/delete _from.sql.txt +++ b/testdata/result/statement/delete _from.sql.txt @@ -43,6 +43,7 @@ delete from foo where foo = 1 and bar = 2 }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/statement/delete.sql.txt b/testdata/result/statement/delete.sql.txt index b5ec82a5..1bf07ded 100644 --- a/testdata/result/statement/delete.sql.txt +++ b/testdata/result/statement/delete.sql.txt @@ -43,6 +43,7 @@ delete foo where foo = 1 and bar = 2 }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/statement/delete_as.sql.txt b/testdata/result/statement/delete_as.sql.txt index 2eee871a..36c330e3 100644 --- a/testdata/result/statement/delete_as.sql.txt +++ b/testdata/result/statement/delete_as.sql.txt @@ -42,6 +42,7 @@ delete foo as F where F.foo = 1 }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/statement/delete_then_return.sql.txt b/testdata/result/statement/delete_then_return.sql.txt new file mode 100644 index 00000000..94b742a1 --- /dev/null +++ b/testdata/result/statement/delete_then_return.sql.txt @@ -0,0 +1,58 @@ +--- delete_then_return.sql +delete foo where foo = 1 and bar = 2 then return * +--- AST +&ast.Delete{ + Delete: 0, + TableName: &ast.Ident{ + NamePos: 7, + NameEnd: 10, + Name: "foo", + }, + As: (*ast.AsAlias)(nil), + Where: &ast.Where{ + Where: 11, + Expr: &ast.BinaryExpr{ + Op: "AND", + Left: &ast.BinaryExpr{ + Op: "=", + Left: &ast.Ident{ + NamePos: 17, + NameEnd: 20, + Name: "foo", + }, + Right: &ast.IntLiteral{ + ValuePos: 23, + ValueEnd: 24, + Base: 10, + Value: "1", + }, + }, + Right: &ast.BinaryExpr{ + Op: "=", + Left: &ast.Ident{ + NamePos: 29, + NameEnd: 32, + Name: "bar", + }, + Right: &ast.IntLiteral{ + ValuePos: 35, + ValueEnd: 36, + Base: 10, + Value: "2", + }, + }, + }, + }, + ThenReturn: &ast.ThenReturn{ + Then: 37, + WithAction: (*ast.WithAction)(nil), + Items: []ast.SelectItem{ + &ast.Star{ + Star: 49, + }, + }, + }, +} + +--- SQL +DELETE FROM foo WHERE foo = 1 AND bar = 2 THEN RETURN * diff --git a/testdata/result/statement/insert_into_values.sql.txt b/testdata/result/statement/insert_into_values.sql.txt index 047a68ed..dc897ce3 100644 --- a/testdata/result/statement/insert_into_values.sql.txt +++ b/testdata/result/statement/insert_into_values.sql.txt @@ -105,6 +105,7 @@ values (1, 2, 3), }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/statement/insert_or_ignore.sql.txt b/testdata/result/statement/insert_or_ignore.sql.txt index 28adbf40..9994ff8e 100644 --- a/testdata/result/statement/insert_or_ignore.sql.txt +++ b/testdata/result/statement/insert_or_ignore.sql.txt @@ -53,6 +53,7 @@ INSERT OR IGNORE INTO foo }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/statement/insert_or_update.sql.txt b/testdata/result/statement/insert_or_update.sql.txt index fbda7b80..a87b61f8 100644 --- a/testdata/result/statement/insert_or_update.sql.txt +++ b/testdata/result/statement/insert_or_update.sql.txt @@ -53,6 +53,7 @@ INSERT OR UPDATE INTO foo }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/statement/insert_or_update_then_return_with_action_as.sql.txt b/testdata/result/statement/insert_or_update_then_return_with_action_as.sql.txt new file mode 100644 index 00000000..ab5e4a6d --- /dev/null +++ b/testdata/result/statement/insert_or_update_then_return_with_action_as.sql.txt @@ -0,0 +1,80 @@ +--- insert_or_update_then_return_with_action_as.sql +INSERT OR UPDATE INTO foo +(foo, bar) VALUES (1, 2) +THEN RETURN WITH ACTION AS act * +--- AST +&ast.Insert{ + Insert: 0, + InsertOrType: "UPDATE", + TableName: &ast.Ident{ + NamePos: 22, + NameEnd: 25, + Name: "foo", + }, + Columns: []*ast.Ident{ + &ast.Ident{ + NamePos: 27, + NameEnd: 30, + Name: "foo", + }, + &ast.Ident{ + NamePos: 32, + NameEnd: 35, + Name: "bar", + }, + }, + Input: &ast.ValuesInput{ + Values: 37, + Rows: []*ast.ValuesRow{ + &ast.ValuesRow{ + Lparen: 44, + Rparen: 49, + Exprs: []*ast.DefaultExpr{ + &ast.DefaultExpr{ + DefaultPos: -1, + Default: false, + Expr: &ast.IntLiteral{ + ValuePos: 45, + ValueEnd: 46, + Base: 10, + Value: "1", + }, + }, + &ast.DefaultExpr{ + DefaultPos: -1, + Default: false, + Expr: &ast.IntLiteral{ + ValuePos: 48, + ValueEnd: 49, + Base: 10, + Value: "2", + }, + }, + }, + }, + }, + }, + ThenReturn: &ast.ThenReturn{ + Then: 51, + WithAction: &ast.WithAction{ + With: 63, + Action: 68, + Alias: &ast.AsAlias{ + As: 75, + Alias: &ast.Ident{ + NamePos: 78, + NameEnd: 81, + Name: "act", + }, + }, + }, + Items: []ast.SelectItem{ + &ast.Star{ + Star: 82, + }, + }, + }, +} + +--- SQL +INSERT OR UPDATE INTO foo (foo, bar) VALUES (1, 2) THEN RETURN WITH ACTION AS act * diff --git a/testdata/result/statement/insert_select.sql.txt b/testdata/result/statement/insert_select.sql.txt index 6afe8c7c..5b3b5590 100644 --- a/testdata/result/statement/insert_select.sql.txt +++ b/testdata/result/statement/insert_select.sql.txt @@ -94,6 +94,7 @@ select * from unnest([(1, 2), (3, 4)]) Limit: (*ast.Limit)(nil), }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/statement/insert_values.sql.txt b/testdata/result/statement/insert_values.sql.txt index 09897f47..aae84cad 100644 --- a/testdata/result/statement/insert_values.sql.txt +++ b/testdata/result/statement/insert_values.sql.txt @@ -105,6 +105,7 @@ values (1, 2, 3), }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/statement/insert_values_default.sql.txt b/testdata/result/statement/insert_values_default.sql.txt index ae7d07c4..2b3b0083 100644 --- a/testdata/result/statement/insert_values_default.sql.txt +++ b/testdata/result/statement/insert_values_default.sql.txt @@ -48,6 +48,7 @@ values (1, default) }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/statement/insert_with_sequence_function.sql.txt b/testdata/result/statement/insert_with_sequence_function.sql.txt index 7f5a4b8d..c78a7cd4 100644 --- a/testdata/result/statement/insert_with_sequence_function.sql.txt +++ b/testdata/result/statement/insert_with_sequence_function.sql.txt @@ -54,6 +54,7 @@ INSERT INTO foo(bar) VALUES (GET_NEXT_SEQUENCE_VALUE(SEQUENCE my_sequence)) }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/statement/update.sql.txt b/testdata/result/statement/update.sql.txt index 8f218958..fcf32946 100644 --- a/testdata/result/statement/update.sql.txt +++ b/testdata/result/statement/update.sql.txt @@ -78,6 +78,7 @@ update foo set foo = bar, bar = foo, baz = DEFAULT where foo = 1 }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/statement/update_as.sql.txt b/testdata/result/statement/update_as.sql.txt index a647ea85..00622578 100644 --- a/testdata/result/statement/update_as.sql.txt +++ b/testdata/result/statement/update_as.sql.txt @@ -84,6 +84,7 @@ update foo as F set F.foo = F.bar + 1 where foo = F.bar }, }, }, + ThenReturn: (*ast.ThenReturn)(nil), } --- SQL diff --git a/testdata/result/statement/update_then_return_with_action.sql.txt b/testdata/result/statement/update_then_return_with_action.sql.txt new file mode 100644 index 00000000..438a476f --- /dev/null +++ b/testdata/result/statement/update_then_return_with_action.sql.txt @@ -0,0 +1,97 @@ +--- update_then_return_with_action.sql +update foo set foo = bar, bar = foo, baz = DEFAULT where foo = 1 then return with action * +--- AST +&ast.Update{ + Update: 0, + TableName: &ast.Ident{ + NamePos: 7, + NameEnd: 10, + Name: "foo", + }, + As: (*ast.AsAlias)(nil), + Updates: []*ast.UpdateItem{ + &ast.UpdateItem{ + Path: []*ast.Ident{ + &ast.Ident{ + NamePos: 15, + NameEnd: 18, + Name: "foo", + }, + }, + DefaultExpr: &ast.DefaultExpr{ + DefaultPos: -1, + Default: false, + Expr: &ast.Ident{ + NamePos: 21, + NameEnd: 24, + Name: "bar", + }, + }, + }, + &ast.UpdateItem{ + Path: []*ast.Ident{ + &ast.Ident{ + NamePos: 26, + NameEnd: 29, + Name: "bar", + }, + }, + DefaultExpr: &ast.DefaultExpr{ + DefaultPos: -1, + Default: false, + Expr: &ast.Ident{ + NamePos: 32, + NameEnd: 35, + Name: "foo", + }, + }, + }, + &ast.UpdateItem{ + Path: []*ast.Ident{ + &ast.Ident{ + NamePos: 37, + NameEnd: 40, + Name: "baz", + }, + }, + DefaultExpr: &ast.DefaultExpr{ + DefaultPos: 43, + Default: true, + Expr: nil, + }, + }, + }, + Where: &ast.Where{ + Where: 51, + Expr: &ast.BinaryExpr{ + Op: "=", + Left: &ast.Ident{ + NamePos: 57, + NameEnd: 60, + Name: "foo", + }, + Right: &ast.IntLiteral{ + ValuePos: 63, + ValueEnd: 64, + Base: 10, + Value: "1", + }, + }, + }, + ThenReturn: &ast.ThenReturn{ + Then: 65, + WithAction: &ast.WithAction{ + With: 77, + Action: 82, + Alias: (*ast.AsAlias)(nil), + }, + Items: []ast.SelectItem{ + &ast.Star{ + Star: 89, + }, + }, + }, +} + +--- SQL +UPDATE foo SET foo = bar, bar = foo, baz = DEFAULT WHERE foo = 1 THEN RETURN WITH ACTION *