milvus/internal/parser/planparserv2/pattern_match.go

79 lines
1.6 KiB
Go

package planparserv2
import (
"strings"
"github.com/milvus-io/milvus/pkg/v2/proto/planpb"
)
var wildcards = map[byte]struct{}{
'_': {},
'%': {},
}
var escapeCharacter byte = '\\'
// hasWildcards returns true if pattern contains any wildcard.
func hasWildcards(pattern string) (string, bool) {
var result strings.Builder
hasWildcard := false
for i := 0; i < len(pattern); i++ {
if pattern[i] == '\\' && i+1 < len(pattern) {
next := pattern[i+1]
if next == '_' || next == '%' {
result.WriteByte(next)
i++
continue
}
}
if pattern[i] == '_' || pattern[i] == '%' {
hasWildcard = true
}
result.WriteByte(pattern[i])
}
return result.String(), hasWildcard
}
// findLastNotOfWildcards find the last location not of last wildcard.
func findLastNotOfWildcards(pattern string) int {
loc := len(pattern) - 1
for ; loc >= 0; loc-- {
_, ok := wildcards[pattern[loc]]
if !ok {
break
}
if ok {
if loc > 0 && pattern[loc-1] == escapeCharacter {
break
}
}
}
return loc
}
// translatePatternMatch translates pattern to related op type and operand.
func translatePatternMatch(pattern string) (op planpb.OpType, operand string, err error) {
l := len(pattern)
loc := findLastNotOfWildcards(pattern)
if loc < 0 {
// always match.
return planpb.OpType_PrefixMatch, "", nil
}
newPattern, exist := hasWildcards(pattern[:loc+1])
if loc >= l-1 && !exist {
// equal match.
return planpb.OpType_Equal, newPattern, nil
}
if !exist {
// prefix match.
return planpb.OpType_PrefixMatch, newPattern, nil
}
return planpb.OpType_Match, pattern, nil
}