Commit ddbea705 authored by unknown's avatar unknown

Fixed a bug: deadlock without any locking, simple select and update (Bug #7975).

Backported from 5.0.3.


innobase/row/row0ins.c:
  If the SQL-query will update or replace duplicate records we take X-lock
  for duplicate records.
sql/ha_innodb.cc:
  INSERT ON DUPLICATE KEY UPDATE will also update duplicate records and we should
  take X-lock in this case for duplicate records.
parent a6040851
...@@ -51,14 +51,19 @@ innobase_invalidate_query_cache( ...@@ -51,14 +51,19 @@ innobase_invalidate_query_cache(
chars count */ 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. 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 NOTE that /mysql/innobase/row/row0ins.c must contain the
prototype for this function ! */ prototype for this function ! */
ibool ibool
innobase_query_is_replace(void); innobase_query_is_update(void);
/*===========================*/
/************************************************************************* /*************************************************************************
Creates an insert node struct. */ Creates an insert node struct. */
...@@ -1562,12 +1567,12 @@ row_ins_scan_sec_index_for_duplicate( ...@@ -1562,12 +1567,12 @@ row_ins_scan_sec_index_for_duplicate(
trx = thr_get_trx(thr); trx = thr_get_trx(thr);
ut_ad(trx); ut_ad(trx);
if (innobase_query_is_replace()) { if (innobase_query_is_update()) {
/* The manual defines the REPLACE semantics that it /* If the SQL-query will update or replace
is either an INSERT or DELETE(s) for duplicate key duplicate key we will take X-lock for
+ INSERT. Therefore, we should take X-lock for duplicates ( REPLACE, LOAD DATAFILE REPLACE,
duplicates */ INSERT ON DUPLICATE KEY UPDATE). */
err = row_ins_set_exclusive_rec_lock( err = row_ins_set_exclusive_rec_lock(
LOCK_ORDINARY,rec,index,thr); LOCK_ORDINARY,rec,index,thr);
...@@ -1675,12 +1680,12 @@ row_ins_duplicate_error_in_clust( ...@@ -1675,12 +1680,12 @@ row_ins_duplicate_error_in_clust(
sure that in roll-forward we get the same duplicate sure that in roll-forward we get the same duplicate
errors as in original execution */ errors as in original execution */
if (innobase_query_is_replace()) { if (innobase_query_is_update()) {
/* The manual defines the REPLACE semantics /* If the SQL-query will update or replace
that it is either an INSERT or DELETE(s) duplicate key we will take X-lock for
for duplicate key + INSERT. Therefore, we duplicates ( REPLACE, LOAD DATAFILE REPLACE,
should take X-lock for duplicates */ INSERT ON DUPLICATE KEY UPDATE). */
err = row_ins_set_exclusive_rec_lock( err = row_ins_set_exclusive_rec_lock(
LOCK_REC_NOT_GAP,rec,cursor->index, LOCK_REC_NOT_GAP,rec,cursor->index,
...@@ -1713,12 +1718,12 @@ row_ins_duplicate_error_in_clust( ...@@ -1713,12 +1718,12 @@ row_ins_duplicate_error_in_clust(
if (rec != page_get_supremum_rec(page)) { if (rec != page_get_supremum_rec(page)) {
/* The manual defines the REPLACE semantics that it if (innobase_query_is_update()) {
is either an INSERT or DELETE(s) for duplicate key
+ INSERT. Therefore, we should take X-lock for
duplicates. */
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( err = row_ins_set_exclusive_rec_lock(
LOCK_REC_NOT_GAP, LOCK_REC_NOT_GAP,
......
...@@ -5653,13 +5653,19 @@ innobase_get_at_most_n_mbchars( ...@@ -5653,13 +5653,19 @@ innobase_get_at_most_n_mbchars(
extern "C" { 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. 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 NOTE that /mysql/innobase/row/row0ins.c must contain the
prototype for this function ! */ prototype for this function ! */
ibool ibool
innobase_query_is_replace(void) innobase_query_is_update(void)
/*===========================*/ /*===========================*/
{ {
THD* thd; THD* thd;
...@@ -5671,9 +5677,14 @@ innobase_query_is_replace(void) ...@@ -5671,9 +5677,14 @@ innobase_query_is_replace(void)
( thd->lex->sql_command == SQLCOM_LOAD && ( thd->lex->sql_command == SQLCOM_LOAD &&
thd->lex->duplicates == DUP_REPLACE )) { thd->lex->duplicates == DUP_REPLACE )) {
return true; return true;
} else {
return false;
} }
if ( thd->lex->sql_command == SQLCOM_INSERT &&
thd->lex->duplicates == DUP_UPDATE ) {
return true;
}
return false;
} }
} }
......
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