Skip to content

Commit 4955a88

Browse files
authored
Add support of the typed placeholder parameters for INSERT statement (#151)
The sample can refer to: ```SQL INSERT INTO TABLE test_with_typed_columns (id, created_at) VALUES ({id:Int32}, {created_at:DateTime64(6)}); ```
1 parent 5e4c15e commit 4955a88

File tree

6 files changed

+178
-1
lines changed

6 files changed

+178
-1
lines changed

parser/ast.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3340,6 +3340,43 @@ func (w *WindowFunctionExpr) Accept(visitor ASTVisitor) error {
33403340
return visitor.VisitWindowFunctionExpr(w)
33413341
}
33423342

3343+
type TypedPlaceholder struct {
3344+
LeftBracePos Pos
3345+
RightBracePos Pos
3346+
Name *Ident
3347+
Type ColumnType
3348+
}
3349+
3350+
func (t *TypedPlaceholder) Pos() Pos {
3351+
return t.LeftBracePos
3352+
}
3353+
3354+
func (t *TypedPlaceholder) End() Pos {
3355+
return t.RightBracePos
3356+
}
3357+
3358+
func (t *TypedPlaceholder) String() string {
3359+
var builder strings.Builder
3360+
builder.WriteString("{")
3361+
builder.WriteString(t.Name.String())
3362+
builder.WriteByte(':')
3363+
builder.WriteString(t.Type.String())
3364+
builder.WriteString("}")
3365+
return builder.String()
3366+
}
3367+
3368+
func (t *TypedPlaceholder) Accept(visitor ASTVisitor) error {
3369+
visitor.enter(t)
3370+
defer visitor.leave(t)
3371+
if err := t.Name.Accept(visitor); err != nil {
3372+
return err
3373+
}
3374+
if err := t.Type.Accept(visitor); err != nil {
3375+
return err
3376+
}
3377+
return visitor.VisitTypedPlaceholder(t)
3378+
}
3379+
33433380
type ColumnExpr struct {
33443381
Expr Expr
33453382
Alias *Ident

parser/ast_visitor.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ type ASTVisitor interface {
7777
VisitWindowFunctionExpr(expr *WindowFunctionExpr) error
7878
VisitColumnDef(expr *ColumnDef) error
7979
VisitColumnExpr(expr *ColumnExpr) error
80+
VisitTypedPlaceholder(expr *TypedPlaceholder) error
8081
VisitScalarType(expr *ScalarType) error
8182
VisitJSONType(expr *JSONType) error
8283
VisitPropertyType(expr *PropertyType) error
@@ -711,6 +712,13 @@ func (v *DefaultASTVisitor) VisitColumnExpr(expr *ColumnExpr) error {
711712
return nil
712713
}
713714

715+
func (v *DefaultASTVisitor) VisitTypedPlaceholder(expr *TypedPlaceholder) error {
716+
if v.Visit != nil {
717+
return v.Visit(expr)
718+
}
719+
return nil
720+
}
721+
714722
func (v *DefaultASTVisitor) VisitScalarType(expr *ScalarType) error {
715723
if v.Visit != nil {
716724
return v.Visit(expr)

parser/parser_table.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,34 @@ func (p *Parser) parseColumnNamesExpr(pos Pos) (*ColumnNamesExpr, error) {
12021202
}, nil
12031203
}
12041204

1205+
func (p *Parser) parseTypedPlaceholder(pos Pos) (Expr, error) {
1206+
if _, err := p.expectTokenKind(TokenKindLBrace); err != nil {
1207+
return nil, err
1208+
}
1209+
1210+
name, err := p.parseIdent()
1211+
if err != nil {
1212+
return nil, err
1213+
}
1214+
if _, err := p.expectTokenKind(TokenKindColon); err != nil {
1215+
return nil, err
1216+
}
1217+
columnType, err := p.parseColumnType(p.Pos())
1218+
if err != nil {
1219+
return nil, err
1220+
}
1221+
1222+
if _, err := p.expectTokenKind(TokenKindRBrace); err != nil {
1223+
return nil, err
1224+
}
1225+
return &TypedPlaceholder{
1226+
LeftBracePos: pos,
1227+
RightBracePos: p.Pos(),
1228+
Name: name,
1229+
Type: columnType,
1230+
}, nil
1231+
}
1232+
12051233
func (p *Parser) parseAssignmentValues(pos Pos) (*AssignmentValues, error) {
12061234
if _, err := p.expectTokenKind(TokenKindLParen); err != nil {
12071235
return nil, err
@@ -1214,6 +1242,9 @@ func (p *Parser) parseAssignmentValues(pos Pos) (*AssignmentValues, error) {
12141242
switch {
12151243
case p.matchTokenKind(TokenKindLParen):
12161244
value, err = p.parseAssignmentValues(p.Pos())
1245+
case p.matchTokenKind(TokenKindLBrace):
1246+
// placeholder with type, e.g. {a :Int32}, {b :DateTime(6)}
1247+
value, err = p.parseTypedPlaceholder(p.Pos())
12171248
default:
12181249
value, err = p.parseExpr(p.Pos())
12191250
}

parser/testdata/dml/format/insert_with_placeholder.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ INSERT INTO t0(user_id, message, timestamp, metric) VALUES
44
(?, ?, ?, ?),
55
(?, ?, ?, ?),
66
(?, ?, ?, ?)
7+
;
8+
9+
INSERT INTO test_with_typed_columns (id, created_at)
10+
VALUES ({id: Int32}, {created_at: DateTime64(6)});
711

812
-- Format SQL:
913
INSERT INTO TABLE t0 (user_id, message, timestamp, metric) VALUES (?, ?, ?, ?), (?, ?, ?, ?), (?, ?, ?, ?), (?, ?, ?, ?);
14+
INSERT INTO TABLE test_with_typed_columns (id, created_at) VALUES ({id:Int32}, {created_at:DateTime64(6)});

parser/testdata/dml/insert_with_placeholder.sql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@ INSERT INTO t0(user_id, message, timestamp, metric) VALUES
22
(?, ?, ?, ?),
33
(?, ?, ?, ?),
44
(?, ?, ?, ?),
5-
(?, ?, ?, ?)
5+
(?, ?, ?, ?)
6+
;
7+
8+
INSERT INTO test_with_typed_columns (id, created_at)
9+
VALUES ({id: Int32}, {created_at: DateTime64(6)});

parser/testdata/dml/output/insert_with_placeholder.sql.golden.json

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,5 +160,97 @@
160160
}
161161
],
162162
"SelectExpr": null
163+
},
164+
{
165+
"InsertPos": 133,
166+
"Format": null,
167+
"Table": {
168+
"Database": null,
169+
"Table": {
170+
"Name": "test_with_typed_columns",
171+
"QuoteType": 1,
172+
"NamePos": 145,
173+
"NameEnd": 168
174+
}
175+
},
176+
"ColumnNames": {
177+
"LeftParenPos": 169,
178+
"RightParenPos": 184,
179+
"ColumnNames": [
180+
{
181+
"Ident": {
182+
"Name": "id",
183+
"QuoteType": 1,
184+
"NamePos": 170,
185+
"NameEnd": 172
186+
},
187+
"DotIdent": null
188+
},
189+
{
190+
"Ident": {
191+
"Name": "created_at",
192+
"QuoteType": 1,
193+
"NamePos": 174,
194+
"NameEnd": 184
195+
},
196+
"DotIdent": null
197+
}
198+
]
199+
},
200+
"Values": [
201+
{
202+
"LeftParenPos": 193,
203+
"RightParenPos": 234,
204+
"Values": [
205+
{
206+
"LeftBracePos": 194,
207+
"RightBracePos": 205,
208+
"Name": {
209+
"Name": "id",
210+
"QuoteType": 1,
211+
"NamePos": 195,
212+
"NameEnd": 197
213+
},
214+
"Type": {
215+
"Name": {
216+
"Name": "Int32",
217+
"QuoteType": 1,
218+
"NamePos": 199,
219+
"NameEnd": 204
220+
}
221+
}
222+
},
223+
{
224+
"LeftBracePos": 207,
225+
"RightBracePos": 234,
226+
"Name": {
227+
"Name": "created_at",
228+
"QuoteType": 1,
229+
"NamePos": 208,
230+
"NameEnd": 218
231+
},
232+
"Type": {
233+
"LeftParenPos": 231,
234+
"RightParenPos": 232,
235+
"Name": {
236+
"Name": "DateTime64",
237+
"QuoteType": 1,
238+
"NamePos": 220,
239+
"NameEnd": 230
240+
},
241+
"Params": [
242+
{
243+
"NumPos": 231,
244+
"NumEnd": 232,
245+
"Literal": "6",
246+
"Base": 10
247+
}
248+
]
249+
}
250+
}
251+
]
252+
}
253+
],
254+
"SelectExpr": null
163255
}
164256
]

0 commit comments

Comments
 (0)