github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/memristed/memex/builtin_string.go (about) 1 // Copyright 2020 The ql Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSES/QL-LICENSE file. 4 5 // Copyright 2020 WHTCORPS INC, Inc. 6 // 7 // Licensed under the Apache License, Version 2.0 (the "License"); 8 // you may not use this file except in compliance with the License. 9 // You may obtain a copy of the License at 10 // 11 // http://www.apache.org/licenses/LICENSE-2.0 12 // 13 // Unless required by applicable law or agreed to in writing, software 14 // distributed under the License is distributed on an "AS IS" BASIS, 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 18 package memex 19 20 import ( 21 "bytes" 22 "encoding/base64" 23 "encoding/hex" 24 "fmt" 25 "math" 26 "strconv" 27 "strings" 28 "unicode/utf8" 29 30 "github.com/whtcorpsinc/errors" 31 "github.com/whtcorpsinc/BerolinaSQL/ast" 32 "github.com/whtcorpsinc/BerolinaSQL/charset" 33 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 34 "github.com/whtcorpsinc/milevadb/stochastikctx" 35 "github.com/whtcorpsinc/milevadb/stochastikctx/variable" 36 "github.com/whtcorpsinc/milevadb/types" 37 "github.com/whtcorpsinc/milevadb/soliton/chunk" 38 "github.com/whtcorpsinc/milevadb/soliton/defCauslate" 39 "github.com/whtcorpsinc/milevadb/soliton/replog" 40 "github.com/whtcorpsinc/milevadb/soliton/logutil" 41 "github.com/whtcorpsinc/fidelpb/go-fidelpb" 42 "go.uber.org/zap" 43 "golang.org/x/text/transform" 44 ) 45 46 var ( 47 _ functionClass = &lengthFunctionClass{} 48 _ functionClass = &asciiFunctionClass{} 49 _ functionClass = &concatFunctionClass{} 50 _ functionClass = &concatWSFunctionClass{} 51 _ functionClass = &leftFunctionClass{} 52 _ functionClass = &repeatFunctionClass{} 53 _ functionClass = &lowerFunctionClass{} 54 _ functionClass = &reverseFunctionClass{} 55 _ functionClass = &spaceFunctionClass{} 56 _ functionClass = &upperFunctionClass{} 57 _ functionClass = &strcmpFunctionClass{} 58 _ functionClass = &replaceFunctionClass{} 59 _ functionClass = &convertFunctionClass{} 60 _ functionClass = &substringFunctionClass{} 61 _ functionClass = &substringIndexFunctionClass{} 62 _ functionClass = &locateFunctionClass{} 63 _ functionClass = &hexFunctionClass{} 64 _ functionClass = &unhexFunctionClass{} 65 _ functionClass = &trimFunctionClass{} 66 _ functionClass = &lTrimFunctionClass{} 67 _ functionClass = &rTrimFunctionClass{} 68 _ functionClass = &lpadFunctionClass{} 69 _ functionClass = &rpadFunctionClass{} 70 _ functionClass = &bitLengthFunctionClass{} 71 _ functionClass = &charFunctionClass{} 72 _ functionClass = &charLengthFunctionClass{} 73 _ functionClass = &findInSetFunctionClass{} 74 _ functionClass = &fieldFunctionClass{} 75 _ functionClass = &makeSetFunctionClass{} 76 _ functionClass = &octFunctionClass{} 77 _ functionClass = &ordFunctionClass{} 78 _ functionClass = "eFunctionClass{} 79 _ functionClass = &binFunctionClass{} 80 _ functionClass = &eltFunctionClass{} 81 _ functionClass = &exportSetFunctionClass{} 82 _ functionClass = &formatFunctionClass{} 83 _ functionClass = &fromBase64FunctionClass{} 84 _ functionClass = &toBase64FunctionClass{} 85 _ functionClass = &insertFunctionClass{} 86 _ functionClass = &instrFunctionClass{} 87 _ functionClass = &loadFileFunctionClass{} 88 _ functionClass = &weightStringFunctionClass{} 89 ) 90 91 var ( 92 _ builtinFunc = &builtinLengthSig{} 93 _ builtinFunc = &builtinASCIISig{} 94 _ builtinFunc = &builtinConcatSig{} 95 _ builtinFunc = &builtinConcatWSSig{} 96 _ builtinFunc = &builtinLeftSig{} 97 _ builtinFunc = &builtinLeftUTF8Sig{} 98 _ builtinFunc = &builtinRightSig{} 99 _ builtinFunc = &builtinRightUTF8Sig{} 100 _ builtinFunc = &builtinRepeatSig{} 101 _ builtinFunc = &builtinLowerSig{} 102 _ builtinFunc = &builtinReverseUTF8Sig{} 103 _ builtinFunc = &builtinReverseSig{} 104 _ builtinFunc = &builtinSpaceSig{} 105 _ builtinFunc = &builtinUpperUTF8Sig{} 106 _ builtinFunc = &builtinUpperSig{} 107 _ builtinFunc = &builtinStrcmpSig{} 108 _ builtinFunc = &builtinReplaceSig{} 109 _ builtinFunc = &builtinConvertSig{} 110 _ builtinFunc = &builtinSubstring2ArgsSig{} 111 _ builtinFunc = &builtinSubstring3ArgsSig{} 112 _ builtinFunc = &builtinSubstring2ArgsUTF8Sig{} 113 _ builtinFunc = &builtinSubstring3ArgsUTF8Sig{} 114 _ builtinFunc = &builtinSubstringIndexSig{} 115 _ builtinFunc = &builtinLocate2ArgsUTF8Sig{} 116 _ builtinFunc = &builtinLocate3ArgsUTF8Sig{} 117 _ builtinFunc = &builtinLocate2ArgsSig{} 118 _ builtinFunc = &builtinLocate3ArgsSig{} 119 _ builtinFunc = &builtinHexStrArgSig{} 120 _ builtinFunc = &builtinHexIntArgSig{} 121 _ builtinFunc = &builtinUnHexSig{} 122 _ builtinFunc = &builtinTrim1ArgSig{} 123 _ builtinFunc = &builtinTrim2ArgsSig{} 124 _ builtinFunc = &builtinTrim3ArgsSig{} 125 _ builtinFunc = &builtinLTrimSig{} 126 _ builtinFunc = &builtinRTrimSig{} 127 _ builtinFunc = &builtinLpadUTF8Sig{} 128 _ builtinFunc = &builtinLpadSig{} 129 _ builtinFunc = &builtinRpadUTF8Sig{} 130 _ builtinFunc = &builtinRpadSig{} 131 _ builtinFunc = &builtinBitLengthSig{} 132 _ builtinFunc = &builtinCharSig{} 133 _ builtinFunc = &builtinCharLengthUTF8Sig{} 134 _ builtinFunc = &builtinFindInSetSig{} 135 _ builtinFunc = &builtinMakeSetSig{} 136 _ builtinFunc = &builtinOctIntSig{} 137 _ builtinFunc = &builtinOctStringSig{} 138 _ builtinFunc = &builtinOrdSig{} 139 _ builtinFunc = &builtinQuoteSig{} 140 _ builtinFunc = &builtinBinSig{} 141 _ builtinFunc = &builtinEltSig{} 142 _ builtinFunc = &builtinExportSet3ArgSig{} 143 _ builtinFunc = &builtinExportSet4ArgSig{} 144 _ builtinFunc = &builtinExportSet5ArgSig{} 145 _ builtinFunc = &builtinFormatWithLocaleSig{} 146 _ builtinFunc = &builtinFormatSig{} 147 _ builtinFunc = &builtinFromBase64Sig{} 148 _ builtinFunc = &builtinToBase64Sig{} 149 _ builtinFunc = &builtinInsertSig{} 150 _ builtinFunc = &builtinInsertUTF8Sig{} 151 _ builtinFunc = &builtinInstrUTF8Sig{} 152 _ builtinFunc = &builtinInstrSig{} 153 _ builtinFunc = &builtinFieldRealSig{} 154 _ builtinFunc = &builtinFieldIntSig{} 155 _ builtinFunc = &builtinFieldStringSig{} 156 _ builtinFunc = &builtinWeightStringSig{} 157 ) 158 159 func reverseBytes(origin []byte) []byte { 160 for i, length := 0, len(origin); i < length/2; i++ { 161 origin[i], origin[length-i-1] = origin[length-i-1], origin[i] 162 } 163 return origin 164 } 165 166 func reverseRunes(origin []rune) []rune { 167 for i, length := 0, len(origin); i < length/2; i++ { 168 origin[i], origin[length-i-1] = origin[length-i-1], origin[i] 169 } 170 return origin 171 } 172 173 // SetBinFlagOrBinStr sets resTp to binary string if argTp is a binary string, 174 // if not, sets the binary flag of resTp to true if argTp has binary flag. 175 func SetBinFlagOrBinStr(argTp *types.FieldType, resTp *types.FieldType) { 176 if types.IsBinaryStr(argTp) { 177 types.SetBinChsClnFlag(resTp) 178 } else if allegrosql.HasBinaryFlag(argTp.Flag) || !types.IsNonBinaryStr(argTp) { 179 resTp.Flag |= allegrosql.BinaryFlag 180 } 181 } 182 183 type lengthFunctionClass struct { 184 baseFunctionClass 185 } 186 187 func (c *lengthFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 188 if err := c.verifyArgs(args); err != nil { 189 return nil, err 190 } 191 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETInt, types.ETString) 192 if err != nil { 193 return nil, err 194 } 195 bf.tp.Flen = 10 196 sig := &builtinLengthSig{bf} 197 sig.setPbCode(fidelpb.ScalarFuncSig_Length) 198 return sig, nil 199 } 200 201 type builtinLengthSig struct { 202 baseBuiltinFunc 203 } 204 205 func (b *builtinLengthSig) Clone() builtinFunc { 206 newSig := &builtinLengthSig{} 207 newSig.cloneFrom(&b.baseBuiltinFunc) 208 return newSig 209 } 210 211 // evalInt evaluates a builtinLengthSig. 212 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html 213 func (b *builtinLengthSig) evalInt(event chunk.Event) (int64, bool, error) { 214 val, isNull, err := b.args[0].EvalString(b.ctx, event) 215 if isNull || err != nil { 216 return 0, isNull, err 217 } 218 return int64(len([]byte(val))), false, nil 219 } 220 221 type asciiFunctionClass struct { 222 baseFunctionClass 223 } 224 225 func (c *asciiFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 226 if err := c.verifyArgs(args); err != nil { 227 return nil, err 228 } 229 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETInt, types.ETString) 230 if err != nil { 231 return nil, err 232 } 233 bf.tp.Flen = 3 234 sig := &builtinASCIISig{bf} 235 sig.setPbCode(fidelpb.ScalarFuncSig_ASCII) 236 return sig, nil 237 } 238 239 type builtinASCIISig struct { 240 baseBuiltinFunc 241 } 242 243 func (b *builtinASCIISig) Clone() builtinFunc { 244 newSig := &builtinASCIISig{} 245 newSig.cloneFrom(&b.baseBuiltinFunc) 246 return newSig 247 } 248 249 // evalInt evals a builtinASCIISig. 250 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_ascii 251 func (b *builtinASCIISig) evalInt(event chunk.Event) (int64, bool, error) { 252 val, isNull, err := b.args[0].EvalString(b.ctx, event) 253 if isNull || err != nil { 254 return 0, isNull, err 255 } 256 if len(val) == 0 { 257 return 0, false, nil 258 } 259 return int64(val[0]), false, nil 260 } 261 262 type concatFunctionClass struct { 263 baseFunctionClass 264 } 265 266 func (c *concatFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 267 if err := c.verifyArgs(args); err != nil { 268 return nil, err 269 } 270 argTps := make([]types.EvalType, 0, len(args)) 271 for i := 0; i < len(args); i++ { 272 argTps = append(argTps, types.ETString) 273 } 274 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, argTps...) 275 if err != nil { 276 return nil, err 277 } 278 bf.tp.Flen = 0 279 for i := range args { 280 argType := args[i].GetType() 281 SetBinFlagOrBinStr(argType, bf.tp) 282 283 if argType.Flen < 0 { 284 bf.tp.Flen = allegrosql.MaxBlobWidth 285 logutil.BgLogger().Warn("unexpected `Flen` value(-1) in CONCAT's args", zap.Int("arg's index", i)) 286 } 287 bf.tp.Flen += argType.Flen 288 } 289 if bf.tp.Flen >= allegrosql.MaxBlobWidth { 290 bf.tp.Flen = allegrosql.MaxBlobWidth 291 } 292 293 valStr, _ := ctx.GetStochastikVars().GetSystemVar(variable.MaxAllowedPacket) 294 maxAllowedPacket, err := strconv.ParseUint(valStr, 10, 64) 295 if err != nil { 296 return nil, errors.Trace(err) 297 } 298 299 sig := &builtinConcatSig{bf, maxAllowedPacket} 300 sig.setPbCode(fidelpb.ScalarFuncSig_Concat) 301 return sig, nil 302 } 303 304 type builtinConcatSig struct { 305 baseBuiltinFunc 306 maxAllowedPacket uint64 307 } 308 309 func (b *builtinConcatSig) Clone() builtinFunc { 310 newSig := &builtinConcatSig{} 311 newSig.cloneFrom(&b.baseBuiltinFunc) 312 newSig.maxAllowedPacket = b.maxAllowedPacket 313 return newSig 314 } 315 316 // evalString evals a builtinConcatSig 317 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_concat 318 func (b *builtinConcatSig) evalString(event chunk.Event) (d string, isNull bool, err error) { 319 var s []byte 320 for _, a := range b.getArgs() { 321 d, isNull, err = a.EvalString(b.ctx, event) 322 if isNull || err != nil { 323 return d, isNull, err 324 } 325 if uint64(len(s)+len(d)) > b.maxAllowedPacket { 326 b.ctx.GetStochastikVars().StmtCtx.AppendWarning(errWarnAllowedPacketOverflowed.GenWithStackByArgs("concat", b.maxAllowedPacket)) 327 return "", true, nil 328 } 329 s = append(s, []byte(d)...) 330 } 331 return string(s), false, nil 332 } 333 334 type concatWSFunctionClass struct { 335 baseFunctionClass 336 } 337 338 func (c *concatWSFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 339 if err := c.verifyArgs(args); err != nil { 340 return nil, err 341 } 342 argTps := make([]types.EvalType, 0, len(args)) 343 for i := 0; i < len(args); i++ { 344 argTps = append(argTps, types.ETString) 345 } 346 347 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, argTps...) 348 if err != nil { 349 return nil, err 350 } 351 bf.tp.Flen = 0 352 353 for i := range args { 354 argType := args[i].GetType() 355 SetBinFlagOrBinStr(argType, bf.tp) 356 357 // skip separator param 358 if i != 0 { 359 if argType.Flen < 0 { 360 bf.tp.Flen = allegrosql.MaxBlobWidth 361 logutil.BgLogger().Warn("unexpected `Flen` value(-1) in CONCAT_WS's args", zap.Int("arg's index", i)) 362 } 363 bf.tp.Flen += argType.Flen 364 } 365 } 366 367 // add separator 368 argsLen := len(args) - 1 369 bf.tp.Flen += argsLen - 1 370 371 if bf.tp.Flen >= allegrosql.MaxBlobWidth { 372 bf.tp.Flen = allegrosql.MaxBlobWidth 373 } 374 375 valStr, _ := ctx.GetStochastikVars().GetSystemVar(variable.MaxAllowedPacket) 376 maxAllowedPacket, err := strconv.ParseUint(valStr, 10, 64) 377 if err != nil { 378 return nil, errors.Trace(err) 379 } 380 381 sig := &builtinConcatWSSig{bf, maxAllowedPacket} 382 sig.setPbCode(fidelpb.ScalarFuncSig_ConcatWS) 383 return sig, nil 384 } 385 386 type builtinConcatWSSig struct { 387 baseBuiltinFunc 388 maxAllowedPacket uint64 389 } 390 391 func (b *builtinConcatWSSig) Clone() builtinFunc { 392 newSig := &builtinConcatWSSig{} 393 newSig.cloneFrom(&b.baseBuiltinFunc) 394 newSig.maxAllowedPacket = b.maxAllowedPacket 395 return newSig 396 } 397 398 // evalString evals a CONCAT_WS(separator,str1,str2,...). 399 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_concat-ws 400 func (b *builtinConcatWSSig) evalString(event chunk.Event) (string, bool, error) { 401 args := b.getArgs() 402 strs := make([]string, 0, len(args)) 403 var sep string 404 var targetLength int 405 406 N := len(args) 407 if N > 0 { 408 val, isNull, err := args[0].EvalString(b.ctx, event) 409 if err != nil || isNull { 410 // If the separator is NULL, the result is NULL. 411 return val, isNull, err 412 } 413 sep = val 414 } 415 for i := 1; i < N; i++ { 416 val, isNull, err := args[i].EvalString(b.ctx, event) 417 if err != nil { 418 return val, isNull, err 419 } 420 if isNull { 421 // CONCAT_WS() does not skip empty strings. However, 422 // it does skip any NULL values after the separator argument. 423 continue 424 } 425 426 targetLength += len(val) 427 if i > 1 { 428 targetLength += len(sep) 429 } 430 if uint64(targetLength) > b.maxAllowedPacket { 431 b.ctx.GetStochastikVars().StmtCtx.AppendWarning(errWarnAllowedPacketOverflowed.GenWithStackByArgs("concat_ws", b.maxAllowedPacket)) 432 return "", true, nil 433 } 434 strs = append(strs, val) 435 } 436 437 str := strings.Join(strs, sep) 438 // todo check whether the length of result is larger than Flen 439 //if b.tp.Flen != types.UnspecifiedLength && len(str) > b.tp.Flen { 440 // return "", true, nil 441 //} 442 return str, false, nil 443 } 444 445 type leftFunctionClass struct { 446 baseFunctionClass 447 } 448 449 func (c *leftFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 450 if err := c.verifyArgs(args); err != nil { 451 return nil, err 452 } 453 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString, types.ETInt) 454 if err != nil { 455 return nil, err 456 } 457 argType := args[0].GetType() 458 bf.tp.Flen = argType.Flen 459 SetBinFlagOrBinStr(argType, bf.tp) 460 if types.IsBinaryStr(argType) { 461 sig := &builtinLeftSig{bf} 462 sig.setPbCode(fidelpb.ScalarFuncSig_Left) 463 return sig, nil 464 } 465 sig := &builtinLeftUTF8Sig{bf} 466 sig.setPbCode(fidelpb.ScalarFuncSig_LeftUTF8) 467 return sig, nil 468 } 469 470 type builtinLeftSig struct { 471 baseBuiltinFunc 472 } 473 474 func (b *builtinLeftSig) Clone() builtinFunc { 475 newSig := &builtinLeftSig{} 476 newSig.cloneFrom(&b.baseBuiltinFunc) 477 return newSig 478 } 479 480 // evalString evals LEFT(str,len). 481 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_left 482 func (b *builtinLeftSig) evalString(event chunk.Event) (string, bool, error) { 483 str, isNull, err := b.args[0].EvalString(b.ctx, event) 484 if isNull || err != nil { 485 return "", true, err 486 } 487 left, isNull, err := b.args[1].EvalInt(b.ctx, event) 488 if isNull || err != nil { 489 return "", true, err 490 } 491 leftLength := int(left) 492 if strLength := len(str); leftLength > strLength { 493 leftLength = strLength 494 } else if leftLength < 0 { 495 leftLength = 0 496 } 497 return str[:leftLength], false, nil 498 } 499 500 type builtinLeftUTF8Sig struct { 501 baseBuiltinFunc 502 } 503 504 func (b *builtinLeftUTF8Sig) Clone() builtinFunc { 505 newSig := &builtinLeftUTF8Sig{} 506 newSig.cloneFrom(&b.baseBuiltinFunc) 507 return newSig 508 } 509 510 // evalString evals LEFT(str,len). 511 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_left 512 func (b *builtinLeftUTF8Sig) evalString(event chunk.Event) (string, bool, error) { 513 str, isNull, err := b.args[0].EvalString(b.ctx, event) 514 if isNull || err != nil { 515 return "", true, err 516 } 517 left, isNull, err := b.args[1].EvalInt(b.ctx, event) 518 if isNull || err != nil { 519 return "", true, err 520 } 521 runes, leftLength := []rune(str), int(left) 522 if runeLength := len(runes); leftLength > runeLength { 523 leftLength = runeLength 524 } else if leftLength < 0 { 525 leftLength = 0 526 } 527 return string(runes[:leftLength]), false, nil 528 } 529 530 type rightFunctionClass struct { 531 baseFunctionClass 532 } 533 534 func (c *rightFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 535 if err := c.verifyArgs(args); err != nil { 536 return nil, err 537 } 538 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString, types.ETInt) 539 if err != nil { 540 return nil, err 541 } 542 argType := args[0].GetType() 543 bf.tp.Flen = argType.Flen 544 SetBinFlagOrBinStr(argType, bf.tp) 545 if types.IsBinaryStr(argType) { 546 sig := &builtinRightSig{bf} 547 sig.setPbCode(fidelpb.ScalarFuncSig_Right) 548 return sig, nil 549 } 550 sig := &builtinRightUTF8Sig{bf} 551 sig.setPbCode(fidelpb.ScalarFuncSig_RightUTF8) 552 return sig, nil 553 } 554 555 type builtinRightSig struct { 556 baseBuiltinFunc 557 } 558 559 func (b *builtinRightSig) Clone() builtinFunc { 560 newSig := &builtinRightSig{} 561 newSig.cloneFrom(&b.baseBuiltinFunc) 562 return newSig 563 } 564 565 // evalString evals RIGHT(str,len). 566 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_right 567 func (b *builtinRightSig) evalString(event chunk.Event) (string, bool, error) { 568 str, isNull, err := b.args[0].EvalString(b.ctx, event) 569 if isNull || err != nil { 570 return "", true, err 571 } 572 right, isNull, err := b.args[1].EvalInt(b.ctx, event) 573 if isNull || err != nil { 574 return "", true, err 575 } 576 strLength, rightLength := len(str), int(right) 577 if rightLength > strLength { 578 rightLength = strLength 579 } else if rightLength < 0 { 580 rightLength = 0 581 } 582 return str[strLength-rightLength:], false, nil 583 } 584 585 type builtinRightUTF8Sig struct { 586 baseBuiltinFunc 587 } 588 589 func (b *builtinRightUTF8Sig) Clone() builtinFunc { 590 newSig := &builtinRightUTF8Sig{} 591 newSig.cloneFrom(&b.baseBuiltinFunc) 592 return newSig 593 } 594 595 // evalString evals RIGHT(str,len). 596 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_right 597 func (b *builtinRightUTF8Sig) evalString(event chunk.Event) (string, bool, error) { 598 str, isNull, err := b.args[0].EvalString(b.ctx, event) 599 if isNull || err != nil { 600 return "", true, err 601 } 602 right, isNull, err := b.args[1].EvalInt(b.ctx, event) 603 if isNull || err != nil { 604 return "", true, err 605 } 606 runes := []rune(str) 607 strLength, rightLength := len(runes), int(right) 608 if rightLength > strLength { 609 rightLength = strLength 610 } else if rightLength < 0 { 611 rightLength = 0 612 } 613 return string(runes[strLength-rightLength:]), false, nil 614 } 615 616 type repeatFunctionClass struct { 617 baseFunctionClass 618 } 619 620 func (c *repeatFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 621 if err := c.verifyArgs(args); err != nil { 622 return nil, err 623 } 624 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString, types.ETInt) 625 if err != nil { 626 return nil, err 627 } 628 bf.tp.Flen = allegrosql.MaxBlobWidth 629 SetBinFlagOrBinStr(args[0].GetType(), bf.tp) 630 valStr, _ := ctx.GetStochastikVars().GetSystemVar(variable.MaxAllowedPacket) 631 maxAllowedPacket, err := strconv.ParseUint(valStr, 10, 64) 632 if err != nil { 633 return nil, errors.Trace(err) 634 } 635 sig := &builtinRepeatSig{bf, maxAllowedPacket} 636 return sig, nil 637 } 638 639 type builtinRepeatSig struct { 640 baseBuiltinFunc 641 maxAllowedPacket uint64 642 } 643 644 func (b *builtinRepeatSig) Clone() builtinFunc { 645 newSig := &builtinRepeatSig{} 646 newSig.cloneFrom(&b.baseBuiltinFunc) 647 newSig.maxAllowedPacket = b.maxAllowedPacket 648 return newSig 649 } 650 651 // evalString evals a builtinRepeatSig. 652 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_repeat 653 func (b *builtinRepeatSig) evalString(event chunk.Event) (d string, isNull bool, err error) { 654 str, isNull, err := b.args[0].EvalString(b.ctx, event) 655 if isNull || err != nil { 656 return "", isNull, err 657 } 658 byteLength := len(str) 659 660 num, isNull, err := b.args[1].EvalInt(b.ctx, event) 661 if isNull || err != nil { 662 return "", isNull, err 663 } 664 if num < 1 { 665 return "", false, nil 666 } 667 if num > math.MaxInt32 { 668 num = math.MaxInt32 669 } 670 671 if uint64(byteLength)*uint64(num) > b.maxAllowedPacket { 672 b.ctx.GetStochastikVars().StmtCtx.AppendWarning(errWarnAllowedPacketOverflowed.GenWithStackByArgs("repeat", b.maxAllowedPacket)) 673 return "", true, nil 674 } 675 676 if int64(byteLength) > int64(b.tp.Flen)/num { 677 return "", true, nil 678 } 679 return strings.Repeat(str, int(num)), false, nil 680 } 681 682 type lowerFunctionClass struct { 683 baseFunctionClass 684 } 685 686 func (c *lowerFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 687 if err := c.verifyArgs(args); err != nil { 688 return nil, err 689 } 690 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString) 691 if err != nil { 692 return nil, err 693 } 694 argTp := args[0].GetType() 695 bf.tp.Flen = argTp.Flen 696 SetBinFlagOrBinStr(argTp, bf.tp) 697 sig := &builtinLowerSig{bf} 698 sig.setPbCode(fidelpb.ScalarFuncSig_Lower) 699 return sig, nil 700 } 701 702 type builtinLowerSig struct { 703 baseBuiltinFunc 704 } 705 706 func (b *builtinLowerSig) Clone() builtinFunc { 707 newSig := &builtinLowerSig{} 708 newSig.cloneFrom(&b.baseBuiltinFunc) 709 return newSig 710 } 711 712 // evalString evals a builtinLowerSig. 713 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_lower 714 func (b *builtinLowerSig) evalString(event chunk.Event) (d string, isNull bool, err error) { 715 d, isNull, err = b.args[0].EvalString(b.ctx, event) 716 if isNull || err != nil { 717 return d, isNull, err 718 } 719 720 if types.IsBinaryStr(b.args[0].GetType()) { 721 return d, false, nil 722 } 723 724 return strings.ToLower(d), false, nil 725 } 726 727 type reverseFunctionClass struct { 728 baseFunctionClass 729 } 730 731 func (c *reverseFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 732 if err := c.verifyArgs(args); err != nil { 733 return nil, err 734 } 735 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString) 736 if err != nil { 737 return nil, err 738 } 739 retTp := *args[0].GetType() 740 retTp.Tp = allegrosql.TypeVarString 741 retTp.Decimal = types.UnspecifiedLength 742 bf.tp = &retTp 743 var sig builtinFunc 744 if types.IsBinaryStr(bf.tp) { 745 sig = &builtinReverseSig{bf} 746 sig.setPbCode(fidelpb.ScalarFuncSig_Reverse) 747 } else { 748 sig = &builtinReverseUTF8Sig{bf} 749 sig.setPbCode(fidelpb.ScalarFuncSig_ReverseUTF8) 750 } 751 return sig, nil 752 } 753 754 type builtinReverseSig struct { 755 baseBuiltinFunc 756 } 757 758 func (b *builtinReverseSig) Clone() builtinFunc { 759 newSig := &builtinReverseSig{} 760 newSig.cloneFrom(&b.baseBuiltinFunc) 761 return newSig 762 } 763 764 // evalString evals a REVERSE(str). 765 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_reverse 766 func (b *builtinReverseSig) evalString(event chunk.Event) (string, bool, error) { 767 str, isNull, err := b.args[0].EvalString(b.ctx, event) 768 if isNull || err != nil { 769 return "", true, err 770 } 771 reversed := reverseBytes([]byte(str)) 772 return string(reversed), false, nil 773 } 774 775 type builtinReverseUTF8Sig struct { 776 baseBuiltinFunc 777 } 778 779 func (b *builtinReverseUTF8Sig) Clone() builtinFunc { 780 newSig := &builtinReverseUTF8Sig{} 781 newSig.cloneFrom(&b.baseBuiltinFunc) 782 return newSig 783 } 784 785 // evalString evals a REVERSE(str). 786 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_reverse 787 func (b *builtinReverseUTF8Sig) evalString(event chunk.Event) (string, bool, error) { 788 str, isNull, err := b.args[0].EvalString(b.ctx, event) 789 if isNull || err != nil { 790 return "", true, err 791 } 792 reversed := reverseRunes([]rune(str)) 793 return string(reversed), false, nil 794 } 795 796 type spaceFunctionClass struct { 797 baseFunctionClass 798 } 799 800 func (c *spaceFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 801 if err := c.verifyArgs(args); err != nil { 802 return nil, err 803 } 804 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETInt) 805 if err != nil { 806 return nil, err 807 } 808 bf.tp.Charset, bf.tp.DefCauslate = ctx.GetStochastikVars().GetCharsetInfo() 809 bf.tp.Flen = allegrosql.MaxBlobWidth 810 valStr, _ := ctx.GetStochastikVars().GetSystemVar(variable.MaxAllowedPacket) 811 maxAllowedPacket, err := strconv.ParseUint(valStr, 10, 64) 812 if err != nil { 813 return nil, errors.Trace(err) 814 } 815 sig := &builtinSpaceSig{bf, maxAllowedPacket} 816 sig.setPbCode(fidelpb.ScalarFuncSig_Space) 817 return sig, nil 818 } 819 820 type builtinSpaceSig struct { 821 baseBuiltinFunc 822 maxAllowedPacket uint64 823 } 824 825 func (b *builtinSpaceSig) Clone() builtinFunc { 826 newSig := &builtinSpaceSig{} 827 newSig.cloneFrom(&b.baseBuiltinFunc) 828 newSig.maxAllowedPacket = b.maxAllowedPacket 829 return newSig 830 } 831 832 // evalString evals a builtinSpaceSig. 833 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_space 834 func (b *builtinSpaceSig) evalString(event chunk.Event) (d string, isNull bool, err error) { 835 var x int64 836 837 x, isNull, err = b.args[0].EvalInt(b.ctx, event) 838 if isNull || err != nil { 839 return d, isNull, err 840 } 841 if x < 0 { 842 x = 0 843 } 844 if uint64(x) > b.maxAllowedPacket { 845 b.ctx.GetStochastikVars().StmtCtx.AppendWarning(errWarnAllowedPacketOverflowed.GenWithStackByArgs("space", b.maxAllowedPacket)) 846 return d, true, nil 847 } 848 if x > allegrosql.MaxBlobWidth { 849 return d, true, nil 850 } 851 return strings.Repeat(" ", int(x)), false, nil 852 } 853 854 type upperFunctionClass struct { 855 baseFunctionClass 856 } 857 858 func (c *upperFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 859 if err := c.verifyArgs(args); err != nil { 860 return nil, err 861 } 862 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString) 863 if err != nil { 864 return nil, err 865 } 866 argTp := args[0].GetType() 867 bf.tp.Flen = argTp.Flen 868 SetBinFlagOrBinStr(argTp, bf.tp) 869 var sig builtinFunc 870 if types.IsBinaryStr(argTp) { 871 sig = &builtinUpperSig{bf} 872 sig.setPbCode(fidelpb.ScalarFuncSig_Upper) 873 } else { 874 sig = &builtinUpperUTF8Sig{bf} 875 sig.setPbCode(fidelpb.ScalarFuncSig_UpperUTF8) 876 } 877 return sig, nil 878 } 879 880 type builtinUpperUTF8Sig struct { 881 baseBuiltinFunc 882 } 883 884 func (b *builtinUpperUTF8Sig) Clone() builtinFunc { 885 newSig := &builtinUpperUTF8Sig{} 886 newSig.cloneFrom(&b.baseBuiltinFunc) 887 return newSig 888 } 889 890 // evalString evals a builtinUpperUTF8Sig. 891 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_upper 892 func (b *builtinUpperUTF8Sig) evalString(event chunk.Event) (d string, isNull bool, err error) { 893 d, isNull, err = b.args[0].EvalString(b.ctx, event) 894 if isNull || err != nil { 895 return d, isNull, err 896 } 897 898 return strings.ToUpper(d), false, nil 899 } 900 901 type builtinUpperSig struct { 902 baseBuiltinFunc 903 } 904 905 func (b *builtinUpperSig) Clone() builtinFunc { 906 newSig := &builtinUpperSig{} 907 newSig.cloneFrom(&b.baseBuiltinFunc) 908 return newSig 909 } 910 911 // evalString evals a builtinUpperSig. 912 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_upper 913 func (b *builtinUpperSig) evalString(event chunk.Event) (d string, isNull bool, err error) { 914 d, isNull, err = b.args[0].EvalString(b.ctx, event) 915 if isNull || err != nil { 916 return d, isNull, err 917 } 918 919 return d, false, nil 920 } 921 922 type strcmpFunctionClass struct { 923 baseFunctionClass 924 } 925 926 func (c *strcmpFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 927 if err := c.verifyArgs(args); err != nil { 928 return nil, err 929 } 930 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETInt, types.ETString, types.ETString) 931 if err != nil { 932 return nil, err 933 } 934 bf.tp.Flen = 2 935 types.SetBinChsClnFlag(bf.tp) 936 sig := &builtinStrcmpSig{bf} 937 sig.setPbCode(fidelpb.ScalarFuncSig_Strcmp) 938 return sig, nil 939 } 940 941 type builtinStrcmpSig struct { 942 baseBuiltinFunc 943 } 944 945 func (b *builtinStrcmpSig) Clone() builtinFunc { 946 newSig := &builtinStrcmpSig{} 947 newSig.cloneFrom(&b.baseBuiltinFunc) 948 return newSig 949 } 950 951 // evalInt evals a builtinStrcmpSig. 952 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-comparison-functions.html 953 func (b *builtinStrcmpSig) evalInt(event chunk.Event) (int64, bool, error) { 954 var ( 955 left, right string 956 isNull bool 957 err error 958 ) 959 960 left, isNull, err = b.args[0].EvalString(b.ctx, event) 961 if isNull || err != nil { 962 return 0, isNull, err 963 } 964 right, isNull, err = b.args[1].EvalString(b.ctx, event) 965 if isNull || err != nil { 966 return 0, isNull, err 967 } 968 res := types.CompareString(left, right, b.defCauslation) 969 return int64(res), false, nil 970 } 971 972 type replaceFunctionClass struct { 973 baseFunctionClass 974 } 975 976 func (c *replaceFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 977 if err := c.verifyArgs(args); err != nil { 978 return nil, err 979 } 980 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString, types.ETString, types.ETString) 981 if err != nil { 982 return nil, err 983 } 984 bf.tp.Flen = c.fixLength(args) 985 for _, a := range args { 986 SetBinFlagOrBinStr(a.GetType(), bf.tp) 987 } 988 sig := &builtinReplaceSig{bf} 989 sig.setPbCode(fidelpb.ScalarFuncSig_Replace) 990 return sig, nil 991 } 992 993 // fixLength calculate the Flen of the return type. 994 func (c *replaceFunctionClass) fixLength(args []Expression) int { 995 charLen := args[0].GetType().Flen 996 oldStrLen := args[1].GetType().Flen 997 diff := args[2].GetType().Flen - oldStrLen 998 if diff > 0 && oldStrLen > 0 { 999 charLen += (charLen / oldStrLen) * diff 1000 } 1001 return charLen 1002 } 1003 1004 type builtinReplaceSig struct { 1005 baseBuiltinFunc 1006 } 1007 1008 func (b *builtinReplaceSig) Clone() builtinFunc { 1009 newSig := &builtinReplaceSig{} 1010 newSig.cloneFrom(&b.baseBuiltinFunc) 1011 return newSig 1012 } 1013 1014 // evalString evals a builtinReplaceSig. 1015 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_replace 1016 func (b *builtinReplaceSig) evalString(event chunk.Event) (d string, isNull bool, err error) { 1017 var str, oldStr, newStr string 1018 1019 str, isNull, err = b.args[0].EvalString(b.ctx, event) 1020 if isNull || err != nil { 1021 return d, isNull, err 1022 } 1023 oldStr, isNull, err = b.args[1].EvalString(b.ctx, event) 1024 if isNull || err != nil { 1025 return d, isNull, err 1026 } 1027 newStr, isNull, err = b.args[2].EvalString(b.ctx, event) 1028 if isNull || err != nil { 1029 return d, isNull, err 1030 } 1031 if oldStr == "" { 1032 return str, false, nil 1033 } 1034 return strings.Replace(str, oldStr, newStr, -1), false, nil 1035 } 1036 1037 type convertFunctionClass struct { 1038 baseFunctionClass 1039 } 1040 1041 func (c *convertFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 1042 if err := c.verifyArgs(args); err != nil { 1043 return nil, err 1044 } 1045 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString, types.ETString) 1046 if err != nil { 1047 return nil, err 1048 } 1049 1050 charsetArg, ok := args[1].(*Constant) 1051 if !ok { 1052 // `args[1]` is limited by BerolinaSQL to be a constant string, 1053 // should never go into here. 1054 return nil, errIncorrectArgs.GenWithStackByArgs("charset") 1055 } 1056 transcodingName := charsetArg.Value.GetString() 1057 bf.tp.Charset = strings.ToLower(transcodingName) 1058 // Quoted about the behavior of syntax CONVERT(expr, type) to CHAR(): 1059 // In all cases, the string has the default defCauslation for the character set. 1060 // See https://dev.allegrosql.com/doc/refman/5.7/en/cast-functions.html#function_convert 1061 // Here in syntax CONVERT(expr USING transcoding_name), behavior is kept the same, 1062 // picking the default defCauslation of target charset. 1063 bf.tp.DefCauslate, err = charset.GetDefaultDefCauslation(bf.tp.Charset) 1064 if err != nil { 1065 return nil, errUnknownCharacterSet.GenWithStackByArgs(transcodingName) 1066 } 1067 // Result will be a binary string if converts charset to BINARY. 1068 // See https://dev.allegrosql.com/doc/refman/5.7/en/charset-binary-set.html 1069 if types.IsBinaryStr(bf.tp) { 1070 types.SetBinChsClnFlag(bf.tp) 1071 } else { 1072 bf.tp.Flag &= ^allegrosql.BinaryFlag 1073 } 1074 1075 bf.tp.Flen = allegrosql.MaxBlobWidth 1076 sig := &builtinConvertSig{bf} 1077 sig.setPbCode(fidelpb.ScalarFuncSig_Convert) 1078 return sig, nil 1079 } 1080 1081 type builtinConvertSig struct { 1082 baseBuiltinFunc 1083 } 1084 1085 func (b *builtinConvertSig) Clone() builtinFunc { 1086 newSig := &builtinConvertSig{} 1087 newSig.cloneFrom(&b.baseBuiltinFunc) 1088 return newSig 1089 } 1090 1091 // evalString evals CONVERT(expr USING transcoding_name). 1092 // Syntax CONVERT(expr, type) is parsed as cast expr so not handled here. 1093 // See https://dev.allegrosql.com/doc/refman/5.7/en/cast-functions.html#function_convert 1094 func (b *builtinConvertSig) evalString(event chunk.Event) (string, bool, error) { 1095 expr, isNull, err := b.args[0].EvalString(b.ctx, event) 1096 if isNull || err != nil { 1097 return "", true, err 1098 } 1099 1100 // Since charset is already validated and set from getFunction(), there's no 1101 // need to get charset from args again. 1102 encoding, _ := charset.Lookup(b.tp.Charset) 1103 // However, if `b.tp.Charset` is abnormally set to a wrong charset, we still 1104 // return with error. 1105 if encoding == nil { 1106 return "", true, errUnknownCharacterSet.GenWithStackByArgs(b.tp.Charset) 1107 } 1108 1109 target, _, err := transform.String(encoding.NewCausetDecoder(), expr) 1110 return target, err != nil, err 1111 } 1112 1113 type substringFunctionClass struct { 1114 baseFunctionClass 1115 } 1116 1117 func (c *substringFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 1118 if err := c.verifyArgs(args); err != nil { 1119 return nil, err 1120 } 1121 argTps := []types.EvalType{types.ETString, types.ETInt} 1122 if len(args) == 3 { 1123 argTps = append(argTps, types.ETInt) 1124 } 1125 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, argTps...) 1126 if err != nil { 1127 return nil, err 1128 } 1129 1130 argType := args[0].GetType() 1131 bf.tp.Flen = argType.Flen 1132 SetBinFlagOrBinStr(argType, bf.tp) 1133 1134 var sig builtinFunc 1135 switch { 1136 case len(args) == 3 && types.IsBinaryStr(argType): 1137 sig = &builtinSubstring3ArgsSig{bf} 1138 sig.setPbCode(fidelpb.ScalarFuncSig_Substring3Args) 1139 case len(args) == 3: 1140 sig = &builtinSubstring3ArgsUTF8Sig{bf} 1141 sig.setPbCode(fidelpb.ScalarFuncSig_Substring3ArgsUTF8) 1142 case len(args) == 2 && types.IsBinaryStr(argType): 1143 sig = &builtinSubstring2ArgsSig{bf} 1144 sig.setPbCode(fidelpb.ScalarFuncSig_Substring2Args) 1145 case len(args) == 2: 1146 sig = &builtinSubstring2ArgsUTF8Sig{bf} 1147 sig.setPbCode(fidelpb.ScalarFuncSig_Substring2ArgsUTF8) 1148 default: 1149 // Should never happens. 1150 return nil, errors.Errorf("SUBSTR invalid arg length, expect 2 or 3 but got: %v", len(args)) 1151 } 1152 return sig, nil 1153 } 1154 1155 type builtinSubstring2ArgsSig struct { 1156 baseBuiltinFunc 1157 } 1158 1159 func (b *builtinSubstring2ArgsSig) Clone() builtinFunc { 1160 newSig := &builtinSubstring2ArgsSig{} 1161 newSig.cloneFrom(&b.baseBuiltinFunc) 1162 return newSig 1163 } 1164 1165 // evalString evals SUBSTR(str,pos), SUBSTR(str FROM pos), SUBSTR() is a synonym for SUBSTRING(). 1166 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_substr 1167 func (b *builtinSubstring2ArgsSig) evalString(event chunk.Event) (string, bool, error) { 1168 str, isNull, err := b.args[0].EvalString(b.ctx, event) 1169 if isNull || err != nil { 1170 return "", true, err 1171 } 1172 pos, isNull, err := b.args[1].EvalInt(b.ctx, event) 1173 if isNull || err != nil { 1174 return "", true, err 1175 } 1176 length := int64(len(str)) 1177 if pos < 0 { 1178 pos += length 1179 } else { 1180 pos-- 1181 } 1182 if pos > length || pos < 0 { 1183 pos = length 1184 } 1185 return str[pos:], false, nil 1186 } 1187 1188 type builtinSubstring2ArgsUTF8Sig struct { 1189 baseBuiltinFunc 1190 } 1191 1192 func (b *builtinSubstring2ArgsUTF8Sig) Clone() builtinFunc { 1193 newSig := &builtinSubstring2ArgsUTF8Sig{} 1194 newSig.cloneFrom(&b.baseBuiltinFunc) 1195 return newSig 1196 } 1197 1198 // evalString evals SUBSTR(str,pos), SUBSTR(str FROM pos), SUBSTR() is a synonym for SUBSTRING(). 1199 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_substr 1200 func (b *builtinSubstring2ArgsUTF8Sig) evalString(event chunk.Event) (string, bool, error) { 1201 str, isNull, err := b.args[0].EvalString(b.ctx, event) 1202 if isNull || err != nil { 1203 return "", true, err 1204 } 1205 pos, isNull, err := b.args[1].EvalInt(b.ctx, event) 1206 if isNull || err != nil { 1207 return "", true, err 1208 } 1209 runes := []rune(str) 1210 length := int64(len(runes)) 1211 if pos < 0 { 1212 pos += length 1213 } else { 1214 pos-- 1215 } 1216 if pos > length || pos < 0 { 1217 pos = length 1218 } 1219 return string(runes[pos:]), false, nil 1220 } 1221 1222 type builtinSubstring3ArgsSig struct { 1223 baseBuiltinFunc 1224 } 1225 1226 func (b *builtinSubstring3ArgsSig) Clone() builtinFunc { 1227 newSig := &builtinSubstring3ArgsSig{} 1228 newSig.cloneFrom(&b.baseBuiltinFunc) 1229 return newSig 1230 } 1231 1232 // evalString evals SUBSTR(str,pos,len), SUBSTR(str FROM pos FOR len), SUBSTR() is a synonym for SUBSTRING(). 1233 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_substr 1234 func (b *builtinSubstring3ArgsSig) evalString(event chunk.Event) (string, bool, error) { 1235 str, isNull, err := b.args[0].EvalString(b.ctx, event) 1236 if isNull || err != nil { 1237 return "", true, err 1238 } 1239 pos, isNull, err := b.args[1].EvalInt(b.ctx, event) 1240 if isNull || err != nil { 1241 return "", true, err 1242 } 1243 length, isNull, err := b.args[2].EvalInt(b.ctx, event) 1244 if isNull || err != nil { 1245 return "", true, err 1246 } 1247 byteLen := int64(len(str)) 1248 if pos < 0 { 1249 pos += byteLen 1250 } else { 1251 pos-- 1252 } 1253 if pos > byteLen || pos < 0 { 1254 pos = byteLen 1255 } 1256 end := pos + length 1257 if end < pos { 1258 return "", false, nil 1259 } else if end < byteLen { 1260 return str[pos:end], false, nil 1261 } 1262 return str[pos:], false, nil 1263 } 1264 1265 type builtinSubstring3ArgsUTF8Sig struct { 1266 baseBuiltinFunc 1267 } 1268 1269 func (b *builtinSubstring3ArgsUTF8Sig) Clone() builtinFunc { 1270 newSig := &builtinSubstring3ArgsUTF8Sig{} 1271 newSig.cloneFrom(&b.baseBuiltinFunc) 1272 return newSig 1273 } 1274 1275 // evalString evals SUBSTR(str,pos,len), SUBSTR(str FROM pos FOR len), SUBSTR() is a synonym for SUBSTRING(). 1276 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_substr 1277 func (b *builtinSubstring3ArgsUTF8Sig) evalString(event chunk.Event) (string, bool, error) { 1278 str, isNull, err := b.args[0].EvalString(b.ctx, event) 1279 if isNull || err != nil { 1280 return "", true, err 1281 } 1282 pos, isNull, err := b.args[1].EvalInt(b.ctx, event) 1283 if isNull || err != nil { 1284 return "", true, err 1285 } 1286 length, isNull, err := b.args[2].EvalInt(b.ctx, event) 1287 if isNull || err != nil { 1288 return "", true, err 1289 } 1290 runes := []rune(str) 1291 numRunes := int64(len(runes)) 1292 if pos < 0 { 1293 pos += numRunes 1294 } else { 1295 pos-- 1296 } 1297 if pos > numRunes || pos < 0 { 1298 pos = numRunes 1299 } 1300 end := pos + length 1301 if end < pos { 1302 return "", false, nil 1303 } else if end < numRunes { 1304 return string(runes[pos:end]), false, nil 1305 } 1306 return string(runes[pos:]), false, nil 1307 } 1308 1309 type substringIndexFunctionClass struct { 1310 baseFunctionClass 1311 } 1312 1313 func (c *substringIndexFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 1314 if err := c.verifyArgs(args); err != nil { 1315 return nil, err 1316 } 1317 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString, types.ETString, types.ETInt) 1318 if err != nil { 1319 return nil, err 1320 } 1321 argType := args[0].GetType() 1322 bf.tp.Flen = argType.Flen 1323 SetBinFlagOrBinStr(argType, bf.tp) 1324 sig := &builtinSubstringIndexSig{bf} 1325 sig.setPbCode(fidelpb.ScalarFuncSig_SubstringIndex) 1326 return sig, nil 1327 } 1328 1329 type builtinSubstringIndexSig struct { 1330 baseBuiltinFunc 1331 } 1332 1333 func (b *builtinSubstringIndexSig) Clone() builtinFunc { 1334 newSig := &builtinSubstringIndexSig{} 1335 newSig.cloneFrom(&b.baseBuiltinFunc) 1336 return newSig 1337 } 1338 1339 // evalString evals a builtinSubstringIndexSig. 1340 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_substring-index 1341 func (b *builtinSubstringIndexSig) evalString(event chunk.Event) (d string, isNull bool, err error) { 1342 var ( 1343 str, delim string 1344 count int64 1345 ) 1346 str, isNull, err = b.args[0].EvalString(b.ctx, event) 1347 if isNull || err != nil { 1348 return d, isNull, err 1349 } 1350 delim, isNull, err = b.args[1].EvalString(b.ctx, event) 1351 if isNull || err != nil { 1352 return d, isNull, err 1353 } 1354 count, isNull, err = b.args[2].EvalInt(b.ctx, event) 1355 if isNull || err != nil { 1356 return d, isNull, err 1357 } 1358 if len(delim) == 0 { 1359 return "", false, nil 1360 } 1361 1362 strs := strings.Split(str, delim) 1363 start, end := int64(0), int64(len(strs)) 1364 if count > 0 { 1365 // If count is positive, everything to the left of the final delimiter (counting from the left) is returned. 1366 if count < end { 1367 end = count 1368 } 1369 } else { 1370 // If count is negative, everything to the right of the final delimiter (counting from the right) is returned. 1371 count = -count 1372 if count < 0 { 1373 // -count overflows max int64, returns an empty string. 1374 return "", false, nil 1375 } 1376 1377 if count < end { 1378 start = end - count 1379 } 1380 } 1381 substrs := strs[start:end] 1382 return strings.Join(substrs, delim), false, nil 1383 } 1384 1385 type locateFunctionClass struct { 1386 baseFunctionClass 1387 } 1388 1389 func (c *locateFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 1390 if err := c.verifyArgs(args); err != nil { 1391 return nil, err 1392 } 1393 hasStartPos, argTps := len(args) == 3, []types.EvalType{types.ETString, types.ETString} 1394 if hasStartPos { 1395 argTps = append(argTps, types.ETInt) 1396 } 1397 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETInt, argTps...) 1398 if err != nil { 1399 return nil, err 1400 } 1401 var sig builtinFunc 1402 // Locate is multibyte safe. 1403 useBinary := bf.defCauslation == charset.DefCauslationBin 1404 switch { 1405 case hasStartPos && useBinary: 1406 sig = &builtinLocate3ArgsSig{bf} 1407 sig.setPbCode(fidelpb.ScalarFuncSig_Locate3Args) 1408 case hasStartPos: 1409 sig = &builtinLocate3ArgsUTF8Sig{bf} 1410 sig.setPbCode(fidelpb.ScalarFuncSig_Locate3ArgsUTF8) 1411 case useBinary: 1412 sig = &builtinLocate2ArgsSig{bf} 1413 sig.setPbCode(fidelpb.ScalarFuncSig_Locate2Args) 1414 default: 1415 sig = &builtinLocate2ArgsUTF8Sig{bf} 1416 sig.setPbCode(fidelpb.ScalarFuncSig_Locate2ArgsUTF8) 1417 } 1418 return sig, nil 1419 } 1420 1421 type builtinLocate2ArgsSig struct { 1422 baseBuiltinFunc 1423 } 1424 1425 func (b *builtinLocate2ArgsSig) Clone() builtinFunc { 1426 newSig := &builtinLocate2ArgsSig{} 1427 newSig.cloneFrom(&b.baseBuiltinFunc) 1428 return newSig 1429 } 1430 1431 // evalInt evals LOCATE(substr,str), case-sensitive. 1432 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_locate 1433 func (b *builtinLocate2ArgsSig) evalInt(event chunk.Event) (int64, bool, error) { 1434 subStr, isNull, err := b.args[0].EvalString(b.ctx, event) 1435 if isNull || err != nil { 1436 return 0, isNull, err 1437 } 1438 str, isNull, err := b.args[1].EvalString(b.ctx, event) 1439 if isNull || err != nil { 1440 return 0, isNull, err 1441 } 1442 subStrLen := len(subStr) 1443 if subStrLen == 0 { 1444 return 1, false, nil 1445 } 1446 ret, idx := 0, strings.Index(str, subStr) 1447 if idx != -1 { 1448 ret = idx + 1 1449 } 1450 return int64(ret), false, nil 1451 } 1452 1453 type builtinLocate2ArgsUTF8Sig struct { 1454 baseBuiltinFunc 1455 } 1456 1457 func (b *builtinLocate2ArgsUTF8Sig) Clone() builtinFunc { 1458 newSig := &builtinLocate2ArgsUTF8Sig{} 1459 newSig.cloneFrom(&b.baseBuiltinFunc) 1460 return newSig 1461 } 1462 1463 // evalInt evals LOCATE(substr,str). 1464 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_locate 1465 func (b *builtinLocate2ArgsUTF8Sig) evalInt(event chunk.Event) (int64, bool, error) { 1466 subStr, isNull, err := b.args[0].EvalString(b.ctx, event) 1467 if isNull || err != nil { 1468 return 0, isNull, err 1469 } 1470 str, isNull, err := b.args[1].EvalString(b.ctx, event) 1471 if isNull || err != nil { 1472 return 0, isNull, err 1473 } 1474 if int64(len([]rune(subStr))) == 0 { 1475 return 1, false, nil 1476 } 1477 if defCauslate.IsCIDefCauslation(b.defCauslation) { 1478 str = strings.ToLower(str) 1479 subStr = strings.ToLower(subStr) 1480 } 1481 ret, idx := 0, strings.Index(str, subStr) 1482 if idx != -1 { 1483 ret = utf8.RuneCountInString(str[:idx]) + 1 1484 } 1485 return int64(ret), false, nil 1486 } 1487 1488 type builtinLocate3ArgsSig struct { 1489 baseBuiltinFunc 1490 } 1491 1492 func (b *builtinLocate3ArgsSig) Clone() builtinFunc { 1493 newSig := &builtinLocate3ArgsSig{} 1494 newSig.cloneFrom(&b.baseBuiltinFunc) 1495 return newSig 1496 } 1497 1498 // evalInt evals LOCATE(substr,str,pos), case-sensitive. 1499 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_locate 1500 func (b *builtinLocate3ArgsSig) evalInt(event chunk.Event) (int64, bool, error) { 1501 subStr, isNull, err := b.args[0].EvalString(b.ctx, event) 1502 if isNull || err != nil { 1503 return 0, isNull, err 1504 } 1505 str, isNull, err := b.args[1].EvalString(b.ctx, event) 1506 if isNull || err != nil { 1507 return 0, isNull, err 1508 } 1509 pos, isNull, err := b.args[2].EvalInt(b.ctx, event) 1510 // Transfer the argument which starts from 1 to real index which starts from 0. 1511 pos-- 1512 if isNull || err != nil { 1513 return 0, isNull, err 1514 } 1515 subStrLen := len(subStr) 1516 if pos < 0 || pos > int64(len(str)-subStrLen) { 1517 return 0, false, nil 1518 } else if subStrLen == 0 { 1519 return pos + 1, false, nil 1520 } 1521 slice := str[pos:] 1522 idx := strings.Index(slice, subStr) 1523 if idx != -1 { 1524 return pos + int64(idx) + 1, false, nil 1525 } 1526 return 0, false, nil 1527 } 1528 1529 type builtinLocate3ArgsUTF8Sig struct { 1530 baseBuiltinFunc 1531 } 1532 1533 func (b *builtinLocate3ArgsUTF8Sig) Clone() builtinFunc { 1534 newSig := &builtinLocate3ArgsUTF8Sig{} 1535 newSig.cloneFrom(&b.baseBuiltinFunc) 1536 return newSig 1537 } 1538 1539 // evalInt evals LOCATE(substr,str,pos). 1540 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_locate 1541 func (b *builtinLocate3ArgsUTF8Sig) evalInt(event chunk.Event) (int64, bool, error) { 1542 subStr, isNull, err := b.args[0].EvalString(b.ctx, event) 1543 if isNull || err != nil { 1544 return 0, isNull, err 1545 } 1546 str, isNull, err := b.args[1].EvalString(b.ctx, event) 1547 if isNull || err != nil { 1548 return 0, isNull, err 1549 } 1550 if defCauslate.IsCIDefCauslation(b.defCauslation) { 1551 subStr = strings.ToLower(subStr) 1552 str = strings.ToLower(str) 1553 } 1554 pos, isNull, err := b.args[2].EvalInt(b.ctx, event) 1555 // Transfer the argument which starts from 1 to real index which starts from 0. 1556 pos-- 1557 if isNull || err != nil { 1558 return 0, isNull, err 1559 } 1560 subStrLen := len([]rune(subStr)) 1561 if pos < 0 || pos > int64(len([]rune(str))-subStrLen) { 1562 return 0, false, nil 1563 } else if subStrLen == 0 { 1564 return pos + 1, false, nil 1565 } 1566 slice := string([]rune(str)[pos:]) 1567 idx := strings.Index(slice, subStr) 1568 if idx != -1 { 1569 return pos + int64(utf8.RuneCountInString(slice[:idx])) + 1, false, nil 1570 } 1571 return 0, false, nil 1572 } 1573 1574 type hexFunctionClass struct { 1575 baseFunctionClass 1576 } 1577 1578 func (c *hexFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 1579 if err := c.verifyArgs(args); err != nil { 1580 return nil, err 1581 } 1582 1583 argTp := args[0].GetType().EvalType() 1584 switch argTp { 1585 case types.ETString, types.ETDatetime, types.ETTimestamp, types.ETDuration, types.ETJson: 1586 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString) 1587 if err != nil { 1588 return nil, err 1589 } 1590 bf.tp.Charset, bf.tp.DefCauslate = ctx.GetStochastikVars().GetCharsetInfo() 1591 // Use UTF-8 as default 1592 bf.tp.Flen = args[0].GetType().Flen * 3 * 2 1593 sig := &builtinHexStrArgSig{bf} 1594 sig.setPbCode(fidelpb.ScalarFuncSig_HexStrArg) 1595 return sig, nil 1596 case types.ETInt, types.ETReal, types.ETDecimal: 1597 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETInt) 1598 if err != nil { 1599 return nil, err 1600 } 1601 bf.tp.Flen = args[0].GetType().Flen * 2 1602 bf.tp.Charset, bf.tp.DefCauslate = ctx.GetStochastikVars().GetCharsetInfo() 1603 sig := &builtinHexIntArgSig{bf} 1604 sig.setPbCode(fidelpb.ScalarFuncSig_HexIntArg) 1605 return sig, nil 1606 default: 1607 return nil, errors.Errorf("Hex invalid args, need int or string but get %T", args[0].GetType()) 1608 } 1609 } 1610 1611 type builtinHexStrArgSig struct { 1612 baseBuiltinFunc 1613 } 1614 1615 func (b *builtinHexStrArgSig) Clone() builtinFunc { 1616 newSig := &builtinHexStrArgSig{} 1617 newSig.cloneFrom(&b.baseBuiltinFunc) 1618 return newSig 1619 } 1620 1621 // evalString evals a builtinHexStrArgSig, corresponding to hex(str) 1622 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_hex 1623 func (b *builtinHexStrArgSig) evalString(event chunk.Event) (string, bool, error) { 1624 d, isNull, err := b.args[0].EvalString(b.ctx, event) 1625 if isNull || err != nil { 1626 return d, isNull, err 1627 } 1628 return strings.ToUpper(hex.EncodeToString(replog.Slice(d))), false, nil 1629 } 1630 1631 type builtinHexIntArgSig struct { 1632 baseBuiltinFunc 1633 } 1634 1635 func (b *builtinHexIntArgSig) Clone() builtinFunc { 1636 newSig := &builtinHexIntArgSig{} 1637 newSig.cloneFrom(&b.baseBuiltinFunc) 1638 return newSig 1639 } 1640 1641 // evalString evals a builtinHexIntArgSig, corresponding to hex(N) 1642 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_hex 1643 func (b *builtinHexIntArgSig) evalString(event chunk.Event) (string, bool, error) { 1644 x, isNull, err := b.args[0].EvalInt(b.ctx, event) 1645 if isNull || err != nil { 1646 return "", isNull, err 1647 } 1648 return strings.ToUpper(fmt.Sprintf("%x", uint64(x))), false, nil 1649 } 1650 1651 type unhexFunctionClass struct { 1652 baseFunctionClass 1653 } 1654 1655 func (c *unhexFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 1656 if err := c.verifyArgs(args); err != nil { 1657 return nil, err 1658 } 1659 var retFlen int 1660 1661 if err := c.verifyArgs(args); err != nil { 1662 return nil, err 1663 } 1664 argType := args[0].GetType() 1665 argEvalTp := argType.EvalType() 1666 switch argEvalTp { 1667 case types.ETString, types.ETDatetime, types.ETTimestamp, types.ETDuration, types.ETJson: 1668 // Use UTF-8 as default charset, so there're (Flen * 3 + 1) / 2 byte-pairs 1669 retFlen = (argType.Flen*3 + 1) / 2 1670 case types.ETInt, types.ETReal, types.ETDecimal: 1671 // For number value, there're (Flen + 1) / 2 byte-pairs 1672 retFlen = (argType.Flen + 1) / 2 1673 default: 1674 return nil, errors.Errorf("Unhex invalid args, need int or string but get %s", argType) 1675 } 1676 1677 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString) 1678 if err != nil { 1679 return nil, err 1680 } 1681 bf.tp.Flen = retFlen 1682 types.SetBinChsClnFlag(bf.tp) 1683 sig := &builtinUnHexSig{bf} 1684 sig.setPbCode(fidelpb.ScalarFuncSig_UnHex) 1685 return sig, nil 1686 } 1687 1688 type builtinUnHexSig struct { 1689 baseBuiltinFunc 1690 } 1691 1692 func (b *builtinUnHexSig) Clone() builtinFunc { 1693 newSig := &builtinUnHexSig{} 1694 newSig.cloneFrom(&b.baseBuiltinFunc) 1695 return newSig 1696 } 1697 1698 // evalString evals a builtinUnHexSig. 1699 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_unhex 1700 func (b *builtinUnHexSig) evalString(event chunk.Event) (string, bool, error) { 1701 var bs []byte 1702 1703 d, isNull, err := b.args[0].EvalString(b.ctx, event) 1704 if isNull || err != nil { 1705 return d, isNull, err 1706 } 1707 // Add a '0' to the front, if the length is not the multiple of 2 1708 if len(d)%2 != 0 { 1709 d = "0" + d 1710 } 1711 bs, err = hex.DecodeString(d) 1712 if err != nil { 1713 return "", true, nil 1714 } 1715 return string(bs), false, nil 1716 } 1717 1718 const spaceChars = " " 1719 1720 type trimFunctionClass struct { 1721 baseFunctionClass 1722 } 1723 1724 // getFunction sets trim built-in function signature. 1725 // The syntax of trim in allegrosql is 'TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str), TRIM([remstr FROM] str)', 1726 // but we wil convert it into trim(str), trim(str, remstr) and trim(str, remstr, direction) in AST. 1727 func (c *trimFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 1728 if err := c.verifyArgs(args); err != nil { 1729 return nil, err 1730 } 1731 1732 switch len(args) { 1733 case 1: 1734 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString) 1735 if err != nil { 1736 return nil, err 1737 } 1738 argType := args[0].GetType() 1739 bf.tp.Flen = argType.Flen 1740 SetBinFlagOrBinStr(argType, bf.tp) 1741 sig := &builtinTrim1ArgSig{bf} 1742 sig.setPbCode(fidelpb.ScalarFuncSig_Trim1Arg) 1743 return sig, nil 1744 1745 case 2: 1746 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString, types.ETString) 1747 if err != nil { 1748 return nil, err 1749 } 1750 argType := args[0].GetType() 1751 SetBinFlagOrBinStr(argType, bf.tp) 1752 sig := &builtinTrim2ArgsSig{bf} 1753 sig.setPbCode(fidelpb.ScalarFuncSig_Trim2Args) 1754 return sig, nil 1755 1756 case 3: 1757 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString, types.ETString, types.ETInt) 1758 if err != nil { 1759 return nil, err 1760 } 1761 argType := args[0].GetType() 1762 bf.tp.Flen = argType.Flen 1763 SetBinFlagOrBinStr(argType, bf.tp) 1764 sig := &builtinTrim3ArgsSig{bf} 1765 sig.setPbCode(fidelpb.ScalarFuncSig_Trim3Args) 1766 return sig, nil 1767 1768 default: 1769 return nil, c.verifyArgs(args) 1770 } 1771 } 1772 1773 type builtinTrim1ArgSig struct { 1774 baseBuiltinFunc 1775 } 1776 1777 func (b *builtinTrim1ArgSig) Clone() builtinFunc { 1778 newSig := &builtinTrim1ArgSig{} 1779 newSig.cloneFrom(&b.baseBuiltinFunc) 1780 return newSig 1781 } 1782 1783 // evalString evals a builtinTrim1ArgSig, corresponding to trim(str) 1784 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_trim 1785 func (b *builtinTrim1ArgSig) evalString(event chunk.Event) (d string, isNull bool, err error) { 1786 d, isNull, err = b.args[0].EvalString(b.ctx, event) 1787 if isNull || err != nil { 1788 return d, isNull, err 1789 } 1790 return strings.Trim(d, spaceChars), false, nil 1791 } 1792 1793 type builtinTrim2ArgsSig struct { 1794 baseBuiltinFunc 1795 } 1796 1797 func (b *builtinTrim2ArgsSig) Clone() builtinFunc { 1798 newSig := &builtinTrim2ArgsSig{} 1799 newSig.cloneFrom(&b.baseBuiltinFunc) 1800 return newSig 1801 } 1802 1803 // evalString evals a builtinTrim2ArgsSig, corresponding to trim(str, remstr) 1804 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_trim 1805 func (b *builtinTrim2ArgsSig) evalString(event chunk.Event) (d string, isNull bool, err error) { 1806 var str, remstr string 1807 1808 str, isNull, err = b.args[0].EvalString(b.ctx, event) 1809 if isNull || err != nil { 1810 return d, isNull, err 1811 } 1812 remstr, isNull, err = b.args[1].EvalString(b.ctx, event) 1813 if isNull || err != nil { 1814 return d, isNull, err 1815 } 1816 d = trimLeft(str, remstr) 1817 d = trimRight(d, remstr) 1818 return d, false, nil 1819 } 1820 1821 type builtinTrim3ArgsSig struct { 1822 baseBuiltinFunc 1823 } 1824 1825 func (b *builtinTrim3ArgsSig) Clone() builtinFunc { 1826 newSig := &builtinTrim3ArgsSig{} 1827 newSig.cloneFrom(&b.baseBuiltinFunc) 1828 return newSig 1829 } 1830 1831 // evalString evals a builtinTrim3ArgsSig, corresponding to trim(str, remstr, direction) 1832 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_trim 1833 func (b *builtinTrim3ArgsSig) evalString(event chunk.Event) (d string, isNull bool, err error) { 1834 var ( 1835 str, remstr string 1836 x int64 1837 direction ast.TrimDirectionType 1838 isRemStrNull bool 1839 ) 1840 str, isNull, err = b.args[0].EvalString(b.ctx, event) 1841 if isNull || err != nil { 1842 return d, isNull, err 1843 } 1844 remstr, isRemStrNull, err = b.args[1].EvalString(b.ctx, event) 1845 if err != nil { 1846 return d, isNull, err 1847 } 1848 x, isNull, err = b.args[2].EvalInt(b.ctx, event) 1849 if isNull || err != nil { 1850 return d, isNull, err 1851 } 1852 direction = ast.TrimDirectionType(x) 1853 if direction == ast.TrimLeading { 1854 if isRemStrNull { 1855 d = strings.TrimLeft(str, spaceChars) 1856 } else { 1857 d = trimLeft(str, remstr) 1858 } 1859 } else if direction == ast.TrimTrailing { 1860 if isRemStrNull { 1861 d = strings.TrimRight(str, spaceChars) 1862 } else { 1863 d = trimRight(str, remstr) 1864 } 1865 } else { 1866 if isRemStrNull { 1867 d = strings.Trim(str, spaceChars) 1868 } else { 1869 d = trimLeft(str, remstr) 1870 d = trimRight(d, remstr) 1871 } 1872 } 1873 return d, false, nil 1874 } 1875 1876 type lTrimFunctionClass struct { 1877 baseFunctionClass 1878 } 1879 1880 func (c *lTrimFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 1881 if err := c.verifyArgs(args); err != nil { 1882 return nil, err 1883 } 1884 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString) 1885 if err != nil { 1886 return nil, err 1887 } 1888 argType := args[0].GetType() 1889 bf.tp.Flen = argType.Flen 1890 SetBinFlagOrBinStr(argType, bf.tp) 1891 sig := &builtinLTrimSig{bf} 1892 sig.setPbCode(fidelpb.ScalarFuncSig_LTrim) 1893 return sig, nil 1894 } 1895 1896 type builtinLTrimSig struct { 1897 baseBuiltinFunc 1898 } 1899 1900 func (b *builtinLTrimSig) Clone() builtinFunc { 1901 newSig := &builtinLTrimSig{} 1902 newSig.cloneFrom(&b.baseBuiltinFunc) 1903 return newSig 1904 } 1905 1906 // evalString evals a builtinLTrimSig 1907 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_ltrim 1908 func (b *builtinLTrimSig) evalString(event chunk.Event) (d string, isNull bool, err error) { 1909 d, isNull, err = b.args[0].EvalString(b.ctx, event) 1910 if isNull || err != nil { 1911 return d, isNull, err 1912 } 1913 return strings.TrimLeft(d, spaceChars), false, nil 1914 } 1915 1916 type rTrimFunctionClass struct { 1917 baseFunctionClass 1918 } 1919 1920 func (c *rTrimFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 1921 if err := c.verifyArgs(args); err != nil { 1922 return nil, err 1923 } 1924 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString) 1925 if err != nil { 1926 return nil, err 1927 } 1928 argType := args[0].GetType() 1929 bf.tp.Flen = argType.Flen 1930 SetBinFlagOrBinStr(argType, bf.tp) 1931 sig := &builtinRTrimSig{bf} 1932 sig.setPbCode(fidelpb.ScalarFuncSig_RTrim) 1933 return sig, nil 1934 } 1935 1936 type builtinRTrimSig struct { 1937 baseBuiltinFunc 1938 } 1939 1940 func (b *builtinRTrimSig) Clone() builtinFunc { 1941 newSig := &builtinRTrimSig{} 1942 newSig.cloneFrom(&b.baseBuiltinFunc) 1943 return newSig 1944 } 1945 1946 // evalString evals a builtinRTrimSig 1947 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_rtrim 1948 func (b *builtinRTrimSig) evalString(event chunk.Event) (d string, isNull bool, err error) { 1949 d, isNull, err = b.args[0].EvalString(b.ctx, event) 1950 if isNull || err != nil { 1951 return d, isNull, err 1952 } 1953 return strings.TrimRight(d, spaceChars), false, nil 1954 } 1955 1956 func trimLeft(str, remstr string) string { 1957 for { 1958 x := strings.TrimPrefix(str, remstr) 1959 if len(x) == len(str) { 1960 return x 1961 } 1962 str = x 1963 } 1964 } 1965 1966 func trimRight(str, remstr string) string { 1967 for { 1968 x := strings.TrimSuffix(str, remstr) 1969 if len(x) == len(str) { 1970 return x 1971 } 1972 str = x 1973 } 1974 } 1975 1976 func getFlen4LpadAndRpad(ctx stochastikctx.Context, arg Expression) int { 1977 if constant, ok := arg.(*Constant); ok { 1978 length, isNull, err := constant.EvalInt(ctx, chunk.Event{}) 1979 if err != nil { 1980 logutil.BgLogger().Error("eval `Flen` for LPAD/RPAD", zap.Error(err)) 1981 } 1982 if isNull || err != nil || length > allegrosql.MaxBlobWidth { 1983 return allegrosql.MaxBlobWidth 1984 } 1985 return int(length) 1986 } 1987 return allegrosql.MaxBlobWidth 1988 } 1989 1990 type lpadFunctionClass struct { 1991 baseFunctionClass 1992 } 1993 1994 func (c *lpadFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 1995 if err := c.verifyArgs(args); err != nil { 1996 return nil, err 1997 } 1998 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString, types.ETInt, types.ETString) 1999 if err != nil { 2000 return nil, err 2001 } 2002 bf.tp.Flen = getFlen4LpadAndRpad(bf.ctx, args[1]) 2003 SetBinFlagOrBinStr(args[0].GetType(), bf.tp) 2004 SetBinFlagOrBinStr(args[2].GetType(), bf.tp) 2005 2006 valStr, _ := ctx.GetStochastikVars().GetSystemVar(variable.MaxAllowedPacket) 2007 maxAllowedPacket, err := strconv.ParseUint(valStr, 10, 64) 2008 if err != nil { 2009 return nil, errors.Trace(err) 2010 } 2011 2012 if types.IsBinaryStr(args[0].GetType()) || types.IsBinaryStr(args[2].GetType()) { 2013 sig := &builtinLpadSig{bf, maxAllowedPacket} 2014 sig.setPbCode(fidelpb.ScalarFuncSig_Lpad) 2015 return sig, nil 2016 } 2017 if bf.tp.Flen *= 4; bf.tp.Flen > allegrosql.MaxBlobWidth { 2018 bf.tp.Flen = allegrosql.MaxBlobWidth 2019 } 2020 sig := &builtinLpadUTF8Sig{bf, maxAllowedPacket} 2021 sig.setPbCode(fidelpb.ScalarFuncSig_LpadUTF8) 2022 return sig, nil 2023 } 2024 2025 type builtinLpadSig struct { 2026 baseBuiltinFunc 2027 maxAllowedPacket uint64 2028 } 2029 2030 func (b *builtinLpadSig) Clone() builtinFunc { 2031 newSig := &builtinLpadSig{} 2032 newSig.cloneFrom(&b.baseBuiltinFunc) 2033 newSig.maxAllowedPacket = b.maxAllowedPacket 2034 return newSig 2035 } 2036 2037 // evalString evals LPAD(str,len,padstr). 2038 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_lpad 2039 func (b *builtinLpadSig) evalString(event chunk.Event) (string, bool, error) { 2040 str, isNull, err := b.args[0].EvalString(b.ctx, event) 2041 if isNull || err != nil { 2042 return "", true, err 2043 } 2044 byteLength := len(str) 2045 2046 length, isNull, err := b.args[1].EvalInt(b.ctx, event) 2047 if isNull || err != nil { 2048 return "", true, err 2049 } 2050 targetLength := int(length) 2051 2052 if uint64(targetLength) > b.maxAllowedPacket { 2053 b.ctx.GetStochastikVars().StmtCtx.AppendWarning(errWarnAllowedPacketOverflowed.GenWithStackByArgs("lpad", b.maxAllowedPacket)) 2054 return "", true, nil 2055 } 2056 2057 padStr, isNull, err := b.args[2].EvalString(b.ctx, event) 2058 if isNull || err != nil { 2059 return "", true, err 2060 } 2061 padLength := len(padStr) 2062 2063 if targetLength < 0 || targetLength > b.tp.Flen || (byteLength < targetLength && padLength == 0) { 2064 return "", true, nil 2065 } 2066 2067 if tailLen := targetLength - byteLength; tailLen > 0 { 2068 repeatCount := tailLen/padLength + 1 2069 str = strings.Repeat(padStr, repeatCount)[:tailLen] + str 2070 } 2071 return str[:targetLength], false, nil 2072 } 2073 2074 type builtinLpadUTF8Sig struct { 2075 baseBuiltinFunc 2076 maxAllowedPacket uint64 2077 } 2078 2079 func (b *builtinLpadUTF8Sig) Clone() builtinFunc { 2080 newSig := &builtinLpadUTF8Sig{} 2081 newSig.cloneFrom(&b.baseBuiltinFunc) 2082 newSig.maxAllowedPacket = b.maxAllowedPacket 2083 return newSig 2084 } 2085 2086 // evalString evals LPAD(str,len,padstr). 2087 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_lpad 2088 func (b *builtinLpadUTF8Sig) evalString(event chunk.Event) (string, bool, error) { 2089 str, isNull, err := b.args[0].EvalString(b.ctx, event) 2090 if isNull || err != nil { 2091 return "", true, err 2092 } 2093 runeLength := len([]rune(str)) 2094 2095 length, isNull, err := b.args[1].EvalInt(b.ctx, event) 2096 if isNull || err != nil { 2097 return "", true, err 2098 } 2099 targetLength := int(length) 2100 2101 if uint64(targetLength)*uint64(allegrosql.MaxBytesOfCharacter) > b.maxAllowedPacket { 2102 b.ctx.GetStochastikVars().StmtCtx.AppendWarning(errWarnAllowedPacketOverflowed.GenWithStackByArgs("lpad", b.maxAllowedPacket)) 2103 return "", true, nil 2104 } 2105 2106 padStr, isNull, err := b.args[2].EvalString(b.ctx, event) 2107 if isNull || err != nil { 2108 return "", true, err 2109 } 2110 padLength := len([]rune(padStr)) 2111 2112 if targetLength < 0 || targetLength*4 > b.tp.Flen || (runeLength < targetLength && padLength == 0) { 2113 return "", true, nil 2114 } 2115 2116 if tailLen := targetLength - runeLength; tailLen > 0 { 2117 repeatCount := tailLen/padLength + 1 2118 str = string([]rune(strings.Repeat(padStr, repeatCount))[:tailLen]) + str 2119 } 2120 return string([]rune(str)[:targetLength]), false, nil 2121 } 2122 2123 type rpadFunctionClass struct { 2124 baseFunctionClass 2125 } 2126 2127 func (c *rpadFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 2128 if err := c.verifyArgs(args); err != nil { 2129 return nil, err 2130 } 2131 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString, types.ETInt, types.ETString) 2132 if err != nil { 2133 return nil, err 2134 } 2135 bf.tp.Flen = getFlen4LpadAndRpad(bf.ctx, args[1]) 2136 SetBinFlagOrBinStr(args[0].GetType(), bf.tp) 2137 SetBinFlagOrBinStr(args[2].GetType(), bf.tp) 2138 2139 valStr, _ := ctx.GetStochastikVars().GetSystemVar(variable.MaxAllowedPacket) 2140 maxAllowedPacket, err := strconv.ParseUint(valStr, 10, 64) 2141 if err != nil { 2142 return nil, errors.Trace(err) 2143 } 2144 2145 if types.IsBinaryStr(args[0].GetType()) || types.IsBinaryStr(args[2].GetType()) { 2146 sig := &builtinRpadSig{bf, maxAllowedPacket} 2147 sig.setPbCode(fidelpb.ScalarFuncSig_Rpad) 2148 return sig, nil 2149 } 2150 if bf.tp.Flen *= 4; bf.tp.Flen > allegrosql.MaxBlobWidth { 2151 bf.tp.Flen = allegrosql.MaxBlobWidth 2152 } 2153 sig := &builtinRpadUTF8Sig{bf, maxAllowedPacket} 2154 sig.setPbCode(fidelpb.ScalarFuncSig_RpadUTF8) 2155 return sig, nil 2156 } 2157 2158 type builtinRpadSig struct { 2159 baseBuiltinFunc 2160 maxAllowedPacket uint64 2161 } 2162 2163 func (b *builtinRpadSig) Clone() builtinFunc { 2164 newSig := &builtinRpadSig{} 2165 newSig.cloneFrom(&b.baseBuiltinFunc) 2166 newSig.maxAllowedPacket = b.maxAllowedPacket 2167 return newSig 2168 } 2169 2170 // evalString evals RPAD(str,len,padstr). 2171 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_rpad 2172 func (b *builtinRpadSig) evalString(event chunk.Event) (string, bool, error) { 2173 str, isNull, err := b.args[0].EvalString(b.ctx, event) 2174 if isNull || err != nil { 2175 return "", true, err 2176 } 2177 byteLength := len(str) 2178 2179 length, isNull, err := b.args[1].EvalInt(b.ctx, event) 2180 if isNull || err != nil { 2181 return "", true, err 2182 } 2183 targetLength := int(length) 2184 if uint64(targetLength) > b.maxAllowedPacket { 2185 b.ctx.GetStochastikVars().StmtCtx.AppendWarning(errWarnAllowedPacketOverflowed.GenWithStackByArgs("rpad", b.maxAllowedPacket)) 2186 return "", true, nil 2187 } 2188 2189 padStr, isNull, err := b.args[2].EvalString(b.ctx, event) 2190 if isNull || err != nil { 2191 return "", true, err 2192 } 2193 padLength := len(padStr) 2194 2195 if targetLength < 0 || targetLength > b.tp.Flen || (byteLength < targetLength && padLength == 0) { 2196 return "", true, nil 2197 } 2198 2199 if tailLen := targetLength - byteLength; tailLen > 0 { 2200 repeatCount := tailLen/padLength + 1 2201 str = str + strings.Repeat(padStr, repeatCount) 2202 } 2203 return str[:targetLength], false, nil 2204 } 2205 2206 type builtinRpadUTF8Sig struct { 2207 baseBuiltinFunc 2208 maxAllowedPacket uint64 2209 } 2210 2211 func (b *builtinRpadUTF8Sig) Clone() builtinFunc { 2212 newSig := &builtinRpadUTF8Sig{} 2213 newSig.cloneFrom(&b.baseBuiltinFunc) 2214 newSig.maxAllowedPacket = b.maxAllowedPacket 2215 return newSig 2216 } 2217 2218 // evalString evals RPAD(str,len,padstr). 2219 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_rpad 2220 func (b *builtinRpadUTF8Sig) evalString(event chunk.Event) (string, bool, error) { 2221 str, isNull, err := b.args[0].EvalString(b.ctx, event) 2222 if isNull || err != nil { 2223 return "", true, err 2224 } 2225 runeLength := len([]rune(str)) 2226 2227 length, isNull, err := b.args[1].EvalInt(b.ctx, event) 2228 if isNull || err != nil { 2229 return "", true, err 2230 } 2231 targetLength := int(length) 2232 2233 if uint64(targetLength)*uint64(allegrosql.MaxBytesOfCharacter) > b.maxAllowedPacket { 2234 b.ctx.GetStochastikVars().StmtCtx.AppendWarning(errWarnAllowedPacketOverflowed.GenWithStackByArgs("rpad", b.maxAllowedPacket)) 2235 return "", true, nil 2236 } 2237 2238 padStr, isNull, err := b.args[2].EvalString(b.ctx, event) 2239 if isNull || err != nil { 2240 return "", true, err 2241 } 2242 padLength := len([]rune(padStr)) 2243 2244 if targetLength < 0 || targetLength*4 > b.tp.Flen || (runeLength < targetLength && padLength == 0) { 2245 return "", true, nil 2246 } 2247 2248 if tailLen := targetLength - runeLength; tailLen > 0 { 2249 repeatCount := tailLen/padLength + 1 2250 str = str + strings.Repeat(padStr, repeatCount) 2251 } 2252 return string([]rune(str)[:targetLength]), false, nil 2253 } 2254 2255 type bitLengthFunctionClass struct { 2256 baseFunctionClass 2257 } 2258 2259 func (c *bitLengthFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 2260 if err := c.verifyArgs(args); err != nil { 2261 return nil, err 2262 } 2263 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETInt, types.ETString) 2264 if err != nil { 2265 return nil, err 2266 } 2267 bf.tp.Flen = 10 2268 sig := &builtinBitLengthSig{bf} 2269 sig.setPbCode(fidelpb.ScalarFuncSig_BitLength) 2270 return sig, nil 2271 } 2272 2273 type builtinBitLengthSig struct { 2274 baseBuiltinFunc 2275 } 2276 2277 func (b *builtinBitLengthSig) Clone() builtinFunc { 2278 newSig := &builtinBitLengthSig{} 2279 newSig.cloneFrom(&b.baseBuiltinFunc) 2280 return newSig 2281 } 2282 2283 // evalInt evaluates a builtinBitLengthSig. 2284 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_bit-length 2285 func (b *builtinBitLengthSig) evalInt(event chunk.Event) (int64, bool, error) { 2286 val, isNull, err := b.args[0].EvalString(b.ctx, event) 2287 if isNull || err != nil { 2288 return 0, isNull, err 2289 } 2290 2291 return int64(len(val) * 8), false, nil 2292 } 2293 2294 type charFunctionClass struct { 2295 baseFunctionClass 2296 } 2297 2298 func (c *charFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 2299 if err := c.verifyArgs(args); err != nil { 2300 return nil, err 2301 } 2302 argTps := make([]types.EvalType, 0, len(args)) 2303 for i := 0; i < len(args)-1; i++ { 2304 argTps = append(argTps, types.ETInt) 2305 } 2306 argTps = append(argTps, types.ETString) 2307 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, argTps...) 2308 if err != nil { 2309 return nil, err 2310 } 2311 // The last argument represents the charset name after "using". 2312 if _, ok := args[len(args)-1].(*Constant); !ok { 2313 // If we got there, there must be something wrong in other places. 2314 logutil.BgLogger().Warn(fmt.Sprintf("The last argument in char function must be constant, but got %T", args[len(args)-1])) 2315 return nil, errIncorrectArgs 2316 } 2317 charsetName, isNull, err := args[len(args)-1].EvalString(ctx, chunk.Event{}) 2318 if err != nil { 2319 return nil, err 2320 } 2321 if isNull { 2322 // Use the default charset binary if it is nil. 2323 bf.tp.Charset, bf.tp.DefCauslate = charset.CharsetBin, charset.DefCauslationBin 2324 bf.tp.Flag |= allegrosql.BinaryFlag 2325 } else { 2326 bf.tp.Charset = charsetName 2327 defaultDefCauslate, err := charset.GetDefaultDefCauslation(charsetName) 2328 if err != nil { 2329 return nil, err 2330 } 2331 bf.tp.DefCauslate = defaultDefCauslate 2332 } 2333 bf.tp.Flen = 4 * (len(args) - 1) 2334 2335 sig := &builtinCharSig{bf} 2336 sig.setPbCode(fidelpb.ScalarFuncSig_Char) 2337 return sig, nil 2338 } 2339 2340 type builtinCharSig struct { 2341 baseBuiltinFunc 2342 } 2343 2344 func (b *builtinCharSig) Clone() builtinFunc { 2345 newSig := &builtinCharSig{} 2346 newSig.cloneFrom(&b.baseBuiltinFunc) 2347 return newSig 2348 } 2349 2350 func (b *builtinCharSig) convertToBytes(ints []int64) []byte { 2351 buffer := bytes.NewBuffer([]byte{}) 2352 for i := len(ints) - 1; i >= 0; i-- { 2353 for count, val := 0, ints[i]; count < 4; count++ { 2354 buffer.WriteByte(byte(val & 0xff)) 2355 if val >>= 8; val == 0 { 2356 break 2357 } 2358 } 2359 } 2360 return reverseBytes(buffer.Bytes()) 2361 } 2362 2363 // evalString evals CHAR(N,... [USING charset_name]). 2364 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_char. 2365 func (b *builtinCharSig) evalString(event chunk.Event) (string, bool, error) { 2366 bigints := make([]int64, 0, len(b.args)-1) 2367 2368 for i := 0; i < len(b.args)-1; i++ { 2369 val, IsNull, err := b.args[i].EvalInt(b.ctx, event) 2370 if err != nil { 2371 return "", true, err 2372 } 2373 if IsNull { 2374 continue 2375 } 2376 bigints = append(bigints, val) 2377 } 2378 result := string(b.convertToBytes(bigints)) 2379 return result, false, nil 2380 } 2381 2382 type charLengthFunctionClass struct { 2383 baseFunctionClass 2384 } 2385 2386 func (c *charLengthFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 2387 if argsErr := c.verifyArgs(args); argsErr != nil { 2388 return nil, argsErr 2389 } 2390 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETInt, types.ETString) 2391 if err != nil { 2392 return nil, err 2393 } 2394 if types.IsBinaryStr(args[0].GetType()) { 2395 sig := &builtinCharLengthBinarySig{bf} 2396 sig.setPbCode(fidelpb.ScalarFuncSig_CharLength) 2397 return sig, nil 2398 } 2399 sig := &builtinCharLengthUTF8Sig{bf} 2400 sig.setPbCode(fidelpb.ScalarFuncSig_CharLengthUTF8) 2401 return sig, nil 2402 } 2403 2404 type builtinCharLengthBinarySig struct { 2405 baseBuiltinFunc 2406 } 2407 2408 func (b *builtinCharLengthBinarySig) Clone() builtinFunc { 2409 newSig := &builtinCharLengthBinarySig{} 2410 newSig.cloneFrom(&b.baseBuiltinFunc) 2411 return newSig 2412 } 2413 2414 // evalInt evals a builtinCharLengthUTF8Sig for binary string type. 2415 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_char-length 2416 func (b *builtinCharLengthBinarySig) evalInt(event chunk.Event) (int64, bool, error) { 2417 val, isNull, err := b.args[0].EvalString(b.ctx, event) 2418 if isNull || err != nil { 2419 return 0, isNull, err 2420 } 2421 return int64(len(val)), false, nil 2422 } 2423 2424 type builtinCharLengthUTF8Sig struct { 2425 baseBuiltinFunc 2426 } 2427 2428 func (b *builtinCharLengthUTF8Sig) Clone() builtinFunc { 2429 newSig := &builtinCharLengthUTF8Sig{} 2430 newSig.cloneFrom(&b.baseBuiltinFunc) 2431 return newSig 2432 } 2433 2434 // evalInt evals a builtinCharLengthUTF8Sig for non-binary string type. 2435 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_char-length 2436 func (b *builtinCharLengthUTF8Sig) evalInt(event chunk.Event) (int64, bool, error) { 2437 val, isNull, err := b.args[0].EvalString(b.ctx, event) 2438 if isNull || err != nil { 2439 return 0, isNull, err 2440 } 2441 return int64(len([]rune(val))), false, nil 2442 } 2443 2444 type findInSetFunctionClass struct { 2445 baseFunctionClass 2446 } 2447 2448 func (c *findInSetFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 2449 if err := c.verifyArgs(args); err != nil { 2450 return nil, err 2451 } 2452 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETInt, types.ETString, types.ETString) 2453 if err != nil { 2454 return nil, err 2455 } 2456 bf.tp.Flen = 3 2457 sig := &builtinFindInSetSig{bf} 2458 sig.setPbCode(fidelpb.ScalarFuncSig_FindInSet) 2459 return sig, nil 2460 } 2461 2462 type builtinFindInSetSig struct { 2463 baseBuiltinFunc 2464 } 2465 2466 func (b *builtinFindInSetSig) Clone() builtinFunc { 2467 newSig := &builtinFindInSetSig{} 2468 newSig.cloneFrom(&b.baseBuiltinFunc) 2469 return newSig 2470 } 2471 2472 // evalInt evals FIND_IN_SET(str,strlist). 2473 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_find-in-set 2474 // TODO: This function can be optimized by using bit arithmetic when the first argument is 2475 // a constant string and the second is a defCausumn of type SET. 2476 func (b *builtinFindInSetSig) evalInt(event chunk.Event) (int64, bool, error) { 2477 str, isNull, err := b.args[0].EvalString(b.ctx, event) 2478 if isNull || err != nil { 2479 return 0, isNull, err 2480 } 2481 2482 strlist, isNull, err := b.args[1].EvalString(b.ctx, event) 2483 if isNull || err != nil { 2484 return 0, isNull, err 2485 } 2486 2487 if len(strlist) == 0 { 2488 return 0, false, nil 2489 } 2490 2491 for i, strInSet := range strings.Split(strlist, ",") { 2492 if b.ctor.Compare(str, strInSet) == 0 { 2493 return int64(i + 1), false, nil 2494 } 2495 } 2496 return 0, false, nil 2497 } 2498 2499 type fieldFunctionClass struct { 2500 baseFunctionClass 2501 } 2502 2503 func (c *fieldFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 2504 if err := c.verifyArgs(args); err != nil { 2505 return nil, err 2506 } 2507 2508 isAllString, isAllNumber := true, true 2509 for i, length := 0, len(args); i < length; i++ { 2510 argTp := args[i].GetType().EvalType() 2511 isAllString = isAllString && (argTp == types.ETString) 2512 isAllNumber = isAllNumber && (argTp == types.ETInt) 2513 } 2514 2515 argTps := make([]types.EvalType, len(args)) 2516 argTp := types.ETReal 2517 if isAllString { 2518 argTp = types.ETString 2519 } else if isAllNumber { 2520 argTp = types.ETInt 2521 } 2522 for i, length := 0, len(args); i < length; i++ { 2523 argTps[i] = argTp 2524 } 2525 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETInt, argTps...) 2526 if err != nil { 2527 return nil, err 2528 } 2529 var sig builtinFunc 2530 switch argTp { 2531 case types.ETReal: 2532 sig = &builtinFieldRealSig{bf} 2533 sig.setPbCode(fidelpb.ScalarFuncSig_FieldReal) 2534 case types.ETInt: 2535 sig = &builtinFieldIntSig{bf} 2536 sig.setPbCode(fidelpb.ScalarFuncSig_FieldInt) 2537 case types.ETString: 2538 sig = &builtinFieldStringSig{bf} 2539 sig.setPbCode(fidelpb.ScalarFuncSig_FieldString) 2540 } 2541 return sig, nil 2542 } 2543 2544 type builtinFieldIntSig struct { 2545 baseBuiltinFunc 2546 } 2547 2548 func (b *builtinFieldIntSig) Clone() builtinFunc { 2549 newSig := &builtinFieldIntSig{} 2550 newSig.cloneFrom(&b.baseBuiltinFunc) 2551 return newSig 2552 } 2553 2554 // evalInt evals FIELD(str,str1,str2,str3,...). 2555 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_field 2556 func (b *builtinFieldIntSig) evalInt(event chunk.Event) (int64, bool, error) { 2557 str, isNull, err := b.args[0].EvalInt(b.ctx, event) 2558 if isNull || err != nil { 2559 return 0, err != nil, err 2560 } 2561 for i, length := 1, len(b.args); i < length; i++ { 2562 stri, isNull, err := b.args[i].EvalInt(b.ctx, event) 2563 if err != nil { 2564 return 0, true, err 2565 } 2566 if !isNull && str == stri { 2567 return int64(i), false, nil 2568 } 2569 } 2570 return 0, false, nil 2571 } 2572 2573 type builtinFieldRealSig struct { 2574 baseBuiltinFunc 2575 } 2576 2577 func (b *builtinFieldRealSig) Clone() builtinFunc { 2578 newSig := &builtinFieldRealSig{} 2579 newSig.cloneFrom(&b.baseBuiltinFunc) 2580 return newSig 2581 } 2582 2583 // evalInt evals FIELD(str,str1,str2,str3,...). 2584 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_field 2585 func (b *builtinFieldRealSig) evalInt(event chunk.Event) (int64, bool, error) { 2586 str, isNull, err := b.args[0].EvalReal(b.ctx, event) 2587 if isNull || err != nil { 2588 return 0, err != nil, err 2589 } 2590 for i, length := 1, len(b.args); i < length; i++ { 2591 stri, isNull, err := b.args[i].EvalReal(b.ctx, event) 2592 if err != nil { 2593 return 0, true, err 2594 } 2595 if !isNull && str == stri { 2596 return int64(i), false, nil 2597 } 2598 } 2599 return 0, false, nil 2600 } 2601 2602 type builtinFieldStringSig struct { 2603 baseBuiltinFunc 2604 } 2605 2606 func (b *builtinFieldStringSig) Clone() builtinFunc { 2607 newSig := &builtinFieldStringSig{} 2608 newSig.cloneFrom(&b.baseBuiltinFunc) 2609 return newSig 2610 } 2611 2612 // evalInt evals FIELD(str,str1,str2,str3,...). 2613 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_field 2614 func (b *builtinFieldStringSig) evalInt(event chunk.Event) (int64, bool, error) { 2615 str, isNull, err := b.args[0].EvalString(b.ctx, event) 2616 if isNull || err != nil { 2617 return 0, err != nil, err 2618 } 2619 for i, length := 1, len(b.args); i < length; i++ { 2620 stri, isNull, err := b.args[i].EvalString(b.ctx, event) 2621 if err != nil { 2622 return 0, true, err 2623 } 2624 if !isNull && b.ctor.Compare(str, stri) == 0 { 2625 return int64(i), false, nil 2626 } 2627 } 2628 return 0, false, nil 2629 } 2630 2631 type makeSetFunctionClass struct { 2632 baseFunctionClass 2633 } 2634 2635 func (c *makeSetFunctionClass) getFlen(ctx stochastikctx.Context, args []Expression) int { 2636 flen, count := 0, 0 2637 if constant, ok := args[0].(*Constant); ok { 2638 bits, isNull, err := constant.EvalInt(ctx, chunk.Event{}) 2639 if err == nil && !isNull { 2640 for i, length := 1, len(args); i < length; i++ { 2641 if (bits & (1 << uint(i-1))) != 0 { 2642 flen += args[i].GetType().Flen 2643 count++ 2644 } 2645 } 2646 if count > 0 { 2647 flen += count - 1 2648 } 2649 return flen 2650 } 2651 } 2652 for i, length := 1, len(args); i < length; i++ { 2653 flen += args[i].GetType().Flen 2654 } 2655 return flen + len(args) - 1 - 1 2656 } 2657 2658 func (c *makeSetFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 2659 if err := c.verifyArgs(args); err != nil { 2660 return nil, err 2661 } 2662 argTps := make([]types.EvalType, len(args)) 2663 argTps[0] = types.ETInt 2664 for i, length := 1, len(args); i < length; i++ { 2665 argTps[i] = types.ETString 2666 } 2667 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, argTps...) 2668 if err != nil { 2669 return nil, err 2670 } 2671 for i, length := 0, len(args); i < length; i++ { 2672 SetBinFlagOrBinStr(args[i].GetType(), bf.tp) 2673 } 2674 bf.tp.Flen = c.getFlen(bf.ctx, args) 2675 if bf.tp.Flen > allegrosql.MaxBlobWidth { 2676 bf.tp.Flen = allegrosql.MaxBlobWidth 2677 } 2678 sig := &builtinMakeSetSig{bf} 2679 sig.setPbCode(fidelpb.ScalarFuncSig_MakeSet) 2680 return sig, nil 2681 } 2682 2683 type builtinMakeSetSig struct { 2684 baseBuiltinFunc 2685 } 2686 2687 func (b *builtinMakeSetSig) Clone() builtinFunc { 2688 newSig := &builtinMakeSetSig{} 2689 newSig.cloneFrom(&b.baseBuiltinFunc) 2690 return newSig 2691 } 2692 2693 // evalString evals MAKE_SET(bits,str1,str2,...). 2694 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_make-set 2695 func (b *builtinMakeSetSig) evalString(event chunk.Event) (string, bool, error) { 2696 bits, isNull, err := b.args[0].EvalInt(b.ctx, event) 2697 if isNull || err != nil { 2698 return "", true, err 2699 } 2700 2701 sets := make([]string, 0, len(b.args)-1) 2702 for i, length := 1, len(b.args); i < length; i++ { 2703 if (bits & (1 << uint(i-1))) == 0 { 2704 continue 2705 } 2706 str, isNull, err := b.args[i].EvalString(b.ctx, event) 2707 if err != nil { 2708 return "", true, err 2709 } 2710 if !isNull { 2711 sets = append(sets, str) 2712 } 2713 } 2714 2715 return strings.Join(sets, ","), false, nil 2716 } 2717 2718 type octFunctionClass struct { 2719 baseFunctionClass 2720 } 2721 2722 func (c *octFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 2723 if err := c.verifyArgs(args); err != nil { 2724 return nil, err 2725 } 2726 var sig builtinFunc 2727 if IsBinaryLiteral(args[0]) || args[0].GetType().EvalType() == types.ETInt { 2728 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETInt) 2729 if err != nil { 2730 return nil, err 2731 } 2732 bf.tp.Charset, bf.tp.DefCauslate = ctx.GetStochastikVars().GetCharsetInfo() 2733 bf.tp.Flen, bf.tp.Decimal = 64, types.UnspecifiedLength 2734 sig = &builtinOctIntSig{bf} 2735 sig.setPbCode(fidelpb.ScalarFuncSig_OctInt) 2736 } else { 2737 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString) 2738 if err != nil { 2739 return nil, err 2740 } 2741 bf.tp.Charset, bf.tp.DefCauslate = ctx.GetStochastikVars().GetCharsetInfo() 2742 bf.tp.Flen, bf.tp.Decimal = 64, types.UnspecifiedLength 2743 sig = &builtinOctStringSig{bf} 2744 sig.setPbCode(fidelpb.ScalarFuncSig_OctString) 2745 } 2746 2747 return sig, nil 2748 } 2749 2750 type builtinOctIntSig struct { 2751 baseBuiltinFunc 2752 } 2753 2754 func (b *builtinOctIntSig) Clone() builtinFunc { 2755 newSig := &builtinOctIntSig{} 2756 newSig.cloneFrom(&b.baseBuiltinFunc) 2757 return newSig 2758 } 2759 2760 // evalString evals OCT(N). 2761 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_oct 2762 func (b *builtinOctIntSig) evalString(event chunk.Event) (string, bool, error) { 2763 val, isNull, err := b.args[0].EvalInt(b.ctx, event) 2764 if isNull || err != nil { 2765 return "", isNull, err 2766 } 2767 2768 return strconv.FormatUint(uint64(val), 8), false, nil 2769 } 2770 2771 type builtinOctStringSig struct { 2772 baseBuiltinFunc 2773 } 2774 2775 func (b *builtinOctStringSig) Clone() builtinFunc { 2776 newSig := &builtinOctStringSig{} 2777 newSig.cloneFrom(&b.baseBuiltinFunc) 2778 return newSig 2779 } 2780 2781 // evalString evals OCT(N). 2782 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_oct 2783 func (b *builtinOctStringSig) evalString(event chunk.Event) (string, bool, error) { 2784 val, isNull, err := b.args[0].EvalString(b.ctx, event) 2785 if isNull || err != nil { 2786 return "", isNull, err 2787 } 2788 2789 negative, overflow := false, false 2790 val = getValidPrefix(strings.TrimSpace(val), 10) 2791 if len(val) == 0 { 2792 return "0", false, nil 2793 } 2794 2795 if val[0] == '-' { 2796 negative, val = true, val[1:] 2797 } 2798 numVal, err := strconv.ParseUint(val, 10, 64) 2799 if err != nil { 2800 numError, ok := err.(*strconv.NumError) 2801 if !ok || numError.Err != strconv.ErrRange { 2802 return "", true, errors.Trace(err) 2803 } 2804 overflow = true 2805 } 2806 if negative && !overflow { 2807 numVal = -numVal 2808 } 2809 return strconv.FormatUint(numVal, 8), false, nil 2810 } 2811 2812 type ordFunctionClass struct { 2813 baseFunctionClass 2814 } 2815 2816 func (c *ordFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 2817 if err := c.verifyArgs(args); err != nil { 2818 return nil, err 2819 } 2820 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETInt, types.ETString) 2821 if err != nil { 2822 return nil, err 2823 } 2824 bf.tp.Flen = 10 2825 sig := &builtinOrdSig{bf} 2826 sig.setPbCode(fidelpb.ScalarFuncSig_Ord) 2827 return sig, nil 2828 } 2829 2830 type builtinOrdSig struct { 2831 baseBuiltinFunc 2832 } 2833 2834 func (b *builtinOrdSig) Clone() builtinFunc { 2835 newSig := &builtinOrdSig{} 2836 newSig.cloneFrom(&b.baseBuiltinFunc) 2837 return newSig 2838 } 2839 2840 // evalInt evals a builtinOrdSig. 2841 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_ord 2842 func (b *builtinOrdSig) evalInt(event chunk.Event) (int64, bool, error) { 2843 str, isNull, err := b.args[0].EvalString(b.ctx, event) 2844 if isNull || err != nil { 2845 return 0, isNull, err 2846 } 2847 2848 ord, err := chooseOrdFunc(b.args[0].GetType().Charset) 2849 if err != nil { 2850 return 0, false, err 2851 } 2852 return ord(str), false, nil 2853 } 2854 2855 func chooseOrdFunc(charSet string) (func(string) int64, error) { 2856 // use utf8 by default 2857 if charSet == "" { 2858 charSet = charset.CharsetUTF8 2859 } 2860 desc, err := charset.GetCharsetDesc(charSet) 2861 if err != nil { 2862 return nil, err 2863 } 2864 if desc.Maxlen == 1 { 2865 return ordSingleByte, nil 2866 } 2867 return ordUtf8, nil 2868 } 2869 2870 func ordSingleByte(str string) int64 { 2871 if len(str) == 0 { 2872 return 0 2873 } 2874 return int64(str[0]) 2875 } 2876 2877 func ordUtf8(str string) int64 { 2878 if len(str) == 0 { 2879 return 0 2880 } 2881 _, size := utf8.DecodeRuneInString(str) 2882 leftMost := str[:size] 2883 var result int64 2884 var factor int64 = 1 2885 for i := len(leftMost) - 1; i >= 0; i-- { 2886 result += int64(leftMost[i]) * factor 2887 factor *= 256 2888 } 2889 return result 2890 } 2891 2892 type quoteFunctionClass struct { 2893 baseFunctionClass 2894 } 2895 2896 func (c *quoteFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 2897 if err := c.verifyArgs(args); err != nil { 2898 return nil, err 2899 } 2900 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString) 2901 if err != nil { 2902 return nil, err 2903 } 2904 SetBinFlagOrBinStr(args[0].GetType(), bf.tp) 2905 bf.tp.Flen = 2*args[0].GetType().Flen + 2 2906 if bf.tp.Flen > allegrosql.MaxBlobWidth { 2907 bf.tp.Flen = allegrosql.MaxBlobWidth 2908 } 2909 sig := &builtinQuoteSig{bf} 2910 sig.setPbCode(fidelpb.ScalarFuncSig_Quote) 2911 return sig, nil 2912 } 2913 2914 type builtinQuoteSig struct { 2915 baseBuiltinFunc 2916 } 2917 2918 func (b *builtinQuoteSig) Clone() builtinFunc { 2919 newSig := &builtinQuoteSig{} 2920 newSig.cloneFrom(&b.baseBuiltinFunc) 2921 return newSig 2922 } 2923 2924 // evalString evals QUOTE(str). 2925 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_quote 2926 func (b *builtinQuoteSig) evalString(event chunk.Event) (string, bool, error) { 2927 str, isNull, err := b.args[0].EvalString(b.ctx, event) 2928 if err != nil { 2929 return "", true, err 2930 } else if isNull { 2931 // If the argument is NULL, the return value is the word "NULL" without enclosing single quotation marks. see ref. 2932 return "NULL", false, err 2933 } 2934 2935 return Quote(str), false, nil 2936 } 2937 2938 // Quote produce a result that can be used as a properly escaped data value in an ALLEGROALLEGROSQL memex. 2939 func Quote(str string) string { 2940 runes := []rune(str) 2941 buffer := bytes.NewBufferString("") 2942 buffer.WriteRune('\'') 2943 for i, runeLength := 0, len(runes); i < runeLength; i++ { 2944 switch runes[i] { 2945 case '\\', '\'': 2946 buffer.WriteRune('\\') 2947 buffer.WriteRune(runes[i]) 2948 case 0: 2949 buffer.WriteRune('\\') 2950 buffer.WriteRune('0') 2951 case '\032': 2952 buffer.WriteRune('\\') 2953 buffer.WriteRune('Z') 2954 default: 2955 buffer.WriteRune(runes[i]) 2956 } 2957 } 2958 buffer.WriteRune('\'') 2959 2960 return buffer.String() 2961 } 2962 2963 type binFunctionClass struct { 2964 baseFunctionClass 2965 } 2966 2967 func (c *binFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 2968 if err := c.verifyArgs(args); err != nil { 2969 return nil, err 2970 } 2971 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETInt) 2972 if err != nil { 2973 return nil, err 2974 } 2975 bf.tp.Charset, bf.tp.DefCauslate = ctx.GetStochastikVars().GetCharsetInfo() 2976 bf.tp.Flen = 64 2977 sig := &builtinBinSig{bf} 2978 sig.setPbCode(fidelpb.ScalarFuncSig_Bin) 2979 return sig, nil 2980 } 2981 2982 type builtinBinSig struct { 2983 baseBuiltinFunc 2984 } 2985 2986 func (b *builtinBinSig) Clone() builtinFunc { 2987 newSig := &builtinBinSig{} 2988 newSig.cloneFrom(&b.baseBuiltinFunc) 2989 return newSig 2990 } 2991 2992 // evalString evals BIN(N). 2993 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_bin 2994 func (b *builtinBinSig) evalString(event chunk.Event) (string, bool, error) { 2995 val, isNull, err := b.args[0].EvalInt(b.ctx, event) 2996 if isNull || err != nil { 2997 return "", true, err 2998 } 2999 return fmt.Sprintf("%b", uint64(val)), false, nil 3000 } 3001 3002 type eltFunctionClass struct { 3003 baseFunctionClass 3004 } 3005 3006 func (c *eltFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 3007 if argsErr := c.verifyArgs(args); argsErr != nil { 3008 return nil, argsErr 3009 } 3010 argTps := make([]types.EvalType, 0, len(args)) 3011 argTps = append(argTps, types.ETInt) 3012 for i := 1; i < len(args); i++ { 3013 argTps = append(argTps, types.ETString) 3014 } 3015 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, argTps...) 3016 if err != nil { 3017 return nil, err 3018 } 3019 for _, arg := range args[1:] { 3020 argType := arg.GetType() 3021 if types.IsBinaryStr(argType) { 3022 types.SetBinChsClnFlag(bf.tp) 3023 } 3024 if argType.Flen > bf.tp.Flen { 3025 bf.tp.Flen = argType.Flen 3026 } 3027 } 3028 sig := &builtinEltSig{bf} 3029 sig.setPbCode(fidelpb.ScalarFuncSig_Elt) 3030 return sig, nil 3031 } 3032 3033 type builtinEltSig struct { 3034 baseBuiltinFunc 3035 } 3036 3037 func (b *builtinEltSig) Clone() builtinFunc { 3038 newSig := &builtinEltSig{} 3039 newSig.cloneFrom(&b.baseBuiltinFunc) 3040 return newSig 3041 } 3042 3043 // evalString evals a ELT(N,str1,str2,str3,...). 3044 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_elt 3045 func (b *builtinEltSig) evalString(event chunk.Event) (string, bool, error) { 3046 idx, isNull, err := b.args[0].EvalInt(b.ctx, event) 3047 if isNull || err != nil { 3048 return "", true, err 3049 } 3050 if idx < 1 || idx >= int64(len(b.args)) { 3051 return "", true, nil 3052 } 3053 arg, isNull, err := b.args[idx].EvalString(b.ctx, event) 3054 if isNull || err != nil { 3055 return "", true, err 3056 } 3057 return arg, false, nil 3058 } 3059 3060 type exportSetFunctionClass struct { 3061 baseFunctionClass 3062 } 3063 3064 func (c *exportSetFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (sig builtinFunc, err error) { 3065 if err = c.verifyArgs(args); err != nil { 3066 return nil, err 3067 } 3068 argTps := make([]types.EvalType, 0, 5) 3069 argTps = append(argTps, types.ETInt, types.ETString, types.ETString) 3070 if len(args) > 3 { 3071 argTps = append(argTps, types.ETString) 3072 } 3073 if len(args) > 4 { 3074 argTps = append(argTps, types.ETInt) 3075 } 3076 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, argTps...) 3077 if err != nil { 3078 return nil, err 3079 } 3080 bf.tp.Flen = allegrosql.MaxBlobWidth 3081 switch len(args) { 3082 case 3: 3083 sig = &builtinExportSet3ArgSig{bf} 3084 sig.setPbCode(fidelpb.ScalarFuncSig_ExportSet3Arg) 3085 case 4: 3086 sig = &builtinExportSet4ArgSig{bf} 3087 sig.setPbCode(fidelpb.ScalarFuncSig_ExportSet4Arg) 3088 case 5: 3089 sig = &builtinExportSet5ArgSig{bf} 3090 sig.setPbCode(fidelpb.ScalarFuncSig_ExportSet5Arg) 3091 } 3092 return sig, nil 3093 } 3094 3095 // exportSet evals EXPORT_SET(bits,on,off,separator,number_of_bits). 3096 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_export-set 3097 func exportSet(bits int64, on, off, separator string, numberOfBits int64) string { 3098 result := "" 3099 for i := uint64(0); i < uint64(numberOfBits); i++ { 3100 if (bits & (1 << i)) > 0 { 3101 result += on 3102 } else { 3103 result += off 3104 } 3105 if i < uint64(numberOfBits)-1 { 3106 result += separator 3107 } 3108 } 3109 return result 3110 } 3111 3112 type builtinExportSet3ArgSig struct { 3113 baseBuiltinFunc 3114 } 3115 3116 func (b *builtinExportSet3ArgSig) Clone() builtinFunc { 3117 newSig := &builtinExportSet3ArgSig{} 3118 newSig.cloneFrom(&b.baseBuiltinFunc) 3119 return newSig 3120 } 3121 3122 // evalString evals EXPORT_SET(bits,on,off). 3123 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_export-set 3124 func (b *builtinExportSet3ArgSig) evalString(event chunk.Event) (string, bool, error) { 3125 bits, isNull, err := b.args[0].EvalInt(b.ctx, event) 3126 if isNull || err != nil { 3127 return "", true, err 3128 } 3129 3130 on, isNull, err := b.args[1].EvalString(b.ctx, event) 3131 if isNull || err != nil { 3132 return "", true, err 3133 } 3134 3135 off, isNull, err := b.args[2].EvalString(b.ctx, event) 3136 if isNull || err != nil { 3137 return "", true, err 3138 } 3139 3140 return exportSet(bits, on, off, ",", 64), false, nil 3141 } 3142 3143 type builtinExportSet4ArgSig struct { 3144 baseBuiltinFunc 3145 } 3146 3147 func (b *builtinExportSet4ArgSig) Clone() builtinFunc { 3148 newSig := &builtinExportSet4ArgSig{} 3149 newSig.cloneFrom(&b.baseBuiltinFunc) 3150 return newSig 3151 } 3152 3153 // evalString evals EXPORT_SET(bits,on,off,separator). 3154 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_export-set 3155 func (b *builtinExportSet4ArgSig) evalString(event chunk.Event) (string, bool, error) { 3156 bits, isNull, err := b.args[0].EvalInt(b.ctx, event) 3157 if isNull || err != nil { 3158 return "", true, err 3159 } 3160 3161 on, isNull, err := b.args[1].EvalString(b.ctx, event) 3162 if isNull || err != nil { 3163 return "", true, err 3164 } 3165 3166 off, isNull, err := b.args[2].EvalString(b.ctx, event) 3167 if isNull || err != nil { 3168 return "", true, err 3169 } 3170 3171 separator, isNull, err := b.args[3].EvalString(b.ctx, event) 3172 if isNull || err != nil { 3173 return "", true, err 3174 } 3175 3176 return exportSet(bits, on, off, separator, 64), false, nil 3177 } 3178 3179 type builtinExportSet5ArgSig struct { 3180 baseBuiltinFunc 3181 } 3182 3183 func (b *builtinExportSet5ArgSig) Clone() builtinFunc { 3184 newSig := &builtinExportSet5ArgSig{} 3185 newSig.cloneFrom(&b.baseBuiltinFunc) 3186 return newSig 3187 } 3188 3189 // evalString evals EXPORT_SET(bits,on,off,separator,number_of_bits). 3190 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_export-set 3191 func (b *builtinExportSet5ArgSig) evalString(event chunk.Event) (string, bool, error) { 3192 bits, isNull, err := b.args[0].EvalInt(b.ctx, event) 3193 if isNull || err != nil { 3194 return "", true, err 3195 } 3196 3197 on, isNull, err := b.args[1].EvalString(b.ctx, event) 3198 if isNull || err != nil { 3199 return "", true, err 3200 } 3201 3202 off, isNull, err := b.args[2].EvalString(b.ctx, event) 3203 if isNull || err != nil { 3204 return "", true, err 3205 } 3206 3207 separator, isNull, err := b.args[3].EvalString(b.ctx, event) 3208 if isNull || err != nil { 3209 return "", true, err 3210 } 3211 3212 numberOfBits, isNull, err := b.args[4].EvalInt(b.ctx, event) 3213 if isNull || err != nil { 3214 return "", true, err 3215 } 3216 if numberOfBits < 0 || numberOfBits > 64 { 3217 numberOfBits = 64 3218 } 3219 3220 return exportSet(bits, on, off, separator, numberOfBits), false, nil 3221 } 3222 3223 type formatFunctionClass struct { 3224 baseFunctionClass 3225 } 3226 3227 func (c *formatFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 3228 if err := c.verifyArgs(args); err != nil { 3229 return nil, err 3230 } 3231 argTps := make([]types.EvalType, 2, 3) 3232 argTps[1] = types.ETInt 3233 argTp := args[0].GetType().EvalType() 3234 if argTp == types.ETDecimal || argTp == types.ETInt { 3235 argTps[0] = types.ETDecimal 3236 } else { 3237 argTps[0] = types.ETReal 3238 } 3239 if len(args) == 3 { 3240 argTps = append(argTps, types.ETString) 3241 } 3242 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, argTps...) 3243 if err != nil { 3244 return nil, err 3245 } 3246 bf.tp.Charset, bf.tp.DefCauslate = ctx.GetStochastikVars().GetCharsetInfo() 3247 bf.tp.Flen = allegrosql.MaxBlobWidth 3248 var sig builtinFunc 3249 if len(args) == 3 { 3250 sig = &builtinFormatWithLocaleSig{bf} 3251 sig.setPbCode(fidelpb.ScalarFuncSig_FormatWithLocale) 3252 } else { 3253 sig = &builtinFormatSig{bf} 3254 sig.setPbCode(fidelpb.ScalarFuncSig_Format) 3255 } 3256 return sig, nil 3257 } 3258 3259 // formatMaxDecimals limits the maximum number of decimal digits for result of 3260 // function `format`, this value is same as `FORMAT_MAX_DECIMALS` in MyALLEGROSQL source code. 3261 const formatMaxDecimals int64 = 30 3262 3263 // evalNumDecArgsForFormat evaluates first 2 arguments, i.e, x and d, for function `format`. 3264 func evalNumDecArgsForFormat(f builtinFunc, event chunk.Event) (string, string, bool, error) { 3265 var xStr string 3266 arg0, arg1 := f.getArgs()[0], f.getArgs()[1] 3267 ctx := f.getCtx() 3268 if arg0.GetType().EvalType() == types.ETDecimal { 3269 x, isNull, err := arg0.EvalDecimal(ctx, event) 3270 if isNull || err != nil { 3271 return "", "", isNull, err 3272 } 3273 xStr = x.String() 3274 } else { 3275 x, isNull, err := arg0.EvalReal(ctx, event) 3276 if isNull || err != nil { 3277 return "", "", isNull, err 3278 } 3279 xStr = strconv.FormatFloat(x, 'f', -1, 64) 3280 } 3281 d, isNull, err := arg1.EvalInt(ctx, event) 3282 if isNull || err != nil { 3283 return "", "", isNull, err 3284 } 3285 if d < 0 { 3286 d = 0 3287 } else if d > formatMaxDecimals { 3288 d = formatMaxDecimals 3289 } 3290 xStr = roundFormatArgs(xStr, int(d)) 3291 dStr := strconv.FormatInt(d, 10) 3292 return xStr, dStr, false, nil 3293 } 3294 3295 func roundFormatArgs(xStr string, maxNumDecimals int) string { 3296 if !strings.Contains(xStr, ".") { 3297 return xStr 3298 } 3299 3300 sign := false 3301 // xStr cannot have '+' prefix now. 3302 // It is built in `evalNumDecArgsFormat` after evaluating `Evalxxx` method. 3303 if strings.HasPrefix(xStr, "-") { 3304 xStr = strings.Trim(xStr, "-") 3305 sign = true 3306 } 3307 3308 xArr := strings.Split(xStr, ".") 3309 integerPart := xArr[0] 3310 decimalPart := xArr[1] 3311 3312 if len(decimalPart) > maxNumDecimals { 3313 t := []byte(decimalPart) 3314 carry := false 3315 if t[maxNumDecimals] >= '5' { 3316 carry = true 3317 } 3318 for i := maxNumDecimals - 1; i >= 0 && carry; i-- { 3319 if t[i] == '9' { 3320 t[i] = '0' 3321 } else { 3322 t[i] = t[i] + 1 3323 carry = false 3324 } 3325 } 3326 decimalPart = string(t) 3327 t = []byte(integerPart) 3328 for i := len(integerPart) - 1; i >= 0 && carry; i-- { 3329 if t[i] == '9' { 3330 t[i] = '0' 3331 } else { 3332 t[i] = t[i] + 1 3333 carry = false 3334 } 3335 } 3336 if carry { 3337 integerPart = "1" + string(t) 3338 } else { 3339 integerPart = string(t) 3340 } 3341 } 3342 3343 xStr = integerPart + "." + decimalPart 3344 if sign { 3345 xStr = "-" + xStr 3346 } 3347 return xStr 3348 } 3349 3350 type builtinFormatWithLocaleSig struct { 3351 baseBuiltinFunc 3352 } 3353 3354 func (b *builtinFormatWithLocaleSig) Clone() builtinFunc { 3355 newSig := &builtinFormatWithLocaleSig{} 3356 newSig.cloneFrom(&b.baseBuiltinFunc) 3357 return newSig 3358 } 3359 3360 // evalString evals FORMAT(X,D,locale). 3361 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_format 3362 func (b *builtinFormatWithLocaleSig) evalString(event chunk.Event) (string, bool, error) { 3363 x, d, isNull, err := evalNumDecArgsForFormat(b, event) 3364 if isNull || err != nil { 3365 return "", isNull, err 3366 } 3367 locale, isNull, err := b.args[2].EvalString(b.ctx, event) 3368 if err != nil { 3369 return "", false, err 3370 } 3371 if isNull { 3372 b.ctx.GetStochastikVars().StmtCtx.AppendWarning(errUnknownLocale.GenWithStackByArgs("NULL")) 3373 locale = "en_US" 3374 } 3375 formatString, err := allegrosql.GetLocaleFormatFunction(locale)(x, d) 3376 return formatString, false, err 3377 } 3378 3379 type builtinFormatSig struct { 3380 baseBuiltinFunc 3381 } 3382 3383 func (b *builtinFormatSig) Clone() builtinFunc { 3384 newSig := &builtinFormatSig{} 3385 newSig.cloneFrom(&b.baseBuiltinFunc) 3386 return newSig 3387 } 3388 3389 // evalString evals FORMAT(X,D). 3390 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_format 3391 func (b *builtinFormatSig) evalString(event chunk.Event) (string, bool, error) { 3392 x, d, isNull, err := evalNumDecArgsForFormat(b, event) 3393 if isNull || err != nil { 3394 return "", isNull, err 3395 } 3396 formatString, err := allegrosql.GetLocaleFormatFunction("en_US")(x, d) 3397 return formatString, false, err 3398 } 3399 3400 type fromBase64FunctionClass struct { 3401 baseFunctionClass 3402 } 3403 3404 func (c *fromBase64FunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 3405 if err := c.verifyArgs(args); err != nil { 3406 return nil, err 3407 } 3408 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString) 3409 if err != nil { 3410 return nil, err 3411 } 3412 bf.tp.Flen = allegrosql.MaxBlobWidth 3413 3414 valStr, _ := ctx.GetStochastikVars().GetSystemVar(variable.MaxAllowedPacket) 3415 maxAllowedPacket, err := strconv.ParseUint(valStr, 10, 64) 3416 if err != nil { 3417 return nil, errors.Trace(err) 3418 } 3419 3420 types.SetBinChsClnFlag(bf.tp) 3421 sig := &builtinFromBase64Sig{bf, maxAllowedPacket} 3422 return sig, nil 3423 } 3424 3425 // base64NeededDecodedLength return the base64 decoded string length. 3426 func base64NeededDecodedLength(n int) int { 3427 // Returns -1 indicate the result will overflow. 3428 if strconv.IntSize == 64 && n > math.MaxInt64/3 { 3429 return -1 3430 } 3431 if strconv.IntSize == 32 && n > math.MaxInt32/3 { 3432 return -1 3433 } 3434 return n * 3 / 4 3435 } 3436 3437 type builtinFromBase64Sig struct { 3438 baseBuiltinFunc 3439 maxAllowedPacket uint64 3440 } 3441 3442 func (b *builtinFromBase64Sig) Clone() builtinFunc { 3443 newSig := &builtinFromBase64Sig{} 3444 newSig.cloneFrom(&b.baseBuiltinFunc) 3445 newSig.maxAllowedPacket = b.maxAllowedPacket 3446 return newSig 3447 } 3448 3449 // evalString evals FROM_BASE64(str). 3450 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_from-base64 3451 func (b *builtinFromBase64Sig) evalString(event chunk.Event) (string, bool, error) { 3452 str, isNull, err := b.args[0].EvalString(b.ctx, event) 3453 if isNull || err != nil { 3454 return "", true, err 3455 } 3456 3457 needDecodeLen := base64NeededDecodedLength(len(str)) 3458 if needDecodeLen == -1 { 3459 return "", true, nil 3460 } 3461 if needDecodeLen > int(b.maxAllowedPacket) { 3462 b.ctx.GetStochastikVars().StmtCtx.AppendWarning(errWarnAllowedPacketOverflowed.GenWithStackByArgs("from_base64", b.maxAllowedPacket)) 3463 return "", true, nil 3464 } 3465 3466 str = strings.Replace(str, "\t", "", -1) 3467 str = strings.Replace(str, " ", "", -1) 3468 result, err := base64.StdEncoding.DecodeString(str) 3469 if err != nil { 3470 // When error happens, take `from_base64("asc")` as an example, we should return NULL. 3471 return "", true, nil 3472 } 3473 return string(result), false, nil 3474 } 3475 3476 type toBase64FunctionClass struct { 3477 baseFunctionClass 3478 } 3479 3480 func (c *toBase64FunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 3481 if err := c.verifyArgs(args); err != nil { 3482 return nil, err 3483 } 3484 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString) 3485 if err != nil { 3486 return nil, err 3487 } 3488 bf.tp.Charset, bf.tp.DefCauslate = ctx.GetStochastikVars().GetCharsetInfo() 3489 bf.tp.Flen = base64NeededEncodedLength(bf.args[0].GetType().Flen) 3490 3491 valStr, _ := ctx.GetStochastikVars().GetSystemVar(variable.MaxAllowedPacket) 3492 maxAllowedPacket, err := strconv.ParseUint(valStr, 10, 64) 3493 if err != nil { 3494 return nil, errors.Trace(err) 3495 } 3496 3497 sig := &builtinToBase64Sig{bf, maxAllowedPacket} 3498 return sig, nil 3499 } 3500 3501 type builtinToBase64Sig struct { 3502 baseBuiltinFunc 3503 maxAllowedPacket uint64 3504 } 3505 3506 func (b *builtinToBase64Sig) Clone() builtinFunc { 3507 newSig := &builtinToBase64Sig{} 3508 newSig.cloneFrom(&b.baseBuiltinFunc) 3509 newSig.maxAllowedPacket = b.maxAllowedPacket 3510 return newSig 3511 } 3512 3513 // base64NeededEncodedLength return the base64 encoded string length. 3514 func base64NeededEncodedLength(n int) int { 3515 // Returns -1 indicate the result will overflow. 3516 if strconv.IntSize == 64 { 3517 // len(arg) -> len(to_base64(arg)) 3518 // 6827690988321067803 -> 9223372036854775804 3519 // 6827690988321067804 -> -9223372036854775808 3520 if n > 6827690988321067803 { 3521 return -1 3522 } 3523 } else { 3524 // len(arg) -> len(to_base64(arg)) 3525 // 1589695686 -> 2147483645 3526 // 1589695687 -> -2147483646 3527 if n > 1589695686 { 3528 return -1 3529 } 3530 } 3531 3532 length := (n + 2) / 3 * 4 3533 return length + (length-1)/76 3534 } 3535 3536 // evalString evals a builtinToBase64Sig. 3537 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_to-base64 3538 func (b *builtinToBase64Sig) evalString(event chunk.Event) (d string, isNull bool, err error) { 3539 str, isNull, err := b.args[0].EvalString(b.ctx, event) 3540 if isNull || err != nil { 3541 return "", isNull, err 3542 } 3543 needEncodeLen := base64NeededEncodedLength(len(str)) 3544 if needEncodeLen == -1 { 3545 return "", true, nil 3546 } 3547 if needEncodeLen > int(b.maxAllowedPacket) { 3548 b.ctx.GetStochastikVars().StmtCtx.AppendWarning(errWarnAllowedPacketOverflowed.GenWithStackByArgs("to_base64", b.maxAllowedPacket)) 3549 return "", true, nil 3550 } 3551 if b.tp.Flen == -1 || b.tp.Flen > allegrosql.MaxBlobWidth { 3552 return "", true, nil 3553 } 3554 3555 //encode 3556 strBytes := []byte(str) 3557 result := base64.StdEncoding.EncodeToString(strBytes) 3558 //A newline is added after each 76 characters of encoded output to divide long output into multiple lines. 3559 count := len(result) 3560 if count > 76 { 3561 resultArr := splitToSubN(result, 76) 3562 result = strings.Join(resultArr, "\n") 3563 } 3564 3565 return result, false, nil 3566 } 3567 3568 // splitToSubN splits a string every n runes into a string[] 3569 func splitToSubN(s string, n int) []string { 3570 subs := make([]string, 0, len(s)/n+1) 3571 for len(s) > n { 3572 subs = append(subs, s[:n]) 3573 s = s[n:] 3574 } 3575 subs = append(subs, s) 3576 return subs 3577 } 3578 3579 type insertFunctionClass struct { 3580 baseFunctionClass 3581 } 3582 3583 func (c *insertFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (sig builtinFunc, err error) { 3584 if err = c.verifyArgs(args); err != nil { 3585 return nil, err 3586 } 3587 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString, types.ETInt, types.ETInt, types.ETString) 3588 if err != nil { 3589 return nil, err 3590 } 3591 bf.tp.Flen = allegrosql.MaxBlobWidth 3592 SetBinFlagOrBinStr(args[0].GetType(), bf.tp) 3593 SetBinFlagOrBinStr(args[3].GetType(), bf.tp) 3594 3595 valStr, _ := ctx.GetStochastikVars().GetSystemVar(variable.MaxAllowedPacket) 3596 maxAllowedPacket, err := strconv.ParseUint(valStr, 10, 64) 3597 if err != nil { 3598 return nil, errors.Trace(err) 3599 } 3600 3601 if types.IsBinaryStr(args[0].GetType()) { 3602 sig = &builtinInsertSig{bf, maxAllowedPacket} 3603 sig.setPbCode(fidelpb.ScalarFuncSig_Insert) 3604 } else { 3605 sig = &builtinInsertUTF8Sig{bf, maxAllowedPacket} 3606 sig.setPbCode(fidelpb.ScalarFuncSig_InsertUTF8) 3607 } 3608 return sig, nil 3609 } 3610 3611 type builtinInsertSig struct { 3612 baseBuiltinFunc 3613 maxAllowedPacket uint64 3614 } 3615 3616 func (b *builtinInsertSig) Clone() builtinFunc { 3617 newSig := &builtinInsertSig{} 3618 newSig.cloneFrom(&b.baseBuiltinFunc) 3619 newSig.maxAllowedPacket = b.maxAllowedPacket 3620 return newSig 3621 } 3622 3623 // evalString evals INSERT(str,pos,len,newstr). 3624 // See https://dev.allegrosql.com/doc/refman/5.6/en/string-functions.html#function_insert 3625 func (b *builtinInsertSig) evalString(event chunk.Event) (string, bool, error) { 3626 str, isNull, err := b.args[0].EvalString(b.ctx, event) 3627 if isNull || err != nil { 3628 return "", true, err 3629 } 3630 3631 pos, isNull, err := b.args[1].EvalInt(b.ctx, event) 3632 if isNull || err != nil { 3633 return "", true, err 3634 } 3635 3636 length, isNull, err := b.args[2].EvalInt(b.ctx, event) 3637 if isNull || err != nil { 3638 return "", true, err 3639 } 3640 3641 newstr, isNull, err := b.args[3].EvalString(b.ctx, event) 3642 if isNull || err != nil { 3643 return "", true, err 3644 } 3645 3646 strLength := int64(len(str)) 3647 if pos < 1 || pos > strLength { 3648 return str, false, nil 3649 } 3650 if length > strLength-pos+1 || length < 0 { 3651 length = strLength - pos + 1 3652 } 3653 3654 if uint64(strLength-length+int64(len(newstr))) > b.maxAllowedPacket { 3655 b.ctx.GetStochastikVars().StmtCtx.AppendWarning(errWarnAllowedPacketOverflowed.GenWithStackByArgs("insert", b.maxAllowedPacket)) 3656 return "", true, nil 3657 } 3658 3659 return str[0:pos-1] + newstr + str[pos+length-1:], false, nil 3660 } 3661 3662 type builtinInsertUTF8Sig struct { 3663 baseBuiltinFunc 3664 maxAllowedPacket uint64 3665 } 3666 3667 func (b *builtinInsertUTF8Sig) Clone() builtinFunc { 3668 newSig := &builtinInsertUTF8Sig{} 3669 newSig.cloneFrom(&b.baseBuiltinFunc) 3670 newSig.maxAllowedPacket = b.maxAllowedPacket 3671 return newSig 3672 } 3673 3674 // evalString evals INSERT(str,pos,len,newstr). 3675 // See https://dev.allegrosql.com/doc/refman/5.6/en/string-functions.html#function_insert 3676 func (b *builtinInsertUTF8Sig) evalString(event chunk.Event) (string, bool, error) { 3677 str, isNull, err := b.args[0].EvalString(b.ctx, event) 3678 if isNull || err != nil { 3679 return "", true, err 3680 } 3681 3682 pos, isNull, err := b.args[1].EvalInt(b.ctx, event) 3683 if isNull || err != nil { 3684 return "", true, err 3685 } 3686 3687 length, isNull, err := b.args[2].EvalInt(b.ctx, event) 3688 if isNull || err != nil { 3689 return "", true, err 3690 } 3691 3692 newstr, isNull, err := b.args[3].EvalString(b.ctx, event) 3693 if isNull || err != nil { 3694 return "", true, err 3695 } 3696 3697 runes := []rune(str) 3698 runeLength := int64(len(runes)) 3699 if pos < 1 || pos > runeLength { 3700 return str, false, nil 3701 } 3702 if length > runeLength-pos+1 || length < 0 { 3703 length = runeLength - pos + 1 3704 } 3705 3706 strHead := string(runes[0 : pos-1]) 3707 strTail := string(runes[pos+length-1:]) 3708 if uint64(len(strHead)+len(newstr)+len(strTail)) > b.maxAllowedPacket { 3709 b.ctx.GetStochastikVars().StmtCtx.AppendWarning(errWarnAllowedPacketOverflowed.GenWithStackByArgs("insert", b.maxAllowedPacket)) 3710 return "", true, nil 3711 } 3712 return strHead + newstr + strTail, false, nil 3713 } 3714 3715 type instrFunctionClass struct { 3716 baseFunctionClass 3717 } 3718 3719 func (c *instrFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 3720 if err := c.verifyArgs(args); err != nil { 3721 return nil, err 3722 } 3723 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETInt, types.ETString, types.ETString) 3724 if err != nil { 3725 return nil, err 3726 } 3727 bf.tp.Flen = 11 3728 if bf.defCauslation == charset.DefCauslationBin { 3729 sig := &builtinInstrSig{bf} 3730 sig.setPbCode(fidelpb.ScalarFuncSig_Instr) 3731 return sig, nil 3732 } 3733 sig := &builtinInstrUTF8Sig{bf} 3734 sig.setPbCode(fidelpb.ScalarFuncSig_InstrUTF8) 3735 return sig, nil 3736 } 3737 3738 type builtinInstrUTF8Sig struct{ baseBuiltinFunc } 3739 3740 func (b *builtinInstrUTF8Sig) Clone() builtinFunc { 3741 newSig := &builtinInstrUTF8Sig{} 3742 newSig.cloneFrom(&b.baseBuiltinFunc) 3743 return newSig 3744 } 3745 3746 type builtinInstrSig struct{ baseBuiltinFunc } 3747 3748 func (b *builtinInstrSig) Clone() builtinFunc { 3749 newSig := &builtinInstrSig{} 3750 newSig.cloneFrom(&b.baseBuiltinFunc) 3751 return newSig 3752 } 3753 3754 // evalInt evals INSTR(str,substr). 3755 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_instr 3756 func (b *builtinInstrUTF8Sig) evalInt(event chunk.Event) (int64, bool, error) { 3757 str, IsNull, err := b.args[0].EvalString(b.ctx, event) 3758 if IsNull || err != nil { 3759 return 0, true, err 3760 } 3761 substr, IsNull, err := b.args[1].EvalString(b.ctx, event) 3762 if IsNull || err != nil { 3763 return 0, true, err 3764 } 3765 if defCauslate.IsCIDefCauslation(b.defCauslation) { 3766 str = strings.ToLower(str) 3767 substr = strings.ToLower(substr) 3768 } 3769 3770 idx := strings.Index(str, substr) 3771 if idx == -1 { 3772 return 0, false, nil 3773 } 3774 return int64(utf8.RuneCountInString(str[:idx]) + 1), false, nil 3775 } 3776 3777 // evalInt evals INSTR(str,substr), case sensitive. 3778 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_instr 3779 func (b *builtinInstrSig) evalInt(event chunk.Event) (int64, bool, error) { 3780 str, IsNull, err := b.args[0].EvalString(b.ctx, event) 3781 if IsNull || err != nil { 3782 return 0, true, err 3783 } 3784 3785 substr, IsNull, err := b.args[1].EvalString(b.ctx, event) 3786 if IsNull || err != nil { 3787 return 0, true, err 3788 } 3789 3790 idx := strings.Index(str, substr) 3791 if idx == -1 { 3792 return 0, false, nil 3793 } 3794 return int64(idx + 1), false, nil 3795 } 3796 3797 type loadFileFunctionClass struct { 3798 baseFunctionClass 3799 } 3800 3801 func (c *loadFileFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 3802 return nil, errFunctionNotExists.GenWithStackByArgs("FUNCTION", "load_file") 3803 } 3804 3805 type weightStringPadding byte 3806 3807 const ( 3808 // weightStringPaddingNone is used for WEIGHT_STRING(expr) if the expr is non-numeric. 3809 weightStringPaddingNone weightStringPadding = iota 3810 // weightStringPaddingAsChar is used for WEIGHT_STRING(expr AS CHAR(x)) and the expr is non-numeric. 3811 weightStringPaddingAsChar 3812 // weightStringPaddingAsBinary is used for WEIGHT_STRING(expr as BINARY(x)) and the expr is not null. 3813 weightStringPaddingAsBinary 3814 // weightStringPaddingNull is used for WEIGHT_STRING(expr [AS (CHAR|BINARY)]) for all other cases, it returns null always. 3815 weightStringPaddingNull 3816 ) 3817 3818 type weightStringFunctionClass struct { 3819 baseFunctionClass 3820 } 3821 3822 func (c *weightStringFunctionClass) verifyArgs(args []Expression) (weightStringPadding, int, error) { 3823 padding := weightStringPaddingNone 3824 l := len(args) 3825 if l != 1 && l != 3 { 3826 return weightStringPaddingNone, 0, ErrIncorrectParameterCount.GenWithStackByArgs(c.funcName) 3827 } 3828 if types.IsTypeNumeric(args[0].GetType().Tp) { 3829 padding = weightStringPaddingNull 3830 } 3831 length := 0 3832 if l == 3 { 3833 if args[1].GetType().EvalType() != types.ETString { 3834 return weightStringPaddingNone, 0, ErrIncorrectType.GenWithStackByArgs(args[1].String(), c.funcName) 3835 } 3836 c1, ok := args[1].(*Constant) 3837 if !ok { 3838 return weightStringPaddingNone, 0, ErrIncorrectType.GenWithStackByArgs(args[1].String(), c.funcName) 3839 } 3840 switch x := c1.Value.GetString(); x { 3841 case "CHAR": 3842 if padding == weightStringPaddingNone { 3843 padding = weightStringPaddingAsChar 3844 } 3845 case "BINARY": 3846 padding = weightStringPaddingAsBinary 3847 default: 3848 return weightStringPaddingNone, 0, ErrIncorrectType.GenWithStackByArgs(x, c.funcName) 3849 } 3850 if args[2].GetType().EvalType() != types.ETInt { 3851 return weightStringPaddingNone, 0, ErrIncorrectType.GenWithStackByArgs(args[2].String(), c.funcName) 3852 } 3853 c2, ok := args[2].(*Constant) 3854 if !ok { 3855 return weightStringPaddingNone, 0, ErrIncorrectType.GenWithStackByArgs(args[1].String(), c.funcName) 3856 } 3857 length = int(c2.Value.GetInt64()) 3858 if length == 0 { 3859 return weightStringPaddingNone, 0, ErrIncorrectType.GenWithStackByArgs(args[2].String(), c.funcName) 3860 } 3861 } 3862 return padding, length, nil 3863 } 3864 3865 func (c *weightStringFunctionClass) getFunction(ctx stochastikctx.Context, args []Expression) (builtinFunc, error) { 3866 padding, length, err := c.verifyArgs(args) 3867 if err != nil { 3868 return nil, err 3869 } 3870 argTps := make([]types.EvalType, len(args)) 3871 argTps[0] = types.ETString 3872 3873 if len(args) == 3 { 3874 argTps[1] = types.ETString 3875 argTps[2] = types.ETInt 3876 } 3877 3878 bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, argTps...) 3879 if err != nil { 3880 return nil, err 3881 } 3882 var sig builtinFunc 3883 if padding == weightStringPaddingNull { 3884 sig = &builtinWeightStringNullSig{bf} 3885 } else { 3886 sig = &builtinWeightStringSig{bf, padding, length} 3887 } 3888 return sig, nil 3889 } 3890 3891 type builtinWeightStringNullSig struct { 3892 baseBuiltinFunc 3893 } 3894 3895 func (b *builtinWeightStringNullSig) Clone() builtinFunc { 3896 newSig := &builtinWeightStringNullSig{} 3897 newSig.cloneFrom(&b.baseBuiltinFunc) 3898 return newSig 3899 } 3900 3901 // evalString evals a WEIGHT_STRING(expr [AS CHAR|BINARY]) when the expr is numeric types, it always returns null. 3902 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_weight-string 3903 func (b *builtinWeightStringNullSig) evalString(event chunk.Event) (string, bool, error) { 3904 return "", true, nil 3905 } 3906 3907 type builtinWeightStringSig struct { 3908 baseBuiltinFunc 3909 3910 padding weightStringPadding 3911 length int 3912 } 3913 3914 func (b *builtinWeightStringSig) Clone() builtinFunc { 3915 newSig := &builtinWeightStringSig{} 3916 newSig.cloneFrom(&b.baseBuiltinFunc) 3917 newSig.padding = b.padding 3918 newSig.length = b.length 3919 return newSig 3920 } 3921 3922 // evalString evals a WEIGHT_STRING(expr [AS (CHAR|BINARY)]) when the expr is non-numeric types. 3923 // See https://dev.allegrosql.com/doc/refman/5.7/en/string-functions.html#function_weight-string 3924 func (b *builtinWeightStringSig) evalString(event chunk.Event) (string, bool, error) { 3925 str, isNull, err := b.args[0].EvalString(b.ctx, event) 3926 if err != nil { 3927 return "", false, err 3928 } 3929 if isNull { 3930 return "", true, nil 3931 } 3932 3933 var ctor defCauslate.DefCauslator 3934 // TODO: refactor padding codes after padding is implemented by all defCauslators. 3935 switch b.padding { 3936 case weightStringPaddingAsChar: 3937 runes := []rune(str) 3938 lenRunes := len(runes) 3939 if b.length < lenRunes { 3940 str = string(runes[:b.length]) 3941 } else if b.length > lenRunes { 3942 str += strings.Repeat(" ", b.length-lenRunes) 3943 } 3944 ctor = defCauslate.GetDefCauslator(b.args[0].GetType().DefCauslate) 3945 case weightStringPaddingAsBinary: 3946 lenStr := len(str) 3947 if b.length < lenStr { 3948 tpInfo := fmt.Sprintf("BINARY(%d)", b.length) 3949 b.ctx.GetStochastikVars().StmtCtx.AppendWarning(errTruncatedWrongValue.GenWithStackByArgs(tpInfo, str)) 3950 str = str[:b.length] 3951 } else if b.length > lenStr { 3952 str += strings.Repeat("\x00", b.length-lenStr) 3953 } 3954 ctor = defCauslate.GetDefCauslator(charset.DefCauslationBin) 3955 case weightStringPaddingNone: 3956 ctor = defCauslate.GetDefCauslator(b.args[0].GetType().DefCauslate) 3957 default: 3958 return "", false, ErrIncorrectType.GenWithStackByArgs(ast.WeightString, string(b.padding)) 3959 } 3960 return string(ctor.Key(str)), false, nil 3961 }