summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@oracle.com>2011-11-10 12:49:31 +0200
committerMarko Mäkelä <marko.makela@oracle.com>2011-11-10 12:49:31 +0200
commita0a51251e49365cc0f256a2ebc90994dbe0d9a95 (patch)
treea1e5e010bd0a3644af8424d22ce41dcb33d26be1 /storage
parent77eb01b82776dc222da1543dc2d20295156a123d (diff)
downloadmariadb-git-a0a51251e49365cc0f256a2ebc90994dbe0d9a95.tar.gz
Bug#11759688 52020: InnoDB can still deadlock on just INSERT...ON DUPLICATE KEY
a.k.a. Bug#7975 deadlock without any locking, simple select and update Bug#7975 was reintroduced when the storage engine API was made pluggable in MySQL 5.1. Instead of looking at thd->lex directly, we rely on handler::extra(). But, we were looking at the wrong extra() flag, and we were ignoring the TRX_DUP_REPLACE flag in places where we should obey it. innodb_replace.test: Add tests for hopefully all affected statement types, so that bug should never ever resurface. This kind of tests should have been added when fixing Bug#7975 in MySQL 5.0.3 in the first place. rb:806 approved by Sunny Bains
Diffstat (limited to 'storage')
-rw-r--r--storage/innobase/handler/ha_innodb.cc16
-rw-r--r--storage/innobase/row/row0ins.c6
-rw-r--r--storage/innodb_plugin/ChangeLog7
-rw-r--r--storage/innodb_plugin/handler/ha_innodb.cc16
-rw-r--r--storage/innodb_plugin/row/row0ins.c8
5 files changed, 28 insertions, 25 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 3e3db33e588..7f82959dffd 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -4087,8 +4087,7 @@ no_commit:
switch (sql_command) {
case SQLCOM_LOAD:
- if ((trx->duplicates
- & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
+ if (trx->duplicates) {
goto set_max_autoinc;
}
@@ -4364,8 +4363,7 @@ ha_innobase::update_row(
&& table->next_number_field
&& new_row == table->record[0]
&& thd_sql_command(user_thd) == SQLCOM_INSERT
- && (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
- == TRX_DUP_IGNORE) {
+ && trx->duplicates) {
ulonglong auto_inc;
ulonglong col_max_value;
@@ -7099,6 +7097,7 @@ ha_innobase::extra(
break;
case HA_EXTRA_RESET_STATE:
reset_template(prebuilt);
+ thd_to_trx(ha_thd())->duplicates = 0;
break;
case HA_EXTRA_NO_KEYREAD:
prebuilt->read_just_key = 0;
@@ -7116,19 +7115,18 @@ ha_innobase::extra(
parameters below. We must not invoke update_thd()
either, because the calling threads may change.
CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
- case HA_EXTRA_IGNORE_DUP_KEY:
+ case HA_EXTRA_INSERT_WITH_UPDATE:
thd_to_trx(ha_thd())->duplicates |= TRX_DUP_IGNORE;
break;
+ case HA_EXTRA_NO_IGNORE_DUP_KEY:
+ thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_IGNORE;
+ break;
case HA_EXTRA_WRITE_CAN_REPLACE:
thd_to_trx(ha_thd())->duplicates |= TRX_DUP_REPLACE;
break;
case HA_EXTRA_WRITE_CANNOT_REPLACE:
thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_REPLACE;
break;
- case HA_EXTRA_NO_IGNORE_DUP_KEY:
- thd_to_trx(ha_thd())->duplicates &=
- ~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
- break;
default:/* Do nothing */
;
}
diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c
index 6366beb6b47..c18b6995066 100644
--- a/storage/innobase/row/row0ins.c
+++ b/storage/innobase/row/row0ins.c
@@ -1674,7 +1674,7 @@ row_ins_scan_sec_index_for_duplicate(
btr_pcur_open(index, entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr);
- allow_duplicates = thr_get_trx(thr)->duplicates & TRX_DUP_IGNORE;
+ allow_duplicates = thr_get_trx(thr)->duplicates;
/* Scan index records and check if there is a duplicate */
@@ -1814,7 +1814,7 @@ row_ins_duplicate_error_in_clust(
sure that in roll-forward we get the same duplicate
errors as in original execution */
- if (trx->duplicates & TRX_DUP_IGNORE) {
+ if (trx->duplicates) {
/* If the SQL-query will update or replace
duplicate key we will take X-lock for
@@ -1856,7 +1856,7 @@ row_ins_duplicate_error_in_clust(
offsets = rec_get_offsets(rec, cursor->index, offsets,
ULINT_UNDEFINED, &heap);
- if (trx->duplicates & TRX_DUP_IGNORE) {
+ if (trx->duplicates) {
/* If the SQL-query will update or replace
duplicate key we will take X-lock for
diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog
index f7d01cd6773..a7c9c6e3212 100644
--- a/storage/innodb_plugin/ChangeLog
+++ b/storage/innodb_plugin/ChangeLog
@@ -1,3 +1,10 @@
+2011-11-10 The InnoDB Team
+
+ * handler/ha_innodb.cc, row/row0ins.c, innodb_replace.test:
+ Fix Bug#11759688 52020: InnoDB can still deadlock
+ on just INSERT...ON DUPLICATE KEY a.k.a. the reintroduction of
+ Bug#7975 deadlock without any locking, simple select and update
+
2011-11-08 The InnoDB Team
* btr/btr0pcur.c, include/btr0pcur.h, include/btr0pcur.ic:
diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc
index 35b2dcec23c..5ed4abe3d08 100644
--- a/storage/innodb_plugin/handler/ha_innodb.cc
+++ b/storage/innodb_plugin/handler/ha_innodb.cc
@@ -4793,8 +4793,7 @@ no_commit:
switch (sql_command) {
case SQLCOM_LOAD:
- if ((trx->duplicates
- & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
+ if (trx->duplicates) {
goto set_max_autoinc;
}
@@ -5069,8 +5068,7 @@ ha_innobase::update_row(
&& table->next_number_field
&& new_row == table->record[0]
&& thd_sql_command(user_thd) == SQLCOM_INSERT
- && (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
- == TRX_DUP_IGNORE) {
+ && trx->duplicates) {
ulonglong auto_inc;
ulonglong col_max_value;
@@ -8423,6 +8421,7 @@ ha_innobase::extra(
break;
case HA_EXTRA_RESET_STATE:
reset_template(prebuilt);
+ thd_to_trx(ha_thd())->duplicates = 0;
break;
case HA_EXTRA_NO_KEYREAD:
prebuilt->read_just_key = 0;
@@ -8440,19 +8439,18 @@ ha_innobase::extra(
parameters below. We must not invoke update_thd()
either, because the calling threads may change.
CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
- case HA_EXTRA_IGNORE_DUP_KEY:
+ case HA_EXTRA_INSERT_WITH_UPDATE:
thd_to_trx(ha_thd())->duplicates |= TRX_DUP_IGNORE;
break;
+ case HA_EXTRA_NO_IGNORE_DUP_KEY:
+ thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_IGNORE;
+ break;
case HA_EXTRA_WRITE_CAN_REPLACE:
thd_to_trx(ha_thd())->duplicates |= TRX_DUP_REPLACE;
break;
case HA_EXTRA_WRITE_CANNOT_REPLACE:
thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_REPLACE;
break;
- case HA_EXTRA_NO_IGNORE_DUP_KEY:
- thd_to_trx(ha_thd())->duplicates &=
- ~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
- break;
default:/* Do nothing */
;
}
diff --git a/storage/innodb_plugin/row/row0ins.c b/storage/innodb_plugin/row/row0ins.c
index 0f158cdc706..b14ae3de2bd 100644
--- a/storage/innodb_plugin/row/row0ins.c
+++ b/storage/innodb_plugin/row/row0ins.c
@@ -1662,7 +1662,7 @@ row_ins_scan_sec_index_for_duplicate(
ulint n_fields_cmp;
btr_pcur_t pcur;
ulint err = DB_SUCCESS;
- unsigned allow_duplicates;
+ ulint allow_duplicates;
mtr_t mtr;
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
@@ -1693,7 +1693,7 @@ row_ins_scan_sec_index_for_duplicate(
btr_pcur_open(index, entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr);
- allow_duplicates = thr_get_trx(thr)->duplicates & TRX_DUP_IGNORE;
+ allow_duplicates = thr_get_trx(thr)->duplicates;
/* Scan index records and check if there is a duplicate */
@@ -1827,7 +1827,7 @@ row_ins_duplicate_error_in_clust(
sure that in roll-forward we get the same duplicate
errors as in original execution */
- if (trx->duplicates & TRX_DUP_IGNORE) {
+ if (trx->duplicates) {
/* If the SQL-query will update or replace
duplicate key we will take X-lock for
@@ -1871,7 +1871,7 @@ row_ins_duplicate_error_in_clust(
offsets = rec_get_offsets(rec, cursor->index, offsets,
ULINT_UNDEFINED, &heap);
- if (trx->duplicates & TRX_DUP_IGNORE) {
+ if (trx->duplicates) {
/* If the SQL-query will update or replace
duplicate key we will take X-lock for