Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(spanner/spansql): define structures and parse UPDATE DML statements #3192

Merged
merged 1 commit into from Nov 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
63 changes: 62 additions & 1 deletion spanner/spansql/parser.go
Expand Up @@ -1281,7 +1281,13 @@ func (p *parser) parseDMLStmt() (DMLStmt, *parseError) {
DELETE [FROM] target_name [[AS] alias]
WHERE condition

TODO: Insert, Update.
UPDATE target_name [[AS] alias]
SET update_item [, ...]
WHERE condition

update_item: path_expression = expression | path_expression = DEFAULT

TODO: Insert.
*/

if p.eat("DELETE") {
Expand All @@ -1304,9 +1310,64 @@ func (p *parser) parseDMLStmt() (DMLStmt, *parseError) {
}, nil
}

if p.eat("UPDATE") {
tname, err := p.parseTableOrIndexOrColumnName()
if err != nil {
return nil, err
}
u := &Update{
Table: tname,
}
// TODO: parse alias.
if err := p.expect("SET"); err != nil {
return nil, err
}
for {
ui, err := p.parseUpdateItem()
if err != nil {
return nil, err
}
u.Items = append(u.Items, ui)
if p.eat(",") {
continue
}
break
}
if err := p.expect("WHERE"); err != nil {
return nil, err
}
where, err := p.parseBoolExpr()
if err != nil {
return nil, err
}
u.Where = where
return u, nil
}

return nil, p.errorf("unknown DML statement")
}

func (p *parser) parseUpdateItem() (UpdateItem, *parseError) {
col, err := p.parseTableOrIndexOrColumnName()
if err != nil {
return UpdateItem{}, err
}
ui := UpdateItem{
Column: col,
}
if err := p.expect("="); err != nil {
return UpdateItem{}, err
}
if p.eat("DEFAULT") {
return ui, nil
dsymonds marked this conversation as resolved.
Show resolved Hide resolved
}
ui.Value, err = p.parseExpr()
if err != nil {
return UpdateItem{}, err
}
return ui, nil
}

func (p *parser) parseColumnDef() (ColumnDef, *parseError) {
debugf("parseColumnDef: %v", p)

Expand Down
17 changes: 17 additions & 0 deletions spanner/spansql/sql.go
Expand Up @@ -158,6 +158,23 @@ func (d *Delete) SQL() string {
return "DELETE FROM " + d.Table.SQL() + " WHERE " + d.Where.SQL()
}

func (u *Update) SQL() string {
str := "UPDATE " + u.Table.SQL() + " SET "
for i, item := range u.Items {
if i > 0 {
str += ", "
}
str += item.Column.SQL() + " = "
if item.Value != nil {
str += item.Value.SQL()
} else {
str += "DEFAULT"
}
}
str += " WHERE " + u.Where.SQL()
return str
}

func (cd ColumnDef) SQL() string {
str := cd.Name.SQL() + " " + cd.Type.SQL()
if cd.NotNull {
Expand Down
15 changes: 15 additions & 0 deletions spanner/spansql/sql_test.go
Expand Up @@ -232,6 +232,21 @@ func TestSQL(t *testing.T) {
"DELETE FROM Ta WHERE C > 2",
reparseDML,
},
{
&Update{
Table: "Ta",
Items: []UpdateItem{
{Column: "Cb", Value: IntegerLiteral(4)},
{Column: "Ce", Value: StringLiteral("wow")},
{Column: "Cf", Value: ID("Cg")},
{Column: "Cg", Value: Null},
{Column: "Ch", Value: nil},
dsymonds marked this conversation as resolved.
Show resolved Hide resolved
},
Where: ID("Ca"),
},
`UPDATE Ta SET Cb = 4, Ce = "wow", Cf = Cg, Cg = NULL, Ch = DEFAULT WHERE Ca`,
reparseDML,
},
{
Query{
Select: Select{
Expand Down
20 changes: 19 additions & 1 deletion spanner/spansql/types.go
Expand Up @@ -217,7 +217,25 @@ type Delete struct {
func (d *Delete) String() string { return fmt.Sprintf("%#v", d) }
func (*Delete) isDMLStmt() {}

// TODO: Insert, Update.
// TODO: Insert.

// Update represents an UPDATE statement.
// https://cloud.google.com/spanner/docs/dml-syntax#update-statement
type Update struct {
Table ID
Items []UpdateItem
Where BoolExpr

// TODO: Alias
}

func (u *Update) String() string { return fmt.Sprintf("%#v", u) }
func (*Update) isDMLStmt() {}

type UpdateItem struct {
Column ID
Value Expr // or nil for DEFAULT
}

// ColumnDef represents a column definition as part of a CREATE TABLE
// or ALTER TABLE statement.
Expand Down