Skip to content

Commit f58d935

Browse files
ajitpratap0Ajit Pratap Singh
andauthored
feat(parser): LIKE ANY/ALL and ILIKE ANY/ALL for Snowflake (#483) (#500)
Co-authored-by: Ajit Pratap Singh <ajitpratapsingh@Ajits-Mac-mini-2655.local>
1 parent 670dd7e commit f58d935

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

pkg/sql/parser/expressions_operators.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,30 @@ func (p *Parser) parseComparisonExpression() (ast.Expression, error) {
110110
}
111111
p.advance() // Consume LIKE/ILIKE
112112

113+
// Snowflake LIKE ANY / LIKE ALL / ILIKE ANY / ILIKE ALL:
114+
// expr [NOT] LIKE ANY ('pattern1', 'pattern2', ...)
115+
// expr [NOT] ILIKE ALL ('%a%', '%b%')
116+
// The ANY/ALL quantifier is followed by a parenthesised tuple.
117+
if p.isType(models.TokenTypeAny) || p.isType(models.TokenTypeAll) {
118+
quantifier := strings.ToUpper(p.currentToken.Token.Value)
119+
operator = strings.ToUpper(operator) + " " + quantifier
120+
p.advance() // Consume ANY/ALL
121+
// Expect a tuple: (pattern, pattern, ...)
122+
if !p.isType(models.TokenTypeLParen) {
123+
return nil, p.expectedError("( after " + quantifier)
124+
}
125+
tuple, err := p.parsePrimaryExpression()
126+
if err != nil {
127+
return nil, err
128+
}
129+
return &ast.BinaryExpression{
130+
Left: left,
131+
Operator: operator,
132+
Right: tuple,
133+
Not: notPrefix,
134+
}, nil
135+
}
136+
113137
// Parse pattern
114138
pattern, err := p.parsePrimaryExpression()
115139
if err != nil {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
// TestSnowflakeLikeAnyAll verifies LIKE ANY/ALL and ILIKE ANY/ALL parse in
15+
// the Snowflake dialect. Regression for #483.
16+
func TestSnowflakeLikeAnyAll(t *testing.T) {
17+
queries := map[string]string{
18+
"like_any": `SELECT * FROM users WHERE name LIKE ANY ('%alice%', '%bob%')`,
19+
"like_all": `SELECT * FROM users WHERE name LIKE ALL ('%a%', '%b%')`,
20+
"ilike_any": `SELECT * FROM events WHERE msg ILIKE ANY ('%error%', '%warn%')`,
21+
"not_like_any": `SELECT * FROM users WHERE name NOT LIKE ANY ('%test%', '%demo%')`,
22+
"not_ilike_all": `SELECT * FROM users WHERE name NOT ILIKE ALL ('%a%', '%b%')`,
23+
}
24+
for name, q := range queries {
25+
q := q
26+
t.Run(name, func(t *testing.T) {
27+
if _, err := gosqlx.ParseWithDialect(q, keywords.DialectSnowflake); err != nil {
28+
t.Fatalf("parse failed: %v", err)
29+
}
30+
})
31+
}
32+
}

0 commit comments

Comments
 (0)