summaryrefslogtreecommitdiff
path: root/storage/innobase
diff options
context:
space:
mode:
authorTimothy Smith <timothy.smith@sun.com>2008-12-14 13:57:54 -0700
committerTimothy Smith <timothy.smith@sun.com>2008-12-14 13:57:54 -0700
commit5e421fb8fe54b51979761b49416cc463b4eaf652 (patch)
tree4e38a0c57c4dde5a9689923493ed0c50153a0784 /storage/innobase
parenta32e048645cb2bf3435f8f95eb36958aeaba0f3a (diff)
downloadmariadb-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.cc100
-rw-r--r--storage/innobase/handler/ha_innodb.h1
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: