From a69a354339bf8c8d059b65d0c819297069bdcc6b Mon Sep 17 00:00:00 2001 From: wjHuang Date: Tue, 31 Jan 2023 20:29:55 +0800 Subject: [PATCH] This is an automated cherry-pick of #38826 Signed-off-by: ti-chi-bot --- .../r/collation_check_use_collation.result | 52 ++ ...lation_check_use_collation_disabled.result | 181 +++++++ cmd/explaintest/r/subquery.result | 29 ++ .../t/collation_check_use_collation.test | 40 ++ expression/collation.go | 8 - expression/integration_test.go | 475 ++++++++++++++++++ expression/util.go | 33 ++ planner/core/exhaust_physical_plans.go | 9 + 8 files changed, 819 insertions(+), 8 deletions(-) create mode 100644 cmd/explaintest/r/collation_check_use_collation_disabled.result diff --git a/cmd/explaintest/r/collation_check_use_collation.result b/cmd/explaintest/r/collation_check_use_collation.result index d878d140f647e..da286af98349c 100644 --- a/cmd/explaintest/r/collation_check_use_collation.result +++ b/cmd/explaintest/r/collation_check_use_collation.result @@ -147,4 +147,56 @@ col_25 select col_25 from tbl_2 use index(primary) where ( tbl_2.col_27 > 'nSWYrpTH' or not( tbl_2.col_27 between 'CsWIuxlSjU' and 'SfwoyjUEzgg' ) ) and ( tbl_2.col_23 <= -95); col_25 89 +<<<<<<< HEAD:cmd/explaintest/r/collation_check_use_collation.result +======= +drop table if exists t1; +drop table if exists t2; +create table t1(a char(20)); +create table t2(b binary(20), c binary(20)); +insert into t1 value('-1'); +insert into t2 value(0x2D31, 0x67); +insert into t2 value(0x2D31, 0x73); +select a from t1, t2 where t1.a between t2.b and t2.c; +a +select a from t1, t2 where cast(t1.a as binary(20)) between t2.b and t2.c; +a +-1 +-1 +drop table if exists t1; +drop table if exists t2; +create table t1(a char(20)) collate utf8mb4_general_ci; +create table t2(b binary(20), c char(20)) collate utf8mb4_general_ci; +insert into t1 values ('a'); +insert into t2 values (0x0, 'A'); +select * from t1, t2 where t1.a between t2.b and t2.c; +a b c +insert into t1 values ('-1'); +insert into t2 values (0x2d31, ''); +select * from t1, t2 where t1.a in (t2.b, 3); +a b c +drop table if exists t0; +drop table if exists t1; +CREATE TABLE t0(c0 BOOL, c1 INT); +CREATE TABLE t1 LIKE t0; +CREATE VIEW v0(c0) AS SELECT IS_IPV4(t0.c1) FROM t0, t1; +INSERT INTO t0(c0, c1) VALUES (true, 0); +INSERT INTO t1(c0, c1) VALUES (true, 2); +SELECT v0.c0 FROM v0; +c0 +0 +SELECT (v0.c0)NOT LIKE(BINARY v0.c0) FROM v0; +(v0.c0)NOT LIKE(BINARY v0.c0) +0 +SELECT v0.c0 FROM v0 WHERE (v0.c0)NOT LIKE(BINARY v0.c0); +c0 +desc format='brief' SELECT v0.c0 FROM v0 WHERE (v0.c0)NOT LIKE(BINARY v0.c0); +id estRows task access object operator info +Projection 80000000.00 root is_ipv4(cast(collation_check_use_collation.t0.c1, var_string(20)))->Column#7 +└─HashJoin 80000000.00 root CARTESIAN inner join + ├─Selection(Build) 8000.00 root not(like(cast(is_ipv4(cast(collation_check_use_collation.t0.c1, var_string(20))), var_string(20)), cast(is_ipv4(cast(collation_check_use_collation.t0.c1, var_string(20))), binary(1)), 92)) + │ └─TableReader 10000.00 root data:TableFullScan + │ └─TableFullScan 10000.00 cop[tikv] table:t0 keep order:false, stats:pseudo + └─TableReader(Probe) 10000.00 root data:TableFullScan + └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo +>>>>>>> 00617c96ef (expression, cmd: fix ColumnSubstitute and allow some cases to substitute (#38826)):cmd/explaintest/r/collation_check_use_collation_enabled.result use test diff --git a/cmd/explaintest/r/collation_check_use_collation_disabled.result b/cmd/explaintest/r/collation_check_use_collation_disabled.result new file mode 100644 index 0000000000000..9e633133b1f4f --- /dev/null +++ b/cmd/explaintest/r/collation_check_use_collation_disabled.result @@ -0,0 +1,181 @@ +set tidb_cost_model_version=1; +create database collation_check_use_collation; +use collation_check_use_collation; +CREATE TABLE `t` ( +`a` char(10) DEFAULT NULL +); +CREATE TABLE `t1` ( +`a` char(10) COLLATE utf8mb4_general_ci DEFAULT NULL +); +insert into t values ("A"); +insert into t1 values ("a"); +select a as a_col from t where t.a = all (select a collate utf8mb4_general_ci from t1); +a_col +select a as a_col from t where t.a != any (select a collate utf8mb4_general_ci from t1); +a_col +A +select a as a_col from t where t.a <= all (select a collate utf8mb4_general_ci from t1); +a_col +A +select a as a_col from t where t.a <= any (select a collate utf8mb4_general_ci from t1); +a_col +A +select a as a_col from t where t.a = (select a collate utf8mb4_general_ci from t1); +a_col +drop table if exists t; +create table t(a enum('a', 'b'), b varchar(20)); +insert into t values ("a", "b"); +select * from t where a in (a); +a b +a b +drop table if exists t; +create table t(a enum('a', 'b') charset utf8mb4 collate utf8mb4_general_ci, b varchar(20)); +insert into t values ("b", "c"); +insert into t values ("B", "b"); +Error 1265 (01000): Data truncated for column 'a' at row 1 +select * from t where 'B' collate utf8mb4_general_ci in (a); +a b +select * from t where 'B' collate utf8mb4_bin in (a); +a b +select * from t where 'B' collate utf8mb4_bin in (a, b); +a b +select * from t where 'B' collate utf8mb4_bin in (a, "a", 1); +a b +select * from t where 'B' collate utf8mb4_bin in (a, "B", 1); +a b +b c +select * from t where 1 in (a); +a b +select * from t where 2 in (a); +a b +b c +select * from t where 1 in (a, 0); +a b +select * from t where a between 1 and 2; +a b +b c +select * from t where a between 1 and "a"; +a b +select * from t where a between "a" and "b"; +a b +b c +select * from t where 2 between a and "c"; +a b +select * from t where 2 between a and 3; +a b +b c +select * from t where "b" between a and a; +a b +b c +select * from t where "b" collate utf8mb4_bin between a and a; +a b +b c +select * from t where "b" between a and 3; +a b +drop table if exists t; +create table t(a set('a', 'b'), b varchar(20)); +insert into t values ("a", "b"); +select * from t where a in (a); +a b +a b +drop table if exists t; +create table t(a set('a', 'b') charset utf8mb4 collate utf8mb4_general_ci, b varchar(20)); +insert into t values ("b", "c"); +insert into t values ("B", "b"); +Error 1265 (01000): Data truncated for column 'a' at row 1 +select * from t where 'B' collate utf8mb4_general_ci in (a); +a b +select * from t where 'B' collate utf8mb4_bin in (a); +a b +select * from t where 'B' collate utf8mb4_bin in (a, b); +a b +select * from t where 'B' collate utf8mb4_bin in (a, "a", 1); +a b +select * from t where 'B' collate utf8mb4_bin in (a, "B", 1); +a b +b c +select * from t where 1 in (a); +a b +select * from t where 2 in (a); +a b +b c +select * from t where 1 in (a, 0); +a b +select * from t where a between 1 and 2; +a b +b c +select * from t where a between 1 and "a"; +a b +select * from t where a between "a" and "b"; +a b +b c +select * from t where 2 between a and "c"; +a b +select * from t where 2 between a and 3; +a b +b c +select * from t where "b" between a and a; +a b +b c +select * from t where "b" collate utf8mb4_bin between a and a; +a b +b c +select * from t where "b" between a and 3; +a b +drop table if exists tbl_2; +create table tbl_2 ( col_20 bigint not null , col_21 smallint not null , col_22 decimal(24,10) default null , col_23 tinyint default 71 not null , col_24 bigint not null , col_25 tinyint default 18 , col_26 varchar(330) collate utf8_bin not null , col_27 char(77) collate utf8mb4_unicode_ci , col_28 char(46) collate utf8_general_ci not null , col_29 smallint unsigned not null , primary key idx_13 ( col_27(5) ) , key idx_14 ( col_24 ) , unique key idx_15 ( col_23,col_21,col_28,col_29,col_24 ) ) collate utf8_bin ; +insert ignore into tbl_2 values ( 5888267793391993829,5371,94.63,-109,5728076076919247337,89,'WUicqUTgdGJcjbC','SapBPqczTWWSN','xUSwH',49462 ); +select col_25 from tbl_2 where ( tbl_2.col_27 > 'nSWYrpTH' or not( tbl_2.col_27 between 'CsWIuxlSjU' and 'SfwoyjUEzgg' ) ) and ( tbl_2.col_23 <= -95); +col_25 +select col_25 from tbl_2 use index(primary) where ( tbl_2.col_27 > 'nSWYrpTH' or not( tbl_2.col_27 between 'CsWIuxlSjU' and 'SfwoyjUEzgg' ) ) and ( tbl_2.col_23 <= -95); +col_25 +drop table if exists t1; +drop table if exists t2; +create table t1(a char(20)); +create table t2(b binary(20), c binary(20)); +insert into t1 value('-1'); +insert into t2 value(0x2D31, 0x67); +insert into t2 value(0x2D31, 0x73); +select a from t1, t2 where t1.a between t2.b and t2.c; +a +select a from t1, t2 where cast(t1.a as binary(20)) between t2.b and t2.c; +a +-1 +-1 +drop table if exists t1; +drop table if exists t2; +create table t1(a char(20)) collate utf8mb4_general_ci; +create table t2(b binary(20), c char(20)) collate utf8mb4_general_ci; +insert into t1 values ('a'); +insert into t2 values (0x0, 'A'); +select * from t1, t2 where t1.a between t2.b and t2.c; +a b c +insert into t1 values ('-1'); +insert into t2 values (0x2d31, ''); +select * from t1, t2 where t1.a in (t2.b, 3); +a b c +drop table if exists t0; +drop table if exists t1; +CREATE TABLE t0(c0 BOOL, c1 INT); +CREATE TABLE t1 LIKE t0; +CREATE VIEW v0(c0) AS SELECT IS_IPV4(t0.c1) FROM t0, t1; +INSERT INTO t0(c0, c1) VALUES (true, 0); +INSERT INTO t1(c0, c1) VALUES (true, 2); +SELECT v0.c0 FROM v0; +c0 +0 +SELECT (v0.c0)NOT LIKE(BINARY v0.c0) FROM v0; +(v0.c0)NOT LIKE(BINARY v0.c0) +0 +SELECT v0.c0 FROM v0 WHERE (v0.c0)NOT LIKE(BINARY v0.c0); +c0 +desc format='brief' SELECT v0.c0 FROM v0 WHERE (v0.c0)NOT LIKE(BINARY v0.c0); +id estRows task access object operator info +Projection 80000000.00 root is_ipv4(cast(collation_check_use_collation.t0.c1, var_string(20)))->Column#7 +└─HashJoin 80000000.00 root CARTESIAN inner join + ├─Selection(Build) 8000.00 root not(like(cast(is_ipv4(cast(collation_check_use_collation.t0.c1, var_string(20))), var_string(20)), cast(is_ipv4(cast(collation_check_use_collation.t0.c1, var_string(20))), binary(1)), 92)) + │ └─TableReader 10000.00 root data:TableFullScan + │ └─TableFullScan 10000.00 cop[tikv] table:t0 keep order:false, stats:pseudo + └─TableReader(Probe) 10000.00 root data:TableFullScan + └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo +use test diff --git a/cmd/explaintest/r/subquery.result b/cmd/explaintest/r/subquery.result index 84bac87bb1d23..4c2b5f3207712 100644 --- a/cmd/explaintest/r/subquery.result +++ b/cmd/explaintest/r/subquery.result @@ -46,3 +46,32 @@ create table t1(a int(11)); create table t2(a decimal(40,20) unsigned, b decimal(40,20)); select count(*) as x from t1 group by a having x not in (select a from t2 where x = t2.b); x +<<<<<<< HEAD +======= +drop table if exists stu; +drop table if exists exam; +create table stu(id int, name varchar(100)); +insert into stu values(1, null); +create table exam(stu_id int, course varchar(100), grade int); +insert into exam values(1, 'math', 100); +set names utf8 collate utf8_general_ci; +explain format = 'brief' select * from stu where stu.name not in (select 'guo' from exam where exam.stu_id = stu.id); +id estRows task access object operator info +HashJoin 8000.00 root anti semi join, equal:[eq(test.stu.id, test.exam.stu_id)], other cond:eq(test.stu.name, "guo") +├─TableReader(Build) 10000.00 root data:TableFullScan +│ └─TableFullScan 10000.00 cop[tikv] table:exam keep order:false, stats:pseudo +└─TableReader(Probe) 10000.00 root data:TableFullScan + └─TableFullScan 10000.00 cop[tikv] table:stu keep order:false, stats:pseudo +select * from stu where stu.name not in (select 'guo' from exam where exam.stu_id = stu.id); +id name +set names utf8mb4; +explain format = 'brief' select * from stu where stu.name not in (select 'guo' from exam where exam.stu_id = stu.id); +id estRows task access object operator info +HashJoin 8000.00 root anti semi join, equal:[eq(test.stu.id, test.exam.stu_id)], other cond:eq(test.stu.name, "guo") +├─TableReader(Build) 10000.00 root data:TableFullScan +│ └─TableFullScan 10000.00 cop[tikv] table:exam keep order:false, stats:pseudo +└─TableReader(Probe) 10000.00 root data:TableFullScan + └─TableFullScan 10000.00 cop[tikv] table:stu keep order:false, stats:pseudo +select * from stu where stu.name not in (select 'guo' from exam where exam.stu_id = stu.id); +id name +>>>>>>> 00617c96ef (expression, cmd: fix ColumnSubstitute and allow some cases to substitute (#38826)) diff --git a/cmd/explaintest/t/collation_check_use_collation.test b/cmd/explaintest/t/collation_check_use_collation.test index 2d73a6afa5716..12d44d95c2587 100644 --- a/cmd/explaintest/t/collation_check_use_collation.test +++ b/cmd/explaintest/t/collation_check_use_collation.test @@ -80,5 +80,45 @@ insert ignore into tbl_2 values ( 5888267793391993829,5371,94.63,-109,5728076076 select col_25 from tbl_2 where ( tbl_2.col_27 > 'nSWYrpTH' or not( tbl_2.col_27 between 'CsWIuxlSjU' and 'SfwoyjUEzgg' ) ) and ( tbl_2.col_23 <= -95); select col_25 from tbl_2 use index(primary) where ( tbl_2.col_27 > 'nSWYrpTH' or not( tbl_2.col_27 between 'CsWIuxlSjU' and 'SfwoyjUEzgg' ) ) and ( tbl_2.col_23 <= -95); +<<<<<<< HEAD +======= +# check implicit binary collation cast +drop table if exists t1; +drop table if exists t2; +# issue 34823 +create table t1(a char(20)); +create table t2(b binary(20), c binary(20)); +insert into t1 value('-1'); +insert into t2 value(0x2D31, 0x67); +insert into t2 value(0x2D31, 0x73); +select a from t1, t2 where t1.a between t2.b and t2.c; +select a from t1, t2 where cast(t1.a as binary(20)) between t2.b and t2.c; +# binary collation in single side +drop table if exists t1; +drop table if exists t2; +create table t1(a char(20)) collate utf8mb4_general_ci; +create table t2(b binary(20), c char(20)) collate utf8mb4_general_ci; +insert into t1 values ('a'); +insert into t2 values (0x0, 'A'); +select * from t1, t2 where t1.a between t2.b and t2.c; +insert into t1 values ('-1'); +insert into t2 values (0x2d31, ''); +select * from t1, t2 where t1.a in (t2.b, 3); + +# issue 38736 +drop table if exists t0; +drop table if exists t1; +CREATE TABLE t0(c0 BOOL, c1 INT); +CREATE TABLE t1 LIKE t0; +CREATE VIEW v0(c0) AS SELECT IS_IPV4(t0.c1) FROM t0, t1; +INSERT INTO t0(c0, c1) VALUES (true, 0); +INSERT INTO t1(c0, c1) VALUES (true, 2); + +SELECT v0.c0 FROM v0; +SELECT (v0.c0)NOT LIKE(BINARY v0.c0) FROM v0; +SELECT v0.c0 FROM v0 WHERE (v0.c0)NOT LIKE(BINARY v0.c0); +desc format='brief' SELECT v0.c0 FROM v0 WHERE (v0.c0)NOT LIKE(BINARY v0.c0); + +>>>>>>> 00617c96ef (expression, cmd: fix ColumnSubstitute and allow some cases to substitute (#38826)) # cleanup environment use test diff --git a/expression/collation.go b/expression/collation.go index 40f3104dd48ae..7b769de209522 100644 --- a/expression/collation.go +++ b/expression/collation.go @@ -285,14 +285,6 @@ func deriveCollation(ctx sessionctx.Context, funcName string, args []Expression, return ec, nil } -// DeriveCollationFromExprs derives collation information from these expressions. -// Deprecated, use CheckAndDeriveCollationFromExprs instead. -// TODO: remove this function after the all usage is replaced by CheckAndDeriveCollationFromExprs -func DeriveCollationFromExprs(ctx sessionctx.Context, exprs ...Expression) (dstCharset, dstCollation string) { - collation := inferCollation(exprs...) - return collation.Charset, collation.Collation -} - // CheckAndDeriveCollationFromExprs derives collation information from these expressions, return error if derives collation error. func CheckAndDeriveCollationFromExprs(ctx sessionctx.Context, funcName string, evalType types.EvalType, args ...Expression) (et *ExprCollation, err error) { ec := inferCollation(args...) diff --git a/expression/integration_test.go b/expression/integration_test.go index b3aa0c84f7195..831bb41f11513 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -7055,3 +7055,478 @@ func TestIssue31569(t *testing.T) { tk.MustQuery("show warnings").Check([][]interface{}{}) tk.MustExec("drop table t") } +<<<<<<< HEAD +======= + +func TestTimestampAddWithFractionalSecond(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(a date)") + tk.MustExec("insert into t values ('2021-08-20');") + tk.MustQuery("select timestampadd(microsecond, 1, a) from t").Check(testkit.Rows("2021-08-20 00:00:00.000001")) + tk.MustQuery("select timestampadd(second, 6/4, a) from t").Check(testkit.Rows("2021-08-20 00:00:01.500000")) + tk.MustQuery("select timestampadd(second, 9.9999e2, a) from t").Check(testkit.Rows("2021-08-20 00:16:39.990000")) + tk.MustQuery("select timestampadd(second, 1, '2021-08-20 00:00:01.0001')").Check(testkit.Rows("2021-08-20 00:00:02.000100")) + tk.MustQuery("select timestampadd(minute, 1.5, '2021-08-20 00:00:00')").Check(testkit.Rows("2021-08-20 00:02:00")) + tk.MustQuery("select timestampadd(minute, 1.5, '2021-08-20 00:00:00.0001')").Check(testkit.Rows("2021-08-20 00:02:00.000100")) + // overflow + tk.MustQuery("SELECT timestampadd(year,1.212208e+308,'1995-01-05 06:32:20.859724') as result").Check(testkit.Rows("")) + warnings := tk.Session().GetSessionVars().StmtCtx.GetWarnings() + require.Len(t, warnings, 1) + for _, warning := range warnings { + require.EqualError(t, warning.Err, "[types:1441]Datetime function: datetime field overflow") + } +} + +func TestDateAddForNonExistingTimestamp(t *testing.T) { + store := testkit.CreateMockStore(t) + + tk := testkit.NewTestKit(t, store) + tk.MustExec("set time_zone = 'CET'") + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(ts timestamp)") + tk.MustExec("set time_zone = 'UTC'") + tk.MustExec("insert into t values('2022-03-27 00:30:00')") + tk.MustExec("insert into t values('2022-10-30 00:30:00')") + tk.MustExec("insert into t values('2022-10-30 01:30:00')") + tk.MustExec("set time_zone = 'Europe/Amsterdam'") + // Non-existing CET timestamp. + tk.MustGetErrCode("insert into t values('2022-03-27 02:30:00')", errno.ErrTruncatedWrongValue) + tk.MustQuery("select date_add(ts, interval 1 hour) from t order by ts").Check([][]interface{}{ + {"2022-03-27 02:30:00"}, + {"2022-10-30 03:30:00"}, + {"2022-10-30 03:30:00"}, + }) + tk.MustExec("drop table t") +} + +func TestImcompleteDateFunc(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustQuery("select to_seconds('1998-10-00')").Check(testkit.Rows("")) + tk.MustQuery("select to_seconds('1998-00-11')").Check(testkit.Rows("")) + tk.MustQuery("SELECT CONVERT_TZ('2004-10-00 12:00:00','GMT','MET');").Check(testkit.Rows("")) + tk.MustQuery("SELECT CONVERT_TZ('2004-00-01 12:00:00','GMT','MET');").Check(testkit.Rows("")) + tk.MustQuery("SELECT DATE_ADD('1998-10-00',INTERVAL 1 DAY);").Check(testkit.Rows("")) + tk.MustQuery("SELECT DATE_ADD('2004-00-01',INTERVAL 1 DAY);").Check(testkit.Rows("")) + tk.MustQuery("SELECT DATE_SUB('1998-10-00', INTERVAL 31 DAY);").Check(testkit.Rows("")) + tk.MustQuery("SELECT DATE_SUB('2004-00-01', INTERVAL 31 DAY);").Check(testkit.Rows("")) + tk.MustQuery("SELECT DAYOFYEAR('2007-00-03');").Check(testkit.Rows("")) + tk.MustQuery("SELECT DAYOFYEAR('2007-02-00');;").Check(testkit.Rows("")) + tk.MustQuery("SELECT TIMESTAMPDIFF(MONTH,'2003-00-01','2003-05-01');").Check(testkit.Rows("")) + tk.MustQuery("SELECT TIMESTAMPDIFF(MONTH,'2003-02-01','2003-05-00');;").Check(testkit.Rows("")) + tk.MustQuery("select to_days('1998-10-00')").Check(testkit.Rows("")) + tk.MustQuery("select to_days('1998-10-00')").Check(testkit.Rows("")) + tk.MustQuery("select week('1998-10-00')").Check(testkit.Rows("")) + tk.MustQuery("select week('1998-00-11')").Check(testkit.Rows("")) + tk.MustQuery("select WEEKDAY('1998-10-00')").Check(testkit.Rows("")) + tk.MustQuery("select WEEKDAY('1998-00-11')").Check(testkit.Rows("")) + tk.MustQuery("select WEEKOFYEAR('1998-10-00')").Check(testkit.Rows("")) + tk.MustQuery("select WEEKOFYEAR('1998-00-11')").Check(testkit.Rows("")) + tk.MustQuery("select YEARWEEK('1998-10-00')").Check(testkit.Rows("")) + tk.MustQuery("select YEARWEEK('1998-00-11')").Check(testkit.Rows("")) +} + +func TestIssue31640(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + + tk.MustExec("use test") + tk.MustExec("create table t(a json);") + tk.MustExec(`insert into t values ('"a"'), ('"B"'), ('"c"'), ('"D"'), ('{"a": 1}'), ('1'), ('{"b": 2}'), ('[1, 2]'), ('[3, 4]');`) + tk.MustQuery("select min(a) from t;").Check(testkit.Rows("1")) + tk.MustQuery("select max(a) from t;").Check(testkit.Rows("[3, 4]")) + tk.MustQuery("select min(a collate utf8mb4_bin) from t;").Check(testkit.Rows("\"B\"")) + tk.MustQuery("select max(a collate utf8mb4_bin) from t;").Check(testkit.Rows("{\"b\": 2}")) + tk.MustQuery("select min(a collate utf8mb4_unicode_ci) from t;").Check(testkit.Rows("\"a\"")) + tk.MustQuery("select max(a collate utf8mb4_unicode_ci) from t;").Check(testkit.Rows("1")) +} + +func TestIssue36279(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("SET timestamp=UNIX_TIMESTAMP('2011-11-01 17:48:00')") + + // test const + tk.MustQuery("SELECT cast(cast('12:12:12' as time) as datetime(6))").Check(testkit.Rows("2011-11-01 12:12:12.000000")) + + // test vec + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (tm time(6))") + tk.MustExec("insert into t values('23:59:59')") + tk.MustQuery("SELECT cast(tm as datetime(6)) from t").Check(testkit.Rows("2011-11-01 23:59:59.000000")) +} + +func TestIssue34998(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("CREATE TABLE `PK_S_MULTI_43`(`COL1` time(2) NOT NULL, `COL2` time(2) NOT NULL, `COL3` time(2) DEFAULT NULL, PRIMARY KEY(`COL1`,`COL2`))") + tk.MustExec("insert into PK_S_MULTI_43(col1, col2) values('-512:37:22.00', '-512:37:22.00')") + tk.MustQuery("select extract(day_microsecond from '-512:37:22.00')").Check(testkit.Rows("-5123722000000")) + tk.MustQuery("select extract(day_microsecond from col1) from PK_S_MULTI_43").Check(testkit.Rows("-5123722000000")) +} + +func TestIssue36358(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("create table t(c datetime(6))") + tk.MustExec("insert into t values('2001-01-01 02:03:04.050607')") + tk.MustQuery("select extract(day_microsecond from cast('2001-01-01 02:03:04.050607' as datetime(6))) from t").Check(testkit.Rows("1020304050607")) + tk.MustQuery("select extract(day_microsecond from c) from t").Check(testkit.Rows("1020304050607")) +} + +func TestJSONObjectWithBinaryCharset(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("create table t(a char(20), b blob);") + tk.MustExec("insert into t values ('a string', 'a binary string');") + tk.MustExec("select json_object(a, b) from t;") + tk.MustExec("select json_objectagg(a, b) from t;") + tk.MustGetErrCode("select json_object(b, a) from t;", errno.ErrInvalidJSONCharset) + err := tk.QueryToErr("select json_objectagg(b, a) from t;") + require.Error(t, err) + require.Equal(t, "[json:3144]Cannot create a JSON value from a string with CHARACTER SET 'binary'.", err.Error()) +} + +func TestCastJSONOpaqueValueToNumeric(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustQuery("select cast(cast(b'010101' as json) as signed);").Check(testkit.Rows("0")) + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1292 Truncated incorrect INTEGER value: '\"base64:type253:FQ==\"'")) + tk.MustQuery("select cast(json_extract(json_objectagg('a', b'010101'), '$.a') as signed);").Check(testkit.Rows("0")) + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1292 Truncated incorrect INTEGER value: '\"base64:type253:FQ==\"'")) + tk.MustQuery("select cast(json_extract(json_objectagg('a', b'010101'), '$.a') as double);").Check(testkit.Rows("0")) + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1292 Truncated incorrect FLOAT value: '\"base64:type253:FQ==\"'")) +} + +func TestCompareJSONWithOtherType(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("create table t(a JSON)") + tk.MustExec("insert into t values ('{}'), ('true'), ('5')") + tk.MustQuery("select * from t where a = TRUE;").Check(testkit.Rows("true")) + tk.MustQuery("select * from t where a < 6;").Check(testkit.Rows("5")) + tk.MustQuery("select * from t where a > 5;").Check(testkit.Rows("{}", "true")) +} + +func TestCastRealAsTime(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("create table t(d1 double, f float, d2 decimal(24,8))") + + // zero input + tk.MustExec("insert into t values(0, 0, 0)") + + // const + tk.MustQuery("select cast(111.1 as datetime) from t").Check(testkit.Rows("2000-01-11 00:00:00")) + tk.MustQuery("select cast(1311.1 as datetime) from t").Check(testkit.Rows("")) + + // vec + // valid input + tk.MustExec("insert into t values(111.1, 1122.1, 31212.111)") + tk.MustExec("insert into t values(121212.1111, 1121212.111111, 11121212.111111)") + tk.MustExec("insert into t values(99991111.1111111, 101.1111111, 20121212121212.1111111)") + // null input + tk.MustExec("insert into t values(NULL, NULL, NULL)") + // invalid input + tk.MustExec("insert into t values(1.1, 48.1, 100.1)") + tk.MustExec("insert into t values(1301.11, 1131.111, 100001111.111)") + tk.MustExec("insert into t values(20121212121260.1111111, 20121212126012.1111111, 20121212241212.1111111)") + tk.MustQuery("select cast(d1 as datetime), cast(f as datetime), cast(d2 as datetime) from t").Check(testkit.Rows( + "0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00", + "2000-01-11 00:00:00 2000-11-22 00:00:00 2003-12-12 00:00:00", + "2012-12-12 00:00:00 0112-12-12 00:00:00 1112-12-12 00:00:00", + "9999-11-11 00:00:00 2000-01-01 00:00:00 2012-12-12 12:12:12", + " ", + " ", + " ", + " ")) +} + +func TestJSONDepth(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("create table t(a JSON)") + tk.MustGetErrCode(`insert into t +with recursive c1 as (select cast(1 as signed) c, json_array(1) as a + union + select c + 1, json_array_insert(a, concat('$', repeat('[0]', c)), json_array(1)) + from c1 + where c < 101) +select a from c1 where c > 100;`, errno.ErrJSONDocumentTooDeep) + tk.MustExec(`insert into t +with recursive c1 as (select cast(1 as signed) c, json_array(1) as a + union + select c + 1, json_array_insert(a, concat('$', repeat('[0]', c)), json_array(1)) + from c1 + where c < 100) +select a from c1 where c > 99;`) + + err := tk.QueryToErr(`select json_array(a, 1) from t`) + require.Error(t, err) + // FIXME: mysql client shows the error. + //err = tk.QueryToErr(`select json_objectagg(1, a) from t;`) + //require.Error(t, err) + err = tk.QueryToErr(`select json_object(1, a) from t;`) + require.Error(t, err) + err = tk.QueryToErr(`select json_set(a, concat('$', repeat('[0]', 100)), json_array(json_array(3))) from t;`) + require.Error(t, err) + err = tk.QueryToErr(`select json_array_append(a, concat('$', repeat('[0]', 100)), 1) from t;`) + require.Error(t, err) + // FIXME: mysql client shows the error. + //err = tk.QueryToErr(`select json_arrayagg(a) from t;`) + //require.Error(t, err) +} + +func TestCastJSONTimeDuration(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("create table t(i INT, j JSON)") + + nowDate := time.Now().Format("2006-01-02") + + // DATE/DATETIME/TIME will be automatically converted to json date/datetime/duration + tk.MustExec("insert into t values (0, DATE('1998-06-13'))") + tk.MustExec("insert into t values (1, CAST('1998-06-13 12:12:12' as DATETIME))") + tk.MustExec("insert into t values (2, DATE('1596-03-31'))") + tk.MustExec("insert into t values (3, CAST('1596-03-31 12:12:12' as DATETIME))") + tk.MustExec(`insert into t values (4, '"1596-03-31 12:12:12"')`) + tk.MustExec(`insert into t values (5, '"12:12:12"')`) + tk.MustExec("insert into t values (6, CAST('12:12:12' as TIME))") + tk.MustQuery("select i, cast(j as date), cast(j as datetime), cast(j as time), json_type(j) from t").Check(testkit.Rows( + "0 1998-06-13 1998-06-13 00:00:00 00:00:00 DATE", + "1 1998-06-13 1998-06-13 12:12:12 12:12:12 DATETIME", + "2 1596-03-31 1596-03-31 00:00:00 00:00:00 DATE", + "3 1596-03-31 1596-03-31 12:12:12 12:12:12 DATETIME", + "4 1596-03-31 1596-03-31 12:12:12 12:12:12 STRING", + "5 2012-12-12 2012-12-12 00:00:00 12:12:12 STRING", + fmt.Sprintf("6 %s %s 12:12:12 12:12:12 TIME", nowDate, nowDate), + )) +} + +func TestRegexpPushdown(t *testing.T) { + store := testkit.CreateMockStore(t) + + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + + tk.MustExec("drop table if exists reg") + tk.MustExec("create table reg(a varchar(20) null,b varchar(20) null,rep varchar(20) null) charset=utf8mb4 collate=utf8mb4_general_ci;") + + tk.MustQuery("explain select a from reg where regexp_like(a, b);").Check(testkit.Rows( + "Projection_4 8000.00 root test.reg.a", + "└─TableReader_7 8000.00 root data:Selection_6", + " └─Selection_6 8000.00 cop[tikv] regexp_like(test.reg.a, test.reg.b)", + " └─TableFullScan_5 10000.00 cop[tikv] table:reg keep order:false, stats:pseudo")) + + tk.MustQuery("explain select a from reg where regexp_instr(a, b);").Check(testkit.Rows( + "Projection_4 8000.00 root test.reg.a", + "└─TableReader_7 8000.00 root data:Selection_6", + " └─Selection_6 8000.00 cop[tikv] regexp_instr(test.reg.a, test.reg.b)", + " └─TableFullScan_5 10000.00 cop[tikv] table:reg keep order:false, stats:pseudo")) + + tk.MustQuery("explain select a from reg where regexp_substr(a, b);").Check(testkit.Rows( + "Projection_4 8000.00 root test.reg.a", + "└─TableReader_7 8000.00 root data:Selection_6", + " └─Selection_6 8000.00 cop[tikv] regexp_substr(test.reg.a, test.reg.b)", + " └─TableFullScan_5 10000.00 cop[tikv] table:reg keep order:false, stats:pseudo")) + + tk.MustQuery("explain select a from reg where regexp_replace(a, b, rep);").Check(testkit.Rows( + "Projection_4 8000.00 root test.reg.a", + "└─TableReader_7 8000.00 root data:Selection_6", + " └─Selection_6 8000.00 cop[tikv] regexp_replace(test.reg.a, test.reg.b, test.reg.rep)", + " └─TableFullScan_5 10000.00 cop[tikv] table:reg keep order:false, stats:pseudo")) + + tk.MustExec("drop table if exists regbin") + tk.MustExec("create table regbin(a varchar(20) null,b varchar(20) null,rep varchar(20) null) charset=binary collate=binary;") + + tk.MustQuery("explain select a from regbin where regexp_like(a, b);").Check(testkit.Rows( + "Projection_4 8000.00 root test.regbin.a", + "└─Selection_5 8000.00 root regexp_like(test.regbin.a, test.regbin.b)", + " └─TableReader_7 10000.00 root data:TableFullScan_6", + " └─TableFullScan_6 10000.00 cop[tikv] table:regbin keep order:false, stats:pseudo")) +} + +func TestIssue35184(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + + tk.MustExec("drop table if exists ft") + tk.MustExec("create table ft (tint int, tdou double, tdec decimal(22,9),tchar char(44))") + tk.MustExec("insert into ft values(1234567890,123467890.1234,123467890.1234,'123467890.1234')") + tk.MustExec("insert into ft values(1234567890,123467890.123456789,123467890.123456789,'123467890.123456789')") + + result := tk.MustQuery("SELECT FROM_UNIXTIME(tchar) from ft") + unixTime1 := "1973-11-30 08:38:10.123400" + unixTime2 := "1973-11-30 08:38:10.123457" + result.Check(testkit.Rows(unixTime1, unixTime2)) + + tk.MustExec("drop table if exists ft") + tk.MustExec("create table ft (tint int, tdou double, tdec decimal(22,9),tchar varchar(44))") + tk.MustExec("insert into ft values(1234567890,123467890.1234,123467890.1234,'123467890.1234')") + tk.MustExec("insert into ft values(1234567890,123467890.123456789,123467890.123456789,'123467890.123456789')") + result = tk.MustQuery("SELECT FROM_UNIXTIME(tchar) from ft") + result.Check(testkit.Rows(unixTime1, unixTime2)) + + tk.MustExec("drop table if exists ft") + tk.MustExec("create table ft (tint int, tdou double, tdec decimal(22,9),tchar blob)") + tk.MustExec("insert into ft values(1234567890,123467890.1234,123467890.1234,'123467890.1234')") + tk.MustExec("insert into ft values(1234567890,123467890.123456789,123467890.123456789,'123467890.123456789')") + result = tk.MustQuery("SELECT FROM_UNIXTIME(tchar) from ft") + result.Check(testkit.Rows(unixTime1, unixTime2)) + + tk.MustExec("drop table if exists ft") + tk.MustExec("create table ft (tint int, tdou double, tdec decimal(22,9),tchar tinyblob)") + tk.MustExec("insert into ft values(1234567890,123467890.1234,123467890.1234,'123467890.1234')") + tk.MustExec("insert into ft values(1234567890,123467890.123456789,123467890.123456789,'123467890.123456789')") + result = tk.MustQuery("SELECT FROM_UNIXTIME(tchar) from ft") + result.Check(testkit.Rows(unixTime1, unixTime2)) + + tk.MustExec("drop table if exists ft") + tk.MustExec("create table ft (tint int, tdou double, tdec decimal(22,9),tchar mediumblob)") + tk.MustExec("insert into ft values(1234567890,123467890.1234,123467890.1234,'123467890.1234')") + tk.MustExec("insert into ft values(1234567890,123467890.123456789,123467890.123456789,'123467890.123456789')") + result = tk.MustQuery("SELECT FROM_UNIXTIME(tchar) from ft") + result.Check(testkit.Rows(unixTime1, unixTime2)) + + tk.MustExec("drop table if exists ft") + tk.MustExec("create table ft (tint int, tdou double, tdec decimal(22,9),tchar longblob)") + tk.MustExec("insert into ft values(1234567890,123467890.1234,123467890.1234,'123467890.1234')") + tk.MustExec("insert into ft values(1234567890,123467890.123456789,123467890.123456789,'123467890.123456789')") + result = tk.MustQuery("SELECT FROM_UNIXTIME(tchar) from ft") + result.Check(testkit.Rows(unixTime1, unixTime2)) + + tk.MustExec("truncate table ft") + tk.MustExec("insert into ft values(1234567890,123467890.1234,123467890.1234,'123467890.1234000000000000000000100111111111')") + result = tk.MustQuery("SELECT FROM_UNIXTIME(tchar) from ft") + result.Check(testkit.Rows(unixTime1)) + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1292 Truncated incorrect DECIMAL value: '123467890.1234000000000000000000100111111111'")) + + tk.MustExec("truncate table ft") + tk.MustExec("insert into ft values(1234567890,123467890.1234,123467890.1234,'11111123467890.1234')") + result = tk.MustQuery("SELECT FROM_UNIXTIME(tchar) from ft") + result.Check(testkit.Rows("")) + + tk.MustExec("drop table if exists ft") + tk.MustExec("create table ft (tint int, tdou double, tdec decimal(22,9),tchar char(44))") + tk.MustExec("insert into ft values(1234567890,123467890.1234,123467890.1234,'123467890.1234')") + result = tk.MustQuery("SELECT FROM_UNIXTIME(tchar) from ft where FROM_UNIXTIME(tchar)= '1973-11-30 08:38:10.123400' ") + result.Check(testkit.Rows(unixTime1)) + + result = tk.MustQuery("SELECT FROM_UNIXTIME(cast(tchar as decimal(44,1))) from ft where FROM_UNIXTIME(tchar)= '1973-11-30 08:38:10.123400' ") + result.Check(testkit.Rows("1973-11-30 08:38:10.1")) + + result = tk.MustQuery("SELECT FROM_UNIXTIME(tchar,'%Y%m%d') from ft where FROM_UNIXTIME(tchar)= '1973-11-30 08:38:10.123400' ") + result.Check(testkit.Rows("19731130")) +} + +func TestFix38127(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("create table t(dou double, varc varchar(100))") + tk.MustExec("insert into t values (1.23e23, '111111111111111111111111111111111111111111111111111111111111111111111111111')") + tk.MustQuery("select from_unixtime(dou) from t").Check(testkit.Rows("")) + tk.MustQuery("select from_unixtime(varc) from t").Check(testkit.Rows("")) + tk.MustQuery("select from_unixtime(dou, '%Y-%m-%d') from t").Check(testkit.Rows("")) + tk.MustQuery("select from_unixtime(varc, '%Y-%m-%d') from t").Check(testkit.Rows("")) +} + +func TestJSONStorageFree(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustQuery("select json_storage_free(NULL)").Check(testkit.Rows("")) + tk.MustQuery("select json_storage_free('{}')").Check(testkit.Rows("0")) + tk.MustQuery("select json_storage_free('1')").Check(testkit.Rows("0")) + tk.MustQuery(`select json_storage_free('{"a": "b"}')`).Check(testkit.Rows("0")) + err := tk.ExecToErr(`select json_storage_free('{"c":["a","b"]`) + require.Error(t, err, "[json:3140]Invalid JSON text: The document root must not be followed by other values.") +} + +func TestIssue38736(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("CREATE TABLE t0(c0 BOOL, c1 INT);") + tk.MustExec("CREATE TABLE t1 LIKE t0;") + tk.MustExec("CREATE definer='root'@'localhost' VIEW v0(c0) AS SELECT IS_IPV4(t0.c1) FROM t0, t1;") + tk.MustExec("INSERT INTO t0(c0, c1) VALUES (true, 0);") + tk.MustExec("INSERT INTO t1(c0, c1) VALUES (true, 2);") + + // The filter is evaled as false. + tk.MustQuery("SELECT v0.c0 FROM v0 WHERE (v0.c0)NOT LIKE(BINARY v0.c0);").Check(testkit.Rows()) + + // Also the filter is evaled as false. + tk.MustQuery("SELECT v0.c0 FROM v0 WHERE (v0.c0)NOT LIKE(BINARY v0.c0) or v0.c0 > 0").Check(testkit.Rows()) +} + +func TestJSONExtractFromLast(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustQuery(`select json_extract('[{"a": [1,2,3,4]}]', '$[0] . a[last]')`).Check(testkit.Rows("4")) + tk.MustQuery(`select json_extract('[{"a": [1,2,3,4]}]', '$[0] . a [last - 1]')`).Check(testkit.Rows("3")) + tk.MustQuery(`select json_extract('[{"a": [1,2,3,4]}]', '$[0].a [last - 100]')`).Check(testkit.Rows("")) +} + +func TestJSONExtractRange(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustQuery(`select json_extract('[{"a": [1,2,3,4]}]', '$[0].a[1 to last]')`).Check(testkit.Rows("[2, 3, 4]")) + tk.MustQuery(`select json_extract('[{"a": [1,2,3,4]}]', '$[0].a[1 to last - 1]')`).Check(testkit.Rows("[2, 3]")) + tk.MustQuery(`select json_extract('[{"a": [1,2,3,4]}]', '$[0].a[1 to last - 100]')`).Check(testkit.Rows("")) + tk.MustQuery(`select json_extract('[{"a": [1,2,3,4]}]', '$[0].a[1 to 100]')`).Check(testkit.Rows("[2, 3, 4]")) + tk.MustQuery(`select json_extract('[{"a": [1,2,3,4]}]', '$[0].a[0 to last]')`).Check(testkit.Rows("[1, 2, 3, 4]")) + tk.MustQuery(`select json_extract('[{"a": [1,2,3,4]}]', '$[0].a[0 to 2]')`).Check(testkit.Rows("[1, 2, 3]")) +} + +func TestIfNullParamMarker(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("create table t (c1 varchar(100), c2 varchar(128));") + tk.MustExec(`prepare pr1 from "insert into t values(ifnull(?,' '),ifnull(?,' '))";`) + tk.MustExec(`set @a='1',@b=repeat('x', 80);`) + // Should not report 'Data too long for column' error. + tk.MustExec(`execute pr1 using @a,@b;`) +} + +func TestIssue39146(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("CREATE TABLE `sun` ( `dest` varchar(10) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;") + tk.MustExec("insert into sun values('20231020');") + tk.MustExec("set @@sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';") + tk.MustExec("set @@tidb_enable_vectorized_expression = on;") + tk.MustQuery(`select str_to_date(substr(dest,1,6),'%H%i%s') from sun;`).Check(testkit.Rows("20:23:10")) + tk.MustExec("set @@tidb_enable_vectorized_expression = off;") + tk.MustQuery(`select str_to_date(substr(dest,1,6),'%H%i%s') from sun;`).Check(testkit.Rows("20:23:10")) +} + +func TestIssue40536(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("CREATE TABLE `6bf9e76d-ab44-4031-8a07-418b10741580` (\n `e0b5f703-6cfe-49b4-bc21-16a6455e43a7` set('7','va','ung60','ow','1g','gxwz5','uhnh','k','5la1','q8d9c','1f') NOT NULL DEFAULT '7,1g,uhnh,5la1,q8d9c',\n `fbc3527f-9617-4b9d-a5dc-4be31c00d8a5` datetime DEFAULT '6449-09-28 14:39:04',\n PRIMARY KEY (`e0b5f703-6cfe-49b4-bc21-16a6455e43a7`) /*T![clustered_index] CLUSTERED */\n) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;") + tk.MustExec("CREATE TABLE `8919f3f4-25be-4a1a-904a-bb5e863d8fc8` (\n `9804d5f2-cbc7-43b7-b241-ea2656dc941a` enum('s951','36d','ua65','49yru','6l2em','4ea','jf2d2','vprsc','3yl7n','hz','ov') DEFAULT '4ea',\n `323cdbcb-0c14-4362-90ab-ea42caaed6a5` year(4) NOT NULL DEFAULT '1983',\n `b9b70f39-1a02-4114-9d7d-fa6259c1b691` time DEFAULT '20:18:04',\n PRIMARY KEY (`323cdbcb-0c14-4362-90ab-ea42caaed6a5`) /*T![clustered_index] CLUSTERED */,\n KEY `a704d6bb-772b-44ea-8cb0-6f7491c1aaa6` (`323cdbcb-0c14-4362-90ab-ea42caaed6a5`,`9804d5f2-cbc7-43b7-b241-ea2656dc941a`)\n) ENGINE=InnoDB DEFAULT CHARSET=ascii COLLATE=ascii_bin;") + tk.MustExec("delete from `6bf9e76d-ab44-4031-8a07-418b10741580` where not( `6bf9e76d-ab44-4031-8a07-418b10741580`.`e0b5f703-6cfe-49b4-bc21-16a6455e43a7` in ( select `9804d5f2-cbc7-43b7-b241-ea2656dc941a` from `8919f3f4-25be-4a1a-904a-bb5e863d8fc8` where `6bf9e76d-ab44-4031-8a07-418b10741580`.`e0b5f703-6cfe-49b4-bc21-16a6455e43a7` in ( '1f' ) and `6bf9e76d-ab44-4031-8a07-418b10741580`.`e0b5f703-6cfe-49b4-bc21-16a6455e43a7` in ( '1g' ,'va' ,'uhnh' ) ) ) and not( IsNull( `6bf9e76d-ab44-4031-8a07-418b10741580`.`e0b5f703-6cfe-49b4-bc21-16a6455e43a7` ) );\n") +} +>>>>>>> 00617c96ef (expression, cmd: fix ColumnSubstitute and allow some cases to substitute (#38826)) diff --git a/expression/util.go b/expression/util.go index e3ace0b037c42..c9062490c251e 100644 --- a/expression/util.go +++ b/expression/util.go @@ -244,8 +244,12 @@ func ColumnSubstituteImpl(expr Expression, schema *Schema, newExprs []Expression if v.InOperand { newExpr = setExprColumnInOperand(newExpr) } +<<<<<<< HEAD newExpr.SetCoercibility(v.Coercibility()) return true, newExpr +======= + return true, false, newExpr +>>>>>>> 00617c96ef (expression, cmd: fix ColumnSubstitute and allow some cases to substitute (#38826)) case *ScalarFunction: substituted := false if v.FuncName.L == ast.Cast { @@ -262,11 +266,24 @@ func ColumnSubstituteImpl(expr Expression, schema *Schema, newExprs []Expression // cowExprRef is a copy-on-write util, args array allocation happens only // when expr in args is changed refExprArr := cowExprRef{v.GetArgs(), nil} +<<<<<<< HEAD _, coll := DeriveCollationFromExprs(v.GetCtx(), v.GetArgs()...) +======= + oldCollEt, err := CheckAndDeriveCollationFromExprs(v.GetCtx(), v.FuncName.L, v.RetType.EvalType(), v.GetArgs()...) + if err != nil { + logutil.BgLogger().Error("Unexpected error happened during ColumnSubstitution", zap.Stack("stack")) + return false, false, v + } + var tmpArgForCollCheck []Expression + if collate.NewCollationEnabled() { + tmpArgForCollCheck = make([]Expression, len(v.GetArgs())) + } +>>>>>>> 00617c96ef (expression, cmd: fix ColumnSubstitute and allow some cases to substitute (#38826)) for idx, arg := range v.GetArgs() { changed, newFuncExpr := ColumnSubstituteImpl(arg, schema, newExprs) if collate.NewCollationEnabled() { // Make sure the collation used by the ScalarFunction isn't changed and its result collation is not weaker than the collation used by the ScalarFunction. +<<<<<<< HEAD if changed { changed = false tmpArgs := make([]Expression, 0, len(v.GetArgs())) @@ -274,6 +291,22 @@ func ColumnSubstituteImpl(expr Expression, schema *Schema, newExprs []Expression _, newColl := DeriveCollationFromExprs(v.GetCtx(), append(v.GetArgs(), newFuncExpr)...) if coll == newColl { changed = checkCollationStrictness(coll, newFuncExpr.GetType().Collate) +======= + changed = false + copy(tmpArgForCollCheck, refExprArr.Result()) + tmpArgForCollCheck[idx] = newFuncExpr + newCollEt, err := CheckAndDeriveCollationFromExprs(v.GetCtx(), v.FuncName.L, v.RetType.EvalType(), tmpArgForCollCheck...) + if err != nil { + logutil.BgLogger().Error("Unexpected error happened during ColumnSubstitution", zap.Stack("stack")) + return false, failed, v + } + if oldCollEt.Collation == newCollEt.Collation { + if newFuncExpr.GetType().GetCollate() == arg.GetType().GetCollate() && newFuncExpr.Coercibility() == arg.Coercibility() { + // It's safe to use the new expression, otherwise some cases in projection push-down will be wrong. + changed = true + } else { + changed = checkCollationStrictness(oldCollEt.Collation, newFuncExpr.GetType().GetCollate()) +>>>>>>> 00617c96ef (expression, cmd: fix ColumnSubstitute and allow some cases to substitute (#38826)) } } } diff --git a/planner/core/exhaust_physical_plans.go b/planner/core/exhaust_physical_plans.go index 5dd497f2385e0..072f746d46b66 100644 --- a/planner/core/exhaust_physical_plans.go +++ b/planner/core/exhaust_physical_plans.go @@ -1253,9 +1253,18 @@ func (ijHelper *indexJoinBuildHelper) resetContextForIndex(innerKeys []*expressi ijHelper.curIdxOff2KeyOff[i] = tmpSchema.ColumnIndex(idxCol) if ijHelper.curIdxOff2KeyOff[i] >= 0 { // Don't use the join columns if their collations are unmatched and the new collation is enabled. +<<<<<<< HEAD if collate.NewCollationEnabled() && types.IsString(idxCol.RetType.Tp) && types.IsString(outerKeys[ijHelper.curIdxOff2KeyOff[i]].RetType.Tp) { _, coll := expression.DeriveCollationFromExprs(nil, idxCol, outerKeys[ijHelper.curIdxOff2KeyOff[i]]) if !collate.CompatibleCollate(idxCol.GetType().Collate, coll) { +======= + if collate.NewCollationEnabled() && types.IsString(idxCol.RetType.GetType()) && types.IsString(outerKeys[ijHelper.curIdxOff2KeyOff[i]].RetType.GetType()) { + et, err := expression.CheckAndDeriveCollationFromExprs(ijHelper.innerPlan.ctx, "equal", types.ETInt, idxCol, outerKeys[ijHelper.curIdxOff2KeyOff[i]]) + if err != nil { + logutil.BgLogger().Error("Unexpected error happened during constructing index join", zap.Stack("stack")) + } + if !collate.CompatibleCollate(idxCol.GetType().GetCollate(), et.Collation) { +>>>>>>> 00617c96ef (expression, cmd: fix ColumnSubstitute and allow some cases to substitute (#38826)) ijHelper.curIdxOff2KeyOff[i] = -1 } }