diff --git a/mysql-test/suite/innodb/r/innodb-alter-autoinc.result b/mysql-test/suite/innodb/r/innodb-alter-autoinc.result index 82eb448fe45..c3ae453486a 100644 --- a/mysql-test/suite/innodb/r/innodb-alter-autoinc.result +++ b/mysql-test/suite/innodb/r/innodb-alter-autoinc.result @@ -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; diff --git a/mysql-test/suite/innodb/r/innodb-autoinc.result b/mysql-test/suite/innodb/r/innodb-autoinc.result index 2c428b0ba1a..f2e2e087818 100644 --- a/mysql-test/suite/innodb/r/innodb-autoinc.result +++ b/mysql-test/suite/innodb/r/innodb-autoinc.result @@ -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()) diff --git a/mysql-test/suite/innodb/t/innodb-autoinc.test b/mysql-test/suite/innodb/t/innodb-autoinc.test index 8b202f5db6b..b14d6db7f5d 100644 --- a/mysql-test/suite/innodb/t/innodb-autoinc.test +++ b/mysql-test/suite/innodb/t/innodb-autoinc.test @@ -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; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index fd8f0d3787f..ed15c704373 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1,6 +1,6 @@ /***************************************************************************** -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, diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 55e231ef770..ccaeadce932 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -1,6 +1,6 @@ /***************************************************************************** -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,