Skip to content

Commit 3ecb2c7

Browse files
authored
Add support of parsing map literal and query parameter (#94)
1 parent da1392e commit 3ecb2c7

File tree

7 files changed

+616
-4
lines changed

7 files changed

+616
-4
lines changed

parser/ast.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2844,6 +2844,92 @@ func (f *ParamExprList) Accept(visitor ASTVisitor) error {
28442844
return visitor.VisitParamExprList(f)
28452845
}
28462846

2847+
type KeyValue struct {
2848+
Key StringLiteral
2849+
Value Expr
2850+
}
2851+
2852+
type MapLiteral struct {
2853+
LBracePos Pos
2854+
RBracePos Pos
2855+
KeyValues []KeyValue
2856+
}
2857+
2858+
func (m *MapLiteral) Pos() Pos {
2859+
return m.LBracePos
2860+
}
2861+
2862+
func (m *MapLiteral) End() Pos {
2863+
return m.RBracePos
2864+
}
2865+
2866+
func (m *MapLiteral) String(level int) string {
2867+
var builder strings.Builder
2868+
builder.WriteString("{")
2869+
2870+
for i, value := range m.KeyValues {
2871+
if i > 0 {
2872+
builder.WriteString(", ")
2873+
}
2874+
builder.WriteString(value.Key.String(level))
2875+
builder.WriteString(": ")
2876+
builder.WriteString(value.Value.String(level))
2877+
}
2878+
builder.WriteString("}")
2879+
return builder.String()
2880+
}
2881+
2882+
func (m *MapLiteral) Accept(visitor ASTVisitor) error {
2883+
visitor.enter(m)
2884+
defer visitor.leave(m)
2885+
for _, kv := range m.KeyValues {
2886+
if err := kv.Key.Accept(visitor); err != nil {
2887+
return err
2888+
}
2889+
if err := kv.Value.Accept(visitor); err != nil {
2890+
return err
2891+
}
2892+
}
2893+
return visitor.VisitMapLiteral(m)
2894+
}
2895+
2896+
type QueryParam struct {
2897+
LBracePos Pos
2898+
RBracePos Pos
2899+
Name *Ident
2900+
Type Expr
2901+
}
2902+
2903+
func (q *QueryParam) Pos() Pos {
2904+
return q.LBracePos
2905+
}
2906+
2907+
func (q *QueryParam) End() Pos {
2908+
return q.RBracePos
2909+
}
2910+
2911+
func (q *QueryParam) String(level int) string {
2912+
var builder strings.Builder
2913+
builder.WriteString("{")
2914+
builder.WriteString(q.Name.String(level))
2915+
builder.WriteString(": ")
2916+
builder.WriteString(q.Type.String(level))
2917+
builder.WriteString("}")
2918+
return builder.String()
2919+
}
2920+
2921+
func (q *QueryParam) Accept(visitor ASTVisitor) error {
2922+
visitor.enter(q)
2923+
defer visitor.leave(q)
2924+
if err := q.Name.Accept(visitor); err != nil {
2925+
return err
2926+
}
2927+
if err := q.Type.Accept(visitor); err != nil {
2928+
return err
2929+
}
2930+
return visitor.VisitQueryParam(q)
2931+
}
2932+
28472933
type ArrayParamList struct {
28482934
LeftBracketPos Pos
28492935
RightBracketPos Pos

parser/ast_visitor.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ type ASTVisitor interface {
6565
VisitSettingsExpr(expr *SettingExprList) error
6666
VisitSettingsExprList(expr *SettingsClause) error
6767
VisitParamExprList(expr *ParamExprList) error
68+
VisitMapLiteral(expr *MapLiteral) error
6869
VisitArrayParamList(expr *ArrayParamList) error
70+
VisitQueryParam(expr *QueryParam) error
6971
VisitObjectParams(expr *ObjectParams) error
7072
VisitFunctionExpr(expr *FunctionExpr) error
7173
VisitWindowFunctionExpr(expr *WindowFunctionExpr) error
@@ -624,6 +626,20 @@ func (v *DefaultASTVisitor) VisitArrayParamList(expr *ArrayParamList) error {
624626
return nil
625627
}
626628

629+
func (v *DefaultASTVisitor) VisitQueryParam(expr *QueryParam) error {
630+
if v.Visit != nil {
631+
return v.Visit(expr)
632+
}
633+
return nil
634+
}
635+
636+
func (v *DefaultASTVisitor) VisitMapLiteral(expr *MapLiteral) error {
637+
if v.Visit != nil {
638+
return v.Visit(expr)
639+
}
640+
return nil
641+
}
642+
627643
func (v *DefaultASTVisitor) VisitObjectParams(expr *ObjectParams) error {
628644
if v.Visit != nil {
629645
return v.Visit(expr)

parser/parser_column.go

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,17 @@ func (p *Parser) parseUnaryExpr(pos Pos) (Expr, error) {
325325

326326
}
327327

328+
func (p *Parser) peekTokenKind(kind TokenKind) bool {
329+
if p.lexer.isEOF() {
330+
return false
331+
}
332+
token, err := p.lexer.peekToken()
333+
if err != nil || token == nil {
334+
return false
335+
}
336+
return token.Kind == kind
337+
}
338+
328339
func (p *Parser) parseColumnExpr(pos Pos) (Expr, error) { //nolint:funlen
329340
switch {
330341
case p.matchKeyword(KeywordInterval):
@@ -357,12 +368,18 @@ func (p *Parser) parseColumnExpr(pos Pos) (Expr, error) { //nolint:funlen
357368
return p.parseSelectQuery(pos)
358369
}
359370
}
360-
return p.parseFunctionParams(pos)
371+
return p.parseFunctionParams(p.Pos())
361372
case p.matchTokenKind("*"):
362-
return p.parseColumnStar(pos)
373+
return p.parseColumnStar(p.Pos())
363374
case p.matchTokenKind("["):
364-
return p.parseArrayParams(pos)
365-
375+
return p.parseArrayParams(p.Pos())
376+
case p.matchTokenKind("{"):
377+
// The map literal string also starts with '{', so we need to check the next token
378+
// to determine if it is a map literal or a query param.
379+
if p.peekTokenKind(TokenIdent) {
380+
return p.parseQueryParam(p.Pos())
381+
}
382+
return p.parseMapLiteral(p.Pos())
366383
default:
367384
return nil, fmt.Errorf("unexpected token kind: %s", p.lastTokenKind())
368385
}
@@ -561,6 +578,71 @@ func (p *Parser) parseFunctionParams(pos Pos) (*ParamExprList, error) {
561578
return paramExprList, nil
562579
}
563580

581+
func (p *Parser) parseMapLiteral(pos Pos) (*MapLiteral, error) {
582+
if _, err := p.consumeTokenKind("{"); err != nil {
583+
return nil, err
584+
}
585+
586+
keyValues := make([]KeyValue, 0)
587+
for !p.lexer.isEOF() && !p.matchTokenKind("}") {
588+
key, err := p.parseString(p.Pos())
589+
if err != nil {
590+
return nil, err
591+
}
592+
if _, err := p.consumeTokenKind(":"); err != nil {
593+
return nil, err
594+
}
595+
value, err := p.parseExpr(p.Pos())
596+
if err != nil {
597+
return nil, err
598+
}
599+
keyValues = append(keyValues, KeyValue{
600+
Key: *key,
601+
Value: value,
602+
})
603+
if p.tryConsumeTokenKind(",") == nil {
604+
break
605+
}
606+
}
607+
rightBracePos := p.Pos()
608+
if _, err := p.consumeTokenKind("}"); err != nil {
609+
return nil, err
610+
}
611+
return &MapLiteral{
612+
LBracePos: pos,
613+
RBracePos: rightBracePos,
614+
KeyValues: keyValues,
615+
}, nil
616+
}
617+
618+
func (p *Parser) parseQueryParam(pos Pos) (*QueryParam, error) {
619+
if _, err := p.consumeTokenKind("{"); err != nil {
620+
return nil, err
621+
}
622+
623+
ident, err := p.parseIdent()
624+
if err != nil {
625+
return nil, err
626+
}
627+
if _, err := p.consumeTokenKind(":"); err != nil {
628+
return nil, err
629+
}
630+
columnType, err := p.parseColumnType(p.Pos())
631+
if err != nil {
632+
return nil, err
633+
}
634+
rightBracePos := p.Pos()
635+
if _, err := p.consumeTokenKind("}"); err != nil {
636+
return nil, err
637+
}
638+
return &QueryParam{
639+
LBracePos: pos,
640+
RBracePos: rightBracePos,
641+
Name: ident,
642+
Type: columnType,
643+
}, nil
644+
}
645+
564646
func (p *Parser) parseArrayParams(pos Pos) (*ArrayParamList, error) {
565647
if _, err := p.consumeTokenKind("["); err != nil {
566648
return nil, err

parser/parser_table.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,12 @@ func (p *Parser) parseSettingsExprList(pos Pos) (*SettingExprList, error) {
797797
if err != nil {
798798
return nil, err
799799
}
800+
case p.matchTokenKind("{"):
801+
m, err := p.parseMapLiteral(p.Pos())
802+
if err != nil {
803+
return nil, err
804+
}
805+
expr = m
800806
default:
801807
return nil, fmt.Errorf("unexpected token: %q, expected <number> or <string>", p.last().String)
802808
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
-- Origin SQL:
2+
SET param_a = 13;
3+
SET param_b = 'str';
4+
SET param_c = '2022-08-04 18:30:53';
5+
SET param_d = {'10': [11, 12], '13': [14, 15]};
6+
7+
SELECT
8+
{a: UInt32},
9+
{b: String},
10+
{c: DateTime},
11+
{d: Map(String, Array(UInt8))};
12+
13+
SELECT * FROM clickhouse WHERE tenant_id = {tenant_id: String};
14+
15+
16+
-- Format SQL:
17+
SET param_a=13;
18+
SET param_b='str';
19+
SET param_c='2022-08-04 18:30:53';
20+
SET param_d={'10': [11, 12], '13': [14, 15]};
21+
22+
SELECT
23+
{a: UInt32},
24+
{b: String},
25+
{c: DateTime},
26+
{d: Map(String,Array(UInt8))};
27+
28+
SELECT
29+
*
30+
FROM
31+
clickhouse
32+
WHERE
33+
tenant_id = {tenant_id: String};

0 commit comments

Comments
 (0)