Skip to content

Commit 1d2e773

Browse files
lcwangchaoti-chi-bot
authored andcommitted
This is an automated cherry-pick of pingcap#57484
Signed-off-by: ti-chi-bot <[email protected]>
1 parent eee9ab7 commit 1d2e773

File tree

9 files changed

+150
-2
lines changed

9 files changed

+150
-2
lines changed

pkg/expression/builtin_cast.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,27 @@ func (c *castAsStringFunctionClass) getFunction(ctx BuildContext, args []Express
282282
if err != nil {
283283
return nil, err
284284
}
285+
<<<<<<< HEAD
285286
if args[0].GetType().Hybrid() {
286287
sig = &builtinCastStringAsStringSig{bf}
287288
sig.setPbCode(tipb.ScalarFuncSig_CastStringAsString)
288289
return sig, nil
290+
=======
291+
if ft := args[0].GetType(ctx.GetEvalCtx()); ft.Hybrid() {
292+
castBitAsUnBinary := ft.GetType() == mysql.TypeBit && c.tp.GetCharset() != charset.CharsetBin
293+
if !castBitAsUnBinary {
294+
sig = &builtinCastStringAsStringSig{bf}
295+
sig.setPbCode(tipb.ScalarFuncSig_CastStringAsString)
296+
return sig, nil
297+
}
298+
// for type BIT, it maybe an invalid value for the specified charset, we need to convert it to binary first,
299+
// and then convert it to the specified charset with `HandleBinaryLiteral` in the following code.
300+
tp := types.NewFieldType(mysql.TypeString)
301+
tp.SetCharset(charset.CharsetBin)
302+
tp.SetCollate(charset.CollationBin)
303+
tp.AddFlag(mysql.BinaryFlag)
304+
args[0] = BuildCastFunction(ctx, args[0], tp)
305+
>>>>>>> 38104f4f328 (expression: fix tikv crash when `bool like cast(bit as char)` (#57484))
289306
}
290307
argTp := args[0].GetType().EvalType()
291308
switch argTp {

pkg/expression/builtin_convert_charset.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ type builtinInternalFromBinarySig struct {
169169
func (b *builtinInternalFromBinarySig) Clone() builtinFunc {
170170
newSig := &builtinInternalFromBinarySig{}
171171
newSig.cloneFrom(&b.baseBuiltinFunc)
172+
newSig.cannotConvertStringAsWarning = b.cannotConvertStringAsWarning
172173
return newSig
173174
}
174175

pkg/expression/expr_to_pb_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1579,6 +1579,33 @@ func TestExprPushDownToTiKV(t *testing.T) {
15791579
require.Len(t, pushed, 0)
15801580
require.Len(t, remained, len(exprs))
15811581

1582+
<<<<<<< HEAD
1583+
=======
1584+
// Test Conv function, `conv` function for a BIT column should not be pushed down for its special behavior which
1585+
// is only handled in TiDB currently.
1586+
// see issue: https://github.com/pingcap/tidb/issues/51877
1587+
exprs = exprs[:0]
1588+
function, err = NewFunction(mock.NewContext(), ast.Conv, types.NewFieldType(mysql.TypeString), stringColumn, intColumn, intColumn)
1589+
require.NoError(t, err)
1590+
exprs = append(exprs, function)
1591+
pushed, remained = PushDownExprs(pushDownCtx, exprs, kv.TiKV)
1592+
require.Len(t, pushed, len(exprs))
1593+
require.Len(t, remained, 0)
1594+
exprs = exprs[:0]
1595+
// when conv a column with type BIT, a cast function will be used to cast bit to a binary string
1596+
castTp := types.NewFieldType(mysql.TypeString)
1597+
castTp.SetCharset(charset.CharsetBin)
1598+
castTp.SetCollate(charset.CollationBin)
1599+
castByteAsStringFunc, err := NewFunction(mock.NewContext(), ast.Cast, castTp, byteColumn)
1600+
require.NoError(t, err)
1601+
function, err = NewFunction(mock.NewContext(), ast.Conv, types.NewFieldType(mysql.TypeString), castByteAsStringFunc, intColumn, intColumn)
1602+
require.NoError(t, err)
1603+
exprs = append(exprs, function)
1604+
pushed, remained = PushDownExprs(pushDownCtx, exprs, kv.TiKV)
1605+
require.Len(t, pushed, 0)
1606+
require.Len(t, remained, len(exprs))
1607+
1608+
>>>>>>> 38104f4f328 (expression: fix tikv crash when `bool like cast(bit as char)` (#57484))
15821609
// Test exprs that can be pushed.
15831610
exprs = exprs[:0]
15841611
pushed = pushed[:0]

pkg/planner/core/integration_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,15 +330,15 @@ func TestBitColumnPushDown(t *testing.T) {
330330
tk.MustQuery(sql).Check(testkit.Rows("A"))
331331
tk.MustQuery(fmt.Sprintf("explain analyze %s", sql)).CheckAt([]int{0, 3, 6}, rows)
332332

333-
rows[1][2] = `eq(cast(test.t1.a, var_string(1)), "A")`
333+
rows[1][2] = `eq(cast(from_binary(cast(test.t1.a, binary(1))), var_string(1)), "A")`
334334
sql = "select a from t1 where cast(a as char)='A'"
335335
tk.MustQuery(sql).Check(testkit.Rows("A"))
336336
tk.MustQuery(fmt.Sprintf("explain analyze %s", sql)).CheckAt([]int{0, 3, 6}, rows)
337337

338338
tk.MustExec("insert into mysql.expr_pushdown_blacklist values('bit', 'tikv','');")
339339
tk.MustExec("admin reload expr_pushdown_blacklist;")
340340
rows = [][]any{
341-
{"Selection_5", "root", `eq(cast(test.t1.a, var_string(1)), "A")`},
341+
{"Selection_5", "root", `eq(cast(from_binary(cast(test.t1.a, binary(1))), var_string(1)), "A")`},
342342
{"└─TableReader_7", "root", "data:TableFullScan_6"},
343343
{" └─TableFullScan_6", "cop[tikv]", "keep order:false, stats:pseudo"},
344344
}

tests/integrationtest/r/expression/cast.result

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,18 @@ id update_user
178178
2 李四
179179
4 李四
180180
1 张三
181+
drop table if exists test;
182+
create table test(a bit(24));
183+
insert into test values('中');
184+
select a from test where '中' like convert(a, char);
185+
a
186+
187+
select a from test where false not like convert(a, char);
188+
a
189+
190+
select a from test where false like convert(a, char);
191+
a
192+
truncate table test;
193+
insert into test values(0xffffff);
194+
select a from test where false not like convert(a, char);
195+
Error 1105 (HY000): Cannot convert string '\xFF\xFF\xFF' from binary to utf8mb4

tests/integrationtest/t/expression/cast.test

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,14 @@ insert into test values(3,'张三');
113113
insert into test values(4,'李四');
114114
select * from test order by cast(update_user as char) desc , id limit 3;
115115

116+
# issue #56494, cast bit as char
117+
drop table if exists test;
118+
create table test(a bit(24));
119+
insert into test values('中');
120+
select a from test where '中' like convert(a, char);
121+
select a from test where false not like convert(a, char);
122+
select a from test where false like convert(a, char);
123+
truncate table test;
124+
insert into test values(0xffffff);
125+
-- error 1105
126+
select a from test where false not like convert(a, char);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_test")
2+
3+
go_test(
4+
name = "pushdowntest_test",
5+
timeout = "short",
6+
srcs = [
7+
"expr_test.go",
8+
"main_test.go",
9+
],
10+
flaky = True,
11+
deps = [
12+
"//pkg/testkit",
13+
"//tests/realtikvtest",
14+
"@com_github_stretchr_testify//require",
15+
],
16+
)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2024 PingCAP, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package pushdowntest
16+
17+
import (
18+
"testing"
19+
20+
"github.com/pingcap/tidb/pkg/testkit"
21+
"github.com/pingcap/tidb/tests/realtikvtest"
22+
"github.com/stretchr/testify/require"
23+
)
24+
25+
// TestBitCastInTiKV see issue: https://github.com/pingcap/tidb/issues/56494
26+
func TestBitCastInTiKV(t *testing.T) {
27+
store := realtikvtest.CreateMockStoreAndSetup(t)
28+
tk := testkit.NewTestKit(t, store)
29+
tk.MustExec("use test")
30+
tk.MustExec("drop table if exists t1")
31+
defer tk.MustExec("drop table if exists t1")
32+
tk.MustExec("create table t1(a bit(24))")
33+
tk.MustExec("insert into t1 values(0xffffff)")
34+
err := tk.QueryToErr("select a from t1 where false not like convert(a, char)")
35+
require.EqualError(t, err, "[tikv:3854]Cannot convert string '\\xFF\\xFF\\xFF' from binary to utf8mb4")
36+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2024 PingCAP, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package pushdowntest
16+
17+
import (
18+
"testing"
19+
20+
"github.com/pingcap/tidb/tests/realtikvtest"
21+
)
22+
23+
func TestMain(m *testing.M) {
24+
realtikvtest.RunTestMain(m)
25+
}

0 commit comments

Comments
 (0)