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 @@ ha_innobase::write_row(
prebuilt->sql_stat_start = TRUE;
}
/*
We must use the handler code to update the auto-increment
value to be sure that increment it correctly.
*/
/* 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. 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();
auto_inc_used= 1;
auto_inc_used = 1;
}
......@@ -3198,24 +3214,15 @@ ha_innobase::write_row(
auto_inc = table->next_number_field->val_int();
if (auto_inc != 0) {
/* This call will calculate the max of the current
value and the value supplied by the user and
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);
/* This call will update the counter according to the
value that was inserted in the table */
if (error != DB_SUCCESS) {
error = convert_error_code_to_mysql(error,
user_thd);
goto func_exit;
}
dict_table_autoinc_update(prebuilt->table, auto_inc);
}
}
......@@ -5795,7 +5802,6 @@ ha_innobase::start_stmt(
read_view_close_for_mysql(trx);
}
auto_inc_counter_for_this_stat = 0;
prebuilt->sql_stat_start = TRUE;
prebuilt->hint_need_to_fetch_extra_cols = 0;
prebuilt->read_just_key = 0;
......@@ -5985,7 +5991,7 @@ ha_innobase::external_lock(
trx->n_mysql_tables_in_use--;
prebuilt->mysql_has_locked = FALSE;
auto_inc_counter_for_this_stat = 0;
if (trx->n_lock_table_exp) {
row_unlock_tables_for_mysql(trx);
}
......@@ -6505,7 +6511,7 @@ ha_innobase::store_lock(
/***********************************************************************
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
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. */
int
......@@ -6624,7 +6630,14 @@ ha_innobase::get_auto_increment()
error = innobase_read_and_init_auto_inc(&nr);
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);
}
......
......@@ -70,7 +70,6 @@ class ha_innobase: public handler
ROW_SEL_EXACT, ROW_SEL_EXACT_PREFIX,
or undefined */
uint num_write_row; /* number of write_row() calls */
longlong auto_inc_counter_for_this_stat;
ulong max_supported_row_length(const byte *buf);
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