diff --git a/mysql-test/main/partition_index_scan,desc.rdiff b/mysql-test/main/partition_index_scan,desc.rdiff index 99093b20a3982..b54723f1cb10f 100644 --- a/mysql-test/main/partition_index_scan,desc.rdiff +++ b/mysql-test/main/partition_index_scan,desc.rdiff @@ -287,8 +287,8 @@ show status like 'handler_read_%'; Variable_name Value Handler_read_first 0 --Handler_read_key 6 -+Handler_read_key 7 +-Handler_read_key 8 ++Handler_read_key 11 Handler_read_last 0 Handler_read_next 0 Handler_read_prev 0 @@ -301,9 +301,12 @@ ) PARTITION BY RANGE COLUMNS(d) ( PARTITION `p1` VALUES LESS THAN (10), PARTITION `p2` VALUES LESS THAN (20), -@@ -688,8 +688,8 @@ +@@ -686,10 +686,10 @@ + show status like 'handler_read_%'; + Variable_name Value Handler_read_first 0 - Handler_read_key 1 +-Handler_read_key 1 ++Handler_read_key 2 Handler_read_last 0 -Handler_read_next 2 -Handler_read_prev 0 @@ -312,6 +315,15 @@ Handler_read_retry 0 Handler_read_rnd 0 Handler_read_rnd_deleted 0 +@@ -698,7 +698,7 @@ + set @js='$out'; + select json_extract(@js,'$**.partitions_index_scan_method'); + json_extract(@js,'$**.partitions_index_scan_method') +-["iterate_over_partitions"] ++["merge_ordered_scans"] + ## Case 2: Unordered scans in ha_partition::index_read_map + flush status; + select * from t1 where c = 120 ORDER BY d DESC LIMIT 1; @@ -725,8 +725,8 @@ Handler_read_first 0 Handler_read_key 1 @@ -479,7 +491,7 @@ Handler_read_prev 0 Handler_read_retry 0 Handler_read_rnd 0 -@@ -1202,18 +1202,18 @@ +@@ -1202,20 +1202,20 @@ # # MDEV-40479: Reverse prefix scan across partitions # @@ -503,3 +515,5 @@ +11 +15 DROP TABLE t1; + # + # MDEV-41366 Wrong result with Case 2 of non-merging partition index scan diff --git a/mysql-test/main/partition_index_scan.result b/mysql-test/main/partition_index_scan.result index 4450568bdc5fb..dba3b683765f6 100644 --- a/mysql-test/main/partition_index_scan.result +++ b/mysql-test/main/partition_index_scan.result @@ -630,8 +630,8 @@ select json_extract(@js,'$**.partitions_index_scan_method'); json_extract(@js,'$**.partitions_index_scan_method') ["iterate_over_partitions"] DROP TABLE t1; -## Case 2: calls to ha_partition::read_range_first and -## ha_partition::index_read_map, via loose index scan +## Case 2 loose index scan: calls to read_range_first iterates; +## index_read_map with AFTER_KEY is merged CREATE TABLE t1 ( a INT, b INT, @@ -651,7 +651,7 @@ a MIN(b) show status like 'handler_read_%'; Variable_name Value Handler_read_first 0 -Handler_read_key 6 +Handler_read_key 8 Handler_read_last 0 Handler_read_next 0 Handler_read_prev 0 @@ -662,7 +662,7 @@ Handler_read_rnd_next 0 set @js='$out'; select json_extract(@js,'$**.partitions_index_scan_method'); json_extract(@js,'$**.partitions_index_scan_method') -["iterate_over_partitions"] +["both"] DROP TABLE t1; CREATE TABLE t1 ( c int, @@ -676,7 +676,8 @@ PARTITION `p4` VALUES LESS THAN (40), PARTITION `p5` VALUES LESS THAN MAXVALUE ); insert into t1 select t2.seq, t3.seq from seq_100_to_200 t2, seq_1_to_50 t3; -## Case 2: Unordered scans with MRR +## Case 2: iterated partition scans with MRR with ASC key; +## merged scan with index_read_map with DESC key flush status; select * from t1 where c=113 and d between 25 and 35 order by d limit 3; c d @@ -1217,3 +1218,227 @@ c 11 6 DROP TABLE t1; +# +# MDEV-41366 Wrong result with Case 2 of non-merging partition index scan +# +# prefix-only PREFIX_LAST_OR_PREV, merged scan +CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,c), KEY(b,c)) ENGINE=InnoDB +PARTITION BY RANGE(c) (PARTITION p0 VALUES LESS THAN (10), +PARTITION p1 VALUES LESS THAN (20)); +INSERT INTO t1 VALUES (1,1,5),(2,0,12); +SELECT c FROM t1 FORCE INDEX(b) WHERE b=1 AND c<=15 ORDER BY c DESC; +c +5 +set @js='$out'; +select json_extract(@js,'$**.partitions_index_scan_method'); +json_extract(@js,'$**.partitions_index_scan_method') +["merge_ordered_scans"] +DROP TABLE t1; +# same but with desc key +CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,c), KEY(b desc,c desc)) ENGINE=InnoDB +PARTITION BY RANGE(c) (PARTITION p0 VALUES LESS THAN (10), +PARTITION p1 VALUES LESS THAN (20)); +INSERT INTO t1 VALUES (1,1,5),(2,0,12); +SELECT c FROM t1 FORCE INDEX(b) WHERE b=0 AND c>=2 ORDER BY c; +c +12 +set @js='$out'; +select json_extract(@js,'$**.partitions_index_scan_method'); +json_extract(@js,'$**.partitions_index_scan_method') +["merge_ordered_scans"] +DROP TABLE t1; +# prefix-only KEY_OR_NEXT / PREFIX_LAST_OR_PREV (opt_sum) +# merged scan +CREATE TABLE t1 (a INT, b INT, c INT NOT NULL, PRIMARY KEY(a,c), KEY k(b,c)) +ENGINE=InnoDB +PARTITION BY RANGE(c) (PARTITION p0 VALUES LESS THAN (10), +PARTITION p1 VALUES LESS THAN (20), +PARTITION p2 VALUES LESS THAN (30)); +# no b=1 in p0 or p2 +INSERT INTO t1 VALUES (1,2,5),(2,1,15),(3,0,22); +EXPLAIN +SELECT MIN(c) FROM t1 WHERE b=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +FLUSH STATUS; +SELECT MIN(c) FROM t1 WHERE b=1; +MIN(c) +15 +# 3 (merged scan: p0, p1, p2) +SHOW STATUS LIKE 'Handler_read_key'; +Variable_name Value +Handler_read_key 3 +EXPLAIN +SELECT MAX(c) FROM t1 WHERE b=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +FLUSH STATUS; +SELECT MAX(c) FROM t1 WHERE b=1; +MAX(c) +15 +# 3 (merged scan: p0, p1, p2) +SHOW STATUS LIKE 'Handler_read_key'; +Variable_name Value +Handler_read_key 3 +DROP TABLE t1; +# index_first with prefix does not qualify Case 2 +# neither does index_read_map with AFTER_KEY +CREATE TABLE t1 (a INT, b INT, KEY(a,b)) ENGINE=InnoDB +PARTITION BY RANGE COLUMNS(b) (PARTITION p1 VALUES LESS THAN (100), +PARTITION p2 VALUES LESS THAN (200), +PARTITION p3 VALUES LESS THAN MAXVALUE); +INSERT INTO t1 SELECT seq % 3 + 1, seq FROM seq_1_to_300; +ANALYZE TABLE t1 PERSISTENT FOR ALL; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +EXPLAIN SELECT a, MIN(b) FROM t1 GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL a 10 NULL 4 Using index for group-by +SELECT a, MIN(b) FROM t1 GROUP BY a; +a MIN(b) +1 3 +2 1 +3 2 +set @js='$out'; +select json_extract(@js,'$**.partitions_index_scan_method'); +json_extract(@js,'$**.partitions_index_scan_method') +["merge_ordered_scans"] +DROP TABLE t1; +# index_first with prefix does not qualify Case 2 +# neither does index_read_map with AFTER_KEY +CREATE TABLE t1 (a INT, c INT, KEY(a,c)) ENGINE=InnoDB +PARTITION BY RANGE COLUMNS(c) (PARTITION p1 VALUES LESS THAN (100), +PARTITION p2 VALUES LESS THAN (200), +PARTITION p3 VALUES LESS THAN MAXVALUE); +INSERT INTO t1 SELECT 1, seq FROM seq_1_to_99; +INSERT INTO t1 SELECT 2, seq FROM seq_100_to_199; +INSERT INTO t1 SELECT 3, seq FROM seq_1_to_99; +ANALYZE TABLE t1 PERSISTENT FOR ALL; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +EXPLAIN SELECT a, MIN(c) FROM t1 GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL a 10 NULL 4 Using index for group-by +SELECT a, MIN(c) FROM t1 GROUP BY a; +a MIN(c) +1 1 +2 100 +3 1 +set @js='$out'; +select json_extract(@js,'$**.partitions_index_scan_method'); +json_extract(@js,'$**.partitions_index_scan_method') +["merge_ordered_scans"] +DROP TABLE t1; +# AFTER_KEY / BEFORE_KEY merged scan +CREATE TABLE t1 (a INT, b INT, c INT NOT NULL, PRIMARY KEY(a,c), KEY k(b,c)) +ENGINE=InnoDB +PARTITION BY RANGE(c) (PARTITION p0 VALUES LESS THAN (10), +PARTITION p1 VALUES LESS THAN (20), +PARTITION p2 VALUES LESS THAN (30)); +INSERT INTO t1 VALUES +(1,1,5),(2,2,7),(3,2,10),(4,1,15),(5,2,18),(6,0,22),(7,1,25); +EXPLAIN +SELECT MIN(c) FROM t1 WHERE b=1 AND c>5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +FLUSH STATUS; +SELECT MIN(c) FROM t1 WHERE b=1 AND c>5; +MIN(c) +15 +# 3 (merged: p0, p1, p2) +SHOW STATUS LIKE 'Handler_read_key'; +Variable_name Value +Handler_read_key 3 +EXPLAIN +SELECT MAX(c) FROM t1 WHERE b=1 AND c<25; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +FLUSH STATUS; +SELECT MAX(c) FROM t1 WHERE b=1 AND c<25; +MAX(c) +15 +# 3 (merged: p0, p1, p2) +SHOW STATUS LIKE 'Handler_read_key'; +Variable_name Value +Handler_read_key 3 +DROP TABLE t1; +# KEY_OR_PREV needs a reverse partition scan. +# Ordered scan (HASH) +CREATE TABLE t1 (a INT, KEY k(a)) ENGINE=InnoDB +PARTITION BY HASH(a) PARTITIONS 3; +INSERT INTO t1 SELECT seq FROM seq_1_to_9; +HANDLER t1 OPEN; +HANDLER t1 READ k <= (5); +a +5 +HANDLER t1 READ k PREV; +a +4 +HANDLER t1 READ k PREV; +a +3 +HANDLER t1 READ k <= (0); +a +HANDLER t1 CLOSE; +DROP TABLE t1; +# KEY_OR_PREV merged scan +CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,c), KEY k(b,c)) +ENGINE=InnoDB +PARTITION BY RANGE(c) (PARTITION p0 VALUES LESS THAN (10), +PARTITION p1 VALUES LESS THAN (20)); +INSERT INTO t1 VALUES (1,1,5),(2,2,7),(3,1,15); +HANDLER t1 OPEN; +HANDLER t1 READ k <= (1,17); +a b c +3 1 15 +HANDLER t1 READ k PREV; +a b c +1 1 5 +HANDLER t1 CLOSE; +DROP TABLE t1; +# A range spanning several prefix values: +# QUICK_SELECT_DESC reads PREFIX_LAST_OR_PREV (2,15), keypart_map=b,c +CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,c), KEY k(b,c)) ENGINE=InnoDB +PARTITION BY RANGE(c) (PARTITION p0 VALUES LESS THAN (10), +PARTITION p1 VALUES LESS THAN (20)); +INSERT INTO t1 VALUES (1,1,7),(2,2,7),(3,1,12),(4,2,12); +EXPLAIN SELECT b, c FROM t1 FORCE INDEX(k) +WHERE b BETWEEN 1 AND 2 AND c BETWEEN 5 AND 15 ORDER BY b DESC, c DESC; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range k k 9 NULL 4 Using where; Using index +SELECT b, c FROM t1 FORCE INDEX(k) +WHERE b BETWEEN 1 AND 2 AND c BETWEEN 5 AND 15 ORDER BY b DESC, c DESC; +b c +2 12 +2 7 +1 12 +1 7 +set @js='$out'; +select json_extract(@js,'$**.partitions_index_scan_method'); +json_extract(@js,'$**.partitions_index_scan_method') +["merge_ordered_scans"] +DROP TABLE t1; +# reset m_unordered_prefix_len: single partition scan skips +# can_skip_merging_scans() +CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,c), +KEY k(b,c), KEY kc(c,b)) ENGINE=InnoDB +PARTITION BY RANGE(c) (PARTITION p0 VALUES LESS THAN (10), +PARTITION p1 VALUES LESS THAN (20)); +INSERT INTO t1 VALUES (1,1,5),(2,1,12),(3,2,13); +HANDLER t1 OPEN; +# 2 partitions, Case 2 on k(b,c): m_unordered_prefix_len = len(b) +HANDLER t1 READ k = (1); +a b c +1 1 5 +# full key of kc binds c: single partition p1, reset +HANDLER t1 READ kc = (13,2); +a b c +3 2 13 +# expect (2,1,12) +HANDLER t1 READ kc PREV; +a b c +2 1 12 +HANDLER t1 CLOSE; +DROP TABLE t1; diff --git a/mysql-test/main/partition_index_scan.test b/mysql-test/main/partition_index_scan.test index 571dc014b7a0d..642a07fe3891d 100644 --- a/mysql-test/main/partition_index_scan.test +++ b/mysql-test/main/partition_index_scan.test @@ -1,5 +1,6 @@ --source include/have_partition.inc --source include/have_sequence.inc +--source include/have_innodb.inc --source include/no_view_protocol.inc --disable_ps2_protocol --disable_cursor_protocol @@ -251,8 +252,8 @@ select json_extract(@js,'$**.partitions_index_scan_method'); DROP TABLE t1; ---echo ## Case 2: calls to ha_partition::read_range_first and ---echo ## ha_partition::index_read_map, via loose index scan +--echo ## Case 2 loose index scan: calls to read_range_first iterates; +--echo ## index_read_map with AFTER_KEY is merged eval CREATE TABLE t1 ( a INT, @@ -293,7 +294,8 @@ CREATE TABLE t1 ( insert into t1 select t2.seq, t3.seq from seq_100_to_200 t2, seq_1_to_50 t3; ---echo ## Case 2: Unordered scans with MRR +--echo ## Case 2: iterated partition scans with MRR with ASC key; +--echo ## merged scan with index_read_map with DESC key flush status; select * from t1 where c=113 and d between 25 and 35 order by d limit 3; show status like 'handler_read_%'; @@ -572,5 +574,180 @@ SELECT c FROM t1 WHERE b = 1 ORDER BY c $opposite_direction; DROP TABLE t1; +--echo # +--echo # MDEV-41366 Wrong result with Case 2 of non-merging partition index scan +--echo # + +--echo # prefix-only PREFIX_LAST_OR_PREV, merged scan +CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,c), KEY(b,c)) ENGINE=InnoDB +PARTITION BY RANGE(c) (PARTITION p0 VALUES LESS THAN (10), + PARTITION p1 VALUES LESS THAN (20)); +INSERT INTO t1 VALUES (1,1,5),(2,0,12); +let $q= +SELECT c FROM t1 FORCE INDEX(b) WHERE b=1 AND c<=15 ORDER BY c DESC; +eval $q; +let $out=`analyze format=json $q`; +evalp set @js='$out'; +select json_extract(@js,'$**.partitions_index_scan_method'); + +DROP TABLE t1; + +--echo # same but with desc key +CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,c), KEY(b desc,c desc)) ENGINE=InnoDB +PARTITION BY RANGE(c) (PARTITION p0 VALUES LESS THAN (10), + PARTITION p1 VALUES LESS THAN (20)); +INSERT INTO t1 VALUES (1,1,5),(2,0,12); +let $q= +SELECT c FROM t1 FORCE INDEX(b) WHERE b=0 AND c>=2 ORDER BY c; +eval $q; +let $out=`analyze format=json $q`; +evalp set @js='$out'; +select json_extract(@js,'$**.partitions_index_scan_method'); + +DROP TABLE t1; + +--echo # prefix-only KEY_OR_NEXT / PREFIX_LAST_OR_PREV (opt_sum) +--echo # merged scan +CREATE TABLE t1 (a INT, b INT, c INT NOT NULL, PRIMARY KEY(a,c), KEY k(b,c)) + ENGINE=InnoDB +PARTITION BY RANGE(c) (PARTITION p0 VALUES LESS THAN (10), + PARTITION p1 VALUES LESS THAN (20), + PARTITION p2 VALUES LESS THAN (30)); +--echo # no b=1 in p0 or p2 +INSERT INTO t1 VALUES (1,2,5),(2,1,15),(3,0,22); + +EXPLAIN +SELECT MIN(c) FROM t1 WHERE b=1; +FLUSH STATUS; +SELECT MIN(c) FROM t1 WHERE b=1; +--echo # 3 (merged scan: p0, p1, p2) +SHOW STATUS LIKE 'Handler_read_key'; + +EXPLAIN +SELECT MAX(c) FROM t1 WHERE b=1; +FLUSH STATUS; +SELECT MAX(c) FROM t1 WHERE b=1; +--echo # 3 (merged scan: p0, p1, p2) +SHOW STATUS LIKE 'Handler_read_key'; +DROP TABLE t1; + +--echo # index_first with prefix does not qualify Case 2 +--echo # neither does index_read_map with AFTER_KEY +CREATE TABLE t1 (a INT, b INT, KEY(a,b)) ENGINE=InnoDB +PARTITION BY RANGE COLUMNS(b) (PARTITION p1 VALUES LESS THAN (100), + PARTITION p2 VALUES LESS THAN (200), + PARTITION p3 VALUES LESS THAN MAXVALUE); +INSERT INTO t1 SELECT seq % 3 + 1, seq FROM seq_1_to_300; +ANALYZE TABLE t1 PERSISTENT FOR ALL; +let $q= +SELECT a, MIN(b) FROM t1 GROUP BY a; +eval EXPLAIN $q; +eval $q; +let $out=`analyze format=json $q`; +evalp set @js='$out'; +select json_extract(@js,'$**.partitions_index_scan_method'); +DROP TABLE t1; + +--echo # index_first with prefix does not qualify Case 2 +--echo # neither does index_read_map with AFTER_KEY +CREATE TABLE t1 (a INT, c INT, KEY(a,c)) ENGINE=InnoDB +PARTITION BY RANGE COLUMNS(c) (PARTITION p1 VALUES LESS THAN (100), + PARTITION p2 VALUES LESS THAN (200), + PARTITION p3 VALUES LESS THAN MAXVALUE); +INSERT INTO t1 SELECT 1, seq FROM seq_1_to_99; +INSERT INTO t1 SELECT 2, seq FROM seq_100_to_199; +INSERT INTO t1 SELECT 3, seq FROM seq_1_to_99; +ANALYZE TABLE t1 PERSISTENT FOR ALL; +let $q= +SELECT a, MIN(c) FROM t1 GROUP BY a; +eval EXPLAIN $q; +eval $q; +let $out=`analyze format=json $q`; +evalp set @js='$out'; +select json_extract(@js,'$**.partitions_index_scan_method'); +DROP TABLE t1; + +--echo # AFTER_KEY / BEFORE_KEY merged scan +CREATE TABLE t1 (a INT, b INT, c INT NOT NULL, PRIMARY KEY(a,c), KEY k(b,c)) + ENGINE=InnoDB +PARTITION BY RANGE(c) (PARTITION p0 VALUES LESS THAN (10), + PARTITION p1 VALUES LESS THAN (20), + PARTITION p2 VALUES LESS THAN (30)); +INSERT INTO t1 VALUES + (1,1,5),(2,2,7),(3,2,10),(4,1,15),(5,2,18),(6,0,22),(7,1,25); + +EXPLAIN +SELECT MIN(c) FROM t1 WHERE b=1 AND c>5; +FLUSH STATUS; +SELECT MIN(c) FROM t1 WHERE b=1 AND c>5; +--echo # 3 (merged: p0, p1, p2) +SHOW STATUS LIKE 'Handler_read_key'; + +EXPLAIN +SELECT MAX(c) FROM t1 WHERE b=1 AND c<25; +FLUSH STATUS; +SELECT MAX(c) FROM t1 WHERE b=1 AND c<25; +--echo # 3 (merged: p0, p1, p2) +SHOW STATUS LIKE 'Handler_read_key'; +DROP TABLE t1; + +--echo # KEY_OR_PREV needs a reverse partition scan. +--echo # Ordered scan (HASH) +CREATE TABLE t1 (a INT, KEY k(a)) ENGINE=InnoDB +PARTITION BY HASH(a) PARTITIONS 3; +INSERT INTO t1 SELECT seq FROM seq_1_to_9; +HANDLER t1 OPEN; +HANDLER t1 READ k <= (5); +HANDLER t1 READ k PREV; +HANDLER t1 READ k PREV; +HANDLER t1 READ k <= (0); +HANDLER t1 CLOSE; +DROP TABLE t1; + +--echo # KEY_OR_PREV merged scan +CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,c), KEY k(b,c)) +ENGINE=InnoDB +PARTITION BY RANGE(c) (PARTITION p0 VALUES LESS THAN (10), + PARTITION p1 VALUES LESS THAN (20)); +INSERT INTO t1 VALUES (1,1,5),(2,2,7),(3,1,15); +HANDLER t1 OPEN; +HANDLER t1 READ k <= (1,17); +HANDLER t1 READ k PREV; +HANDLER t1 CLOSE; +DROP TABLE t1; + +--echo # A range spanning several prefix values: +--echo # QUICK_SELECT_DESC reads PREFIX_LAST_OR_PREV (2,15), keypart_map=b,c +CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,c), KEY k(b,c)) ENGINE=InnoDB +PARTITION BY RANGE(c) (PARTITION p0 VALUES LESS THAN (10), + PARTITION p1 VALUES LESS THAN (20)); +INSERT INTO t1 VALUES (1,1,7),(2,2,7),(3,1,12),(4,2,12); +let $q= +SELECT b, c FROM t1 FORCE INDEX(k) +WHERE b BETWEEN 1 AND 2 AND c BETWEEN 5 AND 15 ORDER BY b DESC, c DESC; +eval EXPLAIN $q; +eval $q; +let $out=`analyze format=json $q`; +evalp set @js='$out'; +select json_extract(@js,'$**.partitions_index_scan_method'); +DROP TABLE t1; + +--echo # reset m_unordered_prefix_len: single partition scan skips +--echo # can_skip_merging_scans() +CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,c), + KEY k(b,c), KEY kc(c,b)) ENGINE=InnoDB +PARTITION BY RANGE(c) (PARTITION p0 VALUES LESS THAN (10), + PARTITION p1 VALUES LESS THAN (20)); +INSERT INTO t1 VALUES (1,1,5),(2,1,12),(3,2,13); +HANDLER t1 OPEN; +--echo # 2 partitions, Case 2 on k(b,c): m_unordered_prefix_len = len(b) +HANDLER t1 READ k = (1); +--echo # full key of kc binds c: single partition p1, reset +HANDLER t1 READ kc = (13,2); +--echo # expect (2,1,12) +HANDLER t1 READ kc PREV; +HANDLER t1 CLOSE; +DROP TABLE t1; + --enable_cursor_protocol --enable_ps2_protocol diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 343ab395ffc32..143a2bf56ef81 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -5991,7 +5991,8 @@ int ha_partition::common_index_read(uchar *buf, bool have_start_key) } if (have_start_key && - (m_start_key.flag == HA_READ_PREFIX_LAST || + (m_start_key.flag == HA_READ_KEY_OR_PREV || + m_start_key.flag == HA_READ_PREFIX_LAST || m_start_key.flag == HA_READ_PREFIX_LAST_OR_PREV || m_start_key.flag == HA_READ_BEFORE_KEY)) { @@ -7515,8 +7516,23 @@ bool ha_partition::can_skip_merging_scans() (key_part->key_part_flag & HA_REVERSE_SORT) ? true : false; if (m_index_scan_type == partition_index_read) { - return - m_start_key.key && (m_start_key.keypart_map & prefix) == prefix; + switch (m_start_key.flag) { + case HA_READ_AFTER_KEY: + case HA_READ_BEFORE_KEY: + case HA_READ_KEY_OR_NEXT: + case HA_READ_KEY_OR_PREV: + case HA_READ_PREFIX_LAST_OR_PREV: + return false; + case HA_READ_KEY_EXACT: + case HA_READ_PREFIX: + case HA_READ_PREFIX_LAST: + return m_start_key.key && + (m_start_key.keypart_map & prefix) == prefix; + default: + /* SPATIAL keys have a single key part, so Case 2 cannot apply */ + DBUG_ASSERT(0); + return false; + } } else if (m_index_scan_type == partition_read_range) { @@ -7595,6 +7611,7 @@ int ha_partition::partition_scan_set_up(uchar * buf, bool idx_read_flag) DBUG_PRINT("info", ("index scan using the single partition %u", (uint) m_part_spec.start_part)); m_ordered_scan_ongoing= FALSE; + m_unordered_prefix_len= 0; } else {