From 714df29d7841001ccd2eeb56ea84a6520ff9e782 Mon Sep 17 00:00:00 2001 From: Yuanjia Zhang Date: Wed, 2 Sep 2020 09:20:32 +0800 Subject: [PATCH] cherry pick #19331 to release-3.0 Signed-off-by: ti-srebot --- expression/expression.go | 349 +++++++++++++++++++++++++++++++++ expression/integration_test.go | 140 +++++++++++++ 2 files changed, 489 insertions(+) diff --git a/expression/expression.go b/expression/expression.go index f8686f5d57031..72708403a0c62 100644 --- a/expression/expression.go +++ b/expression/expression.go @@ -387,6 +387,355 @@ func IsBinaryLiteral(expr Expression) bool { return ok && con.Value.Kind() == types.KindBinaryLiteral } +<<<<<<< HEAD +======= +func canFuncBePushed(sf *ScalarFunction, storeType kv.StoreType) bool { + // Use the failpoint to control whether to push down an expression in the integration test. + // Push down all expression if the `failpoint expression` is `all`, otherwise, check + // whether scalar function's name is contained in the enabled expression list (e.g.`ne,eq,lt`). + // If neither of the above is true, switch to original logic. + failpoint.Inject("PushDownTestSwitcher", func(val failpoint.Value) { + enabled := val.(string) + if enabled == "all" { + failpoint.Return(true) + } + exprs := strings.Split(enabled, ",") + for _, expr := range exprs { + if strings.ToLower(strings.TrimSpace(expr)) == sf.FuncName.L { + failpoint.Return(true) + } + } + }) + + ret := false + switch sf.FuncName.L { + case + // op functions. + ast.LogicAnd, + ast.LogicOr, + ast.LogicXor, + ast.UnaryNot, + ast.And, + ast.Or, + ast.Xor, + ast.BitNeg, + ast.LeftShift, + ast.RightShift, + ast.UnaryMinus, + + // compare functions. + ast.LT, + ast.LE, + ast.EQ, + ast.NE, + ast.GE, + ast.GT, + ast.NullEQ, + ast.In, + ast.IsNull, + ast.Like, + ast.IsTruth, + ast.IsFalsity, + + // arithmetical functions. + ast.Plus, + ast.Minus, + ast.Mul, + ast.Div, + ast.Abs, + + // math functions. + ast.Ceil, + ast.Ceiling, + ast.Floor, + ast.Sqrt, + ast.Sign, + ast.Ln, + ast.Log, + ast.Log2, + ast.Log10, + ast.Exp, + ast.Pow, + // Rust use the llvm math functions, which have different precision with Golang/MySQL(cmath) + // open the following switchers if we implement them in coprocessor via `cmath` + // ast.Sin, + // ast.Asin, + // ast.Cos, + // ast.Acos, + // ast.Tan, + // ast.Atan, + // ast.Atan2, + // ast.Cot, + ast.Radians, + ast.Degrees, + ast.Conv, + ast.CRC32, + + // control flow functions. + ast.Case, + ast.If, + ast.Ifnull, + ast.Coalesce, + + // string functions. + ast.Length, + ast.BitLength, + ast.Concat, + ast.ConcatWS, + // ast.Locate, + ast.Replace, + ast.ASCII, + ast.Hex, + ast.Reverse, + ast.LTrim, + ast.RTrim, + // ast.Left, + ast.Strcmp, + ast.Space, + ast.Elt, + ast.Field, + + // json functions. + ast.JSONType, + ast.JSONExtract, + // FIXME: JSONUnquote is incompatible with Coprocessor + // ast.JSONUnquote, + ast.JSONObject, + ast.JSONArray, + ast.JSONMerge, + ast.JSONSet, + ast.JSONInsert, + // ast.JSONReplace, + ast.JSONRemove, + ast.JSONLength, + + // date functions. + ast.DateFormat, + ast.FromDays, + // ast.ToDays, + ast.DayOfYear, + ast.DayOfMonth, + ast.Year, + ast.Month, + // FIXME: the coprocessor cannot keep the same behavior with TiDB in current compute framework + // ast.Hour, + // ast.Minute, + // ast.Second, + // ast.MicroSecond, + // ast.DayName, + ast.PeriodAdd, + ast.PeriodDiff, + ast.TimestampDiff, + ast.DateAdd, + ast.FromUnixTime, + + // encryption functions. + ast.MD5, + ast.SHA1, + ast.UncompressedLength, + + ast.Cast, + + // misc functions. + ast.InetNtoa, + ast.InetAton, + ast.Inet6Ntoa, + ast.Inet6Aton, + ast.IsIPv4, + ast.IsIPv4Compat, + ast.IsIPv4Mapped, + ast.IsIPv6: + ret = true + + // A special case: Only push down Round by signature + case ast.Round: + switch sf.Function.PbCode() { + case + tipb.ScalarFuncSig_RoundReal, + tipb.ScalarFuncSig_RoundInt, + tipb.ScalarFuncSig_RoundDec: + ret = true + } + case + ast.Substring, + ast.Substr: + switch sf.Function.PbCode() { + case + tipb.ScalarFuncSig_Substring2ArgsUTF8, + tipb.ScalarFuncSig_Substring3ArgsUTF8: + ret = true + } + case ast.Rand: + switch sf.Function.PbCode() { + case + tipb.ScalarFuncSig_RandWithSeedFirstGen: + ret = true + } + } + if ret { + switch storeType { + case kv.TiFlash: + ret = scalarExprSupportedByFlash(sf) + case kv.TiKV: + ret = scalarExprSupportedByTiKV(sf) + case kv.TiDB: + ret = scalarExprSupportedByTiDB(sf) + } + } + if ret { + ret = IsPushDownEnabled(sf.FuncName.L, storeType) + } + return ret +} + +func storeTypeMask(storeType kv.StoreType) uint32 { + if storeType == kv.UnSpecified { + return 1<>>>>>> 853e0b4... expression: fix errors in Apply when the type of correlation column is `bit` (#19331) // wrapWithIsTrue wraps `arg` with istrue function if the return type of expr is not // type int, otherwise, returns `arg` directly. // The `keepNull` controls what the istrue function will return when `arg` is null: diff --git a/expression/integration_test.go b/expression/integration_test.go index ed033cbd15a95..56efc1cb66e3e 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -5144,3 +5144,143 @@ func (s *testIntegrationSuite) TestIssue18850(c *C) { tk.MustExec("insert into t1 values (1, 'A');") tk.MustQuery("select /*+ HASH_JOIN(t, t1) */ * from t join t1 on t.b = t1.b1;").Check(testkit.Rows("1 A 1 A")) } +<<<<<<< HEAD +======= + +func (s *testIntegrationSerialSuite) TestNullValueRange(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(a int, b int, index(a))") + tk.MustExec("insert into t values (null, 0), (null, 1), (10, 11), (10, 12)") + tk.MustQuery("select * from t use index(a) where a is null order by b").Check(testkit.Rows(" 0", " 1")) + tk.MustQuery("select * from t use index(a) where a<=>null order by b").Check(testkit.Rows(" 0", " 1")) + tk.MustQuery("select * from t use index(a) where a<=>10 order by b").Check(testkit.Rows("10 11", "10 12")) + + tk.MustExec("drop table if exists t1") + tk.MustExec("create table t1(a int, b int, c int, unique key(a, b, c))") + tk.MustExec("insert into t1 values (1, null, 1), (1, null, 2), (1, null, 3), (1, null, 4)") + tk.MustExec("insert into t1 values (1, 1, 1), (1, 2, 2), (1, 3, 33), (1, 4, 44)") + tk.MustQuery("select c from t1 where a=1 and b<=>null and c>2 order by c").Check(testkit.Rows("3", "4")) + tk.MustQuery("select c from t1 where a=1 and b is null and c>2 order by c").Check(testkit.Rows("3", "4")) + tk.MustQuery("select c from t1 where a=1 and b is not null and c>2 order by c").Check(testkit.Rows("33", "44")) +} + +func (s *testIntegrationSerialSuite) TestIssue18662(c *C) { + collate.SetNewCollationEnabledForTest(true) + defer collate.SetNewCollationEnabledForTest(false) + + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(a varchar(10) collate utf8mb4_bin, b varchar(10) collate utf8mb4_general_ci);") + tk.MustExec("insert into t (a, b) values ('a', 'A');") + tk.MustQuery("select * from t where field('A', a collate utf8mb4_general_ci, b) > 1;").Check(testkit.Rows()) + tk.MustQuery("select * from t where field('A', a, b collate utf8mb4_general_ci) > 1;").Check(testkit.Rows()) + tk.MustQuery("select * from t where field('A' collate utf8mb4_general_ci, a, b) > 1;").Check(testkit.Rows()) + tk.MustQuery("select * from t where field('A', a, b) > 1;").Check(testkit.Rows("a A")) +} + +func (s *testIntegrationSerialSuite) TestIssue19045(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t, t1, t2") + tk.MustExec(`CREATE TABLE t ( + id int(11) NOT NULL AUTO_INCREMENT, + a char(10) DEFAULT NULL, + PRIMARY KEY (id) +);`) + tk.MustExec(`CREATE TABLE t1 ( + id int(11) NOT NULL AUTO_INCREMENT, + a char(10) DEFAULT NULL, + b char(10) DEFAULT NULL, + c char(10) DEFAULT NULL, + PRIMARY KEY (id) +);`) + tk.MustExec(`CREATE TABLE t2 ( + id int(11) NOT NULL AUTO_INCREMENT, + a char(10) DEFAULT NULL, + b char(10) DEFAULT NULL, + PRIMARY KEY (id), + UNIQUE KEY b (b) +);`) + tk.MustExec(`insert into t1(a,b,c) values('hs4_0004', "04", "101"), ('a01', "01", "101"),('a011', "02", "101");`) + tk.MustExec(`insert into t2(a,b) values("02","03");`) + tk.MustExec(`insert into t(a) values('101'),('101');`) + tk.MustQuery(`select ( SELECT t1.a FROM t1, t2 WHERE t1.b = t2.a AND t2.b = '03' AND t1.c = a.a) invode from t a ;`).Check(testkit.Rows("a011", "a011")) +} + +func (s *testIntegrationSerialSuite) TestIssue19116(c *C) { + collate.SetNewCollationEnabledForTest(true) + defer collate.SetNewCollationEnabledForTest(false) + + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("set names utf8mb4 collate utf8mb4_general_ci;") + tk.MustQuery("select collation(concat(1 collate `binary`));").Check(testkit.Rows("binary")) + tk.MustQuery("select coercibility(concat(1 collate `binary`));").Check(testkit.Rows("0")) + tk.MustQuery("select collation(concat(NULL,NULL));").Check(testkit.Rows("binary")) + tk.MustQuery("select coercibility(concat(NULL,NULL));").Check(testkit.Rows("6")) + tk.MustQuery("select collation(concat(1,1));").Check(testkit.Rows("utf8mb4_general_ci")) + tk.MustQuery("select coercibility(concat(1,1));").Check(testkit.Rows("4")) + tk.MustQuery("select collation(1);").Check(testkit.Rows("binary")) + tk.MustQuery("select coercibility(1);").Check(testkit.Rows("5")) + tk.MustQuery("select coercibility(1=1);").Check(testkit.Rows("5")) +} + +func (s *testIntegrationSerialSuite) TestIssue19315(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("drop table if exists t1") + tk.MustExec("CREATE TABLE `t` (`a` bit(10) DEFAULT NULL,`b` int(11) DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin") + tk.MustExec("INSERT INTO `t` VALUES (_binary '\\0',1),(_binary '\\0',2),(_binary '\\0',5),(_binary '\\0',4),(_binary '\\0',2),(_binary '\\0 ',4)") + tk.MustExec("CREATE TABLE `t1` (`a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin") + tk.MustExec("INSERT INTO `t1` VALUES (1,1),(1,5),(2,3),(2,4),(3,3)") + err := tk.QueryToErr("select * from t where t.b > (select min(t1.b) from t1 where t1.a > t.a)") + c.Assert(err, IsNil) +} + +func (s *testIntegrationSerialSuite) TestIssue18674(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustQuery("select -1.0 % -1.0").Check(testkit.Rows("0.0")) + tk.MustExec("use test") + tk.MustExec("drop table if exists t1") + tk.MustExec("create table t1(`pk` int primary key,`col_float_key_signed` float ,key (`col_float_key_signed`))") + tk.MustExec("insert into t1 values (0, null), (1, 0), (2, -0), (3, 1), (-1,-1)") + tk.MustQuery("select * from t1 where ( `col_float_key_signed` % `col_float_key_signed`) IS FALSE").Sort().Check(testkit.Rows("-1 -1", "3 1")) + tk.MustQuery("select `col_float_key_signed` , `col_float_key_signed` % `col_float_key_signed` from t1").Sort().Check(testkit.Rows( + "-1 -0", "0 ", "0 ", "1 0", " ")) + tk.MustQuery("select `col_float_key_signed` , (`col_float_key_signed` % `col_float_key_signed`) IS FALSE from t1").Sort().Check(testkit.Rows( + "-1 1", "0 0", "0 0", "1 1", " 0")) +} + +func (s *testIntegrationSerialSuite) TestIssue17063(c *C) { + collate.SetNewCollationEnabledForTest(true) + defer collate.SetNewCollationEnabledForTest(false) + + tk := testkit.NewTestKit(c, s.store) + tk.MustExec(`use test;`) + tk.MustExec(`drop table if exists t;`) + tk.MustExec("create table t(a char, b char) collate utf8mb4_general_ci;") + tk.MustExec(`insert into t values('a', 'b');`) + tk.MustExec(`insert into t values('a', 'B');`) + tk.MustQuery(`select * from t where if(a='x', a, b) = 'b';`).Check(testkit.Rows("a b", "a B")) + tk.MustQuery(`select collation(if(a='x', a, b)) from t;`).Check(testkit.Rows("utf8mb4_general_ci", "utf8mb4_general_ci")) + tk.MustQuery(`select coercibility(if(a='x', a, b)) from t;`).Check(testkit.Rows("2", "2")) + tk.MustQuery(`select collation(lag(b, 1, 'B') over w) from t window w as (order by b);`).Check(testkit.Rows("utf8mb4_general_ci", "utf8mb4_general_ci")) + tk.MustQuery(`select coercibility(lag(b, 1, 'B') over w) from t window w as (order by b);`).Check(testkit.Rows("2", "2")) +} + +func (s *testIntegrationSuite) TestIssue19504(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t1;") + tk.MustExec("create table t1 (c_int int, primary key (c_int));") + tk.MustExec("insert into t1 values (1), (2), (3);") + tk.MustExec("drop table if exists t2;") + tk.MustExec("create table t2 (c_int int, primary key (c_int));") + tk.MustExec("insert into t2 values (1);") + tk.MustQuery("select (select count(c_int) from t2 where c_int = t1.c_int) c1, (select count(1) from t2 where c_int = t1.c_int) c2 from t1;"). + Check(testkit.Rows("1 1", "0 0", "0 0")) +} +>>>>>>> 853e0b4... expression: fix errors in Apply when the type of correlation column is `bit` (#19331)