Skip to content

Commit

Permalink
parser: support for LIKE/ILIKE (no validation or evaluation)
Browse files Browse the repository at this point in the history
  • Loading branch information
kokes committed Sep 10, 2021
1 parent ff697f6 commit 2fc0514
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 4 deletions.
11 changes: 7 additions & 4 deletions src/query/expr/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ var precedences = map[tokenType]int{
tokenNeq: EQUALS,
tokenIn: EQUALS,
tokenNot: EQUALS,
tokenLike: EQUALS,
tokenIlike: EQUALS,
tokenLt: LESSGREATER,
tokenGt: LESSGREATER,
tokenLte: LESSGREATER,
Expand Down Expand Up @@ -107,6 +109,8 @@ func NewParser(s string) (*Parser, error) {
tokenEq: p.parseInfixExpression,
tokenIs: p.parseInfixExpression,
tokenNeq: p.parseInfixExpression,
tokenLike: p.parseInfixExpression,
tokenIlike: p.parseInfixExpression,
tokenIn: p.parseInfixExpression,
tokenNot: p.parseInfixExpression,
tokenLt: p.parseInfixExpression,
Expand Down Expand Up @@ -265,8 +269,8 @@ func (p *Parser) parseInfixExpression(left Expression) Expression {
p.position++

// IS NOT => NOT
// TODO(like): && (p.cur == tokenNot || p.cur == tokenLike || p.cur == tokenIlike)
// expr.operator = p.cur
// ARCH/COMPAT: maybe this whole IS IN, IS NOT IN, IS LIKE etc. are not supported (at least I can't get them to work in pg)
// it would certainly simplify a lot of code over here
if expr.operator == tokenIs && p.curToken().ttype == tokenNot {
expr.operator = tokenNot
p.position++
Expand All @@ -276,8 +280,7 @@ func (p *Parser) parseInfixExpression(left Expression) Expression {
// and a weird one, because it turns an infix operation to a prefix one (`foo NOT IN bar` -> `NOT(foo IN bar)`)
// but we also have to support a range of expressions: foo not true, foo is not true, foo is in bar, foo is not in bar, ...
if expr.operator == tokenNot {
// TODO(like): p.curToken().ttype == tokenIn || p.curToken().ttype == tokenLike || p.curToken().ttype == tokenIlike
if p.curToken().ttype == tokenIn {
if p.curToken().ttype == tokenIn || p.curToken().ttype == tokenLike || p.curToken().ttype == tokenIlike {
infix := p.parseInfixExpression(expr.left)

return &Prefix{operator: tokenNot, right: infix}
Expand Down
20 changes: 20 additions & 0 deletions src/query/expr/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,26 @@ func TestParsingContents(t *testing.T) {
right: &Integer{value: 4},
},
}},
{"foo like '%ahoy%'", &Infix{operator: tokenLike,
left: &Identifier{Name: "foo"},
right: &String{value: "%ahoy%"},
}},
{"foo not like '%ahoy%'", &Prefix{operator: tokenNot,
right: &Infix{operator: tokenLike,
left: &Identifier{Name: "foo"},
right: &String{value: "%ahoy%"},
},
}},
{"foo ilike '%ahoy%'", &Infix{operator: tokenIlike,
left: &Identifier{Name: "foo"},
right: &String{value: "%ahoy%"},
}},
{"foo not ilike '%ahoy%'", &Prefix{operator: tokenNot,
right: &Infix{operator: tokenIlike,
left: &Identifier{Name: "foo"},
right: &String{value: "%ahoy%"},
},
}},

// prefix and infix
{"-4 / foo", &Infix{operator: tokenQuo,
Expand Down
6 changes: 6 additions & 0 deletions src/query/expr/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,12 @@ func (ex *Infix) ReturnType(ts column.TableSchema) (column.Schema, error) {
}
schema.Dtype = column.DtypeBool
schema.Nullable = t1.Nullable || t2.Nullable
case tokenLike, tokenIlike:
if _, ok := ex.right.(*String); !ok {
return schema, errTypeMismatch // ARCH: specify more? wrap?
}
schema.Dtype = column.DtypeBool
schema.Nullable = t1.Nullable
case tokenAdd, tokenSub, tokenMul, tokenQuo:
if !comparableTypes(t1.Dtype, t2.Dtype) {
return schema, errTypeMismatch
Expand Down

0 comments on commit 2fc0514

Please sign in to comment.