From bb0507fa5d3e1161d418112f1c412fb9fa815571 Mon Sep 17 00:00:00 2001 From: unknown <jan@hundin.mysql.fi> Date: Thu, 3 Feb 2005 10:54:38 +0200 Subject: [PATCH] Fixed a bug: deadlock without any locking, simple select and update (Bug #7975). innobase/row/row0ins.c: If the SQL-query will update or replace duplicate key row we take X-lcok for duplicate row. sql/ha_innodb.cc: INSERT ON DUPLICATE KEY UPDATE will also update duplicate key and we can take X-lock in this case for duplicate key records. BitKeeper/etc/ignore: Added innobase/row/row0index.c to the ignore list --- .bzrignore | 1 + innobase/row/row0ins.c | 41 +++++++++++++++++++++++------------------ sql/ha_innodb.cc | 19 +++++++++++++++---- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/.bzrignore b/.bzrignore index bb1cdb1c0c..3aab3a7b4d 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1055,3 +1055,4 @@ vio/viotest-ssl include/mysqld_ername.h include/mysqld_error.h include/sql_state.h +innobase/row/row0index.c diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index aab0f5affa..9edc18025d 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -51,14 +51,19 @@ innobase_invalidate_query_cache( chars count */ /********************************************************************** -This function returns true if SQL-query in the current thread +This function returns true if + +1) SQL-query in the current thread is either REPLACE or LOAD DATA INFILE REPLACE. + +2) SQL-query in the current thread +is INSERT ON DUPLICATE KEY UPDATE. + NOTE that /mysql/innobase/row/row0ins.c must contain the prototype for this function ! */ ibool -innobase_query_is_replace(void); -/*===========================*/ +innobase_query_is_update(void); /************************************************************************* Creates an insert node struct. */ @@ -1597,12 +1602,12 @@ row_ins_scan_sec_index_for_duplicate( offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap); - if (innobase_query_is_replace()) { + if (innobase_query_is_update()) { - /* The manual defines the REPLACE semantics that it - is either an INSERT or DELETE(s) for duplicate key - + INSERT. Therefore, we should take X-lock for - duplicates */ + /* If the SQL-query will update or replace + duplicate key we will take X-lock for + duplicates ( REPLACE, LOAD DATAFILE REPLACE, + INSERT ON DUPLICATE KEY UPDATE). */ err = row_ins_set_exclusive_rec_lock(LOCK_ORDINARY, rec, index, offsets, thr); @@ -1720,12 +1725,12 @@ row_ins_duplicate_error_in_clust( sure that in roll-forward we get the same duplicate errors as in original execution */ - if (innobase_query_is_replace()) { + if (innobase_query_is_update()) { - /* The manual defines the REPLACE semantics - that it is either an INSERT or DELETE(s) - for duplicate key + INSERT. Therefore, we - should take X-lock for duplicates */ + /* If the SQL-query will update or replace + duplicate key we will take X-lock for + duplicates ( REPLACE, LOAD DATAFILE REPLACE, + INSERT ON DUPLICATE KEY UPDATE). */ err = row_ins_set_exclusive_rec_lock( LOCK_REC_NOT_GAP,rec,cursor->index, @@ -1759,12 +1764,12 @@ row_ins_duplicate_error_in_clust( offsets = rec_get_offsets(rec, cursor->index, offsets, ULINT_UNDEFINED, &heap); - /* The manual defines the REPLACE semantics that it - is either an INSERT or DELETE(s) for duplicate key - + INSERT. Therefore, we should take X-lock for - duplicates. */ + if (innobase_query_is_update()) { - if (innobase_query_is_replace()) { + /* If the SQL-query will update or replace + duplicate key we will take X-lock for + duplicates ( REPLACE, LOAD DATAFILE REPLACE, + INSERT ON DUPLICATE KEY UPDATE). */ err = row_ins_set_exclusive_rec_lock( LOCK_REC_NOT_GAP, rec, diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 797f51c029..04ae021197 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -6142,13 +6142,19 @@ innobase_get_at_most_n_mbchars( extern "C" { /********************************************************************** -This function returns true if SQL-query in the current thread +This function returns true if + +1) SQL-query in the current thread is either REPLACE or LOAD DATA INFILE REPLACE. + +2) SQL-query in the current thread +is INSERT ON DUPLICATE KEY UPDATE. + NOTE that /mysql/innobase/row/row0ins.c must contain the prototype for this function ! */ ibool -innobase_query_is_replace(void) +innobase_query_is_update(void) /*===========================*/ { THD* thd; @@ -6160,9 +6166,14 @@ innobase_query_is_replace(void) ( thd->lex->sql_command == SQLCOM_LOAD && thd->lex->duplicates == DUP_REPLACE )) { return true; - } else { - return false; } + + if ( thd->lex->sql_command == SQLCOM_INSERT && + thd->lex->duplicates == DUP_UPDATE ) { + return true; + } + + return false; } } -- 2.30.9