Skip to content

Commit 57ee598

Browse files
ajitpratap0Ajit Pratap Singh
andauthored
feat(parser): support ClickHouse bare-bracket array literals (#482) (#485)
ClickHouse accepts `[1, 2, 3]` as a shorthand for `array(1, 2, 3)`. Add a small parsePrimaryExpression branch (gated to the ClickHouse dialect to avoid colliding with subscript usage in other dialects) that delegates to a new parseBracketArrayLiteral helper. The helper mirrors the existing parseArrayConstructor square-bracket path. Part of #482 (ClickHouse parser gaps from QA sweep). Co-authored-by: Ajit Pratap Singh <ajitpratapsingh@Ajits-Mac-mini-2655.local>
1 parent 6d5182c commit 57ee598

File tree

3 files changed

+74
-0
lines changed

3 files changed

+74
-0
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2026 GoSQLX Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
5+
package parser_test
6+
7+
import (
8+
"testing"
9+
10+
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
11+
"github.com/ajitpratap0/GoSQLX/pkg/sql/keywords"
12+
)
13+
14+
// TestClickHouseArrayLiteral verifies that the bare-bracket array literal
15+
// `[1, 2, 3]` parses in the ClickHouse dialect. ClickHouse supports this as
16+
// a shorthand for `array(1, 2, 3)`. Regression for #482.
17+
func TestClickHouseArrayLiteral(t *testing.T) {
18+
queries := map[string]string{
19+
"int_literal": `SELECT [1, 2, 3] AS nums`,
20+
"string_literal": `SELECT ['a', 'b', 'c'] AS words`,
21+
"empty": `SELECT [] AS empty`,
22+
"nested": `SELECT [[1, 2], [3, 4]] AS matrix`,
23+
"in_function": `SELECT arrayJoin([10, 20, 30]) AS x`,
24+
"mixed_with_col": `SELECT id, [status, type] AS labels FROM events`,
25+
}
26+
for name, q := range queries {
27+
q := q
28+
t.Run(name, func(t *testing.T) {
29+
if _, err := gosqlx.ParseWithDialect(q, keywords.DialectClickHouse); err != nil {
30+
t.Fatalf("ParseWithDialect failed: %v", err)
31+
}
32+
})
33+
}
34+
}

pkg/sql/parser/expressions_complex.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,3 +332,36 @@ func (p *Parser) parseArrayConstructor() (*ast.ArrayConstructorExpression, error
332332

333333
return nil, p.expectedError("[ or (")
334334
}
335+
336+
// parseBracketArrayLiteral parses a ClickHouse-style bare bracket array
337+
// literal: [expr, expr, ...]. The opening '[' is the current token.
338+
func (p *Parser) parseBracketArrayLiteral() (*ast.ArrayConstructorExpression, error) {
339+
p.advance() // Consume [
340+
341+
arrayExpr := ast.GetArrayConstructor()
342+
343+
if !p.isType(models.TokenTypeRBracket) {
344+
for {
345+
elem, err := p.parseExpression()
346+
if err != nil {
347+
return nil, err
348+
}
349+
arrayExpr.Elements = append(arrayExpr.Elements, elem)
350+
351+
if p.isType(models.TokenTypeComma) {
352+
p.advance()
353+
} else if p.isType(models.TokenTypeRBracket) {
354+
break
355+
} else {
356+
return nil, p.expectedError(", or ]")
357+
}
358+
}
359+
}
360+
361+
if !p.isType(models.TokenTypeRBracket) {
362+
return nil, p.expectedError("]")
363+
}
364+
p.advance() // Consume ]
365+
366+
return arrayExpr, nil
367+
}

pkg/sql/parser/expressions_literal.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ func (p *Parser) parsePrimaryExpression() (ast.Expression, error) {
7171
return p.parseArrayConstructor()
7272
}
7373

74+
// ClickHouse array literal: [expr, expr, ...] without the ARRAY keyword.
75+
// Gated to ClickHouse to avoid colliding with subscript-style usage in other
76+
// dialects.
77+
if p.isType(models.TokenTypeLBracket) && p.dialect == string(keywords.DialectClickHouse) {
78+
return p.parseBracketArrayLiteral()
79+
}
80+
7481
// Handle MySQL VALUES(column) helper in ON DUPLICATE KEY UPDATE.
7582
// VALUES is normally a DML keyword, but inside ON DUPLICATE KEY UPDATE it acts
7683
// as a scalar function that returns the value that was attempted for insertion.

0 commit comments

Comments
 (0)