Skip to content

Commit 951f4e6

Browse files
authored
Sync keyword list and implements IfExpr (#197)
* Make IF and GRAPH_TABLE as a keyword, and add IfExpr * Update testdata * Add newline
1 parent 2bd7987 commit 951f4e6

14 files changed

+270
-241
lines changed

ast/ast.go

+17
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ func (CountStarExpr) isExpr() {}
170170
func (CastExpr) isExpr() {}
171171
func (ExtractExpr) isExpr() {}
172172
func (CaseExpr) isExpr() {}
173+
func (IfExpr) isExpr() {}
173174
func (ParenExpr) isExpr() {}
174175
func (ScalarSubQuery) isExpr() {}
175176
func (ArraySubQuery) isExpr() {}
@@ -1307,6 +1308,22 @@ type CaseElse struct {
13071308
Expr Expr
13081309
}
13091310

1311+
// IfExpr is IF conditional expression.
1312+
// Because IF is SQL keyword, it can't be a normal CallExpr.
1313+
//
1314+
// IF({{.Expr | sql}}, {{.TrueResult | sql}}, {{.ElseResult | sql}})
1315+
type IfExpr struct {
1316+
// pos = If
1317+
// end = Rparen + 1
1318+
1319+
If token.Pos // position of "IF" keyword
1320+
Rparen token.Pos // position of ")"
1321+
1322+
Expr Expr
1323+
TrueResult Expr
1324+
ElseResult Expr
1325+
}
1326+
13101327
// ParenExpr is parenthesized expression node.
13111328
//
13121329
// ({{. | sql}})

ast/pos.go

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ast/sql.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ const (
7777

7878
func exprPrec(e Expr) prec {
7979
switch e := e.(type) {
80-
case *CallExpr, *CountStarExpr, *CastExpr, *ExtractExpr, *CaseExpr, *ParenExpr, *ScalarSubQuery, *ArraySubQuery, *ExistsSubQuery, *Param, *Ident, *Path, *ArrayLiteral, *TupleStructLiteral, *TypedStructLiteral, *TypelessStructLiteral, *NullLiteral, *BoolLiteral, *IntLiteral, *FloatLiteral, *StringLiteral, *BytesLiteral, *DateLiteral, *TimestampLiteral, *NumericLiteral:
80+
case *CallExpr, *CountStarExpr, *CastExpr, *ExtractExpr, *CaseExpr, *IfExpr, *ParenExpr, *ScalarSubQuery, *ArraySubQuery, *ExistsSubQuery, *Param, *Ident, *Path, *ArrayLiteral, *TupleStructLiteral, *TypedStructLiteral, *TypelessStructLiteral, *NullLiteral, *BoolLiteral, *IntLiteral, *FloatLiteral, *StringLiteral, *BytesLiteral, *DateLiteral, *TimestampLiteral, *NumericLiteral:
8181
return precLit
8282
case *IndexExpr, *SelectorExpr:
8383
return precSelector
@@ -576,6 +576,10 @@ func (c *CaseElse) SQL() string {
576576
return "ELSE " + c.Expr.SQL()
577577
}
578578

579+
func (i *IfExpr) SQL() string {
580+
return "IF(" + i.Expr.SQL() + ", " + i.TrueResult.SQL() + ", " + i.ElseResult.SQL() + ")"
581+
}
582+
579583
func (p *ParenExpr) SQL() string {
580584
return "(" + p.Expr.SQL() + ")"
581585
}

parser.go

+23-2
Original file line numberDiff line numberDiff line change
@@ -1425,6 +1425,8 @@ func (p *Parser) parseLit() ast.Expr {
14251425
return p.parseParam()
14261426
case "CASE":
14271427
return p.parseCaseExpr()
1428+
case "IF":
1429+
return p.parseIfExpr()
14281430
case "CAST":
14291431
return p.parseCastExpr()
14301432
case "EXISTS":
@@ -1715,6 +1717,25 @@ func (p *Parser) parseCaseElse() *ast.CaseElse {
17151717
}
17161718
}
17171719

1720+
func (p *Parser) parseIfExpr() *ast.IfExpr {
1721+
pos := p.expect("IF").Pos
1722+
p.expect("(")
1723+
expr := p.parseExpr()
1724+
p.expect(",")
1725+
trueResult := p.parseExpr()
1726+
p.expect(",")
1727+
elseResult := p.parseExpr()
1728+
rparen := p.expect(")").Pos
1729+
1730+
return &ast.IfExpr{
1731+
If: pos,
1732+
Rparen: rparen,
1733+
Expr: expr,
1734+
TrueResult: trueResult,
1735+
ElseResult: elseResult,
1736+
}
1737+
}
1738+
17181739
func (p *Parser) parseCastExpr() *ast.CastExpr {
17191740
if p.Token.Kind != "CAST" && !p.Token.IsKeywordLike("SAFE_CAST") {
17201741
panic(p.errorfAtToken(&p.Token, `expected CAST keyword or SAFE_CAST pseudo keyword, but: %v`, p.Token.Kind))
@@ -3818,7 +3839,7 @@ func (p *Parser) parseScalarSchemaType() ast.SchemaType {
38183839
}
38193840

38203841
func (p *Parser) parseIfNotExists() bool {
3821-
if p.Token.IsKeywordLike("IF") {
3842+
if p.Token.Kind == "IF" {
38223843
p.nextToken()
38233844
p.expect("NOT")
38243845
p.expect("EXISTS")
@@ -3828,7 +3849,7 @@ func (p *Parser) parseIfNotExists() bool {
38283849
}
38293850

38303851
func (p *Parser) parseIfExists() bool {
3831-
if p.Token.IsKeywordLike("IF") {
3852+
if p.Token.Kind == "IF" {
38323853
p.nextToken()
38333854
p.expect("EXISTS")
38343855
return true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
`IF` + `GRAPH_TABLE`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
`DATABASE` + `SCHEMA`

testdata/result/ddl/alter_table_add_column_with_if_expression.sql.txt

+61-77
Original file line numberDiff line numberDiff line change
@@ -32,92 +32,76 @@ ALTER TABLE foo ADD COLUMN expired_at TIMESTAMP AS (IF (status != "OPEN" AND sta
3232
As: 48,
3333
Stored: 153,
3434
Rparen: 151,
35-
Expr: &ast.CallExpr{
35+
Expr: &ast.IfExpr{
36+
If: 52,
3637
Rparen: 150,
37-
Func: &ast.Ident{
38-
NamePos: 52,
39-
NameEnd: 54,
40-
Name: "IF",
38+
Expr: &ast.BinaryExpr{
39+
Op: "AND",
40+
Left: &ast.BinaryExpr{
41+
Op: "!=",
42+
Left: &ast.Ident{
43+
NamePos: 56,
44+
NameEnd: 62,
45+
Name: "status",
46+
},
47+
Right: &ast.StringLiteral{
48+
ValuePos: 66,
49+
ValueEnd: 72,
50+
Value: "OPEN",
51+
},
52+
},
53+
Right: &ast.BinaryExpr{
54+
Op: "!=",
55+
Left: &ast.Ident{
56+
NamePos: 77,
57+
NameEnd: 83,
58+
Name: "status",
59+
},
60+
Right: &ast.StringLiteral{
61+
ValuePos: 87,
62+
ValueEnd: 99,
63+
Value: "SCHEDULING",
64+
},
65+
},
4166
},
42-
Distinct: false,
43-
Args: []ast.Arg{
44-
&ast.ExprArg{
45-
Expr: &ast.BinaryExpr{
46-
Op: "AND",
47-
Left: &ast.BinaryExpr{
48-
Op: "!=",
49-
Left: &ast.Ident{
50-
NamePos: 56,
51-
NameEnd: 62,
52-
Name: "status",
53-
},
54-
Right: &ast.StringLiteral{
55-
ValuePos: 66,
56-
ValueEnd: 72,
57-
Value: "OPEN",
58-
},
59-
},
60-
Right: &ast.BinaryExpr{
61-
Op: "!=",
62-
Left: &ast.Ident{
63-
NamePos: 77,
64-
NameEnd: 83,
65-
Name: "status",
66-
},
67-
Right: &ast.StringLiteral{
68-
ValuePos: 87,
69-
ValueEnd: 99,
70-
Value: "SCHEDULING",
71-
},
67+
TrueResult: &ast.CallExpr{
68+
Rparen: 143,
69+
Func: &ast.Ident{
70+
NamePos: 101,
71+
NameEnd: 114,
72+
Name: "TIMESTAMP_ADD",
73+
},
74+
Distinct: false,
75+
Args: []ast.Arg{
76+
&ast.ExprArg{
77+
Expr: &ast.Ident{
78+
NamePos: 115,
79+
NameEnd: 125,
80+
Name: "updated_at",
7281
},
7382
},
74-
},
75-
&ast.ExprArg{
76-
Expr: &ast.CallExpr{
77-
Rparen: 143,
78-
Func: &ast.Ident{
79-
NamePos: 101,
80-
NameEnd: 114,
81-
Name: "TIMESTAMP_ADD",
83+
&ast.IntervalArg{
84+
Interval: 127,
85+
Expr: &ast.IntLiteral{
86+
ValuePos: 136,
87+
ValueEnd: 139,
88+
Base: 10,
89+
Value: "120",
8290
},
83-
Distinct: false,
84-
Args: []ast.Arg{
85-
&ast.ExprArg{
86-
Expr: &ast.Ident{
87-
NamePos: 115,
88-
NameEnd: 125,
89-
Name: "updated_at",
90-
},
91-
},
92-
&ast.IntervalArg{
93-
Interval: 127,
94-
Expr: &ast.IntLiteral{
95-
ValuePos: 136,
96-
ValueEnd: 139,
97-
Base: 10,
98-
Value: "120",
99-
},
100-
Unit: &ast.Ident{
101-
NamePos: 140,
102-
NameEnd: 143,
103-
Name: "DAY",
104-
},
105-
},
91+
Unit: &ast.Ident{
92+
NamePos: 140,
93+
NameEnd: 143,
94+
Name: "DAY",
10695
},
107-
NamedArgs: []*ast.NamedArg(nil),
108-
NullHandling: nil,
109-
Having: nil,
110-
},
111-
},
112-
&ast.ExprArg{
113-
Expr: &ast.NullLiteral{
114-
Null: 146,
11596
},
11697
},
98+
NamedArgs: []*ast.NamedArg(nil),
99+
NullHandling: nil,
100+
Having: nil,
101+
},
102+
ElseResult: &ast.NullLiteral{
103+
Null: 146,
117104
},
118-
NamedArgs: []*ast.NamedArg(nil),
119-
NullHandling: nil,
120-
Having: nil,
121105
},
122106
},
123107
Hidden: -1,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--- edge_case_backquote_keyword.sql
2+
`IF` + `GRAPH_TABLE`
3+
--- AST
4+
&ast.BinaryExpr{
5+
Op: "+",
6+
Left: &ast.Ident{
7+
NamePos: 0,
8+
NameEnd: 4,
9+
Name: "IF",
10+
},
11+
Right: &ast.Ident{
12+
NamePos: 7,
13+
NameEnd: 20,
14+
Name: "GRAPH_TABLE",
15+
},
16+
}
17+
18+
--- SQL
19+
`IF` + `GRAPH_TABLE`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--- edge_case_backquote_non_keyword.sql
2+
`DATABASE` + `SCHEMA`
3+
--- AST
4+
&ast.BinaryExpr{
5+
Op: "+",
6+
Left: &ast.Ident{
7+
NamePos: 0,
8+
NameEnd: 10,
9+
Name: "DATABASE",
10+
},
11+
Right: &ast.Ident{
12+
NamePos: 13,
13+
NameEnd: 21,
14+
Name: "SCHEMA",
15+
},
16+
}
17+
18+
--- SQL
19+
DATABASE + SCHEMA

testdata/result/query/select_expr.sql.txt

+26-42
Original file line numberDiff line numberDiff line change
@@ -860,52 +860,36 @@ select 1 + 2, 1 - 2,
860860
&ast.Alias{
861861
Expr: &ast.BinaryExpr{
862862
Op: "+",
863-
Left: &ast.CallExpr{
863+
Left: &ast.IfExpr{
864+
If: 773,
864865
Rparen: 788,
865-
Func: &ast.Ident{
866-
NamePos: 773,
867-
NameEnd: 775,
868-
Name: "IF",
869-
},
870-
Distinct: false,
871-
Args: []ast.Arg{
872-
&ast.ExprArg{
873-
Expr: &ast.BinaryExpr{
874-
Op: ">",
875-
Left: &ast.IntLiteral{
876-
ValuePos: 777,
877-
ValueEnd: 778,
878-
Base: 10,
879-
Value: "1",
880-
},
881-
Right: &ast.IntLiteral{
882-
ValuePos: 781,
883-
ValueEnd: 782,
884-
Base: 10,
885-
Value: "1",
886-
},
887-
},
888-
},
889-
&ast.ExprArg{
890-
Expr: &ast.IntLiteral{
891-
ValuePos: 784,
892-
ValueEnd: 785,
893-
Base: 10,
894-
Value: "1",
895-
},
866+
Expr: &ast.BinaryExpr{
867+
Op: ">",
868+
Left: &ast.IntLiteral{
869+
ValuePos: 777,
870+
ValueEnd: 778,
871+
Base: 10,
872+
Value: "1",
896873
},
897-
&ast.ExprArg{
898-
Expr: &ast.IntLiteral{
899-
ValuePos: 787,
900-
ValueEnd: 788,
901-
Base: 10,
902-
Value: "2",
903-
},
874+
Right: &ast.IntLiteral{
875+
ValuePos: 781,
876+
ValueEnd: 782,
877+
Base: 10,
878+
Value: "1",
904879
},
905880
},
906-
NamedArgs: []*ast.NamedArg(nil),
907-
NullHandling: nil,
908-
Having: nil,
881+
TrueResult: &ast.IntLiteral{
882+
ValuePos: 784,
883+
ValueEnd: 785,
884+
Base: 10,
885+
Value: "1",
886+
},
887+
ElseResult: &ast.IntLiteral{
888+
ValuePos: 787,
889+
ValueEnd: 788,
890+
Base: 10,
891+
Value: "2",
892+
},
909893
},
910894
Right: &ast.IntLiteral{
911895
ValuePos: 790,

0 commit comments

Comments
 (0)