ha_innodb.h, ha_innodb.cc:

  Fix bug #10359 : the critical AUTO-INC bug in InnoDB; since reading of the auto-inc counter in an INSERT was not protected by the AUTO-INC table lock of InnoDB, two inserted rows could get the same value for the auto-inc counter, leading to a duplicate key error
parent 56fa40e5
...@@ -3170,12 +3170,28 @@ no_commit: ...@@ -3170,12 +3170,28 @@ no_commit:
prebuilt->sql_stat_start = TRUE; prebuilt->sql_stat_start = TRUE;
} }
/* /* We have to use the transactional lock mechanism on the
We must use the handler code to update the auto-increment auto-inc counter of the table to ensure that replication and
value to be sure that increment it correctly. roll-forward of the binlog exactly imitates also the given
*/ auto-inc values. The lock is released at each SQL statement's
end. This lock also prevents a race where two threads would
call ::get_auto_increment() simultaneously. */
error = row_lock_table_autoinc_for_mysql(prebuilt);
if (error != DB_SUCCESS) {
/* Deadlock or lock wait timeout */
error = convert_error_code_to_mysql(error, user_thd);
goto func_exit;
}
/* We must use the handler code to update the auto-increment
value to be sure that we increment it correctly. */
update_auto_increment(); update_auto_increment();
auto_inc_used= 1; auto_inc_used = 1;
} }
...@@ -3198,24 +3214,15 @@ no_commit: ...@@ -3198,24 +3214,15 @@ no_commit:
auto_inc = table->next_number_field->val_int(); auto_inc = table->next_number_field->val_int();
if (auto_inc != 0) { if (auto_inc != 0) {
/* This call will calculate the max of the current /* This call will update the counter according to the
value and the value supplied by the user and value that was inserted in the table */
update the counter accordingly */
/* We have to use the transactional lock mechanism
on the auto-inc counter of the table to ensure
that replication and roll-forward of the binlog
exactly imitates also the given auto-inc values.
The lock is released at each SQL statement's
end. */
error = row_lock_table_autoinc_for_mysql(prebuilt);
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {
error = convert_error_code_to_mysql(error, error = convert_error_code_to_mysql(error,
user_thd); user_thd);
goto func_exit; goto func_exit;
} }
dict_table_autoinc_update(prebuilt->table, auto_inc); dict_table_autoinc_update(prebuilt->table, auto_inc);
} }
} }
...@@ -5795,7 +5802,6 @@ ha_innobase::start_stmt( ...@@ -5795,7 +5802,6 @@ ha_innobase::start_stmt(
read_view_close_for_mysql(trx); read_view_close_for_mysql(trx);
} }
auto_inc_counter_for_this_stat = 0;
prebuilt->sql_stat_start = TRUE; prebuilt->sql_stat_start = TRUE;
prebuilt->hint_need_to_fetch_extra_cols = 0; prebuilt->hint_need_to_fetch_extra_cols = 0;
prebuilt->read_just_key = 0; prebuilt->read_just_key = 0;
...@@ -5985,7 +5991,7 @@ ha_innobase::external_lock( ...@@ -5985,7 +5991,7 @@ ha_innobase::external_lock(
trx->n_mysql_tables_in_use--; trx->n_mysql_tables_in_use--;
prebuilt->mysql_has_locked = FALSE; prebuilt->mysql_has_locked = FALSE;
auto_inc_counter_for_this_stat = 0;
if (trx->n_lock_table_exp) { if (trx->n_lock_table_exp) {
row_unlock_tables_for_mysql(trx); row_unlock_tables_for_mysql(trx);
} }
...@@ -6505,7 +6511,7 @@ ha_innobase::store_lock( ...@@ -6505,7 +6511,7 @@ ha_innobase::store_lock(
/*********************************************************************** /***********************************************************************
This function initializes the auto-inc counter if it has not been This function initializes the auto-inc counter if it has not been
initialized yet. This function does not change the value of the auto-inc initialized yet. This function does not change the value of the auto-inc
counter if it already has been initialized. In paramete ret returns counter if it already has been initialized. In parameter ret returns
the value of the auto-inc counter. */ the value of the auto-inc counter. */
int int
...@@ -6624,7 +6630,14 @@ ha_innobase::get_auto_increment() ...@@ -6624,7 +6630,14 @@ ha_innobase::get_auto_increment()
error = innobase_read_and_init_auto_inc(&nr); error = innobase_read_and_init_auto_inc(&nr);
if (error) { if (error) {
/* This should never happen in the current (5.0.6) code, since
we call this function only after the counter has been
initialized. */
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: error %lu in ::get_auto_increment()\n",
(ulong)error);
return(~(ulonglong) 0); return(~(ulonglong) 0);
} }
......
...@@ -70,7 +70,6 @@ class ha_innobase: public handler ...@@ -70,7 +70,6 @@ class ha_innobase: public handler
ROW_SEL_EXACT, ROW_SEL_EXACT_PREFIX, ROW_SEL_EXACT, ROW_SEL_EXACT_PREFIX,
or undefined */ or undefined */
uint num_write_row; /* number of write_row() calls */ uint num_write_row; /* number of write_row() calls */
longlong auto_inc_counter_for_this_stat;
ulong max_supported_row_length(const byte *buf); ulong max_supported_row_length(const byte *buf);
uint store_key_val_for_row(uint keynr, char* buff, uint buff_len, uint store_key_val_for_row(uint keynr, char* buff, uint buff_len,
......
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