Skip to content

Commit 02a5207

Browse files
AliSQLAliSQL
authored andcommitted
[Feature] Issue #42 Persistent AUTO_INCREMENT value for InnoDB table
InnoDB auto_increment value is not persistent and can lead to some values reused, as described by official bug #199. This patch fix the problem by writing the last used AUTO_INCREMENT to the root page of the clustered index, using the PAGE_MAX_TRX_ID field, which is unused for root page. Two InnoDB variables are introduced to control this persistent behaviour: - innodb_autoinc_persistent This persistent behaviour is enabled or not. - innodb_autoinc_persistent_interval The interval of persist max auto_increment value.
1 parent 3487832 commit 02a5207

25 files changed

Lines changed: 533 additions & 29 deletions

mysql-test/r/events_2.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
drop database if exists events_test;
22
create database events_test;
33
use events_test;
4-
create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
4+
create event e_26 on schedule at 'ONE_YEAR_FROM_NOW' disable do set @a = 5;
55
select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
66
db name body definer convert_tz(execute_at, 'UTC', 'SYSTEM') on_completion
7-
events_test e_26 set @a = 5 root@localhost 2017-01-01 00:00:00 DROP
7+
events_test e_26 set @a = 5 root@localhost ONE_YEAR_FROM_NOW DROP
88
drop event e_26;
99
create event e_26 on schedule at NULL disable do set @a = 5;
1010
ERROR HY000: Incorrect AT value: 'NULL'

mysql-test/suite/innodb/r/innodb-autoinc.result

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,3 +1384,95 @@ t CREATE TABLE `t` (
13841384
KEY `i` (`i`)
13851385
) ENGINE=InnoDB AUTO_INCREMENT=401 DEFAULT CHARSET=latin1
13861386
DROP TABLE t;
1387+
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
1388+
SET @@INSERT_ID=1;
1389+
SHOW VARIABLES LIKE "%auto_inc%";
1390+
Variable_name Value
1391+
auto_increment_increment 1
1392+
auto_increment_offset 1
1393+
DROP TABLE IF EXISTS t1;
1394+
Warnings:
1395+
Note 1051 Unknown table 'test.t1'
1396+
CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
1397+
INSERT INTO t1 VALUES(null);
1398+
INSERT INTO t1 VALUES(null);
1399+
SELECT * FROM t1;
1400+
c1
1401+
1
1402+
2
1403+
SHOW CREATE TABLE t1;
1404+
Table Create Table
1405+
t1 CREATE TABLE `t1` (
1406+
`c1` int(11) NOT NULL AUTO_INCREMENT,
1407+
PRIMARY KEY (`c1`)
1408+
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
1409+
# restart: --innodb_autoinc_persistent=on
1410+
SHOW CREATE TABLE t1;
1411+
Table Create Table
1412+
t1 CREATE TABLE `t1` (
1413+
`c1` int(11) NOT NULL AUTO_INCREMENT,
1414+
PRIMARY KEY (`c1`)
1415+
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
1416+
INSERT INTO t1 VALUES(null);
1417+
INSERT INTO t1 VALUES(null);
1418+
SELECT * FROM t1;
1419+
c1
1420+
1
1421+
2
1422+
3
1423+
4
1424+
DELETE FROM t1 WHERE c1 in(3,4);
1425+
SELECT * FROM t1;
1426+
c1
1427+
1
1428+
2
1429+
# restart: --innodb_autoinc_persistent=on
1430+
SHOW CREATE TABLE t1;
1431+
Table Create Table
1432+
t1 CREATE TABLE `t1` (
1433+
`c1` int(11) NOT NULL AUTO_INCREMENT,
1434+
PRIMARY KEY (`c1`)
1435+
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
1436+
update t1 set c1=1000 where c1=1;
1437+
select * from t1;
1438+
c1
1439+
2
1440+
1000
1441+
SHOW CREATE TABLE t1;
1442+
Table Create Table
1443+
t1 CREATE TABLE `t1` (
1444+
`c1` int(11) NOT NULL AUTO_INCREMENT,
1445+
PRIMARY KEY (`c1`)
1446+
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
1447+
# restart: --innodb_autoinc_persistent=on --innodb_autoinc_persistent_interval=10
1448+
SHOW CREATE TABLE t1;
1449+
Table Create Table
1450+
t1 CREATE TABLE `t1` (
1451+
`c1` int(11) NOT NULL AUTO_INCREMENT,
1452+
PRIMARY KEY (`c1`)
1453+
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
1454+
insert into t1 values(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null);
1455+
select * from t1;
1456+
c1
1457+
2
1458+
5
1459+
6
1460+
7
1461+
8
1462+
9
1463+
10
1464+
11
1465+
12
1466+
13
1467+
14
1468+
15
1469+
16
1470+
1000
1471+
# restart: --innodb_autoinc_persistent=on innodb_autoinc_persistent_interval=10
1472+
SHOW CREATE TABLE t1;
1473+
Table Create Table
1474+
t1 CREATE TABLE `t1` (
1475+
`c1` int(11) NOT NULL AUTO_INCREMENT,
1476+
PRIMARY KEY (`c1`)
1477+
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=latin1
1478+
DROP TABLE t1;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
SELECT COUNT(@@GLOBAL.innodb_autoinc_persistent);
2+
COUNT(@@GLOBAL.innodb_autoinc_persistent)
3+
1
4+
SET @@GLOBAL.innodb_autoinc_persistent=OFF;
5+
SET @@GLOBAL.innodb_autoinc_persistent=ON;
6+
SET @@GLOBAL.innodb_autoinc_persistent=OFF;
7+
SELECT COUNT(@@local.innodb_autoinc_persistent);
8+
ERROR HY000: Variable 'innodb_autoinc_persistent' is a GLOBAL variable
9+
Expected error 'Variable is a GLOBAL variable'
10+
SELECT COUNT(@@SESSION.innodb_autoinc_persistent);
11+
ERROR HY000: Variable 'innodb_autoinc_persistent' is a GLOBAL variable
12+
Expected error 'Variable is a GLOBAL variable'
13+
SELECT VARIABLE_NAME, VARIABLE_VALUE
14+
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
15+
WHERE VARIABLE_NAME = 'innodb_autoinc_persistent';
16+
VARIABLE_NAME VARIABLE_VALUE
17+
INNODB_AUTOINC_PERSISTENT OFF
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
SET @start_global_value = @@global.innodb_autoinc_persistent_interval;
2+
SELECT @start_global_value;
3+
@start_global_value
4+
1
5+
SELECT VARIABLE_NAME, VARIABLE_VALUE
6+
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
7+
WHERE VARIABLE_NAME = 'innodb_autoinc_persistent_interval';
8+
VARIABLE_NAME VARIABLE_VALUE
9+
INNODB_AUTOINC_PERSISTENT_INTERVAL 1
10+
SELECT COUNT(@@local.innodb_autoinc_persistent_interval);
11+
ERROR HY000: Variable 'innodb_autoinc_persistent_interval' is a GLOBAL variable
12+
Expected error 'Variable is a GLOBAL variable'
13+
SELECT COUNT(@@SESSION.innodb_autoinc_persistent_interval);
14+
ERROR HY000: Variable 'innodb_autoinc_persistent_interval' is a GLOBAL variable
15+
Expected error 'Variable is a GLOBAL variable'
16+
SET innodb_autoinc_persistent_interval = 100;
17+
ERROR HY000: Variable 'innodb_autoinc_persistent_interval' is a GLOBAL variable and should be set with SET GLOBAL
18+
SET global innodb_autoinc_persistent_interval = 100;
19+
SELECT @@global.innodb_autoinc_persistent_interval;
20+
@@global.innodb_autoinc_persistent_interval
21+
100
22+
SET global innodb_autoinc_persistent_interval = 0;
23+
Warnings:
24+
Warning 1292 Truncated incorrect innodb_autoinc_persistent_interv value: '0'
25+
SET global innodb_autoinc_persistent_interval = 10001;
26+
Warnings:
27+
Warning 1292 Truncated incorrect innodb_autoinc_persistent_interv value: '10001'
28+
SET @@global.innodb_autoinc_persistent_interval = 30.34;
29+
ERROR 42000: Incorrect argument type to variable 'innodb_autoinc_persistent_interval'
30+
SET @@global.innodb_autoinc_persistent_interval = @start_global_value;
31+
SELECT @@global.innodb_autoinc_persistent_interval;
32+
@@global.innodb_autoinc_persistent_interval
33+
1

mysql-test/suite/innodb/t/innodb-autoinc.test

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,3 +699,76 @@ INSERT INTO t VALUES (NULL);
699699
SELECT * FROM t;
700700
SHOW CREATE TABLE t;
701701
DROP TABLE t;
702+
703+
#
704+
# Test innodb_autoinc_persistent
705+
#
706+
707+
# Reset the AUTOINC session variables
708+
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
709+
SET @@INSERT_ID=1;
710+
SHOW VARIABLES LIKE "%auto_inc%";
711+
DROP TABLE IF EXISTS t1;
712+
CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
713+
INSERT INTO t1 VALUES(null);
714+
INSERT INTO t1 VALUES(null);
715+
SELECT * FROM t1;
716+
SHOW CREATE TABLE t1;
717+
718+
719+
--echo # restart: --innodb_autoinc_persistent=on
720+
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
721+
--shutdown_server 10
722+
--source include/wait_until_disconnected.inc
723+
# Do something while server is down
724+
--enable_reconnect
725+
# Write file to make mysql-test-run.pl start up the server again
726+
--exec echo "restart: --innodb_autoinc_persistent=on" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
727+
--source include/wait_until_connected_again.inc
728+
SHOW CREATE TABLE t1;
729+
INSERT INTO t1 VALUES(null);
730+
INSERT INTO t1 VALUES(null);
731+
SELECT * FROM t1;
732+
DELETE FROM t1 WHERE c1 in(3,4);
733+
SELECT * FROM t1;
734+
735+
--echo # restart: --innodb_autoinc_persistent=on
736+
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
737+
--shutdown_server 10
738+
--source include/wait_until_disconnected.inc
739+
# Do something while server is down
740+
--enable_reconnect
741+
# Write file to make mysql-test-run.pl start up the server again
742+
--exec echo "restart: --innodb_autoinc_persistent=on" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
743+
--source include/wait_until_connected_again.inc
744+
SHOW CREATE TABLE t1;
745+
746+
update t1 set c1=1000 where c1=1;
747+
select * from t1;
748+
SHOW CREATE TABLE t1;
749+
750+
--echo # restart: --innodb_autoinc_persistent=on --innodb_autoinc_persistent_interval=10
751+
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
752+
--shutdown_server 10
753+
--source include/wait_until_disconnected.inc
754+
# Do something while server is down
755+
--enable_reconnect
756+
# Write file to make mysql-test-run.pl start up the server again
757+
--exec echo "restart: --innodb_autoinc_persistent=on --innodb_autoinc_persistent_interval=10" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
758+
--source include/wait_until_connected_again.inc
759+
SHOW CREATE TABLE t1;
760+
insert into t1 values(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null);
761+
select * from t1;
762+
763+
--echo # restart: --innodb_autoinc_persistent=on innodb_autoinc_persistent_interval=10
764+
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
765+
--shutdown_server 10
766+
--source include/wait_until_disconnected.inc
767+
# Do something while server is down
768+
--enable_reconnect
769+
# Write file to make mysql-test-run.pl start up the server again
770+
--exec echo "restart: --innodb_autoinc_persistent=on --innodb_autoinc_persistent_interval=10" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
771+
--source include/wait_until_connected_again.inc
772+
SHOW CREATE TABLE t1;
773+
774+
DROP TABLE t1;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Variable name: innodb_autoinc_persistent
2+
# Scope: Global
3+
# Access type: Static
4+
# Data type: boolen
5+
# Default value: OFF
6+
7+
--source include/have_innodb.inc
8+
9+
SELECT COUNT(@@GLOBAL.innodb_autoinc_persistent);
10+
11+
SET @@GLOBAL.innodb_autoinc_persistent=OFF;
12+
SET @@GLOBAL.innodb_autoinc_persistent=ON;
13+
SET @@GLOBAL.innodb_autoinc_persistent=OFF;
14+
15+
--Error ER_INCORRECT_GLOBAL_LOCAL_VAR
16+
SELECT COUNT(@@local.innodb_autoinc_persistent);
17+
--echo Expected error 'Variable is a GLOBAL variable'
18+
19+
--Error ER_INCORRECT_GLOBAL_LOCAL_VAR
20+
SELECT COUNT(@@SESSION.innodb_autoinc_persistent);
21+
--echo Expected error 'Variable is a GLOBAL variable'
22+
23+
# Check the default value
24+
SELECT VARIABLE_NAME, VARIABLE_VALUE
25+
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
26+
WHERE VARIABLE_NAME = 'innodb_autoinc_persistent';
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Variable Name:innodb_autoinc_persistent_interval
2+
# Scope: GLOBAL
3+
# Access Type: Dynamic
4+
# Data Type: Numeric
5+
# Default Value: 1
6+
# Range: 1 - 10000
7+
8+
9+
--source include/have_innodb.inc
10+
# Save initial value #
11+
#############################################################
12+
SET @start_global_value = @@global.innodb_autoinc_persistent_interval;
13+
SELECT @start_global_value;
14+
15+
# Check the default value
16+
SELECT VARIABLE_NAME, VARIABLE_VALUE
17+
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
18+
WHERE VARIABLE_NAME = 'innodb_autoinc_persistent_interval';
19+
20+
--Error ER_INCORRECT_GLOBAL_LOCAL_VAR
21+
SELECT COUNT(@@local.innodb_autoinc_persistent_interval);
22+
--echo Expected error 'Variable is a GLOBAL variable'
23+
24+
--Error ER_INCORRECT_GLOBAL_LOCAL_VAR
25+
SELECT COUNT(@@SESSION.innodb_autoinc_persistent_interval);
26+
--echo Expected error 'Variable is a GLOBAL variable'
27+
28+
--Error ER_GLOBAL_VARIABLE
29+
SET innodb_autoinc_persistent_interval = 100;
30+
31+
SET global innodb_autoinc_persistent_interval = 100;
32+
33+
SELECT @@global.innodb_autoinc_persistent_interval;
34+
35+
SET global innodb_autoinc_persistent_interval = 0;
36+
SET global innodb_autoinc_persistent_interval = 10001;
37+
38+
--Error ER_WRONG_TYPE_FOR_VAR
39+
SET @@global.innodb_autoinc_persistent_interval = 30.34;
40+
41+
####################################
42+
## Restore initial value #
43+
#####################################
44+
45+
SET @@global.innodb_autoinc_persistent_interval = @start_global_value;
46+
SELECT @@global.innodb_autoinc_persistent_interval;

mysql-test/suite/sys_vars/r/all_vars.result

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ left join t1 on variable_name=test_name where test_name is null ORDER BY variabl
1414
There should be *no* variables listed below:
1515
ANONYMOUS_IN_GTID_OUT_ENABLE
1616
ANONYMOUS_IN_GTID_OUT_ENABLE
17+
INNODB_AUTOINC_PERSISTENT
18+
INNODB_AUTOINC_PERSISTENT
19+
INNODB_AUTOINC_PERSISTENT_INTERVAL
20+
INNODB_AUTOINC_PERSISTENT_INTERVAL
1721
INNODB_RDS_ADAPTIVE_TICKETS_ALGO
1822
INNODB_RDS_ADAPTIVE_TICKETS_ALGO
1923
INNODB_RDS_COLUMN_COMPRESSION_LEVEL

mysql-test/t/events_2.test

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ use events_test;
1313
# mysql.event intact checking end
1414
#
1515

16-
create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
16+
--let $one_year_from_now = `SELECT NOW() + INTERVAL 1 YEAR`
17+
--replace_result $one_year_from_now ONE_YEAR_FROM_NOW
18+
eval create event e_26 on schedule at '$one_year_from_now' disable do set @a = 5;
19+
--replace_result $one_year_from_now ONE_YEAR_FROM_NOW
1720
select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
1821
drop event e_26;
1922
--error ER_WRONG_VALUE

sql/handler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,6 +1057,7 @@ typedef struct st_ha_create_information
10571057
const char *alias;
10581058
ulonglong max_rows,min_rows;
10591059
ulonglong auto_increment_value;
1060+
ulonglong auto_increment_increment;
10601061
ulong table_options;
10611062
ulong avg_row_length;
10621063
ulong used_fields;

0 commit comments

Comments
 (0)