From e43df58eade0b6806377966a0d3a2cdb88743a5d Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 4 Jun 2009 23:36:34 +0500 Subject: [PATCH 001/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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/159] 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 21317d5df3033850ae862a8ec6202f059c2ba16b Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 5 Oct 2009 20:06:04 +0500 Subject: [PATCH 078/159] WL#4584 Internationalized number format @ mysql-test/r/func_str.result Adding tests @ mysql-test/t/func_str.test Adding tests @ mysql-test/t/variables.test Fixing error number @ sql/item_create.cc Allowing 2 and 3 arguments to format() @ sql/item_strfunc.cc Adding new formatting code. @ sql/item_strfunc.h Adding new contructors and "locale" member @ sql/mysql_priv.h Adding number formatting members into MY_LOCALE @ sql/sql_locale.cc Adding number formatting data into locale constants @ sql/set_var.cc Using new error message @ sql/share/errmgs.txt Adding new error message --- mysql-test/r/func_str.result | 130 +++++++++ mysql-test/t/func_str.test | 42 +++ mysql-test/t/variables.test | 6 +- sql/item_create.cc | 33 ++- sql/item_strfunc.cc | 90 ++++-- sql/item_strfunc.h | 7 +- sql/mysql_priv.h | 12 +- sql/set_var.cc | 5 +- sql/share/errmsg.txt | 2 + sql/sql_locale.cc | 547 ++++++++++++++++++++++++++++------- 10 files changed, 725 insertions(+), 149 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index c87879e13b5..39d11aa3e2c 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -2558,3 +2558,133 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 2 Using join buffer 2 DERIVED t1 ALL NULL NULL NULL NULL 2 drop table t1; +Start of 5.4 tests +SELECT format(12345678901234567890.123, 3); +format(12345678901234567890.123, 3) +12,345,678,901,234,567,890.123 +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' +SELECT format(12345678901234567890.123, 3, 'ar_AE'); +format(12345678901234567890.123, 3, 'ar_AE') +12,345,678,901,234,567,890.123 +SELECT format(12345678901234567890.123, 3, 'ar_SA'); +format(12345678901234567890.123, 3, 'ar_SA') +12345678901234567890.123 +SELECT format(12345678901234567890.123, 3, 'be_BY'); +format(12345678901234567890.123, 3, 'be_BY') +12.345.678.901.234.567.890,123 +SELECT format(12345678901234567890.123, 3, 'de_DE'); +format(12345678901234567890.123, 3, 'de_DE') +12.345.678.901.234.567.890,123 +SELECT format(12345678901234567890.123, 3, 'en_IN'); +format(12345678901234567890.123, 3, 'en_IN') +1,23,45,67,89,01,23,45,67,890.123 +SELECT format(12345678901234567890.123, 3, 'en_US'); +format(12345678901234567890.123, 3, 'en_US') +12,345,678,901,234,567,890.123 +SELECT format(12345678901234567890.123, 3, 'it_CH'); +format(12345678901234567890.123, 3, 'it_CH') +12'345'678'901'234'567'890,123 +SELECT format(12345678901234567890.123, 3, 'ru_RU'); +format(12345678901234567890.123, 3, 'ru_RU') +12 345 678 901 234 567 890,123 +SELECT format(12345678901234567890.123, 3, 'ta_IN'); +format(12345678901234567890.123, 3, 'ta_IN') +1,23,45,67,89,01,23,45,67,890.123 +CREATE TABLE t1 (fmt CHAR(5) NOT NULL); +INSERT INTO t1 VALUES ('ar_AE'); +INSERT INTO t1 VALUES ('ar_SA'); +INSERT INTO t1 VALUES ('be_BY'); +INSERT INTO t1 VALUES ('de_DE'); +INSERT INTO t1 VALUES ('en_IN'); +INSERT INTO t1 VALUES ('en_US'); +INSERT INTO t1 VALUES ('it_CH'); +INSERT INTO t1 VALUES ('ru_RU'); +INSERT INTO t1 VALUES ('ta_IN'); +SELECT fmt, format(12345678901234567890.123, 3, fmt) FROM t1 ORDER BY fmt; +fmt format(12345678901234567890.123, 3, fmt) +ar_AE 12,345,678,901,234,567,890.123 +ar_SA 12345678901234567890.123 +be_BY 12.345.678.901.234.567.890,123 +de_DE 12.345.678.901.234.567.890,123 +en_IN 1,23,45,67,89,01,23,45,67,890.123 +en_US 12,345,678,901,234,567,890.123 +it_CH 12'345'678'901'234'567'890,123 +ru_RU 12 345 678 901 234 567 890,123 +ta_IN 1,23,45,67,89,01,23,45,67,890.123 +SELECT fmt, format(12345678901234567890.123, 0, fmt) FROM t1 ORDER BY fmt; +fmt format(12345678901234567890.123, 0, fmt) +ar_AE 12,345,678,901,234,567,890 +ar_SA 12345678901234567890 +be_BY 12.345.678.901.234.567.890 +de_DE 12.345.678.901.234.567.890 +en_IN 1,23,45,67,89,01,23,45,67,890 +en_US 12,345,678,901,234,567,890 +it_CH 12'345'678'901'234'567'890 +ru_RU 12 345 678 901 234 567 890 +ta_IN 1,23,45,67,89,01,23,45,67,890 +SELECT fmt, format(12345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +fmt format(12345678901234567890, 3, fmt) +ar_AE 12,345,678,901,234,567,890.000 +ar_SA 12345678901234567890.000 +be_BY 12.345.678.901.234.567.890,000 +de_DE 12.345.678.901.234.567.890,000 +en_IN 1,23,45,67,89,01,23,45,67,890.000 +en_US 12,345,678,901,234,567,890.000 +it_CH 12'345'678'901'234'567'890,000 +ru_RU 12 345 678 901 234 567 890,000 +ta_IN 1,23,45,67,89,01,23,45,67,890.000 +SELECT fmt, format(-12345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +fmt format(-12345678901234567890, 3, fmt) +ar_AE -12,345,678,901,234,567,890.000 +ar_SA -12345678901234567890.000 +be_BY -12.345.678.901.234.567.890,000 +de_DE -12.345.678.901.234.567.890,000 +en_IN -1,23,45,67,89,01,23,45,67,890.000 +en_US -12,345,678,901,234,567,890.000 +it_CH -12'345'678'901'234'567'890,000 +ru_RU -12 345 678 901 234 567 890,000 +ta_IN -1,23,45,67,89,01,23,45,67,890.000 +SELECT fmt, format(-02345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +fmt format(-02345678901234567890, 3, fmt) +ar_AE -2,345,678,901,234,567,890.000 +ar_SA -2345678901234567890.000 +be_BY -2.345.678.901.234.567.890,000 +de_DE -2.345.678.901.234.567.890,000 +en_IN -23,45,67,89,01,23,45,67,890.000 +en_US -2,345,678,901,234,567,890.000 +it_CH -2'345'678'901'234'567'890,000 +ru_RU -2 345 678 901 234 567 890,000 +ta_IN -23,45,67,89,01,23,45,67,890.000 +SELECT fmt, format(-00345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +fmt format(-00345678901234567890, 3, fmt) +ar_AE -345,678,901,234,567,890.000 +ar_SA -345678901234567890.000 +be_BY -345.678.901.234.567.890,000 +de_DE -345.678.901.234.567.890,000 +en_IN -3,45,67,89,01,23,45,67,890.000 +en_US -345,678,901,234,567,890.000 +it_CH -345'678'901'234'567'890,000 +ru_RU -345 678 901 234 567 890,000 +ta_IN -3,45,67,89,01,23,45,67,890.000 +SELECT fmt, format(-00045678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +fmt format(-00045678901234567890, 3, fmt) +ar_AE -45,678,901,234,567,890.000 +ar_SA -45678901234567890.000 +be_BY -45.678.901.234.567.890,000 +de_DE -45.678.901.234.567.890,000 +en_IN -45,67,89,01,23,45,67,890.000 +en_US -45,678,901,234,567,890.000 +it_CH -45'678'901'234'567'890,000 +ru_RU -45 678 901 234 567 890,000 +ta_IN -45,67,89,01,23,45,67,890.000 +DROP TABLE t1; +SELECT format(123, 1, 'Non-existent-locale'); +format(123, 1, 'Non-existent-locale') +123.0 +Warnings: +Warning 1647 Unknown locale: 'Non-existent-locale' +End of 5.4 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 66b9eabd385..032c9ade643 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -1318,3 +1318,45 @@ insert into t1 values (-1),(null); explain select 1 as a from t1,(select decode(f1,f1) as b from t1) a; explain select 1 as a from t1,(select encode(f1,f1) as b from t1) a; drop table t1; + + + +--echo Start of 5.4 tests +# +# WL#4584 Internationalized number format +# +SELECT format(12345678901234567890.123, 3); +SELECT format(12345678901234567890.123, 3, NULL); +SELECT format(12345678901234567890.123, 3, 'ar_AE'); +SELECT format(12345678901234567890.123, 3, 'ar_SA'); +SELECT format(12345678901234567890.123, 3, 'be_BY'); +SELECT format(12345678901234567890.123, 3, 'de_DE'); +SELECT format(12345678901234567890.123, 3, 'en_IN'); +SELECT format(12345678901234567890.123, 3, 'en_US'); +SELECT format(12345678901234567890.123, 3, 'it_CH'); +SELECT format(12345678901234567890.123, 3, 'ru_RU'); +SELECT format(12345678901234567890.123, 3, 'ta_IN'); + +CREATE TABLE t1 (fmt CHAR(5) NOT NULL); +INSERT INTO t1 VALUES ('ar_AE'); +INSERT INTO t1 VALUES ('ar_SA'); +INSERT INTO t1 VALUES ('be_BY'); +INSERT INTO t1 VALUES ('de_DE'); +INSERT INTO t1 VALUES ('en_IN'); +INSERT INTO t1 VALUES ('en_US'); +INSERT INTO t1 VALUES ('it_CH'); +INSERT INTO t1 VALUES ('ru_RU'); +INSERT INTO t1 VALUES ('ta_IN'); +SELECT fmt, format(12345678901234567890.123, 3, fmt) FROM t1 ORDER BY fmt; +SELECT fmt, format(12345678901234567890.123, 0, fmt) FROM t1 ORDER BY fmt; +SELECT fmt, format(12345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +SELECT fmt, format(-12345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +SELECT fmt, format(-02345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +SELECT fmt, format(-00345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +SELECT fmt, format(-00045678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +DROP TABLE t1; + +SELECT format(123, 1, 'Non-existent-locale'); + +--echo End of 5.4 tests + diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 1580d7f36d7..a98163e026c 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -559,7 +559,7 @@ select @@lc_time_names; --echo *** LC_TIME_NAMES: testing with string expressions set lc_time_names=concat('de','_','DE'); select @@lc_time_names; ---error ER_UNKNOWN_ERROR +--error ER_UNKNOWN_LOCALE set lc_time_names=concat('de','+','DE'); select @@lc_time_names; --echo LC_TIME_NAMES: testing with numeric expressions @@ -572,14 +572,14 @@ set lc_time_names=en_US; --echo LC_TIME_NAMES: testing NULL and a negative number: --error ER_WRONG_VALUE_FOR_VAR set lc_time_names=NULL; ---error ER_UNKNOWN_ERROR +--error ER_UNKNOWN_LOCALE set lc_time_names=-1; select @@lc_time_names; --echo LC_TIME_NAMES: testing locale with the last ID: set lc_time_names=108; select @@lc_time_names; --echo LC_TIME_NAMES: testing a number beyond the valid ID range: ---error ER_UNKNOWN_ERROR +--error ER_UNKNOWN_LOCALE set lc_time_names=109; select @@lc_time_names; --echo LC_TIME_NAMES: testing that 0 is en_US: diff --git a/sql/item_create.cc b/sql/item_create.cc index 7991d9adf82..2f80d16b928 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -927,10 +927,10 @@ protected: }; -class Create_func_format : public Create_func_arg2 +class Create_func_format : public Create_native_func { public: - virtual Item *create(THD *thd, Item *arg1, Item *arg2); + virtual Item *create_native(THD *thd, LEX_STRING name, List *item_list); static Create_func_format s_singleton; @@ -3352,9 +3352,34 @@ Create_func_floor::create(THD *thd, Item *arg1) Create_func_format Create_func_format::s_singleton; Item* -Create_func_format::create(THD *thd, Item *arg1, Item *arg2) +Create_func_format::create_native(THD *thd, LEX_STRING name, + List *item_list) { - return new (thd->mem_root) Item_func_format(arg1, arg2); + Item *func= NULL; + int arg_count= item_list ? item_list->elements : 0; + + switch (arg_count) { + case 2: + { + Item *param_1= item_list->pop(); + Item *param_2= item_list->pop(); + func= new (thd->mem_root) Item_func_format(param_1, param_2); + break; + } + case 3: + { + Item *param_1= item_list->pop(); + Item *param_2= item_list->pop(); + Item *param_3= item_list->pop(); + func= new (thd->mem_root) Item_func_format(param_1, param_2, param_3); + break; + } + default: + my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); + break; + } + + return func; } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 7a4ffedac10..d4ef55e5609 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2040,9 +2040,22 @@ String *Item_func_soundex::val_str(String *str) const int FORMAT_MAX_DECIMALS= 30; -Item_func_format::Item_func_format(Item *org, Item *dec) -: Item_str_func(org, dec) + +MY_LOCALE *Item_func_format::get_locale(Item *item) { + DBUG_ASSERT(arg_count == 3); + String tmp, *locale_name= args[2]->val_str(&tmp); + MY_LOCALE *lc; + if (!locale_name || + !(lc= my_locale_by_name(locale_name->c_ptr_safe()))) + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_UNKNOWN_LOCALE, + ER(ER_UNKNOWN_LOCALE), + locale_name ? locale_name->c_ptr_safe() : "NULL"); + lc= &my_locale_en_US; + } + return lc; } void Item_func_format::fix_length_and_dec() @@ -2052,6 +2065,10 @@ void Item_func_format::fix_length_and_dec() collation.set(default_charset()); max_length= (char_length + max_sep_count + decimals) * collation.collation->mbmaxlen; + if (arg_count == 3) + locale= args[2]->basic_const_item() ? get_locale(args[2]) : NULL; + else + locale= &my_locale_en_US; /* Two arguments */ } @@ -2063,13 +2080,12 @@ void Item_func_format::fix_length_and_dec() String *Item_func_format::val_str(String *str) { - uint32 length; uint32 str_length; /* Number of decimal digits */ int dec; /* Number of characters used to represent the decimals, including '.' */ uint32 dec_length; - int diff; + MY_LOCALE *lc; DBUG_ASSERT(fixed == 1); dec= (int) args[1]->val_int(); @@ -2079,6 +2095,8 @@ String *Item_func_format::val_str(String *str) return NULL; } + lc= locale ? locale : get_locale(args[2]); + dec= set_zone(dec, 0, FORMAT_MAX_DECIMALS); dec_length= dec ? dec+1 : 0; null_value=0; @@ -2093,8 +2111,6 @@ String *Item_func_format::val_str(String *str) my_decimal_round(E_DEC_FATAL_ERROR, res, dec, false, &rnd_dec); my_decimal2string(E_DEC_FATAL_ERROR, &rnd_dec, 0, 0, 0, str); str_length= str->length(); - if (rnd_dec.sign()) - str_length--; } else { @@ -2107,31 +2123,51 @@ String *Item_func_format::val_str(String *str) if (isnan(nr)) return str; str_length=str->length(); - if (nr < 0) - str_length--; // Don't count sign } - /* We need this test to handle 'nan' values */ - if (str_length >= dec_length+4) + /* We need this test to handle 'nan' and short values */ + if (lc->grouping[0] > 0 && + str_length >= dec_length + 1 + lc->grouping[0]) { - char *tmp,*pos; - length= str->length()+(diff=((int)(str_length- dec_length-1))/3); - str= copy_if_not_alloced(&tmp_str,str,length); - str->length(length); - tmp= (char*) str->ptr()+length - dec_length-1; - for (pos= (char*) str->ptr()+length-1; pos != tmp; pos--) - pos[0]= pos[-diff]; - while (diff) + char buf[DECIMAL_MAX_STR_LENGTH * 2]; /* 2 - in the worst case when grouping=1 */ + int count; + const char *grouping= lc->grouping; + char sign_length= *str->ptr() == '-' ? 1 : 0; + const char *src= str->ptr() + str_length - dec_length - 1; + const char *src_begin= str->ptr() + sign_length; + char *dst= buf + sizeof(buf); + + /* Put the fractional part */ + if (dec) { - *pos= *(pos - diff); - pos--; - *pos= *(pos - diff); - pos--; - *pos= *(pos - diff); - pos--; - pos[0]=','; - pos--; - diff--; + dst-= (dec + 1); + *dst= lc->decimal_point; + memcpy(dst + 1, src + 2, dec); } + + /* Put the integer part with grouping */ + for (count= *grouping; src >= src_begin; count--) + { + /* + When *grouping==0x80 (which means "end of grouping") + count will be initialized to -1 and + we'll never get into this "if" anymore. + */ + if (!count) + { + *--dst= lc->thousand_sep; + if (grouping[1]) + grouping++; + count= *grouping; + } + DBUG_ASSERT(dst > buf); + *--dst= *src--; + } + + if (sign_length) /* Put '-' */ + *--dst= *str->ptr(); + + /* Put the rest of the integer part without grouping */ + str->copy(dst, buf + sizeof(buf) - dst, &my_charset_latin1); } return str; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 2cdb45100ae..87d8c7bd438 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -498,8 +498,13 @@ public: class Item_func_format :public Item_str_func { String tmp_str; + MY_LOCALE *locale; public: - Item_func_format(Item *org, Item *dec); + Item_func_format(Item *org, Item *dec): Item_str_func(org, dec) {} + Item_func_format(Item *org, Item *dec, Item *lang): + Item_str_func(org, dec, lang) {} + + MY_LOCALE *get_locale(Item *item); String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "format"; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index f5e43c5100a..fc0c688610b 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -156,18 +156,26 @@ typedef struct my_locale_st TYPELIB *ab_day_names; uint max_month_name_length; uint max_day_name_length; + uint decimal_point; + uint thousand_sep; + const char *grouping; #ifdef __cplusplus my_locale_st(uint number_par, const char *name_par, const char *descr_par, bool is_ascii_par, TYPELIB *month_names_par, TYPELIB *ab_month_names_par, TYPELIB *day_names_par, TYPELIB *ab_day_names_par, - uint max_month_name_length_par, uint max_day_name_length_par) : + uint max_month_name_length_par, uint max_day_name_length_par, + uint decimal_point_par, uint thousand_sep_par, + const char *grouping_par) : number(number_par), name(name_par), description(descr_par), is_ascii(is_ascii_par), month_names(month_names_par), ab_month_names(ab_month_names_par), day_names(day_names_par), ab_day_names(ab_day_names_par), max_month_name_length(max_month_name_length_par), - max_day_name_length(max_day_name_length_par) + max_day_name_length(max_day_name_length_par), + decimal_point(decimal_point_par), + thousand_sep(thousand_sep_par), + grouping(grouping_par) {} #endif } MY_LOCALE; diff --git a/sql/set_var.cc b/sql/set_var.cc index 2e2bb369af1..def0be4aff4 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2916,7 +2916,7 @@ bool sys_var_thd_lc_time_names::check(THD *thd, set_var *var) { char buf[20]; int10_to_str((int) var->value->val_int(), buf, -10); - my_printf_error(ER_UNKNOWN_ERROR, "Unknown locale: '%s'", MYF(0), buf); + my_printf_error(ER_UNKNOWN_LOCALE, ER(ER_UNKNOWN_LOCALE), MYF(0), buf); return 1; } } @@ -2932,8 +2932,7 @@ bool sys_var_thd_lc_time_names::check(THD *thd, set_var *var) const char *locale_str= res->c_ptr(); if (!(locale_match= my_locale_by_name(locale_str))) { - my_printf_error(ER_UNKNOWN_ERROR, - "Unknown locale: '%s'", MYF(0), locale_str); + my_printf_error(ER_UNKNOWN_LOCALE, ER(ER_UNKNOWN_LOCALE), MYF(0), locale_str); return 1; } } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 49707f09ca5..a98b3af5dd5 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6228,3 +6228,5 @@ WARN_COND_ITEM_TRUNCATED ER_COND_ITEM_TOO_LONG eng "Data too long for condition item '%s'" +ER_UNKNOWN_LOCALE + eng "Unknown locale: '%-.64s'" diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc index 3def9864c29..b59c3f16735 100644 --- a/sql/sql_locale.cc +++ b/sql/sql_locale.cc @@ -51,7 +51,10 @@ MY_LOCALE my_locale_ar_AE &my_locale_typelib_day_names_ar_AE, &my_locale_typelib_ab_day_names_ar_AE, 6, - 8 + 8, + '.', /* decimal point ar_AE */ + ',', /* thousands_sep ar_AE */ + "\x03" /* grouping ar_AE */ ); /***** LOCALE END ar_AE *****/ @@ -83,7 +86,10 @@ MY_LOCALE my_locale_ar_BH &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_BH */ + ',', /* thousands_sep ar_BH */ + "\x03" /* grouping ar_BH */ ); /***** LOCALE END ar_BH *****/ @@ -115,7 +121,10 @@ MY_LOCALE my_locale_ar_JO &my_locale_typelib_day_names_ar_JO, &my_locale_typelib_ab_day_names_ar_JO, 12, - 8 + 8, + '.', /* decimal point ar_JO */ + ',', /* thousands_sep ar_JO */ + "\x03" /* grouping ar_JO */ ); /***** LOCALE END ar_JO *****/ @@ -147,7 +156,10 @@ MY_LOCALE my_locale_ar_SA &my_locale_typelib_day_names_ar_SA, &my_locale_typelib_ab_day_names_ar_SA, 12, - 8 + 8, + '.', /* decimal point ar_SA */ + '\0', /* thousands_sep ar_SA */ + "\x80" /* grouping ar_SA */ ); /***** LOCALE END ar_SA *****/ @@ -179,7 +191,10 @@ MY_LOCALE my_locale_ar_SY &my_locale_typelib_day_names_ar_SY, &my_locale_typelib_ab_day_names_ar_SY, 12, - 8 + 8, + '.', /* decimal point ar_SY */ + ',', /* thousands_sep ar_SY */ + "\x03" /* grouping ar_SY */ ); /***** LOCALE END ar_SY *****/ @@ -211,7 +226,10 @@ MY_LOCALE my_locale_be_BY &my_locale_typelib_day_names_be_BY, &my_locale_typelib_ab_day_names_be_BY, 10, - 10 + 10, + ',', /* decimal point be_BY */ + '.', /* thousands_sep be_BY */ + "\x03\x03" /* grouping be_BY */ ); /***** LOCALE END be_BY *****/ @@ -243,7 +261,10 @@ MY_LOCALE my_locale_bg_BG &my_locale_typelib_day_names_bg_BG, &my_locale_typelib_ab_day_names_bg_BG, 9, - 10 + 10, + ',', /* decimal point bg_BG */ + '\0', /* thousands_sep bg_BG */ + "\x03\x03" /* grouping bg_BG */ ); /***** LOCALE END bg_BG *****/ @@ -275,7 +296,11 @@ MY_LOCALE my_locale_ca_ES &my_locale_typelib_day_names_ca_ES, &my_locale_typelib_ab_day_names_ca_ES, 8, - 9 + 9, + ',', /* decimal point ca_ES */ + '\0', /* thousands_sep ca_ES */ + "\x80\x80" /* grouping ca_ES */ + ); /***** LOCALE END ca_ES *****/ @@ -307,7 +332,10 @@ MY_LOCALE my_locale_cs_CZ &my_locale_typelib_day_names_cs_CZ, &my_locale_typelib_ab_day_names_cs_CZ, 8, - 7 + 7, + ',', /* decimal point cs_CZ */ + ' ', /* thousands_sep cs_CZ */ + "\x03\x03" /* grouping cs_CZ */ ); /***** LOCALE END cs_CZ *****/ @@ -339,7 +367,10 @@ MY_LOCALE my_locale_da_DK &my_locale_typelib_day_names_da_DK, &my_locale_typelib_ab_day_names_da_DK, 9, - 7 + 7, + ',', /* decimal point da_DK */ + '.', /* thousands_sep da_DK */ + "\x03\x03" /* grouping da_DK */ ); /***** LOCALE END da_DK *****/ @@ -371,7 +402,10 @@ MY_LOCALE my_locale_de_AT &my_locale_typelib_day_names_de_AT, &my_locale_typelib_ab_day_names_de_AT, 9, - 10 + 10, + ',', /* decimal point de_AT */ + '\0', /* thousands_sep de_AT */ + "\x80\x80" /* grouping de_AT */ ); /***** LOCALE END de_AT *****/ @@ -403,7 +437,10 @@ MY_LOCALE my_locale_de_DE &my_locale_typelib_day_names_de_DE, &my_locale_typelib_ab_day_names_de_DE, 9, - 10 + 10, + ',', /* decimal point de_DE */ + '.', /* thousands_sep de_DE */ + "\x03\x03" /* grouping de_DE */ ); /***** LOCALE END de_DE *****/ @@ -435,7 +472,10 @@ MY_LOCALE my_locale_en_US &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_US */ + ',', /* thousands_sep en_US */ + "\x03\x03" /* grouping en_US */ ); /***** LOCALE END en_US *****/ @@ -467,7 +507,10 @@ MY_LOCALE my_locale_es_ES &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_ES */ + '\0', /* thousands_sep es_ES */ + "\x80\x80" /* grouping es_ES */ ); /***** LOCALE END es_ES *****/ @@ -499,7 +542,10 @@ MY_LOCALE my_locale_et_EE &my_locale_typelib_day_names_et_EE, &my_locale_typelib_ab_day_names_et_EE, 9, - 9 + 9, + ',', /* decimal point et_EE */ + ' ', /* thousands_sep et_EE */ + "\x03\x03" /* grouping et_EE */ ); /***** LOCALE END et_EE *****/ @@ -531,7 +577,10 @@ MY_LOCALE my_locale_eu_ES &my_locale_typelib_day_names_eu_ES, &my_locale_typelib_ab_day_names_eu_ES, 9, - 10 + 10, + ',', /* decimal point eu_ES */ + '\0', /* thousands_sep eu_ES */ + "\x80\x80" /* grouping eu_ES */ ); /***** LOCALE END eu_ES *****/ @@ -563,7 +612,10 @@ MY_LOCALE my_locale_fi_FI &my_locale_typelib_day_names_fi_FI, &my_locale_typelib_ab_day_names_fi_FI, 9, - 11 + 11, + ',', /* decimal point fi_FI */ + ' ', /* thousands_sep fi_FI */ + "\x03\x03" /* grouping fi_FI */ ); /***** LOCALE END fi_FI *****/ @@ -595,7 +647,10 @@ MY_LOCALE my_locale_fo_FO &my_locale_typelib_day_names_fo_FO, &my_locale_typelib_ab_day_names_fo_FO, 9, - 12 + 12, + ',', /* decimal point fo_FO */ + '.', /* thousands_sep fo_FO */ + "\x03\x03" /* grouping fo_FO */ ); /***** LOCALE END fo_FO *****/ @@ -627,7 +682,10 @@ MY_LOCALE my_locale_fr_FR &my_locale_typelib_day_names_fr_FR, &my_locale_typelib_ab_day_names_fr_FR, 9, - 8 + 8, + ',', /* decimal point fr_FR */ + '\0', /* thousands_sep fr_FR */ + "\x80\x80" /* grouping fr_FR */ ); /***** LOCALE END fr_FR *****/ @@ -659,7 +717,10 @@ MY_LOCALE my_locale_gl_ES &my_locale_typelib_day_names_gl_ES, &my_locale_typelib_ab_day_names_gl_ES, 8, - 8 + 8, + ',', /* decimal point gl_ES */ + '\0', /* thousands_sep gl_ES */ + "\x80\x80" /* grouping gl_ES */ ); /***** LOCALE END gl_ES *****/ @@ -691,7 +752,10 @@ MY_LOCALE my_locale_gu_IN &my_locale_typelib_day_names_gu_IN, &my_locale_typelib_ab_day_names_gu_IN, 10, - 8 + 8, + '.', /* decimal point gu_IN */ + ',', /* thousands_sep gu_IN */ + "\x03" /* grouping gu_IN */ ); /***** LOCALE END gu_IN *****/ @@ -723,7 +787,10 @@ MY_LOCALE my_locale_he_IL &my_locale_typelib_day_names_he_IL, &my_locale_typelib_ab_day_names_he_IL, 7, - 5 + 5, + '.', /* decimal point he_IL */ + ',', /* thousands_sep he_IL */ + "\x03\x03" /* grouping he_IL */ ); /***** LOCALE END he_IL *****/ @@ -755,7 +822,10 @@ MY_LOCALE my_locale_hi_IN &my_locale_typelib_day_names_hi_IN, &my_locale_typelib_ab_day_names_hi_IN, 7, - 9 + 9, + '.', /* decimal point hi_IN */ + ',', /* thousands_sep hi_IN */ + "\x03" /* grouping hi_IN */ ); /***** LOCALE END hi_IN *****/ @@ -787,7 +857,10 @@ MY_LOCALE my_locale_hr_HR &my_locale_typelib_day_names_hr_HR, &my_locale_typelib_ab_day_names_hr_HR, 8, - 11 + 11, + ',', /* decimal point hr_HR */ + '\0', /* thousands_sep hr_HR */ + "\x80\x80" /* grouping hr_HR */ ); /***** LOCALE END hr_HR *****/ @@ -819,7 +892,10 @@ MY_LOCALE my_locale_hu_HU &my_locale_typelib_day_names_hu_HU, &my_locale_typelib_ab_day_names_hu_HU, 10, - 9 + 9, + ',', /* decimal point hu_HU */ + '.', /* thousands_sep hu_HU */ + "\x03\x03" /* grouping hu_HU */ ); /***** LOCALE END hu_HU *****/ @@ -851,7 +927,10 @@ MY_LOCALE my_locale_id_ID &my_locale_typelib_day_names_id_ID, &my_locale_typelib_ab_day_names_id_ID, 9, - 6 + 6, + ',', /* decimal point id_ID */ + '.', /* thousands_sep id_ID */ + "\x03\x03" /* grouping id_ID */ ); /***** LOCALE END id_ID *****/ @@ -883,7 +962,10 @@ MY_LOCALE my_locale_is_IS &my_locale_typelib_day_names_is_IS, &my_locale_typelib_ab_day_names_is_IS, 9, - 12 + 12, + ',', /* decimal point is_IS */ + '.', /* thousands_sep is_IS */ + "\x03\x03" /* grouping is_IS */ ); /***** LOCALE END is_IS *****/ @@ -915,7 +997,10 @@ MY_LOCALE my_locale_it_CH &my_locale_typelib_day_names_it_CH, &my_locale_typelib_ab_day_names_it_CH, 9, - 9 + 9, + ',', /* decimal point it_CH */ + '\'', /* thousands_sep it_CH */ + "\x03\x03" /* grouping it_CH */ ); /***** LOCALE END it_CH *****/ @@ -947,7 +1032,10 @@ MY_LOCALE my_locale_ja_JP &my_locale_typelib_day_names_ja_JP, &my_locale_typelib_ab_day_names_ja_JP, 3, - 3 + 3, + '.', /* decimal point ja_JP */ + ',', /* thousands_sep ja_JP */ + "\x03" /* grouping ja_JP */ ); /***** LOCALE END ja_JP *****/ @@ -979,7 +1067,10 @@ MY_LOCALE my_locale_ko_KR &my_locale_typelib_day_names_ko_KR, &my_locale_typelib_ab_day_names_ko_KR, 3, - 3 + 3, + '.', /* decimal point ko_KR */ + ',', /* thousands_sep ko_KR */ + "\x03\x03" /* grouping ko_KR */ ); /***** LOCALE END ko_KR *****/ @@ -1011,7 +1102,10 @@ MY_LOCALE my_locale_lt_LT &my_locale_typelib_day_names_lt_LT, &my_locale_typelib_ab_day_names_lt_LT, 9, - 14 + 14, + ',', /* decimal point lt_LT */ + '.', /* thousands_sep lt_LT */ + "\x03\x03" /* grouping lt_LT */ ); /***** LOCALE END lt_LT *****/ @@ -1043,7 +1137,10 @@ MY_LOCALE my_locale_lv_LV &my_locale_typelib_day_names_lv_LV, &my_locale_typelib_ab_day_names_lv_LV, 10, - 11 + 11, + ',', /* decimal point lv_LV */ + ' ', /* thousands_sep lv_LV */ + "\x03\x03" /* grouping lv_LV */ ); /***** LOCALE END lv_LV *****/ @@ -1075,7 +1172,10 @@ MY_LOCALE my_locale_mk_MK &my_locale_typelib_day_names_mk_MK, &my_locale_typelib_ab_day_names_mk_MK, 9, - 10 + 10, + ',', /* decimal point mk_MK */ + ' ', /* thousands_sep mk_MK */ + "\x03\x03" /* grouping mk_MK */ ); /***** LOCALE END mk_MK *****/ @@ -1107,7 +1207,10 @@ MY_LOCALE my_locale_mn_MN &my_locale_typelib_day_names_mn_MN, &my_locale_typelib_ab_day_names_mn_MN, 18, - 6 + 6, + ',', /* decimal point mn_MN */ + '.', /* thousands_sep mn_MN */ + "\x03\x03" /* grouping mn_MN */ ); /***** LOCALE END mn_MN *****/ @@ -1139,7 +1242,10 @@ MY_LOCALE my_locale_ms_MY &my_locale_typelib_day_names_ms_MY, &my_locale_typelib_ab_day_names_ms_MY, 9, - 6 + 6, + '.', /* decimal point ms_MY */ + ',', /* thousands_sep ms_MY */ + "\x03" /* grouping ms_MY */ ); /***** LOCALE END ms_MY *****/ @@ -1171,7 +1277,10 @@ MY_LOCALE my_locale_nb_NO &my_locale_typelib_day_names_nb_NO, &my_locale_typelib_ab_day_names_nb_NO, 9, - 7 + 7, + ',', /* decimal point nb_NO */ + '.', /* thousands_sep nb_NO */ + "\x03\x03" /* grouping nb_NO */ ); /***** LOCALE END nb_NO *****/ @@ -1203,7 +1312,10 @@ MY_LOCALE my_locale_nl_NL &my_locale_typelib_day_names_nl_NL, &my_locale_typelib_ab_day_names_nl_NL, 9, - 9 + 9, + ',', /* decimal point nl_NL */ + '\0', /* thousands_sep nl_NL */ + "\x80\x80" /* grouping nl_NL */ ); /***** LOCALE END nl_NL *****/ @@ -1235,7 +1347,10 @@ MY_LOCALE my_locale_pl_PL &my_locale_typelib_day_names_pl_PL, &my_locale_typelib_ab_day_names_pl_PL, 11, - 12 + 12, + ',', /* decimal point pl_PL */ + '\0', /* thousands_sep pl_PL */ + "\x80\x80" /* grouping pl_PL */ ); /***** LOCALE END pl_PL *****/ @@ -1267,7 +1382,10 @@ MY_LOCALE my_locale_pt_BR &my_locale_typelib_day_names_pt_BR, &my_locale_typelib_ab_day_names_pt_BR, 9, - 7 + 7, + ',', /* decimal point pt_BR */ + '\0', /* thousands_sep pt_BR */ + "\x80\x80" /* grouping pt_BR */ ); /***** LOCALE END pt_BR *****/ @@ -1299,7 +1417,10 @@ MY_LOCALE my_locale_pt_PT &my_locale_typelib_day_names_pt_PT, &my_locale_typelib_ab_day_names_pt_PT, 9, - 7 + 7, + ',', /* decimal point pt_PT */ + '\0', /* thousands_sep pt_PT */ + "\x80\x80" /* grouping pt_PT */ ); /***** LOCALE END pt_PT *****/ @@ -1331,7 +1452,10 @@ MY_LOCALE my_locale_ro_RO &my_locale_typelib_day_names_ro_RO, &my_locale_typelib_ab_day_names_ro_RO, 10, - 8 + 8, + ',', /* decimal point ro_RO */ + '.', /* thousands_sep ro_RO */ + "\x03\x03" /* grouping ro_RO */ ); /***** LOCALE END ro_RO *****/ @@ -1363,7 +1487,10 @@ MY_LOCALE my_locale_ru_RU &my_locale_typelib_day_names_ru_RU, &my_locale_typelib_ab_day_names_ru_RU, 8, - 11 + 11, + ',', /* decimal point ru_RU */ + ' ', /* thousands_sep ru_RU */ + "\x03\x03" /* grouping ru_RU */ ); /***** LOCALE END ru_RU *****/ @@ -1395,7 +1522,10 @@ MY_LOCALE my_locale_ru_UA &my_locale_typelib_day_names_ru_UA, &my_locale_typelib_ab_day_names_ru_UA, 8, - 11 + 11, + ',', /* decimal point ru_UA */ + '.', /* thousands_sep ru_UA */ + "\x03\x03" /* grouping ru_UA */ ); /***** LOCALE END ru_UA *****/ @@ -1427,7 +1557,10 @@ MY_LOCALE my_locale_sk_SK &my_locale_typelib_day_names_sk_SK, &my_locale_typelib_ab_day_names_sk_SK, 9, - 8 + 8, + ',', /* decimal point sk_SK */ + ' ', /* thousands_sep sk_SK */ + "\x03\x03" /* grouping sk_SK */ ); /***** LOCALE END sk_SK *****/ @@ -1459,7 +1592,10 @@ MY_LOCALE my_locale_sl_SI &my_locale_typelib_day_names_sl_SI, &my_locale_typelib_ab_day_names_sl_SI, 9, - 10 + 10, + ',', /* decimal point sl_SI */ + ' ', /* thousands_sep sl_SI */ + "\x80\x80" /* grouping sl_SI */ ); /***** LOCALE END sl_SI *****/ @@ -1491,7 +1627,10 @@ MY_LOCALE my_locale_sq_AL &my_locale_typelib_day_names_sq_AL, &my_locale_typelib_ab_day_names_sq_AL, 7, - 10 + 10, + ',', /* decimal point sq_AL */ + '.', /* thousands_sep sq_AL */ + "\x03" /* grouping sq_AL */ ); /***** LOCALE END sq_AL *****/ @@ -1523,7 +1662,10 @@ MY_LOCALE my_locale_sr_YU &my_locale_typelib_day_names_sr_YU, &my_locale_typelib_ab_day_names_sr_YU, 9, - 10 + 10, + '.', /* decimal point sr_YU */ + '\0', /* thousands_sep sr_YU */ + "\x80" /* grouping sr_YU */ ); /***** LOCALE END sr_YU *****/ @@ -1555,7 +1697,10 @@ MY_LOCALE my_locale_sv_SE &my_locale_typelib_day_names_sv_SE, &my_locale_typelib_ab_day_names_sv_SE, 9, - 7 + 7, + ',', /* decimal point sv_SE */ + ' ', /* thousands_sep sv_SE */ + "\x03\x03" /* grouping sv_SE */ ); /***** LOCALE END sv_SE *****/ @@ -1587,7 +1732,10 @@ MY_LOCALE my_locale_ta_IN &my_locale_typelib_day_names_ta_IN, &my_locale_typelib_ab_day_names_ta_IN, 10, - 8 + 8, + '.', /* decimal point ta_IN */ + ',', /* thousands_sep ta_IN */ + "\x03\x02" /* grouping ta_IN */ ); /***** LOCALE END ta_IN *****/ @@ -1619,7 +1767,10 @@ MY_LOCALE my_locale_te_IN &my_locale_typelib_day_names_te_IN, &my_locale_typelib_ab_day_names_te_IN, 10, - 9 + 9, + '.', /* decimal point te_IN */ + ',', /* thousands_sep te_IN */ + "\x03\x02" /* grouping te_IN */ ); /***** LOCALE END te_IN *****/ @@ -1651,7 +1802,10 @@ MY_LOCALE my_locale_th_TH &my_locale_typelib_day_names_th_TH, &my_locale_typelib_ab_day_names_th_TH, 10, - 8 + 8, + '.', /* decimal point th_TH */ + ',', /* thousands_sep th_TH */ + "\x03" /* grouping th_TH */ ); /***** LOCALE END th_TH *****/ @@ -1683,7 +1837,10 @@ MY_LOCALE my_locale_tr_TR &my_locale_typelib_day_names_tr_TR, &my_locale_typelib_ab_day_names_tr_TR, 7, - 9 + 9, + ',', /* decimal point tr_TR */ + '.', /* thousands_sep tr_TR */ + "\x03\x03" /* grouping tr_TR */ ); /***** LOCALE END tr_TR *****/ @@ -1715,7 +1872,10 @@ MY_LOCALE my_locale_uk_UA &my_locale_typelib_day_names_uk_UA, &my_locale_typelib_ab_day_names_uk_UA, 8, - 9 + 9, + ',', /* decimal point uk_UA */ + '.', /* thousands_sep uk_UA */ + "\x03\x03" /* grouping uk_UA */ ); /***** LOCALE END uk_UA *****/ @@ -1747,7 +1907,10 @@ MY_LOCALE my_locale_ur_PK &my_locale_typelib_day_names_ur_PK, &my_locale_typelib_ab_day_names_ur_PK, 6, - 6 + 6, + '.', /* decimal point ur_PK */ + ',', /* thousands_sep ur_PK */ + "\x03\x03" /* grouping ur_PK */ ); /***** LOCALE END ur_PK *****/ @@ -1779,7 +1942,10 @@ MY_LOCALE my_locale_vi_VN &my_locale_typelib_day_names_vi_VN, &my_locale_typelib_ab_day_names_vi_VN, 16, - 11 + 11, + ',', /* decimal point vi_VN */ + '.', /* thousands_sep vi_VN */ + "\x03\x03" /* grouping vi_VN */ ); /***** LOCALE END vi_VN *****/ @@ -1811,7 +1977,10 @@ MY_LOCALE my_locale_zh_CN &my_locale_typelib_day_names_zh_CN, &my_locale_typelib_ab_day_names_zh_CN, 3, - 3 + 3, + '.', /* decimal point zh_CN */ + ',', /* thousands_sep zh_CN */ + "\x03" /* grouping zh_CN */ ); /***** LOCALE END zh_CN *****/ @@ -1843,7 +2012,10 @@ MY_LOCALE my_locale_zh_TW &my_locale_typelib_day_names_zh_TW, &my_locale_typelib_ab_day_names_zh_TW, 3, - 2 + 2, + '.', /* decimal point zh_TW */ + ',', /* thousands_sep zh_TW */ + "\x03" /* grouping zh_TW */ ); /***** LOCALE END zh_TW *****/ @@ -1859,7 +2031,10 @@ MY_LOCALE my_locale_ar_DZ &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_DZ */ + ',', /* thousands_sep ar_DZ */ + "\x03" /* grouping ar_DZ */ ); /***** LOCALE END ar_DZ *****/ @@ -1875,7 +2050,10 @@ MY_LOCALE my_locale_ar_EG &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_EG */ + ',', /* thousands_sep ar_EG */ + "\x03" /* grouping ar_EG */ ); /***** LOCALE END ar_EG *****/ @@ -1891,7 +2069,10 @@ MY_LOCALE my_locale_ar_IN &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_IN */ + ',', /* thousands_sep ar_IN */ + "\x03" /* grouping ar_IN */ ); /***** LOCALE END ar_IN *****/ @@ -1907,7 +2088,10 @@ MY_LOCALE my_locale_ar_IQ &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_IQ */ + ',', /* thousands_sep ar_IQ */ + "\x03" /* grouping ar_IQ */ ); /***** LOCALE END ar_IQ *****/ @@ -1923,7 +2107,10 @@ MY_LOCALE my_locale_ar_KW &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_KW */ + ',', /* thousands_sep ar_KW */ + "\x03" /* grouping ar_KW */ ); /***** LOCALE END ar_KW *****/ @@ -1939,7 +2126,10 @@ MY_LOCALE my_locale_ar_LB &my_locale_typelib_day_names_ar_JO, &my_locale_typelib_ab_day_names_ar_JO, 12, - 8 + 8, + '.', /* decimal point ar_LB */ + ',', /* thousands_sep ar_LB */ + "\x03" /* grouping ar_LB */ ); /***** LOCALE END ar_LB *****/ @@ -1955,7 +2145,10 @@ MY_LOCALE my_locale_ar_LY &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_LY */ + ',', /* thousands_sep ar_LY */ + "\x03" /* grouping ar_LY */ ); /***** LOCALE END ar_LY *****/ @@ -1971,7 +2164,10 @@ MY_LOCALE my_locale_ar_MA &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_MA */ + ',', /* thousands_sep ar_MA */ + "\x03" /* grouping ar_MA */ ); /***** LOCALE END ar_MA *****/ @@ -1987,7 +2183,10 @@ MY_LOCALE my_locale_ar_OM &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_OM */ + ',', /* thousands_sep ar_OM */ + "\x03" /* grouping ar_OM */ ); /***** LOCALE END ar_OM *****/ @@ -2003,7 +2202,10 @@ MY_LOCALE my_locale_ar_QA &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_QA */ + ',', /* thousands_sep ar_QA */ + "\x03" /* grouping ar_QA */ ); /***** LOCALE END ar_QA *****/ @@ -2019,7 +2221,10 @@ MY_LOCALE my_locale_ar_SD &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_SD */ + ',', /* thousands_sep ar_SD */ + "\x03" /* grouping ar_SD */ ); /***** LOCALE END ar_SD *****/ @@ -2035,7 +2240,10 @@ MY_LOCALE my_locale_ar_TN &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_TN */ + ',', /* thousands_sep ar_TN */ + "\x03" /* grouping ar_TN */ ); /***** LOCALE END ar_TN *****/ @@ -2051,7 +2259,10 @@ MY_LOCALE my_locale_ar_YE &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_YE */ + ',', /* thousands_sep ar_YE */ + "\x03" /* grouping ar_YE */ ); /***** LOCALE END ar_YE *****/ @@ -2067,7 +2278,10 @@ MY_LOCALE my_locale_de_BE &my_locale_typelib_day_names_de_DE, &my_locale_typelib_ab_day_names_de_DE, 9, - 10 + 10, + ',', /* decimal point de_BE */ + '.', /* thousands_sep de_BE */ + "\x03\x03" /* grouping de_BE */ ); /***** LOCALE END de_BE *****/ @@ -2083,7 +2297,10 @@ MY_LOCALE my_locale_de_CH &my_locale_typelib_day_names_de_DE, &my_locale_typelib_ab_day_names_de_DE, 9, - 10 + 10, + '.', /* decimal point de_CH */ + '\'', /* thousands_sep de_CH */ + "\x03\x03" /* grouping de_CH */ ); /***** LOCALE END de_CH *****/ @@ -2099,7 +2316,10 @@ MY_LOCALE my_locale_de_LU &my_locale_typelib_day_names_de_DE, &my_locale_typelib_ab_day_names_de_DE, 9, - 10 + 10, + ',', /* decimal point de_LU */ + '.', /* thousands_sep de_LU */ + "\x03\x03" /* grouping de_LU */ ); /***** LOCALE END de_LU *****/ @@ -2115,7 +2335,10 @@ MY_LOCALE my_locale_en_AU &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_AU */ + ',', /* thousands_sep en_AU */ + "\x03\x03" /* grouping en_AU */ ); /***** LOCALE END en_AU *****/ @@ -2131,7 +2354,10 @@ MY_LOCALE my_locale_en_CA &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_CA */ + ',', /* thousands_sep en_CA */ + "\x03\x03" /* grouping en_CA */ ); /***** LOCALE END en_CA *****/ @@ -2147,7 +2373,10 @@ MY_LOCALE my_locale_en_GB &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_GB */ + ',', /* thousands_sep en_GB */ + "\x03\x03" /* grouping en_GB */ ); /***** LOCALE END en_GB *****/ @@ -2163,7 +2392,10 @@ MY_LOCALE my_locale_en_IN &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_IN */ + ',', /* thousands_sep en_IN */ + "\x03\x02" /* grouping en_IN */ ); /***** LOCALE END en_IN *****/ @@ -2179,7 +2411,10 @@ MY_LOCALE my_locale_en_NZ &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_NZ */ + ',', /* thousands_sep en_NZ */ + "\x03\x03" /* grouping en_NZ */ ); /***** LOCALE END en_NZ *****/ @@ -2195,7 +2430,10 @@ MY_LOCALE my_locale_en_PH &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_PH */ + ',', /* thousands_sep en_PH */ + "\x03" /* grouping en_PH */ ); /***** LOCALE END en_PH *****/ @@ -2211,7 +2449,10 @@ MY_LOCALE my_locale_en_ZA &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_ZA */ + ',', /* thousands_sep en_ZA */ + "\x03\x03" /* grouping en_ZA */ ); /***** LOCALE END en_ZA *****/ @@ -2227,7 +2468,10 @@ MY_LOCALE my_locale_en_ZW &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_ZW */ + ',', /* thousands_sep en_ZW */ + "\x03\x03" /* grouping en_ZW */ ); /***** LOCALE END en_ZW *****/ @@ -2243,7 +2487,10 @@ MY_LOCALE my_locale_es_AR &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_AR */ + '.', /* thousands_sep es_AR */ + "\x03\x03" /* grouping es_AR */ ); /***** LOCALE END es_AR *****/ @@ -2259,7 +2506,10 @@ MY_LOCALE my_locale_es_BO &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_BO */ + '\0', /* thousands_sep es_BO */ + "\x80\x80" /* grouping es_BO */ ); /***** LOCALE END es_BO *****/ @@ -2275,7 +2525,10 @@ MY_LOCALE my_locale_es_CL &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_CL */ + '\0', /* thousands_sep es_CL */ + "\x80\x80" /* grouping es_CL */ ); /***** LOCALE END es_CL *****/ @@ -2291,7 +2544,10 @@ MY_LOCALE my_locale_es_CO &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_CO */ + '\0', /* thousands_sep es_CO */ + "\x80\x80" /* grouping es_CO */ ); /***** LOCALE END es_CO *****/ @@ -2307,7 +2563,10 @@ MY_LOCALE my_locale_es_CR &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_CR */ + '\0', /* thousands_sep es_CR */ + "\x80\x80" /* grouping es_CR */ ); /***** LOCALE END es_CR *****/ @@ -2323,7 +2582,10 @@ MY_LOCALE my_locale_es_DO &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_DO */ + '\0', /* thousands_sep es_DO */ + "\x80\x80" /* grouping es_DO */ ); /***** LOCALE END es_DO *****/ @@ -2339,7 +2601,10 @@ MY_LOCALE my_locale_es_EC &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_EC */ + '\0', /* thousands_sep es_EC */ + "\x80\x80" /* grouping es_EC */ ); /***** LOCALE END es_EC *****/ @@ -2355,7 +2620,10 @@ MY_LOCALE my_locale_es_GT &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_GT */ + '\0', /* thousands_sep es_GT */ + "\x80\x80" /* grouping es_GT */ ); /***** LOCALE END es_GT *****/ @@ -2371,7 +2639,10 @@ MY_LOCALE my_locale_es_HN &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_HN */ + '\0', /* thousands_sep es_HN */ + "\x80\x80" /* grouping es_HN */ ); /***** LOCALE END es_HN *****/ @@ -2387,7 +2658,10 @@ MY_LOCALE my_locale_es_MX &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_MX */ + '\0', /* thousands_sep es_MX */ + "\x80\x80" /* grouping es_MX */ ); /***** LOCALE END es_MX *****/ @@ -2403,7 +2677,10 @@ MY_LOCALE my_locale_es_NI &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_NI */ + '\0', /* thousands_sep es_NI */ + "\x80\x80" /* grouping es_NI */ ); /***** LOCALE END es_NI *****/ @@ -2419,7 +2696,10 @@ MY_LOCALE my_locale_es_PA &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_PA */ + '\0', /* thousands_sep es_PA */ + "\x80\x80" /* grouping es_PA */ ); /***** LOCALE END es_PA *****/ @@ -2435,7 +2715,10 @@ MY_LOCALE my_locale_es_PE &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_PE */ + '\0', /* thousands_sep es_PE */ + "\x80\x80" /* grouping es_PE */ ); /***** LOCALE END es_PE *****/ @@ -2451,7 +2734,10 @@ MY_LOCALE my_locale_es_PR &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_PR */ + '\0', /* thousands_sep es_PR */ + "\x80\x80" /* grouping es_PR */ ); /***** LOCALE END es_PR *****/ @@ -2467,7 +2753,10 @@ MY_LOCALE my_locale_es_PY &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_PY */ + '\0', /* thousands_sep es_PY */ + "\x80\x80" /* grouping es_PY */ ); /***** LOCALE END es_PY *****/ @@ -2483,7 +2772,10 @@ MY_LOCALE my_locale_es_SV &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_SV */ + '\0', /* thousands_sep es_SV */ + "\x80\x80" /* grouping es_SV */ ); /***** LOCALE END es_SV *****/ @@ -2499,7 +2791,10 @@ MY_LOCALE my_locale_es_US &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_US */ + ',', /* thousands_sep es_US */ + "\x03\x03" /* grouping es_US */ ); /***** LOCALE END es_US *****/ @@ -2515,7 +2810,10 @@ MY_LOCALE my_locale_es_UY &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_UY */ + '\0', /* thousands_sep es_UY */ + "\x80\x80" /* grouping es_UY */ ); /***** LOCALE END es_UY *****/ @@ -2531,7 +2829,10 @@ MY_LOCALE my_locale_es_VE &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_VE */ + '\0', /* thousands_sep es_VE */ + "\x80\x80" /* grouping es_VE */ ); /***** LOCALE END es_VE *****/ @@ -2547,7 +2848,10 @@ MY_LOCALE my_locale_fr_BE &my_locale_typelib_day_names_fr_FR, &my_locale_typelib_ab_day_names_fr_FR, 9, - 8 + 8, + ',', /* decimal point fr_BE */ + '.', /* thousands_sep fr_BE */ + "\x80\x80" /* grouping fr_BE */ ); /***** LOCALE END fr_BE *****/ @@ -2563,7 +2867,10 @@ MY_LOCALE my_locale_fr_CA &my_locale_typelib_day_names_fr_FR, &my_locale_typelib_ab_day_names_fr_FR, 9, - 8 + 8, + ',', /* decimal point fr_CA */ + ' ', /* thousands_sep fr_CA */ + "\x80\x80" /* grouping fr_CA */ ); /***** LOCALE END fr_CA *****/ @@ -2579,7 +2886,10 @@ MY_LOCALE my_locale_fr_CH &my_locale_typelib_day_names_fr_FR, &my_locale_typelib_ab_day_names_fr_FR, 9, - 8 + 8, + ',', /* decimal point fr_CH */ + '\0', /* thousands_sep fr_CH */ + "\x80\x80" /* grouping fr_CH */ ); /***** LOCALE END fr_CH *****/ @@ -2595,7 +2905,10 @@ MY_LOCALE my_locale_fr_LU &my_locale_typelib_day_names_fr_FR, &my_locale_typelib_ab_day_names_fr_FR, 9, - 8 + 8, + ',', /* decimal point fr_LU */ + '\0', /* thousands_sep fr_LU */ + "\x80\x80" /* grouping fr_LU */ ); /***** LOCALE END fr_LU *****/ @@ -2611,7 +2924,10 @@ MY_LOCALE my_locale_it_IT &my_locale_typelib_day_names_it_CH, &my_locale_typelib_ab_day_names_it_CH, 9, - 9 + 9, + ',', /* decimal point it_IT */ + '\0', /* thousands_sep it_IT */ + "\x80\x80" /* grouping it_IT */ ); /***** LOCALE END it_IT *****/ @@ -2627,7 +2943,10 @@ MY_LOCALE my_locale_nl_BE &my_locale_typelib_day_names_nl_NL, &my_locale_typelib_ab_day_names_nl_NL, 9, - 9 + 9, + ',', /* decimal point nl_BE */ + '.', /* thousands_sep nl_BE */ + "\x80\x80" /* grouping nl_BE */ ); /***** LOCALE END nl_BE *****/ @@ -2643,7 +2962,10 @@ MY_LOCALE my_locale_no_NO &my_locale_typelib_day_names_nb_NO, &my_locale_typelib_ab_day_names_nb_NO, 9, - 7 + 7, + ',', /* decimal point no_NO */ + '.', /* thousands_sep no_NO */ + "\x03\x03" /* grouping no_NO */ ); /***** LOCALE END no_NO *****/ @@ -2659,7 +2981,10 @@ MY_LOCALE my_locale_sv_FI &my_locale_typelib_day_names_sv_SE, &my_locale_typelib_ab_day_names_sv_SE, 9, - 7 + 7, + ',', /* decimal point sv_FI */ + ' ', /* thousands_sep sv_FI */ + "\x03\x03" /* grouping sv_FI */ ); /***** LOCALE END sv_FI *****/ @@ -2675,7 +3000,11 @@ MY_LOCALE my_locale_zh_HK &my_locale_typelib_day_names_zh_CN, &my_locale_typelib_ab_day_names_zh_CN, 3, - 3 + 3, + '.', /* decimal point zh_HK */ + ',', /* thousands_sep zh_HK */ + "\x03" /* grouping zh_HK */ + ); /***** LOCALE END zh_HK *****/ From d0d2853b8eb09b621c44ed75c29d2a9c74a46a2e Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Mon, 5 Oct 2009 20:14:43 +0200 Subject: [PATCH 079/159] 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 080/159] 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 081/159] 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 1c58e90695a781d32ea4aa49768017ff4d9fab07 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 6 Oct 2009 11:02:51 +0500 Subject: [PATCH 082/159] Backporting WL#4642 Greek locale for DAYNAME, MONTHNAME, DATE_FORMAT added: mysql-test/r/locale.result mysql-test/t/locale.test modified: mysql-test/r/variables.result mysql-test/t/variables.test sql/sql_locale.cc --- mysql-test/r/locale.result | 49 ++++++++++++++++++++++++ mysql-test/r/variables.result | 14 +++---- mysql-test/t/locale.test | 34 +++++++++++++++++ mysql-test/t/variables.test | 4 +- sql/sql_locale.cc | 72 +++++++++++++++++++++++++++++++++++ 5 files changed, 164 insertions(+), 9 deletions(-) create mode 100644 mysql-test/r/locale.result create mode 100644 mysql-test/t/locale.test diff --git a/mysql-test/r/locale.result b/mysql-test/r/locale.result new file mode 100644 index 00000000000..467eb97b639 --- /dev/null +++ b/mysql-test/r/locale.result @@ -0,0 +1,49 @@ +DROP TABLE IF EXISTS t1; +Start of 5.4 tests +# +# WL#4642 Greek locale for DAYNAME, MONTHNAME, DATE_FORMAT +# +SET NAMES utf8; +SET @@lc_time_names=109; +SELECT @@lc_time_names; +@@lc_time_names +el_GR +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES +('2006-01-01'),('2006-01-02'),('2006-01-03'), +('2006-01-04'),('2006-01-05'),('2006-01-06'),('2006-01-07'); +SELECT a, date_format(a,'%a') as abday, dayname(a) as day FROM t1 ORDER BY a; +a abday day +2006-01-01 螝蠀蟻 螝蠀蟻喂伪魏萎 +2006-01-02 螖蔚蠀 螖蔚蠀蟿苇蟻伪 +2006-01-03 韦蟻委 韦蟻委蟿畏 +2006-01-04 韦蔚蟿 韦蔚蟿维蟻蟿畏 +2006-01-05 螤苇渭 螤苇渭蟺蟿畏 +2006-01-06 螤伪蟻 螤伪蟻伪蟽魏蔚蠀萎 +2006-01-07 危维尾 危维尾尾伪蟿慰 +DROP TABLE t1; +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES +('2006-01-01'),('2006-02-01'),('2006-03-01'), +('2006-04-01'),('2006-05-01'),('2006-06-01'), +('2006-07-01'),('2006-08-01'),('2006-09-01'), +('2006-10-01'),('2006-11-01'),('2006-12-01'); +SELECT a, date_format(a,'%b') as abmon, monthname(a) as mon FROM t1 ORDER BY a; +a abmon mon +2006-01-01 螜伪谓 螜伪谓慰蠀维蟻喂慰蟼 +2006-02-01 桅蔚尾 桅蔚尾蟻慰蠀维蟻喂慰蟼 +2006-03-01 螠维蟻 螠维蟻蟿喂慰蟼 +2006-04-01 螒蟺蟻 螒蟺蟻委位喂慰蟼 +2006-05-01 螠维喂 螠维喂慰蟼 +2006-06-01 螜慰蠉谓 螜慰蠉谓喂慰蟼 +2006-07-01 螜慰蠉位 螜慰蠉位喂慰蟼 +2006-08-01 螒蠉纬 螒蠉纬慰蠀蟽蟿慰蟼 +2006-09-01 危蔚蟺 危蔚蟺蟿苇渭尾蟻喂慰蟼 +2006-10-01 螣魏蟿 螣魏蟿蠋尾蟻喂慰蟼 +2006-11-01 螡慰苇 螡慰苇渭尾蟻喂慰蟼 +2006-12-01 螖蔚魏 螖蔚魏苇渭尾蟻喂慰蟼 +SELECT format(123456.789, 3, 'el_GR'); +format(123456.789, 3, 'el_GR') +123456.789 +DROP TABLE t1; +End of 5.4 tests diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index c1cd1840df8..da833c79bb7 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -812,16 +812,16 @@ select @@lc_time_names; @@lc_time_names en_US LC_TIME_NAMES: testing locale with the last ID: -set lc_time_names=108; -select @@lc_time_names; -@@lc_time_names -zh_HK -LC_TIME_NAMES: testing a number beyond the valid ID range: set lc_time_names=109; -ERROR HY000: Unknown locale: '109' select @@lc_time_names; @@lc_time_names -zh_HK +el_GR +LC_TIME_NAMES: testing a number beyond the valid ID range: +set lc_time_names=110; +ERROR HY000: Unknown locale: '110' +select @@lc_time_names; +@@lc_time_names +el_GR LC_TIME_NAMES: testing that 0 is en_US: set lc_time_names=0; select @@lc_time_names; diff --git a/mysql-test/t/locale.test b/mysql-test/t/locale.test new file mode 100644 index 00000000000..a6291d9048d --- /dev/null +++ b/mysql-test/t/locale.test @@ -0,0 +1,34 @@ +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +--echo Start of 5.4 tests + +--echo # +--echo # WL#4642 Greek locale for DAYNAME, MONTHNAME, DATE_FORMAT +--echo # + +SET NAMES utf8; + +SET @@lc_time_names=109; +SELECT @@lc_time_names; + +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES +('2006-01-01'),('2006-01-02'),('2006-01-03'), +('2006-01-04'),('2006-01-05'),('2006-01-06'),('2006-01-07'); +SELECT a, date_format(a,'%a') as abday, dayname(a) as day FROM t1 ORDER BY a; +DROP TABLE t1; + +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES +('2006-01-01'),('2006-02-01'),('2006-03-01'), +('2006-04-01'),('2006-05-01'),('2006-06-01'), +('2006-07-01'),('2006-08-01'),('2006-09-01'), +('2006-10-01'),('2006-11-01'),('2006-12-01'); +SELECT a, date_format(a,'%b') as abmon, monthname(a) as mon FROM t1 ORDER BY a; + +SELECT format(123456.789, 3, 'el_GR'); +DROP TABLE t1; + +--echo End of 5.4 tests diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index a98163e026c..e7d7d5ca16b 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -576,11 +576,11 @@ set lc_time_names=NULL; set lc_time_names=-1; select @@lc_time_names; --echo LC_TIME_NAMES: testing locale with the last ID: -set lc_time_names=108; +set lc_time_names=109; select @@lc_time_names; --echo LC_TIME_NAMES: testing a number beyond the valid ID range: --error ER_UNKNOWN_LOCALE -set lc_time_names=109; +set lc_time_names=110; select @@lc_time_names; --echo LC_TIME_NAMES: testing that 0 is en_US: set lc_time_names=0; diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc index b59c3f16735..fcfd60e72e6 100644 --- a/sql/sql_locale.cc +++ b/sql/sql_locale.cc @@ -3009,6 +3009,77 @@ MY_LOCALE my_locale_zh_HK /***** LOCALE END zh_HK *****/ +/***** LOCALE BEGIN el_GR: Greek - Greece *****/ +static const char *my_locale_month_names_el_GR[13]= +{ + "螜伪谓慰蠀维蟻喂慰蟼", "桅蔚尾蟻慰蠀维蟻喂慰蟼", "螠维蟻蟿喂慰蟼", + "螒蟺蟻委位喂慰蟼", "螠维喂慰蟼", "螜慰蠉谓喂慰蟼", + "螜慰蠉位喂慰蟼", "螒蠉纬慰蠀蟽蟿慰蟼", "危蔚蟺蟿苇渭尾蟻喂慰蟼", + "螣魏蟿蠋尾蟻喂慰蟼", "螡慰苇渭尾蟻喂慰蟼", "螖蔚魏苇渭尾蟻喂慰蟼", NullS +}; + +static const char *my_locale_ab_month_names_el_GR[13]= +{ + "螜伪谓", "桅蔚尾", "螠维蟻", + "螒蟺蟻", "螠维喂", "螜慰蠉谓", + "螜慰蠉位","螒蠉纬", "危蔚蟺", + "螣魏蟿", "螡慰苇", "螖蔚魏", NullS +}; + +static const char *my_locale_day_names_el_GR[8] = +{ + "螖蔚蠀蟿苇蟻伪", "韦蟻委蟿畏", "韦蔚蟿维蟻蟿畏", "螤苇渭蟺蟿畏", + "螤伪蟻伪蟽魏蔚蠀萎", "危维尾尾伪蟿慰", "螝蠀蟻喂伪魏萎", NullS +}; + +static const char *my_locale_ab_day_names_el_GR[8]= +{ + "螖蔚蠀", "韦蟻委", "韦蔚蟿", "螤苇渭", + "螤伪蟻", "危维尾", "螝蠀蟻", NullS +}; + +static TYPELIB my_locale_typelib_month_names_el_GR= +{ + array_elements(my_locale_month_names_el_GR) - 1, + "", my_locale_month_names_el_GR, NULL +}; + +static TYPELIB my_locale_typelib_ab_month_names_el_GR= +{ + array_elements(my_locale_ab_month_names_el_GR)-1, + "", my_locale_ab_month_names_el_GR, NULL +}; + +static TYPELIB my_locale_typelib_day_names_el_GR= +{ + array_elements(my_locale_day_names_el_GR)-1, + "", my_locale_day_names_el_GR, NULL +}; + +static TYPELIB my_locale_typelib_ab_day_names_el_GR= +{ + array_elements(my_locale_ab_day_names_el_GR) - 1, + "", my_locale_ab_day_names_el_GR, NULL +}; + +MY_LOCALE my_locale_el_GR +( + 109, + "el_GR", + "Greek - Greece", + FALSE, + &my_locale_typelib_month_names_el_GR, + &my_locale_typelib_ab_month_names_el_GR, + &my_locale_typelib_day_names_el_GR, + &my_locale_typelib_ab_day_names_el_GR, + 11, /* max mon name length */ + 9, /* max day name length */ + ',', /* decimal point el_GR */ + '.', /* thousands_sep el_GR */ + "\x80" /* grouping el_GR */ +); +/***** LOCALE END el_GR *****/ + /* The list of all locales. Note, locales must be ordered according to their @@ -3126,6 +3197,7 @@ MY_LOCALE *my_locales[]= &my_locale_no_NO, &my_locale_sv_FI, &my_locale_zh_HK, + &my_locale_el_GR, NULL }; From bf1b7b7dedb125907454c79b7a28610a20ad826b Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 6 Oct 2009 10:32:02 +0300 Subject: [PATCH 083/159] 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 084/159] 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 a16a82d4ebefa437b86252c5fc18b0c476c67506 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 6 Oct 2009 15:34:49 +0500 Subject: [PATCH 085/159] Bsckporting WL#3764 Sinhala Collation modified: mysql-test/r/ctype_utf8.result mysql-test/t/ctype_utf8.test mysys/charset-def.c strings/ctype-uca.c --- mysql-test/r/ctype_utf8.result | 112 +++++++++++++++++++++++++++++++++ mysql-test/t/ctype_utf8.test | 19 ++++++ mysys/charset-def.c | 4 ++ strings/ctype-uca.c | 93 +++++++++++++++++++++++++++ 4 files changed, 228 insertions(+) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 70f976ee9a7..393625f5192 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -1880,3 +1880,115 @@ CONVERT(a, CHAR) CONVERT(b, CHAR) 70000 1092 DROP TABLE t1; End of 5.0 tests +Start of 5.4 tests +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( +predicted_order int NOT NULL, +utf8_encoding VARCHAR(10) NOT NULL +) CHARACTER SET utf8; +INSERT INTO t1 VALUES (19, x'E0B696'), (30, x'E0B69AE0B798'), (61, x'E0B6AF'), (93, x'E0B799'), (52, x'E0B6A6'), (73, x'E0B6BBE0B78AE2808D'), (3, x'E0B686'), (56, x'E0B6AA'), (55, x'E0B6A9'), (70, x'E0B6B9'), (94, x'E0B79A'), (80, x'E0B785'), (25, x'E0B69AE0B791'), (48, x'E0B6A2'), (13, x'E0B690'), (86, x'E0B793'), (91, x'E0B79F'), (81, x'E0B786'), (79, x'E0B784'), (14, x'E0B691'), (99, x'E0B78A'), (8, x'E0B68B'), (68, x'E0B6B7'), (22, x'E0B69A'), (16, x'E0B693'), (33, x'E0B69AE0B7B3'), (38, x'E0B69AE0B79D'), (21, x'E0B683'), (11, x'E0B68E'), (77, x'E0B782'), (40, x'E0B69AE0B78A'), (101, x'E0B78AE2808DE0B6BB'), (35, x'E0B69AE0B79A'), (1, x'E0B7B4'), (9, x'E0B68C'), (96, x'E0B79C'), (6, x'E0B689'), (95, x'E0B79B'), (88, x'E0B796'), (64, x'E0B6B3'), (26, x'E0B69AE0B792'), (82, x'E0B78F'), (28, x'E0B69AE0B794'), (39, x'E0B69AE0B79E'), (97, x'E0B79D'), (2, x'E0B685'), (75, x'E0B780'), (34, x'E0B69AE0B799'), (69, x'E0B6B8'), (83, x'E0B790'), (18, x'E0B695'), (90, x'E0B7B2'), (17, x'E0B694'), (72, x'E0B6BB'), (66, x'E0B6B5'), (59, x'E0B6AD'), (44, x'E0B69E'), (15, x'E0B692'), (23, x'E0B69AE0B78F'), (65, x'E0B6B4'), (42, x'E0B69C'), (63, x'E0B6B1'), (85, x'E0B792'), (47, x'E0B6A1'), (49, x'E0B6A3'), (92, x'E0B7B3'), (78, x'E0B783'), (36, x'E0B69AE0B79B'), (4, x'E0B687'), (24, x'E0B69AE0B790'), (87, x'E0B794'), (37, x'E0B69AE0B79C'), (32, x'E0B69AE0B79F'), (29, x'E0B69AE0B796'), (43, x'E0B69D'), (62, x'E0B6B0'), (100, x'E0B78AE2808DE0B6BA'), (60, x'E0B6AE'), (45, x'E0B69F'), (12, x'E0B68F'), (46, x'E0B6A0'), (50, x'E0B6A5'), (51, x'E0B6A4'), (5, x'E0B688'), (76, x'E0B781'), (89, x'E0B798'), (74, x'E0B6BD'), (10, x'E0B68D'), (57, x'E0B6AB'), (71, x'E0B6BA'), (58, x'E0B6AC'), (27, x'E0B69AE0B793'), (54, x'E0B6A8'), (84, x'E0B791'), (31, x'E0B69AE0B7B2'), (98, x'E0B79E'), (53, x'E0B6A7'), (41, x'E0B69B'), (67, x'E0B6B6'), (7, x'E0B68A'), (20, x'E0B682'); +SELECT predicted_order, hex(utf8_encoding) FROM t1 ORDER BY utf8_encoding COLLATE utf8_sinhala_ci; +predicted_order hex(utf8_encoding) +1 E0B7B4 +2 E0B685 +3 E0B686 +4 E0B687 +5 E0B688 +6 E0B689 +7 E0B68A +8 E0B68B +9 E0B68C +10 E0B68D +11 E0B68E +12 E0B68F +13 E0B690 +14 E0B691 +15 E0B692 +16 E0B693 +17 E0B694 +18 E0B695 +19 E0B696 +20 E0B682 +21 E0B683 +22 E0B69A +23 E0B69AE0B78F +24 E0B69AE0B790 +25 E0B69AE0B791 +26 E0B69AE0B792 +27 E0B69AE0B793 +28 E0B69AE0B794 +29 E0B69AE0B796 +30 E0B69AE0B798 +31 E0B69AE0B7B2 +32 E0B69AE0B79F +33 E0B69AE0B7B3 +34 E0B69AE0B799 +35 E0B69AE0B79A +36 E0B69AE0B79B +37 E0B69AE0B79C +38 E0B69AE0B79D +39 E0B69AE0B79E +40 E0B69AE0B78A +41 E0B69B +42 E0B69C +43 E0B69D +44 E0B69E +45 E0B69F +46 E0B6A0 +47 E0B6A1 +48 E0B6A2 +49 E0B6A3 +50 E0B6A5 +51 E0B6A4 +52 E0B6A6 +53 E0B6A7 +54 E0B6A8 +55 E0B6A9 +56 E0B6AA +57 E0B6AB +58 E0B6AC +59 E0B6AD +60 E0B6AE +61 E0B6AF +62 E0B6B0 +63 E0B6B1 +64 E0B6B3 +65 E0B6B4 +66 E0B6B5 +67 E0B6B6 +68 E0B6B7 +69 E0B6B8 +70 E0B6B9 +71 E0B6BA +72 E0B6BB +73 E0B6BBE0B78AE2808D +74 E0B6BD +75 E0B780 +76 E0B781 +77 E0B782 +78 E0B783 +79 E0B784 +80 E0B785 +81 E0B786 +82 E0B78F +83 E0B790 +84 E0B791 +85 E0B792 +86 E0B793 +87 E0B794 +88 E0B796 +89 E0B798 +90 E0B7B2 +91 E0B79F +92 E0B7B3 +93 E0B799 +94 E0B79A +95 E0B79B +96 E0B79C +97 E0B79D +98 E0B79E +99 E0B78A +100 E0B78AE2808DE0B6BA +101 E0B78AE2808DE0B6BB +DROP TABLE t1; +End of 5.4 tests diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index f0c769251cf..7e93b638acb 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -1456,3 +1456,22 @@ SELECT CONVERT(a, CHAR), CONVERT(b, CHAR) from t1 GROUP BY b; DROP TABLE t1; --echo End of 5.0 tests + + +--echo Start of 5.4 tests +# +# Bug#26474: Add Sinhala script (Sri Lanka) collation to MySQL +# +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TABLE t1 ( + predicted_order int NOT NULL, + utf8_encoding VARCHAR(10) NOT NULL +) CHARACTER SET utf8; +INSERT INTO t1 VALUES (19, x'E0B696'), (30, x'E0B69AE0B798'), (61, x'E0B6AF'), (93, x'E0B799'), (52, x'E0B6A6'), (73, x'E0B6BBE0B78AE2808D'), (3, x'E0B686'), (56, x'E0B6AA'), (55, x'E0B6A9'), (70, x'E0B6B9'), (94, x'E0B79A'), (80, x'E0B785'), (25, x'E0B69AE0B791'), (48, x'E0B6A2'), (13, x'E0B690'), (86, x'E0B793'), (91, x'E0B79F'), (81, x'E0B786'), (79, x'E0B784'), (14, x'E0B691'), (99, x'E0B78A'), (8, x'E0B68B'), (68, x'E0B6B7'), (22, x'E0B69A'), (16, x'E0B693'), (33, x'E0B69AE0B7B3'), (38, x'E0B69AE0B79D'), (21, x'E0B683'), (11, x'E0B68E'), (77, x'E0B782'), (40, x'E0B69AE0B78A'), (101, x'E0B78AE2808DE0B6BB'), (35, x'E0B69AE0B79A'), (1, x'E0B7B4'), (9, x'E0B68C'), (96, x'E0B79C'), (6, x'E0B689'), (95, x'E0B79B'), (88, x'E0B796'), (64, x'E0B6B3'), (26, x'E0B69AE0B792'), (82, x'E0B78F'), (28, x'E0B69AE0B794'), (39, x'E0B69AE0B79E'), (97, x'E0B79D'), (2, x'E0B685'), (75, x'E0B780'), (34, x'E0B69AE0B799'), (69, x'E0B6B8'), (83, x'E0B790'), (18, x'E0B695'), (90, x'E0B7B2'), (17, x'E0B694'), (72, x'E0B6BB'), (66, x'E0B6B5'), (59, x'E0B6AD'), (44, x'E0B69E'), (15, x'E0B692'), (23, x'E0B69AE0B78F'), (65, x'E0B6B4'), (42, x'E0B69C'), (63, x'E0B6B1'), (85, x'E0B792'), (47, x'E0B6A1'), (49, x'E0B6A3'), (92, x'E0B7B3'), (78, x'E0B783'), (36, x'E0B69AE0B79B'), (4, x'E0B687'), (24, x'E0B69AE0B790'), (87, x'E0B794'), (37, x'E0B69AE0B79C'), (32, x'E0B69AE0B79F'), (29, x'E0B69AE0B796'), (43, x'E0B69D'), (62, x'E0B6B0'), (100, x'E0B78AE2808DE0B6BA'), (60, x'E0B6AE'), (45, x'E0B69F'), (12, x'E0B68F'), (46, x'E0B6A0'), (50, x'E0B6A5'), (51, x'E0B6A4'), (5, x'E0B688'), (76, x'E0B781'), (89, x'E0B798'), (74, x'E0B6BD'), (10, x'E0B68D'), (57, x'E0B6AB'), (71, x'E0B6BA'), (58, x'E0B6AC'), (27, x'E0B69AE0B793'), (54, x'E0B6A8'), (84, x'E0B791'), (31, x'E0B69AE0B7B2'), (98, x'E0B79E'), (53, x'E0B6A7'), (41, x'E0B69B'), (67, x'E0B6B6'), (7, x'E0B68A'), (20, x'E0B682'); +SELECT predicted_order, hex(utf8_encoding) FROM t1 ORDER BY utf8_encoding COLLATE utf8_sinhala_ci; +DROP TABLE t1; + +--echo End of 5.4 tests + diff --git a/mysys/charset-def.c b/mysys/charset-def.c index 63bbceef29b..bf2576621ce 100644 --- a/mysys/charset-def.c +++ b/mysys/charset-def.c @@ -42,6 +42,7 @@ extern CHARSET_INFO my_charset_ucs2_roman_uca_ci; extern CHARSET_INFO my_charset_ucs2_persian_uca_ci; extern CHARSET_INFO my_charset_ucs2_esperanto_uca_ci; extern CHARSET_INFO my_charset_ucs2_hungarian_uca_ci; +extern CHARSET_INFO my_charset_ucs2_sinhala_uca_ci; #endif #ifdef HAVE_CHARSET_utf8 @@ -63,6 +64,7 @@ extern CHARSET_INFO my_charset_utf8_roman_uca_ci; extern CHARSET_INFO my_charset_utf8_persian_uca_ci; extern CHARSET_INFO my_charset_utf8_esperanto_uca_ci; extern CHARSET_INFO my_charset_utf8_hungarian_uca_ci; +extern CHARSET_INFO my_charset_utf8_sinhala_uca_ci; #ifdef HAVE_UTF8_GENERAL_CS extern CHARSET_INFO my_charset_utf8_general_cs; #endif @@ -152,6 +154,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_ucs2_persian_uca_ci); add_compiled_collation(&my_charset_ucs2_esperanto_uca_ci); add_compiled_collation(&my_charset_ucs2_hungarian_uca_ci); + add_compiled_collation(&my_charset_ucs2_sinhala_uca_ci); #endif #endif @@ -186,6 +189,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_utf8_persian_uca_ci); add_compiled_collation(&my_charset_utf8_esperanto_uca_ci); add_compiled_collation(&my_charset_utf8_hungarian_uca_ci); + add_compiled_collation(&my_charset_utf8_sinhala_uca_ci); #endif #endif diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c index 566cc58ab0a..ecf92c1b7d4 100644 --- a/strings/ctype-uca.c +++ b/strings/ctype-uca.c @@ -6712,6 +6712,34 @@ static const char hungarian[]= "&O < \\u00F6 <<< \\u00D6 << \\u0151 <<< \\u0150" "&U < \\u00FC <<< \\u00DC << \\u0171 <<< \\u0170"; +/* + SCCII Part 1 : Collation Sequence (SLS1134) + 2006/11/24 + Harshula Jayasuriya + Language Technology Research Lab, University of Colombo / ICTA +*/ +#if 0 +static const char sinhala[]= + "& \\u0D96 < \\u0D82 < \\u0D83" + "& \\u0DA5 < \\u0DA4" + "& \\u0DD8 < \\u0DF2 < \\u0DDF < \\u0DF3" + "& \\u0DDE < \\u0DCA"; +#else +static const char sinhala[]= + "& \\u0D96 < \\u0D82 < \\u0D83 < \\u0D9A < \\u0D9B < \\u0D9C < \\u0D9D" + "< \\u0D9E < \\u0D9F < \\u0DA0 < \\u0DA1 < \\u0DA2 < \\u0DA3" + "< \\u0DA5 < \\u0DA4 < \\u0DA6" + "< \\u0DA7 < \\u0DA8 < \\u0DA9 < \\u0DAA < \\u0DAB < \\u0DAC" + "< \\u0DAD < \\u0DAE < \\u0DAF < \\u0DB0 < \\u0DB1" + "< \\u0DB3 < \\u0DB4 < \\u0DB5 < \\u0DB6 < \\u0DB7 < \\u0DB8" + "< \\u0DB9 < \\u0DBA < \\u0DBB < \\u0DBD < \\u0DC0 < \\u0DC1" + "< \\u0DC2 < \\u0DC3 < \\u0DC4 < \\u0DC5 < \\u0DC6" + "< \\u0DCF" + "< \\u0DD0 < \\u0DD1 < \\u0DD2 < \\u0DD3 < \\u0DD4 < \\u0DD6" + "< \\u0DD8 < \\u0DF2 < \\u0DDF < \\u0DF3 < \\u0DD9 < \\u0DDA" + "< \\u0DDB < \\u0DDC < \\u0DDD < \\u0DDE < \\u0DCA"; +#endif + /* Unicode Collation Algorithm: @@ -8698,6 +8726,39 @@ CHARSET_INFO my_charset_ucs2_hungarian_uca_ci= }; +CHARSET_INFO my_charset_ucs2_sinhala_uca_ci= +{ + 147,0,0, /* number */ + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + "ucs2", /* csname */ + "ucs2_sinhala_ci", /* name */ + "", /* comment */ + sinhala, /* tailoring */ + NULL, /* ctype */ + NULL, /* to_lower */ + NULL, /* to_upper */ + NULL, /* sort_order */ + NULL, /* contractions */ + NULL, /* sort_order_big*/ + NULL, /* tab_to_uni */ + NULL, /* tab_from_uni */ + my_unicase_default, /* caseinfo */ + NULL, /* state_map */ + NULL, /* ident_map */ + 8, /* strxfrm_multiply */ + 1, /* caseup_multiply */ + 1, /* casedn_multiply */ + 2, /* mbminlen */ + 2, /* mbmaxlen */ + 9, /* min_sort_char */ + 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ + 0, /* escape_with_backslash_is_dangerous */ + &my_charset_ucs2_handler, + &my_collation_ucs2_uca_handler +}; + + #endif @@ -9355,6 +9416,38 @@ CHARSET_INFO my_charset_utf8_hungarian_uca_ci= &my_collation_any_uca_handler }; +CHARSET_INFO my_charset_utf8_sinhala_uca_ci= +{ + 211,0,0, /* number */ + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + "utf8", /* cs name */ + "utf8_sinhala_ci", /* name */ + "", /* comment */ + sinhala, /* tailoring */ + ctype_utf8, /* ctype */ + NULL, /* to_lower */ + NULL, /* to_upper */ + NULL, /* sort_order */ + NULL, /* contractions */ + NULL, /* sort_order_big*/ + NULL, /* tab_to_uni */ + NULL, /* tab_from_uni */ + my_unicase_default, /* caseinfo */ + NULL, /* state_map */ + NULL, /* ident_map */ + 8, /* strxfrm_multiply */ + 1, /* caseup_multiply */ + 1, /* casedn_multiply */ + 3, /* mbminlen */ + 3, /* mbmaxlen */ + 9, /* min_sort_char */ + 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ + 0, /* escape_with_backslash_is_dangerous */ + &my_charset_utf8_handler, + &my_collation_any_uca_handler +}; + #endif /* HAVE_CHARSET_utf8 */ #endif /* HAVE_UCA_COLLATIONS */ From ca8706ff0f9fd98289921219905f684941086293 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Tue, 6 Oct 2009 14:47:04 +0400 Subject: [PATCH 086/159] Backport WL#4085: Merge revno:2476.657.219 from 6.0. --- mysql-test/mysql-test-run.pl | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 17102196f42..78b69b26367 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -816,7 +816,6 @@ sub command_line_setup { 'combination=s' => \@opt_combinations, 'skip-combinations' => \&collect_option, 'experimental=s' => \$opt_experimental, - 'skip-im' => \&ignore_option, # Specify ports 'build-thread|mtr-build-thread=i' => \$opt_build_thread, From aabeeccf86b01969e94cecc735d1bf97f953176f Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Tue, 6 Oct 2009 14:52:26 +0400 Subject: [PATCH 087/159] Backport WL#4085: Merge revno:2476.1105.1 from 6.0. --- server-tools/CMakeLists.txt | 33 - server-tools/Makefile.am | 20 - server-tools/instance-manager/CMakeLists.txt | 38 - server-tools/instance-manager/IMService.cpp | 124 -- server-tools/instance-manager/IMService.h | 32 - server-tools/instance-manager/Makefile.am | 103 - server-tools/instance-manager/README | 11 - .../instance-manager/WindowsService.cpp | 231 --- .../instance-manager/WindowsService.h | 56 - server-tools/instance-manager/angel.cc | 407 ---- server-tools/instance-manager/angel.h | 34 - server-tools/instance-manager/buffer.cc | 110 -- server-tools/instance-manager/buffer.h | 65 - server-tools/instance-manager/command.cc | 30 - server-tools/instance-manager/command.h | 60 - server-tools/instance-manager/commands.cc | 1752 ----------------- server-tools/instance-manager/commands.h | 393 ---- server-tools/instance-manager/exit_codes.h | 40 - server-tools/instance-manager/guardian.cc | 496 ----- server-tools/instance-manager/guardian.h | 110 -- server-tools/instance-manager/instance.cc | 944 --------- server-tools/instance-manager/instance.h | 273 --- server-tools/instance-manager/instance_map.cc | 649 ------ server-tools/instance-manager/instance_map.h | 102 - .../instance-manager/instance_options.cc | 753 ------- .../instance-manager/instance_options.h | 126 -- server-tools/instance-manager/listener.cc | 337 ---- server-tools/instance-manager/listener.h | 61 - server-tools/instance-manager/log.cc | 196 -- server-tools/instance-manager/log.h | 59 - server-tools/instance-manager/manager.cc | 526 ----- server-tools/instance-manager/manager.h | 71 - server-tools/instance-manager/messages.cc | 104 - server-tools/instance-manager/messages.h | 23 - .../instance-manager/mysql_connection.cc | 376 ---- .../instance-manager/mysql_connection.h | 74 - .../instance-manager/mysql_manager_error.h | 40 - server-tools/instance-manager/mysqlmanager.cc | 232 --- server-tools/instance-manager/options.cc | 558 ------ server-tools/instance-manager/options.h | 108 - server-tools/instance-manager/parse.cc | 509 ----- server-tools/instance-manager/parse.h | 212 -- server-tools/instance-manager/parse_output.cc | 407 ---- server-tools/instance-manager/parse_output.h | 33 - server-tools/instance-manager/portability.h | 65 - server-tools/instance-manager/priv.cc | 76 - server-tools/instance-manager/priv.h | 99 - server-tools/instance-manager/protocol.cc | 217 -- server-tools/instance-manager/protocol.h | 47 - .../instance-manager/thread_registry.cc | 419 ---- .../instance-manager/thread_registry.h | 176 -- .../user_management_commands.cc | 421 ---- .../user_management_commands.h | 167 -- server-tools/instance-manager/user_map.cc | 395 ---- server-tools/instance-manager/user_map.h | 103 - 55 files changed, 13103 deletions(-) delete mode 100644 server-tools/CMakeLists.txt delete mode 100644 server-tools/Makefile.am delete mode 100755 server-tools/instance-manager/CMakeLists.txt delete mode 100644 server-tools/instance-manager/IMService.cpp delete mode 100644 server-tools/instance-manager/IMService.h delete mode 100644 server-tools/instance-manager/Makefile.am delete mode 100644 server-tools/instance-manager/README delete mode 100644 server-tools/instance-manager/WindowsService.cpp delete mode 100644 server-tools/instance-manager/WindowsService.h delete mode 100644 server-tools/instance-manager/angel.cc delete mode 100644 server-tools/instance-manager/angel.h delete mode 100644 server-tools/instance-manager/buffer.cc delete mode 100644 server-tools/instance-manager/buffer.h delete mode 100644 server-tools/instance-manager/command.cc delete mode 100644 server-tools/instance-manager/command.h delete mode 100644 server-tools/instance-manager/commands.cc delete mode 100644 server-tools/instance-manager/commands.h delete mode 100644 server-tools/instance-manager/exit_codes.h delete mode 100644 server-tools/instance-manager/guardian.cc delete mode 100644 server-tools/instance-manager/guardian.h delete mode 100644 server-tools/instance-manager/instance.cc delete mode 100644 server-tools/instance-manager/instance.h delete mode 100644 server-tools/instance-manager/instance_map.cc delete mode 100644 server-tools/instance-manager/instance_map.h delete mode 100644 server-tools/instance-manager/instance_options.cc delete mode 100644 server-tools/instance-manager/instance_options.h delete mode 100644 server-tools/instance-manager/listener.cc delete mode 100644 server-tools/instance-manager/listener.h delete mode 100644 server-tools/instance-manager/log.cc delete mode 100644 server-tools/instance-manager/log.h delete mode 100644 server-tools/instance-manager/manager.cc delete mode 100644 server-tools/instance-manager/manager.h delete mode 100644 server-tools/instance-manager/messages.cc delete mode 100644 server-tools/instance-manager/messages.h delete mode 100644 server-tools/instance-manager/mysql_connection.cc delete mode 100644 server-tools/instance-manager/mysql_connection.h delete mode 100644 server-tools/instance-manager/mysql_manager_error.h delete mode 100644 server-tools/instance-manager/mysqlmanager.cc delete mode 100644 server-tools/instance-manager/options.cc delete mode 100644 server-tools/instance-manager/options.h delete mode 100644 server-tools/instance-manager/parse.cc delete mode 100644 server-tools/instance-manager/parse.h delete mode 100644 server-tools/instance-manager/parse_output.cc delete mode 100644 server-tools/instance-manager/parse_output.h delete mode 100644 server-tools/instance-manager/portability.h delete mode 100644 server-tools/instance-manager/priv.cc delete mode 100644 server-tools/instance-manager/priv.h delete mode 100644 server-tools/instance-manager/protocol.cc delete mode 100644 server-tools/instance-manager/protocol.h delete mode 100644 server-tools/instance-manager/thread_registry.cc delete mode 100644 server-tools/instance-manager/thread_registry.h delete mode 100644 server-tools/instance-manager/user_management_commands.cc delete mode 100644 server-tools/instance-manager/user_management_commands.h delete mode 100644 server-tools/instance-manager/user_map.cc delete mode 100644 server-tools/instance-manager/user_map.h diff --git a/server-tools/CMakeLists.txt b/server-tools/CMakeLists.txt deleted file mode 100644 index 3f02ba88f1d..00000000000 --- a/server-tools/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) 2006 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") - -ADD_DEFINITIONS(-DMYSQL_SERVER -DMYSQL_INSTANCE_MANAGER) -INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/sql - ${PROJECT_SOURCE_DIR}/extra/yassl/include) - -ADD_EXECUTABLE(mysqlmanager buffer.cc command.cc commands.cc guardian.cc instance.cc instance_map.cc - instance_options.cc listener.cc log.cc manager.cc messages.cc mysql_connection.cc - mysqlmanager.cc options.cc parse.cc parse_output.cc priv.cc protocol.cc - thread_registry.cc user_map.cc imservice.cpp windowsservice.cpp - user_management_commands.cc - ../../sql/net_serv.cc ../../sql-common/pack.c ../../sql/password.c - ../../sql/sql_state.c ../../sql-common/client.c ../../libmysql/get_password.c - ../../libmysql/errmsg.c) - -ADD_DEPENDENCIES(mysqlmanager GenError) -TARGET_LINK_LIBRARIES(mysqlmanager dbug mysys strings taocrypt vio yassl zlib wsock32) diff --git a/server-tools/Makefile.am b/server-tools/Makefile.am deleted file mode 100644 index 96e9d5a946e..00000000000 --- a/server-tools/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (C) 2003, 2006 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -SUBDIRS = . instance-manager -DIST_SUBDIRS = . instance-manager - -# Don't update the files from bitkeeper -%::SCCS/s.% diff --git a/server-tools/instance-manager/CMakeLists.txt b/server-tools/instance-manager/CMakeLists.txt deleted file mode 100755 index 2b9bce56ff7..00000000000 --- a/server-tools/instance-manager/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (C) 2006 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") - -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") - -ADD_DEFINITIONS(-DMYSQL_SERVER -DMYSQL_INSTANCE_MANAGER) -INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/sql - ${PROJECT_SOURCE_DIR}/extra/yassl/include) - -ADD_EXECUTABLE(mysqlmanager buffer.cc command.cc commands.cc guardian.cc instance.cc instance_map.cc - instance_options.cc listener.cc log.cc manager.cc messages.cc mysql_connection.cc - mysqlmanager.cc options.cc parse.cc parse_output.cc priv.cc protocol.cc - thread_registry.cc user_map.cc IMService.cpp WindowsService.cpp - user_management_commands.cc - ../../sql/net_serv.cc ../../sql-common/pack.c ../../sql/password.c - ../../sql/sql_state.c ../../sql-common/client.c ../../libmysql/get_password.c - ../../libmysql/errmsg.c) - -ADD_DEPENDENCIES(mysqlmanager GenError) -TARGET_LINK_LIBRARIES(mysqlmanager debug dbug mysys strings taocrypt vio yassl zlib wsock32) - -IF(EMBED_MANIFESTS) - MYSQL_EMBED_MANIFEST("mysqlmanager" "asInvoker") -ENDIF(EMBED_MANIFESTS) diff --git a/server-tools/instance-manager/IMService.cpp b/server-tools/instance-manager/IMService.cpp deleted file mode 100644 index feccaadbecc..00000000000 --- a/server-tools/instance-manager/IMService.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* Copyright (C) 2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include -#include - -#include "IMService.h" - -#include "log.h" -#include "manager.h" -#include "options.h" - -static const char * const IM_SVC_USERNAME= NULL; -static const char * const IM_SVC_PASSWORD= NULL; - -IMService::IMService(void) - :WindowsService("MySqlManager", "MySQL Manager") -{ -} - -IMService::~IMService(void) -{ -} - -void IMService::Stop() -{ - ReportStatus(SERVICE_STOP_PENDING); - - /* stop the IM work */ - raise(SIGTERM); -} - -void IMService::Run(DWORD argc, LPTSTR *argv) -{ - /* report to the SCM that we're about to start */ - ReportStatus((DWORD)SERVICE_START_PENDING); - - Options::load(argc, argv); - - /* init goes here */ - ReportStatus((DWORD)SERVICE_RUNNING); - - /* wait for main loop to terminate */ - (void) Manager::main(); - Options::cleanup(); -} - -void IMService::Log(const char *msg) -{ - log_info(msg); -} - -int IMService::main() -{ - IMService winService; - - if (Options::Service::install_as_service) - { - if (winService.IsInstalled()) - { - log_info("Service is already installed."); - return 1; - } - - if (winService.Install(IM_SVC_USERNAME, IM_SVC_PASSWORD)) - { - log_info("Service installed successfully."); - return 0; - } - else - { - log_error("Service failed to install."); - return 1; - } - } - - if (Options::Service::remove_service) - { - if (!winService.IsInstalled()) - { - log_info("Service is not installed."); - return 1; - } - - if (winService.Remove()) - { - log_info("Service removed successfully."); - return 0; - } - else - { - log_error("Service failed to remove."); - return 1; - } - } - - log_info("Initializing Instance Manager service..."); - - if (!winService.Init()) - { - log_error("Service failed to initialize."); - - fprintf(stderr, - "The service should be started by Windows Service Manager.\n" - "The MySQL Manager should be started with '--standalone'\n" - "to run from command line."); - - return 1; - } - - return 0; -} diff --git a/server-tools/instance-manager/IMService.h b/server-tools/instance-manager/IMService.h deleted file mode 100644 index aceafb2fca6..00000000000 --- a/server-tools/instance-manager/IMService.h +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright (C) 2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#pragma once -#include "WindowsService.h" - -class IMService: public WindowsService -{ -public: - static int main(); - -private: - IMService(void); - ~IMService(void); - -protected: - void Log(const char *msg); - void Stop(); - void Run(DWORD argc, LPTSTR *argv); -}; diff --git a/server-tools/instance-manager/Makefile.am b/server-tools/instance-manager/Makefile.am deleted file mode 100644 index 19c4ac8de19..00000000000 --- a/server-tools/instance-manager/Makefile.am +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright (C) 2004 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 - -INCLUDES= @ZLIB_INCLUDES@ -I$(top_srcdir)/include \ - @openssl_includes@ -I$(top_builddir)/include - -DEFS= -DMYSQL_INSTANCE_MANAGER -DMYSQL_SERVER - -# As all autoconf variables depend from ${prefix} and being resolved only when -# make is run, we can not put these defines to a header file (e.g. to -# default_options.h, generated from default_options.h.in) -# See automake/autoconf docs for details - -noinst_LTLIBRARIES= liboptions.la -noinst_LIBRARIES= libnet.a - -liboptions_la_CXXFLAGS= $(CXXFLAGS) \ - -DDEFAULT_PID_FILE_NAME="$(localstatedir)/mysqlmanager.pid" \ - -DDEFAULT_LOG_FILE_NAME="$(localstatedir)/mysqlmanager.log" \ - -DDEFAULT_SOCKET_FILE_NAME="/tmp/mysqlmanager.sock" \ - -DDEFAULT_PASSWORD_FILE_NAME="/etc/mysqlmanager.passwd" \ - -DDEFAULT_MYSQLD_PATH="$(libexecdir)/mysqld$(EXEEXT)" \ - -DDEFAULT_CONFIG_FILE="my.cnf" \ - -DPROTOCOL_VERSION=@PROTOCOL_VERSION@ - -liboptions_la_SOURCES= options.h options.cc priv.h priv.cc -liboptions_la_LIBADD= $(top_builddir)/libmysql/get_password.lo - -# MySQL sometimes uses symlinks to reuse code -# All symlinked files are grouped in libnet.a - -nodist_libnet_a_SOURCES= net_serv.cc client_settings.h -libnet_a_LIBADD= $(top_builddir)/sql/password.$(OBJEXT) \ - $(top_builddir)/sql/pack.$(OBJEXT) \ - $(top_builddir)/sql/sql_state.$(OBJEXT) \ - $(top_builddir)/sql/mini_client_errors.$(OBJEXT)\ - $(top_builddir)/sql/client.$(OBJEXT) - -CLEANFILES= net_serv.cc client_settings.h - -net_serv.cc: - rm -f net_serv.cc - @LN_CP_F@ $(top_srcdir)/sql/net_serv.cc net_serv.cc - -client_settings.h: - rm -f client_settings.h - @LN_CP_F@ $(top_srcdir)/sql/client_settings.h client_settings.h - -libexec_PROGRAMS= mysqlmanager - -mysqlmanager_CXXFLAGS= - -mysqlmanager_SOURCES= command.cc command.h mysqlmanager.cc \ - manager.h manager.cc log.h log.cc \ - thread_registry.h thread_registry.cc \ - listener.h listener.cc protocol.h protocol.cc \ - mysql_connection.h mysql_connection.cc \ - user_map.h user_map.cc \ - messages.h messages.cc \ - commands.h commands.cc \ - instance.h instance.cc \ - instance_map.h instance_map.cc\ - instance_options.h instance_options.cc \ - buffer.h buffer.cc parse.cc parse.h \ - guardian.cc guardian.h \ - parse_output.cc parse_output.h \ - mysql_manager_error.h \ - portability.h \ - exit_codes.h \ - user_management_commands.h \ - user_management_commands.cc \ - angel.h \ - angel.cc - -mysqlmanager_LDADD= @CLIENT_EXTRA_LDFLAGS@ \ - liboptions.la \ - libnet.a \ - $(top_builddir)/vio/libvio.a \ - $(top_builddir)/mysys/libmysys.a \ - $(top_builddir)/strings/libmystrings.a \ - $(top_builddir)/dbug/libdbug.a \ - @openssl_libs@ @yassl_libs@ @ZLIB_LIBS@ - -EXTRA_DIST = WindowsService.cpp WindowsService.h IMService.cpp \ - IMService.h CMakeLists.txt - -tags: - ctags -R *.h *.cc - -# Don't update the files from bitkeeper -%::SCCS/s.% diff --git a/server-tools/instance-manager/README b/server-tools/instance-manager/README deleted file mode 100644 index ac799775003..00000000000 --- a/server-tools/instance-manager/README +++ /dev/null @@ -1,11 +0,0 @@ -Instance Manager - manage MySQL instances locally and remotely. - -File description: - mysqlmanager.cc - entry point to the manager, main, - options.{h,cc} - handle startup options - manager.{h,cc} - manager process - mysql_connection.{h,cc} - handle one connection with mysql client. - -See also instance manager architecture description in mysqlmanager.cc. - - diff --git a/server-tools/instance-manager/WindowsService.cpp b/server-tools/instance-manager/WindowsService.cpp deleted file mode 100644 index 14795e2225a..00000000000 --- a/server-tools/instance-manager/WindowsService.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* Copyright (C) 2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "my_global.h" -#include -#include "WindowsService.h" - -static WindowsService *gService; - -WindowsService::WindowsService(const char *p_serviceName, - const char *p_displayName) : - statusCheckpoint(0), - serviceName(p_serviceName), - displayName(p_displayName), - inited(FALSE), - dwAcceptedControls(SERVICE_ACCEPT_STOP), - debugging(FALSE) -{ - DBUG_ASSERT(serviceName != NULL); - - /* TODO: shouldn't we check displayName too (can it really be NULL)? */ - - /* WindowsService is assumed to be singleton. Let's assure this. */ - DBUG_ASSERT(gService == NULL); - - gService= this; - - status.dwServiceType= SERVICE_WIN32_OWN_PROCESS; - status.dwServiceSpecificExitCode= 0; -} - -WindowsService::~WindowsService(void) -{ -} - -BOOL WindowsService::Install(const char *username, const char *password) -{ - bool ret_val= FALSE; - SC_HANDLE newService; - SC_HANDLE scm; - - if (IsInstalled()) - return TRUE; - - // determine the name of the currently executing file - char szFilePath[_MAX_PATH]; - GetModuleFileName(NULL, szFilePath, sizeof(szFilePath)); - - // open a connection to the SCM - if (!(scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE))) - return FALSE; - - newService= CreateService(scm, serviceName, displayName, - SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, - SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, - szFilePath, NULL, NULL, NULL, username, - password); - - if (newService) - { - CloseServiceHandle(newService); - ret_val= TRUE; - } - - CloseServiceHandle(scm); - return ret_val; -} - -BOOL WindowsService::Init() -{ - DBUG_ASSERT(serviceName != NULL); - - if (inited) - return TRUE; - - SERVICE_TABLE_ENTRY stb[] = - { - { (LPSTR)serviceName, (LPSERVICE_MAIN_FUNCTION) ServiceMain}, - { NULL, NULL } - }; - inited= TRUE; - return StartServiceCtrlDispatcher(stb); //register with the Service Manager -} - -BOOL WindowsService::Remove() -{ - bool ret_val= FALSE; - - if (!IsInstalled()) - return TRUE; - - // open a connection to the SCM - SC_HANDLE scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE); - if (!scm) - return FALSE; - - SC_HANDLE service= OpenService(scm, serviceName, DELETE); - if (service) - { - if (DeleteService(service)) - ret_val= TRUE; - DWORD dw= ::GetLastError(); - CloseServiceHandle(service); - } - - CloseServiceHandle(scm); - return ret_val; -} - -BOOL WindowsService::IsInstalled() -{ - BOOL ret_val= FALSE; - - SC_HANDLE scm= ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); - SC_HANDLE serv_handle= ::OpenService(scm, serviceName, SERVICE_QUERY_STATUS); - - ret_val= serv_handle != NULL; - - ::CloseServiceHandle(serv_handle); - ::CloseServiceHandle(scm); - - return ret_val; -} - -void WindowsService::SetAcceptedControls(DWORD acceptedControls) -{ - dwAcceptedControls= acceptedControls; -} - - -BOOL WindowsService::ReportStatus(DWORD currentState, DWORD waitHint, - DWORD dwError) -{ - if (debugging) - return TRUE; - - if(currentState == SERVICE_START_PENDING) - status.dwControlsAccepted= 0; - else - status.dwControlsAccepted= dwAcceptedControls; - - status.dwCurrentState= currentState; - status.dwWin32ExitCode= dwError != 0 ? - ERROR_SERVICE_SPECIFIC_ERROR : NO_ERROR; - status.dwWaitHint= waitHint; - status.dwServiceSpecificExitCode= dwError; - - if(currentState == SERVICE_RUNNING || currentState == SERVICE_STOPPED) - { - status.dwCheckPoint= 0; - statusCheckpoint= 0; - } - else - status.dwCheckPoint= ++statusCheckpoint; - - // Report the status of the service to the service control manager. - BOOL result= SetServiceStatus(statusHandle, &status); - if (!result) - Log("ReportStatus failed"); - - return result; -} - -void WindowsService::RegisterAndRun(DWORD argc, LPTSTR *argv) -{ - statusHandle= ::RegisterServiceCtrlHandler(serviceName, ControlHandler); - if (statusHandle && ReportStatus(SERVICE_START_PENDING)) - Run(argc, argv); - ReportStatus(SERVICE_STOPPED); -} - -void WindowsService::HandleControlCode(DWORD opcode) -{ - // Handle the requested control code. - switch(opcode) { - case SERVICE_CONTROL_STOP: - // Stop the service. - status.dwCurrentState= SERVICE_STOP_PENDING; - Stop(); - break; - - case SERVICE_CONTROL_PAUSE: - status.dwCurrentState= SERVICE_PAUSE_PENDING; - Pause(); - break; - - case SERVICE_CONTROL_CONTINUE: - status.dwCurrentState= SERVICE_CONTINUE_PENDING; - Continue(); - break; - - case SERVICE_CONTROL_SHUTDOWN: - Shutdown(); - break; - - case SERVICE_CONTROL_INTERROGATE: - ReportStatus(status.dwCurrentState); - break; - - default: - // invalid control code - break; - } -} - -void WINAPI WindowsService::ServiceMain(DWORD argc, LPTSTR *argv) -{ - DBUG_ASSERT(gService != NULL); - - // register our service control handler: - gService->RegisterAndRun(argc, argv); -} - -void WINAPI WindowsService::ControlHandler(DWORD opcode) -{ - DBUG_ASSERT(gService != NULL); - - return gService->HandleControlCode(opcode); -} diff --git a/server-tools/instance-manager/WindowsService.h b/server-tools/instance-manager/WindowsService.h deleted file mode 100644 index 02a499e5f0c..00000000000 --- a/server-tools/instance-manager/WindowsService.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (C) 2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#pragma once - -class WindowsService -{ -protected: - bool inited; - const char *serviceName; - const char *displayName; - SERVICE_STATUS_HANDLE statusHandle; - DWORD statusCheckpoint; - SERVICE_STATUS status; - DWORD dwAcceptedControls; - bool debugging; - -public: - WindowsService(const char *p_serviceName, const char *p_displayName); - ~WindowsService(void); - - BOOL Install(const char *username, const char *password); - BOOL Remove(); - BOOL Init(); - BOOL IsInstalled(); - void SetAcceptedControls(DWORD acceptedControls); - void Debug(bool debugFlag) { debugging= debugFlag; } - -public: - static void WINAPI ServiceMain(DWORD argc, LPTSTR *argv); - static void WINAPI ControlHandler(DWORD CtrlType); - -protected: - virtual void Run(DWORD argc, LPTSTR *argv)= 0; - virtual void Stop() {} - virtual void Shutdown() {} - virtual void Pause() {} - virtual void Continue() {} - virtual void Log(const char *msg) {} - - BOOL ReportStatus(DWORD currentStatus, DWORD waitHint= 3000, DWORD dwError=0); - void HandleControlCode(DWORD opcode); - void RegisterAndRun(DWORD argc, LPTSTR *argv); -}; diff --git a/server-tools/instance-manager/angel.cc b/server-tools/instance-manager/angel.cc deleted file mode 100644 index 64515c8498c..00000000000 --- a/server-tools/instance-manager/angel.cc +++ /dev/null @@ -1,407 +0,0 @@ -/* Copyright (C) 2003-2006 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 */ - -#ifndef __WIN__ - -#include "angel.h" - -#include -/* - sys/wait.h is needed for waitpid(). Unfortunately, there is no MySQL - include file, that can serve for this. Include it before MySQL system - headers so that we can change system defines if needed. -*/ - -#include "my_global.h" -#include "my_alarm.h" -#include "my_dir.h" -#include "my_sys.h" - -/* Include other IM files. */ - -#include "log.h" -#include "manager.h" -#include "options.h" -#include "priv.h" - -/************************************************************************/ - -enum { CHILD_OK= 0, CHILD_NEED_RESPAWN, CHILD_EXIT_ANGEL }; - -static int log_fd; - -static volatile sig_atomic_t child_status= CHILD_OK; -static volatile sig_atomic_t child_exit_code= 0; -static volatile sig_atomic_t shutdown_request_signo= 0; - - -/************************************************************************/ -/** - Open log file. - - @return - TRUE on error; - FALSE on success. -*************************************************************************/ - -static bool open_log_file() -{ - log_info("Angel: opening log file '%s'...", - (const char *) Options::Daemon::log_file_name); - - log_fd= open(Options::Daemon::log_file_name, - O_WRONLY | O_CREAT | O_APPEND | O_NOCTTY, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - - if (log_fd < 0) - { - log_error("Can not open log file '%s': %s.", - (const char *) Options::Daemon::log_file_name, - (const char *) strerror(errno)); - - return TRUE; - } - - return FALSE; -} - - -/************************************************************************/ -/** - Detach the process from controlling tty. - - @return - TRUE on error; - FALSE on success. -*************************************************************************/ - -static bool detach_process() -{ - /* - Become a session leader (the goal is not to have a controlling tty). - - setsid() must succeed because child is guaranteed not to be a process - group leader (it belongs to the process group of the parent). - - NOTE: if we now don't have a controlling tty we will not receive - tty-related signals - no need to ignore them. - */ - - if (setsid() < 0) - { - log_error("setsid() failed: %s.", (const char *) strerror(errno)); - return -1; - } - - /* Close STDIN. */ - - log_info("Angel: preparing standard streams."); - - if (close(STDIN_FILENO) < 0) - { - log_error("Warning: can not close stdin (%s)." - "Trying to continue...", - (const char *) strerror(errno)); - } - - /* Dup STDOUT and STDERR to the log file. */ - - if (dup2(log_fd, STDOUT_FILENO) < 0 || - dup2(log_fd, STDERR_FILENO) < 0) - { - log_error("Can not redirect stdout and stderr to the log file: %s.", - (const char *) strerror(errno)); - - return TRUE; - } - - if (log_fd != STDOUT_FILENO && log_fd != STDERR_FILENO) - { - if (close(log_fd) < 0) - { - log_error("Can not close original log file handler (%d): %s. " - "Trying to continue...", - (int) log_fd, - (const char *) strerror(errno)); - } - } - - return FALSE; -} - - -/************************************************************************/ -/** - Create PID file. - - @return - TRUE on error; - FALSE on success. -*************************************************************************/ - -static bool create_pid_file() -{ - if (create_pid_file(Options::Daemon::angel_pid_file_name, getpid())) - { - log_error("Angel: can not create pid file (%s).", - (const char *) Options::Daemon::angel_pid_file_name); - - return TRUE; - } - - log_info("Angel: pid file (%s) created.", - (const char *) Options::Daemon::angel_pid_file_name); - - return FALSE; -} - - -/************************************************************************/ -/** - SIGCHLD handler. - - Reap child, analyze child exit code, and set child_status - appropriately. -*************************************************************************/ - -extern "C" void reap_child(int); - -void reap_child(int __attribute__((unused)) signo) -{ - /* NOTE: As we have only one child, no need to cycle waitpid(). */ - - int exit_code; - - if (waitpid(0, &exit_code, WNOHANG) > 0) - { - child_exit_code= exit_code; - child_status= exit_code ? CHILD_NEED_RESPAWN : CHILD_EXIT_ANGEL; - } -} - - -/************************************************************************/ -/** - SIGTERM, SIGHUP, SIGINT handler. - - Set termination status and return. -*************************************************************************/ - -extern "C" void terminate(int signo); -void terminate(int signo) -{ - shutdown_request_signo= signo; -} - - -/************************************************************************/ -/** - Angel main loop. - - @return - The function returns exit status for global main(): - 0 -- program completed successfully; - !0 -- error occurred. -*************************************************************************/ - -static int angel_main_loop() -{ - /* - Install signal handlers. - - NOTE: Although signal handlers are needed only for parent process - (IM-angel), we should install them before fork() in order to avoid race - condition (i.e. to be sure, that IM-angel will receive SIGCHLD in any - case). - */ - - sigset_t wait_for_signals_mask; - - struct sigaction sa_chld; - struct sigaction sa_term; - struct sigaction sa_chld_orig; - struct sigaction sa_term_orig; - struct sigaction sa_int_orig; - struct sigaction sa_hup_orig; - - log_info("Angel: setting necessary signal actions..."); - - sigemptyset(&wait_for_signals_mask); - - sigemptyset(&sa_chld.sa_mask); - sa_chld.sa_handler= reap_child; - sa_chld.sa_flags= SA_NOCLDSTOP; - - sigemptyset(&sa_term.sa_mask); - sa_term.sa_handler= terminate; - sa_term.sa_flags= 0; - - /* NOTE: sigaction() fails only if arguments are wrong. */ - - sigaction(SIGCHLD, &sa_chld, &sa_chld_orig); - sigaction(SIGTERM, &sa_term, &sa_term_orig); - sigaction(SIGINT, &sa_term, &sa_int_orig); - sigaction(SIGHUP, &sa_term, &sa_hup_orig); - - /* The main Angel loop. */ - - while (true) - { - /* Spawn a new Manager. */ - - log_info("Angel: forking Manager process..."); - - switch (fork()) { - case -1: - log_error("Angel: can not fork IM-main: %s.", - (const char *) strerror(errno)); - - return -1; - - case 0: - /* - We are in child process, which will be IM-main: - - Restore default signal actions to let the IM-main work with - signals as he wishes; - - Call Manager::main(); - */ - - log_info("Angel: Manager process created successfully."); - - /* NOTE: sigaction() fails only if arguments are wrong. */ - - sigaction(SIGCHLD, &sa_chld_orig, NULL); - sigaction(SIGTERM, &sa_term_orig, NULL); - sigaction(SIGINT, &sa_int_orig, NULL); - sigaction(SIGHUP, &sa_hup_orig, NULL); - - log_info("Angel: executing Manager..."); - - return Manager::main(); - } - - /* Wait for signals. */ - - log_info("Angel: waiting for signals..."); - - while (child_status == CHILD_OK && shutdown_request_signo == 0) - sigsuspend(&wait_for_signals_mask); - - /* Exit if one of shutdown signals has been caught. */ - - if (shutdown_request_signo) - { - log_info("Angel: received shutdown signal (%d). Exiting...", - (int) shutdown_request_signo); - - return 0; - } - - /* Manager process died. Respawn it if it was a failure. */ - - if (child_status == CHILD_NEED_RESPAWN) - { - child_status= CHILD_OK; - - log_error("Angel: Manager exited abnormally (exit code: %d).", - (int) child_exit_code); - - log_info("Angel: sleeping 1 second..."); - - sleep(1); /* don't respawn too fast */ - - log_info("Angel: respawning Manager..."); - - continue; - } - - /* Delete IM-angel PID file. */ - - my_delete(Options::Daemon::angel_pid_file_name, MYF(0)); - - /* IM-angel finished. */ - - log_info("Angel: Manager exited normally. Exiting..."); - - return 0; - } -} - - -/************************************************************************/ -/** - Angel main function. - - @return - The function returns exit status for global main(): - 0 -- program completed successfully; - !0 -- error occurred. -*************************************************************************/ - -int Angel::main() -{ - log_info("Angel: started."); - - /* Open log file. */ - - if (open_log_file()) - return -1; - - /* Fork a new process. */ - - log_info("Angel: daemonizing..."); - - switch (fork()) { - case -1: - /* - This is the main Instance Manager process, fork() failed. - Log an error and bail out with error code. - */ - - log_error("fork() failed: %s.", (const char *) strerror(errno)); - return -1; - - case 0: - /* We are in child process. Continue Angel::main() execution. */ - - break; - - default: - /* - We are in the parent process. Return 0 so that parent exits - successfully. - */ - - log_info("Angel: exiting from the original process..."); - - return 0; - } - - /* Detach child from controlling tty. */ - - if (detach_process()) - return -1; - - /* Create PID file. */ - - if (create_pid_file()) - return -1; - - /* Start Angel main loop. */ - - return angel_main_loop(); -} - -#endif // __WIN__ diff --git a/server-tools/instance-manager/angel.h b/server-tools/instance-manager/angel.h deleted file mode 100644 index db21c250972..00000000000 --- a/server-tools/instance-manager/angel.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (C) 2003-2006 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 */ - -#ifndef INCLUDES_MYSQL_ANGEL_H -#define INCLUDES_MYSQL_ANGEL_H - -#ifndef __WIN__ - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -#include - -class Angel -{ -public: - static int main(); -}; - -#endif // INCLUDES_MYSQL_ANGEL_H -#endif // __WIN__ diff --git a/server-tools/instance-manager/buffer.cc b/server-tools/instance-manager/buffer.cc deleted file mode 100644 index f197f42d009..00000000000 --- a/server-tools/instance-manager/buffer.cc +++ /dev/null @@ -1,110 +0,0 @@ -/* Copyright (C) 2004 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 */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "buffer.h" -#include - -const uint Buffer::BUFFER_INITIAL_SIZE= 4096; -const uint Buffer::MAX_BUFFER_SIZE= 16777216; - -/* - Puts the given string to the buffer. - - SYNOPSIS - append() - position start position in the buffer - string string to be put in the buffer - len_arg the length of the string. This way we can avoid some - strlens. - - DESCRIPTION - - The method puts a string into the buffer, starting from position . - In the case when the buffer is too small it reallocs the buffer. The - total size of the buffer is restricted with 16. - - RETURN - 0 - ok - 1 - got an error in reserve() -*/ - -int Buffer::append(size_t position, const char *string, size_t len_arg) -{ - if (reserve(position, len_arg)) - return 1; - - strnmov((char*) buffer + position, string, len_arg); - return 0; -} - - -/* - Checks whether the current buffer size is ok to put a string of the length - "len_arg" starting from "position" and reallocs it if no. - - SYNOPSIS - reserve() - position the number starting byte on the buffer to store a buffer - len_arg the length of the string. - - DESCRIPTION - - The method checks whether it is possible to put a string of the "len_arg" - length into the buffer, starting from "position" byte. In the case when the - buffer is too small it reallocs the buffer. The total size of the buffer is - restricted with 16 Mb. - - RETURN - 0 - ok - 1 - realloc error or we have come to the 16Mb barrier -*/ - -int Buffer::reserve(size_t position, size_t len_arg) -{ - if (position + len_arg >= MAX_BUFFER_SIZE) - goto err; - - if (position + len_arg >= buffer_size) - { - buffer= (uchar*) my_realloc(buffer, - min(MAX_BUFFER_SIZE, - max((uint) (buffer_size*1.5), - position + len_arg)), MYF(0)); - if (!(buffer)) - goto err; - buffer_size= (size_t) (buffer_size*1.5); - } - return 0; - -err: - error= 1; - return 1; -} - - -int Buffer::get_size() -{ - return (uint) buffer_size; -} - - -int Buffer::is_error() -{ - return error; -} diff --git a/server-tools/instance-manager/buffer.h b/server-tools/instance-manager/buffer.h deleted file mode 100644 index 3bd7a714437..00000000000 --- a/server-tools/instance-manager/buffer.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H -/* Copyright (C) 2004 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 */ - -#include -#include - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -/* - This class is a simple implementation of the buffer of varying size. - It is used to store MySQL client-server protocol packets. This is why - the maximum buffer size if 16Mb. (See internals manual section - 7. MySQL Client/Server Protocol) -*/ - -class Buffer -{ -private: - static const uint BUFFER_INITIAL_SIZE; - /* maximum buffer size is 16Mb */ - static const uint MAX_BUFFER_SIZE; - size_t buffer_size; - /* Error flag. Triggered if we get an error of some kind */ - int error; -public: - Buffer(size_t buffer_size_arg= BUFFER_INITIAL_SIZE) - :buffer_size(buffer_size_arg), error(0) - { - /* - As append() will invokes realloc() anyway, it's ok if malloc returns 0 - */ - if (!(buffer= (uchar*) my_malloc(buffer_size, MYF(0)))) - buffer_size= 0; - } - - ~Buffer() - { - my_free(buffer, MYF(0)); - } - -public: - uchar *buffer; - int get_size(); - int is_error(); - int append(size_t position, const char *string, size_t len_arg); - int reserve(size_t position, size_t len_arg); -}; - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H */ diff --git a/server-tools/instance-manager/command.cc b/server-tools/instance-manager/command.cc deleted file mode 100644 index ba84285ead2..00000000000 --- a/server-tools/instance-manager/command.cc +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2004 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 */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "manager.h" -#include "command.h" - -Command::Command() - :guardian(Manager::get_guardian()), - instance_map(Manager::get_instance_map()) -{} - -Command::~Command() -{} - diff --git a/server-tools/instance-manager/command.h b/server-tools/instance-manager/command.h deleted file mode 100644 index 25d8c9849e8..00000000000 --- a/server-tools/instance-manager/command.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H -/* Copyright (C) 2004 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 */ - -#include - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -/* Class responsible for allocation of IM commands. */ - -class Guardian; -class Instance_map; - -struct st_net; - -/* - Command - entry point for any command. - GangOf4: 'Command' design pattern -*/ - -class Command -{ -public: - Command(); - virtual ~Command(); - - /* - This operation incapsulates behaviour of the command. - - SYNOPSIS - net The network connection to the client. - connection_id Client connection ID - - RETURN - 0 On success - non 0 On error. Client error code is returned. - */ - virtual int execute(st_net *net, ulong connection_id) = 0; - -protected: - Guardian *guardian; - Instance_map *instance_map; -}; - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H */ diff --git a/server-tools/instance-manager/commands.cc b/server-tools/instance-manager/commands.cc deleted file mode 100644 index 56bd720b3e9..00000000000 --- a/server-tools/instance-manager/commands.cc +++ /dev/null @@ -1,1752 +0,0 @@ -/* Copyright (C) 2004 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 */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "commands.h" - -#include -#include -#include -#include - -#include "buffer.h" -#include "guardian.h" -#include "instance_map.h" -#include "log.h" -#include "manager.h" -#include "messages.h" -#include "mysqld_error.h" -#include "mysql_manager_error.h" -#include "options.h" -#include "priv.h" -#include "protocol.h" - -/************************************************************************** - {{{ Static functions. -**************************************************************************/ - -/** - modify_defaults_to_im_error -- a map of error codes of - mysys::modify_defaults_file() into Instance Manager error codes. -*/ - -static const int modify_defaults_to_im_error[]= { 0, ER_OUT_OF_RESOURCES, - ER_ACCESS_OPTION_FILE }; - - -/** - Parse version number from the version string. - - SYNOPSIS - parse_version_number() - version_str - version - version_size - - DESCRIPTION - TODO - - TODO: Move this function to Instance_options and parse version number - only once. - - NOTE: This function is used only in SHOW INSTANCE STATUS statement at the - moment. -*/ - -static int parse_version_number(const char *version_str, char *version, - uint version_size) -{ - const char *start= version_str; - const char *end; - - // skip garbage - while (!my_isdigit(default_charset_info, *start)) - start++; - - end= start; - // skip digits and dots - while (my_isdigit(default_charset_info, *end) || *end == '.') - end++; - - if ((uint)(end - start) >= version_size) - return -1; - - strncpy(version, start, end-start); - version[end-start]= '\0'; - - return 0; -} - -/************************************************************************** - }}} -**************************************************************************/ - -/************************************************************************** - Implementation of Instance_name. -**************************************************************************/ - -Instance_name::Instance_name(const LEX_STRING *name) -{ - str.str= str_buffer; - str.length= name->length; - - if (str.length > MAX_INSTANCE_NAME_SIZE - 1) - str.length= MAX_INSTANCE_NAME_SIZE - 1; - - strmake(str.str, name->str, str.length); -} - -/************************************************************************** - Implementation of Show_instances. -**************************************************************************/ - -/** - Implementation of SHOW INSTANCES statement. - - Possible error codes: - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instances::execute(st_net *net, ulong /* connection_id */) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net))) - return err_code; - - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instances::write_header(st_net *net) -{ - LIST name, state; - LEX_STRING name_field, state_field; - LIST *field_list; - - name_field.str= (char *) "instance_name"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - state_field.str= (char *) "state"; - state_field.length= DEFAULT_FIELD_LENGTH; - state.data= &state_field; - - field_list= list_add(NULL, &state); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instances::write_data(st_net *net) -{ - my_bool err_status= FALSE; - - Instance *instance; - Instance_map::Iterator iterator(instance_map); - - instance_map->lock(); - - while ((instance= iterator.next())) - { - Buffer send_buf; /* buffer for packets */ - size_t pos= 0; - - instance->lock(); - - const char *instance_name= instance->options.instance_name.str; - const char *state_name= instance->get_state_name(); - - if (store_to_protocol_packet(&send_buf, instance_name, &pos) || - store_to_protocol_packet(&send_buf, state_name, &pos) || - my_net_write(net, send_buf.buffer, pos)) - { - err_status= TRUE; - } - - instance->unlock(); - - if (err_status) - break; - } - - instance_map->unlock(); - - return err_status ? ER_OUT_OF_RESOURCES : 0; -} - - -/************************************************************************** - Implementation of Flush_instances. -**************************************************************************/ - -/** - Implementation of FLUSH INSTANCES statement. - - Possible error codes: - ER_OUT_OF_RESOURCES Not enough resources to complete the operation - ER_THERE_IS_ACTIVE_INSTACE If there is an active instance -*/ - -int Flush_instances::execute(st_net *net, ulong connection_id) -{ - int err_status= Manager::flush_instances(); - - if (err_status) - return err_status; - - return net_send_ok(net, connection_id, NULL) ? ER_OUT_OF_RESOURCES : 0; -} - - -/************************************************************************** - Implementation of Instance_cmd. -**************************************************************************/ - -Instance_cmd::Instance_cmd(const LEX_STRING *instance_name_arg): - instance_name(instance_name_arg) -{ - /* - MT-NOTE: we can not make a search for Instance object here, - because it can dissappear after releasing the lock. - */ -} - - -/************************************************************************** - Implementation of Abstract_instance_cmd. -**************************************************************************/ - -Abstract_instance_cmd::Abstract_instance_cmd( - const LEX_STRING *instance_name_arg) - :Instance_cmd(instance_name_arg) -{ -} - - -int Abstract_instance_cmd::execute(st_net *net, ulong connection_id) -{ - int err_code; - Instance *instance; - - instance_map->lock(); - - instance= instance_map->find(get_instance_name()); - - if (!instance) - { - instance_map->unlock(); - return ER_BAD_INSTANCE_NAME; - } - - instance->lock(); - instance_map->unlock(); - - err_code= execute_impl(net, instance); - - instance->unlock(); - - if (!err_code) - err_code= send_ok_response(net, connection_id); - - return err_code; -} - - -/************************************************************************** - Implementation of Show_instance_status. -**************************************************************************/ - -Show_instance_status::Show_instance_status(const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE STATUS statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_status::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_status::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_status::write_header(st_net *net) -{ - LIST name, state, version, version_number, mysqld_compatible; - LIST *field_list; - LEX_STRING name_field, state_field, version_field, - version_number_field, mysqld_compatible_field; - - /* Create list of the fileds to be passed to send_fields(). */ - - name_field.str= (char *) "instance_name"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - state_field.str= (char *) "state"; - state_field.length= DEFAULT_FIELD_LENGTH; - state.data= &state_field; - - version_field.str= (char *) "version"; - version_field.length= MAX_VERSION_LENGTH; - version.data= &version_field; - - version_number_field.str= (char *) "version_number"; - version_number_field.length= MAX_VERSION_LENGTH; - version_number.data= &version_number_field; - - mysqld_compatible_field.str= (char *) "mysqld_compatible"; - mysqld_compatible_field.length= DEFAULT_FIELD_LENGTH; - mysqld_compatible.data= &mysqld_compatible_field; - - field_list= list_add(NULL, &mysqld_compatible); - field_list= list_add(field_list, &version); - field_list= list_add(field_list, &version_number); - field_list= list_add(field_list, &state); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_status::write_data(st_net *net, Instance *instance) -{ - Buffer send_buf; /* buffer for packets */ - char version_num_buf[MAX_VERSION_LENGTH]; - size_t pos= 0; - - const char *state_name= instance->get_state_name(); - const char *version_tag= "unknown"; - const char *version_num= "unknown"; - const char *mysqld_compatible_status= - instance->is_mysqld_compatible() ? "yes" : "no"; - - if (instance->options.mysqld_version) - { - if (parse_version_number(instance->options.mysqld_version, version_num_buf, - sizeof(version_num_buf))) - return ER_OUT_OF_RESOURCES; - - version_num= version_num_buf; - version_tag= instance->options.mysqld_version; - } - - if (store_to_protocol_packet(&send_buf, get_instance_name()->str, &pos) || - store_to_protocol_packet(&send_buf, state_name, &pos) || - store_to_protocol_packet(&send_buf, version_num, &pos) || - store_to_protocol_packet(&send_buf, version_tag, &pos) || - store_to_protocol_packet(&send_buf, mysqld_compatible_status, &pos) || - my_net_write(net, send_buf.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - - return 0; -} - - -/************************************************************************** - Implementation of Show_instance_options. -**************************************************************************/ - -Show_instance_options::Show_instance_options( - const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE OPTIONS statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_options::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_options::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_options::write_header(st_net *net) -{ - LIST name, option; - LIST *field_list; - LEX_STRING name_field, option_field; - - /* Create list of the fileds to be passed to send_fields(). */ - - name_field.str= (char *) "option_name"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - option_field.str= (char *) "value"; - option_field.length= DEFAULT_FIELD_LENGTH; - option.data= &option_field; - - field_list= list_add(NULL, &option); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_options::write_data(st_net *net, Instance *instance) -{ - Buffer send_buff; /* buffer for packets */ - size_t pos= 0; - - if (store_to_protocol_packet(&send_buff, "instance_name", &pos) || - store_to_protocol_packet(&send_buff, get_instance_name()->str, &pos) || - my_net_write(net, send_buff.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - - /* Loop through the options. */ - - for (int i= 0; i < instance->options.get_num_options(); i++) - { - Named_value option= instance->options.get_option(i); - const char *option_value= option.get_value()[0] ? option.get_value() : ""; - - pos= 0; - - if (store_to_protocol_packet(&send_buff, option.get_name(), &pos) || - store_to_protocol_packet(&send_buff, option_value, &pos) || - my_net_write(net, send_buff.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - } - - return 0; -} - - -/************************************************************************** - Implementation of Start_instance. -**************************************************************************/ - -Start_instance::Start_instance(const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of START INSTANCE statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_INSTANCE_MISCONFIGURED The instance configuration is invalid - ER_INSTANCE_ALREADY_STARTED The instance is already started - ER_CANNOT_START_INSTANCE The instance could not have been started - - TODO: as soon as this method operates only with Instance, we probably - should introduce a new method (execute_stop_instance()) in Instance and - just call it from here. -*/ - -int Start_instance::execute_impl(st_net * /* net */, Instance *instance) -{ - if (!instance->is_configured()) - return ER_INSTANCE_MISCONFIGURED; - - if (instance->is_active()) - return ER_INSTANCE_ALREADY_STARTED; - - if (instance->start_mysqld()) - return ER_CANNOT_START_INSTANCE; - - instance->reset_stat(); - instance->set_state(Instance::NOT_STARTED); - - return 0; -} - - -int Start_instance::send_ok_response(st_net *net, ulong connection_id) -{ - if (net_send_ok(net, connection_id, "Instance started")) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation of Stop_instance. -**************************************************************************/ - -Stop_instance::Stop_instance(const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of STOP INSTANCE statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation - - TODO: as soon as this method operates only with Instance, we probably - should introduce a new method (execute_stop_instance()) in Instance and - just call it from here. -*/ - -int Stop_instance::execute_impl(st_net * /* net */, Instance *instance) -{ - if (!instance->is_active()) - return ER_INSTANCE_IS_NOT_STARTED; - - instance->set_state(Instance::STOPPED); - - return instance->stop_mysqld() ? ER_STOP_INSTANCE : 0; -} - - -int Stop_instance::send_ok_response(st_net *net, ulong connection_id) -{ - if (net_send_ok(net, connection_id, NULL)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation for Create_instance. -**************************************************************************/ - -Create_instance::Create_instance(const LEX_STRING *instance_name_arg) - :Instance_cmd(instance_name_arg) -{ -} - - -/** - This operation initializes Create_instance object. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing instance options. - - RETURN - FALSE On success. - TRUE On error. -*/ - -bool Create_instance::init(const char **text) -{ - return options.init() || parse_args(text); -} - - -/** - This operation parses CREATE INSTANCE options. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing instance options. - - RETURN - FALSE On success. - TRUE On syntax error. -*/ - -bool Create_instance::parse_args(const char **text) -{ - size_t len; - - /* Check if we have something (and trim leading spaces). */ - - get_word(text, &len, NONSPACE); - - if (len == 0) - return FALSE; /* OK: no option. */ - - /* Main parsing loop. */ - - while (TRUE) - { - LEX_STRING option_name; - char *option_name_str; - char *option_value_str= NULL; - - /* Looking for option name. */ - - get_word(text, &option_name.length, OPTION_NAME); - - if (option_name.length == 0) - return TRUE; /* Syntax error: option name expected. */ - - option_name.str= (char *) *text; - *text+= option_name.length; - - /* Looking for equal sign. */ - - skip_spaces(text); - - if (**text == '=') - { - ++(*text); /* Skip an equal sign. */ - - /* Looking for option value. */ - - skip_spaces(text); - - if (!**text) - return TRUE; /* Syntax error: EOS when option value expected. */ - - if (**text != '\'' && **text != '"') - { - /* Option value is a simple token. */ - - LEX_STRING option_value; - - get_word(text, &option_value.length, ALPHANUM); - - if (option_value.length == 0) - return TRUE; /* internal parser error. */ - - option_value.str= (char *) *text; - *text+= option_value.length; - - if (!(option_value_str= Named_value::alloc_str(&option_value))) - return TRUE; /* out of memory during parsing. */ - } - else - { - /* Option value is a string. */ - - if (parse_option_value(*text, &len, &option_value_str)) - return TRUE; /* Syntax error: invalid string specification. */ - - *text+= len; - } - } - - if (!option_value_str) - { - LEX_STRING empty_str= { C_STRING_WITH_LEN("") }; - - if (!(option_value_str= Named_value::alloc_str(&empty_str))) - return TRUE; /* out of memory during parsing. */ - } - - if (!(option_name_str= Named_value::alloc_str(&option_name))) - { - Named_value::free_str(&option_value_str); - return TRUE; /* out of memory during parsing. */ - } - - { - Named_value option(option_name_str, option_value_str); - - if (options.add_element(&option)) - { - option.free(); - return TRUE; /* out of memory during parsing. */ - } - } - - skip_spaces(text); - - if (!**text) - return FALSE; /* OK: end of options. */ - - if (**text != ',') - return TRUE; /* Syntax error: comma expected. */ - - ++(*text); - } -} - - -/** - Implementation of CREATE INSTANCE statement. - - Possible error codes: - ER_MALFORMED_INSTANCE_NAME Instance name is malformed - ER_CREATE_EXISTING_INSTANCE There is an instance with the given name - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Create_instance::execute(st_net *net, ulong connection_id) -{ - int err_code; - Instance *instance; - - /* Check that the name is valid and there is no instance with such name. */ - - if (!Instance::is_name_valid(get_instance_name())) - return ER_MALFORMED_INSTANCE_NAME; - - /* - NOTE: In order to prevent race condition, we should perform all operations - on under acquired lock. - */ - - instance_map->lock(); - - if (instance_map->find(get_instance_name())) - { - instance_map->unlock(); - return ER_CREATE_EXISTING_INSTANCE; - } - - if ((err_code= instance_map->create_instance(get_instance_name(), &options))) - { - instance_map->unlock(); - return err_code; - } - - instance= instance_map->find(get_instance_name()); - DBUG_ASSERT(instance); - - if ((err_code= create_instance_in_file(get_instance_name(), &options))) - { - instance_map->remove_instance(instance); /* instance is deleted here. */ - - instance_map->unlock(); - return err_code; - } - - /* - CREATE INSTANCE must not lead to start instance, even if it guarded. - - TODO: The problem however is that if Instance Manager restarts after - creating instance, the instance will be restarted (see also BUG#19718). - */ - - instance->set_state(Instance::STOPPED); - - /* That's all. */ - - instance_map->unlock(); - - /* Send the result. */ - - if (net_send_ok(net, connection_id, NULL)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation for Drop_instance. -**************************************************************************/ - -Drop_instance::Drop_instance(const LEX_STRING *instance_name_arg) - :Instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of DROP INSTANCE statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_DROP_ACTIVE_INSTANCE The specified instance is active - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Drop_instance::execute(st_net *net, ulong connection_id) -{ - int err_code; - Instance *instance; - - /* Lock Guardian, then Instance_map. */ - - instance_map->lock(); - - /* Find an instance. */ - - instance= instance_map->find(get_instance_name()); - - if (!instance) - { - instance_map->unlock(); - return ER_BAD_INSTANCE_NAME; - } - - instance->lock(); - - /* Check that the instance is offline. */ - - if (instance->is_active()) - { - instance->unlock(); - instance_map->unlock(); - - return ER_DROP_ACTIVE_INSTANCE; - } - - /* Try to remove instance from the file. */ - - err_code= modify_defaults_file(Options::Main::config_file, NULL, NULL, - get_instance_name()->str, MY_REMOVE_SECTION); - DBUG_ASSERT(err_code >= 0 && err_code <= 2); - - if (err_code) - { - log_error("Can not remove instance '%s' from defaults file (%s). " - "Original error code: %d.", - (const char *) get_instance_name()->str, - (const char *) Options::Main::config_file, - (int) err_code); - - instance->unlock(); - instance_map->unlock(); - - return modify_defaults_to_im_error[err_code]; - } - - /* Unlock the instance before destroy. */ - - instance->unlock(); - - /* - Remove instance from the instance map - (the instance will be also destroyed here). - */ - - instance_map->remove_instance(instance); - - /* Unlock the instance map. */ - - instance_map->unlock(); - - /* That's all: send ok. */ - - if (net_send_ok(net, connection_id, "Instance dropped")) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation for Show_instance_log. -**************************************************************************/ - -Show_instance_log::Show_instance_log(const LEX_STRING *instance_name_arg, - Log_type log_type_arg, - uint size_arg, uint offset_arg) - :Abstract_instance_cmd(instance_name_arg), - log_type(log_type_arg), - size(size_arg), - offset(offset_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE LOG statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OFFSET_ERROR We were requested to read negative number of - bytes from the log - ER_NO_SUCH_LOG The specified type of log is not available for - the given instance - ER_GUESS_LOGFILE IM wasn't able to figure out the log - placement, while it is enabled. Probably user - should specify the path to the logfile - explicitly. - ER_OPEN_LOGFILE Cannot open the logfile - ER_READ_FILE Cannot read the logfile - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_log::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= check_params(instance))) - return err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_log::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_log::check_params(Instance *instance) -{ - const char *logpath= instance->options.logs[log_type]; - - /* Cannot read negative number of bytes. */ - - if (offset > size) - return ER_OFFSET_ERROR; - - /* Instance has no such log. */ - - if (logpath == NULL) - return ER_NO_SUCH_LOG; - - if (*logpath == '\0') - return ER_GUESS_LOGFILE; - - return 0; -} - - -int Show_instance_log::write_header(st_net *net) -{ - LIST name; - LIST *field_list; - LEX_STRING name_field; - - /* Create list of the fields to be passed to send_fields(). */ - - name_field.str= (char *) "Log"; - name_field.length= DEFAULT_FIELD_LENGTH; - - name.data= &name_field; - - field_list= list_add(NULL, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_log::write_data(st_net *net, Instance *instance) -{ - Buffer send_buff; /* buffer for packets */ - size_t pos= 0; - - const char *logpath= instance->options.logs[log_type]; - File fd; - - size_t buff_size; - size_t read_len; - - MY_STAT file_stat; - Buffer read_buff; - - if ((fd= my_open(logpath, O_RDONLY | O_BINARY, MYF(MY_WME))) <= 0) - return ER_OPEN_LOGFILE; - - /* my_fstat doesn't use the flag parameter */ - if (my_fstat(fd, &file_stat, MYF(0))) - { - close(fd); - return ER_OUT_OF_RESOURCES; - } - - /* calculate buffer size */ - buff_size= (size - offset); - - read_buff.reserve(0, buff_size); - - /* read in one chunk */ - read_len= (int)my_seek(fd, file_stat.st_size - size, MY_SEEK_SET, MYF(0)); - - if ((read_len= my_read(fd, read_buff.buffer, buff_size, MYF(0))) == - MY_FILE_ERROR) - { - close(fd); - return ER_READ_FILE; - } - - close(fd); - - if (store_to_protocol_packet(&send_buff, (char*) read_buff.buffer, &pos, - read_len) || - my_net_write(net, send_buff.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - - return 0; -} - - -/************************************************************************** - Implementation of Show_instance_log_files. -**************************************************************************/ - -Show_instance_log_files::Show_instance_log_files - (const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE LOG FILES statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_log_files::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_log_files::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_log_files::write_header(st_net *net) -{ - LIST name, path, size; - LIST *field_list; - LEX_STRING name_field, path_field, size_field; - - /* Create list of the fileds to be passed to send_fields(). */ - - name_field.str= (char *) "Logfile"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - path_field.str= (char *) "Path"; - path_field.length= DEFAULT_FIELD_LENGTH; - path.data= &path_field; - - size_field.str= (char *) "File size"; - size_field.length= DEFAULT_FIELD_LENGTH; - size.data= &size_field; - - field_list= list_add(NULL, &size); - field_list= list_add(field_list, &path); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_log_files::write_data(st_net *net, Instance *instance) -{ - Buffer send_buff; /* buffer for packets */ - - /* - We have alike structure in instance_options.cc. We use such to be able - to loop through the options, which we need to handle in some common way. - */ - struct log_files_st - { - const char *name; - const char *value; - } logs[]= - { - {"ERROR LOG", instance->options.logs[IM_LOG_ERROR]}, - {"GENERAL LOG", instance->options.logs[IM_LOG_GENERAL]}, - {"SLOW LOG", instance->options.logs[IM_LOG_SLOW]}, - {NULL, NULL} - }; - struct log_files_st *log_files; - - for (log_files= logs; log_files->name; log_files++) - { - if (!log_files->value) - continue; - - struct stat file_stat; - /* - Save some more space for the log file names. In fact all - we need is strlen("GENERAL_LOG") + 1 - */ - enum { LOG_NAME_BUFFER_SIZE= 20 }; - char buff[LOG_NAME_BUFFER_SIZE]; - - size_t pos= 0; - - const char *log_path= ""; - const char *log_size= "0"; - - if (!stat(log_files->value, &file_stat) && - MY_S_ISREG(file_stat.st_mode)) - { - int10_to_str(file_stat.st_size, buff, 10); - - log_path= log_files->value; - log_size= buff; - } - - if (store_to_protocol_packet(&send_buff, log_files->name, &pos) || - store_to_protocol_packet(&send_buff, log_path, &pos) || - store_to_protocol_packet(&send_buff, log_size, &pos) || - my_net_write(net, send_buff.buffer, pos)) - return ER_OUT_OF_RESOURCES; - } - - return 0; -} - - -/************************************************************************** - Implementation of Abstract_option_cmd. -**************************************************************************/ - -/** - Instance_options_list -- a data class representing a list of options for - some instance. -*/ - -class Instance_options_list -{ -public: - Instance_options_list(const LEX_STRING *instance_name_arg); - -public: - bool init(); - - const LEX_STRING *get_instance_name() const - { - return instance_name.get_str(); - } - -public: - /* - This member is set and used only in Abstract_option_cmd::execute_impl(). - Normally it is not used (and should not). - - The problem is that construction and execution of commands are made not - in one transaction (not under one lock session). So, we can not initialize - instance in constructor and use it in execution. - */ - Instance *instance; - - Named_value_arr options; - -private: - Instance_name instance_name; -}; - - -/**************************************************************************/ - -Instance_options_list::Instance_options_list( - const LEX_STRING *instance_name_arg) - :instance(NULL), - instance_name(instance_name_arg) -{ -} - - -bool Instance_options_list::init() -{ - return options.init(); -} - - -/**************************************************************************/ - -C_MODE_START - -static uchar* get_item_key(const uchar* item, size_t* len, - my_bool __attribute__((unused)) t) -{ - const Instance_options_list *lst= (const Instance_options_list *) item; - *len= lst->get_instance_name()->length; - return (uchar *) lst->get_instance_name()->str; -} - -static void delete_item(void *item) -{ - delete (Instance_options_list *) item; -} - -C_MODE_END - - -/**************************************************************************/ - -Abstract_option_cmd::Abstract_option_cmd() - :initialized(FALSE) -{ -} - - -Abstract_option_cmd::~Abstract_option_cmd() -{ - if (initialized) - hash_free(&instance_options_map); -} - - -bool Abstract_option_cmd::add_option(const LEX_STRING *instance_name, - Named_value *option) -{ - Instance_options_list *lst= get_instance_options_list(instance_name); - - if (!lst) - return TRUE; - - lst->options.add_element(option); - - return FALSE; -} - - -bool Abstract_option_cmd::init(const char **text) -{ - static const int INITIAL_HASH_SIZE= 16; - - if (hash_init(&instance_options_map, default_charset_info, - INITIAL_HASH_SIZE, 0, 0, get_item_key, delete_item, 0)) - return TRUE; - - if (parse_args(text)) - return TRUE; - - initialized= TRUE; - - return FALSE; -} - - -/** - Correct the option file. The "skip" option is used to remove the found - option. - - SYNOPSIS - Abstract_option_cmd::correct_file() - skip Skip the option, being searched while writing the result file. - That is, to delete it. - - RETURN - 0 Success - ER_OUT_OF_RESOURCES Not enough resources to complete the operation - ER_ACCESS_OPTION_FILE Cannot access the option file -*/ - -int Abstract_option_cmd::correct_file(Instance *instance, Named_value *option, - bool skip) -{ - int err_code= modify_defaults_file(Options::Main::config_file, - option->get_name(), - option->get_value(), - instance->get_name()->str, - skip); - - DBUG_ASSERT(err_code >= 0 && err_code <= 2); - - if (err_code) - { - log_error("Can not modify option (%s) in defaults file (%s). " - "Original error code: %d.", - (const char *) option->get_name(), - (const char *) Options::Main::config_file, - (int) err_code); - } - - return modify_defaults_to_im_error[err_code]; -} - - -/** - Lock Instance Map and call execute_impl(). - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_INCOMPATIBLE_OPTION The specified option can not be set for - mysqld-compatible instance - ER_INSTANCE_IS_ACTIVE The specified instance is active - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Abstract_option_cmd::execute(st_net *net, ulong connection_id) -{ - int err_code; - - instance_map->lock(); - - err_code= execute_impl(net, connection_id); - - instance_map->unlock(); - - return err_code; -} - - -Instance_options_list * -Abstract_option_cmd::get_instance_options_list(const LEX_STRING *instance_name) -{ - Instance_options_list *lst= - (Instance_options_list *) hash_search(&instance_options_map, - (uchar *) instance_name->str, - instance_name->length); - - if (!lst) - { - lst= new Instance_options_list(instance_name); - - if (!lst) - return NULL; - - if (lst->init() || my_hash_insert(&instance_options_map, (uchar *) lst)) - { - delete lst; - return NULL; - } - } - - return lst; -} - - -/** - Skeleton implementation of option-management command. - - MT-NOTE: Instance Map is locked before calling this operation. -*/ -int Abstract_option_cmd::execute_impl(st_net *net, ulong connection_id) -{ - int err_code= 0; - - /* Check that all the specified instances exist and are offline. */ - - for (uint i= 0; i < instance_options_map.records; ++i) - { - Instance_options_list *lst= - (Instance_options_list *) hash_element(&instance_options_map, i); - - bool instance_is_active; - - lst->instance= instance_map->find(lst->get_instance_name()); - - if (!lst->instance) - return ER_BAD_INSTANCE_NAME; - - lst->instance->lock(); - instance_is_active= lst->instance->is_active(); - lst->instance->unlock(); - - if (instance_is_active) - return ER_INSTANCE_IS_ACTIVE; - } - - /* Perform command-specific (SET/UNSET) actions. */ - - for (uint i= 0; i < instance_options_map.records; ++i) - { - Instance_options_list *lst= - (Instance_options_list *) hash_element(&instance_options_map, i); - - lst->instance->lock(); - - for (int j= 0; j < lst->options.get_size(); ++j) - { - Named_value option= lst->options.get_element(j); - err_code= process_option(lst->instance, &option); - - if (err_code) - break; - } - - lst->instance->unlock(); - - if (err_code) - break; - } - - if (err_code == 0) - net_send_ok(net, connection_id, NULL); - - return err_code; -} - - -/************************************************************************** - Implementation of Set_option. -**************************************************************************/ - -/** - This operation parses SET options. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing options. - - RETURN - FALSE On success. - TRUE On syntax error. -*/ - -bool Set_option::parse_args(const char **text) -{ - size_t len; - - /* Check if we have something (and trim leading spaces). */ - - get_word(text, &len, NONSPACE); - - if (len == 0) - return TRUE; /* Syntax error: no option. */ - - /* Main parsing loop. */ - - while (TRUE) - { - LEX_STRING instance_name; - LEX_STRING option_name; - char *option_name_str; - char *option_value_str= NULL; - - /* Looking for instance name. */ - - get_word(text, &instance_name.length, ALPHANUM); - - if (instance_name.length == 0) - return TRUE; /* Syntax error: instance name expected. */ - - instance_name.str= (char *) *text; - *text+= instance_name.length; - - skip_spaces(text); - - /* Check the the delimiter is a dot. */ - - if (**text != '.') - return TRUE; /* Syntax error: dot expected. */ - - ++(*text); - - /* Looking for option name. */ - - get_word(text, &option_name.length, OPTION_NAME); - - if (option_name.length == 0) - return TRUE; /* Syntax error: option name expected. */ - - option_name.str= (char *) *text; - *text+= option_name.length; - - /* Looking for equal sign. */ - - skip_spaces(text); - - if (**text == '=') - { - ++(*text); /* Skip an equal sign. */ - - /* Looking for option value. */ - - skip_spaces(text); - - if (!**text) - return TRUE; /* Syntax error: EOS when option value expected. */ - - if (**text != '\'' && **text != '"') - { - /* Option value is a simple token. */ - - LEX_STRING option_value; - - get_word(text, &option_value.length, ALPHANUM); - - if (option_value.length == 0) - return TRUE; /* internal parser error. */ - - option_value.str= (char *) *text; - *text+= option_value.length; - - if (!(option_value_str= Named_value::alloc_str(&option_value))) - return TRUE; /* out of memory during parsing. */ - } - else - { - /* Option value is a string. */ - - if (parse_option_value(*text, &len, &option_value_str)) - return TRUE; /* Syntax error: invalid string specification. */ - - *text+= len; - } - } - - if (!option_value_str) - { - LEX_STRING empty_str= { C_STRING_WITH_LEN("") }; - - if (!(option_value_str= Named_value::alloc_str(&empty_str))) - return TRUE; /* out of memory during parsing. */ - } - - if (!(option_name_str= Named_value::alloc_str(&option_name))) - { - Named_value::free_str(&option_name_str); - return TRUE; /* out of memory during parsing. */ - } - - { - Named_value option(option_name_str, option_value_str); - - if (add_option(&instance_name, &option)) - { - option.free(); - return TRUE; /* out of memory during parsing. */ - } - } - - skip_spaces(text); - - if (!**text) - return FALSE; /* OK: end of options. */ - - if (**text != ',') - return TRUE; /* Syntax error: comma expected. */ - - ++(*text); /* Skip a comma. */ - } -} - - -int Set_option::process_option(Instance *instance, Named_value *option) -{ - /* Check that the option is valid. */ - - if (instance->is_mysqld_compatible() && - Instance_options::is_option_im_specific(option->get_name())) - { - log_error("IM-option (%s) can not be used " - "in the configuration of mysqld-compatible instance (%s).", - (const char *) option->get_name(), - (const char *) instance->get_name()->str); - return ER_INCOMPATIBLE_OPTION; - } - - /* Update the configuration file. */ - - int err_code= correct_file(instance, option, FALSE); - - if (err_code) - return err_code; - - /* Update the internal cache. */ - - if (instance->options.set_option(option)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation of Unset_option. -**************************************************************************/ - -/** - This operation parses UNSET options. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing options. - - RETURN - FALSE On success. - TRUE On syntax error. -*/ - -bool Unset_option::parse_args(const char **text) -{ - size_t len; - - /* Check if we have something (and trim leading spaces). */ - - get_word(text, &len, NONSPACE); - - if (len == 0) - return TRUE; /* Syntax error: no option. */ - - /* Main parsing loop. */ - - while (TRUE) - { - LEX_STRING instance_name; - LEX_STRING option_name; - char *option_name_str; - char *option_value_str; - - /* Looking for instance name. */ - - get_word(text, &instance_name.length, ALPHANUM); - - if (instance_name.length == 0) - return TRUE; /* Syntax error: instance name expected. */ - - instance_name.str= (char *) *text; - *text+= instance_name.length; - - skip_spaces(text); - - /* Check the the delimiter is a dot. */ - - if (**text != '.') - return TRUE; /* Syntax error: dot expected. */ - - ++(*text); /* Skip a dot. */ - - /* Looking for option name. */ - - get_word(text, &option_name.length, OPTION_NAME); - - if (option_name.length == 0) - return TRUE; /* Syntax error: option name expected. */ - - option_name.str= (char *) *text; - *text+= option_name.length; - - if (!(option_name_str= Named_value::alloc_str(&option_name))) - return TRUE; /* out of memory during parsing. */ - - { - LEX_STRING empty_str= { C_STRING_WITH_LEN("") }; - - if (!(option_value_str= Named_value::alloc_str(&empty_str))) - { - Named_value::free_str(&option_name_str); - return TRUE; - } - } - - { - Named_value option(option_name_str, option_value_str); - - if (add_option(&instance_name, &option)) - { - option.free(); - return TRUE; /* out of memory during parsing. */ - } - } - - skip_spaces(text); - - if (!**text) - return FALSE; /* OK: end of options. */ - - if (**text != ',') - return TRUE; /* Syntax error: comma expected. */ - - ++(*text); /* Skip a comma. */ - } -} - - -/** - Implementation of UNSET statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance name specified is not valid - ER_INSTANCE_IS_ACTIVE The specified instance is active - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Unset_option::process_option(Instance *instance, Named_value *option) -{ - /* Update the configuration file. */ - - int err_code= correct_file(instance, option, TRUE); - - if (err_code) - return err_code; - - /* Update the internal cache. */ - - instance->options.unset_option(option->get_name()); - - return 0; -} - - -/************************************************************************** - Implementation of Syntax_error. -**************************************************************************/ - -int Syntax_error::execute(st_net * /* net */, ulong /* connection_id */) -{ - return ER_SYNTAX_ERROR; -} diff --git a/server-tools/instance-manager/commands.h b/server-tools/instance-manager/commands.h deleted file mode 100644 index 5c2b2f9bbb7..00000000000 --- a/server-tools/instance-manager/commands.h +++ /dev/null @@ -1,393 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H -/* Copyright (C) 2004 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 */ - -#include -#include -#include -#include - -#include "command.h" -#include "instance.h" -#include "parse.h" - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - - -/** - Print all instances of this instance manager. - Grammar: SHOW INSTANCES -*/ - -class Show_instances: public Command -{ -public: - Show_instances() - { } - -public: - int execute(st_net *net, ulong connection_id); - -private: - int write_header(st_net *net); - int write_data(st_net *net); -}; - - -/** - Reread configuration file and refresh internal cache. - Grammar: FLUSH INSTANCES -*/ - -class Flush_instances: public Command -{ -public: - Flush_instances() - { } - -public: - int execute(st_net *net, ulong connection_id); -}; - - -/** - Base class for Instance-specific commands - (commands that operate on one instance). - - Instance_cmd extends Command class by: - - an attribute for storing instance name; - - code to initialize instance name in constructor; - - an accessor to get instance name. -*/ - -class Instance_cmd : public Command -{ -public: - Instance_cmd(const LEX_STRING *instance_name_arg); - -protected: - inline const LEX_STRING *get_instance_name() const - { - return instance_name.get_str(); - } - -private: - Instance_name instance_name; -}; - - -/** - Abstract class for Instance-specific commands. - - Abstract_instance_cmd extends Instance_cmd by providing a common - framework for writing command-implementations. Basically, the class - implements Command::execute() pure virtual function in the following - way: - - Lock Instance_map; - - Get an instance by name. Return an error, if there is no such - instance; - - Lock the instance; - - Unlock Instance_map; - - Call execute_impl(), which should be implemented in derived class; - - Unlock the instance; - - Send response to the client and return error status. -*/ - -class Abstract_instance_cmd: public Instance_cmd -{ -public: - Abstract_instance_cmd(const LEX_STRING *instance_name_arg); - -public: - virtual int execute(st_net *net, ulong connection_id); - -protected: - /** - This operation is intended to contain command-specific implementation. - - MT-NOTE: this operation is called under acquired Instance's lock. - */ - virtual int execute_impl(st_net *net, Instance *instance) = 0; - - /** - This operation is invoked on successful return of execute_impl() and is - intended to send closing data. - - MT-NOTE: this operation is called under released Instance's lock. - */ - virtual int send_ok_response(st_net *net, ulong connection_id) = 0; -}; - - -/** - Print status of an instance. - Grammar: SHOW INSTANCE STATUS -*/ - -class Show_instance_status: public Abstract_instance_cmd -{ -public: - Show_instance_status(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); - -private: - int write_header(st_net *net); - int write_data(st_net *net, Instance *instance); -}; - - -/** - Print options of chosen instance. - Grammar: SHOW INSTANCE OPTIONS -*/ - -class Show_instance_options: public Abstract_instance_cmd -{ -public: - Show_instance_options(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); - -private: - int write_header(st_net *net); - int write_data(st_net *net, Instance *instance); -}; - - -/** - Start an instance. - Grammar: START INSTANCE -*/ - -class Start_instance: public Abstract_instance_cmd -{ -public: - Start_instance(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); -}; - - -/** - Stop an instance. - Grammar: STOP INSTANCE -*/ - -class Stop_instance: public Abstract_instance_cmd -{ -public: - Stop_instance(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); -}; - - -/** - Create an instance. - Grammar: CREATE INSTANCE [] -*/ - -class Create_instance: public Instance_cmd -{ -public: - Create_instance(const LEX_STRING *instance_name_arg); - -public: - bool init(const char **text); - -protected: - virtual int execute(st_net *net, ulong connection_id); - -private: - bool parse_args(const char **text); - -private: - Named_value_arr options; -}; - - -/** - Drop an instance. - Grammar: DROP INSTANCE - - Operation is permitted only if the instance is stopped. On successful - completion the instance section is removed from config file and the instance - is removed from the instance map. -*/ - -class Drop_instance: public Instance_cmd -{ -public: - Drop_instance(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute(st_net *net, ulong connection_id); -}; - - -/** - Print requested part of the log. - Grammar: - SHOW LOG {ERROR | SLOW | GENERAL} size[, offset_from_end] -*/ - -class Show_instance_log: public Abstract_instance_cmd -{ -public: - Show_instance_log(const LEX_STRING *instance_name_arg, - Log_type log_type_arg, uint size_arg, uint offset_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); - -private: - int check_params(Instance *instance); - int write_header(st_net *net); - int write_data(st_net *net, Instance *instance); - -private: - Log_type log_type; - uint size; - uint offset; -}; - - -/** - Shows the list of the log files, used by an instance. - Grammar: SHOW LOG FILES -*/ - -class Show_instance_log_files: public Abstract_instance_cmd -{ -public: - Show_instance_log_files(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); - -private: - int write_header(st_net *net); - int write_data(st_net *net, Instance *instance); -}; - - -/** - Abstract class for option-management commands. -*/ - -class Instance_options_list; - -class Abstract_option_cmd: public Command -{ -public: - ~Abstract_option_cmd(); - -public: - bool add_option(const LEX_STRING *instance_name, Named_value *option); - -public: - bool init(const char **text); - - virtual int execute(st_net *net, ulong connection_id); - -protected: - Abstract_option_cmd(); - - int correct_file(Instance *instance, Named_value *option, bool skip); - -protected: - virtual bool parse_args(const char **text) = 0; - virtual int process_option(Instance *instance, Named_value *option) = 0; - -private: - Instance_options_list * - get_instance_options_list(const LEX_STRING *instance_name); - - int execute_impl(st_net *net, ulong connection_id); - -private: - HASH instance_options_map; - bool initialized; -}; - - -/** - Set an option for the instance. - Grammar: SET instance_name.option[=option_value][, ...] -*/ - -class Set_option: public Abstract_option_cmd -{ -public: - Set_option() - { } - -protected: - virtual bool parse_args(const char **text); - virtual int process_option(Instance *instance, Named_value *option); -}; - - -/** - Remove option of the instance. - Grammar: UNSET instance_name.option[, ...] -*/ - -class Unset_option: public Abstract_option_cmd -{ -public: - Unset_option() - { } - -protected: - virtual bool parse_args(const char **text); - virtual int process_option(Instance *instance, Named_value *option); -}; - - -/** - Syntax error command. - - This command is issued if parser reported a syntax error. We need it to - distinguish between syntax error and internal parser error. E.g. parsing - failed because we hadn't had enought memory. In the latter case the parser - just returns NULL. -*/ - -class Syntax_error: public Command -{ -public: - Syntax_error() - { } - -public: - int execute(st_net *net, ulong connection_id); -}; - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H */ diff --git a/server-tools/instance-manager/exit_codes.h b/server-tools/instance-manager/exit_codes.h deleted file mode 100644 index 1609debd8f9..00000000000 --- a/server-tools/instance-manager/exit_codes.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H - -/* - Copyright (C) 2006 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 -*/ - -/* - This file contains a list of exit codes, which are used when Instance - Manager is working in user-management mode. -*/ - -const int ERR_OK = 0; - -const int ERR_OUT_OF_MEMORY = 1; -const int ERR_INVALID_USAGE = 2; -const int ERR_INTERNAL_ERROR = 3; -const int ERR_IO_ERROR = 4; -const int ERR_PASSWORD_FILE_CORRUPTED = 5; -const int ERR_PASSWORD_FILE_DOES_NOT_EXIST = 6; - -const int ERR_CAN_NOT_READ_USER_NAME = 10; -const int ERR_CAN_NOT_READ_PASSWORD = 11; -const int ERR_USER_ALREADY_EXISTS = 12; -const int ERR_USER_NOT_FOUND = 13; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H diff --git a/server-tools/instance-manager/guardian.cc b/server-tools/instance-manager/guardian.cc deleted file mode 100644 index b49b0ec0a00..00000000000 --- a/server-tools/instance-manager/guardian.cc +++ /dev/null @@ -1,496 +0,0 @@ -/* Copyright (C) 2004 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 */ - - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "guardian.h" -#include -#include -#include - -#include "instance.h" -#include "instance_map.h" -#include "log.h" -#include "mysql_manager_error.h" -#include "options.h" - - -/************************************************************************* - {{{ Constructor & destructor. -*************************************************************************/ - -/** - Guardian constructor. - - SYNOPSIS - Guardian() - thread_registry_arg - instance_map_arg - - DESCRIPTION - Nominal contructor intended for assigning references and initialize - trivial objects. Real initialization is made by init() method. -*/ - -Guardian::Guardian(Thread_registry *thread_registry_arg, - Instance_map *instance_map_arg) - :shutdown_requested(FALSE), - stopped(FALSE), - thread_registry(thread_registry_arg), - instance_map(instance_map_arg) -{ - pthread_mutex_init(&LOCK_guardian, 0); - pthread_cond_init(&COND_guardian, 0); -} - - -Guardian::~Guardian() -{ - /* - NOTE: it's necessary to synchronize here, because Guiardian thread can be - still alive an hold the mutex (because it is detached and we have no - control over it). - */ - - lock(); - unlock(); - - pthread_mutex_destroy(&LOCK_guardian); - pthread_cond_destroy(&COND_guardian); -} - -/************************************************************************* - }}} -*************************************************************************/ - - -/** - Send request to stop Guardian. - - SYNOPSIS - request_shutdown() -*/ - -void Guardian::request_shutdown() -{ - stop_instances(); - - lock(); - shutdown_requested= TRUE; - unlock(); - - ping(); -} - - -/** - Process an instance. - - SYNOPSIS - process_instance() - instance a pointer to the instance for processing - - MT-NOTE: - - the given instance must be locked before calling this operation; - - Guardian must be locked before calling this operation. -*/ - -void Guardian::process_instance(Instance *instance) -{ - int restart_retry= 100; - time_t current_time= time(NULL); - - if (instance->get_state() == Instance::STOPPING) - { - /* This brach is executed during shutdown. */ - - /* This returns TRUE if and only if an instance was stopped for sure. */ - if (instance->is_crashed()) - { - log_info("Guardian: '%s' stopped.", - (const char *) instance->get_name()->str); - - instance->set_state(Instance::STOPPED); - } - else if ((uint) (current_time - instance->last_checked) >= - instance->options.get_shutdown_delay()) - { - log_info("Guardian: '%s' hasn't stopped within %d secs.", - (const char *) instance->get_name()->str, - (int) instance->options.get_shutdown_delay()); - - instance->kill_mysqld(SIGKILL); - - log_info("Guardian: pretend that '%s' is killed.", - (const char *) instance->get_name()->str); - - instance->set_state(Instance::STOPPED); - } - else - { - log_info("Guardian: waiting for '%s' to stop (%d secs left).", - (const char *) instance->get_name()->str, - (int) (instance->options.get_shutdown_delay() - - current_time + instance->last_checked)); - } - - return; - } - - if (instance->is_mysqld_running()) - { - /* The instance can be contacted on it's port */ - - /* If STARTING also check that pidfile has been created */ - if (instance->get_state() == Instance::STARTING && - instance->options.load_pid() == 0) - { - /* Pid file not created yet, don't go to STARTED state yet */ - } - else if (instance->get_state() != Instance::STARTED) - { - /* clear status fields */ - log_info("Guardian: '%s' is running, set state to STARTED.", - (const char *) instance->options.instance_name.str); - instance->reset_stat(); - instance->set_state(Instance::STARTED); - } - } - else - { - switch (instance->get_state()) { - case Instance::NOT_STARTED: - log_info("Guardian: starting '%s'...", - (const char *) instance->options.instance_name.str); - - /* NOTE: set state to STARTING _before_ start() is called. */ - instance->set_state(Instance::STARTING); - instance->last_checked= current_time; - - instance->start_mysqld(); - - return; - - case Instance::STARTED: /* fallthrough */ - case Instance::STARTING: /* let the instance start or crash */ - if (!instance->is_crashed()) - return; - - instance->crash_moment= current_time; - instance->last_checked= current_time; - instance->set_state(Instance::JUST_CRASHED); - /* fallthrough -- restart an instance immediately */ - - case Instance::JUST_CRASHED: - if (current_time - instance->crash_moment <= 2) - { - if (instance->is_crashed()) - { - instance->start_mysqld(); - log_info("Guardian: starting '%s'...", - (const char *) instance->options.instance_name.str); - } - } - else - instance->set_state(Instance::CRASHED); - - return; - - case Instance::CRASHED: /* just regular restarts */ - if ((ulong) (current_time - instance->last_checked) <= - (ulong) Options::Main::monitoring_interval) - return; - - if (instance->restart_counter < restart_retry) - { - if (instance->is_crashed()) - { - instance->start_mysqld(); - instance->last_checked= current_time; - - log_info("Guardian: restarting '%s'...", - (const char *) instance->options.instance_name.str); - } - } - else - { - log_info("Guardian: can not start '%s'. " - "Abandoning attempts to (re)start it", - (const char *) instance->options.instance_name.str); - - instance->set_state(Instance::CRASHED_AND_ABANDONED); - } - - return; - - case Instance::CRASHED_AND_ABANDONED: - return; /* do nothing */ - - default: - DBUG_ASSERT(0); - } - } -} - - -/** - Main function of Guardian thread. - - SYNOPSIS - run() - - DESCRIPTION - Check for all guarded instances and restart them if needed. -*/ - -void Guardian::run() -{ - struct timespec timeout; - - log_info("Guardian: started."); - - thread_registry->register_thread(&thread_info); - - /* Loop, until all instances were shut down at the end. */ - - while (true) - { - Instance_map::Iterator instances_it(instance_map); - Instance *instance; - bool all_instances_stopped= TRUE; - - instance_map->lock(); - - while ((instance= instances_it.next())) - { - instance->lock(); - - if (!instance->is_guarded() || - instance->get_state() == Instance::STOPPED) - { - instance->unlock(); - continue; - } - - process_instance(instance); - - if (instance->get_state() != Instance::STOPPED) - all_instances_stopped= FALSE; - - instance->unlock(); - } - - instance_map->unlock(); - - lock(); - - if (shutdown_requested && all_instances_stopped) - { - log_info("Guardian: all guarded mysqlds stopped."); - - stopped= TRUE; - unlock(); - break; - } - - set_timespec(timeout, Options::Main::monitoring_interval); - - thread_registry->cond_timedwait(&thread_info, &COND_guardian, - &LOCK_guardian, &timeout); - unlock(); - } - - log_info("Guardian: stopped."); - - /* Now, when the Guardian is stopped we can stop the IM. */ - - thread_registry->unregister_thread(&thread_info); - thread_registry->request_shutdown(); - - log_info("Guardian: finished."); -} - - -/** - Return the value of stopped flag. -*/ - -bool Guardian::is_stopped() -{ - int var; - - lock(); - var= stopped; - unlock(); - - return var; -} - - -/** - Wake up Guardian thread. - - MT-NOTE: though usually the mutex associated with condition variable should - be acquired before signalling the variable, here this is not needed. - Signalling under locked mutex is used to avoid lost signals. In the current - logic however locking mutex does not guarantee that the signal will not be - lost. -*/ - -void Guardian::ping() -{ - pthread_cond_signal(&COND_guardian); -} - - -/** - Prepare list of instances. - - SYNOPSIS - init() - - MT-NOTE: Instance Map must be locked before calling the operation. -*/ - -void Guardian::init() -{ - Instance *instance; - Instance_map::Iterator iterator(instance_map); - - while ((instance= iterator.next())) - { - instance->lock(); - - instance->reset_stat(); - instance->set_state(Instance::NOT_STARTED); - - instance->unlock(); - } -} - - -/** - An internal method which is called at shutdown to unregister instances and - attempt to stop them if requested. - - SYNOPSIS - stop_instances() - - DESCRIPTION - Loops through the guarded_instances list and prepares them for shutdown. - For each instance we issue a stop command and change the state - accordingly. - - NOTE - Guardian object should be locked by the caller. - -*/ - -void Guardian::stop_instances() -{ - static const int NUM_STOP_ATTEMPTS = 100; - - Instance_map::Iterator instances_it(instance_map); - Instance *instance; - - instance_map->lock(); - - while ((instance= instances_it.next())) - { - instance->lock(); - - if (!instance->is_guarded() || - instance->get_state() == Instance::STOPPED) - { - instance->unlock(); - continue; - } - - /* - If instance is running or was running (and now probably hanging), - request stop. - */ - - if (instance->is_mysqld_running() || - instance->get_state() == Instance::STARTED) - { - instance->set_state(Instance::STOPPING); - instance->last_checked= time(NULL); - } - else - { - /* Otherwise mark it as STOPPED. */ - instance->set_state(Instance::STOPPED); - } - - /* Request mysqld to stop. */ - - bool instance_stopped= FALSE; - - for (int cur_attempt= 0; cur_attempt < NUM_STOP_ATTEMPTS; ++cur_attempt) - { - if (!instance->kill_mysqld(SIGTERM)) - { - instance_stopped= TRUE; - break; - } - - if (!instance->is_active()) - { - instance_stopped= TRUE; - break; - } - - /* Sleep for 0.3 sec and check again. */ - - my_sleep(300000); - } - - /* - Abort if we failed to stop mysqld instance. That should not happen, - but if it happened, we don't know what to do and prefer to have clear - failure with coredump. - */ - - DBUG_ASSERT(instance_stopped); - - instance->unlock(); - } - - instance_map->unlock(); -} - - -/** - Lock Guardian. -*/ - -void Guardian::lock() -{ - pthread_mutex_lock(&LOCK_guardian); -} - - -/** - Unlock Guardian. -*/ - -void Guardian::unlock() -{ - pthread_mutex_unlock(&LOCK_guardian); -} diff --git a/server-tools/instance-manager/guardian.h b/server-tools/instance-manager/guardian.h deleted file mode 100644 index d78058a6fc5..00000000000 --- a/server-tools/instance-manager/guardian.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H -/* Copyright (C) 2004 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 */ - - -#include -#include -#include - -#include "thread_registry.h" - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -class Instance; -class Instance_map; -class Thread_registry; - -/** - The guardian thread is responsible for monitoring and restarting of guarded - instances. -*/ - -class Guardian: public Thread -{ -public: - Guardian(Thread_registry *thread_registry_arg, - Instance_map *instance_map_arg); - ~Guardian(); - - void init(); - -public: - void request_shutdown(); - - bool is_stopped(); - - void lock(); - void unlock(); - - void ping(); - -protected: - virtual void run(); - -private: - void stop_instances(); - - void process_instance(Instance *instance); - -private: - /* - LOCK_guardian protectes the members in this section: - - shutdown_requested; - - stopped; - - Also, it is used for COND_guardian. - */ - pthread_mutex_t LOCK_guardian; - - /* - Guardian's main loop waits on this condition. So, it should be signalled - each time, when instance state has been changed and we want Guardian to - wake up. - - TODO: Change this to having data-scoped conditions, i.e. conditions, - which indicate that some data has been changed. - */ - pthread_cond_t COND_guardian; - - /* - This variable is set to TRUE, when Manager thread is shutting down. - The flag is used by Guardian thread to understand that it's time to - finish. - */ - bool shutdown_requested; - - /* - This flag is set to TRUE on shutdown by Guardian thread, when all guarded - mysqlds are stopped. - - The flag is used in the Manager thread to wait for Guardian to stop all - mysqlds. - */ - bool stopped; - - Thread_info thread_info; - Thread_registry *thread_registry; - Instance_map *instance_map; - -private: - Guardian(const Guardian &); - Guardian&operator =(const Guardian &); -}; - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H */ diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc deleted file mode 100644 index 1ad728d40eb..00000000000 --- a/server-tools/instance-manager/instance.cc +++ /dev/null @@ -1,944 +0,0 @@ -/* Copyright (C) 2004 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 */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include -#include - -#include -#ifndef __WIN__ -#include -#endif - -#include "manager.h" -#include "guardian.h" -#include "instance.h" -#include "log.h" -#include "mysql_manager_error.h" -#include "portability.h" -#include "priv.h" -#include "thread_registry.h" -#include "instance_map.h" - - -/************************************************************************* - {{{ Platform-specific functions. -*************************************************************************/ - -#ifndef __WIN__ -typedef pid_t My_process_info; -#else -typedef PROCESS_INFORMATION My_process_info; -#endif - -/* - Wait for an instance - - SYNOPSIS - wait_process() - pi Pointer to the process information structure - (platform-dependent). - - RETURN - 0 - Success - 1 - Error -*/ - -#ifndef __WIN__ -static int wait_process(My_process_info *pi) -{ - /* - Here we wait for the child created. This process differs for systems - running LinuxThreads and POSIX Threads compliant systems. This is because - according to POSIX we could wait() for a child in any thread of the - process. While LinuxThreads require that wait() is called by the thread, - which created the child. - On the other hand we could not expect mysqld to return the pid, we - got in from fork(), to wait4() fucntion when running on LinuxThreads. - This is because MySQL shutdown thread is not the one, which was created - by our fork() call. - So basically we have two options: whether the wait() call returns only in - the creator thread, but we cannot use waitpid() since we have no idea - which pid we should wait for (in fact it should be the pid of shutdown - thread, but we don't know this one). Or we could use waitpid(), but - couldn't use wait(), because it could return in any wait() in the program. - */ - - if (Manager::is_linux_threads()) - wait(NULL); /* LinuxThreads were detected */ - else - waitpid(*pi, NULL, 0); - - return 0; -} -#else -static int wait_process(My_process_info *pi) -{ - /* Wait until child process exits. */ - WaitForSingleObject(pi->hProcess, INFINITE); - - DWORD exitcode; - ::GetExitCodeProcess(pi->hProcess, &exitcode); - - /* Close process and thread handles. */ - CloseHandle(pi->hProcess); - CloseHandle(pi->hThread); - - /* - GetExitCodeProces returns zero on failure. We should revert this value - to report an error. - */ - return (!exitcode); -} -#endif - -/* - Launch an instance - - SYNOPSIS - start_process() - instance_options Pointer to the options of the instance to be - launched. - pi Pointer to the process information structure - (platform-dependent). - - RETURN - FALSE - Success - TRUE - Cannot create an instance -*/ - -#ifndef __WIN__ -static bool start_process(Instance_options *instance_options, - My_process_info *pi) -{ -#ifndef __QNX__ - *pi= fork(); -#else - /* - On QNX one cannot use fork() in multithreaded environment and we - should use spawn() or one of it's siblings instead. - Here we use spawnv(), which is a combination of fork() and execv() - in one call. It returns the pid of newly created process (>0) or -1 - */ - *pi= spawnv(P_NOWAIT, instance_options->mysqld_path, instance_options->argv); -#endif - - switch (*pi) { - case 0: /* never happens on QNX */ - execv(instance_options->mysqld_path.str, instance_options->argv); - /* exec never returns */ - exit(1); - case -1: - log_error("Instance '%s': can not start mysqld: fork() failed.", - (const char *) instance_options->instance_name.str); - return TRUE; - } - - return FALSE; -} -#else -static bool start_process(Instance_options *instance_options, - My_process_info *pi) -{ - STARTUPINFO si; - - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb= sizeof(STARTUPINFO); - ZeroMemory(pi, sizeof(PROCESS_INFORMATION)); - - int cmdlen= 0; - for (int i= 0; instance_options->argv[i] != 0; i++) - cmdlen+= (uint) strlen(instance_options->argv[i]) + 3; - cmdlen++; /* make room for the null */ - - char *cmdline= new char[cmdlen]; - if (cmdline == NULL) - return TRUE; - - cmdline[0]= 0; - for (int i= 0; instance_options->argv[i] != 0; i++) - { - strcat(cmdline, "\""); - strcat(cmdline, instance_options->argv[i]); - strcat(cmdline, "\" "); - } - - /* Start the child process */ - BOOL result= - CreateProcess(NULL, /* Put it all in cmdline */ - cmdline, /* Command line */ - NULL, /* Process handle not inheritable */ - NULL, /* Thread handle not inheritable */ - FALSE, /* Set handle inheritance to FALSE */ - 0, /* No creation flags */ - NULL, /* Use parent's environment block */ - NULL, /* Use parent's starting directory */ - &si, /* Pointer to STARTUPINFO structure */ - pi); /* Pointer to PROCESS_INFORMATION structure */ - delete cmdline; - - return !result; -} -#endif - -#ifdef __WIN__ - -BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode) -{ - DWORD dwTID, dwCode, dwErr= 0; - HANDLE hProcessDup= INVALID_HANDLE_VALUE; - HANDLE hRT= NULL; - HINSTANCE hKernel= GetModuleHandle("Kernel32"); - BOOL bSuccess= FALSE; - - BOOL bDup= DuplicateHandle(GetCurrentProcess(), - hProcess, GetCurrentProcess(), &hProcessDup, - PROCESS_ALL_ACCESS, FALSE, 0); - - // Detect the special case where the process is - // already dead... - if (GetExitCodeProcess((bDup) ? hProcessDup : hProcess, &dwCode) && - (dwCode == STILL_ACTIVE)) - { - FARPROC pfnExitProc; - - pfnExitProc= GetProcAddress(hKernel, "ExitProcess"); - - hRT= CreateRemoteThread((bDup) ? hProcessDup : hProcess, NULL, 0, - (LPTHREAD_START_ROUTINE)pfnExitProc, - (PVOID)uExitCode, 0, &dwTID); - - if (hRT == NULL) - dwErr= GetLastError(); - } - else - dwErr= ERROR_PROCESS_ABORTED; - - if (hRT) - { - // Must wait process to terminate to - // guarantee that it has exited... - WaitForSingleObject((bDup) ? hProcessDup : hProcess, INFINITE); - - CloseHandle(hRT); - bSuccess= TRUE; - } - - if (bDup) - CloseHandle(hProcessDup); - - if (!bSuccess) - SetLastError(dwErr); - - return bSuccess; -} - -int kill(pid_t pid, int signum) -{ - HANDLE processhandle= ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); - if (signum == SIGTERM) - ::SafeTerminateProcess(processhandle, 0); - else - ::TerminateProcess(processhandle, -1); - return 0; -} -#endif - -/************************************************************************* - }}} -*************************************************************************/ - - -/************************************************************************* - {{{ Static constants. -*************************************************************************/ - -const LEX_STRING -Instance::DFLT_INSTANCE_NAME= { C_STRING_WITH_LEN("mysqld") }; - -/************************************************************************* - }}} -*************************************************************************/ - - -/************************************************************************* - {{{ Instance Monitor thread. -*************************************************************************/ - -/** - Proxy thread is a simple way to avoid all pitfalls of the threads - implementation in the OS (e.g. LinuxThreads). With such a thread we - don't have to process SIGCHLD, which is a tricky business if we want - to do it in a portable way. - - Instance Monitor Thread forks a child process, execs mysqld and waits for - the child to die. - - Instance Monitor assumes that the monitoring instance will not be dropped. - This is guaranteed by having flag monitoring_thread_active and - Instance::is_active() operation. -*/ - -class Instance_monitor: public Thread -{ -public: - Instance_monitor(Instance *instance_arg) :instance(instance_arg) {} -protected: - virtual void run(); - void start_and_monitor_instance(); -private: - Instance *instance; -}; - - -void Instance_monitor::run() -{ - start_and_monitor_instance(); - delete this; -} - - -void Instance_monitor::start_and_monitor_instance() -{ - Thread_registry *thread_registry= Manager::get_thread_registry(); - Guardian *guardian= Manager::get_guardian(); - - My_process_info mysqld_process_info; - Thread_info monitor_thread_info; - - log_info("Instance '%s': Monitor: started.", - (const char *) instance->get_name()->str); - - /* - For guarded instance register the thread in Thread_registry to wait for - the thread to stop on shutdown (nonguarded instances are not stopped on - shutdown, so the thread will no finish). - */ - - if (instance->is_guarded()) - { - thread_registry->register_thread(&monitor_thread_info, FALSE); - } - - /* Starting mysqld. */ - - log_info("Instance '%s': Monitor: starting mysqld...", - (const char *) instance->get_name()->str); - - if (start_process(&instance->options, &mysqld_process_info)) - { - instance->lock(); - instance->monitoring_thread_active= FALSE; - instance->unlock(); - - return; - } - - /* Waiting for mysqld to die. */ - - log_info("Instance '%s': Monitor: waiting for mysqld to stop...", - (const char *) instance->get_name()->str); - - wait_process(&mysqld_process_info); /* Don't check for return value. */ - - log_info("Instance '%s': Monitor: mysqld stopped.", - (const char *) instance->get_name()->str); - - /* Update instance status. */ - - instance->lock(); - - if (instance->is_guarded()) - thread_registry->unregister_thread(&monitor_thread_info); - - instance->crashed= TRUE; - instance->monitoring_thread_active= FALSE; - - log_info("Instance '%s': Monitor: finished.", - (const char *) instance->get_name()->str); - - instance->unlock(); - - /* Wake up guardian. */ - - guardian->ping(); -} - -/************************************************************************** - }}} -**************************************************************************/ - - -/************************************************************************** - {{{ Static operations. -**************************************************************************/ - -/** - The operation is intended to check whether string is a well-formed - instance name or not. - - SYNOPSIS - is_name_valid() - name string to check - - RETURN - TRUE string is a valid instance name - FALSE string is not a valid instance name - - TODO: Move to Instance_name class: Instance_name::is_valid(). -*/ - -bool Instance::is_name_valid(const LEX_STRING *name) -{ - const char *name_suffix= name->str + DFLT_INSTANCE_NAME.length; - - if (strncmp(name->str, Instance::DFLT_INSTANCE_NAME.str, - Instance::DFLT_INSTANCE_NAME.length) != 0) - return FALSE; - - return *name_suffix == 0 || my_isdigit(default_charset_info, *name_suffix); -} - - -/** - The operation is intended to check if the given instance name is - mysqld-compatible or not. - - SYNOPSIS - is_mysqld_compatible_name() - name name to check - - RETURN - TRUE name is mysqld-compatible - FALSE otherwise - - TODO: Move to Instance_name class: Instance_name::is_mysqld_compatible(). -*/ - -bool Instance::is_mysqld_compatible_name(const LEX_STRING *name) -{ - return strcmp(name->str, DFLT_INSTANCE_NAME.str) == 0; -} - - -/** - Return client state name. Must not be used outside the class. - Use Instance::get_state_name() instead. -*/ - -const char * Instance::get_instance_state_name(enum_instance_state state) -{ - switch (state) { - case STOPPED: - return "offline"; - - case NOT_STARTED: - return "not started"; - - case STARTING: - return "starting"; - - case STARTED: - return "online"; - - case JUST_CRASHED: - return "failed"; - - case CRASHED: - return "crashed"; - - case CRASHED_AND_ABANDONED: - return "abandoned"; - - case STOPPING: - return "stopping"; - } - - return NULL; /* just to ignore compiler warning. */ -} - -/************************************************************************** - }}} -**************************************************************************/ - - -/************************************************************************** - {{{ Initialization & deinitialization. -**************************************************************************/ - -Instance::Instance() - :monitoring_thread_active(FALSE), - crashed(FALSE), - configured(FALSE), - /* mysqld_compatible is initialized in init() */ - state(NOT_STARTED), - restart_counter(0), - crash_moment(0), - last_checked(0) -{ - pthread_mutex_init(&LOCK_instance, 0); -} - - -Instance::~Instance() -{ - log_info("Instance '%s': destroying...", (const char *) get_name()->str); - - pthread_mutex_destroy(&LOCK_instance); -} - - -/** - Initialize instance options. - - SYNOPSIS - init() - name_arg name of the instance - - RETURN: - FALSE - ok - TRUE - error -*/ - -bool Instance::init(const LEX_STRING *name_arg) -{ - mysqld_compatible= is_mysqld_compatible_name(name_arg); - - return options.init(name_arg); -} - - -/** - @brief Complete instance options initialization. - - @return Error status. - @retval FALSE ok - @retval TRUE error -*/ - -bool Instance::complete_initialization() -{ - configured= ! options.complete_initialization(); - return !configured; -} - -/************************************************************************** - }}} -**************************************************************************/ - - -/************************************************************************** - {{{ Instance: public interface implementation. -**************************************************************************/ - -/** - Determine if there is some activity with the instance. - - SYNOPSIS - is_active() - - DESCRIPTION - An instance is active if one of the following conditions is true: - - Instance-monitoring thread is running; - - Instance is guarded and its state is other than STOPPED; - - Corresponding mysqld-server accepts connections. - - MT-NOTE: instance must be locked before calling the operation. - - RETURN - TRUE - instance is active - FALSE - otherwise. -*/ - -bool Instance::is_active() -{ - if (monitoring_thread_active) - return TRUE; - - if (is_guarded() && get_state() != STOPPED) - return TRUE; - - return is_mysqld_running(); -} - - -/** - Determine if mysqld is accepting connections. - - SYNOPSIS - is_mysqld_running() - - DESCRIPTION - Try to connect to mysqld with fake login/password to check whether it is - accepting connections or not. - - MT-NOTE: instance must be locked before calling the operation. - - RETURN - TRUE - mysqld is alive and accept connections - FALSE - otherwise. -*/ - -bool Instance::is_mysqld_running() -{ - MYSQL mysql; - uint port= options.get_mysqld_port(); /* 0 if not specified. */ - const char *socket= NULL; - static const char *password= "check_connection"; - static const char *username= "MySQL_Instance_Manager"; - static const char *access_denied_message= "Access denied for user"; - bool return_val; - - if (options.mysqld_socket) - socket= options.mysqld_socket; - - /* no port was specified => instance falled back to default value */ - if (!port && !options.mysqld_socket) - port= SERVER_DEFAULT_PORT; - - mysql_init(&mysql); - /* try to connect to a server with a fake username/password pair */ - if (mysql_real_connect(&mysql, LOCAL_HOST, username, - password, - NullS, port, - socket, 0)) - { - /* - We have successfully connected to the server using fake - username/password. Write a warning to the logfile. - */ - log_error("Instance '%s': was able to log into mysqld.", - (const char *) get_name()->str); - return_val= TRUE; /* server is alive */ - } - else - return_val= test(!strncmp(access_denied_message, mysql_error(&mysql), - sizeof(access_denied_message) - 1)); - - mysql_close(&mysql); - - return return_val; -} - - -/** - @brief Start mysqld. - - Reset flags and start Instance Monitor thread, which will start mysqld. - - @note Instance must be locked before calling the operation. - - @return Error status code - @retval FALSE Ok - @retval TRUE Could not start instance -*/ - -bool Instance::start_mysqld() -{ - Instance_monitor *instance_monitor; - - if (!configured) - return TRUE; - - /* - Prepare instance to start Instance Monitor thread. - - NOTE: It's important to set these actions here in order to avoid - race conditions -- these actions must be done under acquired lock on - Instance. - */ - - crashed= FALSE; - monitoring_thread_active= TRUE; - - remove_pid(); - - /* Create and start the Instance Monitor thread. */ - - instance_monitor= new Instance_monitor(this); - - if (instance_monitor == NULL || instance_monitor->start(Thread::DETACHED)) - { - delete instance_monitor; - monitoring_thread_active= FALSE; - - log_error("Instance '%s': can not create instance monitor thread.", - (const char *) get_name()->str); - - return TRUE; - } - - ++restart_counter; - - /* The Instance Monitor thread will delete itself when it's finished. */ - - return FALSE; -} - - -/** - Stop mysqld. - - SYNOPSIS - stop_mysqld() - - DESCRIPTION - Try to stop mysqld gracefully. Otherwise kill it with SIGKILL. - - MT-NOTE: instance must be locked before calling the operation. - - RETURN - FALSE - ok - TRUE - could not stop the instance -*/ - -bool Instance::stop_mysqld() -{ - log_info("Instance '%s': stopping mysqld...", - (const char *) get_name()->str); - - kill_mysqld(SIGTERM); - - if (!wait_for_stop()) - { - log_info("Instance '%s': mysqld stopped gracefully.", - (const char *) get_name()->str); - return FALSE; - } - - log_info("Instance '%s': mysqld failed to stop gracefully within %d seconds.", - (const char *) get_name()->str, - (int) options.get_shutdown_delay()); - - log_info("Instance'%s': killing mysqld...", - (const char *) get_name()->str); - - kill_mysqld(SIGKILL); - - if (!wait_for_stop()) - { - log_info("Instance '%s': mysqld has been killed.", - (const char *) get_name()->str); - return FALSE; - } - - log_info("Instance '%s': can not kill mysqld within %d seconds.", - (const char *) get_name()->str, - (int) options.get_shutdown_delay()); - - return TRUE; -} - - -/** - Send signal to mysqld. - - SYNOPSIS - kill_mysqld() - - DESCRIPTION - Load pid from the pid file and send the given signal to that process. - If the signal is SIGKILL, remove the pid file after sending the signal. - - MT-NOTE: instance must be locked before calling the operation. - - TODO - This too low-level and OS-specific operation for public interface. - Also, it has some implicit behaviour for SIGKILL signal. Probably, we - should have the following public operations instead: - - start_mysqld() -- as is; - - stop_mysqld -- request mysqld to shutdown gracefully (send SIGTERM); - don't wait for complete shutdown; - - wait_for_stop() (or join_mysqld()) -- wait for mysqld to stop within - time interval; - - kill_mysqld() -- request to terminate mysqld; don't wait for - completion. - These operations should also be used in Guardian to manage instances. -*/ - -bool Instance::kill_mysqld(int signum) -{ - pid_t mysqld_pid= options.load_pid(); - - if (mysqld_pid == 0) - { - log_info("Instance '%s': no pid file to send a signal (%d).", - (const char *) get_name()->str, - (int) signum); - return TRUE; - } - - log_info("Instance '%s': sending %d to %d...", - (const char *) get_name()->str, - (int) signum, - (int) mysqld_pid); - - if (kill(mysqld_pid, signum)) - { - log_info("Instance '%s': kill() failed.", - (const char *) get_name()->str); - return TRUE; - } - - /* Kill suceeded */ - if (signum == SIGKILL) /* really killed instance with SIGKILL */ - { - log_error("Instance '%s': killed.", - (const char *) options.instance_name.str); - - /* After sucessful hard kill the pidfile need to be removed */ - options.unlink_pidfile(); - } - - return FALSE; -} - - -/** - Lock instance. -*/ - -void Instance::lock() -{ - pthread_mutex_lock(&LOCK_instance); -} - - -/** - Unlock instance. -*/ - -void Instance::unlock() -{ - pthread_mutex_unlock(&LOCK_instance); -} - - -/** - Return instance state name. - - SYNOPSIS - get_state_name() - - DESCRIPTION - The operation returns user-friendly state name. The operation can be - used both for guarded and non-guarded instances. - - MT-NOTE: instance must be locked before calling the operation. - - TODO: Replace with the static get_state_name(state_code) function. -*/ - -const char *Instance::get_state_name() -{ - if (!is_configured()) - return "misconfigured"; - - if (is_guarded()) - { - /* The instance is managed by Guardian: we can report precise state. */ - - return get_instance_state_name(get_state()); - } - - /* The instance is not managed by Guardian: we can report status only. */ - - return is_active() ? "online" : "offline"; -} - - -/** - Reset statistics. - - SYNOPSIS - reset_stat() - - DESCRIPTION - The operation resets statistics used for guarding the instance. - - MT-NOTE: instance must be locked before calling the operation. - - TODO: Make private. -*/ - -void Instance::reset_stat() -{ - restart_counter= 0; - crash_moment= 0; - last_checked= 0; -} - -/************************************************************************** - }}} -**************************************************************************/ - - -/************************************************************************** - {{{ Instance: implementation of private operations. -**************************************************************************/ - -/** - Remove pid file. -*/ - -void Instance::remove_pid() -{ - int mysqld_pid= options.load_pid(); - - if (mysqld_pid == 0) - return; - - if (options.unlink_pidfile()) - { - log_error("Instance '%s': can not unlink pid file.", - (const char *) options.instance_name.str); - } -} - - -/** - Wait for mysqld to stop within shutdown interval. -*/ - -bool Instance::wait_for_stop() -{ - int start_time= (int) time(NULL); - int finish_time= start_time + options.get_shutdown_delay(); - - log_info("Instance '%s': waiting for mysqld to stop " - "(timeout: %d seconds)...", - (const char *) get_name()->str, - (int) options.get_shutdown_delay()); - - while (true) - { - if (options.load_pid() == 0 && !is_mysqld_running()) - return FALSE; - - if (time(NULL) >= finish_time) - return TRUE; - - /* Sleep for 0.3 sec and check again. */ - - my_sleep(300000); - } -} - -/************************************************************************** - }}} -**************************************************************************/ diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h deleted file mode 100644 index aa9c923cba1..00000000000 --- a/server-tools/instance-manager/instance.h +++ /dev/null @@ -1,273 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H -/* Copyright (C) 2004 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 */ - -#include -#include - -#include "instance_options.h" -#include "priv.h" - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -class Instance_map; -class Thread_registry; - - -/** - Instance_name -- the class represents instance name -- a string of length - less than MAX_INSTANCE_NAME_SIZE. - - Generally, this is just a string with self-memory-management and should be - eliminated in the future. -*/ - -class Instance_name -{ -public: - Instance_name(const LEX_STRING *name); - -public: - inline const LEX_STRING *get_str() const - { - return &str; - } - - inline const char *get_c_str() const - { - return str.str; - } - - inline uint get_length() const - { - return str.length; - } - -private: - LEX_STRING str; - char str_buffer[MAX_INSTANCE_NAME_SIZE]; -}; - - -class Instance -{ -public: - /* States of an instance. */ - enum enum_instance_state - { - STOPPED, - NOT_STARTED, - STARTING, - STARTED, - JUST_CRASHED, - CRASHED, - CRASHED_AND_ABANDONED, - STOPPING - }; - -public: - /** - The constant defines name of the default mysqld-instance ("mysqld"). - */ - static const LEX_STRING DFLT_INSTANCE_NAME; - -public: - static bool is_name_valid(const LEX_STRING *name); - static bool is_mysqld_compatible_name(const LEX_STRING *name); - -public: - Instance(); - ~Instance(); - - bool init(const LEX_STRING *name_arg); - bool complete_initialization(); - -public: - bool is_active(); - - bool is_mysqld_running(); - - bool start_mysqld(); - bool stop_mysqld(); - bool kill_mysqld(int signo); - - void lock(); - void unlock(); - - const char *get_state_name(); - - void reset_stat(); - -public: - /** - The operation is intended to check if the instance is mysqld-compatible - or not. - */ - inline bool is_mysqld_compatible() const; - - /** - The operation is intended to check if the instance is configured properly - or not. Misconfigured instances are not managed. - */ - inline bool is_configured() const; - - /** - The operation returns TRUE if the instance is guarded and FALSE otherwise. - */ - inline bool is_guarded() const; - - /** - The operation returns name of the instance. - */ - inline const LEX_STRING *get_name() const; - - /** - The operation returns the current state of the instance. - - NOTE: At the moment should be used only for guarded instances. - */ - inline enum_instance_state get_state() const; - - /** - The operation changes the state of the instance. - - NOTE: At the moment should be used only for guarded instances. - TODO: Make private. - */ - inline void set_state(enum_instance_state new_state); - - /** - The operation returns crashed flag. - */ - inline bool is_crashed(); - -public: - /** - This attributes contains instance options. - - TODO: Make private. - */ - Instance_options options; - -private: - /** - monitoring_thread_active is TRUE if there is a thread that monitors the - corresponding mysqld-process. - */ - bool monitoring_thread_active; - - /** - crashed is TRUE when corresponding mysqld-process has been died after - start. - */ - bool crashed; - - /** - configured is TRUE when the instance is configured and FALSE otherwise. - Misconfigured instances are not managed. - */ - bool configured; - - /* - mysqld_compatible specifies whether the instance is mysqld-compatible - or not. Mysqld-compatible instances can contain only mysqld-specific - options. At the moment an instance is mysqld-compatible if its name is - "mysqld". - - The idea is that [mysqld] section should contain only mysqld-specific - options (no Instance Manager-specific options) to be readable by mysqld - program. - */ - bool mysqld_compatible; - - /* - Mutex protecting the instance. - */ - pthread_mutex_t LOCK_instance; - -private: - /* Guarded-instance attributes. */ - - /* state of an instance (i.e. STARTED, CRASHED, etc.) */ - enum_instance_state state; - -public: - /* the amount of attemts to restart instance (cleaned up at success) */ - int restart_counter; - - /* triggered at a crash */ - time_t crash_moment; - - /* General time field. Used to provide timeouts (at shutdown and restart) */ - time_t last_checked; - -private: - static const char *get_instance_state_name(enum_instance_state state); - -private: - void remove_pid(); - - bool wait_for_stop(); - -private: - friend class Instance_monitor; -}; - - -inline bool Instance::is_mysqld_compatible() const -{ - return mysqld_compatible; -} - - -inline bool Instance::is_configured() const -{ - return configured; -} - - -inline bool Instance::is_guarded() const -{ - return !options.nonguarded; -} - - -inline const LEX_STRING *Instance::get_name() const -{ - return &options.instance_name; -} - - -inline Instance::enum_instance_state Instance::get_state() const -{ - return state; -} - - -inline void Instance::set_state(enum_instance_state new_state) -{ - state= new_state; -} - - -inline bool Instance::is_crashed() -{ - return crashed; -} - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */ diff --git a/server-tools/instance-manager/instance_map.cc b/server-tools/instance-manager/instance_map.cc deleted file mode 100644 index b137370b50a..00000000000 --- a/server-tools/instance-manager/instance_map.cc +++ /dev/null @@ -1,649 +0,0 @@ -/* Copyright (C) 2004 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 */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "instance_map.h" - -#include -#include -#include - -#include "buffer.h" -#include "instance.h" -#include "log.h" -#include "mysqld_error.h" -#include "mysql_manager_error.h" -#include "options.h" -#include "priv.h" - -C_MODE_START - -/** - HASH-routines: get key of instance for storing in hash. -*/ - -static uchar* get_instance_key(const uchar* u, size_t* len, - my_bool __attribute__((unused)) t) -{ - const Instance *instance= (const Instance *) u; - *len= instance->options.instance_name.length; - return (uchar *) instance->options.instance_name.str; -} - -/** - HASH-routines: cleanup handler. -*/ - -static void delete_instance(void *u) -{ - Instance *instance= (Instance *) u; - delete instance; -} - -/** - The option handler to pass to the process_default_option_files function. - - SYNOPSIS - process_option() - ctx Handler context. Here it is an instance_map structure. - group_name The name of the group the option belongs to. - option The very option to be processed. It is already - prepared to be used in argv (has -- prefix) - - DESCRIPTION - - This handler checks whether a group is an instance group and adds - an option to the appropriate instance class. If this is the first - occurence of an instance name, we'll also create the instance - with such name and add it to the instance map. - - RETURN - 0 - ok - 1 - error occured -*/ - -static int process_option(void *ctx, const char *group, const char *option) -{ - Instance_map *map= (Instance_map*) ctx; - LEX_STRING group_str; - - group_str.str= (char *) group; - group_str.length= strlen(group); - - return map->process_one_option(&group_str, option); -} - -C_MODE_END - - -/** - Parse option string. - - SYNOPSIS - parse_option() - option_str [IN] option string (e.g. "--name=value") - option_name_buf [OUT] parsed name of the option. - Must be of (MAX_OPTION_LEN + 1) size. - option_value_buf [OUT] parsed value of the option. - Must be of (MAX_OPTION_LEN + 1) size. - - DESCRIPTION - This is an auxiliary function and should not be used externally. It is - intended to parse whole option string into option name and option value. -*/ - -static void parse_option(const char *option_str, - char *option_name_buf, - char *option_value_buf) -{ - const char *eq_pos; - const char *ptr= option_str; - - while (*ptr == '-') - ++ptr; - - strmake(option_name_buf, ptr, MAX_OPTION_LEN + 1); - - eq_pos= strchr(ptr, '='); - if (eq_pos) - { - option_name_buf[eq_pos - ptr]= 0; - strmake(option_value_buf, eq_pos + 1, MAX_OPTION_LEN + 1); - } - else - { - option_value_buf[0]= 0; - } -} - - -/** - Process one option from the configuration file. - - SYNOPSIS - Instance_map::process_one_option() - group group name - option option string (e.g. "--name=value") - - DESCRIPTION - This is an auxiliary function and should not be used externally. - It is used only by flush_instances(), which pass it to - process_option(). The caller ensures proper locking - of the instance map object. -*/ - /* - Process a given option and assign it to appropricate instance. This is - required for the option handler, passed to my_search_option_files(). - */ - -int Instance_map::process_one_option(const LEX_STRING *group, - const char *option) -{ - Instance *instance= NULL; - - if (!Instance::is_name_valid(group)) - { - /* - Current section name is not a valid instance name. - We should skip it w/o error. - */ - return 0; - } - - if (!(instance= (Instance *) hash_search(&hash, (uchar *) group->str, - group->length))) - { - if (!(instance= new Instance())) - return 1; - - if (instance->init(group) || add_instance(instance)) - { - delete instance; - return 1; - } - - if (instance->is_mysqld_compatible()) - log_info("Warning: instance name '%s' is mysqld-compatible.", - (const char *) group->str); - - log_info("mysqld instance '%s' has been added successfully.", - (const char *) group->str); - } - - if (option) - { - char option_name[MAX_OPTION_LEN + 1]; - char option_value[MAX_OPTION_LEN + 1]; - - parse_option(option, option_name, option_value); - - if (instance->is_mysqld_compatible() && - Instance_options::is_option_im_specific(option_name)) - { - log_info("Warning: configuration of mysqld-compatible instance '%s' " - "contains IM-specific option '%s'. " - "This breaks backward compatibility for the configuration file.", - (const char *) group->str, - (const char *) option_name); - } - - Named_value option(option_name, option_value); - - if (instance->options.set_option(&option)) - return 1; /* the instance'll be deleted when we destroy the map */ - } - - return 0; -} - - -/** - Instance_map constructor. -*/ - -Instance_map::Instance_map() -{ - pthread_mutex_init(&LOCK_instance_map, 0); -} - - -/** - Initialize Instance_map internals. -*/ - -bool Instance_map::init() -{ - return hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0, - get_instance_key, delete_instance, 0); -} - - -/** - Reset Instance_map data. -*/ - -bool Instance_map::reset() -{ - hash_free(&hash); - return init(); -} - - -/** - Instance_map destructor. -*/ - -Instance_map::~Instance_map() -{ - lock(); - - /* - NOTE: it's necessary to synchronize on each instance before removal, - because Instance-monitoring thread can be still alive an hold the mutex - (because it is detached and we have no control over it). - */ - - while (true) - { - Iterator it(this); - Instance *instance= it.next(); - - if (!instance) - break; - - instance->lock(); - instance->unlock(); - - remove_instance(instance); - } - - hash_free(&hash); - unlock(); - - pthread_mutex_destroy(&LOCK_instance_map); -} - - -/** - Lock Instance_map. -*/ - -void Instance_map::lock() -{ - pthread_mutex_lock(&LOCK_instance_map); -} - - -/** - Unlock Instance_map. -*/ - -void Instance_map::unlock() -{ - pthread_mutex_unlock(&LOCK_instance_map); -} - - -/** - Check if there is an active instance or not. -*/ - -bool Instance_map::is_there_active_instance() -{ - Instance *instance; - Iterator iterator(this); - - while ((instance= iterator.next())) - { - bool active_instance_found; - - instance->lock(); - active_instance_found= instance->is_active(); - instance->unlock(); - - if (active_instance_found) - return TRUE; - } - - return FALSE; -} - - -/** - Add an instance into the internal hash. - - MT-NOTE: Instance Map must be locked before calling the operation. -*/ - -int Instance_map::add_instance(Instance *instance) -{ - return my_hash_insert(&hash, (uchar *) instance); -} - - -/** - Remove instance from the internal hash. - - MT-NOTE: Instance Map must be locked before calling the operation. -*/ - -int Instance_map::remove_instance(Instance *instance) -{ - return hash_delete(&hash, (uchar *) instance); -} - - -/** - Create a new instance and register it in the internal hash. - - MT-NOTE: Instance Map must be locked before calling the operation. -*/ - -int Instance_map::create_instance(const LEX_STRING *instance_name, - const Named_value_arr *options) -{ - Instance *instance= new Instance(); - - if (!instance) - { - log_error("Can not allocate instance (name: '%s').", - (const char *) instance_name->str); - return ER_OUT_OF_RESOURCES; - } - - if (instance->init(instance_name)) - { - log_error("Can not initialize instance (name: '%s').", - (const char *) instance_name->str); - delete instance; - return ER_OUT_OF_RESOURCES; - } - - for (int i= 0; options && i < options->get_size(); ++i) - { - Named_value option= options->get_element(i); - - if (instance->is_mysqld_compatible() && - Instance_options::is_option_im_specific(option.get_name())) - { - log_error("IM-option (%s) can not be used " - "in configuration of mysqld-compatible instance (%s).", - (const char *) option.get_name(), - (const char *) instance_name->str); - delete instance; - return ER_INCOMPATIBLE_OPTION; - } - - instance->options.set_option(&option); - } - - if (instance->is_mysqld_compatible()) - log_info("Warning: instance name '%s' is mysqld-compatible.", - (const char *) instance_name->str); - - if (instance->complete_initialization()) - { - log_error("Can not complete initialization of instance (name: '%s').", - (const char *) instance_name->str); - delete instance; - return ER_OUT_OF_RESOURCES; - /* TODO: return more appropriate error code in this case. */ - } - - if (add_instance(instance)) - { - log_error("Can not register instance (name: '%s').", - (const char *) instance_name->str); - delete instance; - return ER_OUT_OF_RESOURCES; - } - - return 0; -} - - -/** - Return a pointer to the instance or NULL, if there is no such instance. - - MT-NOTE: Instance Map must be locked before calling the operation. -*/ - -Instance * Instance_map::find(const LEX_STRING *name) -{ - return (Instance *) hash_search(&hash, (uchar *) name->str, name->length); -} - - -/** - Init instances command line arguments after all options have been loaded. -*/ - -bool Instance_map::complete_initialization() -{ - bool mysqld_found; - - /* Complete initialization of all registered instances. */ - - for (uint i= 0; i < hash.records; ++i) - { - Instance *instance= (Instance *) hash_element(&hash, i); - - if (instance->complete_initialization()) - return TRUE; - } - - /* That's all if we are runnning in an ordinary mode. */ - - if (!Options::Main::mysqld_safe_compatible) - return FALSE; - - /* In mysqld-compatible mode we must ensure that there 'mysqld' instance. */ - - mysqld_found= find(&Instance::DFLT_INSTANCE_NAME) != NULL; - - if (mysqld_found) - return FALSE; - - if (create_instance(&Instance::DFLT_INSTANCE_NAME, NULL)) - { - log_error("Can not create default instance."); - return TRUE; - } - - switch (create_instance_in_file(&Instance::DFLT_INSTANCE_NAME, NULL)) - { - case 0: - case ER_CONF_FILE_DOES_NOT_EXIST: - /* - Continue if the instance has been added to the config file - successfully, or the config file just does not exist. - */ - break; - - default: - log_error("Can not add default instance to the config file."); - - Instance *instance= find(&Instance::DFLT_INSTANCE_NAME); - - if (instance) - remove_instance(instance); /* instance is deleted here. */ - - return TRUE; - } - - return FALSE; -} - - -/** - Load options from config files and create appropriate instance - structures. -*/ - -int Instance_map::load() -{ - int argc= 1; - /* this is a dummy variable for search_option_files() */ - uint args_used= 0; - const char *argv_options[3]; - char **argv= (char **) &argv_options; - char defaults_file_arg[FN_REFLEN]; - - /* the name of the program may be orbitrary here in fact */ - argv_options[0]= "mysqlmanager"; - - /* - If the option file was forced by the user when starting - the IM with --defaults-file=xxxx, make sure it is also - passed as --defaults-file, not only as Options::config_file. - This is important for option files given with relative path: - e.g. --defaults-file=my.cnf. - Otherwise my_search_option_files will treat "my.cnf" as a group - name and start looking for files named "my.cnf.cnf" in all - default dirs. Which is not what we want. - */ - if (Options::Main::is_forced_default_file) - { - snprintf(defaults_file_arg, FN_REFLEN, "--defaults-file=%s", - Options::Main::config_file); - - argv_options[1]= defaults_file_arg; - argv_options[2]= '\0'; - - argc= 2; - } - else - argv_options[1]= '\0'; - - /* - If the routine failed, we'll simply fallback to defaults in - complete_initialization(). - */ - if (my_search_option_files(Options::Main::config_file, &argc, - (char ***) &argv, &args_used, - process_option, (void*) this, - Options::default_directories)) - log_info("Falling back to compiled-in defaults."); - - return complete_initialization(); -} - - -/************************************************************************* - {{{ Instance_map::Iterator implementation. -*************************************************************************/ - -void Instance_map::Iterator::go_to_first() -{ - current_instance=0; -} - - -Instance *Instance_map::Iterator::next() -{ - if (current_instance < instance_map->hash.records) - return (Instance *) hash_element(&instance_map->hash, current_instance++); - - return NULL; -} - -/************************************************************************* - }}} -*************************************************************************/ - - -/** - Create a new configuration section for mysqld-instance in the config file. - - SYNOPSIS - create_instance_in_file() - instance_name mysqld-instance name - options options for the new mysqld-instance - - RETURN - 0 On success - ER_CONF_FILE_DOES_NOT_EXIST If config file does not exist - ER_ACCESS_OPTION_FILE If config file is not writable or some I/O - error ocurred during writing configuration -*/ - -int create_instance_in_file(const LEX_STRING *instance_name, - const Named_value_arr *options) -{ - File cnf_file; - - if (my_access(Options::Main::config_file, W_OK)) - { - log_error("Configuration file (%s) does not exist.", - (const char *) Options::Main::config_file); - return ER_CONF_FILE_DOES_NOT_EXIST; - } - - cnf_file= my_open(Options::Main::config_file, O_WRONLY | O_APPEND, MYF(0)); - - if (cnf_file <= 0) - { - log_error("Can not open configuration file (%s): %s.", - (const char *) Options::Main::config_file, - (const char *) strerror(errno)); - return ER_ACCESS_OPTION_FILE; - } - - if (my_write(cnf_file, (uchar*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP)) || - my_write(cnf_file, (uchar*)"[", 1, MYF(MY_NABP)) || - my_write(cnf_file, (uchar*)instance_name->str, instance_name->length, - MYF(MY_NABP)) || - my_write(cnf_file, (uchar*)"]", 1, MYF(MY_NABP)) || - my_write(cnf_file, (uchar*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP))) - { - log_error("Can not write to configuration file (%s): %s.", - (const char *) Options::Main::config_file, - (const char *) strerror(errno)); - my_close(cnf_file, MYF(0)); - return ER_ACCESS_OPTION_FILE; - } - - for (int i= 0; options && i < options->get_size(); ++i) - { - char option_str[MAX_OPTION_STR_LEN]; - char *ptr; - int option_str_len; - Named_value option= options->get_element(i); - - ptr= strxnmov(option_str, MAX_OPTION_LEN + 1, option.get_name(), NullS); - - if (option.get_value()[0]) - ptr= strxnmov(ptr, MAX_OPTION_LEN + 2, "=", option.get_value(), NullS); - - option_str_len= ptr - option_str; - - if (my_write(cnf_file, (uchar*)option_str, option_str_len, MYF(MY_NABP)) || - my_write(cnf_file, (uchar*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP))) - { - log_error("Can not write to configuration file (%s): %s.", - (const char *) Options::Main::config_file, - (const char *) strerror(errno)); - my_close(cnf_file, MYF(0)); - return ER_ACCESS_OPTION_FILE; - } - } - - my_close(cnf_file, MYF(0)); - - return 0; -} diff --git a/server-tools/instance-manager/instance_map.h b/server-tools/instance-manager/instance_map.h deleted file mode 100644 index af2f1868195..00000000000 --- a/server-tools/instance-manager/instance_map.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H -/* Copyright (C) 2004 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 */ - -#include -#include -#include -#include - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -class Guardian; -class Instance; -class Named_value_arr; -class Thread_registry; - -extern int load_all_groups(char ***groups, const char *filename); -extern void free_groups(char **groups); - -extern int create_instance_in_file(const LEX_STRING *instance_name, - const Named_value_arr *options); - - -/** - Instance_map - stores all existing instances -*/ - -class Instance_map -{ -public: - /** - Instance_map iterator - */ - - class Iterator - { - private: - uint current_instance; - Instance_map *instance_map; - public: - Iterator(Instance_map *instance_map_arg) : - current_instance(0), instance_map(instance_map_arg) - {} - - void go_to_first(); - Instance *next(); - }; - -public: - Instance *find(const LEX_STRING *name); - - bool is_there_active_instance(); - - void lock(); - void unlock(); - - bool init(); - bool reset(); - - int load(); - - int process_one_option(const LEX_STRING *group, const char *option); - - int add_instance(Instance *instance); - - int remove_instance(Instance *instance); - - int create_instance(const LEX_STRING *instance_name, - const Named_value_arr *options); - -public: - Instance_map(); - ~Instance_map(); - -private: - bool complete_initialization(); - -private: - enum { START_HASH_SIZE = 16 }; - pthread_mutex_t LOCK_instance_map; - HASH hash; - -private: - friend class Iterator; -}; - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H */ diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc deleted file mode 100644 index 8b96d6f0f96..00000000000 --- a/server-tools/instance-manager/instance_options.cc +++ /dev/null @@ -1,753 +0,0 @@ -/* Copyright (C) 2004 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 */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "instance_options.h" - -#include -#include -#include - -#include - -#include "buffer.h" -#include "instance.h" -#include "log.h" -#include "options.h" -#include "parse_output.h" -#include "priv.h" - - -/* Create "mysqld ..." command in the buffer */ - -static inline bool create_mysqld_command(Buffer *buf, - const LEX_STRING *mysqld_path, - const LEX_STRING *option) -{ - int position= 0; - - if (buf->get_size()) /* malloc succeeded */ - { -#ifdef __WIN__ - buf->append(position++, "\"", 1); -#endif - buf->append(position, mysqld_path->str, mysqld_path->length); - position+= mysqld_path->length; -#ifdef __WIN__ - buf->append(position++, "\"", 1); -#endif - /* here the '\0' character is copied from the option string */ - buf->append(position, option->str, option->length + 1); - - return buf->is_error() ? TRUE : FALSE; - } - return TRUE; -} - -static inline bool is_path_separator(char ch) -{ -#if defined(__WIN__) || defined(__NETWARE__) - /* On windows and netware more delimiters are possible */ - return ch == FN_LIBCHAR || ch == FN_DEVCHAR || ch == '/'; -#else - return ch == FN_LIBCHAR; /* Unixes */ -#endif -} - - -static char *find_last_path_separator(char *path, uint length) -{ - while (length) - { - if (is_path_separator(path[length])) - return path + length; - length--; - } - return NULL; /* No path separator found */ -} - - - -bool Instance_options::is_option_im_specific(const char *option_name) -{ - static const char *IM_SPECIFIC_OPTIONS[] = - { - "nonguarded", - "mysqld-path", - "shutdown-delay", - NULL - }; - - for (int i= 0; IM_SPECIFIC_OPTIONS[i]; ++i) - { - if (!strcmp(option_name, IM_SPECIFIC_OPTIONS[i])) - return TRUE; - } - - return FALSE; -} - - -Instance_options::Instance_options() - :mysqld_version(NULL), mysqld_socket(NULL), mysqld_datadir(NULL), - mysqld_pid_file(NULL), - nonguarded(NULL), - mysqld_port(NULL), - mysqld_port_val(0), - shutdown_delay(NULL), - shutdown_delay_val(0), - filled_default_options(0) -{ - mysqld_path.str= NULL; - mysqld_path.length= 0; - - mysqld_real_path.str= NULL; - mysqld_real_path.length= 0; - - memset(logs, 0, sizeof(logs)); -} - - -/* - Get compiled-in value of default_option - - SYNOPSIS - get_default_option() - result buffer to put found value - result_len buffer size - option_name the name of the option, prefixed with "--" - - DESCRIPTION - - Get compile-in value of requested option from server - - RETURN - 0 - ok - 1 - error occured -*/ - - -int Instance_options::get_default_option(char *result, size_t result_len, - const char *option_name) -{ - int rc= 1; - LEX_STRING verbose_option= - { C_STRING_WITH_LEN(" --no-defaults --verbose --help") }; - - /* reserve space for the path + option + final '\0' */ - Buffer cmd(mysqld_path.length + verbose_option.length + 1); - - if (create_mysqld_command(&cmd, &mysqld_path, &verbose_option)) - goto err; - - /* +2 eats first "--" from the option string (E.g. "--datadir") */ - rc= parse_output_and_get_value((char*) cmd.buffer, - option_name + 2, strlen(option_name + 2), - result, result_len, GET_VALUE); -err: - return rc; -} - - -/* - Fill mysqld_version option (used at initialization stage) - - SYNOPSIS - fill_instance_version() - - DESCRIPTION - - Get mysqld version string from "mysqld --version" output. - - RETURN - FALSE - ok - TRUE - error occured -*/ - -bool Instance_options::fill_instance_version() -{ - char result[MAX_VERSION_LENGTH]; - LEX_STRING version_option= - { C_STRING_WITH_LEN(" --no-defaults --version") }; - Buffer cmd(mysqld_path.length + version_option.length + 1); - - if (create_mysqld_command(&cmd, &mysqld_path, &version_option)) - { - log_error("Failed to get version of '%s': out of memory.", - (const char *) mysqld_path.str); - return TRUE; - } - - bzero(result, MAX_VERSION_LENGTH); - - if (parse_output_and_get_value((char*) cmd.buffer, STRING_WITH_LEN("Ver"), - result, MAX_VERSION_LENGTH, GET_LINE)) - { - log_error("Failed to get version of '%s': unexpected output.", - (const char *) mysqld_path.str); - return TRUE; - } - - DBUG_ASSERT(*result != '\0'); - - { - char *start; - - /* trim leading whitespaces */ - start= result; - while (my_isspace(default_charset_info, *start)) - ++start; - - mysqld_version= strdup_root(&alloc, start); - } - - return FALSE; -} - - -/* - Fill mysqld_real_path - - SYNOPSIS - fill_mysqld_real_path() - - DESCRIPTION - - Get the real path to mysqld from "mysqld --help" output. - Will print the realpath of mysqld between "Usage: " and "[OPTIONS]" - - This is needed if the mysqld_path variable is pointing at a - script(for example libtool) or a symlink. - - RETURN - FALSE - ok - TRUE - error occured -*/ - -bool Instance_options::fill_mysqld_real_path() -{ - char result[FN_REFLEN]; - LEX_STRING help_option= - { C_STRING_WITH_LEN(" --no-defaults --help") }; - Buffer cmd(mysqld_path.length + help_option.length); - - if (create_mysqld_command(&cmd, &mysqld_path, &help_option)) - { - log_error("Failed to get real path of '%s': out of memory.", - (const char *) mysqld_path.str); - return TRUE; - } - - bzero(result, FN_REFLEN); - - if (parse_output_and_get_value((char*) cmd.buffer, - STRING_WITH_LEN("Usage: "), - result, FN_REFLEN, - GET_LINE)) - { - log_error("Failed to get real path of '%s': unexpected output.", - (const char *) mysqld_path.str); - return TRUE; - } - - DBUG_ASSERT(*result != '\0'); - - { - char* options_str; - /* chop the path of at [OPTIONS] */ - if ((options_str= strstr(result, "[OPTIONS]"))) - *options_str= '\0'; - mysqld_real_path.str= strdup_root(&alloc, result); - mysqld_real_path.length= strlen(mysqld_real_path.str); - } - - return FALSE; -} - - -/* - Fill various log options - - SYNOPSIS - fill_log_options() - - DESCRIPTION - - Compute paths to enabled log files. If the path is not specified in the - instance explicitly (I.e. log=/home/user/mysql.log), we try to guess the - file name and placement. - - RETURN - FALSE - ok - TRUE - error occured -*/ - -bool Instance_options::fill_log_options() -{ - Buffer buff; - enum { MAX_LOG_OPTION_LENGTH= 256 }; - char datadir[MAX_LOG_OPTION_LENGTH]; - char hostname[MAX_LOG_OPTION_LENGTH]; - uint hostname_length; - struct log_files_st - { - const char *name; - uint length; - char **value; - const char *default_suffix; - } logs_st[]= - { - {"--log-error", 11, &(logs[IM_LOG_ERROR]), ".err"}, - {"--log", 5, &(logs[IM_LOG_GENERAL]), ".log"}, - {"--log-slow-queries", 18, &(logs[IM_LOG_SLOW]), "-slow.log"}, - {NULL, 0, NULL, NULL} - }; - struct log_files_st *log_files; - - /* compute hostname and datadir for the instance */ - if (mysqld_datadir == NULL) - { - if (get_default_option(datadir, MAX_LOG_OPTION_LENGTH, "--datadir")) - return TRUE; - } - else - { - /* below is safe, as --datadir always has a value */ - strmake(datadir, mysqld_datadir, MAX_LOG_OPTION_LENGTH - 1); - } - - if (gethostname(hostname,sizeof(hostname)-1) < 0) - strmov(hostname, "mysql"); - - hostname[MAX_LOG_OPTION_LENGTH - 1]= 0; /* Safety */ - hostname_length= strlen(hostname); - - - for (log_files= logs_st; log_files->name; log_files++) - { - for (int i=0; (argv[i] != 0); i++) - { - if (!strncmp(argv[i], log_files->name, log_files->length)) - { - /* - This is really log_files->name option if and only if it is followed - by '=', '\0' or space character. This way we can distinguish such - options as '--log' and '--log-bin'. This is checked in the following - two statements. - */ - if (argv[i][log_files->length] == '\0' || - my_isspace(default_charset_info, argv[i][log_files->length])) - { - char full_name[MAX_LOG_OPTION_LENGTH]; - - fn_format(full_name, hostname, datadir, "", - MY_UNPACK_FILENAME | MY_SAFE_PATH); - - - if ((MAX_LOG_OPTION_LENGTH - strlen(full_name)) <= - strlen(log_files->default_suffix)) - return TRUE; - - strmov(full_name + strlen(full_name), log_files->default_suffix); - - /* - If there were specified two identical logfiles options, - we would loose some memory in MEM_ROOT here. However - this situation is not typical. - */ - *(log_files->value)= strdup_root(&alloc, full_name); - } - - if (argv[i][log_files->length] == '=') - { - char full_name[MAX_LOG_OPTION_LENGTH]; - - fn_format(full_name, argv[i] +log_files->length + 1, - datadir, "", MY_UNPACK_FILENAME | MY_SAFE_PATH); - - if (!(*(log_files->value)= strdup_root(&alloc, full_name))) - return TRUE; - } - } - } - } - - return FALSE; -} - - -/* - Get the full pid file name with path - - SYNOPSIS - get_pid_filaname() - result buffer to sotre the pidfile value - - IMPLEMENTATION - Get the data directory, then get the pid filename - (which is always set for an instance), then load the - full path with my_load_path(). It takes into account - whether it is already an absolute path or it should be - prefixed with the datadir and so on. - - RETURN - 0 - ok - 1 - error occured -*/ - -int Instance_options::get_pid_filename(char *result) -{ - char datadir[MAX_PATH_LEN]; - - if (mysqld_datadir == NULL) - { - /* we might get an error here if we have wrong path to the mysqld binary */ - if (get_default_option(datadir, sizeof(datadir), "--datadir")) - return 1; - } - else - strxnmov(datadir, MAX_PATH_LEN - 1, mysqld_datadir, "/", NullS); - - /* get the full path to the pidfile */ - my_load_path(result, mysqld_pid_file, datadir); - return 0; -} - - -int Instance_options::unlink_pidfile() -{ - return unlink(pid_file_with_path); -} - - -pid_t Instance_options::load_pid() -{ - FILE *pid_file_stream; - - /* get the pid */ - if ((pid_file_stream= my_fopen(pid_file_with_path, - O_RDONLY | O_BINARY, MYF(0))) != NULL) - { - pid_t pid; - - if (fscanf(pid_file_stream, "%i", &pid) != 1) - pid= -1; - my_fclose(pid_file_stream, MYF(0)); - return pid; - } - return 0; -} - - -bool Instance_options::complete_initialization() -{ - int arg_idx; - const char *tmp; - char *end; - char bin_name_firstchar; - - if (!mysqld_path.str) - { - /* - Need to copy the path to allocated memory, as convert_dirname() might - need to change it - */ - mysqld_path.str= strdup_root(&alloc, Options::Main::default_mysqld_path); - if (!mysqld_path.str) - return TRUE; - } - - mysqld_path.length= strlen(mysqld_path.str); - - /* - If we found path with no slashes (end == NULL), we should not call - convert_dirname() at all. As we have got relative path to the binary. - That is, user supposes that mysqld resides in the same dir as - mysqlmanager. - */ - if ((end= find_last_path_separator(mysqld_path.str, mysqld_path.length))) - { - bin_name_firstchar= end[1]; - - /* - Below we will conver the path to mysqld in the case, it was given - in a format of another OS (e.g. uses '/' instead of '\' etc). - Here we strip the path to get rid of the binary name ("mysqld"), - we do it by removing first letter of the binary name (e.g. 'm' - in "mysqld"). Later we put it back. - */ - end[1]= 0; - - /* convert dirname to the format of current OS */ - convert_dirname((char*)mysqld_path.str, mysqld_path.str, NullS); - - /* put back the first character of the binary name*/ - end[1]= bin_name_firstchar; - } - - if (mysqld_port) - mysqld_port_val= atoi(mysqld_port); - - if (shutdown_delay) - shutdown_delay_val= atoi(shutdown_delay); - - if (!(tmp= strdup_root(&alloc, "--no-defaults"))) - return TRUE; - - if (!mysqld_pid_file) - { - char pidfilename[MAX_PATH_LEN]; - char hostname[MAX_PATH_LEN]; - - /* - If we created only one istance [mysqld], because no config. files were - found, we would like to model mysqld pid file values. - */ - - if (!gethostname(hostname, sizeof(hostname) - 1)) - { - if (Instance::is_mysqld_compatible_name(&instance_name)) - strxnmov(pidfilename, MAX_PATH_LEN - 1, hostname, ".pid", NullS); - else - strxnmov(pidfilename, MAX_PATH_LEN - 1, instance_name.str, "-", - hostname, ".pid", NullS); - } - else - { - if (Instance::is_mysqld_compatible_name(&instance_name)) - strxnmov(pidfilename, MAX_PATH_LEN - 1, "mysql", ".pid", NullS); - else - strxnmov(pidfilename, MAX_PATH_LEN - 1, instance_name.str, ".pid", - NullS); - } - - Named_value option((char *) "pid-file", pidfilename); - - set_option(&option); - } - - if (get_pid_filename(pid_file_with_path)) - return TRUE; - - /* we need to reserve space for the final zero + possible default options */ - if (!(argv= (char**) - alloc_root(&alloc, (get_num_options() + 1 - + MAX_NUMBER_OF_DEFAULT_OPTIONS) * sizeof(char*)))) - return TRUE; - filled_default_options= 0; - - /* the path must be first in the argv */ - if (add_to_argv(mysqld_path.str)) - return TRUE; - - if (add_to_argv(tmp)) - return TRUE; - - arg_idx= filled_default_options; - for (int opt_idx= 0; opt_idx < get_num_options(); ++opt_idx) - { - char option_str[MAX_OPTION_STR_LEN]; - Named_value option= get_option(opt_idx); - - if (is_option_im_specific(option.get_name())) - continue; - - char *ptr= strxnmov(option_str, MAX_OPTION_LEN + 3, "--", option.get_name(), - NullS); - - if (option.get_value()[0]) - strxnmov(ptr, MAX_OPTION_LEN + 2, "=", option.get_value(), NullS); - - argv[arg_idx++]= strdup_root(&alloc, option_str); - } - - argv[arg_idx]= 0; - - if (fill_log_options() || fill_mysqld_real_path() || fill_instance_version()) - return TRUE; - - return FALSE; -} - - -bool Instance_options::set_option(Named_value *option) -{ - bool err_status; - int idx= find_option(option->get_name()); - char *option_name_str; - char *option_value_str; - - if (!(option_name_str= Named_value::alloc_str(option->get_name()))) - return TRUE; - - if (!(option_value_str= Named_value::alloc_str(option->get_value()))) - { - Named_value::free_str(&option_name_str); - return TRUE; - } - - Named_value option_copy(option_name_str, option_value_str); - - if (idx < 0) - err_status= options.add_element(&option_copy); - else - err_status= options.replace_element(idx, &option_copy); - - if (!err_status) - update_var(option_copy.get_name(), option_copy.get_value()); - else - option_copy.free(); - - return err_status; -} - - -void Instance_options::unset_option(const char *option_name) -{ - int idx= find_option(option_name); - - if (idx < 0) - return; /* the option has not been set. */ - - options.remove_element(idx); - - update_var(option_name, NULL); -} - - -void Instance_options::update_var(const char *option_name, - const char *option_value) -{ - struct options_st - { - const char *name; - uint name_len; - const char **var; - } options_def[]= - { - {"socket", 6, &mysqld_socket}, - {"port", 4, &mysqld_port}, - {"datadir", 7, &mysqld_datadir}, - {"pid-file", 8, &mysqld_pid_file}, - {"nonguarded", 10, &nonguarded}, - {"mysqld-path", 11, (const char **) &mysqld_path.str}, - {"shutdown-delay", 14, &shutdown_delay}, - {NULL, 0, NULL} - }; - - for (options_st *opt= options_def; opt->name; ++opt) - { - if (!strncmp(opt->name, option_name, opt->name_len)) - { - *(opt->var)= option_value; - break; - } - } -} - - -int Instance_options::find_option(const char *option_name) -{ - for (int i= 0; i < get_num_options(); i++) - { - if (!strcmp(get_option(i).get_name(), option_name)) - return i; - } - - return -1; -} - - -int Instance_options::add_to_argv(const char* option) -{ - DBUG_ASSERT(filled_default_options < MAX_NUMBER_OF_DEFAULT_OPTIONS); - - if (option) - argv[filled_default_options++]= (char*) option; - return 0; -} - - -/* function for debug purposes */ -void Instance_options::print_argv() -{ - int i; - - printf("printing out an instance %s argv:\n", - (const char *) instance_name.str); - - for (i=0; argv[i] != NULL; i++) - printf("argv: %s\n", argv[i]); -} - - -/* - We execute this function to initialize some options. - - RETURN - FALSE - ok - TRUE - memory allocation error -*/ - -bool Instance_options::init(const LEX_STRING *instance_name_arg) -{ - instance_name.length= instance_name_arg->length; - - init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0); - - if (options.init()) - return TRUE; - - if (!(instance_name.str= strmake_root(&alloc, instance_name_arg->str, - instance_name_arg->length))) - return TRUE; - - return FALSE; -} - - -Instance_options::~Instance_options() -{ - free_root(&alloc, MYF(0)); -} - - -uint Instance_options::get_shutdown_delay() const -{ - static const uint DEFAULT_SHUTDOWN_DELAY= 35; - - /* - NOTE: it is important to check shutdown_delay here, but use - shutdown_delay_val. The idea is that if the option is unset, - shutdown_delay will be NULL, but shutdown_delay_val will not be reset. - */ - - return shutdown_delay ? shutdown_delay_val : DEFAULT_SHUTDOWN_DELAY; -} - -int Instance_options::get_mysqld_port() const -{ - /* - NOTE: it is important to check mysqld_port here, but use mysqld_port_val. - The idea is that if the option is unset, mysqld_port will be NULL, but - mysqld_port_val will not be reset. - */ - - return mysqld_port ? mysqld_port_val : 0; -} - diff --git a/server-tools/instance-manager/instance_options.h b/server-tools/instance-manager/instance_options.h deleted file mode 100644 index b0503815036..00000000000 --- a/server-tools/instance-manager/instance_options.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H -/* Copyright (C) 2004 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 */ - -#include -#include - -#include "parse.h" -#include "portability.h" /* for pid_t on Win32 */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - - -/* - This class contains options of an instance and methods to operate them. - - We do not provide this class with the means of synchronization as it is - supposed that options for instances are all loaded at once during the - instance_map initilization and we do not change them later. This way we - don't have to synchronize between threads. -*/ - -class Instance_options -{ -public: - /* The operation is used to check if the option is IM-specific or not. */ - static bool is_option_im_specific(const char *option_name); - -public: - Instance_options(); - ~Instance_options(); - - bool complete_initialization(); - - bool set_option(Named_value *option); - void unset_option(const char *option_name); - - inline int get_num_options() const; - inline Named_value get_option(int idx) const; - -public: - bool init(const LEX_STRING *instance_name_arg); - pid_t load_pid(); - int get_pid_filename(char *result); - int unlink_pidfile(); - void print_argv(); - - uint get_shutdown_delay() const; - int get_mysqld_port() const; - -public: - /* - We need this value to be greater or equal then FN_REFLEN found in - my_global.h to use my_load_path() - */ - enum { MAX_PATH_LEN= 512 }; - enum { MAX_NUMBER_OF_DEFAULT_OPTIONS= 2 }; - char pid_file_with_path[MAX_PATH_LEN]; - char **argv; - /* - Here we cache the version string, obtained from mysqld --version. - In the case when mysqld binary is not found we get NULL here. - */ - const char *mysqld_version; - /* We need the some options, so we store them as a separate pointers */ - const char *mysqld_socket; - const char *mysqld_datadir; - const char *mysqld_pid_file; - LEX_STRING instance_name; - LEX_STRING mysqld_path; - LEX_STRING mysqld_real_path; - const char *nonguarded; - /* log enums are defined in parse.h */ - char *logs[3]; - -private: - bool fill_log_options(); - bool fill_instance_version(); - bool fill_mysqld_real_path(); - int add_to_argv(const char *option); - int get_default_option(char *result, size_t result_len, - const char *option_name); - - void update_var(const char *option_name, const char *option_value); - int find_option(const char *option_name); - -private: - const char *mysqld_port; - uint mysqld_port_val; - const char *shutdown_delay; - uint shutdown_delay_val; - - uint filled_default_options; - MEM_ROOT alloc; - - Named_value_arr options; -}; - - -inline int Instance_options::get_num_options() const -{ - return options.get_size(); -} - - -inline Named_value Instance_options::get_option(int idx) const -{ - return options.get_element(idx); -} - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H */ diff --git a/server-tools/instance-manager/listener.cc b/server-tools/instance-manager/listener.cc deleted file mode 100644 index 4d8a33e7db1..00000000000 --- a/server-tools/instance-manager/listener.cc +++ /dev/null @@ -1,337 +0,0 @@ -/* Copyright (C) 2003-2006 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 */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "listener.h" - -#include -#include -#include - -#include -#ifndef __WIN__ -#include -#endif - -#include "log.h" -#include "mysql_connection.h" -#include "options.h" -#include "portability.h" -#include "priv.h" -#include "thread_registry.h" - - -static void set_non_blocking(int socket) -{ -#ifndef __WIN__ - int flags= fcntl(socket, F_GETFL, 0); - fcntl(socket, F_SETFL, flags | O_NONBLOCK); -#else - u_long arg= 1; - ioctlsocket(socket, FIONBIO, &arg); -#endif -} - - -static void set_no_inherit(int socket) -{ -#ifndef __WIN__ - int flags= fcntl(socket, F_GETFD, 0); - fcntl(socket, F_SETFD, flags | FD_CLOEXEC); -#endif -} - -const int Listener::LISTEN_BACK_LOG_SIZE= 5; /* standard backlog size */ - -Listener::Listener(Thread_registry *thread_registry_arg, - User_map *user_map_arg) - :thread_registry(thread_registry_arg), - user_map(user_map_arg), - total_connection_count(0), - num_sockets(0) -{ -} - - -/* - Listener::run() - listen all supported sockets and spawn a thread - to handle incoming connection. - Using 'die' in case of syscall failure is OK now - we don't hold any - resources and 'die' kills the signal thread automatically. To be rewritten - one day. - See also comments in mysqlmanager.cc to picture general Instance Manager - architecture. -*/ - -void Listener::run() -{ - int i, n= 0; - -#ifndef __WIN__ - struct sockaddr_un unix_socket_address; -#endif - - log_info("Listener: started."); - - thread_registry->register_thread(&thread_info); - - FD_ZERO(&read_fds); - - /* I. prepare 'listen' sockets */ - if (create_tcp_socket()) - goto err; - -#ifndef __WIN__ - if (create_unix_socket(unix_socket_address)) - goto err; -#endif - - /* II. Listen sockets and spawn childs */ - for (i= 0; i < num_sockets; i++) - n= max(n, sockets[i]); - n++; - - timeval tv; - while (!thread_registry->is_shutdown()) - { - fd_set read_fds_arg= read_fds; - /* - We should reintialize timer as on linux it is modified - to reflect amount of time not slept. - */ - tv.tv_sec= 0; - tv.tv_usec= 100000; - - /* - When using valgrind 2.0 this syscall doesn't get kicked off by a - signal during shutdown. This results in failing assert - (Thread_registry::~Thread_registry). Valgrind 2.2 works fine. - */ - int rc= select(n, &read_fds_arg, 0, 0, &tv); - - if (rc == 0 || rc == -1) - { - if (rc == -1 && errno != EINTR) - log_error("Listener: select() failed: %s.", - (const char *) strerror(errno)); - continue; - } - - - for (int socket_index= 0; socket_index < num_sockets; socket_index++) - { - /* Assuming that rc > 0 as we asked to wait forever */ - if (FD_ISSET(sockets[socket_index], &read_fds_arg)) - { - int client_fd= accept(sockets[socket_index], 0, 0); - /* accept may return -1 (failure or spurious wakeup) */ - if (client_fd >= 0) // connection established - { - set_no_inherit(client_fd); - - struct st_vio *vio= - vio_new(client_fd, - socket_index == 0 ? VIO_TYPE_SOCKET : VIO_TYPE_TCPIP, - socket_index == 0 ? 1 : 0); - - if (vio != NULL) - handle_new_mysql_connection(vio); - else - { - shutdown(client_fd, SHUT_RDWR); - closesocket(client_fd); - } - } - } - } - } - - /* III. Release all resources and exit */ - - log_info("Listener: shutdown requested, exiting..."); - - for (i= 0; i < num_sockets; i++) - closesocket(sockets[i]); - -#ifndef __WIN__ - unlink(unix_socket_address.sun_path); -#endif - - thread_registry->unregister_thread(&thread_info); - - log_info("Listener: finished."); - return; - -err: - log_error("Listener: failed to initialize. Initiate shutdown..."); - - // we have to close the ip sockets in case of error - for (i= 0; i < num_sockets; i++) - closesocket(sockets[i]); - - thread_registry->set_error_status(); - thread_registry->unregister_thread(&thread_info); - thread_registry->request_shutdown(); - return; -} - -int Listener::create_tcp_socket() -{ - /* value to be set by setsockopt */ - int arg= 1; - - int ip_socket= socket(AF_INET, SOCK_STREAM, 0); - if (ip_socket == INVALID_SOCKET) - { - log_error("Listener: socket(AF_INET) failed: %s.", - (const char *) strerror(errno)); - return -1; - } - - struct sockaddr_in ip_socket_address; - bzero(&ip_socket_address, sizeof(ip_socket_address)); - - ulong im_bind_addr; - if (Options::Main::bind_address != 0) - { - im_bind_addr= (ulong) inet_addr(Options::Main::bind_address); - - if (im_bind_addr == (ulong) INADDR_NONE) - im_bind_addr= htonl(INADDR_ANY); - } - else - im_bind_addr= htonl(INADDR_ANY); - uint im_port= Options::Main::port_number; - - ip_socket_address.sin_family= AF_INET; - ip_socket_address.sin_addr.s_addr= im_bind_addr; - - - ip_socket_address.sin_port= (unsigned short) - htons((unsigned short) im_port); - - setsockopt(ip_socket, SOL_SOCKET, SO_REUSEADDR, (char*) &arg, sizeof(arg)); - if (bind(ip_socket, (struct sockaddr *) &ip_socket_address, - sizeof(ip_socket_address))) - { - log_error("Listener: bind(ip socket) failed: %s.", - (const char *) strerror(errno)); - closesocket(ip_socket); - return -1; - } - - if (listen(ip_socket, LISTEN_BACK_LOG_SIZE)) - { - log_error("Listener: listen(ip socket) failed: %s.", - (const char *) strerror(errno)); - closesocket(ip_socket); - return -1; - } - - /* set the socket nonblocking */ - set_non_blocking(ip_socket); - - /* make sure that instances won't be listening our sockets */ - set_no_inherit(ip_socket); - - FD_SET(ip_socket, &read_fds); - sockets[num_sockets++]= ip_socket; - log_info("Listener: accepting connections on ip socket (port: %d)...", - (int) im_port); - return 0; -} - -#ifndef __WIN__ -int Listener:: -create_unix_socket(struct sockaddr_un &unix_socket_address) -{ - int unix_socket= socket(AF_UNIX, SOCK_STREAM, 0); - if (unix_socket == INVALID_SOCKET) - { - log_error("Listener: socket(AF_UNIX) failed: %s.", - (const char *) strerror(errno)); - return -1; - } - - bzero(&unix_socket_address, sizeof(unix_socket_address)); - - unix_socket_address.sun_family= AF_UNIX; - strmake(unix_socket_address.sun_path, Options::Main::socket_file_name, - sizeof(unix_socket_address.sun_path)); - unlink(unix_socket_address.sun_path); // in case we have stale socket file - - /* - POSIX specifies default permissions for a pathname created by bind - to be 0777. We need everybody to have access to the socket. - */ - mode_t old_mask= umask(0); - if (bind(unix_socket, (struct sockaddr *) &unix_socket_address, - sizeof(unix_socket_address))) - { - log_error("Listener: bind(unix socket) failed for '%s': %s.", - (const char *) unix_socket_address.sun_path, - (const char *) strerror(errno)); - close(unix_socket); - return -1; - } - - umask(old_mask); - - if (listen(unix_socket, LISTEN_BACK_LOG_SIZE)) - { - log_error("Listener: listen(unix socket) failed: %s.", - (const char *) strerror(errno)); - close(unix_socket); - return -1; - } - - /* set the socket nonblocking */ - set_non_blocking(unix_socket); - - /* make sure that instances won't be listening our sockets */ - set_no_inherit(unix_socket); - - log_info("Listener: accepting connections on unix socket '%s'...", - (const char *) unix_socket_address.sun_path); - sockets[num_sockets++]= unix_socket; - FD_SET(unix_socket, &read_fds); - return 0; -} -#endif - - -/* - Create new mysql connection. Created thread is responsible for deletion of - the Mysql_connection and Vio instances passed to it. - SYNOPSIS - handle_new_mysql_connection() -*/ - -void Listener::handle_new_mysql_connection(struct st_vio *vio) -{ - Mysql_connection *mysql_connection= - new Mysql_connection(thread_registry, user_map, - vio, ++total_connection_count); - if (mysql_connection == NULL || mysql_connection->start(Thread::DETACHED)) - { - log_error("Listener: can not start connection handler."); - delete mysql_connection; - vio_delete(vio); - } - /* The connection will delete itself when the thread is finished */ -} diff --git a/server-tools/instance-manager/listener.h b/server-tools/instance-manager/listener.h deleted file mode 100644 index 964fb361fb5..00000000000 --- a/server-tools/instance-manager/listener.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (C) 2003-2006 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 */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H - -#include "thread_registry.h" - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -class Thread_registry; -class User_map; - -/** - Listener - a thread listening on sockets and spawning - connection threads. -*/ - -class Listener: public Thread -{ -public: - Listener(Thread_registry *thread_registry_arg, User_map *user_map_arg); - -protected: - virtual void run(); - -private: - static const int LISTEN_BACK_LOG_SIZE; - -private: - Thread_info thread_info; - Thread_registry *thread_registry; - User_map *user_map; - - ulong total_connection_count; - - int sockets[2]; - int num_sockets; - fd_set read_fds; - -private: - void handle_new_mysql_connection(struct st_vio *vio); - int create_tcp_socket(); - int create_unix_socket(struct sockaddr_un &unix_socket_address); -}; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H diff --git a/server-tools/instance-manager/log.cc b/server-tools/instance-manager/log.cc deleted file mode 100644 index 9f276523e49..00000000000 --- a/server-tools/instance-manager/log.cc +++ /dev/null @@ -1,196 +0,0 @@ -/* Copyright (C) 2003-2006 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 */ - -#include "log.h" - -#include -#include -#include - -#include - -#include "portability.h" /* for vsnprintf() on Windows. */ - -/* - TODO: - - add flexible header support - - rewrite all fprintf with fwrite - - think about using 'write' instead of fwrite/fprintf on POSIX systems -*/ - -/* - Format log entry and write it to the given stream. - SYNOPSIS - log() -*/ - -static void log(FILE *file,const char *level_tag, const char *format, - va_list args) -{ - /* - log() should be thread-safe; it implies that we either call fprintf() - once per log(), or use flockfile()/funlockfile(). But flockfile() is - POSIX, not ANSI C, so we try to vsnprintf the whole message to the - stack, and if stack buffer is not enough, to malloced string. When - message is formatted, it is fprintf()'ed to the file. - */ - - /* Format time like MYSQL_LOG does. */ - time_t now= time(0); - struct tm bd_time; // broken-down time - localtime_r(&now, &bd_time); - - char buff_date[128]; - sprintf(buff_date, "[%d/%lu] [%02d/%02d/%02d %02d:%02d:%02d] [%s] ", - (int) getpid(), - (unsigned long) pthread_self(), - (int) bd_time.tm_year % 100, - (int) bd_time.tm_mon + 1, - (int) bd_time.tm_mday, - (int) bd_time.tm_hour, - (int) bd_time.tm_min, - (int) bd_time.tm_sec, - (const char *) level_tag); - /* Format the message */ - char buff_stack[256]; - - int n= vsnprintf(buff_stack, sizeof(buff_stack), format, args); - /* - return value of vsnprintf can vary, according to various standards; - try to check all cases. - */ - char *buff_msg= buff_stack; - if (n < 0 || n == sizeof(buff_stack)) - { - int size= sizeof(buff_stack) * 2; - buff_msg= (char*) my_malloc(size, MYF(0)); - while (TRUE) - { - if (buff_msg == 0) - { - strmake(buff_stack, "log(): message is too big, my_malloc() failed", - sizeof(buff_stack) - 1); - buff_msg= buff_stack; - break; - } - n = vsnprintf(buff_msg, size, format, args); - if (n >= 0 && n < size) - break; - size*= 2; - /* realloc() does unnecessary memcpy */ - my_free(buff_msg, 0); - buff_msg= (char*) my_malloc(size, MYF(0)); - } - } - else if ((size_t) n > sizeof(buff_stack)) - { - buff_msg= (char*) my_malloc(n + 1, MYF(0)); -#ifdef DBUG - DBUG_ASSERT(n == vsnprintf(buff_msg, n + 1, format, args)); -#else - vsnprintf(buff_msg, n + 1, format, args); -#endif - } - fprintf(file, "%s%s\n", buff_date, buff_msg); - if (buff_msg != buff_stack) - my_free(buff_msg, 0); - - /* don't fflush() the file: buffering strategy is set in log_init() */ -} - -/************************************************************************** - Logging: implementation of public interface. -**************************************************************************/ - -/* - The function initializes logging sub-system. - - SYNOPSIS - log_init() -*/ - -void log_init() -{ - /* - stderr is unbuffered by default; there is no good of line buffering, - as all logging is performed linewise - so remove buffering from stdout - also - */ - setbuf(stdout, 0); -} - - -/* - The function is intended to log error messages. It precedes a message - with date, time and [ERROR] tag and print it to the stderr and stdout. - - We want to print it on stdout to be able to know in which context we got the - error - - SYNOPSIS - log_error() - format [IN] format string - ... [IN] arguments to format -*/ - -void log_error(const char *format, ...) -{ - va_list args; - va_start(args, format); - log(stdout, "ERROR", format, args); - fflush(stdout); - log(stderr, "ERROR", format, args); - fflush(stderr); - va_end(args); -} - - -/* - The function is intended to log information messages. It precedes - a message with date, time and [INFO] tag and print it to the stdout. - - SYNOPSIS - log_error() - format [IN] format string - ... [IN] arguments to format -*/ - -void log_info(const char *format, ...) -{ - va_list args; - va_start(args, format); - log(stdout, "INFO", format, args); - va_end(args); -} - -/* - The function prints information to the error log and eixt(1). - - SYNOPSIS - die() - format [IN] format string - ... [IN] arguments to format -*/ - -void die(const char *format, ...) -{ - va_list args; - fprintf(stderr,"%s: ", my_progname); - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - fprintf(stderr, "\n"); - exit(1); -} diff --git a/server-tools/instance-manager/log.h b/server-tools/instance-manager/log.h deleted file mode 100644 index e6c3b55c54c..00000000000 --- a/server-tools/instance-manager/log.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (C) 2003-2006 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 */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H - -/* - Logging facilities. - - Two logging streams are supported: error log and info log. - Additionally libdbug may be used for debug information output. - - ANSI C buffered I/O is used to perform logging. - - Logging is performed via stdout/stder, so one can reopen them to point to - ordinary files. To initialize logging environment log_init() must be called. - - Rationale: - - no MYSQL_LOG as it has BIN mode, and not easy to fetch from sql_class.h - - no constructors/desctructors to make logging available all the time -*/ - - -void log_init(); - - -void log_info(const char *format, ...) -#ifdef __GNUC__ - __attribute__ ((format(printf, 1, 2))) -#endif - ; - - -void log_error(const char *format, ...) -#ifdef __GNUC__ - __attribute__ ((format (printf, 1, 2))) -#endif - ; - - -void die(const char *format, ...) -#ifdef __GNUC__ - __attribute__ ((format (printf, 1, 2))) -#endif - ; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc deleted file mode 100644 index 792461e41a9..00000000000 --- a/server-tools/instance-manager/manager.cc +++ /dev/null @@ -1,526 +0,0 @@ -/* Copyright (C) 2003-2006 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 */ - -#include "manager.h" - -#include -#include -#include -#include - -#include -#ifndef __WIN__ -#include -#endif - -#include "exit_codes.h" -#include "guardian.h" -#include "instance_map.h" -#include "listener.h" -#include "mysql_manager_error.h" -#include "mysqld_error.h" -#include "log.h" -#include "options.h" -#include "priv.h" -#include "thread_registry.h" -#include "user_map.h" - - -/********************************************************************** - {{{ Platform-specific implementation. -**********************************************************************/ - -#ifndef __WIN__ -void set_signals(sigset_t *mask) -{ - /* block signals */ - sigemptyset(mask); - sigaddset(mask, SIGINT); - sigaddset(mask, SIGTERM); - sigaddset(mask, SIGPIPE); - sigaddset(mask, SIGHUP); - signal(SIGPIPE, SIG_IGN); - - /* - We want this signal to be blocked in all theads but the signal - one. It is needed for the thr_alarm subsystem to work. - */ - sigaddset(mask,THR_SERVER_ALARM); - - /* all new threads will inherite this signal mask */ - pthread_sigmask(SIG_BLOCK, mask, NULL); - - /* - In our case the signal thread also implements functions of alarm thread. - Here we init alarm thread functionality. We suppose that we won't have - more then 10 alarms at the same time. - */ - init_thr_alarm(10); -} -#else - -bool have_signal; - -void onsignal(int signo) -{ - have_signal= TRUE; -} - -void set_signals(sigset_t *set) -{ - signal(SIGINT, onsignal); - signal(SIGTERM, onsignal); - have_signal= FALSE; -} - -int my_sigwait(const sigset_t *set, int *sig) -{ - while (!have_signal) - { - Sleep(100); - } - return 0; -} - -#endif - -/********************************************************************** - }}} -**********************************************************************/ - - -/********************************************************************** - {{{ Implementation of checking the actual thread model. -***********************************************************************/ - -namespace { /* no-indent */ - -class ThreadModelChecker: public Thread -{ -public: - ThreadModelChecker() - :main_pid(getpid()) - { } - -public: - inline bool is_linux_threads() const - { - return linux_threads; - } - -protected: - virtual void run() - { - linux_threads= main_pid != getpid(); - } - -private: - pid_t main_pid; - bool linux_threads; -}; - -bool check_if_linux_threads(bool *linux_threads) -{ - ThreadModelChecker checker; - - if (checker.start() || checker.join()) - return TRUE; - - *linux_threads= checker.is_linux_threads(); - - return FALSE; -} - -} - -/********************************************************************** - }}} -***********************************************************************/ - - -/********************************************************************** - Manager implementation -***********************************************************************/ - -Guardian *Manager::p_guardian; -Instance_map *Manager::p_instance_map; -Thread_registry *Manager::p_thread_registry; -User_map *Manager::p_user_map; - -#ifndef __WIN__ -bool Manager::linux_threads; -#endif // __WIN__ - - -/** - Request shutdown of guardian and threads registered in Thread_registry. - - SYNOPSIS - stop_all_threads() -*/ - -void Manager::stop_all_threads() -{ - /* - Let Guardian thread know that it should break it's processing cycle, - once it wakes up. - */ - p_guardian->request_shutdown(); - - /* Stop all threads. */ - p_thread_registry->deliver_shutdown(); - - /* Set error status in the thread registry. */ - p_thread_registry->set_error_status(); -} - - -/** - Initialize user map and load password file. - - SYNOPSIS - init_user_map() - - RETURN - FALSE on success - TRUE on failure -*/ - -bool Manager::init_user_map(User_map *user_map) -{ - int err_code; - const char *err_msg; - - if (user_map->init()) - { - log_error("Manager: can not initialize user list: out of memory."); - return TRUE; - } - - err_code= user_map->load(Options::Main::password_file_name, &err_msg); - - if (!err_code) - return FALSE; - - if (err_code == ERR_PASSWORD_FILE_DOES_NOT_EXIST && - Options::Main::mysqld_safe_compatible) - { - /* - The password file does not exist, but we are running in - mysqld_safe-compatible mode. Continue, but complain in log. - */ - - log_info("Warning: password file does not exist, " - "nobody will be able to connect to Instance Manager."); - - return FALSE; - } - - log_error("Manager: %s.", (const char *) err_msg); - - return TRUE; -} - - -/** - Main manager function. - - SYNOPSIS - main() - - DESCRIPTION - This is an entry point to the main instance manager process: - start listener thread, write pid file and enter into signal handling. - See also comments in mysqlmanager.cc to picture general Instance Manager - architecture. - - RETURNS - main() returns exit status (exit code). -*/ - -int Manager::main() -{ - bool shutdown_complete= FALSE; - pid_t manager_pid= getpid(); - - log_info("Manager: initializing..."); - -#ifndef __WIN__ - if (check_if_linux_threads(&linux_threads)) - { - log_error("Manager: can not determine thread model."); - return 1; - } - - log_info("Manager: detected threads model: %s.", - (const char *) (linux_threads ? "LINUX threads" : "POSIX threads")); -#endif // __WIN__ - - /* - All objects created in the Manager object live as long as thread_registry - lives, and thread_registry is alive until there are working threads. - - There are two main purposes of the Thread Registry: - 1. Interrupt blocking I/O and signal condition variables in case of - shutdown; - 2. Wait for detached threads before shutting down the main thread. - - NOTE: - 1. Handling shutdown can be done in more elegant manner by introducing - Event (or Condition) object with support of logical operations. - 2. Using Thread Registry to wait for detached threads is definitely not - the best way, because when Thread Registry unregisters an thread, the - thread is still alive. Accurate way to wait for threads to stop is - not using detached threads and join all threads before shutdown. - */ - - Thread_registry thread_registry; - User_map user_map; - Instance_map instance_map; - Guardian guardian(&thread_registry, &instance_map); - - Listener listener(&thread_registry, &user_map); - - p_instance_map= &instance_map; - p_guardian= &guardian; - p_thread_registry= &thread_registry; - p_user_map= &user_map; - - /* Initialize instance map. */ - - if (instance_map.init()) - { - log_error("Manager: can not initialize instance list: out of memory."); - return 1; - } - - /* Initialize user db. */ - - if (init_user_map(&user_map)) - return 1; /* logging has been already done. */ - - /* Write Instance Manager pid file. */ - - if (create_pid_file(Options::Main::pid_file_name, manager_pid)) - return 1; /* necessary logging has been already done. */ - - log_info("Manager: pid file (%s) created.", - (const char *) Options::Main::pid_file_name); - - /* - Initialize signals and alarm-infrastructure. - - NOTE: To work nicely with LinuxThreads, the signal thread is the first - thread in the process. - - NOTE: After init_thr_alarm() call it's possible to call thr_alarm() - (from different threads), that results in sending ALARM signal to the - alarm thread (which can be the main thread). That signal can interrupt - blocking calls. In other words, a blocking call can be interrupted in - the main thread after init_thr_alarm(). - */ - - sigset_t mask; - set_signals(&mask); - - /* - Create the guardian thread. The newly started thread will block until - we actually load instances. - - NOTE: Guardian should be shutdown first. Only then all other threads - can be stopped. This should be done in this order because the guardian - is responsible for shutting down all the guarded instances, and this - is a long operation. - - NOTE: Guardian uses thr_alarm() when detects the current state of an - instance (is_running()), but this does not interfere with - flush_instances() call later in the code, because until - flush_instances() completes in the main thread, Guardian thread is not - permitted to process instances. And before flush_instances() has - completed, there are no instances to guard. - */ - - if (guardian.start(Thread::DETACHED)) - { - log_error("Manager: can not start Guardian thread."); - goto err; - } - - /* Load instances. */ - - if (Manager::flush_instances()) - { - log_error("Manager: can not init instances repository."); - stop_all_threads(); - goto err; - } - - /* Initialize the Listener. */ - - if (listener.start(Thread::DETACHED)) - { - log_error("Manager: can not start Listener thread."); - stop_all_threads(); - goto err; - } - - /* - After the list of guarded instances have been initialized, - Guardian should start them. - */ - - guardian.ping(); - - /* Main loop. */ - - log_info("Manager: started."); - - while (!shutdown_complete) - { - int signo; - int status= 0; - - if ((status= my_sigwait(&mask, &signo)) != 0) - { - log_error("Manager: sigwait() failed"); - stop_all_threads(); - goto err; - } - - /* - The general idea in this loop is the following: - - we are waiting for SIGINT, SIGTERM -- signals that mean we should - shutdown; - - as shutdown signal is caught, we stop Guardian thread (by calling - Guardian::request_shutdown()); - - as Guardian is stopped, it sends SIGTERM to this thread - (by calling Thread_registry::request_shutdown()), so that the - my_sigwait() above returns; - - as we catch the second SIGTERM, we send signals to all threads - registered in Thread_registry (by calling - Thread_registry::deliver_shutdown()) and waiting for threads to stop; - */ - -#ifndef __WIN__ -/* - On some Darwin kernels SIGHUP is delivered along with most - signals. This is why we skip it's processing on these - platforms. For more details and test program see - Bug #14164 IM tests fail on MacOS X (powermacg5) -*/ -#ifdef IGNORE_SIGHUP_SIGQUIT - if (SIGHUP == signo) - continue; -#endif - if (THR_SERVER_ALARM == signo) - process_alarm(signo); - else -#endif - { - log_info("Manager: got shutdown signal."); - - if (!guardian.is_stopped()) - { - guardian.request_shutdown(); - } - else - { - thread_registry.deliver_shutdown(); - shutdown_complete= TRUE; - } - } - } - - log_info("Manager: finished."); - -err: - /* delete the pid file */ - my_delete(Options::Main::pid_file_name, MYF(0)); - -#ifndef __WIN__ - /* free alarm structures */ - end_thr_alarm(1); -#endif - - return thread_registry.get_error_status() ? 1 : 0; -} - - -/** - Re-read instance configuration file. - - SYNOPSIS - flush_instances() - - DESCRIPTION - This function will: - - clear the current list of instances. This removes both - running and stopped instances. - - load a new instance configuration from the file. - - pass on the new map to the guardian thread: it will start - all instances that are marked `guarded' and not yet started. - - Note, as the check whether an instance is started is currently - very simple (returns TRUE if there is a MySQL server running - at the given port), this function has some peculiar - side-effects: - * if the port number of a running instance was changed, the - old instance is forgotten, even if it was running. The new - instance will be started at the new port. - * if the configuration was changed in a way that two - instances swapped their port numbers, the guardian thread - will not notice that and simply report that both instances - are configured successfully and running. - - In order to avoid such side effects one should never call - FLUSH INSTANCES without prior stop of all running instances. - - RETURN - 0 On success - ER_OUT_OF_RESOURCES Not enough resources to complete the operation - ER_THERE_IS_ACTIVE_INSTACE If there is an active instance -*/ - -int Manager::flush_instances() -{ - p_instance_map->lock(); - - if (p_instance_map->is_there_active_instance()) - { - p_instance_map->unlock(); - return ER_THERE_IS_ACTIVE_INSTACE; - } - - if (p_instance_map->reset()) - { - p_instance_map->unlock(); - return ER_OUT_OF_RESOURCES; - } - - if (p_instance_map->load()) - { - p_instance_map->unlock(); - - /* Don't init guardian if we failed to load instances. */ - return ER_OUT_OF_RESOURCES; - } - - get_guardian()->init(); - get_guardian()->ping(); - - p_instance_map->unlock(); - - return 0; -} diff --git a/server-tools/instance-manager/manager.h b/server-tools/instance-manager/manager.h deleted file mode 100644 index e6956884603..00000000000 --- a/server-tools/instance-manager/manager.h +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright (C) 2003-2006 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 */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -#include - -class Guardian; -class Instance_map; -class Thread_registry; -class User_map; - -class Manager -{ -public: - static int main(); - - static int flush_instances(); - -public: - /** - These methods return a non-NULL value only for the duration - of main(). - */ - static Instance_map *get_instance_map() { return p_instance_map; } - static Guardian *get_guardian() { return p_guardian; } - static Thread_registry *get_thread_registry() { return p_thread_registry; } - static User_map *get_user_map() { return p_user_map; } - -public: -#ifndef __WIN__ - static bool is_linux_threads() { return linux_threads; } -#endif // __WIN__ - -private: - static void stop_all_threads(); - static bool init_user_map(User_map *user_map); - -private: - static Guardian *p_guardian; - static Instance_map *p_instance_map; - static Thread_registry *p_thread_registry; - static User_map *p_user_map; - -#ifndef __WIN__ - /* - This flag is set if Instance Manager is running on the system using - LinuxThreads. - */ - static bool linux_threads; -#endif // __WIN__ -}; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H diff --git a/server-tools/instance-manager/messages.cc b/server-tools/instance-manager/messages.cc deleted file mode 100644 index 201ebfd62fc..00000000000 --- a/server-tools/instance-manager/messages.cc +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright (C) 2004-2006 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 */ - -#include "messages.h" - -#include -#include - -#include "mysqld_error.h" -#include "mysql_manager_error.h" - - -static const char *mysqld_error_message(unsigned sql_errno) -{ - switch (sql_errno) { - case ER_HANDSHAKE_ERROR: - return "Bad handshake"; - case ER_OUT_OF_RESOURCES: - return "Out of memory; Check if mysqld or some other process" - " uses all available memory. If not you may have to use" - " 'ulimit' to allow mysqld to use more memory or you can" - " add more swap space"; - case ER_ACCESS_DENIED_ERROR: - return "Access denied. Bad username/password pair"; - case ER_NOT_SUPPORTED_AUTH_MODE: - return "Client does not support authentication protocol requested by" - " server; consider upgrading MySQL client"; - case ER_UNKNOWN_COM_ERROR: - return "Unknown command"; - case ER_SYNTAX_ERROR: - return "You have an error in your command syntax. Check the manual that" - " corresponds to your MySQL Instance Manager version for the right" - " syntax to use"; - case ER_BAD_INSTANCE_NAME: - return "Unknown instance name"; - case ER_INSTANCE_IS_NOT_STARTED: - return "Cannot stop instance. Perhaps the instance is not started, or was" - " started manually, so IM cannot find the pidfile."; - case ER_INSTANCE_ALREADY_STARTED: - return "The instance is already started"; - case ER_CANNOT_START_INSTANCE: - return "Cannot start instance. Possible reasons are wrong instance options" - " or resources shortage"; - case ER_OFFSET_ERROR: - return "Cannot read negative number of bytes"; - case ER_STOP_INSTANCE: - return "Cannot stop instance"; - case ER_READ_FILE: - return "Cannot read requested part of the logfile"; - case ER_NO_SUCH_LOG: - return "The instance has no such log enabled"; - case ER_OPEN_LOGFILE: - return "Cannot open log file"; - case ER_GUESS_LOGFILE: - return "Cannot guess the log filename. Try specifying full log name" - " in the instance options"; - case ER_ACCESS_OPTION_FILE: - return "Cannot open the option file to edit. Check permissions"; - case ER_DROP_ACTIVE_INSTANCE: - return "Cannot drop an active instance. You should stop it first"; - case ER_CREATE_EXISTING_INSTANCE: - return "Instance already exists"; - case ER_INSTANCE_MISCONFIGURED: - return "Instance is misconfigured. Cannot start it"; - case ER_MALFORMED_INSTANCE_NAME: - return "Malformed instance name."; - case ER_INSTANCE_IS_ACTIVE: - return "The instance is active. Stop the instance first"; - case ER_THERE_IS_ACTIVE_INSTACE: - return "At least one instance is active. Stop all instances first"; - case ER_INCOMPATIBLE_OPTION: - return "Instance Manager-specific options are prohibited from being used " - "in the configuration of mysqld-compatible instances"; - case ER_CONF_FILE_DOES_NOT_EXIST: - return "Configuration file does not exist"; - default: - DBUG_ASSERT(0); - return 0; - } -} - - -const char *message(unsigned sql_errno) -{ - return mysqld_error_message(sql_errno); -} - - -const char *errno_to_sqlstate(unsigned sql_errno) -{ - return mysql_errno_to_sqlstate(sql_errno); -} diff --git a/server-tools/instance-manager/messages.h b/server-tools/instance-manager/messages.h deleted file mode 100644 index 5d9383093bc..00000000000 --- a/server-tools/instance-manager/messages.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (C) 2004-2006 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 */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H - -const char *message(unsigned sql_errno); - -const char *errno_to_sqlstate(unsigned sql_errno); - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H diff --git a/server-tools/instance-manager/mysql_connection.cc b/server-tools/instance-manager/mysql_connection.cc deleted file mode 100644 index 12ea0a3ea5a..00000000000 --- a/server-tools/instance-manager/mysql_connection.cc +++ /dev/null @@ -1,376 +0,0 @@ -/* Copyright (C) 2004-2006 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 */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "mysql_connection.h" - -#include -#include -#include -#include -#include -#include - -#include "command.h" -#include "log.h" -#include "messages.h" -#include "mysqld_error.h" -#include "mysql_manager_error.h" -#include "parse.h" -#include "priv.h" -#include "protocol.h" -#include "thread_registry.h" -#include "user_map.h" - - -Mysql_connection::Mysql_connection(Thread_registry *thread_registry_arg, - User_map *user_map_arg, - struct st_vio *vio_arg, ulong - connection_id_arg) - :vio(vio_arg), - connection_id(connection_id_arg), - thread_registry(thread_registry_arg), - user_map(user_map_arg) -{ -} - - -/* - NET subsystem requieres its user to provide my_net_local_init extern - C function (exactly as declared below). my_net_local_init is called by - my_net_init and is supposed to set NET controlling variables. - See also priv.h for variables description. -*/ - -C_MODE_START - -void my_net_local_init(NET *net) -{ - net->max_packet= net_buffer_length; - my_net_set_read_timeout(net, (uint)net_read_timeout); - my_net_set_write_timeout(net, (uint)net_write_timeout); - net->retry_count= net_retry_count; - net->max_packet_size= max_allowed_packet; -} - -C_MODE_END - -/* - Unused stub hook required for linking the client API. -*/ - -C_MODE_START - -void slave_io_thread_detach_vio() -{ -} - -C_MODE_END - - -/* - Every resource, which we can fail to acquire, is allocated in init(). - This function is complementary to cleanup(). -*/ - -bool Mysql_connection::init() -{ - /* Allocate buffers for network I/O */ - if (my_net_init(&net, vio)) - return TRUE; - - net.return_status= &status; - - /* Initialize random number generator */ - { - ulong seed1= (ulong) &rand_st + rand(); - ulong seed2= (ulong) rand() + (ulong) time(0); - randominit(&rand_st, seed1, seed2); - } - - /* Fill scramble - server's random message used for handshake */ - create_random_string(scramble, SCRAMBLE_LENGTH, &rand_st); - - /* We don't support transactions, every query is atomic */ - status= SERVER_STATUS_AUTOCOMMIT; - - thread_registry->register_thread(&thread_info); - - return FALSE; -} - - -void Mysql_connection::cleanup() -{ - net_end(&net); - thread_registry->unregister_thread(&thread_info); -} - - -Mysql_connection::~Mysql_connection() -{ - /* vio_delete closes the socket if necessary */ - vio_delete(vio); -} - - -void Mysql_connection::main() -{ - log_info("Connection %lu: accepted.", (unsigned long) connection_id); - - if (check_connection()) - { - log_info("Connection %lu: failed to authorize the user.", - (unsigned long) connection_id); - - return; - } - - log_info("Connection %lu: the user was authorized successfully.", - (unsigned long) connection_id); - - vio_keepalive(vio, TRUE); - - while (!net.error && net.vio && !thread_registry->is_shutdown()) - { - if (do_command()) - break; - } -} - - -int Mysql_connection::check_connection() -{ - ulong pkt_len=0; // to hold client reply length - - /* buffer for the first packet */ /* packet contains: */ - uchar buff[MAX_VERSION_LENGTH + 1 + // server version, 0-ended - 4 + // connection id - SCRAMBLE_LENGTH + 2 + // scramble (in 2 pieces) - 18]; // server variables: flags, - // charset number, status, - uchar *pos= buff; - ulong server_flags; - - memcpy(pos, mysqlmanager_version.str, mysqlmanager_version.length + 1); - pos+= mysqlmanager_version.length + 1; - - int4store((uchar*) pos, connection_id); - pos+= 4; - - /* - Old clients does not understand long scrambles, but can ignore packet - tail: that's why first part of the scramble is placed here, and second - part at the end of packet (even though we don't support old clients, - we must follow standard packet format.) - */ - memcpy(pos, scramble, SCRAMBLE_LENGTH_323); - pos+= SCRAMBLE_LENGTH_323; - *pos++= '\0'; - - server_flags= CLIENT_LONG_FLAG | CLIENT_PROTOCOL_41 | - CLIENT_SECURE_CONNECTION; - - /* - 18-bytes long section for various flags/variables - - Every flag occupies a bit in first half of ulong; int2store will - gracefully pick up all flags. - */ - int2store(pos, server_flags); - pos+= 2; - *pos++= (char) default_charset_info->number; // global mysys variable - int2store(pos, status); // connection status - pos+= 2; - bzero(pos, 13); // not used now - pos+= 13; - - /* second part of the scramble, null-terminated */ - memcpy(pos, scramble + SCRAMBLE_LENGTH_323, - SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1); - pos+= SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1; - - /* write connection message and read reply */ - enum { MIN_HANDSHAKE_SIZE= 2 }; - if (net_write_command(&net, protocol_version, (uchar*) "", 0, - buff, pos - buff) || - (pkt_len= my_net_read(&net)) == packet_error || - pkt_len < MIN_HANDSHAKE_SIZE) - { - net_send_error(&net, ER_HANDSHAKE_ERROR); - return 1; - } - - client_capabilities= uint2korr(net.read_pos); - if (!(client_capabilities & CLIENT_PROTOCOL_41)) - { - net_send_error_323(&net, ER_NOT_SUPPORTED_AUTH_MODE); - return 1; - } - client_capabilities|= ((ulong) uint2korr(net.read_pos + 2)) << 16; - - pos= net.read_pos + 32; - - /* At least one byte for username and one byte for password */ - if (pos >= net.read_pos + pkt_len + 2) - { - /*TODO add user and password handling in error messages*/ - net_send_error(&net, ER_HANDSHAKE_ERROR); - return 1; - } - - const char *user= (char*) pos; - const char *password= strend(user)+1; - ulong password_len= *password++; - LEX_STRING user_name= { (char *) user, password - user - 2 }; - - if (password_len != SCRAMBLE_LENGTH) - { - net_send_error(&net, ER_ACCESS_DENIED_ERROR); - return 1; - } - if (user_map->authenticate(&user_name, password, scramble)) - { - net_send_error(&net, ER_ACCESS_DENIED_ERROR); - return 1; - } - net_send_ok(&net, connection_id, NULL); - return 0; -} - - -int Mysql_connection::do_command() -{ - char *packet; - ulong packet_length; - - /* We start to count packets from 0 for each new command */ - net.pkt_nr= 0; - - if ((packet_length=my_net_read(&net)) == packet_error) - { - /* Check if we can continue without closing the connection */ - if (net.error != 3) // what is 3 - find out - return 1; - if (thread_registry->is_shutdown()) - return 1; - net_send_error(&net, net.last_errno); - net.error= 0; - return 0; - } - else - { - if (thread_registry->is_shutdown()) - return 1; - packet= (char*) net.read_pos; - enum enum_server_command command= (enum enum_server_command) - (uchar) *packet; - log_info("Connection %lu: received packet (length: %lu; command: %d).", - (unsigned long) connection_id, - (unsigned long) packet_length, - (int) command); - - return dispatch_command(command, packet + 1); - } -} - -int Mysql_connection::dispatch_command(enum enum_server_command command, - const char *packet) -{ - switch (command) { - case COM_QUIT: // client exit - log_info("Connection %lu: received QUIT command.", - (unsigned long) connection_id); - return 1; - - case COM_PING: - log_info("Connection %lu: received PING command.", - (unsigned long) connection_id); - net_send_ok(&net, connection_id, NULL); - return 0; - - case COM_QUERY: - { - log_info("Connection %lu: received QUERY command: '%s'.", - (unsigned long) connection_id, - (const char *) packet); - - if (Command *com= parse_command(packet)) - { - int res= 0; - - log_info("Connection %lu: query parsed successfully.", - (unsigned long) connection_id); - - res= com->execute(&net, connection_id); - delete com; - if (!res) - { - log_info("Connection %lu: query executed successfully", - (unsigned long) connection_id); - } - else - { - log_info("Connection %lu: can not execute query (error: %d).", - (unsigned long) connection_id, - (int) res); - - net_send_error(&net, res); - } - } - else - { - log_error("Connection %lu: can not parse query: out ot resources.", - (unsigned long) connection_id); - - net_send_error(&net,ER_OUT_OF_RESOURCES); - } - - return 0; - } - - default: - log_info("Connection %lu: received unsupported command (%d).", - (unsigned long) connection_id, - (int) command); - - net_send_error(&net, ER_UNKNOWN_COM_ERROR); - return 0; - } - - return 0; /* Just to make compiler happy. */ -} - - -void Mysql_connection::run() -{ - if (init()) - log_error("Connection %lu: can not init handler.", - (unsigned long) connection_id); - else - { - main(); - cleanup(); - } - - delete this; -} - -/* - vim: fdm=marker -*/ diff --git a/server-tools/instance-manager/mysql_connection.h b/server-tools/instance-manager/mysql_connection.h deleted file mode 100644 index 56bbf76e146..00000000000 --- a/server-tools/instance-manager/mysql_connection.h +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright (C) 2004-2006 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 */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H - -#include "thread_registry.h" -#include - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -struct st_vio; -class User_map; - -/* - MySQL connection - handle one connection with mysql command line client - See also comments in mysqlmanager.cc to picture general Instance Manager - architecture. - We use conventional technique to work with classes without exceptions: - class acquires all vital resource in init(); Thus if init() succeed, - a user must call cleanup(). All other methods are valid only between - init() and cleanup(). -*/ - -class Mysql_connection: public Thread -{ -public: - Mysql_connection(Thread_registry *thread_registry_arg, - User_map *user_map_arg, - struct st_vio *vio_arg, - ulong connection_id_arg); - virtual ~Mysql_connection(); - -protected: - virtual void run(); - -private: - struct st_vio *vio; - ulong connection_id; - Thread_info thread_info; - Thread_registry *thread_registry; - User_map *user_map; - NET net; - struct rand_struct rand_st; - char scramble[SCRAMBLE_LENGTH + 1]; - uint status; - ulong client_capabilities; -private: - /* The main loop implementation triad */ - bool init(); - void main(); - void cleanup(); - - /* Names are conventionally the same as in mysqld */ - int check_connection(); - int do_command(); - int dispatch_command(enum enum_server_command command, const char *text); -}; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H diff --git a/server-tools/instance-manager/mysql_manager_error.h b/server-tools/instance-manager/mysql_manager_error.h deleted file mode 100644 index e50e5d24f6d..00000000000 --- a/server-tools/instance-manager/mysql_manager_error.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H -/* Copyright (C) 2004 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 */ - -/* Definefile for instance manager error messagenumbers */ - -#define ER_BAD_INSTANCE_NAME 3000 -#define ER_INSTANCE_IS_NOT_STARTED 3001 -#define ER_INSTANCE_ALREADY_STARTED 3002 -#define ER_CANNOT_START_INSTANCE 3003 -#define ER_STOP_INSTANCE 3004 -#define ER_NO_SUCH_LOG 3005 -#define ER_OPEN_LOGFILE 3006 -#define ER_GUESS_LOGFILE 3007 -#define ER_ACCESS_OPTION_FILE 3008 -#define ER_OFFSET_ERROR 3009 -#define ER_READ_FILE 3010 -#define ER_DROP_ACTIVE_INSTANCE 3011 -#define ER_CREATE_EXISTING_INSTANCE 3012 -#define ER_INSTANCE_MISCONFIGURED 3013 -#define ER_MALFORMED_INSTANCE_NAME 3014 -#define ER_INSTANCE_IS_ACTIVE 3015 -#define ER_THERE_IS_ACTIVE_INSTACE 3016 -#define ER_INCOMPATIBLE_OPTION 3017 -#define ER_CONF_FILE_DOES_NOT_EXIST 3018 - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H */ diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc deleted file mode 100644 index 276d1ca3b49..00000000000 --- a/server-tools/instance-manager/mysqlmanager.cc +++ /dev/null @@ -1,232 +0,0 @@ -/* Copyright (C) 2003-2006 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 */ - -#include -#include -#include - -#include - -#ifndef __WIN__ -#include -#include -#endif - -#include "angel.h" -#include "log.h" -#include "manager.h" -#include "options.h" -#include "user_management_commands.h" - -#ifdef __WIN__ -#include "IMService.h" -#endif - - -/* - Instance Manager consists of two processes: the angel process (IM-angel), - and the manager process (IM-main). Responsibilities of IM-angel is to - monitor IM-main, and restart it in case of failure/shutdown. IM-angel is - started only if startup option '--run-as-service' is provided. - - IM-main consists of several subsystems (thread sets): - - - the signal handling thread - - The signal thread handles user signals and propagates them to the - other threads. All other threads are accounted in the signal handler - thread Thread Registry. - - - the listener - - The listener listens to all sockets. There is a listening socket for - each subsystem (TCP/IP, UNIX socket). - - - mysql subsystem - - Instance Manager acts like an ordinary MySQL Server, but with very - restricted command set. Each MySQL client connection is handled in a - separate thread. All MySQL client connections threads constitute - mysql subsystem. -*/ - -static int main_impl(int argc, char *argv[]); - -#ifndef __WIN__ -static struct passwd *check_user(); -static bool switch_user(); -#endif - - -/************************************************************************/ -/** - The entry point. -*************************************************************************/ - -int main(int argc, char *argv[]) -{ - int return_value; - - puts("\n" - "WARNING: This program is deprecated and will be removed in 6.0.\n"); - - /* Initialize. */ - - MY_INIT(argv[0]); - log_init(); - umask(0117); - srand((uint) time(0)); - - /* Main function. */ - - log_info("IM: started."); - - return_value= main_impl(argc, argv); - - log_info("IM: finished."); - - /* Cleanup. */ - - Options::cleanup(); - my_end(0); - - return return_value; -} - - -/************************************************************************/ -/** - Instance Manager main functionality. -*************************************************************************/ - -int main_impl(int argc, char *argv[]) -{ - int rc; - - if ((rc= Options::load(argc, argv))) - return rc; - - if (Options::User_management::cmd) - return Options::User_management::cmd->execute(); - -#ifndef __WIN__ - - if (switch_user()) - return 1; - - return Options::Daemon::run_as_service ? - Angel::main() : - Manager::main(); - -#else - - return Options::Service::stand_alone ? - Manager::main() : - IMService::main(); - -#endif -} - -/************************************************************************** - OS-specific functions implementation. -**************************************************************************/ - -#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__) - -/************************************************************************/ -/** - Change to run as another user if started with --user. -*************************************************************************/ - -static struct passwd *check_user() -{ - const char *user= Options::Daemon::user; - struct passwd *user_info; - uid_t user_id= geteuid(); - - /* Don't bother if we aren't superuser */ - if (user_id) - { - if (user) - { - /* Don't give a warning, if real user is same as given with --user */ - user_info= getpwnam(user); - if ((!user_info || user_id != user_info->pw_uid)) - log_info("One can only use the --user switch if running as root\n"); - } - return NULL; - } - if (!user) - { - log_info("You are running mysqlmanager as root! This might introduce security problems. It is safer to use --user option istead.\n"); - return NULL; - } - if (!strcmp(user, "root")) - return NULL; /* Avoid problem with dynamic libraries */ - if (!(user_info= getpwnam(user))) - { - /* Allow a numeric uid to be used */ - const char *pos; - for (pos= user; my_isdigit(default_charset_info, *pos); pos++) - {} - if (*pos) /* Not numeric id */ - goto err; - if (!(user_info= getpwuid(atoi(user)))) - goto err; - else - return user_info; - } - else - return user_info; - -err: - log_error("Can not start under user '%s'.", - (const char *) user); - return NULL; -} - - -/************************************************************************/ -/** - Switch user. -*************************************************************************/ - -static bool switch_user() -{ - struct passwd *user_info= check_user(); - - if (!user_info) - return FALSE; - -#ifdef HAVE_INITGROUPS - initgroups(Options::Daemon::user, user_info->pw_gid); -#endif - - if (setgid(user_info->pw_gid) == -1) - { - log_error("setgid() failed"); - return TRUE; - } - - if (setuid(user_info->pw_uid) == -1) - { - log_error("setuid() failed"); - return TRUE; - } - - return FALSE; -} - -#endif diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc deleted file mode 100644 index ebca593bb03..00000000000 --- a/server-tools/instance-manager/options.cc +++ /dev/null @@ -1,558 +0,0 @@ -/* Copyright (C) 2003-2006 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 */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "options.h" - -#include -#include -#include -#include - -#include "exit_codes.h" -#include "log.h" -#include "portability.h" -#include "priv.h" -#include "user_management_commands.h" - -#define QUOTE2(x) #x -#define QUOTE(x) QUOTE2(x) - -#ifdef __WIN__ - -/* Define holders for default values. */ - -static char win_dflt_config_file_name[FN_REFLEN]; -static char win_dflt_password_file_name[FN_REFLEN]; -static char win_dflt_pid_file_name[FN_REFLEN]; - -static char win_dflt_mysqld_path[FN_REFLEN]; - -/* Define and initialize Windows-specific options. */ - -my_bool Options::Service::install_as_service; -my_bool Options::Service::remove_service; -my_bool Options::Service::stand_alone; - -const char *Options::Main::config_file= win_dflt_config_file_name; -const char *Options::Main::password_file_name= win_dflt_password_file_name; -const char *Options::Main::pid_file_name= win_dflt_pid_file_name; - -const char *Options::Main::default_mysqld_path= win_dflt_mysqld_path; - -static int setup_windows_defaults(); - -#else /* UNIX */ - -/* Define and initialize UNIX-specific options. */ - -my_bool Options::Daemon::run_as_service= FALSE; -const char *Options::Daemon::log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME); -const char *Options::Daemon::user= NULL; /* No default value */ -const char *Options::Daemon::angel_pid_file_name= NULL; - -const char *Options::Main::config_file= QUOTE(DEFAULT_CONFIG_FILE); -const char * -Options::Main::password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME); -const char *Options::Main::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME); -const char *Options::Main::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME); - -const char *Options::Main::default_mysqld_path= QUOTE(DEFAULT_MYSQLD_PATH); - -#endif - -/* Remember if the config file was forced. */ - -bool Options::Main::is_forced_default_file= FALSE; - -/* Define and initialize common options. */ - -const char *Options::Main::bind_address= NULL; /* No default value */ -uint Options::Main::monitoring_interval= DEFAULT_MONITORING_INTERVAL; -uint Options::Main::port_number= DEFAULT_PORT; -my_bool Options::Main::mysqld_safe_compatible= FALSE; -const char **Options::default_directories= NULL; - -/* Options::User_management */ - -char *Options::User_management::user_name= NULL; -char *Options::User_management::password= NULL; - -User_management_cmd *Options::User_management::cmd= NULL; - -/* Private members. */ - -char **Options::saved_argv= NULL; - -#ifndef DBUG_OFF -const char *Options::Debug::config_str= "d:t:i:O,im.trace"; -#endif - -static const char * const ANGEL_PID_FILE_SUFFIX= ".angel.pid"; -static const int ANGEL_PID_FILE_SUFFIX_LEN= (uint) strlen(ANGEL_PID_FILE_SUFFIX); - -/* - List of options, accepted by the instance manager. - List must be closed with empty option. -*/ - -enum options { - OPT_USERNAME= 'u', - OPT_PASSWORD= 'p', - OPT_LOG= 256, - OPT_PID_FILE, - OPT_SOCKET, - OPT_PASSWORD_FILE, - OPT_MYSQLD_PATH, -#ifdef __WIN__ - OPT_INSTALL_SERVICE, - OPT_REMOVE_SERVICE, - OPT_STAND_ALONE, -#else - OPT_RUN_AS_SERVICE, - OPT_USER, - OPT_ANGEL_PID_FILE, -#endif - OPT_MONITORING_INTERVAL, - OPT_PORT, - OPT_WAIT_TIMEOUT, - OPT_BIND_ADDRESS, - OPT_PRINT_PASSWORD_LINE, - OPT_ADD_USER, - OPT_DROP_USER, - OPT_EDIT_USER, - OPT_CLEAN_PASSWORD_FILE, - OPT_CHECK_PASSWORD_FILE, - OPT_LIST_USERS, - OPT_MYSQLD_SAFE_COMPATIBLE -}; - -static struct my_option my_long_options[] = -{ - { "help", '?', "Display this help and exit.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - - { "add-user", OPT_ADD_USER, - "Add a user to the password file", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - -#ifndef __WIN__ - { "angel-pid-file", OPT_ANGEL_PID_FILE, "Pid file for angel process.", - (uchar* *) &Options::Daemon::angel_pid_file_name, - (uchar* *) &Options::Daemon::angel_pid_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, -#endif - - { "bind-address", OPT_BIND_ADDRESS, "Bind address to use for connection.", - (uchar* *) &Options::Main::bind_address, - (uchar* *) &Options::Main::bind_address, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "check-password-file", OPT_CHECK_PASSWORD_FILE, - "Check the password file for consistency", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - - { "clean-password-file", OPT_CLEAN_PASSWORD_FILE, - "Clean the password file", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - -#ifndef DBUG_OFF - {"debug", '#', "Debug log.", - (uchar* *) &Options::Debug::config_str, - (uchar* *) &Options::Debug::config_str, - 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, -#endif - - { "default-mysqld-path", OPT_MYSQLD_PATH, "Where to look for MySQL" - " Server binary.", - (uchar* *) &Options::Main::default_mysqld_path, - (uchar* *) &Options::Main::default_mysqld_path, - 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0 }, - - { "drop-user", OPT_DROP_USER, - "Drop existing user from the password file", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - - { "edit-user", OPT_EDIT_USER, - "Edit existing user in the password file", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - -#ifdef __WIN__ - { "install", OPT_INSTALL_SERVICE, "Install as system service.", - (uchar* *) &Options::Service::install_as_service, - (uchar* *) &Options::Service::install_as_service, - 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 }, -#endif - - { "list-users", OPT_LIST_USERS, - "Print out a list of registered users", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - -#ifndef __WIN__ - { "log", OPT_LOG, "Path to log file. Used only with --run-as-service.", - (uchar* *) &Options::Daemon::log_file_name, - (uchar* *) &Options::Daemon::log_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, -#endif - - { "monitoring-interval", OPT_MONITORING_INTERVAL, "Interval to monitor" - " instances in seconds.", - (uchar* *) &Options::Main::monitoring_interval, - (uchar* *) &Options::Main::monitoring_interval, - 0, GET_UINT, REQUIRED_ARG, DEFAULT_MONITORING_INTERVAL, - 0, 0, 0, 0, 0 }, - - { "mysqld-safe-compatible", OPT_MYSQLD_SAFE_COMPATIBLE, - "Start Instance Manager in mysqld_safe compatible manner", - (uchar* *) &Options::Main::mysqld_safe_compatible, - (uchar* *) &Options::Main::mysqld_safe_compatible, - 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 }, - - { "print-password-line", OPT_PRINT_PASSWORD_LINE, - "Print out a user entry as a line for the password file and exit.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - - { "password", OPT_PASSWORD, "Password to update the password file", - (uchar* *) &Options::User_management::password, - (uchar* *) &Options::User_management::password, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "password-file", OPT_PASSWORD_FILE, - "Look for Instance Manager users and passwords here.", - (uchar* *) &Options::Main::password_file_name, - (uchar* *) &Options::Main::password_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "pid-file", OPT_PID_FILE, "Pid file to use.", - (uchar* *) &Options::Main::pid_file_name, - (uchar* *) &Options::Main::pid_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "port", OPT_PORT, "Port number to use for connections", - (uchar* *) &Options::Main::port_number, - (uchar* *) &Options::Main::port_number, - 0, GET_UINT, REQUIRED_ARG, DEFAULT_PORT, 0, 0, 0, 0, 0 }, - -#ifdef __WIN__ - { "remove", OPT_REMOVE_SERVICE, "Remove system service.", - (uchar* *) &Options::Service::remove_service, - (uchar* *) &Options::Service::remove_service, - 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0}, -#else - { "run-as-service", OPT_RUN_AS_SERVICE, - "Daemonize and start angel process.", - (uchar* *) &Options::Daemon::run_as_service, - 0, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 }, -#endif - -#ifndef __WIN__ - { "socket", OPT_SOCKET, "Socket file to use for connection.", - (uchar* *) &Options::Main::socket_file_name, - (uchar* *) &Options::Main::socket_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, -#endif - -#ifdef __WIN__ - { "standalone", OPT_STAND_ALONE, "Run the application in stand alone mode.", - (uchar* *) &Options::Service::stand_alone, - (uchar* *) &Options::Service::stand_alone, - 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0}, -#else - { "user", OPT_USER, "Username to start mysqlmanager", - (uchar* *) &Options::Daemon::user, - (uchar* *) &Options::Daemon::user, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, -#endif - - { "username", OPT_USERNAME, - "Username to update the password file", - (uchar* *) &Options::User_management::user_name, - (uchar* *) &Options::User_management::user_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "version", 'V', "Output version information and exit.", 0, 0, 0, - GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - - { "wait-timeout", OPT_WAIT_TIMEOUT, "The number of seconds IM waits " - "for activity on a connection before closing it.", - (uchar* *) &net_read_timeout, - (uchar* *) &net_read_timeout, - 0, GET_ULONG, REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0 }, - - { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 } -}; - -static void version() -{ - printf("%s Ver %s for %s on %s\n", my_progname, - (const char *) mysqlmanager_version.str, - SYSTEM_TYPE, MACHINE_TYPE); -} - - -static const char *default_groups[]= { "manager", 0 }; - - -static void usage() -{ - version(); - - printf("Copyright (C) 2003, 2004 MySQL AB\n" - "This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n" - "and you are welcome to modify and redistribute it under the GPL license\n"); - printf("Usage: %s [OPTIONS] \n", my_progname); - - my_print_help(my_long_options); - printf("\nThe following options may be given as the first argument:\n" - "--print-defaults Print the program argument list and exit\n" - "--defaults-file=# Only read manager configuration and instance\n" - " setings from the given file #. The same file\n" - " will be used to modify configuration of instances\n" - " with SET commands.\n"); - my_print_variables(my_long_options); -} - - -C_MODE_START - -static my_bool -get_one_option(int optid, - const struct my_option *opt __attribute__((unused)), - char *argument) -{ - switch(optid) { - case 'V': - version(); - exit(0); - case OPT_PRINT_PASSWORD_LINE: - case OPT_ADD_USER: - case OPT_DROP_USER: - case OPT_EDIT_USER: - case OPT_CLEAN_PASSWORD_FILE: - case OPT_CHECK_PASSWORD_FILE: - case OPT_LIST_USERS: - if (Options::User_management::cmd) - { - fprintf(stderr, "Error: only one password-management command " - "can be specified at a time.\n"); - exit(ERR_INVALID_USAGE); - } - - switch (optid) { - case OPT_PRINT_PASSWORD_LINE: - Options::User_management::cmd= new Print_password_line_cmd(); - break; - case OPT_ADD_USER: - Options::User_management::cmd= new Add_user_cmd(); - break; - case OPT_DROP_USER: - Options::User_management::cmd= new Drop_user_cmd(); - break; - case OPT_EDIT_USER: - Options::User_management::cmd= new Edit_user_cmd(); - break; - case OPT_CLEAN_PASSWORD_FILE: - Options::User_management::cmd= new Clean_db_cmd(); - break; - case OPT_CHECK_PASSWORD_FILE: - Options::User_management::cmd= new Check_db_cmd(); - break; - case OPT_LIST_USERS: - Options::User_management::cmd= new List_users_cmd(); - break; - } - - break; - case '?': - usage(); - exit(0); - case '#': -#ifndef DBUG_OFF - DBUG_SET(argument ? argument : Options::Debug::config_str); - DBUG_SET_INITIAL(argument ? argument : Options::Debug::config_str); -#endif - break; - } - return 0; -} - -C_MODE_END - - -/* - - Process argv of original program: get tid of --defaults-extra-file - and print a message if met there. - - call load_defaults to load configuration file section and save the pointer - for free_defaults. - - call handle_options to assign defaults and command-line arguments - to the class members. - if either of these function fail, return the error code. -*/ - -int Options::load(int argc, char **argv) -{ - if (argc >= 2) - { - if (is_prefix(argv[1], "--defaults-file=")) - { - Main::config_file= strchr(argv[1], '=') + 1; - Main::is_forced_default_file= TRUE; - } - if (is_prefix(argv[1], "--defaults-extra-file=") || - is_prefix(argv[1], "--no-defaults")) - { - /* the log is not enabled yet */ - fprintf(stderr, "The --defaults-extra-file and --no-defaults options" - " are not supported by\n" - "Instance Manager. Program aborted.\n"); - return ERR_INVALID_USAGE; - } - } - -#ifdef __WIN__ - if (setup_windows_defaults()) - { - fprintf(stderr, "Internal error: could not setup default values.\n"); - return ERR_OUT_OF_MEMORY; - } -#endif - - /* load_defaults will reset saved_argv with a new allocated list */ - saved_argv= argv; - - /* config-file options are prepended to command-line ones */ - - log_info("Loading config file '%s'...", - (const char *) Main::config_file); - - my_load_defaults(Main::config_file, default_groups, &argc, - &saved_argv, &default_directories); - - if ((handle_options(&argc, &saved_argv, my_long_options, get_one_option))) - return ERR_INVALID_USAGE; - - if (!User_management::cmd && - (User_management::user_name || User_management::password)) - { - fprintf(stderr, - "--username and/or --password options have been specified, " - "but no password-management command has been given.\n"); - return ERR_INVALID_USAGE; - } - -#ifndef __WIN__ - if (Options::Daemon::run_as_service) - { - if (Options::Daemon::angel_pid_file_name == NULL) - { - /* - Calculate angel pid file on the IM pid file basis: replace the - extension (everything after the last dot) of the pid file basename to - '.angel.pid'. - */ - - char *local_angel_pid_file_name; - char *base_name_ptr; - char *ext_ptr; - - local_angel_pid_file_name= - (char *) malloc(strlen(Options::Main::pid_file_name) + - ANGEL_PID_FILE_SUFFIX_LEN); - - strcpy(local_angel_pid_file_name, Options::Main::pid_file_name); - - base_name_ptr= strrchr(local_angel_pid_file_name, '/'); - - if (!base_name_ptr) - base_name_ptr= local_angel_pid_file_name + 1; - - ext_ptr= strrchr(base_name_ptr, '.'); - if (ext_ptr) - *ext_ptr= 0; - - strcat(local_angel_pid_file_name, ANGEL_PID_FILE_SUFFIX); - - Options::Daemon::angel_pid_file_name= local_angel_pid_file_name; - } - else - { - Options::Daemon::angel_pid_file_name= - strdup(Options::Daemon::angel_pid_file_name); - } - } -#endif - - return 0; -} - -void Options::cleanup() -{ - if (saved_argv) - free_defaults(saved_argv); - - delete User_management::cmd; - -#ifndef __WIN__ - if (Options::Daemon::run_as_service) - free((void *) Options::Daemon::angel_pid_file_name); -#endif -} - -#ifdef __WIN__ - -static int setup_windows_defaults() -{ - char module_full_name[FN_REFLEN]; - char dir_name[FN_REFLEN]; - char base_name[FN_REFLEN]; - char im_name[FN_REFLEN]; - char *base_name_ptr; - char *ptr; - - /* Determine dirname and basename. */ - - if (!GetModuleFileName(NULL, module_full_name, sizeof (module_full_name)) || - !GetFullPathName(module_full_name, sizeof (dir_name), dir_name, - &base_name_ptr)) - { - return 1; - } - - strmake(base_name, base_name_ptr, FN_REFLEN); - *base_name_ptr= 0; - - strmake(im_name, base_name, FN_REFLEN); - ptr= strrchr(im_name, '.'); - - if (!ptr) - return 1; - - *ptr= 0; - - /* Initialize the defaults. */ - - strxmov(win_dflt_config_file_name, dir_name, DFLT_CONFIG_FILE_NAME, NullS); - strxmov(win_dflt_mysqld_path, dir_name, DFLT_MYSQLD_PATH, NullS); - strxmov(win_dflt_password_file_name, dir_name, im_name, DFLT_PASSWD_FILE_EXT, - NullS); - strxmov(win_dflt_pid_file_name, dir_name, im_name, DFLT_PID_FILE_EXT, NullS); - - return 0; -} - -#endif diff --git a/server-tools/instance-manager/options.h b/server-tools/instance-manager/options.h deleted file mode 100644 index 5d4df51faae..00000000000 --- a/server-tools/instance-manager/options.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (C) 2003-2006 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 */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H - -/* - Options - all possible command-line options for the Instance Manager grouped - in one struct. -*/ - -#include - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -class User_management_cmd; - -struct Options -{ - /* - NOTE: handle_options() expects value of my_bool type for GET_BOOL - accessor (i.e. bool must not be used). - */ - - struct User_management - { - static User_management_cmd *cmd; - - static char *user_name; - static char *password; - }; - - struct Main - { - /* this is not an option parsed by handle_options(). */ - static bool is_forced_default_file; - - static const char *pid_file_name; -#ifndef __WIN__ - static const char *socket_file_name; -#endif - static const char *password_file_name; - static const char *default_mysqld_path; - static uint monitoring_interval; - static uint port_number; - static const char *bind_address; - static const char *config_file; - static my_bool mysqld_safe_compatible; - }; - -#ifndef DBUG_OFF - struct Debug - { - static const char *config_str; - }; -#endif - -#ifndef __WIN__ - - struct Daemon - { - static my_bool run_as_service; - static const char *log_file_name; - static const char *user; - static const char *angel_pid_file_name; - }; - -#else - - struct Service - { - static my_bool install_as_service; - static my_bool remove_service; - static my_bool stand_alone; - }; - -#endif - -public: - /* Array of paths to be passed to my_search_option_files() later */ - static const char **default_directories; - - static int load(int argc, char **argv); - static void cleanup(); - -private: - Options(); /* Deny instantiation of this class. */ - -private: - /* argv pointer returned by load_defaults() to be used by free_defaults() */ - static char **saved_argv; -}; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H diff --git a/server-tools/instance-manager/parse.cc b/server-tools/instance-manager/parse.cc deleted file mode 100644 index cd20e3bc7ab..00000000000 --- a/server-tools/instance-manager/parse.cc +++ /dev/null @@ -1,509 +0,0 @@ -/* Copyright (C) 2004 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 */ - -#include "parse.h" -#include "commands.h" - - -enum Token -{ - TOK_CREATE= 0, - TOK_DROP, - TOK_ERROR, /* Encodes the "ERROR" word, it doesn't indicate error. */ - TOK_FILES, - TOK_FLUSH, - TOK_GENERAL, - TOK_INSTANCE, - TOK_INSTANCES, - TOK_LOG, - TOK_OPTIONS, - TOK_SET, - TOK_SLOW, - TOK_START, - TOK_STATUS, - TOK_STOP, - TOK_SHOW, - TOK_UNSET, - TOK_NOT_FOUND, // must be after all tokens - TOK_END -}; - - -struct tokens_st -{ - uint length; - const char *tok_name; -}; - - -static struct tokens_st tokens[]= { - {6, "CREATE"}, - {4, "DROP"}, - {5, "ERROR"}, - {5, "FILES"}, - {5, "FLUSH"}, - {7, "GENERAL"}, - {8, "INSTANCE"}, - {9, "INSTANCES"}, - {3, "LOG"}, - {7, "OPTIONS"}, - {3, "SET"}, - {4, "SLOW"}, - {5, "START"}, - {6, "STATUS"}, - {4, "STOP"}, - {4, "SHOW"}, - {5, "UNSET"} -}; - -/************************************************************************/ - -Named_value_arr::Named_value_arr() : - initialized(FALSE) -{ -} - - -bool Named_value_arr::init() -{ - if (my_init_dynamic_array(&arr, sizeof(Named_value), 0, 32)) - return TRUE; - - initialized= TRUE; - - return FALSE; -} - - -Named_value_arr::~Named_value_arr() -{ - if (!initialized) - return; - - for (int i= 0; i < get_size(); ++i) - get_element(i).free(); - - delete_dynamic(&arr); -} - -/************************************************************************/ - -/* - Returns token no if word corresponds to some token, otherwise returns - TOK_NOT_FOUND -*/ - -inline Token find_token(const char *word, size_t word_len) -{ - int i= 0; - do - { - if (my_strnncoll(default_charset_info, (const uchar *) tokens[i].tok_name, - tokens[i].length, (const uchar *) word, word_len) == 0) - break; - } - while (++i < TOK_NOT_FOUND); - return (Token) i; -} - - -Token get_token(const char **text, size_t *word_len) -{ - get_word(text, word_len); - if (*word_len) - return find_token(*text, *word_len); - return TOK_END; -} - - -Token shift_token(const char **text, size_t *word_len) -{ - Token save= get_token(text, word_len); - (*text)+= *word_len; - return save; -} - - -int get_text_id(const char **text, LEX_STRING *token) -{ - get_word(text, &token->length); - if (token->length == 0) - return 1; - token->str= (char *) *text; - return 0; -} - - -static bool parse_long(const LEX_STRING *token, long *value) -{ - int err_code; - char *end_ptr= token->str + token->length; - - *value= (long)my_strtoll10(token->str, &end_ptr, &err_code); - - return err_code != 0; -} - - -bool parse_option_value(const char *text, size_t *text_len, char **value) -{ - char beginning_quote; - const char *text_start_ptr; - char *v; - bool escape_mode= FALSE; - - if (!*text || (*text != '\'' && *text != '"')) - return TRUE; /* syntax error: string expected. */ - - beginning_quote= *text; - - ++text; /* skip the beginning quote. */ - - text_start_ptr= text; - - if (!(v= Named_value::alloc_str(text))) - return TRUE; - - *value= v; - - while (TRUE) - { - if (!*text) - { - Named_value::free_str(value); - return TRUE; /* syntax error: missing terminating ' character. */ - } - - if (*text == '\n' || *text == '\r') - { - Named_value::free_str(value); - return TRUE; /* syntax error: option value should be a single line. */ - } - - if (!escape_mode && *text == beginning_quote) - break; - - if (escape_mode) - { - switch (*text) - { - case 'b': /* \b -- backspace */ - if (v > *value) - --v; - break; - - case 't': /* \t -- tab */ - *v= '\t'; - ++v; - break; - - case 'n': /* \n -- newline */ - *v= '\n'; - ++v; - break; - - case 'r': /* \r -- carriage return */ - *v= '\r'; - ++v; - break; - - case '\\': /* \\ -- back slash */ - *v= '\\'; - ++v; - break; - - case 's': /* \s -- space */ - *v= ' '; - ++v; - break; - - default: /* Unknown escape sequence. Treat as error. */ - Named_value::free_str(value); - return TRUE; - } - - escape_mode= FALSE; - } - else - { - if (*text == '\\') - { - escape_mode= TRUE; - } - else - { - *v= *text; - ++v; - } - } - - ++text; - } - - *v= 0; - - /* "2" below stands for beginning and ending quotes. */ - *text_len= text - text_start_ptr + 2; - - return FALSE; -} - - -void skip_spaces(const char **text) -{ - while (**text && my_isspace(default_charset_info, **text)) - ++(*text); -} - - -Command *parse_command(const char *text) -{ - size_t word_len; - LEX_STRING instance_name; - Command *command= 0; - - Token tok1= shift_token(&text, &word_len); - - switch (tok1) { - case TOK_START: // fallthrough - case TOK_STOP: - case TOK_CREATE: - case TOK_DROP: - if (shift_token(&text, &word_len) != TOK_INSTANCE) - goto syntax_error; - get_word(&text, &word_len); - if (word_len == 0) - goto syntax_error; - instance_name.str= (char *) text; - instance_name.length= word_len; - text+= word_len; - - if (tok1 == TOK_CREATE) - { - Create_instance *cmd= new Create_instance(&instance_name); - - if (!cmd) - return NULL; /* Report ER_OUT_OF_RESOURCES. */ - - if (cmd->init(&text)) - { - delete cmd; - goto syntax_error; - } - - command= cmd; - } - else - { - /* it should be the end of command */ - get_word(&text, &word_len, NONSPACE); - if (word_len) - goto syntax_error; - } - - switch (tok1) { - case TOK_START: - command= new Start_instance(&instance_name); - break; - case TOK_STOP: - command= new Stop_instance(&instance_name); - break; - case TOK_CREATE: - ; /* command already initialized. */ - break; - case TOK_DROP: - command= new Drop_instance(&instance_name); - break; - default: /* this is impossible, but nevertheless... */ - DBUG_ASSERT(0); - } - break; - case TOK_FLUSH: - if (shift_token(&text, &word_len) != TOK_INSTANCES) - goto syntax_error; - - get_word(&text, &word_len, NONSPACE); - if (word_len) - goto syntax_error; - - command= new Flush_instances(); - break; - case TOK_UNSET: - case TOK_SET: - { - Abstract_option_cmd *cmd; - - if (tok1 == TOK_SET) - cmd= new Set_option(); - else - cmd= new Unset_option(); - - if (!cmd) - return NULL; /* Report ER_OUT_OF_RESOURCES. */ - - if (cmd->init(&text)) - { - delete cmd; - goto syntax_error; - } - - command= cmd; - - break; - } - case TOK_SHOW: - switch (shift_token(&text, &word_len)) { - case TOK_INSTANCES: - get_word(&text, &word_len, NONSPACE); - if (word_len) - goto syntax_error; - command= new Show_instances(); - break; - case TOK_INSTANCE: - switch (Token tok2= shift_token(&text, &word_len)) { - case TOK_OPTIONS: - case TOK_STATUS: - if (get_text_id(&text, &instance_name)) - goto syntax_error; - text+= instance_name.length; - /* check that this is the end of the command */ - get_word(&text, &word_len, NONSPACE); - if (word_len) - goto syntax_error; - if (tok2 == TOK_STATUS) - command= new Show_instance_status(&instance_name); - else - command= new Show_instance_options(&instance_name); - break; - default: - goto syntax_error; - } - break; - default: - instance_name.str= (char *) text - word_len; - instance_name.length= word_len; - if (instance_name.length) - { - Log_type log_type; - - long log_size; - LEX_STRING log_size_str; - - long log_offset= 0; - LEX_STRING log_offset_str= { NULL, 0 }; - - switch (shift_token(&text, &word_len)) { - case TOK_LOG: - switch (Token tok3= shift_token(&text, &word_len)) { - case TOK_FILES: - get_word(&text, &word_len, NONSPACE); - /* check that this is the end of the command */ - if (word_len) - goto syntax_error; - command= new Show_instance_log_files(&instance_name); - break; - case TOK_ERROR: - case TOK_GENERAL: - case TOK_SLOW: - /* define a log type */ - switch (tok3) { - case TOK_ERROR: - log_type= IM_LOG_ERROR; - break; - case TOK_GENERAL: - log_type= IM_LOG_GENERAL; - break; - case TOK_SLOW: - log_type= IM_LOG_SLOW; - break; - default: - goto syntax_error; - } - /* get the size of the log we want to retrieve */ - if (get_text_id(&text, &log_size_str)) - goto syntax_error; - text+= log_size_str.length; - - /* this parameter is required */ - if (!log_size_str.length) - goto syntax_error; - - /* the next token should be comma, or nothing */ - get_word(&text, &word_len); - switch (*text) { - case ',': - text++; /* swallow the comma */ - /* read the next word */ - get_word(&text, &word_len); - if (!word_len) - goto syntax_error; - log_offset_str.str= (char *) text; - log_offset_str.length= word_len; - text+= word_len; - get_word(&text, &word_len, NONSPACE); - /* check that this is the end of the command */ - if (word_len) - goto syntax_error; - break; - case '\0': - break; /* this is ok */ - default: - goto syntax_error; - } - - /* Parse size parameter. */ - - if (parse_long(&log_size_str, &log_size)) - goto syntax_error; - - if (log_size <= 0) - goto syntax_error; - - /* Parse offset parameter (if specified). */ - - if (log_offset_str.length) - { - if (parse_long(&log_offset_str, &log_offset)) - goto syntax_error; - - if (log_offset <= 0) - goto syntax_error; - } - - command= new Show_instance_log(&instance_name, - log_type, log_size, log_offset); - break; - default: - goto syntax_error; - } - break; - default: - goto syntax_error; - } - } - else - goto syntax_error; - break; - } - break; - default: -syntax_error: - command= new Syntax_error(); - } - - DBUG_ASSERT(command); - - return command; -} diff --git a/server-tools/instance-manager/parse.h b/server-tools/instance-manager/parse.h deleted file mode 100644 index 9c50ace5948..00000000000 --- a/server-tools/instance-manager/parse.h +++ /dev/null @@ -1,212 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H -/* Copyright (C) 2004 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 */ - -#include -#include -#include - -class Command; - -enum Log_type -{ - IM_LOG_ERROR= 0, - IM_LOG_GENERAL, - IM_LOG_SLOW -}; - -Command *parse_command(const char *text); - -bool parse_option_value(const char *text, size_t *text_len, char **value); - -void skip_spaces(const char **text); - -/* define kinds of the word seek method */ -enum enum_seek_method { ALPHANUM= 1, NONSPACE, OPTION_NAME }; - -/************************************************************************/ - -class Named_value -{ -public: - /* - The purpose of these methods is just to have one method for - allocating/deallocating memory for strings for Named_value. - */ - - static inline char *alloc_str(const LEX_STRING *str); - static inline char *alloc_str(const char *str); - static inline void free_str(char **str); - -public: - inline Named_value(); - inline Named_value(char *name_arg, char *value_arg); - - inline char *get_name(); - inline char *get_value(); - - inline void free(); - -private: - char *name; - char *value; -}; - -inline char *Named_value::alloc_str(const LEX_STRING *str) -{ - return my_strndup(str->str, str->length, MYF(0)); -} - -inline char *Named_value::alloc_str(const char *str) -{ - return my_strdup(str, MYF(0)); -} - -inline void Named_value::free_str(char **str) -{ - my_free(*str, MYF(MY_ALLOW_ZERO_PTR)); - *str= NULL; -} - -inline Named_value::Named_value() - :name(NULL), value(NULL) -{ } - -inline Named_value::Named_value(char *name_arg, char *value_arg) - :name(name_arg), value(value_arg) -{ } - -inline char *Named_value::get_name() -{ - return name; -} - -inline char *Named_value::get_value() -{ - return value; -} - -void Named_value::free() -{ - free_str(&name); - free_str(&value); -} - -/************************************************************************/ - -class Named_value_arr -{ -public: - Named_value_arr(); - ~Named_value_arr(); - - bool init(); - - inline int get_size() const; - inline Named_value get_element(int idx) const; - inline void remove_element(int idx); - inline bool add_element(Named_value *option); - inline bool replace_element(int idx, Named_value *option); - -private: - bool initialized; - DYNAMIC_ARRAY arr; -}; - - -inline int Named_value_arr::get_size() const -{ - return arr.elements; -} - - -inline Named_value Named_value_arr::get_element(int idx) const -{ - DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements); - - Named_value option; - get_dynamic((DYNAMIC_ARRAY *) &arr, (uchar*) &option, idx); - - return option; -} - - -inline void Named_value_arr::remove_element(int idx) -{ - DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements); - - get_element(idx).free(); - - delete_dynamic_element(&arr, idx); -} - - -inline bool Named_value_arr::add_element(Named_value *option) -{ - return insert_dynamic(&arr, (uchar*) option); -} - - -inline bool Named_value_arr::replace_element(int idx, Named_value *option) -{ - DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements); - - get_element(idx).free(); - - return set_dynamic(&arr, (uchar*) option, idx); -} - -/************************************************************************/ - -/* - tries to find next word in the text - if found, returns the beginning and puts word length to word_len argument. - if not found returns pointer to first non-space or to '\0', word_len == 0 -*/ - -inline void get_word(const char **text, size_t *word_len, - enum_seek_method seek_method= ALPHANUM) -{ - const char *word_end; - - /* skip space */ - while (my_isspace(default_charset_info, **text)) - ++(*text); - - word_end= *text; - - switch (seek_method) { - case ALPHANUM: - while (my_isalnum(default_charset_info, *word_end)) - ++word_end; - break; - case NONSPACE: - while (!my_isspace(default_charset_info, *word_end) && - (*word_end != '\0')) - ++word_end; - break; - case OPTION_NAME: - while (my_isalnum(default_charset_info, *word_end) || - *word_end == '-' || - *word_end == '_') - ++word_end; - break; - } - - *word_len= (uint) (word_end - *text); -} - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H */ diff --git a/server-tools/instance-manager/parse_output.cc b/server-tools/instance-manager/parse_output.cc deleted file mode 100644 index 3511589acd6..00000000000 --- a/server-tools/instance-manager/parse_output.cc +++ /dev/null @@ -1,407 +0,0 @@ -/* Copyright (C) 2004 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 */ - -#include "parse_output.h" - -#include -#include -#include - -#include - -#include "parse.h" -#include "portability.h" - -/************************************************************************** - Private module implementation. -**************************************************************************/ - -namespace { /* no-indent */ - -/*************************************************************************/ - -void trim_space(const char **text, uint *word_len) -{ - const char *start= *text; - while (*start != 0 && *start == ' ') - start++; - *text= start; - - int len= strlen(start); - const char *end= start + len - 1; - while (end > start && my_isspace(&my_charset_latin1, *end)) - end--; - *word_len= (end - start)+1; -} - -/*************************************************************************/ - -/** - @brief A facade to the internal workings of optaining the output from an - executed system process. -*/ - -class Mysqld_output_parser -{ -public: - Mysqld_output_parser() - { } - - virtual ~Mysqld_output_parser() - { } - -public: - bool parse(const char *command, - const char *option_name_str, - uint option_name_length, - char *option_value_buf, - size_t option_value_buf_size, - enum_option_type option_type); - -protected: - /** - @brief Run a process and attach stdout- and stdin-pipes to it. - - @param command The path to the process to be executed - - @return Error status. - @retval TRUE An error occurred - @retval FALSE Operation was a success - */ - - virtual bool run_command(const char *command)= 0; - - - /** - @brief Read a sequence of bytes from the executed process' stdout pipe. - - The sequence is terminated by either '\0', LF or CRLF tokens. The - terminating token is excluded from the result. - - @param line_buffer A pointer to a character buffer - @param line_buffer_size The size of the buffer in bytes - - @return Error status. - @retval TRUE An error occured - @retval FALSE Operation was a success - */ - - virtual bool read_line(char *line_buffer, - uint line_buffer_size)= 0; - - - /** - @brief Release any resources needed after a execution and parsing. - */ - - virtual bool cleanup()= 0; -}; - -/*************************************************************************/ - -bool Mysqld_output_parser::parse(const char *command, - const char *option_name_str, - uint option_name_length, - char *option_value_buf, - size_t option_value_buf_size, - enum_option_type option_type) -{ - /* should be enough to store the string from the output */ - const int LINE_BUFFER_SIZE= 512; - char line_buffer[LINE_BUFFER_SIZE]; - - if (run_command(command)) - return TRUE; - - while (true) - { - if (read_line(line_buffer, LINE_BUFFER_SIZE)) - { - cleanup(); - return TRUE; - } - - uint found_word_len= 0; - char *linep= line_buffer; - - line_buffer[sizeof(line_buffer) - 1]= '\0'; /* safety */ - - /* Find the word(s) we are looking for in the line. */ - - linep= strstr(linep, option_name_str); - - if (!linep) - continue; - - linep+= option_name_length; - - switch (option_type) - { - case GET_VALUE: - trim_space((const char**) &linep, &found_word_len); - - if (option_value_buf_size <= found_word_len) - { - cleanup(); - return TRUE; - } - - strmake(option_value_buf, linep, found_word_len); - - break; - - case GET_LINE: - strmake(option_value_buf, linep, option_value_buf_size - 1); - - break; - } - - cleanup(); - - return FALSE; - } -} - -/************************************************************************** - Platform-specific implementation: UNIX. -**************************************************************************/ - -#ifndef __WIN__ - -class Mysqld_output_parser_unix : public Mysqld_output_parser -{ -public: - Mysqld_output_parser_unix() : - m_stdout(NULL) - { } - -protected: - virtual bool run_command(const char *command); - - virtual bool read_line(char *line_buffer, - uint line_buffer_size); - - virtual bool cleanup(); - -private: - FILE *m_stdout; -}; - -bool Mysqld_output_parser_unix::run_command(const char *command) -{ - if (!(m_stdout= popen(command, "r"))) - return TRUE; - - /* - We want fully buffered stream. We also want system to allocate - appropriate buffer. - */ - - setvbuf(m_stdout, NULL, _IOFBF, 0); - - return FALSE; -} - -bool Mysqld_output_parser_unix::read_line(char *line_buffer, - uint line_buffer_size) -{ - char *retbuff = fgets(line_buffer, line_buffer_size, m_stdout); - /* Remove any tailing new line charaters */ - if (line_buffer[line_buffer_size-1] == LF) - line_buffer[line_buffer_size-1]= '\0'; - return (retbuff == NULL); -} - -bool Mysqld_output_parser_unix::cleanup() -{ - if (m_stdout) - pclose(m_stdout); - - return FALSE; -} - -#else /* Windows */ - -/************************************************************************** - Platform-specific implementation: Windows. -**************************************************************************/ - -class Mysqld_output_parser_win : public Mysqld_output_parser -{ -public: - Mysqld_output_parser_win() : - m_internal_buffer(NULL), - m_internal_buffer_offset(0), - m_internal_buffer_size(0) - { } - -protected: - virtual bool run_command(const char *command); - virtual bool read_line(char *line_buffer, - uint line_buffer_size); - virtual bool cleanup(); - -private: - HANDLE m_h_child_stdout_wr; - HANDLE m_h_child_stdout_rd; - uint m_internal_buffer_offset; - uint m_internal_buffer_size; - char *m_internal_buffer; -}; - -bool Mysqld_output_parser_win::run_command(const char *command) -{ - BOOL op_status; - - SECURITY_ATTRIBUTES sa_attr; - sa_attr.nLength= sizeof(SECURITY_ATTRIBUTES); - sa_attr.bInheritHandle= TRUE; - sa_attr.lpSecurityDescriptor= NULL; - - op_status= CreatePipe(&m_h_child_stdout_rd, - &m_h_child_stdout_wr, - &sa_attr, - 0 /* Use system-default buffer size. */); - - if (!op_status) - return TRUE; - - SetHandleInformation(m_h_child_stdout_rd, HANDLE_FLAG_INHERIT, 0); - - STARTUPINFO si_start_info; - ZeroMemory(&si_start_info, sizeof(STARTUPINFO)); - si_start_info.cb= sizeof(STARTUPINFO); - si_start_info.hStdError= m_h_child_stdout_wr; - si_start_info.hStdOutput= m_h_child_stdout_wr; - si_start_info.dwFlags|= STARTF_USESTDHANDLES; - - PROCESS_INFORMATION pi_proc_info; - - op_status= CreateProcess(NULL, /* Application name. */ - (char*)command, /* Command line. */ - NULL, /* Process security attributes. */ - NULL, /* Primary thread security attr.*/ - TRUE, /* Handles are inherited. */ - 0, /* Creation flags. */ - NULL, /* Use parent's environment. */ - NULL, /* Use parent's curr. directory. */ - &si_start_info, /* STARTUPINFO pointer. */ - &pi_proc_info); /* Rec. PROCESS_INFORMATION. */ - - if (!op_status) - { - CloseHandle(m_h_child_stdout_rd); - CloseHandle(m_h_child_stdout_wr); - - return TRUE; - } - - /* Close unnessary handles. */ - - CloseHandle(pi_proc_info.hProcess); - CloseHandle(pi_proc_info.hThread); - - return FALSE; -} - -bool Mysqld_output_parser_win::read_line(char *line_buffer, - uint line_buffer_size) -{ - DWORD dw_read_count= m_internal_buffer_size; - bzero(line_buffer,line_buffer_size); - char *buff_ptr= line_buffer; - char ch; - - while ((unsigned)(buff_ptr - line_buffer) < line_buffer_size) - { - do - { - ReadFile(m_h_child_stdout_rd, &ch, - 1, &dw_read_count, NULL); - } while ((ch == CR || ch == LF) && buff_ptr == line_buffer); - - if (dw_read_count == 0) - return TRUE; - - if (ch == CR || ch == LF) - break; - - *buff_ptr++ = ch; - } - - return FALSE; -} - -bool Mysqld_output_parser_win::cleanup() -{ - /* Close all handles. */ - - CloseHandle(m_h_child_stdout_wr); - CloseHandle(m_h_child_stdout_rd); - - return FALSE; -} -#endif - -/*************************************************************************/ - -} /* End of private module implementation. */ - -/*************************************************************************/ - -/** - @brief Parse output of the given command - - @param command The command to execute. - @param option_name_str Option name. - @param option_name_length Length of the option name. - @param[out] option_value_buf The buffer to store option value. - @param option_value_buf_size Size of the option value buffer. - @param option_type Type of the option: - - GET_LINE if we want to get all the - line after the option name; - - GET_VALUE otherwise. - - Execute the process by running "command". Find the "option name" and - return the next word if "option_type" is GET_VALUE. Return the rest of - the parsed string otherwise. - - @note This function has a separate windows implementation. - - @return The error status. - @retval FALSE Ok, the option name has been found. - @retval TRUE Error occured or the option name is not found. -*/ - -bool parse_output_and_get_value(const char *command, - const char *option_name_str, - uint option_name_length, - char *option_value_buf, - size_t option_value_buf_size, - enum_option_type option_type) -{ -#ifndef __WIN__ - Mysqld_output_parser_unix parser; -#else /* __WIN__ */ - Mysqld_output_parser_win parser; -#endif - - return parser.parse(command, - option_name_str, - option_name_length, - option_value_buf, - option_value_buf_size, - option_type); -} diff --git a/server-tools/instance-manager/parse_output.h b/server-tools/instance-manager/parse_output.h deleted file mode 100644 index 41618f643a3..00000000000 --- a/server-tools/instance-manager/parse_output.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H -/* Copyright (C) 2004 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 */ - -#include - -enum enum_option_type -{ - GET_VALUE = 1, - GET_LINE -}; - -bool parse_output_and_get_value(const char *command, - const char *option_name_str, - uint option_name_length, - char *option_value_buf, - size_t option_value_buf_size, - enum_option_type option_type); - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H */ diff --git a/server-tools/instance-manager/portability.h b/server-tools/instance-manager/portability.h deleted file mode 100644 index 990e6140a9e..00000000000 --- a/server-tools/instance-manager/portability.h +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (C) 2005-2006 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PORTABILITY_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_PORTABILITY_H - -#if (defined(_SCO_DS) || defined(UNIXWARE_7)) && !defined(SHUT_RDWR) -/* - SHUT_* functions are defined only if - "(defined(_XOPEN_SOURCE) && _XOPEN_SOURCE_EXTENDED - 0 >= 1)" -*/ -#define SHUT_RDWR 2 -#endif - -#ifdef __WIN__ - -#define vsnprintf _vsnprintf -#define snprintf _snprintf - -#define SIGKILL 9 - -/*TODO: fix this */ -#define PROTOCOL_VERSION 10 - -#define DFLT_CONFIG_FILE_NAME "my.ini" -#define DFLT_MYSQLD_PATH "mysqld" -#define DFLT_PASSWD_FILE_EXT ".passwd" -#define DFLT_PID_FILE_EXT ".pid" -#define DFLT_SOCKET_FILE_EXT ".sock" - -typedef int pid_t; - -#undef popen -#define popen(A,B) _popen(A,B) - -#define NEWLINE "\r\n" -#define NEWLINE_LEN 2 - -const char CR = '\r'; -const char LF = '\n'; - -#else /* ! __WIN__ */ - -#define NEWLINE "\n" -#define NEWLINE_LEN 1 - -const char LF = '\n'; - -#endif /* __WIN__ */ - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PORTABILITY_H */ - - diff --git a/server-tools/instance-manager/priv.cc b/server-tools/instance-manager/priv.cc deleted file mode 100644 index 74263934924..00000000000 --- a/server-tools/instance-manager/priv.cc +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright (C) 2004-2006 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 */ - -#include "priv.h" - -#include -#include -#include - -#include "log.h" - -/* - The following string must be less then 80 characters, as - mysql_connection.cc relies on it -*/ -const LEX_STRING mysqlmanager_version= { C_STRING_WITH_LEN("1.0-beta") }; - -const unsigned char protocol_version= PROTOCOL_VERSION; - -unsigned long net_buffer_length= 16384; - -unsigned long max_allowed_packet= 16384; - -unsigned long net_read_timeout= NET_WAIT_TIMEOUT; // same as in mysqld - -unsigned long net_write_timeout= 60; // same as in mysqld - -unsigned long net_retry_count= 10; // same as in mysqld - -/* needed by net_serv.cc */ -unsigned int test_flags= 0; -unsigned long bytes_sent = 0L, bytes_received = 0L; -unsigned long mysqld_net_retry_count = 10L; -unsigned long open_files_limit; - - - -bool create_pid_file(const char *pid_file_name, int pid) -{ - FILE *pid_file; - - if (!(pid_file= my_fopen(pid_file_name, O_WRONLY | O_CREAT | O_BINARY, - MYF(0)))) - { - log_error("Can not create pid file '%s': %s (errno: %d)", - (const char *) pid_file_name, - (const char *) strerror(errno), - (int) errno); - return TRUE; - } - - if (fprintf(pid_file, "%d\n", (int) pid) <= 0) - { - log_error("Can not write to pid file '%s': %s (errno: %d)", - (const char *) pid_file_name, - (const char *) strerror(errno), - (int) errno); - return TRUE; - } - - my_fclose(pid_file, MYF(0)); - - return FALSE; -} diff --git a/server-tools/instance-manager/priv.h b/server-tools/instance-manager/priv.h deleted file mode 100644 index 1c2124c0e77..00000000000 --- a/server-tools/instance-manager/priv.h +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright (C) 2004-2006 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 */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H - -#include -#include -#include - -#include - -#ifndef __WIN__ -#include -#endif - -#include "portability.h" - -/* IM-wide platform-independent defines */ -#define SERVER_DEFAULT_PORT MYSQL_PORT -#define DEFAULT_MONITORING_INTERVAL 20 -#define DEFAULT_PORT 2273 -/* three-week timeout should be enough */ -#define LONG_TIMEOUT ((ulong) 3600L*24L*21L) - -const int MEM_ROOT_BLOCK_SIZE= 512; - -/* The maximal length of option name and option value. */ -const int MAX_OPTION_LEN= 1024; - -/* - The maximal length of whole option string: - --