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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:

strategy:
matrix:
go-version: [1.18.x]
go-version: [1.21.x]
os: [ ubuntu-latest ]
runs-on: ${{ matrix.os }}

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/AfterShip/clickhouse-sql-parser

go 1.18
go 1.21.0

require (
github.com/sebdah/goldie/v2 v2.5.3
Expand Down
47 changes: 7 additions & 40 deletions parser/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -6422,6 +6422,13 @@ func (j *JoinExpr) Pos() Pos {
}

func (j *JoinExpr) End() Pos {
// Return the rightmost position
if j.Right != nil {
return j.Right.End()
}
if j.Constraints != nil {
return j.Constraints.End()
}
return j.Left.End()
}

Expand Down Expand Up @@ -7237,36 +7244,6 @@ func (f *WindowFrameParam) Accept(visitor ASTVisitor) error {
return visitor.VisitWindowFrameParam(f)
}

type ArrayJoinClause struct {
ArrayPos Pos
Type string
Expr Expr
}

func (a *ArrayJoinClause) Pos() Pos {
return a.ArrayPos
}

func (a *ArrayJoinClause) End() Pos {
return a.Expr.End()
}

func (a *ArrayJoinClause) String() string {
if a.Type != "" {
return a.Type + " ARRAY JOIN " + a.Expr.String()
}
return "ARRAY JOIN " + a.Expr.String()
}

func (a *ArrayJoinClause) Accept(visitor ASTVisitor) error {
visitor.Enter(a)
defer visitor.Leave(a)
if err := a.Expr.Accept(visitor); err != nil {
return err
}
return visitor.VisitArrayJoinExpr(a)
}

type SelectQuery struct {
SelectPos Pos
StatementEnd Pos
Expand All @@ -7276,7 +7253,6 @@ type SelectQuery struct {
DistinctOn *DistinctOn
SelectItems []*SelectItem
From *FromClause
ArrayJoin []*ArrayJoinClause
Window *WindowClause
Prewhere *PrewhereClause
Where *WhereClause
Expand Down Expand Up @@ -7337,10 +7313,6 @@ func (s *SelectQuery) String() string { // nolint: funlen
builder.WriteString(" ")
builder.WriteString(s.From.String())
}
for _, arrayJoin := range s.ArrayJoin {
builder.WriteString(" ")
builder.WriteString(arrayJoin.String())
}
if s.Window != nil {
builder.WriteString(" ")
builder.WriteString(s.Window.String())
Expand Down Expand Up @@ -7419,11 +7391,6 @@ func (s *SelectQuery) Accept(visitor ASTVisitor) error {
return err
}
}
for _, arrayJoin := range s.ArrayJoin {
if err := arrayJoin.Accept(visitor); err != nil {
return err
}
}
if s.Window != nil {
if err := s.Window.Accept(visitor); err != nil {
return err
Expand Down
8 changes: 0 additions & 8 deletions parser/ast_visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ type ASTVisitor interface {
VisitWindowFrameUnbounded(expr *WindowFrameUnbounded) error
VisitWindowFrameNumber(expr *WindowFrameNumber) error
VisitWindowFrameParam(expr *WindowFrameParam) error
VisitArrayJoinExpr(expr *ArrayJoinClause) error
VisitSelectQuery(expr *SelectQuery) error
VisitSubQueryExpr(expr *SubQuery) error
VisitNotExpr(expr *NotExpr) error
Expand Down Expand Up @@ -1270,13 +1269,6 @@ func (v *DefaultASTVisitor) VisitWindowFrameParam(expr *WindowFrameParam) error
return nil
}

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

func (v *DefaultASTVisitor) VisitSelectQuery(expr *SelectQuery) error {
if v.Visit != nil {
return v.Visit(expr)
Expand Down
94 changes: 44 additions & 50 deletions parser/parser_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package parser
import (
"errors"
"fmt"

"slices"
)

func (p *Parser) tryParseWithClause(pos Pos) (*WithClause, error) {
Expand Down Expand Up @@ -196,11 +198,11 @@ func (p *Parser) parseJoinOp(_ Pos) []string {
case p.matchKeyword(KeywordInner):
modifiers = append(modifiers, p.last().String)
_ = p.lexer.consumeToken()
if p.matchKeyword(KeywordAll) || p.matchKeyword(KeywordAny) || p.matchKeyword(KeywordAsof) {
if p.matchKeyword(KeywordAll) || p.matchKeyword(KeywordAny) || p.matchKeyword(KeywordAsof) || p.matchKeyword(KeywordArray) {
modifiers = append(modifiers, p.last().String)
_ = p.lexer.consumeToken()
}
case p.matchKeyword(KeywordLeft), p.matchKeyword(KeywordRight):
case p.matchKeyword(KeywordLeft):
modifiers = append(modifiers, p.last().String)
_ = p.lexer.consumeToken()
if p.matchKeyword(KeywordOuter) {
Expand All @@ -213,6 +215,19 @@ func (p *Parser) parseJoinOp(_ Pos) []string {
modifiers = append(modifiers, p.last().String)
_ = p.lexer.consumeToken()
}
case p.matchKeyword(KeywordRight):
modifiers = append(modifiers, p.last().String)
_ = p.lexer.consumeToken()
if p.matchKeyword(KeywordOuter) {
modifiers = append(modifiers, p.last().String)
_ = p.lexer.consumeToken()
}
if p.matchKeyword(KeywordSemi) || p.matchKeyword(KeywordAnti) ||
p.matchKeyword(KeywordAny) || p.matchKeyword(KeywordAll) ||
p.matchKeyword(KeywordAsof) {
modifiers = append(modifiers, p.last().String)
_ = p.lexer.consumeToken()
}
case p.matchKeyword(KeywordFull):
modifiers = append(modifiers, p.last().String)
_ = p.lexer.consumeToken()
Expand All @@ -224,6 +239,9 @@ func (p *Parser) parseJoinOp(_ Pos) []string {
modifiers = append(modifiers, p.last().String)
_ = p.lexer.consumeToken()
}
case p.matchKeyword(KeywordArray):
modifiers = append(modifiers, p.last().String)
_ = p.lexer.consumeToken()
}
return modifiers
}
Expand Down Expand Up @@ -281,6 +299,30 @@ func (p *Parser) parseJoinRightExpr(pos Pos) (expr Expr, err error) {
}

modifiers = append(modifiers, KeywordJoin)

// Check if this is an ARRAY JOIN
if slices.Contains(modifiers, KeywordArray) {
// For ARRAY JOIN, parse column expression list instead of table expression
expr, err = p.parseColumnExprList(p.Pos())
if err != nil {
return nil, err
}

// ARRAY JOIN doesn't have constraints (ON/USING)
// try parse next join
rightExpr, err = p.parseJoinRightExpr(p.Pos())
if err != nil {
return nil, err
}
return &JoinExpr{
JoinPos: pos,
Left: expr,
Right: rightExpr,
Modifiers: modifiers,
Constraints: nil,
}, nil
}

expr, err = p.parseJoinTableExpr(p.Pos())
if err != nil {
return nil, err
Expand Down Expand Up @@ -852,41 +894,6 @@ func (p *Parser) parseWindowClause(pos Pos) (*WindowClause, error) {
}, nil
}

func (p *Parser) tryParseArrayJoinClause(pos Pos) (*ArrayJoinClause, error) {
if !p.matchKeyword(KeywordLeft) && !p.matchKeyword(KeywordInner) && !p.matchKeyword(KeywordArray) {
return nil, nil
}
return p.parseArrayJoinClause(pos)
}

func (p *Parser) parseArrayJoinClause(_ Pos) (*ArrayJoinClause, error) {
var typ string
switch {
case p.matchKeyword(KeywordLeft), p.matchKeyword(KeywordInner):
typ = p.last().String
_ = p.lexer.consumeToken()
}
arrayPos := p.Pos()
if err := p.expectKeyword(KeywordArray); err != nil {
return nil, err
}

if err := p.expectKeyword(KeywordJoin); err != nil {
return nil, err
}

expr, err := p.parseColumnExprList(p.Pos())
if err != nil {
return nil, err
}

return &ArrayJoinClause{
ArrayPos: arrayPos,
Type: typ,
Expr: expr,
}, nil
}

func (p *Parser) tryParseHavingClause(pos Pos) (*HavingClause, error) {
if !p.matchKeyword(KeywordHaving) {
return nil, nil
Expand Down Expand Up @@ -1009,18 +1016,6 @@ func (p *Parser) parseSelectStmt(pos Pos) (*SelectQuery, error) { // nolint: fun
if from != nil {
statementEnd = from.End()
}
var arrayJoins []*ArrayJoinClause
for {
arrayJoin, err := p.tryParseArrayJoinClause(p.Pos())
if err != nil {
return nil, err
}
if arrayJoin == nil {
break
}
arrayJoins = append(arrayJoins, arrayJoin)
statementEnd = arrayJoin.End()
}
prewhere, err := p.tryParsePrewhereClause(p.Pos())
if err != nil {
return nil, err
Expand Down Expand Up @@ -1129,7 +1124,6 @@ func (p *Parser) parseSelectStmt(pos Pos) (*SelectQuery, error) { // nolint: fun
DistinctOn: distinctOn,
SelectItems: selectItems,
From: from,
ArrayJoin: arrayJoins,
Window: window,
Prewhere: prewhere,
Where: where,
Expand Down
3 changes: 3 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ func TestParser_InvalidSyntax(t *testing.T) {
"SELECT n FROM t ORDER BY n WITH FILL INTERPOLATE (x", // Missing closing paren
"SELECT n FROM t ORDER BY n WITH FILL INTERPOLATE x AS x + 1", // Missing parens around column list
"ALTER TABLE foo_mv MODIFY QUERY AS SELECT * FROM baz", // MODIFY QUERY followed by an invalid query
// Invalid ARRAY JOIN types (only ARRAY JOIN, LEFT ARRAY JOIN, and INNER ARRAY JOIN are valid)
"SELECT * FROM t RIGHT ARRAY JOIN arr AS a", // RIGHT ARRAY JOIN not supported
"SELECT * FROM t FULL ARRAY JOIN arr AS a", // FULL ARRAY JOIN not supported
}
for _, sql := range invalidSQLs {
parser := NewParser(sql)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@
}
],
"From": null,
"ArrayJoin": null,
"Window": null,
"Prewhere": null,
"Where": null,
Expand Down
1 change: 0 additions & 1 deletion parser/testdata/ddl/output/bug_001.sql.golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,6 @@
"HasFinal": false
}
},
"ArrayJoin": null,
"Window": null,
"Prewhere": null,
"Where": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@
"HasFinal": false
}
},
"ArrayJoin": null,
"Window": null,
"Prewhere": null,
"Where": null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,6 @@
"HasFinal": false
}
},
"ArrayJoin": null,
"Window": null,
"Prewhere": null,
"Where": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,6 @@
}
],
"From": null,
"ArrayJoin": null,
"Window": null,
"Prewhere": null,
"Where": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,6 @@
"HasFinal": false
}
},
"ArrayJoin": null,
"Window": null,
"Prewhere": null,
"Where": {
Expand Down Expand Up @@ -519,7 +518,6 @@
"HasFinal": false
}
},
"ArrayJoin": null,
"Window": null,
"Prewhere": null,
"Where": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@
"HasFinal": false
}
},
"ArrayJoin": null,
"Window": null,
"Prewhere": null,
"Where": null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@
}
],
"From": null,
"ArrayJoin": null,
"Window": null,
"Prewhere": null,
"Where": null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,6 @@
"HasFinal": false
}
},
"ArrayJoin": null,
"Window": null,
"Prewhere": null,
"Where": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@
"HasFinal": false
}
},
"ArrayJoin": null,
"Window": null,
"Prewhere": null,
"Where": null,
Expand Down Expand Up @@ -274,7 +273,6 @@
"HasFinal": false
}
},
"ArrayJoin": null,
"Window": null,
"Prewhere": null,
"Where": null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,6 @@
"HasFinal": false
}
},
"ArrayJoin": null,
"Window": null,
"Prewhere": null,
"Where": null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@
"HasFinal": false
}
},
"ArrayJoin": null,
"Window": null,
"Prewhere": null,
"Where": null,
Expand Down
Loading