Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions parser/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -3340,6 +3340,43 @@ func (w *WindowFunctionExpr) Accept(visitor ASTVisitor) error {
return visitor.VisitWindowFunctionExpr(w)
}

type TypedPlaceholder struct {
LeftBracePos Pos
RightBracePos Pos
Name *Ident
Type ColumnType
}

func (t *TypedPlaceholder) Pos() Pos {
return t.LeftBracePos
}

func (t *TypedPlaceholder) End() Pos {
return t.RightBracePos
}

func (t *TypedPlaceholder) String() string {
var builder strings.Builder
builder.WriteString("{")
builder.WriteString(t.Name.String())
builder.WriteByte(':')
builder.WriteString(t.Type.String())
builder.WriteString("}")
return builder.String()
}

func (t *TypedPlaceholder) Accept(visitor ASTVisitor) error {
visitor.enter(t)
defer visitor.leave(t)
if err := t.Name.Accept(visitor); err != nil {
return err
}
if err := t.Type.Accept(visitor); err != nil {
return err
}
return visitor.VisitTypedPlaceholder(t)
}

type ColumnExpr struct {
Expr Expr
Alias *Ident
Expand Down
8 changes: 8 additions & 0 deletions parser/ast_visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ type ASTVisitor interface {
VisitWindowFunctionExpr(expr *WindowFunctionExpr) error
VisitColumnDef(expr *ColumnDef) error
VisitColumnExpr(expr *ColumnExpr) error
VisitTypedPlaceholder(expr *TypedPlaceholder) error
VisitScalarType(expr *ScalarType) error
VisitJSONType(expr *JSONType) error
VisitPropertyType(expr *PropertyType) error
Expand Down Expand Up @@ -711,6 +712,13 @@ func (v *DefaultASTVisitor) VisitColumnExpr(expr *ColumnExpr) error {
return nil
}

func (v *DefaultASTVisitor) VisitTypedPlaceholder(expr *TypedPlaceholder) error {
if v.Visit != nil {
return v.Visit(expr)
}
return nil
}

func (v *DefaultASTVisitor) VisitScalarType(expr *ScalarType) error {
if v.Visit != nil {
return v.Visit(expr)
Expand Down
31 changes: 31 additions & 0 deletions parser/parser_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -1202,6 +1202,34 @@ func (p *Parser) parseColumnNamesExpr(pos Pos) (*ColumnNamesExpr, error) {
}, nil
}

func (p *Parser) parseTypedPlaceholder(pos Pos) (Expr, error) {
if _, err := p.expectTokenKind(TokenKindLBrace); err != nil {
return nil, err
}

name, err := p.parseIdent()
if err != nil {
return nil, err
}
if _, err := p.expectTokenKind(TokenKindColon); err != nil {
return nil, err
}
columnType, err := p.parseColumnType(p.Pos())
if err != nil {
return nil, err
}

if _, err := p.expectTokenKind(TokenKindRBrace); err != nil {
return nil, err
}
return &TypedPlaceholder{
LeftBracePos: pos,
RightBracePos: p.Pos(),
Name: name,
Type: columnType,
}, nil
}

func (p *Parser) parseAssignmentValues(pos Pos) (*AssignmentValues, error) {
if _, err := p.expectTokenKind(TokenKindLParen); err != nil {
return nil, err
Expand All @@ -1214,6 +1242,9 @@ func (p *Parser) parseAssignmentValues(pos Pos) (*AssignmentValues, error) {
switch {
case p.matchTokenKind(TokenKindLParen):
value, err = p.parseAssignmentValues(p.Pos())
case p.matchTokenKind(TokenKindLBrace):
// placeholder with type, e.g. {a :Int32}, {b :DateTime(6)}
value, err = p.parseTypedPlaceholder(p.Pos())
default:
value, err = p.parseExpr(p.Pos())
}
Expand Down
5 changes: 5 additions & 0 deletions parser/testdata/dml/format/insert_with_placeholder.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ INSERT INTO t0(user_id, message, timestamp, metric) VALUES
(?, ?, ?, ?),
(?, ?, ?, ?),
(?, ?, ?, ?)
;

INSERT INTO test_with_typed_columns (id, created_at)
VALUES ({id: Int32}, {created_at: DateTime64(6)});

-- Format SQL:
INSERT INTO TABLE t0 (user_id, message, timestamp, metric) VALUES (?, ?, ?, ?), (?, ?, ?, ?), (?, ?, ?, ?), (?, ?, ?, ?);
INSERT INTO TABLE test_with_typed_columns (id, created_at) VALUES ({id:Int32}, {created_at:DateTime64(6)});
6 changes: 5 additions & 1 deletion parser/testdata/dml/insert_with_placeholder.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ INSERT INTO t0(user_id, message, timestamp, metric) VALUES
(?, ?, ?, ?),
(?, ?, ?, ?),
(?, ?, ?, ?),
(?, ?, ?, ?)
(?, ?, ?, ?)
;

INSERT INTO test_with_typed_columns (id, created_at)
VALUES ({id: Int32}, {created_at: DateTime64(6)});
92 changes: 92 additions & 0 deletions parser/testdata/dml/output/insert_with_placeholder.sql.golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,5 +160,97 @@
}
],
"SelectExpr": null
},
{
"InsertPos": 133,
"Format": null,
"Table": {
"Database": null,
"Table": {
"Name": "test_with_typed_columns",
"QuoteType": 1,
"NamePos": 145,
"NameEnd": 168
}
},
"ColumnNames": {
"LeftParenPos": 169,
"RightParenPos": 184,
"ColumnNames": [
{
"Ident": {
"Name": "id",
"QuoteType": 1,
"NamePos": 170,
"NameEnd": 172
},
"DotIdent": null
},
{
"Ident": {
"Name": "created_at",
"QuoteType": 1,
"NamePos": 174,
"NameEnd": 184
},
"DotIdent": null
}
]
},
"Values": [
{
"LeftParenPos": 193,
"RightParenPos": 234,
"Values": [
{
"LeftBracePos": 194,
"RightBracePos": 205,
"Name": {
"Name": "id",
"QuoteType": 1,
"NamePos": 195,
"NameEnd": 197
},
"Type": {
"Name": {
"Name": "Int32",
"QuoteType": 1,
"NamePos": 199,
"NameEnd": 204
}
}
},
{
"LeftBracePos": 207,
"RightBracePos": 234,
"Name": {
"Name": "created_at",
"QuoteType": 1,
"NamePos": 208,
"NameEnd": 218
},
"Type": {
"LeftParenPos": 231,
"RightParenPos": 232,
"Name": {
"Name": "DateTime64",
"QuoteType": 1,
"NamePos": 220,
"NameEnd": 230
},
"Params": [
{
"NumPos": 231,
"NumEnd": 232,
"Literal": "6",
"Base": 10
}
]
}
}
]
}
],
"SelectExpr": null
}
]