diff options
author | Timothy Smith <timothy.smith@sun.com> | 2008-12-14 13:57:54 -0700 |
---|---|---|
committer | Timothy Smith <timothy.smith@sun.com> | 2008-12-14 13:57:54 -0700 |
commit | 5e421fb8fe54b51979761b49416cc463b4eaf652 (patch) | |
tree | 4e38a0c57c4dde5a9689923493ed0c50153a0784 /storage/innobase | |
parent | a32e048645cb2bf3435f8f95eb36958aeaba0f3a (diff) | |
download | mariadb-git-5e421fb8fe54b51979761b49416cc463b4eaf652.tar.gz |
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.
Diffstat (limited to 'storage/innobase')
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 100 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.h | 1 |
2 files changed, 88 insertions, 13 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 195ec799ce9..ab4d4e96cef 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -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; } @@ -3340,6 +3341,59 @@ skip_field: } /************************************************************************ +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 INSERT ... SELECT type of statements, since MySQL binlog only stores the @@ -3598,6 +3652,7 @@ no_commit: 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 @@ no_commit: --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 @@ no_commit: 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 @@ set_max_autoinc: 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; diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 4ffcdb1e3c2..95890e2215d 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -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: |