Support antlr as plan parser (#16696)

Signed-off-by: dragondriver <jiquan.long@zilliz.com>

Co-authored-by: xaxys <tpnnghd@163.com>

Co-authored-by: xaxys <tpnnghd@163.com>
pull/16814/head
Jiquan Long 2022-05-06 17:43:51 +08:00 committed by GitHub
parent b0053b7a45
commit 98ceb162aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 8671 additions and 305 deletions

1
go.mod
View File

@ -7,6 +7,7 @@ require (
github.com/HdrHistogram/hdrhistogram-go v1.0.1 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/antonmedv/expr v1.8.9
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e // indirect
github.com/apache/arrow/go/v8 v8.0.0-20220322092137-778b1772fd20
github.com/apache/pulsar-client-go v0.6.1-0.20210728062540-29414db801a7
github.com/apache/pulsar-client-go/oauth2 v0.0.0-20201120111947-b8bd55bc02bd // indirect

2
go.sum
View File

@ -72,6 +72,8 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e h1:GCzyKMDDjSGnlpl3clrdAK7I1AaVoaiKDOYkUzChZzg=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
github.com/antonmedv/expr v1.8.9 h1:O9stiHmHHww9b4ozhPx7T6BK7fXfOCHJ8ybxf0833zw=
github.com/antonmedv/expr v1.8.9/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8=
github.com/apache/arrow/go/v8 v8.0.0-20220322092137-778b1772fd20 h1:YcSFhAin12rxRsvvfzD6gepH7jZwtFVdikXRyhzUC2w=

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,131 @@
grammar Plan;
expr:
IntegerConstant # Integer
| FloatingConstant # Floating
| BooleanConstant # Boolean
| StringLiteral # String
| Identifier # Identifier
| '(' expr ')' # Parens
| expr LIKE StringLiteral # Like
| expr POW expr # Power
| op = (ADD | SUB | BNOT | NOT) expr # Unary
// | '(' typeName ')' expr # Cast
| expr op = (MUL | DIV | MOD) expr # MulDivMod
| expr op = (ADD | SUB) expr # AddSub
| expr op = (SHL | SHR) expr # Shift
| expr op = (IN | NIN) ('[' expr (',' expr)* ','? ']') # Term
| expr op = (IN | NIN) EmptyTerm # EmptyTerm
| expr op1 = (LT | LE) expr op2 = (LT | LE) expr # Range
| expr op1 = (GT | GE) expr op2 = (GT | GE) expr # ReverseRange
| expr op = (LT | LE | GT | GE) expr # Relational
| expr op = (EQ | NE) expr # Equality
| expr BAND expr # BitAnd
| expr BXOR expr # BitXor
| expr BOR expr # BitOr
| expr AND expr # LogicalAnd
| expr OR expr # LogicalOr;
// typeName: ty = (BOOL | INT8 | INT16 | INT32 | INT64 | FLOAT | DOUBLE);
// BOOL: 'bool';
// INT8: 'int8';
// INT16: 'int16';
// INT32: 'int32';
// INT64: 'int64';
// FLOAT: 'float';
// DOUBLE: 'double';
LT: '<';
LE: '<=';
GT: '>';
GE: '>=';
EQ: '==';
NE: '!=';
LIKE: 'like' | 'LIKE';
ADD: '+';
SUB: '-';
MUL: '*';
DIV: '/';
MOD: '%';
POW: '**';
SHL: '<<';
SHR: '>>';
BAND: '&';
BOR: '|';
BXOR: '^';
AND: '&&' | 'and';
OR: '||' | 'or';
BNOT: '~';
NOT: '!' | 'not';
IN: 'in';
NIN: 'not in';
EmptyTerm: '[' (Whitespace | Newline)* ']';
BooleanConstant: 'true' | 'True' | 'TRUE' | 'false' | 'False' | 'FALSE';
IntegerConstant:
DecimalConstant
| OctalConstant
| HexadecimalConstant
| BinaryConstant;
FloatingConstant:
DecimalFloatingConstant
| HexadecimalFloatingConstant;
Identifier: Nondigit (Nondigit | Digit)*;
StringLiteral: EncodingPrefix? '"' SCharSequence? '"';
fragment EncodingPrefix: 'u8' | 'u' | 'U' | 'L';
fragment SCharSequence: SChar+;
fragment SChar: ~["\\\r\n] | EscapeSequence | '\\\n' | '\\\r\n';
fragment Nondigit: [a-zA-Z_];
fragment Digit: [0-9];
fragment BinaryConstant: '0' [bB] [0-1]+;
fragment DecimalConstant: NonzeroDigit Digit*;
fragment OctalConstant: '0' OctalDigit*;
fragment HexadecimalConstant: '0' [xX] HexadecimalDigitSequence;
fragment NonzeroDigit: [1-9];
fragment OctalDigit: [0-7];
fragment HexadecimalDigit: [0-9a-fA-F];
fragment HexQuad:
HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit;
fragment UniversalCharacterName:
'\\u' HexQuad
| '\\U' HexQuad HexQuad;
fragment DecimalFloatingConstant:
FractionalConstant ExponentPart?
| DigitSequence ExponentPart;
fragment HexadecimalFloatingConstant:
'0' [xX] (
HexadecimalFractionalConstant
| HexadecimalDigitSequence
) BinaryExponentPart;
fragment FractionalConstant:
DigitSequence? '.' DigitSequence
| DigitSequence '.';
fragment ExponentPart: [eE] [+-]? DigitSequence;
fragment DigitSequence: Digit+;
fragment HexadecimalFractionalConstant:
HexadecimalDigitSequence? '.' HexadecimalDigitSequence
| HexadecimalDigitSequence '.';
fragment HexadecimalDigitSequence: HexadecimalDigit+;
fragment BinaryExponentPart: [pP] [+-]? DigitSequence;
fragment EscapeSequence:
'\\' ['"?abfnrtv\\]
| '\\' OctalDigit OctalDigit? OctalDigit?
| '\\x' HexadecimalDigitSequence
| UniversalCharacterName;
Whitespace: [ \t]+ -> skip;
Newline: ( '\r' '\n'? | '\n') -> skip;

View File

@ -0,0 +1,23 @@
# Generate Parser with Antlr4
## Install Antlr4
Please follow [install antlr4](https://github.com/antlr/antlr4/blob/master/doc/go-target.md) to install the antlr tool.
The version of antlr tool: `4.9`.
## Code Generate
After you install the antlr4, you can generate the parser code in golang with:
```shell
export CLASSPATH=".:${PWD}/antlr-4.9-complete.jar:$CLASSPATH"
alias antlr4='java -Xmx500M -cp "${PWD}/antlr-4.9-complete.jar:$CLASSPATH" org.antlr.v4.Tool'
alias grun='java -Xmx500M -cp "${PWD}/antlr-4.9-complete.jar:$CLASSPATH" org.antlr.v4.gui.TestRig'
```
```shell
antlr4 -Dlanguage=Go -package planparserv2 -o generated -no-listener -visitor Plan.g4
```
All generated code will be under directory `generated`.

View File

@ -0,0 +1,15 @@
package planparserv2
import (
"reflect"
"github.com/milvus-io/milvus/internal/proto/planpb"
)
// CheckIdentical check if two exprs are identical.
func CheckIdentical(expr, other *planpb.Expr) bool {
v := NewShowExprVisitor()
js1 := v.VisitExpr(expr)
js2 := v.VisitExpr(other)
return reflect.DeepEqual(js1, js2)
}

View File

@ -0,0 +1,26 @@
package planparserv2
import (
"testing"
"github.com/milvus-io/milvus/internal/util/typeutil"
"github.com/stretchr/testify/assert"
)
func TestCheckIdentical(t *testing.T) {
schema := newTestSchema()
helper, err := typeutil.CreateSchemaHelper(schema)
assert.NoError(t, err)
exprStr1 := `not (((Int64Field > 0) and (FloatField <= 20.0)) or ((Int32Field in [1, 2, 3]) and (VarCharField < "str")))`
exprStr2 := `Int32Field in [1, 2, 3]`
expr1, err := ParseExpr(helper, exprStr1)
assert.NoError(t, err)
expr2, err := ParseExpr(helper, exprStr2)
assert.NoError(t, err)
assert.True(t, CheckIdentical(expr1, expr1))
assert.True(t, CheckIdentical(expr2, expr2))
assert.False(t, CheckIdentical(expr1, expr2))
}

View File

@ -0,0 +1,17 @@
package planparserv2
import (
"fmt"
"strconv"
"github.com/antlr/antlr4/runtime/Go/antlr"
)
type errorListener struct {
*antlr.DefaultErrorListener
err error
}
func (l *errorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) {
l.err = fmt.Errorf("line " + strconv.Itoa(line) + ":" + strconv.Itoa(column) + " " + msg)
}

View File

@ -0,0 +1,8 @@
package planparserv2
const float64EqualityThreshold = 1e-9
func floatingEqual(a, b float64) bool {
// return math.Abs(a-b) <= float64EqualityThreshold
return a == b
}

View File

@ -0,0 +1,44 @@
package planparserv2
import "testing"
func Test_floatingEqual(t *testing.T) {
type args struct {
a float64
b float64
}
tests := []struct {
name string
args args
want bool
}{
{
args: args{
a: 1.0,
b: 1.0,
},
want: true,
},
{
args: args{
a: 1.0,
b: 2.0,
},
want: false,
},
{
args: args{
a: 0.000000001,
b: 0,
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := floatingEqual(tt.args.a, tt.args.b); got != tt.want {
t.Errorf("floatingEqual() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -0,0 +1,86 @@
token literal names:
null
'('
')'
'['
','
']'
'<'
'<='
'>'
'>='
'=='
'!='
null
'+'
'-'
'*'
'/'
'%'
'**'
'<<'
'>>'
'&'
'|'
'^'
null
null
'~'
null
'in'
'not in'
null
null
null
null
null
null
null
null
token symbolic names:
null
null
null
null
null
null
LT
LE
GT
GE
EQ
NE
LIKE
ADD
SUB
MUL
DIV
MOD
POW
SHL
SHR
BAND
BOR
BXOR
AND
OR
BNOT
NOT
IN
NIN
EmptyTerm
BooleanConstant
IntegerConstant
FloatingConstant
Identifier
StringLiteral
Whitespace
Newline
rule names:
expr
atn:
[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 39, 91, 4, 2, 9, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 5, 2, 17, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 7, 2, 73, 10, 2, 12, 2, 14, 2, 76, 11, 2, 3, 2, 5, 2, 79, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 7, 2, 86, 10, 2, 12, 2, 14, 2, 89, 11, 2, 3, 2, 2, 3, 2, 3, 2, 2, 11, 4, 2, 15, 16, 28, 29, 3, 2, 17, 19, 3, 2, 15, 16, 3, 2, 21, 22, 3, 2, 8, 9, 3, 2, 10, 11, 3, 2, 8, 11, 3, 2, 12, 13, 3, 2, 30, 31, 2, 113, 2, 16, 3, 2, 2, 2, 4, 5, 8, 2, 1, 2, 5, 17, 7, 34, 2, 2, 6, 17, 7, 35, 2, 2, 7, 17, 7, 33, 2, 2, 8, 17, 7, 37, 2, 2, 9, 17, 7, 36, 2, 2, 10, 11, 7, 3, 2, 2, 11, 12, 5, 2, 2, 2, 12, 13, 7, 4, 2, 2, 13, 17, 3, 2, 2, 2, 14, 15, 9, 2, 2, 2, 15, 17, 5, 2, 2, 17, 16, 4, 3, 2, 2, 2, 16, 6, 3, 2, 2, 2, 16, 7, 3, 2, 2, 2, 16, 8, 3, 2, 2, 2, 16, 9, 3, 2, 2, 2, 16, 10, 3, 2, 2, 2, 16, 14, 3, 2, 2, 2, 17, 87, 3, 2, 2, 2, 18, 19, 12, 18, 2, 2, 19, 20, 7, 20, 2, 2, 20, 86, 5, 2, 2, 19, 21, 22, 12, 16, 2, 2, 22, 23, 9, 3, 2, 2, 23, 86, 5, 2, 2, 17, 24, 25, 12, 15, 2, 2, 25, 26, 9, 4, 2, 2, 26, 86, 5, 2, 2, 16, 27, 28, 12, 14, 2, 2, 28, 29, 9, 5, 2, 2, 29, 86, 5, 2, 2, 15, 30, 31, 12, 11, 2, 2, 31, 32, 9, 6, 2, 2, 32, 33, 5, 2, 2, 2, 33, 34, 9, 6, 2, 2, 34, 35, 5, 2, 2, 12, 35, 86, 3, 2, 2, 2, 36, 37, 12, 10, 2, 2, 37, 38, 9, 7, 2, 2, 38, 39, 5, 2, 2, 2, 39, 40, 9, 7, 2, 2, 40, 41, 5, 2, 2, 11, 41, 86, 3, 2, 2, 2, 42, 43, 12, 9, 2, 2, 43, 44, 9, 8, 2, 2, 44, 86, 5, 2, 2, 10, 45, 46, 12, 8, 2, 2, 46, 47, 9, 9, 2, 2, 47, 86, 5, 2, 2, 9, 48, 49, 12, 7, 2, 2, 49, 50, 7, 23, 2, 2, 50, 86, 5, 2, 2, 8, 51, 52, 12, 6, 2, 2, 52, 53, 7, 25, 2, 2, 53, 86, 5, 2, 2, 7, 54, 55, 12, 5, 2, 2, 55, 56, 7, 24, 2, 2, 56, 86, 5, 2, 2, 6, 57, 58, 12, 4, 2, 2, 58, 59, 7, 26, 2, 2, 59, 86, 5, 2, 2, 5, 60, 61, 12, 3, 2, 2, 61, 62, 7, 27, 2, 2, 62, 86, 5, 2, 2, 4, 63, 64, 12, 19, 2, 2, 64, 65, 7, 14, 2, 2, 65, 86, 7, 37, 2, 2, 66, 67, 12, 13, 2, 2, 67, 68, 9, 10, 2, 2, 68, 69, 7, 5, 2, 2, 69, 74, 5, 2, 2, 2, 70, 71, 7, 6, 2, 2, 71, 73, 5, 2, 2, 2, 72, 70, 3, 2, 2, 2, 73, 76, 3, 2, 2, 2, 74, 72, 3, 2, 2, 2, 74, 75, 3, 2, 2, 2, 75, 78, 3, 2, 2, 2, 76, 74, 3, 2, 2, 2, 77, 79, 7, 6, 2, 2, 78, 77, 3, 2, 2, 2, 78, 79, 3, 2, 2, 2, 79, 80, 3, 2, 2, 2, 80, 81, 7, 7, 2, 2, 81, 86, 3, 2, 2, 2, 82, 83, 12, 12, 2, 2, 83, 84, 9, 10, 2, 2, 84, 86, 7, 32, 2, 2, 85, 18, 3, 2, 2, 2, 85, 21, 3, 2, 2, 2, 85, 24, 3, 2, 2, 2, 85, 27, 3, 2, 2, 2, 85, 30, 3, 2, 2, 2, 85, 36, 3, 2, 2, 2, 85, 42, 3, 2, 2, 2, 85, 45, 3, 2, 2, 2, 85, 48, 3, 2, 2, 2, 85, 51, 3, 2, 2, 2, 85, 54, 3, 2, 2, 2, 85, 57, 3, 2, 2, 2, 85, 60, 3, 2, 2, 2, 85, 63, 3, 2, 2, 2, 85, 66, 3, 2, 2, 2, 85, 82, 3, 2, 2, 2, 86, 89, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 87, 88, 3, 2, 2, 2, 88, 3, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 7, 16, 74, 78, 85, 87]

View File

@ -0,0 +1,62 @@
T__0=1
T__1=2
T__2=3
T__3=4
T__4=5
LT=6
LE=7
GT=8
GE=9
EQ=10
NE=11
LIKE=12
ADD=13
SUB=14
MUL=15
DIV=16
MOD=17
POW=18
SHL=19
SHR=20
BAND=21
BOR=22
BXOR=23
AND=24
OR=25
BNOT=26
NOT=27
IN=28
NIN=29
EmptyTerm=30
BooleanConstant=31
IntegerConstant=32
FloatingConstant=33
Identifier=34
StringLiteral=35
Whitespace=36
Newline=37
'('=1
')'=2
'['=3
','=4
']'=5
'<'=6
'<='=7
'>'=8
'>='=9
'=='=10
'!='=11
'+'=13
'-'=14
'*'=15
'/'=16
'%'=17
'**'=18
'<<'=19
'>>'=20
'&'=21
'|'=22
'^'=23
'~'=26
'in'=28
'not in'=29

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,62 @@
T__0=1
T__1=2
T__2=3
T__3=4
T__4=5
LT=6
LE=7
GT=8
GE=9
EQ=10
NE=11
LIKE=12
ADD=13
SUB=14
MUL=15
DIV=16
MOD=17
POW=18
SHL=19
SHR=20
BAND=21
BOR=22
BXOR=23
AND=24
OR=25
BNOT=26
NOT=27
IN=28
NIN=29
EmptyTerm=30
BooleanConstant=31
IntegerConstant=32
FloatingConstant=33
Identifier=34
StringLiteral=35
Whitespace=36
Newline=37
'('=1
')'=2
'['=3
','=4
']'=5
'<'=6
'<='=7
'>'=8
'>='=9
'=='=10
'!='=11
'+'=13
'-'=14
'*'=15
'/'=16
'%'=17
'**'=18
'<<'=19
'>>'=20
'&'=21
'|'=22
'^'=23
'~'=26
'in'=28
'not in'=29

View File

@ -0,0 +1,100 @@
// Code generated from Plan.g4 by ANTLR 4.9. DO NOT EDIT.
package planparserv2 // Plan
import "github.com/antlr/antlr4/runtime/Go/antlr"
type BasePlanVisitor struct {
*antlr.BaseParseTreeVisitor
}
func (v *BasePlanVisitor) VisitShift(ctx *ShiftContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitReverseRange(ctx *ReverseRangeContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitBitOr(ctx *BitOrContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitAddSub(ctx *AddSubContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitParens(ctx *ParensContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitRelational(ctx *RelationalContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitString(ctx *StringContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitTerm(ctx *TermContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitFloating(ctx *FloatingContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitRange(ctx *RangeContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitUnary(ctx *UnaryContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitLogicalOr(ctx *LogicalOrContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitInteger(ctx *IntegerContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitMulDivMod(ctx *MulDivModContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitIdentifier(ctx *IdentifierContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitBitXor(ctx *BitXorContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitLike(ctx *LikeContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitBitAnd(ctx *BitAndContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitLogicalAnd(ctx *LogicalAndContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitEmptyTerm(ctx *EmptyTermContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitEquality(ctx *EqualityContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitBoolean(ctx *BooleanContext) interface{} {
return v.VisitChildren(ctx)
}
func (v *BasePlanVisitor) VisitPower(ctx *PowerContext) interface{} {
return v.VisitChildren(ctx)
}

View File

@ -0,0 +1,333 @@
// Code generated from Plan.g4 by ANTLR 4.9. DO NOT EDIT.
package planparserv2
import (
"fmt"
"unicode"
"github.com/antlr/antlr4/runtime/Go/antlr"
)
// Suppress unused import error
var _ = fmt.Printf
var _ = unicode.IsLetter
var serializedLexerAtn = []uint16{
3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 39, 444,
8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7,
9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12,
4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4,
18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23,
9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9,
28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33,
4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4,
39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44,
9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9,
49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54,
4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4,
60, 9, 60, 4, 61, 9, 61, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5,
3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3,
10, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13,
3, 13, 3, 13, 3, 13, 3, 13, 5, 13, 158, 10, 13, 3, 14, 3, 14, 3, 15, 3,
15, 3, 16, 3, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 20,
3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3,
24, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 5, 25, 190, 10, 25, 3, 26, 3, 26,
3, 26, 3, 26, 5, 26, 196, 10, 26, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3,
28, 5, 28, 204, 10, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 30,
3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 31, 7, 31, 219, 10, 31, 12, 31, 14,
31, 222, 11, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32,
3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3,
32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32,
5, 32, 253, 10, 32, 3, 33, 3, 33, 3, 33, 3, 33, 5, 33, 259, 10, 33, 3,
34, 3, 34, 5, 34, 263, 10, 34, 3, 35, 3, 35, 3, 35, 7, 35, 268, 10, 35,
12, 35, 14, 35, 271, 11, 35, 3, 36, 5, 36, 274, 10, 36, 3, 36, 3, 36, 5,
36, 278, 10, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 37, 5, 37, 285, 10, 37,
3, 38, 6, 38, 288, 10, 38, 13, 38, 14, 38, 289, 3, 39, 3, 39, 3, 39, 3,
39, 3, 39, 3, 39, 3, 39, 5, 39, 299, 10, 39, 3, 40, 3, 40, 3, 41, 3, 41,
3, 42, 3, 42, 3, 42, 6, 42, 308, 10, 42, 13, 42, 14, 42, 309, 3, 43, 3,
43, 7, 43, 314, 10, 43, 12, 43, 14, 43, 317, 11, 43, 3, 44, 3, 44, 7, 44,
321, 10, 44, 12, 44, 14, 44, 324, 11, 44, 3, 45, 3, 45, 3, 45, 3, 45, 3,
46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 49, 3, 49, 3, 49,
3, 50, 3, 50, 3, 50, 3, 50, 3, 50, 3, 50, 3, 50, 3, 50, 3, 50, 3, 50, 5,
50, 351, 10, 50, 3, 51, 3, 51, 5, 51, 355, 10, 51, 3, 51, 3, 51, 3, 51,
5, 51, 360, 10, 51, 3, 52, 3, 52, 3, 52, 3, 52, 5, 52, 366, 10, 52, 3,
52, 3, 52, 3, 53, 5, 53, 371, 10, 53, 3, 53, 3, 53, 3, 53, 3, 53, 3, 53,
5, 53, 378, 10, 53, 3, 54, 3, 54, 5, 54, 382, 10, 54, 3, 54, 3, 54, 3,
55, 6, 55, 387, 10, 55, 13, 55, 14, 55, 388, 3, 56, 5, 56, 392, 10, 56,
3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 5, 56, 399, 10, 56, 3, 57, 6, 57, 402,
10, 57, 13, 57, 14, 57, 403, 3, 58, 3, 58, 5, 58, 408, 10, 58, 3, 58, 3,
58, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 5, 59, 417, 10, 59, 3, 59, 5, 59,
420, 10, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 5, 59, 427, 10, 59, 3,
60, 6, 60, 430, 10, 60, 13, 60, 14, 60, 431, 3, 60, 3, 60, 3, 61, 3, 61,
5, 61, 438, 10, 61, 3, 61, 5, 61, 441, 10, 61, 3, 61, 3, 61, 2, 2, 62,
3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23,
13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41,
22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59,
31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 73, 2, 75, 2, 77, 2,
79, 2, 81, 2, 83, 2, 85, 2, 87, 2, 89, 2, 91, 2, 93, 2, 95, 2, 97, 2, 99,
2, 101, 2, 103, 2, 105, 2, 107, 2, 109, 2, 111, 2, 113, 2, 115, 2, 117,
2, 119, 38, 121, 39, 3, 2, 17, 5, 2, 78, 78, 87, 87, 119, 119, 6, 2, 12,
12, 15, 15, 36, 36, 94, 94, 5, 2, 67, 92, 97, 97, 99, 124, 3, 2, 50, 59,
4, 2, 68, 68, 100, 100, 3, 2, 50, 51, 4, 2, 90, 90, 122, 122, 3, 2, 51,
59, 3, 2, 50, 57, 5, 2, 50, 59, 67, 72, 99, 104, 4, 2, 71, 71, 103, 103,
4, 2, 45, 45, 47, 47, 4, 2, 82, 82, 114, 114, 12, 2, 36, 36, 41, 41, 65,
65, 94, 94, 99, 100, 104, 104, 112, 112, 116, 116, 118, 118, 120, 120,
4, 2, 11, 11, 34, 34, 2, 467, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7,
3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2,
15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2,
2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2,
2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2,
2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3,
2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53,
3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2,
61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2,
2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 119, 3, 2, 2, 2, 2, 121, 3, 2,
2, 2, 3, 123, 3, 2, 2, 2, 5, 125, 3, 2, 2, 2, 7, 127, 3, 2, 2, 2, 9, 129,
3, 2, 2, 2, 11, 131, 3, 2, 2, 2, 13, 133, 3, 2, 2, 2, 15, 135, 3, 2, 2,
2, 17, 138, 3, 2, 2, 2, 19, 140, 3, 2, 2, 2, 21, 143, 3, 2, 2, 2, 23, 146,
3, 2, 2, 2, 25, 157, 3, 2, 2, 2, 27, 159, 3, 2, 2, 2, 29, 161, 3, 2, 2,
2, 31, 163, 3, 2, 2, 2, 33, 165, 3, 2, 2, 2, 35, 167, 3, 2, 2, 2, 37, 169,
3, 2, 2, 2, 39, 172, 3, 2, 2, 2, 41, 175, 3, 2, 2, 2, 43, 178, 3, 2, 2,
2, 45, 180, 3, 2, 2, 2, 47, 182, 3, 2, 2, 2, 49, 189, 3, 2, 2, 2, 51, 195,
3, 2, 2, 2, 53, 197, 3, 2, 2, 2, 55, 203, 3, 2, 2, 2, 57, 205, 3, 2, 2,
2, 59, 208, 3, 2, 2, 2, 61, 215, 3, 2, 2, 2, 63, 252, 3, 2, 2, 2, 65, 258,
3, 2, 2, 2, 67, 262, 3, 2, 2, 2, 69, 264, 3, 2, 2, 2, 71, 273, 3, 2, 2,
2, 73, 284, 3, 2, 2, 2, 75, 287, 3, 2, 2, 2, 77, 298, 3, 2, 2, 2, 79, 300,
3, 2, 2, 2, 81, 302, 3, 2, 2, 2, 83, 304, 3, 2, 2, 2, 85, 311, 3, 2, 2,
2, 87, 318, 3, 2, 2, 2, 89, 325, 3, 2, 2, 2, 91, 329, 3, 2, 2, 2, 93, 331,
3, 2, 2, 2, 95, 333, 3, 2, 2, 2, 97, 335, 3, 2, 2, 2, 99, 350, 3, 2, 2,
2, 101, 359, 3, 2, 2, 2, 103, 361, 3, 2, 2, 2, 105, 377, 3, 2, 2, 2, 107,
379, 3, 2, 2, 2, 109, 386, 3, 2, 2, 2, 111, 398, 3, 2, 2, 2, 113, 401,
3, 2, 2, 2, 115, 405, 3, 2, 2, 2, 117, 426, 3, 2, 2, 2, 119, 429, 3, 2,
2, 2, 121, 440, 3, 2, 2, 2, 123, 124, 7, 42, 2, 2, 124, 4, 3, 2, 2, 2,
125, 126, 7, 43, 2, 2, 126, 6, 3, 2, 2, 2, 127, 128, 7, 93, 2, 2, 128,
8, 3, 2, 2, 2, 129, 130, 7, 46, 2, 2, 130, 10, 3, 2, 2, 2, 131, 132, 7,
95, 2, 2, 132, 12, 3, 2, 2, 2, 133, 134, 7, 62, 2, 2, 134, 14, 3, 2, 2,
2, 135, 136, 7, 62, 2, 2, 136, 137, 7, 63, 2, 2, 137, 16, 3, 2, 2, 2, 138,
139, 7, 64, 2, 2, 139, 18, 3, 2, 2, 2, 140, 141, 7, 64, 2, 2, 141, 142,
7, 63, 2, 2, 142, 20, 3, 2, 2, 2, 143, 144, 7, 63, 2, 2, 144, 145, 7, 63,
2, 2, 145, 22, 3, 2, 2, 2, 146, 147, 7, 35, 2, 2, 147, 148, 7, 63, 2, 2,
148, 24, 3, 2, 2, 2, 149, 150, 7, 110, 2, 2, 150, 151, 7, 107, 2, 2, 151,
152, 7, 109, 2, 2, 152, 158, 7, 103, 2, 2, 153, 154, 7, 78, 2, 2, 154,
155, 7, 75, 2, 2, 155, 156, 7, 77, 2, 2, 156, 158, 7, 71, 2, 2, 157, 149,
3, 2, 2, 2, 157, 153, 3, 2, 2, 2, 158, 26, 3, 2, 2, 2, 159, 160, 7, 45,
2, 2, 160, 28, 3, 2, 2, 2, 161, 162, 7, 47, 2, 2, 162, 30, 3, 2, 2, 2,
163, 164, 7, 44, 2, 2, 164, 32, 3, 2, 2, 2, 165, 166, 7, 49, 2, 2, 166,
34, 3, 2, 2, 2, 167, 168, 7, 39, 2, 2, 168, 36, 3, 2, 2, 2, 169, 170, 7,
44, 2, 2, 170, 171, 7, 44, 2, 2, 171, 38, 3, 2, 2, 2, 172, 173, 7, 62,
2, 2, 173, 174, 7, 62, 2, 2, 174, 40, 3, 2, 2, 2, 175, 176, 7, 64, 2, 2,
176, 177, 7, 64, 2, 2, 177, 42, 3, 2, 2, 2, 178, 179, 7, 40, 2, 2, 179,
44, 3, 2, 2, 2, 180, 181, 7, 126, 2, 2, 181, 46, 3, 2, 2, 2, 182, 183,
7, 96, 2, 2, 183, 48, 3, 2, 2, 2, 184, 185, 7, 40, 2, 2, 185, 190, 7, 40,
2, 2, 186, 187, 7, 99, 2, 2, 187, 188, 7, 112, 2, 2, 188, 190, 7, 102,
2, 2, 189, 184, 3, 2, 2, 2, 189, 186, 3, 2, 2, 2, 190, 50, 3, 2, 2, 2,
191, 192, 7, 126, 2, 2, 192, 196, 7, 126, 2, 2, 193, 194, 7, 113, 2, 2,
194, 196, 7, 116, 2, 2, 195, 191, 3, 2, 2, 2, 195, 193, 3, 2, 2, 2, 196,
52, 3, 2, 2, 2, 197, 198, 7, 128, 2, 2, 198, 54, 3, 2, 2, 2, 199, 204,
7, 35, 2, 2, 200, 201, 7, 112, 2, 2, 201, 202, 7, 113, 2, 2, 202, 204,
7, 118, 2, 2, 203, 199, 3, 2, 2, 2, 203, 200, 3, 2, 2, 2, 204, 56, 3, 2,
2, 2, 205, 206, 7, 107, 2, 2, 206, 207, 7, 112, 2, 2, 207, 58, 3, 2, 2,
2, 208, 209, 7, 112, 2, 2, 209, 210, 7, 113, 2, 2, 210, 211, 7, 118, 2,
2, 211, 212, 7, 34, 2, 2, 212, 213, 7, 107, 2, 2, 213, 214, 7, 112, 2,
2, 214, 60, 3, 2, 2, 2, 215, 220, 7, 93, 2, 2, 216, 219, 5, 119, 60, 2,
217, 219, 5, 121, 61, 2, 218, 216, 3, 2, 2, 2, 218, 217, 3, 2, 2, 2, 219,
222, 3, 2, 2, 2, 220, 218, 3, 2, 2, 2, 220, 221, 3, 2, 2, 2, 221, 223,
3, 2, 2, 2, 222, 220, 3, 2, 2, 2, 223, 224, 7, 95, 2, 2, 224, 62, 3, 2,
2, 2, 225, 226, 7, 118, 2, 2, 226, 227, 7, 116, 2, 2, 227, 228, 7, 119,
2, 2, 228, 253, 7, 103, 2, 2, 229, 230, 7, 86, 2, 2, 230, 231, 7, 116,
2, 2, 231, 232, 7, 119, 2, 2, 232, 253, 7, 103, 2, 2, 233, 234, 7, 86,
2, 2, 234, 235, 7, 84, 2, 2, 235, 236, 7, 87, 2, 2, 236, 253, 7, 71, 2,
2, 237, 238, 7, 104, 2, 2, 238, 239, 7, 99, 2, 2, 239, 240, 7, 110, 2,
2, 240, 241, 7, 117, 2, 2, 241, 253, 7, 103, 2, 2, 242, 243, 7, 72, 2,
2, 243, 244, 7, 99, 2, 2, 244, 245, 7, 110, 2, 2, 245, 246, 7, 117, 2,
2, 246, 253, 7, 103, 2, 2, 247, 248, 7, 72, 2, 2, 248, 249, 7, 67, 2, 2,
249, 250, 7, 78, 2, 2, 250, 251, 7, 85, 2, 2, 251, 253, 7, 71, 2, 2, 252,
225, 3, 2, 2, 2, 252, 229, 3, 2, 2, 2, 252, 233, 3, 2, 2, 2, 252, 237,
3, 2, 2, 2, 252, 242, 3, 2, 2, 2, 252, 247, 3, 2, 2, 2, 253, 64, 3, 2,
2, 2, 254, 259, 5, 85, 43, 2, 255, 259, 5, 87, 44, 2, 256, 259, 5, 89,
45, 2, 257, 259, 5, 83, 42, 2, 258, 254, 3, 2, 2, 2, 258, 255, 3, 2, 2,
2, 258, 256, 3, 2, 2, 2, 258, 257, 3, 2, 2, 2, 259, 66, 3, 2, 2, 2, 260,
263, 5, 101, 51, 2, 261, 263, 5, 103, 52, 2, 262, 260, 3, 2, 2, 2, 262,
261, 3, 2, 2, 2, 263, 68, 3, 2, 2, 2, 264, 269, 5, 79, 40, 2, 265, 268,
5, 79, 40, 2, 266, 268, 5, 81, 41, 2, 267, 265, 3, 2, 2, 2, 267, 266, 3,
2, 2, 2, 268, 271, 3, 2, 2, 2, 269, 267, 3, 2, 2, 2, 269, 270, 3, 2, 2,
2, 270, 70, 3, 2, 2, 2, 271, 269, 3, 2, 2, 2, 272, 274, 5, 73, 37, 2, 273,
272, 3, 2, 2, 2, 273, 274, 3, 2, 2, 2, 274, 275, 3, 2, 2, 2, 275, 277,
7, 36, 2, 2, 276, 278, 5, 75, 38, 2, 277, 276, 3, 2, 2, 2, 277, 278, 3,
2, 2, 2, 278, 279, 3, 2, 2, 2, 279, 280, 7, 36, 2, 2, 280, 72, 3, 2, 2,
2, 281, 282, 7, 119, 2, 2, 282, 285, 7, 58, 2, 2, 283, 285, 9, 2, 2, 2,
284, 281, 3, 2, 2, 2, 284, 283, 3, 2, 2, 2, 285, 74, 3, 2, 2, 2, 286, 288,
5, 77, 39, 2, 287, 286, 3, 2, 2, 2, 288, 289, 3, 2, 2, 2, 289, 287, 3,
2, 2, 2, 289, 290, 3, 2, 2, 2, 290, 76, 3, 2, 2, 2, 291, 299, 10, 3, 2,
2, 292, 299, 5, 117, 59, 2, 293, 294, 7, 94, 2, 2, 294, 299, 7, 12, 2,
2, 295, 296, 7, 94, 2, 2, 296, 297, 7, 15, 2, 2, 297, 299, 7, 12, 2, 2,
298, 291, 3, 2, 2, 2, 298, 292, 3, 2, 2, 2, 298, 293, 3, 2, 2, 2, 298,
295, 3, 2, 2, 2, 299, 78, 3, 2, 2, 2, 300, 301, 9, 4, 2, 2, 301, 80, 3,
2, 2, 2, 302, 303, 9, 5, 2, 2, 303, 82, 3, 2, 2, 2, 304, 305, 7, 50, 2,
2, 305, 307, 9, 6, 2, 2, 306, 308, 9, 7, 2, 2, 307, 306, 3, 2, 2, 2, 308,
309, 3, 2, 2, 2, 309, 307, 3, 2, 2, 2, 309, 310, 3, 2, 2, 2, 310, 84, 3,
2, 2, 2, 311, 315, 5, 91, 46, 2, 312, 314, 5, 81, 41, 2, 313, 312, 3, 2,
2, 2, 314, 317, 3, 2, 2, 2, 315, 313, 3, 2, 2, 2, 315, 316, 3, 2, 2, 2,
316, 86, 3, 2, 2, 2, 317, 315, 3, 2, 2, 2, 318, 322, 7, 50, 2, 2, 319,
321, 5, 93, 47, 2, 320, 319, 3, 2, 2, 2, 321, 324, 3, 2, 2, 2, 322, 320,
3, 2, 2, 2, 322, 323, 3, 2, 2, 2, 323, 88, 3, 2, 2, 2, 324, 322, 3, 2,
2, 2, 325, 326, 7, 50, 2, 2, 326, 327, 9, 8, 2, 2, 327, 328, 5, 113, 57,
2, 328, 90, 3, 2, 2, 2, 329, 330, 9, 9, 2, 2, 330, 92, 3, 2, 2, 2, 331,
332, 9, 10, 2, 2, 332, 94, 3, 2, 2, 2, 333, 334, 9, 11, 2, 2, 334, 96,
3, 2, 2, 2, 335, 336, 5, 95, 48, 2, 336, 337, 5, 95, 48, 2, 337, 338, 5,
95, 48, 2, 338, 339, 5, 95, 48, 2, 339, 98, 3, 2, 2, 2, 340, 341, 7, 94,
2, 2, 341, 342, 7, 119, 2, 2, 342, 343, 3, 2, 2, 2, 343, 351, 5, 97, 49,
2, 344, 345, 7, 94, 2, 2, 345, 346, 7, 87, 2, 2, 346, 347, 3, 2, 2, 2,
347, 348, 5, 97, 49, 2, 348, 349, 5, 97, 49, 2, 349, 351, 3, 2, 2, 2, 350,
340, 3, 2, 2, 2, 350, 344, 3, 2, 2, 2, 351, 100, 3, 2, 2, 2, 352, 354,
5, 105, 53, 2, 353, 355, 5, 107, 54, 2, 354, 353, 3, 2, 2, 2, 354, 355,
3, 2, 2, 2, 355, 360, 3, 2, 2, 2, 356, 357, 5, 109, 55, 2, 357, 358, 5,
107, 54, 2, 358, 360, 3, 2, 2, 2, 359, 352, 3, 2, 2, 2, 359, 356, 3, 2,
2, 2, 360, 102, 3, 2, 2, 2, 361, 362, 7, 50, 2, 2, 362, 365, 9, 8, 2, 2,
363, 366, 5, 111, 56, 2, 364, 366, 5, 113, 57, 2, 365, 363, 3, 2, 2, 2,
365, 364, 3, 2, 2, 2, 366, 367, 3, 2, 2, 2, 367, 368, 5, 115, 58, 2, 368,
104, 3, 2, 2, 2, 369, 371, 5, 109, 55, 2, 370, 369, 3, 2, 2, 2, 370, 371,
3, 2, 2, 2, 371, 372, 3, 2, 2, 2, 372, 373, 7, 48, 2, 2, 373, 378, 5, 109,
55, 2, 374, 375, 5, 109, 55, 2, 375, 376, 7, 48, 2, 2, 376, 378, 3, 2,
2, 2, 377, 370, 3, 2, 2, 2, 377, 374, 3, 2, 2, 2, 378, 106, 3, 2, 2, 2,
379, 381, 9, 12, 2, 2, 380, 382, 9, 13, 2, 2, 381, 380, 3, 2, 2, 2, 381,
382, 3, 2, 2, 2, 382, 383, 3, 2, 2, 2, 383, 384, 5, 109, 55, 2, 384, 108,
3, 2, 2, 2, 385, 387, 5, 81, 41, 2, 386, 385, 3, 2, 2, 2, 387, 388, 3,
2, 2, 2, 388, 386, 3, 2, 2, 2, 388, 389, 3, 2, 2, 2, 389, 110, 3, 2, 2,
2, 390, 392, 5, 113, 57, 2, 391, 390, 3, 2, 2, 2, 391, 392, 3, 2, 2, 2,
392, 393, 3, 2, 2, 2, 393, 394, 7, 48, 2, 2, 394, 399, 5, 113, 57, 2, 395,
396, 5, 113, 57, 2, 396, 397, 7, 48, 2, 2, 397, 399, 3, 2, 2, 2, 398, 391,
3, 2, 2, 2, 398, 395, 3, 2, 2, 2, 399, 112, 3, 2, 2, 2, 400, 402, 5, 95,
48, 2, 401, 400, 3, 2, 2, 2, 402, 403, 3, 2, 2, 2, 403, 401, 3, 2, 2, 2,
403, 404, 3, 2, 2, 2, 404, 114, 3, 2, 2, 2, 405, 407, 9, 14, 2, 2, 406,
408, 9, 13, 2, 2, 407, 406, 3, 2, 2, 2, 407, 408, 3, 2, 2, 2, 408, 409,
3, 2, 2, 2, 409, 410, 5, 109, 55, 2, 410, 116, 3, 2, 2, 2, 411, 412, 7,
94, 2, 2, 412, 427, 9, 15, 2, 2, 413, 414, 7, 94, 2, 2, 414, 416, 5, 93,
47, 2, 415, 417, 5, 93, 47, 2, 416, 415, 3, 2, 2, 2, 416, 417, 3, 2, 2,
2, 417, 419, 3, 2, 2, 2, 418, 420, 5, 93, 47, 2, 419, 418, 3, 2, 2, 2,
419, 420, 3, 2, 2, 2, 420, 427, 3, 2, 2, 2, 421, 422, 7, 94, 2, 2, 422,
423, 7, 122, 2, 2, 423, 424, 3, 2, 2, 2, 424, 427, 5, 113, 57, 2, 425,
427, 5, 99, 50, 2, 426, 411, 3, 2, 2, 2, 426, 413, 3, 2, 2, 2, 426, 421,
3, 2, 2, 2, 426, 425, 3, 2, 2, 2, 427, 118, 3, 2, 2, 2, 428, 430, 9, 16,
2, 2, 429, 428, 3, 2, 2, 2, 430, 431, 3, 2, 2, 2, 431, 429, 3, 2, 2, 2,
431, 432, 3, 2, 2, 2, 432, 433, 3, 2, 2, 2, 433, 434, 8, 60, 2, 2, 434,
120, 3, 2, 2, 2, 435, 437, 7, 15, 2, 2, 436, 438, 7, 12, 2, 2, 437, 436,
3, 2, 2, 2, 437, 438, 3, 2, 2, 2, 438, 441, 3, 2, 2, 2, 439, 441, 7, 12,
2, 2, 440, 435, 3, 2, 2, 2, 440, 439, 3, 2, 2, 2, 441, 442, 3, 2, 2, 2,
442, 443, 8, 61, 2, 2, 443, 122, 3, 2, 2, 2, 40, 2, 157, 189, 195, 203,
218, 220, 252, 258, 262, 267, 269, 273, 277, 284, 289, 298, 309, 315, 322,
350, 354, 359, 365, 370, 377, 381, 388, 391, 398, 403, 407, 416, 419, 426,
431, 437, 440, 3, 8, 2, 2,
}
var lexerChannelNames = []string{
"DEFAULT_TOKEN_CHANNEL", "HIDDEN",
}
var lexerModeNames = []string{
"DEFAULT_MODE",
}
var lexerLiteralNames = []string{
"", "'('", "')'", "'['", "','", "']'", "'<'", "'<='", "'>'", "'>='", "'=='",
"'!='", "", "'+'", "'-'", "'*'", "'/'", "'%'", "'**'", "'<<'", "'>>'",
"'&'", "'|'", "'^'", "", "", "'~'", "", "'in'", "'not in'",
}
var lexerSymbolicNames = []string{
"", "", "", "", "", "", "LT", "LE", "GT", "GE", "EQ", "NE", "LIKE", "ADD",
"SUB", "MUL", "DIV", "MOD", "POW", "SHL", "SHR", "BAND", "BOR", "BXOR",
"AND", "OR", "BNOT", "NOT", "IN", "NIN", "EmptyTerm", "BooleanConstant",
"IntegerConstant", "FloatingConstant", "Identifier", "StringLiteral", "Whitespace",
"Newline",
}
var lexerRuleNames = []string{
"T__0", "T__1", "T__2", "T__3", "T__4", "LT", "LE", "GT", "GE", "EQ", "NE",
"LIKE", "ADD", "SUB", "MUL", "DIV", "MOD", "POW", "SHL", "SHR", "BAND",
"BOR", "BXOR", "AND", "OR", "BNOT", "NOT", "IN", "NIN", "EmptyTerm", "BooleanConstant",
"IntegerConstant", "FloatingConstant", "Identifier", "StringLiteral", "EncodingPrefix",
"SCharSequence", "SChar", "Nondigit", "Digit", "BinaryConstant", "DecimalConstant",
"OctalConstant", "HexadecimalConstant", "NonzeroDigit", "OctalDigit", "HexadecimalDigit",
"HexQuad", "UniversalCharacterName", "DecimalFloatingConstant", "HexadecimalFloatingConstant",
"FractionalConstant", "ExponentPart", "DigitSequence", "HexadecimalFractionalConstant",
"HexadecimalDigitSequence", "BinaryExponentPart", "EscapeSequence", "Whitespace",
"Newline",
}
type PlanLexer struct {
*antlr.BaseLexer
channelNames []string
modeNames []string
// TODO: EOF string
}
// NewPlanLexer produces a new lexer instance for the optional input antlr.CharStream.
//
// The *PlanLexer instance produced may be reused by calling the SetInputStream method.
// The initial lexer configuration is expensive to construct, and the object is not thread-safe;
// however, if used within a Golang sync.Pool, the construction cost amortizes well and the
// objects can be used in a thread-safe manner.
func NewPlanLexer(input antlr.CharStream) *PlanLexer {
l := new(PlanLexer)
lexerDeserializer := antlr.NewATNDeserializer(nil)
lexerAtn := lexerDeserializer.DeserializeFromUInt16(serializedLexerAtn)
lexerDecisionToDFA := make([]*antlr.DFA, len(lexerAtn.DecisionToState))
for index, ds := range lexerAtn.DecisionToState {
lexerDecisionToDFA[index] = antlr.NewDFA(ds, index)
}
l.BaseLexer = antlr.NewBaseLexer(input)
l.Interpreter = antlr.NewLexerATNSimulator(l, lexerAtn, lexerDecisionToDFA, antlr.NewPredictionContextCache())
l.channelNames = lexerChannelNames
l.modeNames = lexerModeNames
l.RuleNames = lexerRuleNames
l.LiteralNames = lexerLiteralNames
l.SymbolicNames = lexerSymbolicNames
l.GrammarFileName = "Plan.g4"
// TODO: l.EOF = antlr.TokenEOF
return l
}
// PlanLexer tokens.
const (
PlanLexerT__0 = 1
PlanLexerT__1 = 2
PlanLexerT__2 = 3
PlanLexerT__3 = 4
PlanLexerT__4 = 5
PlanLexerLT = 6
PlanLexerLE = 7
PlanLexerGT = 8
PlanLexerGE = 9
PlanLexerEQ = 10
PlanLexerNE = 11
PlanLexerLIKE = 12
PlanLexerADD = 13
PlanLexerSUB = 14
PlanLexerMUL = 15
PlanLexerDIV = 16
PlanLexerMOD = 17
PlanLexerPOW = 18
PlanLexerSHL = 19
PlanLexerSHR = 20
PlanLexerBAND = 21
PlanLexerBOR = 22
PlanLexerBXOR = 23
PlanLexerAND = 24
PlanLexerOR = 25
PlanLexerBNOT = 26
PlanLexerNOT = 27
PlanLexerIN = 28
PlanLexerNIN = 29
PlanLexerEmptyTerm = 30
PlanLexerBooleanConstant = 31
PlanLexerIntegerConstant = 32
PlanLexerFloatingConstant = 33
PlanLexerIdentifier = 34
PlanLexerStringLiteral = 35
PlanLexerWhitespace = 36
PlanLexerNewline = 37
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,78 @@
// Code generated from Plan.g4 by ANTLR 4.9. DO NOT EDIT.
package planparserv2 // Plan
import "github.com/antlr/antlr4/runtime/Go/antlr"
// A complete Visitor for a parse tree produced by PlanParser.
type PlanVisitor interface {
antlr.ParseTreeVisitor
// Visit a parse tree produced by PlanParser#Shift.
VisitShift(ctx *ShiftContext) interface{}
// Visit a parse tree produced by PlanParser#ReverseRange.
VisitReverseRange(ctx *ReverseRangeContext) interface{}
// Visit a parse tree produced by PlanParser#BitOr.
VisitBitOr(ctx *BitOrContext) interface{}
// Visit a parse tree produced by PlanParser#AddSub.
VisitAddSub(ctx *AddSubContext) interface{}
// Visit a parse tree produced by PlanParser#Parens.
VisitParens(ctx *ParensContext) interface{}
// Visit a parse tree produced by PlanParser#Relational.
VisitRelational(ctx *RelationalContext) interface{}
// Visit a parse tree produced by PlanParser#String.
VisitString(ctx *StringContext) interface{}
// Visit a parse tree produced by PlanParser#Term.
VisitTerm(ctx *TermContext) interface{}
// Visit a parse tree produced by PlanParser#Floating.
VisitFloating(ctx *FloatingContext) interface{}
// Visit a parse tree produced by PlanParser#Range.
VisitRange(ctx *RangeContext) interface{}
// Visit a parse tree produced by PlanParser#Unary.
VisitUnary(ctx *UnaryContext) interface{}
// Visit a parse tree produced by PlanParser#LogicalOr.
VisitLogicalOr(ctx *LogicalOrContext) interface{}
// Visit a parse tree produced by PlanParser#Integer.
VisitInteger(ctx *IntegerContext) interface{}
// Visit a parse tree produced by PlanParser#MulDivMod.
VisitMulDivMod(ctx *MulDivModContext) interface{}
// Visit a parse tree produced by PlanParser#Identifier.
VisitIdentifier(ctx *IdentifierContext) interface{}
// Visit a parse tree produced by PlanParser#BitXor.
VisitBitXor(ctx *BitXorContext) interface{}
// Visit a parse tree produced by PlanParser#Like.
VisitLike(ctx *LikeContext) interface{}
// Visit a parse tree produced by PlanParser#BitAnd.
VisitBitAnd(ctx *BitAndContext) interface{}
// Visit a parse tree produced by PlanParser#LogicalAnd.
VisitLogicalAnd(ctx *LogicalAndContext) interface{}
// Visit a parse tree produced by PlanParser#EmptyTerm.
VisitEmptyTerm(ctx *EmptyTermContext) interface{}
// Visit a parse tree produced by PlanParser#Equality.
VisitEquality(ctx *EqualityContext) interface{}
// Visit a parse tree produced by PlanParser#Boolean.
VisitBoolean(ctx *BooleanContext) interface{}
// Visit a parse tree produced by PlanParser#Power.
VisitPower(ctx *PowerContext) interface{}
}

View File

@ -0,0 +1,17 @@
package planparserv2
import "github.com/milvus-io/milvus/internal/proto/planpb"
type LogicalExprVisitor interface {
VisitExpr(expr *planpb.Expr) interface{}
VisitTermExpr(expr *planpb.TermExpr) interface{}
VisitUnaryExpr(expr *planpb.UnaryExpr) interface{}
VisitBinaryExpr(expr *planpb.BinaryExpr) interface{}
VisitCompareExpr(expr *planpb.CompareExpr) interface{}
VisitUnaryRangeExpr(expr *planpb.UnaryRangeExpr) interface{}
VisitBinaryRangeExpr(expr *planpb.BinaryRangeExpr) interface{}
VisitBinaryArithOpEvalRangeExpr(expr *planpb.BinaryArithOpEvalRangeExpr) interface{}
VisitBinaryArithExpr(expr *planpb.BinaryArithExpr) interface{}
VisitValueExpr(expr *planpb.ValueExpr) interface{}
VisitColumnExpr(expr *planpb.ColumnExpr) interface{}
}

View File

@ -0,0 +1,37 @@
package planparserv2
import (
"github.com/milvus-io/milvus/internal/proto/planpb"
"github.com/milvus-io/milvus/internal/proto/schemapb"
)
type ExprWithType struct {
expr *planpb.Expr
dataType schemapb.DataType
}
func getError(obj interface{}) error {
err, ok := obj.(error)
if !ok {
// obj is not an error.
return nil
}
return err
}
func getExpr(obj interface{}) *ExprWithType {
n, ok := obj.(*ExprWithType)
if !ok {
// obj is not of *ExprWithType
return nil
}
return n
}
func getGenericValue(obj interface{}) *planpb.GenericValue {
expr := getExpr(obj)
if expr == nil {
return nil
}
return expr.expr.GetValueExpr().GetValue()
}

View File

@ -0,0 +1,633 @@
package planparserv2
import (
"fmt"
"math"
parser "github.com/milvus-io/milvus/internal/parser/planparserv2/generated"
"github.com/milvus-io/milvus/internal/proto/planpb"
"github.com/milvus-io/milvus/internal/proto/schemapb"
)
var arithExprMap = map[int]planpb.ArithOpType{
parser.PlanParserADD: planpb.ArithOpType_Add,
parser.PlanParserSUB: planpb.ArithOpType_Sub,
parser.PlanParserMUL: planpb.ArithOpType_Mul,
parser.PlanParserDIV: planpb.ArithOpType_Div,
parser.PlanParserMOD: planpb.ArithOpType_Mod,
}
var arithNameMap = map[int]string{
parser.PlanParserADD: "add",
parser.PlanParserSUB: "subtract",
parser.PlanParserMUL: "multiply",
parser.PlanParserDIV: "divide",
parser.PlanParserMOD: "modulo",
}
var cmpOpMap = map[int]planpb.OpType{
parser.PlanParserLT: planpb.OpType_LessThan,
parser.PlanParserLE: planpb.OpType_LessEqual,
parser.PlanParserGT: planpb.OpType_GreaterThan,
parser.PlanParserGE: planpb.OpType_GreaterEqual,
parser.PlanParserEQ: planpb.OpType_Equal,
parser.PlanParserNE: planpb.OpType_NotEqual,
}
var cmpNameMap = map[int]string{
parser.PlanParserLT: "less",
parser.PlanParserLE: "lessequal",
parser.PlanParserGT: "greater",
parser.PlanParserGE: "greaterequal",
parser.PlanParserEQ: "equal",
parser.PlanParserNE: "notequal",
}
var unaryLogicalOpMap = map[int]planpb.UnaryExpr_UnaryOp{
parser.PlanParserNOT: planpb.UnaryExpr_Not,
}
var unaryLogicalNameMap = map[int]string{
parser.PlanParserNOT: "not",
}
var binaryLogicalOpMap = map[int]planpb.BinaryExpr_BinaryOp{
parser.PlanParserAND: planpb.BinaryExpr_LogicalAnd,
parser.PlanParserOR: planpb.BinaryExpr_LogicalOr,
}
var binaryLogicalNameMap = map[int]string{
parser.PlanParserAND: "and",
parser.PlanParserOR: "or",
}
func Add(a, b *planpb.GenericValue) *ExprWithType {
ret := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{},
},
},
}
if IsBool(a) || IsBool(b) {
return nil
}
if IsString(a) || IsString(b) {
return nil
}
aFloat, bFloat, aInt, bInt := IsFloating(a), IsFloating(b), IsInteger(a), IsInteger(b)
if aFloat && bFloat {
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(a.GetFloatVal() + b.GetFloatVal())
} else if aFloat && bInt {
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(a.GetFloatVal() + float64(b.GetInt64Val()))
} else if aInt && bFloat {
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(float64(a.GetInt64Val()) + b.GetFloatVal())
} else {
// aInt && bInt
ret.dataType = schemapb.DataType_Int64
ret.expr.GetValueExpr().Value = NewInt(a.GetInt64Val() + b.GetInt64Val())
}
return ret
}
func Subtract(a, b *planpb.GenericValue) *ExprWithType {
ret := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{},
},
},
}
if IsBool(a) || IsBool(b) {
return nil
}
if IsString(a) || IsString(b) {
return nil
}
aFloat, bFloat, aInt, bInt := IsFloating(a), IsFloating(b), IsInteger(a), IsInteger(b)
if aFloat && bFloat {
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(a.GetFloatVal() - b.GetFloatVal())
} else if aFloat && bInt {
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(a.GetFloatVal() - float64(b.GetInt64Val()))
} else if aInt && bFloat {
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(float64(a.GetInt64Val()) - b.GetFloatVal())
} else {
// aInt && bInt
ret.dataType = schemapb.DataType_Int64
ret.expr.GetValueExpr().Value = NewInt(a.GetInt64Val() - b.GetInt64Val())
}
return ret
}
func Multiply(a, b *planpb.GenericValue) *ExprWithType {
ret := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{},
},
},
}
if IsBool(a) || IsBool(b) {
return nil
}
if IsString(a) || IsString(b) {
return nil
}
aFloat, bFloat, aInt, bInt := IsFloating(a), IsFloating(b), IsInteger(a), IsInteger(b)
if aFloat && bFloat {
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(a.GetFloatVal() * b.GetFloatVal())
} else if aFloat && bInt {
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(a.GetFloatVal() * float64(b.GetInt64Val()))
} else if aInt && bFloat {
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(float64(a.GetInt64Val()) * b.GetFloatVal())
} else {
// aInt && bInt
ret.dataType = schemapb.DataType_Int64
ret.expr.GetValueExpr().Value = NewInt(a.GetInt64Val() * b.GetInt64Val())
}
return ret
}
func Divide(a, b *planpb.GenericValue) (*ExprWithType, error) {
ret := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{},
},
},
}
if IsBool(a) || IsBool(b) {
return nil, fmt.Errorf("divide cannot apply on bool field")
}
if IsString(a) || IsString(b) {
return nil, fmt.Errorf("divide cannot apply on string field")
}
aFloat, bFloat, aInt, bInt := IsFloating(a), IsFloating(b), IsInteger(a), IsInteger(b)
if bFloat && b.GetFloatVal() == 0 {
return nil, fmt.Errorf("cannot divide by zero")
}
if bInt && b.GetInt64Val() == 0 {
return nil, fmt.Errorf("cannot divide by zero")
}
if aFloat && bFloat {
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(a.GetFloatVal() / b.GetFloatVal())
} else if aFloat && bInt {
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(a.GetFloatVal() / float64(b.GetInt64Val()))
} else if aInt && bFloat {
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(float64(a.GetInt64Val()) / b.GetFloatVal())
} else {
// aInt && bInt
ret.dataType = schemapb.DataType_Int64
ret.expr.GetValueExpr().Value = NewInt(a.GetInt64Val() / b.GetInt64Val())
}
return ret, nil
}
func Modulo(a, b *planpb.GenericValue) (*ExprWithType, error) {
ret := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{},
},
},
}
aInt, bInt := IsInteger(a), IsInteger(b)
if !aInt || !bInt {
return nil, fmt.Errorf("modulo can only apply on integer")
}
// aInt && bInt
if b.GetInt64Val() == 0 {
return nil, fmt.Errorf("cannot modulo by zero")
}
ret.dataType = schemapb.DataType_Int64
ret.expr.GetValueExpr().Value = NewInt(a.GetInt64Val() % b.GetInt64Val())
return ret, nil
}
func Power(a, b *planpb.GenericValue) *ExprWithType {
ret := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{},
},
},
}
if IsBool(a) || IsBool(b) {
return nil
}
if IsString(a) || IsString(b) {
return nil
}
aFloat, bFloat, aInt, bInt := IsFloating(a), IsFloating(b), IsInteger(a), IsInteger(b)
if aFloat && bFloat {
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(math.Pow(a.GetFloatVal(), b.GetFloatVal()))
} else if aFloat && bInt {
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(math.Pow(a.GetFloatVal(), float64(b.GetInt64Val())))
} else if aInt && bFloat {
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(math.Pow(float64(a.GetInt64Val()), b.GetFloatVal()))
} else {
// aInt && bInt
// 2 ** (-1) = 0.5
ret.dataType = schemapb.DataType_Double
ret.expr.GetValueExpr().Value = NewFloat(math.Pow(float64(a.GetInt64Val()), float64(b.GetInt64Val())))
}
return ret
}
func BitAnd(a, b *planpb.GenericValue) (*ExprWithType, error) {
return nil, fmt.Errorf("todo: unsupported")
}
func BitOr(a, b *planpb.GenericValue) (*ExprWithType, error) {
return nil, fmt.Errorf("todo: unsupported")
}
func BitXor(a, b *planpb.GenericValue) (*ExprWithType, error) {
return nil, fmt.Errorf("todo: unsupported")
}
func ShiftLeft(a, b *planpb.GenericValue) (*ExprWithType, error) {
return nil, fmt.Errorf("todo: unsupported")
}
func ShiftRight(a, b *planpb.GenericValue) (*ExprWithType, error) {
return nil, fmt.Errorf("todo: unsupported")
}
func And(a, b *planpb.GenericValue) (*ExprWithType, error) {
aBool, bBool := IsBool(a), IsBool(b)
if !aBool || !bBool {
return nil, fmt.Errorf("and can only apply on boolean")
}
return &ExprWithType{
dataType: schemapb.DataType_Bool,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{
Value: NewBool(a.GetBoolVal() && b.GetBoolVal()),
},
},
},
}, nil
}
func Or(a, b *planpb.GenericValue) (*ExprWithType, error) {
aBool, bBool := IsBool(a), IsBool(b)
if !aBool || !bBool {
return nil, fmt.Errorf("or can only apply on boolean")
}
return &ExprWithType{
dataType: schemapb.DataType_Bool,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{
Value: NewBool(a.GetBoolVal() || b.GetBoolVal()),
},
},
},
}, nil
}
func BitNot(a *planpb.GenericValue) (*ExprWithType, error) {
return nil, fmt.Errorf("todo: unsupported")
}
func Negative(a *planpb.GenericValue) *ExprWithType {
if IsFloating(a) {
return &ExprWithType{
dataType: schemapb.DataType_Double,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{
Value: NewFloat(-a.GetFloatVal()),
},
},
},
}
}
if IsInteger(a) {
return &ExprWithType{
dataType: schemapb.DataType_Int64,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{
Value: NewInt(-a.GetInt64Val()),
},
},
},
}
}
return nil
}
func Not(a *planpb.GenericValue) *ExprWithType {
if !IsBool(a) {
return nil
}
return &ExprWithType{
dataType: schemapb.DataType_Bool,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{
Value: NewBool(!a.GetBoolVal()),
},
},
},
}
}
/*
type relationalFn func(a, b *planpb.GenericValue) (bool, error)
func applyRelational(a, b *planpb.GenericValue, relational relationalFn) *ExprWithType {
ret, err := relational(a, b)
if err != nil {
return nil
}
return &ExprWithType{
dataType: schemapb.DataType_Bool,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{
Value: NewBool(ret),
},
},
},
}
}
func less() relationalFn {
return func(a, b *planpb.GenericValue) (bool, error) {
if IsString(a) && IsString(b) {
return a.GetStringVal() < b.GetStringVal(), nil
}
aFloat, bFloat, aInt, bInt := IsFloating(a), IsFloating(b), IsInteger(a), IsInteger(b)
if aFloat && bFloat {
return a.GetFloatVal() < b.GetFloatVal(), nil
} else if aFloat && bInt {
return a.GetFloatVal() < float64(b.GetInt64Val()), nil
} else if aInt && bFloat {
return float64(a.GetInt64Val()) < b.GetFloatVal(), nil
} else if aInt && bInt {
return a.GetInt64Val() < b.GetInt64Val(), nil
}
return false, fmt.Errorf("incompatible data type")
}
}
func Less(a, b *planpb.GenericValue) *ExprWithType {
return applyRelational(a, b, less())
}
// TODO: Can we abstract these relational function?
*/
func Less(a, b *planpb.GenericValue) *ExprWithType {
ret := &ExprWithType{
dataType: schemapb.DataType_Bool,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{},
},
},
}
if IsString(a) && IsString(b) {
ret.expr.GetValueExpr().Value = NewBool(a.GetStringVal() < b.GetStringVal())
return ret
}
aFloat, bFloat, aInt, bInt := IsFloating(a), IsFloating(b), IsInteger(a), IsInteger(b)
if aFloat && bFloat {
ret.expr.GetValueExpr().Value = NewBool(a.GetFloatVal() < b.GetFloatVal())
return ret
} else if aFloat && bInt {
ret.expr.GetValueExpr().Value = NewBool(a.GetFloatVal() < float64(b.GetInt64Val()))
return ret
} else if aInt && bFloat {
ret.expr.GetValueExpr().Value = NewBool(float64(a.GetInt64Val()) < b.GetFloatVal())
return ret
} else if aInt && bInt {
// aInt && bInt
ret.expr.GetValueExpr().Value = NewBool(a.GetInt64Val() < b.GetInt64Val())
return ret
}
return nil
}
func LessEqual(a, b *planpb.GenericValue) *ExprWithType {
ret := &ExprWithType{
dataType: schemapb.DataType_Bool,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{},
},
},
}
if IsString(a) && IsString(b) {
ret.expr.GetValueExpr().Value = NewBool(a.GetStringVal() <= b.GetStringVal())
return ret
}
aFloat, bFloat, aInt, bInt := IsFloating(a), IsFloating(b), IsInteger(a), IsInteger(b)
if aFloat && bFloat {
ret.expr.GetValueExpr().Value = NewBool(a.GetFloatVal() <= b.GetFloatVal())
return ret
} else if aFloat && bInt {
ret.expr.GetValueExpr().Value = NewBool(a.GetFloatVal() <= float64(b.GetInt64Val()))
return ret
} else if aInt && bFloat {
ret.expr.GetValueExpr().Value = NewBool(float64(a.GetInt64Val()) <= b.GetFloatVal())
return ret
} else if aInt && bInt {
// aInt && bInt
ret.expr.GetValueExpr().Value = NewBool(a.GetInt64Val() <= b.GetInt64Val())
return ret
}
return nil
}
func Greater(a, b *planpb.GenericValue) *ExprWithType {
ret := &ExprWithType{
dataType: schemapb.DataType_Bool,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{},
},
},
}
if IsString(a) && IsString(b) {
ret.expr.GetValueExpr().Value = NewBool(a.GetStringVal() > b.GetStringVal())
return ret
}
aFloat, bFloat, aInt, bInt := IsFloating(a), IsFloating(b), IsInteger(a), IsInteger(b)
if aFloat && bFloat {
ret.expr.GetValueExpr().Value = NewBool(a.GetFloatVal() > b.GetFloatVal())
return ret
} else if aFloat && bInt {
ret.expr.GetValueExpr().Value = NewBool(a.GetFloatVal() > float64(b.GetInt64Val()))
return ret
} else if aInt && bFloat {
ret.expr.GetValueExpr().Value = NewBool(float64(a.GetInt64Val()) > b.GetFloatVal())
return ret
} else if aInt && bInt {
// aInt && bInt
ret.expr.GetValueExpr().Value = NewBool(a.GetInt64Val() > b.GetInt64Val())
return ret
}
return nil
}
func GreaterEqual(a, b *planpb.GenericValue) *ExprWithType {
ret := &ExprWithType{
dataType: schemapb.DataType_Bool,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{},
},
},
}
if IsString(a) && IsString(b) {
ret.expr.GetValueExpr().Value = NewBool(a.GetStringVal() >= b.GetStringVal())
return ret
}
aFloat, bFloat, aInt, bInt := IsFloating(a), IsFloating(b), IsInteger(a), IsInteger(b)
if aFloat && bFloat {
ret.expr.GetValueExpr().Value = NewBool(a.GetFloatVal() >= b.GetFloatVal())
return ret
} else if aFloat && bInt {
ret.expr.GetValueExpr().Value = NewBool(a.GetFloatVal() >= float64(b.GetInt64Val()))
return ret
} else if aInt && bFloat {
ret.expr.GetValueExpr().Value = NewBool(float64(a.GetInt64Val()) >= b.GetFloatVal())
return ret
} else if aInt && bInt {
// aInt && bInt
ret.expr.GetValueExpr().Value = NewBool(a.GetInt64Val() >= b.GetInt64Val())
return ret
}
return nil
}
func Equal(a, b *planpb.GenericValue) *ExprWithType {
ret := &ExprWithType{
dataType: schemapb.DataType_Bool,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{},
},
},
}
if IsBool(a) && IsBool(b) {
ret.expr.GetValueExpr().Value = NewBool(a.GetBoolVal() == b.GetBoolVal())
return ret
}
if IsString(a) && IsString(b) {
ret.expr.GetValueExpr().Value = NewBool(a.GetStringVal() == b.GetStringVal())
return ret
}
aFloat, bFloat, aInt, bInt := IsFloating(a), IsFloating(b), IsInteger(a), IsInteger(b)
if aFloat && bFloat {
ret.expr.GetValueExpr().Value = NewBool(floatingEqual(a.GetFloatVal(), b.GetFloatVal()))
return ret
} else if aFloat && bInt {
ret.expr.GetValueExpr().Value = NewBool(floatingEqual(a.GetFloatVal(), float64(b.GetInt64Val())))
return ret
} else if aInt && bFloat {
ret.expr.GetValueExpr().Value = NewBool(floatingEqual(float64(a.GetInt64Val()), b.GetFloatVal()))
return ret
} else if aInt && bInt {
// aInt && bInt
ret.expr.GetValueExpr().Value = NewBool(a.GetInt64Val() == b.GetInt64Val())
return ret
}
return nil
}
func NotEqual(a, b *planpb.GenericValue) *ExprWithType {
ret := &ExprWithType{
dataType: schemapb.DataType_Bool,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{},
},
},
}
if IsBool(a) && IsBool(b) {
ret.expr.GetValueExpr().Value = NewBool(a.GetBoolVal() != b.GetBoolVal())
return ret
}
if IsString(a) && IsString(b) {
ret.expr.GetValueExpr().Value = NewBool(a.GetStringVal() != b.GetStringVal())
return ret
}
aFloat, bFloat, aInt, bInt := IsFloating(a), IsFloating(b), IsInteger(a), IsInteger(b)
if aFloat && bFloat {
ret.expr.GetValueExpr().Value = NewBool(!floatingEqual(a.GetFloatVal(), b.GetFloatVal()))
return ret
} else if aFloat && bInt {
ret.expr.GetValueExpr().Value = NewBool(!floatingEqual(a.GetFloatVal(), float64(b.GetInt64Val())))
return ret
} else if aInt && bFloat {
ret.expr.GetValueExpr().Value = NewBool(!floatingEqual(float64(a.GetInt64Val()), b.GetFloatVal()))
return ret
} else if aInt && bInt {
// aInt && bInt
ret.expr.GetValueExpr().Value = NewBool(a.GetInt64Val() != b.GetInt64Val())
return ret
}
return nil
}

View File

@ -0,0 +1,877 @@
package planparserv2
import (
"fmt"
"strconv"
parser "github.com/milvus-io/milvus/internal/parser/planparserv2/generated"
"github.com/milvus-io/milvus/internal/proto/planpb"
"github.com/milvus-io/milvus/internal/proto/schemapb"
"github.com/milvus-io/milvus/internal/util/typeutil"
)
type ParserVisitor struct {
parser.BasePlanVisitor
schema *typeutil.SchemaHelper
}
func NewParserVisitor(schema *typeutil.SchemaHelper) *ParserVisitor {
return &ParserVisitor{schema: schema}
}
// VisitParens unpack the parentheses.
func (v *ParserVisitor) VisitParens(ctx *parser.ParensContext) interface{} {
return ctx.Expr().Accept(v)
}
// VisitIdentifier translates expr to column plan.
func (v *ParserVisitor) VisitIdentifier(ctx *parser.IdentifierContext) interface{} {
fieldName := ctx.Identifier().GetText()
field, err := v.schema.GetFieldFromName(fieldName)
if err != nil {
return err
}
return &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ColumnExpr{
ColumnExpr: &planpb.ColumnExpr{
Info: &planpb.ColumnInfo{
FieldId: field.FieldID,
DataType: field.DataType,
IsPrimaryKey: field.IsPrimaryKey,
IsAutoID: field.AutoID,
},
},
},
},
dataType: field.DataType,
}
}
// VisitBoolean translates expr to GenericValue.
func (v *ParserVisitor) VisitBoolean(ctx *parser.BooleanContext) interface{} {
literal := ctx.BooleanConstant().GetText()
b, err := strconv.ParseBool(literal)
if err != nil {
return err
}
return &ExprWithType{
dataType: schemapb.DataType_Bool,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{
Value: NewBool(b),
},
},
},
}
}
// VisitInteger translates expr to GenericValue.
func (v *ParserVisitor) VisitInteger(ctx *parser.IntegerContext) interface{} {
literal := ctx.IntegerConstant().GetText()
i, err := strconv.ParseInt(literal, 0, 64)
if err != nil {
return err
}
return &ExprWithType{
dataType: schemapb.DataType_Int64,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{
Value: NewInt(i),
},
},
},
}
}
// VisitFloating translates expr to GenericValue.
func (v *ParserVisitor) VisitFloating(ctx *parser.FloatingContext) interface{} {
literal := ctx.FloatingConstant().GetText()
f, err := strconv.ParseFloat(literal, 64)
if err != nil {
return err
}
return &ExprWithType{
dataType: schemapb.DataType_Double,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{
Value: NewFloat(f),
},
},
},
}
}
// VisitString translates expr to GenericValue.
func (v *ParserVisitor) VisitString(ctx *parser.StringContext) interface{} {
literal, err := strconv.Unquote(ctx.StringLiteral().GetText())
if err != nil {
return err
}
return &ExprWithType{
dataType: schemapb.DataType_VarChar,
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{
Value: NewString(literal),
},
},
},
}
}
// VisitAddSub translates expr to arithmetic plan.
func (v *ParserVisitor) VisitAddSub(ctx *parser.AddSubContext) interface{} {
left := ctx.Expr(0).Accept(v)
if err := getError(left); err != nil {
return err
}
right := ctx.Expr(1).Accept(v)
if err := getError(right); err != nil {
return err
}
leftValue, rightValue := getGenericValue(left), getGenericValue(right)
if leftValue != nil && rightValue != nil {
switch ctx.GetOp().GetTokenType() {
case parser.PlanParserADD:
return Add(leftValue, rightValue)
case parser.PlanParserSUB:
return Subtract(leftValue, rightValue)
default:
return fmt.Errorf("unexpected op: %s", ctx.GetOp().GetText())
}
}
var leftExpr *ExprWithType
var rightExpr *ExprWithType
reverse := true
if leftValue != nil {
leftExpr = toValueExpr(leftValue)
} else {
reverse = false
leftExpr = getExpr(left)
}
if rightValue != nil {
rightExpr = toValueExpr(rightValue)
} else {
rightExpr = getExpr(right)
}
if leftExpr == nil || rightExpr == nil {
return fmt.Errorf("invalid arithmetic expression, left: %s, op: %s, right: %s", ctx.Expr(0).GetText(), ctx.GetOp(), ctx.Expr(1).GetText())
}
if !typeutil.IsArithmetic(leftExpr.dataType) || !typeutil.IsArithmetic(rightExpr.dataType) {
return fmt.Errorf("'%s' can only be used between integer or floating expressions", arithNameMap[ctx.GetOp().GetTokenType()])
}
expr := &planpb.Expr{
Expr: &planpb.Expr_BinaryArithExpr{
BinaryArithExpr: &planpb.BinaryArithExpr{
Left: leftExpr.expr,
Right: rightExpr.expr,
Op: arithExprMap[ctx.GetOp().GetTokenType()],
},
},
}
dataType, err := calcDataType(leftExpr, rightExpr, reverse)
if err != nil {
return err
}
return &ExprWithType{
expr: expr,
dataType: dataType,
}
}
// VisitMulDivMod translates expr to arithmetic plan.
func (v *ParserVisitor) VisitMulDivMod(ctx *parser.MulDivModContext) interface{} {
left := ctx.Expr(0).Accept(v)
if err := getError(left); err != nil {
return err
}
right := ctx.Expr(1).Accept(v)
if err := getError(right); err != nil {
return err
}
leftValue, rightValue := getGenericValue(left), getGenericValue(right)
if leftValue != nil && rightValue != nil {
switch ctx.GetOp().GetTokenType() {
case parser.PlanParserMUL:
return Multiply(leftValue, rightValue)
case parser.PlanParserDIV:
n, err := Divide(leftValue, rightValue)
if err != nil {
return err
}
return n
case parser.PlanParserMOD:
n, err := Modulo(leftValue, rightValue)
if err != nil {
return err
}
return n
default:
return fmt.Errorf("unexpected op: %s", ctx.GetOp().GetText())
}
}
var leftExpr *ExprWithType
var rightExpr *ExprWithType
reverse := true
if leftValue != nil {
leftExpr = toValueExpr(leftValue)
} else {
leftExpr = getExpr(left)
reverse = false
}
if rightValue != nil {
rightExpr = toValueExpr(rightValue)
} else {
rightExpr = getExpr(right)
}
if leftExpr == nil || rightExpr == nil {
return fmt.Errorf("invalid arithmetic expression, left: %s, op: %s, right: %s", ctx.Expr(0).GetText(), ctx.GetOp(), ctx.Expr(1).GetText())
}
if !typeutil.IsArithmetic(leftExpr.dataType) || !typeutil.IsArithmetic(rightExpr.dataType) {
return fmt.Errorf("'%s' can only be used between integer or floating expressions", arithNameMap[ctx.GetOp().GetTokenType()])
}
switch ctx.GetOp().GetTokenType() {
case parser.PlanParserMOD:
if !typeutil.IsIntegerType(leftExpr.dataType) || !typeutil.IsIntegerType(rightExpr.dataType) {
return fmt.Errorf("modulo can only apply on integer types")
}
default:
break
}
expr := &planpb.Expr{
Expr: &planpb.Expr_BinaryArithExpr{
BinaryArithExpr: &planpb.BinaryArithExpr{
Left: leftExpr.expr,
Right: rightExpr.expr,
Op: arithExprMap[ctx.GetOp().GetTokenType()],
},
},
}
dataType, err := calcDataType(leftExpr, rightExpr, reverse)
if err != nil {
return err
}
return &ExprWithType{
expr: expr,
dataType: dataType,
}
}
// VisitEquality translates expr to compare/range plan.
func (v *ParserVisitor) VisitEquality(ctx *parser.EqualityContext) interface{} {
left := ctx.Expr(0).Accept(v)
if err := getError(left); err != nil {
return err
}
right := ctx.Expr(1).Accept(v)
if err := getError(right); err != nil {
return err
}
leftValue, rightValue := getGenericValue(left), getGenericValue(right)
if leftValue != nil && rightValue != nil {
switch ctx.GetOp().GetTokenType() {
case parser.PlanParserEQ:
return Equal(leftValue, rightValue)
case parser.PlanParserNE:
return NotEqual(leftValue, rightValue)
default:
return fmt.Errorf("unexpected op: %s", ctx.GetOp().GetText())
}
}
var leftExpr *ExprWithType
var rightExpr *ExprWithType
if leftValue != nil {
leftExpr = toValueExpr(leftValue)
} else {
leftExpr = getExpr(left)
}
if rightValue != nil {
rightExpr = toValueExpr(rightValue)
} else {
rightExpr = getExpr(right)
}
expr, err := HandleCompare(ctx.GetOp().GetTokenType(), leftExpr, rightExpr)
if err != nil {
return err
}
return &ExprWithType{
expr: expr,
dataType: schemapb.DataType_Bool,
}
}
// VisitRelational translates expr to range/compare plan.
func (v *ParserVisitor) VisitRelational(ctx *parser.RelationalContext) interface{} {
left := ctx.Expr(0).Accept(v)
if err := getError(left); err != nil {
return err
}
right := ctx.Expr(1).Accept(v)
if err := getError(right); err != nil {
return err
}
leftValue, rightValue := getGenericValue(left), getGenericValue(right)
if leftValue != nil && rightValue != nil {
switch ctx.GetOp().GetTokenType() {
case parser.PlanParserLT:
return Less(leftValue, rightValue)
case parser.PlanParserLE:
return LessEqual(leftValue, rightValue)
case parser.PlanParserGT:
return Greater(leftValue, rightValue)
case parser.PlanParserGE:
return GreaterEqual(leftValue, rightValue)
default:
return fmt.Errorf("unexpected op: %s", ctx.GetOp().GetText())
}
}
var leftExpr *ExprWithType
var rightExpr *ExprWithType
if leftValue != nil {
leftExpr = toValueExpr(leftValue)
} else {
leftExpr = getExpr(left)
}
if rightValue != nil {
rightExpr = toValueExpr(rightValue)
} else {
rightExpr = getExpr(right)
}
expr, err := HandleCompare(ctx.GetOp().GetTokenType(), leftExpr, rightExpr)
if err != nil {
return err
}
return &ExprWithType{
expr: expr,
dataType: schemapb.DataType_Bool,
}
}
// VisitLike handles match operations.
func (v *ParserVisitor) VisitLike(ctx *parser.LikeContext) interface{} {
left := ctx.Expr().Accept(v)
if err := getError(left); err != nil {
return err
}
leftExpr := getExpr(left)
if leftExpr == nil {
return fmt.Errorf("the left operand of like is invalid")
}
if !typeutil.IsStringType(leftExpr.dataType) {
return fmt.Errorf("like operation on non-text field is unsupported")
}
column := toColumnInfo(leftExpr)
if column == nil {
return fmt.Errorf("like operation on complicated expr is unsupported")
}
operand := NewString(ctx.StringLiteral().GetText())
return &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_UnaryRangeExpr{
UnaryRangeExpr: &planpb.UnaryRangeExpr{
ColumnInfo: column,
Op: planpb.OpType_Match,
Value: operand,
},
},
},
dataType: schemapb.DataType_Bool,
}
}
// VisitTerm translates expr to term plan.
func (v *ParserVisitor) VisitTerm(ctx *parser.TermContext) interface{} {
child := ctx.Expr(0).Accept(v)
if err := getError(child); err != nil {
return err
}
if childValue := getGenericValue(child); childValue != nil {
return fmt.Errorf("'term' can only be used on non-const expression, but got: %s", ctx.Expr(0).GetText())
}
childExpr := getExpr(child)
columnInfo := toColumnInfo(childExpr)
if columnInfo == nil {
return fmt.Errorf("'term' can only be used on single field, but got: %s", ctx.Expr(0).GetText())
}
allExpr := ctx.AllExpr()
lenOfAllExpr := len(allExpr)
values := make([]*planpb.GenericValue, 0, lenOfAllExpr)
for i := 1; i < lenOfAllExpr; i++ {
term := allExpr[i].Accept(v)
if getError(term) != nil {
return term
}
n := getGenericValue(term)
if n == nil {
return fmt.Errorf("value '%s' in list cannot be a non-const expression", ctx.Expr(i).GetText())
}
castedValue, err := castValue(childExpr.dataType, n)
if err != nil {
return fmt.Errorf("value '%s' in list cannot be casted to %s", ctx.Expr(i).GetText(), childExpr.dataType.String())
}
values = append(values, castedValue)
}
if len(values) <= 0 {
return fmt.Errorf("'term' has empty value list")
}
expr := &planpb.Expr{
Expr: &planpb.Expr_TermExpr{
TermExpr: &planpb.TermExpr{
ColumnInfo: columnInfo,
Values: values,
},
},
}
if ctx.GetOp().GetTokenType() == parser.PlanParserNIN {
expr = &planpb.Expr{
Expr: &planpb.Expr_UnaryExpr{
UnaryExpr: &planpb.UnaryExpr{
Op: planpb.UnaryExpr_Not,
Child: expr,
},
},
}
}
return &ExprWithType{
expr: expr,
dataType: schemapb.DataType_Bool,
}
}
// VisitEmptyTerm translates expr to term plan.
func (v *ParserVisitor) VisitEmptyTerm(ctx *parser.EmptyTermContext) interface{} {
child := ctx.Expr().Accept(v)
if err := getError(child); err != nil {
return err
}
if childValue := getGenericValue(child); childValue != nil {
return fmt.Errorf("'term' can only be used on non-const expression, but got: %s", ctx.Expr().GetText())
}
childExpr := getExpr(child)
columnInfo := toColumnInfo(childExpr)
if columnInfo == nil {
return fmt.Errorf("'term' can only be used on single field, but got: %s", ctx.Expr().GetText())
}
expr := &planpb.Expr{
Expr: &planpb.Expr_TermExpr{
TermExpr: &planpb.TermExpr{
ColumnInfo: columnInfo,
Values: nil,
},
},
}
if ctx.GetOp().GetTokenType() == parser.PlanParserNIN {
expr = &planpb.Expr{
Expr: &planpb.Expr_UnaryExpr{
UnaryExpr: &planpb.UnaryExpr{
Op: planpb.UnaryExpr_Not,
Child: expr,
},
},
}
}
return &ExprWithType{
expr: expr,
dataType: schemapb.DataType_Bool,
}
}
// VisitRange translates expr to range plan.
func (v *ParserVisitor) VisitRange(ctx *parser.RangeContext) interface{} {
child := ctx.Expr(1).Accept(v)
if err := getError(child); err != nil {
return err
}
childValue := getGenericValue(child)
if childValue != nil {
return fmt.Errorf("'range' can only be used on non-const expression")
}
childExpr := getExpr(child)
columnInfo := toColumnInfo(childExpr)
if columnInfo == nil {
return fmt.Errorf("range operations are only supported on single fields now, got: %s", ctx.Expr(1).GetText())
}
lower := ctx.Expr(0).Accept(v)
upper := ctx.Expr(2).Accept(v)
if err := getError(lower); err != nil {
return err
}
if err := getError(upper); err != nil {
return err
}
lowerValue := getGenericValue(lower)
upperValue := getGenericValue(upper)
if lowerValue == nil {
return fmt.Errorf("lowerbound cannot be a non-const expression: %s", ctx.Expr(0).GetText())
}
if upperValue == nil {
return fmt.Errorf("upperbound cannot be a non-const expression: %s", ctx.Expr(1).GetText())
}
switch childExpr.dataType {
case schemapb.DataType_String, schemapb.DataType_VarChar:
if !IsString(lowerValue) || !IsString(upperValue) {
return fmt.Errorf("invalid range operations")
}
case schemapb.DataType_Bool:
return fmt.Errorf("invalid range operations on boolean expr")
case schemapb.DataType_Int8, schemapb.DataType_Int16, schemapb.DataType_Int32, schemapb.DataType_Int64:
if !IsInteger(lowerValue) || !IsInteger(upperValue) {
return fmt.Errorf("invalid range operations")
}
case schemapb.DataType_Float, schemapb.DataType_Double:
if !IsNumber(lowerValue) || !IsNumber(upperValue) {
return fmt.Errorf("invalid range operations")
}
if IsInteger(lowerValue) {
lowerValue = NewFloat(float64(lowerValue.GetInt64Val()))
}
if IsInteger(upperValue) {
upperValue = NewFloat(float64(upperValue.GetInt64Val()))
}
}
lowerInclusive := ctx.GetOp1().GetTokenType() == parser.PlanParserLE
upperInclusive := ctx.GetOp2().GetTokenType() == parser.PlanParserLE
// if !(lowerInclusive && upperInclusive) {
// if getGenericValue(GreaterEqual(lowerValue, upperValue)).GetBoolVal() {
// return fmt.Errorf("invalid range: lowerbound is greater than upperbound")
// }
// } else {
// if getGenericValue(Greater(lowerValue, upperValue)).GetBoolVal() {
// return fmt.Errorf("invalid range: lowerbound is greater than upperbound")
// }
// }
expr := &planpb.Expr{
Expr: &planpb.Expr_BinaryRangeExpr{
BinaryRangeExpr: &planpb.BinaryRangeExpr{
ColumnInfo: columnInfo,
LowerInclusive: lowerInclusive,
UpperInclusive: upperInclusive,
LowerValue: lowerValue,
UpperValue: upperValue,
},
},
}
return &ExprWithType{
expr: expr,
dataType: schemapb.DataType_Bool,
}
}
// VisitReverseRange parses the expression like "1 > a > 0".
func (v *ParserVisitor) VisitReverseRange(ctx *parser.ReverseRangeContext) interface{} {
child := ctx.Expr(1).Accept(v)
if err := getError(child); err != nil {
return err
}
childValue := getGenericValue(child)
if childValue != nil {
return fmt.Errorf("'range' can only be used on non-const expression")
}
childExpr := getExpr(child)
columnInfo := toColumnInfo(childExpr)
if columnInfo == nil {
return fmt.Errorf("range operations are only supported on single fields now, got: %s", ctx.Expr(1).GetText())
}
lower := ctx.Expr(2).Accept(v)
upper := ctx.Expr(0).Accept(v)
if err := getError(lower); err != nil {
return err
}
if err := getError(upper); err != nil {
return err
}
lowerValue := getGenericValue(lower)
upperValue := getGenericValue(upper)
if lowerValue == nil {
return fmt.Errorf("lowerbound cannot be a non-const expression: %s", ctx.Expr(0).GetText())
}
if upperValue == nil {
return fmt.Errorf("upperbound cannot be a non-const expression: %s", ctx.Expr(1).GetText())
}
switch childExpr.dataType {
case schemapb.DataType_String, schemapb.DataType_VarChar:
if !IsString(lowerValue) || !IsString(upperValue) {
return fmt.Errorf("invalid range operations")
}
case schemapb.DataType_Bool:
return fmt.Errorf("invalid range operations on boolean expr")
case schemapb.DataType_Int8, schemapb.DataType_Int16, schemapb.DataType_Int32, schemapb.DataType_Int64:
if !IsInteger(lowerValue) || !IsInteger(upperValue) {
return fmt.Errorf("invalid range operations")
}
case schemapb.DataType_Float, schemapb.DataType_Double:
if !IsNumber(lowerValue) || !IsNumber(upperValue) {
return fmt.Errorf("invalid range operations")
}
if IsInteger(lowerValue) {
lowerValue = NewFloat(float64(lowerValue.GetInt64Val()))
}
if IsInteger(upperValue) {
upperValue = NewFloat(float64(upperValue.GetInt64Val()))
}
}
lowerInclusive := ctx.GetOp2().GetTokenType() == parser.PlanParserGE
upperInclusive := ctx.GetOp1().GetTokenType() == parser.PlanParserGE
// if !(lowerInclusive && upperInclusive) {
// if getGenericValue(GreaterEqual(lowerValue, upperValue)).GetBoolVal() {
// return fmt.Errorf("invalid range: lowerbound is greater than upperbound")
// }
// } else {
// if getGenericValue(Greater(lowerValue, upperValue)).GetBoolVal() {
// return fmt.Errorf("invalid range: lowerbound is greater than upperbound")
// }
// }
expr := &planpb.Expr{
Expr: &planpb.Expr_BinaryRangeExpr{
BinaryRangeExpr: &planpb.BinaryRangeExpr{
ColumnInfo: columnInfo,
LowerInclusive: lowerInclusive,
UpperInclusive: upperInclusive,
LowerValue: lowerValue,
UpperValue: upperValue,
},
},
}
return &ExprWithType{
expr: expr,
dataType: schemapb.DataType_Bool,
}
}
// VisitUnary unpack the +expr to expr.
func (v *ParserVisitor) VisitUnary(ctx *parser.UnaryContext) interface{} {
child := ctx.Expr().Accept(v)
if err := getError(child); err != nil {
return err
}
childValue := getGenericValue(child)
if childValue != nil {
switch ctx.GetOp().GetTokenType() {
case parser.PlanParserADD:
return child
case parser.PlanParserSUB:
return Negative(childValue)
case parser.PlanParserNOT:
return Not(childValue)
default:
return fmt.Errorf("unexpected op: %s", ctx.GetOp().GetText())
}
}
childExpr := getExpr(child)
if childExpr == nil {
return fmt.Errorf("failed to parse unary expressions")
}
switch ctx.GetOp().GetTokenType() {
case parser.PlanParserADD:
return childExpr
case parser.PlanParserNOT:
if !typeutil.IsBoolType(childExpr.dataType) {
return fmt.Errorf("%s op can only be applied on boolean expression", unaryLogicalNameMap[parser.PlanParserNOT])
}
return &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_UnaryExpr{
UnaryExpr: &planpb.UnaryExpr{
Op: unaryLogicalOpMap[parser.PlanParserNOT],
Child: childExpr.expr,
},
},
},
dataType: schemapb.DataType_Bool,
}
default:
return fmt.Errorf("unexpected op: %s", ctx.GetOp().GetText())
}
}
// VisitLogicalOr apply logical or to two boolean expressions.
func (v *ParserVisitor) VisitLogicalOr(ctx *parser.LogicalOrContext) interface{} {
left := ctx.Expr(0).Accept(v)
if err := getError(left); err != nil {
return err
}
right := ctx.Expr(1).Accept(v)
if err := getError(right); err != nil {
return err
}
leftValue, rightValue := getGenericValue(left), getGenericValue(right)
if leftValue != nil && rightValue != nil {
n, err := Or(leftValue, rightValue)
if err != nil {
return err
}
return n
}
if leftValue != nil || rightValue != nil {
return fmt.Errorf("'or' can only be used between boolean expressions")
}
var leftExpr *ExprWithType
var rightExpr *ExprWithType
leftExpr = getExpr(left)
rightExpr = getExpr(right)
if !typeutil.IsBoolType(leftExpr.dataType) || !typeutil.IsBoolType(rightExpr.dataType) {
return fmt.Errorf("'or' can only be used between boolean expressions")
}
expr := &planpb.Expr{
Expr: &planpb.Expr_BinaryExpr{
BinaryExpr: &planpb.BinaryExpr{
Left: leftExpr.expr,
Right: rightExpr.expr,
Op: planpb.BinaryExpr_LogicalOr,
},
},
}
return &ExprWithType{
expr: expr,
dataType: schemapb.DataType_Bool,
}
}
// VisitLogicalAnd apply logical and to two boolean expressions.
func (v *ParserVisitor) VisitLogicalAnd(ctx *parser.LogicalAndContext) interface{} {
left := ctx.Expr(0).Accept(v)
if err := getError(left); err != nil {
return err
}
right := ctx.Expr(1).Accept(v)
if err := getError(right); err != nil {
return err
}
leftValue, rightValue := getGenericValue(left), getGenericValue(right)
if leftValue != nil && rightValue != nil {
n, err := And(leftValue, rightValue)
if err != nil {
return err
}
return n
}
if leftValue != nil || rightValue != nil {
return fmt.Errorf("'and' can only be used between boolean expressions")
}
var leftExpr *ExprWithType
var rightExpr *ExprWithType
leftExpr = getExpr(left)
rightExpr = getExpr(right)
if !typeutil.IsBoolType(leftExpr.dataType) || !typeutil.IsBoolType(rightExpr.dataType) {
return fmt.Errorf("'and' can only be used between boolean expressions")
}
expr := &planpb.Expr{
Expr: &planpb.Expr_BinaryExpr{
BinaryExpr: &planpb.BinaryExpr{
Left: leftExpr.expr,
Right: rightExpr.expr,
Op: planpb.BinaryExpr_LogicalAnd,
},
},
}
return &ExprWithType{
expr: expr,
dataType: schemapb.DataType_Bool,
}
}
// VisitBitXor not supported.
func (v *ParserVisitor) VisitBitXor(ctx *parser.BitXorContext) interface{} {
return fmt.Errorf("BitXor is not supported: %s", ctx.GetText())
}
// VisitBitAnd not supported.
func (v *ParserVisitor) VisitBitAnd(ctx *parser.BitAndContext) interface{} {
return fmt.Errorf("BitAnd is not supported: %s", ctx.GetText())
}
// VisitPower parses power expression.
func (v *ParserVisitor) VisitPower(ctx *parser.PowerContext) interface{} {
left := ctx.Expr(0).Accept(v)
if err := getError(left); err != nil {
return err
}
right := ctx.Expr(1).Accept(v)
if err := getError(right); err != nil {
return err
}
leftValue, rightValue := getGenericValue(left), getGenericValue(right)
if leftValue != nil && rightValue != nil {
return Power(leftValue, rightValue)
}
return fmt.Errorf("power can only apply on constants: %s", ctx.GetText())
}
// VisitShift unsupported.
func (v *ParserVisitor) VisitShift(ctx *parser.ShiftContext) interface{} {
return fmt.Errorf("shift is not supported: %s", ctx.GetText())
}
// VisitBitOr unsupported.
func (v *ParserVisitor) VisitBitOr(ctx *parser.BitOrContext) interface{} {
return fmt.Errorf("BitOr is not supported: %s", ctx.GetText())
}

View File

@ -0,0 +1,106 @@
package planparserv2
import (
"fmt"
"github.com/milvus-io/milvus/internal/proto/planpb"
"github.com/milvus-io/milvus/internal/proto/schemapb"
"github.com/milvus-io/milvus/internal/util/typeutil"
"github.com/antlr/antlr4/runtime/Go/antlr"
)
func handleExpr(schema *typeutil.SchemaHelper, exprStr string) interface{} {
if exprStr == "" {
return nil
}
inputStream := antlr.NewInputStream(exprStr)
errorListener := &errorListener{}
parser := getParser(inputStream, errorListener)
ast := parser.Expr()
if errorListener.err != nil {
return errorListener.err
}
visitor := NewParserVisitor(schema)
return ast.Accept(visitor)
}
func ParseExpr(schema *typeutil.SchemaHelper, exprStr string) (*planpb.Expr, error) {
if len(exprStr) <= 0 {
return nil, nil
}
ret := handleExpr(schema, exprStr)
if err := getError(ret); err != nil {
return nil, fmt.Errorf("cannot parse expression: %s, error: %s", exprStr, err)
}
predicate := getExpr(ret)
if predicate == nil {
return nil, fmt.Errorf("cannot parse expression: %s", exprStr)
}
if !typeutil.IsBoolType(predicate.dataType) {
return nil, fmt.Errorf("predicate is not a boolean expression: %s, data type: %s", exprStr, predicate.dataType)
}
return predicate.expr, nil
}
func CreateRetrievePlan(schemaPb *schemapb.CollectionSchema, exprStr string) (*planpb.PlanNode, error) {
schema, err := typeutil.CreateSchemaHelper(schemaPb)
if err != nil {
return nil, err
}
expr, err := ParseExpr(schema, exprStr)
if err != nil {
return nil, err
}
planNode := &planpb.PlanNode{
Node: &planpb.PlanNode_Predicates{
Predicates: expr,
},
}
return planNode, nil
}
func CreateSearchPlan(schemaPb *schemapb.CollectionSchema, exprStr string, vectorFieldName string, queryInfo *planpb.QueryInfo) (*planpb.PlanNode, error) {
schema, err := typeutil.CreateSchemaHelper(schemaPb)
if err != nil {
return nil, err
}
expr, err := ParseExpr(schema, exprStr)
if err != nil {
return nil, err
}
vectorField, err := schema.GetFieldFromName(vectorFieldName)
if err != nil {
return nil, err
}
fieldID := vectorField.FieldID
dataType := vectorField.DataType
if !typeutil.IsVectorType(dataType) {
return nil, fmt.Errorf("field (%s) to search is not of vector data type", vectorFieldName)
}
planNode := &planpb.PlanNode{
Node: &planpb.PlanNode_VectorAnns{
VectorAnns: &planpb.VectorANNS{
IsBinary: dataType == schemapb.DataType_BinaryVector,
Predicates: expr,
QueryInfo: queryInfo,
PlaceholderTag: "$0",
FieldId: fieldID,
},
},
}
return planNode, nil
}

View File

@ -0,0 +1,479 @@
package planparserv2
import (
"testing"
"github.com/milvus-io/milvus/internal/proto/planpb"
"github.com/stretchr/testify/assert"
"github.com/milvus-io/milvus/internal/proto/schemapb"
"github.com/milvus-io/milvus/internal/util/typeutil"
)
func newTestSchema() *schemapb.CollectionSchema {
fields := []*schemapb.FieldSchema{
{FieldID: 0, Name: "FieldID", IsPrimaryKey: false, Description: "field no.1", DataType: schemapb.DataType_Int64},
}
for name, value := range schemapb.DataType_value {
dataType := schemapb.DataType(value)
newField := &schemapb.FieldSchema{
FieldID: int64(100 + value), Name: name + "Field", IsPrimaryKey: false, Description: "", DataType: dataType,
}
fields = append(fields, newField)
}
return &schemapb.CollectionSchema{
Name: "test",
Description: "schema for test used",
AutoID: true,
Fields: fields,
}
}
func assertValidExpr(t *testing.T, helper *typeutil.SchemaHelper, exprStr string) {
_, err := ParseExpr(helper, exprStr)
assert.NoError(t, err, exprStr)
// expr, err := ParseExpr(helper, exprStr)
// assert.NoError(t, err, exprStr)
// fmt.Printf("expr: %s\n", exprStr)
// ShowExpr(expr)
}
func assertInvalidExpr(t *testing.T, helper *typeutil.SchemaHelper, exprStr string) {
_, err := ParseExpr(helper, exprStr)
assert.Error(t, err, exprStr)
}
func TestExpr_Term(t *testing.T) {
schema := newTestSchema()
helper, err := typeutil.CreateSchemaHelper(schema)
assert.NoError(t, err)
exprStrs := []string{
`BoolField in [true, false]`,
`Int8Field in [1, 2]`,
`Int16Field in [3, 4]`,
`Int32Field in [5, 6]`,
`Int64Field in [7, 8]`,
`FloatField in [9.0, 10.0]`,
`DoubleField in [11.0, 12.0]`,
`StringField in ["str13", "str14"]`,
`VarCharField in ["str15", "str16"]`,
`FloatField in [1373, 115]`,
`Int64Field in []`,
`Int64Field not in []`,
}
for _, exprStr := range exprStrs {
assertValidExpr(t, helper, exprStr)
}
}
func TestExpr_Compare(t *testing.T) {
schema := newTestSchema()
helper, err := typeutil.CreateSchemaHelper(schema)
assert.NoError(t, err)
exprStrs := []string{
`Int8Field < Int16Field`,
`Int16Field <= Int32Field`,
`Int32Field > Int64Field`,
`Int64Field >= FloatField`,
`FloatField == DoubleField`,
`StringField != VarCharField`,
}
for _, exprStr := range exprStrs {
assertValidExpr(t, helper, exprStr)
}
}
func TestExpr_UnaryRange(t *testing.T) {
schema := newTestSchema()
helper, err := typeutil.CreateSchemaHelper(schema)
assert.NoError(t, err)
exprStrs := []string{
`Int8Field < 0`,
`Int16Field <= 1`,
`Int32Field > 2`,
`Int64Field >= 3`,
`FloatField == 4.0`,
`FloatField == 2`,
`DoubleField != 5.0`,
`StringField > "str6"`,
`VarCharField <= "str7"`,
}
for _, exprStr := range exprStrs {
assertValidExpr(t, helper, exprStr)
}
}
func TestExpr_Like(t *testing.T) {
schema := newTestSchema()
helper, err := typeutil.CreateSchemaHelper(schema)
assert.NoError(t, err)
exprStrs := []string{
`VarCharField like "prefix%"`,
}
for _, exprStr := range exprStrs {
assertValidExpr(t, helper, exprStr)
}
}
func TestExpr_BinaryRange(t *testing.T) {
schema := newTestSchema()
helper, err := typeutil.CreateSchemaHelper(schema)
assert.NoError(t, err)
exprStrs := []string{
`1 < Int8Field < 2`,
`3 <= Int16Field < 4`,
`5 <= Int32Field <= 6`,
`7 < Int64Field <= 8`,
`9.0 < FloatField < 10.0`,
`11.0 < DoubleField < 12.0`,
`"str13" < StringField < "str14"`,
`"str15" < VarCharField < "str16"`,
`17 < DoubleField < 18`,
`2 > Int8Field > 1`,
`4 >= Int16Field >= 3`,
`6 >= Int32Field >= 5`,
`8 >= Int64Field > 7`,
`10.0 > FloatField > 9.0`,
`12.0 > DoubleField > 11.0`,
`"str14" > StringField > "str13"`,
`"str16" > VarCharField > "str15"`,
`18 > DoubleField > 17`,
}
for _, exprStr := range exprStrs {
assertValidExpr(t, helper, exprStr)
}
}
func TestExpr_BinaryArith(t *testing.T) {
schema := newTestSchema()
helper, err := typeutil.CreateSchemaHelper(schema)
assert.NoError(t, err)
exprStrs := []string{
`Int64Field % 10 == 9`,
`Int64Field % 10 != 9`,
}
for _, exprStr := range exprStrs {
assertValidExpr(t, helper, exprStr)
}
// TODO: enable these after execution backend is ready.
unsupported := []string{
`Int8Field + 1 < 2`,
`Int16Field - 3 <= 4`,
`Int32Field * 5 > 6`,
`Int64Field / 7 >= 8`,
`FloatField + 11 < 12`,
`DoubleField - 13 < 14`,
}
for _, exprStr := range unsupported {
assertInvalidExpr(t, helper, exprStr)
}
}
func TestExpr_Value(t *testing.T) {
schema := newTestSchema()
helper, err := typeutil.CreateSchemaHelper(schema)
assert.NoError(t, err)
exprStrs := []string{
`1`,
`2.0`,
`true`,
`false`,
`"str"`,
}
for _, exprStr := range exprStrs {
expr := handleExpr(helper, exprStr)
assert.NotNil(t, getExpr(expr).expr, exprStr)
// fmt.Printf("expr: %s\n", exprStr)
// ShowExpr(getExpr(expr).expr)
}
}
func TestExpr_Identifier(t *testing.T) {
schema := newTestSchema()
helper, err := typeutil.CreateSchemaHelper(schema)
assert.NoError(t, err)
exprStrs := []string{
`BoolField`,
`Int8Field`,
`Int16Field`,
`Int32Field`,
`Int64Field`,
`FloatField`,
`DoubleField`,
`StringField`,
`VarCharField`,
}
for _, exprStr := range exprStrs {
expr := handleExpr(helper, exprStr)
assert.NotNil(t, getExpr(expr).expr, exprStr)
// fmt.Printf("expr: %s\n", exprStr)
// ShowExpr(getExpr(expr).expr)
}
}
func TestExpr_Constant(t *testing.T) {
schema := newTestSchema()
helper, err := typeutil.CreateSchemaHelper(schema)
assert.NoError(t, err)
exprStrs := []string{
// ------------------- arithmetic operations ----------------
`1.0 + 2.0`,
`1.0 + 2`,
`1 + 2.0`,
`1 + 2`,
`1.0 - 2.0`,
`1.0 - 2`,
`1 - 2.0`,
`1 - 2`,
`1.0 * 2.0`,
`1.0 * 2`,
`1 * 2.0`,
`1 * 2`,
`1.0 / 2.0`,
`1.0 / 2`,
`1 / 2.0`,
`1 / 2`,
`1 % 2`,
// ------------------- logical operations ----------------
`true and false`,
`true or false`,
`!true`,
`!false`,
// ------------------- relational operations ----------------
`"1" < "2"`,
`1.0 < 2.0`,
`1.0 < 2`,
`1 < 2.0`,
`1 < 2`,
`"1" <= "2"`,
`1.0 <= 2.0`,
`1.0 <= 2`,
`1 <= 2.0`,
`1 <= 2`,
`"1" > "2"`,
`1.0 > 2.0`,
`1.0 > 2`,
`1 > 2.0`,
`1 > 2`,
`"1" >= "2"`,
`1.0 >= 2.0`,
`1.0 >= 2`,
`1 >= 2.0`,
`1 >= 2`,
`"1" == "2"`,
`1.0 == 2.0`,
`1.0 == 2`,
`1 == 2.0`,
`1 == 2`,
`true == false`,
`"1" != "2"`,
`1.0 != 2.0`,
`1.0 != 2`,
`1 != 2.0`,
`1 != 2`,
`true != false`,
}
for _, exprStr := range exprStrs {
expr := handleExpr(helper, exprStr)
assert.NotNil(t, getExpr(expr).expr, exprStr)
// fmt.Printf("expr: %s\n", exprStr)
// ShowExpr(getExpr(expr).expr)
}
}
func TestExpr_Combinations(t *testing.T) {
schema := newTestSchema()
helper, err := typeutil.CreateSchemaHelper(schema)
assert.NoError(t, err)
exprStrs := []string{
`not (Int8Field + 1 == 2)`,
`(Int16Field - 3 == 4) and (Int32Field * 5 != 6)`,
`(Int64Field / 7 != 8) or (Int64Field % 10 == 9)`,
}
for _, exprStr := range exprStrs {
assertValidExpr(t, helper, exprStr)
}
}
func TestCreateRetrievePlan(t *testing.T) {
schema := newTestSchema()
_, err := CreateRetrievePlan(schema, "Int64Field > 0")
assert.NoError(t, err)
}
func TestCreateSearchPlan(t *testing.T) {
schema := newTestSchema()
_, err := CreateSearchPlan(schema, "Int64Field > 0", "FloatVectorField", &planpb.QueryInfo{
Topk: 0,
MetricType: "",
SearchParams: "",
RoundDecimal: 0,
})
assert.NoError(t, err)
}
func TestExpr_Invalid(t *testing.T) {
schema := newTestSchema()
helper, err := typeutil.CreateSchemaHelper(schema)
assert.NoError(t, err)
exprStrs := []string{
`invalid expression`,
`"constant"`,
// -------------- identifier not in schema --------------
`not_in_schema`,
// ------------------------ Add/Sub ---------------------
`not_in_schema + 1`,
`1 - not_in_schema`,
`true + false`,
`"str" + "text"`,
`true + "str"`,
`true - false`,
`"str" - "text"`,
`true - "str"`,
`StringField + VarCharField`,
`StringField - 2`,
`2 + StringField`,
// ------------------------ Mul/Div/Mod ---------------------
`not_in_schema * 1`,
`1 / not_in_schema`,
`1 % not_in_schema`,
`true * false`,
`true / false`,
`true % false`,
`"str" * "text"`,
`"str" / "text"`,
`"str" % "text"`,
`2 / 0`,
`2 % 0`,
`StringField % VarCharField`,
`StringField * 2`,
`2 / StringField`,
// ----------------------- ==/!= -------------------------
`not_in_schema != 1`,
`1 == not_in_schema`,
`true == "str"`,
`"str" != false`,
// ---------------------- relational --------------------
`not_in_schema < 1`,
`1 <= not_in_schema`,
`true <= "str"`,
`"str" >= false`,
// ------------------------ like ------------------------
`(VarCharField % 2) like "prefix%"`,
`FloatField like "prefix%"`,
`value like "prefix%"`,
// ------------------------ term ------------------------
`not_in_schema in [1, 2, 3]`,
`1 in [1, 2, 3]`,
`(Int8Field + 8) in [1, 2, 3]`,
`Int8Field in [(true + 1)]`,
`Int8Field in [Int16Field]`,
`BoolField in [4.0]`,
`VarCharField in [4.0]`,
`Int32Field in [4.0]`,
`FloatField in [5, 6.0, true]`,
// ----------------------- range -------------------------
`1 < not_in_schema < 2`,
`1 < 3 < 2`,
`1 < (Int8Field + Int16Field) < 2`,
`(invalid_lower) < Int32Field < 2`,
`1 < Int32Field < (invalid_upper)`,
`(Int8Field) < Int32Field < 2`,
`1 < Int32Field < (Int16Field)`,
`1 < StringField < 2`,
`1 < BoolField < 2`,
`1.0 < Int32Field < 2.0`,
`true < FloatField < false`,
// `2 <= Int32Field <= 1`,
`2 = Int32Field = 1`,
`true = BoolField = false`,
// ----------------------- unary ------------------------
`-true`,
`!"str"`,
`!(not_in_schema)`,
`-Int32Field`,
`!(Int32Field)`,
// ----------------------- or/and ------------------------
`not_in_schema or true`,
`false or not_in_schema`,
`"str" or false`,
`BoolField or false`,
`Int32Field or Int64Field`,
`not_in_schema and true`,
`false and not_in_schema`,
`"str" and false`,
`BoolField and false`,
`Int32Field and Int64Field`,
// -------------------- unsupported ----------------------
`1 ^ 2`,
`1 & 2`,
`1 ** 2`,
`1 << 2`,
`1 | 2`,
}
for _, exprStr := range exprStrs {
_, err := ParseExpr(helper, exprStr)
assert.Error(t, err, exprStr)
}
}
func TestCreateRetrievePlan_Invalid(t *testing.T) {
t.Run("invalid schema", func(t *testing.T) {
schema := newTestSchema()
schema.Fields = append(schema.Fields, schema.Fields[0])
_, err := CreateRetrievePlan(schema, "")
assert.Error(t, err)
})
t.Run("invalid expr", func(t *testing.T) {
schema := newTestSchema()
_, err := CreateRetrievePlan(schema, "invalid expression")
assert.Error(t, err)
})
}
func TestCreateSearchPlan_Invalid(t *testing.T) {
t.Run("invalid schema", func(t *testing.T) {
schema := newTestSchema()
schema.Fields = append(schema.Fields, schema.Fields[0])
_, err := CreateSearchPlan(schema, "", "", nil)
assert.Error(t, err)
})
t.Run("invalid expr", func(t *testing.T) {
schema := newTestSchema()
_, err := CreateSearchPlan(schema, "invalid expression", "", nil)
assert.Error(t, err)
})
t.Run("invalid vector field", func(t *testing.T) {
schema := newTestSchema()
_, err := CreateSearchPlan(schema, "Int64Field > 0", "not_exist", nil)
assert.Error(t, err)
})
t.Run("not vector type", func(t *testing.T) {
schema := newTestSchema()
_, err := CreateSearchPlan(schema, "Int64Field > 0", "VarCharField", nil)
assert.Error(t, err)
})
}

View File

@ -0,0 +1,50 @@
package planparserv2
import (
"sync"
"github.com/antlr/antlr4/runtime/Go/antlr"
antlrparser "github.com/milvus-io/milvus/internal/parser/planparserv2/generated"
)
var (
lexerPool = sync.Pool{
New: func() interface{} {
return antlrparser.NewPlanLexer(nil)
},
}
parserPool = sync.Pool{
New: func() interface{} {
return antlrparser.NewPlanParser(nil)
},
}
)
func getLexer(stream *antlr.InputStream, listeners ...antlr.ErrorListener) *antlrparser.PlanLexer {
lexer, ok := lexerPool.Get().(*antlrparser.PlanLexer)
if !ok {
lexer = antlrparser.NewPlanLexer(nil)
}
lexer.SetInputStream(stream)
for _, listener := range listeners {
lexer.AddErrorListener(listener)
}
lexerPool.Put(lexer)
return lexer
}
func getParser(stream *antlr.InputStream, listeners ...antlr.ErrorListener) *antlrparser.PlanParser {
lexer := getLexer(stream, listeners...)
tokenStream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)
parser, ok := parserPool.Get().(*antlrparser.PlanParser)
if !ok {
parser = antlrparser.NewPlanParser(nil)
}
parser.SetInputStream(tokenStream)
parser.BuildParseTrees = true
for _, listener := range listeners {
parser.AddErrorListener(listener)
}
parserPool.Put(parser)
return parser
}

View File

@ -0,0 +1,35 @@
package planparserv2
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/antlr/antlr4/runtime/Go/antlr"
antlrparser "github.com/milvus-io/milvus/internal/parser/planparserv2/generated"
)
func genNaiveInputStream() *antlr.InputStream {
return antlr.NewInputStream("a > 2")
}
func Test_getLexer(t *testing.T) {
var lexer *antlrparser.PlanLexer
lexer = getLexer(genNaiveInputStream(), &errorListener{})
assert.NotNil(t, lexer)
lexer = getLexer(genNaiveInputStream(), &errorListener{})
assert.NotNil(t, lexer)
}
func Test_getParser(t *testing.T) {
var parser *antlrparser.PlanParser
parser = getParser(genNaiveInputStream(), &errorListener{})
assert.NotNil(t, parser)
parser = getParser(genNaiveInputStream(), &errorListener{})
assert.NotNil(t, parser)
}

View File

@ -0,0 +1,168 @@
package planparserv2
import (
"encoding/json"
"fmt"
"github.com/milvus-io/milvus/internal/proto/planpb"
)
type ShowExprVisitor struct {
}
func extractColumnInfo(info *planpb.ColumnInfo) interface{} {
js := make(map[string]interface{})
js["field_id"] = info.GetFieldId()
js["data_type"] = info.GetDataType().String()
js["auto_id"] = info.GetIsAutoID()
js["is_pk"] = info.GetIsPrimaryKey()
return js
}
func extractGenericValue(value *planpb.GenericValue) interface{} {
switch realValue := value.Val.(type) {
case *planpb.GenericValue_BoolVal:
return realValue.BoolVal
case *planpb.GenericValue_Int64Val:
return realValue.Int64Val
case *planpb.GenericValue_FloatVal:
// // floating point value is not convenient to compare.
// return strconv.FormatFloat(realValue.FloatVal, 'g', 10, 64)
return realValue.FloatVal
case *planpb.GenericValue_StringVal:
return realValue.StringVal
default:
return nil
}
}
func (v *ShowExprVisitor) VisitExpr(expr *planpb.Expr) interface{} {
js := make(map[string]interface{})
switch realExpr := expr.Expr.(type) {
case *planpb.Expr_TermExpr:
js["expr"] = v.VisitTermExpr(realExpr.TermExpr)
case *planpb.Expr_UnaryExpr:
js["expr"] = v.VisitUnaryExpr(realExpr.UnaryExpr)
case *planpb.Expr_BinaryExpr:
js["expr"] = v.VisitBinaryExpr(realExpr.BinaryExpr)
case *planpb.Expr_CompareExpr:
js["expr"] = v.VisitCompareExpr(realExpr.CompareExpr)
case *planpb.Expr_UnaryRangeExpr:
js["expr"] = v.VisitUnaryRangeExpr(realExpr.UnaryRangeExpr)
case *planpb.Expr_BinaryRangeExpr:
js["expr"] = v.VisitBinaryRangeExpr(realExpr.BinaryRangeExpr)
case *planpb.Expr_BinaryArithOpEvalRangeExpr:
js["expr"] = v.VisitBinaryArithOpEvalRangeExpr(realExpr.BinaryArithOpEvalRangeExpr)
case *planpb.Expr_BinaryArithExpr:
js["expr"] = v.VisitBinaryArithExpr(realExpr.BinaryArithExpr)
case *planpb.Expr_ValueExpr:
js["expr"] = v.VisitValueExpr(realExpr.ValueExpr)
case *planpb.Expr_ColumnExpr:
js["expr"] = v.VisitColumnExpr(realExpr.ColumnExpr)
default:
js["expr"] = ""
}
return js
}
func (v *ShowExprVisitor) VisitTermExpr(expr *planpb.TermExpr) interface{} {
js := make(map[string]interface{})
js["expr_type"] = "term"
js["column_info"] = extractColumnInfo(expr.ColumnInfo)
terms := make([]interface{}, 0, len(expr.Values))
for _, v := range expr.Values {
terms = append(terms, extractGenericValue(v))
}
js["terms"] = terms
return js
}
func (v *ShowExprVisitor) VisitUnaryExpr(expr *planpb.UnaryExpr) interface{} {
js := make(map[string]interface{})
js["expr_type"] = expr.Op.String()
js["child"] = v.VisitExpr(expr.Child)
return js
}
func (v *ShowExprVisitor) VisitBinaryExpr(expr *planpb.BinaryExpr) interface{} {
js := make(map[string]interface{})
js["expr_type"] = expr.Op.String()
js["left_child"] = v.VisitExpr(expr.Left)
js["right_child"] = v.VisitExpr(expr.Right)
return js
}
func (v *ShowExprVisitor) VisitCompareExpr(expr *planpb.CompareExpr) interface{} {
js := make(map[string]interface{})
js["expr_type"] = "compare"
js["op"] = expr.Op.String()
js["left_column_info"] = extractColumnInfo(expr.LeftColumnInfo)
js["right_column_info"] = extractColumnInfo(expr.RightColumnInfo)
return js
}
func (v *ShowExprVisitor) VisitUnaryRangeExpr(expr *planpb.UnaryRangeExpr) interface{} {
js := make(map[string]interface{})
js["expr_type"] = "unary_range"
js["op"] = expr.Op.String()
js["column_info"] = extractColumnInfo(expr.GetColumnInfo())
js["operand"] = extractGenericValue(expr.Value)
return js
}
func (v *ShowExprVisitor) VisitBinaryRangeExpr(expr *planpb.BinaryRangeExpr) interface{} {
js := make(map[string]interface{})
js["expr_type"] = "binary_range"
js["column_info"] = extractColumnInfo(expr.GetColumnInfo())
js["lower_value"] = extractGenericValue(expr.GetLowerValue())
js["upper_value"] = extractGenericValue(expr.GetUpperValue())
js["lower_inclusive"] = expr.GetLowerInclusive()
js["upper_inclusive"] = expr.GetUpperInclusive()
return js
}
func (v *ShowExprVisitor) VisitBinaryArithOpEvalRangeExpr(expr *planpb.BinaryArithOpEvalRangeExpr) interface{} {
js := make(map[string]interface{})
js["expr_type"] = "binary_arith_op_eval_range"
js["column_info"] = extractColumnInfo(expr.ColumnInfo)
js["arith_op"] = expr.ArithOp.String()
js["right_operand"] = extractGenericValue(expr.GetRightOperand())
js["op"] = expr.Op.String()
js["value"] = extractGenericValue(expr.GetValue())
return js
}
func (v *ShowExprVisitor) VisitBinaryArithExpr(expr *planpb.BinaryArithExpr) interface{} {
js := make(map[string]interface{})
js["expr_type"] = "binary_arith"
js["left_expr"] = v.VisitExpr(expr.GetLeft())
js["right_expr"] = v.VisitExpr(expr.GetRight())
js["op"] = expr.Op.String()
return js
}
func (v *ShowExprVisitor) VisitValueExpr(expr *planpb.ValueExpr) interface{} {
js := make(map[string]interface{})
js["expr_type"] = "value_expr"
js["value"] = extractGenericValue(expr.GetValue())
return js
}
func (v *ShowExprVisitor) VisitColumnExpr(expr *planpb.ColumnExpr) interface{} {
js := make(map[string]interface{})
js["expr_type"] = "column"
js["column_info"] = extractColumnInfo(expr.GetInfo())
return js
}
func NewShowExprVisitor() LogicalExprVisitor {
return &ShowExprVisitor{}
}
// ShowExpr print the expr tree, used for debugging, not safe.
func ShowExpr(expr *planpb.Expr) {
v := NewShowExprVisitor()
js := v.VisitExpr(expr)
b, _ := json.MarshalIndent(js, "", " ")
fmt.Println(string(b))
}

View File

@ -0,0 +1,322 @@
package planparserv2
import (
"fmt"
"github.com/milvus-io/milvus/internal/util/typeutil"
"github.com/milvus-io/milvus/internal/proto/planpb"
"github.com/milvus-io/milvus/internal/proto/schemapb"
)
func IsBool(n *planpb.GenericValue) bool {
switch n.GetVal().(type) {
case *planpb.GenericValue_BoolVal:
return true
}
return false
}
func IsInteger(n *planpb.GenericValue) bool {
switch n.GetVal().(type) {
case *planpb.GenericValue_Int64Val:
return true
}
return false
}
func IsFloating(n *planpb.GenericValue) bool {
switch n.GetVal().(type) {
case *planpb.GenericValue_FloatVal:
return true
}
return false
}
func IsNumber(n *planpb.GenericValue) bool {
return IsInteger(n) || IsFloating(n)
}
func IsString(n *planpb.GenericValue) bool {
switch n.GetVal().(type) {
case *planpb.GenericValue_StringVal:
return true
}
return false
}
func NewBool(value bool) *planpb.GenericValue {
return &planpb.GenericValue{
Val: &planpb.GenericValue_BoolVal{
BoolVal: value,
},
}
}
func NewInt(value int64) *planpb.GenericValue {
return &planpb.GenericValue{
Val: &planpb.GenericValue_Int64Val{
Int64Val: value,
},
}
}
func NewFloat(value float64) *planpb.GenericValue {
return &planpb.GenericValue{
Val: &planpb.GenericValue_FloatVal{
FloatVal: value,
},
}
}
func NewString(value string) *planpb.GenericValue {
return &planpb.GenericValue{
Val: &planpb.GenericValue_StringVal{
StringVal: value,
},
}
}
func toValueExpr(n *planpb.GenericValue) *ExprWithType {
expr := &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{
Value: n,
},
},
}
switch n.GetVal().(type) {
case *planpb.GenericValue_BoolVal:
return &ExprWithType{
expr: expr,
dataType: schemapb.DataType_Bool,
}
case *planpb.GenericValue_Int64Val:
return &ExprWithType{
expr: expr,
dataType: schemapb.DataType_Int64,
}
case *planpb.GenericValue_FloatVal:
return &ExprWithType{
expr: expr,
dataType: schemapb.DataType_Double,
}
case *planpb.GenericValue_StringVal:
return &ExprWithType{
expr: expr,
dataType: schemapb.DataType_VarChar,
}
default:
return nil
}
}
func getSameType(a, b schemapb.DataType) (schemapb.DataType, error) {
if typeutil.IsFloatingType(a) && typeutil.IsArithmetic(b) {
return schemapb.DataType_Double, nil
}
if typeutil.IsIntegerType(a) && typeutil.IsIntegerType(b) {
return schemapb.DataType_Int64, nil
}
return schemapb.DataType_None, fmt.Errorf("incompatible data type, %s, %s", a.String(), b.String())
}
func calcDataType(left, right *ExprWithType, reverse bool) (schemapb.DataType, error) {
if reverse {
return getSameType(right.dataType, left.dataType)
}
return getSameType(left.dataType, right.dataType)
}
func reverseOrder(op planpb.OpType) (planpb.OpType, error) {
switch op {
case planpb.OpType_LessThan:
return planpb.OpType_GreaterThan, nil
case planpb.OpType_LessEqual:
return planpb.OpType_GreaterEqual, nil
case planpb.OpType_GreaterThan:
return planpb.OpType_LessThan, nil
case planpb.OpType_GreaterEqual:
return planpb.OpType_LessEqual, nil
case planpb.OpType_Equal:
return planpb.OpType_Equal, nil
case planpb.OpType_NotEqual:
return planpb.OpType_NotEqual, nil
default:
return planpb.OpType_Invalid, fmt.Errorf("cannot reverse order: %s", op)
}
}
func toColumnInfo(left *ExprWithType) *planpb.ColumnInfo {
return left.expr.GetColumnExpr().GetInfo()
}
func castValue(dataType schemapb.DataType, value *planpb.GenericValue) (*planpb.GenericValue, error) {
if typeutil.IsStringType(dataType) && IsString(value) {
return value, nil
}
if typeutil.IsBoolType(dataType) && IsBool(value) {
return value, nil
}
if typeutil.IsFloatingType(dataType) {
if IsFloating(value) {
return value, nil
}
if IsInteger(value) {
return NewFloat(float64(value.GetInt64Val())), nil
}
}
if typeutil.IsIntegerType(dataType) {
if IsInteger(value) {
return value, nil
}
}
return nil, fmt.Errorf("cannot cast value to %s, value: %s", dataType.String(), value)
}
func combineBinaryArithExpr(op planpb.OpType, arithOp planpb.ArithOpType, columnInfo *planpb.ColumnInfo, operand *planpb.GenericValue, value *planpb.GenericValue) *planpb.Expr {
castedValue, err := castValue(columnInfo.GetDataType(), operand)
if err != nil {
return nil
}
return &planpb.Expr{
Expr: &planpb.Expr_BinaryArithOpEvalRangeExpr{
BinaryArithOpEvalRangeExpr: &planpb.BinaryArithOpEvalRangeExpr{
ColumnInfo: columnInfo,
ArithOp: arithOp,
RightOperand: castedValue,
Op: op,
Value: value,
},
},
}
}
func handleBinaryArithExpr(op planpb.OpType, arithExpr *planpb.BinaryArithExpr, valueExpr *planpb.ValueExpr) (*planpb.Expr, error) {
switch op {
case planpb.OpType_Equal, planpb.OpType_NotEqual:
break
default:
// TODO: enable this after execution is ready.
return nil, fmt.Errorf("%s is not supported in execution backend", op)
}
leftExpr, leftValue := arithExpr.Left.GetColumnExpr(), arithExpr.Left.GetValueExpr()
rightExpr, rightValue := arithExpr.Right.GetColumnExpr(), arithExpr.Right.GetValueExpr()
if leftExpr != nil && rightExpr != nil {
// a + b == 3
return nil, fmt.Errorf("not supported to do arithmetic operations between multiple fields")
}
if leftValue != nil && rightValue != nil {
// 2 + 1 == 3
return nil, fmt.Errorf("unexpected, should be optimized already")
}
if leftExpr != nil && rightValue != nil {
// a + 2 == 3
// a - 2 == 3
// a * 2 == 3
// a / 2 == 3
// a % 2 == 3
return combineBinaryArithExpr(op, arithExpr.GetOp(), leftExpr.GetInfo(), rightValue.GetValue(), valueExpr.GetValue()), nil
} else if rightExpr != nil && leftValue != nil {
// 2 + a == 3
// 2 - a == 3
// 2 * a == 3
// 2 / a == 3
// 2 % a == 3
switch arithExpr.GetOp() {
case planpb.ArithOpType_Add, planpb.ArithOpType_Mul:
return combineBinaryArithExpr(op, arithExpr.GetOp(), rightExpr.GetInfo(), leftValue.GetValue(), valueExpr.GetValue()), nil
default:
return nil, fmt.Errorf("todo")
}
} else {
// (a + b) / 2 == 3
return nil, fmt.Errorf("complicated arithmetic operations are not supported")
}
}
func handleCompareRightValue(op planpb.OpType, left *ExprWithType, right *planpb.ValueExpr) (*planpb.Expr, error) {
castedValue, err := castValue(left.dataType, right.GetValue())
if err != nil {
return nil, err
}
if leftArithExpr := left.expr.GetBinaryArithExpr(); leftArithExpr != nil {
return handleBinaryArithExpr(op, leftArithExpr, &planpb.ValueExpr{Value: castedValue})
}
columnInfo := toColumnInfo(left)
if columnInfo == nil {
return nil, fmt.Errorf("not supported to combine multiple fields")
}
expr := &planpb.Expr{
Expr: &planpb.Expr_UnaryRangeExpr{
UnaryRangeExpr: &planpb.UnaryRangeExpr{
ColumnInfo: columnInfo,
Op: op,
Value: castedValue,
},
},
}
switch op {
case planpb.OpType_Invalid:
return nil, fmt.Errorf("unsupported op type: %s", op)
default:
return expr, nil
}
}
func handleCompare(op planpb.OpType, left *ExprWithType, right *ExprWithType) (*planpb.Expr, error) {
leftColumnInfo := toColumnInfo(left)
rightColumnInfo := toColumnInfo(right)
if leftColumnInfo == nil || rightColumnInfo == nil {
return nil, fmt.Errorf("only comparison between two fields is supported")
}
expr := &planpb.Expr{
Expr: &planpb.Expr_CompareExpr{
CompareExpr: &planpb.CompareExpr{
LeftColumnInfo: leftColumnInfo,
RightColumnInfo: rightColumnInfo,
Op: op,
},
},
}
switch op {
case planpb.OpType_Invalid:
return nil, fmt.Errorf("unsupported op type: %s", op)
default:
return expr, nil
}
}
func HandleCompare(op int, left, right *ExprWithType) (*planpb.Expr, error) {
cmpOp := cmpOpMap[op]
if valueExpr := left.expr.GetValueExpr(); valueExpr != nil {
op, err := reverseOrder(cmpOp)
if err != nil {
return nil, err
}
return handleCompareRightValue(op, right, valueExpr)
} else if valueExpr := right.expr.GetValueExpr(); valueExpr != nil {
return handleCompareRightValue(cmpOp, left, valueExpr)
} else {
return handleCompare(cmpOp, left, right)
}
}

View File

@ -14,6 +14,7 @@ enum OpType {
NotEqual = 6;
PrefixMatch = 7; // startsWith
PostfixMatch = 8; // endsWith
Match = 9; // like
};
enum ArithOpType {
@ -48,16 +49,20 @@ message ColumnInfo {
bool is_autoID = 4;
}
// For example: a startsWith "prefix", a >= "str", b < 2 and etc,
// where both a and b are field in schema.
message ColumnExpr {
ColumnInfo info = 1;
}
message ValueExpr {
GenericValue value = 1;
}
message UnaryRangeExpr {
ColumnInfo column_info = 1;
OpType op = 2;
GenericValue value = 3;
}
// For example: "str1" < a <= "str9", 1 <= b < 9 and etc,
// where both a and b are field in schema.
message BinaryRangeExpr {
ColumnInfo column_info = 1;
bool lower_inclusive = 2;
@ -66,22 +71,17 @@ message BinaryRangeExpr {
GenericValue upper_value = 5;
}
// For example: a startsWith b, a >= b, a < b, a == b and etc,
// where both a and b are field in schema.
message CompareExpr {
ColumnInfo left_column_info = 1;
ColumnInfo right_column_info = 2;
OpType op = 3;
}
// For example: a in ["term0", "term1"], b in [1, 2, 3, 4] and etc,
// where both a and b are field in schema.
message TermExpr {
ColumnInfo column_info = 1;
repeated GenericValue values = 2;
}
// !(expr).
message UnaryExpr {
enum UnaryOp {
Invalid = 0;
@ -91,7 +91,6 @@ message UnaryExpr {
Expr child = 2;
}
// (expr) op (expr), where op is of (LogicalAnd, LogicalOr).
message BinaryExpr {
enum BinaryOp {
Invalid = 0;
@ -109,6 +108,12 @@ message BinaryArithOp {
GenericValue right_operand = 3;
}
message BinaryArithExpr {
Expr left = 1;
Expr right = 2;
ArithOpType op = 3;
}
message BinaryArithOpEvalRangeExpr {
ColumnInfo column_info = 1;
ArithOpType arith_op = 2;
@ -126,6 +131,9 @@ message Expr {
UnaryRangeExpr unary_range_expr = 5;
BinaryRangeExpr binary_range_expr = 6;
BinaryArithOpEvalRangeExpr binary_arith_op_eval_range_expr = 7;
BinaryArithExpr binary_arith_expr = 8;
ValueExpr value_expr = 9;
ColumnExpr column_expr = 10;
};
}

View File

@ -33,6 +33,7 @@ const (
OpType_NotEqual OpType = 6
OpType_PrefixMatch OpType = 7
OpType_PostfixMatch OpType = 8
OpType_Match OpType = 9
)
var OpType_name = map[int32]string{
@ -45,6 +46,7 @@ var OpType_name = map[int32]string{
6: "NotEqual",
7: "PrefixMatch",
8: "PostfixMatch",
9: "Match",
}
var OpType_value = map[string]int32{
@ -57,6 +59,7 @@ var OpType_value = map[string]int32{
"NotEqual": 6,
"PrefixMatch": 7,
"PostfixMatch": 8,
"Match": 9,
}
func (x OpType) String() string {
@ -126,7 +129,7 @@ func (x UnaryExpr_UnaryOp) String() string {
}
func (UnaryExpr_UnaryOp) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{7, 0}
return fileDescriptor_2d655ab2f7683c23, []int{9, 0}
}
type BinaryExpr_BinaryOp int32
@ -154,7 +157,7 @@ func (x BinaryExpr_BinaryOp) String() string {
}
func (BinaryExpr_BinaryOp) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{8, 0}
return fileDescriptor_2d655ab2f7683c23, []int{10, 0}
}
type GenericValue struct {
@ -393,8 +396,84 @@ func (m *ColumnInfo) GetIsAutoID() bool {
return false
}
// For example: a startsWith "prefix", a >= "str", b < 2 and etc,
// where both a and b are field in schema.
type ColumnExpr struct {
Info *ColumnInfo `protobuf:"bytes,1,opt,name=info,proto3" json:"info,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ColumnExpr) Reset() { *m = ColumnExpr{} }
func (m *ColumnExpr) String() string { return proto.CompactTextString(m) }
func (*ColumnExpr) ProtoMessage() {}
func (*ColumnExpr) Descriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{3}
}
func (m *ColumnExpr) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ColumnExpr.Unmarshal(m, b)
}
func (m *ColumnExpr) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ColumnExpr.Marshal(b, m, deterministic)
}
func (m *ColumnExpr) XXX_Merge(src proto.Message) {
xxx_messageInfo_ColumnExpr.Merge(m, src)
}
func (m *ColumnExpr) XXX_Size() int {
return xxx_messageInfo_ColumnExpr.Size(m)
}
func (m *ColumnExpr) XXX_DiscardUnknown() {
xxx_messageInfo_ColumnExpr.DiscardUnknown(m)
}
var xxx_messageInfo_ColumnExpr proto.InternalMessageInfo
func (m *ColumnExpr) GetInfo() *ColumnInfo {
if m != nil {
return m.Info
}
return nil
}
type ValueExpr struct {
Value *GenericValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ValueExpr) Reset() { *m = ValueExpr{} }
func (m *ValueExpr) String() string { return proto.CompactTextString(m) }
func (*ValueExpr) ProtoMessage() {}
func (*ValueExpr) Descriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{4}
}
func (m *ValueExpr) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ValueExpr.Unmarshal(m, b)
}
func (m *ValueExpr) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ValueExpr.Marshal(b, m, deterministic)
}
func (m *ValueExpr) XXX_Merge(src proto.Message) {
xxx_messageInfo_ValueExpr.Merge(m, src)
}
func (m *ValueExpr) XXX_Size() int {
return xxx_messageInfo_ValueExpr.Size(m)
}
func (m *ValueExpr) XXX_DiscardUnknown() {
xxx_messageInfo_ValueExpr.DiscardUnknown(m)
}
var xxx_messageInfo_ValueExpr proto.InternalMessageInfo
func (m *ValueExpr) GetValue() *GenericValue {
if m != nil {
return m.Value
}
return nil
}
type UnaryRangeExpr struct {
ColumnInfo *ColumnInfo `protobuf:"bytes,1,opt,name=column_info,json=columnInfo,proto3" json:"column_info,omitempty"`
Op OpType `protobuf:"varint,2,opt,name=op,proto3,enum=milvus.proto.plan.OpType" json:"op,omitempty"`
@ -408,7 +487,7 @@ func (m *UnaryRangeExpr) Reset() { *m = UnaryRangeExpr{} }
func (m *UnaryRangeExpr) String() string { return proto.CompactTextString(m) }
func (*UnaryRangeExpr) ProtoMessage() {}
func (*UnaryRangeExpr) Descriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{3}
return fileDescriptor_2d655ab2f7683c23, []int{5}
}
func (m *UnaryRangeExpr) XXX_Unmarshal(b []byte) error {
@ -450,8 +529,6 @@ func (m *UnaryRangeExpr) GetValue() *GenericValue {
return nil
}
// For example: "str1" < a <= "str9", 1 <= b < 9 and etc,
// where both a and b are field in schema.
type BinaryRangeExpr struct {
ColumnInfo *ColumnInfo `protobuf:"bytes,1,opt,name=column_info,json=columnInfo,proto3" json:"column_info,omitempty"`
LowerInclusive bool `protobuf:"varint,2,opt,name=lower_inclusive,json=lowerInclusive,proto3" json:"lower_inclusive,omitempty"`
@ -467,7 +544,7 @@ func (m *BinaryRangeExpr) Reset() { *m = BinaryRangeExpr{} }
func (m *BinaryRangeExpr) String() string { return proto.CompactTextString(m) }
func (*BinaryRangeExpr) ProtoMessage() {}
func (*BinaryRangeExpr) Descriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{4}
return fileDescriptor_2d655ab2f7683c23, []int{6}
}
func (m *BinaryRangeExpr) XXX_Unmarshal(b []byte) error {
@ -523,8 +600,6 @@ func (m *BinaryRangeExpr) GetUpperValue() *GenericValue {
return nil
}
// For example: a startsWith b, a >= b, a < b, a == b and etc,
// where both a and b are field in schema.
type CompareExpr struct {
LeftColumnInfo *ColumnInfo `protobuf:"bytes,1,opt,name=left_column_info,json=leftColumnInfo,proto3" json:"left_column_info,omitempty"`
RightColumnInfo *ColumnInfo `protobuf:"bytes,2,opt,name=right_column_info,json=rightColumnInfo,proto3" json:"right_column_info,omitempty"`
@ -538,7 +613,7 @@ func (m *CompareExpr) Reset() { *m = CompareExpr{} }
func (m *CompareExpr) String() string { return proto.CompactTextString(m) }
func (*CompareExpr) ProtoMessage() {}
func (*CompareExpr) Descriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{5}
return fileDescriptor_2d655ab2f7683c23, []int{7}
}
func (m *CompareExpr) XXX_Unmarshal(b []byte) error {
@ -580,8 +655,6 @@ func (m *CompareExpr) GetOp() OpType {
return OpType_Invalid
}
// For example: a in ["term0", "term1"], b in [1, 2, 3, 4] and etc,
// where both a and b are field in schema.
type TermExpr struct {
ColumnInfo *ColumnInfo `protobuf:"bytes,1,opt,name=column_info,json=columnInfo,proto3" json:"column_info,omitempty"`
Values []*GenericValue `protobuf:"bytes,2,rep,name=values,proto3" json:"values,omitempty"`
@ -594,7 +667,7 @@ func (m *TermExpr) Reset() { *m = TermExpr{} }
func (m *TermExpr) String() string { return proto.CompactTextString(m) }
func (*TermExpr) ProtoMessage() {}
func (*TermExpr) Descriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{6}
return fileDescriptor_2d655ab2f7683c23, []int{8}
}
func (m *TermExpr) XXX_Unmarshal(b []byte) error {
@ -629,7 +702,6 @@ func (m *TermExpr) GetValues() []*GenericValue {
return nil
}
// !(expr).
type UnaryExpr struct {
Op UnaryExpr_UnaryOp `protobuf:"varint,1,opt,name=op,proto3,enum=milvus.proto.plan.UnaryExpr_UnaryOp" json:"op,omitempty"`
Child *Expr `protobuf:"bytes,2,opt,name=child,proto3" json:"child,omitempty"`
@ -642,7 +714,7 @@ func (m *UnaryExpr) Reset() { *m = UnaryExpr{} }
func (m *UnaryExpr) String() string { return proto.CompactTextString(m) }
func (*UnaryExpr) ProtoMessage() {}
func (*UnaryExpr) Descriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{7}
return fileDescriptor_2d655ab2f7683c23, []int{9}
}
func (m *UnaryExpr) XXX_Unmarshal(b []byte) error {
@ -677,7 +749,6 @@ func (m *UnaryExpr) GetChild() *Expr {
return nil
}
// (expr) op (expr), where op is of (LogicalAnd, LogicalOr).
type BinaryExpr struct {
Op BinaryExpr_BinaryOp `protobuf:"varint,1,opt,name=op,proto3,enum=milvus.proto.plan.BinaryExpr_BinaryOp" json:"op,omitempty"`
Left *Expr `protobuf:"bytes,2,opt,name=left,proto3" json:"left,omitempty"`
@ -691,7 +762,7 @@ func (m *BinaryExpr) Reset() { *m = BinaryExpr{} }
func (m *BinaryExpr) String() string { return proto.CompactTextString(m) }
func (*BinaryExpr) ProtoMessage() {}
func (*BinaryExpr) Descriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{8}
return fileDescriptor_2d655ab2f7683c23, []int{10}
}
func (m *BinaryExpr) XXX_Unmarshal(b []byte) error {
@ -746,7 +817,7 @@ func (m *BinaryArithOp) Reset() { *m = BinaryArithOp{} }
func (m *BinaryArithOp) String() string { return proto.CompactTextString(m) }
func (*BinaryArithOp) ProtoMessage() {}
func (*BinaryArithOp) Descriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{9}
return fileDescriptor_2d655ab2f7683c23, []int{11}
}
func (m *BinaryArithOp) XXX_Unmarshal(b []byte) error {
@ -788,6 +859,61 @@ func (m *BinaryArithOp) GetRightOperand() *GenericValue {
return nil
}
type BinaryArithExpr struct {
Left *Expr `protobuf:"bytes,1,opt,name=left,proto3" json:"left,omitempty"`
Right *Expr `protobuf:"bytes,2,opt,name=right,proto3" json:"right,omitempty"`
Op ArithOpType `protobuf:"varint,3,opt,name=op,proto3,enum=milvus.proto.plan.ArithOpType" json:"op,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *BinaryArithExpr) Reset() { *m = BinaryArithExpr{} }
func (m *BinaryArithExpr) String() string { return proto.CompactTextString(m) }
func (*BinaryArithExpr) ProtoMessage() {}
func (*BinaryArithExpr) Descriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{12}
}
func (m *BinaryArithExpr) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_BinaryArithExpr.Unmarshal(m, b)
}
func (m *BinaryArithExpr) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_BinaryArithExpr.Marshal(b, m, deterministic)
}
func (m *BinaryArithExpr) XXX_Merge(src proto.Message) {
xxx_messageInfo_BinaryArithExpr.Merge(m, src)
}
func (m *BinaryArithExpr) XXX_Size() int {
return xxx_messageInfo_BinaryArithExpr.Size(m)
}
func (m *BinaryArithExpr) XXX_DiscardUnknown() {
xxx_messageInfo_BinaryArithExpr.DiscardUnknown(m)
}
var xxx_messageInfo_BinaryArithExpr proto.InternalMessageInfo
func (m *BinaryArithExpr) GetLeft() *Expr {
if m != nil {
return m.Left
}
return nil
}
func (m *BinaryArithExpr) GetRight() *Expr {
if m != nil {
return m.Right
}
return nil
}
func (m *BinaryArithExpr) GetOp() ArithOpType {
if m != nil {
return m.Op
}
return ArithOpType_Unknown
}
type BinaryArithOpEvalRangeExpr struct {
ColumnInfo *ColumnInfo `protobuf:"bytes,1,opt,name=column_info,json=columnInfo,proto3" json:"column_info,omitempty"`
ArithOp ArithOpType `protobuf:"varint,2,opt,name=arith_op,json=arithOp,proto3,enum=milvus.proto.plan.ArithOpType" json:"arith_op,omitempty"`
@ -803,7 +929,7 @@ func (m *BinaryArithOpEvalRangeExpr) Reset() { *m = BinaryArithOpEvalRan
func (m *BinaryArithOpEvalRangeExpr) String() string { return proto.CompactTextString(m) }
func (*BinaryArithOpEvalRangeExpr) ProtoMessage() {}
func (*BinaryArithOpEvalRangeExpr) Descriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{10}
return fileDescriptor_2d655ab2f7683c23, []int{13}
}
func (m *BinaryArithOpEvalRangeExpr) XXX_Unmarshal(b []byte) error {
@ -868,6 +994,9 @@ type Expr struct {
// *Expr_UnaryRangeExpr
// *Expr_BinaryRangeExpr
// *Expr_BinaryArithOpEvalRangeExpr
// *Expr_BinaryArithExpr
// *Expr_ValueExpr
// *Expr_ColumnExpr
Expr isExpr_Expr `protobuf_oneof:"expr"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
@ -878,7 +1007,7 @@ func (m *Expr) Reset() { *m = Expr{} }
func (m *Expr) String() string { return proto.CompactTextString(m) }
func (*Expr) ProtoMessage() {}
func (*Expr) Descriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{11}
return fileDescriptor_2d655ab2f7683c23, []int{14}
}
func (m *Expr) XXX_Unmarshal(b []byte) error {
@ -931,6 +1060,18 @@ type Expr_BinaryArithOpEvalRangeExpr struct {
BinaryArithOpEvalRangeExpr *BinaryArithOpEvalRangeExpr `protobuf:"bytes,7,opt,name=binary_arith_op_eval_range_expr,json=binaryArithOpEvalRangeExpr,proto3,oneof"`
}
type Expr_BinaryArithExpr struct {
BinaryArithExpr *BinaryArithExpr `protobuf:"bytes,8,opt,name=binary_arith_expr,json=binaryArithExpr,proto3,oneof"`
}
type Expr_ValueExpr struct {
ValueExpr *ValueExpr `protobuf:"bytes,9,opt,name=value_expr,json=valueExpr,proto3,oneof"`
}
type Expr_ColumnExpr struct {
ColumnExpr *ColumnExpr `protobuf:"bytes,10,opt,name=column_expr,json=columnExpr,proto3,oneof"`
}
func (*Expr_TermExpr) isExpr_Expr() {}
func (*Expr_UnaryExpr) isExpr_Expr() {}
@ -945,6 +1086,12 @@ func (*Expr_BinaryRangeExpr) isExpr_Expr() {}
func (*Expr_BinaryArithOpEvalRangeExpr) isExpr_Expr() {}
func (*Expr_BinaryArithExpr) isExpr_Expr() {}
func (*Expr_ValueExpr) isExpr_Expr() {}
func (*Expr_ColumnExpr) isExpr_Expr() {}
func (m *Expr) GetExpr() isExpr_Expr {
if m != nil {
return m.Expr
@ -1001,6 +1148,27 @@ func (m *Expr) GetBinaryArithOpEvalRangeExpr() *BinaryArithOpEvalRangeExpr {
return nil
}
func (m *Expr) GetBinaryArithExpr() *BinaryArithExpr {
if x, ok := m.GetExpr().(*Expr_BinaryArithExpr); ok {
return x.BinaryArithExpr
}
return nil
}
func (m *Expr) GetValueExpr() *ValueExpr {
if x, ok := m.GetExpr().(*Expr_ValueExpr); ok {
return x.ValueExpr
}
return nil
}
func (m *Expr) GetColumnExpr() *ColumnExpr {
if x, ok := m.GetExpr().(*Expr_ColumnExpr); ok {
return x.ColumnExpr
}
return nil
}
// XXX_OneofWrappers is for the internal use of the proto package.
func (*Expr) XXX_OneofWrappers() []interface{} {
return []interface{}{
@ -1011,6 +1179,9 @@ func (*Expr) XXX_OneofWrappers() []interface{} {
(*Expr_UnaryRangeExpr)(nil),
(*Expr_BinaryRangeExpr)(nil),
(*Expr_BinaryArithOpEvalRangeExpr)(nil),
(*Expr_BinaryArithExpr)(nil),
(*Expr_ValueExpr)(nil),
(*Expr_ColumnExpr)(nil),
}
}
@ -1029,7 +1200,7 @@ func (m *VectorANNS) Reset() { *m = VectorANNS{} }
func (m *VectorANNS) String() string { return proto.CompactTextString(m) }
func (*VectorANNS) ProtoMessage() {}
func (*VectorANNS) Descriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{12}
return fileDescriptor_2d655ab2f7683c23, []int{15}
}
func (m *VectorANNS) XXX_Unmarshal(b []byte) error {
@ -1100,7 +1271,7 @@ func (m *PlanNode) Reset() { *m = PlanNode{} }
func (m *PlanNode) String() string { return proto.CompactTextString(m) }
func (*PlanNode) ProtoMessage() {}
func (*PlanNode) Descriptor() ([]byte, []int) {
return fileDescriptor_2d655ab2f7683c23, []int{13}
return fileDescriptor_2d655ab2f7683c23, []int{16}
}
func (m *PlanNode) XXX_Unmarshal(b []byte) error {
@ -1181,6 +1352,8 @@ func init() {
proto.RegisterType((*GenericValue)(nil), "milvus.proto.plan.GenericValue")
proto.RegisterType((*QueryInfo)(nil), "milvus.proto.plan.QueryInfo")
proto.RegisterType((*ColumnInfo)(nil), "milvus.proto.plan.ColumnInfo")
proto.RegisterType((*ColumnExpr)(nil), "milvus.proto.plan.ColumnExpr")
proto.RegisterType((*ValueExpr)(nil), "milvus.proto.plan.ValueExpr")
proto.RegisterType((*UnaryRangeExpr)(nil), "milvus.proto.plan.UnaryRangeExpr")
proto.RegisterType((*BinaryRangeExpr)(nil), "milvus.proto.plan.BinaryRangeExpr")
proto.RegisterType((*CompareExpr)(nil), "milvus.proto.plan.CompareExpr")
@ -1188,6 +1361,7 @@ func init() {
proto.RegisterType((*UnaryExpr)(nil), "milvus.proto.plan.UnaryExpr")
proto.RegisterType((*BinaryExpr)(nil), "milvus.proto.plan.BinaryExpr")
proto.RegisterType((*BinaryArithOp)(nil), "milvus.proto.plan.BinaryArithOp")
proto.RegisterType((*BinaryArithExpr)(nil), "milvus.proto.plan.BinaryArithExpr")
proto.RegisterType((*BinaryArithOpEvalRangeExpr)(nil), "milvus.proto.plan.BinaryArithOpEvalRangeExpr")
proto.RegisterType((*Expr)(nil), "milvus.proto.plan.Expr")
proto.RegisterType((*VectorANNS)(nil), "milvus.proto.plan.VectorANNS")
@ -1197,86 +1371,92 @@ func init() {
func init() { proto.RegisterFile("plan.proto", fileDescriptor_2d655ab2f7683c23) }
var fileDescriptor_2d655ab2f7683c23 = []byte{
// 1284 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x56, 0xcd, 0x72, 0xdb, 0x36,
0x10, 0x16, 0x45, 0xc9, 0x22, 0x97, 0xb2, 0xcc, 0xf0, 0xd2, 0xfc, 0x34, 0xb1, 0xcb, 0x66, 0x1a,
0x37, 0x9d, 0xd8, 0xd3, 0x24, 0x4d, 0x26, 0xe9, 0xb4, 0x13, 0xff, 0xa4, 0x96, 0xa7, 0x89, 0xed,
0x32, 0x8e, 0x0f, 0xbd, 0x70, 0x20, 0x12, 0x96, 0x30, 0x81, 0x00, 0x06, 0x04, 0x95, 0xe8, 0xdc,
0x5b, 0x6f, 0x79, 0x89, 0xf6, 0xde, 0x5b, 0x4f, 0x7d, 0x81, 0x1e, 0x7a, 0xec, 0xbd, 0x2f, 0xd2,
0x01, 0x40, 0xeb, 0x27, 0x23, 0x25, 0xca, 0xd4, 0x33, 0xbd, 0x01, 0x8b, 0xdd, 0x0f, 0xfb, 0x2d,
0x76, 0x17, 0x0b, 0x90, 0x51, 0xc4, 0x36, 0x32, 0xc1, 0x25, 0x0f, 0x2e, 0xf4, 0x09, 0x1d, 0x14,
0xb9, 0xd9, 0x6d, 0xa8, 0x83, 0xcb, 0xcd, 0x3c, 0xe9, 0xe1, 0x3e, 0x32, 0xa2, 0xf0, 0x8d, 0x05,
0xcd, 0x3d, 0xcc, 0xb0, 0x20, 0xc9, 0x09, 0xa2, 0x05, 0x0e, 0xae, 0x80, 0xd3, 0xe1, 0x9c, 0xc6,
0x03, 0x44, 0x2f, 0x5a, 0x6b, 0xd6, 0xba, 0xd3, 0xae, 0x44, 0x0d, 0x25, 0x39, 0x41, 0x34, 0xb8,
0x0a, 0x2e, 0x61, 0xf2, 0xde, 0x5d, 0x7d, 0x5a, 0x5d, 0xb3, 0xd6, 0xed, 0x76, 0x25, 0x72, 0xb4,
0xa8, 0x3c, 0x3e, 0xa5, 0x1c, 0x49, 0x7d, 0x6c, 0xaf, 0x59, 0xeb, 0x96, 0x3a, 0xd6, 0x22, 0x75,
0xbc, 0x0a, 0x90, 0x4b, 0x41, 0x58, 0x57, 0x9f, 0xd7, 0xd6, 0xac, 0x75, 0xb7, 0x5d, 0x89, 0x5c,
0x23, 0x3b, 0x41, 0x74, 0xbb, 0x0e, 0xf6, 0x00, 0xd1, 0xf0, 0x67, 0x0b, 0xdc, 0x1f, 0x0a, 0x2c,
0x86, 0xfb, 0xec, 0x94, 0x07, 0x01, 0xd4, 0x24, 0xcf, 0x5e, 0x68, 0x67, 0xec, 0x48, 0xaf, 0x83,
0x55, 0xf0, 0xfa, 0x58, 0x0a, 0x92, 0xc4, 0x72, 0x98, 0x61, 0x7d, 0x95, 0x1b, 0x81, 0x11, 0x1d,
0x0f, 0x33, 0x1c, 0x7c, 0x0a, 0xcb, 0x39, 0x46, 0x22, 0xe9, 0xc5, 0x19, 0x12, 0xa8, 0x9f, 0x9b,
0xdb, 0xa2, 0xa6, 0x11, 0x1e, 0x69, 0x99, 0x52, 0x12, 0xbc, 0x60, 0x69, 0x9c, 0xe2, 0x84, 0xf4,
0x11, 0xbd, 0x58, 0xd7, 0x57, 0x34, 0xb5, 0x70, 0xd7, 0xc8, 0xc2, 0x5f, 0x2c, 0x80, 0x1d, 0x4e,
0x8b, 0x3e, 0xd3, 0xde, 0x5c, 0x02, 0xe7, 0x94, 0x60, 0x9a, 0xc6, 0x24, 0x2d, 0x3d, 0x6a, 0xe8,
0xfd, 0x7e, 0x1a, 0x3c, 0x04, 0x37, 0x45, 0x12, 0x19, 0x97, 0x54, 0x70, 0x5a, 0xb7, 0xaf, 0x6e,
0x4c, 0xc5, 0xbf, 0x8c, 0xfc, 0x2e, 0x92, 0x48, 0x79, 0x19, 0x39, 0x69, 0xb9, 0x0a, 0xae, 0x43,
0x8b, 0xe4, 0x71, 0x26, 0x48, 0x1f, 0x89, 0x61, 0xfc, 0x02, 0x0f, 0x35, 0x27, 0x27, 0x6a, 0x92,
0xfc, 0xc8, 0x08, 0xbf, 0xc7, 0xc3, 0xe0, 0x0a, 0xb8, 0x24, 0x8f, 0x51, 0x21, 0xf9, 0xfe, 0xae,
0x66, 0xe4, 0x44, 0x0e, 0xc9, 0xb7, 0xf4, 0x3e, 0xfc, 0xcd, 0x82, 0xd6, 0x73, 0x86, 0xc4, 0x30,
0x42, 0xac, 0x8b, 0x1f, 0xbf, 0xce, 0x44, 0xf0, 0x2d, 0x78, 0x89, 0x76, 0x3d, 0x26, 0xec, 0x94,
0x6b, 0x7f, 0xbd, 0xb7, 0x7d, 0xd2, 0xc9, 0x32, 0x26, 0x18, 0x41, 0x32, 0x26, 0xfb, 0x39, 0x54,
0x79, 0x56, 0x52, 0xb9, 0x34, 0xc3, 0xec, 0x30, 0xd3, 0x34, 0xaa, 0x3c, 0x0b, 0xbe, 0x82, 0xfa,
0x40, 0xe5, 0x8f, 0xf6, 0xdb, 0xbb, 0xbd, 0x3a, 0x43, 0x7b, 0x32, 0xcd, 0x22, 0xa3, 0x1d, 0xfe,
0x5a, 0x85, 0x95, 0x6d, 0x72, 0xbe, 0x5e, 0xdf, 0x80, 0x15, 0xca, 0x5f, 0x61, 0x11, 0x13, 0x96,
0xd0, 0x22, 0x27, 0x03, 0xf3, 0x1a, 0x4e, 0xd4, 0xd2, 0xe2, 0xfd, 0x33, 0xa9, 0x52, 0x2c, 0xb2,
0x6c, 0x4a, 0xd1, 0x44, 0xbd, 0xa5, 0xc5, 0x63, 0xc5, 0x47, 0xe0, 0x19, 0x44, 0x43, 0xb1, 0xb6,
0x18, 0x45, 0xd0, 0x36, 0xa6, 0xaa, 0x1e, 0x81, 0x67, 0xae, 0x32, 0x08, 0xf5, 0x05, 0x11, 0xb4,
0x8d, 0x5e, 0x87, 0x7f, 0x5a, 0xe0, 0xed, 0xf0, 0x7e, 0x86, 0x84, 0x89, 0xd2, 0x1e, 0xf8, 0x14,
0x9f, 0xca, 0xf8, 0x83, 0x43, 0xd5, 0x52, 0x66, 0x13, 0x19, 0xbd, 0x0f, 0x17, 0x04, 0xe9, 0xf6,
0xa6, 0x91, 0xaa, 0x8b, 0x20, 0xad, 0x68, 0xbb, 0x9d, 0xb7, 0xf3, 0xc5, 0x5e, 0x20, 0x5f, 0xc2,
0x9f, 0x2c, 0x70, 0x8e, 0xb1, 0xe8, 0x9f, 0xcb, 0x8b, 0xdf, 0x87, 0x25, 0x1d, 0xd7, 0xfc, 0x62,
0x75, 0xcd, 0x5e, 0x24, 0xb0, 0xa5, 0xba, 0xea, 0x7e, 0xae, 0xae, 0x19, 0xed, 0xc6, 0x5d, 0xed,
0xbe, 0xa5, 0xdd, 0xbf, 0x3e, 0x03, 0x62, 0xa4, 0x69, 0x56, 0x87, 0x99, 0xce, 0xfc, 0x5b, 0x50,
0x4f, 0x7a, 0x84, 0xa6, 0x65, 0xcc, 0x3e, 0x9a, 0x61, 0xa8, 0x6c, 0x22, 0xa3, 0x15, 0xae, 0x42,
0xa3, 0xb4, 0x0e, 0x3c, 0x68, 0xec, 0xb3, 0x01, 0xa2, 0x24, 0xf5, 0x2b, 0x41, 0x03, 0xec, 0x03,
0x2e, 0x7d, 0x2b, 0xfc, 0xdb, 0x02, 0x30, 0x25, 0xa1, 0x9d, 0xba, 0x37, 0xe1, 0xd4, 0x67, 0x33,
0xb0, 0xc7, 0xaa, 0xe5, 0xb2, 0x74, 0xeb, 0x0b, 0xa8, 0xa9, 0x87, 0x7e, 0x9f, 0x57, 0x5a, 0x49,
0x71, 0xd0, 0x6f, 0x59, 0x56, 0xef, 0x7c, 0x0e, 0x5a, 0x2b, 0xbc, 0x07, 0xce, 0xd9, 0x5d, 0xd3,
0x24, 0x5a, 0x00, 0x4f, 0x78, 0x97, 0x24, 0x88, 0x6e, 0xb1, 0xd4, 0xb7, 0x82, 0x65, 0x70, 0xcb,
0xfd, 0xa1, 0xf0, 0xab, 0xe1, 0x5f, 0x16, 0x2c, 0x1b, 0xc3, 0x2d, 0x41, 0x64, 0xef, 0x30, 0xfb,
0xcf, 0x2f, 0xff, 0x00, 0x1c, 0xa4, 0xa0, 0xe2, 0x51, 0x9f, 0xba, 0x36, 0xc3, 0xb8, 0xbc, 0x4d,
0x27, 0x5f, 0x03, 0x95, 0x57, 0xef, 0xc2, 0xb2, 0xc9, 0x7b, 0x9e, 0x61, 0x81, 0x58, 0xba, 0x68,
0xe7, 0x6a, 0x6a, 0xab, 0x43, 0x63, 0x14, 0xfe, 0x51, 0x85, 0xcb, 0x53, 0x94, 0x1e, 0x0f, 0x10,
0x3d, 0xbf, 0x5e, 0xf6, 0x7f, 0xf3, 0x2b, 0x4b, 0xba, 0xf6, 0x41, 0x5f, 0x40, 0xfd, 0xc3, 0xbe,
0x80, 0x1a, 0xd4, 0x74, 0xac, 0x1e, 0x82, 0x2b, 0xb1, 0xe8, 0xc7, 0xf8, 0x75, 0x26, 0xca, 0x48,
0x5d, 0x99, 0x81, 0x71, 0xd6, 0x35, 0xd4, 0x68, 0x21, 0xcf, 0x3a, 0xc8, 0x37, 0x00, 0x85, 0x7a,
0x04, 0x63, 0x6c, 0x72, 0xfe, 0xe3, 0x77, 0x95, 0xb0, 0x1a, 0x3c, 0x8a, 0x51, 0x91, 0x3d, 0x02,
0xaf, 0x43, 0xc6, 0xf6, 0xf6, 0xdc, 0x67, 0x1a, 0x57, 0x5b, 0xbb, 0x12, 0x41, 0x67, 0x5c, 0xa6,
0x3b, 0xd0, 0x4c, 0x4c, 0x77, 0x36, 0x10, 0xe6, 0x8f, 0xb8, 0x36, 0xf3, 0xa5, 0x47, 0x4d, 0xbc,
0x5d, 0x89, 0xbc, 0x64, 0xa2, 0xa7, 0x3f, 0x05, 0xdf, 0xb0, 0x10, 0x2a, 0x81, 0x0c, 0x90, 0x09,
0xe6, 0x27, 0xf3, 0xb8, 0x8c, 0x52, 0xad, 0x5d, 0x89, 0x5a, 0xc5, 0xf4, 0x47, 0x7a, 0x04, 0x17,
0x4a, 0x56, 0x13, 0x78, 0x4b, 0x1a, 0x2f, 0x9c, 0xcb, 0x6d, 0x12, 0x70, 0xa5, 0xf3, 0xd6, 0xd7,
0x2c, 0x61, 0xb5, 0x44, 0x3c, 0xcb, 0xca, 0x18, 0x0f, 0x10, 0x9d, 0xc4, 0x6f, 0x68, 0xfc, 0x5b,
0x73, 0xf1, 0x67, 0x95, 0x49, 0xbb, 0x12, 0x5d, 0xee, 0xcc, 0x3d, 0xdd, 0x5e, 0x82, 0x9a, 0x82,
0x0e, 0xff, 0xb1, 0x00, 0x4e, 0x70, 0x22, 0xb9, 0xd8, 0x3a, 0x38, 0x78, 0x56, 0x4e, 0x43, 0xc6,
0xce, 0x8c, 0xaa, 0x6a, 0x1a, 0x32, 0xb7, 0x4c, 0xcd, 0x69, 0xd5, 0xe9, 0x39, 0xed, 0x3e, 0x40,
0x26, 0x70, 0x4a, 0x12, 0x24, 0x71, 0xfe, 0xbe, 0x8e, 0x37, 0xa1, 0x1a, 0x7c, 0x0d, 0xf0, 0x52,
0x8d, 0xa5, 0xa6, 0x96, 0x6b, 0x73, 0x93, 0x6c, 0x34, 0xbb, 0x46, 0xee, 0xcb, 0xd1, 0x18, 0x7b,
0x03, 0x56, 0x32, 0x8a, 0x12, 0xdc, 0xe3, 0x34, 0xc5, 0x22, 0x96, 0xa8, 0xab, 0x9f, 0xd6, 0x8d,
0x5a, 0x13, 0xe2, 0x63, 0xd4, 0x0d, 0x7f, 0xb7, 0xc0, 0x39, 0xa2, 0x88, 0x1d, 0xf0, 0x54, 0xcf,
0x0d, 0x03, 0xcd, 0x38, 0x46, 0x8c, 0xe5, 0xef, 0xe8, 0x1f, 0xe3, 0xb8, 0xa8, 0xc4, 0x34, 0x36,
0x5b, 0x8c, 0xe5, 0xc1, 0x83, 0x29, 0xb6, 0xef, 0xfe, 0x0d, 0x94, 0xe9, 0x04, 0xdf, 0x75, 0xf0,
0x79, 0x21, 0xb3, 0x42, 0xc6, 0x67, 0xa1, 0x54, 0xe1, 0xb2, 0xd7, 0xed, 0xa8, 0x65, 0xe4, 0xdf,
0x99, 0x88, 0xe6, 0xea, 0x85, 0x18, 0x4f, 0xf1, 0xcd, 0x37, 0x16, 0x2c, 0x99, 0x8e, 0x30, 0xfd,
0x2f, 0xac, 0x80, 0xb7, 0x27, 0x30, 0x92, 0x58, 0x1c, 0xf7, 0x10, 0xf3, 0xad, 0xc0, 0x87, 0x66,
0x29, 0x78, 0xfc, 0xb2, 0x40, 0xd4, 0xaf, 0x06, 0x4d, 0x70, 0x9e, 0xe0, 0x3c, 0xd7, 0xe7, 0xb6,
0xfe, 0x38, 0x70, 0x9e, 0x9b, 0xc3, 0x5a, 0xe0, 0x42, 0xdd, 0x2c, 0xeb, 0x4a, 0xef, 0x80, 0x4b,
0xb3, 0x5b, 0x52, 0xc0, 0x47, 0x02, 0x9f, 0x92, 0xd7, 0x4f, 0x91, 0x4c, 0x7a, 0x7e, 0x43, 0x01,
0x1f, 0xf1, 0x5c, 0x8e, 0x24, 0xce, 0xcd, 0x3d, 0xf0, 0x26, 0xfa, 0xa3, 0xf2, 0xeb, 0x39, 0x7b,
0xc1, 0xf8, 0x2b, 0x66, 0x3e, 0xdd, 0xad, 0x54, 0x7d, 0x54, 0x0d, 0xb0, 0x9f, 0x15, 0x1d, 0xbf,
0xaa, 0x16, 0x4f, 0x0b, 0xea, 0xdb, 0x6a, 0xb1, 0x4b, 0x06, 0x7e, 0x4d, 0x4b, 0x78, 0xea, 0xd7,
0xb7, 0xef, 0xfc, 0xf8, 0x65, 0x97, 0xc8, 0x5e, 0xd1, 0xd9, 0x48, 0x78, 0x7f, 0xd3, 0x44, 0xf0,
0x16, 0xe1, 0xe5, 0x6a, 0x93, 0x30, 0x89, 0x05, 0x43, 0x74, 0x53, 0x07, 0x75, 0x53, 0x05, 0x35,
0xeb, 0x74, 0x96, 0xf4, 0xee, 0xce, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x7b, 0x2c, 0x0c, 0x69,
0x95, 0x0d, 0x00, 0x00,
// 1387 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0xcd, 0x73, 0xdb, 0x44,
0x14, 0xb7, 0x2c, 0x3b, 0x96, 0x9e, 0x1d, 0x47, 0xd5, 0x85, 0x7e, 0xd0, 0x26, 0x88, 0x0e, 0x0d,
0x65, 0x9a, 0x4c, 0x69, 0x69, 0xa7, 0x65, 0x0a, 0xf9, 0x2a, 0x49, 0x86, 0x36, 0x09, 0x6a, 0x9a,
0x03, 0x17, 0xcd, 0x5a, 0xda, 0xd8, 0x3b, 0x95, 0xb5, 0xea, 0x6a, 0xe5, 0xd6, 0x67, 0x6e, 0xdc,
0xb8, 0xc3, 0x15, 0xee, 0xdc, 0x38, 0xf1, 0x0f, 0x70, 0xe0, 0xc8, 0x9d, 0xff, 0x82, 0x13, 0xb3,
0x6f, 0xe5, 0xaf, 0x8e, 0xdd, 0x38, 0x43, 0x67, 0xb8, 0xed, 0xbe, 0x7d, 0xef, 0xb7, 0xef, 0xfd,
0xf6, 0xed, 0xdb, 0xb7, 0x00, 0x69, 0x4c, 0x92, 0xb5, 0x54, 0x70, 0xc9, 0xdd, 0x0b, 0x5d, 0x16,
0xf7, 0xf2, 0x4c, 0xcf, 0xd6, 0xd4, 0xc2, 0xe5, 0x46, 0x16, 0x76, 0x68, 0x97, 0x68, 0x91, 0xf7,
0x83, 0x01, 0x8d, 0x5d, 0x9a, 0x50, 0xc1, 0xc2, 0x13, 0x12, 0xe7, 0xd4, 0xbd, 0x02, 0x56, 0x8b,
0xf3, 0x38, 0xe8, 0x91, 0xf8, 0xa2, 0xb1, 0x62, 0xac, 0x5a, 0x7b, 0x25, 0xbf, 0xa6, 0x24, 0x27,
0x24, 0x76, 0xaf, 0x82, 0xcd, 0x12, 0x79, 0xef, 0x2e, 0xae, 0x96, 0x57, 0x8c, 0x55, 0x73, 0xaf,
0xe4, 0x5b, 0x28, 0x2a, 0x96, 0x4f, 0x63, 0x4e, 0x24, 0x2e, 0x9b, 0x2b, 0xc6, 0xaa, 0xa1, 0x96,
0x51, 0xa4, 0x96, 0x97, 0x01, 0x32, 0x29, 0x58, 0xd2, 0xc6, 0xf5, 0xca, 0x8a, 0xb1, 0x6a, 0xef,
0x95, 0x7c, 0x5b, 0xcb, 0x4e, 0x48, 0xbc, 0x55, 0x05, 0xb3, 0x47, 0x62, 0xef, 0x7b, 0x03, 0xec,
0x6f, 0x72, 0x2a, 0xfa, 0xfb, 0xc9, 0x29, 0x77, 0x5d, 0xa8, 0x48, 0x9e, 0xbe, 0x40, 0x67, 0x4c,
0x1f, 0xc7, 0xee, 0x32, 0xd4, 0xbb, 0x54, 0x0a, 0x16, 0x06, 0xb2, 0x9f, 0x52, 0xdc, 0xca, 0xf6,
0x41, 0x8b, 0x8e, 0xfb, 0x29, 0x75, 0x3f, 0x84, 0xc5, 0x8c, 0x12, 0x11, 0x76, 0x82, 0x94, 0x08,
0xd2, 0xcd, 0xf4, 0x6e, 0x7e, 0x43, 0x0b, 0x8f, 0x50, 0xa6, 0x94, 0x04, 0xcf, 0x93, 0x28, 0x88,
0x68, 0xc8, 0xba, 0x24, 0xbe, 0x58, 0xc5, 0x2d, 0x1a, 0x28, 0xdc, 0xd1, 0x32, 0xef, 0x67, 0x03,
0x60, 0x9b, 0xc7, 0x79, 0x37, 0x41, 0x6f, 0x2e, 0x81, 0x75, 0xca, 0x68, 0x1c, 0x05, 0x2c, 0x2a,
0x3c, 0xaa, 0xe1, 0x7c, 0x3f, 0x72, 0x1f, 0x82, 0x1d, 0x11, 0x49, 0xb4, 0x4b, 0x8a, 0x9c, 0xe6,
0xa7, 0x57, 0xd7, 0x26, 0xf8, 0x2f, 0x98, 0xdf, 0x21, 0x92, 0x28, 0x2f, 0x7d, 0x2b, 0x2a, 0x46,
0xee, 0x75, 0x68, 0xb2, 0x2c, 0x48, 0x05, 0xeb, 0x12, 0xd1, 0x0f, 0x5e, 0xd0, 0x3e, 0xc6, 0x64,
0xf9, 0x0d, 0x96, 0x1d, 0x69, 0xe1, 0xd7, 0xb4, 0xef, 0x5e, 0x01, 0x9b, 0x65, 0x01, 0xc9, 0x25,
0xdf, 0xdf, 0xc1, 0x88, 0x2c, 0xdf, 0x62, 0xd9, 0x26, 0xce, 0xbd, 0x2f, 0x07, 0x7e, 0x3e, 0x7e,
0x9d, 0x0a, 0xf7, 0x36, 0x54, 0x58, 0x72, 0xca, 0xd1, 0xc7, 0xfa, 0x9b, 0x7e, 0x60, 0x82, 0x8c,
0x82, 0xf2, 0x51, 0xd5, 0xdb, 0x02, 0x1b, 0x53, 0x00, 0xed, 0x3f, 0x83, 0x6a, 0x4f, 0x4d, 0x0a,
0x80, 0xe5, 0x29, 0x00, 0xe3, 0x69, 0xe3, 0x6b, 0x6d, 0xef, 0x57, 0x03, 0x9a, 0xcf, 0x13, 0x22,
0xfa, 0x3e, 0x49, 0xda, 0x1a, 0xe9, 0x0b, 0xa8, 0x87, 0xb8, 0x55, 0x30, 0xbf, 0x43, 0x10, 0x8e,
0x18, 0xff, 0x18, 0xca, 0x3c, 0x2d, 0xf8, 0xbc, 0x34, 0xc5, 0xec, 0x30, 0x45, 0x2e, 0xcb, 0x3c,
0x1d, 0x39, 0x6d, 0x9e, 0xcb, 0xe9, 0x5f, 0xca, 0xb0, 0xb4, 0xc5, 0xde, 0xad, 0xd7, 0x37, 0x60,
0x29, 0xe6, 0xaf, 0xa8, 0x08, 0x58, 0x12, 0xc6, 0x79, 0xc6, 0x7a, 0x3a, 0x25, 0x2c, 0xbf, 0x89,
0xe2, 0xfd, 0x81, 0x54, 0x29, 0xe6, 0x69, 0x3a, 0xa1, 0xa8, 0x8f, 0xbe, 0x89, 0xe2, 0x91, 0xe2,
0x06, 0xd4, 0x35, 0xa2, 0x0e, 0xb1, 0x32, 0x5f, 0x88, 0x80, 0x36, 0xfa, 0x6a, 0x6f, 0x40, 0x5d,
0x6f, 0xa5, 0x11, 0xaa, 0x73, 0x22, 0xa0, 0x0d, 0x8e, 0xbd, 0x3f, 0x0c, 0xa8, 0x6f, 0xf3, 0x6e,
0x4a, 0x84, 0x66, 0x69, 0x17, 0x9c, 0x98, 0x9e, 0xca, 0xe0, 0xdc, 0x54, 0x35, 0x95, 0xd9, 0xd8,
0xb5, 0xda, 0x87, 0x0b, 0x82, 0xb5, 0x3b, 0x93, 0x48, 0xe5, 0x79, 0x90, 0x96, 0xd0, 0x6e, 0xfb,
0xcd, 0x7c, 0x31, 0xe7, 0xc8, 0x17, 0xef, 0x3b, 0x03, 0xac, 0x63, 0x2a, 0xba, 0xef, 0xe4, 0xc4,
0xef, 0xc3, 0x02, 0xf2, 0x9a, 0x5d, 0x2c, 0xaf, 0x98, 0xf3, 0x10, 0x5b, 0xa8, 0xab, 0x12, 0x6c,
0xe3, 0x9d, 0x41, 0x37, 0xee, 0xa2, 0xfb, 0x06, 0xba, 0x7f, 0x7d, 0x0a, 0xc4, 0x50, 0x53, 0x8f,
0x0e, 0x53, 0xcc, 0xfc, 0x5b, 0x50, 0x0d, 0x3b, 0x2c, 0x8e, 0x0a, 0xce, 0xde, 0x9b, 0x62, 0xa8,
0x6c, 0x7c, 0xad, 0xe5, 0x2d, 0x43, 0xad, 0xb0, 0x76, 0xeb, 0x50, 0xdb, 0x4f, 0x7a, 0x24, 0x66,
0x91, 0x53, 0x72, 0x6b, 0x60, 0x1e, 0x70, 0xe9, 0x18, 0xde, 0x5f, 0x06, 0x80, 0xbe, 0x12, 0xe8,
0xd4, 0xbd, 0x31, 0xa7, 0x3e, 0x9a, 0x82, 0x3d, 0x52, 0x2d, 0x86, 0x85, 0x5b, 0x9f, 0x40, 0x45,
0x1d, 0xf4, 0x59, 0x5e, 0xa1, 0x92, 0x8a, 0x01, 0xcf, 0xb2, 0xb8, 0xbd, 0xb3, 0x63, 0x40, 0x2d,
0xef, 0x1e, 0x58, 0x83, 0xbd, 0x26, 0x83, 0x68, 0x02, 0x3c, 0xe1, 0x6d, 0x16, 0x92, 0x78, 0x33,
0x89, 0x1c, 0xc3, 0x5d, 0x04, 0xbb, 0x98, 0x1f, 0x0a, 0xa7, 0xec, 0xfd, 0x69, 0xc0, 0xa2, 0x36,
0xdc, 0x14, 0x4c, 0x76, 0x0e, 0xd3, 0xff, 0x7c, 0xf2, 0x0f, 0xc0, 0x22, 0x0a, 0x2a, 0x18, 0xd6,
0xa9, 0x6b, 0x53, 0x8c, 0x8b, 0xdd, 0x30, 0xf9, 0x6a, 0xa4, 0xd8, 0x7a, 0x07, 0x16, 0x75, 0xde,
0xf3, 0x94, 0x0a, 0x92, 0x44, 0xf3, 0x56, 0xae, 0x06, 0x5a, 0x1d, 0x6a, 0x23, 0xef, 0x27, 0x63,
0x50, 0xc0, 0x70, 0x13, 0x3c, 0xb2, 0x01, 0xf5, 0xc6, 0xb9, 0xa8, 0x2f, 0xcf, 0x43, 0xbd, 0xbb,
0x36, 0x76, 0xc5, 0xce, 0x0a, 0x55, 0xdd, 0xb3, 0xdf, 0xcb, 0x70, 0x79, 0x82, 0xf2, 0xc7, 0x3d,
0x12, 0xbf, 0xbb, 0x5a, 0xfb, 0x7f, 0xf3, 0x5f, 0x94, 0x9c, 0xca, 0xb9, 0x9e, 0xa8, 0xea, 0xb9,
0x9e, 0xa8, 0x7f, 0xaa, 0x50, 0x41, 0xae, 0x1e, 0x82, 0x2d, 0xa9, 0xe8, 0x06, 0xf4, 0x75, 0x2a,
0x0a, 0xa6, 0xae, 0x4c, 0xc1, 0x18, 0x54, 0x35, 0xd5, 0x7f, 0xc9, 0x41, 0x85, 0x7b, 0x04, 0x90,
0xab, 0x43, 0xd0, 0xc6, 0xfa, 0xa8, 0xdf, 0x7f, 0x5b, 0x89, 0x51, 0xdd, 0x59, 0x3e, 0x2c, 0x02,
0x1b, 0x50, 0x6f, 0xb1, 0x91, 0xbd, 0x39, 0xf3, 0x98, 0x46, 0xd5, 0x60, 0xaf, 0xe4, 0x43, 0x6b,
0x54, 0x46, 0xb6, 0xa1, 0x11, 0xea, 0xd7, 0x43, 0x43, 0xe8, 0x37, 0xec, 0xda, 0xd4, 0x93, 0x1e,
0x3e, 0x32, 0x7b, 0x25, 0xbf, 0x1e, 0x8e, 0xbd, 0x39, 0x4f, 0xc1, 0xd1, 0x51, 0x08, 0x95, 0x40,
0x1a, 0x48, 0x93, 0xf9, 0xc1, 0xac, 0x58, 0x86, 0xa9, 0xb6, 0x57, 0xf2, 0x9b, 0xf9, 0xe4, 0x43,
0x7f, 0x04, 0x17, 0x8a, 0xa8, 0xc6, 0xf0, 0x16, 0x10, 0xcf, 0x9b, 0x19, 0xdb, 0x38, 0xe0, 0x52,
0xeb, 0x8d, 0xd6, 0x41, 0xc2, 0x72, 0x81, 0x38, 0xc8, 0xca, 0x80, 0xf6, 0x48, 0x3c, 0x8e, 0x5f,
0x43, 0xfc, 0x5b, 0x33, 0xf1, 0xa7, 0x5d, 0x93, 0xbd, 0x92, 0x7f, 0xb9, 0x35, 0xfb, 0x12, 0x8d,
0xe2, 0xd0, 0xbb, 0xe2, 0x3e, 0xd6, 0x19, 0x71, 0x0c, 0xcb, 0xc5, 0x28, 0x8e, 0x51, 0x05, 0x79,
0x04, 0x80, 0xc9, 0xa7, 0xa1, 0xec, 0x99, 0xe9, 0x32, 0x6c, 0x1a, 0x55, 0xba, 0xf4, 0x86, 0x1d,
0xe4, 0xc6, 0xf0, 0x56, 0xa3, 0x3d, 0x9c, 0x71, 0xab, 0x07, 0xe9, 0x12, 0x0e, 0x67, 0x5b, 0x0b,
0x50, 0x51, 0xa6, 0xde, 0xdf, 0x06, 0xc0, 0x09, 0x0d, 0x25, 0x17, 0x9b, 0x07, 0x07, 0xcf, 0x8a,
0x2e, 0x58, 0x7b, 0xab, 0xbf, 0x28, 0xaa, 0x0b, 0xd6, 0x01, 0x4d, 0xf4, 0xe7, 0xe5, 0xc9, 0xfe,
0xfc, 0x3e, 0x40, 0x2a, 0x68, 0xc4, 0x42, 0x22, 0x69, 0x76, 0xd6, 0x23, 0x33, 0xa6, 0xea, 0x7e,
0x0e, 0xf0, 0x52, 0x7d, 0x47, 0x74, 0x79, 0xaa, 0xcc, 0x24, 0x62, 0xf8, 0x67, 0xf1, 0xed, 0x97,
0xc3, 0xef, 0xcb, 0x0d, 0x58, 0x4a, 0x63, 0x12, 0xd2, 0x0e, 0x8f, 0x23, 0x2a, 0x02, 0x49, 0xda,
0x98, 0xad, 0xb6, 0xdf, 0x1c, 0x13, 0x1f, 0x93, 0xb6, 0xf7, 0x9b, 0x01, 0xd6, 0x51, 0x4c, 0x92,
0x03, 0x1e, 0x61, 0xab, 0xd6, 0xc3, 0x88, 0x03, 0x92, 0x24, 0xd9, 0x5b, 0x4a, 0xe2, 0x88, 0x17,
0x45, 0x9e, 0xb6, 0xd9, 0x4c, 0x92, 0xcc, 0x7d, 0x30, 0x11, 0xed, 0xdb, 0xeb, 0xba, 0x32, 0x1d,
0x8b, 0x77, 0x15, 0x1c, 0x9e, 0xcb, 0x34, 0x97, 0xc1, 0x80, 0x4a, 0x45, 0x97, 0xb9, 0x6a, 0xfa,
0x4d, 0x2d, 0xff, 0x4a, 0x33, 0x9a, 0xa9, 0x13, 0x4a, 0x78, 0x44, 0x6f, 0xfe, 0x68, 0xc0, 0x82,
0x2e, 0x72, 0x93, 0x4f, 0xf1, 0x12, 0xd4, 0x77, 0x05, 0x25, 0x92, 0x8a, 0xe3, 0x0e, 0x49, 0x1c,
0xc3, 0x75, 0xa0, 0x51, 0x08, 0x1e, 0xbf, 0xcc, 0x49, 0xec, 0x94, 0xdd, 0x06, 0x58, 0x4f, 0x68,
0x96, 0xe1, 0xba, 0x89, 0x6f, 0x35, 0xcd, 0x32, 0xbd, 0x58, 0x71, 0x6d, 0xa8, 0xea, 0x61, 0x55,
0xe9, 0x1d, 0x70, 0xa9, 0x67, 0x0b, 0x0a, 0xf8, 0x48, 0xd0, 0x53, 0xf6, 0xfa, 0x29, 0x91, 0x61,
0xc7, 0xa9, 0x29, 0xe0, 0x23, 0x9e, 0xc9, 0xa1, 0xc4, 0x52, 0xb6, 0x7a, 0x68, 0xdf, 0xdc, 0x85,
0xfa, 0x58, 0xf5, 0x57, 0x2e, 0x3e, 0x4f, 0x5e, 0x24, 0xfc, 0x55, 0xa2, 0x5b, 0x9e, 0xcd, 0x48,
0xb5, 0x09, 0x35, 0x30, 0x9f, 0xe5, 0x2d, 0xa7, 0xac, 0x06, 0x4f, 0xf3, 0xd8, 0x31, 0xd5, 0x60,
0x87, 0xf5, 0x9c, 0x0a, 0x4a, 0x78, 0xe4, 0x54, 0xb7, 0xee, 0x7c, 0x7b, 0xbb, 0xcd, 0x64, 0x27,
0x6f, 0xad, 0x85, 0xbc, 0xbb, 0xae, 0xc9, 0xbc, 0xc5, 0x78, 0x31, 0x5a, 0x67, 0x89, 0xa4, 0x22,
0x21, 0xf1, 0x3a, 0xf2, 0xbb, 0xae, 0xf8, 0x4d, 0x5b, 0xad, 0x05, 0x9c, 0xdd, 0xf9, 0x37, 0x00,
0x00, 0xff, 0xff, 0xc8, 0xcd, 0x73, 0x91, 0x98, 0x0f, 0x00, 0x00,
}

View File

@ -289,6 +289,16 @@ func isSameOrder(opStr1, opStr2 string) bool {
return isLess1 == isLess2
}
var opMap = map[planpb.OpType]string{
planpb.OpType_Invalid: "invalid",
planpb.OpType_GreaterThan: ">",
planpb.OpType_GreaterEqual: ">=",
planpb.OpType_LessThan: "<",
planpb.OpType_LessEqual: "<=",
planpb.OpType_Equal: "==",
planpb.OpType_NotEqual: "!=",
}
func getCompareOpType(opStr string, reverse bool) (op planpb.OpType) {
switch opStr {
case ">":
@ -513,16 +523,23 @@ func (pc *parserContext) handleCmpExpr(node *ant_ast.BinaryNode) (*planpb.Expr,
func (pc *parserContext) handleBinaryArithCmpExpr(node *ant_ast.BinaryNode) (*planpb.Expr, error) {
leftNode, funcNodeLeft := node.Left.(*ant_ast.FunctionNode)
_, funcNodeRight := node.Right.(*ant_ast.FunctionNode)
rightNode, funcNodeRight := node.Right.(*ant_ast.FunctionNode)
if funcNodeRight {
return nil, fmt.Errorf("right node as a function is not supported yet")
} else if !funcNodeLeft {
// Both left and right are not function nodes, pass to createCmpExpr
return pc.createCmpExpr(node.Left, node.Right, node.Operator)
} else {
if funcNodeLeft && funcNodeRight {
return nil, fmt.Errorf("left and right are both expression are not supported")
} else if funcNodeRight {
// Only the right node is a function node
op := getCompareOpType(node.Operator, true)
if op == planpb.OpType_Invalid {
return nil, fmt.Errorf("invalid right expression")
}
return pc.createBinaryArithOpEvalExpr(rightNode, &node.Left, opMap[op])
} else if funcNodeLeft {
// Only the left node is a function node
return pc.createBinaryArithOpEvalExpr(leftNode, &node.Right, node.Operator)
} else {
// Both left and right are not function nodes, pass to createCmpExpr
return pc.createCmpExpr(node.Left, node.Right, node.Operator)
}
}
@ -687,9 +704,10 @@ func (pc *parserContext) handleMultiCmpExpr(node *ant_ast.BinaryNode) (*planpb.E
}
func (pc *parserContext) handleBinaryExpr(node *ant_ast.BinaryNode) (*planpb.Expr, error) {
_, arithExpr := node.Left.(*ant_ast.FunctionNode)
_, leftArithExpr := node.Left.(*ant_ast.FunctionNode)
_, rightArithExpr := node.Right.(*ant_ast.FunctionNode)
if arithExpr {
if leftArithExpr || rightArithExpr {
return pc.handleBinaryArithCmpExpr(node)
}

View File

@ -20,6 +20,8 @@ import (
"fmt"
"testing"
"github.com/milvus-io/milvus/internal/parser/planparserv2"
ant_ast "github.com/antonmedv/expr/ast"
ant_parser "github.com/antonmedv/expr/parser"
@ -55,6 +57,85 @@ func newTestSchema() *schemapb.CollectionSchema {
}
}
func assertValidExpr(t *testing.T, schema *typeutil.SchemaHelper, exprStr string) {
// fmt.Println("expr: ", exprStr)
_, err := parseExpr(schema, exprStr)
assert.Nil(t, err, exprStr)
// fmt.Println("AST1:")
// planparserv2.ShowExpr(expr1)
}
func assertValidExprV2(t *testing.T, schema *typeutil.SchemaHelper, exprStr string) {
expr1, err := parseExpr(schema, exprStr)
assert.Nil(t, err)
expr2, err := planparserv2.ParseExpr(schema, exprStr)
assert.Nil(t, err)
if !planparserv2.CheckIdentical(expr1, expr2) {
fmt.Println("expr: ", exprStr)
fmt.Println("AST1:")
planparserv2.ShowExpr(expr1)
fmt.Println("AST2:")
planparserv2.ShowExpr(expr2)
t.Errorf("parsed asts are not identical")
}
}
func assertInvalidExpr(t *testing.T, schema *typeutil.SchemaHelper, exprStr string) {
// fmt.Println("expr: ", exprStr)
_, err := parseExpr(schema, exprStr)
assert.Error(t, err, exprStr)
_, err = planparserv2.ParseExpr(schema, exprStr)
assert.Error(t, err, exprStr)
}
func assertValidSearchPlan(t *testing.T, schema *schemapb.CollectionSchema, exprStr string, vectorFieldName string, queryInfo *planpb.QueryInfo) {
_, err := createQueryPlan(schema, exprStr, vectorFieldName, queryInfo)
assert.Nil(t, err)
}
func assertValidSearchPlanV2(t *testing.T, schema *schemapb.CollectionSchema, exprStr string, vectorFieldName string, queryInfo *planpb.QueryInfo) {
planProto1, err := createQueryPlan(schema, exprStr, vectorFieldName, queryInfo)
assert.Nil(t, err)
planProto2, err := planparserv2.CreateSearchPlan(schema, exprStr, vectorFieldName, queryInfo)
assert.Nil(t, err)
expr1 := planProto1.GetVectorAnns().GetPredicates()
assert.NotNil(t, expr1)
expr2 := planProto2.GetVectorAnns().GetPredicates()
assert.NotNil(t, expr2)
if !planparserv2.CheckIdentical(expr1, expr2) {
fmt.Println("expr: ", exprStr)
fmt.Println("AST1:")
planparserv2.ShowExpr(expr1)
fmt.Println("AST2:")
planparserv2.ShowExpr(expr2)
t.Errorf("parsed asts are not identical")
}
}
func assertInvalidSearchPlan(t *testing.T, schema *schemapb.CollectionSchema, exprStr string, vectorFieldName string, queryInfo *planpb.QueryInfo) {
_, err := createQueryPlan(schema, exprStr, vectorFieldName, queryInfo)
assert.Error(t, err, exprStr)
_, err = planparserv2.CreateSearchPlan(schema, exprStr, vectorFieldName, queryInfo)
assert.Error(t, err, exprStr)
}
func TestParseExpr_Naive(t *testing.T) {
schemaPb := newTestSchema()
schema, err := typeutil.CreateSchemaHelper(schemaPb)
@ -67,14 +148,19 @@ func TestParseExpr_Naive(t *testing.T) {
"FloatField > +1.0",
"FloatField > -1.0",
`VarCharField > "str"`,
}
for _, exprStr := range exprStrs {
assertValidExprV2(t, schema, exprStr)
}
})
t.Run("test string unary", func(t *testing.T) {
exprStrs := []string{
`VarCharField startsWith "str"`,
`VarCharField endsWith "str"`,
}
for _, exprStr := range exprStrs {
exprProto, err := parseExpr(schema, exprStr)
assert.Nil(t, err)
str := proto.MarshalTextString(exprProto)
println(str)
assertValidExpr(t, schema, exprStr)
}
})
@ -85,9 +171,7 @@ func TestParseExpr_Naive(t *testing.T) {
`VarCharField > -aa`,
}
for _, exprStr := range exprStrs {
exprProto, err := parseExpr(schema, exprStr)
assert.Error(t, err)
assert.Nil(t, exprProto)
assertInvalidExpr(t, schema, exprStr)
}
})
@ -122,10 +206,7 @@ func TestParseExpr_Naive(t *testing.T) {
"FloatField > 1.0 ** 2.0",
}
for _, exprStr := range exprStrs {
exprProto, err := parseExpr(schema, exprStr)
assert.Nil(t, err)
str := proto.MarshalTextString(exprProto)
println(str)
assertValidExprV2(t, schema, exprStr)
}
})
@ -156,9 +237,7 @@ func TestParseExpr_Naive(t *testing.T) {
"FloatField > aa ** 2.0",
}
for _, exprStr := range exprStrs {
exprProto, err := parseExpr(schema, exprStr)
assert.Error(t, err)
assert.Nil(t, exprProto)
assertInvalidExpr(t, schema, exprStr)
}
})
@ -184,10 +263,7 @@ func TestParseExpr_Naive(t *testing.T) {
"Int64Field % 7 == 5",
}
for _, exprStr := range exprStrs {
exprProto, err := parseExpr(schema, exprStr)
assert.Nil(t, err)
str := proto.MarshalTextString(exprProto)
println(str)
assertValidExprV2(t, schema, exprStr)
}
})
@ -233,11 +309,8 @@ func TestParsePlanNode_Naive(t *testing.T) {
"DoubleField in [1.0, 2, 3] && Int64Field < 3 or Int64Field > 2",
`not (VarCharField > "str")`,
`not ("str" > VarCharField)`,
`not (VarCharField startsWith "str")`,
`not (VarCharField endsWith "str")`,
`VarCharField in ["term0", "term1", "term2"]`,
`VarCharField < "str3" and (VarCharField > "str2" || VarCharField == "str1")`,
`VarCharField < "str3" and (VarCharField startsWith "str2" || VarCharField endsWith "str1")`,
`DoubleField in [1.0, 2, 3] && VarCharField < "str3" or Int64Field > 2`,
}
@ -248,16 +321,18 @@ func TestParsePlanNode_Naive(t *testing.T) {
SearchParams: "{\"nprobe\": 10}",
}
// Note: use pointer to string to represent nullable string
// TODO: change it to better solution
for offset, exprStr := range exprStrs {
fmt.Printf("case %d: %s\n", offset, exprStr)
planProto, err := createQueryPlan(schema, exprStr, "FloatVectorField", queryInfo)
assert.Nil(t, err)
dbgStr := proto.MarshalTextString(planProto)
println(dbgStr)
for _, exprStr := range exprStrs {
assertValidSearchPlanV2(t, schema, exprStr, "FloatVectorField", queryInfo)
}
stringFuncs := []string{
`not (VarCharField startsWith "str")`,
`not (VarCharField endsWith "str")`,
`VarCharField < "str3" and (VarCharField startsWith "str2" || VarCharField endsWith "str1")`,
}
for _, exprStr := range stringFuncs {
assertValidSearchPlan(t, schema, exprStr, "FloatVectorField", queryInfo)
}
}
func TestExternalParser(t *testing.T) {
@ -299,19 +374,15 @@ func TestExprPlan_Str(t *testing.T) {
"age not in [1, 2, 3]",
}
for offset, exprStr := range exprStrs {
fmt.Printf("case %d: %s\n", offset, exprStr)
planProto, err := createQueryPlan(schema, exprStr, "fakevec", queryInfo)
assert.Nil(t, err)
dbgStr := proto.MarshalTextString(planProto)
println(dbgStr)
for _, exprStr := range exprStrs {
assertValidSearchPlanV2(t, schema, exprStr, "fakevec", queryInfo)
}
}
func TestExprMultiRange_Str(t *testing.T) {
exprStrs := []string{
"3 < FloatN < 4.0",
"3 < age1 < 5 < age2 < 7 < FloatN < 9.0 < FloatN2",
// "3 < age1 < 5 < age2 < 7 < FloatN < 9.0 < FloatN2", // no need to support this, ambiguous.
"1 + 1 < age1 < 2 * 2",
"1 - 1 < age1 < 3 / 2",
"1.0 - 1 < FloatN < 3 / 2",
@ -351,26 +422,18 @@ func TestExprMultiRange_Str(t *testing.T) {
SearchParams: "{\"nprobe\": 10}",
}
for offset, exprStr := range exprStrs {
fmt.Printf("case %d: %s\n", offset, exprStr)
planProto, err := createQueryPlan(schema, exprStr, "fakevec", queryInfo)
assert.Nil(t, err)
dbgStr := proto.MarshalTextString(planProto)
println(dbgStr)
for _, exprStr := range exprStrs {
assertValidSearchPlanV2(t, schema, exprStr, "fakevec", queryInfo)
}
for offset, exprStr := range invalidExprs {
fmt.Printf("invalid case %d: %s\n", offset, exprStr)
planProto, err := createQueryPlan(schema, exprStr, "fakevec", queryInfo)
assert.Error(t, err)
dbgStr := proto.MarshalTextString(planProto)
println(dbgStr)
for _, exprStr := range invalidExprs {
assertInvalidSearchPlan(t, schema, exprStr, "fakevec", queryInfo)
}
}
func TestExprFieldCompare_Str(t *testing.T) {
exprStrs := []string{
"age1 < age2",
"3 < age1 <= age2 < 4",
// "3 < age1 <= age2 < 4", // no need to support this, ambiguous.
}
fields := []*schemapb.FieldSchema{
@ -393,12 +456,8 @@ func TestExprFieldCompare_Str(t *testing.T) {
SearchParams: "{\"nprobe\": 10}",
}
for offset, exprStr := range exprStrs {
fmt.Printf("case %d: %s\n", offset, exprStr)
planProto, err := createQueryPlan(schema, exprStr, "fakevec", queryInfo)
assert.Nil(t, err)
dbgStr := proto.MarshalTextString(planProto)
println(dbgStr)
for _, exprStr := range exprStrs {
assertValidSearchPlanV2(t, schema, exprStr, "fakevec", queryInfo)
}
}
@ -418,6 +477,8 @@ func TestExprBinaryArithOp_Str(t *testing.T) {
"(age1 * 4) != 9",
"(5 * FloatN) != 0",
"(9 * FloatN) != 0",
// Functional nodes at the right can be reversed
"0 == (age1 + 3)",
}
unsupportedExprStrs := []string{
@ -426,8 +487,6 @@ func TestExprBinaryArithOp_Str(t *testing.T) {
"(age1 + 2) >= 4",
"(age1 + 2) < 4",
"(age1 + 2) <= 4",
// Functional nodes at the right of the comparison are not allowed
"0 == (age1 + 3)",
// Field as the right operand for -, /, and % operators are not supported
"(10 - age1) == 0",
"(20 / age1) == 0",
@ -459,19 +518,12 @@ func TestExprBinaryArithOp_Str(t *testing.T) {
SearchParams: "{\"nprobe\": 10}",
}
for offset, exprStr := range exprStrs {
fmt.Printf("case %d: %s\n", offset, exprStr)
planProto, err := createQueryPlan(schema, exprStr, "fakevec", queryInfo)
assert.Nil(t, err)
dbgStr := proto.MarshalTextString(planProto)
println(dbgStr)
for _, exprStr := range exprStrs {
assertValidSearchPlanV2(t, schema, exprStr, "fakevec", queryInfo)
}
for offset, exprStr := range unsupportedExprStrs {
fmt.Printf("case %d: %s\n", offset, exprStr)
planProto, err := createQueryPlan(schema, exprStr, "fakevec", queryInfo)
assert.Error(t, err)
dbgStr := proto.MarshalTextString(planProto)
println(dbgStr)
for _, exprStr := range unsupportedExprStrs {
assertInvalidSearchPlan(t, schema, exprStr, "fakevec", queryInfo)
}
}
@ -546,3 +598,44 @@ func TestPlanParseAPIs(t *testing.T) {
assert.Nil(t, parseBoolNode(&nodeRaw4))
})
}
func Test_CheckIdentical(t *testing.T) {
schema := newTestSchema()
helper, err := typeutil.CreateSchemaHelper(schema)
assert.NoError(t, err)
n := 5000
int64s := generateInt64Array(n)
largeIntTermExpr := `Int64Field in [`
largeFloatTermExpr := `FloatField in [`
for _, i := range int64s[:n-1] {
largeIntTermExpr += fmt.Sprintf("%d, ", i)
largeFloatTermExpr += fmt.Sprintf("%d, ", i)
}
largeIntTermExpr += fmt.Sprintf("%d]", int64s[n-1])
largeFloatTermExpr += fmt.Sprintf("%d]", int64s[n-1])
// cases in regression.
inputs := []string{
"Int64Field > 0",
"(Int64Field > 0 && Int64Field < 400) or (Int64Field > 500 && Int64Field < 1000)",
"Int64Field not in [1, 2, 3]",
"Int64Field in [1, 2, 3] and FloatField != 2",
"Int64Field == 0 || Int64Field == 1 || Int64Field == 2",
"0 < Int64Field < 400",
"500 <= Int64Field < 1000",
"200+300 < Int64Field <= 500+500",
"Int32Field != Int64Field",
"Int64Field not in []",
largeIntTermExpr,
largeFloatTermExpr,
}
for _, input := range inputs {
// fmt.Println("expr: ", input)
expr1, err := parseExpr(helper, input)
assert.NoError(t, err)
expr2, err := planparserv2.ParseExpr(helper, input)
assert.NoError(t, err)
assert.True(t, planparserv2.CheckIdentical(expr1, expr2))
}
}

View File

@ -238,6 +238,11 @@ func IsFloatingType(dataType schemapb.DataType) bool {
}
}
// IsArithmetic returns true if input is of arithmetic type, otherwise false.
func IsArithmetic(dataType schemapb.DataType) bool {
return IsIntegerType(dataType) || IsFloatingType(dataType)
}
// IsBoolType returns true if input is a bool type, otherwise false
func IsBoolType(dataType schemapb.DataType) bool {
switch dataType {
@ -251,7 +256,7 @@ func IsBoolType(dataType schemapb.DataType) bool {
// IsStringType returns true if input is a varChar type, otherwise false
func IsStringType(dataType schemapb.DataType) bool {
switch dataType {
case schemapb.DataType_VarChar:
case schemapb.DataType_String, schemapb.DataType_VarChar:
return true
default:
return false

View File

@ -18,7 +18,9 @@
package gorules
import "github.com/quasilyte/go-ruleguard/dsl/fluent"
import (
"github.com/quasilyte/go-ruleguard/dsl/fluent"
)
// This is a collection of rules for ruleguard: https://github.com/quasilyte/go-ruleguard
@ -222,14 +224,14 @@ func floateq(m fluent.Matcher) {
"$x == $y",
"$x != $y",
).
Where(m["x"].Type.Is("float32") && !m["x"].Const && !m["y"].Text.Matches("0(.0+)?")).
Where(m["x"].Type.Is("float32") && !m["x"].Const && !m["y"].Text.Matches("0(.0+)?") && !m.File().Name.Matches("floating_comparision.go")).
Report("floating point tested for equality")
m.Match(
"$x == $y",
"$x != $y",
).
Where(m["x"].Type.Is("float64") && !m["x"].Const && !m["y"].Text.Matches("0(.0+)?")).
Where(m["x"].Type.Is("float64") && !m["x"].Const && !m["y"].Text.Matches("0(.0+)?") && !m.File().Name.Matches("floating_comparision.go")).
Report("floating point tested for equality")
m.Match("switch $x { $*_ }", "switch $*_; $x { $*_ }").

View File

@ -27,10 +27,10 @@ echo "Running unittest under ./internal"
if [[ $(uname -s) == "Darwin" && "$(uname -m)" == "arm64" ]]; then
APPLE_SILICON_FLAG="-tags dynamic"
fi
for d in $(go list ./internal/... | grep -v -e vendor -e kafka); do
for d in $(go list ./internal/... | grep -v -e vendor -e kafka -e planparserv2/generated); do
go test -race ${APPLE_SILICON_FLAG} -v -coverpkg=./... -coverprofile=profile.out -covermode=atomic "$d"
if [ -f profile.out ]; then
grep -v kafka profile.out | sed '1d' >> ${FILE_COVERAGE_INFO}
grep -v kafka profile.out | grep -v planparserv2/generated | sed '1d' >> ${FILE_COVERAGE_INFO}
rm profile.out
fi
done