mirror of https://github.com/milvus-io/milvus.git
88 lines
2.1 KiB
Go
88 lines
2.1 KiB
Go
package planparserv2
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/milvus-io/milvus/pkg/v2/proto/planpb"
|
|
)
|
|
|
|
var wildcards = map[byte]struct{}{
|
|
'_': {},
|
|
'%': {},
|
|
}
|
|
|
|
var escapeCharacter byte = '\\'
|
|
|
|
func optimizeLikePattern(pattern string) (planpb.OpType, string, bool) {
|
|
if len(pattern) == 0 {
|
|
return planpb.OpType_Equal, "", true
|
|
}
|
|
|
|
if pattern == "%" || pattern == "%%" {
|
|
return planpb.OpType_PrefixMatch, "", true
|
|
}
|
|
|
|
process := func(s string) (string, bool) {
|
|
var buf strings.Builder
|
|
for i := 0; i < len(s); i++ {
|
|
c := s[i]
|
|
if c == escapeCharacter && i+1 < len(s) {
|
|
next := s[i+1]
|
|
if _, ok := wildcards[next]; ok {
|
|
buf.WriteByte(next)
|
|
i++
|
|
continue
|
|
}
|
|
}
|
|
if _, ok := wildcards[c]; ok {
|
|
return "", false
|
|
}
|
|
buf.WriteByte(c)
|
|
}
|
|
return buf.String(), true
|
|
}
|
|
|
|
leading := pattern[0] == '%'
|
|
trailing := pattern[len(pattern)-1] == '%'
|
|
|
|
switch {
|
|
case leading && trailing:
|
|
inner := pattern[1 : len(pattern)-1]
|
|
trimmed := strings.TrimLeft(inner, "%")
|
|
trimmed = strings.TrimRight(trimmed, "%")
|
|
if subStr, valid := process(trimmed); valid {
|
|
// if subStr is empty, it means the pattern is all %,
|
|
// return prefix match and empty operand, means all match
|
|
if len(subStr) == 0 {
|
|
return planpb.OpType_PrefixMatch, "", true
|
|
}
|
|
return planpb.OpType_InnerMatch, subStr, true
|
|
}
|
|
case leading:
|
|
trimmed := strings.TrimLeft(pattern[1:], "%")
|
|
if subStr, valid := process(trimmed); valid {
|
|
return planpb.OpType_PostfixMatch, subStr, true
|
|
}
|
|
case trailing:
|
|
trimmed := strings.TrimRight(pattern[:len(pattern)-1], "%")
|
|
if subStr, valid := process(trimmed); valid {
|
|
return planpb.OpType_PrefixMatch, subStr, true
|
|
}
|
|
default:
|
|
if subStr, valid := process(pattern); valid {
|
|
return planpb.OpType_Equal, subStr, true
|
|
}
|
|
}
|
|
return planpb.OpType_Invalid, "", false
|
|
}
|
|
|
|
// translatePatternMatch translates pattern to related op type and operand.
|
|
func translatePatternMatch(pattern string) (op planpb.OpType, operand string, err error) {
|
|
op, operand, ok := optimizeLikePattern(pattern)
|
|
if ok {
|
|
return op, operand, nil
|
|
}
|
|
|
|
return planpb.OpType_Match, pattern, nil
|
|
}
|