Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions pkg/planner/core/casetest/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,15 +452,15 @@ func TestIssue52023(t *testing.T) {
tk.MustQuery(`select * from t where a IN (0x5,55)`).Check(testkit.Rows("\u0005"))
tk.MustQuery(`explain select * from t where a = 0x5`).Check(testkit.Rows("Point_Get_1 1.00 root table:t, partition:P4, clustered index:PRIMARY(a) "))
tk.MustQuery(`explain format='brief' select * from t where a = 5`).Check(testkit.Rows(""+
"TableReader 0.80 root partition:all data:Selection",
"TableReader 0.80 root partition:P4 data:Selection",
"└─Selection 0.80 cop[tikv] eq(cast(test.t.a, double BINARY), 5)",
" └─TableFullScan 1.00 cop[tikv] table:t keep order:false"))
tk.MustQuery(`explain format='brief' select * from t where a IN (5,55)`).Check(testkit.Rows(""+
"TableReader 0.96 root partition:all data:Selection",
"TableReader 0.96 root partition:P4 data:Selection",
"└─Selection 0.96 cop[tikv] or(eq(cast(test.t.a, double BINARY), 5), eq(cast(test.t.a, double BINARY), 55))",
" └─TableFullScan 1.00 cop[tikv] table:t keep order:false"))
tk.MustQuery(`explain format='brief' select * from t where a IN (0x5,55)`).Check(testkit.Rows(""+
"TableReader 1.00 root partition:all data:Selection",
"TableReader 1.00 root partition:P4 data:Selection",
"└─Selection 1.00 cop[tikv] or(eq(test.t.a, \"0x05\"), eq(cast(test.t.a, double BINARY), 55))",
" └─TableFullScan 1.00 cop[tikv] table:t keep order:false"))
}
Expand Down
213 changes: 213 additions & 0 deletions pkg/planner/core/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,219 @@ func TestPartitionPruningForEQ(t *testing.T) {
require.Equal(t, 0, res[0])
}

func TestCast4PartitionPruning(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)

tk.MustExec("use test")
tk.MustExec(`drop table if exists t`)
tk.MustExec(`drop table if exists t_ts`)
tk.MustExec(`drop table if exists t_hash`)
tk.MustExec(`drop table if exists t_range_col`)
tk.MustExec("drop table if exists t_range_col_v2")

tk.MustExec(`create table t(a int, b int, c int) partition by range(a) (
partition p1 values less than (100),
partition p2 values less than (200),
partition pm values less than (MAXVALUE));`)
// case 1: range partition
// 1.1.1 test between castIntAsReal(int) and real
tk.MustQuery(`explain select * from t where a between "123" and "199";`).Check(
testkit.Rows("TableReader_7 8000.00 root partition:p2 data:Selection_6",
"└─Selection_6 8000.00 cop[tikv] ge(cast(test.t.a, double BINARY), 123), le(cast(test.t.a, double BINARY), 199)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"))
// MySQL explain:
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| 1 | SIMPLE | t | p2 | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where |
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

// 1.1.2 test between castIntAsReal(int) and real
tk.MustQuery(`explain select * from t where a between "123.12" and "199.99";`).Check(
testkit.Rows("TableReader_7 8000.00 root partition:p2 data:Selection_6",
"└─Selection_6 8000.00 cop[tikv] ge(cast(test.t.a, double BINARY), 123.12), le(cast(test.t.a, double BINARY), 199.99)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"))
// MySQL explain:
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| 1 | SIMPLE | t | p2 | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where |
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

// 1.1.3 test between castIntAsReal(int) and real
tk.MustQuery(`explain select * from t where a between "ddd" and "99";`).Check(
testkit.Rows("TableReader_7 8000.00 root partition:p1 data:Selection_6",
"└─Selection_6 8000.00 cop[tikv] ge(cast(test.t.a, double BINARY), 0), le(cast(test.t.a, double BINARY), 99)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"))
// MySQL explain:
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| 1 | SIMPLE | t | p1 | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where |
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

// 1.1.4 test between castIntAsReal(int) and real
tk.MustQuery(`explain select * from t where a between "123.12" and cast("199.99" as decimal);`).Check(
testkit.Rows("TableReader_7 8000.00 root partition:p2,pm data:Selection_6",
"└─Selection_6 8000.00 cop[tikv] ge(cast(test.t.a, double BINARY), 123.12), le(cast(test.t.a, double BINARY), 200)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"))
// MySQL explain:
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| 1 | SIMPLE | t | p2,pm | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where |
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

// 1.2.1 test between castIntAsDecimal(int) and decimal
tk.MustQuery(`explain select * from t where a between 123.12 and 199.99;`).Check(
testkit.Rows("TableReader_7 8000.00 root partition:p2 data:Selection_6",
"└─Selection_6 8000.00 cop[tikv] ge(cast(test.t.a, decimal(10,0) BINARY), 123.12), le(cast(test.t.a, decimal(10,0) BINARY), 199.99)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"))
// MySQL explain:
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| 1 | SIMPLE | t | p2 | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where |
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

// case 2: range partition, but not support expression
tk.MustExec(`create table t_ts (report_updated timestamp) partition by range(unix_timestamp(report_updated)) (
partition p1 values less than (1732982400), -- 2024-12-01 00:00:00
partition p2 values less than (1733068800), -- 2024-12-02 00:00:00
partition pm values less than (MAXVALUE));`)
tk.MustExec("insert into t_ts values('2024-11-30 00:00:00'), ('2024-12-01 00:00:00'), ('2024-12-02 00:00:00')")
tk.MustQuery("select * from t_ts where report_updated = '2024-12-01 00:00:00'").Check(testkit.Rows("2024-12-01 00:00:00"))
tk.MustQuery("explain select * from t_ts where report_updated = 20241201").Check(testkit.Rows(
"TableReader_7 10.00 root partition:p2 data:Selection_6",
"└─Selection_6 10.00 cop[tikv] eq(test.t_ts.report_updated, 2024-12-01 00:00:00)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t_ts keep order:false, stats:pseudo"))
tk.MustQuery("explain select * from t_ts where report_updated = '2024-12-01 00:00:00'").Check(testkit.Rows(
"TableReader_7 10.00 root partition:p2 data:Selection_6",
"└─Selection_6 10.00 cop[tikv] eq(test.t_ts.report_updated, 2024-12-01 00:00:00.000000)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t_ts keep order:false, stats:pseudo"))
rs := tk.MustQuery("explain select * from t_ts where report_updated > unix_timestamp('2008-05-01 00:00:00')").Rows()
require.Equal(t, rs[0][3], "partition:all")
//MysQL explain:
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| 1 | SIMPLE | t_ts | p1,p2,pm | ALL | NULL | NULL | NULL | NULL | 3 | 33.33 | Using where |
//+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

// case 3: hash partition
tk.MustExec(`CREATE TABLE t_hash(a int, b int) PARTITION BY HASH(a) PARTITIONS 6`)
tk.MustExec(`insert into t_hash values(1, 1), (10, 10), (26, 26)`)
tk.MustQuery(`select * from t_hash where a = '1'`).Check(testkit.Rows("1 1"))
tk.MustQuery(`explain select * from t_hash where a = '1'`).Check(testkit.Rows(
"TableReader_7 10.00 root partition:p1 data:Selection_6",
"└─Selection_6 10.00 cop[tikv] eq(test.t_hash.a, 1)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t_hash keep order:false, stats:pseudo"))
// MySQL explain:
//+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
//+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| 1 | SIMPLE | t_hash | p1 | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where |
//+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+

// case 4: range columns partition
tk.MustExec(`CREATE TABLE t_range_col(a int, b int)
PARTITION BY RANGE COLUMNS(a) (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use a different datatype if testing COLUMNS partitioning, since that is the main usage (apart from partitioning on multiple columns, which is not as useful).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will complete the task,thanks for your advice!

PARTITION p_100 VALUES LESS THAN (100),
PARTITION p_200 VALUES LESS THAN (200),
PARTITION p_300 VALUES LESS THAN (300),
PARTITION p_max VALUES LESS THAN MAXVALUE
);`)
tk.MustExec(`insert into t_range_col values(1, 1), (100, 100), (200, 200);`)
// 4.1.1 test between castIntAsReal(int) and real
tk.MustQuery(`select * from t_range_col where a between '100' and '199';`).Check(testkit.Rows("100 100"))
tk.MustQuery(`explain select * from t_range_col where a between '100' and '199'`).Check(testkit.Rows(
"TableReader_7 8000.00 root partition:p_200 data:Selection_6",
"└─Selection_6 8000.00 cop[tikv] ge(cast(test.t_range_col.a, double BINARY), 100), le(cast(test.t_range_col.a, double BINARY), 199)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t_range_col keep order:false, stats:pseudo"))
// MySQL explain:
//+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
//+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| 1 | SIMPLE | t_range_col | p_200 | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where |
//+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+

// 4.1.2 test between castIntAsReal(int) and real
tk.MustQuery(`select * from t_range_col where a between "ddd" and "199";`).Sort().Check(testkit.Rows("1 1", "100 100"))
tk.MustQuery(`explain select * from t where a between "ddd" and "199";`).Check(testkit.Rows(
"TableReader_7 8000.00 root partition:p1,p2 data:Selection_6",
"└─Selection_6 8000.00 cop[tikv] ge(cast(test.t.a, double BINARY), 0), le(cast(test.t.a, double BINARY), 199)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"))
// MySQL explain:
//+----+-------------+-------------+-------------+------+---------------+------+---------+------+------+----------+-------------+
//| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
//+----+-------------+-------------+-------------+------+---------------+------+---------+------+------+----------+-------------+
//| 1 | SIMPLE | t_range_col | p_100,p_200 | ALL | NULL | NULL | NULL | NULL | 2 | 50.00 | Using where |
//+----+-------------+-------------+-------------+------+---------------+------+---------+------+------+----------+-------------+

// 4.1.3 test between castIntAsReal(int) and real
tk.MustQuery(`select * from t_range_col where a between "23.12" and "199.99";`).Check(testkit.Rows("100 100"))
tk.MustQuery(`explain select * from t_range_col where a between "23.12" and "199.99";`).Check(
testkit.Rows("TableReader_7 8000.00 root partition:p_100,p_200 data:Selection_6",
"└─Selection_6 8000.00 cop[tikv] ge(cast(test.t_range_col.a, double BINARY), 23.12), le(cast(test.t_range_col.a, double BINARY), 199.99)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t_range_col keep order:false, stats:pseudo"))
// MySQL explain:
//+----+-------------+-------------+-------------+------+---------------+------+---------+------+------+----------+-------------+
//| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
//+----+-------------+-------------+-------------+------+---------------+------+---------+------+------+----------+-------------+
//| 1 | SIMPLE | t_range_col | p_100,p_200 | ALL | NULL | NULL | NULL | NULL | 2 | 50.00 | Using where |
//+----+-------------+-------------+-------------+------+---------------+------+---------+------+------+----------+-------------+

// 4.1.4 test between castIntAsReal(int) and real
tk.MustQuery(`select * from t_range_col where a between "23.12" and cast("199.99" as decimal);`).Sort().Check(testkit.Rows("100 100", "200 200"))
tk.MustQuery(`explain select * from t where a between "23.12" and cast("199.99" as decimal);`).Check(
testkit.Rows("TableReader_7 8000.00 root partition:all data:Selection_6",
"└─Selection_6 8000.00 cop[tikv] ge(cast(test.t.a, double BINARY), 23.12), le(cast(test.t.a, double BINARY), 200)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"))
// MySQL explain:
//+----+-------------+-------------+-------------------+------+---------------+------+---------+------+------+----------+-------------+
//| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
//+----+-------------+-------------+-------------------+------+---------------+------+---------+------+------+----------+-------------+
//| 1 | SIMPLE | t_range_col | p_100,p_200,p_300 | ALL | NULL | NULL | NULL | NULL | 3 | 33.33 | Using where |
//+----+-------------+-------------+-------------------+------+---------------+------+---------+------+------+----------+-------------+

// 4.2.1 test between castIntAsDecimal(int) and decimal
tk.MustQuery(`select * from t_range_col where a between 100.00 and 199.99;`).Check(testkit.Rows("100 100"))
tk.MustQuery(`explain select * from t_range_col where a between 100.00 and 199.99`).Check(testkit.Rows(
"TableReader_7 8000.00 root partition:p_200 data:Selection_6",
"└─Selection_6 8000.00 cop[tikv] ge(cast(test.t_range_col.a, decimal(10,0) BINARY), 100.00), le(cast(test.t_range_col.a, decimal(10,0) BINARY), 199.99)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t_range_col keep order:false, stats:pseudo"))
// MySQL explain:
//+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
//+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| 1 | SIMPLE | t_range_col | p_200 | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where |
//+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+

// case 5: test range column partition, and partition key is non-numeric type
tk.MustExec(`CREATE TABLE t_range_col_v2(a varchar(12), b int)
PARTITION BY RANGE COLUMNS(a) (
PARTITION p_111 VALUES LESS THAN ('111'),
PARTITION p_555 VALUES LESS THAN ('555'),
PARTITION p_999 VALUES LESS THAN ('999'),
PARTITION p_max VALUES LESS THAN MAXVALUE
);`)
tk.MustExec(`insert into t_range_col_v2 values('111', 1), ('222', 1), ('333', 1), ('444', 1), ('555', 1), ('666', 1), ('777', 1);`)
tk.MustQuery(`select * from t_range_col_v2 where a between 111 and 444;`).Sort().Check(testkit.Rows(
"111 1", "222 1", "333 1", "444 1"))
// all partitions are visited, because `a` col's collation is utf8mb4_bin, while constant's collation is binary.
tk.MustQuery(`explain select * from t_range_col_v2 where a between 111 and 444;`).Check(testkit.Rows(
"TableReader_7 8000.00 root partition:all data:Selection_6",
"└─Selection_6 8000.00 cop[tikv] ge(cast(test.t_range_col_v2.a, double BINARY), 111), le(cast(test.t_range_col_v2.a, double BINARY), 444)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t_range_col_v2 keep order:false, stats:pseudo"))
// MySQL explain:
//+----+-------------+----------------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
//+----+-------------+----------------+------------+------+---------------+------+---------+------+------+----------+-------------+
//| 1 | SIMPLE | t_range_col_v2 | NULL | ALL | NULL | NULL | NULL | NULL | 7 | 14.29 | Using where |
//+----+-------------+----------------+------------+------+---------------+------+---------+------+------+----------+-------------+
}

func TestNotReadOnlySQLOnTiFlash(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
Expand Down
Loading