mirror of
https://github.com/minio/minio.git
synced 2025-11-20 18:06:10 -05:00
rename all remaining packages to internal/ (#12418)
This is to ensure that there are no projects that try to import `minio/minio/pkg` into their own repo. Any such common packages should go to `https://github.com/minio/pkg`
This commit is contained in:
200
internal/s3select/sql/stringfuncs.go
Normal file
200
internal/s3select/sql/stringfuncs.go
Normal file
@@ -0,0 +1,200 @@
|
||||
// Copyright (c) 2015-2021 MinIO, Inc.
|
||||
//
|
||||
// This file is part of MinIO Object Storage stack
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package sql
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
errMalformedEscapeSequence = errors.New("Malformed escape sequence in LIKE clause")
|
||||
errInvalidTrimArg = errors.New("Trim argument is invalid - this should not happen")
|
||||
errInvalidSubstringIndexLen = errors.New("Substring start index or length falls outside the string")
|
||||
)
|
||||
|
||||
const (
|
||||
percent rune = '%'
|
||||
underscore rune = '_'
|
||||
runeZero rune = 0
|
||||
)
|
||||
|
||||
func evalSQLLike(text, pattern string, escape rune) (match bool, err error) {
|
||||
s := []rune{}
|
||||
prev := runeZero
|
||||
hasLeadingPercent := false
|
||||
patLen := len([]rune(pattern))
|
||||
for i, r := range pattern {
|
||||
if i > 0 && prev == escape {
|
||||
switch r {
|
||||
case percent, escape, underscore:
|
||||
s = append(s, r)
|
||||
prev = r
|
||||
if r == escape {
|
||||
prev = runeZero
|
||||
}
|
||||
default:
|
||||
return false, errMalformedEscapeSequence
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
prev = r
|
||||
|
||||
var ok bool
|
||||
switch r {
|
||||
case percent:
|
||||
if len(s) == 0 {
|
||||
hasLeadingPercent = true
|
||||
continue
|
||||
}
|
||||
|
||||
text, ok = matcher(text, string(s), hasLeadingPercent)
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
hasLeadingPercent = true
|
||||
s = []rune{}
|
||||
|
||||
if i == patLen-1 {
|
||||
// Last pattern character is a %, so
|
||||
// we are done.
|
||||
return true, nil
|
||||
}
|
||||
|
||||
case underscore:
|
||||
if len(s) == 0 {
|
||||
text, ok = dropRune(text)
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
text, ok = matcher(text, string(s), hasLeadingPercent)
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
hasLeadingPercent = false
|
||||
|
||||
text, ok = dropRune(text)
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
s = []rune{}
|
||||
|
||||
case escape:
|
||||
if i == patLen-1 {
|
||||
return false, errMalformedEscapeSequence
|
||||
}
|
||||
// Otherwise do nothing.
|
||||
|
||||
default:
|
||||
s = append(s, r)
|
||||
}
|
||||
|
||||
}
|
||||
if hasLeadingPercent {
|
||||
return strings.HasSuffix(text, string(s)), nil
|
||||
}
|
||||
return string(s) == text, nil
|
||||
}
|
||||
|
||||
// matcher - Finds `pat` in `text`, and returns the part remainder of
|
||||
// `text`, after the match. If leadingPercent is false, `pat` must be
|
||||
// the prefix of `text`, otherwise it must be a substring.
|
||||
func matcher(text, pat string, leadingPercent bool) (res string, match bool) {
|
||||
if !leadingPercent {
|
||||
res = strings.TrimPrefix(text, pat)
|
||||
if len(text) == len(res) {
|
||||
return "", false
|
||||
}
|
||||
} else {
|
||||
parts := strings.SplitN(text, pat, 2)
|
||||
if len(parts) == 1 {
|
||||
return "", false
|
||||
}
|
||||
res = parts[1]
|
||||
}
|
||||
return res, true
|
||||
}
|
||||
|
||||
func dropRune(text string) (res string, ok bool) {
|
||||
r := []rune(text)
|
||||
if len(r) == 0 {
|
||||
return "", false
|
||||
}
|
||||
return string(r[1:]), true
|
||||
}
|
||||
|
||||
func evalSQLSubstring(s string, startIdx, length int) (res string, err error) {
|
||||
rs := []rune(s)
|
||||
|
||||
// According to s3 document, if startIdx < 1, it is set to 1.
|
||||
if startIdx < 1 {
|
||||
startIdx = 1
|
||||
}
|
||||
|
||||
if startIdx > len(rs) {
|
||||
startIdx = len(rs) + 1
|
||||
}
|
||||
|
||||
// StartIdx is 1-based in the input
|
||||
startIdx--
|
||||
endIdx := len(rs)
|
||||
if length != -1 {
|
||||
if length < 0 {
|
||||
return "", errInvalidSubstringIndexLen
|
||||
}
|
||||
|
||||
if length > (endIdx - startIdx) {
|
||||
length = endIdx - startIdx
|
||||
}
|
||||
|
||||
endIdx = startIdx + length
|
||||
}
|
||||
|
||||
return string(rs[startIdx:endIdx]), nil
|
||||
}
|
||||
|
||||
const (
|
||||
trimLeading = "LEADING"
|
||||
trimTrailing = "TRAILING"
|
||||
trimBoth = "BOTH"
|
||||
)
|
||||
|
||||
func evalSQLTrim(where *string, trimChars, text string) (result string, err error) {
|
||||
cutSet := " "
|
||||
if trimChars != "" {
|
||||
cutSet = trimChars
|
||||
}
|
||||
|
||||
trimFunc := strings.Trim
|
||||
switch {
|
||||
case where == nil:
|
||||
case *where == trimBoth:
|
||||
case *where == trimLeading:
|
||||
trimFunc = strings.TrimLeft
|
||||
case *where == trimTrailing:
|
||||
trimFunc = strings.TrimRight
|
||||
default:
|
||||
return "", errInvalidTrimArg
|
||||
}
|
||||
|
||||
return trimFunc(text, cutSet), nil
|
||||
}
|
||||
Reference in New Issue
Block a user