Skip to content

Commit

Permalink
Implement CALL statement (#231)
Browse files Browse the repository at this point in the history
* Implement CALL statement

* Update testdata
  • Loading branch information
apstndb authored Dec 19, 2024
1 parent 9cc634e commit 31325dd
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 4 deletions.
21 changes: 21 additions & 0 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ func (DropVectorIndex) isStatement() {}
func (Insert) isStatement() {}
func (Delete) isStatement() {}
func (Update) isStatement() {}
func (Call) isStatement() {}

// QueryExpr represents query expression, which can be body of QueryStatement or subqueries.
// Select and FromQuery are leaf QueryExpr and others wrap other QueryExpr.
Expand Down Expand Up @@ -3504,3 +3505,23 @@ type UpdateItem struct {
Path []*Ident // len(Path) > 0
DefaultExpr *DefaultExpr
}

// ================================================================================
//
// Procedural language
//
// ================================================================================

// Call is CALL statement.
//
// CALL {{.Name | sql}}({{.Args | sqlJoin ", "}})
type Call struct {
// pos = Call
// end = Rparen +1

Call token.Pos
Rparen token.Pos

Name *Path
Args []TVFArg // len(Args) > 0
}
8 changes: 8 additions & 0 deletions ast/pos.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions ast/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -1194,3 +1194,13 @@ func (u *Update) SQL() string {
func (u *UpdateItem) SQL() string {
return sqlJoin(u.Path, ".") + " = " + u.DefaultExpr.SQL()
}

// ================================================================================
//
// Procedural language
//
// ================================================================================

func (c *Call) SQL() string {
return "CALL " + c.Name.SQL() + "(" + sqlJoin(c.Args, ", ") + ")"
}
35 changes: 33 additions & 2 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,41 @@ func (p *Parser) parseStatement() ast.Statement {
return p.parseDDL()
case p.Token.IsKeywordLike("INSERT") || p.Token.IsKeywordLike("DELETE") || p.Token.IsKeywordLike("UPDATE"):
return p.parseDML()
case p.Token.IsKeywordLike("CALL"):
return p.parseOtherStatement()
}

panic(p.errorfAtToken(&p.Token, "unexpected token: %s", p.Token.Kind))
}

func (p *Parser) parseOtherStatement() ast.Statement {
switch {
case p.Token.IsKeywordLike("CALL"):
return p.parseCall()
}

panic(p.errorfAtToken(&p.Token, "unexpected token: %s", p.Token.Kind))
}

func (p *Parser) parseCall() *ast.Call {
pos := p.expectKeywordLike("CALL").Pos
name := p.parsePath()
p.expect("(")

var args []ast.TVFArg
if p.Token.Kind != ")" {
args = parseCommaSeparatedList(p, p.parseTVFArg)
}

rparen := p.expect(")").Pos

return &ast.Call{
Call: pos,
Rparen: rparen,
Name: name,
Args: args,
}
}
func (p *Parser) parseStatements(doParse func()) {
for p.Token.Kind != token.TokenEOF {
if p.Token.Kind == ";" {
Expand Down Expand Up @@ -1726,7 +1756,7 @@ func (p *Parser) parseLit() ast.Expr {
p.nextToken()
switch p.Token.Kind {
case "(":
return p.parseCall(id)
return p.parseCallLike(id)
case token.TokenString:
if id.IsKeywordLike("DATE") {
return p.parseDateLiteral(id)
Expand All @@ -1751,7 +1781,8 @@ func (p *Parser) parseLit() ast.Expr {
panic(p.errorfAtToken(&p.Token, "unexpected token: %s", p.Token.Kind))
}

func (p *Parser) parseCall(id token.Token) ast.Expr {
// parseCallLike parses after identifier part of function call like structures.
func (p *Parser) parseCallLike(id token.Token) ast.Expr {
p.expect("(")
if id.IsIdent("COUNT") && p.Token.Kind == "*" {
p.nextToken()
Expand Down
6 changes: 4 additions & 2 deletions parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import (
"path/filepath"
"testing"

"github.com/k0kubun/pp/v3"
"github.com/pmezard/go-difflib/difflib"

"github.com/cloudspannerecosystem/memefish"
"github.com/cloudspannerecosystem/memefish/ast"
"github.com/cloudspannerecosystem/memefish/token"
"github.com/k0kubun/pp/v3"
"github.com/pmezard/go-difflib/difflib"
)

var update = flag.Bool("update", false, "update result files")
Expand Down Expand Up @@ -168,6 +169,7 @@ func TestParseStatement(t *testing.T) {
"./testdata/input/query",
"./testdata/input/ddl",
"./testdata/input/dml",
"./testdata/input/statement",
}
resultPath := "./testdata/result/statement"

Expand Down
1 change: 1 addition & 0 deletions testdata/input/statement/call_cancel_query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CALL cancel_query("12345")
2 changes: 2 additions & 0 deletions testdata/input/statement/call_complex_args.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- https://github.com/google/zetasql/blob/a516c6b26d183efc4f56293256bba92e243b7a61/zetasql/parser/testdata/call.test#L92C1-L93C1
call myprocedure(TABLE my.table, (SELECT * FROM my.another_table), mytvf(1, 2))
2 changes: 2 additions & 0 deletions testdata/input/statement/call_path.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- https://github.com/google/zetasql/blob/a516c6b26d183efc4f56293256bba92e243b7a61/zetasql/parser/testdata/call.test#L15C1-L15C26
call schema.myprocedure()
27 changes: 27 additions & 0 deletions testdata/result/statement/call_cancel_query.sql.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--- call_cancel_query.sql
CALL cancel_query("12345")
--- AST
&ast.Call{
Rparen: 25,
Name: &ast.Path{
Idents: []*ast.Ident{
&ast.Ident{
NamePos: 5,
NameEnd: 17,
Name: "cancel_query",
},
},
},
Args: []ast.TVFArg{
&ast.ExprArg{
Expr: &ast.StringLiteral{
ValuePos: 18,
ValueEnd: 25,
Value: "12345",
},
},
},
}

--- SQL
CALL cancel_query("12345")
100 changes: 100 additions & 0 deletions testdata/result/statement/call_complex_args.sql.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
--- call_complex_args.sql
-- https://github.com/google/zetasql/blob/a516c6b26d183efc4f56293256bba92e243b7a61/zetasql/parser/testdata/call.test#L92C1-L93C1
call myprocedure(TABLE my.table, (SELECT * FROM my.another_table), mytvf(1, 2))
--- AST
&ast.Call{
Call: 129,
Rparen: 207,
Name: &ast.Path{
Idents: []*ast.Ident{
&ast.Ident{
NamePos: 134,
NameEnd: 145,
Name: "myprocedure",
},
},
},
Args: []ast.TVFArg{
&ast.TableArg{
Table: 146,
Name: &ast.Path{
Idents: []*ast.Ident{
&ast.Ident{
NamePos: 152,
NameEnd: 154,
Name: "my",
},
&ast.Ident{
NamePos: 155,
NameEnd: 160,
Name: "table",
},
},
},
},
&ast.ExprArg{
Expr: &ast.ScalarSubQuery{
Lparen: 162,
Rparen: 193,
Query: &ast.Select{
Select: 163,
Results: []ast.SelectItem{
&ast.Star{
Star: 170,
},
},
From: &ast.From{
From: 172,
Source: &ast.PathTableExpr{
Path: &ast.Path{
Idents: []*ast.Ident{
&ast.Ident{
NamePos: 177,
NameEnd: 179,
Name: "my",
},
&ast.Ident{
NamePos: 180,
NameEnd: 193,
Name: "another_table",
},
},
},
},
},
},
},
},
&ast.ExprArg{
Expr: &ast.CallExpr{
Rparen: 206,
Func: &ast.Ident{
NamePos: 196,
NameEnd: 201,
Name: "mytvf",
},
Args: []ast.Arg{
&ast.ExprArg{
Expr: &ast.IntLiteral{
ValuePos: 202,
ValueEnd: 203,
Base: 10,
Value: "1",
},
},
&ast.ExprArg{
Expr: &ast.IntLiteral{
ValuePos: 205,
ValueEnd: 206,
Base: 10,
Value: "2",
},
},
},
},
},
},
}

--- SQL
CALL myprocedure(TABLE my.table, (SELECT * FROM my.another_table), mytvf(1, 2))
25 changes: 25 additions & 0 deletions testdata/result/statement/call_path.sql.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
--- call_path.sql
-- https://github.com/google/zetasql/blob/a516c6b26d183efc4f56293256bba92e243b7a61/zetasql/parser/testdata/call.test#L15C1-L15C26
call schema.myprocedure()
--- AST
&ast.Call{
Call: 130,
Rparen: 154,
Name: &ast.Path{
Idents: []*ast.Ident{
&ast.Ident{
NamePos: 135,
NameEnd: 141,
Name: "schema",
},
&ast.Ident{
NamePos: 142,
NameEnd: 153,
Name: "myprocedure",
},
},
},
}

--- SQL
CALL schema.myprocedure()

0 comments on commit 31325dd

Please sign in to comment.