Commit 165ca17f authored by sunny's avatar sunny

branches/5.1: Return the actual error code encountered when allocating

a new autoinc value. The change in behavior (bug) was introduced in 5.1.22
when we introduced the new AUTOINC locking model.

rb://31

Bug#40224 New AUTOINC changes mask reporting of deadlock/timeout errors
parent 67a913e9
......@@ -3561,8 +3561,20 @@ ha_innobase::write_row(
/* This is the case where the table has an auto-increment column */
if (table->next_number_field && record == table->record[0]) {
/* Reset the error code before calling
innobase_get_auto_increment(). */
prebuilt->autoinc_error = DB_SUCCESS;
if ((error = update_auto_increment())) {
/* We don't want to mask autoinc overflow errors. */
if (prebuilt->autoinc_error != DB_SUCCESS) {
error = prebuilt->autoinc_error;
goto report_error;
}
/* MySQL errors are passed straight back. */
goto func_exit;
}
......@@ -3658,6 +3670,7 @@ ha_innobase::write_row(
innodb_srv_conc_exit_innodb(prebuilt->trx);
report_error:
error = convert_error_code_to_mysql(error, user_thd);
func_exit:
......@@ -6056,25 +6069,12 @@ ha_innobase::info(
if (flag & HA_STATUS_AUTO && table->found_next_number_field) {
ulonglong auto_inc;
int ret;
/* The following function call can the first time fail in
a lock wait timeout error because it reserves the auto-inc
lock on the table. If it fails, then someone is already initing
the auto-inc counter, and the second call is guaranteed to
succeed. */
ret = innobase_read_and_init_auto_inc(&auto_inc);
if (ret != 0) {
ret = innobase_read_and_init_auto_inc(&auto_inc);
if (ret != 0) {
sql_print_error("Cannot get table %s auto-inc"
"counter value in ::info\n",
ib_table->name);
auto_inc = 0;
}
if (innobase_read_and_init_auto_inc(&auto_inc) != 0) {
sql_print_error("Cannot get table %s auto-inc"
"counter value in ::info\n",
ib_table->name);
auto_inc = 0;
}
stats.auto_increment_value = auto_inc;
......@@ -7459,7 +7459,6 @@ ha_innobase::innobase_read_and_init_auto_inc(
if (auto_inc == 0) {
dict_index_t* index;
ulint error;
const char* autoinc_col_name;
ut_a(!innodb_table->autoinc_inited);
......@@ -7468,10 +7467,10 @@ ha_innobase::innobase_read_and_init_auto_inc(
autoinc_col_name = table->found_next_number_field->field_name;
error = row_search_max_autoinc(
prebuilt->autoinc_error = row_search_max_autoinc(
index, autoinc_col_name, &auto_inc);
if (error == DB_SUCCESS) {
if (prebuilt->autoinc_error == DB_SUCCESS) {
if (auto_inc < ~0x0ULL) {
++auto_inc;
}
......@@ -7480,7 +7479,7 @@ ha_innobase::innobase_read_and_init_auto_inc(
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Error: (%lu) Couldn't read "
"the max AUTOINC value from the index (%s).\n",
error, index->name);
prebuilt->autoinc_error, index->name);
mysql_error = 1;
}
......@@ -7511,22 +7510,23 @@ ha_innobase::innobase_read_and_init_auto_inc(
Read the next autoinc value, initialize the table if it's not initialized.
On return if there is no error then the tables AUTOINC lock is locked.*/
ulong
ulint
ha_innobase::innobase_get_auto_increment(
/*=====================================*/
ulonglong* value) /* out: autoinc value */
{
ulong error;
*value = 0;
/* Note: If the table is not initialized when we attempt the
read below. We initialize the table's auto-inc counter and
always do a reread of the AUTOINC value. */
do {
error = innobase_autoinc_lock();
/* We need to send the correct error code to the client
because handler::get_auto_increment() doesn't allow a way
to return the specific error for why it failed. */
prebuilt->autoinc_error = innobase_autoinc_lock();
if (error == DB_SUCCESS) {
if (prebuilt->autoinc_error == DB_SUCCESS) {
ulonglong autoinc;
/* Determine the first value of the interval */
......@@ -7548,46 +7548,17 @@ ha_innobase::innobase_get_auto_increment(
/* Just to make sure */
ut_a(!trx->auto_inc_lock);
int mysql_error;
mysql_error = innobase_read_and_init_auto_inc(
&autoinc);
/* Will set prebuilt->autoinc_error if there
is a problem during init. */
innobase_read_and_init_auto_inc(&autoinc);
if (mysql_error) {
error = DB_ERROR;
}
} else {
*value = autoinc;
}
/* We need to send the messages to the client because
handler::get_auto_increment() doesn't allow a way
to return the specific error for why it failed. */
} else if (error == DB_DEADLOCK) {
THD* thd = ha_thd();
push_warning(
thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_LOCK_DEADLOCK,
"InnoDB: Deadlock in "
"innobase_get_auto_increment()");
} else if (error == DB_LOCK_WAIT_TIMEOUT) {
THD* thd = ha_thd();
push_warning(
thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_LOCK_WAIT_TIMEOUT,
"InnoDB: Lock wait timeout in "
"innobase_get_auto_increment()");
} else {
sql_print_error(
"InnoDB: Error: %lu in "
"innobase_get_auto_increment()",
error);
}
} while (*value == 0 && error == DB_SUCCESS);
} while (*value == 0 && prebuilt->autoinc_error == DB_SUCCESS);
return(error);
return(prebuilt->autoinc_error);
}
/*******************************************************************************
......
......@@ -692,6 +692,11 @@ struct row_prebuilt_struct {
ulonglong autoinc_offset; /* The offset passed to
get_auto_increment() by MySQL. Required
to calculate the next value */
ulint autoinc_error; /* The actual error code encountered
while trying to init or read the
autoinc value from the table. We
store it here so that we can return
it to MySQL */
/*----------------------*/
ulint magic_n2; /* this should be the same as
magic_n */
......
......@@ -661,6 +661,7 @@ row_create_prebuilt(
prebuilt->old_vers_heap = NULL;
prebuilt->autoinc_error = 0;
prebuilt->autoinc_offset = 0;
/* Default to 1, we will set the actual value later in
......
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