Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expression: fix the collation of functions with json arguments (#53126) #53202

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions expression/builtin_ilike.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ func (b *builtinIlikeSig) evalInt(row chunk.Row) (int64, bool, error) {
valStr = string(valStrBytes)
patternStr = string(patternStrBytes)

<<<<<<< HEAD:expression/builtin_ilike.go
memorization := func() {
if b.pattern == nil {
b.pattern = collate.ConvertAndGetBinCollation(b.collation).Pattern()
Expand All @@ -107,6 +108,23 @@ func (b *builtinIlikeSig) evalInt(row chunk.Row) (int64, bool, error) {
b.isMemorizedPattern = true
}
}
=======
var pattern collate.WildcardPattern
if b.args[1].ConstLevel() >= ConstOnlyInContext && b.args[2].ConstLevel() >= ConstOnlyInContext {
pattern, err = b.patternCache.getOrInitCache(ctx, func() (collate.WildcardPattern, error) {
ret := collate.ConvertAndGetBinCollator(b.collation).Pattern()
ret.Compile(patternStr, byte(escape))
return ret, nil
})

intest.AssertNoError(err)
if err != nil {
return 0, true, err
}
} else {
pattern = collate.ConvertAndGetBinCollator(b.collation).Pattern()
pattern.Compile(patternStr, byte(escape))
>>>>>>> dcd1fa9d967 (expression: fix the collation of functions with json arguments (#53126)):pkg/expression/builtin_ilike.go
}
// Only be executed once to achieve thread-safe
b.once.Do(memorization)
Expand Down
19 changes: 19 additions & 0 deletions expression/builtin_ilike_vec.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,24 @@ func (b *builtinIlikeSig) tryToMemorize(param *funcParam, escape int64) {
return
}

<<<<<<< HEAD:expression/builtin_ilike_vec.go
memorization := func() {
if b.pattern == nil {
b.pattern = collate.ConvertAndGetBinCollation(b.collation).Pattern()
b.pattern.Compile(param.getStringVal(0), byte(escape))
b.isMemorizedPattern = true
}
=======
pattern, err := b.patternCache.getOrInitCache(ctx, func() (collate.WildcardPattern, error) {
pattern := collate.ConvertAndGetBinCollator(b.collation).Pattern()
pattern.Compile(param.getStringVal(0), byte(escape))
return pattern, nil
})

intest.AssertNoError(err)
if err != nil {
return nil, false
>>>>>>> dcd1fa9d967 (expression: fix the collation of functions with json arguments (#53126)):pkg/expression/builtin_ilike_vec.go
}

// Only be executed once to achieve thread-safe
Expand Down Expand Up @@ -196,10 +208,17 @@ func (b *builtinIlikeSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) e
b.lowerExpr(params[0], rowNum)
escape = b.lowerPattern(params[1], rowNum, escape)

<<<<<<< HEAD:expression/builtin_ilike_vec.go
b.tryToMemorize(params[1], escape)
if !b.isMemorizedPattern {
b.pattern = collate.ConvertAndGetBinCollation(b.collation).Pattern()
return b.ilikeWithoutMemorization(params, rowNum, escape, result)
=======
pattern, ok := b.tryToVecMemorize(ctx, params[1], escape)
if !ok {
pattern = collate.ConvertAndGetBinCollator(b.collation).Pattern()
return b.ilikeWithoutMemorization(pattern, params, rowNum, escape, result)
>>>>>>> dcd1fa9d967 (expression: fix the collation of functions with json arguments (#53126)):pkg/expression/builtin_ilike_vec.go
}

return b.ilikeWithMemorization(params[0], rowNum, result)
Expand Down
40 changes: 39 additions & 1 deletion expression/collation.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,45 @@ func CheckAndDeriveCollationFromExprs(ctx sessionctx.Context, funcName string, e
return nil, illegalMixCollationErr(funcName, args)
}

return ec, nil
return fixStringTypeForMaxLength(funcName, args, ec), nil
}

// fixStringTypeForMaxLength changes the type of string from `VARCHAR` to `MEDIUM BLOB` or `LONG BLOB` according to the max length of
// the argument. However, as TiDB doesn't have `MaxLength` for `FieldType`, this function handles the logic manually for different types. Now it only
// handles the `JSON` type, because in MySQL, `JSON` type has a big max length and will lead to `LONG BLOB` in many situations.
// To learn more about this case, read the discussion under https://github.com/pingcap/tidb/issues/52833
//
// TODO: also consider types other than `JSON`. And also think about when it'll become `MEDIUM BLOB`. This function only handles the collation, but
// not change the type and binary flag.
// TODO: some function will generate big values, like `repeat` and `space`. They should be handled according to the argument if it's a constant.
func fixStringTypeForMaxLength(funcName string, args []Expression, ec *ExprCollation) *ExprCollation {
// Be careful that the `args` is not all arguments of the `funcName`. You should check `deriveCollation` function to see which arguments are passed
// to the `CheckAndDeriveCollationFromExprs` function, and then passed here.
shouldChangeToBin := false

switch funcName {
case ast.Reverse, ast.Lower, ast.Upper, ast.SubstringIndex, ast.Trim, ast.Quote, ast.InsertFunc, ast.Substr, ast.Repeat, ast.Replace:
shouldChangeToBin = args[0].GetType().EvalType() == types.ETJson
case ast.Concat, ast.ConcatWS, ast.Elt, ast.MakeSet:
for _, arg := range args {
if arg.GetType().EvalType() == types.ETJson {
shouldChangeToBin = true
break
}
}
case ast.ExportSet:
if len(args) >= 2 {
shouldChangeToBin = args[0].GetType().EvalType() == types.ETJson || args[1].GetType().EvalType() == types.ETJson
}
if len(args) >= 3 {
shouldChangeToBin = shouldChangeToBin || args[2].GetType().EvalType() == types.ETJson
}
}

if shouldChangeToBin {
ec.Collation = collate.ConvertAndGetBinCollation(ec.Collation)
}
return ec
}

func safeConvert(ctx sessionctx.Context, ec *ExprCollation, args ...Expression) bool {
Expand Down
Loading