From e43df58eade0b6806377966a0d3a2cdb88743a5d Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 4 Jun 2009 23:36:34 +0500 Subject: [PATCH 001/146] Bug#43733 Select on processlist let the embedded server crash (concurrent_innodb_safelog) the thread->mysys_var parameter should be empty for the idle embedded-server threads so that working threads can safely free this memory. per-file comments: libmysqld/lib_sql.cc Bug#43733 Select on processlist let the embedded server crash (concurrent_innodb_safelog) set thread->mysys_var= 0 after the query is handled mysql-test/include/concurrent.inc Bug#43733 Select on processlist let the embedded server crash (concurrent_innodb_safelog) enable these for the embedded-server mode sql/sql_show.cc Bug#43733 Select on processlist let the embedded server crash (concurrent_innodb_safelog) show thread lock status in the query result --- libmysqld/lib_sql.cc | 3 +++ mysql-test/include/concurrent.inc | 2 -- sql/sql_show.cc | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index d644c45a66a..4fd5cf19812 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -142,6 +142,8 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, if (!skip_check) result= thd->is_error() ? -1 : 0; + thd->mysys_var= 0; + #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.finish_current_query(); #endif @@ -634,6 +636,7 @@ void *create_embedded_thd(int client_flag) thread_count++; threads.append(thd); + thd->mysys_var= 0; return thd; err: delete(thd); diff --git a/mysql-test/include/concurrent.inc b/mysql-test/include/concurrent.inc index 66f8a65a102..0b7299a3c34 100644 --- a/mysql-test/include/concurrent.inc +++ b/mysql-test/include/concurrent.inc @@ -25,8 +25,6 @@ # new wrapper t/concurrent_innodb_safelog.test # ---source include/not_embedded.inc - connection default; # # Show prerequisites for this test. diff --git a/sql/sql_show.cc b/sql/sql_show.cc index d08b3a248c4..e9ae8fea3ed 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1888,7 +1888,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) tmp->mysys_var->current_cond ? "Waiting on cond" : NullS); #else - val= (char *) "Writing to net"; + val= (char *) (tmp->proc_info ? tmp->proc_info : NullS); #endif if (val) { From 63212b164363569a51106c3f516b53d4df745a28 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 11 Sep 2009 15:52:08 +0300 Subject: [PATCH 002/146] Bug #45159 : some tests in suite "jp" fail in embedded server (use LOAD DATA) Initialize correctly client flags for the embedded client Test cases in jp updated to work correctly with embedded server. --- libmysqld/libmysqld.c | 1 + mysql-test/suite/jp/r/jp_charset_sjis.result | 12 --------- mysql-test/suite/jp/r/jp_charset_ujis.result | 12 --------- mysql-test/suite/jp/r/jp_charset_utf8.result | 12 --------- mysql-test/suite/jp/r/jp_convert_sjis.result | 12 --------- mysql-test/suite/jp/r/jp_convert_ujis.result | 12 --------- mysql-test/suite/jp/r/jp_convert_utf8.result | 12 --------- mysql-test/suite/jp/r/jp_like_sjis.result | 12 --------- mysql-test/suite/jp/r/jp_like_ujis.result | 12 --------- mysql-test/suite/jp/r/jp_like_utf8.result | 12 --------- mysql-test/suite/jp/r/jp_select_sjis.result | 12 --------- mysql-test/suite/jp/r/jp_select_ujis.result | 12 --------- mysql-test/suite/jp/r/jp_select_utf8.result | 12 --------- mysql-test/suite/jp/r/jp_where_sjis.result | 12 --------- mysql-test/suite/jp/r/jp_where_ujis.result | 12 --------- mysql-test/suite/jp/r/jp_where_utf8.result | 12 --------- mysql-test/suite/jp/t/jp_charset_sjis.test | 26 +++++++++++--------- mysql-test/suite/jp/t/jp_charset_ujis.test | 26 +++++++++++--------- mysql-test/suite/jp/t/jp_charset_utf8.test | 26 +++++++++++--------- mysql-test/suite/jp/t/jp_convert_sjis.test | 26 +++++++++++--------- mysql-test/suite/jp/t/jp_convert_ujis.test | 26 +++++++++++--------- mysql-test/suite/jp/t/jp_convert_utf8.test | 26 +++++++++++--------- mysql-test/suite/jp/t/jp_like_sjis.test | 26 +++++++++++--------- mysql-test/suite/jp/t/jp_like_ujis.test | 26 +++++++++++--------- mysql-test/suite/jp/t/jp_like_utf8.test | 26 +++++++++++--------- mysql-test/suite/jp/t/jp_select_sjis.test | 26 +++++++++++--------- mysql-test/suite/jp/t/jp_select_ujis.test | 26 +++++++++++--------- mysql-test/suite/jp/t/jp_select_utf8.test | 26 +++++++++++--------- mysql-test/suite/jp/t/jp_where_sjis.test | 26 +++++++++++--------- mysql-test/suite/jp/t/jp_where_ujis.test | 26 +++++++++++--------- mysql-test/suite/jp/t/jp_where_utf8.test | 26 +++++++++++--------- 31 files changed, 211 insertions(+), 360 deletions(-) diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c index eb47a045669..969ea442622 100644 --- a/libmysqld/libmysqld.c +++ b/libmysqld/libmysqld.c @@ -164,6 +164,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, port=0; unix_socket=0; + client_flag|=mysql->options.client_flag; /* Send client information for access check */ client_flag|=CLIENT_CAPABILITIES; if (client_flag & CLIENT_MULTI_STATEMENTS) diff --git a/mysql-test/suite/jp/r/jp_charset_sjis.result b/mysql-test/suite/jp/r/jp_charset_sjis.result index 80ef24a7334..312033be719 100644 --- a/mysql-test/suite/jp/r/jp_charset_sjis.result +++ b/mysql-test/suite/jp/r/jp_charset_sjis.result @@ -24,18 +24,6 @@ CREATE TABLE ` CREATE TABLE `俿侾侽` (`俠侾` char(20)) DEFAULT CHARSET = sjis engine = bdb; CREATE TABLE `俿侾侾` (`俠侾` char(20)) DEFAULT CHARSET = sjis engine = bdb; CREATE TABLE `俿侾俀` (`俠侾` char(20)) DEFAULT CHARSET = sjis engine = bdb; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俀`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俁`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿係`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俆`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俇`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿俈`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俉`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俋`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾侽`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿侾侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿侾俀`; SELECT DISTINCT CHARSET(`俠侾`) FROM `俿侾`; CHARSET(`俠侾`) sjis diff --git a/mysql-test/suite/jp/r/jp_charset_ujis.result b/mysql-test/suite/jp/r/jp_charset_ujis.result index 964477896bd..4f6e68ba137 100644 --- a/mysql-test/suite/jp/r/jp_charset_ujis.result +++ b/mysql-test/suite/jp/r/jp_charset_ujis.result @@ -24,18 +24,6 @@ CREATE TABLE ` CREATE TABLE `T10` (`C1` char(20)) DEFAULT CHARSET = ujis engine = bdb; CREATE TABLE `T11` (`C1` char(20)) DEFAULT CHARSET = ujis engine = bdb; CREATE TABLE `T12` (`C1` char(20)) DEFAULT CHARSET = ujis engine = bdb; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T1`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T2`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T3`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T4`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T5`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T6`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T7`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T8`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T9`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T10`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T11`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T12`; SELECT DISTINCT CHARSET(`C1`) FROM `T1`; CHARSET(`C1`) ujis diff --git a/mysql-test/suite/jp/r/jp_charset_utf8.result b/mysql-test/suite/jp/r/jp_charset_utf8.result index 2fdd3fb1a6b..04140828d14 100644 --- a/mysql-test/suite/jp/r/jp_charset_utf8.result +++ b/mysql-test/suite/jp/r/jp_charset_utf8.result @@ -24,18 +24,6 @@ CREATE TABLE `锛达紮` (`锛o紤` char(20)) DEFAULT CHARSET = utf8 engine = heap; CREATE TABLE `锛达紤锛恅 (`锛o紤` char(20)) DEFAULT CHARSET = utf8 engine = bdb; CREATE TABLE `锛达紤锛慲 (`锛o紤` char(20)) DEFAULT CHARSET = utf8 engine = bdb; CREATE TABLE `锛达紤锛抈 (`锛o紤` char(20)) DEFAULT CHARSET = utf8 engine = bdb; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紥`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紦`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紨`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紩`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紪`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紬`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紭`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紮`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤锛恅; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紤锛慲; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紤锛抈; SELECT DISTINCT CHARSET(`锛o紤`) FROM `锛达紤`; CHARSET(`锛o紤`) utf8 diff --git a/mysql-test/suite/jp/r/jp_convert_sjis.result b/mysql-test/suite/jp/r/jp_convert_sjis.result index ff8a3fb2cd9..bc581ca56b0 100644 --- a/mysql-test/suite/jp/r/jp_convert_sjis.result +++ b/mysql-test/suite/jp/r/jp_convert_sjis.result @@ -24,18 +24,6 @@ CREATE TABLE ` CREATE TABLE `俿侾侽` (`俠侾` char(20), INDEX(`俠侾`)) DEFAULT CHARSET = sjis engine = bdb; CREATE TABLE `俿侾侾` (`俠侾` char(20), INDEX(`俠侾`)) DEFAULT CHARSET = sjis engine = bdb; CREATE TABLE `俿侾俀` (`俠侾` char(20), INDEX(`俠侾`)) DEFAULT CHARSET = sjis engine = bdb; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俀`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俁`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿係`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俆`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俇`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿俈`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俉`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俋`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾侽`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿侾侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿侾俀`; SELECT `俠侾`, CONVERT(`俠侾` using utf8) FROM `俿侾`; 俠侾 CONVERT(`俠侾` using utf8) !"#$%&'()*+,-./ !"#$%&'()*+,-./ diff --git a/mysql-test/suite/jp/r/jp_convert_ujis.result b/mysql-test/suite/jp/r/jp_convert_ujis.result index 55f2ab0aea3..f256d8b08b4 100644 --- a/mysql-test/suite/jp/r/jp_convert_ujis.result +++ b/mysql-test/suite/jp/r/jp_convert_ujis.result @@ -24,18 +24,6 @@ CREATE TABLE ` CREATE TABLE `T10` (`C1` char(20), INDEX(`C1`)) DEFAULT CHARSET = ujis engine = bdb; CREATE TABLE `T11` (`C1` char(20), INDEX(`C1`)) DEFAULT CHARSET = ujis engine = bdb; CREATE TABLE `T12` (`C1` char(20), INDEX(`C1`)) DEFAULT CHARSET = ujis engine = bdb; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T1`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T2`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T3`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T4`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T5`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T6`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T7`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T8`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T9`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T10`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T11`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T12`; SELECT `C1`, CONVERT(`C1` using utf8) FROM `T1`; C1 CONVERT(`C1` using utf8) !"#$%&'()*+,-./ !"#$%&'()*+,-./ diff --git a/mysql-test/suite/jp/r/jp_convert_utf8.result b/mysql-test/suite/jp/r/jp_convert_utf8.result index 505d6c1cebf..944f1c1068c 100644 --- a/mysql-test/suite/jp/r/jp_convert_utf8.result +++ b/mysql-test/suite/jp/r/jp_convert_utf8.result @@ -24,18 +24,6 @@ CREATE TABLE `锛达紮` (`锛o紤` char(20), INDEX(`锛o紤`)) DEFAULT CHARSET = utf CREATE TABLE `锛达紤锛恅 (`锛o紤` char(20), INDEX(`锛o紤`)) DEFAULT CHARSET = utf8 engine = bdb; CREATE TABLE `锛达紤锛慲 (`锛o紤` char(20), INDEX(`锛o紤`)) DEFAULT CHARSET = utf8 engine = bdb; CREATE TABLE `锛达紤锛抈 (`锛o紤` char(20), INDEX(`锛o紤`)) DEFAULT CHARSET = utf8 engine = bdb; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紥`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紦`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紨`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紩`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紪`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紬`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紭`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紮`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤锛恅; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紤锛慲; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紤锛抈; SELECT `锛o紤`, CONVERT(`锛o紤` using ujis) FROM `锛达紤`; 锛o紤 CONVERT(`锛o紤` using ujis) !"#$%&'()*+,-./ !"#$%&'()*+,-./ diff --git a/mysql-test/suite/jp/r/jp_like_sjis.result b/mysql-test/suite/jp/r/jp_like_sjis.result index a8145fb08f0..3e52781c7bd 100644 --- a/mysql-test/suite/jp/r/jp_like_sjis.result +++ b/mysql-test/suite/jp/r/jp_like_sjis.result @@ -24,18 +24,6 @@ CREATE TABLE ` CREATE TABLE `俿侾侽` (`俠侾` char(20), INDEX(`俠侾`)) DEFAULT CHARSET = sjis engine = bdb; CREATE TABLE `俿侾侾` (`俠侾` char(20), INDEX(`俠侾`)) DEFAULT CHARSET = sjis engine = bdb; CREATE TABLE `俿侾俀` (`俠侾` char(20), INDEX(`俠侾`)) DEFAULT CHARSET = sjis engine = bdb; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俀`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俁`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿係`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俆`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俇`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿俈`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俉`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俋`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾侽`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿侾侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿侾俀`; SELECT * FROM `俿侾` WHERE `俠侾` LIKE ' %'; 俠侾 !"#$%&'()*+,-./ diff --git a/mysql-test/suite/jp/r/jp_like_ujis.result b/mysql-test/suite/jp/r/jp_like_ujis.result index 5d623df0384..f685d185072 100644 --- a/mysql-test/suite/jp/r/jp_like_ujis.result +++ b/mysql-test/suite/jp/r/jp_like_ujis.result @@ -24,18 +24,6 @@ CREATE TABLE ` CREATE TABLE `T10` (`C1` char(20), INDEX(`C1`)) DEFAULT CHARSET = ujis engine = bdb; CREATE TABLE `T11` (`C1` char(20), INDEX(`C1`)) DEFAULT CHARSET = ujis engine = bdb; CREATE TABLE `T12` (`C1` char(20), INDEX(`C1`)) DEFAULT CHARSET = ujis engine = bdb; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T1`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T2`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T3`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T4`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T5`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T6`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T7`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T8`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T9`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T10`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T11`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T12`; SELECT * FROM `T1` WHERE `C1` LIKE ' %'; C1 !"#$%&'()*+,-./ diff --git a/mysql-test/suite/jp/r/jp_like_utf8.result b/mysql-test/suite/jp/r/jp_like_utf8.result index bf48da79951..90b960ca3a7 100644 --- a/mysql-test/suite/jp/r/jp_like_utf8.result +++ b/mysql-test/suite/jp/r/jp_like_utf8.result @@ -24,18 +24,6 @@ CREATE TABLE `锛达紮` (`锛o紤` char(20), INDEX(`锛o紤`)) DEFAULT CHARSET = utf CREATE TABLE `锛达紤锛恅 (`锛o紤` char(20), INDEX(`锛o紤`)) DEFAULT CHARSET = utf8 engine = bdb; CREATE TABLE `锛达紤锛慲 (`锛o紤` char(20), INDEX(`锛o紤`)) DEFAULT CHARSET = utf8 engine = bdb; CREATE TABLE `锛达紤锛抈 (`锛o紤` char(20), INDEX(`锛o紤`)) DEFAULT CHARSET = utf8 engine = bdb; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紥`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紦`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紨`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紩`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紪`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紬`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紭`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紮`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤锛恅; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紤锛慲; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紤锛抈; SELECT * FROM `锛达紤` WHERE `锛o紤` LIKE ' %'; 锛o紤 !"#$%&'()*+,-./ diff --git a/mysql-test/suite/jp/r/jp_select_sjis.result b/mysql-test/suite/jp/r/jp_select_sjis.result index 652b538fb88..021b0d29f43 100644 --- a/mysql-test/suite/jp/r/jp_select_sjis.result +++ b/mysql-test/suite/jp/r/jp_select_sjis.result @@ -24,18 +24,6 @@ CREATE TABLE ` CREATE TABLE `俿侾侽` (`俠侾` char(20), INDEX(`俠侾`)) DEFAULT CHARSET = sjis engine = bdb; CREATE TABLE `俿侾侾` (`俠侾` char(20), INDEX(`俠侾`)) DEFAULT CHARSET = sjis engine = bdb; CREATE TABLE `俿侾俀` (`俠侾` char(20), INDEX(`俠侾`)) DEFAULT CHARSET = sjis engine = bdb; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俀`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俁`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿係`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俆`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俇`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿俈`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俉`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俋`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾侽`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿侾侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿侾俀`; SELECT * FROM `俿侾`; 俠侾 !"#$%&'()*+,-./ diff --git a/mysql-test/suite/jp/r/jp_select_ujis.result b/mysql-test/suite/jp/r/jp_select_ujis.result index 3eea73c8083..d70997b0a01 100644 --- a/mysql-test/suite/jp/r/jp_select_ujis.result +++ b/mysql-test/suite/jp/r/jp_select_ujis.result @@ -24,18 +24,6 @@ CREATE TABLE ` CREATE TABLE `T10` (c1 char(20), INDEX(c1)) DEFAULT CHARSET = ujis engine = bdb; CREATE TABLE `T11` (c1 char(20), INDEX(c1)) DEFAULT CHARSET = ujis engine = bdb; CREATE TABLE `T12` (c1 char(20), INDEX(c1)) DEFAULT CHARSET = ujis engine = bdb; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T1`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T2`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T3`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T4`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T5`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T6`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T7`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T8`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T9`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T10`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T11`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T12`; SELECT * FROM `T1`; c1 !"#$%&'()*+,-./ diff --git a/mysql-test/suite/jp/r/jp_select_utf8.result b/mysql-test/suite/jp/r/jp_select_utf8.result index 43704ad2f6e..8bc61b802be 100644 --- a/mysql-test/suite/jp/r/jp_select_utf8.result +++ b/mysql-test/suite/jp/r/jp_select_utf8.result @@ -24,18 +24,6 @@ CREATE TABLE `锛达紮` (c1 char(20), INDEX(c1)) DEFAULT CHARSET = utf8 engine = h CREATE TABLE `锛达紤锛恅 (c1 char(20), INDEX(c1)) DEFAULT CHARSET = utf8 engine = bdb; CREATE TABLE `锛达紤锛慲 (c1 char(20), INDEX(c1)) DEFAULT CHARSET = utf8 engine = bdb; CREATE TABLE `锛达紤锛抈 (c1 char(20), INDEX(c1)) DEFAULT CHARSET = utf8 engine = bdb; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紥`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紦`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紨`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紩`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紪`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紬`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紭`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紮`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤锛恅; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紤锛慲; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紤锛抈; SELECT * FROM `锛达紤`; c1 !"#$%&'()*+,-./ diff --git a/mysql-test/suite/jp/r/jp_where_sjis.result b/mysql-test/suite/jp/r/jp_where_sjis.result index a3cbc24c113..e8be6e10850 100644 --- a/mysql-test/suite/jp/r/jp_where_sjis.result +++ b/mysql-test/suite/jp/r/jp_where_sjis.result @@ -24,18 +24,6 @@ CREATE TABLE ` CREATE TABLE `俿侾侽` (`俠侾` char(20), INDEX(`俠侾`)) DEFAULT CHARSET = sjis engine = bdb; CREATE TABLE `俿侾侾` (`俠侾` char(20), INDEX(`俠侾`)) DEFAULT CHARSET = sjis engine = bdb; CREATE TABLE `俿侾俀` (`俠侾` char(20), INDEX(`俠侾`)) DEFAULT CHARSET = sjis engine = bdb; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俀`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俁`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿係`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俆`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俇`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿俈`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俉`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俋`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾侽`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿侾侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿侾俀`; SELECT * FROM `俿侾` WHERE `俠侾` = '氨渤吹斗腹夯冀究'; 俠侾 氨渤吹斗腹夯冀究 diff --git a/mysql-test/suite/jp/r/jp_where_ujis.result b/mysql-test/suite/jp/r/jp_where_ujis.result index b13b8a10ef8..6b7dc4dde22 100644 --- a/mysql-test/suite/jp/r/jp_where_ujis.result +++ b/mysql-test/suite/jp/r/jp_where_ujis.result @@ -24,18 +24,6 @@ CREATE TABLE ` CREATE TABLE `T10` (`C1` char(20), INDEX(`C1`)) DEFAULT CHARSET = ujis engine = bdb; CREATE TABLE `T11` (`C1` char(20), INDEX(`C1`)) DEFAULT CHARSET = ujis engine = bdb; CREATE TABLE `T12` (`C1` char(20), INDEX(`C1`)) DEFAULT CHARSET = ujis engine = bdb; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T1`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T2`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T3`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T4`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T5`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T6`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T7`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T8`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T9`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T10`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T11`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T12`; SELECT * FROM `T1` WHERE `C1` = '幇幈幉幊幋幍幎幏幐幑幒幓幖幗幘幙'; C1 幇幈幉幊幋幍幎幏幐幑幒幓幖幗幘幙 diff --git a/mysql-test/suite/jp/r/jp_where_utf8.result b/mysql-test/suite/jp/r/jp_where_utf8.result index d69aaf8715d..cd7a4c0e500 100644 --- a/mysql-test/suite/jp/r/jp_where_utf8.result +++ b/mysql-test/suite/jp/r/jp_where_utf8.result @@ -24,18 +24,6 @@ CREATE TABLE `锛达紮` (`锛o紤` char(20), INDEX(`锛o紤`)) DEFAULT CHARSET = utf CREATE TABLE `锛达紤锛恅 (`锛o紤` char(20), INDEX(`锛o紤`)) DEFAULT CHARSET = utf8 engine = bdb; CREATE TABLE `锛达紤锛慲 (`锛o紤` char(20), INDEX(`锛o紤`)) DEFAULT CHARSET = utf8 engine = bdb; CREATE TABLE `锛达紤锛抈 (`锛o紤` char(20), INDEX(`锛o紤`)) DEFAULT CHARSET = utf8 engine = bdb; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紥`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紦`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紨`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紩`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紪`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紬`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紭`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紮`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤锛恅; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紤锛慲; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紤锛抈; SELECT * FROM `锛达紤` WHERE `锛o紤` = '锝帮奖锝诧匠锝达降锝讹椒锝革焦锝猴交锝硷浇锝撅娇'; 锛o紤 锝帮奖锝诧匠锝达降锝讹椒锝革焦锝猴交锝硷浇锝撅娇 diff --git a/mysql-test/suite/jp/t/jp_charset_sjis.test b/mysql-test/suite/jp/t/jp_charset_sjis.test index 276be86cd9d..26a56fb61d6 100644 --- a/mysql-test/suite/jp/t/jp_charset_sjis.test +++ b/mysql-test/suite/jp/t/jp_charset_sjis.test @@ -40,18 +40,20 @@ CREATE TABLE ` # jisx0201 hankaku-katakana data # jisx0208 data - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俀`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俁`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿係`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俆`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俇`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿俈`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俉`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俋`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾侽`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿侾侾`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿侾俀`; +--disable_query_log + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俀`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俁`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿係`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俆`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俇`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿俈`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俉`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俋`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾侽`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿侾侾`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿侾俀`; +--enable_query_log #InnoDB SELECT DISTINCT CHARSET(`俠侾`) FROM `俿侾`; diff --git a/mysql-test/suite/jp/t/jp_charset_ujis.test b/mysql-test/suite/jp/t/jp_charset_ujis.test index a8a6544537a..6308c7124ee 100644 --- a/mysql-test/suite/jp/t/jp_charset_ujis.test +++ b/mysql-test/suite/jp/t/jp_charset_ujis.test @@ -42,18 +42,20 @@ CREATE TABLE ` # jisx0208 data # jisx0212 supplemental character data - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T1`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T2`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T3`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T4`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T5`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T6`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T7`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T8`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T9`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T10`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T11`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T12`; +--disable_query_log + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T1`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T2`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T3`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T4`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T5`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T6`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T7`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T8`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T9`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T10`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T11`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T12`; +--enable_query_log #InnoDB SELECT DISTINCT CHARSET(`C1`) FROM `T1`; diff --git a/mysql-test/suite/jp/t/jp_charset_utf8.test b/mysql-test/suite/jp/t/jp_charset_utf8.test index 7d8311c2f72..dcce0477204 100644 --- a/mysql-test/suite/jp/t/jp_charset_utf8.test +++ b/mysql-test/suite/jp/t/jp_charset_utf8.test @@ -40,18 +40,20 @@ CREATE TABLE `锛达紤锛抈 (`锛o紤` char(20)) DEFAULT CHARSET = utf8 engine = bdb # jisx0208 data # jisx0212 supplemental character data - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紥`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紦`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紨`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紩`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紪`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紬`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紭`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紮`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤锛恅; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紤锛慲; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紤锛抈; +--disable_query_log + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紥`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紦`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紨`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紩`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紪`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紬`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紭`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紮`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤锛恅; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紤锛慲; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紤锛抈; +--enable_query_log #InnoDB SELECT DISTINCT CHARSET(`锛o紤`) FROM `锛达紤`; diff --git a/mysql-test/suite/jp/t/jp_convert_sjis.test b/mysql-test/suite/jp/t/jp_convert_sjis.test index 835328c92eb..4e76b414442 100644 --- a/mysql-test/suite/jp/t/jp_convert_sjis.test +++ b/mysql-test/suite/jp/t/jp_convert_sjis.test @@ -41,18 +41,20 @@ CREATE TABLE ` # jisx0208 data # jisx0212 supplemental character data - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俀`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俁`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿係`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俆`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俇`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿俈`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俉`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俋`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾侽`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿侾侾`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿侾俀`; +--disable_query_log + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俀`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俁`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿係`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俆`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俇`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿俈`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俉`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俋`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾侽`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿侾侾`; + --eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿侾俀`; +--enable_query_log #InnoDB SELECT `俠侾`, CONVERT(`俠侾` using utf8) FROM `俿侾`; diff --git a/mysql-test/suite/jp/t/jp_convert_ujis.test b/mysql-test/suite/jp/t/jp_convert_ujis.test index 4409b6cad90..7d53d1853d3 100644 --- a/mysql-test/suite/jp/t/jp_convert_ujis.test +++ b/mysql-test/suite/jp/t/jp_convert_ujis.test @@ -42,18 +42,20 @@ CREATE TABLE ` # jisx0208 data # jisx0212 supplemental character data - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T1`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T2`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T3`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T4`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T5`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T6`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T7`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T8`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T9`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T10`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T11`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T12`; +--disable_query_log +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T1`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T2`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T3`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T4`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T5`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T6`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T7`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T8`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T9`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T10`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T11`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T12`; +--enable_query_log #InnoDB SELECT `C1`, CONVERT(`C1` using utf8) FROM `T1`; diff --git a/mysql-test/suite/jp/t/jp_convert_utf8.test b/mysql-test/suite/jp/t/jp_convert_utf8.test index e7c180e72fc..3d81704e87c 100644 --- a/mysql-test/suite/jp/t/jp_convert_utf8.test +++ b/mysql-test/suite/jp/t/jp_convert_utf8.test @@ -40,18 +40,20 @@ CREATE TABLE `锛达紤锛抈 (`锛o紤` char(20), INDEX(`锛o紤`)) DEFAULT CHARSET = # jisx0208 data # jisx0212 supplemental character data - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紥`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紦`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紨`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紩`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紪`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紬`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紭`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紮`; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤锛恅; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紤锛慲; - LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紤锛抈; +--disable_query_log +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紥`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紦`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紨`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紩`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紪`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紬`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紭`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紮`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤锛恅; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紤锛慲; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紤锛抈; +--enable_query_log #InnoDB SELECT `锛o紤`, CONVERT(`锛o紤` using ujis) FROM `锛达紤`; diff --git a/mysql-test/suite/jp/t/jp_like_sjis.test b/mysql-test/suite/jp/t/jp_like_sjis.test index 1cb7aadb876..ad2c5f7b465 100644 --- a/mysql-test/suite/jp/t/jp_like_sjis.test +++ b/mysql-test/suite/jp/t/jp_like_sjis.test @@ -40,18 +40,20 @@ CREATE TABLE ` # jisx0201 hankaku-katakana data # jisx0208 data -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俀`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俁`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿係`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俆`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俇`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿俈`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俉`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俋`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾侽`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿侾侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿侾俀`; +--disable_query_log +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俀`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俁`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿係`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俆`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俇`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿俈`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俉`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俋`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾侽`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿侾侾`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿侾俀`; +--enable_query_log #InnoDB SELECT * FROM `俿侾` WHERE `俠侾` LIKE ' %'; diff --git a/mysql-test/suite/jp/t/jp_like_ujis.test b/mysql-test/suite/jp/t/jp_like_ujis.test index 56c4fa8a8b0..c3660e8f88f 100644 --- a/mysql-test/suite/jp/t/jp_like_ujis.test +++ b/mysql-test/suite/jp/t/jp_like_ujis.test @@ -42,18 +42,20 @@ CREATE TABLE ` # jisx0208 data # jisx0212 supplemental character data -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T1`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T2`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T3`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T4`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T5`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T6`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T7`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T8`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T9`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T10`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T11`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T12`; +--disable_query_log +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T1`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T2`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T3`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T4`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T5`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T6`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T7`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T8`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T9`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T10`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T11`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T12`; +--enable_query_log #InnoDB SELECT * FROM `T1` WHERE `C1` LIKE ' %'; diff --git a/mysql-test/suite/jp/t/jp_like_utf8.test b/mysql-test/suite/jp/t/jp_like_utf8.test index f6cc895d814..57fc1584471 100644 --- a/mysql-test/suite/jp/t/jp_like_utf8.test +++ b/mysql-test/suite/jp/t/jp_like_utf8.test @@ -40,18 +40,20 @@ CREATE TABLE `锛达紤锛抈 (`锛o紤` char(20), INDEX(`锛o紤`)) DEFAULT CHARSET = # jisx0208 data # jisx0212 supplemental character data -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紥`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紦`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紨`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紩`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紪`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紬`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紭`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紮`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤锛恅; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紤锛慲; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紤锛抈; +--disable_query_log +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紥`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紦`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紨`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紩`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紪`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紬`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紭`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紮`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤锛恅; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紤锛慲; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紤锛抈; +--enable_query_log #InnoDB SELECT * FROM `锛达紤` WHERE `锛o紤` LIKE ' %'; diff --git a/mysql-test/suite/jp/t/jp_select_sjis.test b/mysql-test/suite/jp/t/jp_select_sjis.test index fc80ce01471..698d87a6852 100644 --- a/mysql-test/suite/jp/t/jp_select_sjis.test +++ b/mysql-test/suite/jp/t/jp_select_sjis.test @@ -41,18 +41,20 @@ CREATE TABLE ` # jisx0208 data # jisx0212 supplemental character data -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俀`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俁`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿係`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俆`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俇`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿俈`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俉`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俋`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾侽`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿侾侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿侾俀`; +--disable_query_log +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俀`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俁`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿係`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俆`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俇`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿俈`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俉`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俋`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾侽`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿侾侾`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿侾俀`; +--enable_query_log #InnoDB SELECT * FROM `俿侾`; diff --git a/mysql-test/suite/jp/t/jp_select_ujis.test b/mysql-test/suite/jp/t/jp_select_ujis.test index 0e4d1ffc771..7c8ec46d06e 100644 --- a/mysql-test/suite/jp/t/jp_select_ujis.test +++ b/mysql-test/suite/jp/t/jp_select_ujis.test @@ -42,18 +42,20 @@ CREATE TABLE ` # jisx0208 data # jisx0212 supplemental character data -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T1`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T2`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T3`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T4`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T5`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T6`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T7`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T8`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T9`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T10`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T11`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T12`; +--disable_query_log +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T1`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T2`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T3`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T4`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T5`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T6`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T7`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T8`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T9`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T10`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T11`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T12`; +--enable_query_log #InnoDB SELECT * FROM `T1`; diff --git a/mysql-test/suite/jp/t/jp_select_utf8.test b/mysql-test/suite/jp/t/jp_select_utf8.test index 88fd6677f7c..f410333fcfa 100644 --- a/mysql-test/suite/jp/t/jp_select_utf8.test +++ b/mysql-test/suite/jp/t/jp_select_utf8.test @@ -40,18 +40,20 @@ CREATE TABLE `锛达紤锛抈 (c1 char(20), INDEX(c1)) DEFAULT CHARSET = utf8 engine # jisx0208 data # jisx0212 supplemental character data -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紥`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紦`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紨`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紩`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紪`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紬`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紭`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紮`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤锛恅; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紤锛慲; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紤锛抈; +--disable_query_log +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紥`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紦`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紨`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紩`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紪`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紬`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紭`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紮`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤锛恅; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紤锛慲; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紤锛抈; +--enable_query_log #InnoDB SELECT * FROM `锛达紤`; diff --git a/mysql-test/suite/jp/t/jp_where_sjis.test b/mysql-test/suite/jp/t/jp_where_sjis.test index 890a4c28f3c..6fda91a7b4b 100644 --- a/mysql-test/suite/jp/t/jp_where_sjis.test +++ b/mysql-test/suite/jp/t/jp_where_sjis.test @@ -41,18 +41,20 @@ CREATE TABLE ` # jisx0208 data # jisx0212 supplemental character data -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俀`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俁`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿係`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俆`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俇`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿俈`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俉`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俋`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾侽`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿侾侾`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿侾俀`; +--disable_query_log +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俀`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俁`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿係`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俆`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俇`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿俈`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿俉`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿俋`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_sjis.dat' INTO TABLE `俿侾侽`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis.dat' INTO TABLE `俿侾侾`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_sjis2.dat' INTO TABLE `俿侾俀`; +--enable_query_log #InnoDB SELECT * FROM `俿侾` WHERE `俠侾` = '氨渤吹斗腹夯冀究'; diff --git a/mysql-test/suite/jp/t/jp_where_ujis.test b/mysql-test/suite/jp/t/jp_where_ujis.test index 2f0924e8c8e..6343610306e 100644 --- a/mysql-test/suite/jp/t/jp_where_ujis.test +++ b/mysql-test/suite/jp/t/jp_where_ujis.test @@ -42,18 +42,20 @@ CREATE TABLE ` # jisx0208 data # jisx0212 supplemental character data -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T1`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T2`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T3`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T4`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T5`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T6`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T7`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T8`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T9`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T10`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T11`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T12`; +--disable_query_log +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T1`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T2`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T3`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T4`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T5`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T6`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T7`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T8`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T9`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_ujis.dat' INTO TABLE `T10`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_ujis.dat' INTO TABLE `T11`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_ujis.dat' INTO TABLE `T12`; +--enable_query_log #InnoDB SELECT * FROM `T1` WHERE `C1` = '幇幈幉幊幋幍幎幏幐幑幒幓幖幗幘幙'; diff --git a/mysql-test/suite/jp/t/jp_where_utf8.test b/mysql-test/suite/jp/t/jp_where_utf8.test index 231553e8819..a37b6f1a41a 100644 --- a/mysql-test/suite/jp/t/jp_where_utf8.test +++ b/mysql-test/suite/jp/t/jp_where_utf8.test @@ -40,18 +40,20 @@ CREATE TABLE `锛达紤锛抈 (`锛o紤` char(20), INDEX(`锛o紤`)) DEFAULT CHARSET = # jisx0208 data # jisx0212 supplemental character data -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紥`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紦`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紨`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紩`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紪`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紬`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紭`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紮`; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤锛恅; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紤锛慲; -LOAD DATA LOCAL INFILE 'suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紤锛抈; +--disable_query_log +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紥`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紦`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紨`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紩`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紪`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紬`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紭`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紮`; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0201_utf8.dat' INTO TABLE `锛达紤锛恅; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0208_utf8.dat' INTO TABLE `锛达紤锛慲; +--eval LOAD DATA LOCAL INFILE '$MYSQL_TEST_DIR/suite/jp/std_data/jisx0212_utf8.dat' INTO TABLE `锛达紤锛抈; +--enable_query_log #InnoDB SELECT * FROM `锛达紤` WHERE `锛o紤` = '锝帮奖锝诧匠锝达降锝讹椒锝革焦锝猴交锝硷浇锝撅娇'; From 6e6974a553de6f88dc0a5c639fb28c640ac9d834 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 17 Sep 2009 14:25:07 +0300 Subject: [PATCH 003/146] Bug #46917: mysqd-nt installs wrong When parsing the service installation parameter in default_service_handling() make sure the value of the optional parameter doesn't overwrite it's name. --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index afbbf753813..ce1d562d0ca 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4022,7 +4022,7 @@ default_service_handling(char **argv, if (opt_delim= strchr(extra_opt, '=')) { size_t length= ++opt_delim - extra_opt; - strnmov(pos, extra_opt, length); + pos= strnmov(pos, extra_opt, length); } else opt_delim= extra_opt; From 05bf2ebaa8d00e2df564a4017749140b28d38714 Mon Sep 17 00:00:00 2001 From: Anurag Shekhar Date: Thu, 17 Sep 2009 17:35:43 +0530 Subject: [PATCH 004/146] Bug #45840 read_buffer_size allocated for each partition when "insert into.. select * from" When inserting into a partitioned table using 'insert into select * from ', read_buffer_size bytes of memory are allocated for each partition in the target table. This resulted in large memory consumption when the number of partitions are high. This patch introduces a new method which tries to estimate the buffer size required for each partition and limits the maximum buffer size used to maximum of 10 * read_buffer_size, 11 * read_buffer_size in case of monotonic partition functions. --- sql/ha_partition.cc | 52 ++++++++++++++++++++++++++++++++++++++++++--- sql/ha_partition.h | 3 ++- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 5b053ab9cac..b27f493b80a 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -3037,7 +3037,7 @@ int ha_partition::write_row(uchar * buf) } m_last_part= part_id; DBUG_PRINT("info", ("Insert in partition %d", part_id)); - start_part_bulk_insert(part_id); + start_part_bulk_insert(thd, part_id); tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ error= m_file[part_id]->ha_write_row(buf); @@ -3101,7 +3101,7 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data) } m_last_part= new_part_id; - start_part_bulk_insert(new_part_id); + start_part_bulk_insert(thd, new_part_id); if (new_part_id == old_part_id) { DBUG_PRINT("info", ("Update in partition %d", new_part_id)); @@ -3282,17 +3282,63 @@ void ha_partition::start_bulk_insert(ha_rows rows) Check if start_bulk_insert has been called for this partition, if not, call it and mark it called */ -void ha_partition::start_part_bulk_insert(uint part_id) +void ha_partition::start_part_bulk_insert(THD *thd, uint part_id) { + long old_buffer_size; if (!bitmap_is_set(&m_bulk_insert_started, part_id) && bitmap_is_set(&m_bulk_insert_started, m_tot_parts)) { + old_buffer_size= thd->variables.read_buff_size; + /* Update read_buffer_size for this partition */ + thd->variables.read_buff_size= estimate_read_buffer_size(old_buffer_size); m_file[part_id]->ha_start_bulk_insert(guess_bulk_insert_rows()); bitmap_set_bit(&m_bulk_insert_started, part_id); + thd->variables.read_buff_size= old_buffer_size; } m_bulk_inserted_rows++; } +/* + Estimate the read buffer size for each partition. + SYNOPSIS + ha_partition::estimate_read_buffer_size() + original_size read buffer size originally set for the server + RETURN VALUE + estimated buffer size. + DESCRIPTION + If the estimated number of rows to insert is less than 10 (but not 0) + the new buffer size is same as original buffer size. + In case of first partition of when partition function is monotonic + new buffer size is same as the original buffer size. + For rest of the partition total buffer of 10*original_size is divided + equally if number of partition is more than 10 other wise each partition + will be allowed to use original buffer size. +*/ +long ha_partition::estimate_read_buffer_size(long original_size) +{ + /* + If number of rows to insert is less than 10, but not 0, + return original buffer size. + */ + if (estimation_rows_to_insert && (estimation_rows_to_insert < 10)) + return (original_size); + /* + If first insert/partition and monotonic partition function, + allow using buffer size originally set. + */ + if (!m_bulk_inserted_rows && + m_part_func_monotonicity_info != NON_MONOTONIC && + m_tot_parts > 1) + return original_size; + /* + Allow total buffer used in all partition to go up to 10*read_buffer_size. + 11*read_buffer_size in case of monotonic partition function. + */ + + if (m_tot_parts < 10) + return original_size; + return (original_size * 10 / m_tot_parts); +} /* Try to predict the number of inserts into this partition. diff --git a/sql/ha_partition.h b/sql/ha_partition.h index f47dfe8f621..1c863d6c294 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -367,7 +367,8 @@ public: virtual int end_bulk_insert(); private: ha_rows guess_bulk_insert_rows(); - void start_part_bulk_insert(uint part_id); + void start_part_bulk_insert(THD *thd, uint part_id); + long estimate_read_buffer_size(long original_size); public: virtual bool is_fatal_error(int error, uint flags) From 38b6d49e826e1fde46c445d790eb7609b14c4220 Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Thu, 17 Sep 2009 17:10:30 +0200 Subject: [PATCH 005/146] Bug #43414 Parenthesis (and other) warnings compiling MySQL with gcc 4.3.2 This is the fifth patch cleaning up more GCC warnings about variables used before initialized using the new macro UNINIT_VAR(). --- heap/hp_write.c | 7 ++----- include/my_global.h | 6 ------ myisam/mi_search.c | 6 ++---- myisam/mi_write.c | 6 ++---- mysys/hash.c | 7 ++----- sql-common/my_time.c | 3 +-- sql/item_func.cc | 6 ++---- sql/item_timefunc.cc | 11 +++-------- sql/sql_handler.cc | 7 ++----- sql/sql_lex.cc | 3 +-- sql/sql_select.cc | 3 +-- sql/udf_example.c | 4 ++-- 12 files changed, 20 insertions(+), 49 deletions(-) diff --git a/heap/hp_write.c b/heap/hp_write.c index 6aa34acf2c3..85551c1cc41 100644 --- a/heap/hp_write.c +++ b/heap/hp_write.c @@ -196,13 +196,10 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, HP_SHARE *share = info->s; int flag; ulong halfbuff,hashnr,first_index; - byte *ptr_to_rec,*ptr_to_rec2; - HASH_INFO *empty,*gpos,*gpos2,*pos; + byte *UNINIT_VAR(ptr_to_rec),*UNINIT_VAR(ptr_to_rec2); + HASH_INFO *empty,*UNINIT_VAR(gpos),*UNINIT_VAR(gpos2),*pos; DBUG_ENTER("hp_write_key"); - LINT_INIT(gpos); LINT_INIT(gpos2); - LINT_INIT(ptr_to_rec); LINT_INIT(ptr_to_rec2); - flag=0; if (!(empty= hp_find_free_hash(share,&keyinfo->block,share->records))) DBUG_RETURN(-1); /* No more memory */ diff --git a/include/my_global.h b/include/my_global.h index 0b5458215c6..6910ae092e1 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -458,12 +458,6 @@ int __void__; #define LINT_INIT(var) #endif -#if defined(_lint) || defined(FORCE_INIT_OF_VARS) || defined(HAVE_purify) -#define PURIFY_OR_LINT_INIT(var) var=0 -#else -#define PURIFY_OR_LINT_INIT(var) -#endif - /* Suppress uninitialized variable warning without generating code. diff --git a/myisam/mi_search.c b/myisam/mi_search.c index 3b1cd6158f2..21efaa03744 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -295,7 +295,8 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, uchar *end, *kseg, *vseg; uchar *sort_order=keyinfo->seg->charset->sort_order; uchar tt_buff[MI_MAX_KEY_BUFF+2], *t_buff=tt_buff+2; - uchar *saved_from, *saved_to, *saved_vseg; + uchar *UNINIT_VAR(saved_from), *UNINIT_VAR(saved_to); + uchar *UNINIT_VAR(saved_vseg); uint saved_length=0, saved_prefix_len=0; uint length_pack; DBUG_ENTER("_mi_prefix_search"); @@ -303,9 +304,6 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, LINT_INIT(length); LINT_INIT(prefix_len); LINT_INIT(seg_len_pack); - LINT_INIT(saved_from); - LINT_INIT(saved_to); - LINT_INIT(saved_vseg); t_buff[0]=0; /* Avoid bugs */ end= page+mi_getint(page); diff --git a/myisam/mi_write.c b/myisam/mi_write.c index b4843a748dd..61cea588562 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -700,8 +700,8 @@ static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page, uchar *key, uint *return_key_length, uchar **after_key) { - uint keys,length,last_length,key_ref_length; - uchar *end,*lastpos,*prevpos; + uint keys,length,UNINIT_VAR(last_length),key_ref_length; + uchar *end,*lastpos,*UNINIT_VAR(prevpos); uchar key_buff[MI_MAX_KEY_BUFF]; DBUG_ENTER("_mi_find_last_pos"); @@ -720,8 +720,6 @@ static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page, DBUG_RETURN(end); } - LINT_INIT(prevpos); - LINT_INIT(last_length); end=page+length-key_ref_length; *key='\0'; length=0; diff --git a/mysys/hash.c b/mysys/hash.c index 4aab75609f4..3e7851a886f 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -332,11 +332,8 @@ my_bool my_hash_insert(HASH *info,const byte *record) { int flag; uint halfbuff,hash_nr,first_index,idx; - byte *ptr_to_rec,*ptr_to_rec2; - HASH_LINK *data,*empty,*gpos,*gpos2,*pos; - - LINT_INIT(gpos); LINT_INIT(gpos2); - LINT_INIT(ptr_to_rec); LINT_INIT(ptr_to_rec2); + byte *UNINIT_VAR(ptr_to_rec),*UNINIT_VAR(ptr_to_rec2); + HASH_LINK *data,*empty,*UNINIT_VAR(gpos),*UNINIT_VAR(gpos2),*pos; flag=0; if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array))) diff --git a/sql-common/my_time.c b/sql-common/my_time.c index d2ef9da25f5..ed1279f7afb 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -165,7 +165,7 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, uint add_hours= 0, start_loop; ulong not_zero_date, allow_space; my_bool is_internal_format; - const char *pos, *last_field_pos; + const char *pos, *UNINIT_VAR(last_field_pos); const char *end=str+length; const uchar *format_position; my_bool found_delimitier= 0, found_space= 0; @@ -174,7 +174,6 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, DBUG_PRINT("ENTER",("str: %.*s",length,str)); LINT_INIT(field_length); - LINT_INIT(last_field_pos); *was_cut= 0; diff --git a/sql/item_func.cc b/sql/item_func.cc index 3c1e2126008..c6dbdb1d9a7 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -428,8 +428,7 @@ bool Item_func::eq(const Item *item, bool binary_cmp) const Field *Item_func::tmp_table_field(TABLE *t_arg) { - Field *res; - LINT_INIT(res); + Field *res= NULL; switch (result_type()) { case INT_RESULT: @@ -4202,9 +4201,8 @@ void Item_func_set_user_var::save_item_result(Item *item) bool Item_func_set_user_var::update() { - bool res; + bool res= NULL; DBUG_ENTER("Item_func_set_user_var::update"); - LINT_INIT(res); switch (cached_result_type) { case REAL_RESULT: diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 39f869106b6..de76f821795 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -271,9 +271,9 @@ static bool extract_date_time(DATE_TIME_FORMAT *format, int strict_week_number_year= -1; int frac_part; bool usa_time= 0; - bool sunday_first_n_first_week_non_iso; - bool strict_week_number; - bool strict_week_number_year_type; + bool UNINIT_VAR(sunday_first_n_first_week_non_iso); + bool UNINIT_VAR(strict_week_number); + bool UNINIT_VAR(strict_week_number_year_type); const char *val_begin= val; const char *val_end= val + length; const char *ptr= format->format.str; @@ -281,11 +281,6 @@ static bool extract_date_time(DATE_TIME_FORMAT *format, CHARSET_INFO *cs= &my_charset_bin; DBUG_ENTER("extract_date_time"); - LINT_INIT(strict_week_number); - /* Remove valgrind varnings when using gcc 3.3 and -O1 */ - PURIFY_OR_LINT_INIT(strict_week_number_year_type); - PURIFY_OR_LINT_INIT(sunday_first_n_first_week_non_iso); - if (!sub_pattern_end) bzero((char*) l_time, sizeof(*l_time)); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 721b365a7b9..5bd28add428 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -385,16 +385,13 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, String buffer(buff, sizeof(buff), system_charset_info); int error, keyno= -1; uint num_rows; - byte *key; - uint key_len; + byte *UNINIT_VAR(key); + uint UNINIT_VAR(key_len); bool need_reopen; DBUG_ENTER("mysql_ha_read"); DBUG_PRINT("enter",("'%s'.'%s' as '%s'", tables->db, tables->table_name, tables->alias)); - LINT_INIT(key); - LINT_INIT(key_len); - thd->lex->select_lex.context.resolve_in_table_list_only(tables); list.push_front(new Item_field(&thd->lex->select_lex.context, NULL, NULL, "*")); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index b0b4256184c..17ee53d446b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -530,7 +530,7 @@ static inline uint int_token(const char *str,uint length) int MYSQLlex(void *arg, void *yythd) { - reg1 uchar c; + reg1 uchar UNINIT_VAR(c); bool comment_closed; int tokval, result_state; uint length; @@ -550,7 +550,6 @@ int MYSQLlex(void *arg, void *yythd) lip->tok_start=lip->tok_end=lip->ptr; state=lip->next_state; lip->next_state=MY_LEX_OPERATOR_OR_IDENT; - LINT_INIT(c); for (;;) { switch (state) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9d5e67c9532..84b5b61c941 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10480,9 +10480,8 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) { int rc= 0; enum_nested_loop_state error= NESTED_LOOP_OK; - JOIN_TAB *join_tab; + JOIN_TAB *UNINIT_VAR(join_tab); DBUG_ENTER("do_select"); - LINT_INIT(join_tab); join->procedure=procedure; join->tmp_table= table; /* Save for easy recursion */ diff --git a/sql/udf_example.c b/sql/udf_example.c index db48984eed8..019d4d834dd 100644 --- a/sql/udf_example.c +++ b/sql/udf_example.c @@ -139,10 +139,10 @@ typedef long long longlong; #include #include -static pthread_mutex_t LOCK_hostname; - #ifdef HAVE_DLOPEN +static pthread_mutex_t LOCK_hostname; + /* These must be right or mysqld will not find the symbol! */ my_bool metaphon_init(UDF_INIT *initid, UDF_ARGS *args, char *message); From d39f0a72ade10a20453aefafefa85856ccaaa417 Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Fri, 18 Sep 2009 11:19:02 +0400 Subject: [PATCH 006/146] Bug #43606: 4GB Limit on huge_pages shared memory set-up Large pages allocator could not allocate more than 4 GB due to incorrect size alignment. --- mysys/my_largepage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/my_largepage.c b/mysys/my_largepage.c index a20111396cb..b50a606c8d8 100644 --- a/mysys/my_largepage.c +++ b/mysys/my_largepage.c @@ -121,7 +121,7 @@ uchar* my_large_malloc_int(size_t size, myf my_flags) DBUG_ENTER("my_large_malloc_int"); /* Align block size to my_large_page_size */ - size = ((size - 1) & ~(my_large_page_size - 1)) + my_large_page_size; + size= MY_ALIGN(size, (size_t) my_large_page_size); shmid = shmget(IPC_PRIVATE, size, SHM_HUGETLB | SHM_R | SHM_W); if (shmid < 0) From 7079338e0ed8f5ef52c77fd81ad23bbb8fd8c86a Mon Sep 17 00:00:00 2001 From: Date: Fri, 18 Sep 2009 16:20:29 +0800 Subject: [PATCH 007/146] Bug #42914 Log event that larger than max_allowed_packet results in stop of slave I/O thread, But there is no Last_IO_Error reported. On the master, if a binary log event is larger than max_allowed_packet, ER_MASTER_FATAL_ERROR_READING_BINLOG and the specific reason of this error is sent to a slave when it requests a dump from the master, thus leading the I/O thread to stop. On a slave, the I/O thread stops when receiving a packet larger than max_allowed_packet. In both cases, however, there was no Last_IO_Error reported. This patch adds code to report the Last_IO_Error and exact reason before stopping the I/O thread and also reports the case the out memory pops up while handling packets from the master. --- mysql-test/suite/rpl/r/rpl_packet.result | 15 ++++++++++++ mysql-test/suite/rpl/t/rpl_packet.test | 30 ++++++++++++++++++++++++ sql/share/errmsg.txt | 2 +- sql/slave.cc | 12 ++++++---- sql/sql_repl.cc | 14 ++++------- 5 files changed, 58 insertions(+), 15 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_packet.result b/mysql-test/suite/rpl/r/rpl_packet.result index 4c64054e348..cb26d04bea9 100644 --- a/mysql-test/suite/rpl/r/rpl_packet.result +++ b/mysql-test/suite/rpl/r/rpl_packet.result @@ -32,6 +32,21 @@ include/start_slave.inc CREATE TABLE `t1` (`f1` LONGTEXT) ENGINE=MyISAM; INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048'); Slave_IO_Running = No (expect No) +SELECT "Got a packet bigger than 'max_allowed_packet' bytes" AS Last_IO_Error; +Last_IO_Error +Got a packet bigger than 'max_allowed_packet' bytes +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +CREATE TABLE t1 (f1 int PRIMARY KEY, f2 LONGTEXT, f3 LONGTEXT) ENGINE=MyISAM; +INSERT INTO t1(f1, f2, f3) VALUES(1, REPEAT('a', @@global.max_allowed_packet), REPEAT('b', @@global.max_allowed_packet)); +Slave_IO_Running = No (expect No) +SELECT "Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master'" AS Last_IO_Error; +Last_IO_Error +Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master' ==== clean up ==== DROP TABLE t1; SET @@global.max_allowed_packet= 1024; diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test index 79cb2d9d735..b4e04405037 100644 --- a/mysql-test/suite/rpl/t/rpl_packet.test +++ b/mysql-test/suite/rpl/t/rpl_packet.test @@ -5,6 +5,7 @@ # max-out size db name source include/master-slave.inc; +source include/have_binlog_format_row.inc; let $db= DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; disable_warnings; @@ -86,6 +87,35 @@ connection slave; --source include/wait_for_slave_io_to_stop.inc let $slave_io_running= query_get_value(SHOW SLAVE STATUS, Slave_IO_Running, 1); --echo Slave_IO_Running = $slave_io_running (expect No) +# +# Bug#42914: The slave I/O thread must stop after trying to read the above +# event, However there is no Last_IO_Error report. +# +let $last_io_error= query_get_value(SHOW SLAVE STATUS, Last_IO_Error, 1); +eval SELECT "$last_io_error" AS Last_IO_Error; + +# +# Bug#42914: On the master, if a binary log event is larger than +# max_allowed_packet, the error message ER_MASTER_FATAL_ERROR_READING_BINLOG +# is sent to a slave when it requests a dump from the master, thus leading the +# I/O thread to stop. However, there is no Last_IO_Error reported. +# +source include/master-slave-reset.inc; +connection master; +CREATE TABLE t1 (f1 int PRIMARY KEY, f2 LONGTEXT, f3 LONGTEXT) ENGINE=MyISAM; +sync_slave_with_master; + +connection master; +INSERT INTO t1(f1, f2, f3) VALUES(1, REPEAT('a', @@global.max_allowed_packet), REPEAT('b', @@global.max_allowed_packet)); + +connection slave; +# The slave I/O thread must stop after receiving +# ER_MASTER_FATAL_ERROR_READING_BINLOG error message from master. +--source include/wait_for_slave_io_to_stop.inc +let $slave_io_running= query_get_value(SHOW SLAVE STATUS, Slave_IO_Running, 1); +--echo Slave_IO_Running = $slave_io_running (expect No) +let $last_io_error= query_get_value(SHOW SLAVE STATUS, Last_IO_Error, 1); +eval SELECT "$last_io_error" AS Last_IO_Error; --echo ==== clean up ==== connection master; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 3aba434b284..fdad2a44b68 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -4702,7 +4702,7 @@ ER_NOT_SUPPORTED_YET 42000 swe "Denna version av MySQL kan 鋘nu inte utf鰎a '%s'" ER_MASTER_FATAL_ERROR_READING_BINLOG nla "Kreeg fatale fout %d: '%-.128s' van master tijdens lezen van data uit binaire log" - eng "Got fatal error %d: '%-.128s' from master when reading data from binary log" + eng "Got fatal error %d from master when reading data from binary log: '%-.128s'" ger "Schwerer Fehler %d: '%-.128s vom Master beim Lesen des bin鋜en Logs" ita "Errore fatale %d: '%-.128s' dal master leggendo i dati dal log binario" por "Obteve fatal erro %d: '%-.128s' do master quando lendo dados do binary log" diff --git a/sql/slave.cc b/sql/slave.cc index fac9ee214c5..b489eb3b45f 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2678,15 +2678,19 @@ Log entry on master is longer than max_allowed_packet (%ld) on \ slave. If the entry is correct, restart the server with a higher value of \ max_allowed_packet", thd->variables.max_allowed_packet); + mi->report(ERROR_LEVEL, ER_NET_PACKET_TOO_LARGE, + ER(ER_NET_PACKET_TOO_LARGE)); goto err; case ER_MASTER_FATAL_ERROR_READING_BINLOG: - sql_print_error(ER(mysql_error_number), mysql_error_number, - mysql_error(mysql)); + mi->report(ERROR_LEVEL, ER_MASTER_FATAL_ERROR_READING_BINLOG, + ER(ER_MASTER_FATAL_ERROR_READING_BINLOG), + mysql_error_number, mysql_error(mysql)); goto err; - case EE_OUTOFMEMORY: - case ER_OUTOFMEMORY: + case ER_OUT_OF_RESOURCES: sql_print_error("\ Stopping slave I/O thread due to out-of-memory error from master"); + mi->report(ERROR_LEVEL, ER_OUT_OF_RESOURCES, + ER(ER_OUT_OF_RESOURCES)); goto err; } if (try_to_reconnect(thd, mysql, mi, &retry_count, suppress_warnings, diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 0ec8d91214c..b8f2e1e39bf 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -623,7 +623,7 @@ impossible position"; */ { log.error=0; - bool read_packet = 0, fatal_error = 0; + bool read_packet = 0; #ifndef DBUG_OFF if (max_binlog_dump_events && !left_events--) @@ -645,7 +645,7 @@ impossible position"; */ pthread_mutex_lock(log_lock); - switch (Log_event::read_log_event(&log, packet, (pthread_mutex_t*)0)) { + switch (error= Log_event::read_log_event(&log, packet, (pthread_mutex_t*) 0)) { case 0: /* we read successfully, so we'll need to send it to the slave */ pthread_mutex_unlock(log_lock); @@ -671,8 +671,8 @@ impossible position"; default: pthread_mutex_unlock(log_lock); - fatal_error = 1; - break; + test_for_non_eof_log_read_errors(error, &errmsg); + goto err; } if (read_packet) @@ -701,12 +701,6 @@ impossible position"; */ } - if (fatal_error) - { - errmsg = "error reading log entry"; - my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; - goto err; - } log.error=0; } } From a31f655d82277fda1b89266e0dab849292434a02 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 18 Sep 2009 12:34:08 +0300 Subject: [PATCH 008/146] Bug #47106: Crash / segfault on adding EXPLAIN to a non-crashing query The fix for bug 46749 removed the check for OUTER_REF_TABLE_BIT and substituted it for a check on the presence of Item_ident::depended_from. Removing it altogether was wrong : OUTER_REF_TABLE_BIT should still be checked in addition to depended_from (because it's not set in all cases and doesn't contradict to the check of depended_from). Fixed by returning the old condition back as a compliment to the new one. --- mysql-test/r/subselect4.result | 31 +++++++++++++++++++++++++++++++ mysql-test/t/subselect4.test | 32 ++++++++++++++++++++++++++++++++ sql/sql_select.cc | 8 ++++---- 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index 68577cb2a4c..e863cbfb7a8 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -27,4 +27,35 @@ SELECT 1; 1 1 DROP TABLE t1,t2,t3; +# +# Bug #47106: Crash / segfault on adding EXPLAIN to a non-crashing +# query +# +CREATE TABLE t1 ( +a INT, +b INT, +PRIMARY KEY (a), +KEY b (b) +); +INSERT INTO t1 VALUES (1, 1), (2, 1); +CREATE TABLE t2 LIKE t1; +INSERT INTO t2 SELECT * FROM t1; +CREATE TABLE t3 LIKE t1; +INSERT INTO t3 SELECT * FROM t1; +# Should not crash. +# Should have 1 impossible where and 2 dependent subqs. +EXPLAIN +SELECT +(SELECT 1 FROM t1,t2 WHERE t2.b > t3.b) +FROM t3 WHERE 1 = 0 GROUP BY 1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 DEPENDENT SUBQUERY t1 index NULL PRIMARY 4 NULL 2 Using index +2 DEPENDENT SUBQUERY t2 index b b 5 NULL 2 Using where; Using index +# should return 0 rows +SELECT +(SELECT 1 FROM t1,t2 WHERE t2.b > t3.b) +FROM t3 WHERE 1 = 0 GROUP BY 1; +(SELECT 1 FROM t1,t2 WHERE t2.b > t3.b) +DROP TABLE t1,t2,t3; End of 5.0 tests. diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index ff4cdf3c439..440eca22828 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -28,5 +28,37 @@ SELECT 1; DROP TABLE t1,t2,t3; +--echo # +--echo # Bug #47106: Crash / segfault on adding EXPLAIN to a non-crashing +--echo # query +--echo # + +CREATE TABLE t1 ( + a INT, + b INT, + PRIMARY KEY (a), + KEY b (b) +); +INSERT INTO t1 VALUES (1, 1), (2, 1); + +CREATE TABLE t2 LIKE t1; +INSERT INTO t2 SELECT * FROM t1; + +CREATE TABLE t3 LIKE t1; +INSERT INTO t3 SELECT * FROM t1; + +--echo # Should not crash. +--echo # Should have 1 impossible where and 2 dependent subqs. +EXPLAIN +SELECT + (SELECT 1 FROM t1,t2 WHERE t2.b > t3.b) +FROM t3 WHERE 1 = 0 GROUP BY 1; + +--echo # should return 0 rows +SELECT + (SELECT 1 FROM t1,t2 WHERE t2.b > t3.b) +FROM t3 WHERE 1 = 0 GROUP BY 1; + +DROP TABLE t1,t2,t3; --echo End of 5.0 tests. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 84b5b61c941..76d6833de5c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3216,12 +3216,12 @@ add_key_equal_fields(KEY_FIELD **key_fields, uint and_level, @retval FALSE it's something else */ -inline static bool +static bool is_local_field (Item *field) { - field= field->real_item(); - return field->type() == Item::FIELD_ITEM && - !((Item_field *)field)->depended_from; + return field->real_item()->type() == Item::FIELD_ITEM + && !(field->used_tables() & OUTER_REF_TABLE_BIT) + && !((Item_field *)field->real_item())->depended_from; } From faacd36a128da1623132e904e6e1ab84bbc61df7 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 18 Sep 2009 16:01:18 +0300 Subject: [PATCH 009/146] Bug#46760: Fast ALTER TABLE no longer works for InnoDB Despite copying the value of the old table's row type we don't always have to mark row type as being specified. Innodb uses this to check if it can do fast ALTER TABLE or not. Fixed by correctly flagging the presence of row_type only when it's actually changed. Added a test case for 39200. --- mysql-test/r/bug46760.result | 43 ++++++++++++++++++++++++++++++++ mysql-test/t/bug46760-master.opt | 2 ++ mysql-test/t/bug46760.test | 38 ++++++++++++++++++++++++++++ sql/handler.h | 9 +++++++ sql/sql_table.cc | 10 ++++++++ 5 files changed, 102 insertions(+) create mode 100644 mysql-test/r/bug46760.result create mode 100644 mysql-test/t/bug46760-master.opt create mode 100644 mysql-test/t/bug46760.test diff --git a/mysql-test/r/bug46760.result b/mysql-test/r/bug46760.result new file mode 100644 index 00000000000..413df050b10 --- /dev/null +++ b/mysql-test/r/bug46760.result @@ -0,0 +1,43 @@ +# +# Bug#46760: Fast ALTER TABLE no longer works for InnoDB +# +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +# By using --enable_info and verifying that number of affected +# rows is 0 we check that this ALTER TABLE is really carried +# out as "fast/online" operation, i.e. without full-blown data +# copying. +# +# I.e. info for the below statement should normally look like: +# +# affected rows: 0 +# info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 10; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT '10' +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t1; +# +# MySQL Bug#39200: optimize table does not recognize +# ROW_FORMAT=COMPRESSED +# +CREATE TABLE t1 (a INT) ROW_FORMAT=compressed; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status Table is already up to date +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED +DROP TABLE t1; +End of 5.1 tests diff --git a/mysql-test/t/bug46760-master.opt b/mysql-test/t/bug46760-master.opt new file mode 100644 index 00000000000..f830d135149 --- /dev/null +++ b/mysql-test/t/bug46760-master.opt @@ -0,0 +1,2 @@ +--innodb-lock-wait-timeout=2 +--innodb-file-per-table diff --git a/mysql-test/t/bug46760.test b/mysql-test/t/bug46760.test new file mode 100644 index 00000000000..f55edbbfa42 --- /dev/null +++ b/mysql-test/t/bug46760.test @@ -0,0 +1,38 @@ +-- source include/have_innodb.inc + +--echo # +--echo # Bug#46760: Fast ALTER TABLE no longer works for InnoDB +--echo # + +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); + +--echo # By using --enable_info and verifying that number of affected +--echo # rows is 0 we check that this ALTER TABLE is really carried +--echo # out as "fast/online" operation, i.e. without full-blown data +--echo # copying. +--echo # +--echo # I.e. info for the below statement should normally look like: +--echo # +--echo # affected rows: 0 +--echo # info: Records: 0 Duplicates: 0 Warnings: 0 + +--enable_info +ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 10; +--disable_info +SHOW CREATE TABLE t1; + +DROP TABLE t1; + +--echo # +--echo # MySQL Bug#39200: optimize table does not recognize +--echo # ROW_FORMAT=COMPRESSED +--echo # + +CREATE TABLE t1 (a INT) ROW_FORMAT=compressed; +SHOW CREATE TABLE t1; +OPTIMIZE TABLE t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--echo End of 5.1 tests diff --git a/sql/handler.h b/sql/handler.h index f759239d66e..fe8f7c437ff 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -913,6 +913,15 @@ typedef struct st_ha_create_information ulong key_block_size; SQL_LIST merge_list; handlerton *db_type; + /** + Row type of the table definition. + + Defaults to ROW_TYPE_DEFAULT for all non-ALTER statements. + For ALTER TABLE defaults to ROW_TYPE_NOT_USED (means "keep the current"). + + Can be changed either explicitly by the parser. + If nothing speficied inherits the value of the original table (if present). + */ enum row_type row_type; uint null_bits; /* NULL bits at start of record */ uint options; /* OR of HA_CREATE_ options */ diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 41e76211dd8..9d929c0d1a3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6656,9 +6656,19 @@ view_err: goto err; } + /* + If this is an ALTER TABLE and no explicit row type specified reuse + the table's row type. + Note : this is the same as if the row type was specified explicitly. + */ if (create_info->row_type == ROW_TYPE_NOT_USED) { + /* ALTER TABLE without explicit row type */ create_info->row_type= table->s->row_type; + } + else + { + /* ALTER TABLE with specific row type */ create_info->used_fields |= HA_CREATE_USED_ROW_FORMAT; } From b2beff7415dc971897023f629b244a403c1b7ee5 Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Mon, 21 Sep 2009 11:58:15 +0200 Subject: [PATCH 010/146] Fix for BUG#35570 "CHECKSUM TABLE unreliable if LINESTRING field (same content/ differen checksum)" The problem was that checksum of GEOMETRY type used memory addresses in the computation, making it un-repeatable thus useless. (This patch is a backport from 6.0 branch) --- mysql-test/r/myisam.result | 19 +++++++++++++++++++ mysql-test/t/myisam.test | 15 +++++++++++++++ sql/sql_table.cc | 10 ++++++++-- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 732b1b260f8..58e2e451a0d 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -2252,4 +2252,23 @@ h+0 d + 0 e g + 0 1 1 3 0 1 1 4 0 DROP TABLE t1; +# +# Test of BUG#35570 CHECKSUM TABLE unreliable if LINESTRING field +# (same content / differen checksum) +# +CREATE TABLE t1 (line LINESTRING NOT NULL) engine=myisam; +INSERT INTO t1 VALUES (GeomFromText("POINT(0 0)")); +checksum table t1; +Table Checksum +test.t1 326284887 +CREATE TABLE t2 (line LINESTRING NOT NULL) engine=myisam; +INSERT INTO t2 VALUES (GeomFromText("POINT(0 0)")); +checksum table t2; +Table Checksum +test.t2 326284887 +CREATE TABLE t3 select * from t1; +checksum table t3; +Table Checksum +test.t3 326284887 +drop table t1,t2,t3; End of 5.1 tests diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index ba6bc05cfea..5de7c997a24 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -1503,5 +1503,20 @@ SELECT h+0, d + 0, e, g + 0 FROM t1; DROP TABLE t1; +--echo # +--echo # Test of BUG#35570 CHECKSUM TABLE unreliable if LINESTRING field +--echo # (same content / differen checksum) +--echo # + +CREATE TABLE t1 (line LINESTRING NOT NULL) engine=myisam; +INSERT INTO t1 VALUES (GeomFromText("POINT(0 0)")); +checksum table t1; +CREATE TABLE t2 (line LINESTRING NOT NULL) engine=myisam; +INSERT INTO t2 VALUES (GeomFromText("POINT(0 0)")); +checksum table t2; +CREATE TABLE t3 select * from t1; +checksum table t3; +drop table t1,t2,t3; + --echo End of 5.1 tests diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9d929c0d1a3..08f3311be9d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7897,8 +7897,14 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, for (uint i= 0; i < t->s->fields; i++ ) { Field *f= t->field[i]; - if ((f->type() == MYSQL_TYPE_BLOB) || - (f->type() == MYSQL_TYPE_VARCHAR)) + enum_field_types field_type= f->type(); + /* + BLOB and VARCHAR have pointers in their field, we must convert + to string; GEOMETRY is implemented on top of BLOB. + */ + if ((field_type == MYSQL_TYPE_BLOB) || + (field_type == MYSQL_TYPE_VARCHAR) || + (field_type == MYSQL_TYPE_GEOMETRY)) { String tmp; f->val_str(&tmp); From 0e7242d895dfe8c428a2101450032ce68a8e5519 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Tue, 22 Sep 2009 08:22:07 -0300 Subject: [PATCH 011/146] Bug#45498: Socket variable not available on Windows The "socket" variable is not available on Windows even though the --socket option can be used to specify the pipe name for local connections that use a named pipe. The solution is to ensure that the variable is always defined. --- mysql-test/r/windows.result | 7 +++++++ mysql-test/t/windows.test | 6 ++++++ sql/set_var.cc | 4 ++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/windows.result b/mysql-test/r/windows.result index 4e0d73ea0eb..d0cdd858d4a 100644 --- a/mysql-test/r/windows.result +++ b/mysql-test/r/windows.result @@ -53,3 +53,10 @@ ERROR HY000: No paths allowed for shared library execute abc; ERROR HY000: No paths allowed for shared library deallocate prepare abc; +# +# Bug#45498: Socket variable not available on Windows +# +SELECT VARIABLE_NAME FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME = 'socket'; +VARIABLE_NAME +SOCKET diff --git a/mysql-test/t/windows.test b/mysql-test/t/windows.test index 89cd2ed19e8..b7d31948d23 100755 --- a/mysql-test/t/windows.test +++ b/mysql-test/t/windows.test @@ -92,3 +92,9 @@ execute abc; execute abc; deallocate prepare abc; +--echo # +--echo # Bug#45498: Socket variable not available on Windows +--echo # + +SELECT VARIABLE_NAME FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES + WHERE VARIABLE_NAME = 'socket'; diff --git a/sql/set_var.cc b/sql/set_var.cc index b64b54fdd29..51c6ca219c6 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -529,11 +529,11 @@ static sys_var_const sys_skip_networking(&vars, "skip_networking", static sys_var_const sys_skip_show_database(&vars, "skip_show_database", OPT_GLOBAL, SHOW_BOOL, (uchar*) &opt_skip_show_db); -#ifdef HAVE_SYS_UN_H + static sys_var_const sys_socket(&vars, "socket", OPT_GLOBAL, SHOW_CHAR_PTR, (uchar*) &mysqld_unix_port); -#endif + #ifdef HAVE_THR_SETCONCURRENCY /* purecov: begin tested */ static sys_var_const sys_thread_concurrency(&vars, "thread_concurrency", From 1e755480943bcabebc7c4a90fcf0783d111c57f6 Mon Sep 17 00:00:00 2001 From: "timothy.smith@sun.com" <> Date: Tue, 22 Sep 2009 20:52:24 +0200 Subject: [PATCH 012/146] Set version number for mysql-5.1.37sp1 release --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index d68a4121642..8013307facc 100644 --- a/configure.in +++ b/configure.in @@ -10,7 +10,7 @@ AC_CANONICAL_SYSTEM # # When changing major version number please also check switch statement # in mysqlbinlog::check_master_version(). -AM_INIT_AUTOMAKE(mysql, 5.1.37) +AM_INIT_AUTOMAKE(mysql, 5.1.37sp1) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10 From fe8304cf93ad0d55d41e6fe68227224a9e31a77d Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Tue, 22 Sep 2009 22:38:25 +0200 Subject: [PATCH 013/146] Backport into build-200909221805-5.1.37sp1 > ------------------------------------------------------------ > revno: 2949.5.6 > revision-id: jperkin@sun.com-20090824091334-6ktgrhq218vl7zq1 > parent: joerg@mysql.com-20090821095644-12woawc4d2d3u7k4 > committer: Jonathan Perkin > branch nick: mysql-5.1-build > timestamp: Mon 2009-08-24 10:13:34 +0100 > message: > Apply changes from mysql-5.1.38-release clone: > > - Add conditionals for bundled zlib and innodb plugin. > - Apply patch from bug#46834 to install the test suite in RPMs. > - Add plugins to RPMs. Disable example plugins. --- support-files/mysql.spec.sh | 41 ++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 778b04b30fe..5b8d7a5922d 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -31,6 +31,20 @@ %{?_with_yassl:%define YASSL_BUILD 1} %{!?_with_yassl:%define YASSL_BUILD 0} +# ---------------------------------------------------------------------- +# use "rpmbuild --with bundled_zlib" or "rpm --define '_with_bundled_zlib 1'" +# (for RPM 3.x) to build using the bundled zlib (off by default) +# ---------------------------------------------------------------------- +%{?_with_bundled_zlib:%define WITH_BUNDLED_ZLIB 1} +%{!?_with_bundled_zlib:%define WITH_BUNDLED_ZLIB 0} + +# ---------------------------------------------------------------------- +# use "rpmbuild --without innodb_plugin" or "rpm --define '_without_innodb_plugin 1'" +# (for RPM 3.x) to not build the innodb plugin (on by default with innodb builds) +# ---------------------------------------------------------------------- +%{?_without_innodb_plugin:%define WITHOUT_INNODB_PLUGIN 1} +%{!?_without_innodb_plugin:%define WITHOUT_INNODB_PLUGIN 0} + # use "rpmbuild --with cluster" or "rpm --define '_with_cluster 1'" (for RPM 3.x) # to build with cluster support (off by default) %{?_with_cluster:%define CLUSTER_BUILD 1} @@ -292,6 +306,9 @@ sh -c "PATH=\"${MYSQL_BUILD_PATH:-$PATH}\" \ --enable-thread-safe-client \ --with-readline \ --with-innodb \ +%if %{WITHOUT_INNODB_PLUGIN} + --without-plugin-innodb_plugin \ +%endif %if %{CLUSTER_BUILD} --with-ndbcluster \ %else @@ -301,8 +318,13 @@ sh -c "PATH=\"${MYSQL_BUILD_PATH:-$PATH}\" \ --with-csv-storage-engine \ --with-blackhole-storage-engine \ --with-federated-storage-engine \ + --without-plugin-daemon_example \ + --without-plugin-example \ --with-partition \ --with-big-tables \ +%if %{WITH_BUNDLED_ZLIB} + --with-zlib-dir=bundled \ +%endif --enable-shared \ " make @@ -426,7 +448,7 @@ install -d $RBR%{_sbindir} # Install all binaries -(cd $MBD && make install DESTDIR=$RBR benchdir_root=%{_datadir}) +(cd $MBD && make install DESTDIR=$RBR testroot=%{_datadir}) # Old packages put shared libs in %{_libdir}/ (not %{_libdir}/mysql), so do # the same here. mv $RBR/%{_libdir}/mysql/*.so* $RBR/%{_libdir}/ @@ -693,6 +715,8 @@ fi %attr(755, root, root) %{_bindir}/resolve_stack_dump %attr(755, root, root) %{_bindir}/resolveip +%attr(755, root, root) %{_libdir}/plugin/*.so* + %attr(755, root, root) %{_sbindir}/mysqld %attr(755, root, root) %{_sbindir}/mysqld-debug %attr(755, root, root) %{_sbindir}/mysqlmanager @@ -818,6 +842,8 @@ fi %{_libdir}/mysql/libvio.a %{_libdir}/mysql/libz.a %{_libdir}/mysql/libz.la +%{_libdir}/plugin/*.a +%{_libdir}/plugin/*.la %files shared %defattr(-, root, root, 0755) @@ -847,6 +873,19 @@ fi # itself - note that they must be ordered by date (important when # merging BK trees) %changelog +* Mon Aug 24 2009 Jonathan Perkin + +- Add conditionals for bundled zlib and innodb plugin + +* Fri Aug 21 2009 Jonathan Perkin + +- Install plugin libraries in appropriate packages. +- Disable example plugins. + +* Thu Aug 20 2009 Jonathan Perkin + +- Update variable used for mysql-test suite location to match source. + * Fri Nov 07 2008 Joerg Bruehe - Correct yesterday's fix, so that it also works for the last flag, From 55b0d9772ebc29966bbabeb15a0acc847e20b9de Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Tue, 22 Sep 2009 22:40:02 +0200 Subject: [PATCH 014/146] Backport into build-200909221805-5.1.37sp1 > ------------------------------------------------------------ > revno: 3019.1.3 > revision-id: ramil@mysql.com-20090714150729-xqv7aicsnoz6epy6 > parent: jimw@mysql.com-20090713191116-c8qxsrjagzbvbytj > committer: Ramil Kalimullin > branch nick: b45998-5.1-bugteam > timestamp: Tue 2009-07-14 20:07:29 +0500 > message: > Fix for bug#45998: database crashes when running > "create as select" (innodb table) > > Problem: code constructing "CREATE TABLE..." statement > doesn't take into account that current database is not set > in some cases. That may lead to a server crash. > > Fix: check if current database is set. --- mysql-test/extra/binlog_tests/binlog.test | 12 ++++++++++++ mysql-test/suite/binlog/r/binlog_row_binlog.result | 11 +++++++++++ sql/sql_show.cc | 2 +- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/mysql-test/extra/binlog_tests/binlog.test b/mysql-test/extra/binlog_tests/binlog.test index d72dc693cee..5d898d41a54 100644 --- a/mysql-test/extra/binlog_tests/binlog.test +++ b/mysql-test/extra/binlog_tests/binlog.test @@ -258,3 +258,15 @@ dec $it; } show master status /* must show new binlog index after rotating */; drop table t3; + +--echo # +--echo # Bug #45998: database crashes when running "create as select" +--echo # +CREATE DATABASE test1; +USE test1; +DROP DATABASE test1; +CREATE TABLE test.t1(a int); +INSERT INTO test.t1 VALUES (1), (2); +CREATE TABLE test.t2 SELECT * FROM test.t1; +USE test; +DROP TABLES t1, t2; diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result index 4baa47db129..f6b5392dbc8 100644 --- a/mysql-test/suite/binlog/r/binlog_row_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result @@ -1298,3 +1298,14 @@ show master status /* must show new binlog index after rotating */; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000002 106 drop table t3; +# +# Bug #45998: database crashes when running "create as select" +# +CREATE DATABASE test1; +USE test1; +DROP DATABASE test1; +CREATE TABLE test.t1(a int); +INSERT INTO test.t1 VALUES (1), (2); +CREATE TABLE test.t2 SELECT * FROM test.t1; +USE test; +DROP TABLES t1, t2; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index d07e951bfd1..a1f6798244e 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1151,7 +1151,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, { const LEX_STRING *const db= table_list->schema_table ? &INFORMATION_SCHEMA_NAME : &table->s->db; - if (strcmp(db->str, thd->db) != 0) + if (!thd->db || strcmp(db->str, thd->db)) { append_identifier(thd, packet, db->str, db->length); packet->append(STRING_WITH_LEN(".")); From 0005020fbeecc69ca4e7bcae82c01f22ccf9d2de Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Tue, 22 Sep 2009 22:41:25 +0200 Subject: [PATCH 015/146] Backport into build-200909221805-5.1.37sp1 > ------------------------------------------------------------ > revno: 3027 > revision-id: ramil@mysql.com-20090715102544-ejid81yz8k39m2fa > parent: anurag.shekhar@sun.com-20090715101345-6n3o8wf8woyaqlwc > committer: Ramil Kalimullin > branch nick: mysql-5.1-bugteam > timestamp: Wed 2009-07-15 15:25:44 +0500 > message: > Addition to #45998 fix, result adjusted. --- mysql-test/suite/binlog/r/binlog_stm_binlog.result | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result index d151e31269f..d05d3ccdb7a 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result @@ -773,3 +773,14 @@ show master status /* must show new binlog index after rotating */; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000002 106 drop table t3; +# +# Bug #45998: database crashes when running "create as select" +# +CREATE DATABASE test1; +USE test1; +DROP DATABASE test1; +CREATE TABLE test.t1(a int); +INSERT INTO test.t1 VALUES (1), (2); +CREATE TABLE test.t2 SELECT * FROM test.t1; +USE test; +DROP TABLES t1, t2; From 868f1fa480fe0de577def21cabc97186b30dbe55 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Tue, 22 Sep 2009 22:43:48 +0200 Subject: [PATCH 016/146] Backport into build-200909221805-5.1.37sp1 > ------------------------------------------------------------ > revno: 3028 [merge] > revision-id: davi.arnaut@sun.com-20090715182250-ru0l00nqqlcfqe8n > parent: ramil@mysql.com-20090715102544-ejid81yz8k39m2fa > parent: kostja@sun.com-20090715170034-kjzpmq3px90pedw7 > committer: Davi Arnaut > branch nick: 44495-5.1 > timestamp: Wed 2009-07-15 15:22:50 -0300 > message: > Bug#44495: Prepared Statement: CALL p() - `thd->protocol == &thd->protocol_text' failed > > Merge Konstantin's patch and add a test case. > ------------------------------------------------------------ > Use --include-merges or -n0 to see merged revisions. --- sql/sql_prepare.cc | 43 ++++++++++++++++++-------------- tests/mysql_client_test.c | 52 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 18 deletions(-) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index e7e821dd4ae..c1839b7220f 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -127,12 +127,12 @@ class Prepared_statement: public Statement public: enum flag_values { - IS_IN_USE= 1 + IS_IN_USE= 1, + IS_SQL_PREPARE= 2 }; THD *thd; Select_fetch_protocol_binary result; - Protocol *protocol; Item_param **param_array; uint param_count; uint last_errno; @@ -148,7 +148,7 @@ public: List& varnames, String *expanded_query); public: - Prepared_statement(THD *thd_arg, Protocol *protocol_arg); + Prepared_statement(THD *thd_arg); virtual ~Prepared_statement(); void setup_set_params(); virtual Query_arena::Type type() const; @@ -156,7 +156,8 @@ public: bool set_name(LEX_STRING *name); inline void close_cursor() { delete cursor; cursor= 0; } inline bool is_in_use() { return flags & (uint) IS_IN_USE; } - inline bool is_protocol_text() const { return protocol == &thd->protocol_text; } + inline bool is_sql_prepare() const { return flags & (uint) IS_SQL_PREPARE; } + void set_sql_prepare() { flags|= (uint) IS_SQL_PREPARE; } bool prepare(const char *packet, uint packet_length); bool execute_loop(String *expanded_query, bool open_cursor, @@ -1358,7 +1359,7 @@ static int mysql_test_select(Prepared_statement *stmt, */ if (unit->prepare(thd, 0, 0)) goto error; - if (!lex->describe && !stmt->is_protocol_text()) + if (!lex->describe && !stmt->is_sql_prepare()) { /* Make copy of item list, as change_columns may change it */ List fields(lex->select_lex.item_list); @@ -1988,7 +1989,7 @@ static bool check_prepared_statement(Prepared_statement *stmt) break; } if (res == 0) - DBUG_RETURN(stmt->is_protocol_text() ? + DBUG_RETURN(stmt->is_sql_prepare() ? FALSE : (send_prep_stmt(stmt, 0) || thd->protocol->flush())); error: DBUG_RETURN(TRUE); @@ -2058,6 +2059,7 @@ static bool init_param_array(Prepared_statement *stmt) void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length) { + Protocol *save_protocol= thd->protocol; Prepared_statement *stmt; bool error; DBUG_ENTER("mysqld_stmt_prepare"); @@ -2067,7 +2069,7 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length) /* First of all clear possible warnings from the previous command */ mysql_reset_thd_for_next_command(thd); - if (! (stmt= new Prepared_statement(thd, &thd->protocol_binary))) + if (! (stmt= new Prepared_statement(thd))) DBUG_VOID_RETURN; /* out of memory: error is set in Sql_alloc */ if (thd->stmt_map.insert(thd, stmt)) @@ -2084,6 +2086,8 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length) sp_cache_flush_obsolete(&thd->sp_proc_cache); sp_cache_flush_obsolete(&thd->sp_func_cache); + thd->protocol= &thd->protocol_binary; + if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),QUERY_PRIOR); @@ -2097,6 +2101,9 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length) /* Statement map deletes statement on erase */ thd->stmt_map.erase(stmt); } + + thd->protocol= save_protocol; + /* check_prepared_statemnt sends the metadata packet in case of success */ DBUG_VOID_RETURN; } @@ -2229,7 +2236,6 @@ void mysql_sql_stmt_prepare(THD *thd) const char *query; uint query_len= 0; DBUG_ENTER("mysql_sql_stmt_prepare"); - DBUG_ASSERT(thd->protocol == &thd->protocol_text); if ((stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name))) { @@ -2247,11 +2253,13 @@ void mysql_sql_stmt_prepare(THD *thd) } if (! (query= get_dynamic_sql_string(lex, &query_len)) || - ! (stmt= new Prepared_statement(thd, &thd->protocol_text))) + ! (stmt= new Prepared_statement(thd))) { DBUG_VOID_RETURN; /* out of memory */ } + stmt->set_sql_prepare(); + /* Set the name first, insert should know that this statement has a name */ if (stmt->set_name(name)) { @@ -2431,6 +2439,7 @@ void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length) String expanded_query; uchar *packet_end= packet + packet_length; Prepared_statement *stmt; + Protocol *save_protocol= thd->protocol; bool open_cursor; DBUG_ENTER("mysqld_stmt_execute"); @@ -2458,7 +2467,9 @@ void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length) open_cursor= test(flags & (ulong) CURSOR_TYPE_READ_ONLY); + thd->protocol= &thd->protocol_binary; stmt->execute_loop(&expanded_query, open_cursor, packet, packet_end); + thd->protocol= save_protocol; /* Close connection socket; for use with client testing (Bug#43560). */ DBUG_EXECUTE_IF("close_conn_after_stmt_execute", vio_close(thd->net.vio);); @@ -2814,12 +2825,11 @@ Select_fetch_protocol_binary::send_data(List &fields) Prepared_statement ****************************************************************************/ -Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg) +Prepared_statement::Prepared_statement(THD *thd_arg) :Statement(NULL, &main_mem_root, INITIALIZED, ++thd_arg->statement_id_counter), thd(thd_arg), result(thd_arg), - protocol(protocol_arg), param_array(0), param_count(0), last_errno(0), @@ -3288,7 +3298,9 @@ Prepared_statement::reprepare() bool cur_db_changed; bool error; - Prepared_statement copy(thd, &thd->protocol_text); + Prepared_statement copy(thd); + + copy.set_sql_prepare(); /* To suppress sending metadata to the client. */ status_var_increment(thd->status_var.com_stmt_reprepare); @@ -3346,7 +3358,7 @@ bool Prepared_statement::validate_metadata(Prepared_statement *copy) return FALSE -- the metadata of the original SELECT, if any, has not been sent to the client. */ - if (is_protocol_text() || lex->describe) + if (is_sql_prepare() || lex->describe) return FALSE; if (lex->select_lex.item_list.elements != @@ -3409,7 +3421,6 @@ Prepared_statement::swap_prepared_statement(Prepared_statement *copy) DBUG_ASSERT(thd == copy->thd); last_error[0]= '\0'; last_errno= 0; - /* Do not swap protocols, the copy always has protocol_text */ } @@ -3550,8 +3561,6 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) thd->stmt_arena= this; reinit_stmt_before_use(thd, lex); - thd->protocol= protocol; /* activate stmt protocol */ - /* Go! */ if (open_cursor) @@ -3582,8 +3591,6 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) if (cur_db_changed) mysql_change_db(thd, &saved_cur_db_name, TRUE); - thd->protocol= &thd->protocol_text; /* use normal protocol */ - /* Assert that if an error, no cursor is open */ DBUG_ASSERT(! (error && cursor)); diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index b836293442a..c51e3984fc9 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -17940,6 +17940,57 @@ static void test_bug41078(void) DBUG_VOID_RETURN; } + +/** + Bug#44495: Prepared Statement: + CALL p() - `thd->protocol == &thd->protocol_text' failed +*/ + +static void test_bug44495() +{ + int rc; + MYSQL con; + MYSQL_STMT *stmt; + + DBUG_ENTER("test_bug44495"); + myheader("test_44495"); + + rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE PROCEDURE p1(IN arg VARCHAR(25))" + " BEGIN SET @stmt = CONCAT('SELECT \"', arg, '\"');" + " PREPARE ps1 FROM @stmt;" + " EXECUTE ps1;" + " DROP PREPARE ps1;" + "END;"); + myquery(rc); + + DIE_UNLESS(mysql_init(&con)); + + DIE_UNLESS(mysql_real_connect(&con, opt_host, opt_user, opt_password, + current_db, opt_port, opt_unix_socket, + CLIENT_MULTI_RESULTS)); + + stmt= mysql_simple_prepare(&con, "CALL p1('abc')"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + + mysql_stmt_close(stmt); + + mysql_close(&con); + + rc= mysql_query(mysql, "DROP PROCEDURE p1"); + myquery(rc); + + DBUG_VOID_RETURN; +} + /* Read and parse arguments and MySQL options from my.cnf */ @@ -18255,6 +18306,7 @@ static struct my_tests_st my_tests[]= { { "test_bug36326", test_bug36326 }, #endif { "test_bug41078", test_bug41078 }, + { "test_bug44495", test_bug44495 }, { 0, 0 } }; From a96a92d67bc24760d22412e90a0a8924791cf8e8 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Tue, 22 Sep 2009 22:52:30 +0200 Subject: [PATCH 017/146] Backport into build-200909221805-5.1.37sp1 > ------------------------------------------------------------ > revno: 3044.1.1 > revision-id: kristofer.pettersson@sun.com-20090729200708-cb0td7n9r5md0aa0 > parent: davi.arnaut@sun.com-20090728195938-qabe9ldm2l4k8xns > committer: Kristofer Pettersson > branch nick: mysql-5.1-bugteam > timestamp: Wed 2009-07-29 22:07:08 +0200 > message: > Bug#44521 Executing a stored procedure as a prepared statement can sometimes cause > an assertion in a debug build. > > The reason is that the C API doesn't support multiple result sets for prepared > statements and attempting to execute a stored routine which returns multiple result > sets sometimes lead to a network error. The network error sets the diagnostic area > prematurely which later leads to the assert when an attempt is made to set a second > server state. > > This patch fixes the issue by changing the scope of the error code returned by > sp_instr_stmt::execute() to include any error which happened during the execution. > To assure that Diagnostic_area::is_sent really mean that the message was sent all > network related functions are checked for return status. --- libmysqld/lib_sql.cc | 32 ++++--- mysql-test/r/sp_notembedded.result | 22 +++++ mysql-test/t/sp_notembedded.test | 36 ++++++++ sql/protocol.cc | 130 ++++++++++++++++++++--------- sql/protocol.h | 2 +- sql/sp_head.cc | 4 +- 6 files changed, 171 insertions(+), 55 deletions(-) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index d644c45a66a..4034414cd12 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -803,11 +803,11 @@ MYSQL_DATA *THD::alloc_new_dataset() */ static -void +bool write_eof_packet(THD *thd, uint server_status, uint total_warn_count) { if (!thd->mysql) // bootstrap file handling - return; + return FALSE; /* The following test should never be true, but it's better to do it because if 'is_fatal_error' is set the server is not going to execute @@ -822,6 +822,7 @@ write_eof_packet(THD *thd, uint server_status, uint total_warn_count) */ thd->cur_data->embedded_info->warning_count= (thd->spcont ? 0 : min(total_warn_count, 65535)); + return FALSE; } @@ -1032,31 +1033,34 @@ bool Protocol_binary::write() @sa Server implementation of net_send_ok in protocol.cc for description of the arguments. - @return The function does not return errors. + @return + @retval TRUE An error occurred + @retval FALSE Success */ -void +bool net_send_ok(THD *thd, uint server_status, uint total_warn_count, ha_rows affected_rows, ulonglong id, const char *message) { DBUG_ENTER("emb_net_send_ok"); MYSQL_DATA *data; + bool error; MYSQL *mysql= thd->mysql; if (!mysql) // bootstrap file handling - DBUG_VOID_RETURN; + DBUG_RETURN(FALSE); if (!(data= thd->alloc_new_dataset())) - return; + return TRUE; data->embedded_info->affected_rows= affected_rows; data->embedded_info->insert_id= id; if (message) strmake(data->embedded_info->info, message, sizeof(data->embedded_info->info)-1); - write_eof_packet(thd, server_status, total_warn_count); + error= write_eof_packet(thd, server_status, total_warn_count); thd->cur_data= 0; - DBUG_VOID_RETURN; + DBUG_RETURN(error); } @@ -1065,18 +1069,21 @@ net_send_ok(THD *thd, @sa net_send_ok - @return This function does not return errors. + @return + @retval TRUE An error occurred + @retval FALSE Success */ -void +bool net_send_eof(THD *thd, uint server_status, uint total_warn_count) { - write_eof_packet(thd, server_status, total_warn_count); + bool error= write_eof_packet(thd, server_status, total_warn_count); thd->cur_data= 0; + return error; } -void net_send_error_packet(THD *thd, uint sql_errno, const char *err) +bool net_send_error_packet(THD *thd, uint sql_errno, const char *err) { MYSQL_DATA *data= thd->cur_data ? thd->cur_data : thd->alloc_new_dataset(); struct embedded_query_result *ei= data->embedded_info; @@ -1086,6 +1093,7 @@ void net_send_error_packet(THD *thd, uint sql_errno, const char *err) strmov(ei->sqlstate, mysql_errno_to_sqlstate(sql_errno)); ei->server_status= thd->server_status; thd->cur_data= 0; + return FALSE; } diff --git a/mysql-test/r/sp_notembedded.result b/mysql-test/r/sp_notembedded.result index c6641e673ee..831616f491b 100644 --- a/mysql-test/r/sp_notembedded.result +++ b/mysql-test/r/sp_notembedded.result @@ -249,3 +249,25 @@ DROP PROCEDURE p1; DELETE FROM mysql.user WHERE User='mysqltest_1'; FLUSH PRIVILEGES; set @@global.concurrent_insert= @old_concurrent_insert; +# +# Bug#44521 Prepared Statement: CALL p() - crashes: `! thd->main_da.is_sent' failed et.al. +# +SELECT GET_LOCK('Bug44521', 0); +GET_LOCK('Bug44521', 0) +1 +** Connection con1 +CREATE PROCEDURE p() +BEGIN +SELECT 1; +SELECT GET_LOCK('Bug44521', 100); +SELECT 2; +END$ +CALL p();; +** Default connection +SELECT RELEASE_LOCK('Bug44521'); +RELEASE_LOCK('Bug44521') +1 +DROP PROCEDURE p; +# ------------------------------------------------------------------ +# -- End of 5.1 tests +# ------------------------------------------------------------------ diff --git a/mysql-test/t/sp_notembedded.test b/mysql-test/t/sp_notembedded.test index ecb37c1299c..f593e184ad2 100644 --- a/mysql-test/t/sp_notembedded.test +++ b/mysql-test/t/sp_notembedded.test @@ -380,3 +380,39 @@ set @@global.concurrent_insert= @old_concurrent_insert; # Wait till all disconnects are completed --source include/wait_until_count_sessions.inc + +--echo # +--echo # Bug#44521 Prepared Statement: CALL p() - crashes: `! thd->main_da.is_sent' failed et.al. +--echo # +SELECT GET_LOCK('Bug44521', 0); +--connect (con1,localhost,root,,) +--echo ** Connection con1 +delimiter $; +CREATE PROCEDURE p() +BEGIN + SELECT 1; + SELECT GET_LOCK('Bug44521', 100); + SELECT 2; +END$ +delimiter ;$ +--send CALL p(); +--connection default +--echo ** Default connection +let $wait_condition= + SELECT count(*) = 1 FROM information_schema.processlist + WHERE state = "User lock" AND info = "SELECT GET_LOCK('Bug44521', 100)"; +--source include/wait_condition.inc +let $conid = + `SELECT id FROM information_schema.processlist + WHERE state = "User lock" AND info = "SELECT GET_LOCK('Bug44521', 100)"`; +dirty_close con1; +SELECT RELEASE_LOCK('Bug44521'); +let $wait_condition= + SELECT count(*) = 0 FROM information_schema.processlist + WHERE id = $conid; +--source include/wait_condition.inc +DROP PROCEDURE p; + +--echo # ------------------------------------------------------------------ +--echo # -- End of 5.1 tests +--echo # ------------------------------------------------------------------ diff --git a/sql/protocol.cc b/sql/protocol.cc index 16975c68a54..4f69a0fdb52 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -29,11 +29,11 @@ static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024; /* Declared non-static only because of the embedded library. */ -void net_send_error_packet(THD *thd, uint sql_errno, const char *err); -void net_send_ok(THD *, uint, uint, ha_rows, ulonglong, const char *); -void net_send_eof(THD *thd, uint server_status, uint total_warn_count); +bool net_send_error_packet(THD *thd, uint sql_errno, const char *err); +bool net_send_ok(THD *, uint, uint, ha_rows, ulonglong, const char *); +bool net_send_eof(THD *thd, uint server_status, uint total_warn_count); #ifndef EMBEDDED_LIBRARY -static void write_eof_packet(THD *thd, NET *net, +static bool write_eof_packet(THD *thd, NET *net, uint server_status, uint total_warn_count); #endif @@ -70,8 +70,17 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length) For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's critical that every error that can be intercepted is issued in one place only, my_message_sql. + + @param thd Thread handler + @param sql_errno The error code to send + @param err A pointer to the error message + + @return + @retval FALSE The message was sent to the client + @retval TRUE An error occurred and the message wasn't sent properly */ -void net_send_error(THD *thd, uint sql_errno, const char *err) + +bool net_send_error(THD *thd, uint sql_errno, const char *err) { DBUG_ENTER("net_send_error"); @@ -80,6 +89,7 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) DBUG_ASSERT(err && err[0]); DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno, err)); + bool error; /* It's one case when we can push an error even though there @@ -90,11 +100,11 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) /* Abort multi-result sets */ thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; - net_send_error_packet(thd, sql_errno, err); + error= net_send_error_packet(thd, sql_errno, err); thd->main_da.can_overwrite_status= FALSE; - DBUG_VOID_RETURN; + DBUG_RETURN(error); } /** @@ -113,25 +123,33 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) Is not stored if no message. @param thd Thread handler + @param server_status The server status + @param total_warn_count Total number of warnings @param affected_rows Number of rows changed by statement @param id Auto_increment id for first row (if used) @param message Message to send to the client (Used by mysql_status) + + @return + @retval FALSE The message was successfully sent + @retval TRUE An error occurred and the messages wasn't sent properly + */ #ifndef EMBEDDED_LIBRARY -void +bool net_send_ok(THD *thd, uint server_status, uint total_warn_count, ha_rows affected_rows, ulonglong id, const char *message) { NET *net= &thd->net; uchar buff[MYSQL_ERRMSG_SIZE+10],*pos; + bool error= FALSE; DBUG_ENTER("my_ok"); if (! net->vio) // hack for re-parsing queries { DBUG_PRINT("info", ("vio present: NO")); - DBUG_VOID_RETURN; + DBUG_RETURN(FALSE); } buff[0]=0; // No fields @@ -162,13 +180,14 @@ net_send_ok(THD *thd, if (message && message[0]) pos= net_store_data(pos, (uchar*) message, strlen(message)); - VOID(my_net_write(net, buff, (size_t) (pos-buff))); - VOID(net_flush(net)); + error= my_net_write(net, buff, (size_t) (pos-buff)); + if (!error) + error= net_flush(net); thd->main_da.can_overwrite_status= FALSE; DBUG_PRINT("info", ("OK sent, so no more error sending allowed")); - DBUG_VOID_RETURN; + DBUG_RETURN(error); } static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */ @@ -188,37 +207,54 @@ static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */ client. @param thd Thread handler - @param no_flush Set to 1 if there will be more data to the client, - like in send_fields(). + @param server_status The server status + @param total_warn_count Total number of warnings + + @return + @retval FALSE The message was successfully sent + @retval TRUE An error occurred and the message wasn't sent properly */ -void +bool net_send_eof(THD *thd, uint server_status, uint total_warn_count) { NET *net= &thd->net; + bool error= FALSE; DBUG_ENTER("net_send_eof"); /* Set to TRUE if no active vio, to work well in case of --init-file */ if (net->vio != 0) { thd->main_da.can_overwrite_status= TRUE; - write_eof_packet(thd, net, server_status, total_warn_count); - VOID(net_flush(net)); + error= write_eof_packet(thd, net, server_status, total_warn_count); + if (!error) + error= net_flush(net); thd->main_da.can_overwrite_status= FALSE; DBUG_PRINT("info", ("EOF sent, so no more error sending allowed")); } - DBUG_VOID_RETURN; + DBUG_RETURN(error); } /** Format EOF packet according to the current protocol and write it to the network output buffer. + + @param thd The thread handler + @param net The network handler + @param server_status The server status + @param total_warn_count The number of warnings + + + @return + @retval FALSE The message was sent successfully + @retval TRUE An error occurred and the messages wasn't sent properly */ -static void write_eof_packet(THD *thd, NET *net, +static bool write_eof_packet(THD *thd, NET *net, uint server_status, uint total_warn_count) { + bool error; if (thd->client_capabilities & CLIENT_PROTOCOL_41) { uchar buff[5]; @@ -237,10 +273,12 @@ static void write_eof_packet(THD *thd, NET *net, if (thd->is_fatal_error) server_status&= ~SERVER_MORE_RESULTS_EXISTS; int2store(buff + 3, server_status); - VOID(my_net_write(net, buff, 5)); + error= my_net_write(net, buff, 5); } else - VOID(my_net_write(net, eof_buff, 1)); + error= my_net_write(net, eof_buff, 1); + + return error; } /** @@ -261,7 +299,17 @@ bool send_old_password_request(THD *thd) } -void net_send_error_packet(THD *thd, uint sql_errno, const char *err) +/** + @param thd Thread handler + @param sql_errno The error code to send + @param err A pointer to the error message + + @return + @retval FALSE The message was successfully sent + @retval TRUE An error occurred and the messages wasn't sent properly +*/ + +bool net_send_error_packet(THD *thd, uint sql_errno, const char *err) { NET *net= &thd->net; uint length; @@ -279,7 +327,7 @@ void net_send_error_packet(THD *thd, uint sql_errno, const char *err) /* In bootstrap it's ok to print on stderr */ fprintf(stderr,"ERROR: %d %s\n",sql_errno,err); } - DBUG_VOID_RETURN; + DBUG_RETURN(FALSE); } if (net->return_errno) @@ -301,9 +349,8 @@ void net_send_error_packet(THD *thd, uint sql_errno, const char *err) length=(uint) strlen(err); set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); } - VOID(net_write_command(net,(uchar) 255, (uchar*) "", 0, (uchar*) err, + DBUG_RETURN(net_write_command(net,(uchar) 255, (uchar*) "", 0, (uchar*) err, length)); - DBUG_VOID_RETURN; } #endif /* EMBEDDED_LIBRARY */ @@ -389,36 +436,39 @@ void net_end_statement(THD *thd) if (thd->main_da.is_sent) return; + bool error= FALSE; + switch (thd->main_da.status()) { case Diagnostics_area::DA_ERROR: /* The query failed, send error to log and abort bootstrap. */ - net_send_error(thd, - thd->main_da.sql_errno(), - thd->main_da.message()); + error= net_send_error(thd, + thd->main_da.sql_errno(), + thd->main_da.message()); break; case Diagnostics_area::DA_EOF: - net_send_eof(thd, - thd->main_da.server_status(), - thd->main_da.total_warn_count()); + error= net_send_eof(thd, + thd->main_da.server_status(), + thd->main_da.total_warn_count()); break; case Diagnostics_area::DA_OK: - net_send_ok(thd, - thd->main_da.server_status(), - thd->main_da.total_warn_count(), - thd->main_da.affected_rows(), - thd->main_da.last_insert_id(), - thd->main_da.message()); + error= net_send_ok(thd, + thd->main_da.server_status(), + thd->main_da.total_warn_count(), + thd->main_da.affected_rows(), + thd->main_da.last_insert_id(), + thd->main_da.message()); break; case Diagnostics_area::DA_DISABLED: break; case Diagnostics_area::DA_EMPTY: default: DBUG_ASSERT(0); - net_send_ok(thd, thd->server_status, thd->total_warn_count, - 0, 0, NULL); + error= net_send_ok(thd, thd->server_status, thd->total_warn_count, + 0, 0, NULL); break; } - thd->main_da.is_sent= TRUE; + if (!error) + thd->main_da.is_sent= TRUE; } diff --git a/sql/protocol.h b/sql/protocol.h index a4770e9b6e3..251ba6fbc33 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -173,7 +173,7 @@ public: }; void send_warning(THD *thd, uint sql_errno, const char *err=0); -void net_send_error(THD *thd, uint sql_errno=0, const char *err=0); +bool net_send_error(THD *thd, uint sql_errno=0, const char *err=0); void net_end_statement(THD *thd); bool send_old_password_request(THD *thd); uchar *net_store_data(uchar *to,const uchar *from, size_t length); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 8a8a5b06cc1..f65c3455944 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1249,7 +1249,7 @@ sp_head::execute(THD *thd) */ if (thd->prelocked_mode == NON_PRELOCKED) thd->user_var_events_alloc= thd->mem_root; - + err_status= i->execute(thd, &ip); if (i->free_list) @@ -2865,7 +2865,7 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) if (!thd->is_error()) thd->main_da.reset_diagnostics_area(); } - DBUG_RETURN(res); + DBUG_RETURN(res || thd->is_error()); } From 35bac688bea4f23af8db1fec89e71c063af67c89 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Tue, 22 Sep 2009 22:54:06 +0200 Subject: [PATCH 018/146] Backport into build-200909221805-5.1.37sp1 > ------------------------------------------------------------ > revno: 3044.1.3 > revision-id: kristofer.pettersson@sun.com-20090729224404-hwevly1cbi7gojf0 > parent: kristofer.pettersson@sun.com-20090729202743-tp9ihd5xavq8eguw > committer: Kristofer Pettersson > branch nick: mysql-5.1-bugteam > timestamp: Thu 2009-07-30 00:44:04 +0200 > message: > Bug#44521 Prepared Statement: CALL p() - crashes: `! thd->main_da.is_sent' failed et.al. > > Fixed wrong prototype declaration which cased build failure on solaris. --- libmysqld/emb_qcache.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmysqld/emb_qcache.h b/libmysqld/emb_qcache.h index 67413739f2c..ecf91487667 100644 --- a/libmysqld/emb_qcache.h +++ b/libmysqld/emb_qcache.h @@ -79,4 +79,4 @@ public: uint emb_count_querycache_size(THD *thd); int emb_load_querycache_result(THD *thd, Querycache_stream *src); void emb_store_querycache_result(Querycache_stream *dst, THD* thd); -void net_send_eof(THD *thd, uint server_status, uint total_warn_count); +bool net_send_eof(THD *thd, uint server_status, uint total_warn_count); From 191c0c0b6ddf82e97f416f188392c4d7289b3878 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Tue, 22 Sep 2009 22:55:02 +0200 Subject: [PATCH 019/146] Backport into build-200909221805-5.1.37sp1 > ------------------------------------------------------------ > revno: 3059 [merge] > revision-id: martin.hansson@sun.com-20090810140851-aw5peehzdxi4gjja > parent: iggy@mysql.com-20090806145453-ion37sfdsldwwjrj > parent: martin.hansson@sun.com-20090807115140-7fn6wjx0mrui7zl5 > committer: Martin Hansson > branch nick: 5.1bt > timestamp: Mon 2009-08-10 16:08:51 +0200 > message: > Merge > ------------------------------------------------------------ > Use --include-merges or -n0 to see merged revisions. --- mysql-test/r/order_by.result | 57 ++++++++++++++++++++++++++++++++++++ mysql-test/t/order_by.test | 41 ++++++++++++++++++++++++++ sql/sql_select.cc | 25 ++++++++-------- sql/table.h | 8 ++++- 4 files changed, 118 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index dc29c5ec226..306fce1f3c2 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -1500,3 +1500,60 @@ id1 15 16 DROP TABLE t1; +CREATE TABLE t1 ( +a INT, +b INT NOT NULL, +c char(100), +KEY (b, c), +KEY (b, a, c) +) +DEFAULT CHARSET = utf8; +INSERT INTO t1 VALUES +(1, 1, 1), +(2, 2, 2), +(3, 3, 3), +(4, 4, 4), +(5, 5, 5), +(6, 6, 6), +(7, 7, 7), +(8, 8, 8), +(9, 9, 9); +INSERT INTO t1 SELECT a + 10, b, c FROM t1; +INSERT INTO t1 SELECT a + 20, b, c FROM t1; +INSERT INTO t1 SELECT a + 40, b, c FROM t1; +INSERT INTO t1 SELECT a + 80, b, c FROM t1; +INSERT INTO t1 SELECT a + 160, b, c FROM t1; +INSERT INTO t1 SELECT a + 320, b, c FROM t1; +INSERT INTO t1 SELECT a + 640, b, c FROM t1; +INSERT INTO t1 SELECT a + 1280, b, c FROM t1 LIMIT 80; +EXPLAIN +SELECT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 9; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range b,b_2 b 4 NULL 226 Using where +SELECT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 9; +a +2071 +2061 +2051 +2041 +2031 +2021 +2011 +2001 +1991 +EXPLAIN +SELECT DISTINCT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 0, 9; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range b,b_2 b 4 NULL 226 Using where; Using temporary +SELECT DISTINCT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 0, 9; +a +2071 +2061 +2051 +2041 +2031 +2021 +2011 +2001 +1991 +DROP TABLE t1; diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index f09c1aa7bd4..cca1e3209cc 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -1361,3 +1361,44 @@ DROP TABLE t1; +# +# Bug#46454: MySQL wrong index optimisation leads to incorrect result & crashes +# +CREATE TABLE t1 ( + a INT, + b INT NOT NULL, + c char(100), + KEY (b, c), + KEY (b, a, c) +) +DEFAULT CHARSET = utf8; + +INSERT INTO t1 VALUES +(1, 1, 1), +(2, 2, 2), +(3, 3, 3), +(4, 4, 4), +(5, 5, 5), +(6, 6, 6), +(7, 7, 7), +(8, 8, 8), +(9, 9, 9); + +INSERT INTO t1 SELECT a + 10, b, c FROM t1; +INSERT INTO t1 SELECT a + 20, b, c FROM t1; +INSERT INTO t1 SELECT a + 40, b, c FROM t1; +INSERT INTO t1 SELECT a + 80, b, c FROM t1; +INSERT INTO t1 SELECT a + 160, b, c FROM t1; +INSERT INTO t1 SELECT a + 320, b, c FROM t1; +INSERT INTO t1 SELECT a + 640, b, c FROM t1; +INSERT INTO t1 SELECT a + 1280, b, c FROM t1 LIMIT 80; + +EXPLAIN +SELECT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 9; +SELECT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 9; + +EXPLAIN +SELECT DISTINCT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 0, 9; +SELECT DISTINCT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 0, 9; + +DROP TABLE t1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 401745bd9b8..b40ab8f71f4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6141,7 +6141,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) } } - if (tmp || !cond) + if (tmp || !cond || tab->type == JT_REF) { DBUG_EXECUTE("where",print_where(tmp,tab->table->alias, QT_ORDINARY);); SQL_SELECT *sel= tab->select= ((SQL_SELECT*) @@ -6155,7 +6155,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) The guard will turn the predicate on only after the first match for outer tables is encountered. */ - if (cond) + if (cond && tmp) { /* Because of QUICK_GROUP_MIN_MAX_SELECT there may be a select without @@ -12931,6 +12931,8 @@ find_field_in_item_list (Field *field, void *data) The index must cover all fields in , or it will not be considered. + @param no_changes No changes will be made to the query plan. + @todo - sergeyp: Results of all index merge selects actually are ordered by clustered PK values. @@ -13265,6 +13267,15 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, } if (!no_changes) { + /* + If ref_key used index tree reading only ('Using index' in EXPLAIN), + and best_key doesn't, then revert the decision. + */ + if (!table->covering_keys.is_set(best_key) && table->key_read) + { + table->key_read= 0; + table->file->extra(HA_EXTRA_NO_KEYREAD); + } if (!quick_created) { tab->index= best_key; @@ -13281,16 +13292,6 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, table->key_read=1; table->file->extra(HA_EXTRA_KEYREAD); } - else if (table->key_read) - { - /* - Clear the covering key read flags that might have been - previously set for some key other than the current best_key. - */ - table->key_read= 0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } - table->file->ha_index_or_rnd_end(); if (join->select_options & SELECT_DESCRIBE) { diff --git a/sql/table.h b/sql/table.h index cb53013cd59..1d2ed294833 100644 --- a/sql/table.h +++ b/sql/table.h @@ -753,7 +753,13 @@ struct st_table { */ my_bool force_index; my_bool distinct,const_table,no_rows; - my_bool key_read, no_keyread; + + /** + If set, the optimizer has found that row retrieval should access index + tree only. + */ + my_bool key_read; + my_bool no_keyread; /* Placeholder for an open table which prevents other connections from taking name-locks on this table. Typically used with From f69f4c09b272cdf8044504b6591f72dcc94b5e74 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Tue, 22 Sep 2009 22:59:11 +0200 Subject: [PATCH 020/146] Backport into build-200909221805-5.1.37sp1 > ------------------------------------------------------------ > revno: 3068 > revision-id: ramil@mysql.com-20090813194928-3djdqvpock0pxhgp > parent: li-bing.song@sun.com-20090813024857-1emgf5lhj0zikoj8 > committer: Ramil Kalimullin > branch nick: mysql-5.1-bugteam > timestamp: Fri 2009-08-14 00:49:28 +0500 > message: > Fix for bug #46614: Assertion in show_create_trigger() > on SHOW CREATE TRIGGER + MERGE table > > Problem: SHOW CREATE TRIGGER erroneously relies on fact > that we have the only underlying table for a trigger > (wrong for merge tables). > > Fix: remove erroneous assert(). --- mysql-test/r/merge.result | 12 ++++++++++++ mysql-test/t/merge.test | 11 +++++++++++ sql/sql_show.cc | 2 -- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index bf9108459d7..d1d0370e528 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -2141,4 +2141,16 @@ SELECT * FROM m1; c1 DROP TABLE m1; DROP TABLE t1; +# +# Bug #46614: Assertion in show_create_trigger() +# +CREATE TABLE t1(a int); +CREATE TABLE t2(a int); +CREATE TABLE t3(a int) ENGINE = MERGE UNION(t1, t2); +CREATE TRIGGER tr1 AFTER INSERT ON t3 FOR EACH ROW CALL foo(); +SHOW CREATE TRIGGER tr1; +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +tr1 CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER INSERT ON t3 FOR EACH ROW CALL foo() latin1 latin1_swedish_ci latin1_swedish_ci +DROP TRIGGER tr1; +DROP TABLE t1, t2, t3; End of 5.1 tests diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index 8760876b7ee..95d1100d4d7 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -1555,4 +1555,15 @@ SELECT * FROM m1; DROP TABLE m1; DROP TABLE t1; +--echo # +--echo # Bug #46614: Assertion in show_create_trigger() +--echo # +CREATE TABLE t1(a int); +CREATE TABLE t2(a int); +CREATE TABLE t3(a int) ENGINE = MERGE UNION(t1, t2); +CREATE TRIGGER tr1 AFTER INSERT ON t3 FOR EACH ROW CALL foo(); +SHOW CREATE TRIGGER tr1; +DROP TRIGGER tr1; +DROP TABLE t1, t2, t3; + --echo End of 5.1 tests diff --git a/sql/sql_show.cc b/sql/sql_show.cc index a1f6798244e..4b028688373 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -7098,8 +7098,6 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name) /* Perform closing actions and return error status. */ } - DBUG_ASSERT(num_tables == 1); - Table_triggers_list *triggers= lst->table->triggers; if (!triggers) From 7d520f5104a0e5f05525eaa0453da64f88b0823c Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Tue, 22 Sep 2009 23:00:30 +0200 Subject: [PATCH 021/146] Backport into build-200909221805-5.1.37sp1 > ------------------------------------------------------------ > revno: 3075 > revision-id: ramil@mysql.com-20090821055535-a5aeas33epokjjnp > parent: joro@sun.com-20090820141122-gq6eyozybvar4o4s > committer: Ramil Kalimullin > branch nick: mysql-5.1-bugteam > timestamp: Fri 2009-08-21 10:55:35 +0500 > message: > Fix for bug #46456 [Ver->Prg]: HANDLER OPEN + TRUNCATE + DROP > (temporary) TABLE, crash > > Problem: if one has an open "HANDLER t1", further "TRUNCATE t1" > doesn't close the handler and leaves handler table hash in an > inconsistent state, that may lead to a server crash. > > Fix: TRUNCATE should implicitly close all open handlers. > > Doc. request: the fact should be described in the manual accordingly. --- mysql-test/r/handler_myisam.result | 16 ++++++++++++++++ mysql-test/t/handler_myisam.test | 19 +++++++++++++++++++ sql/sql_delete.cc | 4 ++++ 3 files changed, 39 insertions(+) diff --git a/mysql-test/r/handler_myisam.result b/mysql-test/r/handler_myisam.result index dde6a4586bc..90a1bdfe6be 100644 --- a/mysql-test/r/handler_myisam.result +++ b/mysql-test/r/handler_myisam.result @@ -741,3 +741,19 @@ USE information_schema; HANDLER COLUMNS OPEN; ERROR HY000: Incorrect usage of HANDLER OPEN and information_schema USE test; +# +# BUG #46456: HANDLER OPEN + TRUNCATE + DROP (temporary) TABLE, crash +# +CREATE TABLE t1 AS SELECT 1 AS f1; +HANDLER t1 OPEN; +TRUNCATE t1; +HANDLER t1 READ FIRST; +ERROR 42S02: Unknown table 't1' in HANDLER +DROP TABLE t1; +CREATE TEMPORARY TABLE t1 AS SELECT 1 AS f1; +HANDLER t1 OPEN; +TRUNCATE t1; +HANDLER t1 READ FIRST; +ERROR 42S02: Unknown table 't1' in HANDLER +DROP TABLE t1; +End of 5.1 tests diff --git a/mysql-test/t/handler_myisam.test b/mysql-test/t/handler_myisam.test index 644c28de5b2..da02a90af0f 100644 --- a/mysql-test/t/handler_myisam.test +++ b/mysql-test/t/handler_myisam.test @@ -19,3 +19,22 @@ let $other_engine_type= MEMORY; let $other_handler_engine_type= MyISAM; --source include/handler.inc + +--echo # +--echo # BUG #46456: HANDLER OPEN + TRUNCATE + DROP (temporary) TABLE, crash +--echo # +CREATE TABLE t1 AS SELECT 1 AS f1; +HANDLER t1 OPEN; +TRUNCATE t1; +--error ER_UNKNOWN_TABLE +HANDLER t1 READ FIRST; +DROP TABLE t1; + +CREATE TEMPORARY TABLE t1 AS SELECT 1 AS f1; +HANDLER t1 OPEN; +TRUNCATE t1; +--error ER_UNKNOWN_TABLE +HANDLER t1 READ FIRST; +DROP TABLE t1; + +--echo End of 5.1 tests diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 677098d275a..c56e783e03f 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -1058,6 +1058,10 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) DBUG_ENTER("mysql_truncate"); bzero((char*) &create_info,sizeof(create_info)); + + /* Remove tables from the HANDLER's hash. */ + mysql_ha_rm_tables(thd, table_list, FALSE); + /* If it is a temporary table, close and regenerate it */ if (!dont_send_ok && (table= find_temporary_table(thd, table_list))) { From 55baa0c54dc52422e5361dc99648c091294414fe Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Tue, 22 Sep 2009 23:01:19 +0200 Subject: [PATCH 022/146] Backport into build-200909221805-5.1.37sp1 > ------------------------------------------------------------ > revno: 3085 [merge] > revision-id: sergey.glukhov@sun.com-20090827105925-j56pdghdzb8nlw3p > parent: alfranio.correia@sun.com-20090827093227-9exafl3k6362bvq7 > parent: sergey.glukhov@sun.com-20090827102219-sgjz0v5t1rfccs14 > committer: Sergey Glukhov > branch nick: mysql-5.1-bugteam > timestamp: Thu 2009-08-27 15:59:25 +0500 > message: > 5.0-bugteam->5.1-bugteam merge > ------------------------------------------------------------ > Use --include-merges or -n0 to see merged revisions. --- mysql-test/r/analyse.result | 9 ++++++--- mysql-test/r/subselect.result | 2 +- mysql-test/t/analyse.test | 10 ++++++++++ mysql-test/t/subselect.test | 2 +- sql/sql_yacc.yy | 3 ++- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/analyse.result b/mysql-test/r/analyse.result index c0b16778f9c..6eaa8731dc6 100644 --- a/mysql-test/r/analyse.result +++ b/mysql-test/r/analyse.result @@ -28,9 +28,7 @@ test.t1.bool N Y 1 1 0 0 1.0000 NULL ENUM('N','Y') NOT NULL test.t1.d 2002-03-03 2002-03-05 10 10 0 0 10.0000 NULL ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL drop table t1,t2; EXPLAIN SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(); -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY system NULL NULL NULL NULL 1 -2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +ERROR HY000: Incorrect usage of PROCEDURE and subquery create table t1 (a int not null); create table t2 select * from t1 where 0=1 procedure analyse(); show create table t2; @@ -153,4 +151,9 @@ select f3 from t1 procedure analyse(1, 1); Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype test.t1.f3 5.99999 9.55555 7 7 0 0 7.77777 1.77778 FLOAT(6,5) NOT NULL drop table t1; +CREATE TABLE t1(a INT,b INT,c INT,d INT,e INT,f INT,g INT,h INT,i INT,j INT,k INT); +INSERT INTO t1 VALUES (); +SELECT * FROM (SELECT * FROM t1) d PROCEDURE ANALYSE(); +ERROR HY000: Incorrect usage of PROCEDURE and subquery +DROP TABLE t1; End of 4.1 tests diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 7f6ebb14c3e..ee6865fe764 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -75,7 +75,7 @@ SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a)); select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1)); ERROR HY000: Incorrect usage of PROCEDURE and subquery SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1)); -ERROR HY000: Incorrect parameters to procedure 'ANALYSE' +ERROR HY000: Incorrect usage of PROCEDURE and subquery SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL; ERROR 42S22: Unknown column 'a' in 'field list' SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NOT NULL; diff --git a/mysql-test/t/analyse.test b/mysql-test/t/analyse.test index efcf5f6421c..d8466df14bf 100644 --- a/mysql-test/t/analyse.test +++ b/mysql-test/t/analyse.test @@ -14,6 +14,7 @@ create table t2 select * from t1 procedure analyse(); select * from t2; drop table t1,t2; +--error ER_WRONG_USAGE EXPLAIN SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(); # @@ -102,4 +103,13 @@ select f2 from t1 procedure analyse(1, 1); select f3 from t1 procedure analyse(1, 1); drop table t1; +# +# Bug#46184 Crash, SELECT ... FROM derived table procedure analyze +# +CREATE TABLE t1(a INT,b INT,c INT,d INT,e INT,f INT,g INT,h INT,i INT,j INT,k INT); +INSERT INTO t1 VALUES (); +--error ER_WRONG_USAGE +SELECT * FROM (SELECT * FROM t1) d PROCEDURE ANALYSE(); +DROP TABLE t1; + --echo End of 4.1 tests diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index e82764d6ac4..bc3d6d44798 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -30,7 +30,7 @@ SELECT 1 IN (SELECT 1); SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a)); -- error ER_WRONG_USAGE select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1)); --- error ER_WRONG_PARAMETERS_TO_PROCEDURE +-- error ER_WRONG_USAGE SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1)); -- error ER_BAD_FIELD_ERROR SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7d6a7ade540..2eedbf5d1e7 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9069,7 +9069,8 @@ procedure_clause: MYSQL_YYABORT; } - if (&lex->select_lex != lex->current_select) + if (&lex->select_lex != lex->current_select || + lex->select_lex.get_table_list()->derived) { my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery"); MYSQL_YYABORT; From f95558870defc948e2d95db3609037b0a34affbf Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Tue, 22 Sep 2009 23:05:28 +0200 Subject: [PATCH 023/146] Backport into build-200909221805-5.1.37sp1 > ------------------------------------------------------------ > revno: 3092.1.2 [merge] > revision-id: joro@sun.com-20090831134035-wndnw04gy8kzogpm > parent: anurag.shekhar@sun.com-20090831075609-tkpqu41hxtupdeip > parent: joro@sun.com-20090827114042-h55n7qp9990bl6ge > committer: Georgi Kodinov > branch nick: B46749-5.1-bugteam > timestamp: Mon 2009-08-31 16:40:35 +0300 > message: > automerge > ------------------------------------------------------------ > Use --include-merges or -n0 to see merged revisions. --- mysql-test/r/subselect.result | 28 ++++++++++++++++++++++++ mysql-test/t/subselect.test | 32 +++++++++++++++++++++++++++ sql/sql_select.cc | 41 +++++++++++++++++++++++++---------- 3 files changed, 89 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index ee6865fe764..164a65ac47d 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4361,6 +4361,34 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select 1 AS `1` from `test`.`t1` where (1,(select 1 AS `1` from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` having ((1) = (1)))) DROP TABLE t1; +# +# Bug #46749: Segfault in add_key_fields() with outer subquery level +# field references +# +CREATE TABLE t1 ( +a int, +b int, +UNIQUE (a), KEY (b) +); +INSERT INTO t1 VALUES (1,1), (2,1); +CREATE TABLE st1 like t1; +INSERT INTO st1 VALUES (1,1), (2,1); +CREATE TABLE st2 like t1; +INSERT INTO st2 VALUES (1,1), (2,1); +EXPLAIN +SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b) +FROM t1 +WHERE a = 230; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 DEPENDENT SUBQUERY st1 index NULL a 5 NULL 2 Using index +2 DEPENDENT SUBQUERY st2 index b b 5 NULL 2 Using where; Using index; Using join buffer +SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b) +FROM t1 +WHERE a = 230; +MAX(b) (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b) +NULL 0 +DROP TABLE t1, st1, st2; End of 5.0 tests. CREATE TABLE t1 (a INT, b INT); INSERT INTO t1 VALUES (2,22),(1,11),(2,22); diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index bc3d6d44798..0bf844f23af 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -3315,6 +3315,38 @@ EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 GROUP BY a); EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 WHERE a > 3 GROUP BY a); DROP TABLE t1; + +--echo # +--echo # Bug #46749: Segfault in add_key_fields() with outer subquery level +--echo # field references +--echo # + +CREATE TABLE t1 ( + a int, + b int, + UNIQUE (a), KEY (b) +); +INSERT INTO t1 VALUES (1,1), (2,1); + +CREATE TABLE st1 like t1; +INSERT INTO st1 VALUES (1,1), (2,1); + +CREATE TABLE st2 like t1; +INSERT INTO st2 VALUES (1,1), (2,1); + +# should have "impossible where" +EXPLAIN +SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b) +FROM t1 +WHERE a = 230; + +# should not crash +SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b) +FROM t1 +WHERE a = 230; + +DROP TABLE t1, st1, st2; + --echo End of 5.0 tests. # diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b40ab8f71f4..6b16ebc3406 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3289,6 +3289,28 @@ add_key_equal_fields(KEY_FIELD **key_fields, uint and_level, } } + +/** + Check if an expression is a non-outer field. + + Checks if an expression is a field and belongs to the current select. + + @param field Item expression to check + + @return boolean + @retval TRUE the expression is a local field + @retval FALSE it's something else +*/ + +inline static bool +is_local_field (Item *field) +{ + field= field->real_item(); + return field->type() == Item::FIELD_ITEM && + !((Item_field *)field)->depended_from; +} + + static void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, COND *cond, table_map usable_tables, @@ -3364,13 +3386,12 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, { Item **values; // BETWEEN, IN, NE - if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM && + if (is_local_field (cond_func->key_item()) && !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) { values= cond_func->arguments()+1; if (cond_func->functype() == Item_func::NE_FUNC && - cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM && - !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT)) + is_local_field (cond_func->arguments()[1])) values--; DBUG_ASSERT(cond_func->functype() != Item_func::IN_FUNC || cond_func->argument_count() != 2); @@ -3386,9 +3407,7 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, for (uint i= 1 ; i < cond_func->argument_count() ; i++) { Item_field *field_item; - if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM - && - !(cond_func->arguments()[i]->used_tables() & OUTER_REF_TABLE_BIT)) + if (is_local_field (cond_func->arguments()[i])) { field_item= (Item_field *) (cond_func->arguments()[i]->real_item()); add_key_equal_fields(key_fields, *and_level, cond_func, @@ -3404,8 +3423,7 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, bool equal_func=(cond_func->functype() == Item_func::EQ_FUNC || cond_func->functype() == Item_func::EQUAL_FUNC); - if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM && - !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT)) + if (is_local_field (cond_func->arguments()[0])) { add_key_equal_fields(key_fields, *and_level, cond_func, (Item_field*) (cond_func->arguments()[0])->real_item(), @@ -3413,9 +3431,8 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, cond_func->arguments()+1, 1, usable_tables, sargables); } - if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM && - cond_func->functype() != Item_func::LIKE_FUNC && - !(cond_func->arguments()[1]->used_tables() & OUTER_REF_TABLE_BIT)) + if (is_local_field (cond_func->arguments()[1]) && + cond_func->functype() != Item_func::LIKE_FUNC) { add_key_equal_fields(key_fields, *and_level, cond_func, (Item_field*) (cond_func->arguments()[1])->real_item(), @@ -3427,7 +3444,7 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, } case Item_func::OPTIMIZE_NULL: /* column_name IS [NOT] NULL */ - if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM && + if (is_local_field (cond_func->arguments()[0]) && !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) { Item *tmp=new Item_null; From 768f2cdb6a7be8a747495bc9c4fad74d22346c5d Mon Sep 17 00:00:00 2001 From: "timothy.smith@sun.com" <> Date: Wed, 23 Sep 2009 01:26:08 +0200 Subject: [PATCH 024/146] Add --malloc-lib=LIB option to mysqld_safe to LD_PRELOAD a shared library for mysqld --- scripts/mysql_config.sh | 13 ++++ scripts/mysqld_safe.sh | 133 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 145 insertions(+), 1 deletion(-) diff --git a/scripts/mysql_config.sh b/scripts/mysql_config.sh index 4118856af19..d2699726a25 100644 --- a/scripts/mysql_config.sh +++ b/scripts/mysql_config.sh @@ -167,6 +167,10 @@ Options: --port [$port] --version [$version] --libmysqld-libs [$embedded_libs] + --variable=VAR VAR is one of: + pkgincludedir [$pkgincludedir] + pkglibdir [$pkglibdir] + plugindir [$plugindir] EOF exit 1 } @@ -184,6 +188,15 @@ while test $# -gt 0; do --port) echo "$port" ;; --version) echo "$version" ;; --embedded-libs | --embedded | --libmysqld-libs) echo "$embedded_libs" ;; + --variable=*) + var=`echo "$1" | sed 's,^[^=]*=,,'` + case "$var" in + pkgincludedir) echo "$pkgincludedir" ;; + pkglibdir) echo "$pkglibdir" ;; + plugindir) echo "$plugindir" ;; + *) usage ;; + esac + ;; *) usage ;; esac diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 23b5efcaf2b..95c4419273f 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -11,9 +11,13 @@ # mysql.server works by first doing a cd to the base directory and from there # executing mysqld_safe +# Initialize script globals KILL_MYSQLD=1; MYSQLD= niceness=0 +mysqld_ld_preload= +mysqld_ld_library_path= + # Initial logging status: error log is not open, and not using syslog logging=init want_syslog=0 @@ -46,6 +50,7 @@ Usage: $0 [OPTIONS] --open-files-limit=LIMIT Limit the number of open files --core-file-size=LIMIT Limit core files to the specified size --timezone=TZ Set the system timezone + --malloc-lib=LIB Preload shared library LIB if available --mysqld=FILE Use the specified file as mysqld --mysqld-version=VERSION Use "mysqld-VERSION" as mysqld --nice=NICE Set the scheduling priority of mysqld @@ -172,6 +177,7 @@ parse_arguments() { # mysqld_safe-specific options - must be set in my.cnf ([mysqld_safe])! --core-file-size=*) core_file_size="$val" ;; --ledir=*) ledir="$val" ;; + --malloc-lib=*) set_malloc_lib "$val" ;; --mysqld=*) MYSQLD="$val" ;; --mysqld-version=*) if test -n "$val" @@ -202,6 +208,131 @@ parse_arguments() { } +# Add a single shared library to the list of libraries which will be added to +# LD_PRELOAD for mysqld +# +# Since LD_PRELOAD is a space-separated value (for historical reasons), if a +# shared lib's path contains spaces, that path will be prepended to +# LD_LIBRARY_PATH and stripped from the lib value. +add_mysqld_ld_preload() { + lib_to_add="$1" + log_notice "Adding '$lib_to_add' to LD_PRELOAD for mysqld" + + case "$lib_to_add" in + *' '*) + # Must strip path from lib, and add it to LD_LIBRARY_PATH + lib_file=`basename "$lib_to_add"` + case "$lib_file" in + *' '*) + # The lib file itself has a space in its name, and can't + # be used in LD_PRELOAD + log_error "library name '$lib_to_add' contains spaces and can not be used with LD_PRELOAD" + exit 1 + ;; + esac + lib_path=`dirname "$lib_to_add"` + lib_to_add="$lib_file" + [ -n "$mysqld_ld_library_path" ] && mysqld_ld_library_path="$mysqld_ld_library_path:" + mysqld_ld_library_path="$mysqld_ld_library_path$lib_path" + ;; + esac + + # LD_PRELOAD is a space-separated + [ -n "$mysqld_ld_preload" ] && mysqld_ld_preload="$mysqld_ld_preload " + mysqld_ld_preload="${mysqld_ld_preload}$lib_to_add" +} + + +# Returns LD_PRELOAD (and LD_LIBRARY_PATH, if needed) text, quoted to be +# suitable for use in the eval that calls mysqld. +# +# All values in mysqld_ld_preload are prepended to LD_PRELOAD. +mysqld_ld_preload_text() { + text= + + if [ -n "$mysqld_ld_preload" ]; then + new_text="$mysqld_ld_preload" + [ -n "$LD_PRELOAD" ] && new_text="$new_text $LD_PRELOAD" + text="${text}LD_PRELOAD="`shell_quote_string "$new_text"`' ' + fi + + if [ -n "$mysqld_ld_library_path" ]; then + new_text="$mysqld_ld_library_path" + [ -n "$LD_LIBRARY_PATH" ] && new_text="$new_text:$LD_LIBRARY_PATH" + text="${text}LD_LIBRARY_PATH="`shell_quote_string "$new_text"`' ' + fi + + echo "$text" +} + + +mysql_config= +get_mysql_config() { + if [ -z "$mysql_config" ]; then + mysql_config=`echo "$0" | sed 's,/[^/][^/]*$,/mysql_config,'` + if [ ! -x "$mysql_config" ]; then + log_error "Can not run mysql_config $@ from '$mysql_config'" + exit 1 + fi + fi + + "$mysql_config" "$@" +} + + +# set_malloc_lib LIB +# - If LIB is empty, do nothing and return +# - If LIB is 'tcmalloc', look for tcmalloc shared library in /usr/lib +# then pkglibdir. tcmalloc is part of the Google perftools project. +# - If LIB is an absolute path, assume it is a malloc shared library +# +# Put LIB in mysqld_ld_preload, which will be added to LD_PRELOAD when +# running mysqld. See ld.so for details. +set_malloc_lib() { + malloc_lib="$1" + + if [ "$malloc_lib" = tcmalloc ]; then + pkglibdir=`get_mysql_config --variable=pkglibdir` + malloc_lib= + # This list is kept intentionally simple. Simply set --malloc-lib + # to a full path if another location is desired. + for libdir in /usr/lib "$pkglibdir"; do + for flavor in _minimal '' _and_profiler _debug; do + tmp="$libdir/libtcmalloc$flavor.so" + #log_notice "DEBUG: Checking for malloc lib '$tmp'" + [ -r "$tmp" ] || continue + malloc_lib="$tmp" + break 2 + done + done + + if [ -z "$malloc_lib" ]; then + log_error "no shared library for --malloc-lib=tcmalloc found in /usr/lib or $pkglibdir" + exit 1 + fi + fi + + # Allow --malloc-lib='' to override other settings + [ -z "$malloc_lib" ] && return + + case "$malloc_lib" in + /*) + if [ ! -r "$malloc_lib" ]; then + log_error "--malloc-lib '$malloc_lib' can not be read and will not be used" + exit 1 + fi + ;; + *) + log_error "--malloc-lib must be an absolute path or 'tcmalloc'; " \ + "ignoring value '$malloc_lib'" + exit 1 + ;; + esac + + add_mysqld_ld_preload "$malloc_lib" +} + + # # First, try to find BASEDIR and ledir (where mysqld is) # @@ -549,7 +680,7 @@ fi # ulimit -n 256 > /dev/null 2>&1 # Fix for BSD and FreeBSD systems #fi -cmd="$NOHUP_NICENESS" +cmd="`mysqld_ld_preload_text`$NOHUP_NICENESS" for i in "$ledir/$MYSQLD" "$defaults" "--basedir=$MY_BASEDIR_VERSION" \ "--datadir=$DATADIR" "$USER_OPTION" From 185698530e1bbe506837538462ba832f78a44db7 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 23 Sep 2009 13:40:33 +0500 Subject: [PATCH 025/146] Bug#45989 memory leak after explain encounters an error in the query the fix is reverted from 5.1, mysql-pe as unnecessary(no valgrind warnings there). --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8b1e0ae365b..1ff068c8881 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2248,7 +2248,7 @@ JOIN::destroy() tab->cleanup(); } tmp_join->tmp_join= 0; - tmp_table_param.cleanup(); + tmp_table_param.copy_field= 0; DBUG_RETURN(tmp_join->destroy()); } cond_equal= 0; From 29b6cc60cdc1e643f2bab162ac3d18c227263a8d Mon Sep 17 00:00:00 2001 From: Satya B Date: Wed, 23 Sep 2009 17:42:12 +0530 Subject: [PATCH 026/146] Additional Fix for BUG#44030 - Error: (1500) Couldn't read the MAX(ID) autoinc value from the index (PRIMARY) With the fix for BUG#46760, we correctly flag the presence of row_type only when it's actually changed and enables the FAST ALTER TABLE which was disabled with the BUG#39200. So the changes made by BUG#46760 makes MySQL data dictionaries to be out of sync but they are handled already by InnoDB with this BUG#44030. The test was originally written to handle this but we requested Innodb to update the test as the data dictionaries were in sync after the fix for BUG#39200. Adjusting the innodb-autoinc testcase as mentioned in the comments. --- mysql-test/lib/mtr_cases.pm | 1 - mysql-test/r/innodb-autoinc.result | 2 +- mysql-test/t/innodb-autoinc.test | 6 +----- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index dff005105f6..224babaaf32 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -500,7 +500,6 @@ sub collect_one_suite($) # Exceptions next if ($test->{'name'} eq 'main.innodb'); # Failed with wrong errno (fk) next if ($test->{'name'} eq 'main.index_merge_innodb'); # Explain diff - next if ($test->{'name'} eq 'main.innodb-autoinc'); # Need dfrnt result file # innodb_file_per_table is rw with innodb_plugin next if ($test->{'name'} eq 'sys_vars.innodb_file_per_table_basic'); # innodb_lock_wait_timeout is rw with innodb_plugin diff --git a/mysql-test/r/innodb-autoinc.result b/mysql-test/r/innodb-autoinc.result index 76575ae4160..d2e8eb19e0c 100644 --- a/mysql-test/r/innodb-autoinc.result +++ b/mysql-test/r/innodb-autoinc.result @@ -880,6 +880,7 @@ d1 1 3 INSERT INTO t1 VALUES(null); +Got one of the listed errors ALTER TABLE t1 AUTO_INCREMENT = 3; INSERT INTO t1 VALUES(null); SELECT * FROM t1; @@ -887,5 +888,4 @@ d1 1 3 4 -5 DROP TABLE t1; diff --git a/mysql-test/t/innodb-autoinc.test b/mysql-test/t/innodb-autoinc.test index b51014ef4b3..61c42f45733 100644 --- a/mysql-test/t/innodb-autoinc.test +++ b/mysql-test/t/innodb-autoinc.test @@ -492,11 +492,7 @@ SELECT * FROM t1; # 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. -# -- error ER_AUTOINC_READ_FAILED,1467 +-- error ER_AUTOINC_READ_FAILED,1467 INSERT INTO t1 VALUES(null); ALTER TABLE t1 AUTO_INCREMENT = 3; INSERT INTO t1 VALUES(null); From 613297ff1e66a0fcf517e4e1bcf2a573d2e2c815 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Wed, 23 Sep 2009 17:10:23 +0400 Subject: [PATCH 027/146] A patch for Bug#47474 (mysqld hits Dbug_violation_helper assert when compiled with Sun Studio compiler). The thing is that Sun Studio compiler calls destructor of stack objects when pthread_exit() is called. That triggered an assertion in DBUG_ENTER()/DBUG_RETURN() validation logic (if DBUG_ENTER() is used in the beginning of function, all returns should be replaced by DBUG_RETURN/DBUG_VOID_RETURN macros). A fix is to explicitly use DBUG_LEAVE macro. --- sql/ha_ndbcluster.cc | 4 +++- sql/ha_ndbcluster_binlog.cc | 9 ++++++--- sql/mysqld.cc | 23 ++++++++++++++++++----- sql/repl_failsafe.cc | 4 +++- sql/slave.cc | 9 ++++++--- 5 files changed, 36 insertions(+), 13 deletions(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index ddb90427fdc..dfd7ddc4d6c 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -9426,9 +9426,11 @@ ndb_util_thread_fail: pthread_cond_signal(&COND_ndb_util_ready); pthread_mutex_unlock(&LOCK_ndb_util_thread); DBUG_PRINT("exit", ("ndb_util_thread")); + + DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); pthread_exit(0); - DBUG_RETURN(NULL); + return NULL; // Avoid compiler warnings } /* diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index d9a9738ce72..2a87697c7fa 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -3663,9 +3663,11 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) ndb_binlog_thread_running= -1; pthread_mutex_unlock(&injector_mutex); pthread_cond_signal(&injector_cond); + + DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); pthread_exit(0); - DBUG_RETURN(NULL); + return NULL; // Avoid compiler warnings } lex_start(thd); @@ -4376,10 +4378,11 @@ err: (void) pthread_cond_signal(&injector_cond); DBUG_PRINT("exit", ("ndb_binlog_thread")); - my_thread_end(); + DBUG_LEAVE; // Must match DBUG_ENTER() + my_thread_end(); pthread_exit(0); - DBUG_RETURN(NULL); + return NULL; // Avoid compiler warnings } bool diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 430592e7688..5778e6ab4aa 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1107,13 +1107,13 @@ void kill_mysql(void) #if defined(__NETWARE__) extern "C" void kill_server(int sig_ptr) -#define RETURN_FROM_KILL_SERVER DBUG_VOID_RETURN +#define RETURN_FROM_KILL_SERVER return #elif !defined(__WIN__) static void *kill_server(void *sig_ptr) -#define RETURN_FROM_KILL_SERVER DBUG_RETURN(0) +#define RETURN_FROM_KILL_SERVER return 0 #else static void __cdecl kill_server(int sig_ptr) -#define RETURN_FROM_KILL_SERVER DBUG_VOID_RETURN +#define RETURN_FROM_KILL_SERVER return #endif { DBUG_ENTER("kill_server"); @@ -1121,7 +1121,10 @@ static void __cdecl kill_server(int sig_ptr) int sig=(int) (long) sig_ptr; // This is passed a int // if there is a signal during the kill in progress, ignore the other if (kill_in_progress) // Safety + { + DBUG_LEAVE; RETURN_FROM_KILL_SERVER; + } kill_in_progress=TRUE; abort_loop=1; // This should be set if (sig != 0) // 0 is not a valid signal number @@ -1156,12 +1159,19 @@ static void __cdecl kill_server(int sig_ptr) pthread_join(select_thread, NULL); // wait for main thread #endif /* __NETWARE__ */ + DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); pthread_exit(0); /* purecov: end */ -#endif /* EMBEDDED_LIBRARY */ + RETURN_FROM_KILL_SERVER; // Avoid compiler warnings + +#else /* EMBEDDED_LIBRARY*/ + + DBUG_LEAVE; RETURN_FROM_KILL_SERVER; + +#endif /* EMBEDDED_LIBRARY */ } @@ -1935,8 +1945,9 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache) my_thread_end(); (void) pthread_cond_broadcast(&COND_thread_count); + DBUG_LEAVE; // Must match DBUG_ENTER() pthread_exit(0); - DBUG_RETURN(0); // Impossible + return 0; // Avoid compiler warnings } @@ -2756,7 +2767,9 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) DBUG_PRINT("quit",("signal_handler: calling my_thread_end()")); my_thread_end(); signal_thread_in_use= 0; + DBUG_LEAVE; // Must match DBUG_ENTER() pthread_exit(0); // Safety + return 0; // Avoid compiler warnings } switch (sig) { case SIGTERM: diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 582348608de..312499bb4ee 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -638,9 +638,11 @@ err: if (recovery_captain) mysql_close(recovery_captain); delete thd; + + DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); pthread_exit(0); - DBUG_RETURN(0); + return 0; // Avoid compiler warnings } #endif diff --git a/sql/slave.cc b/sql/slave.cc index b489eb3b45f..8bf126ce2c2 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2799,9 +2799,11 @@ err: pthread_cond_broadcast(&mi->stop_cond); // tell the world we are done DBUG_EXECUTE_IF("simulate_slave_delay_at_terminate_bug38694", sleep(5);); pthread_mutex_unlock(&mi->run_lock); + + DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); pthread_exit(0); - DBUG_RETURN(0); // Can't return anything here + return 0; // Avoid compiler warnings } /* @@ -3157,10 +3159,11 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ pthread_cond_broadcast(&rli->stop_cond); DBUG_EXECUTE_IF("simulate_slave_delay_at_terminate_bug38694", sleep(5);); pthread_mutex_unlock(&rli->run_lock); // tell the world we are done - + + DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); pthread_exit(0); - DBUG_RETURN(0); // Can't return anything here + return 0; // Avoid compiler warnings } From 8b9843408d8b1068798228f397cd1a20fa56f504 Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Wed, 23 Sep 2009 15:21:29 +0200 Subject: [PATCH 028/146] Bug #43414 Parenthesis (and other) warnings compiling MySQL with gcc 4.3.2 Cleaning up warnings not present in 5.0. --- client/mysql.cc | 2 +- client/mysqlslap.c | 9 +++++++-- cmd-line-utils/readline/display.c | 6 +++--- extra/yassl/include/yassl_int.hpp | 2 +- extra/yassl/src/yassl_int.cpp | 2 +- include/my_dbug.h | 6 +++--- sql/event_db_repository.cc | 2 +- sql/ha_partition.cc | 2 +- sql/ha_partition.h | 8 ++++---- sql/handler.cc | 12 ++++-------- sql/item_timefunc.cc | 10 +++------- sql/item_xmlfunc.cc | 6 +++--- sql/log_event_old.cc | 6 +++--- sql/mysqld.cc | 3 ++- sql/partition_info.cc | 6 ++---- sql/rpl_rli.cc | 4 ++-- sql/set_var.cc | 9 ++++++--- sql/set_var.h | 3 ++- sql/slave.cc | 14 +++++++------- sql/sql_cache.cc | 2 +- sql/sql_connect.cc | 2 +- sql/sql_db.cc | 6 +++--- sql/sql_partition.cc | 4 ++-- sql/sql_plugin.cc | 2 +- sql/sql_show.cc | 2 ++ sql/strfunc.cc | 2 +- storage/archive/ha_archive.cc | 10 ++++------ storage/csv/ha_tina.cc | 4 ++-- storage/myisammrg/myrg_open.c | 3 +-- unittest/mysys/base64-t.c | 2 +- 30 files changed, 75 insertions(+), 76 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index bafd173343e..28da6d75c1b 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -3561,7 +3561,7 @@ static void print_warnings() messages. To be safe, skip printing the duplicate only if it is the only warning. */ - if (!cur || num_rows == 1 && error == (uint) strtoul(cur[1], NULL, 10)) + if (!cur || (num_rows == 1 && error == (uint) strtoul(cur[1], NULL, 10))) goto end; /* Print the warnings */ diff --git a/client/mysqlslap.c b/client/mysqlslap.c index 70abfbb7136..28c5e8df79d 100644 --- a/client/mysqlslap.c +++ b/client/mysqlslap.c @@ -423,6 +423,7 @@ void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr) stats *sptr; conclusions conclusion; unsigned long long client_limit; + int sysret; head_sptr= (stats *)my_malloc(sizeof(stats) * iterations, MYF(MY_ZEROFILL|MY_FAE|MY_WME)); @@ -463,7 +464,9 @@ void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr) run_query(mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0")); if (pre_system) - system(pre_system); + if ((sysret= system(pre_system)) != 0) + fprintf(stderr, "Warning: Execution of pre_system option returned %d.\n", + sysret); /* Pre statements are always run after all other logic so they can @@ -478,7 +481,9 @@ void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr) run_statements(mysql, post_statements); if (post_system) - system(post_system); + if ((sysret= system(post_system)) != 0) + fprintf(stderr, "Warning: Execution of post_system option returned %d.\n", + sysret); /* We are finished with this run */ if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary) diff --git a/cmd-line-utils/readline/display.c b/cmd-line-utils/readline/display.c index f9b88f0006c..4a9dd466b2f 100644 --- a/cmd-line-utils/readline/display.c +++ b/cmd-line-utils/readline/display.c @@ -465,10 +465,10 @@ rl_redisplay () int newlines, lpos, temp, modmark; const char *prompt_this_line; #if defined (HANDLE_MULTIBYTE) - int num, n0; + int num, n0= 0; wchar_t wc; size_t wc_bytes; - int wc_width; + int wc_width= 0; mbstate_t ps; int _rl_wrapped_multicolumn = 0; #endif @@ -828,7 +828,7 @@ rl_redisplay () cpos_buffer_position = out; lb_linenum = newlines; } - for (i = in; i < in+wc_bytes; i++) + for (i = in; i < in+(int)wc_bytes; i++) line[out++] = rl_line_buffer[i]; for (i = 0; i < wc_width; i++) CHECK_LPOS(); diff --git a/extra/yassl/include/yassl_int.hpp b/extra/yassl/include/yassl_int.hpp index d18dc41860c..1e761f559e2 100644 --- a/extra/yassl/include/yassl_int.hpp +++ b/extra/yassl/include/yassl_int.hpp @@ -441,7 +441,7 @@ public: const Ciphers& GetCiphers() const; const DH_Parms& GetDH_Parms() const; const Stats& GetStats() const; - const VerifyCallback getVerifyCallback() const; + VerifyCallback getVerifyCallback() const; pem_password_cb GetPasswordCb() const; void* GetUserData() const; bool GetSessionCacheOff() const; diff --git a/extra/yassl/src/yassl_int.cpp b/extra/yassl/src/yassl_int.cpp index b7f91d72166..8e4a9aa95ec 100644 --- a/extra/yassl/src/yassl_int.cpp +++ b/extra/yassl/src/yassl_int.cpp @@ -1833,7 +1833,7 @@ SSL_CTX::GetCA_List() const } -const VerifyCallback SSL_CTX::getVerifyCallback() const +VerifyCallback SSL_CTX::getVerifyCallback() const { return verifyCallback_; } diff --git a/include/my_dbug.h b/include/my_dbug.h index 474a46f29dd..0ba72b2210d 100644 --- a/include/my_dbug.h +++ b/include/my_dbug.h @@ -137,13 +137,13 @@ extern FILE *_db_fp_(void); #define DBUG_EVALUATE_IF(keyword,a1,a2) (a2) #define DBUG_PRINT(keyword,arglist) do { } while(0) #define DBUG_PUSH(a1) -#define DBUG_SET(a1) -#define DBUG_SET_INITIAL(a1) +#define DBUG_SET(a1) do { } while(0) +#define DBUG_SET_INITIAL(a1) do { } while(0) #define DBUG_POP() #define DBUG_PROCESS(a1) #define DBUG_SETJMP(a1) setjmp(a1) #define DBUG_LONGJMP(a1) longjmp(a1) -#define DBUG_DUMP(keyword,a1,a2) +#define DBUG_DUMP(keyword,a1,a2) do { } while(0) #define DBUG_END() #define DBUG_ASSERT(A) do { } while(0) #define DBUG_LOCK_FILE diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 9a253d74546..8faab5023da 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -711,7 +711,7 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data, DBUG_ENTER("Event_db_repository::update_event"); /* None or both must be set */ - DBUG_ASSERT(new_dbname && new_name || new_dbname == new_name); + DBUG_ASSERT((new_dbname && new_name) || new_dbname == new_name); /* Reset sql_mode during data dictionary operations. */ thd->variables.sql_mode= 0; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index b27f493b80a..df5badccb1e 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1001,7 +1001,7 @@ static bool print_admin_msg(THD* thd, const char* msg_type, if (!thd->vio_ok()) { - sql_print_error(msgbuf); + sql_print_error("%s", msgbuf); return TRUE; } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 1c863d6c294..c08b1f77eca 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -773,10 +773,10 @@ public: if (m_handler_status < handler_initialized || m_handler_status >= handler_closed) DBUG_RETURN(PARTITION_ENABLED_TABLE_FLAGS); - else - DBUG_RETURN((m_file[0]->ha_table_flags() & - ~(PARTITION_DISABLED_TABLE_FLAGS)) | - (PARTITION_ENABLED_TABLE_FLAGS)); + + DBUG_RETURN((m_file[0]->ha_table_flags() & + ~(PARTITION_DISABLED_TABLE_FLAGS)) | + (PARTITION_ENABLED_TABLE_FLAGS)); } /* diff --git a/sql/handler.cc b/sql/handler.cc index a4d88e84f4c..d07ebed8ab9 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3501,14 +3501,10 @@ int handler::index_next_same(uchar *buf, const uchar *key, uint keylen) if (!(error=index_next(buf))) { my_ptrdiff_t ptrdiff= buf - table->record[0]; - uchar *save_record_0; - KEY *key_info; - KEY_PART_INFO *key_part; - KEY_PART_INFO *key_part_end; - LINT_INIT(save_record_0); - LINT_INIT(key_info); - LINT_INIT(key_part); - LINT_INIT(key_part_end); + uchar *UNINIT_VAR(save_record_0); + KEY *UNINIT_VAR(key_info); + KEY_PART_INFO *UNINIT_VAR(key_part); + KEY_PART_INFO *UNINIT_VAR(key_part_end); /* key_cmp_if_same() compares table->record[0] against 'key'. diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index cf38a294e55..b5037c08b3c 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1344,15 +1344,11 @@ bool get_interval_value(Item *args,interval_type int_type, String *str_value, INTERVAL *interval) { ulonglong array[5]; - longlong value; - const char *str; - size_t length; + longlong UNINIT_VAR(value); + const char *UNINIT_VAR(str); + size_t UNINIT_VAR(length); CHARSET_INFO *cs=str_value->charset(); - LINT_INIT(value); - LINT_INIT(str); - LINT_INIT(length); - bzero((char*) interval,sizeof(*interval)); if ((int) int_type <= INTERVAL_MICROSECOND) { diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 6320873e4d3..1eff00027f2 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -1354,7 +1354,7 @@ my_xpath_lex_scan(MY_XPATH *xpath, MY_XPATH_LEX *lex, const char *beg, const char *end) { int ch, ctype, length; - for ( ; beg < end && *beg == ' ' ; beg++); // skip leading spaces + for ( ; beg < end && *beg == ' ' ; beg++) ; // skip leading spaces lex->beg= beg; if (beg >= end) @@ -1423,7 +1423,7 @@ my_xpath_lex_scan(MY_XPATH *xpath, if (my_xdigit(ch)) // a sequence of digits { - for ( ; beg < end && my_xdigit(*beg) ; beg++); + for ( ; beg < end && my_xdigit(*beg) ; beg++) ; lex->end= beg; lex->term= MY_XPATH_LEX_DIGITS; return; @@ -1431,7 +1431,7 @@ my_xpath_lex_scan(MY_XPATH *xpath, if (ch == '"' || ch == '\'') // a string: either '...' or "..." { - for ( ; beg < end && *beg != ch ; beg++); + for ( ; beg < end && *beg != ch ; beg++) ; if (beg < end) { lex->end= beg+1; diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 68cd2bf4673..f14ebe49706 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1245,8 +1245,8 @@ Old_rows_log_event::Old_rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid, solution, to be able to terminate a started statement in the binary log: the extraneous events will be removed in the future. */ - DBUG_ASSERT(tbl_arg && tbl_arg->s && tid != ~0UL || - !tbl_arg && !cols && tid == ~0UL); + DBUG_ASSERT((tbl_arg && tbl_arg->s && tid != ~0UL) || + (!tbl_arg && !cols && tid == ~0UL)); if (thd_arg->options & OPTION_NO_FOREIGN_KEY_CHECKS) set_flags(NO_FOREIGN_KEY_CHECKS_F); @@ -1409,7 +1409,7 @@ int Old_rows_log_event::do_add_row_data(uchar *row_data, size_t length) #endif DBUG_ASSERT(m_rows_buf <= m_rows_cur); - DBUG_ASSERT(!m_rows_buf || m_rows_end && m_rows_buf < m_rows_end); + DBUG_ASSERT(!m_rows_buf || (m_rows_end && m_rows_buf < m_rows_end)); DBUG_ASSERT(m_rows_cur <= m_rows_end); /* The cast will always work since m_rows_cur <= m_rows_end */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5778e6ab4aa..3433b54cb29 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3719,6 +3719,7 @@ static void end_ssl() static int init_server_components() { + FILE* reopen; DBUG_ENTER("init_server_components"); /* We need to call each of these following functions to ensure that @@ -3761,7 +3762,7 @@ static int init_server_components() if (freopen(log_error_file, "a+", stdout)) #endif { - freopen(log_error_file, "a+", stderr); + reopen= freopen(log_error_file, "a+", stderr); setbuf(stderr, NULL); } } diff --git a/sql/partition_info.cc b/sql/partition_info.cc index e2027d3571e..ba9ea0e876e 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -483,10 +483,8 @@ static bool check_engine_condition(partition_element *p_elem, { DBUG_RETURN(TRUE); } - else - { - DBUG_RETURN(FALSE); - } + + DBUG_RETURN(FALSE); } diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 18fbae9bb9d..0c6cc15297f 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -33,10 +33,10 @@ Relay_log_info::Relay_log_info() :Slave_reporting_capability("SQL"), no_storage(FALSE), replicate_same_server_id(::replicate_same_server_id), info_fd(-1), cur_log_fd(-1), save_temporary_tables(0), + cur_log_old_open_count(0), group_relay_log_pos(0), event_relay_log_pos(0), #if HAVE_purify is_fake(FALSE), #endif - cur_log_old_open_count(0), group_relay_log_pos(0), event_relay_log_pos(0), group_master_log_pos(0), log_space_total(0), ignore_log_space_limit(0), last_master_timestamp(0), slave_skip_counter(0), abort_pos_wait(0), slave_run_id(0), sql_thd(0), @@ -300,7 +300,7 @@ Failed to open the existing relay log info file '%s' (errno %d)", DBUG_RETURN(error); err: - sql_print_error(msg); + sql_print_error("%s", msg); end_io_cache(&rli->info_file); if (info_fd >= 0) my_close(info_fd, MYF(0)); diff --git a/sql/set_var.cc b/sql/set_var.cc index 51c6ca219c6..cd01f6c8624 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -3349,7 +3349,7 @@ int set_var_init() uint count= 0; DBUG_ENTER("set_var_init"); - for (sys_var *var=vars.first; var; var= var->next, count++); + for (sys_var *var=vars.first; var; var= var->next, count++) ; if (hash_init(&system_variable_hash, system_charset_info, count, 0, 0, (hash_get_key) get_sys_var_length, 0, HASH_UNIQUE)) @@ -4184,10 +4184,10 @@ bool sys_var_opt_readonly::update(THD *thd, set_var *var) can cause to wait on a read lock, it's required for the client application to unlock everything, and acceptable for the server to wait on all locks. */ - if (result= close_cached_tables(thd, NULL, FALSE, TRUE, TRUE)) + if ((result= close_cached_tables(thd, NULL, FALSE, TRUE, TRUE))) goto end_with_read_lock; - if (result= make_global_read_lock_block_commit(thd)) + if ((result= make_global_read_lock_block_commit(thd))) goto end_with_read_lock; /* Change the opt_readonly system variable, safe because the lock is held */ @@ -4200,6 +4200,7 @@ end_with_read_lock: } +#ifndef DBUG_OFF /* even session variable here requires SUPER, because of -#o,file */ bool sys_var_thd_dbug::check(THD *thd, set_var *var) { @@ -4226,6 +4227,8 @@ uchar *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b) DBUG_EXPLAIN(buf, sizeof(buf)); return (uchar*) thd->strdup(buf); } +#endif /* DBUG_OFF */ + #ifdef HAVE_EVENT_SCHEDULER bool sys_var_event_scheduler::check(THD *thd, set_var *var) diff --git a/sql/set_var.h b/sql/set_var.h index 10e6e0f9c35..a54591b0fd6 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -621,6 +621,7 @@ public: uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; +#ifndef DBUG_OFF class sys_var_thd_dbug :public sys_var_thd { public: @@ -634,7 +635,7 @@ public: void set_default(THD *thd, enum_var_type type) { DBUG_POP(); } uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *b); }; - +#endif /* DBUG_OFF */ /* some variables that require special handling */ diff --git a/sql/slave.cc b/sql/slave.cc index 8bf126ce2c2..66cbef1029a 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1195,7 +1195,7 @@ err: if (master_res) mysql_free_result(master_res); DBUG_ASSERT(err_code != 0); - mi->report(ERROR_LEVEL, err_code, err_buff); + mi->report(ERROR_LEVEL, err_code, "%s", err_buff); DBUG_RETURN(1); } @@ -2386,7 +2386,7 @@ static bool check_io_slave_killed(THD *thd, Master_info *mi, const char *info) if (io_slave_killed(thd, mi)) { if (info && global_system_variables.log_warnings) - sql_print_information(info); + sql_print_information("%s", info); return TRUE; } return FALSE; @@ -2456,13 +2456,13 @@ static int try_to_reconnect(THD *thd, MYSQL *mysql, Master_info *mi, } else { - sql_print_information(buf); + sql_print_information("%s", buf); } } if (safe_reconnect(thd, mysql, mi, 1) || io_slave_killed(thd, mi)) { if (global_system_variables.log_warnings) - sql_print_information(messages[SLAVE_RECON_MSG_KILLED_AFTER]); + sql_print_information("%s", messages[SLAVE_RECON_MSG_KILLED_AFTER]); return 1; } return 0; @@ -2679,7 +2679,7 @@ slave. If the entry is correct, restart the server with a higher value of \ max_allowed_packet", thd->variables.max_allowed_packet); mi->report(ERROR_LEVEL, ER_NET_PACKET_TOO_LARGE, - ER(ER_NET_PACKET_TOO_LARGE)); + "%s", ER(ER_NET_PACKET_TOO_LARGE)); goto err; case ER_MASTER_FATAL_ERROR_READING_BINLOG: mi->report(ERROR_LEVEL, ER_MASTER_FATAL_ERROR_READING_BINLOG, @@ -2690,7 +2690,7 @@ max_allowed_packet", sql_print_error("\ Stopping slave I/O thread due to out-of-memory error from master"); mi->report(ERROR_LEVEL, ER_OUT_OF_RESOURCES, - ER(ER_OUT_OF_RESOURCES)); + "%s", ER(ER_OUT_OF_RESOURCES)); goto err; } if (try_to_reconnect(thd, mysql, mi, &retry_count, suppress_warnings, @@ -3050,7 +3050,7 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME, This function is reporting an error which was not reported while executing exec_relay_log_event(). */ - rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), errmsg); + rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), "%s", errmsg); } else if (last_errno != thd->main_da.sql_errno()) { diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index df19fd05417..a41b7bd40bb 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -383,7 +383,7 @@ static void debug_wait_for_kill(const char *info) thd= current_thd; prev_info= thd->proc_info; thd->proc_info= info; - sql_print_information(info); + sql_print_information("%s", info); while(!thd->killed) my_sleep(1000); thd->killed= THD::NOT_KILLED; diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 98574a07a4e..bb4ba2bf21b 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -985,7 +985,7 @@ static void end_connection(THD *thd) if (thd->user_connect) decrease_user_connections(thd->user_connect); - if (thd->killed || net->error && net->vio != 0) + if (thd->killed || (net->error && net->vio != 0)) { statistic_increment(aborted_threads,&LOCK_status); } diff --git a/sql/sql_db.cc b/sql/sql_db.cc index bcc8fcf54fc..c19bfba9fc1 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -1450,11 +1450,11 @@ cmp_db_names(const char *db1_name, { return /* db1 is NULL and db2 is NULL */ - !db1_name && !db2_name || + (!db1_name && !db2_name) || /* db1 is not-NULL, db2 is not-NULL, db1 == db2. */ - db1_name && db2_name && - my_strcasecmp(system_charset_info, db1_name, db2_name) == 0; + (db1_name && db2_name && + my_strcasecmp(system_charset_info, db1_name, db2_name) == 0); } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 08ff2daacb9..2fb09ab7566 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -7098,9 +7098,9 @@ static uint32 get_next_partition_via_walking(PARTITION_ITERATOR *part_iter) longlong dummy; field->store(part_iter->field_vals.cur++, ((Field_num*)field)->unsigned_flag); - if (part_iter->part_info->is_sub_partitioned() && + if ((part_iter->part_info->is_sub_partitioned() && !part_iter->part_info->get_part_partition_id(part_iter->part_info, - &part_id, &dummy) || + &part_id, &dummy)) || !part_iter->part_info->get_partition_id(part_iter->part_info, &part_id, &dummy)) return part_id; diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 025c8a8248d..b411d5e3095 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -368,7 +368,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report) if (report & REPORT_TO_USER) my_error(ER_UDF_NO_PATHS, MYF(0)); if (report & REPORT_TO_LOG) - sql_print_error(ER(ER_UDF_NO_PATHS)); + sql_print_error("%s", ER(ER_UDF_NO_PATHS)); DBUG_RETURN(0); } /* If this dll is already loaded just increase ref_count. */ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5c2c351652b..bb377e676e2 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3529,7 +3529,9 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, TABLE_SHARE *share= show_table->s; handler *file= show_table->file; handlerton *tmp_db_type= share->db_type(); +#ifdef WITH_PARTITION_STORAGE_ENGINE bool is_partitioned= FALSE; +#endif if (share->tmp_table == SYSTEM_TMP_TABLE) table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs); else if (share->tmp_table) diff --git a/sql/strfunc.cc b/sql/strfunc.cc index 1fb9c1a8451..56fa4a380ea 100644 --- a/sql/strfunc.cc +++ b/sql/strfunc.cc @@ -147,7 +147,7 @@ static uint parse_name(TYPELIB *lib, const char **strpos, const char *end, } } else - for (; pos != end && *pos != '=' && *pos !=',' ; pos++); + for (; pos != end && *pos != '=' && *pos !=',' ; pos++) ; uint var_len= (uint) (pos - start); /* Determine which flag it is */ diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index 981814628f9..6fa8333c1b7 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -522,8 +522,8 @@ int ha_archive::open(const char *name, int mode, uint open_options) { DBUG_RETURN(0); } - else - DBUG_RETURN(rc); + + DBUG_RETURN(rc); } @@ -1575,10 +1575,8 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt) share->crashed= FALSE; DBUG_RETURN(HA_ADMIN_CORRUPT); } - else - { - DBUG_RETURN(HA_ADMIN_OK); - } + + DBUG_RETURN(HA_ADMIN_OK); } /* diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc index e18d4025777..ca9d5215310 100644 --- a/storage/csv/ha_tina.cc +++ b/storage/csv/ha_tina.cc @@ -1598,8 +1598,8 @@ int ha_tina::check(THD* thd, HA_CHECK_OPT* check_opt) share->crashed= TRUE; DBUG_RETURN(HA_ADMIN_CORRUPT); } - else - DBUG_RETURN(HA_ADMIN_OK); + + DBUG_RETURN(HA_ADMIN_OK); } diff --git a/storage/myisammrg/myrg_open.c b/storage/myisammrg/myrg_open.c index b82e3682ebf..7b310dc2eed 100644 --- a/storage/myisammrg/myrg_open.c +++ b/storage/myisammrg/myrg_open.c @@ -392,7 +392,7 @@ int myrg_attach_children(MYRG_INFO *m_info, int handle_locking, int save_errno; uint idx; uint child_nr; - uint key_parts; + uint UNINIT_VAR(key_parts); uint min_keys; my_bool bad_children= FALSE; DBUG_ENTER("myrg_attach_children"); @@ -409,7 +409,6 @@ int myrg_attach_children(MYRG_INFO *m_info, int handle_locking, rc= 1; errpos= 0; file_offset= 0; - LINT_INIT(key_parts); min_keys= 0; child_nr= 0; while ((myisam= (*callback)(callback_param))) diff --git a/unittest/mysys/base64-t.c b/unittest/mysys/base64-t.c index 1622fe22b4d..e1a40f89ff0 100644 --- a/unittest/mysys/base64-t.c +++ b/unittest/mysys/base64-t.c @@ -84,7 +84,7 @@ main(void) unsigned char c= dst[k+l]; sprintf(buf, "%.2x ", (unsigned)c); } - diag(buf); + diag("%s", buf); } diag("src length: %.8x, dst length: %.8x\n", (uint) src_len, (uint) dst_len); From 40bd549b9b2412953608aec96e1be3711a0ce037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Bl=C3=A5udd?= Date: Thu, 24 Sep 2009 08:30:31 +0200 Subject: [PATCH 029/146] Bug#42850 race condition in my_thr_init.c - Create the "dummy" thread joinable and wait for it to exit before continuing in 'my_thread_global_init' - This way we know that the pthread library is initialized by one thread only --- mysys/my_thr_init.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index c446808c7da..64fc99952e9 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -107,10 +107,11 @@ my_bool my_thread_global_init(void) pthread_attr_t dummy_thread_attr; pthread_attr_init(&dummy_thread_attr); - pthread_attr_setdetachstate(&dummy_thread_attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setdetachstate(&dummy_thread_attr, PTHREAD_CREATE_JOINABLE); - pthread_create(&dummy_thread,&dummy_thread_attr, - nptl_pthread_exit_hack_handler, NULL); + if (pthread_create(&dummy_thread,&dummy_thread_attr, + nptl_pthread_exit_hack_handler, NULL) == 0) + (void)pthread_join(dummy_thread, NULL); } #endif /* TARGET_OS_LINUX */ From 7dde009fff6d37921dc7741c3ce17f9f43578348 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 24 Sep 2009 16:19:06 +0300 Subject: [PATCH 030/146] added suppressions for existing warnings in the result file. --- mysql-test/include/mtr_warnings.sql | 1 + mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result | 2 ++ mysql-test/suite/rpl/r/rpl_log_pos.result | 1 + mysql-test/suite/rpl/r/rpl_packet.result | 2 ++ mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test | 2 ++ mysql-test/suite/rpl/t/rpl_log_pos.test | 1 + mysql-test/suite/rpl/t/rpl_packet.test | 2 ++ 7 files changed, 11 insertions(+) diff --git a/mysql-test/include/mtr_warnings.sql b/mysql-test/include/mtr_warnings.sql index 2156c37f3e3..134e448953a 100644 --- a/mysql-test/include/mtr_warnings.sql +++ b/mysql-test/include/mtr_warnings.sql @@ -173,6 +173,7 @@ INSERT INTO global_suppressions VALUES this error message. */ ("Can't find file: '.\\\\test\\\\\\?{8}.frm'"), + ("Slave: Unknown table 't1' Error_code: 1051"), ("THE_LAST_SUPPRESSION")|| diff --git a/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result b/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result index 263896b884a..99a0fd21f66 100644 --- a/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result +++ b/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result @@ -4,6 +4,8 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +call mtr.add_suppression("Slave I/O: .* failed with error: Lost connection to MySQL server at 'reading initial communication packet'"); +call mtr.add_suppression("Slave I/O: Master command COM_REGISTER_SLAVE failed: failed registering on master, reconnecting to try again"); SELECT IS_FREE_LOCK("debug_lock.before_get_UNIX_TIMESTAMP"); IS_FREE_LOCK("debug_lock.before_get_UNIX_TIMESTAMP") 1 diff --git a/mysql-test/suite/rpl/r/rpl_log_pos.result b/mysql-test/suite/rpl/r/rpl_log_pos.result index 7b3ebf62959..85fa4c10eac 100644 --- a/mysql-test/suite/rpl/r/rpl_log_pos.result +++ b/mysql-test/suite/rpl/r/rpl_log_pos.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +call mtr.add_suppression ("Slave I/O: Got fatal error 1236 from master when reading data from binary"); show master status; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 # diff --git a/mysql-test/suite/rpl/r/rpl_packet.result b/mysql-test/suite/rpl/r/rpl_packet.result index cb26d04bea9..0a9495751fe 100644 --- a/mysql-test/suite/rpl/r/rpl_packet.result +++ b/mysql-test/suite/rpl/r/rpl_packet.result @@ -4,6 +4,8 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +call mtr.add_suppression("Slave I/O: Got a packet bigger than 'max_allowed_packet' bytes, Error_code: 1153"); +call mtr.add_suppression("Slave I/O: Got fatal error 1236 from master when reading data from binary log:"); drop database if exists DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; create database DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; SET @@global.max_allowed_packet=1024; diff --git a/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test b/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test index 40d11f2cec2..a391b1f5344 100644 --- a/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test +++ b/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test @@ -16,6 +16,8 @@ source include/master-slave.inc; source include/have_debug.inc; +call mtr.add_suppression("Slave I/O: .* failed with error: Lost connection to MySQL server at 'reading initial communication packet'"); +call mtr.add_suppression("Slave I/O: Master command COM_REGISTER_SLAVE failed: failed registering on master, reconnecting to try again"); #Test case 1: Try to get the value of the UNIX_TIMESTAMP from master under network disconnection connection slave; let $debug_saved= `select @@global.debug`; diff --git a/mysql-test/suite/rpl/t/rpl_log_pos.test b/mysql-test/suite/rpl/t/rpl_log_pos.test index 5e8390f97ed..48effa00b64 100644 --- a/mysql-test/suite/rpl/t/rpl_log_pos.test +++ b/mysql-test/suite/rpl/t/rpl_log_pos.test @@ -11,6 +11,7 @@ # Passes with rbr no problem, removed statement include [jbm] source include/master-slave.inc; +call mtr.add_suppression ("Slave I/O: Got fatal error 1236 from master when reading data from binary"); source include/show_master_status.inc; sync_slave_with_master; source include/stop_slave.inc; diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test index b4e04405037..bfc144c759b 100644 --- a/mysql-test/suite/rpl/t/rpl_packet.test +++ b/mysql-test/suite/rpl/t/rpl_packet.test @@ -6,6 +6,8 @@ # max-out size db name source include/master-slave.inc; source include/have_binlog_format_row.inc; +call mtr.add_suppression("Slave I/O: Got a packet bigger than 'max_allowed_packet' bytes, Error_code: 1153"); +call mtr.add_suppression("Slave I/O: Got fatal error 1236 from master when reading data from binary log:"); let $db= DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; disable_warnings; From 59069cac4a88fc1e6bacd1162f64f5c02b87222b Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 24 Sep 2009 16:21:46 +0300 Subject: [PATCH 031/146] fixed compilation warnings --- mysys/mf_keycache.c | 2 +- sql/item_func.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index f9898e263aa..3c11e6731b7 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -3113,7 +3113,7 @@ int key_cache_write(KEY_CACHE *keycache, /* Used in the server. */ keycache->global_cache_write++; keycache_pthread_mutex_unlock(&keycache->cache_lock); - if (my_pwrite(file, (uchar*) buff, read_length, filepos + offset, + if (my_pwrite(file, (byte*) buff, read_length, filepos + offset, MYF(MY_NABP | MY_WAIT_IF_FULL))) error=1; keycache_pthread_mutex_lock(&keycache->cache_lock); diff --git a/sql/item_func.cc b/sql/item_func.cc index c6dbdb1d9a7..d6f315fda50 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4201,7 +4201,7 @@ void Item_func_set_user_var::save_item_result(Item *item) bool Item_func_set_user_var::update() { - bool res= NULL; + bool res= 0; DBUG_ENTER("Item_func_set_user_var::update"); switch (cached_result_type) { From 138474ec0334080cb303c9810201665e72cce181 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 24 Sep 2009 18:29:00 +0300 Subject: [PATCH 032/146] More valgrind suppressions added for libc 2.6.1 64 bit --- mysql-test/valgrind.supp | 84 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 21c6c30abcc..fe3a0334fae 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -625,3 +625,87 @@ fun:start_thread } +{ + Mem loss within nptl_pthread_exit_hack_handler 6 + Memcheck:Leak + fun:malloc + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/libc-*.so + obj:*/ld-*.so + obj:*/libc-*.so + fun:__libc_dlopen_mode + fun:pthread_cancel_init + fun:_Unwind_ForcedUnwind + fun:__pthread_unwind + fun:pthread_exit + fun:nptl_pthread_exit_hack_handler +} + +{ + Mem loss within nptl_pthread_exit_hack_handler 7 + Memcheck:Leak + fun:malloc + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/libc-*.so + obj:*/ld-*.so + obj:*/libc-*.so + fun:__libc_dlopen_mode + fun:pthread_cancel_init + fun:_Unwind_ForcedUnwind + fun:__pthread_unwind + fun:pthread_exit + fun:nptl_pthread_exit_hack_handler + fun:start_thread + fun:clone +} + +{ + Mem loss within nptl_pthread_exit_hack_handler 8 + Memcheck:Leak + fun:calloc + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/libc-*.so + obj:*/ld-*.so + obj:*/libc-*.so + fun:__libc_dlopen_mode + fun:pthread_cancel_init + fun:_Unwind_ForcedUnwind + fun:__pthread_unwind + fun:pthread_exit + fun:nptl_pthread_exit_hack_handler + fun:start_thread + fun:clone +} + +{ + Mem loss within nptl_pthread_exit_hack_handler 8 + Memcheck:Leak + fun:calloc + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/libc-*.so + obj:*/ld-*.so + obj:*/libc-*.so + fun:__libc_dlopen_mode + fun:pthread_cancel_init + fun:_Unwind_ForcedUnwind + fun:__pthread_unwind + fun:pthread_exit + fun:nptl_pthread_exit_hack_handler +} + From 90f570b5b3db4fff8c5336e550e8921a2cca86e8 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 25 Sep 2009 11:57:14 +0300 Subject: [PATCH 033/146] added more valgrind suppressions for glibc 2.6.1 --- mysql-test/valgrind.supp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index fe3a0334fae..26f0d329a4a 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -1,5 +1,4 @@ -# -# Suppress some common (not fatal) errors in system libraries found by valgrind +*# Suppress some common (not fatal) errors in system libraries found by valgrind # # @@ -625,6 +624,8 @@ fun:start_thread } +# suppressions for glibc 2.6.1 64 bit + { Mem loss within nptl_pthread_exit_hack_handler 6 Memcheck:Leak @@ -709,3 +710,14 @@ fun:nptl_pthread_exit_hack_handler } +# +# Pthread doesn't free all thread specific memory before program exists +# +{ + pthread allocate_tls memory loss in 2.6.1. + Memcheck:Leak + fun:calloc + obj:*/ld-*.so + fun:_dl_allocate_tls + fun:pthread_create* +} From 7d9548d26b276c7932d0f366e6f9acd516c86257 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Fri, 25 Sep 2009 11:26:49 +0200 Subject: [PATCH 034/146] Bug#32430: 'show innodb status' causes errors Invalid (old?) table or database name in logs Problem was still not completely fixed, due to qouting. This is the server side only fix (in explain_filename), the change from filename_to_tablename to use explain_filename in the InnoDB code must be done before the bug is fixed. --- mysql-test/include/have_not_innodb_plugin.inc | 4 + mysql-test/r/not_true.require | 2 + mysql-test/r/partition_innodb_builtin.result | 39 ++++++++++ mysql-test/r/partition_innodb_plugin.result | 50 +++++++++++++ mysql-test/t/disabled.def | 3 +- mysql-test/t/partition_innodb_builtin.test | 67 +++++++++++++++++ mysql-test/t/partition_innodb_plugin.test | 75 +++++++++++++++++++ sql/mysql_priv.h | 5 +- sql/sql_table.cc | 58 +++++++------- 9 files changed, 271 insertions(+), 32 deletions(-) create mode 100644 mysql-test/include/have_not_innodb_plugin.inc create mode 100644 mysql-test/r/not_true.require create mode 100644 mysql-test/r/partition_innodb_builtin.result create mode 100644 mysql-test/r/partition_innodb_plugin.result create mode 100644 mysql-test/t/partition_innodb_builtin.test create mode 100644 mysql-test/t/partition_innodb_plugin.test diff --git a/mysql-test/include/have_not_innodb_plugin.inc b/mysql-test/include/have_not_innodb_plugin.inc new file mode 100644 index 00000000000..aaefbaf661c --- /dev/null +++ b/mysql-test/include/have_not_innodb_plugin.inc @@ -0,0 +1,4 @@ +disable_query_log; +--require r/not_true.require +select (PLUGIN_LIBRARY LIKE 'ha_innodb_plugin%') as `TRUE` from information_schema.plugins where PLUGIN_NAME='InnoDB'; +enable_query_log; diff --git a/mysql-test/r/not_true.require b/mysql-test/r/not_true.require new file mode 100644 index 00000000000..0032832f3d1 --- /dev/null +++ b/mysql-test/r/not_true.require @@ -0,0 +1,2 @@ +TRUE +NULL diff --git a/mysql-test/r/partition_innodb_builtin.result b/mysql-test/r/partition_innodb_builtin.result new file mode 100644 index 00000000000..384ce0790a4 --- /dev/null +++ b/mysql-test/r/partition_innodb_builtin.result @@ -0,0 +1,39 @@ +SET NAMES utf8; +CREATE TABLE `t``\""e` (a INT, PRIMARY KEY (a)) +ENGINE=InnoDB +PARTITION BY RANGE (a) +SUBPARTITION BY HASH (a) +(PARTITION `p0``\""e` VALUES LESS THAN (100) +(SUBPARTITION `sp0``\""e`, +SUBPARTITION `sp1``\""e`), +PARTITION `p1``\""e` VALUES LESS THAN (MAXVALUE) +(SUBPARTITION `sp2``\""e`, +SUBPARTITION `sp3``\""e`)); +INSERT INTO `t``\""e` VALUES (0), (2), (6), (10), (14), (18), (22); +START TRANSACTION; +# con1 +SET NAMES utf8; +START TRANSACTION; +# default connection +UPDATE `t``\""e` SET a = 16 WHERE a = 0; +# con1 +UPDATE `t``\""e` SET a = 8 WHERE a = 22; +UPDATE `t``\""e` SET a = 12 WHERE a = 0; +# default connection +UPDATE `t``\""e` SET a = 4 WHERE a = 22; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +# First table reported in 'SHOW ENGINE InnoDB STATUS' +SHOW ENGINE InnoDB STATUS; +Type Name Status +InnoDB index `PRIMARY` of table `test`.`t``\""e` /* Partition `p0``\""e`, Subpartition `sp0``\""e` */ +set @old_sql_mode = @@sql_mode; +set sql_mode = 'ANSI_QUOTES'; +SHOW ENGINE InnoDB STATUS; +Type Name Status +InnoDB index `PRIMARY` of table `test`.`t``\""e` /* Partition `p0``\""e`, Subpartition `sp0``\""e` */ +set @@sql_mode = @old_sql_mode; +# con1 +ROLLBACK; +# default connection +DROP TABLE `t``\""e`; +SET NAMES DEFAULT; diff --git a/mysql-test/r/partition_innodb_plugin.result b/mysql-test/r/partition_innodb_plugin.result new file mode 100644 index 00000000000..dd91eee316a --- /dev/null +++ b/mysql-test/r/partition_innodb_plugin.result @@ -0,0 +1,50 @@ +SET NAMES utf8; +CREATE TABLE `t``\""e` (a INT, PRIMARY KEY (a)) +ENGINE=InnoDB +PARTITION BY RANGE (a) +SUBPARTITION BY HASH (a) +(PARTITION `p0``\""e` VALUES LESS THAN (100) +(SUBPARTITION `sp0``\""e`, +SUBPARTITION `sp1``\""e`), +PARTITION `p1``\""e` VALUES LESS THAN (MAXVALUE) +(SUBPARTITION `sp2``\""e`, +SUBPARTITION `sp3``\""e`)); +INSERT INTO `t``\""e` VALUES (0), (2), (6), (10), (14), (18), (22); +START TRANSACTION; +# con1 +SET NAMES utf8; +START TRANSACTION; +# default connection +UPDATE `t``\""e` SET a = 16 WHERE a = 0; +# con1 +UPDATE `t``\""e` SET a = 8 WHERE a = 22; +UPDATE `t``\""e` SET a = 12 WHERE a = 0; +# default connection +SELECT lock_table, COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS +GROUP BY lock_table; +lock_table COUNT(*) +`test`.`t``\""e` /* Partition `p0``\""e`, Subpartition `sp0``\""e` */ 2 +set @old_sql_mode = @@sql_mode; +set sql_mode = 'ANSI_QUOTES'; +SELECT lock_table, COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS +GROUP BY lock_table; +lock_table COUNT(*) +"test"."t`\""""e" /* Partition "p0`\""""e", Subpartition "sp0`\""""e" */ 2 +set @@sql_mode = @old_sql_mode; +UPDATE `t``\""e` SET a = 4 WHERE a = 22; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +# First table reported in 'SHOW ENGINE InnoDB STATUS' +SHOW ENGINE InnoDB STATUS; +Type Name Status +InnoDB index `PRIMARY` of table `test`.`t``\""e` /* Partition `p0``\""e`, Subpartition `sp0``\""e` */ +set @old_sql_mode = @@sql_mode; +set sql_mode = 'ANSI_QUOTES'; +SHOW ENGINE InnoDB STATUS; +Type Name Status +InnoDB index `PRIMARY` of table `test`.`t``\""e` /* Partition `p0``\""e`, Subpartition `sp0``\""e` */ +set @@sql_mode = @old_sql_mode; +# con1 +ROLLBACK; +# default connection +DROP TABLE `t``\""e`; +SET NAMES DEFAULT; diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 5436b7166f4..6613b6da415 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -13,4 +13,5 @@ kill : Bug#37780 2008-12-03 HHunger need some changes to be innodb_bug39438 : Bug#42383 2009-01-28 lsoares "This fails in embedded and on windows. Note that this test is not run on windows and on embedded in PB for main trees currently" query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails sporadically init_connect : Bug#44920 2009-07-06 pcrews MTR not processing master.opt input properly on Windows. *Must be done this way due to the nature of the bug* - +partition_innodb_builtin : Bug#32430 2009-09-25 mattiasj Waiting for push of Innodb changes +partition_innodb_plugin : Bug#32430 2009-09-25 mattiasj Waiting for push of Innodb changes diff --git a/mysql-test/t/partition_innodb_builtin.test b/mysql-test/t/partition_innodb_builtin.test new file mode 100644 index 00000000000..a9be41c7455 --- /dev/null +++ b/mysql-test/t/partition_innodb_builtin.test @@ -0,0 +1,67 @@ +--source include/have_partition.inc +--source include/have_innodb.inc +--source include/have_not_innodb_plugin.inc + +# +# Bug#32430 - show engine innodb status causes errors +# +SET NAMES utf8; +CREATE TABLE `t``\""e` (a INT, PRIMARY KEY (a)) +ENGINE=InnoDB +PARTITION BY RANGE (a) +SUBPARTITION BY HASH (a) +(PARTITION `p0``\""e` VALUES LESS THAN (100) + (SUBPARTITION `sp0``\""e`, + SUBPARTITION `sp1``\""e`), + PARTITION `p1``\""e` VALUES LESS THAN (MAXVALUE) + (SUBPARTITION `sp2``\""e`, + SUBPARTITION `sp3``\""e`)); +INSERT INTO `t``\""e` VALUES (0), (2), (6), (10), (14), (18), (22); +START TRANSACTION; +--echo # con1 +connect(con1,localhost,root,,); +SET NAMES utf8; +START TRANSACTION; +--echo # default connection +connection default; +UPDATE `t``\""e` SET a = 16 WHERE a = 0; +--echo # con1 +connection con1; +UPDATE `t``\""e` SET a = 8 WHERE a = 22; +let $id_1= `SELECT CONNECTION_ID()`; +SEND; +UPDATE `t``\""e` SET a = 12 WHERE a = 0; +--echo # default connection +connection default; +let $wait_timeout= 2; +let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE ID = $id_1 AND STATE = 'Searching rows for update'; +--source include/wait_condition.inc +#--echo # tested wait condition $wait_condition_reps times +--error ER_LOCK_DEADLOCK +UPDATE `t``\""e` SET a = 4 WHERE a = 22; +--echo # First table reported in 'SHOW ENGINE InnoDB STATUS' +# RECORD LOCKS space id 0 page no 50 n bits 80 index `PRIMARY` in \ +# Database `test`, Table `t1`, Partition `p0`, Subpartition `sp0` \ +# trx id 0 775 +# NOTE: replace_regex is very slow on match copy/past '(.*)' regex's +# on big texts, removing a lot of text before + after makes it much faster. +#/.*in (.*) trx.*/\1/ +--replace_regex /.*RECORD LOCKS space id [0-9]* page no [0-9]* n bits [0-9]* // / trx id .*// /.*index .* in // +SHOW ENGINE InnoDB STATUS; +set @old_sql_mode = @@sql_mode; +set sql_mode = 'ANSI_QUOTES'; +# INNODB_LOCKS only exists in innodb_plugin +#SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; +--replace_regex /.*RECORD LOCKS space id [0-9]* page no [0-9]* n bits [0-9]* // / trx id .*// /.*index .* in // +SHOW ENGINE InnoDB STATUS; +set @@sql_mode = @old_sql_mode; +--echo # con1 +connection con1; +REAP; +ROLLBACK; +disconnect con1; +--echo # default connection +connection default; +DROP TABLE `t``\""e`; +SET NAMES DEFAULT; diff --git a/mysql-test/t/partition_innodb_plugin.test b/mysql-test/t/partition_innodb_plugin.test new file mode 100644 index 00000000000..fed8c96424a --- /dev/null +++ b/mysql-test/t/partition_innodb_plugin.test @@ -0,0 +1,75 @@ +--source include/have_partition.inc +--source include/have_innodb.inc +--source suite/innodb/include/have_innodb_plugin.inc + +# +# Bug#32430 - show engine innodb status causes errors +# +SET NAMES utf8; +CREATE TABLE `t``\""e` (a INT, PRIMARY KEY (a)) +ENGINE=InnoDB +PARTITION BY RANGE (a) +SUBPARTITION BY HASH (a) +(PARTITION `p0``\""e` VALUES LESS THAN (100) + (SUBPARTITION `sp0``\""e`, + SUBPARTITION `sp1``\""e`), + PARTITION `p1``\""e` VALUES LESS THAN (MAXVALUE) + (SUBPARTITION `sp2``\""e`, + SUBPARTITION `sp3``\""e`)); +INSERT INTO `t``\""e` VALUES (0), (2), (6), (10), (14), (18), (22); +START TRANSACTION; +--echo # con1 +connect(con1,localhost,root,,); +SET NAMES utf8; +START TRANSACTION; +--echo # default connection +connection default; +UPDATE `t``\""e` SET a = 16 WHERE a = 0; +--echo # con1 +connection con1; +UPDATE `t``\""e` SET a = 8 WHERE a = 22; +let $id_1= `SELECT CONNECTION_ID()`; +SEND; +UPDATE `t``\""e` SET a = 12 WHERE a = 0; +--echo # default connection +connection default; +let $wait_timeout= 2; +let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE ID = $id_1 AND STATE = 'Searching rows for update'; +--source include/wait_condition.inc +#--echo # tested wait condition $wait_condition_reps times +# INNODB_LOCKS only exists in innodb_plugin +--sorted_result +SELECT lock_table, COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS +GROUP BY lock_table; +set @old_sql_mode = @@sql_mode; +set sql_mode = 'ANSI_QUOTES'; +--sorted_result +SELECT lock_table, COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS +GROUP BY lock_table; +set @@sql_mode = @old_sql_mode; +--error ER_LOCK_DEADLOCK +UPDATE `t``\""e` SET a = 4 WHERE a = 22; +--echo # First table reported in 'SHOW ENGINE InnoDB STATUS' +# RECORD LOCKS space id 0 page no 50 n bits 80 index `PRIMARY` in \ +# Database `test`, Table `t1`, Partition `p0`, Subpartition `sp0` \ +# trx id 0 775 +# NOTE: replace_regex is very slow on match copy/past '(.*)' regex's +# on big texts, removing a lot of text before + after makes it much faster. +#/.*in (.*) trx.*/\1/ +--replace_regex /.*RECORD LOCKS space id [0-9]* page no [0-9]* n bits [0-9]* // / trx id .*// /.*index .* in // +SHOW ENGINE InnoDB STATUS; +set @old_sql_mode = @@sql_mode; +set sql_mode = 'ANSI_QUOTES'; +--replace_regex /.*RECORD LOCKS space id [0-9]* page no [0-9]* n bits [0-9]* // / trx id .*// /.*index .* in // +SHOW ENGINE InnoDB STATUS; +set @@sql_mode = @old_sql_mode; +--echo # con1 +connection con1; +REAP; +ROLLBACK; +disconnect con1; +--echo # default connection +connection default; +DROP TABLE `t``\""e`; +SET NAMES DEFAULT; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 381a0313add..6fde16d3049 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -2277,10 +2277,9 @@ enum enum_explain_filename_mode { EXPLAIN_ALL_VERBOSE= 0, EXPLAIN_PARTITIONS_VERBOSE, - EXPLAIN_PARTITIONS_AS_COMMENT, - EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING + EXPLAIN_PARTITIONS_AS_COMMENT }; -uint explain_filename(const char *from, char *to, uint to_length, +uint explain_filename(THD* thd, const char *from, char *to, uint to_length, enum_explain_filename_mode explain_mode); uint filename_to_tablename(const char *from, char *to, uint to_length); uint tablename_to_filename(const char *from, char *to, uint to_length); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 41e76211dd8..5f718b25d60 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -70,15 +70,21 @@ static void wait_for_kill_signal(THD *thd) /** @brief Helper function for explain_filename + @param thd Thread handle + @param to_p Explained name in system_charset_info + @param end_p End of the to_p buffer + @param name Name to be converted + @param name_len Length of the name, in bytes */ -static char* add_identifier(char *to_p, const char * end_p, - const char* name, uint name_len, bool add_quotes) +static char* add_identifier(THD* thd, char *to_p, const char * end_p, + const char* name, uint name_len) { uint res; uint errors; const char *conv_name; char tmp_name[FN_REFLEN]; char conv_string[FN_REFLEN]; + int quote; DBUG_ENTER("add_identifier"); if (!name[name_len]) @@ -102,19 +108,21 @@ static char* add_identifier(char *to_p, const char * end_p, conv_name= conv_string; } - if (add_quotes && (end_p - to_p > 2)) + quote = thd ? get_quote_char_for_identifier(thd, conv_name, res - 1) : '"'; + + if (quote != EOF && (end_p - to_p > 2)) { - *(to_p++)= '`'; + *(to_p++)= (char) quote; while (*conv_name && (end_p - to_p - 1) > 0) { uint length= my_mbcharlen(system_charset_info, *conv_name); if (!length) length= 1; - if (length == 1 && *conv_name == '`') + if (length == 1 && *conv_name == (char) quote) { if ((end_p - to_p) < 3) break; - *(to_p++)= '`'; + *(to_p++)= (char) quote; *(to_p++)= *(conv_name++); } else if (((long) length) < (end_p - to_p)) @@ -125,7 +133,11 @@ static char* add_identifier(char *to_p, const char * end_p, else break; /* string already filled */ } - to_p= strnmov(to_p, "`", end_p - to_p); + if (end_p > to_p) { + *(to_p++)= (char) quote; + if (end_p > to_p) + *to_p= 0; /* terminate by NUL, but do not include it in the count */ + } } else to_p= strnmov(to_p, conv_name, end_p - to_p); @@ -145,6 +157,7 @@ static char* add_identifier(char *to_p, const char * end_p, diagnostic, error etc. when it would be useful to know what a particular file [and directory] means. Such as SHOW ENGINE STATUS, error messages etc. + @param thd Thread handle @param from Path name in my_charset_filename Null terminated in my_charset_filename, normalized to use '/' as directory separation character. @@ -161,13 +174,12 @@ static char* add_identifier(char *to_p, const char * end_p, [,[ Temporary| Renamed] Partition `p` [, Subpartition `sp`]] *| (| is really a /, and it is all in one line) - EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING -> - same as above but no quotes are added. @retval Length of returned string */ -uint explain_filename(const char *from, +uint explain_filename(THD* thd, + const char *from, char *to, uint to_length, enum_explain_filename_mode explain_mode) @@ -281,14 +293,12 @@ uint explain_filename(const char *from, { to_p= strnmov(to_p, ER(ER_DATABASE_NAME), end_p - to_p); *(to_p++)= ' '; - to_p= add_identifier(to_p, end_p, db_name, db_name_len, 1); + to_p= add_identifier(thd, to_p, end_p, db_name, db_name_len); to_p= strnmov(to_p, ", ", end_p - to_p); } else { - to_p= add_identifier(to_p, end_p, db_name, db_name_len, - (explain_mode != - EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); + to_p= add_identifier(thd, to_p, end_p, db_name, db_name_len); to_p= strnmov(to_p, ".", end_p - to_p); } } @@ -296,16 +306,13 @@ uint explain_filename(const char *from, { to_p= strnmov(to_p, ER(ER_TABLE_NAME), end_p - to_p); *(to_p++)= ' '; - to_p= add_identifier(to_p, end_p, table_name, table_name_len, 1); + to_p= add_identifier(thd, to_p, end_p, table_name, table_name_len); } else - to_p= add_identifier(to_p, end_p, table_name, table_name_len, - (explain_mode != - EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); + to_p= add_identifier(thd, to_p, end_p, table_name, table_name_len); if (part_name) { - if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT || - explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING) + if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT) to_p= strnmov(to_p, " /* ", end_p - to_p); else if (explain_mode == EXPLAIN_PARTITIONS_VERBOSE) to_p= strnmov(to_p, " ", end_p - to_p); @@ -321,20 +328,15 @@ uint explain_filename(const char *from, } to_p= strnmov(to_p, ER(ER_PARTITION_NAME), end_p - to_p); *(to_p++)= ' '; - to_p= add_identifier(to_p, end_p, part_name, part_name_len, - (explain_mode != - EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); + to_p= add_identifier(thd, to_p, end_p, part_name, part_name_len); if (subpart_name) { to_p= strnmov(to_p, ", ", end_p - to_p); to_p= strnmov(to_p, ER(ER_SUBPARTITION_NAME), end_p - to_p); *(to_p++)= ' '; - to_p= add_identifier(to_p, end_p, subpart_name, subpart_name_len, - (explain_mode != - EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); + to_p= add_identifier(thd, to_p, end_p, subpart_name, subpart_name_len); } - if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT || - explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING) + if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT) to_p= strnmov(to_p, " */", end_p - to_p); } DBUG_PRINT("exit", ("to '%s'", to)); From 2c1c01436776bf9bf98880a8ad90f0d9ed5b35fc Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 25 Sep 2009 14:52:41 +0300 Subject: [PATCH 035/146] fixed a typo in valgrind.supp --- mysql-test/valgrind.supp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 26f0d329a4a..6b10e4cb544 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -1,4 +1,4 @@ -*# Suppress some common (not fatal) errors in system libraries found by valgrind +# Suppress some common (not fatal) errors in system libraries found by valgrind # # @@ -721,3 +721,4 @@ fun:_dl_allocate_tls fun:pthread_create* } + From 864ed1efd0ae9870575b1cb35873a2c41fa7ba6e Mon Sep 17 00:00:00 2001 From: Omer BarNir Date: Fri, 25 Sep 2009 08:27:55 -0700 Subject: [PATCH 036/146] Checking in new version of 'mysql-stress-test.pl that was used for the last few month from test-extra tree. Changes include improvements to error handling and are based on WL#4685 --- mysql-test/mysql-stress-test.pl | 133 ++++++++++++++++++++++++-------- 1 file changed, 101 insertions(+), 32 deletions(-) diff --git a/mysql-test/mysql-stress-test.pl b/mysql-test/mysql-stress-test.pl index 3061506da51..c80706d9f25 100755 --- a/mysql-test/mysql-stress-test.pl +++ b/mysql-test/mysql-stress-test.pl @@ -14,17 +14,16 @@ # # Design of stress script should allow one: # -# - To stress test the mysqltest binary test engine. -# - To stress test the regular test suite and any additional test suites -# (such as mysql-test-extra-5.0). -# - To specify files with lists of tests both for initialization of -# stress db and for further testing itself. -# - To define the number of threads to be concurrently used in testing. -# - To define limitations for the test run. such as the number of tests or -# loops for execution or duration of testing, delay between test -# executions, and so forth. -# - To get a readable log file that can be used for identification of -# errors that occur during testing. +# - to use for stress testing mysqltest binary as test engine +# - to use for stress testing both regular test suite and any +# additional test suites (e.g. mysql-test-extra-5.0) +# - to specify files with lists of tests both for initialization of +# stress db and for further testing itself +# - to define number of threads that will be concurrently used in testing +# - to define limitations for test run. e.g. number of tests or loops +# for execution or duration of testing, delay between test executions, etc. +# - to get readable log file which can be used for identification of +# errors arose during testing # # Basic scenarios: # @@ -58,6 +57,8 @@ # to reproduce and debug errors that was found in continued stress # testing # +# 2009-01-28 OBN Additions and modifications per WL#4685 +# ######################################################################## use Config; @@ -114,13 +115,15 @@ $opt_stress_mode="random"; $opt_loop_count=0; $opt_test_count=0; $opt_test_duration=0; -$opt_abort_on_error=0; +# OBN: Changing abort-on-error default to -1 (for WL-4626/4685): -1 means no abort +$opt_abort_on_error=-1; $opt_sleep_time = 0; $opt_threads=1; $pid_file="mysql_stress_test.pid"; $opt_mysqltest= ($^O =~ /mswin32/i) ? "mysqltest.exe" : "mysqltest"; $opt_check_tests_file=""; -@mysqltest_args=("--silent", "-v", "--skip-safemalloc"); +# OBM adding a setting for 'max-connect-retries=7' the default of 500 is to high +@mysqltest_args=("--silent", "-v", "--skip-safemalloc", "--max-connect-retries=7"); # Client ip address $client_ip=inet_ntoa((gethostbyname(hostname()))[4]); @@ -133,24 +136,31 @@ $client_ip=~ s/\.//g; # # S1 - Critical errors - cause immediately abort of testing. These errors # could be caused by server crash or impossibility -# of test execution +# of test execution. # # S2 - Serious errors - these errors are bugs for sure as it knowns that # they shouldn't appear during stress testing # -# S3 - Non-seriuos errros - these errors could be caused by fact that +# S3 - Unknown errors - Errors were returned but we don't know what they are +# so script can't determine if they are OK or not +# +# S4 - Non-seriuos errros - these errors could be caused by fact that # we execute simultaneously statements that # affect tests executed by other threads %error_strings = ( 'Failed in mysql_real_connect()' => S1, + 'Can\'t connect' => S1, 'not found (Errcode: 2)' => S1 ); %error_codes = ( 1012 => S2, 1015 => S2, 1021 => S2, 1027 => S2, 1037 => S2, 1038 => S2, 1039 => S2, 1040 => S2, 1046 => S2, - 1180 => S2, 1181 => S2, 1203 => S2, - 1205 => S2, 1206 => S2, 1207 => S2, - 1223 => S2, 2013 => S1); + 1053 => S2, 1180 => S2, 1181 => S2, + 1203 => S2, 1205 => S4, 1206 => S2, + 1207 => S2, 1213 => S4, 1223 => S2, + 2002 => S1, 2003 => S1, 2006 => S1, + 2013 => S1 + ); share(%test_counters); %test_counters=( loop_count => 0, test_count=>0); @@ -158,6 +168,35 @@ share(%test_counters); share($exiting); $exiting=0; +# OBN Code and 'set_exit_code' function added by ES to set an exit code based on the error category returned +# in combination with the --abort-on-error value see WL#4685) +use constant ABORT_MAKEWEIGHT => 20; +share($gExitCode); +$gExitCode = 0; # global exit code +sub set_exit_code { + my $severity = shift; + my $code = 0; + if ( $severity =~ /^S(\d+)/ ) { + $severity = $1; + $code = 11 - $severity; # S1=10, S2=9, ... -- as per WL + } + else { + # we know how we call the sub: severity should be S; so, we should never be here... + print STDERR "Unknown severity format: $severity; setting to S1\n"; + $severity = 1; + } + $abort = 0; + if ( $severity <= $opt_abort_on_error ) { + # the test finished with a failure severe enough to abort. We are adding the 'abort flag' to the exit code + $code += ABORT_MAKEWEIGHT; + # but are not exiting just yet -- we need to update global exit code first + $abort = 1; + } + lock $gExitCode; # we can use lock here because the script uses threads anyway + $gExitCode = $code if $code > $gExitCode; + kill INT, $$ if $abort; # this is just a way to call sig_INT_handler: it will set exiting flag, which should do the rest +} + share($test_counters_lock); $test_counters_lock=0; share($log_file_lock); @@ -176,7 +215,8 @@ GetOptions("server-host=s", "server-logs-dir=s", "server-port=s", "threads=s", "sleep-time=s", "loop-count=i", "test-count=i", "test-duration=i", "test-suffix=s", "check-tests-file", "verbose", "log-error-details", "cleanup", "mysqltest=s", - "abort-on-error", "help") || usage(); + # OBN: (changing 'abort-on-error' to numberic for WL-4626/4685) + "abort-on-error=i" => \$opt_abort_on_error, "help") || usage(); usage() if ($opt_help); @@ -563,7 +603,15 @@ EOF if ($opt_test_duration) { - sleep($opt_test_duration); + # OBN - At this point we need to wait for the duration of the test, hoever + # we need to be able to quit if an 'abort-on-error' condition has happend + # with one of the children (WL#4685). Using solution by ES and replacing + # the 'sleep' command with a loop checking the abort condition every second + + foreach ( 1..$opt_test_duration ) { + last if $exiting; + sleep 1; + } kill INT, $$; #Interrupt child threads } @@ -580,6 +628,8 @@ EOF print "EXIT\n"; } +exit $gExitCode; # ES WL#4685: script should return a meaningful exit code + sub test_init { my ($env)=@_; @@ -681,7 +731,9 @@ sub test_execute { if (!exists($error_codes{$err_code})) { - $severity="S3"; + # OBN Changing severity level to S4 from S3 as S3 now reserved + # for the case where the error is unknown (for WL#4626/4685 + $severity="S4"; $err_code=0; } else @@ -734,6 +786,7 @@ sub test_execute { push @{$env->{test_status}}, "Severity $severity: $total"; $env->{errors}->{total}=+$total; + set_exit_code($severity); } } @@ -748,18 +801,20 @@ sub test_execute log_session_errors($env, $test_file); - if (!$exiting && ($signal_num == 2 || $signal_num == 15 || - ($opt_abort_on_error && $env->{errors}->{S1} > 0))) + #OBN Removing the case of S1 and abort-on-error as that is now set + # inside the set_exit_code function (for WL#4626/4685) + #if (!$exiting && ($signal_num == 2 || $signal_num == 15 || + # ($opt_abort_on_error && $env->{errors}->{S1} > 0))) + if (!$exiting && ($signal_num == 2 || $signal_num == 15)) { - #mysqltest was interrupted with INT or TERM signals or test was - #ran with --abort-on-error option and we got errors with severity S1 + #mysqltest was interrupted with INT or TERM signals #so we assume that we should cancel testing and exit $exiting=1; + # OBN - Adjusted text to exclude case of S1 and abort-on-error that + # was mentioned (for WL#4626/4685) print STDERR< --stress-suite-basedir= --serve --cleanup Force to clean up working directory (specified with --stress-basedir) +--abort-on-error= + Causes the script to abort if an error with severity <= number was encounterd + --log-error-details Enable errors details in the global error log file. (Default: off) From 774a8db96005864908b1b63513818ecf95844b75 Mon Sep 17 00:00:00 2001 From: Date: Sun, 27 Sep 2009 17:00:29 +0800 Subject: [PATCH 037/146] Bug #46931 rpl.rpl_get_master_version_and_clock fails on hpux11.31 Network error happened here, but it can be caused by CR_CONNECTION_ERROR, CR_CONN_HOST_ERROR, CR_SERVER_GONE_ERROR, CR_SERVER_LOST, ER_CON_COUNT_ERROR, and ER_SERVER_SHUTDOWN. We just check CR_SERVER_LOST here, so the test fails. To fix the problem, check all errors that can be cause by the master shutdown. --- .../rpl_tests/rpl_get_master_version_and_clock.test | 12 +++++++++++- .../rpl/r/rpl_get_master_version_and_clock.result | 6 ++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/mysql-test/extra/rpl_tests/rpl_get_master_version_and_clock.test b/mysql-test/extra/rpl_tests/rpl_get_master_version_and_clock.test index c79ccdd044f..89c136d8893 100644 --- a/mysql-test/extra/rpl_tests/rpl_get_master_version_and_clock.test +++ b/mysql-test/extra/rpl_tests/rpl_get_master_version_and_clock.test @@ -41,7 +41,17 @@ eval SELECT RELEASE_LOCK($debug_lock); connection slave; source include/wait_for_slave_io_error.inc; let $last_io_errno= query_get_value("show slave status", Last_IO_Errno, 1); -echo Slave_IO_Errno= $last_io_errno; +--echo Check network error happened here +if (`SELECT '$last_io_errno' = '2013' || # CR_SERVER_LOST + '$last_io_errno' = '2003' || # CR_CONN_HOST_ERROR + '$last_io_errno' = '2002' || # CR_CONNECTION_ERROR + '$last_io_errno' = '2006' || # CR_SERVER_GONE_ERROR + '$last_io_errno' = '1040' || # ER_CON_COUNT_ERROR + '$last_io_errno' = '1053' # ER_SERVER_SHUTDOWN + `) +{ + --echo NETWORK ERROR +} # Write file to make mysql-test-run.pl start up the server again --append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect diff --git a/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result b/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result index 99a0fd21f66..ae3554a5420 100644 --- a/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result +++ b/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result @@ -18,7 +18,8 @@ start slave; SELECT RELEASE_LOCK("debug_lock.before_get_UNIX_TIMESTAMP"); RELEASE_LOCK("debug_lock.before_get_UNIX_TIMESTAMP") 1 -Slave_IO_Errno= 2013 +Check network error happened here +NETWORK ERROR SELECT IS_FREE_LOCK("debug_lock.before_get_SERVER_ID"); IS_FREE_LOCK("debug_lock.before_get_SERVER_ID") 1 @@ -31,7 +32,8 @@ start slave; SELECT RELEASE_LOCK("debug_lock.before_get_SERVER_ID"); RELEASE_LOCK("debug_lock.before_get_SERVER_ID") 1 -Slave_IO_Errno= 2013 +Check network error happened here +NETWORK ERROR set global debug= ''; reset master; include/stop_slave.inc From 9256ace00a148ed5763b139dcf562f199b11695f Mon Sep 17 00:00:00 2001 From: Date: Sun, 27 Sep 2009 18:12:58 +0800 Subject: [PATCH 038/146] Bug #43913 rpl_cross_version can't pass on conflicts complainig clash with --slave-load-tm The failure is not reproduced on 5.1, so enable the 'rpl_cross_version' test. --- mysql-test/suite/rpl/t/disabled.def | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index 38fc9e21322..8cae44a3607 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -10,4 +10,3 @@ # ############################################################################## -rpl_cross_version : Bug#42311 2009-03-27 joro rpl_cross_version fails on macosx From 80f96fae63a29aa1b9ae99a8ea287a3f3b6204b4 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Sun, 27 Sep 2009 22:02:47 +0100 Subject: [PATCH 039/146] BUG#47312: RBR: Disabling key on slave breaks replication: HA_ERR_WRONG_INDEX In RBR, disabling keys on slave table will break replication when updating or deleting a record. When the slave thread tries to find the row, by searching in the storage engine, it checks whether the table has a key or not. If it has one, then the slave thread uses it to search the record. Nonetheless, the slave only checks whether the key exists or not, it does not verify if it is active. Should the key be disabled (eg, DBA has issued an ALTER TABLE ... DISABLE KEYS) then it will result in error: HA_ERR_WRONG_INDEX. This patch addresses this issue by making the slave thread also check whether the key is active or not before actually using it. --- .../rpl/r/rpl_row_disabled_slave_key.result | 26 +++++++ .../rpl/t/rpl_row_disabled_slave_key.test | 73 +++++++++++++++++++ sql/log_event.cc | 4 +- 3 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_row_disabled_slave_key.result create mode 100644 mysql-test/suite/rpl/t/rpl_row_disabled_slave_key.test diff --git a/mysql-test/suite/rpl/r/rpl_row_disabled_slave_key.result b/mysql-test/suite/rpl/r/rpl_row_disabled_slave_key.result new file mode 100644 index 00000000000..01e3dfd6508 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_row_disabled_slave_key.result @@ -0,0 +1,26 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +SET SQL_LOG_BIN=0; +CREATE TABLE t (a int, b int, c int, key(b)); +SET SQL_LOG_BIN=1; +CREATE TABLE t (a int, b int, c int); +INSERT INTO t VALUES (1,2,4); +INSERT INTO t VALUES (4,3,4); +DELETE FROM t; +DROP TABLE t; +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +CREATE TABLE t (a int, b int, c int, key(b)); +ALTER TABLE t DISABLE KEYS; +INSERT INTO t VALUES (1,2,4); +INSERT INTO t VALUES (4,3,4); +DELETE FROM t; +DROP TABLE t; diff --git a/mysql-test/suite/rpl/t/rpl_row_disabled_slave_key.test b/mysql-test/suite/rpl/t/rpl_row_disabled_slave_key.test new file mode 100644 index 00000000000..1d7e134f4f4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_disabled_slave_key.test @@ -0,0 +1,73 @@ +# BUG#47312: RBR: Disabling key on slave breaks replication: +# HA_ERR_WRONG_INDEX +# +# Description +# =========== +# +# This test case checks whether disabling a key on a slave breaks +# replication or not. +# +# Case #1, shows that while not using ALTER TABLE... DISABLE KEYS and +# the slave has no key defined while the master has one, replication +# won't break. +# +# Case #2, shows that before patch for BUG#47312, if defining key on +# slave table, and later disable it, replication would break. This +# has been fixed. +# + +-- source include/master-slave.inc +-- source include/have_binlog_format_row.inc + +# +# Case #1: master has key, but slave has not. +# Replication does not break. +# + +SET SQL_LOG_BIN=0; +CREATE TABLE t (a int, b int, c int, key(b)); +SET SQL_LOG_BIN=1; + +-- connection slave + +CREATE TABLE t (a int, b int, c int); + +-- connection master + +INSERT INTO t VALUES (1,2,4); +INSERT INTO t VALUES (4,3,4); +DELETE FROM t; + +-- sync_slave_with_master + +-- connection master +DROP TABLE t; + +-- sync_slave_with_master + +# +# Case #2: master has key, slave also has one, +# but it gets disabled sometime. +# Replication does not break anymore. +# +-- source include/master-slave-reset.inc +-- connection master + +CREATE TABLE t (a int, b int, c int, key(b)); + +-- sync_slave_with_master + +ALTER TABLE t DISABLE KEYS; + +-- connection master + +INSERT INTO t VALUES (1,2,4); +INSERT INTO t VALUES (4,3,4); +DELETE FROM t; + +-- sync_slave_with_master + +-- connection master +DROP TABLE t; + +-- sync_slave_with_master diff --git a/sql/log_event.cc b/sql/log_event.cc index 08fe3aba8ed..3c584011bfb 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -8835,11 +8835,11 @@ int Rows_log_event::find_row(const Relay_log_info *rli) */ store_record(table,record[1]); - if (table->s->keys > 0) + if (table->s->keys > 0 && table->s->keys_in_use.is_set(0)) { DBUG_PRINT("info",("locating record using primary key (index_read)")); - /* We have a key: search the table using the index */ + /* The 0th key is active: search the table using the index */ if (!table->file->inited && (error= table->file->ha_index_init(0, FALSE))) { DBUG_PRINT("info",("ha_index_init returns error %d",error)); From ea6cb65089617b0cfbb6ff09bbc6889d3052ec7a Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Sun, 27 Sep 2009 23:03:05 +0100 Subject: [PATCH 040/146] BUG#44661: rpl_ndb.rpl_ndb_circular_simplex fails because of failure to cleanup of table The test case was not dropping a table before exiting (ie, it was not cleaning itself after execution). In this case, the warning message stating that the test did not do a proper cleanup was deterministic (which can be annoying). I have found other tests cases on which mtr sporadically reports that they have not cleaned up after execution: - rpl_ndb_circular - rpl_failed_optimize In this case, the master was dropping a table but there was no synchronization between the slave and the master. This patch addresses the rpl_ndb_circular_simplex case by adding the missing DROP table. The other cases are fixed by deploying the missing sync_slave_with_master instruction. --- mysql-test/extra/rpl_tests/rpl_failed_optimize.test | 1 + mysql-test/suite/rpl_ndb/r/rpl_ndb_circular_simplex.result | 1 + mysql-test/suite/rpl_ndb/t/rpl_ndb_circular.test | 1 + mysql-test/suite/rpl_ndb/t/rpl_ndb_circular_simplex.test | 4 ++++ 4 files changed, 7 insertions(+) diff --git a/mysql-test/extra/rpl_tests/rpl_failed_optimize.test b/mysql-test/extra/rpl_tests/rpl_failed_optimize.test index 0c537ee188d..cd81f2497b8 100644 --- a/mysql-test/extra/rpl_tests/rpl_failed_optimize.test +++ b/mysql-test/extra/rpl_tests/rpl_failed_optimize.test @@ -22,3 +22,4 @@ connection master; select * from t1; commit; drop table t1; +-- sync_slave_with_master diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular_simplex.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular_simplex.result index 01f8d94da48..b6f32668c42 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular_simplex.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular_simplex.result @@ -102,3 +102,4 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +DROP TABLE t1; diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular.test index 2cc46e2420e..7b8497d8dab 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular.test +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular.test @@ -58,3 +58,4 @@ STOP SLAVE; # cleanup --connection master DROP TABLE t1; +-- sync_slave_with_master diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular_simplex.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular_simplex.test index d5ddfc2b739..eb04dc2e260 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular_simplex.test +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular_simplex.test @@ -78,3 +78,7 @@ SELECT * FROM t1 ORDER BY a; --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 # 35 # 36 # query_vertical SHOW SLAVE STATUS; + +-- connection master +DROP TABLE t1; +-- sync_slave_with_master From f8f2362bf48852b94705ae59e0ba56d1c941cab8 Mon Sep 17 00:00:00 2001 From: Date: Mon, 28 Sep 2009 10:23:06 +0800 Subject: [PATCH 041/146] BUG #46572 DROP TEMPORARY table IF EXISTS does not have a consistent behavior in ROW mode In RBR, 'DROP TEMPORARY TABLE IF EXISTS...' statement is binlogged when the table does not exist. In fact, 'DROP TEMPORARY TABLE ...' statement should never be binlogged in RBR no matter if the table exists or not. This patch addresses this by checking whether we are dropping a temporary table or not, when building the custom drop statement. --- .../extra/binlog_tests/drop_temp_table.test | 57 +++++++++++++++---- .../binlog/r/binlog_row_drop_tmp_tbl.result | 40 ++++++++----- .../binlog/r/binlog_stm_drop_tmp_tbl.result | 54 ++++++++++++------ sql/sql_table.cc | 2 +- 4 files changed, 112 insertions(+), 41 deletions(-) diff --git a/mysql-test/extra/binlog_tests/drop_temp_table.test b/mysql-test/extra/binlog_tests/drop_temp_table.test index 7d37fca2bef..5616fb4a643 100644 --- a/mysql-test/extra/binlog_tests/drop_temp_table.test +++ b/mysql-test/extra/binlog_tests/drop_temp_table.test @@ -1,27 +1,62 @@ --disable_warnings -drop database if exists `drop-temp+table-test`; +DROP DATABASE IF EXISTS `drop-temp+table-test`; --enable_warnings connect (con1,localhost,root,,); connect (con2,localhost,root,,); connection con1; -reset master; -create database `drop-temp+table-test`; -use `drop-temp+table-test`; -create temporary table shortn1 (a int); -create temporary table `table:name` (a int); -create temporary table shortn2 (a int); -select get_lock("a",10); +RESET MASTER; +CREATE DATABASE `drop-temp+table-test`; +USE `drop-temp+table-test`; +CREATE TEMPORARY TABLE shortn1 (a INT); +CREATE TEMPORARY TABLE `table:name` (a INT); +CREATE TEMPORARY TABLE shortn2 (a INT); + +############################################################################## +# BUG#46572 DROP TEMPORARY table IF EXISTS does not have a consistent behavior +# in ROW mode +# +# In RBR, 'DROP TEMPORARY TABLE ...' statement should never be binlogged no +# matter if the tables exist or not. In contrast, both in SBR and MBR, the +# statement should be always binlogged no matter if the tables exist or not. +############################################################################## +CREATE TEMPORARY TABLE tmp(c1 int); +CREATE TEMPORARY TABLE tmp1(c1 int); +CREATE TEMPORARY TABLE tmp2(c1 int); +CREATE TEMPORARY TABLE tmp3(c1 int); +CREATE TABLE t(c1 int); + +DROP TEMPORARY TABLE IF EXISTS tmp; + +--disable_warnings +# Before fixing BUG#46572, 'DROP TEMPORARY TABLE IF EXISTS...' statement was +# binlogged when the table did not exist in RBR. +DROP TEMPORARY TABLE IF EXISTS tmp; + +# In RBR, 'DROP TEMPORARY TABLE ...' statement is never binlogged no matter if +# the tables exist or not. +DROP TEMPORARY TABLE IF EXISTS tmp, tmp1; +DROP TEMPORARY TABLE tmp3; + +#In RBR, tmp2 will NOT be binlogged, because it is a temporary table. +DROP TABLE IF EXISTS tmp2, t; + +#In RBR, tmp2 will be binlogged, because it does not exist and master do not know +# whether it is a temporary table or not. +DROP TABLE IF EXISTS tmp2, t; +--enable_warnings + +SELECT GET_LOCK("a",10); disconnect con1; connection con2; # We want to SHOW BINLOG EVENTS, to know what was logged. But there is no # guarantee that logging of the terminated con1 has been done yet. # To be sure that logging has been done, we use a user lock. -select get_lock("a",10); -let $VERSION=`select version()`; +SELECT GET_LOCK("a",10); +let $VERSION=`SELECT VERSION()`; source include/show_binlog_events.inc; -drop database `drop-temp+table-test`; +DROP DATABASE `drop-temp+table-test`; # End of 4.1 tests diff --git a/mysql-test/suite/binlog/r/binlog_row_drop_tmp_tbl.result b/mysql-test/suite/binlog/r/binlog_row_drop_tmp_tbl.result index 503076d66d9..0a6ff1d4400 100644 --- a/mysql-test/suite/binlog/r/binlog_row_drop_tmp_tbl.result +++ b/mysql-test/suite/binlog/r/binlog_row_drop_tmp_tbl.result @@ -1,17 +1,31 @@ -drop database if exists `drop-temp+table-test`; -reset master; -create database `drop-temp+table-test`; -use `drop-temp+table-test`; -create temporary table shortn1 (a int); -create temporary table `table:name` (a int); -create temporary table shortn2 (a int); -select get_lock("a",10); -get_lock("a",10) +DROP DATABASE IF EXISTS `drop-temp+table-test`; +RESET MASTER; +CREATE DATABASE `drop-temp+table-test`; +USE `drop-temp+table-test`; +CREATE TEMPORARY TABLE shortn1 (a INT); +CREATE TEMPORARY TABLE `table:name` (a INT); +CREATE TEMPORARY TABLE shortn2 (a INT); +CREATE TEMPORARY TABLE tmp(c1 int); +CREATE TEMPORARY TABLE tmp1(c1 int); +CREATE TEMPORARY TABLE tmp2(c1 int); +CREATE TEMPORARY TABLE tmp3(c1 int); +CREATE TABLE t(c1 int); +DROP TEMPORARY TABLE IF EXISTS tmp; +DROP TEMPORARY TABLE IF EXISTS tmp; +DROP TEMPORARY TABLE IF EXISTS tmp, tmp1; +DROP TEMPORARY TABLE tmp3; +DROP TABLE IF EXISTS tmp2, t; +DROP TABLE IF EXISTS tmp2, t; +SELECT GET_LOCK("a",10); +GET_LOCK("a",10) 1 -select get_lock("a",10); -get_lock("a",10) +SELECT GET_LOCK("a",10); +GET_LOCK("a",10) 1 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # create database `drop-temp+table-test` -drop database `drop-temp+table-test`; +master-bin.000001 # Query # # CREATE DATABASE `drop-temp+table-test` +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TABLE t(c1 int) +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TABLE IF EXISTS `t` /* generated by server */ +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TABLE IF EXISTS tmp2, t +DROP DATABASE `drop-temp+table-test`; diff --git a/mysql-test/suite/binlog/r/binlog_stm_drop_tmp_tbl.result b/mysql-test/suite/binlog/r/binlog_stm_drop_tmp_tbl.result index 4d24b2409b9..8bbf1bccc63 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_drop_tmp_tbl.result +++ b/mysql-test/suite/binlog/r/binlog_stm_drop_tmp_tbl.result @@ -1,21 +1,43 @@ -drop database if exists `drop-temp+table-test`; -reset master; -create database `drop-temp+table-test`; -use `drop-temp+table-test`; -create temporary table shortn1 (a int); -create temporary table `table:name` (a int); -create temporary table shortn2 (a int); -select get_lock("a",10); -get_lock("a",10) +DROP DATABASE IF EXISTS `drop-temp+table-test`; +RESET MASTER; +CREATE DATABASE `drop-temp+table-test`; +USE `drop-temp+table-test`; +CREATE TEMPORARY TABLE shortn1 (a INT); +CREATE TEMPORARY TABLE `table:name` (a INT); +CREATE TEMPORARY TABLE shortn2 (a INT); +CREATE TEMPORARY TABLE tmp(c1 int); +CREATE TEMPORARY TABLE tmp1(c1 int); +CREATE TEMPORARY TABLE tmp2(c1 int); +CREATE TEMPORARY TABLE tmp3(c1 int); +CREATE TABLE t(c1 int); +DROP TEMPORARY TABLE IF EXISTS tmp; +DROP TEMPORARY TABLE IF EXISTS tmp; +DROP TEMPORARY TABLE IF EXISTS tmp, tmp1; +DROP TEMPORARY TABLE tmp3; +DROP TABLE IF EXISTS tmp2, t; +DROP TABLE IF EXISTS tmp2, t; +SELECT GET_LOCK("a",10); +GET_LOCK("a",10) 1 -select get_lock("a",10); -get_lock("a",10) +SELECT GET_LOCK("a",10); +GET_LOCK("a",10) 1 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # create database `drop-temp+table-test` -master-bin.000001 # Query # # use `drop-temp+table-test`; create temporary table shortn1 (a int) -master-bin.000001 # Query # # use `drop-temp+table-test`; create temporary table `table:name` (a int) -master-bin.000001 # Query # # use `drop-temp+table-test`; create temporary table shortn2 (a int) +master-bin.000001 # Query # # CREATE DATABASE `drop-temp+table-test` +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TEMPORARY TABLE shortn1 (a INT) +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TEMPORARY TABLE `table:name` (a INT) +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TEMPORARY TABLE shortn2 (a INT) +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TEMPORARY TABLE tmp(c1 int) +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TEMPORARY TABLE tmp1(c1 int) +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TEMPORARY TABLE tmp2(c1 int) +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TEMPORARY TABLE tmp3(c1 int) +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TABLE t(c1 int) +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TEMPORARY TABLE IF EXISTS tmp +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TEMPORARY TABLE IF EXISTS tmp +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TEMPORARY TABLE IF EXISTS tmp, tmp1 +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TEMPORARY TABLE tmp3 +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TABLE IF EXISTS tmp2, t +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TABLE IF EXISTS tmp2, t master-bin.000001 # Query # # use `drop-temp+table-test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `shortn2`,`table:name`,`shortn1` -drop database `drop-temp+table-test`; +DROP DATABASE `drop-temp+table-test`; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 08f3311be9d..6dba2f02071 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1949,7 +1949,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, being built. The string always end in a comma and the comma will be chopped off before being written to the binary log. */ - if (thd->current_stmt_binlog_row_based && !dont_log_query) + if (!drop_temporary && thd->current_stmt_binlog_row_based && !dont_log_query) { non_temp_tables_count++; /* From 90d4b21d1d8418d4e6180cddbebd90daeea5b02d Mon Sep 17 00:00:00 2001 From: Date: Mon, 28 Sep 2009 14:24:19 +0800 Subject: [PATCH 042/146] BUG#43579 mysql_upgrade tries to alter log tables on replicated database All statements executed by mysql_upgrade are binlogged and then are replicated to slave. This will result in some errors. The report of this bug has demonstrated some examples. Master and slave should be upgraded separately. All statements executed by mysql_upgrade will not be binlogged. --write-binlog and --skip-write-binlog options are added into mysql_upgrade. These options control whether sql statements are binlogged or not. --- client/mysql_upgrade.c | 27 +++++++++ client/mysqlcheck.c | 19 +++++++ mysql-test/include/have_mysql_upgrade.inc | 4 ++ .../suite/rpl/r/rpl_mysql_upgrade.result | 13 +++++ mysql-test/suite/rpl/t/rpl_mysql_upgrade.test | 56 +++++++++++++++++++ 5 files changed, 119 insertions(+) create mode 100644 mysql-test/include/have_mysql_upgrade.inc create mode 100644 mysql-test/suite/rpl/r/rpl_mysql_upgrade.result create mode 100644 mysql-test/suite/rpl/t/rpl_mysql_upgrade.test diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index cfd7ed4ea56..52c3636219d 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -54,6 +54,8 @@ static char **defaults_argv; static my_bool not_used; /* Can't use GET_BOOL without a value pointer */ +static my_bool opt_write_binlog; + #include static struct my_option my_long_options[]= @@ -124,6 +126,11 @@ static struct my_option my_long_options[]= {"verbose", 'v', "Display more output about the process", (uchar**) &opt_verbose, (uchar**) &opt_verbose, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"write-binlog", OPT_WRITE_BINLOG, + "All commands including mysqlcheck are binlogged. Enabled by default;" + "use --skip-write-binlog when commands should not be sent to replication slaves.", + (uchar**) &opt_write_binlog, (uchar**) &opt_write_binlog, 0, GET_BOOL, NO_ARG, + 1, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -448,6 +455,8 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res, int ret; File fd; char query_file_path[FN_REFLEN]; + const uchar sql_log_bin[]= "SET SQL_LOG_BIN=0;"; + DBUG_ENTER("run_query"); DBUG_PRINT("enter", ("query: %s", query)); if ((fd= create_temp_file(query_file_path, opt_tmpdir, @@ -455,6 +464,22 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res, MYF(MY_WME))) < 0) die("Failed to create temporary file for defaults"); + /* + Master and slave should be upgraded separately. All statements executed + by mysql_upgrade will not be binlogged. + 'SET SQL_LOG_BIN=0' is executed before any other statements. + */ + if (!opt_write_binlog) + { + if (my_write(fd, sql_log_bin, sizeof(sql_log_bin)-1, + MYF(MY_FNABP | MY_WME))) + { + my_close(fd, MYF(0)); + my_delete(query_file_path, MYF(0)); + die("Failed to write to '%s'", query_file_path); + } + } + if (my_write(fd, (uchar*) query, strlen(query), MYF(MY_FNABP | MY_WME))) { @@ -648,6 +673,7 @@ static int run_mysqlcheck_upgrade(void) "--check-upgrade", "--all-databases", "--auto-repair", + opt_write_binlog ? "--write-binlog" : "--skip-write-binlog", NULL); } @@ -662,6 +688,7 @@ static int run_mysqlcheck_fixnames(void) "--all-databases", "--fix-db-names", "--fix-table-names", + opt_write_binlog ? "--write-binlog" : "--skip-write-binlog", NULL); } diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 82aabd77b24..1533e602639 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -652,6 +652,17 @@ static int use_db(char *database) return 0; } /* use_db */ +static int disable_binlog() +{ + const char *stmt= "SET SQL_LOG_BIN=0"; + if (mysql_query(sock, stmt)) + { + fprintf(stderr, "Failed to %s\n", stmt); + fprintf(stderr, "Error: %s\n", mysql_error(sock)); + return 1; + } + return 0; +} static int handle_request_for_tables(char *tables, uint length) { @@ -844,6 +855,14 @@ int main(int argc, char **argv) if (dbConnect(current_host, current_user, opt_password)) exit(EX_MYSQLERR); + if (!opt_write_binlog) + { + if (disable_binlog()) { + first_error= 1; + goto end; + } + } + if (opt_auto_repair && my_init_dynamic_array(&tables4repair, sizeof(char)*(NAME_LEN*2+2),16,64)) { diff --git a/mysql-test/include/have_mysql_upgrade.inc b/mysql-test/include/have_mysql_upgrade.inc new file mode 100644 index 00000000000..8f486176018 --- /dev/null +++ b/mysql-test/include/have_mysql_upgrade.inc @@ -0,0 +1,4 @@ +--require r/have_mysql_upgrade.result +--disable_query_log +select LENGTH("$MYSQL_UPGRADE")>0 as have_mysql_upgrade; +--enable_query_log diff --git a/mysql-test/suite/rpl/r/rpl_mysql_upgrade.result b/mysql-test/suite/rpl/r/rpl_mysql_upgrade.result new file mode 100644 index 00000000000..09a9121d22c --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_mysql_upgrade.result @@ -0,0 +1,13 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +DROP DATABASE IF EXISTS `#mysql50#mysqltest-1`; +CREATE DATABASE `#mysql50#mysqltest-1`; +Master position is not changed +STOP SLAVE SQL_THREAD; +Master position has been changed +DROP DATABASE `mysqltest-1`; +DROP DATABASE `#mysql50#mysqltest-1`; diff --git a/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test b/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test new file mode 100644 index 00000000000..bf5c6d2b921 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test @@ -0,0 +1,56 @@ +############################################################################# +# BUG#43579 mysql_upgrade tries to alter log tables on replicated database +# Master and slave should be upgraded separately. All statements executed by +# mysql_upgrade will not be binlogged. --write-binlog and --skip-write-binlog +# options are added into mysql_upgrade. These options control whether sql +# statements are binlogged or not. +############################################################################# +--source include/master-slave.inc + +# Only run test if "mysql_upgrade" is found +--source include/have_mysql_upgrade.inc + +connection master; +--disable_warnings +DROP DATABASE IF EXISTS `#mysql50#mysqltest-1`; +CREATE DATABASE `#mysql50#mysqltest-1`; +--enable_warnings +sync_slave_with_master; + +connection master; +let $before_position= query_get_value(SHOW MASTER STATUS, Position, 1); + +#With '--force' option, mysql_upgrade always executes all sql statements for upgrading. +#--skip-write-binlog option disables binlog. +--exec $MYSQL_UPGRADE --skip-write-binlog --skip-verbose --force --user=root > $MYSQLTEST_VARDIR/log/mysql_upgrade.log 2>&1 +sync_slave_with_master; + +connection master; +let $after_position= query_get_value(SHOW MASTER STATUS, Position, 1); + +if (`SELECT '$before_position'='$after_position'`) +{ + echo Master position is not changed; +} + +#Some log events of the mysql_upgrade's will cause errors on slave. +connection slave; +STOP SLAVE SQL_THREAD; +source include/wait_for_slave_sql_to_stop.inc; + +connection master; +#With '--force' option, mysql_upgrade always executes all sql statements for upgrading. +--exec $MYSQL_UPGRADE --skip-verbose --force --user=root > $MYSQLTEST_VARDIR/log/mysql_upgrade.log 2>&1 + +connection master; +let $after_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $after_position= query_get_value(SHOW MASTER STATUS, Position, 1); + +if (!`SELECT '$before_position'='$after_position'`) +{ + echo Master position has been changed; +} + +DROP DATABASE `mysqltest-1`; +connection slave; +DROP DATABASE `#mysql50#mysqltest-1`; From 99bb6acb62262c2f62dbd864162241ad5ddb8c66 Mon Sep 17 00:00:00 2001 From: Martin Hansson Date: Mon, 28 Sep 2009 12:48:52 +0200 Subject: [PATCH 043/146] Bug#46958: Assertion in Diagnostics_area::set_ok_status, trigger, merge table The problem with break statements is that they have very local effects. Hence a break statement within the inner loop of a nested-loops join caused execution to proceed to the next table even though a serious error occurred. The problem was fixed by breaking out the inner loop into its own method. The change empowers all errors to terminate the execution. The errors that will now halt multi-DELETE execution altogether are - triggers returning errors - handler errors - server being killed --- mysql-test/r/delete.result | 45 +++++++++++ mysql-test/t/delete.test | 44 +++++++++++ sql/sql_class.h | 3 +- sql/sql_delete.cc | 156 +++++++++++++++++++++---------------- 4 files changed, 182 insertions(+), 66 deletions(-) diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result index eb93c69d960..0124a7da35a 100644 --- a/mysql-test/r/delete.result +++ b/mysql-test/r/delete.result @@ -279,3 +279,48 @@ ERROR 42000: Incorrect number of arguments for FUNCTION test.f1; expected 0, got DROP TABLE t1; DROP FUNCTION f1; End of 5.0 tests +# +# Bug#46958: Assertion in Diagnostics_area::set_ok_status, trigger, +# merge table +# +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +CREATE TABLE t3 ( a INT ); +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1), (2); +INSERT INTO t3 VALUES (1), (2); +CREATE TRIGGER tr1 BEFORE DELETE ON t2 +FOR EACH ROW INSERT INTO no_such_table VALUES (1); +DELETE t1, t2, t3 FROM t1, t2, t3; +ERROR 42S02: Table 'test.no_such_table' doesn't exist +SELECT * FROM t1; +a +SELECT * FROM t2; +a +1 +2 +SELECT * FROM t3; +a +1 +2 +DROP TABLE t1, t2, t3; +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +CREATE TABLE t3 ( a INT ); +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1), (2); +INSERT INTO t3 VALUES (1), (2); +CREATE TRIGGER tr1 AFTER DELETE ON t2 +FOR EACH ROW INSERT INTO no_such_table VALUES (1); +DELETE t1, t2, t3 FROM t1, t2, t3; +ERROR 42S02: Table 'test.no_such_table' doesn't exist +SELECT * FROM t1; +a +SELECT * FROM t2; +a +2 +SELECT * FROM t3; +a +1 +2 +DROP TABLE t1, t2, t3; diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test index 602e30687c8..d77f5eb128b 100644 --- a/mysql-test/t/delete.test +++ b/mysql-test/t/delete.test @@ -292,3 +292,47 @@ DROP TABLE t1; DROP FUNCTION f1; --echo End of 5.0 tests + +--echo # +--echo # Bug#46958: Assertion in Diagnostics_area::set_ok_status, trigger, +--echo # merge table +--echo # +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +CREATE TABLE t3 ( a INT ); + +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1), (2); +INSERT INTO t3 VALUES (1), (2); + +CREATE TRIGGER tr1 BEFORE DELETE ON t2 +FOR EACH ROW INSERT INTO no_such_table VALUES (1); + +--error ER_NO_SUCH_TABLE +DELETE t1, t2, t3 FROM t1, t2, t3; + +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; + +DROP TABLE t1, t2, t3; + +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +CREATE TABLE t3 ( a INT ); + +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1), (2); +INSERT INTO t3 VALUES (1), (2); + +CREATE TRIGGER tr1 AFTER DELETE ON t2 +FOR EACH ROW INSERT INTO no_such_table VALUES (1); + +--error ER_NO_SUCH_TABLE +DELETE t1, t2, t3 FROM t1, t2, t3; + +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; + +DROP TABLE t1, t2, t3; diff --git a/sql/sql_class.h b/sql/sql_class.h index c38eb17f191..b0128244030 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2907,7 +2907,8 @@ public: bool send_data(List &items); bool initialize_tables (JOIN *join); void send_error(uint errcode,const char *err); - int do_deletes(); + int do_deletes(); + int do_table_deletes(TABLE *table, bool ignore); bool send_eof(); virtual void abort(); }; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index d2f90fa9288..a81a5f4641f 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -860,22 +860,19 @@ void multi_delete::abort() -/* +/** Do delete from other tables. - Returns values: - 0 ok - 1 error + + @retval 0 ok + @retval 1 error + + @todo Is there any reason not use the normal nested-loops join? If not, and + there is no documentation supporting it, this method and callee should be + removed and there should be hooks within normal execution. */ int multi_delete::do_deletes() { - int local_error= 0, counter= 0, tmp_error; - bool will_batch; - /* - If the IGNORE option is used all non fatal errors will be translated - to warnings and we should not break the row-by-row iteration - */ - bool ignore= thd->lex->current_select->no_error; DBUG_ENTER("do_deletes"); DBUG_ASSERT(do_delete); @@ -886,79 +883,108 @@ int multi_delete::do_deletes() table_being_deleted= (delete_while_scanning ? delete_tables->next_local : delete_tables); - for (; table_being_deleted; + for (uint counter= 0; table_being_deleted; table_being_deleted= table_being_deleted->next_local, counter++) { - ha_rows last_deleted= deleted; TABLE *table = table_being_deleted->table; if (tempfiles[counter]->get(table)) + DBUG_RETURN(1); + + int local_error= + do_table_deletes(table, thd->lex->current_select->no_error); + + if (thd->killed && !local_error) + DBUG_RETURN(1); + + if (local_error == -1) // End of file + local_error = 0; + + if (local_error) + DBUG_RETURN(local_error); + } + DBUG_RETURN(0); +} + + +/** + Implements the inner loop of nested-loops join within multi-DELETE + execution. + + @param table The table from which to delete. + + @param ignore If used, all non fatal errors will be translated + to warnings and we should not break the row-by-row iteration. + + @return Status code + + @retval 0 All ok. + @retval 1 Triggers or handler reported error. + @retval -1 End of file from handler. +*/ +int multi_delete::do_table_deletes(TABLE *table, bool ignore) +{ + int local_error= 0; + READ_RECORD info; + ha_rows last_deleted= deleted; + DBUG_ENTER("do_deletes_for_table"); + init_read_record(&info, thd, table, NULL, 0, 1, FALSE); + /* + Ignore any rows not found in reference tables as they may already have + been deleted by foreign key handling + */ + info.ignore_not_found_rows= 1; + bool will_batch= !table->file->start_bulk_delete(); + while (!(local_error= info.read_record(&info)) && !thd->killed) + { + if (table->triggers && + table->triggers->process_triggers(thd, TRG_EVENT_DELETE, + TRG_ACTION_BEFORE, FALSE)) { - local_error=1; + local_error= 1; break; } - - READ_RECORD info; - init_read_record(&info, thd, table, NULL, 0, 1, FALSE); - /* - Ignore any rows not found in reference tables as they may already have - been deleted by foreign key handling - */ - info.ignore_not_found_rows= 1; - will_batch= !table->file->start_bulk_delete(); - while (!(local_error=info.read_record(&info)) && !thd->killed) + + local_error= table->file->ha_delete_row(table->record[0]); + if (local_error && !ignore) { + table->file->print_error(local_error, MYF(0)); + break; + } + + /* + Increase the reported number of deleted rows only if no error occurred + during ha_delete_row. + Also, don't execute the AFTER trigger if the row operation failed. + */ + if (!local_error) + { + deleted++; if (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_DELETE, - TRG_ACTION_BEFORE, FALSE)) + TRG_ACTION_AFTER, FALSE)) { local_error= 1; break; } - - local_error= table->file->ha_delete_row(table->record[0]); - if (local_error && !ignore) - { - table->file->print_error(local_error,MYF(0)); - break; - } - - /* - Increase the reported number of deleted rows only if no error occurred - during ha_delete_row. - Also, don't execute the AFTER trigger if the row operation failed. - */ - if (!local_error) - { - deleted++; - if (table->triggers && - table->triggers->process_triggers(thd, TRG_EVENT_DELETE, - TRG_ACTION_AFTER, FALSE)) - { - local_error= 1; - break; - } - } } - if (will_batch && (tmp_error= table->file->end_bulk_delete())) - { - if (!local_error) - { - local_error= tmp_error; - table->file->print_error(local_error,MYF(0)); - } - } - if (last_deleted != deleted && !table->file->has_transactions()) - thd->transaction.stmt.modified_non_trans_table= TRUE; - end_read_record(&info); - if (thd->killed && !local_error) - local_error= 1; - if (local_error == -1) // End of file - local_error = 0; } + if (will_batch) + { + int tmp_error= table->file->end_bulk_delete(); + if (tmp_error && !local_error) + { + local_error= tmp_error; + table->file->print_error(local_error, MYF(0)); + } + } + if (last_deleted != deleted && !table->file->has_transactions()) + thd->transaction.stmt.modified_non_trans_table= TRUE; + + end_read_record(&info); + DBUG_RETURN(local_error); } - /* Send ok to the client From 4b17ef621fcf02721d08c2e14437937a6b844b57 Mon Sep 17 00:00:00 2001 From: Martin Hansson Date: Mon, 28 Sep 2009 13:25:47 +0200 Subject: [PATCH 044/146] Bug#35996: SELECT + SHOW VIEW should be enough to display view definition During SHOW CREATE VIEW there is no reason to 'anonymize' errors that name objects that a user does not have access to. Moreover it was inconsistently implemented. For example base tables being referenced from a view appear to be ok, but not views. The manual on the other hand is clear: If a user has the privileges SELECT and SHOW VIEW, the view definition is available to that user, period. The fix changes the behavior to support the manual. --- mysql-test/r/information_schema_db.result | 7 +- mysql-test/r/view_grant.result | 182 +++++++++++++++++++++- mysql-test/t/information_schema_db.test | 1 - mysql-test/t/view_grant.test | 121 ++++++++++++++ sql/sql_acl.cc | 3 +- sql/sql_show.cc | 143 ++++++++++++++--- sql/table.cc | 9 +- 7 files changed, 437 insertions(+), 29 deletions(-) diff --git a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result index 6305f8cd47a..2e3fa7f4acd 100644 --- a/mysql-test/r/information_schema_db.result +++ b/mysql-test/r/information_schema_db.result @@ -139,7 +139,7 @@ show create view testdb_1.v7; View Create View character_set_client collation_connection v7 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such_user`@`no_such_host` SQL SECURITY DEFINER VIEW `v7` AS select `testdb_1`.`t2`.`f1` AS `f1` from `t2` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'testdb_1.v7' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no_such_user'@'no_such_host') does not exist show fields from testdb_1.v7; Field Type Null Key Default Extra f1 char(4) YES NULL @@ -169,7 +169,7 @@ show create view testdb_1.v7; View Create View character_set_client collation_connection v7 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such_user`@`no_such_host` SQL SECURITY DEFINER VIEW `v7` AS select `testdb_1`.`t2`.`f1` AS `f1` from `t2` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'testdb_1.v7' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no_such_user'@'no_such_host') does not exist revoke insert(f1) on v3 from testdb_2@localhost; revoke show view on v5 from testdb_2@localhost; use testdb_1; @@ -187,7 +187,8 @@ ERROR 42000: SELECT command denied to user 'testdb_2'@'localhost' for table 'v7' show create view testdb_1.v7; ERROR 42000: SELECT command denied to user 'testdb_2'@'localhost' for table 'v7' show create view v4; -ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +View Create View character_set_client collation_connection +v4 CREATE ALGORITHM=UNDEFINED DEFINER=`testdb_2`@`localhost` SQL SECURITY DEFINER VIEW `v4` AS select `v3`.`f1` AS `f1`,`v3`.`f2` AS `f2` from `testdb_1`.`v3` latin1 latin1_swedish_ci show fields from v4; Field Type Null Key Default Extra f1 char(4) YES NULL diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index 7e280fa2fe5..4e43f52d8d7 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -606,7 +606,7 @@ SHOW CREATE VIEW v; View Create View character_set_client collation_connection v CREATE ALGORITHM=UNDEFINED DEFINER=`no-such-user`@`localhost` SQL SECURITY DEFINER VIEW `v` AS select `test`.`t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'test.v' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no-such-user'@'localhost') does not exist SELECT * FROM v; ERROR HY000: The user specified as a definer ('no-such-user'@'localhost') does not exist DROP VIEW v; @@ -963,7 +963,7 @@ SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such`@`user_1` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist ALTER ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1; Warnings: Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist @@ -971,7 +971,7 @@ SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=MERGE DEFINER=`no_such`@`user_1` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist ALTER ALGORITHM=TEMPTABLE DEFINER=no_such@user_2 VIEW v1 AS SELECT * FROM t1; Warnings: Note 1449 The user specified as a definer ('no_such'@'user_2') does not exist @@ -979,7 +979,7 @@ SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=TEMPTABLE DEFINER=`no_such`@`user_2` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no_such'@'user_2') does not exist DROP VIEW v1; DROP TABLE t1; CREATE USER mysqluser1@localhost; @@ -1044,3 +1044,177 @@ DROP DATABASE mysqltest1; DROP VIEW test.v3; DROP USER mysqluser1@localhost; USE test; +# +# Bug#35996: SELECT + SHOW VIEW should be enough to display view +# definition +# +CREATE USER mysqluser1@localhost; +CREATE DATABASE mysqltest1; +CREATE DATABASE mysqltest2; +GRANT USAGE, SELECT, CREATE VIEW, SHOW VIEW +ON mysqltest2.* TO mysqluser1@localhost; +USE mysqltest1; +CREATE TABLE t1( a INT ); +CREATE TABLE t2( a INT, b INT ); +CREATE FUNCTION f1() RETURNS INT RETURN 1; +CREATE VIEW v1 AS SELECT 1 AS a; +CREATE VIEW v2 AS SELECT 1 AS a, 2 AS b; +GRANT SELECT ON TABLE t1 TO mysqluser1@localhost; +GRANT SELECT (a, b) ON TABLE t2 TO mysqluser1@localhost; +GRANT EXECUTE ON FUNCTION f1 TO mysqluser1@localhost; +GRANT SELECT ON TABLE v1 TO mysqluser1@localhost; +GRANT SELECT (a, b) ON TABLE v2 TO mysqluser1@localhost; +CREATE VIEW v_t1 AS SELECT * FROM t1; +CREATE VIEW v_t2 AS SELECT * FROM t2; +CREATE VIEW v_f1 AS SELECT f1() AS a; +CREATE VIEW v_v1 AS SELECT * FROM v1; +CREATE VIEW v_v2 AS SELECT * FROM v2; +GRANT SELECT, SHOW VIEW ON v_t1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_t2 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_f1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_v1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_v2 TO mysqluser1@localhost; +CREATE VIEW v_mysqluser1_t1 AS SELECT * FROM mysqltest1.t1; +CREATE VIEW v_mysqluser1_t2 AS SELECT * FROM mysqltest1.t2; +CREATE VIEW v_mysqluser1_f1 AS SELECT mysqltest1.f1() AS a; +CREATE VIEW v_mysqluser1_v1 AS SELECT * FROM mysqltest1.v1; +CREATE VIEW v_mysqluser1_v2 AS SELECT * FROM mysqltest1.v2; +SHOW CREATE VIEW mysqltest1.v_t1; +View Create View character_set_client collation_connection +v_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_t2; +View Create View character_set_client collation_connection +v_t2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t2` AS select `mysqltest1`.`t2`.`a` AS `a`,`mysqltest1`.`t2`.`b` AS `b` from `mysqltest1`.`t2` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_f1; +View Create View character_set_client collation_connection +v_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_f1` AS select `f1`() AS `a` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_v1; +View Create View character_set_client collation_connection +v_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_v2; +View Create View character_set_client collation_connection +v_v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v2` AS select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `mysqltest1`.`v2` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_t1; +View Create View character_set_client collation_connection +v_mysqluser1_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_t2; +View Create View character_set_client collation_connection +v_mysqluser1_t2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t2` AS select `mysqltest1`.`t2`.`a` AS `a`,`mysqltest1`.`t2`.`b` AS `b` from `mysqltest1`.`t2` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_f1; +View Create View character_set_client collation_connection +v_mysqluser1_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_f1` AS select `mysqltest1`.`f1`() AS `a` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_v1; +View Create View character_set_client collation_connection +v_mysqluser1_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_v2; +View Create View character_set_client collation_connection +v_mysqluser1_v2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v2` AS select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `mysqltest1`.`v2` latin1 latin1_swedish_ci +REVOKE SELECT ON TABLE t1 FROM mysqluser1@localhost; +REVOKE SELECT (a) ON TABLE t2 FROM mysqluser1@localhost; +REVOKE EXECUTE ON FUNCTION f1 FROM mysqluser1@localhost; +REVOKE SELECT ON TABLE v1 FROM mysqluser1@localhost; +SHOW CREATE VIEW mysqltest1.v_t1; +View Create View character_set_client collation_connection +v_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_t2; +View Create View character_set_client collation_connection +v_t2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t2` AS select `mysqltest1`.`t2`.`a` AS `a`,`mysqltest1`.`t2`.`b` AS `b` from `mysqltest1`.`t2` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_f1; +View Create View character_set_client collation_connection +v_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_f1` AS select `f1`() AS `a` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_v1; +View Create View character_set_client collation_connection +v_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_v2; +View Create View character_set_client collation_connection +v_v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v2` AS select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `mysqltest1`.`v2` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_t1; +View Create View character_set_client collation_connection +v_mysqluser1_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_t2; +View Create View character_set_client collation_connection +v_mysqluser1_t2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t2` AS select `mysqltest1`.`t2`.`a` AS `a`,`mysqltest1`.`t2`.`b` AS `b` from `mysqltest1`.`t2` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_f1; +View Create View character_set_client collation_connection +v_mysqluser1_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_f1` AS select `mysqltest1`.`f1`() AS `a` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_v1; +View Create View character_set_client collation_connection +v_mysqluser1_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_v2; +View Create View character_set_client collation_connection +v_mysqluser1_v2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v2` AS select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `mysqltest1`.`v2` latin1 latin1_swedish_ci +# Testing the case when the views reference missing objects. +# Obviously, there are no privileges to check for, so we +# need only each object type once. +DROP TABLE t1; +DROP FUNCTION f1; +DROP VIEW v1; +SHOW CREATE VIEW mysqltest1.v_t1; +View Create View character_set_client collation_connection +v_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW mysqltest1.v_f1; +View Create View character_set_client collation_connection +v_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_f1` AS select `f1`() AS `a` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest1.v_f1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW mysqltest1.v_v1; +View Create View character_set_client collation_connection +v_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest1.v_v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW v_mysqluser1_t1; +View Create View character_set_client collation_connection +v_mysqluser1_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW v_mysqluser1_f1; +View Create View character_set_client collation_connection +v_mysqluser1_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_f1` AS select `mysqltest1`.`f1`() AS `a` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_f1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW v_mysqluser1_v1; +View Create View character_set_client collation_connection +v_mysqluser1_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +REVOKE SHOW VIEW ON v_t1 FROM mysqluser1@localhost; +REVOKE SHOW VIEW ON v_f1 FROM mysqluser1@localhost; +REVOKE SHOW VIEW ON v_v1 FROM mysqluser1@localhost; +SHOW CREATE VIEW mysqltest1.v_t1; +ERROR 42000: SHOW VIEW command denied to user 'mysqluser1'@'localhost' for table 'v_t1' +SHOW CREATE VIEW mysqltest1.v_f1; +ERROR 42000: SHOW VIEW command denied to user 'mysqluser1'@'localhost' for table 'v_f1' +SHOW CREATE VIEW mysqltest1.v_v1; +ERROR 42000: SHOW VIEW command denied to user 'mysqluser1'@'localhost' for table 'v_v1' +SHOW CREATE VIEW v_mysqluser1_t1; +View Create View character_set_client collation_connection +v_mysqluser1_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW v_mysqluser1_f1; +View Create View character_set_client collation_connection +v_mysqluser1_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_f1` AS select `mysqltest1`.`f1`() AS `a` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_f1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW v_mysqluser1_v1; +View Create View character_set_client collation_connection +v_mysqluser1_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +DROP USER mysqluser1@localhost; +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; +USE test; +CREATE TABLE t1( a INT ); +CREATE DEFINER = no_such_user@no_such_host VIEW v1 AS SELECT * FROM t1; +Warnings: +Note 1449 The user specified as a definer ('no_such_user'@'no_such_host') does not exist +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such_user`@`no_such_host` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci +Warnings: +Note 1449 The user specified as a definer ('no_such_user'@'no_such_host') does not exist +DROP TABLE t1; +DROP VIEW v1; diff --git a/mysql-test/t/information_schema_db.test b/mysql-test/t/information_schema_db.test index 0ff1d05f364..2f651057e5c 100644 --- a/mysql-test/t/information_schema_db.test +++ b/mysql-test/t/information_schema_db.test @@ -184,7 +184,6 @@ show fields from testdb_1.v7; --error ER_TABLEACCESS_DENIED_ERROR show create view testdb_1.v7; ---error ER_VIEW_NO_EXPLAIN show create view v4; #--error ER_VIEW_NO_EXPLAIN show fields from v4; diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index 824c67d867e..2ad488b7529 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -1382,6 +1382,127 @@ DROP VIEW test.v3; DROP USER mysqluser1@localhost; USE test; +--echo # +--echo # Bug#35996: SELECT + SHOW VIEW should be enough to display view +--echo # definition +--echo # +-- source include/not_embedded.inc +CREATE USER mysqluser1@localhost; +CREATE DATABASE mysqltest1; +CREATE DATABASE mysqltest2; +GRANT USAGE, SELECT, CREATE VIEW, SHOW VIEW +ON mysqltest2.* TO mysqluser1@localhost; + +USE mysqltest1; + +CREATE TABLE t1( a INT ); +CREATE TABLE t2( a INT, b INT ); +CREATE FUNCTION f1() RETURNS INT RETURN 1; +CREATE VIEW v1 AS SELECT 1 AS a; +CREATE VIEW v2 AS SELECT 1 AS a, 2 AS b; + +GRANT SELECT ON TABLE t1 TO mysqluser1@localhost; +GRANT SELECT (a, b) ON TABLE t2 TO mysqluser1@localhost; +GRANT EXECUTE ON FUNCTION f1 TO mysqluser1@localhost; +GRANT SELECT ON TABLE v1 TO mysqluser1@localhost; +GRANT SELECT (a, b) ON TABLE v2 TO mysqluser1@localhost; + +CREATE VIEW v_t1 AS SELECT * FROM t1; +CREATE VIEW v_t2 AS SELECT * FROM t2; +CREATE VIEW v_f1 AS SELECT f1() AS a; +CREATE VIEW v_v1 AS SELECT * FROM v1; +CREATE VIEW v_v2 AS SELECT * FROM v2; + +GRANT SELECT, SHOW VIEW ON v_t1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_t2 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_f1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_v1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_v2 TO mysqluser1@localhost; + +--connect (connection1, localhost, mysqluser1,, mysqltest2) +CREATE VIEW v_mysqluser1_t1 AS SELECT * FROM mysqltest1.t1; +CREATE VIEW v_mysqluser1_t2 AS SELECT * FROM mysqltest1.t2; +CREATE VIEW v_mysqluser1_f1 AS SELECT mysqltest1.f1() AS a; +CREATE VIEW v_mysqluser1_v1 AS SELECT * FROM mysqltest1.v1; +CREATE VIEW v_mysqluser1_v2 AS SELECT * FROM mysqltest1.v2; + +SHOW CREATE VIEW mysqltest1.v_t1; +SHOW CREATE VIEW mysqltest1.v_t2; +SHOW CREATE VIEW mysqltest1.v_f1; +SHOW CREATE VIEW mysqltest1.v_v1; +SHOW CREATE VIEW mysqltest1.v_v2; + +SHOW CREATE VIEW v_mysqluser1_t1; +SHOW CREATE VIEW v_mysqluser1_t2; +SHOW CREATE VIEW v_mysqluser1_f1; +SHOW CREATE VIEW v_mysqluser1_v1; +SHOW CREATE VIEW v_mysqluser1_v2; + +--connection default +REVOKE SELECT ON TABLE t1 FROM mysqluser1@localhost; +REVOKE SELECT (a) ON TABLE t2 FROM mysqluser1@localhost; +REVOKE EXECUTE ON FUNCTION f1 FROM mysqluser1@localhost; +REVOKE SELECT ON TABLE v1 FROM mysqluser1@localhost; + +--connection connection1 +SHOW CREATE VIEW mysqltest1.v_t1; +SHOW CREATE VIEW mysqltest1.v_t2; +SHOW CREATE VIEW mysqltest1.v_f1; +SHOW CREATE VIEW mysqltest1.v_v1; +SHOW CREATE VIEW mysqltest1.v_v2; + +SHOW CREATE VIEW v_mysqluser1_t1; +SHOW CREATE VIEW v_mysqluser1_t2; +SHOW CREATE VIEW v_mysqluser1_f1; +SHOW CREATE VIEW v_mysqluser1_v1; +SHOW CREATE VIEW v_mysqluser1_v2; + +--connection default +--echo # Testing the case when the views reference missing objects. +--echo # Obviously, there are no privileges to check for, so we +--echo # need only each object type once. +DROP TABLE t1; +DROP FUNCTION f1; +DROP VIEW v1; + +--connection connection1 +SHOW CREATE VIEW mysqltest1.v_t1; +SHOW CREATE VIEW mysqltest1.v_f1; +SHOW CREATE VIEW mysqltest1.v_v1; + +SHOW CREATE VIEW v_mysqluser1_t1; +SHOW CREATE VIEW v_mysqluser1_f1; +SHOW CREATE VIEW v_mysqluser1_v1; + +--connection default +REVOKE SHOW VIEW ON v_t1 FROM mysqluser1@localhost; +REVOKE SHOW VIEW ON v_f1 FROM mysqluser1@localhost; +REVOKE SHOW VIEW ON v_v1 FROM mysqluser1@localhost; + +--connection connection1 +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE VIEW mysqltest1.v_t1; +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE VIEW mysqltest1.v_f1; +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE VIEW mysqltest1.v_v1; +SHOW CREATE VIEW v_mysqluser1_t1; +SHOW CREATE VIEW v_mysqluser1_f1; +SHOW CREATE VIEW v_mysqluser1_v1; + +--disconnect connection1 +--connection default +DROP USER mysqluser1@localhost; +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; +USE test; + +CREATE TABLE t1( a INT ); +CREATE DEFINER = no_such_user@no_such_host VIEW v1 AS SELECT * FROM t1; +SHOW CREATE VIEW v1; +DROP TABLE t1; +DROP VIEW v1; + # Wait till we reached the initial number of concurrent sessions --source include/wait_until_count_sessions.inc diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index ab18a2d1d04..d7d662f912d 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -4072,8 +4072,7 @@ bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref, db_name= table_ref->view_db.str; table_name= table_ref->view_name.str; if (table_ref->belong_to_view && - (thd->lex->sql_command == SQLCOM_SHOW_FIELDS || - thd->lex->sql_command == SQLCOM_SHOW_CREATE)) + thd->lex->sql_command == SQLCOM_SHOW_FIELDS) { view_privs= get_column_grant(thd, grant, db_name, table_name, name); if (view_privs & VIEW_ANY_ACL) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bb377e676e2..a065d953b67 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -581,6 +581,126 @@ find_files(THD *thd, List *files, const char *db, } +/** + An Internal_error_handler that suppresses errors regarding views' + underlying tables that occur during privilege checking within SHOW CREATE + VIEW commands. This happens in the cases when + + - A view's underlying table (e.g. referenced in its SELECT list) does not + exist. There should not be an error as no attempt was made to access it + per se. + + - Access is denied for some table, column, function or stored procedure + such as mentioned above. This error gets raised automatically, since we + can't untangle its access checking from that of the view itself. + */ +class Show_create_error_handler : public Internal_error_handler { + + TABLE_LIST *m_top_view; + bool m_handling; + Security_context *m_sctx; + + char m_view_access_denied_message[MYSQL_ERRMSG_SIZE]; + char *m_view_access_denied_message_ptr; + +public: + + /** + Creates a new Show_create_error_handler for the particular security + context and view. + + @thd Thread context, used for security context information if needed. + @top_view The view. We do not verify at this point that top_view is in + fact a view since, alas, these things do not stay constant. + */ + explicit Show_create_error_handler(THD *thd, TABLE_LIST *top_view) : + m_top_view(top_view), m_handling(FALSE), + m_view_access_denied_message_ptr(NULL) + { + + m_sctx = test(m_top_view->security_ctx) ? + m_top_view->security_ctx : thd->security_ctx; + } + + /** + Lazy instantiation of 'view access denied' message. The purpose of the + Show_create_error_handler is to hide details of underlying tables for + which we have no privileges behind ER_VIEW_INVALID messages. But this + obviously does not apply if we lack privileges on the view itself. + Unfortunately the information about for which table privilege checking + failed is not available at this point. The only way for us to check is by + reconstructing the actual error message and see if it's the same. + */ + char* get_view_access_denied_message() + { + if (!m_view_access_denied_message_ptr) + { + m_view_access_denied_message_ptr= m_view_access_denied_message; + my_snprintf(m_view_access_denied_message, MYSQL_ERRMSG_SIZE, + ER(ER_TABLEACCESS_DENIED_ERROR), "SHOW VIEW", + m_sctx->priv_user, + m_sctx->host_or_ip, m_top_view->get_table_name()); + } + return m_view_access_denied_message_ptr; + } + + bool handle_error(uint sql_errno, const char *message, + MYSQL_ERROR::enum_warning_level level, THD *thd) { + /* + The handler does not handle the errors raised by itself. + At this point we know if top_view is really a view. + */ + if (m_handling || !m_top_view->view) + return FALSE; + + m_handling= TRUE; + + bool is_handled; + + switch (sql_errno) + { + case ER_TABLEACCESS_DENIED_ERROR: + if (!strcmp(get_view_access_denied_message(), message)) + { + /* Access to top view is not granted, don't interfere. */ + is_handled= FALSE; + break; + } + case ER_COLUMNACCESS_DENIED_ERROR: + case ER_VIEW_NO_EXPLAIN: /* Error was anonymized, ignore all the same. */ + case ER_PROCACCESS_DENIED_ERROR: + is_handled= TRUE; + break; + + case ER_NO_SUCH_TABLE: + /* Established behavior: warn if underlying tables are missing. */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_VIEW_INVALID, + ER(ER_VIEW_INVALID), + m_top_view->get_db_name(), + m_top_view->get_table_name()); + is_handled= TRUE; + break; + + case ER_SP_DOES_NOT_EXIST: + /* Established behavior: warn if underlying functions are missing. */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_VIEW_INVALID, + ER(ER_VIEW_INVALID), + m_top_view->get_db_name(), + m_top_view->get_table_name()); + is_handled= TRUE; + break; + default: + is_handled= FALSE; + } + + m_handling= FALSE; + return is_handled; + } +}; + + bool mysqld_show_create(THD *thd, TABLE_LIST *table_list) { @@ -594,26 +714,13 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) /* We want to preserve the tree for views. */ thd->lex->view_prepare_mode= TRUE; - /* Only one table for now, but VIEW can involve several tables */ - if (open_normal_and_derived_tables(thd, table_list, 0)) { - if (!table_list->view || - (thd->is_error() && thd->main_da.sql_errno() != ER_VIEW_INVALID)) + Show_create_error_handler view_error_suppressor(thd, table_list); + thd->push_internal_handler(&view_error_suppressor); + bool error= open_normal_and_derived_tables(thd, table_list, 0); + thd->pop_internal_handler(); + if (error && thd->main_da.is_error()) DBUG_RETURN(TRUE); - - /* - Clear all messages with 'error' level status and - issue a warning with 'warning' level status in - case of invalid view and last error is ER_VIEW_INVALID - */ - mysql_reset_errors(thd, true); - thd->clear_error(); - - push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN, - ER_VIEW_INVALID, - ER(ER_VIEW_INVALID), - table_list->view_db.str, - table_list->view_name.str); } /* TODO: add environment variables show when it become possible */ diff --git a/sql/table.cc b/sql/table.cc index 4f647618979..04f2a3fbcf8 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3338,7 +3338,12 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type) /** - Hide errors which show view underlying table information + Hide errors which show view underlying table information. + There are currently two mechanisms at work that handle errors for views, + this one and a more general mechanism based on an Internal_error_handler, + see Show_create_error_handler. The latter handles errors encountered during + execution of SHOW CREATE VIEW, while the machanism using this method is + handles SELECT from views. The two methods should not clash. @param[in,out] thd thread handler @@ -3347,6 +3352,8 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type) void TABLE_LIST::hide_view_error(THD *thd) { + if (thd->get_internal_handler()) + return; /* Hide "Unknown column" or "Unknown function" error */ DBUG_ASSERT(thd->is_error()); From 197182d74904e2ef88e95675d81c0c39782c635d Mon Sep 17 00:00:00 2001 From: "Tatiana A. Nurnberg" Date: Mon, 28 Sep 2009 05:41:10 -0700 Subject: [PATCH 045/146] Bug#43746: YACC return wrong query string when parse 'load data infile' sql statement "load data" statements were written to the binlog as a mix of the original statement and bits recreated from parse-info. This relied on implementation details and broke with IGNORE_SPACES and versioned comments. We now completely resynthesize the query for LOAD DATA for binlog (which among other things normalizes them somewhat with regard to case, spaces, etc.). We have already parsed the query properly, so we make use of that rather than mix-and-match string literals and parsed items. This should make us safe with regard to versioned comments, even those spanning multiple tokens. Also no longer affected by IGNORE_SPACES. --- mysql-test/r/mysqlbinlog.result | 30 ++--- .../binlog/r/binlog_killed_simulate.result | 2 +- .../r/binlog_row_mix_innodb_myisam.result | 2 +- .../binlog/r/binlog_stm_blackhole.result | 2 +- .../r/binlog_stm_mix_innodb_myisam.result | 4 +- .../suite/rpl/r/rpl_innodb_mixed_dml.result | 2 +- mysql-test/suite/rpl/r/rpl_loaddata.result | 4 +- .../suite/rpl/r/rpl_loaddata_fatal.result | 2 +- .../suite/rpl/r/rpl_loaddata_map.result | 2 +- .../suite/rpl/r/rpl_loaddatalocal.result | 28 +++++ mysql-test/suite/rpl/r/rpl_stm_log.result | 6 +- mysql-test/suite/rpl/t/rpl_loaddatalocal.test | 70 +++++++++++ mysql-test/t/mysqlbinlog.test | 5 +- sql/log_event.cc | 29 +++-- sql/log_event.h | 6 +- sql/sql_lex.h | 7 -- sql/sql_load.cc | 114 ++++++++++++++++-- sql/sql_yacc.yy | 12 +- 18 files changed, 254 insertions(+), 73 deletions(-) diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index 295a2f41d40..3a373734fc4 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -44,16 +44,16 @@ SET TIMESTAMP=1000000000/*!*/; insert into t2 values () /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; DELIMITER ; # End of log file @@ -144,16 +144,16 @@ SET TIMESTAMP=1000000000/*!*/; insert into t2 values () /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; DELIMITER ; # End of log file @@ -359,29 +359,29 @@ SET @@session.collation_database=DEFAULT/*!*/; create table t1 (a varchar(64) character set utf8) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) /*!*/; SET TIMESTAMP=1000000000/*!*/; SET @@session.collation_database=7/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) /*!*/; SET TIMESTAMP=1000000000/*!*/; SET @@session.collation_database=DEFAULT/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) /*!*/; SET TIMESTAMP=1000000000/*!*/; SET @@session.collation_database=7/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-a-0' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-a-0' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) /*!*/; SET TIMESTAMP=1000000000/*!*/; SET @@session.collation_database=DEFAULT/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-b-0' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-b-0' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-c-0' INTO table t1 character set koi8r +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-c-0' INTO TABLE `t1` CHARACTER SET koi8r FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) /*!*/; SET TIMESTAMP=1000000000/*!*/; drop table t1 diff --git a/mysql-test/suite/binlog/r/binlog_killed_simulate.result b/mysql-test/suite/binlog/r/binlog_killed_simulate.result index 634d3f62814..df04f5129cf 100644 --- a/mysql-test/suite/binlog/r/binlog_killed_simulate.result +++ b/mysql-test/suite/binlog/r/binlog_killed_simulate.result @@ -19,7 +19,7 @@ ERROR 70100: Query execution was interrupted show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# -master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */ ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t2` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a, b) ;file_id=# select (@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) is not null; diff --git a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result index 9ae5121f618..2d11fec5787 100644 --- a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result @@ -917,7 +917,7 @@ master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci -master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t4` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a, @b) SET b=((@b) + `bug27417`(2)) ;file_id=# master-bin.000001 # Query # # ROLLBACK drop trigger trg_del_t2; drop table t1,t2,t3,t4,t5; diff --git a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result index f3a01f66fc2..434c1b0896f 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result +++ b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result @@ -127,7 +127,7 @@ master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; create table t2 (a varchar(200)) engine=blackhole master-bin.000001 # Query # # BEGIN master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=581 -master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/words.dat' into table t2 ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE `t2` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) ;file_id=# master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; alter table t1 add b int master-bin.000001 # Query # # use `test`; alter table t1 drop b diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result index c15374dc1c6..06c57fba2e7 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result @@ -625,7 +625,7 @@ master-bin.000001 # Query # # BEGIN master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# master-bin.000001 # Intvar # # INSERT_ID=10 -master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t4` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a, @b) SET b=((@b) + `bug27417`(2)) ;file_id=# master-bin.000001 # Query # # ROLLBACK /* the output must denote there is the query */; drop trigger trg_del_t2; @@ -863,7 +863,7 @@ master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci -master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t4` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a, @b) SET b=((@b) + `bug27417`(2)) ;file_id=# master-bin.000001 # Query # # ROLLBACK drop trigger trg_del_t2; drop table t1,t2,t3,t4,t5; diff --git a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result index 81c486cb43c..3a1c2b68b01 100644 --- a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result +++ b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result @@ -885,7 +885,7 @@ master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2 master-bin.000001 # Xid 1 # # master-bin.000001 # Query 1 # BEGIN master-bin.000001 # Begin_load_query 1 # ;file_id=#;block_len=# -master-bin.000001 # Execute_load_query 1 # use `test_rpl`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/std_data/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ;file_id=# +master-bin.000001 # Execute_load_query 1 # use `test_rpl`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/std_data/rpl_mixed.dat' INTO TABLE `t1` FIELDS TERMINATED BY '|' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a, b) ;file_id=# master-bin.000001 # Xid 1 # # master-bin.000001 # Query 1 # BEGIN master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1 diff --git a/mysql-test/suite/rpl/r/rpl_loaddata.result b/mysql-test/suite/rpl/r/rpl_loaddata.result index d7a02bc84a5..0653936f0ec 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddata.result +++ b/mysql-test/suite/rpl/r/rpl_loaddata.result @@ -36,7 +36,7 @@ set global sql_slave_skip_counter=1; start slave; show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error -# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1797 # # master-bin.000001 Yes Yes # 0 0 1797 # None 0 No # No 0 0 +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 2009 # # master-bin.000001 Yes Yes # 0 0 2009 # None 0 No # No 0 0 set sql_log_bin=0; delete from t1; set sql_log_bin=1; @@ -46,7 +46,7 @@ change master to master_user='test'; change master to master_user='root'; show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error -# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1832 # # master-bin.000001 No No # 0 0 1832 # None 0 No # No 0 0 +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 2044 # # master-bin.000001 No No # 0 0 2044 # None 0 No # No 0 0 set global sql_slave_skip_counter=1; start slave; set sql_log_bin=0; diff --git a/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result b/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result index 27fb8623e85..35696615b5a 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result +++ b/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result @@ -53,7 +53,7 @@ Master_User root Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 465 +Read_Master_Log_Pos 556 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 diff --git a/mysql-test/suite/rpl/r/rpl_loaddata_map.result b/mysql-test/suite/rpl/r/rpl_loaddata_map.result index 901f3352b44..006f84043a4 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddata_map.result +++ b/mysql-test/suite/rpl/r/rpl_loaddata_map.result @@ -20,7 +20,7 @@ master-bin.000001 # Query # # use `test`; create table t2 (id int not null prima master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# master-bin.000001 # Append_block # # ;file_id=#;block_len=# master-bin.000001 # Append_block # # ;file_id=#;block_len=# -master-bin.000001 # Execute_load_query # # use `test`; load data infile 'MYSQLTEST_VARDIR/tmp/bug30435_5k.txt' into table t2 ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug30435_5k.txt' INTO TABLE `t2` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (id) ;file_id=# ==== Verify results on slave ==== [on slave] select count(*) from t2 /* 5 000 */; diff --git a/mysql-test/suite/rpl/r/rpl_loaddatalocal.result b/mysql-test/suite/rpl/r/rpl_loaddatalocal.result index 93ef33f3fc0..6dccaa3d74c 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddatalocal.result +++ b/mysql-test/suite/rpl/r/rpl_loaddatalocal.result @@ -54,3 +54,31 @@ a [on master] DROP TABLE t1; [on slave] + +Bug #43746: +"return wrong query string when parse 'load data infile' sql statement" + +[master] +SELECT @@SESSION.sql_mode INTO @old_mode; +SET sql_mode='ignore_space'; +CREATE TABLE t1(a int); +INSERT INTO t1 VALUES (1), (2), (3), (4); +SELECT * INTO OUTFILE 'MYSQLD_DATADIR/bug43746.sql' FROM t1; +TRUNCATE TABLE t1; +LOAD DATA LOCAL INFILE 'MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; +LOAD/* look mum, with comments in weird places! */DATA/* oh hai */LOCAL INFILE 'MYSQLD_DATADIR/bug43746.sql'/* we are */INTO/* from the internets */TABLE t1; +LOAD DATA/*!10000 LOCAL */INFILE 'MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; +LOAD DATA LOCAL INFILE 'MYSQLD_DATADIR/bug43746.sql' /*!10000 INTO */ TABLE t1; +LOAD DATA LOCAL INFILE 'MYSQLD_DATADIR/bug43746.sql' /*!10000 INTO TABLE */ t1; +LOAD DATA /*!10000 LOCAL INFILE 'MYSQLD_DATADIR/bug43746.sql' INTO TABLE */ t1; +LOAD DATA/*!10000 LOCAL */INFILE 'MYSQLD_DATADIR/bug43746.sql'/*!10000 INTO*/TABLE t1; +LOAD DATA/*!10000 LOCAL */INFILE 'MYSQLD_DATADIR/bug43746.sql'/* empty */INTO TABLE t1; +LOAD DATA/*!10000 LOCAL */INFILE 'MYSQLD_DATADIR/bug43746.sql' INTO/* empty */TABLE t1; +LOAD/*!99999 special comments that do not expand */DATA/*!99999 code from the future */LOCAL INFILE 'MYSQLD_DATADIR/bug43746.sql'/*!99999 have flux capacitor */INTO/*!99999 will travel */TABLE t1; +SET sql_mode='PIPES_AS_CONCAT,ANSI_QUOTES,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER'; +LOAD DATA LOCAL INFILE 'MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; +[slave] +[master] +DROP TABLE t1; +SET SESSION sql_mode=@old_mode; +[slave] diff --git a/mysql-test/suite/rpl/r/rpl_stm_log.result b/mysql-test/suite/rpl/r/rpl_stm_log.result index bcefc6f9d3d..d73b8990041 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_log.result +++ b/mysql-test/suite/rpl/r/rpl_stm_log.result @@ -25,7 +25,7 @@ master-bin.000001 # Query 1 # use `test`; insert into t1 values (NULL) master-bin.000001 # Query 1 # use `test`; drop table t1 master-bin.000001 # Query 1 # use `test`; create table t1 (word char(20) not null)ENGINE=MyISAM master-bin.000001 # Begin_load_query 1 # ;file_id=1;block_len=581 -master-bin.000001 # Execute_load_query 1 # use `test`; load data infile '../../std_data/words.dat' into table t1 ignore 1 lines ;file_id=1 +master-bin.000001 # Execute_load_query 1 # use `test`; LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' IGNORE 1 LINES (word) ;file_id=1 show binlog events from 106 limit 1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=MyISAM @@ -193,7 +193,7 @@ master-bin.000001 # Query # # use `test`; insert into t1 values (NULL) master-bin.000001 # Query # # use `test`; drop table t1 master-bin.000001 # Query # # use `test`; create table t1 (word char(20) not null)ENGINE=MyISAM master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# -master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/words.dat' into table t1 ignore 1 lines ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' IGNORE 1 LINES (word) ;file_id=# master-bin.000001 # Rotate # # master-bin.000002;pos=4 show binlog events in 'master-bin.000002'; Log_name Pos Event_type Server_id End_log_pos Info @@ -218,7 +218,7 @@ slave-bin.000001 # Query 1 # use `test`; insert into t1 values (NULL) slave-bin.000001 # Query 1 # use `test`; drop table t1 slave-bin.000001 # Query 1 # use `test`; create table t1 (word char(20) not null)ENGINE=MyISAM slave-bin.000001 # Begin_load_query 1 # ;file_id=1;block_len=581 -slave-bin.000001 # Execute_load_query 1 # use `test`; load data INFILE '../../tmp/SQL_LOAD-2-1-1.data' INTO table t1 ignore 1 lines ;file_id=1 +slave-bin.000001 # Execute_load_query 1 # use `test`; LOAD DATA INFILE '../../tmp/SQL_LOAD-2-1-1.data' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' IGNORE 1 LINES (word) ;file_id=1 slave-bin.000001 # Query 1 # use `test`; create table t3 (a int)ENGINE=MyISAM slave-bin.000001 # Rotate 2 # slave-bin.000002;pos=4 show binlog events in 'slave-bin.000002' from 4; diff --git a/mysql-test/suite/rpl/t/rpl_loaddatalocal.test b/mysql-test/suite/rpl/t/rpl_loaddatalocal.test index 23c802ab3de..a93a82d6d9f 100644 --- a/mysql-test/suite/rpl/t/rpl_loaddatalocal.test +++ b/mysql-test/suite/rpl/t/rpl_loaddatalocal.test @@ -98,3 +98,73 @@ DROP TABLE t1; --echo [on slave] sync_slave_with_master; +--echo +--echo Bug #43746: +--echo "return wrong query string when parse 'load data infile' sql statement" +--echo + +--echo [master] +connection master; +let $MYSQLD_DATADIR= `select @@datadir`; +SELECT @@SESSION.sql_mode INTO @old_mode; + +SET sql_mode='ignore_space'; + +CREATE TABLE t1(a int); +INSERT INTO t1 VALUES (1), (2), (3), (4); + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval SELECT * INTO OUTFILE '$MYSQLD_DATADIR/bug43746.sql' FROM t1; +TRUNCATE TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD/* look mum, with comments in weird places! */DATA/* oh hai */LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql'/* we are */INTO/* from the internets */TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA/*!10000 LOCAL */INFILE '$MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql' /*!10000 INTO */ TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql' /*!10000 INTO TABLE */ t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA /*!10000 LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql' INTO TABLE */ t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA/*!10000 LOCAL */INFILE '$MYSQLD_DATADIR/bug43746.sql'/*!10000 INTO*/TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA/*!10000 LOCAL */INFILE '$MYSQLD_DATADIR/bug43746.sql'/* empty */INTO TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA/*!10000 LOCAL */INFILE '$MYSQLD_DATADIR/bug43746.sql' INTO/* empty */TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD/*!99999 special comments that do not expand */DATA/*!99999 code from the future */LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql'/*!99999 have flux capacitor */INTO/*!99999 will travel */TABLE t1; + +SET sql_mode='PIPES_AS_CONCAT,ANSI_QUOTES,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER'; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; + +--echo [slave] +sync_slave_with_master; + +# cleanup + +--remove_file $MYSQLD_DATADIR/bug43746.sql + +--echo [master] +connection master; +DROP TABLE t1; +SET SESSION sql_mode=@old_mode; + +--echo [slave] +sync_slave_with_master; + +connection master; diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 7767abe43d0..9af631b7187 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -71,7 +71,8 @@ select "--- --position --" as ""; --enable_query_log --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/ ---exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --position=239 $MYSQLD_DATADIR/master-bin.000002 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --position=330 $MYSQLD_DATADIR/master-bin.000002 + # These are tests for remote binlog. # They should return the same as previous test. @@ -107,7 +108,7 @@ select "--- --position --" as ""; --enable_query_log --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/ ---exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --read-from-remote-server --position=239 --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --read-from-remote-server --position=330 --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 # Bug#7853 mysqlbinlog does not accept input from stdin --disable_query_log diff --git a/sql/log_event.cc b/sql/log_event.cc index 08fe3aba8ed..d91b09d90c9 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4010,7 +4010,7 @@ uint Load_log_event::get_query_buffer_length() } -void Load_log_event::print_query(bool need_db, char *buf, +void Load_log_event::print_query(bool need_db, const char *cs, char *buf, char **end, char **fn_start, char **fn_end) { char *pos= buf; @@ -4034,9 +4034,9 @@ void Load_log_event::print_query(bool need_db, char *buf, pos= strmov(pos+fname_len, "' "); if (sql_ex.opt_flags & REPLACE_FLAG) - pos= strmov(pos, " REPLACE "); + pos= strmov(pos, "REPLACE "); else if (sql_ex.opt_flags & IGNORE_FLAG) - pos= strmov(pos, " IGNORE "); + pos= strmov(pos, "IGNORE "); pos= strmov(pos ,"INTO"); @@ -4047,8 +4047,16 @@ void Load_log_event::print_query(bool need_db, char *buf, memcpy(pos, table_name, table_name_len); pos+= table_name_len; - /* We have to create all optinal fields as the default is not empty */ - pos= strmov(pos, "` FIELDS TERMINATED BY "); + if (cs != NULL) + { + pos= strmov(pos ,"` CHARACTER SET "); + pos= strmov(pos , cs); + } + else + pos= strmov(pos, "`"); + + /* We have to create all optional fields as the default is not empty */ + pos= strmov(pos, " FIELDS TERMINATED BY "); pos= pretty_print_str(pos, sql_ex.field_term, sql_ex.field_term_len); if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG) pos= strmov(pos, " OPTIONALLY "); @@ -4102,7 +4110,7 @@ void Load_log_event::pack_info(Protocol *protocol) if (!(buf= (char*) my_malloc(get_query_buffer_length(), MYF(MY_WME)))) return; - print_query(TRUE, buf, &end, 0, 0); + print_query(TRUE, NULL, buf, &end, 0, 0); protocol->store(buf, end-buf, &my_charset_bin); my_free(buf, MYF(0)); } @@ -4367,9 +4375,9 @@ void Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info, my_b_printf(&cache, "INFILE '%-*s' ", fname_len, fname); if (sql_ex.opt_flags & REPLACE_FLAG) - my_b_printf(&cache," REPLACE "); + my_b_printf(&cache,"REPLACE "); else if (sql_ex.opt_flags & IGNORE_FLAG) - my_b_printf(&cache," IGNORE "); + my_b_printf(&cache,"IGNORE "); my_b_printf(&cache, "INTO TABLE `%s`", table_name); my_b_printf(&cache, " FIELDS TERMINATED BY "); @@ -4577,8 +4585,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, goto error; } - print_query(FALSE, load_data_query, &end, (char **)&thd->lex->fname_start, - (char **)&thd->lex->fname_end); + print_query(FALSE, NULL, load_data_query, &end, NULL, NULL); *end= 0; thd->set_query(load_data_query, (uint) (end - load_data_query)); @@ -6732,7 +6739,7 @@ void Execute_load_query_log_event::print(FILE* file, my_b_printf(&cache, "\'"); if (dup_handling == LOAD_DUP_REPLACE) my_b_printf(&cache, " REPLACE"); - my_b_printf(&cache, " INTO "); + my_b_printf(&cache, " INTO"); my_b_write(&cache, (uchar*) query + fn_pos_end, q_len-fn_pos_end); my_b_printf(&cache, "\n%s\n", print_event_info->delimiter); } diff --git a/sql/log_event.h b/sql/log_event.h index 8202dddcc76..31d4a7480c2 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1960,15 +1960,15 @@ private: class Load_log_event: public Log_event { private: - uint get_query_buffer_length(); - void print_query(bool need_db, char *buf, char **end, - char **fn_start, char **fn_end); protected: int copy_log_event(const char *buf, ulong event_len, int body_offset, const Format_description_log_event* description_event); public: + uint get_query_buffer_length(); + void print_query(bool need_db, const char *cs, char *buf, char **end, + char **fn_start, char **fn_end); ulong thread_id; ulong slave_proxy_id; uint32 table_name_len; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 76fd5354c51..4e4794ef2cf 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1735,13 +1735,6 @@ typedef struct st_lex : public Query_tables_list const char *stmt_definition_end; - /* - Pointers to part of LOAD DATA statement that should be rewritten - during replication ("LOCAL 'filename' REPLACE INTO" part). - */ - const char *fname_start; - const char *fname_end; - /** During name resolution search only in the table list given by Name_resolution_context::first_name_resolution_table and diff --git a/sql/sql_load.cc b/sql/sql_load.cc index b7f33d51335..e830e29176b 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -83,10 +83,13 @@ static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, String &enclosed, ulong skip_lines, bool ignore_check_option_errors); #ifndef EMBEDDED_LIBRARY -static bool write_execute_load_query_log_event(THD *thd, - bool duplicates, bool ignore, - bool transactional_table, - int errcode); +static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, + const char* db_arg, + const char* table_name_arg, + enum enum_duplicates duplicates, + bool ignore, + bool transactional_table, + int errocode); #endif /* EMBEDDED_LIBRARY */ /* @@ -497,8 +500,10 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); if (thd->transaction.stmt.modified_non_trans_table) - write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table, + write_execute_load_query_log_event(thd, ex, + tdb, table_list->table_name, + handle_duplicates, ignore, + transactional_table, errcode); else { @@ -542,8 +547,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (lf_info.wrote_create_file) { int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); - write_execute_load_query_log_event(thd, handle_duplicates, ignore, - transactional_table, errcode); + write_execute_load_query_log_event(thd, ex, + tdb, table_list->table_name, + handle_duplicates, ignore, + transactional_table, + errcode); } } } @@ -564,15 +572,95 @@ err: #ifndef EMBEDDED_LIBRARY /* Not a very useful function; just to avoid duplication of code */ -static bool write_execute_load_query_log_event(THD *thd, - bool duplicates, bool ignore, - bool transactional_table, +static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, + const char* db_arg, + const char* table_name_arg, + enum enum_duplicates duplicates, + bool ignore, + bool transactional_table, int errcode) { + char *load_data_query, + *end, + *fname_start, + *fname_end, + *p= NULL; + size_t pl= 0; + List fv; + Item *item, *val; + String pfield, pfields; + int n; + + Load_log_event lle(thd, ex, db_arg, table_name_arg, fv, duplicates, + ignore, transactional_table); + + /* + force in a LOCAL if there was one in the original. + */ + if (thd->lex->local_file) + lle.set_fname_outside_temp_buf(ex->file_name, strlen(ex->file_name)); + + /* + prepare fields-list and SET if needed; print_query won't do that for us. + */ + if (!thd->lex->field_list.is_empty()) + { + List_iterator li(thd->lex->field_list); + + pfields.append(" ("); + n= 0; + + while ((item= li++)) + { + if (n++) + pfields.append(", "); + if (item->name) + pfields.append(item->name); + else + item->print(&pfields, QT_ORDINARY); + } + pfields.append(")"); + } + + if (!thd->lex->update_list.is_empty()) + { + List_iterator lu(thd->lex->update_list); + List_iterator lv(thd->lex->value_list); + + pfields.append(" SET "); + n= 0; + + while ((item= lu++)) + { + val= lv++; + if (n++) + pfields.append(", "); + pfields.append(item->name); + pfields.append("="); + val->print(&pfields, QT_ORDINARY); + } + } + + p= pfields.c_ptr_safe(); + pl= strlen(p); + + if (!(load_data_query= (char *)thd->alloc(lle.get_query_buffer_length() + 1 + pl))) + return TRUE; + + lle.print_query(FALSE, (const char *) ex->cs?ex->cs->csname:NULL, + load_data_query, &end, + (char **)&fname_start, (char **)&fname_end); + + strcpy(end, p); + end += pl; + + thd->query_length= end - load_data_query; + thd->query= load_data_query; + Execute_load_query_log_event e(thd, thd->query, thd->query_length, - (uint) ((char*)thd->lex->fname_start - (char*)thd->query), - (uint) ((char*)thd->lex->fname_end - (char*)thd->query), + (uint) ((char*)fname_start - (char*)thd->query - 1), + (uint) ((char*)fname_end - (char*)thd->query), (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE : (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR), transactional_table, FALSE, errcode); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index db97e77bbd0..12e124230e5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -10425,14 +10425,12 @@ load: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= YYLIP; if (lex->sphead) { my_error(ER_SP_BADSTATEMENT, MYF(0), "LOAD DATA"); MYSQL_YYABORT; } - lex->fname_start= lip->get_ptr(); } load_data {} @@ -10464,14 +10462,10 @@ load_data: if (!(lex->exchange= new sql_exchange($4.str, 0))) MYSQL_YYABORT; } - opt_duplicate INTO - { - Lex->fname_end= YYLIP->get_ptr(); - } - TABLE_SYM table_ident + opt_duplicate INTO TABLE_SYM table_ident { LEX *lex=Lex; - if (!Select->add_table_to_list(YYTHD, $10, NULL, TL_OPTION_UPDATING, + if (!Select->add_table_to_list(YYTHD, $9, NULL, TL_OPTION_UPDATING, lex->lock_option)) MYSQL_YYABORT; lex->field_list.empty(); @@ -10479,7 +10473,7 @@ load_data: lex->value_list.empty(); } opt_load_data_charset - { Lex->exchange->cs= $12; } + { Lex->exchange->cs= $11; } opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec opt_load_data_set_spec {} From da5d0c90a4dc6da9eb43ad94f834c0ecf86a258d Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Mon, 28 Sep 2009 16:55:01 +0300 Subject: [PATCH 046/146] Fixed Sun Studio 8 compilation failures as suggested by Jorgen and reviewed by Svoj over e-mail. --- storage/myisam/mi_check.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c index 15eb28e6183..1c33ffa90f5 100644 --- a/storage/myisam/mi_check.c +++ b/storage/myisam/mi_check.c @@ -801,7 +801,7 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, { DBUG_DUMP("old",(uchar*) info->lastkey, info->lastkey_length); DBUG_DUMP("new",(uchar*) key, key_length); - DBUG_DUMP("new_in_page",(char*) old_keypos,(uint) (keypos-old_keypos)); + DBUG_DUMP("new_in_page",(uchar*) old_keypos,(uint) (keypos-old_keypos)); if (comp_flag & SEARCH_FIND && flag == 0) mi_check_print_error(param,"Found duplicated key at page %s",llstr(page,llbuff)); @@ -871,7 +871,7 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, llstr(page,llbuff),llstr(record,llbuff2), llstr(info->state->data_file_length,llbuff3))); DBUG_DUMP("key",(uchar*) key,key_length); - DBUG_DUMP("new_in_page",(char*) old_keypos,(uint) (keypos-old_keypos)); + DBUG_DUMP("new_in_page",(uchar*) old_keypos,(uint) (keypos-old_keypos)); goto err; } param->record_checksum+=(ha_checksum) record; @@ -1545,6 +1545,8 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, if (info->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)) param->testflag|=T_CALC_CHECKSUM; + DBUG_ASSERT(param->use_buffers < SIZE_T_MAX); + if (!param->using_global_keycache) VOID(init_key_cache(dflt_key_cache, param->key_cache_block_size, (size_t) param->use_buffers, 0, 0)); From 8f640b6239babacf2f7fc23b19b279a1c69f8b30 Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Mon, 28 Sep 2009 15:14:33 +0100 Subject: [PATCH 047/146] bug#30954: "configure" script in binary distributions considered harmfull Add --help option. --- support-files/binary-configure.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/support-files/binary-configure.sh b/support-files/binary-configure.sh index 884a8363e22..5e6d62f69a0 100644 --- a/support-files/binary-configure.sh +++ b/support-files/binary-configure.sh @@ -1,4 +1,28 @@ #!/bin/sh + +SCRIPT_NAME="`basename $0`" + +usage() +{ + echo "Usage: ${SCRIPT_NAME} [--help|-h]" + echo "" + echo "This script creates the MySQL system tables and starts the server." +} + +for arg do + case "$arg" in + --help|-h) + usage + exit 0 + ;; + *) + echo "${SCRIPT_NAME}: unknown option $arg" + usage + exit 2 + ;; + esac +done + if test ! -x ./scripts/mysql_install_db then echo "I didn't find the script './scripts/mysql_install_db'." From 4299943064130539cdba21ca9d045aa7424eb2ce Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Tue, 29 Sep 2009 07:23:38 +0500 Subject: [PATCH 048/146] Bug#47150 Assertion in Field_long::val_int() on MERGE + TRIGGER + multi-table UPDATE The bug is not related to MERGE table or TRIGGER. More correct description would be 'assertion on multi-table UPDATE + NATURAL JOIN + MERGEABLE VIEW'. On PREPARE stage(see test case) we call mark_common_columns() func which creates ON condition for NATURAL JOIN and sets appropriate table read_set bitmaps for fields which are used in ON condition. On EXECUTE stage mark_common_columns() is not called, we set necessary read_set bitmaps in setup_conds(). But 'B.f1' field is already processed and related item alredy fixed before setup_conds() as updated field and setup_conds can not set read_set bitmap because of that. The fix is to set read_set bitmap for appropriate table field even if Item_direct_view_ref item which represents a refernce to this field is fixed. --- mysql-test/r/join.result | 10 ++++++++++ mysql-test/t/join.test | 20 ++++++++++++++++++++ sql/item.cc | 21 +++++++++++++++++++-- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index 736ecf1d90e..77f73532474 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -1064,3 +1064,13 @@ a b c d 128 NULL 128 NULL DROP TABLE IF EXISTS t1,t2; End of 5.0 tests. +CREATE TABLE t1 (f1 int); +CREATE TABLE t2 (f1 int); +INSERT INTO t2 VALUES (1); +CREATE VIEW v1 AS SELECT * FROM t2; +PREPARE stmt FROM 'UPDATE t2 AS A NATURAL JOIN v1 B SET B.f1 = 1'; +EXECUTE stmt; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; +DROP VIEW v1; +DROP TABLE t1, t2; diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index b5e30e63f54..1cd05c8cb65 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -729,4 +729,24 @@ SELECT * FROM t1 JOIN t2 ON b=c ORDER BY a; SELECT * FROM t1 JOIN t2 ON a=c ORDER BY a; DROP TABLE IF EXISTS t1,t2; + --echo End of 5.0 tests. + + +# +# Bug#47150 Assertion in Field_long::val_int() on MERGE + TRIGGER + multi-table UPDATE +# +CREATE TABLE t1 (f1 int); + +CREATE TABLE t2 (f1 int); +INSERT INTO t2 VALUES (1); +CREATE VIEW v1 AS SELECT * FROM t2; + +PREPARE stmt FROM 'UPDATE t2 AS A NATURAL JOIN v1 B SET B.f1 = 1'; +EXECUTE stmt; +EXECUTE stmt; + +DEALLOCATE PREPARE stmt; + +DROP VIEW v1; +DROP TABLE t1, t2; diff --git a/sql/item.cc b/sql/item.cc index 26df3a45971..86e4551e55b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6331,9 +6331,26 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference) /* view fild reference must be defined */ DBUG_ASSERT(*ref); /* (*ref)->check_cols() will be made in Item_direct_ref::fix_fields */ - if (!(*ref)->fixed && - ((*ref)->fix_fields(thd, ref))) + if ((*ref)->fixed) + { + Item *ref_item= (*ref)->real_item(); + if (ref_item->type() == Item::FIELD_ITEM) + { + /* + In some cases we need to update table read set(see bug#47150). + If ref item is FIELD_ITEM and fixed then field and table + have proper values. So we can use them for update. + */ + Field *fld= ((Item_field*) ref_item)->field; + DBUG_ASSERT(fld && fld->table); + if (thd->mark_used_columns == MARK_COLUMNS_READ) + bitmap_set_bit(fld->table->read_set, fld->field_index); + } + } + else if (!(*ref)->fixed && + ((*ref)->fix_fields(thd, ref))) return TRUE; + return Item_direct_ref::fix_fields(thd, reference); } From d86e8b7c64567bd475ab840be6e4ac28ac069234 Mon Sep 17 00:00:00 2001 From: "timothy.smith@sun.com" <> Date: Tue, 29 Sep 2009 08:58:32 +0200 Subject: [PATCH 049/146] make_binary_distribution and mysql.spec: add options to copy a shared library, for use by mysqld_safe, into pkglibdir during package creation --- scripts/make_binary_distribution.sh | 8 ++++++++ support-files/mysql.spec.sh | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh index bf22267cf42..27fe2acb447 100644 --- a/scripts/make_binary_distribution.sh +++ b/scripts/make_binary_distribution.sh @@ -64,6 +64,7 @@ cflags="@CFLAGS@" STRIP=1 # Option ignored SILENT=0 +MALLOC_LIB= PLATFORM="" TMP=/tmp NEW_NAME="" # Final top directory and TAR package name @@ -76,6 +77,7 @@ for arg do --tmp=*) TMP=`echo "$arg" | sed -e "s;--tmp=;;"` ;; --suffix=*) SUFFIX=`echo "$arg" | sed -e "s;--suffix=;;"` ;; --short-product-tag=*) SHORT_PRODUCT_TAG=`echo "$arg" | sed -e "s;--short-product-tag=;;"` ;; + --inject-malloc-lib=*) MALLOC_LIB=`echo "$arg" | sed -e 's;^[^=]*=;;'` ;; --no-strip) STRIP=0 ;; --machine=*) machine=`echo "$arg" | sed -e "s;--machine=;;"` ;; --platform=*) PLATFORM=`echo "$arg" | sed -e "s;--platform=;;"` ;; @@ -293,6 +295,12 @@ if [ x"$BASE_SYSTEM" != x"netware" ] ; then fi fi + # If requested, add a malloc library .so into pkglibdir for use + # by mysqld_safe + if [ -n "$MALLOC_LIB" ]; then + cp "$MALLOC_LIB" '@pkglibdir@' + fi + # FIXME let this script be in "bin/", where it is in the RPMs? # http://dev.mysql.com/doc/refman/5.1/en/mysql-install-db-problems.html mkdir $DEST/scripts diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 02561a2551d..6fd8929266e 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -448,6 +448,13 @@ $MBD/libtool --mode=execute install -m 755 \ $RPM_BUILD_DIR/mysql-%{mysql_version}/mysql-debug-%{mysql_version}/sql/mysqld \ $RBR%{_sbindir}/mysqld-debug +%if %{?malloc_lib_target:1}%{!?malloc_lib_target:0} +# Even though this is a shared library, put it under /usr/lib/mysql, so it +# doesn't conflict with possible shared lib by the same name in /usr/lib. See +# `mysql_config --variable=pkglibdir` and mysqld_safe for how this is used. +install -m 644 "%{malloc_lib_source}" "$RBR%{_libdir}/mysql/%{malloc_lib_target}" +%endif + # install saved perror binary with NDB support (BUG#13740) install -m 755 $MBD/extra/perror $RBR%{_bindir}/perror @@ -703,6 +710,10 @@ fi %attr(755, root, root) %{_libdir}/plugin/*.so* +%if %{?malloc_lib_target:1}%{!?malloc_lib_target:0} +%attr(644, root, root) %{_libdir}/mysql/%{malloc_lib_target} +%endif + %attr(755, root, root) %{_sbindir}/mysqld %attr(755, root, root) %{_sbindir}/mysqld-debug %attr(755, root, root) %{_sbindir}/rcmysql From fc3740368aed05f95da167deda7544a91a904d3f Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Tue, 29 Sep 2009 07:58:42 -0300 Subject: [PATCH 050/146] Bug#45567: Fast ALTER TABLE broken for enum and set The problem was that appending values to the end of an existing ENUM or SET column was being treated as table data modification, preventing a immediately (fast) table alteration that occurs when only table metadata is being modified. The cause was twofold: adding a enumeration or set members to the end of the list of valid member values was not being considered a "compatible" table alteration, and for SET columns, the check was being done upon the max display length and not the underlying (pack) length of the field. The solution is to augment the function that checks wether two ENUM or SET fields are compatible -- by comparing the pack lengths and performing a limited comparison of the member values. --- mysql-test/r/alter_table.result | 62 +++++++++++++++++++++++++++ mysql-test/t/alter_table.test | 46 ++++++++++++++++++++ sql/field.cc | 75 ++++++++++++++++++++++++++------- sql/field.h | 8 +++- 4 files changed, 174 insertions(+), 17 deletions(-) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index 5a115e9ea99..db7173d0b47 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -1268,4 +1268,66 @@ a b 4 b 5 a DROP TABLE t1; +# +# Bug#45567: Fast ALTER TABLE broken for enum and set +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a ENUM('a1','a2')); +INSERT INTO t1 VALUES ('a1'),('a2'); +# No copy: No modification +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +# No copy: Add new enumeration to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a3'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +# Copy: Modify and add new to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','xx','a5'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# Copy: Remove from the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','xx'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# Copy: Add new enumeration +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a0','xx'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# No copy: Add new enumerations to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a0','xx','a5','a6'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +DROP TABLE t1; +CREATE TABLE t1 (a SET('a1','a2')); +INSERT INTO t1 VALUES ('a1'),('a2'); +# No copy: No modification +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +# No copy: Add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a3'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +# Copy: Modify and add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','xx','a5'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# Copy: Remove from the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','xx'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# Copy: Add new member +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# No copy: Add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx','a5','a6'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +# Copy: Numerical incrase (pack lenght) +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx','a5','a6','a7','a8','a9','a10'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index ae48d5a8736..17549745203 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -1000,4 +1000,50 @@ ALTER TABLE t1 MODIFY b ENUM('a', 'z', 'b', 'c') NOT NULL; SELECT * FROM t1; DROP TABLE t1; +--echo # +--echo # Bug#45567: Fast ALTER TABLE broken for enum and set +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (a ENUM('a1','a2')); +INSERT INTO t1 VALUES ('a1'),('a2'); +--enable_info +--echo # No copy: No modification +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2'); +--echo # No copy: Add new enumeration to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a3'); +--echo # Copy: Modify and add new to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','xx','a5'); +--echo # Copy: Remove from the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','xx'); +--echo # Copy: Add new enumeration +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a0','xx'); +--echo # No copy: Add new enumerations to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a0','xx','a5','a6'); +--disable_info +DROP TABLE t1; + +CREATE TABLE t1 (a SET('a1','a2')); +INSERT INTO t1 VALUES ('a1'),('a2'); +--enable_info +--echo # No copy: No modification +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2'); +--echo # No copy: Add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a3'); +--echo # Copy: Modify and add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','xx','a5'); +--echo # Copy: Remove from the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','xx'); +--echo # Copy: Add new member +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx'); +--echo # No copy: Add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx','a5','a6'); +--echo # Copy: Numerical incrase (pack lenght) +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx','a5','a6','a7','a8','a9','a10'); +--disable_info +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/sql/field.cc b/sql/field.cc index 9f46552d5bd..0df9b0fc2e4 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -8832,6 +8832,24 @@ bool Field::eq_def(Field *field) } +/** + Compare the first t1::count type names. + + @return TRUE if the type names of t1 match those of t2. FALSE otherwise. +*/ + +static bool compare_type_names(CHARSET_INFO *charset, TYPELIB *t1, TYPELIB *t2) +{ + for (uint i= 0; i < t1->count; i++) + if (my_strnncoll(charset, + (const uchar*) t1->type_names[i], + t1->type_lengths[i], + (const uchar*) t2->type_names[i], + t2->type_lengths[i])) + return FALSE; + return TRUE; +} + /** @return returns 1 if the fields are equally defined @@ -8839,32 +8857,57 @@ bool Field::eq_def(Field *field) bool Field_enum::eq_def(Field *field) { + TYPELIB *values; + if (!Field::eq_def(field)) - return 0; - return compare_enum_values(((Field_enum*) field)->typelib); -} + return FALSE; + values= ((Field_enum*) field)->typelib; -bool Field_enum::compare_enum_values(TYPELIB *values) -{ + /* Definition must be strictly equal. */ if (typelib->count != values->count) return FALSE; - for (uint i= 0; i < typelib->count; i++) - if (my_strnncoll(field_charset, - (const uchar*) typelib->type_names[i], - typelib->type_lengths[i], - (const uchar*) values->type_names[i], - values->type_lengths[i])) - return FALSE; - return TRUE; + + return compare_type_names(field_charset, typelib, values); } +/** + Check whether two fields can be considered 'equal' for table + alteration purposes. Fields are equal if they retain the same + pack length and if new members are added to the end of the list. + + @return IS_EQUAL_YES if fields are compatible. + IS_EQUAL_NO otherwise. +*/ + uint Field_enum::is_equal(Create_field *new_field) { - if (!Field_str::is_equal(new_field)) - return 0; - return compare_enum_values(new_field->interval); + TYPELIB *values= new_field->interval; + + /* + The fields are compatible if they have the same flags, + type, charset and have the same underlying length. + */ + if (compare_str_field_flags(new_field, flags) || + new_field->sql_type != real_type() || + new_field->charset != field_charset || + new_field->pack_length != pack_length()) + return IS_EQUAL_NO; + + /* + Changing the definition of an ENUM or SET column by adding a new + enumeration or set members to the end of the list of valid member + values only alters table metadata and not table data. + */ + if (typelib->count > values->count) + return IS_EQUAL_NO; + + /* Check whether there are modification before the end. */ + if (! compare_type_names(field_charset, typelib, new_field->interval)) + return IS_EQUAL_NO; + + return IS_EQUAL_YES; } diff --git a/sql/field.h b/sql/field.h index a9299256f88..7a9b69eff40 100644 --- a/sql/field.h +++ b/sql/field.h @@ -472,6 +472,13 @@ public: /* maximum possible display length */ virtual uint32 max_display_length()= 0; + /** + Whether a field being created is compatible with a existing one. + + Used by the ALTER TABLE code to evaluate whether the new definition + of a table is compatible with the old definition so that it can + determine if data needs to be copied over (table data change). + */ virtual uint is_equal(Create_field *new_field); /* convert decimal to longlong with overflow check */ longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag, @@ -1862,7 +1869,6 @@ public: CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; } private: int do_save_field_metadata(uchar *first_byte); - bool compare_enum_values(TYPELIB *values); uint is_equal(Create_field *new_field); }; From 73153f1cb354cf6c38f4c9ba80714ef849cddb65 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Tue, 29 Sep 2009 11:11:46 -0300 Subject: [PATCH 051/146] Don't use the semicolon character as a argument separator as it can be interpreted as a shell metacharacter in some circumstances. For example, it is interpreted as a command separator when invoking a debugger. --- mysql-test/lib/mtr_cases.pm | 6 ++++-- mysql-test/mysql-test-run.pl | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 224babaaf32..27165d56b50 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -493,6 +493,7 @@ sub collect_one_suite($) $lib_innodb_plugin) { my @new_cases; + my $sep= (IS_WINDOWS) ? ';' : ':'; foreach my $test (@cases) { @@ -520,12 +521,13 @@ sub collect_one_suite($) } } my $plugin_filename= basename($lib_innodb_plugin); + my $plugin_list= "innodb=$plugin_filename" . $sep . "innodb_locks=$plugin_filename"; push(@{$new_test->{master_opt}}, '--ignore-builtin-innodb'); push(@{$new_test->{master_opt}}, '--plugin-dir=' . dirname($lib_innodb_plugin)); - push(@{$new_test->{master_opt}}, "--plugin_load=innodb=$plugin_filename;innodb_locks=$plugin_filename"); + push(@{$new_test->{master_opt}}, "--plugin_load=$plugin_list"); push(@{$new_test->{slave_opt}}, '--ignore-builtin-innodb'); push(@{$new_test->{slave_opt}}, '--plugin-dir=' . dirname($lib_innodb_plugin)); - push(@{$new_test->{slave_opt}}, "--plugin_load=innodb=$plugin_filename;innodb_locks=$plugin_filename"); + push(@{$new_test->{slave_opt}}, "--plugin_load=$plugin_list"); if ($new_test->{combination}) { $new_test->{combination}.= ' + InnoDB plugin'; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 114b6c84aa3..5cae3e8258b 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1812,7 +1812,7 @@ sub environment_setup { ($lib_example_plugin ? dirname($lib_example_plugin) : ""); $ENV{'HA_EXAMPLE_SO'}="'".$plugin_filename."'"; - $ENV{'EXAMPLE_PLUGIN_LOAD'}="--plugin_load=;EXAMPLE=".$plugin_filename.";"; + $ENV{'EXAMPLE_PLUGIN_LOAD'}="--plugin_load=EXAMPLE=".$plugin_filename; } # ---------------------------------------------------- From 21d401c202e2580c087d51130778f88e76873c6f Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Tue, 29 Sep 2009 17:06:51 +0200 Subject: [PATCH 052/146] Bug#42108 Wrong locking for UPDATE with subqueries leads to broken statement replication MySQL server uses wrong lock type (always TL_READ instead of TL_READ_NO_INSERT when appropriate) for tables used in subqueries of UPDATE statement. This leads in some cases to a broken replication as statements are written in the wrong order to the binlog. --- sql/sql_yacc.yy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 09a0a4b2f12..0aa6308ab93 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7810,7 +7810,7 @@ update: LEX *lex= Lex; mysql_init_select(lex); lex->sql_command= SQLCOM_UPDATE; - lex->lock_option= TL_UNLOCK; /* Will be set later */ + lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ; lex->duplicates= DUP_ERROR; } opt_low_priority opt_ignore join_table_list From 21586dfb084b05ac7d98ee990d64637b4be9222a Mon Sep 17 00:00:00 2001 From: Ingo Struewing Date: Tue, 29 Sep 2009 17:38:40 +0200 Subject: [PATCH 053/146] WL#4259 - Debug Sync Facility Backport from 6.0 to 5.1. Only those sync points are included, which are used in debug_sync.test. The Debug Sync Facility allows to place synchronization points in the code: open_tables(...) DEBUG_SYNC(thd, "after_open_tables"); lock_tables(...) When activated, a sync point can - Send a signal and/or - Wait for a signal Nomenclature: - signal: A value of a global variable that persists until overwritten by a new signal. The global variable can also be seen as a "signal post" or "flag mast". Then the signal is what is attached to the "signal post" or "flag mast". - send a signal: Assign the value (the signal) to the global variable ("set a flag") and broadcast a global condition to wake those waiting for a signal. - wait for a signal: Loop over waiting for the global condition until the global value matches the wait-for signal. Please find more information in the top comment in debug_sync.cc or in the worklog entry. --- .bzrignore | 1 + CMakeLists.txt | 6 + configure.in | 17 + include/my_sys.h | 10 + libmysqld/CMakeLists.txt | 1 + libmysqld/Makefile.am | 1 + mysql-test/include/have_debug_sync.inc | 5 + mysql-test/mysql-test-run.pl | 9 + mysql-test/r/debug_sync.result | 277 ++++ mysql-test/r/have_debug_sync.require | 2 + mysql-test/t/debug_sync.test | 420 ++++++ mysys/my_static.c | 8 + mysys/thr_lock.c | 22 + sql/CMakeLists.txt | 1 + sql/Makefile.am | 2 + sql/debug_sync.cc | 1906 ++++++++++++++++++++++++ sql/debug_sync.h | 60 + sql/mysqld.cc | 46 +- sql/set_var.cc | 6 + sql/set_var.h | 15 + sql/share/errmsg.txt | 7 + sql/sql_base.cc | 4 + sql/sql_class.cc | 15 + sql/sql_class.h | 5 + storage/myisam/myisamchk.c | 2 +- 25 files changed, 2846 insertions(+), 2 deletions(-) create mode 100644 mysql-test/include/have_debug_sync.inc create mode 100644 mysql-test/r/debug_sync.result create mode 100644 mysql-test/r/have_debug_sync.require create mode 100644 mysql-test/t/debug_sync.test create mode 100644 sql/debug_sync.cc create mode 100644 sql/debug_sync.h diff --git a/.bzrignore b/.bzrignore index 6c6a43dacab..e1e2083e2d2 100644 --- a/.bzrignore +++ b/.bzrignore @@ -3064,3 +3064,4 @@ sql/share/spanish sql/share/swedish sql/share/ukrainian libmysqld/examples/mysqltest.cc +libmysqld/debug_sync.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d91e39eb6d..8c40312e32b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,12 @@ IF(EXTRA_DEBUG) ADD_DEFINITIONS(-D EXTRA_DEBUG) ENDIF(EXTRA_DEBUG) +IF(ENABLED_DEBUG_SYNC) + ADD_DEFINITIONS(-D ENABLED_DEBUG_SYNC) +ENDIF(ENABLED_DEBUG_SYNC) +SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DENABLED_DEBUG_SYNC") +SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DENABLED_DEBUG_SYNC") + # in some places we use DBUG_OFF SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DDBUG_OFF") SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DDBUG_OFF") diff --git a/configure.in b/configure.in index b974d7076d7..bec902f83c1 100644 --- a/configure.in +++ b/configure.in @@ -1708,6 +1708,23 @@ else CXXFLAGS="$OPTIMIZE_CXXFLAGS $CXXFLAGS" fi +# Debug Sync Facility. NOTE: depends on 'with_debug'. Must be behind it. +AC_MSG_CHECKING(if Debug Sync Facility should be enabled.) +AC_ARG_ENABLE(debug_sync, + AS_HELP_STRING([--enable-debug-sync], + [Build a version with Debug Sync Facility]), + [ enable_debug_sync=$enableval ], + [ enable_debug_sync=$with_debug ]) + +if test "$enable_debug_sync" != "no" +then + AC_DEFINE([ENABLED_DEBUG_SYNC], [1], + [If Debug Sync Facility should be enabled]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + # If we should allow error injection tests AC_ARG_WITH(error-inject, AC_HELP_STRING([--with-error-inject],[Enable error injection in MySQL Server]), diff --git a/include/my_sys.h b/include/my_sys.h index cb9a24bbd7f..166133251bc 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -172,6 +172,16 @@ extern char *my_strndup(const char *from, size_t length, #define TRASH(A,B) /* nothing */ #endif +#if defined(ENABLED_DEBUG_SYNC) +extern void (*debug_sync_C_callback_ptr)(const char *, size_t); +#define DEBUG_SYNC_C(_sync_point_name_) do { \ + if (debug_sync_C_callback_ptr != NULL) \ + (*debug_sync_C_callback_ptr)(STRING_WITH_LEN(_sync_point_name_)); } \ + while(0) +#else +#define DEBUG_SYNC_C(_sync_point_name_) +#endif /* defined(ENABLED_DEBUG_SYNC) */ + #ifdef HAVE_LARGE_PAGES extern uint my_get_large_page_size(void); extern uchar * my_large_malloc(size_t size, myf my_flags); diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 8500d73863a..bea6f6c0e1f 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -129,6 +129,7 @@ SET(LIBMYSQLD_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ../sql/sql_list.cc ../sql/sql_load.cc ../sql/sql_locale.cc ../sql/sql_binlog.cc ../sql/sql_manager.cc ../sql/sql_map.cc ../sql/sql_parse.cc ../sql/sql_partition.cc ../sql/sql_plugin.cc + ../sql/debug_sync.cc ../sql/sql_prepare.cc ../sql/sql_rename.cc ../sql/sql_repl.cc ../sql/sql_select.cc ../sql/sql_servers.cc ../sql/sql_show.cc ../sql/sql_state.c ../sql/sql_string.cc diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index a9bd8d9e17c..16c45816bbf 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -74,6 +74,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \ parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \ rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \ + debug_sync.cc \ sql_tablespace.cc \ rpl_injector.cc my_user.c partition_info.cc \ sql_servers.cc event_parse_data.cc diff --git a/mysql-test/include/have_debug_sync.inc b/mysql-test/include/have_debug_sync.inc new file mode 100644 index 00000000000..7aa5baf3342 --- /dev/null +++ b/mysql-test/include/have_debug_sync.inc @@ -0,0 +1,5 @@ +--require r/have_debug_sync.require +disable_query_log; +let $value= query_get_value(SHOW VARIABLES LIKE 'debug_sync', Value, 1); +eval SELECT ('$value' LIKE 'ON %') AS debug_sync; +enable_query_log; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 114b6c84aa3..da94f02fb27 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -226,6 +226,7 @@ my @default_valgrind_args= ("--show-reachable=yes"); my @valgrind_args; my $opt_valgrind_path; my $opt_callgrind; +my $opt_debug_sync_timeout= 300; # Default timeout for WAIT_FOR actions. our $opt_warnings= 1; @@ -867,6 +868,7 @@ sub command_line_setup { 'valgrind-option=s' => \@valgrind_args, 'valgrind-path=s' => \$opt_valgrind_path, 'callgrind' => \$opt_callgrind, + 'debug-sync-timeout=i' => \$opt_debug_sync_timeout, # Directories 'tmpdir=s' => \$opt_tmpdir, @@ -4170,6 +4172,11 @@ sub mysqld_arguments ($$$) { mtr_add_arg($args, "%s", "--core-file"); } + # Enable the debug sync facility, set default wait timeout. + # Facility stays disabled if timeout value is zero. + mtr_add_arg($args, "--loose-debug-sync-timeout=%s", + $opt_debug_sync_timeout); + return $args; } @@ -5280,6 +5287,8 @@ Misc options to turn off. sleep=SECONDS Passed to mysqltest, will be used as fixed sleep time + debug-sync-timeout=NUM Set default timeout for WAIT_FOR debug sync + actions. Disable facility with NUM=0. gcov Collect coverage information after the test. The result is a gcov file per source and header file. experimental= Refer to list of tests considered experimental; diff --git a/mysql-test/r/debug_sync.result b/mysql-test/r/debug_sync.result new file mode 100644 index 00000000000..47e968f79cf --- /dev/null +++ b/mysql-test/r/debug_sync.result @@ -0,0 +1,277 @@ +SET DEBUG_SYNC= 'RESET'; +DROP TABLE IF EXISTS t1; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: '' +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 EXECUTE 2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 SIGNAL s1 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 EXECUTE 2'; +SET DEBUG_SYNC='p0 SIGNAL s1 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 EXECUTE 2'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 CLEAR'; +SET DEBUG_SYNC='p0 TEST'; +SET DEBUG_SYNC='RESET'; +set debug_sync='p0 signal s1 wait_for s2 timeout 6 execute 2 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2 timeout 6 execute 2'; +set debug_sync='p0 signal s1 wait_for s2 timeout 6 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2 timeout 6'; +set debug_sync='p0 signal s1 wait_for s2 execute 2 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2 execute 2'; +set debug_sync='p0 signal s1 wait_for s2 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2'; +set debug_sync='p0 signal s1 execute 2 hit_limit 3'; +set debug_sync='p0 signal s1 execute 2'; +set debug_sync='p0 signal s1 hit_limit 3'; +set debug_sync='p0 signal s1'; +set debug_sync='p0 wait_for s2 timeout 6 execute 2 hit_limit 3'; +set debug_sync='p0 wait_for s2 timeout 6 execute 2'; +set debug_sync='p0 wait_for s2 timeout 6 hit_limit 3'; +set debug_sync='p0 wait_for s2 timeout 6'; +set debug_sync='p0 wait_for s2 execute 2 hit_limit 3'; +set debug_sync='p0 wait_for s2 execute 2'; +set debug_sync='p0 wait_for s2 hit_limit 3'; +set debug_sync='p0 wait_for s2'; +set debug_sync='p0 hit_limit 3'; +set debug_sync='p0 clear'; +set debug_sync='p0 test'; +set debug_sync='reset'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 + EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC=' p0 SIGNAL s1 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 '; +SET DEBUG_SYNC=' p0 SIGNAL s1 WAIT_FOR s2 '; +SET DEBUG_SYNC=' p0 SIGNAL s1 WAIT_FOR s2 '; +SET DEBUG_SYNC=''; +ERROR 42000: Missing synchronization point name +SET DEBUG_SYNC=' '; +ERROR 42000: Missing synchronization point name +SET DEBUG_SYNC='p0'; +ERROR 42000: Missing action after synchronization point name 'p0' +SET DEBUG_SYNC='p0 EXECUTE 2'; +ERROR 42000: Missing action before EXECUTE +SET DEBUG_SYNC='p0 TIMEOUT 6 EXECUTE 2'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT' +SET DEBUG_SYNC='p0 TIMEOUT 6'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT' +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1'; +ERROR 42000: Illegal or out of order stuff: 'SIGNAL' +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 EXECUTE 2'; +ERROR 42000: Illegal or out of order stuff: 'SIGNAL' +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 TIMEOUT 6 EXECUTE 2'; +ERROR 42000: Illegal or out of order stuff: 'SIGNAL' +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 TIMEOUT 6'; +ERROR 42000: Illegal or out of order stuff: 'SIGNAL' +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 SIGNAL s1 EXECUTE 2'; +ERROR 42000: Illegal or out of order stuff: 'SIGNAL' +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 SIGNAL s1'; +ERROR 42000: Illegal or out of order stuff: 'SIGNAL' +SET DEBUG_SYNC='p0 TIMEOUT 6 WAIT_FOR s2 EXECUTE 2'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT' +SET DEBUG_SYNC='p0 TIMEOUT 6 WAIT_FOR s2'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT' +SET DEBUG_SYNC='p0 SIGNAL s1 TIMEOUT 6 EXECUTE 2'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT' +SET DEBUG_SYNC='p0 SIGNAL s1 TIMEOUT 6'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT' +SET DEBUG_SYNC='p0 EXECUTE 2 SIGNAL s1 TIMEOUT 6'; +ERROR 42000: Missing action before EXECUTE +SET DEBUG_SYNC='p0 TIMEOUT 6 SIGNAL s1'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT' +SET DEBUG_SYNC='p0 EXECUTE 2 TIMEOUT 6 SIGNAL s1'; +ERROR 42000: Missing action before EXECUTE +SET DEBUG_SYNC='p0 CLEAR HIT_LIMIT 3'; +ERROR 42000: Nothing must follow action CLEAR +SET DEBUG_SYNC='CLEAR'; +ERROR 42000: Missing action after synchronization point name 'CLEAR' +SET DEBUG_SYNC='p0 CLEAR p0'; +ERROR 42000: Nothing must follow action CLEAR +SET DEBUG_SYNC='TEST'; +ERROR 42000: Missing action after synchronization point name 'TEST' +SET DEBUG_SYNC='p0 TEST p0'; +ERROR 42000: Nothing must follow action TEST +SET DEBUG_SYNC='p0 RESET'; +ERROR 42000: Illegal or out of order stuff: 'RESET' +SET DEBUG_SYNC='RESET p0'; +ERROR 42000: Illegal or out of order stuff: 'p0' +SET DEBUG_SYNC='p0 RESET p0'; +ERROR 42000: Illegal or out of order stuff: 'RESET' +SET DEBUG_SYNC='p0 SIGNAL '; +ERROR 42000: Missing signal name after action SIGNAL +SET DEBUG_SYNC='p0 WAIT_FOR '; +ERROR 42000: Missing signal name after action WAIT_FOR +SET DEBUG_SYNC='p0 SIGNAL s1 EXECUTE '; +ERROR 42000: Missing valid number after EXECUTE +SET DEBUG_SYNCx='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +ERROR HY000: Unknown system variable 'DEBUG_SYNCx' +SET DEBUG_SYNC='p0 SIGNAx s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +ERROR 42000: Illegal or out of order stuff: 'SIGNAx' +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOx s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +ERROR 42000: Illegal or out of order stuff: 'WAIT_FOx' +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUx 0 EXECUTE 2 HIT_LIMIT 3'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUx' +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTx 2 HIT_LIMIT 3'; +ERROR 42000: Illegal or out of order stuff: 'EXECUTx' +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIx 3'; +ERROR 42000: Illegal or out of order stuff: 'HIT_LIMIx' +SET DEBUG_SYNC='p0 CLEARx'; +ERROR 42000: Illegal or out of order stuff: 'CLEARx' +SET DEBUG_SYNC='p0 TESTx'; +ERROR 42000: Illegal or out of order stuff: 'TESTx' +SET DEBUG_SYNC='RESETx'; +ERROR 42000: Missing action after synchronization point name 'RESETx' +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 0x6 EXECUTE 2 HIT_LIMIT 3'; +ERROR 42000: Missing valid number after TIMEOUT +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 EXECUTE 0x2 HIT_LIMIT 3'; +ERROR 42000: Missing valid number after EXECUTE +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 7 EXECUTE 2 HIT_LIMIT 0x3'; +ERROR 42000: Missing valid number after HIT_LIMIT +SET DEBUG_SYNC= 7; +ERROR 42000: Incorrect argument type to variable 'debug_sync' +SET GLOBAL DEBUG_SYNC= 'p0 CLEAR'; +ERROR HY000: Variable 'debug_sync' is a SESSION variable and can't be used with SET GLOBAL +SET @myvar= 'now SIGNAL from_myvar'; +SET DEBUG_SYNC= @myvar; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 'from_myvar' +SET DEBUG_SYNC= LEFT('now SIGNAL from_function_cut_here', 24); +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 'from_function' +SET DEBUG_SYNC= 'now SIGNAL something'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 'something' +SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0'; +Warnings: +Warning #### debug sync point wait timed out +SET DEBUG_SYNC= 'now SIGNAL nothing'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 'nothing' +SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0'; +SET DEBUG_SYNC= 'now SIGNAL something EXECUTE 0'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 'nothing' +SET DEBUG_SYNC= 'now WAIT_FOR anotherthing TIMEOUT 0 EXECUTE 0'; +SET DEBUG_SYNC= 'now HIT_LIMIT 1'; +ERROR HY000: debug sync point hit limit reached +SET DEBUG_SYNC= 'RESET'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: '' +SET DEBUG_SYNC= 'p1abcd SIGNAL s1 EXECUTE 2'; +SET DEBUG_SYNC= 'p2abc SIGNAL s2 EXECUTE 2'; +SET DEBUG_SYNC= 'p9abcdef SIGNAL s9 EXECUTE 2'; +SET DEBUG_SYNC= 'p4a SIGNAL s4 EXECUTE 2'; +SET DEBUG_SYNC= 'p5abcde SIGNAL s5 EXECUTE 2'; +SET DEBUG_SYNC= 'p6ab SIGNAL s6 EXECUTE 2'; +SET DEBUG_SYNC= 'p7 SIGNAL s7 EXECUTE 2'; +SET DEBUG_SYNC= 'p8abcdef SIGNAL s8 EXECUTE 2'; +SET DEBUG_SYNC= 'p3abcdef SIGNAL s3 EXECUTE 2'; +SET DEBUG_SYNC= 'p4a TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's4' +SET DEBUG_SYNC= 'p1abcd TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's1' +SET DEBUG_SYNC= 'p7 TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's7' +SET DEBUG_SYNC= 'p9abcdef TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's9' +SET DEBUG_SYNC= 'p3abcdef TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's3' +SET DEBUG_SYNC= 'p1abcd CLEAR'; +SET DEBUG_SYNC= 'p2abc CLEAR'; +SET DEBUG_SYNC= 'p5abcde CLEAR'; +SET DEBUG_SYNC= 'p6ab CLEAR'; +SET DEBUG_SYNC= 'p8abcdef CLEAR'; +SET DEBUG_SYNC= 'p9abcdef CLEAR'; +SET DEBUG_SYNC= 'p3abcdef CLEAR'; +SET DEBUG_SYNC= 'p4a CLEAR'; +SET DEBUG_SYNC= 'p7 CLEAR'; +SET DEBUG_SYNC= 'p1abcd TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's3' +SET DEBUG_SYNC= 'p7 TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's3' +SET DEBUG_SYNC= 'p9abcdef TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's3' +SET DEBUG_SYNC= 'RESET'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: '' +CREATE USER mysqltest_1@localhost; +GRANT SUPER ON *.* TO mysqltest_1@localhost; +connection con1, mysqltest_1 +SET DEBUG_SYNC= 'RESET'; +connection default +DROP USER mysqltest_1@localhost; +CREATE USER mysqltest_2@localhost; +GRANT ALL ON *.* TO mysqltest_2@localhost; +REVOKE SUPER ON *.* FROM mysqltest_2@localhost; +connection con1, mysqltest_2 +SET DEBUG_SYNC= 'RESET'; +ERROR 42000: Access denied; you need the SUPER privilege for this operation +connection default +DROP USER mysqltest_2@localhost; +SET DEBUG_SYNC= 'RESET'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 INT); +connection con1 +SET DEBUG_SYNC= 'before_lock_tables_takes_lock + SIGNAL opened WAIT_FOR flushed'; +INSERT INTO t1 VALUES(1); +connection default +SET DEBUG_SYNC= 'now WAIT_FOR opened'; +SET DEBUG_SYNC= 'after_flush_unlock SIGNAL flushed'; +FLUSH TABLE t1; +connection con1 +connection default +DROP TABLE t1; +SET DEBUG_SYNC= 'RESET'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 INT); +LOCK TABLE t1 WRITE; +connection con1 +SET DEBUG_SYNC= 'wait_for_lock SIGNAL locked EXECUTE 2'; +INSERT INTO t1 VALUES (1); +connection default +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +UNLOCK TABLES; +connection con1 +retrieve INSERT result. +connection default +DROP TABLE t1; +SET DEBUG_SYNC= 'RESET'; diff --git a/mysql-test/r/have_debug_sync.require b/mysql-test/r/have_debug_sync.require new file mode 100644 index 00000000000..c2090bc5657 --- /dev/null +++ b/mysql-test/r/have_debug_sync.require @@ -0,0 +1,2 @@ +debug_sync +1 diff --git a/mysql-test/t/debug_sync.test b/mysql-test/t/debug_sync.test new file mode 100644 index 00000000000..514e471b603 --- /dev/null +++ b/mysql-test/t/debug_sync.test @@ -0,0 +1,420 @@ +###################### t/debug_sync.test ############################### +# # +# Testing of the Debug Sync Facility. # +# # +# There is important documentation within sql/debug_sync.cc # +# # +# Used objects in this test case: # +# p0 - synchronization point 0. Non-existent dummy sync point. # +# s1 - signal 1. # +# s2 - signal 2. # +# # +# Creation: # +# 2008-02-18 istruewing # +# # +######################################################################## + +# +# We need the Debug Sync Facility. +# +--source include/have_debug_sync.inc + +# +# We are checking privileges, which the embedded server cannot do. +# +--source include/not_embedded.inc + +# +# Preparative cleanup. +# +--disable_warnings +SET DEBUG_SYNC= 'RESET'; +DROP TABLE IF EXISTS t1; +--enable_warnings + +# +# Show the special system variable. +# It shows ON or OFF depending on the command line option --debug-sync. +# The test case assumes it is ON (command line option present). +# +SHOW VARIABLES LIKE 'DEBUG_SYNC'; + +# +# Syntax. Valid forms. +# +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 EXECUTE 2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 SIGNAL s1 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 EXECUTE 2'; +SET DEBUG_SYNC='p0 SIGNAL s1 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 EXECUTE 2'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 CLEAR'; +SET DEBUG_SYNC='p0 TEST'; +SET DEBUG_SYNC='RESET'; + +# +# Syntax. Valid forms. Lower case. +# +set debug_sync='p0 signal s1 wait_for s2 timeout 6 execute 2 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2 timeout 6 execute 2'; +set debug_sync='p0 signal s1 wait_for s2 timeout 6 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2 timeout 6'; +set debug_sync='p0 signal s1 wait_for s2 execute 2 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2 execute 2'; +set debug_sync='p0 signal s1 wait_for s2 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2'; +set debug_sync='p0 signal s1 execute 2 hit_limit 3'; +set debug_sync='p0 signal s1 execute 2'; +set debug_sync='p0 signal s1 hit_limit 3'; +set debug_sync='p0 signal s1'; +set debug_sync='p0 wait_for s2 timeout 6 execute 2 hit_limit 3'; +set debug_sync='p0 wait_for s2 timeout 6 execute 2'; +set debug_sync='p0 wait_for s2 timeout 6 hit_limit 3'; +set debug_sync='p0 wait_for s2 timeout 6'; +set debug_sync='p0 wait_for s2 execute 2 hit_limit 3'; +set debug_sync='p0 wait_for s2 execute 2'; +set debug_sync='p0 wait_for s2 hit_limit 3'; +set debug_sync='p0 wait_for s2'; +set debug_sync='p0 hit_limit 3'; +set debug_sync='p0 clear'; +set debug_sync='p0 test'; +set debug_sync='reset'; + +# +# Syntax. Valid forms. Line wrap, leading, mid, trailing space. +# +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 + EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC=' p0 SIGNAL s1 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 '; +SET DEBUG_SYNC=' p0 SIGNAL s1 WAIT_FOR s2 '; +SET DEBUG_SYNC=' p0 SIGNAL s1 WAIT_FOR s2 '; + +# +# Syntax. Invalid forms. +# +--error ER_PARSE_ERROR +SET DEBUG_SYNC=''; +--error ER_PARSE_ERROR +SET DEBUG_SYNC=' '; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 EXECUTE 2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 TIMEOUT 6 EXECUTE 2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 TIMEOUT 6'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 EXECUTE 2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 TIMEOUT 6 EXECUTE 2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 TIMEOUT 6'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 SIGNAL s1 EXECUTE 2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 SIGNAL s1'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 TIMEOUT 6 WAIT_FOR s2 EXECUTE 2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 TIMEOUT 6 WAIT_FOR s2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL s1 TIMEOUT 6 EXECUTE 2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL s1 TIMEOUT 6'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 EXECUTE 2 SIGNAL s1 TIMEOUT 6'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 TIMEOUT 6 SIGNAL s1'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 EXECUTE 2 TIMEOUT 6 SIGNAL s1'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 CLEAR HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='CLEAR'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 CLEAR p0'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='TEST'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 TEST p0'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 RESET'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='RESET p0'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 RESET p0'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL '; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR '; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL s1 EXECUTE '; + +# +# Syntax. Invalid keywords used. +# +--error ER_UNKNOWN_SYSTEM_VARIABLE +SET DEBUG_SYNCx='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAx s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOx s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUx 0 EXECUTE 2 HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTx 2 HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIx 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 CLEARx'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 TESTx'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='RESETx'; + +# +# Syntax. Invalid numbers. Decimal only. +# +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 0x6 EXECUTE 2 HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 EXECUTE 0x2 HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 7 EXECUTE 2 HIT_LIMIT 0x3'; + +# +# Syntax. Invalid value type. +# +--error ER_WRONG_TYPE_FOR_VAR +SET DEBUG_SYNC= 7; + +# +# Syntax. DEBUG_SYNC is a SESSION-only variable. +# +--error ER_LOCAL_VARIABLE +SET GLOBAL DEBUG_SYNC= 'p0 CLEAR'; + +# +# Syntax. The variable value does not need to be a string literal. +# +SET @myvar= 'now SIGNAL from_myvar'; +SET DEBUG_SYNC= @myvar; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +# +SET DEBUG_SYNC= LEFT('now SIGNAL from_function_cut_here', 24); +SHOW VARIABLES LIKE 'DEBUG_SYNC'; + +# +# Functional tests. +# +# NOTE: There is the special synchronization point 'now'. It is placed +# immediately after setting of the DEBUG_SYNC variable. +# So it is executed before the SET statement ends. +# +# NOTE: There is only one global signal (say "signal post" or "flag mast"). +# A SIGNAL action writes its signal into it ("sets a flag"). +# The signal persists until explicitly overwritten. +# To avoid confusion for later tests, it is recommended to clear +# the signal by signalling "empty" ("setting the 'empty' flag"): +# SET DEBUG_SYNC= 'now SIGNAL empty'; +# Preferably you can reset the whole facility with: +# SET DEBUG_SYNC= 'RESET'; +# The signal is then '' (really empty) which connot be done otherwise. +# + +# +# Time out immediately. This gives just a warning. +# +SET DEBUG_SYNC= 'now SIGNAL something'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +# Suppress warning number +--replace_column 2 #### +SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0'; +# +# If signal is present already, TIMEOUT 0 does not give a warning. +# +SET DEBUG_SYNC= 'now SIGNAL nothing'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0'; + +# +# EXECUTE 0 is effectively a no-op. +# +SET DEBUG_SYNC= 'now SIGNAL something EXECUTE 0'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'now WAIT_FOR anotherthing TIMEOUT 0 EXECUTE 0'; + +# +# Run into HIT_LIMIT. This gives an error. +# +--error ER_DEBUG_SYNC_HIT_LIMIT +SET DEBUG_SYNC= 'now HIT_LIMIT 1'; + +# +# Many actions. Watch the array growing and shrinking in the debug trace: +# egrep 'query:|debug_sync_action:' mysql-test/var/log/master.trace +# +SET DEBUG_SYNC= 'RESET'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'p1abcd SIGNAL s1 EXECUTE 2'; +SET DEBUG_SYNC= 'p2abc SIGNAL s2 EXECUTE 2'; +SET DEBUG_SYNC= 'p9abcdef SIGNAL s9 EXECUTE 2'; +SET DEBUG_SYNC= 'p4a SIGNAL s4 EXECUTE 2'; +SET DEBUG_SYNC= 'p5abcde SIGNAL s5 EXECUTE 2'; +SET DEBUG_SYNC= 'p6ab SIGNAL s6 EXECUTE 2'; +SET DEBUG_SYNC= 'p7 SIGNAL s7 EXECUTE 2'; +SET DEBUG_SYNC= 'p8abcdef SIGNAL s8 EXECUTE 2'; +SET DEBUG_SYNC= 'p3abcdef SIGNAL s3 EXECUTE 2'; +# +# Execute some actions to show they exist. Each sets a distinct signal. +# +SET DEBUG_SYNC= 'p4a TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'p1abcd TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'p7 TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'p9abcdef TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'p3abcdef TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +# +# Clear the actions. +# +SET DEBUG_SYNC= 'p1abcd CLEAR'; +SET DEBUG_SYNC= 'p2abc CLEAR'; +SET DEBUG_SYNC= 'p5abcde CLEAR'; +SET DEBUG_SYNC= 'p6ab CLEAR'; +SET DEBUG_SYNC= 'p8abcdef CLEAR'; +SET DEBUG_SYNC= 'p9abcdef CLEAR'; +SET DEBUG_SYNC= 'p3abcdef CLEAR'; +SET DEBUG_SYNC= 'p4a CLEAR'; +SET DEBUG_SYNC= 'p7 CLEAR'; +# +# Execute some actions to show they have gone. +# +SET DEBUG_SYNC= 'p1abcd TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'p7 TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'p9abcdef TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +# +# Now cleanup. Actions are clear already, but signal needs to be cleared. +# +SET DEBUG_SYNC= 'RESET'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; + +# +# Facility requires SUPER privilege. +# +CREATE USER mysqltest_1@localhost; +GRANT SUPER ON *.* TO mysqltest_1@localhost; +--echo connection con1, mysqltest_1 +connect (con1,localhost,mysqltest_1,,); +SET DEBUG_SYNC= 'RESET'; +disconnect con1; +--echo connection default +connection default; +DROP USER mysqltest_1@localhost; +# +CREATE USER mysqltest_2@localhost; +GRANT ALL ON *.* TO mysqltest_2@localhost; +REVOKE SUPER ON *.* FROM mysqltest_2@localhost; +--echo connection con1, mysqltest_2 +connect (con1,localhost,mysqltest_2,,); +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +SET DEBUG_SYNC= 'RESET'; +disconnect con1; +--echo connection default +connection default; +DROP USER mysqltest_2@localhost; + +# +# Example 1. +# +# Preparative cleanup. +--disable_warnings +SET DEBUG_SYNC= 'RESET'; +DROP TABLE IF EXISTS t1; +--enable_warnings +# +# Test. +CREATE TABLE t1 (c1 INT); + --echo connection con1 + connect (con1,localhost,root,,); + SET DEBUG_SYNC= 'before_lock_tables_takes_lock + SIGNAL opened WAIT_FOR flushed'; + send INSERT INTO t1 VALUES(1); +--echo connection default +connection default; +SET DEBUG_SYNC= 'now WAIT_FOR opened'; +SET DEBUG_SYNC= 'after_flush_unlock SIGNAL flushed'; +FLUSH TABLE t1; + --echo connection con1 + connection con1; + reap; + disconnect con1; +--echo connection default +connection default; +DROP TABLE t1; + +# +# Example 2. +# +# Preparative cleanup. +--disable_warnings +SET DEBUG_SYNC= 'RESET'; +DROP TABLE IF EXISTS t1; +--enable_warnings +# +# Test. +CREATE TABLE t1 (c1 INT); +LOCK TABLE t1 WRITE; + --echo connection con1 + connect (con1,localhost,root,,); + # Retain action after use. First used by general_log. + SET DEBUG_SYNC= 'wait_for_lock SIGNAL locked EXECUTE 2'; + send INSERT INTO t1 VALUES (1); +--echo connection default +connection default; +# Wait until INSERT waits for lock. +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +# let INSERT continue. +UNLOCK TABLES; + --echo connection con1 + connection con1; + --echo retrieve INSERT result. + reap; + disconnect con1; +--echo connection default +connection default; +DROP TABLE t1; + +# +# Cleanup after test case. +# Otherwise signal would contain 'flushed' here, +# which could confuse the next test. +# +SET DEBUG_SYNC= 'RESET'; + diff --git a/mysys/my_static.c b/mysys/my_static.c index d0c20da828a..a21a3d11104 100644 --- a/mysys/my_static.c +++ b/mysys/my_static.c @@ -92,6 +92,14 @@ int (*error_handler_hook)(uint error,const char *str,myf MyFlags)= int (*fatal_error_handler_hook)(uint error,const char *str,myf MyFlags)= my_message_no_curses; +#if defined(ENABLED_DEBUG_SYNC) +/** + Global pointer to be set if callback function is defined + (e.g. in mysqld). See sql/debug_sync.cc. +*/ +void (*debug_sync_C_callback_ptr)(const char *, size_t); +#endif /* defined(ENABLED_DEBUG_SYNC) */ + #ifdef __WIN__ /* from my_getsystime.c */ ulonglong query_performance_frequency, query_performance_offset; diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 31638ecee9a..0e0e93cf220 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -398,6 +398,28 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, my_bool can_deadlock= test(data->owner->info->n_cursors); DBUG_ENTER("wait_for_lock"); + /* + One can use this to signal when a thread is going to wait for a lock. + See debug_sync.cc. + + Beware of waiting for a signal here. The lock has aquired its mutex. + While waiting on a signal here, the locking thread could not aquire + the mutex to release the lock. One could lock up the table + completely. + + In detail it works so: When thr_lock() tries to acquire a table + lock, it locks the lock->mutex, checks if it can have the lock, and + if not, it calls wait_for_lock(). Here it unlocks the table lock + while waiting on a condition. The sync point is located before this + wait for condition. If we have a waiting action here, we hold the + the table locks mutex all the time. Any attempt to look at the table + lock by another thread blocks it immediately on lock->mutex. This + can easily become an unexpected and unobvious blockage. So be + warned: Do not request a WAIT_FOR action for the 'wait_for_lock' + sync point unless you really know what you do. + */ + DEBUG_SYNC_C("wait_for_lock"); + if (!in_wait_list) { (*wait->last)=data; /* Wait for lock */ diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 6f162f4d84d..7f6074c903c 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -64,6 +64,7 @@ SET (SQL_SOURCE sql_error.cc sql_handler.cc sql_help.cc sql_insert.cc sql_lex.cc sql_list.cc sql_load.cc sql_manager.cc sql_map.cc sql_parse.cc sql_partition.cc sql_plugin.cc sql_prepare.cc sql_rename.cc + debug_sync.cc debug_sync.h sql_repl.cc sql_select.cc sql_show.cc sql_state.c sql_string.cc sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc diff --git a/sql/Makefile.am b/sql/Makefile.am index 2a12de2eaf6..0b22481f850 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -58,6 +58,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ ha_ndbcluster.h ha_ndbcluster_cond.h \ ha_ndbcluster_binlog.h ha_ndbcluster_tables.h \ ha_partition.h rpl_constants.h \ + debug_sync.h \ opt_range.h protocol.h rpl_tblmap.h rpl_utility.h \ rpl_reporting.h \ log.h sql_show.h rpl_rli.h rpl_mi.h \ @@ -102,6 +103,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ discover.cc time.cc opt_range.cc opt_sum.cc \ records.cc filesort.cc handler.cc \ ha_partition.cc \ + debug_sync.cc \ sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \ sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \ sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \ diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc new file mode 100644 index 00000000000..58ec4af7841 --- /dev/null +++ b/sql/debug_sync.cc @@ -0,0 +1,1906 @@ +/* Copyright (C) 2008 MySQL AB, 2008 - 2009 Sun Microsystems, Inc. + + 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 Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/** + == Debug Sync Facility == + + The Debug Sync Facility allows placement of synchronization points in + the server code by using the DEBUG_SYNC macro: + + open_tables(...) + + DEBUG_SYNC(thd, "after_open_tables"); + + lock_tables(...) + + When activated, a sync point can + + - Emit a signal and/or + - Wait for a signal + + Nomenclature: + + - signal: A value of a global variable that persists + until overwritten by a new signal. The global + variable can also be seen as a "signal post" + or "flag mast". Then the signal is what is + attached to the "signal post" or "flag mast". + + - emit a signal: Assign the value (the signal) to the global + variable ("set a flag") and broadcast a + global condition to wake those waiting for + a signal. + + - wait for a signal: Loop over waiting for the global condition until + the global value matches the wait-for signal. + + By default, all sync points are inactive. They do nothing (except to + burn a couple of CPU cycles for checking if they are active). + + A sync point becomes active when an action is requested for it. + To do so, put a line like this in the test case file: + + SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed'; + + This activates the sync point 'after_open_tables'. It requests it to + emit the signal 'opened' and wait for another thread to emit the signal + 'flushed' when the thread's execution runs through the sync point. + + For every sync point there can be one action per thread only. Every + thread can request multiple actions, but only one per sync point. In + other words, a thread can activate multiple sync points. + + Here is an example how to activate and use the sync points: + + --connection conn1 + SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed'; + send INSERT INTO t1 VALUES(1); + --connection conn2 + SET DEBUG_SYNC= 'now WAIT_FOR opened'; + SET DEBUG_SYNC= 'after_abort_locks SIGNAL flushed'; + FLUSH TABLE t1; + + When conn1 runs through the INSERT statement, it hits the sync point + 'after_open_tables'. It notices that it is active and executes its + action. It emits the signal 'opened' and waits for another thread to + emit the signal 'flushed'. + + conn2 waits immediately at the special sync point 'now' for another + thread to emit the 'opened' signal. + + A signal remains in effect until it is overwritten. If conn1 signals + 'opened' before conn2 reaches 'now', conn2 will still find the 'opened' + signal. It does not wait in this case. + + When conn2 reaches 'after_abort_locks', it signals 'flushed', which lets + conn1 awake. + + Normally the activation of a sync point is cleared when it has been + executed. Sometimes it is necessary to keep the sync point active for + another execution. You can add an execute count to the action: + + SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 3'; + + This sets the signal point's activation counter to 3. Each execution + decrements the counter. After the third execution the sync point + becomes inactive. + + One of the primary goals of this facility is to eliminate sleeps from + the test suite. In most cases it should be possible to rewrite test + cases so that they do not need to sleep. (But this facility cannot + synchronize multiple processes.) However, to support test development, + and as a last resort, sync point waiting times out. There is a default + timeout, but it can be overridden: + + SET DEBUG_SYNC= 'name WAIT_FOR sig TIMEOUT 10 EXECUTE 2'; + + TIMEOUT 0 is special: If the signal is not present, the wait times out + immediately. + + When a wait timed out (even on TIMEOUT 0), a warning is generated so + that it shows up in the test result. + + You can throw an error message and kill the query when a synchronization + point is hit a certain number of times: + + SET DEBUG_SYNC= 'name HIT_LIMIT 3'; + + Or combine it with signal and/or wait: + + SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 2 HIT_LIMIT 3'; + + Here the first two hits emit the signal, the third hit returns the error + message and kills the query. + + For cases where you are not sure that an action is taken and thus + cleared in any case, you can force to clear (deactivate) a sync point: + + SET DEBUG_SYNC= 'name CLEAR'; + + If you want to clear all actions and clear the global signal, use: + + SET DEBUG_SYNC= 'RESET'; + + This is the only way to reset the global signal to an empty string. + + For testing of the facility itself you can execute a sync point just + as if it had been hit: + + SET DEBUG_SYNC= 'name TEST'; + + + === Formal Syntax === + + The string to "assign" to the DEBUG_SYNC variable can contain: + + {RESET | + TEST | + CLEAR | + {{SIGNAL | + WAIT_FOR [TIMEOUT ]} + [EXECUTE ] &| HIT_LIMIT } + + Here '&|' means 'and/or'. This means that one of the sections + separated by '&|' must be present or both of them. + + + === Activation/Deactivation === + + The facility is an optional part of the MySQL server. + It is enabled in a debug server by default. + + ./configure --enable-debug-sync + + The Debug Sync Facility, when compiled in, is disabled by default. It + can be enabled by a mysqld command line option: + + --debug-sync-timeout[=default_wait_timeout_value_in_seconds] + + 'default_wait_timeout_value_in_seconds' is the default timeout for the + WAIT_FOR action. If set to zero, the facility stays disabled. + + The facility is enabled by default in the test suite, but can be + disabled with: + + mysql-test-run.pl ... --debug-sync-timeout=0 ... + + Likewise the default wait timeout can be set: + + mysql-test-run.pl ... --debug-sync-timeout=10 ... + + The command line option influences the readable value of the system + variable 'debug_sync'. + + * If the facility is not compiled in, the system variable does not exist. + + * If --debug-sync-timeout=0 the value of the variable reads as "OFF". + + * Otherwise the value reads as "ON - current signal: " followed by the + current signal string, which can be empty. + + The readable variable value is the same, regardless if read as global + or session value. + + Setting the 'debug-sync' system variable requires 'SUPER' privilege. + You can never read back the string that you assigned to the variable, + unless you assign the value that the variable does already have. But + that would give a parse error. A syntactically correct string is + parsed into a debug sync action and stored apart from the variable value. + + + === Implementation === + + Pseudo code for a sync point: + + #define DEBUG_SYNC(thd, sync_point_name) + if (unlikely(opt_debug_sync_timeout)) + debug_sync(thd, STRING_WITH_LEN(sync_point_name)) + + The sync point performs a binary search in a sorted array of actions + for this thread. + + The SET DEBUG_SYNC statement adds a requested action to the array or + overwrites an existing action for the same sync point. When it adds a + new action, the array is sorted again. + + + === A typical synchronization pattern === + + There are quite a few places in MySQL, where we use a synchronization + pattern like this: + + pthread_mutex_lock(&mutex); + thd->enter_cond(&condition_variable, &mutex, new_message); + #if defined(ENABLE_DEBUG_SYNC) + if (!thd->killed && !end_of_wait_condition) + DEBUG_SYNC(thd, "sync_point_name"); + #endif + while (!thd->killed && !end_of_wait_condition) + pthread_cond_wait(&condition_variable, &mutex); + thd->exit_cond(old_message); + + Here some explanations: + + thd->enter_cond() is used to register the condition variable and the + mutex in thd->mysys_var. This is done to allow the thread to be + interrupted (killed) from its sleep. Another thread can find the + condition variable to signal and mutex to use for synchronization in + this thread's THD::mysys_var. + + thd->enter_cond() requires the mutex to be acquired in advance. + + thd->exit_cond() unregisters the condition variable and mutex and + releases the mutex. + + If you want to have a Debug Sync point with the wait, please place it + behind enter_cond(). Only then you can safely decide, if the wait will + be taken. Also you will have THD::proc_info correct when the sync + point emits a signal. DEBUG_SYNC sets its own proc_info, but restores + the previous one before releasing its internal mutex. As soon as + another thread sees the signal, it does also see the proc_info from + before entering the sync point. In this case it will be "new_message", + which is associated with the wait that is to be synchronized. + + In the example above, the wait condition is repeated before the sync + point. This is done to skip the sync point, if no wait takes place. + The sync point is before the loop (not inside the loop) to have it hit + once only. It is possible that the condition variable is signaled + multiple times without the wait condition to be true. + + A bit off-topic: At some places, the loop is taken around the whole + synchronization pattern: + + while (!thd->killed && !end_of_wait_condition) + { + pthread_mutex_lock(&mutex); + thd->enter_cond(&condition_variable, &mutex, new_message); + if (!thd->killed [&& !end_of_wait_condition]) + { + [DEBUG_SYNC(thd, "sync_point_name");] + pthread_cond_wait(&condition_variable, &mutex); + } + thd->exit_cond(old_message); + } + + Note that it is important to repeat the test for thd->killed after + enter_cond(). Otherwise the killing thread may kill this thread after + it tested thd->killed in the loop condition and before it registered + the condition variable and mutex in enter_cond(). In this case, the + killing thread does not know that this thread is going to wait on a + condition variable. It would just set THD::killed. But if we would not + test it again, we would go asleep though we are killed. If the killing + thread would kill us when we are after the second test, but still + before sleeping, we hold the mutex, which is registered in mysys_var. + The killing thread would try to acquire the mutex before signaling + the condition variable. Since the mutex is only released implicitly in + pthread_cond_wait(), the signaling happens at the right place. We + have a safe synchronization. + + === Co-work with the DBUG facility === + + When running the MySQL test suite with the --debug command line + option, the Debug Sync Facility writes trace messages to the DBUG + trace. The following shell commands proved very useful in extracting + relevant information: + + egrep 'query:|debug_sync_exec:' mysql-test/var/log/mysqld.1.trace + + It shows all executed SQL statements and all actions executed by + synchronization points. + + Sometimes it is also useful to see, which synchronization points have + been run through (hit) with or without executing actions. Then add + "|debug_sync_point:" to the egrep pattern. + + === Further reading === + + For a discussion of other methods to synchronize threads see + http://forge.mysql.com/wiki/MySQL_Internals_Test_Synchronization + + For complete syntax tests, functional tests, and examples see the test + case debug_sync.test. + + See also worklog entry WL#4259 - Test Synchronization Facility +*/ + +#include "debug_sync.h" + +#if defined(ENABLED_DEBUG_SYNC) + +/* + Due to weaknesses in our include files, we need to include + mysql_priv.h here. To have THD declared, we need to include + sql_class.h. This includes log_event.h, which in turn requires + declarations from mysql_priv.h (e.g. OPTION_AUTO_IS_NULL). + mysql_priv.h includes almost everything, so is sufficient here. +*/ +#include "mysql_priv.h" + +/* + Action to perform at a synchronization point. + NOTE: This structure is moved around in memory by realloc(), qsort(), + and memmove(). Do not add objects with non-trivial constuctors + or destructors, which might prevent moving of this structure + with these functions. +*/ +struct st_debug_sync_action +{ + ulong activation_count; /* max(hit_limit, execute) */ + ulong hit_limit; /* hits before kill query */ + ulong execute; /* executes before self-clear */ + ulong timeout; /* wait_for timeout */ + String signal; /* signal to emit */ + String wait_for; /* signal to wait for */ + String sync_point; /* sync point name */ + bool need_sort; /* if new action, array needs sort */ +}; + +/* Debug sync control. Referenced by THD. */ +struct st_debug_sync_control +{ + st_debug_sync_action *ds_action; /* array of actions */ + uint ds_active; /* # active actions */ + uint ds_allocated; /* # allocated actions */ + ulonglong dsp_hits; /* statistics */ + ulonglong dsp_executed; /* statistics */ + ulonglong dsp_max_active; /* statistics */ + /* + thd->proc_info points at unsynchronized memory. + It must not go away as long as the thread exists. + */ + char ds_proc_info[80]; /* proc_info string */ +}; + + +/** + Definitions for the debug sync facility. + 1. Global string variable to hold a "signal" ("signal post", "flag mast"). + 2. Global condition variable for signaling and waiting. + 3. Global mutex to synchronize access to the above. +*/ +struct st_debug_sync_globals +{ + String ds_signal; /* signal variable */ + pthread_cond_t ds_cond; /* condition variable */ + pthread_mutex_t ds_mutex; /* mutex variable */ + ulonglong dsp_hits; /* statistics */ + ulonglong dsp_executed; /* statistics */ + ulonglong dsp_max_active; /* statistics */ +}; +static st_debug_sync_globals debug_sync_global; /* All globals in one object */ + +/** + Callback pointer for C files. +*/ +extern "C" void (*debug_sync_C_callback_ptr)(const char *, size_t); + + +/** + Callback for debug sync, to be used by C files. See thr_lock.c for example. + + @description + + We cannot place a sync point directly in C files (like those in mysys or + certain storage engines written mostly in C like MyISAM or Maria). Because + they are C code and do not include mysql_priv.h. So they do not know the + macro DEBUG_SYNC(thd, sync_point_name). The macro needs a 'thd' argument. + Hence it cannot be used in files outside of the sql/ directory. + + The workaround is to call back simple functions like this one from + non-sql/ files. + + We want to allow modules like thr_lock to be used without sql/ and + especially without Debug Sync. So we cannot just do a simple call + of the callback function. Instead we provide a global pointer in + the other file, which is to be set to the callback by Debug Sync. + If the pointer is not set, no call back will be done. If Debug + Sync sets the pointer to a callback function like this one, it will + be called. That way thr_lock.c does not have an undefined reference + to Debug Sync and can be used without it. Debug Sync, in contrast, + has an undefined reference to that pointer and thus requires + thr_lock to be linked too. But this is not a problem as it is part + of the MySQL server anyway. + + @note + The callback pointer in C files is set only if debug sync is + initialized. And this is done only if opt_debug_sync_timeout is set. +*/ + +static void debug_sync_C_callback(const char *sync_point_name, + size_t name_len) +{ + if (unlikely(opt_debug_sync_timeout)) + debug_sync(current_thd, sync_point_name, name_len); +} + + +/** + Initialize the debug sync facility at server start. + + @return status + @retval 0 ok + @retval != 0 error +*/ + +int debug_sync_init(void) +{ + DBUG_ENTER("debug_sync_init"); + + if (opt_debug_sync_timeout) + { + int rc; + + /* Initialize the global variables. */ + debug_sync_global.ds_signal.length(0); + if ((rc= pthread_cond_init(&debug_sync_global.ds_cond, NULL)) || + (rc= pthread_mutex_init(&debug_sync_global.ds_mutex, + MY_MUTEX_INIT_FAST))) + DBUG_RETURN(rc); /* purecov: inspected */ + + /* Set the call back pointer in C files. */ + debug_sync_C_callback_ptr= debug_sync_C_callback; + } + + DBUG_RETURN(0); +} + + +/** + End the debug sync facility. + + @description + This is called at server shutdown or after a thread initialization error. +*/ + +void debug_sync_end(void) +{ + DBUG_ENTER("debug_sync_end"); + + /* End the facility only if it had been initialized. */ + if (debug_sync_C_callback_ptr) + { + /* Clear the call back pointer in C files. */ + debug_sync_C_callback_ptr= NULL; + + /* Destroy the global variables. */ + debug_sync_global.ds_signal.free(); + (void) pthread_cond_destroy(&debug_sync_global.ds_cond); + (void) pthread_mutex_destroy(&debug_sync_global.ds_mutex); + + /* Print statistics. */ + { + char llbuff[22]; + sql_print_information("Debug sync points hit: %22s", + llstr(debug_sync_global.dsp_hits, llbuff)); + sql_print_information("Debug sync points executed: %22s", + llstr(debug_sync_global.dsp_executed, llbuff)); + sql_print_information("Debug sync points max active per thread: %22s", + llstr(debug_sync_global.dsp_max_active, llbuff)); + } + } + + DBUG_VOID_RETURN; +} + + +/* purecov: begin tested */ + +/** + Disable the facility after lack of memory if no error can be returned. + + @note + Do not end the facility here because the global variables can + be in use by other threads. +*/ + +static void debug_sync_emergency_disable(void) +{ + DBUG_ENTER("debug_sync_emergency_disable"); + + opt_debug_sync_timeout= 0; + + DBUG_PRINT("debug_sync", + ("Debug Sync Facility disabled due to lack of memory.")); + sql_print_error("Debug Sync Facility disabled due to lack of memory."); + + DBUG_VOID_RETURN; +} + +/* purecov: end */ + + +/** + Initialize the debug sync facility at thread start. + + @param[in] thd thread handle +*/ + +void debug_sync_init_thread(THD *thd) +{ + DBUG_ENTER("debug_sync_init_thread"); + DBUG_ASSERT(thd); + + if (opt_debug_sync_timeout) + { + thd->debug_sync_control= (st_debug_sync_control*) + my_malloc(sizeof(st_debug_sync_control), MYF(MY_WME | MY_ZEROFILL)); + if (!thd->debug_sync_control) + { + /* + Error is reported by my_malloc(). + We must disable the facility. We have no way to return an error. + */ + debug_sync_emergency_disable(); /* purecov: tested */ + } + } + + DBUG_VOID_RETURN; +} + + +/** + End the debug sync facility at thread end. + + @param[in] thd thread handle +*/ + +void debug_sync_end_thread(THD *thd) +{ + DBUG_ENTER("debug_sync_end_thread"); + DBUG_ASSERT(thd); + + if (thd->debug_sync_control) + { + st_debug_sync_control *ds_control= thd->debug_sync_control; + + /* + This synchronization point can be used to synchronize on thread end. + This is the latest point in a THD's life, where this can be done. + */ + DEBUG_SYNC(thd, "thread_end"); + + if (ds_control->ds_action) + { + st_debug_sync_action *action= ds_control->ds_action; + st_debug_sync_action *action_end= action + ds_control->ds_allocated; + for (; action < action_end; action++) + { + action->signal.free(); + action->wait_for.free(); + action->sync_point.free(); + } + my_free(ds_control->ds_action, MYF(0)); + } + + /* Statistics. */ + pthread_mutex_lock(&debug_sync_global.ds_mutex); + debug_sync_global.dsp_hits+= ds_control->dsp_hits; + debug_sync_global.dsp_executed+= ds_control->dsp_executed; + if (debug_sync_global.dsp_max_active < ds_control->dsp_max_active) + debug_sync_global.dsp_max_active= ds_control->dsp_max_active; + pthread_mutex_unlock(&debug_sync_global.ds_mutex); + + my_free(ds_control, MYF(0)); + thd->debug_sync_control= NULL; + } + + DBUG_VOID_RETURN; +} + + +/** + Move a string by length. + + @param[out] to buffer for the resulting string + @param[in] to_end end of buffer + @param[in] from source string + @param[in] length number of bytes to copy + + @return pointer to end of copied string +*/ + +static char *debug_sync_bmove_len(char *to, char *to_end, + const char *from, size_t length) +{ + DBUG_ASSERT(to); + DBUG_ASSERT(to_end); + DBUG_ASSERT(!length || from); + set_if_smaller(length, (size_t) (to_end - to)); + memcpy(to, from, length); + return (to + length); +} + + +#if !defined(DBUG_OFF) + +/** + Create a string that describes an action. + + @param[out] result buffer for the resulting string + @param[in] size size of result buffer + @param[in] action action to describe +*/ + +static void debug_sync_action_string(char *result, uint size, + st_debug_sync_action *action) +{ + char *wtxt= result; + char *wend= wtxt + size - 1; /* Allow emergency '\0'. */ + DBUG_ASSERT(result); + DBUG_ASSERT(action); + + /* If an execute count is present, signal or wait_for are needed too. */ + DBUG_ASSERT(!action->execute || + action->signal.length() || action->wait_for.length()); + + if (action->execute) + { + if (action->signal.length()) + { + wtxt= debug_sync_bmove_len(wtxt, wend, STRING_WITH_LEN("SIGNAL ")); + wtxt= debug_sync_bmove_len(wtxt, wend, action->signal.ptr(), + action->signal.length()); + } + if (action->wait_for.length()) + { + if ((wtxt == result) && (wtxt < wend)) + *(wtxt++)= ' '; + wtxt= debug_sync_bmove_len(wtxt, wend, STRING_WITH_LEN(" WAIT_FOR ")); + wtxt= debug_sync_bmove_len(wtxt, wend, action->wait_for.ptr(), + action->wait_for.length()); + + if (action->timeout != opt_debug_sync_timeout) + { + wtxt+= my_snprintf(wtxt, wend - wtxt, " TIMEOUT %lu", action->timeout); + } + } + if (action->execute != 1) + { + wtxt+= my_snprintf(wtxt, wend - wtxt, " EXECUTE %lu", action->execute); + } + } + if (action->hit_limit) + { + wtxt+= my_snprintf(wtxt, wend - wtxt, "%sHIT_LIMIT %lu", + (wtxt == result) ? "" : " ", action->hit_limit); + } + + /* + If (wtxt == wend) string may not be terminated. + There is one byte left for an emergency termination. + */ + *wtxt= '\0'; +} + + +/** + Print actions. + + @param[in] thd thread handle +*/ + +static void debug_sync_print_actions(THD *thd) +{ + st_debug_sync_control *ds_control= thd->debug_sync_control; + uint idx; + DBUG_ENTER("debug_sync_print_actions"); + DBUG_ASSERT(thd); + + if (!ds_control) + return; + + for (idx= 0; idx < ds_control->ds_active; idx++) + { + const char *dsp_name= ds_control->ds_action[idx].sync_point.c_ptr(); + char action_string[256]; + + debug_sync_action_string(action_string, sizeof(action_string), + ds_control->ds_action + idx); + DBUG_PRINT("debug_sync_list", ("%s %s", dsp_name, action_string)); + } + + DBUG_VOID_RETURN; +} + +#endif /* !defined(DBUG_OFF) */ + + +/** + Compare two actions by sync point name length, string. + + @param[in] arg1 reference to action1 + @param[in] arg2 reference to action2 + + @return difference + @retval == 0 length1/string1 is same as length2/string2 + @retval < 0 length1/string1 is smaller + @retval > 0 length1/string1 is bigger +*/ + +static int debug_sync_qsort_cmp(const void* arg1, const void* arg2) +{ + st_debug_sync_action *action1= (st_debug_sync_action*) arg1; + st_debug_sync_action *action2= (st_debug_sync_action*) arg2; + int diff; + DBUG_ASSERT(action1); + DBUG_ASSERT(action2); + + if (!(diff= action1->sync_point.length() - action2->sync_point.length())) + diff= memcmp(action1->sync_point.ptr(), action2->sync_point.ptr(), + action1->sync_point.length()); + + return diff; +} + + +/** + Find a debug sync action. + + @param[in] actionarr array of debug sync actions + @param[in] quantity number of actions in array + @param[in] dsp_name name of debug sync point to find + @param[in] name_len length of name of debug sync point + + @return action + @retval != NULL found sync point in array + @retval NULL not found + + @description + Binary search. Array needs to be sorted by length, sync point name. +*/ + +static st_debug_sync_action *debug_sync_find(st_debug_sync_action *actionarr, + int quantity, + const char *dsp_name, + uint name_len) +{ + st_debug_sync_action *action; + int low ; + int high ; + int mid ; + int diff ; + DBUG_ASSERT(actionarr); + DBUG_ASSERT(dsp_name); + DBUG_ASSERT(name_len); + + low= 0; + high= quantity; + + while (low < high) + { + mid= (low + high) / 2; + action= actionarr + mid; + if (!(diff= name_len - action->sync_point.length()) && + !(diff= memcmp(dsp_name, action->sync_point.ptr(), name_len))) + return action; + if (diff > 0) + low= mid + 1; + else + high= mid - 1; + } + + if (low < quantity) + { + action= actionarr + low; + if ((name_len == action->sync_point.length()) && + !memcmp(dsp_name, action->sync_point.ptr(), name_len)) + return action; + } + + return NULL; +} + + +/** + Reset the debug sync facility. + + @param[in] thd thread handle + + @description + Remove all actions of this thread. + Clear the global signal. +*/ + +static void debug_sync_reset(THD *thd) +{ + st_debug_sync_control *ds_control= thd->debug_sync_control; + DBUG_ENTER("debug_sync_reset"); + DBUG_ASSERT(thd); + DBUG_ASSERT(ds_control); + + /* Remove all actions of this thread. */ + ds_control->ds_active= 0; + + /* Clear the global signal. */ + pthread_mutex_lock(&debug_sync_global.ds_mutex); + debug_sync_global.ds_signal.length(0); + pthread_mutex_unlock(&debug_sync_global.ds_mutex); + + DBUG_VOID_RETURN; +} + + +/** + Remove a debug sync action. + + @param[in] ds_control control object + @param[in] action action to be removed + + @description + Removing an action mainly means to decrement the ds_active counter. + But if the action is between other active action in the array, then + the array needs to be shrinked. The active actions above the one to + be removed have to be moved down by one slot. +*/ + +static void debug_sync_remove_action(st_debug_sync_control *ds_control, + st_debug_sync_action *action) +{ + uint dsp_idx= action - ds_control->ds_action; + DBUG_ENTER("debug_sync_remove_action"); + DBUG_ASSERT(ds_control); + DBUG_ASSERT(ds_control == current_thd->debug_sync_control); + DBUG_ASSERT(action); + DBUG_ASSERT(dsp_idx < ds_control->ds_active); + + /* Decrement the number of currently active actions. */ + ds_control->ds_active--; + + /* + If this was not the last active action in the array, we need to + shift remaining active actions down to keep the array gap-free. + Otherwise binary search might fail or take longer than necessary at + least. Also new actions are always put to the end of the array. + */ + if (ds_control->ds_active > dsp_idx) + { + /* + Do not make save_action an object of class st_debug_sync_action. + Its destructor would tamper with the String pointers. + */ + uchar save_action[sizeof(st_debug_sync_action)]; + + /* + Copy the to-be-removed action object to temporary storage before + the shift copies the string pointers over. Do not use assignment + because it would use assignment operator methods for the Strings. + This would copy the strings. The shift below overwrite the string + pointers without freeing them first. By using memmove() we save + the pointers, which are overwritten by the shift. + */ + memmove(save_action, action, sizeof(st_debug_sync_action)); + + /* Move actions down. */ + memmove(ds_control->ds_action + dsp_idx, + ds_control->ds_action + dsp_idx + 1, + (ds_control->ds_active - dsp_idx) * + sizeof(st_debug_sync_action)); + + /* + Copy back the saved action object to the now free array slot. This + replaces the double references of String pointers that have been + produced by the shift. Again do not use an assignment operator to + avoid string allocation/copy. + */ + memmove(ds_control->ds_action + ds_control->ds_active, save_action, + sizeof(st_debug_sync_action)); + } + + DBUG_VOID_RETURN; +} + + +/** + Get a debug sync action. + + @param[in] thd thread handle + @param[in] dsp_name debug sync point name + @param[in] name_len length of sync point name + + @return action + @retval != NULL ok + @retval NULL error + + @description + Find the debug sync action for a debug sync point or make a new one. +*/ + +static st_debug_sync_action *debug_sync_get_action(THD *thd, + const char *dsp_name, + uint name_len) +{ + st_debug_sync_control *ds_control= thd->debug_sync_control; + st_debug_sync_action *action; + DBUG_ENTER("debug_sync_get_action"); + DBUG_ASSERT(thd); + DBUG_ASSERT(dsp_name); + DBUG_ASSERT(name_len); + DBUG_ASSERT(ds_control); + DBUG_PRINT("debug_sync", ("sync_point: '%.*s'", (int) name_len, dsp_name)); + DBUG_PRINT("debug_sync", ("active: %u allocated: %u", + ds_control->ds_active, ds_control->ds_allocated)); + + /* There cannot be more active actions than allocated. */ + DBUG_ASSERT(ds_control->ds_active <= ds_control->ds_allocated); + /* If there are active actions, the action array must be present. */ + DBUG_ASSERT(!ds_control->ds_active || ds_control->ds_action); + + /* Try to reuse existing action if there is one for this sync point. */ + if (ds_control->ds_active && + (action= debug_sync_find(ds_control->ds_action, ds_control->ds_active, + dsp_name, name_len))) + { + /* Reuse an already active sync point action. */ + DBUG_ASSERT((uint)(action - ds_control->ds_action) < ds_control->ds_active); + DBUG_PRINT("debug_sync", ("reuse action idx: %ld", + (long) (action - ds_control->ds_action))); + } + else + { + /* Create a new action. */ + int dsp_idx= ds_control->ds_active++; + set_if_bigger(ds_control->dsp_max_active, ds_control->ds_active); + if (ds_control->ds_active > ds_control->ds_allocated) + { + uint new_alloc= ds_control->ds_active + 3; + void *new_action= my_realloc(ds_control->ds_action, + new_alloc * sizeof(st_debug_sync_action), + MYF(MY_WME | MY_ALLOW_ZERO_PTR)); + if (!new_action) + { + /* Error is reported by my_malloc(). */ + goto err; /* purecov: tested */ + } + ds_control->ds_action= (st_debug_sync_action*) new_action; + ds_control->ds_allocated= new_alloc; + /* Clear memory as we do not run string constructors here. */ + bzero((uchar*) (ds_control->ds_action + dsp_idx), + (new_alloc - dsp_idx) * sizeof(st_debug_sync_action)); + } + DBUG_PRINT("debug_sync", ("added action idx: %u", dsp_idx)); + action= ds_control->ds_action + dsp_idx; + if (action->sync_point.copy(dsp_name, name_len, system_charset_info)) + { + /* Error is reported by my_malloc(). */ + goto err; /* purecov: tested */ + } + action->need_sort= TRUE; + } + DBUG_ASSERT(action >= ds_control->ds_action); + DBUG_ASSERT(action < ds_control->ds_action + ds_control->ds_active); + DBUG_PRINT("debug_sync", ("action: 0x%lx array: 0x%lx count: %u", + (long) action, (long) ds_control->ds_action, + ds_control->ds_active)); + + DBUG_RETURN(action); + + /* purecov: begin tested */ + err: + DBUG_RETURN(NULL); + /* purecov: end */ +} + + +/** + Set a debug sync action. + + @param[in] thd thread handle + @param[in] action synchronization action + + @return status + @retval FALSE ok + @retval TRUE error + + @description + This is called from the debug sync parser. It arms the action for + the requested sync point. If the action parsed into an empty action, + it is removed instead. + + Setting an action for a sync point means to make the sync point + active. When it is hit it will execute this action. + + Before parsing, we "get" an action object. This is placed at the + end of the thread's action array unless the requested sync point + has an action already. + + Then the parser fills the action object from the request string. + + Finally the action is "set" for the sync point. If it was parsed + to be empty, it is removed from the array. If it did belong to a + sync point before, the sync point becomes inactive. If the action + became non-empty and it did not belong to a sync point before (it + was added at the end of the action array), the action array needs + to be sorted by sync point. + + If the sync point name is "now", it is executed immediately. +*/ + +static bool debug_sync_set_action(THD *thd, st_debug_sync_action *action) +{ + st_debug_sync_control *ds_control= thd->debug_sync_control; + bool is_dsp_now= FALSE; + DBUG_ENTER("debug_sync_set_action"); + DBUG_ASSERT(thd); + DBUG_ASSERT(action); + DBUG_ASSERT(ds_control); + + action->activation_count= max(action->hit_limit, action->execute); + if (!action->activation_count) + { + debug_sync_remove_action(ds_control, action); + DBUG_PRINT("debug_sync", ("action cleared")); + } + else + { + const char *dsp_name= action->sync_point.c_ptr(); + DBUG_EXECUTE("debug_sync", { + /* Functions as DBUG_PRINT args can change keyword and line nr. */ + const char *sig_emit= action->signal.c_ptr(); + const char *sig_wait= action->wait_for.c_ptr(); + DBUG_PRINT("debug_sync", + ("sync_point: '%s' activation_count: %lu hit_limit: %lu " + "execute: %lu timeout: %lu signal: '%s' wait_for: '%s'", + dsp_name, action->activation_count, + action->hit_limit, action->execute, action->timeout, + sig_emit, sig_wait));}); + + /* Check this before sorting the array. action may move. */ + is_dsp_now= !my_strcasecmp(system_charset_info, dsp_name, "now"); + + if (action->need_sort) + { + action->need_sort= FALSE; + /* Sort actions by (name_len, name). */ + my_qsort(ds_control->ds_action, ds_control->ds_active, + sizeof(st_debug_sync_action), debug_sync_qsort_cmp); + } + } + DBUG_EXECUTE("debug_sync_list", debug_sync_print_actions(thd);); + + /* Execute the special sync point 'now' if activated above. */ + if (is_dsp_now) + { + DEBUG_SYNC(thd, "now"); + /* + If HIT_LIMIT for sync point "now" was 1, the execution of the sync + point decremented it to 0. In this case the following happened: + + - an error message was reported with my_error() and + - the statement was killed with thd->killed= THD::KILL_QUERY. + + If a statement reports an error, it must not call send_ok(). + The calling functions will not call send_ok(), if we return TRUE + from this function. + + thd->killed is also set if the wait is interrupted from a + KILL or KILL QUERY statement. In this case, no error is reported + and shall not be reported as a result of SET DEBUG_SYNC. + Hence, we check for the first condition above. + */ + if (thd->is_error()) + DBUG_RETURN(TRUE); + } + + DBUG_RETURN(FALSE); +} + + +/** + Extract a token from a string. + + @param[out] token_p returns start of token + @param[out] token_length_p returns length of token + @param[in,out] ptr current string pointer, adds '\0' terminators + + @return string pointer or NULL + @retval != NULL ptr behind token terminator or at string end + @retval NULL no token found in remainder of string + + @note + This function assumes that the string is in system_charset_info, + that this charset is single byte for ASCII NUL ('\0'), that no + character except of ASCII NUL ('\0') contains a byte with value 0, + and that ASCII NUL ('\0') is used as the string terminator. + + This function needs to return tokens that are terminated with ASCII + NUL ('\0'). The tokens are used in my_strcasecmp(). Unfortunately + there is no my_strncasecmp(). + + To return the last token without copying it, we require the input + string to be nul terminated. + + @description + This function skips space characters at string begin. + + It returns a pointer to the first non-space character in *token_p. + + If no non-space character is found before the string terminator + ASCII NUL ('\0'), the function returns NULL. *token_p and + *token_length_p remain unchanged in this case (they are not set). + + The function takes a space character or an ASCII NUL ('\0') as a + terminator of the token. The space character could be multi-byte. + + It returns the length of the token in bytes, excluding the + terminator, in *token_length_p. + + If the terminator of the token is ASCII NUL ('\0'), it returns a + pointer to the terminator (string end). + + If the terminator is a space character, it replaces the the first + byte of the terminator character by ASCII NUL ('\0'), skips the (now + corrupted) terminator character, and skips all following space + characters. It returns a pointer to the next non-space character or + to the string terminator ASCII NUL ('\0'). +*/ + +static char *debug_sync_token(char **token_p, uint *token_length_p, char *ptr) +{ + DBUG_ASSERT(token_p); + DBUG_ASSERT(token_length_p); + DBUG_ASSERT(ptr); + + /* Skip leading space */ + while (my_isspace(system_charset_info, *ptr)) + ptr+= my_mbcharlen(system_charset_info, (uchar) *ptr); + + if (!*ptr) + { + ptr= NULL; + goto end; + } + + /* Get token start. */ + *token_p= ptr; + + /* Find token end. */ + while (*ptr && !my_isspace(system_charset_info, *ptr)) + ptr+= my_mbcharlen(system_charset_info, (uchar) *ptr); + + /* Get token length. */ + *token_length_p= ptr - *token_p; + + /* If necessary, terminate token. */ + if (*ptr) + { + /* Get terminator character length. */ + uint mbspacelen= my_mbcharlen(system_charset_info, (uchar) *ptr); + + /* Terminate token. */ + *ptr= '\0'; + + /* Skip the terminator. */ + ptr+= mbspacelen; + + /* Skip trailing space */ + while (my_isspace(system_charset_info, *ptr)) + ptr+= my_mbcharlen(system_charset_info, (uchar) *ptr); + } + + end: + return ptr; +} + + +/** + Extract a number from a string. + + @param[out] number_p returns number + @param[in] actstrptr current pointer in action string + + @return string pointer or NULL + @retval != NULL ptr behind token terminator or at string end + @retval NULL no token found or token is not valid number + + @note + The same assumptions about charset apply as for debug_sync_token(). + + @description + This function fetches a token from the string and converts it + into a number. + + If there is no token left in the string, or the token is not a valid + decimal number, NULL is returned. The result in *number_p is + undefined in this case. +*/ + +static char *debug_sync_number(ulong *number_p, char *actstrptr) +{ + char *ptr; + char *ept; + char *token; + uint token_length; + DBUG_ASSERT(number_p); + DBUG_ASSERT(actstrptr); + + /* Get token from string. */ + if (!(ptr= debug_sync_token(&token, &token_length, actstrptr))) + goto end; + + *number_p= strtoul(token, &ept, 10); + if (*ept) + ptr= NULL; + + end: + return ptr; +} + + +/** + Evaluate a debug sync action string. + + @param[in] thd thread handle + @param[in,out] action_str action string to receive '\0' terminators + + @return status + @retval FALSE ok + @retval TRUE error + + @description + This is called when the DEBUG_SYNC system variable is set. + Parse action string, build a debug sync action, activate it. + + Before parsing, we "get" an action object. This is placed at the + end of the thread's action array unless the requested sync point + has an action already. + + Then the parser fills the action object from the request string. + + Finally the action is "set" for the sync point. This means that the + sync point becomes active or inactive, depending on the action + values. + + @note + The input string needs to be ASCII NUL ('\0') terminated. We split + nul-terminated tokens in it without copy. + + @see the function comment of debug_sync_token() for more constraints + for the string. +*/ + +static bool debug_sync_eval_action(THD *thd, char *action_str) +{ + st_debug_sync_action *action= NULL; + const char *errmsg; + char *ptr; + char *token; + uint token_length; + DBUG_ENTER("debug_sync_eval_action"); + DBUG_ASSERT(thd); + DBUG_ASSERT(action_str); + + /* + Get debug sync point name. Or a special command. + */ + if (!(ptr= debug_sync_token(&token, &token_length, action_str))) + { + errmsg= "Missing synchronization point name"; + goto err; + } + + /* + If there is a second token, the first one is the sync point name. + */ + if (*ptr) + { + /* Get an action object to collect the requested action parameters. */ + action= debug_sync_get_action(thd, token, token_length); + if (!action) + { + /* Error message is sent. */ + DBUG_RETURN(TRUE); /* purecov: tested */ + } + } + + /* + Get kind of action to be taken at sync point. + */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + { + /* No action present. Try special commands. Token unchanged. */ + + /* + Try RESET. + */ + if (!my_strcasecmp(system_charset_info, token, "RESET")) + { + /* It is RESET. Reset all actions and global signal. */ + debug_sync_reset(thd); + goto end; + } + + /* Token unchanged. It still contains sync point name. */ + errmsg= "Missing action after synchronization point name '%.*s'"; + goto err; + } + + /* + Check for pseudo actions first. Start with actions that work on + an existing action. + */ + DBUG_ASSERT(action); + + /* + Try TEST. + */ + if (!my_strcasecmp(system_charset_info, token, "TEST")) + { + /* It is TEST. Nothing must follow it. */ + if (*ptr) + { + errmsg= "Nothing must follow action TEST"; + goto err; + } + + /* Execute sync point. */ + debug_sync(thd, action->sync_point.ptr(), action->sync_point.length()); + /* Fix statistics. This was not a real hit of the sync point. */ + thd->debug_sync_control->dsp_hits--; + goto end; + } + + /* + Now check for actions that define a new action. + Initialize action. Do not use bzero(). Strings may have malloced. + */ + action->activation_count= 0; + action->hit_limit= 0; + action->execute= 0; + action->timeout= 0; + action->signal.length(0); + action->wait_for.length(0); + + /* + Try CLEAR. + */ + if (!my_strcasecmp(system_charset_info, token, "CLEAR")) + { + /* It is CLEAR. Nothing must follow it. */ + if (*ptr) + { + errmsg= "Nothing must follow action CLEAR"; + goto err; + } + + /* Set (clear/remove) action. */ + goto set_action; + } + + /* + Now check for real sync point actions. + */ + + /* + Try SIGNAL. + */ + if (!my_strcasecmp(system_charset_info, token, "SIGNAL")) + { + /* It is SIGNAL. Signal name must follow. */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + { + errmsg= "Missing signal name after action SIGNAL"; + goto err; + } + if (action->signal.copy(token, token_length, system_charset_info)) + { + /* Error is reported by my_malloc(). */ + /* purecov: begin tested */ + errmsg= NULL; + goto err; + /* purecov: end */ + } + + /* Set default for EXECUTE option. */ + action->execute= 1; + + /* Get next token. If none follows, set action. */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + goto set_action; + } + + /* + Try WAIT_FOR. + */ + if (!my_strcasecmp(system_charset_info, token, "WAIT_FOR")) + { + /* It is WAIT_FOR. Wait_for signal name must follow. */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + { + errmsg= "Missing signal name after action WAIT_FOR"; + goto err; + } + if (action->wait_for.copy(token, token_length, system_charset_info)) + { + /* Error is reported by my_malloc(). */ + /* purecov: begin tested */ + errmsg= NULL; + goto err; + /* purecov: end */ + } + + /* Set default for EXECUTE and TIMEOUT options. */ + action->execute= 1; + action->timeout= opt_debug_sync_timeout; + + /* Get next token. If none follows, set action. */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + goto set_action; + + /* + Try TIMEOUT. + */ + if (!my_strcasecmp(system_charset_info, token, "TIMEOUT")) + { + /* It is TIMEOUT. Number must follow. */ + if (!(ptr= debug_sync_number(&action->timeout, ptr))) + { + errmsg= "Missing valid number after TIMEOUT"; + goto err; + } + + /* Get next token. If none follows, set action. */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + goto set_action; + } + } + + /* + Try EXECUTE. + */ + if (!my_strcasecmp(system_charset_info, token, "EXECUTE")) + { + /* + EXECUTE requires either SIGNAL and/or WAIT_FOR to be present. + In this case action->execute has been preset to 1. + */ + if (!action->execute) + { + errmsg= "Missing action before EXECUTE"; + goto err; + } + + /* Number must follow. */ + if (!(ptr= debug_sync_number(&action->execute, ptr))) + { + errmsg= "Missing valid number after EXECUTE"; + goto err; + } + + /* Get next token. If none follows, set action. */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + goto set_action; + } + + /* + Try HIT_LIMIT. + */ + if (!my_strcasecmp(system_charset_info, token, "HIT_LIMIT")) + { + /* Number must follow. */ + if (!(ptr= debug_sync_number(&action->hit_limit, ptr))) + { + errmsg= "Missing valid number after HIT_LIMIT"; + goto err; + } + + /* Get next token. If none follows, set action. */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + goto set_action; + } + + errmsg= "Illegal or out of order stuff: '%.*s'"; + + err: + if (errmsg) + { + /* + NOTE: errmsg must either have %.*s or none % at all. + It can be NULL if an error message is already reported + (e.g. by my_malloc()). + */ + set_if_smaller(token_length, 64); /* Limit error message length. */ + my_printf_error(ER_PARSE_ERROR, errmsg, MYF(0), token_length, token); + } + if (action) + debug_sync_remove_action(thd->debug_sync_control, action); + DBUG_RETURN(TRUE); + + set_action: + DBUG_RETURN(debug_sync_set_action(thd, action)); + + end: + DBUG_RETURN(FALSE); +} + + +/** + Check if the system variable 'debug_sync' can be set. + + @param[in] thd thread handle + @param[in] var set variable request + + @return status + @retval FALSE ok, variable can be set + @retval TRUE error, variable cannot be set +*/ + +bool sys_var_debug_sync::check(THD *thd, set_var *var) +{ + DBUG_ENTER("sys_var_debug_sync::check"); + DBUG_ASSERT(thd); + DBUG_ASSERT(var); + + /* + Variable can be set for the session only. + + This could be changed later. Then we need to have a global array of + actions in addition to the thread local ones. SET GLOBAL would + manage the global array, SET [SESSION] the local array. A sync point + would need to look for a local and a global action. Setting and + executing of global actions need to be protected by a mutex. + + The purpose of global actions could be to allow synchronizing with + connectionless threads that cannot execute SET statements. + */ + if (var->type == OPT_GLOBAL) + { + my_error(ER_LOCAL_VARIABLE, MYF(0), name); + DBUG_RETURN(TRUE); + } + + /* + Do not check for disabled facility. Test result should not + unnecessarily differ from enabled facility. + */ + + /* + Facility requires SUPER privilege. Sync points could be inside + global mutexes (e.g. LOCK_open). Waiting there forever would + stall the whole server. + */ + DBUG_RETURN(check_global_access(thd, SUPER_ACL)); +} + + +/** + Set the system variable 'debug_sync'. + + @param[in] thd thread handle + @param[in] var set variable request + + @return status + @retval FALSE ok, variable is set + @retval TRUE error, variable could not be set + + @note + "Setting" of the system variable 'debug_sync' does not mean to + assign a value to it as usual. Instead a debug sync action is parsed + from the input string and stored apart from the variable value. + + @note + For efficiency reasons, the action string parser places '\0' + terminators in the string. So we need to take a copy here. +*/ + +bool sys_var_debug_sync::update(THD *thd, set_var *var) +{ + char *val_str; + String *val_ptr; + String val_buf; + DBUG_ENTER("sys_var_debug_sync::update"); + DBUG_ASSERT(thd); + + /* + Depending on the value type (string literal, user variable, ...) + val_buf receives a copy of the value or not. But we always need + a copy. So we take a copy, if it is not done by val_str(). + If val_str() puts a copy into val_buf, then it returns &val_buf, + otherwise it returns a pointer to the string object that we need + to copy. + */ + val_ptr= var ? var->value->val_str(&val_buf) : &val_buf; + if (val_ptr != &val_buf) + { + val_buf.copy(*val_ptr); + } + val_str= val_buf.c_ptr(); + DBUG_PRINT("debug_sync", ("set action: '%s'", val_str)); + + /* + debug_sync_eval_action() places '\0' in the string, which itself + must be '\0' terminated. + */ + DBUG_RETURN(opt_debug_sync_timeout ? + debug_sync_eval_action(thd, val_str) : + FALSE); +} + + +/** + Retrieve the value of the system variable 'debug_sync'. + + @param[in] thd thread handle + @param[in] type variable type, unused + @param[in] base variable base, unused + + @return string + @retval != NULL ok, string pointer + @retval NULL memory allocation error + + @note + The value of the system variable 'debug_sync' reflects if + the facility is enabled ("ON") or disabled (default, "OFF"). + + When "ON", the current signal is added. +*/ + +uchar *sys_var_debug_sync::value_ptr(THD *thd, + enum_var_type type __attribute__((unused)), + LEX_STRING *base __attribute__((unused))) +{ + char *value; + DBUG_ENTER("sys_var_debug_sync::value_ptr"); + DBUG_ASSERT(thd); + + if (opt_debug_sync_timeout) + { + static char on[]= "ON - current signal: '"; + + // Ensure exclusive access to debug_sync_global.ds_signal + pthread_mutex_lock(&debug_sync_global.ds_mutex); + + size_t lgt= (sizeof(on) /* includes '\0' */ + + debug_sync_global.ds_signal.length() + 1 /* for '\'' */); + char *vend; + char *vptr; + + if ((value= (char*) alloc_root(thd->mem_root, lgt))) + { + vend= value + lgt - 1; /* reserve space for '\0'. */ + vptr= debug_sync_bmove_len(value, vend, STRING_WITH_LEN(on)); + vptr= debug_sync_bmove_len(vptr, vend, debug_sync_global.ds_signal.ptr(), + debug_sync_global.ds_signal.length()); + if (vptr < vend) + *(vptr++)= '\''; + *vptr= '\0'; /* We have one byte reserved for the worst case. */ + } + pthread_mutex_unlock(&debug_sync_global.ds_mutex); + } + else + { + /* purecov: begin tested */ + value= strmake_root(thd->mem_root, STRING_WITH_LEN("OFF")); + /* purecov: end */ + } + + DBUG_RETURN((uchar*) value); +} + + +/** + Execute requested action at a synchronization point. + + @param[in] thd thread handle + @param[in] action action to be executed + + @note + This is to be called only if activation count > 0. +*/ + +static void debug_sync_execute(THD *thd, st_debug_sync_action *action) +{ + IF_DBUG(const char *dsp_name= action->sync_point.c_ptr()); + IF_DBUG(const char *sig_emit= action->signal.c_ptr()); + IF_DBUG(const char *sig_wait= action->wait_for.c_ptr()); + DBUG_ENTER("debug_sync_execute"); + DBUG_ASSERT(thd); + DBUG_ASSERT(action); + DBUG_PRINT("debug_sync", + ("sync_point: '%s' activation_count: %lu hit_limit: %lu " + "execute: %lu timeout: %lu signal: '%s' wait_for: '%s'", + dsp_name, action->activation_count, action->hit_limit, + action->execute, action->timeout, sig_emit, sig_wait)); + + DBUG_ASSERT(action->activation_count); + action->activation_count--; + + if (action->execute) + { + const char *old_proc_info; + + action->execute--; + + /* + If we will be going to wait, set proc_info for the PROCESSLIST table. + Do this before emitting the signal, so other threads can see it + if they awake before we enter_cond() below. + */ + if (action->wait_for.length()) + { + st_debug_sync_control *ds_control= thd->debug_sync_control; + strxnmov(ds_control->ds_proc_info, sizeof(ds_control->ds_proc_info)-1, + "debug sync point: ", action->sync_point.c_ptr(), NullS); + old_proc_info= thd->proc_info; + thd_proc_info(thd, ds_control->ds_proc_info); + } + + /* + Take mutex to ensure that only one thread access + debug_sync_global.ds_signal at a time. Need to take mutex for + read access too, to create a memory barrier in order to avoid that + threads just reads an old cached version of the signal. + */ + pthread_mutex_lock(&debug_sync_global.ds_mutex); + + if (action->signal.length()) + { + /* Copy the signal to the global variable. */ + if (debug_sync_global.ds_signal.copy(action->signal)) + { + /* + Error is reported by my_malloc(). + We must disable the facility. We have no way to return an error. + */ + debug_sync_emergency_disable(); /* purecov: tested */ + } + /* Wake threads waiting in a sync point. */ + pthread_cond_broadcast(&debug_sync_global.ds_cond); + DBUG_PRINT("debug_sync_exec", ("signal '%s' at: '%s'", + sig_emit, dsp_name)); + } /* end if (action->signal.length()) */ + + if (action->wait_for.length()) + { + pthread_mutex_t *old_mutex; + pthread_cond_t *old_cond; + int error= 0; + struct timespec abstime; + + /* + We don't use enter_cond()/exit_cond(). They do not save old + mutex and cond. This would prohibit the use of DEBUG_SYNC + between other places of enter_cond() and exit_cond(). + */ + old_mutex= thd->mysys_var->current_mutex; + old_cond= thd->mysys_var->current_cond; + thd->mysys_var->current_mutex= &debug_sync_global.ds_mutex; + thd->mysys_var->current_cond= &debug_sync_global.ds_cond; + + set_timespec(abstime, action->timeout); + DBUG_EXECUTE("debug_sync_exec", { + /* Functions as DBUG_PRINT args can change keyword and line nr. */ + const char *sig_glob= debug_sync_global.ds_signal.c_ptr(); + DBUG_PRINT("debug_sync_exec", + ("wait for '%s' at: '%s' curr: '%s'", + sig_wait, dsp_name, sig_glob));}); + + /* + Wait until global signal string matches the wait_for string. + Interrupt when thread or query is killed or facility disabled. + The facility can become disabled when some thread cannot get + the required dynamic memory allocated. + */ + while (stringcmp(&debug_sync_global.ds_signal, &action->wait_for) && + !thd->killed && opt_debug_sync_timeout) + { + error= pthread_cond_timedwait(&debug_sync_global.ds_cond, + &debug_sync_global.ds_mutex, + &abstime); + DBUG_EXECUTE("debug_sync", { + /* Functions as DBUG_PRINT args can change keyword and line nr. */ + const char *sig_glob= debug_sync_global.ds_signal.c_ptr(); + DBUG_PRINT("debug_sync", + ("awoke from %s global: %s error: %d", + sig_wait, sig_glob, error));}); + if (error == ETIMEDOUT || error == ETIME) + { + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_DEBUG_SYNC_TIMEOUT, ER(ER_DEBUG_SYNC_TIMEOUT)); + break; + } + error= 0; + } + DBUG_EXECUTE("debug_sync_exec", + if (thd->killed) + DBUG_PRINT("debug_sync_exec", + ("killed %d from '%s' at: '%s'", + thd->killed, sig_wait, dsp_name)); + else + DBUG_PRINT("debug_sync_exec", + ("%s from '%s' at: '%s'", + error ? "timeout" : "resume", + sig_wait, dsp_name));); + + /* + We don't use enter_cond()/exit_cond(). They do not save old + mutex and cond. This would prohibit the use of DEBUG_SYNC + between other places of enter_cond() and exit_cond(). The + protected mutex must always unlocked _before_ mysys_var->mutex + is locked. (See comment in THD::exit_cond().) + */ + pthread_mutex_unlock(&debug_sync_global.ds_mutex); + pthread_mutex_lock(&thd->mysys_var->mutex); + thd->mysys_var->current_mutex= old_mutex; + thd->mysys_var->current_cond= old_cond; + thd_proc_info(thd, old_proc_info); + pthread_mutex_unlock(&thd->mysys_var->mutex); + + } + else + { + /* In case we don't wait, we just release the mutex. */ + pthread_mutex_unlock(&debug_sync_global.ds_mutex); + } /* end if (action->wait_for.length()) */ + + } /* end if (action->execute) */ + + /* hit_limit is zero for infinite. Don't decrement unconditionally. */ + if (action->hit_limit) + { + if (!--action->hit_limit) + { + thd->killed= THD::KILL_QUERY; + my_error(ER_DEBUG_SYNC_HIT_LIMIT, MYF(0)); + } + DBUG_PRINT("debug_sync_exec", ("hit_limit: %lu at: '%s'", + action->hit_limit, dsp_name)); + } + + DBUG_VOID_RETURN; +} + + +/** + Execute requested action at a synchronization point. + + @param[in] thd thread handle + @param[in] sync_point_name name of synchronization point + @param[in] name_len length of sync point name +*/ + +void debug_sync(THD *thd, const char *sync_point_name, size_t name_len) +{ + st_debug_sync_control *ds_control= thd->debug_sync_control; + st_debug_sync_action *action; + DBUG_ENTER("debug_sync"); + DBUG_ASSERT(thd); + DBUG_ASSERT(sync_point_name); + DBUG_ASSERT(name_len); + DBUG_ASSERT(ds_control); + DBUG_PRINT("debug_sync_point", ("hit: '%s'", sync_point_name)); + + /* Statistics. */ + ds_control->dsp_hits++; + + if (ds_control->ds_active && + (action= debug_sync_find(ds_control->ds_action, ds_control->ds_active, + sync_point_name, name_len)) && + action->activation_count) + { + /* Sync point is active (action exists). */ + debug_sync_execute(thd, action); + + /* Statistics. */ + ds_control->dsp_executed++; + + /* If action became inactive, remove it to shrink the search array. */ + if (!action->activation_count) + debug_sync_remove_action(ds_control, action); + } + + DBUG_VOID_RETURN; +} + +#endif /* defined(ENABLED_DEBUG_SYNC) */ diff --git a/sql/debug_sync.h b/sql/debug_sync.h new file mode 100644 index 00000000000..f4cd0b364cf --- /dev/null +++ b/sql/debug_sync.h @@ -0,0 +1,60 @@ +#ifndef DEBUG_SYNC_INCLUDED +#define DEBUG_SYNC_INCLUDED + +/* Copyright (C) 2008 Sun Microsystems, Inc. + + 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 Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/** + @file + + Declarations for the Debug Sync Facility. See debug_sync.cc for details. +*/ + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class implementation */ +#endif + +#include + +class THD; + +#if defined(ENABLED_DEBUG_SYNC) + +/* Macro to be put in the code at synchronization points. */ +#define DEBUG_SYNC(_thd_, _sync_point_name_) \ + do { if (unlikely(opt_debug_sync_timeout)) \ + debug_sync(_thd_, STRING_WITH_LEN(_sync_point_name_)); \ + } while (0) + +/* Command line option --debug-sync-timeout. See mysqld.cc. */ +extern uint opt_debug_sync_timeout; + +/* Default WAIT_FOR timeout if command line option is given without argument. */ +#define DEBUG_SYNC_DEFAULT_WAIT_TIMEOUT 300 + +/* Debug Sync prototypes. See debug_sync.cc. */ +extern int debug_sync_init(void); +extern void debug_sync_end(void); +extern void debug_sync_init_thread(THD *thd); +extern void debug_sync_end_thread(THD *thd); +extern void debug_sync(THD *thd, const char *sync_point_name, size_t name_len); + +#else /* defined(ENABLED_DEBUG_SYNC) */ + +#define DEBUG_SYNC(_thd_, _sync_point_name_) /* disabled DEBUG_SYNC */ + +#endif /* defined(ENABLED_DEBUG_SYNC) */ + +#endif /* DEBUG_SYNC_INCLUDED */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3433b54cb29..896be4a7f19 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -26,6 +26,7 @@ #include "mysqld_suffix.h" #include "mysys_err.h" #include "events.h" +#include "debug_sync.h" #include "../storage/myisam/ha_myisam.h" @@ -486,6 +487,9 @@ my_bool lower_case_file_system= 0; my_bool opt_large_pages= 0; my_bool opt_myisam_use_mmap= 0; uint opt_large_page_size= 0; +#if defined(ENABLED_DEBUG_SYNC) +uint opt_debug_sync_timeout= 0; +#endif /* defined(ENABLED_DEBUG_SYNC) */ my_bool opt_old_style_user_limits= 0, trust_function_creators= 0; /* True if there is at least one per-hour limit for some user, so we should @@ -1333,6 +1337,10 @@ void clean_up(bool print_message) #ifdef USE_REGEX my_regex_end(); #endif +#if defined(ENABLED_DEBUG_SYNC) + /* End the debug sync facility. See debug_sync.cc. */ + debug_sync_end(); +#endif /* defined(ENABLED_DEBUG_SYNC) */ #if !defined(EMBEDDED_LIBRARY) if (!opt_bootstrap) @@ -3464,6 +3472,12 @@ static int init_common_variables(const char *conf_file_name, int argc, sys_var_slow_log_path.value= my_strdup(s, MYF(0)); sys_var_slow_log_path.value_length= strlen(s); +#if defined(ENABLED_DEBUG_SYNC) + /* Initialize the debug sync facility. See debug_sync.cc. */ + if (debug_sync_init()) + return 1; /* purecov: tested */ +#endif /* defined(ENABLED_DEBUG_SYNC) */ + #if (ENABLE_TEMP_POOL) if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1)) return 1; @@ -4858,7 +4872,7 @@ void create_thread_to_handle_connection(THD *thd) handle_one_connection, (void*) thd))) { - /* purify: begin inspected */ + /* purecov: begin inspected */ DBUG_PRINT("error", ("Can't create thread to handle request (error %d)", error)); @@ -5671,6 +5685,9 @@ enum options_mysqld OPT_SECURE_FILE_PRIV, OPT_MIN_EXAMINED_ROW_LIMIT, OPT_LOG_SLOW_SLAVE_STATEMENTS, +#if defined(ENABLED_DEBUG_SYNC) + OPT_DEBUG_SYNC_TIMEOUT, +#endif /* defined(ENABLED_DEBUG_SYNC) */ OPT_OLD_MODE, OPT_SLAVE_EXEC_MODE, OPT_GENERAL_LOG_FILE, @@ -6442,6 +6459,14 @@ log and this option does nothing anymore.", "Decision to use in heuristic recover process. Possible values are COMMIT or ROLLBACK.", (uchar**) &opt_tc_heuristic_recover, (uchar**) &opt_tc_heuristic_recover, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#if defined(ENABLED_DEBUG_SYNC) + {"debug-sync-timeout", OPT_DEBUG_SYNC_TIMEOUT, + "Enable the debug sync facility " + "and optionally specify a default wait timeout in seconds. " + "A zero value keeps the facility disabled.", + (uchar**) &opt_debug_sync_timeout, 0, + 0, GET_UINT, OPT_ARG, 0, 0, UINT_MAX, 0, 0, 0}, +#endif /* defined(ENABLED_DEBUG_SYNC) */ {"temp-pool", OPT_TEMP_POOL, #if (ENABLE_TEMP_POOL) "Using this option will cause most temporary files created to use a small set of names, rather than a unique name for each new file.", @@ -7626,6 +7651,9 @@ static int mysql_init_variables(void) bzero((uchar*) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list)); bzero((char *) &global_status_var, sizeof(global_status_var)); opt_large_pages= 0; +#if defined(ENABLED_DEBUG_SYNC) + opt_debug_sync_timeout= 0; +#endif /* defined(ENABLED_DEBUG_SYNC) */ key_map_full.set_all(); /* Character sets */ @@ -8360,6 +8388,22 @@ mysqld_get_one_option(int optid, lower_case_table_names= argument ? atoi(argument) : 1; lower_case_table_names_used= 1; break; +#if defined(ENABLED_DEBUG_SYNC) + case OPT_DEBUG_SYNC_TIMEOUT: + /* + Debug Sync Facility. See debug_sync.cc. + Default timeout for WAIT_FOR action. + Default value is zero (facility disabled). + If option is given without an argument, supply a non-zero value. + */ + if (!argument) + { + /* purecov: begin tested */ + opt_debug_sync_timeout= DEBUG_SYNC_DEFAULT_WAIT_TIMEOUT; + /* purecov: end */ + } + break; +#endif /* defined(ENABLED_DEBUG_SYNC) */ } return 0; } diff --git a/sql/set_var.cc b/sql/set_var.cc index cd01f6c8624..b80bdde9670 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -625,6 +625,12 @@ static sys_var_long_ptr sys_table_cache_size(&vars, "table_open_cache", &table_cache_size); static sys_var_long_ptr sys_table_lock_wait_timeout(&vars, "table_lock_wait_timeout", &table_lock_wait_timeout); + +#if defined(ENABLED_DEBUG_SYNC) +/* Debug Sync Facility. Implemented in debug_sync.cc. */ +static sys_var_debug_sync sys_debug_sync(&vars, "debug_sync"); +#endif /* defined(ENABLED_DEBUG_SYNC) */ + static sys_var_long_ptr sys_thread_cache_size(&vars, "thread_cache_size", &thread_cache_size); #if HAVE_POOL_OF_THREADS == 1 diff --git a/sql/set_var.h b/sql/set_var.h index a54591b0fd6..fa747107870 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -637,6 +637,21 @@ public: }; #endif /* DBUG_OFF */ +#if defined(ENABLED_DEBUG_SYNC) +/* Debug Sync Facility. Implemented in debug_sync.cc. */ +class sys_var_debug_sync :public sys_var_thd +{ +public: + sys_var_debug_sync(sys_var_chain *chain, const char *name_arg) + :sys_var_thd(name_arg) + { chain_sys_var(chain); } + bool check(THD *thd, set_var *var); + bool update(THD *thd, set_var *var); + SHOW_TYPE show_type() { return SHOW_CHAR; } + bool check_update_type(Item_result type) { return type != STRING_RESULT; } + uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); +}; +#endif /* defined(ENABLED_DEBUG_SYNC) */ /* some variables that require special handling */ diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index fdad2a44b68..a17ad94ba82 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6206,3 +6206,10 @@ ER_TOO_MANY_CONCURRENT_TRXS WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED eng "Non-ASCII separator arguments are not fully supported" + +ER_DEBUG_SYNC_TIMEOUT + eng "debug sync point wait timed out" + ger "Debug Sync Point Wartezeit 黚erschritten" +ER_DEBUG_SYNC_HIT_LIMIT + eng "debug sync point hit limit reached" + ger "Debug Sync Point Hit Limit erreicht" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f55d3fc5006..af3ae03424e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -17,6 +17,7 @@ /* Basic functions needed by many modules */ #include "mysql_priv.h" +#include "debug_sync.h" #include "sql_select.h" #include "sp_head.h" #include "sp.h" @@ -950,6 +951,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock, close_old_data_files(thd,thd->open_tables,1,1); mysql_ha_flush(thd); + DEBUG_SYNC(thd, "after_flush_unlock"); bool found=1; /* Wait until all threads has closed all the tables we had locked */ @@ -5289,6 +5291,8 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) } } + DEBUG_SYNC(thd, "before_lock_tables_takes_lock"); + if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start), lock_flag, need_reopen))) { diff --git a/sql/sql_class.cc b/sql/sql_class.cc index daef5a26742..f75dc2cb88a 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -42,6 +42,7 @@ #include "sp_rcontext.h" #include "sp_cache.h" +#include "debug_sync.h" /* The following is used to initialise Table_ident with a internal @@ -584,6 +585,9 @@ THD::THD() derived_tables_processing(FALSE), spcont(NULL), m_parser_state(NULL) +#if defined(ENABLED_DEBUG_SYNC) + , debug_sync_control(0) +#endif /* defined(ENABLED_DEBUG_SYNC) */ { ulong tmp; @@ -832,6 +836,11 @@ void THD::init(void) reset_current_stmt_binlog_row_based(); bzero((char *) &status_var, sizeof(status_var)); sql_log_bin_toplevel= options & OPTION_BIN_LOG; + +#if defined(ENABLED_DEBUG_SYNC) + /* Initialize the Debug Sync Facility. See debug_sync.cc. */ + debug_sync_init_thread(this); +#endif /* defined(ENABLED_DEBUG_SYNC) */ } @@ -911,6 +920,12 @@ void THD::cleanup(void) lock=locked_tables; locked_tables=0; close_thread_tables(this); } + +#if defined(ENABLED_DEBUG_SYNC) + /* End the Debug Sync Facility. See debug_sync.cc. */ + debug_sync_end_thread(this); +#endif /* defined(ENABLED_DEBUG_SYNC) */ + mysql_ha_cleanup(this); delete_dynamic(&user_var_events); hash_free(&user_vars); diff --git a/sql/sql_class.h b/sql/sql_class.h index c38eb17f191..27b59bde7be 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1896,6 +1896,11 @@ public: partition_info *work_part_info; #endif +#if defined(ENABLED_DEBUG_SYNC) + /* Debug Sync facility. See debug_sync.cc. */ + struct st_debug_sync_control *debug_sync_control; +#endif /* defined(ENABLED_DEBUG_SYNC) */ + THD(); ~THD(); diff --git a/storage/myisam/myisamchk.c b/storage/myisam/myisamchk.c index 270bcf7f6ce..611fb6325c8 100644 --- a/storage/myisam/myisamchk.c +++ b/storage/myisam/myisamchk.c @@ -837,7 +837,7 @@ static int myisamchk(MI_CHECK *param, char * filename) mi_check_print_error(param,"'%s' is marked as crashed after last repair",filename); break; case HA_ERR_OLD_FILE: - mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename); + mi_check_print_error(param,"'%s' is an old type of MyISAM-table", filename); break; case HA_ERR_END_OF_FILE: mi_check_print_error(param,"Couldn't read complete header from '%s'", filename); From 92485639d636a0455f8d8a4a58f3f63d31ba5eaa Mon Sep 17 00:00:00 2001 From: "timothy.smith@sun.com" <> Date: Tue, 29 Sep 2009 21:11:41 +0200 Subject: [PATCH 054/146] make_binary_distribution.sh: fix path for installing the MALLOC_LIB (to $DEST/lib) --- scripts/make_binary_distribution.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh index 27fe2acb447..bd0f4f99ca6 100644 --- a/scripts/make_binary_distribution.sh +++ b/scripts/make_binary_distribution.sh @@ -298,7 +298,7 @@ if [ x"$BASE_SYSTEM" != x"netware" ] ; then # If requested, add a malloc library .so into pkglibdir for use # by mysqld_safe if [ -n "$MALLOC_LIB" ]; then - cp "$MALLOC_LIB" '@pkglibdir@' + cp "$MALLOC_LIB" "$DEST/lib/" fi # FIXME let this script be in "bin/", where it is in the RPMs? From 869c011218b43552ab4e43335cecda5685e04229 Mon Sep 17 00:00:00 2001 From: Date: Wed, 30 Sep 2009 10:01:52 +0800 Subject: [PATCH 055/146] Bug #46998 mysqlbinlog can't output BEGIN even if the database is included in a transaction The 'BEGIN/COMMIT/ROLLBACK' log event could be filtered out if the database is not selected by --database option of mysqlbinlog command. This can result in problem if there are some statements in the transaction are not filtered out. To fix the problem, mysqlbinlog will output 'BEGIN/ROLLBACK/COMMIT' in regardless of the database filtering rules. --- client/mysqlbinlog.cc | 5 +- mysql-test/r/mysqlbinlog.result | 81 ++++++++++++++++++ mysql-test/std_data/binlog_transaction.000001 | Bin 0 -> 1670 bytes mysql-test/t/mysqlbinlog.test | 62 ++++++++++++++ 4 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 mysql-test/std_data/binlog_transaction.000001 diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index ab78bbea944..05d8b539543 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -557,7 +557,10 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, switch (ev_type) { case QUERY_EVENT: - if (check_database(((Query_log_event*)ev)->db)) + if (strncmp(((Query_log_event*)ev)->query, "BEGIN", 5) && + strncmp(((Query_log_event*)ev)->query, "COMMIT", 6) && + strncmp(((Query_log_event*)ev)->query, "ROLLBACK", 8) && + check_database(((Query_log_event*)ev)->db)) goto end; ev->print(result_file, print_event_info); break; diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index 4cb8eb29f19..75b4b41b342 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -382,4 +382,85 @@ IS NOT NULL SET @@global.server_id= 1; RESET MASTER; FLUSH LOGS; +RESET MASTER; +FLUSH LOGS; +# +# Test if the 'BEGIN', 'ROLLBACK' and 'COMMIT' are output if the database specified is exist +/*!40019 SET @@session.max_insert_delayed_threads=0*/; +/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; +DELIMITER /*!*/; +ROLLBACK/*!*/; +use test/*!*/; +SET TIMESTAMP=1253783037/*!*/; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1/*!*/; +SET @@session.sql_mode=0/*!*/; +/*!\C latin1 *//*!*/; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; +create table t1(a int) engine= innodb +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +BEGIN +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +insert into t1 (a) values (1) +/*!*/; +COMMIT/*!*/; +SET TIMESTAMP=1253783037/*!*/; +create table t3(a int) engine= innodb +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +BEGIN +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +insert into t3 (a) values (2) +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +ROLLBACK +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +create table t5(a int) engine= NDB +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +BEGIN +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +insert into t5 (a) values (3) +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +COMMIT +/*!*/; +DELIMITER ; +# End of log file +ROLLBACK /* added by mysqlbinlog */; +/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; +# +# Test if the 'BEGIN', 'ROLLBACK' and 'COMMIT' are output if the database specified is not exist +/*!40019 SET @@session.max_insert_delayed_threads=0*/; +/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; +DELIMITER /*!*/; +ROLLBACK/*!*/; +SET TIMESTAMP=1253783037/*!*/; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1/*!*/; +SET @@session.sql_mode=0/*!*/; +/*!\C latin1 *//*!*/; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; +BEGIN +/*!*/; +COMMIT/*!*/; +SET TIMESTAMP=1253783037/*!*/; +BEGIN +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +ROLLBACK +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +BEGIN +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +COMMIT +/*!*/; +DELIMITER ; +# End of log file +ROLLBACK /* added by mysqlbinlog */; +/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; End of 5.0 tests diff --git a/mysql-test/std_data/binlog_transaction.000001 b/mysql-test/std_data/binlog_transaction.000001 new file mode 100644 index 0000000000000000000000000000000000000000..c1d0745d57c30b094124b772d9379eda1e07c9b2 GIT binary patch literal 1670 zcmbuA%SyvQ6o!v&EP+y#DlY0K%LZ*}(+k}Q+KXCygX+o~BxWdqB-JJr`T{-70(13IMucZ9XJza7TWL>ee^k9^T@ zJCI1VankJion9m4lXM!y4a0WW$mJFc(F`fA%F?51j+rB+^RmyrLAD&hDO`gDuKWYv z`H^`Z2!i6Q~^Mn&oF1td)#aR(+VmPYhAA~2|N0F5iej%L( zaf5_VAR#C;;W*+#xHEEQyLwb>`7Wx+c_mE-F@Ro&(ri-Qdes-u zP+$k&UPu?HLV1w_zX(^T5YmdjPyLOw8N>&YRf%L(pci2~7TN*=FVBM?Bli;FAx~fH hbvn%po|3@d=swny*P?e9aAm2E%SIXe^<;B=D8Gmu7kmH! literal 0 HcmV?d00001 diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index dd45f499866..c5b46b81207 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -304,4 +304,66 @@ FLUSH LOGS; # We do not need the results, just make sure that mysqlbinlog does not crash --exec $MYSQL_BINLOG --hexdump --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 >/dev/null +# +# #46998 +# This test verifies if the 'BEGIN', 'COMMIT' and 'ROLLBACK' are output +# in regardless of database filtering +# + +RESET MASTER; +FLUSH LOGS; + +# The following three test cases were wrtten into binlog_transaction.000001 +# Test case1: Test if the 'BEGIN' and 'COMMIT' are output for the 'test' database +# in transaction1 base on innodb engine tables +# use test; +# create table t1(a int) engine= innodb; +# use mysql; +# create table t2(a int) engine= innodb; +# Transaction1 begin +# begin; +# use test; +# insert into t1 (a) values (1); +# use mysql; +# insert into t2 (a) values (1); +# commit; +# Transaction1 end + +# Test case2: Test if the 'BEGIN' and 'ROLLBACK' are output for the 'test' database +# in transaction2 base on innodb and myisam engine tables +# use test; +# create table t3(a int) engine= innodb; +# use mysql; +# create table t4(a int) engine= myisam; +# Transaction2 begin +# begin; +# use test; +# insert into t3 (a) values (2); +# use mysql; +# insert into t4 (a) values (2); +# rollback; +# Transaction2 end + +# Test case3: Test if the 'BEGIN' and 'COMMIT' are output for the 'test' database +# in transaction3 base on NDB engine tables +# use test; +# create table t5(a int) engine= NDB; +# use mysql; +# create table t6(a int) engine= NDB; +# Transaction3 begin +# begin; +# use test; +# insert into t5 (a) values (3); +# use mysql; +# insert into t6 (a) values (3); +# commit; +# Transaction3 end + +--echo # +--echo # Test if the 'BEGIN', 'ROLLBACK' and 'COMMIT' are output if the database specified is exist +--exec $MYSQL_BINLOG --database=test --short-form $MYSQLTEST_VARDIR/std_data_ln/binlog_transaction.000001 +--echo # +--echo # Test if the 'BEGIN', 'ROLLBACK' and 'COMMIT' are output if the database specified is not exist +--exec $MYSQL_BINLOG --database=not_exist --short-form $MYSQLTEST_VARDIR/std_data_ln/binlog_transaction.000001 + --echo End of 5.0 tests From c18746a47e1fe737802a055fc7fb4fa0362fb6eb Mon Sep 17 00:00:00 2001 From: "sunanda.menon@sun.com" <> Date: Wed, 30 Sep 2009 13:53:41 +0200 Subject: [PATCH 056/146] Set version number for mysql-5.0.84sp1 release --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index ec432e19ce3..de96f1c6020 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.84) +AM_INIT_AUTOMAKE(mysql, 5.0.84sp1) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10 From 9d827fef37ebb2649dca1060bf186d792d5e0664 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 30 Sep 2009 14:22:38 +0200 Subject: [PATCH 057/146] Backport into build-200909301147-5.0.84sp1 > ------------------------------------------------------------ > revno: 2791.2.3 > revision-id: joro@sun.com-20090827114042-h55n7qp9990bl6ge > parent: anurag.shekhar@sun.com-20090831073231-e55y1hsck6n08ux8 > committer: Georgi Kodinov > branch nick: B46749-5.0-bugteam > timestamp: Thu 2009-08-27 14:40:42 +0300 > message: > Bug #46749: Segfault in add_key_fields() with outer subquery level > field references > > This error requires a combination of factors : > 1. An "impossible where" in the outermost SELECT > 2. An aggregate in the outermost SELECT > 3. A correlated subquery with a WHERE clause that includes an outer > field reference as a top level WHERE sargable predicate > > When JOIN::optimize detects an "impossible WHERE" it will bail out > without doing the rest of the work and initializations. It will not > call make_join_statistics() as well. And make_join_statistics fills > in various structures for each table referenced. > When processing the result of the "impossible WHERE" the query must > send a single row of data if there are aggregate functions in it. > In this case the server marks all the aggregates as having received > no rows and calls the relevant Item::val_xxx() method on the SELECT > list. However if this SELECT list happens to contain a correlated > subquery this subquery is evaluated in a normal evaluation mode. > And if this correlated subquery has a reference to a field from the > outermost "impossible where" SELECT the add_key_fields will mistakenly > consider the outer field reference as a "local" field reference when > looking for sargable predicates. > But since the SELECT where the outer field reference refers to is not > completely initialized due to the "impossible WHERE" in this level > we'll get a NULL pointer reference. > Fixed by making a better condition for discovering if a field is "local" > to the SELECT level being processed. > It's not enough to look for OUTER_REF_TABLE_BIT in this case since > for outer references to constant tables the Item_field::used_tables() > will return 0 regardless of whether the field reference is from the > local SELECT or not. --- mysql-test/r/subselect.result | 28 ++++++++++++++++++++++++ mysql-test/t/subselect.test | 31 ++++++++++++++++++++++++++ sql/sql_select.cc | 41 +++++++++++++++++++++++++---------- 3 files changed, 88 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 671e5d8f532..213695fa004 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4452,4 +4452,32 @@ WHERE 1 IN (SELECT id FROM t1) WITH CHECK OPTION; DELETE FROM v3; DROP VIEW v1,v2,v3; DROP TABLE t1,t2; +# +# Bug #46749: Segfault in add_key_fields() with outer subquery level +# field references +# +CREATE TABLE t1 ( +a int, +b int, +UNIQUE (a), KEY (b) +); +INSERT INTO t1 VALUES (1,1), (2,1); +CREATE TABLE st1 like t1; +INSERT INTO st1 VALUES (1,1), (2,1); +CREATE TABLE st2 like t1; +INSERT INTO st2 VALUES (1,1), (2,1); +EXPLAIN +SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b) +FROM t1 +WHERE a = 230; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 DEPENDENT SUBQUERY st1 index NULL a 5 NULL 2 Using index +2 DEPENDENT SUBQUERY st2 index b b 5 NULL 2 Using where; Using index +SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b) +FROM t1 +WHERE a = 230; +MAX(b) (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b) +NULL 0 +DROP TABLE t1, st1, st2; End of 5.0 tests. diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 96e5738526b..2b19841d170 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -3428,4 +3428,35 @@ DELETE FROM v3; DROP VIEW v1,v2,v3; DROP TABLE t1,t2; +--echo # +--echo # Bug #46749: Segfault in add_key_fields() with outer subquery level +--echo # field references +--echo # + +CREATE TABLE t1 ( + a int, + b int, + UNIQUE (a), KEY (b) +); +INSERT INTO t1 VALUES (1,1), (2,1); + +CREATE TABLE st1 like t1; +INSERT INTO st1 VALUES (1,1), (2,1); + +CREATE TABLE st2 like t1; +INSERT INTO st2 VALUES (1,1), (2,1); + +# should have "impossible where" +EXPLAIN +SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b) +FROM t1 +WHERE a = 230; + +# should not crash +SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b) +FROM t1 +WHERE a = 230; + +DROP TABLE t1, st1, st2; + --echo End of 5.0 tests. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 672ebaf9259..20bff90612d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3197,6 +3197,28 @@ add_key_equal_fields(KEY_FIELD **key_fields, uint and_level, } } + +/** + Check if an expression is a non-outer field. + + Checks if an expression is a field and belongs to the current select. + + @param field Item expression to check + + @return boolean + @retval TRUE the expression is a local field + @retval FALSE it's something else +*/ + +inline static bool +is_local_field (Item *field) +{ + field= field->real_item(); + return field->type() == Item::FIELD_ITEM && + !((Item_field *)field)->depended_from; +} + + static void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, COND *cond, table_map usable_tables, @@ -3272,13 +3294,12 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, { Item **values; // BETWEEN, IN, NE - if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM && + if (is_local_field (cond_func->key_item()) && !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) { values= cond_func->arguments()+1; if (cond_func->functype() == Item_func::NE_FUNC && - cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM && - !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT)) + is_local_field (cond_func->arguments()[1])) values--; DBUG_ASSERT(cond_func->functype() != Item_func::IN_FUNC || cond_func->argument_count() != 2); @@ -3294,9 +3315,7 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, for (uint i= 1 ; i < cond_func->argument_count() ; i++) { Item_field *field_item; - if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM - && - !(cond_func->arguments()[i]->used_tables() & OUTER_REF_TABLE_BIT)) + if (is_local_field (cond_func->arguments()[i])) { field_item= (Item_field *) (cond_func->arguments()[i]->real_item()); add_key_equal_fields(key_fields, *and_level, cond_func, @@ -3312,8 +3331,7 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, bool equal_func=(cond_func->functype() == Item_func::EQ_FUNC || cond_func->functype() == Item_func::EQUAL_FUNC); - if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM && - !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT)) + if (is_local_field (cond_func->arguments()[0])) { add_key_equal_fields(key_fields, *and_level, cond_func, (Item_field*) (cond_func->arguments()[0])->real_item(), @@ -3321,9 +3339,8 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, cond_func->arguments()+1, 1, usable_tables, sargables); } - if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM && - cond_func->functype() != Item_func::LIKE_FUNC && - !(cond_func->arguments()[1]->used_tables() & OUTER_REF_TABLE_BIT)) + if (is_local_field (cond_func->arguments()[1]) && + cond_func->functype() != Item_func::LIKE_FUNC) { add_key_equal_fields(key_fields, *and_level, cond_func, (Item_field*) (cond_func->arguments()[1])->real_item(), @@ -3335,7 +3352,7 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, } case Item_func::OPTIMIZE_NULL: /* column_name IS [NOT] NULL */ - if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM && + if (is_local_field (cond_func->arguments()[0]) && !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) { Item *tmp=new Item_null; From 97f1600d2d29d404498fbb861cb8d71433a25e6a Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 30 Sep 2009 14:24:59 +0200 Subject: [PATCH 058/146] Backport into build-200909301147-5.0.84sp1 > ------------------------------------------------------------ > revno: 2796 > revision-id: sergey.glukhov@sun.com-20090827102219-sgjz0v5t1rfccs14 > parent: joro@sun.com-20090824122803-1d5jlaysjc7a7j6q > committer: Sergey Glukhov > branch nick: mysql-5.0-bugteam > timestamp: Thu 2009-08-27 15:22:19 +0500 > message: > Bug#46184 Crash, SELECT ... FROM derived table procedure analyze > The crash happens because select_union object is used as result set > for queries which have derived tables. > select_union use temporary table as data storage and if > fields count exceeds 10(count of values for procedure ANALYSE()) > then we get a crash on fill_record() function. --- mysql-test/r/analyse.result | 9 ++++++--- mysql-test/r/subselect.result | 2 +- mysql-test/t/analyse.test | 10 ++++++++++ mysql-test/t/subselect.test | 2 +- sql/sql_yacc.yy | 3 ++- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/analyse.result b/mysql-test/r/analyse.result index 49722d5b0ab..1e3a2985f74 100644 --- a/mysql-test/r/analyse.result +++ b/mysql-test/r/analyse.result @@ -28,9 +28,7 @@ test.t1.bool N Y 1 1 0 0 1.0000 NULL ENUM('N','Y') NOT NULL test.t1.d 2002-03-03 2002-03-05 10 10 0 0 10.0000 NULL ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL drop table t1,t2; EXPLAIN SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(); -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY system NULL NULL NULL NULL 1 -2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +ERROR HY000: Incorrect usage of PROCEDURE and subquery create table t1 (a int not null); create table t2 select * from t1 where 0=1 procedure analyse(); show create table t2; @@ -153,4 +151,9 @@ select f3 from t1 procedure analyse(1, 1); Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype test.t1.f3 5.99999 9.55555 7 7 0 0 7.77777 1.77778 FLOAT(6,5) NOT NULL drop table t1; +CREATE TABLE t1(a INT,b INT,c INT,d INT,e INT,f INT,g INT,h INT,i INT,j INT,k INT); +INSERT INTO t1 VALUES (); +SELECT * FROM (SELECT * FROM t1) d PROCEDURE ANALYSE(); +ERROR HY000: Incorrect usage of PROCEDURE and subquery +DROP TABLE t1; End of 4.1 tests diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 213695fa004..2c66ac9c1de 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -75,7 +75,7 @@ SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a)); select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1)); ERROR HY000: Incorrect usage of PROCEDURE and subquery SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1)); -ERROR HY000: Incorrect parameters to procedure 'ANALYSE' +ERROR HY000: Incorrect usage of PROCEDURE and subquery SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL; ERROR 42S22: Unknown column 'a' in 'field list' SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NOT NULL; diff --git a/mysql-test/t/analyse.test b/mysql-test/t/analyse.test index efcf5f6421c..d8466df14bf 100644 --- a/mysql-test/t/analyse.test +++ b/mysql-test/t/analyse.test @@ -14,6 +14,7 @@ create table t2 select * from t1 procedure analyse(); select * from t2; drop table t1,t2; +--error ER_WRONG_USAGE EXPLAIN SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(); # @@ -102,4 +103,13 @@ select f2 from t1 procedure analyse(1, 1); select f3 from t1 procedure analyse(1, 1); drop table t1; +# +# Bug#46184 Crash, SELECT ... FROM derived table procedure analyze +# +CREATE TABLE t1(a INT,b INT,c INT,d INT,e INT,f INT,g INT,h INT,i INT,j INT,k INT); +INSERT INTO t1 VALUES (); +--error ER_WRONG_USAGE +SELECT * FROM (SELECT * FROM t1) d PROCEDURE ANALYSE(); +DROP TABLE t1; + --echo End of 4.1 tests diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 2b19841d170..58db0b94f5e 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -30,7 +30,7 @@ SELECT 1 IN (SELECT 1); SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a)); -- error ER_WRONG_USAGE select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1)); --- error ER_WRONG_PARAMETERS_TO_PROCEDURE +-- error ER_WRONG_USAGE SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1)); -- error ER_BAD_FIELD_ERROR SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 49b7fafcc0b..8258268f390 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7328,7 +7328,8 @@ procedure_clause: MYSQL_YYABORT; } - if (&lex->select_lex != lex->current_select) + if (&lex->select_lex != lex->current_select || + lex->select_lex.get_table_list()->derived) { my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery"); MYSQL_YYABORT; From 9b28e81413a7bc307c478173472b80cf07242ceb Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 30 Sep 2009 14:26:15 +0200 Subject: [PATCH 059/146] Backport into build-200909301147-5.0.84sp1 > ------------------------------------------------------------ > revno: 2802.1.1 > tags: mysql-5.0.86 > revision-id: hery.ramilison@sun.com-20090909185217-mooeczu391ztp2fz > parent: joro@sun.com-20090902123318-8qe40pr91xmui5ue > committer: hery > branch nick: mysql-5.0.86-release > timestamp: Wed 2009-09-09 20:52:17 +0200 > message: > change c++ comment to c comment --- client/mysqltest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 24d021b7239..40c8b6bba46 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1404,7 +1404,7 @@ void show_diff(DYNAMIC_STRING* ds, else diff_name = 0; #else - diff_name = "diff"; // Otherwise always assume it's called diff + diff_name = "diff"; /* Otherwise always assume it's called diff */ #endif if (diff_name) From f7ebdaef80ff6a015b048af9b1df5c45fb683e8f Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Wed, 30 Sep 2009 14:50:25 +0200 Subject: [PATCH 060/146] Bug#34895 'show procedure status' or 'show function status' + 'flush tables' crashes The server crashes when 'show procedure status' and 'flush tables' are run concurrently. This is caused by the way mysql.proc table is added twice to the list of table to lock although the requirements on the current locking API assumes differently. No test case is submitted because of the nature of the crash which is currently difficult to reproduce in a deterministic way. This is a backport from 5.1 --- myisam/mi_dbug.c | 10 ++++++---- sql/sql_yacc.yy | 4 ---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/myisam/mi_dbug.c b/myisam/mi_dbug.c index 07c314c43e6..111cae13344 100644 --- a/myisam/mi_dbug.c +++ b/myisam/mi_dbug.c @@ -171,7 +171,7 @@ my_bool check_table_is_closed(const char *name, const char *where) char filename[FN_REFLEN]; LIST *pos; DBUG_ENTER("check_table_is_closed"); - + pthread_mutex_lock(&THR_LOCK_myisam); (void) fn_format(filename,name,"",MI_NAME_IEXT,4+16+32); for (pos=myisam_open_list ; pos ; pos=pos->next) { @@ -181,12 +181,14 @@ my_bool check_table_is_closed(const char *name, const char *where) { if (share->last_version) { - fprintf(stderr,"Warning: Table: %s is open on %s\n", name,where); - DBUG_PRINT("warning",("Table: %s is open on %s", name,where)); - DBUG_RETURN(1); + fprintf(stderr,"Warning: Table: %s is open on %s\n", name,where); + DBUG_PRINT("warning",("Table: %s is open on %s", name,where)); + pthread_mutex_unlock(&THR_LOCK_myisam); + DBUG_RETURN(1); } } } + pthread_mutex_unlock(&THR_LOCK_myisam); DBUG_RETURN(0); } #endif /* EXTRA_DEBUG */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0aa6308ab93..c0247fd8d56 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -8276,8 +8276,6 @@ show_param: LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; lex->orig_sql_command= SQLCOM_SHOW_STATUS_PROC; - if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ)) - MYSQL_YYABORT; if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES)) MYSQL_YYABORT; } @@ -8286,8 +8284,6 @@ show_param: LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; lex->orig_sql_command= SQLCOM_SHOW_STATUS_FUNC; - if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ)) - MYSQL_YYABORT; if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES)) MYSQL_YYABORT; } From e1f4344e68e8208ff6e625f2723687a9fcb515b4 Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Wed, 30 Sep 2009 14:46:47 +0100 Subject: [PATCH 061/146] bug#41546: mysql-stress-run.pl is not packaged on Windows Copy mysql-stress-run.pl into noinstall package. --- scripts/make_win_bin_dist | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/make_win_bin_dist b/scripts/make_win_bin_dist index fdb34f2f48d..c65439181ef 100755 --- a/scripts/make_win_bin_dist +++ b/scripts/make_win_bin_dist @@ -338,6 +338,7 @@ fi mkdir $DESTDIR/mysql-test cp mysql-test/mysql-test-run.pl $DESTDIR/mysql-test/ +cp mysql-test/mysql-stress-test.pl $DESTDIR/mysql-test/ cp mysql-test/README $DESTDIR/mysql-test/ cp -R mysql-test/{t,r,include,suite,std_data,lib} $DESTDIR/mysql-test/ From 706241d679877d8d69c0719a1a84cdddf922298e Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Wed, 30 Sep 2009 15:46:51 +0100 Subject: [PATCH 062/146] bug#27693: Windows compilation from bk fails using WITH_BERKELEY_STORAGE_ENGINE Make configure.js bail with an error if trying to build bdb from a bzr tree. --- win/configure.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/win/configure.js b/win/configure.js index 8370497ea4b..54345522ab8 100755 --- a/win/configure.js +++ b/win/configure.js @@ -41,7 +41,6 @@ try { case "WITH_COMMUNITY_FEATURES": case "WITH_ARCHIVE_STORAGE_ENGINE": - case "WITH_BERKELEY_STORAGE_ENGINE": case "WITH_BLACKHOLE_STORAGE_ENGINE": case "WITH_EXAMPLE_STORAGE_ENGINE": case "WITH_FEDERATED_STORAGE_ENGINE": @@ -51,6 +50,21 @@ try case "EMBED_MANIFESTS": configfile.WriteLine("SET (" + args.Item(i) + " TRUE)"); break; + // BDB includes auto-generated files which are not handled by + // cmake, so only allow this option if building from a source + // distribution + case "WITH_BERKELEY_STORAGE_ENGINE": + if (!fso.FileExists("bdb\\btree\\btree_auto.c")) + { + BDBSourceError = new Error("BDB cannot be built directly" + + " from a bzr tree, see comment in bdb\\CMakeLists.txt"); + throw BDBSourceError; + } + else + { + configfile.WriteLine("SET (" + args.Item(i) + " TRUE)"); + break; + } case "MYSQL_SERVER_SUFFIX": case "MYSQLD_EXE_SUFFIX": configfile.WriteLine("SET (" + parts[0] + " \"" From d941a1f3042c4b6278cc41b32b7367a8b4c76c90 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Wed, 30 Sep 2009 18:38:02 -0300 Subject: [PATCH 063/146] Bug#47525: MySQL crashed (Federated) On Mac OS X or Windows, sending a SIGHUP to the server or a asynchronous flush (triggered by flush_time), would cause the server to crash. The problem was that a hook used to detach client API handles wasn't prepared to handle cases where the thread does not have a associated session. The solution is to verify whether the thread has a associated session before trying to detach a handle. --- mysql-test/r/federated_debug.result | 37 +++++++++++++++++++++++ mysql-test/t/federated_debug-master.opt | 1 + mysql-test/t/federated_debug.test | 39 +++++++++++++++++++++++++ sql/slave.cc | 2 +- sql/sql_parse.cc | 20 +++++++++++++ 5 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 mysql-test/r/federated_debug.result create mode 100644 mysql-test/t/federated_debug-master.opt create mode 100644 mysql-test/t/federated_debug.test diff --git a/mysql-test/r/federated_debug.result b/mysql-test/r/federated_debug.result new file mode 100644 index 00000000000..a6659d065b2 --- /dev/null +++ b/mysql-test/r/federated_debug.result @@ -0,0 +1,37 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +stop slave; +DROP DATABASE IF EXISTS federated; +CREATE DATABASE federated; +DROP DATABASE IF EXISTS federated; +CREATE DATABASE federated; +# +# Bug#47525: MySQL crashed (Federated) +# +# Switch to slave +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (1); +# Switch to master +CREATE TABLE t1(a INT) ENGINE=FEDERATED +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1'; +SELECT * FROM t1; +a +1 +# Start a asynchronous reload +# Wait for tables to be closed +# Ensure that the server didn't crash +SELECT * FROM t1; +a +1 +# Drop tables on master and slave +DROP TABLE t1; +DROP TABLE t1; +# Federated cleanup +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; diff --git a/mysql-test/t/federated_debug-master.opt b/mysql-test/t/federated_debug-master.opt new file mode 100644 index 00000000000..ad9ba4795af --- /dev/null +++ b/mysql-test/t/federated_debug-master.opt @@ -0,0 +1 @@ +--loose-debug=d,simulate_detached_thread_refresh diff --git a/mysql-test/t/federated_debug.test b/mysql-test/t/federated_debug.test new file mode 100644 index 00000000000..9de440f4d79 --- /dev/null +++ b/mysql-test/t/federated_debug.test @@ -0,0 +1,39 @@ +--source include/have_debug.inc +--source include/federated.inc + +--echo # +--echo # Bug#47525: MySQL crashed (Federated) +--echo # + +connection slave; +--echo # Switch to slave +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (1); + +connection master; +--echo # Switch to master +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE t1(a INT) ENGINE=FEDERATED + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1'; + +SELECT * FROM t1; + +--echo # Start a asynchronous reload +--exec $MYSQLADMIN --no-defaults -S $MASTER_MYSOCK -P $MASTER_MYPORT -u root --password= refresh 2>&1 + +--echo # Wait for tables to be closed +let $show_statement= SHOW STATUS LIKE 'Open_tables'; +let $field= Value; +let $condition= = '0'; +--source include/wait_show_condition.inc + +--echo # Ensure that the server didn't crash +SELECT * FROM t1; +--echo # Drop tables on master and slave +DROP TABLE t1; +connection slave; +DROP TABLE t1; + +connection default; +--echo # Federated cleanup +source include/federated_cleanup.inc; diff --git a/sql/slave.cc b/sql/slave.cc index 17855ed04e5..dd29a3f45c9 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4756,7 +4756,7 @@ extern "C" void slave_io_thread_detach_vio() { #ifdef SIGNAL_WITH_VIO_CLOSE THD *thd= current_thd; - if (thd->slave_thread) + if (thd && thd->slave_thread) thd->clear_active_vio(); #endif } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 65b2a9d60b0..62cca71ee97 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2161,6 +2161,26 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (check_global_access(thd,RELOAD_ACL)) break; mysql_log.write(thd,command,NullS); +#ifndef DBUG_OFF + DBUG_EXECUTE_IF("simulate_detached_thread_refresh", + { + /* + Simulate a reload without a attached thread session. + Provides a environment similar to that of when the + server receives a SIGHUP signal and reloads caches + and flushes tables. + */ + bool res; + my_pthread_setspecific_ptr(THR_THD, NULL); + res= reload_acl_and_cache(NULL, options | REFRESH_FAST, + NULL, ¬_used); + my_pthread_setspecific_ptr(THR_THD, thd); + if (!res) + send_ok(thd); + break; + } + ); +#endif if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used)) send_ok(thd); break; From e1e038ab1efe4c783a3b920661a0ee4db27b03d7 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Wed, 30 Sep 2009 19:14:55 -0300 Subject: [PATCH 064/146] Post-merge fix: DBUG macros are wrapped inside a loop. --- sql/sql_parse.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 62cca71ee97..88e70a129c4 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2177,7 +2177,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, my_pthread_setspecific_ptr(THR_THD, thd); if (!res) send_ok(thd); - break; + goto end; } ); #endif @@ -2318,6 +2318,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd, my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); break; } + + /* Break the switch for DBUG wrapped code. */ +#ifndef DBUG_OFF +end: +#endif + if (thd->lock || thd->open_tables || thd->derived_tables || thd->prelocked_mode) { From 1442ef0f2576bb3e33f922e0570ba7f58134fec1 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Wed, 30 Sep 2009 19:59:30 -0300 Subject: [PATCH 065/146] Post-merge cleanup: Reorganize code for better comprehensibility. Removes the need of a hack (the jump to label). --- sql/sql_parse.cc | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 88e70a129c4..f34aa3c3bad 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2162,26 +2162,27 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; mysql_log.write(thd,command,NullS); #ifndef DBUG_OFF - DBUG_EXECUTE_IF("simulate_detached_thread_refresh", - { - /* - Simulate a reload without a attached thread session. - Provides a environment similar to that of when the - server receives a SIGHUP signal and reloads caches - and flushes tables. - */ - bool res; - my_pthread_setspecific_ptr(THR_THD, NULL); - res= reload_acl_and_cache(NULL, options | REFRESH_FAST, - NULL, ¬_used); - my_pthread_setspecific_ptr(THR_THD, thd); - if (!res) - send_ok(thd); - goto end; - } - ); + bool debug_simulate= FALSE; + DBUG_EXECUTE_IF("simulate_detached_thread_refresh", debug_simulate= TRUE;); + if (debug_simulate) + { + /* + Simulate a reload without a attached thread session. + Provides a environment similar to that of when the + server receives a SIGHUP signal and reloads caches + and flushes tables. + */ + bool res; + my_pthread_setspecific_ptr(THR_THD, NULL); + res= reload_acl_and_cache(NULL, options | REFRESH_FAST, + NULL, ¬_used); + my_pthread_setspecific_ptr(THR_THD, thd); + if (!res) + send_ok(thd); + break; + } #endif - if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used)) + if (!reload_acl_and_cache(thd, options, NULL, ¬_used)) send_ok(thd); break; } @@ -2319,11 +2320,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; } - /* Break the switch for DBUG wrapped code. */ -#ifndef DBUG_OFF -end: -#endif - if (thd->lock || thd->open_tables || thd->derived_tables || thd->prelocked_mode) { From 5903c1e94c1679ca092c351a1a9723cc2eaf0eee Mon Sep 17 00:00:00 2001 From: Date: Thu, 1 Oct 2009 07:19:36 +0800 Subject: [PATCH 066/146] Bug #45677 Slave stops with Duplicate entry for key PRIMARY when using trigger The problem is that there is only one autoinc value associated with the query when binlogging. If more than one autoinc values are used in the query, the autoinc values after the first one can be inserted wrongly on slave. So these autoinc values can become inconsistent on master and slave. The problem is resolved by marking all the statements that invoke a trigger or call a function that updated autoinc fields as unsafe, and will switch to row-format in Mixed mode. Actually, the statement is safe if just one autoinc value is used in sub-statement, but it's impossible to check how many autoinc values are used in sub-statement.) --- .../rpl_auto_increment_insert_view.test | 44 + .../rpl_auto_increment_invoke_trigger.test | 82 ++ .../rpl_autoinc_func_invokes_trigger.test | 57 + .../rpl_auto_increment_update_failure.result | 1041 +++++++++++++++++ .../t/rpl_auto_increment_update_failure.test | 214 ++++ sql/sql_base.cc | 48 +- 6 files changed, 1455 insertions(+), 31 deletions(-) create mode 100644 mysql-test/extra/rpl_tests/rpl_auto_increment_insert_view.test create mode 100644 mysql-test/extra/rpl_tests/rpl_auto_increment_invoke_trigger.test create mode 100644 mysql-test/extra/rpl_tests/rpl_autoinc_func_invokes_trigger.test create mode 100644 mysql-test/suite/rpl/r/rpl_auto_increment_update_failure.result create mode 100644 mysql-test/suite/rpl/t/rpl_auto_increment_update_failure.test diff --git a/mysql-test/extra/rpl_tests/rpl_auto_increment_insert_view.test b/mysql-test/extra/rpl_tests/rpl_auto_increment_insert_view.test new file mode 100644 index 00000000000..0bfa46de113 --- /dev/null +++ b/mysql-test/extra/rpl_tests/rpl_auto_increment_insert_view.test @@ -0,0 +1,44 @@ +# +# This test verifies if inserting data into view that invokes a +# trigger will make the autoinc values become inconsistent on +# master and slave. +# +connection master; +CREATE TABLE t1(i1 int not null auto_increment, c1 INT, primary key(i1)) engine=innodb; +CREATE TABLE t2(i1 int not null auto_increment, c2 INT, primary key(i1)) engine=innodb; +CREATE TABLE t3(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +eval create trigger tr16 $insert_action on t1 for each row insert into t3(a) values(new.c1); +eval create trigger tr17 $insert_action on t2 for each row insert into t3(a) values(new.c2); +begin; +INSERT INTO t1(c1) VALUES (11), (12); +INSERT INTO t2(c2) VALUES (13), (14); + +CREATE VIEW v16 AS SELECT c1, c2 FROM t1, t2; + +INSERT INTO v16(c1) VALUES (15),(16); +INSERT INTO v16(c2) VALUES (17),(18); + +connection master1; +INSERT INTO v16(c1) VALUES (19),(20); +INSERT INTO v16(c2) VALUES (21),(22); + +connection master; +INSERT INTO v16(c1) VALUES (23), (24); +INSERT INTO v16(c1) VALUES (25), (26); +commit; +sync_slave_with_master; +--echo #Test if the results are consistent on master and slave +--echo #for 'INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS' +let $diff_table_1=master:test.t3; +let $diff_table_2=slave:test.t3; +source include/diff_tables.inc; + +connection master; +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP VIEW v16; +sync_slave_with_master; + + + diff --git a/mysql-test/extra/rpl_tests/rpl_auto_increment_invoke_trigger.test b/mysql-test/extra/rpl_tests/rpl_auto_increment_invoke_trigger.test new file mode 100644 index 00000000000..614d79d9c2d --- /dev/null +++ b/mysql-test/extra/rpl_tests/rpl_auto_increment_invoke_trigger.test @@ -0,0 +1,82 @@ +# +# This test verifies if concurrent transactions that invoke a +# trigger that inserts more than one values into one or more +# tables with an auto_increment column will make the autoinc +# values become inconsistent on master and slave. +# + +connection master; +create table t1(a int, b int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +eval create trigger tr1 $trigger_action on t1 for each row insert into t2(a) values(6); + +create table t3(a int, b int) engine=innodb; +create table t4(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t5(a int) engine=innodb; +delimiter |; +eval create trigger tr2 $trigger_action on t3 for each row begin + insert into t4(a) values(f1_insert_triggered()); + insert into t4(a) values(f1_insert_triggered()); + insert into t5(a) values(8); +end | +delimiter ;| + +create table t6(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +delimiter //; +CREATE FUNCTION f1_insert_triggered() RETURNS INTEGER +BEGIN + INSERT INTO t6(a) values(2),(3); + RETURN 1; +END// +delimiter ;// + +begin; +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +insert into t1(a,b) values(1,1),(2,1); +insert into t3(a,b) values(1,1),(2,1); +update t1 set a = a + 5 where b = 1; +update t3 set a = a + 5 where b = 1; +delete from t1 where b = 1; +delete from t3 where b = 1; + +connection master1; +#The default autocommit is set to 1, so the statement is auto committed +insert into t2(a) values(3); +insert into t4(a) values(3); + +connection master; +commit; +insert into t1(a,b) values(4,2); +insert into t3(a,b) values(4,2); +update t1 set a = a + 5 where b = 2; +update t3 set a = a + 5 where b = 2; +delete from t1 where b = 2; +delete from t3 where b = 2; +--echo # To verify if insert/update in an autoinc column causes statement to be logged in row format +source include/show_binlog_events.inc; +commit; + +connection master; +sync_slave_with_master; +--echo #Test if the results are consistent on master and slave +--echo #for 'INVOKES A TRIGGER with $trigger_action action' +let $diff_table_1=master:test.t2; +let $diff_table_2=slave:test.t2; +source include/diff_tables.inc; +let $diff_table_1=master:test.t4; +let $diff_table_2=slave:test.t4; +source include/diff_tables.inc; +let $diff_table_1=master:test.t6; +let $diff_table_2=slave:test.t6; +source include/diff_tables.inc; + +connection master; +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t6; +DROP FUNCTION f1_insert_triggered; +sync_slave_with_master; + diff --git a/mysql-test/extra/rpl_tests/rpl_autoinc_func_invokes_trigger.test b/mysql-test/extra/rpl_tests/rpl_autoinc_func_invokes_trigger.test new file mode 100644 index 00000000000..fece19b397d --- /dev/null +++ b/mysql-test/extra/rpl_tests/rpl_autoinc_func_invokes_trigger.test @@ -0,0 +1,57 @@ +# +# This test verifies if concurrent transactions that call a +# function which invokes a 'after/before insert action' trigger +# that inserts more than one values into a table with autoinc +# column will make the autoinc values become inconsistent on +# master and slave. +# + +connection master; +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t3(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +delimiter |; +CREATE FUNCTION f1_two_inserts_trigger() RETURNS INTEGER +BEGIN + INSERT INTO t2(a) values(2),(3); + INSERT INTO t2(a) values(2),(3); + RETURN 1; +END | +eval create trigger tr11 $insert_action on t2 for each row begin + insert into t3(a) values(new.a); + insert into t3(a) values(new.a); +end | +delimiter ;| +begin; +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +insert into t1(a) values(f1_two_inserts_trigger()); + +connection master1; +#The default autocommit is set to 1, so the statement is auto committed +insert into t2(a) values(4),(5); + +connection master; +commit; +insert into t1(a) values(f1_two_inserts_trigger()); +--echo # To verify if insert/update in an autoinc column causes statement to be logged in row format +source include/show_binlog_events.inc; +commit; + +connection master; +sync_slave_with_master; +--echo #Test if the results are consistent on master and slave +--echo #for 'CALLS A FUNCTION which INVOKES A TRIGGER with $insert_action action' +let $diff_table_1=master:test.t2; +let $diff_table_2=slave:test.t2; +source include/diff_tables.inc; +let $diff_table_1=master:test.t3; +let $diff_table_2=slave:test.t3; +source include/diff_tables.inc; + +connection master; +drop table t1; +drop table t2; +drop table t3; +drop function f1_two_inserts_trigger; +sync_slave_with_master; + diff --git a/mysql-test/suite/rpl/r/rpl_auto_increment_update_failure.result b/mysql-test/suite/rpl/r/rpl_auto_increment_update_failure.result new file mode 100644 index 00000000000..b2cc92491c3 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_auto_increment_update_failure.result @@ -0,0 +1,1041 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +# Test case1: INVOKES A TRIGGER with after insert action +create table t1(a int, b int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr1 after insert on t1 for each row insert into t2(a) values(6); +create table t3(a int, b int) engine=innodb; +create table t4(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t5(a int) engine=innodb; +create trigger tr2 after insert on t3 for each row begin +insert into t4(a) values(f1_insert_triggered()); +insert into t4(a) values(f1_insert_triggered()); +insert into t5(a) values(8); +end | +create table t6(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_insert_triggered() RETURNS INTEGER +BEGIN +INSERT INTO t6(a) values(2),(3); +RETURN 1; +END// +begin; +insert into t1(a,b) values(1,1),(2,1); +insert into t3(a,b) values(1,1),(2,1); +update t1 set a = a + 5 where b = 1; +update t3 set a = a + 5 where b = 1; +delete from t1 where b = 1; +delete from t3 where b = 1; +insert into t2(a) values(3); +insert into t4(a) values(3); +commit; +insert into t1(a,b) values(4,2); +insert into t3(a,b) values(4,2); +update t1 set a = a + 5 where b = 2; +update t3 set a = a + 5 where b = 2; +delete from t1 where b = 2; +delete from t3 where b = 2; +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; insert into t4(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 1 +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 1 +master-bin.000001 # Query # # use `test`; delete from t1 where b = 1 +master-bin.000001 # Query # # use `test`; delete from t3 where b = 1 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t1 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t3 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'INVOKES A TRIGGER with after insert action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t4 and slave:test.t4 +Comparing tables master:test.t6 and slave:test.t6 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t6; +DROP FUNCTION f1_insert_triggered; +# Test case2: INVOKES A TRIGGER with before insert action +create table t1(a int, b int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr1 before insert on t1 for each row insert into t2(a) values(6); +create table t3(a int, b int) engine=innodb; +create table t4(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t5(a int) engine=innodb; +create trigger tr2 before insert on t3 for each row begin +insert into t4(a) values(f1_insert_triggered()); +insert into t4(a) values(f1_insert_triggered()); +insert into t5(a) values(8); +end | +create table t6(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_insert_triggered() RETURNS INTEGER +BEGIN +INSERT INTO t6(a) values(2),(3); +RETURN 1; +END// +begin; +insert into t1(a,b) values(1,1),(2,1); +insert into t3(a,b) values(1,1),(2,1); +update t1 set a = a + 5 where b = 1; +update t3 set a = a + 5 where b = 1; +delete from t1 where b = 1; +delete from t3 where b = 1; +insert into t2(a) values(3); +insert into t4(a) values(3); +commit; +insert into t1(a,b) values(4,2); +insert into t3(a,b) values(4,2); +update t1 set a = a + 5 where b = 2; +update t3 set a = a + 5 where b = 2; +delete from t1 where b = 2; +delete from t3 where b = 2; +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; insert into t4(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 1 +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 1 +master-bin.000001 # Query # # use `test`; delete from t1 where b = 1 +master-bin.000001 # Query # # use `test`; delete from t3 where b = 1 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t1 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t3 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'INVOKES A TRIGGER with before insert action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t4 and slave:test.t4 +Comparing tables master:test.t6 and slave:test.t6 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t6; +DROP FUNCTION f1_insert_triggered; +# Test case3: INVOKES A TRIGGER with after update action +create table t1(a int, b int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr1 after update on t1 for each row insert into t2(a) values(6); +create table t3(a int, b int) engine=innodb; +create table t4(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t5(a int) engine=innodb; +create trigger tr2 after update on t3 for each row begin +insert into t4(a) values(f1_insert_triggered()); +insert into t4(a) values(f1_insert_triggered()); +insert into t5(a) values(8); +end | +create table t6(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_insert_triggered() RETURNS INTEGER +BEGIN +INSERT INTO t6(a) values(2),(3); +RETURN 1; +END// +begin; +insert into t1(a,b) values(1,1),(2,1); +insert into t3(a,b) values(1,1),(2,1); +update t1 set a = a + 5 where b = 1; +update t3 set a = a + 5 where b = 1; +delete from t1 where b = 1; +delete from t3 where b = 1; +insert into t2(a) values(3); +insert into t4(a) values(3); +commit; +insert into t1(a,b) values(4,2); +insert into t3(a,b) values(4,2); +update t1 set a = a + 5 where b = 2; +update t3 set a = a + 5 where b = 2; +delete from t1 where b = 2; +delete from t3 where b = 2; +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; insert into t4(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(1,1),(2,1) +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(1,1),(2,1) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; delete from t1 where b = 1 +master-bin.000001 # Query # # use `test`; delete from t3 where b = 1 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t1 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t3 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'INVOKES A TRIGGER with after update action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t4 and slave:test.t4 +Comparing tables master:test.t6 and slave:test.t6 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t6; +DROP FUNCTION f1_insert_triggered; +# Test case4: INVOKES A TRIGGER with before update action +create table t1(a int, b int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr1 before update on t1 for each row insert into t2(a) values(6); +create table t3(a int, b int) engine=innodb; +create table t4(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t5(a int) engine=innodb; +create trigger tr2 before update on t3 for each row begin +insert into t4(a) values(f1_insert_triggered()); +insert into t4(a) values(f1_insert_triggered()); +insert into t5(a) values(8); +end | +create table t6(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_insert_triggered() RETURNS INTEGER +BEGIN +INSERT INTO t6(a) values(2),(3); +RETURN 1; +END// +begin; +insert into t1(a,b) values(1,1),(2,1); +insert into t3(a,b) values(1,1),(2,1); +update t1 set a = a + 5 where b = 1; +update t3 set a = a + 5 where b = 1; +delete from t1 where b = 1; +delete from t3 where b = 1; +insert into t2(a) values(3); +insert into t4(a) values(3); +commit; +insert into t1(a,b) values(4,2); +insert into t3(a,b) values(4,2); +update t1 set a = a + 5 where b = 2; +update t3 set a = a + 5 where b = 2; +delete from t1 where b = 2; +delete from t3 where b = 2; +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; insert into t4(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(1,1),(2,1) +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(1,1),(2,1) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; delete from t1 where b = 1 +master-bin.000001 # Query # # use `test`; delete from t3 where b = 1 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t1 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t3 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'INVOKES A TRIGGER with before update action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t4 and slave:test.t4 +Comparing tables master:test.t6 and slave:test.t6 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t6; +DROP FUNCTION f1_insert_triggered; +# Test case5: INVOKES A TRIGGER with after delete action +create table t1(a int, b int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr1 after delete on t1 for each row insert into t2(a) values(6); +create table t3(a int, b int) engine=innodb; +create table t4(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t5(a int) engine=innodb; +create trigger tr2 after delete on t3 for each row begin +insert into t4(a) values(f1_insert_triggered()); +insert into t4(a) values(f1_insert_triggered()); +insert into t5(a) values(8); +end | +create table t6(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_insert_triggered() RETURNS INTEGER +BEGIN +INSERT INTO t6(a) values(2),(3); +RETURN 1; +END// +begin; +insert into t1(a,b) values(1,1),(2,1); +insert into t3(a,b) values(1,1),(2,1); +update t1 set a = a + 5 where b = 1; +update t3 set a = a + 5 where b = 1; +delete from t1 where b = 1; +delete from t3 where b = 1; +insert into t2(a) values(3); +insert into t4(a) values(3); +commit; +insert into t1(a,b) values(4,2); +insert into t3(a,b) values(4,2); +update t1 set a = a + 5 where b = 2; +update t3 set a = a + 5 where b = 2; +delete from t1 where b = 2; +delete from t3 where b = 2; +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; insert into t4(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(1,1),(2,1) +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(1,1),(2,1) +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 1 +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 1 +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'INVOKES A TRIGGER with after delete action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t4 and slave:test.t4 +Comparing tables master:test.t6 and slave:test.t6 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t6; +DROP FUNCTION f1_insert_triggered; +# Test case6: INVOKES A TRIGGER with before delete action +create table t1(a int, b int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr1 before delete on t1 for each row insert into t2(a) values(6); +create table t3(a int, b int) engine=innodb; +create table t4(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t5(a int) engine=innodb; +create trigger tr2 before delete on t3 for each row begin +insert into t4(a) values(f1_insert_triggered()); +insert into t4(a) values(f1_insert_triggered()); +insert into t5(a) values(8); +end | +create table t6(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_insert_triggered() RETURNS INTEGER +BEGIN +INSERT INTO t6(a) values(2),(3); +RETURN 1; +END// +begin; +insert into t1(a,b) values(1,1),(2,1); +insert into t3(a,b) values(1,1),(2,1); +update t1 set a = a + 5 where b = 1; +update t3 set a = a + 5 where b = 1; +delete from t1 where b = 1; +delete from t3 where b = 1; +insert into t2(a) values(3); +insert into t4(a) values(3); +commit; +insert into t1(a,b) values(4,2); +insert into t3(a,b) values(4,2); +update t1 set a = a + 5 where b = 2; +update t3 set a = a + 5 where b = 2; +delete from t1 where b = 2; +delete from t3 where b = 2; +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; insert into t4(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(1,1),(2,1) +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(1,1),(2,1) +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 1 +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 1 +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'INVOKES A TRIGGER with before delete action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t4 and slave:test.t4 +Comparing tables master:test.t6 and slave:test.t6 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t6; +DROP FUNCTION f1_insert_triggered; +# Test case7: CALLS A FUNCTION which INVOKES A TRIGGER with after insert action +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t3(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_two_inserts_trigger() RETURNS INTEGER +BEGIN +INSERT INTO t2(a) values(2),(3); +INSERT INTO t2(a) values(2),(3); +RETURN 1; +END | +create trigger tr11 after insert on t2 for each row begin +insert into t3(a) values(new.a); +insert into t3(a) values(new.a); +end | +begin; +insert into t1(a) values(f1_two_inserts_trigger()); +insert into t2(a) values(4),(5); +commit; +insert into t1(a) values(f1_two_inserts_trigger()); +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'CALLS A FUNCTION which INVOKES A TRIGGER with after insert action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t3 and slave:test.t3 +drop table t1; +drop table t2; +drop table t3; +drop function f1_two_inserts_trigger; +# Test case8: CALLS A FUNCTION which INVOKES A TRIGGER with before insert action +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t3(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_two_inserts_trigger() RETURNS INTEGER +BEGIN +INSERT INTO t2(a) values(2),(3); +INSERT INTO t2(a) values(2),(3); +RETURN 1; +END | +create trigger tr11 before insert on t2 for each row begin +insert into t3(a) values(new.a); +insert into t3(a) values(new.a); +end | +begin; +insert into t1(a) values(f1_two_inserts_trigger()); +insert into t2(a) values(4),(5); +commit; +insert into t1(a) values(f1_two_inserts_trigger()); +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'CALLS A FUNCTION which INVOKES A TRIGGER with before insert action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t3 and slave:test.t3 +drop table t1; +drop table t2; +drop table t3; +drop function f1_two_inserts_trigger; +# Test case9: INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS with after insert action +CREATE TABLE t1(i1 int not null auto_increment, c1 INT, primary key(i1)) engine=innodb; +CREATE TABLE t2(i1 int not null auto_increment, c2 INT, primary key(i1)) engine=innodb; +CREATE TABLE t3(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr16 after insert on t1 for each row insert into t3(a) values(new.c1); +create trigger tr17 after insert on t2 for each row insert into t3(a) values(new.c2); +begin; +INSERT INTO t1(c1) VALUES (11), (12); +INSERT INTO t2(c2) VALUES (13), (14); +CREATE VIEW v16 AS SELECT c1, c2 FROM t1, t2; +INSERT INTO v16(c1) VALUES (15),(16); +INSERT INTO v16(c2) VALUES (17),(18); +INSERT INTO v16(c1) VALUES (19),(20); +INSERT INTO v16(c2) VALUES (21),(22); +INSERT INTO v16(c1) VALUES (23), (24); +INSERT INTO v16(c1) VALUES (25), (26); +commit; +#Test if the results are consistent on master and slave +#for 'INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS' +Comparing tables master:test.t3 and slave:test.t3 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP VIEW v16; +# Test case10: INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS with before insert action +CREATE TABLE t1(i1 int not null auto_increment, c1 INT, primary key(i1)) engine=innodb; +CREATE TABLE t2(i1 int not null auto_increment, c2 INT, primary key(i1)) engine=innodb; +CREATE TABLE t3(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr16 before insert on t1 for each row insert into t3(a) values(new.c1); +create trigger tr17 before insert on t2 for each row insert into t3(a) values(new.c2); +begin; +INSERT INTO t1(c1) VALUES (11), (12); +INSERT INTO t2(c2) VALUES (13), (14); +CREATE VIEW v16 AS SELECT c1, c2 FROM t1, t2; +INSERT INTO v16(c1) VALUES (15),(16); +INSERT INTO v16(c2) VALUES (17),(18); +INSERT INTO v16(c1) VALUES (19),(20); +INSERT INTO v16(c2) VALUES (21),(22); +INSERT INTO v16(c1) VALUES (23), (24); +INSERT INTO v16(c1) VALUES (25), (26); +commit; +#Test if the results are consistent on master and slave +#for 'INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS' +Comparing tables master:test.t3 and slave:test.t3 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP VIEW v16; +# Test case11: INVOKES A FUNCTION TO INSERT TWO OR MORE VALUES INTO A TABLE WITH AUTOINC COLUMN +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_two_inserts() RETURNS INTEGER +BEGIN +INSERT INTO t2(a) values(2); +INSERT INTO t2(a) values(2); +RETURN 1; +END// +begin; +insert into t1(a) values(f1_two_inserts()); +insert into t2(a) values(4),(5); +commit; +insert into t1(a) values(f1_two_inserts()); +commit; +#Test result for INVOKES A FUNCTION TO INSERT TWO OR MORE VALUES on master +select * from t2 ORDER BY i1; +i1 a +1 2 +2 2 +3 4 +4 5 +5 2 +6 2 +#Test result for INVOKES A FUNCTION TO INSERT TWO OR MORE VALUES on slave +select * from t2 ORDER BY i1; +i1 a +1 2 +2 2 +3 4 +4 5 +5 2 +6 2 +drop table t1; +drop table t2; +drop function f1_two_inserts; +# Test case12: INVOKES A FUNCTION TO UPDATE TWO OR MORE VALUES OF A TABLE WITH AUTOINC COLUMN +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, b int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_two_updates() RETURNS INTEGER +BEGIN +update t2 set a = a + 5 where b = 1; +update t2 set a = a + 5 where b = 2; +update t2 set a = a + 5 where b = 3; +update t2 set a = a + 5 where b = 4; +RETURN 1; +END// +insert into t2(a,b) values(1,1); +insert into t2(a,b) values(2,2); +insert into t2(a,b) values(3,3); +insert into t2(a,b) values(4,4); +insert into t1(a) values(f1_two_updates()); +begin; +insert into t1(a) values(f1_two_updates()); +commit; +#Test result for INVOKES A FUNCTION TO UPDATE TWO OR MORE VALUES on master +select * from t2 ORDER BY i1; +i1 a b +1 11 1 +2 12 2 +3 13 3 +4 14 4 +#Test result for INVOKES A FUNCTION TO UPDATE TWO OR MORE VALUES on slave +select * from t2 ORDER BY i1; +i1 a b +1 11 1 +2 12 2 +3 13 3 +4 14 4 +drop table t1; +drop table t2; +drop function f1_two_updates; +# Test case13: UPDATE MORE THAN ONE TABLES ON TOP-STATEMENT +create table t1(i1 int not null auto_increment, a int, b int, primary key(i1)) engine=innodb; +create table t2(i1 int not null auto_increment, a int, b int, primary key(i1)) engine=innodb; +begin; +insert into t1(a,b) values(1,1),(2,2); +insert into t2(a,b) values(1,1),(2,2); +update t1,t2 set t1.a=t1.a+5, t2.a=t2.a+5 where t1.b=t2.b; +insert into t1(a,b) values(3,3); +insert into t2(a,b) values(3,3); +commit; +# To verify if it works fine when these statements are not be marked as unsafe +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=1 +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(1,1),(2,2) +master-bin.000001 # Intvar # # INSERT_ID=1 +master-bin.000001 # Query # # use `test`; insert into t2(a,b) values(1,1),(2,2) +master-bin.000001 # Query # # use `test`; update t1,t2 set t1.a=t1.a+5, t2.a=t2.a+5 where t1.b=t2.b +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(3,3) +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2(a,b) values(3,3) +master-bin.000001 # Xid # # COMMIT /* XID */ +#Test if the results are consistent on master and slave +#for 'UPDATE MORE THAN ONE TABLES ON TOP-STATEMENT' +Comparing tables master:test.t1 and slave:test.t1 +Comparing tables master:test.t2 and slave:test.t2 +drop table t1; +drop table t2; +# Test case14: INSERT DATA INTO VIEW WHICH INVOLVED MORE THAN ONE TABLES +CREATE TABLE t1(i1 int not null auto_increment, c1 INT, primary key(i1)) engine=innodb; +CREATE TABLE t2(i1 int not null auto_increment, c2 INT, primary key(i1)) engine=innodb; +begin; +INSERT INTO t1(c1) VALUES (11), (12); +INSERT INTO t2(c2) VALUES (13), (14); +CREATE VIEW v15 AS SELECT c1, c2 FROM t1, t2; +INSERT INTO v15(c1) VALUES (15),(16); +INSERT INTO v15(c2) VALUES (17),(18); +INSERT INTO v15(c1) VALUES (19),(20); +INSERT INTO v15(c2) VALUES (21),(22); +INSERT INTO v15(c1) VALUES (23), (24); +INSERT INTO v15(c2) VALUES (25), (26); +commit; +# To verify if it works fine when these statements are not be marked as unsafe +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=1 +master-bin.000001 # Query # # use `test`; INSERT INTO t1(c1) VALUES (11), (12) +master-bin.000001 # Intvar # # INSERT_ID=1 +master-bin.000001 # Query # # use `test`; INSERT INTO t2(c2) VALUES (13), (14) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `test`; CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v15` AS SELECT c1, c2 FROM t1, t2 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; INSERT INTO v15(c1) VALUES (15),(16) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; INSERT INTO v15(c2) VALUES (17),(18) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; INSERT INTO v15(c1) VALUES (19),(20) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; INSERT INTO v15(c2) VALUES (21),(22) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Query # # use `test`; INSERT INTO v15(c1) VALUES (23), (24) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Query # # use `test`; INSERT INTO v15(c2) VALUES (25), (26) +master-bin.000001 # Xid # # COMMIT /* XID */ +#Test if the results are consistent on master and slave +#for 'INSERT DATA INTO VIEW WHICH INVOLVED MORE THAN ONE TABLES' +Comparing tables master:test.t1 and slave:test.t1 +Comparing tables master:test.t2 and slave:test.t2 +drop table t1; +drop table t2; +drop view v15; diff --git a/mysql-test/suite/rpl/t/rpl_auto_increment_update_failure.test b/mysql-test/suite/rpl/t/rpl_auto_increment_update_failure.test new file mode 100644 index 00000000000..f38d2151ab3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_auto_increment_update_failure.test @@ -0,0 +1,214 @@ +# +# Bug45677 +# This test verifies the following two properties: +# P1) insert/update in an autoinc column causes statement to +# be logged in row format if binlog_format=mixed. +# P2) if binlog_format=mixed, and a trigger or function contains +# two or more inserts/updates in a table that has an autoinc +# column, then the slave should not go out of sync, even if +# there are concurrent transactions. +# +# Property (P1) is tested by executing an insert and an update on +# a table that has an autoinc column, and verifying that these +# statements result in row events in the binlog. +# Property (P2) is tested by setting up the test scenario and +# verifying that the tables are identical on master and slave. +# + +source include/have_binlog_format_mixed.inc; +source include/have_innodb.inc; +source include/master-slave.inc; + +--echo # Test case1: INVOKES A TRIGGER with after insert action +let $trigger_action = after insert; +source extra/rpl_tests/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case2: INVOKES A TRIGGER with before insert action +let $trigger_action = before insert; +source extra/rpl_tests/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case3: INVOKES A TRIGGER with after update action +let $trigger_action = after update; +source extra/rpl_tests/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case4: INVOKES A TRIGGER with before update action +let $trigger_action = before update; +source extra/rpl_tests/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case5: INVOKES A TRIGGER with after delete action +let $trigger_action = after delete; +source extra/rpl_tests/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case6: INVOKES A TRIGGER with before delete action +let $trigger_action = before delete; +source extra/rpl_tests/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case7: CALLS A FUNCTION which INVOKES A TRIGGER with after insert action +let $insert_action = after insert; +source extra/rpl_tests/rpl_autoinc_func_invokes_trigger.test; + +--echo # Test case8: CALLS A FUNCTION which INVOKES A TRIGGER with before insert action +let $insert_action = before insert; +source extra/rpl_tests/rpl_autoinc_func_invokes_trigger.test; + +--echo # Test case9: INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS with after insert action +let $insert_action = after insert; +source extra/rpl_tests/rpl_auto_increment_insert_view.test; + +--echo # Test case10: INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS with before insert action +let $insert_action = before insert; +source extra/rpl_tests/rpl_auto_increment_insert_view.test; + +--echo # Test case11: INVOKES A FUNCTION TO INSERT TWO OR MORE VALUES INTO A TABLE WITH AUTOINC COLUMN +connection master; +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +delimiter //; +CREATE FUNCTION f1_two_inserts() RETURNS INTEGER +BEGIN + INSERT INTO t2(a) values(2); + INSERT INTO t2(a) values(2); + RETURN 1; +END// +delimiter ;// +begin; +insert into t1(a) values(f1_two_inserts()); + +connection master1; +#The default autocommit is set to 1, so the statement is auto committed +insert into t2(a) values(4),(5); + +connection master; +commit; +insert into t1(a) values(f1_two_inserts()); +commit; + +connection master; +--echo #Test result for INVOKES A FUNCTION TO INSERT TWO OR MORE VALUES on master +select * from t2 ORDER BY i1; + +sync_slave_with_master; +connection slave; +--echo #Test result for INVOKES A FUNCTION TO INSERT TWO OR MORE VALUES on slave +select * from t2 ORDER BY i1; + +connection master; +drop table t1; +drop table t2; +drop function f1_two_inserts; +sync_slave_with_master; + +--echo # Test case12: INVOKES A FUNCTION TO UPDATE TWO OR MORE VALUES OF A TABLE WITH AUTOINC COLUMN +connection master; +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, b int, primary key(i1)) engine=innodb; +delimiter //; +CREATE FUNCTION f1_two_updates() RETURNS INTEGER +BEGIN + update t2 set a = a + 5 where b = 1; + update t2 set a = a + 5 where b = 2; + update t2 set a = a + 5 where b = 3; + update t2 set a = a + 5 where b = 4; + RETURN 1; +END// +delimiter ;// + +connection master1; +#The default autocommit is set to 1, so the statement is auto committed +insert into t2(a,b) values(1,1); +insert into t2(a,b) values(2,2); +insert into t2(a,b) values(3,3); +insert into t2(a,b) values(4,4); +insert into t1(a) values(f1_two_updates()); + +connection master; +begin; +insert into t1(a) values(f1_two_updates()); +commit; + +connection master; +--echo #Test result for INVOKES A FUNCTION TO UPDATE TWO OR MORE VALUES on master +select * from t2 ORDER BY i1; + +sync_slave_with_master; +connection slave; +--echo #Test result for INVOKES A FUNCTION TO UPDATE TWO OR MORE VALUES on slave +select * from t2 ORDER BY i1; + +connection master; +drop table t1; +drop table t2; +drop function f1_two_updates; +sync_slave_with_master; + +--echo # Test case13: UPDATE MORE THAN ONE TABLES ON TOP-STATEMENT +connection master; +create table t1(i1 int not null auto_increment, a int, b int, primary key(i1)) engine=innodb; +create table t2(i1 int not null auto_increment, a int, b int, primary key(i1)) engine=innodb; +begin; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +insert into t1(a,b) values(1,1),(2,2); +insert into t2(a,b) values(1,1),(2,2); +update t1,t2 set t1.a=t1.a+5, t2.a=t2.a+5 where t1.b=t2.b; +insert into t1(a,b) values(3,3); +insert into t2(a,b) values(3,3); +commit; +--echo # To verify if it works fine when these statements are not be marked as unsafe +source include/show_binlog_events.inc; + +sync_slave_with_master; +--echo #Test if the results are consistent on master and slave +--echo #for 'UPDATE MORE THAN ONE TABLES ON TOP-STATEMENT' +let $diff_table_1=master:test.t1; +let $diff_table_2=slave:test.t1; +source include/diff_tables.inc; +let $diff_table_1=master:test.t2; +let $diff_table_2=slave:test.t2; +source include/diff_tables.inc; + +connection master; +drop table t1; +drop table t2; +sync_slave_with_master; + +--echo # Test case14: INSERT DATA INTO VIEW WHICH INVOLVED MORE THAN ONE TABLES +connection master; +CREATE TABLE t1(i1 int not null auto_increment, c1 INT, primary key(i1)) engine=innodb; +CREATE TABLE t2(i1 int not null auto_increment, c2 INT, primary key(i1)) engine=innodb; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +begin; +INSERT INTO t1(c1) VALUES (11), (12); +INSERT INTO t2(c2) VALUES (13), (14); + +CREATE VIEW v15 AS SELECT c1, c2 FROM t1, t2; + +INSERT INTO v15(c1) VALUES (15),(16); +INSERT INTO v15(c2) VALUES (17),(18); + +connection master1; +INSERT INTO v15(c1) VALUES (19),(20); +INSERT INTO v15(c2) VALUES (21),(22); + +connection master; +INSERT INTO v15(c1) VALUES (23), (24); +INSERT INTO v15(c2) VALUES (25), (26); +commit; +--echo # To verify if it works fine when these statements are not be marked as unsafe +source include/show_binlog_events.inc; + +sync_slave_with_master; +--echo #Test if the results are consistent on master and slave +--echo #for 'INSERT DATA INTO VIEW WHICH INVOLVED MORE THAN ONE TABLES' +let $diff_table_1=master:test.t1; +let $diff_table_2=slave:test.t1; +source include/diff_tables.inc; +let $diff_table_1=master:test.t2; +let $diff_table_2=slave:test.t2; +source include/diff_tables.inc; + +connection master; +drop table t1; +drop table t2; +drop view v15; +sync_slave_with_master; + diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f55d3fc5006..89fe6dc4b41 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -106,7 +106,7 @@ static bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias, static void close_old_data_files(THD *thd, TABLE *table, bool morph_locks, bool send_refresh); static bool -has_two_write_locked_tables_with_auto_increment(TABLE_LIST *tables); +has_write_table_with_auto_increment(TABLE_LIST *tables); extern "C" uchar *table_cache_key(const uchar *record, size_t *length, @@ -5277,15 +5277,17 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) thd->in_lock_tables=1; thd->options|= OPTION_TABLE_LOCK; /* - If we have >= 2 different tables to update with auto_inc columns, - statement-based binlogging won't work. We can solve this problem in - mixed mode by switching to row-based binlogging: + A query that modifies autoinc column in sub-statement can make the + master and slave inconsistent. + We can solve these problems in mixed mode by switching to binlogging + if at least one updated table is used by sub-statement */ - if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED && - has_two_write_locked_tables_with_auto_increment(tables)) + /* The BINLOG_FORMAT_MIXED judgement is saved for suppressing + warnings, but it will be removed by fixing bug#45827 */ + if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED && tables && + has_write_table_with_auto_increment(thd->lex->first_not_own_table())) { thd->lex->set_stmt_unsafe(); - thd->set_current_stmt_binlog_row_based_if_mixed(); } } @@ -8815,47 +8817,31 @@ void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table /* - Tells if two (or more) tables have auto_increment columns and we want to - lock those tables with a write lock. + Check if one (or more) write tables have auto_increment columns. - SYNOPSIS - has_two_write_locked_tables_with_auto_increment - tables Table list + @param[in] tables Table list + + @retval 0 if at least one write tables has an auto_increment column + @retval 1 otherwise NOTES: Call this function only when you have established the list of all tables which you'll want to update (including stored functions, triggers, views inside your statement). - - RETURN - 0 No - 1 Yes */ static bool -has_two_write_locked_tables_with_auto_increment(TABLE_LIST *tables) +has_write_table_with_auto_increment(TABLE_LIST *tables) { - char *first_table_name= NULL, *first_db; - LINT_INIT(first_db); - for (TABLE_LIST *table= tables; table; table= table->next_global) { /* we must do preliminary checks as table->table may be NULL */ if (!table->placeholder() && table->table->found_next_number_field && (table->lock_type >= TL_WRITE_ALLOW_WRITE)) - { - if (first_table_name == NULL) - { - first_table_name= table->table_name; - first_db= table->db; - DBUG_ASSERT(first_db); - } - else if (strcmp(first_db, table->db) || - strcmp(first_table_name, table->table_name)) - return 1; - } + return 1; } + return 0; } From e86e52e50f5dd4da60367a3491fb520a13309062 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Sun, 4 Oct 2009 12:53:02 +0300 Subject: [PATCH 067/146] Fixed a valgrind error in debug_sync --- sql/debug_sync.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc index 9e7141b775b..2580d526b52 100644 --- a/sql/debug_sync.cc +++ b/sql/debug_sync.cc @@ -1276,7 +1276,7 @@ static bool debug_sync_eval_action(THD *thd, char *action_str) const char *errmsg; char *ptr; char *token; - uint token_length; + uint token_length= 0; DBUG_ENTER("debug_sync_eval_action"); DBUG_ASSERT(thd); DBUG_ASSERT(action_str); From 2c14b845ae7d62c508601d8e1a30a214c643da2b Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Sun, 4 Oct 2009 13:15:53 +0300 Subject: [PATCH 068/146] Disable innodb_information_schema.test until bug #47808 is fixed. --- mysql-test/suite/innodb/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/innodb/t/disabled.def b/mysql-test/suite/innodb/t/disabled.def index baf8c89f539..176963df340 100644 --- a/mysql-test/suite/innodb/t/disabled.def +++ b/mysql-test/suite/innodb/t/disabled.def @@ -1 +1,2 @@ innodb-index: InnoDB: Error: table `test`.`t1#1` already exists in InnoDB internal +innodb_information_schema: Bug #47808 joro : innodb_information_schema.test fails when run under valgrind From b2511985ae7fb25e0d8e39c88b4b5e513f2b8ad9 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Sun, 4 Oct 2009 13:16:56 +0300 Subject: [PATCH 069/146] Make innodb-autoinc.test experimental until bug#47809 is fixed. --- mysql-test/collections/default.experimental | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index 416bf7d9e67..67c1eb439b0 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -6,3 +6,4 @@ rpl.rpl_row_create_table* # Bug#45576: rpl_row_create_table fails rpl_ndb.rpl_ndb_log # Bug#38998 rpl.rpl_innodb_bug28430* @solaris # Bug#46029 rpl.rpl_get_master_version_and_clock* # Bug#46931 2009-08-26 alik rpl.rpl_get_master_version_and_clock fails on hpux11.31 +innodb-autoinc # Bug#47809 2009-10-04 joro innodb-autoinc.test fails with valgrind errors with the innodb plugin From 5992e70623737048e3bb1d6f32496e03a703b847 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Sun, 4 Oct 2009 13:31:55 +0300 Subject: [PATCH 070/146] rpl.rpl_trigger made experimental because of bug #47810 : rpl.rpl_trigger.test fails with valgrind errors with the innodb plugin --- mysql-test/collections/default.experimental | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index 67c1eb439b0..ad4e463f253 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -7,3 +7,4 @@ rpl_ndb.rpl_ndb_log # Bug#38998 rpl.rpl_innodb_bug28430* @solaris # Bug#46029 rpl.rpl_get_master_version_and_clock* # Bug#46931 2009-08-26 alik rpl.rpl_get_master_version_and_clock fails on hpux11.31 innodb-autoinc # Bug#47809 2009-10-04 joro innodb-autoinc.test fails with valgrind errors with the innodb plugin +rpl.rpl_trigger # Bug#47810 2009-10-04 joro rpl.rpl_trigger.test fails with valgrind errors with the innodb plugin From 2b78dbff54d94cd02bdf31f4d52cd3e1823a4fe7 Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Mon, 5 Oct 2009 10:27:36 +0500 Subject: [PATCH 071/146] Bug #44139: Table scan when NULL appears in IN clause SELECT ... WHERE ... IN (NULL, ...) does full table scan, even if the same query without the NULL uses efficient range scan. The bugfix for the bug 18360 introduced an optimization: if 1) all right-hand arguments of the IN function are constants 2) result types of all right argument items are compatible enough to use the same single comparison function to compare all of them to the left argument, then we can convert the right-hand list of constant items to an array of equally-typed constant values for the further QUICK index access etc. (see Item_func_in::fix_length_and_dec()). The Item_null constant item objects have STRING_RESULT result types, so, as far as Item_func_in::fix_length_and_dec() is aware of NULLs in the right list, this improvement efficiently optimizes IN function calls with a mixed right list of NULLs and string constants. However, the optimization doesn't affect mixed lists of NULLs and integers, floats etc., because there is no unique common comparator. New optimization has been added to ignore the result type of NULL constants in the static analysis of mixed right-hand lists. This is safe, because at the execution phase we care about presence of NULLs anyway. 1. The collect_cmp_types() function has been modified to optionally ignore NULL constants in the item list. 2. NULL-skipping code of the Item_func_in::fix_length_and_dec() function has been modified to work not only with in_string vectors but with in_vectors of other types. --- mysql-test/r/func_in.result | 142 ++++++++++++++++++++++++++++++++++++ mysql-test/t/func_in.test | 85 +++++++++++++++++++++ sql/item_cmpfunc.cc | 17 ++++- 3 files changed, 241 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index 88a822a2fa6..ffdacc43735 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -608,4 +608,146 @@ SELECT SUM( DISTINCT e ) FROM t1 GROUP BY b,c,d HAVING (b,c,d) IN ((AVG( 1 ), 1 + c, 1 + d), (AVG( 1 ), 2 + c, 2 + d)); SUM( DISTINCT e ) DROP TABLE t1; +# +# Bug #44139: Table scan when NULL appears in IN clause +# +CREATE TABLE t1 ( +c_int INT NOT NULL, +c_decimal DECIMAL(5,2) NOT NULL, +c_float FLOAT(5, 2) NOT NULL, +c_bit BIT(10) NOT NULL, +c_date DATE NOT NULL, +c_datetime DATETIME NOT NULL, +c_timestamp TIMESTAMP NOT NULL, +c_time TIME NOT NULL, +c_year YEAR NOT NULL, +c_char CHAR(10) NOT NULL, +INDEX(c_int), INDEX(c_decimal), INDEX(c_float), INDEX(c_bit), INDEX(c_date), +INDEX(c_datetime), INDEX(c_timestamp), INDEX(c_time), INDEX(c_year), +INDEX(c_char)); +INSERT INTO t1 (c_int) VALUES (1), (2), (3), (4), (5); +INSERT INTO t1 (c_int) SELECT 0 FROM t1; +INSERT INTO t1 (c_int) SELECT 0 FROM t1; +EXPLAIN SELECT * FROM t1 WHERE c_int IN (1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_int c_int 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_int IN (NULL, 1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_int c_int 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_int IN (1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_int c_int 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_int IN (1, NULL, 2, NULL, 3, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_int c_int 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_int IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_int IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_decimal c_decimal 3 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (NULL, 1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_decimal c_decimal 3 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_float IN (1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_float c_float 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_float IN (NULL, 1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_float c_float 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_float IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_float IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_bit c_bit 2 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (NULL, 1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_bit c_bit 2 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_date +IN ('2009-09-01', '2009-09-02', '2009-09-03'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_date c_date 3 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_date +IN (NULL, '2009-09-01', '2009-09-02', '2009-09-03'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_date c_date 3 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_date IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_date IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_datetime +IN ('2009-09-01 00:00:01', '2009-09-02 00:00:01', '2009-09-03 00:00:01'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_datetime c_datetime 8 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_datetime +IN (NULL, '2009-09-01 00:00:01', '2009-09-02 00:00:01', '2009-09-03 00:00:01'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_datetime c_datetime 8 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_datetime IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_datetime IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_timestamp +IN ('2009-09-01 00:00:01', '2009-09-01 00:00:02', '2009-09-01 00:00:03'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_timestamp c_timestamp 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_timestamp +IN (NULL, '2009-09-01 00:00:01', '2009-09-01 00:00:02', '2009-09-01 00:00:03'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_timestamp c_timestamp 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_timestamp IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_timestamp IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_year IN (1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_year c_year 1 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_year IN (NULL, 1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_year c_year 1 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_year IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_year IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_char IN ('1', '2', '3'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_char c_char 10 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_char IN (NULL, '1', '2', '3'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_char c_char 10 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_char IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_char IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +DROP TABLE t1; +# End of 5.1 tests diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index adc074259ad..61ae812d874 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -456,4 +456,89 @@ SELECT SUM( DISTINCT e ) FROM t1 GROUP BY b,c,d HAVING (b,c,d) IN ((AVG( 1 ), 1 + c, 1 + d), (AVG( 1 ), 2 + c, 2 + d)); DROP TABLE t1; +--echo # +--echo # Bug #44139: Table scan when NULL appears in IN clause +--echo # + +--disable_warnings + +CREATE TABLE t1 ( + c_int INT NOT NULL, + c_decimal DECIMAL(5,2) NOT NULL, + c_float FLOAT(5, 2) NOT NULL, + c_bit BIT(10) NOT NULL, + c_date DATE NOT NULL, + c_datetime DATETIME NOT NULL, + c_timestamp TIMESTAMP NOT NULL, + c_time TIME NOT NULL, + c_year YEAR NOT NULL, + c_char CHAR(10) NOT NULL, + INDEX(c_int), INDEX(c_decimal), INDEX(c_float), INDEX(c_bit), INDEX(c_date), + INDEX(c_datetime), INDEX(c_timestamp), INDEX(c_time), INDEX(c_year), + INDEX(c_char)); + +INSERT INTO t1 (c_int) VALUES (1), (2), (3), (4), (5); +INSERT INTO t1 (c_int) SELECT 0 FROM t1; +INSERT INTO t1 (c_int) SELECT 0 FROM t1; + +--enable_warnings + +EXPLAIN SELECT * FROM t1 WHERE c_int IN (1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_int IN (NULL, 1, 2, 3); + +EXPLAIN SELECT * FROM t1 WHERE c_int IN (1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_int IN (1, NULL, 2, NULL, 3, NULL); +EXPLAIN SELECT * FROM t1 WHERE c_int IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_int IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (NULL, 1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_float IN (1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_float IN (NULL, 1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_float IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_float IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (NULL, 1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_date + IN ('2009-09-01', '2009-09-02', '2009-09-03'); +EXPLAIN SELECT * FROM t1 WHERE c_date + IN (NULL, '2009-09-01', '2009-09-02', '2009-09-03'); +EXPLAIN SELECT * FROM t1 WHERE c_date IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_date IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_datetime + IN ('2009-09-01 00:00:01', '2009-09-02 00:00:01', '2009-09-03 00:00:01'); +EXPLAIN SELECT * FROM t1 WHERE c_datetime + IN (NULL, '2009-09-01 00:00:01', '2009-09-02 00:00:01', '2009-09-03 00:00:01'); +EXPLAIN SELECT * FROM t1 WHERE c_datetime IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_datetime IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_timestamp + IN ('2009-09-01 00:00:01', '2009-09-01 00:00:02', '2009-09-01 00:00:03'); +EXPLAIN SELECT * FROM t1 WHERE c_timestamp + IN (NULL, '2009-09-01 00:00:01', '2009-09-01 00:00:02', '2009-09-01 00:00:03'); +EXPLAIN SELECT * FROM t1 WHERE c_timestamp IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_timestamp IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_year IN (1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_year IN (NULL, 1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_year IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_year IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_char IN ('1', '2', '3'); +EXPLAIN SELECT * FROM t1 WHERE c_char IN (NULL, '1', '2', '3'); +EXPLAIN SELECT * FROM t1 WHERE c_char IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_char IN (NULL, NULL); + +DROP TABLE t1; + +--echo # + --echo End of 5.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index d229453b795..c29031d25b5 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -189,6 +189,7 @@ enum_field_types agg_field_type(Item **items, uint nitems) collect_cmp_types() items Array of items to collect types from nitems Number of items in the array + skip_nulls Don't collect types of NULL items if TRUE DESCRIPTION This function collects different result types for comparison of the first @@ -199,7 +200,7 @@ enum_field_types agg_field_type(Item **items, uint nitems) Bitmap of collected types - otherwise */ -static uint collect_cmp_types(Item **items, uint nitems) +static uint collect_cmp_types(Item **items, uint nitems, bool skip_nulls= FALSE) { uint i; uint found_types; @@ -208,6 +209,8 @@ static uint collect_cmp_types(Item **items, uint nitems) found_types= 0; for (i= 1; i < nitems ; i++) { + if (skip_nulls && items[i]->type() == Item::NULL_ITEM) + continue; // Skip NULL constant items if ((left_result == ROW_RESULT || items[i]->result_type() == ROW_RESULT) && cmp_row_type(items[0], items[i])) @@ -215,6 +218,12 @@ static uint collect_cmp_types(Item **items, uint nitems) found_types|= 1<< (uint)item_cmp_type(left_result, items[i]->result_type()); } + /* + Even if all right-hand items are NULLs and we are skipping them all, we need + at least one type bit in the found_type bitmask. + */ + if (skip_nulls && !found_types) + found_types= 1 << (uint)left_result; return found_types; } @@ -3515,7 +3524,7 @@ void Item_func_in::fix_length_and_dec() uint type_cnt= 0, i; Item_result cmp_type= STRING_RESULT; left_result_type= args[0]->result_type(); - if (!(found_types= collect_cmp_types(args, arg_count))) + if (!(found_types= collect_cmp_types(args, arg_count, true))) return; for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++) @@ -3693,9 +3702,11 @@ void Item_func_in::fix_length_and_dec() uint j=0; for (uint i=1 ; i < arg_count ; i++) { - array->set(j,args[i]); if (!args[i]->null_value) // Skip NULL values + { + array->set(j,args[i]); j++; + } else have_null= 1; } From 67ac3fac7fe9b1fef7170d7a8581d4b395e095ef Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Mon, 5 Oct 2009 11:18:59 +0300 Subject: [PATCH 072/146] fixed typos in exeprimental list --- mysql-test/collections/default.experimental | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index ad4e463f253..50c5a71e252 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -6,5 +6,5 @@ rpl.rpl_row_create_table* # Bug#45576: rpl_row_create_table fails rpl_ndb.rpl_ndb_log # Bug#38998 rpl.rpl_innodb_bug28430* @solaris # Bug#46029 rpl.rpl_get_master_version_and_clock* # Bug#46931 2009-08-26 alik rpl.rpl_get_master_version_and_clock fails on hpux11.31 -innodb-autoinc # Bug#47809 2009-10-04 joro innodb-autoinc.test fails with valgrind errors with the innodb plugin -rpl.rpl_trigger # Bug#47810 2009-10-04 joro rpl.rpl_trigger.test fails with valgrind errors with the innodb plugin +main.innodb-autoinc* # Bug#47809 2009-10-04 joro innodb-autoinc.test fails with valgrind errors with the innodb plugin +rpl.rpl_trigger* # Bug#47810 2009-10-04 joro rpl.rpl_trigger.test fails with valgrind errors with the innodb plugin From cfae755d7de846581f820064b7cc83502f7c16d8 Mon Sep 17 00:00:00 2001 From: Satya B Date: Mon, 5 Oct 2009 16:39:07 +0530 Subject: [PATCH 073/146] Applying InnoDB snapshot 5.1-ss5921, Part 1. Fixes BUG#46000 1. BUG#46000 - using index called GEN_CLUST_INDEX crashes server Detailed revision comments: r5895 | jyang | 2009-09-15 03:39:21 +0300 (Tue, 15 Sep 2009) | 5 lines branches/5.1: Disallow creating index with the name of "GEN_CLUST_INDEX" which is reserved for the default system primary index. (Bug #46000) rb://149 approved by Marko Makela. --- mysql-test/lib/mtr_cases.pm | 2 + mysql-test/r/innodb_bug46000.result | 17 +++++ mysql-test/t/innodb_bug46000.test | 34 ++++++++++ storage/innobase/handler/ha_innodb.cc | 94 +++++++++++++++++++++++---- 4 files changed, 135 insertions(+), 12 deletions(-) create mode 100644 mysql-test/r/innodb_bug46000.result create mode 100644 mysql-test/t/innodb_bug46000.test diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 27165d56b50..5c2d2d5380e 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -507,6 +507,8 @@ sub collect_one_suite($) next if ($test->{'name'} eq 'sys_vars.innodb_lock_wait_timeout_basic'); # Diff around innodb_thread_concurrency variable next if ($test->{'name'} eq 'sys_vars.innodb_thread_concurrency_basic'); + # Disable for Innodb Plugin until the fix for Plugin is received + next if ($test->{'name'} eq 'main.innodb_bug46000'); # Copy test options my $new_test= My::Test->new(); while (my ($key, $value) = each(%$test)) diff --git a/mysql-test/r/innodb_bug46000.result b/mysql-test/r/innodb_bug46000.result new file mode 100644 index 00000000000..ccff888a48d --- /dev/null +++ b/mysql-test/r/innodb_bug46000.result @@ -0,0 +1,17 @@ +create table bug46000(`id` int,key `GEN_CLUST_INDEX`(`id`))engine=innodb; +ERROR HY000: Can't create table 'test.bug46000' (errno: -1) +create table bug46000(`id` int, key `GEN_clust_INDEX`(`id`))engine=innodb; +ERROR HY000: Can't create table 'test.bug46000' (errno: -1) +show errors; +Level Code Message +Error 1005 Cannot Create Index with name 'GEN_CLUST_INDEX'. The name is reserved for the system default primary index. +Error 1005 Can't create table 'test.bug46000' (errno: -1) +create table bug46000(id int) engine=innodb; +create index GEN_CLUST_INDEX on bug46000(id); +ERROR HY000: Can't create table '#sql-temporary' (errno: -1) +show errors; +Level Code Message +Error 1005 Cannot Create Index with name 'GEN_CLUST_INDEX'. The name is reserved for the system default primary index. +Error 1005 Can't create table '#sql-temporary' (errno: -1) +create index idx on bug46000(id); +drop table bug46000; diff --git a/mysql-test/t/innodb_bug46000.test b/mysql-test/t/innodb_bug46000.test new file mode 100644 index 00000000000..80c18c58ef0 --- /dev/null +++ b/mysql-test/t/innodb_bug46000.test @@ -0,0 +1,34 @@ +# This is the test for bug 46000. We shall +# block any index creation with the name of +# "GEN_CLUST_INDEX", which is the reserved +# name for innodb default primary index. + +--source include/have_innodb.inc + +# This 'create table' operation should fail because of +# using the reserve name as its index name. +--error ER_CANT_CREATE_TABLE +create table bug46000(`id` int,key `GEN_CLUST_INDEX`(`id`))engine=innodb; + +# Mixed upper/lower case of the reserved key words +--error ER_CANT_CREATE_TABLE +create table bug46000(`id` int, key `GEN_clust_INDEX`(`id`))engine=innodb; + +show errors; + +create table bug46000(id int) engine=innodb; + +# This 'create index' operation should fail. +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +create index GEN_CLUST_INDEX on bug46000(id); + +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +show errors; + +# This 'create index' operation should succeed, no +# temp table left from last failed create index +# operation. +create index idx on bug46000(id); + +drop table bug46000; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 207406f8673..10f8da40b36 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -155,17 +155,36 @@ static void free_share(INNOBASE_SHARE *share); static int innobase_close_connection(handlerton *hton, THD* thd); static int innobase_commit(handlerton *hton, THD* thd, bool all); static int innobase_rollback(handlerton *hton, THD* thd, bool all); -static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd, +static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd, void *savepoint); static int innobase_savepoint(handlerton *hton, THD* thd, void *savepoint); -static int innobase_release_savepoint(handlerton *hton, THD* thd, +static int innobase_release_savepoint(handlerton *hton, THD* thd, void *savepoint); static handler *innobase_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); +/*********************************************************************** +This function checks each index name for a table against reserved +system default primary index name 'GEN_CLUST_INDEX'. If a name matches, +this function pushes an error message to the client, and returns true. */ +static +bool +innobase_index_name_is_reserved( +/*============================*/ + /* out: true if index name matches a + reserved name */ + const trx_t* trx, /* in: InnoDB transaction handle */ + const TABLE* form, /* in: information on table + columns and indexes */ + const char* norm_name); /* in: table name */ + static const char innobase_hton_name[]= "InnoDB"; +/* "GEN_CLUST_INDEX" is the name reserved for Innodb default +system primary index. */ +static const char innobase_index_reserve_name[]= "GEN_CLUST_INDEX"; + /** @brief Initialize the default value of innodb_commit_concurrency. Once InnoDB is running, the innodb_commit_concurrency must not change @@ -5199,6 +5218,9 @@ create_index( n_fields = key->key_parts; + /* Assert that "GEN_CLUST_INDEX" cannot be used as non-primary index */ + ut_a(innobase_strcasecmp(key->name, innobase_index_reserve_name) != 0); + ind_type = 0; if (key_num == form->s->primary_key) { @@ -5311,8 +5333,8 @@ create_clustered_index_when_no_primary( /* We pass 0 as the space id, and determine at a lower level the space id where to store the table */ - - index = dict_mem_index_create(table_name, "GEN_CLUST_INDEX", + index = dict_mem_index_create(table_name, + innobase_index_reserve_name, 0, DICT_CLUSTERED, 0); error = row_create_index_for_mysql(index, trx, NULL); @@ -5444,14 +5466,6 @@ ha_innobase::create( flags |= DICT_TF_COMPACT; } - error = create_table_def(trx, form, norm_name, - create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, - flags); - - if (error) { - goto cleanup; - } - /* Look for a primary key */ primary_key_no= (form->s->primary_key != MAX_KEY ? @@ -5463,6 +5477,22 @@ ha_innobase::create( DBUG_ASSERT(primary_key_no == -1 || primary_key_no == 0); + /* Check for name conflicts (with reserved name) for + any user indices to be created. */ + if (innobase_index_name_is_reserved(trx, form, norm_name)) { + error = -1; + goto cleanup; + } + + error = create_table_def(trx, form, norm_name, + create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, + flags); + + if (error) { + goto cleanup; + } + + /* Create the keys */ if (form->s->keys == 0 || primary_key_no == -1) { @@ -8409,6 +8439,46 @@ static int show_innodb_vars(THD *thd, SHOW_VAR *var, char *buff) return 0; } +/*********************************************************************** +This function checks each index name for a table against reserved +system default primary index name 'GEN_CLUST_INDEX'. If a name matches, +this function pushes an error message to the client, and returns true. */ +static +bool +innobase_index_name_is_reserved( +/*============================*/ + /* out: true if an index name + matches the reserved name */ + const trx_t* trx, /* in: InnoDB transaction handle */ + const TABLE* form, /* in: information on table + columns and indexes */ + const char* norm_name) /* in: table name */ +{ + KEY* key; + uint key_num; /* index number */ + + for (key_num = 0; key_num < form->s->keys; key_num++) { + key = form->key_info + key_num; + + if (innobase_strcasecmp(key->name, + innobase_index_reserve_name) == 0) { + /* Push warning to mysql */ + push_warning_printf((THD*) trx->mysql_thd, + MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_CANT_CREATE_TABLE, + "Cannot Create Index with name " + "'%s'. The name is reserved " + "for the system default primary " + "index.", + innobase_index_reserve_name); + + return(true); + } + } + + return(false); +} + static SHOW_VAR innodb_status_variables_export[]= { {"Innodb", (char*) &show_innodb_vars, SHOW_FUNC}, {NullS, NullS, SHOW_LONG} From 37e4f861ed7864488f49c808be79f1c315afbe44 Mon Sep 17 00:00:00 2001 From: Satya B Date: Mon, 5 Oct 2009 16:47:48 +0530 Subject: [PATCH 074/146] Applying InnoDB snapshot 5.1-ss5921, part 2. Fixes BUG#44369 BUG#44369 - InnoDB: Does not uniformly disallow disallowed column names Detailed revision comments: r5741 | jyang | 2009-09-03 07:16:01 +0300 (Thu, 03 Sep 2009) | 5 lines branches/5.1: Block creating table with column name conflicting with Innodb reserved key words. (Bug #44369) rb://151 approved by Sunny Bains. r5760 | jyang | 2009-09-04 07:07:34 +0300 (Fri, 04 Sep 2009) | 3 lines branches/5.1: This is to revert change 5741. A return status for create_table_def() needs to be fixed. r5834 | jyang | 2009-09-11 00:43:05 +0300 (Fri, 11 Sep 2009) | 5 lines branches/5.1: Block creating table with column name conflicting with Innodb reserved key words. (Bug #44369) rb://151 approved by Sunny Bains. --- mysql-test/lib/mtr_cases.pm | 2 ++ mysql-test/r/innodb_bug44369.result | 14 ++++++++++++++ mysql-test/t/innodb_bug44369.test | 21 +++++++++++++++++++++ storage/innobase/dict/dict0dict.c | 2 +- storage/innobase/handler/ha_innodb.cc | 23 +++++++++++++++++++++++ storage/innobase/row/row0mysql.c | 13 ------------- 6 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 mysql-test/r/innodb_bug44369.result create mode 100644 mysql-test/t/innodb_bug44369.test diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 5c2d2d5380e..84253ddc5a6 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -509,6 +509,8 @@ sub collect_one_suite($) next if ($test->{'name'} eq 'sys_vars.innodb_thread_concurrency_basic'); # Disable for Innodb Plugin until the fix for Plugin is received next if ($test->{'name'} eq 'main.innodb_bug46000'); + # Disable for Innodb Plugin until the fix for Plugin is received + next if ($test->{'name'} eq 'main.innodb_bug44369'); # Copy test options my $new_test= My::Test->new(); while (my ($key, $value) = each(%$test)) diff --git a/mysql-test/r/innodb_bug44369.result b/mysql-test/r/innodb_bug44369.result new file mode 100644 index 00000000000..e4b84ecac19 --- /dev/null +++ b/mysql-test/r/innodb_bug44369.result @@ -0,0 +1,14 @@ +create table bug44369 (DB_ROW_ID int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +create table bug44369 (db_row_id int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +show errors; +Level Code Message +Error 1005 Error creating table 'test/bug44369' with column name 'db_row_id'. 'db_row_id' is a reserved name. Please try to re-create the table with a different column name. +Error 1005 Can't create table 'test.bug44369' (errno: -1) +create table bug44369 (db_TRX_Id int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +show errors; +Level Code Message +Error 1005 Error creating table 'test/bug44369' with column name 'db_TRX_Id'. 'db_TRX_Id' is a reserved name. Please try to re-create the table with a different column name. +Error 1005 Can't create table 'test.bug44369' (errno: -1) diff --git a/mysql-test/t/innodb_bug44369.test b/mysql-test/t/innodb_bug44369.test new file mode 100644 index 00000000000..495059eb5e6 --- /dev/null +++ b/mysql-test/t/innodb_bug44369.test @@ -0,0 +1,21 @@ +# This is the test for bug 44369. We should +# block table creation with columns match +# some innodb internal reserved key words, +# both case sensitively and insensitely. + +--source include/have_innodb.inc + +# This create table operation should fail. +--error ER_CANT_CREATE_TABLE +create table bug44369 (DB_ROW_ID int) engine=innodb; + +# This create should fail as well +--error ER_CANT_CREATE_TABLE +create table bug44369 (db_row_id int) engine=innodb; + +show errors; + +--error ER_CANT_CREATE_TABLE +create table bug44369 (db_TRX_Id int) engine=innodb; + +show errors; diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 8cb196bf983..b8251a99105 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -1268,7 +1268,7 @@ dict_col_name_is_reserved( ulint i; for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) { - if (strcmp(name, reserved_names[i]) == 0) { + if (innobase_strcasecmp(name, reserved_names[i]) == 0) { return(TRUE); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 10f8da40b36..3431a5c7e37 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -5166,6 +5166,28 @@ create_table_def( } } + /* First check whether the column to be added has a + system reserved name. */ + if (dict_col_name_is_reserved(field->field_name)){ + push_warning_printf( + (THD*) trx->mysql_thd, + MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_CANT_CREATE_TABLE, + "Error creating table '%s' with " + "column name '%s'. '%s' is a " + "reserved name. Please try to " + "re-create the table with a " + "different column name.", + table->name, (char*) field->field_name, + (char*) field->field_name); + + dict_mem_table_free(table); + trx_commit_for_mysql(trx); + + error = DB_ERROR; + goto error_ret; + } + dict_mem_table_add_col(table, table->heap, (char*) field->field_name, col_type, @@ -5181,6 +5203,7 @@ create_table_def( innodb_check_for_record_too_big_error(flags & DICT_TF_COMPACT, error); +error_ret: error = convert_error_code_to_mysql(error, NULL); DBUG_RETURN(error); diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 6ec466cf995..d0364c9c568 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -1788,7 +1788,6 @@ row_create_table_for_mysql( const char* table_name; ulint table_name_len; ulint err; - ulint i; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); #ifdef UNIV_SYNC_DEBUG @@ -1827,18 +1826,6 @@ row_create_table_for_mysql( return(DB_ERROR); } - /* Check that no reserved column names are used. */ - for (i = 0; i < dict_table_get_n_user_cols(table); i++) { - if (dict_col_name_is_reserved( - dict_table_get_col_name(table, i))) { - - dict_mem_table_free(table); - trx_commit_for_mysql(trx); - - return(DB_ERROR); - } - } - trx_start_if_not_started(trx); /* The table name is prefixed with the database name and a '/'. From 00297f65d717b4ffb3c00df2fda9494944950788 Mon Sep 17 00:00:00 2001 From: Satya B Date: Mon, 5 Oct 2009 16:56:10 +0530 Subject: [PATCH 075/146] Applying InnoDB snapshot 5.1-ss5921, part 3. Fixes BUG#46256 1. BUG#46256 - drop table with unknown collation crashes innodb Note: No testcase attached and has to be verified manually Detailed revision comments: r5799 | calvin | 2009-09-09 20:47:31 +0300 (Wed, 09 Sep 2009) | 10 lines branches/5.1: fix bug#46256 Allow tables to be dropped even if the collation is not found, but issue a warning. Could not find an easy way to add mysql-test since it requires changes to charsets and restarting the server. Tests were executed manually. Approved by: Heikki (on IM) r5805 | vasil | 2009-09-10 08:41:48 +0300 (Thu, 10 Sep 2009) | 7 lines branches/5.1: Fix a compilation warning caused by c5799: handler/ha_innodb.cc: In function 'void innobase_get_cset_width(ulint, ulint*, ulint*)': handler/ha_innodb.cc:830: warning: format '%d' expects type 'int', but argument 2 has type 'ulint' --- storage/innobase/handler/ha_innodb.cc | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 3431a5c7e37..a8b9b678282 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -837,7 +837,22 @@ innobase_get_cset_width( *mbminlen = cs->mbminlen; *mbmaxlen = cs->mbmaxlen; } else { - ut_a(cset == 0); + if (current_thd + && (thd_sql_command(current_thd) == SQLCOM_DROP_TABLE)) { + + /* Fix bug#46256: allow tables to be dropped if the + collation is not found, but issue a warning. */ + if ((global_system_variables.log_warnings) + && (cset != 0)){ + + sql_print_warning( + "Unknown collation #%lu.", cset); + } + } else { + + ut_a(cset == 0); + } + *mbminlen = *mbmaxlen = 0; } } From 166d08c7ebc8db3a4b8c40988a089c5a28663d0a Mon Sep 17 00:00:00 2001 From: Frazer Clement Date: Mon, 5 Oct 2009 13:57:00 +0100 Subject: [PATCH 076/146] Bug#39663 mysqltest: --enable_info, affected_rows and ps-protocol broken --- client/mysqltest.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 4f8e6cdac99..fb33d30da81 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -6346,6 +6346,16 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, */ } + /* + Need to grab affected rows information before getting + warnings here + */ + ulonglong affected_rows; + LINT_INIT(affected_rows); + + if (!disable_info) + affected_rows= mysql_affected_rows(mysql); + if (!disable_warnings) { /* Get the warnings from execute */ @@ -6370,7 +6380,7 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, } if (!disable_info) - append_info(ds, mysql_affected_rows(mysql), mysql_info(mysql)); + append_info(ds, affected_rows, mysql_info(mysql)); } From 23bdf0d805026b220061487688f0cb2d2b272975 Mon Sep 17 00:00:00 2001 From: "John H. Embretsen" Date: Mon, 5 Oct 2009 15:16:27 +0200 Subject: [PATCH 077/146] Bug#47746 - main.innodb_mysql fails sporadically: Mask part of EXPLAIN output with '#' to account for varying row count estimation. --- mysql-test/include/mix1.inc | 2 ++ mysql-test/r/innodb_mysql.result | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index 6dabe4864a9..194d9e41108 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -442,6 +442,8 @@ INSERT INTO t1(id, dept, age, name) VALUES EXPLAIN SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5'; SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5'; DELETE FROM t1; +--echo # Masking (#) number in "rows" column of the following EXPLAIN output, as it may vary (bug#47746). +--replace_column 9 # EXPLAIN SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5'; SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5'; diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 3ff5f04b6c6..b112bde4f27 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -385,9 +385,10 @@ name dept rs5 cs10 rs5 cs9 DELETE FROM t1; +# Masking (#) number in "rows" column of the following EXPLAIN output, as it may vary (bug#47746). EXPLAIN SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range name name 44 NULL 2 Using where; Using index for group-by +1 SIMPLE t1 range name name 44 NULL # Using where; Using index for group-by SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5'; name dept DROP TABLE t1; From d0d2853b8eb09b621c44ed75c29d2a9c74a46a2e Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Mon, 5 Oct 2009 20:14:43 +0200 Subject: [PATCH 078/146] Add fixes for Bug#46834: Test suite missing from RPMs Additional changes from the following commits: http://lists.mysql.com/commits/81279 http://lists.mysql.com/commits/81607 These were missed when scanning 'bzr log' for changes. --- mysql-test/Makefile.am | 3 ++- mysql-test/lib/My/SafeProcess/Makefile.am | 3 ++- mysql-test/lib/mtr_cases.pm | 3 ++- storage/ndb/test/run-test/Makefile.am | 3 ++- support-files/mysql.spec.sh | 4 ++++ 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index 7a56584190d..c183553f963 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -17,7 +17,8 @@ ## Process this file with automake to create Makefile.in -testdir = $(prefix)/mysql-test +testroot = $(prefix) +testdir = $(testroot)/mysql-test test_SCRIPTS = mtr \ mysql-test-run \ diff --git a/mysql-test/lib/My/SafeProcess/Makefile.am b/mysql-test/lib/My/SafeProcess/Makefile.am index 623c0e9a87a..722331453fe 100644 --- a/mysql-test/lib/My/SafeProcess/Makefile.am +++ b/mysql-test/lib/My/SafeProcess/Makefile.am @@ -13,7 +13,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -safedir = $(prefix)/mysql-test/lib/My/SafeProcess +testroot = $(prefix) +safedir = $(testroot)/mysql-test/lib/My/SafeProcess #nobase_bin_PROGRAMS = ... safe_PROGRAMS = my_safe_process diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 2a7b07debd0..841def4d0ad 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -239,7 +239,8 @@ sub collect_one_suite($) else { $suitedir= my_find_dir($::basedir, - ["mysql-test/suite", + ["share/mysql-test/suite", + "mysql-test/suite", "mysql-test", # Look in storage engine specific suite dirs "storage/*/mysql-test-suites" diff --git a/storage/ndb/test/run-test/Makefile.am b/storage/ndb/test/run-test/Makefile.am index 65aa62d11f0..54ca0c009b2 100644 --- a/storage/ndb/test/run-test/Makefile.am +++ b/storage/ndb/test/run-test/Makefile.am @@ -13,7 +13,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -testdir=$(prefix)/mysql-test/ndb +testroot=$(prefix) +testdir=$(testroot)/mysql-test/ndb include $(top_srcdir)/storage/ndb/config/common.mk.am include $(top_srcdir)/storage/ndb/config/type_util.mk.am diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 5b8d7a5922d..bd2098b1aca 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -886,6 +886,10 @@ fi - Update variable used for mysql-test suite location to match source. +* Thu Aug 20 2009 Jonathan Perkin + +- Update variable used for mysql-test suite location to match source. + * Fri Nov 07 2008 Joerg Bruehe - Correct yesterday's fix, so that it also works for the last flag, From 678eb3d66f4e9b4ef2341c0ba732700ec554381a Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Tue, 6 Oct 2009 01:38:58 +0100 Subject: [PATCH 079/146] BUG#47287 RBR: replication diff on basic case with txn- and non-txn tables in a statement Let - T be a transactional table and N non-transactional table. - B be begin, C commit and R rollback. - M be a mixed statement, i.e. a statement that updates both T and N. - M* be a mixed statement that fails while updating either T or N. This patch restore the behavior presented in 5.1.37 for rows either produced in the RBR or MIXED modes, when a M* statement that happened early in a transaction had their changes written to the binary log outside the boundaries of the transaction and wrapped in a BEGIN/ROLLBACK. This was done to keep the slave consistent with with the master as the rollback would keep the changes on N and undo them on T. In particular, we do what follows: . B M* T C would log - B M* R B T C. Note that, we are not preserving history from the master as we are introducing a rollback that never happened. However, this seems to be more acceptable than making the slave diverge. We do not fix the following case: . B T M* C would log B T M* C. The slave will diverge as the changes on T tables that originated from the M statement are rolled back on the master but not on the slave. Unfortunately, we cannot simply rollback the transaction as this would undo any uncommitted changes on T tables. SBR is not considered in this patch because a failing statement is written to the binary along with the error code and a slave executes and then rolls back the statement when it has an associated error code, thus undoing the effects on T. In RBR and MBR, a full-fledged fix will be pushed after the WL 2687. --- .../binlog_failure_mixing_engines.test | 200 +++++++++++++ ...binlog_mixed_failure_mixing_engines.result | 234 +++++++++++++++ .../binlog_row_failure_mixing_engines.result | 268 ++++++++++++++++++ .../binlog_mixed_failure_mixing_engines.test | 4 + .../t/binlog_row_failure_mixing_engines.test | 4 + sql/log.cc | 25 +- 6 files changed, 726 insertions(+), 9 deletions(-) create mode 100644 mysql-test/extra/binlog_tests/binlog_failure_mixing_engines.test create mode 100644 mysql-test/suite/binlog/r/binlog_mixed_failure_mixing_engines.result create mode 100644 mysql-test/suite/binlog/r/binlog_row_failure_mixing_engines.result create mode 100644 mysql-test/suite/binlog/t/binlog_mixed_failure_mixing_engines.test create mode 100644 mysql-test/suite/binlog/t/binlog_row_failure_mixing_engines.test diff --git a/mysql-test/extra/binlog_tests/binlog_failure_mixing_engines.test b/mysql-test/extra/binlog_tests/binlog_failure_mixing_engines.test new file mode 100644 index 00000000000..26ae8f625a9 --- /dev/null +++ b/mysql-test/extra/binlog_tests/binlog_failure_mixing_engines.test @@ -0,0 +1,200 @@ +################################################################################ +# Let +# - B be begin, C commit and R rollback. +# - T a statement that accesses and changes only transactional tables, i.e. +# T-tables +# - N a statement that accesses and changes only non-transactional tables, +# i.e, N-tables. +# - M be a mixed statement, i.e. a statement that updates both T- and +# N-tables. +# - M* be a mixed statement that fails while updating either a T +# or N-table. +# - N* be a statement that fails while updating a N-table. +# +# In this test case, when changes are logged as rows either in the RBR or MIXED +# modes, we check if a M* statement that happens early in a transaction is +# written to the binary log outside the boundaries of the transaction and +# wrapped up in a BEGIN/ROLLBACK. This is done to keep the slave consistent with +# the master as the rollback will keep the changes on N-tables and undo them on +# T-tables. In particular, we expect the following behavior: +# +# 1. B M* T C would generate in the binlog B M* R B T C. +# 2. B M M* C would generate in the binlog B M M* C. +# 3. B M* M* T C would generate in the binlog B M* R B M* R B T C. +# +# SBR is not considered in this test because a failing statement is written to +# the binary along with the error code such that a slave executes and rolls it +# back, thus undoing the effects on T-tables. +# +# Note that, in the first case, we are not preserving history from the master as +# we are introducing a rollback that never happened. However, this seems to be +# more acceptable than making the slave diverge. In the second case, the slave +# will diverge as the changes on T-tables that originated from the M statement +# are rolled back on the master but not on the slave. Unfortunately, we cannot +# simply roll the transaction back as this would undo any uncommitted changes +# on T-tables. +# +# We check one more case. INSERT M...SELECT* which produces the following +# results: +# +# 1. B T INSERT M...SELECT* C" with an error in INSERT M...SELECT* generates in +# the binlog the following entries: "Nothing". +# 2. B INSERT M...SELECT* C" with an error in INSERT M...SELECT* generates in +# the binlog the following entries: B INSERT M...SELECT* R. +# +# Such issues do not happen in SBR. In RBR and MBR, a full-fledged fix will be +# pushed after the WL#2687. +# +# Please, remove this test case after pushing WL#2687. +################################################################################ + + +--echo ################################################################################### +--echo # CONFIGURATION +--echo ################################################################################### +CREATE TABLE nt_1 (a text, b int PRIMARY KEY) ENGINE = MyISAM; +CREATE TABLE nt_2 (a text, b int PRIMARY KEY) ENGINE = MyISAM; +CREATE TABLE tt_1 (a text, b int PRIMARY KEY) ENGINE = Innodb; +CREATE TABLE tt_2 (a text, b int PRIMARY KEY) ENGINE = Innodb; + +DELIMITER |; + +CREATE TRIGGER tr_i_tt_1_to_nt_1 BEFORE INSERT ON tt_1 FOR EACH ROW +BEGIN + INSERT INTO nt_1 VALUES (NEW.a, NEW.b); +END| + +CREATE TRIGGER tr_i_nt_2_to_tt_2 BEFORE INSERT ON nt_2 FOR EACH ROW +BEGIN + INSERT INTO tt_2 VALUES (NEW.a, NEW.b); +END| + +DELIMITER ;| + +--echo ################################################################################### +--echo # CHECK HISTORY IN BINLOG +--echo ################################################################################### +--echo +--echo +--echo +--echo *** "B M* T C" with error in M* generates in the binlog the "B M* R B T C" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +INSERT INTO nt_1 VALUES ("new text 1", 1); +BEGIN; +--error ER_DUP_ENTRY +INSERT INTO tt_1 VALUES (USER(), 2), (USER(), 1); +INSERT INTO tt_2 VALUES ("new text 3", 3); +COMMIT; +--source include/show_binlog_events.inc + +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +INSERT INTO tt_2 VALUES ("new text 4", 4); +BEGIN; +--error ER_DUP_ENTRY +INSERT INTO nt_2 VALUES (USER(), 5), (USER(), 4); +INSERT INTO tt_2 VALUES ("new text 6", 6); +COMMIT; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B M M* T C" with error in M* generates in the binlog the "B M M* T C" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +INSERT INTO nt_1 VALUES ("new text 10", 10); +BEGIN; +INSERT INTO tt_1 VALUES ("new text 7", 7), ("new text 8", 8); +--error ER_DUP_ENTRY +INSERT INTO tt_1 VALUES (USER(), 9), (USER(), 10); +INSERT INTO tt_2 VALUES ("new text 11", 11); +COMMIT; +--source include/show_binlog_events.inc + +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +INSERT INTO tt_2 VALUES ("new text 15", 15); +BEGIN; +INSERT INTO nt_2 VALUES ("new text 12", 12), ("new text 13", 13); +--error ER_DUP_ENTRY +INSERT INTO nt_2 VALUES (USER(), 14), (USER(), 15); +INSERT INTO tt_2 VALUES ("new text 16", 16); +COMMIT; +--source include/show_binlog_events.inc + + +--echo +--echo +--echo +--echo *** "B M* M* T C" with error in M* generates in the binlog the "B M* R B M* R B T C" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +INSERT INTO nt_1 VALUES ("new text 18", 18); +INSERT INTO nt_1 VALUES ("new text 20", 20); +BEGIN; +--error ER_DUP_ENTRY +INSERT INTO tt_1 VALUES (USER(), 17), (USER(), 18); +--error ER_DUP_ENTRY +INSERT INTO tt_1 VALUES (USER(), 19), (USER(), 20); +INSERT INTO tt_2 VALUES ("new text 21", 21); +COMMIT; +--source include/show_binlog_events.inc + +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +INSERT INTO tt_2 VALUES ("new text 23", 23); +INSERT INTO tt_2 VALUES ("new text 25", 25); +BEGIN; +--error ER_DUP_ENTRY +INSERT INTO nt_2 VALUES (USER(), 22), (USER(), 23); +--error ER_DUP_ENTRY +INSERT INTO nt_2 VALUES (USER(), 24), (USER(), 25); +INSERT INTO tt_2 VALUES ("new text 26", 26); +COMMIT; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B T INSERT M...SELECT* C" with an error in INSERT M...SELECT* generates +--echo *** in the binlog the following entries: "Nothing". +--echo *** There is a bug in that will be fixed after WL#2687. Please, check BUG#47175 for further details. +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +TRUNCATE TABLE nt_2; +TRUNCATE TABLE tt_2; +INSERT INTO tt_2 VALUES ("new text 7", 7); +BEGIN; +INSERT INTO tt_2 VALUES ("new text 27", 27); +--error ER_DUP_ENTRY +INSERT INTO nt_2(a, b) SELECT USER(), b FROM nt_1; +INSERT INTO tt_2 VALUES ("new text 28", 28); +ROLLBACK; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B INSERT M..SELECT* C" with an error in INSERT M...SELECT* generates +--echo *** in the binlog the following entries: "B INSERT M..SELECT* R". +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +TRUNCATE TABLE nt_2; +TRUNCATE TABLE tt_2; +INSERT INTO tt_2 VALUES ("new text 7", 7); +BEGIN; +--error ER_DUP_ENTRY +INSERT INTO nt_2(a, b) SELECT USER(), b FROM nt_1; +COMMIT; +--source include/show_binlog_events.inc + +--echo ################################################################################### +--echo # CLEAN +--echo ################################################################################### + +DROP TABLE tt_1; +DROP TABLE tt_2; +DROP TABLE nt_1; +DROP TABLE nt_2; diff --git a/mysql-test/suite/binlog/r/binlog_mixed_failure_mixing_engines.result b/mysql-test/suite/binlog/r/binlog_mixed_failure_mixing_engines.result new file mode 100644 index 00000000000..16a2ce50655 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_mixed_failure_mixing_engines.result @@ -0,0 +1,234 @@ +################################################################################### +# CONFIGURATION +################################################################################### +CREATE TABLE nt_1 (a text, b int PRIMARY KEY) ENGINE = MyISAM; +CREATE TABLE nt_2 (a text, b int PRIMARY KEY) ENGINE = MyISAM; +CREATE TABLE tt_1 (a text, b int PRIMARY KEY) ENGINE = Innodb; +CREATE TABLE tt_2 (a text, b int PRIMARY KEY) ENGINE = Innodb; +CREATE TRIGGER tr_i_tt_1_to_nt_1 BEFORE INSERT ON tt_1 FOR EACH ROW +BEGIN +INSERT INTO nt_1 VALUES (NEW.a, NEW.b); +END| +CREATE TRIGGER tr_i_nt_2_to_tt_2 BEFORE INSERT ON nt_2 FOR EACH ROW +BEGIN +INSERT INTO tt_2 VALUES (NEW.a, NEW.b); +END| +################################################################################### +# CHECK HISTORY IN BINLOG +################################################################################### + + + +*** "B M* T C" with error in M* generates in the binlog the "B M* R B T C" entries + +INSERT INTO nt_1 VALUES ("new text 1", 1); +BEGIN; +INSERT INTO tt_1 VALUES (USER(), 2), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 3", 3); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; INSERT INTO nt_1 VALUES ("new text 1", 1) +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 3", 3) +master-bin.000001 # Xid # # COMMIT /* XID */ + +INSERT INTO tt_2 VALUES ("new text 4", 4); +BEGIN; +INSERT INTO nt_2 VALUES (USER(), 5), (USER(), 4); +ERROR 23000: Duplicate entry '4' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 6", 6); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 4", 4) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 6", 6) +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B M M* T C" with error in M* generates in the binlog the "B M M* T C" entries + +INSERT INTO nt_1 VALUES ("new text 10", 10); +BEGIN; +INSERT INTO tt_1 VALUES ("new text 7", 7), ("new text 8", 8); +INSERT INTO tt_1 VALUES (USER(), 9), (USER(), 10); +ERROR 23000: Duplicate entry '10' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 11", 11); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; INSERT INTO nt_1 VALUES ("new text 10", 10) +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_1 VALUES ("new text 7", 7), ("new text 8", 8) +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 11", 11) +master-bin.000001 # Xid # # COMMIT /* XID */ + +INSERT INTO tt_2 VALUES ("new text 15", 15); +BEGIN; +INSERT INTO nt_2 VALUES ("new text 12", 12), ("new text 13", 13); +INSERT INTO nt_2 VALUES (USER(), 14), (USER(), 15); +ERROR 23000: Duplicate entry '15' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 16", 16); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 15", 15) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO nt_2 VALUES ("new text 12", 12), ("new text 13", 13) +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 16", 16) +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B M* M* T C" with error in M* generates in the binlog the "B M* R B M* R B T C" entries + +INSERT INTO nt_1 VALUES ("new text 18", 18); +INSERT INTO nt_1 VALUES ("new text 20", 20); +BEGIN; +INSERT INTO tt_1 VALUES (USER(), 17), (USER(), 18); +ERROR 23000: Duplicate entry '18' for key 'PRIMARY' +INSERT INTO tt_1 VALUES (USER(), 19), (USER(), 20); +ERROR 23000: Duplicate entry '20' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 21", 21); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; INSERT INTO nt_1 VALUES ("new text 18", 18) +master-bin.000001 # Query # # use `test`; INSERT INTO nt_1 VALUES ("new text 20", 20) +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 21", 21) +master-bin.000001 # Xid # # COMMIT /* XID */ + +INSERT INTO tt_2 VALUES ("new text 23", 23); +INSERT INTO tt_2 VALUES ("new text 25", 25); +BEGIN; +INSERT INTO nt_2 VALUES (USER(), 22), (USER(), 23); +ERROR 23000: Duplicate entry '23' for key 'PRIMARY' +INSERT INTO nt_2 VALUES (USER(), 24), (USER(), 25); +ERROR 23000: Duplicate entry '25' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 26", 26); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 23", 23) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 25", 25) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 26", 26) +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B T INSERT M...SELECT* C" with an error in INSERT M...SELECT* generates +*** in the binlog the following entries: "Nothing". +*** There is a bug in that will be fixed after WL#2687. Please, check BUG#47175 for further details. + +TRUNCATE TABLE nt_2; +TRUNCATE TABLE tt_2; +INSERT INTO tt_2 VALUES ("new text 7", 7); +BEGIN; +INSERT INTO tt_2 VALUES ("new text 27", 27); +INSERT INTO nt_2(a, b) SELECT USER(), b FROM nt_1; +ERROR 23000: Duplicate entry '7' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 28", 28); +ROLLBACK; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE nt_2 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE tt_2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 7", 7) +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B INSERT M..SELECT* C" with an error in INSERT M...SELECT* generates +*** in the binlog the following entries: "B INSERT M..SELECT* R". + +TRUNCATE TABLE nt_2; +TRUNCATE TABLE tt_2; +INSERT INTO tt_2 VALUES ("new text 7", 7); +BEGIN; +INSERT INTO nt_2(a, b) SELECT USER(), b FROM nt_1; +ERROR 23000: Duplicate entry '7' for key 'PRIMARY' +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE nt_2 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE tt_2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 7", 7) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +################################################################################### +# CLEAN +################################################################################### +DROP TABLE tt_1; +DROP TABLE tt_2; +DROP TABLE nt_1; +DROP TABLE nt_2; diff --git a/mysql-test/suite/binlog/r/binlog_row_failure_mixing_engines.result b/mysql-test/suite/binlog/r/binlog_row_failure_mixing_engines.result new file mode 100644 index 00000000000..85a13af3957 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_row_failure_mixing_engines.result @@ -0,0 +1,268 @@ +################################################################################### +# CONFIGURATION +################################################################################### +CREATE TABLE nt_1 (a text, b int PRIMARY KEY) ENGINE = MyISAM; +CREATE TABLE nt_2 (a text, b int PRIMARY KEY) ENGINE = MyISAM; +CREATE TABLE tt_1 (a text, b int PRIMARY KEY) ENGINE = Innodb; +CREATE TABLE tt_2 (a text, b int PRIMARY KEY) ENGINE = Innodb; +CREATE TRIGGER tr_i_tt_1_to_nt_1 BEFORE INSERT ON tt_1 FOR EACH ROW +BEGIN +INSERT INTO nt_1 VALUES (NEW.a, NEW.b); +END| +CREATE TRIGGER tr_i_nt_2_to_tt_2 BEFORE INSERT ON nt_2 FOR EACH ROW +BEGIN +INSERT INTO tt_2 VALUES (NEW.a, NEW.b); +END| +################################################################################### +# CHECK HISTORY IN BINLOG +################################################################################### + + + +*** "B M* T C" with error in M* generates in the binlog the "B M* R B T C" entries + +INSERT INTO nt_1 VALUES ("new text 1", 1); +BEGIN; +INSERT INTO tt_1 VALUES (USER(), 2), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 3", 3); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + +INSERT INTO tt_2 VALUES ("new text 4", 4); +BEGIN; +INSERT INTO nt_2 VALUES (USER(), 5), (USER(), 4); +ERROR 23000: Duplicate entry '4' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 6", 6); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B M M* T C" with error in M* generates in the binlog the "B M M* T C" entries + +INSERT INTO nt_1 VALUES ("new text 10", 10); +BEGIN; +INSERT INTO tt_1 VALUES ("new text 7", 7), ("new text 8", 8); +INSERT INTO tt_1 VALUES (USER(), 9), (USER(), 10); +ERROR 23000: Duplicate entry '10' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 11", 11); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + +INSERT INTO tt_2 VALUES ("new text 15", 15); +BEGIN; +INSERT INTO nt_2 VALUES ("new text 12", 12), ("new text 13", 13); +INSERT INTO nt_2 VALUES (USER(), 14), (USER(), 15); +ERROR 23000: Duplicate entry '15' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 16", 16); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B M* M* T C" with error in M* generates in the binlog the "B M* R B M* R B T C" entries + +INSERT INTO nt_1 VALUES ("new text 18", 18); +INSERT INTO nt_1 VALUES ("new text 20", 20); +BEGIN; +INSERT INTO tt_1 VALUES (USER(), 17), (USER(), 18); +ERROR 23000: Duplicate entry '18' for key 'PRIMARY' +INSERT INTO tt_1 VALUES (USER(), 19), (USER(), 20); +ERROR 23000: Duplicate entry '20' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 21", 21); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + +INSERT INTO tt_2 VALUES ("new text 23", 23); +INSERT INTO tt_2 VALUES ("new text 25", 25); +BEGIN; +INSERT INTO nt_2 VALUES (USER(), 22), (USER(), 23); +ERROR 23000: Duplicate entry '23' for key 'PRIMARY' +INSERT INTO nt_2 VALUES (USER(), 24), (USER(), 25); +ERROR 23000: Duplicate entry '25' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 26", 26); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B T INSERT M...SELECT* C" with an error in INSERT M...SELECT* generates +*** in the binlog the following entries: "Nothing". +*** There is a bug in that will be fixed after WL#2687. Please, check BUG#47175 for further details. + +TRUNCATE TABLE nt_2; +TRUNCATE TABLE tt_2; +INSERT INTO tt_2 VALUES ("new text 7", 7); +BEGIN; +INSERT INTO tt_2 VALUES ("new text 27", 27); +INSERT INTO nt_2(a, b) SELECT USER(), b FROM nt_1; +ERROR 23000: Duplicate entry '7' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 28", 28); +ROLLBACK; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE nt_2 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE tt_2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B INSERT M..SELECT* C" with an error in INSERT M...SELECT* generates +*** in the binlog the following entries: "B INSERT M..SELECT* R". + +TRUNCATE TABLE nt_2; +TRUNCATE TABLE tt_2; +INSERT INTO tt_2 VALUES ("new text 7", 7); +BEGIN; +INSERT INTO nt_2(a, b) SELECT USER(), b FROM nt_1; +ERROR 23000: Duplicate entry '7' for key 'PRIMARY' +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE nt_2 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE tt_2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +################################################################################### +# CLEAN +################################################################################### +DROP TABLE tt_1; +DROP TABLE tt_2; +DROP TABLE nt_1; +DROP TABLE nt_2; diff --git a/mysql-test/suite/binlog/t/binlog_mixed_failure_mixing_engines.test b/mysql-test/suite/binlog/t/binlog_mixed_failure_mixing_engines.test new file mode 100644 index 00000000000..09b168c2882 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_mixed_failure_mixing_engines.test @@ -0,0 +1,4 @@ +--source include/have_binlog_format_mixed.inc +--source include/have_innodb.inc + +--source extra/binlog_tests/binlog_failure_mixing_engines.test diff --git a/mysql-test/suite/binlog/t/binlog_row_failure_mixing_engines.test b/mysql-test/suite/binlog/t/binlog_row_failure_mixing_engines.test new file mode 100644 index 00000000000..e25af7a7e10 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_row_failure_mixing_engines.test @@ -0,0 +1,4 @@ +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc + +--source extra/binlog_tests/binlog_failure_mixing_engines.test diff --git a/sql/log.cc b/sql/log.cc index feaa5499912..9c733636bad 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -153,7 +153,7 @@ private: class binlog_trx_data { public: binlog_trx_data() - : at_least_one_stmt(0), incident(FALSE), m_pending(0), + : at_least_one_stmt_committed(0), incident(FALSE), m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF) { trans_log.end_of_file= max_binlog_cache_size; @@ -182,7 +182,10 @@ public: { DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos)); DBUG_PRINT("info", ("before_stmt_pos=%lu", (ulong) pos)); - delete pending(); + if (pending()) + { + delete pending(); + } set_pending(0); reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0); trans_log.end_of_file= max_binlog_cache_size; @@ -192,12 +195,12 @@ public: /* The only valid positions that can be truncated to are at the beginning of a statement. We are relying on this fact to be able - to set the at_least_one_stmt flag correctly. In other word, if + to set the at_least_one_stmt_committed flag correctly. In other word, if we are truncating to the beginning of the transaction cache, there will be no statements in the cache, otherwhise, we will have at least one statement in the transaction cache. */ - at_least_one_stmt= (pos > 0); + at_least_one_stmt_committed= (pos > 0); } /* @@ -239,7 +242,7 @@ public: Boolean that is true if there is at least one statement in the transaction cache. */ - bool at_least_one_stmt; + bool at_least_one_stmt_committed; bool incident; private: @@ -1539,9 +1542,10 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) { Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, TRUE, 0); error= binlog_end_trans(thd, trx_data, &qev, all); - goto end; } + trx_data->at_least_one_stmt_committed = my_b_tell(&trx_data->trans_log) > 0; + end: if (!all) trx_data->before_stmt_pos = MY_OFF_T_UNDEF; // part of the stmt commit @@ -1608,15 +1612,18 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) { /* We flush the cache with a rollback, wrapped in a beging/rollback if: - . aborting a transcation that modified a non-transactional table or; + . aborting a transaction that modified a non-transactional table; . aborting a statement that modified both transactional and - non-transctional tables but which is not in the boundaries of any - transaction; + non-transactional tables but which is not in the boundaries of any + transaction or there was no early change; . the OPTION_KEEP_LOG is activate. */ if ((all && thd->transaction.all.modified_non_trans_table) || (!all && thd->transaction.stmt.modified_non_trans_table && !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))) || + (!all && thd->transaction.stmt.modified_non_trans_table && + !trx_data->at_least_one_stmt_committed && + thd->current_stmt_binlog_row_based) || ((thd->options & OPTION_KEEP_LOG))) { Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, TRUE, 0); From b31e0c9a48a1e4de68353c562a3e5ea34ed10c20 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Tue, 6 Oct 2009 01:54:00 +0100 Subject: [PATCH 080/146] BUG#47678 Changes to n-tables that happen early in a trans. are only flushed upon commit Let - T be a transactional table and N non-transactional table. - B be begin, C commit and R rollback. - N be a statement that accesses and changes only N-tables. - T be a statement that accesses and changes only T-tables. In RBR, changes to N-tables that happen early in a transaction are not immediately flushed upon committing a statement. This behavior may, however, break consistency in the presence of concurrency since changes done to N-tables become immediately visible to other connections. To fix this problem, we do the following: . B N N T C would log - B N C B N C B T C. . B N N T R would log - B N C B N C B T R. Note that we are not preserving history from the master as we are introducing a commit that never happened. However, this seems to be more acceptable than the possibility of breaking consistency in the presence of concurrency. --- .../binlog_failure_mixing_engines.test | 102 ++++++++++- ...binlog_mixed_failure_mixing_engines.result | 172 ++++++++++++++++++ .../binlog_row_failure_mixing_engines.result | 172 ++++++++++++++++++ .../r/binlog_row_mix_innodb_myisam.result | 22 ++- .../suite/rpl/r/rpl_row_create_table.result | 4 +- sql/log.cc | 7 +- 6 files changed, 469 insertions(+), 10 deletions(-) diff --git a/mysql-test/extra/binlog_tests/binlog_failure_mixing_engines.test b/mysql-test/extra/binlog_tests/binlog_failure_mixing_engines.test index 26ae8f625a9..54f3c538c79 100644 --- a/mysql-test/extra/binlog_tests/binlog_failure_mixing_engines.test +++ b/mysql-test/extra/binlog_tests/binlog_failure_mixing_engines.test @@ -34,13 +34,25 @@ # simply roll the transaction back as this would undo any uncommitted changes # on T-tables. # -# We check one more case. INSERT M...SELECT* which produces the following +# We check two more cases. First, INSERT...SELECT* which produces the following # results: # # 1. B T INSERT M...SELECT* C" with an error in INSERT M...SELECT* generates in # the binlog the following entries: "Nothing". # 2. B INSERT M...SELECT* C" with an error in INSERT M...SELECT* generates in # the binlog the following entries: B INSERT M...SELECT* R. +# +# Finally, we also check if any N statement that happens early in a transaction +# (i.e. before any T or M statement) is written to the binary log outside the +# boundaries of the transaction. In particular, we expect the following +# behavior: +# +# 1. B N N T C would generate in the binlog B N C B N C B T C. +# 2. B N N T R would generate in the binlog B N C B N C B T R. +# 3. B N* N* T C would generate in the binlog B N R B N R B T C. +# 4. B N* N* T R would generate in the binlog B N R B N R B T R. +# 5. B N N T N T C would generate in the binlog B N C B N C B T N T C. +# 6. B N N T N T R would generate in the binlog the B N C B N C B T N T R. # # Such issues do not happen in SBR. In RBR and MBR, a full-fledged fix will be # pushed after the WL#2687. @@ -190,6 +202,94 @@ INSERT INTO nt_2(a, b) SELECT USER(), b FROM nt_1; COMMIT; --source include/show_binlog_events.inc +--echo +--echo +--echo +--echo *** "B N N T C" generates in the binlog the "B N C B N C B T C" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +TRUNCATE TABLE nt_1; +TRUNCATE TABLE tt_2; +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 1); +INSERT INTO nt_1 VALUES (USER(), 2); +INSERT INTO tt_2 VALUES (USER(), 3); +COMMIT; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B N N T R" generates in the binlog the "B N C B N C B T R" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 4); +INSERT INTO nt_1 VALUES (USER(), 5); +INSERT INTO tt_2 VALUES (USER(), 6); +ROLLBACK; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B N* N* T C" with error in N* generates in the binlog the "B N R B N R B T C" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +BEGIN; +--error ER_DUP_ENTRY +INSERT INTO nt_1 VALUES (USER(), 7), (USER(), 1); +--error ER_DUP_ENTRY +INSERT INTO nt_1 VALUES (USER(), 8), (USER(), 1); +INSERT INTO tt_2 VALUES (USER(), 9); +COMMIT; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B N* N* T R" with error in N* generates in the binlog the "B N R B N R B T R" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +BEGIN; +--error ER_DUP_ENTRY +INSERT INTO nt_1 VALUES (USER(), 10), (USER(), 1); +--error ER_DUP_ENTRY +INSERT INTO nt_1 VALUES (USER(), 11), (USER(), 1); +INSERT INTO tt_2 VALUES (USER(), 12); +ROLLBACK; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B N N T N T C" generates in the binlog the "B N C B N C B T N T C" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 13); +INSERT INTO nt_1 VALUES (USER(), 14); +INSERT INTO tt_2 VALUES (USER(), 15); +INSERT INTO nt_1 VALUES (USER(), 16); +INSERT INTO tt_2 VALUES (USER(), 17); +COMMIT; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B N N T N T R" generates in the binlog the "B N C B N C B T N T R" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 18); +INSERT INTO nt_1 VALUES (USER(), 19); +INSERT INTO tt_2 VALUES (USER(), 20); +INSERT INTO nt_1 VALUES (USER(), 21); +INSERT INTO tt_2 VALUES (USER(), 22); +ROLLBACK; +--source include/show_binlog_events.inc + --echo ################################################################################### --echo # CLEAN --echo ################################################################################### diff --git a/mysql-test/suite/binlog/r/binlog_mixed_failure_mixing_engines.result b/mysql-test/suite/binlog/r/binlog_mixed_failure_mixing_engines.result index 16a2ce50655..dfc08d76a6a 100644 --- a/mysql-test/suite/binlog/r/binlog_mixed_failure_mixing_engines.result +++ b/mysql-test/suite/binlog/r/binlog_mixed_failure_mixing_engines.result @@ -225,6 +225,178 @@ master-bin.000001 # Write_rows # # table_id: # master-bin.000001 # Write_rows # # table_id: # master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # ROLLBACK + + + +*** "B N N T C" generates in the binlog the "B N C B N C B T C" entries + +TRUNCATE TABLE nt_1; +TRUNCATE TABLE tt_2; +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 1); +INSERT INTO nt_1 VALUES (USER(), 2); +INSERT INTO tt_2 VALUES (USER(), 3); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE nt_1 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE tt_2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B N N T R" generates in the binlog the "B N C B N C B T R" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 4); +INSERT INTO nt_1 VALUES (USER(), 5); +INSERT INTO tt_2 VALUES (USER(), 6); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK + + + +*** "B N* N* T C" with error in N* generates in the binlog the "B N R B N R B T C" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 7), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO nt_1 VALUES (USER(), 8), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO tt_2 VALUES (USER(), 9); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B N* N* T R" with error in N* generates in the binlog the "B N R B N R B T R" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 10), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO nt_1 VALUES (USER(), 11), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO tt_2 VALUES (USER(), 12); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK + + + +*** "B N N T N T C" generates in the binlog the "B N C B N C B T N T C" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 13); +INSERT INTO nt_1 VALUES (USER(), 14); +INSERT INTO tt_2 VALUES (USER(), 15); +INSERT INTO nt_1 VALUES (USER(), 16); +INSERT INTO tt_2 VALUES (USER(), 17); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B N N T N T R" generates in the binlog the "B N C B N C B T N T R" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 18); +INSERT INTO nt_1 VALUES (USER(), 19); +INSERT INTO tt_2 VALUES (USER(), 20); +INSERT INTO nt_1 VALUES (USER(), 21); +INSERT INTO tt_2 VALUES (USER(), 22); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK ################################################################################### # CLEAN ################################################################################### diff --git a/mysql-test/suite/binlog/r/binlog_row_failure_mixing_engines.result b/mysql-test/suite/binlog/r/binlog_row_failure_mixing_engines.result index 85a13af3957..45c8640d3e3 100644 --- a/mysql-test/suite/binlog/r/binlog_row_failure_mixing_engines.result +++ b/mysql-test/suite/binlog/r/binlog_row_failure_mixing_engines.result @@ -259,6 +259,178 @@ master-bin.000001 # Write_rows # # table_id: # master-bin.000001 # Write_rows # # table_id: # master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # ROLLBACK + + + +*** "B N N T C" generates in the binlog the "B N C B N C B T C" entries + +TRUNCATE TABLE nt_1; +TRUNCATE TABLE tt_2; +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 1); +INSERT INTO nt_1 VALUES (USER(), 2); +INSERT INTO tt_2 VALUES (USER(), 3); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE nt_1 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE tt_2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B N N T R" generates in the binlog the "B N C B N C B T R" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 4); +INSERT INTO nt_1 VALUES (USER(), 5); +INSERT INTO tt_2 VALUES (USER(), 6); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK + + + +*** "B N* N* T C" with error in N* generates in the binlog the "B N R B N R B T C" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 7), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO nt_1 VALUES (USER(), 8), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO tt_2 VALUES (USER(), 9); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B N* N* T R" with error in N* generates in the binlog the "B N R B N R B T R" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 10), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO nt_1 VALUES (USER(), 11), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO tt_2 VALUES (USER(), 12); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK + + + +*** "B N N T N T C" generates in the binlog the "B N C B N C B T N T C" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 13); +INSERT INTO nt_1 VALUES (USER(), 14); +INSERT INTO tt_2 VALUES (USER(), 15); +INSERT INTO nt_1 VALUES (USER(), 16); +INSERT INTO tt_2 VALUES (USER(), 17); +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B N N T N T R" generates in the binlog the "B N C B N C B T N T R" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 18); +INSERT INTO nt_1 VALUES (USER(), 19); +INSERT INTO tt_2 VALUES (USER(), 20); +INSERT INTO nt_1 VALUES (USER(), 21); +INSERT INTO tt_2 VALUES (USER(), 22); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK ################################################################################### # CLEAN ################################################################################### diff --git a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result index 9ae5121f618..76105005367 100644 --- a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result @@ -133,6 +133,10 @@ master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT insert into t1 values(11); commit; show binlog events from ; @@ -144,6 +148,8 @@ master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t2) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Xid # # COMMIT /* XID */ @@ -272,6 +278,10 @@ master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; drop table t1,t2 master-bin.000001 # Query # # use `test`; create table t0 (n int) master-bin.000001 # Query # # BEGIN @@ -372,7 +382,7 @@ master-bin.000001 # Query # # use `test`; DROP TABLE if exists t2 master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t2 master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (a int, b int, primary key (a)) engine=innodb master-bin.000001 # Query # # BEGIN @@ -390,9 +400,7 @@ master-bin.000001 # Query # # use `test`; DROP TABLE t2 master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F @@ -400,7 +408,11 @@ master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; TRUNCATE table t2 master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) diff --git a/mysql-test/suite/rpl/r/rpl_row_create_table.result b/mysql-test/suite/rpl/r/rpl_row_create_table.result index 5bed9106009..b7122adea2a 100644 --- a/mysql-test/suite/rpl/r/rpl_row_create_table.result +++ b/mysql-test/suite/rpl/r/rpl_row_create_table.result @@ -176,7 +176,7 @@ Log_name Pos Event_type Server_id End_log_pos Info # 106 Query # 174 BEGIN # 174 Table_map # 216 table_id: # (test.t7) # 216 Write_rows # 272 table_id: # flags: STMT_END_F -# 272 Query # 343 ROLLBACK +# 272 Query # 341 COMMIT SELECT * FROM t7 ORDER BY a,b; a b 1 2 @@ -327,7 +327,7 @@ Log_name Pos Event_type Server_id End_log_pos Info # 1329 Query # 1397 BEGIN # 1397 Table_map # 1438 table_id: # (test.t1) # 1438 Write_rows # 1482 table_id: # flags: STMT_END_F -# 1482 Query # 1553 ROLLBACK +# 1482 Query # 1551 COMMIT SHOW TABLES; Tables_in_test t1 diff --git a/sql/log.cc b/sql/log.cc index 9c733636bad..e8366c47863 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1275,7 +1275,7 @@ static bool stmt_has_updated_trans_table(THD *thd) { Ha_trx_info *ha_info; - for (ha_info= thd->transaction.stmt.ha_list; ha_info; ha_info= ha_info->next()) + for (ha_info= thd->transaction.stmt.ha_list; ha_info && ha_info->is_started(); ha_info= ha_info->next()) { if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton) return (TRUE); @@ -1538,7 +1538,10 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) YESNO(in_transaction), YESNO(thd->transaction.all.modified_non_trans_table), YESNO(thd->transaction.stmt.modified_non_trans_table))); - if (!in_transaction || all) + if (!in_transaction || all || + (!all && !trx_data->at_least_one_stmt_committed && + !stmt_has_updated_trans_table(thd) && + thd->transaction.stmt.modified_non_trans_table)) { Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, TRUE, 0); error= binlog_end_trans(thd, trx_data, &qev, all); From bf1b7b7dedb125907454c79b7a28610a20ad826b Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 6 Oct 2009 10:32:02 +0300 Subject: [PATCH 081/146] version update --- .bzr-mysql/default.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index 557df1b1ffe..f79c1cd6319 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@lists.mysql.com" post_push_to = "commits@lists.mysql.com" -tree_name = "mysql-5.0-bugteam" +tree_name = "mysql-5.0" From dfed28e750fabdc22a8821e54dc366b7bf019609 Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Tue, 6 Oct 2009 09:38:44 +0200 Subject: [PATCH 082/146] Bug#47768 pthread_cond_timedwait() is broken on windows The pthread_cond_wait implementations for windows might dead lock in some rare circumstances. 1) One thread (I) enter a timed wait and at a point in time ends up after mutex unlock and before WaitForMultipleObjects(...) 2) Another thread (II) enters pthread_cond_broadcast. Grabs the mutex and discovers one waiter. It set the broadcast event and closes the broadcast gate then unlocks the mutex. 3) A third thread (III) issues a pthread_cond_signal. It grabs the mutex, discovers one waiter, sets the signal event then unlock the mutex. 4) The first threads (I) enters WaitForMultipleObjects and finds out that the signal object is in a signalled state and exits the wait. 5) Thread (I) grabs the mutex and checks result status. The number of waiters is decreased and becomes equal to 0. The event returned was a signal event so the broadcast gate isn't opened. The mutex is released. 6) Thread (II) issues a new broadcast. The mutex is acquired but the number of waiters are 0 hence the broadcast gate remains closed. 7) Thread (I) enters the wait again but is blocked by the broadcast gate. This fix resolves the above issue by always resetting broadcast gate when there are no more waiters in th queue. --- mysys/my_wincond.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/my_wincond.c b/mysys/my_wincond.c index 353b2fced4e..72a8d65bf1f 100644 --- a/mysys/my_wincond.c +++ b/mysys/my_wincond.c @@ -126,7 +126,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, EnterCriticalSection(&cond->lock_waiting); cond->waiting--; - if (cond->waiting == 0 && result == (WAIT_OBJECT_0+BROADCAST)) + if (cond->waiting == 0) { /* We're the last waiter to be notified or to stop waiting, so From b64dbeed6ec47ae03ccbf8d492265af071cbead4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Bl=C3=A5udd?= Date: Tue, 6 Oct 2009 13:04:51 +0200 Subject: [PATCH 083/146] Bug#47857 strip_sp function in mysys/mf_strip.c never used and cause name clash - Remove mf_strip.c and the declaration of 'strip_sp' --- include/my_sys.h | 1 - mysys/CMakeLists.txt | 2 +- mysys/Makefile.am | 2 +- mysys/mf_strip.c | 45 -------------------------------------------- sql/mysql_priv.h.pp | 1 - 5 files changed, 2 insertions(+), 49 deletions(-) delete mode 100644 mysys/mf_strip.c diff --git a/include/my_sys.h b/include/my_sys.h index 166133251bc..b4aac3a17bd 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -720,7 +720,6 @@ extern int wild_compare(const char *str,const char *wildstr, extern WF_PACK *wf_comp(char * str); extern int wf_test(struct wild_file_pack *wf_pack,const char *name); extern void wf_end(struct wild_file_pack *buffer); -extern size_t strip_sp(char * str); extern my_bool array_append_string_unique(const char *str, const char **array, size_t size); extern void get_date(char * to,int timeflag,time_t use_time); diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 545278485d1..7afb800643c 100755 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -29,7 +29,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c default_ errors.c hash.c list.c md5.c mf_brkhant.c mf_cache.c mf_dirname.c mf_fn_ext.c mf_format.c mf_getdate.c mf_iocache.c mf_iocache2.c mf_keycache.c mf_keycaches.c mf_loadpath.c mf_pack.c mf_path.c mf_qsort.c mf_qsort2.c - mf_radix.c mf_same.c mf_sort.c mf_soundex.c mf_strip.c mf_arr_appstr.c mf_tempdir.c + mf_radix.c mf_same.c mf_sort.c mf_soundex.c mf_arr_appstr.c mf_tempdir.c mf_tempfile.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_access.c my_aes.c my_alarm.c my_alloc.c my_append.c my_bit.c my_bitmap.c my_chsize.c my_clock.c my_compress.c my_conio.c my_copy.c my_crc32.c my_create.c my_delete.c diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 16f0e1a9759..19017330654 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -35,7 +35,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ my_error.c errors.c my_div.c my_messnc.c \ mf_format.c mf_same.c mf_dirname.c mf_fn_ext.c \ my_symlink.c my_symlink2.c \ - mf_pack.c mf_unixpath.c mf_strip.c mf_arr_appstr.c \ + mf_pack.c mf_unixpath.c mf_arr_appstr.c \ mf_wcomp.c mf_wfile.c my_gethwaddr.c \ mf_qsort.c mf_qsort2.c mf_sort.c \ ptr_cmp.c mf_radix.c queues.c my_getncpus.c \ diff --git a/mysys/mf_strip.c b/mysys/mf_strip.c deleted file mode 100644 index b33620b1b2d..00000000000 --- a/mysys/mf_strip.c +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - 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 Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* T|mmer en str{ng p{ slut_space */ - -#include "mysys_priv.h" - -/* - strip_sp(char * str) - Strips end-space from string and returns new length. -*/ - -size_t strip_sp(register char * str) -{ - reg2 char * found; - reg3 char * start; - - start=found=str; - - while (*str) - { - if (*str != ' ') - { - while (*++str && *str != ' ') {}; - if (!*str) - return (size_t) (str-start); /* Return stringlength */ - } - found=str; - while (*++str == ' ') {}; - } - *found= '\0'; /* Stripp at first space */ - return (size_t) (found-start); -} /* strip_sp */ diff --git a/sql/mysql_priv.h.pp b/sql/mysql_priv.h.pp index 8bb31f64587..d874a2591d1 100644 --- a/sql/mysql_priv.h.pp +++ b/sql/mysql_priv.h.pp @@ -773,7 +773,6 @@ extern int wild_compare(const char *str,const char *wildstr, extern WF_PACK *wf_comp(char * str); extern int wf_test(struct wild_file_pack *wf_pack,const char *name); extern void wf_end(struct wild_file_pack *buffer); -extern size_t strip_sp(char * str); extern my_bool array_append_string_unique(const char *str, const char **array, size_t size); extern void get_date(char * to,int timeflag,time_t use_time); From a611e2eba1d0288849c191ad19b4627a38770277 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 6 Oct 2009 14:37:37 +0200 Subject: [PATCH 084/146] merge of 47383 from 5.1-mtr --- mysql-test/lib/mtr_cases.pm | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 84253ddc5a6..ebb330396be 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -69,6 +69,10 @@ require "mtr_misc.pl"; my $do_test_reg; my $skip_test_reg; +# Related to adding InnoDB plugin combinations +my $lib_innodb_plugin; +my $do_innodb_plugin; + # If "Quick collect", set to 1 once a test to run has been found. my $some_test_found; @@ -103,6 +107,17 @@ sub collect_test_cases ($$) { $do_test_reg= init_pattern($do_test, "--do-test"); $skip_test_reg= init_pattern($skip_test, "--skip-test"); + $lib_innodb_plugin= + my_find_file($::basedir, + ["storage/innodb_plugin", "storage/innodb_plugin/.libs", + "lib/mysql/plugin", "lib/plugin"], + ["ha_innodb_plugin.dll", "ha_innodb_plugin.so", + "ha_innodb_plugin.sl"], + NOT_REQUIRED); + $do_innodb_plugin= ($::mysql_version_id >= 50100 && + !(IS_WINDOWS && $::opt_embedded_server) && + $lib_innodb_plugin); + foreach my $suite (split(",", $suites)) { push(@$cases, collect_one_suite($suite, $opt_cases)); @@ -484,20 +499,16 @@ sub collect_one_suite($) # ---------------------------------------------------------------------- # Testing InnoDB plugin. # ---------------------------------------------------------------------- - my $lib_innodb_plugin= - mtr_file_exists(::vs_config_dirs('storage/innodb_plugin', 'ha_innodb_plugin.dll'), - "$::basedir/storage/innodb_plugin/.libs/ha_innodb_plugin.so", - "$::basedir/lib/mysql/plugin/ha_innodb_plugin.so", - "$::basedir/lib/mysql/plugin/ha_innodb_plugin.dll"); - if ($::mysql_version_id >= 50100 && !(IS_WINDOWS && $::opt_embedded_server) && - $lib_innodb_plugin) + if ($do_innodb_plugin) { my @new_cases; my $sep= (IS_WINDOWS) ? ';' : ':'; foreach my $test (@cases) { - next if ($test->{'skip'} || !$test->{'innodb_test'}); + next if (!$test->{'innodb_test'}); + # If skipped due to no builtin innodb, we can still run it with plugin + next if ($test->{'skip'} && $test->{comment} ne "No innodb support"); # Exceptions next if ($test->{'name'} eq 'main.innodb'); # Failed with wrong errno (fk) next if ($test->{'name'} eq 'main.index_merge_innodb'); # Explain diff @@ -521,7 +532,7 @@ sub collect_one_suite($) } else { - $new_test->{$key}= $value; + $new_test->{$key}= $value unless ($key eq 'skip'); } } my $plugin_filename= basename($lib_innodb_plugin); @@ -981,8 +992,11 @@ sub collect_one_test_case { { # innodb is not supported, skip it $tinfo->{'skip'}= 1; + # This comment is checked for running with innodb plugin (see above), + # please keep that in mind if changing the text. $tinfo->{'comment'}= "No innodb support"; - return $tinfo; + # But continue processing if we may run it with innodb plugin + return $tinfo unless $do_innodb_plugin; } } else From 0e8c86f4263be0ae55607437c7276721de6a8fe9 Mon Sep 17 00:00:00 2001 From: "hery.ramilison@sun.com" <> Date: Tue, 6 Oct 2009 19:37:08 +0200 Subject: [PATCH 085/146] Raise version number after cloning 5.1.40 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 3e43a5f5779..d87adf395ed 100644 --- a/configure.in +++ b/configure.in @@ -10,7 +10,7 @@ AC_CANONICAL_SYSTEM # # When changing major version number please also check switch statement # in mysqlbinlog::check_master_version(). -AM_INIT_AUTOMAKE(mysql, 5.1.40) +AM_INIT_AUTOMAKE(mysql, 5.1.41) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10 From 5faf23bf55ee7a7110514cf0cc7aeab96dc1013d Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 7 Oct 2009 18:03:42 +0300 Subject: [PATCH 086/146] Bug #43029: FORCE INDEX FOR ORDER BY is ignored when join buffering is used FORCE INDEX FOR ORDER BY now prevents the optimizer from using join buffering. As a result the optimizer can use indexed access on the first table and doesn't need to sort the complete resultset at the end of the statement. --- mysql-test/r/order_by.result | 31 +++++++++++++++++++++++++++++++ mysql-test/t/order_by.test | 32 ++++++++++++++++++++++++++++++++ sql/sql_base.cc | 6 ++++-- sql/sql_parse.cc | 1 + sql/sql_select.cc | 19 ++++++++++++++----- sql/sql_select.h | 2 ++ sql/table.cc | 25 ++++++++++++++++++++----- sql/table.h | 12 ++++++++++++ 8 files changed, 116 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 306fce1f3c2..0c72f816c21 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -1557,3 +1557,34 @@ a 2001 1991 DROP TABLE t1; +# +# Bug #43029: FORCE INDEX FOR ORDER BY is ignored when join buffering +# is used +# +CREATE TABLE t1 (a INT, b INT, KEY (a)); +INSERT INTO t1 VALUES (0, NULL), (1, NULL), (2, NULL), (3, NULL); +INSERT INTO t1 SELECT a+4, b FROM t1; +INSERT INTO t1 SELECT a+8, b FROM t1; +CREATE TABLE t2 (a INT, b INT); +INSERT INTO t2 VALUES (0,NULL), (1,NULL), (2,NULL), (3,NULL), (4,NULL); +INSERT INTO t2 SELECT a+4, b FROM t2; +# shouldn't have "using filesort" +EXPLAIN +SELECT * FROM t1 FORCE INDEX FOR ORDER BY (a), t2 WHERE t1.a < 2 ORDER BY t1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 2 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 10 +# should have "using filesort" +EXPLAIN +SELECT * FROM t1 USE INDEX FOR ORDER BY (a), t2 WHERE t1.a < 2 ORDER BY t1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 2 Using where; Using temporary; Using filesort +1 SIMPLE t2 ALL NULL NULL NULL NULL 10 Using join buffer +# should have "using filesort" +EXPLAIN +SELECT * FROM t1 FORCE INDEX FOR JOIN (a), t2 WHERE t1.a < 2 ORDER BY t1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 2 Using where; Using temporary; Using filesort +1 SIMPLE t2 ALL NULL NULL NULL NULL 10 Using join buffer +DROP TABLE t1, t2; +End of 5.1 tests diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index cca1e3209cc..ac2bbaaeeac 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -1402,3 +1402,35 @@ SELECT DISTINCT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 0, 9; SELECT DISTINCT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 0, 9; DROP TABLE t1; + +--echo # +--echo # Bug #43029: FORCE INDEX FOR ORDER BY is ignored when join buffering +--echo # is used +--echo # + +CREATE TABLE t1 (a INT, b INT, KEY (a)); + +INSERT INTO t1 VALUES (0, NULL), (1, NULL), (2, NULL), (3, NULL); +INSERT INTO t1 SELECT a+4, b FROM t1; +INSERT INTO t1 SELECT a+8, b FROM t1; + +CREATE TABLE t2 (a INT, b INT); + +INSERT INTO t2 VALUES (0,NULL), (1,NULL), (2,NULL), (3,NULL), (4,NULL); +INSERT INTO t2 SELECT a+4, b FROM t2; + +--echo # shouldn't have "using filesort" +EXPLAIN +SELECT * FROM t1 FORCE INDEX FOR ORDER BY (a), t2 WHERE t1.a < 2 ORDER BY t1.a; + +--echo # should have "using filesort" +EXPLAIN +SELECT * FROM t1 USE INDEX FOR ORDER BY (a), t2 WHERE t1.a < 2 ORDER BY t1.a; + +--echo # should have "using filesort" +EXPLAIN +SELECT * FROM t1 FORCE INDEX FOR JOIN (a), t2 WHERE t1.a < 2 ORDER BY t1.a; + +DROP TABLE t1, t2; + +--echo End of 5.1 tests diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d1e96fcdbb3..e706bd04ea6 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2305,7 +2305,8 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in) table->tablenr=thd->current_tablenr++; table->used_fields=0; table->const_table=0; - table->null_row= table->maybe_null= table->force_index= 0; + table->null_row= table->maybe_null= 0; + table->force_index= table->force_index_order= table->force_index_group= 0; table->status=STATUS_NO_RECORD; DBUG_RETURN(FALSE); } @@ -2963,7 +2964,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table->tablenr=thd->current_tablenr++; table->used_fields=0; table->const_table=0; - table->null_row= table->maybe_null= table->force_index= 0; + table->null_row= table->maybe_null= 0; + table->force_index= table->force_index_order= table->force_index_group= 0; table->status=STATUS_NO_RECORD; table->insert_values= 0; table->fulltext_searched= 0; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 83ef525e3eb..27688e41d4f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6258,6 +6258,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->table_name_length=table->table.length; ptr->lock_type= lock_type; ptr->updating= test(table_options & TL_OPTION_UPDATING); + /* TODO: remove TL_OPTION_FORCE_INDEX as it looks like it's not used */ ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX); ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES); ptr->derived= table->sel; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3f1432914a0..9dacb2c2ce4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1231,13 +1231,22 @@ JOIN::optimize() (!group_list && tmp_table_param.sum_func_count)) order=0; - // Can't use sort on head table if using row cache + // Can't use sort on head table if using join buffering if (full_join) { - if (group_list) - simple_group=0; - if (order) - simple_order=0; + TABLE *stable= (sort_by_table == (TABLE *) 1 ? + join_tab[const_tables].table : sort_by_table); + /* + FORCE INDEX FOR ORDER BY can be used to prevent join buffering when + sorting on the first table. + */ + if (!stable || !stable->force_index_order) + { + if (group_list) + simple_group= 0; + if (order) + simple_order= 0; + } } /* diff --git a/sql/sql_select.h b/sql/sql_select.h index a0366d47149..3f06b402638 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -357,6 +357,8 @@ public: simple_xxxxx is set if ORDER/GROUP BY doesn't include any references to other tables than the first non-constant table in the JOIN. It's also set if ORDER/GROUP BY is empty. + Used for deciding for or against using a temporary table to compute + GROUP/ORDER BY. */ bool simple_order, simple_group; /** diff --git a/sql/table.cc b/sql/table.cc index 04f2a3fbcf8..d2538eb4d59 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4637,7 +4637,8 @@ Item_subselect *TABLE_LIST::containing_subselect() (TABLE_LIST::index_hints). Using the information in this tagged list this function sets the members st_table::keys_in_use_for_query, st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by, - st_table::force_index and st_table::covering_keys. + st_table::force_index, st_table::force_index_order, + st_table::force_index_group and st_table::covering_keys. Current implementation of the runtime does not allow mixing FORCE INDEX and USE INDEX, so this is checked here. Then the FORCE INDEX list @@ -4765,14 +4766,28 @@ bool TABLE_LIST::process_index_hints(TABLE *tbl) } /* process FORCE INDEX as USE INDEX with a flag */ + if (!index_order[INDEX_HINT_FORCE].is_clear_all()) + { + tbl->force_index_order= TRUE; + index_order[INDEX_HINT_USE].merge(index_order[INDEX_HINT_FORCE]); + } + + if (!index_group[INDEX_HINT_FORCE].is_clear_all()) + { + tbl->force_index_group= TRUE; + index_group[INDEX_HINT_USE].merge(index_group[INDEX_HINT_FORCE]); + } + + /* + TODO: get rid of tbl->force_index (on if any FORCE INDEX is specified) and + create tbl->force_index_join instead. + Then use the correct force_index_XX instead of the global one. + */ if (!index_join[INDEX_HINT_FORCE].is_clear_all() || - !index_order[INDEX_HINT_FORCE].is_clear_all() || - !index_group[INDEX_HINT_FORCE].is_clear_all()) + tbl->force_index_group || tbl->force_index_order) { tbl->force_index= TRUE; index_join[INDEX_HINT_USE].merge(index_join[INDEX_HINT_FORCE]); - index_order[INDEX_HINT_USE].merge(index_order[INDEX_HINT_FORCE]); - index_group[INDEX_HINT_USE].merge(index_group[INDEX_HINT_FORCE]); } /* apply USE INDEX */ diff --git a/sql/table.h b/sql/table.h index 40372fa91cf..e4a382c799f 100644 --- a/sql/table.h +++ b/sql/table.h @@ -752,6 +752,18 @@ struct st_table { bytes, it would take up 4. */ my_bool force_index; + + /** + Flag set when the statement contains FORCE INDEX FOR ORDER BY + See TABLE_LIST::process_index_hints(). + */ + my_bool force_index_order; + + /** + Flag set when the statement contains FORCE INDEX FOR GROUP BY + See TABLE_LIST::process_index_hints(). + */ + my_bool force_index_group; my_bool distinct,const_table,no_rows; /** From e4a45e2666a44c14a8949ff251fd8a7603412ad8 Mon Sep 17 00:00:00 2001 From: Satya B Date: Thu, 8 Oct 2009 14:43:16 +0530 Subject: [PATCH 087/146] Applying InnoDB Plugin 1.0.5 snapshot , part 1 From revision r5537 to r5636 r5527 is already applied before Detailed revision comments: For HotBackup builds we don't want to hide the symbols. r5537 | vasil | 2009-07-21 04:31:26 -0500 (Tue, 21 Jul 2009) | 5 lines branches/zip: Fixups in ChangeLog: sort filenames alphabetically and wrap to 78 chars per line. r5539 | vasil | 2009-07-21 05:28:27 -0500 (Tue, 21 Jul 2009) | 4 lines branches/zip: Add a test program to check whether the PAUSE instruction is available. r5625 | vasil | 2009-08-04 00:52:48 -0500 (Tue, 04 Aug 2009) | 32 lines branches/zip: Merge 5518:5622 from branches/5.1, resolving conflict in r5622 (after resolving the conflict Makefile.am was not changed so I have made a dummy change so I can commit and thus record that branches/5.1 has been merged in branches/zip up to 5622): ------------------------------------------------------------------------ r5622 | vasil | 2009-08-03 15:27:00 +0300 (Mon, 03 Aug 2009) | 20 lines Changed paths: M /branches/5.1/Makefile.am branches/5.1: Merge a change from MySQL: ------------------------------------------------------------ revno: 2988 committer: Satya B branch nick: mysql-5.1-bugteam timestamp: Wed 2009-07-01 11:06:05 +0530 message: Fix build failure after applying Innodb snapshot 5.1-ss5282 After applying Innodb snapshot 5.1-ss5282, build was broken because of missing header file. Adding the header file to Makefile.am after informing the innodb developers. modified: storage/innobase/Makefile.am ------------------------------------------------------------------------ r5626 | vasil | 2009-08-04 00:53:31 -0500 (Tue, 04 Aug 2009) | 4 lines branches/zip: Revert the dummy change from c5625. r5629 | marko | 2009-08-04 06:42:44 -0500 (Tue, 04 Aug 2009) | 1 line branches/zip: mysql-test: Pass MTR's internal checks. r5635 | marko | 2009-08-05 06:06:55 -0500 (Wed, 05 Aug 2009) | 2 lines branches/zip: Replace with NUMBER in some comments, to avoid problems with Doxygen XML output. r5636 | marko | 2009-08-05 07:27:30 -0500 (Wed, 05 Aug 2009) | 2 lines branches/zip: lock_rec_validate_page(): Add the parameter zip_size. This should help track down Mantis Issue #289. --- mysql-test/t/innodb_bug34300.test | 1 + storage/innodb_plugin/ChangeLog | 22 ++++++------- storage/innodb_plugin/dict/dict0crea.c | 2 +- storage/innodb_plugin/include/dict0crea.h | 2 +- storage/innodb_plugin/lock/lock0lock.c | 14 ++++++-- .../mysql-test/innodb_bug34300.test | 2 ++ storage/innodb_plugin/row/row0mysql.c | 2 +- storage/innodb_plugin/ut/ut0auxconf_pause.c | 32 +++++++++++++++++++ 8 files changed, 60 insertions(+), 17 deletions(-) diff --git a/mysql-test/t/innodb_bug34300.test b/mysql-test/t/innodb_bug34300.test index 432ddd03547..ecec381da14 100644 --- a/mysql-test/t/innodb_bug34300.test +++ b/mysql-test/t/innodb_bug34300.test @@ -9,6 +9,7 @@ -- disable_result_log # set packet size and reconnect +let $max_packet=`select @@global.max_allowed_packet`; SET @@global.max_allowed_packet=16777216; --connect (newconn, localhost, root,,) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 2b04c06f0e8..593a9fa3418 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,7 +1,6 @@ 2009-07-20 The InnoDB Team - * buf/buf0rea.c, handler/ha_innodb.cc, include/srv0srv.h, - srv/srv0srv.c: + * handler/ha_innodb.cc, buf/buf0rea.c, include/srv0srv.h, srv/srv0srv.c Change the read ahead parameter name to innodb_read_ahead_threshold. Change the meaning of this parameter to signify the number of pages that must be sequentially accessed for InnoDB to trigger a readahead @@ -16,8 +15,8 @@ * include/univ.i: Support inlining of functions and prefetch with Sun Studio. - These changes are based on contribution from Sun Microsystems Inc. - under a BSD license. + These changes are based on contribution from + Sun Microsystems Inc. under a BSD license. 2009-07-14 The InnoDB Team @@ -40,9 +39,9 @@ 2009-07-08 The InnoDB Team - * buf/buf0flu.c, handler/ha_innodb.cc, include/buf0flu.h, - include/log0log.h, include/log0log.ic, include/srv0srv.h, - srv/srv0srv.c: + * srv/srv0srv.c, buf/buf0flu.c, handler/ha_innodb.cc, + include/srv0srv.h, include/log0log.ic, include/buf0flu.h, + include/log0log.h: Implement the adaptive flushing of dirty pages, which uses a heuristics based flushing rate of dirty pages to avoid IO bursts at checkpoint. Expose new configure knob @@ -51,8 +50,8 @@ 2009-07-07 The InnoDB Team - * handler/ha_innodb.cc, include/srv0srv.h, log/log0log.c, - srv/srv0srv.c: + * srv/srv0srv.c, handler/ha_innodb.cc, log/log0log.c, + include/srv0srv.h: Implement IO capacity tuning. Expose new configure knob innodb_io_capacity to control the master threads IO rate. The ibuf merge is also changed from synchronous to asynchronous. @@ -89,12 +88,13 @@ * handler/handler0alter.cc: Start the user transaction prebuilt->trx if it was not started - before adding or dropping an index. Without this fix, the + before adding or dropping an index. Without this fix, the table could be locked outside an active transaction. 2009-06-25 The InnoDB Team - * handler/ha_innodb.cc, mysql-test/innodb_bug42101.test, + * handler/ha_innodb.cc, + mysql-test/innodb_bug42101.test, mysql-test/innodb_bug42101.result, mysql-test/innodb_bug42101-nonzero.test, mysql-test/innodb_bug42101-nonzero.result: diff --git a/storage/innodb_plugin/dict/dict0crea.c b/storage/innodb_plugin/dict/dict0crea.c index 7bad4d2057e..96a9bd8152e 100644 --- a/storage/innodb_plugin/dict/dict0crea.c +++ b/storage/innodb_plugin/dict/dict0crea.c @@ -1379,7 +1379,7 @@ dict_create_add_foreign_field_to_dictionary( Add a single foreign key definition to the data dictionary tables in the database. We also generate names to constraints that were not named by the user. A generated constraint has a name of the format -databasename/tablename_ibfk_, where the numbers start from 1, and +databasename/tablename_ibfk_NUMBER, where the numbers start from 1, and are given locally for this table, that is, the number is not global, as in the old format constraints < 4.0.18 it used to be. @return error code or DB_SUCCESS */ diff --git a/storage/innodb_plugin/include/dict0crea.h b/storage/innodb_plugin/include/dict0crea.h index 3107d771d88..cce1246b789 100644 --- a/storage/innodb_plugin/include/dict0crea.h +++ b/storage/innodb_plugin/include/dict0crea.h @@ -110,7 +110,7 @@ dict_create_or_check_foreign_constraint_tables(void); Adds foreign key definitions to data dictionary tables in the database. We look at table->foreign_list, and also generate names to constraints that were not named by the user. A generated constraint has a name of the format -databasename/tablename_ibfk_, where the numbers start from 1, and are +databasename/tablename_ibfk_NUMBER, where the numbers start from 1, and are given locally for this table, that is, the number is not global, as in the old format constraints < 4.0.18 it used to be. @return error code or DB_SUCCESS */ diff --git a/storage/innodb_plugin/lock/lock0lock.c b/storage/innodb_plugin/lock/lock0lock.c index fcd8d268331..23c2ff4740f 100644 --- a/storage/innodb_plugin/lock/lock0lock.c +++ b/storage/innodb_plugin/lock/lock0lock.c @@ -360,6 +360,8 @@ ibool lock_rec_validate_page( /*===================*/ ulint space, /*!< in: space id */ + ulint zip_size,/*!< in: compressed page size in bytes + or 0 for uncompressed pages */ ulint page_no);/*!< in: page number */ /* Define the following in order to enable lock_rec_validate_page() checks. */ @@ -2622,6 +2624,7 @@ lock_move_reorganize_page( #ifdef UNIV_DEBUG_LOCK_VALIDATE ut_ad(lock_rec_validate_page(buf_block_get_space(block), + buf_block_get_zip_size(block), buf_block_get_page_no(block))); #endif } @@ -2711,8 +2714,10 @@ lock_move_rec_list_end( #ifdef UNIV_DEBUG_LOCK_VALIDATE ut_ad(lock_rec_validate_page(buf_block_get_space(block), + buf_block_get_zip_size(block), buf_block_get_page_no(block))); ut_ad(lock_rec_validate_page(buf_block_get_space(new_block), + buf_block_get_zip_size(block), buf_block_get_page_no(new_block))); #endif } @@ -2822,6 +2827,7 @@ lock_move_rec_list_start( #ifdef UNIV_DEBUG_LOCK_VALIDATE ut_ad(lock_rec_validate_page(buf_block_get_space(block), + buf_block_get_zip_size(block), buf_block_get_page_no(block))); #endif } @@ -4684,6 +4690,8 @@ ibool lock_rec_validate_page( /*===================*/ ulint space, /*!< in: space id */ + ulint zip_size,/*!< in: compressed page size in bytes + or 0 for uncompressed pages */ ulint page_no)/*!< in: page number */ { dict_index_t* index; @@ -4694,7 +4702,6 @@ lock_rec_validate_page( ulint nth_lock = 0; ulint nth_bit = 0; ulint i; - ulint zip_size; mtr_t mtr; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; @@ -4705,7 +4712,6 @@ lock_rec_validate_page( mtr_start(&mtr); - zip_size = fil_space_get_zip_size(space); ut_ad(zip_size != ULINT_UNDEFINED); block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, &mtr); buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK); @@ -4840,7 +4846,9 @@ lock_validate(void) lock_mutex_exit_kernel(); - lock_rec_validate_page(space, page_no); + lock_rec_validate_page(space, + fil_space_get_zip_size(space), + page_no); lock_mutex_enter_kernel(); diff --git a/storage/innodb_plugin/mysql-test/innodb_bug34300.test b/storage/innodb_plugin/mysql-test/innodb_bug34300.test index 114bcf98c25..68c385fd72a 100644 --- a/storage/innodb_plugin/mysql-test/innodb_bug34300.test +++ b/storage/innodb_plugin/mysql-test/innodb_bug34300.test @@ -9,6 +9,7 @@ -- disable_result_log # set packet size and reconnect +let $max_packet=`select @@global.max_allowed_packet`; SET @@global.max_allowed_packet=16777216; --connect (newconn, localhost, root,,) @@ -30,3 +31,4 @@ ALTER TABLE bug34300 ADD COLUMN (f10 INT); SELECT f4, f8 FROM bug34300; DROP TABLE bug34300; +EVAL SET @@global.max_allowed_packet=$max_packet; diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index b345bb59624..f7701a701ce 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -3590,7 +3590,7 @@ row_delete_constraint( if ((err == DB_SUCCESS) && !strchr(id, '/')) { /* Old format < 4.0.18 constraints have constraint ids - _. We only try deleting them if the + NUMBER_NUMBER. We only try deleting them if the constraint name does not contain a '/' character, otherwise deleting a new format constraint named 'foo/bar' from database 'baz' would remove constraint 'bar' from database diff --git a/storage/innodb_plugin/ut/ut0auxconf_pause.c b/storage/innodb_plugin/ut/ut0auxconf_pause.c index 54d63bdd9bc..227fc2b204e 100644 --- a/storage/innodb_plugin/ut/ut0auxconf_pause.c +++ b/storage/innodb_plugin/ut/ut0auxconf_pause.c @@ -30,3 +30,35 @@ main(int argc, char** argv) return(0); } +/***************************************************************************** + +Copyright (c) 2009, Innobase Oy. 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 +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +/***************************************************************************** +If this program compiles and can be run and returns 0, then the pause +instruction is available. + +Created Jul 21, 2009 Vasil Dimov +*****************************************************************************/ + +int +main(int argc, char** argv) +{ + __asm__ __volatile__ ("pause"); + + return(0); +} From cf8c95e0653129b19c80f0c1cd6eb42d20edc406 Mon Sep 17 00:00:00 2001 From: Satya B Date: Thu, 8 Oct 2009 15:30:49 +0530 Subject: [PATCH 088/146] Applying InnoDB Plugin 1.0.5 snapshot, part 2 From r5639 to r5685 Detailed revision comments: r5639 | marko | 2009-08-06 05:39:34 -0500 (Thu, 06 Aug 2009) | 3 lines branches/zip: mem_heap_block_free(): If innodb_use_sys_malloc is set, do not tell Valgrind that the memory is free, to avoid a bogus warning in Valgrind's built-in free() hook. r5642 | calvin | 2009-08-06 18:04:03 -0500 (Thu, 06 Aug 2009) | 2 lines branches/zip: remove duplicate "the" in comments. r5662 | marko | 2009-08-11 04:54:16 -0500 (Tue, 11 Aug 2009) | 1 line branches/zip: Bump the version number to 1.0.5 after releasing 1.0.4. r5663 | marko | 2009-08-11 06:42:37 -0500 (Tue, 11 Aug 2009) | 2 lines branches/zip: trx_general_rollback_for_mysql(): Remove the redundant parameter partial. If savept==NULL, partial==FALSE. r5670 | marko | 2009-08-12 08:16:37 -0500 (Wed, 12 Aug 2009) | 2 lines branches/zip: trx_undo_rec_copy(): Add const qualifier to undo_rec. This is a non-functional change. r5671 | marko | 2009-08-13 03:46:33 -0500 (Thu, 13 Aug 2009) | 5 lines branches/zip: ha_innobase::add_index(): Fix Bug #46557: after a successful operation, read innodb_table->flags from the newly created table object, not from the old one that was just freed. Approved by Sunny. r5681 | sunny | 2009-08-14 01:16:24 -0500 (Fri, 14 Aug 2009) | 3 lines branches/zip: When building HotBackup srv_use_sys_malloc is #ifdef out. We move access to the this variable within a !UNIV_HOTBACKUP block. r5684 | sunny | 2009-08-20 03:05:30 -0500 (Thu, 20 Aug 2009) | 10 lines branches/zip: Fix bug# 46650: Innodb assertion autoinc_lock == lock in lock_table_remove_low on INSERT SELECT We only store the autoinc locks that are granted in the transaction's autoinc lock vector. A transacton, that has been rolled back due to a deadlock because of an AUTOINC lock attempt, will not have added that lock to the vector. We need to check for that when we remove that lock. rb://145 Approved by Marko. r5685 | sunny | 2009-08-20 03:18:29 -0500 (Thu, 20 Aug 2009) | 2 lines branches/zip: Update the ChangeLog with r5684 change. --- storage/innodb_plugin/ChangeLog | 17 +++++++++++++ storage/innodb_plugin/btr/btr0btr.c | 4 ++-- storage/innodb_plugin/buf/buf0rea.c | 2 +- storage/innodb_plugin/fsp/fsp0fsp.c | 2 +- .../innodb_plugin/handler/handler0alter.cc | 5 ++-- storage/innodb_plugin/include/buf0rea.h | 2 +- storage/innodb_plugin/include/dict0mem.h | 2 +- storage/innodb_plugin/include/fsp0fsp.h | 2 +- storage/innodb_plugin/include/log0log.h | 2 +- storage/innodb_plugin/include/rem0cmp.h | 2 +- storage/innodb_plugin/include/rem0rec.ic | 2 +- storage/innodb_plugin/include/trx0rec.h | 4 ++-- storage/innodb_plugin/include/trx0rec.ic | 4 ++-- storage/innodb_plugin/include/trx0roll.h | 4 ++-- storage/innodb_plugin/include/trx0sys.ic | 4 ++-- storage/innodb_plugin/include/trx0trx.h | 2 +- storage/innodb_plugin/include/univ.i | 2 +- storage/innodb_plugin/lock/lock0lock.c | 9 ++++--- storage/innodb_plugin/log/log0log.c | 2 +- storage/innodb_plugin/mem/mem0mem.c | 20 ++++++++++++---- storage/innodb_plugin/page/page0page.c | 2 +- storage/innodb_plugin/rem/rem0cmp.c | 6 ++--- storage/innodb_plugin/row/row0merge.c | 2 +- storage/innodb_plugin/row/row0mysql.c | 24 +++++++++---------- storage/innodb_plugin/srv/srv0srv.c | 2 +- storage/innodb_plugin/srv/srv0start.c | 2 +- storage/innodb_plugin/thr/thr0loc.c | 2 +- storage/innodb_plugin/trx/trx0rec.c | 4 ++-- storage/innodb_plugin/trx/trx0roll.c | 16 ++++++------- 29 files changed, 91 insertions(+), 62 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 593a9fa3418..6f456d4c4ad 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,20 @@ +2009-08-20 The InnoDB Team + + * lock/lock0lock.c: + Fix Bug#46650 InnoDB plugin: We only store the autoinc locks that are + granted in the transaction's autoinc lock vector. A transacton, that + has been rolled back due to a deadlock because of an AUTOINC lock + attempt, will not have added that lock to the vector. We need to check + for that when we remove that lock. + +2009-08-13 The InnoDB Team + + * handler/handler0alter.cc: + Fix Bug#46657 InnoDB plugin: invalid read in index_merge_innodb test + On a successful CREATE INDEX, diagnostic code read the table flags + from a recently freed table object. Read them from the newly + created object instead. + 2009-07-20 The InnoDB Team * handler/ha_innodb.cc, buf/buf0rea.c, include/srv0srv.h, srv/srv0srv.c diff --git a/storage/innodb_plugin/btr/btr0btr.c b/storage/innodb_plugin/btr/btr0btr.c index 6ba9b36207b..f34490ae101 100644 --- a/storage/innodb_plugin/btr/btr0btr.c +++ b/storage/innodb_plugin/btr/btr0btr.c @@ -797,7 +797,7 @@ btr_create( buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); } - /* Create a new index page on the the allocated segment page */ + /* Create a new index page on the allocated segment page */ page_zip = buf_block_get_page_zip(block); if (UNIV_LIKELY_NULL(page_zip)) { @@ -1902,7 +1902,7 @@ func_start: n_uniq, &heap); /* If the new record is less than the existing record - the the split in the middle will copy the existing + the split in the middle will copy the existing record to the new node. */ if (cmp_dtuple_rec(tuple, first_rec, offsets) < 0) { split_rec = page_get_middle_rec(page); diff --git a/storage/innodb_plugin/buf/buf0rea.c b/storage/innodb_plugin/buf/buf0rea.c index 319d6b2a522..4910f82ccde 100644 --- a/storage/innodb_plugin/buf/buf0rea.c +++ b/storage/innodb_plugin/buf/buf0rea.c @@ -378,7 +378,7 @@ buf_read_page( Applies linear read-ahead if in the buf_pool the page is a border page of a linear read-ahead area and all the pages in the area have been accessed. Does not read any page if the read-ahead mechanism is not activated. Note -that the the algorithm looks at the 'natural' adjacent successor and +that the algorithm looks at the 'natural' adjacent successor and predecessor of the page, which on the leaf level of a B-tree are the next and previous page in the chain of leaves. To know these, the page specified in (space, offset) must already be present in the buf_pool. Thus, the diff --git a/storage/innodb_plugin/fsp/fsp0fsp.c b/storage/innodb_plugin/fsp/fsp0fsp.c index ce14723ba18..f59a76aa3a3 100644 --- a/storage/innodb_plugin/fsp/fsp0fsp.c +++ b/storage/innodb_plugin/fsp/fsp0fsp.c @@ -1099,7 +1099,7 @@ fsp_header_inc_size( /**********************************************************************//** Gets the current free limit of the system tablespace. The free limit -means the place of the first page which has never been put to the the +means the place of the first page which has never been put to the free list for allocation. The space above that address is initialized to zero. Sets also the global variable log_fsp_current_free_limit. @return free limit in megabytes */ diff --git a/storage/innodb_plugin/handler/handler0alter.cc b/storage/innodb_plugin/handler/handler0alter.cc index d1f64a1985c..1aa0e6b126c 100644 --- a/storage/innodb_plugin/handler/handler0alter.cc +++ b/storage/innodb_plugin/handler/handler0alter.cc @@ -663,7 +663,7 @@ ha_innobase::add_index( if (UNIV_UNLIKELY(error)) { err_exit: mem_heap_free(heap); - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx_free_for_mysql(trx); trx_commit_for_mysql(prebuilt->trx); DBUG_RETURN(error); @@ -801,7 +801,7 @@ error_handling: alter table t drop index b, add index (b); The fix will have to parse the SQL and note that the index - being added has the same name as the the one being dropped and + being added has the same name as the one being dropped and ignore that in the dup index check.*/ //dict_table_check_for_dup_indexes(prebuilt->table); #endif @@ -863,6 +863,7 @@ error_handling: indexed_table->n_mysql_handles_opened++; error = row_merge_drop_table(trx, innodb_table); + innodb_table = indexed_table; goto convert_error; case DB_TOO_BIG_RECORD: diff --git a/storage/innodb_plugin/include/buf0rea.h b/storage/innodb_plugin/include/buf0rea.h index b4d25e6fde0..a3b5685bd91 100644 --- a/storage/innodb_plugin/include/buf0rea.h +++ b/storage/innodb_plugin/include/buf0rea.h @@ -48,7 +48,7 @@ buf_read_page( Applies linear read-ahead if in the buf_pool the page is a border page of a linear read-ahead area and all the pages in the area have been accessed. Does not read any page if the read-ahead mechanism is not activated. Note -that the the algorithm looks at the 'natural' adjacent successor and +that the algorithm looks at the 'natural' adjacent successor and predecessor of the page, which on the leaf level of a B-tree are the next and previous page in the chain of leaves. To know these, the page specified in (space, offset) must already be present in the buf_pool. Thus, the diff --git a/storage/innodb_plugin/include/dict0mem.h b/storage/innodb_plugin/include/dict0mem.h index 1ee906fbf57..2d001111938 100644 --- a/storage/innodb_plugin/include/dict0mem.h +++ b/storage/innodb_plugin/include/dict0mem.h @@ -317,7 +317,7 @@ struct dict_foreign_struct{ char* id; /*!< id of the constraint as a null-terminated string */ unsigned n_fields:10; /*!< number of indexes' first fields - for which the the foreign key + for which the foreign key constraint is defined: we allow the indexes to contain more fields than mentioned in the constraint, as long diff --git a/storage/innodb_plugin/include/fsp0fsp.h b/storage/innodb_plugin/include/fsp0fsp.h index 5f7dc58eedc..7abd3914eda 100644 --- a/storage/innodb_plugin/include/fsp0fsp.h +++ b/storage/innodb_plugin/include/fsp0fsp.h @@ -42,7 +42,7 @@ fsp_init(void); /*==========*/ /**********************************************************************//** Gets the current free limit of the system tablespace. The free limit -means the place of the first page which has never been put to the the +means the place of the first page which has never been put to the free list for allocation. The space above that address is initialized to zero. Sets also the global variable log_fsp_current_free_limit. @return free limit in megabytes */ diff --git a/storage/innodb_plugin/include/log0log.h b/storage/innodb_plugin/include/log0log.h index 059f548a085..5897067798d 100644 --- a/storage/innodb_plugin/include/log0log.h +++ b/storage/innodb_plugin/include/log0log.h @@ -283,7 +283,7 @@ log_make_checkpoint_at( later lsn, if IB_ULONGLONG_MAX, makes a checkpoint at the latest lsn */ ibool write_always); /*!< in: the function normally checks if - the the new checkpoint would have a + the new checkpoint would have a greater lsn than the previous one: if not, then no physical write is done; by setting this parameter TRUE, a diff --git a/storage/innodb_plugin/include/rem0cmp.h b/storage/innodb_plugin/include/rem0cmp.h index d30d9f86abe..072f74267ea 100644 --- a/storage/innodb_plugin/include/rem0cmp.h +++ b/storage/innodb_plugin/include/rem0cmp.h @@ -89,7 +89,7 @@ cmp_dfield_dfield( /*************************************************************//** This function is used to compare a data tuple to a physical record. Only dtuple->n_fields_cmp first fields are taken into account for -the the data tuple! If we denote by n = n_fields_cmp, then rec must +the data tuple! If we denote by n = n_fields_cmp, then rec must have either m >= n fields, or it must differ from dtuple in some of the m fields rec has. If rec has an externally stored field we do not compare it but return with value 0 if such a comparison should be diff --git a/storage/innodb_plugin/include/rem0rec.ic b/storage/innodb_plugin/include/rem0rec.ic index 9fe736f9b0b..8e5bd9a7fcd 100644 --- a/storage/innodb_plugin/include/rem0rec.ic +++ b/storage/innodb_plugin/include/rem0rec.ic @@ -65,7 +65,7 @@ most significant bytes and bits are written below less significant. - offset_of_this_record) mod 64Ki, where mod is the modulo as a non-negative number; - we can calculate the the offset of the next + we can calculate the offset of the next record with the formula: relative_offset + offset_of_this_record mod UNIV_PAGE_SIZE diff --git a/storage/innodb_plugin/include/trx0rec.h b/storage/innodb_plugin/include/trx0rec.h index 0ae82c33afe..a6e56e963c6 100644 --- a/storage/innodb_plugin/include/trx0rec.h +++ b/storage/innodb_plugin/include/trx0rec.h @@ -44,8 +44,8 @@ UNIV_INLINE trx_undo_rec_t* trx_undo_rec_copy( /*==============*/ - trx_undo_rec_t* undo_rec, /*!< in: undo log record */ - mem_heap_t* heap); /*!< in: heap where copied */ + const trx_undo_rec_t* undo_rec, /*!< in: undo log record */ + mem_heap_t* heap); /*!< in: heap where copied */ /**********************************************************************//** Reads the undo log record type. @return record type */ diff --git a/storage/innodb_plugin/include/trx0rec.ic b/storage/innodb_plugin/include/trx0rec.ic index 037b5d4f6cf..e7e41d6d9f6 100644 --- a/storage/innodb_plugin/include/trx0rec.ic +++ b/storage/innodb_plugin/include/trx0rec.ic @@ -100,8 +100,8 @@ UNIV_INLINE trx_undo_rec_t* trx_undo_rec_copy( /*==============*/ - trx_undo_rec_t* undo_rec, /*!< in: undo log record */ - mem_heap_t* heap) /*!< in: heap where copied */ + const trx_undo_rec_t* undo_rec, /*!< in: undo log record */ + mem_heap_t* heap) /*!< in: heap where copied */ { ulint len; diff --git a/storage/innodb_plugin/include/trx0roll.h b/storage/innodb_plugin/include/trx0roll.h index ddca9e9e4ef..37205dcd4b3 100644 --- a/storage/innodb_plugin/include/trx0roll.h +++ b/storage/innodb_plugin/include/trx0roll.h @@ -208,9 +208,9 @@ int trx_general_rollback_for_mysql( /*===========================*/ trx_t* trx, /*!< in: transaction handle */ - ibool partial,/*!< in: TRUE if partial rollback requested */ trx_savept_t* savept);/*!< in: pointer to savepoint undo number, if - partial rollback requested */ + partial rollback requested, or NULL for + complete rollback */ /*******************************************************************//** Rolls back a transaction back to a named savepoint. Modifications after the savepoint are undone but InnoDB does NOT release the corresponding locks diff --git a/storage/innodb_plugin/include/trx0sys.ic b/storage/innodb_plugin/include/trx0sys.ic index 1c7c732751b..820d31d0692 100644 --- a/storage/innodb_plugin/include/trx0sys.ic +++ b/storage/innodb_plugin/include/trx0sys.ic @@ -34,11 +34,11 @@ typedef byte trx_sysf_rseg_t; /* Rollback segment specification slot offsets */ /*-------------------------------------------------------------*/ -#define TRX_SYS_RSEG_SPACE 0 /* space where the the segment +#define TRX_SYS_RSEG_SPACE 0 /* space where the segment header is placed; starting with MySQL/InnoDB 5.1.7, this is UNIV_UNDEFINED if the slot is unused */ -#define TRX_SYS_RSEG_PAGE_NO 4 /* page number where the the segment +#define TRX_SYS_RSEG_PAGE_NO 4 /* page number where the segment header is placed; this is FIL_NULL if the slot is unused */ /*-------------------------------------------------------------*/ diff --git a/storage/innodb_plugin/include/trx0trx.h b/storage/innodb_plugin/include/trx0trx.h index 681feeaec94..4b79732b4bf 100644 --- a/storage/innodb_plugin/include/trx0trx.h +++ b/storage/innodb_plugin/include/trx0trx.h @@ -360,7 +360,7 @@ enum trx_dict_op { operation modes in crash recovery. */ TRX_DICT_OP_TABLE = 1, /** The transaction is creating or dropping an index in an - existing table. In crash recovery, the the data dictionary + existing table. In crash recovery, the data dictionary must be locked, but the table must not be dropped. */ TRX_DICT_OP_INDEX = 2 }; diff --git a/storage/innodb_plugin/include/univ.i b/storage/innodb_plugin/include/univ.i index 023a6c9cd89..35e609a78e5 100644 --- a/storage/innodb_plugin/include/univ.i +++ b/storage/innodb_plugin/include/univ.i @@ -46,7 +46,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 1 #define INNODB_VERSION_MINOR 0 -#define INNODB_VERSION_BUGFIX 4 +#define INNODB_VERSION_BUGFIX 5 /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; diff --git a/storage/innodb_plugin/lock/lock0lock.c b/storage/innodb_plugin/lock/lock0lock.c index 23c2ff4740f..5ec9cdbf4dd 100644 --- a/storage/innodb_plugin/lock/lock0lock.c +++ b/storage/innodb_plugin/lock/lock0lock.c @@ -214,7 +214,7 @@ a waiting s-lock request on the next record? If this s-lock was placed by a read cursor moving in the ascending order in the index, we cannot do the insert immediately, because when we finally commit our transaction, the read cursor should see also the new inserted record. So we should -move the read cursor backward from the the next record for it to pass over +move the read cursor backward from the next record for it to pass over the new inserted record. This move backward may be too cumbersome to implement. If we in this situation just enqueue a second x-lock request for our transaction on the next record, then the deadlock mechanism @@ -3580,7 +3580,8 @@ lock_table_remove_low( and lock_grant()). Therefore it can be empty and we need to check for that. */ - if (!ib_vector_is_empty(trx->autoinc_locks)) { + if (!lock_get_wait(lock) + && !ib_vector_is_empty(trx->autoinc_locks)) { lock_t* autoinc_lock; autoinc_lock = ib_vector_pop(trx->autoinc_locks); @@ -3653,8 +3654,10 @@ lock_table_enqueue_waiting( if (lock_deadlock_occurs(lock, trx)) { - lock_reset_lock_and_trx_wait(lock); + /* The order here is important, we don't want to + lose the state of the lock before calling remove. */ lock_table_remove_low(lock); + lock_reset_lock_and_trx_wait(lock); return(DB_DEADLOCK); } diff --git a/storage/innodb_plugin/log/log0log.c b/storage/innodb_plugin/log/log0log.c index 24c828cdf5f..f67a1067301 100644 --- a/storage/innodb_plugin/log/log0log.c +++ b/storage/innodb_plugin/log/log0log.c @@ -2047,7 +2047,7 @@ log_make_checkpoint_at( later lsn, if IB_ULONGLONG_MAX, makes a checkpoint at the latest lsn */ ibool write_always) /*!< in: the function normally checks if - the the new checkpoint would have a + the new checkpoint would have a greater lsn than the previous one: if not, then no physical write is done; by setting this parameter TRUE, a diff --git a/storage/innodb_plugin/mem/mem0mem.c b/storage/innodb_plugin/mem/mem0mem.c index e0dc8716f13..ccb2fd8a7b4 100644 --- a/storage/innodb_plugin/mem/mem0mem.c +++ b/storage/innodb_plugin/mem/mem0mem.c @@ -475,16 +475,18 @@ mem_heap_block_free( len = block->len; block->magic_n = MEM_FREED_BLOCK_MAGIC_N; +#ifndef UNIV_HOTBACKUP + if (!srv_use_sys_malloc) { #ifdef UNIV_MEM_DEBUG - /* In the debug version we set the memory to a random combination - of hex 0xDE and 0xAD. */ + /* In the debug version we set the memory to a random + combination of hex 0xDE and 0xAD. */ - mem_erase_buf((byte*)block, len); + mem_erase_buf((byte*)block, len); #else /* UNIV_MEM_DEBUG */ - UNIV_MEM_ASSERT_AND_FREE(block, len); + UNIV_MEM_ASSERT_AND_FREE(block, len); #endif /* UNIV_MEM_DEBUG */ -#ifndef UNIV_HOTBACKUP + } if (type == MEM_HEAP_DYNAMIC || len < UNIV_PAGE_SIZE / 2) { ut_ad(!buf_block); @@ -495,6 +497,14 @@ mem_heap_block_free( buf_block_free(buf_block); } #else /* !UNIV_HOTBACKUP */ +#ifdef UNIV_MEM_DEBUG + /* In the debug version we set the memory to a random + combination of hex 0xDE and 0xAD. */ + + mem_erase_buf((byte*)block, len); +#else /* UNIV_MEM_DEBUG */ + UNIV_MEM_ASSERT_AND_FREE(block, len); +#endif /* UNIV_MEM_DEBUG */ ut_free(block); #endif /* !UNIV_HOTBACKUP */ } diff --git a/storage/innodb_plugin/page/page0page.c b/storage/innodb_plugin/page/page0page.c index f056ef77bdc..b771bf4ded9 100644 --- a/storage/innodb_plugin/page/page0page.c +++ b/storage/innodb_plugin/page/page0page.c @@ -45,7 +45,7 @@ Created 2/2/1994 Heikki Tuuri ============== The index page consists of a page header which contains the page's -id and other information. On top of it are the the index records +id and other information. On top of it are the index records in a heap linked into a one way linear list according to alphabetic order. Just below page end is an array of pointers which we call page directory, diff --git a/storage/innodb_plugin/rem/rem0cmp.c b/storage/innodb_plugin/rem/rem0cmp.c index b707f2116d6..e6dab0bc66b 100644 --- a/storage/innodb_plugin/rem/rem0cmp.c +++ b/storage/innodb_plugin/rem/rem0cmp.c @@ -36,7 +36,7 @@ Created 7/1/1994 Heikki Tuuri The records are put into alphabetical order in the following way: let F be the first field where two records disagree. -If there is a character in some position n where the the +If there is a character in some position n where the records disagree, the order is determined by comparison of the characters at position n, possibly after collating transformation. If there is no such character, @@ -76,7 +76,7 @@ cmp_debug_dtuple_rec_with_match( /*************************************************************//** This function is used to compare two data fields for which the data type is such that we must use MySQL code to compare them. The prototype here -must be a copy of the the one in ha_innobase.cc! +must be a copy of the one in ha_innobase.cc! @return 1, 0, -1, if a is greater, equal, less than b, respectively */ extern int @@ -399,7 +399,7 @@ next_byte: /*************************************************************//** This function is used to compare a data tuple to a physical record. Only dtuple->n_fields_cmp first fields are taken into account for -the the data tuple! If we denote by n = n_fields_cmp, then rec must +the data tuple! If we denote by n = n_fields_cmp, then rec must have either m >= n fields, or it must differ from dtuple in some of the m fields rec has. If rec has an externally stored field we do not compare it but return with value 0 if such a comparison should be diff --git a/storage/innodb_plugin/row/row0merge.c b/storage/innodb_plugin/row/row0merge.c index 05a45dc647c..924b7ffba58 100644 --- a/storage/innodb_plugin/row/row0merge.c +++ b/storage/innodb_plugin/row/row0merge.c @@ -2129,7 +2129,7 @@ row_merge_rename_tables( if (err != DB_SUCCESS) { err_exit: trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; } diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index f7701a701ce..8d80d73f0c7 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -510,7 +510,7 @@ handle_new_error: switch (err) { case DB_LOCK_WAIT_TIMEOUT: if (row_rollback_on_timeout) { - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); break; } /* fall through */ @@ -526,7 +526,7 @@ handle_new_error: /* Roll back the latest, possibly incomplete insertion or update */ - trx_general_rollback_for_mysql(trx, TRUE, savept); + trx_general_rollback_for_mysql(trx, savept); } /* MySQL will roll back the latest SQL statement */ break; @@ -548,7 +548,7 @@ handle_new_error: /* Roll back the whole transaction; this resolution was added to version 3.23.43 */ - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); break; case DB_MUST_GET_MORE_FILE_SPACE: @@ -1885,7 +1885,7 @@ err_exit: if (UNIV_UNLIKELY(err != DB_SUCCESS)) { trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); } switch (err) { @@ -2053,7 +2053,7 @@ error_handling: trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); row_drop_table_for_mysql(table_name, trx, FALSE); @@ -2121,7 +2121,7 @@ row_table_add_foreign_constraints( trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); row_drop_table_for_mysql(name, trx, FALSE); @@ -2488,7 +2488,7 @@ row_discard_tablespace_for_mysql( if (err != DB_SUCCESS) { trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; } else { dict_table_change_id_in_cache(table, new_id); @@ -2497,7 +2497,7 @@ row_discard_tablespace_for_mysql( if (!success) { trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; err = DB_ERROR; @@ -2949,7 +2949,7 @@ next_rec: if (err != DB_SUCCESS) { trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; ut_print_timestamp(stderr); fputs(" InnoDB: Unable to assign a new identifier to table ", @@ -3854,7 +3854,7 @@ end: "InnoDB: succeed.\n", stderr); } trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; } else { /* The following call will also rename the .ibd data file if @@ -3863,7 +3863,7 @@ end: if (!dict_table_rename_in_cache(table, new_name, !new_is_tmp)) { trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; goto funct_exit; } @@ -3903,7 +3903,7 @@ end: ut_a(dict_table_rename_in_cache(table, old_name, FALSE)); trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; } } diff --git a/storage/innodb_plugin/srv/srv0srv.c b/storage/innodb_plugin/srv/srv0srv.c index 79fa08e7cdf..b41c8acfab4 100644 --- a/storage/innodb_plugin/srv/srv0srv.c +++ b/storage/innodb_plugin/srv/srv0srv.c @@ -614,7 +614,7 @@ future, but at the moment we plan to implement a more coarse solution, which could be called a global priority inheritance. If a thread has to wait for a long time, say 300 milliseconds, for a resource, we just guess that it may be waiting for a resource owned by a background -thread, and boost the the priority of all runnable background threads +thread, and boost the priority of all runnable background threads to the normal level. The background threads then themselves adjust their fixed priority back to background after releasing all resources they had (or, at some fixed points in their program code). diff --git a/storage/innodb_plugin/srv/srv0start.c b/storage/innodb_plugin/srv/srv0start.c index a942fd439a3..f7447499b3b 100644 --- a/storage/innodb_plugin/srv/srv0start.c +++ b/storage/innodb_plugin/srv/srv0start.c @@ -1829,7 +1829,7 @@ innobase_start_or_create_for_mysql(void) /* Actually, we did not change the undo log format between 4.0 and 4.1.1, and we would not need to run purge to completion. Note also that the purge algorithm in 4.1.1 - can process the the history list again even after a full + can process the history list again even after a full purge, because our algorithm does not cut the end of the history list in all cases so that it would become empty after a full purge. That mean that we may purge 4.0 type diff --git a/storage/innodb_plugin/thr/thr0loc.c b/storage/innodb_plugin/thr/thr0loc.c index 18f7b0707bd..49275be1d7d 100644 --- a/storage/innodb_plugin/thr/thr0loc.c +++ b/storage/innodb_plugin/thr/thr0loc.c @@ -62,7 +62,7 @@ struct thr_local_struct{ os_thread_t handle; /*!< operating system handle to the thread */ ulint slot_no;/*!< the index of the slot in the thread table for this thread */ - ibool in_ibuf;/*!< TRUE if the the thread is doing an ibuf + ibool in_ibuf;/*!< TRUE if the thread is doing an ibuf operation */ hash_node_t hash; /*!< hash chain node */ ulint magic_n;/*!< magic number (THR_LOCAL_MAGIC_N) */ diff --git a/storage/innodb_plugin/trx/trx0rec.c b/storage/innodb_plugin/trx/trx0rec.c index 36911c9df85..5097cf18dcd 100644 --- a/storage/innodb_plugin/trx/trx0rec.c +++ b/storage/innodb_plugin/trx/trx0rec.c @@ -1333,7 +1333,7 @@ trx_undo_get_undo_rec_low( ulint rseg_id; ulint page_no; ulint offset; - page_t* undo_page; + const page_t* undo_page; trx_rseg_t* rseg; ibool is_insert; mtr_t mtr; @@ -1572,7 +1572,7 @@ trx_undo_prev_version_build( /* We have to set the appropriate extern storage bits in the old version of the record: the extern bits in rec for those - fields that update does NOT update, as well as the the bits for + fields that update does NOT update, as well as the bits for those fields that update updates to become externally stored fields. Store the info: */ diff --git a/storage/innodb_plugin/trx/trx0roll.c b/storage/innodb_plugin/trx/trx0roll.c index 51d17192d5b..b139a8a19af 100644 --- a/storage/innodb_plugin/trx/trx0roll.c +++ b/storage/innodb_plugin/trx/trx0roll.c @@ -66,9 +66,9 @@ int trx_general_rollback_for_mysql( /*===========================*/ trx_t* trx, /*!< in: transaction handle */ - ibool partial,/*!< in: TRUE if partial rollback requested */ trx_savept_t* savept) /*!< in: pointer to savepoint undo number, if - partial rollback requested */ + partial rollback requested, or NULL for + complete rollback */ { mem_heap_t* heap; que_thr_t* thr; @@ -85,9 +85,8 @@ trx_general_rollback_for_mysql( roll_node = roll_node_create(heap); - roll_node->partial = partial; - - if (partial) { + if (savept) { + roll_node->partial = TRUE; roll_node->savept = *savept; } @@ -145,7 +144,7 @@ trx_rollback_for_mysql( the transaction object does not have an InnoDB session object, and we set a dummy session that we use for all MySQL transactions. */ - err = trx_general_rollback_for_mysql(trx, FALSE, NULL); + err = trx_general_rollback_for_mysql(trx, NULL); trx->op_info = ""; @@ -170,8 +169,7 @@ trx_rollback_last_sql_stat_for_mysql( trx->op_info = "rollback of SQL statement"; - err = trx_general_rollback_for_mysql(trx, TRUE, - &(trx->last_sql_stat_start)); + err = trx_general_rollback_for_mysql(trx, &trx->last_sql_stat_start); /* The following call should not be needed, but we play safe: */ trx_mark_sql_stat_end(trx); @@ -282,7 +280,7 @@ trx_rollback_to_savepoint_for_mysql( trx->op_info = "rollback to a savepoint"; - err = trx_general_rollback_for_mysql(trx, TRUE, &(savep->savept)); + err = trx_general_rollback_for_mysql(trx, &savep->savept); /* Store the current undo_no of the transaction so that we know where to roll back if we have to roll back the next SQL statement: */ From 266c7cd6b792babc4828be455b0cbffe72de6803 Mon Sep 17 00:00:00 2001 From: Satya B Date: Thu, 8 Oct 2009 16:08:57 +0530 Subject: [PATCH 089/146] Applying InnoDB Plugin 1.0.5 snapshot, part 3 From revision r5686 to r5702 r5696 is already applied Detailed revision comments: r5686 | vasil | 2009-08-20 04:15:05 -0500 (Thu, 20 Aug 2009) | 4 lines branches/zip: White-space fixup. r5687 | vasil | 2009-08-20 04:20:22 -0500 (Thu, 20 Aug 2009) | 8 lines branches/zip: ChangeLog: Follow the convention from the rest of the ChangeLog: for bugfixes from bugs.mysql.com only the bug number and title goes in the ChangeLog. Detailed explanation on what is the problem and how it was fixed is present in the bugs database. r5694 | marko | 2009-08-26 06:25:26 -0500 (Wed, 26 Aug 2009) | 2 lines branches/zip: buf_page_t: Clarify that bpage->list may contain garbage. This comment was provoked by Inaam. r5695 | marko | 2009-08-26 08:14:59 -0500 (Wed, 26 Aug 2009) | 1 line branches/zip: UNIV_DEBUG_LOCK_VALIDATE: Move the definition to univ.i. r5697 | vasil | 2009-08-26 08:44:40 -0500 (Wed, 26 Aug 2009) | 4 lines branches/zip: Fix typo. r5698 | inaam | 2009-08-26 09:34:35 -0500 (Wed, 26 Aug 2009) | 13 lines branches/zip bug#42885 rb://148 The call to put IO threads to sleep was most probably meant for Windows only as the comment in buf0rea.c suggests. However it was enabled on all platforms. This patch restricts the sleep call to windows. This approach of not putting threads to sleep makes even more sense because now we have multiple threads working in the background and it probably is not a good idea to put all of them to sleep because a user thread wants to post a batch for readahead. Approved by: Marko r5701 | marko | 2009-08-27 02:01:42 -0500 (Thu, 27 Aug 2009) | 1 line branches/zip: Document r5698 in the ChangeLog. r5702 | marko | 2009-08-27 02:03:15 -0500 (Thu, 27 Aug 2009) | 1 line branches/zip: Document also the files affected by r5698 in the ChangeLog. --- storage/innodb_plugin/ChangeLog | 17 +++++++++-------- storage/innodb_plugin/handler/ha_innodb.cc | 8 +++----- storage/innodb_plugin/handler/i_s.cc | 18 ++++++++---------- storage/innodb_plugin/include/buf0buf.h | 11 ++++++++++- storage/innodb_plugin/include/univ.i | 3 +++ storage/innodb_plugin/lock/lock0lock.c | 3 --- storage/innodb_plugin/os/os0file.c | 13 +++++++++++++ storage/innodb_plugin/plug.in | 2 +- 8 files changed, 47 insertions(+), 28 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 6f456d4c4ad..b488b21c768 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,19 +1,20 @@ +2009-08-26 The InnoDB Team + + * handler/ha_innodb.cc, os/os0file.c: + Fix Bug#42885 buf_read_ahead_random, buf_read_ahead_linear counters, + thread wakeups + 2009-08-20 The InnoDB Team * lock/lock0lock.c: - Fix Bug#46650 InnoDB plugin: We only store the autoinc locks that are - granted in the transaction's autoinc lock vector. A transacton, that - has been rolled back due to a deadlock because of an AUTOINC lock - attempt, will not have added that lock to the vector. We need to check - for that when we remove that lock. + Fix Bug#46650 Innodb assertion autoinc_lock == lock in + lock_table_remove_low on INSERT SELECT 2009-08-13 The InnoDB Team * handler/handler0alter.cc: Fix Bug#46657 InnoDB plugin: invalid read in index_merge_innodb test - On a successful CREATE INDEX, diagnostic code read the table flags - from a recently freed table object. Read them from the newly - created object instead. + (Valgrind) 2009-07-20 The InnoDB Team diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 682004407c7..616c227ae0c 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -166,9 +166,7 @@ file formats in the configuration file, but can only be set to any of the supported file formats during runtime. */ static char* innobase_file_format_check = NULL; -/* The following has a misleading name: starting from 4.0.5, this also -affects Windows: */ -static char* innobase_unix_file_flush_method = NULL; +static char* innobase_file_flush_method = NULL; /* Below we have boolean-valued start-up parameters, and their default values */ @@ -2151,7 +2149,7 @@ innobase_change_buffering_inited_ok: /* --------------------------------------------------*/ - srv_file_flush_method_str = innobase_unix_file_flush_method; + srv_file_flush_method_str = innobase_file_flush_method; srv_n_log_groups = (ulint) innobase_mirrored_log_groups; srv_n_log_files = (ulint) innobase_log_files_in_group; @@ -9753,7 +9751,7 @@ static MYSQL_SYSVAR_ULONG(flush_log_at_trx_commit, srv_flush_log_at_trx_commit, " or 2 (write at commit, flush once per second).", NULL, NULL, 1, 0, 2, 0); -static MYSQL_SYSVAR_STR(flush_method, innobase_unix_file_flush_method, +static MYSQL_SYSVAR_STR(flush_method, innobase_file_flush_method, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "With which method to flush data.", NULL, NULL, NULL); diff --git a/storage/innodb_plugin/handler/i_s.cc b/storage/innodb_plugin/handler/i_s.cc index 524fe696de2..c0d488d1c49 100644 --- a/storage/innodb_plugin/handler/i_s.cc +++ b/storage/innodb_plugin/handler/i_s.cc @@ -69,16 +69,14 @@ do { \ #define STRUCT_FLD(name, value) value #endif -/* Don't use a static const variable here, as some C++ compilers (notably -HPUX aCC: HP ANSI C++ B3910B A.03.65) can't handle it. */ -#define END_OF_ST_FIELD_INFO \ - {STRUCT_FLD(field_name, NULL), \ - STRUCT_FLD(field_length, 0), \ - STRUCT_FLD(field_type, MYSQL_TYPE_NULL), \ - STRUCT_FLD(value, 0), \ - STRUCT_FLD(field_flags, 0), \ - STRUCT_FLD(old_name, ""), \ - STRUCT_FLD(open_method, SKIP_OPEN_TABLE)} +static const ST_FIELD_INFO END_OF_ST_FIELD_INFO = + {STRUCT_FLD(field_name, NULL), + STRUCT_FLD(field_length, 0), + STRUCT_FLD(field_type, MYSQL_TYPE_NULL), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}; /* Use the following types mapping: diff --git a/storage/innodb_plugin/include/buf0buf.h b/storage/innodb_plugin/include/buf0buf.h index 65ad42c895a..a24fc4cdbbb 100644 --- a/storage/innodb_plugin/include/buf0buf.h +++ b/storage/innodb_plugin/include/buf0buf.h @@ -1103,7 +1103,16 @@ struct buf_page_struct{ - BUF_BLOCK_FILE_PAGE: flush_list - BUF_BLOCK_ZIP_DIRTY: flush_list - BUF_BLOCK_ZIP_PAGE: zip_clean - - BUF_BLOCK_ZIP_FREE: zip_free[] */ + - BUF_BLOCK_ZIP_FREE: zip_free[] + + The contents of the list node + is undefined if !in_flush_list + && state == BUF_BLOCK_FILE_PAGE, + or if state is one of + BUF_BLOCK_MEMORY, + BUF_BLOCK_REMOVE_HASH or + BUF_BLOCK_READY_IN_USE. */ + #ifdef UNIV_DEBUG ibool in_flush_list; /*!< TRUE if in buf_pool->flush_list; when buf_pool_mutex is free, the diff --git a/storage/innodb_plugin/include/univ.i b/storage/innodb_plugin/include/univ.i index 35e609a78e5..aa01f072b1d 100644 --- a/storage/innodb_plugin/include/univ.i +++ b/storage/innodb_plugin/include/univ.i @@ -196,6 +196,9 @@ command. Not tested on Windows. */ debugging without UNIV_DEBUG */ #define UNIV_DEBUG /* Enable ut_ad() assertions and disable UNIV_INLINE */ +#define UNIV_DEBUG_LOCK_VALIDATE /* Enable + ut_ad(lock_rec_validate_page()) + assertions. */ #define UNIV_DEBUG_FILE_ACCESSES /* Debug .ibd file access (field file_page_was_freed in buf_page_t) */ diff --git a/storage/innodb_plugin/lock/lock0lock.c b/storage/innodb_plugin/lock/lock0lock.c index 5ec9cdbf4dd..41805b58e0b 100644 --- a/storage/innodb_plugin/lock/lock0lock.c +++ b/storage/innodb_plugin/lock/lock0lock.c @@ -363,9 +363,6 @@ lock_rec_validate_page( ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ ulint page_no);/*!< in: page number */ - -/* Define the following in order to enable lock_rec_validate_page() checks. */ -# undef UNIV_DEBUG_LOCK_VALIDATE #endif /* UNIV_DEBUG */ /* The lock system */ diff --git a/storage/innodb_plugin/os/os0file.c b/storage/innodb_plugin/os/os0file.c index d3bd6465f5f..dc25d55f818 100644 --- a/storage/innodb_plugin/os/os0file.c +++ b/storage/innodb_plugin/os/os0file.c @@ -3371,9 +3371,21 @@ void os_aio_simulated_put_read_threads_to_sleep(void) /*============================================*/ { + +/* The idea of putting background IO threads to sleep is only for +Windows when using simulated AIO. Windows XP seems to schedule +background threads too eagerly to allow for coalescing during +readahead requests. */ +#ifdef __WIN__ os_aio_array_t* array; ulint g; + if (os_aio_use_native_aio) { + /* We do not use simulated aio: do nothing */ + + return; + } + os_aio_recommend_sleep_for_read_threads = TRUE; for (g = 0; g < os_aio_n_segments; g++) { @@ -3384,6 +3396,7 @@ os_aio_simulated_put_read_threads_to_sleep(void) os_event_reset(os_aio_segment_wait_events[g]); } } +#endif /* __WIN__ */ } /*******************************************************************//** diff --git a/storage/innodb_plugin/plug.in b/storage/innodb_plugin/plug.in index 6daa6c5daed..a620f10a0da 100644 --- a/storage/innodb_plugin/plug.in +++ b/storage/innodb_plugin/plug.in @@ -103,7 +103,7 @@ MYSQL_PLUGIN_ACTIONS(innodb_plugin, [ AC_CHECK_DECLS( [HAVE_SOLARIS_ATOMICS], [ - AC_MSG_CHECKING(checking if pthread_t size is integral) + AC_MSG_CHECKING(checking if pthread_t type is integral) AC_TRY_RUN( [ #include From edd89cf7f75df785b3c59f5c72a853bcb4dc31ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Bl=C3=A5udd?= Date: Thu, 8 Oct 2009 13:25:11 +0200 Subject: [PATCH 090/146] Merge --- .../suite/binlog/t/binlog_stm_unsafe_warning.test | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test b/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test index a5472952f08..656eaae5721 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test +++ b/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test @@ -94,15 +94,24 @@ DROP TABLE t1; SET GLOBAL log_warnings = @old_log_warnings; -let LOG_ERROR= `SELECT @@GLOBAL.log_error`; +let $log_error= `SELECT @@GLOBAL.log_error`; +if(!$log_error) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error = $MYSQLTEST_VARDIR/log/mysqld.1.err; +} +# Assign env variable LOG_ERROR +let LOG_ERROR=$log_error; --echo # Count the number of times the "Unsafe" message was printed --echo # to the error log. perl; - $log_error= $ENV{'LOG_ERROR'}; + use strict; + my $log_error= $ENV{'LOG_ERROR'} || die "LOG_ERROR not set"; open(FILE, "$log_error") or die("Unable to open $log_error: $!\n"); - $count = () = grep(/Bug#46265/g,); + my $count = () = grep(/Bug#46265/g,); print "Occurrences: $count\n"; close(FILE); EOF From 7f890ab6aa436386f1aa9eb989b164d9af82b008 Mon Sep 17 00:00:00 2001 From: Satya B Date: Thu, 8 Oct 2009 16:58:37 +0530 Subject: [PATCH 091/146] Applying InnoDB Plugin 1.0.5 snapshot, part 4 From revision r5703 to r5716 Detailed revision comments: r5703 | marko | 2009-08-27 02:25:00 -0500 (Thu, 27 Aug 2009) | 41 lines branches/zip: Replace the constant 3/8 ratio that controls the LRU_old size with the settable global variable innodb_old_blocks_pct. The minimum and maximum values are 5 and 95 per cent, respectively. The default is 100*3/8, in line with the old behavior. ut_time_ms(): New utility function, to return the current time in milliseconds. TODO: Is there a more efficient timestamp function, such as rdtsc divided by a power of two? buf_LRU_old_threshold_ms: New variable, corresponding to innodb_old_blocks_time. The value 0 is the default behaviour: no timeout before making blocks 'new'. bpage->accessed, bpage->LRU_position, buf_pool->ulint_clock: Remove. bpage->access_time: New field, replacing bpage->accessed. Protected by buf_pool_mutex instead of bpage->mutex. Updated when a page is created or accessed the first time in the buffer pool. buf_LRU_old_ratio, innobase_old_blocks_pct: New variables, corresponding to innodb_old_blocks_pct buf_LRU_old_ratio_update(), innobase_old_blocks_pct_update(): Update functions for buf_LRU_old_ratio, innobase_old_blocks_pct. buf_page_peek_if_too_old(): Compare ut_time_ms() to bpage->access_time if buf_LRU_old_threshold_ms && bpage->old. Else observe buf_LRU_old_ratio and bpage->freed_page_clock. buf_pool_t: Add n_pages_made_young, n_pages_not_made_young, n_pages_made_young_old, n_pages_not_made_young, for statistics. buf_print(): Display buf_pool->n_pages_made_young, buf_pool->n_pages_not_made_young. This function is only for crash diagnostics. buf_print_io(): Display buf_pool->LRU_old_len and quantities derived from buf_pool->n_pages_made_young, buf_pool->n_pages_not_made_young. This function is invoked by SHOW ENGINE INNODB STATUS. rb://129 approved by Heikki Tuuri. This addresses Bug #45015. r5704 | marko | 2009-08-27 03:31:17 -0500 (Thu, 27 Aug 2009) | 32 lines branches/zip: Fix a critical bug in fast index creation that could corrupt the created indexes. row_merge(): Make "half" an in/out parameter. Determine the offset of half the output file. Copy the last blocks record-by-record instead of block-by-block, so that the records can be counted. Check that the input and output have matching n_rec. row_merge_sort(): Do not assume that two blocks of size N are merged into a block of size 2*N. The output block can be shorter than the input if the last page of each input block is almost empty. Use an accurate termination condition, based on the "half" computed by row_merge(). row_merge_read(), row_merge_write(), row_merge_blocks(): Add debug output. merge_file_t, row_merge_file_create(): Add n_rec, the number of records in the merge file. row_merge_read_clustered_index(): Update n_rec. row_merge_blocks(): Update and check n_rec. row_merge_blocks_copy(): New function, for copying the last blocks in row_merge(). Update and check n_rec. This bug was discovered with a user-supplied test case that creates an index where the initial temporary file is 249 one-megabyte blocks and the merged files become smaller. In the test, possible merge record sizes are 10, 18, and 26 bytes. rb://150 approved by Sunny Bains. This addresses Issue #320. r5705 | marko | 2009-08-27 06:56:24 -0500 (Thu, 27 Aug 2009) | 11 lines branches/zip: dict_index_find_cols(): On column name lookup failure, return DB_CORRUPTION (HA_ERR_CRASHED) instead of abnormally terminating the server. Also, disable the previously added diagnostic output to the error log, because mysql-test-run does not like extra output in the error log. (Bug #44571) dict_index_add_to_cache(): Handle errors from dict_index_find_cols(). mysql-test/innodb_bug44571.test: A test case for triggering the bug. rb://135 approved by Sunny Bains. r5706 | inaam | 2009-08-27 11:00:27 -0500 (Thu, 27 Aug 2009) | 20 lines branches/zip rb://147 Done away with following two status variables: innodb_buffer_pool_read_ahead_rnd innodb_buffer_pool_read_ahead_seq Introduced two new status variables: innodb_buffer_pool_read_ahead = number of pages read as part of readahead since server startup innodb_buffer_pool_read_ahead_evicted = number of pages that are read in as readahead but were evicted before ever being accessed since server startup i.e.: a measure of how badly our readahead is performing SHOW INNODB STATUS will show two extra numbers in buffer pool section: pages read ahead/sec and pages evicted without access/sec Approved by: Marko r5707 | inaam | 2009-08-27 11:20:35 -0500 (Thu, 27 Aug 2009) | 6 lines branches/zip Remove unused macros as we erased the random readahead code in r5703. Also fixed some comments. r5708 | inaam | 2009-08-27 17:43:32 -0500 (Thu, 27 Aug 2009) | 4 lines branches/zip Remove redundant TRUE : FALSE from the return statement r5709 | inaam | 2009-08-28 01:22:46 -0500 (Fri, 28 Aug 2009) | 5 lines branches/zip rb://152 Disable display of deprecated parameter innodb_file_io_threads in 'show variables'. r5714 | marko | 2009-08-31 01:10:10 -0500 (Mon, 31 Aug 2009) | 5 lines branches/zip: buf_chunk_not_freed(): Do not acquire block->mutex unless block->page.state == BUF_BLOCK_FILE_PAGE. Check that block->page.state makes sense. Approved by Sunny Bains over the IM. r5716 | vasil | 2009-08-31 02:47:49 -0500 (Mon, 31 Aug 2009) | 9 lines branches/zip: Fix Bug#46718 InnoDB plugin incompatible with gcc 4.1 (at least: on PPC): "Undefined symbol" by implementing our own check in plug.in instead of using the result from the check from MySQL because it is insufficient. Approved by: Marko (rb://154) --- .../suite/innodb/r/innodb_bug44571.result | 9 + .../suite/innodb/t/innodb_bug44571.test | 18 ++ storage/innodb_plugin/ChangeLog | 34 +++ storage/innodb_plugin/btr/btr0sea.c | 2 +- storage/innodb_plugin/buf/buf0buf.c | 226 ++++++++++------- storage/innodb_plugin/buf/buf0lru.c | 229 ++++++++++-------- storage/innodb_plugin/buf/buf0rea.c | 207 ++-------------- storage/innodb_plugin/dict/dict0dict.c | 23 +- storage/innodb_plugin/handler/ha_innodb.cc | 51 +++- storage/innodb_plugin/include/buf0buf.h | 115 ++++----- storage/innodb_plugin/include/buf0buf.ic | 70 +++--- storage/innodb_plugin/include/buf0lru.h | 52 +++- storage/innodb_plugin/include/buf0rea.h | 8 +- storage/innodb_plugin/include/buf0types.h | 2 + storage/innodb_plugin/include/dict0dict.h | 2 +- storage/innodb_plugin/include/os0sync.h | 4 +- storage/innodb_plugin/include/srv0srv.h | 16 +- storage/innodb_plugin/include/univ.i | 4 +- storage/innodb_plugin/include/ut0ut.h | 9 + storage/innodb_plugin/plug.in | 51 ++++ storage/innodb_plugin/row/row0merge.c | 208 +++++++++++++--- storage/innodb_plugin/srv/srv0srv.c | 53 ++-- storage/innodb_plugin/srv/srv0start.c | 6 +- storage/innodb_plugin/ut/ut0ut.c | 17 ++ 24 files changed, 814 insertions(+), 602 deletions(-) create mode 100644 mysql-test/suite/innodb/r/innodb_bug44571.result create mode 100644 mysql-test/suite/innodb/t/innodb_bug44571.test diff --git a/mysql-test/suite/innodb/r/innodb_bug44571.result b/mysql-test/suite/innodb/r/innodb_bug44571.result new file mode 100644 index 00000000000..36374edcb3e --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug44571.result @@ -0,0 +1,9 @@ +CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; +ALTER TABLE bug44571 CHANGE foo bar INT; +ALTER TABLE bug44571 ADD INDEX bug44571b (foo); +ERROR 42000: Key column 'foo' doesn't exist in table +ALTER TABLE bug44571 ADD INDEX bug44571b (bar); +ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it +CREATE INDEX bug44571b ON bug44571 (bar); +ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it +DROP TABLE bug44571; diff --git a/mysql-test/suite/innodb/t/innodb_bug44571.test b/mysql-test/suite/innodb/t/innodb_bug44571.test new file mode 100644 index 00000000000..43f290cde84 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug44571.test @@ -0,0 +1,18 @@ +# +# Bug#44571 InnoDB Plugin crashes on ADD INDEX +# http://bugs.mysql.com/44571 +# +-- source include/have_innodb.inc +-- source suite/innodb/include/have_innodb_plugin.inc + +CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; +ALTER TABLE bug44571 CHANGE foo bar INT; +-- error ER_KEY_COLUMN_DOES_NOT_EXITS +ALTER TABLE bug44571 ADD INDEX bug44571b (foo); +# The following will fail, because the CHANGE foo bar was +# not communicated to InnoDB. +--error ER_NOT_KEYFILE +ALTER TABLE bug44571 ADD INDEX bug44571b (bar); +--error ER_NOT_KEYFILE +CREATE INDEX bug44571b ON bug44571 (bar); +DROP TABLE bug44571; diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index b488b21c768..df71a1c25a5 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,37 @@ +2009-08-27 The InnoDB Team + + * dict/dict0dict.c, include/dict0dict.h, + mysql-test/innodb_bug44571.result, mysql-test/innodb_bug44571.test: + Fix Bug#44571 InnoDB Plugin crashes on ADD INDEX + +2009-08-27 The InnoDB Team + + * row/row0merge.c: + Fix a bug in the merge sort that can corrupt indexes in fast index + creation. Add some consistency checks. Check that the number of + records remains constant in every merge sort pass. + +2009-08-27 The InnoDB Team + + * buf/buf0buf.c, buf/buf0lru.c, buf/buf0rea.c, + handler/ha_innodb.cc, include/buf0buf.h, include/buf0buf.ic, + include/buf0lru.h, include/ut0ut.h, ut/ut0ut.c: + Make it possible to tune the buffer pool LRU eviction policy to be + more resistant against index scans. Introduce the settable global + variables innodb_old_blocks_pct and innodb_old_blocks_time for + controlling the buffer pool eviction policy. The parameter + innodb_old_blocks_pct (5..95) controls the desired amount of "old" + blocks in the LRU list. The default is 37, corresponding to the + old fixed ratio of 3/8. Each time a block is accessed, it will be + moved to the "new" blocks if its first access was at least + innodb_old_blocks_time milliseconds ago (default 0, meaning every + block). The idea is that in index scans, blocks will be accessed + a few times within innodb_old_blocks_time, and they will remain in + the "old" section of the LRU list. Thus, when + innodb_old_blocks_time is nonzero, blocks retrieved for one-time + index scans will be more likely candidates for eviction than + blocks that are accessed in random patterns. + 2009-08-26 The InnoDB Team * handler/ha_innodb.cc, os/os0file.c: diff --git a/storage/innodb_plugin/btr/btr0sea.c b/storage/innodb_plugin/btr/btr0sea.c index faa1c13897e..0a80c61a58d 100644 --- a/storage/innodb_plugin/btr/btr0sea.c +++ b/storage/innodb_plugin/btr/btr0sea.c @@ -957,7 +957,7 @@ btr_search_guess_on_hash( /* Increment the page get statistics though we did not really fix the page: for user info only */ - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; return(TRUE); diff --git a/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c index 0008fcb1271..6af3dff460a 100644 --- a/storage/innodb_plugin/buf/buf0buf.c +++ b/storage/innodb_plugin/buf/buf0buf.c @@ -837,16 +837,35 @@ buf_chunk_not_freed( block = chunk->blocks; for (i = chunk->size; i--; block++) { - mutex_enter(&block->mutex); - - if (buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE - && !buf_flush_ready_for_replace(&block->page)) { + ibool ready; + switch (buf_block_get_state(block)) { + case BUF_BLOCK_ZIP_FREE: + case BUF_BLOCK_ZIP_PAGE: + case BUF_BLOCK_ZIP_DIRTY: + /* The uncompressed buffer pool should never + contain compressed block descriptors. */ + ut_error; + break; + case BUF_BLOCK_NOT_USED: + case BUF_BLOCK_READY_FOR_USE: + case BUF_BLOCK_MEMORY: + case BUF_BLOCK_REMOVE_HASH: + /* Skip blocks that are not being used for + file pages. */ + break; + case BUF_BLOCK_FILE_PAGE: + mutex_enter(&block->mutex); + ready = buf_flush_ready_for_replace(&block->page); mutex_exit(&block->mutex); - return(block); - } - mutex_exit(&block->mutex); + if (!ready) { + + return(block); + } + + break; + } } return(NULL); @@ -966,8 +985,6 @@ buf_pool_init(void) buf_pool->no_flush[i] = os_event_create(NULL); } - buf_pool->ulint_clock = 1; - /* 3. Initialize LRU fields --------------------------- */ /* All fields are initialized by mem_zalloc(). */ @@ -1470,31 +1487,6 @@ buf_pool_resize(void) buf_pool_page_hash_rebuild(); } -/********************************************************************//** -Moves the block to the start of the LRU list if there is a danger -that the block would drift out of the buffer pool. */ -UNIV_INLINE -void -buf_block_make_young( -/*=================*/ - buf_page_t* bpage) /*!< in: block to make younger */ -{ - ut_ad(!buf_pool_mutex_own()); - - /* Note that we read freed_page_clock's without holding any mutex: - this is allowed since the result is used only in heuristics */ - - if (buf_page_peek_if_too_old(bpage)) { - - buf_pool_mutex_enter(); - /* There has been freeing activity in the LRU list: - best to move to the head of the LRU list */ - - buf_LRU_make_block_young(bpage); - buf_pool_mutex_exit(); - } -} - /********************************************************************//** Moves a page to the start of the buffer pool LRU list. This high-level function can be used to prevent an important page from from slipping out of @@ -1649,7 +1641,7 @@ buf_page_get_zip( #ifndef UNIV_LOG_DEBUG ut_ad(!ibuf_inside()); #endif - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; for (;;) { buf_pool_mutex_enter(); @@ -1713,14 +1705,16 @@ err_exit: got_block: must_read = buf_page_get_io_fix(bpage) == BUF_IO_READ; + if (buf_page_peek_if_too_old(bpage)) { + buf_LRU_make_block_young(bpage); + } + + buf_page_set_accessed(bpage); + buf_pool_mutex_exit(); - buf_page_set_accessed(bpage, TRUE); - mutex_exit(block_mutex); - buf_block_make_young(bpage); - #ifdef UNIV_DEBUG_FILE_ACCESSES ut_a(!bpage->file_page_was_freed); #endif @@ -2000,7 +1994,7 @@ buf_page_get_gen( mtr_t* mtr) /*!< in: mini-transaction */ { buf_block_t* block; - ibool accessed; + unsigned access_time; ulint fix_type; ibool must_read; @@ -2016,7 +2010,7 @@ buf_page_get_gen( #ifndef UNIV_LOG_DEBUG ut_ad(!ibuf_inside() || ibuf_page(space, zip_size, offset, NULL)); #endif - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; loop: block = guess; buf_pool_mutex_enter(); @@ -2243,17 +2237,20 @@ wait_until_unfixed: UNIV_MEM_ASSERT_RW(&block->page, sizeof block->page); buf_block_buf_fix_inc(block, file, line); - buf_pool_mutex_exit(); - - /* Check if this is the first access to the page */ - - accessed = buf_page_is_accessed(&block->page); - - buf_page_set_accessed(&block->page, TRUE); mutex_exit(&block->mutex); - buf_block_make_young(&block->page); + /* Check if this is the first access to the page */ + + access_time = buf_page_is_accessed(&block->page); + + if (buf_page_peek_if_too_old(&block->page)) { + buf_LRU_make_block_young(&block->page); + } + + buf_page_set_accessed(&block->page); + + buf_pool_mutex_exit(); #ifdef UNIV_DEBUG_FILE_ACCESSES ut_a(!block->page.file_page_was_freed); @@ -2306,7 +2303,7 @@ wait_until_unfixed: mtr_memo_push(mtr, block, fix_type); - if (!accessed) { + if (!access_time) { /* In the case of a first access, try to apply linear read-ahead */ @@ -2336,7 +2333,7 @@ buf_page_optimistic_get_func( ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mini-transaction */ { - ibool accessed; + unsigned access_time; ibool success; ulint fix_type; @@ -2353,14 +2350,21 @@ buf_page_optimistic_get_func( } buf_block_buf_fix_inc(block, file, line); - accessed = buf_page_is_accessed(&block->page); - buf_page_set_accessed(&block->page, TRUE); mutex_exit(&block->mutex); - buf_block_make_young(&block->page); + buf_pool_mutex_enter(); /* Check if this is the first access to the page */ + access_time = buf_page_is_accessed(&block->page); + + if (buf_page_peek_if_too_old(&block->page)) { + buf_LRU_make_block_young(&block->page); + } + + buf_page_set_accessed(&block->page); + + buf_pool_mutex_exit(); ut_ad(!ibuf_inside() || ibuf_page(buf_block_get_space(block), @@ -2412,7 +2416,7 @@ buf_page_optimistic_get_func( #ifdef UNIV_DEBUG_FILE_ACCESSES ut_a(block->page.file_page_was_freed == FALSE); #endif - if (UNIV_UNLIKELY(!accessed)) { + if (UNIV_UNLIKELY(!access_time)) { /* In the case of a first access, try to apply linear read-ahead */ @@ -2425,7 +2429,7 @@ buf_page_optimistic_get_func( ut_a(ibuf_count_get(buf_block_get_space(block), buf_block_get_page_no(block)) == 0); #endif - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; return(TRUE); } @@ -2473,10 +2477,16 @@ buf_page_get_known_nowait( mutex_exit(&block->mutex); - if (mode == BUF_MAKE_YOUNG) { - buf_block_make_young(&block->page); + buf_pool_mutex_enter(); + + if (mode == BUF_MAKE_YOUNG && buf_page_peek_if_too_old(&block->page)) { + buf_LRU_make_block_young(&block->page); } + buf_page_set_accessed(&block->page); + + buf_pool_mutex_exit(); + ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD)); if (rw_latch == RW_S_LATCH) { @@ -2513,7 +2523,7 @@ buf_page_get_known_nowait( || (ibuf_count_get(buf_block_get_space(block), buf_block_get_page_no(block)) == 0)); #endif - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; return(TRUE); } @@ -2589,7 +2599,7 @@ buf_page_try_get_func( #endif /* UNIV_DEBUG_FILE_ACCESSES */ buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK); - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; #ifdef UNIV_IBUF_COUNT_DEBUG ut_a(ibuf_count_get(buf_block_get_space(block), @@ -2608,10 +2618,10 @@ buf_page_init_low( buf_page_t* bpage) /*!< in: block to init */ { bpage->flush_type = BUF_FLUSH_LRU; - bpage->accessed = FALSE; bpage->io_fix = BUF_IO_NONE; bpage->buf_fix_count = 0; bpage->freed_page_clock = 0; + bpage->access_time = 0; bpage->newest_modification = 0; bpage->oldest_modification = 0; HASH_INVALIDATE(bpage, hash); @@ -2953,7 +2963,7 @@ buf_page_create( buf_LRU_add_block(&block->page, FALSE); buf_block_buf_fix_inc(block, __FILE__, __LINE__); - buf_pool->n_pages_created++; + buf_pool->stat.n_pages_created++; if (zip_size) { void* data; @@ -2990,12 +3000,12 @@ buf_page_create( rw_lock_x_unlock(&block->lock); } + buf_page_set_accessed(&block->page); + buf_pool_mutex_exit(); mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX); - buf_page_set_accessed(&block->page, TRUE); - mutex_exit(&block->mutex); /* Delete possible entries for the page from the insert buffer: @@ -3201,7 +3211,7 @@ corrupt: ut_ad(buf_pool->n_pend_reads > 0); buf_pool->n_pend_reads--; - buf_pool->n_pages_read++; + buf_pool->stat.n_pages_read++; if (uncompressed) { rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock, @@ -3221,7 +3231,7 @@ corrupt: BUF_IO_WRITE); } - buf_pool->n_pages_written++; + buf_pool->stat.n_pages_written++; break; @@ -3528,6 +3538,7 @@ buf_print(void) "n pending decompressions %lu\n" "n pending reads %lu\n" "n pending flush LRU %lu list %lu single page %lu\n" + "pages made young %lu, not young %lu\n" "pages read %lu, created %lu, written %lu\n", (ulong) size, (ulong) UT_LIST_GET_LEN(buf_pool->LRU), @@ -3538,8 +3549,11 @@ buf_print(void) (ulong) buf_pool->n_flush[BUF_FLUSH_LRU], (ulong) buf_pool->n_flush[BUF_FLUSH_LIST], (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE], - (ulong) buf_pool->n_pages_read, buf_pool->n_pages_created, - (ulong) buf_pool->n_pages_written); + (ulong) buf_pool->stat.n_pages_made_young, + (ulong) buf_pool->stat.n_pages_not_made_young, + (ulong) buf_pool->stat.n_pages_read, + (ulong) buf_pool->stat.n_pages_created, + (ulong) buf_pool->stat.n_pages_written); /* Count the number of blocks belonging to each index in the buffer */ @@ -3744,10 +3758,9 @@ buf_print_io( { time_t current_time; double time_elapsed; - ulint size; + ulint n_gets_diff; ut_ad(buf_pool); - size = buf_pool->curr_size; buf_pool_mutex_enter(); @@ -3755,12 +3768,14 @@ buf_print_io( "Buffer pool size %lu\n" "Free buffers %lu\n" "Database pages %lu\n" + "Old database pages %lu\n" "Modified db pages %lu\n" "Pending reads %lu\n" "Pending writes: LRU %lu, flush list %lu, single page %lu\n", - (ulong) size, + (ulong) buf_pool->curr_size, (ulong) UT_LIST_GET_LEN(buf_pool->free), (ulong) UT_LIST_GET_LEN(buf_pool->LRU), + (ulong) buf_pool->LRU_old_len, (ulong) UT_LIST_GET_LEN(buf_pool->flush_list), (ulong) buf_pool->n_pend_reads, (ulong) buf_pool->n_flush[BUF_FLUSH_LRU] @@ -3772,37 +3787,66 @@ buf_print_io( current_time = time(NULL); time_elapsed = 0.001 + difftime(current_time, buf_pool->last_printout_time); - buf_pool->last_printout_time = current_time; fprintf(file, + "Pages made young %lu, not young %lu\n" + "%.2f youngs/s, %.2f non-youngs/s\n" "Pages read %lu, created %lu, written %lu\n" "%.2f reads/s, %.2f creates/s, %.2f writes/s\n", - (ulong) buf_pool->n_pages_read, - (ulong) buf_pool->n_pages_created, - (ulong) buf_pool->n_pages_written, - (buf_pool->n_pages_read - buf_pool->n_pages_read_old) + (ulong) buf_pool->stat.n_pages_made_young, + (ulong) buf_pool->stat.n_pages_not_made_young, + (buf_pool->stat.n_pages_made_young + - buf_pool->old_stat.n_pages_made_young) / time_elapsed, - (buf_pool->n_pages_created - buf_pool->n_pages_created_old) + (buf_pool->stat.n_pages_not_made_young + - buf_pool->old_stat.n_pages_not_made_young) / time_elapsed, - (buf_pool->n_pages_written - buf_pool->n_pages_written_old) + (ulong) buf_pool->stat.n_pages_read, + (ulong) buf_pool->stat.n_pages_created, + (ulong) buf_pool->stat.n_pages_written, + (buf_pool->stat.n_pages_read + - buf_pool->old_stat.n_pages_read) + / time_elapsed, + (buf_pool->stat.n_pages_created + - buf_pool->old_stat.n_pages_created) + / time_elapsed, + (buf_pool->stat.n_pages_written + - buf_pool->old_stat.n_pages_written) / time_elapsed); - if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) { - fprintf(file, "Buffer pool hit rate %lu / 1000\n", + n_gets_diff = buf_pool->stat.n_page_gets - buf_pool->old_stat.n_page_gets; + + if (n_gets_diff) { + fprintf(file, + "Buffer pool hit rate %lu / 1000," + " young-making rate %lu / 1000 not %lu / 1000\n", (ulong) - (1000 - ((1000 * (buf_pool->n_pages_read - - buf_pool->n_pages_read_old)) - / (buf_pool->n_page_gets - - buf_pool->n_page_gets_old)))); + (1000 - ((1000 * (buf_pool->stat.n_pages_read + - buf_pool->old_stat.n_pages_read)) + / (buf_pool->stat.n_page_gets + - buf_pool->old_stat.n_page_gets))), + (ulong) + (1000 * (buf_pool->stat.n_pages_made_young + - buf_pool->old_stat.n_pages_made_young) + / n_gets_diff), + (ulong) + (1000 * (buf_pool->stat.n_pages_not_made_young + - buf_pool->old_stat.n_pages_not_made_young) + / n_gets_diff)); } else { fputs("No buffer pool page gets since the last printout\n", file); } - buf_pool->n_page_gets_old = buf_pool->n_page_gets; - buf_pool->n_pages_read_old = buf_pool->n_pages_read; - buf_pool->n_pages_created_old = buf_pool->n_pages_created; - buf_pool->n_pages_written_old = buf_pool->n_pages_written; + /* Statistics about read ahead algorithm */ + fprintf(file, "Pages read ahead %.2f/s," + " evicted without access %.2f/s\n", + (buf_pool->stat.n_ra_pages_read + - buf_pool->old_stat.n_ra_pages_read) + / time_elapsed, + (buf_pool->stat.n_ra_pages_evicted + - buf_pool->old_stat.n_ra_pages_evicted) + / time_elapsed); /* Print some values to help us with visualizing what is happening with LRU eviction. */ @@ -3814,6 +3858,7 @@ buf_print_io( buf_LRU_stat_sum.io, buf_LRU_stat_cur.io, buf_LRU_stat_sum.unzip, buf_LRU_stat_cur.unzip); + buf_refresh_io_stats(); buf_pool_mutex_exit(); } @@ -3825,10 +3870,7 @@ buf_refresh_io_stats(void) /*======================*/ { buf_pool->last_printout_time = time(NULL); - buf_pool->n_page_gets_old = buf_pool->n_page_gets; - buf_pool->n_pages_read_old = buf_pool->n_pages_read; - buf_pool->n_pages_created_old = buf_pool->n_pages_created; - buf_pool->n_pages_written_old = buf_pool->n_pages_written; + buf_pool->old_stat = buf_pool->stat; } /*********************************************************************//** diff --git a/storage/innodb_plugin/buf/buf0lru.c b/storage/innodb_plugin/buf/buf0lru.c index be53a5f5d9d..223746e0d01 100644 --- a/storage/innodb_plugin/buf/buf0lru.c +++ b/storage/innodb_plugin/buf/buf0lru.c @@ -49,14 +49,23 @@ Created 11/5/1995 Heikki Tuuri #include "log0recv.h" #include "srv0srv.h" -/** The number of blocks from the LRU_old pointer onward, including the block -pointed to, must be 3/8 of the whole LRU list length, except that the -tolerance defined below is allowed. Note that the tolerance must be small -enough such that for even the BUF_LRU_OLD_MIN_LEN long LRU list, the -LRU_old pointer is not allowed to point to either end of the LRU list. */ +/** The number of blocks from the LRU_old pointer onward, including +the block pointed to, must be buf_LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV +of the whole LRU list length, except that the tolerance defined below +is allowed. Note that the tolerance must be small enough such that for +even the BUF_LRU_OLD_MIN_LEN long LRU list, the LRU_old pointer is not +allowed to point to either end of the LRU list. */ #define BUF_LRU_OLD_TOLERANCE 20 +/** The minimum amount of non-old blocks when the LRU_old list exists +(that is, when there are more than BUF_LRU_OLD_MIN_LEN blocks). +@see buf_LRU_old_adjust_len */ +#define BUF_LRU_NON_OLD_MIN_LEN 5 +#if BUF_LRU_NON_OLD_MIN_LEN >= BUF_LRU_OLD_MIN_LEN +# error "BUF_LRU_NON_OLD_MIN_LEN >= BUF_LRU_OLD_MIN_LEN" +#endif + /** The whole LRU list length is divided by this number to determine an initial segment in buf_LRU_get_recent_limit */ @@ -107,6 +116,15 @@ UNIV_INTERN buf_LRU_stat_t buf_LRU_stat_sum; /* @} */ +/** @name Heuristics for detecting index scan @{ */ +/** Reserve this much/BUF_LRU_OLD_RATIO_DIV of the buffer pool for +"old" blocks. Protected by buf_pool_mutex. */ +UNIV_INTERN uint buf_LRU_old_ratio; +/** Move blocks to "new" LRU list only if the first access was at +least this many milliseconds ago. Not protected by any mutex or latch. */ +UNIV_INTERN uint buf_LRU_old_threshold_ms; +/* @} */ + /******************************************************************//** Takes a block out of the LRU list and page hash table. If the block is compressed-only (BUF_BLOCK_ZIP_PAGE), @@ -428,42 +446,6 @@ next_page: } } -/******************************************************************//** -Gets the minimum LRU_position field for the blocks in an initial segment -(determined by BUF_LRU_INITIAL_RATIO) of the LRU list. The limit is not -guaranteed to be precise, because the ulint_clock may wrap around. -@return the limit; zero if could not determine it */ -UNIV_INTERN -ulint -buf_LRU_get_recent_limit(void) -/*==========================*/ -{ - const buf_page_t* bpage; - ulint len; - ulint limit; - - buf_pool_mutex_enter(); - - len = UT_LIST_GET_LEN(buf_pool->LRU); - - if (len < BUF_LRU_OLD_MIN_LEN) { - /* The LRU list is too short to do read-ahead */ - - buf_pool_mutex_exit(); - - return(0); - } - - bpage = UT_LIST_GET_FIRST(buf_pool->LRU); - - limit = buf_page_get_LRU_position(bpage); - len /= BUF_LRU_INITIAL_RATIO; - - buf_pool_mutex_exit(); - - return(limit > len ? (limit - len) : 0); -} - /********************************************************************//** Insert a compressed block into buf_pool->zip_clean in the LRU order. */ UNIV_INTERN @@ -594,6 +576,7 @@ buf_LRU_free_from_common_LRU_list( bpage = UT_LIST_GET_PREV(LRU, bpage), distance--) { enum buf_lru_free_block_status freed; + unsigned accessed; mutex_t* block_mutex = buf_page_get_mutex(bpage); @@ -601,11 +584,18 @@ buf_LRU_free_from_common_LRU_list( ut_ad(bpage->in_LRU_list); mutex_enter(block_mutex); + accessed = buf_page_is_accessed(bpage); freed = buf_LRU_free_block(bpage, TRUE, NULL); mutex_exit(block_mutex); switch (freed) { case BUF_LRU_FREED: + /* Keep track of pages that are evicted without + ever being accessed. This gives us a measure of + the effectiveness of readahead */ + if (!accessed) { + ++buf_pool->stat.n_ra_pages_evicted; + } return(TRUE); case BUF_LRU_NOT_FREED: @@ -953,8 +943,10 @@ buf_LRU_old_adjust_len(void) ut_a(buf_pool->LRU_old); ut_ad(buf_pool_mutex_own()); -#if 3 * (BUF_LRU_OLD_MIN_LEN / 8) <= BUF_LRU_OLD_TOLERANCE + 5 -# error "3 * (BUF_LRU_OLD_MIN_LEN / 8) <= BUF_LRU_OLD_TOLERANCE + 5" + ut_ad(buf_LRU_old_ratio >= BUF_LRU_OLD_RATIO_MIN); + ut_ad(buf_LRU_old_ratio <= BUF_LRU_OLD_RATIO_MAX); +#if BUF_LRU_OLD_RATIO_MIN * BUF_LRU_OLD_MIN_LEN <= BUF_LRU_OLD_RATIO_DIV * (BUF_LRU_OLD_TOLERANCE + 5) +# error "BUF_LRU_OLD_RATIO_MIN * BUF_LRU_OLD_MIN_LEN <= BUF_LRU_OLD_RATIO_DIV * (BUF_LRU_OLD_TOLERANCE + 5)" #endif #ifdef UNIV_LRU_DEBUG /* buf_pool->LRU_old must be the first item in the LRU list @@ -966,34 +958,39 @@ buf_LRU_old_adjust_len(void) || UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)->old); #endif /* UNIV_LRU_DEBUG */ - for (;;) { - old_len = buf_pool->LRU_old_len; - new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8); + old_len = buf_pool->LRU_old_len; + new_len = ut_min(UT_LIST_GET_LEN(buf_pool->LRU) + * buf_LRU_old_ratio / BUF_LRU_OLD_RATIO_DIV, + UT_LIST_GET_LEN(buf_pool->LRU) + - (BUF_LRU_OLD_TOLERANCE + + BUF_LRU_NON_OLD_MIN_LEN)); - ut_ad(buf_pool->LRU_old->in_LRU_list); - ut_a(buf_pool->LRU_old); + for (;;) { + buf_page_t* LRU_old = buf_pool->LRU_old; + + ut_a(LRU_old); + ut_ad(LRU_old->in_LRU_list); #ifdef UNIV_LRU_DEBUG - ut_a(buf_pool->LRU_old->old); + ut_a(LRU_old->old); #endif /* UNIV_LRU_DEBUG */ /* Update the LRU_old pointer if necessary */ - if (old_len < new_len - BUF_LRU_OLD_TOLERANCE) { + if (old_len + BUF_LRU_OLD_TOLERANCE < new_len) { - buf_pool->LRU_old = UT_LIST_GET_PREV( - LRU, buf_pool->LRU_old); + buf_pool->LRU_old = LRU_old = UT_LIST_GET_PREV( + LRU, LRU_old); #ifdef UNIV_LRU_DEBUG - ut_a(!buf_pool->LRU_old->old); + ut_a(!LRU_old->old); #endif /* UNIV_LRU_DEBUG */ - buf_page_set_old(buf_pool->LRU_old, TRUE); - buf_pool->LRU_old_len++; + buf_page_set_old(LRU_old, TRUE); + old_len = ++buf_pool->LRU_old_len; } else if (old_len > new_len + BUF_LRU_OLD_TOLERANCE) { - buf_page_set_old(buf_pool->LRU_old, FALSE); - buf_pool->LRU_old = UT_LIST_GET_NEXT( - LRU, buf_pool->LRU_old); - buf_pool->LRU_old_len--; + buf_page_set_old(LRU_old, FALSE); + buf_pool->LRU_old = UT_LIST_GET_NEXT(LRU, LRU_old); + old_len = --buf_pool->LRU_old_len; } else { return; } @@ -1021,6 +1018,7 @@ buf_LRU_old_init(void) while (bpage != NULL) { ut_ad(bpage->in_LRU_list); + ut_ad(buf_page_in_file(bpage)); buf_page_set_old(bpage, TRUE); bpage = UT_LIST_GET_NEXT(LRU, bpage); } @@ -1075,16 +1073,19 @@ buf_LRU_remove_block( if (UNIV_UNLIKELY(bpage == buf_pool->LRU_old)) { - /* Below: the previous block is guaranteed to exist, because - the LRU_old pointer is only allowed to differ by the - tolerance value from strict 3/8 of the LRU list length. */ + /* Below: the previous block is guaranteed to exist, + because the LRU_old pointer is only allowed to differ + by BUF_LRU_OLD_TOLERANCE from strict + buf_LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV of the LRU + list length. */ + buf_page_t* prev_bpage = UT_LIST_GET_PREV(LRU, bpage); - buf_pool->LRU_old = UT_LIST_GET_PREV(LRU, bpage); - ut_a(buf_pool->LRU_old); + ut_a(prev_bpage); #ifdef UNIV_LRU_DEBUG - ut_a(!buf_pool->LRU_old->old); + ut_a(!prev_bpage->old); #endif /* UNIV_LRU_DEBUG */ - buf_page_set_old(buf_pool->LRU_old, TRUE); + buf_pool->LRU_old = prev_bpage; + buf_page_set_old(prev_bpage, TRUE); buf_pool->LRU_old_len++; } @@ -1149,39 +1150,25 @@ buf_LRU_add_block_to_end_low( /*=========================*/ buf_page_t* bpage) /*!< in: control block */ { - buf_page_t* last_bpage; - ut_ad(buf_pool); ut_ad(bpage); ut_ad(buf_pool_mutex_own()); ut_a(buf_page_in_file(bpage)); - last_bpage = UT_LIST_GET_LAST(buf_pool->LRU); - - if (last_bpage) { - bpage->LRU_position = last_bpage->LRU_position; - } else { - bpage->LRU_position = buf_pool_clock_tic(); - } - ut_ad(!bpage->in_LRU_list); UT_LIST_ADD_LAST(LRU, buf_pool->LRU, bpage); ut_d(bpage->in_LRU_list = TRUE); buf_page_set_old(bpage, TRUE); - if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) { - - buf_pool->LRU_old_len++; - } - if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) { ut_ad(buf_pool->LRU_old); /* Adjust the length of the old block list if necessary */ + buf_pool->LRU_old_len++; buf_LRU_old_adjust_len(); } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) { @@ -1189,6 +1176,7 @@ buf_LRU_add_block_to_end_low( /* The LRU list is now long enough for LRU_old to become defined: init it */ + buf_pool->LRU_old_len++; buf_LRU_old_init(); } @@ -1222,7 +1210,6 @@ buf_LRU_add_block_low( UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, bpage); - bpage->LRU_position = buf_pool_clock_tic(); bpage->freed_page_clock = buf_pool->freed_page_clock; } else { #ifdef UNIV_LRU_DEBUG @@ -1237,11 +1224,6 @@ buf_LRU_add_block_low( UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, buf_pool->LRU_old, bpage); buf_pool->LRU_old_len++; - - /* We copy the LRU position field of the previous block - to the new block */ - - bpage->LRU_position = (buf_pool->LRU_old)->LRU_position; } ut_d(bpage->in_LRU_list = TRUE); @@ -1295,6 +1277,9 @@ buf_LRU_make_block_young( /*=====================*/ buf_page_t* bpage) /*!< in: control block */ { + ut_ad(buf_pool_mutex_own()); + buf_pool->stat.n_pages_made_young++; + buf_LRU_remove_block(bpage); buf_LRU_add_block_low(bpage, FALSE); } @@ -1847,6 +1832,48 @@ buf_LRU_block_free_hashed_page( buf_LRU_block_free_non_file_page(block); } +/**********************************************************************//** +Updates buf_LRU_old_ratio. +@return updated old_pct */ +UNIV_INTERN +uint +buf_LRU_old_ratio_update( +/*=====================*/ + uint old_pct,/*!< in: Reserve this percentage of + the buffer pool for "old" blocks. */ + ibool adjust) /*!< in: TRUE=adjust the LRU list; + FALSE=just assign buf_LRU_old_ratio + during the initialization of InnoDB */ +{ + uint ratio; + + ratio = old_pct * BUF_LRU_OLD_RATIO_DIV / 100; + if (ratio < BUF_LRU_OLD_RATIO_MIN) { + ratio = BUF_LRU_OLD_RATIO_MIN; + } else if (ratio > BUF_LRU_OLD_RATIO_MAX) { + ratio = BUF_LRU_OLD_RATIO_MAX; + } + + if (adjust) { + buf_pool_mutex_enter(); + + if (ratio != buf_LRU_old_ratio) { + buf_LRU_old_ratio = ratio; + + if (UT_LIST_GET_LEN(buf_pool->LRU) + >= BUF_LRU_OLD_MIN_LEN) { + buf_LRU_old_adjust_len(); + } + } + + buf_pool_mutex_exit(); + } else { + buf_LRU_old_ratio = ratio; + } + + return(ratio * 100 / BUF_LRU_OLD_RATIO_DIV); +} + /********************************************************************//** Update the historical stats that we are collecting for LRU eviction policy at the end of each interval. */ @@ -1896,7 +1923,6 @@ buf_LRU_validate(void) buf_block_t* block; ulint old_len; ulint new_len; - ulint LRU_pos; ut_ad(buf_pool); buf_pool_mutex_enter(); @@ -1905,7 +1931,11 @@ buf_LRU_validate(void) ut_a(buf_pool->LRU_old); old_len = buf_pool->LRU_old_len; - new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8); + new_len = ut_min(UT_LIST_GET_LEN(buf_pool->LRU) + * buf_LRU_old_ratio / BUF_LRU_OLD_RATIO_DIV, + UT_LIST_GET_LEN(buf_pool->LRU) + - (BUF_LRU_OLD_TOLERANCE + + BUF_LRU_NON_OLD_MIN_LEN)); ut_a(old_len >= new_len - BUF_LRU_OLD_TOLERANCE); ut_a(old_len <= new_len + BUF_LRU_OLD_TOLERANCE); } @@ -1943,16 +1973,7 @@ buf_LRU_validate(void) ut_a(buf_pool->LRU_old == bpage); } - LRU_pos = buf_page_get_LRU_position(bpage); - bpage = UT_LIST_GET_NEXT(LRU, bpage); - - if (bpage) { - /* If the following assert fails, it may - not be an error: just the buf_pool clock - has wrapped around */ - ut_a(LRU_pos >= buf_page_get_LRU_position(bpage)); - } } if (buf_pool->LRU_old) { @@ -2000,9 +2021,6 @@ buf_LRU_print(void) ut_ad(buf_pool); buf_pool_mutex_enter(); - fprintf(stderr, "Pool ulint clock %lu\n", - (ulong) buf_pool->ulint_clock); - bpage = UT_LIST_GET_FIRST(buf_pool->LRU); while (bpage != NULL) { @@ -2033,18 +2051,16 @@ buf_LRU_print(void) const byte* frame; case BUF_BLOCK_FILE_PAGE: frame = buf_block_get_frame((buf_block_t*) bpage); - fprintf(stderr, "\nLRU pos %lu type %lu" + fprintf(stderr, "\ntype %lu" " index id %lu\n", - (ulong) buf_page_get_LRU_position(bpage), (ulong) fil_page_get_type(frame), (ulong) ut_dulint_get_low( btr_page_get_index_id(frame))); break; case BUF_BLOCK_ZIP_PAGE: frame = bpage->zip.data; - fprintf(stderr, "\nLRU pos %lu type %lu size %lu" + fprintf(stderr, "\ntype %lu size %lu" " index id %lu\n", - (ulong) buf_page_get_LRU_position(bpage), (ulong) fil_page_get_type(frame), (ulong) buf_page_get_zip_size(bpage), (ulong) ut_dulint_get_low( @@ -2052,8 +2068,7 @@ buf_LRU_print(void) break; default: - fprintf(stderr, "\nLRU pos %lu !state %lu!\n", - (ulong) buf_page_get_LRU_position(bpage), + fprintf(stderr, "\n!state %lu!\n", (ulong) buf_page_get_state(bpage)); break; } diff --git a/storage/innodb_plugin/buf/buf0rea.c b/storage/innodb_plugin/buf/buf0rea.c index 4910f82ccde..dd98ea17eb5 100644 --- a/storage/innodb_plugin/buf/buf0rea.c +++ b/storage/innodb_plugin/buf/buf0rea.c @@ -38,14 +38,6 @@ Created 11/5/1995 Heikki Tuuri #include "srv0start.h" #include "srv0srv.h" -/** The size in blocks of the area where the random read-ahead algorithm counts -the accessed pages when deciding whether to read-ahead */ -#define BUF_READ_AHEAD_RANDOM_AREA BUF_READ_AHEAD_AREA - -/** There must be at least this many pages in buf_pool in the area to start -a random read-ahead */ -#define BUF_READ_AHEAD_RANDOM_THRESHOLD (1 + BUF_READ_AHEAD_RANDOM_AREA / 2) - /** The linear read-ahead area size */ #define BUF_READ_AHEAD_LINEAR_AREA BUF_READ_AHEAD_AREA @@ -62,7 +54,8 @@ flag is cleared and the x-lock released by an i/o-handler thread. @return 1 if a read request was queued, 0 if the page already resided in buf_pool, or if the page is in the doublewrite buffer blocks in which case it is never read into the pool, or if the tablespace does -not exist or is being dropped */ +not exist or is being dropped +@return 1 if read request is issued. 0 if it is not */ static ulint buf_read_page_low( @@ -164,175 +157,14 @@ buf_read_page_low( return(1); } -/********************************************************************//** -Applies a random read-ahead in buf_pool if there are at least a threshold -value of accessed pages from the random read-ahead area. Does not read any -page, not even the one at the position (space, offset), if the read-ahead -mechanism is not activated. NOTE 1: the calling thread may own latches on -pages: to avoid deadlocks this function must be written such that it cannot -end up waiting for these latches! NOTE 2: the calling thread must want -access to the page given: this rule is set to prevent unintended read-aheads -performed by ibuf routines, a situation which could result in a deadlock if -the OS does not support asynchronous i/o. -@return number of page read requests issued; NOTE that if we read ibuf -pages, it may happen that the page at the given page number does not -get read even if we return a positive value! */ -static -ulint -buf_read_ahead_random( -/*==================*/ - ulint space, /*!< in: space id */ - ulint zip_size,/*!< in: compressed page size in bytes, or 0 */ - ulint offset) /*!< in: page number of a page which the current thread - wants to access */ -{ - ib_int64_t tablespace_version; - ulint recent_blocks = 0; - ulint count; - ulint LRU_recent_limit; - ulint ibuf_mode; - ulint low, high; - ulint err; - ulint i; - ulint buf_read_ahead_random_area; - - /* We have currently disabled random readahead */ - return(0); - - if (srv_startup_is_before_trx_rollback_phase) { - /* No read-ahead to avoid thread deadlocks */ - return(0); - } - - if (ibuf_bitmap_page(zip_size, offset) - || trx_sys_hdr_page(space, offset)) { - - /* If it is an ibuf bitmap page or trx sys hdr, we do - no read-ahead, as that could break the ibuf page access - order */ - - return(0); - } - - /* Remember the tablespace version before we ask te tablespace size - below: if DISCARD + IMPORT changes the actual .ibd file meanwhile, we - do not try to read outside the bounds of the tablespace! */ - - tablespace_version = fil_space_get_version(space); - - buf_read_ahead_random_area = BUF_READ_AHEAD_RANDOM_AREA; - - low = (offset / buf_read_ahead_random_area) - * buf_read_ahead_random_area; - high = (offset / buf_read_ahead_random_area + 1) - * buf_read_ahead_random_area; - if (high > fil_space_get_size(space)) { - - high = fil_space_get_size(space); - } - - /* Get the minimum LRU_position field value for an initial segment - of the LRU list, to determine which blocks have recently been added - to the start of the list. */ - - LRU_recent_limit = buf_LRU_get_recent_limit(); - - buf_pool_mutex_enter(); - - if (buf_pool->n_pend_reads - > buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) { - buf_pool_mutex_exit(); - - return(0); - } - - /* Count how many blocks in the area have been recently accessed, - that is, reside near the start of the LRU list. */ - - for (i = low; i < high; i++) { - const buf_page_t* bpage = buf_page_hash_get(space, i); - - if (bpage - && buf_page_is_accessed(bpage) - && (buf_page_get_LRU_position(bpage) > LRU_recent_limit)) { - - recent_blocks++; - - if (recent_blocks >= BUF_READ_AHEAD_RANDOM_THRESHOLD) { - - buf_pool_mutex_exit(); - goto read_ahead; - } - } - } - - buf_pool_mutex_exit(); - /* Do nothing */ - return(0); - -read_ahead: - /* Read all the suitable blocks within the area */ - - if (ibuf_inside()) { - ibuf_mode = BUF_READ_IBUF_PAGES_ONLY; - } else { - ibuf_mode = BUF_READ_ANY_PAGE; - } - - count = 0; - - for (i = low; i < high; i++) { - /* It is only sensible to do read-ahead in the non-sync aio - mode: hence FALSE as the first parameter */ - - if (!ibuf_bitmap_page(zip_size, i)) { - count += buf_read_page_low( - &err, FALSE, - ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER, - space, zip_size, FALSE, - tablespace_version, i); - if (err == DB_TABLESPACE_DELETED) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Warning: in random" - " readahead trying to access\n" - "InnoDB: tablespace %lu page %lu,\n" - "InnoDB: but the tablespace does not" - " exist or is just being dropped.\n", - (ulong) space, (ulong) i); - } - } - } - - /* In simulated aio we wake the aio handler threads only after - queuing all aio requests, in native aio the following call does - nothing: */ - - os_aio_simulated_wake_handler_threads(); - -#ifdef UNIV_DEBUG - if (buf_debug_prints && (count > 0)) { - fprintf(stderr, - "Random read-ahead space %lu offset %lu pages %lu\n", - (ulong) space, (ulong) offset, - (ulong) count); - } -#endif /* UNIV_DEBUG */ - - ++srv_read_ahead_rnd; - return(count); -} - /********************************************************************//** High-level function which reads a page asynchronously from a file to the buffer buf_pool if it is not already there. Sets the io_fix flag and sets an exclusive lock on the buffer frame. The flag is cleared and the x-lock -released by the i/o-handler thread. Does a random read-ahead if it seems -sensible. -@return number of page read requests issued: this can be greater than -1 if read-ahead occurred */ +released by the i/o-handler thread. +@return TRUE if page has been read in, FALSE in case of failure */ UNIV_INTERN -ulint +ibool buf_read_page( /*==========*/ ulint space, /*!< in: space id */ @@ -341,20 +173,17 @@ buf_read_page( { ib_int64_t tablespace_version; ulint count; - ulint count2; ulint err; tablespace_version = fil_space_get_version(space); - count = buf_read_ahead_random(space, zip_size, offset); - /* We do the i/o in the synchronous aio mode to save thread switches: hence TRUE */ - count2 = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space, - zip_size, FALSE, - tablespace_version, offset); - srv_buf_pool_reads+= count2; + count = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space, + zip_size, FALSE, + tablespace_version, offset); + srv_buf_pool_reads += count; if (err == DB_TABLESPACE_DELETED) { ut_print_timestamp(stderr); fprintf(stderr, @@ -371,7 +200,7 @@ buf_read_page( /* Increment number of I/O operations used for LRU policy. */ buf_LRU_stat_inc_io(); - return(count + count2); + return(count > 0); } /********************************************************************//** @@ -498,9 +327,17 @@ buf_read_ahead_linear( fail_count++; } else if (pred_bpage) { - int res = (ut_ulint_cmp( - buf_page_get_LRU_position(bpage), - buf_page_get_LRU_position(pred_bpage))); + /* Note that buf_page_is_accessed() returns + the time of the first access. If some blocks + of the extent existed in the buffer pool at + the time of a linear access pattern, the first + access times may be nonmonotonic, even though + the latest access times were linear. The + threshold (srv_read_ahead_factor) should help + a little against this. */ + int res = ut_ulint_cmp( + buf_page_is_accessed(bpage), + buf_page_is_accessed(pred_bpage)); /* Accesses not in the right order */ if (res != 0 && res != asc_or_desc) { fail_count++; @@ -643,7 +480,7 @@ buf_read_ahead_linear( LRU policy decision. */ buf_LRU_stat_inc_io(); - ++srv_read_ahead_seq; + buf_pool->stat.n_ra_pages_read += count; return(count); } diff --git a/storage/innodb_plugin/dict/dict0dict.c b/storage/innodb_plugin/dict/dict0dict.c index d1f0e0ffc19..a8ee593e35c 100644 --- a/storage/innodb_plugin/dict/dict0dict.c +++ b/storage/innodb_plugin/dict/dict0dict.c @@ -82,9 +82,10 @@ static char dict_ibfk[] = "_ibfk_"; /*******************************************************************//** Tries to find column names for the index and sets the col field of the -index. */ +index. +@return TRUE if the column names were found */ static -void +ibool dict_index_find_cols( /*=================*/ dict_table_t* table, /*!< in: table */ @@ -1431,7 +1432,7 @@ add_field_size: /**********************************************************************//** Adds an index to the dictionary cache. -@return DB_SUCCESS or DB_TOO_BIG_RECORD */ +@return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */ UNIV_INTERN ulint dict_index_add_to_cache( @@ -1457,7 +1458,10 @@ dict_index_add_to_cache( ut_a(!dict_index_is_clust(index) || UT_LIST_GET_LEN(table->indexes) == 0); - dict_index_find_cols(table, index); + if (!dict_index_find_cols(table, index)) { + + return(DB_CORRUPTION); + } /* Build the cache internal representation of the index, containing also the added system fields */ @@ -1665,9 +1669,10 @@ dict_index_remove_from_cache( /*******************************************************************//** Tries to find column names for the index and sets the col field of the -index. */ +index. +@return TRUE if the column names were found */ static -void +ibool dict_index_find_cols( /*=================*/ dict_table_t* table, /*!< in: table */ @@ -1692,17 +1697,21 @@ dict_index_find_cols( } } +#ifdef UNIV_DEBUG /* It is an error not to find a matching column. */ fputs("InnoDB: Error: no matching column for ", stderr); ut_print_name(stderr, NULL, FALSE, field->name); fputs(" in ", stderr); dict_index_name_print(stderr, NULL, index); fputs("!\n", stderr); - ut_error; +#endif /* UNIV_DEBUG */ + return(FALSE); found: ; } + + return(TRUE); } #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 616c227ae0c..d279f0ba4f3 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -72,6 +72,7 @@ with this program; if not, write to the Free Software Foundation, Inc., /* Include necessary InnoDB headers */ extern "C" { #include "univ.i" +#include "buf0lru.h" #include "btr0sea.h" #include "os0file.h" #include "os0thread.h" @@ -152,6 +153,10 @@ static ulong innobase_write_io_threads; static long long innobase_buffer_pool_size, innobase_log_file_size; +/** Percentage of the buffer pool to reserve for 'old' blocks. +Connected to buf_LRU_old_ratio. */ +static uint innobase_old_blocks_pct; + /* The default values for the following char* start-up parameters are determined in innobase_init below: */ @@ -490,10 +495,10 @@ static SHOW_VAR innodb_status_variables[]= { (char*) &export_vars.innodb_buffer_pool_pages_misc, SHOW_LONG}, {"buffer_pool_pages_total", (char*) &export_vars.innodb_buffer_pool_pages_total, SHOW_LONG}, - {"buffer_pool_read_ahead_rnd", - (char*) &export_vars.innodb_buffer_pool_read_ahead_rnd, SHOW_LONG}, - {"buffer_pool_read_ahead_seq", - (char*) &export_vars.innodb_buffer_pool_read_ahead_seq, SHOW_LONG}, + {"buffer_pool_read_ahead", + (char*) &export_vars.innodb_buffer_pool_read_ahead, SHOW_LONG}, + {"buffer_pool_read_ahead_evicted", + (char*) &export_vars.innodb_buffer_pool_read_ahead_evicted, SHOW_LONG}, {"buffer_pool_read_requests", (char*) &export_vars.innodb_buffer_pool_read_requests, SHOW_LONG}, {"buffer_pool_reads", @@ -2204,6 +2209,9 @@ innobase_change_buffering_inited_ok: ut_a(0 == strcmp(my_charset_latin1.name, "latin1_swedish_ci")); srv_latin1_ordering = my_charset_latin1.sort_order; + innobase_old_blocks_pct = buf_LRU_old_ratio_update( + innobase_old_blocks_pct, FALSE); + innobase_commit_concurrency_init_default(); /* Since we in this module access directly the fields of a trx @@ -9610,6 +9618,25 @@ innodb_adaptive_hash_index_update( } } +/****************************************************************//** +Update the system variable innodb_old_blocks_pct using the "saved" +value. This function is registered as a callback with MySQL. */ +static +void +innodb_old_blocks_pct_update( +/*=========================*/ + THD* thd, /*!< in: thread handle */ + struct st_mysql_sys_var* var, /*!< in: pointer to + system variable */ + void* var_ptr,/*!< out: where the + formal string goes */ + const void* save) /*!< in: immediate result + from check function */ +{ + innobase_old_blocks_pct = buf_LRU_old_ratio_update( + *static_cast(save), TRUE); +} + /*************************************************************//** Check if it is a valid value of innodb_change_buffering. This function is registered as a callback with MySQL. @@ -9847,7 +9874,7 @@ static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, NULL, NULL, 500L, 1L, ~0L, 0); static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads, - PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR, "Number of file I/O threads in InnoDB.", NULL, NULL, 4, 4, 64, 0); @@ -9886,6 +9913,18 @@ static MYSQL_SYSVAR_LONG(mirrored_log_groups, innobase_mirrored_log_groups, "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.", NULL, NULL, 1, 1, 10, 0); +static MYSQL_SYSVAR_UINT(old_blocks_pct, innobase_old_blocks_pct, + PLUGIN_VAR_RQCMDARG, + "Percentage of the buffer pool to reserve for 'old' blocks.", + NULL, innodb_old_blocks_pct_update, 100 * 3 / 8, 5, 95, 0); + +static MYSQL_SYSVAR_UINT(old_blocks_time, buf_LRU_old_threshold_ms, + PLUGIN_VAR_RQCMDARG, + "Move blocks to the 'new' end of the buffer pool if the first access" + " was at least this many milliseconds ago." + " The timeout is disabled if 0 (the default).", + NULL, NULL, 0, 0, UINT_MAX32, 0); + static MYSQL_SYSVAR_LONG(open_files, innobase_open_files, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "How many files at the maximum InnoDB keeps open at the same time.", @@ -9984,6 +10023,8 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(adaptive_flushing), MYSQL_SYSVAR(max_purge_lag), MYSQL_SYSVAR(mirrored_log_groups), + MYSQL_SYSVAR(old_blocks_pct), + MYSQL_SYSVAR(old_blocks_time), MYSQL_SYSVAR(open_files), MYSQL_SYSVAR(rollback_on_timeout), MYSQL_SYSVAR(stats_on_metadata), diff --git a/storage/innodb_plugin/include/buf0buf.h b/storage/innodb_plugin/include/buf0buf.h index a24fc4cdbbb..299312e5d10 100644 --- a/storage/innodb_plugin/include/buf0buf.h +++ b/storage/innodb_plugin/include/buf0buf.h @@ -707,15 +707,6 @@ buf_page_belongs_to_unzip_LRU( /*==========================*/ const buf_page_t* bpage) /*!< in: pointer to control block */ __attribute__((pure)); -/*********************************************************************//** -Determine the approximate LRU list position of a block. -@return LRU list position */ -UNIV_INLINE -ulint -buf_page_get_LRU_position( -/*======================*/ - const buf_page_t* bpage) /*!< in: control block */ - __attribute__((pure)); /*********************************************************************//** Gets the mutex of a block. @@ -816,22 +807,22 @@ buf_page_set_old( buf_page_t* bpage, /*!< in/out: control block */ ibool old); /*!< in: old */ /*********************************************************************//** -Determine if a block has been accessed in the buffer pool. -@return TRUE if accessed */ +Determine the time of last access a block in the buffer pool. +@return ut_time_ms() at the time of last access, 0 if not accessed */ UNIV_INLINE -ibool +unsigned buf_page_is_accessed( /*=================*/ const buf_page_t* bpage) /*!< in: control block */ - __attribute__((pure)); + __attribute__((nonnull, pure)); /*********************************************************************//** Flag a block accessed. */ UNIV_INLINE void buf_page_set_accessed( /*==================*/ - buf_page_t* bpage, /*!< in/out: control block */ - ibool accessed); /*!< in: accessed */ + buf_page_t* bpage) /*!< in/out: control block */ + __attribute__((nonnull)); /*********************************************************************//** Gets the buf_block_t handle of a buffered file block if an uncompressed page frame exists, or NULL. @@ -1017,14 +1008,6 @@ buf_block_hash_get( /*===============*/ ulint space, /*!< in: space id */ ulint offset);/*!< in: offset of the page within space */ -/*******************************************************************//** -Increments the pool clock by one and returns its new value. Remember that -in the 32 bit version the clock wraps around at 4 billion! -@return new clock value */ -UNIV_INLINE -ulint -buf_pool_clock_tic(void); -/*====================*/ /*********************************************************************//** Gets the current length of the free list of buffer blocks. @return length of the free list */ @@ -1064,16 +1047,10 @@ struct buf_page_struct{ flushed to disk, this tells the flush_type. @see enum buf_flush */ - unsigned accessed:1; /*!< TRUE if the page has been accessed - while in the buffer pool: read-ahead - may read in pages which have not been - accessed yet; a thread is allowed to - read this for heuristic purposes - without holding any mutex or latch */ unsigned io_fix:2; /*!< type of pending I/O operation; also protected by buf_pool_mutex @see enum buf_io_fix */ - unsigned buf_fix_count:24;/*!< count of how manyfold this block + unsigned buf_fix_count:25;/*!< count of how manyfold this block is currently bufferfixed */ /* @} */ #endif /* !UNIV_HOTBACKUP */ @@ -1152,17 +1129,7 @@ struct buf_page_struct{ #endif /* UNIV_DEBUG */ unsigned old:1; /*!< TRUE if the block is in the old blocks in the LRU list */ - unsigned LRU_position:31;/*!< value which monotonically - decreases (or may stay - constant if old==TRUE) toward - the end of the LRU list, if - buf_pool->ulint_clock has not - wrapped around: NOTE that this - value can only be used in - heuristic algorithms, because - of the possibility of a - wrap-around! */ - unsigned freed_page_clock:32;/*!< the value of + unsigned freed_page_clock:31;/*!< the value of buf_pool->freed_page_clock when this block was the last time put to the head of the @@ -1170,6 +1137,9 @@ struct buf_page_struct{ to read this for heuristic purposes without holding any mutex or latch */ + unsigned access_time:32; /*!< time of first access, or + 0 if the block was never accessed + in the buffer pool */ /* @} */ # ifdef UNIV_DEBUG_FILE_ACCESSES ibool file_page_was_freed; @@ -1314,6 +1284,31 @@ Compute the hash fold value for blocks in buf_pool->zip_hash. */ #define BUF_POOL_ZIP_FOLD_BPAGE(b) BUF_POOL_ZIP_FOLD((buf_block_t*) (b)) /* @} */ +/** @brief The buffer pool statistics structure. */ +struct buf_pool_stat_struct{ + ulint n_page_gets; /*!< number of page gets performed; + also successful searches through + the adaptive hash index are + counted as page gets; this field + is NOT protected by the buffer + pool mutex */ + ulint n_pages_read; /*!< number read operations */ + ulint n_pages_written;/*!< number write operations */ + ulint n_pages_created;/*!< number of pages created + in the pool with no read */ + ulint n_ra_pages_read;/*!< number of pages read in + as part of read ahead */ + ulint n_ra_pages_evicted;/*!< number of read ahead + pages that are evicted without + being accessed */ + ulint n_pages_made_young; /*!< number of pages made young, in + calls to buf_LRU_make_block_young() */ + ulint n_pages_not_made_young; /*!< number of pages not made + young because the first access + was not long enough ago, in + buf_page_peek_if_too_old() */ +}; + /** @brief The buffer pool structure. NOTE! The definition appears here only for other modules of this @@ -1338,28 +1333,16 @@ struct buf_pool_struct{ ulint n_pend_reads; /*!< number of pending read operations */ ulint n_pend_unzip; /*!< number of pending decompressions */ - time_t last_printout_time; /*!< when buf_print was last time + time_t last_printout_time; + /*!< when buf_print_io was last time called */ - ulint n_pages_read; /*!< number read operations */ - ulint n_pages_written;/*!< number write operations */ - ulint n_pages_created;/*!< number of pages created - in the pool with no read */ - ulint n_page_gets; /*!< number of page gets performed; - also successful searches through - the adaptive hash index are - counted as page gets; this field - is NOT protected by the buffer - pool mutex */ - ulint n_page_gets_old;/*!< n_page_gets when buf_print was - last time called: used to calculate - hit rate */ - ulint n_pages_read_old;/*!< n_pages_read when buf_print was - last time called */ - ulint n_pages_written_old;/*!< number write operations */ - ulint n_pages_created_old;/*!< number of pages created in - the pool with no read */ + buf_pool_stat_t stat; /*!< current statistics */ + buf_pool_stat_t old_stat; /*!< old statistics */ + /* @} */ + /** @name Page flushing algorithm fields */ + /* @{ */ UT_LIST_BASE_NODE_T(buf_page_t) flush_list; @@ -1375,10 +1358,6 @@ struct buf_pool_struct{ /*!< this is in the set state when there is no flush batch of the given type running */ - ulint ulint_clock; /*!< a sequence number used to count - time. NOTE! This counter wraps - around at 4 billion (if ulint == - 32 bits)! */ ulint freed_page_clock;/*!< a sequence number used to count the number of buffer blocks removed from the end of @@ -1402,9 +1381,11 @@ struct buf_pool_struct{ block list */ UT_LIST_BASE_NODE_T(buf_page_t) LRU; /*!< base node of the LRU list */ - buf_page_t* LRU_old; /*!< pointer to the about 3/8 oldest - blocks in the LRU list; NULL if LRU - length less than BUF_LRU_OLD_MIN_LEN; + buf_page_t* LRU_old; /*!< pointer to the about + buf_LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV + oldest blocks in the LRU list; + NULL if LRU length less than + BUF_LRU_OLD_MIN_LEN; NOTE: when LRU_old != NULL, its length should always equal LRU_old_len */ ulint LRU_old_len; /*!< length of the LRU list from diff --git a/storage/innodb_plugin/include/buf0buf.ic b/storage/innodb_plugin/include/buf0buf.ic index 17064342116..409d339aa16 100644 --- a/storage/innodb_plugin/include/buf0buf.ic +++ b/storage/innodb_plugin/include/buf0buf.ic @@ -72,9 +72,24 @@ buf_page_peek_if_too_old( /*=====================*/ const buf_page_t* bpage) /*!< in: block to make younger */ { - return(buf_pool->freed_page_clock - >= buf_page_get_freed_page_clock(bpage) - + 1 + (buf_pool->curr_size / 4)); + if (buf_LRU_old_threshold_ms && bpage->old) { + unsigned access_time = buf_page_is_accessed(bpage); + + if (access_time && ut_time_ms() - access_time + >= buf_LRU_old_threshold_ms) { + return(TRUE); + } + + buf_pool->stat.n_pages_not_made_young++; + return(FALSE); + } else { + /* FIXME: bpage->freed_page_clock is 31 bits */ + return((buf_pool->freed_page_clock & ~(1 << 31)) + > bpage->freed_page_clock + + (buf_pool->curr_size + * (BUF_LRU_OLD_RATIO_DIV - buf_LRU_old_ratio) + / (BUF_LRU_OLD_RATIO_DIV * 4))); + } } /*********************************************************************//** @@ -118,22 +133,6 @@ buf_pool_get_oldest_modification(void) return(lsn); } - -/*******************************************************************//** -Increments the buf_pool clock by one and returns its new value. Remember -that in the 32 bit version the clock wraps around at 4 billion! -@return new clock value */ -UNIV_INLINE -ulint -buf_pool_clock_tic(void) -/*====================*/ -{ - ut_ad(buf_pool_mutex_own()); - - buf_pool->ulint_clock++; - - return(buf_pool->ulint_clock); -} #endif /* !UNIV_HOTBACKUP */ /*********************************************************************//** @@ -279,21 +278,6 @@ buf_page_belongs_to_unzip_LRU( && buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE); } -/*********************************************************************//** -Determine the approximate LRU list position of a block. -@return LRU list position */ -UNIV_INLINE -ulint -buf_page_get_LRU_position( -/*======================*/ - const buf_page_t* bpage) /*!< in: control block */ -{ - ut_ad(buf_page_in_file(bpage)); - ut_ad(buf_pool_mutex_own()); - - return(bpage->LRU_position); -} - /*********************************************************************//** Gets the mutex of a block. @return pointer to mutex protecting bpage */ @@ -487,17 +471,17 @@ buf_page_set_old( } /*********************************************************************//** -Determine if a block has been accessed in the buffer pool. -@return TRUE if accessed */ +Determine the time of last access a block in the buffer pool. +@return ut_time_ms() at the time of last access, 0 if not accessed */ UNIV_INLINE -ibool +unsigned buf_page_is_accessed( /*=================*/ const buf_page_t* bpage) /*!< in: control block */ { ut_ad(buf_page_in_file(bpage)); - return(bpage->accessed); + return(bpage->access_time); } /*********************************************************************//** @@ -506,13 +490,15 @@ UNIV_INLINE void buf_page_set_accessed( /*==================*/ - buf_page_t* bpage, /*!< in/out: control block */ - ibool accessed) /*!< in: accessed */ + buf_page_t* bpage) /*!< in/out: control block */ { ut_a(buf_page_in_file(bpage)); - ut_ad(mutex_own(buf_page_get_mutex(bpage))); + ut_ad(buf_pool_mutex_own()); - bpage->accessed = accessed; + if (!bpage->access_time) { + /* Make this the time of the first access. */ + bpage->access_time = ut_time_ms(); + } } /*********************************************************************//** diff --git a/storage/innodb_plugin/include/buf0lru.h b/storage/innodb_plugin/include/buf0lru.h index 463aca0982c..009430af35b 100644 --- a/storage/innodb_plugin/include/buf0lru.h +++ b/storage/innodb_plugin/include/buf0lru.h @@ -69,7 +69,7 @@ These are low-level functions #########################################################################*/ /** Minimum LRU list length for which the LRU_old pointer is defined */ -#define BUF_LRU_OLD_MIN_LEN 80 +#define BUF_LRU_OLD_MIN_LEN 512 /* 8 megabytes of 16k pages */ /** Maximum LRU list search length in buf_flush_LRU_recommendation() */ #define BUF_LRU_FREE_SEARCH_LEN (5 + 2 * BUF_READ_AHEAD_AREA) @@ -84,15 +84,6 @@ void buf_LRU_invalidate_tablespace( /*==========================*/ ulint id); /*!< in: space id */ -/******************************************************************//** -Gets the minimum LRU_position field for the blocks in an initial segment -(determined by BUF_LRU_INITIAL_RATIO) of the LRU list. The limit is not -guaranteed to be precise, because the ulint_clock may wrap around. -@return the limit; zero if could not determine it */ -UNIV_INTERN -ulint -buf_LRU_get_recent_limit(void); -/*==========================*/ /********************************************************************//** Insert a compressed block into buf_pool->zip_clean in the LRU order. */ UNIV_INTERN @@ -201,6 +192,18 @@ void buf_LRU_make_block_old( /*===================*/ buf_page_t* bpage); /*!< in: control block */ +/**********************************************************************//** +Updates buf_LRU_old_ratio. +@return updated old_pct */ +UNIV_INTERN +uint +buf_LRU_old_ratio_update( +/*=====================*/ + uint old_pct,/*!< in: Reserve this percentage of + the buffer pool for "old" blocks. */ + ibool adjust);/*!< in: TRUE=adjust the LRU list; + FALSE=just assign buf_LRU_old_ratio + during the initialization of InnoDB */ /********************************************************************//** Update the historical stats that we are collecting for LRU eviction policy at the end of each interval. */ @@ -227,6 +230,35 @@ buf_LRU_print(void); /*===============*/ #endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */ +/** @name Heuristics for detecting index scan @{ */ +/** Reserve this much/BUF_LRU_OLD_RATIO_DIV of the buffer pool for +"old" blocks. Protected by buf_pool_mutex. */ +extern uint buf_LRU_old_ratio; +/** The denominator of buf_LRU_old_ratio. */ +#define BUF_LRU_OLD_RATIO_DIV 1024 +/** Maximum value of buf_LRU_old_ratio. +@see buf_LRU_old_adjust_len +@see buf_LRU_old_ratio_update */ +#define BUF_LRU_OLD_RATIO_MAX BUF_LRU_OLD_RATIO_DIV +/** Minimum value of buf_LRU_old_ratio. +@see buf_LRU_old_adjust_len +@see buf_LRU_old_ratio_update +The minimum must exceed +(BUF_LRU_OLD_TOLERANCE + 5) * BUF_LRU_OLD_RATIO_DIV / BUF_LRU_OLD_MIN_LEN. */ +#define BUF_LRU_OLD_RATIO_MIN 51 + +#if BUF_LRU_OLD_RATIO_MIN >= BUF_LRU_OLD_RATIO_MAX +# error "BUF_LRU_OLD_RATIO_MIN >= BUF_LRU_OLD_RATIO_MAX" +#endif +#if BUF_LRU_OLD_RATIO_MAX > BUF_LRU_OLD_RATIO_DIV +# error "BUF_LRU_OLD_RATIO_MAX > BUF_LRU_OLD_RATIO_DIV" +#endif + +/** Move blocks to "new" LRU list only if the first access was at +least this many milliseconds ago. Not protected by any mutex or latch. */ +extern uint buf_LRU_old_threshold_ms; +/* @} */ + /** @brief Statistics for selecting the LRU list for eviction. These statistics are not 'of' LRU but 'for' LRU. We keep count of I/O diff --git a/storage/innodb_plugin/include/buf0rea.h b/storage/innodb_plugin/include/buf0rea.h index a3b5685bd91..093750623d6 100644 --- a/storage/innodb_plugin/include/buf0rea.h +++ b/storage/innodb_plugin/include/buf0rea.h @@ -33,12 +33,10 @@ Created 11/5/1995 Heikki Tuuri High-level function which reads a page asynchronously from a file to the buffer buf_pool if it is not already there. Sets the io_fix flag and sets an exclusive lock on the buffer frame. The flag is cleared and the x-lock -released by the i/o-handler thread. Does a random read-ahead if it seems -sensible. -@return number of page read requests issued: this can be greater than -1 if read-ahead occurred */ +released by the i/o-handler thread. +@return TRUE if page has been read in, FALSE in case of failure */ UNIV_INTERN -ulint +ibool buf_read_page( /*==========*/ ulint space, /*!< in: space id */ diff --git a/storage/innodb_plugin/include/buf0types.h b/storage/innodb_plugin/include/buf0types.h index e7167d716a0..bfae6477135 100644 --- a/storage/innodb_plugin/include/buf0types.h +++ b/storage/innodb_plugin/include/buf0types.h @@ -34,6 +34,8 @@ typedef struct buf_block_struct buf_block_t; typedef struct buf_chunk_struct buf_chunk_t; /** Buffer pool comprising buf_chunk_t */ typedef struct buf_pool_struct buf_pool_t; +/** Buffer pool statistics struct */ +typedef struct buf_pool_stat_struct buf_pool_stat_t; /** A buffer frame. @see page_t */ typedef byte buf_frame_t; diff --git a/storage/innodb_plugin/include/dict0dict.h b/storage/innodb_plugin/include/dict0dict.h index b2029699e51..d425241a3a2 100644 --- a/storage/innodb_plugin/include/dict0dict.h +++ b/storage/innodb_plugin/include/dict0dict.h @@ -712,7 +712,7 @@ dict_index_find_on_id_low( dulint id); /*!< in: index id */ /**********************************************************************//** Adds an index to the dictionary cache. -@return DB_SUCCESS or error code */ +@return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */ UNIV_INTERN ulint dict_index_add_to_cache( diff --git a/storage/innodb_plugin/include/os0sync.h b/storage/innodb_plugin/include/os0sync.h index 0e0b32e7036..6e52fa1350e 100644 --- a/storage/innodb_plugin/include/os0sync.h +++ b/storage/innodb_plugin/include/os0sync.h @@ -285,7 +285,7 @@ os_fast_mutex_free( /**********************************************************//** Atomic compare-and-swap and increment for InnoDB. */ -#ifdef HAVE_GCC_ATOMIC_BUILTINS +#ifdef HAVE_IB_GCC_ATOMIC_BUILTINS /**********************************************************//** Returns true if swapped, ptr is pointer to target, old_val is value to compare to, new_val is the value to swap in. */ @@ -377,7 +377,7 @@ InterlockedExchange() operates on LONG, and the LONG will be clobbered */ # define os_atomic_test_and_set_byte(ptr, new_val) \ ((byte) InterlockedExchange(ptr, new_val)) -#endif /* HAVE_GCC_ATOMIC_BUILTINS */ +#endif /* HAVE_IB_GCC_ATOMIC_BUILTINS */ #ifndef UNIV_NONINL #include "os0sync.ic" diff --git a/storage/innodb_plugin/include/srv0srv.h b/storage/innodb_plugin/include/srv0srv.h index 499bccfe2b8..23472bd100e 100644 --- a/storage/innodb_plugin/include/srv0srv.h +++ b/storage/innodb_plugin/include/srv0srv.h @@ -315,10 +315,6 @@ extern ulint srv_buf_pool_flushed; /** Number of buffer pool reads that led to the reading of a disk page */ extern ulint srv_buf_pool_reads; -/** Number of sequential read-aheads */ -extern ulint srv_read_ahead_seq; -/** Number of random read-aheads */ -extern ulint srv_read_ahead_rnd; /** Status variables to be passed to MySQL */ typedef struct export_var_struct export_struc; @@ -605,13 +601,13 @@ struct export_var_struct{ #ifdef UNIV_DEBUG ulint innodb_buffer_pool_pages_latched; /*!< Latched pages */ #endif /* UNIV_DEBUG */ - ulint innodb_buffer_pool_read_requests; /*!< buf_pool->n_page_gets */ + ulint innodb_buffer_pool_read_requests; /*!< buf_pool->stat.n_page_gets */ ulint innodb_buffer_pool_reads; /*!< srv_buf_pool_reads */ ulint innodb_buffer_pool_wait_free; /*!< srv_buf_pool_wait_free */ ulint innodb_buffer_pool_pages_flushed; /*!< srv_buf_pool_flushed */ ulint innodb_buffer_pool_write_requests;/*!< srv_buf_pool_write_requests */ - ulint innodb_buffer_pool_read_ahead_seq;/*!< srv_read_ahead_seq */ - ulint innodb_buffer_pool_read_ahead_rnd;/*!< srv_read_ahead_rnd */ + ulint innodb_buffer_pool_read_ahead; /*!< srv_read_ahead */ + ulint innodb_buffer_pool_read_ahead_evicted;/*!< srv_read_ahead evicted*/ ulint innodb_dblwr_pages_written; /*!< srv_dblwr_pages_written */ ulint innodb_dblwr_writes; /*!< srv_dblwr_writes */ ibool innodb_have_atomic_builtins; /*!< HAVE_ATOMIC_BUILTINS */ @@ -623,9 +619,9 @@ struct export_var_struct{ ulint innodb_os_log_pending_writes; /*!< srv_os_log_pending_writes */ ulint innodb_os_log_pending_fsyncs; /*!< fil_n_pending_log_flushes */ ulint innodb_page_size; /*!< UNIV_PAGE_SIZE */ - ulint innodb_pages_created; /*!< buf_pool->n_pages_created */ - ulint innodb_pages_read; /*!< buf_pool->n_pages_read */ - ulint innodb_pages_written; /*!< buf_pool->n_pages_written */ + ulint innodb_pages_created; /*!< buf_pool->stat.n_pages_created */ + ulint innodb_pages_read; /*!< buf_pool->stat.n_pages_read */ + ulint innodb_pages_written; /*!< buf_pool->stat.n_pages_written */ ulint innodb_row_lock_waits; /*!< srv_n_lock_wait_count */ ulint innodb_row_lock_current_waits; /*!< srv_n_lock_wait_current_count */ ib_int64_t innodb_row_lock_time; /*!< srv_n_lock_wait_time diff --git a/storage/innodb_plugin/include/univ.i b/storage/innodb_plugin/include/univ.i index aa01f072b1d..66240d96a11 100644 --- a/storage/innodb_plugin/include/univ.i +++ b/storage/innodb_plugin/include/univ.i @@ -125,11 +125,11 @@ if we are compiling on Windows. */ # include # endif -# if defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_SOLARIS_ATOMICS) \ +# if defined(HAVE_IB_GCC_ATOMIC_BUILTINS) || defined(HAVE_SOLARIS_ATOMICS) \ || defined(HAVE_WINDOWS_ATOMICS) /* If atomics are defined we use them in InnoDB mutex implementation */ # define HAVE_ATOMIC_BUILTINS -# endif /* (HAVE_GCC_ATOMIC_BUILTINS) || (HAVE_SOLARIS_ATOMICS) +# endif /* (HAVE_IB_GCC_ATOMIC_BUILTINS) || (HAVE_SOLARIS_ATOMICS) || (HAVE_WINDOWS_ATOMICS) */ /* For InnoDB rw_locks to work with atomics we need the thread_id diff --git a/storage/innodb_plugin/include/ut0ut.h b/storage/innodb_plugin/include/ut0ut.h index 80094321041..12c1cd59166 100644 --- a/storage/innodb_plugin/include/ut0ut.h +++ b/storage/innodb_plugin/include/ut0ut.h @@ -239,6 +239,15 @@ ullint ut_time_us( /*=======*/ ullint* tloc); /*!< out: us since epoch, if non-NULL */ +/**********************************************************//** +Returns the number of milliseconds since some epoch. The +value may wrap around. It should only be used for heuristic +purposes. +@return ms since epoch */ +UNIV_INTERN +uint +ut_time_ms(void); +/*============*/ /**********************************************************//** Returns the difference of two times in seconds. diff --git a/storage/innodb_plugin/plug.in b/storage/innodb_plugin/plug.in index a620f10a0da..230c6ed34df 100644 --- a/storage/innodb_plugin/plug.in +++ b/storage/innodb_plugin/plug.in @@ -63,6 +63,57 @@ MYSQL_PLUGIN_ACTIONS(innodb_plugin, [ ;; esac AC_SUBST(INNODB_DYNAMIC_CFLAGS) + + AC_MSG_CHECKING(whether GCC atomic builtins are available) + AC_TRY_RUN( + [ + int main() + { + long x; + long y; + long res; + char c; + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x, y); + if (!res || x != y) { + return(1); + } + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x + 1, y); + if (res || x != 10) { + return(1); + } + + x = 10; + y = 123; + res = __sync_add_and_fetch(&x, y); + if (res != 123 + 10 || x != 123 + 10) { + return(1); + } + + c = 10; + res = __sync_lock_test_and_set(&c, 123); + if (res != 10 || c != 123) { + return(1); + } + + return(0); + } + ], + [ + AC_DEFINE([HAVE_IB_GCC_ATOMIC_BUILTINS], [1], + [GCC atomic builtins are available]) + AC_MSG_RESULT(yes) + ], + [ + AC_MSG_RESULT(no) + ] + ) + AC_MSG_CHECKING(whether pthread_t can be used by GCC atomic builtins) AC_TRY_RUN( [ diff --git a/storage/innodb_plugin/row/row0merge.c b/storage/innodb_plugin/row/row0merge.c index 924b7ffba58..9a51221732b 100644 --- a/storage/innodb_plugin/row/row0merge.c +++ b/storage/innodb_plugin/row/row0merge.c @@ -60,9 +60,19 @@ Completed by Sunny Bains and Marko Makela #ifdef UNIV_DEBUG /** Set these in order ot enable debug printout. */ /* @{ */ +/** Log the outcome of each row_merge_cmp() call, comparing records. */ static ibool row_merge_print_cmp; +/** Log each record read from temporary file. */ static ibool row_merge_print_read; +/** Log each record write to temporary file. */ static ibool row_merge_print_write; +/** Log each row_merge_blocks() call, merging two blocks of records to +a bigger one. */ +static ibool row_merge_print_block; +/** Log each block read from temporary file. */ +static ibool row_merge_print_block_read; +/** Log each block read from temporary file. */ +static ibool row_merge_print_block_write; /* @} */ #endif /* UNIV_DEBUG */ @@ -109,8 +119,9 @@ typedef struct row_merge_buf_struct row_merge_buf_t; /** Information about temporary files used in merge sort */ struct merge_file_struct { - int fd; /*!< file descriptor */ - ulint offset; /*!< file offset */ + int fd; /*!< file descriptor */ + ulint offset; /*!< file offset (end of file) */ + ib_uint64_t n_rec; /*!< number of records in the file */ }; /** Information about temporary files used in merge sort */ @@ -682,6 +693,13 @@ row_merge_read( ib_uint64_t ofs = ((ib_uint64_t) offset) * sizeof *buf; ibool success; +#ifdef UNIV_DEBUG + if (row_merge_print_block_read) { + fprintf(stderr, "row_merge_read fd=%d ofs=%lu\n", + fd, (ulong) offset); + } +#endif /* UNIV_DEBUG */ + success = os_file_read_no_error_handling(OS_FILE_FROM_FD(fd), buf, (ulint) (ofs & 0xFFFFFFFF), (ulint) (ofs >> 32), @@ -709,6 +727,13 @@ row_merge_write( ib_uint64_t ofs = ((ib_uint64_t) offset) * sizeof(row_merge_block_t); +#ifdef UNIV_DEBUG + if (row_merge_print_block_write) { + fprintf(stderr, "row_merge_write fd=%d ofs=%lu\n", + fd, (ulong) offset); + } +#endif /* UNIV_DEBUG */ + return(UNIV_LIKELY(os_file_write("(merge)", OS_FILE_FROM_FD(fd), buf, (ulint) (ofs & 0xFFFFFFFF), (ulint) (ofs >> 32), @@ -718,7 +743,7 @@ row_merge_write( /********************************************************************//** Read a merge record. @return pointer to next record, or NULL on I/O error or end of list */ -static +static __attribute__((nonnull)) const byte* row_merge_read_rec( /*===============*/ @@ -1070,7 +1095,7 @@ row_merge_cmp( Reads clustered index of the table and create temporary files containing the index entries for the indexes to be built. @return DB_SUCCESS or error */ -static +static __attribute__((nonnull)) ulint row_merge_read_clustered_index( /*===========================*/ @@ -1233,6 +1258,7 @@ row_merge_read_clustered_index( if (UNIV_LIKELY (row && row_merge_buf_add(buf, row, ext))) { + file->n_rec++; continue; } @@ -1274,14 +1300,19 @@ err_exit: UNIV_MEM_INVALID(block[0], sizeof block[0]); merge_buf[i] = row_merge_buf_empty(buf); - /* Try writing the record again, now that - the buffer has been written out and emptied. */ + if (UNIV_LIKELY(row != NULL)) { + /* Try writing the record again, now + that the buffer has been written out + and emptied. */ - if (UNIV_UNLIKELY - (row && !row_merge_buf_add(buf, row, ext))) { - /* An empty buffer should have enough - room for at least one record. */ - ut_error; + if (UNIV_UNLIKELY + (!row_merge_buf_add(buf, row, ext))) { + /* An empty buffer should have enough + room for at least one record. */ + ut_error; + } + + file->n_rec++; } } @@ -1320,7 +1351,7 @@ func_exit: b2 = row_merge_write_rec(&block[2], &buf[2], b2, \ of->fd, &of->offset, \ mrec##N, offsets##N); \ - if (UNIV_UNLIKELY(!b2)) { \ + if (UNIV_UNLIKELY(!b2 || ++of->n_rec > file->n_rec)) { \ goto corrupt; \ } \ b##N = row_merge_read_rec(&block[N], &buf[N], \ @@ -1336,14 +1367,14 @@ func_exit: } while (0) /*************************************************************//** -Merge two blocks of linked lists on disk and write a bigger block. +Merge two blocks of records on disk and write a bigger block. @return DB_SUCCESS or error code */ static ulint row_merge_blocks( /*=============*/ const dict_index_t* index, /*!< in: index being created */ - merge_file_t* file, /*!< in/out: file containing + const merge_file_t* file, /*!< in: file containing index entries */ row_merge_block_t* block, /*!< in/out: 3 buffers */ ulint* foffs0, /*!< in/out: offset of first @@ -1366,6 +1397,17 @@ row_merge_blocks( ulint* offsets0;/* offsets of mrec0 */ ulint* offsets1;/* offsets of mrec1 */ +#ifdef UNIV_DEBUG + if (row_merge_print_block) { + fprintf(stderr, + "row_merge_blocks fd=%d ofs=%lu + fd=%d ofs=%lu" + " = fd=%d ofs=%lu\n", + file->fd, (ulong) *foffs0, + file->fd, (ulong) *foffs1, + of->fd, (ulong) of->offset); + } +#endif /* UNIV_DEBUG */ + heap = row_merge_heap_create(index, &offsets0, &offsets1); /* Write a record and read the next record. Split the output @@ -1437,17 +1479,88 @@ done1: return(b2 ? DB_SUCCESS : DB_CORRUPTION); } +/*************************************************************//** +Copy a block of index entries. +@return TRUE on success, FALSE on failure */ +static __attribute__((nonnull)) +ibool +row_merge_blocks_copy( +/*==================*/ + const dict_index_t* index, /*!< in: index being created */ + const merge_file_t* file, /*!< in: input file */ + row_merge_block_t* block, /*!< in/out: 3 buffers */ + ulint* foffs0, /*!< in/out: input file offset */ + merge_file_t* of) /*!< in/out: output file */ +{ + mem_heap_t* heap; /*!< memory heap for offsets0, offsets1 */ + + mrec_buf_t buf[3]; /*!< buffer for handling + split mrec in block[] */ + const byte* b0; /*!< pointer to block[0] */ + byte* b2; /*!< pointer to block[2] */ + const mrec_t* mrec0; /*!< merge rec, points to block[0] */ + ulint* offsets0;/* offsets of mrec0 */ + ulint* offsets1;/* dummy offsets */ + +#ifdef UNIV_DEBUG + if (row_merge_print_block) { + fprintf(stderr, + "row_merge_blocks_copy fd=%d ofs=%lu" + " = fd=%d ofs=%lu\n", + file->fd, (ulong) foffs0, + of->fd, (ulong) of->offset); + } +#endif /* UNIV_DEBUG */ + + heap = row_merge_heap_create(index, &offsets0, &offsets1); + + /* Write a record and read the next record. Split the output + file in two halves, which can be merged on the following pass. */ + + if (!row_merge_read(file->fd, *foffs0, &block[0])) { +corrupt: + mem_heap_free(heap); + return(FALSE); + } + + b0 = block[0]; + b2 = block[2]; + + b0 = row_merge_read_rec(&block[0], &buf[0], b0, index, file->fd, + foffs0, &mrec0, offsets0); + if (UNIV_UNLIKELY(!b0 && mrec0)) { + + goto corrupt; + } + + if (mrec0) { + /* append all mrec0 to output */ + for (;;) { + ROW_MERGE_WRITE_GET_NEXT(0, goto done0); + } + } +done0: + + /* The file offset points to the beginning of the last page + that has been read. Update it to point to the next block. */ + (*foffs0)++; + + mem_heap_free(heap); + return(row_merge_write_eof(&block[2], b2, of->fd, &of->offset) + != NULL); +} + /*************************************************************//** Merge disk files. @return DB_SUCCESS or error code */ -static +static __attribute__((nonnull)) ulint row_merge( /*======*/ const dict_index_t* index, /*!< in: index being created */ merge_file_t* file, /*!< in/out: file containing index entries */ - ulint half, /*!< in: half the file */ + ulint* half, /*!< in/out: half the file */ row_merge_block_t* block, /*!< in/out: 3 buffers */ int* tmpfd, /*!< in/out: temporary file handle */ TABLE* table) /*!< in/out: MySQL table, for @@ -1458,43 +1571,76 @@ row_merge( ulint foffs1; /*!< second input offset */ ulint error; /*!< error code */ merge_file_t of; /*!< output file */ + const ulint ihalf = *half; + /*!< half the input file */ + ulint ohalf; /*!< half the output file */ UNIV_MEM_ASSERT_W(block[0], 3 * sizeof block[0]); - ut_ad(half > 0); + ut_ad(ihalf > 0); + ut_ad(ihalf < file->offset); of.fd = *tmpfd; of.offset = 0; + of.n_rec = 0; /* Merge blocks to the output file. */ + ohalf = 0; foffs0 = 0; - foffs1 = half; + foffs1 = ihalf; + + for (; foffs0 < ihalf && foffs1 < file->offset; foffs0++, foffs1++) { + ulint ahalf; /*!< arithmetic half the input file */ - for (; foffs0 < half && foffs1 < file->offset; foffs0++, foffs1++) { error = row_merge_blocks(index, file, block, &foffs0, &foffs1, &of, table); if (error != DB_SUCCESS) { return(error); } + + /* Record the offset of the output file when + approximately half the output has been generated. In + this way, the next invocation of row_merge() will + spend most of the time in this loop. The initial + estimate is ohalf==0. */ + ahalf = file->offset / 2; + ut_ad(ohalf <= of.offset); + + /* Improve the estimate until reaching half the input + file size, or we can not get any closer to it. All + comparands should be non-negative when !(ohalf < ahalf) + because ohalf <= of.offset. */ + if (ohalf < ahalf || of.offset - ahalf < ohalf - ahalf) { + ohalf = of.offset; + } } - /* Copy the last block, if there is one. */ - while (foffs0 < half) { - if (!row_merge_read(file->fd, foffs0++, block) - || !row_merge_write(of.fd, of.offset++, block)) { + /* Copy the last blocks, if there are any. */ + + while (foffs0 < ihalf) { + if (!row_merge_blocks_copy(index, file, block, &foffs0, &of)) { return(DB_CORRUPTION); } } + + ut_ad(foffs0 == ihalf); + while (foffs1 < file->offset) { - if (!row_merge_read(file->fd, foffs1++, block) - || !row_merge_write(of.fd, of.offset++, block)) { + if (!row_merge_blocks_copy(index, file, block, &foffs1, &of)) { return(DB_CORRUPTION); } } + ut_ad(foffs1 == file->offset); + + if (UNIV_UNLIKELY(of.n_rec != file->n_rec)) { + return(DB_CORRUPTION); + } + /* Swap file descriptors for the next pass. */ *tmpfd = file->fd; *file = of; + *half = ohalf; UNIV_MEM_INVALID(block[0], 3 * sizeof block[0]); @@ -1517,20 +1663,17 @@ row_merge_sort( reporting erroneous key value if applicable */ { - ulint blksz; /*!< block size */ + ulint half = file->offset / 2; - for (blksz = 1; blksz < file->offset; blksz *= 2) { - ulint half; + do { ulint error; - ut_ad(ut_is_2pow(blksz)); - half = ut_2pow_round((file->offset + (blksz - 1)) / 2, blksz); - error = row_merge(index, file, half, block, tmpfd, table); + error = row_merge(index, file, &half, block, tmpfd, table); if (error != DB_SUCCESS) { return(error); } - } + } while (half < file->offset && half > 0); return(DB_SUCCESS); } @@ -1909,6 +2052,7 @@ row_merge_file_create( { merge_file->fd = innobase_mysql_tmpfile(); merge_file->offset = 0; + merge_file->n_rec = 0; } /*********************************************************************//** diff --git a/storage/innodb_plugin/srv/srv0srv.c b/storage/innodb_plugin/srv/srv0srv.c index b41c8acfab4..2f54e9b3734 100644 --- a/storage/innodb_plugin/srv/srv0srv.c +++ b/storage/innodb_plugin/srv/srv0srv.c @@ -292,12 +292,6 @@ UNIV_INTERN ulint srv_buf_pool_flushed = 0; reading of a disk page */ UNIV_INTERN ulint srv_buf_pool_reads = 0; -/** Number of sequential read-aheads */ -UNIV_INTERN ulint srv_read_ahead_seq = 0; - -/** Number of random read-aheads */ -UNIV_INTERN ulint srv_read_ahead_rnd = 0; - /* structure to pass status variables to MySQL */ UNIV_INTERN export_struc export_vars; @@ -464,8 +458,6 @@ static ulint srv_main_background_loops = 0; static ulint srv_main_flush_loops = 0; /* Log writes involving flush. */ static ulint srv_log_writes_and_flush = 0; -/* Log writes not including flush. */ -static ulint srv_log_buffer_writes = 0; /* This is only ever touched by the master thread. It records the time when the last flush of log file has happened. The master @@ -714,9 +706,8 @@ srv_print_master_thread_info( srv_main_1_second_loops, srv_main_sleeps, srv_main_10_second_loops, srv_main_background_loops, srv_main_flush_loops); - fprintf(file, "srv_master_thread log flush and writes: %lu " - " log writes only: %lu\n", - srv_log_writes_and_flush, srv_log_buffer_writes); + fprintf(file, "srv_master_thread log flush and writes: %lu\n", + srv_log_writes_and_flush); } /*********************************************************************//** @@ -1877,14 +1868,16 @@ srv_export_innodb_status(void) export_vars.innodb_data_reads = os_n_file_reads; export_vars.innodb_data_writes = os_n_file_writes; export_vars.innodb_data_written = srv_data_written; - export_vars.innodb_buffer_pool_read_requests = buf_pool->n_page_gets; + export_vars.innodb_buffer_pool_read_requests = buf_pool->stat.n_page_gets; export_vars.innodb_buffer_pool_write_requests = srv_buf_pool_write_requests; export_vars.innodb_buffer_pool_wait_free = srv_buf_pool_wait_free; export_vars.innodb_buffer_pool_pages_flushed = srv_buf_pool_flushed; export_vars.innodb_buffer_pool_reads = srv_buf_pool_reads; - export_vars.innodb_buffer_pool_read_ahead_rnd = srv_read_ahead_rnd; - export_vars.innodb_buffer_pool_read_ahead_seq = srv_read_ahead_seq; + export_vars.innodb_buffer_pool_read_ahead + = buf_pool->stat.n_ra_pages_read; + export_vars.innodb_buffer_pool_read_ahead_evicted + = buf_pool->stat.n_ra_pages_evicted; export_vars.innodb_buffer_pool_pages_data = UT_LIST_GET_LEN(buf_pool->LRU); export_vars.innodb_buffer_pool_pages_dirty @@ -1915,9 +1908,9 @@ srv_export_innodb_status(void) export_vars.innodb_log_writes = srv_log_writes; export_vars.innodb_dblwr_pages_written = srv_dblwr_pages_written; export_vars.innodb_dblwr_writes = srv_dblwr_writes; - export_vars.innodb_pages_created = buf_pool->n_pages_created; - export_vars.innodb_pages_read = buf_pool->n_pages_read; - export_vars.innodb_pages_written = buf_pool->n_pages_written; + export_vars.innodb_pages_created = buf_pool->stat.n_pages_created; + export_vars.innodb_pages_read = buf_pool->stat.n_pages_read; + export_vars.innodb_pages_written = buf_pool->stat.n_pages_written; export_vars.innodb_row_lock_waits = srv_n_lock_wait_count; export_vars.innodb_row_lock_current_waits = srv_n_lock_wait_current_count; @@ -2284,12 +2277,6 @@ srv_sync_log_buffer_in_background(void) log_buffer_sync_in_background(TRUE); srv_last_log_flush_time = current_time; srv_log_writes_and_flush++; - } else { - /* Actually we don't need to write logs here. - We are just being extra safe here by forcing - the log buffer to log file. */ - log_buffer_sync_in_background(FALSE); - srv_log_buffer_writes++; } } @@ -2340,8 +2327,8 @@ loop: srv_main_thread_op_info = "reserving kernel mutex"; - n_ios_very_old = log_sys->n_log_ios + buf_pool->n_pages_read - + buf_pool->n_pages_written; + n_ios_very_old = log_sys->n_log_ios + buf_pool->stat.n_pages_read + + buf_pool->stat.n_pages_written; mutex_enter(&kernel_mutex); /* Store the user activity counter at the start of this loop */ @@ -2361,8 +2348,8 @@ loop: skip_sleep = FALSE; for (i = 0; i < 10; i++) { - n_ios_old = log_sys->n_log_ios + buf_pool->n_pages_read - + buf_pool->n_pages_written; + n_ios_old = log_sys->n_log_ios + buf_pool->stat.n_pages_read + + buf_pool->stat.n_pages_written; srv_main_thread_op_info = "sleeping"; srv_main_1_second_loops++; @@ -2401,8 +2388,8 @@ loop: n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes; - n_ios = log_sys->n_log_ios + buf_pool->n_pages_read - + buf_pool->n_pages_written; + n_ios = log_sys->n_log_ios + buf_pool->stat.n_pages_read + + buf_pool->stat.n_pages_written; if (n_pend_ios < SRV_PEND_IO_THRESHOLD && (n_ios - n_ios_old < SRV_RECENT_IO_ACTIVITY)) { srv_main_thread_op_info = "doing insert buffer merge"; @@ -2418,6 +2405,8 @@ loop: /* Try to keep the number of modified pages in the buffer pool under the limit wished by the user */ + srv_main_thread_op_info = + "flushing buffer pool pages"; n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, PCT_IO(100), IB_ULONGLONG_MAX); @@ -2436,6 +2425,8 @@ loop: ulint n_flush = buf_flush_get_desired_flush_rate(); if (n_flush) { + srv_main_thread_op_info = + "flushing buffer pool pages"; n_flush = ut_min(PCT_IO(100), n_flush); n_pages_flushed = buf_flush_batch( @@ -2473,8 +2464,8 @@ loop: are not required, and may be disabled. */ n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes; - n_ios = log_sys->n_log_ios + buf_pool->n_pages_read - + buf_pool->n_pages_written; + n_ios = log_sys->n_log_ios + buf_pool->stat.n_pages_read + + buf_pool->stat.n_pages_written; srv_main_10_second_loops++; if (n_pend_ios < SRV_PEND_IO_THRESHOLD diff --git a/storage/innodb_plugin/srv/srv0start.c b/storage/innodb_plugin/srv/srv0start.c index f7447499b3b..e4278f6b5a8 100644 --- a/storage/innodb_plugin/srv/srv0start.c +++ b/storage/innodb_plugin/srv/srv0start.c @@ -1106,7 +1106,7 @@ innobase_start_or_create_for_mysql(void) "InnoDB: The InnoDB memory heap is disabled\n"); } -#ifdef HAVE_GCC_ATOMIC_BUILTINS +#ifdef HAVE_IB_GCC_ATOMIC_BUILTINS # ifdef INNODB_RW_LOCKS_USE_ATOMICS fprintf(stderr, "InnoDB: Mutexes and rw_locks use GCC atomic builtins.\n"); @@ -1130,10 +1130,10 @@ innobase_start_or_create_for_mysql(void) fprintf(stderr, "InnoDB: Mutexes use Windows interlocked functions.\n"); # endif /* INNODB_RW_LOCKS_USE_ATOMICS */ -#else /* HAVE_GCC_ATOMIC_BUILTINS */ +#else /* HAVE_IB_GCC_ATOMIC_BUILTINS */ fprintf(stderr, "InnoDB: Neither mutexes nor rw_locks use GCC atomic builtins.\n"); -#endif /* HAVE_GCC_ATOMIC_BUILTINS */ +#endif /* HAVE_IB_GCC_ATOMIC_BUILTINS */ /* Since InnoDB does not currently clean up all its internal data structures in MySQL Embedded Server Library server_end(), we diff --git a/storage/innodb_plugin/ut/ut0ut.c b/storage/innodb_plugin/ut/ut0ut.c index e4cc226fbad..a01a0470938 100644 --- a/storage/innodb_plugin/ut/ut0ut.c +++ b/storage/innodb_plugin/ut/ut0ut.c @@ -199,6 +199,23 @@ ut_time_us( return(us); } +/**********************************************************//** +Returns the number of milliseconds since some epoch. The +value may wrap around. It should only be used for heuristic +purposes. +@return ms since epoch */ +UNIV_INTERN +uint +ut_time_ms(void) +/*============*/ +{ + struct timeval tv; + + ut_gettimeofday(&tv, NULL); + + return((uint) tv.tv_sec * 1000 + tv.tv_usec / 1000); +} + /**********************************************************//** Returns the difference of two times in seconds. @return time2 - time1 expressed in seconds */ From 99318017d5c71853b6f3c7e3da1c81b19a2b9f09 Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Thu, 8 Oct 2009 16:56:31 +0500 Subject: [PATCH 092/146] Fix for bug #42803: Field_bit does not have unsigned_flag field, can lead to bad memory access Problem: Field_bit is the only field which returns INT_RESULT and doesn't have unsigned flag. As it's not a descendant of the Field_num, so using ((Field_num *) field_bit)->unsigned_flag may lead to unpredictable results. Fix: check the field type before casting. --- mysql-test/r/type_bit.result | 10 ++++++++++ mysql-test/t/type_bit.test | 11 +++++++++++ sql/opt_range.cc | 5 ++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result index 63dec0297d0..252f8165aec 100644 --- a/mysql-test/r/type_bit.result +++ b/mysql-test/r/type_bit.result @@ -749,4 +749,14 @@ bin(a1) 110000111111111 110001011111111 drop table t1bit7, t2bit7; +# +# Bug42803: Field_bit does not have unsigned_flag field, +# can lead to bad memory access +# +CREATE TABLE t1 (a BIT(7), b BIT(9), KEY(a, b)); +INSERT INTO t1 VALUES(0, 0), (5, 3), (5, 6), (6, 4), (7, 0); +EXPLAIN SELECT a+0, b+0 FROM t1 WHERE a > 4 and b < 7 ORDER BY 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 2 NULL 4 Using where; Using index; Using filesort +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test index bdc678688f1..7ec0649cbdd 100644 --- a/mysql-test/t/type_bit.test +++ b/mysql-test/t/type_bit.test @@ -397,4 +397,15 @@ insert into t2bit7 values (b'110011011111111'); select bin(a1) from t1bit7, t2bit7 where t1bit7.a1=t2bit7.b1; drop table t1bit7, t2bit7; + +--echo # +--echo # Bug42803: Field_bit does not have unsigned_flag field, +--echo # can lead to bad memory access +--echo # +CREATE TABLE t1 (a BIT(7), b BIT(9), KEY(a, b)); +INSERT INTO t1 VALUES(0, 0), (5, 3), (5, 6), (6, 4), (7, 0); +EXPLAIN SELECT a+0, b+0 FROM t1 WHERE a > 4 and b < 7 ORDER BY 2; +DROP TABLE t1; + + --echo End of 5.0 tests diff --git a/sql/opt_range.cc b/sql/opt_range.cc index fdf6cc03a44..355317fe280 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -4536,6 +4536,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, if (type == Item_func::LT_FUNC && (value->val_int() > 0)) type = Item_func::LE_FUNC; else if (type == Item_func::GT_FUNC && + (field->type() != FIELD_TYPE_BIT) && !((Field_num*)field)->unsigned_flag && !((Item_int*)value)->unsigned_flag && (value->val_int() < 0)) @@ -4572,7 +4573,9 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, */ if (field->result_type() == INT_RESULT && value->result_type() == INT_RESULT && - ((Field_num*)field)->unsigned_flag && !((Item_int*)value)->unsigned_flag) + ((field->type() == FIELD_TYPE_BIT || + ((Field_num *) field)->unsigned_flag) && + !((Item_int*) value)->unsigned_flag)) { longlong item_val= value->val_int(); if (item_val < 0) From ec025c694bbaf268479e705f77c096ce13a1c983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Bl=C3=A5udd?= Date: Thu, 8 Oct 2009 14:00:43 +0200 Subject: [PATCH 093/146] BUG#47129 fix small bug in test --- .../suite/binlog/t/binlog_stm_unsafe_warning.test | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test b/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test index 656eaae5721..21c11d5a3df 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test +++ b/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test @@ -94,22 +94,22 @@ DROP TABLE t1; SET GLOBAL log_warnings = @old_log_warnings; -let $log_error= `SELECT @@GLOBAL.log_error`; -if(!$log_error) +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!`select LENGTH('$log_error_')`) { # MySQL Server on windows is started with --console and thus # does not know the location of its .err log, use default location - let $log_error = $MYSQLTEST_VARDIR/log/mysqld.1.err; + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.1.err; } # Assign env variable LOG_ERROR -let LOG_ERROR=$log_error; +let LOG_ERROR=$log_error_; --echo # Count the number of times the "Unsafe" message was printed --echo # to the error log. perl; use strict; - my $log_error= $ENV{'LOG_ERROR'} || die "LOG_ERROR not set"; + my $log_error= $ENV{'LOG_ERROR'} or die "LOG_ERROR not set"; open(FILE, "$log_error") or die("Unable to open $log_error: $!\n"); my $count = () = grep(/Bug#46265/g,); print "Occurrences: $count\n"; From b0a67daf4d2f04df1203ef5d99ddaf188da5790b Mon Sep 17 00:00:00 2001 From: Satya B Date: Thu, 8 Oct 2009 17:48:19 +0530 Subject: [PATCH 094/146] Applying InnoDB Plugin 1.0.5 snapshot , part 5 From revision r5733 to r5747 Detailed revision comments: r5733 | sunny | 2009-09-02 02:05:15 -0500 (Wed, 02 Sep 2009) | 6 lines branches/zip: Fix a regression introduced by the fix for bug#26316. We check whether a transaction holds any AUTOINC locks before we acquire the kernel mutex and release those locks. Fix for rb://153. Approved by Marko. r5734 | sunny | 2009-09-02 02:08:45 -0500 (Wed, 02 Sep 2009) | 2 lines branches/zip: Update ChangeLog with r5733 changes. r5735 | marko | 2009-09-02 02:43:09 -0500 (Wed, 02 Sep 2009) | 2 lines branches/zip: univ.i: Do not undefine PACKAGE or VERSION. InnoDB source code does not refer to these macros. r5736 | marko | 2009-09-02 02:53:19 -0500 (Wed, 02 Sep 2009) | 1 line branches/zip: Enclose some timestamp functions in #ifndef UNIV_HOTBACKUP. r5743 | marko | 2009-09-03 01:36:12 -0500 (Thu, 03 Sep 2009) | 3 lines branches/zip: log_reserve_and_write_fast(): Remove the redundant output parameter "success". Success is also indicated by a nonzero return value. r5744 | marko | 2009-09-03 03:28:35 -0500 (Thu, 03 Sep 2009) | 1 line branches/zip: ut_align(): Make ptr const, like in ut_align_down(). r5745 | marko | 2009-09-03 03:38:22 -0500 (Thu, 03 Sep 2009) | 2 lines branches/zip: log_check_log_recs(): Enclose in #ifdef UNIV_LOG_DEBUG. Add const qualifiers. r5746 | marko | 2009-09-03 03:55:36 -0500 (Thu, 03 Sep 2009) | 2 lines branches/zip: log_reserve_and_write_fast(): Do not cache the log_sys pointer in a local variable. r5747 | marko | 2009-09-03 05:46:38 -0500 (Thu, 03 Sep 2009) | 2 lines branches/zip: recv_scan_log_recs(): Replace while with do...while, because the termination condition will always hold on the first iteration. --- storage/innodb_plugin/ChangeLog | 8 +++++ storage/innodb_plugin/include/lock0lock.h | 8 +++++ storage/innodb_plugin/include/log0log.h | 5 ++- storage/innodb_plugin/include/log0log.ic | 42 +++++++++++------------ storage/innodb_plugin/include/row0mysql.h | 4 ++- storage/innodb_plugin/include/univ.i | 9 ++--- storage/innodb_plugin/include/ut0byte.h | 4 +-- storage/innodb_plugin/include/ut0byte.ic | 4 +-- storage/innodb_plugin/include/ut0ut.h | 2 ++ storage/innodb_plugin/lock/lock0lock.c | 14 ++++++++ storage/innodb_plugin/log/log0log.c | 8 +++-- storage/innodb_plugin/log/log0recv.c | 6 ++-- storage/innodb_plugin/mtr/mtr0mtr.c | 5 ++- storage/innodb_plugin/page/page0zip.c | 14 ++++++++ storage/innodb_plugin/row/row0mysql.c | 12 ++++--- storage/innodb_plugin/ut/ut0ut.c | 2 ++ 16 files changed, 98 insertions(+), 49 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index df71a1c25a5..15d951cb5d1 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,11 @@ +2009-09-02 The InnoDB Team + + * include/lock0lock.h, include/row0mysql.h, lock/lock0lock.c, + row/row0mysql.c: + Fix a regression introduced by the fix for MySQL bug#26316. We check + whether a transaction holds any AUTOINC locks before we acquire + the kernel mutex and release those locks. + 2009-08-27 The InnoDB Team * dict/dict0dict.c, include/dict0dict.h, diff --git a/storage/innodb_plugin/include/lock0lock.h b/storage/innodb_plugin/include/lock0lock.h index fa5db831d4f..aeabe39e1a9 100644 --- a/storage/innodb_plugin/include/lock0lock.h +++ b/storage/innodb_plugin/include/lock0lock.h @@ -630,6 +630,14 @@ lock_number_of_rows_locked( /*=======================*/ trx_t* trx); /*!< in: transaction */ /*******************************************************************//** +Check if a transaction holds any autoinc locks. +@return TRUE if the transaction holds any AUTOINC locks. */ +UNIV_INTERN +ibool +lock_trx_holds_autoinc_locks( +/*=========================*/ + const trx_t* trx); /*!< in: transaction */ +/*******************************************************************//** Release all the transaction's autoinc locks. */ UNIV_INTERN void diff --git a/storage/innodb_plugin/include/log0log.h b/storage/innodb_plugin/include/log0log.h index 5897067798d..299b4a05b40 100644 --- a/storage/innodb_plugin/include/log0log.h +++ b/storage/innodb_plugin/include/log0log.h @@ -118,10 +118,9 @@ UNIV_INLINE ib_uint64_t log_reserve_and_write_fast( /*=======================*/ - byte* str, /*!< in: string */ + const void* str, /*!< in: string */ ulint len, /*!< in: string length */ - ib_uint64_t* start_lsn,/*!< out: start lsn of the log record */ - ibool* success);/*!< out: TRUE if success */ + ib_uint64_t* start_lsn);/*!< out: start lsn of the log record */ /***********************************************************************//** Releases the log mutex. */ UNIV_INLINE diff --git a/storage/innodb_plugin/include/log0log.ic b/storage/innodb_plugin/include/log0log.ic index d071985982a..4d2f64af695 100644 --- a/storage/innodb_plugin/include/log0log.ic +++ b/storage/innodb_plugin/include/log0log.ic @@ -27,6 +27,7 @@ Created 12/9/1995 Heikki Tuuri #include "mach0data.h" #include "mtr0mtr.h" +#ifdef UNIV_LOG_DEBUG /******************************************************//** Checks by parsing that the catenated log segment for a single mtr is consistent. */ @@ -34,11 +35,12 @@ UNIV_INTERN ibool log_check_log_recs( /*===============*/ - byte* buf, /*!< in: pointer to the start of + const byte* buf, /*!< in: pointer to the start of the log segment in the log_sys->buf log buffer */ ulint len, /*!< in: segment length in bytes */ ib_uint64_t buf_start_lsn); /*!< in: buffer start lsn */ +#endif /* UNIV_LOG_DEBUG */ /************************************************************//** Gets a log block flush bit. @@ -305,53 +307,49 @@ UNIV_INLINE ib_uint64_t log_reserve_and_write_fast( /*=======================*/ - byte* str, /*!< in: string */ + const void* str, /*!< in: string */ ulint len, /*!< in: string length */ - ib_uint64_t* start_lsn,/*!< out: start lsn of the log record */ - ibool* success)/*!< out: TRUE if success */ + ib_uint64_t* start_lsn)/*!< out: start lsn of the log record */ { - log_t* log = log_sys; ulint data_len; ib_uint64_t lsn; - *success = TRUE; + mutex_enter(&log_sys->mutex); - mutex_enter(&(log->mutex)); - - data_len = len + log->buf_free % OS_FILE_LOG_BLOCK_SIZE; + data_len = len + log_sys->buf_free % OS_FILE_LOG_BLOCK_SIZE; if (data_len >= OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) { /* The string does not fit within the current log block or the log block would become full */ - *success = FALSE; - - mutex_exit(&(log->mutex)); + mutex_exit(&log_sys->mutex); return(0); } - *start_lsn = log->lsn; + *start_lsn = log_sys->lsn; - ut_memcpy(log->buf + log->buf_free, str, len); + ut_memcpy(log_sys->buf + log_sys->buf_free, str, len); - log_block_set_data_len((byte*) ut_align_down(log->buf + log->buf_free, + log_block_set_data_len((byte*) ut_align_down(log_sys->buf + + log_sys->buf_free, OS_FILE_LOG_BLOCK_SIZE), data_len); #ifdef UNIV_LOG_DEBUG - log->old_buf_free = log->buf_free; - log->old_lsn = log->lsn; + log_sys->old_buf_free = log_sys->buf_free; + log_sys->old_lsn = log_sys->lsn; #endif - log->buf_free += len; + log_sys->buf_free += len; - ut_ad(log->buf_free <= log->buf_size); + ut_ad(log_sys->buf_free <= log_sys->buf_size); - lsn = log->lsn += len; + lsn = log_sys->lsn += len; #ifdef UNIV_LOG_DEBUG - log_check_log_recs(log->buf + log->old_buf_free, - log->buf_free - log->old_buf_free, log->old_lsn); + log_check_log_recs(log_sys->buf + log_sys->old_buf_free, + log_sys->buf_free - log_sys->old_buf_free, + log_sys->old_lsn); #endif return(lsn); } diff --git a/storage/innodb_plugin/include/row0mysql.h b/storage/innodb_plugin/include/row0mysql.h index 97028622505..6d5d195172e 100644 --- a/storage/innodb_plugin/include/row0mysql.h +++ b/storage/innodb_plugin/include/row0mysql.h @@ -177,7 +177,9 @@ row_update_prebuilt_trx( in MySQL handle */ trx_t* trx); /*!< in: transaction handle */ /*********************************************************************//** -Unlocks AUTO_INC type locks that were possibly reserved by a trx. */ +Unlocks AUTO_INC type locks that were possibly reserved by a trx. This +function should be called at the the end of an SQL statement, by the +connection thread that owns the transaction (trx->mysql_thd). */ UNIV_INTERN void row_unlock_table_autoinc_for_mysql( diff --git a/storage/innodb_plugin/include/univ.i b/storage/innodb_plugin/include/univ.i index 66240d96a11..815c9ffcee0 100644 --- a/storage/innodb_plugin/include/univ.i +++ b/storage/innodb_plugin/include/univ.i @@ -111,14 +111,11 @@ if we are compiling on Windows. */ # include /* mmap() for os0proc.c */ # endif -# undef PACKAGE -# undef VERSION - /* Include the header file generated by GNU autoconf */ # ifndef __WIN__ -#ifndef UNIV_HOTBACKUP -# include "config.h" -#endif /* UNIV_HOTBACKUP */ +# ifndef UNIV_HOTBACKUP +# include "config.h" +# endif /* UNIV_HOTBACKUP */ # endif # ifdef HAVE_SCHED_H diff --git a/storage/innodb_plugin/include/ut0byte.h b/storage/innodb_plugin/include/ut0byte.h index a2687e62f08..f55e2888c60 100644 --- a/storage/innodb_plugin/include/ut0byte.h +++ b/storage/innodb_plugin/include/ut0byte.h @@ -219,8 +219,8 @@ UNIV_INLINE void* ut_align( /*=====*/ - void* ptr, /*!< in: pointer */ - ulint align_no); /*!< in: align by this number */ + const void* ptr, /*!< in: pointer */ + ulint align_no); /*!< in: align by this number */ /*********************************************************//** The following function rounds down a pointer to the nearest aligned address. diff --git a/storage/innodb_plugin/include/ut0byte.ic b/storage/innodb_plugin/include/ut0byte.ic index e3beed65138..3dd51890cb4 100644 --- a/storage/innodb_plugin/include/ut0byte.ic +++ b/storage/innodb_plugin/include/ut0byte.ic @@ -319,8 +319,8 @@ UNIV_INLINE void* ut_align( /*=====*/ - void* ptr, /*!< in: pointer */ - ulint align_no) /*!< in: align by this number */ + const void* ptr, /*!< in: pointer */ + ulint align_no) /*!< in: align by this number */ { ut_ad(align_no > 0); ut_ad(((align_no - 1) & align_no) == 0); diff --git a/storage/innodb_plugin/include/ut0ut.h b/storage/innodb_plugin/include/ut0ut.h index 12c1cd59166..94a93dff6c7 100644 --- a/storage/innodb_plugin/include/ut0ut.h +++ b/storage/innodb_plugin/include/ut0ut.h @@ -216,6 +216,7 @@ UNIV_INTERN ib_time_t ut_time(void); /*=========*/ +#ifndef UNIV_HOTBACKUP /**********************************************************//** Returns system time. Upon successful completion, the value 0 is returned; otherwise the @@ -248,6 +249,7 @@ UNIV_INTERN uint ut_time_ms(void); /*============*/ +#endif /* !UNIV_HOTBACKUP */ /**********************************************************//** Returns the difference of two times in seconds. diff --git a/storage/innodb_plugin/lock/lock0lock.c b/storage/innodb_plugin/lock/lock0lock.c index 41805b58e0b..20d444af3f4 100644 --- a/storage/innodb_plugin/lock/lock0lock.c +++ b/storage/innodb_plugin/lock/lock0lock.c @@ -5371,6 +5371,20 @@ lock_release_autoinc_last_lock( lock_table_dequeue(lock); } +/*******************************************************************//** +Check if a transaction holds any autoinc locks. +@return TRUE if the transaction holds any AUTOINC locks. */ +UNIV_INTERN +ibool +lock_trx_holds_autoinc_locks( +/*=========================*/ + const trx_t* trx) /*!< in: transaction */ +{ + ut_a(trx->autoinc_locks != NULL); + + return(!ib_vector_is_empty(trx->autoinc_locks)); +} + /*******************************************************************//** Release all the transaction's autoinc locks. */ UNIV_INTERN diff --git a/storage/innodb_plugin/log/log0log.c b/storage/innodb_plugin/log/log0log.c index f67a1067301..85de72bb768 100644 --- a/storage/innodb_plugin/log/log0log.c +++ b/storage/innodb_plugin/log/log0log.c @@ -3234,6 +3234,7 @@ loop: ut_a(lsn == log_sys->lsn); } +#ifdef UNIV_LOG_DEBUG /******************************************************//** Checks by parsing that the catenated log segment for a single mtr is consistent. */ @@ -3241,7 +3242,7 @@ UNIV_INTERN ibool log_check_log_recs( /*===============*/ - byte* buf, /*!< in: pointer to the start of + const byte* buf, /*!< in: pointer to the start of the log segment in the log_sys->buf log buffer */ ulint len, /*!< in: segment length in bytes */ @@ -3249,8 +3250,8 @@ log_check_log_recs( { ib_uint64_t contiguous_lsn; ib_uint64_t scanned_lsn; - byte* start; - byte* end; + const byte* start; + const byte* end; byte* buf1; byte* scan_buf; @@ -3283,6 +3284,7 @@ log_check_log_recs( return(TRUE); } +#endif /* UNIV_LOG_DEBUG */ /******************************************************//** Peeks the current lsn. diff --git a/storage/innodb_plugin/log/log0recv.c b/storage/innodb_plugin/log/log0recv.c index aea29c78517..3b40925f079 100644 --- a/storage/innodb_plugin/log/log0recv.c +++ b/storage/innodb_plugin/log/log0recv.c @@ -2415,8 +2415,7 @@ recv_scan_log_recs( scanned_lsn = start_lsn; more_data = FALSE; - while (log_block < buf + len && !finished) { - + do { no = log_block_get_hdr_no(log_block); /* fprintf(stderr, "Log block header no %lu\n", no); @@ -2546,10 +2545,11 @@ recv_scan_log_recs( /* Log data for this group ends here */ finished = TRUE; + break; } else { log_block += OS_FILE_LOG_BLOCK_SIZE; } - } + } while (log_block < buf + len && !finished); *group_scanned_lsn = scanned_lsn; diff --git a/storage/innodb_plugin/mtr/mtr0mtr.c b/storage/innodb_plugin/mtr/mtr0mtr.c index be31c5df801..0c4bec8c82c 100644 --- a/storage/innodb_plugin/mtr/mtr0mtr.c +++ b/storage/innodb_plugin/mtr/mtr0mtr.c @@ -115,7 +115,6 @@ mtr_log_reserve_and_write( dyn_array_t* mlog; dyn_block_t* block; ulint data_size; - ibool success; byte* first_data; ut_ad(mtr); @@ -134,8 +133,8 @@ mtr_log_reserve_and_write( if (mlog->heap == NULL) { mtr->end_lsn = log_reserve_and_write_fast( first_data, dyn_block_get_used(mlog), - &(mtr->start_lsn), &success); - if (success) { + &mtr->start_lsn); + if (mtr->end_lsn) { return; } diff --git a/storage/innodb_plugin/page/page0zip.c b/storage/innodb_plugin/page/page0zip.c index 92ba0ec768a..e170adce30a 100644 --- a/storage/innodb_plugin/page/page0zip.c +++ b/storage/innodb_plugin/page/page0zip.c @@ -47,8 +47,10 @@ Created June 2005 by Marko Makela # define buf_LRU_stat_inc_unzip() ((void) 0) #endif /* !UNIV_HOTBACKUP */ +#ifndef UNIV_HOTBACKUP /** Statistics on compression, indexed by page_zip_des_t::ssize - 1 */ UNIV_INTERN page_zip_stat_t page_zip_stat[PAGE_ZIP_NUM_SSIZE - 1]; +#endif /* !UNIV_HOTBACKUP */ /* Please refer to ../include/page0zip.ic for a description of the compressed page format. */ @@ -1144,7 +1146,9 @@ page_zip_compress( ulint* offsets = NULL; ulint n_blobs = 0; byte* storage;/* storage of uncompressed columns */ +#ifndef UNIV_HOTBACKUP ullint usec = ut_time_us(NULL); +#endif /* !UNIV_HOTBACKUP */ #ifdef PAGE_ZIP_COMPRESS_DBG FILE* logfile = NULL; #endif @@ -1208,7 +1212,9 @@ page_zip_compress( } } #endif /* PAGE_ZIP_COMPRESS_DBG */ +#ifndef UNIV_HOTBACKUP page_zip_stat[page_zip->ssize - 1].compressed++; +#endif /* !UNIV_HOTBACKUP */ if (UNIV_UNLIKELY(n_dense * PAGE_ZIP_DIR_SLOT_SIZE >= page_zip_get_size(page_zip))) { @@ -1345,8 +1351,10 @@ err_exit: fclose(logfile); } #endif /* PAGE_ZIP_COMPRESS_DBG */ +#ifndef UNIV_HOTBACKUP page_zip_stat[page_zip->ssize - 1].compressed_usec += ut_time_us(NULL) - usec; +#endif /* !UNIV_HOTBACKUP */ return(FALSE); } @@ -1404,12 +1412,14 @@ err_exit: fclose(logfile); } #endif /* PAGE_ZIP_COMPRESS_DBG */ +#ifndef UNIV_HOTBACKUP { page_zip_stat_t* zip_stat = &page_zip_stat[page_zip->ssize - 1]; zip_stat->compressed_ok++; zip_stat->compressed_usec += ut_time_us(NULL) - usec; } +#endif /* !UNIV_HOTBACKUP */ return(TRUE); } @@ -2820,7 +2830,9 @@ page_zip_decompress( ulint trx_id_col = ULINT_UNDEFINED; mem_heap_t* heap; ulint* offsets; +#ifndef UNIV_HOTBACKUP ullint usec = ut_time_us(NULL); +#endif /* !UNIV_HOTBACKUP */ ut_ad(page_zip_simple_validate(page_zip)); UNIV_MEM_ASSERT_W(page, UNIV_PAGE_SIZE); @@ -2976,12 +2988,14 @@ err_exit: page_zip_fields_free(index); mem_heap_free(heap); +#ifndef UNIV_HOTBACKUP { page_zip_stat_t* zip_stat = &page_zip_stat[page_zip->ssize - 1]; zip_stat->decompressed++; zip_stat->decompressed_usec += ut_time_us(NULL) - usec; } +#endif /* !UNIV_HOTBACKUP */ /* Update the stat counter for LRU policy. */ buf_LRU_stat_inc_unzip(); diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index 8d80d73f0c7..5fd57efa00c 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -866,18 +866,22 @@ row_update_statistics_if_needed( } /*********************************************************************//** -Unlocks AUTO_INC type locks that were possibly reserved by a trx. */ +Unlocks AUTO_INC type locks that were possibly reserved by a trx. This +function should be called at the the end of an SQL statement, by the +connection thread that owns the transaction (trx->mysql_thd). */ UNIV_INTERN void row_unlock_table_autoinc_for_mysql( /*===============================*/ trx_t* trx) /*!< in/out: transaction */ { - mutex_enter(&kernel_mutex); + if (lock_trx_holds_autoinc_locks(trx)) { + mutex_enter(&kernel_mutex); - lock_release_autoinc_locks(trx); + lock_release_autoinc_locks(trx); - mutex_exit(&kernel_mutex); + mutex_exit(&kernel_mutex); + } } /*********************************************************************//** diff --git a/storage/innodb_plugin/ut/ut0ut.c b/storage/innodb_plugin/ut/ut0ut.c index a01a0470938..5857c9bdef4 100644 --- a/storage/innodb_plugin/ut/ut0ut.c +++ b/storage/innodb_plugin/ut/ut0ut.c @@ -132,6 +132,7 @@ ut_time(void) return(time(NULL)); } +#ifndef UNIV_HOTBACKUP /**********************************************************//** Returns system time. Upon successful completion, the value 0 is returned; otherwise the @@ -215,6 +216,7 @@ ut_time_ms(void) return((uint) tv.tv_sec * 1000 + tv.tv_usec / 1000); } +#endif /* !UNIV_HOTBACKUP */ /**********************************************************//** Returns the difference of two times in seconds. From 104f791312b6303a5a7d2b7326664888c123d319 Mon Sep 17 00:00:00 2001 From: Satya B Date: Thu, 8 Oct 2009 18:22:21 +0530 Subject: [PATCH 095/146] Applying InnoDB Plugin 1.0.5 snapshot, part 6 From revision r5748 to r5783 Detailed revision comments: r5748 | marko | 2009-09-03 06:05:44 -0500 (Thu, 03 Sep 2009) | 1 line branches/zip: MLOG_MULTI_REC_END: Correct the comment. r5751 | marko | 2009-09-03 09:36:15 -0500 (Thu, 03 Sep 2009) | 7 lines branches/zip: row_merge(): Remove a bogus debug assertion that was triggered when creating an index on an empty table. row_merge_sort(): Add debug assertions and comments that justify the loop termination condition. The bogus assertion ut_ad(ihalf > 0) was reported by Michael. r5752 | marko | 2009-09-03 09:55:51 -0500 (Thu, 03 Sep 2009) | 10 lines branches/zip: recv_recover_page_func(): Write the log sequence number to the compressed page, if there is one. Previously, the function only wrote the LSN to the uncompressed page. It is not clear why recv_recover_page_func() is updating FIL_PAGE_LSN in the buffer pool. The log sequence number will be stamped on the page when it is flushed to disk, in buf_flush_init_for_writing(). I noticed this inconsistency when analyzing Issue #313, but this patch does not fix it. That is no surprise, since FIL_PAGE_LSN should only matter on disk files, not in the buffer pool. r5775 | calvin | 2009-09-07 16:15:05 -0500 (Mon, 07 Sep 2009) | 13 lines branches/zip: Build InnoDB on Windows with UNIV_HOTBACKUP The changes are non-functional changes for normal InnoDB, but needed for building the Hot Backup on Windows (with UNIV_HOTBACKUP defined). - Define os_aio_use_native_aio for HB. - Do not acquire seek mutexes for backup since HB is single threaded. - Do not use srv_flush_log_at_trx_commit for HB build rb://155 Approved by: Marko r5777 | marko | 2009-09-08 10:50:25 -0500 (Tue, 08 Sep 2009) | 2 lines branches/zip: Remove BUF_LRU_INITIAL_RATIO, which should have been removed together with buf_LRU_get_recent_limit(). r5779 | marko | 2009-09-09 01:17:19 -0500 (Wed, 09 Sep 2009) | 2 lines branches/zip: buf_page_peek_if_too_old(): Make the bitmasking work when buf_pool->freed_page_clock is wider than 32 bits. r5780 | marko | 2009-09-09 01:50:50 -0500 (Wed, 09 Sep 2009) | 1 line branches/zip: ut_time_ms(): Return ulint, not uint. r5782 | marko | 2009-09-09 02:00:59 -0500 (Wed, 09 Sep 2009) | 2 lines branches/zip: buf_page_peek_if_too_old(): Silence a compiler warning that was introduced in r5779 on 32-bit systems. r5783 | marko | 2009-09-09 02:25:00 -0500 (Wed, 09 Sep 2009) | 1 line branches/zip: buf_page_is_accessed(): Correct the function comment. --- storage/innodb_plugin/buf/buf0lru.c | 5 --- storage/innodb_plugin/include/buf0buf.h | 4 +- storage/innodb_plugin/include/buf0buf.ic | 6 +-- storage/innodb_plugin/include/mtr0mtr.h | 2 +- storage/innodb_plugin/include/ut0ut.h | 2 +- storage/innodb_plugin/log/log0recv.c | 30 ++++++++++---- storage/innodb_plugin/os/os0file.c | 52 ++++++++++++++++++++---- storage/innodb_plugin/row/row0merge.c | 9 +++- storage/innodb_plugin/ut/ut0ut.c | 4 +- 9 files changed, 82 insertions(+), 32 deletions(-) diff --git a/storage/innodb_plugin/buf/buf0lru.c b/storage/innodb_plugin/buf/buf0lru.c index 223746e0d01..e7cf852e200 100644 --- a/storage/innodb_plugin/buf/buf0lru.c +++ b/storage/innodb_plugin/buf/buf0lru.c @@ -66,11 +66,6 @@ allowed to point to either end of the LRU list. */ # error "BUF_LRU_NON_OLD_MIN_LEN >= BUF_LRU_OLD_MIN_LEN" #endif -/** The whole LRU list length is divided by this number to determine an -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. */ diff --git a/storage/innodb_plugin/include/buf0buf.h b/storage/innodb_plugin/include/buf0buf.h index 299312e5d10..db95aa7ce21 100644 --- a/storage/innodb_plugin/include/buf0buf.h +++ b/storage/innodb_plugin/include/buf0buf.h @@ -807,8 +807,8 @@ buf_page_set_old( buf_page_t* bpage, /*!< in/out: control block */ ibool old); /*!< in: old */ /*********************************************************************//** -Determine the time of last access a block in the buffer pool. -@return ut_time_ms() at the time of last access, 0 if not accessed */ +Determine the time of first access of a block in the buffer pool. +@return ut_time_ms() at the time of first access, 0 if not accessed */ UNIV_INLINE unsigned buf_page_is_accessed( diff --git a/storage/innodb_plugin/include/buf0buf.ic b/storage/innodb_plugin/include/buf0buf.ic index 409d339aa16..18ee4551eb4 100644 --- a/storage/innodb_plugin/include/buf0buf.ic +++ b/storage/innodb_plugin/include/buf0buf.ic @@ -84,7 +84,7 @@ buf_page_peek_if_too_old( return(FALSE); } else { /* FIXME: bpage->freed_page_clock is 31 bits */ - return((buf_pool->freed_page_clock & ~(1 << 31)) + return((buf_pool->freed_page_clock & ((1UL << 31) - 1)) > bpage->freed_page_clock + (buf_pool->curr_size * (BUF_LRU_OLD_RATIO_DIV - buf_LRU_old_ratio) @@ -471,8 +471,8 @@ buf_page_set_old( } /*********************************************************************//** -Determine the time of last access a block in the buffer pool. -@return ut_time_ms() at the time of last access, 0 if not accessed */ +Determine the time of first access of a block in the buffer pool. +@return ut_time_ms() at the time of first access, 0 if not accessed */ UNIV_INLINE unsigned buf_page_is_accessed( diff --git a/storage/innodb_plugin/include/mtr0mtr.h b/storage/innodb_plugin/include/mtr0mtr.h index 69a2c03f4cb..44bba43b1ab 100644 --- a/storage/innodb_plugin/include/mtr0mtr.h +++ b/storage/innodb_plugin/include/mtr0mtr.h @@ -118,7 +118,7 @@ For 1 - 8 bytes, the flag value must give the length also! @{ */ #define MLOG_WRITE_STRING ((byte)30) /*!< write a string to a page */ #define MLOG_MULTI_REC_END ((byte)31) /*!< if a single mtr writes - log records for several pages, + several log records, this log record ends the sequence of these records */ #define MLOG_DUMMY_RECORD ((byte)32) /*!< dummy log record used to diff --git a/storage/innodb_plugin/include/ut0ut.h b/storage/innodb_plugin/include/ut0ut.h index 94a93dff6c7..6655d522c18 100644 --- a/storage/innodb_plugin/include/ut0ut.h +++ b/storage/innodb_plugin/include/ut0ut.h @@ -246,7 +246,7 @@ value may wrap around. It should only be used for heuristic purposes. @return ms since epoch */ UNIV_INTERN -uint +ulint ut_time_ms(void); /*============*/ #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innodb_plugin/log/log0recv.c b/storage/innodb_plugin/log/log0recv.c index 3b40925f079..971c5600d39 100644 --- a/storage/innodb_plugin/log/log0recv.c +++ b/storage/innodb_plugin/log/log0recv.c @@ -1327,6 +1327,7 @@ recv_recover_page_func( buf_block_t* block) /*!< in/out: buffer block */ { page_t* page; + page_zip_des_t* page_zip; recv_addr_t* recv_addr; recv_t* recv; byte* buf; @@ -1376,6 +1377,7 @@ recv_recover_page_func( mtr_set_log_mode(&mtr, MTR_LOG_NONE); page = block->frame; + page_zip = buf_block_get_page_zip(block); #ifndef UNIV_HOTBACKUP if (just_read_in) { @@ -1436,13 +1438,19 @@ recv_recover_page_func( if (recv->type == MLOG_INIT_FILE_PAGE) { page_lsn = page_newest_lsn; - mach_write_ull(page + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN_OLD_CHKSUM, 0); - mach_write_ull(page + FIL_PAGE_LSN, 0); + memset(FIL_PAGE_LSN + page, 0, 8); + memset(UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM + + page, 0, 8); + + if (page_zip) { + memset(FIL_PAGE_LSN + page_zip->data, 0, 8); + } } if (recv->start_lsn >= page_lsn) { + ib_uint64_t end_lsn; + if (!modification_to_page) { modification_to_page = TRUE; @@ -1464,11 +1472,17 @@ recv_recover_page_func( recv_parse_or_apply_log_rec_body(recv->type, buf, buf + recv->len, block, &mtr); - mach_write_ull(page + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN_OLD_CHKSUM, - recv->start_lsn + recv->len); - mach_write_ull(page + FIL_PAGE_LSN, - recv->start_lsn + recv->len); + + end_lsn = recv->start_lsn + recv->len; + mach_write_ull(FIL_PAGE_LSN + page, end_lsn); + mach_write_ull(UNIV_PAGE_SIZE + - FIL_PAGE_END_LSN_OLD_CHKSUM + + page, end_lsn); + + if (page_zip) { + mach_write_ull(FIL_PAGE_LSN + + page_zip->data, end_lsn); + } } if (recv->len > RECV_DATA_BLOCK_SIZE) { diff --git a/storage/innodb_plugin/os/os0file.c b/storage/innodb_plugin/os/os0file.c index dc25d55f818..50612282f69 100644 --- a/storage/innodb_plugin/os/os0file.c +++ b/storage/innodb_plugin/os/os0file.c @@ -88,7 +88,9 @@ UNIV_INTERN ibool os_do_not_call_flush_at_each_write = FALSE; /* We do not call os_file_flush in every os_file_write. */ #endif /* UNIV_DO_FLUSH */ -#ifndef UNIV_HOTBACKUP +#ifdef UNIV_HOTBACKUP +# define os_aio_use_native_aio FALSE +#else /* UNIV_HOTBACKUP */ /* We use these mutexes to protect lseek + file i/o operation, if the OS does not provide an atomic pread or pwrite, or similar */ #define OS_FILE_N_SEEK_MUTEXES 16 @@ -198,7 +200,7 @@ static ulint os_aio_n_segments = ULINT_UNDEFINED; /** If the following is TRUE, read i/o handler threads try to wait until a batch of new read requests have been posted */ static ibool os_aio_recommend_sleep_for_read_threads = FALSE; -#endif /* !UNIV_HOTBACKUP */ +#endif /* UNIV_HOTBACKUP */ UNIV_INTERN ulint os_n_file_reads = 0; UNIV_INTERN ulint os_bytes_read_since_printout = 0; @@ -1245,6 +1247,7 @@ try_again: } #endif #ifdef UNIV_NON_BUFFERED_IO +# ifndef UNIV_HOTBACKUP if (type == OS_LOG_FILE && srv_flush_log_at_trx_commit == 2) { /* Do not use unbuffered i/o to log files because value 2 denotes that we do not flush the log at every @@ -1253,10 +1256,14 @@ try_again: == SRV_WIN_IO_UNBUFFERED) { attributes = attributes | FILE_FLAG_NO_BUFFERING; } -#endif +# else /* !UNIV_HOTBACKUP */ + attributes = attributes | FILE_FLAG_NO_BUFFERING; +# endif /* !UNIV_HOTBACKUP */ +#endif /* UNIV_NON_BUFFERED_IO */ } else if (purpose == OS_FILE_NORMAL) { attributes = 0; #ifdef UNIV_NON_BUFFERED_IO +# ifndef UNIV_HOTBACKUP if (type == OS_LOG_FILE && srv_flush_log_at_trx_commit == 2) { /* Do not use unbuffered i/o to log files because value 2 denotes that we do not flush the log at every @@ -1265,7 +1272,10 @@ try_again: == SRV_WIN_IO_UNBUFFERED) { attributes = attributes | FILE_FLAG_NO_BUFFERING; } -#endif +# else /* !UNIV_HOTBACKUP */ + attributes = attributes | FILE_FLAG_NO_BUFFERING; +# endif /* !UNIV_HOTBACKUP */ +#endif /* UNIV_NON_BUFFERED_IO */ } else { attributes = 0; ut_error; @@ -2227,7 +2237,9 @@ os_file_read( DWORD low; DWORD high; ibool retry; +#ifndef UNIV_HOTBACKUP ulint i; +#endif /* !UNIV_HOTBACKUP */ ut_a((offset & 0xFFFFFFFFUL) == offset); @@ -2246,16 +2258,20 @@ try_again: os_n_pending_reads++; os_mutex_exit(os_file_count_mutex); +#ifndef UNIV_HOTBACKUP /* Protect the seek / read operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; os_mutex_enter(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ ret2 = SetFilePointer(file, low, &high, FILE_BEGIN); if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) { +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads--; @@ -2266,7 +2282,9 @@ try_again: ret = ReadFile(file, buf, (DWORD) n, &len, NULL); +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads--; @@ -2275,7 +2293,7 @@ try_again: if (ret && len == n) { return(TRUE); } -#else +#else /* __WIN__ */ ibool retry; ssize_t ret; @@ -2294,7 +2312,7 @@ try_again: "InnoDB: Was only able to read %ld.\n", (ulong)n, (ulong)offset_high, (ulong)offset, (long)ret); -#endif +#endif /* __WIN__ */ #ifdef __WIN__ error_handling: #endif @@ -2343,7 +2361,9 @@ os_file_read_no_error_handling( DWORD low; DWORD high; ibool retry; +#ifndef UNIV_HOTBACKUP ulint i; +#endif /* !UNIV_HOTBACKUP */ ut_a((offset & 0xFFFFFFFFUL) == offset); @@ -2362,16 +2382,20 @@ try_again: os_n_pending_reads++; os_mutex_exit(os_file_count_mutex); +#ifndef UNIV_HOTBACKUP /* Protect the seek / read operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; os_mutex_enter(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ ret2 = SetFilePointer(file, low, &high, FILE_BEGIN); if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) { +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads--; @@ -2382,7 +2406,9 @@ try_again: ret = ReadFile(file, buf, (DWORD) n, &len, NULL); +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads--; @@ -2391,7 +2417,7 @@ try_again: if (ret && len == n) { return(TRUE); } -#else +#else /* __WIN__ */ ibool retry; ssize_t ret; @@ -2404,7 +2430,7 @@ try_again: return(TRUE); } -#endif +#endif /* __WIN__ */ #ifdef __WIN__ error_handling: #endif @@ -2463,9 +2489,11 @@ os_file_write( DWORD ret2; DWORD low; DWORD high; - ulint i; ulint n_retries = 0; ulint err; +#ifndef UNIV_HOTBACKUP + ulint i; +#endif /* !UNIV_HOTBACKUP */ ut_a((offset & 0xFFFFFFFF) == offset); @@ -2482,16 +2510,20 @@ retry: os_n_pending_writes++; os_mutex_exit(os_file_count_mutex); +#ifndef UNIV_HOTBACKUP /* Protect the seek / write operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; os_mutex_enter(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ ret2 = SetFilePointer(file, low, &high, FILE_BEGIN); if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) { +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_writes--; @@ -2525,7 +2557,9 @@ retry: } # endif /* UNIV_DO_FLUSH */ +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_writes--; diff --git a/storage/innodb_plugin/row/row0merge.c b/storage/innodb_plugin/row/row0merge.c index 9a51221732b..a968fe80864 100644 --- a/storage/innodb_plugin/row/row0merge.c +++ b/storage/innodb_plugin/row/row0merge.c @@ -1576,7 +1576,6 @@ row_merge( ulint ohalf; /*!< half the output file */ UNIV_MEM_ASSERT_W(block[0], 3 * sizeof block[0]); - ut_ad(ihalf > 0); ut_ad(ihalf < file->offset); of.fd = *tmpfd; @@ -1665,6 +1664,10 @@ row_merge_sort( { ulint half = file->offset / 2; + /* The file should always contain at least one byte (the end + of file marker). Thus, it must be at least one block. */ + ut_ad(file->offset > 0); + do { ulint error; @@ -1673,6 +1676,10 @@ row_merge_sort( if (error != DB_SUCCESS) { return(error); } + + /* half > 0 should hold except when the file consists + of one block. No need to merge further then. */ + ut_ad(half > 0 || file->offset == 1); } while (half < file->offset && half > 0); return(DB_SUCCESS); diff --git a/storage/innodb_plugin/ut/ut0ut.c b/storage/innodb_plugin/ut/ut0ut.c index 5857c9bdef4..498873e290a 100644 --- a/storage/innodb_plugin/ut/ut0ut.c +++ b/storage/innodb_plugin/ut/ut0ut.c @@ -206,7 +206,7 @@ value may wrap around. It should only be used for heuristic purposes. @return ms since epoch */ UNIV_INTERN -uint +ulint ut_time_ms(void) /*============*/ { @@ -214,7 +214,7 @@ ut_time_ms(void) ut_gettimeofday(&tv, NULL); - return((uint) tv.tv_sec * 1000 + tv.tv_usec / 1000); + return((ulint) tv.tv_sec * 1000 + tv.tv_usec / 1000); } #endif /* !UNIV_HOTBACKUP */ From 5da8781d7cfa8935a60335ea9bf5f665f12ced69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Bl=C3=A5udd?= Date: Thu, 8 Oct 2009 14:54:11 +0200 Subject: [PATCH 096/146] Bug #47797 CMake, engine can't specify additional libraries to link with - Make it possible for the CmakeLists.txt files in an engine to use ${engine}_LIBS to set additional libraries to link with Example: NDBCLUSTER_LIBS = ndbclient --- storage/mysql_storage_engine.cmake | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/storage/mysql_storage_engine.cmake b/storage/mysql_storage_engine.cmake index bb368494898..af8c3a85cd1 100644 --- a/storage/mysql_storage_engine.cmake +++ b/storage/mysql_storage_engine.cmake @@ -7,6 +7,8 @@ # Remarks: # ${engine}_SOURCES variable containing source files to produce the library must set before # calling this macro +# ${engine}_LIBS variable containing extra libraries to link with may be set + MACRO(MYSQL_STORAGE_ENGINE engine) IF(NOT SOURCE_SUBLIBS) @@ -22,6 +24,9 @@ IF(NOT SOURCE_SUBLIBS) #Create static library. The name of the library is .lib ADD_LIBRARY(${libname} ${${engine}_SOURCES}) ADD_DEPENDENCIES(${libname} GenError) + IF(${engine}_LIBS) + TARGET_LINK_LIBRARIES(${libname} ${${engine}_LIBS}) + ENDIF(${engine}_LIBS) MESSAGE("build ${engine} as static library") ELSEIF(${ENGINE_BUILD_TYPE} STREQUAL "DYNAMIC") ADD_DEFINITIONS(-DMYSQL_DYNAMIC_PLUGIN) @@ -30,6 +35,9 @@ IF(NOT SOURCE_SUBLIBS) SET(dyn_libname ha_${libname}) ADD_LIBRARY(${dyn_libname} SHARED ${${engine}_SOURCES}) TARGET_LINK_LIBRARIES (${dyn_libname} mysqld) + IF(${engine}_LIBS) + TARGET_LINK_LIBRARIES(${dyn_libname} ${${engine}_LIBS}) + ENDIF(${engine}_LIBS) MESSAGE("build ${engine} as DLL") ENDIF(${ENGINE_BUILD_TYPE} STREQUAL "STATIC") ENDIF(NOT SOURCE_SUBLIBS) From bf3b0747af10346bcdb97ea1cae42460f94b182e Mon Sep 17 00:00:00 2001 From: Satya B Date: Thu, 8 Oct 2009 18:35:59 +0530 Subject: [PATCH 097/146] Applying InnoDB Plugin 1.0.5 snapshot, part 7 From revisions r5792 to r5864 Detailed revision comments: r5792 | vasil | 2009-09-09 08:35:58 -0500 (Wed, 09 Sep 2009) | 32 lines branches/zip: Fix a bug in manipulating the variable innodb_old_blocks_pct: for any value assigned it got that value -1, except for 75. When assigned 75, it got 75. mysql> set global innodb_old_blocks_pct=15; Query OK, 0 rows affected (0.00 sec) mysql> show variables like 'innodb_old_blocks_pct'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | innodb_old_blocks_pct | 14 | +-----------------------+-------+ 1 row in set (0.00 sec) mysql> set global innodb_old_blocks_pct=75; Query OK, 0 rows affected (0.00 sec) mysql> show variables like 'innodb_old_blocks_pct'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | innodb_old_blocks_pct | 75 | +-----------------------+-------+ After the fix it gets exactly what was assigned. Approved by: Marko (via IM) r5798 | calvin | 2009-09-09 10:28:10 -0500 (Wed, 09 Sep 2009) | 5 lines branches/zip: HA_ERR_TOO_MANY_CONCURRENT_TRXS is added in 5.1.38. But the plugin should still work with previous versions of MySQL. r5804 | marko | 2009-09-10 00:29:31 -0500 (Thu, 10 Sep 2009) | 1 line branches/zip: trx_cleanup_at_db_startup(): Fix a typo in comment. r5822 | marko | 2009-09-10 05:10:20 -0500 (Thu, 10 Sep 2009) | 1 line branches/zip: buf_page_release(): De-stutter the function comment. r5825 | marko | 2009-09-10 05:47:09 -0500 (Thu, 10 Sep 2009) | 20 lines branches/zip: Reduce mutex contention that was introduced when addressing Bug #45015 (Issue #316), in r5703. buf_page_set_accessed_make_young(): New auxiliary function, called by buf_page_get_zip(), buf_page_get_gen(), buf_page_optimistic_get_func(). Call ut_time_ms() outside of buf_pool_mutex. Use cached access_time. buf_page_set_accessed(): Add the parameter time_ms, so that ut_time_ms() need not be called while holding buf_pool_mutex. buf_page_optimistic_get_func(), buf_page_get_known_nowait(): Read buf_page_t::access_time without holding buf_pool_mutex. This should be OK, because the field is only used for heuristic purposes. buf_page_peek_if_too_old(): If buf_pool->freed_page_clock == 0, return FALSE, so that we will not waste time moving blocks in the LRU list in the warm-up phase or when the workload fits in the buffer pool. rb://156 approved by Sunny Bains r5826 | marko | 2009-09-10 06:29:46 -0500 (Thu, 10 Sep 2009) | 12 lines branches/zip: Roll back recovered dictionary transactions before dropping incomplete indexes (Issue #337). trx_rollback_or_clean_recovered(ibool all): New function, split from trx_rollback_or_clean_all_recovered(). all==FALSE will only roll back dictionary transactions. recv_recovery_from_checkpoint_finish(): Call trx_rollback_or_clean_recovered(FALSE) before row_merge_drop_temp_indexes(). rb://158 approved by Sunny Bains r5858 | vasil | 2009-09-11 12:46:47 -0500 (Fri, 11 Sep 2009) | 4 lines branches/zip: Fix the indentation of the closing bracket. r5863 | vasil | 2009-09-12 02:07:08 -0500 (Sat, 12 Sep 2009) | 10 lines branches/zip: Check that pthread_t can indeed be passed to Solaris atomic functions, instead of assuming that it can be passed if 0 can be assigned to it. It could be that: * 0 can be assigned, but pthread_t cannot be passed and * 0 cannot be assigned but pthread_t can be passed Better to check what we are interested in, not something else and make assumptions. r5864 | vasil | 2009-09-12 02:22:55 -0500 (Sat, 12 Sep 2009) | 4 lines branches/zip: Include string.h which is needed for memset(). --- storage/innodb_plugin/buf/buf0buf.c | 86 ++++++++++++------- storage/innodb_plugin/buf/buf0lru.c | 4 +- storage/innodb_plugin/handler/ha_innodb.cc | 17 ++-- storage/innodb_plugin/include/buf0buf.h | 5 +- storage/innodb_plugin/include/buf0buf.ic | 23 +++-- storage/innodb_plugin/include/trx0roll.h | 11 +++ storage/innodb_plugin/include/trx0trx.h | 2 +- storage/innodb_plugin/log/log0recv.c | 5 ++ storage/innodb_plugin/plug.in | 4 +- storage/innodb_plugin/trx/trx0roll.c | 58 +++++++++---- storage/innodb_plugin/trx/trx0trx.c | 2 +- .../ut/ut0auxconf_atomic_pthread_t_solaris.c | 26 +++++- 12 files changed, 167 insertions(+), 76 deletions(-) diff --git a/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c index 6af3dff460a..32435bd1f87 100644 --- a/storage/innodb_plugin/buf/buf0buf.c +++ b/storage/innodb_plugin/buf/buf0buf.c @@ -1489,7 +1489,7 @@ buf_pool_resize(void) /********************************************************************//** Moves a page to the start of the buffer pool LRU list. This high-level -function can be used to prevent an important page from from slipping out of +function can be used to prevent an important page from slipping out of the buffer pool. */ UNIV_INTERN void @@ -1506,6 +1506,36 @@ buf_page_make_young( buf_pool_mutex_exit(); } +/********************************************************************//** +Sets the time of the first access of a page and moves a page to the +start of the buffer pool LRU list if it is too old. This high-level +function can be used to prevent an important page from slipping +out of the buffer pool. */ +static +void +buf_page_set_accessed_make_young( +/*=============================*/ + buf_page_t* bpage, /*!< in/out: buffer block of a + file page */ + unsigned access_time) /*!< in: bpage->access_time + read under mutex protection, + or 0 if unknown */ +{ + ut_ad(!buf_pool_mutex_own()); + ut_a(buf_page_in_file(bpage)); + + if (buf_page_peek_if_too_old(bpage)) { + buf_pool_mutex_enter(); + buf_LRU_make_block_young(bpage); + buf_pool_mutex_exit(); + } else if (!access_time) { + ulint time_ms = ut_time_ms(); + buf_pool_mutex_enter(); + buf_page_set_accessed(bpage, time_ms); + buf_pool_mutex_exit(); + } +} + /********************************************************************//** Resets the check_index_page_at_flush field of a page if found in the buffer pool. */ @@ -1637,6 +1667,7 @@ buf_page_get_zip( buf_page_t* bpage; mutex_t* block_mutex; ibool must_read; + unsigned access_time; #ifndef UNIV_LOG_DEBUG ut_ad(!ibuf_inside()); @@ -1704,17 +1735,14 @@ err_exit: got_block: must_read = buf_page_get_io_fix(bpage) == BUF_IO_READ; - - if (buf_page_peek_if_too_old(bpage)) { - buf_LRU_make_block_young(bpage); - } - - buf_page_set_accessed(bpage); + access_time = buf_page_is_accessed(bpage); buf_pool_mutex_exit(); mutex_exit(block_mutex); + buf_page_set_accessed_make_young(bpage, access_time); + #ifdef UNIV_DEBUG_FILE_ACCESSES ut_a(!bpage->file_page_was_freed); #endif @@ -2244,14 +2272,10 @@ wait_until_unfixed: access_time = buf_page_is_accessed(&block->page); - if (buf_page_peek_if_too_old(&block->page)) { - buf_LRU_make_block_young(&block->page); - } - - buf_page_set_accessed(&block->page); - buf_pool_mutex_exit(); + buf_page_set_accessed_make_young(&block->page, access_time); + #ifdef UNIV_DEBUG_FILE_ACCESSES ut_a(!block->page.file_page_was_freed); #endif @@ -2353,18 +2377,13 @@ buf_page_optimistic_get_func( mutex_exit(&block->mutex); - buf_pool_mutex_enter(); + /* Check if this is the first access to the page. + We do a dirty read on purpose, to avoid mutex contention. + This field is only used for heuristic purposes; it does not + affect correctness. */ - /* Check if this is the first access to the page */ access_time = buf_page_is_accessed(&block->page); - - if (buf_page_peek_if_too_old(&block->page)) { - buf_LRU_make_block_young(&block->page); - } - - buf_page_set_accessed(&block->page); - - buf_pool_mutex_exit(); + buf_page_set_accessed_make_young(&block->page, access_time); ut_ad(!ibuf_inside() || ibuf_page(buf_block_get_space(block), @@ -2477,16 +2496,22 @@ buf_page_get_known_nowait( mutex_exit(&block->mutex); - buf_pool_mutex_enter(); - if (mode == BUF_MAKE_YOUNG && buf_page_peek_if_too_old(&block->page)) { + buf_pool_mutex_enter(); buf_LRU_make_block_young(&block->page); + buf_pool_mutex_exit(); + } else if (!buf_page_is_accessed(&block->page)) { + /* Above, we do a dirty read on purpose, to avoid + mutex contention. The field buf_page_t::access_time + is only used for heuristic purposes. Writes to the + field must be protected by mutex, however. */ + ulint time_ms = ut_time_ms(); + + buf_pool_mutex_enter(); + buf_page_set_accessed(&block->page, time_ms); + buf_pool_mutex_exit(); } - buf_page_set_accessed(&block->page); - - buf_pool_mutex_exit(); - ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD)); if (rw_latch == RW_S_LATCH) { @@ -2917,6 +2942,7 @@ buf_page_create( buf_frame_t* frame; buf_block_t* block; buf_block_t* free_block = NULL; + ulint time_ms = ut_time_ms(); ut_ad(mtr); ut_ad(space || !zip_size); @@ -3000,7 +3026,7 @@ buf_page_create( rw_lock_x_unlock(&block->lock); } - buf_page_set_accessed(&block->page); + buf_page_set_accessed(&block->page, time_ms); buf_pool_mutex_exit(); diff --git a/storage/innodb_plugin/buf/buf0lru.c b/storage/innodb_plugin/buf/buf0lru.c index e7cf852e200..dd632ace4ac 100644 --- a/storage/innodb_plugin/buf/buf0lru.c +++ b/storage/innodb_plugin/buf/buf0lru.c @@ -1866,7 +1866,9 @@ buf_LRU_old_ratio_update( buf_LRU_old_ratio = ratio; } - return(ratio * 100 / BUF_LRU_OLD_RATIO_DIV); + /* the reverse of + ratio = old_pct * BUF_LRU_OLD_RATIO_DIV / 100 */ + return((uint) (ratio * 100 / (double) BUF_LRU_OLD_RATIO_DIV + 0.5)); } /********************************************************************//** diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index d279f0ba4f3..1d72d09727e 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -868,17 +868,14 @@ convert_error_code_to_mysql( return(ER_PRIMARY_CANT_HAVE_NULL); case DB_TOO_MANY_CONCURRENT_TRXS: - /* Once MySQL add the appropriate code to errmsg.txt then - we can get rid of this #ifdef. NOTE: The code checked by - the #ifdef is the suggested name for the error condition - and the actual error code name could very well be different. - This will require some monitoring, ie. the status - of this request on our part.*/ -#ifdef ER_TOO_MANY_CONCURRENT_TRXS - return(ER_TOO_MANY_CONCURRENT_TRXS); -#else + /* New error code HA_ERR_TOO_MANY_CONCURRENT_TRXS is only + available in 5.1.38 and later, but the plugin should still + work with previous versions of MySQL. */ +#ifdef HA_ERR_TOO_MANY_CONCURRENT_TRXS + return(HA_ERR_TOO_MANY_CONCURRENT_TRXS); +#else /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */ return(HA_ERR_RECORD_FILE_FULL); -#endif +#endif /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */ case DB_UNSUPPORTED: return(HA_ERR_UNSUPPORTED); } diff --git a/storage/innodb_plugin/include/buf0buf.h b/storage/innodb_plugin/include/buf0buf.h index db95aa7ce21..e9d95a14f1b 100644 --- a/storage/innodb_plugin/include/buf0buf.h +++ b/storage/innodb_plugin/include/buf0buf.h @@ -346,7 +346,7 @@ buf_page_release( mtr_t* mtr); /*!< in: mtr */ /********************************************************************//** Moves a page to the start of the buffer pool LRU list. This high-level -function can be used to prevent an important page from from slipping out of +function can be used to prevent an important page from slipping out of the buffer pool. */ UNIV_INTERN void @@ -821,7 +821,8 @@ UNIV_INLINE void buf_page_set_accessed( /*==================*/ - buf_page_t* bpage) /*!< in/out: control block */ + buf_page_t* bpage, /*!< in/out: control block */ + ulint time_ms) /*!< in: ut_time_ms() */ __attribute__((nonnull)); /*********************************************************************//** Gets the buf_block_t handle of a buffered file block if an uncompressed diff --git a/storage/innodb_plugin/include/buf0buf.ic b/storage/innodb_plugin/include/buf0buf.ic index 18ee4551eb4..8b1f904a090 100644 --- a/storage/innodb_plugin/include/buf0buf.ic +++ b/storage/innodb_plugin/include/buf0buf.ic @@ -72,10 +72,16 @@ buf_page_peek_if_too_old( /*=====================*/ const buf_page_t* bpage) /*!< in: block to make younger */ { - if (buf_LRU_old_threshold_ms && bpage->old) { + if (UNIV_UNLIKELY(buf_pool->freed_page_clock == 0)) { + /* If eviction has not started yet, do not update the + statistics or move blocks in the LRU list. This is + either the warm-up phase or an in-memory workload. */ + return(FALSE); + } else if (buf_LRU_old_threshold_ms && bpage->old) { unsigned access_time = buf_page_is_accessed(bpage); - if (access_time && ut_time_ms() - access_time + if (access_time > 0 + && (ut_time_ms() - access_time) >= buf_LRU_old_threshold_ms) { return(TRUE); } @@ -85,10 +91,10 @@ buf_page_peek_if_too_old( } else { /* FIXME: bpage->freed_page_clock is 31 bits */ return((buf_pool->freed_page_clock & ((1UL << 31) - 1)) - > bpage->freed_page_clock - + (buf_pool->curr_size - * (BUF_LRU_OLD_RATIO_DIV - buf_LRU_old_ratio) - / (BUF_LRU_OLD_RATIO_DIV * 4))); + > ((ulint) bpage->freed_page_clock + + (buf_pool->curr_size + * (BUF_LRU_OLD_RATIO_DIV - buf_LRU_old_ratio) + / (BUF_LRU_OLD_RATIO_DIV * 4)))); } } @@ -490,14 +496,15 @@ UNIV_INLINE void buf_page_set_accessed( /*==================*/ - buf_page_t* bpage) /*!< in/out: control block */ + buf_page_t* bpage, /*!< in/out: control block */ + ulint time_ms) /*!< in: ut_time_ms() */ { ut_a(buf_page_in_file(bpage)); ut_ad(buf_pool_mutex_own()); if (!bpage->access_time) { /* Make this the time of the first access. */ - bpage->access_time = ut_time_ms(); + bpage->access_time = time_ms; } } diff --git a/storage/innodb_plugin/include/trx0roll.h b/storage/innodb_plugin/include/trx0roll.h index 37205dcd4b3..1dee5655c8c 100644 --- a/storage/innodb_plugin/include/trx0roll.h +++ b/storage/innodb_plugin/include/trx0roll.h @@ -133,6 +133,17 @@ trx_rollback( Rollback or clean up any incomplete transactions which were encountered in crash recovery. If the transaction already was committed, then we clean up a possible insert undo log. If the +transaction was not yet committed, then we roll it back. */ +UNIV_INTERN +void +trx_rollback_or_clean_recovered( +/*============================*/ + ibool all); /*!< in: FALSE=roll back dictionary transactions; + TRUE=roll back all non-PREPARED transactions */ +/*******************************************************************//** +Rollback or clean up any incomplete transactions which were +encountered in crash recovery. If the transaction already was +committed, then we clean up a possible insert undo log. If the transaction was not yet committed, then we roll it back. Note: this is done in a background thread. @return a dummy parameter */ diff --git a/storage/innodb_plugin/include/trx0trx.h b/storage/innodb_plugin/include/trx0trx.h index 4b79732b4bf..d2a59740c93 100644 --- a/storage/innodb_plugin/include/trx0trx.h +++ b/storage/innodb_plugin/include/trx0trx.h @@ -179,7 +179,7 @@ trx_commit_off_kernel( /****************************************************************//** Cleans up a transaction at database startup. The cleanup is needed if the transaction already got to the middle of a commit when the database -crashed, andf we cannot roll it back. */ +crashed, and we cannot roll it back. */ UNIV_INTERN void trx_cleanup_at_db_startup( diff --git a/storage/innodb_plugin/log/log0recv.c b/storage/innodb_plugin/log/log0recv.c index 971c5600d39..e2d85b2f1bb 100644 --- a/storage/innodb_plugin/log/log0recv.c +++ b/storage/innodb_plugin/log/log0recv.c @@ -3118,6 +3118,11 @@ recv_recovery_from_checkpoint_finish(void) #ifndef UNIV_LOG_DEBUG recv_sys_free(); #endif + /* Roll back any recovered data dictionary transactions, so + that the data dictionary tables will be free of any locks. + The data dictionary latch should guarantee that there is at + most one data dictionary transaction active at a time. */ + trx_rollback_or_clean_recovered(FALSE); /* Drop partially created indexes. */ row_merge_drop_temp_indexes(); diff --git a/storage/innodb_plugin/plug.in b/storage/innodb_plugin/plug.in index 230c6ed34df..195800462aa 100644 --- a/storage/innodb_plugin/plug.in +++ b/storage/innodb_plugin/plug.in @@ -112,7 +112,7 @@ MYSQL_PLUGIN_ACTIONS(innodb_plugin, [ [ AC_MSG_RESULT(no) ] - ) + ) AC_MSG_CHECKING(whether pthread_t can be used by GCC atomic builtins) AC_TRY_RUN( @@ -142,7 +142,7 @@ MYSQL_PLUGIN_ACTIONS(innodb_plugin, [ [ AC_MSG_RESULT(no) ] - ) + ) # Try using solaris atomics on SunOS if GCC atomics are not available AC_CHECK_DECLS( diff --git a/storage/innodb_plugin/trx/trx0roll.c b/storage/innodb_plugin/trx/trx0roll.c index b139a8a19af..c925478cdf4 100644 --- a/storage/innodb_plugin/trx/trx0roll.c +++ b/storage/innodb_plugin/trx/trx0roll.c @@ -532,28 +532,26 @@ trx_rollback_active( Rollback or clean up any incomplete transactions which were encountered in crash recovery. If the transaction already was committed, then we clean up a possible insert undo log. If the -transaction was not yet committed, then we roll it back. -Note: this is done in a background thread. -@return a dummy parameter */ +transaction was not yet committed, then we roll it back. */ UNIV_INTERN -os_thread_ret_t -trx_rollback_or_clean_all_recovered( -/*================================*/ - void* arg __attribute__((unused))) - /*!< in: a dummy parameter required by - os_thread_create */ +void +trx_rollback_or_clean_recovered( +/*============================*/ + ibool all) /*!< in: FALSE=roll back dictionary transactions; + TRUE=roll back all non-PREPARED transactions */ { trx_t* trx; mutex_enter(&kernel_mutex); - if (UT_LIST_GET_FIRST(trx_sys->trx_list)) { + if (!UT_LIST_GET_FIRST(trx_sys->trx_list)) { + goto leave_function; + } + if (all) { fprintf(stderr, "InnoDB: Starting in background the rollback" " of uncommitted transactions\n"); - } else { - goto leave_function; } mutex_exit(&kernel_mutex); @@ -582,18 +580,42 @@ loop: goto loop; case TRX_ACTIVE: - mutex_exit(&kernel_mutex); - trx_rollback_active(trx); - goto loop; + if (all || trx_get_dict_operation(trx) + != TRX_DICT_OP_NONE) { + mutex_exit(&kernel_mutex); + trx_rollback_active(trx); + goto loop; + } } } - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Rollback of non-prepared transactions completed\n"); + if (all) { + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Rollback of non-prepared" + " transactions completed\n"); + } leave_function: mutex_exit(&kernel_mutex); +} + +/*******************************************************************//** +Rollback or clean up any incomplete transactions which were +encountered in crash recovery. If the transaction already was +committed, then we clean up a possible insert undo log. If the +transaction was not yet committed, then we roll it back. +Note: this is done in a background thread. +@return a dummy parameter */ +UNIV_INTERN +os_thread_ret_t +trx_rollback_or_clean_all_recovered( +/*================================*/ + void* arg __attribute__((unused))) + /*!< in: a dummy parameter required by + os_thread_create */ +{ + trx_rollback_or_clean_recovered(TRUE); /* We count the number of threads in os_thread_exit(). A created thread should always use that to exit and not use return() to exit. */ diff --git a/storage/innodb_plugin/trx/trx0trx.c b/storage/innodb_plugin/trx/trx0trx.c index 4d4885062a6..1e36a2e4fe7 100644 --- a/storage/innodb_plugin/trx/trx0trx.c +++ b/storage/innodb_plugin/trx/trx0trx.c @@ -950,7 +950,7 @@ trx_commit_off_kernel( /****************************************************************//** Cleans up a transaction at database startup. The cleanup is needed if the transaction already got to the middle of a commit when the database -crashed, andf we cannot roll it back. */ +crashed, and we cannot roll it back. */ UNIV_INTERN void trx_cleanup_at_db_startup( diff --git a/storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_solaris.c b/storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_solaris.c index a18a537d1d4..310603c7503 100644 --- a/storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_solaris.c +++ b/storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_solaris.c @@ -17,18 +17,38 @@ Place, Suite 330, Boston, MA 02111-1307 USA *****************************************************************************/ /***************************************************************************** -If this program compiles, then pthread_t objects can be used as arguments -to Solaris libc atomic functions. +If this program compiles and returns 0, then pthread_t objects can be used as +arguments to Solaris libc atomic functions. Created April 18, 2009 Vasil Dimov *****************************************************************************/ #include +#include int main(int argc, char** argv) { - pthread_t x = 0; + pthread_t x1; + pthread_t x2; + pthread_t x3; + + memset(&x1, 0x0, sizeof(x1)); + memset(&x2, 0x0, sizeof(x2)); + memset(&x3, 0x0, sizeof(x3)); + + if (sizeof(pthread_t) == 4) { + + atomic_cas_32(&x1, x2, x3); + + } else if (sizeof(pthread_t) == 8) { + + atomic_cas_64(&x1, x2, x3); + + } else { + + return(1); + } return(0); } From b92892dc9cc30ba2c6fd83ed684afe3ef4279f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Bl=C3=A5udd?= Date: Thu, 8 Oct 2009 15:19:24 +0200 Subject: [PATCH 098/146] Bug #47795 CMake, storage engine name different from directory name - Read plug.in to fid the name of the engine to link with, does not have to be same as engine dir - Use engine dir when figuring out which libraries to build limbysqld with --- CMakeLists.txt | 9 +++++++-- libmysqld/CMakeLists.txt | 13 +++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c40312e32b..7da3bd05cef 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,12 +217,16 @@ ENDIF(WITHOUT_DYNAMIC_PLUGINS) FILE(GLOB STORAGE_SUBDIRS storage/*) FOREACH(SUBDIR ${STORAGE_SUBDIRS}) FILE(RELATIVE_PATH DIRNAME ${PROJECT_SOURCE_DIR}/storage ${SUBDIR}) - STRING(TOUPPER ${DIRNAME} ENGINE) - STRING(TOLOWER ${DIRNAME} ENGINE_LOWER) IF (EXISTS ${SUBDIR}/CMakeLists.txt) # Check MYSQL_STORAGE_ENGINE macro is present FILE(STRINGS ${SUBDIR}/CMakeLists.txt HAVE_STORAGE_ENGINE REGEX MYSQL_STORAGE_ENGINE) IF(HAVE_STORAGE_ENGINE) + # Extract name of engine from HAVE_STORAGE_ENGINE + STRING(REGEX REPLACE ".*MYSQL_STORAGE_ENGINE\\((.*\)\\).*" + "\\1" ENGINE_NAME ${HAVE_STORAGE_ENGINE}) + STRING(TOUPPER ${ENGINE_NAME} ENGINE) + STRING(TOLOWER ${ENGINE_NAME} ENGINE_LOWER) + SET(ENGINE_BUILD_TYPE "DYNAMIC") # Read plug.in to find out if a plugin is mandatory and whether it supports # build as shared library (dynamic). @@ -248,6 +252,7 @@ FOREACH(SUBDIR ${STORAGE_SUBDIRS}) SET (MYSQLD_STATIC_ENGINE_LIBS ${MYSQLD_STATIC_ENGINE_LIBS} ${ENGINE_LOWER}) SET (STORAGE_ENGINE_DEFS "${STORAGE_ENGINE_DEFS} -DWITH_${ENGINE}_STORAGE_ENGINE") SET (WITH_${ENGINE}_STORAGE_ENGINE TRUE) + SET (${ENGINE}_DIR ${DIRNAME}) ENDIF (ENGINE_BUILD_TYPE STREQUAL "STATIC") ENDIF(EXISTS ${SUBDIR}/plug.in) diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index bea6f6c0e1f..db398258b69 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -90,10 +90,11 @@ ENDFOREACH(rpath) FOREACH (ENGINE_LIB ${MYSQLD_STATIC_ENGINE_LIBS}) - INCLUDE(${CMAKE_SOURCE_DIR}/storage/${ENGINE_LIB}/CMakeLists.txt) STRING(TOUPPER ${ENGINE_LIB} ENGINE_LIB_UPPER) + SET(ENGINE_DIR ${${ENGINE_LIB_UPPER}_DIR}) + INCLUDE(${CMAKE_SOURCE_DIR}/storage/${ENGINE_DIR}/CMakeLists.txt) FOREACH(rpath ${${ENGINE_LIB_UPPER}_SOURCES}) - SET(LIB_SOURCES ${LIB_SOURCES} ${CMAKE_SOURCE_DIR}/storage/${ENGINE_LIB}/${rpath}) + SET(LIB_SOURCES ${LIB_SOURCES} ${CMAKE_SOURCE_DIR}/storage/${ENGINE_DIR}/${rpath}) ENDFOREACH(rpath) ENDFOREACH(ENGINE_LIB) @@ -155,6 +156,14 @@ ADD_LIBRARY(mysqlserver STATIC ${LIBMYSQLD_SOURCES}) ADD_DEPENDENCIES(mysqlserver GenServerSource GenError) TARGET_LINK_LIBRARIES(mysqlserver) +# Add any additional libraries requested by engine(s) +FOREACH (ENGINE_LIB ${MYSQLD_STATIC_ENGINE_LIBS}) + STRING(TOUPPER ${ENGINE_LIB} ENGINE_LIB_UPPER) + IF(${ENGINE_LIB_UPPER}_LIBS) + TARGET_LINK_LIBRARIES(mysqlserver ${${ENGINE_LIB_UPPER}_LIBS}) + ENDIF(${ENGINE_LIB_UPPER}_LIBS) +ENDFOREACH(ENGINE_LIB) + ADD_LIBRARY(libmysqld SHARED cmake_dummy.c libmysqld.def) ADD_DEPENDENCIES(libmysqld mysqlserver) TARGET_LINK_LIBRARIES(libmysqld mysqlserver wsock32) From 03904aee4ef2fb72408053bd3ca4cc9ccc952c59 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 8 Oct 2009 16:21:07 +0300 Subject: [PATCH 099/146] Addendum to the fix for bug 43029 --- sql/mysql_priv.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 6fde16d3049..c04b1f5ae38 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -2433,6 +2433,7 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr) table->tablenr= tablenr; table->map= (table_map) 1 << tablenr; table->force_index= table_list->force_index; + table->force_index_order= table->force_index_group= 0; table->covering_keys= table->s->keys_for_keyread; table->merge_keys.clear_all(); } From 87a4644db8715c1d04560f8c80a776d5a7ebfd9e Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Thu, 8 Oct 2009 15:36:43 +0200 Subject: [PATCH 100/146] Bug#46922: crash when adding partitions and open_files_limit is reached Problem was bad error handling, leaving some new temporary partitions locked and initialized and some not yet initialized and locked, leading to a crash when trying to unlock the not yet initialized and locked partitions Solution was to unlock the already locked partitions, and not include any of the new temporary partitions in later unlocks --- .../r/partition_open_files_limit.result | 22 +++++++++++++++++++ .../t/partition_open_files_limit-master.opt | 1 + mysql-test/t/partition_open_files_limit.test | 19 ++++++++++++++++ sql/ha_partition.cc | 2 +- 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 mysql-test/r/partition_open_files_limit.result create mode 100644 mysql-test/t/partition_open_files_limit-master.opt create mode 100644 mysql-test/t/partition_open_files_limit.test diff --git a/mysql-test/r/partition_open_files_limit.result b/mysql-test/r/partition_open_files_limit.result new file mode 100644 index 00000000000..1441ba4e78e --- /dev/null +++ b/mysql-test/r/partition_open_files_limit.result @@ -0,0 +1,22 @@ +DROP TABLE IF EXISTS `t1`; +# Bug#46922: crash when adding partitions and open_files_limit is reached +CREATE TABLE t1 (a INT PRIMARY KEY) +ENGINE=MyISAM PARTITION BY KEY () PARTITIONS 1; +INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11); +# if the bug exists, then crash will happen here +ALTER TABLE t1 ADD PARTITION PARTITIONS 511; +ERROR HY000: Out of resources when opening file '' (Errcode: 24) +SELECT * FROM t1; +a +1 +10 +11 +2 +3 +4 +5 +6 +7 +8 +9 +DROP TABLE t1; diff --git a/mysql-test/t/partition_open_files_limit-master.opt b/mysql-test/t/partition_open_files_limit-master.opt new file mode 100644 index 00000000000..4c1ed0c3da3 --- /dev/null +++ b/mysql-test/t/partition_open_files_limit-master.opt @@ -0,0 +1 @@ +--open-files-limit=5 --max_connections=2 --table_open_cache=1 diff --git a/mysql-test/t/partition_open_files_limit.test b/mysql-test/t/partition_open_files_limit.test new file mode 100644 index 00000000000..92a9b18b573 --- /dev/null +++ b/mysql-test/t/partition_open_files_limit.test @@ -0,0 +1,19 @@ +--source include/have_partition.inc + +--disable_warnings +DROP TABLE IF EXISTS `t1`; +--enable_warnings + +# +--echo # Bug#46922: crash when adding partitions and open_files_limit is reached +# +CREATE TABLE t1 (a INT PRIMARY KEY) +ENGINE=MyISAM PARTITION BY KEY () PARTITIONS 1; +INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11); +--echo # if the bug exists, then crash will happen here +--replace_regex /file '.*'/file ''/ +--error 23 +ALTER TABLE t1 ADD PARTITION PARTITIONS 511; +--sorted_result +SELECT * FROM t1; +DROP TABLE t1; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 5b053ab9cac..6b5350a82cd 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1280,10 +1280,10 @@ void ha_partition::cleanup_new_partition(uint part_count) m_file= m_added_file; m_added_file= NULL; + external_lock(ha_thd(), F_UNLCK); /* delete_table also needed, a bit more complex */ close(); - m_added_file= m_file; m_file= save_m_file; } DBUG_VOID_RETURN; From 27b80f9db8f611cc9f4d28d58efc34697363e875 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Thu, 8 Oct 2009 15:58:17 +0200 Subject: [PATCH 101/146] Bug#44059: Incorrect cardinality of indexes on a partitioned table backport for bug#44059 from mysql-pe to mysql-5.1-bugteam Using the partition with most rows instead of first partition to estimate the cardinality of indexes. --- mysql-test/r/partition.result | 15 +++++++++++++++ mysql-test/t/partition.test | 13 +++++++++++++ sql/ha_partition.cc | 34 +++++++++++++++++++++++++++------- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 2d54a66fe11..6611d39628f 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -50,6 +50,21 @@ t1 CREATE TABLE `t1` ( PARTITION p3 VALUES LESS THAN (733969) ENGINE = MyISAM, PARTITION pmax VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ DROP TABLE t1; +create table t1 (a int, b int, key(a)) +partition by list (a) +( partition p0 values in (1), +partition p1 values in (2)); +insert into t1 values (1,1),(2,1),(2,2),(2,3); +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A 1 NULL NULL YES BTREE +drop table t1; CREATE TABLE t1 (a INT, FOREIGN KEY (a) REFERENCES t0 (a)) ENGINE=MyISAM PARTITION BY HASH (a); diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index c5ed098b678..1dfc53c6232 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -61,6 +61,19 @@ SELECT * FROM t1; SHOW CREATE TABLE t1; DROP TABLE t1; +# +# Bug#44059: rec_per_key on empty partition gives weird optimiser results +# +create table t1 (a int, b int, key(a)) +partition by list (a) +( partition p0 values in (1), + partition p1 values in (2)); +insert into t1 values (1,1),(2,1),(2,2),(2,3); +show indexes from t1; +analyze table t1; +show indexes from t1; +drop table t1; + # # Bug#36001: Partitions: spelling and using some error messages # diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index df5badccb1e..ac55c4e718e 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -5011,8 +5011,9 @@ int ha_partition::info(uint flag) If the handler doesn't support statistics, it should set all of the above to 0. - We will allow the first handler to set the rec_per_key and use - this as an estimate on the total table. + We first scans through all partitions to get the one holding most rows. + We will then allow the handler with the most rows to set + the rec_per_key and use this as an estimate on the total table. max_data_file_length: Maximum data file length We ignore it, is only used in @@ -5024,14 +5025,33 @@ int ha_partition::info(uint flag) ref_length: We set this to the value calculated and stored in local object create_time: Creation time of table - Set by first handler - So we calculate these constants by using the variables on the first - handler. + So we calculate these constants by using the variables from the + handler with most rows. */ - handler *file; + handler *file, **file_array; + ulonglong max_records= 0; + uint32 i= 0; + uint32 handler_instance= 0; - file= m_file[0]; + file_array= m_file; + do + { + file= *file_array; + /* Get variables if not already done */ + if (!(flag & HA_STATUS_VARIABLE) || + !bitmap_is_set(&(m_part_info->used_partitions), + (file_array - m_file))) + file->info(HA_STATUS_VARIABLE); + if (file->stats.records > max_records) + { + max_records= file->stats.records; + handler_instance= i; + } + i++; + } while (*(++file_array)); + + file= m_file[handler_instance]; file->info(HA_STATUS_CONST); stats.create_time= file->stats.create_time; ref_length= m_ref_length; From 844eb557e64cc4fe03db48493b7f55728f4f4f32 Mon Sep 17 00:00:00 2001 From: Frazer Clement Date: Thu, 8 Oct 2009 16:23:15 +0100 Subject: [PATCH 102/146] Fix compile break from bug#39663 fix --- client/mysqltest.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index fb33d30da81..442b2020a56 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -6214,8 +6214,10 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, MYSQL_STMT *stmt; DYNAMIC_STRING ds_prepare_warnings; DYNAMIC_STRING ds_execute_warnings; + ulonglong affected_rows; DBUG_ENTER("run_query_stmt"); DBUG_PRINT("query", ("'%-.60s'", query)); + LINT_INIT(affected_rows); /* Init a new stmt if it's not already one created for this connection @@ -6350,9 +6352,6 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, Need to grab affected rows information before getting warnings here */ - ulonglong affected_rows; - LINT_INIT(affected_rows); - if (!disable_info) affected_rows= mysql_affected_rows(mysql); From 5184530308466e83b8a77c35e05201778cdc6827 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Thu, 8 Oct 2009 21:58:17 +0200 Subject: [PATCH 103/146] Fix bug#47923 New "mf_keycache.c" requires thread support The bug is a compilation issue: Function "find_key_block()" had thread operations which were not guarded by "#if THREAD", add that now. --- mysys/mf_keycache.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index 3c11e6731b7..6ffa8fb3ea8 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -1742,6 +1742,7 @@ restart: - block assigned but not yet read from file (invalid data). */ +#if THREAD if (keycache->in_resize) { /* This is a request during a resize operation */ @@ -1983,6 +1984,9 @@ restart: } DBUG_RETURN(0); } +#else /* THREAD */ + DBUG_ASSERT(!keycache->in_resize); +#endif if (page_status == PAGE_READ && (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH | From 60132409f8b8c52ec4c3c9fe3a1b0b31399d501a Mon Sep 17 00:00:00 2001 From: Kent Boortz Date: Thu, 8 Oct 2009 22:55:28 +0200 Subject: [PATCH 104/146] "MySQL Network" => "MySQL Enterprise" --- client/mysql.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysql.cc b/client/mysql.cc index d103a3eec17..0b8b44b3421 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2813,7 +2813,7 @@ com_help(String *buffer __attribute__((unused)), "For developer information, including the MySQL Reference Manual, " "visit:\n" " http://dev.mysql.com/\n" - "To buy MySQL Network Support, training, or other products, visit:\n" + "To buy MySQL Enterprise support, training, or other products, visit:\n" " https://shop.mysql.com/\n", INFO_INFO); put_info("List of all MySQL commands:", INFO_INFO); if (!named_cmds) From e94ae02cbcbf71157857a414a0c48bf60ea5f2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Bl=C3=A5udd?= Date: Fri, 9 Oct 2009 09:53:29 +0200 Subject: [PATCH 105/146] BUG#47850: too many files built in regex/ - Don't build split.c or debug.c since they are not part of the actual regex library --- regex/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regex/CMakeLists.txt b/regex/CMakeLists.txt index a3088c00357..2e3b18c7bb0 100755 --- a/regex/CMakeLists.txt +++ b/regex/CMakeLists.txt @@ -18,7 +18,7 @@ SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -DSAFEMALLOC -DSAFE_MUT INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) -SET(REGEX_SOURCES debug.c regcomp.c regerror.c regexec.c regfree.c reginit.c split.c) +SET(REGEX_SOURCES regcomp.c regerror.c regexec.c regfree.c reginit.c) IF(NOT SOURCE_SUBLIBS) ADD_LIBRARY(regex ${REGEX_SOURCES}) From 090985ffe650cd78e875282089749c54a22830fc Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Fri, 9 Oct 2009 16:54:48 +0800 Subject: [PATCH 106/146] Bug#47323 : mysqlbinlog --verbose displays bad output when events contain subset of columns Commit the non-NDB specific part (originated by frazer) to 5.1 mainline. --- .../r/binlog_row_mysqlbinlog_verbose.result | 161 ++++++++++++++++++ .../binlog/std_data/update-full-row.binlog | Bin 0 -> 614 bytes .../binlog/std_data/update-partial-row.binlog | Bin 0 -> 606 bytes .../binlog/std_data/write-full-row.binlog | Bin 0 -> 571 bytes .../binlog/std_data/write-partial-row.binlog | Bin 0 -> 596 bytes .../t/binlog_row_mysqlbinlog_verbose.test | 82 +++++++++ sql/log_event.cc | 6 +- 7 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result create mode 100644 mysql-test/suite/binlog/std_data/update-full-row.binlog create mode 100644 mysql-test/suite/binlog/std_data/update-partial-row.binlog create mode 100644 mysql-test/suite/binlog/std_data/write-full-row.binlog create mode 100644 mysql-test/suite/binlog/std_data/write-partial-row.binlog create mode 100644 mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test diff --git a/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result new file mode 100644 index 00000000000..f1a3fafc498 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result @@ -0,0 +1,161 @@ +Verbose statements from : write-partial-row.binlog +select txt from raw_binlog_rows where txt like '###%'; +txt +### INSERT INTO mysql.ndb_apply_status +### SET +### @1=1 +### @2=25769803786 +### @3='' +### @4=0 +### @5=0 +### INSERT INTO test.ba +### SET +### @1=3 +### @2=3 +### @3=3 +### INSERT INTO test.ba +### SET +### @1=1 +### @2=1 +### @3=1 +### INSERT INTO test.ba +### SET +### @1=2 +### @2=2 +### @3=2 +### INSERT INTO test.ba +### SET +### @1=4 +### @2=4 +### @3=4 +### INSERT INTO test.ba +### SET +### @1=4 +### @3=40 +### DELETE FROM test.ba +### WHERE +### @1=2 +drop table raw_binlog_rows; +Verbose statements from : write-full-row.binlog +select txt from raw_binlog_rows where txt like '###%'; +txt +### INSERT INTO mysql.ndb_apply_status +### SET +### @1=2 +### @2=25769803786 +### @3='' +### @4=0 +### @5=0 +### INSERT INTO test.ba +### SET +### @1=3 +### @2=3 +### @3=3 +### INSERT INTO test.ba +### SET +### @1=1 +### @2=1 +### @3=1 +### INSERT INTO test.ba +### SET +### @1=2 +### @2=2 +### @3=2 +### INSERT INTO test.ba +### SET +### @1=4 +### @2=4 +### @3=4 +### INSERT INTO test.ba +### SET +### @1=4 +### @2=4 +### @3=40 +### DELETE FROM test.ba +### WHERE +### @1=2 +drop table raw_binlog_rows; +Verbose statements from : update-partial-row.binlog +select txt from raw_binlog_rows where txt like '###%'; +txt +### INSERT INTO mysql.ndb_apply_status +### SET +### @1=3 +### @2=25769803786 +### @3='' +### @4=0 +### @5=0 +### INSERT INTO test.ba +### SET +### @1=3 +### @2=3 +### @3=3 +### INSERT INTO test.ba +### SET +### @1=1 +### @2=1 +### @3=1 +### INSERT INTO test.ba +### SET +### @1=2 +### @2=2 +### @3=2 +### INSERT INTO test.ba +### SET +### @1=4 +### @2=4 +### @3=4 +### UPDATE test.ba +### WHERE +### @1=4 +### @3=4 +### SET +### @1=4 +### @3=40 +### DELETE FROM test.ba +### WHERE +### @1=2 +drop table raw_binlog_rows; +Verbose statements from : update-full-row.binlog +select txt from raw_binlog_rows where txt like '###%'; +txt +### INSERT INTO mysql.ndb_apply_status +### SET +### @1=4 +### @2=25769803786 +### @3='' +### @4=0 +### @5=0 +### INSERT INTO test.ba +### SET +### @1=3 +### @2=3 +### @3=3 +### INSERT INTO test.ba +### SET +### @1=1 +### @2=1 +### @3=1 +### INSERT INTO test.ba +### SET +### @1=2 +### @2=2 +### @3=2 +### INSERT INTO test.ba +### SET +### @1=4 +### @2=4 +### @3=4 +### UPDATE test.ba +### WHERE +### @1=4 +### @2=4 +### @3=4 +### SET +### @1=4 +### @2=4 +### @3=40 +### DELETE FROM test.ba +### WHERE +### @1=2 +drop table raw_binlog_rows; diff --git a/mysql-test/suite/binlog/std_data/update-full-row.binlog b/mysql-test/suite/binlog/std_data/update-full-row.binlog new file mode 100644 index 0000000000000000000000000000000000000000..866a351033e5fd95cd96736f7575cf1278cba11c GIT binary patch literal 614 zcma)4!Ab&A6g|#7^$~=ki_A^XDySLKsH`BYh%nHI+Ka=e6sFdU3%{gg`@W&yh_-#k zw9(FeF$3bJ3uk8Tz2}^JXWq=bhvE43<2t7R^oU0SP}p}X?%ts@^gZXmt-6&X$M1TR zzB3s04P*HtHpSX1Gzw6R0&oXa)?{j}EooaarB1v{kw~J;@q$uLGNbOhP?nvuHd^h6tperor<7dA?V>Gae77?I7%glK^R3 z=eXq@5cQf2Iw4w%>Wyz{tPmMuDH7=|TW>}h?`Y2>o5dKBG-E^-lNgaqh#`h0NovH` zqG2|>KuwY@Qbo5ex=rGTx;*|CNx@FdWRx(>ahx$ZX666KadFdZHtt_&pk%}j(GyFv QwcO1&_8tCO?yf}j7fK*a0{{R3 literal 0 HcmV?d00001 diff --git a/mysql-test/suite/binlog/std_data/update-partial-row.binlog b/mysql-test/suite/binlog/std_data/update-partial-row.binlog new file mode 100644 index 0000000000000000000000000000000000000000..67e3611aa3a5d8dd2bd9b1b0bd6a590b0562cdce GIT binary patch literal 606 zcma))%}T>S6opTdNf`ubX&2UR1XqG4v=#plq$(l`t%$BI4XH(`wI%7IPvX+O&)_?_ za_=j+%R*Yu9hpMu#tUDPnS0K?HNaXkmq}~+JixF+=`QS zGK%53I>#xefVfwr(IIKhyVt%Xu|%?DA!gQVre2NJ&gf24v073|T2hA#ORBiANWqeL zD&%9npy&NqnR(ctMD(koUnk$x=kYf{25x2|Ekt3C;h2jWcm972r&o=}#qE#BBq4l6=OG0Wzei zc=PUK}DQ3598U#ZP6y8C-4G@BprJ-@95MWhJkzH)xBE7 z4g0}l;6|f?R;)hQrgFAUipnGrWukkMRRyI|%I31otF*uyCqW)nj9NsNNjM@&L#ZHw z?DG1i-PQKozYo5&ZhNVgX+KHH4tx>_a&qZ81QqSMxs(=Or^z^?627bF$8j|6C8?iI z5-JE)#4Z;^+`YjIH9_}p_s%yL)_?<6B5!>}>0P&)J&HvpkThgmG-PaQ$Rs9)e6oim zyKk{<7kr|*M8ED932V*;R_HUnz=W^#|7U!4*Xgt$#xRiVbO4$>&|BfRKDf}u|Kc5T G)PDdA3P>dY literal 0 HcmV?d00001 diff --git a/mysql-test/suite/binlog/std_data/write-partial-row.binlog b/mysql-test/suite/binlog/std_data/write-partial-row.binlog new file mode 100644 index 0000000000000000000000000000000000000000..7424ec4e940b5bd3b3d261e5be16f685d883c241 GIT binary patch literal 596 zcmaJ?=e}h+l zf_HEJg&ef?&1xc2@WI>c%)I%?uru#=IC^-#C|E>v1Kxo|l6G}X?=+mD?>T$Au4@O5 z-}fd1Cm0QkV)5WI<^5$+R3ZtKh^|Ri6qHISJ4D##E=}->onVFvZcQSN8{|b4`%*y! z*~!^?tHb$aj&FjmMx@P&Y2$trlkK@A0Lo|5BM3|mRez+p`)M=|sEGgSxnUSgdr|Dh zlZbLc6)@$Th_hF?(IMC|6J^J>tdCN-T=%o71;%7lX{6B|a#M8Zg! z72JUH $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +create table raw_binlog_rows (txt varchar(1000)); +--eval load data local infile '$MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql' into table raw_binlog_rows columns terminated by '\n'; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +--enable_query_log +--echo Verbose statements from : $binlog_file +select txt from raw_binlog_rows where txt like '###%'; +drop table raw_binlog_rows; + +--disable_query_log +--let $binlog_file=write-full-row.binlog +--exec $MYSQL_BINLOG --verbose suite/binlog/std_data/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +create table raw_binlog_rows (txt varchar(1000)); +--eval load data local infile '$MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql' into table raw_binlog_rows columns terminated by '\n'; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +--enable_query_log +--echo Verbose statements from : $binlog_file +select txt from raw_binlog_rows where txt like '###%'; +drop table raw_binlog_rows; + +--disable_query_log +--let $binlog_file=update-partial-row.binlog +--exec $MYSQL_BINLOG --verbose suite/binlog/std_data/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +create table raw_binlog_rows (txt varchar(1000)); +--eval load data local infile '$MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql' into table raw_binlog_rows columns terminated by '\n'; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +--enable_query_log +--echo Verbose statements from : $binlog_file +select txt from raw_binlog_rows where txt like '###%'; +drop table raw_binlog_rows; + +--disable_query_log +--let $binlog_file=update-full-row.binlog +--exec $MYSQL_BINLOG --verbose suite/binlog/std_data/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +create table raw_binlog_rows (txt varchar(1000)); +--eval load data local infile '$MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql' into table raw_binlog_rows columns terminated by '\n'; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +--enable_query_log +--echo Verbose statements from : $binlog_file +select txt from raw_binlog_rows where txt like '###%'; +drop table raw_binlog_rows; diff --git a/sql/log_event.cc b/sql/log_event.cc index d7921ad3c27..ae7c4335f59 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1852,6 +1852,7 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td, { const uchar *value0= value; const uchar *null_bits= value; + uint null_bit_index= 0; char typestr[64]= ""; value+= (m_width + 7) / 8; @@ -1860,7 +1861,8 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td, for (size_t i= 0; i < td->size(); i ++) { - int is_null= (null_bits[i / 8] >> (i % 8)) & 0x01; + int is_null= (null_bits[null_bit_index / 8] + >> (null_bit_index % 8)) & 0x01; if (bitmap_is_set(cols_bitmap, i) == 0) continue; @@ -1897,6 +1899,8 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td, } my_b_printf(file, "\n"); + + null_bit_index++; } return value - value0; } From eded60737d6bd233c50c4f68e76432154f768363 Mon Sep 17 00:00:00 2001 From: Martin Hansson Date: Fri, 9 Oct 2009 11:30:40 +0200 Subject: [PATCH 107/146] Bug#42846: wrong result returned for range scan when using covering index When two range predicates were combined under an OR predicate, the algorithm tried to merge overlapping ranges into one. But the case when a range overlapped several other ranges was not handled. This lead to 1) ranges overlapping, which gave repeated results and 2) a range that overlapped several other ranges was cut off. Fixed by 1) Making sure that a range got an upper bound equal to the next range with a greater minimum. 2) Removing a continue statement --- mysql-test/r/group_min_max.result | 6 +- mysql-test/r/range.result | 179 ++++++++++++++++++++++++++++++ mysql-test/t/range.test | 125 +++++++++++++++++++++ sql/opt_range.cc | 75 ++++++++++++- 4 files changed, 379 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index ac9a53ca238..620f5dc19ec 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -876,10 +876,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by explain select a1,a2,b, max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b111') and (c <= 'g112') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by @@ -924,7 +924,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by explain select a1,a2,b, max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 range NULL idx_t2_1 146 NULL # Using where; Using index for group-by +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index cc5e8d2be96..c98a7696ea6 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -1219,3 +1219,182 @@ explain select * from t2 where a=1000 and b<11; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ref a a 5 const 502 Using where drop table t1, t2; +CREATE TABLE t1( a INT, b INT, KEY( a, b ) ); +CREATE TABLE t2( a INT, b INT, KEY( a, b ) ); +CREATE TABLE t3( a INT, b INT, KEY( a, b ) ); +INSERT INTO t1( a, b ) +VALUES (0, 1), (1, 2), (1, 4), (2, 3), (5, 0), (9, 7); +INSERT INTO t2( a, b ) +VALUES ( 1, 1), ( 2, 1), ( 3, 1), ( 4, 1), ( 5, 1), +( 6, 1), ( 7, 1), ( 8, 1), ( 9, 1), (10, 1), +(11, 1), (12, 1), (13, 1), (14, 1), (15, 1), +(16, 1), (17, 1), (18, 1), (19, 1), (20, 1); +INSERT INTO t2 SELECT a, 2 FROM t2 WHERE b = 1; +INSERT INTO t2 SELECT a, 3 FROM t2 WHERE b = 1; +INSERT INTO t2 SELECT -1, -1 FROM t2; +INSERT INTO t2 SELECT -1, -1 FROM t2; +INSERT INTO t2 SELECT -1, -1 FROM t2; +INSERT INTO t3 +VALUES (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), +(6, 0), (7, 0), (8, 0), (9, 0), (10, 0); +INSERT INTO t3 SELECT * FROM t3 WHERE a = 10; +INSERT INTO t3 SELECT * FROM t3 WHERE a = 10; +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 < a AND b = 3 OR +3 <= a; +a b +5 0 +9 7 +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 < a AND b = 3 OR +3 <= a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 3 Using where; Using index +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 <= a AND b = 3 OR +3 <= a; +a b +5 0 +9 7 +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 <= a AND b = 3 OR +3 <= a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 4 Using where; Using index +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +5 <= a AND b = 3 OR +3 <= a; +a b +5 0 +9 7 +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +5 <= a AND b = 3 OR +3 <= a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 3 Using where; Using index +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +3 <= a; +a b +5 0 +9 7 +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +3 <= a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 3 Using where; Using index +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 1 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; +a b +1 1 +2 1 +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 +9 1 +10 1 +11 1 +12 1 +13 1 +14 1 +15 1 +15 3 +16 1 +16 3 +17 1 +17 3 +18 1 +18 3 +19 1 +19 3 +20 1 +EXPLAIN +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 1 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range a a 10 NULL 50 Using where; Using index +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 2 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; +a b +1 1 +2 1 +3 1 +4 1 +5 1 +5 2 +6 1 +6 2 +7 1 +7 2 +8 1 +8 2 +9 1 +9 2 +10 1 +11 1 +12 1 +13 1 +14 1 +15 1 +15 3 +16 1 +16 3 +17 1 +17 3 +18 1 +18 3 +19 1 +19 3 +20 1 +EXPLAIN +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 2 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range a a 10 NULL 50 Using where; Using index +SELECT * FROM t3 WHERE +5 <= a AND a < 10 AND b = 3 OR +a < 5 OR +a < 10; +a b +1 0 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +EXPLAIN +SELECT * FROM t3 WHERE +5 <= a AND a < 10 AND b = 3 OR +a < 5 OR +a < 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 range a a 5 NULL 8 Using where; Using index +DROP TABLE t1, t2, t3; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index e1411e7fd46..dc119b6a77e 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1046,3 +1046,128 @@ explain select * from t2 where a=1000 and b<11; drop table t1, t2; +# +# Bug#42846: wrong result returned for range scan when using covering index +# +CREATE TABLE t1( a INT, b INT, KEY( a, b ) ); + +CREATE TABLE t2( a INT, b INT, KEY( a, b ) ); + +CREATE TABLE t3( a INT, b INT, KEY( a, b ) ); + +INSERT INTO t1( a, b ) +VALUES (0, 1), (1, 2), (1, 4), (2, 3), (5, 0), (9, 7); + +INSERT INTO t2( a, b ) +VALUES ( 1, 1), ( 2, 1), ( 3, 1), ( 4, 1), ( 5, 1), + ( 6, 1), ( 7, 1), ( 8, 1), ( 9, 1), (10, 1), + (11, 1), (12, 1), (13, 1), (14, 1), (15, 1), + (16, 1), (17, 1), (18, 1), (19, 1), (20, 1); + +INSERT INTO t2 SELECT a, 2 FROM t2 WHERE b = 1; +INSERT INTO t2 SELECT a, 3 FROM t2 WHERE b = 1; + +# To make range scan compelling to the optimizer +INSERT INTO t2 SELECT -1, -1 FROM t2; +INSERT INTO t2 SELECT -1, -1 FROM t2; +INSERT INTO t2 SELECT -1, -1 FROM t2; + +INSERT INTO t3 +VALUES (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), + (6, 0), (7, 0), (8, 0), (9, 0), (10, 0); + +# To make range scan compelling to the optimizer +INSERT INTO t3 SELECT * FROM t3 WHERE a = 10; +INSERT INTO t3 SELECT * FROM t3 WHERE a = 10; + + +# +# Problem#1 Test queries. Will give missing results unless Problem#1 is fixed. +# With one exception, they are independent of Problem#2. +# +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 < a AND b = 3 OR +3 <= a; + +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 < a AND b = 3 OR +3 <= a; + +# Query below: Tests both Problem#1 and Problem#2 (EXPLAIN differs as well) +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 <= a AND b = 3 OR +3 <= a; + +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 <= a AND b = 3 OR +3 <= a; + +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +5 <= a AND b = 3 OR +3 <= a; + +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +5 <= a AND b = 3 OR +3 <= a; + +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +3 <= a; + +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +3 <= a; + +# +# Problem#2 Test queries. +# These queries will give missing results if Problem#1 is fixed. +# But Problem#1 also hides this bug. +# +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 1 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; + +EXPLAIN +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 1 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; + +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 2 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; + +EXPLAIN +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 2 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; + +SELECT * FROM t3 WHERE +5 <= a AND a < 10 AND b = 3 OR +a < 5 OR +a < 10; + +EXPLAIN +SELECT * FROM t3 WHERE +5 <= a AND a < 10 AND b = 3 OR +a < 5 OR +a < 10; + +DROP TABLE t1, t2, t3; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 1b1d948b3b9..119f90bc97a 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -6512,6 +6512,63 @@ get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1) } +/** + Combine two range expression under a common OR. On a logical level, the + transformation is key_or( expr1, expr2 ) => expr1 OR expr2. + + Both expressions are assumed to be in the SEL_ARG format. In a logic sense, + theformat is reminiscent of DNF, since an expression such as the following + + ( 1 < kp1 < 10 AND p1 ) OR ( 10 <= kp2 < 20 AND p2 ) + + where there is a key consisting of keyparts ( kp1, kp2, ..., kpn ) and p1 + and p2 are valid SEL_ARG expressions over keyparts kp2 ... kpn, is a valid + SEL_ARG condition. The disjuncts appear ordered by the minimum endpoint of + the first range and ranges must not overlap. It follows that they are also + ordered by maximum endpoints. Thus + + ( 1 < kp1 <= 2 AND ( kp2 = 2 OR kp2 = 3 ) ) OR kp1 = 3 + + Is a a valid SER_ARG expression for a key of at least 2 keyparts. + + For simplicity, we will assume that expr2 is a single range predicate, + i.e. on the form ( a < x < b AND ... ). It is easy to generalize to a + disjunction of several predicates by subsequently call key_or for each + disjunct. + + The algorithm iterates over each disjunct of expr1, and for each disjunct + where the first keypart's range overlaps with the first keypart's range in + expr2: + + If the predicates are equal for the rest of the keyparts, or if there are + no more, the range in expr2 has its endpoints copied in, and the SEL_ARG + node in expr2 is deallocated. If more ranges became connected in expr1, the + surplus is also dealocated. If they differ, two ranges are created. + + - The range leading up to the overlap. Empty if endpoints are equal. + + - The overlapping sub-range. May be the entire range if they are equal. + + Finally, there may be one more range if expr2's first keypart's range has a + greater maximum endpoint than the last range in expr1. + + For the overlapping sub-range, we recursively call key_or. Thus in order to + compute key_or of + + (1) ( 1 < kp1 < 10 AND 1 < kp2 < 10 ) + + (2) ( 2 < kp1 < 20 AND 4 < kp2 < 20 ) + + We create the ranges 1 < kp <= 2, 2 < kp1 < 10, 10 <= kp1 < 20. For the + first one, we simply hook on the condition for the second keypart from (1) + : 1 < kp2 < 10. For the second range 2 < kp1 < 10, key_or( 1 < kp2 < 10, 4 + < kp2 < 20 ) is called, yielding 1 < kp2 < 20. For the last range, we reuse + the range 4 < kp2 < 20 from (2) for the second keypart. The result is thus + + ( 1 < kp1 <= 2 AND 1 < kp2 < 10 ) OR + ( 2 < kp1 < 10 AND 1 < kp2 < 20 ) OR + ( 10 <= kp1 < 20 AND 4 < kp2 < 20 ) +*/ static SEL_ARG * key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) { @@ -6663,7 +6720,21 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) key1=key1->tree_delete(save); } last->copy_min(tmp); - if (last->copy_min(key2) || last->copy_max(key2)) + bool full_range= last->copy_min(key2); + if (!full_range) + { + if (last->next && key2->cmp_max_to_min(last->next) >= 0) + { + last->max_value= last->next->min_value; + if (last->next->min_flag & NEAR_MIN) + last->max_flag&= ~NEAR_MAX; + else + last->max_flag|= NEAR_MAX; + } + else + full_range= last->copy_max(key2); + } + if (full_range) { // Full range key1->free_tree(); for (; key2 ; key2=key2->next) @@ -6673,8 +6744,6 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) return 0; } } - key2=key2->next; - continue; } if (cmp >= 0 && tmp->cmp_min_to_min(key2) < 0) From 913f8903d0ea60d91d41f2cd8cc9c6fb365c22e7 Mon Sep 17 00:00:00 2001 From: Satya B Date: Fri, 9 Oct 2009 17:49:13 +0530 Subject: [PATCH 108/146] Applying InnoDB Plugin 1.0.5 snapshot , part 8 Note : r5865 is skipped r5869 plug.in related changes are aslo skipped Detailed revision comments: r5865 | vasil | 2009-09-12 02:26:03 -0500 (Sat, 12 Sep 2009) | 10 lines branches/zip: Simplify the compile time checks by splittig them into 5 independent checks: * Whether GCC atomics are available * Whether pthread_t can be used by GCC atomics * Whether Solaris libc atomics are available * Whether pthread_t can be used by Solaris libs atomics * Checking the size of pthread_t r5866 | vasil | 2009-09-12 02:30:08 -0500 (Sat, 12 Sep 2009) | 5 lines branches/zip: Add the check for GCC atomics to ut0auxconf* (copied from plug.in) because we no longer rely on MySQL's HAVE_GCC_ATOMIC_BUILTINS. r5867 | vasil | 2009-09-12 02:43:45 -0500 (Sat, 12 Sep 2009) | 4 lines branches/zip: Update comment to reflect reality. r5868 | vasil | 2009-09-12 03:01:17 -0500 (Sat, 12 Sep 2009) | 6 lines branches/zip: Move the check whether to include ut0auxconf.h before everything because we are now even checking for GCC atomics, we relied on MySQL to define this macro before. r5869 | vasil | 2009-09-12 03:33:11 -0500 (Sat, 12 Sep 2009) | 15 lines branches/zip: Include ut0auxconf.h only if none of the macros it would define is defined. The check when to include this header was outdated from the time when there was only one macro involved. Move the atomics checks that are in univ.i outside of #if windows ... #else ... #endif This simplifies the code and removes some duplicates like defining HAVE_ATOMIC_BUILTINS if HAVE_WINDOWS_ATOMICS is defined in both branches. Do not define the same macro HAVE_ATOMIC_PTHREAD_T for different events. Instead define HAVE_IB_ATOMIC_PTHREAD_T_GCC and HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS. r5870 | vasil | 2009-09-12 04:13:44 -0500 (Sat, 12 Sep 2009) | 7 lines branches/zip: Define HAVE_ATOMIC_BUILTINS and INNODB_RW_LOCKS_USE_ATOMICS in os0sync.h instead of in univ.i. The code expects os_*() macros to be present if HAVE_ATOMIC_BUILTINS and INNODB_RW_LOCKS_USE_ATOMICS are defined. So define them next to defining the os_*() macros. r5871 | vasil | 2009-09-12 04:25:44 -0500 (Sat, 12 Sep 2009) | 6 lines branches/zip: Rename HAVE_SOLARIS_ATOMICS to HAVE_IB_SOLARIS_ATOMICS and IB_HAVE_PAUSE_INSTRUCTION to HAVE_IB_PAUSE_INSTRUCTION so they all follow the same HAVE_IB_* convention. r5872 | vasil | 2009-09-12 04:35:17 -0500 (Sat, 12 Sep 2009) | 5 lines branches/zip: Explicitly include os0sync.h to the places where HAVE_ATOMIC_BUILTINS and INNODB_RW_LOCKS_USE_ATOMICS are used to avoid potential problems. --- storage/innodb_plugin/include/os0sync.h | 64 +++++++-- storage/innodb_plugin/include/univ.i | 43 ++---- storage/innodb_plugin/include/ut0auxconf.h | 12 +- storage/innodb_plugin/include/ut0ut.h | 5 +- storage/innodb_plugin/srv/srv0srv.c | 1 + storage/innodb_plugin/srv/srv0start.c | 3 +- storage/innodb_plugin/sync/sync0rw.c | 1 + storage/innodb_plugin/sync/sync0sync.c | 1 + .../ut/ut0auxconf_have_gcc_atomics.c | 122 ++++++++++++++++++ 9 files changed, 204 insertions(+), 48 deletions(-) create mode 100644 storage/innodb_plugin/ut/ut0auxconf_have_gcc_atomics.c diff --git a/storage/innodb_plugin/include/os0sync.h b/storage/innodb_plugin/include/os0sync.h index 6e52fa1350e..ba7c8776f7b 100644 --- a/storage/innodb_plugin/include/os0sync.h +++ b/storage/innodb_plugin/include/os0sync.h @@ -286,43 +286,68 @@ os_fast_mutex_free( Atomic compare-and-swap and increment for InnoDB. */ #ifdef HAVE_IB_GCC_ATOMIC_BUILTINS + +#define HAVE_ATOMIC_BUILTINS + /**********************************************************//** Returns true if swapped, ptr is pointer to target, old_val is value to compare to, new_val is the value to swap in. */ + # define os_compare_and_swap(ptr, old_val, new_val) \ __sync_bool_compare_and_swap(ptr, old_val, new_val) + # define os_compare_and_swap_ulint(ptr, old_val, new_val) \ os_compare_and_swap(ptr, old_val, new_val) + # define os_compare_and_swap_lint(ptr, old_val, new_val) \ os_compare_and_swap(ptr, old_val, new_val) -# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ + +# ifdef HAVE_IB_ATOMIC_PTHREAD_T_GCC +# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ os_compare_and_swap(ptr, old_val, new_val) +# define INNODB_RW_LOCKS_USE_ATOMICS +# endif /* HAVE_IB_ATOMIC_PTHREAD_T_GCC */ + /**********************************************************//** Returns the resulting value, ptr is pointer to target, amount is the amount of increment. */ + # define os_atomic_increment(ptr, amount) \ __sync_add_and_fetch(ptr, amount) + # define os_atomic_increment_lint(ptr, amount) \ os_atomic_increment(ptr, amount) + # define os_atomic_increment_ulint(ptr, amount) \ os_atomic_increment(ptr, amount) + /**********************************************************//** Returns the old value of *ptr, atomically sets *ptr to new_val */ + # define os_atomic_test_and_set_byte(ptr, new_val) \ __sync_lock_test_and_set(ptr, new_val) + +#elif defined(HAVE_IB_SOLARIS_ATOMICS) + +#define HAVE_ATOMIC_BUILTINS + /* If not compiling with GCC or GCC doesn't support the atomic intrinsics and running on Solaris >= 10 use Solaris atomics */ -#elif defined(HAVE_SOLARIS_ATOMICS) + #include + /**********************************************************//** Returns true if swapped, ptr is pointer to target, old_val is value to compare to, new_val is the value to swap in. */ + # define os_compare_and_swap_ulint(ptr, old_val, new_val) \ (atomic_cas_ulong(ptr, old_val, new_val) == old_val) + # define os_compare_and_swap_lint(ptr, old_val, new_val) \ ((lint)atomic_cas_ulong((ulong_t*) ptr, old_val, new_val) == old_val) -# ifdef INNODB_RW_LOCKS_USE_ATOMICS -# if SIZEOF_PTHREAD_T == 4 + +# ifdef HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS +# if SIZEOF_PTHREAD_T == 4 # define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ ((pthread_t)atomic_cas_32(ptr, old_val, new_val) == old_val) # elif SIZEOF_PTHREAD_T == 8 @@ -331,21 +356,30 @@ compare to, new_val is the value to swap in. */ # else # error "SIZEOF_PTHREAD_T != 4 or 8" # endif /* SIZEOF_PTHREAD_T CHECK */ -# endif /* INNODB_RW_LOCKS_USE_ATOMICS */ +# define INNODB_RW_LOCKS_USE_ATOMICS +# endif /* HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS */ /**********************************************************//** Returns the resulting value, ptr is pointer to target, amount is the amount of increment. */ + # define os_atomic_increment_lint(ptr, amount) \ atomic_add_long_nv((ulong_t*) ptr, amount) + # define os_atomic_increment_ulint(ptr, amount) \ atomic_add_long_nv(ptr, amount) + /**********************************************************//** Returns the old value of *ptr, atomically sets *ptr to new_val */ + # define os_atomic_test_and_set_byte(ptr, new_val) \ atomic_swap_uchar(ptr, new_val) -/* On Windows, use Windows atomics / interlocked */ + #elif defined(HAVE_WINDOWS_ATOMICS) + +#define HAVE_ATOMIC_BUILTINS + +/* On Windows, use Windows atomics / interlocked */ # ifdef _WIN64 # define win_cmp_and_xchg InterlockedCompareExchange64 # define win_xchg_and_add InterlockedExchangeAdd64 @@ -353,31 +387,41 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */ # define win_cmp_and_xchg InterlockedCompareExchange # define win_xchg_and_add InterlockedExchangeAdd # endif + /**********************************************************//** Returns true if swapped, ptr is pointer to target, old_val is value to compare to, new_val is the value to swap in. */ + # define os_compare_and_swap_ulint(ptr, old_val, new_val) \ (win_cmp_and_xchg(ptr, new_val, old_val) == old_val) + # define os_compare_and_swap_lint(ptr, old_val, new_val) \ (win_cmp_and_xchg(ptr, new_val, old_val) == old_val) -# ifdef INNODB_RW_LOCKS_USE_ATOMICS -# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ + +# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ (InterlockedCompareExchange(ptr, new_val, old_val) == old_val) -# endif /* INNODB_RW_LOCKS_USE_ATOMICS */ +/* windows thread objects can always be passed to windows atomic functions */ +# define HAVE_IB_ATOMIC_PTHREAD_T_WINDOWS + /**********************************************************//** Returns the resulting value, ptr is pointer to target, amount is the amount of increment. */ + # define os_atomic_increment_lint(ptr, amount) \ (win_xchg_and_add(ptr, amount) + amount) + # define os_atomic_increment_ulint(ptr, amount) \ ((ulint) (win_xchg_and_add(ptr, amount) + amount)) + /**********************************************************//** Returns the old value of *ptr, atomically sets *ptr to new_val. InterlockedExchange() operates on LONG, and the LONG will be clobbered */ + # define os_atomic_test_and_set_byte(ptr, new_val) \ ((byte) InterlockedExchange(ptr, new_val)) -#endif /* HAVE_IB_GCC_ATOMIC_BUILTINS */ + +#endif #ifndef UNIV_NONINL #include "os0sync.ic" diff --git a/storage/innodb_plugin/include/univ.i b/storage/innodb_plugin/include/univ.i index 815c9ffcee0..c087e449cae 100644 --- a/storage/innodb_plugin/include/univ.i +++ b/storage/innodb_plugin/include/univ.i @@ -78,17 +78,25 @@ the virtual method table (vtable) in GCC 3. */ # define ha_innobase ha_innodb #endif /* MYSQL_DYNAMIC_PLUGIN */ +/* if any of the following macros is defined at this point this means +that the code from the "right" plug.in was executed and we do not +need to include ut0auxconf.h which would either define the same macros +or will be empty */ +#if !defined(HAVE_IB_GCC_ATOMIC_BUILTINS) \ + && !defined(HAVE_IB_ATOMIC_PTHREAD_T_GCC) \ + && !defined(HAVE_IB_SOLARIS_ATOMICS) \ + && !defined(HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS) \ + && !defined(SIZEOF_PTHREAD_T) \ + && !defined(HAVE_IB_PAUSE_INSTRUCTION) +# include "ut0auxconf.h" +#endif + #if (defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)) && !defined(MYSQL_SERVER) && !defined(__WIN__) # undef __WIN__ # define __WIN__ # include -# if defined(HAVE_WINDOWS_ATOMICS) -/* If atomics are defined we use them in InnoDB mutex implementation */ -# define HAVE_ATOMIC_BUILTINS -# endif /* HAVE_WINDOWS_ATOMICS */ - # ifdef _NT_ # define __NT__ # endif @@ -122,31 +130,6 @@ if we are compiling on Windows. */ # include # endif -# if defined(HAVE_IB_GCC_ATOMIC_BUILTINS) || defined(HAVE_SOLARIS_ATOMICS) \ - || defined(HAVE_WINDOWS_ATOMICS) -/* If atomics are defined we use them in InnoDB mutex implementation */ -# define HAVE_ATOMIC_BUILTINS -# endif /* (HAVE_IB_GCC_ATOMIC_BUILTINS) || (HAVE_SOLARIS_ATOMICS) - || (HAVE_WINDOWS_ATOMICS) */ - -/* For InnoDB rw_locks to work with atomics we need the thread_id -to be no more than machine word wide. The following enables using -atomics for InnoDB rw_locks where these conditions are met. */ -#ifdef HAVE_ATOMIC_BUILTINS -/* if HAVE_ATOMIC_PTHREAD_T is defined at this point that means that -the code from plug.in has defined it and we do not need to include -ut0auxconf.h which would either define HAVE_ATOMIC_PTHREAD_T or will -be empty */ -# ifndef HAVE_ATOMIC_PTHREAD_T -# include "ut0auxconf.h" -# endif /* HAVE_ATOMIC_PTHREAD_T */ -/* now HAVE_ATOMIC_PTHREAD_T is eventually defined either by plug.in or -from Makefile.in->ut0auxconf.h */ -# ifdef HAVE_ATOMIC_PTHREAD_T -# define INNODB_RW_LOCKS_USE_ATOMICS -# endif /* HAVE_ATOMIC_PTHREAD_T */ -#endif /* HAVE_ATOMIC_BUILTINS */ - /* We only try to do explicit inlining of functions with gcc and Sun Studio */ diff --git a/storage/innodb_plugin/include/ut0auxconf.h b/storage/innodb_plugin/include/ut0auxconf.h index 88fb26f1863..16bcc308392 100644 --- a/storage/innodb_plugin/include/ut0auxconf.h +++ b/storage/innodb_plugin/include/ut0auxconf.h @@ -1,14 +1,14 @@ /* Do not remove this file even though it is empty. This file is included in univ.i and will cause compilation failure if not present. -A custom check has been added in the generated +A custom checks have been added in the generated storage/innobase/Makefile.in that is shipped with the InnoDB Plugin -source archive. This check tries to compile a test program and if -successful then adds "#define HAVE_ATOMIC_PTHREAD_T" to this file. -This is a hack that has been developed in order to check for pthread_t -atomicity without the need to regenerate the ./configure script that is +source archive. These checks eventually define some macros and put +them in this file. +This is a hack that has been developed in order to deploy new compile +time checks without the need to regenerate the ./configure script that is distributed in the MySQL 5.1 official source archives. If by any chance Makefile.in and ./configure are regenerated and thus -the hack from Makefile.in wiped away then the "real" check from plug.in +the hack from Makefile.in wiped away then the "real" checks from plug.in will take over. */ diff --git a/storage/innodb_plugin/include/ut0ut.h b/storage/innodb_plugin/include/ut0ut.h index 6655d522c18..9604833b278 100644 --- a/storage/innodb_plugin/include/ut0ut.h +++ b/storage/innodb_plugin/include/ut0ut.h @@ -34,6 +34,9 @@ Created 1/20/1994 Heikki Tuuri #define ut0ut_h #include "univ.i" + +#include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ + #include #ifndef MYSQL_SERVER #include @@ -47,7 +50,7 @@ Created 1/20/1994 Heikki Tuuri /** Time stamp */ typedef time_t ib_time_t; -#if defined(IB_HAVE_PAUSE_INSTRUCTION) +#if defined(HAVE_IB_PAUSE_INSTRUCTION) # ifdef WIN32 /* In the Win32 API, the x86 PAUSE instruction is executed by calling the YieldProcessor macro defined in WinNT.h. It is a CPU architecture- diff --git a/storage/innodb_plugin/srv/srv0srv.c b/storage/innodb_plugin/srv/srv0srv.c index 2f54e9b3734..d638b23692e 100644 --- a/storage/innodb_plugin/srv/srv0srv.c +++ b/storage/innodb_plugin/srv/srv0srv.c @@ -102,6 +102,7 @@ Created 10/8/1995 Heikki Tuuri #include "row0mysql.h" #include "ha_prototypes.h" #include "trx0i_s.h" +#include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ /* This is set to TRUE if the MySQL user has set it in MySQL; currently affects only FOREIGN KEY definition parsing */ diff --git a/storage/innodb_plugin/srv/srv0start.c b/storage/innodb_plugin/srv/srv0start.c index e4278f6b5a8..068cb9dbe64 100644 --- a/storage/innodb_plugin/srv/srv0start.c +++ b/storage/innodb_plugin/srv/srv0start.c @@ -103,6 +103,7 @@ Created 2/16/1996 Heikki Tuuri # include "row0row.h" # include "row0mysql.h" # include "btr0pcur.h" +# include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */ /** Log sequence number immediately after startup */ UNIV_INTERN ib_uint64_t srv_start_lsn; @@ -1114,7 +1115,7 @@ innobase_start_or_create_for_mysql(void) fprintf(stderr, "InnoDB: Mutexes use GCC atomic builtins, rw_locks do not.\n"); # endif /* INNODB_RW_LOCKS_USE_ATOMICS */ -#elif defined(HAVE_SOLARIS_ATOMICS) +#elif defined(HAVE_IB_SOLARIS_ATOMICS) # ifdef INNODB_RW_LOCKS_USE_ATOMICS fprintf(stderr, "InnoDB: Mutexes and rw_locks use Solaris atomic functions.\n"); diff --git a/storage/innodb_plugin/sync/sync0rw.c b/storage/innodb_plugin/sync/sync0rw.c index 0ed114e330c..d231b6acdf7 100644 --- a/storage/innodb_plugin/sync/sync0rw.c +++ b/storage/innodb_plugin/sync/sync0rw.c @@ -38,6 +38,7 @@ Created 9/11/1995 Heikki Tuuri #include "os0thread.h" #include "mem0mem.h" #include "srv0srv.h" +#include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */ /* IMPLEMENTATION OF THE RW_LOCK diff --git a/storage/innodb_plugin/sync/sync0sync.c b/storage/innodb_plugin/sync/sync0sync.c index 84ed08e14e7..beef3a1f2db 100644 --- a/storage/innodb_plugin/sync/sync0sync.c +++ b/storage/innodb_plugin/sync/sync0sync.c @@ -39,6 +39,7 @@ Created 9/5/1995 Heikki Tuuri #include "buf0buf.h" #include "srv0srv.h" #include "buf0types.h" +#include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ /* REASONS FOR IMPLEMENTING THE SPIN LOCK MUTEX diff --git a/storage/innodb_plugin/ut/ut0auxconf_have_gcc_atomics.c b/storage/innodb_plugin/ut/ut0auxconf_have_gcc_atomics.c new file mode 100644 index 00000000000..cc4acec9590 --- /dev/null +++ b/storage/innodb_plugin/ut/ut0auxconf_have_gcc_atomics.c @@ -0,0 +1,122 @@ +/***************************************************************************** + +Copyright (c) 2009, Innobase Oy. 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 +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +/***************************************************************************** +If this program compiles and returns 0, then GCC atomic funcions are available. + +Created September 12, 2009 Vasil Dimov +*****************************************************************************/ + +int +main(int argc, char** argv) +{ + long x; + long y; + long res; + char c; + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x, y); + if (!res || x != y) { + return(1); + } + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x + 1, y); + if (res || x != 10) { + return(1); + } + + x = 10; + y = 123; + res = __sync_add_and_fetch(&x, y); + if (res != 123 + 10 || x != 123 + 10) { + return(1); + } + + c = 10; + res = __sync_lock_test_and_set(&c, 123); + if (res != 10 || c != 123) { + return(1); + } + + return(0); +} +/***************************************************************************** + +Copyright (c) 2009, Innobase Oy. 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 +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +/***************************************************************************** +If this program compiles and returns 0, then GCC atomic funcions are available. + +Created September 12, 2009 Vasil Dimov +*****************************************************************************/ + +int +main(int argc, char** argv) +{ + long x; + long y; + long res; + char c; + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x, y); + if (!res || x != y) { + return(1); + } + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x + 1, y); + if (res || x != 10) { + return(1); + } + + x = 10; + y = 123; + res = __sync_add_and_fetch(&x, y); + if (res != 123 + 10 || x != 123 + 10) { + return(1); + } + + c = 10; + res = __sync_lock_test_and_set(&c, 123); + if (res != 10 || c != 123) { + return(1); + } + + return(0); +} From 15fd02cb0209d5e13b852d4e3b1a5e3d1fcd36e8 Mon Sep 17 00:00:00 2001 From: Satya B Date: Fri, 9 Oct 2009 18:22:18 +0530 Subject: [PATCH 109/146] Applying InnoDB Plugin 1.0.5 snapshot , part 9 r5888 - plug.in related changes skipped r5889 - skipped(plug.in related changes) r5916 - innodb_bug4600.test and innodb_bug44369.test already exists in main suite Detailed revision comments: r5875 | vasil | 2009-09-12 07:11:25 -0500 (Sat, 12 Sep 2009) | 4 lines branches/zip: Remove unnecessary macro. r5888 | vasil | 2009-09-14 03:38:45 -0500 (Mon, 14 Sep 2009) | 40 lines branches/zip: Back-merge c5880 and c5881 from branches/embedded-1.0: ------------------------------------------------------------------------ r5880 | vasil | 2009-09-12 17:28:44 +0300 (Sat, 12 Sep 2009) | 18 lines Changed paths: M /branches/embedded-1.0/configure.in M /branches/embedded-1.0/include/os0sync.h M /branches/embedded-1.0/srv/srv0start.c branches/embedded-1.0: Clean up and simplify the code that surrounds the atomic ops: * Simplify the code that prints what atomics are used: Instead of repeating the same conditions on which each atomics are used use just one printf that prints a variable defined by the code which chooses what atomics to use. * In os0sync.h pick up each atomic variant only if it has been selected by autoconf (based on IB_ATOMIC_MODE_* macros). Define the startup message to be printed. * In configure.in: check what user has chosen and if he has chosen something that is not available, emit an error. If nothing has been chosen explicitly by the user, auto select an option according to the described logic in configure.in. ------------------------------------------------------------------------ r5881 | vasil | 2009-09-12 20:08:27 +0300 (Sat, 12 Sep 2009) | 4 lines Changed paths: M /branches/embedded-1.0/configure.in branches/embedded-1.0: Fix syntax error in test program. r5910 | marko | 2009-09-16 03:07:21 -0500 (Wed, 16 Sep 2009) | 9 lines branches/zip: Introduce UNIV_LOG_LSN_DEBUG and MLOG_LSN for redo log diagnostics. This was written in order to better track down Issue #313 in InnoDB Hot Backup. MLOG_LSN: A new redo log entry type, for recording the current log sequence number (LSN). This will be checked in an assertion in recv_parse_log_rec(). rb://161, discussed with Sunny and Vasil. r5916 | marko | 2009-09-16 04:54:43 -0500 (Wed, 16 Sep 2009) | 128 lines branches/zip: Merge revisions 5622:5912 from branches/5.1, except r5700 (changes to CMakeLists.txt) ------------------------------------------------------------------------ r5622 | vasil | 2009-08-03 15:27:00 +0300 (Mon, 03 Aug 2009) | 20 lines Changed paths: M /branches/5.1/Makefile.am branches/5.1: Merge a change from MySQL: ------------------------------------------------------------ revno: 2988 committer: Satya B branch nick: mysql-5.1-bugteam timestamp: Wed 2009-07-01 11:06:05 +0530 message: Fix build failure after applying Innodb snapshot 5.1-ss5282 After applying Innodb snapshot 5.1-ss5282, build was broken because of missing header file. Adding the header file to Makefile.am after informing the innodb developers. modified: storage/innobase/Makefile.am ------------------------------------------------------------------------ r5740 | jyang | 2009-09-03 06:33:47 +0300 (Thu, 03 Sep 2009) | 5 lines Changed paths: M /branches/5.1/handler/ha_innodb.cc M /branches/5.1/include/db0err.h A /branches/5.1/mysql-test/innodb_bug46000.result A /branches/5.1/mysql-test/innodb_bug46000.test branches/5.1: Disallow creating index with the name of "GEN_CLUST_INDEX" which is reserved for the default system primary index. (Bug #46000) rb://149 approved by Sunny Bains. ------------------------------------------------------------------------ r5741 | jyang | 2009-09-03 07:16:01 +0300 (Thu, 03 Sep 2009) | 5 lines Changed paths: M /branches/5.1/dict/dict0dict.c M /branches/5.1/handler/ha_innodb.cc A /branches/5.1/mysql-test/innodb_bug44369.result A /branches/5.1/mysql-test/innodb_bug44369.test M /branches/5.1/row/row0mysql.c branches/5.1: Block creating table with column name conflicting with Innodb reserved key words. (Bug #44369) rb://151 approved by Sunny Bains. ------------------------------------------------------------------------ r5757 | jyang | 2009-09-04 04:26:13 +0300 (Fri, 04 Sep 2009) | 3 lines Changed paths: M /branches/5.1/handler/ha_innodb.cc M /branches/5.1/include/db0err.h D /branches/5.1/mysql-test/innodb_bug46000.result D /branches/5.1/mysql-test/innodb_bug46000.test branches/5.1: Revert change in 5740. Making the fix in a subsequent check in. ------------------------------------------------------------------------ r5760 | jyang | 2009-09-04 07:07:34 +0300 (Fri, 04 Sep 2009) | 3 lines Changed paths: M /branches/5.1/dict/dict0dict.c M /branches/5.1/handler/ha_innodb.cc D /branches/5.1/mysql-test/innodb_bug44369.result D /branches/5.1/mysql-test/innodb_bug44369.test M /branches/5.1/row/row0mysql.c branches/5.1: This is to revert change 5741. A return status for create_table_def() needs to be fixed. ------------------------------------------------------------------------ r5797 | calvin | 2009-09-09 18:26:29 +0300 (Wed, 09 Sep 2009) | 3 lines Changed paths: M /branches/5.1/handler/ha_innodb.cc branches/5.1: merge change from 5.1.38 HA_ERR_TOO_MANY_CONCURRENT_TRXS is added in 5.1.38. ------------------------------------------------------------------------ r5799 | calvin | 2009-09-09 20:47:31 +0300 (Wed, 09 Sep 2009) | 10 lines Changed paths: M /branches/5.1/handler/ha_innodb.cc branches/5.1: fix bug#46256 Allow tables to be dropped even if the collation is not found, but issue a warning. Could not find an easy way to add mysql-test since it requires changes to charsets and restarting the server. Tests were executed manually. Approved by: Heikki (on IM) ------------------------------------------------------------------------ r5805 | vasil | 2009-09-10 08:41:48 +0300 (Thu, 10 Sep 2009) | 7 lines Changed paths: M /branches/5.1/handler/ha_innodb.cc branches/5.1: Fix a compilation warning caused by c5799: handler/ha_innodb.cc: In function 'void innobase_get_cset_width(ulint, ulint*, ulint*)': handler/ha_innodb.cc:830: warning: format '%d' expects type 'int', but argument 2 has type 'ulint' ------------------------------------------------------------------------ r5834 | jyang | 2009-09-11 00:43:05 +0300 (Fri, 11 Sep 2009) | 5 lines Changed paths: M /branches/5.1/dict/dict0dict.c M /branches/5.1/handler/ha_innodb.cc A /branches/5.1/mysql-test/innodb_bug44369.result A /branches/5.1/mysql-test/innodb_bug44369.test M /branches/5.1/row/row0mysql.c branches/5.1: Block creating table with column name conflicting with Innodb reserved key words. (Bug #44369) rb://151 approved by Sunny Bains. ------------------------------------------------------------------------ r5895 | jyang | 2009-09-15 03:39:21 +0300 (Tue, 15 Sep 2009) | 5 lines Changed paths: M /branches/5.1/handler/ha_innodb.cc A /branches/5.1/mysql-test/innodb_bug46000.result A /branches/5.1/mysql-test/innodb_bug46000.test branches/5.1: Disallow creating index with the name of "GEN_CLUST_INDEX" which is reserved for the default system primary index. (Bug #46000) rb://149 approved by Marko Makela. ------------------------------------------------------------------------ --- storage/innodb_plugin/dict/dict0dict.c | 2 +- storage/innodb_plugin/handler/ha_innodb.cc | 134 +++++++++++++++++++-- storage/innodb_plugin/include/log0log.ic | 35 +++++- storage/innodb_plugin/include/mtr0mtr.h | 3 + storage/innodb_plugin/include/os0sync.h | 3 +- storage/innodb_plugin/include/univ.i | 3 + storage/innodb_plugin/log/log0recv.c | 32 ++++- storage/innodb_plugin/row/row0mysql.c | 10 -- storage/innodb_plugin/srv/srv0start.c | 4 + 9 files changed, 192 insertions(+), 34 deletions(-) diff --git a/storage/innodb_plugin/dict/dict0dict.c b/storage/innodb_plugin/dict/dict0dict.c index a8ee593e35c..aedaf7cec1d 100644 --- a/storage/innodb_plugin/dict/dict0dict.c +++ b/storage/innodb_plugin/dict/dict0dict.c @@ -1170,7 +1170,7 @@ dict_col_name_is_reserved( ulint i; for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) { - if (strcmp(name, reserved_names[i]) == 0) { + if (innobase_strcasecmp(name, reserved_names[i]) == 0) { return(TRUE); } diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 1d72d09727e..9db4d202d93 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -217,15 +217,34 @@ static void free_share(INNOBASE_SHARE *share); static int innobase_close_connection(handlerton *hton, THD* thd); static int innobase_commit(handlerton *hton, THD* thd, bool all); static int innobase_rollback(handlerton *hton, THD* thd, bool all); -static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd, +static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd, void *savepoint); static int innobase_savepoint(handlerton *hton, THD* thd, void *savepoint); -static int innobase_release_savepoint(handlerton *hton, THD* thd, +static int innobase_release_savepoint(handlerton *hton, THD* thd, void *savepoint); static handler *innobase_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); +/*********************************************************************** +This function checks each index name for a table against reserved +system default primary index name 'GEN_CLUST_INDEX'. If a name matches, +this function pushes an error message to the client, and returns true. */ +static +bool +innobase_index_name_is_reserved( +/*============================*/ + /* out: true if index name matches a + reserved name */ + const trx_t* trx, /* in: InnoDB transaction handle */ + const TABLE* form, /* in: information on table + columns and indexes */ + const char* norm_name); /* in: table name */ + +/* "GEN_CLUST_INDEX" is the name reserved for Innodb default +system primary index. */ +static const char innobase_index_reserve_name[]= "GEN_CLUST_INDEX"; + /** @brief Initialize the default value of innodb_commit_concurrency. Once InnoDB is running, the innodb_commit_concurrency must not change @@ -949,7 +968,22 @@ innobase_get_cset_width( *mbminlen = cs->mbminlen; *mbmaxlen = cs->mbmaxlen; } else { - ut_a(cset == 0); + if (current_thd + && (thd_sql_command(current_thd) == SQLCOM_DROP_TABLE)) { + + /* Fix bug#46256: allow tables to be dropped if the + collation is not found, but issue a warning. */ + if ((global_system_variables.log_warnings) + && (cset != 0)){ + + sql_print_warning( + "Unknown collation #%lu.", cset); + } + } else { + + ut_a(cset == 0); + } + *mbminlen = *mbmaxlen = 0; } } @@ -5660,6 +5694,28 @@ create_table_def( } } + /* First check whether the column to be added has a + system reserved name. */ + if (dict_col_name_is_reserved(field->field_name)){ + push_warning_printf( + (THD*) trx->mysql_thd, + MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_CANT_CREATE_TABLE, + "Error creating table '%s' with " + "column name '%s'. '%s' is a " + "reserved name. Please try to " + "re-create the table with a " + "different column name.", + table->name, (char*) field->field_name, + (char*) field->field_name); + + dict_mem_table_free(table); + trx_commit_for_mysql(trx); + + error = DB_ERROR; + goto error_ret; + } + dict_mem_table_add_col(table, table->heap, (char*) field->field_name, col_type, @@ -5673,6 +5729,7 @@ create_table_def( error = row_create_table_for_mysql(table, trx); +error_ret: error = convert_error_code_to_mysql(error, flags, NULL); DBUG_RETURN(error); @@ -5711,6 +5768,9 @@ create_index( n_fields = key->key_parts; + /* Assert that "GEN_CLUST_INDEX" cannot be used as non-primary index */ + ut_a(innobase_strcasecmp(key->name, innobase_index_reserve_name) != 0); + ind_type = 0; if (key_num == form->s->primary_key) { @@ -5819,8 +5879,8 @@ create_clustered_index_when_no_primary( /* We pass 0 as the space id, and determine at a lower level the space id where to store the table */ - - index = dict_mem_index_create(table_name, "GEN_CLUST_INDEX", + index = dict_mem_index_create(table_name, + innobase_index_reserve_name, 0, DICT_CLUSTERED, 0); error = row_create_index_for_mysql(index, trx, NULL); @@ -6246,14 +6306,6 @@ ha_innobase::create( flags = DICT_TF_COMPACT; } - error = create_table_def(trx, form, norm_name, - create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, - flags); - - if (error) { - goto cleanup; - } - /* Look for a primary key */ primary_key_no= (form->s->primary_key != MAX_KEY ? @@ -6265,6 +6317,22 @@ ha_innobase::create( ut_a(primary_key_no == -1 || primary_key_no == 0); + /* Check for name conflicts (with reserved name) for + any user indices to be created. */ + if (innobase_index_name_is_reserved(trx, form, norm_name)) { + error = -1; + goto cleanup; + } + + error = create_table_def(trx, form, norm_name, + create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, + flags); + + if (error) { + goto cleanup; + } + + /* Create the keys */ if (form->s->keys == 0 || primary_key_no == -1) { @@ -9707,6 +9775,46 @@ static int show_innodb_vars(THD *thd, SHOW_VAR *var, char *buff) return 0; } +/*********************************************************************** +This function checks each index name for a table against reserved +system default primary index name 'GEN_CLUST_INDEX'. If a name matches, +this function pushes an error message to the client, and returns true. */ +static +bool +innobase_index_name_is_reserved( +/*============================*/ + /* out: true if an index name + matches the reserved name */ + const trx_t* trx, /* in: InnoDB transaction handle */ + const TABLE* form, /* in: information on table + columns and indexes */ + const char* norm_name) /* in: table name */ +{ + KEY* key; + uint key_num; /* index number */ + + for (key_num = 0; key_num < form->s->keys; key_num++) { + key = form->key_info + key_num; + + if (innobase_strcasecmp(key->name, + innobase_index_reserve_name) == 0) { + /* Push warning to mysql */ + push_warning_printf((THD*) trx->mysql_thd, + MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_CANT_CREATE_TABLE, + "Cannot Create Index with name " + "'%s'. The name is reserved " + "for the system default primary " + "index.", + innobase_index_reserve_name); + + return(true); + } + } + + return(false); +} + static SHOW_VAR innodb_status_variables_export[]= { {"Innodb", (char*) &show_innodb_vars, SHOW_FUNC}, {NullS, NullS, SHOW_LONG} diff --git a/storage/innodb_plugin/include/log0log.ic b/storage/innodb_plugin/include/log0log.ic index 4d2f64af695..36d151a3064 100644 --- a/storage/innodb_plugin/include/log0log.ic +++ b/storage/innodb_plugin/include/log0log.ic @@ -312,11 +312,20 @@ log_reserve_and_write_fast( ib_uint64_t* start_lsn)/*!< out: start lsn of the log record */ { ulint data_len; - ib_uint64_t lsn; +#ifdef UNIV_LOG_LSN_DEBUG + /* length of the LSN pseudo-record */ + ulint lsn_len = 1 + + mach_get_compressed_size(log_sys->lsn >> 32) + + mach_get_compressed_size(log_sys->lsn & 0xFFFFFFFFUL); +#endif /* UNIV_LOG_LSN_DEBUG */ mutex_enter(&log_sys->mutex); - data_len = len + log_sys->buf_free % OS_FILE_LOG_BLOCK_SIZE; + data_len = len +#ifdef UNIV_LOG_LSN_DEBUG + + lsn_len +#endif /* UNIV_LOG_LSN_DEBUG */ + + log_sys->buf_free % OS_FILE_LOG_BLOCK_SIZE; if (data_len >= OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) { @@ -330,7 +339,23 @@ log_reserve_and_write_fast( *start_lsn = log_sys->lsn; - ut_memcpy(log_sys->buf + log_sys->buf_free, str, len); +#ifdef UNIV_LOG_LSN_DEBUG + { + /* Write the LSN pseudo-record. */ + byte* b = &log_sys->buf[log_sys->buf_free]; + *b++ = MLOG_LSN | (MLOG_SINGLE_REC_FLAG & *(const byte*) str); + /* Write the LSN in two parts, + as a pseudo page number and space id. */ + b += mach_write_compressed(b, log_sys->lsn >> 32); + b += mach_write_compressed(b, log_sys->lsn & 0xFFFFFFFFUL); + ut_a(b - lsn_len == &log_sys->buf[log_sys->buf_free]); + + memcpy(b, str, len); + len += lsn_len; + } +#else /* UNIV_LOG_LSN_DEBUG */ + memcpy(log_sys->buf + log_sys->buf_free, str, len); +#endif /* UNIV_LOG_LSN_DEBUG */ log_block_set_data_len((byte*) ut_align_down(log_sys->buf + log_sys->buf_free, @@ -344,14 +369,14 @@ log_reserve_and_write_fast( ut_ad(log_sys->buf_free <= log_sys->buf_size); - lsn = log_sys->lsn += len; + log_sys->lsn += len; #ifdef UNIV_LOG_DEBUG log_check_log_recs(log_sys->buf + log_sys->old_buf_free, log_sys->buf_free - log_sys->old_buf_free, log_sys->old_lsn); #endif - return(lsn); + return(log_sys->lsn); } /***********************************************************************//** diff --git a/storage/innodb_plugin/include/mtr0mtr.h b/storage/innodb_plugin/include/mtr0mtr.h index 44bba43b1ab..bc3f1951be9 100644 --- a/storage/innodb_plugin/include/mtr0mtr.h +++ b/storage/innodb_plugin/include/mtr0mtr.h @@ -106,6 +106,9 @@ For 1 - 8 bytes, the flag value must give the length also! @{ */ #define MLOG_IBUF_BITMAP_INIT ((byte)27) /*!< initialize an ibuf bitmap page */ /*#define MLOG_FULL_PAGE ((byte)28) full contents of a page */ +#ifdef UNIV_LOG_LSN_DEBUG +# define MLOG_LSN ((byte)28) /* current LSN */ +#endif #define MLOG_INIT_FILE_PAGE ((byte)29) /*!< this means that a file page is taken into use and the prior diff --git a/storage/innodb_plugin/include/os0sync.h b/storage/innodb_plugin/include/os0sync.h index ba7c8776f7b..317c6d612fd 100644 --- a/storage/innodb_plugin/include/os0sync.h +++ b/storage/innodb_plugin/include/os0sync.h @@ -398,10 +398,9 @@ compare to, new_val is the value to swap in. */ # define os_compare_and_swap_lint(ptr, old_val, new_val) \ (win_cmp_and_xchg(ptr, new_val, old_val) == old_val) +/* windows thread objects can always be passed to windows atomic functions */ # define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ (InterlockedCompareExchange(ptr, new_val, old_val) == old_val) -/* windows thread objects can always be passed to windows atomic functions */ -# define HAVE_IB_ATOMIC_PTHREAD_T_WINDOWS /**********************************************************//** Returns the resulting value, ptr is pointer to target, amount is the diff --git a/storage/innodb_plugin/include/univ.i b/storage/innodb_plugin/include/univ.i index c087e449cae..73491d9eda4 100644 --- a/storage/innodb_plugin/include/univ.i +++ b/storage/innodb_plugin/include/univ.i @@ -185,6 +185,9 @@ command. Not tested on Windows. */ #define UNIV_LRU_DEBUG /* debug the buffer pool LRU */ #define UNIV_HASH_DEBUG /* debug HASH_ macros */ #define UNIV_LIST_DEBUG /* debug UT_LIST_ macros */ +#define UNIV_LOG_LSN_DEBUG /* write LSN to the redo log; +this will break redo log file compatibility, but it may be useful when +debugging redo log application problems. */ #define UNIV_MEM_DEBUG /* detect memory leaks etc */ #define UNIV_IBUF_DEBUG /* debug the insert buffer */ #define UNIV_IBUF_COUNT_DEBUG /* debug the insert buffer; diff --git a/storage/innodb_plugin/log/log0recv.c b/storage/innodb_plugin/log/log0recv.c index e2d85b2f1bb..ca1a4d3636c 100644 --- a/storage/innodb_plugin/log/log0recv.c +++ b/storage/innodb_plugin/log/log0recv.c @@ -853,6 +853,11 @@ recv_parse_or_apply_log_rec_body( } switch (type) { +#ifdef UNIV_LOG_LSN_DEBUG + case MLOG_LSN: + /* The LSN is checked in recv_parse_log_rec(). */ + break; +#endif /* UNIV_LOG_LSN_DEBUG */ case MLOG_1BYTE: case MLOG_2BYTES: case MLOG_4BYTES: case MLOG_8BYTES: #ifdef UNIV_DEBUG if (page && page_type == FIL_PAGE_TYPE_ALLOCATED @@ -1924,6 +1929,17 @@ recv_parse_log_rec( return(0); } +#ifdef UNIV_LOG_LSN_DEBUG + if (*type == MLOG_LSN) { + ib_uint64_t lsn = (ib_uint64_t) *space << 32 | *page_no; +# ifdef UNIV_LOG_DEBUG + ut_a(lsn == log_sys->old_lsn); +# else /* UNIV_LOG_DEBUG */ + ut_a(lsn == recv_sys->recovered_lsn); +# endif /* UNIV_LOG_DEBUG */ + } +#endif /* UNIV_LOG_LSN_DEBUG */ + /* Check that page_no is sensible */ if (UNIV_UNLIKELY(*page_no > 0x8FFFFFFFUL)) { @@ -2181,6 +2197,12 @@ loop: #endif /* In normal mysqld crash recovery we do not try to replay file operations */ +#ifdef UNIV_LOG_LSN_DEBUG + } else if (type == MLOG_LSN) { + /* Do not add these records to the hash table. + The page number and space id fields are misused + for something else. */ +#endif /* UNIV_LOG_LSN_DEBUG */ } else { recv_add_to_hash_table(type, space, page_no, body, ptr + len, old_lsn, @@ -2212,11 +2234,11 @@ loop: = recv_sys->recovered_offset + total_len; recv_previous_parsed_rec_is_multi = 1; - if ((!store_to_hash) && (type != MLOG_MULTI_REC_END)) { #ifdef UNIV_LOG_DEBUG + if ((!store_to_hash) && (type != MLOG_MULTI_REC_END)) { recv_check_incomplete_log_recs(ptr, len); -#endif /* UNIV_LOG_DEBUG */ } +#endif /* UNIV_LOG_DEBUG */ #ifdef UNIV_DEBUG if (log_debug_writes) { @@ -2280,7 +2302,11 @@ loop: break; } - if (store_to_hash) { + if (store_to_hash +#ifdef UNIV_LOG_LSN_DEBUG + && type != MLOG_LSN +#endif /* UNIV_LOG_LSN_DEBUG */ + ) { recv_add_to_hash_table(type, space, page_no, body, ptr + len, old_lsn, diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index 5fd57efa00c..819381fc280 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -1771,7 +1771,6 @@ row_create_table_for_mysql( const char* table_name; ulint table_name_len; ulint err; - ulint i; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); #ifdef UNIV_SYNC_DEBUG @@ -1806,15 +1805,6 @@ err_exit: goto err_exit; } - /* Check that no reserved column names are used. */ - for (i = 0; i < dict_table_get_n_user_cols(table); i++) { - if (dict_col_name_is_reserved( - dict_table_get_col_name(table, i))) { - - goto err_exit; - } - } - trx_start_if_not_started(trx); /* The table name is prefixed with the database name and a '/'. diff --git a/storage/innodb_plugin/srv/srv0start.c b/storage/innodb_plugin/srv/srv0start.c index 068cb9dbe64..20b77155e5f 100644 --- a/storage/innodb_plugin/srv/srv0start.c +++ b/storage/innodb_plugin/srv/srv0start.c @@ -1097,6 +1097,10 @@ innobase_start_or_create_for_mysql(void) "InnoDB: !!!!!!!! UNIV_SEARCH_DEBUG switched on !!!!!!!!!\n"); #endif +#ifdef UNIV_LOG_LSN_DEBUG + fprintf(stderr, + "InnoDB: !!!!!!!! UNIV_LOG_LSN_DEBUG switched on !!!!!!!!!\n"); +#endif /* UNIV_LOG_LSN_DEBUG */ #ifdef UNIV_MEM_DEBUG fprintf(stderr, "InnoDB: !!!!!!!! UNIV_MEM_DEBUG switched on !!!!!!!!!\n"); From 8fffb92862b643e4d38232d7fa790917caac31e8 Mon Sep 17 00:00:00 2001 From: Satya B Date: Fri, 9 Oct 2009 19:07:47 +0530 Subject: [PATCH 110/146] Applying InnoDB Plugin 1.0.5 snapshot, part 10 From r5917 to r5940 Detailed revision comments: r5917 | marko | 2009-09-16 04:56:23 -0500 (Wed, 16 Sep 2009) | 1 line branches/zip: innobase_get_cset_width(): Cache the value of current_thd. r5919 | vasil | 2009-09-16 13:37:13 -0500 (Wed, 16 Sep 2009) | 4 lines branches/zip: Whitespace cleanup in the ChangeLog. r5920 | vasil | 2009-09-16 13:47:22 -0500 (Wed, 16 Sep 2009) | 4 lines branches/zip: Add ChangeLog entries for r5916. r5922 | marko | 2009-09-17 01:32:08 -0500 (Thu, 17 Sep 2009) | 4 lines branches/zip: innodb-zip.test: Make the test work with zlib 1.2.3.3. Apparently, the definition of compressBound() has slightly changed. This has been filed as Mantis Issue #345. r5924 | vasil | 2009-09-17 23:59:30 -0500 (Thu, 17 Sep 2009) | 4 lines branches/zip: White space and formatting cleanup in the ChangeLog r5934 | vasil | 2009-09-18 12:06:46 -0500 (Fri, 18 Sep 2009) | 4 lines branches/zip: Fix typo. r5935 | calvin | 2009-09-18 16:08:02 -0500 (Fri, 18 Sep 2009) | 6 lines branches/zip: fix bug#44338; minor non-functional changes Bug#44338 innodb has message about non-existing option innodb_max_files_open. Change the option to innodb_open_files. The fix was committed into 6.0 branch. r5938 | calvin | 2009-09-19 02:14:25 -0500 (Sat, 19 Sep 2009) | 41 lines branches/zip: Merge revisions 2584:2956 from branches/6.0, except c2932. Bug#37232 and bug#31183 were fixed in the 6.0 branch only. They should be fixed in the plugin too, specially MySQL 6.0 is discontinued at this point. ------------------------------------------------------------------------ r2604 | inaam | 2008-08-21 09:37:06 -0500 (Thu, 21 Aug 2008) | 8 lines branches/6.0 bug#37232 Relax locking behaviour for REPLACE INTO t SELECT ... FROM t1. Now SELECT on t1 is performed as a consistent read when the isolation level is set to READ COMMITTED. Reviewed by: Heikki ------------------------------------------------------------------------ r2605 | inaam | 2008-08-21 09:59:33 -0500 (Thu, 21 Aug 2008) | 7 lines branches/6.0 Added a comment to clarify why distinct calls to read MySQL binary log file name and log position do not entail any race condition. Suggested by: Heikki ------------------------------------------------------------------------ r2956 | inaam | 2008-11-04 04:47:30 -0600 (Tue, 04 Nov 2008) | 11 lines branches/6.0 bug#31183 If the system tablespace runs out of space because 'autoextend' is not specified with innodb_data_file_path there was no error message printed to the error log. The client would get 'table full' error. This patch prints an appropriate error message to the error log. rb://43 Approved by: Marko ------------------------------------------------------------------------ r5940 | vasil | 2009-09-21 00:26:04 -0500 (Mon, 21 Sep 2009) | 4 lines branches/zip: Add ChangeLog entries for c5938. --- .../suite/innodb/r/innodb-consistent.result | 35 +++++++++ mysql-test/suite/innodb/r/innodb-zip.result | 2 +- .../innodb/t/innodb-consistent-master.opt | 1 + .../suite/innodb/t/innodb-consistent.test | 59 +++++++++++++++ mysql-test/suite/innodb/t/innodb-zip.test | 2 +- storage/innodb_plugin/ChangeLog | 71 +++++++++++++++---- storage/innodb_plugin/fil/fil0fil.c | 4 +- storage/innodb_plugin/fsp/fsp0fsp.c | 16 +++++ storage/innodb_plugin/handler/ha_innodb.cc | 28 ++++++-- storage/innodb_plugin/include/univ.i | 2 +- 10 files changed, 195 insertions(+), 25 deletions(-) create mode 100644 mysql-test/suite/innodb/r/innodb-consistent.result create mode 100644 mysql-test/suite/innodb/t/innodb-consistent-master.opt create mode 100644 mysql-test/suite/innodb/t/innodb-consistent.test diff --git a/mysql-test/suite/innodb/r/innodb-consistent.result b/mysql-test/suite/innodb/r/innodb-consistent.result new file mode 100644 index 00000000000..9115791b99c --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb-consistent.result @@ -0,0 +1,35 @@ +drop table if exists t1; +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +create table t2 like t1; +insert into t2 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; +begin; +replace into t1 select * from t2; +set session transaction isolation level read committed; +set autocommit=0; +delete from t2 where a=5; +commit; +delete from t2; +commit; +commit; +begin; +insert into t1 select * from t2; +set session transaction isolation level read committed; +set autocommit=0; +delete from t2 where a=5; +commit; +delete from t2; +commit; +commit; +select * from t1; +a +1 +2 +3 +4 +5 +6 +7 +drop table t1; +drop table t2; diff --git a/mysql-test/suite/innodb/r/innodb-zip.result b/mysql-test/suite/innodb/r/innodb-zip.result index c81401743a5..b26c4112826 100644 --- a/mysql-test/suite/innodb/r/innodb-zip.result +++ b/mysql-test/suite/innodb/r/innodb-zip.result @@ -141,7 +141,7 @@ drop table t1; CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs -CREATE TABLE t1(c TEXT, PRIMARY KEY (c(439))) +CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512)); DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/innodb-consistent-master.opt b/mysql-test/suite/innodb/t/innodb-consistent-master.opt new file mode 100644 index 00000000000..e76299453d3 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb-consistent-master.opt @@ -0,0 +1 @@ +--innodb_lock_wait_timeout=2 diff --git a/mysql-test/suite/innodb/t/innodb-consistent.test b/mysql-test/suite/innodb/t/innodb-consistent.test new file mode 100644 index 00000000000..b58d0cb0e62 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb-consistent.test @@ -0,0 +1,59 @@ +-- source include/not_embedded.inc +-- source include/have_innodb.inc +-- source suite/innodb/include/have_innodb_plugin.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# REPLACE INTO ... SELECT and INSERT INTO ... SELECT should do +# a consistent read of the source table. + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +create table t2 like t1; +insert into t2 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; + +# REPLACE INTO ... SELECT case +begin; +# this should not result in any locks on t2. +replace into t1 select * from t2; + +connection b; +set session transaction isolation level read committed; +set autocommit=0; +# should not cuase a lock wait. +delete from t2 where a=5; +commit; +delete from t2; +commit; +connection a; +commit; + +# INSERT INTO ... SELECT case +begin; +# this should not result in any locks on t2. +insert into t1 select * from t2; + +connection b; +set session transaction isolation level read committed; +set autocommit=0; +# should not cuase a lock wait. +delete from t2 where a=5; +commit; +delete from t2; +commit; +connection a; +commit; + +select * from t1; +drop table t1; +drop table t2; + +connection default; +disconnect a; +disconnect b; diff --git a/mysql-test/suite/innodb/t/innodb-zip.test b/mysql-test/suite/innodb/t/innodb-zip.test index 3ee278b7c5a..09320570546 100644 --- a/mysql-test/suite/innodb/t/innodb-zip.test +++ b/mysql-test/suite/innodb/t/innodb-zip.test @@ -106,7 +106,7 @@ drop table t1; --error ER_TOO_BIG_ROWSIZE CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; -CREATE TABLE t1(c TEXT, PRIMARY KEY (c(439))) +CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512)); DROP TABLE t1; diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 15d951cb5d1..7fae480a9be 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,10 +1,53 @@ +2009-09-19 The InnoDB Team + + * handler/ha_innodb.cc, mysql-test/innodb-consistent-master.opt, + mysql-test/innodb-consistent.result, + mysql-test/innodb-consistent.test: + Fix Bug#37232 Innodb might get too many read locks for DML with + repeatable-read + +2009-09-19 The InnoDB Team + + * fsp/fsp0fsp.c: + Fix Bug#31183 Tablespace full problems not reported in error log, + error message unclear + +2009-09-17 The InnoDB Team + + * mysql-test/innodb-zip.result, mysql-test/innodb-zip.test: + Make the test pass with zlib 1.2.3.3. Apparently, the definition + of compressBound() has changed between zlib versions, and the + maximum record size of a table with 1K compressed page size has + been reduced by one byte. This is an arbitrary test. In practical + applications, for good write performance, the compressed page size + should be chosen to be bigger than the absolute minimum. + +2009-09-16 The InnoDB Team + + * handler/ha_innodb.cc: + Fix Bug#46256 drop table with unknown collation crashes innodb + +2009-09-16 The InnoDB Team + + * dict/dict0dict.c, handler/ha_innodb.cc, + mysql-test/innodb_bug44369.result, mysql-test/innodb_bug44369.test, + row/row0mysql.c: + Fix Bug#44369 InnoDB: Does not uniformly disallow disallowed column + names + +2009-09-16 The InnoDB Team + + * handler/ha_innodb.cc, include/db0err.h, + mysql-test/innodb_bug46000.result, mysql-test/innodb_bug46000.test: + Fix Bug#46000 using index called GEN_CLUST_INDEX crashes server + 2009-09-02 The InnoDB Team * include/lock0lock.h, include/row0mysql.h, lock/lock0lock.c, row/row0mysql.c: Fix a regression introduced by the fix for MySQL bug#26316. We check whether a transaction holds any AUTOINC locks before we acquire - the kernel mutex and release those locks. + the kernel mutex and release those locks. 2009-08-27 The InnoDB Team @@ -16,29 +59,29 @@ * row/row0merge.c: Fix a bug in the merge sort that can corrupt indexes in fast index - creation. Add some consistency checks. Check that the number of + creation. Add some consistency checks. Check that the number of records remains constant in every merge sort pass. 2009-08-27 The InnoDB Team - * buf/buf0buf.c, buf/buf0lru.c, buf/buf0rea.c, - handler/ha_innodb.cc, include/buf0buf.h, include/buf0buf.ic, - include/buf0lru.h, include/ut0ut.h, ut/ut0ut.c: + * buf/buf0buf.c, buf/buf0lru.c, buf/buf0rea.c, handler/ha_innodb.cc, + include/buf0buf.h, include/buf0buf.ic, include/buf0lru.h, + include/ut0ut.h, ut/ut0ut.c: Make it possible to tune the buffer pool LRU eviction policy to be - more resistant against index scans. Introduce the settable global + more resistant against index scans. Introduce the settable global variables innodb_old_blocks_pct and innodb_old_blocks_time for - controlling the buffer pool eviction policy. The parameter + controlling the buffer pool eviction policy. The parameter innodb_old_blocks_pct (5..95) controls the desired amount of "old" - blocks in the LRU list. The default is 37, corresponding to the - old fixed ratio of 3/8. Each time a block is accessed, it will be + blocks in the LRU list. The default is 37, corresponding to the + old fixed ratio of 3/8. Each time a block is accessed, it will be moved to the "new" blocks if its first access was at least innodb_old_blocks_time milliseconds ago (default 0, meaning every - block). The idea is that in index scans, blocks will be accessed + block). The idea is that in index scans, blocks will be accessed a few times within innodb_old_blocks_time, and they will remain in - the "old" section of the LRU list. Thus, when - innodb_old_blocks_time is nonzero, blocks retrieved for one-time - index scans will be more likely candidates for eviction than - blocks that are accessed in random patterns. + the "old" section of the LRU list. Thus, when innodb_old_blocks_time + is nonzero, blocks retrieved for one-time index scans will be more + likely candidates for eviction than blocks that are accessed in + random patterns. 2009-08-26 The InnoDB Team diff --git a/storage/innodb_plugin/fil/fil0fil.c b/storage/innodb_plugin/fil/fil0fil.c index 96e60b0128f..c6ffef5caef 100644 --- a/storage/innodb_plugin/fil/fil0fil.c +++ b/storage/innodb_plugin/fil/fil0fil.c @@ -955,7 +955,7 @@ close_more: " while the maximum\n" "InnoDB: allowed value would be %lu.\n" "InnoDB: You may need to raise the value of" - " innodb_max_files_open in\n" + " innobase_open_files in\n" "InnoDB: my.cnf.\n", (ulong) fil_system->n_open, (ulong) fil_system->max_n_open); @@ -1535,7 +1535,7 @@ fil_open_log_and_system_tablespace_files(void) fprintf(stderr, "InnoDB: Warning: you must" " raise the value of" - " innodb_max_open_files in\n" + " innobase_open_files in\n" "InnoDB: my.cnf! Remember that" " InnoDB keeps all log files" " and all system\n" diff --git a/storage/innodb_plugin/fsp/fsp0fsp.c b/storage/innodb_plugin/fsp/fsp0fsp.c index f59a76aa3a3..08bd2ac8116 100644 --- a/storage/innodb_plugin/fsp/fsp0fsp.c +++ b/storage/innodb_plugin/fsp/fsp0fsp.c @@ -231,6 +231,9 @@ the extent are free and which contain old tuple version to clean. */ /* Offset of the descriptor array on a descriptor page */ #define XDES_ARR_OFFSET (FSP_HEADER_OFFSET + FSP_HEADER_SIZE) +/* Flag to indicate if we have printed the tablespace full error. */ +static ibool fsp_tbs_full_error_printed = FALSE; + #ifndef UNIV_HOTBACKUP /**********************************************************************//** Returns an extent to the free list of a space. */ @@ -1218,6 +1221,19 @@ fsp_try_extend_data_file( if (space == 0 && !srv_auto_extend_last_data_file) { + /* We print the error message only once to avoid + spamming the error log. Note that we don't need + to reset the flag to FALSE as dealing with this + error requires server restart. */ + if (fsp_tbs_full_error_printed == FALSE) { + fprintf(stderr, + "InnoDB: Error: Data file(s) ran" + " out of space.\n" + "Please add another data file or" + " use \'autoextend\' for the last" + " data file.\n"); + fsp_tbs_full_error_printed = TRUE; + } return(FALSE); } diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 9db4d202d93..49f3336a4c8 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -968,8 +968,9 @@ innobase_get_cset_width( *mbminlen = cs->mbminlen; *mbmaxlen = cs->mbmaxlen; } else { - if (current_thd - && (thd_sql_command(current_thd) == SQLCOM_DROP_TABLE)) { + THD* thd = current_thd; + + if (thd && thd_sql_command(thd) == SQLCOM_DROP_TABLE) { /* Fix bug#46256: allow tables to be dropped if the collation is not found, but issue a warning. */ @@ -2496,6 +2497,19 @@ retry: } } + /* The following calls to read the MySQL binary log + file name and the position return consistent results: + 1) Other InnoDB transactions cannot intervene between + these calls as we are holding prepare_commit_mutex. + 2) Binary logging of other engines is not relevant + to InnoDB as all InnoDB requires is that committing + InnoDB transactions appear in the same order in the + MySQL binary log as they appear in InnoDB logs. + 3) A MySQL log file rotation cannot happen because + MySQL protects against this by having a counter of + transactions in prepared state and it only allows + a rotation when the counter drops to zero. See + LOCK_prep_xids and COND_prep_xids in log.cc. */ trx->mysql_log_file_name = mysql_bin_log_file_name(); trx->mysql_log_offset = (ib_int64_t) mysql_bin_log_file_pos(); @@ -8517,6 +8531,7 @@ ha_innobase::store_lock( && isolation_level != TRX_ISO_SERIALIZABLE && (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT) && (sql_command == SQLCOM_INSERT_SELECT + || sql_command == SQLCOM_REPLACE_SELECT || sql_command == SQLCOM_UPDATE || sql_command == SQLCOM_CREATE_TABLE)) { @@ -8524,10 +8539,11 @@ ha_innobase::store_lock( option set or this session is using READ COMMITTED isolation level and isolation level of the transaction is not set to serializable and MySQL is doing - INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or - CREATE ... SELECT... without FOR UPDATE or - IN SHARE MODE in select, then we use consistent - read for select. */ + INSERT INTO...SELECT or REPLACE INTO...SELECT + or UPDATE ... = (SELECT ...) or CREATE ... + SELECT... without FOR UPDATE or IN SHARE + MODE in select, then we use consistent read + for select. */ prebuilt->select_lock_type = LOCK_NONE; prebuilt->stored_select_lock_type = LOCK_NONE; diff --git a/storage/innodb_plugin/include/univ.i b/storage/innodb_plugin/include/univ.i index 73491d9eda4..b508a42c445 100644 --- a/storage/innodb_plugin/include/univ.i +++ b/storage/innodb_plugin/include/univ.i @@ -50,7 +50,7 @@ Created 1/20/1994 Heikki Tuuri /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; -calculated in in make_version_string() in sql/sql_show.cc like this: +calculated in make_version_string() in sql/sql_show.cc like this: "version >> 8" . "version & 0xff" because the version is shown with only one dot, we skip the last component, i.e. we show M.N.P as M.N */ From a1bb24eb2b7345edaf6d47305cd5c205f7a9c903 Mon Sep 17 00:00:00 2001 From: Satya B Date: Fri, 9 Oct 2009 19:32:18 +0530 Subject: [PATCH 111/146] Applying InnoDB Plugin 1.0.5 snapshot, part 11 From revision r5945 to r5994 r5950 - already applied and so skipped Detailed revision comments: r5945 | calvin | 2009-09-21 09:53:22 -0500 (Mon, 21 Sep 2009) | 4 lines branches/zip: fix a type in r5935 Should be innodb_open_files, spotted by Michael. r5951 | calvin | 2009-09-22 10:17:01 -0500 (Tue, 22 Sep 2009) | 4 lines branches/zip: adjust CMake file to work with old versions of MySQL Tested with MySQL 5.1.38 and 5.1.30. r5956 | calvin | 2009-09-22 18:30:10 -0500 (Tue, 22 Sep 2009) | 4 lines branches/zip: remove handler0vars.h from Makefile.am Left over from r5950. r5971 | marko | 2009-09-23 08:03:51 -0500 (Wed, 23 Sep 2009) | 2 lines branches/zip: os_file_pwrite(): Make the code compile in InnoDB Hot Backup when the pwrite system call is not available. r5972 | marko | 2009-09-23 14:44:52 -0500 (Wed, 23 Sep 2009) | 5 lines branches/zip: fil_node_open_file(): In InnoDB Hot Backup, determine the page size of single-file tablespaces before computing the file node size. Otherwise, the space->size of compressed tablespaces would be computed with UNIV_PAGE_SIZE instead of key_block_size. This should fix Issue #313. r5973 | marko | 2009-09-23 14:53:21 -0500 (Wed, 23 Sep 2009) | 2 lines branches/zip: recv_add_to_hash_table(): Simplify obfuscated pointer arithmetics. r5978 | marko | 2009-09-24 02:47:56 -0500 (Thu, 24 Sep 2009) | 1 line branches/zip: Fix warnings and errors when UNIV_HOTBACKUP is defined. r5979 | marko | 2009-09-24 05:16:10 -0500 (Thu, 24 Sep 2009) | 4 lines branches/zip: ha_innodb.cc: Define MYSQL_PLUGIN_IMPORT when necessary. This preprocessor symbol has been recently introduced in MySQL 5.1. The InnoDB Plugin should remain source compatible with MySQL 5.1.24 and later. r5988 | calvin | 2009-09-25 14:14:43 -0500 (Fri, 25 Sep 2009) | 8 lines branches/zip: fix bug#47055 unconditional exit(1) on ERROR_WORKING_SET_QUOTA 1453 (0x5AD) for InnoDB backend When error ERROR_WORKING_SET_QUOTA or ERROR_NO_SYSTEM_RESOURCES occurs, yields for 100ms and retries the operation. Approved by: Heikki (on IM) r5992 | vasil | 2009-09-28 02:10:29 -0500 (Mon, 28 Sep 2009) | 4 lines branches/zip: Add ChangeLog entry for c5988. r5994 | marko | 2009-09-28 03:33:59 -0500 (Mon, 28 Sep 2009) | 17 lines branches/zip: Try to prevent the reuse of tablespace identifiers after InnoDB has crashed during table creation. Also, refuse to start if files with duplicate tablespace identifiers are encountered. fil_node_create(): Update fil_system->max_assigned_id. This should prevent the reuse of a space->id when InnoDB does a full crash recovery and invokes fil_load_single_table_tablespaces(). Normally, fil_system->max_assigned_id is initialized from SELECT MAX(ID) FROM SYS_TABLES. fil_open_single_table_tablespace(): Return FALSE when fil_space_create() fails. fil_load_single_table_tablespace(): Exit if fil_space_create() fails and innodb_force_recovery=0. rb://173 approved by Heikki Tuuri. This addresses Issue #335. --- storage/innodb_plugin/CMakeLists.txt | 24 +++++++++++-- storage/innodb_plugin/ChangeLog | 13 +++++++ storage/innodb_plugin/Makefile.am | 1 - storage/innodb_plugin/fil/fil0fil.c | 41 +++++++++++++++------- storage/innodb_plugin/fsp/fsp0fsp.c | 2 +- storage/innodb_plugin/handler/ha_innodb.cc | 3 ++ storage/innodb_plugin/include/os0file.h | 1 + storage/innodb_plugin/log/log0recv.c | 2 +- storage/innodb_plugin/os/os0file.c | 27 ++++++++++++++ 9 files changed, 97 insertions(+), 17 deletions(-) diff --git a/storage/innodb_plugin/CMakeLists.txt b/storage/innodb_plugin/CMakeLists.txt index 7762ece9bcd..b86a3e7c8e1 100644 --- a/storage/innodb_plugin/CMakeLists.txt +++ b/storage/innodb_plugin/CMakeLists.txt @@ -18,7 +18,13 @@ SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") + +# Starting at 5.1.38, MySQL CMake files are simplified. But the plugin +# CMakeLists.txt still needs to work with previous versions of MySQL. +IF (MYSQL_VERSION_ID GREATER "50137") + INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") +ENDIF (MYSQL_VERSION_ID GREATER "50137") + IF (CMAKE_SIZEOF_VOID_P MATCHES 8) SET(WIN64 TRUE) ENDIF (CMAKE_SIZEOF_VOID_P MATCHES 8) @@ -75,4 +81,18 @@ SET(INNODB_PLUGIN_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c ut/ut0list.c ut/ut0wqueue.c) ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS -DINNODB_RW_LOCKS_USE_ATOMICS -DIB_HAVE_PAUSE_INSTRUCTION) -MYSQL_STORAGE_ENGINE(INNODB_PLUGIN) \ No newline at end of file +MYSQL_STORAGE_ENGINE(INNODB_PLUGIN) +IF (MYSQL_VERSION_ID GREATER "50137") + IF (WITH_INNOBASE_STORAGE_ENGINE) + MYSQL_STORAGE_ENGINE(INNOBASE) + ELSE (WITH_INNOBASE_STORAGE_ENGINE) + SET (INNODB_SOURCES ${INNOBASE_SOURCES}) + MYSQL_STORAGE_ENGINE(INNODB) + ENDIF (WITH_INNOBASE_STORAGE_ENGINE) +ELSE (MYSQL_VERSION_ID GREATER "50137") + IF (NOT SOURCE_SUBLIBS) + ADD_DEFINITIONS(-D_WIN32 -DMYSQL_SERVER) + ADD_LIBRARY(innobase STATIC ${INNOBASE_SOURCES}) + # Require mysqld_error.h, which is built as part of the GenError + ADD_DEPENDENCIES(innobase GenError) + ENDIF (NOT SOURCE_SUBLIBS) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 7fae480a9be..6ae7a353142 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,16 @@ +2009-09-28 The InnoDB Team + + * fil/fil0fil.c: + Try to prevent the reuse of tablespace identifiers after InnoDB + has crashed during table creation. Also, refuse to start if files + with duplicate tablespace identifiers are encountered. + +2009-09-25 The InnoDB Team + + * include/os0file.h, os/os0file.c: + Fix Bug#47055 unconditional exit(1) on ERROR_WORKING_SET_QUOTA + 1453 (0x5AD) for InnoDB backend + 2009-09-19 The InnoDB Team * handler/ha_innodb.cc, mysql-test/innodb-consistent-master.opt, diff --git a/storage/innodb_plugin/Makefile.am b/storage/innodb_plugin/Makefile.am index 50a3c1e6cab..5c71fe18d14 100644 --- a/storage/innodb_plugin/Makefile.am +++ b/storage/innodb_plugin/Makefile.am @@ -31,7 +31,6 @@ DEFS= @DEFS@ noinst_HEADERS= \ handler/ha_innodb.h \ - handler/handler0vars.h \ handler/i_s.h \ include/btr0btr.h \ include/btr0btr.ic \ diff --git a/storage/innodb_plugin/fil/fil0fil.c b/storage/innodb_plugin/fil/fil0fil.c index c6ffef5caef..df6dad86990 100644 --- a/storage/innodb_plugin/fil/fil0fil.c +++ b/storage/innodb_plugin/fil/fil0fil.c @@ -594,6 +594,11 @@ fil_node_create( UT_LIST_ADD_LAST(chain, space->chain, node); + if (id < SRV_LOG_SPACE_FIRST_ID && fil_system->max_assigned_id < id) { + + fil_system->max_assigned_id = id; + } + mutex_exit(&fil_system->mutex); } @@ -613,12 +618,10 @@ fil_node_open_file( ulint size_high; ibool ret; ibool success; -#ifndef UNIV_HOTBACKUP byte* buf2; byte* page; ulint space_id; ulint flags; -#endif /* !UNIV_HOTBACKUP */ ut_ad(mutex_own(&(system->mutex))); ut_a(node->n_pending == 0); @@ -654,9 +657,11 @@ fil_node_open_file( size_bytes = (((ib_int64_t)size_high) << 32) + (ib_int64_t)size_low; #ifdef UNIV_HOTBACKUP - node->size = (ulint) (size_bytes / UNIV_PAGE_SIZE); - /* TODO: adjust to zip_size, like below? */ -#else + if (space->id == 0) { + node->size = (ulint) (size_bytes / UNIV_PAGE_SIZE); + goto add_size; + } +#endif /* UNIV_HOTBACKUP */ ut_a(space->purpose != FIL_LOG); ut_a(space->id != 0); @@ -735,7 +740,10 @@ fil_node_open_file( (size_bytes / dict_table_flags_to_zip_size(flags)); } -#endif + +#ifdef UNIV_HOTBACKUP +add_size: +#endif /* UNIV_HOTBACKUP */ space->size += node->size; } @@ -955,7 +963,7 @@ close_more: " while the maximum\n" "InnoDB: allowed value would be %lu.\n" "InnoDB: You may need to raise the value of" - " innobase_open_files in\n" + " innodb_open_files in\n" "InnoDB: my.cnf.\n", (ulong) fil_system->n_open, (ulong) fil_system->max_n_open); @@ -1535,7 +1543,7 @@ fil_open_log_and_system_tablespace_files(void) fprintf(stderr, "InnoDB: Warning: you must" " raise the value of" - " innobase_open_files in\n" + " innodb_open_files in\n" "InnoDB: my.cnf! Remember that" " InnoDB keeps all log files" " and all system\n" @@ -2923,7 +2931,6 @@ fil_open_single_table_tablespace( byte* page; ulint space_id; ulint space_flags; - ibool ret = TRUE; filepath = fil_make_ibd_name(name, FALSE); @@ -3001,7 +3008,7 @@ fil_open_single_table_tablespace( (ulong) space_id, (ulong) space_flags, (ulong) id, (ulong) flags); - ret = FALSE; + success = FALSE; goto func_exit; } @@ -3021,7 +3028,7 @@ func_exit: os_file_close(file); mem_free(filepath); - return(ret); + return(success); } #endif /* !UNIV_HOTBACKUP */ @@ -3299,7 +3306,17 @@ fil_load_single_table_tablespace( if (!success) { - goto func_exit; + if (srv_force_recovery > 0) { + fprintf(stderr, + "InnoDB: innodb_force_recovery" + " was set to %lu. Continuing crash recovery\n" + "InnoDB: even though the tablespace creation" + " of this table failed.\n", + srv_force_recovery); + goto func_exit; + } + + exit(1); } /* We do not use the size information we have about the file, because diff --git a/storage/innodb_plugin/fsp/fsp0fsp.c b/storage/innodb_plugin/fsp/fsp0fsp.c index 08bd2ac8116..9b4dca198c1 100644 --- a/storage/innodb_plugin/fsp/fsp0fsp.c +++ b/storage/innodb_plugin/fsp/fsp0fsp.c @@ -231,10 +231,10 @@ the extent are free and which contain old tuple version to clean. */ /* Offset of the descriptor array on a descriptor page */ #define XDES_ARR_OFFSET (FSP_HEADER_OFFSET + FSP_HEADER_SIZE) +#ifndef UNIV_HOTBACKUP /* Flag to indicate if we have printed the tablespace full error. */ static ibool fsp_tbs_full_error_printed = FALSE; -#ifndef UNIV_HOTBACKUP /**********************************************************************//** Returns an extent to the free list of a space. */ static diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 49f3336a4c8..18d6adf7a92 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -107,6 +107,9 @@ extern "C" { #include "i_s.h" #ifndef MYSQL_SERVER +# ifndef MYSQL_PLUGIN_IMPORT +# define MYSQL_PLUGIN_IMPORT /* nothing */ +# endif /* MYSQL_PLUGIN_IMPORT */ /* This is needed because of Bug #3596. Let us hope that pthread_mutex_t is defined the same in both builds: the MySQL server and the InnoDB plugin. */ extern MYSQL_PLUGIN_IMPORT pthread_mutex_t LOCK_thread_count; diff --git a/storage/innodb_plugin/include/os0file.h b/storage/innodb_plugin/include/os0file.h index d8d2f0e5d9e..8535ef092c3 100644 --- a/storage/innodb_plugin/include/os0file.h +++ b/storage/innodb_plugin/include/os0file.h @@ -157,6 +157,7 @@ log. */ to become available again */ #define OS_FILE_SHARING_VIOLATION 76 #define OS_FILE_ERROR_NOT_SPECIFIED 77 +#define OS_FILE_INSUFFICIENT_RESOURCE 78 /* @} */ /** Types for aio operations @{ */ diff --git a/storage/innodb_plugin/log/log0recv.c b/storage/innodb_plugin/log/log0recv.c index ca1a4d3636c..2e4f14beccb 100644 --- a/storage/innodb_plugin/log/log0recv.c +++ b/storage/innodb_plugin/log/log0recv.c @@ -1274,7 +1274,7 @@ recv_add_to_hash_table( sizeof(recv_data_t) + len); *prev_field = recv_data; - ut_memcpy(((byte*)recv_data) + sizeof(recv_data_t), body, len); + memcpy(recv_data + 1, body, len); prev_field = &(recv_data->next); diff --git a/storage/innodb_plugin/os/os0file.c b/storage/innodb_plugin/os/os0file.c index 50612282f69..a1d3bad2add 100644 --- a/storage/innodb_plugin/os/os0file.c +++ b/storage/innodb_plugin/os/os0file.c @@ -317,6 +317,12 @@ os_file_get_last_error( " software or another instance\n" "InnoDB: of MySQL." " Please close it to get rid of this error.\n"); + } else if (err == ERROR_WORKING_SET_QUOTA + || err == ERROR_NO_SYSTEM_RESOURCES) { + fprintf(stderr, + "InnoDB: The error means that there are no" + " sufficient system resources or quota to" + " complete the operation.\n"); } else { fprintf(stderr, "InnoDB: Some operating system error numbers" @@ -338,6 +344,9 @@ os_file_get_last_error( } else if (err == ERROR_SHARING_VIOLATION || err == ERROR_LOCK_VIOLATION) { return(OS_FILE_SHARING_VIOLATION); + } else if (err == ERROR_WORKING_SET_QUOTA + || err == ERROR_NO_SYSTEM_RESOURCES) { + return(OS_FILE_INSUFFICIENT_RESOURCE); } else { return(100 + err); } @@ -456,6 +465,10 @@ os_file_handle_error_cond_exit( os_thread_sleep(10000000); /* 10 sec */ return(TRUE); + } else if (err == OS_FILE_INSUFFICIENT_RESOURCE) { + + os_thread_sleep(100000); /* 100 ms */ + return(TRUE); } else { if (name) { fprintf(stderr, "InnoDB: File name %s\n", name); @@ -2032,7 +2045,9 @@ os_file_pread( offset */ { off_t offs; +#if defined(HAVE_PREAD) && !defined(HAVE_BROKEN_PREAD) ssize_t n_bytes; +#endif /* HAVE_PREAD && !HAVE_BROKEN_PREAD */ ut_a((offset & 0xFFFFFFFFUL) == offset); @@ -2071,16 +2086,20 @@ os_file_pread( { off_t ret_offset; ssize_t ret; +#ifndef UNIV_HOTBACKUP ulint i; +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads++; os_mutex_exit(os_file_count_mutex); +#ifndef UNIV_HOTBACKUP /* Protect the seek / read operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; os_mutex_enter(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ ret_offset = lseek(file, offs, SEEK_SET); @@ -2090,7 +2109,9 @@ os_file_pread( ret = read(file, buf, (ssize_t)n); } +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads--; @@ -2168,16 +2189,20 @@ os_file_pwrite( #else { off_t ret_offset; +# ifndef UNIV_HOTBACKUP ulint i; +# endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_writes++; os_mutex_exit(os_file_count_mutex); +# ifndef UNIV_HOTBACKUP /* Protect the seek / write operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; os_mutex_enter(os_file_seek_mutexes[i]); +# endif /* UNIV_HOTBACKUP */ ret_offset = lseek(file, offs, SEEK_SET); @@ -2203,7 +2228,9 @@ os_file_pwrite( # endif /* UNIV_DO_FLUSH */ func_exit: +# ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +# endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_writes--; From fa548cd0ffe4a029db71c27d783b8cbcd642c50f Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Fri, 9 Oct 2009 16:12:01 +0200 Subject: [PATCH 112/146] Bug#46922 post push update Disable the test when it will not hit the open_files_limit --- mysql-test/t/partition_open_files_limit.test | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mysql-test/t/partition_open_files_limit.test b/mysql-test/t/partition_open_files_limit.test index 92a9b18b573..e62ebd0ade7 100644 --- a/mysql-test/t/partition_open_files_limit.test +++ b/mysql-test/t/partition_open_files_limit.test @@ -4,6 +4,13 @@ DROP TABLE IF EXISTS `t1`; --enable_warnings +# On some platforms the lowest possible open_files_limit is too high... +let $max_open_files_limit= `SELECT @@open_files_limit > 511`; +if ($max_open_files_limit) +{ + skip Need open_files_limit to be lower than 512; +} + # --echo # Bug#46922: crash when adding partitions and open_files_limit is reached # From adb93e54e8b08b44425fe3b4647debdbdc948e73 Mon Sep 17 00:00:00 2001 From: Satya B Date: Fri, 9 Oct 2009 19:43:15 +0530 Subject: [PATCH 113/146] Applying InnoDB Plugin 1.0.5 snapshot ,part 12 From r5995 to r6043 Detailed revision comments: r5995 | marko | 2009-09-28 03:52:25 -0500 (Mon, 28 Sep 2009) | 17 lines branches/zip: Do not write to PAGE_INDEX_ID after page creation, not even when restoring an uncompressed page after a compression failure. btr_page_reorganize_low(): On compression failure, do not restore those page header fields that should not be affected by the reorganization. Instead, compare the fields. page_zip_decompress(): Add the parameter ibool all, for copying all page header fields. Pass the parameter all=TRUE on block read completion, redo log application, and page_zip_validate(); pass all=FALSE in all other cases. page_zip_reorganize(): Do not restore the uncompressed page on failure. It will be restored (to pre-modification state) by the caller anyway. rb://167, Issue #346 r5996 | marko | 2009-09-28 07:46:02 -0500 (Mon, 28 Sep 2009) | 4 lines branches/zip: Address Issue #350 in comments. lock_rec_queue_validate(), lock_rec_queue_validate(): Note that this debug code may violate the latching order and cause deadlocks. r5997 | marko | 2009-09-28 08:03:58 -0500 (Mon, 28 Sep 2009) | 12 lines branches/zip: Remove an assertion failure when the InnoDB data dictionary is inconsistent with the MySQL .frm file. ha_innobase::index_read(): When the index cannot be found, return an error. ha_innobase::change_active_index(): When prebuilt->index == NULL, set also prebuilt->index_usable = FALSE. This is not needed for correctness, because prebuilt->index_usable is only checked by row_search_for_mysql(), which requires prebuilt->index != NULL. This addresses Issue #349. Approved by Heikki Tuuri over IM. r6005 | vasil | 2009-09-29 03:09:52 -0500 (Tue, 29 Sep 2009) | 4 lines branches/zip: ChangeLog: wrap around 78th column, not earlier. r6006 | vasil | 2009-09-29 05:15:25 -0500 (Tue, 29 Sep 2009) | 4 lines branches/zip: Add ChangeLog entry for the release of 1.0.4. r6007 | vasil | 2009-09-29 08:19:59 -0500 (Tue, 29 Sep 2009) | 6 lines branches/zip: Fix the year, should be 2009. Pointed by: Calvin r6026 | marko | 2009-09-30 02:18:24 -0500 (Wed, 30 Sep 2009) | 1 line branches/zip: Add some debug assertions for checking FSEG_MAGIC_N. r6028 | marko | 2009-09-30 08:55:23 -0500 (Wed, 30 Sep 2009) | 3 lines branches/zip: recv_no_log_write: New debug flag for tracking down Mantis Issue #347. No modifications should be made to the database while recv_apply_hashed_log_recs() is about to complete. r6029 | calvin | 2009-09-30 15:32:02 -0500 (Wed, 30 Sep 2009) | 4 lines branches/zip: non-functional changes Fix typo. r6031 | marko | 2009-10-01 06:24:33 -0500 (Thu, 01 Oct 2009) | 49 lines branches/zip: Clean up after a crash during DROP INDEX. When InnoDB crashes while dropping an index, ensure that the index will be completely dropped during crash recovery. row_merge_drop_index(): Before dropping an index, rename the index to start with TEMP_INDEX_PREFIX_STR and commit the change, so that row_merge_drop_temp_indexes() will drop the index after crash recovery if the server crashes while dropping the index. fseg_inode_try_get(): New function, forked from fseg_inode_get(). Return NULL if the file segment index node is free. fseg_inode_get(): Assert that the file segment index node is not free. fseg_free_step(): If the file segment index node is already free, print a diagnostic message and return TRUE. fsp_free_seg_inode(): Write a nonzero number to FSEG_MAGIC_N, so that allocated-and-freed file segment index nodes can be better distinguished from uninitialized ones. This is rb://174, addressing Issue #348. Tested by restarting mysqld upon the completion of the added log_write_up_to() invocation below, during DROP INDEX. The index was dropped after crash recovery, and re-issuing the DROP INDEX did not crash the server. Index: btr/btr0btr.c =================================================================== --- btr/btr0btr.c (revision 6026) +++ btr/btr0btr.c (working copy) @@ -42,6 +42,7 @@ Created 6/2/1994 Heikki Tuuri #include "ibuf0ibuf.h" #include "trx0trx.h" +#include "log0log.h" /* Latching strategy of the InnoDB B-tree -------------------------------------- @@ -873,6 +874,8 @@ leaf_loop: goto leaf_loop; } + + log_write_up_to(mtr.end_lsn, LOG_WAIT_ALL_GROUPS, TRUE); top_loop: mtr_start(&mtr); r6033 | calvin | 2009-10-01 15:19:46 -0500 (Thu, 01 Oct 2009) | 4 lines branches/zip: fix a typo in error message Reported as bug#47763. r6043 | inaam | 2009-10-05 09:45:35 -0500 (Mon, 05 Oct 2009) | 12 lines branches/zip rb://176 Do not invalidate buffer pool while an LRU batch is active. Added code to buf_pool_invalidate() to wait for the running batches to finish. This patch also resets the state of buf_pool struct at invalidation. This addresses the concern where buf_pool->freed_page_clock becomes non-zero because we read in a system tablespace page for file format info at startup. Approved by: Marko --- storage/innodb_plugin/ChangeLog | 30 +++++++++++ storage/innodb_plugin/btr/btr0btr.c | 24 ++++++++- storage/innodb_plugin/buf/buf0buf.c | 37 ++++++++++++- storage/innodb_plugin/fsp/fsp0fsp.c | 62 +++++++++++++++++++--- storage/innodb_plugin/handler/ha_innodb.cc | 8 ++- storage/innodb_plugin/include/log0recv.h | 5 ++ storage/innodb_plugin/include/page0page.h | 7 ++- storage/innodb_plugin/include/page0zip.h | 12 +++-- storage/innodb_plugin/include/row0ins.h | 2 +- storage/innodb_plugin/lock/lock0lock.c | 9 ++++ storage/innodb_plugin/log/log0log.c | 12 ++++- storage/innodb_plugin/log/log0recv.c | 7 +++ storage/innodb_plugin/mtr/mtr0mtr.c | 3 ++ storage/innodb_plugin/page/page0cur.c | 2 +- storage/innodb_plugin/page/page0page.c | 4 +- storage/innodb_plugin/page/page0zip.c | 51 +++++++++++++----- storage/innodb_plugin/row/row0ins.c | 2 +- storage/innodb_plugin/row/row0merge.c | 8 +++ storage/innodb_plugin/trx/trx0trx.c | 2 +- 19 files changed, 250 insertions(+), 37 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 6ae7a353142..d88a3ace872 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,29 @@ +2009-10-01 The InnoDB Team + + * fsp/fsp0fsp.c, row/row0merge.c: + Clean up after a crash during DROP INDEX. When InnoDB crashes + while dropping an index, ensure that the index will be completely + dropped during crash recovery. The MySQL .frm file may still + contain the dropped index, but there is little that we can do + about it. + +2009-09-28 The InnoDB Team + + * handler/ha_innodb.cc: + When a secondary index exists in the MySQL .frm file but not in + the InnoDB data dictionary, return an error instead of letting an + assertion fail in index_read. + +2009-09-28 The InnoDB Team + + * btr/btr0btr.c, buf/buf0buf.c, include/page0page.h, + include/page0zip.h, page/page0cur.c, page/page0page.c, + page/page0zip.c: + Do not write to PAGE_INDEX_ID when restoring an uncompressed page + after a compression failure. The field should only be written + when creating a B-tree page. This fix addresses a race condition + in a debug assertion. + 2009-09-28 The InnoDB Team * fil/fil0fil.c: @@ -114,6 +140,10 @@ Fix Bug#46657 InnoDB plugin: invalid read in index_merge_innodb test (Valgrind) +2009-08-11 The InnoDB Team + + InnoDB Plugin 1.0.4 released + 2009-07-20 The InnoDB Team * handler/ha_innodb.cc, buf/buf0rea.c, include/srv0srv.h, srv/srv0srv.c diff --git a/storage/innodb_plugin/btr/btr0btr.c b/storage/innodb_plugin/btr/btr0btr.c index f34490ae101..108575798cf 100644 --- a/storage/innodb_plugin/btr/btr0btr.c +++ b/storage/innodb_plugin/btr/btr0btr.c @@ -41,6 +41,7 @@ Created 6/2/1994 Heikki Tuuri #include "lock0lock.h" #include "ibuf0ibuf.h" #include "trx0trx.h" +#include "log0log.h" /* Latching strategy of the InnoDB B-tree @@ -873,6 +874,8 @@ leaf_loop: goto leaf_loop; } + + log_write_up_to(mtr.end_lsn, LOG_WAIT_ALL_GROUPS, TRUE); top_loop: mtr_start(&mtr); @@ -1011,7 +1014,26 @@ btr_page_reorganize_low( (!page_zip_compress(page_zip, page, index, NULL))) { /* Restore the old page and exit. */ - buf_frame_copy(page, temp_page); + +#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG + /* Check that the bytes that we skip are identical. */ + ut_a(!memcmp(page, temp_page, PAGE_HEADER)); + ut_a(!memcmp(PAGE_HEADER + PAGE_N_RECS + page, + PAGE_HEADER + PAGE_N_RECS + temp_page, + PAGE_DATA - (PAGE_HEADER + PAGE_N_RECS))); + ut_a(!memcmp(UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + page, + UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + temp_page, + FIL_PAGE_DATA_END)); +#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */ + + memcpy(PAGE_HEADER + page, PAGE_HEADER + temp_page, + PAGE_N_RECS - PAGE_N_DIR_SLOTS); + memcpy(PAGE_DATA + page, PAGE_DATA + temp_page, + UNIV_PAGE_SIZE - PAGE_DATA - FIL_PAGE_DATA_END); + +#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG + ut_a(!memcmp(page, temp_page, UNIV_PAGE_SIZE)); +#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */ goto func_exit; } diff --git a/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c index 32435bd1f87..d87abbd0ed9 100644 --- a/storage/innodb_plugin/buf/buf0buf.c +++ b/storage/innodb_plugin/buf/buf0buf.c @@ -1834,7 +1834,7 @@ buf_zip_decompress( switch (fil_page_get_type(frame)) { case FIL_PAGE_INDEX: if (page_zip_decompress(&block->page.zip, - block->frame)) { + block->frame, TRUE)) { return(TRUE); } @@ -3287,7 +3287,32 @@ void buf_pool_invalidate(void) /*=====================*/ { - ibool freed; + ibool freed; + enum buf_flush i; + + buf_pool_mutex_enter(); + + for (i = BUF_FLUSH_LRU; i < BUF_FLUSH_N_TYPES; i++) { + + /* As this function is called during startup and + during redo application phase during recovery, InnoDB + is single threaded (apart from IO helper threads) at + this stage. No new write batch can be in intialization + stage at this point. */ + ut_ad(buf_pool->init_flush[i] == FALSE); + + /* However, it is possible that a write batch that has + been posted earlier is still not complete. For buffer + pool invalidation to proceed we must ensure there is NO + write activity happening. */ + if (buf_pool->n_flush[i] > 0) { + buf_pool_mutex_exit(); + buf_flush_wait_batch_end(i); + buf_pool_mutex_enter(); + } + } + + buf_pool_mutex_exit(); ut_ad(buf_all_freed()); @@ -3302,6 +3327,14 @@ buf_pool_invalidate(void) ut_ad(UT_LIST_GET_LEN(buf_pool->LRU) == 0); ut_ad(UT_LIST_GET_LEN(buf_pool->unzip_LRU) == 0); + buf_pool->freed_page_clock = 0; + buf_pool->LRU_old = NULL; + buf_pool->LRU_old_len = 0; + buf_pool->LRU_flush_ended = 0; + + memset(&buf_pool->stat, 0x00, sizeof(buf_pool->stat)); + buf_refresh_io_stats(); + buf_pool_mutex_exit(); } diff --git a/storage/innodb_plugin/fsp/fsp0fsp.c b/storage/innodb_plugin/fsp/fsp0fsp.c index 9b4dca198c1..3cc4318fc06 100644 --- a/storage/innodb_plugin/fsp/fsp0fsp.c +++ b/storage/innodb_plugin/fsp/fsp0fsp.c @@ -1848,6 +1848,8 @@ fsp_seg_inode_page_find_used( if (!ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID))) { /* This is used */ + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); return(i); } } @@ -1879,6 +1881,9 @@ fsp_seg_inode_page_find_free( return(i); } + + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); } return(ULINT_UNDEFINED); @@ -1997,6 +2002,8 @@ fsp_alloc_seg_inode( page + FSEG_INODE_PAGE_NODE, mtr); } + ut_ad(ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID)) + || mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); return(inode); } @@ -2034,7 +2041,7 @@ fsp_free_seg_inode( } mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr); - mlog_write_ulint(inode + FSEG_MAGIC_N, 0, MLOG_4BYTES, mtr); + mlog_write_ulint(inode + FSEG_MAGIC_N, 0xfa051ce3, MLOG_4BYTES, mtr); if (ULINT_UNDEFINED == fsp_seg_inode_page_find_used(page, zip_size, mtr)) { @@ -2050,11 +2057,11 @@ fsp_free_seg_inode( /**********************************************************************//** Returns the file segment inode, page x-latched. -@return segment inode, page x-latched */ +@return segment inode, page x-latched; NULL if the inode is free */ static fseg_inode_t* -fseg_inode_get( -/*===========*/ +fseg_inode_try_get( +/*===============*/ fseg_header_t* header, /*!< in: segment header */ ulint space, /*!< in: space id */ ulint zip_size,/*!< in: compressed page size in bytes @@ -2070,8 +2077,34 @@ fseg_inode_get( inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr); - ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); + if (UNIV_UNLIKELY + (ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID)))) { + inode = NULL; + } else { + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); + } + + return(inode); +} + +/**********************************************************************//** +Returns the file segment inode, page x-latched. +@return segment inode, page x-latched */ +static +fseg_inode_t* +fseg_inode_get( +/*===========*/ + fseg_header_t* header, /*!< in: segment header */ + ulint space, /*!< in: space id */ + ulint zip_size,/*!< in: compressed page size in bytes + or 0 for uncompressed pages */ + mtr_t* mtr) /*!< in: mtr handle */ +{ + fseg_inode_t* inode + = fseg_inode_try_get(header, space, zip_size, mtr); + ut_a(inode); return(inode); } @@ -2089,6 +2122,7 @@ fseg_get_nth_frag_page_no( ut_ad(inode && mtr); ut_ad(n < FSEG_FRAG_ARR_N_SLOTS); ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX)); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); return(mach_read_from_4(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE)); } @@ -2107,6 +2141,7 @@ fseg_set_nth_frag_page_no( ut_ad(inode && mtr); ut_ad(n < FSEG_FRAG_ARR_N_SLOTS); ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX)); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE, page_no, MLOG_4BYTES, mtr); @@ -2467,6 +2502,8 @@ fseg_fill_free_list( xdes_set_state(descr, XDES_FSEG, mtr); seg_id = mtr_read_dulint(inode + FSEG_ID, mtr); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); mlog_write_dulint(descr + XDES_ID, seg_id, mtr); flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr); @@ -2495,6 +2532,7 @@ fseg_alloc_free_extent( fil_addr_t first; ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE)); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); if (flst_get_len(inode + FSEG_FREE, mtr) > 0) { /* Segment free list is not empty, allocate from it */ @@ -3152,6 +3190,8 @@ fseg_mark_page_used( ut_ad(seg_inode && mtr); ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE)); + ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); descr = xdes_get_descriptor(space, zip_size, page, mtr); @@ -3389,6 +3429,8 @@ fseg_free_extent( ut_a(xdes_get_state(descr, mtr) == XDES_FSEG); ut_a(0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, mtr), mtr_read_dulint(seg_inode + FSEG_ID, mtr))); + ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); first_page_in_extent = page - (page % FSP_EXTENT_SIZE); @@ -3479,7 +3521,13 @@ fseg_free_step( ut_a(descr); ut_a(xdes_get_bit(descr, XDES_FREE_BIT, header_page % FSP_EXTENT_SIZE, mtr) == FALSE); - inode = fseg_inode_get(header, space, zip_size, mtr); + inode = fseg_inode_try_get(header, space, zip_size, mtr); + + if (UNIV_UNLIKELY(inode == NULL)) { + fprintf(stderr, "double free of inode from %u:%u\n", + (unsigned) space, (unsigned) header_page); + return(TRUE); + } descr = fseg_get_first_extent(inode, space, zip_size, mtr); @@ -3603,6 +3651,7 @@ fseg_get_first_extent( ut_ad(inode && mtr); ut_ad(space == page_get_space_id(page_align(inode))); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); first = fil_addr_null; @@ -3817,6 +3866,7 @@ fseg_print_low( (ulong) reserved, (ulong) used, (ulong) n_full, (ulong) n_frag, (ulong) n_free, (ulong) n_not_full, (ulong) n_used); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); } #ifdef UNIV_BTR_PRINT diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 18d6adf7a92..8ac804ca9b6 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -3159,7 +3159,7 @@ retry: if (is_part) { sql_print_error("Failed to open table %s after " - "%lu attemtps.\n", norm_name, + "%lu attempts.\n", norm_name, retries); } @@ -5060,6 +5060,11 @@ ha_innobase::index_read( index = prebuilt->index; + if (UNIV_UNLIKELY(index == NULL)) { + prebuilt->index_usable = FALSE; + DBUG_RETURN(HA_ERR_CRASHED); + } + /* Note that if the index for which the search template is built is not necessarily prebuilt->index, but can also be the clustered index */ @@ -5219,6 +5224,7 @@ ha_innobase::change_active_index( if (UNIV_UNLIKELY(!prebuilt->index)) { sql_print_warning("InnoDB: change_active_index(%u) failed", keynr); + prebuilt->index_usable = FALSE; DBUG_RETURN(1); } diff --git a/storage/innodb_plugin/include/log0recv.h b/storage/innodb_plugin/include/log0recv.h index 8468c213bdb..6de735be945 100644 --- a/storage/innodb_plugin/include/log0recv.h +++ b/storage/innodb_plugin/include/log0recv.h @@ -433,6 +433,11 @@ are allowed yet: the variable name is misleading. */ extern ibool recv_no_ibuf_operations; /** TRUE when recv_init_crash_recovery() has been called. */ extern ibool recv_needed_recovery; +#ifdef UNIV_DEBUG +/** TRUE if writing to the redo log (mtr_commit) is forbidden. +Protected by log_sys->mutex. */ +extern ibool recv_no_log_write; +#endif /* UNIV_DEBUG */ /** TRUE if buf_page_is_corrupted() should check if the log sequence number (FIL_PAGE_LSN) is in the future. Initially FALSE, and set by diff --git a/storage/innodb_plugin/include/page0page.h b/storage/innodb_plugin/include/page0page.h index a4fe069d022..3899499fb6a 100644 --- a/storage/innodb_plugin/include/page0page.h +++ b/storage/innodb_plugin/include/page0page.h @@ -76,8 +76,11 @@ typedef byte page_header_t; header which are set in a page create */ /*----*/ #define PAGE_LEVEL 26 /* level of the node in an index tree; the - leaf level is the level 0 */ -#define PAGE_INDEX_ID 28 /* index id where the page belongs */ + leaf level is the level 0. This field should + not be written to after page creation. */ +#define PAGE_INDEX_ID 28 /* index id where the page belongs. + This field should not be written to after + page creation. */ #define PAGE_BTR_SEG_LEAF 36 /* file segment header for the leaf pages in a B-tree: defined only on the root page of a B-tree, but not in the root of an ibuf tree */ diff --git a/storage/innodb_plugin/include/page0zip.h b/storage/innodb_plugin/include/page0zip.h index 9aaa066306b..574809e5227 100644 --- a/storage/innodb_plugin/include/page0zip.h +++ b/storage/innodb_plugin/include/page0zip.h @@ -127,8 +127,12 @@ page_zip_decompress( /*================*/ page_zip_des_t* page_zip,/*!< in: data, ssize; out: m_start, m_end, m_nonempty, n_blobs */ - page_t* page) /*!< out: uncompressed page, may be trashed */ - __attribute__((nonnull)); + page_t* page, /*!< out: uncompressed page, may be trashed */ + ibool all) /*!< in: TRUE=decompress the whole page; + FALSE=verify but do not copy some + page header fields that should not change + after page creation */ + __attribute__((nonnull(1,2))); #ifdef UNIV_DEBUG /**********************************************************************//** @@ -385,8 +389,8 @@ IMPORTANT: if page_zip_reorganize() is invoked on a leaf page of a non-clustered index, the caller must update the insert buffer free bits in the same mini-transaction in such a way that the modification will be redo-logged. -@return TRUE on success, FALSE on failure; page and page_zip will be -left intact on failure. */ +@return TRUE on success, FALSE on failure; page_zip will be left +intact on failure, but page will be overwritten. */ UNIV_INTERN ibool page_zip_reorganize( diff --git a/storage/innodb_plugin/include/row0ins.h b/storage/innodb_plugin/include/row0ins.h index 530622e6225..9f93565ddb7 100644 --- a/storage/innodb_plugin/include/row0ins.h +++ b/storage/innodb_plugin/include/row0ins.h @@ -45,7 +45,7 @@ row_ins_check_foreign_constraint( /*=============================*/ ibool check_ref,/*!< in: TRUE If we want to check that the referenced table is ok, FALSE if we - want to to check the foreign key table */ + want to check the foreign key table */ dict_foreign_t* foreign,/*!< in: foreign constraint; NOTE that the tables mentioned in it must be in the dictionary cache if they exist at all */ diff --git a/storage/innodb_plugin/lock/lock0lock.c b/storage/innodb_plugin/lock/lock0lock.c index 20d444af3f4..67b2eac7219 100644 --- a/storage/innodb_plugin/lock/lock0lock.c +++ b/storage/innodb_plugin/lock/lock0lock.c @@ -4633,6 +4633,10 @@ lock_rec_queue_validate( next function call: we have to release lock table mutex to obey the latching order */ + /* If this thread is holding the file space latch + (fil_space_t::latch), the following check WILL break + latching order and may cause a deadlock of threads. */ + impl_trx = lock_sec_rec_some_has_impl_off_kernel( rec, index, offsets); @@ -4756,6 +4760,11 @@ loop: lock_mutex_exit_kernel(); + /* If this thread is holding the file space + latch (fil_space_t::latch), the following + check WILL break the latching order and may + cause a deadlock of threads. */ + lock_rec_queue_validate(block, rec, index, offsets); lock_mutex_enter_kernel(); diff --git a/storage/innodb_plugin/log/log0log.c b/storage/innodb_plugin/log/log0log.c index 85de72bb768..a23dd20772a 100644 --- a/storage/innodb_plugin/log/log0log.c +++ b/storage/innodb_plugin/log/log0log.c @@ -241,6 +241,7 @@ log_reserve_and_open( ut_a(len < log->buf_size / 2); loop: mutex_enter(&(log->mutex)); + ut_ad(!recv_no_log_write); /* Calculate an upper limit for the space the string may take in the log buffer */ @@ -309,6 +310,7 @@ log_write_low( ut_ad(mutex_own(&(log->mutex))); part_loop: + ut_ad(!recv_no_log_write); /* Calculate a part length */ data_len = (log->buf_free % OS_FILE_LOG_BLOCK_SIZE) + str_len; @@ -377,6 +379,7 @@ log_close(void) ib_uint64_t checkpoint_age; ut_ad(mutex_own(&(log->mutex))); + ut_ad(!recv_no_log_write); lsn = log->lsn; @@ -668,8 +671,6 @@ log_calc_max_ages(void) ulint archive_margin; ulint smallest_archive_margin; - ut_ad(!mutex_own(&(log_sys->mutex))); - mutex_enter(&(log_sys->mutex)); group = UT_LIST_GET_FIRST(log_sys->log_groups); @@ -1117,6 +1118,7 @@ log_io_complete( } mutex_enter(&(log_sys->mutex)); + ut_ad(!recv_no_log_write); ut_a(group->n_pending_writes > 0); ut_a(log_sys->n_pending_writes > 0); @@ -1148,6 +1150,7 @@ log_group_file_header_flush( ulint dest_offset; ut_ad(mutex_own(&(log_sys->mutex))); + ut_ad(!recv_no_log_write); ut_a(nth_file < group->n_files); buf = *(group->file_header_bufs + nth_file); @@ -1219,6 +1222,7 @@ log_group_write_buf( ulint i; ut_ad(mutex_own(&(log_sys->mutex))); + ut_ad(!recv_no_log_write); ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0); ut_a(((ulint) start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); @@ -1361,6 +1365,7 @@ loop: #endif mutex_enter(&(log_sys->mutex)); + ut_ad(!recv_no_log_write); if (flush_to_disk && log_sys->flushed_to_disk_lsn >= lsn) { @@ -1974,6 +1979,7 @@ log_checkpoint( mutex_enter(&(log_sys->mutex)); + ut_ad(!recv_no_log_write); oldest_lsn = log_buf_pool_get_oldest_modification(); mutex_exit(&(log_sys->mutex)); @@ -2086,6 +2092,7 @@ loop: do_checkpoint = FALSE; mutex_enter(&(log->mutex)); + ut_ad(!recv_no_log_write); if (log->check_flush_or_checkpoint == FALSE) { mutex_exit(&(log->mutex)); @@ -3035,6 +3042,7 @@ loop: #endif /* UNIV_LOG_ARCHIVE */ mutex_enter(&(log_sys->mutex)); + ut_ad(!recv_no_log_write); if (log_sys->check_flush_or_checkpoint) { diff --git a/storage/innodb_plugin/log/log0recv.c b/storage/innodb_plugin/log/log0recv.c index 2e4f14beccb..81dcc9cd4f8 100644 --- a/storage/innodb_plugin/log/log0recv.c +++ b/storage/innodb_plugin/log/log0recv.c @@ -78,6 +78,11 @@ UNIV_INTERN ibool recv_recovery_from_backup_on = FALSE; #ifndef UNIV_HOTBACKUP /** TRUE when recv_init_crash_recovery() has been called. */ UNIV_INTERN ibool recv_needed_recovery = FALSE; +# ifdef UNIV_DEBUG +/** TRUE if writing to the redo log (mtr_commit) is forbidden. +Protected by log_sys->mutex. */ +UNIV_INTERN ibool recv_no_log_write = FALSE; +# endif /* UNIV_DEBUG */ /** TRUE if buf_page_is_corrupted() should check if the log sequence number (FIL_PAGE_LSN) is in the future. Initially FALSE, and set by @@ -1705,6 +1710,7 @@ loop: /* Flush all the file pages to disk and invalidate them in the buffer pool */ + ut_d(recv_no_log_write = TRUE); mutex_exit(&(recv_sys->mutex)); mutex_exit(&(log_sys->mutex)); @@ -1718,6 +1724,7 @@ loop: mutex_enter(&(log_sys->mutex)); mutex_enter(&(recv_sys->mutex)); + ut_d(recv_no_log_write = FALSE); recv_no_ibuf_operations = FALSE; } diff --git a/storage/innodb_plugin/mtr/mtr0mtr.c b/storage/innodb_plugin/mtr/mtr0mtr.c index 0c4bec8c82c..417e97732bb 100644 --- a/storage/innodb_plugin/mtr/mtr0mtr.c +++ b/storage/innodb_plugin/mtr/mtr0mtr.c @@ -35,6 +35,7 @@ Created 11/26/1995 Heikki Tuuri #include "log0log.h" #ifndef UNIV_HOTBACKUP +# include "log0recv.h" /*****************************************************************//** Releases the item in the slot given. */ UNIV_INLINE @@ -181,6 +182,8 @@ mtr_commit( ut_d(mtr->state = MTR_COMMITTING); #ifndef UNIV_HOTBACKUP + /* This is a dirty read, for debugging. */ + ut_ad(!recv_no_log_write); write_log = mtr->modifications && mtr->n_log_recs; if (write_log) { diff --git a/storage/innodb_plugin/page/page0cur.c b/storage/innodb_plugin/page/page0cur.c index 65f3ba67439..f10f16a7dd9 100644 --- a/storage/innodb_plugin/page/page0cur.c +++ b/storage/innodb_plugin/page/page0cur.c @@ -1195,7 +1195,7 @@ page_cur_insert_rec_zip_reorg( } /* Out of space: restore the page */ - if (!page_zip_decompress(page_zip, page)) { + if (!page_zip_decompress(page_zip, page, FALSE)) { ut_error; /* Memory corrupted? */ } ut_ad(page_validate(page, index)); diff --git a/storage/innodb_plugin/page/page0page.c b/storage/innodb_plugin/page/page0page.c index b771bf4ded9..ab2ba60570e 100644 --- a/storage/innodb_plugin/page/page0page.c +++ b/storage/innodb_plugin/page/page0page.c @@ -679,7 +679,7 @@ page_copy_rec_list_end( if (UNIV_UNLIKELY (!page_zip_decompress(new_page_zip, - new_page))) { + new_page, FALSE))) { ut_error; } ut_ad(page_validate(new_page, index)); @@ -792,7 +792,7 @@ page_copy_rec_list_start( if (UNIV_UNLIKELY (!page_zip_decompress(new_page_zip, - new_page))) { + new_page, FALSE))) { ut_error; } ut_ad(page_validate(new_page, index)); diff --git a/storage/innodb_plugin/page/page0zip.c b/storage/innodb_plugin/page/page0zip.c index e170adce30a..aa5e39ff04a 100644 --- a/storage/innodb_plugin/page/page0zip.c +++ b/storage/innodb_plugin/page/page0zip.c @@ -2821,7 +2821,11 @@ page_zip_decompress( /*================*/ page_zip_des_t* page_zip,/*!< in: data, ssize; out: m_start, m_end, m_nonempty, n_blobs */ - page_t* page) /*!< out: uncompressed page, may be trashed */ + page_t* page, /*!< out: uncompressed page, may be trashed */ + ibool all) /*!< in: TRUE=decompress the whole page; + FALSE=verify but do not copy some + page header fields that should not change + after page creation */ { z_stream d_stream; dict_index_t* index = NULL; @@ -2851,13 +2855,36 @@ page_zip_decompress( heap = mem_heap_create(n_dense * (3 * sizeof *recs) + UNIV_PAGE_SIZE); recs = mem_heap_alloc(heap, n_dense * (2 * sizeof *recs)); + if (all) { + /* Copy the page header. */ + memcpy(page, page_zip->data, PAGE_DATA); + } else { + /* Check that the bytes that we skip are identical. */ +#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG + ut_a(!memcmp(FIL_PAGE_TYPE + page, + FIL_PAGE_TYPE + page_zip->data, + PAGE_HEADER - FIL_PAGE_TYPE)); + ut_a(!memcmp(PAGE_HEADER + PAGE_LEVEL + page, + PAGE_HEADER + PAGE_LEVEL + page_zip->data, + PAGE_DATA - (PAGE_HEADER + PAGE_LEVEL))); +#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */ + + /* Copy the mutable parts of the page header. */ + memcpy(page, page_zip->data, FIL_PAGE_TYPE); + memcpy(PAGE_HEADER + page, PAGE_HEADER + page_zip->data, + PAGE_LEVEL - PAGE_N_DIR_SLOTS); + +#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG + /* Check that the page headers match after copying. */ + ut_a(!memcmp(page, page_zip->data, PAGE_DATA)); +#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */ + } + #ifdef UNIV_ZIP_DEBUG - /* Clear the page. */ - memset(page, 0x55, UNIV_PAGE_SIZE); + /* Clear the uncompressed page, except the header. */ + memset(PAGE_DATA + page, 0x55, UNIV_PAGE_SIZE - PAGE_DATA); #endif /* UNIV_ZIP_DEBUG */ - UNIV_MEM_INVALID(page, UNIV_PAGE_SIZE); - /* Copy the page header. */ - memcpy(page, page_zip->data, PAGE_DATA); + UNIV_MEM_INVALID(PAGE_DATA + page, UNIV_PAGE_SIZE - PAGE_DATA); /* Copy the page directory. */ if (UNIV_UNLIKELY(!page_zip_dir_decode(page_zip, page, recs, @@ -3098,7 +3125,7 @@ page_zip_validate_low( #endif /* UNIV_DEBUG_VALGRIND */ temp_page_zip = *page_zip; - valid = page_zip_decompress(&temp_page_zip, temp_page); + valid = page_zip_decompress(&temp_page_zip, temp_page, TRUE); if (!valid) { fputs("page_zip_validate(): failed to decompress\n", stderr); goto func_exit; @@ -4376,8 +4403,8 @@ IMPORTANT: if page_zip_reorganize() is invoked on a leaf page of a non-clustered index, the caller must update the insert buffer free bits in the same mini-transaction in such a way that the modification will be redo-logged. -@return TRUE on success, FALSE on failure; page and page_zip will be -left intact on failure. */ +@return TRUE on success, FALSE on failure; page_zip will be left +intact on failure, but page will be overwritten. */ UNIV_INTERN ibool page_zip_reorganize( @@ -4442,9 +4469,6 @@ page_zip_reorganize( if (UNIV_UNLIKELY(!page_zip_compress(page_zip, page, index, mtr))) { - /* Restore the old page and exit. */ - buf_frame_copy(page, temp_page); - #ifndef UNIV_HOTBACKUP buf_block_free(temp_block); #endif /* !UNIV_HOTBACKUP */ @@ -4605,7 +4629,8 @@ corrupt: memcpy(page_zip->data + page_zip_get_size(page_zip) - trailer_size, ptr + 8 + size, trailer_size); - if (UNIV_UNLIKELY(!page_zip_decompress(page_zip, page))) { + if (UNIV_UNLIKELY(!page_zip_decompress(page_zip, page, + TRUE))) { goto corrupt; } diff --git a/storage/innodb_plugin/row/row0ins.c b/storage/innodb_plugin/row/row0ins.c index 930c9ec1fc7..ab3ae70e3e2 100644 --- a/storage/innodb_plugin/row/row0ins.c +++ b/storage/innodb_plugin/row/row0ins.c @@ -1191,7 +1191,7 @@ row_ins_check_foreign_constraint( /*=============================*/ ibool check_ref,/*!< in: TRUE if we want to check that the referenced table is ok, FALSE if we - want to to check the foreign key table */ + want to check the foreign key table */ dict_foreign_t* foreign,/*!< in: foreign constraint; NOTE that the tables mentioned in it must be in the dictionary cache if they exist at all */ diff --git a/storage/innodb_plugin/row/row0merge.c b/storage/innodb_plugin/row/row0merge.c index a968fe80864..a303a2f3278 100644 --- a/storage/innodb_plugin/row/row0merge.c +++ b/storage/innodb_plugin/row/row0merge.c @@ -1947,7 +1947,15 @@ row_merge_drop_index( static const char str1[] = "PROCEDURE DROP_INDEX_PROC () IS\n" "BEGIN\n" + /* Rename the index, so that it will be dropped by + row_merge_drop_temp_indexes() at crash recovery + if the server crashes before this trx is committed. */ + "UPDATE SYS_INDEXES SET NAME=CONCAT('" + TEMP_INDEX_PREFIX_STR "', NAME) WHERE ID = :indexid;\n" + "COMMIT WORK;\n" + /* Drop the field definitions of the index. */ "DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n" + /* Drop the index definition and the B-tree. */ "DELETE FROM SYS_INDEXES WHERE ID = :indexid\n" " AND TABLE_ID = :tableid;\n" "END;\n"; diff --git a/storage/innodb_plugin/trx/trx0trx.c b/storage/innodb_plugin/trx/trx0trx.c index 1e36a2e4fe7..21ba6e481a7 100644 --- a/storage/innodb_plugin/trx/trx0trx.c +++ b/storage/innodb_plugin/trx/trx0trx.c @@ -803,7 +803,7 @@ trx_commit_off_kernel( in exactly the same order as commit lsn's, if the transactions have different rollback segments. To get exactly the same order we should hold the kernel mutex up to this point, - adding to to the contention of the kernel mutex. However, if + adding to the contention of the kernel mutex. However, if a transaction T2 is able to see modifications made by a transaction T1, T2 will always get a bigger transaction number and a bigger commit lsn than T1. */ From 858713edd376ccb7eaf4826732869be8e71d0190 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Fri, 9 Oct 2009 21:16:29 +0500 Subject: [PATCH 114/146] BUG#47073 - valgrind errs, corruption,failed repair of partition, low myisam_sort_buffer_size Repair by sort (default) or parallel repair of a MyISAM table (doesn't matter partitioned or not) as well as bulk inserts and enable indexes some times didn't failover to repair with key cache. The problem was that after unsuccessful attempt, data file was closed. Whereas repair with key cache requires open data file. Fixed by reopening data file. Also fixed a valgrind warning, which may appear during repair by sort or parallel repair with certain myisam_sort_buffer_size number of rows and length of an index entry (very dependent). --- mysql-test/r/myisam.result | 28 ++++++++++++++++++++++++++++ mysql-test/t/myisam.test | 28 ++++++++++++++++++++++++++++ storage/myisam/ha_myisam.cc | 16 ---------------- storage/myisam/mi_check.c | 10 ++++++---- storage/myisam/sort.c | 4 ++++ 5 files changed, 66 insertions(+), 20 deletions(-) diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 58e2e451a0d..df97e96c334 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -2271,4 +2271,32 @@ checksum table t3; Table Checksum test.t3 326284887 drop table t1,t2,t3; +CREATE TABLE t1(a INT, b CHAR(10), KEY(a), KEY(b)); +INSERT INTO t1 VALUES(1,'0'),(2,'0'),(3,'0'),(4,'0'),(5,'0'), +(6,'0'),(7,'0'); +INSERT INTO t1 SELECT a+10,b FROM t1; +INSERT INTO t1 SELECT a+20,b FROM t1; +INSERT INTO t1 SELECT a+40,b FROM t1; +INSERT INTO t1 SELECT a+80,b FROM t1; +INSERT INTO t1 SELECT a+160,b FROM t1; +INSERT INTO t1 SELECT a+320,b FROM t1; +INSERT INTO t1 SELECT a+640,b FROM t1; +INSERT INTO t1 SELECT a+1280,b FROM t1; +INSERT INTO t1 SELECT a+2560,b FROM t1; +INSERT INTO t1 SELECT a+5120,b FROM t1; +SET myisam_sort_buffer_size=4; +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair error myisam_sort_buffer_size is too small +test.t1 repair warning Number of rows changed from 0 to 7168 +test.t1 repair status OK +SET myisam_repair_threads=2; +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair error myisam_sort_buffer_size is too small +test.t1 repair warning Number of rows changed from # to 7168 +test.t1 repair status OK +SET myisam_repair_threads=@@global.myisam_repair_threads; +SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size; +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 5de7c997a24..faeb5ee686a 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -1518,5 +1518,33 @@ CREATE TABLE t3 select * from t1; checksum table t3; drop table t1,t2,t3; + +# +# BUG#47073 - valgrind errs, corruption,failed repair of partition, +# low myisam_sort_buffer_size +# +CREATE TABLE t1(a INT, b CHAR(10), KEY(a), KEY(b)); +INSERT INTO t1 VALUES(1,'0'),(2,'0'),(3,'0'),(4,'0'),(5,'0'), + (6,'0'),(7,'0'); +INSERT INTO t1 SELECT a+10,b FROM t1; +INSERT INTO t1 SELECT a+20,b FROM t1; +INSERT INTO t1 SELECT a+40,b FROM t1; +INSERT INTO t1 SELECT a+80,b FROM t1; +INSERT INTO t1 SELECT a+160,b FROM t1; +INSERT INTO t1 SELECT a+320,b FROM t1; +INSERT INTO t1 SELECT a+640,b FROM t1; +INSERT INTO t1 SELECT a+1280,b FROM t1; +INSERT INTO t1 SELECT a+2560,b FROM t1; +INSERT INTO t1 SELECT a+5120,b FROM t1; +SET myisam_sort_buffer_size=4; +REPAIR TABLE t1; +SET myisam_repair_threads=2; +# May report different values depending on threads activity. +--replace_regex /changed from [0-9]+/changed from #/ +REPAIR TABLE t1; +SET myisam_repair_threads=@@global.myisam_repair_threads; +SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size; +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 5198e685817..aa9a2eeb77a 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -1087,22 +1087,6 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_optimize) ha_rows rows= file->state->records; DBUG_ENTER("ha_myisam::repair"); - /* - Normally this method is entered with a properly opened table. If the - repair fails, it can be repeated with more elaborate options. Under - special circumstances it can happen that a repair fails so that it - closed the data file and cannot re-open it. In this case file->dfile - is set to -1. We must not try another repair without an open data - file. (Bug #25289) - */ - if (file->dfile == -1) - { - sql_print_information("Retrying repair of: '%s' failed. " - "Please try REPAIR EXTENDED or myisamchk", - table->s->path.str); - DBUG_RETURN(HA_ADMIN_FAILED); - } - param.db_name= table->s->db.str; param.table_name= table->alias; param.tmpfile_createflag = O_RDWR | O_TRUNC; diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c index 1c33ffa90f5..8f7b1399aa2 100644 --- a/storage/myisam/mi_check.c +++ b/storage/myisam/mi_check.c @@ -2561,8 +2561,9 @@ err: VOID(my_close(new_file,MYF(0))); VOID(my_raid_delete(param->temp_filename,share->base.raid_chunks, MYF(MY_WME))); - if (info->dfile == new_file) - info->dfile= -1; + if (info->dfile == new_file) /* Retry with key cache */ + if (unlikely(mi_open_datafile(info, share, name, -1))) + param->retry_repair= 0; /* Safety */ } mi_mark_crashed_on_repair(info); } @@ -3095,8 +3096,9 @@ err: VOID(my_close(new_file,MYF(0))); VOID(my_raid_delete(param->temp_filename,share->base.raid_chunks, MYF(MY_WME))); - if (info->dfile == new_file) - info->dfile= -1; + if (info->dfile == new_file) /* Retry with key cache */ + if (unlikely(mi_open_datafile(info, share, name, -1))) + param->retry_repair= 0; /* Safety */ } mi_mark_crashed_on_repair(info); } diff --git a/storage/myisam/sort.c b/storage/myisam/sort.c index f31edbe1249..fb16af9cddf 100644 --- a/storage/myisam/sort.c +++ b/storage/myisam/sort.c @@ -788,7 +788,11 @@ static int NEAR_F merge_many_buff(MI_SORT_PARAM *info, uint keys, cleanup: close_cached_file(to_file); /* This holds old result */ if (to_file == t_file) + { *t_file=t_file2; /* Copy result file */ + t_file->current_pos= &t_file->write_pos; + t_file->current_end= &t_file->write_end; + } DBUG_RETURN(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */ } /* merge_many_buff */ From 0f1547a0ab09b6e470d2b9f690015a99c6b7c682 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Fri, 9 Oct 2009 21:31:37 +0200 Subject: [PATCH 115/146] Fix Bug #47957 A build "--without-server" fails if using "--with-ssl" (YaSSL) The problem was the lack of directory "extra" in a build which did not include the server. --- configure.in | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/configure.in b/configure.in index 3e43a5f5779..82335e2c3fd 100644 --- a/configure.in +++ b/configure.in @@ -2769,7 +2769,7 @@ server_scripts= dnl This probably should be cleaned up more - for now the threaded dnl client is just using plain-old libs. -sql_client_dirs="strings regex mysys dbug libmysql" +sql_client_dirs="strings mysys dbug extra regex libmysql" AM_CONDITIONAL(THREAD_SAFE_CLIENT, test "$THREAD_SAFE_CLIENT" != "no") @@ -2835,9 +2835,10 @@ AC_SUBST(mysql_plugin_defs) # Now that sql_client_dirs and sql_server_dirs are stable, determine the union. -# Start with the (longer) server list, add each client item not yet present. -sql_union_dirs=" $sql_server_dirs " -for DIR in $sql_client_dirs +# We support client-only builds by "--without-server", but not vice versa, +# so we start with the client list, then add each server item not yet present. +sql_union_dirs=" $sql_client_dirs " +for DIR in $sql_server_dirs do if echo " $sql_union_dirs " | grep " $DIR " >/dev/null then From 3b02f76aaf17d423f70cb817a601ff61bdbea024 Mon Sep 17 00:00:00 2001 From: V Narayanan Date: Mon, 12 Oct 2009 13:13:15 +0530 Subject: [PATCH 116/146] Bug#46448 trailing spaces are not ignored when user collation maps space != 0x20 In MySQL when the mapping for space is changed to something other than 0x20 by defining a different collation, then space is not ignored when comparing two strings. This was happening because the function that performs the comparison of two strings while ignoring ending spaces, was comparing the collation value of a space with the ascii value of the ' ' character. This should be changed to do comparison between the collated values. --- mysql-test/r/ctype_ldml.result | 8 ++ mysql-test/std_data/Index.xml | 13 ++++ mysql-test/std_data/latin1.xml | 135 +++++++++++++++++++++++++++++++++ mysql-test/t/ctype_ldml.test | 5 ++ strings/ctype-simple.c | 4 +- 5 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 mysql-test/std_data/latin1.xml diff --git a/mysql-test/r/ctype_ldml.result b/mysql-test/r/ctype_ldml.result index 711921eb526..fe870f82743 100644 --- a/mysql-test/r/ctype_ldml.result +++ b/mysql-test/r/ctype_ldml.result @@ -321,3 +321,11 @@ Vv Xx Yy脻媒峄册怀峄瘁坏峄夺环峄羔还 drop table t1; +Bug#46448 trailing spaces are not ignored when user collation maps space != 0x20 +set names latin1; +show collation like 'latin1_test'; +Collation Charset Id Default Compiled Sortlen +latin1_test latin1 99 Yes 1 +select "foo" = "foo " collate latin1_test; +"foo" = "foo " collate latin1_test +1 diff --git a/mysql-test/std_data/Index.xml b/mysql-test/std_data/Index.xml index 988dddcc68a..3dc647d8195 100644 --- a/mysql-test/std_data/Index.xml +++ b/mysql-test/std_data/Index.xml @@ -68,4 +68,17 @@ + + Western + cp1252 West European + csisolatin1 + iso-8859-1 + iso-ir-100 + iso_8859-1 + iso_8859-1:1987 + l1 + latin1 + + + diff --git a/mysql-test/std_data/latin1.xml b/mysql-test/std_data/latin1.xml new file mode 100644 index 00000000000..42b4342c1ae --- /dev/null +++ b/mysql-test/std_data/latin1.xml @@ -0,0 +1,135 @@ + + + + + + Copyright (C) 2003 MySQL AB + + 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 Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + + + + + 00 + 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20 + 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 + 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10 + 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10 + 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20 + 10 00 10 02 10 10 10 10 10 10 01 10 01 00 01 00 + 00 10 10 10 10 10 10 10 10 10 02 10 02 00 02 01 + 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 + 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 02 + + + + + + + 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F + 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F + 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F + 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F + 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F + 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F + 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F + 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F + 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F + 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F + A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF + B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF + + + + + + + 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F + 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F + 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F + 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F + 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F + 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F + 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F + 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F + 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F + 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F + A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF + B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF + + + + + + + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 20AC 0081 201A 0192 201E 2026 2020 2021 02C6 2030 0160 2039 0152 008D 017D 008F + 0090 2018 2019 201C 201D 2022 2013 2014 02DC 2122 0161 203A 0153 009D 017E 0178 + 00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF + 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF + 00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF + 00D0 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF + 00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF + 00F0 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 00FD 00FE 00FF + + + + + + 00 01 02 03 37 2D 2E 2F 16 05 25 0B 0C 0D 0E 0F + 10 11 12 13 3C 3D 32 26 18 19 3F 27 1C 1D 1E 1F + 40 4F 7F 7B 5B 6C 50 7D 4D 5D 5C 4E 6B 60 4B 61 + F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 7A 5E 4C 7E 6E 6F + 7C C1 C2 C3 C4 C5 C6 C7 C8 C9 D1 D2 D3 D4 D5 D6 + D7 D8 D9 E2 E3 E4 E5 E6 E7 E8 E9 4A E0 5A 5F 6D + 79 81 82 83 84 85 86 87 88 89 91 92 93 94 95 96 + 97 98 99 A2 A3 A4 A5 A6 A7 A8 A9 C0 6A D0 A1 07 + 20 21 22 23 24 15 06 17 28 29 2A 2B 2C 09 0A 1B + 30 31 1A 33 34 35 36 08 38 39 3A 3B 04 14 3E E1 + 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 + 58 59 62 63 64 65 66 67 68 69 70 71 72 73 74 75 + 76 77 78 80 8A 8B 8C 8D 8E 8F 90 9A 9B 9C 9D 9E + 9F A0 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 + B8 B9 BA BB BC BD BE BF CA CB CC CD CE CF DA DB + DC DD DE DF EA EB EC ED EE EF FA FB FC FD FE FF + + + + + + diff --git a/mysql-test/t/ctype_ldml.test b/mysql-test/t/ctype_ldml.test index db9461bfbf7..bc04b93a935 100644 --- a/mysql-test/t/ctype_ldml.test +++ b/mysql-test/t/ctype_ldml.test @@ -86,3 +86,8 @@ select hex(c1) as h, c1 from t1 order by c1, h; select group_concat(hex(c1) order by hex(c1)) from t1 group by c1; select group_concat(c1 order by hex(c1) SEPARATOR '') from t1 group by c1; drop table t1; + +--echo Bug#46448 trailing spaces are not ignored when user collation maps space != 0x20 +set names latin1; +show collation like 'latin1_test'; +select "foo" = "foo " collate latin1_test; diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 7de00025eda..4f3aaa6f668 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -185,8 +185,8 @@ int my_strnncollsp_simple(CHARSET_INFO * cs, const uchar *a, size_t a_length, } for (end= a + a_length-length; a < end ; a++) { - if (map[*a] != ' ') - return (map[*a] < ' ') ? -swap : swap; + if (map[*a] != map[' ']) + return (map[*a] < map[' ']) ? -swap : swap; } } return res; From db4e61acd41bf95bbb66c041db78196eca160088 Mon Sep 17 00:00:00 2001 From: V Narayanan Date: Mon, 12 Oct 2009 15:05:40 +0530 Subject: [PATCH 117/146] Bug#46448 trailing spaces are not ignored when user collation maps space != 0x20 Fixing copyright header in test collation file. --- mysql-test/std_data/latin1.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/std_data/latin1.xml b/mysql-test/std_data/latin1.xml index 42b4342c1ae..a2dab731656 100644 --- a/mysql-test/std_data/latin1.xml +++ b/mysql-test/std_data/latin1.xml @@ -3,7 +3,7 @@ - Copyright (C) 2003 MySQL AB + Copyright (C) 2008 Sun Microsystems, Inc 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 From 7ad93d9b2ca5af173a983d5e6d93f1590db48fba Mon Sep 17 00:00:00 2001 From: V Narayanan Date: Mon, 12 Oct 2009 15:25:59 +0530 Subject: [PATCH 118/146] Bug#46448 trailing spaces are not ignored when user collation maps space != 0x20 changing year in copyright header to 2009. --- mysql-test/std_data/latin1.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/std_data/latin1.xml b/mysql-test/std_data/latin1.xml index a2dab731656..458b1c34da1 100644 --- a/mysql-test/std_data/latin1.xml +++ b/mysql-test/std_data/latin1.xml @@ -3,7 +3,7 @@ - Copyright (C) 2008 Sun Microsystems, Inc + Copyright (C) 2009 Sun Microsystems, Inc 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 From d0c28265aeeb26feb8e34a2e3ae1ed42f6774f87 Mon Sep 17 00:00:00 2001 From: Satya B Date: Mon, 12 Oct 2009 17:30:56 +0530 Subject: [PATCH 119/146] Applying InnoDB Plugin 1.0.5 snapshot, part 13 1. Undo r6031 btr/btr0btr.c changes 2. apply skipped Plug.in changes and missed revisions Detailed revision comments: r5865 | vasil | 2009-09-12 02:26:03 -0500 (Sat, 12 Sep 2009) | 10 lines branches/zip: Simplify the compile time checks by splittig them into 5 independent checks: * Whether GCC atomics are available * Whether pthread_t can be used by GCC atomics * Whether Solaris libc atomics are available * Whether pthread_t can be used by Solaris libs atomics * Checking the size of pthread_t r5869 | vasil | 2009-09-12 03:33:11 -0500 (Sat, 12 Sep 2009) | 15 lines branches/zip: Include ut0auxconf.h only if none of the macros it would define is defined. The check when to include this header was outdated from the time when there was only one macro involved. Move the atomics checks that are in univ.i outside of #if windows ... #else ... #endif This simplifies the code and removes some duplicates like defining HAVE_ATOMIC_BUILTINS if HAVE_WINDOWS_ATOMICS is defined in both branches. Do not define the same macro HAVE_ATOMIC_PTHREAD_T for different events. Instead define HAVE_IB_ATOMIC_PTHREAD_T_GCC and HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS. r5871 | vasil | 2009-09-12 04:25:44 -0500 (Sat, 12 Sep 2009) | 6 lines branches/zip: Rename HAVE_SOLARIS_ATOMICS to HAVE_IB_SOLARIS_ATOMICS and IB_HAVE_PAUSE_INSTRUCTION to HAVE_IB_PAUSE_INSTRUCTION so they all follow the same HAVE_IB_* convention. r5888 | vasil | 2009-09-14 03:38:45 -0500 (Mon, 14 Sep 2009) | 40 lines branches/zip: Back-merge c5880 and c5881 from branches/embedded-1.0: ------------------------------------------------------------------------ r5880 | vasil | 2009-09-12 17:28:44 +0300 (Sat, 12 Sep 2009) | 18 lines Changed paths: M /branches/embedded-1.0/configure.in M /branches/embedded-1.0/include/os0sync.h M /branches/embedded-1.0/srv/srv0start.c branches/embedded-1.0: Clean up and simplify the code that surrounds the atomic ops: * Simplify the code that prints what atomics are used: Instead of repeating the same conditions on which each atomics are used use just one printf that prints a variable defined by the code which chooses what atomics to use. * In os0sync.h pick up each atomic variant only if it has been selected by autoconf (based on IB_ATOMIC_MODE_* macros). Define the startup message to be printed. * In configure.in: check what user has chosen and if he has chosen something that is not available, emit an error. If nothing has been chosen explicitly by the user, auto select an option according to the described logic in configure.in. ------------------------------------------------------------------------ r5881 | vasil | 2009-09-12 20:08:27 +0300 (Sat, 12 Sep 2009) | 4 lines Changed paths: M /branches/embedded-1.0/configure.in branches/embedded-1.0: Fix syntax error in test program. ------------------------------------------------------------------------ r5889 | vasil | 2009-09-14 04:17:18 -0500 (Mon, 14 Sep 2009) | 5 lines branches/zip: Add missing return statement in the test program that could have caused a warning. r5893 | inaam | 2009-09-14 10:20:48 -0500 (Mon, 14 Sep 2009) | 10 lines branches/zip rb://159 In case of pages that are not made young the counter is incremented only when the page in question is 'old'. In case of pages that are made young the counter is incremented in case of all pages. For apple to apple comparison this patch changes the 'young-making' counter to consider only 'old' blocks. Approved by: Marko r5537 | vasil | 2009-07-21 04:31:26 -0500 (Tue, 21 Jul 2009) | 5 lines branches/zip: Fixups in ChangeLog: sort filenames alphabetically and wrap to 78 chars per line. r5870 | vasil | 2009-09-12 04:13:44 -0500 (Sat, 12 Sep 2009) | 7 lines branches/zip: Define HAVE_ATOMIC_BUILTINS and INNODB_RW_LOCKS_USE_ATOMICS in os0sync.h instead of in univ.i. The code expects os_*() macros to be present if HAVE_ATOMIC_BUILTINS and INNODB_RW_LOCKS_USE_ATOMICS are defined. So define them next to defining the os_*() macros. r5696 | vasil | 2009-08-26 08:15:59 -0500 (Wed, 26 Aug 2009) | 14 lines branches/zip: Merge a change from MySQL: http://lists.mysql.com/commits/80832 2968 Jonathan Perkin 2009-08-14 Build fixes for Windows, AIX, HP/UX and Sun Studio11, from Timothy Smith. modified: CMakeLists.txt cmd-line-utils/readline/util.c storage/innodb_plugin/handler/i_s.cc storage/innodb_plugin/include/univ.i r5897 | marko | 2009-09-15 03:29:00 -0500 (Tue, 15 Sep 2009) | 8 lines branches/zip: Avoid bogus messages about latching order violations when UNIV_SYNC_DEBUG is defined. sync_thread_levels_g(): Add the parameter "warn". Do not print anything unless it is set. sync_thread_add_level(): Pass warn=TRUE to sync_thread_levels_g() when the check is within an assertion; FALSE if it is not. r5899 | marko | 2009-09-15 06:26:01 -0500 (Tue, 15 Sep 2009) | 4 lines branches/zip: ut0ut.h: Do not #include "os0sync.h" #ifdef UNIV_HOTBACKUP. Since r5872, the InnoDB Hot Backup build was broken. Fix it by not defining any thread synchronization primitives in ut0ut.h. InnoDB Hot Backup is a single-threaded program. --- storage/innodb_plugin/CMakeLists.txt | 29 +- storage/innodb_plugin/ChangeLog | 22 +- storage/innodb_plugin/btr/btr0btr.c | 3 - storage/innodb_plugin/buf/buf0lru.c | 5 +- storage/innodb_plugin/handler/handler0vars.h | 69 -- storage/innodb_plugin/handler/i_s.cc | 18 +- .../innodb_plugin/handler/win_delay_loader.cc | 1024 ----------------- storage/innodb_plugin/include/os0sync.h | 20 +- storage/innodb_plugin/include/univ.i | 3 +- storage/innodb_plugin/include/ut0ut.h | 6 +- storage/innodb_plugin/plug.in | 109 +- storage/innodb_plugin/srv/srv0start.c | 29 +- storage/innodb_plugin/sync/sync0sync.c | 70 +- .../ut/ut0auxconf_have_gcc_atomics.c | 61 - storage/innodb_plugin/ut/ut0auxconf_pause.c | 32 - storage/innodb_plugin/win-plugin/README | 22 - .../innodb_plugin/win-plugin/win-plugin.diff | 279 ----- 17 files changed, 173 insertions(+), 1628 deletions(-) delete mode 100644 storage/innodb_plugin/handler/handler0vars.h delete mode 100644 storage/innodb_plugin/handler/win_delay_loader.cc delete mode 100644 storage/innodb_plugin/win-plugin/README delete mode 100644 storage/innodb_plugin/win-plugin/win-plugin.diff diff --git a/storage/innodb_plugin/CMakeLists.txt b/storage/innodb_plugin/CMakeLists.txt index b86a3e7c8e1..1b05b5be6b9 100644 --- a/storage/innodb_plugin/CMakeLists.txt +++ b/storage/innodb_plugin/CMakeLists.txt @@ -42,10 +42,10 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include # Removing compiler optimizations for innodb/mem/* files on 64-bit Windows # due to 64-bit compiler error, See MySQL Bug #19424, #36366, #34297 -IF(MSVC AND $(WIN64)) +IF (MSVC AND $(WIN64)) SET_SOURCE_FILES_PROPERTIES(mem/mem0mem.c mem/mem0pool.c PROPERTIES COMPILE_FLAGS -Od) -ENDIF(MSVC AND $(WIN64)) +ENDIF (MSVC AND $(WIN64)) SET(INNODB_PLUGIN_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c buf/buf0buddy.c buf/buf0buf.c buf/buf0flu.c buf/buf0lru.c buf/buf0rea.c @@ -83,16 +83,17 @@ SET(INNODB_PLUGIN_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS -DINNODB_RW_LOCKS_USE_ATOMICS -DIB_HAVE_PAUSE_INSTRUCTION) MYSQL_STORAGE_ENGINE(INNODB_PLUGIN) IF (MYSQL_VERSION_ID GREATER "50137") - IF (WITH_INNOBASE_STORAGE_ENGINE) - MYSQL_STORAGE_ENGINE(INNOBASE) - ELSE (WITH_INNOBASE_STORAGE_ENGINE) - SET (INNODB_SOURCES ${INNOBASE_SOURCES}) - MYSQL_STORAGE_ENGINE(INNODB) - ENDIF (WITH_INNOBASE_STORAGE_ENGINE) + IF (WITH_INNOBASE_STORAGE_ENGINE) + MYSQL_STORAGE_ENGINE(INNOBASE) + ELSE (WITH_INNOBASE_STORAGE_ENGINE) + SET (INNODB_SOURCES ${INNOBASE_SOURCES}) + MYSQL_STORAGE_ENGINE(INNODB) + ENDIF (WITH_INNOBASE_STORAGE_ENGINE) ELSE (MYSQL_VERSION_ID GREATER "50137") - IF (NOT SOURCE_SUBLIBS) - ADD_DEFINITIONS(-D_WIN32 -DMYSQL_SERVER) - ADD_LIBRARY(innobase STATIC ${INNOBASE_SOURCES}) - # Require mysqld_error.h, which is built as part of the GenError - ADD_DEPENDENCIES(innobase GenError) - ENDIF (NOT SOURCE_SUBLIBS) + IF (NOT SOURCE_SUBLIBS) + ADD_DEFINITIONS(-D_WIN32 -DMYSQL_SERVER) + ADD_LIBRARY(innobase STATIC ${INNOBASE_SOURCES}) + # Require mysqld_error.h, which is built as part of the GenError + ADD_DEPENDENCIES(innobase GenError) + ENDIF (NOT SOURCE_SUBLIBS) +ENDIF (MYSQL_VERSION_ID GREATER "50137") diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index d88a3ace872..0f8f4c4d071 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -146,7 +146,8 @@ 2009-07-20 The InnoDB Team - * handler/ha_innodb.cc, buf/buf0rea.c, include/srv0srv.h, srv/srv0srv.c + * buf/buf0rea.c, handler/ha_innodb.cc, include/srv0srv.h, + srv/srv0srv.c: Change the read ahead parameter name to innodb_read_ahead_threshold. Change the meaning of this parameter to signify the number of pages that must be sequentially accessed for InnoDB to trigger a readahead @@ -161,8 +162,8 @@ * include/univ.i: Support inlining of functions and prefetch with Sun Studio. - These changes are based on contribution from - Sun Microsystems Inc. under a BSD license. + These changes are based on contribution from Sun Microsystems Inc. + under a BSD license. 2009-07-14 The InnoDB Team @@ -185,9 +186,9 @@ 2009-07-08 The InnoDB Team - * srv/srv0srv.c, buf/buf0flu.c, handler/ha_innodb.cc, - include/srv0srv.h, include/log0log.ic, include/buf0flu.h, - include/log0log.h: + * buf/buf0flu.c, handler/ha_innodb.cc, include/buf0flu.h, + include/log0log.h, include/log0log.ic, include/srv0srv.h, + srv/srv0srv.c: Implement the adaptive flushing of dirty pages, which uses a heuristics based flushing rate of dirty pages to avoid IO bursts at checkpoint. Expose new configure knob @@ -196,8 +197,8 @@ 2009-07-07 The InnoDB Team - * srv/srv0srv.c, handler/ha_innodb.cc, log/log0log.c, - include/srv0srv.h: + * handler/ha_innodb.cc, include/srv0srv.h, log/log0log.c, + srv/srv0srv.c: Implement IO capacity tuning. Expose new configure knob innodb_io_capacity to control the master threads IO rate. The ibuf merge is also changed from synchronous to asynchronous. @@ -234,13 +235,12 @@ * handler/handler0alter.cc: Start the user transaction prebuilt->trx if it was not started - before adding or dropping an index. Without this fix, the + before adding or dropping an index. Without this fix, the table could be locked outside an active transaction. 2009-06-25 The InnoDB Team - * handler/ha_innodb.cc, - mysql-test/innodb_bug42101.test, + * handler/ha_innodb.cc, mysql-test/innodb_bug42101.test, mysql-test/innodb_bug42101.result, mysql-test/innodb_bug42101-nonzero.test, mysql-test/innodb_bug42101-nonzero.result: diff --git a/storage/innodb_plugin/btr/btr0btr.c b/storage/innodb_plugin/btr/btr0btr.c index 108575798cf..94b34ecece1 100644 --- a/storage/innodb_plugin/btr/btr0btr.c +++ b/storage/innodb_plugin/btr/btr0btr.c @@ -41,7 +41,6 @@ Created 6/2/1994 Heikki Tuuri #include "lock0lock.h" #include "ibuf0ibuf.h" #include "trx0trx.h" -#include "log0log.h" /* Latching strategy of the InnoDB B-tree @@ -874,8 +873,6 @@ leaf_loop: goto leaf_loop; } - - log_write_up_to(mtr.end_lsn, LOG_WAIT_ALL_GROUPS, TRUE); top_loop: mtr_start(&mtr); diff --git a/storage/innodb_plugin/buf/buf0lru.c b/storage/innodb_plugin/buf/buf0lru.c index dd632ace4ac..d3a79d62d3f 100644 --- a/storage/innodb_plugin/buf/buf0lru.c +++ b/storage/innodb_plugin/buf/buf0lru.c @@ -1273,7 +1273,10 @@ buf_LRU_make_block_young( buf_page_t* bpage) /*!< in: control block */ { ut_ad(buf_pool_mutex_own()); - buf_pool->stat.n_pages_made_young++; + + if (bpage->old) { + buf_pool->stat.n_pages_made_young++; + } buf_LRU_remove_block(bpage); buf_LRU_add_block_low(bpage, FALSE); diff --git a/storage/innodb_plugin/handler/handler0vars.h b/storage/innodb_plugin/handler/handler0vars.h deleted file mode 100644 index e0f8f75e34d..00000000000 --- a/storage/innodb_plugin/handler/handler0vars.h +++ /dev/null @@ -1,69 +0,0 @@ -/***************************************************************************** - -Copyright (c) 2008, 2009, Innobase Oy. 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 -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA - -*****************************************************************************/ - -/*******************************************************************//** -@file handler/handler0vars.h -This file contains accessor functions for dynamic plugin on Windows. -***********************************************************************/ - -#if defined __WIN__ && defined MYSQL_DYNAMIC_PLUGIN -/*******************************************************************//** -This is a list of externals that can not be resolved by delay loading. -They have to be resolved indirectly via their addresses in the .map file. -All of them are external variables. */ -extern CHARSET_INFO* wdl_my_charset_bin; -extern CHARSET_INFO* wdl_my_charset_latin1; -extern CHARSET_INFO* wdl_my_charset_filename; -extern CHARSET_INFO** wdl_system_charset_info; -extern CHARSET_INFO** wdl_default_charset_info; -extern CHARSET_INFO** wdl_all_charsets; -extern system_variables* wdl_global_system_variables; -extern char* wdl_mysql_real_data_home; -extern char** wdl_mysql_data_home; -extern char** wdl_tx_isolation_names; -extern char** wdl_binlog_format_names; -extern char* wdl_reg_ext; -extern pthread_mutex_t* wdl_LOCK_thread_count; -extern key_map* wdl_key_map_full; -extern MY_TMPDIR* wdl_mysql_tmpdir_list; -extern bool* wdl_mysqld_embedded; -extern uint* wdl_lower_case_table_names; -extern ulong* wdl_specialflag; -extern int* wdl_my_umask; - -#define my_charset_bin (*wdl_my_charset_bin) -#define my_charset_latin1 (*wdl_my_charset_latin1) -#define my_charset_filename (*wdl_my_charset_filename) -#define system_charset_info (*wdl_system_charset_info) -#define default_charset_info (*wdl_default_charset_info) -#define all_charsets (wdl_all_charsets) -#define global_system_variables (*wdl_global_system_variables) -#define mysql_real_data_home (wdl_mysql_real_data_home) -#define mysql_data_home (*wdl_mysql_data_home) -#define tx_isolation_names (wdl_tx_isolation_names) -#define binlog_format_names (wdl_binlog_format_names) -#define reg_ext (wdl_reg_ext) -#define LOCK_thread_count (*wdl_LOCK_thread_count) -#define key_map_full (*wdl_key_map_full) -#define mysql_tmpdir_list (*wdl_mysql_tmpdir_list) -#define mysqld_embedded (*wdl_mysqld_embedded) -#define lower_case_table_names (*wdl_lower_case_table_names) -#define specialflag (*wdl_specialflag) -#define my_umask (*wdl_my_umask) - -#endif diff --git a/storage/innodb_plugin/handler/i_s.cc b/storage/innodb_plugin/handler/i_s.cc index c0d488d1c49..524fe696de2 100644 --- a/storage/innodb_plugin/handler/i_s.cc +++ b/storage/innodb_plugin/handler/i_s.cc @@ -69,14 +69,16 @@ do { \ #define STRUCT_FLD(name, value) value #endif -static const ST_FIELD_INFO END_OF_ST_FIELD_INFO = - {STRUCT_FLD(field_name, NULL), - STRUCT_FLD(field_length, 0), - STRUCT_FLD(field_type, MYSQL_TYPE_NULL), - STRUCT_FLD(value, 0), - STRUCT_FLD(field_flags, 0), - STRUCT_FLD(old_name, ""), - STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}; +/* Don't use a static const variable here, as some C++ compilers (notably +HPUX aCC: HP ANSI C++ B3910B A.03.65) can't handle it. */ +#define END_OF_ST_FIELD_INFO \ + {STRUCT_FLD(field_name, NULL), \ + STRUCT_FLD(field_length, 0), \ + STRUCT_FLD(field_type, MYSQL_TYPE_NULL), \ + STRUCT_FLD(value, 0), \ + STRUCT_FLD(field_flags, 0), \ + STRUCT_FLD(old_name, ""), \ + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)} /* Use the following types mapping: diff --git a/storage/innodb_plugin/handler/win_delay_loader.cc b/storage/innodb_plugin/handler/win_delay_loader.cc deleted file mode 100644 index 9b92f6a9cf2..00000000000 --- a/storage/innodb_plugin/handler/win_delay_loader.cc +++ /dev/null @@ -1,1024 +0,0 @@ -/***************************************************************************** - -Copyright (c) 2008, 2009, Innobase Oy. 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 -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA - -*****************************************************************************/ - -/*******************************************************************//** -@file handler/win_delay_loader.cc -This file contains functions that implement the delay loader on Windows. - -This is a customized version of delay loader with limited functionalities. -It does not support: - -* (manual) unloading -* multiple delay loaded DLLs -* multiple loading of the same DLL - -This delay loader is used only by the InnoDB plugin. Other components (DLLs) -can still use the default delay loader, provided by MSVC. - -Several acronyms used by Microsoft: - * IAT: import address table - * INT: import name table - * RVA: Relative Virtual Address - -See http://msdn.microsoft.com/en-us/magazine/bb985992.aspx for details of -PE format. -***********************************************************************/ -#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) -# define WIN32_LEAN_AND_MEAN -# include -# include -# include - -extern "C" { -# include "univ.i" -# include "hash0hash.h" -} - -/*******************************************************************//** -This following contains a list of externals that can not be resolved by -delay loading. They have to be resolved indirectly via their addresses -in the .map file. All of them are external variables. */ -CHARSET_INFO* wdl_my_charset_bin; -CHARSET_INFO* wdl_my_charset_latin1; -CHARSET_INFO* wdl_my_charset_filename; -CHARSET_INFO** wdl_system_charset_info; -CHARSET_INFO** wdl_default_charset_info; -CHARSET_INFO** wdl_all_charsets; -system_variables* wdl_global_system_variables; -char* wdl_mysql_real_data_home; -char** wdl_mysql_data_home; -char** wdl_tx_isolation_names; -char** wdl_binlog_format_names; -char* wdl_reg_ext; -pthread_mutex_t* wdl_LOCK_thread_count; -key_map* wdl_key_map_full; -MY_TMPDIR* wdl_mysql_tmpdir_list; -bool* wdl_mysqld_embedded; -uint* wdl_lower_case_table_names; -ulong* wdl_specialflag; -int* wdl_my_umask; - -/*******************************************************************//** -The preferred load-address defined in PE (portable executable format). */ -#if defined(_M_IA64) -#pragma section(".base", long, read) -extern "C" -__declspec(allocate(".base")) -const IMAGE_DOS_HEADER __ImageBase; -#else -extern "C" -const IMAGE_DOS_HEADER __ImageBase; -#endif - -/*******************************************************************//** -A template function for converting a relative address (RVA) to an -absolute address (VA). This is due to the pointers in the delay -descriptor (ImgDelayDescr in delayimp.h) have been changed from -VAs to RVAs to work on both 32- and 64-bit platforms. -@return absolute virtual address */ -template -X PFromRva( -/*=======*/ - RVA rva) /*!< in: relative virtual address */ -{ - return X(PBYTE(&__ImageBase) + rva); -} - -/*******************************************************************//** -Convert to the old format for convenience. The structure as well as its -element names follow the definition of ImgDelayDescr in delayimp.h. */ -struct InternalImgDelayDescr -{ - DWORD grAttrs; /*!< attributes */ - LPCSTR szName; /*!< pointer to dll name */ - HMODULE* phmod; /*!< address of module handle */ - PImgThunkData pIAT; /*!< address of the IAT */ - PCImgThunkData pINT; /*!< address of the INT */ - PCImgThunkData pBoundIAT; /*!< address of the optional bound IAT */ - PCImgThunkData pUnloadIAT; /*!< address of optional copy of - original IAT */ - DWORD dwTimeStamp; /*!< 0 if not bound, - otherwise date/time stamp of DLL - bound to (Old BIND) */ -}; - -typedef struct map_hash_chain_struct map_hash_chain_t; - -struct map_hash_chain_struct { - char* symbol; /*!< pointer to a symbol */ - ulint value; /*!< address of the symbol */ - map_hash_chain_t* next; /*!< pointer to the next cell - in the same folder. */ - map_hash_chain_t* chain; /*!< a linear chain used for - cleanup. */ -}; - -static HMODULE my_hmod = 0; -static struct hash_table_struct* m_htbl = NULL ; -static map_hash_chain_t* chain_header = NULL; -static ibool wdl_init = FALSE; -const ulint MAP_HASH_CELLS_NUM = 10000; - -#ifndef DBUG_OFF -/*******************************************************************//** -In the dynamic plugin, it is required to call the following dbug functions -in the server: - _db_pargs_ - _db_doprnt_ - _db_enter_ - _db_return_ - _db_dump_ - -The plugin will get those function pointers during the initialization. */ -typedef void (__cdecl* pfn_db_enter_)( - const char* _func_, - const char* _file_, - uint _line_, - const char** _sfunc_, - const char** _sfile_, - uint* _slevel_, - char***); - -typedef void (__cdecl* pfn_db_return_)( - uint _line_, - const char** _sfunc_, - const char** _sfile_, - uint* _slevel_); - -typedef void (__cdecl* pfn_db_pargs_)( - uint _line_, - const char* keyword); - -typedef void (__cdecl* pfn_db_doprnt_)( - const char* format, - ...); - -typedef void (__cdecl* pfn_db_dump_)( - uint _line_, - const char* keyword, - const unsigned char* memory, - size_t length); - -static pfn_db_enter_ wdl_db_enter_; -static pfn_db_return_ wdl_db_return_; -static pfn_db_pargs_ wdl_db_pargs_; -static pfn_db_doprnt_ wdl_db_doprnt_; -static pfn_db_dump_ wdl_db_dump_; -#endif /* !DBUG_OFF */ - -/*************************************************************//** -Creates a hash table with >= n array cells. The actual number of cells is -chosen to be a prime number slightly bigger than n. - -This is the same function as hash_create in hash0hash.c, except the -memory allocation. This function is invoked before the engine is -initialized, and buffer pools are not ready yet. -@return own: created hash table */ -static -hash_table_t* -wdl_hash_create( -/*============*/ - ulint n) /*!< in: number of array cells */ -{ - hash_cell_t* array; - ulint prime; - hash_table_t* table; - - prime = ut_find_prime(n); - - table = (hash_table_t*) malloc(sizeof(hash_table_t)); - if (table == NULL) { - return(NULL); - } - - array = (hash_cell_t*) malloc(sizeof(hash_cell_t) * prime); - if (array == NULL) { - free(table); - return(NULL); - } - - table->array = array; - table->n_cells = prime; - table->n_mutexes = 0; - table->mutexes = NULL; - table->heaps = NULL; - table->heap = NULL; - table->magic_n = HASH_TABLE_MAGIC_N; - - /* Initialize the cell array */ - hash_table_clear(table); - - return(table); -} - -/*************************************************************//** -Frees a hash table. */ -static -void -wdl_hash_table_free( -/*================*/ - hash_table_t* table) /*!< in, own: hash table */ -{ - ut_a(table != NULL); - ut_a(table->mutexes == NULL); - - free(table->array); - free(table); -} - -/*******************************************************************//** -Function for calculating the count of imports given the base of the IAT. -@return number of imports */ -static -ulint -wdl_import_count( -/*=============*/ - PCImgThunkData pitd_base) /*!< in: base of the IAT */ -{ - ulint ret = 0; - PCImgThunkData pitd = pitd_base; - - while (pitd->u1.Function) { - pitd++; - ret++; - } - - return(ret); -} - -/*******************************************************************//** -Read Mapfile to a hashtable for faster access -@return TRUE if the mapfile is loaded successfully. */ -static -ibool -wdl_load_mapfile( -/*=============*/ - const char* filename) /*!< in: name of the mapfile. */ -{ - FILE* fp; - const size_t nSize = 256; - char tmp_buf[nSize]; - char* func_name; - char* func_addr; - ulint load_addr = 0; - ibool valid_load_addr = FALSE; -#ifdef _WIN64 - const char* tmp_string = " Preferred load address is %16llx"; -#else - const char* tmp_string = " Preferred load address is %08x"; -#endif - - fp = fopen(filename, "r"); - if (fp == NULL) { - - return(FALSE); - } - - /* Check whether to create the hashtable */ - if (m_htbl == NULL) { - - m_htbl = wdl_hash_create(MAP_HASH_CELLS_NUM); - - if (m_htbl == NULL) { - - fclose(fp); - return(FALSE); - } - } - - /* Search start of symbol list and get the preferred load address */ - while (fgets(tmp_buf, sizeof(tmp_buf), fp)) { - - if (sscanf(tmp_buf, tmp_string, &load_addr) == 1) { - - valid_load_addr = TRUE; - } - - if (strstr(tmp_buf, "Rva+Base") != NULL) { - - break; - } - } - - if (valid_load_addr == FALSE) { - - /* No "Preferred load address", the map file is wrong. */ - fclose(fp); - return(FALSE); - } - - /* Read symbol list */ - while (fgets(tmp_buf, sizeof(tmp_buf), fp)) - { - map_hash_chain_t* map_cell; - ulint map_fold; - - if (*tmp_buf == 0) { - - continue; - } - - func_name = strtok(tmp_buf, " "); - func_name = strtok(NULL, " "); - func_addr = strtok(NULL, " "); - - if (func_name && func_addr) { - - ut_snprintf(tmp_buf, nSize, "0x%s", func_addr); - if (*func_name == '_') { - - func_name++; - } - - map_cell = (map_hash_chain_t*) - malloc(sizeof(map_hash_chain_t)); - if (map_cell == NULL) { - return(FALSE); - } - - /* Chain all cells together */ - map_cell->chain = chain_header; - chain_header = map_cell; - - map_cell->symbol = strdup(func_name); - map_cell->value = (ulint) _strtoui64(tmp_buf, NULL, 0) - - load_addr; - map_fold = ut_fold_string(map_cell->symbol); - - HASH_INSERT(map_hash_chain_t, - next, - m_htbl, - map_fold, - map_cell); - } - } - - fclose(fp); - - return(TRUE); -} - -/*************************************************************//** -Cleanup.during DLL unload */ -static -void -wdl_cleanup(void) -/*=============*/ -{ - while (chain_header != NULL) { - map_hash_chain_t* tmp; - - tmp = chain_header->chain; - free(chain_header->symbol); - free(chain_header); - chain_header = tmp; - } - - if (m_htbl != NULL) { - - wdl_hash_table_free(m_htbl); - } -} - -/*******************************************************************//** -Load the mapfile mysqld.map. -@return the module handle */ -static -HMODULE -wdl_get_mysqld_mapfile(void) -/*========================*/ -{ - char file_name[MAX_PATH]; - char* ext; - ulint err; - - if (my_hmod == 0) { - - size_t nSize = MAX_PATH - strlen(".map") -1; - - /* First find out the name of current executable */ - my_hmod = GetModuleHandle(NULL); - if (my_hmod == 0) { - - return(my_hmod); - } - - err = GetModuleFileName(my_hmod, file_name, nSize); - if (err == 0) { - - my_hmod = 0; - return(my_hmod); - } - - ext = strrchr(file_name, '.'); - if (ext != NULL) { - - *ext = 0; - strcat(file_name, ".map"); - - err = wdl_load_mapfile(file_name); - if (err == 0) { - - my_hmod = 0; - } - } else { - - my_hmod = 0; - } - } - - return(my_hmod); -} - -/*******************************************************************//** -Retrieves the address of an exported function. It follows the convention -of GetProcAddress(). -@return address of exported function. */ -static -FARPROC -wdl_get_procaddr_from_map( -/*======================*/ - HANDLE m_handle, /*!< in: module handle */ - const char* import_proc) /*!< in: procedure name */ -{ - map_hash_chain_t* hash_chain; - ulint map_fold; - - map_fold = ut_fold_string(import_proc); - HASH_SEARCH( - next, - m_htbl, - map_fold, - map_hash_chain_t*, - hash_chain, - , - (ut_strcmp(hash_chain->symbol, import_proc) == 0)); - - if (hash_chain == NULL) { - -#ifdef _WIN64 - /* On Win64, the leading '_' may not be taken out. In this - case, search again without the leading '_'. */ - if (*import_proc == '_') { - - import_proc++; - } - - map_fold = ut_fold_string(import_proc); - HASH_SEARCH( - next, - m_htbl, - map_fold, - map_hash_chain_t*, - hash_chain, - , - (ut_strcmp(hash_chain->symbol, import_proc) == 0)); - - if (hash_chain == NULL) { -#endif - if (wdl_init == TRUE) { - - sql_print_error( - "InnoDB: the procedure pointer of %s" - " is not found.", - import_proc); - } - - return(0); -#ifdef _WIN64 - } -#endif - } - - return((FARPROC) ((ulint) m_handle + hash_chain->value)); -} - -/*******************************************************************//** -Retrieves the address of an exported variable. -Note: It does not follow the Windows call convention FARPROC. -@return address of exported variable. */ -static -void* -wdl_get_varaddr_from_map( -/*=====================*/ - HANDLE m_handle, /*!< in: module handle */ - const char* import_variable) /*!< in: variable name */ -{ - map_hash_chain_t* hash_chain; - ulint map_fold; - - map_fold = ut_fold_string(import_variable); - HASH_SEARCH( - next, - m_htbl, - map_fold, - map_hash_chain_t*, - hash_chain, - , - (ut_strcmp(hash_chain->symbol, import_variable) == 0)); - - if (hash_chain == NULL) { - -#ifdef _WIN64 - /* On Win64, the leading '_' may not be taken out. In this - case, search again without the leading '_'. */ - if (*import_variable == '_') { - - import_variable++; - } - - map_fold = ut_fold_string(import_variable); - HASH_SEARCH( - next, - m_htbl, - map_fold, - map_hash_chain_t*, - hash_chain, - , - (ut_strcmp(hash_chain->symbol, import_variable) == 0)); - - if (hash_chain == NULL) { -#endif - if (wdl_init == TRUE) { - - sql_print_error( - "InnoDB: the variable address of %s" - " is not found.", - import_variable); - } - - return(0); -#ifdef _WIN64 - } -#endif - } - - return((void*) ((ulint) m_handle + hash_chain->value)); -} - -/*******************************************************************//** -Bind all unresolved external variables from the MySQL executable. -@return TRUE if successful */ -static -bool -wdl_get_external_variables(void) -/*============================*/ -{ - HMODULE hmod = wdl_get_mysqld_mapfile(); - - if (hmod == 0) { - - return(FALSE); - } - -#define GET_SYM(sym, var, type) \ - var = (type*) wdl_get_varaddr_from_map(hmod, sym); \ - if (var == NULL) return(FALSE) -#ifdef _WIN64 -#define GET_SYM2(sym1, sym2, var, type) \ - var = (type*) wdl_get_varaddr_from_map(hmod, sym1); \ - if (var == NULL) return(FALSE) -#else -#define GET_SYM2(sym1, sym2, var, type) \ - var = (type*) wdl_get_varaddr_from_map(hmod, sym2); \ - if (var == NULL) return(FALSE) -#endif // (_WIN64) -#define GET_C_SYM(sym, type) GET_SYM(#sym, wdl_##sym, type) -#define GET_PROC_ADDR(sym) \ - wdl##sym = (pfn##sym) wdl_get_procaddr_from_map(hmod, #sym) - - GET_C_SYM(my_charset_bin, CHARSET_INFO); - GET_C_SYM(my_charset_latin1, CHARSET_INFO); - GET_C_SYM(my_charset_filename, CHARSET_INFO); - GET_C_SYM(default_charset_info, CHARSET_INFO*); - GET_C_SYM(all_charsets, CHARSET_INFO*); - GET_C_SYM(my_umask, int); - - GET_SYM("?global_system_variables@@3Usystem_variables@@A", - wdl_global_system_variables, struct system_variables); - GET_SYM("?mysql_real_data_home@@3PADA", - wdl_mysql_real_data_home, char); - GET_SYM("?reg_ext@@3PADA", wdl_reg_ext, char); - GET_SYM("?LOCK_thread_count@@3U_RTL_CRITICAL_SECTION@@A", - wdl_LOCK_thread_count, pthread_mutex_t); - GET_SYM("?key_map_full@@3V?$Bitmap@$0EA@@@A", - wdl_key_map_full, key_map); - GET_SYM("?mysql_tmpdir_list@@3Ust_my_tmpdir@@A", - wdl_mysql_tmpdir_list, MY_TMPDIR); - GET_SYM("?mysqld_embedded@@3_NA", - wdl_mysqld_embedded, bool); - GET_SYM("?lower_case_table_names@@3IA", - wdl_lower_case_table_names, uint); - GET_SYM("?specialflag@@3KA", wdl_specialflag, ulong); - - GET_SYM2("?system_charset_info@@3PEAUcharset_info_st@@EA", - "?system_charset_info@@3PAUcharset_info_st@@A", - wdl_system_charset_info, CHARSET_INFO*); - GET_SYM2("?mysql_data_home@@3PEADEA", - "?mysql_data_home@@3PADA", - wdl_mysql_data_home, char*); - GET_SYM2("?tx_isolation_names@@3PAPEBDA", - "?tx_isolation_names@@3PAPBDA", - wdl_tx_isolation_names, char*); - GET_SYM2("?binlog_format_names@@3PAPEBDA", - "?binlog_format_names@@3PAPBDA", - wdl_binlog_format_names, char*); - -#ifndef DBUG_OFF - GET_PROC_ADDR(_db_enter_); - GET_PROC_ADDR(_db_return_); - GET_PROC_ADDR(_db_pargs_); - GET_PROC_ADDR(_db_doprnt_); - GET_PROC_ADDR(_db_dump_); - - /* If any of the dbug functions is not available, just make them - all invalid. This is the case when working with a non-debug - version of the server. */ - if (wdl_db_enter_ == NULL || wdl_db_return_ == NULL - || wdl_db_pargs_ == NULL || wdl_db_doprnt_ == NULL - || wdl_db_dump_ == NULL) { - - wdl_db_enter_ = NULL; - wdl_db_return_ = NULL; - wdl_db_pargs_ = NULL; - wdl_db_doprnt_ = NULL; - wdl_db_dump_ = NULL; - } -#endif /* !DBUG_OFF */ - - wdl_init = TRUE; - return(TRUE); - -#undef GET_SYM -#undef GET_SYM2 -#undef GET_C_SYM -#undef GET_PROC_ADDR -} - -/*******************************************************************//** -The DLL Delayed Loading Helper Function for resolving externals. - -The function may fail due to one of the three reasons: - -* Invalid parameter, which happens if the attributes in pidd aren't - specified correctly. -* Failed to load the map file mysqld.map. -* Failed to find an external name in the map file mysqld.map. - -Note: this function is called by run-time as well as __HrLoadAllImportsForDll. -So, it has to follow Windows call convention. -@return the address of the imported function */ -extern "C" -FARPROC WINAPI -__delayLoadHelper2( -/*===============*/ - PCImgDelayDescr pidd, /*!< in: a const pointer to a - ImgDelayDescr, see delayimp.h. */ - FARPROC* iat_entry) /*!< in/out: A pointer to the slot in - the delay load import address table - to be updated with the address of the - imported function. */ -{ - ulint iIAT, iINT; - HMODULE hmod; - PCImgThunkData pitd; - FARPROC fun = NULL; - - /* Set up data used for the hook procs */ - InternalImgDelayDescr idd = { - pidd->grAttrs, - PFromRva(pidd->rvaDLLName), - PFromRva(pidd->rvaHmod), - PFromRva(pidd->rvaIAT), - PFromRva(pidd->rvaINT), - PFromRva(pidd->rvaBoundIAT), - PFromRva(pidd->rvaUnloadIAT), - pidd->dwTimeStamp - }; - - DelayLoadInfo dli = { - sizeof(DelayLoadInfo), - pidd, - iat_entry, - idd.szName, - {0}, - 0, - 0, - 0 - }; - - /* Check the Delay Load Attributes, log an error of invalid - parameter, which happens if the attributes in pidd are not - specified correctly. */ - if ((idd.grAttrs & dlattrRva) == 0) { - - sql_print_error("InnoDB: invalid parameter for delay loader."); - return(0); - } - - hmod = *idd.phmod; - - /* Calculate the index for the IAT entry in the import address table. - The INT entries are ordered the same as the IAT entries so the - calculation can be done on the IAT side. */ - iIAT = (PCImgThunkData) iat_entry - idd.pIAT; - iINT = iIAT; - - pitd = &(idd.pINT[iINT]); - - dli.dlp.fImportByName = !IMAGE_SNAP_BY_ORDINAL(pitd->u1.Ordinal); - - if (dli.dlp.fImportByName) { - - dli.dlp.szProcName = (LPCSTR) (PFromRva - ((RVA) ((UINT_PTR) pitd->u1.AddressOfData))->Name); - } else { - - dli.dlp.dwOrdinal = (ulint) IMAGE_ORDINAL(pitd->u1.Ordinal); - } - - /* Now, load the mapfile, if it has not been done yet */ - if (hmod == 0) { - - hmod = wdl_get_mysqld_mapfile(); - } - - if (hmod == 0) { - /* LoadLibrary failed. */ - PDelayLoadInfo rgpdli[1] = {&dli}; - - dli.dwLastError = ::GetLastError(); - - sql_print_error( - "InnoDB: failed to load mysqld.map with error %d.", - dli.dwLastError); - - return(0); - } - - /* Store the library handle. */ - idd.phmod = &hmod; - - /* Go for the procedure now. */ - dli.hmodCur = hmod; - - if (pidd->rvaBoundIAT && pidd->dwTimeStamp) { - - /* Bound imports exist, check the timestamp from the target - image */ - PIMAGE_NT_HEADERS pinh; - - pinh = (PIMAGE_NT_HEADERS) ((byte*) hmod - + ((PIMAGE_DOS_HEADER) hmod)->e_lfanew); - - if (pinh->Signature == IMAGE_NT_SIGNATURE - && pinh->FileHeader.TimeDateStamp == idd.dwTimeStamp - && (DWORD) hmod == pinh->OptionalHeader.ImageBase) { - - /* We have a decent address in the bound IAT. */ - fun = (FARPROC) (UINT_PTR) - idd.pBoundIAT[iIAT].u1.Function; - - if (fun) { - - *iat_entry = fun; - return(fun); - } - } - } - - fun = wdl_get_procaddr_from_map(hmod, dli.dlp.szProcName); - - if (fun == 0) { - - return(0); - } - - *iat_entry = fun; - return(fun); -} - -/*******************************************************************//** -Unload a DLL that was delay loaded. This function is called by run-time. -@return TRUE is returned if the DLL is found and the IAT matches the -original one. */ -extern "C" -BOOL WINAPI -__FUnloadDelayLoadedDLL2( -/*=====================*/ - LPCSTR module_name) /*!< in: DLL name */ -{ - return(TRUE); -} - -/**************************************************************//** -Load all imports from a DLL that was specified with the /delayload linker -option. -Note: this function is called by run-time. So, it has to follow Windows call -convention. -@return S_OK if the DLL matches, otherwise ERROR_MOD_NOT_FOUND is returned. */ -extern "C" -HRESULT WINAPI -__HrLoadAllImportsForDll( -/*=====================*/ - LPCSTR module_name) /*!< in: DLL name */ -{ - PIMAGE_NT_HEADERS img; - PCImgDelayDescr pidd; - IMAGE_DATA_DIRECTORY* image_data; - LPCSTR current_module; - HRESULT ret = ERROR_MOD_NOT_FOUND; - HMODULE hmod = (HMODULE) &__ImageBase; - - img = (PIMAGE_NT_HEADERS) ((byte*) hmod - + ((PIMAGE_DOS_HEADER) hmod)->e_lfanew); - image_data = - &img->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT]; - - /* Scan the delay load IAT/INT for the DLL */ - if (image_data->Size) { - - pidd = PFromRva(image_data->VirtualAddress); - - /* Check all of the listed DLLs we want to load. */ - while (pidd->rvaDLLName) { - - current_module = PFromRva(pidd->rvaDLLName); - - if (stricmp(module_name, current_module) == 0) { - - /* Found it, break out with pidd and - current_module set appropriately */ - break; - } - - /* To the next delay import descriptor */ - pidd++; - } - - if (pidd->rvaDLLName) { - - /* Found a matching DLL, now process it. */ - FARPROC* iat_entry; - size_t count; - - iat_entry = PFromRva(pidd->rvaIAT); - count = wdl_import_count((PCImgThunkData) iat_entry); - - /* now load all the imports from the DLL */ - while (count > 0) { - - /* No need to check the return value */ - __delayLoadHelper2(pidd, iat_entry); - iat_entry++; - count--; - } - - ret = S_OK; - } - } - - return ret; -} - -/**************************************************************//** -The main function of a DLL -@return TRUE if the call succeeds */ -BOOL -WINAPI -DllMain( -/*====*/ - HINSTANCE hinstDLL, /*!< in: handle to the DLL module */ - DWORD fdwReason, /*!< Reason code that indicates why the - DLL entry-point function is being - called.*/ - LPVOID lpvReserved) /*!< in: additional parameter based on - fdwReason */ -{ - BOOL success = TRUE; - - switch (fdwReason) { - - case DLL_PROCESS_ATTACH: - success = wdl_get_external_variables(); - break; - - case DLL_PROCESS_DETACH: - wdl_cleanup(); - break; - } - - return(success); -} - -#ifndef DBUG_OFF -/**************************************************************//** -Process entry point to user function. It makes the call to _db_enter_ -in mysqld.exe. The DBUG functions are defined in my_dbug.h. */ -extern "C" UNIV_INTERN -void -_db_enter_( - const char* _func_, /*!< in: current function name */ - const char* _file_, /*!< in: current file name */ - uint _line_, /*!< in: current source line number */ - const char** _sfunc_, /*!< out: previous _func_ */ - const char** _sfile_, /*!< out: previous _file_ */ - uint* _slevel_, /*!< out: previous nesting level */ - char*** _sframep_) /*!< out: previous frame pointer */ -{ - if (wdl_db_enter_ != NULL) { - - wdl_db_enter_(_func_, _file_, _line_, _sfunc_, _sfile_, - _slevel_, _sframep_); - } -} - -/**************************************************************//** -Process exit from user function. It makes the call to _db_return_() -in the server. */ -extern "C" UNIV_INTERN -void -_db_return_( - uint _line_, /*!< in: current source line number */ - const char** _sfunc_, /*!< out: previous _func_ */ - const char** _sfile_, /*!< out: previous _file_ */ - uint* _slevel_) /*!< out: previous level */ -{ - if (wdl_db_return_ != NULL) { - - wdl_db_return_(_line_, _sfunc_, _sfile_, _slevel_); - } -} - -/**************************************************************//** -Log arguments for subsequent use. It makes the call to _db_pargs_() -in the server. */ -extern "C" UNIV_INTERN -void -_db_pargs_( - uint _line_, /*!< in: current source line number */ - const char* keyword) /*!< in: keyword for current macro */ -{ - if (wdl_db_pargs_ != NULL) { - - wdl_db_pargs_(_line_, keyword); - } -} - -/**************************************************************//** -Handle print of debug lines. It saves the text into a buffer first, -then makes the call to _db_doprnt_() in the server. The text is -truncated to the size of buffer. */ -extern "C" UNIV_INTERN -void -_db_doprnt_( - const char* format, /*!< in: the format string */ - ...) /*!< in: list of arguments */ -{ - va_list argp; - char buffer[512]; - - if (wdl_db_doprnt_ != NULL) { - - va_start(argp, format); - /* it is ok to ignore the trunction. */ - _vsnprintf(buffer, sizeof(buffer), format, argp); - wdl_db_doprnt_(buffer); - va_end(argp); - } -} - -/**************************************************************//** -Dump a string in hex. It makes the call to _db_dump_() in the server. */ -extern "C" UNIV_INTERN -void -_db_dump_( - uint _line_, /*!< in: current source line - number */ - const char* keyword, /*!< in: keyword list */ - const unsigned char* memory, /*!< in: memory to dump */ - size_t length) /*!< in: bytes to dump */ -{ - if (wdl_db_dump_ != NULL) { - - wdl_db_dump_(_line_, keyword, memory, length); - } -} - -#endif /* !DBUG_OFF */ -#endif /* defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) */ diff --git a/storage/innodb_plugin/include/os0sync.h b/storage/innodb_plugin/include/os0sync.h index 317c6d612fd..0c22162b900 100644 --- a/storage/innodb_plugin/include/os0sync.h +++ b/storage/innodb_plugin/include/os0sync.h @@ -285,7 +285,7 @@ os_fast_mutex_free( /**********************************************************//** Atomic compare-and-swap and increment for InnoDB. */ -#ifdef HAVE_IB_GCC_ATOMIC_BUILTINS +#if defined(HAVE_IB_GCC_ATOMIC_BUILTINS) #define HAVE_ATOMIC_BUILTINS @@ -306,6 +306,11 @@ compare to, new_val is the value to swap in. */ # define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ os_compare_and_swap(ptr, old_val, new_val) # define INNODB_RW_LOCKS_USE_ATOMICS +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes and rw_locks use GCC atomic builtins" +# else /* HAVE_IB_ATOMIC_PTHREAD_T_GCC */ +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes use GCC atomic builtins, rw_locks do not" # endif /* HAVE_IB_ATOMIC_PTHREAD_T_GCC */ /**********************************************************//** @@ -356,7 +361,12 @@ compare to, new_val is the value to swap in. */ # else # error "SIZEOF_PTHREAD_T != 4 or 8" # endif /* SIZEOF_PTHREAD_T CHECK */ -# define INNODB_RW_LOCKS_USE_ATOMICS +# define INNODB_RW_LOCKS_USE_ATOMICS +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes and rw_locks use Solaris atomic functions" +# else /* HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS */ +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes use Solaris atomic functions, rw_locks do not" # endif /* HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS */ /**********************************************************//** @@ -401,6 +411,9 @@ compare to, new_val is the value to swap in. */ /* windows thread objects can always be passed to windows atomic functions */ # define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ (InterlockedCompareExchange(ptr, new_val, old_val) == old_val) +# define INNODB_RW_LOCKS_USE_ATOMICS +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes and rw_locks use Windows interlocked functions" /**********************************************************//** Returns the resulting value, ptr is pointer to target, amount is the @@ -420,6 +433,9 @@ clobbered */ # define os_atomic_test_and_set_byte(ptr, new_val) \ ((byte) InterlockedExchange(ptr, new_val)) +#else +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes and rw_locks use InnoDB's own implementation" #endif #ifndef UNIV_NONINL diff --git a/storage/innodb_plugin/include/univ.i b/storage/innodb_plugin/include/univ.i index b508a42c445..0e14f7b1cba 100644 --- a/storage/innodb_plugin/include/univ.i +++ b/storage/innodb_plugin/include/univ.i @@ -395,7 +395,8 @@ it is read. */ it is read or written. */ # define UNIV_PREFETCH_RW(addr) __builtin_prefetch(addr, 1, 3) /* Sun Studio includes sun_prefetch.h as of version 5.9 */ -#elif (defined(__SUNPRO_C) && __SUNPRO_C >= 0x590) || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x590) +#elif (defined(__SUNPRO_C) && __SUNPRO_C >= 0x590) \ + || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x590) # include #if __SUNPRO_C >= 0x550 # undef UNIV_INTERN diff --git a/storage/innodb_plugin/include/ut0ut.h b/storage/innodb_plugin/include/ut0ut.h index 9604833b278..197b8401428 100644 --- a/storage/innodb_plugin/include/ut0ut.h +++ b/storage/innodb_plugin/include/ut0ut.h @@ -35,7 +35,9 @@ Created 1/20/1994 Heikki Tuuri #include "univ.i" -#include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ +#ifndef UNIV_HOTBACKUP +# include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ +#endif /* UNIV_HOTBACKUP */ #include #ifndef MYSQL_SERVER @@ -50,6 +52,7 @@ Created 1/20/1994 Heikki Tuuri /** Time stamp */ typedef time_t ib_time_t; +#ifndef UNIV_HOTBACKUP #if defined(HAVE_IB_PAUSE_INSTRUCTION) # ifdef WIN32 /* In the Win32 API, the x86 PAUSE instruction is executed by calling @@ -87,6 +90,7 @@ do { \ os_thread_sleep(2000 /* 2 ms */); \ } \ } while (0) +#endif /* !UNIV_HOTBACKUP */ /********************************************************//** Gets the high 32 bits in a ulint. That is makes a shift >> 32, diff --git a/storage/innodb_plugin/plug.in b/storage/innodb_plugin/plug.in index 195800462aa..94a2c969694 100644 --- a/storage/innodb_plugin/plug.in +++ b/storage/innodb_plugin/plug.in @@ -37,27 +37,16 @@ MYSQL_PLUGIN_ACTIONS(innodb_plugin, [ irix*|osf*|sysv5uw7*|openbsd*) CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";; *solaris*|*SunOS*) - # Begin Solaris atomic function checks - AC_CHECK_FUNCS(atomic_cas_ulong atomic_cas_32 \ - atomic_cas_64 atomic_add_long, - AC_DEFINE( - [HAVE_SOLARIS_ATOMICS], - [1], - [Define to 1 if Solaris supports \ - atomic functions.])) - ### End Solaris atomic function checks - CFLAGS="$CFLAGS -DUNIV_SOLARIS";; esac + INNODB_DYNAMIC_CFLAGS="-DMYSQL_DYNAMIC_PLUGIN" - case "$target_cpu---$target_os" in - x86_64---*) + + case "$target_cpu" in + x86_64) # The AMD64 ABI forbids absolute addresses in shared libraries ;; - *---solaris*|*---SunOS*) - # Shared objects must be linked from PIC code on Solaris. - ;; - *86---) + *86) # Use absolute addresses on IA-32 INNODB_DYNAMIC_CFLAGS="$INNODB_DYNAMIC_CFLAGS -prefer-non-pic" ;; @@ -65,6 +54,7 @@ MYSQL_PLUGIN_ACTIONS(innodb_plugin, [ AC_SUBST(INNODB_DYNAMIC_CFLAGS) AC_MSG_CHECKING(whether GCC atomic builtins are available) + # either define HAVE_IB_GCC_ATOMIC_BUILTINS or not AC_TRY_RUN( [ int main() @@ -115,6 +105,7 @@ MYSQL_PLUGIN_ACTIONS(innodb_plugin, [ ) AC_MSG_CHECKING(whether pthread_t can be used by GCC atomic builtins) + # either define HAVE_IB_ATOMIC_PTHREAD_T_GCC or not AC_TRY_RUN( [ #include @@ -135,7 +126,7 @@ MYSQL_PLUGIN_ACTIONS(innodb_plugin, [ } ], [ - AC_DEFINE([HAVE_ATOMIC_PTHREAD_T], [1], + AC_DEFINE([HAVE_IB_ATOMIC_PTHREAD_T_GCC], [1], [pthread_t can be used by GCC atomic builtins]) AC_MSG_RESULT(yes) ], @@ -144,38 +135,64 @@ MYSQL_PLUGIN_ACTIONS(innodb_plugin, [ ] ) - # Try using solaris atomics on SunOS if GCC atomics are not available - AC_CHECK_DECLS( - [HAVE_ATOMIC_PTHREAD_T], + AC_MSG_CHECKING(whether Solaris libc atomic functions are available) + # either define HAVE_IB_SOLARIS_ATOMICS or not + AC_CHECK_FUNCS(atomic_add_long \ + atomic_cas_32 \ + atomic_cas_64 \ + atomic_cas_ulong, + + AC_DEFINE([HAVE_IB_SOLARIS_ATOMICS], [1], + [Define to 1 if Solaris libc atomic functions \ + are available]) + ) + + AC_MSG_CHECKING(whether pthread_t can be used by Solaris libc atomic functions) + # either define HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS or not + AC_TRY_RUN( [ - AC_MSG_NOTICE(no need to check pthread_t size) + #include + #include + + int main(int argc, char** argv) { + pthread_t x1; + pthread_t x2; + pthread_t x3; + + memset(&x1, 0x0, sizeof(x1)); + memset(&x2, 0x0, sizeof(x2)); + memset(&x3, 0x0, sizeof(x3)); + + if (sizeof(pthread_t) == 4) { + + atomic_cas_32(&x1, x2, x3); + + } else if (sizeof(pthread_t) == 8) { + + atomic_cas_64(&x1, x2, x3); + + } else { + + return(1); + } + + return(0); + } ], [ - AC_CHECK_DECLS( - [HAVE_SOLARIS_ATOMICS], - [ - AC_MSG_CHECKING(checking if pthread_t type is integral) - AC_TRY_RUN( - [ - #include - int main() - { - pthread_t x = 0; - return(0); - } - ], - [ - AC_DEFINE([HAVE_ATOMIC_PTHREAD_T], [1], + AC_DEFINE([HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS], [1], [pthread_t can be used by solaris atomics]) - AC_MSG_RESULT(yes) - # size of pthread_t is needed for typed solaris atomics - AC_CHECK_SIZEOF([pthread_t], [], [#include ]) - ], - [ - AC_MSG_RESULT(no) - ]) - ]) - ]) + AC_MSG_RESULT(yes) + ], + [ + AC_MSG_RESULT(no) + ] + ) + + # this is needed to know which one of atomic_cas_32() or atomic_cas_64() + # to use in the source + AC_CHECK_SIZEOF([pthread_t], [], [#include ]) + # Check for x86 PAUSE instruction AC_MSG_CHECKING(for x86 PAUSE instruction) # We have to actually try running the test program, because of a bug @@ -192,7 +209,7 @@ MYSQL_PLUGIN_ACTIONS(innodb_plugin, [ } ], [ - AC_DEFINE([IB_HAVE_PAUSE_INSTRUCTION], [1], [Does x86 PAUSE instruction exist]) + AC_DEFINE([HAVE_IB_PAUSE_INSTRUCTION], [1], [Does x86 PAUSE instruction exist]) AC_MSG_RESULT(yes) ], [ diff --git a/storage/innodb_plugin/srv/srv0start.c b/storage/innodb_plugin/srv/srv0start.c index 20b77155e5f..37263317126 100644 --- a/storage/innodb_plugin/srv/srv0start.c +++ b/storage/innodb_plugin/srv/srv0start.c @@ -1111,34 +1111,7 @@ innobase_start_or_create_for_mysql(void) "InnoDB: The InnoDB memory heap is disabled\n"); } -#ifdef HAVE_IB_GCC_ATOMIC_BUILTINS -# ifdef INNODB_RW_LOCKS_USE_ATOMICS - fprintf(stderr, - "InnoDB: Mutexes and rw_locks use GCC atomic builtins.\n"); -# else /* INNODB_RW_LOCKS_USE_ATOMICS */ - fprintf(stderr, - "InnoDB: Mutexes use GCC atomic builtins, rw_locks do not.\n"); -# endif /* INNODB_RW_LOCKS_USE_ATOMICS */ -#elif defined(HAVE_IB_SOLARIS_ATOMICS) -# ifdef INNODB_RW_LOCKS_USE_ATOMICS - fprintf(stderr, - "InnoDB: Mutexes and rw_locks use Solaris atomic functions.\n"); -# else - fprintf(stderr, - "InnoDB: Mutexes use Solaris atomic functions.\n"); -# endif /* INNODB_RW_LOCKS_USE_ATOMICS */ -#elif HAVE_WINDOWS_ATOMICS -# ifdef INNODB_RW_LOCKS_USE_ATOMICS - fprintf(stderr, - "InnoDB: Mutexes and rw_locks use Windows interlocked functions.\n"); -# else - fprintf(stderr, - "InnoDB: Mutexes use Windows interlocked functions.\n"); -# endif /* INNODB_RW_LOCKS_USE_ATOMICS */ -#else /* HAVE_IB_GCC_ATOMIC_BUILTINS */ - fprintf(stderr, - "InnoDB: Neither mutexes nor rw_locks use GCC atomic builtins.\n"); -#endif /* HAVE_IB_GCC_ATOMIC_BUILTINS */ + fprintf(stderr, "InnoDB: %s\n", IB_ATOMICS_STARTUP_MSG); /* Since InnoDB does not currently clean up all its internal data structures in MySQL Embedded Server Library server_end(), we diff --git a/storage/innodb_plugin/sync/sync0sync.c b/storage/innodb_plugin/sync/sync0sync.c index beef3a1f2db..5ad143075a7 100644 --- a/storage/innodb_plugin/sync/sync0sync.c +++ b/storage/innodb_plugin/sync/sync0sync.c @@ -850,7 +850,8 @@ sync_thread_levels_g( /*=================*/ sync_level_t* arr, /*!< in: pointer to level array for an OS thread */ - ulint limit) /*!< in: level limit */ + ulint limit, /*!< in: level limit */ + ulint warn) /*!< in: TRUE=display a diagnostic message */ { sync_level_t* slot; rw_lock_t* lock; @@ -864,6 +865,11 @@ sync_thread_levels_g( if (slot->latch != NULL) { if (slot->level <= limit) { + if (!warn) { + + return(FALSE); + } + lock = slot->latch; mutex = slot->latch; @@ -1101,7 +1107,7 @@ sync_thread_add_level( case SYNC_DICT_HEADER: case SYNC_TRX_I_S_RWLOCK: case SYNC_TRX_I_S_LAST_READ: - if (!sync_thread_levels_g(array, level)) { + if (!sync_thread_levels_g(array, level, TRUE)) { fprintf(stderr, "InnoDB: sync_thread_levels_g(array, %lu)" " does not hold!\n", level); @@ -1112,36 +1118,44 @@ sync_thread_add_level( /* Either the thread must own the buffer pool mutex (buf_pool_mutex), or it is allowed to latch only ONE buffer block (block->mutex or buf_pool_zip_mutex). */ - if (!sync_thread_levels_g(array, level)) { - ut_a(sync_thread_levels_g(array, level - 1)); + if (!sync_thread_levels_g(array, level, FALSE)) { + ut_a(sync_thread_levels_g(array, level - 1, TRUE)); ut_a(sync_thread_levels_contain(array, SYNC_BUF_POOL)); } break; case SYNC_REC_LOCK: - ut_a((sync_thread_levels_contain(array, SYNC_KERNEL) - && sync_thread_levels_g(array, SYNC_REC_LOCK - 1)) - || sync_thread_levels_g(array, SYNC_REC_LOCK)); + if (sync_thread_levels_contain(array, SYNC_KERNEL)) { + ut_a(sync_thread_levels_g(array, SYNC_REC_LOCK - 1, + TRUE)); + } else { + ut_a(sync_thread_levels_g(array, SYNC_REC_LOCK, TRUE)); + } break; case SYNC_IBUF_BITMAP: /* Either the thread must own the master mutex to all the bitmap pages, or it is allowed to latch only ONE bitmap page. */ - ut_a((sync_thread_levels_contain(array, SYNC_IBUF_BITMAP_MUTEX) - && sync_thread_levels_g(array, SYNC_IBUF_BITMAP - 1)) - || sync_thread_levels_g(array, SYNC_IBUF_BITMAP)); + if (sync_thread_levels_contain(array, + SYNC_IBUF_BITMAP_MUTEX)) { + ut_a(sync_thread_levels_g(array, SYNC_IBUF_BITMAP - 1, + TRUE)); + } else { + ut_a(sync_thread_levels_g(array, SYNC_IBUF_BITMAP, + TRUE)); + } break; case SYNC_FSP_PAGE: ut_a(sync_thread_levels_contain(array, SYNC_FSP)); break; case SYNC_FSP: ut_a(sync_thread_levels_contain(array, SYNC_FSP) - || sync_thread_levels_g(array, SYNC_FSP)); + || sync_thread_levels_g(array, SYNC_FSP, TRUE)); break; case SYNC_TRX_UNDO_PAGE: ut_a(sync_thread_levels_contain(array, SYNC_TRX_UNDO) || sync_thread_levels_contain(array, SYNC_RSEG) || sync_thread_levels_contain(array, SYNC_PURGE_SYS) - || sync_thread_levels_g(array, SYNC_TRX_UNDO_PAGE)); + || sync_thread_levels_g(array, SYNC_TRX_UNDO_PAGE, TRUE)); break; case SYNC_RSEG_HEADER: ut_a(sync_thread_levels_contain(array, SYNC_RSEG)); @@ -1153,37 +1167,41 @@ sync_thread_add_level( case SYNC_TREE_NODE: ut_a(sync_thread_levels_contain(array, SYNC_INDEX_TREE) || sync_thread_levels_contain(array, SYNC_DICT_OPERATION) - || sync_thread_levels_g(array, SYNC_TREE_NODE - 1)); + || sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE)); break; case SYNC_TREE_NODE_NEW: ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE) || sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); break; case SYNC_INDEX_TREE: - ut_a((sync_thread_levels_contain(array, SYNC_IBUF_MUTEX) - && sync_thread_levels_contain(array, SYNC_FSP) - && sync_thread_levels_g(array, SYNC_FSP_PAGE - 1)) - || sync_thread_levels_g(array, SYNC_TREE_NODE - 1)); + if (sync_thread_levels_contain(array, SYNC_IBUF_MUTEX) + && sync_thread_levels_contain(array, SYNC_FSP)) { + ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, + TRUE)); + } else { + ut_a(sync_thread_levels_g(array, SYNC_TREE_NODE - 1, + TRUE)); + } break; case SYNC_IBUF_MUTEX: - ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1)); + ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, TRUE)); break; case SYNC_IBUF_PESS_INSERT_MUTEX: - ut_a(sync_thread_levels_g(array, SYNC_FSP - 1) - && !sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); + ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE)); + ut_a(!sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); break; case SYNC_IBUF_HEADER: - ut_a(sync_thread_levels_g(array, SYNC_FSP - 1) - && !sync_thread_levels_contain(array, SYNC_IBUF_MUTEX) - && !sync_thread_levels_contain( - array, SYNC_IBUF_PESS_INSERT_MUTEX)); + ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE)); + ut_a(!sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); + ut_a(!sync_thread_levels_contain(array, + SYNC_IBUF_PESS_INSERT_MUTEX)); break; case SYNC_DICT: #ifdef UNIV_DEBUG ut_a(buf_debug_prints - || sync_thread_levels_g(array, SYNC_DICT)); + || sync_thread_levels_g(array, SYNC_DICT, TRUE)); #else /* UNIV_DEBUG */ - ut_a(sync_thread_levels_g(array, SYNC_DICT)); + ut_a(sync_thread_levels_g(array, SYNC_DICT, TRUE)); #endif /* UNIV_DEBUG */ break; default: diff --git a/storage/innodb_plugin/ut/ut0auxconf_have_gcc_atomics.c b/storage/innodb_plugin/ut/ut0auxconf_have_gcc_atomics.c index cc4acec9590..da5c13d7d79 100644 --- a/storage/innodb_plugin/ut/ut0auxconf_have_gcc_atomics.c +++ b/storage/innodb_plugin/ut/ut0auxconf_have_gcc_atomics.c @@ -59,64 +59,3 @@ main(int argc, char** argv) return(0); } -/***************************************************************************** - -Copyright (c) 2009, Innobase Oy. 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 -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA - -*****************************************************************************/ - -/***************************************************************************** -If this program compiles and returns 0, then GCC atomic funcions are available. - -Created September 12, 2009 Vasil Dimov -*****************************************************************************/ - -int -main(int argc, char** argv) -{ - long x; - long y; - long res; - char c; - - x = 10; - y = 123; - res = __sync_bool_compare_and_swap(&x, x, y); - if (!res || x != y) { - return(1); - } - - x = 10; - y = 123; - res = __sync_bool_compare_and_swap(&x, x + 1, y); - if (res || x != 10) { - return(1); - } - - x = 10; - y = 123; - res = __sync_add_and_fetch(&x, y); - if (res != 123 + 10 || x != 123 + 10) { - return(1); - } - - c = 10; - res = __sync_lock_test_and_set(&c, 123); - if (res != 10 || c != 123) { - return(1); - } - - return(0); -} diff --git a/storage/innodb_plugin/ut/ut0auxconf_pause.c b/storage/innodb_plugin/ut/ut0auxconf_pause.c index 227fc2b204e..54d63bdd9bc 100644 --- a/storage/innodb_plugin/ut/ut0auxconf_pause.c +++ b/storage/innodb_plugin/ut/ut0auxconf_pause.c @@ -30,35 +30,3 @@ main(int argc, char** argv) return(0); } -/***************************************************************************** - -Copyright (c) 2009, Innobase Oy. 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 -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA - -*****************************************************************************/ - -/***************************************************************************** -If this program compiles and can be run and returns 0, then the pause -instruction is available. - -Created Jul 21, 2009 Vasil Dimov -*****************************************************************************/ - -int -main(int argc, char** argv) -{ - __asm__ __volatile__ ("pause"); - - return(0); -} diff --git a/storage/innodb_plugin/win-plugin/README b/storage/innodb_plugin/win-plugin/README deleted file mode 100644 index 00f4e996a3f..00000000000 --- a/storage/innodb_plugin/win-plugin/README +++ /dev/null @@ -1,22 +0,0 @@ -This directory contains patches that need to be applied to the MySQL -source tree in order to build the dynamic plugin on Windows -- -HA_INNODB.DLL. Please note the followings when adding the patches: - -* The patch must be applied from the mysql top-level source directory. - patch -p0 < win-plugin.diff -* The patch filenames end in ".diff". -* All patches here are expected to apply cleanly to the latest MySQL 5.1 - tree when storage/innobase is replaced with this InnoDB branch. - -When applying the patch, the following files will be modified: - - * CMakeLists.txt - * sql/CMakeLists.txt - * win/configure.js - -Also, two new files will be added: - - * sql/mysqld.def - * sql/mysqld_x64.def - -You can get "patch" utility for Windows from http://unxutils.sourceforge.net/ diff --git a/storage/innodb_plugin/win-plugin/win-plugin.diff b/storage/innodb_plugin/win-plugin/win-plugin.diff deleted file mode 100644 index 4b3354ac4de..00000000000 --- a/storage/innodb_plugin/win-plugin/win-plugin.diff +++ /dev/null @@ -1,279 +0,0 @@ -diff -Nur CMakeLists.txt.orig CMakeLists.txt ---- CMakeLists.txt.orig 2008-10-03 12:25:41 -05:00 -+++ CMakeLists.txt 2008-09-26 17:32:51 -05:00 -@@ -254,9 +254,9 @@ - IF(WITH_FEDERATED_STORAGE_ENGINE) - ADD_SUBDIRECTORY(storage/federated) - ENDIF(WITH_FEDERATED_STORAGE_ENGINE) --IF(WITH_INNOBASE_STORAGE_ENGINE) -+IF(WITH_INNOBASE_STORAGE_ENGINE OR INNODB_DYNAMIC_PLUGIN) - ADD_SUBDIRECTORY(storage/innobase) --ENDIF(WITH_INNOBASE_STORAGE_ENGINE) -+ENDIF(WITH_INNOBASE_STORAGE_ENGINE OR INNODB_DYNAMIC_PLUGIN) - ADD_SUBDIRECTORY(sql) - ADD_SUBDIRECTORY(server-tools/instance-manager) - ADD_SUBDIRECTORY(libmysql) - -diff -Nur sql/CMakeLists.txt.orig sql/CMakeLists.txt ---- sql/CMakeLists.txt.orig 2008-10-03 12:25:41 -05:00 -+++ sql/CMakeLists.txt 2008-09-24 03:58:19 -05:00 -@@ -98,6 +98,15 @@ - LINK_FLAGS "/PDB:${CMAKE_CFG_INTDIR}/mysqld${MYSQLD_EXE_SUFFIX}.pdb") - ENDIF(cmake_version EQUAL 20406) - -+# Checks for 64-bit version -+IF(CMAKE_SIZEOF_VOID_P MATCHES 8) -+SET_TARGET_PROPERTIES(mysqld PROPERTIES -+ LINK_FLAGS "/def:\"${PROJECT_SOURCE_DIR}/sql/mysqld_x64.def\"") -+ELSE(CMAKE_SIZEOF_VOID_P MATCHES 8) -+SET_TARGET_PROPERTIES(mysqld PROPERTIES -+ LINK_FLAGS "/def:\"${PROJECT_SOURCE_DIR}/sql/mysqld.def\"") -+ENDIF(CMAKE_SIZEOF_VOID_P MATCHES 8) -+ - IF(EMBED_MANIFESTS) - MYSQL_EMBED_MANIFEST("mysqld" "asInvoker") - ENDIF(EMBED_MANIFESTS) - -diff -Nur sql/mysqld.def.orig sql/mysqld.def ---- sql/mysqld.def.orig 1969-12-31 18:00:00 -06:00 -+++ sql/mysqld.def 2009-04-09 02:20:32 -05:00 -@@ -0,0 +1,111 @@ -+EXPORTS -+ ?use_hidden_primary_key@handler@@UAEXXZ -+ ?get_dynamic_partition_info@handler@@UAEXPAUPARTITION_INFO@@I@Z -+ ?read_first_row@handler@@UAEHPAEI@Z -+ ?read_range_next@handler@@UAEHXZ -+ ?read_range_first@handler@@UAEHPBUst_key_range@@0_N1@Z -+ ?read_multi_range_first@handler@@UAEHPAPAUst_key_multi_range@@PAU2@I_NPAUst_handler_buffer@@@Z -+ ?read_multi_range_next@handler@@UAEHPAPAUst_key_multi_range@@@Z -+ ?index_read_idx_map@handler@@UAEHPAEIPBEKW4ha_rkey_function@@@Z -+ ?print_error@handler@@UAEXHH@Z -+ ?clone@handler@@UAEPAV1@PAUst_mem_root@@@Z -+ ?get_auto_increment@handler@@UAEX_K00PA_K1@Z -+ ?index_next_same@handler@@UAEHPAEPBEI@Z -+ ?get_error_message@handler@@UAE_NHPAVString@@@Z -+ ?ha_thd@handler@@IBEPAVTHD@@XZ -+ ?update_auto_increment@handler@@QAEHXZ -+ ?ha_statistic_increment@handler@@IBEXPQsystem_status_var@@K@Z -+ ?trans_register_ha@@YAXPAVTHD@@_NPAUhandlerton@@@Z -+ ?cmp@Field_blob@@QAEHPBEI0I@Z -+ ?set_time@Field_timestamp@@QAEXXZ -+ ?sql_print_error@@YAXPBDZZ -+ ?sql_print_warning@@YAXPBDZZ -+ ?check_global_access@@YA_NPAVTHD@@K@Z -+ ?schema_table_store_record@@YA_NPAVTHD@@PAUst_table@@@Z -+ ?get_quote_char_for_identifier@@YAHPAVTHD@@PBDI@Z -+ ?copy@String@@QAE_NXZ -+ ?copy@String@@QAE_NABV1@@Z -+ ?copy@String@@QAE_NPBDIPAUcharset_info_st@@@Z -+ ?copy_and_convert@@YAIPADIPAUcharset_info_st@@PBDI1PAI@Z -+ ?filename_to_tablename@@YAIPBDPADI@Z -+ ?strconvert@@YAIPAUcharset_info_st@@PBD0PADIPAI@Z -+ ?calculate_key_len@@YAIPAUst_table@@IPBEK@Z -+ ?sql_alloc@@YAPAXI@Z -+ ?localtime_to_TIME@@YAXPAUst_mysql_time@@PAUtm@@@Z -+ ?push_warning@@YAPAVMYSQL_ERROR@@PAVTHD@@W4enum_warning_level@1@IPBD@Z -+ ?push_warning_printf@@YAXPAVTHD@@W4enum_warning_level@MYSQL_ERROR@@IPBDZZ -+ ?drop_table@handler@@EAEXPBD@Z -+ ?column_bitmaps_signal@handler@@UAEXXZ -+ ?delete_table@handler@@MAEHPBD@Z -+ ?rename_table@handler@@MAEHPBD0@Z -+ ?key_map_empty@@3V?$Bitmap@$0EA@@@B -+ ?THR_THD@@3PAVTHD@@A -+ ?end_of_list@@3Ulist_node@@A -+ ?mysql_tmpdir_list@@3Ust_my_tmpdir@@A -+ mysql_query_cache_invalidate4 -+ thd_query -+ thd_sql_command -+ thd_get_thread_id -+ thd_get_xid -+ thd_slave_thread -+ thd_non_transactional_update -+ thd_mark_transaction_to_rollback -+ thd_security_context -+ thd_charset -+ thd_test_options -+ thd_ha_data -+ thd_killed -+ thd_tx_isolation -+ thd_tablespace_op -+ thd_sql_command -+ thd_memdup -+ thd_make_lex_string -+ thd_in_lock_tables -+ thd_binlog_format -+ _my_hash_init -+ my_hash_free -+ my_tmpdir -+ check_if_legal_filename -+ my_filename -+ my_sync_dir_by_file -+ alloc_root -+ thr_lock_data_init -+ thr_lock_init -+ thr_lock_delete -+ my_multi_malloc -+ get_charset -+ unpack_filename -+ my_hash_insert -+ my_hash_search -+ my_hash_delete -+ mysql_bin_log_file_pos -+ mysql_bin_log_file_name -+ mysqld_embedded -+ my_thread_name -+ my_malloc -+ my_no_flags_free -+ _sanity -+ _mymalloc -+ _myfree -+ _my_strdup -+ _my_thread_var -+ my_error -+ pthread_cond_init -+ pthread_cond_signal -+ pthread_cond_wait -+ pthread_cond_destroy -+ localtime_r -+ my_strdup -+ deflate -+ deflateEnd -+ deflateReset -+ deflateInit2_ -+ inflateEnd -+ inflateInit_ -+ inflate -+ compressBound -+ inflateInit2_ -+ adler32 -+ longlong2str -+ strend -+ my_snprintf - -diff -Nur sql/mysqld_x64.def.orig sql/mysqld_x64.def ---- sql/mysqld_x64.def.orig 1969-12-31 18:00:00 -06:00 -+++ sql/mysqld_x64.def 2009-04-09 02:22:04 -05:00 -@@ -0,0 +1,111 @@ -+EXPORTS -+ ?use_hidden_primary_key@handler@@UEAAXXZ -+ ?get_dynamic_partition_info@handler@@UEAAXPEAUPARTITION_INFO@@I@Z -+ ?read_first_row@handler@@UEAAHPEAEI@Z -+ ?read_range_next@handler@@UEAAHXZ -+ ?read_range_first@handler@@UEAAHPEBUst_key_range@@0_N1@Z -+ ?read_multi_range_first@handler@@UEAAHPEAPEAUst_key_multi_range@@PEAU2@I_NPEAUst_handler_buffer@@@Z -+ ?read_multi_range_next@handler@@UEAAHPEAPEAUst_key_multi_range@@@Z -+ ?index_read_idx_map@handler@@UEAAHPEAEIPEBEKW4ha_rkey_function@@@Z -+ ?print_error@handler@@UEAAXHH@Z -+ ?clone@handler@@UEAAPEAV1@PEAUst_mem_root@@@Z -+ ?get_auto_increment@handler@@UEAAX_K00PEA_K1@Z -+ ?index_next_same@handler@@UEAAHPEAEPEBEI@Z -+ ?get_error_message@handler@@UEAA_NHPEAVString@@@Z -+ ?ha_thd@handler@@IEBAPEAVTHD@@XZ -+ ?update_auto_increment@handler@@QEAAHXZ -+ ?ha_statistic_increment@handler@@IEBAXPEQsystem_status_var@@K@Z -+ ?trans_register_ha@@YAXPEAVTHD@@_NPEAUhandlerton@@@Z -+ ?cmp@Field_blob@@QEAAHPEBEI0I@Z -+ ?set_time@Field_timestamp@@QEAAXXZ -+ ?sql_print_error@@YAXPEBDZZ -+ ?sql_print_warning@@YAXPEBDZZ -+ ?check_global_access@@YA_NPEAVTHD@@K@Z -+ ?schema_table_store_record@@YA_NPEAVTHD@@PEAUst_table@@@Z -+ ?get_quote_char_for_identifier@@YAHPEAVTHD@@PEBDI@Z -+ ?copy@String@@QEAA_NXZ -+ ?copy@String@@QEAA_NAEBV1@@Z -+ ?copy@String@@QEAA_NPEBDIPEAUcharset_info_st@@@Z -+ ?copy_and_convert@@YAIPEADIPEAUcharset_info_st@@PEBDI1PEAI@Z -+ ?filename_to_tablename@@YAIPEBDPEADI@Z -+ ?strconvert@@YAIPEAUcharset_info_st@@PEBD0PEADIPEAI@Z -+ ?calculate_key_len@@YAIPEAUst_table@@IPEBEK@Z -+ ?sql_alloc@@YAPEAX_K@Z -+ ?localtime_to_TIME@@YAXPEAUst_mysql_time@@PEAUtm@@@Z -+ ?push_warning@@YAPEAVMYSQL_ERROR@@PEAVTHD@@W4enum_warning_level@1@IPEBD@Z -+ ?push_warning_printf@@YAXPEAVTHD@@W4enum_warning_level@MYSQL_ERROR@@IPEBDZZ -+ ?drop_table@handler@@EEAAXPEBD@Z -+ ?column_bitmaps_signal@handler@@UEAAXXZ -+ ?delete_table@handler@@MEAAHPEBD@Z -+ ?rename_table@handler@@MEAAHPEBD0@Z -+ ?key_map_empty@@3V?$Bitmap@$0EA@@@B -+ ?THR_THD@@3PEAVTHD@@EA -+ ?end_of_list@@3Ulist_node@@A -+ ?mysql_tmpdir_list@@3Ust_my_tmpdir@@A -+ mysql_query_cache_invalidate4 -+ thd_query -+ thd_sql_command -+ thd_get_thread_id -+ thd_get_xid -+ thd_slave_thread -+ thd_non_transactional_update -+ thd_mark_transaction_to_rollback -+ thd_security_context -+ thd_charset -+ thd_test_options -+ thd_ha_data -+ thd_killed -+ thd_tx_isolation -+ thd_tablespace_op -+ thd_sql_command -+ thd_memdup -+ thd_make_lex_string -+ thd_in_lock_tables -+ thd_binlog_format -+ _my_hash_init -+ my_hash_free -+ my_tmpdir -+ check_if_legal_filename -+ my_filename -+ my_sync_dir_by_file -+ alloc_root -+ thr_lock_data_init -+ thr_lock_init -+ thr_lock_delete -+ my_multi_malloc -+ get_charset -+ unpack_filename -+ my_hash_insert -+ my_hash_search -+ my_hash_delete -+ mysql_bin_log_file_pos -+ mysql_bin_log_file_name -+ mysqld_embedded -+ my_thread_name -+ my_malloc -+ my_no_flags_free -+ _sanity -+ _mymalloc -+ _myfree -+ _my_strdup -+ _my_thread_var -+ my_error -+ pthread_cond_init -+ pthread_cond_signal -+ pthread_cond_wait -+ pthread_cond_destroy -+ localtime_r -+ my_strdup -+ deflate -+ deflateEnd -+ deflateReset -+ deflateInit2_ -+ inflateEnd -+ inflateInit_ -+ inflate -+ compressBound -+ inflateInit2_ -+ adler32 -+ longlong2str -+ strend -+ my_snprintf - -diff -Nur win/configure.js.orig win/configure.js ---- win/configure.js.orig 2008-09-26 21:18:37 -05:00 -+++ win/configure.js 2008-10-01 11:21:27 -05:00 -@@ -50,6 +50,7 @@ - case "EMBED_MANIFESTS": - case "EXTRA_DEBUG": - case "WITH_EMBEDDED_SERVER": -+ case "INNODB_DYNAMIC_PLUGIN": - configfile.WriteLine("SET (" + args.Item(i) + " TRUE)"); - break; - case "MYSQL_SERVER_SUFFIX": From 672c04d6576ae9b6e972ebee557a784b8920efbb Mon Sep 17 00:00:00 2001 From: Satya B Date: Mon, 12 Oct 2009 18:26:02 +0530 Subject: [PATCH 120/146] Applying Innodb Plugin 1.0.5 snapshot, part 14 Sync the storage/innodb_plugin/mysql-test directory with Innodb_plugin-1.0.5/mysql-test directory Update the README file --- storage/innodb_plugin/README | 2 +- .../mysql-test/innodb-analyze.test | 2 + .../mysql-test/innodb-consistent-master.opt | 1 + .../mysql-test/innodb-consistent.result | 35 +++++++++ .../mysql-test/innodb-consistent.test | 58 +++++++++++++++ .../mysql-test/innodb-zip.result | 2 +- .../innodb_plugin/mysql-test/innodb-zip.test | 2 +- .../mysql-test/innodb_bug36169.test | 4 + .../mysql-test/innodb_bug36172.test | 6 ++ .../mysql-test/innodb_bug44369.result | 14 ++++ .../mysql-test/innodb_bug44369.test | 21 ++++++ .../mysql-test/innodb_bug44571.result | 9 +++ .../mysql-test/innodb_bug44571.test | 17 +++++ .../mysql-test/innodb_bug46000.result | 17 +++++ .../mysql-test/innodb_bug46000.test | 34 +++++++++ .../mysql-test/innodb_file_format.result | 1 + .../mysql-test/innodb_file_format.test | 1 + storage/innodb_plugin/revert_gen.sh | 8 ++ storage/innodb_plugin/scripts/export.sh | 74 +++++++++++++++++++ 19 files changed, 305 insertions(+), 3 deletions(-) create mode 100644 storage/innodb_plugin/mysql-test/innodb-consistent-master.opt create mode 100644 storage/innodb_plugin/mysql-test/innodb-consistent.result create mode 100644 storage/innodb_plugin/mysql-test/innodb-consistent.test create mode 100644 storage/innodb_plugin/mysql-test/innodb_bug44369.result create mode 100644 storage/innodb_plugin/mysql-test/innodb_bug44369.test create mode 100644 storage/innodb_plugin/mysql-test/innodb_bug44571.result create mode 100644 storage/innodb_plugin/mysql-test/innodb_bug44571.test create mode 100644 storage/innodb_plugin/mysql-test/innodb_bug46000.result create mode 100644 storage/innodb_plugin/mysql-test/innodb_bug46000.test create mode 100755 storage/innodb_plugin/revert_gen.sh create mode 100755 storage/innodb_plugin/scripts/export.sh diff --git a/storage/innodb_plugin/README b/storage/innodb_plugin/README index 56aa8058224..075508e1ae0 100644 --- a/storage/innodb_plugin/README +++ b/storage/innodb_plugin/README @@ -1,4 +1,4 @@ -This is the source of the InnoDB Plugin 1.0.4 for MySQL 5.1 +This is the source of the InnoDB Plugin 1.0.5 for MySQL 5.1 =========================================================== Instructions for compiling the plugin: diff --git a/storage/innodb_plugin/mysql-test/innodb-analyze.test b/storage/innodb_plugin/mysql-test/innodb-analyze.test index d5d6d698170..9bdb9db697c 100644 --- a/storage/innodb_plugin/mysql-test/innodb-analyze.test +++ b/storage/innodb_plugin/mysql-test/innodb-analyze.test @@ -11,6 +11,7 @@ -- disable_result_log -- enable_warnings +let $sample_pages=`select @@innodb_stats_sample_pages`; SET GLOBAL innodb_stats_sample_pages=0; # check that the value has been adjusted to 1 @@ -61,3 +62,4 @@ SET GLOBAL innodb_stats_sample_pages=16; ANALYZE TABLE innodb_analyze; DROP TABLE innodb_analyze; +EVAL SET GLOBAL innodb_stats_sample_pages=$sample_pages; diff --git a/storage/innodb_plugin/mysql-test/innodb-consistent-master.opt b/storage/innodb_plugin/mysql-test/innodb-consistent-master.opt new file mode 100644 index 00000000000..8cca44767da --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb-consistent-master.opt @@ -0,0 +1 @@ +--innodb_lock_wait_timeout=2 diff --git a/storage/innodb_plugin/mysql-test/innodb-consistent.result b/storage/innodb_plugin/mysql-test/innodb-consistent.result new file mode 100644 index 00000000000..9115791b99c --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb-consistent.result @@ -0,0 +1,35 @@ +drop table if exists t1; +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +create table t2 like t1; +insert into t2 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; +begin; +replace into t1 select * from t2; +set session transaction isolation level read committed; +set autocommit=0; +delete from t2 where a=5; +commit; +delete from t2; +commit; +commit; +begin; +insert into t1 select * from t2; +set session transaction isolation level read committed; +set autocommit=0; +delete from t2 where a=5; +commit; +delete from t2; +commit; +commit; +select * from t1; +a +1 +2 +3 +4 +5 +6 +7 +drop table t1; +drop table t2; diff --git a/storage/innodb_plugin/mysql-test/innodb-consistent.test b/storage/innodb_plugin/mysql-test/innodb-consistent.test new file mode 100644 index 00000000000..791600fc8a7 --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb-consistent.test @@ -0,0 +1,58 @@ +-- source include/not_embedded.inc +-- source include/have_innodb.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# REPLACE INTO ... SELECT and INSERT INTO ... SELECT should do +# a consistent read of the source table. + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +create table t2 like t1; +insert into t2 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; + +# REPLACE INTO ... SELECT case +begin; +# this should not result in any locks on t2. +replace into t1 select * from t2; + +connection b; +set session transaction isolation level read committed; +set autocommit=0; +# should not cuase a lock wait. +delete from t2 where a=5; +commit; +delete from t2; +commit; +connection a; +commit; + +# INSERT INTO ... SELECT case +begin; +# this should not result in any locks on t2. +insert into t1 select * from t2; + +connection b; +set session transaction isolation level read committed; +set autocommit=0; +# should not cuase a lock wait. +delete from t2 where a=5; +commit; +delete from t2; +commit; +connection a; +commit; + +select * from t1; +drop table t1; +drop table t2; + +connection default; +disconnect a; +disconnect b; diff --git a/storage/innodb_plugin/mysql-test/innodb-zip.result b/storage/innodb_plugin/mysql-test/innodb-zip.result index c81401743a5..b26c4112826 100644 --- a/storage/innodb_plugin/mysql-test/innodb-zip.result +++ b/storage/innodb_plugin/mysql-test/innodb-zip.result @@ -141,7 +141,7 @@ drop table t1; CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs -CREATE TABLE t1(c TEXT, PRIMARY KEY (c(439))) +CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512)); DROP TABLE t1; diff --git a/storage/innodb_plugin/mysql-test/innodb-zip.test b/storage/innodb_plugin/mysql-test/innodb-zip.test index ddc39d44487..5bcd0e3c824 100644 --- a/storage/innodb_plugin/mysql-test/innodb-zip.test +++ b/storage/innodb_plugin/mysql-test/innodb-zip.test @@ -105,7 +105,7 @@ drop table t1; --error ER_TOO_BIG_ROWSIZE CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; -CREATE TABLE t1(c TEXT, PRIMARY KEY (c(439))) +CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512)); DROP TABLE t1; diff --git a/storage/innodb_plugin/mysql-test/innodb_bug36169.test b/storage/innodb_plugin/mysql-test/innodb_bug36169.test index d3566d3eb39..5bf55193b5c 100644 --- a/storage/innodb_plugin/mysql-test/innodb_bug36169.test +++ b/storage/innodb_plugin/mysql-test/innodb_bug36169.test @@ -5,6 +5,8 @@ -- source include/have_innodb.inc +let $file_format=`select @@innodb_file_format`; +let $file_per_table=`select @@innodb_file_per_table`; SET GLOBAL innodb_file_format='Barracuda'; SET GLOBAL innodb_file_per_table=ON; @@ -1153,3 +1155,5 @@ DROP TABLE IF EXISTS table4; DROP TABLE IF EXISTS table5; DROP TABLE IF EXISTS table6; +EVAL SET GLOBAL innodb_file_format=$file_format; +EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/storage/innodb_plugin/mysql-test/innodb_bug36172.test b/storage/innodb_plugin/mysql-test/innodb_bug36172.test index 666d4a2f4b7..c6c4e6fae47 100644 --- a/storage/innodb_plugin/mysql-test/innodb_bug36172.test +++ b/storage/innodb_plugin/mysql-test/innodb_bug36172.test @@ -14,6 +14,9 @@ SET storage_engine=InnoDB; -- disable_query_log -- disable_result_log +let $file_format=`select @@innodb_file_format`; +let $file_format_check=`select @@innodb_file_format_check`; +let $file_per_table=`select @@innodb_file_per_table`; SET GLOBAL innodb_file_format='Barracuda'; SET GLOBAL innodb_file_per_table=on; @@ -24,3 +27,6 @@ CHECK TABLE table0 EXTENDED; INSERT IGNORE INTO `table0` SET `col19` = '19940127002709', `col20` = 2383927.9055146948, `col21` = 4293243420.5621204000, `col22` = '20511211123705', `col23` = 4289899778.6573381000, `col24` = 4293449279.0540481000, `col25` = 'emphysemic', `col26` = 'dentally', `col27` = '2347406', `col28` = 'eruct', `col30` = 1222, `col31` = 4294372994.9941406000, `col32` = 4291385574.1173744000, `col33` = 'borrowing\'s', `col34` = 'septics', `col35` = 'ratter\'s', `col36` = 'Kaye', `col37` = 'Florentia', `col38` = 'allium', `col39` = 'barkeep', `col40` = '19510407003441', `col41` = 4293559200.4215522000, `col42` = 22482, `col43` = 'decussate', `col44` = 'Brom\'s', `col45` = 'violated', `col46` = 4925506.4635456400, `col47` = 930549, `col48` = '51296066', `col49` = 'voluminously', `col50` = '29306676', `col51` = -88, `col52` = -2153690, `col53` = 4290250202.1464887000, `col54` = 'expropriation', `col55` = 'Aberdeen\'s', `col56` = 20343, `col58` = '19640415171532', `col59` = 'extern', `col60` = 'Ubana', `col61` = 4290487961.8539081000, `col62` = '2147', `col63` = -24271, `col64` = '20750801194548', `col65` = 'Cunaxa\'s', `col66` = 'pasticcio', `col67` = 2795817, `col68` = 'Indore\'s', `col70` = 6864127, `col71` = '1817832', `col72` = '20540506114211', `col73` = '20040101012300', `col74` = 'rationalized', `col75` = '45522', `col76` = 'indene', `col77` = -6964559, `col78` = 4247535.5266884370, `col79` = '20720416124357', `col80` = '2143', `col81` = 4292060102.4466386000, `col82` = 'striving', `col83` = 'boneblack\'s', `col84` = 'redolent', `col85` = 6489697.9009369183, `col86` = 4287473465.9731131000, `col87` = 7726015, `col88` = 'perplexed', `col89` = '17153791', `col90` = 5478587.1108127078, `col91` = 4287091404.7004304000, `col92` = 'Boulez\'s', `col93` = '2931278'; CHECK TABLE table0 EXTENDED; DROP TABLE table0; +EVAL SET GLOBAL innodb_file_format=$file_format; +EVAL SET GLOBAL innodb_file_format_check=$file_format_check; +EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/storage/innodb_plugin/mysql-test/innodb_bug44369.result b/storage/innodb_plugin/mysql-test/innodb_bug44369.result new file mode 100644 index 00000000000..e4b84ecac19 --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb_bug44369.result @@ -0,0 +1,14 @@ +create table bug44369 (DB_ROW_ID int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +create table bug44369 (db_row_id int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +show errors; +Level Code Message +Error 1005 Error creating table 'test/bug44369' with column name 'db_row_id'. 'db_row_id' is a reserved name. Please try to re-create the table with a different column name. +Error 1005 Can't create table 'test.bug44369' (errno: -1) +create table bug44369 (db_TRX_Id int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +show errors; +Level Code Message +Error 1005 Error creating table 'test/bug44369' with column name 'db_TRX_Id'. 'db_TRX_Id' is a reserved name. Please try to re-create the table with a different column name. +Error 1005 Can't create table 'test.bug44369' (errno: -1) diff --git a/storage/innodb_plugin/mysql-test/innodb_bug44369.test b/storage/innodb_plugin/mysql-test/innodb_bug44369.test new file mode 100644 index 00000000000..495059eb5e6 --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb_bug44369.test @@ -0,0 +1,21 @@ +# This is the test for bug 44369. We should +# block table creation with columns match +# some innodb internal reserved key words, +# both case sensitively and insensitely. + +--source include/have_innodb.inc + +# This create table operation should fail. +--error ER_CANT_CREATE_TABLE +create table bug44369 (DB_ROW_ID int) engine=innodb; + +# This create should fail as well +--error ER_CANT_CREATE_TABLE +create table bug44369 (db_row_id int) engine=innodb; + +show errors; + +--error ER_CANT_CREATE_TABLE +create table bug44369 (db_TRX_Id int) engine=innodb; + +show errors; diff --git a/storage/innodb_plugin/mysql-test/innodb_bug44571.result b/storage/innodb_plugin/mysql-test/innodb_bug44571.result new file mode 100644 index 00000000000..36374edcb3e --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb_bug44571.result @@ -0,0 +1,9 @@ +CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; +ALTER TABLE bug44571 CHANGE foo bar INT; +ALTER TABLE bug44571 ADD INDEX bug44571b (foo); +ERROR 42000: Key column 'foo' doesn't exist in table +ALTER TABLE bug44571 ADD INDEX bug44571b (bar); +ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it +CREATE INDEX bug44571b ON bug44571 (bar); +ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it +DROP TABLE bug44571; diff --git a/storage/innodb_plugin/mysql-test/innodb_bug44571.test b/storage/innodb_plugin/mysql-test/innodb_bug44571.test new file mode 100644 index 00000000000..685463ceff9 --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb_bug44571.test @@ -0,0 +1,17 @@ +# +# Bug#44571 InnoDB Plugin crashes on ADD INDEX +# http://bugs.mysql.com/44571 +# +-- source include/have_innodb.inc + +CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; +ALTER TABLE bug44571 CHANGE foo bar INT; +-- error ER_KEY_COLUMN_DOES_NOT_EXITS +ALTER TABLE bug44571 ADD INDEX bug44571b (foo); +# The following will fail, because the CHANGE foo bar was +# not communicated to InnoDB. +--error ER_NOT_KEYFILE +ALTER TABLE bug44571 ADD INDEX bug44571b (bar); +--error ER_NOT_KEYFILE +CREATE INDEX bug44571b ON bug44571 (bar); +DROP TABLE bug44571; diff --git a/storage/innodb_plugin/mysql-test/innodb_bug46000.result b/storage/innodb_plugin/mysql-test/innodb_bug46000.result new file mode 100644 index 00000000000..ccff888a48d --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb_bug46000.result @@ -0,0 +1,17 @@ +create table bug46000(`id` int,key `GEN_CLUST_INDEX`(`id`))engine=innodb; +ERROR HY000: Can't create table 'test.bug46000' (errno: -1) +create table bug46000(`id` int, key `GEN_clust_INDEX`(`id`))engine=innodb; +ERROR HY000: Can't create table 'test.bug46000' (errno: -1) +show errors; +Level Code Message +Error 1005 Cannot Create Index with name 'GEN_CLUST_INDEX'. The name is reserved for the system default primary index. +Error 1005 Can't create table 'test.bug46000' (errno: -1) +create table bug46000(id int) engine=innodb; +create index GEN_CLUST_INDEX on bug46000(id); +ERROR HY000: Can't create table '#sql-temporary' (errno: -1) +show errors; +Level Code Message +Error 1005 Cannot Create Index with name 'GEN_CLUST_INDEX'. The name is reserved for the system default primary index. +Error 1005 Can't create table '#sql-temporary' (errno: -1) +create index idx on bug46000(id); +drop table bug46000; diff --git a/storage/innodb_plugin/mysql-test/innodb_bug46000.test b/storage/innodb_plugin/mysql-test/innodb_bug46000.test new file mode 100644 index 00000000000..80c18c58ef0 --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb_bug46000.test @@ -0,0 +1,34 @@ +# This is the test for bug 46000. We shall +# block any index creation with the name of +# "GEN_CLUST_INDEX", which is the reserved +# name for innodb default primary index. + +--source include/have_innodb.inc + +# This 'create table' operation should fail because of +# using the reserve name as its index name. +--error ER_CANT_CREATE_TABLE +create table bug46000(`id` int,key `GEN_CLUST_INDEX`(`id`))engine=innodb; + +# Mixed upper/lower case of the reserved key words +--error ER_CANT_CREATE_TABLE +create table bug46000(`id` int, key `GEN_clust_INDEX`(`id`))engine=innodb; + +show errors; + +create table bug46000(id int) engine=innodb; + +# This 'create index' operation should fail. +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +create index GEN_CLUST_INDEX on bug46000(id); + +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +show errors; + +# This 'create index' operation should succeed, no +# temp table left from last failed create index +# operation. +create index idx on bug46000(id); + +drop table bug46000; diff --git a/storage/innodb_plugin/mysql-test/innodb_file_format.result b/storage/innodb_plugin/mysql-test/innodb_file_format.result index 9cfac5f001c..8e9a317308b 100644 --- a/storage/innodb_plugin/mysql-test/innodb_file_format.result +++ b/storage/innodb_plugin/mysql-test/innodb_file_format.result @@ -42,3 +42,4 @@ ERROR HY000: Incorrect arguments to SET select @@innodb_file_format_check; @@innodb_file_format_check Barracuda +set global innodb_file_format_check=antelope; diff --git a/storage/innodb_plugin/mysql-test/innodb_file_format.test b/storage/innodb_plugin/mysql-test/innodb_file_format.test index 62ce4157183..d63c9b0228f 100644 --- a/storage/innodb_plugin/mysql-test/innodb_file_format.test +++ b/storage/innodb_plugin/mysql-test/innodb_file_format.test @@ -26,3 +26,4 @@ set global innodb_file_format=on; --error ER_WRONG_ARGUMENTS set global innodb_file_format=off; select @@innodb_file_format_check; +set global innodb_file_format_check=antelope; diff --git a/storage/innodb_plugin/revert_gen.sh b/storage/innodb_plugin/revert_gen.sh new file mode 100755 index 00000000000..231e05a21e0 --- /dev/null +++ b/storage/innodb_plugin/revert_gen.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# +# revert changes to all generated files. this is useful in some situations +# when merging changes between branches. + +set -eu + +svn revert include/pars0grm.h pars/pars0grm.h pars/lexyy.c pars/pars0grm.c diff --git a/storage/innodb_plugin/scripts/export.sh b/storage/innodb_plugin/scripts/export.sh new file mode 100755 index 00000000000..2a4355c1e43 --- /dev/null +++ b/storage/innodb_plugin/scripts/export.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# +# export current working directory in a format suitable for sending to MySQL +# as a snapshot. also generates the actual snapshot and sends it to MySQL. + +set -eu + +die () { + echo $* + exit 1 +} + +if [ $# -ne 2 ] ; then + die "Usage: export.sh revision-number-of-last-snapshot current-revision-number" +fi + +# If we are run from within the scripts/ directory then change directory to +# one level up so that the relative paths work. +DIR=`basename $PWD` + +if [ "${DIR}" = "scripts" ]; then + cd .. +fi + +START_REV=$(($1 + 1)) +END_REV=$2 + +set +u +if test -z $EDITOR; then + die "\$EDITOR is not set" +fi +set -u + +rm -rf to-mysql +mkdir to-mysql{,/storage,/patches,/mysql-test{,/t,/r,/include}} +svn log -v -r "$START_REV:BASE" > to-mysql/log +svn export -q . to-mysql/storage/innobase + +REV=$START_REV +while [ $REV -le $END_REV ] +do + PATCH=to-mysql/patches/r$REV.patch + svn log -v -r$REV > $PATCH + if [ $(wc -c < $PATCH) -gt 73 ] + then + svn diff -r$(($REV-1)):$REV >> $PATCH + else + rm $PATCH + fi + REV=$(($REV + 1)) +done + +cd to-mysql/storage/innobase + +mv mysql-test/*.test mysql-test/*.opt ../../mysql-test/t +mv mysql-test/*.result ../../mysql-test/r +mv mysql-test/*.inc ../../mysql-test/include +rmdir mysql-test + +rm setup.sh export.sh revert_gen.sh compile-innodb-debug compile-innodb + +cd ../.. +$EDITOR log +cd .. + +fname="innodb-5.1-ss$2.tar.gz" + +rm -f $fname +tar czf $fname to-mysql +scp $fname mysql:snapshots +rm $fname +rm -rf to-mysql + +echo "Sent $fname to MySQL" From 814a3cc2469e365064ab495d378d00faa9abd41e Mon Sep 17 00:00:00 2001 From: Date: Tue, 13 Oct 2009 10:26:15 +0800 Subject: [PATCH 121/146] Bug#45578: Test binlog_tmp_table fails ramdonly on PB2: Unknown table 't2' The bug has been closed. --- mysql-test/collections/default.experimental | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index 50c5a71e252..214b732e5cb 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -1,6 +1,5 @@ funcs_1.charset_collation_1 # depends on compile-time decisions main.plugin_load @solaris # Bug#42144 -binlog.binlog_tmp_table* # Bug#45578: Test binlog_tmp_table fails ramdonly on PB2: Unknown table 't2' main.ctype_gbk_binlog @solaris # Bug#46010: main.ctype_gbk_binlog fails sporadically : Table 't2' already exists rpl.rpl_row_create_table* # Bug#45576: rpl_row_create_table fails on PB2 rpl_ndb.rpl_ndb_log # Bug#38998 From 2bcb511072b4f38636c9e54653a419e66c5e6b89 Mon Sep 17 00:00:00 2001 From: Satya B Date: Tue, 13 Oct 2009 12:41:42 +0530 Subject: [PATCH 122/146] Applying Innodb Plugin 1.0.5 snapshot, part 15 - Fix a typo and adjust the CMakeLists.txt - Remove the README file as it doesn't exist in Innodb plugin 1.0.5 --- storage/innodb_plugin/CMakeLists.txt | 19 ++---------------- storage/innodb_plugin/README | 29 ---------------------------- 2 files changed, 2 insertions(+), 46 deletions(-) delete mode 100644 storage/innodb_plugin/README diff --git a/storage/innodb_plugin/CMakeLists.txt b/storage/innodb_plugin/CMakeLists.txt index 1b05b5be6b9..25cd212a473 100644 --- a/storage/innodb_plugin/CMakeLists.txt +++ b/storage/innodb_plugin/CMakeLists.txt @@ -31,7 +31,7 @@ ENDIF (CMAKE_SIZEOF_VOID_P MATCHES 8) # Include directories under innodb_plugin INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/innodb_plugin/include - ${CMAKE_SOURCE_DIR}/storage/innodfb_plugin/handler) + ${CMAKE_SOURCE_DIR}/storage/innodb_plugin/handler) # Include directories under mysql INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include @@ -80,20 +80,5 @@ SET(INNODB_PLUGIN_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea usr/usr0sess.c ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c ut/ut0list.c ut/ut0wqueue.c) -ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS -DINNODB_RW_LOCKS_USE_ATOMICS -DIB_HAVE_PAUSE_INSTRUCTION) +ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS -DIB_HAVE_PAUSE_INSTRUCTION) MYSQL_STORAGE_ENGINE(INNODB_PLUGIN) -IF (MYSQL_VERSION_ID GREATER "50137") - IF (WITH_INNOBASE_STORAGE_ENGINE) - MYSQL_STORAGE_ENGINE(INNOBASE) - ELSE (WITH_INNOBASE_STORAGE_ENGINE) - SET (INNODB_SOURCES ${INNOBASE_SOURCES}) - MYSQL_STORAGE_ENGINE(INNODB) - ENDIF (WITH_INNOBASE_STORAGE_ENGINE) -ELSE (MYSQL_VERSION_ID GREATER "50137") - IF (NOT SOURCE_SUBLIBS) - ADD_DEFINITIONS(-D_WIN32 -DMYSQL_SERVER) - ADD_LIBRARY(innobase STATIC ${INNOBASE_SOURCES}) - # Require mysqld_error.h, which is built as part of the GenError - ADD_DEPENDENCIES(innobase GenError) - ENDIF (NOT SOURCE_SUBLIBS) -ENDIF (MYSQL_VERSION_ID GREATER "50137") diff --git a/storage/innodb_plugin/README b/storage/innodb_plugin/README deleted file mode 100644 index 075508e1ae0..00000000000 --- a/storage/innodb_plugin/README +++ /dev/null @@ -1,29 +0,0 @@ -This is the source of the InnoDB Plugin 1.0.5 for MySQL 5.1 -=========================================================== - -Instructions for compiling the plugin: --------------------------------------- - -1. Get the latest MySQL 5.1 sources from - http://dev.mysql.com/downloads/mysql/5.1.html#source - -2. Replace the contents of the mysql-5.1.N/storage/innobase/ directory - with the contents of this directory. - -3. Optional (only necessary if you are going to run tests from the - mysql-test suite): cd into the innobase directory and run ./setup.sh - -4. Compile MySQL as usual. - -5. Enjoy! - -See the online documentation for more detailed instructions: -http://www.innodb.com/doc/innodb_plugin-1.0/innodb-plugin-installation.html - -For more information about InnoDB visit -http://www.innodb.com - -Please report any problems or issues with the plugin in the InnoDB Forums -http://forums.innodb.com/ or in the MySQL Bugs database http://bugs.mysql.com - -Thank you for using the InnoDB plugin! From 5db734a896bff99d044eb6e08bb5c849d04915ef Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Tue, 13 Oct 2009 19:49:32 +0400 Subject: [PATCH 123/146] Bug #47123: Endless 100% CPU loop with STRAIGHT_JOIN The problem was in incorrect handling of predicates involving NULL as a constant value by the range optimizer. For example, when creating a SEL_ARG node from a condition of the form "field < const" (which would normally result in the "NULL < field < const" SEL_ARG), the special case when "const" is NULL was not taken into account, so "NULL < field < NULL" was produced for the "field < NULL" condition. As a result, SEL_ARG structures of this form could not be further optimized which in turn could lead to incorrectly constructed SEL_ARG trees. In particular, code assuming SEL_ARG structures to always form a sequence of ordered disjoint intervals could enter an infinite loop under some circumstances. Fixed by changing get_mm_leaf() so that for any sargable predicate except "<=>" involving NULL as a constant, "empty" SEL_ARG is returned, since such a predicate is always false. --- mysql-test/r/range.result | 9 +++++++++ mysql-test/t/range.test | 10 ++++++++++ sql/opt_range.cc | 11 +++++++++++ 3 files changed, 30 insertions(+) diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index cc5e8d2be96..69ae81982a9 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -1219,3 +1219,12 @@ explain select * from t2 where a=1000 and b<11; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ref a a 5 const 502 Using where drop table t1, t2; +# +# Bug #47123: Endless 100% CPU loop with STRAIGHT_JOIN +# +CREATE TABLE t1(a INT, KEY(a)); +INSERT INTO t1 VALUES (1), (NULL); +SELECT * FROM t1 WHERE a <> NULL and (a <> NULL or a <= NULL); +a +DROP TABLE t1; +# End of 5.1 tests diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index e1411e7fd46..7b35f69c041 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1046,3 +1046,13 @@ explain select * from t2 where a=1000 and b<11; drop table t1, t2; +--echo # +--echo # Bug #47123: Endless 100% CPU loop with STRAIGHT_JOIN +--echo # + +CREATE TABLE t1(a INT, KEY(a)); +INSERT INTO t1 VALUES (1), (NULL); +SELECT * FROM t1 WHERE a <> NULL and (a <> NULL or a <= NULL); +DROP TABLE t1; + +--echo # End of 5.1 tests diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 2239aafbeec..cfaff76b96b 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -5887,6 +5887,17 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, goto end; } field->table->in_use->variables.sql_mode= orig_sql_mode; + + /* + Any sargable predicate except "<=>" involving NULL as a constant is always + FALSE + */ + if (type != Item_func::EQUAL_FUNC && field->is_real_null()) + { + tree= &null_element; + goto end; + } + str= (uchar*) alloc_root(alloc, key_part->store_length+1); if (!str) goto end; From 5ad32f3e89d835f5d53fd609d90a9f9cd6f0b7fc Mon Sep 17 00:00:00 2001 From: "karen.langford@sun.com" <> Date: Tue, 13 Oct 2009 20:50:37 +0200 Subject: [PATCH 124/146] Raise version number after cloning 5.0.87 --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index f2d95ff826c..11c97e517ba 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.87) +AM_INIT_AUTOMAKE(mysql, 5.0.88) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10 @@ -23,7 +23,7 @@ NDB_SHARED_LIB_VERSION=$NDB_SHARED_LIB_MAJOR_VERSION:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=87 +NDB_VERSION_BUILD=88 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From 0ece5891a28d9e7f8387573a4c69f2c278edd225 Mon Sep 17 00:00:00 2001 From: Date: Wed, 14 Oct 2009 09:39:05 +0800 Subject: [PATCH 125/146] Bug#46640: output from mysqlbinlog command in 5.1 breaks replication The BINLOG statement was sharing too much code with the slave SQL thread, introduced with the patch for Bug#32407. This caused statements to be logged with the wrong server_id, the id stored inside the events of the BINLOG statement rather than the id of the running server. Fix by rearranging code a bit so that only relevant parts of the code are executed by the BINLOG statement, and the server_id of the server executing the statements will not be overrided by the server_id stored in the 'format description BINLOG statement'. --- mysql-test/extra/binlog_tests/binlog.test | 39 ++++++ .../suite/binlog/r/binlog_row_binlog.result | 24 ++++ .../suite/binlog/r/binlog_stm_binlog.result | 21 +++ sql/log_event.cc | 66 +++++----- sql/log_event_old.cc | 124 +++++++++--------- sql/slave.cc | 61 ++++----- sql/slave.h | 3 +- sql/sql_binlog.cc | 51 +++---- 8 files changed, 233 insertions(+), 156 deletions(-) diff --git a/mysql-test/extra/binlog_tests/binlog.test b/mysql-test/extra/binlog_tests/binlog.test index 5d898d41a54..b819996acb0 100644 --- a/mysql-test/extra/binlog_tests/binlog.test +++ b/mysql-test/extra/binlog_tests/binlog.test @@ -270,3 +270,42 @@ INSERT INTO test.t1 VALUES (1), (2); CREATE TABLE test.t2 SELECT * FROM test.t1; USE test; DROP TABLES t1, t2; + +# +# Bug#46640 +# This test verifies if the server_id stored in the "format +# description BINLOG statement" will override the server_id +# of the server executing the statements. +# + +connect (fresh,localhost,root,,test); +connection fresh; + +RESET MASTER; +CREATE TABLE t1 (a INT PRIMARY KEY); + +# Format description event, with server_id = 10; +BINLOG ' +3u9kSA8KAAAAZgAAAGoAAAABAAQANS4xLjM1LW1hcmlhLWJldGExLWRlYnVnLWxvZwAAAAAAAAAA +AAAAAAAAAAAAAAAAAADe72RIEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC +'; + +# What server_id is logged for a statement? Should be our own, not the +# one from the format description event. +INSERT INTO t1 VALUES (1); + +# INSERT INTO t1 VALUES (2), with server_id=20. Check that this is logged +# with our own server id, not the 20 from the BINLOG statement. +BINLOG ' +3u9kSBMUAAAAKQAAAJEBAAAAABoAAAAAAAAABHRlc3QAAnQxAAEDAAA= +3u9kSBcUAAAAIgAAALMBAAAQABoAAAAAAAEAAf/+AgAAAA== +'; + +# Show binlog events to check that server ids are correct. +--replace_column 1 # 2 # 5 # +--replace_regex /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/ +SHOW BINLOG EVENTS; + +DROP TABLE t1; +disconnect fresh; + diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result index f6b5392dbc8..4d32a4f4739 100644 --- a/mysql-test/suite/binlog/r/binlog_row_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result @@ -1309,3 +1309,27 @@ INSERT INTO test.t1 VALUES (1), (2); CREATE TABLE test.t2 SELECT * FROM test.t1; USE test; DROP TABLES t1, t2; +RESET MASTER; +CREATE TABLE t1 (a INT PRIMARY KEY); +BINLOG ' +3u9kSA8KAAAAZgAAAGoAAAABAAQANS4xLjM1LW1hcmlhLWJldGExLWRlYnVnLWxvZwAAAAAAAAAA +AAAAAAAAAAAAAAAAAADe72RIEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC +'; +INSERT INTO t1 VALUES (1); +BINLOG ' +3u9kSBMUAAAAKQAAAJEBAAAAABoAAAAAAAAABHRlc3QAAnQxAAEDAAA= +3u9kSBcUAAAAIgAAALMBAAAQABoAAAAAAAEAAf/+AgAAAA== +'; +SHOW BINLOG EVENTS; +Log_name Pos Event_type Server_id End_log_pos Info +# # Format_desc 1 # Server ver: #, Binlog ver: # +# # Query 1 # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY) +# # Query 1 # BEGIN +# # Table_map 1 # table_id: # (test.t1) +# # Write_rows 1 # table_id: # flags: STMT_END_F +# # Query 1 # COMMIT +# # Query 1 # BEGIN +# # Table_map 1 # table_id: # (test.t1) +# # Write_rows 1 # table_id: # flags: STMT_END_F +# # Query 1 # COMMIT +DROP TABLE t1; diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result index d05d3ccdb7a..eebcfceaa25 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result @@ -784,3 +784,24 @@ INSERT INTO test.t1 VALUES (1), (2); CREATE TABLE test.t2 SELECT * FROM test.t1; USE test; DROP TABLES t1, t2; +RESET MASTER; +CREATE TABLE t1 (a INT PRIMARY KEY); +BINLOG ' +3u9kSA8KAAAAZgAAAGoAAAABAAQANS4xLjM1LW1hcmlhLWJldGExLWRlYnVnLWxvZwAAAAAAAAAA +AAAAAAAAAAAAAAAAAADe72RIEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC +'; +INSERT INTO t1 VALUES (1); +BINLOG ' +3u9kSBMUAAAAKQAAAJEBAAAAABoAAAAAAAAABHRlc3QAAnQxAAEDAAA= +3u9kSBcUAAAAIgAAALMBAAAQABoAAAAAAAEAAf/+AgAAAA== +'; +SHOW BINLOG EVENTS; +Log_name Pos Event_type Server_id End_log_pos Info +# # Format_desc 1 # Server ver: #, Binlog ver: # +# # Query 1 # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY) +# # Query 1 # use `test`; INSERT INTO t1 VALUES (1) +# # Query 1 # BEGIN +# # Table_map 1 # table_id: # (test.t1) +# # Write_rows 1 # table_id: # flags: STMT_END_F +# # Query 1 # COMMIT +DROP TABLE t1; diff --git a/sql/log_event.cc b/sql/log_event.cc index ae7c4335f59..0e1500dac39 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3859,6 +3859,7 @@ bool Format_description_log_event::write(IO_CACHE* file) #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Format_description_log_event::do_apply_event(Relay_log_info const *rli) { + int ret= 0; DBUG_ENTER("Format_description_log_event::do_apply_event"); #ifdef USING_TRANSACTIONS @@ -3900,17 +3901,21 @@ int Format_description_log_event::do_apply_event(Relay_log_info const *rli) 0, then 96, then jump to first really asked event (which is >96). So this is ok. */ - DBUG_RETURN(Start_log_event_v3::do_apply_event(rli)); + ret= Start_log_event_v3::do_apply_event(rli); } - DBUG_RETURN(0); + + if (!ret) + { + /* Save the information describing this binlog */ + delete rli->relay_log.description_event_for_exec; + const_cast(rli)->relay_log.description_event_for_exec= this; + } + + DBUG_RETURN(ret); } int Format_description_log_event::do_update_pos(Relay_log_info *rli) { - /* save the information describing this binlog */ - delete rli->relay_log.description_event_for_exec; - rli->relay_log.description_event_for_exec= this; - if (server_id == (uint32) ::server_id) { /* @@ -7506,6 +7511,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) thd->reset_current_stmt_binlog_row_based(); const_cast(rli)->cleanup_context(thd, error); thd->is_slave_error= 1; + DBUG_RETURN(error); } /* This code would ideally be placed in do_update_pos() instead, but @@ -7534,6 +7540,14 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) const_cast(rli)->last_event_start_time= my_time(0); } + if (get_flags(STMT_END_F)) + if (error= rows_event_stmt_cleanup(rli, thd)) + rli->report(ERROR_LEVEL, error, + "Error in %s event: commit of row events failed, " + "table `%s`.`%s`", + get_type_str(), m_table->s->db.str, + m_table->s->table_name.str); + DBUG_RETURN(error); } @@ -7632,33 +7646,19 @@ Rows_log_event::do_update_pos(Relay_log_info *rli) if (get_flags(STMT_END_F)) { - if ((error= rows_event_stmt_cleanup(rli, thd)) == 0) - { - /* - Indicate that a statement is finished. - Step the group log position if we are not in a transaction, - otherwise increase the event log position. - */ - rli->stmt_done(log_pos, when); - - /* - Clear any errors pushed in thd->net.last_err* if for example "no key - found" (as this is allowed). This is a safety measure; apparently - those errors (e.g. when executing a Delete_rows_log_event of a - non-existing row, like in rpl_row_mystery22.test, - thd->net.last_error = "Can't find record in 't1'" and last_errno=1032) - do not become visible. We still prefer to wipe them out. - */ - thd->clear_error(); - } - else - { - rli->report(ERROR_LEVEL, error, - "Error in %s event: commit of row events failed, " - "table `%s`.`%s`", - get_type_str(), m_table->s->db.str, - m_table->s->table_name.str); - } + /* + Indicate that a statement is finished. + Step the group log position if we are not in a transaction, + otherwise increase the event log position. + */ + rli->stmt_done(log_pos, when); + /* + Clear any errors in thd->net.last_err*. It is not known if this is + needed or not. It is believed that any errors that may exist in + thd->net.last_err* are allowed. Examples of errors are "key not + found", which is produced in the test case rpl_row_conflicts.test + */ + thd->clear_error(); } else { diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index f14ebe49706..3389821a718 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1814,7 +1814,56 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) const_cast(rli)->last_event_start_time= my_time(0); } - DBUG_RETURN(0); + if (get_flags(STMT_END_F)) + { + /* + This is the end of a statement or transaction, so close (and + unlock) the tables we opened when processing the + Table_map_log_event starting the statement. + + OBSERVER. This will clear *all* mappings, not only those that + are open for the table. There is not good handle for on-close + actions for tables. + + NOTE. Even if we have no table ('table' == 0) we still need to be + here, so that we increase the group relay log position. If we didn't, we + could have a group relay log position which lags behind "forever" + (assume the last master's transaction is ignored by the slave because of + replicate-ignore rules). + */ + thd->binlog_flush_pending_rows_event(true); + + /* + If this event is not in a transaction, the call below will, if some + transactional storage engines are involved, commit the statement into + them and flush the pending event to binlog. + If this event is in a transaction, the call will do nothing, but a + Xid_log_event will come next which will, if some transactional engines + are involved, commit the transaction and flush the pending event to the + binlog. + */ + if (error= ha_autocommit_or_rollback(thd, 0)) + rli->report(ERROR_LEVEL, error, + "Error in %s event: commit of row events failed, " + "table `%s`.`%s`", + get_type_str(), m_table->s->db.str, + m_table->s->table_name.str); + + /* + Now what if this is not a transactional engine? we still need to + flush the pending event to the binlog; we did it with + thd->binlog_flush_pending_rows_event(). Note that we imitate + what is done for real queries: a call to + ha_autocommit_or_rollback() (sometimes only if involves a + transactional engine), and a call to be sure to have the pending + event flushed. + */ + + thd->reset_current_stmt_binlog_row_based(); + const_cast(rli)->cleanup_context(thd, 0); + } + + DBUG_RETURN(error); } @@ -1844,71 +1893,18 @@ Old_rows_log_event::do_update_pos(Relay_log_info *rli) if (get_flags(STMT_END_F)) { /* - This is the end of a statement or transaction, so close (and - unlock) the tables we opened when processing the - Table_map_log_event starting the statement. - - OBSERVER. This will clear *all* mappings, not only those that - are open for the table. There is not good handle for on-close - actions for tables. - - NOTE. Even if we have no table ('table' == 0) we still need to be - here, so that we increase the group relay log position. If we didn't, we - could have a group relay log position which lags behind "forever" - (assume the last master's transaction is ignored by the slave because of - replicate-ignore rules). - */ - thd->binlog_flush_pending_rows_event(true); - + Indicate that a statement is finished. + Step the group log position if we are not in a transaction, + otherwise increase the event log position. + */ + rli->stmt_done(log_pos, when); /* - If this event is not in a transaction, the call below will, if some - transactional storage engines are involved, commit the statement into - them and flush the pending event to binlog. - If this event is in a transaction, the call will do nothing, but a - Xid_log_event will come next which will, if some transactional engines - are involved, commit the transaction and flush the pending event to the - binlog. + Clear any errors in thd->net.last_err*. It is not known if this is + needed or not. It is believed that any errors that may exist in + thd->net.last_err* are allowed. Examples of errors are "key not + found", which is produced in the test case rpl_row_conflicts.test */ - error= ha_autocommit_or_rollback(thd, 0); - - /* - Now what if this is not a transactional engine? we still need to - flush the pending event to the binlog; we did it with - thd->binlog_flush_pending_rows_event(). Note that we imitate - what is done for real queries: a call to - ha_autocommit_or_rollback() (sometimes only if involves a - transactional engine), and a call to be sure to have the pending - event flushed. - */ - - thd->reset_current_stmt_binlog_row_based(); - rli->cleanup_context(thd, 0); - if (error == 0) - { - /* - Indicate that a statement is finished. - Step the group log position if we are not in a transaction, - otherwise increase the event log position. - */ - rli->stmt_done(log_pos, when); - - /* - Clear any errors pushed in thd->net.client_last_err* if for - example "no key found" (as this is allowed). This is a safety - measure; apparently those errors (e.g. when executing a - Delete_rows_log_event_old of a non-existing row, like in - rpl_row_mystery22.test, thd->net.last_error = "Can't - find record in 't1'" and last_errno=1032) do not become - visible. We still prefer to wipe them out. - */ - thd->clear_error(); - } - else - rli->report(ERROR_LEVEL, error, - "Error in %s event: commit of row events failed, " - "table `%s`.`%s`", - get_type_str(), m_table->s->db.str, - m_table->s->table_name.str); + thd->clear_error(); } else { diff --git a/sql/slave.cc b/sql/slave.cc index 82c9d035fd2..9718b54ea9e 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2082,8 +2082,7 @@ static int has_temporary_error(THD *thd) @retval 2 No error calling ev->apply_event(), but error calling ev->update_pos(). */ -int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, - bool skip) +int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli) { int exec_res= 0; @@ -2128,38 +2127,34 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, ev->when= my_time(0); ev->thd = thd; // because up to this point, ev->thd == 0 - if (skip) - { - int reason= ev->shall_skip(rli); - if (reason == Log_event::EVENT_SKIP_COUNT) - --rli->slave_skip_counter; - pthread_mutex_unlock(&rli->data_lock); - if (reason == Log_event::EVENT_SKIP_NOT) - exec_res= ev->apply_event(rli); -#ifndef DBUG_OFF - /* - This only prints information to the debug trace. - - TODO: Print an informational message to the error log? - */ - static const char *const explain[] = { - // EVENT_SKIP_NOT, - "not skipped", - // EVENT_SKIP_IGNORE, - "skipped because event should be ignored", - // EVENT_SKIP_COUNT - "skipped because event skip counter was non-zero" - }; - DBUG_PRINT("info", ("OPTION_BEGIN: %d; IN_STMT: %d", - thd->options & OPTION_BEGIN ? 1 : 0, - rli->get_flag(Relay_log_info::IN_STMT))); - DBUG_PRINT("skip_event", ("%s event was %s", - ev->get_type_str(), explain[reason])); -#endif - } - else + int reason= ev->shall_skip(rli); + if (reason == Log_event::EVENT_SKIP_COUNT) + --rli->slave_skip_counter; + pthread_mutex_unlock(&rli->data_lock); + if (reason == Log_event::EVENT_SKIP_NOT) exec_res= ev->apply_event(rli); +#ifndef DBUG_OFF + /* + This only prints information to the debug trace. + + TODO: Print an informational message to the error log? + */ + static const char *const explain[] = { + // EVENT_SKIP_NOT, + "not skipped", + // EVENT_SKIP_IGNORE, + "skipped because event should be ignored", + // EVENT_SKIP_COUNT + "skipped because event skip counter was non-zero" + }; + DBUG_PRINT("info", ("OPTION_BEGIN: %d; IN_STMT: %d", + thd->options & OPTION_BEGIN ? 1 : 0, + rli->get_flag(Relay_log_info::IN_STMT))); + DBUG_PRINT("skip_event", ("%s event was %s", + ev->get_type_str(), explain[reason])); +#endif + DBUG_PRINT("info", ("apply_event error = %d", exec_res)); if (exec_res == 0) { @@ -2278,7 +2273,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) delete ev; DBUG_RETURN(1); } - exec_res= apply_event_and_update_pos(ev, thd, rli, TRUE); + exec_res= apply_event_and_update_pos(ev, thd, rli); /* Format_description_log_event should not be deleted because it will be diff --git a/sql/slave.h b/sql/slave.h index a44a7eed83e..f356d28b626 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -190,8 +190,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset, void set_slave_thread_options(THD* thd); void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli); void rotate_relay_log(Master_info* mi); -int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, - bool skip); +int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli); pthread_handler_t handle_slave_io(void *arg); pthread_handler_t handle_slave_sql(void *arg); diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index 96e99b57e3c..ee51480411b 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -56,17 +56,20 @@ void mysql_client_binlog_statement(THD* thd) Format_description_event. */ my_bool have_fd_event= TRUE; - if (!thd->rli_fake) + int err; + Relay_log_info *rli; + rli= thd->rli_fake; + if (!rli) { - thd->rli_fake= new Relay_log_info; + rli= thd->rli_fake= new Relay_log_info; #ifdef HAVE_purify - thd->rli_fake->is_fake= TRUE; + rli->is_fake= TRUE; #endif have_fd_event= FALSE; } - if (thd->rli_fake && !thd->rli_fake->relay_log.description_event_for_exec) + if (rli && !rli->relay_log.description_event_for_exec) { - thd->rli_fake->relay_log.description_event_for_exec= + rli->relay_log.description_event_for_exec= new Format_description_log_event(4); have_fd_event= FALSE; } @@ -78,16 +81,16 @@ void mysql_client_binlog_statement(THD* thd) /* Out of memory check */ - if (!(thd->rli_fake && - thd->rli_fake->relay_log.description_event_for_exec && + if (!(rli && + rli->relay_log.description_event_for_exec && buf)) { my_error(ER_OUTOFMEMORY, MYF(0), 1); /* needed 1 bytes */ goto end; } - thd->rli_fake->sql_thd= thd; - thd->rli_fake->no_storage= TRUE; + rli->sql_thd= thd; + rli->no_storage= TRUE; for (char const *strptr= thd->lex->comment.str ; strptr < thd->lex->comment.str + thd->lex->comment.length ; ) @@ -170,8 +173,7 @@ void mysql_client_binlog_statement(THD* thd) } ev= Log_event::read_log_event(bufptr, event_len, &error, - thd->rli_fake->relay_log. - description_event_for_exec); + rli->relay_log.description_event_for_exec); DBUG_PRINT("info",("binlog base64 err=%s", error)); if (!ev) @@ -209,18 +211,10 @@ void mysql_client_binlog_statement(THD* thd) reporting. */ #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) - if (apply_event_and_update_pos(ev, thd, thd->rli_fake, FALSE)) - { - delete ev; - /* - TODO: Maybe a better error message since the BINLOG statement - now contains several events. - */ - my_error(ER_UNKNOWN_ERROR, MYF(0), "Error executing BINLOG statement"); - goto end; - } + err= ev->apply_event(rli); +#else + err= 0; #endif - /* Format_description_log_event should not be deleted because it will be used to read info about the relay log's format; it @@ -228,8 +222,17 @@ void mysql_client_binlog_statement(THD* thd) i.e. when this thread terminates. */ if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT) - delete ev; + delete ev; ev= 0; + if (err) + { + /* + TODO: Maybe a better error message since the BINLOG statement + now contains several events. + */ + my_error(ER_UNKNOWN_ERROR, MYF(0), "Error executing BINLOG statement"); + goto end; + } } } @@ -238,7 +241,7 @@ void mysql_client_binlog_statement(THD* thd) my_ok(thd); end: - thd->rli_fake->clear_tables_to_lock(); + rli->clear_tables_to_lock(); my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); DBUG_VOID_RETURN; } From bf0aa2bd3460039a0b44d5c0f1411ac2ad47b310 Mon Sep 17 00:00:00 2001 From: Jorgen Loland Date: Wed, 14 Oct 2009 10:46:50 +0200 Subject: [PATCH 126/146] Bug#47280 - strange results from count(*) with order by multiple columns without where/group Simple SELECT with implicit grouping used to return many rows if the query was ordered by the aggregated column in the SELECT list. This was incorrect because queries with implicit grouping should only return a single record. The problem was that when JOIN:exec() decided if execution needed to handle grouping, it was assumed that sum_func_count==0 meant that there were no aggregate functions in the query. This assumption was not correct in JOIN::exec() because the aggregate functions might have been optimized away during JOIN::optimize(). The reason why queries without ordering behaved correctly was that sum_func_count is only recalculated if the optimizer chooses to use temporary tables (which it does in the ordered case). Hence, non-ordered queries were correctly treated as grouped. The fix for this bug was to remove the assumption that sum_func_count==0 means that there is no need for grouping. This was done by introducing variable "bool implicit_grouping" in the JOIN object. --- mysql-test/r/func_group.result | 44 +++++++++++++++++++++++++++++++ mysql-test/t/func_group.test | 48 ++++++++++++++++++++++++++++++++++ sql/opt_sum.cc | 3 ++- sql/sql_class.h | 27 ++++++++++++++++++- sql/sql_select.cc | 27 +++++++++++++++---- sql/sql_select.h | 15 ++++++++++- 6 files changed, 156 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 3d989ad1730..94147640cde 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1477,3 +1477,47 @@ COUNT(*) SET SQL_MODE=default; DROP TABLE t1; End of 5.0 tests +# +# BUG#47280 - strange results from count(*) with order by multiple +# columns without where/group +# +# +# Initialize test +# +CREATE TABLE t1 ( +pk INT NOT NULL, +i INT, +PRIMARY KEY (pk) +); +INSERT INTO t1 VALUES (1,11),(2,12),(3,13); +# +# Start test +# All the following queries shall return 1 record +# + +# Masking all correct values {11...13} for column i in this result. +SELECT MAX(pk) as max, i +FROM t1 +ORDER BY max; +max i +3 # + +EXPLAIN +SELECT MAX(pk) as max, i +FROM t1 +ORDER BY max; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using temporary + +# Only 11 is correct for collumn i in this result +SELECT MAX(pk) as max, i +FROM t1 +WHERE pk<2 +ORDER BY max; +max i +1 11 +# +# Cleanup +# +DROP TABLE t1; +End of 5.1 tests diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index b0a3d0feb79..6e39795a5d6 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -1006,3 +1006,51 @@ DROP TABLE t1; ### --echo End of 5.0 tests + +--echo # +--echo # BUG#47280 - strange results from count(*) with order by multiple +--echo # columns without where/group +--echo # + +--echo # +--echo # Initialize test +--echo # + +CREATE TABLE t1 ( + pk INT NOT NULL, + i INT, + PRIMARY KEY (pk) +); +INSERT INTO t1 VALUES (1,11),(2,12),(3,13); + +--echo # +--echo # Start test +--echo # All the following queries shall return 1 record +--echo # + +--echo +--echo # Masking all correct values {11...13} for column i in this result. +--replace_column 2 # +SELECT MAX(pk) as max, i +FROM t1 +ORDER BY max; + +--echo +EXPLAIN +SELECT MAX(pk) as max, i +FROM t1 +ORDER BY max; + +--echo +--echo # Only 11 is correct for collumn i in this result +SELECT MAX(pk) as max, i +FROM t1 +WHERE pk<2 +ORDER BY max; + +--echo # +--echo # Cleanup +--echo # +DROP TABLE t1; + +--echo End of 5.1 tests diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 8e7265ba1ad..e009cf1ca9f 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -97,7 +97,8 @@ static ulonglong get_exact_record_count(TABLE_LIST *tables) @note This function is only called for queries with sum functions and no - GROUP BY part. + GROUP BY part. This means that the result set shall contain a single + row only @retval 0 no errors diff --git a/sql/sql_class.h b/sql/sql_class.h index 024a6587b43..922e960c805 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2647,7 +2647,32 @@ public: MI_COLUMNDEF *recinfo,*start_recinfo; KEY *keyinfo; ha_rows end_write_records; - uint field_count,sum_func_count,func_count; + /** + Number of normal fields in the query, including those referred to + from aggregate functions. Hence, "SELECT `field1`, + SUM(`field2`) from t1" sets this counter to 2. + + @see count_field_types + */ + uint field_count; + /** + Number of fields in the query that have functions. Includes both + aggregate functions (e.g., SUM) and non-aggregates (e.g., RAND). + Also counts functions referred to from aggregate functions, i.e., + "SELECT SUM(RAND())" sets this counter to 2. + + @see count_field_types + */ + uint func_count; + /** + Number of fields in the query that have aggregate functions. Note + that the optimizer may choose to optimize away these fields by + replacing them with constants, in which case sum_func_count will + need to be updated. + + @see opt_sum_query, count_field_types + */ + uint sum_func_count; uint hidden_field_count; uint group_parts,group_length,group_null_parts; uint quick_group; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9dacb2c2ce4..02e52e0c518 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -644,8 +644,11 @@ JOIN::prepare(Item ***rref_pointer_array, this->group= group_list != 0; unit= unit_arg; + if (tmp_table_param.sum_func_count && !group_list) + implicit_grouping= TRUE; + #ifdef RESTRICTED_GROUP - if (sum_func_count && !group_list && (func_count || field_count)) + if (implicit_grouping) { my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0)); goto err; @@ -881,15 +884,23 @@ JOIN::optimize() } #endif - /* Optimize count(*), min() and max() */ - if (tables_list && tmp_table_param.sum_func_count && ! group_list) + /* + Try to optimize count(*), min() and max() to const fields if + there is implicit grouping (aggregate functions but no + group_list). In this case, the result set shall only contain one + row. + */ + if (tables_list && implicit_grouping) { int res; /* opt_sum_query() returns HA_ERR_KEY_NOT_FOUND if no rows match to the WHERE conditions, - or 1 if all items were resolved, + or 1 if all items were resolved (optimized away), or 0, or an error number HA_ERR_... + + If all items were resolved by opt_sum_query, there is no need to + open any tables. */ if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds))) { @@ -2024,7 +2035,7 @@ JOIN::exec() count_field_types(select_lex, &curr_join->tmp_table_param, *curr_all_fields, 0); - if (curr_join->group || curr_join->tmp_table_param.sum_func_count || + if (curr_join->group || curr_join->implicit_grouping || (procedure && (procedure->flags & PROC_GROUP))) { if (make_group_fields(this, curr_join)) @@ -10811,6 +10822,12 @@ Next_select_func setup_end_select_func(JOIN *join) } else { + /* + Choose method for presenting result to user. Use end_send_group + if the query requires grouping (has a GROUP BY clause and/or one or + more aggregate functions). Use end_send if the query should not + be grouped. + */ if ((join->sort_and_group || (join->procedure && join->procedure->flags & PROC_GROUP)) && !tmp_tbl->precomputed_group_by) diff --git a/sql/sql_select.h b/sql/sql_select.h index 3f06b402638..92356a4c96f 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -278,7 +278,14 @@ public: TABLE **table,**all_tables,*sort_by_table; uint tables,const_tables; uint send_group_parts; - bool sort_and_group,first_record,full_join,group, no_field_update; + /** + Indicates that grouping will be performed on the result set during + query execution. This field belongs to query execution. + + @see make_group_fields, alloc_group_fields, JOIN::exec + */ + bool sort_and_group; + bool first_record,full_join,group, no_field_update; bool do_send_rows; /** TRUE when we want to resume nested loop iterations when @@ -428,6 +435,7 @@ public: tables= 0; const_tables= 0; join_list= 0; + implicit_grouping= FALSE; sort_and_group= 0; first_record= 0; do_send_rows= 1; @@ -533,6 +541,11 @@ public: select_lex == unit->fake_select_lex)); } private: + /** + TRUE if the query contains an aggregate function but has no GROUP + BY clause. + */ + bool implicit_grouping; bool make_simple_join(JOIN *join, TABLE *tmp_table); }; From 1c3de291f72f0f05c9ae688dcf8d7d2de972ced8 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Wed, 14 Oct 2009 15:36:55 +0400 Subject: [PATCH 127/146] Fix test results after the latest merge. --- mysql-test/r/func_str.result | 4 +-- mysql-test/r/signal.result | 38 ++++++++++---------- mysql-test/r/signal_demo3.result | 60 ++++++++++++++++---------------- 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 39d11aa3e2c..779a125c5cc 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -2566,7 +2566,7 @@ SELECT format(12345678901234567890.123, 3, NULL); format(12345678901234567890.123, 3, NULL) 12,345,678,901,234,567,890.123 Warnings: -Warning 1647 Unknown locale: 'NULL' +Warning 1649 Unknown locale: 'NULL' SELECT format(12345678901234567890.123, 3, 'ar_AE'); format(12345678901234567890.123, 3, 'ar_AE') 12,345,678,901,234,567,890.123 @@ -2686,5 +2686,5 @@ SELECT format(123, 1, 'Non-existent-locale'); format(123, 1, 'Non-existent-locale') 123.0 Warnings: -Warning 1647 Unknown locale: 'Non-existent-locale' +Warning 1649 Unknown locale: 'Non-existent-locale' End of 5.4 tests diff --git a/mysql-test/r/signal.result b/mysql-test/r/signal.result index 56140733c33..e20c6ee7455 100644 --- a/mysql-test/r/signal.result +++ b/mysql-test/r/signal.result @@ -580,7 +580,7 @@ SIGNAL foo; ERROR 42000: Undefined CONDITION: foo SIGNAL SQLSTATE '01000'; Warnings: -Warning 1640 Unhandled user-defined warning condition +Warning 1642 Unhandled user-defined warning condition SIGNAL SQLSTATE '02000'; ERROR 02000: Unhandled user-defined not found condition SIGNAL SQLSTATE '23000'; @@ -694,7 +694,7 @@ SIGNAL warn; end $$ call test_signal() $$ Warnings: -Warning 1640 Unhandled user-defined warning condition +Warning 1642 Unhandled user-defined warning condition drop procedure test_signal $$ create procedure test_signal() begin @@ -704,7 +704,7 @@ SIGNAL warn; end $$ call test_signal() $$ Warnings: -Warning 1640 Unhandled user-defined warning condition +Warning 1642 Unhandled user-defined warning condition drop procedure test_signal $$ create procedure test_signal() begin @@ -853,7 +853,7 @@ SIGNAL warn SET MESSAGE_TEXT = "Something bad happened"; end $$ call test_signal() $$ Warnings: -Warning 1640 Something bad happened +Warning 1642 Something bad happened drop procedure test_signal $$ create procedure test_signal() begin @@ -878,7 +878,7 @@ SIGNAL something SET MESSAGE_TEXT = _utf8 "This is a UTF8 text"; end $$ call test_signal() $$ Warnings: -Warning 1640 This is a UTF8 text +Warning 1642 This is a UTF8 text drop procedure test_signal $$ create procedure test_signal() begin @@ -887,7 +887,7 @@ SIGNAL something SET MESSAGE_TEXT = ""; end $$ call test_signal() $$ Warnings: -Warning 1640 +Warning 1642 drop procedure test_signal $$ create procedure test_signal() begin @@ -896,10 +896,10 @@ SIGNAL warn SET MESSAGE_TEXT = "谩 a"; end $$ call test_signal() $$ Warnings: -Warning 1640 谩 a +Warning 1642 谩 a show warnings $$ Level Code Message -Warning 1640 谩 a +Warning 1642 谩 a drop procedure test_signal $$ # # Test SET complex expressions @@ -1162,17 +1162,17 @@ MYSQL_ERRNO = 10000; end $$ call test_signal() $$ Warnings: -Warning 1645 Data truncated for condition item 'CLASS_ORIGIN' -Warning 1645 Data truncated for condition item 'SUBCLASS_ORIGIN' -Warning 1645 Data truncated for condition item 'CONSTRAINT_CATALOG' -Warning 1645 Data truncated for condition item 'CONSTRAINT_SCHEMA' -Warning 1645 Data truncated for condition item 'CONSTRAINT_NAME' -Warning 1645 Data truncated for condition item 'CATALOG_NAME' -Warning 1645 Data truncated for condition item 'SCHEMA_NAME' -Warning 1645 Data truncated for condition item 'TABLE_NAME' -Warning 1645 Data truncated for condition item 'COLUMN_NAME' -Warning 1645 Data truncated for condition item 'CURSOR_NAME' -Warning 1645 Data truncated for condition item 'MESSAGE_TEXT' +Warning 1647 Data truncated for condition item 'CLASS_ORIGIN' +Warning 1647 Data truncated for condition item 'SUBCLASS_ORIGIN' +Warning 1647 Data truncated for condition item 'CONSTRAINT_CATALOG' +Warning 1647 Data truncated for condition item 'CONSTRAINT_SCHEMA' +Warning 1647 Data truncated for condition item 'CONSTRAINT_NAME' +Warning 1647 Data truncated for condition item 'CATALOG_NAME' +Warning 1647 Data truncated for condition item 'SCHEMA_NAME' +Warning 1647 Data truncated for condition item 'TABLE_NAME' +Warning 1647 Data truncated for condition item 'COLUMN_NAME' +Warning 1647 Data truncated for condition item 'CURSOR_NAME' +Warning 1647 Data truncated for condition item 'MESSAGE_TEXT' Warning 10000 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222288888888 drop procedure test_signal $$ create procedure test_signal() diff --git a/mysql-test/r/signal_demo3.result b/mysql-test/r/signal_demo3.result index fea41ec2ef9..aa769659e51 100644 --- a/mysql-test/r/signal_demo3.result +++ b/mysql-test/r/signal_demo3.result @@ -78,15 +78,15 @@ ERROR 45000: Oops in proc_1 show warnings; Level Code Message Error 1051 Unknown table 'oops_it_is_not_here' -Error 1642 Oops in proc_9 -Error 1642 Oops in proc_8 -Error 1642 Oops in proc_7 -Error 1642 Oops in proc_6 -Error 1642 Oops in proc_5 -Error 1642 Oops in proc_4 -Error 1642 Oops in proc_3 -Error 1642 Oops in proc_2 -Error 1642 Oops in proc_1 +Error 1644 Oops in proc_9 +Error 1644 Oops in proc_8 +Error 1644 Oops in proc_7 +Error 1644 Oops in proc_6 +Error 1644 Oops in proc_5 +Error 1644 Oops in proc_4 +Error 1644 Oops in proc_3 +Error 1644 Oops in proc_2 +Error 1644 Oops in proc_1 SET @@session.max_error_count = 5; SELECT @@session.max_error_count; @@session.max_error_count @@ -95,11 +95,11 @@ call proc_1(); ERROR 45000: Oops in proc_1 show warnings; Level Code Message -Error 1642 Oops in proc_5 -Error 1642 Oops in proc_4 -Error 1642 Oops in proc_3 -Error 1642 Oops in proc_2 -Error 1642 Oops in proc_1 +Error 1644 Oops in proc_5 +Error 1644 Oops in proc_4 +Error 1644 Oops in proc_3 +Error 1644 Oops in proc_2 +Error 1644 Oops in proc_1 SET @@session.max_error_count = 7; SELECT @@session.max_error_count; @@session.max_error_count @@ -108,13 +108,13 @@ call proc_1(); ERROR 45000: Oops in proc_1 show warnings; Level Code Message -Error 1642 Oops in proc_7 -Error 1642 Oops in proc_6 -Error 1642 Oops in proc_5 -Error 1642 Oops in proc_4 -Error 1642 Oops in proc_3 -Error 1642 Oops in proc_2 -Error 1642 Oops in proc_1 +Error 1644 Oops in proc_7 +Error 1644 Oops in proc_6 +Error 1644 Oops in proc_5 +Error 1644 Oops in proc_4 +Error 1644 Oops in proc_3 +Error 1644 Oops in proc_2 +Error 1644 Oops in proc_1 SET @@session.max_error_count = 9; SELECT @@session.max_error_count; @@session.max_error_count @@ -123,15 +123,15 @@ call proc_1(); ERROR 45000: Oops in proc_1 show warnings; Level Code Message -Error 1642 Oops in proc_9 -Error 1642 Oops in proc_8 -Error 1642 Oops in proc_7 -Error 1642 Oops in proc_6 -Error 1642 Oops in proc_5 -Error 1642 Oops in proc_4 -Error 1642 Oops in proc_3 -Error 1642 Oops in proc_2 -Error 1642 Oops in proc_1 +Error 1644 Oops in proc_9 +Error 1644 Oops in proc_8 +Error 1644 Oops in proc_7 +Error 1644 Oops in proc_6 +Error 1644 Oops in proc_5 +Error 1644 Oops in proc_4 +Error 1644 Oops in proc_3 +Error 1644 Oops in proc_2 +Error 1644 Oops in proc_1 drop database demo; SET @@global.max_error_count = @start_global_value; SELECT @@global.max_error_count; From adab17b9e6f68aef9c5f30b4d95b26e498a304a4 Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Wed, 14 Oct 2009 21:25:11 +0800 Subject: [PATCH 128/146] Attempt to fix Windows testcase output issue --- .../r/binlog_row_mysqlbinlog_verbose.result | 16 ++++++++-------- .../binlog/t/binlog_row_mysqlbinlog_verbose.test | 12 ++++++++---- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result index f1a3fafc498..2687b21213a 100644 --- a/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result +++ b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result @@ -1,6 +1,6 @@ Verbose statements from : write-partial-row.binlog -select txt from raw_binlog_rows where txt like '###%'; -txt +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +stmt ### INSERT INTO mysql.ndb_apply_status ### SET ### @1=1 @@ -37,8 +37,8 @@ txt ### @1=2 drop table raw_binlog_rows; Verbose statements from : write-full-row.binlog -select txt from raw_binlog_rows where txt like '###%'; -txt +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +stmt ### INSERT INTO mysql.ndb_apply_status ### SET ### @1=2 @@ -76,8 +76,8 @@ txt ### @1=2 drop table raw_binlog_rows; Verbose statements from : update-partial-row.binlog -select txt from raw_binlog_rows where txt like '###%'; -txt +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +stmt ### INSERT INTO mysql.ndb_apply_status ### SET ### @1=3 @@ -117,8 +117,8 @@ txt ### @1=2 drop table raw_binlog_rows; Verbose statements from : update-full-row.binlog -select txt from raw_binlog_rows where txt like '###%'; -txt +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +stmt ### INSERT INTO mysql.ndb_apply_status ### SET ### @1=4 diff --git a/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test b/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test index b68e56d0215..42d92e1a44d 100644 --- a/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test +++ b/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test @@ -45,7 +45,8 @@ create table raw_binlog_rows (txt varchar(1000)); --remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql --enable_query_log --echo Verbose statements from : $binlog_file -select txt from raw_binlog_rows where txt like '###%'; +# Output --verbose lines, with extra Windows CR's trimmed +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; drop table raw_binlog_rows; --disable_query_log @@ -56,7 +57,8 @@ create table raw_binlog_rows (txt varchar(1000)); --remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql --enable_query_log --echo Verbose statements from : $binlog_file -select txt from raw_binlog_rows where txt like '###%'; +# Output --verbose lines, with extra Windows CR's trimmed +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; drop table raw_binlog_rows; --disable_query_log @@ -67,7 +69,8 @@ create table raw_binlog_rows (txt varchar(1000)); --remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql --enable_query_log --echo Verbose statements from : $binlog_file -select txt from raw_binlog_rows where txt like '###%'; +# Output --verbose lines, with extra Windows CR's trimmed +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; drop table raw_binlog_rows; --disable_query_log @@ -78,5 +81,6 @@ create table raw_binlog_rows (txt varchar(1000)); --remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql --enable_query_log --echo Verbose statements from : $binlog_file -select txt from raw_binlog_rows where txt like '###%'; +# Output --verbose lines, with extra Windows CR's trimmed +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; drop table raw_binlog_rows; From 8fc8d661a154dc63efec88cd89cd086dc467d5f2 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 14 Oct 2009 18:44:22 +0300 Subject: [PATCH 129/146] version change --- .bzr-mysql/default.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index f79c1cd6319..557df1b1ffe 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@lists.mysql.com" post_push_to = "commits@lists.mysql.com" -tree_name = "mysql-5.0" +tree_name = "mysql-5.0-bugteam" From a91b18262c7b2e704e8014b4cb157198cfba5ebe Mon Sep 17 00:00:00 2001 From: Jorgen Loland Date: Wed, 14 Oct 2009 18:20:01 +0200 Subject: [PATCH 130/146] Followup patch for BUG#47280 Temporary tables may set join->group to 0 even though there is grouping. Also need to test if sum_func_count>0 when JOIN::exec() decides whether to present results in a grouped manner. --- sql/sql_select.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 02e52e0c518..c5e0bce498d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2036,6 +2036,7 @@ JOIN::exec() *curr_all_fields, 0); if (curr_join->group || curr_join->implicit_grouping || + curr_join->tmp_table_param.sum_func_count || (procedure && (procedure->flags & PROC_GROUP))) { if (make_group_fields(this, curr_join)) From cd69e34ca7c0e6fbbbac5823f22e30035566b180 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 15 Oct 2009 12:31:11 +0500 Subject: [PATCH 131/146] Disabled part of test for BUG#47073 until additional fix is pushed. --- mysql-test/r/myisam.result | 7 ------- mysql-test/t/myisam.test | 11 +++++++---- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index df97e96c334..f5050ccf1c0 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -2290,13 +2290,6 @@ Table Op Msg_type Msg_text test.t1 repair error myisam_sort_buffer_size is too small test.t1 repair warning Number of rows changed from 0 to 7168 test.t1 repair status OK -SET myisam_repair_threads=2; -REPAIR TABLE t1; -Table Op Msg_type Msg_text -test.t1 repair error myisam_sort_buffer_size is too small -test.t1 repair warning Number of rows changed from # to 7168 -test.t1 repair status OK -SET myisam_repair_threads=@@global.myisam_repair_threads; SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size; DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index faeb5ee686a..e4ea939f348 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -1538,11 +1538,14 @@ INSERT INTO t1 SELECT a+2560,b FROM t1; INSERT INTO t1 SELECT a+5120,b FROM t1; SET myisam_sort_buffer_size=4; REPAIR TABLE t1; -SET myisam_repair_threads=2; + +# !!! Disabled until additional fix for BUG#47073 is pushed. +#SET myisam_repair_threads=2; # May report different values depending on threads activity. ---replace_regex /changed from [0-9]+/changed from #/ -REPAIR TABLE t1; -SET myisam_repair_threads=@@global.myisam_repair_threads; +#--replace_regex /changed from [0-9]+/changed from #/ +#REPAIR TABLE t1; +#SET myisam_repair_threads=@@global.myisam_repair_threads; + SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size; DROP TABLE t1; From 77fd19b5ec89efd324a05be90c0d9a5f1e693231 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 15 Oct 2009 14:02:29 +0300 Subject: [PATCH 132/146] Marked all the NDB related tests experimental as agreed with Bernard Ocklin. --- mysql-test/collections/default.experimental | 42 ++++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index 214b732e5cb..8b513af382c 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -1,9 +1,41 @@ +binlog.binlog_multi_engine.test # joro : NDB tests marked as experimental as agreed with bochklin + funcs_1.charset_collation_1 # depends on compile-time decisions -main.plugin_load @solaris # Bug#42144 +funcs_1.is_cml_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +funcs_1.is_columns_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +funcs_1.is_engines_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +funcs_1.is_tables_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +funcs_1.ndb* # joro : NDB tests marked as experimental as agreed with bochklin + +funcs_2.ndb_charset.test # joro : NDB tests marked as experimental as agreed with bochklin + main.ctype_gbk_binlog @solaris # Bug#46010: main.ctype_gbk_binlog fails sporadically : Table 't2' already exists -rpl.rpl_row_create_table* # Bug#45576: rpl_row_create_table fails on PB2 -rpl_ndb.rpl_ndb_log # Bug#38998 -rpl.rpl_innodb_bug28430* @solaris # Bug#46029 -rpl.rpl_get_master_version_and_clock* # Bug#46931 2009-08-26 alik rpl.rpl_get_master_version_and_clock fails on hpux11.31 main.innodb-autoinc* # Bug#47809 2009-10-04 joro innodb-autoinc.test fails with valgrind errors with the innodb plugin +main.plugin_load @solaris # Bug#42144 + +ndb.* # joro : NDB tests marked as experimental as agreed with bochklin + +rpl.rpl_get_master_version_and_clock* # Bug#46931 2009-08-26 alik rpl.rpl_get_master_version_and_clock fails on hpux11.31 +rpl.rpl_innodb_bug28430* @solaris # Bug#46029 +rpl.rpl_row_create_table* # Bug#45576: rpl_row_create_table fails on PB2 rpl.rpl_trigger* # Bug#47810 2009-10-04 joro rpl.rpl_trigger.test fails with valgrind errors with the innodb plugin + +rpl_ndb.* # joro : NDB tests marked as experimental as agreed with bochklin +rpl_ndb.rpl_ndb_log # Bug#38998 + +stress.ddl_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin + +parts.ndb_dd_backuprestore.test # joro : NDB tests marked as experimental as agreed with bochklin +parts.part_supported_sql_func_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_alter1_1_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_alter1_1_2_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_alter1_2_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_auto_increment_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_basic_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_engine_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_int_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_mgm_lc0_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_mgm_lc1_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_mgm_lc2_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_syntax_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_value_ndb.test # joro : NDB tests marked as experimental as agreed with bochklin From ff5833d3467fa927893afe00e8032c2bce84742d Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 15 Oct 2009 14:22:25 +0300 Subject: [PATCH 133/146] All NDB tests made experimental after a discussion with Bernhard Ocklin. --- mysql-test/collections/default.experimental | 42 ++++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index 214b732e5cb..907f0f6fdb9 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -1,9 +1,41 @@ +binlog.binlog_multi_engine # joro : NDB tests marked as experimental as agreed with bochklin + funcs_1.charset_collation_1 # depends on compile-time decisions -main.plugin_load @solaris # Bug#42144 +funcs_1.is_cml_ndb # joro : NDB tests marked as experimental as agreed with bochklin +funcs_1.is_columns_ndb # joro : NDB tests marked as experimental as agreed with bochklin +funcs_1.is_engines_ndb # joro : NDB tests marked as experimental as agreed with bochklin +funcs_1.is_tables_ndb # joro : NDB tests marked as experimental as agreed with bochklin +funcs_1.ndb* # joro : NDB tests marked as experimental as agreed with bochklin + +funcs_2.ndb_charset # joro : NDB tests marked as experimental as agreed with bochklin + main.ctype_gbk_binlog @solaris # Bug#46010: main.ctype_gbk_binlog fails sporadically : Table 't2' already exists -rpl.rpl_row_create_table* # Bug#45576: rpl_row_create_table fails on PB2 -rpl_ndb.rpl_ndb_log # Bug#38998 -rpl.rpl_innodb_bug28430* @solaris # Bug#46029 -rpl.rpl_get_master_version_and_clock* # Bug#46931 2009-08-26 alik rpl.rpl_get_master_version_and_clock fails on hpux11.31 main.innodb-autoinc* # Bug#47809 2009-10-04 joro innodb-autoinc.test fails with valgrind errors with the innodb plugin +main.plugin_load @solaris # Bug#42144 + +ndb.* # joro : NDB tests marked as experimental as agreed with bochklin + +rpl.rpl_get_master_version_and_clock* # Bug#46931 2009-08-26 alik rpl.rpl_get_master_version_and_clock fails on hpux11.31 +rpl.rpl_innodb_bug28430* @solaris # Bug#46029 +rpl.rpl_row_create_table* # Bug#45576: rpl_row_create_table fails on PB2 rpl.rpl_trigger* # Bug#47810 2009-10-04 joro rpl.rpl_trigger.test fails with valgrind errors with the innodb plugin + +rpl_ndb.* # joro : NDB tests marked as experimental as agreed with bochklin +rpl_ndb.rpl_ndb_log # Bug#38998 + +stress.ddl_ndb # joro : NDB tests marked as experimental as agreed with bochklin + +parts.ndb_dd_backuprestore # joro : NDB tests marked as experimental as agreed with bochklin +parts.part_supported_sql_func_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_alter1_1_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_alter1_1_2_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_alter1_2_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_auto_increment_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_basic_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_engine_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_int_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_mgm_lc0_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_mgm_lc1_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_mgm_lc2_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_syntax_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_value_ndb # joro : NDB tests marked as experimental as agreed with bochklin From f79064c4d449abec1a96380a5494aba5c3f16994 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 15 Oct 2009 14:48:12 +0300 Subject: [PATCH 134/146] version change --- .bzr-mysql/default.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index e613cefc614..f044f8e62da 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@lists.mysql.com" post_push_to = "commits@lists.mysql.com" -tree_name = "mysql-5.1-bugteam" +tree_name = "mysql-5.1" From 6b81bff83ce0982bc1eb65f7f87db396de18b0b9 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 16 Oct 2009 11:42:16 +0300 Subject: [PATCH 135/146] Revert the fix for bug #47123 until test suite failures are resolved. --- mysql-test/r/range.result | 9 --------- mysql-test/t/range.test | 11 ----------- sql/opt_range.cc | 11 ----------- 3 files changed, 31 deletions(-) diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 0d44e79b39a..c98a7696ea6 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -1398,12 +1398,3 @@ a < 10; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t3 range a a 5 NULL 8 Using where; Using index DROP TABLE t1, t2, t3; -# -# Bug #47123: Endless 100% CPU loop with STRAIGHT_JOIN -# -CREATE TABLE t1(a INT, KEY(a)); -INSERT INTO t1 VALUES (1), (NULL); -SELECT * FROM t1 WHERE a <> NULL and (a <> NULL or a <= NULL); -a -DROP TABLE t1; -End of 5.1 tests diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index f0fa99f3d95..dc119b6a77e 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1171,14 +1171,3 @@ a < 5 OR a < 10; DROP TABLE t1, t2, t3; - ---echo # ---echo # Bug #47123: Endless 100% CPU loop with STRAIGHT_JOIN ---echo # - -CREATE TABLE t1(a INT, KEY(a)); -INSERT INTO t1 VALUES (1), (NULL); -SELECT * FROM t1 WHERE a <> NULL and (a <> NULL or a <= NULL); -DROP TABLE t1; - ---echo End of 5.1 tests diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 04dae4fd815..119f90bc97a 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -5891,17 +5891,6 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, goto end; } field->table->in_use->variables.sql_mode= orig_sql_mode; - - /* - Any sargable predicate except "<=>" involving NULL as a constant is always - FALSE - */ - if (type != Item_func::EQUAL_FUNC && field->is_real_null()) - { - tree= &null_element; - goto end; - } - str= (uchar*) alloc_root(alloc, key_part->store_length+1); if (!str) goto end; From a0e12ec26996b9f2bad46c84e13110087feadfa4 Mon Sep 17 00:00:00 2001 From: Satya B Date: Fri, 16 Oct 2009 17:28:02 +0530 Subject: [PATCH 136/146] Merging Innodb plugin 1.0.5 revisions from 5.1-main from revisions 3149 to 3163 also merged missing Innodb plugin revisions r5636,r5635 manually --- mysql-test/r/innodb-consistent.result | 35 + mysql-test/r/innodb_bug34300.result | 1 + mysql-test/r/innodb_bug44369.result | 14 + mysql-test/r/innodb_bug44571.result | 9 + mysql-test/r/innodb_bug46000.result | 17 + mysql-test/suite/innodb/t/innodb-zip.test | 6 - mysql-test/t/disabled.def | 1 + mysql-test/t/innodb-consistent-master.opt | 1 + mysql-test/t/innodb-consistent.test | 58 + mysql-test/t/innodb_bug34300.test | 2 + mysql-test/t/innodb_bug44369.test | 21 + mysql-test/t/innodb_bug44571.test | 17 + mysql-test/t/innodb_bug46000.test | 34 + storage/innobase/CMakeLists.txt | 19 +- storage/innobase/ChangeLog | 146 +++ storage/innobase/Makefile.am | 1 - storage/innobase/README | 29 - storage/innobase/btr/btr0btr.c | 25 +- storage/innobase/btr/btr0sea.c | 2 +- storage/innobase/buf/buf0buf.c | 291 +++-- storage/innobase/buf/buf0lru.c | 237 ++-- storage/innobase/buf/buf0rea.c | 209 +--- storage/innobase/dict/dict0crea.c | 2 +- storage/innobase/dict/dict0dict.c | 25 +- storage/innobase/fil/fil0fil.c | 41 +- storage/innobase/fsp/fsp0fsp.c | 80 +- storage/innobase/handler/ha_innodb.cc | 245 +++- storage/innobase/handler/handler0alter.cc | 4 +- storage/innobase/handler/handler0vars.h | 69 -- storage/innobase/handler/win_delay_loader.cc | 1024 ----------------- storage/innobase/include/buf0buf.h | 127 +- storage/innobase/include/buf0buf.ic | 75 +- storage/innobase/include/buf0lru.h | 52 +- storage/innobase/include/buf0rea.h | 10 +- storage/innobase/include/buf0types.h | 2 + storage/innobase/include/dict0crea.h | 2 +- storage/innobase/include/dict0dict.h | 2 +- storage/innobase/include/dict0mem.h | 2 +- storage/innobase/include/fsp0fsp.h | 2 +- storage/innobase/include/lock0lock.h | 8 + storage/innobase/include/log0log.h | 7 +- storage/innobase/include/log0log.ic | 71 +- storage/innobase/include/log0recv.h | 5 + storage/innobase/include/mtr0mtr.h | 5 +- storage/innobase/include/os0file.h | 1 + storage/innobase/include/os0sync.h | 81 +- storage/innobase/include/page0page.h | 7 +- storage/innobase/include/page0zip.h | 12 +- storage/innobase/include/rem0cmp.h | 2 +- storage/innobase/include/rem0rec.ic | 2 +- storage/innobase/include/row0ins.h | 2 +- storage/innobase/include/row0mysql.h | 4 +- storage/innobase/include/srv0srv.h | 16 +- storage/innobase/include/trx0rec.h | 4 +- storage/innobase/include/trx0rec.ic | 4 +- storage/innobase/include/trx0roll.h | 15 +- storage/innobase/include/trx0sys.ic | 4 +- storage/innobase/include/trx0trx.h | 4 +- storage/innobase/include/univ.i | 65 +- storage/innobase/include/ut0auxconf.h | 12 +- storage/innobase/include/ut0byte.h | 4 +- storage/innobase/include/ut0byte.ic | 4 +- storage/innobase/include/ut0ut.h | 20 +- storage/innobase/lock/lock0lock.c | 42 +- storage/innobase/log/log0log.c | 22 +- storage/innobase/log/log0recv.c | 82 +- storage/innobase/mem/mem0mem.c | 20 +- storage/innobase/mtr/mtr0mtr.c | 8 +- .../innobase/mysql-test/innodb-analyze.test | 2 + .../mysql-test/innodb-consistent-master.opt | 1 + .../mysql-test/innodb-consistent.result | 35 + .../mysql-test/innodb-consistent.test | 58 + storage/innobase/mysql-test/innodb-zip.result | 2 +- storage/innobase/mysql-test/innodb-zip.test | 2 +- .../innobase/mysql-test/innodb_bug34300.test | 2 + .../innobase/mysql-test/innodb_bug36169.test | 4 + .../innobase/mysql-test/innodb_bug36172.test | 6 + .../mysql-test/innodb_bug44369.result | 14 + .../innobase/mysql-test/innodb_bug44369.test | 21 + .../mysql-test/innodb_bug44571.result | 9 + .../innobase/mysql-test/innodb_bug44571.test | 17 + .../mysql-test/innodb_bug46000.result | 17 + .../innobase/mysql-test/innodb_bug46000.test | 34 + .../mysql-test/innodb_file_format.result | 1 + .../mysql-test/innodb_file_format.test | 1 + storage/innobase/os/os0file.c | 92 +- storage/innobase/page/page0cur.c | 2 +- storage/innobase/page/page0page.c | 6 +- storage/innobase/page/page0zip.c | 65 +- storage/innobase/plug.in | 164 ++- storage/innobase/rem/rem0cmp.c | 6 +- storage/innobase/revert_gen.sh | 8 + storage/innobase/row/row0ins.c | 2 +- storage/innobase/row/row0merge.c | 225 +++- storage/innobase/row/row0mysql.c | 48 +- storage/innobase/scripts/export.sh | 74 ++ storage/innobase/srv/srv0srv.c | 56 +- storage/innobase/srv/srv0start.c | 36 +- storage/innobase/sync/sync0rw.c | 1 + storage/innobase/sync/sync0sync.c | 71 +- storage/innobase/thr/thr0loc.c | 2 +- storage/innobase/trx/trx0rec.c | 4 +- storage/innobase/trx/trx0roll.c | 74 +- storage/innobase/trx/trx0trx.c | 4 +- .../ut/ut0auxconf_atomic_pthread_t_solaris.c | 26 +- .../innobase/ut/ut0auxconf_have_gcc_atomics.c | 61 + storage/innobase/ut/ut0ut.c | 19 + storage/innobase/win-plugin/README | 22 - storage/innobase/win-plugin/win-plugin.diff | 279 ----- 109 files changed, 2599 insertions(+), 2446 deletions(-) create mode 100644 mysql-test/r/innodb-consistent.result create mode 100644 mysql-test/r/innodb_bug44369.result create mode 100644 mysql-test/r/innodb_bug44571.result create mode 100644 mysql-test/r/innodb_bug46000.result create mode 100644 mysql-test/t/innodb-consistent-master.opt create mode 100644 mysql-test/t/innodb-consistent.test create mode 100644 mysql-test/t/innodb_bug44369.test create mode 100644 mysql-test/t/innodb_bug44571.test create mode 100644 mysql-test/t/innodb_bug46000.test delete mode 100644 storage/innobase/README delete mode 100644 storage/innobase/handler/handler0vars.h delete mode 100644 storage/innobase/handler/win_delay_loader.cc create mode 100644 storage/innobase/mysql-test/innodb-consistent-master.opt create mode 100644 storage/innobase/mysql-test/innodb-consistent.result create mode 100644 storage/innobase/mysql-test/innodb-consistent.test create mode 100644 storage/innobase/mysql-test/innodb_bug44369.result create mode 100644 storage/innobase/mysql-test/innodb_bug44369.test create mode 100644 storage/innobase/mysql-test/innodb_bug44571.result create mode 100644 storage/innobase/mysql-test/innodb_bug44571.test create mode 100644 storage/innobase/mysql-test/innodb_bug46000.result create mode 100644 storage/innobase/mysql-test/innodb_bug46000.test create mode 100755 storage/innobase/revert_gen.sh create mode 100755 storage/innobase/scripts/export.sh create mode 100644 storage/innobase/ut/ut0auxconf_have_gcc_atomics.c delete mode 100644 storage/innobase/win-plugin/README delete mode 100644 storage/innobase/win-plugin/win-plugin.diff diff --git a/mysql-test/r/innodb-consistent.result b/mysql-test/r/innodb-consistent.result new file mode 100644 index 00000000000..9115791b99c --- /dev/null +++ b/mysql-test/r/innodb-consistent.result @@ -0,0 +1,35 @@ +drop table if exists t1; +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +create table t2 like t1; +insert into t2 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; +begin; +replace into t1 select * from t2; +set session transaction isolation level read committed; +set autocommit=0; +delete from t2 where a=5; +commit; +delete from t2; +commit; +commit; +begin; +insert into t1 select * from t2; +set session transaction isolation level read committed; +set autocommit=0; +delete from t2 where a=5; +commit; +delete from t2; +commit; +commit; +select * from t1; +a +1 +2 +3 +4 +5 +6 +7 +drop table t1; +drop table t2; diff --git a/mysql-test/r/innodb_bug34300.result b/mysql-test/r/innodb_bug34300.result index 03ae355de7b..4e3d3c17040 100644 --- a/mysql-test/r/innodb_bug34300.result +++ b/mysql-test/r/innodb_bug34300.result @@ -6,4 +6,5 @@ SELECT f4, f8 FROM bug34300; f4 f8 xxx zzz DROP TABLE bug34300; +SET @@global.max_allowed_packet=1048576; SET @@global.max_allowed_packet=default; diff --git a/mysql-test/r/innodb_bug44369.result b/mysql-test/r/innodb_bug44369.result new file mode 100644 index 00000000000..e4b84ecac19 --- /dev/null +++ b/mysql-test/r/innodb_bug44369.result @@ -0,0 +1,14 @@ +create table bug44369 (DB_ROW_ID int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +create table bug44369 (db_row_id int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +show errors; +Level Code Message +Error 1005 Error creating table 'test/bug44369' with column name 'db_row_id'. 'db_row_id' is a reserved name. Please try to re-create the table with a different column name. +Error 1005 Can't create table 'test.bug44369' (errno: -1) +create table bug44369 (db_TRX_Id int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +show errors; +Level Code Message +Error 1005 Error creating table 'test/bug44369' with column name 'db_TRX_Id'. 'db_TRX_Id' is a reserved name. Please try to re-create the table with a different column name. +Error 1005 Can't create table 'test.bug44369' (errno: -1) diff --git a/mysql-test/r/innodb_bug44571.result b/mysql-test/r/innodb_bug44571.result new file mode 100644 index 00000000000..36374edcb3e --- /dev/null +++ b/mysql-test/r/innodb_bug44571.result @@ -0,0 +1,9 @@ +CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; +ALTER TABLE bug44571 CHANGE foo bar INT; +ALTER TABLE bug44571 ADD INDEX bug44571b (foo); +ERROR 42000: Key column 'foo' doesn't exist in table +ALTER TABLE bug44571 ADD INDEX bug44571b (bar); +ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it +CREATE INDEX bug44571b ON bug44571 (bar); +ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it +DROP TABLE bug44571; diff --git a/mysql-test/r/innodb_bug46000.result b/mysql-test/r/innodb_bug46000.result new file mode 100644 index 00000000000..ccff888a48d --- /dev/null +++ b/mysql-test/r/innodb_bug46000.result @@ -0,0 +1,17 @@ +create table bug46000(`id` int,key `GEN_CLUST_INDEX`(`id`))engine=innodb; +ERROR HY000: Can't create table 'test.bug46000' (errno: -1) +create table bug46000(`id` int, key `GEN_clust_INDEX`(`id`))engine=innodb; +ERROR HY000: Can't create table 'test.bug46000' (errno: -1) +show errors; +Level Code Message +Error 1005 Cannot Create Index with name 'GEN_CLUST_INDEX'. The name is reserved for the system default primary index. +Error 1005 Can't create table 'test.bug46000' (errno: -1) +create table bug46000(id int) engine=innodb; +create index GEN_CLUST_INDEX on bug46000(id); +ERROR HY000: Can't create table '#sql-temporary' (errno: -1) +show errors; +Level Code Message +Error 1005 Cannot Create Index with name 'GEN_CLUST_INDEX'. The name is reserved for the system default primary index. +Error 1005 Can't create table '#sql-temporary' (errno: -1) +create index idx on bug46000(id); +drop table bug46000; diff --git a/mysql-test/suite/innodb/t/innodb-zip.test b/mysql-test/suite/innodb/t/innodb-zip.test index bba5ccfbcd3..5bcd0e3c824 100644 --- a/mysql-test/suite/innodb/t/innodb-zip.test +++ b/mysql-test/suite/innodb/t/innodb-zip.test @@ -105,12 +105,6 @@ drop table t1; --error ER_TOO_BIG_ROWSIZE CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; -# 439 throws error with certain system zlib (ubuntu "intrepid") -# but not with zlib bundled with MySQL, because zlib's compressBound() -# are different (and used by InnoDB's page_zip_empty_size()); see -# http://www.linux-archive.org/archlinux-development/119356-zlib-1-2-3-3-1-a.html -# "Fix compressBound(), was low for some pathological cases [Fearnley]". -# 438 works with both zlib-s. CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512)); diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 6f0b1716d38..8b34bd03faa 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -14,3 +14,4 @@ innodb_bug39438 : Bug#42383 2009-01-28 lsoares "This fails in embedded query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails sporadically partition_innodb_builtin : Bug#32430 2009-09-25 mattiasj Waiting for push of Innodb changes partition_innodb_plugin : Bug#32430 2009-09-25 mattiasj Waiting for push of Innodb changes +innodb_bug46000 : Bug#47860 2009-10-16 satyab Test fails for innodb plugin 1.0.5 diff --git a/mysql-test/t/innodb-consistent-master.opt b/mysql-test/t/innodb-consistent-master.opt new file mode 100644 index 00000000000..8cca44767da --- /dev/null +++ b/mysql-test/t/innodb-consistent-master.opt @@ -0,0 +1 @@ +--innodb_lock_wait_timeout=2 diff --git a/mysql-test/t/innodb-consistent.test b/mysql-test/t/innodb-consistent.test new file mode 100644 index 00000000000..791600fc8a7 --- /dev/null +++ b/mysql-test/t/innodb-consistent.test @@ -0,0 +1,58 @@ +-- source include/not_embedded.inc +-- source include/have_innodb.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# REPLACE INTO ... SELECT and INSERT INTO ... SELECT should do +# a consistent read of the source table. + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +create table t2 like t1; +insert into t2 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; + +# REPLACE INTO ... SELECT case +begin; +# this should not result in any locks on t2. +replace into t1 select * from t2; + +connection b; +set session transaction isolation level read committed; +set autocommit=0; +# should not cuase a lock wait. +delete from t2 where a=5; +commit; +delete from t2; +commit; +connection a; +commit; + +# INSERT INTO ... SELECT case +begin; +# this should not result in any locks on t2. +insert into t1 select * from t2; + +connection b; +set session transaction isolation level read committed; +set autocommit=0; +# should not cuase a lock wait. +delete from t2 where a=5; +commit; +delete from t2; +commit; +connection a; +commit; + +select * from t1; +drop table t1; +drop table t2; + +connection default; +disconnect a; +disconnect b; diff --git a/mysql-test/t/innodb_bug34300.test b/mysql-test/t/innodb_bug34300.test index 432ddd03547..0bd50abcabf 100644 --- a/mysql-test/t/innodb_bug34300.test +++ b/mysql-test/t/innodb_bug34300.test @@ -9,6 +9,7 @@ -- disable_result_log # set packet size and reconnect +let $max_packet=`select @@global.max_allowed_packet`; SET @@global.max_allowed_packet=16777216; --connect (newconn, localhost, root,,) @@ -32,6 +33,7 @@ SELECT f4, f8 FROM bug34300; DROP TABLE bug34300; +EVAL SET @@global.max_allowed_packet=$max_packet; disconnect newconn; connection default; SET @@global.max_allowed_packet=default; diff --git a/mysql-test/t/innodb_bug44369.test b/mysql-test/t/innodb_bug44369.test new file mode 100644 index 00000000000..495059eb5e6 --- /dev/null +++ b/mysql-test/t/innodb_bug44369.test @@ -0,0 +1,21 @@ +# This is the test for bug 44369. We should +# block table creation with columns match +# some innodb internal reserved key words, +# both case sensitively and insensitely. + +--source include/have_innodb.inc + +# This create table operation should fail. +--error ER_CANT_CREATE_TABLE +create table bug44369 (DB_ROW_ID int) engine=innodb; + +# This create should fail as well +--error ER_CANT_CREATE_TABLE +create table bug44369 (db_row_id int) engine=innodb; + +show errors; + +--error ER_CANT_CREATE_TABLE +create table bug44369 (db_TRX_Id int) engine=innodb; + +show errors; diff --git a/mysql-test/t/innodb_bug44571.test b/mysql-test/t/innodb_bug44571.test new file mode 100644 index 00000000000..685463ceff9 --- /dev/null +++ b/mysql-test/t/innodb_bug44571.test @@ -0,0 +1,17 @@ +# +# Bug#44571 InnoDB Plugin crashes on ADD INDEX +# http://bugs.mysql.com/44571 +# +-- source include/have_innodb.inc + +CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; +ALTER TABLE bug44571 CHANGE foo bar INT; +-- error ER_KEY_COLUMN_DOES_NOT_EXITS +ALTER TABLE bug44571 ADD INDEX bug44571b (foo); +# The following will fail, because the CHANGE foo bar was +# not communicated to InnoDB. +--error ER_NOT_KEYFILE +ALTER TABLE bug44571 ADD INDEX bug44571b (bar); +--error ER_NOT_KEYFILE +CREATE INDEX bug44571b ON bug44571 (bar); +DROP TABLE bug44571; diff --git a/mysql-test/t/innodb_bug46000.test b/mysql-test/t/innodb_bug46000.test new file mode 100644 index 00000000000..80c18c58ef0 --- /dev/null +++ b/mysql-test/t/innodb_bug46000.test @@ -0,0 +1,34 @@ +# This is the test for bug 46000. We shall +# block any index creation with the name of +# "GEN_CLUST_INDEX", which is the reserved +# name for innodb default primary index. + +--source include/have_innodb.inc + +# This 'create table' operation should fail because of +# using the reserve name as its index name. +--error ER_CANT_CREATE_TABLE +create table bug46000(`id` int,key `GEN_CLUST_INDEX`(`id`))engine=innodb; + +# Mixed upper/lower case of the reserved key words +--error ER_CANT_CREATE_TABLE +create table bug46000(`id` int, key `GEN_clust_INDEX`(`id`))engine=innodb; + +show errors; + +create table bug46000(id int) engine=innodb; + +# This 'create index' operation should fail. +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +create index GEN_CLUST_INDEX on bug46000(id); + +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +show errors; + +# This 'create index' operation should succeed, no +# temp table left from last failed create index +# operation. +create index idx on bug46000(id); + +drop table bug46000; diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index f4d8e7b8231..f48c4ea39b2 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -21,7 +21,16 @@ # those trees. SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") + +# Starting at 5.1.38, MySQL CMake files are simplified. But the plugin +# CMakeLists.txt still needs to work with previous versions of MySQL. +IF (MYSQL_VERSION_ID GREATER "50137") + INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") +ENDIF (MYSQL_VERSION_ID GREATER "50137") + +IF (CMAKE_SIZEOF_VOID_P MATCHES 8) + SET(WIN64 TRUE) +ENDIF (CMAKE_SIZEOF_VOID_P MATCHES 8) # Include directories under innobase INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/innobase/include @@ -36,10 +45,10 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include # Removing compiler optimizations for innodb/mem/* files on 64-bit Windows # due to 64-bit compiler error, See MySQL Bug #19424, #36366, #34297 -IF(MSVC AND CMAKE_SIZEOF_VOID_P MATCHES 8) +IF (MSVC AND $(WIN64)) SET_SOURCE_FILES_PROPERTIES(mem/mem0mem.c mem/mem0pool.c PROPERTIES COMPILE_FLAGS -Od) -ENDIF(MSVC AND CMAKE_SIZEOF_VOID_P MATCHES 8) +ENDIF (MSVC AND $(WIN64)) SET(INNOBASE_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c buf/buf0buddy.c buf/buf0buf.c buf/buf0flu.c buf/buf0lru.c buf/buf0rea.c @@ -74,5 +83,5 @@ SET(INNOBASE_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c usr/usr0sess.c ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c ut/ut0list.c ut/ut0wqueue.c) -ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS -DINNODB_RW_LOCKS_USE_ATOMICS -DIB_HAVE_PAUSE_INSTRUCTION) -MYSQL_STORAGE_ENGINE(INNOBASE) \ No newline at end of file +ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS -DIB_HAVE_PAUSE_INSTRUCTION) +MYSQL_STORAGE_ENGINE(INNOBASE) diff --git a/storage/innobase/ChangeLog b/storage/innobase/ChangeLog index 2b04c06f0e8..0f8f4c4d071 100644 --- a/storage/innobase/ChangeLog +++ b/storage/innobase/ChangeLog @@ -1,3 +1,149 @@ +2009-10-01 The InnoDB Team + + * fsp/fsp0fsp.c, row/row0merge.c: + Clean up after a crash during DROP INDEX. When InnoDB crashes + while dropping an index, ensure that the index will be completely + dropped during crash recovery. The MySQL .frm file may still + contain the dropped index, but there is little that we can do + about it. + +2009-09-28 The InnoDB Team + + * handler/ha_innodb.cc: + When a secondary index exists in the MySQL .frm file but not in + the InnoDB data dictionary, return an error instead of letting an + assertion fail in index_read. + +2009-09-28 The InnoDB Team + + * btr/btr0btr.c, buf/buf0buf.c, include/page0page.h, + include/page0zip.h, page/page0cur.c, page/page0page.c, + page/page0zip.c: + Do not write to PAGE_INDEX_ID when restoring an uncompressed page + after a compression failure. The field should only be written + when creating a B-tree page. This fix addresses a race condition + in a debug assertion. + +2009-09-28 The InnoDB Team + + * fil/fil0fil.c: + Try to prevent the reuse of tablespace identifiers after InnoDB + has crashed during table creation. Also, refuse to start if files + with duplicate tablespace identifiers are encountered. + +2009-09-25 The InnoDB Team + + * include/os0file.h, os/os0file.c: + Fix Bug#47055 unconditional exit(1) on ERROR_WORKING_SET_QUOTA + 1453 (0x5AD) for InnoDB backend + +2009-09-19 The InnoDB Team + + * handler/ha_innodb.cc, mysql-test/innodb-consistent-master.opt, + mysql-test/innodb-consistent.result, + mysql-test/innodb-consistent.test: + Fix Bug#37232 Innodb might get too many read locks for DML with + repeatable-read + +2009-09-19 The InnoDB Team + + * fsp/fsp0fsp.c: + Fix Bug#31183 Tablespace full problems not reported in error log, + error message unclear + +2009-09-17 The InnoDB Team + + * mysql-test/innodb-zip.result, mysql-test/innodb-zip.test: + Make the test pass with zlib 1.2.3.3. Apparently, the definition + of compressBound() has changed between zlib versions, and the + maximum record size of a table with 1K compressed page size has + been reduced by one byte. This is an arbitrary test. In practical + applications, for good write performance, the compressed page size + should be chosen to be bigger than the absolute minimum. + +2009-09-16 The InnoDB Team + + * handler/ha_innodb.cc: + Fix Bug#46256 drop table with unknown collation crashes innodb + +2009-09-16 The InnoDB Team + + * dict/dict0dict.c, handler/ha_innodb.cc, + mysql-test/innodb_bug44369.result, mysql-test/innodb_bug44369.test, + row/row0mysql.c: + Fix Bug#44369 InnoDB: Does not uniformly disallow disallowed column + names + +2009-09-16 The InnoDB Team + + * handler/ha_innodb.cc, include/db0err.h, + mysql-test/innodb_bug46000.result, mysql-test/innodb_bug46000.test: + Fix Bug#46000 using index called GEN_CLUST_INDEX crashes server + +2009-09-02 The InnoDB Team + + * include/lock0lock.h, include/row0mysql.h, lock/lock0lock.c, + row/row0mysql.c: + Fix a regression introduced by the fix for MySQL bug#26316. We check + whether a transaction holds any AUTOINC locks before we acquire + the kernel mutex and release those locks. + +2009-08-27 The InnoDB Team + + * dict/dict0dict.c, include/dict0dict.h, + mysql-test/innodb_bug44571.result, mysql-test/innodb_bug44571.test: + Fix Bug#44571 InnoDB Plugin crashes on ADD INDEX + +2009-08-27 The InnoDB Team + + * row/row0merge.c: + Fix a bug in the merge sort that can corrupt indexes in fast index + creation. Add some consistency checks. Check that the number of + records remains constant in every merge sort pass. + +2009-08-27 The InnoDB Team + + * buf/buf0buf.c, buf/buf0lru.c, buf/buf0rea.c, handler/ha_innodb.cc, + include/buf0buf.h, include/buf0buf.ic, include/buf0lru.h, + include/ut0ut.h, ut/ut0ut.c: + Make it possible to tune the buffer pool LRU eviction policy to be + more resistant against index scans. Introduce the settable global + variables innodb_old_blocks_pct and innodb_old_blocks_time for + controlling the buffer pool eviction policy. The parameter + innodb_old_blocks_pct (5..95) controls the desired amount of "old" + blocks in the LRU list. The default is 37, corresponding to the + old fixed ratio of 3/8. Each time a block is accessed, it will be + moved to the "new" blocks if its first access was at least + innodb_old_blocks_time milliseconds ago (default 0, meaning every + block). The idea is that in index scans, blocks will be accessed + a few times within innodb_old_blocks_time, and they will remain in + the "old" section of the LRU list. Thus, when innodb_old_blocks_time + is nonzero, blocks retrieved for one-time index scans will be more + likely candidates for eviction than blocks that are accessed in + random patterns. + +2009-08-26 The InnoDB Team + + * handler/ha_innodb.cc, os/os0file.c: + Fix Bug#42885 buf_read_ahead_random, buf_read_ahead_linear counters, + thread wakeups + +2009-08-20 The InnoDB Team + + * lock/lock0lock.c: + Fix Bug#46650 Innodb assertion autoinc_lock == lock in + lock_table_remove_low on INSERT SELECT + +2009-08-13 The InnoDB Team + + * handler/handler0alter.cc: + Fix Bug#46657 InnoDB plugin: invalid read in index_merge_innodb test + (Valgrind) + +2009-08-11 The InnoDB Team + + InnoDB Plugin 1.0.4 released + 2009-07-20 The InnoDB Team * buf/buf0rea.c, handler/ha_innodb.cc, include/srv0srv.h, diff --git a/storage/innobase/Makefile.am b/storage/innobase/Makefile.am index 26f6b741227..6051fe9ef96 100644 --- a/storage/innobase/Makefile.am +++ b/storage/innobase/Makefile.am @@ -31,7 +31,6 @@ DEFS= @DEFS@ noinst_HEADERS= \ handler/ha_innodb.h \ - handler/handler0vars.h \ handler/i_s.h \ include/btr0btr.h \ include/btr0btr.ic \ diff --git a/storage/innobase/README b/storage/innobase/README deleted file mode 100644 index 56aa8058224..00000000000 --- a/storage/innobase/README +++ /dev/null @@ -1,29 +0,0 @@ -This is the source of the InnoDB Plugin 1.0.4 for MySQL 5.1 -=========================================================== - -Instructions for compiling the plugin: --------------------------------------- - -1. Get the latest MySQL 5.1 sources from - http://dev.mysql.com/downloads/mysql/5.1.html#source - -2. Replace the contents of the mysql-5.1.N/storage/innobase/ directory - with the contents of this directory. - -3. Optional (only necessary if you are going to run tests from the - mysql-test suite): cd into the innobase directory and run ./setup.sh - -4. Compile MySQL as usual. - -5. Enjoy! - -See the online documentation for more detailed instructions: -http://www.innodb.com/doc/innodb_plugin-1.0/innodb-plugin-installation.html - -For more information about InnoDB visit -http://www.innodb.com - -Please report any problems or issues with the plugin in the InnoDB Forums -http://forums.innodb.com/ or in the MySQL Bugs database http://bugs.mysql.com - -Thank you for using the InnoDB plugin! diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index 6ba9b36207b..94b34ecece1 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -797,7 +797,7 @@ btr_create( buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); } - /* Create a new index page on the the allocated segment page */ + /* Create a new index page on the allocated segment page */ page_zip = buf_block_get_page_zip(block); if (UNIV_LIKELY_NULL(page_zip)) { @@ -1011,7 +1011,26 @@ btr_page_reorganize_low( (!page_zip_compress(page_zip, page, index, NULL))) { /* Restore the old page and exit. */ - buf_frame_copy(page, temp_page); + +#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG + /* Check that the bytes that we skip are identical. */ + ut_a(!memcmp(page, temp_page, PAGE_HEADER)); + ut_a(!memcmp(PAGE_HEADER + PAGE_N_RECS + page, + PAGE_HEADER + PAGE_N_RECS + temp_page, + PAGE_DATA - (PAGE_HEADER + PAGE_N_RECS))); + ut_a(!memcmp(UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + page, + UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + temp_page, + FIL_PAGE_DATA_END)); +#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */ + + memcpy(PAGE_HEADER + page, PAGE_HEADER + temp_page, + PAGE_N_RECS - PAGE_N_DIR_SLOTS); + memcpy(PAGE_DATA + page, PAGE_DATA + temp_page, + UNIV_PAGE_SIZE - PAGE_DATA - FIL_PAGE_DATA_END); + +#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG + ut_a(!memcmp(page, temp_page, UNIV_PAGE_SIZE)); +#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */ goto func_exit; } @@ -1902,7 +1921,7 @@ func_start: n_uniq, &heap); /* If the new record is less than the existing record - the the split in the middle will copy the existing + the split in the middle will copy the existing record to the new node. */ if (cmp_dtuple_rec(tuple, first_rec, offsets) < 0) { split_rec = page_get_middle_rec(page); diff --git a/storage/innobase/btr/btr0sea.c b/storage/innobase/btr/btr0sea.c index faa1c13897e..0a80c61a58d 100644 --- a/storage/innobase/btr/btr0sea.c +++ b/storage/innobase/btr/btr0sea.c @@ -957,7 +957,7 @@ btr_search_guess_on_hash( /* Increment the page get statistics though we did not really fix the page: for user info only */ - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; return(TRUE); diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index 0008fcb1271..d87abbd0ed9 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -837,16 +837,35 @@ buf_chunk_not_freed( block = chunk->blocks; for (i = chunk->size; i--; block++) { - mutex_enter(&block->mutex); - - if (buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE - && !buf_flush_ready_for_replace(&block->page)) { + ibool ready; + switch (buf_block_get_state(block)) { + case BUF_BLOCK_ZIP_FREE: + case BUF_BLOCK_ZIP_PAGE: + case BUF_BLOCK_ZIP_DIRTY: + /* The uncompressed buffer pool should never + contain compressed block descriptors. */ + ut_error; + break; + case BUF_BLOCK_NOT_USED: + case BUF_BLOCK_READY_FOR_USE: + case BUF_BLOCK_MEMORY: + case BUF_BLOCK_REMOVE_HASH: + /* Skip blocks that are not being used for + file pages. */ + break; + case BUF_BLOCK_FILE_PAGE: + mutex_enter(&block->mutex); + ready = buf_flush_ready_for_replace(&block->page); mutex_exit(&block->mutex); - return(block); - } - mutex_exit(&block->mutex); + if (!ready) { + + return(block); + } + + break; + } } return(NULL); @@ -966,8 +985,6 @@ buf_pool_init(void) buf_pool->no_flush[i] = os_event_create(NULL); } - buf_pool->ulint_clock = 1; - /* 3. Initialize LRU fields --------------------------- */ /* All fields are initialized by mem_zalloc(). */ @@ -1470,34 +1487,9 @@ buf_pool_resize(void) buf_pool_page_hash_rebuild(); } -/********************************************************************//** -Moves the block to the start of the LRU list if there is a danger -that the block would drift out of the buffer pool. */ -UNIV_INLINE -void -buf_block_make_young( -/*=================*/ - buf_page_t* bpage) /*!< in: block to make younger */ -{ - ut_ad(!buf_pool_mutex_own()); - - /* Note that we read freed_page_clock's without holding any mutex: - this is allowed since the result is used only in heuristics */ - - if (buf_page_peek_if_too_old(bpage)) { - - buf_pool_mutex_enter(); - /* There has been freeing activity in the LRU list: - best to move to the head of the LRU list */ - - buf_LRU_make_block_young(bpage); - buf_pool_mutex_exit(); - } -} - /********************************************************************//** Moves a page to the start of the buffer pool LRU list. This high-level -function can be used to prevent an important page from from slipping out of +function can be used to prevent an important page from slipping out of the buffer pool. */ UNIV_INTERN void @@ -1514,6 +1506,36 @@ buf_page_make_young( buf_pool_mutex_exit(); } +/********************************************************************//** +Sets the time of the first access of a page and moves a page to the +start of the buffer pool LRU list if it is too old. This high-level +function can be used to prevent an important page from slipping +out of the buffer pool. */ +static +void +buf_page_set_accessed_make_young( +/*=============================*/ + buf_page_t* bpage, /*!< in/out: buffer block of a + file page */ + unsigned access_time) /*!< in: bpage->access_time + read under mutex protection, + or 0 if unknown */ +{ + ut_ad(!buf_pool_mutex_own()); + ut_a(buf_page_in_file(bpage)); + + if (buf_page_peek_if_too_old(bpage)) { + buf_pool_mutex_enter(); + buf_LRU_make_block_young(bpage); + buf_pool_mutex_exit(); + } else if (!access_time) { + ulint time_ms = ut_time_ms(); + buf_pool_mutex_enter(); + buf_page_set_accessed(bpage, time_ms); + buf_pool_mutex_exit(); + } +} + /********************************************************************//** Resets the check_index_page_at_flush field of a page if found in the buffer pool. */ @@ -1645,11 +1667,12 @@ buf_page_get_zip( buf_page_t* bpage; mutex_t* block_mutex; ibool must_read; + unsigned access_time; #ifndef UNIV_LOG_DEBUG ut_ad(!ibuf_inside()); #endif - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; for (;;) { buf_pool_mutex_enter(); @@ -1712,14 +1735,13 @@ err_exit: got_block: must_read = buf_page_get_io_fix(bpage) == BUF_IO_READ; + access_time = buf_page_is_accessed(bpage); buf_pool_mutex_exit(); - buf_page_set_accessed(bpage, TRUE); - mutex_exit(block_mutex); - buf_block_make_young(bpage); + buf_page_set_accessed_make_young(bpage, access_time); #ifdef UNIV_DEBUG_FILE_ACCESSES ut_a(!bpage->file_page_was_freed); @@ -1812,7 +1834,7 @@ buf_zip_decompress( switch (fil_page_get_type(frame)) { case FIL_PAGE_INDEX: if (page_zip_decompress(&block->page.zip, - block->frame)) { + block->frame, TRUE)) { return(TRUE); } @@ -2000,7 +2022,7 @@ buf_page_get_gen( mtr_t* mtr) /*!< in: mini-transaction */ { buf_block_t* block; - ibool accessed; + unsigned access_time; ulint fix_type; ibool must_read; @@ -2016,7 +2038,7 @@ buf_page_get_gen( #ifndef UNIV_LOG_DEBUG ut_ad(!ibuf_inside() || ibuf_page(space, zip_size, offset, NULL)); #endif - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; loop: block = guess; buf_pool_mutex_enter(); @@ -2243,17 +2265,16 @@ wait_until_unfixed: UNIV_MEM_ASSERT_RW(&block->page, sizeof block->page); buf_block_buf_fix_inc(block, file, line); - buf_pool_mutex_exit(); - - /* Check if this is the first access to the page */ - - accessed = buf_page_is_accessed(&block->page); - - buf_page_set_accessed(&block->page, TRUE); mutex_exit(&block->mutex); - buf_block_make_young(&block->page); + /* Check if this is the first access to the page */ + + access_time = buf_page_is_accessed(&block->page); + + buf_pool_mutex_exit(); + + buf_page_set_accessed_make_young(&block->page, access_time); #ifdef UNIV_DEBUG_FILE_ACCESSES ut_a(!block->page.file_page_was_freed); @@ -2306,7 +2327,7 @@ wait_until_unfixed: mtr_memo_push(mtr, block, fix_type); - if (!accessed) { + if (!access_time) { /* In the case of a first access, try to apply linear read-ahead */ @@ -2336,7 +2357,7 @@ buf_page_optimistic_get_func( ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mini-transaction */ { - ibool accessed; + unsigned access_time; ibool success; ulint fix_type; @@ -2353,14 +2374,16 @@ buf_page_optimistic_get_func( } buf_block_buf_fix_inc(block, file, line); - accessed = buf_page_is_accessed(&block->page); - buf_page_set_accessed(&block->page, TRUE); mutex_exit(&block->mutex); - buf_block_make_young(&block->page); + /* Check if this is the first access to the page. + We do a dirty read on purpose, to avoid mutex contention. + This field is only used for heuristic purposes; it does not + affect correctness. */ - /* Check if this is the first access to the page */ + access_time = buf_page_is_accessed(&block->page); + buf_page_set_accessed_make_young(&block->page, access_time); ut_ad(!ibuf_inside() || ibuf_page(buf_block_get_space(block), @@ -2412,7 +2435,7 @@ buf_page_optimistic_get_func( #ifdef UNIV_DEBUG_FILE_ACCESSES ut_a(block->page.file_page_was_freed == FALSE); #endif - if (UNIV_UNLIKELY(!accessed)) { + if (UNIV_UNLIKELY(!access_time)) { /* In the case of a first access, try to apply linear read-ahead */ @@ -2425,7 +2448,7 @@ buf_page_optimistic_get_func( ut_a(ibuf_count_get(buf_block_get_space(block), buf_block_get_page_no(block)) == 0); #endif - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; return(TRUE); } @@ -2473,8 +2496,20 @@ buf_page_get_known_nowait( mutex_exit(&block->mutex); - if (mode == BUF_MAKE_YOUNG) { - buf_block_make_young(&block->page); + if (mode == BUF_MAKE_YOUNG && buf_page_peek_if_too_old(&block->page)) { + buf_pool_mutex_enter(); + buf_LRU_make_block_young(&block->page); + buf_pool_mutex_exit(); + } else if (!buf_page_is_accessed(&block->page)) { + /* Above, we do a dirty read on purpose, to avoid + mutex contention. The field buf_page_t::access_time + is only used for heuristic purposes. Writes to the + field must be protected by mutex, however. */ + ulint time_ms = ut_time_ms(); + + buf_pool_mutex_enter(); + buf_page_set_accessed(&block->page, time_ms); + buf_pool_mutex_exit(); } ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD)); @@ -2513,7 +2548,7 @@ buf_page_get_known_nowait( || (ibuf_count_get(buf_block_get_space(block), buf_block_get_page_no(block)) == 0)); #endif - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; return(TRUE); } @@ -2589,7 +2624,7 @@ buf_page_try_get_func( #endif /* UNIV_DEBUG_FILE_ACCESSES */ buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK); - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; #ifdef UNIV_IBUF_COUNT_DEBUG ut_a(ibuf_count_get(buf_block_get_space(block), @@ -2608,10 +2643,10 @@ buf_page_init_low( buf_page_t* bpage) /*!< in: block to init */ { bpage->flush_type = BUF_FLUSH_LRU; - bpage->accessed = FALSE; bpage->io_fix = BUF_IO_NONE; bpage->buf_fix_count = 0; bpage->freed_page_clock = 0; + bpage->access_time = 0; bpage->newest_modification = 0; bpage->oldest_modification = 0; HASH_INVALIDATE(bpage, hash); @@ -2907,6 +2942,7 @@ buf_page_create( buf_frame_t* frame; buf_block_t* block; buf_block_t* free_block = NULL; + ulint time_ms = ut_time_ms(); ut_ad(mtr); ut_ad(space || !zip_size); @@ -2953,7 +2989,7 @@ buf_page_create( buf_LRU_add_block(&block->page, FALSE); buf_block_buf_fix_inc(block, __FILE__, __LINE__); - buf_pool->n_pages_created++; + buf_pool->stat.n_pages_created++; if (zip_size) { void* data; @@ -2990,12 +3026,12 @@ buf_page_create( rw_lock_x_unlock(&block->lock); } + buf_page_set_accessed(&block->page, time_ms); + buf_pool_mutex_exit(); mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX); - buf_page_set_accessed(&block->page, TRUE); - mutex_exit(&block->mutex); /* Delete possible entries for the page from the insert buffer: @@ -3201,7 +3237,7 @@ corrupt: ut_ad(buf_pool->n_pend_reads > 0); buf_pool->n_pend_reads--; - buf_pool->n_pages_read++; + buf_pool->stat.n_pages_read++; if (uncompressed) { rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock, @@ -3221,7 +3257,7 @@ corrupt: BUF_IO_WRITE); } - buf_pool->n_pages_written++; + buf_pool->stat.n_pages_written++; break; @@ -3251,7 +3287,32 @@ void buf_pool_invalidate(void) /*=====================*/ { - ibool freed; + ibool freed; + enum buf_flush i; + + buf_pool_mutex_enter(); + + for (i = BUF_FLUSH_LRU; i < BUF_FLUSH_N_TYPES; i++) { + + /* As this function is called during startup and + during redo application phase during recovery, InnoDB + is single threaded (apart from IO helper threads) at + this stage. No new write batch can be in intialization + stage at this point. */ + ut_ad(buf_pool->init_flush[i] == FALSE); + + /* However, it is possible that a write batch that has + been posted earlier is still not complete. For buffer + pool invalidation to proceed we must ensure there is NO + write activity happening. */ + if (buf_pool->n_flush[i] > 0) { + buf_pool_mutex_exit(); + buf_flush_wait_batch_end(i); + buf_pool_mutex_enter(); + } + } + + buf_pool_mutex_exit(); ut_ad(buf_all_freed()); @@ -3266,6 +3327,14 @@ buf_pool_invalidate(void) ut_ad(UT_LIST_GET_LEN(buf_pool->LRU) == 0); ut_ad(UT_LIST_GET_LEN(buf_pool->unzip_LRU) == 0); + buf_pool->freed_page_clock = 0; + buf_pool->LRU_old = NULL; + buf_pool->LRU_old_len = 0; + buf_pool->LRU_flush_ended = 0; + + memset(&buf_pool->stat, 0x00, sizeof(buf_pool->stat)); + buf_refresh_io_stats(); + buf_pool_mutex_exit(); } @@ -3528,6 +3597,7 @@ buf_print(void) "n pending decompressions %lu\n" "n pending reads %lu\n" "n pending flush LRU %lu list %lu single page %lu\n" + "pages made young %lu, not young %lu\n" "pages read %lu, created %lu, written %lu\n", (ulong) size, (ulong) UT_LIST_GET_LEN(buf_pool->LRU), @@ -3538,8 +3608,11 @@ buf_print(void) (ulong) buf_pool->n_flush[BUF_FLUSH_LRU], (ulong) buf_pool->n_flush[BUF_FLUSH_LIST], (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE], - (ulong) buf_pool->n_pages_read, buf_pool->n_pages_created, - (ulong) buf_pool->n_pages_written); + (ulong) buf_pool->stat.n_pages_made_young, + (ulong) buf_pool->stat.n_pages_not_made_young, + (ulong) buf_pool->stat.n_pages_read, + (ulong) buf_pool->stat.n_pages_created, + (ulong) buf_pool->stat.n_pages_written); /* Count the number of blocks belonging to each index in the buffer */ @@ -3744,10 +3817,9 @@ buf_print_io( { time_t current_time; double time_elapsed; - ulint size; + ulint n_gets_diff; ut_ad(buf_pool); - size = buf_pool->curr_size; buf_pool_mutex_enter(); @@ -3755,12 +3827,14 @@ buf_print_io( "Buffer pool size %lu\n" "Free buffers %lu\n" "Database pages %lu\n" + "Old database pages %lu\n" "Modified db pages %lu\n" "Pending reads %lu\n" "Pending writes: LRU %lu, flush list %lu, single page %lu\n", - (ulong) size, + (ulong) buf_pool->curr_size, (ulong) UT_LIST_GET_LEN(buf_pool->free), (ulong) UT_LIST_GET_LEN(buf_pool->LRU), + (ulong) buf_pool->LRU_old_len, (ulong) UT_LIST_GET_LEN(buf_pool->flush_list), (ulong) buf_pool->n_pend_reads, (ulong) buf_pool->n_flush[BUF_FLUSH_LRU] @@ -3772,37 +3846,66 @@ buf_print_io( current_time = time(NULL); time_elapsed = 0.001 + difftime(current_time, buf_pool->last_printout_time); - buf_pool->last_printout_time = current_time; fprintf(file, + "Pages made young %lu, not young %lu\n" + "%.2f youngs/s, %.2f non-youngs/s\n" "Pages read %lu, created %lu, written %lu\n" "%.2f reads/s, %.2f creates/s, %.2f writes/s\n", - (ulong) buf_pool->n_pages_read, - (ulong) buf_pool->n_pages_created, - (ulong) buf_pool->n_pages_written, - (buf_pool->n_pages_read - buf_pool->n_pages_read_old) + (ulong) buf_pool->stat.n_pages_made_young, + (ulong) buf_pool->stat.n_pages_not_made_young, + (buf_pool->stat.n_pages_made_young + - buf_pool->old_stat.n_pages_made_young) / time_elapsed, - (buf_pool->n_pages_created - buf_pool->n_pages_created_old) + (buf_pool->stat.n_pages_not_made_young + - buf_pool->old_stat.n_pages_not_made_young) / time_elapsed, - (buf_pool->n_pages_written - buf_pool->n_pages_written_old) + (ulong) buf_pool->stat.n_pages_read, + (ulong) buf_pool->stat.n_pages_created, + (ulong) buf_pool->stat.n_pages_written, + (buf_pool->stat.n_pages_read + - buf_pool->old_stat.n_pages_read) + / time_elapsed, + (buf_pool->stat.n_pages_created + - buf_pool->old_stat.n_pages_created) + / time_elapsed, + (buf_pool->stat.n_pages_written + - buf_pool->old_stat.n_pages_written) / time_elapsed); - if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) { - fprintf(file, "Buffer pool hit rate %lu / 1000\n", + n_gets_diff = buf_pool->stat.n_page_gets - buf_pool->old_stat.n_page_gets; + + if (n_gets_diff) { + fprintf(file, + "Buffer pool hit rate %lu / 1000," + " young-making rate %lu / 1000 not %lu / 1000\n", (ulong) - (1000 - ((1000 * (buf_pool->n_pages_read - - buf_pool->n_pages_read_old)) - / (buf_pool->n_page_gets - - buf_pool->n_page_gets_old)))); + (1000 - ((1000 * (buf_pool->stat.n_pages_read + - buf_pool->old_stat.n_pages_read)) + / (buf_pool->stat.n_page_gets + - buf_pool->old_stat.n_page_gets))), + (ulong) + (1000 * (buf_pool->stat.n_pages_made_young + - buf_pool->old_stat.n_pages_made_young) + / n_gets_diff), + (ulong) + (1000 * (buf_pool->stat.n_pages_not_made_young + - buf_pool->old_stat.n_pages_not_made_young) + / n_gets_diff)); } else { fputs("No buffer pool page gets since the last printout\n", file); } - buf_pool->n_page_gets_old = buf_pool->n_page_gets; - buf_pool->n_pages_read_old = buf_pool->n_pages_read; - buf_pool->n_pages_created_old = buf_pool->n_pages_created; - buf_pool->n_pages_written_old = buf_pool->n_pages_written; + /* Statistics about read ahead algorithm */ + fprintf(file, "Pages read ahead %.2f/s," + " evicted without access %.2f/s\n", + (buf_pool->stat.n_ra_pages_read + - buf_pool->old_stat.n_ra_pages_read) + / time_elapsed, + (buf_pool->stat.n_ra_pages_evicted + - buf_pool->old_stat.n_ra_pages_evicted) + / time_elapsed); /* Print some values to help us with visualizing what is happening with LRU eviction. */ @@ -3814,6 +3917,7 @@ buf_print_io( buf_LRU_stat_sum.io, buf_LRU_stat_cur.io, buf_LRU_stat_sum.unzip, buf_LRU_stat_cur.unzip); + buf_refresh_io_stats(); buf_pool_mutex_exit(); } @@ -3825,10 +3929,7 @@ buf_refresh_io_stats(void) /*======================*/ { buf_pool->last_printout_time = time(NULL); - buf_pool->n_page_gets_old = buf_pool->n_page_gets; - buf_pool->n_pages_read_old = buf_pool->n_pages_read; - buf_pool->n_pages_created_old = buf_pool->n_pages_created; - buf_pool->n_pages_written_old = buf_pool->n_pages_written; + buf_pool->old_stat = buf_pool->stat; } /*********************************************************************//** diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c index be53a5f5d9d..d3a79d62d3f 100644 --- a/storage/innobase/buf/buf0lru.c +++ b/storage/innobase/buf/buf0lru.c @@ -49,18 +49,22 @@ Created 11/5/1995 Heikki Tuuri #include "log0recv.h" #include "srv0srv.h" -/** The number of blocks from the LRU_old pointer onward, including the block -pointed to, must be 3/8 of the whole LRU list length, except that the -tolerance defined below is allowed. Note that the tolerance must be small -enough such that for even the BUF_LRU_OLD_MIN_LEN long LRU list, the -LRU_old pointer is not allowed to point to either end of the LRU list. */ +/** The number of blocks from the LRU_old pointer onward, including +the block pointed to, must be buf_LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV +of the whole LRU list length, except that the tolerance defined below +is allowed. Note that the tolerance must be small enough such that for +even the BUF_LRU_OLD_MIN_LEN long LRU list, the LRU_old pointer is not +allowed to point to either end of the LRU list. */ #define BUF_LRU_OLD_TOLERANCE 20 -/** The whole LRU list length is divided by this number to determine an -initial segment in buf_LRU_get_recent_limit */ - -#define BUF_LRU_INITIAL_RATIO 8 +/** The minimum amount of non-old blocks when the LRU_old list exists +(that is, when there are more than BUF_LRU_OLD_MIN_LEN blocks). +@see buf_LRU_old_adjust_len */ +#define BUF_LRU_NON_OLD_MIN_LEN 5 +#if BUF_LRU_NON_OLD_MIN_LEN >= BUF_LRU_OLD_MIN_LEN +# error "BUF_LRU_NON_OLD_MIN_LEN >= BUF_LRU_OLD_MIN_LEN" +#endif /** When dropping the search hash index entries before deleting an ibd file, we build a local array of pages belonging to that tablespace @@ -107,6 +111,15 @@ UNIV_INTERN buf_LRU_stat_t buf_LRU_stat_sum; /* @} */ +/** @name Heuristics for detecting index scan @{ */ +/** Reserve this much/BUF_LRU_OLD_RATIO_DIV of the buffer pool for +"old" blocks. Protected by buf_pool_mutex. */ +UNIV_INTERN uint buf_LRU_old_ratio; +/** Move blocks to "new" LRU list only if the first access was at +least this many milliseconds ago. Not protected by any mutex or latch. */ +UNIV_INTERN uint buf_LRU_old_threshold_ms; +/* @} */ + /******************************************************************//** Takes a block out of the LRU list and page hash table. If the block is compressed-only (BUF_BLOCK_ZIP_PAGE), @@ -428,42 +441,6 @@ next_page: } } -/******************************************************************//** -Gets the minimum LRU_position field for the blocks in an initial segment -(determined by BUF_LRU_INITIAL_RATIO) of the LRU list. The limit is not -guaranteed to be precise, because the ulint_clock may wrap around. -@return the limit; zero if could not determine it */ -UNIV_INTERN -ulint -buf_LRU_get_recent_limit(void) -/*==========================*/ -{ - const buf_page_t* bpage; - ulint len; - ulint limit; - - buf_pool_mutex_enter(); - - len = UT_LIST_GET_LEN(buf_pool->LRU); - - if (len < BUF_LRU_OLD_MIN_LEN) { - /* The LRU list is too short to do read-ahead */ - - buf_pool_mutex_exit(); - - return(0); - } - - bpage = UT_LIST_GET_FIRST(buf_pool->LRU); - - limit = buf_page_get_LRU_position(bpage); - len /= BUF_LRU_INITIAL_RATIO; - - buf_pool_mutex_exit(); - - return(limit > len ? (limit - len) : 0); -} - /********************************************************************//** Insert a compressed block into buf_pool->zip_clean in the LRU order. */ UNIV_INTERN @@ -594,6 +571,7 @@ buf_LRU_free_from_common_LRU_list( bpage = UT_LIST_GET_PREV(LRU, bpage), distance--) { enum buf_lru_free_block_status freed; + unsigned accessed; mutex_t* block_mutex = buf_page_get_mutex(bpage); @@ -601,11 +579,18 @@ buf_LRU_free_from_common_LRU_list( ut_ad(bpage->in_LRU_list); mutex_enter(block_mutex); + accessed = buf_page_is_accessed(bpage); freed = buf_LRU_free_block(bpage, TRUE, NULL); mutex_exit(block_mutex); switch (freed) { case BUF_LRU_FREED: + /* Keep track of pages that are evicted without + ever being accessed. This gives us a measure of + the effectiveness of readahead */ + if (!accessed) { + ++buf_pool->stat.n_ra_pages_evicted; + } return(TRUE); case BUF_LRU_NOT_FREED: @@ -953,8 +938,10 @@ buf_LRU_old_adjust_len(void) ut_a(buf_pool->LRU_old); ut_ad(buf_pool_mutex_own()); -#if 3 * (BUF_LRU_OLD_MIN_LEN / 8) <= BUF_LRU_OLD_TOLERANCE + 5 -# error "3 * (BUF_LRU_OLD_MIN_LEN / 8) <= BUF_LRU_OLD_TOLERANCE + 5" + ut_ad(buf_LRU_old_ratio >= BUF_LRU_OLD_RATIO_MIN); + ut_ad(buf_LRU_old_ratio <= BUF_LRU_OLD_RATIO_MAX); +#if BUF_LRU_OLD_RATIO_MIN * BUF_LRU_OLD_MIN_LEN <= BUF_LRU_OLD_RATIO_DIV * (BUF_LRU_OLD_TOLERANCE + 5) +# error "BUF_LRU_OLD_RATIO_MIN * BUF_LRU_OLD_MIN_LEN <= BUF_LRU_OLD_RATIO_DIV * (BUF_LRU_OLD_TOLERANCE + 5)" #endif #ifdef UNIV_LRU_DEBUG /* buf_pool->LRU_old must be the first item in the LRU list @@ -966,34 +953,39 @@ buf_LRU_old_adjust_len(void) || UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)->old); #endif /* UNIV_LRU_DEBUG */ - for (;;) { - old_len = buf_pool->LRU_old_len; - new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8); + old_len = buf_pool->LRU_old_len; + new_len = ut_min(UT_LIST_GET_LEN(buf_pool->LRU) + * buf_LRU_old_ratio / BUF_LRU_OLD_RATIO_DIV, + UT_LIST_GET_LEN(buf_pool->LRU) + - (BUF_LRU_OLD_TOLERANCE + + BUF_LRU_NON_OLD_MIN_LEN)); - ut_ad(buf_pool->LRU_old->in_LRU_list); - ut_a(buf_pool->LRU_old); + for (;;) { + buf_page_t* LRU_old = buf_pool->LRU_old; + + ut_a(LRU_old); + ut_ad(LRU_old->in_LRU_list); #ifdef UNIV_LRU_DEBUG - ut_a(buf_pool->LRU_old->old); + ut_a(LRU_old->old); #endif /* UNIV_LRU_DEBUG */ /* Update the LRU_old pointer if necessary */ - if (old_len < new_len - BUF_LRU_OLD_TOLERANCE) { + if (old_len + BUF_LRU_OLD_TOLERANCE < new_len) { - buf_pool->LRU_old = UT_LIST_GET_PREV( - LRU, buf_pool->LRU_old); + buf_pool->LRU_old = LRU_old = UT_LIST_GET_PREV( + LRU, LRU_old); #ifdef UNIV_LRU_DEBUG - ut_a(!buf_pool->LRU_old->old); + ut_a(!LRU_old->old); #endif /* UNIV_LRU_DEBUG */ - buf_page_set_old(buf_pool->LRU_old, TRUE); - buf_pool->LRU_old_len++; + buf_page_set_old(LRU_old, TRUE); + old_len = ++buf_pool->LRU_old_len; } else if (old_len > new_len + BUF_LRU_OLD_TOLERANCE) { - buf_page_set_old(buf_pool->LRU_old, FALSE); - buf_pool->LRU_old = UT_LIST_GET_NEXT( - LRU, buf_pool->LRU_old); - buf_pool->LRU_old_len--; + buf_page_set_old(LRU_old, FALSE); + buf_pool->LRU_old = UT_LIST_GET_NEXT(LRU, LRU_old); + old_len = --buf_pool->LRU_old_len; } else { return; } @@ -1021,6 +1013,7 @@ buf_LRU_old_init(void) while (bpage != NULL) { ut_ad(bpage->in_LRU_list); + ut_ad(buf_page_in_file(bpage)); buf_page_set_old(bpage, TRUE); bpage = UT_LIST_GET_NEXT(LRU, bpage); } @@ -1075,16 +1068,19 @@ buf_LRU_remove_block( if (UNIV_UNLIKELY(bpage == buf_pool->LRU_old)) { - /* Below: the previous block is guaranteed to exist, because - the LRU_old pointer is only allowed to differ by the - tolerance value from strict 3/8 of the LRU list length. */ + /* Below: the previous block is guaranteed to exist, + because the LRU_old pointer is only allowed to differ + by BUF_LRU_OLD_TOLERANCE from strict + buf_LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV of the LRU + list length. */ + buf_page_t* prev_bpage = UT_LIST_GET_PREV(LRU, bpage); - buf_pool->LRU_old = UT_LIST_GET_PREV(LRU, bpage); - ut_a(buf_pool->LRU_old); + ut_a(prev_bpage); #ifdef UNIV_LRU_DEBUG - ut_a(!buf_pool->LRU_old->old); + ut_a(!prev_bpage->old); #endif /* UNIV_LRU_DEBUG */ - buf_page_set_old(buf_pool->LRU_old, TRUE); + buf_pool->LRU_old = prev_bpage; + buf_page_set_old(prev_bpage, TRUE); buf_pool->LRU_old_len++; } @@ -1149,39 +1145,25 @@ buf_LRU_add_block_to_end_low( /*=========================*/ buf_page_t* bpage) /*!< in: control block */ { - buf_page_t* last_bpage; - ut_ad(buf_pool); ut_ad(bpage); ut_ad(buf_pool_mutex_own()); ut_a(buf_page_in_file(bpage)); - last_bpage = UT_LIST_GET_LAST(buf_pool->LRU); - - if (last_bpage) { - bpage->LRU_position = last_bpage->LRU_position; - } else { - bpage->LRU_position = buf_pool_clock_tic(); - } - ut_ad(!bpage->in_LRU_list); UT_LIST_ADD_LAST(LRU, buf_pool->LRU, bpage); ut_d(bpage->in_LRU_list = TRUE); buf_page_set_old(bpage, TRUE); - if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) { - - buf_pool->LRU_old_len++; - } - if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) { ut_ad(buf_pool->LRU_old); /* Adjust the length of the old block list if necessary */ + buf_pool->LRU_old_len++; buf_LRU_old_adjust_len(); } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) { @@ -1189,6 +1171,7 @@ buf_LRU_add_block_to_end_low( /* The LRU list is now long enough for LRU_old to become defined: init it */ + buf_pool->LRU_old_len++; buf_LRU_old_init(); } @@ -1222,7 +1205,6 @@ buf_LRU_add_block_low( UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, bpage); - bpage->LRU_position = buf_pool_clock_tic(); bpage->freed_page_clock = buf_pool->freed_page_clock; } else { #ifdef UNIV_LRU_DEBUG @@ -1237,11 +1219,6 @@ buf_LRU_add_block_low( UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, buf_pool->LRU_old, bpage); buf_pool->LRU_old_len++; - - /* We copy the LRU position field of the previous block - to the new block */ - - bpage->LRU_position = (buf_pool->LRU_old)->LRU_position; } ut_d(bpage->in_LRU_list = TRUE); @@ -1295,6 +1272,12 @@ buf_LRU_make_block_young( /*=====================*/ buf_page_t* bpage) /*!< in: control block */ { + ut_ad(buf_pool_mutex_own()); + + if (bpage->old) { + buf_pool->stat.n_pages_made_young++; + } + buf_LRU_remove_block(bpage); buf_LRU_add_block_low(bpage, FALSE); } @@ -1847,6 +1830,50 @@ buf_LRU_block_free_hashed_page( buf_LRU_block_free_non_file_page(block); } +/**********************************************************************//** +Updates buf_LRU_old_ratio. +@return updated old_pct */ +UNIV_INTERN +uint +buf_LRU_old_ratio_update( +/*=====================*/ + uint old_pct,/*!< in: Reserve this percentage of + the buffer pool for "old" blocks. */ + ibool adjust) /*!< in: TRUE=adjust the LRU list; + FALSE=just assign buf_LRU_old_ratio + during the initialization of InnoDB */ +{ + uint ratio; + + ratio = old_pct * BUF_LRU_OLD_RATIO_DIV / 100; + if (ratio < BUF_LRU_OLD_RATIO_MIN) { + ratio = BUF_LRU_OLD_RATIO_MIN; + } else if (ratio > BUF_LRU_OLD_RATIO_MAX) { + ratio = BUF_LRU_OLD_RATIO_MAX; + } + + if (adjust) { + buf_pool_mutex_enter(); + + if (ratio != buf_LRU_old_ratio) { + buf_LRU_old_ratio = ratio; + + if (UT_LIST_GET_LEN(buf_pool->LRU) + >= BUF_LRU_OLD_MIN_LEN) { + buf_LRU_old_adjust_len(); + } + } + + buf_pool_mutex_exit(); + } else { + buf_LRU_old_ratio = ratio; + } + + /* the reverse of + ratio = old_pct * BUF_LRU_OLD_RATIO_DIV / 100 */ + return((uint) (ratio * 100 / (double) BUF_LRU_OLD_RATIO_DIV + 0.5)); +} + /********************************************************************//** Update the historical stats that we are collecting for LRU eviction policy at the end of each interval. */ @@ -1896,7 +1923,6 @@ buf_LRU_validate(void) buf_block_t* block; ulint old_len; ulint new_len; - ulint LRU_pos; ut_ad(buf_pool); buf_pool_mutex_enter(); @@ -1905,7 +1931,11 @@ buf_LRU_validate(void) ut_a(buf_pool->LRU_old); old_len = buf_pool->LRU_old_len; - new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8); + new_len = ut_min(UT_LIST_GET_LEN(buf_pool->LRU) + * buf_LRU_old_ratio / BUF_LRU_OLD_RATIO_DIV, + UT_LIST_GET_LEN(buf_pool->LRU) + - (BUF_LRU_OLD_TOLERANCE + + BUF_LRU_NON_OLD_MIN_LEN)); ut_a(old_len >= new_len - BUF_LRU_OLD_TOLERANCE); ut_a(old_len <= new_len + BUF_LRU_OLD_TOLERANCE); } @@ -1943,16 +1973,7 @@ buf_LRU_validate(void) ut_a(buf_pool->LRU_old == bpage); } - LRU_pos = buf_page_get_LRU_position(bpage); - bpage = UT_LIST_GET_NEXT(LRU, bpage); - - if (bpage) { - /* If the following assert fails, it may - not be an error: just the buf_pool clock - has wrapped around */ - ut_a(LRU_pos >= buf_page_get_LRU_position(bpage)); - } } if (buf_pool->LRU_old) { @@ -2000,9 +2021,6 @@ buf_LRU_print(void) ut_ad(buf_pool); buf_pool_mutex_enter(); - fprintf(stderr, "Pool ulint clock %lu\n", - (ulong) buf_pool->ulint_clock); - bpage = UT_LIST_GET_FIRST(buf_pool->LRU); while (bpage != NULL) { @@ -2033,18 +2051,16 @@ buf_LRU_print(void) const byte* frame; case BUF_BLOCK_FILE_PAGE: frame = buf_block_get_frame((buf_block_t*) bpage); - fprintf(stderr, "\nLRU pos %lu type %lu" + fprintf(stderr, "\ntype %lu" " index id %lu\n", - (ulong) buf_page_get_LRU_position(bpage), (ulong) fil_page_get_type(frame), (ulong) ut_dulint_get_low( btr_page_get_index_id(frame))); break; case BUF_BLOCK_ZIP_PAGE: frame = bpage->zip.data; - fprintf(stderr, "\nLRU pos %lu type %lu size %lu" + fprintf(stderr, "\ntype %lu size %lu" " index id %lu\n", - (ulong) buf_page_get_LRU_position(bpage), (ulong) fil_page_get_type(frame), (ulong) buf_page_get_zip_size(bpage), (ulong) ut_dulint_get_low( @@ -2052,8 +2068,7 @@ buf_LRU_print(void) break; default: - fprintf(stderr, "\nLRU pos %lu !state %lu!\n", - (ulong) buf_page_get_LRU_position(bpage), + fprintf(stderr, "\n!state %lu!\n", (ulong) buf_page_get_state(bpage)); break; } diff --git a/storage/innobase/buf/buf0rea.c b/storage/innobase/buf/buf0rea.c index 319d6b2a522..dd98ea17eb5 100644 --- a/storage/innobase/buf/buf0rea.c +++ b/storage/innobase/buf/buf0rea.c @@ -38,14 +38,6 @@ Created 11/5/1995 Heikki Tuuri #include "srv0start.h" #include "srv0srv.h" -/** The size in blocks of the area where the random read-ahead algorithm counts -the accessed pages when deciding whether to read-ahead */ -#define BUF_READ_AHEAD_RANDOM_AREA BUF_READ_AHEAD_AREA - -/** There must be at least this many pages in buf_pool in the area to start -a random read-ahead */ -#define BUF_READ_AHEAD_RANDOM_THRESHOLD (1 + BUF_READ_AHEAD_RANDOM_AREA / 2) - /** The linear read-ahead area size */ #define BUF_READ_AHEAD_LINEAR_AREA BUF_READ_AHEAD_AREA @@ -62,7 +54,8 @@ flag is cleared and the x-lock released by an i/o-handler thread. @return 1 if a read request was queued, 0 if the page already resided in buf_pool, or if the page is in the doublewrite buffer blocks in which case it is never read into the pool, or if the tablespace does -not exist or is being dropped */ +not exist or is being dropped +@return 1 if read request is issued. 0 if it is not */ static ulint buf_read_page_low( @@ -164,175 +157,14 @@ buf_read_page_low( return(1); } -/********************************************************************//** -Applies a random read-ahead in buf_pool if there are at least a threshold -value of accessed pages from the random read-ahead area. Does not read any -page, not even the one at the position (space, offset), if the read-ahead -mechanism is not activated. NOTE 1: the calling thread may own latches on -pages: to avoid deadlocks this function must be written such that it cannot -end up waiting for these latches! NOTE 2: the calling thread must want -access to the page given: this rule is set to prevent unintended read-aheads -performed by ibuf routines, a situation which could result in a deadlock if -the OS does not support asynchronous i/o. -@return number of page read requests issued; NOTE that if we read ibuf -pages, it may happen that the page at the given page number does not -get read even if we return a positive value! */ -static -ulint -buf_read_ahead_random( -/*==================*/ - ulint space, /*!< in: space id */ - ulint zip_size,/*!< in: compressed page size in bytes, or 0 */ - ulint offset) /*!< in: page number of a page which the current thread - wants to access */ -{ - ib_int64_t tablespace_version; - ulint recent_blocks = 0; - ulint count; - ulint LRU_recent_limit; - ulint ibuf_mode; - ulint low, high; - ulint err; - ulint i; - ulint buf_read_ahead_random_area; - - /* We have currently disabled random readahead */ - return(0); - - if (srv_startup_is_before_trx_rollback_phase) { - /* No read-ahead to avoid thread deadlocks */ - return(0); - } - - if (ibuf_bitmap_page(zip_size, offset) - || trx_sys_hdr_page(space, offset)) { - - /* If it is an ibuf bitmap page or trx sys hdr, we do - no read-ahead, as that could break the ibuf page access - order */ - - return(0); - } - - /* Remember the tablespace version before we ask te tablespace size - below: if DISCARD + IMPORT changes the actual .ibd file meanwhile, we - do not try to read outside the bounds of the tablespace! */ - - tablespace_version = fil_space_get_version(space); - - buf_read_ahead_random_area = BUF_READ_AHEAD_RANDOM_AREA; - - low = (offset / buf_read_ahead_random_area) - * buf_read_ahead_random_area; - high = (offset / buf_read_ahead_random_area + 1) - * buf_read_ahead_random_area; - if (high > fil_space_get_size(space)) { - - high = fil_space_get_size(space); - } - - /* Get the minimum LRU_position field value for an initial segment - of the LRU list, to determine which blocks have recently been added - to the start of the list. */ - - LRU_recent_limit = buf_LRU_get_recent_limit(); - - buf_pool_mutex_enter(); - - if (buf_pool->n_pend_reads - > buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) { - buf_pool_mutex_exit(); - - return(0); - } - - /* Count how many blocks in the area have been recently accessed, - that is, reside near the start of the LRU list. */ - - for (i = low; i < high; i++) { - const buf_page_t* bpage = buf_page_hash_get(space, i); - - if (bpage - && buf_page_is_accessed(bpage) - && (buf_page_get_LRU_position(bpage) > LRU_recent_limit)) { - - recent_blocks++; - - if (recent_blocks >= BUF_READ_AHEAD_RANDOM_THRESHOLD) { - - buf_pool_mutex_exit(); - goto read_ahead; - } - } - } - - buf_pool_mutex_exit(); - /* Do nothing */ - return(0); - -read_ahead: - /* Read all the suitable blocks within the area */ - - if (ibuf_inside()) { - ibuf_mode = BUF_READ_IBUF_PAGES_ONLY; - } else { - ibuf_mode = BUF_READ_ANY_PAGE; - } - - count = 0; - - for (i = low; i < high; i++) { - /* It is only sensible to do read-ahead in the non-sync aio - mode: hence FALSE as the first parameter */ - - if (!ibuf_bitmap_page(zip_size, i)) { - count += buf_read_page_low( - &err, FALSE, - ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER, - space, zip_size, FALSE, - tablespace_version, i); - if (err == DB_TABLESPACE_DELETED) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Warning: in random" - " readahead trying to access\n" - "InnoDB: tablespace %lu page %lu,\n" - "InnoDB: but the tablespace does not" - " exist or is just being dropped.\n", - (ulong) space, (ulong) i); - } - } - } - - /* In simulated aio we wake the aio handler threads only after - queuing all aio requests, in native aio the following call does - nothing: */ - - os_aio_simulated_wake_handler_threads(); - -#ifdef UNIV_DEBUG - if (buf_debug_prints && (count > 0)) { - fprintf(stderr, - "Random read-ahead space %lu offset %lu pages %lu\n", - (ulong) space, (ulong) offset, - (ulong) count); - } -#endif /* UNIV_DEBUG */ - - ++srv_read_ahead_rnd; - return(count); -} - /********************************************************************//** High-level function which reads a page asynchronously from a file to the buffer buf_pool if it is not already there. Sets the io_fix flag and sets an exclusive lock on the buffer frame. The flag is cleared and the x-lock -released by the i/o-handler thread. Does a random read-ahead if it seems -sensible. -@return number of page read requests issued: this can be greater than -1 if read-ahead occurred */ +released by the i/o-handler thread. +@return TRUE if page has been read in, FALSE in case of failure */ UNIV_INTERN -ulint +ibool buf_read_page( /*==========*/ ulint space, /*!< in: space id */ @@ -341,20 +173,17 @@ buf_read_page( { ib_int64_t tablespace_version; ulint count; - ulint count2; ulint err; tablespace_version = fil_space_get_version(space); - count = buf_read_ahead_random(space, zip_size, offset); - /* We do the i/o in the synchronous aio mode to save thread switches: hence TRUE */ - count2 = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space, - zip_size, FALSE, - tablespace_version, offset); - srv_buf_pool_reads+= count2; + count = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space, + zip_size, FALSE, + tablespace_version, offset); + srv_buf_pool_reads += count; if (err == DB_TABLESPACE_DELETED) { ut_print_timestamp(stderr); fprintf(stderr, @@ -371,14 +200,14 @@ buf_read_page( /* Increment number of I/O operations used for LRU policy. */ buf_LRU_stat_inc_io(); - return(count + count2); + return(count > 0); } /********************************************************************//** Applies linear read-ahead if in the buf_pool the page is a border page of a linear read-ahead area and all the pages in the area have been accessed. Does not read any page if the read-ahead mechanism is not activated. Note -that the the algorithm looks at the 'natural' adjacent successor and +that the algorithm looks at the 'natural' adjacent successor and predecessor of the page, which on the leaf level of a B-tree are the next and previous page in the chain of leaves. To know these, the page specified in (space, offset) must already be present in the buf_pool. Thus, the @@ -498,9 +327,17 @@ buf_read_ahead_linear( fail_count++; } else if (pred_bpage) { - int res = (ut_ulint_cmp( - buf_page_get_LRU_position(bpage), - buf_page_get_LRU_position(pred_bpage))); + /* Note that buf_page_is_accessed() returns + the time of the first access. If some blocks + of the extent existed in the buffer pool at + the time of a linear access pattern, the first + access times may be nonmonotonic, even though + the latest access times were linear. The + threshold (srv_read_ahead_factor) should help + a little against this. */ + int res = ut_ulint_cmp( + buf_page_is_accessed(bpage), + buf_page_is_accessed(pred_bpage)); /* Accesses not in the right order */ if (res != 0 && res != asc_or_desc) { fail_count++; @@ -643,7 +480,7 @@ buf_read_ahead_linear( LRU policy decision. */ buf_LRU_stat_inc_io(); - ++srv_read_ahead_seq; + buf_pool->stat.n_ra_pages_read += count; return(count); } diff --git a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c index 7bad4d2057e..96a9bd8152e 100644 --- a/storage/innobase/dict/dict0crea.c +++ b/storage/innobase/dict/dict0crea.c @@ -1379,7 +1379,7 @@ dict_create_add_foreign_field_to_dictionary( Add a single foreign key definition to the data dictionary tables in the database. We also generate names to constraints that were not named by the user. A generated constraint has a name of the format -databasename/tablename_ibfk_, where the numbers start from 1, and +databasename/tablename_ibfk_NUMBER, where the numbers start from 1, and are given locally for this table, that is, the number is not global, as in the old format constraints < 4.0.18 it used to be. @return error code or DB_SUCCESS */ diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index d1f0e0ffc19..aedaf7cec1d 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -82,9 +82,10 @@ static char dict_ibfk[] = "_ibfk_"; /*******************************************************************//** Tries to find column names for the index and sets the col field of the -index. */ +index. +@return TRUE if the column names were found */ static -void +ibool dict_index_find_cols( /*=================*/ dict_table_t* table, /*!< in: table */ @@ -1169,7 +1170,7 @@ dict_col_name_is_reserved( ulint i; for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) { - if (strcmp(name, reserved_names[i]) == 0) { + if (innobase_strcasecmp(name, reserved_names[i]) == 0) { return(TRUE); } @@ -1431,7 +1432,7 @@ add_field_size: /**********************************************************************//** Adds an index to the dictionary cache. -@return DB_SUCCESS or DB_TOO_BIG_RECORD */ +@return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */ UNIV_INTERN ulint dict_index_add_to_cache( @@ -1457,7 +1458,10 @@ dict_index_add_to_cache( ut_a(!dict_index_is_clust(index) || UT_LIST_GET_LEN(table->indexes) == 0); - dict_index_find_cols(table, index); + if (!dict_index_find_cols(table, index)) { + + return(DB_CORRUPTION); + } /* Build the cache internal representation of the index, containing also the added system fields */ @@ -1665,9 +1669,10 @@ dict_index_remove_from_cache( /*******************************************************************//** Tries to find column names for the index and sets the col field of the -index. */ +index. +@return TRUE if the column names were found */ static -void +ibool dict_index_find_cols( /*=================*/ dict_table_t* table, /*!< in: table */ @@ -1692,17 +1697,21 @@ dict_index_find_cols( } } +#ifdef UNIV_DEBUG /* It is an error not to find a matching column. */ fputs("InnoDB: Error: no matching column for ", stderr); ut_print_name(stderr, NULL, FALSE, field->name); fputs(" in ", stderr); dict_index_name_print(stderr, NULL, index); fputs("!\n", stderr); - ut_error; +#endif /* UNIV_DEBUG */ + return(FALSE); found: ; } + + return(TRUE); } #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c index 96e60b0128f..df6dad86990 100644 --- a/storage/innobase/fil/fil0fil.c +++ b/storage/innobase/fil/fil0fil.c @@ -594,6 +594,11 @@ fil_node_create( UT_LIST_ADD_LAST(chain, space->chain, node); + if (id < SRV_LOG_SPACE_FIRST_ID && fil_system->max_assigned_id < id) { + + fil_system->max_assigned_id = id; + } + mutex_exit(&fil_system->mutex); } @@ -613,12 +618,10 @@ fil_node_open_file( ulint size_high; ibool ret; ibool success; -#ifndef UNIV_HOTBACKUP byte* buf2; byte* page; ulint space_id; ulint flags; -#endif /* !UNIV_HOTBACKUP */ ut_ad(mutex_own(&(system->mutex))); ut_a(node->n_pending == 0); @@ -654,9 +657,11 @@ fil_node_open_file( size_bytes = (((ib_int64_t)size_high) << 32) + (ib_int64_t)size_low; #ifdef UNIV_HOTBACKUP - node->size = (ulint) (size_bytes / UNIV_PAGE_SIZE); - /* TODO: adjust to zip_size, like below? */ -#else + if (space->id == 0) { + node->size = (ulint) (size_bytes / UNIV_PAGE_SIZE); + goto add_size; + } +#endif /* UNIV_HOTBACKUP */ ut_a(space->purpose != FIL_LOG); ut_a(space->id != 0); @@ -735,7 +740,10 @@ fil_node_open_file( (size_bytes / dict_table_flags_to_zip_size(flags)); } -#endif + +#ifdef UNIV_HOTBACKUP +add_size: +#endif /* UNIV_HOTBACKUP */ space->size += node->size; } @@ -955,7 +963,7 @@ close_more: " while the maximum\n" "InnoDB: allowed value would be %lu.\n" "InnoDB: You may need to raise the value of" - " innodb_max_files_open in\n" + " innodb_open_files in\n" "InnoDB: my.cnf.\n", (ulong) fil_system->n_open, (ulong) fil_system->max_n_open); @@ -1535,7 +1543,7 @@ fil_open_log_and_system_tablespace_files(void) fprintf(stderr, "InnoDB: Warning: you must" " raise the value of" - " innodb_max_open_files in\n" + " innodb_open_files in\n" "InnoDB: my.cnf! Remember that" " InnoDB keeps all log files" " and all system\n" @@ -2923,7 +2931,6 @@ fil_open_single_table_tablespace( byte* page; ulint space_id; ulint space_flags; - ibool ret = TRUE; filepath = fil_make_ibd_name(name, FALSE); @@ -3001,7 +3008,7 @@ fil_open_single_table_tablespace( (ulong) space_id, (ulong) space_flags, (ulong) id, (ulong) flags); - ret = FALSE; + success = FALSE; goto func_exit; } @@ -3021,7 +3028,7 @@ func_exit: os_file_close(file); mem_free(filepath); - return(ret); + return(success); } #endif /* !UNIV_HOTBACKUP */ @@ -3299,7 +3306,17 @@ fil_load_single_table_tablespace( if (!success) { - goto func_exit; + if (srv_force_recovery > 0) { + fprintf(stderr, + "InnoDB: innodb_force_recovery" + " was set to %lu. Continuing crash recovery\n" + "InnoDB: even though the tablespace creation" + " of this table failed.\n", + srv_force_recovery); + goto func_exit; + } + + exit(1); } /* We do not use the size information we have about the file, because diff --git a/storage/innobase/fsp/fsp0fsp.c b/storage/innobase/fsp/fsp0fsp.c index ce14723ba18..3cc4318fc06 100644 --- a/storage/innobase/fsp/fsp0fsp.c +++ b/storage/innobase/fsp/fsp0fsp.c @@ -232,6 +232,9 @@ the extent are free and which contain old tuple version to clean. */ #define XDES_ARR_OFFSET (FSP_HEADER_OFFSET + FSP_HEADER_SIZE) #ifndef UNIV_HOTBACKUP +/* Flag to indicate if we have printed the tablespace full error. */ +static ibool fsp_tbs_full_error_printed = FALSE; + /**********************************************************************//** Returns an extent to the free list of a space. */ static @@ -1099,7 +1102,7 @@ fsp_header_inc_size( /**********************************************************************//** Gets the current free limit of the system tablespace. The free limit -means the place of the first page which has never been put to the the +means the place of the first page which has never been put to the free list for allocation. The space above that address is initialized to zero. Sets also the global variable log_fsp_current_free_limit. @return free limit in megabytes */ @@ -1218,6 +1221,19 @@ fsp_try_extend_data_file( if (space == 0 && !srv_auto_extend_last_data_file) { + /* We print the error message only once to avoid + spamming the error log. Note that we don't need + to reset the flag to FALSE as dealing with this + error requires server restart. */ + if (fsp_tbs_full_error_printed == FALSE) { + fprintf(stderr, + "InnoDB: Error: Data file(s) ran" + " out of space.\n" + "Please add another data file or" + " use \'autoextend\' for the last" + " data file.\n"); + fsp_tbs_full_error_printed = TRUE; + } return(FALSE); } @@ -1832,6 +1848,8 @@ fsp_seg_inode_page_find_used( if (!ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID))) { /* This is used */ + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); return(i); } } @@ -1863,6 +1881,9 @@ fsp_seg_inode_page_find_free( return(i); } + + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); } return(ULINT_UNDEFINED); @@ -1981,6 +2002,8 @@ fsp_alloc_seg_inode( page + FSEG_INODE_PAGE_NODE, mtr); } + ut_ad(ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID)) + || mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); return(inode); } @@ -2018,7 +2041,7 @@ fsp_free_seg_inode( } mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr); - mlog_write_ulint(inode + FSEG_MAGIC_N, 0, MLOG_4BYTES, mtr); + mlog_write_ulint(inode + FSEG_MAGIC_N, 0xfa051ce3, MLOG_4BYTES, mtr); if (ULINT_UNDEFINED == fsp_seg_inode_page_find_used(page, zip_size, mtr)) { @@ -2034,11 +2057,11 @@ fsp_free_seg_inode( /**********************************************************************//** Returns the file segment inode, page x-latched. -@return segment inode, page x-latched */ +@return segment inode, page x-latched; NULL if the inode is free */ static fseg_inode_t* -fseg_inode_get( -/*===========*/ +fseg_inode_try_get( +/*===============*/ fseg_header_t* header, /*!< in: segment header */ ulint space, /*!< in: space id */ ulint zip_size,/*!< in: compressed page size in bytes @@ -2054,8 +2077,34 @@ fseg_inode_get( inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr); - ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); + if (UNIV_UNLIKELY + (ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID)))) { + inode = NULL; + } else { + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); + } + + return(inode); +} + +/**********************************************************************//** +Returns the file segment inode, page x-latched. +@return segment inode, page x-latched */ +static +fseg_inode_t* +fseg_inode_get( +/*===========*/ + fseg_header_t* header, /*!< in: segment header */ + ulint space, /*!< in: space id */ + ulint zip_size,/*!< in: compressed page size in bytes + or 0 for uncompressed pages */ + mtr_t* mtr) /*!< in: mtr handle */ +{ + fseg_inode_t* inode + = fseg_inode_try_get(header, space, zip_size, mtr); + ut_a(inode); return(inode); } @@ -2073,6 +2122,7 @@ fseg_get_nth_frag_page_no( ut_ad(inode && mtr); ut_ad(n < FSEG_FRAG_ARR_N_SLOTS); ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX)); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); return(mach_read_from_4(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE)); } @@ -2091,6 +2141,7 @@ fseg_set_nth_frag_page_no( ut_ad(inode && mtr); ut_ad(n < FSEG_FRAG_ARR_N_SLOTS); ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX)); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE, page_no, MLOG_4BYTES, mtr); @@ -2451,6 +2502,8 @@ fseg_fill_free_list( xdes_set_state(descr, XDES_FSEG, mtr); seg_id = mtr_read_dulint(inode + FSEG_ID, mtr); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); mlog_write_dulint(descr + XDES_ID, seg_id, mtr); flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr); @@ -2479,6 +2532,7 @@ fseg_alloc_free_extent( fil_addr_t first; ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE)); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); if (flst_get_len(inode + FSEG_FREE, mtr) > 0) { /* Segment free list is not empty, allocate from it */ @@ -3136,6 +3190,8 @@ fseg_mark_page_used( ut_ad(seg_inode && mtr); ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE)); + ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); descr = xdes_get_descriptor(space, zip_size, page, mtr); @@ -3373,6 +3429,8 @@ fseg_free_extent( ut_a(xdes_get_state(descr, mtr) == XDES_FSEG); ut_a(0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, mtr), mtr_read_dulint(seg_inode + FSEG_ID, mtr))); + ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); first_page_in_extent = page - (page % FSP_EXTENT_SIZE); @@ -3463,7 +3521,13 @@ fseg_free_step( ut_a(descr); ut_a(xdes_get_bit(descr, XDES_FREE_BIT, header_page % FSP_EXTENT_SIZE, mtr) == FALSE); - inode = fseg_inode_get(header, space, zip_size, mtr); + inode = fseg_inode_try_get(header, space, zip_size, mtr); + + if (UNIV_UNLIKELY(inode == NULL)) { + fprintf(stderr, "double free of inode from %u:%u\n", + (unsigned) space, (unsigned) header_page); + return(TRUE); + } descr = fseg_get_first_extent(inode, space, zip_size, mtr); @@ -3587,6 +3651,7 @@ fseg_get_first_extent( ut_ad(inode && mtr); ut_ad(space == page_get_space_id(page_align(inode))); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); first = fil_addr_null; @@ -3801,6 +3866,7 @@ fseg_print_low( (ulong) reserved, (ulong) used, (ulong) n_full, (ulong) n_frag, (ulong) n_free, (ulong) n_not_full, (ulong) n_used); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); } #ifdef UNIV_BTR_PRINT diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index f9c893ac845..3b0b53fed74 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -72,6 +72,7 @@ with this program; if not, write to the Free Software Foundation, Inc., /* Include necessary InnoDB headers */ extern "C" { #include "univ.i" +#include "buf0lru.h" #include "btr0sea.h" #include "os0file.h" #include "os0thread.h" @@ -106,6 +107,9 @@ extern "C" { #include "i_s.h" #ifndef MYSQL_SERVER +# ifndef MYSQL_PLUGIN_IMPORT +# define MYSQL_PLUGIN_IMPORT /* nothing */ +# endif /* MYSQL_PLUGIN_IMPORT */ /* This is needed because of Bug #3596. Let us hope that pthread_mutex_t is defined the same in both builds: the MySQL server and the InnoDB plugin. */ extern MYSQL_PLUGIN_IMPORT pthread_mutex_t LOCK_thread_count; @@ -152,6 +156,10 @@ static ulong innobase_write_io_threads; static long long innobase_buffer_pool_size, innobase_log_file_size; +/** Percentage of the buffer pool to reserve for 'old' blocks. +Connected to buf_LRU_old_ratio. */ +static uint innobase_old_blocks_pct; + /* The default values for the following char* start-up parameters are determined in innobase_init below: */ @@ -166,9 +174,7 @@ file formats in the configuration file, but can only be set to any of the supported file formats during runtime. */ static char* innobase_file_format_check = NULL; -/* The following has a misleading name: starting from 4.0.5, this also -affects Windows: */ -static char* innobase_unix_file_flush_method = NULL; +static char* innobase_file_flush_method = NULL; /* Below we have boolean-valued start-up parameters, and their default values */ @@ -214,15 +220,34 @@ static void free_share(INNOBASE_SHARE *share); static int innobase_close_connection(handlerton *hton, THD* thd); static int innobase_commit(handlerton *hton, THD* thd, bool all); static int innobase_rollback(handlerton *hton, THD* thd, bool all); -static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd, +static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd, void *savepoint); static int innobase_savepoint(handlerton *hton, THD* thd, void *savepoint); -static int innobase_release_savepoint(handlerton *hton, THD* thd, +static int innobase_release_savepoint(handlerton *hton, THD* thd, void *savepoint); static handler *innobase_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); +/*********************************************************************** +This function checks each index name for a table against reserved +system default primary index name 'GEN_CLUST_INDEX'. If a name matches, +this function pushes an error message to the client, and returns true. */ +static +bool +innobase_index_name_is_reserved( +/*============================*/ + /* out: true if index name matches a + reserved name */ + const trx_t* trx, /* in: InnoDB transaction handle */ + const TABLE* form, /* in: information on table + columns and indexes */ + const char* norm_name); /* in: table name */ + +/* "GEN_CLUST_INDEX" is the name reserved for Innodb default +system primary index. */ +static const char innobase_index_reserve_name[]= "GEN_CLUST_INDEX"; + /** @brief Initialize the default value of innodb_commit_concurrency. Once InnoDB is running, the innodb_commit_concurrency must not change @@ -492,10 +517,10 @@ static SHOW_VAR innodb_status_variables[]= { (char*) &export_vars.innodb_buffer_pool_pages_misc, SHOW_LONG}, {"buffer_pool_pages_total", (char*) &export_vars.innodb_buffer_pool_pages_total, SHOW_LONG}, - {"buffer_pool_read_ahead_rnd", - (char*) &export_vars.innodb_buffer_pool_read_ahead_rnd, SHOW_LONG}, - {"buffer_pool_read_ahead_seq", - (char*) &export_vars.innodb_buffer_pool_read_ahead_seq, SHOW_LONG}, + {"buffer_pool_read_ahead", + (char*) &export_vars.innodb_buffer_pool_read_ahead, SHOW_LONG}, + {"buffer_pool_read_ahead_evicted", + (char*) &export_vars.innodb_buffer_pool_read_ahead_evicted, SHOW_LONG}, {"buffer_pool_read_requests", (char*) &export_vars.innodb_buffer_pool_read_requests, SHOW_LONG}, {"buffer_pool_reads", @@ -865,17 +890,14 @@ convert_error_code_to_mysql( return(ER_PRIMARY_CANT_HAVE_NULL); case DB_TOO_MANY_CONCURRENT_TRXS: - /* Once MySQL add the appropriate code to errmsg.txt then - we can get rid of this #ifdef. NOTE: The code checked by - the #ifdef is the suggested name for the error condition - and the actual error code name could very well be different. - This will require some monitoring, ie. the status - of this request on our part.*/ -#ifdef ER_TOO_MANY_CONCURRENT_TRXS - return(ER_TOO_MANY_CONCURRENT_TRXS); -#else + /* New error code HA_ERR_TOO_MANY_CONCURRENT_TRXS is only + available in 5.1.38 and later, but the plugin should still + work with previous versions of MySQL. */ +#ifdef HA_ERR_TOO_MANY_CONCURRENT_TRXS + return(HA_ERR_TOO_MANY_CONCURRENT_TRXS); +#else /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */ return(HA_ERR_RECORD_FILE_FULL); -#endif +#endif /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */ case DB_UNSUPPORTED: return(HA_ERR_UNSUPPORTED); } @@ -949,7 +971,23 @@ innobase_get_cset_width( *mbminlen = cs->mbminlen; *mbmaxlen = cs->mbmaxlen; } else { - ut_a(cset == 0); + THD* thd = current_thd; + + if (thd && thd_sql_command(thd) == SQLCOM_DROP_TABLE) { + + /* Fix bug#46256: allow tables to be dropped if the + collation is not found, but issue a warning. */ + if ((global_system_variables.log_warnings) + && (cset != 0)){ + + sql_print_warning( + "Unknown collation #%lu.", cset); + } + } else { + + ut_a(cset == 0); + } + *mbminlen = *mbmaxlen = 0; } } @@ -2151,7 +2189,7 @@ innobase_change_buffering_inited_ok: /* --------------------------------------------------*/ - srv_file_flush_method_str = innobase_unix_file_flush_method; + srv_file_flush_method_str = innobase_file_flush_method; srv_n_log_groups = (ulint) innobase_mirrored_log_groups; srv_n_log_files = (ulint) innobase_log_files_in_group; @@ -2206,6 +2244,9 @@ innobase_change_buffering_inited_ok: ut_a(0 == strcmp(my_charset_latin1.name, "latin1_swedish_ci")); srv_latin1_ordering = my_charset_latin1.sort_order; + innobase_old_blocks_pct = buf_LRU_old_ratio_update( + innobase_old_blocks_pct, FALSE); + innobase_commit_concurrency_init_default(); /* Since we in this module access directly the fields of a trx @@ -2459,6 +2500,19 @@ retry: } } + /* The following calls to read the MySQL binary log + file name and the position return consistent results: + 1) Other InnoDB transactions cannot intervene between + these calls as we are holding prepare_commit_mutex. + 2) Binary logging of other engines is not relevant + to InnoDB as all InnoDB requires is that committing + InnoDB transactions appear in the same order in the + MySQL binary log as they appear in InnoDB logs. + 3) A MySQL log file rotation cannot happen because + MySQL protects against this by having a counter of + transactions in prepared state and it only allows + a rotation when the counter drops to zero. See + LOCK_prep_xids and COND_prep_xids in log.cc. */ trx->mysql_log_file_name = mysql_bin_log_file_name(); trx->mysql_log_offset = (ib_int64_t) mysql_bin_log_file_pos(); @@ -3105,7 +3159,7 @@ retry: if (is_part) { sql_print_error("Failed to open table %s after " - "%lu attemtps.\n", norm_name, + "%lu attempts.\n", norm_name, retries); } @@ -5006,6 +5060,11 @@ ha_innobase::index_read( index = prebuilt->index; + if (UNIV_UNLIKELY(index == NULL)) { + prebuilt->index_usable = FALSE; + DBUG_RETURN(HA_ERR_CRASHED); + } + /* Note that if the index for which the search template is built is not necessarily prebuilt->index, but can also be the clustered index */ @@ -5165,6 +5224,7 @@ ha_innobase::change_active_index( if (UNIV_UNLIKELY(!prebuilt->index)) { sql_print_warning("InnoDB: change_active_index(%u) failed", keynr); + prebuilt->index_usable = FALSE; DBUG_RETURN(1); } @@ -5657,6 +5717,28 @@ create_table_def( } } + /* First check whether the column to be added has a + system reserved name. */ + if (dict_col_name_is_reserved(field->field_name)){ + push_warning_printf( + (THD*) trx->mysql_thd, + MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_CANT_CREATE_TABLE, + "Error creating table '%s' with " + "column name '%s'. '%s' is a " + "reserved name. Please try to " + "re-create the table with a " + "different column name.", + table->name, (char*) field->field_name, + (char*) field->field_name); + + dict_mem_table_free(table); + trx_commit_for_mysql(trx); + + error = DB_ERROR; + goto error_ret; + } + dict_mem_table_add_col(table, table->heap, (char*) field->field_name, col_type, @@ -5670,6 +5752,7 @@ create_table_def( error = row_create_table_for_mysql(table, trx); +error_ret: error = convert_error_code_to_mysql(error, flags, NULL); DBUG_RETURN(error); @@ -5708,6 +5791,9 @@ create_index( n_fields = key->key_parts; + /* Assert that "GEN_CLUST_INDEX" cannot be used as non-primary index */ + ut_a(innobase_strcasecmp(key->name, innobase_index_reserve_name) != 0); + ind_type = 0; if (key_num == form->s->primary_key) { @@ -5816,8 +5902,8 @@ create_clustered_index_when_no_primary( /* We pass 0 as the space id, and determine at a lower level the space id where to store the table */ - - index = dict_mem_index_create(table_name, "GEN_CLUST_INDEX", + index = dict_mem_index_create(table_name, + innobase_index_reserve_name, 0, DICT_CLUSTERED, 0); error = row_create_index_for_mysql(index, trx, NULL); @@ -6243,14 +6329,6 @@ ha_innobase::create( flags = DICT_TF_COMPACT; } - error = create_table_def(trx, form, norm_name, - create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, - flags); - - if (error) { - goto cleanup; - } - /* Look for a primary key */ primary_key_no= (form->s->primary_key != MAX_KEY ? @@ -6262,6 +6340,22 @@ ha_innobase::create( ut_a(primary_key_no == -1 || primary_key_no == 0); + /* Check for name conflicts (with reserved name) for + any user indices to be created. */ + if (innobase_index_name_is_reserved(trx, form, norm_name)) { + error = -1; + goto cleanup; + } + + error = create_table_def(trx, form, norm_name, + create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, + flags); + + if (error) { + goto cleanup; + } + + /* Create the keys */ if (form->s->keys == 0 || primary_key_no == -1) { @@ -8446,6 +8540,7 @@ ha_innobase::store_lock( && isolation_level != TRX_ISO_SERIALIZABLE && (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT) && (sql_command == SQLCOM_INSERT_SELECT + || sql_command == SQLCOM_REPLACE_SELECT || sql_command == SQLCOM_UPDATE || sql_command == SQLCOM_CREATE_TABLE)) { @@ -8453,10 +8548,11 @@ ha_innobase::store_lock( option set or this session is using READ COMMITTED isolation level and isolation level of the transaction is not set to serializable and MySQL is doing - INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or - CREATE ... SELECT... without FOR UPDATE or - IN SHARE MODE in select, then we use consistent - read for select. */ + INSERT INTO...SELECT or REPLACE INTO...SELECT + or UPDATE ... = (SELECT ...) or CREATE ... + SELECT... without FOR UPDATE or IN SHARE + MODE in select, then we use consistent read + for select. */ prebuilt->select_lock_type = LOCK_NONE; prebuilt->stored_select_lock_type = LOCK_NONE; @@ -9612,6 +9708,25 @@ innodb_adaptive_hash_index_update( } } +/****************************************************************//** +Update the system variable innodb_old_blocks_pct using the "saved" +value. This function is registered as a callback with MySQL. */ +static +void +innodb_old_blocks_pct_update( +/*=========================*/ + THD* thd, /*!< in: thread handle */ + struct st_mysql_sys_var* var, /*!< in: pointer to + system variable */ + void* var_ptr,/*!< out: where the + formal string goes */ + const void* save) /*!< in: immediate result + from check function */ +{ + innobase_old_blocks_pct = buf_LRU_old_ratio_update( + *static_cast(save), TRUE); +} + /*************************************************************//** Check if it is a valid value of innodb_change_buffering. This function is registered as a callback with MySQL. @@ -9685,6 +9800,46 @@ static int show_innodb_vars(THD *thd, SHOW_VAR *var, char *buff) return 0; } +/*********************************************************************** +This function checks each index name for a table against reserved +system default primary index name 'GEN_CLUST_INDEX'. If a name matches, +this function pushes an error message to the client, and returns true. */ +static +bool +innobase_index_name_is_reserved( +/*============================*/ + /* out: true if an index name + matches the reserved name */ + const trx_t* trx, /* in: InnoDB transaction handle */ + const TABLE* form, /* in: information on table + columns and indexes */ + const char* norm_name) /* in: table name */ +{ + KEY* key; + uint key_num; /* index number */ + + for (key_num = 0; key_num < form->s->keys; key_num++) { + key = form->key_info + key_num; + + if (innobase_strcasecmp(key->name, + innobase_index_reserve_name) == 0) { + /* Push warning to mysql */ + push_warning_printf((THD*) trx->mysql_thd, + MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_CANT_CREATE_TABLE, + "Cannot Create Index with name " + "'%s'. The name is reserved " + "for the system default primary " + "index.", + innobase_index_reserve_name); + + return(true); + } + } + + return(false); +} + static SHOW_VAR innodb_status_variables_export[]= { {"Innodb", (char*) &show_innodb_vars, SHOW_FUNC}, {NullS, NullS, SHOW_LONG} @@ -9753,7 +9908,7 @@ static MYSQL_SYSVAR_ULONG(flush_log_at_trx_commit, srv_flush_log_at_trx_commit, " or 2 (write at commit, flush once per second).", NULL, NULL, 1, 0, 2, 0); -static MYSQL_SYSVAR_STR(flush_method, innobase_unix_file_flush_method, +static MYSQL_SYSVAR_STR(flush_method, innobase_file_flush_method, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "With which method to flush data.", NULL, NULL, NULL); @@ -9849,7 +10004,7 @@ static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, NULL, NULL, 500L, 1L, ~0L, 0); static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads, - PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR, "Number of file I/O threads in InnoDB.", NULL, NULL, 4, 4, 64, 0); @@ -9888,6 +10043,18 @@ static MYSQL_SYSVAR_LONG(mirrored_log_groups, innobase_mirrored_log_groups, "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.", NULL, NULL, 1, 1, 10, 0); +static MYSQL_SYSVAR_UINT(old_blocks_pct, innobase_old_blocks_pct, + PLUGIN_VAR_RQCMDARG, + "Percentage of the buffer pool to reserve for 'old' blocks.", + NULL, innodb_old_blocks_pct_update, 100 * 3 / 8, 5, 95, 0); + +static MYSQL_SYSVAR_UINT(old_blocks_time, buf_LRU_old_threshold_ms, + PLUGIN_VAR_RQCMDARG, + "Move blocks to the 'new' end of the buffer pool if the first access" + " was at least this many milliseconds ago." + " The timeout is disabled if 0 (the default).", + NULL, NULL, 0, 0, UINT_MAX32, 0); + static MYSQL_SYSVAR_LONG(open_files, innobase_open_files, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "How many files at the maximum InnoDB keeps open at the same time.", @@ -9986,6 +10153,8 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(adaptive_flushing), MYSQL_SYSVAR(max_purge_lag), MYSQL_SYSVAR(mirrored_log_groups), + MYSQL_SYSVAR(old_blocks_pct), + MYSQL_SYSVAR(old_blocks_time), MYSQL_SYSVAR(open_files), MYSQL_SYSVAR(rollback_on_timeout), MYSQL_SYSVAR(stats_on_metadata), diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 5075b841879..1aa0e6b126c 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -663,7 +663,7 @@ ha_innobase::add_index( if (UNIV_UNLIKELY(error)) { err_exit: mem_heap_free(heap); - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx_free_for_mysql(trx); trx_commit_for_mysql(prebuilt->trx); DBUG_RETURN(error); @@ -801,7 +801,7 @@ error_handling: alter table t drop index b, add index (b); The fix will have to parse the SQL and note that the index - being added has the same name as the the one being dropped and + being added has the same name as the one being dropped and ignore that in the dup index check.*/ //dict_table_check_for_dup_indexes(prebuilt->table); #endif diff --git a/storage/innobase/handler/handler0vars.h b/storage/innobase/handler/handler0vars.h deleted file mode 100644 index e0f8f75e34d..00000000000 --- a/storage/innobase/handler/handler0vars.h +++ /dev/null @@ -1,69 +0,0 @@ -/***************************************************************************** - -Copyright (c) 2008, 2009, Innobase Oy. 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 -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA - -*****************************************************************************/ - -/*******************************************************************//** -@file handler/handler0vars.h -This file contains accessor functions for dynamic plugin on Windows. -***********************************************************************/ - -#if defined __WIN__ && defined MYSQL_DYNAMIC_PLUGIN -/*******************************************************************//** -This is a list of externals that can not be resolved by delay loading. -They have to be resolved indirectly via their addresses in the .map file. -All of them are external variables. */ -extern CHARSET_INFO* wdl_my_charset_bin; -extern CHARSET_INFO* wdl_my_charset_latin1; -extern CHARSET_INFO* wdl_my_charset_filename; -extern CHARSET_INFO** wdl_system_charset_info; -extern CHARSET_INFO** wdl_default_charset_info; -extern CHARSET_INFO** wdl_all_charsets; -extern system_variables* wdl_global_system_variables; -extern char* wdl_mysql_real_data_home; -extern char** wdl_mysql_data_home; -extern char** wdl_tx_isolation_names; -extern char** wdl_binlog_format_names; -extern char* wdl_reg_ext; -extern pthread_mutex_t* wdl_LOCK_thread_count; -extern key_map* wdl_key_map_full; -extern MY_TMPDIR* wdl_mysql_tmpdir_list; -extern bool* wdl_mysqld_embedded; -extern uint* wdl_lower_case_table_names; -extern ulong* wdl_specialflag; -extern int* wdl_my_umask; - -#define my_charset_bin (*wdl_my_charset_bin) -#define my_charset_latin1 (*wdl_my_charset_latin1) -#define my_charset_filename (*wdl_my_charset_filename) -#define system_charset_info (*wdl_system_charset_info) -#define default_charset_info (*wdl_default_charset_info) -#define all_charsets (wdl_all_charsets) -#define global_system_variables (*wdl_global_system_variables) -#define mysql_real_data_home (wdl_mysql_real_data_home) -#define mysql_data_home (*wdl_mysql_data_home) -#define tx_isolation_names (wdl_tx_isolation_names) -#define binlog_format_names (wdl_binlog_format_names) -#define reg_ext (wdl_reg_ext) -#define LOCK_thread_count (*wdl_LOCK_thread_count) -#define key_map_full (*wdl_key_map_full) -#define mysql_tmpdir_list (*wdl_mysql_tmpdir_list) -#define mysqld_embedded (*wdl_mysqld_embedded) -#define lower_case_table_names (*wdl_lower_case_table_names) -#define specialflag (*wdl_specialflag) -#define my_umask (*wdl_my_umask) - -#endif diff --git a/storage/innobase/handler/win_delay_loader.cc b/storage/innobase/handler/win_delay_loader.cc deleted file mode 100644 index 9b92f6a9cf2..00000000000 --- a/storage/innobase/handler/win_delay_loader.cc +++ /dev/null @@ -1,1024 +0,0 @@ -/***************************************************************************** - -Copyright (c) 2008, 2009, Innobase Oy. 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 -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA - -*****************************************************************************/ - -/*******************************************************************//** -@file handler/win_delay_loader.cc -This file contains functions that implement the delay loader on Windows. - -This is a customized version of delay loader with limited functionalities. -It does not support: - -* (manual) unloading -* multiple delay loaded DLLs -* multiple loading of the same DLL - -This delay loader is used only by the InnoDB plugin. Other components (DLLs) -can still use the default delay loader, provided by MSVC. - -Several acronyms used by Microsoft: - * IAT: import address table - * INT: import name table - * RVA: Relative Virtual Address - -See http://msdn.microsoft.com/en-us/magazine/bb985992.aspx for details of -PE format. -***********************************************************************/ -#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) -# define WIN32_LEAN_AND_MEAN -# include -# include -# include - -extern "C" { -# include "univ.i" -# include "hash0hash.h" -} - -/*******************************************************************//** -This following contains a list of externals that can not be resolved by -delay loading. They have to be resolved indirectly via their addresses -in the .map file. All of them are external variables. */ -CHARSET_INFO* wdl_my_charset_bin; -CHARSET_INFO* wdl_my_charset_latin1; -CHARSET_INFO* wdl_my_charset_filename; -CHARSET_INFO** wdl_system_charset_info; -CHARSET_INFO** wdl_default_charset_info; -CHARSET_INFO** wdl_all_charsets; -system_variables* wdl_global_system_variables; -char* wdl_mysql_real_data_home; -char** wdl_mysql_data_home; -char** wdl_tx_isolation_names; -char** wdl_binlog_format_names; -char* wdl_reg_ext; -pthread_mutex_t* wdl_LOCK_thread_count; -key_map* wdl_key_map_full; -MY_TMPDIR* wdl_mysql_tmpdir_list; -bool* wdl_mysqld_embedded; -uint* wdl_lower_case_table_names; -ulong* wdl_specialflag; -int* wdl_my_umask; - -/*******************************************************************//** -The preferred load-address defined in PE (portable executable format). */ -#if defined(_M_IA64) -#pragma section(".base", long, read) -extern "C" -__declspec(allocate(".base")) -const IMAGE_DOS_HEADER __ImageBase; -#else -extern "C" -const IMAGE_DOS_HEADER __ImageBase; -#endif - -/*******************************************************************//** -A template function for converting a relative address (RVA) to an -absolute address (VA). This is due to the pointers in the delay -descriptor (ImgDelayDescr in delayimp.h) have been changed from -VAs to RVAs to work on both 32- and 64-bit platforms. -@return absolute virtual address */ -template -X PFromRva( -/*=======*/ - RVA rva) /*!< in: relative virtual address */ -{ - return X(PBYTE(&__ImageBase) + rva); -} - -/*******************************************************************//** -Convert to the old format for convenience. The structure as well as its -element names follow the definition of ImgDelayDescr in delayimp.h. */ -struct InternalImgDelayDescr -{ - DWORD grAttrs; /*!< attributes */ - LPCSTR szName; /*!< pointer to dll name */ - HMODULE* phmod; /*!< address of module handle */ - PImgThunkData pIAT; /*!< address of the IAT */ - PCImgThunkData pINT; /*!< address of the INT */ - PCImgThunkData pBoundIAT; /*!< address of the optional bound IAT */ - PCImgThunkData pUnloadIAT; /*!< address of optional copy of - original IAT */ - DWORD dwTimeStamp; /*!< 0 if not bound, - otherwise date/time stamp of DLL - bound to (Old BIND) */ -}; - -typedef struct map_hash_chain_struct map_hash_chain_t; - -struct map_hash_chain_struct { - char* symbol; /*!< pointer to a symbol */ - ulint value; /*!< address of the symbol */ - map_hash_chain_t* next; /*!< pointer to the next cell - in the same folder. */ - map_hash_chain_t* chain; /*!< a linear chain used for - cleanup. */ -}; - -static HMODULE my_hmod = 0; -static struct hash_table_struct* m_htbl = NULL ; -static map_hash_chain_t* chain_header = NULL; -static ibool wdl_init = FALSE; -const ulint MAP_HASH_CELLS_NUM = 10000; - -#ifndef DBUG_OFF -/*******************************************************************//** -In the dynamic plugin, it is required to call the following dbug functions -in the server: - _db_pargs_ - _db_doprnt_ - _db_enter_ - _db_return_ - _db_dump_ - -The plugin will get those function pointers during the initialization. */ -typedef void (__cdecl* pfn_db_enter_)( - const char* _func_, - const char* _file_, - uint _line_, - const char** _sfunc_, - const char** _sfile_, - uint* _slevel_, - char***); - -typedef void (__cdecl* pfn_db_return_)( - uint _line_, - const char** _sfunc_, - const char** _sfile_, - uint* _slevel_); - -typedef void (__cdecl* pfn_db_pargs_)( - uint _line_, - const char* keyword); - -typedef void (__cdecl* pfn_db_doprnt_)( - const char* format, - ...); - -typedef void (__cdecl* pfn_db_dump_)( - uint _line_, - const char* keyword, - const unsigned char* memory, - size_t length); - -static pfn_db_enter_ wdl_db_enter_; -static pfn_db_return_ wdl_db_return_; -static pfn_db_pargs_ wdl_db_pargs_; -static pfn_db_doprnt_ wdl_db_doprnt_; -static pfn_db_dump_ wdl_db_dump_; -#endif /* !DBUG_OFF */ - -/*************************************************************//** -Creates a hash table with >= n array cells. The actual number of cells is -chosen to be a prime number slightly bigger than n. - -This is the same function as hash_create in hash0hash.c, except the -memory allocation. This function is invoked before the engine is -initialized, and buffer pools are not ready yet. -@return own: created hash table */ -static -hash_table_t* -wdl_hash_create( -/*============*/ - ulint n) /*!< in: number of array cells */ -{ - hash_cell_t* array; - ulint prime; - hash_table_t* table; - - prime = ut_find_prime(n); - - table = (hash_table_t*) malloc(sizeof(hash_table_t)); - if (table == NULL) { - return(NULL); - } - - array = (hash_cell_t*) malloc(sizeof(hash_cell_t) * prime); - if (array == NULL) { - free(table); - return(NULL); - } - - table->array = array; - table->n_cells = prime; - table->n_mutexes = 0; - table->mutexes = NULL; - table->heaps = NULL; - table->heap = NULL; - table->magic_n = HASH_TABLE_MAGIC_N; - - /* Initialize the cell array */ - hash_table_clear(table); - - return(table); -} - -/*************************************************************//** -Frees a hash table. */ -static -void -wdl_hash_table_free( -/*================*/ - hash_table_t* table) /*!< in, own: hash table */ -{ - ut_a(table != NULL); - ut_a(table->mutexes == NULL); - - free(table->array); - free(table); -} - -/*******************************************************************//** -Function for calculating the count of imports given the base of the IAT. -@return number of imports */ -static -ulint -wdl_import_count( -/*=============*/ - PCImgThunkData pitd_base) /*!< in: base of the IAT */ -{ - ulint ret = 0; - PCImgThunkData pitd = pitd_base; - - while (pitd->u1.Function) { - pitd++; - ret++; - } - - return(ret); -} - -/*******************************************************************//** -Read Mapfile to a hashtable for faster access -@return TRUE if the mapfile is loaded successfully. */ -static -ibool -wdl_load_mapfile( -/*=============*/ - const char* filename) /*!< in: name of the mapfile. */ -{ - FILE* fp; - const size_t nSize = 256; - char tmp_buf[nSize]; - char* func_name; - char* func_addr; - ulint load_addr = 0; - ibool valid_load_addr = FALSE; -#ifdef _WIN64 - const char* tmp_string = " Preferred load address is %16llx"; -#else - const char* tmp_string = " Preferred load address is %08x"; -#endif - - fp = fopen(filename, "r"); - if (fp == NULL) { - - return(FALSE); - } - - /* Check whether to create the hashtable */ - if (m_htbl == NULL) { - - m_htbl = wdl_hash_create(MAP_HASH_CELLS_NUM); - - if (m_htbl == NULL) { - - fclose(fp); - return(FALSE); - } - } - - /* Search start of symbol list and get the preferred load address */ - while (fgets(tmp_buf, sizeof(tmp_buf), fp)) { - - if (sscanf(tmp_buf, tmp_string, &load_addr) == 1) { - - valid_load_addr = TRUE; - } - - if (strstr(tmp_buf, "Rva+Base") != NULL) { - - break; - } - } - - if (valid_load_addr == FALSE) { - - /* No "Preferred load address", the map file is wrong. */ - fclose(fp); - return(FALSE); - } - - /* Read symbol list */ - while (fgets(tmp_buf, sizeof(tmp_buf), fp)) - { - map_hash_chain_t* map_cell; - ulint map_fold; - - if (*tmp_buf == 0) { - - continue; - } - - func_name = strtok(tmp_buf, " "); - func_name = strtok(NULL, " "); - func_addr = strtok(NULL, " "); - - if (func_name && func_addr) { - - ut_snprintf(tmp_buf, nSize, "0x%s", func_addr); - if (*func_name == '_') { - - func_name++; - } - - map_cell = (map_hash_chain_t*) - malloc(sizeof(map_hash_chain_t)); - if (map_cell == NULL) { - return(FALSE); - } - - /* Chain all cells together */ - map_cell->chain = chain_header; - chain_header = map_cell; - - map_cell->symbol = strdup(func_name); - map_cell->value = (ulint) _strtoui64(tmp_buf, NULL, 0) - - load_addr; - map_fold = ut_fold_string(map_cell->symbol); - - HASH_INSERT(map_hash_chain_t, - next, - m_htbl, - map_fold, - map_cell); - } - } - - fclose(fp); - - return(TRUE); -} - -/*************************************************************//** -Cleanup.during DLL unload */ -static -void -wdl_cleanup(void) -/*=============*/ -{ - while (chain_header != NULL) { - map_hash_chain_t* tmp; - - tmp = chain_header->chain; - free(chain_header->symbol); - free(chain_header); - chain_header = tmp; - } - - if (m_htbl != NULL) { - - wdl_hash_table_free(m_htbl); - } -} - -/*******************************************************************//** -Load the mapfile mysqld.map. -@return the module handle */ -static -HMODULE -wdl_get_mysqld_mapfile(void) -/*========================*/ -{ - char file_name[MAX_PATH]; - char* ext; - ulint err; - - if (my_hmod == 0) { - - size_t nSize = MAX_PATH - strlen(".map") -1; - - /* First find out the name of current executable */ - my_hmod = GetModuleHandle(NULL); - if (my_hmod == 0) { - - return(my_hmod); - } - - err = GetModuleFileName(my_hmod, file_name, nSize); - if (err == 0) { - - my_hmod = 0; - return(my_hmod); - } - - ext = strrchr(file_name, '.'); - if (ext != NULL) { - - *ext = 0; - strcat(file_name, ".map"); - - err = wdl_load_mapfile(file_name); - if (err == 0) { - - my_hmod = 0; - } - } else { - - my_hmod = 0; - } - } - - return(my_hmod); -} - -/*******************************************************************//** -Retrieves the address of an exported function. It follows the convention -of GetProcAddress(). -@return address of exported function. */ -static -FARPROC -wdl_get_procaddr_from_map( -/*======================*/ - HANDLE m_handle, /*!< in: module handle */ - const char* import_proc) /*!< in: procedure name */ -{ - map_hash_chain_t* hash_chain; - ulint map_fold; - - map_fold = ut_fold_string(import_proc); - HASH_SEARCH( - next, - m_htbl, - map_fold, - map_hash_chain_t*, - hash_chain, - , - (ut_strcmp(hash_chain->symbol, import_proc) == 0)); - - if (hash_chain == NULL) { - -#ifdef _WIN64 - /* On Win64, the leading '_' may not be taken out. In this - case, search again without the leading '_'. */ - if (*import_proc == '_') { - - import_proc++; - } - - map_fold = ut_fold_string(import_proc); - HASH_SEARCH( - next, - m_htbl, - map_fold, - map_hash_chain_t*, - hash_chain, - , - (ut_strcmp(hash_chain->symbol, import_proc) == 0)); - - if (hash_chain == NULL) { -#endif - if (wdl_init == TRUE) { - - sql_print_error( - "InnoDB: the procedure pointer of %s" - " is not found.", - import_proc); - } - - return(0); -#ifdef _WIN64 - } -#endif - } - - return((FARPROC) ((ulint) m_handle + hash_chain->value)); -} - -/*******************************************************************//** -Retrieves the address of an exported variable. -Note: It does not follow the Windows call convention FARPROC. -@return address of exported variable. */ -static -void* -wdl_get_varaddr_from_map( -/*=====================*/ - HANDLE m_handle, /*!< in: module handle */ - const char* import_variable) /*!< in: variable name */ -{ - map_hash_chain_t* hash_chain; - ulint map_fold; - - map_fold = ut_fold_string(import_variable); - HASH_SEARCH( - next, - m_htbl, - map_fold, - map_hash_chain_t*, - hash_chain, - , - (ut_strcmp(hash_chain->symbol, import_variable) == 0)); - - if (hash_chain == NULL) { - -#ifdef _WIN64 - /* On Win64, the leading '_' may not be taken out. In this - case, search again without the leading '_'. */ - if (*import_variable == '_') { - - import_variable++; - } - - map_fold = ut_fold_string(import_variable); - HASH_SEARCH( - next, - m_htbl, - map_fold, - map_hash_chain_t*, - hash_chain, - , - (ut_strcmp(hash_chain->symbol, import_variable) == 0)); - - if (hash_chain == NULL) { -#endif - if (wdl_init == TRUE) { - - sql_print_error( - "InnoDB: the variable address of %s" - " is not found.", - import_variable); - } - - return(0); -#ifdef _WIN64 - } -#endif - } - - return((void*) ((ulint) m_handle + hash_chain->value)); -} - -/*******************************************************************//** -Bind all unresolved external variables from the MySQL executable. -@return TRUE if successful */ -static -bool -wdl_get_external_variables(void) -/*============================*/ -{ - HMODULE hmod = wdl_get_mysqld_mapfile(); - - if (hmod == 0) { - - return(FALSE); - } - -#define GET_SYM(sym, var, type) \ - var = (type*) wdl_get_varaddr_from_map(hmod, sym); \ - if (var == NULL) return(FALSE) -#ifdef _WIN64 -#define GET_SYM2(sym1, sym2, var, type) \ - var = (type*) wdl_get_varaddr_from_map(hmod, sym1); \ - if (var == NULL) return(FALSE) -#else -#define GET_SYM2(sym1, sym2, var, type) \ - var = (type*) wdl_get_varaddr_from_map(hmod, sym2); \ - if (var == NULL) return(FALSE) -#endif // (_WIN64) -#define GET_C_SYM(sym, type) GET_SYM(#sym, wdl_##sym, type) -#define GET_PROC_ADDR(sym) \ - wdl##sym = (pfn##sym) wdl_get_procaddr_from_map(hmod, #sym) - - GET_C_SYM(my_charset_bin, CHARSET_INFO); - GET_C_SYM(my_charset_latin1, CHARSET_INFO); - GET_C_SYM(my_charset_filename, CHARSET_INFO); - GET_C_SYM(default_charset_info, CHARSET_INFO*); - GET_C_SYM(all_charsets, CHARSET_INFO*); - GET_C_SYM(my_umask, int); - - GET_SYM("?global_system_variables@@3Usystem_variables@@A", - wdl_global_system_variables, struct system_variables); - GET_SYM("?mysql_real_data_home@@3PADA", - wdl_mysql_real_data_home, char); - GET_SYM("?reg_ext@@3PADA", wdl_reg_ext, char); - GET_SYM("?LOCK_thread_count@@3U_RTL_CRITICAL_SECTION@@A", - wdl_LOCK_thread_count, pthread_mutex_t); - GET_SYM("?key_map_full@@3V?$Bitmap@$0EA@@@A", - wdl_key_map_full, key_map); - GET_SYM("?mysql_tmpdir_list@@3Ust_my_tmpdir@@A", - wdl_mysql_tmpdir_list, MY_TMPDIR); - GET_SYM("?mysqld_embedded@@3_NA", - wdl_mysqld_embedded, bool); - GET_SYM("?lower_case_table_names@@3IA", - wdl_lower_case_table_names, uint); - GET_SYM("?specialflag@@3KA", wdl_specialflag, ulong); - - GET_SYM2("?system_charset_info@@3PEAUcharset_info_st@@EA", - "?system_charset_info@@3PAUcharset_info_st@@A", - wdl_system_charset_info, CHARSET_INFO*); - GET_SYM2("?mysql_data_home@@3PEADEA", - "?mysql_data_home@@3PADA", - wdl_mysql_data_home, char*); - GET_SYM2("?tx_isolation_names@@3PAPEBDA", - "?tx_isolation_names@@3PAPBDA", - wdl_tx_isolation_names, char*); - GET_SYM2("?binlog_format_names@@3PAPEBDA", - "?binlog_format_names@@3PAPBDA", - wdl_binlog_format_names, char*); - -#ifndef DBUG_OFF - GET_PROC_ADDR(_db_enter_); - GET_PROC_ADDR(_db_return_); - GET_PROC_ADDR(_db_pargs_); - GET_PROC_ADDR(_db_doprnt_); - GET_PROC_ADDR(_db_dump_); - - /* If any of the dbug functions is not available, just make them - all invalid. This is the case when working with a non-debug - version of the server. */ - if (wdl_db_enter_ == NULL || wdl_db_return_ == NULL - || wdl_db_pargs_ == NULL || wdl_db_doprnt_ == NULL - || wdl_db_dump_ == NULL) { - - wdl_db_enter_ = NULL; - wdl_db_return_ = NULL; - wdl_db_pargs_ = NULL; - wdl_db_doprnt_ = NULL; - wdl_db_dump_ = NULL; - } -#endif /* !DBUG_OFF */ - - wdl_init = TRUE; - return(TRUE); - -#undef GET_SYM -#undef GET_SYM2 -#undef GET_C_SYM -#undef GET_PROC_ADDR -} - -/*******************************************************************//** -The DLL Delayed Loading Helper Function for resolving externals. - -The function may fail due to one of the three reasons: - -* Invalid parameter, which happens if the attributes in pidd aren't - specified correctly. -* Failed to load the map file mysqld.map. -* Failed to find an external name in the map file mysqld.map. - -Note: this function is called by run-time as well as __HrLoadAllImportsForDll. -So, it has to follow Windows call convention. -@return the address of the imported function */ -extern "C" -FARPROC WINAPI -__delayLoadHelper2( -/*===============*/ - PCImgDelayDescr pidd, /*!< in: a const pointer to a - ImgDelayDescr, see delayimp.h. */ - FARPROC* iat_entry) /*!< in/out: A pointer to the slot in - the delay load import address table - to be updated with the address of the - imported function. */ -{ - ulint iIAT, iINT; - HMODULE hmod; - PCImgThunkData pitd; - FARPROC fun = NULL; - - /* Set up data used for the hook procs */ - InternalImgDelayDescr idd = { - pidd->grAttrs, - PFromRva(pidd->rvaDLLName), - PFromRva(pidd->rvaHmod), - PFromRva(pidd->rvaIAT), - PFromRva(pidd->rvaINT), - PFromRva(pidd->rvaBoundIAT), - PFromRva(pidd->rvaUnloadIAT), - pidd->dwTimeStamp - }; - - DelayLoadInfo dli = { - sizeof(DelayLoadInfo), - pidd, - iat_entry, - idd.szName, - {0}, - 0, - 0, - 0 - }; - - /* Check the Delay Load Attributes, log an error of invalid - parameter, which happens if the attributes in pidd are not - specified correctly. */ - if ((idd.grAttrs & dlattrRva) == 0) { - - sql_print_error("InnoDB: invalid parameter for delay loader."); - return(0); - } - - hmod = *idd.phmod; - - /* Calculate the index for the IAT entry in the import address table. - The INT entries are ordered the same as the IAT entries so the - calculation can be done on the IAT side. */ - iIAT = (PCImgThunkData) iat_entry - idd.pIAT; - iINT = iIAT; - - pitd = &(idd.pINT[iINT]); - - dli.dlp.fImportByName = !IMAGE_SNAP_BY_ORDINAL(pitd->u1.Ordinal); - - if (dli.dlp.fImportByName) { - - dli.dlp.szProcName = (LPCSTR) (PFromRva - ((RVA) ((UINT_PTR) pitd->u1.AddressOfData))->Name); - } else { - - dli.dlp.dwOrdinal = (ulint) IMAGE_ORDINAL(pitd->u1.Ordinal); - } - - /* Now, load the mapfile, if it has not been done yet */ - if (hmod == 0) { - - hmod = wdl_get_mysqld_mapfile(); - } - - if (hmod == 0) { - /* LoadLibrary failed. */ - PDelayLoadInfo rgpdli[1] = {&dli}; - - dli.dwLastError = ::GetLastError(); - - sql_print_error( - "InnoDB: failed to load mysqld.map with error %d.", - dli.dwLastError); - - return(0); - } - - /* Store the library handle. */ - idd.phmod = &hmod; - - /* Go for the procedure now. */ - dli.hmodCur = hmod; - - if (pidd->rvaBoundIAT && pidd->dwTimeStamp) { - - /* Bound imports exist, check the timestamp from the target - image */ - PIMAGE_NT_HEADERS pinh; - - pinh = (PIMAGE_NT_HEADERS) ((byte*) hmod - + ((PIMAGE_DOS_HEADER) hmod)->e_lfanew); - - if (pinh->Signature == IMAGE_NT_SIGNATURE - && pinh->FileHeader.TimeDateStamp == idd.dwTimeStamp - && (DWORD) hmod == pinh->OptionalHeader.ImageBase) { - - /* We have a decent address in the bound IAT. */ - fun = (FARPROC) (UINT_PTR) - idd.pBoundIAT[iIAT].u1.Function; - - if (fun) { - - *iat_entry = fun; - return(fun); - } - } - } - - fun = wdl_get_procaddr_from_map(hmod, dli.dlp.szProcName); - - if (fun == 0) { - - return(0); - } - - *iat_entry = fun; - return(fun); -} - -/*******************************************************************//** -Unload a DLL that was delay loaded. This function is called by run-time. -@return TRUE is returned if the DLL is found and the IAT matches the -original one. */ -extern "C" -BOOL WINAPI -__FUnloadDelayLoadedDLL2( -/*=====================*/ - LPCSTR module_name) /*!< in: DLL name */ -{ - return(TRUE); -} - -/**************************************************************//** -Load all imports from a DLL that was specified with the /delayload linker -option. -Note: this function is called by run-time. So, it has to follow Windows call -convention. -@return S_OK if the DLL matches, otherwise ERROR_MOD_NOT_FOUND is returned. */ -extern "C" -HRESULT WINAPI -__HrLoadAllImportsForDll( -/*=====================*/ - LPCSTR module_name) /*!< in: DLL name */ -{ - PIMAGE_NT_HEADERS img; - PCImgDelayDescr pidd; - IMAGE_DATA_DIRECTORY* image_data; - LPCSTR current_module; - HRESULT ret = ERROR_MOD_NOT_FOUND; - HMODULE hmod = (HMODULE) &__ImageBase; - - img = (PIMAGE_NT_HEADERS) ((byte*) hmod - + ((PIMAGE_DOS_HEADER) hmod)->e_lfanew); - image_data = - &img->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT]; - - /* Scan the delay load IAT/INT for the DLL */ - if (image_data->Size) { - - pidd = PFromRva(image_data->VirtualAddress); - - /* Check all of the listed DLLs we want to load. */ - while (pidd->rvaDLLName) { - - current_module = PFromRva(pidd->rvaDLLName); - - if (stricmp(module_name, current_module) == 0) { - - /* Found it, break out with pidd and - current_module set appropriately */ - break; - } - - /* To the next delay import descriptor */ - pidd++; - } - - if (pidd->rvaDLLName) { - - /* Found a matching DLL, now process it. */ - FARPROC* iat_entry; - size_t count; - - iat_entry = PFromRva(pidd->rvaIAT); - count = wdl_import_count((PCImgThunkData) iat_entry); - - /* now load all the imports from the DLL */ - while (count > 0) { - - /* No need to check the return value */ - __delayLoadHelper2(pidd, iat_entry); - iat_entry++; - count--; - } - - ret = S_OK; - } - } - - return ret; -} - -/**************************************************************//** -The main function of a DLL -@return TRUE if the call succeeds */ -BOOL -WINAPI -DllMain( -/*====*/ - HINSTANCE hinstDLL, /*!< in: handle to the DLL module */ - DWORD fdwReason, /*!< Reason code that indicates why the - DLL entry-point function is being - called.*/ - LPVOID lpvReserved) /*!< in: additional parameter based on - fdwReason */ -{ - BOOL success = TRUE; - - switch (fdwReason) { - - case DLL_PROCESS_ATTACH: - success = wdl_get_external_variables(); - break; - - case DLL_PROCESS_DETACH: - wdl_cleanup(); - break; - } - - return(success); -} - -#ifndef DBUG_OFF -/**************************************************************//** -Process entry point to user function. It makes the call to _db_enter_ -in mysqld.exe. The DBUG functions are defined in my_dbug.h. */ -extern "C" UNIV_INTERN -void -_db_enter_( - const char* _func_, /*!< in: current function name */ - const char* _file_, /*!< in: current file name */ - uint _line_, /*!< in: current source line number */ - const char** _sfunc_, /*!< out: previous _func_ */ - const char** _sfile_, /*!< out: previous _file_ */ - uint* _slevel_, /*!< out: previous nesting level */ - char*** _sframep_) /*!< out: previous frame pointer */ -{ - if (wdl_db_enter_ != NULL) { - - wdl_db_enter_(_func_, _file_, _line_, _sfunc_, _sfile_, - _slevel_, _sframep_); - } -} - -/**************************************************************//** -Process exit from user function. It makes the call to _db_return_() -in the server. */ -extern "C" UNIV_INTERN -void -_db_return_( - uint _line_, /*!< in: current source line number */ - const char** _sfunc_, /*!< out: previous _func_ */ - const char** _sfile_, /*!< out: previous _file_ */ - uint* _slevel_) /*!< out: previous level */ -{ - if (wdl_db_return_ != NULL) { - - wdl_db_return_(_line_, _sfunc_, _sfile_, _slevel_); - } -} - -/**************************************************************//** -Log arguments for subsequent use. It makes the call to _db_pargs_() -in the server. */ -extern "C" UNIV_INTERN -void -_db_pargs_( - uint _line_, /*!< in: current source line number */ - const char* keyword) /*!< in: keyword for current macro */ -{ - if (wdl_db_pargs_ != NULL) { - - wdl_db_pargs_(_line_, keyword); - } -} - -/**************************************************************//** -Handle print of debug lines. It saves the text into a buffer first, -then makes the call to _db_doprnt_() in the server. The text is -truncated to the size of buffer. */ -extern "C" UNIV_INTERN -void -_db_doprnt_( - const char* format, /*!< in: the format string */ - ...) /*!< in: list of arguments */ -{ - va_list argp; - char buffer[512]; - - if (wdl_db_doprnt_ != NULL) { - - va_start(argp, format); - /* it is ok to ignore the trunction. */ - _vsnprintf(buffer, sizeof(buffer), format, argp); - wdl_db_doprnt_(buffer); - va_end(argp); - } -} - -/**************************************************************//** -Dump a string in hex. It makes the call to _db_dump_() in the server. */ -extern "C" UNIV_INTERN -void -_db_dump_( - uint _line_, /*!< in: current source line - number */ - const char* keyword, /*!< in: keyword list */ - const unsigned char* memory, /*!< in: memory to dump */ - size_t length) /*!< in: bytes to dump */ -{ - if (wdl_db_dump_ != NULL) { - - wdl_db_dump_(_line_, keyword, memory, length); - } -} - -#endif /* !DBUG_OFF */ -#endif /* defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) */ diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 65ad42c895a..e9d95a14f1b 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -346,7 +346,7 @@ buf_page_release( mtr_t* mtr); /*!< in: mtr */ /********************************************************************//** Moves a page to the start of the buffer pool LRU list. This high-level -function can be used to prevent an important page from from slipping out of +function can be used to prevent an important page from slipping out of the buffer pool. */ UNIV_INTERN void @@ -707,15 +707,6 @@ buf_page_belongs_to_unzip_LRU( /*==========================*/ const buf_page_t* bpage) /*!< in: pointer to control block */ __attribute__((pure)); -/*********************************************************************//** -Determine the approximate LRU list position of a block. -@return LRU list position */ -UNIV_INLINE -ulint -buf_page_get_LRU_position( -/*======================*/ - const buf_page_t* bpage) /*!< in: control block */ - __attribute__((pure)); /*********************************************************************//** Gets the mutex of a block. @@ -816,14 +807,14 @@ buf_page_set_old( buf_page_t* bpage, /*!< in/out: control block */ ibool old); /*!< in: old */ /*********************************************************************//** -Determine if a block has been accessed in the buffer pool. -@return TRUE if accessed */ +Determine the time of first access of a block in the buffer pool. +@return ut_time_ms() at the time of first access, 0 if not accessed */ UNIV_INLINE -ibool +unsigned buf_page_is_accessed( /*=================*/ const buf_page_t* bpage) /*!< in: control block */ - __attribute__((pure)); + __attribute__((nonnull, pure)); /*********************************************************************//** Flag a block accessed. */ UNIV_INLINE @@ -831,7 +822,8 @@ void buf_page_set_accessed( /*==================*/ buf_page_t* bpage, /*!< in/out: control block */ - ibool accessed); /*!< in: accessed */ + ulint time_ms) /*!< in: ut_time_ms() */ + __attribute__((nonnull)); /*********************************************************************//** Gets the buf_block_t handle of a buffered file block if an uncompressed page frame exists, or NULL. @@ -1017,14 +1009,6 @@ buf_block_hash_get( /*===============*/ ulint space, /*!< in: space id */ ulint offset);/*!< in: offset of the page within space */ -/*******************************************************************//** -Increments the pool clock by one and returns its new value. Remember that -in the 32 bit version the clock wraps around at 4 billion! -@return new clock value */ -UNIV_INLINE -ulint -buf_pool_clock_tic(void); -/*====================*/ /*********************************************************************//** Gets the current length of the free list of buffer blocks. @return length of the free list */ @@ -1064,16 +1048,10 @@ struct buf_page_struct{ flushed to disk, this tells the flush_type. @see enum buf_flush */ - unsigned accessed:1; /*!< TRUE if the page has been accessed - while in the buffer pool: read-ahead - may read in pages which have not been - accessed yet; a thread is allowed to - read this for heuristic purposes - without holding any mutex or latch */ unsigned io_fix:2; /*!< type of pending I/O operation; also protected by buf_pool_mutex @see enum buf_io_fix */ - unsigned buf_fix_count:24;/*!< count of how manyfold this block + unsigned buf_fix_count:25;/*!< count of how manyfold this block is currently bufferfixed */ /* @} */ #endif /* !UNIV_HOTBACKUP */ @@ -1103,7 +1081,16 @@ struct buf_page_struct{ - BUF_BLOCK_FILE_PAGE: flush_list - BUF_BLOCK_ZIP_DIRTY: flush_list - BUF_BLOCK_ZIP_PAGE: zip_clean - - BUF_BLOCK_ZIP_FREE: zip_free[] */ + - BUF_BLOCK_ZIP_FREE: zip_free[] + + The contents of the list node + is undefined if !in_flush_list + && state == BUF_BLOCK_FILE_PAGE, + or if state is one of + BUF_BLOCK_MEMORY, + BUF_BLOCK_REMOVE_HASH or + BUF_BLOCK_READY_IN_USE. */ + #ifdef UNIV_DEBUG ibool in_flush_list; /*!< TRUE if in buf_pool->flush_list; when buf_pool_mutex is free, the @@ -1143,17 +1130,7 @@ struct buf_page_struct{ #endif /* UNIV_DEBUG */ unsigned old:1; /*!< TRUE if the block is in the old blocks in the LRU list */ - unsigned LRU_position:31;/*!< value which monotonically - decreases (or may stay - constant if old==TRUE) toward - the end of the LRU list, if - buf_pool->ulint_clock has not - wrapped around: NOTE that this - value can only be used in - heuristic algorithms, because - of the possibility of a - wrap-around! */ - unsigned freed_page_clock:32;/*!< the value of + unsigned freed_page_clock:31;/*!< the value of buf_pool->freed_page_clock when this block was the last time put to the head of the @@ -1161,6 +1138,9 @@ struct buf_page_struct{ to read this for heuristic purposes without holding any mutex or latch */ + unsigned access_time:32; /*!< time of first access, or + 0 if the block was never accessed + in the buffer pool */ /* @} */ # ifdef UNIV_DEBUG_FILE_ACCESSES ibool file_page_was_freed; @@ -1305,6 +1285,31 @@ Compute the hash fold value for blocks in buf_pool->zip_hash. */ #define BUF_POOL_ZIP_FOLD_BPAGE(b) BUF_POOL_ZIP_FOLD((buf_block_t*) (b)) /* @} */ +/** @brief The buffer pool statistics structure. */ +struct buf_pool_stat_struct{ + ulint n_page_gets; /*!< number of page gets performed; + also successful searches through + the adaptive hash index are + counted as page gets; this field + is NOT protected by the buffer + pool mutex */ + ulint n_pages_read; /*!< number read operations */ + ulint n_pages_written;/*!< number write operations */ + ulint n_pages_created;/*!< number of pages created + in the pool with no read */ + ulint n_ra_pages_read;/*!< number of pages read in + as part of read ahead */ + ulint n_ra_pages_evicted;/*!< number of read ahead + pages that are evicted without + being accessed */ + ulint n_pages_made_young; /*!< number of pages made young, in + calls to buf_LRU_make_block_young() */ + ulint n_pages_not_made_young; /*!< number of pages not made + young because the first access + was not long enough ago, in + buf_page_peek_if_too_old() */ +}; + /** @brief The buffer pool structure. NOTE! The definition appears here only for other modules of this @@ -1329,28 +1334,16 @@ struct buf_pool_struct{ ulint n_pend_reads; /*!< number of pending read operations */ ulint n_pend_unzip; /*!< number of pending decompressions */ - time_t last_printout_time; /*!< when buf_print was last time + time_t last_printout_time; + /*!< when buf_print_io was last time called */ - ulint n_pages_read; /*!< number read operations */ - ulint n_pages_written;/*!< number write operations */ - ulint n_pages_created;/*!< number of pages created - in the pool with no read */ - ulint n_page_gets; /*!< number of page gets performed; - also successful searches through - the adaptive hash index are - counted as page gets; this field - is NOT protected by the buffer - pool mutex */ - ulint n_page_gets_old;/*!< n_page_gets when buf_print was - last time called: used to calculate - hit rate */ - ulint n_pages_read_old;/*!< n_pages_read when buf_print was - last time called */ - ulint n_pages_written_old;/*!< number write operations */ - ulint n_pages_created_old;/*!< number of pages created in - the pool with no read */ + buf_pool_stat_t stat; /*!< current statistics */ + buf_pool_stat_t old_stat; /*!< old statistics */ + /* @} */ + /** @name Page flushing algorithm fields */ + /* @{ */ UT_LIST_BASE_NODE_T(buf_page_t) flush_list; @@ -1366,10 +1359,6 @@ struct buf_pool_struct{ /*!< this is in the set state when there is no flush batch of the given type running */ - ulint ulint_clock; /*!< a sequence number used to count - time. NOTE! This counter wraps - around at 4 billion (if ulint == - 32 bits)! */ ulint freed_page_clock;/*!< a sequence number used to count the number of buffer blocks removed from the end of @@ -1393,9 +1382,11 @@ struct buf_pool_struct{ block list */ UT_LIST_BASE_NODE_T(buf_page_t) LRU; /*!< base node of the LRU list */ - buf_page_t* LRU_old; /*!< pointer to the about 3/8 oldest - blocks in the LRU list; NULL if LRU - length less than BUF_LRU_OLD_MIN_LEN; + buf_page_t* LRU_old; /*!< pointer to the about + buf_LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV + oldest blocks in the LRU list; + NULL if LRU length less than + BUF_LRU_OLD_MIN_LEN; NOTE: when LRU_old != NULL, its length should always equal LRU_old_len */ ulint LRU_old_len; /*!< length of the LRU list from diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic index 17064342116..8b1f904a090 100644 --- a/storage/innobase/include/buf0buf.ic +++ b/storage/innobase/include/buf0buf.ic @@ -72,9 +72,30 @@ buf_page_peek_if_too_old( /*=====================*/ const buf_page_t* bpage) /*!< in: block to make younger */ { - return(buf_pool->freed_page_clock - >= buf_page_get_freed_page_clock(bpage) - + 1 + (buf_pool->curr_size / 4)); + if (UNIV_UNLIKELY(buf_pool->freed_page_clock == 0)) { + /* If eviction has not started yet, do not update the + statistics or move blocks in the LRU list. This is + either the warm-up phase or an in-memory workload. */ + return(FALSE); + } else if (buf_LRU_old_threshold_ms && bpage->old) { + unsigned access_time = buf_page_is_accessed(bpage); + + if (access_time > 0 + && (ut_time_ms() - access_time) + >= buf_LRU_old_threshold_ms) { + return(TRUE); + } + + buf_pool->stat.n_pages_not_made_young++; + return(FALSE); + } else { + /* FIXME: bpage->freed_page_clock is 31 bits */ + return((buf_pool->freed_page_clock & ((1UL << 31) - 1)) + > ((ulint) bpage->freed_page_clock + + (buf_pool->curr_size + * (BUF_LRU_OLD_RATIO_DIV - buf_LRU_old_ratio) + / (BUF_LRU_OLD_RATIO_DIV * 4)))); + } } /*********************************************************************//** @@ -118,22 +139,6 @@ buf_pool_get_oldest_modification(void) return(lsn); } - -/*******************************************************************//** -Increments the buf_pool clock by one and returns its new value. Remember -that in the 32 bit version the clock wraps around at 4 billion! -@return new clock value */ -UNIV_INLINE -ulint -buf_pool_clock_tic(void) -/*====================*/ -{ - ut_ad(buf_pool_mutex_own()); - - buf_pool->ulint_clock++; - - return(buf_pool->ulint_clock); -} #endif /* !UNIV_HOTBACKUP */ /*********************************************************************//** @@ -279,21 +284,6 @@ buf_page_belongs_to_unzip_LRU( && buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE); } -/*********************************************************************//** -Determine the approximate LRU list position of a block. -@return LRU list position */ -UNIV_INLINE -ulint -buf_page_get_LRU_position( -/*======================*/ - const buf_page_t* bpage) /*!< in: control block */ -{ - ut_ad(buf_page_in_file(bpage)); - ut_ad(buf_pool_mutex_own()); - - return(bpage->LRU_position); -} - /*********************************************************************//** Gets the mutex of a block. @return pointer to mutex protecting bpage */ @@ -487,17 +477,17 @@ buf_page_set_old( } /*********************************************************************//** -Determine if a block has been accessed in the buffer pool. -@return TRUE if accessed */ +Determine the time of first access of a block in the buffer pool. +@return ut_time_ms() at the time of first access, 0 if not accessed */ UNIV_INLINE -ibool +unsigned buf_page_is_accessed( /*=================*/ const buf_page_t* bpage) /*!< in: control block */ { ut_ad(buf_page_in_file(bpage)); - return(bpage->accessed); + return(bpage->access_time); } /*********************************************************************//** @@ -507,12 +497,15 @@ void buf_page_set_accessed( /*==================*/ buf_page_t* bpage, /*!< in/out: control block */ - ibool accessed) /*!< in: accessed */ + ulint time_ms) /*!< in: ut_time_ms() */ { ut_a(buf_page_in_file(bpage)); - ut_ad(mutex_own(buf_page_get_mutex(bpage))); + ut_ad(buf_pool_mutex_own()); - bpage->accessed = accessed; + if (!bpage->access_time) { + /* Make this the time of the first access. */ + bpage->access_time = time_ms; + } } /*********************************************************************//** diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h index 463aca0982c..009430af35b 100644 --- a/storage/innobase/include/buf0lru.h +++ b/storage/innobase/include/buf0lru.h @@ -69,7 +69,7 @@ These are low-level functions #########################################################################*/ /** Minimum LRU list length for which the LRU_old pointer is defined */ -#define BUF_LRU_OLD_MIN_LEN 80 +#define BUF_LRU_OLD_MIN_LEN 512 /* 8 megabytes of 16k pages */ /** Maximum LRU list search length in buf_flush_LRU_recommendation() */ #define BUF_LRU_FREE_SEARCH_LEN (5 + 2 * BUF_READ_AHEAD_AREA) @@ -84,15 +84,6 @@ void buf_LRU_invalidate_tablespace( /*==========================*/ ulint id); /*!< in: space id */ -/******************************************************************//** -Gets the minimum LRU_position field for the blocks in an initial segment -(determined by BUF_LRU_INITIAL_RATIO) of the LRU list. The limit is not -guaranteed to be precise, because the ulint_clock may wrap around. -@return the limit; zero if could not determine it */ -UNIV_INTERN -ulint -buf_LRU_get_recent_limit(void); -/*==========================*/ /********************************************************************//** Insert a compressed block into buf_pool->zip_clean in the LRU order. */ UNIV_INTERN @@ -201,6 +192,18 @@ void buf_LRU_make_block_old( /*===================*/ buf_page_t* bpage); /*!< in: control block */ +/**********************************************************************//** +Updates buf_LRU_old_ratio. +@return updated old_pct */ +UNIV_INTERN +uint +buf_LRU_old_ratio_update( +/*=====================*/ + uint old_pct,/*!< in: Reserve this percentage of + the buffer pool for "old" blocks. */ + ibool adjust);/*!< in: TRUE=adjust the LRU list; + FALSE=just assign buf_LRU_old_ratio + during the initialization of InnoDB */ /********************************************************************//** Update the historical stats that we are collecting for LRU eviction policy at the end of each interval. */ @@ -227,6 +230,35 @@ buf_LRU_print(void); /*===============*/ #endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */ +/** @name Heuristics for detecting index scan @{ */ +/** Reserve this much/BUF_LRU_OLD_RATIO_DIV of the buffer pool for +"old" blocks. Protected by buf_pool_mutex. */ +extern uint buf_LRU_old_ratio; +/** The denominator of buf_LRU_old_ratio. */ +#define BUF_LRU_OLD_RATIO_DIV 1024 +/** Maximum value of buf_LRU_old_ratio. +@see buf_LRU_old_adjust_len +@see buf_LRU_old_ratio_update */ +#define BUF_LRU_OLD_RATIO_MAX BUF_LRU_OLD_RATIO_DIV +/** Minimum value of buf_LRU_old_ratio. +@see buf_LRU_old_adjust_len +@see buf_LRU_old_ratio_update +The minimum must exceed +(BUF_LRU_OLD_TOLERANCE + 5) * BUF_LRU_OLD_RATIO_DIV / BUF_LRU_OLD_MIN_LEN. */ +#define BUF_LRU_OLD_RATIO_MIN 51 + +#if BUF_LRU_OLD_RATIO_MIN >= BUF_LRU_OLD_RATIO_MAX +# error "BUF_LRU_OLD_RATIO_MIN >= BUF_LRU_OLD_RATIO_MAX" +#endif +#if BUF_LRU_OLD_RATIO_MAX > BUF_LRU_OLD_RATIO_DIV +# error "BUF_LRU_OLD_RATIO_MAX > BUF_LRU_OLD_RATIO_DIV" +#endif + +/** Move blocks to "new" LRU list only if the first access was at +least this many milliseconds ago. Not protected by any mutex or latch. */ +extern uint buf_LRU_old_threshold_ms; +/* @} */ + /** @brief Statistics for selecting the LRU list for eviction. These statistics are not 'of' LRU but 'for' LRU. We keep count of I/O diff --git a/storage/innobase/include/buf0rea.h b/storage/innobase/include/buf0rea.h index b4d25e6fde0..093750623d6 100644 --- a/storage/innobase/include/buf0rea.h +++ b/storage/innobase/include/buf0rea.h @@ -33,12 +33,10 @@ Created 11/5/1995 Heikki Tuuri High-level function which reads a page asynchronously from a file to the buffer buf_pool if it is not already there. Sets the io_fix flag and sets an exclusive lock on the buffer frame. The flag is cleared and the x-lock -released by the i/o-handler thread. Does a random read-ahead if it seems -sensible. -@return number of page read requests issued: this can be greater than -1 if read-ahead occurred */ +released by the i/o-handler thread. +@return TRUE if page has been read in, FALSE in case of failure */ UNIV_INTERN -ulint +ibool buf_read_page( /*==========*/ ulint space, /*!< in: space id */ @@ -48,7 +46,7 @@ buf_read_page( Applies linear read-ahead if in the buf_pool the page is a border page of a linear read-ahead area and all the pages in the area have been accessed. Does not read any page if the read-ahead mechanism is not activated. Note -that the the algorithm looks at the 'natural' adjacent successor and +that the algorithm looks at the 'natural' adjacent successor and predecessor of the page, which on the leaf level of a B-tree are the next and previous page in the chain of leaves. To know these, the page specified in (space, offset) must already be present in the buf_pool. Thus, the diff --git a/storage/innobase/include/buf0types.h b/storage/innobase/include/buf0types.h index e7167d716a0..bfae6477135 100644 --- a/storage/innobase/include/buf0types.h +++ b/storage/innobase/include/buf0types.h @@ -34,6 +34,8 @@ typedef struct buf_block_struct buf_block_t; typedef struct buf_chunk_struct buf_chunk_t; /** Buffer pool comprising buf_chunk_t */ typedef struct buf_pool_struct buf_pool_t; +/** Buffer pool statistics struct */ +typedef struct buf_pool_stat_struct buf_pool_stat_t; /** A buffer frame. @see page_t */ typedef byte buf_frame_t; diff --git a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h index 3107d771d88..cce1246b789 100644 --- a/storage/innobase/include/dict0crea.h +++ b/storage/innobase/include/dict0crea.h @@ -110,7 +110,7 @@ dict_create_or_check_foreign_constraint_tables(void); Adds foreign key definitions to data dictionary tables in the database. We look at table->foreign_list, and also generate names to constraints that were not named by the user. A generated constraint has a name of the format -databasename/tablename_ibfk_, where the numbers start from 1, and are +databasename/tablename_ibfk_NUMBER, where the numbers start from 1, and are given locally for this table, that is, the number is not global, as in the old format constraints < 4.0.18 it used to be. @return error code or DB_SUCCESS */ diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index b2029699e51..d425241a3a2 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -712,7 +712,7 @@ dict_index_find_on_id_low( dulint id); /*!< in: index id */ /**********************************************************************//** Adds an index to the dictionary cache. -@return DB_SUCCESS or error code */ +@return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */ UNIV_INTERN ulint dict_index_add_to_cache( diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 1ee906fbf57..2d001111938 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -317,7 +317,7 @@ struct dict_foreign_struct{ char* id; /*!< id of the constraint as a null-terminated string */ unsigned n_fields:10; /*!< number of indexes' first fields - for which the the foreign key + for which the foreign key constraint is defined: we allow the indexes to contain more fields than mentioned in the constraint, as long diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index 5f7dc58eedc..7abd3914eda 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/include/fsp0fsp.h @@ -42,7 +42,7 @@ fsp_init(void); /*==========*/ /**********************************************************************//** Gets the current free limit of the system tablespace. The free limit -means the place of the first page which has never been put to the the +means the place of the first page which has never been put to the free list for allocation. The space above that address is initialized to zero. Sets also the global variable log_fsp_current_free_limit. @return free limit in megabytes */ diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index fa5db831d4f..aeabe39e1a9 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -630,6 +630,14 @@ lock_number_of_rows_locked( /*=======================*/ trx_t* trx); /*!< in: transaction */ /*******************************************************************//** +Check if a transaction holds any autoinc locks. +@return TRUE if the transaction holds any AUTOINC locks. */ +UNIV_INTERN +ibool +lock_trx_holds_autoinc_locks( +/*=========================*/ + const trx_t* trx); /*!< in: transaction */ +/*******************************************************************//** Release all the transaction's autoinc locks. */ UNIV_INTERN void diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index 059f548a085..299b4a05b40 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -118,10 +118,9 @@ UNIV_INLINE ib_uint64_t log_reserve_and_write_fast( /*=======================*/ - byte* str, /*!< in: string */ + const void* str, /*!< in: string */ ulint len, /*!< in: string length */ - ib_uint64_t* start_lsn,/*!< out: start lsn of the log record */ - ibool* success);/*!< out: TRUE if success */ + ib_uint64_t* start_lsn);/*!< out: start lsn of the log record */ /***********************************************************************//** Releases the log mutex. */ UNIV_INLINE @@ -283,7 +282,7 @@ log_make_checkpoint_at( later lsn, if IB_ULONGLONG_MAX, makes a checkpoint at the latest lsn */ ibool write_always); /*!< in: the function normally checks if - the the new checkpoint would have a + the new checkpoint would have a greater lsn than the previous one: if not, then no physical write is done; by setting this parameter TRUE, a diff --git a/storage/innobase/include/log0log.ic b/storage/innobase/include/log0log.ic index d071985982a..36d151a3064 100644 --- a/storage/innobase/include/log0log.ic +++ b/storage/innobase/include/log0log.ic @@ -27,6 +27,7 @@ Created 12/9/1995 Heikki Tuuri #include "mach0data.h" #include "mtr0mtr.h" +#ifdef UNIV_LOG_DEBUG /******************************************************//** Checks by parsing that the catenated log segment for a single mtr is consistent. */ @@ -34,11 +35,12 @@ UNIV_INTERN ibool log_check_log_recs( /*===============*/ - byte* buf, /*!< in: pointer to the start of + const byte* buf, /*!< in: pointer to the start of the log segment in the log_sys->buf log buffer */ ulint len, /*!< in: segment length in bytes */ ib_uint64_t buf_start_lsn); /*!< in: buffer start lsn */ +#endif /* UNIV_LOG_DEBUG */ /************************************************************//** Gets a log block flush bit. @@ -305,55 +307,76 @@ UNIV_INLINE ib_uint64_t log_reserve_and_write_fast( /*=======================*/ - byte* str, /*!< in: string */ + const void* str, /*!< in: string */ ulint len, /*!< in: string length */ - ib_uint64_t* start_lsn,/*!< out: start lsn of the log record */ - ibool* success)/*!< out: TRUE if success */ + ib_uint64_t* start_lsn)/*!< out: start lsn of the log record */ { - log_t* log = log_sys; ulint data_len; - ib_uint64_t lsn; +#ifdef UNIV_LOG_LSN_DEBUG + /* length of the LSN pseudo-record */ + ulint lsn_len = 1 + + mach_get_compressed_size(log_sys->lsn >> 32) + + mach_get_compressed_size(log_sys->lsn & 0xFFFFFFFFUL); +#endif /* UNIV_LOG_LSN_DEBUG */ - *success = TRUE; + mutex_enter(&log_sys->mutex); - mutex_enter(&(log->mutex)); - - data_len = len + log->buf_free % OS_FILE_LOG_BLOCK_SIZE; + data_len = len +#ifdef UNIV_LOG_LSN_DEBUG + + lsn_len +#endif /* UNIV_LOG_LSN_DEBUG */ + + log_sys->buf_free % OS_FILE_LOG_BLOCK_SIZE; if (data_len >= OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) { /* The string does not fit within the current log block or the log block would become full */ - *success = FALSE; - - mutex_exit(&(log->mutex)); + mutex_exit(&log_sys->mutex); return(0); } - *start_lsn = log->lsn; + *start_lsn = log_sys->lsn; - ut_memcpy(log->buf + log->buf_free, str, len); +#ifdef UNIV_LOG_LSN_DEBUG + { + /* Write the LSN pseudo-record. */ + byte* b = &log_sys->buf[log_sys->buf_free]; + *b++ = MLOG_LSN | (MLOG_SINGLE_REC_FLAG & *(const byte*) str); + /* Write the LSN in two parts, + as a pseudo page number and space id. */ + b += mach_write_compressed(b, log_sys->lsn >> 32); + b += mach_write_compressed(b, log_sys->lsn & 0xFFFFFFFFUL); + ut_a(b - lsn_len == &log_sys->buf[log_sys->buf_free]); - log_block_set_data_len((byte*) ut_align_down(log->buf + log->buf_free, + memcpy(b, str, len); + len += lsn_len; + } +#else /* UNIV_LOG_LSN_DEBUG */ + memcpy(log_sys->buf + log_sys->buf_free, str, len); +#endif /* UNIV_LOG_LSN_DEBUG */ + + log_block_set_data_len((byte*) ut_align_down(log_sys->buf + + log_sys->buf_free, OS_FILE_LOG_BLOCK_SIZE), data_len); #ifdef UNIV_LOG_DEBUG - log->old_buf_free = log->buf_free; - log->old_lsn = log->lsn; + log_sys->old_buf_free = log_sys->buf_free; + log_sys->old_lsn = log_sys->lsn; #endif - log->buf_free += len; + log_sys->buf_free += len; - ut_ad(log->buf_free <= log->buf_size); + ut_ad(log_sys->buf_free <= log_sys->buf_size); - lsn = log->lsn += len; + log_sys->lsn += len; #ifdef UNIV_LOG_DEBUG - log_check_log_recs(log->buf + log->old_buf_free, - log->buf_free - log->old_buf_free, log->old_lsn); + log_check_log_recs(log_sys->buf + log_sys->old_buf_free, + log_sys->buf_free - log_sys->old_buf_free, + log_sys->old_lsn); #endif - return(lsn); + return(log_sys->lsn); } /***********************************************************************//** diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h index 8468c213bdb..6de735be945 100644 --- a/storage/innobase/include/log0recv.h +++ b/storage/innobase/include/log0recv.h @@ -433,6 +433,11 @@ are allowed yet: the variable name is misleading. */ extern ibool recv_no_ibuf_operations; /** TRUE when recv_init_crash_recovery() has been called. */ extern ibool recv_needed_recovery; +#ifdef UNIV_DEBUG +/** TRUE if writing to the redo log (mtr_commit) is forbidden. +Protected by log_sys->mutex. */ +extern ibool recv_no_log_write; +#endif /* UNIV_DEBUG */ /** TRUE if buf_page_is_corrupted() should check if the log sequence number (FIL_PAGE_LSN) is in the future. Initially FALSE, and set by diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 69a2c03f4cb..bc3f1951be9 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -106,6 +106,9 @@ For 1 - 8 bytes, the flag value must give the length also! @{ */ #define MLOG_IBUF_BITMAP_INIT ((byte)27) /*!< initialize an ibuf bitmap page */ /*#define MLOG_FULL_PAGE ((byte)28) full contents of a page */ +#ifdef UNIV_LOG_LSN_DEBUG +# define MLOG_LSN ((byte)28) /* current LSN */ +#endif #define MLOG_INIT_FILE_PAGE ((byte)29) /*!< this means that a file page is taken into use and the prior @@ -118,7 +121,7 @@ For 1 - 8 bytes, the flag value must give the length also! @{ */ #define MLOG_WRITE_STRING ((byte)30) /*!< write a string to a page */ #define MLOG_MULTI_REC_END ((byte)31) /*!< if a single mtr writes - log records for several pages, + several log records, this log record ends the sequence of these records */ #define MLOG_DUMMY_RECORD ((byte)32) /*!< dummy log record used to diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index d8d2f0e5d9e..8535ef092c3 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -157,6 +157,7 @@ log. */ to become available again */ #define OS_FILE_SHARING_VIOLATION 76 #define OS_FILE_ERROR_NOT_SPECIFIED 77 +#define OS_FILE_INSUFFICIENT_RESOURCE 78 /* @} */ /** Types for aio operations @{ */ diff --git a/storage/innobase/include/os0sync.h b/storage/innobase/include/os0sync.h index 0e0b32e7036..0c22162b900 100644 --- a/storage/innobase/include/os0sync.h +++ b/storage/innobase/include/os0sync.h @@ -285,44 +285,74 @@ os_fast_mutex_free( /**********************************************************//** Atomic compare-and-swap and increment for InnoDB. */ -#ifdef HAVE_GCC_ATOMIC_BUILTINS +#if defined(HAVE_IB_GCC_ATOMIC_BUILTINS) + +#define HAVE_ATOMIC_BUILTINS + /**********************************************************//** Returns true if swapped, ptr is pointer to target, old_val is value to compare to, new_val is the value to swap in. */ + # define os_compare_and_swap(ptr, old_val, new_val) \ __sync_bool_compare_and_swap(ptr, old_val, new_val) + # define os_compare_and_swap_ulint(ptr, old_val, new_val) \ os_compare_and_swap(ptr, old_val, new_val) + # define os_compare_and_swap_lint(ptr, old_val, new_val) \ os_compare_and_swap(ptr, old_val, new_val) -# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ + +# ifdef HAVE_IB_ATOMIC_PTHREAD_T_GCC +# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ os_compare_and_swap(ptr, old_val, new_val) +# define INNODB_RW_LOCKS_USE_ATOMICS +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes and rw_locks use GCC atomic builtins" +# else /* HAVE_IB_ATOMIC_PTHREAD_T_GCC */ +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes use GCC atomic builtins, rw_locks do not" +# endif /* HAVE_IB_ATOMIC_PTHREAD_T_GCC */ + /**********************************************************//** Returns the resulting value, ptr is pointer to target, amount is the amount of increment. */ + # define os_atomic_increment(ptr, amount) \ __sync_add_and_fetch(ptr, amount) + # define os_atomic_increment_lint(ptr, amount) \ os_atomic_increment(ptr, amount) + # define os_atomic_increment_ulint(ptr, amount) \ os_atomic_increment(ptr, amount) + /**********************************************************//** Returns the old value of *ptr, atomically sets *ptr to new_val */ + # define os_atomic_test_and_set_byte(ptr, new_val) \ __sync_lock_test_and_set(ptr, new_val) + +#elif defined(HAVE_IB_SOLARIS_ATOMICS) + +#define HAVE_ATOMIC_BUILTINS + /* If not compiling with GCC or GCC doesn't support the atomic intrinsics and running on Solaris >= 10 use Solaris atomics */ -#elif defined(HAVE_SOLARIS_ATOMICS) + #include + /**********************************************************//** Returns true if swapped, ptr is pointer to target, old_val is value to compare to, new_val is the value to swap in. */ + # define os_compare_and_swap_ulint(ptr, old_val, new_val) \ (atomic_cas_ulong(ptr, old_val, new_val) == old_val) + # define os_compare_and_swap_lint(ptr, old_val, new_val) \ ((lint)atomic_cas_ulong((ulong_t*) ptr, old_val, new_val) == old_val) -# ifdef INNODB_RW_LOCKS_USE_ATOMICS -# if SIZEOF_PTHREAD_T == 4 + +# ifdef HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS +# if SIZEOF_PTHREAD_T == 4 # define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ ((pthread_t)atomic_cas_32(ptr, old_val, new_val) == old_val) # elif SIZEOF_PTHREAD_T == 8 @@ -331,21 +361,35 @@ compare to, new_val is the value to swap in. */ # else # error "SIZEOF_PTHREAD_T != 4 or 8" # endif /* SIZEOF_PTHREAD_T CHECK */ -# endif /* INNODB_RW_LOCKS_USE_ATOMICS */ +# define INNODB_RW_LOCKS_USE_ATOMICS +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes and rw_locks use Solaris atomic functions" +# else /* HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS */ +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes use Solaris atomic functions, rw_locks do not" +# endif /* HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS */ /**********************************************************//** Returns the resulting value, ptr is pointer to target, amount is the amount of increment. */ + # define os_atomic_increment_lint(ptr, amount) \ atomic_add_long_nv((ulong_t*) ptr, amount) + # define os_atomic_increment_ulint(ptr, amount) \ atomic_add_long_nv(ptr, amount) + /**********************************************************//** Returns the old value of *ptr, atomically sets *ptr to new_val */ + # define os_atomic_test_and_set_byte(ptr, new_val) \ atomic_swap_uchar(ptr, new_val) -/* On Windows, use Windows atomics / interlocked */ + #elif defined(HAVE_WINDOWS_ATOMICS) + +#define HAVE_ATOMIC_BUILTINS + +/* On Windows, use Windows atomics / interlocked */ # ifdef _WIN64 # define win_cmp_and_xchg InterlockedCompareExchange64 # define win_xchg_and_add InterlockedExchangeAdd64 @@ -353,31 +397,46 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */ # define win_cmp_and_xchg InterlockedCompareExchange # define win_xchg_and_add InterlockedExchangeAdd # endif + /**********************************************************//** Returns true if swapped, ptr is pointer to target, old_val is value to compare to, new_val is the value to swap in. */ + # define os_compare_and_swap_ulint(ptr, old_val, new_val) \ (win_cmp_and_xchg(ptr, new_val, old_val) == old_val) + # define os_compare_and_swap_lint(ptr, old_val, new_val) \ (win_cmp_and_xchg(ptr, new_val, old_val) == old_val) -# ifdef INNODB_RW_LOCKS_USE_ATOMICS -# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ + +/* windows thread objects can always be passed to windows atomic functions */ +# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ (InterlockedCompareExchange(ptr, new_val, old_val) == old_val) -# endif /* INNODB_RW_LOCKS_USE_ATOMICS */ +# define INNODB_RW_LOCKS_USE_ATOMICS +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes and rw_locks use Windows interlocked functions" + /**********************************************************//** Returns the resulting value, ptr is pointer to target, amount is the amount of increment. */ + # define os_atomic_increment_lint(ptr, amount) \ (win_xchg_and_add(ptr, amount) + amount) + # define os_atomic_increment_ulint(ptr, amount) \ ((ulint) (win_xchg_and_add(ptr, amount) + amount)) + /**********************************************************//** Returns the old value of *ptr, atomically sets *ptr to new_val. InterlockedExchange() operates on LONG, and the LONG will be clobbered */ + # define os_atomic_test_and_set_byte(ptr, new_val) \ ((byte) InterlockedExchange(ptr, new_val)) -#endif /* HAVE_GCC_ATOMIC_BUILTINS */ + +#else +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes and rw_locks use InnoDB's own implementation" +#endif #ifndef UNIV_NONINL #include "os0sync.ic" diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index a4fe069d022..3899499fb6a 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -76,8 +76,11 @@ typedef byte page_header_t; header which are set in a page create */ /*----*/ #define PAGE_LEVEL 26 /* level of the node in an index tree; the - leaf level is the level 0 */ -#define PAGE_INDEX_ID 28 /* index id where the page belongs */ + leaf level is the level 0. This field should + not be written to after page creation. */ +#define PAGE_INDEX_ID 28 /* index id where the page belongs. + This field should not be written to after + page creation. */ #define PAGE_BTR_SEG_LEAF 36 /* file segment header for the leaf pages in a B-tree: defined only on the root page of a B-tree, but not in the root of an ibuf tree */ diff --git a/storage/innobase/include/page0zip.h b/storage/innobase/include/page0zip.h index 9aaa066306b..574809e5227 100644 --- a/storage/innobase/include/page0zip.h +++ b/storage/innobase/include/page0zip.h @@ -127,8 +127,12 @@ page_zip_decompress( /*================*/ page_zip_des_t* page_zip,/*!< in: data, ssize; out: m_start, m_end, m_nonempty, n_blobs */ - page_t* page) /*!< out: uncompressed page, may be trashed */ - __attribute__((nonnull)); + page_t* page, /*!< out: uncompressed page, may be trashed */ + ibool all) /*!< in: TRUE=decompress the whole page; + FALSE=verify but do not copy some + page header fields that should not change + after page creation */ + __attribute__((nonnull(1,2))); #ifdef UNIV_DEBUG /**********************************************************************//** @@ -385,8 +389,8 @@ IMPORTANT: if page_zip_reorganize() is invoked on a leaf page of a non-clustered index, the caller must update the insert buffer free bits in the same mini-transaction in such a way that the modification will be redo-logged. -@return TRUE on success, FALSE on failure; page and page_zip will be -left intact on failure. */ +@return TRUE on success, FALSE on failure; page_zip will be left +intact on failure, but page will be overwritten. */ UNIV_INTERN ibool page_zip_reorganize( diff --git a/storage/innobase/include/rem0cmp.h b/storage/innobase/include/rem0cmp.h index d30d9f86abe..072f74267ea 100644 --- a/storage/innobase/include/rem0cmp.h +++ b/storage/innobase/include/rem0cmp.h @@ -89,7 +89,7 @@ cmp_dfield_dfield( /*************************************************************//** This function is used to compare a data tuple to a physical record. Only dtuple->n_fields_cmp first fields are taken into account for -the the data tuple! If we denote by n = n_fields_cmp, then rec must +the data tuple! If we denote by n = n_fields_cmp, then rec must have either m >= n fields, or it must differ from dtuple in some of the m fields rec has. If rec has an externally stored field we do not compare it but return with value 0 if such a comparison should be diff --git a/storage/innobase/include/rem0rec.ic b/storage/innobase/include/rem0rec.ic index 9fe736f9b0b..8e5bd9a7fcd 100644 --- a/storage/innobase/include/rem0rec.ic +++ b/storage/innobase/include/rem0rec.ic @@ -65,7 +65,7 @@ most significant bytes and bits are written below less significant. - offset_of_this_record) mod 64Ki, where mod is the modulo as a non-negative number; - we can calculate the the offset of the next + we can calculate the offset of the next record with the formula: relative_offset + offset_of_this_record mod UNIV_PAGE_SIZE diff --git a/storage/innobase/include/row0ins.h b/storage/innobase/include/row0ins.h index 530622e6225..9f93565ddb7 100644 --- a/storage/innobase/include/row0ins.h +++ b/storage/innobase/include/row0ins.h @@ -45,7 +45,7 @@ row_ins_check_foreign_constraint( /*=============================*/ ibool check_ref,/*!< in: TRUE If we want to check that the referenced table is ok, FALSE if we - want to to check the foreign key table */ + want to check the foreign key table */ dict_foreign_t* foreign,/*!< in: foreign constraint; NOTE that the tables mentioned in it must be in the dictionary cache if they exist at all */ diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 97028622505..6d5d195172e 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -177,7 +177,9 @@ row_update_prebuilt_trx( in MySQL handle */ trx_t* trx); /*!< in: transaction handle */ /*********************************************************************//** -Unlocks AUTO_INC type locks that were possibly reserved by a trx. */ +Unlocks AUTO_INC type locks that were possibly reserved by a trx. This +function should be called at the the end of an SQL statement, by the +connection thread that owns the transaction (trx->mysql_thd). */ UNIV_INTERN void row_unlock_table_autoinc_for_mysql( diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 499bccfe2b8..23472bd100e 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -315,10 +315,6 @@ extern ulint srv_buf_pool_flushed; /** Number of buffer pool reads that led to the reading of a disk page */ extern ulint srv_buf_pool_reads; -/** Number of sequential read-aheads */ -extern ulint srv_read_ahead_seq; -/** Number of random read-aheads */ -extern ulint srv_read_ahead_rnd; /** Status variables to be passed to MySQL */ typedef struct export_var_struct export_struc; @@ -605,13 +601,13 @@ struct export_var_struct{ #ifdef UNIV_DEBUG ulint innodb_buffer_pool_pages_latched; /*!< Latched pages */ #endif /* UNIV_DEBUG */ - ulint innodb_buffer_pool_read_requests; /*!< buf_pool->n_page_gets */ + ulint innodb_buffer_pool_read_requests; /*!< buf_pool->stat.n_page_gets */ ulint innodb_buffer_pool_reads; /*!< srv_buf_pool_reads */ ulint innodb_buffer_pool_wait_free; /*!< srv_buf_pool_wait_free */ ulint innodb_buffer_pool_pages_flushed; /*!< srv_buf_pool_flushed */ ulint innodb_buffer_pool_write_requests;/*!< srv_buf_pool_write_requests */ - ulint innodb_buffer_pool_read_ahead_seq;/*!< srv_read_ahead_seq */ - ulint innodb_buffer_pool_read_ahead_rnd;/*!< srv_read_ahead_rnd */ + ulint innodb_buffer_pool_read_ahead; /*!< srv_read_ahead */ + ulint innodb_buffer_pool_read_ahead_evicted;/*!< srv_read_ahead evicted*/ ulint innodb_dblwr_pages_written; /*!< srv_dblwr_pages_written */ ulint innodb_dblwr_writes; /*!< srv_dblwr_writes */ ibool innodb_have_atomic_builtins; /*!< HAVE_ATOMIC_BUILTINS */ @@ -623,9 +619,9 @@ struct export_var_struct{ ulint innodb_os_log_pending_writes; /*!< srv_os_log_pending_writes */ ulint innodb_os_log_pending_fsyncs; /*!< fil_n_pending_log_flushes */ ulint innodb_page_size; /*!< UNIV_PAGE_SIZE */ - ulint innodb_pages_created; /*!< buf_pool->n_pages_created */ - ulint innodb_pages_read; /*!< buf_pool->n_pages_read */ - ulint innodb_pages_written; /*!< buf_pool->n_pages_written */ + ulint innodb_pages_created; /*!< buf_pool->stat.n_pages_created */ + ulint innodb_pages_read; /*!< buf_pool->stat.n_pages_read */ + ulint innodb_pages_written; /*!< buf_pool->stat.n_pages_written */ ulint innodb_row_lock_waits; /*!< srv_n_lock_wait_count */ ulint innodb_row_lock_current_waits; /*!< srv_n_lock_wait_current_count */ ib_int64_t innodb_row_lock_time; /*!< srv_n_lock_wait_time diff --git a/storage/innobase/include/trx0rec.h b/storage/innobase/include/trx0rec.h index 0ae82c33afe..a6e56e963c6 100644 --- a/storage/innobase/include/trx0rec.h +++ b/storage/innobase/include/trx0rec.h @@ -44,8 +44,8 @@ UNIV_INLINE trx_undo_rec_t* trx_undo_rec_copy( /*==============*/ - trx_undo_rec_t* undo_rec, /*!< in: undo log record */ - mem_heap_t* heap); /*!< in: heap where copied */ + const trx_undo_rec_t* undo_rec, /*!< in: undo log record */ + mem_heap_t* heap); /*!< in: heap where copied */ /**********************************************************************//** Reads the undo log record type. @return record type */ diff --git a/storage/innobase/include/trx0rec.ic b/storage/innobase/include/trx0rec.ic index 037b5d4f6cf..e7e41d6d9f6 100644 --- a/storage/innobase/include/trx0rec.ic +++ b/storage/innobase/include/trx0rec.ic @@ -100,8 +100,8 @@ UNIV_INLINE trx_undo_rec_t* trx_undo_rec_copy( /*==============*/ - trx_undo_rec_t* undo_rec, /*!< in: undo log record */ - mem_heap_t* heap) /*!< in: heap where copied */ + const trx_undo_rec_t* undo_rec, /*!< in: undo log record */ + mem_heap_t* heap) /*!< in: heap where copied */ { ulint len; diff --git a/storage/innobase/include/trx0roll.h b/storage/innobase/include/trx0roll.h index ddca9e9e4ef..1dee5655c8c 100644 --- a/storage/innobase/include/trx0roll.h +++ b/storage/innobase/include/trx0roll.h @@ -133,6 +133,17 @@ trx_rollback( Rollback or clean up any incomplete transactions which were encountered in crash recovery. If the transaction already was committed, then we clean up a possible insert undo log. If the +transaction was not yet committed, then we roll it back. */ +UNIV_INTERN +void +trx_rollback_or_clean_recovered( +/*============================*/ + ibool all); /*!< in: FALSE=roll back dictionary transactions; + TRUE=roll back all non-PREPARED transactions */ +/*******************************************************************//** +Rollback or clean up any incomplete transactions which were +encountered in crash recovery. If the transaction already was +committed, then we clean up a possible insert undo log. If the transaction was not yet committed, then we roll it back. Note: this is done in a background thread. @return a dummy parameter */ @@ -208,9 +219,9 @@ int trx_general_rollback_for_mysql( /*===========================*/ trx_t* trx, /*!< in: transaction handle */ - ibool partial,/*!< in: TRUE if partial rollback requested */ trx_savept_t* savept);/*!< in: pointer to savepoint undo number, if - partial rollback requested */ + partial rollback requested, or NULL for + complete rollback */ /*******************************************************************//** Rolls back a transaction back to a named savepoint. Modifications after the savepoint are undone but InnoDB does NOT release the corresponding locks diff --git a/storage/innobase/include/trx0sys.ic b/storage/innobase/include/trx0sys.ic index 1c7c732751b..820d31d0692 100644 --- a/storage/innobase/include/trx0sys.ic +++ b/storage/innobase/include/trx0sys.ic @@ -34,11 +34,11 @@ typedef byte trx_sysf_rseg_t; /* Rollback segment specification slot offsets */ /*-------------------------------------------------------------*/ -#define TRX_SYS_RSEG_SPACE 0 /* space where the the segment +#define TRX_SYS_RSEG_SPACE 0 /* space where the segment header is placed; starting with MySQL/InnoDB 5.1.7, this is UNIV_UNDEFINED if the slot is unused */ -#define TRX_SYS_RSEG_PAGE_NO 4 /* page number where the the segment +#define TRX_SYS_RSEG_PAGE_NO 4 /* page number where the segment header is placed; this is FIL_NULL if the slot is unused */ /*-------------------------------------------------------------*/ diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 681feeaec94..d2a59740c93 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -179,7 +179,7 @@ trx_commit_off_kernel( /****************************************************************//** Cleans up a transaction at database startup. The cleanup is needed if the transaction already got to the middle of a commit when the database -crashed, andf we cannot roll it back. */ +crashed, and we cannot roll it back. */ UNIV_INTERN void trx_cleanup_at_db_startup( @@ -360,7 +360,7 @@ enum trx_dict_op { operation modes in crash recovery. */ TRX_DICT_OP_TABLE = 1, /** The transaction is creating or dropping an index in an - existing table. In crash recovery, the the data dictionary + existing table. In crash recovery, the data dictionary must be locked, but the table must not be dropped. */ TRX_DICT_OP_INDEX = 2 }; diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index 023a6c9cd89..0e14f7b1cba 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -46,11 +46,11 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 1 #define INNODB_VERSION_MINOR 0 -#define INNODB_VERSION_BUGFIX 4 +#define INNODB_VERSION_BUGFIX 5 /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; -calculated in in make_version_string() in sql/sql_show.cc like this: +calculated in make_version_string() in sql/sql_show.cc like this: "version >> 8" . "version & 0xff" because the version is shown with only one dot, we skip the last component, i.e. we show M.N.P as M.N */ @@ -78,17 +78,25 @@ the virtual method table (vtable) in GCC 3. */ # define ha_innobase ha_innodb #endif /* MYSQL_DYNAMIC_PLUGIN */ +/* if any of the following macros is defined at this point this means +that the code from the "right" plug.in was executed and we do not +need to include ut0auxconf.h which would either define the same macros +or will be empty */ +#if !defined(HAVE_IB_GCC_ATOMIC_BUILTINS) \ + && !defined(HAVE_IB_ATOMIC_PTHREAD_T_GCC) \ + && !defined(HAVE_IB_SOLARIS_ATOMICS) \ + && !defined(HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS) \ + && !defined(SIZEOF_PTHREAD_T) \ + && !defined(HAVE_IB_PAUSE_INSTRUCTION) +# include "ut0auxconf.h" +#endif + #if (defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)) && !defined(MYSQL_SERVER) && !defined(__WIN__) # undef __WIN__ # define __WIN__ # include -# if defined(HAVE_WINDOWS_ATOMICS) -/* If atomics are defined we use them in InnoDB mutex implementation */ -# define HAVE_ATOMIC_BUILTINS -# endif /* HAVE_WINDOWS_ATOMICS */ - # ifdef _NT_ # define __NT__ # endif @@ -111,45 +119,17 @@ if we are compiling on Windows. */ # include /* mmap() for os0proc.c */ # endif -# undef PACKAGE -# undef VERSION - /* Include the header file generated by GNU autoconf */ # ifndef __WIN__ -#ifndef UNIV_HOTBACKUP -# include "config.h" -#endif /* UNIV_HOTBACKUP */ +# ifndef UNIV_HOTBACKUP +# include "config.h" +# endif /* UNIV_HOTBACKUP */ # endif # ifdef HAVE_SCHED_H # include # endif -# if defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_SOLARIS_ATOMICS) \ - || defined(HAVE_WINDOWS_ATOMICS) -/* If atomics are defined we use them in InnoDB mutex implementation */ -# define HAVE_ATOMIC_BUILTINS -# endif /* (HAVE_GCC_ATOMIC_BUILTINS) || (HAVE_SOLARIS_ATOMICS) - || (HAVE_WINDOWS_ATOMICS) */ - -/* For InnoDB rw_locks to work with atomics we need the thread_id -to be no more than machine word wide. The following enables using -atomics for InnoDB rw_locks where these conditions are met. */ -#ifdef HAVE_ATOMIC_BUILTINS -/* if HAVE_ATOMIC_PTHREAD_T is defined at this point that means that -the code from plug.in has defined it and we do not need to include -ut0auxconf.h which would either define HAVE_ATOMIC_PTHREAD_T or will -be empty */ -# ifndef HAVE_ATOMIC_PTHREAD_T -# include "ut0auxconf.h" -# endif /* HAVE_ATOMIC_PTHREAD_T */ -/* now HAVE_ATOMIC_PTHREAD_T is eventually defined either by plug.in or -from Makefile.in->ut0auxconf.h */ -# ifdef HAVE_ATOMIC_PTHREAD_T -# define INNODB_RW_LOCKS_USE_ATOMICS -# endif /* HAVE_ATOMIC_PTHREAD_T */ -#endif /* HAVE_ATOMIC_BUILTINS */ - /* We only try to do explicit inlining of functions with gcc and Sun Studio */ @@ -196,12 +176,18 @@ command. Not tested on Windows. */ debugging without UNIV_DEBUG */ #define UNIV_DEBUG /* Enable ut_ad() assertions and disable UNIV_INLINE */ +#define UNIV_DEBUG_LOCK_VALIDATE /* Enable + ut_ad(lock_rec_validate_page()) + assertions. */ #define UNIV_DEBUG_FILE_ACCESSES /* Debug .ibd file access (field file_page_was_freed in buf_page_t) */ #define UNIV_LRU_DEBUG /* debug the buffer pool LRU */ #define UNIV_HASH_DEBUG /* debug HASH_ macros */ #define UNIV_LIST_DEBUG /* debug UT_LIST_ macros */ +#define UNIV_LOG_LSN_DEBUG /* write LSN to the redo log; +this will break redo log file compatibility, but it may be useful when +debugging redo log application problems. */ #define UNIV_MEM_DEBUG /* detect memory leaks etc */ #define UNIV_IBUF_DEBUG /* debug the insert buffer */ #define UNIV_IBUF_COUNT_DEBUG /* debug the insert buffer; @@ -409,7 +395,8 @@ it is read. */ it is read or written. */ # define UNIV_PREFETCH_RW(addr) __builtin_prefetch(addr, 1, 3) /* Sun Studio includes sun_prefetch.h as of version 5.9 */ -#elif (defined(__SUNPRO_C) && __SUNPRO_C >= 0x590) || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x590) +#elif (defined(__SUNPRO_C) && __SUNPRO_C >= 0x590) \ + || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x590) # include #if __SUNPRO_C >= 0x550 # undef UNIV_INTERN diff --git a/storage/innobase/include/ut0auxconf.h b/storage/innobase/include/ut0auxconf.h index 88fb26f1863..16bcc308392 100644 --- a/storage/innobase/include/ut0auxconf.h +++ b/storage/innobase/include/ut0auxconf.h @@ -1,14 +1,14 @@ /* Do not remove this file even though it is empty. This file is included in univ.i and will cause compilation failure if not present. -A custom check has been added in the generated +A custom checks have been added in the generated storage/innobase/Makefile.in that is shipped with the InnoDB Plugin -source archive. This check tries to compile a test program and if -successful then adds "#define HAVE_ATOMIC_PTHREAD_T" to this file. -This is a hack that has been developed in order to check for pthread_t -atomicity without the need to regenerate the ./configure script that is +source archive. These checks eventually define some macros and put +them in this file. +This is a hack that has been developed in order to deploy new compile +time checks without the need to regenerate the ./configure script that is distributed in the MySQL 5.1 official source archives. If by any chance Makefile.in and ./configure are regenerated and thus -the hack from Makefile.in wiped away then the "real" check from plug.in +the hack from Makefile.in wiped away then the "real" checks from plug.in will take over. */ diff --git a/storage/innobase/include/ut0byte.h b/storage/innobase/include/ut0byte.h index a2687e62f08..f55e2888c60 100644 --- a/storage/innobase/include/ut0byte.h +++ b/storage/innobase/include/ut0byte.h @@ -219,8 +219,8 @@ UNIV_INLINE void* ut_align( /*=====*/ - void* ptr, /*!< in: pointer */ - ulint align_no); /*!< in: align by this number */ + const void* ptr, /*!< in: pointer */ + ulint align_no); /*!< in: align by this number */ /*********************************************************//** The following function rounds down a pointer to the nearest aligned address. diff --git a/storage/innobase/include/ut0byte.ic b/storage/innobase/include/ut0byte.ic index e3beed65138..3dd51890cb4 100644 --- a/storage/innobase/include/ut0byte.ic +++ b/storage/innobase/include/ut0byte.ic @@ -319,8 +319,8 @@ UNIV_INLINE void* ut_align( /*=====*/ - void* ptr, /*!< in: pointer */ - ulint align_no) /*!< in: align by this number */ + const void* ptr, /*!< in: pointer */ + ulint align_no) /*!< in: align by this number */ { ut_ad(align_no > 0); ut_ad(((align_no - 1) & align_no) == 0); diff --git a/storage/innobase/include/ut0ut.h b/storage/innobase/include/ut0ut.h index 80094321041..197b8401428 100644 --- a/storage/innobase/include/ut0ut.h +++ b/storage/innobase/include/ut0ut.h @@ -34,6 +34,11 @@ Created 1/20/1994 Heikki Tuuri #define ut0ut_h #include "univ.i" + +#ifndef UNIV_HOTBACKUP +# include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ +#endif /* UNIV_HOTBACKUP */ + #include #ifndef MYSQL_SERVER #include @@ -47,7 +52,8 @@ Created 1/20/1994 Heikki Tuuri /** Time stamp */ typedef time_t ib_time_t; -#if defined(IB_HAVE_PAUSE_INSTRUCTION) +#ifndef UNIV_HOTBACKUP +#if defined(HAVE_IB_PAUSE_INSTRUCTION) # ifdef WIN32 /* In the Win32 API, the x86 PAUSE instruction is executed by calling the YieldProcessor macro defined in WinNT.h. It is a CPU architecture- @@ -84,6 +90,7 @@ do { \ os_thread_sleep(2000 /* 2 ms */); \ } \ } while (0) +#endif /* !UNIV_HOTBACKUP */ /********************************************************//** Gets the high 32 bits in a ulint. That is makes a shift >> 32, @@ -216,6 +223,7 @@ UNIV_INTERN ib_time_t ut_time(void); /*=========*/ +#ifndef UNIV_HOTBACKUP /**********************************************************//** Returns system time. Upon successful completion, the value 0 is returned; otherwise the @@ -239,6 +247,16 @@ ullint ut_time_us( /*=======*/ ullint* tloc); /*!< out: us since epoch, if non-NULL */ +/**********************************************************//** +Returns the number of milliseconds since some epoch. The +value may wrap around. It should only be used for heuristic +purposes. +@return ms since epoch */ +UNIV_INTERN +ulint +ut_time_ms(void); +/*============*/ +#endif /* !UNIV_HOTBACKUP */ /**********************************************************//** Returns the difference of two times in seconds. diff --git a/storage/innobase/lock/lock0lock.c b/storage/innobase/lock/lock0lock.c index 0cc89336199..67b2eac7219 100644 --- a/storage/innobase/lock/lock0lock.c +++ b/storage/innobase/lock/lock0lock.c @@ -214,7 +214,7 @@ a waiting s-lock request on the next record? If this s-lock was placed by a read cursor moving in the ascending order in the index, we cannot do the insert immediately, because when we finally commit our transaction, the read cursor should see also the new inserted record. So we should -move the read cursor backward from the the next record for it to pass over +move the read cursor backward from the next record for it to pass over the new inserted record. This move backward may be too cumbersome to implement. If we in this situation just enqueue a second x-lock request for our transaction on the next record, then the deadlock mechanism @@ -360,10 +360,9 @@ ibool lock_rec_validate_page( /*===================*/ ulint space, /*!< in: space id */ + ulint zip_size,/*!< in: compressed page size in bytes + or 0 for uncompressed pages */ ulint page_no);/*!< in: page number */ - -/* Define the following in order to enable lock_rec_validate_page() checks. */ -# undef UNIV_DEBUG_LOCK_VALIDATE #endif /* UNIV_DEBUG */ /* The lock system */ @@ -2622,6 +2621,7 @@ lock_move_reorganize_page( #ifdef UNIV_DEBUG_LOCK_VALIDATE ut_ad(lock_rec_validate_page(buf_block_get_space(block), + buf_block_get_zip_size(block), buf_block_get_page_no(block))); #endif } @@ -2711,8 +2711,10 @@ lock_move_rec_list_end( #ifdef UNIV_DEBUG_LOCK_VALIDATE ut_ad(lock_rec_validate_page(buf_block_get_space(block), + buf_block_get_zip_size(block), buf_block_get_page_no(block))); ut_ad(lock_rec_validate_page(buf_block_get_space(new_block), + buf_block_get_zip_size(block), buf_block_get_page_no(new_block))); #endif } @@ -2822,6 +2824,7 @@ lock_move_rec_list_start( #ifdef UNIV_DEBUG_LOCK_VALIDATE ut_ad(lock_rec_validate_page(buf_block_get_space(block), + buf_block_get_zip_size(block), buf_block_get_page_no(block))); #endif } @@ -4630,6 +4633,10 @@ lock_rec_queue_validate( next function call: we have to release lock table mutex to obey the latching order */ + /* If this thread is holding the file space latch + (fil_space_t::latch), the following check WILL break + latching order and may cause a deadlock of threads. */ + impl_trx = lock_sec_rec_some_has_impl_off_kernel( rec, index, offsets); @@ -4687,6 +4694,8 @@ ibool lock_rec_validate_page( /*===================*/ ulint space, /*!< in: space id */ + ulint zip_size,/*!< in: compressed page size in bytes + or 0 for uncompressed pages */ ulint page_no)/*!< in: page number */ { dict_index_t* index; @@ -4697,7 +4706,6 @@ lock_rec_validate_page( ulint nth_lock = 0; ulint nth_bit = 0; ulint i; - ulint zip_size; mtr_t mtr; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; @@ -4708,7 +4716,6 @@ lock_rec_validate_page( mtr_start(&mtr); - zip_size = fil_space_get_zip_size(space); ut_ad(zip_size != ULINT_UNDEFINED); block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, &mtr); buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK); @@ -4753,6 +4760,11 @@ loop: lock_mutex_exit_kernel(); + /* If this thread is holding the file space + latch (fil_space_t::latch), the following + check WILL break the latching order and may + cause a deadlock of threads. */ + lock_rec_queue_validate(block, rec, index, offsets); lock_mutex_enter_kernel(); @@ -4843,7 +4855,9 @@ lock_validate(void) lock_mutex_exit_kernel(); - lock_rec_validate_page(space, page_no); + lock_rec_validate_page(space, + fil_space_get_zip_size(space), + page_no); lock_mutex_enter_kernel(); @@ -5366,6 +5380,20 @@ lock_release_autoinc_last_lock( lock_table_dequeue(lock); } +/*******************************************************************//** +Check if a transaction holds any autoinc locks. +@return TRUE if the transaction holds any AUTOINC locks. */ +UNIV_INTERN +ibool +lock_trx_holds_autoinc_locks( +/*=========================*/ + const trx_t* trx) /*!< in: transaction */ +{ + ut_a(trx->autoinc_locks != NULL); + + return(!ib_vector_is_empty(trx->autoinc_locks)); +} + /*******************************************************************//** Release all the transaction's autoinc locks. */ UNIV_INTERN diff --git a/storage/innobase/log/log0log.c b/storage/innobase/log/log0log.c index 24c828cdf5f..a23dd20772a 100644 --- a/storage/innobase/log/log0log.c +++ b/storage/innobase/log/log0log.c @@ -241,6 +241,7 @@ log_reserve_and_open( ut_a(len < log->buf_size / 2); loop: mutex_enter(&(log->mutex)); + ut_ad(!recv_no_log_write); /* Calculate an upper limit for the space the string may take in the log buffer */ @@ -309,6 +310,7 @@ log_write_low( ut_ad(mutex_own(&(log->mutex))); part_loop: + ut_ad(!recv_no_log_write); /* Calculate a part length */ data_len = (log->buf_free % OS_FILE_LOG_BLOCK_SIZE) + str_len; @@ -377,6 +379,7 @@ log_close(void) ib_uint64_t checkpoint_age; ut_ad(mutex_own(&(log->mutex))); + ut_ad(!recv_no_log_write); lsn = log->lsn; @@ -668,8 +671,6 @@ log_calc_max_ages(void) ulint archive_margin; ulint smallest_archive_margin; - ut_ad(!mutex_own(&(log_sys->mutex))); - mutex_enter(&(log_sys->mutex)); group = UT_LIST_GET_FIRST(log_sys->log_groups); @@ -1117,6 +1118,7 @@ log_io_complete( } mutex_enter(&(log_sys->mutex)); + ut_ad(!recv_no_log_write); ut_a(group->n_pending_writes > 0); ut_a(log_sys->n_pending_writes > 0); @@ -1148,6 +1150,7 @@ log_group_file_header_flush( ulint dest_offset; ut_ad(mutex_own(&(log_sys->mutex))); + ut_ad(!recv_no_log_write); ut_a(nth_file < group->n_files); buf = *(group->file_header_bufs + nth_file); @@ -1219,6 +1222,7 @@ log_group_write_buf( ulint i; ut_ad(mutex_own(&(log_sys->mutex))); + ut_ad(!recv_no_log_write); ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0); ut_a(((ulint) start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); @@ -1361,6 +1365,7 @@ loop: #endif mutex_enter(&(log_sys->mutex)); + ut_ad(!recv_no_log_write); if (flush_to_disk && log_sys->flushed_to_disk_lsn >= lsn) { @@ -1974,6 +1979,7 @@ log_checkpoint( mutex_enter(&(log_sys->mutex)); + ut_ad(!recv_no_log_write); oldest_lsn = log_buf_pool_get_oldest_modification(); mutex_exit(&(log_sys->mutex)); @@ -2047,7 +2053,7 @@ log_make_checkpoint_at( later lsn, if IB_ULONGLONG_MAX, makes a checkpoint at the latest lsn */ ibool write_always) /*!< in: the function normally checks if - the the new checkpoint would have a + the new checkpoint would have a greater lsn than the previous one: if not, then no physical write is done; by setting this parameter TRUE, a @@ -2086,6 +2092,7 @@ loop: do_checkpoint = FALSE; mutex_enter(&(log->mutex)); + ut_ad(!recv_no_log_write); if (log->check_flush_or_checkpoint == FALSE) { mutex_exit(&(log->mutex)); @@ -3035,6 +3042,7 @@ loop: #endif /* UNIV_LOG_ARCHIVE */ mutex_enter(&(log_sys->mutex)); + ut_ad(!recv_no_log_write); if (log_sys->check_flush_or_checkpoint) { @@ -3234,6 +3242,7 @@ loop: ut_a(lsn == log_sys->lsn); } +#ifdef UNIV_LOG_DEBUG /******************************************************//** Checks by parsing that the catenated log segment for a single mtr is consistent. */ @@ -3241,7 +3250,7 @@ UNIV_INTERN ibool log_check_log_recs( /*===============*/ - byte* buf, /*!< in: pointer to the start of + const byte* buf, /*!< in: pointer to the start of the log segment in the log_sys->buf log buffer */ ulint len, /*!< in: segment length in bytes */ @@ -3249,8 +3258,8 @@ log_check_log_recs( { ib_uint64_t contiguous_lsn; ib_uint64_t scanned_lsn; - byte* start; - byte* end; + const byte* start; + const byte* end; byte* buf1; byte* scan_buf; @@ -3283,6 +3292,7 @@ log_check_log_recs( return(TRUE); } +#endif /* UNIV_LOG_DEBUG */ /******************************************************//** Peeks the current lsn. diff --git a/storage/innobase/log/log0recv.c b/storage/innobase/log/log0recv.c index aea29c78517..81dcc9cd4f8 100644 --- a/storage/innobase/log/log0recv.c +++ b/storage/innobase/log/log0recv.c @@ -78,6 +78,11 @@ UNIV_INTERN ibool recv_recovery_from_backup_on = FALSE; #ifndef UNIV_HOTBACKUP /** TRUE when recv_init_crash_recovery() has been called. */ UNIV_INTERN ibool recv_needed_recovery = FALSE; +# ifdef UNIV_DEBUG +/** TRUE if writing to the redo log (mtr_commit) is forbidden. +Protected by log_sys->mutex. */ +UNIV_INTERN ibool recv_no_log_write = FALSE; +# endif /* UNIV_DEBUG */ /** TRUE if buf_page_is_corrupted() should check if the log sequence number (FIL_PAGE_LSN) is in the future. Initially FALSE, and set by @@ -853,6 +858,11 @@ recv_parse_or_apply_log_rec_body( } switch (type) { +#ifdef UNIV_LOG_LSN_DEBUG + case MLOG_LSN: + /* The LSN is checked in recv_parse_log_rec(). */ + break; +#endif /* UNIV_LOG_LSN_DEBUG */ case MLOG_1BYTE: case MLOG_2BYTES: case MLOG_4BYTES: case MLOG_8BYTES: #ifdef UNIV_DEBUG if (page && page_type == FIL_PAGE_TYPE_ALLOCATED @@ -1269,7 +1279,7 @@ recv_add_to_hash_table( sizeof(recv_data_t) + len); *prev_field = recv_data; - ut_memcpy(((byte*)recv_data) + sizeof(recv_data_t), body, len); + memcpy(recv_data + 1, body, len); prev_field = &(recv_data->next); @@ -1327,6 +1337,7 @@ recv_recover_page_func( buf_block_t* block) /*!< in/out: buffer block */ { page_t* page; + page_zip_des_t* page_zip; recv_addr_t* recv_addr; recv_t* recv; byte* buf; @@ -1376,6 +1387,7 @@ recv_recover_page_func( mtr_set_log_mode(&mtr, MTR_LOG_NONE); page = block->frame; + page_zip = buf_block_get_page_zip(block); #ifndef UNIV_HOTBACKUP if (just_read_in) { @@ -1436,13 +1448,19 @@ recv_recover_page_func( if (recv->type == MLOG_INIT_FILE_PAGE) { page_lsn = page_newest_lsn; - mach_write_ull(page + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN_OLD_CHKSUM, 0); - mach_write_ull(page + FIL_PAGE_LSN, 0); + memset(FIL_PAGE_LSN + page, 0, 8); + memset(UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM + + page, 0, 8); + + if (page_zip) { + memset(FIL_PAGE_LSN + page_zip->data, 0, 8); + } } if (recv->start_lsn >= page_lsn) { + ib_uint64_t end_lsn; + if (!modification_to_page) { modification_to_page = TRUE; @@ -1464,11 +1482,17 @@ recv_recover_page_func( recv_parse_or_apply_log_rec_body(recv->type, buf, buf + recv->len, block, &mtr); - mach_write_ull(page + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN_OLD_CHKSUM, - recv->start_lsn + recv->len); - mach_write_ull(page + FIL_PAGE_LSN, - recv->start_lsn + recv->len); + + end_lsn = recv->start_lsn + recv->len; + mach_write_ull(FIL_PAGE_LSN + page, end_lsn); + mach_write_ull(UNIV_PAGE_SIZE + - FIL_PAGE_END_LSN_OLD_CHKSUM + + page, end_lsn); + + if (page_zip) { + mach_write_ull(FIL_PAGE_LSN + + page_zip->data, end_lsn); + } } if (recv->len > RECV_DATA_BLOCK_SIZE) { @@ -1686,6 +1710,7 @@ loop: /* Flush all the file pages to disk and invalidate them in the buffer pool */ + ut_d(recv_no_log_write = TRUE); mutex_exit(&(recv_sys->mutex)); mutex_exit(&(log_sys->mutex)); @@ -1699,6 +1724,7 @@ loop: mutex_enter(&(log_sys->mutex)); mutex_enter(&(recv_sys->mutex)); + ut_d(recv_no_log_write = FALSE); recv_no_ibuf_operations = FALSE; } @@ -1910,6 +1936,17 @@ recv_parse_log_rec( return(0); } +#ifdef UNIV_LOG_LSN_DEBUG + if (*type == MLOG_LSN) { + ib_uint64_t lsn = (ib_uint64_t) *space << 32 | *page_no; +# ifdef UNIV_LOG_DEBUG + ut_a(lsn == log_sys->old_lsn); +# else /* UNIV_LOG_DEBUG */ + ut_a(lsn == recv_sys->recovered_lsn); +# endif /* UNIV_LOG_DEBUG */ + } +#endif /* UNIV_LOG_LSN_DEBUG */ + /* Check that page_no is sensible */ if (UNIV_UNLIKELY(*page_no > 0x8FFFFFFFUL)) { @@ -2167,6 +2204,12 @@ loop: #endif /* In normal mysqld crash recovery we do not try to replay file operations */ +#ifdef UNIV_LOG_LSN_DEBUG + } else if (type == MLOG_LSN) { + /* Do not add these records to the hash table. + The page number and space id fields are misused + for something else. */ +#endif /* UNIV_LOG_LSN_DEBUG */ } else { recv_add_to_hash_table(type, space, page_no, body, ptr + len, old_lsn, @@ -2198,11 +2241,11 @@ loop: = recv_sys->recovered_offset + total_len; recv_previous_parsed_rec_is_multi = 1; - if ((!store_to_hash) && (type != MLOG_MULTI_REC_END)) { #ifdef UNIV_LOG_DEBUG + if ((!store_to_hash) && (type != MLOG_MULTI_REC_END)) { recv_check_incomplete_log_recs(ptr, len); -#endif /* UNIV_LOG_DEBUG */ } +#endif /* UNIV_LOG_DEBUG */ #ifdef UNIV_DEBUG if (log_debug_writes) { @@ -2266,7 +2309,11 @@ loop: break; } - if (store_to_hash) { + if (store_to_hash +#ifdef UNIV_LOG_LSN_DEBUG + && type != MLOG_LSN +#endif /* UNIV_LOG_LSN_DEBUG */ + ) { recv_add_to_hash_table(type, space, page_no, body, ptr + len, old_lsn, @@ -2415,8 +2462,7 @@ recv_scan_log_recs( scanned_lsn = start_lsn; more_data = FALSE; - while (log_block < buf + len && !finished) { - + do { no = log_block_get_hdr_no(log_block); /* fprintf(stderr, "Log block header no %lu\n", no); @@ -2546,10 +2592,11 @@ recv_scan_log_recs( /* Log data for this group ends here */ finished = TRUE; + break; } else { log_block += OS_FILE_LOG_BLOCK_SIZE; } - } + } while (log_block < buf + len && !finished); *group_scanned_lsn = scanned_lsn; @@ -3104,6 +3151,11 @@ recv_recovery_from_checkpoint_finish(void) #ifndef UNIV_LOG_DEBUG recv_sys_free(); #endif + /* Roll back any recovered data dictionary transactions, so + that the data dictionary tables will be free of any locks. + The data dictionary latch should guarantee that there is at + most one data dictionary transaction active at a time. */ + trx_rollback_or_clean_recovered(FALSE); /* Drop partially created indexes. */ row_merge_drop_temp_indexes(); diff --git a/storage/innobase/mem/mem0mem.c b/storage/innobase/mem/mem0mem.c index e0dc8716f13..ccb2fd8a7b4 100644 --- a/storage/innobase/mem/mem0mem.c +++ b/storage/innobase/mem/mem0mem.c @@ -475,16 +475,18 @@ mem_heap_block_free( len = block->len; block->magic_n = MEM_FREED_BLOCK_MAGIC_N; +#ifndef UNIV_HOTBACKUP + if (!srv_use_sys_malloc) { #ifdef UNIV_MEM_DEBUG - /* In the debug version we set the memory to a random combination - of hex 0xDE and 0xAD. */ + /* In the debug version we set the memory to a random + combination of hex 0xDE and 0xAD. */ - mem_erase_buf((byte*)block, len); + mem_erase_buf((byte*)block, len); #else /* UNIV_MEM_DEBUG */ - UNIV_MEM_ASSERT_AND_FREE(block, len); + UNIV_MEM_ASSERT_AND_FREE(block, len); #endif /* UNIV_MEM_DEBUG */ -#ifndef UNIV_HOTBACKUP + } if (type == MEM_HEAP_DYNAMIC || len < UNIV_PAGE_SIZE / 2) { ut_ad(!buf_block); @@ -495,6 +497,14 @@ mem_heap_block_free( buf_block_free(buf_block); } #else /* !UNIV_HOTBACKUP */ +#ifdef UNIV_MEM_DEBUG + /* In the debug version we set the memory to a random + combination of hex 0xDE and 0xAD. */ + + mem_erase_buf((byte*)block, len); +#else /* UNIV_MEM_DEBUG */ + UNIV_MEM_ASSERT_AND_FREE(block, len); +#endif /* UNIV_MEM_DEBUG */ ut_free(block); #endif /* !UNIV_HOTBACKUP */ } diff --git a/storage/innobase/mtr/mtr0mtr.c b/storage/innobase/mtr/mtr0mtr.c index be31c5df801..417e97732bb 100644 --- a/storage/innobase/mtr/mtr0mtr.c +++ b/storage/innobase/mtr/mtr0mtr.c @@ -35,6 +35,7 @@ Created 11/26/1995 Heikki Tuuri #include "log0log.h" #ifndef UNIV_HOTBACKUP +# include "log0recv.h" /*****************************************************************//** Releases the item in the slot given. */ UNIV_INLINE @@ -115,7 +116,6 @@ mtr_log_reserve_and_write( dyn_array_t* mlog; dyn_block_t* block; ulint data_size; - ibool success; byte* first_data; ut_ad(mtr); @@ -134,8 +134,8 @@ mtr_log_reserve_and_write( if (mlog->heap == NULL) { mtr->end_lsn = log_reserve_and_write_fast( first_data, dyn_block_get_used(mlog), - &(mtr->start_lsn), &success); - if (success) { + &mtr->start_lsn); + if (mtr->end_lsn) { return; } @@ -182,6 +182,8 @@ mtr_commit( ut_d(mtr->state = MTR_COMMITTING); #ifndef UNIV_HOTBACKUP + /* This is a dirty read, for debugging. */ + ut_ad(!recv_no_log_write); write_log = mtr->modifications && mtr->n_log_recs; if (write_log) { diff --git a/storage/innobase/mysql-test/innodb-analyze.test b/storage/innobase/mysql-test/innodb-analyze.test index d5d6d698170..9bdb9db697c 100644 --- a/storage/innobase/mysql-test/innodb-analyze.test +++ b/storage/innobase/mysql-test/innodb-analyze.test @@ -11,6 +11,7 @@ -- disable_result_log -- enable_warnings +let $sample_pages=`select @@innodb_stats_sample_pages`; SET GLOBAL innodb_stats_sample_pages=0; # check that the value has been adjusted to 1 @@ -61,3 +62,4 @@ SET GLOBAL innodb_stats_sample_pages=16; ANALYZE TABLE innodb_analyze; DROP TABLE innodb_analyze; +EVAL SET GLOBAL innodb_stats_sample_pages=$sample_pages; diff --git a/storage/innobase/mysql-test/innodb-consistent-master.opt b/storage/innobase/mysql-test/innodb-consistent-master.opt new file mode 100644 index 00000000000..8cca44767da --- /dev/null +++ b/storage/innobase/mysql-test/innodb-consistent-master.opt @@ -0,0 +1 @@ +--innodb_lock_wait_timeout=2 diff --git a/storage/innobase/mysql-test/innodb-consistent.result b/storage/innobase/mysql-test/innodb-consistent.result new file mode 100644 index 00000000000..9115791b99c --- /dev/null +++ b/storage/innobase/mysql-test/innodb-consistent.result @@ -0,0 +1,35 @@ +drop table if exists t1; +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +create table t2 like t1; +insert into t2 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; +begin; +replace into t1 select * from t2; +set session transaction isolation level read committed; +set autocommit=0; +delete from t2 where a=5; +commit; +delete from t2; +commit; +commit; +begin; +insert into t1 select * from t2; +set session transaction isolation level read committed; +set autocommit=0; +delete from t2 where a=5; +commit; +delete from t2; +commit; +commit; +select * from t1; +a +1 +2 +3 +4 +5 +6 +7 +drop table t1; +drop table t2; diff --git a/storage/innobase/mysql-test/innodb-consistent.test b/storage/innobase/mysql-test/innodb-consistent.test new file mode 100644 index 00000000000..791600fc8a7 --- /dev/null +++ b/storage/innobase/mysql-test/innodb-consistent.test @@ -0,0 +1,58 @@ +-- source include/not_embedded.inc +-- source include/have_innodb.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# REPLACE INTO ... SELECT and INSERT INTO ... SELECT should do +# a consistent read of the source table. + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +create table t2 like t1; +insert into t2 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; + +# REPLACE INTO ... SELECT case +begin; +# this should not result in any locks on t2. +replace into t1 select * from t2; + +connection b; +set session transaction isolation level read committed; +set autocommit=0; +# should not cuase a lock wait. +delete from t2 where a=5; +commit; +delete from t2; +commit; +connection a; +commit; + +# INSERT INTO ... SELECT case +begin; +# this should not result in any locks on t2. +insert into t1 select * from t2; + +connection b; +set session transaction isolation level read committed; +set autocommit=0; +# should not cuase a lock wait. +delete from t2 where a=5; +commit; +delete from t2; +commit; +connection a; +commit; + +select * from t1; +drop table t1; +drop table t2; + +connection default; +disconnect a; +disconnect b; diff --git a/storage/innobase/mysql-test/innodb-zip.result b/storage/innobase/mysql-test/innodb-zip.result index c81401743a5..b26c4112826 100644 --- a/storage/innobase/mysql-test/innodb-zip.result +++ b/storage/innobase/mysql-test/innodb-zip.result @@ -141,7 +141,7 @@ drop table t1; CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs -CREATE TABLE t1(c TEXT, PRIMARY KEY (c(439))) +CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512)); DROP TABLE t1; diff --git a/storage/innobase/mysql-test/innodb-zip.test b/storage/innobase/mysql-test/innodb-zip.test index ddc39d44487..5bcd0e3c824 100644 --- a/storage/innobase/mysql-test/innodb-zip.test +++ b/storage/innobase/mysql-test/innodb-zip.test @@ -105,7 +105,7 @@ drop table t1; --error ER_TOO_BIG_ROWSIZE CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; -CREATE TABLE t1(c TEXT, PRIMARY KEY (c(439))) +CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512)); DROP TABLE t1; diff --git a/storage/innobase/mysql-test/innodb_bug34300.test b/storage/innobase/mysql-test/innodb_bug34300.test index 114bcf98c25..68c385fd72a 100644 --- a/storage/innobase/mysql-test/innodb_bug34300.test +++ b/storage/innobase/mysql-test/innodb_bug34300.test @@ -9,6 +9,7 @@ -- disable_result_log # set packet size and reconnect +let $max_packet=`select @@global.max_allowed_packet`; SET @@global.max_allowed_packet=16777216; --connect (newconn, localhost, root,,) @@ -30,3 +31,4 @@ ALTER TABLE bug34300 ADD COLUMN (f10 INT); SELECT f4, f8 FROM bug34300; DROP TABLE bug34300; +EVAL SET @@global.max_allowed_packet=$max_packet; diff --git a/storage/innobase/mysql-test/innodb_bug36169.test b/storage/innobase/mysql-test/innodb_bug36169.test index d3566d3eb39..5bf55193b5c 100644 --- a/storage/innobase/mysql-test/innodb_bug36169.test +++ b/storage/innobase/mysql-test/innodb_bug36169.test @@ -5,6 +5,8 @@ -- source include/have_innodb.inc +let $file_format=`select @@innodb_file_format`; +let $file_per_table=`select @@innodb_file_per_table`; SET GLOBAL innodb_file_format='Barracuda'; SET GLOBAL innodb_file_per_table=ON; @@ -1153,3 +1155,5 @@ DROP TABLE IF EXISTS table4; DROP TABLE IF EXISTS table5; DROP TABLE IF EXISTS table6; +EVAL SET GLOBAL innodb_file_format=$file_format; +EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/storage/innobase/mysql-test/innodb_bug36172.test b/storage/innobase/mysql-test/innodb_bug36172.test index 666d4a2f4b7..c6c4e6fae47 100644 --- a/storage/innobase/mysql-test/innodb_bug36172.test +++ b/storage/innobase/mysql-test/innodb_bug36172.test @@ -14,6 +14,9 @@ SET storage_engine=InnoDB; -- disable_query_log -- disable_result_log +let $file_format=`select @@innodb_file_format`; +let $file_format_check=`select @@innodb_file_format_check`; +let $file_per_table=`select @@innodb_file_per_table`; SET GLOBAL innodb_file_format='Barracuda'; SET GLOBAL innodb_file_per_table=on; @@ -24,3 +27,6 @@ CHECK TABLE table0 EXTENDED; INSERT IGNORE INTO `table0` SET `col19` = '19940127002709', `col20` = 2383927.9055146948, `col21` = 4293243420.5621204000, `col22` = '20511211123705', `col23` = 4289899778.6573381000, `col24` = 4293449279.0540481000, `col25` = 'emphysemic', `col26` = 'dentally', `col27` = '2347406', `col28` = 'eruct', `col30` = 1222, `col31` = 4294372994.9941406000, `col32` = 4291385574.1173744000, `col33` = 'borrowing\'s', `col34` = 'septics', `col35` = 'ratter\'s', `col36` = 'Kaye', `col37` = 'Florentia', `col38` = 'allium', `col39` = 'barkeep', `col40` = '19510407003441', `col41` = 4293559200.4215522000, `col42` = 22482, `col43` = 'decussate', `col44` = 'Brom\'s', `col45` = 'violated', `col46` = 4925506.4635456400, `col47` = 930549, `col48` = '51296066', `col49` = 'voluminously', `col50` = '29306676', `col51` = -88, `col52` = -2153690, `col53` = 4290250202.1464887000, `col54` = 'expropriation', `col55` = 'Aberdeen\'s', `col56` = 20343, `col58` = '19640415171532', `col59` = 'extern', `col60` = 'Ubana', `col61` = 4290487961.8539081000, `col62` = '2147', `col63` = -24271, `col64` = '20750801194548', `col65` = 'Cunaxa\'s', `col66` = 'pasticcio', `col67` = 2795817, `col68` = 'Indore\'s', `col70` = 6864127, `col71` = '1817832', `col72` = '20540506114211', `col73` = '20040101012300', `col74` = 'rationalized', `col75` = '45522', `col76` = 'indene', `col77` = -6964559, `col78` = 4247535.5266884370, `col79` = '20720416124357', `col80` = '2143', `col81` = 4292060102.4466386000, `col82` = 'striving', `col83` = 'boneblack\'s', `col84` = 'redolent', `col85` = 6489697.9009369183, `col86` = 4287473465.9731131000, `col87` = 7726015, `col88` = 'perplexed', `col89` = '17153791', `col90` = 5478587.1108127078, `col91` = 4287091404.7004304000, `col92` = 'Boulez\'s', `col93` = '2931278'; CHECK TABLE table0 EXTENDED; DROP TABLE table0; +EVAL SET GLOBAL innodb_file_format=$file_format; +EVAL SET GLOBAL innodb_file_format_check=$file_format_check; +EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/storage/innobase/mysql-test/innodb_bug44369.result b/storage/innobase/mysql-test/innodb_bug44369.result new file mode 100644 index 00000000000..e4b84ecac19 --- /dev/null +++ b/storage/innobase/mysql-test/innodb_bug44369.result @@ -0,0 +1,14 @@ +create table bug44369 (DB_ROW_ID int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +create table bug44369 (db_row_id int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +show errors; +Level Code Message +Error 1005 Error creating table 'test/bug44369' with column name 'db_row_id'. 'db_row_id' is a reserved name. Please try to re-create the table with a different column name. +Error 1005 Can't create table 'test.bug44369' (errno: -1) +create table bug44369 (db_TRX_Id int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +show errors; +Level Code Message +Error 1005 Error creating table 'test/bug44369' with column name 'db_TRX_Id'. 'db_TRX_Id' is a reserved name. Please try to re-create the table with a different column name. +Error 1005 Can't create table 'test.bug44369' (errno: -1) diff --git a/storage/innobase/mysql-test/innodb_bug44369.test b/storage/innobase/mysql-test/innodb_bug44369.test new file mode 100644 index 00000000000..495059eb5e6 --- /dev/null +++ b/storage/innobase/mysql-test/innodb_bug44369.test @@ -0,0 +1,21 @@ +# This is the test for bug 44369. We should +# block table creation with columns match +# some innodb internal reserved key words, +# both case sensitively and insensitely. + +--source include/have_innodb.inc + +# This create table operation should fail. +--error ER_CANT_CREATE_TABLE +create table bug44369 (DB_ROW_ID int) engine=innodb; + +# This create should fail as well +--error ER_CANT_CREATE_TABLE +create table bug44369 (db_row_id int) engine=innodb; + +show errors; + +--error ER_CANT_CREATE_TABLE +create table bug44369 (db_TRX_Id int) engine=innodb; + +show errors; diff --git a/storage/innobase/mysql-test/innodb_bug44571.result b/storage/innobase/mysql-test/innodb_bug44571.result new file mode 100644 index 00000000000..36374edcb3e --- /dev/null +++ b/storage/innobase/mysql-test/innodb_bug44571.result @@ -0,0 +1,9 @@ +CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; +ALTER TABLE bug44571 CHANGE foo bar INT; +ALTER TABLE bug44571 ADD INDEX bug44571b (foo); +ERROR 42000: Key column 'foo' doesn't exist in table +ALTER TABLE bug44571 ADD INDEX bug44571b (bar); +ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it +CREATE INDEX bug44571b ON bug44571 (bar); +ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it +DROP TABLE bug44571; diff --git a/storage/innobase/mysql-test/innodb_bug44571.test b/storage/innobase/mysql-test/innodb_bug44571.test new file mode 100644 index 00000000000..685463ceff9 --- /dev/null +++ b/storage/innobase/mysql-test/innodb_bug44571.test @@ -0,0 +1,17 @@ +# +# Bug#44571 InnoDB Plugin crashes on ADD INDEX +# http://bugs.mysql.com/44571 +# +-- source include/have_innodb.inc + +CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; +ALTER TABLE bug44571 CHANGE foo bar INT; +-- error ER_KEY_COLUMN_DOES_NOT_EXITS +ALTER TABLE bug44571 ADD INDEX bug44571b (foo); +# The following will fail, because the CHANGE foo bar was +# not communicated to InnoDB. +--error ER_NOT_KEYFILE +ALTER TABLE bug44571 ADD INDEX bug44571b (bar); +--error ER_NOT_KEYFILE +CREATE INDEX bug44571b ON bug44571 (bar); +DROP TABLE bug44571; diff --git a/storage/innobase/mysql-test/innodb_bug46000.result b/storage/innobase/mysql-test/innodb_bug46000.result new file mode 100644 index 00000000000..ccff888a48d --- /dev/null +++ b/storage/innobase/mysql-test/innodb_bug46000.result @@ -0,0 +1,17 @@ +create table bug46000(`id` int,key `GEN_CLUST_INDEX`(`id`))engine=innodb; +ERROR HY000: Can't create table 'test.bug46000' (errno: -1) +create table bug46000(`id` int, key `GEN_clust_INDEX`(`id`))engine=innodb; +ERROR HY000: Can't create table 'test.bug46000' (errno: -1) +show errors; +Level Code Message +Error 1005 Cannot Create Index with name 'GEN_CLUST_INDEX'. The name is reserved for the system default primary index. +Error 1005 Can't create table 'test.bug46000' (errno: -1) +create table bug46000(id int) engine=innodb; +create index GEN_CLUST_INDEX on bug46000(id); +ERROR HY000: Can't create table '#sql-temporary' (errno: -1) +show errors; +Level Code Message +Error 1005 Cannot Create Index with name 'GEN_CLUST_INDEX'. The name is reserved for the system default primary index. +Error 1005 Can't create table '#sql-temporary' (errno: -1) +create index idx on bug46000(id); +drop table bug46000; diff --git a/storage/innobase/mysql-test/innodb_bug46000.test b/storage/innobase/mysql-test/innodb_bug46000.test new file mode 100644 index 00000000000..80c18c58ef0 --- /dev/null +++ b/storage/innobase/mysql-test/innodb_bug46000.test @@ -0,0 +1,34 @@ +# This is the test for bug 46000. We shall +# block any index creation with the name of +# "GEN_CLUST_INDEX", which is the reserved +# name for innodb default primary index. + +--source include/have_innodb.inc + +# This 'create table' operation should fail because of +# using the reserve name as its index name. +--error ER_CANT_CREATE_TABLE +create table bug46000(`id` int,key `GEN_CLUST_INDEX`(`id`))engine=innodb; + +# Mixed upper/lower case of the reserved key words +--error ER_CANT_CREATE_TABLE +create table bug46000(`id` int, key `GEN_clust_INDEX`(`id`))engine=innodb; + +show errors; + +create table bug46000(id int) engine=innodb; + +# This 'create index' operation should fail. +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +create index GEN_CLUST_INDEX on bug46000(id); + +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +show errors; + +# This 'create index' operation should succeed, no +# temp table left from last failed create index +# operation. +create index idx on bug46000(id); + +drop table bug46000; diff --git a/storage/innobase/mysql-test/innodb_file_format.result b/storage/innobase/mysql-test/innodb_file_format.result index 9cfac5f001c..8e9a317308b 100644 --- a/storage/innobase/mysql-test/innodb_file_format.result +++ b/storage/innobase/mysql-test/innodb_file_format.result @@ -42,3 +42,4 @@ ERROR HY000: Incorrect arguments to SET select @@innodb_file_format_check; @@innodb_file_format_check Barracuda +set global innodb_file_format_check=antelope; diff --git a/storage/innobase/mysql-test/innodb_file_format.test b/storage/innobase/mysql-test/innodb_file_format.test index 62ce4157183..d63c9b0228f 100644 --- a/storage/innobase/mysql-test/innodb_file_format.test +++ b/storage/innobase/mysql-test/innodb_file_format.test @@ -26,3 +26,4 @@ set global innodb_file_format=on; --error ER_WRONG_ARGUMENTS set global innodb_file_format=off; select @@innodb_file_format_check; +set global innodb_file_format_check=antelope; diff --git a/storage/innobase/os/os0file.c b/storage/innobase/os/os0file.c index d3bd6465f5f..a1d3bad2add 100644 --- a/storage/innobase/os/os0file.c +++ b/storage/innobase/os/os0file.c @@ -88,7 +88,9 @@ UNIV_INTERN ibool os_do_not_call_flush_at_each_write = FALSE; /* We do not call os_file_flush in every os_file_write. */ #endif /* UNIV_DO_FLUSH */ -#ifndef UNIV_HOTBACKUP +#ifdef UNIV_HOTBACKUP +# define os_aio_use_native_aio FALSE +#else /* UNIV_HOTBACKUP */ /* We use these mutexes to protect lseek + file i/o operation, if the OS does not provide an atomic pread or pwrite, or similar */ #define OS_FILE_N_SEEK_MUTEXES 16 @@ -198,7 +200,7 @@ static ulint os_aio_n_segments = ULINT_UNDEFINED; /** If the following is TRUE, read i/o handler threads try to wait until a batch of new read requests have been posted */ static ibool os_aio_recommend_sleep_for_read_threads = FALSE; -#endif /* !UNIV_HOTBACKUP */ +#endif /* UNIV_HOTBACKUP */ UNIV_INTERN ulint os_n_file_reads = 0; UNIV_INTERN ulint os_bytes_read_since_printout = 0; @@ -315,6 +317,12 @@ os_file_get_last_error( " software or another instance\n" "InnoDB: of MySQL." " Please close it to get rid of this error.\n"); + } else if (err == ERROR_WORKING_SET_QUOTA + || err == ERROR_NO_SYSTEM_RESOURCES) { + fprintf(stderr, + "InnoDB: The error means that there are no" + " sufficient system resources or quota to" + " complete the operation.\n"); } else { fprintf(stderr, "InnoDB: Some operating system error numbers" @@ -336,6 +344,9 @@ os_file_get_last_error( } else if (err == ERROR_SHARING_VIOLATION || err == ERROR_LOCK_VIOLATION) { return(OS_FILE_SHARING_VIOLATION); + } else if (err == ERROR_WORKING_SET_QUOTA + || err == ERROR_NO_SYSTEM_RESOURCES) { + return(OS_FILE_INSUFFICIENT_RESOURCE); } else { return(100 + err); } @@ -454,6 +465,10 @@ os_file_handle_error_cond_exit( os_thread_sleep(10000000); /* 10 sec */ return(TRUE); + } else if (err == OS_FILE_INSUFFICIENT_RESOURCE) { + + os_thread_sleep(100000); /* 100 ms */ + return(TRUE); } else { if (name) { fprintf(stderr, "InnoDB: File name %s\n", name); @@ -1245,6 +1260,7 @@ try_again: } #endif #ifdef UNIV_NON_BUFFERED_IO +# ifndef UNIV_HOTBACKUP if (type == OS_LOG_FILE && srv_flush_log_at_trx_commit == 2) { /* Do not use unbuffered i/o to log files because value 2 denotes that we do not flush the log at every @@ -1253,10 +1269,14 @@ try_again: == SRV_WIN_IO_UNBUFFERED) { attributes = attributes | FILE_FLAG_NO_BUFFERING; } -#endif +# else /* !UNIV_HOTBACKUP */ + attributes = attributes | FILE_FLAG_NO_BUFFERING; +# endif /* !UNIV_HOTBACKUP */ +#endif /* UNIV_NON_BUFFERED_IO */ } else if (purpose == OS_FILE_NORMAL) { attributes = 0; #ifdef UNIV_NON_BUFFERED_IO +# ifndef UNIV_HOTBACKUP if (type == OS_LOG_FILE && srv_flush_log_at_trx_commit == 2) { /* Do not use unbuffered i/o to log files because value 2 denotes that we do not flush the log at every @@ -1265,7 +1285,10 @@ try_again: == SRV_WIN_IO_UNBUFFERED) { attributes = attributes | FILE_FLAG_NO_BUFFERING; } -#endif +# else /* !UNIV_HOTBACKUP */ + attributes = attributes | FILE_FLAG_NO_BUFFERING; +# endif /* !UNIV_HOTBACKUP */ +#endif /* UNIV_NON_BUFFERED_IO */ } else { attributes = 0; ut_error; @@ -2022,7 +2045,9 @@ os_file_pread( offset */ { off_t offs; +#if defined(HAVE_PREAD) && !defined(HAVE_BROKEN_PREAD) ssize_t n_bytes; +#endif /* HAVE_PREAD && !HAVE_BROKEN_PREAD */ ut_a((offset & 0xFFFFFFFFUL) == offset); @@ -2061,16 +2086,20 @@ os_file_pread( { off_t ret_offset; ssize_t ret; +#ifndef UNIV_HOTBACKUP ulint i; +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads++; os_mutex_exit(os_file_count_mutex); +#ifndef UNIV_HOTBACKUP /* Protect the seek / read operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; os_mutex_enter(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ ret_offset = lseek(file, offs, SEEK_SET); @@ -2080,7 +2109,9 @@ os_file_pread( ret = read(file, buf, (ssize_t)n); } +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads--; @@ -2158,16 +2189,20 @@ os_file_pwrite( #else { off_t ret_offset; +# ifndef UNIV_HOTBACKUP ulint i; +# endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_writes++; os_mutex_exit(os_file_count_mutex); +# ifndef UNIV_HOTBACKUP /* Protect the seek / write operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; os_mutex_enter(os_file_seek_mutexes[i]); +# endif /* UNIV_HOTBACKUP */ ret_offset = lseek(file, offs, SEEK_SET); @@ -2193,7 +2228,9 @@ os_file_pwrite( # endif /* UNIV_DO_FLUSH */ func_exit: +# ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +# endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_writes--; @@ -2227,7 +2264,9 @@ os_file_read( DWORD low; DWORD high; ibool retry; +#ifndef UNIV_HOTBACKUP ulint i; +#endif /* !UNIV_HOTBACKUP */ ut_a((offset & 0xFFFFFFFFUL) == offset); @@ -2246,16 +2285,20 @@ try_again: os_n_pending_reads++; os_mutex_exit(os_file_count_mutex); +#ifndef UNIV_HOTBACKUP /* Protect the seek / read operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; os_mutex_enter(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ ret2 = SetFilePointer(file, low, &high, FILE_BEGIN); if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) { +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads--; @@ -2266,7 +2309,9 @@ try_again: ret = ReadFile(file, buf, (DWORD) n, &len, NULL); +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads--; @@ -2275,7 +2320,7 @@ try_again: if (ret && len == n) { return(TRUE); } -#else +#else /* __WIN__ */ ibool retry; ssize_t ret; @@ -2294,7 +2339,7 @@ try_again: "InnoDB: Was only able to read %ld.\n", (ulong)n, (ulong)offset_high, (ulong)offset, (long)ret); -#endif +#endif /* __WIN__ */ #ifdef __WIN__ error_handling: #endif @@ -2343,7 +2388,9 @@ os_file_read_no_error_handling( DWORD low; DWORD high; ibool retry; +#ifndef UNIV_HOTBACKUP ulint i; +#endif /* !UNIV_HOTBACKUP */ ut_a((offset & 0xFFFFFFFFUL) == offset); @@ -2362,16 +2409,20 @@ try_again: os_n_pending_reads++; os_mutex_exit(os_file_count_mutex); +#ifndef UNIV_HOTBACKUP /* Protect the seek / read operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; os_mutex_enter(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ ret2 = SetFilePointer(file, low, &high, FILE_BEGIN); if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) { +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads--; @@ -2382,7 +2433,9 @@ try_again: ret = ReadFile(file, buf, (DWORD) n, &len, NULL); +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads--; @@ -2391,7 +2444,7 @@ try_again: if (ret && len == n) { return(TRUE); } -#else +#else /* __WIN__ */ ibool retry; ssize_t ret; @@ -2404,7 +2457,7 @@ try_again: return(TRUE); } -#endif +#endif /* __WIN__ */ #ifdef __WIN__ error_handling: #endif @@ -2463,9 +2516,11 @@ os_file_write( DWORD ret2; DWORD low; DWORD high; - ulint i; ulint n_retries = 0; ulint err; +#ifndef UNIV_HOTBACKUP + ulint i; +#endif /* !UNIV_HOTBACKUP */ ut_a((offset & 0xFFFFFFFF) == offset); @@ -2482,16 +2537,20 @@ retry: os_n_pending_writes++; os_mutex_exit(os_file_count_mutex); +#ifndef UNIV_HOTBACKUP /* Protect the seek / write operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; os_mutex_enter(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ ret2 = SetFilePointer(file, low, &high, FILE_BEGIN); if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) { +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_writes--; @@ -2525,7 +2584,9 @@ retry: } # endif /* UNIV_DO_FLUSH */ +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_writes--; @@ -3371,9 +3432,21 @@ void os_aio_simulated_put_read_threads_to_sleep(void) /*============================================*/ { + +/* The idea of putting background IO threads to sleep is only for +Windows when using simulated AIO. Windows XP seems to schedule +background threads too eagerly to allow for coalescing during +readahead requests. */ +#ifdef __WIN__ os_aio_array_t* array; ulint g; + if (os_aio_use_native_aio) { + /* We do not use simulated aio: do nothing */ + + return; + } + os_aio_recommend_sleep_for_read_threads = TRUE; for (g = 0; g < os_aio_n_segments; g++) { @@ -3384,6 +3457,7 @@ os_aio_simulated_put_read_threads_to_sleep(void) os_event_reset(os_aio_segment_wait_events[g]); } } +#endif /* __WIN__ */ } /*******************************************************************//** diff --git a/storage/innobase/page/page0cur.c b/storage/innobase/page/page0cur.c index 65f3ba67439..f10f16a7dd9 100644 --- a/storage/innobase/page/page0cur.c +++ b/storage/innobase/page/page0cur.c @@ -1195,7 +1195,7 @@ page_cur_insert_rec_zip_reorg( } /* Out of space: restore the page */ - if (!page_zip_decompress(page_zip, page)) { + if (!page_zip_decompress(page_zip, page, FALSE)) { ut_error; /* Memory corrupted? */ } ut_ad(page_validate(page, index)); diff --git a/storage/innobase/page/page0page.c b/storage/innobase/page/page0page.c index f056ef77bdc..ab2ba60570e 100644 --- a/storage/innobase/page/page0page.c +++ b/storage/innobase/page/page0page.c @@ -45,7 +45,7 @@ Created 2/2/1994 Heikki Tuuri ============== The index page consists of a page header which contains the page's -id and other information. On top of it are the the index records +id and other information. On top of it are the index records in a heap linked into a one way linear list according to alphabetic order. Just below page end is an array of pointers which we call page directory, @@ -679,7 +679,7 @@ page_copy_rec_list_end( if (UNIV_UNLIKELY (!page_zip_decompress(new_page_zip, - new_page))) { + new_page, FALSE))) { ut_error; } ut_ad(page_validate(new_page, index)); @@ -792,7 +792,7 @@ page_copy_rec_list_start( if (UNIV_UNLIKELY (!page_zip_decompress(new_page_zip, - new_page))) { + new_page, FALSE))) { ut_error; } ut_ad(page_validate(new_page, index)); diff --git a/storage/innobase/page/page0zip.c b/storage/innobase/page/page0zip.c index 92ba0ec768a..aa5e39ff04a 100644 --- a/storage/innobase/page/page0zip.c +++ b/storage/innobase/page/page0zip.c @@ -47,8 +47,10 @@ Created June 2005 by Marko Makela # define buf_LRU_stat_inc_unzip() ((void) 0) #endif /* !UNIV_HOTBACKUP */ +#ifndef UNIV_HOTBACKUP /** Statistics on compression, indexed by page_zip_des_t::ssize - 1 */ UNIV_INTERN page_zip_stat_t page_zip_stat[PAGE_ZIP_NUM_SSIZE - 1]; +#endif /* !UNIV_HOTBACKUP */ /* Please refer to ../include/page0zip.ic for a description of the compressed page format. */ @@ -1144,7 +1146,9 @@ page_zip_compress( ulint* offsets = NULL; ulint n_blobs = 0; byte* storage;/* storage of uncompressed columns */ +#ifndef UNIV_HOTBACKUP ullint usec = ut_time_us(NULL); +#endif /* !UNIV_HOTBACKUP */ #ifdef PAGE_ZIP_COMPRESS_DBG FILE* logfile = NULL; #endif @@ -1208,7 +1212,9 @@ page_zip_compress( } } #endif /* PAGE_ZIP_COMPRESS_DBG */ +#ifndef UNIV_HOTBACKUP page_zip_stat[page_zip->ssize - 1].compressed++; +#endif /* !UNIV_HOTBACKUP */ if (UNIV_UNLIKELY(n_dense * PAGE_ZIP_DIR_SLOT_SIZE >= page_zip_get_size(page_zip))) { @@ -1345,8 +1351,10 @@ err_exit: fclose(logfile); } #endif /* PAGE_ZIP_COMPRESS_DBG */ +#ifndef UNIV_HOTBACKUP page_zip_stat[page_zip->ssize - 1].compressed_usec += ut_time_us(NULL) - usec; +#endif /* !UNIV_HOTBACKUP */ return(FALSE); } @@ -1404,12 +1412,14 @@ err_exit: fclose(logfile); } #endif /* PAGE_ZIP_COMPRESS_DBG */ +#ifndef UNIV_HOTBACKUP { page_zip_stat_t* zip_stat = &page_zip_stat[page_zip->ssize - 1]; zip_stat->compressed_ok++; zip_stat->compressed_usec += ut_time_us(NULL) - usec; } +#endif /* !UNIV_HOTBACKUP */ return(TRUE); } @@ -2811,7 +2821,11 @@ page_zip_decompress( /*================*/ page_zip_des_t* page_zip,/*!< in: data, ssize; out: m_start, m_end, m_nonempty, n_blobs */ - page_t* page) /*!< out: uncompressed page, may be trashed */ + page_t* page, /*!< out: uncompressed page, may be trashed */ + ibool all) /*!< in: TRUE=decompress the whole page; + FALSE=verify but do not copy some + page header fields that should not change + after page creation */ { z_stream d_stream; dict_index_t* index = NULL; @@ -2820,7 +2834,9 @@ page_zip_decompress( ulint trx_id_col = ULINT_UNDEFINED; mem_heap_t* heap; ulint* offsets; +#ifndef UNIV_HOTBACKUP ullint usec = ut_time_us(NULL); +#endif /* !UNIV_HOTBACKUP */ ut_ad(page_zip_simple_validate(page_zip)); UNIV_MEM_ASSERT_W(page, UNIV_PAGE_SIZE); @@ -2839,13 +2855,36 @@ page_zip_decompress( heap = mem_heap_create(n_dense * (3 * sizeof *recs) + UNIV_PAGE_SIZE); recs = mem_heap_alloc(heap, n_dense * (2 * sizeof *recs)); + if (all) { + /* Copy the page header. */ + memcpy(page, page_zip->data, PAGE_DATA); + } else { + /* Check that the bytes that we skip are identical. */ +#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG + ut_a(!memcmp(FIL_PAGE_TYPE + page, + FIL_PAGE_TYPE + page_zip->data, + PAGE_HEADER - FIL_PAGE_TYPE)); + ut_a(!memcmp(PAGE_HEADER + PAGE_LEVEL + page, + PAGE_HEADER + PAGE_LEVEL + page_zip->data, + PAGE_DATA - (PAGE_HEADER + PAGE_LEVEL))); +#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */ + + /* Copy the mutable parts of the page header. */ + memcpy(page, page_zip->data, FIL_PAGE_TYPE); + memcpy(PAGE_HEADER + page, PAGE_HEADER + page_zip->data, + PAGE_LEVEL - PAGE_N_DIR_SLOTS); + +#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG + /* Check that the page headers match after copying. */ + ut_a(!memcmp(page, page_zip->data, PAGE_DATA)); +#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */ + } + #ifdef UNIV_ZIP_DEBUG - /* Clear the page. */ - memset(page, 0x55, UNIV_PAGE_SIZE); + /* Clear the uncompressed page, except the header. */ + memset(PAGE_DATA + page, 0x55, UNIV_PAGE_SIZE - PAGE_DATA); #endif /* UNIV_ZIP_DEBUG */ - UNIV_MEM_INVALID(page, UNIV_PAGE_SIZE); - /* Copy the page header. */ - memcpy(page, page_zip->data, PAGE_DATA); + UNIV_MEM_INVALID(PAGE_DATA + page, UNIV_PAGE_SIZE - PAGE_DATA); /* Copy the page directory. */ if (UNIV_UNLIKELY(!page_zip_dir_decode(page_zip, page, recs, @@ -2976,12 +3015,14 @@ err_exit: page_zip_fields_free(index); mem_heap_free(heap); +#ifndef UNIV_HOTBACKUP { page_zip_stat_t* zip_stat = &page_zip_stat[page_zip->ssize - 1]; zip_stat->decompressed++; zip_stat->decompressed_usec += ut_time_us(NULL) - usec; } +#endif /* !UNIV_HOTBACKUP */ /* Update the stat counter for LRU policy. */ buf_LRU_stat_inc_unzip(); @@ -3084,7 +3125,7 @@ page_zip_validate_low( #endif /* UNIV_DEBUG_VALGRIND */ temp_page_zip = *page_zip; - valid = page_zip_decompress(&temp_page_zip, temp_page); + valid = page_zip_decompress(&temp_page_zip, temp_page, TRUE); if (!valid) { fputs("page_zip_validate(): failed to decompress\n", stderr); goto func_exit; @@ -4362,8 +4403,8 @@ IMPORTANT: if page_zip_reorganize() is invoked on a leaf page of a non-clustered index, the caller must update the insert buffer free bits in the same mini-transaction in such a way that the modification will be redo-logged. -@return TRUE on success, FALSE on failure; page and page_zip will be -left intact on failure. */ +@return TRUE on success, FALSE on failure; page_zip will be left +intact on failure, but page will be overwritten. */ UNIV_INTERN ibool page_zip_reorganize( @@ -4428,9 +4469,6 @@ page_zip_reorganize( if (UNIV_UNLIKELY(!page_zip_compress(page_zip, page, index, mtr))) { - /* Restore the old page and exit. */ - buf_frame_copy(page, temp_page); - #ifndef UNIV_HOTBACKUP buf_block_free(temp_block); #endif /* !UNIV_HOTBACKUP */ @@ -4591,7 +4629,8 @@ corrupt: memcpy(page_zip->data + page_zip_get_size(page_zip) - trailer_size, ptr + 8 + size, trailer_size); - if (UNIV_UNLIKELY(!page_zip_decompress(page_zip, page))) { + if (UNIV_UNLIKELY(!page_zip_decompress(page_zip, page, + TRUE))) { goto corrupt; } diff --git a/storage/innobase/plug.in b/storage/innobase/plug.in index af5ee336efe..09a95ecc157 100644 --- a/storage/innobase/plug.in +++ b/storage/innobase/plug.in @@ -14,7 +14,7 @@ # Place, Suite 330, Boston, MA 02111-1307 USA # -MYSQL_STORAGE_ENGINE(innobase, innodb, [InnoDB Storage Engine], +MYSQL_STORAGE_ENGINE(innobase, innodb, [InnoDB Storage Engine], [Transactional Tables using InnoDB], [max,max-no-ndb]) MYSQL_PLUGIN_DIRECTORY(innobase, [storage/innobase]) MYSQL_PLUGIN_STATIC(innobase, [libinnobase.a]) @@ -38,33 +38,75 @@ MYSQL_PLUGIN_ACTIONS(innobase, [ irix*|osf*|sysv5uw7*|openbsd*) CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";; *solaris*|*SunOS*) - # Begin Solaris atomic function checks - AC_CHECK_FUNCS(atomic_cas_ulong atomic_cas_32 \ - atomic_cas_64 atomic_add_long, - AC_DEFINE( - [HAVE_SOLARIS_ATOMICS], - [1], - [Define to 1 if Solaris supports \ - atomic functions.])) - ### End Solaris atomic function checks - CFLAGS="$CFLAGS -DUNIV_SOLARIS";; esac + INNODB_DYNAMIC_CFLAGS="-DMYSQL_DYNAMIC_PLUGIN" - case "$target_cpu---$target_os" in - x86_64---*) + + case "$target_cpu" in + x86_64) # The AMD64 ABI forbids absolute addresses in shared libraries ;; - *---solaris*|*---SunOS*) - # Shared objects must be linked from PIC code on Solaris. - ;; - *86---) + *86) # Use absolute addresses on IA-32 INNODB_DYNAMIC_CFLAGS="$INNODB_DYNAMIC_CFLAGS -prefer-non-pic" ;; esac AC_SUBST(INNODB_DYNAMIC_CFLAGS) + + AC_MSG_CHECKING(whether GCC atomic builtins are available) + # either define HAVE_IB_GCC_ATOMIC_BUILTINS or not + AC_TRY_RUN( + [ + int main() + { + long x; + long y; + long res; + char c; + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x, y); + if (!res || x != y) { + return(1); + } + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x + 1, y); + if (res || x != 10) { + return(1); + } + + x = 10; + y = 123; + res = __sync_add_and_fetch(&x, y); + if (res != 123 + 10 || x != 123 + 10) { + return(1); + } + + c = 10; + res = __sync_lock_test_and_set(&c, 123); + if (res != 10 || c != 123) { + return(1); + } + + return(0); + } + ], + [ + AC_DEFINE([HAVE_IB_GCC_ATOMIC_BUILTINS], [1], + [GCC atomic builtins are available]) + AC_MSG_RESULT(yes) + ], + [ + AC_MSG_RESULT(no) + ] + ) + AC_MSG_CHECKING(whether pthread_t can be used by GCC atomic builtins) + # either define HAVE_IB_ATOMIC_PTHREAD_T_GCC or not AC_TRY_RUN( [ #include @@ -85,47 +127,73 @@ MYSQL_PLUGIN_ACTIONS(innobase, [ } ], [ - AC_DEFINE([HAVE_ATOMIC_PTHREAD_T], [1], + AC_DEFINE([HAVE_IB_ATOMIC_PTHREAD_T_GCC], [1], [pthread_t can be used by GCC atomic builtins]) AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) ] - ) + ) - # Try using solaris atomics on SunOS if GCC atomics are not available - AC_CHECK_DECLS( - [HAVE_ATOMIC_PTHREAD_T], + AC_MSG_CHECKING(whether Solaris libc atomic functions are available) + # either define HAVE_IB_SOLARIS_ATOMICS or not + AC_CHECK_FUNCS(atomic_add_long \ + atomic_cas_32 \ + atomic_cas_64 \ + atomic_cas_ulong, + + AC_DEFINE([HAVE_IB_SOLARIS_ATOMICS], [1], + [Define to 1 if Solaris libc atomic functions \ + are available]) + ) + + AC_MSG_CHECKING(whether pthread_t can be used by Solaris libc atomic functions) + # either define HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS or not + AC_TRY_RUN( [ - AC_MSG_NOTICE(no need to check pthread_t size) + #include + #include + + int main(int argc, char** argv) { + pthread_t x1; + pthread_t x2; + pthread_t x3; + + memset(&x1, 0x0, sizeof(x1)); + memset(&x2, 0x0, sizeof(x2)); + memset(&x3, 0x0, sizeof(x3)); + + if (sizeof(pthread_t) == 4) { + + atomic_cas_32(&x1, x2, x3); + + } else if (sizeof(pthread_t) == 8) { + + atomic_cas_64(&x1, x2, x3); + + } else { + + return(1); + } + + return(0); + } ], [ - AC_CHECK_DECLS( - [HAVE_SOLARIS_ATOMICS], - [ - AC_MSG_CHECKING(checking if pthread_t size is integral) - AC_TRY_RUN( - [ - #include - int main() - { - pthread_t x = 0; - return(0); - } - ], - [ - AC_DEFINE([HAVE_ATOMIC_PTHREAD_T], [1], + AC_DEFINE([HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS], [1], [pthread_t can be used by solaris atomics]) - AC_MSG_RESULT(yes) - # size of pthread_t is needed for typed solaris atomics - AC_CHECK_SIZEOF([pthread_t], [], [#include ]) - ], - [ - AC_MSG_RESULT(no) - ]) - ]) - ]) + AC_MSG_RESULT(yes) + ], + [ + AC_MSG_RESULT(no) + ] + ) + + # this is needed to know which one of atomic_cas_32() or atomic_cas_64() + # to use in the source + AC_CHECK_SIZEOF([pthread_t], [], [#include ]) + # Check for x86 PAUSE instruction AC_MSG_CHECKING(for x86 PAUSE instruction) # We have to actually try running the test program, because of a bug @@ -142,7 +210,7 @@ MYSQL_PLUGIN_ACTIONS(innobase, [ } ], [ - AC_DEFINE([IB_HAVE_PAUSE_INSTRUCTION], [1], [Does x86 PAUSE instruction exist]) + AC_DEFINE([HAVE_IB_PAUSE_INSTRUCTION], [1], [Does x86 PAUSE instruction exist]) AC_MSG_RESULT(yes) ], [ diff --git a/storage/innobase/rem/rem0cmp.c b/storage/innobase/rem/rem0cmp.c index b707f2116d6..e6dab0bc66b 100644 --- a/storage/innobase/rem/rem0cmp.c +++ b/storage/innobase/rem/rem0cmp.c @@ -36,7 +36,7 @@ Created 7/1/1994 Heikki Tuuri The records are put into alphabetical order in the following way: let F be the first field where two records disagree. -If there is a character in some position n where the the +If there is a character in some position n where the records disagree, the order is determined by comparison of the characters at position n, possibly after collating transformation. If there is no such character, @@ -76,7 +76,7 @@ cmp_debug_dtuple_rec_with_match( /*************************************************************//** This function is used to compare two data fields for which the data type is such that we must use MySQL code to compare them. The prototype here -must be a copy of the the one in ha_innobase.cc! +must be a copy of the one in ha_innobase.cc! @return 1, 0, -1, if a is greater, equal, less than b, respectively */ extern int @@ -399,7 +399,7 @@ next_byte: /*************************************************************//** This function is used to compare a data tuple to a physical record. Only dtuple->n_fields_cmp first fields are taken into account for -the the data tuple! If we denote by n = n_fields_cmp, then rec must +the data tuple! If we denote by n = n_fields_cmp, then rec must have either m >= n fields, or it must differ from dtuple in some of the m fields rec has. If rec has an externally stored field we do not compare it but return with value 0 if such a comparison should be diff --git a/storage/innobase/revert_gen.sh b/storage/innobase/revert_gen.sh new file mode 100755 index 00000000000..231e05a21e0 --- /dev/null +++ b/storage/innobase/revert_gen.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# +# revert changes to all generated files. this is useful in some situations +# when merging changes between branches. + +set -eu + +svn revert include/pars0grm.h pars/pars0grm.h pars/lexyy.c pars/pars0grm.c diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index 930c9ec1fc7..ab3ae70e3e2 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -1191,7 +1191,7 @@ row_ins_check_foreign_constraint( /*=============================*/ ibool check_ref,/*!< in: TRUE if we want to check that the referenced table is ok, FALSE if we - want to to check the foreign key table */ + want to check the foreign key table */ dict_foreign_t* foreign,/*!< in: foreign constraint; NOTE that the tables mentioned in it must be in the dictionary cache if they exist at all */ diff --git a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c index 05a45dc647c..a303a2f3278 100644 --- a/storage/innobase/row/row0merge.c +++ b/storage/innobase/row/row0merge.c @@ -60,9 +60,19 @@ Completed by Sunny Bains and Marko Makela #ifdef UNIV_DEBUG /** Set these in order ot enable debug printout. */ /* @{ */ +/** Log the outcome of each row_merge_cmp() call, comparing records. */ static ibool row_merge_print_cmp; +/** Log each record read from temporary file. */ static ibool row_merge_print_read; +/** Log each record write to temporary file. */ static ibool row_merge_print_write; +/** Log each row_merge_blocks() call, merging two blocks of records to +a bigger one. */ +static ibool row_merge_print_block; +/** Log each block read from temporary file. */ +static ibool row_merge_print_block_read; +/** Log each block read from temporary file. */ +static ibool row_merge_print_block_write; /* @} */ #endif /* UNIV_DEBUG */ @@ -109,8 +119,9 @@ typedef struct row_merge_buf_struct row_merge_buf_t; /** Information about temporary files used in merge sort */ struct merge_file_struct { - int fd; /*!< file descriptor */ - ulint offset; /*!< file offset */ + int fd; /*!< file descriptor */ + ulint offset; /*!< file offset (end of file) */ + ib_uint64_t n_rec; /*!< number of records in the file */ }; /** Information about temporary files used in merge sort */ @@ -682,6 +693,13 @@ row_merge_read( ib_uint64_t ofs = ((ib_uint64_t) offset) * sizeof *buf; ibool success; +#ifdef UNIV_DEBUG + if (row_merge_print_block_read) { + fprintf(stderr, "row_merge_read fd=%d ofs=%lu\n", + fd, (ulong) offset); + } +#endif /* UNIV_DEBUG */ + success = os_file_read_no_error_handling(OS_FILE_FROM_FD(fd), buf, (ulint) (ofs & 0xFFFFFFFF), (ulint) (ofs >> 32), @@ -709,6 +727,13 @@ row_merge_write( ib_uint64_t ofs = ((ib_uint64_t) offset) * sizeof(row_merge_block_t); +#ifdef UNIV_DEBUG + if (row_merge_print_block_write) { + fprintf(stderr, "row_merge_write fd=%d ofs=%lu\n", + fd, (ulong) offset); + } +#endif /* UNIV_DEBUG */ + return(UNIV_LIKELY(os_file_write("(merge)", OS_FILE_FROM_FD(fd), buf, (ulint) (ofs & 0xFFFFFFFF), (ulint) (ofs >> 32), @@ -718,7 +743,7 @@ row_merge_write( /********************************************************************//** Read a merge record. @return pointer to next record, or NULL on I/O error or end of list */ -static +static __attribute__((nonnull)) const byte* row_merge_read_rec( /*===============*/ @@ -1070,7 +1095,7 @@ row_merge_cmp( Reads clustered index of the table and create temporary files containing the index entries for the indexes to be built. @return DB_SUCCESS or error */ -static +static __attribute__((nonnull)) ulint row_merge_read_clustered_index( /*===========================*/ @@ -1233,6 +1258,7 @@ row_merge_read_clustered_index( if (UNIV_LIKELY (row && row_merge_buf_add(buf, row, ext))) { + file->n_rec++; continue; } @@ -1274,14 +1300,19 @@ err_exit: UNIV_MEM_INVALID(block[0], sizeof block[0]); merge_buf[i] = row_merge_buf_empty(buf); - /* Try writing the record again, now that - the buffer has been written out and emptied. */ + if (UNIV_LIKELY(row != NULL)) { + /* Try writing the record again, now + that the buffer has been written out + and emptied. */ - if (UNIV_UNLIKELY - (row && !row_merge_buf_add(buf, row, ext))) { - /* An empty buffer should have enough - room for at least one record. */ - ut_error; + if (UNIV_UNLIKELY + (!row_merge_buf_add(buf, row, ext))) { + /* An empty buffer should have enough + room for at least one record. */ + ut_error; + } + + file->n_rec++; } } @@ -1320,7 +1351,7 @@ func_exit: b2 = row_merge_write_rec(&block[2], &buf[2], b2, \ of->fd, &of->offset, \ mrec##N, offsets##N); \ - if (UNIV_UNLIKELY(!b2)) { \ + if (UNIV_UNLIKELY(!b2 || ++of->n_rec > file->n_rec)) { \ goto corrupt; \ } \ b##N = row_merge_read_rec(&block[N], &buf[N], \ @@ -1336,14 +1367,14 @@ func_exit: } while (0) /*************************************************************//** -Merge two blocks of linked lists on disk and write a bigger block. +Merge two blocks of records on disk and write a bigger block. @return DB_SUCCESS or error code */ static ulint row_merge_blocks( /*=============*/ const dict_index_t* index, /*!< in: index being created */ - merge_file_t* file, /*!< in/out: file containing + const merge_file_t* file, /*!< in: file containing index entries */ row_merge_block_t* block, /*!< in/out: 3 buffers */ ulint* foffs0, /*!< in/out: offset of first @@ -1366,6 +1397,17 @@ row_merge_blocks( ulint* offsets0;/* offsets of mrec0 */ ulint* offsets1;/* offsets of mrec1 */ +#ifdef UNIV_DEBUG + if (row_merge_print_block) { + fprintf(stderr, + "row_merge_blocks fd=%d ofs=%lu + fd=%d ofs=%lu" + " = fd=%d ofs=%lu\n", + file->fd, (ulong) *foffs0, + file->fd, (ulong) *foffs1, + of->fd, (ulong) of->offset); + } +#endif /* UNIV_DEBUG */ + heap = row_merge_heap_create(index, &offsets0, &offsets1); /* Write a record and read the next record. Split the output @@ -1437,17 +1479,88 @@ done1: return(b2 ? DB_SUCCESS : DB_CORRUPTION); } +/*************************************************************//** +Copy a block of index entries. +@return TRUE on success, FALSE on failure */ +static __attribute__((nonnull)) +ibool +row_merge_blocks_copy( +/*==================*/ + const dict_index_t* index, /*!< in: index being created */ + const merge_file_t* file, /*!< in: input file */ + row_merge_block_t* block, /*!< in/out: 3 buffers */ + ulint* foffs0, /*!< in/out: input file offset */ + merge_file_t* of) /*!< in/out: output file */ +{ + mem_heap_t* heap; /*!< memory heap for offsets0, offsets1 */ + + mrec_buf_t buf[3]; /*!< buffer for handling + split mrec in block[] */ + const byte* b0; /*!< pointer to block[0] */ + byte* b2; /*!< pointer to block[2] */ + const mrec_t* mrec0; /*!< merge rec, points to block[0] */ + ulint* offsets0;/* offsets of mrec0 */ + ulint* offsets1;/* dummy offsets */ + +#ifdef UNIV_DEBUG + if (row_merge_print_block) { + fprintf(stderr, + "row_merge_blocks_copy fd=%d ofs=%lu" + " = fd=%d ofs=%lu\n", + file->fd, (ulong) foffs0, + of->fd, (ulong) of->offset); + } +#endif /* UNIV_DEBUG */ + + heap = row_merge_heap_create(index, &offsets0, &offsets1); + + /* Write a record and read the next record. Split the output + file in two halves, which can be merged on the following pass. */ + + if (!row_merge_read(file->fd, *foffs0, &block[0])) { +corrupt: + mem_heap_free(heap); + return(FALSE); + } + + b0 = block[0]; + b2 = block[2]; + + b0 = row_merge_read_rec(&block[0], &buf[0], b0, index, file->fd, + foffs0, &mrec0, offsets0); + if (UNIV_UNLIKELY(!b0 && mrec0)) { + + goto corrupt; + } + + if (mrec0) { + /* append all mrec0 to output */ + for (;;) { + ROW_MERGE_WRITE_GET_NEXT(0, goto done0); + } + } +done0: + + /* The file offset points to the beginning of the last page + that has been read. Update it to point to the next block. */ + (*foffs0)++; + + mem_heap_free(heap); + return(row_merge_write_eof(&block[2], b2, of->fd, &of->offset) + != NULL); +} + /*************************************************************//** Merge disk files. @return DB_SUCCESS or error code */ -static +static __attribute__((nonnull)) ulint row_merge( /*======*/ const dict_index_t* index, /*!< in: index being created */ merge_file_t* file, /*!< in/out: file containing index entries */ - ulint half, /*!< in: half the file */ + ulint* half, /*!< in/out: half the file */ row_merge_block_t* block, /*!< in/out: 3 buffers */ int* tmpfd, /*!< in/out: temporary file handle */ TABLE* table) /*!< in/out: MySQL table, for @@ -1458,43 +1571,75 @@ row_merge( ulint foffs1; /*!< second input offset */ ulint error; /*!< error code */ merge_file_t of; /*!< output file */ + const ulint ihalf = *half; + /*!< half the input file */ + ulint ohalf; /*!< half the output file */ UNIV_MEM_ASSERT_W(block[0], 3 * sizeof block[0]); - ut_ad(half > 0); + ut_ad(ihalf < file->offset); of.fd = *tmpfd; of.offset = 0; + of.n_rec = 0; /* Merge blocks to the output file. */ + ohalf = 0; foffs0 = 0; - foffs1 = half; + foffs1 = ihalf; + + for (; foffs0 < ihalf && foffs1 < file->offset; foffs0++, foffs1++) { + ulint ahalf; /*!< arithmetic half the input file */ - for (; foffs0 < half && foffs1 < file->offset; foffs0++, foffs1++) { error = row_merge_blocks(index, file, block, &foffs0, &foffs1, &of, table); if (error != DB_SUCCESS) { return(error); } + + /* Record the offset of the output file when + approximately half the output has been generated. In + this way, the next invocation of row_merge() will + spend most of the time in this loop. The initial + estimate is ohalf==0. */ + ahalf = file->offset / 2; + ut_ad(ohalf <= of.offset); + + /* Improve the estimate until reaching half the input + file size, or we can not get any closer to it. All + comparands should be non-negative when !(ohalf < ahalf) + because ohalf <= of.offset. */ + if (ohalf < ahalf || of.offset - ahalf < ohalf - ahalf) { + ohalf = of.offset; + } } - /* Copy the last block, if there is one. */ - while (foffs0 < half) { - if (!row_merge_read(file->fd, foffs0++, block) - || !row_merge_write(of.fd, of.offset++, block)) { + /* Copy the last blocks, if there are any. */ + + while (foffs0 < ihalf) { + if (!row_merge_blocks_copy(index, file, block, &foffs0, &of)) { return(DB_CORRUPTION); } } + + ut_ad(foffs0 == ihalf); + while (foffs1 < file->offset) { - if (!row_merge_read(file->fd, foffs1++, block) - || !row_merge_write(of.fd, of.offset++, block)) { + if (!row_merge_blocks_copy(index, file, block, &foffs1, &of)) { return(DB_CORRUPTION); } } + ut_ad(foffs1 == file->offset); + + if (UNIV_UNLIKELY(of.n_rec != file->n_rec)) { + return(DB_CORRUPTION); + } + /* Swap file descriptors for the next pass. */ *tmpfd = file->fd; *file = of; + *half = ohalf; UNIV_MEM_INVALID(block[0], 3 * sizeof block[0]); @@ -1517,20 +1662,25 @@ row_merge_sort( reporting erroneous key value if applicable */ { - ulint blksz; /*!< block size */ + ulint half = file->offset / 2; - for (blksz = 1; blksz < file->offset; blksz *= 2) { - ulint half; + /* The file should always contain at least one byte (the end + of file marker). Thus, it must be at least one block. */ + ut_ad(file->offset > 0); + + do { ulint error; - ut_ad(ut_is_2pow(blksz)); - half = ut_2pow_round((file->offset + (blksz - 1)) / 2, blksz); - error = row_merge(index, file, half, block, tmpfd, table); + error = row_merge(index, file, &half, block, tmpfd, table); if (error != DB_SUCCESS) { return(error); } - } + + /* half > 0 should hold except when the file consists + of one block. No need to merge further then. */ + ut_ad(half > 0 || file->offset == 1); + } while (half < file->offset && half > 0); return(DB_SUCCESS); } @@ -1797,7 +1947,15 @@ row_merge_drop_index( static const char str1[] = "PROCEDURE DROP_INDEX_PROC () IS\n" "BEGIN\n" + /* Rename the index, so that it will be dropped by + row_merge_drop_temp_indexes() at crash recovery + if the server crashes before this trx is committed. */ + "UPDATE SYS_INDEXES SET NAME=CONCAT('" + TEMP_INDEX_PREFIX_STR "', NAME) WHERE ID = :indexid;\n" + "COMMIT WORK;\n" + /* Drop the field definitions of the index. */ "DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n" + /* Drop the index definition and the B-tree. */ "DELETE FROM SYS_INDEXES WHERE ID = :indexid\n" " AND TABLE_ID = :tableid;\n" "END;\n"; @@ -1909,6 +2067,7 @@ row_merge_file_create( { merge_file->fd = innobase_mysql_tmpfile(); merge_file->offset = 0; + merge_file->n_rec = 0; } /*********************************************************************//** @@ -2129,7 +2288,7 @@ row_merge_rename_tables( if (err != DB_SUCCESS) { err_exit: trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; } diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index b345bb59624..819381fc280 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -510,7 +510,7 @@ handle_new_error: switch (err) { case DB_LOCK_WAIT_TIMEOUT: if (row_rollback_on_timeout) { - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); break; } /* fall through */ @@ -526,7 +526,7 @@ handle_new_error: /* Roll back the latest, possibly incomplete insertion or update */ - trx_general_rollback_for_mysql(trx, TRUE, savept); + trx_general_rollback_for_mysql(trx, savept); } /* MySQL will roll back the latest SQL statement */ break; @@ -548,7 +548,7 @@ handle_new_error: /* Roll back the whole transaction; this resolution was added to version 3.23.43 */ - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); break; case DB_MUST_GET_MORE_FILE_SPACE: @@ -866,18 +866,22 @@ row_update_statistics_if_needed( } /*********************************************************************//** -Unlocks AUTO_INC type locks that were possibly reserved by a trx. */ +Unlocks AUTO_INC type locks that were possibly reserved by a trx. This +function should be called at the the end of an SQL statement, by the +connection thread that owns the transaction (trx->mysql_thd). */ UNIV_INTERN void row_unlock_table_autoinc_for_mysql( /*===============================*/ trx_t* trx) /*!< in/out: transaction */ { - mutex_enter(&kernel_mutex); + if (lock_trx_holds_autoinc_locks(trx)) { + mutex_enter(&kernel_mutex); - lock_release_autoinc_locks(trx); + lock_release_autoinc_locks(trx); - mutex_exit(&kernel_mutex); + mutex_exit(&kernel_mutex); + } } /*********************************************************************//** @@ -1767,7 +1771,6 @@ row_create_table_for_mysql( const char* table_name; ulint table_name_len; ulint err; - ulint i; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); #ifdef UNIV_SYNC_DEBUG @@ -1802,15 +1805,6 @@ err_exit: goto err_exit; } - /* Check that no reserved column names are used. */ - for (i = 0; i < dict_table_get_n_user_cols(table); i++) { - if (dict_col_name_is_reserved( - dict_table_get_col_name(table, i))) { - - goto err_exit; - } - } - trx_start_if_not_started(trx); /* The table name is prefixed with the database name and a '/'. @@ -1885,7 +1879,7 @@ err_exit: if (UNIV_UNLIKELY(err != DB_SUCCESS)) { trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); } switch (err) { @@ -2053,7 +2047,7 @@ error_handling: trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); row_drop_table_for_mysql(table_name, trx, FALSE); @@ -2121,7 +2115,7 @@ row_table_add_foreign_constraints( trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); row_drop_table_for_mysql(name, trx, FALSE); @@ -2488,7 +2482,7 @@ row_discard_tablespace_for_mysql( if (err != DB_SUCCESS) { trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; } else { dict_table_change_id_in_cache(table, new_id); @@ -2497,7 +2491,7 @@ row_discard_tablespace_for_mysql( if (!success) { trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; err = DB_ERROR; @@ -2949,7 +2943,7 @@ next_rec: if (err != DB_SUCCESS) { trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; ut_print_timestamp(stderr); fputs(" InnoDB: Unable to assign a new identifier to table ", @@ -3590,7 +3584,7 @@ row_delete_constraint( if ((err == DB_SUCCESS) && !strchr(id, '/')) { /* Old format < 4.0.18 constraints have constraint ids - _. We only try deleting them if the + NUMBER_NUMBER. We only try deleting them if the constraint name does not contain a '/' character, otherwise deleting a new format constraint named 'foo/bar' from database 'baz' would remove constraint 'bar' from database @@ -3854,7 +3848,7 @@ end: "InnoDB: succeed.\n", stderr); } trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; } else { /* The following call will also rename the .ibd data file if @@ -3863,7 +3857,7 @@ end: if (!dict_table_rename_in_cache(table, new_name, !new_is_tmp)) { trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; goto funct_exit; } @@ -3903,7 +3897,7 @@ end: ut_a(dict_table_rename_in_cache(table, old_name, FALSE)); trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; } } diff --git a/storage/innobase/scripts/export.sh b/storage/innobase/scripts/export.sh new file mode 100755 index 00000000000..2a4355c1e43 --- /dev/null +++ b/storage/innobase/scripts/export.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# +# export current working directory in a format suitable for sending to MySQL +# as a snapshot. also generates the actual snapshot and sends it to MySQL. + +set -eu + +die () { + echo $* + exit 1 +} + +if [ $# -ne 2 ] ; then + die "Usage: export.sh revision-number-of-last-snapshot current-revision-number" +fi + +# If we are run from within the scripts/ directory then change directory to +# one level up so that the relative paths work. +DIR=`basename $PWD` + +if [ "${DIR}" = "scripts" ]; then + cd .. +fi + +START_REV=$(($1 + 1)) +END_REV=$2 + +set +u +if test -z $EDITOR; then + die "\$EDITOR is not set" +fi +set -u + +rm -rf to-mysql +mkdir to-mysql{,/storage,/patches,/mysql-test{,/t,/r,/include}} +svn log -v -r "$START_REV:BASE" > to-mysql/log +svn export -q . to-mysql/storage/innobase + +REV=$START_REV +while [ $REV -le $END_REV ] +do + PATCH=to-mysql/patches/r$REV.patch + svn log -v -r$REV > $PATCH + if [ $(wc -c < $PATCH) -gt 73 ] + then + svn diff -r$(($REV-1)):$REV >> $PATCH + else + rm $PATCH + fi + REV=$(($REV + 1)) +done + +cd to-mysql/storage/innobase + +mv mysql-test/*.test mysql-test/*.opt ../../mysql-test/t +mv mysql-test/*.result ../../mysql-test/r +mv mysql-test/*.inc ../../mysql-test/include +rmdir mysql-test + +rm setup.sh export.sh revert_gen.sh compile-innodb-debug compile-innodb + +cd ../.. +$EDITOR log +cd .. + +fname="innodb-5.1-ss$2.tar.gz" + +rm -f $fname +tar czf $fname to-mysql +scp $fname mysql:snapshots +rm $fname +rm -rf to-mysql + +echo "Sent $fname to MySQL" diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c index 79fa08e7cdf..d638b23692e 100644 --- a/storage/innobase/srv/srv0srv.c +++ b/storage/innobase/srv/srv0srv.c @@ -102,6 +102,7 @@ Created 10/8/1995 Heikki Tuuri #include "row0mysql.h" #include "ha_prototypes.h" #include "trx0i_s.h" +#include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ /* This is set to TRUE if the MySQL user has set it in MySQL; currently affects only FOREIGN KEY definition parsing */ @@ -292,12 +293,6 @@ UNIV_INTERN ulint srv_buf_pool_flushed = 0; reading of a disk page */ UNIV_INTERN ulint srv_buf_pool_reads = 0; -/** Number of sequential read-aheads */ -UNIV_INTERN ulint srv_read_ahead_seq = 0; - -/** Number of random read-aheads */ -UNIV_INTERN ulint srv_read_ahead_rnd = 0; - /* structure to pass status variables to MySQL */ UNIV_INTERN export_struc export_vars; @@ -464,8 +459,6 @@ static ulint srv_main_background_loops = 0; static ulint srv_main_flush_loops = 0; /* Log writes involving flush. */ static ulint srv_log_writes_and_flush = 0; -/* Log writes not including flush. */ -static ulint srv_log_buffer_writes = 0; /* This is only ever touched by the master thread. It records the time when the last flush of log file has happened. The master @@ -614,7 +607,7 @@ future, but at the moment we plan to implement a more coarse solution, which could be called a global priority inheritance. If a thread has to wait for a long time, say 300 milliseconds, for a resource, we just guess that it may be waiting for a resource owned by a background -thread, and boost the the priority of all runnable background threads +thread, and boost the priority of all runnable background threads to the normal level. The background threads then themselves adjust their fixed priority back to background after releasing all resources they had (or, at some fixed points in their program code). @@ -714,9 +707,8 @@ srv_print_master_thread_info( srv_main_1_second_loops, srv_main_sleeps, srv_main_10_second_loops, srv_main_background_loops, srv_main_flush_loops); - fprintf(file, "srv_master_thread log flush and writes: %lu " - " log writes only: %lu\n", - srv_log_writes_and_flush, srv_log_buffer_writes); + fprintf(file, "srv_master_thread log flush and writes: %lu\n", + srv_log_writes_and_flush); } /*********************************************************************//** @@ -1877,14 +1869,16 @@ srv_export_innodb_status(void) export_vars.innodb_data_reads = os_n_file_reads; export_vars.innodb_data_writes = os_n_file_writes; export_vars.innodb_data_written = srv_data_written; - export_vars.innodb_buffer_pool_read_requests = buf_pool->n_page_gets; + export_vars.innodb_buffer_pool_read_requests = buf_pool->stat.n_page_gets; export_vars.innodb_buffer_pool_write_requests = srv_buf_pool_write_requests; export_vars.innodb_buffer_pool_wait_free = srv_buf_pool_wait_free; export_vars.innodb_buffer_pool_pages_flushed = srv_buf_pool_flushed; export_vars.innodb_buffer_pool_reads = srv_buf_pool_reads; - export_vars.innodb_buffer_pool_read_ahead_rnd = srv_read_ahead_rnd; - export_vars.innodb_buffer_pool_read_ahead_seq = srv_read_ahead_seq; + export_vars.innodb_buffer_pool_read_ahead + = buf_pool->stat.n_ra_pages_read; + export_vars.innodb_buffer_pool_read_ahead_evicted + = buf_pool->stat.n_ra_pages_evicted; export_vars.innodb_buffer_pool_pages_data = UT_LIST_GET_LEN(buf_pool->LRU); export_vars.innodb_buffer_pool_pages_dirty @@ -1915,9 +1909,9 @@ srv_export_innodb_status(void) export_vars.innodb_log_writes = srv_log_writes; export_vars.innodb_dblwr_pages_written = srv_dblwr_pages_written; export_vars.innodb_dblwr_writes = srv_dblwr_writes; - export_vars.innodb_pages_created = buf_pool->n_pages_created; - export_vars.innodb_pages_read = buf_pool->n_pages_read; - export_vars.innodb_pages_written = buf_pool->n_pages_written; + export_vars.innodb_pages_created = buf_pool->stat.n_pages_created; + export_vars.innodb_pages_read = buf_pool->stat.n_pages_read; + export_vars.innodb_pages_written = buf_pool->stat.n_pages_written; export_vars.innodb_row_lock_waits = srv_n_lock_wait_count; export_vars.innodb_row_lock_current_waits = srv_n_lock_wait_current_count; @@ -2284,12 +2278,6 @@ srv_sync_log_buffer_in_background(void) log_buffer_sync_in_background(TRUE); srv_last_log_flush_time = current_time; srv_log_writes_and_flush++; - } else { - /* Actually we don't need to write logs here. - We are just being extra safe here by forcing - the log buffer to log file. */ - log_buffer_sync_in_background(FALSE); - srv_log_buffer_writes++; } } @@ -2340,8 +2328,8 @@ loop: srv_main_thread_op_info = "reserving kernel mutex"; - n_ios_very_old = log_sys->n_log_ios + buf_pool->n_pages_read - + buf_pool->n_pages_written; + n_ios_very_old = log_sys->n_log_ios + buf_pool->stat.n_pages_read + + buf_pool->stat.n_pages_written; mutex_enter(&kernel_mutex); /* Store the user activity counter at the start of this loop */ @@ -2361,8 +2349,8 @@ loop: skip_sleep = FALSE; for (i = 0; i < 10; i++) { - n_ios_old = log_sys->n_log_ios + buf_pool->n_pages_read - + buf_pool->n_pages_written; + n_ios_old = log_sys->n_log_ios + buf_pool->stat.n_pages_read + + buf_pool->stat.n_pages_written; srv_main_thread_op_info = "sleeping"; srv_main_1_second_loops++; @@ -2401,8 +2389,8 @@ loop: n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes; - n_ios = log_sys->n_log_ios + buf_pool->n_pages_read - + buf_pool->n_pages_written; + n_ios = log_sys->n_log_ios + buf_pool->stat.n_pages_read + + buf_pool->stat.n_pages_written; if (n_pend_ios < SRV_PEND_IO_THRESHOLD && (n_ios - n_ios_old < SRV_RECENT_IO_ACTIVITY)) { srv_main_thread_op_info = "doing insert buffer merge"; @@ -2418,6 +2406,8 @@ loop: /* Try to keep the number of modified pages in the buffer pool under the limit wished by the user */ + srv_main_thread_op_info = + "flushing buffer pool pages"; n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, PCT_IO(100), IB_ULONGLONG_MAX); @@ -2436,6 +2426,8 @@ loop: ulint n_flush = buf_flush_get_desired_flush_rate(); if (n_flush) { + srv_main_thread_op_info = + "flushing buffer pool pages"; n_flush = ut_min(PCT_IO(100), n_flush); n_pages_flushed = buf_flush_batch( @@ -2473,8 +2465,8 @@ loop: are not required, and may be disabled. */ n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes; - n_ios = log_sys->n_log_ios + buf_pool->n_pages_read - + buf_pool->n_pages_written; + n_ios = log_sys->n_log_ios + buf_pool->stat.n_pages_read + + buf_pool->stat.n_pages_written; srv_main_10_second_loops++; if (n_pend_ios < SRV_PEND_IO_THRESHOLD diff --git a/storage/innobase/srv/srv0start.c b/storage/innobase/srv/srv0start.c index a942fd439a3..37263317126 100644 --- a/storage/innobase/srv/srv0start.c +++ b/storage/innobase/srv/srv0start.c @@ -103,6 +103,7 @@ Created 2/16/1996 Heikki Tuuri # include "row0row.h" # include "row0mysql.h" # include "btr0pcur.h" +# include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */ /** Log sequence number immediately after startup */ UNIV_INTERN ib_uint64_t srv_start_lsn; @@ -1096,6 +1097,10 @@ innobase_start_or_create_for_mysql(void) "InnoDB: !!!!!!!! UNIV_SEARCH_DEBUG switched on !!!!!!!!!\n"); #endif +#ifdef UNIV_LOG_LSN_DEBUG + fprintf(stderr, + "InnoDB: !!!!!!!! UNIV_LOG_LSN_DEBUG switched on !!!!!!!!!\n"); +#endif /* UNIV_LOG_LSN_DEBUG */ #ifdef UNIV_MEM_DEBUG fprintf(stderr, "InnoDB: !!!!!!!! UNIV_MEM_DEBUG switched on !!!!!!!!!\n"); @@ -1106,34 +1111,7 @@ innobase_start_or_create_for_mysql(void) "InnoDB: The InnoDB memory heap is disabled\n"); } -#ifdef HAVE_GCC_ATOMIC_BUILTINS -# ifdef INNODB_RW_LOCKS_USE_ATOMICS - fprintf(stderr, - "InnoDB: Mutexes and rw_locks use GCC atomic builtins.\n"); -# else /* INNODB_RW_LOCKS_USE_ATOMICS */ - fprintf(stderr, - "InnoDB: Mutexes use GCC atomic builtins, rw_locks do not.\n"); -# endif /* INNODB_RW_LOCKS_USE_ATOMICS */ -#elif defined(HAVE_SOLARIS_ATOMICS) -# ifdef INNODB_RW_LOCKS_USE_ATOMICS - fprintf(stderr, - "InnoDB: Mutexes and rw_locks use Solaris atomic functions.\n"); -# else - fprintf(stderr, - "InnoDB: Mutexes use Solaris atomic functions.\n"); -# endif /* INNODB_RW_LOCKS_USE_ATOMICS */ -#elif HAVE_WINDOWS_ATOMICS -# ifdef INNODB_RW_LOCKS_USE_ATOMICS - fprintf(stderr, - "InnoDB: Mutexes and rw_locks use Windows interlocked functions.\n"); -# else - fprintf(stderr, - "InnoDB: Mutexes use Windows interlocked functions.\n"); -# endif /* INNODB_RW_LOCKS_USE_ATOMICS */ -#else /* HAVE_GCC_ATOMIC_BUILTINS */ - fprintf(stderr, - "InnoDB: Neither mutexes nor rw_locks use GCC atomic builtins.\n"); -#endif /* HAVE_GCC_ATOMIC_BUILTINS */ + fprintf(stderr, "InnoDB: %s\n", IB_ATOMICS_STARTUP_MSG); /* Since InnoDB does not currently clean up all its internal data structures in MySQL Embedded Server Library server_end(), we @@ -1829,7 +1807,7 @@ innobase_start_or_create_for_mysql(void) /* Actually, we did not change the undo log format between 4.0 and 4.1.1, and we would not need to run purge to completion. Note also that the purge algorithm in 4.1.1 - can process the the history list again even after a full + can process the history list again even after a full purge, because our algorithm does not cut the end of the history list in all cases so that it would become empty after a full purge. That mean that we may purge 4.0 type diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index 0ed114e330c..d231b6acdf7 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -38,6 +38,7 @@ Created 9/11/1995 Heikki Tuuri #include "os0thread.h" #include "mem0mem.h" #include "srv0srv.h" +#include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */ /* IMPLEMENTATION OF THE RW_LOCK diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index 84ed08e14e7..5ad143075a7 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -39,6 +39,7 @@ Created 9/5/1995 Heikki Tuuri #include "buf0buf.h" #include "srv0srv.h" #include "buf0types.h" +#include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ /* REASONS FOR IMPLEMENTING THE SPIN LOCK MUTEX @@ -849,7 +850,8 @@ sync_thread_levels_g( /*=================*/ sync_level_t* arr, /*!< in: pointer to level array for an OS thread */ - ulint limit) /*!< in: level limit */ + ulint limit, /*!< in: level limit */ + ulint warn) /*!< in: TRUE=display a diagnostic message */ { sync_level_t* slot; rw_lock_t* lock; @@ -863,6 +865,11 @@ sync_thread_levels_g( if (slot->latch != NULL) { if (slot->level <= limit) { + if (!warn) { + + return(FALSE); + } + lock = slot->latch; mutex = slot->latch; @@ -1100,7 +1107,7 @@ sync_thread_add_level( case SYNC_DICT_HEADER: case SYNC_TRX_I_S_RWLOCK: case SYNC_TRX_I_S_LAST_READ: - if (!sync_thread_levels_g(array, level)) { + if (!sync_thread_levels_g(array, level, TRUE)) { fprintf(stderr, "InnoDB: sync_thread_levels_g(array, %lu)" " does not hold!\n", level); @@ -1111,36 +1118,44 @@ sync_thread_add_level( /* Either the thread must own the buffer pool mutex (buf_pool_mutex), or it is allowed to latch only ONE buffer block (block->mutex or buf_pool_zip_mutex). */ - if (!sync_thread_levels_g(array, level)) { - ut_a(sync_thread_levels_g(array, level - 1)); + if (!sync_thread_levels_g(array, level, FALSE)) { + ut_a(sync_thread_levels_g(array, level - 1, TRUE)); ut_a(sync_thread_levels_contain(array, SYNC_BUF_POOL)); } break; case SYNC_REC_LOCK: - ut_a((sync_thread_levels_contain(array, SYNC_KERNEL) - && sync_thread_levels_g(array, SYNC_REC_LOCK - 1)) - || sync_thread_levels_g(array, SYNC_REC_LOCK)); + if (sync_thread_levels_contain(array, SYNC_KERNEL)) { + ut_a(sync_thread_levels_g(array, SYNC_REC_LOCK - 1, + TRUE)); + } else { + ut_a(sync_thread_levels_g(array, SYNC_REC_LOCK, TRUE)); + } break; case SYNC_IBUF_BITMAP: /* Either the thread must own the master mutex to all the bitmap pages, or it is allowed to latch only ONE bitmap page. */ - ut_a((sync_thread_levels_contain(array, SYNC_IBUF_BITMAP_MUTEX) - && sync_thread_levels_g(array, SYNC_IBUF_BITMAP - 1)) - || sync_thread_levels_g(array, SYNC_IBUF_BITMAP)); + if (sync_thread_levels_contain(array, + SYNC_IBUF_BITMAP_MUTEX)) { + ut_a(sync_thread_levels_g(array, SYNC_IBUF_BITMAP - 1, + TRUE)); + } else { + ut_a(sync_thread_levels_g(array, SYNC_IBUF_BITMAP, + TRUE)); + } break; case SYNC_FSP_PAGE: ut_a(sync_thread_levels_contain(array, SYNC_FSP)); break; case SYNC_FSP: ut_a(sync_thread_levels_contain(array, SYNC_FSP) - || sync_thread_levels_g(array, SYNC_FSP)); + || sync_thread_levels_g(array, SYNC_FSP, TRUE)); break; case SYNC_TRX_UNDO_PAGE: ut_a(sync_thread_levels_contain(array, SYNC_TRX_UNDO) || sync_thread_levels_contain(array, SYNC_RSEG) || sync_thread_levels_contain(array, SYNC_PURGE_SYS) - || sync_thread_levels_g(array, SYNC_TRX_UNDO_PAGE)); + || sync_thread_levels_g(array, SYNC_TRX_UNDO_PAGE, TRUE)); break; case SYNC_RSEG_HEADER: ut_a(sync_thread_levels_contain(array, SYNC_RSEG)); @@ -1152,37 +1167,41 @@ sync_thread_add_level( case SYNC_TREE_NODE: ut_a(sync_thread_levels_contain(array, SYNC_INDEX_TREE) || sync_thread_levels_contain(array, SYNC_DICT_OPERATION) - || sync_thread_levels_g(array, SYNC_TREE_NODE - 1)); + || sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE)); break; case SYNC_TREE_NODE_NEW: ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE) || sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); break; case SYNC_INDEX_TREE: - ut_a((sync_thread_levels_contain(array, SYNC_IBUF_MUTEX) - && sync_thread_levels_contain(array, SYNC_FSP) - && sync_thread_levels_g(array, SYNC_FSP_PAGE - 1)) - || sync_thread_levels_g(array, SYNC_TREE_NODE - 1)); + if (sync_thread_levels_contain(array, SYNC_IBUF_MUTEX) + && sync_thread_levels_contain(array, SYNC_FSP)) { + ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, + TRUE)); + } else { + ut_a(sync_thread_levels_g(array, SYNC_TREE_NODE - 1, + TRUE)); + } break; case SYNC_IBUF_MUTEX: - ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1)); + ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, TRUE)); break; case SYNC_IBUF_PESS_INSERT_MUTEX: - ut_a(sync_thread_levels_g(array, SYNC_FSP - 1) - && !sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); + ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE)); + ut_a(!sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); break; case SYNC_IBUF_HEADER: - ut_a(sync_thread_levels_g(array, SYNC_FSP - 1) - && !sync_thread_levels_contain(array, SYNC_IBUF_MUTEX) - && !sync_thread_levels_contain( - array, SYNC_IBUF_PESS_INSERT_MUTEX)); + ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE)); + ut_a(!sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); + ut_a(!sync_thread_levels_contain(array, + SYNC_IBUF_PESS_INSERT_MUTEX)); break; case SYNC_DICT: #ifdef UNIV_DEBUG ut_a(buf_debug_prints - || sync_thread_levels_g(array, SYNC_DICT)); + || sync_thread_levels_g(array, SYNC_DICT, TRUE)); #else /* UNIV_DEBUG */ - ut_a(sync_thread_levels_g(array, SYNC_DICT)); + ut_a(sync_thread_levels_g(array, SYNC_DICT, TRUE)); #endif /* UNIV_DEBUG */ break; default: diff --git a/storage/innobase/thr/thr0loc.c b/storage/innobase/thr/thr0loc.c index 18f7b0707bd..49275be1d7d 100644 --- a/storage/innobase/thr/thr0loc.c +++ b/storage/innobase/thr/thr0loc.c @@ -62,7 +62,7 @@ struct thr_local_struct{ os_thread_t handle; /*!< operating system handle to the thread */ ulint slot_no;/*!< the index of the slot in the thread table for this thread */ - ibool in_ibuf;/*!< TRUE if the the thread is doing an ibuf + ibool in_ibuf;/*!< TRUE if the thread is doing an ibuf operation */ hash_node_t hash; /*!< hash chain node */ ulint magic_n;/*!< magic number (THR_LOCAL_MAGIC_N) */ diff --git a/storage/innobase/trx/trx0rec.c b/storage/innobase/trx/trx0rec.c index 36911c9df85..5097cf18dcd 100644 --- a/storage/innobase/trx/trx0rec.c +++ b/storage/innobase/trx/trx0rec.c @@ -1333,7 +1333,7 @@ trx_undo_get_undo_rec_low( ulint rseg_id; ulint page_no; ulint offset; - page_t* undo_page; + const page_t* undo_page; trx_rseg_t* rseg; ibool is_insert; mtr_t mtr; @@ -1572,7 +1572,7 @@ trx_undo_prev_version_build( /* We have to set the appropriate extern storage bits in the old version of the record: the extern bits in rec for those - fields that update does NOT update, as well as the the bits for + fields that update does NOT update, as well as the bits for those fields that update updates to become externally stored fields. Store the info: */ diff --git a/storage/innobase/trx/trx0roll.c b/storage/innobase/trx/trx0roll.c index 51d17192d5b..c925478cdf4 100644 --- a/storage/innobase/trx/trx0roll.c +++ b/storage/innobase/trx/trx0roll.c @@ -66,9 +66,9 @@ int trx_general_rollback_for_mysql( /*===========================*/ trx_t* trx, /*!< in: transaction handle */ - ibool partial,/*!< in: TRUE if partial rollback requested */ trx_savept_t* savept) /*!< in: pointer to savepoint undo number, if - partial rollback requested */ + partial rollback requested, or NULL for + complete rollback */ { mem_heap_t* heap; que_thr_t* thr; @@ -85,9 +85,8 @@ trx_general_rollback_for_mysql( roll_node = roll_node_create(heap); - roll_node->partial = partial; - - if (partial) { + if (savept) { + roll_node->partial = TRUE; roll_node->savept = *savept; } @@ -145,7 +144,7 @@ trx_rollback_for_mysql( the transaction object does not have an InnoDB session object, and we set a dummy session that we use for all MySQL transactions. */ - err = trx_general_rollback_for_mysql(trx, FALSE, NULL); + err = trx_general_rollback_for_mysql(trx, NULL); trx->op_info = ""; @@ -170,8 +169,7 @@ trx_rollback_last_sql_stat_for_mysql( trx->op_info = "rollback of SQL statement"; - err = trx_general_rollback_for_mysql(trx, TRUE, - &(trx->last_sql_stat_start)); + err = trx_general_rollback_for_mysql(trx, &trx->last_sql_stat_start); /* The following call should not be needed, but we play safe: */ trx_mark_sql_stat_end(trx); @@ -282,7 +280,7 @@ trx_rollback_to_savepoint_for_mysql( trx->op_info = "rollback to a savepoint"; - err = trx_general_rollback_for_mysql(trx, TRUE, &(savep->savept)); + err = trx_general_rollback_for_mysql(trx, &savep->savept); /* Store the current undo_no of the transaction so that we know where to roll back if we have to roll back the next SQL statement: */ @@ -534,28 +532,26 @@ trx_rollback_active( Rollback or clean up any incomplete transactions which were encountered in crash recovery. If the transaction already was committed, then we clean up a possible insert undo log. If the -transaction was not yet committed, then we roll it back. -Note: this is done in a background thread. -@return a dummy parameter */ +transaction was not yet committed, then we roll it back. */ UNIV_INTERN -os_thread_ret_t -trx_rollback_or_clean_all_recovered( -/*================================*/ - void* arg __attribute__((unused))) - /*!< in: a dummy parameter required by - os_thread_create */ +void +trx_rollback_or_clean_recovered( +/*============================*/ + ibool all) /*!< in: FALSE=roll back dictionary transactions; + TRUE=roll back all non-PREPARED transactions */ { trx_t* trx; mutex_enter(&kernel_mutex); - if (UT_LIST_GET_FIRST(trx_sys->trx_list)) { + if (!UT_LIST_GET_FIRST(trx_sys->trx_list)) { + goto leave_function; + } + if (all) { fprintf(stderr, "InnoDB: Starting in background the rollback" " of uncommitted transactions\n"); - } else { - goto leave_function; } mutex_exit(&kernel_mutex); @@ -584,18 +580,42 @@ loop: goto loop; case TRX_ACTIVE: - mutex_exit(&kernel_mutex); - trx_rollback_active(trx); - goto loop; + if (all || trx_get_dict_operation(trx) + != TRX_DICT_OP_NONE) { + mutex_exit(&kernel_mutex); + trx_rollback_active(trx); + goto loop; + } } } - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Rollback of non-prepared transactions completed\n"); + if (all) { + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Rollback of non-prepared" + " transactions completed\n"); + } leave_function: mutex_exit(&kernel_mutex); +} + +/*******************************************************************//** +Rollback or clean up any incomplete transactions which were +encountered in crash recovery. If the transaction already was +committed, then we clean up a possible insert undo log. If the +transaction was not yet committed, then we roll it back. +Note: this is done in a background thread. +@return a dummy parameter */ +UNIV_INTERN +os_thread_ret_t +trx_rollback_or_clean_all_recovered( +/*================================*/ + void* arg __attribute__((unused))) + /*!< in: a dummy parameter required by + os_thread_create */ +{ + trx_rollback_or_clean_recovered(TRUE); /* We count the number of threads in os_thread_exit(). A created thread should always use that to exit and not use return() to exit. */ diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c index 4d4885062a6..21ba6e481a7 100644 --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -803,7 +803,7 @@ trx_commit_off_kernel( in exactly the same order as commit lsn's, if the transactions have different rollback segments. To get exactly the same order we should hold the kernel mutex up to this point, - adding to to the contention of the kernel mutex. However, if + adding to the contention of the kernel mutex. However, if a transaction T2 is able to see modifications made by a transaction T1, T2 will always get a bigger transaction number and a bigger commit lsn than T1. */ @@ -950,7 +950,7 @@ trx_commit_off_kernel( /****************************************************************//** Cleans up a transaction at database startup. The cleanup is needed if the transaction already got to the middle of a commit when the database -crashed, andf we cannot roll it back. */ +crashed, and we cannot roll it back. */ UNIV_INTERN void trx_cleanup_at_db_startup( diff --git a/storage/innobase/ut/ut0auxconf_atomic_pthread_t_solaris.c b/storage/innobase/ut/ut0auxconf_atomic_pthread_t_solaris.c index a18a537d1d4..310603c7503 100644 --- a/storage/innobase/ut/ut0auxconf_atomic_pthread_t_solaris.c +++ b/storage/innobase/ut/ut0auxconf_atomic_pthread_t_solaris.c @@ -17,18 +17,38 @@ Place, Suite 330, Boston, MA 02111-1307 USA *****************************************************************************/ /***************************************************************************** -If this program compiles, then pthread_t objects can be used as arguments -to Solaris libc atomic functions. +If this program compiles and returns 0, then pthread_t objects can be used as +arguments to Solaris libc atomic functions. Created April 18, 2009 Vasil Dimov *****************************************************************************/ #include +#include int main(int argc, char** argv) { - pthread_t x = 0; + pthread_t x1; + pthread_t x2; + pthread_t x3; + + memset(&x1, 0x0, sizeof(x1)); + memset(&x2, 0x0, sizeof(x2)); + memset(&x3, 0x0, sizeof(x3)); + + if (sizeof(pthread_t) == 4) { + + atomic_cas_32(&x1, x2, x3); + + } else if (sizeof(pthread_t) == 8) { + + atomic_cas_64(&x1, x2, x3); + + } else { + + return(1); + } return(0); } diff --git a/storage/innobase/ut/ut0auxconf_have_gcc_atomics.c b/storage/innobase/ut/ut0auxconf_have_gcc_atomics.c new file mode 100644 index 00000000000..da5c13d7d79 --- /dev/null +++ b/storage/innobase/ut/ut0auxconf_have_gcc_atomics.c @@ -0,0 +1,61 @@ +/***************************************************************************** + +Copyright (c) 2009, Innobase Oy. 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 +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +/***************************************************************************** +If this program compiles and returns 0, then GCC atomic funcions are available. + +Created September 12, 2009 Vasil Dimov +*****************************************************************************/ + +int +main(int argc, char** argv) +{ + long x; + long y; + long res; + char c; + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x, y); + if (!res || x != y) { + return(1); + } + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x + 1, y); + if (res || x != 10) { + return(1); + } + + x = 10; + y = 123; + res = __sync_add_and_fetch(&x, y); + if (res != 123 + 10 || x != 123 + 10) { + return(1); + } + + c = 10; + res = __sync_lock_test_and_set(&c, 123); + if (res != 10 || c != 123) { + return(1); + } + + return(0); +} diff --git a/storage/innobase/ut/ut0ut.c b/storage/innobase/ut/ut0ut.c index e4cc226fbad..498873e290a 100644 --- a/storage/innobase/ut/ut0ut.c +++ b/storage/innobase/ut/ut0ut.c @@ -132,6 +132,7 @@ ut_time(void) return(time(NULL)); } +#ifndef UNIV_HOTBACKUP /**********************************************************//** Returns system time. Upon successful completion, the value 0 is returned; otherwise the @@ -199,6 +200,24 @@ ut_time_us( return(us); } +/**********************************************************//** +Returns the number of milliseconds since some epoch. The +value may wrap around. It should only be used for heuristic +purposes. +@return ms since epoch */ +UNIV_INTERN +ulint +ut_time_ms(void) +/*============*/ +{ + struct timeval tv; + + ut_gettimeofday(&tv, NULL); + + return((ulint) tv.tv_sec * 1000 + tv.tv_usec / 1000); +} +#endif /* !UNIV_HOTBACKUP */ + /**********************************************************//** Returns the difference of two times in seconds. @return time2 - time1 expressed in seconds */ diff --git a/storage/innobase/win-plugin/README b/storage/innobase/win-plugin/README deleted file mode 100644 index 00f4e996a3f..00000000000 --- a/storage/innobase/win-plugin/README +++ /dev/null @@ -1,22 +0,0 @@ -This directory contains patches that need to be applied to the MySQL -source tree in order to build the dynamic plugin on Windows -- -HA_INNODB.DLL. Please note the followings when adding the patches: - -* The patch must be applied from the mysql top-level source directory. - patch -p0 < win-plugin.diff -* The patch filenames end in ".diff". -* All patches here are expected to apply cleanly to the latest MySQL 5.1 - tree when storage/innobase is replaced with this InnoDB branch. - -When applying the patch, the following files will be modified: - - * CMakeLists.txt - * sql/CMakeLists.txt - * win/configure.js - -Also, two new files will be added: - - * sql/mysqld.def - * sql/mysqld_x64.def - -You can get "patch" utility for Windows from http://unxutils.sourceforge.net/ diff --git a/storage/innobase/win-plugin/win-plugin.diff b/storage/innobase/win-plugin/win-plugin.diff deleted file mode 100644 index 4b3354ac4de..00000000000 --- a/storage/innobase/win-plugin/win-plugin.diff +++ /dev/null @@ -1,279 +0,0 @@ -diff -Nur CMakeLists.txt.orig CMakeLists.txt ---- CMakeLists.txt.orig 2008-10-03 12:25:41 -05:00 -+++ CMakeLists.txt 2008-09-26 17:32:51 -05:00 -@@ -254,9 +254,9 @@ - IF(WITH_FEDERATED_STORAGE_ENGINE) - ADD_SUBDIRECTORY(storage/federated) - ENDIF(WITH_FEDERATED_STORAGE_ENGINE) --IF(WITH_INNOBASE_STORAGE_ENGINE) -+IF(WITH_INNOBASE_STORAGE_ENGINE OR INNODB_DYNAMIC_PLUGIN) - ADD_SUBDIRECTORY(storage/innobase) --ENDIF(WITH_INNOBASE_STORAGE_ENGINE) -+ENDIF(WITH_INNOBASE_STORAGE_ENGINE OR INNODB_DYNAMIC_PLUGIN) - ADD_SUBDIRECTORY(sql) - ADD_SUBDIRECTORY(server-tools/instance-manager) - ADD_SUBDIRECTORY(libmysql) - -diff -Nur sql/CMakeLists.txt.orig sql/CMakeLists.txt ---- sql/CMakeLists.txt.orig 2008-10-03 12:25:41 -05:00 -+++ sql/CMakeLists.txt 2008-09-24 03:58:19 -05:00 -@@ -98,6 +98,15 @@ - LINK_FLAGS "/PDB:${CMAKE_CFG_INTDIR}/mysqld${MYSQLD_EXE_SUFFIX}.pdb") - ENDIF(cmake_version EQUAL 20406) - -+# Checks for 64-bit version -+IF(CMAKE_SIZEOF_VOID_P MATCHES 8) -+SET_TARGET_PROPERTIES(mysqld PROPERTIES -+ LINK_FLAGS "/def:\"${PROJECT_SOURCE_DIR}/sql/mysqld_x64.def\"") -+ELSE(CMAKE_SIZEOF_VOID_P MATCHES 8) -+SET_TARGET_PROPERTIES(mysqld PROPERTIES -+ LINK_FLAGS "/def:\"${PROJECT_SOURCE_DIR}/sql/mysqld.def\"") -+ENDIF(CMAKE_SIZEOF_VOID_P MATCHES 8) -+ - IF(EMBED_MANIFESTS) - MYSQL_EMBED_MANIFEST("mysqld" "asInvoker") - ENDIF(EMBED_MANIFESTS) - -diff -Nur sql/mysqld.def.orig sql/mysqld.def ---- sql/mysqld.def.orig 1969-12-31 18:00:00 -06:00 -+++ sql/mysqld.def 2009-04-09 02:20:32 -05:00 -@@ -0,0 +1,111 @@ -+EXPORTS -+ ?use_hidden_primary_key@handler@@UAEXXZ -+ ?get_dynamic_partition_info@handler@@UAEXPAUPARTITION_INFO@@I@Z -+ ?read_first_row@handler@@UAEHPAEI@Z -+ ?read_range_next@handler@@UAEHXZ -+ ?read_range_first@handler@@UAEHPBUst_key_range@@0_N1@Z -+ ?read_multi_range_first@handler@@UAEHPAPAUst_key_multi_range@@PAU2@I_NPAUst_handler_buffer@@@Z -+ ?read_multi_range_next@handler@@UAEHPAPAUst_key_multi_range@@@Z -+ ?index_read_idx_map@handler@@UAEHPAEIPBEKW4ha_rkey_function@@@Z -+ ?print_error@handler@@UAEXHH@Z -+ ?clone@handler@@UAEPAV1@PAUst_mem_root@@@Z -+ ?get_auto_increment@handler@@UAEX_K00PA_K1@Z -+ ?index_next_same@handler@@UAEHPAEPBEI@Z -+ ?get_error_message@handler@@UAE_NHPAVString@@@Z -+ ?ha_thd@handler@@IBEPAVTHD@@XZ -+ ?update_auto_increment@handler@@QAEHXZ -+ ?ha_statistic_increment@handler@@IBEXPQsystem_status_var@@K@Z -+ ?trans_register_ha@@YAXPAVTHD@@_NPAUhandlerton@@@Z -+ ?cmp@Field_blob@@QAEHPBEI0I@Z -+ ?set_time@Field_timestamp@@QAEXXZ -+ ?sql_print_error@@YAXPBDZZ -+ ?sql_print_warning@@YAXPBDZZ -+ ?check_global_access@@YA_NPAVTHD@@K@Z -+ ?schema_table_store_record@@YA_NPAVTHD@@PAUst_table@@@Z -+ ?get_quote_char_for_identifier@@YAHPAVTHD@@PBDI@Z -+ ?copy@String@@QAE_NXZ -+ ?copy@String@@QAE_NABV1@@Z -+ ?copy@String@@QAE_NPBDIPAUcharset_info_st@@@Z -+ ?copy_and_convert@@YAIPADIPAUcharset_info_st@@PBDI1PAI@Z -+ ?filename_to_tablename@@YAIPBDPADI@Z -+ ?strconvert@@YAIPAUcharset_info_st@@PBD0PADIPAI@Z -+ ?calculate_key_len@@YAIPAUst_table@@IPBEK@Z -+ ?sql_alloc@@YAPAXI@Z -+ ?localtime_to_TIME@@YAXPAUst_mysql_time@@PAUtm@@@Z -+ ?push_warning@@YAPAVMYSQL_ERROR@@PAVTHD@@W4enum_warning_level@1@IPBD@Z -+ ?push_warning_printf@@YAXPAVTHD@@W4enum_warning_level@MYSQL_ERROR@@IPBDZZ -+ ?drop_table@handler@@EAEXPBD@Z -+ ?column_bitmaps_signal@handler@@UAEXXZ -+ ?delete_table@handler@@MAEHPBD@Z -+ ?rename_table@handler@@MAEHPBD0@Z -+ ?key_map_empty@@3V?$Bitmap@$0EA@@@B -+ ?THR_THD@@3PAVTHD@@A -+ ?end_of_list@@3Ulist_node@@A -+ ?mysql_tmpdir_list@@3Ust_my_tmpdir@@A -+ mysql_query_cache_invalidate4 -+ thd_query -+ thd_sql_command -+ thd_get_thread_id -+ thd_get_xid -+ thd_slave_thread -+ thd_non_transactional_update -+ thd_mark_transaction_to_rollback -+ thd_security_context -+ thd_charset -+ thd_test_options -+ thd_ha_data -+ thd_killed -+ thd_tx_isolation -+ thd_tablespace_op -+ thd_sql_command -+ thd_memdup -+ thd_make_lex_string -+ thd_in_lock_tables -+ thd_binlog_format -+ _my_hash_init -+ my_hash_free -+ my_tmpdir -+ check_if_legal_filename -+ my_filename -+ my_sync_dir_by_file -+ alloc_root -+ thr_lock_data_init -+ thr_lock_init -+ thr_lock_delete -+ my_multi_malloc -+ get_charset -+ unpack_filename -+ my_hash_insert -+ my_hash_search -+ my_hash_delete -+ mysql_bin_log_file_pos -+ mysql_bin_log_file_name -+ mysqld_embedded -+ my_thread_name -+ my_malloc -+ my_no_flags_free -+ _sanity -+ _mymalloc -+ _myfree -+ _my_strdup -+ _my_thread_var -+ my_error -+ pthread_cond_init -+ pthread_cond_signal -+ pthread_cond_wait -+ pthread_cond_destroy -+ localtime_r -+ my_strdup -+ deflate -+ deflateEnd -+ deflateReset -+ deflateInit2_ -+ inflateEnd -+ inflateInit_ -+ inflate -+ compressBound -+ inflateInit2_ -+ adler32 -+ longlong2str -+ strend -+ my_snprintf - -diff -Nur sql/mysqld_x64.def.orig sql/mysqld_x64.def ---- sql/mysqld_x64.def.orig 1969-12-31 18:00:00 -06:00 -+++ sql/mysqld_x64.def 2009-04-09 02:22:04 -05:00 -@@ -0,0 +1,111 @@ -+EXPORTS -+ ?use_hidden_primary_key@handler@@UEAAXXZ -+ ?get_dynamic_partition_info@handler@@UEAAXPEAUPARTITION_INFO@@I@Z -+ ?read_first_row@handler@@UEAAHPEAEI@Z -+ ?read_range_next@handler@@UEAAHXZ -+ ?read_range_first@handler@@UEAAHPEBUst_key_range@@0_N1@Z -+ ?read_multi_range_first@handler@@UEAAHPEAPEAUst_key_multi_range@@PEAU2@I_NPEAUst_handler_buffer@@@Z -+ ?read_multi_range_next@handler@@UEAAHPEAPEAUst_key_multi_range@@@Z -+ ?index_read_idx_map@handler@@UEAAHPEAEIPEBEKW4ha_rkey_function@@@Z -+ ?print_error@handler@@UEAAXHH@Z -+ ?clone@handler@@UEAAPEAV1@PEAUst_mem_root@@@Z -+ ?get_auto_increment@handler@@UEAAX_K00PEA_K1@Z -+ ?index_next_same@handler@@UEAAHPEAEPEBEI@Z -+ ?get_error_message@handler@@UEAA_NHPEAVString@@@Z -+ ?ha_thd@handler@@IEBAPEAVTHD@@XZ -+ ?update_auto_increment@handler@@QEAAHXZ -+ ?ha_statistic_increment@handler@@IEBAXPEQsystem_status_var@@K@Z -+ ?trans_register_ha@@YAXPEAVTHD@@_NPEAUhandlerton@@@Z -+ ?cmp@Field_blob@@QEAAHPEBEI0I@Z -+ ?set_time@Field_timestamp@@QEAAXXZ -+ ?sql_print_error@@YAXPEBDZZ -+ ?sql_print_warning@@YAXPEBDZZ -+ ?check_global_access@@YA_NPEAVTHD@@K@Z -+ ?schema_table_store_record@@YA_NPEAVTHD@@PEAUst_table@@@Z -+ ?get_quote_char_for_identifier@@YAHPEAVTHD@@PEBDI@Z -+ ?copy@String@@QEAA_NXZ -+ ?copy@String@@QEAA_NAEBV1@@Z -+ ?copy@String@@QEAA_NPEBDIPEAUcharset_info_st@@@Z -+ ?copy_and_convert@@YAIPEADIPEAUcharset_info_st@@PEBDI1PEAI@Z -+ ?filename_to_tablename@@YAIPEBDPEADI@Z -+ ?strconvert@@YAIPEAUcharset_info_st@@PEBD0PEADIPEAI@Z -+ ?calculate_key_len@@YAIPEAUst_table@@IPEBEK@Z -+ ?sql_alloc@@YAPEAX_K@Z -+ ?localtime_to_TIME@@YAXPEAUst_mysql_time@@PEAUtm@@@Z -+ ?push_warning@@YAPEAVMYSQL_ERROR@@PEAVTHD@@W4enum_warning_level@1@IPEBD@Z -+ ?push_warning_printf@@YAXPEAVTHD@@W4enum_warning_level@MYSQL_ERROR@@IPEBDZZ -+ ?drop_table@handler@@EEAAXPEBD@Z -+ ?column_bitmaps_signal@handler@@UEAAXXZ -+ ?delete_table@handler@@MEAAHPEBD@Z -+ ?rename_table@handler@@MEAAHPEBD0@Z -+ ?key_map_empty@@3V?$Bitmap@$0EA@@@B -+ ?THR_THD@@3PEAVTHD@@EA -+ ?end_of_list@@3Ulist_node@@A -+ ?mysql_tmpdir_list@@3Ust_my_tmpdir@@A -+ mysql_query_cache_invalidate4 -+ thd_query -+ thd_sql_command -+ thd_get_thread_id -+ thd_get_xid -+ thd_slave_thread -+ thd_non_transactional_update -+ thd_mark_transaction_to_rollback -+ thd_security_context -+ thd_charset -+ thd_test_options -+ thd_ha_data -+ thd_killed -+ thd_tx_isolation -+ thd_tablespace_op -+ thd_sql_command -+ thd_memdup -+ thd_make_lex_string -+ thd_in_lock_tables -+ thd_binlog_format -+ _my_hash_init -+ my_hash_free -+ my_tmpdir -+ check_if_legal_filename -+ my_filename -+ my_sync_dir_by_file -+ alloc_root -+ thr_lock_data_init -+ thr_lock_init -+ thr_lock_delete -+ my_multi_malloc -+ get_charset -+ unpack_filename -+ my_hash_insert -+ my_hash_search -+ my_hash_delete -+ mysql_bin_log_file_pos -+ mysql_bin_log_file_name -+ mysqld_embedded -+ my_thread_name -+ my_malloc -+ my_no_flags_free -+ _sanity -+ _mymalloc -+ _myfree -+ _my_strdup -+ _my_thread_var -+ my_error -+ pthread_cond_init -+ pthread_cond_signal -+ pthread_cond_wait -+ pthread_cond_destroy -+ localtime_r -+ my_strdup -+ deflate -+ deflateEnd -+ deflateReset -+ deflateInit2_ -+ inflateEnd -+ inflateInit_ -+ inflate -+ compressBound -+ inflateInit2_ -+ adler32 -+ longlong2str -+ strend -+ my_snprintf - -diff -Nur win/configure.js.orig win/configure.js ---- win/configure.js.orig 2008-09-26 21:18:37 -05:00 -+++ win/configure.js 2008-10-01 11:21:27 -05:00 -@@ -50,6 +50,7 @@ - case "EMBED_MANIFESTS": - case "EXTRA_DEBUG": - case "WITH_EMBEDDED_SERVER": -+ case "INNODB_DYNAMIC_PLUGIN": - configfile.WriteLine("SET (" + args.Item(i) + " TRUE)"); - break; - case "MYSQL_SERVER_SUFFIX": From 9ceeabd9b294c35263df29999f724c3d12ffcae9 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Fri, 16 Oct 2009 14:06:33 +0200 Subject: [PATCH 137/146] Compile fix for Windows: Use "#ifdef", not plain "#if". --- mysys/mf_keycache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index 6ffa8fb3ea8..53a3be6f999 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -1742,7 +1742,7 @@ restart: - block assigned but not yet read from file (invalid data). */ -#if THREAD +#ifdef THREAD if (keycache->in_resize) { /* This is a request during a resize operation */ From e1c54dd9ad754d4d3a6b8a921b305d47e180c23a Mon Sep 17 00:00:00 2001 From: Timothy Smith Date: Fri, 16 Oct 2009 19:53:10 +0200 Subject: [PATCH 138/146] Work around a problem in IBM compiler (on aix / i5os) that doesn't use function prototypes from header in conjunction with K&R-style function definitions. The symptom is a type mismatch between int and wchar_t. --- cmd-line-utils/readline/util.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd-line-utils/readline/util.c b/cmd-line-utils/readline/util.c index 50cfea75cb9..f0245b29f2c 100644 --- a/cmd-line-utils/readline/util.c +++ b/cmd-line-utils/readline/util.c @@ -81,8 +81,7 @@ rl_alphabetic (c) #if defined (HANDLE_MULTIBYTE) int -_rl_walphabetic (wc) - wchar_t wc; +_rl_walphabetic (wchar_t wc) { int c; From 6d569306b432eaf068b9dd36ba49c85663743da4 Mon Sep 17 00:00:00 2001 From: Timothy Smith Date: Fri, 16 Oct 2009 19:59:23 +0200 Subject: [PATCH 139/146] Update _libdir/plugin to _libdir/mysql/plugin in a few places --- support-files/mysql.spec.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 6fd8929266e..f3626bb171b 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -708,7 +708,7 @@ fi %attr(755, root, root) %{_bindir}/resolve_stack_dump %attr(755, root, root) %{_bindir}/resolveip -%attr(755, root, root) %{_libdir}/plugin/*.so* +%attr(755, root, root) %{_libdir}/mysql/plugin/*.so* %if %{?malloc_lib_target:1}%{!?malloc_lib_target:0} %attr(644, root, root) %{_libdir}/mysql/%{malloc_lib_target} @@ -838,8 +838,8 @@ fi %{_libdir}/mysql/libvio.a %{_libdir}/mysql/libz.a %{_libdir}/mysql/libz.la -%{_libdir}/plugin/*.a -%{_libdir}/plugin/*.la +%{_libdir}/mysql/plugin/*.a +%{_libdir}/mysql/plugin/*.la %files shared %defattr(-, root, root, 0755) From 356efddad60a9ae26f5cce3943557884d89d1f80 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Tue, 20 Oct 2009 13:37:07 +0400 Subject: [PATCH 140/146] A fix for innodb_bug44369.test due to Bug#47233 (Innodb calls push_warning(MYSQL_ERROR::WARN_LEVEL_ERROR)). The Signal/Resignal patch changes the push_warning() API: now it silently downgrades WARN_LEVEL_ERROR to WARN_LEVEL_WARN. This patch should be rolled back when Bug#47233 is fixed. --- mysql-test/r/innodb_bug44369.result | 8 ++++---- mysql-test/t/innodb_bug44369.test | 10 ++++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/innodb_bug44369.result b/mysql-test/r/innodb_bug44369.result index e4b84ecac19..9cf79aeffab 100644 --- a/mysql-test/r/innodb_bug44369.result +++ b/mysql-test/r/innodb_bug44369.result @@ -2,13 +2,13 @@ create table bug44369 (DB_ROW_ID int) engine=innodb; ERROR HY000: Can't create table 'test.bug44369' (errno: -1) create table bug44369 (db_row_id int) engine=innodb; ERROR HY000: Can't create table 'test.bug44369' (errno: -1) -show errors; +show warnings; Level Code Message -Error 1005 Error creating table 'test/bug44369' with column name 'db_row_id'. 'db_row_id' is a reserved name. Please try to re-create the table with a different column name. +Warning 1005 Error creating table 'test/bug44369' with column name 'db_row_id'. 'db_row_id' is a reserved name. Please try to re-create the table with a different column name. Error 1005 Can't create table 'test.bug44369' (errno: -1) create table bug44369 (db_TRX_Id int) engine=innodb; ERROR HY000: Can't create table 'test.bug44369' (errno: -1) -show errors; +show warnings; Level Code Message -Error 1005 Error creating table 'test/bug44369' with column name 'db_TRX_Id'. 'db_TRX_Id' is a reserved name. Please try to re-create the table with a different column name. +Warning 1005 Error creating table 'test/bug44369' with column name 'db_TRX_Id'. 'db_TRX_Id' is a reserved name. Please try to re-create the table with a different column name. Error 1005 Can't create table 'test.bug44369' (errno: -1) diff --git a/mysql-test/t/innodb_bug44369.test b/mysql-test/t/innodb_bug44369.test index 495059eb5e6..4943627fa90 100644 --- a/mysql-test/t/innodb_bug44369.test +++ b/mysql-test/t/innodb_bug44369.test @@ -13,9 +13,15 @@ create table bug44369 (DB_ROW_ID int) engine=innodb; --error ER_CANT_CREATE_TABLE create table bug44369 (db_row_id int) engine=innodb; -show errors; +# TODO: after Bug#47233 is fixed, 'show warning' should be replaced by 'show +# errors' again. +# show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table bug44369 (db_TRX_Id int) engine=innodb; -show errors; +# TODO: after Bug#47233 is fixed, 'show warning' should be replaced by 'show +# errors' again. +# show errors; +show warnings; From bca54639b6b0fc3958151e0c086e1f1e4c8c9c6c Mon Sep 17 00:00:00 2001 From: Satya B Date: Tue, 20 Oct 2009 15:12:38 +0530 Subject: [PATCH 141/146] Merge a CMakeLists.txt change from Innodb plugin 1.0.5 --- storage/innobase/CMakeLists.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index f48c4ea39b2..2dfd19ef06c 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -84,4 +84,20 @@ SET(INNOBASE_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c ut/ut0list.c ut/ut0wqueue.c) ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS -DIB_HAVE_PAUSE_INSTRUCTION) + +IF (MYSQL_VERSION_ID GREATER "50137") + IF (WITH_INNOBASE_STORAGE_ENGINE) + MYSQL_STORAGE_ENGINE(INNOBASE) + ELSE (WITH_INNOBASE_STORAGE_ENGINE) + SET (INNODB_SOURCES ${INNOBASE_SOURCES}) + MYSQL_STORAGE_ENGINE(INNODB) + ENDIF (WITH_INNOBASE_STORAGE_ENGINE) +ELSE (MYSQL_VERSION_ID GREATER "50137") + IF (NOT SOURCE_SUBLIBS) + ADD_DEFINITIONS(-D_WIN32 -DMYSQL_SERVER) + ADD_LIBRARY(innobase STATIC ${INNOBASE_SOURCES}) + # Require mysqld_error.h, which is built as part of the GenError + ADD_DEPENDENCIES(innobase GenError) + ENDIF (NOT SOURCE_SUBLIBS) +ENDIF (MYSQL_VERSION_ID GREATER "50137") MYSQL_STORAGE_ENGINE(INNOBASE) From 0ddb2ca7405500be1388a4393b78ab48d26ecd9c Mon Sep 17 00:00:00 2001 From: Satya B Date: Tue, 20 Oct 2009 16:11:50 +0530 Subject: [PATCH 142/146] Fix the windows Build failure due to the changes to CMakelists by r2910. Remove the extra line which try to use the name INNOBASE again. The IF ELSE loop above declares the library name based on the version of mysql --- storage/innobase/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index 2dfd19ef06c..57ad7f4b28c 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -100,4 +100,3 @@ ELSE (MYSQL_VERSION_ID GREATER "50137") ADD_DEPENDENCIES(innobase GenError) ENDIF (NOT SOURCE_SUBLIBS) ENDIF (MYSQL_VERSION_ID GREATER "50137") -MYSQL_STORAGE_ENGINE(INNOBASE) From 9787943c5e089e18ae41157a5fe830f055730f8a Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Wed, 21 Oct 2009 00:26:56 +0400 Subject: [PATCH 143/146] Mark rpl.rpl_innodb_bug28430 experimental unconditionally. --- mysql-test/collections/default.experimental | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index 1e811ecd8c2..b4e3d1d5509 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -18,7 +18,7 @@ main.plugin # Bug#47146 Linking problem with exampl main.plugin_load # Bug#47146 rpl.rpl_get_master_version_and_clock* # Bug#46931 2009-08-26 alik rpl.rpl_get_master_version_and_clock fails on hpux11.31 -rpl.rpl_innodb_bug28430* @solaris # Bug#46029 +rpl.rpl_innodb_bug28430* # Bug#46029 rpl.rpl_innodb_bug30888* @solaris # Bug#47646 2009-09-25 alik rpl.rpl_innodb_bug30888 fails sporadically on Solaris rpl.rpl_plugin_load* @solaris # Bug#47146 rpl.rpl_row_create_table* # Bug#45576: rpl_row_create_table fails on PB2 From 1ea4a9f371c9a2c3f945879ffa227a1003c7389c Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Wed, 21 Oct 2009 17:25:10 +0400 Subject: [PATCH 144/146] Update errmsg-utf8.txt after automerge. --- sql/share/errmsg-utf8.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index e8bc2096bf6..62f49250a1a 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -4702,7 +4702,7 @@ ER_NOT_SUPPORTED_YET 42000 swe "Denna version av MySQL kan 盲nnu inte utf枚ra '%s'" ER_MASTER_FATAL_ERROR_READING_BINLOG nla "Kreeg fatale fout %d: '%-.128s' van master tijdens lezen van data uit binaire log" - eng "Got fatal error %d: '%-.128s' from master when reading data from binary log" + eng "Got fatal error %d from master when reading data from binary log: '%-.128s'" ger "Schwerer Fehler %d: '%-.128s vom Master beim Lesen des bin盲ren Logs" ita "Errore fatale %d: '%-.128s' dal master leggendo i dati dal log binario" por "Obteve fatal erro %d: '%-.128s' do master quando lendo dados do binary log" @@ -6203,7 +6203,7 @@ WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED ER_DEBUG_SYNC_TIMEOUT eng "debug sync point wait timed out" - ger "Debug Sync Point Wartezeit 黚erschritten" + ger "Debug Sync Point Wartezeit 眉berschritten" ER_DEBUG_SYNC_HIT_LIMIT eng "debug sync point hit limit reached" ger "Debug Sync Point Hit Limit erreicht" From c0718f032b9c5cfe7115533a1317fcea216e9772 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Thu, 22 Oct 2009 10:01:23 +0400 Subject: [PATCH 145/146] Disable the test in mysql-trunk because of Bug#46931 instead of making it experimental. --- mysql-test/collections/default.experimental | 1 - mysql-test/suite/rpl/t/disabled.def | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index b4e3d1d5509..7f862b9f393 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -17,7 +17,6 @@ main.log_tables # Bug#47924 2009-10-08 alik main.log_ta main.plugin # Bug#47146 Linking problem with example plugin when dtrace enabled main.plugin_load # Bug#47146 -rpl.rpl_get_master_version_and_clock* # Bug#46931 2009-08-26 alik rpl.rpl_get_master_version_and_clock fails on hpux11.31 rpl.rpl_innodb_bug28430* # Bug#46029 rpl.rpl_innodb_bug30888* @solaris # Bug#47646 2009-09-25 alik rpl.rpl_innodb_bug30888 fails sporadically on Solaris rpl.rpl_plugin_load* @solaris # Bug#47146 diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index 8cae44a3607..3e3069d5d92 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -10,3 +10,4 @@ # ############################################################################## +rpl_get_master_version_and_clock: # Bug#46931 2009-10-17 joro rpl.rpl_get_master_version_and_clock fails From 8d953ecef1f8a10e459ca2640a3928b036914eb8 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Thu, 22 Oct 2009 10:05:53 +0400 Subject: [PATCH 146/146] Pass --vardir to MTR in mysql-trunk.push. --- mysql-test/collections/mysql-trunk.push | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mysql-test/collections/mysql-trunk.push b/mysql-test/collections/mysql-trunk.push index 99ff6f21673..97101d5994c 100644 --- a/mysql-test/collections/mysql-trunk.push +++ b/mysql-test/collections/mysql-trunk.push @@ -1,5 +1,5 @@ -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=n_mix --mysqld=--binlog-format=mixed --suite=main,binlog,innodb,federated,rpl -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=ps_row --ps-protocol --mysqld=--binlog-format=row --suite=main,binlog,innodb,federated,rpl -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=embedded --embedded --suite=main,binlog,innodb,federated,rpl -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=rpl_binlog_row --mysqld=--binlog-format=row --suite=rpl,binlog -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=funcs_1 --suite=funcs_1 +perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=n_mix --vardir=var-n_mix --mysqld=--binlog-format=mixed --suite=main,binlog,innodb,federated,rpl +perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=ps_row --vardir=var-ps_row --ps-protocol --mysqld=--binlog-format=row --suite=main,binlog,innodb,federated,rpl +perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=embedded --vardir=var-emebbed --embedded --suite=main,binlog,innodb,federated,rpl +perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=rpl_binlog_row --vardir=var-rpl_binlog_row --mysqld=--binlog-format=row --suite=rpl,binlog +perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=funcs_1 --vardir=var-funcs_1 --suite=funcs_1