1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-07 00:04:31 +03:00

MDEV-6076 Persistent AUTO_INCREMENT for InnoDB

This should be functionally equivalent to WL#6204 in MySQL 8.0.0, with
the notable difference that the file format changes are limited to
repurposing a previously unused data field in B-tree pages.

For persistent InnoDB tables, write the last used AUTO_INCREMENT
value to the root page of the clustered index, in the previously
unused (0) PAGE_MAX_TRX_ID field, now aliased as PAGE_ROOT_AUTO_INC.
Unlike some other previously unused InnoDB data fields, this one was
actually always zero-initialized, at least since MySQL 3.23.49.

The writes to PAGE_ROOT_AUTO_INC are protected by SX or X latch on the
root page. The SX latch will allow concurrent read access to the root
page. (The field PAGE_ROOT_AUTO_INC will only be read on the
first-time call to ha_innobase::open() from the SQL layer. The
PAGE_ROOT_AUTO_INC can only be updated when executing SQL, so
read/write races are not possible.)

During INSERT, the PAGE_ROOT_AUTO_INC is updated by the low-level
function btr_cur_search_to_nth_level(), adding no extra page
access. [Adaptive hash index lookup will be disabled during INSERT.]

If some rare UPDATE modifies an AUTO_INCREMENT column, the
PAGE_ROOT_AUTO_INC will be adjusted in a separate mini-transaction in
ha_innobase::update_row().

When a page is reorganized, we have to preserve the PAGE_ROOT_AUTO_INC
field.

During ALTER TABLE, the initial AUTO_INCREMENT value will be copied
from the table. ALGORITHM=COPY and online log apply in LOCK=NONE will
update PAGE_ROOT_AUTO_INC in real time.

innodb_col_no(): Determine the dict_table_t::cols[] element index
corresponding to a Field of a non-virtual column.
(The MySQL 5.7 implementation of virtual columns breaks the 1:1
relationship between Field::field_index and dict_table_t::cols[].
Virtual columns are omitted from dict_table_t::cols[]. Therefore,
we must translate the field_index of AUTO_INCREMENT columns into
an index of dict_table_t::cols[].)

Upgrade from old data files:

By default, the AUTO_INCREMENT sequence in old data files would appear
to be reset, because PAGE_MAX_TRX_ID or PAGE_ROOT_AUTO_INC would contain
the value 0 in each clustered index page. In new data files,
PAGE_ROOT_AUTO_INC can only be 0 if the table is empty or does not contain
any AUTO_INCREMENT column.

For backward compatibility, we use the old method of
SELECT MAX(auto_increment_column) for initializing the sequence.

btr_read_autoinc(): Read the AUTO_INCREMENT sequence from a new-format
data file.

btr_read_autoinc_with_fallback(): A variant of btr_read_autoinc()
that will resort to reading MAX(auto_increment_column) for data files
that did not use AUTO_INCREMENT yet. It was manually tested that during
the execution of innodb.autoinc_persist the compatibility logic is
not activated (for new files, PAGE_ROOT_AUTO_INC is never 0 in nonempty
clustered index root pages).

initialize_auto_increment(): Replaces
ha_innobase::innobase_initialize_autoinc(). This initializes
the AUTO_INCREMENT metadata. Only called from ha_innobase::open().

ha_innobase::info_low(): Do not try to lazily initialize
dict_table_t::autoinc. It must already have been initialized by
ha_innobase::open() or ha_innobase::create().

Note: The adjustments to class ha_innopart were not tested, because
the source code (native InnoDB partitioning) is not being compiled.
This commit is contained in:
Marko Mäkelä
2016-12-14 19:56:39 +02:00
parent 8938031bc7
commit 8777458a6e
38 changed files with 2534 additions and 719 deletions

View File

@@ -0,0 +1,19 @@
--let $_server_id= `SELECT @@server_id`
--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.$_server_id.expect
if ($restart_parameters)
{
--echo # Kill and restart: $restart_parameters
--exec echo "restart: $restart_parameters" > $_expect_file_name
}
if (!$restart_parameters)
{
--echo # Kill and restart
--exec echo "restart" > $_expect_file_name
}
--shutdown_server 0
--source include/wait_until_disconnected.inc
--enable_reconnect
--source include/wait_until_connected_again.inc
--disable_reconnect

View File

@@ -0,0 +1,61 @@
eval CREATE TABLE $table LIKE $template;
eval INSERT INTO $table SELECT * FROM $template;
eval SELECT * FROM $table;
eval SHOW CREATE TABLE $table;
--echo # This will keep the autoinc counter
eval ALTER TABLE $table AUTO_INCREMENT = 250, ALGORITHM = $algorithm;
--echo # We expect the counter to be 250
eval SHOW CREATE TABLE $table;
--echo # This should keep the autoinc counter as well
eval ALTER TABLE $table ADD COLUMN b INT, ALGORITHM = $algorithm;
--echo # We expect the counter to be 250
eval SHOW CREATE TABLE $table;
eval DELETE FROM $table WHERE a > 150;
eval SELECT * FROM $table;
--echo # This should reset the autoinc counter to the one specified
--echo # Since it's smaller than current one but bigger than existing
--echo # biggest counter in the table
eval ALTER TABLE $table AUTO_INCREMENT = 180, ALGORITHM = $algorithm;
--echo # We expect the counter to be 180
eval SHOW CREATE TABLE $table;
--echo # This should reset the autoinc counter to the next value of
--echo # current max counter in the table, since the specified value
--echo # is smaller than the existing biggest value(50 < 123)
eval ALTER TABLE $table DROP COLUMN b, AUTO_INCREMENT = 50, ALGORITHM = $algorithm;
--echo # We expect the counter to be 123
eval SHOW CREATE TABLE $table;
eval INSERT INTO $table VALUES(0), (0);
eval SELECT MAX(a) AS `Expect 124` FROM $table;
eval OPTIMIZE TABLE $table;
eval SHOW CREATE TABLE $table;
--source include/restart_mysqld.inc
--echo # We expect the counter to still be 125
eval SHOW CREATE TABLE $table;
eval DELETE FROM $table WHERE a >= 123;
eval CREATE UNIQUE INDEX idx_aa ON $table(a);
--source include/restart_mysqld.inc
eval INSERT INTO $table VALUES(0), (0);
eval SELECT MAX(a) AS `Expect 126` FROM $table;
eval DROP TABLE $table;

File diff suppressed because it is too large Load Diff

View File

@@ -3,15 +3,24 @@ CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (null);
INSERT INTO t1 VALUES (null);
ALTER TABLE t1 CHANGE c1 d1 INT NOT NULL AUTO_INCREMENT;
affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 0
SELECT * FROM t1;
d1
1
2
SELECT * FROM t1;
d1
1
2
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`d1` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`d1`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
INSERT INTO t1 VALUES(null);
SELECT * FROM t1;
d1
1
2
3
ALTER TABLE t1 AUTO_INCREMENT = 3;
affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 0

View File

@@ -2429,11 +2429,17 @@ drop table t1;
create table t1 (a int not null auto_increment primary key, val int) engine=InnoDB;
insert into t1 (val) values (1);
update t1 set a=2 where a=1;
insert into t1 (val) values (1);
insert into t1 (val) values (3);
select * from t1;
a val
2 1
3 3
insert into t1 values (2, 2);
ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
select * from t1;
a val
2 1
3 3
drop table t1;
CREATE TABLE t1 (GRADE DECIMAL(4) NOT NULL, PRIMARY KEY (GRADE)) ENGINE=INNODB;
INSERT INTO t1 (GRADE) VALUES (151),(252),(343);

View File

@@ -0,0 +1,533 @@
--source include/have_innodb.inc
--source include/not_embedded.inc
--echo #
--echo # MDEV-6076 Persistent AUTO_INCREMENT for InnoDB
--echo #
--echo # WL#6204 InnoDB persistent max value for autoinc columns
--echo #
--echo # Most of this test case is copied from the test innodb.autoinc_persist
--echo # that was introduced in MySQL 8.0.0. The observable behaviour
--echo # of MDEV-6076 is equivalent to WL#6204, with the exception that
--echo # there is less buffering taking place and redo log checkpoints
--echo # are not being treated specially.
--echo # Due to less buffering, there is no debug instrumentation testing
--echo # for MDEV-6076.
--echo #
--echo # Pre-create several tables
SET SQL_MODE='STRICT_ALL_TABLES';
CREATE TABLE t1(a TINYINT AUTO_INCREMENT KEY) ENGINE = InnoDB;
INSERT INTO t1 VALUES(0), (0), (0), (0), (-1), (-10), (0),
(20), (30), (31);
SELECT * FROM t1;
CREATE TABLE t2(a TINYINT UNSIGNED AUTO_INCREMENT KEY) ENGINE = InnoDB;
--error ER_WARN_DATA_OUT_OF_RANGE
INSERT INTO t2 VALUES(-5);
INSERT INTO t2 VALUES(0), (0), (0), (0), (8), (10), (0),
(20), (30), (31);
SELECT * FROM t2;
CREATE TABLE t3(a SMALLINT AUTO_INCREMENT KEY) ENGINE = InnoDB;
INSERT INTO t3 VALUES(0), (0), (0), (0), (-1), (-10), (0),
(20), (30), (31), (1024), (4096);
SELECT * FROM t3;
CREATE TABLE t4(a SMALLINT UNSIGNED AUTO_INCREMENT KEY) ENGINE = InnoDB;
--error ER_WARN_DATA_OUT_OF_RANGE
INSERT INTO t4 VALUES(-5);
INSERT INTO t4 VALUES(0), (0), (0), (0), (8), (10), (0),
(20), (30), (31), (1024), (4096);
SELECT * FROM t4;
CREATE TABLE t5(a MEDIUMINT AUTO_INCREMENT KEY) ENGINE = InnoDB;
INSERT INTO t5 VALUES(0), (0), (0), (0), (-1), (-10), (0),
(20), (30), (31), (1000000), (1000005);
SELECT * FROM t5;
CREATE TABLE t6(a MEDIUMINT UNSIGNED AUTO_INCREMENT KEY) ENGINE = InnoDB;
--error ER_WARN_DATA_OUT_OF_RANGE
INSERT INTO t6 VALUES(-5);
INSERT INTO t6 VALUES(0), (0), (0), (0), (8), (10), (0),
(20), (30), (31), (1000000), (1000005);
SELECT * FROM t6;
CREATE TABLE t7(a INT AUTO_INCREMENT KEY) ENGINE = InnoDB;
INSERT INTO t7 VALUES(0), (0), (0), (0), (-1), (-10), (0),
(20), (30), (31), (100000000), (100000008);
SELECT * FROM t7;
CREATE TABLE t8(a INT UNSIGNED AUTO_INCREMENT KEY) ENGINE = InnoDB;
--error ER_WARN_DATA_OUT_OF_RANGE
INSERT INTO t8 VALUES(-5);
INSERT INTO t8 VALUES(0), (0), (0), (0), (8), (10), (0),
(20), (30), (31), (100000000), (100000008);
SELECT * FROM t8;
CREATE TABLE t9(a BIGINT AUTO_INCREMENT KEY) ENGINE = InnoDB;
INSERT INTO t9 VALUES(0), (0), (0), (0), (-1), (-10), (0),
(20), (30), (31), (100000000000), (100000000006);
SELECT * FROM t9;
CREATE TABLE t10(a BIGINT UNSIGNED AUTO_INCREMENT KEY) ENGINE = InnoDB;
--error ER_WARN_DATA_OUT_OF_RANGE
INSERT INTO t10 VALUES(-5);
INSERT INTO t10 VALUES(0), (0), (0), (0), (8), (10), (0),
(20), (30), (31), (100000000000), (100000000006);
SELECT * FROM t10;
CREATE TABLE t11(a FLOAT AUTO_INCREMENT KEY) ENGINE = InnoDB;
INSERT INTO t11 VALUES(0), (0), (0), (0), (-1), (-10), (0),
(20), (30), (31);
SELECT * FROM t11;
# Since autoinc counter is persisted by redo logs, we don't want to
# lose them on kill and restart, so to make the result after restart stable.
set global innodb_flush_log_at_trx_commit=1;
CREATE TABLE t12(a DOUBLE AUTO_INCREMENT KEY) ENGINE = InnoDB;
INSERT INTO t12 VALUES(0), (0), (0), (0), (-1), (-10), (0),
(20), (30), (31);
SELECT * FROM t12;
CREATE TABLE t13(a INT AUTO_INCREMENT PRIMARY KEY) ENGINE = InnoDB,
AUTO_INCREMENT = 1234;
--echo # Scenario 1: Normal restart, to test if the counters are persisted
--source include/restart_mysqld.inc
--echo # We expect these results should be equal to above SELECTs
SELECT * FROM t1;
SELECT * FROM t2;
SELECT * FROM t3;
SELECT * FROM t4;
SELECT * FROM t5;
SELECT * FROM t6;
SELECT * FROM t7;
SELECT * FROM t8;
SELECT * FROM t9;
SELECT * FROM t10;
SELECT * FROM t11;
SELECT * FROM t12;
SELECT * FROM t13;
SHOW CREATE TABLE t13;
INSERT INTO t13 VALUES(0);
SELECT a AS `Expect 1234` FROM t13;
--echo # Scenario 2: Delete some values, to test the counters should not be the
--echo # one which is the largest in current table
set global innodb_flush_log_at_trx_commit=1;
DELETE FROM t1 WHERE a > 30;
SELECT MAX(a) AS `Expect 30` FROM t1;
DELETE FROM t3 WHERE a > 2000;
SELECT MAX(a) AS `Expect 2000` FROM t3;
DELETE FROM t5 WHERE a > 1000000;
SELECT MAX(a) AS `Expect 1000000` FROM t5;
DELETE FROM t7 WHERE a > 100000000;
SELECT MAX(a) AS `Expect 100000000` FROM t7;
DELETE FROM t9 WHERE a > 100000000000;
SELECT MAX(a) AS `Expect 100000000000` FROM t9;
--source include/restart_mysqld.inc
INSERT INTO t1 VALUES(0), (0);
SELECT MAX(a) AS `Expect 33` FROM t1;
INSERT INTO t3 VALUES(0), (0);
SELECT MAX(a) AS `Expect 4098` FROM t3;
INSERT INTO t5 VALUES(0), (0);
SELECT MAX(a) AS `Expect 1000007` FROM t5;
INSERT INTO t7 VALUES(0), (0);
SELECT MAX(a) AS `Expect 100000010` FROM t7;
INSERT INTO t9 VALUES(0), (0);
SELECT MAX(a) AS `Expect 100000000008` FROM t9;
--echo # Scenario 3: Insert some bigger counters, the next counter should start
--echo # from there
INSERT INTO t1 VALUES(40), (0);
INSERT INTO t1 VALUES(42), (0);
SELECT a AS `Expect 43, 42` FROM t1 ORDER BY a DESC LIMIT 4;
INSERT INTO t3 VALUES(5000), (0);
INSERT INTO t3 VALUES(5010), (0);
SELECT a AS `Expect 5011, 5010` FROM t3 ORDER BY a DESC LIMIT 4;
INSERT INTO t5 VALUES(1000010), (0);
INSERT INTO t5 VALUES(1000020), (0);
SELECT a AS `Expect 1000021, 1000020` FROM t5 ORDER BY a DESC LIMIT 4;
INSERT INTO t7 VALUES(100000020), (0);
INSERT INTO t7 VALUES(100000030), (0);
SELECT a AS `Expect 100000031, 100000030` FROM t7 ORDER BY a DESC LIMIT 4;
INSERT INTO t9 VALUES(100000000010), (0);
INSERT INTO t9 VALUES(100000000020), (0);
SELECT a AS `Expect 100000000021, 100000000020` FROM t9 ORDER BY a DESC LIMIT 4;
--echo # Scenario 4: Update some values, to test the counters should be updated
--echo # to the bigger value, but not smaller value.
INSERT INTO t1 VALUES(50), (55);
# Updating to bigger value will update the auto-increment counter
UPDATE t1 SET a = 105 WHERE a = 5;
# Updating to smaller value will not update the counter
UPDATE t1 SET a = 100 WHERE a = 55;
--echo # This should insert 102, 106, 107, and make next counter 109.
INSERT INTO t1 VALUES(102), (0), (0);
SELECT a AS `Expect 107, 106` FROM t1 ORDER BY a DESC LIMIT 2;
DELETE FROM t1 WHERE a > 105;
INSERT INTO t1 VALUES(0);
SELECT MAX(a) AS `Expect 109` FROM t1;
--echo # Test the same things on t3, t5, t7, t9, to test if DDTableBuffer would
--echo # be updated accordingly
INSERT INTO t3 VALUES(60), (65);
# Updating to bigger value will update the auto-increment counter
UPDATE t3 SET a = 6005 WHERE a = 5;
# Updating to smaller value will not update the counter
UPDATE t3 SET a = 6000 WHERE a = 60;
--echo # This should insert 6002, 6006, 6007, and make next counter 6009.
INSERT INTO t3 VALUES(6002), (0), (0);
SELECT a AS `Expect 6007, 6006` FROM t3 ORDER BY a DESC LIMIT 2;
DELETE FROM t3 WHERE a > 6005;
INSERT INTO t3 VALUES(0);
SELECT MAX(a) AS `Expect 6009` FROM t3;
INSERT INTO t5 VALUES(100), (200);
# Updating to bigger value will update the auto-increment counter
UPDATE t5 SET a = 1000105 WHERE a = 5;
# Updating to smaller value will not update the counter
UPDATE t5 SET a = 1000100 WHERE a = 100;
--echo # This should insert 1000102, 1000106, 1000107, and make next counter
--echo # 1000109.
INSERT INTO t5 VALUES(1000102), (0), (0);
SELECT a AS `Expect 1000107, 1000106` FROM t5 ORDER BY a DESC LIMIT 2;
DELETE FROM t5 WHERE a > 1000105;
INSERT INTO t5 VALUES(0);
SELECT MAX(a) AS `Expect 1000109` FROM t5;
INSERT INTO t7 VALUES(100), (200);
# Updating to bigger value will update the auto-increment counter
UPDATE t7 SET a = 100000105 WHERE a = 5;
# Updating to smaller value will not update the counter
UPDATE t7 SET a = 100000100 WHERE a = 100;
--echo # This should insert 100000102, 1100000106, 100000107, and make next
--echo # counter 100000109.
INSERT INTO t7 VALUES(100000102), (0), (0);
SELECT a AS `Expect 100000107, 100000106` FROM t7 ORDER BY a DESC LIMIT 2;
DELETE FROM t7 WHERE a > 100000105;
INSERT INTO t7 VALUES(0);
SELECT MAX(a) AS `Expect 100000109` FROM t7;
set global innodb_flush_log_at_trx_commit=1;
INSERT INTO t9 VALUES(100), (200);
# Updating to bigger value will update the auto-increment counter
UPDATE t9 SET a = 100000000105 WHERE a = 5;
# Updating to smaller value will not update the counter
UPDATE t9 SET a = 100000000100 WHERE a = 100;
--echo # This should insert 100000000102, 100000000106, 100000000107, and make
--echo # next counter 100000000109.
INSERT INTO t9 VALUES(100000000102), (0), (0);
SELECT a AS `Expect 100000000107, 100000000106` FROM t9 ORDER BY a DESC LIMIT 2;
DELETE FROM t9 WHERE a > 100000000105;
INSERT INTO t9 VALUES(0);
SELECT MAX(a) AS `Expect 100000000109` FROM t9;
--source include/restart_mysqld.inc
INSERT INTO t1 VALUES(0), (0);
SELECT a AS `Expect 110, 111` FROM t1 ORDER BY a DESC LIMIT 2;
INSERT INTO t3 VALUES(0), (0);
SELECT a AS `Expect 6010, 6011` FROM t3 ORDER BY a DESC LIMIT 2;
INSERT INTO t5 VALUES(0), (0);
SELECT a AS `Expect 1100111, 1100110` FROM t5 ORDER BY a DESC LIMIT 2;
INSERT INTO t7 VALUES(0), (0);
SELECT a AS `Expect 100000111, 100000110` FROM t7 ORDER BY a DESC LIMIT 2;
INSERT INTO t9 VALUES(0), (0);
SELECT a AS `Expect 100000000111, 100000000110` FROM t9 ORDER BY a DESC LIMIT 2;
--echo # Scenario 5: Test kill the server
INSERT INTO t1 VALUES(125);
DELETE FROM t1 WHERE a = 125;
INSERT INTO t3 VALUES(6100);
DELETE FROM t3 WHERE a = 6100;
INSERT INTO t5 VALUES(1100200);
DELETE FROM t5 WHERE a = 1100200;
INSERT INTO t7 VALUES(100000200);
DELETE FROM t7 WHERE a = 100000200;
set global innodb_flush_log_at_trx_commit=1;
INSERT INTO t9 VALUES(100000000200);
DELETE FROM t9 WHERE a = 100000000200;
--source include/kill_and_restart_mysqld.inc
INSERT INTO t1 VALUES(0);
SELECT a AS `Expect 126` FROM t1 ORDER BY a DESC LIMIT 1;
INSERT INTO t3 VALUES(0);
SELECT a AS `Expect 6101` FROM t3 ORDER BY a DESC LIMIT 1;
INSERT INTO t5 VALUES(0);
SELECT a AS `Expect 1100201` FROM t5 ORDER BY a DESC LIMIT 1;
INSERT INTO t7 VALUES(0);
SELECT a AS `Expect 100000201` FROM t7 ORDER BY a DESC LIMIT 1;
INSERT INTO t9 VALUES(0);
SELECT a AS `Expect 100000000201` FROM t9 ORDER BY a DESC LIMIT 1;
--echo # Scenario 6: Test truncate will reset the counters to 0
TRUNCATE TABLE t1;
TRUNCATE TABLE t3;
TRUNCATE TABLE t5;
TRUNCATE TABLE t7;
TRUNCATE TABLE t9;
INSERT INTO t1 VALUES(0), (0);
SELECT * FROM t1;
INSERT INTO t3 VALUES(0), (0);
SELECT * FROM t3;
INSERT INTO t5 VALUES(0), (0);
SELECT * FROM t5;
INSERT INTO t7 VALUES(0), (0);
SELECT * FROM t7;
INSERT INTO t9 VALUES(0), (0);
SELECT * FROM t9;
set global innodb_flush_log_at_trx_commit=1;
TRUNCATE TABLE t1;
TRUNCATE TABLE t3;
TRUNCATE TABLE t5;
TRUNCATE TABLE t7;
TRUNCATE TABLE t9;
--source include/kill_and_restart_mysqld.inc
INSERT INTO t1 VALUES(0), (0);
SELECT * FROM t1;
INSERT INTO t3 VALUES(0), (0);
SELECT * FROM t3;
INSERT INTO t5 VALUES(0), (0);
SELECT * FROM t5;
INSERT INTO t7 VALUES(0), (0);
SELECT * FROM t7;
INSERT INTO t9 VALUES(0), (0);
SELECT * FROM t9;
--echo # Scenario 7: Test explicit rename table won't change the counter
set global innodb_flush_log_at_trx_commit=1;
RENAME TABLE t9 to t19;
INSERT INTO t19 VALUES(0), (0);
SELECT * FROM t19;
DELETE FROM t19 WHERE a = 4;
--source include/kill_and_restart_mysqld.inc
RENAME TABLE t19 to t9;
INSERT INTO t9 VALUES(0), (0);
SELECT * FROM t9;
TRUNCATE TABLE t9;
INSERT INTO t9 VALUES(0), (0);
SELECT * FROM t9;
--echo # Scenario 8: Test ALTER TABLE operations
INSERT INTO t3 VALUES(0), (0), (100), (200), (1000);
SELECT * FROM t3;
DELETE FROM t3 WHERE a > 300;
SELECT MAX(a) AS `Expect 200` FROM t3;
--echo # This will not change the counter to 150, but to 201, which is the next
--echo # of current max counter in the table
ALTER TABLE t3 AUTO_INCREMENT = 150;
SHOW CREATE TABLE t3;
INSERT INTO t3 VALUES(0);
SELECT MAX(a) AS `Expect 201` FROM t3;
--echo # This will change the counter to 500, which is bigger than any counter
--echo # in the table
ALTER TABLE t3 AUTO_INCREMENT = 500;
SHOW CREATE TABLE t3;
INSERT INTO t3 VALUES(0);
SELECT MAX(a) AS `Expect 500` FROM t3;
TRUNCATE TABLE t3;
ALTER TABLE t3 AUTO_INCREMENT = 100;
SHOW CREATE TABLE t3;
INSERT INTO t3 VALUES(0), (0);
SELECT * FROM t3;
INSERT INTO t3 VALUES(150), (180);
UPDATE t3 SET a = 200 WHERE a = 150;
INSERT INTO t3 VALUES(220);
--echo # This still fails to set to 120, but just 221
ALTER TABLE t3 AUTO_INCREMENT = 120;
SHOW CREATE TABLE t3;
INSERT INTO t3 VALUES(0);
SELECT MAX(a) AS `Expect 221` FROM t3;
DELETE FROM t3 WHERE a > 120;
ALTER TABLE t3 AUTO_INCREMENT = 120;
SHOW CREATE TABLE t3;
--echo # MDEV-6076: Test adding an AUTO_INCREMENT COLUMN
CREATE TABLE mdev6076a (b INT) ENGINE=InnoDB;
INSERT INTO mdev6076a VALUES(2),(1);
CREATE TABLE mdev6076b (b INT) ENGINE=InnoDB;
INSERT INTO mdev6076b VALUES(2),(1);
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
ALTER TABLE mdev6076a ADD COLUMN a SERIAL FIRST, LOCK=NONE;
ALTER TABLE mdev6076a ADD COLUMN a SERIAL FIRST, ALGORITHM=INPLACE;
ALTER TABLE mdev6076b ADD COLUMN a SERIAL FIRST, AUTO_INCREMENT=100,
ALGORITHM=INPLACE;
--source include/kill_and_restart_mysqld.inc
INSERT INTO t3 VALUES(0);
SELECT MAX(a) AS `Expect 120` FROM t3;
INSERT INTO mdev6076a SET b=0;
SELECT * FROM mdev6076a;
INSERT INTO mdev6076b SET b=0;
SELECT * FROM mdev6076b;
DROP TABLE mdev6076a, mdev6076b;
set global innodb_flush_log_at_trx_commit=1;
INSERT INTO t3 VALUES(0), (0), (200), (210);
--echo # Test the different algorithms in ALTER TABLE
--let $template = t3
--let $algorithm = INPLACE
--let $table = t_inplace
--source suite/innodb/include/autoinc_persist_alter.inc
--let $algorithm = COPY
--let $table = t_copy
--source suite/innodb/include/autoinc_persist_alter.inc
--echo # Scenario 9: Test the sql_mode = NO_AUTO_VALUE_ON_ZERO
CREATE TABLE t30 (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b INT, key(b)) ENGINE = InnoDB;
set SQL_MODE = NO_AUTO_VALUE_ON_ZERO;
INSERT INTO t30 VALUES(NULL, 1), (200, 2), (0, 3);
INSERT INTO t30(b) VALUES(4), (5), (6), (7);
SELECT * FROM t30 ORDER BY b;
ALTER TABLE t30 MODIFY b MEDIUMINT;
SELECT * FROM t30 ORDER BY b;
set global innodb_flush_log_at_trx_commit=1;
CREATE TABLE t31 (a INT) ENGINE = InnoDB;
INSERT INTO t31 VALUES(1), (2);
ALTER TABLE t31 ADD b INT AUTO_INCREMENT PRIMARY KEY;
INSERT INTO t31 VALUES(3, 0), (4, NULL), (5, NULL);
--error ER_DUP_ENTRY
INSERT INTO t31 VALUES(6, 0);
SELECT * FROM t31;
--source include/kill_and_restart_mysqld.inc
--echo # This will not insert 0
INSERT INTO t31(a) VALUES(6), (0);
SELECT * FROM t31;
DROP TABLE t31;
set SQL_MODE = NO_AUTO_VALUE_ON_ZERO;
DELETE FROM t30 WHERE a = 0;
UPDATE t30 set a = 0 where b = 5;
SELECT * FROM t30 ORDER BY b;
DELETE FROM t30 WHERE a = 0;
UPDATE t30 SET a = NULL WHERE b = 6;
UPDATE t30 SET a = 300 WHERE b = 7;
SELECT * FROM t30 ORDER BY b;
SET SQL_MODE = 0;
--echo # Scenario 10: Rollback would not rollback the counter
CREATE TABLE t32 (
a BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
INSERT INTO t32 VALUES(0), (0);
set global innodb_flush_log_at_trx_commit=1;
START TRANSACTION;
INSERT INTO t32 VALUES(0), (0);
SELECT MAX(a) AS `Expect 4` FROM t32;
DELETE FROM t32 WHERE a >= 2;
ROLLBACK;
--source include/kill_and_restart_mysqld.inc
SELECT MAX(a) AS `Expect 2` FROM t32;
INSERT INTO t32 VALUES(0), (0);
SELECT MAX(a) AS `Expect 6` FROM t32;
--echo # Scenario 11: Test duplicate primary key/secondary key will not stop
--echo # increasing the counter
CREATE TABLE t33 (
a BIGINT NOT NULL PRIMARY KEY,
b BIGINT NOT NULL AUTO_INCREMENT,
KEY(b)) ENGINE = InnoDB;
INSERT INTO t33 VALUES(1, NULL);
INSERT INTO t33 VALUES(2, NULL);
--error ER_DUP_ENTRY
INSERT INTO t33 VALUES(2, NULL);
INSERT INTO t33 VALUES(3, NULL);
SELECT MAX(b) AS `Expect 4` FROM t33;
TRUNCATE TABLE t33;
INSERT INTO t33 VALUES(1, NULL);
INSERT INTO t33 VALUES(2, NULL);
set global innodb_flush_log_at_trx_commit=1;
START TRANSACTION;
UPDATE t33 SET a = 10 WHERE a = 1;
--error ER_DUP_ENTRY
INSERT INTO t33 VALUES(2, NULL);
COMMIT;
--source include/kill_and_restart_mysqld.inc
INSERT INTO t33 VALUES(3, NULL);
SELECT MAX(b) AS `Expect 4` FROM t33;
DROP TABLE t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t30, t32, t33;

View File

@@ -1,3 +0,0 @@
--default-storage-engine=MyISAM
--innodb-strict-mode=0
--innodb-file-per-table=0

View File

@@ -2,27 +2,24 @@
# embedded server does not support restarting
-- source include/not_embedded.inc
#
# 44030: Error: (1500) Couldn't read the MAX(ID) autoinc value from
# Before MDEV-6076 Persistent AUTO_INCREMENT for InnoDB
# this was a test for
# Bug #44030: Error: (1500) Couldn't read the MAX(ID) autoinc value from
# the index (PRIMARY)
# This test requires a restart of the server
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (null);
INSERT INTO t1 VALUES (null);
--enable_info
ALTER TABLE t1 CHANGE c1 d1 INT NOT NULL AUTO_INCREMENT;
--disable_info
SELECT * FROM t1;
# Restart the server
-- source include/restart_mysqld.inc
# The MySQL and InnoDB data dictionaries should now be out of sync.
# The select should print message to the error log
SELECT * FROM t1;
# MySQL have made a change (http://lists.mysql.com/commits/75268) that no
# longer results in the two data dictionaries being out of sync. If they
# revert their changes then this check for ER_AUTOINC_READ_FAILED will need
# to be enabled. Also, see http://bugs.mysql.com/bug.php?id=47621.
#-- error ER_AUTOINC_READ_FAILED,1467
SHOW CREATE TABLE t1;
INSERT INTO t1 VALUES(null);
SELECT * FROM t1;
# Before WL#5534, the following statement would copy the table,
# and effectively set AUTO_INCREMENT to 4, because while copying
# it would write values 1,2,3 to the column.

View File

@@ -1463,15 +1463,18 @@ select * from t1;
drop table t1;
#
# Test that update does not change internal auto-increment value
# Test that update does change internal auto-increment value
#
create table t1 (a int not null auto_increment primary key, val int) engine=InnoDB;
insert into t1 (val) values (1);
update t1 set a=2 where a=1;
# We should get the following error because InnoDB does not update the counter
# This should insert 3, since the counter has been updated to 2 already
insert into t1 (val) values (3);
select * from t1;
# We should get the following error because InnoDB does update the counter
--error ER_DUP_ENTRY
insert into t1 (val) values (1);
insert into t1 values (2, 2);
select * from t1;
drop table t1;
#

View File

@@ -43,7 +43,7 @@ UPDATE t1 SET c1 = 40 WHERE c1 = 50;
SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test'
AND TABLE_NAME='t1';
AUTO_INCREMENT
32
52
UPDATE t1 SET c1 = NULL WHERE c1 = 4;
Warnings:
Warning 1048 Column 'c1' cannot be null
@@ -62,10 +62,10 @@ c1
25
30
31
32
33
40
51
52
53
DROP TABLE t1;
CREATE TABLE t1 (
c1 INT NOT NULL AUTO_INCREMENT,
@@ -255,7 +255,7 @@ UPDATE t1 SET c1 = 140 WHERE c1 = 150;
SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test'
AND TABLE_NAME='t1';
AUTO_INCREMENT
141
152
UPDATE t1 SET c1 = NULL WHERE c1 = 4;
Warnings:
Warning 1048 Column 'c1' cannot be null
@@ -279,9 +279,9 @@ c1
90
91
140
141
142
151
152
153
DROP TABLE t1;
# Test with auto_increment_increment and auto_increment_offset.
CREATE TABLE t1 (

View File

@@ -50,6 +50,7 @@ Created 6/2/1994 Heikki Tuuri
#include "gis0geo.h"
#include "ut0new.h"
#include "dict0boot.h"
#include "row0sel.h" /* row_search_max_autoinc() */
/**************************************************************//**
Checks if the page in the cursor can be merged with given page.
@@ -1405,6 +1406,117 @@ btr_free(
btr_free_root(block, &mtr);
mtr.commit();
}
/** Read the last used AUTO_INCREMENT value from PAGE_ROOT_AUTO_INC.
@param[in,out] index clustered index
@return the last used AUTO_INCREMENT value
@retval 0 on error or if no AUTO_INCREMENT value was used yet */
ib_uint64_t
btr_read_autoinc(dict_index_t* index)
{
ut_ad(dict_index_is_clust(index));
ut_ad(index->table->persistent_autoinc);
ut_ad(!dict_table_is_temporary(index->table));
if (fil_space_t* space = fil_space_acquire(index->space)) {
mtr_t mtr;
mtr.start();
ib_uint64_t autoinc;
if (buf_block_t* block = buf_page_get(
page_id_t(index->space, index->page),
page_size_t(space->flags),
RW_S_LATCH, &mtr)) {
autoinc = page_get_autoinc(block->frame);
} else {
autoinc = 0;
}
mtr.commit();
fil_space_release(space);
return(autoinc);
}
return(0);
}
/** Read the last used AUTO_INCREMENT value from PAGE_ROOT_AUTO_INC,
or fall back to MAX(auto_increment_column).
@param[in] table table containing an AUTO_INCREMENT column
@param[in] col_no index of the AUTO_INCREMENT column
@return the AUTO_INCREMENT value
@retval 0 on error or if no AUTO_INCREMENT value was used yet */
ib_uint64_t
btr_read_autoinc_with_fallback(const dict_table_t* table, unsigned col_no)
{
ut_ad(table->persistent_autoinc);
ut_ad(!dict_table_is_temporary(table));
dict_index_t* index = dict_table_get_first_index(table);
if (index == NULL) {
} else if (fil_space_t* space = fil_space_acquire(index->space)) {
mtr_t mtr;
mtr.start();
buf_block_t* block = buf_page_get(
page_id_t(index->space, index->page),
page_size_t(space->flags),
RW_S_LATCH, &mtr);
ib_uint64_t autoinc = block
? page_get_autoinc(block->frame) : 0;
const bool retry = block && autoinc == 0
&& !page_is_empty(block->frame);
mtr.commit();
fil_space_release(space);
if (retry) {
/* This should be an old data file where
PAGE_ROOT_AUTO_INC was initialized to 0.
Fall back to reading MAX(autoinc_col).
There should be an index on it. */
const dict_col_t* autoinc_col
= dict_table_get_nth_col(table, col_no);
while (index != NULL
&& index->fields[0].col != autoinc_col) {
index = dict_table_get_next_index(index);
}
if (index != NULL && index->space == space->id) {
autoinc = row_search_max_autoinc(index);
}
}
return(autoinc);
}
return(0);
}
/** Write the next available AUTO_INCREMENT value to PAGE_ROOT_AUTO_INC.
@param[in,out] index clustered index
@param[in] autoinc the AUTO_INCREMENT value
@param[in] reset whether to reset the AUTO_INCREMENT
to a possibly smaller value than currently
exists in the page */
void
btr_write_autoinc(dict_index_t* index, ib_uint64_t autoinc, bool reset)
{
ut_ad(dict_index_is_clust(index));
ut_ad(index->table->persistent_autoinc);
ut_ad(!dict_table_is_temporary(index->table));
if (fil_space_t* space = fil_space_acquire(index->space)) {
mtr_t mtr;
mtr.start();
mtr.set_named_space(space);
page_set_autoinc(buf_page_get(
page_id_t(index->space, index->page),
page_size_t(space->flags),
RW_SX_LATCH, &mtr),
index, autoinc, &mtr, reset);
mtr.commit();
fil_space_release(space);
}
}
#endif /* !UNIV_HOTBACKUP */
/*************************************************************//**
@@ -1499,21 +1611,28 @@ btr_page_reorganize_low(
page_get_infimum_rec(temp_page),
index, mtr);
/* Multiple transactions cannot simultaneously operate on the
same temp-table in parallel.
max_trx_id is ignored for temp tables because it not required
for MVCC. */
if (dict_index_is_sec_or_ibuf(index)
&& page_is_leaf(page)
&& !dict_table_is_temporary(index->table)) {
/* Copy max trx id to recreated page */
trx_id_t max_trx_id = page_get_max_trx_id(temp_page);
page_set_max_trx_id(block, NULL, max_trx_id, mtr);
/* In crash recovery, dict_index_is_sec_or_ibuf() always
holds, even for clustered indexes. max_trx_id is
unused in clustered index pages. */
ut_ad(max_trx_id != 0 || recovery);
}
/* Copy the PAGE_MAX_TRX_ID or PAGE_ROOT_AUTO_INC. */
memcpy(page + (PAGE_HEADER + PAGE_MAX_TRX_ID),
temp_page + (PAGE_HEADER + PAGE_MAX_TRX_ID), 8);
/* PAGE_MAX_TRX_ID is unused in clustered index pages,
non-leaf pages, and in temporary tables. It was always
zero-initialized in page_create() in all InnoDB versions.
PAGE_MAX_TRX_ID must be nonzero on dict_index_is_sec_or_ibuf()
leaf pages.
During redo log apply, dict_index_is_sec_or_ibuf() always
holds, even for clustered indexes. */
ut_ad(recovery || dict_table_is_temporary(index->table)
|| !page_is_leaf(temp_page)
|| !dict_index_is_sec_or_ibuf(index)
|| page_get_max_trx_id(page) != 0);
/* PAGE_MAX_TRX_ID must be zero on non-leaf pages other than
clustered index root pages. */
ut_ad(recovery
|| page_get_max_trx_id(page) == 0
|| (dict_index_is_sec_or_ibuf(index)
? page_is_leaf(temp_page)
: page_is_root(temp_page)));
/* If innodb_log_compressed_pages is ON, page reorganize should log the
compressed page image.*/

View File

@@ -751,7 +751,9 @@ btr_cur_search_to_nth_level(
RW_S_LATCH, or 0 */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
mtr_t* mtr) /*!< in: mtr */
mtr_t* mtr, /*!< in: mtr */
ib_uint64_t autoinc)/*!< in: PAGE_ROOT_AUTO_INC to be written
(0 if none) */
{
page_t* page = NULL; /* remove warning */
buf_block_t* block;
@@ -888,6 +890,12 @@ btr_cur_search_to_nth_level(
|| latch_mode == BTR_SEARCH_TREE
|| latch_mode == BTR_MODIFY_LEAF);
ut_ad(autoinc == 0 || dict_index_is_clust(index));
ut_ad(autoinc == 0
|| latch_mode == BTR_MODIFY_TREE
|| latch_mode == BTR_MODIFY_LEAF);
ut_ad(autoinc == 0 || level == 0);
cursor->flag = BTR_CUR_BINARY;
cursor->index = index;
@@ -907,8 +915,7 @@ btr_cur_search_to_nth_level(
# ifdef UNIV_SEARCH_PERF_STAT
info->n_searches++;
# endif
if (rw_lock_get_writer(btr_get_search_latch(index))
== RW_LOCK_NOT_LOCKED
if (autoinc == 0
&& latch_mode <= BTR_MODIFY_LEAF
&& info->last_hash_succ
# ifdef MYSQL_INDEX_DISABLE_AHI
@@ -922,8 +929,10 @@ btr_cur_search_to_nth_level(
/* If !has_search_latch, we do a dirty read of
btr_search_enabled below, and btr_search_guess_on_hash()
will have to check it again. */
&& UNIV_LIKELY(btr_search_enabled)
&& btr_search_enabled
&& !modify_external
&& rw_lock_get_writer(btr_get_search_latch(index))
== RW_LOCK_NOT_LOCKED
&& btr_search_guess_on_hash(index, info, tuple, mode,
latch_mode, cursor,
has_search_latch, mtr)) {
@@ -1071,16 +1080,16 @@ search_loop:
if (height != 0) {
/* We are about to fetch the root or a non-leaf page. */
if ((latch_mode != BTR_MODIFY_TREE
|| height == level)
if ((latch_mode != BTR_MODIFY_TREE || height == level)
&& !retrying_for_search_prev) {
/* If doesn't have SX or X latch of index,
each pages should be latched before reading. */
if (modify_external
&& height == ULINT_UNDEFINED
&& upper_rw_latch == RW_S_LATCH) {
if (height == ULINT_UNDEFINED
&& upper_rw_latch == RW_S_LATCH
&& (modify_external || autoinc)) {
/* needs sx-latch of root page
for fseg operation */
for fseg operation or for writing
PAGE_ROOT_AUTO_INC */
rw_latch = RW_SX_LATCH;
} else {
rw_latch = upper_rw_latch;
@@ -1271,11 +1280,13 @@ retry_page_get:
&& page_is_leaf(page)
&& rw_latch != RW_NO_LATCH
&& rw_latch != root_leaf_rw_latch) {
/* We should retry to get the page, because the root page
is latched with different level as a leaf page. */
/* The root page is also a leaf page (root_leaf).
We should reacquire the page, because the root page
is latched differently from leaf pages. */
ut_ad(root_leaf_rw_latch != RW_NO_LATCH);
ut_ad(rw_latch == RW_S_LATCH || rw_latch == RW_SX_LATCH);
ut_ad(rw_latch == RW_S_LATCH || modify_external);
ut_ad(rw_latch == RW_S_LATCH || modify_external || autoinc);
ut_ad(!autoinc || root_leaf_rw_latch == RW_X_LATCH);
ut_ad(n_blocks == 0);
mtr_release_block_at_savepoint(
@@ -1365,6 +1376,7 @@ retry_page_get:
/* release upper blocks */
if (retrying_for_search_prev) {
ut_ad(!autoinc);
for (;
prev_n_releases < prev_n_blocks;
prev_n_releases++) {
@@ -1378,8 +1390,9 @@ retry_page_get:
}
for (; n_releases < n_blocks; n_releases++) {
if (n_releases == 0 && modify_external) {
/* keep latch of root page */
if (n_releases == 0
&& (modify_external || autoinc)) {
/* keep the root page latch */
ut_ad(mtr_memo_contains_flagged(
mtr, tree_blocks[n_releases],
MTR_MEMO_PAGE_SX_FIX
@@ -1903,6 +1916,8 @@ need_opposite_intention:
}
if (level != 0) {
ut_ad(!autoinc);
if (upper_rw_latch == RW_NO_LATCH) {
/* latch the page */
buf_block_t* child_block;
@@ -1951,6 +1966,11 @@ need_opposite_intention:
cursor->up_match = up_match;
cursor->up_bytes = up_bytes;
if (autoinc) {
page_set_autoinc(tree_blocks[0],
index, autoinc, mtr, false);
}
#ifdef BTR_CUR_ADAPT
/* We do a dirty read of btr_search_enabled here. We
will properly check btr_search_enabled again in

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2016, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -596,7 +597,7 @@ btr_pcur_open_on_user_rec_func(
mtr_t* mtr) /*!< in: mtr */
{
btr_pcur_open_low(index, 0, tuple, mode, latch_mode, cursor,
file, line, mtr);
file, line, 0, mtr);
if ((mode == PAGE_CUR_GE) || (mode == PAGE_CUR_G)) {

View File

@@ -810,20 +810,6 @@ dict_index_zip_pad_lock(
mutex_enter(index->zip_pad.mutex);
}
/********************************************************************//**
Unconditionally set the autoinc counter. */
void
dict_table_autoinc_initialize(
/*==========================*/
dict_table_t* table, /*!< in/out: table */
ib_uint64_t value) /*!< in: next value to assign to a row */
{
ut_ad(dict_table_autoinc_own(table));
table->autoinc = value;
}
/** Get all the FTS indexes on a table.
@param[in] table table
@param[out] indexes all FTS indexes on this table
@@ -849,75 +835,6 @@ dict_table_get_all_fts_indexes(
return(ib_vector_size(indexes));
}
/** Store autoinc value when the table is evicted.
@param[in] table table evicted */
void
dict_table_autoinc_store(
const dict_table_t* table)
{
ut_ad(mutex_own(&dict_sys->mutex));
if (table->autoinc != 0) {
ut_ad(dict_sys->autoinc_map->find(table->id)
== dict_sys->autoinc_map->end());
dict_sys->autoinc_map->insert(
std::pair<table_id_t, ib_uint64_t>(
table->id, table->autoinc));
}
}
/** Restore autoinc value when the table is loaded.
@param[in] table table loaded */
void
dict_table_autoinc_restore(
dict_table_t* table)
{
ut_ad(mutex_own(&dict_sys->mutex));
autoinc_map_t::iterator it;
it = dict_sys->autoinc_map->find(table->id);
if (it != dict_sys->autoinc_map->end()) {
table->autoinc = it->second;
ut_ad(table->autoinc != 0);
dict_sys->autoinc_map->erase(it);
}
}
/********************************************************************//**
Reads the next autoinc value (== autoinc counter value), 0 if not yet
initialized.
@return value for a new row, or 0 */
ib_uint64_t
dict_table_autoinc_read(
/*====================*/
const dict_table_t* table) /*!< in: table */
{
ut_ad(dict_table_autoinc_own(table));
return(table->autoinc);
}
/********************************************************************//**
Updates the autoinc counter if the value supplied is greater than the
current value. */
void
dict_table_autoinc_update_if_greater(
/*=================================*/
dict_table_t* table, /*!< in/out: table */
ib_uint64_t value) /*!< in: value which was assigned to a row */
{
ut_ad(dict_table_autoinc_own(table));
if (value > table->autoinc) {
table->autoinc = value;
}
}
/********************************************************************//**
Release the autoinc lock. */
void
@@ -1212,8 +1129,6 @@ dict_init(void)
}
mutex_create(LATCH_ID_DICT_FOREIGN_ERR, &dict_foreign_err_mutex);
dict_sys->autoinc_map = new autoinc_map_t();
}
/**********************************************************************//**
@@ -1477,8 +1392,6 @@ dict_table_add_to_cache(
UT_LIST_ADD_FIRST(dict_sys->table_non_LRU, table);
}
dict_table_autoinc_restore(table);
ut_ad(dict_lru_validate());
dict_sys->size += mem_heap_get_size(table->heap)
@@ -2213,10 +2126,6 @@ dict_table_remove_from_cache_low(
ut_ad(dict_lru_validate());
if (lru_evict) {
dict_table_autoinc_store(table);
}
if (lru_evict && table->drop_aborted) {
/* Do as dict_table_try_drop_aborted() does. */
@@ -7007,8 +6916,6 @@ dict_close(void)
mutex_free(&dict_foreign_err_mutex);
delete dict_sys->autoinc_map;
ut_ad(dict_sys->size == 0);
ut_free(dict_sys);

View File

@@ -159,12 +159,6 @@ dict_mem_table_create(
/* lazy creation of table autoinc latch */
dict_table_autoinc_create_lazy(table);
table->autoinc = 0;
/* The number of transactions that are either waiting on the
AUTOINC lock or have been granted the lock. */
table->n_waiting_or_granted_auto_inc_locks = 0;
/* If the table has an FTS index or we are in the process
of building one, create the table->fts */
if (dict_table_has_fts_index(table)

View File

@@ -6739,33 +6739,35 @@ innobase_get_int_col_max_value(
return(max_value);
}
/************************************************************************
Set the autoinc column max value. This should only be called once from
ha_innobase::open(). Therefore there's no need for a covering lock. */
/** Initialize the AUTO_INCREMENT column metadata.
Since a partial table definition for a persistent table can already be
present in the InnoDB dict_sys cache before it is accessed from SQL,
we have to initialize the AUTO_INCREMENT counter on the first
ha_innobase::open().
@param[in,out] table persistent table
@param[in] field the AUTO_INCREMENT column */
static
void
ha_innobase::innobase_initialize_autoinc()
/*======================================*/
initialize_auto_increment(dict_table_t* table, const Field* field)
{
ulonglong auto_inc;
const Field* field = table->found_next_number_field;
ut_ad(!dict_table_is_temporary(table));
if (field != NULL) {
auto_inc = innobase_get_int_col_max_value(field);
ut_ad(!innobase_is_v_fld(field));
const unsigned col_no = innodb_col_no(field);
/* autoinc column cannot be virtual column */
ut_ad(!innobase_is_v_fld(field));
} else {
/* We have no idea what's been passed in to us as the
autoinc column. We set it to the 0, effectively disabling
updates to the table. */
auto_inc = 0;
dict_table_autoinc_lock(table);
ib::info() << "Unable to determine the AUTOINC column name";
}
table->persistent_autoinc = 1
+ dict_table_get_nth_col_pos(table, col_no, NULL);
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
if (table->autoinc) {
/* Already initialized. Our caller checked
table->persistent_autoinc without
dict_table_autoinc_lock(), and there might be multiple
ha_innobase::open() executing concurrently. */
} else if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
/* If the recovery level is set so high that writes
are disabled we force the AUTOINC counter to 0
value effectively disabling writes to the table.
@@ -6776,70 +6778,16 @@ ha_innobase::innobase_initialize_autoinc()
tables can be dumped with minimal hassle. If an error
were returned in this case, the first attempt to read
the table would fail and subsequent SELECTs would succeed. */
auto_inc = 0;
} else if (field == NULL) {
/* This is a far more serious error, best to avoid
opening the table and return failure. */
my_error(ER_AUTOINC_READ_FAILED, MYF(0));
} else {
dict_index_t* index;
const char* col_name;
ib_uint64_t read_auto_inc;
ulint err;
update_thd(ha_thd());
col_name = field->field_name;
index = innobase_get_index(table->s->next_number_index);
/* Execute SELECT MAX(col_name) FROM TABLE; */
err = row_search_max_autoinc(index, col_name, &read_auto_inc);
switch (err) {
case DB_SUCCESS: {
ulonglong col_max_value;
col_max_value = innobase_get_int_col_max_value(field);
/* At the this stage we do not know the increment
nor the offset, so use a default increment of 1. */
auto_inc = innobase_next_autoinc(
read_auto_inc, 1, 1, 0, col_max_value);
break;
}
case DB_RECORD_NOT_FOUND:
ib::error() << "MariaDB and InnoDB data dictionaries are"
" out of sync. Unable to find the AUTOINC"
" column " << col_name << " in the InnoDB"
" table " << index->table->name << ". We set"
" the next AUTOINC column value to 0, in"
" effect disabling the AUTOINC next value"
" generation.";
ib::info() << "You can either set the next AUTOINC"
" value explicitly using ALTER TABLE or fix"
" the data dictionary by recreating the"
" table.";
/* This will disable the AUTOINC generation. */
auto_inc = 0;
/* We want the open to succeed, so that the user can
take corrective action. ie. reads should succeed but
updates should fail. */
err = DB_SUCCESS;
break;
default:
/* row_search_max_autoinc() should only return
one of DB_SUCCESS or DB_RECORD_NOT_FOUND. */
ut_error;
}
} else if (table->persistent_autoinc) {
table->autoinc = innobase_next_autoinc(
btr_read_autoinc_with_fallback(table, col_no),
1 /* need */,
1 /* auto_increment_increment */,
0 /* auto_increment_offset */,
innobase_get_int_col_max_value(field));
}
dict_table_autoinc_initialize(m_prebuilt->table, auto_inc);
dict_table_autoinc_unlock(table);
}
/*****************************************************************//**
@@ -7199,22 +7147,12 @@ ha_innobase::open(
dict_table_get_format(m_prebuilt->table));
}
/* Only if the table has an AUTOINC column. */
if (m_prebuilt->table != NULL
&& !m_prebuilt->table->ibd_file_missing
&& table->found_next_number_field != NULL) {
dict_table_autoinc_lock(m_prebuilt->table);
/* Since a table can already be "open" in InnoDB's internal
data dictionary, we only init the autoinc counter once, the
first time the table is loaded. We can safely reuse the
autoinc value from a previous MySQL open. */
if (dict_table_autoinc_read(m_prebuilt->table) == 0) {
innobase_initialize_autoinc();
}
dict_table_autoinc_unlock(m_prebuilt->table);
if (m_prebuilt->table == NULL
|| dict_table_is_temporary(m_prebuilt->table)
|| m_prebuilt->table->persistent_autoinc
|| m_prebuilt->table->ibd_file_missing) {
} else if (const Field* ai = table->found_next_number_field) {
initialize_auto_increment(m_prebuilt->table, ai);
}
/* Set plugin parser for fulltext index */
@@ -7270,6 +7208,24 @@ ha_innobase::open(
DBUG_RETURN(0);
}
/** Convert MySQL column number to dict_table_t::cols[] offset.
@param[in] field non-virtual column
@return column number relative to dict_table_t::cols[] */
unsigned
innodb_col_no(const Field* field)
{
ut_ad(!innobase_is_s_fld(field));
const TABLE* table = field->table;
unsigned col_no = 0;
ut_ad(field == table->field[field->field_index]);
for (unsigned i = 0; i < field->field_index; i++) {
if (table->field[i]->stored_in_db()) {
col_no++;
}
}
return(col_no);
}
/** Opens dictionary table object using table name. For partition, we need to
try alternative lower/upper case names to support moving data files across
platforms.
@@ -9250,28 +9206,32 @@ innodb_fill_old_vcol_val(
return(buf);
}
/**********************************************************************//**
Checks which fields have changed in a row and stores information
of them to an update vector.
/** Calculate an update vector corresponding to the changes
between old_row and new_row.
@param[out] uvect update vector
@param[in] old_row current row in MySQL format
@param[in] new_row intended updated row in MySQL format
@param[in] table MySQL table handle
@param[in,out] upd_buff buffer to use for converted values
@param[in] buff_len length of upd_buff
@param[in,out] prebuilt InnoDB execution context
@param[out] auto_inc updated AUTO_INCREMENT value, or 0 if none
@return DB_SUCCESS or error code */
static
dberr_t
calc_row_difference(
/*================*/
upd_t* uvect, /*!< in/out: update vector */
const uchar* old_row, /*!< in: old row in MySQL format */
uchar* new_row, /*!< in: new row in MySQL format */
TABLE* table, /*!< in: table in MySQL data
dictionary */
uchar* upd_buff, /*!< in: buffer to use */
ulint buff_len, /*!< in: buffer length */
row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */
THD* thd) /*!< in: user thread */
upd_t* uvect,
const uchar* old_row,
uchar* new_row,
TABLE* table,
uchar* upd_buff,
ulint buff_len,
row_prebuilt_t* prebuilt,
ib_uint64_t& auto_inc)
{
uchar* original_upd_buff = upd_buff;
Field* field;
enum_field_types field_mysql_type;
uint n_fields;
ulint o_len;
ulint n_len;
ulint col_pack_len;
@@ -9288,19 +9248,19 @@ calc_row_difference(
uint i;
ibool changes_fts_column = FALSE;
ibool changes_fts_doc_col = FALSE;
trx_t* trx = thd_to_trx(thd);
trx_t* const trx = prebuilt->trx;
doc_id_t doc_id = FTS_NULL_DOC_ID;
ulint num_v = 0;
ut_ad(!srv_read_only_mode);
n_fields = table->s->fields;
clust_index = dict_table_get_first_index(prebuilt->table);
auto_inc = 0;
/* We use upd_buff to convert changed fields */
buf = (byte*) upd_buff;
for (i = 0; i < n_fields; i++) {
for (i = 0; i < table->s->fields; i++) {
field = table->field[i];
bool is_virtual = innobase_is_v_fld(field);
dict_col_t* col;
@@ -9521,11 +9481,22 @@ calc_row_difference(
dfield_set_null(vfield);
}
num_v++;
ut_ad(field != table->found_next_number_field);
} else {
ufield->field_no = dict_col_get_clust_pos(
&prebuilt->table->cols[i - num_v],
clust_index);
ufield->old_v_val = NULL;
if (field != table->found_next_number_field
|| dfield_is_null(&ufield->new_val)) {
} else {
auto_inc = row_parse_int(
static_cast<const byte*>(
ufield->new_val.data),
ufield->new_val.len,
col->mtype,
col->prtype & DATA_UNSIGNED);
}
}
n_changed++;
@@ -9787,20 +9758,15 @@ ha_innobase::update_row(
}
}
upd_t* uvect;
if (m_prebuilt->upd_node) {
uvect = m_prebuilt->upd_node->update;
} else {
uvect = row_get_prebuilt_update_vector(m_prebuilt);
}
upd_t* uvect = row_get_prebuilt_update_vector(m_prebuilt);
ib_uint64_t autoinc;
/* Build an update vector from the modified fields in the rows
(uses m_upd_buf of the handle) */
error = calc_row_difference(
uvect, old_row, new_row, table, m_upd_buf, m_upd_buf_size,
m_prebuilt, m_user_thd);
m_prebuilt, autoinc);
if (error != DB_SUCCESS) {
goto func_exit;
@@ -9821,42 +9787,29 @@ ha_innobase::update_row(
error = row_update_for_mysql((byte*) old_row, m_prebuilt);
/* We need to do some special AUTOINC handling for the following case:
if (error == DB_SUCCESS && autoinc) {
/* A value for an AUTO_INCREMENT column
was specified in the UPDATE statement. */
INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
autoinc = innobase_next_autoinc(
autoinc, 1,
m_prebuilt->autoinc_increment,
m_prebuilt->autoinc_offset,
innobase_get_int_col_max_value(
table->found_next_number_field));
We need to use the AUTOINC counter that was actually used by
MySQL in the UPDATE statement, which can be different from the
value used in the INSERT statement. */
error = innobase_set_max_autoinc(autoinc);
if (error == DB_SUCCESS
&& table->next_number_field
&& new_row == table->record[0]
&& thd_sql_command(m_user_thd) == SQLCOM_INSERT
&& trx->duplicates) {
ulonglong auto_inc;
ulonglong col_max_value;
auto_inc = table->next_number_field->val_int();
/* We need the upper limit of the col type to check for
whether we update the table autoinc counter or not. */
col_max_value =
innobase_get_int_col_max_value(table->next_number_field);
if (auto_inc <= col_max_value && auto_inc != 0) {
ulonglong offset;
ulonglong increment;
offset = m_prebuilt->autoinc_offset;
increment = m_prebuilt->autoinc_increment;
auto_inc = innobase_next_autoinc(
auto_inc, 1, increment, offset, col_max_value);
error = innobase_set_max_autoinc(auto_inc);
if (m_prebuilt->table->persistent_autoinc) {
/* Update the PAGE_ROOT_AUTO_INC. Yes, we do
this even if dict_table_t::autoinc already was
greater than autoinc, because we cannot know
if any INSERT actually used (and wrote to
PAGE_ROOT_AUTO_INC) a value bigger than our
autoinc. */
btr_write_autoinc(dict_table_get_first_index(
m_prebuilt->table),
autoinc);
}
}
@@ -14271,34 +14224,40 @@ create_table_info_t::create_table_update_dict()
}
}
/* Note: We can't call update_thd() as m_prebuilt will not be
setup at this stage and so we use thd. */
if (const Field* ai = m_form->found_next_number_field) {
ut_ad(!innobase_is_v_fld(ai));
/* We need to copy the AUTOINC value from the old table if
this is an ALTER|OPTIMIZE TABLE or CREATE INDEX because CREATE INDEX
does a table copy too. If query was one of :
ib_uint64_t autoinc = m_create_info->auto_increment_value;
CREATE TABLE ...AUTO_INCREMENT = x; or
ALTER TABLE...AUTO_INCREMENT = x; or
OPTIMIZE TABLE t; or
CREATE INDEX x on t(...);
Find out a table definition from the dictionary and get
the current value of the auto increment field. Set a new
value to the auto increment field if the value is greater
than the maximum value in the column. */
if (((m_create_info->used_fields & HA_CREATE_USED_AUTO)
|| thd_sql_command(m_thd) == SQLCOM_ALTER_TABLE
|| thd_sql_command(m_thd) == SQLCOM_OPTIMIZE
|| thd_sql_command(m_thd) == SQLCOM_CREATE_INDEX)
&& m_create_info->auto_increment_value > 0) {
ib_uint64_t auto_inc_value;
auto_inc_value = m_create_info->auto_increment_value;
if (autoinc == 0) {
autoinc = 1;
}
dict_table_autoinc_lock(innobase_table);
dict_table_autoinc_initialize(innobase_table, auto_inc_value);
dict_table_autoinc_initialize(innobase_table, autoinc);
if (dict_table_is_temporary(innobase_table)) {
/* AUTO_INCREMENT is not persistent for
TEMPORARY TABLE. Temporary tables are never
evicted. Keep the counter in memory only. */
} else {
const unsigned col_no = innodb_col_no(ai);
innobase_table->persistent_autoinc = 1
+ dict_table_get_nth_col_pos(
innobase_table, col_no, NULL);
/* Persist the "last used" value, which
typically is AUTO_INCREMENT - 1.
In btr_create(), the value 0 was already written. */
if (--autoinc) {
btr_write_autoinc(
dict_table_get_first_index(
innobase_table),
autoinc);
}
}
dict_table_autoinc_unlock(innobase_table);
}
@@ -16412,18 +16371,7 @@ ha_innobase::info_low(
}
if ((flag & HA_STATUS_AUTO) && table->found_next_number_field) {
ulonglong auto_inc_val = innobase_peek_autoinc();
/* Initialize autoinc value if not set. */
if (auto_inc_val == 0) {
dict_table_autoinc_lock(m_prebuilt->table);
innobase_initialize_autoinc();
dict_table_autoinc_unlock(m_prebuilt->table);
auto_inc_val = innobase_peek_autoinc();
}
stats.auto_increment_value = auto_inc_val;
stats.auto_increment_value = innobase_peek_autoinc();
}
func_exit:

View File

@@ -457,7 +457,6 @@ protected:
int end_stmt();
dberr_t innobase_get_autoinc(ulonglong* value);
void innobase_initialize_autoinc();
dberr_t innobase_lock_autoinc();
ulonglong innobase_peek_autoinc();
dberr_t innobase_set_max_autoinc(ulonglong auto_inc);
@@ -1142,6 +1141,13 @@ innobase_build_v_templ_callback(
the table virtual columns' template */
typedef void (*my_gcolumn_templatecallback_t)(const TABLE*, void*);
/** Convert MySQL column number to dict_table_t::cols[] offset.
@param[in] field non-virtual column
@return column number relative to dict_table_t::cols[] */
unsigned
innodb_col_no(const Field* field)
MY_ATTRIBUTE((nonnull, warn_unused_result));
/********************************************************************//**
Helper function to push frm mismatch error to error log and
if needed to sql-layer. */

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2016, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -827,17 +828,6 @@ ha_innopart::alter_table_flags(
return(HA_PARTITION_FUNCTION_SUPPORTED | HA_FAST_CHANGE_PARTITION);
}
/** Internally called for initializing auto increment value.
Only called from ha_innobase::discard_or_import_table_space()
and should not do anything, since it is ha_innopart will initialize
it on first usage. */
int
ha_innopart::innobase_initialize_autoinc()
{
ut_ad(0);
return(0);
}
/** Set the autoinc column max value.
This should only be called once from ha_innobase::open().
Therefore there's no need for a covering lock.
@@ -892,78 +882,33 @@ ha_innopart::initialize_auto_increment(
my_error(ER_AUTOINC_READ_FAILED, MYF(0));
error = HA_ERR_AUTOINC_READ_FAILED;
} else {
dict_index_t* index;
const char* col_name;
ib_uint64_t read_auto_inc;
ib_uint64_t max_auto_inc = 0;
ulint err;
dict_table_t* ib_table;
ulonglong col_max_value;
col_max_value = field->get_max_int_value();
ib_uint64_t col_max_value = field->get_max_int_value();
update_thd(ha_thd());
col_name = field->field_name;
for (uint part = 0; part < m_tot_parts; part++) {
ib_table = m_part_share->get_table_part(part);
dict_table_t* ib_table
= m_part_share->get_table_part(part);
dict_table_autoinc_lock(ib_table);
read_auto_inc = dict_table_autoinc_read(ib_table);
if (read_auto_inc != 0) {
set_if_bigger(max_auto_inc, read_auto_inc);
dict_table_autoinc_unlock(ib_table);
continue;
}
/* Execute SELECT MAX(col_name) FROM TABLE; */
index = m_part_share->get_index(
part, table->s->next_number_index);
err = row_search_max_autoinc(
index, col_name, &read_auto_inc);
ut_ad(ib_table->persistent_autoinc);
ib_uint64_t read_auto_inc
= dict_table_autoinc_read(ib_table);
if (read_auto_inc == 0) {
read_auto_inc = btr_read_autoinc(
dict_table_get_first_index(ib_table));
switch (err) {
case DB_SUCCESS: {
/* At the this stage we do not know the
increment nor the offset,
so use a default increment of 1. */
auto_inc = innobase_next_autoinc(
read_auto_inc = innobase_next_autoinc(
read_auto_inc, 1, 1, 0, col_max_value);
set_if_bigger(max_auto_inc, auto_inc);
dict_table_autoinc_initialize(ib_table,
auto_inc);
break;
}
case DB_RECORD_NOT_FOUND:
ib::error() << "MySQL and InnoDB data"
" dictionaries are out of sync. Unable"
" to find the AUTOINC column "
<< col_name << " in the InnoDB table "
<< index->table->name << ". We set the"
" next AUTOINC column value to 0, in"
" effect disabling the AUTOINC next"
" value generation.";
ib::info() << "You can either set the next"
" AUTOINC value explicitly using ALTER"
" TABLE or fix the data dictionary by"
" recreating the table.";
/* We want the open to succeed, so that the
user can take corrective action. ie. reads
should succeed but updates should fail. */
/* This will disable the AUTOINC generation. */
auto_inc = 0;
goto done;
default:
/* row_search_max_autoinc() should only return
one of DB_SUCCESS or DB_RECORD_NOT_FOUND. */
ut_error;
read_auto_inc);
}
set_if_bigger(auto_inc, read_auto_inc);
dict_table_autoinc_unlock(ib_table);
}
auto_inc = max_auto_inc;
}
done:
@@ -1578,22 +1523,6 @@ ha_innopart::update_partition(
DBUG_VOID_RETURN;
}
/** Save currently highest auto increment value.
@param[in] nr Auto increment value to save. */
void
ha_innopart::save_auto_increment(
ulonglong nr)
{
/* Store it in the shared dictionary of the partition.
TODO: When the new DD is done, store it in the table and make it
persistent! */
dict_table_autoinc_lock(m_prebuilt->table);
dict_table_autoinc_update_if_greater(m_prebuilt->table, nr + 1);
dict_table_autoinc_unlock(m_prebuilt->table);
}
/** Was the last returned row semi consistent read.
In an UPDATE or DELETE, if the row under the cursor was locked by
another transaction, and the engine used an optimistic read of the last

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2016, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -723,12 +724,6 @@ private:
int
next_partition_index();
/** Internally called for initializing auto increment value.
Should never be called, but defined to catch such errors.
@return 0 on success else error code. */
int
innobase_initialize_autoinc();
/** Get the index for the current partition
@param[in] keynr MySQL index number.
@return InnoDB index or NULL. */
@@ -772,12 +767,6 @@ private:
initialize_auto_increment(
bool /* no_lock */);
/** Save currently highest auto increment value.
@param[in] nr Auto increment value to save. */
void
save_auto_increment(
ulonglong nr);
/** Setup the ordered record buffer and the priority queue.
@param[in] used_parts Number of used partitions in query.
@return false for success, else true. */

View File

@@ -173,8 +173,6 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
const dtuple_t* add_cols;
/** autoinc sequence to use */
ib_sequence_t sequence;
/** maximum auto-increment value */
ulonglong max_autoinc;
/** temporary table name to use for old table when renaming tables */
const char* tmp_name;
/** whether the order of the clustered index is unchanged */
@@ -224,7 +222,6 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
add_cols (0),
sequence(prebuilt->trx->mysql_thd,
autoinc_col_min_value_arg, autoinc_col_max_value_arg),
max_autoinc (0),
tmp_name (0),
skip_pk_sort(false),
num_to_add_vcol(0),
@@ -4975,6 +4972,23 @@ new_clustered_failed:
DBUG_EXECUTE_IF("innodb_alter_table_pk_assert_no_sort",
DBUG_ASSERT(ctx->skip_pk_sort););
DBUG_ASSERT(!ctx->new_table->persistent_autoinc);
if (const Field* ai = altered_table->found_next_number_field) {
const unsigned col_no = innodb_col_no(ai);
ctx->new_table->persistent_autoinc = 1
+ dict_table_get_nth_col_pos(
ctx->new_table, col_no, NULL);
/* Initialize the AUTO_INCREMENT sequence
to the rebuilt table from the old one. */
if (!old_table->found_next_number_field) {
} else if (ib_uint64_t autoinc
= btr_read_autoinc(clust_index)) {
btr_write_autoinc(new_clust_index, autoinc);
}
}
if (ctx->online) {
/* Allocate a log for online table rebuild. */
rw_lock_x_lock(&clust_index->lock);
@@ -7400,83 +7414,120 @@ innobase_rename_or_enlarge_columns_cache(
}
}
/** Get the auto-increment value of the table on commit.
/** Set the auto-increment value of the table on commit.
@param ha_alter_info Data used during in-place alter
@param ctx In-place ALTER TABLE context
@param altered_table MySQL table that is being altered
@param old_table MySQL table as it is before the ALTER operation
@return the next auto-increment value (0 if not present) */
static MY_ATTRIBUTE((nonnull, warn_unused_result))
ulonglong
commit_get_autoinc(
/*===============*/
@param old_table MySQL table as it is before the ALTER operation */
static MY_ATTRIBUTE((nonnull))
void
commit_set_autoinc(
Alter_inplace_info* ha_alter_info,
ha_innobase_inplace_ctx*ctx,
const TABLE* altered_table,
const TABLE* old_table)
{
ulonglong max_autoinc;
DBUG_ENTER("commit_get_autoinc");
if (!altered_table->found_next_number_field) {
/* There is no AUTO_INCREMENT column in the table
after the ALTER operation. */
max_autoinc = 0;
} else if (ctx->add_autoinc != ULINT_UNDEFINED) {
ut_ad(ctx->need_rebuild());
/* An AUTO_INCREMENT column was added. Get the last
value from the sequence, which may be based on a
supplied AUTO_INCREMENT value. */
max_autoinc = ctx->sequence.last();
ib_uint64_t autoinc = ctx->sequence.last();
ctx->new_table->autoinc = autoinc;
/* Bulk index creation does not update
PAGE_ROOT_AUTO_INC, so we must persist the "last used"
value here. */
btr_write_autoinc(dict_table_get_first_index(ctx->new_table),
autoinc - 1, true);
} else if ((ha_alter_info->handler_flags
& Alter_inplace_info::CHANGE_CREATE_OPTION)
&& (ha_alter_info->create_info->used_fields
& HA_CREATE_USED_AUTO)) {
/* An AUTO_INCREMENT value was supplied, but the table was not
rebuilt. Get the user-supplied value or the last value from the
sequence. */
ib_uint64_t max_value_table;
dberr_t err;
/* An AUTO_INCREMENT value was supplied by the user.
It must be persisted to the data file. */
const Field* ai = old_table->found_next_number_field;
ut_ad(!strcmp(dict_table_get_col_name(ctx->old_table,
innodb_col_no(ai)),
ai->field_name));
Field* autoinc_field =
old_table->found_next_number_field;
dict_index_t* index = dict_table_get_index_on_first_col(
ctx->old_table, autoinc_field->field_index,
autoinc_field->field_name);
max_autoinc = ha_alter_info->create_info->auto_increment_value;
dict_table_autoinc_lock(ctx->old_table);
err = row_search_max_autoinc(
index, autoinc_field->field_name, &max_value_table);
if (err != DB_SUCCESS) {
ut_ad(0);
max_autoinc = 0;
} else if (max_autoinc <= max_value_table) {
ulonglong col_max_value;
ulonglong offset;
col_max_value = innobase_get_int_col_max_value(autoinc_field);
offset = ctx->prebuilt->autoinc_offset;
max_autoinc = innobase_next_autoinc(
max_value_table, 1, 1, offset,
col_max_value);
ib_uint64_t autoinc
= ha_alter_info->create_info->auto_increment_value;
if (autoinc == 0) {
autoinc = 1;
}
dict_table_autoinc_unlock(ctx->old_table);
if (autoinc >= ctx->old_table->autoinc) {
/* Persist the predecessor of the
AUTO_INCREMENT value as the last used one. */
ctx->new_table->autoinc = autoinc--;
} else {
/* An AUTO_INCREMENT value was not specified.
Read the old counter value from the table. */
ut_ad(old_table->found_next_number_field);
dict_table_autoinc_lock(ctx->old_table);
max_autoinc = ctx->old_table->autoinc;
dict_table_autoinc_unlock(ctx->old_table);
/* Mimic ALGORITHM=COPY in the following scenario:
CREATE TABLE t (a SERIAL);
INSERT INTO t SET a=100;
ALTER TABLE t AUTO_INCREMENT = 1;
INSERT INTO t SET a=NULL;
SELECT * FROM t;
By default, ALGORITHM=INPLACE would reset the
sequence to 1, while after ALGORITHM=COPY, the
last INSERT would use a value larger than 100.
We could only search the tree to know current
max counter in the table and compare. */
const dict_col_t* autoinc_col
= dict_table_get_nth_col(ctx->old_table,
innodb_col_no(ai));
dict_index_t* index
= dict_table_get_first_index(ctx->old_table);
while (index != NULL
&& index->fields[0].col != autoinc_col) {
index = dict_table_get_next_index(index);
}
DBUG_RETURN(max_autoinc);
ut_ad(index);
ib_uint64_t max_in_table = index
? row_search_max_autoinc(index)
: 0;
if (autoinc <= max_in_table) {
ctx->new_table->autoinc = innobase_next_autoinc(
max_in_table, 1,
ctx->prebuilt->autoinc_increment,
ctx->prebuilt->autoinc_offset,
innobase_get_int_col_max_value(ai));
/* Persist the maximum value as the
last used one. */
autoinc = max_in_table;
} else {
/* Persist the predecessor of the
AUTO_INCREMENT value as the last used one. */
ctx->new_table->autoinc = autoinc--;
}
}
btr_write_autoinc(dict_table_get_first_index(ctx->new_table),
autoinc, true);
} else if (ctx->need_rebuild()) {
/* No AUTO_INCREMENT value was specified.
Copy it from the old table. */
ctx->new_table->autoinc = ctx->old_table->autoinc;
/* The persistent value was already copied in
prepare_inplace_alter_table_dict() when ctx->new_table
was created. If this was a LOCK=NONE operation, the
AUTO_INCREMENT values would be updated during
row_log_table_apply(). If this was LOCK!=NONE,
the table contents could not possibly have changed
between prepare_inplace and commit_inplace. */
}
DBUG_VOID_RETURN;
}
/** Add or drop foreign key constraints to the data dictionary tables,
@@ -8557,8 +8608,7 @@ ha_innobase::commit_inplace_alter_table(
DBUG_ASSERT(new_clustered == ctx->need_rebuild());
ctx->max_autoinc = commit_get_autoinc(
ha_alter_info, ctx, altered_table, table);
commit_set_autoinc(ha_alter_info, ctx, altered_table, table);
if (ctx->need_rebuild()) {
ctx->tmp_name = dict_mem_create_temporary_tablename(
@@ -8896,14 +8946,6 @@ foreign_fail:
(*pctx);
DBUG_ASSERT(ctx->need_rebuild() == new_clustered);
if (altered_table->found_next_number_field) {
dict_table_t* t = ctx->new_table;
dict_table_autoinc_lock(t);
dict_table_autoinc_initialize(t, ctx->max_autoinc);
dict_table_autoinc_unlock(t);
}
bool add_fts = false;
/* Publish the created fulltext index, if any.

View File

@@ -2,7 +2,7 @@
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2014, 2015, MariaDB Corporation. All Rights Reserved.
Copyright (c) 2014, 2016, MariaDB Corporation. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -353,6 +353,34 @@ btr_free(
const page_id_t& page_id,
const page_size_t& page_size);
/** Read the last used AUTO_INCREMENT value from PAGE_ROOT_AUTO_INC.
@param[in,out] index clustered index
@return the last used AUTO_INCREMENT value
@retval 0 on error or if no AUTO_INCREMENT value was used yet */
ib_uint64_t
btr_read_autoinc(dict_index_t* index)
MY_ATTRIBUTE((nonnull, warn_unused_result));
/** Read the last used AUTO_INCREMENT value from PAGE_ROOT_AUTO_INC,
or fall back to MAX(auto_increment_column).
@param[in] table table containing an AUTO_INCREMENT column
@param[in] col_no index of the AUTO_INCREMENT column
@return the AUTO_INCREMENT value
@retval 0 on error or if no AUTO_INCREMENT value was used yet */
ib_uint64_t
btr_read_autoinc_with_fallback(const dict_table_t* table, unsigned col_no)
MY_ATTRIBUTE((nonnull, warn_unused_result));
/** Write the next available AUTO_INCREMENT value to PAGE_ROOT_AUTO_INC.
@param[in,out] index clustered index
@param[in] autoinc the AUTO_INCREMENT value
@param[in] reset whether to reset the AUTO_INCREMENT
to a possibly smaller value than currently
exists in the page */
void
btr_write_autoinc(dict_index_t* index, ib_uint64_t autoinc, bool reset = false)
MY_ATTRIBUTE((nonnull));
/*************************************************************//**
Makes tree one level higher by splitting the root, and inserts
the tuple. It is assumed that mtr contains an x-latch on the tree.

View File

@@ -190,7 +190,10 @@ btr_cur_search_to_nth_level(
RW_S_LATCH, or 0 */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
mtr_t* mtr); /*!< in: mtr */
mtr_t* mtr, /*!< in/out: mini-transaction */
ib_uint64_t autoinc = 0);
/*!< in: PAGE_ROOT_AUTO_INC to be written
(0 if none) */
/*****************************************************************//**
Opens a cursor at either end of an index.

View File

@@ -114,9 +114,11 @@ btr_pcur_open_low(
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
ib_uint64_t autoinc,/*!< in: PAGE_ROOT_AUTO_INC to be written
(0 if none) */
mtr_t* mtr); /*!< in: mtr */
#define btr_pcur_open(i,t,md,l,c,m) \
btr_pcur_open_low(i,0,t,md,l,c,__FILE__,__LINE__,m)
btr_pcur_open_low(i,0,t,md,l,c,__FILE__,__LINE__,0,m)
/**************************************************************//**
Opens an persistent cursor to an index tree without initializing the
cursor. */

View File

@@ -434,6 +434,8 @@ btr_pcur_open_low(
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
ib_uint64_t autoinc,/*!< in: PAGE_ROOT_AUTO_INC to be written
(0 if none) */
mtr_t* mtr) /*!< in: mtr */
{
btr_cur_t* btr_cursor;
@@ -454,7 +456,7 @@ btr_pcur_open_low(
err = btr_cur_search_to_nth_level(
index, level, tuple, mode, latch_mode,
btr_cursor, 0, file, line, mtr);
btr_cursor, 0, file, line, mtr, autoinc);
if (err != DB_SUCCESS) {
ib::warn() << " Error code: " << err

View File

@@ -2,7 +2,7 @@
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2013, 2015, MariaDB Corporation.
Copyright (c) 2013, 2016, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -327,46 +327,52 @@ dict_table_autoinc_lock(
/*====================*/
dict_table_t* table) /*!< in/out: table */
MY_ATTRIBUTE((nonnull));
/********************************************************************//**
Unconditionally set the autoinc counter. */
/** Unconditionally set the AUTO_INCREMENT counter.
@param[in,out] table table or partition
@param[in] value next available AUTO_INCREMENT value */
MY_ATTRIBUTE((nonnull))
UNIV_INLINE
void
dict_table_autoinc_initialize(
/*==========================*/
dict_table_t* table, /*!< in/out: table */
ib_uint64_t value) /*!< in: next value to assign to a row */
MY_ATTRIBUTE((nonnull));
dict_table_autoinc_initialize(dict_table_t* table, ib_uint64_t value)
{
ut_ad(dict_table_autoinc_own(table));
table->autoinc = value;
}
/** Store autoinc value when the table is evicted.
@param[in] table table evicted */
void
dict_table_autoinc_store(
const dict_table_t* table);
/** Restore autoinc value when the table is loaded.
@param[in] table table loaded */
void
dict_table_autoinc_restore(
dict_table_t* table);
/********************************************************************//**
Reads the next autoinc value (== autoinc counter value), 0 if not yet
initialized.
@return value for a new row, or 0 */
/**
@param[in] table table or partition
@return the next AUTO_INCREMENT counter value
@retval 0 if AUTO_INCREMENT is not yet initialized */
MY_ATTRIBUTE((nonnull, warn_unused_result))
UNIV_INLINE
ib_uint64_t
dict_table_autoinc_read(
/*====================*/
const dict_table_t* table) /*!< in: table */
MY_ATTRIBUTE((nonnull, warn_unused_result));
/********************************************************************//**
Updates the autoinc counter if the value supplied is greater than the
current value. */
void
dict_table_autoinc_update_if_greater(
/*=================================*/
dict_table_autoinc_read(const dict_table_t* table)
{
ut_ad(dict_table_autoinc_own(table));
return(table->autoinc);
}
/** Update the AUTO_INCREMENT sequence if the value supplied is greater
than the current value.
@param[in,out] table table or partition
@param[in] value AUTO_INCREMENT value that was assigned to a row
@return whether the AUTO_INCREMENT sequence was updated */
MY_ATTRIBUTE((nonnull))
UNIV_INLINE
bool
dict_table_autoinc_update_if_greater(dict_table_t* table, ib_uint64_t value)
{
ut_ad(dict_table_autoinc_own(table));
if (value > table->autoinc) {
table->autoinc = value;
return(true);
}
return(false);
}
dict_table_t* table, /*!< in/out: table */
ib_uint64_t value) /*!< in: value which was assigned to a row */
MY_ATTRIBUTE((nonnull));
/********************************************************************//**
Release the autoinc lock. */
void
@@ -412,8 +418,9 @@ void
dict_table_remove_from_cache_low(
/*=============================*/
dict_table_t* table, /*!< in, own: table */
ibool lru_evict); /*!< in: TRUE if table being evicted
ibool lru_evict) /*!< in: TRUE if table being evicted
to make room in the table LRU list */
MY_ATTRIBUTE((nonnull));
/**********************************************************************//**
Renames a table object.
@return TRUE if success */
@@ -1746,8 +1753,6 @@ extern dict_sys_t* dict_sys;
/** the data dictionary rw-latch protecting dict_sys */
extern rw_lock_t* dict_operation_lock;
typedef std::map<table_id_t, ib_uint64_t> autoinc_map_t;
/* Dictionary system struct */
struct dict_sys_t{
DictSysMutex mutex; /*!< mutex protecting the data
@@ -1783,8 +1788,6 @@ struct dict_sys_t{
UT_LIST_BASE_NODE_T(dict_table_t)
table_non_LRU; /*!< List of tables that can't be
evicted from the cache */
autoinc_map_t* autoinc_map; /*!< Map to store table id and autoinc
when table is evicted */
};
#endif /* !UNIV_HOTBACKUP */
@@ -2052,18 +2055,6 @@ dict_index_node_ptr_max_size(
/*=========================*/
const dict_index_t* index) /*!< in: index */
MY_ATTRIBUTE((warn_unused_result));
/*****************************************************************//**
Get index by first field of the index
@return index which is having first field matches
with the field present in field_index position of table */
UNIV_INLINE
dict_index_t*
dict_table_get_index_on_first_col(
/*==============================*/
const dict_table_t* table, /*!< in: table */
ulint col_index, /*!< in: position of column
in table */
const char* field_name); /*!< in: field name */
/** Check if a column is a virtual column
@param[in] col column
@return true if it is a virtual column, false otherwise */

View File

@@ -1859,42 +1859,6 @@ dict_table_is_file_per_table(
return(is_file_per_table );
}
/**********************************************************************//**
Get index by first field of the index
@return index which is having first field matches
with the field present in field_index position of table */
UNIV_INLINE
dict_index_t*
dict_table_get_index_on_first_col(
/*==============================*/
const dict_table_t* table, /*!< in: table */
ulint col_index, /*!< in: position of column
in table */
const char* field_name) /*!< in: field name */
{
ut_ad(col_index < table->n_cols);
dict_col_t* column = dict_table_get_nth_col(table, col_index);
for (dict_index_t* index = dict_table_get_first_index(table);
index != NULL; index = dict_table_get_next_index(index)) {
if (index->fields[0].col == column) {
return(index);
}
}
/* If not yet found use field_name */
for (dict_index_t* index = dict_table_get_first_index(table);
index != NULL; index = dict_table_get_next_index(index)) {
if (!strcmp(index->fields[0].name, field_name)) {
return (index);
}
}
ut_error;
return(0);
}
/** Get reference count.
@return current value of n_ref_count */
inline

View File

@@ -1466,6 +1466,11 @@ struct dict_table_t {
/** Number of virtual columns. */
unsigned n_v_cols:10;
/** 1 + the position of autoinc counter field in clustered
index, or 0 if there is no persistent AUTO_INCREMENT column in
the table. */
unsigned persistent_autoinc:10;
/** TRUE if it's not an InnoDB system table or a table that has no FK
relationships. */
unsigned can_be_evicted:1;

View File

@@ -1,5 +1,4 @@
/*****************************************************************************
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2016, MariaDB Corporation
@@ -70,10 +69,12 @@ typedef byte page_header_t;
#define PAGE_N_DIRECTION 14 /* number of consecutive inserts to the same
direction */
#define PAGE_N_RECS 16 /* number of user records on the page */
#define PAGE_MAX_TRX_ID 18 /* highest id of a trx which may have modified
a record on the page; trx_id_t; defined only
in secondary indexes and in the insert buffer
tree */
/** The largest DB_TRX_ID that may have modified a record on the page;
Defined only in secondary index leaf pages and in change buffer leaf pages.
Otherwise written as 0. @see PAGE_ROOT_AUTO_INC */
#define PAGE_MAX_TRX_ID 18
/** The AUTO_INCREMENT value (on persistent clustered index root pages). */
#define PAGE_ROOT_AUTO_INC PAGE_MAX_TRX_ID
#define PAGE_HEADER_PRIV_END 26 /* end of private data structure of the page
header which are set in a page create */
/*----*/
@@ -213,6 +214,32 @@ page_update_max_trx_id(
uncompressed part will be updated, or NULL */
trx_id_t trx_id, /*!< in: transaction id */
mtr_t* mtr); /*!< in/out: mini-transaction */
/** Persist the AUTO_INCREMENT value on a clustered index root page.
@param[in,out] block clustered index root page
@param[in] index clustered index
@param[in] autoinc next available AUTO_INCREMENT value
@param[in,out] mtr mini-transaction
@param[in] reset whether to reset the AUTO_INCREMENT
to a possibly smaller value than currently
exists in the page */
void
page_set_autoinc(
buf_block_t* block,
const dict_index_t* index MY_ATTRIBUTE((unused)),
ib_uint64_t autoinc,
mtr_t* mtr,
bool reset)
MY_ATTRIBUTE((nonnull));
/** Read the AUTO_INCREMENT value from a clustered index root page.
@param[in] page clustered index root page
@return the persisted AUTO_INCREMENT value */
MY_ATTRIBUTE((nonnull, warn_unused_result))
UNIV_INLINE
ib_uint64_t
page_get_autoinc(const page_t* page);
/*************************************************************//**
Returns the RTREE SPLIT SEQUENCE NUMBER (FIL_RTREE_SPLIT_SEQ_NUM).
@return SPLIT SEQUENCE NUMBER */

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2016, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -108,6 +109,17 @@ page_update_max_trx_id(
}
}
/** Read the AUTO_INCREMENT value from a clustered index root page.
@param[in] page clustered index root page
@return the persisted AUTO_INCREMENT value */
UNIV_INLINE
ib_uint64_t
page_get_autoinc(const page_t* page)
{
ut_ad(page_is_root(page));
return(mach_read_from_8(PAGE_HEADER + PAGE_ROOT_AUTO_INC + page));
}
/*************************************************************//**
Returns the RTREE SPLIT SEQUENCE NUMBER (FIL_RTREE_SPLIT_SEQ_NUM).
@return SPLIT SEQUENCE NUMBER */

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2016, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -315,6 +316,22 @@ row_get_clust_rec(
mtr_t* mtr) /*!< in: mtr */
MY_ATTRIBUTE((nonnull, warn_unused_result));
/** Parse the integer data from specified data, which could be
DATA_INT, DATA_FLOAT or DATA_DOUBLE. If the value is less than 0
and the type is not unsigned then we reset the value to 0
@param[in] data data to read
@param[in] len length of data
@param[in] mtype mtype of data
@param[in] unsigned_type if the data is unsigned
@return the integer value from the data */
inline
ib_uint64_t
row_parse_int(
const byte* data,
ulint len,
ulint mtype,
bool unsigned_type);
/** Result of row_search_index_entry */
enum row_search_result {
ROW_FOUND = 0, /*!< the record was found */

View File

@@ -173,3 +173,52 @@ row_build_row_ref_fast(
}
}
}
/** Parse the integer data from specified data, which could be
DATA_INT, DATA_FLOAT or DATA_DOUBLE. If the value is less than 0
and the type is not unsigned then we reset the value to 0
@param[in] data data to read
@param[in] len length of data
@param[in] mtype mtype of data
@param[in] unsigned_type if the data is unsigned
@return the integer value from the data */
ib_uint64_t
row_parse_int(
const byte* data,
ulint len,
ulint mtype,
bool unsigned_type)
{
ib_uint64_t value = 0;
switch (mtype) {
case DATA_INT:
ut_a(len <= sizeof value);
value = mach_read_int_type(data, len, unsigned_type);
break;
case DATA_FLOAT:
ut_a(len == sizeof(float));
value = mach_float_read(data);
break;
case DATA_DOUBLE:
ut_a(len == sizeof(double));
value = mach_double_read(data);
break;
default:
ut_error;
}
if (!unsigned_type && static_cast<int64_t>(value) < 0) {
value = 0;
}
return(value);
}

View File

@@ -230,15 +230,12 @@ row_search_check_if_query_cache_permitted(
trx_t* trx, /*!< in: transaction object */
const char* norm_name); /*!< in: concatenation of database name,
'/' char, table name */
/*******************************************************************//**
Read the max AUTOINC value from an index.
@return DB_SUCCESS if all OK else error code */
dberr_t
row_search_max_autoinc(
/*===================*/
dict_index_t* index, /*!< in: index to search */
const char* col_name, /*!< in: autoinc column name */
ib_uint64_t* value) /*!< out: AUTOINC value read */
/** Read the max AUTOINC value from an index.
@param[in] index index starting with an AUTO_INCREMENT column
@return the largest AUTO_INCREMENT value
@retval 0 if no records were found */
ib_uint64_t
row_search_max_autoinc(dict_index_t* index)
MY_ATTRIBUTE((nonnull, warn_unused_result));
/** A structure for caching column values for prefetched rows */

View File

@@ -228,6 +228,40 @@ page_set_max_trx_id(
}
}
/** Persist the AUTO_INCREMENT value on a clustered index root page.
@param[in,out] block clustered index root page
@param[in] index clustered index
@param[in] autoinc next available AUTO_INCREMENT value
@param[in,out] mtr mini-transaction
@param[in] reset whether to reset the AUTO_INCREMENT
to a possibly smaller value than currently
exists in the page */
void
page_set_autoinc(
buf_block_t* block,
const dict_index_t* index MY_ATTRIBUTE((unused)),
ib_uint64_t autoinc,
mtr_t* mtr,
bool reset)
{
ut_ad(mtr_memo_contains_flagged(
mtr, block, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX));
ut_ad(dict_index_is_clust(index));
ut_ad(index->page == block->page.id.page_no());
ut_ad(index->space == block->page.id.space());
byte* field = PAGE_HEADER + PAGE_ROOT_AUTO_INC
+ buf_block_get_frame(block);
if (!reset && mach_read_from_8(field) >= autoinc) {
/* nothing to update */
} else if (page_zip_des_t* page_zip = buf_block_get_page_zip(block)) {
mach_write_to_8(field, autoinc);
page_zip_write_header(page_zip, field, 8, mtr);
} else {
mlog_write_ull(field, autoinc, mtr);
}
}
/************************************************************//**
Allocates a block of memory from the heap of an index page.
@return pointer to start of allocated buffer, or NULL if allocation fails */

View File

@@ -4753,19 +4753,19 @@ page_zip_reorganize(
page_get_infimum_rec(temp_page),
index, mtr);
/* Temp-Tables are not shared across connection and so we avoid
locking of temp-tables as there would be no 2 trx trying to
operate on same temp-table in parallel.
max_trx_id is use to track which all trxs wrote to the page
in parallel but in case of temp-table this can is not needed. */
if (!dict_index_is_clust(index)
&& !dict_table_is_temporary(index->table)
&& page_is_leaf(temp_page)) {
/* Copy max trx id to recreated page */
trx_id_t max_trx_id = page_get_max_trx_id(temp_page);
page_set_max_trx_id(block, NULL, max_trx_id, NULL);
ut_ad(max_trx_id != 0);
}
/* Copy the PAGE_MAX_TRX_ID or PAGE_ROOT_AUTO_INC. */
memcpy(page + (PAGE_HEADER + PAGE_MAX_TRX_ID),
temp_page + (PAGE_HEADER + PAGE_MAX_TRX_ID), 8);
/* PAGE_MAX_TRX_ID must be set on secondary index leaf pages. */
ut_ad(dict_index_is_clust(index) || !page_is_leaf(temp_page)
|| dict_table_is_temporary(index->table)
|| page_get_max_trx_id(page) != 0);
/* PAGE_MAX_TRX_ID must be zero on non-leaf pages other than
clustered index root pages. */
ut_ad(page_get_max_trx_id(page) == 0
|| (dict_index_is_clust(index)
? page_is_root(temp_page)
: page_is_leaf(temp_page)));
/* Restore logging. */
mtr_set_log_mode(mtr, log_mode);

View File

@@ -4009,18 +4009,15 @@ row_import_for_mysql(
table->ibd_file_missing = false;
table->flags2 &= ~DICT_TF2_DISCARDED;
/* Set autoinc value read from cfg file. The value is set to zero
if the cfg file is missing and is initialized later from table
column value. */
/* Set autoinc value read from .cfg file, if one was specified.
Otherwise, keep the PAGE_ROOT_AUTO_INC as is. */
if (autoinc) {
ib::info() << table->name << " autoinc value set to "
<< autoinc;
dict_table_autoinc_lock(table);
dict_table_autoinc_initialize(table, autoinc);
dict_table_autoinc_unlock(table);
ut_a(err == DB_SUCCESS);
table->autoinc = autoinc--;
btr_write_autoinc(dict_table_get_first_index(table), autoinc);
}
return(row_import_cleanup(prebuilt, trx, err));
}

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2016, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -2473,6 +2474,7 @@ row_ins_clust_index_entry_low(
dberr_t err = DB_SUCCESS;
big_rec_t* big_rec = NULL;
mtr_t mtr;
ib_uint64_t auto_inc = 0;
mem_heap_t* offsets_heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
@@ -2487,7 +2489,6 @@ row_ins_clust_index_entry_low(
ut_ad(!thr_get_trx(thr)->in_rollback);
mtr_start(&mtr);
mtr.set_named_space(index->space);
if (dict_table_is_temporary(index->table)) {
/* Disable REDO logging as the lifetime of temp-tables is
@@ -2496,23 +2497,41 @@ row_ins_clust_index_entry_low(
Disable locking as temp-tables are local to a connection. */
ut_ad(flags & BTR_NO_LOCKING_FLAG);
ut_ad(!dict_index_is_online_ddl(index));
ut_ad(!index->table->persistent_autoinc);
mtr.set_log_mode(MTR_LOG_NO_REDO);
}
} else {
mtr.set_named_space(index->space);
if (mode == BTR_MODIFY_LEAF && dict_index_is_online_ddl(index)) {
if (mode == BTR_MODIFY_LEAF
&& dict_index_is_online_ddl(index)) {
mode = BTR_MODIFY_LEAF | BTR_ALREADY_S_LATCHED;
mtr_s_lock(dict_index_get_lock(index), &mtr);
}
if (unsigned ai = index->table->persistent_autoinc) {
/* Prepare to persist the AUTO_INCREMENT value
from the index entry to PAGE_ROOT_AUTO_INC. */
const dfield_t* dfield = dtuple_get_nth_field(
entry, ai - 1);
auto_inc = dfield_is_null(dfield)
? 0
: row_parse_int(static_cast<const byte*>(
dfield->data),
dfield->len,
dfield->type.mtype,
dfield->type.prtype
& DATA_UNSIGNED);
}
}
/* Note that we use PAGE_CUR_LE as the search mode, because then
the function will return in both low_match and up_match of the
cursor sensible values */
btr_pcur_open(index, entry, PAGE_CUR_LE, mode, &pcur, &mtr);
btr_pcur_open_low(index, 0, entry, PAGE_CUR_LE, mode, &pcur,
__FILE__, __LINE__, auto_inc, &mtr);
cursor = btr_pcur_get_btr_cur(&pcur);
if (cursor) {
cursor->thr = thr;
}
#ifdef UNIV_DEBUG
{

View File

@@ -1705,24 +1705,18 @@ row_get_prebuilt_update_vector(
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
handle */
{
dict_table_t* table = prebuilt->table;
upd_node_t* node;
ut_ad(prebuilt && table && prebuilt->trx);
if (prebuilt->upd_node == NULL) {
/* Not called before for this handle: create an update node
and query graph to the prebuilt struct */
node = row_create_update_node_for_mysql(table, prebuilt->heap);
prebuilt->upd_node = node;
prebuilt->upd_node = row_create_update_node_for_mysql(
prebuilt->table, prebuilt->heap);
prebuilt->upd_graph = static_cast<que_fork_t*>(
que_node_get_parent(
pars_complete_graph_for_exec(
static_cast<upd_node_t*>(node),
prebuilt->upd_node,
prebuilt->trx, prebuilt->heap,
prebuilt)));

View File

@@ -6045,29 +6045,7 @@ row_search_autoinc_read_column(
data = rec_get_nth_field(rec, offsets, col_no, &len);
switch (mtype) {
case DATA_INT:
ut_a(len <= sizeof value);
value = mach_read_int_type(data, len, unsigned_type);
break;
case DATA_FLOAT:
ut_a(len == sizeof(float));
value = (ib_uint64_t) mach_float_read(data);
break;
case DATA_DOUBLE:
ut_a(len == sizeof(double));
value = (ib_uint64_t) mach_double_read(data);
break;
default:
ut_error;
}
if (!unsigned_type && static_cast<int64_t>(value) < 0) {
value = 0;
}
value = row_parse_int(data, len, mtype, unsigned_type);
func_exit:
if (UNIV_LIKELY_NULL(heap)) {
@@ -6113,42 +6091,27 @@ row_search_get_max_rec(
return(rec);
}
/*******************************************************************//**
Read the max AUTOINC value from an index.
@return DB_SUCCESS if all OK else error code, DB_RECORD_NOT_FOUND if
column name can't be found in index */
dberr_t
row_search_max_autoinc(
/*===================*/
dict_index_t* index, /*!< in: index to search */
const char* col_name, /*!< in: name of autoinc column */
ib_uint64_t* value) /*!< out: AUTOINC value read */
/** Read the max AUTOINC value from an index.
@param[in] index index starting with an AUTO_INCREMENT column
@return the largest AUTO_INCREMENT value
@retval 0 if no records were found */
ib_uint64_t
row_search_max_autoinc(dict_index_t* index)
{
dict_field_t* dfield = dict_index_get_nth_field(index, 0);
dberr_t error = DB_SUCCESS;
*value = 0;
const dict_field_t* dfield = dict_index_get_nth_field(index, 0);
ib_uint64_t value = 0;
if (strcmp(col_name, dfield->name) != 0) {
error = DB_RECORD_NOT_FOUND;
} else {
mtr_t mtr;
const rec_t* rec;
mtr.start();
mtr_start(&mtr);
rec = row_search_get_max_rec(index, &mtr);
if (rec != NULL) {
ibool unsigned_type = (
dfield->col->prtype & DATA_UNSIGNED);
*value = row_search_autoinc_read_column(
if (const rec_t* rec = row_search_get_max_rec(index, &mtr)) {
value = row_search_autoinc_read_column(
index, rec, 0,
dfield->col->mtype, unsigned_type);
dfield->col->mtype,
dfield->col->prtype & DATA_UNSIGNED);
}
mtr_commit(&mtr);
}
return(error);
mtr.commit();
return(value);
}