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` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
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 VALUES(-123,-45);
ALTER TABLE t1 AUTO_INCREMENT = 75;
......@@ -161,8 +161,8 @@ 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` (
......@@ -170,5 +170,5 @@ t1 CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
KEY `id` (`id`,`a`)
) ENGINE=InnoDB AUTO_INCREMENT=85 DEFAULT CHARSET=latin1
) ENGINE=InnoDB AUTO_INCREMENT=80 DEFAULT CHARSET=latin1
DROP TABLE t1;
......@@ -567,7 +567,7 @@ Variable_name Value
auto_increment_increment 65535
auto_increment_offset 65535
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;
c1
1
......@@ -674,7 +674,7 @@ SELECT a,b FROM t;
a b
1 S1
3 S2
4 S2
5 S2
# Client 1: Insert a record with auto_increment_increment=1
SET SESSION auto_increment_increment=1;
SHOW CREATE TABLE t;
......@@ -683,14 +683,14 @@ t CREATE TABLE `t` (
`a` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`b` varchar(200) DEFAULT NULL,
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');
SELECT a,b FROM t;
a b
1 S1
3 S2
4 S2
5 S1
5 S2
6 S1
DROP TABLE t;
# Autoincrement behaviour with mixed insert.
CREATE TABLE t(
......@@ -728,22 +728,22 @@ t CREATE TABLE `t` (
`a` tinyint(4) NOT NULL AUTO_INCREMENT,
`b` varchar(200) DEFAULT NULL,
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');
SELECT * FROM t;
a b
1 S0
11 S1
22 S3
23 S4
28 S2
31 S3
32 S4
SHOW CREATE TABLE t;
Table Create Table
t CREATE TABLE `t` (
`a` tinyint(4) NOT NULL AUTO_INCREMENT,
`b` varchar(200) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=latin1
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=latin1
DROP TABLE t;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=5;
DROP TABLE IF EXISTS t1;
......@@ -784,7 +784,7 @@ t2 CREATE TABLE `t2` (
`n` int(10) unsigned NOT NULL,
`o` enum('FALSE','TRUE') DEFAULT NULL,
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 ;
SHOW CREATE TABLE t1;
Table Create Table
......@@ -1464,13 +1464,13 @@ SELECT * FROM t;
i
1
301
351
601
SHOW CREATE TABLE t;
Table Create Table
t CREATE TABLE `t` (
`i` int(11) NOT NULL AUTO_INCREMENT,
KEY `i` (`i`)
) ENGINE=InnoDB AUTO_INCREMENT=401 DEFAULT CHARSET=latin1
) ENGINE=InnoDB AUTO_INCREMENT=651 DEFAULT CHARSET=latin1
DROP TABLE t;
#
# 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
SELECT * FROM t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCREMENT_OFFSET=1152921504606846976;
SHOW VARIABLES LIKE "auto_inc%";
--error 1467
--error HA_ERR_AUTOINC_ERANGE
INSERT INTO t1 VALUES (NULL),(NULL);
SELECT * FROM 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) 2009, Percona Inc.
Copyright (c) 2012, Facebook Inc.
......@@ -2588,11 +2588,10 @@ innobase_next_autoinc(
if (next_value == 0) {
ulonglong next;
if (current >= offset) {
if (current > offset) {
next = (current - offset) / step;
} else {
next = 0;
block -= step;
next = (offset - current) / step;
}
ut_a(max_value > next);
......@@ -16035,6 +16034,37 @@ ha_innobase::get_auto_increment(
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 ? */
if (trx->n_autoinc_rows == 0) {
......@@ -16072,26 +16102,6 @@ ha_innobase::get_auto_increment(
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 */
next_value = innobase_next_autoinc(
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) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
......@@ -2899,11 +2899,10 @@ innobase_next_autoinc(
if (next_value == 0) {
ulonglong next;
if (current >= offset) {
if (current > offset) {
next = (current - offset) / step;
} else {
next = 0;
block -= step;
next = (offset - current) / step;
}
ut_a(max_value > next);
......@@ -16673,6 +16672,37 @@ ha_innobase::get_auto_increment(
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 ? */
if (trx->n_autoinc_rows == 0) {
......@@ -16710,26 +16740,6 @@ ha_innobase::get_auto_increment(
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 */
next_value = innobase_next_autoinc(
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