Commit 2ae86017 authored by Timothy Smith's avatar Timothy Smith

Apply InnoDB snapshot innodb-5.1-ss2858, part 14. Fixes

Bug #37788: InnoDB Plugin: AUTO_INCREMENT wrong for compressed tables

(Note, this bug is not only in the plugin, the overflow checks are relevant
for MySQL's InnoDB as well.)


Detailed revision comments:

r2852 | sunny | 2008-10-23 01:42:24 +0300 (Thu, 23 Oct 2008) | 9 lines
branches/5.1: Backport r2724 from branches/zip

Check column value against the col max value before updating the table's
global autoinc counter value. This is part of simplifying the AUTOINC
sub-system. We extract the type info from MySQL data structures at runtime.
parent 2fb7a53f
......@@ -945,7 +945,8 @@ innobase_next_autoinc(
/* out: the next value */
ulonglong current, /* in: Current value */
ulonglong increment, /* in: increment current by */
ulonglong offset) /* in: AUTOINC offset */
ulonglong offset, /* in: AUTOINC offset */
ulonglong max_value) /* in: max value for type */
{
ulonglong next_value;
......@@ -955,8 +956,8 @@ innobase_next_autoinc(
if (offset <= 1) {
/* Offset 0 and 1 are the same, because there must be at
least one node in the system. */
if (~0x0ULL - current <= increment) {
next_value = ~0x0ULL;
if (max_value - current <= increment) {
next_value = max_value;
} else {
next_value = current + increment;
}
......@@ -971,15 +972,15 @@ innobase_next_autoinc(
ut_a(next_value > 0);
/* Check for multiplication overflow. */
if (increment > (~0x0ULL / next_value)) {
if (increment > (max_value / next_value)) {
next_value = ~0x0ULL;
next_value = max_value;
} else {
next_value *= increment;
/* Check for overflow. */
if (~0x0ULL - next_value <= offset) {
next_value = ~0x0ULL;
if (max_value - next_value <= offset) {
next_value = max_value;
} else {
next_value += offset;
}
......@@ -3339,6 +3340,59 @@ build_template(
}
}
/************************************************************************
Get the upper limit of the MySQL integral type. */
ulonglong
ha_innobase::innobase_get_int_col_max_value(
/*========================================*/
const Field* field)
{
ulonglong max_value = 0;
switch(field->key_type()) {
/* TINY */
case HA_KEYTYPE_BINARY:
max_value = 0xFFULL;
break;
case HA_KEYTYPE_INT8:
max_value = 0x7FULL;
break;
/* SHORT */
case HA_KEYTYPE_USHORT_INT:
max_value = 0xFFFFULL;
break;
case HA_KEYTYPE_SHORT_INT:
max_value = 0x7FFFULL;
break;
/* MEDIUM */
case HA_KEYTYPE_UINT24:
max_value = 0xFFFFFFULL;
break;
case HA_KEYTYPE_INT24:
max_value = 0x7FFFFFULL;
break;
/* LONG */
case HA_KEYTYPE_ULONG_INT:
max_value = 0xFFFFFFFFULL;
break;
case HA_KEYTYPE_LONG_INT:
max_value = 0x7FFFFFFFULL;
break;
/* BIG */
case HA_KEYTYPE_ULONGLONG:
max_value = 0xFFFFFFFFFFFFFFFFULL;
break;
case HA_KEYTYPE_LONGLONG:
max_value = 0x7FFFFFFFFFFFFFFFULL;
break;
default:
ut_error;
}
return(max_value);
}
/************************************************************************
This special handling is really to overcome the limitations of MySQL's
binlogging. We need to eliminate the non-determinism that will arise in
......@@ -3598,6 +3652,7 @@ ha_innobase::write_row(
if (auto_inc_used) {
ulint err;
ulonglong auto_inc;
ulonglong col_max_value;
/* Note the number of rows processed for this statement, used
by get_auto_increment() to determine the number of AUTO-INC
......@@ -3607,6 +3662,11 @@ ha_innobase::write_row(
--trx->n_autoinc_rows;
}
/* We need the upper limit of the col type to check for
whether we update the table autoinc counter or not. */
col_max_value = innobase_get_int_col_max_value(
table->next_number_field);
/* Get the value that MySQL attempted to store in the table.*/
auto_inc = table->next_number_field->val_int();
......@@ -3645,7 +3705,8 @@ ha_innobase::write_row(
update the table upper limit. Note: last_value
will be 0 if get_auto_increment() was not called.*/
if (auto_inc > prebuilt->autoinc_last_value) {
if (auto_inc < col_max_value
&& auto_inc > prebuilt->autoinc_last_value) {
set_max_autoinc:
ut_a(prebuilt->autoinc_increment > 0);
......@@ -3656,7 +3717,7 @@ ha_innobase::write_row(
need = prebuilt->autoinc_increment;
auto_inc = innobase_next_autoinc(
auto_inc, need, offset);
auto_inc, need, offset, col_max_value);
err = innobase_set_max_autoinc(auto_inc);
......@@ -3894,11 +3955,17 @@ ha_innobase::update_row(
&& (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
== TRX_DUP_IGNORE) {
longlong auto_inc;
ulonglong auto_inc;
ulonglong col_max_value;
auto_inc = table->next_number_field->val_int();
if (auto_inc != 0) {
/* We need the upper limit of the col type to check for
whether we update the table autoinc counter or not. */
col_max_value = innobase_get_int_col_max_value(
table->next_number_field);
if (auto_inc < col_max_value && auto_inc != 0) {
ulonglong need;
ulonglong offset;
......@@ -3907,7 +3974,7 @@ ha_innobase::update_row(
need = prebuilt->autoinc_increment;
auto_inc = innobase_next_autoinc(
auto_inc, need, offset);
auto_inc, need, offset, col_max_value);
error = innobase_set_max_autoinc(auto_inc);
}
......@@ -7632,11 +7699,18 @@ ha_innobase::get_auto_increment(
if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) {
ulonglong need;
ulonglong next_value;
ulonglong col_max_value;
/* We need the upper limit of the col type to check for
whether we update the table autoinc counter or not. */
col_max_value = innobase_get_int_col_max_value(
table->next_number_field);
need = *nb_reserved_values * increment;
/* Compute the last value in the interval */
next_value = innobase_next_autoinc(*first_value, need, offset);
next_value = innobase_next_autoinc(
*first_value, need, offset, col_max_value);
prebuilt->autoinc_last_value = next_value;
......
......@@ -78,6 +78,7 @@ class ha_innobase: public handler
ulong innobase_reset_autoinc(ulonglong auto_inc);
ulong innobase_get_auto_increment(ulonglong* value);
dict_index_t* innobase_get_index(uint keynr);
ulonglong innobase_get_int_col_max_value(const Field* field);
/* Init values for the class: */
public:
......
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