Skip to content

Commit

Permalink
Merge branch 'bug1486747-5.5' into bug1486747-5.6.
Browse files Browse the repository at this point in the history
Additionally re-record innodb.innodb-alter-autoinc to account for autoinc
gaps resulting from InnoDB reserving autoinc values more closely to the
estimated row count for bulk inserts.
  • Loading branch information
laurynas-biveinis committed Sep 4, 2015
2 parents f7fa8f7 + bd9d2eb commit c0b58a3
Show file tree
Hide file tree
Showing 12 changed files with 118 additions and 29 deletions.
3 changes: 2 additions & 1 deletion mysql-test/include/strict_autoinc.inc
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ select count(*) from t1;

set auto_increment_increment=1000;
set auto_increment_offset=700;
--error ER_WARN_DATA_OUT_OF_RANGE
--error ER_WARN_DATA_OUT_OF_RANGE,ER_AUTOINC_READ_FAILED
insert into t1 values(null);
select count(*) from t1;

set @@sql_mode=@org_mode;
--error 0,ER_AUTOINC_READ_FAILED
insert into t1 values(null);
select * from t1;

Expand Down
2 changes: 1 addition & 1 deletion mysql-test/r/strict_autoinc_1myisam.result
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ count(*)
set auto_increment_increment=1000;
set auto_increment_offset=700;
insert into t1 values(null);
ERROR 22003: Out of range value for column 'a' at row 1
Got one of the listed errors
select count(*) from t1;
count(*)
0
Expand Down
5 changes: 1 addition & 4 deletions mysql-test/r/strict_autoinc_2innodb.result
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,12 @@ count(*)
set auto_increment_increment=1000;
set auto_increment_offset=700;
insert into t1 values(null);
ERROR 22003: Out of range value for column 'a' at row 1
Got one of the listed errors
select count(*) from t1;
count(*)
0
set @@sql_mode=@org_mode;
insert into t1 values(null);
Warnings:
Warning 1264 Out of range value for column 'a' at row 1
select * from t1;
a
127
drop table t1;
2 changes: 1 addition & 1 deletion mysql-test/r/strict_autoinc_3heap.result
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ count(*)
set auto_increment_increment=1000;
set auto_increment_offset=700;
insert into t1 values(null);
ERROR 22003: Out of range value for column 'a' at row 1
Got one of the listed errors
select count(*) from t1;
count(*)
0
Expand Down
22 changes: 22 additions & 0 deletions mysql-test/suite/innodb/r/bug76872.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
SELECT @@innodb_autoinc_lock_mode;
@@innodb_autoinc_lock_mode
1
CREATE TABLE `test` (
`test_id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`testcol` varchar(256)
) ENGINE=InnoDB;
INSERT INTO `test` (`testcol`) VALUES ('aldsldjfhasjk');
SET SESSION auto_increment_increment = 2;
SET DEBUG_SYNC="ib_after_row_insert SIGNAL insert_1_ready WAIT_FOR insert_1_finish";
INSERT INTO `test` (`testcol`) VALUES ('aldsldjfhasjk');
SET SESSION auto_increment_increment = 2;
SET DEBUG_SYNC="now WAIT_FOR insert_1_ready";
SET DEBUG_SYNC="ib_before_row_insert SIGNAL insert_1_finish WAIT_FOR insert_2_finish";
INSERT INTO `test` (`testcol`) VALUES ('aldsldjfhasjk');
SET DEBUG_SYNC="now SIGNAL insert_2_finish";
SELECT * FROM test;
test_id testcol
1 aldsldjfhasjk
3 aldsldjfhasjk
5 aldsldjfhasjk
DROP TABLE test;
6 changes: 3 additions & 3 deletions mysql-test/suite/innodb/r/innodb-alter-autoinc.result
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ t1 CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
KEY `id` (`id`,`a`)
) ENGINE=InnoDB AUTO_INCREMENT=70 DEFAULT CHARSET=latin1
) ENGINE=InnoDB AUTO_INCREMENT=75 DEFAULT CHARSET=latin1
INSERT INTO t1 SET a=123;
INSERT INTO t1 VALUES(-123,-45);
ALTER TABLE t1 AUTO_INCREMENT = 75;
Expand All @@ -161,14 +161,14 @@ a id
123 55
347 60
33101 65
123 70
123 75
123 80
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) NOT NULL DEFAULT '0',
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
KEY `id` (`id`,`a`)
) ENGINE=InnoDB AUTO_INCREMENT=80 DEFAULT CHARSET=latin1
) ENGINE=InnoDB AUTO_INCREMENT=85 DEFAULT CHARSET=latin1
DROP TABLE t1;
2 changes: 1 addition & 1 deletion mysql-test/suite/innodb/r/innodb-autoinc.result
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ Variable_name Value
auto_increment_increment 65535
auto_increment_offset 65535
INSERT INTO t1 VALUES (NULL),(NULL);
ERROR 22003: Out of range value for column 't1' at row 167
ERROR HY000: Failed to read auto-increment value from storage engine
SELECT * FROM t1;
c1
1
Expand Down
38 changes: 38 additions & 0 deletions mysql-test/suite/innodb/t/bug76872.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#
# Test for bug #76872: InnoDB AUTO_INCREMENT produces same value twice
#
--source include/have_innodb.inc
--source include/have_debug_sync.inc
--source include/count_sessions.inc

# Should be != 0
SELECT @@innodb_autoinc_lock_mode;

CREATE TABLE `test` (
`test_id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`testcol` varchar(256)
) ENGINE=InnoDB;

INSERT INTO `test` (`testcol`) VALUES ('aldsldjfhasjk');

SET SESSION auto_increment_increment = 2;
SET DEBUG_SYNC="ib_after_row_insert SIGNAL insert_1_ready WAIT_FOR insert_1_finish";
send INSERT INTO `test` (`testcol`) VALUES ('aldsldjfhasjk');
--connect(con1,localhost,root,,)
--connection con1
SET SESSION auto_increment_increment = 2;
SET DEBUG_SYNC="now WAIT_FOR insert_1_ready";
SET DEBUG_SYNC="ib_before_row_insert SIGNAL insert_1_finish WAIT_FOR insert_2_finish";
send INSERT INTO `test` (`testcol`) VALUES ('aldsldjfhasjk');
--connection default
reap;
SET DEBUG_SYNC="now SIGNAL insert_2_finish";
--connection con1
reap;
--disconnect con1
--connection default

SELECT * FROM test;

DROP TABLE test;
--source include/wait_until_count_sessions.inc
2 changes: 1 addition & 1 deletion mysql-test/suite/innodb/t/innodb-autoinc.test
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ INSERT INTO t1 VALUES (18446744073709551610); #-- 2^64 - 2
SELECT * FROM t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCREMENT_OFFSET=1152921504606846976;
SHOW VARIABLES LIKE "%auto_inc%";
--error ER_WARN_DATA_OUT_OF_RANGE
--error ER_AUTOINC_READ_FAILED
INSERT INTO t1 VALUES (NULL),(NULL);
SELECT * FROM t1;
DROP TABLE t1;
Expand Down
24 changes: 7 additions & 17 deletions sql/handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3294,23 +3294,8 @@ int handler::read_first_row(uchar * buf, uint primary_key)
inline ulonglong
compute_next_insert_id(ulonglong nr,struct system_variables *variables)
{
const ulonglong save_nr= nr;

if (variables->auto_increment_increment == 1)
nr= nr + 1; // optimization of the formula below
else
{
nr= (((nr+ variables->auto_increment_increment -
variables->auto_increment_offset)) /
(ulonglong) variables->auto_increment_increment);
nr= (nr* (ulonglong) variables->auto_increment_increment +
variables->auto_increment_offset);
}

if (unlikely(nr <= save_nr))
return ULONGLONG_MAX;

return nr;
return compute_next_insert_id(nr, variables->auto_increment_increment,
variables->auto_increment_offset);
}


Expand Down Expand Up @@ -3551,7 +3536,12 @@ int handler::update_auto_increment()
it. Hope that this rounding didn't push us out of the interval; even
if it did we cannot do anything about it (calling the engine again
will not help as we inserted no row).
Assert that this rounding is a no-op for InnoDB, which should respect
offset and increment. Otherwise we can go outside the interval and
result in duplicate key errors, see bug 76872.
*/
DBUG_ASSERT(compute_next_insert_id(nr - 1, variables) == nr
|| ht->db_type != DB_TYPE_INNODB);
nr= compute_next_insert_id(nr-1, variables);
}

Expand Down
33 changes: 33 additions & 0 deletions sql/handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -3490,6 +3490,39 @@ static inline bool ha_storage_engine_is_enabled(const handlerton *db_type)
(db_type->state == SHOW_OPTION_YES) : FALSE;
}

/**
Generate the next auto-increment number based on increment and offset.
computes the lowest number
- strictly greater than "nr"
- of the form: auto_increment_offset + N * auto_increment_increment
If overflow happened then return MAX_ULONGLONG value as an
indication of overflow.
In most cases increment= offset= 1, in which case we get:
@verbatim 1,2,3,4,5,... @endverbatim
If increment=10 and offset=5 and previous number is 1, we get:
@verbatim 1,5,15,25,35,... @endverbatim
*/
inline ulonglong
compute_next_insert_id(ulonglong nr, ulonglong auto_increment_increment,
ulonglong auto_increment_offset)
{
const ulonglong save_nr= nr;

if (auto_increment_increment == 1)
nr= nr + 1; // optimization of the formula below
else
{
nr= (((nr + auto_increment_increment - auto_increment_offset)) /
auto_increment_increment);
nr= (nr * auto_increment_increment + auto_increment_offset);
}

if (unlikely(nr <= save_nr))
return ULONGLONG_MAX;

return nr;
}

/* basic stuff */
int ha_init_errors(void);
int ha_init(void);
Expand Down
8 changes: 8 additions & 0 deletions storage/innobase/handler/ha_innodb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7330,6 +7330,7 @@ ha_innobase::write_row(

innobase_srv_conc_enter_innodb(prebuilt->trx);

DEBUG_SYNC(user_thd, "ib_before_row_insert");
error = row_insert_for_mysql((byte*) record, prebuilt);
DEBUG_SYNC(user_thd, "ib_after_row_insert");

Expand Down Expand Up @@ -14047,6 +14048,13 @@ ha_innobase::get_auto_increment(
}

set_if_bigger(*first_value, autoinc);

/* Honor increment and offset or handler will do that for us,
clobbering unused autoinc value past the end of interval */
set_if_bigger(*first_value,
compute_next_insert_id(*first_value - 1,
increment, offset));

/* Not in the middle of a mult-row INSERT. */
} else if (prebuilt->autoinc_last_value == 0) {
set_if_bigger(*first_value, autoinc);
Expand Down

0 comments on commit c0b58a3

Please sign in to comment.