Skip to content

Commit 7ad87bc

Browse files
Defined2014ti-chi-bot
authored andcommitted
This is an automated cherry-pick of pingcap#55724
Signed-off-by: ti-chi-bot <[email protected]>
1 parent 1e2bb37 commit 7ad87bc

File tree

13 files changed

+198
-7
lines changed

13 files changed

+198
-7
lines changed

pkg/expression/bench_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1449,7 +1449,7 @@ func genVecBuiltinFuncBenchCase(ctx BuildContext, funcName string, testCase vecE
14491449
case types.ETJson:
14501450
fc = &castAsJSONFunctionClass{baseFunctionClass{ast.Cast, 1, 1}, tp}
14511451
case types.ETString:
1452-
fc = &castAsStringFunctionClass{baseFunctionClass{ast.Cast, 1, 1}, tp}
1452+
fc = &castAsStringFunctionClass{baseFunctionClass{ast.Cast, 1, 1}, tp, false}
14531453
}
14541454
baseFunc, err = fc.getFunction(ctx, cols)
14551455
} else if funcName == ast.GetVar {

pkg/expression/builtin.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,35 @@ func newBaseBuiltinCastFunc(builtinFunc baseBuiltinFunc, inUnion bool) baseBuilt
448448
}
449449
}
450450

451+
func newBaseBuiltinCastFunc4String(ctx BuildContext, funcName string, args []Expression, tp *types.FieldType, isExplicitCharset bool) (baseBuiltinFunc, error) {
452+
var bf baseBuiltinFunc
453+
var err error
454+
if isExplicitCharset {
455+
bf = baseBuiltinFunc{
456+
bufAllocator: newLocalColumnPool(),
457+
childrenVectorizedOnce: new(sync.Once),
458+
459+
args: args,
460+
tp: tp,
461+
}
462+
bf.SetCharsetAndCollation(tp.GetCharset(), tp.GetCollate())
463+
bf.setCollator(collate.GetCollator(tp.GetCollate()))
464+
bf.SetCoercibility(CoercibilityExplicit)
465+
bf.SetExplicitCharset(true)
466+
if tp.GetCharset() == charset.CharsetASCII {
467+
bf.SetRepertoire(ASCII)
468+
} else {
469+
bf.SetRepertoire(UNICODE)
470+
}
471+
} else {
472+
bf, err = newBaseBuiltinFunc(ctx, funcName, args, tp)
473+
if err != nil {
474+
return baseBuiltinFunc{}, err
475+
}
476+
}
477+
return bf, nil
478+
}
479+
451480
// vecBuiltinFunc contains all vectorized methods for a builtin function.
452481
type vecBuiltinFunc interface {
453482
// vectorized returns if this builtin function itself supports vectorized evaluation.

pkg/expression/builtin_cast.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,14 +270,15 @@ func (c *castAsDecimalFunctionClass) getFunction(ctx BuildContext, args []Expres
270270
type castAsStringFunctionClass struct {
271271
baseFunctionClass
272272

273-
tp *types.FieldType
273+
tp *types.FieldType
274+
isExplicitCharset bool
274275
}
275276

276277
func (c *castAsStringFunctionClass) getFunction(ctx BuildContext, args []Expression) (sig builtinFunc, err error) {
277278
if err := c.verifyArgs(args); err != nil {
278279
return nil, err
279280
}
280-
bf, err := newBaseBuiltinFunc(ctx, c.funcName, args, c.tp)
281+
bf, err := newBaseBuiltinCastFunc4String(ctx, c.funcName, args, c.tp, c.isExplicitCharset)
281282
if err != nil {
282283
return nil, err
283284
}
@@ -2053,11 +2054,17 @@ func CanImplicitEvalReal(expr Expression) bool {
20532054
// BuildCastFunction4Union build a implicitly CAST ScalarFunction from the Union
20542055
// Expression.
20552056
func BuildCastFunction4Union(ctx BuildContext, expr Expression, tp *types.FieldType) (res Expression) {
2057+
<<<<<<< HEAD
20562058
ctx.SetValue(inUnionCastContext, struct{}{})
20572059
defer func() {
20582060
ctx.SetValue(inUnionCastContext, nil)
20592061
}()
20602062
return BuildCastFunction(ctx, expr, tp)
2063+
=======
2064+
res, err := BuildCastFunctionWithCheck(ctx, expr, tp, true, false)
2065+
terror.Log(err)
2066+
return
2067+
>>>>>>> e0864c6cf1d (expression: let `cast` function supports explicit set charset (#55724))
20612068
}
20622069

20632070
// BuildCastCollationFunction builds a ScalarFunction which casts the collation.
@@ -2092,14 +2099,23 @@ func BuildCastCollationFunction(ctx BuildContext, expr Expression, ec *ExprColla
20922099

20932100
// BuildCastFunction builds a CAST ScalarFunction from the Expression.
20942101
func BuildCastFunction(ctx BuildContext, expr Expression, tp *types.FieldType) (res Expression) {
2102+
<<<<<<< HEAD
20952103
res, err := BuildCastFunctionWithCheck(ctx, expr, tp)
2104+
=======
2105+
res, err := BuildCastFunctionWithCheck(ctx, expr, tp, false, false)
2106+
>>>>>>> e0864c6cf1d (expression: let `cast` function supports explicit set charset (#55724))
20962107
terror.Log(err)
20972108
return
20982109
}
20992110

21002111
// BuildCastFunctionWithCheck builds a CAST ScalarFunction from the Expression and return error if any.
2112+
<<<<<<< HEAD
21012113
func BuildCastFunctionWithCheck(ctx BuildContext, expr Expression, tp *types.FieldType) (res Expression, err error) {
21022114
argType := expr.GetType()
2115+
=======
2116+
func BuildCastFunctionWithCheck(ctx BuildContext, expr Expression, tp *types.FieldType, inUnion bool, isExplicitCharset bool) (res Expression, err error) {
2117+
argType := expr.GetType(ctx.GetEvalCtx())
2118+
>>>>>>> e0864c6cf1d (expression: let `cast` function supports explicit set charset (#55724))
21032119
// If source argument's nullable, then target type should be nullable
21042120
if !mysql.HasNotNullFlag(argType.GetFlag()) {
21052121
tp.DelFlag(mysql.NotNullFlag)
@@ -2124,9 +2140,15 @@ func BuildCastFunctionWithCheck(ctx BuildContext, expr Expression, tp *types.Fie
21242140
fc = &castAsJSONFunctionClass{baseFunctionClass{ast.Cast, 1, 1}, tp}
21252141
}
21262142
case types.ETString:
2143+
<<<<<<< HEAD
21272144
fc = &castAsStringFunctionClass{baseFunctionClass{ast.Cast, 1, 1}, tp}
21282145
if expr.GetType().GetType() == mysql.TypeBit {
21292146
tp.SetFlen((expr.GetType().GetFlen() + 7) / 8)
2147+
=======
2148+
fc = &castAsStringFunctionClass{baseFunctionClass{ast.Cast, 1, 1}, tp, isExplicitCharset}
2149+
if expr.GetType(ctx.GetEvalCtx()).GetType() == mysql.TypeBit {
2150+
tp.SetFlen((expr.GetType(ctx.GetEvalCtx()).GetFlen() + 7) / 8)
2151+
>>>>>>> e0864c6cf1d (expression: let `cast` function supports explicit set charset (#55724))
21302152
}
21312153
}
21322154
f, err := fc.getFunction(ctx, []Expression{expr})

pkg/expression/builtin_cast_test.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ func TestCastFuncSig(t *testing.T) {
655655
tp := types.NewFieldType(mysql.TypeVarString)
656656
tp.SetCharset(charset.CharsetBin)
657657
args := []Expression{c.before}
658-
stringFunc, err := newBaseBuiltinFunc(ctx, "", args, tp)
658+
stringFunc, err := newBaseBuiltinCastFunc4String(ctx, "", args, tp, false)
659659
require.NoError(t, err)
660660
switch i {
661661
case 0:
@@ -742,7 +742,7 @@ func TestCastFuncSig(t *testing.T) {
742742
tp := types.NewFieldType(mysql.TypeVarString)
743743
tp.SetFlen(c.flen)
744744
tp.SetCharset(charset.CharsetBin)
745-
stringFunc, err := newBaseBuiltinFunc(ctx, "", args, tp)
745+
stringFunc, err := newBaseBuiltinCastFunc4String(ctx, "", args, tp, false)
746746
require.NoError(t, err)
747747
switch i {
748748
case 0:
@@ -1099,7 +1099,7 @@ func TestCastFuncSig(t *testing.T) {
10991099
// null case
11001100
args := []Expression{&Column{RetType: types.NewFieldType(mysql.TypeDouble), Index: 0}}
11011101
row := chunk.MutRowFromDatums([]types.Datum{types.NewDatum(nil)})
1102-
bf, err := newBaseBuiltinFunc(ctx, "", args, types.NewFieldType(mysql.TypeVarString))
1102+
bf, err := newBaseBuiltinCastFunc4String(ctx, "", args, types.NewFieldType(mysql.TypeVarString), false)
11031103
require.NoError(t, err)
11041104
sig = &builtinCastRealAsStringSig{bf}
11051105
sRes, err := evalBuiltinFunc(sig, ctx, row.ToRow())
@@ -1694,7 +1694,11 @@ func TestCastArrayFunc(t *testing.T) {
16941694
},
16951695
}
16961696
for _, tt := range tbl {
1697+
<<<<<<< HEAD
16971698
f, err := BuildCastFunctionWithCheck(ctx, datumsToConstants(types.MakeDatums(types.CreateBinaryJSON(tt.input)))[0], tt.tp)
1699+
=======
1700+
f, err := BuildCastFunctionWithCheck(ctx, datumsToConstants(types.MakeDatums(types.CreateBinaryJSON(tt.input)))[0], tt.tp, false, false)
1701+
>>>>>>> e0864c6cf1d (expression: let `cast` function supports explicit set charset (#55724))
16981702
if !tt.buildFuncSuccess {
16991703
require.Error(t, err, tt.input)
17001704
continue

pkg/expression/collation.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,46 @@ type collationInfo struct {
4343

4444
charset string
4545
collation string
46+
47+
isExplicitCharset bool
48+
}
49+
50+
<<<<<<< HEAD
51+
=======
52+
// Hash64 implements the base.Hasher.<0th> interface.
53+
func (c *collationInfo) Hash64(h base.Hasher) {
54+
h.HashInt64(int64(c.coer))
55+
h.HashBool(c.coerInit.Load())
56+
h.HashInt(int(c.repertoire))
57+
h.HashString(c.charset)
58+
h.HashString(c.collation)
59+
h.HashBool(c.isExplicitCharset)
60+
}
61+
62+
// Equals implements the base.Hasher.<1th> interface.
63+
func (c *collationInfo) Equals(other any) bool {
64+
// the caller should care about c is nil or not.
65+
if other == nil {
66+
return false
67+
}
68+
var c2 *collationInfo
69+
switch x := other.(type) {
70+
case *collationInfo:
71+
c2 = x
72+
case collationInfo:
73+
c2 = &x
74+
default:
75+
return false
76+
}
77+
return c.coer == c2.coer &&
78+
c.coerInit.Load() == c2.coerInit.Load() &&
79+
c.repertoire == c2.repertoire &&
80+
c.charset == c2.charset &&
81+
c.collation == c2.collation &&
82+
c.isExplicitCharset == c2.isExplicitCharset
4683
}
4784

85+
>>>>>>> e0864c6cf1d (expression: let `cast` function supports explicit set charset (#55724))
4886
func (c *collationInfo) HasCoercibility() bool {
4987
return c.coerInit.Load()
5088
}
@@ -75,6 +113,14 @@ func (c *collationInfo) CharsetAndCollation() (string, string) {
75113
return c.charset, c.collation
76114
}
77115

116+
func (c *collationInfo) IsExplicitCharset() bool {
117+
return c.isExplicitCharset
118+
}
119+
120+
func (c *collationInfo) SetExplicitCharset(explicit bool) {
121+
c.isExplicitCharset = explicit
122+
}
123+
78124
// CollationInfo contains all interfaces about dealing with collation.
79125
type CollationInfo interface {
80126
// HasCoercibility returns if the Coercibility value is initialized.
@@ -97,6 +143,12 @@ type CollationInfo interface {
97143

98144
// SetCharsetAndCollation sets charset and collation.
99145
SetCharsetAndCollation(chs, coll string)
146+
147+
// IsExplicitCharset return the charset is explicit set or not.
148+
IsExplicitCharset() bool
149+
150+
// SetExplicitCharset set the charset is explicit or not.
151+
SetExplicitCharset(bool)
100152
}
101153

102154
// Coercibility values are used to check whether the collation of one item can be coerced to
@@ -244,10 +296,16 @@ func deriveCollation(ctx BuildContext, funcName string, args []Expression, retTy
244296
return &ExprCollation{args[1].Coercibility(), args[1].Repertoire(), charsetInfo, collation}, nil
245297
case ast.Cast:
246298
// We assume all the cast are implicit.
299+
<<<<<<< HEAD
247300
ec = &ExprCollation{args[0].Coercibility(), args[0].Repertoire(), args[0].GetType().GetCharset(), args[0].GetType().GetCollate()}
248301
// Non-string type cast to string type should use @@character_set_connection and @@collation_connection.
249302
// String type cast to string type should keep its original charset and collation. It should not happen.
250303
if retType == types.ETString && argTps[0] != types.ETString {
304+
=======
305+
ec = &ExprCollation{args[0].Coercibility(), args[0].Repertoire(), args[0].GetType(ctx.GetEvalCtx()).GetCharset(), args[0].GetType(ctx.GetEvalCtx()).GetCollate()}
306+
// Cast to string type should use @@character_set_connection and @@collation_connection.
307+
if retType == types.ETString {
308+
>>>>>>> e0864c6cf1d (expression: let `cast` function supports explicit set charset (#55724))
251309
ec.Charset, ec.Collation = ctx.GetCharsetInfo()
252310
}
253311
return ec, nil

pkg/expression/scalar_function.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,16 @@ func (sf *ScalarFunction) SetRepertoire(r Repertoire) {
824824
sf.Function.SetRepertoire(r)
825825
}
826826

827+
// IsExplicitCharset return the charset is explicit set or not.
828+
func (sf *ScalarFunction) IsExplicitCharset() bool {
829+
return sf.Function.IsExplicitCharset()
830+
}
831+
832+
// SetExplicitCharset set the charset is explicit or not.
833+
func (sf *ScalarFunction) SetExplicitCharset(explicit bool) {
834+
sf.Function.SetExplicitCharset(explicit)
835+
}
836+
827837
const emptyScalarFunctionSize = int64(unsafe.Sizeof(ScalarFunction{}))
828838

829839
// MemoryUsage return the memory usage of ScalarFunction

pkg/expression/util.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,8 +455,10 @@ func ColumnSubstituteImpl(ctx BuildContext, expr Expression, schema *Schema, new
455455
if substituted {
456456
flag := v.RetType.GetFlag()
457457
var e Expression
458+
var err error
458459
if v.FuncName.L == ast.Cast {
459-
e = BuildCastFunction(ctx, newArg, v.RetType)
460+
e, err = BuildCastFunctionWithCheck(ctx, newArg, v.RetType, false, v.Function.IsExplicitCharset())
461+
terror.Log(err)
460462
} else {
461463
// for grouping function recreation, use clone (meta included) instead of newFunction
462464
e = v.Clone()

pkg/expression/util_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,8 @@ func (m *MockExpr) Coercibility() Coercibility { return
593593
func (m *MockExpr) SetCoercibility(Coercibility) {}
594594
func (m *MockExpr) Repertoire() Repertoire { return UNICODE }
595595
func (m *MockExpr) SetRepertoire(Repertoire) {}
596+
func (m *MockExpr) IsExplicitCharset() bool { return false }
597+
func (m *MockExpr) SetExplicitCharset(bool) {}
596598

597599
func (m *MockExpr) CharsetAndCollation() (string, string) {
598600
return "", ""

pkg/planner/core/expression_rewriter.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,7 +1485,11 @@ func (er *expressionRewriter) Leave(originInNode ast.Node) (retNode ast.Node, ok
14851485
return retNode, false
14861486
}
14871487

1488+
<<<<<<< HEAD
14881489
castFunction, err := expression.BuildCastFunctionWithCheck(er.sctx, arg, v.Tp)
1490+
=======
1491+
castFunction, err := expression.BuildCastFunctionWithCheck(er.sctx, arg, v.Tp, false, v.ExplicitCharSet)
1492+
>>>>>>> e0864c6cf1d (expression: let `cast` function supports explicit set charset (#55724))
14891493
if err != nil {
14901494
er.err = err
14911495
return retNode, false

tests/integrationtest/r/executor/executor.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4578,4 +4578,5 @@ LOCK TABLE executor__executor.t WRITE, test2.t2 WRITE;
45784578
LOCK TABLE executor__executor.t WRITE, test2.t2 WRITE;
45794579
Error 8020 (HY000): Table 't' was locked in WRITE by server: <server> session: <session>
45804580
unlock tables;
4581+
unlock tables;
45814582
drop user 'testuser'@'localhost';

0 commit comments

Comments
 (0)