bug#28570: handler::index_read() is called with different find_flag when

ORDER BY is used

The range analysis module did not correctly signal to the 
handler that a range represents a ref (EQ_RANGE flag). This causes 
non-range queries like 
SELECT ... FROM ... WHERE keypart_1=const, ..., keypart_n=const 
ORDER BY ... FOR UPDATE
to wait for a lock unneccesarily if another running transaction uses
SELECT ... FOR UPDATE on the same table.

Fixed by setting EQ_RANGE for all range accesses that represent 
an equality predicate. 
parent 117c3ff9
...@@ -1007,4 +1007,22 @@ CALL p1(); ...@@ -1007,4 +1007,22 @@ CALL p1();
CALL p1(); CALL p1();
DROP PROCEDURE p1; DROP PROCEDURE p1;
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (
a INT,
b INT,
KEY (b)
) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1,10), (2,10), (2,20), (3,30);
START TRANSACTION;
SELECT * FROM t1 WHERE b=20 FOR UPDATE;
a b
2 20
START TRANSACTION;
SELECT * FROM t1 WHERE b=10 ORDER BY A FOR UPDATE;
a b
1 10
2 10
ROLLBACK;
ROLLBACK;
DROP TABLE t1;
End of 5.0 tests End of 5.0 tests
...@@ -840,5 +840,34 @@ DISCONNECT con2; ...@@ -840,5 +840,34 @@ DISCONNECT con2;
DROP PROCEDURE p1; DROP PROCEDURE p1;
DROP TABLE t1; DROP TABLE t1;
#
# Bug #28570: handler::index_read() is called with different find_flag when
# ORDER BY is used
#
CREATE TABLE t1 (
a INT,
b INT,
KEY (b)
) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1,10), (2,10), (2,20), (3,30);
START TRANSACTION;
SELECT * FROM t1 WHERE b=20 FOR UPDATE;
--connect (conn2, localhost, root,,test)
# This statement gives a "failed: 1205: Lock wait timeout exceeded; try
# restarting transaction" message when the bug is present.
START TRANSACTION;
SELECT * FROM t1 WHERE b=10 ORDER BY A FOR UPDATE;
ROLLBACK;
--disconnect conn2
--connection default
ROLLBACK;
DROP TABLE t1;
--echo End of 5.0 tests --echo End of 5.0 tests
...@@ -2610,7 +2610,8 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p) ...@@ -2610,7 +2610,8 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
read_range_first() read_range_first()
start_key Start key. Is 0 if no min range start_key Start key. Is 0 if no min range
end_key End key. Is 0 if no max range end_key End key. Is 0 if no max range
eq_range_arg Set to 1 if start_key == end_key eq_range_arg Set to 1 if start_key == end_key and the range endpoints
will not change during query execution.
sorted Set to 1 if result should be sorted per key sorted Set to 1 if result should be sorted per key
NOTES NOTES
......
...@@ -6369,8 +6369,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, ...@@ -6369,8 +6369,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
range->min_key=range->max_key=(char*) ref->key_buff; range->min_key=range->max_key=(char*) ref->key_buff;
range->min_length=range->max_length=ref->key_length; range->min_length=range->max_length=ref->key_length;
range->flag= ((ref->key_length == key_info->key_length && range->flag= ((ref->key_length == key_info->key_length &&
(key_info->flags & (HA_NOSAME | HA_END_SPACE_KEY)) == (key_info->flags & HA_END_SPACE_KEY) == 0) ? EQ_RANGE : 0);
HA_NOSAME) ? EQ_RANGE : 0);
if (!(quick->key_parts=key_part=(KEY_PART *) if (!(quick->key_parts=key_part=(KEY_PART *)
alloc_root(&quick->alloc,sizeof(KEY_PART)*ref->key_parts))) alloc_root(&quick->alloc,sizeof(KEY_PART)*ref->key_parts)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment