| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- package engine
- import (
- "fmt"
- "math"
- "strings"
- "github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
- )
- // ===============================
- // STRING FUNCTIONS
- // ===============================
- // Length returns the length of a string
- func (e *SQLEngine) Length(value *schema_pb.Value) (*schema_pb.Value, error) {
- if value == nil {
- return nil, fmt.Errorf("LENGTH function requires non-null value")
- }
- str, err := e.valueToString(value)
- if err != nil {
- return nil, fmt.Errorf("LENGTH function conversion error: %v", err)
- }
- length := int64(len(str))
- return &schema_pb.Value{
- Kind: &schema_pb.Value_Int64Value{Int64Value: length},
- }, nil
- }
- // Upper converts a string to uppercase
- func (e *SQLEngine) Upper(value *schema_pb.Value) (*schema_pb.Value, error) {
- if value == nil {
- return nil, fmt.Errorf("UPPER function requires non-null value")
- }
- str, err := e.valueToString(value)
- if err != nil {
- return nil, fmt.Errorf("UPPER function conversion error: %v", err)
- }
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: strings.ToUpper(str)},
- }, nil
- }
- // Lower converts a string to lowercase
- func (e *SQLEngine) Lower(value *schema_pb.Value) (*schema_pb.Value, error) {
- if value == nil {
- return nil, fmt.Errorf("LOWER function requires non-null value")
- }
- str, err := e.valueToString(value)
- if err != nil {
- return nil, fmt.Errorf("LOWER function conversion error: %v", err)
- }
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: strings.ToLower(str)},
- }, nil
- }
- // Trim removes leading and trailing whitespace from a string
- func (e *SQLEngine) Trim(value *schema_pb.Value) (*schema_pb.Value, error) {
- if value == nil {
- return nil, fmt.Errorf("TRIM function requires non-null value")
- }
- str, err := e.valueToString(value)
- if err != nil {
- return nil, fmt.Errorf("TRIM function conversion error: %v", err)
- }
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: strings.TrimSpace(str)},
- }, nil
- }
- // LTrim removes leading whitespace from a string
- func (e *SQLEngine) LTrim(value *schema_pb.Value) (*schema_pb.Value, error) {
- if value == nil {
- return nil, fmt.Errorf("LTRIM function requires non-null value")
- }
- str, err := e.valueToString(value)
- if err != nil {
- return nil, fmt.Errorf("LTRIM function conversion error: %v", err)
- }
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: strings.TrimLeft(str, " \t\n\r")},
- }, nil
- }
- // RTrim removes trailing whitespace from a string
- func (e *SQLEngine) RTrim(value *schema_pb.Value) (*schema_pb.Value, error) {
- if value == nil {
- return nil, fmt.Errorf("RTRIM function requires non-null value")
- }
- str, err := e.valueToString(value)
- if err != nil {
- return nil, fmt.Errorf("RTRIM function conversion error: %v", err)
- }
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: strings.TrimRight(str, " \t\n\r")},
- }, nil
- }
- // Substring extracts a substring from a string
- func (e *SQLEngine) Substring(value *schema_pb.Value, start *schema_pb.Value, length ...*schema_pb.Value) (*schema_pb.Value, error) {
- if value == nil || start == nil {
- return nil, fmt.Errorf("SUBSTRING function requires non-null value and start position")
- }
- str, err := e.valueToString(value)
- if err != nil {
- return nil, fmt.Errorf("SUBSTRING function value conversion error: %v", err)
- }
- startPos, err := e.valueToInt64(start)
- if err != nil {
- return nil, fmt.Errorf("SUBSTRING function start position conversion error: %v", err)
- }
- // Convert to 0-based indexing (SQL uses 1-based)
- if startPos < 1 {
- startPos = 1
- }
- startIdx := int(startPos - 1)
- if startIdx >= len(str) {
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: ""},
- }, nil
- }
- var result string
- if len(length) > 0 && length[0] != nil {
- lengthVal, err := e.valueToInt64(length[0])
- if err != nil {
- return nil, fmt.Errorf("SUBSTRING function length conversion error: %v", err)
- }
- if lengthVal <= 0 {
- result = ""
- } else {
- if lengthVal > int64(math.MaxInt) || lengthVal < int64(math.MinInt) {
- // If length is out-of-bounds for int, take substring from startIdx to end
- result = str[startIdx:]
- } else {
- // Safe conversion after bounds check
- endIdx := startIdx + int(lengthVal)
- if endIdx > len(str) {
- endIdx = len(str)
- }
- result = str[startIdx:endIdx]
- }
- }
- } else {
- result = str[startIdx:]
- }
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: result},
- }, nil
- }
- // Concat concatenates multiple strings
- func (e *SQLEngine) Concat(values ...*schema_pb.Value) (*schema_pb.Value, error) {
- if len(values) == 0 {
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: ""},
- }, nil
- }
- var result strings.Builder
- for i, value := range values {
- if value == nil {
- continue // Skip null values
- }
- str, err := e.valueToString(value)
- if err != nil {
- return nil, fmt.Errorf("CONCAT function value %d conversion error: %v", i, err)
- }
- result.WriteString(str)
- }
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: result.String()},
- }, nil
- }
- // Replace replaces all occurrences of a substring with another substring
- func (e *SQLEngine) Replace(value, oldStr, newStr *schema_pb.Value) (*schema_pb.Value, error) {
- if value == nil || oldStr == nil || newStr == nil {
- return nil, fmt.Errorf("REPLACE function requires non-null values")
- }
- str, err := e.valueToString(value)
- if err != nil {
- return nil, fmt.Errorf("REPLACE function value conversion error: %v", err)
- }
- old, err := e.valueToString(oldStr)
- if err != nil {
- return nil, fmt.Errorf("REPLACE function old string conversion error: %v", err)
- }
- new, err := e.valueToString(newStr)
- if err != nil {
- return nil, fmt.Errorf("REPLACE function new string conversion error: %v", err)
- }
- result := strings.ReplaceAll(str, old, new)
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: result},
- }, nil
- }
- // Position returns the position of a substring in a string (1-based, 0 if not found)
- func (e *SQLEngine) Position(substring, value *schema_pb.Value) (*schema_pb.Value, error) {
- if substring == nil || value == nil {
- return nil, fmt.Errorf("POSITION function requires non-null values")
- }
- str, err := e.valueToString(value)
- if err != nil {
- return nil, fmt.Errorf("POSITION function string conversion error: %v", err)
- }
- substr, err := e.valueToString(substring)
- if err != nil {
- return nil, fmt.Errorf("POSITION function substring conversion error: %v", err)
- }
- pos := strings.Index(str, substr)
- if pos == -1 {
- pos = 0 // SQL returns 0 for not found
- } else {
- pos = pos + 1 // Convert to 1-based indexing
- }
- return &schema_pb.Value{
- Kind: &schema_pb.Value_Int64Value{Int64Value: int64(pos)},
- }, nil
- }
- // Left returns the leftmost characters of a string
- func (e *SQLEngine) Left(value *schema_pb.Value, length *schema_pb.Value) (*schema_pb.Value, error) {
- if value == nil || length == nil {
- return nil, fmt.Errorf("LEFT function requires non-null values")
- }
- str, err := e.valueToString(value)
- if err != nil {
- return nil, fmt.Errorf("LEFT function string conversion error: %v", err)
- }
- lengthVal, err := e.valueToInt64(length)
- if err != nil {
- return nil, fmt.Errorf("LEFT function length conversion error: %v", err)
- }
- if lengthVal <= 0 {
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: ""},
- }, nil
- }
- if lengthVal > int64(len(str)) {
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: str},
- }, nil
- }
- if lengthVal > int64(math.MaxInt) || lengthVal < int64(math.MinInt) {
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: str},
- }, nil
- }
- // Safe conversion after bounds check
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: str[:int(lengthVal)]},
- }, nil
- }
- // Right returns the rightmost characters of a string
- func (e *SQLEngine) Right(value *schema_pb.Value, length *schema_pb.Value) (*schema_pb.Value, error) {
- if value == nil || length == nil {
- return nil, fmt.Errorf("RIGHT function requires non-null values")
- }
- str, err := e.valueToString(value)
- if err != nil {
- return nil, fmt.Errorf("RIGHT function string conversion error: %v", err)
- }
- lengthVal, err := e.valueToInt64(length)
- if err != nil {
- return nil, fmt.Errorf("RIGHT function length conversion error: %v", err)
- }
- if lengthVal <= 0 {
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: ""},
- }, nil
- }
- if lengthVal > int64(len(str)) {
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: str},
- }, nil
- }
- if lengthVal > int64(math.MaxInt) || lengthVal < int64(math.MinInt) {
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: str},
- }, nil
- }
- // Safe conversion after bounds check
- startPos := len(str) - int(lengthVal)
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: str[startPos:]},
- }, nil
- }
- // Reverse reverses a string
- func (e *SQLEngine) Reverse(value *schema_pb.Value) (*schema_pb.Value, error) {
- if value == nil {
- return nil, fmt.Errorf("REVERSE function requires non-null value")
- }
- str, err := e.valueToString(value)
- if err != nil {
- return nil, fmt.Errorf("REVERSE function conversion error: %v", err)
- }
- // Reverse the string rune by rune to handle Unicode correctly
- runes := []rune(str)
- for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
- runes[i], runes[j] = runes[j], runes[i]
- }
- return &schema_pb.Value{
- Kind: &schema_pb.Value_StringValue{StringValue: string(runes)},
- }, nil
- }
|