diff --git a/pkg/expression/expr_to_pb_test.go b/pkg/expression/expr_to_pb_test.go index 15b1ad4603a64..2c008867caf60 100644 --- a/pkg/expression/expr_to_pb_test.go +++ b/pkg/expression/expr_to_pb_test.go @@ -362,6 +362,40 @@ func TestDateFunc2Pb(t *testing.T) { require.Equal(t, "{\"tp\":10000,\"children\":[{\"tp\":201,\"val\":\"gAAAAAAAAAE=\",\"sig\":0,\"field_type\":{\"tp\":12,\"flag\":0,\"flen\":-1,\"decimal\":-1,\"collate\":-63,\"charset\":\"binary\",\"array\":false},\"has_distinct\":false},{\"tp\":201,\"val\":\"gAAAAAAAAAI=\",\"sig\":0,\"field_type\":{\"tp\":254,\"flag\":0,\"flen\":-1,\"decimal\":-1,\"collate\":-46,\"charset\":\"utf8mb4\",\"array\":false},\"has_distinct\":false}],\"sig\":6001,\"field_type\":{\"tp\":253,\"flag\":0,\"flen\":0,\"decimal\":-1,\"collate\":-46,\"charset\":\"utf8mb4\",\"array\":false},\"has_distinct\":false}", string(js)) } +func TestTrimFunc2Pb(t *testing.T) { + ctx := mock.NewContext() + client := new(mock.Client) + stringColumn := genColumn(mysql.TypeString, 1) + remstrColumn := genColumn(mysql.TypeString, 2) + direction := &Constant{ + Value: types.NewIntDatum(int64(ast.TrimLeading)), + RetType: types.NewFieldType(mysql.TypeLonglong), + } + + funcs := make([]Expression, 0, 3) + function, err := NewFunction(ctx, ast.Trim, types.NewFieldType(mysql.TypeString), stringColumn) + require.NoError(t, err) + require.Equal(t, tipb.ScalarFuncSig_Trim1Arg, function.(*ScalarFunction).Function.PbCode()) + funcs = append(funcs, function) + + function, err = NewFunction(ctx, ast.Trim, types.NewFieldType(mysql.TypeString), stringColumn, remstrColumn) + require.NoError(t, err) + require.Equal(t, tipb.ScalarFuncSig_Trim2Args, function.(*ScalarFunction).Function.PbCode()) + funcs = append(funcs, function) + + function, err = NewFunction(ctx, ast.Trim, types.NewFieldType(mysql.TypeString), stringColumn, remstrColumn, direction) + require.NoError(t, err) + require.Equal(t, tipb.ScalarFuncSig_Trim3Args, function.(*ScalarFunction).Function.PbCode()) + funcs = append(funcs, function) + + pbExprs, err := ExpressionsToPBList(ctx, funcs, client) + require.NoError(t, err) + require.Len(t, pbExprs, 3) + require.Equal(t, tipb.ScalarFuncSig_Trim1Arg, pbExprs[0].Sig) + require.Equal(t, tipb.ScalarFuncSig_Trim2Args, pbExprs[1].Sig) + require.Equal(t, tipb.ScalarFuncSig_Trim3Args, pbExprs[2].Sig) +} + func TestLogicalFunc2Pb(t *testing.T) { var logicalFuncs = make([]Expression, 0) ctx := mock.NewContext() diff --git a/pkg/expression/infer_pushdown.go b/pkg/expression/infer_pushdown.go index 6c6c35a208075..7909fee15b672 100644 --- a/pkg/expression/infer_pushdown.go +++ b/pkg/expression/infer_pushdown.go @@ -210,9 +210,10 @@ func scalarExprSupportedByTiKV(ctx EvalContext, sf *ScalarFunction) bool { // string functions. // ast.Bin, ast.Unhex, ast.Locate, ast.Ord, ast.Lpad, ast.Rpad, - // ast.Trim, ast.FromBase64, ast.ToBase64, ast.InsertFunc, + // ast.FromBase64, ast.ToBase64, ast.InsertFunc, // ast.MakeSet, ast.SubstringIndex, ast.Instr, ast.Quote, ast.Oct, // ast.FindInSet, ast.Repeat, + ast.Trim, ast.Upper, ast.Lower, ast.Length, ast.BitLength, ast.Concat, ast.ConcatWS, ast.Replace, ast.ASCII, ast.Hex, ast.Reverse, ast.LTrim, ast.RTrim, ast.Strcmp, ast.Space, ast.Elt, ast.Field, diff --git a/tests/integrationtest/r/expression/builtin.result b/tests/integrationtest/r/expression/builtin.result index a18f6a15495c5..38fd29f37e0c2 100644 --- a/tests/integrationtest/r/expression/builtin.result +++ b/tests/integrationtest/r/expression/builtin.result @@ -1931,6 +1931,84 @@ hex(trim('')) hex(trim('x' from '')) select hex(trim(null from 'bar')), hex(trim('x' from null)), hex(trim(null)), hex(trim(leading null from 'bar')); hex(trim(null from 'bar')) hex(trim('x' from null)) hex(trim(null)) hex(trim(leading null from 'bar')) NULL NULL NULL NULL +drop table if exists t_trim_pushdown; +create table t_trim_pushdown( +id int primary key, +c varchar(64) charset utf8mb4 collate utf8mb4_general_ci +); +insert into t_trim_pushdown values +(1, 'aaaaa'), +(2, 'ppp'), +(3, 'xyxyx'); +explain format = 'brief' select /*+ read_from_storage(tikv[t_trim_pushdown]) */ id from t_trim_pushdown where trim('aaa' from c) = 'aa' order by id; +id estRows task access object operator info +TableReader 8000.00 root data:Projection +└─Projection 8000.00 cop[tikv] expression__builtin.t_trim_pushdown.id + └─Selection 8000.00 cop[tikv] eq(trim(expression__builtin.t_trim_pushdown.c, "aaa"), "aa") + └─TableFullScan 10000.00 cop[tikv] table:t_trim_pushdown keep order:true, stats:pseudo +explain format = 'brief' select /*+ read_from_storage(tikv[t_trim_pushdown]) */ id from t_trim_pushdown where trim(both 'pp' from c) = 'p' order by id; +id estRows task access object operator info +TableReader 8000.00 root data:Projection +└─Projection 8000.00 cop[tikv] expression__builtin.t_trim_pushdown.id + └─Selection 8000.00 cop[tikv] eq(trim(expression__builtin.t_trim_pushdown.c, "pp", 1), "p") + └─TableFullScan 10000.00 cop[tikv] table:t_trim_pushdown keep order:true, stats:pseudo +explain format = 'brief' select /*+ read_from_storage(tikv[t_trim_pushdown]) */ id from t_trim_pushdown where trim(both 'xyx' from c) = 'yx' order by id; +id estRows task access object operator info +TableReader 8000.00 root data:Projection +└─Projection 8000.00 cop[tikv] expression__builtin.t_trim_pushdown.id + └─Selection 8000.00 cop[tikv] eq(trim(expression__builtin.t_trim_pushdown.c, "xyx", 1), "yx") + └─TableFullScan 10000.00 cop[tikv] table:t_trim_pushdown keep order:true, stats:pseudo +delete from mysql.expr_pushdown_blacklist where name = 'trim' and store_type = 'tikv,tiflash,tidb' and reason = 'for trim pushdown test'; +admin reload expr_pushdown_blacklist; +create temporary table trim_push_on(id int primary key); +insert into trim_push_on select id from t_trim_pushdown where trim('aaa' from c) = 'aa' order by id; +insert into mysql.expr_pushdown_blacklist values('trim', 'tikv,tiflash,tidb', 'for trim pushdown test'); +admin reload expr_pushdown_blacklist; +create temporary table trim_push_off(id int primary key); +insert into trim_push_off select id from t_trim_pushdown where trim('aaa' from c) = 'aa' order by id; +select ifnull((select group_concat(id order by id) from trim_push_on), '') as push_on, +ifnull((select group_concat(id order by id) from trim_push_off), '') as push_off, +ifnull((select group_concat(id order by id) from trim_push_on), '') = +ifnull((select group_concat(id order by id) from trim_push_off), '') as same; +push_on push_off same +1 1 1 +drop temporary table trim_push_on; +drop temporary table trim_push_off; +delete from mysql.expr_pushdown_blacklist where name = 'trim' and store_type = 'tikv,tiflash,tidb' and reason = 'for trim pushdown test'; +admin reload expr_pushdown_blacklist; +create temporary table trim_push_on(id int primary key); +insert into trim_push_on select id from t_trim_pushdown where trim(both 'pp' from c) = 'p' order by id; +insert into mysql.expr_pushdown_blacklist values('trim', 'tikv,tiflash,tidb', 'for trim pushdown test'); +admin reload expr_pushdown_blacklist; +create temporary table trim_push_off(id int primary key); +insert into trim_push_off select id from t_trim_pushdown where trim(both 'pp' from c) = 'p' order by id; +select ifnull((select group_concat(id order by id) from trim_push_on), '') as push_on, +ifnull((select group_concat(id order by id) from trim_push_off), '') as push_off, +ifnull((select group_concat(id order by id) from trim_push_on), '') = +ifnull((select group_concat(id order by id) from trim_push_off), '') as same; +push_on push_off same +2 2 1 +drop temporary table trim_push_on; +drop temporary table trim_push_off; +delete from mysql.expr_pushdown_blacklist where name = 'trim' and store_type = 'tikv,tiflash,tidb' and reason = 'for trim pushdown test'; +admin reload expr_pushdown_blacklist; +create temporary table trim_push_on(id int primary key); +insert into trim_push_on select id from t_trim_pushdown where trim(both 'xyx' from c) = 'yx' order by id; +insert into mysql.expr_pushdown_blacklist values('trim', 'tikv,tiflash,tidb', 'for trim pushdown test'); +admin reload expr_pushdown_blacklist; +create temporary table trim_push_off(id int primary key); +insert into trim_push_off select id from t_trim_pushdown where trim(both 'xyx' from c) = 'yx' order by id; +select ifnull((select group_concat(id order by id) from trim_push_on), '') as push_on, +ifnull((select group_concat(id order by id) from trim_push_off), '') as push_off, +ifnull((select group_concat(id order by id) from trim_push_on), '') = +ifnull((select group_concat(id order by id) from trim_push_off), '') as same; +push_on push_off same +3 3 1 +drop temporary table trim_push_on; +drop temporary table trim_push_off; +delete from mysql.expr_pushdown_blacklist where name = 'trim' and store_type = 'tikv,tiflash,tidb' and reason = 'for trim pushdown test'; +admin reload expr_pushdown_blacklist; +drop table if exists t_trim_pushdown; drop table if exists t; create table t(a char(20), b int, c double, d datetime, e time, f binary(5)); insert into t values('www.pingcap.com', 12345, 123.45, "2017-01-01 12:01:01", "12:01:01", "HelLo"); diff --git a/tests/integrationtest/t/expression/builtin.test b/tests/integrationtest/t/expression/builtin.test index 87600121dfda7..f6e566b01ea7f 100644 --- a/tests/integrationtest/t/expression/builtin.test +++ b/tests/integrationtest/t/expression/builtin.test @@ -870,6 +870,63 @@ select hex(trim('\t bar\n ')), hex(trim(' \rbar \t')); select hex(trim(leading from ' bar')), hex(trim('x' from 'xxxbarxxx')), hex(trim('x' from 'bar')), hex(trim('' from ' bar ')); select hex(trim('')), hex(trim('x' from '')); select hex(trim(null from 'bar')), hex(trim('x' from null)), hex(trim(null)), hex(trim(leading null from 'bar')); +drop table if exists t_trim_pushdown; +create table t_trim_pushdown( + id int primary key, + c varchar(64) charset utf8mb4 collate utf8mb4_general_ci +); +insert into t_trim_pushdown values + (1, 'aaaaa'), + (2, 'ppp'), + (3, 'xyxyx'); +explain format = 'brief' select /*+ read_from_storage(tikv[t_trim_pushdown]) */ id from t_trim_pushdown where trim('aaa' from c) = 'aa' order by id; +explain format = 'brief' select /*+ read_from_storage(tikv[t_trim_pushdown]) */ id from t_trim_pushdown where trim(both 'pp' from c) = 'p' order by id; +explain format = 'brief' select /*+ read_from_storage(tikv[t_trim_pushdown]) */ id from t_trim_pushdown where trim(both 'xyx' from c) = 'yx' order by id; +delete from mysql.expr_pushdown_blacklist where name = 'trim' and store_type = 'tikv,tiflash,tidb' and reason = 'for trim pushdown test'; +admin reload expr_pushdown_blacklist; +create temporary table trim_push_on(id int primary key); +insert into trim_push_on select id from t_trim_pushdown where trim('aaa' from c) = 'aa' order by id; +insert into mysql.expr_pushdown_blacklist values('trim', 'tikv,tiflash,tidb', 'for trim pushdown test'); +admin reload expr_pushdown_blacklist; +create temporary table trim_push_off(id int primary key); +insert into trim_push_off select id from t_trim_pushdown where trim('aaa' from c) = 'aa' order by id; +select ifnull((select group_concat(id order by id) from trim_push_on), '') as push_on, + ifnull((select group_concat(id order by id) from trim_push_off), '') as push_off, + ifnull((select group_concat(id order by id) from trim_push_on), '') = + ifnull((select group_concat(id order by id) from trim_push_off), '') as same; +drop temporary table trim_push_on; +drop temporary table trim_push_off; +delete from mysql.expr_pushdown_blacklist where name = 'trim' and store_type = 'tikv,tiflash,tidb' and reason = 'for trim pushdown test'; +admin reload expr_pushdown_blacklist; +create temporary table trim_push_on(id int primary key); +insert into trim_push_on select id from t_trim_pushdown where trim(both 'pp' from c) = 'p' order by id; +insert into mysql.expr_pushdown_blacklist values('trim', 'tikv,tiflash,tidb', 'for trim pushdown test'); +admin reload expr_pushdown_blacklist; +create temporary table trim_push_off(id int primary key); +insert into trim_push_off select id from t_trim_pushdown where trim(both 'pp' from c) = 'p' order by id; +select ifnull((select group_concat(id order by id) from trim_push_on), '') as push_on, + ifnull((select group_concat(id order by id) from trim_push_off), '') as push_off, + ifnull((select group_concat(id order by id) from trim_push_on), '') = + ifnull((select group_concat(id order by id) from trim_push_off), '') as same; +drop temporary table trim_push_on; +drop temporary table trim_push_off; +delete from mysql.expr_pushdown_blacklist where name = 'trim' and store_type = 'tikv,tiflash,tidb' and reason = 'for trim pushdown test'; +admin reload expr_pushdown_blacklist; +create temporary table trim_push_on(id int primary key); +insert into trim_push_on select id from t_trim_pushdown where trim(both 'xyx' from c) = 'yx' order by id; +insert into mysql.expr_pushdown_blacklist values('trim', 'tikv,tiflash,tidb', 'for trim pushdown test'); +admin reload expr_pushdown_blacklist; +create temporary table trim_push_off(id int primary key); +insert into trim_push_off select id from t_trim_pushdown where trim(both 'xyx' from c) = 'yx' order by id; +select ifnull((select group_concat(id order by id) from trim_push_on), '') as push_on, + ifnull((select group_concat(id order by id) from trim_push_off), '') as push_off, + ifnull((select group_concat(id order by id) from trim_push_on), '') = + ifnull((select group_concat(id order by id) from trim_push_off), '') as same; +drop temporary table trim_push_on; +drop temporary table trim_push_off; +delete from mysql.expr_pushdown_blacklist where name = 'trim' and store_type = 'tikv,tiflash,tidb' and reason = 'for trim pushdown test'; +admin reload expr_pushdown_blacklist; +drop table if exists t_trim_pushdown; drop table if exists t; create table t(a char(20), b int, c double, d datetime, e time, f binary(5)); insert into t values('www.pingcap.com', 12345, 123.45, "2017-01-01 12:01:01", "12:01:01", "HelLo"); @@ -1672,4 +1729,4 @@ set sql_mode = default; # Issue 59420 SELECT GET_FORMAT(TIME, 'usa'), GET_FORMAT(TIME, 'USA'), GET_FORMAT(TIME, 'UsA'), GET_FORMAT(time, 'UsA'), GET_FORMAT(TIme, 'UsA'); -SELECT GET_FORMAT(DATE, 'jis'),GET_FORMAT(DATETIME, 'iso'),GET_FORMAT(TIMESTAMP, 'eur'),GET_FORMAT(TIME, 'internal'); \ No newline at end of file +SELECT GET_FORMAT(DATE, 'jis'),GET_FORMAT(DATETIME, 'iso'),GET_FORMAT(TIMESTAMP, 'eur'),GET_FORMAT(TIME, 'internal'); diff --git a/tests/realtikvtest/pushdowntest/expr_test.go b/tests/realtikvtest/pushdowntest/expr_test.go index 110d240b8da43..664d76731faa5 100644 --- a/tests/realtikvtest/pushdowntest/expr_test.go +++ b/tests/realtikvtest/pushdowntest/expr_test.go @@ -15,6 +15,7 @@ package pushdowntest import ( + "strings" "testing" "github.com/pingcap/tidb/pkg/testkit" @@ -34,3 +35,184 @@ func TestBitCastInTiKV(t *testing.T) { err := tk.QueryToErr("select a from t1 where false not like convert(a, char)") require.EqualError(t, err, "[tikv:3854]Cannot convert string '\\xFF\\xFF\\xFF' from binary to utf8mb4") } + +func TestTrimPushDownToTiKV(t *testing.T) { + store := realtikvtest.CreateMockStoreAndSetup(t) + tk := testkit.NewTestKit(t, store) + resetTrimPushdownBlacklist := func() { + tk.MustExec("delete from mysql.expr_pushdown_blacklist where name='trim'") + tk.MustExec("admin reload expr_pushdown_blacklist") + } + checkTrimExplainPushed := func(sql string) { + rows := tk.MustQuery("explain analyze format='brief' " + sql).Rows() + found := false + for _, row := range rows { + op, ok := row[0].(string) + require.True(t, ok, sql) + task, ok := row[3].(string) + require.True(t, ok, sql) + info, ok := row[6].(string) + require.True(t, ok, sql) + if strings.Contains(op, "Selection") && task == "cop[tikv]" && strings.Contains(info, "trim(") { + found = true + break + } + } + require.True(t, found, sql) + } + checkTrimResultConsistency := func(sql string, expected []string) { + resetTrimPushdownBlacklist() + rowsOn := tk.MustQuery(sql).Rows() + require.EqualValues(t, testkit.Rows(expected...), rowsOn, sql) + + tk.MustExec("insert into mysql.expr_pushdown_blacklist values('trim', 'tikv', 'for trim realtikv test')") + tk.MustExec("admin reload expr_pushdown_blacklist") + + rowsOff := tk.MustQuery(sql).Rows() + require.EqualValues(t, rowsOn, rowsOff, sql) + } + + tk.MustExec("use test") + tk.MustExec("drop table if exists t_trim_pushdown") + t.Cleanup(func() { + resetTrimPushdownBlacklist() + tk.MustExec("drop table if exists t_trim_pushdown") + }) + resetTrimPushdownBlacklist() + + tk.MustExec(`create table t_trim_pushdown( + id int primary key, + c varchar(64) charset utf8mb4 collate utf8mb4_general_ci, + c_bin varchar(64) charset utf8mb4 collate utf8mb4_bin, + c_ascii varchar(64) charset ascii collate ascii_bin, + vb varbinary(64) + )`) + tk.MustExec(`insert into t_trim_pushdown values + (1, 'aaaaa', 'aaaaa', 'aaaaa', x'207820'), + (2, 'ppp', 'ppp', 'ppp', x'20707020'), + (3, 'xyxyx', 'xyxyx', 'xyxyx', x'2078797820'), + (4, ' x ', ' x ', ' x ', x'207820'), + (5, 'xybarxy', 'xybarxy', 'xybarxy', x'20787920'), + (6, 'xyxybarxy', 'xyxybarxy', 'xyxybarxy', x'2078797820'), + (7, 'xybarxyxy', 'xybarxyxy', 'xybarxyxy', x'207879787920'), + (8, 'xyxybarxyxy', 'xyxybarxyxy', 'xyxybarxyxy', x'207879787920'), + (9, '', '', '', x''), + (10, null, null, null, null), + (11, ' ', ' ', ' ', x'202020'), + (12, '好好bar好好', '好好bar好好', null, x''), + (13, 'bar', 'bar', 'bar', x'626172'), + (14, 'x', 'x', 'x', x'78'), + (15, 'ff', 'ff', 'ff', x'20ff20'), + (16, null, null, null, x'20ff7820'), + (17, null, null, null, x'00207820')`) + + explainCases := []string{ + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim('aaa' from c) = 'aa'", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim(both 'pp' from c) = 'p'", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim(both 'xyx' from c) = 'yx'", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim(c) = 'x'", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim('xy' from c) = 'bar'", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim(leading 'xy' from c) = 'barxy'", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim(trailing 'xy' from c) = 'xybar'", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim(both 'xy' from c) = 'bar'", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim(c) is null", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim(c) = ''", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim('' from c) = 'bar'", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim('xy' from c) = 'x'", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim('xy' from c) is null", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim(c_ascii) = 'x'", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim(vb) = x''", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim('好' from c_bin) = 'bar' and c_bin like '%好%'", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim(vb) = x'ff'", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim(vb) = x'ff78'", + "select /*+ read_from_storage(tikv[t_trim_pushdown]) */ * from t_trim_pushdown where trim(vb) = x'002078'", + } + for _, sql := range explainCases { + checkTrimExplainPushed(sql) + } + + resultCases := []struct { + sql string + expected []string + }{ + { + sql: "select id from t_trim_pushdown where trim('aaa' from c) = 'aa' order by id", + expected: []string{"1"}, + }, + { + sql: "select id from t_trim_pushdown where trim(both 'pp' from c) = 'p' order by id", + expected: []string{"2"}, + }, + { + sql: "select id from t_trim_pushdown where trim(both 'xyx' from c) = 'yx' order by id", + expected: []string{"3"}, + }, + { + sql: "select id from t_trim_pushdown where trim(c) = 'x' order by id", + expected: []string{"4", "14"}, + }, + { + sql: "select id from t_trim_pushdown where trim('xy' from c) = 'bar' order by id", + expected: []string{"5", "6", "7", "8", "13"}, + }, + { + sql: "select id from t_trim_pushdown where trim(leading 'xy' from c) = 'barxy' order by id", + expected: []string{"5", "6"}, + }, + { + sql: "select id from t_trim_pushdown where trim(trailing 'xy' from c) = 'xybar' order by id", + expected: []string{"5", "7"}, + }, + { + sql: "select id from t_trim_pushdown where trim(both 'xy' from c) = 'bar' order by id", + expected: []string{"5", "6", "7", "8", "13"}, + }, + { + sql: "select id from t_trim_pushdown where trim(c) = '' order by id", + expected: []string{"9", "11"}, + }, + { + sql: "select id from t_trim_pushdown where trim('' from c) = 'bar' order by id", + expected: []string{"13"}, + }, + { + sql: "select id from t_trim_pushdown where trim('xy' from c) = 'x' order by id", + expected: []string{"3", "14"}, + }, + { + sql: "select id from t_trim_pushdown where trim('xy' from c) is null order by id", + expected: []string{"10", "16", "17"}, + }, + { + sql: "select id from t_trim_pushdown where trim(c_ascii) = 'x' order by id", + expected: []string{"4", "14"}, + }, + { + sql: "select id from t_trim_pushdown where trim(vb) = x'' order by id", + expected: []string{"9", "11", "12"}, + }, + { + sql: "select id from t_trim_pushdown where trim('好' from c_bin) = 'bar' and c_bin like '%好%' order by id", + expected: []string{"12"}, + }, + { + sql: "select id from t_trim_pushdown where trim(vb) = x'ff' order by id", + expected: []string{"15"}, + }, + { + sql: "select id from t_trim_pushdown where trim(vb) = x'ff78' order by id", + expected: []string{"16"}, + }, + { + sql: "select id from t_trim_pushdown where trim(vb) = x'002078' order by id", + expected: []string{"17"}, + }, + { + sql: "select id from t_trim_pushdown where trim(c) is null order by id", + expected: []string{"10", "16", "17"}, + }, + } + for _, tc := range resultCases { + checkTrimResultConsistency(tc.sql, tc.expected) + } +}