diff --git a/planner/core/integration_test.go b/planner/core/integration_test.go index 15805ff617e92..92f722105b555 100644 --- a/planner/core/integration_test.go +++ b/planner/core/integration_test.go @@ -1348,8 +1348,2582 @@ func (s *testIntegrationSerialSuite) TestNotReadOnlySQLOnTiFlash(c *C) { tk.MustExec("use test") tk.MustExec("drop table if exists t") +<<<<<<< HEAD tk.MustExec("create table t (a int, b varchar(20))") tk.MustExec(`set @@tidb_isolation_read_engines = "tiflash"`) +======= + tk.MustExec("create table t(a int primary key, b int, c int, key b(b))") + var input []string + var output []struct { + SQL string + Plan []string + Warnings []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + warnings := tk.Se.GetSessionVars().StmtCtx.GetWarnings() + output[i].Warnings = make([]string, len(warnings)) + for j, warning := range warnings { + output[i].Warnings[j] = warning.Err.Error() + } + }) + tk.MustQuery(tt).Check(testkit.Rows(output[i].Plan...)) + warnings := tk.Se.GetSessionVars().StmtCtx.GetWarnings() + c.Assert(len(warnings), Equals, len(output[i].Warnings)) + for j, warning := range warnings { + c.Assert(output[i].Warnings[j], Equals, warning.Err.Error()) + } + } +} + +func (s *testIntegrationSuite) TestIssue15813(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t0, t1") + tk.MustExec("create table t0(c0 int primary key)") + tk.MustExec("create table t1(c0 int primary key)") + tk.MustExec("CREATE INDEX i0 ON t0(c0)") + tk.MustExec("CREATE INDEX i0 ON t1(c0)") + tk.MustQuery("select /*+ MERGE_JOIN(t0, t1) */ * from t0, t1 where t0.c0 = t1.c0").Check(testkit.Rows()) +} + +func (s *testIntegrationSuite) TestIssue31261(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec(`use test`) + tk.MustExec(`drop table if exists PK_MULTI_COL_5177`) + tk.MustExec(` CREATE TABLE PK_MULTI_COL_5177 ( + COL1 binary(10) NOT NULL, + COL2 varbinary(10) NOT NULL, + COL3 smallint(45) NOT NULL, + PRIMARY KEY (COL1(5),COL2,COL3), + UNIQUE KEY UIDXM (COL1(5),COL2), + UNIQUE KEY UIDX (COL2), + KEY IDX3 (COL3), + KEY IDXM (COL3,COL2))`) + tk.MustExec(`insert into PK_MULTI_COL_5177(col1, col2, col3) values(0x00000000000000000000, 0x002B200DF5BA03E59F82, 1)`) + c.Assert(len(tk.MustQuery(`select col1, col2 from PK_MULTI_COL_5177 where col1 = 0x00000000000000000000 and col2 in (0x002B200DF5BA03E59F82, 0x002B200DF5BA03E59F82, 0x002B200DF5BA03E59F82)`).Rows()), Equals, 1) + c.Assert(len(tk.MustQuery(`select col1, col2 from PK_MULTI_COL_5177 where col1 = 0x00000000000000000000 and col2 = 0x002B200DF5BA03E59F82`).Rows()), Equals, 1) +} + +func (s *testIntegrationSuite) TestFullGroupByOrderBy(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)") + tk.MustQuery("select count(a) as b from t group by a order by b").Check(testkit.Rows()) + err := tk.ExecToErr("select count(a) as cnt from t group by a order by b") + c.Assert(terror.ErrorEqual(err, core.ErrFieldNotInGroupBy), IsTrue) +} + +func (s *testIntegrationSuite) TestHintWithoutTableWarning(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t1, t2") + tk.MustExec("create table t1(a int, b int, c int, key a(a))") + tk.MustExec("create table t2(a int, b int, c int, key a(a))") + var input []string + var output []struct { + SQL string + Warnings []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + tk.MustQuery(tt) + warns := tk.Se.GetSessionVars().StmtCtx.GetWarnings() + output[i].Warnings = make([]string, len(warns)) + for j := range warns { + output[i].Warnings[j] = warns[j].Err.Error() + } + }) + tk.MustQuery(tt) + warns := tk.Se.GetSessionVars().StmtCtx.GetWarnings() + c.Assert(len(warns), Equals, len(output[i].Warnings)) + for j := range warns { + c.Assert(warns[j].Level, Equals, stmtctx.WarnLevelWarning) + c.Assert(warns[j].Err.Error(), Equals, output[i].Warnings[j]) + } + } +} + +func (s *testIntegrationSuite) TestIssue15858(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 primary key)") + tk.MustExec("select * from t t1, (select a from t order by a+1) t2 where t1.a = t2.a") +} + +func (s *testIntegrationSuite) TestIssue15846(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t0, t1") + tk.MustExec("CREATE TABLE t0(t0 INT UNIQUE);") + tk.MustExec("CREATE TABLE t1(c0 FLOAT);") + tk.MustExec("INSERT INTO t1(c0) VALUES (0);") + tk.MustExec("INSERT INTO t0(t0) VALUES (NULL), (NULL);") + tk.MustQuery("SELECT t1.c0 FROM t1 LEFT JOIN t0 ON 1;").Check(testkit.Rows("0", "0")) + + tk.MustExec("drop table if exists t0, t1") + tk.MustExec("CREATE TABLE t0(t0 INT);") + tk.MustExec("CREATE TABLE t1(c0 FLOAT);") + tk.MustExec("INSERT INTO t1(c0) VALUES (0);") + tk.MustExec("INSERT INTO t0(t0) VALUES (NULL), (NULL);") + tk.MustQuery("SELECT t1.c0 FROM t1 LEFT JOIN t0 ON 1;").Check(testkit.Rows("0", "0")) + + tk.MustExec("drop table if exists t0, t1") + tk.MustExec("CREATE TABLE t0(t0 INT);") + tk.MustExec("CREATE TABLE t1(c0 FLOAT);") + tk.MustExec("create unique index idx on t0(t0);") + tk.MustExec("INSERT INTO t1(c0) VALUES (0);") + tk.MustExec("INSERT INTO t0(t0) VALUES (NULL), (NULL);") + tk.MustQuery("SELECT t1.c0 FROM t1 LEFT JOIN t0 ON 1;").Check(testkit.Rows("0", "0")) +} + +func (s *testIntegrationSuite) TestFloorUnixTimestampPruning(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists floor_unix_timestamp") + tk.MustExec(`create table floor_unix_timestamp (ts timestamp(3)) +partition by range (floor(unix_timestamp(ts))) ( +partition p0 values less than (unix_timestamp('2020-04-05 00:00:00')), +partition p1 values less than (unix_timestamp('2020-04-12 00:00:00')), +partition p2 values less than (unix_timestamp('2020-04-15 00:00:00')))`) + tk.MustExec("insert into floor_unix_timestamp values ('2020-04-04 00:00:00')") + tk.MustExec("insert into floor_unix_timestamp values ('2020-04-04 23:59:59.999')") + tk.MustExec("insert into floor_unix_timestamp values ('2020-04-05 00:00:00')") + tk.MustExec("insert into floor_unix_timestamp values ('2020-04-05 00:00:00.001')") + tk.MustExec("insert into floor_unix_timestamp values ('2020-04-12 01:02:03.456')") + tk.MustExec("insert into floor_unix_timestamp values ('2020-04-14 00:00:42')") + tk.MustQuery("select count(*) from floor_unix_timestamp where '2020-04-05 00:00:00.001' = ts").Check(testkit.Rows("1")) + tk.MustQuery("select * from floor_unix_timestamp where ts > '2020-04-05 00:00:00' order by ts").Check(testkit.Rows("2020-04-05 00:00:00.001", "2020-04-12 01:02:03.456", "2020-04-14 00:00:42.000")) + tk.MustQuery("select count(*) from floor_unix_timestamp where ts <= '2020-04-05 23:00:00'").Check(testkit.Rows("4")) + tk.MustQuery("select * from floor_unix_timestamp partition(p1, p2) where ts > '2020-04-14 00:00:00'").Check(testkit.Rows("2020-04-14 00:00:42.000")) +} + +func (s *testIntegrationSuite) TestIssue16290And16292(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, primary key(a));") + tk.MustExec("insert into t values(1, 1);") + + for i := 0; i <= 1; i++ { + tk.MustExec(fmt.Sprintf("set session tidb_opt_agg_push_down = %v", i)) + + tk.MustQuery("select avg(a) from (select * from t ta union all select * from t tb) t;").Check(testkit.Rows("1.0000")) + tk.MustQuery("select avg(b) from (select * from t ta union all select * from t tb) t;").Check(testkit.Rows("1.0000")) + tk.MustQuery("select count(distinct a) from (select * from t ta union all select * from t tb) t;").Check(testkit.Rows("1")) + tk.MustQuery("select count(distinct b) from (select * from t ta union all select * from t tb) t;").Check(testkit.Rows("1")) + } +} + +func (s *testIntegrationSuite) TestTableDualWithRequiredProperty(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t1, t2;") + tk.MustExec("create table t1 (a int, b int) partition by range(a) " + + "(partition p0 values less than(10), partition p1 values less than MAXVALUE)") + tk.MustExec("create table t2 (a int, b int)") + tk.MustExec("select /*+ MERGE_JOIN(t1, t2) */ * from t1 partition (p0), t2 where t1.a > 100 and t1.a = t2.a") +} + +func (s *testIntegrationSuite) TestIndexJoinInnerIndexNDV(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t1, t2") + tk.MustExec("create table t1(a int not null, b int not null, c int not null)") + tk.MustExec("create table t2(a int not null, b int not null, c int not null, index idx1(a,b), index idx2(c))") + tk.MustExec("insert into t1 values(1,1,1),(1,1,1),(1,1,1)") + tk.MustExec("insert into t2 values(1,1,1),(1,1,2),(1,1,3)") + tk.MustExec("analyze table t1, t2") + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + tk.MustQuery(tt).Check(testkit.Rows(output[i].Plan...)) + } +} + +func (s *testIntegrationSerialSuite) TestIssue16837(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,c int,d int,e int,unique key idx_ab(a,b),unique key(c),unique key(d))") + tk.MustQuery("explain format = 'brief' select /*+ use_index_merge(t,c,idx_ab) */ * from t where a = 1 or (e = 1 and c = 1)").Check(testkit.Rows( + "IndexMerge 0.01 root ", + "├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:idx_ab(a, b) range:[1,1], keep order:false, stats:pseudo", + "├─IndexRangeScan(Build) 1.00 cop[tikv] table:t, index:c(c) range:[1,1], keep order:false, stats:pseudo", + "└─Selection(Probe) 0.01 cop[tikv] or(eq(test.t.a, 1), and(eq(test.t.e, 1), eq(test.t.c, 1)))", + " └─TableRowIDScan 11.00 cop[tikv] table:t keep order:false, stats:pseudo")) + tk.MustQuery("show warnings").Check(testkit.Rows()) + tk.MustExec("insert into t values (2, 1, 1, 1, 2)") + tk.MustQuery("select /*+ use_index_merge(t,c,idx_ab) */ * from t where a = 1 or (e = 1 and c = 1)").Check(testkit.Rows()) +} + +func (s *testIntegrationSerialSuite) TestIndexMerge(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, unique key(a), unique key(b))") + tk.MustExec("insert into t value (1, 5), (2, 4), (3, 3), (4, 2), (5, 1)") + tk.MustExec("insert into t value (6, 0), (7, -1), (8, -2), (9, -3), (10, -4)") + tk.MustExec("analyze table t") + + var input []string + var output []struct { + SQL string + Plan []string + Warnings []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + output[i].Warnings = s.testData.ConvertRowsToStrings(tk.MustQuery("show warnings").Rows()) + }) + tk.MustQuery(tt).Check(testkit.Rows(output[i].Plan...)) + tk.MustQuery("show warnings").Check(testkit.Rows(output[i].Warnings...)) + } +} + +func (s *testIntegrationSerialSuite) TestIndexMergePartialScansClusteredIndex(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, c int, primary key (a, b) clustered, key idx_c(c));") + tk.MustExec("insert into t values (1, 1, 1), (10, 10, 10), (100, 100, 100);") + const queryTemplate = "select /*+ use_index_merge(t) */ %s from t where %s order by a, b;" + projections := [][]string{{"a"}, {"b"}, {"c"}, {"a", "b"}, {"b", "c"}, {"c", "a"}, {"b", "a", "c"}} + cases := []struct { + condition string + expected []string + }{ + { + // 3 table scans + "a < 2 or a < 10 or a > 11", []string{"1", "100"}, + }, + { + // 3 index scans + "c < 10 or c < 11 or c > 50", []string{"1", "10", "100"}, + }, + { + // 1 table scan + 1 index scan + "a < 2 or c > 10000", []string{"1"}, + }, + { + // 2 table scans + 1 index scan + "a < 2 or a > 88 or c > 10000", []string{"1", "100"}, + }, + { + // 2 table scans + 2 index scans + "a < 2 or (a >= 10 and b >= 10) or c > 100 or c < 1", []string{"1", "10", "100"}, + }, + { + // 3 table scans + 2 index scans + "a < 2 or (a >= 10 and b >= 10) or (a >= 20 and b < 10) or c > 100 or c < 1", []string{"1", "10", "100"}, + }, + } + for _, p := range projections { + for _, ca := range cases { + query := fmt.Sprintf(queryTemplate, strings.Join(p, ","), ca.condition) + tk.HasPlan(query, "IndexMerge") + expected := make([]string, 0, len(ca.expected)) + for _, datum := range ca.expected { + row := strings.Repeat(datum+" ", len(p)) + expected = append(expected, row[:len(row)-1]) + } + tk.MustQuery(query).Check(testkit.Rows(expected...)) + } + } +} + +func (s *testIntegrationSerialSuite) TestIndexMergePartialScansTiDBRowID(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, c int, unique key (a, b), key idx_c(c));") + tk.MustExec("insert into t values (1, 1, 1), (10, 10, 10), (100, 100, 100);") + const queryTemplate = "select /*+ use_index_merge(t) */ %s from t where %s order by a;" + projections := [][]string{{"a"}, {"b"}, {"c"}, {"a", "b"}, {"b", "c"}, {"c", "a"}, {"b", "a", "c"}} + cases := []struct { + condition string + expected []string + }{ + { + // 3 index scans + "c < 10 or c < 11 or c > 50", []string{"1", "10", "100"}, + }, + { + // 2 index scans + "c < 10 or a < 2", []string{"1"}, + }, + { + // 1 table scan + 1 index scan + "_tidb_rowid < 2 or c > 10000", []string{"1"}, + }, + { + // 2 table scans + 1 index scan + "_tidb_rowid < 2 or _tidb_rowid < 10 or c > 11", []string{"1", "10", "100"}, + }, + { + // 1 table scans + 3 index scans + "_tidb_rowid < 2 or (a >= 10 and b >= 10) or c > 100 or c < 1", []string{"1", "10", "100"}, + }, + { + // 1 table scans + 4 index scans + "_tidb_rowid < 2 or (a >= 10 and b >= 10) or (a >= 20 and b < 10) or c > 100 or c < 1", []string{"1", "10", "100"}, + }, + } + for _, p := range projections { + for _, ca := range cases { + query := fmt.Sprintf(queryTemplate, strings.Join(p, ","), ca.condition) + tk.HasPlan(query, "IndexMerge") + expected := make([]string, 0, len(ca.expected)) + for _, datum := range ca.expected { + row := strings.Repeat(datum+" ", len(p)) + expected = append(expected, row[:len(row)-1]) + } + tk.MustQuery(query).Check(testkit.Rows(expected...)) + } + } +} + +func (s *testIntegrationSerialSuite) TestIndexMergePartialScansPKIsHandle(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, c int, primary key (a), unique key (b), key idx_c(c));") + tk.MustExec("insert into t values (1, 1, 1), (10, 10, 10), (100, 100, 100);") + const queryTemplate = "select /*+ use_index_merge(t) */ %s from t where %s order by b;" + projections := [][]string{{"a"}, {"b"}, {"c"}, {"a", "b"}, {"b", "c"}, {"c", "a"}, {"b", "a", "c"}} + cases := []struct { + condition string + expected []string + }{ + { + // 3 index scans + "b < 10 or c < 11 or c > 50", []string{"1", "10", "100"}, + }, + { + // 1 table scan + 1 index scan + "a < 2 or c > 10000", []string{"1"}, + }, + { + // 2 table scans + 1 index scan + "a < 2 or a < 10 or b > 11", []string{"1", "100"}, + }, + { + // 1 table scans + 3 index scans + "a < 2 or b >= 10 or c > 100 or c < 1", []string{"1", "10", "100"}, + }, + { + // 3 table scans + 2 index scans + "a < 2 or a >= 10 or a >= 20 or c > 100 or b < 1", []string{"1", "10", "100"}, + }, + } + for _, p := range projections { + for _, ca := range cases { + query := fmt.Sprintf(queryTemplate, strings.Join(p, ","), ca.condition) + tk.HasPlan(query, "IndexMerge") + expected := make([]string, 0, len(ca.expected)) + for _, datum := range ca.expected { + row := strings.Repeat(datum+" ", len(p)) + expected = append(expected, row[:len(row)-1]) + } + tk.MustQuery(query).Check(testkit.Rows(expected...)) + } + } +} + +func (s *testIntegrationSerialSuite) TestIssue23919(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test;") + + // Test for the minimal reproducible case. + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t (a int, b int, index(a), index(b)) partition by hash (a) partitions 2;") + tk.MustExec("insert into t values (1, 5);") + tk.MustQuery("select /*+ use_index_merge( t ) */ * from t where a in (3) or b in (5) order by a;"). + Check(testkit.Rows("1 5")) + + // Test for the original case. + tk.MustExec("drop table if exists t;") + tk.MustExec(`CREATE TABLE t ( + col_5 text NOT NULL, + col_6 tinyint(3) unsigned DEFAULT NULL, + col_7 float DEFAULT '4779.165058537128', + col_8 smallint(6) NOT NULL DEFAULT '-24790', + col_9 date DEFAULT '2031-01-15', + col_37 int(11) DEFAULT '1350204687', + PRIMARY KEY (col_5(6),col_8) /*T![clustered_index] NONCLUSTERED */, + UNIQUE KEY idx_6 (col_9,col_7,col_8), + KEY idx_8 (col_8,col_6,col_5(6),col_9,col_7), + KEY idx_9 (col_9,col_7,col_8) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin +PARTITION BY RANGE ( col_8 ) ( + PARTITION p0 VALUES LESS THAN (-17650), + PARTITION p1 VALUES LESS THAN (-13033), + PARTITION p2 VALUES LESS THAN (2521), + PARTITION p3 VALUES LESS THAN (7510) +);`) + tk.MustExec("insert into t values ('', NULL, 6304.0146, -24790, '2031-01-15', 1350204687);") + tk.MustQuery("select var_samp(col_7) aggCol from (select /*+ use_index_merge( t ) */ * from t where " + + "t.col_9 in ( '2002-06-22' ) or t.col_5 in ( 'PkfzI' ) or t.col_8 in ( -24874 ) and t.col_6 > null and " + + "t.col_5 > 'r' and t.col_9 in ( '1979-09-04' ) and t.col_7 < 8143.667552769195 or " + + "t.col_5 in ( 'iZhfEjRWci' , 'T' , '' ) or t.col_9 <> '1976-09-11' and t.col_7 = 8796.436181615773 and " + + "t.col_8 = 7372 order by col_5,col_8 ) ordered_tbl group by col_6;").Check(testkit.Rows("")) +} + +func (s *testIntegrationSerialSuite) TestIssue16407(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 char(100),key(a),key(b(10)))") + tk.MustQuery("explain format = 'brief' select /*+ use_index_merge(t) */ * from t where a=10 or b='x'").Check(testkit.Rows( + "IndexMerge 0.04 root ", + "├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:a(a) range:[10,10], keep order:false, stats:pseudo", + "├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:b(b) range:[\"x\",\"x\"], keep order:false, stats:pseudo", + "└─Selection(Probe) 0.04 cop[tikv] or(eq(test.t.a, 10), eq(test.t.b, \"x\"))", + " └─TableRowIDScan 19.99 cop[tikv] table:t keep order:false, stats:pseudo")) + tk.MustQuery("show warnings").Check(testkit.Rows()) + tk.MustExec("insert into t values (1, 'xx')") + tk.MustQuery("select /*+ use_index_merge(t) */ * from t where a=10 or b='x'").Check(testkit.Rows()) +} + +func (s *testIntegrationSuite) TestStreamAggProp(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)") + tk.MustExec("insert into t values(1),(1),(2)") + + var input []string + var output []struct { + SQL string + Plan []string + Res []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery("explain format = 'brief' " + tt).Rows()) + output[i].Res = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + tk.MustQuery("explain format = 'brief' " + tt).Check(testkit.Rows(output[i].Plan...)) + tk.MustQuery(tt).Check(testkit.Rows(output[i].Res...)) + } +} + +func (s *testIntegrationSuite) TestOptimizeHintOnPartitionTable(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, c varchar(20), + primary key(a), key(b), key(c) + ) partition by range columns(a) ( + partition p0 values less than(6), + partition p1 values less than(11), + partition p2 values less than(16));`) + tk.MustExec(`insert into t values (1,1,"1"), (2,2,"2"), (8,8,"8"), (11,11,"11"), (15,15,"15")`) + tk.MustExec("set @@tidb_enable_index_merge = off") + defer func() { + tk.MustExec("set @@tidb_enable_index_merge = on") + }() + + // Create virtual tiflash replica info. + dom := domain.GetDomain(tk.Se) + is := dom.InfoSchema() + db, exists := is.SchemaByName(model.NewCIStr("test")) + c.Assert(exists, IsTrue) + for _, tblInfo := range db.Tables { + if tblInfo.Name.L == "t" { + tblInfo.TiFlashReplica = &model.TiFlashReplicaInfo{ + Count: 1, + Available: true, + } + } + } + + tk.MustExec(`set @@tidb_partition_prune_mode='` + string(variable.Static) + `'`) + + var input []string + var output []struct { + SQL string + Plan []string + Warn []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery("explain format = 'brief' " + tt).Rows()) + output[i].Warn = s.testData.ConvertRowsToStrings(tk.MustQuery("show warnings").Rows()) + }) + tk.MustQuery("explain format = 'brief' " + tt).Check(testkit.Rows(output[i].Plan...)) + tk.MustQuery("show warnings").Check(testkit.Rows(output[i].Warn...)) + } +} + +func (s *testIntegrationSerialSuite) TestNotReadOnlySQLOnTiFlash(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 varchar(20))") + tk.MustExec(`set @@tidb_isolation_read_engines = "tiflash"`) + // Create virtual tiflash replica info. + dom := domain.GetDomain(tk.Se) + is := dom.InfoSchema() + db, exists := is.SchemaByName(model.NewCIStr("test")) + c.Assert(exists, IsTrue) + for _, tblInfo := range db.Tables { + if tblInfo.Name.L == "t" { + tblInfo.TiFlashReplica = &model.TiFlashReplicaInfo{ + Count: 1, + Available: true, + } + } + } + err := tk.ExecToErr("select * from t for update") + c.Assert(err, NotNil) + c.Assert(err.Error(), Equals, `[planner:1815]Internal : No access path for table 't' is found with 'tidb_isolation_read_engines' = 'tiflash', valid values can be 'tiflash, tikv'. Please check tiflash replica or ensure the query is readonly.`) + + err = tk.ExecToErr("insert into t select * from t") + c.Assert(err, NotNil) + c.Assert(err.Error(), Equals, `[planner:1815]Internal : No access path for table 't' is found with 'tidb_isolation_read_engines' = 'tiflash', valid values can be 'tiflash, tikv'. Please check tiflash replica or ensure the query is readonly.`) + + tk.MustExec("prepare stmt_insert from 'insert into t select * from t where t.a = ?'") + tk.MustExec("set @a=1") + err = tk.ExecToErr("execute stmt_insert using @a") + c.Assert(err, NotNil) + c.Assert(err.Error(), Equals, `[planner:1815]Internal : No access path for table 't' is found with 'tidb_isolation_read_engines' = 'tiflash', valid values can be 'tiflash, tikv'. Please check tiflash replica or ensure the query is readonly.`) +} + +func (s *testIntegrationSuite) TestSelectLimit(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)") + tk.MustExec("insert into t values(1),(1),(2)") + + // normal test + tk.MustExec("set @@session.sql_select_limit=1") + result := tk.MustQuery("select * from t order by a") + c.Assert(tk.Se.GetSessionVars().StmtCtx.GetWarnings(), HasLen, 0) + result.Check(testkit.Rows("1")) + result = tk.MustQuery("select * from t order by a limit 2") + result.Check(testkit.Rows("1", "1")) + tk.MustExec("set @@session.sql_select_limit=default") + result = tk.MustQuery("select * from t order by a") + result.Check(testkit.Rows("1", "1", "2")) + + // test for subquery + tk.MustExec("set @@session.sql_select_limit=1") + result = tk.MustQuery("select * from (select * from t) s order by a") + result.Check(testkit.Rows("1")) + result = tk.MustQuery("select * from (select * from t limit 2) s order by a") // limit write in subquery, has no effect. + result.Check(testkit.Rows("1")) + result = tk.MustQuery("select (select * from t limit 1) s") // limit write in subquery, has no effect. + result.Check(testkit.Rows("1")) + result = tk.MustQuery("select * from t where t.a in (select * from t) limit 3") // select_limit will not effect subquery + result.Check(testkit.Rows("1", "1", "2")) + result = tk.MustQuery("select * from (select * from t) s limit 3") // select_limit will not effect subquery + result.Check(testkit.Rows("1", "1", "2")) + + // test for union + result = tk.MustQuery("select * from t union all select * from t limit 2") // limit outside subquery + result.Check(testkit.Rows("1", "1")) + result = tk.MustQuery("select * from t union all (select * from t limit 2)") // limit inside subquery + result.Check(testkit.Rows("1")) + + // test for prepare & execute + tk.MustExec("prepare s1 from 'select * from t where a = ?'") + tk.MustExec("set @a = 1") + result = tk.MustQuery("execute s1 using @a") + result.Check(testkit.Rows("1")) + tk.MustExec("set @@session.sql_select_limit=default") + result = tk.MustQuery("execute s1 using @a") + result.Check(testkit.Rows("1", "1")) + tk.MustExec("set @@session.sql_select_limit=1") + tk.MustExec("prepare s2 from 'select * from t where a = ? limit 3'") + result = tk.MustQuery("execute s2 using @a") // if prepare stmt has limit, select_limit takes no effect. + result.Check(testkit.Rows("1", "1")) + + // test for create view + tk.MustExec("set @@session.sql_select_limit=1") + tk.MustExec("create definer='root'@'localhost' view s as select * from t") // select limit should not effect create view + result = tk.MustQuery("select * from s") + result.Check(testkit.Rows("1")) + tk.MustExec("set @@session.sql_select_limit=default") + result = tk.MustQuery("select * from s") + result.Check(testkit.Rows("1", "1", "2")) + + // test for DML + tk.MustExec("set @@session.sql_select_limit=1") + tk.MustExec("create table b (a int)") + tk.MustExec("insert into b select * from t") // all values are inserted + result = tk.MustQuery("select * from b limit 3") + result.Check(testkit.Rows("1", "1", "2")) + tk.MustExec("update b set a = 2 where a = 1") // all values are updated + result = tk.MustQuery("select * from b limit 3") + result.Check(testkit.Rows("2", "2", "2")) + result = tk.MustQuery("select * from b") + result.Check(testkit.Rows("2")) + tk.MustExec("delete from b where a = 2") // all values are deleted + result = tk.MustQuery("select * from b") + result.Check(testkit.Rows()) +} + +func (s *testIntegrationSuite) TestHintParserWarnings(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, key(a), key(b));") + tk.MustExec("select /*+ use_index_merge() */ * from t where a = 1 or b = 1;") + rows := tk.MustQuery("show warnings;").Rows() + c.Assert(len(rows), Equals, 1) +} + +func (s *testIntegrationSuite) TestIssue16935(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t0;") + tk.MustExec("CREATE TABLE t0(c0 INT);") + tk.MustExec("INSERT INTO t0(c0) VALUES (1), (1), (1), (1), (1), (1);") + tk.MustExec("CREATE definer='root'@'localhost' VIEW v0(c0) AS SELECT NULL FROM t0;") + + tk.MustQuery("SELECT * FROM t0 LEFT JOIN v0 ON TRUE WHERE v0.c0 IS NULL;") +} + +func (s *testIntegrationSuite) TestAccessPathOnClusterIndex(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.Se.GetSessionVars().EnableClusteredIndex = variable.ClusteredIndexDefModeOn + tk.MustExec("drop table if exists t1") + tk.MustExec("create table t1 (a int, b varchar(20), c decimal(40,10), d int, primary key(a,b), key(c))") + tk.MustExec(`insert into t1 values (1,"111",1.1,11), (2,"222",2.2,12), (3,"333",3.3,13)`) + tk.MustExec("analyze table t1") + + var input []string + var output []struct { + SQL string + Plan []string + Res []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery("explain format='brief' " + tt).Rows()) + output[i].Res = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Sort().Rows()) + }) + tk.MustQuery("explain format='brief' " + tt).Check(testkit.Rows(output[i].Plan...)) + tk.MustQuery(tt).Sort().Check(testkit.Rows(output[i].Res...)) + } +} + +func (s *testIntegrationSuite) TestClusterIndexUniqueDoubleRead(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("create database cluster_idx_unique_double_read;") + tk.MustExec("use cluster_idx_unique_double_read;") + defer tk.MustExec("drop database cluster_idx_unique_double_read;") + tk.Se.GetSessionVars().EnableClusteredIndex = variable.ClusteredIndexDefModeOn + tk.MustExec("drop table if exists t") + + tk.MustExec("create table t (a varchar(64), b varchar(64), uk int, v int, primary key(a, b), unique key uuk(uk));") + tk.MustExec("insert t values ('a', 'a1', 1, 11), ('b', 'b1', 2, 22), ('c', 'c1', 3, 33);") + tk.MustQuery("select * from t use index (uuk);").Check(testkit.Rows("a a1 1 11", "b b1 2 22", "c c1 3 33")) +} + +func (s *testIntegrationSuite) TestIndexJoinOnClusteredIndex(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.Se.GetSessionVars().EnableClusteredIndex = variable.ClusteredIndexDefModeOn + tk.MustExec("drop table if exists t1") + tk.MustExec("create table t (a int, b varchar(20), c decimal(40,10), d int, primary key(a,b), key(c))") + tk.MustExec(`insert into t values (1,"111",1.1,11), (2,"222",2.2,12), (3,"333",3.3,13)`) + tk.MustExec("analyze table t") + + var input []string + var output []struct { + SQL string + Plan []string + Res []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery("explain format = 'brief' " + tt).Rows()) + output[i].Res = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + tk.MustQuery("explain format = 'brief'" + tt).Check(testkit.Rows(output[i].Plan...)) + tk.MustQuery(tt).Check(testkit.Rows(output[i].Res...)) + } +} +func (s *testIntegrationSerialSuite) TestIssue18984(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t, t2") + tk.Se.GetSessionVars().EnableClusteredIndex = variable.ClusteredIndexDefModeOn + tk.MustExec("create table t(a int, b int, c int, primary key(a, b))") + tk.MustExec("create table t2(a int, b int, c int, d int, primary key(a,b), index idx(c))") + tk.MustExec("insert into t values(1,1,1), (2,2,2), (3,3,3)") + tk.MustExec("insert into t2 values(1,2,3,4), (2,4,3,5), (1,3,1,1)") + tk.MustQuery("select /*+ INL_MERGE_JOIN(t) */ * from t right outer join t2 on t.a=t2.c").Check(testkit.Rows( + "1 1 1 1 3 1 1", + "3 3 3 1 2 3 4", + "3 3 3 2 4 3 5")) + tk.MustQuery("select /*+ INL_MERGE_JOIN(t2) */ * from t left outer join t2 on t.a=t2.c").Check(testkit.Rows( + "1 1 1 1 3 1 1", + "2 2 2 ", + "3 3 3 1 2 3 4", + "3 3 3 2 4 3 5")) +} + +func (s *testIntegrationSuite) TestScalarFunctionPushDown(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("create table t(id int signed, id2 int unsigned ,c varchar(11), d datetime, b double)") + tk.MustExec("insert into t(id,c,d) values (1,'abc','2021-12-12')") + rows := [][]interface{}{ + {"TableReader_7", "root", "data:Selection_6"}, + {"└─Selection_6", "cop[tikv]", "right(test.t.c, 1)"}, + {" └─TableFullScan_5", "cop[tikv]", "keep order:false, stats:pseudo"}, + } + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where right(c,1);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "left(test.t.c, 1)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where left(c,1);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "mod(test.t.id, test.t.id)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where mod(id, id);"). + CheckAt([]int{0, 3, 6}, rows) + rows[1][2] = "mod(test.t.id, test.t.id2)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where mod(id, id2);"). + CheckAt([]int{0, 3, 6}, rows) + rows[1][2] = "mod(test.t.id2, test.t.id)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where mod(id2, id);"). + CheckAt([]int{0, 3, 6}, rows) + rows[1][2] = "mod(test.t.id2, test.t.id2)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where mod(id2, id2);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "sin(cast(test.t.id, double BINARY))" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where sin(id);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "asin(cast(test.t.id, double BINARY))" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where asin(id);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "cos(cast(test.t.id, double BINARY))" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where cos(id);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "acos(cast(test.t.id, double BINARY))" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where acos(id);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "tan(cast(test.t.id, double BINARY))" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where tan(id);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "atan(cast(test.t.id, double BINARY))" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where atan(id);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "atan2(cast(test.t.id, double BINARY), cast(test.t.id, double BINARY))" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where atan2(id,id);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "hour(cast(test.t.d, time))" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where hour(d);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "hour(cast(test.t.d, time))" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where hour(d);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "minute(cast(test.t.d, time))" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where minute(d);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "second(cast(test.t.d, time))" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where second(d);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "month(test.t.d)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where month(d);"). + CheckAt([]int{0, 3, 6}, rows) + + //rows[1][2] = "dayname(test.t.d)" + //tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where dayname(d);"). + // CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "dayofmonth(test.t.d)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where dayofmonth(d);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "weekday(test.t.d)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where weekday(d);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "weekday(test.t.d)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where weekday(d);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "from_days(test.t.id)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where from_days(id);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "to_days(test.t.d)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where to_days(d);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "last_day(test.t.d)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where last_day(d);"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "gt(4, test.t.id)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where pi() > id;"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "truncate(test.t.id, 0)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where truncate(id,0)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "bin(test.t.id)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where bin(id)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "unhex(test.t.c)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where unhex(c)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "locate(test.t.c, test.t.c)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where locate(c,c)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "ord(test.t.c)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where ord(c)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "lpad(test.t.c, 1, test.t.c)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where lpad(c,1,c)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "rpad(test.t.c, 1, test.t.c)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where rpad(c,1,c)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "trim(test.t.c)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where trim(c)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "from_base64(test.t.c)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where from_base64(c)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "to_base64(test.t.c)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where to_base64(c)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "make_set(1, test.t.c, test.t.c)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where make_set(1,c,c)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "substring_index(test.t.c, test.t.c, 1)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where substring_index(c,c,1)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "instr(test.t.c, test.t.c)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where instr(c,c)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "quote(test.t.c)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where quote(c)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "oct(test.t.id)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where oct(id)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "find_in_set(test.t.c, test.t.c)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where find_in_set(c,c)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "repeat(test.t.c, 2)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where repeat(c,2)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "round(test.t.b)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where round(b)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "round(test.t.b, 2)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where round(b,2)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "date(test.t.d)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where date(d)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "week(test.t.d)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where week(d)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "yearweek(test.t.d)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where yearweek(d)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "to_seconds(test.t.d)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where to_seconds(d)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "datediff(test.t.d, test.t.d)" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where datediff(d,d)"). + CheckAt([]int{0, 3, 6}, rows) + + rows[1][2] = "gt(test.t.d, sysdate())" + tk.MustQuery("explain analyze select /*+read_from_storage(tikv[t])*/ * from t where d > sysdate()"). + CheckAt([]int{0, 3, 6}, rows) +} + +func (s *testIntegrationSuite) TestDistinctScalarFunctionPushDown(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 not null, b int not null, c int not null, primary key (a,c)) partition by range (c) (partition p0 values less than (5), partition p1 values less than (10))") + tk.MustExec("insert into t values(1,1,1),(2,2,2),(3,1,3),(7,1,7),(8,2,8),(9,2,9)") + tk.MustQuery("select count(distinct b+1) as col from t").Check(testkit.Rows( + "2", + )) +} + +func (s *testIntegrationSerialSuite) TestExplainAnalyzePointGet(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 primary key, b varchar(20))") + tk.MustExec("insert into t values (1,1)") + + res := tk.MustQuery("explain analyze select * from t where a=1;") + checkExplain := func(rpc string) { + resBuff := bytes.NewBufferString("") + for _, row := range res.Rows() { + fmt.Fprintf(resBuff, "%s\n", row) + } + explain := resBuff.String() + c.Assert(strings.Contains(explain, rpc+":{num_rpc:"), IsTrue, Commentf("%s", explain)) + c.Assert(strings.Contains(explain, "total_time:"), IsTrue, Commentf("%s", explain)) + } + checkExplain("Get") + res = tk.MustQuery("explain analyze select * from t where a in (1,2,3);") + checkExplain("BatchGet") +} + +func (s *testIntegrationSerialSuite) TestExplainAnalyzeDML(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, unique index (a));") + tk.MustExec("insert into t values (1,1)") + + res := tk.MustQuery("explain analyze select * from t where a=1;") + checkExplain := func(rpc string) { + resBuff := bytes.NewBufferString("") + for _, row := range res.Rows() { + fmt.Fprintf(resBuff, "%s\n", row) + } + explain := resBuff.String() + c.Assert(strings.Contains(explain, rpc+":{num_rpc:"), IsTrue, Commentf("%s", explain)) + c.Assert(strings.Contains(explain, "total_time:"), IsTrue, Commentf("%s", explain)) + } + checkExplain("Get") + res = tk.MustQuery("explain analyze insert ignore into t values (1,1),(2,2),(3,3),(4,4);") + checkExplain("BatchGet") +} + +func (s *testIntegrationSerialSuite) TestExplainAnalyzeDML2(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + + cases := []struct { + prepare string + sql string + planRegexp string + }{ + // Test for alloc auto ID. + { + sql: "insert into t () values ()", + planRegexp: ".*prepare.*total.*, auto_id_allocator.*alloc_cnt: 1, Get.*num_rpc.*total_time.*commit_txn.*prewrite.*get_commit_ts.*commit.*write_keys.*, insert.*", + }, + // Test for rebase ID. + { + sql: "insert into t (a) values (99000000000)", + planRegexp: ".*prepare.*total.*, auto_id_allocator.*rebase_cnt: 1, Get.*num_rpc.*total_time.*commit_txn.*prewrite.*get_commit_ts.*commit.*write_keys.*, insert.*", + }, + // Test for alloc auto ID and rebase ID. + { + sql: "insert into t (a) values (null), (99000000000)", + planRegexp: ".*prepare.*total.*, auto_id_allocator.*alloc_cnt: 1, rebase_cnt: 1, Get.*num_rpc.*total_time.*commit_txn.*prewrite.*get_commit_ts.*commit.*write_keys.*, insert.*", + }, + // Test for insert ignore. + { + sql: "insert ignore into t values (null,1), (2, 2), (99000000000, 3), (100000000000, 4)", + planRegexp: ".*prepare.*total.*, auto_id_allocator.*alloc_cnt: 1, rebase_cnt: 2, Get.*num_rpc.*total_time.*commit_txn.*count: 3, prewrite.*get_commit_ts.*commit.*write_keys.*, check_insert.*", + }, + // Test for insert on duplicate. + { + sql: "insert into t values (null,null), (1,1),(2,2) on duplicate key update a = a + 100000000000", + planRegexp: ".*prepare.*total.*, auto_id_allocator.*alloc_cnt: 1, rebase_cnt: 1, Get.*num_rpc.*total_time.*commit_txn.*count: 2, prewrite.*get_commit_ts.*commit.*write_keys.*, check_insert.*", + }, + // Test for replace with alloc ID. + { + sql: "replace into t () values ()", + planRegexp: ".*auto_id_allocator.*alloc_cnt: 1, Get.*num_rpc.*total_time.*commit_txn.*prewrite.*get_commit_ts.*commit.*write_keys.*", + }, + // Test for replace with alloc ID and rebase ID. + { + sql: "replace into t (a) values (null), (99000000000)", + planRegexp: ".*auto_id_allocator.*alloc_cnt: 1, rebase_cnt: 1, Get.*num_rpc.*total_time.*commit_txn.*prewrite.*get_commit_ts.*commit.*write_keys.*", + }, + // Test for update with rebase ID. + { + prepare: "insert into t values (1,1),(2,2)", + sql: "update t set a=a*100000000000", + planRegexp: ".*auto_id_allocator.*rebase_cnt: 2, Get.*num_rpc.*total_time.*commit_txn.*prewrite.*get_commit_ts.*commit.*write_keys.*", + }, + } + + for _, ca := range cases { + for i := 0; i < 3; i++ { + tk.MustExec("drop table if exists t") + switch i { + case 0: + tk.MustExec("create table t (a bigint auto_increment, b int, primary key (a));") + case 1: + tk.MustExec("create table t (a bigint unsigned auto_increment, b int, primary key (a));") + case 2: + if strings.Contains(ca.sql, "on duplicate key") { + continue + } + tk.MustExec("create table t (a bigint primary key auto_random(5), b int);") + tk.MustExec("set @@allow_auto_random_explicit_insert=1;") + default: + panic("should never happen") + } + if ca.prepare != "" { + tk.MustExec(ca.prepare) + } + res := tk.MustQuery("explain analyze " + ca.sql) + resBuff := bytes.NewBufferString("") + for _, row := range res.Rows() { + fmt.Fprintf(resBuff, "%s\t", row) + } + explain := resBuff.String() + c.Assert(explain, Matches, ca.planRegexp, Commentf("idx: %v,sql: %v", i, ca.sql)) + } + } + + // Test for table without auto id. + for _, ca := range cases { + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (a bigint, b int);") + tk.MustExec("insert into t () values ()") + if ca.prepare != "" { + tk.MustExec(ca.prepare) + } + res := tk.MustQuery("explain analyze " + ca.sql) + resBuff := bytes.NewBufferString("") + for _, row := range res.Rows() { + fmt.Fprintf(resBuff, "%s\t", row) + } + explain := resBuff.String() + c.Assert(strings.Contains(explain, "auto_id_allocator"), IsFalse, Commentf("sql: %v, explain: %v", ca.sql, explain)) + } +} + +func (s *testIntegrationSuite) TestPartitionExplain(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec(`create table pt (id int, c int, key i_id(id), key i_c(c)) partition by range (c) ( +partition p0 values less than (4), +partition p1 values less than (7), +partition p2 values less than (10))`) + + tk.MustExec("set @@tidb_enable_index_merge = 1;") + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery("explain " + tt).Rows()) + }) + tk.MustQuery("explain " + tt).Check(testkit.Rows(output[i].Plan...)) + } +} + +func (s *testIntegrationSuite) TestPartialBatchPointGet(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (c_int int, c_str varchar(40), primary key(c_int, c_str))") + tk.MustExec("insert into t values (3, 'bose')") + tk.MustQuery("select * from t where c_int in (3)").Check(testkit.Rows( + "3 bose", + )) + tk.MustQuery("select * from t where c_int in (3) or c_str in ('yalow') and c_int in (1, 2)").Check(testkit.Rows( + "3 bose", + )) +} + +func (s *testIntegrationSuite) TestIssue19926(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists ta;") + tk.MustExec("drop table if exists tb;") + tk.MustExec("drop table if exists tc;") + tk.MustExec("drop view if exists v;") + tk.MustExec("CREATE TABLE `ta` (\n `id` varchar(36) NOT NULL ,\n `status` varchar(1) NOT NULL \n);") + tk.MustExec("CREATE TABLE `tb` (\n `id` varchar(36) NOT NULL ,\n `status` varchar(1) NOT NULL \n);") + tk.MustExec("CREATE TABLE `tc` (\n `id` varchar(36) NOT NULL ,\n `status` varchar(1) NOT NULL \n);") + tk.MustExec("insert into ta values('1','1');") + tk.MustExec("insert into tb values('1','1');") + tk.MustExec("insert into tc values('1','1');") + tk.MustExec("create definer='root'@'localhost' view v as\nselect \nconcat(`ta`.`status`,`tb`.`status`) AS `status`, \n`ta`.`id` AS `id` from (`ta` join `tb`) \nwhere (`ta`.`id` = `tb`.`id`);") + tk.MustQuery("SELECT tc.status,v.id FROM tc, v WHERE tc.id = v.id AND v.status = '11';").Check(testkit.Rows("1 1")) +} + +func (s *testIntegrationSuite) TestDeleteUsingJoin(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t1, t2") + tk.MustExec("create table t1(a int primary key, b int)") + tk.MustExec("create table t2(a int primary key, b int)") + tk.MustExec("insert into t1 values(1,1),(2,2)") + tk.MustExec("insert into t2 values(2,2)") + tk.MustExec("delete t1.* from t1 join t2 using (a)") + tk.MustQuery("select * from t1").Check(testkit.Rows("1 1")) + tk.MustQuery("select * from t2").Check(testkit.Rows("2 2")) +} + +func (s *testIntegrationSerialSuite) Test19942(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.Se.GetSessionVars().EnableClusteredIndex = variable.ClusteredIndexDefModeOn + tk.MustExec("CREATE TABLE test.`t` (" + + " `a` int(11) NOT NULL," + + " `b` varchar(10) COLLATE utf8_general_ci NOT NULL," + + " `c` varchar(50) COLLATE utf8_general_ci NOT NULL," + + " `d` char(10) NOT NULL," + + " PRIMARY KEY (`c`)," + + " UNIQUE KEY `a_uniq` (`a`)," + + " UNIQUE KEY `b_uniq` (`b`)," + + " UNIQUE KEY `d_uniq` (`d`)," + + " KEY `a_idx` (`a`)," + + " KEY `b_idx` (`b`)," + + " KEY `d_idx` (`d`)" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;") + tk.MustExec("INSERT INTO test.t (a, b, c, d) VALUES (1, '1', '0', '1');") + tk.MustExec("INSERT INTO test.t (a, b, c, d) VALUES (2, ' 2', ' 0', ' 2');") + tk.MustExec("INSERT INTO test.t (a, b, c, d) VALUES (3, ' 3 ', ' 3 ', ' 3 ');") + tk.MustExec("INSERT INTO test.t (a, b, c, d) VALUES (4, 'a', 'a ', 'a');") + tk.MustExec("INSERT INTO test.t (a, b, c, d) VALUES (5, ' A ', ' A ', ' A ');") + tk.MustExec("INSERT INTO test.t (a, b, c, d) VALUES (6, ' E', 'é ', ' E');") + + mkr := func() [][]interface{} { + return testutil.RowsWithSep("|", + "3| 3 | 3 | 3", + "2| 2 0| 2", + "5| A | A | A", + "1|1|0|1", + "4|a|a |a", + "6| E|é | E") + } + tk.MustQuery("SELECT * FROM `test`.`t` FORCE INDEX(`a_uniq`);").Check(mkr()) + tk.MustQuery("SELECT * FROM `test`.`t` FORCE INDEX(`b_uniq`);").Check(mkr()) + tk.MustQuery("SELECT * FROM `test`.`t` FORCE INDEX(`d_uniq`);").Check(mkr()) + tk.MustQuery("SELECT * FROM `test`.`t` FORCE INDEX(`a_idx`);").Check(mkr()) + tk.MustQuery("SELECT * FROM `test`.`t` FORCE INDEX(`b_idx`);").Check(mkr()) + tk.MustQuery("SELECT * FROM `test`.`t` FORCE INDEX(`d_idx`);").Check(mkr()) + tk.MustExec("admin check table t") +} + +func (s *testIntegrationSuite) TestPartitionUnionWithPPruningColumn(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t;") + tk.MustExec("CREATE TABLE `t` (\n `fid` bigint(36) NOT NULL,\n `oty` varchar(30) DEFAULT NULL,\n `oid` int(11) DEFAULT NULL,\n `pid` bigint(20) DEFAULT NULL,\n `bid` int(11) DEFAULT NULL,\n `r5` varchar(240) DEFAULT '',\n PRIMARY KEY (`fid`)\n)PARTITION BY HASH( `fid` ) PARTITIONS 4;") + + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (59, 'm', 441, 1, 2143, 'LE1264_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (135, 'm', 1121, 1, 2423, 'LE2008_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (139, 'm', 1125, 1, 2432, 'LE2005_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (143, 'm', 1129, 1, 2438, 'LE2006_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (147, 'm', 1133, 1, 2446, 'LE2014_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (167, 'm', 1178, 1, 2512, 'LE2055_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (171, 'm', 1321, 1, 2542, 'LE1006_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (179, 'm', 1466, 1, 2648, 'LE2171_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (187, 'm', 1567, 1, 2690, 'LE1293_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (57, 'm', 341, 1, 2102, 'LE1001_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (137, 'm', 1123, 1, 2427, 'LE2003_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (145, 'm', 1131, 1, 2442, 'LE2048_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (138, 'm', 1124, 1, 2429, 'LE2004_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (142, 'm', 1128, 1, 2436, 'LE2049_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (174, 'm', 1381, 1, 2602, 'LE2170_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (28, 'm', 81, 1, 2023, 'LE1009_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (60, 'm', 442, 1, 2145, 'LE1263_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (136, 'm', 1122, 1, 2425, 'LE2002_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (140, 'm', 1126, 1, 2434, 'LE2001_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (168, 'm', 1179, 1, 2514, 'LE2052_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (196, 'm', 3380, 1, 2890, 'LE1300_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (208, 'm', 3861, 1, 3150, 'LE1323_r5');") + tk.MustExec("INSERT INTO t (fid, oty, oid, pid, bid, r5) VALUES (432, 'm', 4060, 1, 3290, 'LE1327_r5');") + + tk.MustQuery("SELECT DISTINCT t.bid, t.r5 FROM t left join t parent on parent.oid = t.pid WHERE t.oty = 'm';").Sort().Check( + testkit.Rows("2023 LE1009_r5", + "2102 LE1001_r5", + "2143 LE1264_r5", + "2145 LE1263_r5", + "2423 LE2008_r5", + "2425 LE2002_r5", + "2427 LE2003_r5", + "2429 LE2004_r5", + "2432 LE2005_r5", + "2434 LE2001_r5", + "2436 LE2049_r5", + "2438 LE2006_r5", + "2442 LE2048_r5", + "2446 LE2014_r5", + "2512 LE2055_r5", + "2514 LE2052_r5", + "2542 LE1006_r5", + "2602 LE2170_r5", + "2648 LE2171_r5", + "2690 LE1293_r5", + "2890 LE1300_r5", + "3150 LE1323_r5", + "3290 LE1327_r5")) +} + +func (s *testIntegrationSuite) TestIssue20139(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (id int, c int) partition by range (id) (partition p0 values less than (4), partition p1 values less than (7))") + tk.MustExec("insert into t values(3, 3), (5, 5)") + plan := tk.MustQuery("explain format = 'brief' select * from t where c = 1 and id = c") + plan.Check(testkit.Rows( + "TableReader 0.01 root partition:p0 data:Selection", + "└─Selection 0.01 cop[tikv] eq(test.t.c, 1), eq(test.t.id, 1)", + " └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", + )) + tk.MustExec("drop table t") +} + +func (s *testIntegrationSuite) TestIssue14481(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 default null, b int default null, c int default null)") + plan := tk.MustQuery("explain format = 'brief' select * from t where a = 1 and a = 2") + plan.Check(testkit.Rows("TableDual 8000.00 root rows:0")) + tk.MustExec("drop table t") +} + +func (s *testIntegrationSerialSuite) TestIssue20710(c *C) { + tk := testkit.NewTestKitWithInit(c, s.store) + tk.MustExec("drop table if exists t;") + tk.MustExec("drop table if exists s;") + tk.MustExec("create table t(a int, b int)") + tk.MustExec("create table s(a int, b int, index(a))") + tk.MustExec("insert into t values(1,1),(1,2),(2,2)") + tk.MustExec("insert into s values(1,1),(2,2),(2,1)") + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + res := tk.MustQuery(tt) + res.Check(testkit.Rows(output[i].Plan...)) + } +} + +func (s *testIntegrationSuite) TestQueryBlockTableAliasInHint(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("use test") + c.Assert(tk.HasPlan("select /*+ HASH_JOIN(@sel_1 t2) */ * FROM (select 1) t1 NATURAL LEFT JOIN (select 2) t2", "HashJoin"), IsTrue) + tk.MustQuery("select /*+ HASH_JOIN(@sel_1 t2) */ * FROM (select 1) t1 NATURAL LEFT JOIN (select 2) t2").Check(testkit.Rows( + "1 2", + )) + c.Assert(tk.Se.GetSessionVars().StmtCtx.GetWarnings(), HasLen, 0) +} + +func (s *testIntegrationSuite) TestIssue10448(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t;") + + tk.MustExec("create table t(pk int(11) primary key)") + tk.MustExec("insert into t values(1),(2),(3)") + tk.MustQuery("select a from (select pk as a from t) t1 where a = 18446744073709551615").Check(testkit.Rows()) +} + +func (s *testIntegrationSuite) TestMultiUpdateOnPrimaryKey(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 not null primary key)") + tk.MustExec("insert into t values (1)") + tk.MustGetErrMsg(`UPDATE t m, t n SET m.a = m.a + 10, n.a = n.a + 10`, + `[planner:1706]Primary key/partition key update is not allowed since the table is updated both as 'm' and 'n'.`) + + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (a varchar(10) not null primary key)") + tk.MustExec("insert into t values ('abc')") + tk.MustGetErrMsg(`UPDATE t m, t n SET m.a = 'def', n.a = 'xyz'`, + `[planner:1706]Primary key/partition key update is not allowed since the table is updated both as 'm' and 'n'.`) + + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (a int, b int, primary key (a, b))") + tk.MustExec("insert into t values (1, 2)") + tk.MustGetErrMsg(`UPDATE t m, t n SET m.a = m.a + 10, n.b = n.b + 10`, + `[planner:1706]Primary key/partition key update is not allowed since the table is updated both as 'm' and 'n'.`) + + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (a int primary key, b int)") + tk.MustExec("insert into t values (1, 2)") + tk.MustGetErrMsg(`UPDATE t m, t n SET m.a = m.a + 10, n.a = n.a + 10`, + `[planner:1706]Primary key/partition key update is not allowed since the table is updated both as 'm' and 'n'.`) + + tk.MustExec(`UPDATE t m, t n SET m.b = m.b + 10, n.b = n.b + 10`) + tk.MustQuery("SELECT * FROM t").Check(testkit.Rows("1 12")) + + tk.MustGetErrMsg(`UPDATE t m, t n SET m.a = m.a + 1, n.b = n.b + 10`, + `[planner:1706]Primary key/partition key update is not allowed since the table is updated both as 'm' and 'n'.`) + tk.MustGetErrMsg(`UPDATE t m, t n, t q SET m.a = m.a + 1, n.b = n.b + 10, q.b = q.b - 10`, + `[planner:1706]Primary key/partition key update is not allowed since the table is updated both as 'm' and 'n'.`) + tk.MustGetErrMsg(`UPDATE t m, t n, t q SET m.b = m.b + 1, n.a = n.a + 10, q.b = q.b - 10`, + `[planner:1706]Primary key/partition key update is not allowed since the table is updated both as 'm' and 'n'.`) + tk.MustGetErrMsg(`UPDATE t m, t n, t q SET m.b = m.b + 1, n.b = n.b + 10, q.a = q.a - 10`, + `[planner:1706]Primary key/partition key update is not allowed since the table is updated both as 'm' and 'q'.`) + tk.MustGetErrMsg(`UPDATE t q, t n, t m SET m.b = m.b + 1, n.b = n.b + 10, q.a = q.a - 10`, + `[planner:1706]Primary key/partition key update is not allowed since the table is updated both as 'q' and 'n'.`) + + tk.MustExec("update t m, t n set m.a = n.a+10 where m.a=n.a") + tk.MustQuery("select * from t").Check(testkit.Rows("11 12")) +} + +func (s *testIntegrationSuite) TestOrderByHavingNotInSelect(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists ttest") + tk.MustExec("create table ttest (v1 int, v2 int)") + tk.MustExec("insert into ttest values(1, 2), (4,6), (1, 7)") + tk.MustGetErrMsg("select v1 from ttest order by count(v2)", + "[planner:3029]Expression #1 of ORDER BY contains aggregate function and applies to the result of a non-aggregated query") + tk.MustGetErrMsg("select v1 from ttest having count(v2)", + "[planner:8123]In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'v1'; this is incompatible with sql_mode=only_full_group_by") + tk.MustGetErrMsg("select v2, v1 from (select * from ttest) t1 join (select 1, 2) t2 group by v1", + "[planner:1055]Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.t1.v2' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by") + tk.MustGetErrMsg("select v2, v1 from (select t1.v1, t2.v2 from ttest t1 join ttest t2) t3 join (select 1, 2) t2 group by v1", + "[planner:1055]Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.t3.v2' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by") + +} + +func (s *testIntegrationSuite) TestUpdateSetDefault(c *C) { + // #20598 + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("create table tt (x int, z int as (x+10) stored)") + tk.MustExec("insert into tt(x) values (1)") + tk.MustExec("update tt set x=2, z = default") + tk.MustExec("update tt set x=2, z = default(z)") + tk.MustQuery("select * from tt").Check(testkit.Rows("2 12")) + + tk.MustGetErrMsg("update tt set x=2, z = default(x)", + "[planner:3105]The value specified for generated column 'z' in table 'tt' is not allowed.") + tk.MustGetErrMsg("update tt set z = 123", + "[planner:3105]The value specified for generated column 'z' in table 'tt' is not allowed.") + tk.MustGetErrMsg("update tt as ss set z = 123", + "[planner:3105]The value specified for generated column 'z' in table 'tt' is not allowed.") + tk.MustGetErrMsg("update tt as ss set x = 3, z = 13", + "[planner:3105]The value specified for generated column 'z' in table 'tt' is not allowed.") + tk.MustGetErrMsg("update tt as s1, tt as s2 set s1.z = default, s2.z = 456", + "[planner:3105]The value specified for generated column 'z' in table 'tt' is not allowed.") +} + +func (s *testIntegrationSuite) TestExtendedStatsSwitch(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 not null, b int not null, key(a), key(b))") + tk.MustExec("insert into t values(1,1),(2,2),(3,3),(4,4),(5,5),(6,6)") + + tk.MustExec("set session tidb_enable_extended_stats = off") + tk.MustGetErrMsg("alter table t add stats_extended s1 correlation(a,b)", + "Extended statistics feature is not generally available now, and tidb_enable_extended_stats is OFF") + tk.MustGetErrMsg("alter table t drop stats_extended s1", + "Extended statistics feature is not generally available now, and tidb_enable_extended_stats is OFF") + tk.MustGetErrMsg("admin reload stats_extended", + "Extended statistics feature is not generally available now, and tidb_enable_extended_stats is OFF") + + tk.MustExec("set session tidb_enable_extended_stats = on") + tk.MustExec("alter table t add stats_extended s1 correlation(a,b)") + tk.MustQuery("select stats, status from mysql.stats_extended where name = 's1'").Check(testkit.Rows( + " 0", + )) + tk.MustExec("set session tidb_enable_extended_stats = off") + // Analyze should not collect extended stats. + tk.MustExec("analyze table t") + tk.MustQuery("select stats, status from mysql.stats_extended where name = 's1'").Check(testkit.Rows( + " 0", + )) + tk.MustExec("set session tidb_enable_extended_stats = on") + // Analyze would collect extended stats. + tk.MustExec("analyze table t") + tk.MustQuery("select stats, status from mysql.stats_extended where name = 's1'").Check(testkit.Rows( + "1.000000 1", + )) + // Estimated index scan count is 4 using extended stats. + tk.MustQuery("explain format = 'brief' select * from t use index(b) where a > 3 order by b limit 1").Check(testkit.Rows( + "Limit 1.00 root offset:0, count:1", + "└─Projection 1.00 root test.t.a, test.t.b", + " └─IndexLookUp 1.00 root ", + " ├─IndexFullScan(Build) 4.00 cop[tikv] table:t, index:b(b) keep order:true", + " └─Selection(Probe) 1.00 cop[tikv] gt(test.t.a, 3)", + " └─TableRowIDScan 4.00 cop[tikv] table:t keep order:false", + )) + tk.MustExec("set session tidb_enable_extended_stats = off") + // Estimated index scan count is 2 using independent assumption. + tk.MustQuery("explain format = 'brief' select * from t use index(b) where a > 3 order by b limit 1").Check(testkit.Rows( + "Limit 1.00 root offset:0, count:1", + "└─Projection 1.00 root test.t.a, test.t.b", + " └─IndexLookUp 1.00 root ", + " ├─IndexFullScan(Build) 2.00 cop[tikv] table:t, index:b(b) keep order:true", + " └─Selection(Probe) 1.00 cop[tikv] gt(test.t.a, 3)", + " └─TableRowIDScan 2.00 cop[tikv] table:t keep order:false", + )) +} + +func (s *testIntegrationSuite) TestOrderByNotInSelectDistinct(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + + // #12442 + tk.MustExec("drop table if exists ttest") + tk.MustExec("create table ttest (v1 int, v2 int)") + tk.MustExec("insert into ttest values(1, 2), (4,6), (1, 7)") + + tk.MustGetErrMsg("select distinct v1 from ttest order by v2", + "[planner:3065]Expression #1 of ORDER BY clause is not in SELECT list, references column 'test.ttest.v2' which is not in SELECT list; this is incompatible with DISTINCT") + tk.MustGetErrMsg("select distinct v1+1 from ttest order by v1", + "[planner:3065]Expression #1 of ORDER BY clause is not in SELECT list, references column 'test.ttest.v1' which is not in SELECT list; this is incompatible with DISTINCT") + tk.MustGetErrMsg("select distinct v1+1 from ttest order by 1+v1", + "[planner:3065]Expression #1 of ORDER BY clause is not in SELECT list, references column 'test.ttest.v1' which is not in SELECT list; this is incompatible with DISTINCT") + tk.MustGetErrMsg("select distinct v1+1 from ttest order by v1+2", + "[planner:3065]Expression #1 of ORDER BY clause is not in SELECT list, references column 'test.ttest.v1' which is not in SELECT list; this is incompatible with DISTINCT") + tk.MustGetErrMsg("select distinct count(v1) from ttest group by v2 order by sum(v1)", + "[planner:3066]Expression #1 of ORDER BY clause is not in SELECT list, contains aggregate function; this is incompatible with DISTINCT") + tk.MustGetErrMsg("select distinct sum(v1)+1 from ttest group by v2 order by sum(v1)", + "[planner:3066]Expression #1 of ORDER BY clause is not in SELECT list, contains aggregate function; this is incompatible with DISTINCT") + + // Expressions in ORDER BY whole match some fields in DISTINCT. + tk.MustQuery("select distinct v1+1 from ttest order by v1+1").Check(testkit.Rows("2", "5")) + tk.MustQuery("select distinct count(v1) from ttest order by count(v1)").Check(testkit.Rows("3")) + tk.MustQuery("select distinct count(v1) from ttest group by v2 order by count(v1)").Check(testkit.Rows("1")) + tk.MustQuery("select distinct sum(v1) from ttest group by v2 order by sum(v1)").Check(testkit.Rows("1", "4")) + tk.MustQuery("select distinct v1, v2 from ttest order by 1, 2").Check(testkit.Rows("1 2", "1 7", "4 6")) + tk.MustQuery("select distinct v1, v2 from ttest order by 2, 1").Check(testkit.Rows("1 2", "4 6", "1 7")) + + // Referenced columns of expressions in ORDER BY whole match some fields in DISTINCT, + // both original expression and alias can be referenced. + tk.MustQuery("select distinct v1 from ttest order by v1+1").Check(testkit.Rows("1", "4")) + tk.MustQuery("select distinct v1, v2 from ttest order by v1+1, v2").Check(testkit.Rows("1 2", "1 7", "4 6")) + tk.MustQuery("select distinct v1+1 as z, v2 from ttest order by v1+1, z+v2").Check(testkit.Rows("2 2", "2 7", "5 6")) + tk.MustQuery("select distinct sum(v1) as z from ttest group by v2 order by z+1").Check(testkit.Rows("1", "4")) + tk.MustQuery("select distinct sum(v1)+1 from ttest group by v2 order by sum(v1)+1").Check(testkit.Rows("2", "5")) + tk.MustQuery("select distinct v1 as z from ttest order by v1+z").Check(testkit.Rows("1", "4")) +} + +func (s *testIntegrationSuite) TestInvalidNamedWindowSpec(c *C) { + // #12356 + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("DROP TABLE IF EXISTS temptest") + tk.MustExec("create table temptest (val int, val1 int)") + tk.MustQuery("SELECT val FROM temptest WINDOW w AS (ORDER BY val RANGE 1 PRECEDING)").Check(testkit.Rows()) + tk.MustGetErrMsg("SELECT val FROM temptest WINDOW w AS (ORDER BY val, val1 RANGE 1 PRECEDING)", + "[planner:3587]Window 'w' with RANGE N PRECEDING/FOLLOWING frame requires exactly one ORDER BY expression, of numeric or temporal type") + tk.MustGetErrMsg("select val1, avg(val1) as a from temptest group by val1 window w as (order by a)", + "[planner:1054]Unknown column 'a' in 'window order by'") + tk.MustGetErrMsg("select val1, avg(val1) as a from temptest group by val1 window w as (partition by a)", + "[planner:1054]Unknown column 'a' in 'window partition by'") +} + +func (s *testIntegrationSuite) TestCorrelatedAggregate(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + + // #18350 + tk.MustExec("DROP TABLE IF EXISTS tab, tab2") + tk.MustExec("CREATE TABLE tab(i INT)") + tk.MustExec("CREATE TABLE tab2(j INT)") + tk.MustExec("insert into tab values(1),(2),(3)") + tk.MustExec("insert into tab2 values(1),(2),(3),(15)") + tk.MustQuery(`SELECT m.i, + (SELECT COUNT(n.j) + FROM tab2 WHERE j=15) AS o + FROM tab m, tab2 n GROUP BY 1 order by m.i`).Check(testkit.Rows("1 4", "2 4", "3 4")) + tk.MustQuery(`SELECT + (SELECT COUNT(n.j) + FROM tab2 WHERE j=15) AS o + FROM tab m, tab2 n order by m.i`).Check(testkit.Rows("12")) + + // #17748 + tk.MustExec("drop table if exists t1, t2") + tk.MustExec("create table t1 (a int, b int)") + tk.MustExec("create table t2 (m int, n int)") + tk.MustExec("insert into t1 values (2,2), (2,2), (3,3), (3,3), (3,3), (4,4)") + tk.MustExec("insert into t2 values (1,11), (2,22), (3,32), (4,44), (4,44)") + tk.MustExec("set @@sql_mode='TRADITIONAL'") + + tk.MustQuery(`select count(*) c, a, + ( select group_concat(count(a)) from t2 where m = a ) + from t1 group by a order by a`). + Check(testkit.Rows("2 2 2", "3 3 3", "1 4 1,1")) + + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (a int, b int)") + tk.MustExec("insert into t values (1,1),(2,1),(2,2),(3,1),(3,2),(3,3)") + + // Sub-queries in SELECT fields + // from SELECT fields + tk.MustQuery("select (select count(a)) from t").Check(testkit.Rows("6")) + tk.MustQuery("select (select (select (select count(a)))) from t").Check(testkit.Rows("6")) + tk.MustQuery("select (select (select count(n.a)) from t m order by count(m.b)) from t n").Check(testkit.Rows("6")) + // from WHERE + tk.MustQuery("select (select count(n.a) from t where count(n.a)=3) from t n").Check(testkit.Rows("")) + tk.MustQuery("select (select count(a) from t where count(distinct n.a)=3) from t n").Check(testkit.Rows("6")) + // from HAVING + tk.MustQuery("select (select count(n.a) from t having count(n.a)=6 limit 1) from t n").Check(testkit.Rows("6")) + tk.MustQuery("select (select count(n.a) from t having count(distinct n.b)=3 limit 1) from t n").Check(testkit.Rows("6")) + tk.MustQuery("select (select sum(distinct n.a) from t having count(distinct n.b)=3 limit 1) from t n").Check(testkit.Rows("6")) + tk.MustQuery("select (select sum(distinct n.a) from t having count(distinct n.b)=6 limit 1) from t n").Check(testkit.Rows("")) + // from ORDER BY + tk.MustQuery("select (select count(n.a) from t order by count(n.b) limit 1) from t n").Check(testkit.Rows("6")) + tk.MustQuery("select (select count(distinct n.b) from t order by count(n.b) limit 1) from t n").Check(testkit.Rows("3")) + // from TableRefsClause + tk.MustQuery("select (select cnt from (select count(a) cnt) s) from t").Check(testkit.Rows("6")) + tk.MustQuery("select (select count(cnt) from (select count(a) cnt) s) from t").Check(testkit.Rows("1")) + // from sub-query inside aggregate + tk.MustQuery("select (select sum((select count(a)))) from t").Check(testkit.Rows("6")) + tk.MustQuery("select (select sum((select count(a))+sum(a))) from t").Check(testkit.Rows("20")) + // from GROUP BY + tk.MustQuery("select (select count(a) from t group by count(n.a)) from t n").Check(testkit.Rows("6")) + tk.MustQuery("select (select count(distinct a) from t group by count(n.a)) from t n").Check(testkit.Rows("3")) + + // Sub-queries in HAVING + tk.MustQuery("select sum(a) from t having (select count(a)) = 0").Check(testkit.Rows()) + tk.MustQuery("select sum(a) from t having (select count(a)) > 0").Check(testkit.Rows("14")) + + // Sub-queries in ORDER BY + tk.MustQuery("select count(a) from t group by b order by (select count(a))").Check(testkit.Rows("1", "2", "3")) + tk.MustQuery("select count(a) from t group by b order by (select -count(a))").Check(testkit.Rows("3", "2", "1")) + + // Nested aggregate (correlated aggregate inside aggregate) + tk.MustQuery("select (select sum(count(a))) from t").Check(testkit.Rows("6")) + tk.MustQuery("select (select sum(sum(a))) from t").Check(testkit.Rows("14")) + + // Combining aggregates + tk.MustQuery("select count(a), (select count(a)) from t").Check(testkit.Rows("6 6")) + tk.MustQuery("select sum(distinct b), count(a), (select count(a)), (select cnt from (select sum(distinct b) as cnt) n) from t"). + Check(testkit.Rows("6 6 6 6")) +} + +func (s *testIntegrationSuite) TestCorrelatedColumnAggFuncPushDown(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);") + tk.MustExec("insert into t values (1,1);") + tk.MustQuery("select (select count(n.a + a) from t) from t n;").Check(testkit.Rows( + "1", + )) +} + +// Test for issue https://github.com/pingcap/tidb/issues/21607. +func (s *testIntegrationSuite) TestConditionColPruneInPhysicalUnionScan(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);") + tk.MustExec("begin;") + tk.MustExec("insert into t values (1, 2);") + tk.MustQuery("select count(*) from t where b = 1 and b in (3);"). + Check(testkit.Rows("0")) + + tk.MustExec("drop table t;") + tk.MustExec("create table t (a int, b int as (a + 1), c int as (b + 1));") + tk.MustExec("begin;") + tk.MustExec("insert into t (a) values (1);") + tk.MustQuery("select count(*) from t where b = 1 and b in (3);"). + Check(testkit.Rows("0")) + tk.MustQuery("select count(*) from t where c = 1 and c in (3);"). + Check(testkit.Rows("0")) +} + +func (s *testIntegrationSuite) TestInvalidHint(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("use test") + tk.MustExec("drop table if exists tt") + tk.MustExec("create table tt(a int, key(a));") + + var input []string + var output []struct { + SQL string + Plan []string + Warnings []string + } + s.testData.GetTestCases(c, &input, &output) + warning := "show warnings;" + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + output[i].Warnings = s.testData.ConvertRowsToStrings(tk.MustQuery(warning).Rows()) + }) + tk.MustQuery(tt).Check(testkit.Rows(output[i].Plan...)) + } +} + +// Test for issue https://github.com/pingcap/tidb/issues/18320 +func (s *testIntegrationSuite) TestNonaggregateColumnWithSingleValueInOnlyFullGroupByMode(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, c int)") + tk.MustExec("insert into t values (1, 2, 3), (4, 5, 6), (7, 8, 9)") + tk.MustQuery("select a, count(b) from t where a = 1").Check(testkit.Rows("1 1")) + tk.MustQuery("select a, count(b) from t where a = 10").Check(testkit.Rows(" 0")) + tk.MustQuery("select a, c, sum(b) from t where a = 1 group by c").Check(testkit.Rows("1 3 2")) + tk.MustGetErrMsg("select a from t where a = 1 order by count(b)", "[planner:3029]Expression #1 of ORDER BY contains aggregate function and applies to the result of a non-aggregated query") + tk.MustQuery("select a from t where a = 1 having count(b) > 0").Check(testkit.Rows("1")) +} + +func (s *testIntegrationSuite) TestConvertRangeToPoint(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t0") + tk.MustExec("create table t0 (a int, b int, index(a, b))") + tk.MustExec("insert into t0 values (1, 1)") + tk.MustExec("insert into t0 values (2, 2)") + tk.MustExec("insert into t0 values (2, 2)") + tk.MustExec("insert into t0 values (2, 2)") + tk.MustExec("insert into t0 values (2, 2)") + tk.MustExec("insert into t0 values (2, 2)") + tk.MustExec("insert into t0 values (3, 3)") + + tk.MustExec("drop table if exists t1") + tk.MustExec("create table t1 (a int, b int, c int, index(a, b, c))") + + tk.MustExec("drop table if exists t2") + tk.MustExec("create table t2 (a float, b float, index(a, b))") + + tk.MustExec("drop table if exists t3") + tk.MustExec("create table t3 (a char(10), b char(10), c char(10), index(a, b, c))") + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + tk.MustQuery(tt).Check(testkit.Rows(output[i].Plan...)) + } +} + +func (s *testIntegrationSuite) TestIssue22040(c *C) { + // #22040 + 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, primary key(a,b))") + // valid case + tk.MustExec("select * from t where (a,b) in ((1,2),(1,2))") + // invalid case, column count doesn't match + { + err := tk.ExecToErr("select * from t where (a,b) in (1,2)") + c.Assert(errors.Cause(err), FitsTypeOf, expression.ErrOperandColumns) + } + { + err := tk.ExecToErr("select * from t where (a,b) in ((1,2),1)") + c.Assert(errors.Cause(err), FitsTypeOf, expression.ErrOperandColumns) + } +} + +func (s *testIntegrationSuite) TestIssue22105(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec(`CREATE TABLE t1 ( + key1 int(11) NOT NULL, + key2 int(11) NOT NULL, + key3 int(11) NOT NULL, + key4 int(11) NOT NULL, + key5 int(11) DEFAULT NULL, + key6 int(11) DEFAULT NULL, + key7 int(11) NOT NULL, + key8 int(11) NOT NULL, + KEY i1 (key1), + KEY i2 (key2), + KEY i3 (key3), + KEY i4 (key4), + KEY i5 (key5), + KEY i6 (key6) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin`) + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + tk.MustQuery(tt).Check(testkit.Rows(output[i].Plan...)) + } +} + +func (s *testIntegrationSuite) TestIssue22071(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("create table t (a int);") + tk.MustExec("insert into t values(1),(2),(5)") + tk.MustQuery("select n in (1,2) from (select a in (1,2) as n from t) g;").Sort().Check(testkit.Rows("0", "1", "1")) + tk.MustQuery("select n in (1,n) from (select a in (1,2) as n from t) g;").Check(testkit.Rows("1", "1", "1")) +} + +func (s *testIntegrationSuite) TestCreateViewIsolationRead(c *C) { + se, err := session.CreateSession4Test(s.store) + c.Assert(err, IsNil) + c.Assert(se.Auth(&auth.UserIdentity{Username: "root", Hostname: "%"}, nil, nil), IsTrue) + tk := testkit.NewTestKit(c, s.store) + tk.Se = se + + tk.MustExec("use test;") + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t(a int, b int);") + tk.MustExec("set session tidb_isolation_read_engines='tiflash,tidb';") + // No error for CreateView. + tk.MustExec("create view v0 (a, avg_b) as select a, avg(b) from t group by a;") + tk.MustGetErrMsg("select * from v0;", "[planner:1815]Internal : No access path for table 't' is found with 'tidb_isolation_read_engines' = 'tiflash,tidb', valid values can be 'tikv'.") + tk.MustExec("set session tidb_isolation_read_engines='tikv,tiflash,tidb';") + tk.MustQuery("select * from v0;").Check(testkit.Rows()) +} + +func (s *testIntegrationSuite) TestIssue22199(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t1, t2") + tk.MustExec("create table t1(i int primary key, j int, index idx_j(j))") + tk.MustExec("create table t2(i int primary key, j int, index idx_j(j))") + tk.MustGetErrMsg("select t1.*, (select t2.* from t1) from t1", "[planner:1051]Unknown table 't2'") +} + +func (s *testIntegrationSuite) TestIssue22892(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("set @@tidb_partition_prune_mode='static'") + tk.MustExec("drop table if exists t1") + tk.MustExec("create table t1(a int) partition by hash (a) partitions 5;") + tk.MustExec("insert into t1 values (0);") + tk.MustQuery("select * from t1 where a not between 1 and 2;").Check(testkit.Rows("0")) + + tk.MustExec("set @@tidb_partition_prune_mode='dynamic'") + tk.MustExec("drop table if exists t2") + tk.MustExec("create table t2(a int) partition by hash (a) partitions 5;") + tk.MustExec("insert into t2 values (0);") + tk.MustQuery("select * from t2 where a not between 1 and 2;").Check(testkit.Rows("0")) +} + +func (s *testIntegrationSuite) TestIssue26719(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec(`create table tx (a int) partition by range (a) (partition p0 values less than (10), partition p1 values less than (20))`) + tk.MustExec(`insert into tx values (1)`) + tk.MustExec("set @@tidb_partition_prune_mode='dynamic'") + + tk.MustExec(`begin`) + tk.MustExec(`delete from tx where a in (1)`) + tk.MustQuery(`select * from tx PARTITION(p0)`).Check(testkit.Rows()) + tk.MustQuery(`select * from tx`).Check(testkit.Rows()) + tk.MustExec(`rollback`) +} + +func (s *testIntegrationSuite) TestIssue32428(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("create table `t1` (`a` enum('aa') DEFAULT NULL, KEY `k` (`a`))") + tk.MustExec("insert into t1 values('aa')") + tk.MustExec("insert into t1 values(null)") + tk.MustQuery("select a from t1 where a<=>'aa'").Check(testkit.Rows("aa")) + tk.MustQuery("select a from t1 where a<=>null").Check(testkit.Rows("")) + + tk.MustExec(`CREATE TABLE IDT_MULTI15860STROBJSTROBJ ( + COL1 enum('aa') DEFAULT NULL, + COL2 int(41) DEFAULT NULL, + COL3 year(4) DEFAULT NULL, + KEY U_M_COL4 (COL1,COL2), + KEY U_M_COL5 (COL3,COL2))`) + tk.MustExec(`insert into IDT_MULTI15860STROBJSTROBJ values("aa", 1013610488, 1982)`) + tk.MustQuery(`SELECT * FROM IDT_MULTI15860STROBJSTROBJ t1 RIGHT JOIN IDT_MULTI15860STROBJSTROBJ t2 ON t1.col1 <=> t2.col1 where t1.col1 is null and t2.col1 = "aa"`).Check(testkit.Rows()) // empty result + tk.MustExec(`prepare stmt from "SELECT * FROM IDT_MULTI15860STROBJSTROBJ t1 RIGHT JOIN IDT_MULTI15860STROBJSTROBJ t2 ON t1.col1 <=> t2.col1 where t1.col1 is null and t2.col1 = ?"`) + tk.MustExec(`set @a="aa"`) + tk.MustQuery(`execute stmt using @a`).Check(testkit.Rows()) // empty result +} + +func (s *testIntegrationSerialSuite) TestPushDownProjectionForTiFlash(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (id int, value decimal(6,3), name char(128))") + tk.MustExec("analyze table t") + tk.MustExec("set session tidb_allow_mpp=OFF") + + // Create virtual tiflash replica info. + dom := domain.GetDomain(tk.Se) + is := dom.InfoSchema() + db, exists := is.SchemaByName(model.NewCIStr("test")) + c.Assert(exists, IsTrue) + for _, tblInfo := range db.Tables { + if tblInfo.Name.L == "t" { + tblInfo.TiFlashReplica = &model.TiFlashReplicaInfo{ + Count: 1, + Available: true, + } + } + } + + tk.MustExec("set @@tidb_opt_broadcast_join=1;") + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + res := tk.MustQuery(tt) + res.Check(testkit.Rows(output[i].Plan...)) + } +} + +func (s *testIntegrationSerialSuite) TestPushDownProjectionForMPP(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (id int, value decimal(6,3), name char(128))") + tk.MustExec("analyze table t") + + // Create virtual tiflash replica info. + dom := domain.GetDomain(tk.Se) + is := dom.InfoSchema() + db, exists := is.SchemaByName(model.NewCIStr("test")) + c.Assert(exists, IsTrue) + for _, tblInfo := range db.Tables { + if tblInfo.Name.L == "t" { + tblInfo.TiFlashReplica = &model.TiFlashReplicaInfo{ + Count: 1, + Available: true, + } + } + } + + tk.MustExec("set @@tidb_allow_mpp=1; set @@tidb_opt_broadcast_join=0; set @@tidb_enforce_mpp=1;") + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + res := tk.MustQuery(tt) + res.Check(testkit.Rows(output[i].Plan...)) + } +} + +func (s *testIntegrationSuite) TestReorderSimplifiedOuterJoins(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t1,t2,t3") + tk.MustExec("create table t1 (pk char(32) primary key, col1 char(32), col2 varchar(40), col3 char(32), key (col1), key (col3), key (col2,col3), key (col1,col3))") + tk.MustExec("create table t2 (pk char(32) primary key, col1 varchar(100))") + tk.MustExec("create table t3 (pk char(32) primary key, keycol varchar(100), pad1 tinyint(1) default null, pad2 varchar(40), key (keycol,pad1,pad2))") + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + tk.MustQuery(tt).Check(testkit.Rows(output[i].Plan...)) + } +} + +// Apply operator may got panic because empty Projection is eliminated. +func (s *testIntegrationSerialSuite) TestIssue23887(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);") + tk.MustExec("insert into t values(1, 2), (3, 4);") + var input []string + var output []struct { + SQL string + Plan []string + Res []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery("explain format = 'brief' " + tt).Rows()) + output[i].Res = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Sort().Rows()) + }) + tk.MustQuery("explain format = 'brief' " + tt).Check(testkit.Rows(output[i].Plan...)) + tk.MustQuery(tt).Sort().Check(testkit.Rows(output[i].Res...)) + } + + tk.MustExec("drop table if exists t1;") + tk.MustExec("create table t1 (c1 int primary key, c2 int, c3 int, index c2 (c2));") + tk.MustQuery("select count(1) from (select count(1) from (select * from t1 where c3 = 100) k) k2;").Check(testkit.Rows("1")) +} + +func (s *testIntegrationSerialSuite) TestDeleteStmt(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("create table t(a int)") + tk.MustExec("delete t from t;") + tk.MustExec("delete t from test.t as t;") + tk.MustGetErrCode("delete test.t from test.t as t;", mysql.ErrUnknownTable) + tk.MustExec("delete test.t from t;") + tk.MustExec("create database db1") + tk.MustExec("use db1") + tk.MustExec("create table t(a int)") + tk.MustGetErrCode("delete test.t from t;", mysql.ErrUnknownTable) +} + +func (s *testIntegrationSuite) TestIndexMergeConstantTrue(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 primary key, b int not null, key(b))") + tk.MustExec("delete /*+ use_index_merge(t) */ FROM t WHERE a=1 OR (b < SOME (SELECT /*+ use_index_merge(t)*/ b FROM t WHERE a<2 OR b<2))") + + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(a int not null, b int not null, key(a), key(b))") + tk.MustExec("delete /*+ use_index_merge(t) */ FROM t WHERE a=1 OR (b < SOME (SELECT /*+ use_index_merge(t)*/ b FROM t WHERE a<2 OR b<2))") + + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(a int primary key, b int not null, c int, key(a), key(b,c))") + tk.MustExec("delete /*+ use_index_merge(t) */ FROM t WHERE a=1 OR (a<2 and b<2)") +} + +func (s *testIntegrationSerialSuite) TestPushDownAggForMPP(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (id int, value decimal(6,3))") + tk.MustExec("analyze table t") + + // Create virtual tiflash replica info. + dom := domain.GetDomain(tk.Se) + is := dom.InfoSchema() + db, exists := is.SchemaByName(model.NewCIStr("test")) + c.Assert(exists, IsTrue) + for _, tblInfo := range db.Tables { + if tblInfo.Name.L == "t" { + tblInfo.TiFlashReplica = &model.TiFlashReplicaInfo{ + Count: 1, + Available: true, + } + } + } + + tk.MustExec(" set @@tidb_allow_mpp=1; set @@tidb_opt_broadcast_join=0; set @@tidb_broadcast_join_threshold_count = 1; set @@tidb_broadcast_join_threshold_size=1;") + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + res := tk.MustQuery(tt) + res.Check(testkit.Rows(output[i].Plan...)) + } +} + +func (s *testIntegrationSerialSuite) TestMppUnionAll(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 int not null, b int, c varchar(20))") + tk.MustExec("create table t1 (a int, b int not null, c double)") + + // Create virtual tiflash replica info. + dom := domain.GetDomain(tk.Se) + is := dom.InfoSchema() + db, exists := is.SchemaByName(model.NewCIStr("test")) + c.Assert(exists, IsTrue) + for _, tblInfo := range db.Tables { + if tblInfo.Name.L == "t" || tblInfo.Name.L == "t1" { + tblInfo.TiFlashReplica = &model.TiFlashReplicaInfo{ + Count: 1, + Available: true, + } + } + } + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + res := tk.MustQuery(tt) + res.Check(testkit.Rows(output[i].Plan...)) + } + +} + +func (s *testIntegrationSerialSuite) TestMppJoinDecimal(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 tt") + tk.MustExec("create table t (c1 decimal(8, 5), c2 decimal(9, 5), c3 decimal(9, 4) NOT NULL, c4 decimal(8, 4) NOT NULL, c5 decimal(40, 20))") + tk.MustExec("create table tt (pk int(11) NOT NULL AUTO_INCREMENT primary key,col_varchar_64 varchar(64),col_char_64_not_null char(64) NOT null, col_decimal_30_10_key decimal(30,10), col_tinyint tinyint, col_varchar_key varchar(1), key col_decimal_30_10_key (col_decimal_30_10_key), key col_varchar_key(col_varchar_key));") + tk.MustExec("analyze table t") + tk.MustExec("analyze table tt") + + // Create virtual tiflash replica info. + dom := domain.GetDomain(tk.Se) + is := dom.InfoSchema() + db, exists := is.SchemaByName(model.NewCIStr("test")) + c.Assert(exists, IsTrue) + for _, tblInfo := range db.Tables { + if tblInfo.Name.L == "t" || tblInfo.Name.L == "tt" { + tblInfo.TiFlashReplica = &model.TiFlashReplicaInfo{ + Count: 1, + Available: true, + } + } + } + + tk.MustExec("set @@tidb_allow_mpp=1;") + tk.MustExec("set @@session.tidb_broadcast_join_threshold_size = 1") + tk.MustExec("set @@session.tidb_broadcast_join_threshold_count = 1") + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + res := tk.MustQuery(tt) + res.Check(testkit.Rows(output[i].Plan...)) + } +} + +func (s *testIntegrationSerialSuite) TestMppAggTopNWithJoin(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (id int, value decimal(6,3))") + tk.MustExec("analyze table t") + + // Create virtual tiflash replica info. + dom := domain.GetDomain(tk.Se) + is := dom.InfoSchema() + db, exists := is.SchemaByName(model.NewCIStr("test")) + c.Assert(exists, IsTrue) + for _, tblInfo := range db.Tables { + if tblInfo.Name.L == "t" { + tblInfo.TiFlashReplica = &model.TiFlashReplicaInfo{ + Count: 1, + Available: true, + } + } + } + + tk.MustExec(" set @@tidb_allow_mpp=1;") + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + res := tk.MustQuery(tt) + res.Check(testkit.Rows(output[i].Plan...)) + } +} + +func (s *testIntegrationSerialSuite) TestLimitIndexLookUpKeepOrder(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, c int, d int, index idx(a,b,c));") + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + tk.MustQuery(tt).Check(testkit.Rows(output[i].Plan...)) + } +} + +func (s *testIntegrationSuite) TestDecorrelateInnerJoinInSubquery(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 not null, b int not null)") + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + tk.MustQuery(tt).Check(testkit.Rows(output[i].Plan...)) + } +} + +func (s *testIntegrationSuite) TestIndexMergeTableFilter(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, c int, d int, key(a), key(b));") + tk.MustExec("insert into t values(10,1,1,10)") + + tk.MustQuery("explain format = 'brief' select /*+ use_index_merge(t) */ * from t where a=10 or (b=10 and c=10)").Check(testkit.Rows( + "IndexMerge 0.02 root ", + "├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:a(a) range:[10,10], keep order:false, stats:pseudo", + "├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:b(b) range:[10,10], keep order:false, stats:pseudo", + "└─Selection(Probe) 0.02 cop[tikv] or(eq(test.t.a, 10), and(eq(test.t.b, 10), eq(test.t.c, 10)))", + " └─TableRowIDScan 19.99 cop[tikv] table:t keep order:false, stats:pseudo", + )) + tk.MustQuery("select /*+ use_index_merge(t) */ * from t where a=10 or (b=10 and c=10)").Check(testkit.Rows( + "10 1 1 10", + )) + tk.MustQuery("explain format = 'brief' select /*+ use_index_merge(t) */ * from t where (a=10 and d=10) or (b=10 and c=10)").Check(testkit.Rows( + "IndexMerge 0.00 root ", + "├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:a(a) range:[10,10], keep order:false, stats:pseudo", + "├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:b(b) range:[10,10], keep order:false, stats:pseudo", + "└─Selection(Probe) 0.00 cop[tikv] or(and(eq(test.t.a, 10), eq(test.t.d, 10)), and(eq(test.t.b, 10), eq(test.t.c, 10)))", + " └─TableRowIDScan 19.99 cop[tikv] table:t keep order:false, stats:pseudo", + )) + tk.MustQuery("select /*+ use_index_merge(t) */ * from t where (a=10 and d=10) or (b=10 and c=10)").Check(testkit.Rows( + "10 1 1 10", + )) +} + +func (s *testIntegrationSuite) TestIssue22850(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t1") + tk.MustExec("CREATE TABLE t1 (a int(11))") + tk.MustQuery("SELECT @v:=(SELECT 1 FROM t1 t2 LEFT JOIN t1 ON t1.a GROUP BY t1.a) FROM t1").Check(testkit.Rows()) // work fine +} + +func (s *testIntegrationSuite) TestJoinSchemaChange(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t1, t2") + tk.MustExec("create table t1(a int(11))") + tk.MustExec("create table t2(a decimal(40,20) unsigned, b decimal(40,20))") + tk.MustQuery("select count(*) as x from t1 group by a having x not in (select a from t2 where x = t2.b)").Check(testkit.Rows()) +} + +// #22949: test HexLiteral Used in GetVar expr +func (s *testIntegrationSuite) TestGetVarExprWithHexLiteral(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test;") + tk.MustExec("drop table if exists t1_no_idx;") + tk.MustExec("create table t1_no_idx(id int, col_bit bit(16));") + tk.MustExec("insert into t1_no_idx values(1, 0x3135);") + tk.MustExec("insert into t1_no_idx values(2, 0x0f);") + + tk.MustExec("prepare stmt from 'select id from t1_no_idx where col_bit = ?';") + tk.MustExec("set @a = 0x3135;") + tk.MustQuery("execute stmt using @a;").Check(testkit.Rows("1")) + tk.MustExec("set @a = 0x0F;") + tk.MustQuery("execute stmt using @a;").Check(testkit.Rows("2")) + + // same test, but use IN expr + tk.MustExec("prepare stmt from 'select id from t1_no_idx where col_bit in (?)';") + tk.MustExec("set @a = 0x3135;") + tk.MustQuery("execute stmt using @a;").Check(testkit.Rows("1")) + tk.MustExec("set @a = 0x0F;") + tk.MustQuery("execute stmt using @a;").Check(testkit.Rows("2")) + + // same test, but use table with index on col_bit + tk.MustExec("drop table if exists t2_idx;") + tk.MustExec("create table t2_idx(id int, col_bit bit(16), key(col_bit));") + tk.MustExec("insert into t2_idx values(1, 0x3135);") + tk.MustExec("insert into t2_idx values(2, 0x0f);") + + tk.MustExec("prepare stmt from 'select id from t2_idx where col_bit = ?';") + tk.MustExec("set @a = 0x3135;") + tk.MustQuery("execute stmt using @a;").Check(testkit.Rows("1")) + tk.MustExec("set @a = 0x0F;") + tk.MustQuery("execute stmt using @a;").Check(testkit.Rows("2")) + + // same test, but use IN expr + tk.MustExec("prepare stmt from 'select id from t2_idx where col_bit in (?)';") + tk.MustExec("set @a = 0x3135;") + tk.MustQuery("execute stmt using @a;").Check(testkit.Rows("1")) + tk.MustExec("set @a = 0x0F;") + tk.MustQuery("execute stmt using @a;").Check(testkit.Rows("2")) + + // test col varchar with GetVar + tk.MustExec("drop table if exists t_varchar;") + tk.MustExec("create table t_varchar(id int, col_varchar varchar(100), key(col_varchar));") + tk.MustExec("insert into t_varchar values(1, '15');") + tk.MustExec("prepare stmt from 'select id from t_varchar where col_varchar = ?';") + tk.MustExec("set @a = 0x3135;") + tk.MustQuery("execute stmt using @a;").Check(testkit.Rows("1")) +} + +// test BitLiteral used with GetVar +func (s *testIntegrationSuite) TestGetVarExprWithBitLiteral(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test;") + tk.MustExec("drop table if exists t1_no_idx;") + tk.MustExec("create table t1_no_idx(id int, col_bit bit(16));") + tk.MustExec("insert into t1_no_idx values(1, 0x3135);") + tk.MustExec("insert into t1_no_idx values(2, 0x0f);") + + tk.MustExec("prepare stmt from 'select id from t1_no_idx where col_bit = ?';") + // 0b11000100110101 is 0x3135 + tk.MustExec("set @a = 0b11000100110101;") + tk.MustQuery("execute stmt using @a;").Check(testkit.Rows("1")) + + // same test, but use IN expr + tk.MustExec("prepare stmt from 'select id from t1_no_idx where col_bit in (?)';") + tk.MustExec("set @a = 0b11000100110101;") + tk.MustQuery("execute stmt using @a;").Check(testkit.Rows("1")) +} + +func (s *testIntegrationSuite) TestIndexMergeClusterIndex(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test;") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (c1 float, c2 int, c3 int, primary key (c1) /*T![clustered_index] CLUSTERED */, key idx_1 (c2), key idx_2 (c3))") + tk.MustExec("insert into t values(1.0,1,2),(2.0,2,1),(3.0,1,1),(4.0,2,2)") + tk.MustQuery("select /*+ use_index_merge(t) */ c3 from t where c3 = 1 or c2 = 1").Sort().Check(testkit.Rows( + "1", + "1", + "2", + )) + tk.MustExec("drop table t") + tk.MustExec("create table t (a int, b int, c int, primary key (a,b) /*T![clustered_index] CLUSTERED */, key idx_c(c))") + tk.MustExec("insert into t values (0,1,2)") + tk.MustQuery("select /*+ use_index_merge(t) */ c from t where c > 10 or a < 1").Check(testkit.Rows( + "2", + )) +} + +func (s *testIntegrationSuite) TestMultiColMaxOneRow(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t1,t2") + tk.MustExec("create table t1(a int)") + tk.MustExec("create table t2(a int, b int, c int, primary key(a,b))") + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery("explain format = 'brief' " + tt).Rows()) + }) + tk.MustQuery("explain format = 'brief' " + tt).Check(testkit.Rows(output[i].Plan...)) + } +} + +func (s *testIntegrationSuite) TestIssue23736(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t0, t1") + tk.MustExec("create table t0(a int, b int, c int as (a + b) virtual, unique index (c) invisible);") + tk.MustExec("create table t1(a int, b int, c int as (a + b) virtual);") + tk.MustExec("insert into t0(a, b) values (12, -1), (8, 7);") + tk.MustExec("insert into t1(a, b) values (12, -1), (8, 7);") + tk.MustQuery("select /*+ stream_agg() */ count(1) from t0 where c > 10 and b < 2;").Check(testkit.Rows("1")) + tk.MustQuery("select /*+ stream_agg() */ count(1) from t1 where c > 10 and b < 2;").Check(testkit.Rows("1")) + tk.MustExec("delete from t0") + tk.MustExec("insert into t0(a, b) values (5, 1);") + tk.MustQuery("select /*+ nth_plan(3) */ count(1) from t0 where c > 10 and b < 2;").Check(testkit.Rows("0")) + + // Should not use invisible index + c.Assert(tk.MustUseIndex("select /*+ stream_agg() */ count(1) from t0 where c > 10 and b < 2", "c"), IsFalse) +} + +// https://github.com/pingcap/tidb/issues/23802 +func (s *testIntegrationSuite) TestPanicWhileQueryTableWithIsNull(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + + tk.MustExec("drop table if exists NT_HP27193") + tk.MustExec("CREATE TABLE `NT_HP27193` ( `COL1` int(20) DEFAULT NULL, `COL2` varchar(20) DEFAULT NULL, `COL4` datetime DEFAULT NULL, `COL3` bigint(20) DEFAULT NULL, `COL5` float DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin PARTITION BY HASH ( `COL1`%`COL3` ) PARTITIONS 10;") + _, err := tk.Exec("select col1 from NT_HP27193 where col1 is null;") + c.Assert(err, IsNil) + tk.MustExec("INSERT INTO NT_HP27193 (COL2, COL4, COL3, COL5) VALUES ('m', '2020-05-04 13:15:27', 8, 2602)") + _, err = tk.Exec("select col1 from NT_HP27193 where col1 is null;") + c.Assert(err, IsNil) + tk.MustExec("drop table if exists NT_HP27193") +} + +func (s *testIntegrationSuite) TestIssue23846(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 varbinary(10),UNIQUE KEY(a))") + tk.MustExec("insert into t values(0x00A4EEF4FA55D6706ED5)") + tk.MustQuery("select count(*) from t where a=0x00A4EEF4FA55D6706ED5").Check(testkit.Rows("1")) + tk.MustQuery("select * from t where a=0x00A4EEF4FA55D6706ED5").Check(testkit.Rows("\x00\xa4\xee\xf4\xfaU\xd6pn\xd5")) // not empty +} + +func (s *testIntegrationSuite) TestIssue23839(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists BB") + tk.MustExec("CREATE TABLE `BB` (\n" + + " `col_int` int(11) DEFAULT NULL,\n" + + " `col_varchar_10` varchar(10) DEFAULT NULL,\n" + + " `pk` int(11) NOT NULL AUTO_INCREMENT,\n" + + " `col_int_not_null` int(11) NOT NULL,\n" + + " `col_decimal` decimal(10,0) DEFAULT NULL,\n" + + " `col_datetime` datetime DEFAULT NULL,\n" + + " `col_decimal_not_null` decimal(10,0) NOT NULL,\n" + + " `col_datetime_not_null` datetime NOT NULL,\n" + + " `col_varchar_10_not_null` varchar(10) NOT NULL,\n" + + " PRIMARY KEY (`pk`) /*T![clustered_index] CLUSTERED */\n" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin AUTO_INCREMENT=2000001") + tk.Exec("explain SELECT OUTR . col2 AS X FROM (SELECT INNR . col1 as col1, SUM( INNR . col2 ) as col2 FROM (SELECT INNR . `col_int_not_null` + 1 as col1, INNR . `pk` as col2 FROM BB AS INNR) AS INNR GROUP BY col1) AS OUTR2 INNER JOIN (SELECT INNR . col1 as col1, MAX( INNR . col2 ) as col2 FROM (SELECT INNR . `col_int_not_null` + 1 as col1, INNR . `pk` as col2 FROM BB AS INNR) AS INNR GROUP BY col1) AS OUTR ON OUTR2.col1 = OUTR.col1 GROUP BY OUTR . col1, OUTR2 . col1 HAVING X <> 'b'") +} + +// https://github.com/pingcap/tidb/issues/24095 +func (s *testIntegrationSuite) TestIssue24095(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test;") + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t (id int, value decimal(10,5));") + tk.MustExec("desc format = 'brief' select count(*) from t join (select t.id, t.value v1 from t join t t1 on t.id = t1.id order by t.value limit 1) v on v.id = t.id and v.v1 = t.value;") + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery("explain format = 'brief' " + tt).Rows()) + }) + tk.MustQuery("explain format = 'brief' " + tt).Check(testkit.Rows(output[i].Plan...)) + } +} + +func (s *testIntegrationSuite) TestIssue24281(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists member, agent, deposit, view_member_agents") + tk.MustExec("create table member(login varchar(50) NOT NULL, agent_login varchar(100) DEFAULT NULL, PRIMARY KEY(login))") + tk.MustExec("create table agent(login varchar(50) NOT NULL, data varchar(100) DEFAULT NULL, share_login varchar(50) NOT NULL, PRIMARY KEY(login))") + tk.MustExec("create table deposit(id varchar(50) NOT NULL, member_login varchar(50) NOT NULL, transfer_amount int NOT NULL, PRIMARY KEY(id), KEY midx(member_login, transfer_amount))") + tk.MustExec("create definer='root'@'localhost' view view_member_agents (member, share_login) as select m.login as member, a.share_login AS share_login from member as m join agent as a on m.agent_login = a.login") + + tk.MustExec(" select s.member_login as v1, SUM(s.transfer_amount) AS v2 " + + "FROM deposit AS s " + + "JOIN view_member_agents AS v ON s.member_login = v.member " + + "WHERE 1 = 1 AND v.share_login = 'somevalue' " + + "GROUP BY s.member_login " + + "UNION select 1 as v1, 2 as v2") +} + +func (s *testIntegrationSuite) TestIssue25799(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t1, t2") + tk.MustExec(`create table t1 (a float default null, b smallint(6) DEFAULT NULL)`) + tk.MustExec(`insert into t1 values (1, 1)`) + tk.MustExec(`create table t2 (a float default null, b tinyint(4) DEFAULT NULL, key b (b))`) + tk.MustExec(`insert into t2 values (null, 1)`) + tk.HasPlan(`select /*+ TIDB_INLJ(t2@sel_2) */ t1.a, t1.b from t1 where t1.a not in (select t2.a from t2 where t1.b=t2.b)`, `IndexJoin`) + tk.MustQuery(`select /*+ TIDB_INLJ(t2@sel_2) */ t1.a, t1.b from t1 where t1.a not in (select t2.a from t2 where t1.b=t2.b)`).Check(testkit.Rows()) +} + +func (s *testIntegrationSuite) TestLimitWindowColPrune(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)") + tk.MustExec("insert into t values(1)") + tk.MustQuery("select count(a) f1, row_number() over (order by count(a)) as f2 from t limit 1").Check(testkit.Rows("1 1")) +} + +func (s *testIntegrationSuite) TestIncrementalAnalyzeStatsVer2(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 primary key, b int, index idx_b(b))") + tk.MustExec("insert into t values(1,1),(2,2),(3,3)") + tk.MustExec("set @@session.tidb_analyze_version = 2") + tk.MustExec("analyze table t") + is := tk.Se.GetInfoSchema().(infoschema.InfoSchema) + tbl, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("t")) + c.Assert(err, IsNil) + tblID := tbl.Meta().ID + rows := tk.MustQuery(fmt.Sprintf("select distinct_count from mysql.stats_histograms where table_id = %d and is_index = 1", tblID)).Rows() + c.Assert(len(rows), Equals, 1) + c.Assert(rows[0][0], Equals, "3") + tk.MustExec("insert into t values(4,4),(5,5),(6,6)") + tk.MustExec("analyze incremental table t index idx_b") + c.Assert(tk.Se.GetSessionVars().StmtCtx.GetWarnings(), HasLen, 3) + c.Assert(tk.Se.GetSessionVars().StmtCtx.GetWarnings()[0].Err.Error(), Equals, "The version 2 would collect all statistics not only the selected indexes") + c.Assert(tk.Se.GetSessionVars().StmtCtx.GetWarnings()[1].Err.Error(), Equals, "The version 2 stats would ignore the INCREMENTAL keyword and do full sampling") + c.Assert(tk.Se.GetSessionVars().StmtCtx.GetWarnings()[2].Err.Error(), Equals, "Analyze use auto adjusted sample rate 1.000000 for table test.t.") + rows = tk.MustQuery(fmt.Sprintf("select distinct_count from mysql.stats_histograms where table_id = %d and is_index = 1", tblID)).Rows() + c.Assert(len(rows), Equals, 1) + c.Assert(rows[0][0], Equals, "6") +} + +func (s *testIntegrationSuite) TestConflictReadFromStorage(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, c varchar(20), + primary key(a), key(b), key(c) + ) partition by range columns(a) ( + partition p0 values less than(6), + partition p1 values less than(11), + partition p2 values less than(16));`) + tk.MustExec(`insert into t values (1,1,"1"), (2,2,"2"), (8,8,"8"), (11,11,"11"), (15,15,"15")`) +>>>>>>> 1b04c3b05... planner: fix wrong range calculation for Nulleq function on Enum values (#32440) // Create virtual tiflash replica info. dom := domain.GetDomain(tk.Se) is := dom.InfoSchema() diff --git a/planner/core/prepare_test.go b/planner/core/prepare_test.go index ca1ddb8424768..f50a27fd9d534 100644 --- a/planner/core/prepare_test.go +++ b/planner/core/prepare_test.go @@ -955,3 +955,702 @@ func (s *testPlanSerialSuite) TestPlanCacheSnapshot(c *C) { tk.MustQuery("execute stmt using @p").Check(testkit.Rows("1")) tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) } +<<<<<<< HEAD +======= + +func TestPlanCachePointGetAndTableDual(t *testing.T) { + store, clean := testkit.CreateMockStore(t) + defer clean() + orgEnable := core.PreparedPlanCacheEnabled() + defer core.SetPreparedPlanCache(orgEnable) + core.SetPreparedPlanCache(true) + se, err := session.CreateSession4TestWithOpt(store, &session.Opt{ + PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64), + }) + require.NoError(t, err) + tk := testkit.NewTestKitWithSession(t, store, se) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t0, t1, t2, t3, t4") + + tk.MustExec("create table t0(c1 varchar(20), c2 varchar(20), c3 bigint(20), primary key(c1, c2))") + tk.MustExec("insert into t0 values('0000','7777',1)") + tk.MustExec("prepare s0 from 'select * from t0 where c1=? and c2>=? and c2<=?'") + tk.MustExec("set @a0='0000', @b0='9999'") + // TableDual is forbidden for plan-cache, a TableReader be built and cached. + tk.MustQuery("execute s0 using @a0, @b0, @a0").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + tk.MustQuery("execute s0 using @a0, @a0, @b0").Check(testkit.Rows("0000 7777 1")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + + tk.MustExec("create table t1(c1 varchar(20), c2 varchar(20), c3 bigint(20), primary key(c1, c2))") + tk.MustExec("insert into t1 values('0000','7777',1)") + tk.MustExec("prepare s1 from 'select * from t1 where c1=? and c2>=? and c2<=?'") + tk.MustExec("set @a1='0000', @b1='9999'") + // IndexLookup plan would be built, we should cache it. + tk.MustQuery("execute s1 using @a1, @b1, @b1").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + tk.MustQuery("execute s1 using @a1, @a1, @b1").Check(testkit.Rows("0000 7777 1")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + + tk.MustExec("create table t2(c1 bigint(20) primary key, c2 varchar(20))") + tk.MustExec("insert into t2 values(1,'7777')") + tk.MustExec("prepare s2 from 'select * from t2 where c1>=? and c1<=?'") + tk.MustExec("set @a2=0, @b2=9") + // TableReader plan would be built, we should cache it. + tk.MustQuery("execute s2 using @a2, @a2").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + tk.MustQuery("execute s2 using @a2, @b2").Check(testkit.Rows("1 7777")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + + tk.MustExec("create table t3(c1 int, c2 int, c3 int, unique key(c1), key(c2))") + tk.MustExec("insert into t3 values(2,1,1)") + tk.MustExec("prepare s3 from 'select /*+ use_index_merge(t3) */ * from t3 where (c1 >= ? and c1 <= ?) or c2 > 1'") + tk.MustExec("set @a3=1,@b3=3") + // TableReader plan would be built, we should cache it. + tk.MustQuery("execute s3 using @a3,@a3").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + tk.MustQuery("execute s3 using @a3,@b3").Check(testkit.Rows("2 1 1")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + + tk.MustExec("prepare s3 from 'select /*+ use_index_merge(t3) */ * from t3 where (c1 >= ? and c1 <= ?) or c2 > 1'") + tk.MustExec("set @a3=1,@b3=3") + // TableReader plan would be built, we should cache it. + tk.MustQuery("execute s3 using @b3,@a3").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + tk.MustQuery("execute s3 using @a3,@b3").Check(testkit.Rows("2 1 1")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + + tk.MustExec("create table t4(c1 int primary key, c2 int, c3 int, key(c2))") + tk.MustExec("insert into t4 values(2,1,1)") + tk.MustExec("prepare s4 from 'select /*+ use_index_merge(t4) */ * from t4 where (c1 >= ? and c1 <= ?) or c2 > 1'") + tk.MustExec("set @a4=1,@b4=3") + tk.MustQuery("execute s4 using @a4,@a4").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + tk.MustQuery("execute s4 using @a4,@b4").Check(testkit.Rows("2 1 1")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + + tk.MustExec("prepare s4 from 'select /*+ use_index_merge(t4) */ * from t4 where (c1 >= ? and c1 <= ?) or c2 > 1'") + tk.MustExec("set @a4=1,@b4=3") + tk.MustQuery("execute s4 using @b4,@a4").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + tk.MustQuery("execute s4 using @a4,@b4").Check(testkit.Rows("2 1 1")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) +} + +func TestIssue26873(t *testing.T) { + store, clean := testkit.CreateMockStore(t) + defer clean() + orgEnable := core.PreparedPlanCacheEnabled() + defer core.SetPreparedPlanCache(orgEnable) + core.SetPreparedPlanCache(true) + se, err := session.CreateSession4TestWithOpt(store, &session.Opt{ + PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64), + }) + require.NoError(t, err) + tk := testkit.NewTestKitWithSession(t, store, se) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + + tk.MustExec("create table t(a int primary key, b int, c int)") + tk.MustExec("prepare stmt from 'select * from t where a = 2 or a = ?'") + tk.MustExec("set @p = 3") + tk.MustQuery("execute stmt using @p").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + tk.MustQuery("execute stmt using @p").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) +} + +func TestIssue29511(t *testing.T) { + store, clean := testkit.CreateMockStore(t) + defer clean() + orgEnable := core.PreparedPlanCacheEnabled() + defer core.SetPreparedPlanCache(orgEnable) + core.SetPreparedPlanCache(true) + se, err := session.CreateSession4TestWithOpt(store, &session.Opt{ + PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64), + }) + require.NoError(t, err) + tk := testkit.NewTestKitWithSession(t, store, se) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + + tk.MustExec("CREATE TABLE `t` (`COL1` bigint(20) DEFAULT NULL COMMENT 'WITH DEFAULT', UNIQUE KEY `UK_COL1` (`COL1`))") + tk.MustExec("insert into t values(-3865356285544170443),(9223372036854775807);") + tk.MustExec("prepare stmt from 'select/*+ hash_agg() */ max(col1) from t where col1 = ? and col1 > ?;';") + tk.MustExec("set @a=-3865356285544170443, @b=-4055949188488870713;") + tk.MustQuery("execute stmt using @a,@b;").Check(testkit.Rows("-3865356285544170443")) +} + +func TestIssue23671(t *testing.T) { + store, clean := testkit.CreateMockStore(t) + defer clean() + orgEnable := core.PreparedPlanCacheEnabled() + defer core.SetPreparedPlanCache(orgEnable) + core.SetPreparedPlanCache(true) + se, err := session.CreateSession4TestWithOpt(store, &session.Opt{ + PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64), + }) + require.NoError(t, err) + tk := testkit.NewTestKitWithSession(t, store, se) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + + tk.MustExec("create table t (a int, b int, index ab(a, b))") + tk.MustExec("insert into t values (1, 1), (2, 2)") + tk.MustExec("prepare s1 from 'select * from t use index(ab) where a>=? and b>=? and b<=?'") + tk.MustExec("set @a=1, @b=1, @c=1") + tk.MustQuery("execute s1 using @a, @b, @c").Check(testkit.Rows("1 1")) + tk.MustExec("set @a=1, @b=1, @c=10") + tk.MustQuery("execute s1 using @a, @b, @c").Check(testkit.Rows("1 1", "2 2")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) +} + +func TestIssue29296(t *testing.T) { + store, clean := testkit.CreateMockStore(t) + defer clean() + orgEnable := core.PreparedPlanCacheEnabled() + defer core.SetPreparedPlanCache(orgEnable) + core.SetPreparedPlanCache(true) + se, err := session.CreateSession4TestWithOpt(store, &session.Opt{ + PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64), + }) + require.NoError(t, err) + tk := testkit.NewTestKitWithSession(t, store, se) + + tk.MustExec(`use test`) + tk.MustExec(`drop table if exists UK_MU14722`) + tk.MustExec(`CREATE TABLE UK_MU14722 ( + COL1 tinytext DEFAULT NULL, + COL2 tinyint(16) DEFAULT NULL, + COL3 datetime DEFAULT NULL, + COL4 int(11) DEFAULT NULL, + UNIQUE KEY U_M_COL (COL1(10)), + UNIQUE KEY U_M_COL2 (COL2), + UNIQUE KEY U_M_COL3 (COL3))`) + tk.MustExec(`insert into UK_MU14722 values("輮睅麤敜溺她晁瀪襄頮鹛涓誗钷廔筪惌嶙鎢塴", -121, "3383-02-19 07:58:28" , -639457963), + ("偧孇鱓鼂瘠钻篝醗時鷷聽箌磇砀玸眞扦鸇祈灇", 127, "7902-03-05 08:54:04", -1094128660), + ("浀玡慃淛漉围甧鴎史嬙砊齄w章炢忲噑硓哈樘", -127, "5813-04-16 03:07:20", -333397107), + ("鑝粼啎鸼贖桖弦簼赭蠅鏪鐥蕿捐榥疗耹岜鬓槊", -117, "7753-11-24 10:14:24", 654872077)`) + tk.MustExec(`prepare stmt from 'SELECT * FROM UK_MU14722 WHERE col2 > ? OR col2 BETWEEN ? AND ? ORDER BY COL2 + ? LIMIT 3'`) + tk.MustExec(`set @a=30410, @b=3937, @c=22045, @d=-4374`) + tk.MustQuery(`execute stmt using @a,@b,@c,@d`).Check(testkit.Rows()) + tk.MustExec(`set @a=127, @b=127, @c=127, @d=127`) + tk.MustQuery(`execute stmt using @a,@b,@c,@d`).Check(testkit.Rows(`偧孇鱓鼂瘠钻篝醗時鷷聽箌磇砀玸眞扦鸇祈灇 127 7902-03-05 08:54:04 -1094128660`)) +} + +func TestIssue28246(t *testing.T) { + store, clean := testkit.CreateMockStore(t) + defer clean() + orgEnable := core.PreparedPlanCacheEnabled() + defer core.SetPreparedPlanCache(orgEnable) + core.SetPreparedPlanCache(true) + se, err := session.CreateSession4TestWithOpt(store, &session.Opt{ + PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64), + }) + require.NoError(t, err) + tk := testkit.NewTestKitWithSession(t, store, se) + + tk.MustExec("use test") + tk.MustExec("drop table if exists PK_AUTO_RANDOM9111;") + tk.MustExec("CREATE TABLE `PK_AUTO_RANDOM9111` ( `COL1` bigint(45) NOT NULL , `COL2` varchar(20) DEFAULT NULL, `COL4` datetime DEFAULT NULL, `COL3` bigint(20) DEFAULT NULL, `COL5` float DEFAULT NULL, PRIMARY KEY (`COL1`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;") + tk.MustExec("insert into PK_AUTO_RANDOM9111(col1) values (-9223372036854775808), (9223372036854775807);") + tk.MustExec("set @a=9223372036854775807, @b=1") + tk.MustExec(`prepare stmt from 'select min(col1) from PK_AUTO_RANDOM9111 where col1 > ?;';`) + tk.MustQuery("execute stmt using @a").Check(testkit.Rows("")) + // The plan contains the tableDual, so it will not be cached. + tk.MustQuery("execute stmt using @a").Check(testkit.Rows("")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + tk.MustQuery("execute stmt using @b").Check(testkit.Rows("9223372036854775807")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + tk.MustQuery("execute stmt using @a").Check(testkit.Rows("")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) +} + +func TestIssue29805(t *testing.T) { + store, clean := testkit.CreateMockStore(t) + defer clean() + orgEnable := core.PreparedPlanCacheEnabled() + defer core.SetPreparedPlanCache(orgEnable) + core.SetPreparedPlanCache(true) + se, err := session.CreateSession4TestWithOpt(store, &session.Opt{ + PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64), + }) + require.NoError(t, err) + tk := testkit.NewTestKitWithSession(t, store, se) + + tk.MustExec("use test") + tk.MustExec("set tidb_enable_clustered_index=on;") + tk.MustExec("drop table if exists PK_TCOLLATION10197;") + tk.MustExec("CREATE TABLE `PK_TCOLLATION10197` (`COL1` char(1) NOT NULL, PRIMARY KEY (`COL1`(1)) /*T![clustered_index] CLUSTERED */) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;") + tk.MustExec("insert into PK_TCOLLATION10197 values('龺');") + tk.MustExec("set @a='畻', @b='龺';") + tk.MustExec(`prepare stmt from 'select/*+ hash_agg() */ count(distinct col1) from PK_TCOLLATION10197 where col1 > ?;';`) + tk.MustQuery("execute stmt using @a").Check(testkit.Rows("1")) + tk.MustQuery("execute stmt using @b").Check(testkit.Rows("0")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + + tk.MustExec(`prepare stmt from 'select/*+ hash_agg() */ count(distinct col1) from PK_TCOLLATION10197 where col1 > ?;';`) + tk.MustQuery("execute stmt using @b").Check(testkit.Rows("0")) + + tk.MustQuery("select/*+ hash_agg() */ count(distinct col1) from PK_TCOLLATION10197 where col1 > '龺';").Check(testkit.Rows("0")) +} + +func TestIssue29993(t *testing.T) { + store, clean := testkit.CreateMockStore(t) + defer clean() + orgEnable := core.PreparedPlanCacheEnabled() + defer core.SetPreparedPlanCache(orgEnable) + core.SetPreparedPlanCache(true) + se, err := session.CreateSession4TestWithOpt(store, &session.Opt{ + PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64), + }) + require.NoError(t, err) + tk := testkit.NewTestKitWithSession(t, store, se) + + tk.MustExec("use test") + + // test PointGet + cluster index + tk.MustExec("set tidb_enable_clustered_index=on;") + tk.MustExec("drop table if exists t;") + tk.MustExec("CREATE TABLE `t` (`COL1` enum('a', 'b') NOT NULL PRIMARY KEY, col2 int) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;") + tk.MustExec("insert into t values('a', 1), ('b', 2);") + tk.MustExec("set @a='a', @b='b', @z='z';") + tk.MustExec(`prepare stmt from 'select col1 from t where col1 = ? and col2 in (1, 2);';`) + tk.MustQuery("execute stmt using @a").Check(testkit.Rows("a")) + tk.MustQuery("execute stmt using @b").Check(testkit.Rows("b")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + tk.MustQuery("execute stmt using @z").Check(testkit.Rows()) + // The length of range have been changed, so the plan can not be cached. + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + tk.MustQuery("execute stmt using @z").Check(testkit.Rows()) + + // test batchPointGet + cluster index + tk.MustExec("drop table if exists t;") + tk.MustExec("CREATE TABLE `t` (`COL1` enum('a', 'b') NOT NULL, col2 int, PRIMARY KEY(col1, col2)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;") + tk.MustExec("insert into t values('a', 1), ('b', 2);") + tk.MustExec("set @a='a', @b='b', @z='z';") + tk.MustExec(`prepare stmt from 'select col1 from t where (col1, col2) in ((?, 1));';`) + tk.MustQuery("execute stmt using @a").Check(testkit.Rows("a")) + tk.MustQuery("execute stmt using @b").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + tk.MustQuery("execute stmt using @z").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + tk.MustQuery("execute stmt using @z").Check(testkit.Rows()) + + // test PointGet + non cluster index + tk.MustExec("set tidb_enable_clustered_index=off;") + tk.MustExec("drop table if exists t;") + tk.MustExec("CREATE TABLE `t` (`COL1` enum('a', 'b') NOT NULL PRIMARY KEY, col2 int) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;") + tk.MustExec("insert into t values('a', 1), ('b', 2);") + tk.MustExec("set @a='a', @b='b', @z='z';") + tk.MustExec(`prepare stmt from 'select col1 from t where col1 = ? and col2 in (1, 2);';`) + tk.MustQuery("execute stmt using @a").Check(testkit.Rows("a")) + tk.MustQuery("execute stmt using @b").Check(testkit.Rows("b")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + tk.MustQuery("execute stmt using @z").Check(testkit.Rows()) + // The length of range have been changed, so the plan can not be cached. + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + tk.MustQuery("execute stmt using @z").Check(testkit.Rows()) + + // test batchPointGet + non cluster index + tk.MustExec("drop table if exists t;") + tk.MustExec("CREATE TABLE `t` (`COL1` enum('a', 'b') NOT NULL, col2 int, PRIMARY KEY(col1, col2)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;") + tk.MustExec("insert into t values('a', 1), ('b', 2);") + tk.MustExec("set @a='a', @b='b', @z='z';") + tk.MustExec(`prepare stmt from 'select col1 from t where (col1, col2) in ((?, 1));';`) + tk.MustQuery("execute stmt using @a").Check(testkit.Rows("a")) + tk.MustQuery("execute stmt using @b").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + tk.MustQuery("execute stmt using @z").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + tk.MustQuery("execute stmt using @z").Check(testkit.Rows()) +} + +func TestIssue30100(t *testing.T) { + store, clean := testkit.CreateMockStore(t) + defer clean() + orgEnable := core.PreparedPlanCacheEnabled() + defer core.SetPreparedPlanCache(orgEnable) + core.SetPreparedPlanCache(true) + se, err := session.CreateSession4TestWithOpt(store, &session.Opt{ + PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64), + }) + require.NoError(t, err) + tk := testkit.NewTestKitWithSession(t, store, se) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t(col1 enum('aa', 'bb'), col2 int, index(col1, col2));") + tk.MustExec("insert into t values('aa', 333);") + tk.MustExec(`prepare stmt from 'SELECT * FROM t t1 JOIN t t2 ON t1.col1 = t2.col1 WHERE t1.col1 <=> NULL';`) + tk.MustQuery("execute stmt").Check(testkit.Rows()) + tk.MustQuery("execute stmt").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + + tk.MustExec(`prepare stmt from 'SELECT * FROM t t1 JOIN t t2 ON t1.col1 = t2.col1 WHERE t1.col1 <=> NULL and t2.col2 > ?';`) + tk.MustExec("set @a=0;") + tk.MustQuery("execute stmt using @a").Check(testkit.Rows()) + tk.MustQuery("execute stmt using @a").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) +} + +func TestPartitionTable(t *testing.T) { + if israce.RaceEnabled { + t.Skip("exhaustive types test, skip race test") + } + + store, clean := testkit.CreateMockStore(t) + defer clean() + orgEnable := core.PreparedPlanCacheEnabled() + defer core.SetPreparedPlanCache(orgEnable) + core.SetPreparedPlanCache(true) + se, err := session.CreateSession4TestWithOpt(store, &session.Opt{ + PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64), + }) + require.NoError(t, err) + tk := testkit.NewTestKitWithSession(t, store, se) + + // enable partition table dynamic mode + tk.MustExec("create database test_plan_cache") + tk.MustExec("use test_plan_cache") + tk.MustExec("set @@tidb_partition_prune_mode = 'dynamic'") + + type testcase struct { + t1Create string + t2Create string + rowGener func() string + varGener func() string + query string + } + randDateTime := func() string { + return fmt.Sprintf("%v-%v-%v %v:%v:%v", + 1950+rand.Intn(100), 1+rand.Intn(12), 1+rand.Intn(28), // date + rand.Intn(24), rand.Intn(60), rand.Intn(60)) // time + } + randDate := func() string { + return fmt.Sprintf("%v-%v-%v", 1950+rand.Intn(100), 1+rand.Intn(12), 1+rand.Intn(28)) + } + testcases := []testcase{ + { // hash partition + int + "create table t1(a int, b int) partition by hash(a) partitions 20", + "create table t2(a int, b int)", + func() string { return fmt.Sprintf("(%v, %v)", rand.Intn(100000000), rand.Intn(100000000)) }, + func() string { return fmt.Sprintf("%v", rand.Intn(100000000)) }, + `select * from %v where a > ?`, + }, + { // range partition + int + `create table t1(a int, b int) partition by range(a) ( + partition p0 values less than (20000000), + partition p1 values less than (40000000), + partition p2 values less than (60000000), + partition p3 values less than (80000000), + partition p4 values less than (100000000))`, + `create table t2(a int, b int)`, + func() string { return fmt.Sprintf("(%v, %v)", rand.Intn(100000000), rand.Intn(100000000)) }, + func() string { return fmt.Sprintf("%v", rand.Intn(100000000)) }, + `select * from %v where a > ?`, + }, + { // range partition + varchar + `create table t1(a varchar(10), b varchar(10)) partition by range columns(a) ( + partition p0 values less than ('200'), + partition p1 values less than ('400'), + partition p2 values less than ('600'), + partition p3 values less than ('800'), + partition p4 values less than ('9999'))`, + `create table t2(a varchar(10), b varchar(10))`, + func() string { return fmt.Sprintf(`("%v", "%v")`, rand.Intn(1000), rand.Intn(1000)) }, + func() string { return fmt.Sprintf(`"%v"`, rand.Intn(1000)) }, + `select * from %v where a > ?`, + }, + { // range partition + datetime + `create table t1(a datetime, b datetime) partition by range columns(a) ( + partition p0 values less than ('1970-01-01 00:00:00'), + partition p1 values less than ('1990-01-01 00:00:00'), + partition p2 values less than ('2010-01-01 00:00:00'), + partition p3 values less than ('2030-01-01 00:00:00'), + partition p4 values less than ('2060-01-01 00:00:00'))`, + `create table t2(a datetime, b datetime)`, + func() string { return fmt.Sprintf(`("%v", "%v")`, randDateTime(), randDateTime()) }, + func() string { return fmt.Sprintf(`"%v"`, randDateTime()) }, + `select * from %v where a > ?`, + }, + { // range partition + date + `create table t1(a date, b date) partition by range columns(a) ( + partition p0 values less than ('1970-01-01'), + partition p1 values less than ('1990-01-01'), + partition p2 values less than ('2010-01-01'), + partition p3 values less than ('2030-01-01'), + partition p4 values less than ('2060-01-01'))`, + `create table t2(a date, b date)`, + func() string { return fmt.Sprintf(`("%v", "%v")`, randDate(), randDate()) }, + func() string { return fmt.Sprintf(`"%v"`, randDate()) }, + `select * from %v where a > ?`, + }, + { // list partition + int + `create table t1(a int, b int) partition by list(a) ( + partition p0 values in (0, 1, 2, 3, 4), + partition p1 values in (5, 6, 7, 8, 9), + partition p2 values in (10, 11, 12, 13, 14), + partition p3 values in (15, 16, 17, 18, 19))`, + `create table t2(a int, b int)`, + func() string { return fmt.Sprintf("(%v, %v)", rand.Intn(20), rand.Intn(20)) }, + func() string { return fmt.Sprintf("%v", rand.Intn(20)) }, + `select * from %v where a > ?`, + }, + } + for _, tc := range testcases { + // create tables and insert some records + tk.MustExec("drop table if exists t1") + tk.MustExec("drop table if exists t2") + tk.MustExec(tc.t1Create) + tk.MustExec(tc.t2Create) + vals := make([]string, 0, 2048) + for i := 0; i < 2048; i++ { + vals = append(vals, tc.rowGener()) + } + tk.MustExec(fmt.Sprintf("insert into t1 values %s", strings.Join(vals, ","))) + tk.MustExec(fmt.Sprintf("insert into t2 values %s", strings.Join(vals, ","))) + + // the first query, @last_plan_from_cache should be zero + tk.MustExec(fmt.Sprintf(`prepare stmt1 from "%s"`, fmt.Sprintf(tc.query, "t1"))) + tk.MustExec(fmt.Sprintf(`prepare stmt2 from "%s"`, fmt.Sprintf(tc.query, "t2"))) + tk.MustExec(fmt.Sprintf("set @a=%v", tc.varGener())) + result1 := tk.MustQuery("execute stmt1 using @a").Sort().Rows() + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + tk.MustQuery("execute stmt2 using @a").Sort().Check(result1) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + + for i := 0; i < 100; i++ { + tk.MustExec(fmt.Sprintf("set @a=%v", tc.varGener())) + result1 := tk.MustQuery("execute stmt1 using @a").Sort().Rows() + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + tk.MustQuery("execute stmt2 using @a").Sort().Check(result1) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + } + } +} + +func TestPartitionWithVariedDataSources(t *testing.T) { + if israce.RaceEnabled { + t.Skip("exhaustive types test, skip race test") + } + + store, clean := testkit.CreateMockStore(t) + defer clean() + orgEnable := core.PreparedPlanCacheEnabled() + defer core.SetPreparedPlanCache(orgEnable) + core.SetPreparedPlanCache(true) + se, err := session.CreateSession4TestWithOpt(store, &session.Opt{ + PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64), + }) + require.NoError(t, err) + tk := testkit.NewTestKitWithSession(t, store, se) + + // enable partition table dynamic mode + tk.MustExec("create database test_plan_cache2") + tk.MustExec("use test_plan_cache2") + tk.MustExec("set @@tidb_partition_prune_mode = 'dynamic'") + + // prepare tables + tk.MustExec(`create table trangePK (a int primary key, b int) partition by range (a) ( + partition p0 values less than (10000), + partition p1 values less than (20000), + partition p2 values less than (30000), + partition p3 values less than (40000))`) + tk.MustExec(`create table thashPK (a int primary key, b int) partition by hash (a) partitions 4`) + tk.MustExec(`create table tnormalPK (a int primary key, b int)`) + tk.MustExec(`create table trangeIdx (a int unique key, b int) partition by range (a) ( + partition p0 values less than (10000), + partition p1 values less than (20000), + partition p2 values less than (30000), + partition p3 values less than (40000))`) + tk.MustExec(`create table thashIdx (a int unique key, b int) partition by hash (a) partitions 4`) + tk.MustExec(`create table tnormalIdx (a int unique key, b int)`) + uniqueVals := make(map[int]struct{}) + vals := make([]string, 0, 1000) + for len(vals) < 1000 { + a := rand.Intn(40000) + if _, ok := uniqueVals[a]; ok { + continue + } + uniqueVals[a] = struct{}{} + b := rand.Intn(40000) + vals = append(vals, fmt.Sprintf("(%v, %v)", a, b)) + } + for _, tbl := range []string{"trangePK", "thashPK", "tnormalPK", "trangeIdx", "thashIdx", "tnormalIdx"} { + tk.MustExec(fmt.Sprintf(`insert into %v values %v`, tbl, strings.Join(vals, ", "))) + } + + // TableReader, PointGet on PK, BatchGet on PK + for _, tbl := range []string{`trangePK`, `thashPK`, `tnormalPK`} { + tk.MustExec(fmt.Sprintf(`prepare stmt%v_tablescan from 'select * from %v use index(primary) where a > ? and a < ?'`, tbl, tbl)) + tk.MustExec(fmt.Sprintf(`prepare stmt%v_pointget from 'select * from %v use index(primary) where a = ?'`, tbl, tbl)) + tk.MustExec(fmt.Sprintf(`prepare stmt%v_batchget from 'select * from %v use index(primary) where a in (?, ?, ?)'`, tbl, tbl)) + } + for i := 0; i < 100; i++ { + mina, maxa := rand.Intn(40000), rand.Intn(40000) + if mina > maxa { + mina, maxa = maxa, mina + } + tk.MustExec(fmt.Sprintf(`set @mina=%v, @maxa=%v`, mina, maxa)) + tk.MustExec(fmt.Sprintf(`set @pointa=%v`, rand.Intn(40000))) + tk.MustExec(fmt.Sprintf(`set @a0=%v, @a1=%v, @a2=%v`, rand.Intn(40000), rand.Intn(40000), rand.Intn(40000))) + + var rscan, rpoint, rbatch [][]interface{} + for id, tbl := range []string{`trangePK`, `thashPK`, `tnormalPK`} { + scan := tk.MustQuery(fmt.Sprintf(`execute stmt%v_tablescan using @mina, @maxa`, tbl)).Sort() + if id == 0 { + rscan = scan.Rows() + } else { + scan.Check(rscan) + } + + point := tk.MustQuery(fmt.Sprintf(`execute stmt%v_pointget using @pointa`, tbl)).Sort() + if id == 0 { + rpoint = point.Rows() + } else { + point.Check(rpoint) + } + + batch := tk.MustQuery(fmt.Sprintf(`execute stmt%v_batchget using @a0, @a1, @a2`, tbl)).Sort() + if id == 0 { + rbatch = batch.Rows() + } else { + batch.Check(rbatch) + } + } + } + + // IndexReader, IndexLookUp, PointGet on Idx, BatchGet on Idx + for _, tbl := range []string{"trangeIdx", "thashIdx", "tnormalIdx"} { + tk.MustExec(fmt.Sprintf(`prepare stmt%v_indexscan from 'select a from %v use index(a) where a > ? and a < ?'`, tbl, tbl)) + tk.MustExec(fmt.Sprintf(`prepare stmt%v_indexlookup from 'select * from %v use index(a) where a > ? and a < ?'`, tbl, tbl)) + tk.MustExec(fmt.Sprintf(`prepare stmt%v_pointget_idx from 'select * from %v use index(a) where a = ?'`, tbl, tbl)) + tk.MustExec(fmt.Sprintf(`prepare stmt%v_batchget_idx from 'select * from %v use index(a) where a in (?, ?, ?)'`, tbl, tbl)) + } + for i := 0; i < 100; i++ { + mina, maxa := rand.Intn(40000), rand.Intn(40000) + if mina > maxa { + mina, maxa = maxa, mina + } + tk.MustExec(fmt.Sprintf(`set @mina=%v, @maxa=%v`, mina, maxa)) + tk.MustExec(fmt.Sprintf(`set @pointa=%v`, rand.Intn(40000))) + tk.MustExec(fmt.Sprintf(`set @a0=%v, @a1=%v, @a2=%v`, rand.Intn(40000), rand.Intn(40000), rand.Intn(40000))) + + var rscan, rlookup, rpoint, rbatch [][]interface{} + for id, tbl := range []string{"trangeIdx", "thashIdx", "tnormalIdx"} { + scan := tk.MustQuery(fmt.Sprintf(`execute stmt%v_indexscan using @mina, @maxa`, tbl)).Sort() + if i > 0 { + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1")) + } + if id == 0 { + rscan = scan.Rows() + } else { + scan.Check(rscan) + } + + lookup := tk.MustQuery(fmt.Sprintf(`execute stmt%v_indexlookup using @mina, @maxa`, tbl)).Sort() + if i > 0 { + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1")) + } + if id == 0 { + rlookup = lookup.Rows() + } else { + lookup.Check(rlookup) + } + + point := tk.MustQuery(fmt.Sprintf(`execute stmt%v_pointget_idx using @pointa`, tbl)).Sort() + if tbl == `tnormalPK` && i > 0 { + // PlanCache cannot support PointGet now since we haven't relocated partition after rebuilding range. + // Please see Execute.rebuildRange for more details. + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0")) + } + if id == 0 { + rpoint = point.Rows() + } else { + point.Check(rpoint) + } + + batch := tk.MustQuery(fmt.Sprintf(`execute stmt%v_batchget_idx using @a0, @a1, @a2`, tbl)).Sort() + if i > 0 { + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1")) + } + if id == 0 { + rbatch = batch.Rows() + } else { + batch.Check(rbatch) + } + } + } +} + +func TestCachedTable(t *testing.T) { + store, clean := testkit.CreateMockStore(t) + defer clean() + orgEnable := core.PreparedPlanCacheEnabled() + defer core.SetPreparedPlanCache(orgEnable) + core.SetPreparedPlanCache(true) + se, err := session.CreateSession4TestWithOpt(store, &session.Opt{ + PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64), + }) + require.NoError(t, err) + tk := testkit.NewTestKitWithSession(t, store, se) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + + tk.MustExec("create table t (a int, b int, index i_b(b))") + tk.MustExec("insert into t values (1, 1), (2, 2)") + tk.MustExec("alter table t cache") + + tk.MustExec("prepare tableScan from 'select * from t where a>=?'") + tk.MustExec("prepare indexScan from 'select b from t use index(i_b) where b>?'") + tk.MustExec("prepare indexLookup from 'select a from t use index(i_b) where b>? and b>>>>>> 1b04c3b05... planner: fix wrong range calculation for Nulleq function on Enum values (#32440) diff --git a/util/ranger/points.go b/util/ranger/points.go index 6475a8be23336..deccfe41f0cad 100644 --- a/util/ranger/points.go +++ b/util/ranger/points.go @@ -335,7 +335,108 @@ func handleUnsignedCol(ft *types.FieldType, val types.Datum, op string) (types.D return val, op, false } +<<<<<<< HEAD func (r *builder) buildFromIsTrue(expr *expression.ScalarFunction, isNot int, keepNull bool) []point { +======= +// handleBoundCol handles the case when column meets overflow value. +// The three returned values are: fixed constant value, fixed operator, and a boolean +// which indicates whether the range is valid or not. +func handleBoundCol(ft *types.FieldType, val types.Datum, op string) (types.Datum, string, bool) { + isUnsigned := mysql.HasUnsignedFlag(ft.Flag) + isNegative := val.Kind() == types.KindInt64 && val.GetInt64() < 0 + if isUnsigned { + return val, op, true + } + + switch ft.Tp { + case mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong: + if !isNegative && val.GetUint64() > math.MaxInt64 { + switch op { + case ast.GT, ast.GE: + return val, op, false + case ast.NE, ast.LE, ast.LT: + op = ast.LE + val = types.NewIntDatum(math.MaxInt64) + } + } + case mysql.TypeFloat: + if val.GetFloat64() > math.MaxFloat32 { + switch op { + case ast.GT, ast.GE: + return val, op, false + case ast.NE, ast.LE, ast.LT: + op = ast.LE + val = types.NewFloat32Datum(math.MaxFloat32) + } + } else if val.GetFloat64() < -math.MaxFloat32 { + switch op { + case ast.LE, ast.LT: + return val, op, false + case ast.GT, ast.GE, ast.NE: + op = ast.GE + val = types.NewFloat32Datum(-math.MaxFloat32) + } + } + } + + return val, op, true +} + +func handleEnumFromBinOp(sc *stmtctx.StatementContext, ft *types.FieldType, val types.Datum, op string) []*point { + res := make([]*point, 0, len(ft.Elems)*2) + appendPointFunc := func(d types.Datum) { + res = append(res, &point{value: d, excl: false, start: true}) + res = append(res, &point{value: d, excl: false, start: false}) + } + + if op == ast.NullEQ && val.IsNull() { + res = append(res, &point{start: true}, &point{}) // null point + } + + tmpEnum := types.Enum{} + for i := 0; i <= len(ft.Elems); i++ { + if i == 0 { + tmpEnum = types.Enum{} + } else { + tmpEnum.Name = ft.Elems[i-1] + tmpEnum.Value = uint64(i) + } + + d := types.NewCollateMysqlEnumDatum(tmpEnum, ft.Collate) + if v, err := d.Compare(sc, &val, collate.GetCollator(ft.Collate)); err == nil { + switch op { + case ast.LT: + if v < 0 { + appendPointFunc(d) + } + case ast.LE: + if v <= 0 { + appendPointFunc(d) + } + case ast.GT: + if v > 0 { + appendPointFunc(d) + } + case ast.GE: + if v >= 0 { + appendPointFunc(d) + } + case ast.EQ, ast.NullEQ: + if v == 0 { + appendPointFunc(d) + } + case ast.NE: + if v != 0 { + appendPointFunc(d) + } + } + } + } + return res +} + +func (r *builder) buildFromIsTrue(expr *expression.ScalarFunction, isNot int, keepNull bool) []*point { +>>>>>>> 1b04c3b05... planner: fix wrong range calculation for Nulleq function on Enum values (#32440) if isNot == 1 { if keepNull { // Range is {[0, 0]}