Skip to content

Commit

Permalink
Suppress Gap Lock errors for unique key lookups
Browse files Browse the repository at this point in the history
Summary:
Non primary unique key locking lookup was logged to Gap Lock
logs (or returned as errors if setting gap_lock_raise_error=1).
This was wrong. This diff covers unique key as well.

squash with: https://reviews.facebook.net/D54813

Test Plan: mtr

Reviewers: jkedgar, spetrunia, mung, hermanlee4

Reviewed By: hermanlee4

Subscribers: webscalesql-eng

Differential Revision: https://reviews.facebook.net/D62139
  • Loading branch information
yoshinorim committed Aug 16, 2016
1 parent 33f177c commit fbd5a3c
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 98 deletions.
1 change: 0 additions & 1 deletion mysql-test/include/gap_lock_raise_error_select.inc
Expand Up @@ -42,7 +42,6 @@ eval select * from gap1 order by id1 desc, id2 desc, id3 desc
--error ER_UNKNOWN_ERROR
eval select * from gap1 force index(i) where c1=1 $select_lock;
# unique index lookup
--error ER_UNKNOWN_ERROR
eval select * from gap3 force index(ui) where value=1 $select_lock;
# primary key lookup
eval select * from gap1 where id1=1 and id2=1 and id3=1 $select_lock;
Expand Down
22 changes: 22 additions & 0 deletions mysql-test/include/gap_lock_raise_error_update.inc
Expand Up @@ -64,3 +64,25 @@ select * from gap1, gap2 limit 1 for update;
--error ER_UNKNOWN_ERROR
select * from gap1 a, gap1 b limit 1 for update;

# unique secondary key
create table u1(
c1 int,
c2 int,
c3 int,
c4 int,
primary key (c1, c2, c3),
unique key (c3, c1)
);
set session gap_lock_raise_error=1;
begin;
insert into u1 values (1,1,1,1);
commit;
begin;
insert into u1 values (1,2,1,1) on duplicate key update c4=10;
commit;
begin;
select * from u1 where c3=1 and c1 = 1 for update;
--error ER_UNKNOWN_ERROR
select * from u1 where c3=1 for update;
commit;
drop table u1;
2 changes: 1 addition & 1 deletion mysql-test/r/gap_lock_option.result
Expand Up @@ -12,6 +12,6 @@ gap_lock_exceptions t2
set session gap_lock_raise_error=1;
begin;
delete from t1 where id=1;
ERROR HY000: Using Gap Lock without full primary key in multi-table or multi-statement transactions is not allowed. You need either 1: Execute 'SET SESSION gap_lock_raise_error=0' if you are sure that your application does not rely on Gap Lock. 2: Rewrite queries to use all primary key columns in WHERE equal conditions. 3: Rewrite to single-table, single-statement transaction. Query: delete from t1 where id=1
ERROR HY000: Using Gap Lock without full unique key in multi-table or multi-statement transactions is not allowed. You need either 1: Execute 'SET SESSION gap_lock_raise_error=0' if you are sure that your application does not rely on Gap Lock. 2: Rewrite queries to use all unique key columns in WHERE equal conditions. 3: Rewrite to single-table, single-statement transaction. Query: delete from t1 where id=1
commit;
drop table t1;
109 changes: 67 additions & 42 deletions mysql-test/suite/innodb/r/gap_lock_raise_error.result

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion mysql-test/suite/rocksdb/r/gap_lock_issue254.result
Expand Up @@ -4,6 +4,6 @@ update t set value=100 where id in (1, 2);
commit;
begin;
select * from t for update;
ERROR HY000: Using Gap Lock without full primary key in multi-table or multi-statement transactions is not allowed. You need either 1: Execute 'SET SESSION gap_lock_raise_error=0' if you are sure that your application does not rely on Gap Lock. 2: Rewrite queries to use all primary key columns in WHERE equal conditions. 3: Rewrite to single-table, single-statement transaction. Query: select * from t for update
ERROR HY000: Using Gap Lock without full unique key in multi-table or multi-statement transactions is not allowed. You need either 1: Execute 'SET SESSION gap_lock_raise_error=0' if you are sure that your application does not rely on Gap Lock. 2: Rewrite queries to use all unique key columns in WHERE equal conditions. 3: Rewrite to single-table, single-statement transaction. Query: select * from t for update
commit;
drop table t;
109 changes: 67 additions & 42 deletions mysql-test/suite/rocksdb/r/gap_lock_raise_error.result

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions sql/handler.cc
Expand Up @@ -2978,7 +2978,7 @@ int handler::ha_index_read_map(uchar *buf, const uchar *key,
m_lock_type != F_UNLCK);
DBUG_ASSERT(inited == INDEX);

if (is_using_prohibited_gap_locks(table, is_using_full_primary_key(
if (is_using_prohibited_gap_locks(table, is_using_full_unique_key(
active_index, keypart_map, find_flag)))
{
DBUG_RETURN(HA_ERR_LOCK_DEADLOCK);
Expand Down Expand Up @@ -3024,7 +3024,7 @@ int handler::ha_index_read_idx_map(uchar *buf, uint index, const uchar *key,
m_lock_type != F_UNLCK);
DBUG_ASSERT(end_range == NULL);

if (is_using_prohibited_gap_locks(table, is_using_full_primary_key(
if (is_using_prohibited_gap_locks(table, is_using_full_unique_key(
index, keypart_map, find_flag)))
{
return HA_ERR_LOCK_DEADLOCK;
Expand Down Expand Up @@ -3122,17 +3122,17 @@ bool handler::is_using_full_key(key_part_map keypart_map,
- 1));
}

bool handler::is_using_full_primary_key(uint index,
bool handler::is_using_full_unique_key(uint index,
key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
return (is_using_full_key(keypart_map,
table->key_info[index].actual_key_parts)
&& index == table->s->primary_key
&& find_flag == HA_READ_KEY_EXACT);
&& find_flag == HA_READ_KEY_EXACT
&& (index == table->s->primary_key
|| (table->key_info[index].flags & HA_NOSAME)));
}


/**
Reads the last row via index.
Expand Down Expand Up @@ -7956,13 +7956,13 @@ bool handler::is_using_prohibited_gap_locks(TABLE *table,
if (thd->variables.gap_lock_raise_error)
{
my_printf_error(ER_UNKNOWN_ERROR,
"Using Gap Lock without full primary key in multi-table "
"Using Gap Lock without full unique key in multi-table "
"or multi-statement transactions is not "
"allowed. You need either 1: Execute 'SET SESSION "
"gap_lock_raise_error=0' if you are sure that "
"your application does not rely on Gap Lock. "
"2: Rewrite queries to use "
"all primary key columns in WHERE equal conditions. "
"all unique key columns in WHERE equal conditions. "
"3: Rewrite to single-table, single-statement "
"transaction. Query: %s",
MYF(0), thd->query());
Expand Down
4 changes: 2 additions & 2 deletions sql/handler.h
Expand Up @@ -2446,11 +2446,11 @@ class handler :public Sql_alloc
return index_read_last(buf, key, key_len);
}
bool is_using_full_key(key_part_map keypart_map, uint actual_key_parts);
bool is_using_full_primary_key(uint active_index,
bool is_using_full_unique_key(uint active_index,
key_part_map keypart_map,
enum ha_rkey_function find_flag);
bool is_using_prohibited_gap_locks(TABLE *table,
bool using_full_primary_key);
bool using_full_unique_key);
public:
virtual int read_range_first(const key_range *start_key,
const key_range *end_key,
Expand Down
2 changes: 1 addition & 1 deletion storage/rocksdb/ha_rocksdb.cc
Expand Up @@ -5774,7 +5774,7 @@ int ha_rocksdb::read_range_first(const key_range *start_key,
else
{
if (is_using_prohibited_gap_locks(table,
is_using_full_primary_key(
is_using_full_unique_key(
active_index,
start_key->keypart_map,
start_key->flag)))
Expand Down

0 comments on commit fbd5a3c

Please sign in to comment.