Repository: cloudspannerecosystem/memefish
Pull request #112 (2024-09-22 07:06:03)

Add Pos, End to SplitRawStatements()
It changes `SplitRawStatements()` result to struct and add `Pos`, `End`.
This decision is talked in GCPUG Slack `#memefish` channel.
https://gcpug.slack.com/archives/C0518HUTECE/p1726919315091699 (This private link will be expired because Slack community plan)

It is a breaking change of exported function, but it is permitted beause memefish has no release `v0.0.0` software.


Patch:
diff --git a/ast/ast.go b/ast/ast.go
index a58895c..4614f24 100644
--- a/ast/ast.go
+++ b/ast/ast.go
@@ -154,6 +154,7 @@ func (BytesLiteral) isExpr()     {}
 func (DateLiteral) isExpr()      {}
 func (TimestampLiteral) isExpr() {}
 func (NumericLiteral) isExpr()   {}
+func (JSONLiteral) isExpr()      {}
 
 // Arg represents argument of function call.
 type Arg interface {
@@ -944,16 +945,17 @@ type IndexExpr struct {
 
 // CallExpr is function call expression node.
 //
-//	{{.Func | sql}}({{if .Distinct}}DISTINCT{{end}} {{.Args | sql}})
+//	{{.Func | sql}}({{if .Distinct}}DISTINCT{{end}} {{.Args | sqlJoin ", "}}{{if len(.Args) > 0 && len(.NamedArgs) > 0}}, {{end}}{{.NamedArgs || sqlJoin ", "}})
 type CallExpr struct {
 	// pos = Func.pos
 	// end = Rparen + 1
 
 	Rparen token.Pos // position of ")"
 
-	Func     *Ident
-	Distinct bool
-	Args     []Arg
+	Func      *Ident
+	Distinct  bool
+	Args      []Arg
+	NamedArgs []*NamedArg
 }
 
 // ExprArg is argument of the generic function call.
@@ -991,6 +993,17 @@ type SequenceArg struct {
 	Expr Expr
 }
 
+// NamedArg represents a name and value pair in named arguments
+//
+//	{{.Name | sql}} => {{.Value | sql}}
+type NamedArg struct {
+	// pos = Name.pos
+	// end = Value.end
+
+	Name  *Ident
+	Value Expr
+}
+
 // CountStarExpr is node just for COUNT(*).
 //
 //	COUNT(*)
@@ -1312,6 +1325,18 @@ type NumericLiteral struct {
 	Value *StringLiteral
 }
 
+// JSONLiteral is JSON literal node.
+//
+//	JSON {{.Value | sql}}
+type JSONLiteral struct {
+	// pos = JSON
+	// end = ValueEnd.end
+
+	JSON token.Pos // position of "JSON"
+
+	Value *StringLiteral
+}
+
 // ================================================================================
 //
 // Type
diff --git a/ast/const.go b/ast/const.go
index 7d1ae6f..9ea04b1 100644
--- a/ast/const.go
+++ b/ast/const.go
@@ -108,6 +108,7 @@ const (
 	DateTypeName      ScalarTypeName = "DATE"
 	TimestampTypeName ScalarTypeName = "TIMESTAMP"
 	NumericTypeName   ScalarTypeName = "NUMERIC"
+	JSONTypeName      ScalarTypeName = "JSON"
 )
 
 type OnDeleteAction string
diff --git a/ast/pos.go b/ast/pos.go
index ad28dca..4e3ebb3 100644
--- a/ast/pos.go
+++ b/ast/pos.go
@@ -328,6 +328,9 @@ func (i *IntervalArg) End() token.Pos {
 func (s *SequenceArg) Pos() token.Pos { return s.Sequence }
 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 (c *CountStarExpr) Pos() token.Pos { return c.Count }
 func (c *CountStarExpr) End() token.Pos { return c.Rparen + 1 }
 
@@ -434,6 +437,9 @@ func (t *TimestampLiteral) End() token.Pos { return t.Value.End() }
 func (t *NumericLiteral) Pos() token.Pos { return t.Numeric }
 func (t *NumericLiteral) End() token.Pos { return t.Value.End() }
 
+func (t *JSONLiteral) Pos() token.Pos { return t.JSON }
+func (t *JSONLiteral) End() token.Pos { return t.Value.End() }
+
 // ================================================================================
 //
 // Type
diff --git a/ast/sql.go b/ast/sql.go
index 8c3fdad..ad5e719 100644
--- a/ast/sql.go
+++ b/ast/sql.go
@@ -474,10 +474,21 @@ func (c *CallExpr) SQL() string {
 		}
 		sql += a.SQL()
 	}
+	if len(c.Args) > 0 && len(c.NamedArgs) > 0 {
+		sql += ", "
+	}
+	for i, v := range c.NamedArgs {
+		if i != 0 {
+			sql += ", "
+		}
+		sql += v.SQL()
+	}
 	sql += ")"
 	return sql
 }
 
+func (n *NamedArg) SQL() string { return n.Name.SQL() + " => " + n.Value.SQL() }
+
 func (o *SequenceOption) SQL() string {
 	return o.Name.SQL() + " = " + o.Value.SQL()
 }
@@ -670,6 +681,10 @@ func (t *NumericLiteral) SQL() string {
 	return "NUMERIC " + t.Value.SQL()
 }
 
+func (t *JSONLiteral) SQL() string {
+	return "JSON " + t.Value.SQL()
+}
+
 // ================================================================================
 //
 // Type
diff --git a/lexer.go b/lexer.go
index 7612ce1..26d679b 100644
--- a/lexer.go
+++ b/lexer.go
@@ -109,7 +109,7 @@ func (l *Lexer) consumeToken() {
 	}
 
 	switch l.peek(0) {
-	case '(', ')', '{', '}', ';', ',', '[', ']', '~', '*', '/', '&', '^', '=', '+', '-':
+	case '(', ')', '{', '}', ';', ',', '[', ']', '~', '*', '/', '&', '^', '+', '-':
 		l.Token.Kind = token.TokenKind([]byte{l.skip()})
 		return
 	case '.':
@@ -151,6 +151,16 @@ func (l *Lexer) consumeToken() {
 			l.Token.Kind = ">"
 		}
 		return
+	case '=':
+		switch {
+		case l.peekIs(1, '>'):
+			l.skipN(2)
+			l.Token.Kind = "=>"
+		default:
+			l.skip()
+			l.Token.Kind = "="
+		}
+		return
 	case '|':
 		switch {
 		case l.peekIs(1, '|'):
diff --git a/parser.go b/parser.go
index fb5473c..b13a461 100644
--- a/parser.go
+++ b/parser.go
@@ -1424,6 +1424,9 @@ func (p *Parser) parseLit() ast.Expr {
 			if id.IsKeywordLike("NUMERIC") {
 				return p.parseNumericLiteral(id)
 			}
+			if id.IsKeywordLike("JSON") {
+				return p.parseJSONLiteral(id)
+			}
 		}
 		return &ast.Ident{
 			NamePos: id.Pos,
@@ -1460,7 +1463,7 @@ func (p *Parser) parseCall(id token.Token) ast.Expr {
 
 	var args []ast.Arg
 	if p.Token.Kind != ")" {
-		for p.Token.Kind != token.TokenEOF {
+		for p.Token.Kind != token.TokenEOF && !p.lookaheadNamedArg() {
 			args = append(args, p.parseArg())
 			if p.Token.Kind != "," {
 				break
@@ -1468,12 +1471,54 @@ func (p *Parser) parseCall(id token.Token) ast.Expr {
 			p.nextToken()
 		}
 	}
+
+	// https://github.com/google/zetasql/blob/master/docs/functions-reference.md#named-arguments
+	// You cannot specify positional arguments after named arguments.
+	var namedArgs []*ast.NamedArg
+	for {
+		namedArg := p.tryParseNamedArg()
+		if namedArg == nil {
+			break
+		}
+		namedArgs = append(namedArgs, namedArg)
+		if p.Token.Kind != "," {
+			break
+		}
+		p.nextToken()
+	}
+
 	rparen := p.expect(")").Pos
 	return &ast.CallExpr{
-		Rparen:   rparen,
-		Func:     fn,
-		Distinct: distinct,
-		Args:     args,
+		Rparen:    rparen,
+		Func:      fn,
+		Distinct:  distinct,
+		Args:      args,
+		NamedArgs: namedArgs,
+	}
+}
+func (p *Parser) lookaheadNamedArg() bool {
+	lexer := p.Lexer.Clone()
+	defer func() {
+		p.Lexer = lexer
+	}()
+
+	if p.Token.Kind != token.TokenIdent {
+		return false
+	}
+	p.parseIdent()
+	return p.Token.Kind == "=>"
+}
+
+func (p *Parser) tryParseNamedArg() *ast.NamedArg {
+	if !p.lookaheadNamedArg() {
+		return nil
+	}
+	name := p.parseIdent()
+	p.expect("=>")
+	value := p.parseExpr()
+	return &ast.NamedArg{
+		Name:  name,
+		Value: value,
 	}
 }
 
@@ -1778,6 +1823,14 @@ func (p *Parser) parseNumericLiteral(id token.Token) *ast.NumericLiteral {
 	}
 }
 
+func (p *Parser) parseJSONLiteral(id token.Token) *ast.JSONLiteral {
+	s := p.parseStringLiteral()
+	return &ast.JSONLiteral{
+		JSON:  id.Pos,
+		Value: s,
+	}
+}
+
 func (p *Parser) lookaheadSubQuery() bool {
 	lexer := p.Lexer.Clone()
 	defer func() {
diff --git a/split.go b/split.go
index 9f0193c..a22a4fd 100644
--- a/split.go
+++ b/split.go
@@ -2,14 +2,20 @@ package memefish
 
 import "github.com/cloudspannerecosystem/memefish/token"
 
+type RawStatement struct {
+	Pos, End  token.Pos
+	Statement string
+}
+
 // SplitRawStatements splits an input string to statement strings at terminating semicolons without parsing.
+// It preserves all comments.
 // Statements are terminated by `;`, `<eof>` or `;<eof>` and the minimum output will be []string{""}.
 // See [terminating semicolons].
 // This function won't panic but return error if lexer become error state.
-// filepath can be used in error message.
+// filepath can be empty, it is only used in error message.
 //
 // [terminating semicolons]: https://cloud.google.com/spanner/docs/reference/standard-sql/lexical#terminating_semicolons
-func SplitRawStatements(filepath, s string) ([]string, error) {
+func SplitRawStatements(filepath, s string) ([]*RawStatement, error) {
 	lex := &Lexer{
 		File: &token.File{
 			FilePath: filepath,
@@ -17,11 +23,15 @@ func SplitRawStatements(filepath, s string) ([]string, error) {
 		},
 	}
 
-	var result []string
+	var result []*RawStatement
 	var firstPos token.Pos
 	for {
 		if lex.Token.Kind == ";" {
-			result = append(result, s[firstPos:lex.Token.Pos])
+			result = append(result, &RawStatement{
+				Pos:       firstPos,
+				End:       lex.Token.Pos,
+				Statement: s[firstPos:lex.Token.Pos],
+			})
 			if err := lex.NextToken(); err != nil {
 				return nil, err
 			}
@@ -36,13 +46,19 @@ func SplitRawStatements(filepath, s string) ([]string, error) {
 
 		if lex.Token.Kind == token.TokenEOF {
 			if lex.Token.Pos != firstPos {
-				result = append(result, s[firstPos:lex.Token.Pos])
+				result = append(result, &RawStatement{
+					Pos:       firstPos,
+					End:       lex.Token.Pos,
+					Statement: s[firstPos:lex.Token.Pos],
+				})
 			}
 			break
 		}
 	}
 	if len(result) == 0 {
-		return []string{""}, nil
+		return []*RawStatement{
+			{Statement: ""},
+		}, nil
 	}
 	return result, nil
 }


Test patch:
diff --git a/parser_test.go b/parser_test.go
index ca732df..80a7328 100644
--- a/parser_test.go
+++ b/parser_test.go
@@ -153,6 +153,15 @@ func TestParseDML(t *testing.T) {
 	})
 }
 
+func TestParseExpr(t *testing.T) {
+	inputPath := "./testdata/input/expr"
+	resultPath := "./testdata/result/expr"
+
+	testParser(t, inputPath, resultPath, func(p *memefish.Parser) (ast.Node, error) {
+		return p.ParseExpr()
+	})
+}
+
 func TestParseStatement(t *testing.T) {
 	inputPaths := []string{
 		"./testdata/input/query",
diff --git a/split_test.go b/split_test.go
index d9b8a5b..14d838f 100644
--- a/split_test.go
+++ b/split_test.go
@@ -2,6 +2,7 @@ package memefish_test
 
 import (
 	"github.com/cloudspannerecosystem/memefish"
+	"github.com/cloudspannerecosystem/memefish/token"
 	"github.com/google/go-cmp/cmp"
 	"regexp"
 	"testing"
@@ -12,23 +13,62 @@ func TestSplitRawStatements(t *testing.T) {
 		desc  string
 		input string
 		errRe *regexp.Regexp
-		want  []string
+		want  []*memefish.RawStatement
 	}{
 		// SplitRawStatements treats only lexical structures, so the test cases can be invalid statements.
-		{desc: "empty input", input: "", want: []string{""}},
-		{desc: "single statement ends with semicolon", input: `SELECT "123";`, want: []string{`SELECT "123"`}},
-		{desc: "single statement ends with EOF", input: `SELECT "123"`, want: []string{`SELECT "123"`}},
-		{desc: "two statement ends with semicolon", input: `SELECT "123"; SELECT "456";`, want: []string{`SELECT "123"`, `SELECT "456"`}},
-		{desc: "two statement ends with EOF", input: `SELECT "123"; SELECT "456"`, want: []string{`SELECT "123"`, `SELECT "456"`}},
-		{desc: "second statement is empty", input: `SELECT 1; ;`, want: []string{`SELECT 1`, ``}},
-		{desc: "two statement with new lines", input: "SELECT 1;\n SELECT 2;\n", want: []string{"SELECT 1", "SELECT 2"}},
+		{desc: "empty input", input: "", want: []*memefish.RawStatement{{Statement: ""}}},
+		{desc: "single statement ends with semicolon", input: `SELECT "123";`,
+			want: []*memefish.RawStatement{
+				{Statement: `SELECT "123"`, End: token.Pos(12)},
+			}},
+		{desc: "single statement ends with EOF", input: `SELECT "123"`,
+			want: []*memefish.RawStatement{
+				{Statement: `SELECT "123"`, End: token.Pos(12)},
+			}},
+		{desc: "two statement ends with semicolon", input: `SELECT "123"; SELECT "456";`,
+			want: []*memefish.RawStatement{
+				{Statement: `SELECT "123"`, End: token.Pos(12)},
+				{Statement: `SELECT "456"`, Pos: token.Pos(14), End: token.Pos(26)},
+			}},
+		{desc: "two statement ends with EOF", input: `SELECT "123"; SELECT "456"`,
+			want: []*memefish.RawStatement{
+				{Statement: `SELECT "123"`, End: token.Pos(12)},
+				{Statement: `SELECT "456"`, Pos: token.Pos(14), End: token.Pos(26)},
+			}},
+		{desc: "second statement is empty", input: `SELECT 1; ;`,
+			want: []*memefish.RawStatement{
+				{Statement: `SELECT 1`, End: token.Pos(8)},
+				{Statement: ``, Pos: token.Pos(10), End: token.Pos(10)},
+			}},
+		{desc: "two statement with new lines", input: "SELECT 1;\n SELECT 2;\n",
+			want: []*memefish.RawStatement{
+				{Statement: "SELECT 1", End: token.Pos(8)},
+				{Statement: "SELECT 2", Pos: token.Pos(11), End: token.Pos(19)},
+			}},
 		{desc: "single statement with line comment", input: `SELECT 1//
-`, want: []string{"SELECT 1//\n"}},
-		{desc: "semicolon in line comment", input: "SELECT 1 //;\n + 2", want: []string{"SELECT 1 //;\n + 2"}},
-		{desc: "semicolon in multi-line comment", input: "SELECT 1 /*;\n*/ + 2", want: []string{"SELECT 1 /*;\n*/ + 2"}},
-		{desc: "semicolon in double-quoted string", input: `SELECT "1;2;3";`, want: []string{`SELECT "1;2;3"`}},
-		{desc: "semicolon in single-quoted string", input: `SELECT '1;2;3';`, want: []string{`SELECT '1;2;3'`}},
-		{desc: "semicolon in back-quote", input: "SELECT `1;2;3`;", want: []string{"SELECT `1;2;3`"}},
+`, want: []*memefish.RawStatement{
+			{Statement: "SELECT 1//\n", End: token.Pos(11)},
+		}},
+		{desc: "semicolon in line comment", input: "SELECT 1 //;\n + 2",
+			want: []*memefish.RawStatement{
+				{Statement: "SELECT 1 //;\n + 2", End: token.Pos(17)},
+			}},
+		{desc: "semicolon in multi-line comment", input: "SELECT 1 /*;\n*/ + 2",
+			want: []*memefish.RawStatement{
+				{Statement: "SELECT 1 /*;\n*/ + 2", End: token.Pos(19)},
+			}},
+		{desc: "semicolon in double-quoted string", input: `SELECT "1;2;3";`,
+			want: []*memefish.RawStatement{
+				{Statement: `SELECT "1;2;3"`, End: token.Pos(14)},
+			}},
+		{desc: "semicolon in single-quoted string", input: `SELECT '1;2;3';`,
+			want: []*memefish.RawStatement{
+				{Statement: `SELECT '1;2;3'`, End: token.Pos(14)},
+			}},
+		{desc: "semicolon in back-quote", input: "SELECT `1;2;3`;",
+			want: []*memefish.RawStatement{
+				{Statement: "SELECT `1;2;3`", End: token.Pos(14)},
+			}},
 		// $` may become a valid token in the future, but it's reasonable to check its current behavior.
 		{desc: "unknown token", input: "SELECT $;", errRe: regexp.MustCompile(`illegal input character: '\$'`)},
 	} {
diff --git a/testdata/input/expr/json_literal.sql b/testdata/input/expr/json_literal.sql
new file mode 100644
index 0000000..0c65982
--- /dev/null
+++ b/testdata/input/expr/json_literal.sql
@@ -0,0 +1,1 @@
+JSON '{"s": "foo", "n": 42}'
\ No newline at end of file
diff --git a/testdata/input/query/select_call_with_named_expr.sql b/testdata/input/query/select_call_with_named_expr.sql
new file mode 100644
index 0000000..cbada76
--- /dev/null
+++ b/testdata/input/query/select_call_with_named_expr.sql
@@ -0,0 +1,3 @@
+SELECT a.AlbumId, a.Description
+FROM Albums a
+WHERE a.SingerId = 1 AND SEARCH(a.DescriptionTokens, 'classic albums', enhance_query => TRUE)
\ No newline at end of file
diff --git a/testdata/input/query/select_literals_all.sql b/testdata/input/query/select_literals_all.sql
index d2f11aa..3d211fd 100644
--- a/testdata/input/query/select_literals_all.sql
+++ b/testdata/input/query/select_literals_all.sql
@@ -40,6 +40,9 @@ lines''',
   TIMESTAMP "2014-09-27 12:30:00.45 America/Los_Angeles",
   TIMESTAMP'2014-09-27',
   TIMESTAMP('2014-09-27'),
+  JSON '1',
+  JSON "[1, 2]",
+  JSON'{}',
   NUMERIC '0',
   NUMERIC "0",
-  true, fals
\ No newline at end of file
+  true, false
\ No newline at end of file
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 72daf18..296ec2a 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,6 +99,7 @@ ALTER TABLE foo ADD COLUMN expired_at TIMESTAMP AS (IF (status != "OPEN" AND sta
                     },
                   },
                 },
+                NamedArgs: []*ast.NamedArg(nil),
               },
             },
             &ast.ExprArg{
@@ -107,6 +108,7 @@ ALTER TABLE foo ADD COLUMN expired_at TIMESTAMP AS (IF (status != "OPEN" AND sta
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
       Options: (*ast.ColumnDefOptions)(nil),
diff --git a/testdata/result/ddl/create_table.sql.txt b/testdata/result/ddl/create_table.sql.txt
index b0640aa..09e7fed 100644
--- a/testdata/result/ddl/create_table.sql.txt
+++ b/testdata/result/ddl/create_table.sql.txt
@@ -133,6 +133,7 @@ create table foo (
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
       Options: (*ast.ColumnDefOptions)(nil),
@@ -175,8 +176,9 @@ create table foo (
             NameEnd: 546,
             Name:    "current_timestamp",
           },
-          Distinct: false,
-          Args:     []ast.Arg(nil),
+          Distinct:  false,
+          Args:      []ast.Arg(nil),
+          NamedArgs: []*ast.NamedArg(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 af66d78..d3fac4a 100644
--- a/testdata/result/ddl/create_table_with_sequence_function.sql.txt
+++ b/testdata/result/ddl/create_table_with_sequence_function.sql.txt
@@ -50,6 +50,7 @@ CREATE TABLE foo
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(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 1928314..2424b7a 100644
--- a/testdata/result/dml/insert_with_sequence_function.sql.txt
+++ b/testdata/result/dml/insert_with_sequence_function.sql.txt
@@ -45,6 +45,7 @@ INSERT INTO foo(bar) VALUES (GET_NEXT_SEQUENCE_VALUE(SEQUENCE my_sequence))
                   },
                 },
               },
+              NamedArgs: []*ast.NamedArg(nil),
             },
           },
         },
diff --git a/testdata/result/expr/json_literal.sql.txt b/testdata/result/expr/json_literal.sql.txt
new file mode 100644
index 0000000..6d4efa7
--- /dev/null
+++ b/testdata/result/expr/json_literal.sql.txt
@@ -0,0 +1,14 @@
+--- json_literal.sql
+JSON '{"s": "foo", "n": 42}'
+--- AST
+&ast.JSONLiteral{
+  JSON:  0,
+  Value: &ast.StringLiteral{
+    ValuePos: 5,
+    ValueEnd: 28,
+    Value:    "{\"s\": \"foo\", \"n\": 42}",
+  },
+}
+
+--- SQL
+JSON "{\"s\": \"foo\", \"n\": 42}"
diff --git a/testdata/result/query/select_call_with_named_expr.sql.txt b/testdata/result/query/select_call_with_named_expr.sql.txt
new file mode 100644
index 0000000..ec26e03
--- /dev/null
+++ b/testdata/result/query/select_call_with_named_expr.sql.txt
@@ -0,0 +1,151 @@
+--- select_call_with_named_expr.sql
+SELECT a.AlbumId, a.Description
+FROM Albums a
+WHERE a.SingerId = 1 AND SEARCH(a.DescriptionTokens, 'classic albums', enhance_query => TRUE)
+--- AST
+&ast.QueryStatement{
+  Hint:  (*ast.Hint)(nil),
+  With:  (*ast.With)(nil),
+  Query: &ast.Select{
+    Select:   0,
+    Distinct: false,
+    AsStruct: false,
+    Results:  []ast.SelectItem{
+      &ast.ExprSelectItem{
+        Expr: &ast.Path{
+          Idents: []*ast.Ident{
+            &ast.Ident{
+              NamePos: 7,
+              NameEnd: 8,
+              Name:    "a",
+            },
+            &ast.Ident{
+              NamePos: 9,
+              NameEnd: 16,
+              Name:    "AlbumId",
+            },
+          },
+        },
+      },
+      &ast.ExprSelectItem{
+        Expr: &ast.Path{
+          Idents: []*ast.Ident{
+            &ast.Ident{
+              NamePos: 18,
+              NameEnd: 19,
+              Name:    "a",
+            },
+            &ast.Ident{
+              NamePos: 20,
+              NameEnd: 31,
+              Name:    "Description",
+            },
+          },
+        },
+      },
+    },
+    From: &ast.From{
+      From:   32,
+      Source: &ast.TableName{
+        Table: &ast.Ident{
+          NamePos: 37,
+          NameEnd: 43,
+          Name:    "Albums",
+        },
+        Hint: (*ast.Hint)(nil),
+        As:   &ast.AsAlias{
+          As:    44,
+          Alias: &ast.Ident{
+            NamePos: 44,
+            NameEnd: 45,
+            Name:    "a",
+          },
+        },
+        Sample: (*ast.TableSample)(nil),
+      },
+    },
+    Where: &ast.Where{
+      Where: 46,
+      Expr:  &ast.BinaryExpr{
+        Op:   "AND",
+        Left: &ast.BinaryExpr{
+          Op:   "=",
+          Left: &ast.Path{
+            Idents: []*ast.Ident{
+              &ast.Ident{
+                NamePos: 52,
+                NameEnd: 53,
+                Name:    "a",
+              },
+              &ast.Ident{
+                NamePos: 54,
+                NameEnd: 62,
+                Name:    "SingerId",
+              },
+            },
+          },
+          Right: &ast.IntLiteral{
+            ValuePos: 65,
+            ValueEnd: 66,
+            Base:     10,
+            Value:    "1",
+          },
+        },
+        Right: &ast.CallExpr{
+          Rparen: 138,
+          Func:   &ast.Ident{
+            NamePos: 71,
+            NameEnd: 77,
+            Name:    "SEARCH",
+          },
+          Distinct: false,
+          Args:     []ast.Arg{
+            &ast.ExprArg{
+              Expr: &ast.Path{
+                Idents: []*ast.Ident{
+                  &ast.Ident{
+                    NamePos: 78,
+                    NameEnd: 79,
+                    Name:    "a",
+                  },
+                  &ast.Ident{
+                    NamePos: 80,
+                    NameEnd: 97,
+                    Name:    "DescriptionTokens",
+                  },
+                },
+              },
+            },
+            &ast.ExprArg{
+              Expr: &ast.StringLiteral{
+                ValuePos: 99,
+                ValueEnd: 115,
+                Value:    "classic albums",
+              },
+            },
+          },
+          NamedArgs: []*ast.NamedArg{
+            &ast.NamedArg{
+              Name: &ast.Ident{
+                NamePos: 117,
+                NameEnd: 130,
+                Name:    "enhance_query",
+              },
+              Value: &ast.BoolLiteral{
+                ValuePos: 134,
+                Value:    true,
+              },
+            },
+          },
+        },
+      },
+    },
+    GroupBy: (*ast.GroupBy)(nil),
+    Having:  (*ast.Having)(nil),
+    OrderBy: (*ast.OrderBy)(nil),
+    Limit:   (*ast.Limit)(nil),
+  },
+}
+
+--- SQL
+SELECT a.AlbumId, a.Description FROM Albums AS a WHERE a.SingerId = 1 AND SEARCH(a.DescriptionTokens, "classic albums", enhance_query => TRUE)
diff --git a/testdata/result/query/select_count_distinct.sql.txt b/testdata/result/query/select_count_distinct.sql.txt
index 5af2d36..49418b2 100644
--- a/testdata/result/query/select_count_distinct.sql.txt
+++ b/testdata/result/query/select_count_distinct.sql.txt
@@ -27,6 +27,7 @@ select count(distinct x) from foo
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
     },
diff --git a/testdata/result/query/select_expr.sql.txt b/testdata/result/query/select_expr.sql.txt
index 87e68b8..bbf9579 100644
--- a/testdata/result/query/select_expr.sql.txt
+++ b/testdata/result/query/select_expr.sql.txt
@@ -617,6 +617,7 @@ select 1 + 2, 1 - 2,
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
       &ast.ExprSelectItem{
@@ -654,6 +655,7 @@ select 1 + 2, 1 - 2,
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
       &ast.ExprSelectItem{
@@ -897,6 +899,7 @@ select 1 + 2, 1 - 2,
                 },
               },
             },
+            NamedArgs: []*ast.NamedArg(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 37ca4c6..53fcf56 100644
--- a/testdata/result/query/select_literals_all.sql.txt
+++ b/testdata/result/query/select_literals_all.sql.txt
@@ -41,9 +41,12 @@ lines''',
   TIMESTAMP "2014-09-27 12:30:00.45 America/Los_Angeles",
   TIMESTAMP'2014-09-27',
   TIMESTAMP('2014-09-27'),
+  JSON '1',
+  JSON "[1, 2]",
+  JSON'{}',
   NUMERIC '0',
   NUMERIC "0",
-  true, fals
+  true, false
 --- AST
 &ast.QueryStatement{
   Hint:  (*ast.Hint)(nil),
@@ -501,6 +504,7 @@ lines''',
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
       &ast.ExprSelectItem{
@@ -551,39 +555,69 @@ lines''',
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
+        },
+      },
+      &ast.ExprSelectItem{
+        Expr: &ast.JSONLiteral{
+          JSON:  708,
+          Value: &ast.StringLiteral{
+            ValuePos: 713,
+            ValueEnd: 716,
+            Value:    "1",
+          },
+        },
+      },
+      &ast.ExprSelectItem{
+        Expr: &ast.JSONLiteral{
+          JSON:  720,
+          Value: &ast.StringLiteral{
+            ValuePos: 725,
+            ValueEnd: 733,
+            Value:    "[1, 2]",
+          },
+        },
+      },
+      &ast.ExprSelectItem{
+        Expr: &ast.JSONLiteral{
+          JSON:  737,
+          Value: &ast.StringLiteral{
+            ValuePos: 741,
+            ValueEnd: 745,
+            Value:    "{}",
+          },
         },
       },
       &ast.ExprSelectItem{
         Expr: &ast.NumericLiteral{
-          Numeric: 708,
+          Numeric: 749,
           Value:   &ast.StringLiteral{
-            ValuePos: 716,
-            ValueEnd: 719,
+            ValuePos: 757,
+            ValueEnd: 760,
             Value:    "0",
           },
         },
       },
       &ast.ExprSelectItem{
         Expr: &ast.NumericLiteral{
-          Numeric: 723,
+          Numeric: 764,
           Value:   &ast.StringLiteral{
-            ValuePos: 731,
-            ValueEnd: 734,
+            ValuePos: 772,
+            ValueEnd: 775,
             Value:    "0",
           },
         },
       },
       &ast.ExprSelectItem{
         Expr: &ast.BoolLiteral{
-          ValuePos: 738,
+          ValuePos: 779,
           Value:    true,
         },
       },
       &ast.ExprSelectItem{
-        Expr: &ast.Ident{
-          NamePos: 744,
-          NameEnd: 748,
-          Name:    "fals",
+        Expr: &ast.BoolLiteral{
+          ValuePos: 785,
+          Value:    false,
         },
       },
     },
@@ -597,4 +631,4 @@ lines''',
 }
 
 --- SQL
-SELECT "abc", "it\'s", "it\'s", "Title: \"Boy\"", "abc", "it\'s", "Title:\"Boy\"", "two\nlines", "why\?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)", B"abc", B"abc", B"abc", B"abc+", B"abc+", B"abc", 123, 0xABC, -123, -0xABC, 123.456e-67, .1E4, 58., 4e2, ARRAY[1, 2, 3], ARRAY["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[], ARRAY(SELECT STRUCT(1, 2, 3)), ARRAY(SELECT STRUCT(1, 2, 3)), DATE "2014-09-27", DATE("2014-09-27"), TIMESTAMP "2014-09-27 12:30:00.45-08", TIMESTAMP "2014-09-27 12:30:00.45 America/Los_Angeles", TIMESTAMP "2014-09-27", TIMESTAMP("2014-09-27"), NUMERIC "0", NUMERIC "0", TRUE, fals
+SELECT "abc", "it\'s", "it\'s", "Title: \"Boy\"", "abc", "it\'s", "Title:\"Boy\"", "two\nlines", "why\?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)", B"abc", B"abc", B"abc", B"abc+", B"abc+", B"abc", 123, 0xABC, -123, -0xABC, 123.456e-67, .1E4, 58., 4e2, ARRAY[1, 2, 3], ARRAY["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[], ARRAY(SELECT STRUCT(1, 2, 3)), ARRAY(SELECT STRUCT(1, 2, 3)), DATE "2014-09-27", DATE("2014-09-27"), TIMESTAMP "2014-09-27 12:30:00.45-08", TIMESTAMP "2014-09-27 12:30:00.45 America/Los_Angeles", TIMESTAMP "2014-09-27", TIMESTAMP("2014-09-27"), JSON "1", JSON "[1, 2]", JSON "{}", NUMERIC "0", NUMERIC "0", TRUE, FALSE
diff --git a/testdata/result/query/select_literals_date.sql.txt b/testdata/result/query/select_literals_date.sql.txt
index 24c0089..082ff35 100644
--- a/testdata/result/query/select_literals_date.sql.txt
+++ b/testdata/result/query/select_literals_date.sql.txt
@@ -48,6 +48,7 @@ SELECT
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
       &ast.ExprSelectItem{
@@ -108,6 +109,7 @@ SELECT
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
       &ast.ExprSelectItem{
@@ -138,6 +140,7 @@ SELECT
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
         As: &ast.AsAlias{
           As:    -1,
@@ -166,6 +169,7 @@ SELECT
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(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 5d5e76e..f940e62 100644
--- a/testdata/result/query/select_with_sequence_function.sql.txt
+++ b/testdata/result/query/select_with_sequence_function.sql.txt
@@ -29,6 +29,7 @@ SELECT GET_NEXT_SEQUENCE_VALUE(SEQUENCE my_sequence) as next_id
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
         As: &ast.AsAlias{
           As:    -1,
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 72daf18..296ec2a 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,6 +99,7 @@ ALTER TABLE foo ADD COLUMN expired_at TIMESTAMP AS (IF (status != "OPEN" AND sta
                     },
                   },
                 },
+                NamedArgs: []*ast.NamedArg(nil),
               },
             },
             &ast.ExprArg{
@@ -107,6 +108,7 @@ ALTER TABLE foo ADD COLUMN expired_at TIMESTAMP AS (IF (status != "OPEN" AND sta
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
       Options: (*ast.ColumnDefOptions)(nil),
diff --git a/testdata/result/statement/create_table.sql.txt b/testdata/result/statement/create_table.sql.txt
index b0640aa..09e7fed 100644
--- a/testdata/result/statement/create_table.sql.txt
+++ b/testdata/result/statement/create_table.sql.txt
@@ -133,6 +133,7 @@ create table foo (
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
       Options: (*ast.ColumnDefOptions)(nil),
@@ -175,8 +176,9 @@ create table foo (
             NameEnd: 546,
             Name:    "current_timestamp",
           },
-          Distinct: false,
-          Args:     []ast.Arg(nil),
+          Distinct:  false,
+          Args:      []ast.Arg(nil),
+          NamedArgs: []*ast.NamedArg(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 af66d78..d3fac4a 100644
--- a/testdata/result/statement/create_table_with_sequence_function.sql.txt
+++ b/testdata/result/statement/create_table_with_sequence_function.sql.txt
@@ -50,6 +50,7 @@ CREATE TABLE foo
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(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 1928314..2424b7a 100644
--- a/testdata/result/statement/insert_with_sequence_function.sql.txt
+++ b/testdata/result/statement/insert_with_sequence_function.sql.txt
@@ -45,6 +45,7 @@ INSERT INTO foo(bar) VALUES (GET_NEXT_SEQUENCE_VALUE(SEQUENCE my_sequence))
                   },
                 },
               },
+              NamedArgs: []*ast.NamedArg(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
new file mode 100644
index 0000000..ec26e03
--- /dev/null
+++ b/testdata/result/statement/select_call_with_named_expr.sql.txt
@@ -0,0 +1,151 @@
+--- select_call_with_named_expr.sql
+SELECT a.AlbumId, a.Description
+FROM Albums a
+WHERE a.SingerId = 1 AND SEARCH(a.DescriptionTokens, 'classic albums', enhance_query => TRUE)
+--- AST
+&ast.QueryStatement{
+  Hint:  (*ast.Hint)(nil),
+  With:  (*ast.With)(nil),
+  Query: &ast.Select{
+    Select:   0,
+    Distinct: false,
+    AsStruct: false,
+    Results:  []ast.SelectItem{
+      &ast.ExprSelectItem{
+        Expr: &ast.Path{
+          Idents: []*ast.Ident{
+            &ast.Ident{
+              NamePos: 7,
+              NameEnd: 8,
+              Name:    "a",
+            },
+            &ast.Ident{
+              NamePos: 9,
+              NameEnd: 16,
+              Name:    "AlbumId",
+            },
+          },
+        },
+      },
+      &ast.ExprSelectItem{
+        Expr: &ast.Path{
+          Idents: []*ast.Ident{
+            &ast.Ident{
+              NamePos: 18,
+              NameEnd: 19,
+              Name:    "a",
+            },
+            &ast.Ident{
+              NamePos: 20,
+              NameEnd: 31,
+              Name:    "Description",
+            },
+          },
+        },
+      },
+    },
+    From: &ast.From{
+      From:   32,
+      Source: &ast.TableName{
+        Table: &ast.Ident{
+          NamePos: 37,
+          NameEnd: 43,
+          Name:    "Albums",
+        },
+        Hint: (*ast.Hint)(nil),
+        As:   &ast.AsAlias{
+          As:    44,
+          Alias: &ast.Ident{
+            NamePos: 44,
+            NameEnd: 45,
+            Name:    "a",
+          },
+        },
+        Sample: (*ast.TableSample)(nil),
+      },
+    },
+    Where: &ast.Where{
+      Where: 46,
+      Expr:  &ast.BinaryExpr{
+        Op:   "AND",
+        Left: &ast.BinaryExpr{
+          Op:   "=",
+          Left: &ast.Path{
+            Idents: []*ast.Ident{
+              &ast.Ident{
+                NamePos: 52,
+                NameEnd: 53,
+                Name:    "a",
+              },
+              &ast.Ident{
+                NamePos: 54,
+                NameEnd: 62,
+                Name:    "SingerId",
+              },
+            },
+          },
+          Right: &ast.IntLiteral{
+            ValuePos: 65,
+            ValueEnd: 66,
+            Base:     10,
+            Value:    "1",
+          },
+        },
+        Right: &ast.CallExpr{
+          Rparen: 138,
+          Func:   &ast.Ident{
+            NamePos: 71,
+            NameEnd: 77,
+            Name:    "SEARCH",
+          },
+          Distinct: false,
+          Args:     []ast.Arg{
+            &ast.ExprArg{
+              Expr: &ast.Path{
+                Idents: []*ast.Ident{
+                  &ast.Ident{
+                    NamePos: 78,
+                    NameEnd: 79,
+                    Name:    "a",
+                  },
+                  &ast.Ident{
+                    NamePos: 80,
+                    NameEnd: 97,
+                    Name:    "DescriptionTokens",
+                  },
+                },
+              },
+            },
+            &ast.ExprArg{
+              Expr: &ast.StringLiteral{
+                ValuePos: 99,
+                ValueEnd: 115,
+                Value:    "classic albums",
+              },
+            },
+          },
+          NamedArgs: []*ast.NamedArg{
+            &ast.NamedArg{
+              Name: &ast.Ident{
+                NamePos: 117,
+                NameEnd: 130,
+                Name:    "enhance_query",
+              },
+              Value: &ast.BoolLiteral{
+                ValuePos: 134,
+                Value:    true,
+              },
+            },
+          },
+        },
+      },
+    },
+    GroupBy: (*ast.GroupBy)(nil),
+    Having:  (*ast.Having)(nil),
+    OrderBy: (*ast.OrderBy)(nil),
+    Limit:   (*ast.Limit)(nil),
+  },
+}
+
+--- SQL
+SELECT a.AlbumId, a.Description FROM Albums AS a WHERE a.SingerId = 1 AND SEARCH(a.DescriptionTokens, "classic albums", enhance_query => TRUE)
diff --git a/testdata/result/statement/select_count_distinct.sql.txt b/testdata/result/statement/select_count_distinct.sql.txt
index 5af2d36..49418b2 100644
--- a/testdata/result/statement/select_count_distinct.sql.txt
+++ b/testdata/result/statement/select_count_distinct.sql.txt
@@ -27,6 +27,7 @@ select count(distinct x) from foo
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
     },
diff --git a/testdata/result/statement/select_expr.sql.txt b/testdata/result/statement/select_expr.sql.txt
index 87e68b8..bbf9579 100644
--- a/testdata/result/statement/select_expr.sql.txt
+++ b/testdata/result/statement/select_expr.sql.txt
@@ -617,6 +617,7 @@ select 1 + 2, 1 - 2,
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
       &ast.ExprSelectItem{
@@ -654,6 +655,7 @@ select 1 + 2, 1 - 2,
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
       &ast.ExprSelectItem{
@@ -897,6 +899,7 @@ select 1 + 2, 1 - 2,
                 },
               },
             },
+            NamedArgs: []*ast.NamedArg(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 37ca4c6..53fcf56 100644
--- a/testdata/result/statement/select_literals_all.sql.txt
+++ b/testdata/result/statement/select_literals_all.sql.txt
@@ -41,9 +41,12 @@ lines''',
   TIMESTAMP "2014-09-27 12:30:00.45 America/Los_Angeles",
   TIMESTAMP'2014-09-27',
   TIMESTAMP('2014-09-27'),
+  JSON '1',
+  JSON "[1, 2]",
+  JSON'{}',
   NUMERIC '0',
   NUMERIC "0",
-  true, fals
+  true, false
 --- AST
 &ast.QueryStatement{
   Hint:  (*ast.Hint)(nil),
@@ -501,6 +504,7 @@ lines''',
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
       &ast.ExprSelectItem{
@@ -551,39 +555,69 @@ lines''',
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
+        },
+      },
+      &ast.ExprSelectItem{
+        Expr: &ast.JSONLiteral{
+          JSON:  708,
+          Value: &ast.StringLiteral{
+            ValuePos: 713,
+            ValueEnd: 716,
+            Value:    "1",
+          },
+        },
+      },
+      &ast.ExprSelectItem{
+        Expr: &ast.JSONLiteral{
+          JSON:  720,
+          Value: &ast.StringLiteral{
+            ValuePos: 725,
+            ValueEnd: 733,
+            Value:    "[1, 2]",
+          },
+        },
+      },
+      &ast.ExprSelectItem{
+        Expr: &ast.JSONLiteral{
+          JSON:  737,
+          Value: &ast.StringLiteral{
+            ValuePos: 741,
+            ValueEnd: 745,
+            Value:    "{}",
+          },
         },
       },
       &ast.ExprSelectItem{
         Expr: &ast.NumericLiteral{
-          Numeric: 708,
+          Numeric: 749,
           Value:   &ast.StringLiteral{
-            ValuePos: 716,
-            ValueEnd: 719,
+            ValuePos: 757,
+            ValueEnd: 760,
             Value:    "0",
           },
         },
       },
       &ast.ExprSelectItem{
         Expr: &ast.NumericLiteral{
-          Numeric: 723,
+          Numeric: 764,
           Value:   &ast.StringLiteral{
-            ValuePos: 731,
-            ValueEnd: 734,
+            ValuePos: 772,
+            ValueEnd: 775,
             Value:    "0",
           },
         },
       },
       &ast.ExprSelectItem{
         Expr: &ast.BoolLiteral{
-          ValuePos: 738,
+          ValuePos: 779,
           Value:    true,
         },
       },
       &ast.ExprSelectItem{
-        Expr: &ast.Ident{
-          NamePos: 744,
-          NameEnd: 748,
-          Name:    "fals",
+        Expr: &ast.BoolLiteral{
+          ValuePos: 785,
+          Value:    false,
         },
       },
     },
@@ -597,4 +631,4 @@ lines''',
 }
 
 --- SQL
-SELECT "abc", "it\'s", "it\'s", "Title: \"Boy\"", "abc", "it\'s", "Title:\"Boy\"", "two\nlines", "why\?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)", B"abc", B"abc", B"abc", B"abc+", B"abc+", B"abc", 123, 0xABC, -123, -0xABC, 123.456e-67, .1E4, 58., 4e2, ARRAY[1, 2, 3], ARRAY["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[], ARRAY(SELECT STRUCT(1, 2, 3)), ARRAY(SELECT STRUCT(1, 2, 3)), DATE "2014-09-27", DATE("2014-09-27"), TIMESTAMP "2014-09-27 12:30:00.45-08", TIMESTAMP "2014-09-27 12:30:00.45 America/Los_Angeles", TIMESTAMP "2014-09-27", TIMESTAMP("2014-09-27"), NUMERIC "0", NUMERIC "0", TRUE, fals
+SELECT "abc", "it\'s", "it\'s", "Title: \"Boy\"", "abc", "it\'s", "Title:\"Boy\"", "two\nlines", "why\?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)", B"abc", B"abc", B"abc", B"abc+", B"abc+", B"abc", 123, 0xABC, -123, -0xABC, 123.456e-67, .1E4, 58., 4e2, ARRAY[1, 2, 3], ARRAY["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[], ARRAY(SELECT STRUCT(1, 2, 3)), ARRAY(SELECT STRUCT(1, 2, 3)), DATE "2014-09-27", DATE("2014-09-27"), TIMESTAMP "2014-09-27 12:30:00.45-08", TIMESTAMP "2014-09-27 12:30:00.45 America/Los_Angeles", TIMESTAMP "2014-09-27", TIMESTAMP("2014-09-27"), JSON "1", JSON "[1, 2]", JSON "{}", NUMERIC "0", NUMERIC "0", TRUE, FALSE
diff --git a/testdata/result/statement/select_literals_date.sql.txt b/testdata/result/statement/select_literals_date.sql.txt
index 24c0089..082ff35 100644
--- a/testdata/result/statement/select_literals_date.sql.txt
+++ b/testdata/result/statement/select_literals_date.sql.txt
@@ -48,6 +48,7 @@ SELECT
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
       &ast.ExprSelectItem{
@@ -108,6 +109,7 @@ SELECT
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
       },
       &ast.ExprSelectItem{
@@ -138,6 +140,7 @@ SELECT
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
         As: &ast.AsAlias{
           As:    -1,
@@ -166,6 +169,7 @@ SELECT
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(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 5d5e76e..f940e62 100644
--- a/testdata/result/statement/select_with_sequence_function.sql.txt
+++ b/testdata/result/statement/select_with_sequence_function.sql.txt
@@ -29,6 +29,7 @@ SELECT GET_NEXT_SEQUENCE_VALUE(SEQUENCE my_sequence) as next_id
               },
             },
           },
+          NamedArgs: []*ast.NamedArg(nil),
         },
         As: &ast.AsAlias{
           As:    -1,