Commit d1e6b0bc authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-20927 Duplicate key with auto increment

Apply the changes to InnoDB and XtraDB that had been
inadvertently skipped in the merge
commit ae476868

That merge failure sabotaged part of MDEV-20127:
>Revert a problematic auto_increment_increment 'fix' from 2014.
>This involves replacing the MDEV-8827 fix and in 10.1,
>removing some WSREP instrumentation.

The code changes were re-merged manually by executing the following:

 # Get the parent of the problematic merge.
git checkout ae476868^
 # Perform the merge again.
git merge ae476868^2
 # Get the conflict resolution from that merge.
git checkout ae476868 .
 # Note: Any changes to these files were removed (empty diff)!
git diff HEAD storage/{innobase,xtradb}/handler/ha_innodb.cc
 # Apply the code changes:
git diff cf403934^2..MERGE_HEAD \
storage/{innobase,xtradb}/handler/ha_innodb.cc|
patch -p1
parent b8eff8bc
...@@ -148,7 +148,7 @@ t1 CREATE TABLE `t1` ( ...@@ -148,7 +148,7 @@ t1 CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `id` (`id`,`a`) KEY `id` (`id`,`a`)
) ENGINE=InnoDB AUTO_INCREMENT=75 DEFAULT CHARSET=latin1 ) ENGINE=InnoDB AUTO_INCREMENT=70 DEFAULT CHARSET=latin1
INSERT INTO t1 SET a=123; INSERT INTO t1 SET a=123;
INSERT INTO t1 VALUES(-123,-45); INSERT INTO t1 VALUES(-123,-45);
ALTER TABLE t1 AUTO_INCREMENT = 75; ALTER TABLE t1 AUTO_INCREMENT = 75;
...@@ -161,8 +161,8 @@ a id ...@@ -161,8 +161,8 @@ a id
123 55 123 55
347 60 347 60
33101 65 33101 65
123 70
123 75 123 75
123 80
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
...@@ -170,5 +170,5 @@ t1 CREATE TABLE `t1` ( ...@@ -170,5 +170,5 @@ t1 CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `id` (`id`,`a`) KEY `id` (`id`,`a`)
) ENGINE=InnoDB AUTO_INCREMENT=85 DEFAULT CHARSET=latin1 ) ENGINE=InnoDB AUTO_INCREMENT=80 DEFAULT CHARSET=latin1
DROP TABLE t1; DROP TABLE t1;
...@@ -567,7 +567,7 @@ Variable_name Value ...@@ -567,7 +567,7 @@ Variable_name Value
auto_increment_increment 65535 auto_increment_increment 65535
auto_increment_offset 65535 auto_increment_offset 65535
INSERT INTO t1 VALUES (NULL),(NULL); INSERT INTO t1 VALUES (NULL),(NULL);
ERROR HY000: Failed to read auto-increment value from storage engine ERROR 22003: Out of range value for column 'c1' at row 1
SELECT * FROM t1; SELECT * FROM t1;
c1 c1
1 1
...@@ -674,7 +674,7 @@ SELECT a,b FROM t; ...@@ -674,7 +674,7 @@ SELECT a,b FROM t;
a b a b
1 S1 1 S1
3 S2 3 S2
4 S2 5 S2
# Client 1: Insert a record with auto_increment_increment=1 # Client 1: Insert a record with auto_increment_increment=1
SET SESSION auto_increment_increment=1; SET SESSION auto_increment_increment=1;
SHOW CREATE TABLE t; SHOW CREATE TABLE t;
...@@ -683,14 +683,14 @@ t CREATE TABLE `t` ( ...@@ -683,14 +683,14 @@ t CREATE TABLE `t` (
`a` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `a` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`b` varchar(200) DEFAULT NULL, `b` varchar(200) DEFAULT NULL,
PRIMARY KEY (`a`) PRIMARY KEY (`a`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1
INSERT INTO t(b) VALUES('S1'); INSERT INTO t(b) VALUES('S1');
SELECT a,b FROM t; SELECT a,b FROM t;
a b a b
1 S1 1 S1
3 S2 3 S2
4 S2 5 S2
5 S1 6 S1
DROP TABLE t; DROP TABLE t;
# Autoincrement behaviour with mixed insert. # Autoincrement behaviour with mixed insert.
CREATE TABLE t( CREATE TABLE t(
...@@ -728,22 +728,22 @@ t CREATE TABLE `t` ( ...@@ -728,22 +728,22 @@ t CREATE TABLE `t` (
`a` tinyint(4) NOT NULL AUTO_INCREMENT, `a` tinyint(4) NOT NULL AUTO_INCREMENT,
`b` varchar(200) DEFAULT NULL, `b` varchar(200) DEFAULT NULL,
PRIMARY KEY (`a`) PRIMARY KEY (`a`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=latin1 ) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=latin1
INSERT INTO t(b) VALUES('S4'); INSERT INTO t(b) VALUES('S4');
SELECT * FROM t; SELECT * FROM t;
a b a b
1 S0 1 S0
11 S1 11 S1
22 S3
23 S4
28 S2 28 S2
31 S3
32 S4
SHOW CREATE TABLE t; SHOW CREATE TABLE t;
Table Create Table Table Create Table
t CREATE TABLE `t` ( t CREATE TABLE `t` (
`a` tinyint(4) NOT NULL AUTO_INCREMENT, `a` tinyint(4) NOT NULL AUTO_INCREMENT,
`b` varchar(200) DEFAULT NULL, `b` varchar(200) DEFAULT NULL,
PRIMARY KEY (`a`) PRIMARY KEY (`a`)
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=latin1 ) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=latin1
DROP TABLE t; DROP TABLE t;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=5; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=5;
DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t1;
...@@ -784,7 +784,7 @@ t2 CREATE TABLE `t2` ( ...@@ -784,7 +784,7 @@ t2 CREATE TABLE `t2` (
`n` int(10) unsigned NOT NULL, `n` int(10) unsigned NOT NULL,
`o` enum('FALSE','TRUE') DEFAULT NULL, `o` enum('FALSE','TRUE') DEFAULT NULL,
PRIMARY KEY (`m`) PRIMARY KEY (`m`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=latin1 ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=latin1
INSERT INTO t1 (b,c) SELECT n,o FROM t2 ; INSERT INTO t1 (b,c) SELECT n,o FROM t2 ;
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
...@@ -1464,13 +1464,13 @@ SELECT * FROM t; ...@@ -1464,13 +1464,13 @@ SELECT * FROM t;
i i
1 1
301 301
351 601
SHOW CREATE TABLE t; SHOW CREATE TABLE t;
Table Create Table Table Create Table
t CREATE TABLE `t` ( t CREATE TABLE `t` (
`i` int(11) NOT NULL AUTO_INCREMENT, `i` int(11) NOT NULL AUTO_INCREMENT,
KEY `i` (`i`) KEY `i` (`i`)
) ENGINE=InnoDB AUTO_INCREMENT=401 DEFAULT CHARSET=latin1 ) ENGINE=InnoDB AUTO_INCREMENT=651 DEFAULT CHARSET=latin1
DROP TABLE t; DROP TABLE t;
# #
# MDEV-14008 Assertion failing: `!is_set() || (m_status == DA_OK_BULK && is_bulk_op()) # MDEV-14008 Assertion failing: `!is_set() || (m_status == DA_OK_BULK && is_bulk_op())
......
...@@ -349,7 +349,7 @@ INSERT INTO t1 VALUES (18446744073709551610); #-- 2^64 - 2 ...@@ -349,7 +349,7 @@ INSERT INTO t1 VALUES (18446744073709551610); #-- 2^64 - 2
SELECT * FROM t1; SELECT * FROM t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCREMENT_OFFSET=1152921504606846976; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCREMENT_OFFSET=1152921504606846976;
SHOW VARIABLES LIKE "auto_inc%"; SHOW VARIABLES LIKE "auto_inc%";
--error 1467 --error HA_ERR_AUTOINC_ERANGE
INSERT INTO t1 VALUES (NULL),(NULL); INSERT INTO t1 VALUES (NULL),(NULL);
SELECT * FROM t1; SELECT * FROM t1;
DROP TABLE t1; DROP TABLE t1;
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2000, 2019, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc. Copyright (c) 2009, Percona Inc.
Copyright (c) 2012, Facebook Inc. Copyright (c) 2012, Facebook Inc.
...@@ -2588,11 +2588,10 @@ innobase_next_autoinc( ...@@ -2588,11 +2588,10 @@ innobase_next_autoinc(
if (next_value == 0) { if (next_value == 0) {
ulonglong next; ulonglong next;
if (current >= offset) { if (current > offset) {
next = (current - offset) / step; next = (current - offset) / step;
} else { } else {
next = 0; next = (offset - current) / step;
block -= step;
} }
ut_a(max_value > next); ut_a(max_value > next);
...@@ -16035,6 +16034,37 @@ ha_innobase::get_auto_increment( ...@@ -16035,6 +16034,37 @@ ha_innobase::get_auto_increment(
ut_ad(autoinc > 0); ut_ad(autoinc > 0);
} }
/** The following logic is needed to avoid duplicate key error
for autoincrement column.
(1) InnoDB gives the current autoincrement value with respect
to increment and offset value.
(2) Basically it does compute_next_insert_id() logic inside InnoDB
to avoid the current auto increment value changed by handler layer.
(3) It is restricted only for insert operations. */
if (increment > 1 && thd_sql_command(user_thd) != SQLCOM_ALTER_TABLE
&& autoinc < col_max_value) {
ulonglong prev_auto_inc = autoinc;
autoinc = ((autoinc - 1) + increment - offset)/ increment;
autoinc = autoinc * increment + offset;
/* If autoinc exceeds the col_max_value then reset
to old autoinc value. Because in case of non-strict
sql mode, boundary value is not considered as error. */
if (autoinc >= col_max_value) {
autoinc = prev_auto_inc;
}
ut_ad(autoinc > 0);
}
/* Called for the first time ? */ /* Called for the first time ? */
if (trx->n_autoinc_rows == 0) { if (trx->n_autoinc_rows == 0) {
...@@ -16072,26 +16102,6 @@ ha_innobase::get_auto_increment( ...@@ -16072,26 +16102,6 @@ ha_innobase::get_auto_increment(
current = *first_value; current = *first_value;
if (prebuilt->autoinc_increment != increment) {
WSREP_DEBUG("autoinc decrease: %llu -> %llu\n"
"THD: %ld, current: %llu, autoinc: %llu",
prebuilt->autoinc_increment,
increment,
thd_get_thread_id(ha_thd()),
current, autoinc);
if (!wsrep_on(ha_thd()))
{
current = autoinc - prebuilt->autoinc_increment;
current = innobase_next_autoinc(
current, 1, increment, offset, col_max_value);
}
dict_table_autoinc_initialize(prebuilt->table, current);
*first_value = current;
}
/* Compute the last value in the interval */ /* Compute the last value in the interval */
next_value = innobase_next_autoinc( next_value = innobase_next_autoinc(
current, *nb_reserved_values, increment, offset, current, *nb_reserved_values, increment, offset,
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2000, 2019, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2018, MariaDB Corporation. Copyright (c) 2013, 2018, MariaDB Corporation.
Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc. Copyright (c) 2009, Percona Inc.
...@@ -2899,11 +2899,10 @@ innobase_next_autoinc( ...@@ -2899,11 +2899,10 @@ innobase_next_autoinc(
if (next_value == 0) { if (next_value == 0) {
ulonglong next; ulonglong next;
if (current >= offset) { if (current > offset) {
next = (current - offset) / step; next = (current - offset) / step;
} else { } else {
next = 0; next = (offset - current) / step;
block -= step;
} }
ut_a(max_value > next); ut_a(max_value > next);
...@@ -16673,6 +16672,37 @@ ha_innobase::get_auto_increment( ...@@ -16673,6 +16672,37 @@ ha_innobase::get_auto_increment(
ut_ad(autoinc > 0); ut_ad(autoinc > 0);
} }
/** The following logic is needed to avoid duplicate key error
for autoincrement column.
(1) InnoDB gives the current autoincrement value with respect
to increment and offset value.
(2) Basically it does compute_next_insert_id() logic inside InnoDB
to avoid the current auto increment value changed by handler layer.
(3) It is restricted only for insert operations. */
if (increment > 1 && thd_sql_command(user_thd) != SQLCOM_ALTER_TABLE
&& autoinc < col_max_value) {
ulonglong prev_auto_inc = autoinc;
autoinc = ((autoinc - 1) + increment - offset)/ increment;
autoinc = autoinc * increment + offset;
/* If autoinc exceeds the col_max_value then reset
to old autoinc value. Because in case of non-strict
sql mode, boundary value is not considered as error. */
if (autoinc >= col_max_value) {
autoinc = prev_auto_inc;
}
ut_ad(autoinc > 0);
}
/* Called for the first time ? */ /* Called for the first time ? */
if (trx->n_autoinc_rows == 0) { if (trx->n_autoinc_rows == 0) {
...@@ -16710,26 +16740,6 @@ ha_innobase::get_auto_increment( ...@@ -16710,26 +16740,6 @@ ha_innobase::get_auto_increment(
current = *first_value; current = *first_value;
if (prebuilt->autoinc_increment != increment) {
WSREP_DEBUG("autoinc decrease: %llu -> %llu\n"
"THD: %ld, current: %llu, autoinc: %llu",
prebuilt->autoinc_increment,
increment,
thd_get_thread_id(ha_thd()),
current, autoinc);
if (!wsrep_on(ha_thd()))
{
current = autoinc - prebuilt->autoinc_increment;
current = innobase_next_autoinc(
current, 1, increment, offset, col_max_value);
}
dict_table_autoinc_initialize(prebuilt->table, current);
*first_value = current;
}
/* Compute the last value in the interval */ /* Compute the last value in the interval */
next_value = innobase_next_autoinc( next_value = innobase_next_autoinc(
current, *nb_reserved_values, increment, offset, current, *nb_reserved_values, increment, offset,
......
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