Commit f82c8c69 authored by Davi Arnaut's avatar Davi Arnaut

Merge before pushing.

parents 3bdbfd70 19891fe9
......@@ -412,7 +412,10 @@ sub mtr_report_stats ($) {
# When trying to set lower_case_table_names = 2
# on a case sensitive file system. Bug#37402.
/lower_case_table_names was set to 2, even though your the file system '.*' is case sensitive. Now setting lower_case_table_names to 0 to avoid future problems./
/lower_case_table_names was set to 2, even though your the file system '.*' is case sensitive. Now setting lower_case_table_names to 0 to avoid future problems./ or
# this test is expected to print warnings
($testname eq 'main.innodb_bug39438')
)
{
next; # Skip these lines
......
......@@ -169,3 +169,413 @@ t1 CREATE TABLE `t1` (
PRIMARY KEY (`c1`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1
DROP TABLE t1;
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
CREATE TABLE t1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (NULL, 1);
DELETE FROM t1 WHERE c1 = 1;
INSERT INTO t1 VALUES (2,1);
INSERT INTO t1 VALUES (NULL,8);
SELECT * FROM t1;
c1 c2
2 1
3 8
DROP TABLE t1;
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
CREATE TABLE t1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (NULL, 1);
DELETE FROM t1 WHERE c1 = 1;
INSERT INTO t1 VALUES (2,1), (NULL, 8);
INSERT INTO t1 VALUES (NULL,9);
SELECT * FROM t1;
c1 c2
2 1
3 8
5 9
DROP TABLE t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 100
auto_increment_offset 10
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (NULL),(5),(NULL);
INSERT INTO t1 VALUES (250),(NULL);
SELECT * FROM t1;
c1
5
10
110
250
310
INSERT INTO t1 VALUES (1000);
SET @@INSERT_ID=400;
INSERT INTO t1 VALUES(NULL),(NULL);
SELECT * FROM t1;
c1
5
10
110
250
310
400
410
1000
DROP TABLE t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES(0);
SELECT * FROM t1;
c1
1
SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
INSERT INTO t1 VALUES (-1), (NULL),(2),(NULL);
INSERT INTO t1 VALUES (250),(NULL);
SELECT * FROM t1;
c1
-1
1
2
10
110
250
410
SET @@INSERT_ID=400;
INSERT INTO t1 VALUES(NULL),(NULL);
Got one of the listed errors
SELECT * FROM t1;
c1
-1
1
2
10
110
250
410
DROP TABLE t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES(-1);
SELECT * FROM t1;
c1
-1
SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 100
auto_increment_offset 10
INSERT INTO t1 VALUES (-2), (NULL),(2),(NULL);
INSERT INTO t1 VALUES (250),(NULL);
SELECT * FROM t1;
c1
-2
-1
1
2
10
250
310
INSERT INTO t1 VALUES (1000);
SET @@INSERT_ID=400;
INSERT INTO t1 VALUES(NULL),(NULL);
SELECT * FROM t1;
c1
-2
-1
1
2
10
250
310
400
410
1000
DROP TABLE t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES(-1);
Warnings:
Warning 1264 Out of range value for column 'c1' at row 1
SELECT * FROM t1;
c1
1
SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 100
auto_increment_offset 10
INSERT INTO t1 VALUES (-2);
Warnings:
Warning 1264 Out of range value for column 'c1' at row 1
INSERT INTO t1 VALUES (NULL);
INSERT INTO t1 VALUES (2);
INSERT INTO t1 VALUES (NULL);
INSERT INTO t1 VALUES (250);
INSERT INTO t1 VALUES (NULL);
SELECT * FROM t1;
c1
1
2
10
110
210
250
310
INSERT INTO t1 VALUES (1000);
SET @@INSERT_ID=400;
INSERT INTO t1 VALUES(NULL);
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
c1
1
2
10
110
210
250
310
400
1000
1010
DROP TABLE t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES(-1);
Warnings:
Warning 1264 Out of range value for column 'c1' at row 1
SELECT * FROM t1;
c1
1
SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 100
auto_increment_offset 10
INSERT INTO t1 VALUES (-2),(NULL),(2),(NULL);
Warnings:
Warning 1264 Out of range value for column 'c1' at row 1
INSERT INTO t1 VALUES (250),(NULL);
SELECT * FROM t1;
c1
1
2
10
110
210
250
410
INSERT INTO t1 VALUES (1000);
SET @@INSERT_ID=400;
INSERT INTO t1 VALUES(NULL),(NULL);
Got one of the listed errors
SELECT * FROM t1;
c1
1
2
10
110
210
250
410
1000
DROP TABLE t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES(NULL);
INSERT INTO t1 VALUES (9223372036854775794);
SELECT * FROM t1;
c1
1
9223372036854775794
SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 2
auto_increment_offset 10
INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL);
SELECT * FROM t1;
c1
1
9223372036854775794
9223372036854775796
9223372036854775798
9223372036854775800
9223372036854775802
9223372036854775804
9223372036854775806
DROP TABLE t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES(NULL);
INSERT INTO t1 VALUES (18446744073709551603);
SELECT * FROM t1;
c1
1
18446744073709551603
SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 2
auto_increment_offset 10
INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL);
SELECT * FROM t1;
c1
1
18446744073709551603
18446744073709551604
18446744073709551606
18446744073709551608
18446744073709551610
18446744073709551612
18446744073709551614
DROP TABLE t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES(NULL);
INSERT INTO t1 VALUES (18446744073709551603);
SELECT * FROM t1;
c1
1
18446744073709551603
SET @@SESSION.AUTO_INCREMENT_INCREMENT=5, @@SESSION.AUTO_INCREMENT_OFFSET=7;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 5
auto_increment_offset 7
INSERT INTO t1 VALUES (NULL),(NULL);
SELECT * FROM t1;
c1
1
18446744073709551603
18446744073709551607
18446744073709551612
DROP TABLE t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES(NULL);
INSERT INTO t1 VALUES(-9223372036854775806);
INSERT INTO t1 VALUES(-9223372036854775807);
INSERT INTO t1 VALUES(-9223372036854775808);
SELECT * FROM t1;
c1
-9223372036854775808
-9223372036854775807
-9223372036854775806
1
SET @@SESSION.AUTO_INCREMENT_INCREMENT=3, @@SESSION.AUTO_INCREMENT_OFFSET=3;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 3
auto_increment_offset 3
INSERT INTO t1 VALUES (NULL),(NULL), (NULL);
SELECT * FROM t1;
c1
-9223372036854775808
-9223372036854775807
-9223372036854775806
1
3
6
9
DROP TABLE t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES(NULL);
INSERT INTO t1 VALUES (18446744073709551610);
SELECT * FROM t1;
c1
1
18446744073709551610
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCREMENT_OFFSET=1152921504606846976;
Warnings:
Warning 1292 Truncated incorrect auto_increment_increment value: '1152921504606846976'
Warning 1292 Truncated incorrect auto_increment_offset value: '1152921504606846976'
SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 65535
auto_increment_offset 65535
INSERT INTO t1 VALUES (NULL);
SELECT * FROM t1;
c1
1
18446744073709551610
18446744073709551615
DROP TABLE t1;
......@@ -3295,3 +3295,11 @@ info: Records: 5 Duplicates: 0 Warnings: 0
TRUNCATE TABLE t1;
affected rows: 0
DROP TABLE t1;
Variable_name Value
Handler_update 0
Variable_name Value
Handler_delete 0
Variable_name Value
Handler_update 1
Variable_name Value
Handler_delete 1
SET storage_engine=InnoDB;
INSERT INTO bug38231 VALUES (1), (10), (300);
SET autocommit=0;
SELECT * FROM bug38231 FOR UPDATE;
a
1
10
300
TRUNCATE TABLE bug38231;
COMMIT;
DROP TABLE bug38231;
SET storage_engine=InnoDB;
......@@ -115,14 +115,14 @@ master-bin.000001 # Xid # # COMMIT /* XID */
DROP TABLE t1;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 15
Binlog_cache_use 13
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 0
create table t1 (a int) engine=innodb;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 16
Binlog_cache_use 14
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
......@@ -131,7 +131,7 @@ delete from t1;
commit;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 17
Binlog_cache_use 15
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
......
......@@ -139,3 +139,262 @@ SELECT c1 FROM t1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
#
# Bug 38839
# Reset the last value generated at end of statement
#
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (NULL, 1);
DELETE FROM t1 WHERE c1 = 1;
INSERT INTO t1 VALUES (2,1);
INSERT INTO t1 VALUES (NULL,8);
SELECT * FROM t1;
DROP TABLE t1;
# Bug 38839 -- same as above but for multi value insert
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (NULL, 1);
DELETE FROM t1 WHERE c1 = 1;
INSERT INTO t1 VALUES (2,1), (NULL, 8);
INSERT INTO t1 VALUES (NULL,9);
SELECT * FROM t1;
DROP TABLE t1;
#
# Test changes to AUTOINC next value calculation
SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
SHOW VARIABLES LIKE "%auto_inc%";
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (NULL),(5),(NULL);
INSERT INTO t1 VALUES (250),(NULL);
SELECT * FROM t1;
INSERT INTO t1 VALUES (1000);
SET @@INSERT_ID=400;
INSERT INTO t1 VALUES(NULL),(NULL);
SELECT * FROM t1;
DROP TABLE t1;
# Test with SIGNED INT column, by inserting a 0 for the first column value
# 0 is treated in the same was NULL.
# Reset the AUTOINC session variables
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES(0);
SELECT * FROM t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
INSERT INTO t1 VALUES (-1), (NULL),(2),(NULL);
INSERT INTO t1 VALUES (250),(NULL);
SELECT * FROM t1;
SET @@INSERT_ID=400;
# Duplicate error expected here for autoinc_lock_mode != TRADITIONAL
-- error ER_DUP_ENTRY,1062
INSERT INTO t1 VALUES(NULL),(NULL);
SELECT * FROM t1;
DROP TABLE t1;
# Test with SIGNED INT column
# Reset the AUTOINC session variables
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES(-1);
SELECT * FROM t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
SHOW VARIABLES LIKE "%auto_inc%";
INSERT INTO t1 VALUES (-2), (NULL),(2),(NULL);
INSERT INTO t1 VALUES (250),(NULL);
SELECT * FROM t1;
INSERT INTO t1 VALUES (1000);
SET @@INSERT_ID=400;
INSERT INTO t1 VALUES(NULL),(NULL);
SELECT * FROM t1;
DROP TABLE t1;
# Test with UNSIGNED INT column, single insert
# The sign in the value is ignored and a new column value is generated
# Reset the AUTOINC session variables
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES(-1);
SELECT * FROM t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
SHOW VARIABLES LIKE "%auto_inc%";
INSERT INTO t1 VALUES (-2);
INSERT INTO t1 VALUES (NULL);
INSERT INTO t1 VALUES (2);
INSERT INTO t1 VALUES (NULL);
INSERT INTO t1 VALUES (250);
INSERT INTO t1 VALUES (NULL);
SELECT * FROM t1;
INSERT INTO t1 VALUES (1000);
SET @@INSERT_ID=400;
INSERT INTO t1 VALUES(NULL);
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
DROP TABLE t1;
# Test with UNSIGNED INT column, multi-value inserts
# The sign in the value is ignored and a new column value is generated
# Reset the AUTOINC session variables
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES(-1);
SELECT * FROM t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10;
SHOW VARIABLES LIKE "%auto_inc%";
INSERT INTO t1 VALUES (-2),(NULL),(2),(NULL);
INSERT INTO t1 VALUES (250),(NULL);
SELECT * FROM t1;
INSERT INTO t1 VALUES (1000);
SET @@INSERT_ID=400;
# Duplicate error expected here for autoinc_lock_mode != TRADITIONAL
-- error ER_DUP_ENTRY,1062
INSERT INTO t1 VALUES(NULL),(NULL);
SELECT * FROM t1;
DROP TABLE t1;
#
# Check for overflow handling when increment is > 1
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
# TODO: Fix the autoinc init code
# We have to do this because of a bug in the AUTOINC init code.
INSERT INTO t1 VALUES(NULL);
INSERT INTO t1 VALUES (9223372036854775794); -- 2^63 - 14
SELECT * FROM t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10;
SHOW VARIABLES LIKE "%auto_inc%";
# This should just fit
INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL);
SELECT * FROM t1;
DROP TABLE t1;
#
# Check for overflow handling when increment and offser are > 1
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
# TODO: Fix the autoinc init code
# We have to do this because of a bug in the AUTOINC init code.
INSERT INTO t1 VALUES(NULL);
INSERT INTO t1 VALUES (18446744073709551603); -- 2^64 - 13
SELECT * FROM t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10;
SHOW VARIABLES LIKE "%auto_inc%";
# This should fail because of overflow but it doesn't, it seems to be
# a MySQL server bug. It wraps around to 0 for the last value.
# See MySQL Bug# 39828
#
# Instead of wrapping around, it asserts when MySQL is compiled --with-debug
# (see sql/handler.cc:handler::update_auto_increment()). Don't test for
# overflow until Bug #39828 is fixed.
#
# Since this asserts when compiled --with-debug, we can't properly test this
# until Bug #39828 is fixed. For now, this test is meaningless.
#if Bug #39828 is fixed
#INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL);
#else
INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL);
#endif
SELECT * FROM t1;
DROP TABLE t1;
#
# Check for overflow handling when increment and offset are odd numbers
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
# TODO: Fix the autoinc init code
# We have to do this because of a bug in the AUTOINC init code.
INSERT INTO t1 VALUES(NULL);
INSERT INTO t1 VALUES (18446744073709551603); -- 2^64 - 13
SELECT * FROM t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=5, @@SESSION.AUTO_INCREMENT_OFFSET=7;
SHOW VARIABLES LIKE "%auto_inc%";
# This should fail because of overflow but it doesn't. It fails with
# a duplicate entry message because of a MySQL server bug, it wraps
# around. See MySQL Bug# 39828, once MySQL fix the bug we can replace
# the ER_DUP_ENTRY, 1062 below with the appropriate error message
#
# Since this asserts when compiled --with-debug, we can't properly test this
# until Bug #39828 is fixed. For now, this test is meaningless.
#if Bug #39828 is fixed
# Still need to fix this error code, error should mention overflow
#-- error ER_DUP_ENTRY,1062
#INSERT INTO t1 VALUES (NULL),(NULL), (NULL);
#else
INSERT INTO t1 VALUES (NULL),(NULL);
#endif
SELECT * FROM t1;
DROP TABLE t1;
# Check for overflow handling when increment and offset are odd numbers
# and check for large -ve numbers
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
# TODO: Fix the autoinc init code
# We have to do this because of a bug in the AUTOINC init code.
INSERT INTO t1 VALUES(NULL);
INSERT INTO t1 VALUES(-9223372036854775806); -- -2^63 + 2
INSERT INTO t1 VALUES(-9223372036854775807); -- -2^63 + 1
INSERT INTO t1 VALUES(-9223372036854775808); -- -2^63
SELECT * FROM t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=3, @@SESSION.AUTO_INCREMENT_OFFSET=3;
SHOW VARIABLES LIKE "%auto_inc%";
INSERT INTO t1 VALUES (NULL),(NULL), (NULL);
SELECT * FROM t1;
DROP TABLE t1;
#
# Check for overflow handling when increment and offset are very
# large numbers 2^60
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%";
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB;
# TODO: Fix the autoinc init code
# We have to do this because of a bug in the AUTOINC init code.
INSERT INTO t1 VALUES(NULL);
INSERT INTO t1 VALUES (18446744073709551610); -- 2^64 - 2
SELECT * FROM t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCREMENT_OFFSET=1152921504606846976;
SHOW VARIABLES LIKE "%auto_inc%";
# This should fail because of overflow but it doesn't. It wraps around
# and the autoinc values look bogus too.
# See MySQL Bug# 39828, once MySQL fix the bug we can enable the error
# code expected test.
# -- error ER_AUTOINC_READ_FAILED,1467
#
# Since this asserts when compiled --with-debug, we can't properly test this
# until Bug #39828 is fixed. For now, this test is meaningless.
#if Bug #39828 is fixed
#-- error ER_AUTOINC_READ_FAILED,1467
#INSERT INTO t1 VALUES (NULL),(NULL);
#else
INSERT INTO t1 VALUES (NULL);
#endif
SELECT * FROM t1;
DROP TABLE t1;
......@@ -2475,6 +2475,7 @@ SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE table_name = 't2';
DROP TABLE t2;
DROP TABLE t1;
# End 34920 test
#
# Bug #29507 TRUNCATE shows to many rows effected
#
CONNECTION default;
......@@ -2491,6 +2492,36 @@ TRUNCATE TABLE t1;
--disable_info
DROP TABLE t1;
#
# Bug#35537 Innodb doesn't increment handler_update and handler_delete.
#
-- disable_query_log
-- disable_result_log
CONNECT (c1,localhost,root,,);
DROP TABLE IF EXISTS bug35537;
CREATE TABLE bug35537 (
c1 int
) ENGINE=InnoDB;
INSERT INTO bug35537 VALUES (1);
-- enable_result_log
SHOW SESSION STATUS LIKE 'Handler_update%';
SHOW SESSION STATUS LIKE 'Handler_delete%';
UPDATE bug35537 SET c1 = 2 WHERE c1 = 1;
DELETE FROM bug35537 WHERE c1 = 2;
SHOW SESSION STATUS LIKE 'Handler_update%';
SHOW SESSION STATUS LIKE 'Handler_delete%';
DROP TABLE bug35537;
DISCONNECT c1;
CONNECTION default;
#######################################################################
# #
# Please, DO NOT TOUCH this file as well as the innodb.result file. #
......
#
# Bug#38231 Innodb crash in lock_reset_all_on_table() on TRUNCATE + LOCK / UNLOCK
# http://bugs.mysql.com/38231
#
-- source include/have_innodb.inc
SET storage_engine=InnoDB;
# we care only that the following SQL commands do not crash the server
-- disable_query_log
-- disable_result_log
DROP TABLE IF EXISTS bug38231;
CREATE TABLE bug38231 (a INT);
-- connect (con1,localhost,root,,)
-- connect (con2,localhost,root,,)
-- connect (con3,localhost,root,,)
-- connection con1
SET autocommit=0;
LOCK TABLE bug38231 WRITE;
-- connection con2
SET autocommit=0;
-- send
LOCK TABLE bug38231 WRITE;
-- connection con3
SET autocommit=0;
-- send
LOCK TABLE bug38231 WRITE;
-- connection default
-- send
TRUNCATE TABLE bug38231;
-- connection con1
# give time to TRUNCATE and others to be executed; without sleep, sometimes
# UNLOCK executes before TRUNCATE
-- sleep 0.2
# this crashes the server if the bug is present
UNLOCK TABLES;
# clean up
-- connection con2
UNLOCK TABLES;
-- connection con3
UNLOCK TABLES;
-- connection default
-- disconnect con1
-- disconnect con2
-- disconnect con3
# test that TRUNCATE works with with row-level locks
-- enable_query_log
-- enable_result_log
INSERT INTO bug38231 VALUES (1), (10), (300);
-- connect (con4,localhost,root,,)
-- connection con4
SET autocommit=0;
SELECT * FROM bug38231 FOR UPDATE;
-- connection default
TRUNCATE TABLE bug38231;
-- connection con4
COMMIT;
-- connection default
-- disconnect con4
DROP TABLE bug38231;
#
# Bug#39438 Testcase for Bug#39436 crashes on 5.1 in fil_space_get_latch
# http://bugs.mysql.com/39438
#
# This test must be run with innodb_file_per_table=1 because the crash
# only occurs if that option is turned on and DISCARD TABLESPACE only
# works with innodb_file_per_table.
#
-- source include/have_innodb.inc
SET storage_engine=InnoDB;
# we care only that the following SQL commands do not crash the server
-- disable_query_log
-- disable_result_log
DROP TABLE IF EXISTS bug39438;
CREATE TABLE bug39438 (id INT) ENGINE=INNODB;
ALTER TABLE bug39438 DISCARD TABLESPACE;
# this crashes the server if the bug is present
SHOW TABLE STATUS;
DROP TABLE bug39438;
......@@ -15,21 +15,21 @@
# Process this file with automake to create Makefile.in
MYSQLDATAdir = $(localstatedir)
MYSQLSHAREdir = $(pkgdatadir)
MYSQLDATAdir= $(localstatedir)
MYSQLSHAREdir= $(pkgdatadir)
MYSQLBASEdir= $(prefix)
MYSQLLIBdir= $(pkglibdir)
pkgplugindir = $(pkglibdir)/plugin
INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include \
pkgplugindir= $(pkglibdir)/plugin
INCLUDES= -I$(top_srcdir)/include -I$(top_builddir)/include \
-I$(top_srcdir)/regex \
-I$(top_srcdir)/storage/innobase/include \
-I$(top_srcdir)/sql \
-I$(srcdir)
DEFS = @DEFS@
DEFS= @DEFS@
noinst_HEADERS = include/btr0btr.h include/btr0btr.ic \
noinst_HEADERS= include/btr0btr.h include/btr0btr.ic \
include/btr0cur.h include/btr0cur.ic \
include/btr0pcur.h include/btr0pcur.ic \
include/btr0sea.h include/btr0sea.ic \
......@@ -121,9 +121,9 @@ noinst_HEADERS = include/btr0btr.h include/btr0btr.ic \
include/ut0list.ic include/ut0wqueue.h \
include/ha_prototypes.h handler/ha_innodb.h
EXTRA_LIBRARIES = libinnobase.a
noinst_LIBRARIES = @plugin_innobase_static_target@
libinnobase_a_SOURCES = btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c \
EXTRA_LIBRARIES= libinnobase.a
noinst_LIBRARIES= @plugin_innobase_static_target@
libinnobase_a_SOURCES= btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c \
btr/btr0sea.c buf/buf0buf.c buf/buf0flu.c \
buf/buf0lru.c buf/buf0rea.c data/data0data.c \
data/data0type.c dict/dict0boot.c \
......@@ -156,17 +156,17 @@ libinnobase_a_SOURCES = btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c \
handler/ha_innodb.cc
libinnobase_a_CXXFLAGS= $(AM_CFLAGS)
libinnobase_a_CFLAGS = $(AM_CFLAGS)
libinnobase_a_CFLAGS= $(AM_CFLAGS)
EXTRA_LTLIBRARIES = ha_innodb.la
EXTRA_LTLIBRARIES= ha_innodb.la
pkgplugin_LTLIBRARIES= @plugin_innobase_shared_target@
ha_innodb_la_LDFLAGS = -module -rpath $(pkgplugindir)
ha_innodb_la_CXXFLAGS= $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN
ha_innodb_la_CFLAGS = $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN
ha_innodb_la_SOURCES = $(libinnobase_a_SOURCES)
ha_innodb_la_LDFLAGS= -module -rpath $(pkgplugindir)
ha_innodb_la_CXXFLAGS= $(AM_CFLAGS) $(INNODB_DYNAMIC_CFLAGS)
ha_innodb_la_CFLAGS= $(AM_CFLAGS) $(INNODB_DYNAMIC_CFLAGS)
ha_innodb_la_SOURCES= $(libinnobase_a_SOURCES)
EXTRA_DIST = CMakeLists.txt plug.in \
EXTRA_DIST= CMakeLists.txt plug.in \
pars/make_bison.sh pars/make_flex.sh \
pars/pars0grm.y pars/pars0lex.l
......
......@@ -161,6 +161,7 @@ btr_search_info_create(
info->magic_n = BTR_SEARCH_MAGIC_N;
#endif /* UNIV_DEBUG */
info->ref_count = 0;
info->root_guess = NULL;
info->hash_analysis = 0;
......@@ -184,6 +185,31 @@ btr_search_info_create(
return(info);
}
/*********************************************************************
Returns the value of ref_count. The value is protected by
btr_search_latch. */
ulint
btr_search_info_get_ref_count(
/*==========================*/
/* out: ref_count value. */
btr_search_t* info) /* in: search info. */
{
ulint ret;
ut_ad(info);
#ifdef UNIV_SYNC_DEBUG
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
rw_lock_s_lock(&btr_search_latch);
ret = info->ref_count;
rw_lock_s_unlock(&btr_search_latch);
return(ret);
}
/*************************************************************************
Updates the search info of an index about hash successes. NOTE that info
is NOT protected by any semaphore, to save CPU time! Do not assume its fields
......@@ -1022,8 +1048,12 @@ btr_search_drop_page_hash_index(
ha_remove_all_nodes_to_page(table, folds[i], page);
}
ut_a(index->search_info->ref_count > 0);
index->search_info->ref_count--;
block->is_hashed = FALSE;
block->index = NULL;
cleanup:
if (UNIV_UNLIKELY(block->n_pointers)) {
/* Corruption */
......@@ -1244,6 +1274,15 @@ btr_search_build_page_hash_index(
goto exit_func;
}
/* This counter is decremented every time we drop page
hash index entries and is incremented here. Since we can
rebuild hash index for a page that is already hashed, we
have to take care not to increment the counter in that
case. */
if (!block->is_hashed) {
index->search_info->ref_count++;
}
block->is_hashed = TRUE;
block->n_hash_helps = 0;
......
......@@ -42,6 +42,11 @@ initial segment in buf_LRU_get_recent_limit */
#define BUF_LRU_INITIAL_RATIO 8
/* When dropping the search hash index entries before deleting an ibd
file, we build a local array of pages belonging to that tablespace
in the buffer pool. Following is the size of that array. */
#define BUF_LRU_DROP_SEARCH_HASH_SIZE 1024
/* If we switch on the InnoDB monitor because there are too few available
frames in the buffer pool, we set this to TRUE */
ibool buf_lru_switched_on_innodb_mon = FALSE;
......@@ -65,6 +70,120 @@ buf_LRU_block_free_hashed_page(
buf_block_t* block); /* in: block, must contain a file page and
be in a state where it can be freed */
/**********************************************************************
Attempts to drop page hash index on a batch of pages belonging to a
particular space id. */
static
void
buf_LRU_drop_page_hash_batch(
/*=========================*/
ulint id, /* in: space id */
const ulint* arr, /* in: array of page_no */
ulint count) /* in: number of entries in array */
{
ulint i;
ut_ad(arr != NULL);
ut_ad(count <= BUF_LRU_DROP_SEARCH_HASH_SIZE);
for (i = 0; i < count; ++i) {
btr_search_drop_page_hash_when_freed(id, arr[i]);
}
}
/**********************************************************************
When doing a DROP TABLE/DISCARD TABLESPACE we have to drop all page
hash index entries belonging to that table. This function tries to
do that in batch. Note that this is a 'best effort' attempt and does
not guarantee that ALL hash entries will be removed. */
static
void
buf_LRU_drop_page_hash_for_tablespace(
/*==================================*/
ulint id) /* in: space id */
{
buf_block_t* block;
ulint* page_arr;
ulint num_entries;
page_arr = ut_malloc(sizeof(ulint)
* BUF_LRU_DROP_SEARCH_HASH_SIZE);
mutex_enter(&buf_pool->mutex);
scan_again:
num_entries = 0;
block = UT_LIST_GET_LAST(buf_pool->LRU);
while (block != NULL) {
buf_block_t* prev_block;
mutex_enter(&block->mutex);
prev_block = UT_LIST_GET_PREV(LRU, block);
ut_a(block->state == BUF_BLOCK_FILE_PAGE);
if (block->space != id
|| block->buf_fix_count > 0
|| block->io_fix != 0) {
/* We leave the fixed pages as is in this scan.
To be dealt with later in the final scan. */
mutex_exit(&block->mutex);
goto next_page;
}
ut_ad(block->space == id);
if (block->is_hashed) {
/* Store the offset(i.e.: page_no) in the array
so that we can drop hash index in a batch
later. */
page_arr[num_entries] = block->offset;
mutex_exit(&block->mutex);
ut_a(num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE);
++num_entries;
if (num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE) {
goto next_page;
}
/* Array full. We release the buf_pool->mutex to
obey the latching order. */
mutex_exit(&buf_pool->mutex);
buf_LRU_drop_page_hash_batch(id, page_arr,
num_entries);
num_entries = 0;
mutex_enter(&buf_pool->mutex);
} else {
mutex_exit(&block->mutex);
}
next_page:
/* Note that we may have released the buf_pool->mutex
above after reading the prev_block during processing
of a page_hash_batch (i.e.: when the array was full).
This means that prev_block can change in LRU list.
This is OK because this function is a 'best effort'
to drop as many search hash entries as possible and
it does not guarantee that ALL such entries will be
dropped. */
block = prev_block;
/* If, however, block has been removed from LRU list
to the free list then we should restart the scan.
block->state is protected by buf_pool->mutex. */
if (block && block->state != BUF_BLOCK_FILE_PAGE) {
ut_a(num_entries == 0);
goto scan_again;
}
}
mutex_exit(&buf_pool->mutex);
/* Drop any remaining batch of search hashed pages. */
buf_LRU_drop_page_hash_batch(id, page_arr, num_entries);
ut_free(page_arr);
}
/**********************************************************************
Invalidates all pages belonging to a given tablespace when we are deleting
the data file(s) of that tablespace. */
......@@ -78,6 +197,14 @@ buf_LRU_invalidate_tablespace(
ulint page_no;
ibool all_freed;
/* Before we attempt to drop pages one by one we first
attempt to drop page hash index entries in batches to make
it more efficient. The batching attempt is a best effort
attempt and does not guarantee that all pages hash entries
will be dropped. We get rid of remaining page hash entries
one by one below. */
buf_LRU_drop_page_hash_for_tablespace(id);
scan_again:
mutex_enter(&(buf_pool->mutex));
......
......@@ -422,8 +422,7 @@ dict_table_autoinc_lock(
}
/************************************************************************
Initializes the autoinc counter. It is not an error to initialize an already
initialized counter. */
Unconditionally set the autoinc counter. */
void
dict_table_autoinc_initialize(
......@@ -433,7 +432,6 @@ dict_table_autoinc_initialize(
{
ut_ad(mutex_own(&table->autoinc_mutex));
table->autoinc_inited = TRUE;
table->autoinc = value;
}
......@@ -447,32 +445,25 @@ dict_table_autoinc_read(
/* out: value for a new row, or 0 */
dict_table_t* table) /* in: table */
{
ib_longlong value;
ut_ad(mutex_own(&table->autoinc_mutex));
if (!table->autoinc_inited) {
value = 0;
} else {
value = table->autoinc;
}
return(value);
return(table->autoinc);
}
/************************************************************************
Updates the autoinc counter if the value supplied is greater than the
current value. If not inited, does nothing. */
current value. */
void
dict_table_autoinc_update(
/*======================*/
dict_table_autoinc_update_if_greater(
/*=================================*/
dict_table_t* table, /* in: table */
ib_ulonglong value) /* in: value which was assigned to a row */
{
if (table->autoinc_inited && value > table->autoinc) {
ut_ad(mutex_own(&table->autoinc_mutex));
if (value > table->autoinc) {
table->autoinc = value;
}
......@@ -1394,12 +1385,59 @@ dict_index_remove_from_cache(
dict_index_t* index) /* in, own: index */
{
ulint size;
ulint retries = 0;
btr_search_t* info;
ut_ad(table && index);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
ut_ad(mutex_own(&(dict_sys->mutex)));
/* We always create search info whether or not adaptive
hash index is enabled or not. */
info = index->search_info;
ut_ad(info);
/* We are not allowed to free the in-memory index struct
dict_index_t until all entries in the adaptive hash index
that point to any of the page belonging to his b-tree index
are dropped. This is so because dropping of these entries
require access to dict_index_t struct. To avoid such scenario
We keep a count of number of such pages in the search_info and
only free the dict_index_t struct when this count drops to
zero. */
for (;;) {
ulint ref_count = btr_search_info_get_ref_count(info);
if (ref_count == 0) {
break;
}
/* Sleep for 10ms before trying again. */
os_thread_sleep(10000);
++retries;
if (retries % 500 == 0) {
/* No luck after 5 seconds of wait. */
fprintf(stderr, "InnoDB: Error: Waited for"
" %lu secs for hash index"
" ref_count (%lu) to drop"
" to 0.\n"
"index: \"%s\""
" table: \"%s\"\n",
retries/100,
ref_count,
index->name,
table->name);
}
/* To avoid a hang here we commit suicide if the
ref_count doesn't drop to zero in 600 seconds. */
if (retries >= 60000) {
ut_error;
}
}
rw_lock_free(&index->lock);
/* Remove the index from the list of indexes of the table */
......
......@@ -89,11 +89,7 @@ dict_mem_table_create(
mutex_create(&table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX);
table->autoinc_inited = FALSE;
/* The actual increment value will be set by MySQL, we simply
default to 1 here.*/
table->autoinc_increment = 1;
table->autoinc = 0;
/* The number of transactions that are either waiting on the
AUTOINC lock or have been granted the lock. */
......
......@@ -507,6 +507,18 @@ thd_has_edited_nontrans_tables(
return((ibool) thd_non_transactional_update((THD*) thd));
}
/**********************************************************************
Returns true if the thread is executing a SELECT statement. */
extern "C"
ibool
thd_is_select(
/*==========*/
/* out: true if thd is executing SELECT */
const void* thd) /* in: thread handle (THD*) */
{
return(thd_sql_command((const THD*) thd) == SQLCOM_SELECT);
}
/************************************************************************
Obtain the InnoDB transaction of a MySQL thread. */
inline
......@@ -909,6 +921,81 @@ innobase_convert_string(
errors));
}
/*************************************************************************
Compute the next autoinc value.
For MySQL replication the autoincrement values can be partitioned among
the nodes. The offset is the start or origin of the autoincrement value
for a particular node. For n nodes the increment will be n and the offset
will be in the interval [1, n]. The formula tries to allocate the next
value for a particular node.
Note: This function is also called with increment set to the number of
values we want to reserve for multi-value inserts e.g.,
INSERT INTO T VALUES(), (), ();
innobase_next_autoinc() will be called with increment set to
n * 3 where autoinc_lock_mode != TRADITIONAL because we want
to reserve 3 values for the multi-value INSERT above. */
static
ulonglong
innobase_next_autoinc(
/*==================*/
/* out: the next value */
ulonglong current, /* in: Current value */
ulonglong increment, /* in: increment current by */
ulonglong offset, /* in: AUTOINC offset */
ulonglong max_value) /* in: max value for type */
{
ulonglong next_value;
/* Should never be 0. */
ut_a(increment > 0);
if (max_value <= current) {
next_value = max_value;
} else if (offset <= 1) {
/* Offset 0 and 1 are the same, because there must be at
least one node in the system. */
if (max_value - current <= increment) {
next_value = max_value;
} else {
next_value = current + increment;
}
} else {
if (current > offset) {
next_value = ((current - offset) / increment) + 1;
} else {
next_value = ((offset - current) / increment) + 1;
}
ut_a(increment > 0);
ut_a(next_value > 0);
/* Check for multiplication overflow. */
if (increment > (max_value / next_value)) {
next_value = max_value;
} else {
next_value *= increment;
ut_a(max_value >= next_value);
/* Check for overflow. */
if (max_value - next_value <= offset) {
next_value = max_value;
} else {
next_value += offset;
}
}
}
ut_a(next_value <= max_value);
return(next_value);
}
/*************************************************************************
Gets the InnoDB transaction handle for a MySQL handler object, creates
an InnoDB transaction struct if the corresponding MySQL thread struct still
......@@ -2262,6 +2349,44 @@ normalize_table_name(
#endif
}
/************************************************************************
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. */
ulong
ha_innobase::innobase_initialize_autoinc()
/*======================================*/
{
dict_index_t* index;
ulonglong auto_inc;
const char* col_name;
ulint error = DB_SUCCESS;
dict_table_t* innodb_table = prebuilt->table;
col_name = table->found_next_number_field->field_name;
index = innobase_get_index(table->s->next_number_index);
/* Execute SELECT MAX(col_name) FROM TABLE; */
error = row_search_max_autoinc(index, col_name, &auto_inc);
if (error == DB_SUCCESS) {
/* At the this stage we dont' know the increment
or the offset, so use default inrement of 1. */
++auto_inc;
dict_table_autoinc_initialize(innodb_table, auto_inc);
} else {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Error: (%lu) Couldn't read "
"the MAX(%s) autoinc value from the "
"index (%s).\n", error, col_name, index->name);
}
return(ulong(error));
}
/*********************************************************************
Creates and opens a handle to a table which already exists in an InnoDB
database. */
......@@ -2286,6 +2411,14 @@ ha_innobase::open(
UT_NOT_USED(test_if_locked);
thd = ha_thd();
/* Under some cases MySQL seems to call this function while
holding btr_search_latch. This breaks the latching order as
we acquire dict_sys->mutex below and leads to a deadlock. */
if (thd != NULL) {
innobase_release_temporary_latches(ht, thd);
}
normalize_table_name(norm_name, name);
user_thd = NULL;
......@@ -2445,6 +2578,26 @@ ha_innobase::open(
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
/* Only if the table has an AUTOINC column. */
if (prebuilt->table != NULL && table->found_next_number_field != NULL) {
ulint error;
dict_table_autoinc_lock(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(prebuilt->table) == 0) {
error = innobase_initialize_autoinc();
/* Should always succeed! */
ut_a(error == DB_SUCCESS);
}
dict_table_autoinc_unlock(prebuilt->table);
}
DBUG_RETURN(0);
}
......@@ -3251,6 +3404,59 @@ build_template(
}
}
/************************************************************************
Get the upper limit of the MySQL integral type. */
ulonglong
ha_innobase::innobase_get_int_col_max_value(
/*========================================*/
const Field* field)
{
ulonglong max_value = 0;
switch(field->key_type()) {
/* TINY */
case HA_KEYTYPE_BINARY:
max_value = 0xFFULL;
break;
case HA_KEYTYPE_INT8:
max_value = 0x7FULL;
break;
/* SHORT */
case HA_KEYTYPE_USHORT_INT:
max_value = 0xFFFFULL;
break;
case HA_KEYTYPE_SHORT_INT:
max_value = 0x7FFFULL;
break;
/* MEDIUM */
case HA_KEYTYPE_UINT24:
max_value = 0xFFFFFFULL;
break;
case HA_KEYTYPE_INT24:
max_value = 0x7FFFFFULL;
break;
/* LONG */
case HA_KEYTYPE_ULONG_INT:
max_value = 0xFFFFFFFFULL;
break;
case HA_KEYTYPE_LONG_INT:
max_value = 0x7FFFFFFFULL;
break;
/* BIG */
case HA_KEYTYPE_ULONGLONG:
max_value = 0xFFFFFFFFFFFFFFFFULL;
break;
case HA_KEYTYPE_LONGLONG:
max_value = 0x7FFFFFFFFFFFFFFFULL;
break;
default:
ut_error;
}
return(max_value);
}
/************************************************************************
This special handling is really to overcome the limitations of MySQL's
binlogging. We need to eliminate the non-determinism that will arise in
......@@ -3259,7 +3465,7 @@ min value of the autoinc interval. Once that is fixed we can get rid of
the special lock handling.*/
ulong
ha_innobase::innobase_autoinc_lock(void)
ha_innobase::innobase_lock_autoinc(void)
/*====================================*/
/* out: DB_SUCCESS if all OK else
error code */
......@@ -3324,7 +3530,7 @@ ha_innobase::innobase_reset_autoinc(
{
ulint error;
error = innobase_autoinc_lock();
error = innobase_lock_autoinc();
if (error == DB_SUCCESS) {
......@@ -3349,11 +3555,11 @@ ha_innobase::innobase_set_max_autoinc(
{
ulint error;
error = innobase_autoinc_lock();
error = innobase_lock_autoinc();
if (error == DB_SUCCESS) {
dict_table_autoinc_update(prebuilt->table, auto_inc);
dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
dict_table_autoinc_unlock(prebuilt->table);
}
......@@ -3473,8 +3679,20 @@ ha_innobase::write_row(
/* This is the case where the table has an auto-increment column */
if (table->next_number_field && record == table->record[0]) {
/* Reset the error code before calling
innobase_get_auto_increment(). */
prebuilt->autoinc_error = DB_SUCCESS;
if ((error = update_auto_increment())) {
/* We don't want to mask autoinc overflow errors. */
if (prebuilt->autoinc_error != DB_SUCCESS) {
error = prebuilt->autoinc_error;
goto report_error;
}
/* MySQL errors are passed straight back. */
goto func_exit;
}
......@@ -3498,6 +3716,7 @@ ha_innobase::write_row(
if (auto_inc_used) {
ulint err;
ulonglong auto_inc;
ulonglong col_max_value;
/* Note the number of rows processed for this statement, used
by get_auto_increment() to determine the number of AUTO-INC
......@@ -3507,6 +3726,11 @@ ha_innobase::write_row(
--trx->n_autoinc_rows;
}
/* 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);
/* Get the value that MySQL attempted to store in the table.*/
auto_inc = table->next_number_field->val_int();
......@@ -3545,22 +3769,19 @@ ha_innobase::write_row(
update the table upper limit. Note: last_value
will be 0 if get_auto_increment() was not called.*/
if (auto_inc > prebuilt->last_value) {
if (auto_inc <= col_max_value
&& auto_inc > prebuilt->autoinc_last_value) {
set_max_autoinc:
ut_a(prebuilt->table->autoinc_increment > 0);
ut_a(prebuilt->autoinc_increment > 0);
ulonglong have;
ulonglong need;
ulonglong offset;
/* Check for overflow conditions. */
need = prebuilt->table->autoinc_increment;
have = ~0x0ULL - auto_inc;
if (have < need) {
need = have;
}
offset = prebuilt->autoinc_offset;
need = prebuilt->autoinc_increment;
auto_inc += need;
auto_inc = innobase_next_autoinc(
auto_inc, need, offset, col_max_value);
err = innobase_set_max_autoinc(auto_inc);
......@@ -3574,6 +3795,7 @@ ha_innobase::write_row(
innodb_srv_conc_exit_innodb(prebuilt->trx);
report_error:
error = convert_error_code_to_mysql(error, user_thd);
func_exit:
......@@ -3755,6 +3977,8 @@ ha_innobase::update_row(
ut_a(prebuilt->trx == trx);
ha_statistic_increment(&SSV::ha_update_count);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
......@@ -3795,12 +4019,26 @@ ha_innobase::update_row(
&& (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
== TRX_DUP_IGNORE) {
longlong auto_inc;
ulonglong auto_inc;
ulonglong col_max_value;
auto_inc = table->next_number_field->val_int();
if (auto_inc != 0) {
auto_inc += prebuilt->table->autoinc_increment;
/* 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 need;
ulonglong offset;
offset = prebuilt->autoinc_offset;
need = prebuilt->autoinc_increment;
auto_inc = innobase_next_autoinc(
auto_inc, need, offset, col_max_value);
error = innobase_set_max_autoinc(auto_inc);
}
......@@ -3844,29 +4082,7 @@ ha_innobase::delete_row(
ut_a(prebuilt->trx == trx);
/* Only if the table has an AUTOINC column */
if (table->found_next_number_field && record == table->record[0]) {
ulonglong dummy = 0;
/* First check whether the AUTOINC sub-system has been
initialized using the AUTOINC mutex. If not then we
do it the "proper" way, by acquiring the heavier locks. */
dict_table_autoinc_lock(prebuilt->table);
if (!prebuilt->table->autoinc_inited) {
dict_table_autoinc_unlock(prebuilt->table);
error = innobase_get_auto_increment(&dummy);
if (error == DB_SUCCESS) {
dict_table_autoinc_unlock(prebuilt->table);
} else {
goto error_exit;
}
} else {
dict_table_autoinc_unlock(prebuilt->table);
}
}
ha_statistic_increment(&SSV::ha_delete_count);
if (!prebuilt->upd_node) {
row_get_prebuilt_update_vector(prebuilt);
......@@ -3882,7 +4098,6 @@ ha_innobase::delete_row(
innodb_srv_conc_exit_innodb(trx);
error_exit:
error = convert_error_code_to_mysql(error, user_thd);
/* Tell the InnoDB server that there might be work for
......@@ -4986,6 +5201,29 @@ ha_innobase::create(
DBUG_ENTER("ha_innobase::create");
DBUG_ASSERT(thd != NULL);
DBUG_ASSERT(create_info != NULL);
#ifdef __WIN__
/* Names passed in from server are in two formats:
1. <database_name>/<table_name>: for normal table creation
2. full path: for temp table creation, or sym link
When srv_file_per_table is on, check for full path pattern, i.e.
X:\dir\..., X is a driver letter, or
\\dir1\dir2\..., UNC path
returns error if it is in full path format, but not creating a temp.
table. Currently InnoDB does not support symbolic link on Windows. */
if (srv_file_per_table
&& (!create_info->options & HA_LEX_CREATE_TMP_TABLE)) {
if ((name[1] == ':')
|| (name[0] == '\\' && name[1] == '\\')) {
sql_print_error("Cannot create table %s\n", name);
DBUG_RETURN(HA_ERR_GENERIC);
}
}
#endif
if (form->s->fields > 1000) {
/* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
......@@ -5216,7 +5454,8 @@ ha_innobase::delete_all_rows(void)
if (thd_sql_command(user_thd) != SQLCOM_TRUNCATE) {
fallback:
/* We only handle TRUNCATE TABLE t as a special case.
DELETE FROM t will have to use ha_innobase::delete_row(). */
DELETE FROM t will have to use ha_innobase::delete_row(),
because DELETE is transactional while TRUNCATE is not. */
DBUG_RETURN(my_errno=HA_ERR_WRONG_COMMAND);
}
......@@ -5797,7 +6036,7 @@ ha_innobase::info(
not be updated. This will force write_row() into
attempting an update of the table's AUTOINC counter. */
prebuilt->last_value = 0;
prebuilt->autoinc_last_value = 0;
}
stats.records = (ha_rows)n_rows;
......@@ -5818,9 +6057,39 @@ ha_innobase::info(
so the "old" value can remain. delete_length is initialized
to 0 in the ha_statistics' constructor. */
if (!(flag & HA_STATUS_NO_LOCK)) {
/* lock the data dictionary to avoid races with
ibd_file_missing and tablespace_discarded */
row_mysql_lock_data_dictionary(prebuilt->trx);
/* ib_table->space must be an existent tablespace */
if (!ib_table->ibd_file_missing
&& !ib_table->tablespace_discarded) {
stats.delete_length =
fsp_get_available_space_in_free_extents(
ib_table->space) * 1024;
} else {
THD* thd;
thd = ha_thd();
push_warning_printf(
thd,
MYSQL_ERROR::WARN_LEVEL_WARN,
ER_CANT_GET_STAT,
"InnoDB: Trying to get the free "
"space for table %s but its "
"tablespace has been discarded or "
"the .ibd file is missing. Setting "
"the free space to zero.",
ib_table->name);
stats.delete_length = 0;
}
row_mysql_unlock_data_dictionary(prebuilt->trx);
}
stats.check_time = 0;
......@@ -5905,29 +6174,7 @@ ha_innobase::info(
}
if (flag & HA_STATUS_AUTO && table->found_next_number_field) {
ulonglong auto_inc;
int ret;
/* The following function call can the first time fail in
a lock wait timeout error because it reserves the auto-inc
lock on the table. If it fails, then someone is already initing
the auto-inc counter, and the second call is guaranteed to
succeed. */
ret = innobase_read_and_init_auto_inc(&auto_inc);
if (ret != 0) {
ret = innobase_read_and_init_auto_inc(&auto_inc);
if (ret != 0) {
sql_print_error("Cannot get table %s auto-inc"
"counter value in ::info\n",
ib_table->name);
auto_inc = 0;
}
}
stats.auto_increment_value = auto_inc;
stats.auto_increment_value = innobase_peek_autoinc();
}
prebuilt->trx->op_info = (char*)"";
......@@ -6390,15 +6637,26 @@ ha_innobase::extra(
return(0);
}
/**********************************************************************
Reset state of file to after 'open'.
This function is called after every statement for all tables used
by that statement. */
int ha_innobase::reset()
{
if (prebuilt->blob_heap) {
row_mysql_prebuilt_free_blob_heap(prebuilt);
}
reset_template(prebuilt);
return 0;
}
/* TODO: This should really be reset in reset_template() but for now
it's safer to do it explicitly here. */
/* This is a statement level counter. */
prebuilt->autoinc_last_value = 0;
return(0);
}
/**********************************************************************
MySQL calls this function at the start of each SQL statement inside LOCK
......@@ -7247,169 +7505,59 @@ ha_innobase::store_lock(
return(to);
}
/***********************************************************************
This function initializes the auto-inc counter if it has not been
initialized yet. This function does not change the value of the auto-inc
counter if it already has been initialized. In parameter ret returns
the value of the auto-inc counter. */
int
ha_innobase::innobase_read_and_init_auto_inc(
/*=========================================*/
/* out: 0 or generic MySQL
error code */
ulonglong* value) /* out: the autoinc value */
{
ulonglong auto_inc;
ibool stmt_start;
int mysql_error = 0;
dict_table_t* innodb_table = prebuilt->table;
ibool trx_was_not_started = FALSE;
ut_a(prebuilt);
ut_a(prebuilt->table);
/* Remember if we are in the beginning of an SQL statement.
This function must not change that flag. */
stmt_start = prebuilt->sql_stat_start;
/* Prepare prebuilt->trx in the table handle */
update_thd(ha_thd());
if (prebuilt->trx->conc_state == TRX_NOT_STARTED) {
trx_was_not_started = TRUE;
}
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_search_latch_release_if_reserved(prebuilt->trx);
dict_table_autoinc_lock(prebuilt->table);
auto_inc = dict_table_autoinc_read(prebuilt->table);
/* Was the AUTOINC counter reset during normal processing, if
so then we simply start count from 1. No need to go to the index.*/
if (auto_inc == 0 && innodb_table->autoinc_inited) {
++auto_inc;
dict_table_autoinc_initialize(innodb_table, auto_inc);
}
if (auto_inc == 0) {
dict_index_t* index;
ulint error;
const char* autoinc_col_name;
ut_a(!innodb_table->autoinc_inited);
index = innobase_get_index(table->s->next_number_index);
autoinc_col_name = table->found_next_number_field->field_name;
error = row_search_max_autoinc(
index, autoinc_col_name, &auto_inc);
if (error == DB_SUCCESS) {
if (auto_inc < ~0x0ULL) {
++auto_inc;
}
dict_table_autoinc_initialize(innodb_table, auto_inc);
} else {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Error: (%lu) Couldn't read "
"the max AUTOINC value from the index (%s).\n",
error, index->name);
mysql_error = 1;
}
}
*value = auto_inc;
dict_table_autoinc_unlock(prebuilt->table);
/* Since MySQL does not seem to call autocommit after SHOW TABLE
STATUS (even if we would register the trx here), we commit our
transaction here if it was started here. This is to eliminate a
dangling transaction. If the user had AUTOCOMMIT=0, then SHOW
TABLE STATUS does leave a dangling transaction if the user does not
himself call COMMIT. */
if (trx_was_not_started) {
innobase_commit_low(prebuilt->trx);
}
prebuilt->sql_stat_start = stmt_start;
return(mysql_error);
}
/*******************************************************************************
Read the next autoinc value, initialize the table if it's not initialized.
On return if there is no error then the tables AUTOINC lock is locked.*/
Read the next autoinc value. Acquire the relevant locks before reading
the AUTOINC value. If SUCCESS then the table AUTOINC mutex will be locked
on return and all relevant locks acquired. */
ulong
ha_innobase::innobase_get_auto_increment(
/*=====================================*/
ha_innobase::innobase_get_autoinc(
/*==============================*/
/* out: DB_SUCCESS or error code */
ulonglong* value) /* out: autoinc value */
{
ulong error;
*value = 0;
/* Note: If the table is not initialized when we attempt the
read below. We initialize the table's auto-inc counter and
always do a reread of the AUTOINC value. */
do {
error = innobase_autoinc_lock();
prebuilt->autoinc_error = innobase_lock_autoinc();
if (error == DB_SUCCESS) {
ulonglong autoinc;
if (prebuilt->autoinc_error == DB_SUCCESS) {
/* Determine the first value of the interval */
autoinc = dict_table_autoinc_read(prebuilt->table);
*value = dict_table_autoinc_read(prebuilt->table);
/* We need to initialize the AUTO-INC value, for
that we release all locks.*/
if (autoinc == 0) {
trx_t* trx;
/* It should have been initialized during open. */
ut_a(*value != 0);
}
trx = prebuilt->trx;
dict_table_autoinc_unlock(prebuilt->table);
return(ulong(prebuilt->autoinc_error));
}
/* If we had reserved the AUTO-INC
lock in this SQL statement we release
it before retrying.*/
row_unlock_table_autoinc_for_mysql(trx);
/***********************************************************************
This function reads the global auto-inc counter. It doesn't use the
AUTOINC lock even if the lock mode is set to TRADITIONAL. */
/* Just to make sure */
ut_a(!trx->auto_inc_lock);
ulonglong
ha_innobase::innobase_peek_autoinc()
/*================================*/
/* out: the autoinc value */
{
ulonglong auto_inc;
dict_table_t* innodb_table;
int mysql_error;
ut_a(prebuilt != NULL);
ut_a(prebuilt->table != NULL);
mysql_error = innobase_read_and_init_auto_inc(
&autoinc);
innodb_table = prebuilt->table;
if (mysql_error) {
error = DB_ERROR;
}
} else {
*value = autoinc;
}
/* A deadlock error during normal processing is OK
and can be ignored. */
} else if (error != DB_DEADLOCK) {
dict_table_autoinc_lock(innodb_table);
sql_print_error("InnoDB: Error: %lu in "
"::innobase_get_auto_increment()",
error);
}
auto_inc = dict_table_autoinc_read(innodb_table);
} while (*value == 0 && error == DB_SUCCESS);
ut_a(auto_inc > 0);
return(error);
dict_table_autoinc_unlock(innodb_table);
return(auto_inc);
}
/*******************************************************************************
......@@ -7436,7 +7584,7 @@ ha_innobase::get_auto_increment(
/* Prepare prebuilt->trx in the table handle */
update_thd(ha_thd());
error = innobase_get_auto_increment(&autoinc);
error = innobase_get_autoinc(&autoinc);
if (error != DB_SUCCESS) {
*first_value = (~(ulonglong) 0);
......@@ -7472,7 +7620,7 @@ ha_innobase::get_auto_increment(
set_if_bigger(*first_value, autoinc);
/* Not in the middle of a mult-row INSERT. */
} else if (prebuilt->last_value == 0) {
} else if (prebuilt->autoinc_last_value == 0) {
set_if_bigger(*first_value, autoinc);
}
......@@ -7481,35 +7629,40 @@ ha_innobase::get_auto_increment(
/* With old style AUTOINC locking we only update the table's
AUTOINC counter after attempting to insert the row. */
if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) {
ulonglong have;
ulonglong need;
ulonglong next_value;
ulonglong col_max_value;
/* Check for overflow conditions. */
need = *nb_reserved_values * increment;
have = ~0x0ULL - *first_value;
/* 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 (have < need) {
need = have;
}
need = *nb_reserved_values * increment;
/* Compute the last value in the interval */
prebuilt->last_value = *first_value + need;
next_value = innobase_next_autoinc(
*first_value, need, offset, col_max_value);
ut_a(prebuilt->last_value >= *first_value);
prebuilt->autoinc_last_value = next_value;
ut_a(prebuilt->autoinc_last_value >= *first_value);
/* Update the table autoinc variable */
dict_table_autoinc_update(
prebuilt->table, prebuilt->last_value);
dict_table_autoinc_update_if_greater(
prebuilt->table, prebuilt->autoinc_last_value);
} else {
/* This will force write_row() into attempting an update
of the table's AUTOINC counter. */
prebuilt->last_value = 0;
prebuilt->autoinc_last_value = 0;
}
/* The increment to be used to increase the AUTOINC value, we use
this in write_row() and update_row() to increase the autoinc counter
for columns that are filled by the user.*/
prebuilt->table->autoinc_increment = increment;
for columns that are filled by the user. We need the offset and
the increment. */
prebuilt->autoinc_offset = offset;
prebuilt->autoinc_increment = increment;
dict_table_autoinc_unlock(prebuilt->table);
}
......@@ -7534,6 +7687,11 @@ ha_innobase::reset_auto_increment(
DBUG_RETURN(error);
}
/* The next value can never be 0. */
if (value == 0) {
value = 1;
}
innobase_reset_autoinc(value);
DBUG_RETURN(0);
......
......@@ -72,12 +72,15 @@ class ha_innobase: public handler
int update_thd(THD* thd);
int change_active_index(uint keynr);
int general_fetch(uchar* buf, uint direction, uint match_mode);
int innobase_read_and_init_auto_inc(ulonglong* ret);
ulong innobase_autoinc_lock();
ulong innobase_lock_autoinc();
ulonglong innobase_peek_autoinc();
ulong innobase_set_max_autoinc(ulonglong auto_inc);
ulong innobase_reset_autoinc(ulonglong auto_inc);
ulong innobase_get_auto_increment(ulonglong* value);
ulong innobase_get_autoinc(ulonglong* value);
ulong innobase_update_autoinc(ulonglong auto_inc);
ulong innobase_initialize_autoinc();
dict_index_t* innobase_get_index(uint keynr);
ulonglong innobase_get_int_col_max_value(const Field* field);
/* Init values for the class: */
public:
......
......@@ -40,6 +40,14 @@ btr_search_info_create(
/*===================*/
/* out, own: search info struct */
mem_heap_t* heap); /* in: heap where created */
/*********************************************************************
Returns the value of ref_count. The value is protected by
btr_search_latch. */
ulint
btr_search_info_get_ref_count(
/*==========================*/
/* out: ref_count value. */
btr_search_t* info); /* in: search info. */
/*************************************************************************
Updates the search info. */
UNIV_INLINE
......@@ -137,6 +145,13 @@ btr_search_validate(void);
/* The search info struct in an index */
struct btr_search_struct{
ulint ref_count; /* Number of blocks in this index tree
that have search index built
i.e. block->index points to this index.
Protected by btr_search_latch except
when during initialization in
btr_search_info_create(). */
/* The following fields are not protected by any latch.
Unfortunately, this means that they must be aligned to
the machine word, i.e., they cannot be turned into bit-fields. */
......
......@@ -178,8 +178,7 @@ dict_table_autoinc_lock(
/*====================*/
dict_table_t* table); /* in: table */
/************************************************************************
Initializes the autoinc counter. It is not an error to initialize an already
initialized counter. */
Unconditionally set the autoinc counter. */
void
dict_table_autoinc_initialize(
......@@ -196,12 +195,12 @@ dict_table_autoinc_read(
/* out: value for a new row, or 0 */
dict_table_t* table); /* in: table */
/************************************************************************
Updates the autoinc counter if the value supplied is equal or bigger than the
current value. If not inited, does nothing. */
Updates the autoinc counter if the value supplied is greater than the
current value. */
void
dict_table_autoinc_update(
/*======================*/
dict_table_autoinc_update_if_greater(
/*=================================*/
dict_table_t* table, /* in: table */
ib_ulonglong value); /* in: value which was assigned to a row */
......
......@@ -405,17 +405,8 @@ struct dict_table_struct{
mutex_t autoinc_mutex;
/* mutex protecting the autoincrement
counter */
ibool autoinc_inited;
/* TRUE if the autoinc counter has been
inited; MySQL gets the init value by executing
SELECT MAX(auto inc column) */
ib_ulonglong autoinc;/* autoinc counter value to give to the
next inserted row */
ib_longlong autoinc_increment;
/* The increment step of the auto increment
column. Value must be greater than or equal
to 1 */
ulong n_waiting_or_granted_auto_inc_locks;
/* This counter is used to track the number
of granted and pending autoinc locks on this
......@@ -425,6 +416,7 @@ struct dict_table_struct{
acquired the AUTOINC lock or not. Of course
only one transaction can be granted the
lock but there can be multiple waiters. */
/*----------------------*/
#ifdef UNIV_DEBUG
ulint magic_n;/* magic number */
......
......@@ -63,5 +63,14 @@ thd_has_edited_nontrans_tables(
been edited */
void* thd); /* in: thread handle (THD*) */
/**********************************************************************
Returns true if the thread is executing a SELECT statement. */
ibool
thd_is_select(
/*==========*/
/* out: true if thd is executing SELECT */
const void* thd); /* in: thread handle (THD*) */
#endif
#endif
......@@ -463,14 +463,21 @@ void
lock_cancel_waiting_and_release(
/*============================*/
lock_t* lock); /* in: waiting lock request */
/*************************************************************************
Resets all locks, both table and record locks, on a table to be dropped.
No lock is allowed to be a wait lock. */
Removes locks on a table to be dropped or truncated.
If remove_also_table_sx_locks is TRUE then table-level S and X locks are
also removed in addition to other table-level and record-level locks.
No lock, that is going to be removed, is allowed to be a wait lock. */
void
lock_reset_all_on_table(
/*====================*/
dict_table_t* table); /* in: table to be dropped */
lock_remove_all_on_table(
/*=====================*/
dict_table_t* table, /* in: table to be dropped
or truncated */
ibool remove_also_table_sx_locks);/* in: also removes
table S and X locks */
/*************************************************************************
Calculates the fold value of a page file address: used in inserting or
searching for a lock in the hash table. */
......
......@@ -683,7 +683,21 @@ struct row_prebuilt_struct {
to this heap */
mem_heap_t* old_vers_heap; /* memory heap where a previous
version is built in consistent read */
ulonglong last_value; /* last value of AUTO-INC interval */
/*----------------------*/
ulonglong autoinc_last_value;/* last value of AUTO-INC interval */
ulonglong autoinc_increment;/* The increment step of the auto
increment column. Value must be
greater than or equal to 1. Required to
calculate the next value */
ulonglong autoinc_offset; /* The offset passed to
get_auto_increment() by MySQL. Required
to calculate the next value */
ulint autoinc_error; /* The actual error code encountered
while trying to init or read the
autoinc value from the table. We
store it here so that we can return
it to MySQL */
/*----------------------*/
ulint magic_n2; /* this should be the same as
magic_n */
};
......
......@@ -197,7 +197,7 @@ mutex_exit(
{
ut_ad(mutex_own(mutex));
ut_d(mutex->thread_id = ULINT_UNDEFINED);
ut_d(mutex->thread_id = (os_thread_id_t) ULINT_UNDEFINED);
#ifdef UNIV_SYNC_DEBUG
sync_thread_reset_level(mutex);
......
......@@ -145,11 +145,15 @@ ib_time_t
ut_time(void);
/*=========*/
/**************************************************************
Returns system time. */
Returns system time.
Upon successful completion, the value 0 is returned; otherwise the
value -1 is returned and the global variable errno is set to indicate the
error. */
void
int
ut_usectime(
/*========*/
/* out: 0 on success, -1 otherwise */
ulint* sec, /* out: seconds since the Epoch */
ulint* ms); /* out: microseconds since the Epoch+*sec */
/**************************************************************
......
......@@ -3920,15 +3920,25 @@ lock_cancel_waiting_and_release(
trx_end_lock_wait(lock->trx);
}
/* True if a lock mode is S or X */
#define IS_LOCK_S_OR_X(lock) \
(lock_get_mode(lock) == LOCK_S \
|| lock_get_mode(lock) == LOCK_X)
/*************************************************************************
Resets all record and table locks of a transaction on a table to be dropped.
No lock is allowed to be a wait lock. */
Removes locks of a transaction on a table to be dropped.
If remove_also_table_sx_locks is TRUE then table-level S and X locks are
also removed in addition to other table-level and record-level locks.
No lock, that is going to be removed, is allowed to be a wait lock. */
static
void
lock_reset_all_on_table_for_trx(
/*============================*/
lock_remove_all_on_table_for_trx(
/*=============================*/
dict_table_t* table, /* in: table to be dropped */
trx_t* trx) /* in: a transaction */
trx_t* trx, /* in: a transaction */
ibool remove_also_table_sx_locks)/* in: also removes
table S and X locks */
{
lock_t* lock;
lock_t* prev_lock;
......@@ -3946,7 +3956,9 @@ lock_reset_all_on_table_for_trx(
lock_rec_discard(lock);
} else if (lock_get_type(lock) & LOCK_TABLE
&& lock->un_member.tab_lock.table == table) {
&& lock->un_member.tab_lock.table == table
&& (remove_also_table_sx_locks
|| !IS_LOCK_S_OR_X(lock))) {
ut_a(!lock_get_wait(lock));
......@@ -3958,27 +3970,66 @@ lock_reset_all_on_table_for_trx(
}
/*************************************************************************
Resets all locks, both table and record locks, on a table to be dropped.
No lock is allowed to be a wait lock. */
Removes locks on a table to be dropped or truncated.
If remove_also_table_sx_locks is TRUE then table-level S and X locks are
also removed in addition to other table-level and record-level locks.
No lock, that is going to be removed, is allowed to be a wait lock. */
void
lock_reset_all_on_table(
/*====================*/
dict_table_t* table) /* in: table to be dropped */
lock_remove_all_on_table(
/*=====================*/
dict_table_t* table, /* in: table to be dropped
or truncated */
ibool remove_also_table_sx_locks)/* in: also removes
table S and X locks */
{
lock_t* lock;
lock_t* prev_lock;
mutex_enter(&kernel_mutex);
lock = UT_LIST_GET_FIRST(table->locks);
while (lock) {
while (lock != NULL) {
prev_lock = UT_LIST_GET_PREV(un_member.tab_lock.locks,
lock);
/* If we should remove all locks (remove_also_table_sx_locks
is TRUE), or if the lock is not table-level S or X lock,
then check we are not going to remove a wait lock. */
if (remove_also_table_sx_locks
|| !(lock_get_type(lock) == LOCK_TABLE
&& IS_LOCK_S_OR_X(lock))) {
ut_a(!lock_get_wait(lock));
}
lock_reset_all_on_table_for_trx(table, lock->trx);
lock_remove_all_on_table_for_trx(table, lock->trx,
remove_also_table_sx_locks);
if (prev_lock == NULL) {
if (lock == UT_LIST_GET_FIRST(table->locks)) {
/* lock was not removed, pick its successor */
lock = UT_LIST_GET_NEXT(
un_member.tab_lock.locks, lock);
} else {
/* lock was removed, pick the first one */
lock = UT_LIST_GET_FIRST(table->locks);
}
} else if (UT_LIST_GET_NEXT(un_member.tab_lock.locks,
prev_lock) != lock) {
/* If lock was removed by
lock_remove_all_on_table_for_trx() then pick the
successor of prev_lock ... */
lock = UT_LIST_GET_NEXT(
un_member.tab_lock.locks, prev_lock);
} else {
/* ... otherwise pick the successor of lock. */
lock = UT_LIST_GET_NEXT(
un_member.tab_lock.locks, lock);
}
}
mutex_exit(&kernel_mutex);
}
......
......@@ -1267,9 +1267,19 @@ os_file_create(
if (file == INVALID_HANDLE_VALUE) {
*success = FALSE;
/* When srv_file_per_table is on, file creation failure may not
be critical to the whole instance. Do not crash the server in
case of unknown errors. */
if (srv_file_per_table) {
retry = os_file_handle_error_no_exit(name,
create_mode == OS_FILE_CREATE ?
"create" : "open");
} else {
retry = os_file_handle_error(name,
create_mode == OS_FILE_CREATE ?
"create" : "open");
}
if (retry) {
goto try_again;
}
......@@ -1344,9 +1354,19 @@ os_file_create(
if (file == -1) {
*success = FALSE;
/* When srv_file_per_table is on, file creation failure may not
be critical to the whole instance. Do not crash the server in
case of unknown errors. */
if (srv_file_per_table) {
retry = os_file_handle_error_no_exit(name,
create_mode == OS_FILE_CREATE ?
"create" : "open");
} else {
retry = os_file_handle_error(name,
create_mode == OS_FILE_CREATE ?
"create" : "open");
}
if (retry) {
goto try_again;
} else {
......
......@@ -23,17 +23,22 @@ MYSQL_PLUGIN_ACTIONS(innobase, [
CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE -DUNIV_HPUX";;
aix*)
CFLAGS="$CFLAGS -DUNIV_AIX";;
irix*)
CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;
osf*)
irix*|osf*|sysv5uw7*|openbsd*)
CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;
*solaris*|*SunOS*)
CFLAGS="$CFLAGS -DUNIV_SOLARIS";;
sysv5uw7*)
# Problem when linking on SCO
CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;
openbsd*)
CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;
esac
INNODB_DYNAMIC_CFLAGS="-DMYSQL_DYNAMIC_PLUGIN"
case "$target_cpu" in
x86_64)
# The AMD64 ABI forbids absolute addresses in shared libraries
;;
*86)
# Use absolute addresses on IA-32
INNODB_DYNAMIC_CFLAGS="$INNODB_DYNAMIC_CFLAGS -prefer-non-pic"
;;
esac
AC_SUBST(INNODB_DYNAMIC_CFLAGS)
])
# vim: set ft=config:
......@@ -661,7 +661,14 @@ row_create_prebuilt(
prebuilt->old_vers_heap = NULL;
prebuilt->last_value = 0;
prebuilt->autoinc_error = 0;
prebuilt->autoinc_offset = 0;
/* Default to 1, we will set the actual value later in
ha_innobase::get_auto_increment(). */
prebuilt->autoinc_increment = 1;
prebuilt->autoinc_last_value = 0;
return(prebuilt);
}
......@@ -1963,6 +1970,7 @@ row_create_index_for_mysql(
ulint err;
ulint i, j;
ulint len;
char* table_name;
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
......@@ -1972,6 +1980,11 @@ row_create_index_for_mysql(
trx->op_info = "creating index";
/* Copy the table name because we may want to drop the
table later, after the index object is freed (inside
que_run_threads()) and thus index->table_name is not available. */
table_name = mem_strdup(index->table_name);
trx_start_if_not_started(trx);
/* Check that the same column does not appear twice in the index.
......@@ -2044,13 +2057,15 @@ row_create_index_for_mysql(
trx_general_rollback_for_mysql(trx, FALSE, NULL);
row_drop_table_for_mysql(index->table_name, trx, FALSE);
row_drop_table_for_mysql(table_name, trx, FALSE);
trx->error_state = DB_SUCCESS;
}
trx->op_info = "";
mem_free(table_name);
return((int) err);
}
......@@ -2443,8 +2458,8 @@ row_discard_tablespace_for_mysql(
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
/* Remove any locks there are on the table or its records */
lock_reset_all_on_table(table);
/* Remove all locks except the table-level S and X locks. */
lock_remove_all_on_table(table, FALSE);
info = pars_info_create();
......@@ -2779,9 +2794,8 @@ row_truncate_table_for_mysql(
goto funct_exit;
}
/* Remove any locks there are on the table or its records */
lock_reset_all_on_table(table);
/* Remove all locks except the table-level S and X locks. */
lock_remove_all_on_table(table, FALSE);
trx->table_id = table->id;
......@@ -2896,7 +2910,7 @@ row_truncate_table_for_mysql(
/* MySQL calls ha_innobase::reset_auto_increment() which does
the same thing. */
dict_table_autoinc_lock(table);
dict_table_autoinc_initialize(table, 0);
dict_table_autoinc_initialize(table, 1);
dict_table_autoinc_unlock(table);
dict_update_statistics(table);
......@@ -3131,9 +3145,8 @@ row_drop_table_for_mysql(
goto funct_exit;
}
/* Remove any locks there are on the table or its records */
lock_reset_all_on_table(table);
/* Remove all locks there are on the table or its records */
lock_remove_all_on_table(table, TRUE);
trx->dict_operation = TRUE;
trx->table_id = table->id;
......@@ -3429,8 +3442,6 @@ row_drop_database_for_mysql(
err = row_drop_table_for_mysql(table_name, trx, TRUE);
mem_free(table_name);
if (err != DB_SUCCESS) {
fputs("InnoDB: DROP DATABASE ", stderr);
ut_print_name(stderr, trx, TRUE, name);
......@@ -3438,8 +3449,11 @@ row_drop_database_for_mysql(
(ulint) err);
ut_print_name(stderr, trx, TRUE, table_name);
putc('\n', stderr);
mem_free(table_name);
break;
}
mem_free(table_name);
}
if (err == DB_SUCCESS) {
......
......@@ -32,6 +32,7 @@ Created 12/19/1997 Heikki Tuuri
#include "row0mysql.h"
#include "read0read.h"
#include "buf0lru.h"
#include "ha_prototypes.h"
/* Maximum number of rows to prefetch; MySQL interface has another parameter */
#define SEL_MAX_N_PREFETCH 16
......@@ -3577,21 +3578,13 @@ row_search_for_mysql(
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
&& prebuilt->select_lock_type != LOCK_NONE
&& trx->mysql_query_str != NULL
&& *trx->mysql_query_str != NULL
&& trx->mysql_thd != NULL) {
/* Scan the MySQL query string; check if SELECT is the first
word there */
if (dict_str_starts_with_keyword(
trx->mysql_thd, *trx->mysql_query_str, "SELECT")) {
&& trx->mysql_thd != NULL
&& thd_is_select(trx->mysql_thd)) {
/* It is a plain locking SELECT and the isolation
level is low: do not lock gaps */
set_also_gap_locks = FALSE;
}
}
/* Note that if the search mode was GE or G, then the cursor
naturally moves upward (in fetch next) in alphabetical order,
......
......@@ -1453,9 +1453,12 @@ srv_suspend_mysql_thread(
srv_n_lock_wait_count++;
srv_n_lock_wait_current_count++;
ut_usectime(&sec, &ms);
if (ut_usectime(&sec, &ms) == -1) {
start_time = -1;
} else {
start_time = (ib_longlong)sec * 1000000 + ms;
}
}
/* Wake the lock timeout monitor thread, if it is suspended */
os_event_set(srv_lock_timeout_thread_event);
......@@ -1508,14 +1511,20 @@ srv_suspend_mysql_thread(
wait_time = ut_difftime(ut_time(), slot->suspend_time);
if (thr->lock_state == QUE_THR_LOCK_ROW) {
ut_usectime(&sec, &ms);
if (ut_usectime(&sec, &ms) == -1) {
finish_time = -1;
} else {
finish_time = (ib_longlong)sec * 1000000 + ms;
}
diff_time = (ulint) (finish_time - start_time);
srv_n_lock_wait_current_count--;
srv_n_lock_wait_time = srv_n_lock_wait_time + diff_time;
if (diff_time > srv_n_lock_max_wait_time) {
if (diff_time > srv_n_lock_max_wait_time &&
/* only update the variable if we successfully
retrieved the start and finish times. See Bug#36819. */
start_time != -1 && finish_time != -1) {
srv_n_lock_max_wait_time = diff_time;
}
}
......
......@@ -202,12 +202,12 @@ srv_parse_data_file_paths_and_sizes(
str = srv_parse_megabytes(str, &size);
if (0 == memcmp(str, ":autoextend",
if (0 == strncmp(str, ":autoextend",
(sizeof ":autoextend") - 1)) {
str += (sizeof ":autoextend") - 1;
if (0 == memcmp(str, ":max:",
if (0 == strncmp(str, ":max:",
(sizeof ":max:") - 1)) {
str += (sizeof ":max:") - 1;
......@@ -290,14 +290,15 @@ srv_parse_data_file_paths_and_sizes(
(*data_file_names)[i] = path;
(*data_file_sizes)[i] = size;
if (0 == memcmp(str, ":autoextend",
if (0 == strncmp(str, ":autoextend",
(sizeof ":autoextend") - 1)) {
*is_auto_extending = TRUE;
str += (sizeof ":autoextend") - 1;
if (0 == memcmp(str, ":max:", (sizeof ":max:") - 1)) {
if (0 == strncmp(str, ":max:",
(sizeof ":max:") - 1)) {
str += (sizeof ":max:") - 1;
......
......@@ -112,19 +112,45 @@ ut_time(void)
}
/**************************************************************
Returns system time. */
Returns system time.
Upon successful completion, the value 0 is returned; otherwise the
value -1 is returned and the global variable errno is set to indicate the
error. */
void
int
ut_usectime(
/*========*/
/* out: 0 on success, -1 otherwise */
ulint* sec, /* out: seconds since the Epoch */
ulint* ms) /* out: microseconds since the Epoch+*sec */
{
struct timeval tv;
int ret;
int errno_gettimeofday;
int i;
for (i = 0; i < 10; i++) {
ut_gettimeofday(&tv, NULL);
ret = ut_gettimeofday(&tv, NULL);
if (ret == -1) {
errno_gettimeofday = errno;
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: gettimeofday(): %s\n",
strerror(errno_gettimeofday));
os_thread_sleep(100000); /* 0.1 sec */
errno = errno_gettimeofday;
} else {
break;
}
}
if (ret != -1) {
*sec = (ulint) tv.tv_sec;
*ms = (ulint) tv.tv_usec;
}
return(ret);
}
/**************************************************************
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment