From ea697fd44565e4da42aa0679bffa91af8cf4ada5 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Dec 2006 11:32:41 +0100 Subject: [PATCH 001/136] BUG#21132 (Slave fails to reconnect on update_slave_list): The update_slave_list() call is a remainder from attempts to implement failsafe replication. This code is now obsolete and not maintained (see comments in rpl_failsafe.cc). Inspecting the code one can see that this function do not interferre with normal slave operation and thus can be safely removed. This will solve the issue reported in the bug (errors on slave reconnection). A related issue is to remove unneccessary reconnections done by slave. This is handled in the patch for BUG#20435. sql/slave.cc: Removed call to obsolete function update_slave_list() upon slave's I/O thread reconnect. --- sql/slave.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/slave.cc b/sql/slave.cc index d0396444ace..a5d2e01b9ec 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3526,7 +3526,7 @@ connected: on with life. */ thd->proc_info = "Registering slave on master"; - if (register_slave_on_master(mysql) || update_slave_list(mysql, mi)) + if (register_slave_on_master(mysql)) goto err; } From 417b20153cae25848110f1337bf1e3c072839ea8 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 12 Apr 2007 09:47:45 +0200 Subject: [PATCH 002/136] Adding build file for Solaris on AMD64 BUILD/compile-solaris-amd64: New BitKeeper file ``BUILD/compile-solaris-amd64'' --- BUILD/compile-solaris-amd64 | 55 +++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100755 BUILD/compile-solaris-amd64 diff --git a/BUILD/compile-solaris-amd64 b/BUILD/compile-solaris-amd64 new file mode 100755 index 00000000000..f128fb12973 --- /dev/null +++ b/BUILD/compile-solaris-amd64 @@ -0,0 +1,55 @@ +#!/usr/bin/bash + +function _find_mysql_root () ( + while [ "x$PWD" != "x/" ]; do + # Check if some directories are present + if [ -d BUILD -a -d sql -a -d mysys ]; then + echo "$PWD" + return 0 + fi + cd .. + done + return 1 +) + +make -k clean || true +/bin/rm -f */.deps/*.P config.cache + +path=`dirname $0` +. "$path/autorun.sh" + +warning_flags="-Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Wunused" +compiler_flags="-g -O3 -fno-omit-frame-pointer" + +export CC CXX CFLAGS CXXFLAGS LDFLAGS LIBS +CC="gcc" +CXX="gcc" +CFLAGS="$warning_flags $compiler_flags" +CXXFLAGS="" +LDFLAGS="-O3 -g -static-libgcc" +LIBS=-lmtmalloc +root=$(_find_mysql_root) + +$root/configure \ + --prefix=/usr/local/mysql \ + --localstatedir=/usr/local/mysql/data \ + --libexecdir=/usr/local/mysql/bin \ + --with-extra-charsets=complex \ + --enable-thread-safe-client \ + --enable-local-infile \ + --with-zlib-dir=bundled \ + --with-big-tables \ + --with-readline \ + --with-archive-storage-engine \ + --with-named-curses=-lcurses \ + --with-big-tables \ + --with-innodb \ + --with-berkeley-db \ + --with-example-storage-engine \ + --with-blackhole-storage-engine \ + --with-ndbcluster \ + --with-federated-storage-engine \ + --with-csv-storage-engine \ + --with-ssl \ + --with-embedded-server \ + --disable-shared From 42886677ca317353d4405dc343373ed21adf29e8 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 17 Jul 2007 15:49:07 -0500 Subject: [PATCH 003/136] Many files: Added new test case for dropping column on the end of master table mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test: Added new test case for dropping column on the end of master table mysql-test/r/rpl_extraCol_innodb.result: Added new test case for dropping column on the end of master table mysql-test/r/rpl_extraCol_myisam.result: Added new test case for dropping column on the end of master table mysql-test/r/rpl_ndb_extraCol.result: Added new test case for dropping column on the end of master table --- .../extra/rpl_tests/rpl_extraSlave_Col.test | 66 ++++++++++++++++++- mysql-test/r/rpl_extraCol_innodb.result | 60 +++++++++++++++++ mysql-test/r/rpl_extraCol_myisam.result | 60 +++++++++++++++++ mysql-test/r/rpl_ndb_extraCol.result | 60 +++++++++++++++++ 4 files changed, 244 insertions(+), 2 deletions(-) diff --git a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test index abeef5f2903..36884c79973 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test @@ -10,7 +10,7 @@ ########### Clean up ################ --disable_warnings --disable_query_log -DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17; +DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t14a,t15,t16,t17; --enable_query_log --enable_warnings @@ -653,6 +653,68 @@ sync_slave_with_master; --replace_column 7 CURRENT_TIMESTAMP SELECT * FROM t14 ORDER BY c1; +#################################################### +# - Alter Master drop column at end of table # +# Expect: column dropped # +#################################################### + +--echo *** Create t14a on slave *** +STOP SLAVE; +RESET SLAVE; +eval CREATE TABLE t14a (c1 INT KEY, c4 BLOB, c5 CHAR(5), + c6 INT DEFAULT '1', + c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP + )ENGINE=$engine_type; + +--echo *** Create t14a on Master *** +connection master; +eval CREATE TABLE t14a (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) + ) ENGINE=$engine_type; +RESET MASTER; + +--echo *** Start Slave *** +connection slave; +START SLAVE; + +--echo *** Master Data Insert *** +connection master; +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14a () VALUES(1,@b1,'Kyle'), + (2,@b1,'JOE'), + (3,@b1,'QA'); + +SELECT * FROM t14a ORDER BY c1; +--echo *** Select on Slave **** +sync_slave_with_master; +--replace_column 5 CURRENT_TIMESTAMP +SELECT * FROM t14a ORDER BY c1; +STOP SLAVE; +RESET SLAVE; + +--echo *** Master Drop c5 *** +connection master; +ALTER TABLE t14a DROP COLUMN c5; +RESET MASTER; + +--echo *** Start Slave *** +connection slave; +START SLAVE; + +--echo *** Master Data Insert *** +connection master; +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); + +INSERT INTO t14a () VALUES(4,@b1), + (5,@b1), + (6,@b1); +SELECT * FROM t14a ORDER BY c1; + +--echo *** Select on Slave **** +sync_slave_with_master; +--replace_column 5 CURRENT_TIMESTAMP +SELECT * FROM t14a ORDER BY c1; #################################################### # - Alter Master Dropping columns from the middle. # @@ -847,7 +909,7 @@ sync_slave_with_master; #### Clean Up #### --disable_warnings --disable_query_log -DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17; +DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t14a,t15,t16,t17; --enable_query_log --enable_warnings diff --git a/mysql-test/r/rpl_extraCol_innodb.result b/mysql-test/r/rpl_extraCol_innodb.result index cfce12b594e..9f38a7116b8 100644 --- a/mysql-test/r/rpl_extraCol_innodb.result +++ b/mysql-test/r/rpl_extraCol_innodb.result @@ -548,6 +548,66 @@ c1 c2 c3 c4 c5 c6 c7 1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP 2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP 3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +*** Create t14a on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t14a (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='InnoDB'; +*** Create t14a on Master *** +CREATE TABLE t14a (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='InnoDB'; +RESET MASTER; +*** Start Slave *** +START SLAVE; +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14a () VALUES(1,@b1,'Kyle'), +(2,@b1,'JOE'), +(3,@b1,'QA'); +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 +1 b1b1b1b1b1b1b1b1 Kyle +2 b1b1b1b1b1b1b1b1 JOE +3 b1b1b1b1b1b1b1b1 QA +*** Select on Slave **** +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 c6 c7 +1 b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP +2 b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP +3 b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +STOP SLAVE; +RESET SLAVE; +*** Master Drop c5 *** +ALTER TABLE t14a DROP COLUMN c5; +RESET MASTER; +*** Start Slave *** +START SLAVE; +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14a () VALUES(4,@b1), +(5,@b1), +(6,@b1); +SELECT * FROM t14a ORDER BY c1; +c1 c4 +1 b1b1b1b1b1b1b1b1 +2 b1b1b1b1b1b1b1b1 +3 b1b1b1b1b1b1b1b1 +4 b1b1b1b1b1b1b1b1 +5 b1b1b1b1b1b1b1b1 +6 b1b1b1b1b1b1b1b1 +*** Select on Slave **** +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 c6 c7 +1 b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP +2 b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP +3 b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +4 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP +5 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP +6 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP *** connect to master and drop columns *** ALTER TABLE t14 DROP COLUMN c2; ALTER TABLE t14 DROP COLUMN c4; diff --git a/mysql-test/r/rpl_extraCol_myisam.result b/mysql-test/r/rpl_extraCol_myisam.result index b250911368c..f7b56c910e5 100644 --- a/mysql-test/r/rpl_extraCol_myisam.result +++ b/mysql-test/r/rpl_extraCol_myisam.result @@ -548,6 +548,66 @@ c1 c2 c3 c4 c5 c6 c7 1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP 2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP 3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +*** Create t14a on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t14a (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='MyISAM'; +*** Create t14a on Master *** +CREATE TABLE t14a (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='MyISAM'; +RESET MASTER; +*** Start Slave *** +START SLAVE; +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14a () VALUES(1,@b1,'Kyle'), +(2,@b1,'JOE'), +(3,@b1,'QA'); +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 +1 b1b1b1b1b1b1b1b1 Kyle +2 b1b1b1b1b1b1b1b1 JOE +3 b1b1b1b1b1b1b1b1 QA +*** Select on Slave **** +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 c6 c7 +1 b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP +2 b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP +3 b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +STOP SLAVE; +RESET SLAVE; +*** Master Drop c5 *** +ALTER TABLE t14a DROP COLUMN c5; +RESET MASTER; +*** Start Slave *** +START SLAVE; +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14a () VALUES(4,@b1), +(5,@b1), +(6,@b1); +SELECT * FROM t14a ORDER BY c1; +c1 c4 +1 b1b1b1b1b1b1b1b1 +2 b1b1b1b1b1b1b1b1 +3 b1b1b1b1b1b1b1b1 +4 b1b1b1b1b1b1b1b1 +5 b1b1b1b1b1b1b1b1 +6 b1b1b1b1b1b1b1b1 +*** Select on Slave **** +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 c6 c7 +1 b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP +2 b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP +3 b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +4 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP +5 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP +6 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP *** connect to master and drop columns *** ALTER TABLE t14 DROP COLUMN c2; ALTER TABLE t14 DROP COLUMN c4; diff --git a/mysql-test/r/rpl_ndb_extraCol.result b/mysql-test/r/rpl_ndb_extraCol.result index 5afc9c1db77..a4cb236a6b8 100644 --- a/mysql-test/r/rpl_ndb_extraCol.result +++ b/mysql-test/r/rpl_ndb_extraCol.result @@ -548,6 +548,66 @@ c1 c2 c3 c4 c5 c6 c7 1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle NULL CURRENT_TIMESTAMP 2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE NULL CURRENT_TIMESTAMP 3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA NULL CURRENT_TIMESTAMP +*** Create t14a on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t14a (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='NDB'; +*** Create t14a on Master *** +CREATE TABLE t14a (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='NDB'; +RESET MASTER; +*** Start Slave *** +START SLAVE; +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14a () VALUES(1,@b1,'Kyle'), +(2,@b1,'JOE'), +(3,@b1,'QA'); +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 +1 b1b1b1b1b1b1b1b1 Kyle +2 b1b1b1b1b1b1b1b1 JOE +3 b1b1b1b1b1b1b1b1 QA +*** Select on Slave **** +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 c6 c7 +1 b1b1b1b1b1b1b1b1 Kyle NULL CURRENT_TIMESTAMP +2 b1b1b1b1b1b1b1b1 JOE NULL CURRENT_TIMESTAMP +3 b1b1b1b1b1b1b1b1 QA NULL CURRENT_TIMESTAMP +STOP SLAVE; +RESET SLAVE; +*** Master Drop c5 *** +ALTER TABLE t14a DROP COLUMN c5; +RESET MASTER; +*** Start Slave *** +START SLAVE; +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14a () VALUES(4,@b1), +(5,@b1), +(6,@b1); +SELECT * FROM t14a ORDER BY c1; +c1 c4 +1 b1b1b1b1b1b1b1b1 +2 b1b1b1b1b1b1b1b1 +3 b1b1b1b1b1b1b1b1 +4 b1b1b1b1b1b1b1b1 +5 b1b1b1b1b1b1b1b1 +6 b1b1b1b1b1b1b1b1 +*** Select on Slave **** +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 c6 c7 +1 b1b1b1b1b1b1b1b1 Kyle NULL CURRENT_TIMESTAMP +2 b1b1b1b1b1b1b1b1 JOE NULL CURRENT_TIMESTAMP +3 b1b1b1b1b1b1b1b1 QA NULL CURRENT_TIMESTAMP +4 b1b1b1b1b1b1b1b1 NULL NULL CURRENT_TIMESTAMP +5 b1b1b1b1b1b1b1b1 NULL NULL CURRENT_TIMESTAMP +6 b1b1b1b1b1b1b1b1 NULL NULL CURRENT_TIMESTAMP *** connect to master and drop columns *** ALTER TABLE t14 DROP COLUMN c2; ALTER TABLE t14 DROP COLUMN c4; From 40f70e75ef5c0babcf07b7d49033c06589f34d72 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 17 Aug 2007 19:51:25 +0200 Subject: [PATCH 004/136] rpl_packet.test: Removed sleep from test per lars request mysql-test/suite/rpl/t/rpl_packet.test: Removed sleep from test per lars request --- mysql-test/suite/rpl/t/rpl_packet.test | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test index 316278cb75d..c3987f7ee15 100644 --- a/mysql-test/suite/rpl/t/rpl_packet.test +++ b/mysql-test/suite/rpl/t/rpl_packet.test @@ -67,7 +67,6 @@ INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa # The slave I/O thread must stop after trying to read the above event connection slave; -sleep 2; --source include/wait_for_slave_io_to_stop.inc SHOW STATUS LIKE 'Slave_running'; From be9619f0472f2ae05efd400f18c09cf756080e72 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 20 Aug 2007 12:31:21 +0400 Subject: [PATCH 005/136] rpl.rpl_innodb_mixed_dml enabled --- mysql-test/suite/rpl/t/disabled.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index d1b636ad9a2..34a8d6988a9 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -12,7 +12,7 @@ rpl_ddl : BUG#26418 2007-03-01 mleich Slave out of sync after CREATE/DROP TEMPORARY TABLE + ROLLBACK on master #rpl_innodb_mixed_ddl : Bug #29363 rpl.rpl_innodb_mixed_* test failures -rpl_innodb_mixed_dml : Bug #29363 rpl.rpl_innodb_mixed_* test failures +#rpl_innodb_mixed_dml : Bug #29363 rpl.rpl_innodb_mixed_* test failures rpl_invoked_features : BUG#29020 2007-06-21 Lars Non-deterministic test case rpl_auto_increment_11932 : Bug#29809 2007-07-16 ingo Slave SQL errors in warnings file rpl_stm_extraColmaster_ndb : WL#3915 : Statement-based replication not supported in ndb. Enable test when supported. From 86c92997ea559d1c799d5a91db48a9e3e527641e Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 20 Aug 2007 13:24:37 +0400 Subject: [PATCH 006/136] Bug#29363 mysql-test/suite/rpl/include/rpl_mixed_dml.inc: removed file_id,block_len from SHOW BINLOG EVENTS mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result: updated result file --- mysql-test/suite/rpl/include/rpl_mixed_dml.inc | 4 ++-- mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc index 1accf40160a..96dfdbed541 100644 --- a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc +++ b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc @@ -328,7 +328,7 @@ DROP VIEW v2; --echo --echo ******************** SHOW BINLOG EVENTS ******************** --replace_column 2 # 5 # ---replace_regex /Server ver: .+/Server ver: #/ /table_id: [0-9]+/table_id: #/ /COMMIT.+xid=[0-9]+.+/#/ +--replace_regex /Server ver: .+/Server ver: #/ /table_id: [0-9]+/table_id: #/ /COMMIT.+xid=[0-9]+.+/#/ /file_id=[0-9]+/file_id=#/ /block_len=[0-9]+/block_len=#/ show binlog events from 1; sync_slave_with_master; # as we're using UUID we don't SELECT but use "diff" like in rpl_row_UUID @@ -344,4 +344,4 @@ sync_slave_with_master; # will be created. You will need to go to the mysql-test dir and diff # the files your self to see what is not matching ---exec diff $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_slave.sql; +--exec diff $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_slave.sql 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 462400e12bb..19c5299df25 100644 --- a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result +++ b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result @@ -867,8 +867,8 @@ master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1 master-bin.000001 # Xid 1 # # master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2 master-bin.000001 # Xid 1 # # -master-bin.000001 # Begin_load_query 1 # ;file_id=1;block_len=30 -master-bin.000001 # Execute_load_query 1 # use `test_rpl`; LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ;file_id=1 +master-bin.000001 # Begin_load_query 1 # ;file_id=#;block_len=# +master-bin.000001 # Execute_load_query 1 # use `test_rpl`; LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ;file_id=# master-bin.000001 # Xid 1 # # master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1 master-bin.000001 # Xid 1 # # From a0849011471dd15c2789436ed57350691e030101 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Aug 2007 15:16:55 +0300 Subject: [PATCH 007/136] Bug #23333 stored function + non-transac table + transac table = breaks stmt-based binlog Binlogging of the statement with a side effect like a modified non-trans table did not happen. The artifact involved all binloggable dml queries. Fixed with changing the binlogging conditions all over the code to exploit thd->transaction.stmt.modified_non_trans_table introduced by the patch for bug@27417. Multi-delete case has own specific addressed by another bug@29136. Multi-update case has been addressed by bug#27716 and patch and will need merging. mysql-test/r/mix_innodb_myisam_binlog.result: results changed mysql-test/r/sp_trans_log.result: results changed mysql-test/t/mix_innodb_myisam_binlog.test: specific to the bug tests added mysql-test/t/sp_trans_log.test: refining of the proof of that there is an event in binlog sql/sql_delete.cc: deploying the binlogging check with thd->transaction.stmt.modified_non_trans_table sql/sql_insert.cc: binlogging when thd->transaction.stmt.modified_non_trans_table is TRUE. Merge with Bug#29571. sql/sql_load.cc: binlogging when thd->transaction.stmt.modified_non_trans_table is true sql/sql_update.cc: binlogging when thd->transaction.stmt.modified_non_trans_table is true --- mysql-test/r/mix_innodb_myisam_binlog.result | 73 ++++++++++- mysql-test/r/sp_trans_log.result | 5 +- mysql-test/t/mix_innodb_myisam_binlog.test | 120 ++++++++++++++++++- mysql-test/t/sp_trans_log.test | 3 +- sql/sql_delete.cc | 6 +- sql/sql_insert.cc | 78 ++++++------ sql/sql_load.cc | 2 +- sql/sql_update.cc | 2 +- 8 files changed, 238 insertions(+), 51 deletions(-) diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index 5777bd890b2..181f4c67254 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -365,7 +365,7 @@ insert into t2 values (bug27417(2)); ERROR 23000: Duplicate entry '2' for key 1 show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 98 +master-bin.000001 196 /* only (!) with fixes for #23333 will show there is the query */; select count(*) from t1 /* must be 3 */; count(*) @@ -390,6 +390,75 @@ affected rows: 0 select count(*) from t1 /* must be 7 */; count(*) 7 -drop function bug27417; drop table t1,t2; +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +insert into t2 values (1); +reset master; +insert into t2 values (bug27417(1)); +ERROR 23000: Duplicate entry '1' for key 1 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 267 +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +delete from t2; +insert into t2 values (2); +reset master; +insert into t2 select bug27417(1) union select bug27417(2); +ERROR 23000: Duplicate entry '2' for key 1 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 290 +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +insert into t3 values (1,1),(2,3),(3,4); +reset master; +update t3 set b=b+bug27417(1); +ERROR 23000: Duplicate entry '4' for key 2 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 190 +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +delete from t2; +delete from t3; +insert into t2 values (1); +insert into t3 values (1,1); +create trigger trg_del before delete on t2 for each row +insert into t3 values (bug27417(1), 2); +reset master; +delete from t2; +ERROR 23000: Duplicate entry '1' for key 1 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 246 +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +create table t4 (a int default 0, b int primary key) engine=innodb; +insert into t4 values (0, 17); +reset master; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +ERROR 23000: Duplicate entry '17' for key 1 +select * from t4; +a b +0 17 +select count(*) from t1 /* must be 2 */; +count(*) +2 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 376 +drop trigger trg_del; +drop table t1,t2,t3; +drop function bug27417; end of tests diff --git a/mysql-test/r/sp_trans_log.result b/mysql-test/r/sp_trans_log.result index 96e6f76b23c..14a8ecf6a37 100644 --- a/mysql-test/r/sp_trans_log.result +++ b/mysql-test/r/sp_trans_log.result @@ -12,8 +12,9 @@ end| reset master| insert into t2 values (bug23333(),1)| ERROR 23000: Duplicate entry '1' for key 1 -show binlog events from 98 /* with fixes for #23333 will show there is the query */| -Log_name Pos Event_type Server_id End_log_pos Info +show master status /* the offset must denote there is the query */| +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 284 select count(*),@a from t1 /* must be 1,1 */| count(*) @a 1 1 diff --git a/mysql-test/t/mix_innodb_myisam_binlog.test b/mysql-test/t/mix_innodb_myisam_binlog.test index f9d7235ff84..e5fec37cc23 100644 --- a/mysql-test/t/mix_innodb_myisam_binlog.test +++ b/mysql-test/t/mix_innodb_myisam_binlog.test @@ -380,8 +380,126 @@ delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; --disable_info select count(*) from t1 /* must be 7 */; -drop function bug27417; +# function bug27417 remains for the following testing of bug#23333 drop table t1,t2; +# +# Bug#23333 using the patch (and the test) for bug#27471 +# throughout the bug tests +# t1 - non-trans side effects gatherer; +# t2 - transactional table; +# +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); + + +# +# INSERT +# + +# prepare + + insert into t2 values (1); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 values (bug27417(1)); + +# check + + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 1 */; + +# +# INSERT SELECT +# + +# prepare + delete from t1; + delete from t2; + insert into t2 values (2); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 select bug27417(1) union select bug27417(2); + +# check + + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 2 */; + +# +# UPDATE (multi-update see bug#27716) +# + +# prepare + delete from t1; + insert into t3 values (1,1),(2,3),(3,4); + reset master; + +# execute + --error ER_DUP_ENTRY + update t3 set b=b+bug27417(1); + +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 2 */; + + +# +# DELETE (for multi-delete see Bug #29136) +# + +# prepare + delete from t1; + delete from t2; + delete from t3; + insert into t2 values (1); + insert into t3 values (1,1); + create trigger trg_del before delete on t2 for each row + insert into t3 values (bug27417(1), 2); + reset master; + +# execute + --error ER_DUP_ENTRY + delete from t2; +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 1 */; + + +# +# LOAD DATA +# + +# prepare + delete from t1; + create table t4 (a int default 0, b int primary key) engine=innodb; + insert into t4 values (0, 17); + reset master; + +# execute + --error ER_DUP_ENTRY + load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +# check + select * from t4; + select count(*) from t1 /* must be 2 */; + show master status /* the offset must denote there is the query */; + +# +# bug#23333 cleanup +# + + +drop trigger trg_del; +drop table t1,t2,t3; +drop function bug27417; + + --echo end of tests diff --git a/mysql-test/t/sp_trans_log.test b/mysql-test/t/sp_trans_log.test index 3e440b3ccc1..508c730a1cf 100644 --- a/mysql-test/t/sp_trans_log.test +++ b/mysql-test/t/sp_trans_log.test @@ -26,8 +26,7 @@ end| reset master| --error ER_DUP_ENTRY insert into t2 values (bug23333(),1)| ---replace_column 2 # 5 # 6 # -show binlog events from 98 /* with fixes for #23333 will show there is the query */| +show master status /* the offset must denote there is the query */| select count(*),@a from t1 /* must be 1,1 */| drop table t1, t2| diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 56edfa6c5b2..7555219f5d8 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -319,7 +319,7 @@ cleanup: thd->transaction.stmt.modified_non_trans_table= TRUE; /* See similar binlogging code in sql_update.cc, for comments */ - if ((error < 0) || (deleted && !transactional_table)) + if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { if (mysql_bin_log.is_open()) { @@ -817,7 +817,8 @@ bool multi_delete::send_eof() { query_cache_invalidate3(thd, delete_tables, 1); } - if ((local_error == 0) || (deleted && normal_tables)) + DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); + if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table) { if (mysql_bin_log.is_open()) { @@ -831,7 +832,6 @@ bool multi_delete::send_eof() if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; } - DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); /* Commit or rollback the current SQL statement */ if (transactional_tables) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index bd21d929291..a2fd71ba240 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -866,8 +866,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, transactional_table= table->file->has_transactions(); - if ((changed= (info.copied || info.deleted || info.updated)) || - was_insert_delayed) + if ((changed= (info.copied || info.deleted || info.updated))) { /* Invalidate the table in the query cache if something changed. @@ -876,46 +875,47 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, */ if (changed) query_cache_invalidate3(thd, table_list, 1); - if (error <= 0 || !transactional_table) + } + if (changed && error <= 0 || thd->transaction.stmt.modified_non_trans_table + || was_insert_delayed) + { + if (mysql_bin_log.is_open()) { - if (mysql_bin_log.is_open()) + if (error <= 0) { - if (error <= 0) - { - /* - [Guilhem wrote] Temporary errors may have filled - thd->net.last_error/errno. For example if there has - been a disk full error when writing the row, and it was - MyISAM, then thd->net.last_error/errno will be set to - "disk full"... and the my_pwrite() will wait until free - space appears, and so when it finishes then the - write_row() was entirely successful - */ - /* todo: consider removing */ - thd->clear_error(); - } - /* bug#22725: - - A query which per-row-loop can not be interrupted with - KILLED, like INSERT, and that does not invoke stored - routines can be binlogged with neglecting the KILLED error. - - If there was no error (error == zero) until after the end of - inserting loop the KILLED flag that appeared later can be - disregarded since previously possible invocation of stored - routines did not result in any error due to the KILLED. In - such case the flag is ignored for constructing binlog event. + /* + [Guilhem wrote] Temporary errors may have filled + thd->net.last_error/errno. For example if there has + been a disk full error when writing the row, and it was + MyISAM, then thd->net.last_error/errno will be set to + "disk full"... and the my_pwrite() will wait until free + space appears, and so when it finishes then the + write_row() was entirely successful */ - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE, - (error>0) ? thd->killed : THD::NOT_KILLED); - DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0); - if (mysql_bin_log.write(&qinfo) && transactional_table) - error=1; + /* todo: consider removing */ + thd->clear_error(); } - if (thd->transaction.stmt.modified_non_trans_table) - thd->transaction.all.modified_non_trans_table= TRUE; + /* bug#22725: + + A query which per-row-loop can not be interrupted with + KILLED, like INSERT, and that does not invoke stored + routines can be binlogged with neglecting the KILLED error. + + If there was no error (error == zero) until after the end of + inserting loop the KILLED flag that appeared later can be + disregarded since previously possible invocation of stored + routines did not result in any error due to the KILLED. In + such case the flag is ignored for constructing binlog event. + */ + Query_log_event qinfo(thd, thd->query, thd->query_length, + transactional_table, FALSE, + (error>0) ? thd->killed : THD::NOT_KILLED); + DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0); + if (mysql_bin_log.write(&qinfo) && transactional_table) + error=1; } + if (thd->transaction.stmt.modified_non_trans_table) + thd->transaction.all.modified_non_trans_table= TRUE; } DBUG_ASSERT(transactional_table || !changed || thd->transaction.stmt.modified_non_trans_table); @@ -3001,6 +3001,7 @@ void select_insert::abort() */ DBUG_VOID_RETURN; } + changed= (info.copied || info.deleted || info.updated); transactional_table= table->file->has_transactions(); if (!thd->prelocked_mode) table->file->end_bulk_insert(); @@ -3010,8 +3011,7 @@ void select_insert::abort() error while inserting into a MyISAM table) we must write to the binlog (and the error code will make the slave stop). */ - if ((changed= info.copied || info.deleted || info.updated) && - !transactional_table) + if (thd->transaction.stmt.modified_non_trans_table) { if (last_insert_id) thd->insert_id(last_insert_id); // For binary log diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 55cbbf1c540..0dc02ac4a68 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -444,7 +444,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, /* If the file was not empty, wrote_create_file is true */ if (lf_info.wrote_create_file) { - if ((info.copied || info.deleted) && !transactional_table) + if (thd->transaction.stmt.modified_non_trans_table) write_execute_load_query_log_event(thd, handle_duplicates, ignore, transactional_table); else diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c78e246f518..3f38ad8b33c 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -580,7 +580,7 @@ int mysql_update(THD *thd, Sometimes we want to binlog even if we updated no rows, in case user used it to be sure master and slave are in same state. */ - if ((error < 0) || (updated && !transactional_table)) + if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { if (mysql_bin_log.is_open()) { From bdfe0b5290df00c85b716bbcd3718b842a3fbbdc Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Aug 2007 10:40:38 +0300 Subject: [PATCH 008/136] bug#27417 refining of cleanup of the tests. mysql-test/r/mix_innodb_myisam_binlog.result: results changed. mysql-test/t/mix_innodb_myisam_binlog.test: proper cleanup. --- mysql-test/r/mix_innodb_myisam_binlog.result | 2 +- mysql-test/t/mix_innodb_myisam_binlog.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index 181f4c67254..5d5726c9689 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -459,6 +459,6 @@ show master status /* the offset must denote there is the query */; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 376 drop trigger trg_del; -drop table t1,t2,t3; +drop table t1,t2,t3,t4; drop function bug27417; end of tests diff --git a/mysql-test/t/mix_innodb_myisam_binlog.test b/mysql-test/t/mix_innodb_myisam_binlog.test index e5fec37cc23..e1740bda03e 100644 --- a/mysql-test/t/mix_innodb_myisam_binlog.test +++ b/mysql-test/t/mix_innodb_myisam_binlog.test @@ -497,7 +497,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); drop trigger trg_del; -drop table t1,t2,t3; +drop table t1,t2,t3,t4; drop function bug27417; From 116995f9165539a254e058f1be13ae364a0bef4b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Aug 2007 15:43:16 +0300 Subject: [PATCH 009/136] bug#23333 fixing the test due a to different offsets in binlog with ps-protocol (a possible bug to be reported) mysql-test/r/sp_trans_log.result: results changed as prescribed mysql-test/t/sp_trans_log.test: Replacing the reporting pattern ### a possible bug: #show master status /* the offset must denote there is the query */| # displays different offests in ps-protocol with show binlog events --- mysql-test/r/sp_trans_log.result | 7 ++++--- mysql-test/t/sp_trans_log.test | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/sp_trans_log.result b/mysql-test/r/sp_trans_log.result index 14a8ecf6a37..9b644798079 100644 --- a/mysql-test/r/sp_trans_log.result +++ b/mysql-test/r/sp_trans_log.result @@ -12,9 +12,10 @@ end| reset master| insert into t2 values (bug23333(),1)| ERROR 23000: Duplicate entry '1' for key 1 -show master status /* the offset must denote there is the query */| -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 284 +show binlog events from 98 /* with fixes for #23333 will show there are 2 queries */| +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query 1 # # +master-bin.000001 # Query 1 # # select count(*),@a from t1 /* must be 1,1 */| count(*) @a 1 1 diff --git a/mysql-test/t/sp_trans_log.test b/mysql-test/t/sp_trans_log.test index 508c730a1cf..93605722f6b 100644 --- a/mysql-test/t/sp_trans_log.test +++ b/mysql-test/t/sp_trans_log.test @@ -26,7 +26,8 @@ end| reset master| --error ER_DUP_ENTRY insert into t2 values (bug23333(),1)| -show master status /* the offset must denote there is the query */| +--replace_column 2 # 5 # 6 # +show binlog events from 98 /* with fixes for #23333 will show there are 2 queries */| select count(*),@a from t1 /* must be 1,1 */| drop table t1, t2| From 79f951adf938f57d2482b2a483d76bcca6d8d842 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 27 Aug 2007 16:17:17 +0200 Subject: [PATCH 010/136] Post merge fixes. sql/log_event.cc: - Rename RELAY_LOG_INFO -> Relay_log_info. - Rows_log_event fields which are used for event application not included when compiling in MYSQL_CLIENT mode. sql/log_event.h: - Rename RELAY_LOG_INFO -> Relay_log_info. - Rows_log_event fields which are used for event application not included when compiling in MYSQL_CLIENT mode. sql/log_event_old.cc: - Rename RELAY_LOG_INFO -> Relay_log_info. sql/log_event_old.h: - Rename RELAY_LOG_INFO -> Relay_log_info. sql/sql_yacc.yy: Reverting to version used in the rpl tree. --- sql/log_event.cc | 41 +++++++++++++++++++++++------------------ sql/log_event.h | 24 ++++++++++++------------ sql/log_event_old.cc | 24 ++++++++++++------------ sql/log_event_old.h | 16 ++++++++-------- sql/sql_yacc.yy | 13 +------------ 5 files changed, 56 insertions(+), 62 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 2142aa0b54e..b77452d1af4 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5653,9 +5653,10 @@ Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid, m_table(tbl_arg), m_table_id(tid), m_width(tbl_arg ? tbl_arg->s->fields : 1), - m_rows_buf(0), m_rows_cur(0), m_rows_end(0), - m_curr_row(NULL), m_curr_row_end(NULL), - m_flags(0), m_key(NULL) + m_rows_buf(0), m_rows_cur(0), m_rows_end(0), m_flags(0) +#ifdef HAVE_REPLICATION + ,m_key(NULL), m_curr_row(NULL), m_curr_row_end(NULL) +#endif { /* We allow a special form of dummy event when the table, and cols @@ -5697,10 +5698,13 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, *description_event) : Log_event(buf, description_event), m_row_count(0), +#ifndef MYSQL_CLIENT m_table(NULL), - m_rows_buf(0), m_rows_cur(0), m_rows_end(0), - m_curr_row(NULL), m_curr_row_end(NULL), - m_key(NULL) +#endif + m_rows_buf(0), m_rows_cur(0), m_rows_end(0) +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) + ,m_key(NULL), m_curr_row(NULL), m_curr_row_end(NULL) +#endif { DBUG_ENTER("Rows_log_event::Rows_log_event(const char*,...)"); uint8 const common_header_len= description_event->common_header_len; @@ -5789,7 +5793,9 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, m_rows_buf= (uchar*) my_malloc(data_size, MYF(MY_WME)); if (likely((bool)m_rows_buf)) { +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) m_curr_row= m_rows_buf; +#endif m_rows_end= m_rows_buf + data_size; m_rows_cur= m_rows_end; memcpy(m_rows_buf, ptr_rows_data, data_size); @@ -6055,7 +6061,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) TABLE* table= - m_table= const_cast(rli)->m_table_map.get_table(m_table_id); + m_table= const_cast(rli)->m_table_map.get_table(m_table_id); if (table) { @@ -6100,7 +6106,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) inside a statement and halting abruptly might cause problems when restarting. */ - const_cast(rli)->set_flag(RELAY_LOG_INFO::IN_STMT); + const_cast(rli)->set_flag(Relay_log_info::IN_STMT); if ( m_width == table->s->fields && bitmap_is_set_all(&m_cols)) set_flags(COMPLETE_ROWS_F); @@ -6187,8 +6193,8 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) } // if (table) /* - We need to delay this clear until the table def stored in m_table_def is no - longer needed. It is used in unpack_current_row(). + We need to delay this clear until here bacause unpack_current_row() uses + master-side table definitions stored in rli. */ if (rli->tables_to_lock && get_flags(STMT_END_F)) const_cast(rli)->clear_tables_to_lock(); @@ -7136,7 +7142,7 @@ is_duplicate_key_error(int errcode) */ int -Rows_log_event::write_row(const RELAY_LOG_INFO *const rli, +Rows_log_event::write_row(const Relay_log_info *const rli, const bool overwrite) { DBUG_ENTER("write_row"); @@ -7323,7 +7329,7 @@ Rows_log_event::write_row(const RELAY_LOG_INFO *const rli, #endif int -Write_rows_log_event::do_exec_row(const RELAY_LOG_INFO *const rli) +Write_rows_log_event::do_exec_row(const Relay_log_info *const rli) { DBUG_ASSERT(m_table != NULL); int error= write_row(rli, TRUE /* overwrite */); @@ -7453,7 +7459,7 @@ record_compare_exit: @c position() and @c rnd_pos() will be used. */ -int Rows_log_event::find_row(const RELAY_LOG_INFO *rli) +int Rows_log_event::find_row(const Relay_log_info *rli) { DBUG_ENTER("find_row"); @@ -7505,7 +7511,7 @@ int Rows_log_event::find_row(const RELAY_LOG_INFO *rli) DBUG_RETURN(error); } - // We can't use pisition() - try other methods. + // We can't use position() - try other methods. /* We need to retrieve all fields @@ -7721,8 +7727,7 @@ Delete_rows_log_event::do_before_row_operations(const Slave_reporting_capability m_table->s->primary_key < MAX_KEY) { /* - We don't need to allocate any memory for m_after_image and - m_key since they are not used. + We don't need to allocate any memory for m_key since it is not used. */ return 0; } @@ -7749,7 +7754,7 @@ Delete_rows_log_event::do_after_row_operations(const Slave_reporting_capability return error; } -int Delete_rows_log_event::do_exec_row(const RELAY_LOG_INFO *const rli) +int Delete_rows_log_event::do_exec_row(const Relay_log_info *const rli) { int error; DBUG_ASSERT(m_table != NULL); @@ -7873,7 +7878,7 @@ Update_rows_log_event::do_after_row_operations(const Slave_reporting_capability } int -Update_rows_log_event::do_exec_row(const RELAY_LOG_INFO *const rli) +Update_rows_log_event::do_exec_row(const Relay_log_info *const rli) { DBUG_ASSERT(m_table != NULL); diff --git a/sql/log_event.h b/sql/log_event.h index 0ec98561ae0..5c6a52fd9db 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -829,7 +829,7 @@ public: @see do_apply_event */ - int apply_event(RELAY_LOG_INFO const *rli) + int apply_event(Relay_log_info const *rli) { return do_apply_event(rli); } @@ -2291,20 +2291,20 @@ protected: uchar *m_rows_cur; /* One-after the end of the data */ uchar *m_rows_end; /* One-after the end of the allocated space */ - const uchar *m_curr_row; /* Start of the row being processed */ - const uchar *m_curr_row_end; /* One-after the end of the current row */ - flag_set m_flags; /* Flags for row-level events */ - uchar *m_key; /* Buffer to keep key value during searches */ /* helper functions */ #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) - int find_row(const RELAY_LOG_INFO *const); - int write_row(const RELAY_LOG_INFO *const, const bool); + const uchar *m_curr_row; /* Start of the row being processed */ + const uchar *m_curr_row_end; /* One-after the end of the current row */ + uchar *m_key; /* Buffer to keep key value during searches */ + + int find_row(const Relay_log_info *const); + int write_row(const Relay_log_info *const, const bool); // Unpack the current row into m_table->record[0] - int unpack_current_row(const RELAY_LOG_INFO *const rli) + int unpack_current_row(const Relay_log_info *const rli) { DBUG_ASSERT(m_table); return ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, @@ -2368,7 +2368,7 @@ private: 0 if execution succeeded, 1 if execution failed. */ - virtual int do_exec_row(const RELAY_LOG_INFO *const rli) = 0; + virtual int do_exec_row(const Relay_log_info *const rli) = 0; #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ friend class Old_rows_log_event; @@ -2424,7 +2424,7 @@ private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) virtual int do_before_row_operations(const Slave_reporting_capability *const); virtual int do_after_row_operations(const Slave_reporting_capability *const,int); - virtual int do_exec_row(const RELAY_LOG_INFO *const); + virtual int do_exec_row(const Relay_log_info *const); #endif }; @@ -2498,7 +2498,7 @@ protected: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) virtual int do_before_row_operations(const Slave_reporting_capability *const); virtual int do_after_row_operations(const Slave_reporting_capability *const,int); - virtual int do_exec_row(const RELAY_LOG_INFO *const); + virtual int do_exec_row(const Relay_log_info *const); #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ }; @@ -2563,7 +2563,7 @@ protected: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) virtual int do_before_row_operations(const Slave_reporting_capability *const); virtual int do_after_row_operations(const Slave_reporting_capability *const,int); - virtual int do_exec_row(const RELAY_LOG_INFO *const); + virtual int do_exec_row(const Relay_log_info *const); #endif }; diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 420df67dc54..949179386ea 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -11,7 +11,7 @@ // Old implementation of do_apply_event() int -Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli) +Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli) { DBUG_ENTER("Rows_log_event::do_apply_event(st_relay_log_info*)"); int error= 0; @@ -32,7 +32,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli */ DBUG_ASSERT(ev->get_flags(Rows_log_event::STMT_END_F)); - const_cast(rli)->clear_tables_to_lock(); + const_cast(rli)->clear_tables_to_lock(); close_thread_tables(thd); thd->clear_error(); DBUG_RETURN(0); @@ -88,7 +88,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli "Error in %s event: when locking tables", ev->get_type_str()); } - const_cast(rli)->clear_tables_to_lock(); + const_cast(rli)->clear_tables_to_lock(); DBUG_RETURN(error); } @@ -125,7 +125,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli "unexpected success or fatal error")); thd->query_error= 1; } - const_cast(rli)->clear_tables_to_lock(); + const_cast(rli)->clear_tables_to_lock(); DBUG_RETURN(error); } } @@ -147,7 +147,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli mysql_unlock_tables(thd, thd->lock); thd->lock= 0; thd->query_error= 1; - const_cast(rli)->clear_tables_to_lock(); + const_cast(rli)->clear_tables_to_lock(); DBUG_RETURN(Rows_log_event::ERR_BAD_TABLE_DEF); } } @@ -169,14 +169,14 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli */ for (TABLE_LIST *ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global) { - const_cast(rli)->m_table_map.set_table(ptr->table_id, ptr->table); + const_cast(rli)->m_table_map.set_table(ptr->table_id, ptr->table); } #ifdef HAVE_QUERY_CACHE query_cache.invalidate_locked_for_write(rli->tables_to_lock); #endif } - TABLE* table= const_cast(rli)->m_table_map.get_table(ev->m_table_id); + TABLE* table= const_cast(rli)->m_table_map.get_table(ev->m_table_id); if (table) { @@ -221,7 +221,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli inside a statement and halting abruptly might cause problems when restarting. */ - const_cast(rli)->set_flag(RELAY_LOG_INFO::IN_STMT); + const_cast(rli)->set_flag(Relay_log_info::IN_STMT); error= do_before_row_operations(table); while (error == 0 && row_start < ev->m_rows_end) @@ -262,7 +262,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli row_start= row_end; } DBUG_EXECUTE_IF("STOP_SLAVE_after_first_Rows_event", - const_cast(rli)->abort_slave= 1;); + const_cast(rli)->abort_slave= 1;); error= do_after_row_operations(table, error); if (!ev->cache_stmt) { @@ -276,7 +276,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli The table def is needed in unpack_row(). */ if (rli->tables_to_lock && ev->get_flags(Rows_log_event::STMT_END_F)) - const_cast(rli)->clear_tables_to_lock(); + const_cast(rli)->clear_tables_to_lock(); if (error) { /* error has occured during the transaction */ @@ -299,7 +299,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli rollback at the caller along with sbr. */ thd->reset_current_stmt_binlog_row_based(); - const_cast(rli)->cleanup_context(thd, error); + const_cast(rli)->cleanup_context(thd, error); thd->query_error= 1; DBUG_RETURN(error); } @@ -329,7 +329,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli problem. When WL#2975 is implemented, just remove the member st_relay_log_info::last_event_start_time and all its occurences. */ - const_cast(rli)->last_event_start_time= my_time(0); + const_cast(rli)->last_event_start_time= my_time(0); } DBUG_RETURN(0); diff --git a/sql/log_event_old.h b/sql/log_event_old.h index ffe87a045cc..81e55097905 100644 --- a/sql/log_event_old.h +++ b/sql/log_event_old.h @@ -31,7 +31,7 @@ class Old_rows_log_event #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) - int do_apply_event(Rows_log_event*,const RELAY_LOG_INFO*); + int do_apply_event(Rows_log_event*,const Relay_log_info*); /* Primitive to prepare for a sequence of row executions. @@ -80,7 +80,7 @@ class Old_rows_log_event RETURN VALUE Error code, if something went wrong, 0 otherwise. */ - virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*, + virtual int do_prepare_row(THD*, Relay_log_info const*, TABLE*, uchar const *row_start, uchar const **row_end) = 0; @@ -131,13 +131,13 @@ private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) // use old definition of do_apply_event() - virtual int do_apply_event(const RELAY_LOG_INFO *rli) + virtual int do_apply_event(const Relay_log_info *rli) { return Old_rows_log_event::do_apply_event(this,rli); } // primitives for old version of do_apply_event() virtual int do_before_row_operations(TABLE *table); virtual int do_after_row_operations(TABLE *table, int error); - virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*, + virtual int do_prepare_row(THD*, Relay_log_info const*, TABLE*, uchar const *row_start, uchar const **row_end); virtual int do_exec_row(TABLE *table); @@ -179,13 +179,13 @@ private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) // use old definition of do_apply_event() - virtual int do_apply_event(const RELAY_LOG_INFO *rli) + virtual int do_apply_event(const Relay_log_info *rli) { return Old_rows_log_event::do_apply_event(this,rli); } // primitives for old version of do_apply_event() virtual int do_before_row_operations(TABLE *table); virtual int do_after_row_operations(TABLE *table, int error); - virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*, + virtual int do_prepare_row(THD*, Relay_log_info const*, TABLE*, uchar const *row_start, uchar const **row_end); virtual int do_exec_row(TABLE *table); #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ @@ -226,13 +226,13 @@ private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) // use old definition of do_apply_event() - virtual int do_apply_event(const RELAY_LOG_INFO *rli) + virtual int do_apply_event(const Relay_log_info *rli) { return Old_rows_log_event::do_apply_event(this,rli); } // primitives for old version of do_apply_event() virtual int do_before_row_operations(TABLE *table); virtual int do_after_row_operations(TABLE *table, int error); - virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*, + virtual int do_prepare_row(THD*, Relay_log_info const*, TABLE*, uchar const *row_start, uchar const **row_end); virtual int do_exec_row(TABLE *table); #endif diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index af6dd590679..ddd63da9adb 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -857,7 +857,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token OUT_SYM /* SQL-2003-R */ %token OWNER_SYM %token PACK_KEYS_SYM -%token PAGE_SYM %token PARAM_MARKER %token PARSER_SYM %token PARTIAL /* SQL-2003-N */ @@ -1010,7 +1009,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token TO_SYM /* SQL-2003-R */ %token TRAILING /* SQL-2003-R */ %token TRANSACTION_SYM -%token TRANSACTIONAL_SYM %token TRIGGERS_SYM %token TRIGGER_SYM /* SQL-2003-R */ %token TRIM /* SQL-2003-N */ @@ -4366,12 +4364,6 @@ create_table_option: Lex->create_info.used_fields|= HA_CREATE_USED_KEY_BLOCK_SIZE; Lex->create_info.key_block_size= $3; } - | TRANSACTIONAL_SYM opt_equal ulong_num - { - Lex->create_info.used_fields|= HA_CREATE_USED_TRANSACTIONAL; - Lex->create_info.transactional= ($3 != 0 ? HA_CHOICE_YES : - HA_CHOICE_NO); - } ; default_charset: @@ -4450,8 +4442,7 @@ row_types: | DYNAMIC_SYM { $$= ROW_TYPE_DYNAMIC; } | COMPRESSED_SYM { $$= ROW_TYPE_COMPRESSED; } | REDUNDANT_SYM { $$= ROW_TYPE_REDUNDANT; } - | COMPACT_SYM { $$= ROW_TYPE_COMPACT; } - | PAGE_SYM { $$= ROW_TYPE_PAGE; }; + | COMPACT_SYM { $$= ROW_TYPE_COMPACT; }; merge_insert_types: NO_SYM { $$= MERGE_INSERT_DISABLED; } @@ -10082,7 +10073,6 @@ keyword_sp: | ONE_SHOT_SYM {} | ONE_SYM {} | PACK_KEYS_SYM {} - | PAGE_SYM {} | PARTIAL {} | PARTITIONING_SYM {} | PARTITIONS_SYM {} @@ -10152,7 +10142,6 @@ keyword_sp: | TEXT_SYM {} | THAN_SYM {} | TRANSACTION_SYM {} - | TRANSACTIONAL_SYM {} | TRIGGERS_SYM {} | TIMESTAMP {} | TIMESTAMP_ADD {} From 013c96ceaabc5059682959d7904ad82ffa648c5f Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 27 Aug 2007 18:44:13 +0400 Subject: [PATCH 011/136] WL#3694 Replication of Invocation and Invoked Features Testing. Bug#29020 Event results not correctly replicated to slave in RBR: partially. mysql-test/suite/rpl/r/rpl_invoked_features.result: Updated result file. mysql-test/suite/rpl/t/disabled.def: removed test cases: rpl_invoked_features and rpl_innodb_mixed_* (alreade were commented out) mysql-test/suite/rpl/t/rpl_invoked_features.test: Added comments, implemented the waiting via include/wait_condition, minor fixes. --- .../suite/rpl/r/rpl_invoked_features.result | 30 +++--- mysql-test/suite/rpl/t/disabled.def | 3 - .../suite/rpl/t/rpl_invoked_features.test | 92 +++++++++++-------- 3 files changed, 69 insertions(+), 56 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_invoked_features.result b/mysql-test/suite/rpl/r/rpl_invoked_features.result index 3bcef762497..502bb040218 100644 --- a/mysql-test/suite/rpl/r/rpl_invoked_features.result +++ b/mysql-test/suite/rpl/r/rpl_invoked_features.result @@ -17,13 +17,13 @@ DROP EVENT IF EXISTS e11; CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=myisam; INSERT INTO t1 VALUES (1,1,'1'); INSERT INTO t1 VALUES (2,2,UUID()); -CREATE TABLE t2 (a INT, b INT, c VARCHAR(64)) ENGINE=myisam; +CREATE TABLE t2 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=myisam; INSERT INTO t2 VALUES (1,1,'1'); INSERT INTO t2 VALUES (2,2,UUID()); CREATE TABLE t11 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=innodb; INSERT INTO t11 VALUES (1,1,'1'); INSERT INTO t11 VALUES (2,2,UUID()); -CREATE TABLE t12 (a INT, b INT, c VARCHAR(64)) ENGINE=innodb; +CREATE TABLE t12 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=innodb; INSERT INTO t12 VALUES (1,1,'1'); INSERT INTO t12 VALUES (2,2,UUID()); @@ -49,21 +49,15 @@ BEGIN UPDATE t12 SET c = ''; UPDATE t13 SET c = ''; END| -CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND ENABLE DO +CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND DISABLE DO BEGIN -DECLARE c INT; -SELECT a INTO c FROM t1 WHERE a < 11 ORDER BY a DESC LIMIT 1; -IF c = 7 THEN +ALTER EVENT e1 DISABLE; CALL p1(10, ''); -END IF; END| -CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND ENABLE DO +CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND DISABLE DO BEGIN -DECLARE c INT; -SELECT a INTO c FROM t11 WHERE a < 11 ORDER BY a DESC LIMIT 1; -IF c = 7 THEN +ALTER EVENT e11 DISABLE; CALL p11(10, ''); -END IF; END| CREATE FUNCTION f1 (x INT) RETURNS VARCHAR(64) BEGIN @@ -78,11 +72,11 @@ RETURN f1(x); END| CREATE PROCEDURE p1 (IN x INT, IN y VARCHAR(64)) BEGIN -INSERT INTO t1 VALUES (x,x,y); +INSERT IGNORE INTO t1 VALUES (x,x,y); END| CREATE PROCEDURE p11 (IN x INT, IN y VARCHAR(64)) BEGIN -INSERT INTO t11 VALUES (x,x,y); +INSERT IGNORE INTO t11 VALUES (x,x,y); END| CREATE TABLE t3 SELECT * FROM v1; @@ -110,6 +104,8 @@ INSERT INTO t11 VALUES(7,7,f2(7)); INSERT INTO t11 VALUES (103,103,''); SET GLOBAL EVENT_SCHEDULER = on; +ALTER EVENT e1 ENABLE; +ALTER EVENT e11 ENABLE; SET GLOBAL EVENT_SCHEDULER = off; SHOW TABLES LIKE 't%'; @@ -138,8 +134,8 @@ PROCEDURE p1 PROCEDURE p11 SELECT event_name, status FROM information_schema.events WHERE event_schema='test'; event_name status -e1 ENABLED -e11 ENABLED +e1 DISABLED +e11 DISABLED SELECT COUNT(*) FROM t1; COUNT(*) @@ -438,6 +434,8 @@ UPDATE t3 SET c=''; UPDATE t11 SET c=''; UPDATE t12 SET c=''; UPDATE t13 SET c=''; +ALTER TABLE t3 ORDER BY a; +ALTER TABLE t13 ORDER BY a; diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index 34a8d6988a9..72b68fa59db 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -11,9 +11,6 @@ ############################################################################## rpl_ddl : BUG#26418 2007-03-01 mleich Slave out of sync after CREATE/DROP TEMPORARY TABLE + ROLLBACK on master -#rpl_innodb_mixed_ddl : Bug #29363 rpl.rpl_innodb_mixed_* test failures -#rpl_innodb_mixed_dml : Bug #29363 rpl.rpl_innodb_mixed_* test failures -rpl_invoked_features : BUG#29020 2007-06-21 Lars Non-deterministic test case rpl_auto_increment_11932 : Bug#29809 2007-07-16 ingo Slave SQL errors in warnings file rpl_stm_extraColmaster_ndb : WL#3915 : Statement-based replication not supported in ndb. Enable test when supported. rpl_row_extraColmaster_ndb : BUG#29549 : Replication of BLOBs fail for NDB diff --git a/mysql-test/suite/rpl/t/rpl_invoked_features.test b/mysql-test/suite/rpl/t/rpl_invoked_features.test index e797e0552ef..0fc5d917566 100644 --- a/mysql-test/suite/rpl/t/rpl_invoked_features.test +++ b/mysql-test/suite/rpl/t/rpl_invoked_features.test @@ -8,10 +8,9 @@ --source include/master-slave.inc --source include/have_innodb.inc - -# -# Define variables used by test case -# +# --disable_warnings/--enable_warnings added before/after query +# if one uses UUID() function because we need to avoid warnings +# for STATEMENT binlog format # Non-transactional engine --let $engine_type= myisam @@ -45,20 +44,24 @@ DROP EVENT IF EXISTS e11; --echo eval CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=$engine_type; ---disable_warnings INSERT INTO t1 VALUES (1,1,'1'); +--disable_warnings INSERT INTO t1 VALUES (2,2,UUID()); -eval CREATE TABLE t2 (a INT, b INT, c VARCHAR(64)) ENGINE=$engine_type; +--enable_warnings +eval CREATE TABLE t2 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=$engine_type; INSERT INTO t2 VALUES (1,1,'1'); +--disable_warnings INSERT INTO t2 VALUES (2,2,UUID()); --enable_warnings eval CREATE TABLE t11 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=$engine_type2; ---disable_warnings INSERT INTO t11 VALUES (1,1,'1'); +--disable_warnings INSERT INTO t11 VALUES (2,2,UUID()); -eval CREATE TABLE t12 (a INT, b INT, c VARCHAR(64)) ENGINE=$engine_type2; +--enable_warnings +eval CREATE TABLE t12 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=$engine_type2; INSERT INTO t12 VALUES (1,1,'1'); +--disable_warnings INSERT INTO t12 VALUES (2,2,UUID()); --enable_warnings @@ -96,22 +99,16 @@ BEGIN END| # Create events which will run every 1 sec -CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND ENABLE DO +CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND DISABLE DO BEGIN - DECLARE c INT; - SELECT a INTO c FROM t1 WHERE a < 11 ORDER BY a DESC LIMIT 1; - IF c = 7 THEN - CALL p1(10, ''); - END IF; + ALTER EVENT e1 DISABLE; + CALL p1(10, ''); END| -CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND ENABLE DO +CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND DISABLE DO BEGIN - DECLARE c INT; - SELECT a INTO c FROM t11 WHERE a < 11 ORDER BY a DESC LIMIT 1; - IF c = 7 THEN - CALL p11(10, ''); - END IF; + ALTER EVENT e11 DISABLE; + CALL p11(10, ''); END| # Create functions and procedures used for events @@ -130,12 +127,12 @@ END| CREATE PROCEDURE p1 (IN x INT, IN y VARCHAR(64)) BEGIN - INSERT INTO t1 VALUES (x,x,y); + INSERT IGNORE INTO t1 VALUES (x,x,y); END| CREATE PROCEDURE p11 (IN x INT, IN y VARCHAR(64)) BEGIN - INSERT INTO t11 VALUES (x,x,y); + INSERT IGNORE INTO t11 VALUES (x,x,y); END| DELIMITER ;| @@ -147,17 +144,24 @@ DELIMITER ;| # Do some actions for non-transactional tables --echo ---disable_warnings CREATE TABLE t3 SELECT * FROM v1; INSERT INTO t1 VALUES (3,3,''); UPDATE t1 SET c='2' WHERE a = 1; +--disable_warnings INSERT INTO t1 VALUES(4,4,f1(4)); +--enable_warnings INSERT INTO t1 VALUES (100,100,''); +--disable_warnings CALL p1(5, UUID()); +--enable_warnings INSERT INTO t1 VALUES (101,101,''); +--disable_warnings INSERT INTO t1 VALUES(6,6,f1(6)); +--enable_warnings INSERT INTO t1 VALUES (102,102,''); +--disable_warnings INSERT INTO t1 VALUES(7,7,f2(7)); +--enable_warnings INSERT INTO t1 VALUES (103,103,''); # Do some actions for transactional tables @@ -165,21 +169,34 @@ INSERT INTO t1 VALUES (103,103,''); CREATE TABLE t13 SELECT * FROM v11; INSERT INTO t11 VALUES (3,3,''); UPDATE t11 SET c='2' WHERE a = 1; +--disable_warnings INSERT INTO t11 VALUES(4,4,f1(4)); -INSERT INTO t11 VALUES (100,100,''); -CALL p11(5, UUID()); -INSERT INTO t11 VALUES (101,101,''); -INSERT INTO t11 VALUES(6,6,f1(6)); -INSERT INTO t11 VALUES (102,102,''); -INSERT INTO t11 VALUES(7,7,f2(7)); -INSERT INTO t11 VALUES (103,103,''); --enable_warnings +INSERT INTO t11 VALUES (100,100,''); +--disable_warnings +CALL p11(5, UUID()); +--enable_warnings +INSERT INTO t11 VALUES (101,101,''); +--disable_warnings +INSERT INTO t11 VALUES(6,6,f1(6)); +--enable_warnings +INSERT INTO t11 VALUES (102,102,''); +--disable_warnings +INSERT INTO t11 VALUES(7,7,f2(7)); +--enable_warnings +INSERT INTO t11 VALUES (103,103,''); # Scheduler is on --echo +# Temporally events fire sequentally due Bug#29020. SET GLOBAL EVENT_SCHEDULER = on; -# Wait 2 sec while events will executed ---sleep 2 +# Wait while events will executed +ALTER EVENT e1 ENABLE; +let $wait_condition= SELECT COUNT(*) = 1 FROM t1 WHERE t1.a = 10; +--source include/wait_condition.inc +ALTER EVENT e11 ENABLE; +let $wait_condition= SELECT COUNT(*) = 1 FROM t11 WHERE t11.a = 10; +--source include/wait_condition.inc SET GLOBAL EVENT_SCHEDULER = off; # Check original objects @@ -234,7 +251,7 @@ SELECT COUNT(*) FROM t13; SELECT a,b FROM t13 ORDER BY a; SELECT a,b FROM v11 ORDER BY a; -# Remove UUID() before comparing +# Remove UUID() before comparing and sort tables --connection master --echo @@ -245,6 +262,9 @@ UPDATE t11 SET c=''; UPDATE t12 SET c=''; UPDATE t13 SET c=''; +ALTER TABLE t3 ORDER BY a; +ALTER TABLE t13 ORDER BY a; + --sync_slave_with_master slave # Compare a data from master and slave @@ -260,13 +280,12 @@ UPDATE t13 SET c=''; # Remove dumps --echo ---exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql ---exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql +#--exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql +#--exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql # Remove tables,views,procedures,functions --connection master --echo ---disable_warnings DROP VIEW IF EXISTS v1,v11; DROP TABLE IF EXISTS t1,t2,t3,t11,t12,t13; DROP PROCEDURE IF EXISTS p1; @@ -275,7 +294,6 @@ DROP FUNCTION IF EXISTS f1; DROP FUNCTION IF EXISTS f2; DROP EVENT IF EXISTS e1; DROP EVENT IF EXISTS e11; ---enable_warnings --sync_slave_with_master slave From ce291125f07df1d77bdba1ff32d8d16f364525ae Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 29 Aug 2007 19:57:10 +0300 Subject: [PATCH 012/136] Bug #30209 rpl_packet.test: Slave_running mismatch (timing bug?) explicit --sleep is removed in favor of wait_for_slave_io_to_stop.inc. The status reporting uses `SHOW SLAVE STATUS' *not* possibly buggy "SHOW STATUS LIKE 'Slave_running'". mysql-test/r/rpl_packet.result: Recording the necessary Slave_IO_Running status at the end of the bug test. It must be No. mysql-test/t/rpl_packet.test: Removing sleep; wait_for_slave_io_to_stop.inc instead; Original "SHOW STATUS LIKE 'Slave_running'" seems to be buggy (to be reported) as with the macro above there were evidence slave IO was stopped indeed but "SHOW STATUS" did not find that (see failures in pb) --- mysql-test/r/rpl_packet.result | 37 +++++++++++++++++++++++++++++++--- mysql-test/t/rpl_packet.test | 10 +++++---- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/rpl_packet.result b/mysql-test/r/rpl_packet.result index 894bc81b08d..9425724b434 100644 --- a/mysql-test/r/rpl_packet.result +++ b/mysql-test/r/rpl_packet.result @@ -21,6 +21,37 @@ STOP SLAVE; START SLAVE; CREATE TABLe `t1` (`f1` LONGTEXT) ENGINE=MyISAM; INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048'); -SHOW STATUS LIKE 'Slave_running'; -Variable_name Value -Slave_running OFF +show slave status; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_MYPORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 2138 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running No +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 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 2138 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # diff --git a/mysql-test/t/rpl_packet.test b/mysql-test/t/rpl_packet.test index f410b561663..84bc5d908bf 100644 --- a/mysql-test/t/rpl_packet.test +++ b/mysql-test/t/rpl_packet.test @@ -64,9 +64,11 @@ CREATE TABLe `t1` (`f1` LONGTEXT) ENGINE=MyISAM; INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048'); # The slave I/O thread must stop after trying to read the above event -connection slave; -sleep 2; -SHOW STATUS LIKE 'Slave_running'; - +connection slave; +--source include/wait_for_slave_io_to_stop.inc +--replace_result $MASTER_MYPORT MASTER_MYPORT +# import is only the 11th column Slave_IO_Running +--replace_column 1 # 8 # 9 # 12 # 23 # 33 # +query_vertical show slave status; # End of tests From 0e466b540cdcdb94fb438753e6f987c26fd9d0dd Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 4 Sep 2007 15:24:04 +0200 Subject: [PATCH 013/136] Disabling rpl_ndb_2other test. mysql-test/suite/rpl_ndb/t/disabled.def: The rpl_ndb_2other test must be disabled until replication correctly handles endianess issues. --- mysql-test/suite/rpl_ndb/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/rpl_ndb/t/disabled.def b/mysql-test/suite/rpl_ndb/t/disabled.def index 90286ecc421..5b102a915ef 100644 --- a/mysql-test/suite/rpl_ndb/t/disabled.def +++ b/mysql-test/suite/rpl_ndb/t/disabled.def @@ -13,6 +13,7 @@ rpl_ndb_2innodb : BUG#19227 2006-04-20 pekka pk delete apparently not replicated rpl_ndb_2myisam : BUG#19227 Seems to pass currently +rpl_ndb_2other : BUG#29549 2007-09-04 rafal test fails on big-endian architectures rpl_ndb_dd_partitions : BUG#19259 2006-04-21 rpl_ndb_dd_partitions fails on s/AMD rpl_ndb_innodb2ndb : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb failed on Solaris for pack_length issue rpl_ndb_myisam2ndb : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb failed on Solaris for pack_length issue From 4b2606f3822c4aee9aa8fb8ee1f711221fb54f10 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 7 Sep 2007 12:04:57 +0400 Subject: [PATCH 014/136] replaced '--exec rm' to '--remove_file' --- mysql-test/suite/rpl/t/rpl_invoked_features.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/rpl/t/rpl_invoked_features.test b/mysql-test/suite/rpl/t/rpl_invoked_features.test index 0fc5d917566..2e69c0fabd9 100644 --- a/mysql-test/suite/rpl/t/rpl_invoked_features.test +++ b/mysql-test/suite/rpl/t/rpl_invoked_features.test @@ -280,8 +280,8 @@ ALTER TABLE t13 ORDER BY a; # Remove dumps --echo -#--exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql -#--exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql +--remove_file $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql +--remove_file $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql # Remove tables,views,procedures,functions --connection master From 431fd2c1aaa4991ae6fe65f321f3ee84397cc0ef Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Sep 2007 11:22:41 -0400 Subject: [PATCH 015/136] BUG#30790 : Suspicious code in rpl_utility.cc This patch clarifies some of the coding choices with documentationa and removes a limitation in the code for future expansion of the CHAR and BINARY fields to length > 255. sql/field.cc: BUG#30790 : Suspicious code in rpl_utility.cc This patch adds an assertion to ensure we are not attempting to encode negative values. sql/log_event.cc: BUG#30790 : Suspicious code in rpl_utility.cc This patch adds comments to help explain the choice of variable types. sql/rpl_utility.cc: BUG#30790 : Suspicious code in rpl_utility.cc This patch removes code from the calc_field_size that is not needed and was ambiguous. Originally intended to future expansion, the code was not needed. Also added are comments to help explain some portions of the code. A change was made to the korr method to use the unsigned version to avoid extended sign problems. sql/rpl_utility.h: BUG#30790 : Suspicious code in rpl_utility.cc This patch corrects some type discrepencies and removes an extra cast. --- sql/field.cc | 1 + sql/log_event.cc | 10 ++++++++++ sql/rpl_utility.cc | 36 +++++++++++++++++++++++------------- sql/rpl_utility.h | 14 +++++++------- 4 files changed, 41 insertions(+), 20 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 1b01d626512..9e86e405512 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6732,6 +6732,7 @@ const uint Field_varstring::MAX_SIZE= UINT_MAX16; int Field_varstring::do_save_field_metadata(uchar *metadata_ptr) { char *ptr= (char *)metadata_ptr; + DBUG_ASSERT(field_length <= 65535); int2store(ptr, field_length); return 2; } diff --git a/sql/log_event.cc b/sql/log_event.cc index 33442baaf90..0dee50c8179 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6469,6 +6469,16 @@ void Rows_log_event::print_helper(FILE *file, data) in the table map are initialized as zero (0). The array size is the same as the columns for the table on the slave. + Additionally, values saved for field metadata on the master are saved as a + string of bytes (uchar) in the binlog. A field may require 1 or more bytes + to store the information. In cases where values require multiple bytes + (e.g. values > 255), the endian-safe methods are used to properly encode + the values on the master and decode them on the slave. When the field + metadata values are captured on the slave, they are stored in an array of + type uint16. This allows the least number of casts to prevent casting bugs + when the field metadata is used in comparisons of field attributes. When + the field metadata is used for calculating addresses in pointer math, the + type used is uint32. */ /** diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index d1ce5bf3b7b..b3ca26d4c2c 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -31,31 +31,34 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const switch (type(col)) { case MYSQL_TYPE_NEWDECIMAL: length= my_decimal_get_binary_size(m_field_metadata[col] >> 8, - m_field_metadata[col] - ((m_field_metadata[col] >> 8) << 8)); + m_field_metadata[col] & 0xff); break; case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: length= m_field_metadata[col]; break; + /* + The cases for SET and ENUM are include for completeness, however + both are mapped to type MYSQL_TYPE_STRING and their real types + are encoded in the field metadata. + */ case MYSQL_TYPE_SET: case MYSQL_TYPE_ENUM: case MYSQL_TYPE_STRING: { - if (((m_field_metadata[col] & 0xff00) == (MYSQL_TYPE_SET << 8)) || - ((m_field_metadata[col] & 0xff00) == (MYSQL_TYPE_ENUM << 8))) + uchar type= m_field_metadata[col] >> 8U; + if ((type == MYSQL_TYPE_SET) || (type == MYSQL_TYPE_ENUM)) length= m_field_metadata[col] & 0x00ff; else { - length= m_field_metadata[col] & 0x00ff; - DBUG_ASSERT(length > 0); - if (length > 255) - { - DBUG_ASSERT(uint2korr(master_data) > 0); - length= uint2korr(master_data) + 2; - } - else - length= (uint) *master_data + 1; + /* + We are reading the actual size from the master_data record + because this field has the actual lengh stored in the first + byte. + */ + length= (uint) *master_data + 1; + DBUG_ASSERT(length != 0); } break; } @@ -95,6 +98,13 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const break; case MYSQL_TYPE_BIT: { + /* + Decode the size of the bit field from the master. + from_len is the length in bytes from the master + from_bit_len is the number of extra bits stored in the master record + If from_bit_len is not 0, add 1 to the length to account for accurate + number of bytes needed. + */ uint from_len= (m_field_metadata[col] >> 8U) & 0x00ff; uint from_bit_len= m_field_metadata[col] & 0x00ff; DBUG_ASSERT(from_bit_len <= 7); @@ -136,7 +146,7 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const length= *master_data; break; case 2: - length= sint2korr(master_data); + length= uint2korr(master_data); break; case 3: length= uint3korr(master_data); diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index 4fd38022da0..f2ab34fe947 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -99,7 +99,7 @@ public: /* These types store a single byte. */ - m_field_metadata[i]= (uchar)field_metadata[index]; + m_field_metadata[i]= field_metadata[index]; index++; break; } @@ -107,14 +107,14 @@ public: case MYSQL_TYPE_ENUM: case MYSQL_TYPE_STRING: { - short int x= field_metadata[index++] << 8U; // real_type - x = x + field_metadata[index++]; // pack or field length + uint16 x= field_metadata[index++] << 8U; // real_type + x+= field_metadata[index++]; // pack or field length m_field_metadata[i]= x; break; } case MYSQL_TYPE_BIT: { - short int x= field_metadata[index++]; + uint16 x= field_metadata[index++]; x = x + (field_metadata[index++] << 8U); m_field_metadata[i]= x; break; @@ -125,14 +125,14 @@ public: These types store two bytes. */ char *ptr= (char *)&field_metadata[index]; - m_field_metadata[i]= sint2korr(ptr); + m_field_metadata[i]= uint2korr(ptr); index= index + 2; break; } case MYSQL_TYPE_NEWDECIMAL: { - short int x= field_metadata[index++] << 8U; // precision - x = x + field_metadata[index++]; // decimals + uint16 x= field_metadata[index++] << 8U; // precision + x+= field_metadata[index++]; // decimals m_field_metadata[i]= x; break; } From 68297025a01fc6094d39a0f1fa01cc079240d026 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 16 Sep 2007 12:07:00 +0200 Subject: [PATCH 016/136] Manual merge fixes/tests for bugs_28960,27417,23333. mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test: follow-up of the previous manual resolve. The snippet is moved into the heading file. mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: results changed mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test: removing explicit offsets from report; appending bug#27417,23333,28960 related snippet, addressing left TODO:s. mysql-test/suite/rpl/r/rpl_packet.result: results changed mysql-test/suite/rpl/t/rpl_packet.test: fixing row/stmt compatibility with #-ing out unneeded values --- .../mix_innodb_myisam_binlog.test | 250 ------------------ .../r/binlog_stm_mix_innodb_myisam.result | 108 ++++++-- .../t/binlog_stm_mix_innodb_myisam.test | 138 +++++++++- mysql-test/suite/rpl/r/rpl_packet.result | 9 +- mysql-test/suite/rpl/t/rpl_packet.test | 2 +- 5 files changed, 223 insertions(+), 284 deletions(-) diff --git a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test index 8d530261662..7141bd1abb9 100644 --- a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test +++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test @@ -316,253 +316,3 @@ disconnect con3; connection con4; select get_lock("a",10); # wait for rollback to finish -# we check that the error code of the "ROLLBACK" event is 0 and not -# ER_SERVER_SHUTDOWN (i.e. disconnection just rolls back transaction -# and does not make slave to stop) ---exec $MYSQL_BINLOG --start-position=547 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output ---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR -eval select -(@a:=load_file("$MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output")) -is not null; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR -eval select -@a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%", -@a not like "%#%error_code=%error_code=%"; -drop table t1, t2; - -# -# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack -# bug #28960 non-trans temp table changes with insert .. select -# not binlogged after rollback -# -# testing appearence of insert into temp_table in binlog. -# There are two branches of execution that require different setup. - -## send_eof() branch - -# prepare - -create temporary table tt (a int unique); -create table ti (a int) engine=innodb; -reset master; -show master status; - -# action - -begin; -insert into ti values (1); -insert into ti values (2) ; -insert into tt select * from ti; -rollback; - -# check - -select count(*) from tt /* 2 */; -show master status; ---replace_column 2 # 5 # -show binlog events from 98; -select count(*) from ti /* zero */; -insert into ti select * from tt; -select * from ti /* that is what slave would miss - a bug */; - - -## send_error() branch -delete from ti; -delete from tt where a=1; -reset master; -show master status; - -# action - -begin; -insert into ti values (1); -insert into ti values (2) /* to make the dup error in the following */; ---error ER_DUP_ENTRY -insert into tt select * from ti /* one affected and error */; -rollback; - -# check - -show master status; ---replace_column 2 # 5 # -show binlog events from 98; -select count(*) from ti /* zero */; -insert into ti select * from tt; -select * from tt /* that is what otherwise slave missed - the bug */; - -drop table ti; - - -# -# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack -# -# Testing asserts: if there is a side effect of modifying non-transactional -# table thd->no_trans_update.stmt must be TRUE; -# the assert is active with debug build -# - ---disable_warnings -drop function if exists bug27417; -drop table if exists t1,t2; ---enable_warnings -# side effect table -CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; -# target tables -CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); - -delimiter |; -create function bug27417(n int) -RETURNS int(11) -begin - insert into t1 values (null); - return n; -end| -delimiter ;| - -reset master; - -# execute - -insert into t2 values (bug27417(1)); -insert into t2 select bug27417(2); -reset master; - ---error ER_DUP_ENTRY -insert into t2 values (bug27417(2)); -show master status; /* only (!) with fixes for #23333 will show there is the query */; -select count(*) from t1 /* must be 3 */; - -reset master; -select count(*) from t2; -delete from t2 where a=bug27417(3); -select count(*) from t2 /* nothing got deleted */; -show master status; /* the query must be in regardless of #23333 */; -select count(*) from t1 /* must be 5 */; - ---enable_info -delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; ---disable_info -select count(*) from t1 /* must be 7 */; - -# function bug27417 remains for the following testing of bug#23333 -drop table t1,t2; - -# -# Bug#23333 using the patch (and the test) for bug#27471 -# throughout the bug tests -# t1 - non-trans side effects gatherer; -# t2 - transactional table; -# -CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; -CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); - - -# -# INSERT -# - -# prepare - - insert into t2 values (1); - reset master; - -# execute - - --error ER_DUP_ENTRY - insert into t2 values (bug27417(1)); - -# check - - show master status /* the offset must denote there is the query */; - select count(*) from t1 /* must be 1 */; - -# -# INSERT SELECT -# - -# prepare - delete from t1; - delete from t2; - insert into t2 values (2); - reset master; - -# execute - - --error ER_DUP_ENTRY - insert into t2 select bug27417(1) union select bug27417(2); - -# check - - show master status /* the offset must denote there is the query */; - select count(*) from t1 /* must be 2 */; - -# -# UPDATE (multi-update see bug#27716) -# - -# prepare - delete from t1; - insert into t3 values (1,1),(2,3),(3,4); - reset master; - -# execute - --error ER_DUP_ENTRY - update t3 set b=b+bug27417(1); - -# check - show master status /* the offset must denote there is the query */; - select count(*) from t1 /* must be 2 */; - - -# -# DELETE (for multi-delete see Bug #29136) -# - -# prepare - delete from t1; - delete from t2; - delete from t3; - insert into t2 values (1); - insert into t3 values (1,1); - create trigger trg_del before delete on t2 for each row - insert into t3 values (bug27417(1), 2); - reset master; - -# execute - --error ER_DUP_ENTRY - delete from t2; -# check - show master status /* the offset must denote there is the query */; - select count(*) from t1 /* must be 1 */; - - -# -# LOAD DATA -# - -# prepare - delete from t1; - create table t4 (a int default 0, b int primary key) engine=innodb; - insert into t4 values (0, 17); - reset master; - -# execute - --error ER_DUP_ENTRY - load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); -# check - select * from t4; - select count(*) from t1 /* must be 2 */; - show master status /* the offset must denote there is the query */; - -# -# bug#23333 cleanup -# - - -drop trigger trg_del; -drop table t1,t2,t3,t4; -drop function bug27417; - - ---echo end of tests 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 5ef36861c30..62c111af19a 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 @@ -380,7 +380,7 @@ select @a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%" @a not like "%#%error_code=%error_code=%" 1 1 drop table t1, t2; -create table tt (a int unique); +create temporary table tt (a int unique); create table ti (a int) engine=innodb; reset master; show master status; @@ -399,18 +399,18 @@ count(*) show master status; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 515 -show binlog events from 106; +show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query 1 # use `test`; BEGIN -master-bin.000001 # Query 1 # use `test`; insert into ti values (1) -master-bin.000001 # Query 1 # use `test`; insert into ti values (2) -master-bin.000001 # Query 1 # use `test`; insert into tt select * from ti -master-bin.000001 # Query 1 # use `test`; ROLLBACK +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Query # # use `test`; insert into ti values (1) +master-bin.000001 # Query # # use `test`; insert into ti values (2) +master-bin.000001 # Query # # use `test`; insert into tt select * from ti +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from ti /* zero */; count(*) 0 insert into ti select * from tt; -select * from ti /* that is what slave would miss - a bug */; +select * from ti /* that is what slave would miss - bug#28960 */; a 1 2 @@ -426,18 +426,11 @@ insert into ti values (2) /* to make the dup error in the following */; insert into tt select * from ti /* one affected and error */; ERROR 23000: Duplicate entry '2' for key 'a' rollback; -Warnings: -Warning 1196 Some non-transactional changed tables couldn't be rolled back show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 589 -show binlog events from 106; +master-bin.000001 106 +show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query 1 # use `test`; BEGIN -master-bin.000001 # Query 1 # use `test`; insert into ti values (1) -master-bin.000001 # Query 1 # use `test`; insert into ti values (2) /* to make the dup error in the following */ -master-bin.000001 # Query 1 # use `test`; insert into tt select * from ti /* one affected and error */ -master-bin.000001 # Query 1 # use `test`; ROLLBACK select count(*) from ti /* zero */; count(*) 0 @@ -446,7 +439,7 @@ select * from tt /* that is what otherwise slave missed - the bug */; a 1 2 -drop table ti,tt; +drop table ti; drop function if exists bug27417; drop table if exists t1,t2; CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; @@ -463,6 +456,10 @@ insert into t2 select bug27417(2); reset master; insert into t2 values (bug27417(2)); ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 222 +/* only (!) with fixes for #23333 will show there is the query */; select count(*) from t1 /* must be 3 */; count(*) 3 @@ -474,6 +471,10 @@ delete from t2 where a=bug27417(3); select count(*) from t2 /* nothing got deleted */; count(*) 2 +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 227 +/* the query must be in regardless of #23333 */; select count(*) from t1 /* must be 5 */; count(*) 5 @@ -482,6 +483,75 @@ affected rows: 0 select count(*) from t1 /* must be 7 */; count(*) 7 -drop function bug27417; drop table t1,t2; +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +insert into t2 values (1); +reset master; +insert into t2 values (bug27417(1)); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 293 +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +delete from t2; +insert into t2 values (2); +reset master; +insert into t2 select bug27417(1) union select bug27417(2); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 332 +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +insert into t3 values (1,1),(2,3),(3,4); +reset master; +update t3 set b=b+bug27417(1); +ERROR 23000: Duplicate entry '4' for key 'b' +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 305 +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +delete from t2; +delete from t3; +insert into t2 values (1); +insert into t3 values (1,1); +create trigger trg_del before delete on t2 for each row +insert into t3 values (bug27417(1), 2); +reset master; +delete from t2; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 335 +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +create table t4 (a int default 0, b int primary key) engine=innodb; +insert into t4 values (0, 17); +reset master; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +ERROR 23000: Duplicate entry '17' for key 'PRIMARY' +select * from t4; +a b +0 17 +select count(*) from t1 /* must be 2 */; +count(*) +2 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 362 +drop trigger trg_del; +drop table t1,t2,t3,t4; +drop function bug27417; end of tests diff --git a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test index 1815f3deb34..826206a1425 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test +++ b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test @@ -36,7 +36,7 @@ drop table t1, t2; # prepare -create table tt (a int unique); +create temporary table tt (a int unique); create table ti (a int) engine=innodb; reset master; show master status; @@ -53,11 +53,10 @@ rollback; select count(*) from tt /* 2 */; show master status; ---replace_column 2 # 5 # -show binlog events from 106; +source include/show_binlog_events.inc; select count(*) from ti /* zero */; insert into ti select * from tt; -select * from ti /* that is what slave would miss - a bug */; +select * from ti /* that is what slave would miss - bug#28960 */; ## send_error() branch @@ -78,13 +77,12 @@ rollback; # check show master status; ---replace_column 2 # 5 # -show binlog events from 106; +source include/show_binlog_events.inc; select count(*) from ti /* zero */; insert into ti select * from tt; select * from tt /* that is what otherwise slave missed - the bug */; -drop table ti,tt; +drop table ti; # @@ -123,16 +121,14 @@ reset master; --error ER_DUP_ENTRY insert into t2 values (bug27417(2)); -#TODO: Andrei: enable this test after 23333 is pushed -#show master status; /* only (!) with fixes for #23333 will show there is the query */; +show master status; /* only (!) with fixes for #23333 will show there is the query */; select count(*) from t1 /* must be 3 */; reset master; select count(*) from t2; delete from t2 where a=bug27417(3); select count(*) from t2 /* nothing got deleted */; -#TODO: Andrei: enable this test after 23333 is pushed -#show master status; /* the query must be in regardless of #23333 */; +show master status; /* the query must be in regardless of #23333 */; select count(*) from t1 /* must be 5 */; --enable_info @@ -140,7 +136,125 @@ delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; --disable_info select count(*) from t1 /* must be 7 */; -drop function bug27417; +# function bug27417 remains for the following testing of bug#23333 drop table t1,t2; +# +# Bug#23333 using the patch (and the test) for bug#27471 +# throughout the bug tests +# t1 - non-trans side effects gatherer; +# t2 - transactional table; +# +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); + + +# +# INSERT +# + +# prepare + + insert into t2 values (1); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 values (bug27417(1)); + +# check + + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 1 */; + +# +# INSERT SELECT +# + +# prepare + delete from t1; + delete from t2; + insert into t2 values (2); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 select bug27417(1) union select bug27417(2); + +# check + + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 2 */; + +# +# UPDATE (multi-update see bug#27716) +# + +# prepare + delete from t1; + insert into t3 values (1,1),(2,3),(3,4); + reset master; + +# execute + --error ER_DUP_ENTRY + update t3 set b=b+bug27417(1); + +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 2 */; + + +# +# DELETE (for multi-delete see Bug #29136) +# + +# prepare + delete from t1; + delete from t2; + delete from t3; + insert into t2 values (1); + insert into t3 values (1,1); + create trigger trg_del before delete on t2 for each row + insert into t3 values (bug27417(1), 2); + reset master; + +# execute + --error ER_DUP_ENTRY + delete from t2; +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 1 */; + + +# +# LOAD DATA +# + +# prepare + delete from t1; + create table t4 (a int default 0, b int primary key) engine=innodb; + insert into t4 values (0, 17); + reset master; + +# execute + --error ER_DUP_ENTRY + load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +# check + select * from t4; + select count(*) from t1 /* must be 2 */; + show master status /* the offset must denote there is the query */; + +# +# bug#23333 cleanup +# + + +drop trigger trg_del; +drop table t1,t2,t3,t4; +drop function bug27417; + + --echo end of tests diff --git a/mysql-test/suite/rpl/r/rpl_packet.result b/mysql-test/suite/rpl/r/rpl_packet.result index c23b990acd4..dd56eb0471c 100644 --- a/mysql-test/suite/rpl/r/rpl_packet.result +++ b/mysql-test/suite/rpl/r/rpl_packet.result @@ -34,7 +34,7 @@ Master_User root Master_Port MASTER_MYPORT Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 2138 +Read_Master_Log_Pos # Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -49,7 +49,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 2138 +Exec_Master_Log_Pos # Relay_Log_Space # Until_Condition None Until_Log_File @@ -61,3 +61,8 @@ Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test index a4b290f89a3..0e17ae3144c 100644 --- a/mysql-test/suite/rpl/t/rpl_packet.test +++ b/mysql-test/suite/rpl/t/rpl_packet.test @@ -70,7 +70,7 @@ connection slave; --source include/wait_for_slave_io_to_stop.inc --replace_result $MASTER_MYPORT MASTER_MYPORT # import is only the 11th column Slave_IO_Running ---replace_column 1 # 8 # 9 # 12 # 23 # 33 # +--replace_column 1 # 7 # 8 # 9 # 12 # 22 # 23 # 33 # query_vertical show slave status; # End of tests From 14f5002d83fc4fe242f311501259955651214122 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 16 Sep 2007 18:16:40 +0200 Subject: [PATCH 017/136] Merge: bug#27417,23333 manual work for fixing tests and a source code. mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: results changed due to 1. tt table made temporary is it's supposed to; 2. show master status is turned into binlog pos masking-out macro 3. merge defect for select_insert::abort() mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test: masking-out binlog postions in the results via source include/show_binlog_events.inc; sql/sql_insert.cc: merging defect in not applied hunk for select_insert::abort() is fixed --- .../r/binlog_stm_mix_innodb_myisam.result | 77 +++++++++++++------ .../t/binlog_stm_mix_innodb_myisam.test | 16 ++-- sql/sql_insert.cc | 19 ++--- 3 files changed, 71 insertions(+), 41 deletions(-) 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 62c111af19a..564fa8d86bd 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 @@ -426,11 +426,18 @@ insert into ti values (2) /* to make the dup error in the following */; insert into tt select * from ti /* one affected and error */; ERROR 23000: Duplicate entry '2' for key 'a' rollback; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 106 +master-bin.000001 589 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Query # # use `test`; insert into ti values (1) +master-bin.000001 # Query # # use `test`; insert into ti values (2) /* to make the dup error in the following */ +master-bin.000001 # Query # # use `test`; insert into tt select * from ti /* one affected and error */ +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from ti /* zero */; count(*) 0 @@ -456,10 +463,11 @@ insert into t2 select bug27417(2); reset master; insert into t2 values (bug27417(2)); ERROR 23000: Duplicate entry '2' for key 'PRIMARY' -show master status; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 222 -/* only (!) with fixes for #23333 will show there is the query */; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F select count(*) from t1 /* must be 3 */; count(*) 3 @@ -471,10 +479,11 @@ delete from t2 where a=bug27417(3); select count(*) from t2 /* nothing got deleted */; count(*) 2 -show master status; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 227 -/* the query must be in regardless of #23333 */; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F select count(*) from t1 /* must be 5 */; count(*) 5 @@ -491,9 +500,12 @@ insert into t2 values (1); reset master; insert into t2 values (bug27417(1)); ERROR 23000: Duplicate entry '1' for key 'PRIMARY' -show master status /* the offset must denote there is the query */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 293 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) 1 @@ -503,9 +515,13 @@ insert into t2 values (2); reset master; insert into t2 select bug27417(1) union select bug27417(2); ERROR 23000: Duplicate entry '2' for key 'PRIMARY' -show master status /* the offset must denote there is the query */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 332 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 2 */; count(*) 2 @@ -514,9 +530,13 @@ insert into t3 values (1,1),(2,3),(3,4); reset master; update t3 set b=b+bug27417(1); ERROR 23000: Duplicate entry '4' for key 'b' -show master status /* the offset must denote there is the query */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 305 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t1) +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 select count(*) from t1 /* must be 2 */; count(*) 2 @@ -530,9 +550,13 @@ insert into t3 values (bug27417(1), 2); reset master; delete from t2; ERROR 23000: Duplicate entry '1' for key 'PRIMARY' -show master status /* the offset must denote there is the query */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 335 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) 1 @@ -548,9 +572,14 @@ a b select count(*) from t1 /* must be 2 */; count(*) 2 -show master status /* the offset must denote there is the query */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 362 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t1) +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`; ROLLBACK drop trigger trg_del; drop table t1,t2,t3,t4; drop function bug27417; diff --git a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test index 826206a1425..14397f85c38 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test +++ b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test @@ -120,15 +120,15 @@ insert into t2 select bug27417(2); reset master; --error ER_DUP_ENTRY -insert into t2 values (bug27417(2)); -show master status; /* only (!) with fixes for #23333 will show there is the query */; +insert into t2 values (bug27417(2)); +source include/show_binlog_events.inc; #only (!) with fixes for #23333 will show there is the query select count(*) from t1 /* must be 3 */; reset master; select count(*) from t2; delete from t2 where a=bug27417(3); select count(*) from t2 /* nothing got deleted */; -show master status; /* the query must be in regardless of #23333 */; +source include/show_binlog_events.inc; # the query must be in regardless of #23333 select count(*) from t1 /* must be 5 */; --enable_info @@ -166,7 +166,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # check - show master status /* the offset must denote there is the query */; + source include/show_binlog_events.inc; # must be event of the query select count(*) from t1 /* must be 1 */; # @@ -186,7 +186,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # check - show master status /* the offset must denote there is the query */; + source include/show_binlog_events.inc; # must be events of the query select count(*) from t1 /* must be 2 */; # @@ -203,7 +203,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); update t3 set b=b+bug27417(1); # check - show master status /* the offset must denote there is the query */; + source include/show_binlog_events.inc; # must be events of the query select count(*) from t1 /* must be 2 */; @@ -225,7 +225,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); --error ER_DUP_ENTRY delete from t2; # check - show master status /* the offset must denote there is the query */; + source include/show_binlog_events.inc; # must be events of the query select count(*) from t1 /* must be 1 */; @@ -245,7 +245,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # check select * from t4; select count(*) from t1 /* must be 2 */; - show master status /* the offset must denote there is the query */; + source include/show_binlog_events.inc; # must be events of the query # # bug#23333 cleanup diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 16ad280c690..2f899a35179 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3163,6 +3163,7 @@ void select_insert::abort() { */ if (table) { + bool changed, transactional_table; /* If we are not in prelocked mode, we end the bulk insert started before. @@ -3184,20 +3185,20 @@ void select_insert::abort() { If table creation failed, the number of rows modified will also be zero, so no check for that is made. */ - if (info.copied || info.deleted || info.updated) + changed= (info.copied || info.deleted || info.updated); + transactional_table= table->file->has_transactions(); + if (thd->transaction.stmt.modified_non_trans_table) { - DBUG_ASSERT(table != NULL); - if (!table->file->has_transactions()) - { if (mysql_bin_log.is_open()) thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - table->file->has_transactions(), FALSE); - if (!thd->current_stmt_binlog_row_based && !table->s->tmp_table && - !can_rollback_data()) + transactional_table, FALSE); + if (!thd->current_stmt_binlog_row_based && !can_rollback_data()) thd->transaction.all.modified_non_trans_table= TRUE; - query_cache_invalidate3(thd, table, 1); - } + if (changed) + query_cache_invalidate3(thd, table, 1); } + DBUG_ASSERT(transactional_table || !changed || + thd->transaction.stmt.modified_non_trans_table); table->file->ha_release_auto_increment(); } From fe24b460c40ef994d9655b3682dfe17f1f6f4339 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Sep 2007 12:31:10 +0200 Subject: [PATCH 018/136] Merge: bug@27417,23333 and bug#28960 tests with 5.1 mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result: results changed mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: results changed mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test: calling included file with testing bug#27417,23333. bug#28960 is not an rbr bug. mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test: moved SF() with side effects bugs to a separate includable file. This test verifies STMT format whereas binlog_row test is reposible for ROW format. mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test: sourced part for bugs with SF() etc having side effects of midifying non-transactional tables. --- .../mix_innodb_myisam_side_effects.test | 234 ++++++++++++++++++ .../r/binlog_row_mix_innodb_myisam.result | 186 ++++++++++++++ .../r/binlog_stm_mix_innodb_myisam.result | 45 ++-- .../t/binlog_row_mix_innodb_myisam.test | 2 + .../t/binlog_stm_mix_innodb_myisam.test | 234 +----------------- 5 files changed, 443 insertions(+), 258 deletions(-) create mode 100644 mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test diff --git a/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test b/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test new file mode 100644 index 00000000000..6c961c4694d --- /dev/null +++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test @@ -0,0 +1,234 @@ +# the file to be sourced from binlog.binlog_mix_innodb_myisam + +# +# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack +# bug #28960 non-trans temp table changes with insert .. select +# not binlogged after rollback +# +# testing appearence of insert into temp_table in binlog. +# There are two branches of execution that require different setup. + +# checking binlog content filled with row-based events due to +# a used stored function modifies non-transactional table + +## send_eof() branch + +# prepare + +create temporary table tt (a int unique); +create table ti (a int) engine=innodb; +reset master; +show master status; + +# action + +begin; +insert into ti values (1); +insert into ti values (2) ; +insert into tt select * from ti; +rollback; + +# check + +select count(*) from tt /* 2 */; +show master status; +source include/show_binlog_events.inc; +select count(*) from ti /* zero */; +insert into ti select * from tt; +select * from ti /* that is what slave would miss - bug#28960 */; + + +## send_error() branch +delete from ti; +delete from tt where a=1; +reset master; +show master status; + +# action + +begin; +insert into ti values (1); +insert into ti values (2) /* to make the dup error in the following */; +--error ER_DUP_ENTRY +insert into tt select * from ti /* one affected and error */; +rollback; + +# check + +show master status; +source include/show_binlog_events.inc; # nothing in binlog with row bilog format +select count(*) from ti /* zero */; +insert into ti select * from tt; +select * from tt /* that is what otherwise slave missed - the bug */; + +drop table ti; + + +# +# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack +# +# Testing asserts: if there is a side effect of modifying non-transactional +# table thd->no_trans_update.stmt must be TRUE; +# the assert is active with debug build +# + +--disable_warnings +drop function if exists bug27417; +drop table if exists t1,t2; +--enable_warnings +# side effect table +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +# target tables +CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); + +delimiter |; +create function bug27417(n int) +RETURNS int(11) +begin + insert into t1 values (null); + return n; +end| +delimiter ;| + +reset master; + +# execute + +insert into t2 values (bug27417(1)); +insert into t2 select bug27417(2); +reset master; + +--error ER_DUP_ENTRY +insert into t2 values (bug27417(2)); +source include/show_binlog_events.inc; #only (!) with fixes for #23333 will show there is the query +select count(*) from t1 /* must be 3 */; + +reset master; +select count(*) from t2; +delete from t2 where a=bug27417(3); +select count(*) from t2 /* nothing got deleted */; +source include/show_binlog_events.inc; # the query must be in regardless of #23333 +select count(*) from t1 /* must be 5 */; + +--enable_info +delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; +--disable_info +select count(*) from t1 /* must be 7 */; + +# function bug27417 remains for the following testing of bug#23333 +drop table t1,t2; + +# +# Bug#23333 using the patch (and the test) for bug#27471 +# throughout the bug tests +# t1 - non-trans side effects gatherer; +# t2 - transactional table; +# +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); + + +# +# INSERT +# + +# prepare + + insert into t2 values (1); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 values (bug27417(1)); + +# check + + source include/show_binlog_events.inc; # must be event of the query + select count(*) from t1 /* must be 1 */; + +# +# INSERT SELECT +# + +# prepare + delete from t1; + delete from t2; + insert into t2 values (2); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 select bug27417(1) union select bug27417(2); + +# check + + source include/show_binlog_events.inc; # must be events of the query + select count(*) from t1 /* must be 2 */; + +# +# UPDATE (multi-update see bug#27716) +# + +# prepare + delete from t1; + insert into t3 values (1,1),(2,3),(3,4); + reset master; + +# execute + --error ER_DUP_ENTRY + update t3 set b=b+bug27417(1); + +# check + source include/show_binlog_events.inc; # must be events of the query + select count(*) from t1 /* must be 2 */; + + +# +# DELETE (for multi-delete see Bug #29136) +# + +# prepare + delete from t1; + delete from t2; + delete from t3; + insert into t2 values (1); + insert into t3 values (1,1); + create trigger trg_del before delete on t2 for each row + insert into t3 values (bug27417(1), 2); + reset master; + +# execute + --error ER_DUP_ENTRY + delete from t2; +# check + source include/show_binlog_events.inc; # must be events of the query + select count(*) from t1 /* must be 1 */; + + +# +# LOAD DATA +# + +# prepare + delete from t1; + create table t4 (a int default 0, b int primary key) engine=innodb; + insert into t4 values (0, 17); + reset master; + +# execute + --error ER_DUP_ENTRY + load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +# check + select * from t4; + select count(*) from t1 /* must be 2 */; + source include/show_binlog_events.inc; # must be events of the query + +# +# bug#23333 cleanup +# +drop trigger trg_del; +drop table t1,t2,t3,t4; +drop function bug27417; 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 6ac942176c7..8022f2b1e10 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 @@ -413,3 +413,189 @@ select @a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%" @a not like "%#%error_code=%error_code=%" 1 1 drop table t1, t2; +create temporary table tt (a int unique); +create table ti (a int) engine=innodb; +reset master; +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 106 +begin; +insert into ti values (1); +insert into ti values (2) ; +insert into tt select * from ti; +rollback; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +select count(*) from tt /* 2 */; +count(*) +2 +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 395 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Table_map # # table_id: # (test.ti) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.ti) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from ti /* zero */; +count(*) +0 +insert into ti select * from tt; +select * from ti /* that is what slave would miss - bug#28960 */; +a +1 +2 +delete from ti; +delete from tt where a=1; +reset master; +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 106 +begin; +insert into ti values (1); +insert into ti values (2) /* to make the dup error in the following */; +insert into tt select * from ti /* one affected and error */; +ERROR 23000: Duplicate entry '2' for key 'a' +rollback; +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 106 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +select count(*) from ti /* zero */; +count(*) +0 +insert into ti select * from tt; +select * from tt /* that is what otherwise slave missed - the bug */; +a +1 +2 +drop table ti; +drop function if exists bug27417; +drop table if exists t1,t2; +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); +create function bug27417(n int) +RETURNS int(11) +begin +insert into t1 values (null); +return n; +end| +reset master; +insert into t2 values (bug27417(1)); +insert into t2 select bug27417(2); +reset master; +insert into t2 values (bug27417(2)); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(2)) +select count(*) from t1 /* must be 3 */; +count(*) +3 +reset master; +select count(*) from t2; +count(*) +2 +delete from t2 where a=bug27417(3); +select count(*) from t2 /* nothing got deleted */; +count(*) +2 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=4 +master-bin.000001 # Query # # use `test`; delete from t2 where a=bug27417(3) +select count(*) from t1 /* must be 5 */; +count(*) +5 +delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; +affected rows: 0 +select count(*) from t1 /* must be 7 */; +count(*) +7 +drop table t1,t2; +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +insert into t2 values (1); +reset master; +insert into t2 values (bug27417(1)); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=1 +master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(1)) +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +delete from t2; +insert into t2 values (2); +reset master; +insert into t2 select bug27417(1) union select bug27417(2); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=2 +master-bin.000001 # Query # # use `test`; insert into t2 select bug27417(1) union select bug27417(2) +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +insert into t3 values (1,1),(2,3),(3,4); +reset master; +update t3 set b=b+bug27417(1); +ERROR 23000: Duplicate entry '4' for key 'b' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=4 +master-bin.000001 # Query # # use `test`; update t3 set b=b+bug27417(1) +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +delete from t2; +delete from t3; +insert into t2 values (1); +insert into t3 values (1,1); +create trigger trg_del before delete on t2 for each row +insert into t3 values (bug27417(1), 2); +reset master; +delete from t2; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Query # # use `test`; delete from t2 +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +create table t4 (a int default 0, b int primary key) engine=innodb; +insert into t4 values (0, 17); +reset master; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +ERROR 23000: Duplicate entry '17' for key 'PRIMARY' +select * from t4; +a b +0 17 +select count(*) from t1 /* must be 2 */; +count(*) +2 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12 +master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=1 +master-bin.000001 # Query # # use `test`; ROLLBACK +drop trigger trg_del; +drop table t1,t2,t3,t4; +drop function bug27417; 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 564fa8d86bd..9c580b2312e 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 @@ -380,6 +380,7 @@ select @a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%" @a not like "%#%error_code=%error_code=%" 1 1 drop table t1, t2; +set @@session.binlog_format=statement; create temporary table tt (a int unique); create table ti (a int) engine=innodb; reset master; @@ -465,9 +466,8 @@ insert into t2 values (bug27417(2)); ERROR 23000: Duplicate entry '2' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(2)) select count(*) from t1 /* must be 3 */; count(*) 3 @@ -481,9 +481,8 @@ count(*) 2 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=4 +master-bin.000001 # Query # # use `test`; delete from t2 where a=bug27417(3) select count(*) from t1 /* must be 5 */; count(*) 5 @@ -502,9 +501,8 @@ insert into t2 values (bug27417(1)); ERROR 23000: Duplicate entry '1' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=1 +master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(1)) master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) @@ -517,10 +515,8 @@ insert into t2 select bug27417(1) union select bug27417(2); ERROR 23000: Duplicate entry '2' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=2 +master-bin.000001 # Query # # use `test`; insert into t2 select bug27417(1) union select bug27417(2) master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 2 */; count(*) @@ -532,11 +528,8 @@ update t3 set b=b+bug27417(1); ERROR 23000: Duplicate entry '4' for key 'b' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t3) -master-bin.000001 # Table_map # # table_id: # (test.t1) -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 # Intvar # # INSERT_ID=4 +master-bin.000001 # Query # # use `test`; update t3 set b=b+bug27417(1) select count(*) from t1 /* must be 2 */; count(*) 2 @@ -552,10 +545,8 @@ delete from t2; ERROR 23000: Duplicate entry '1' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t3) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Query # # use `test`; delete from t2 master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) @@ -574,13 +565,13 @@ count(*) 2 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t4) -master-bin.000001 # Table_map # # table_id: # (test.t1) -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 # Intvar # # INSERT_ID=7 +master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12 +master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=1 master-bin.000001 # Query # # use `test`; ROLLBACK drop trigger trg_del; drop table t1,t2,t3,t4; drop function bug27417; +set @@session.binlog_format=@@global.binlog_format; end of tests diff --git a/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test b/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test index 7b7753a487e..3148cc50fd0 100644 --- a/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test +++ b/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test @@ -31,3 +31,5 @@ eval select @a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%", @a not like "%#%error_code=%error_code=%"; drop table t1, t2; + +-- source extra/binlog_tests/mix_innodb_myisam_side_effects.test diff --git a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test index 14397f85c38..e7149e03b87 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test +++ b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test @@ -24,237 +24,9 @@ eval select drop table t1, t2; -# -# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack -# bug #28960 non-trans temp table changes with insert .. select -# not binlogged after rollback -# -# testing appearence of insert into temp_table in binlog. -# There are two branches of execution that require different setup. - -## send_eof() branch - -# prepare - -create temporary table tt (a int unique); -create table ti (a int) engine=innodb; -reset master; -show master status; - -# action - -begin; -insert into ti values (1); -insert into ti values (2) ; -insert into tt select * from ti; -rollback; - -# check - -select count(*) from tt /* 2 */; -show master status; -source include/show_binlog_events.inc; -select count(*) from ti /* zero */; -insert into ti select * from tt; -select * from ti /* that is what slave would miss - bug#28960 */; - - -## send_error() branch -delete from ti; -delete from tt where a=1; -reset master; -show master status; - -# action - -begin; -insert into ti values (1); -insert into ti values (2) /* to make the dup error in the following */; ---error ER_DUP_ENTRY -insert into tt select * from ti /* one affected and error */; -rollback; - -# check - -show master status; -source include/show_binlog_events.inc; -select count(*) from ti /* zero */; -insert into ti select * from tt; -select * from tt /* that is what otherwise slave missed - the bug */; - -drop table ti; - - -# -# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack -# -# Testing asserts: if there is a side effect of modifying non-transactional -# table thd->no_trans_update.stmt must be TRUE; -# the assert is active with debug build -# - ---disable_warnings -drop function if exists bug27417; -drop table if exists t1,t2; ---enable_warnings -# side effect table -CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; -# target tables -CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); - -delimiter |; -create function bug27417(n int) -RETURNS int(11) -begin - insert into t1 values (null); - return n; -end| -delimiter ;| - -reset master; - -# execute - -insert into t2 values (bug27417(1)); -insert into t2 select bug27417(2); -reset master; - ---error ER_DUP_ENTRY -insert into t2 values (bug27417(2)); -source include/show_binlog_events.inc; #only (!) with fixes for #23333 will show there is the query -select count(*) from t1 /* must be 3 */; - -reset master; -select count(*) from t2; -delete from t2 where a=bug27417(3); -select count(*) from t2 /* nothing got deleted */; -source include/show_binlog_events.inc; # the query must be in regardless of #23333 -select count(*) from t1 /* must be 5 */; - ---enable_info -delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; ---disable_info -select count(*) from t1 /* must be 7 */; - -# function bug27417 remains for the following testing of bug#23333 -drop table t1,t2; - -# -# Bug#23333 using the patch (and the test) for bug#27471 -# throughout the bug tests -# t1 - non-trans side effects gatherer; -# t2 - transactional table; -# -CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; -CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); - - -# -# INSERT -# - -# prepare - - insert into t2 values (1); - reset master; - -# execute - - --error ER_DUP_ENTRY - insert into t2 values (bug27417(1)); - -# check - - source include/show_binlog_events.inc; # must be event of the query - select count(*) from t1 /* must be 1 */; - -# -# INSERT SELECT -# - -# prepare - delete from t1; - delete from t2; - insert into t2 values (2); - reset master; - -# execute - - --error ER_DUP_ENTRY - insert into t2 select bug27417(1) union select bug27417(2); - -# check - - source include/show_binlog_events.inc; # must be events of the query - select count(*) from t1 /* must be 2 */; - -# -# UPDATE (multi-update see bug#27716) -# - -# prepare - delete from t1; - insert into t3 values (1,1),(2,3),(3,4); - reset master; - -# execute - --error ER_DUP_ENTRY - update t3 set b=b+bug27417(1); - -# check - source include/show_binlog_events.inc; # must be events of the query - select count(*) from t1 /* must be 2 */; - - -# -# DELETE (for multi-delete see Bug #29136) -# - -# prepare - delete from t1; - delete from t2; - delete from t3; - insert into t2 values (1); - insert into t3 values (1,1); - create trigger trg_del before delete on t2 for each row - insert into t3 values (bug27417(1), 2); - reset master; - -# execute - --error ER_DUP_ENTRY - delete from t2; -# check - source include/show_binlog_events.inc; # must be events of the query - select count(*) from t1 /* must be 1 */; - - -# -# LOAD DATA -# - -# prepare - delete from t1; - create table t4 (a int default 0, b int primary key) engine=innodb; - insert into t4 values (0, 17); - reset master; - -# execute - --error ER_DUP_ENTRY - load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); -# check - select * from t4; - select count(*) from t1 /* must be 2 */; - source include/show_binlog_events.inc; # must be events of the query - -# -# bug#23333 cleanup -# - - -drop trigger trg_del; -drop table t1,t2,t3,t4; -drop function bug27417; +set @@session.binlog_format=statement; +-- source extra/binlog_tests/mix_innodb_myisam_side_effects.test +set @@session.binlog_format=@@global.binlog_format; --echo end of tests From 08c5f2678480cdc9a52f65df77f4af93d4007265 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Sep 2007 08:13:52 +0200 Subject: [PATCH 019/136] Fixing bug in test in that a database was not dropped and was visible in following tests. mysql-test/suite/rpl/r/rpl_bug31076.result: Result file change. mysql-test/suite/rpl/t/rpl_bug31076.test: Dropping database so that following tests don't see it. --- mysql-test/suite/rpl/r/rpl_bug31076.result | 1 + mysql-test/suite/rpl/t/rpl_bug31076.test | 3 +++ 2 files changed, 4 insertions(+) diff --git a/mysql-test/suite/rpl/r/rpl_bug31076.result b/mysql-test/suite/rpl/r/rpl_bug31076.result index c991b2f1946..2d6bed37901 100644 --- a/mysql-test/suite/rpl/r/rpl_bug31076.result +++ b/mysql-test/suite/rpl/r/rpl_bug31076.result @@ -61,3 +61,4 @@ visits_id myid src ip cc org ref time host entry visit_exit user_id visit_start SELECT * FROM visits_events; event_id visit_id timestamp src data visits_events_id 20000 21231038 2007-09-18 03:59:02 Downloads/MySQL-4.1/mysql-4.1.12a-win32.zip 33712207 +DROP DATABASE track; diff --git a/mysql-test/suite/rpl/t/rpl_bug31076.test b/mysql-test/suite/rpl/t/rpl_bug31076.test index 6cb8cc0d902..95fb1e5fb96 100644 --- a/mysql-test/suite/rpl/t/rpl_bug31076.test +++ b/mysql-test/suite/rpl/t/rpl_bug31076.test @@ -111,3 +111,6 @@ VALUES ('3m3l4rhs6do0sf5p1i9lr94g928a272v', '', '', INET_ATON('71.118.124.98'), SELECT * FROM visits; SELECT * FROM visits_events; + +DROP DATABASE track; +sync_slave_with_master; From 184cddab1328c755e9076028db6ab1deaeed675b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Sep 2007 21:59:17 +0200 Subject: [PATCH 020/136] Bug #26000 SHOW SLAVE STATUS can crash mysqld during shutdown process active_mi has been reset (shutdown) at the time of quering with SHOW SLAVE STATUS so that at handling of SHOW an attempt to read its members segfaults. Fixed with checking the value of active_mi before to call show_master_info() Merely send_ok() is invoked when active_mi does not exist. A test can not be easiely written. Notice, there are more analogical cases in the code which require a similar treatment (to be reported as a bug separately). sql/sql_parse.cc: Ignore reporting and send only OK if master info struct has been destoyed. As this must be at shutdown merely a warning is sent to the client. --- sql/sql_parse.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 58f5ffc5235..075ce2c9e8c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2844,7 +2844,16 @@ mysql_execute_command(THD *thd) if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) goto error; pthread_mutex_lock(&LOCK_active_mi); - res = show_master_info(thd,active_mi); + if (active_mi != NULL) + { + res = show_master_info(thd, active_mi); + } + else + { + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, + "the master info structure does not exist"); + send_ok(thd); + } pthread_mutex_unlock(&LOCK_active_mi); break; } From 1ff1ff869ca7730b272c33765f1c7e1cff90c8a1 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 1 Oct 2007 15:35:42 +0500 Subject: [PATCH 021/136] Bug#30315 Character sets: insertion of euckr code value 0xa141 fails Problem: some valid euc-kr characters were rejected because condition checking multi-byte tail didn't allow multi-byte characters having the second byte in the ranges [0x41..0x5A] and [0x61..0x7A]. Fix: allow these byte ranges for mb tails mysql-test/r/ctype_euckr.result: Adding tests mysql-test/t/ctype_euckr.test: Adding tests strings/ctype-euc_kr.c: Fixing wrong tail character pattern --- mysql-test/r/ctype_euckr.result | 41 +++++++++++++++++++++++++++++++++ mysql-test/t/ctype_euckr.test | 23 ++++++++++++++++++ strings/ctype-euc_kr.c | 27 ++++++++++++++++++---- 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/ctype_euckr.result b/mysql-test/r/ctype_euckr.result index 6017bc07763..57e3e2ed8f8 100644 --- a/mysql-test/r/ctype_euckr.result +++ b/mysql-test/r/ctype_euckr.result @@ -165,3 +165,44 @@ hex(a) A2E6 FEF7 DROP TABLE t1; +create table t1 (s1 varchar(5) character set euckr); +insert into t1 values (0xA141); +insert into t1 values (0xA15A); +insert into t1 values (0xA161); +insert into t1 values (0xA17A); +insert into t1 values (0xA181); +insert into t1 values (0xA1FE); +insert into t1 values (0xA140); +Warnings: +Warning 1366 Incorrect string value: '\xA1@' for column 's1' at row 1 +insert into t1 values (0xA15B); +Warnings: +Warning 1366 Incorrect string value: '\xA1[' for column 's1' at row 1 +insert into t1 values (0xA160); +Warnings: +Warning 1366 Incorrect string value: '\xA1`' for column 's1' at row 1 +insert into t1 values (0xA17B); +Warnings: +Warning 1366 Incorrect string value: '\xA1{' for column 's1' at row 1 +insert into t1 values (0xA180); +Warnings: +Warning 1366 Incorrect string value: '\xA1\x80' for column 's1' at row 1 +insert into t1 values (0xA1FF); +Warnings: +Warning 1366 Incorrect string value: '\xA1\xFF' for column 's1' at row 1 +select hex(s1), hex(convert(s1 using utf8)) from t1 order by binary s1; +hex(s1) hex(convert(s1 using utf8)) + + + + + + +A141 ECA2A5 +A15A ECA381 +A161 ECA382 +A17A ECA3A5 +A181 ECA3A6 +A1FE EFBFA2 +drop table t1; +End of 5.0 tests diff --git a/mysql-test/t/ctype_euckr.test b/mysql-test/t/ctype_euckr.test index 56939817b2f..05e4b04eded 100644 --- a/mysql-test/t/ctype_euckr.test +++ b/mysql-test/t/ctype_euckr.test @@ -31,3 +31,26 @@ SELECT hex(a) FROM t1 ORDER BY a; DROP TABLE t1; # End of 4.1 tests + +# +#Bug #30315 Character sets: insertion of euckr code value 0xa141 fails +# +create table t1 (s1 varchar(5) character set euckr); +# Insert some valid characters +insert into t1 values (0xA141); +insert into t1 values (0xA15A); +insert into t1 values (0xA161); +insert into t1 values (0xA17A); +insert into t1 values (0xA181); +insert into t1 values (0xA1FE); +# Insert some invalid characters +insert into t1 values (0xA140); +insert into t1 values (0xA15B); +insert into t1 values (0xA160); +insert into t1 values (0xA17B); +insert into t1 values (0xA180); +insert into t1 values (0xA1FF); +select hex(s1), hex(convert(s1 using utf8)) from t1 order by binary s1; +drop table t1; + +--echo End of 5.0 tests diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c index abaa8f1a516..1aaf65c98b3 100644 --- a/strings/ctype-euc_kr.c +++ b/strings/ctype-euc_kr.c @@ -179,20 +179,39 @@ static uchar NEAR sort_order_euc_kr[]= /* Support for Korean(EUC_KR) characters, by powerm90@tinc.co.kr and mrpark@tinc.co.kr */ -#define iseuc_kr(c) ((0xa1<=(uchar)(c) && (uchar)(c)<=0xfe)) +/* + Unicode mapping is done according to: + ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/KSC/KSC5601.TXT + + Valid multi-byte characters: + + [A1..FE][41..5A,61..7A,81..FE] + + Note, 0x5C is not a valid MB tail, + so escape_with_backslash_is_dangerous is not set. +*/ +#define iseuc_kr_head(c) ((0xa1<=(uchar)(c) && (uchar)(c)<=0xfe)) + +#define iseuc_kr_tail1(c) ((uchar) (c) >= 0x41 && (uchar) (c) <= 0x5A) +#define iseuc_kr_tail2(c) ((uchar) (c) >= 0x61 && (uchar) (c) <= 0x7A) +#define iseuc_kr_tail3(c) ((uchar) (c) >= 0x81 && (uchar) (c) <= 0xFE) + +#define iseuc_kr_tail(c) (iseuc_kr_tail1(c) || \ + iseuc_kr_tail2(c) || \ + iseuc_kr_tail3(c)) static int ismbchar_euc_kr(CHARSET_INFO *cs __attribute__((unused)), const char* p, const char *e) { return ((*(uchar*)(p)<0x80)? 0:\ - iseuc_kr(*(p)) && (e)-(p)>1 && iseuc_kr(*((p)+1))? 2:\ + iseuc_kr_head(*(p)) && (e)-(p)>1 && iseuc_kr_tail(*((p)+1))? 2:\ 0); } static int mbcharlen_euc_kr(CHARSET_INFO *cs __attribute__((unused)),uint c) { - return (iseuc_kr(c) ? 2 : 1); + return (iseuc_kr_head(c) ? 2 : 1); } @@ -8653,7 +8672,7 @@ my_well_formed_len_euckr(CHARSET_INFO *cs __attribute__((unused)), /* Single byte ascii character */ b++; } - else if (b < emb && iseuc_kr(*b) && iseuc_kr(b[1])) + else if (b < emb && iseuc_kr_head(*b) && iseuc_kr_tail(b[1])) { /* Double byte character */ b+= 2; From a9571690cb8a4369cd6f9490501650402e61fd9b Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 2 Oct 2007 13:28:58 +0500 Subject: [PATCH 022/136] Fixing comments to use "#" instead of "--" --- mysql-test/t/ctype_uca.test | 2 +- mysql-test/t/subselect.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/ctype_uca.test b/mysql-test/t/ctype_uca.test index 17632e7c8fc..695a21adbf5 100644 --- a/mysql-test/t/ctype_uca.test +++ b/mysql-test/t/ctype_uca.test @@ -530,7 +530,7 @@ create table t1 ( a varchar(255), key a(a) ) character set utf8 collate utf8_czech_ci; --- In Czech 'ch' is a single letter between 'h' and 'i' +# In Czech 'ch' is a single letter between 'h' and 'i' insert into t1 values ('b'),('c'),('d'),('e'),('f'),('g'),('h'),('ch'),('i'),('j'); select * from t1 where a like 'c%'; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index d076ca6bd33..86d2aec870c 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2970,7 +2970,7 @@ DROP TABLE t1,t2; CREATE TABLE t1 (a INT, b INT); INSERT INTO t1 VALUES (1, 2), (1,3), (1,4), (2,1), (2,2); --- returns no rows, when it should +# returns no rows, when it should SELECT a1.a, COUNT(*) FROM t1 a1 WHERE a1.a = 1 AND EXISTS( SELECT a2.a FROM t1 a2 WHERE a2.a = a1.a) GROUP BY a1.a; From c359f7ff33d17e1af0bfd1268a68af8332d2538c Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 2 Oct 2007 15:20:45 +0500 Subject: [PATCH 023/136] Bug#29675 collation_connection is defined twice for the same value Removing redundant initialization. sql/mysqld.cc: Removing redundant variable initialization. --- sql/mysqld.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 08c2b60fa79..9b339a59946 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2849,7 +2849,6 @@ static int init_common_variables(const char *conf_file_name, int argc, global_system_variables.collation_connection= default_charset_info; global_system_variables.character_set_results= default_charset_info; global_system_variables.character_set_client= default_charset_info; - global_system_variables.collation_connection= default_charset_info; if (!(character_set_filesystem= get_charset_by_csname(character_set_filesystem_name, From 42cea00e036c1191b7c9251ac1e123df8273d86c Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 Oct 2007 11:57:14 +0200 Subject: [PATCH 024/136] BUG#30752 rpl_dual_pos_advance valgrind (jump depends on uninitialized LOG_INFO) Problem: one thread could read uninitialized memory from (the stack of) another thread. Fix: swapped order of initializing the memory and making it available to the other thread. Fix: put lock around the statement that makes the memory available to the other thread. Fix: all fields of the struct are now initialized in the constructor, to avoid future problems. sql/sql_class.h: Initialize all members in constructor for more safe future code. sql/sql_repl.cc: Swap order so that linfo is first initialized, then assigned, instead of the other way around. Put a lock around the assignment. We use LOCK_thread_count since log_in_use uses it: log_in_use may be running concurrently, called from MYSQL_LOG::purge_logs. --- sql/sql_class.h | 8 +++++++- sql/sql_repl.cc | 10 ++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index 4fac86dc405..a96000a0598 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -159,7 +159,13 @@ typedef struct st_log_info my_off_t pos; bool fatal; // if the purge happens to give us a negative offset pthread_mutex_t lock; - st_log_info():fatal(0) { pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST);} + st_log_info() + : index_file_offset(0), index_file_start_offset(0), + pos(0), fatal(0) + { + log_file_name[0] = '\0'; + pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST); + } ~st_log_info() { pthread_mutex_destroy(&lock);} } LOG_INFO; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 9cc0ba7c29a..903d254db8f 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -364,7 +364,6 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, name=0; // Find first log linfo.index_file_offset = 0; - thd->current_linfo = &linfo; if (mysql_bin_log.find_log_pos(&linfo, name, 1)) { @@ -373,6 +372,10 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, goto err; } + pthread_mutex_lock(&LOCK_thread_count); + thd->current_linfo = &linfo; + pthread_mutex_unlock(&LOCK_thread_count); + if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0) { my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; @@ -1338,7 +1341,6 @@ bool mysql_show_binlog_events(THD* thd) name=0; // Find first log linfo.index_file_offset = 0; - thd->current_linfo = &linfo; if (mysql_bin_log.find_log_pos(&linfo, name, 1)) { @@ -1346,6 +1348,10 @@ bool mysql_show_binlog_events(THD* thd) goto err; } + pthread_mutex_lock(&LOCK_thread_count); + thd->current_linfo = &linfo; + pthread_mutex_unlock(&LOCK_thread_count); + if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0) goto err; From d0b076b66cef0335a884fa96c1c636bbef31a9db Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 4 Oct 2007 13:06:01 +0500 Subject: [PATCH 025/136] Bug#29323 mysql client only accetps ANSI encoded files Fix: ignore BOM marker in the first line. client/mysql.cc: Skip BOM marker in the very first line. mysql-test/r/mysql.result: Adding test mysql-test/t/mysql.test: Adding test --- client/mysql.cc | 11 +++++++++++ mysql-test/r/mysql.result | 2 ++ mysql-test/t/mysql.test | 9 +++++++++ 3 files changed, 22 insertions(+) diff --git a/client/mysql.cc b/client/mysql.cc index 8e1b6c2a9b4..3cc7f2ad090 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1042,6 +1042,17 @@ static int read_and_execute(bool interactive) if (!interactive) { line=batch_readline(status.line_buff); + /* + Skip UTF8 Byte Order Marker (BOM) 0xEFBBBF. + Editors like "notepad" put this marker in + the very beginning of a text file when + you save the file using "Unicode UTF-8" format. + */ + if (!line_number && + (uchar) line[0] == 0xEF && + (uchar) line[1] == 0xBB && + (uchar) line[2] == 0xBF) + line+= 3; line_number++; if (!glob_buffer.length()) status.query_start_line=line_number; diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index c6e589a5fb7..eded1a3fc3b 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -178,4 +178,6 @@ ERROR at line 1: DELIMITER cannot contain a backslash character 1 1 1 +This is a file starting with UTF8 BOM 0xEFBBBF +This is a file starting with UTF8 BOM 0xEFBBBF End of 5.0 tests diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index 6e97d0faede..182b292c817 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -281,4 +281,13 @@ remove_file $MYSQLTEST_VARDIR/tmp/bug21412.sql; # --exec $MYSQL test -e "/*! \C latin1 */ select 1;" +# +# Bug#29323 mysql client only accetps ANSI encoded files +# +--write_file $MYSQLTEST_VARDIR/tmp/bug29323.sql +select "This is a file starting with UTF8 BOM 0xEFBBBF"; +EOF +--exec $MYSQL < $MYSQLTEST_VARDIR/tmp/bug29323.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/bug29323.sql; + --echo End of 5.0 tests From 0f0e0e1aafcc2d0d467ce5de560d7d6f7151d384 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 4 Oct 2007 13:13:04 +0300 Subject: [PATCH 026/136] manual merge sql/log.h: manual merge: moving 5.0 hunk into the correct file. --- sql/log.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sql/log.h b/sql/log.h index e597c986794..afcb1d1adf4 100644 --- a/sql/log.h +++ b/sql/log.h @@ -130,7 +130,13 @@ typedef struct st_log_info my_off_t pos; bool fatal; // if the purge happens to give us a negative offset pthread_mutex_t lock; - st_log_info():fatal(0) { pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST);} + st_log_info() + : index_file_offset(0), index_file_start_offset(0), + pos(0), fatal(0) + { + log_file_name[0] = '\0'; + pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST); + } ~st_log_info() { pthread_mutex_destroy(&lock);} } LOG_INFO; From bf8a85aa56fe755a1712a08b45667734765d45c8 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 4 Oct 2007 18:46:31 +0300 Subject: [PATCH 027/136] Bug #29309 Incorrect "Seconds_Behind_Master" value in SHOW SLAVE STATUS after FLUSH LOGS Report claims that Seconds_behind_master behaves unexpectedly. Code analysis shows that there is an evident flaw in that treating of FormatDescription event is wrong so that after FLUSH LOGS on slave the Seconds_behind_master's calculation slips and incorrect value can be reported to SHOW SLAVE STATUS. Even worse is that the gap between the correct and incorrect deltas grows with time. Fixed with prohibiting changes to rpl->last_master_timestamp by artifical events (any kind of). suggestion as comments is added how to fight with lack of info on the slave side by means of new heartbeat feature coming. The test can not be done ealily fully determistic. sql/log_event.cc: changing timestamp is affirmed only by non-artificial events. Artifical FD won't change it anymore. The simulation code is off unless server is started with the args from the opt-file. The simulation code assumes that it will execute specific schedule generated by rpl_replication_delay.test. sql/slave.cc: Comments are changed to announce a new possibility to cope with Seconds_behind_master jumping due to EOF special treatment (reset of the timestamp) mysql-test/suite/manual/r/rpl_replication_delay.result: result are not deterministic though there are comments saying the most probable expected value for Seconds_behind_master mysql-test/suite/manual/t/rpl_replication_delay-slave.opt: bug emulation mysql-test/suite/manual/t/rpl_replication_delay.test: specic test for bug#29309. It's hard to make it reliable as it deals with timestamps. (a way to automate the test like this is to have I_S table for show slave status' fields) A possible way to check results is to run grep -i 'show\|seconds' < suite/manual/r/rpl_replication_delay.reject and to get the lines like these: show slave status /* Second_behind reports 0 */;; Seconds_Behind_Master 0 show slave status /* bug emulated: reports slave threads starting time about 3*3 not 3 secs */;; Seconds_Behind_Master 9 show slave status /* reports the correct diff with master query time about 3+3 secs */;; Seconds_Behind_Master 6 Due to time discreteness of time the reported numbers may slightly vary. That's why the test is not reliable. --- .../manual/r/rpl_replication_delay.result | 121 ++++++++++++++++++ .../manual/t/rpl_replication_delay-slave.opt | 1 + .../suite/manual/t/rpl_replication_delay.test | 71 ++++++++++ sql/log_event.cc | 32 ++++- sql/slave.cc | 11 +- 5 files changed, 234 insertions(+), 2 deletions(-) create mode 100644 mysql-test/suite/manual/r/rpl_replication_delay.result create mode 100644 mysql-test/suite/manual/t/rpl_replication_delay-slave.opt create mode 100644 mysql-test/suite/manual/t/rpl_replication_delay.test diff --git a/mysql-test/suite/manual/r/rpl_replication_delay.result b/mysql-test/suite/manual/r/rpl_replication_delay.result new file mode 100644 index 00000000000..22447a30cba --- /dev/null +++ b/mysql-test/suite/manual/r/rpl_replication_delay.result @@ -0,0 +1,121 @@ +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; +show slave status /* Second_behind reports 0 */;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port 9306 +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 98 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 98 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master 0 +drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' +create table t1 (f1 int); +flush logs /* contaminate rli->last_master_timestamp */; +lock table t1 write; +insert into t1 values (1); +show slave status /* bug emulated: reports slave threads starting time about 3*3 not 3 secs */;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port 9306 +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 359 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 271 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master 10 +unlock tables; +flush logs /* this time rli->last_master_timestamp is not affected */; +lock table t1 write; +insert into t1 values (2); +show slave status /* reports the correct diff with master query time about 3+3 secs */;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port 9306 +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 447 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 359 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master 6 +unlock tables; +drop table t1; diff --git a/mysql-test/suite/manual/t/rpl_replication_delay-slave.opt b/mysql-test/suite/manual/t/rpl_replication_delay-slave.opt new file mode 100644 index 00000000000..24a4c5952fe --- /dev/null +++ b/mysql-test/suite/manual/t/rpl_replication_delay-slave.opt @@ -0,0 +1 @@ +--loose-debug=d,let_first_flush_log_change_timestamp diff --git a/mysql-test/suite/manual/t/rpl_replication_delay.test b/mysql-test/suite/manual/t/rpl_replication_delay.test new file mode 100644 index 00000000000..8230698c8f9 --- /dev/null +++ b/mysql-test/suite/manual/t/rpl_replication_delay.test @@ -0,0 +1,71 @@ +# +# Testing replication delay reporting (bug#29309) +# there is an unavoidable non-determinism in the test +# please compare the results with the comments +# + + +source include/master-slave.inc; + +connection master; +#connection slave; +sync_slave_with_master; +--replace_result $DEFAULT_MASTER_PORT DEFAULT_MASTER_PORT +--replace_column 1 # 8 # 9 # 23 # +--query_vertical show slave status /* Second_behind reports 0 */; +sleep 3; + +### bug emulation + +connection master; +drop table if exists t1; +create table t1 (f1 int); +sleep 3; + +#connection slave; +sync_slave_with_master; +flush logs /* contaminate rli->last_master_timestamp */; + +connection slave; +lock table t1 write; + +connection master; +insert into t1 values (1); + +sleep 3; + +connection slave; +--replace_result $DEFAULT_MASTER_PORT DEFAULT_MASTER_PORT +--replace_column 1 # 8 # 9 # 23 # +--query_vertical show slave status /* bug emulated: reports slave threads starting time about 3*3 not 3 secs */; +unlock tables; + +connection master; +sync_slave_with_master; + +### bugfix + + +connection slave; +flush logs /* this time rli->last_master_timestamp is not affected */; +lock table t1 write; + +connection master; +insert into t1 values (2); +sleep 3; + +connection slave; +--replace_result $DEFAULT_MASTER_PORT DEFAULT_MASTER_PORT +--replace_column 1 # 8 # 9 # 23 # +--query_vertical show slave status /* reports the correct diff with master query time about 3+3 secs */; +unlock tables; + +connection master; +drop table t1; + +#connection slave; +sync_slave_with_master; + + +# End of tests + diff --git a/sql/log_event.cc b/sql/log_event.cc index 1ef765f607f..3899e772bf8 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -27,6 +27,10 @@ #define log_cs &my_charset_latin1 +#ifndef DBUG_OFF +uint debug_not_change_ts_if_art_event= 1; // bug#29309 simulation +#endif + /* pretty_print_str() */ @@ -481,6 +485,18 @@ int Log_event::exec_event(struct st_relay_log_info* rli) rli->inc_event_relay_log_pos(); else { + /* + bug#29309 simulation: resetting the flag to force + wrong behaviour of artificial event to update + rli->last_master_timestamp for only one time - + the first FLUSH LOGS in the test. + */ + DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp", + if (debug_not_change_ts_if_art_event == 1 + && is_artificial_event()) + { + debug_not_change_ts_if_art_event= 0; + }); rli->inc_group_relay_log_pos(log_pos); flush_relay_log_info(rli); /* @@ -491,7 +507,21 @@ int Log_event::exec_event(struct st_relay_log_info* rli) rare cases, only consequence is that value may take some time to display in Seconds_Behind_Master - not critical). */ - rli->last_master_timestamp= when; +#ifndef DBUG_OFF + if (!(is_artificial_event() && debug_not_change_ts_if_art_event > 0)) +#else + if (!is_artificial_event()) +#endif + rli->last_master_timestamp= when; + /* + The flag is set back to be positive so that + any further FLUSH LOGS will be handled as prescribed. + */ + DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp", + if (debug_not_change_ts_if_art_event == 0) + { + debug_not_change_ts_if_art_event= 2; + }); } } DBUG_RETURN(0); diff --git a/sql/slave.cc b/sql/slave.cc index 57f6e64ce03..0bc4bf7b32f 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4931,7 +4931,16 @@ Log_event* next_event(RELAY_LOG_INFO* rli) a new event and is queuing it; the false "0" will exist until SQL finishes executing the new event; it will be look abnormal only if the events have old timestamps (then you get "many", 0, "many"). - Transient phases like this can't really be fixed. + + Transient phases like this can be fixed with implemeting + Heartbeat event which provides the slave the status of the + master at time the master does not have any new update to send. + Seconds_Behind_Master would be zero only when master has no + more updates in binlog for slave. The heartbeat can be sent + in a (small) fraction of slave_net_timeout. Until it's done + rli->last_master_timestamp is temporarely (for time of + waiting for the following event) reset whenever EOF is + reached. */ time_t save_timestamp= rli->last_master_timestamp; rli->last_master_timestamp= 0; From 64b19133820078a555e73ed1ff429984e82d1041 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 5 Oct 2007 12:15:11 +0500 Subject: [PATCH 028/136] Bug#31081 server crash in regexp function Problem: The "regex" library written by Henry Spencer does not support tricky character sets like UCS2. Fix: convert tricky character sets to UTF8 before calling regex functions. mysql-test/r/ctype_uca.result: Adding tests mysql-test/r/ctype_ucs.result: Adding tests mysql-test/r/ctype_utf8.result: Adding tests mysql-test/r/func_regexp.result: Adding tests mysql-test/t/ctype_uca.test: Adding tests mysql-test/t/ctype_ucs.test: Adding tests mysql-test/t/ctype_utf8.test: Adding tests mysql-test/t/func_regexp.test: Adding tests sql/item_cmpfunc.cc: - Adding new method Item_func_regex::regcomp() to share more code between fix_fields() and val_int() - Adding conversion from ASCII-incompatible charsets like UCS2 to UTF8, because the "regexp" does not support these charsets - Additional optimization: calculate flags for regcomp only once in fix_fields, instead of every regcomp() sql/item_cmpfunc.h: Adding prototypes for new members and methods mysql-test/include/ctype_regex.inc: New BitKeeper file ``mysql-test/include/ctype_regex.inc'' Moving common regular expression tests into a separate file and uncluding it into func_regexp and into many ctype_xxx tests. --- mysql-test/include/ctype_regex.inc | 42 ++++++++++ mysql-test/r/ctype_uca.result | 45 +++++++++++ mysql-test/r/ctype_ucs.result | 45 +++++++++++ mysql-test/r/ctype_utf8.result | 45 +++++++++++ mysql-test/r/func_regexp.result | 14 +++- mysql-test/t/ctype_uca.test | 4 + mysql-test/t/ctype_ucs.test | 4 + mysql-test/t/ctype_utf8.test | 7 ++ mysql-test/t/func_regexp.test | 23 +----- sql/item_cmpfunc.cc | 122 +++++++++++++++++------------ sql/item_cmpfunc.h | 4 + 11 files changed, 283 insertions(+), 72 deletions(-) create mode 100644 mysql-test/include/ctype_regex.inc diff --git a/mysql-test/include/ctype_regex.inc b/mysql-test/include/ctype_regex.inc new file mode 100644 index 00000000000..0e6b4c41607 --- /dev/null +++ b/mysql-test/include/ctype_regex.inc @@ -0,0 +1,42 @@ +# +# To test a desired collation, set session.collation_connection to +# this collation before including this file +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# Create a table with two varchar(64) null-able column, +# using current values of +# @@character_set_connection and @@collation_connection. +# + +create table t1 as +select repeat(' ', 64) as s1, repeat(' ',64) as s2 +union +select null, null; +show create table t1; +delete from t1; + +insert into t1 values('aaa','aaa'); +insert into t1 values('aaa|qqq','qqq'); +insert into t1 values('gheis','^[^a-dXYZ]+$'); +insert into t1 values('aab','^aa?b'); +insert into t1 values('Baaan','^Ba*n'); +insert into t1 values('aaa','qqq|aaa'); +insert into t1 values('qqq','qqq|aaa'); + +insert into t1 values('bbb','qqq|aaa'); +insert into t1 values('bbb','qqq'); +insert into t1 values('aaa','aba'); + +insert into t1 values(null,'abc'); +insert into t1 values('def',null); +insert into t1 values(null,null); +insert into t1 values('ghi','ghi['); + +select HIGH_PRIORITY s1 regexp s2 from t1; + +drop table t1; diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result index 889702e380c..ada7ace9696 100644 --- a/mysql-test/r/ctype_uca.result +++ b/mysql-test/r/ctype_uca.result @@ -2754,4 +2754,49 @@ a c ch drop table t1; +set collation_connection=ucs2_unicode_ci; +drop table if exists t1; +create table t1 as +select repeat(' ', 64) as s1, repeat(' ',64) as s2 +union +select null, null; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` varchar(64) character set ucs2 collate ucs2_unicode_ci default NULL, + `s2` varchar(64) character set ucs2 collate ucs2_unicode_ci default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +delete from t1; +insert into t1 values('aaa','aaa'); +insert into t1 values('aaa|qqq','qqq'); +insert into t1 values('gheis','^[^a-dXYZ]+$'); +insert into t1 values('aab','^aa?b'); +insert into t1 values('Baaan','^Ba*n'); +insert into t1 values('aaa','qqq|aaa'); +insert into t1 values('qqq','qqq|aaa'); +insert into t1 values('bbb','qqq|aaa'); +insert into t1 values('bbb','qqq'); +insert into t1 values('aaa','aba'); +insert into t1 values(null,'abc'); +insert into t1 values('def',null); +insert into t1 values(null,null); +insert into t1 values('ghi','ghi['); +select HIGH_PRIORITY s1 regexp s2 from t1; +s1 regexp s2 +1 +1 +1 +1 +1 +1 +1 +0 +0 +0 +NULL +NULL +NULL +NULL +drop table t1; +set names utf8; End for 5.0 tests diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 023267c227c..954fdab7699 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -922,4 +922,49 @@ ERROR HY000: Illegal mix of collations (ascii_general_ci,IMPLICIT) and (ucs2_gen select * from t1 where a=if(b<10,_ucs2 0x0062,_ucs2 0x00C0); ERROR HY000: Illegal mix of collations (ascii_general_ci,IMPLICIT) and (ucs2_general_ci,COERCIBLE) for operation '=' drop table t1; +set collation_connection=ucs2_general_ci; +drop table if exists t1; +create table t1 as +select repeat(' ', 64) as s1, repeat(' ',64) as s2 +union +select null, null; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` varchar(64) character set ucs2 default NULL, + `s2` varchar(64) character set ucs2 default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +delete from t1; +insert into t1 values('aaa','aaa'); +insert into t1 values('aaa|qqq','qqq'); +insert into t1 values('gheis','^[^a-dXYZ]+$'); +insert into t1 values('aab','^aa?b'); +insert into t1 values('Baaan','^Ba*n'); +insert into t1 values('aaa','qqq|aaa'); +insert into t1 values('qqq','qqq|aaa'); +insert into t1 values('bbb','qqq|aaa'); +insert into t1 values('bbb','qqq'); +insert into t1 values('aaa','aba'); +insert into t1 values(null,'abc'); +insert into t1 values('def',null); +insert into t1 values(null,null); +insert into t1 values('ghi','ghi['); +select HIGH_PRIORITY s1 regexp s2 from t1; +s1 regexp s2 +1 +1 +1 +1 +1 +1 +1 +0 +0 +0 +NULL +NULL +NULL +NULL +drop table t1; +set names latin1; End of 5.0 tests diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 710cac388a5..7cdc5c265d7 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -267,6 +267,51 @@ b select * from t1 where a = 'b' and a != 'b'; a drop table t1; +set collation_connection=utf8_general_ci; +drop table if exists t1; +create table t1 as +select repeat(' ', 64) as s1, repeat(' ',64) as s2 +union +select null, null; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` varchar(64) character set utf8 default NULL, + `s2` varchar(64) character set utf8 default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +delete from t1; +insert into t1 values('aaa','aaa'); +insert into t1 values('aaa|qqq','qqq'); +insert into t1 values('gheis','^[^a-dXYZ]+$'); +insert into t1 values('aab','^aa?b'); +insert into t1 values('Baaan','^Ba*n'); +insert into t1 values('aaa','qqq|aaa'); +insert into t1 values('qqq','qqq|aaa'); +insert into t1 values('bbb','qqq|aaa'); +insert into t1 values('bbb','qqq'); +insert into t1 values('aaa','aba'); +insert into t1 values(null,'abc'); +insert into t1 values('def',null); +insert into t1 values(null,null); +insert into t1 values('ghi','ghi['); +select HIGH_PRIORITY s1 regexp s2 from t1; +s1 regexp s2 +1 +1 +1 +1 +1 +1 +1 +0 +0 +0 +NULL +NULL +NULL +NULL +drop table t1; +set names utf8; set names utf8; select 'вася' rlike '[[:<:]]вася[[:>:]]'; 'вася' rlike '[[:<:]]вася[[:>:]]' diff --git a/mysql-test/r/func_regexp.result b/mysql-test/r/func_regexp.result index 584c8a9b820..752ec3a5810 100644 --- a/mysql-test/r/func_regexp.result +++ b/mysql-test/r/func_regexp.result @@ -1,5 +1,17 @@ drop table if exists t1; -create table t1 (s1 char(64),s2 char(64)); +set names latin1; +drop table if exists t1; +create table t1 as +select repeat(' ', 64) as s1, repeat(' ',64) as s2 +union +select null, null; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` varchar(64) default NULL, + `s2` varchar(64) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +delete from t1; insert into t1 values('aaa','aaa'); insert into t1 values('aaa|qqq','qqq'); insert into t1 values('gheis','^[^a-dXYZ]+$'); diff --git a/mysql-test/t/ctype_uca.test b/mysql-test/t/ctype_uca.test index 17632e7c8fc..bac3ef7d63c 100644 --- a/mysql-test/t/ctype_uca.test +++ b/mysql-test/t/ctype_uca.test @@ -538,4 +538,8 @@ alter table t1 convert to character set ucs2 collate ucs2_czech_ci; select * from t1 where a like 'c%'; drop table t1; +set collation_connection=ucs2_unicode_ci; +--source include/ctype_regex.inc +set names utf8; + -- echo End for 5.0 tests diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index bca3a9c3a96..3779dd50260 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -651,4 +651,8 @@ select * from t1 where a=if(b<10,_ucs2 0x00C0,_ucs2 0x0062); select * from t1 where a=if(b<10,_ucs2 0x0062,_ucs2 0x00C0); drop table t1; +set collation_connection=ucs2_general_ci; +--source include/ctype_regex.inc +set names latin1; + --echo End of 5.0 tests diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index f8eed0bae9a..927794f2d5a 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -185,6 +185,13 @@ select * from t1 where a = 'b' and a = 'b'; select * from t1 where a = 'b' and a != 'b'; drop table t1; +# +# Testing regexp +# +set collation_connection=utf8_general_ci; +--source include/ctype_regex.inc +set names utf8; + # # Bug #3928 regexp [[:>:]] and UTF-8 # diff --git a/mysql-test/t/func_regexp.test b/mysql-test/t/func_regexp.test index 23070c71fe9..f34830f6100 100644 --- a/mysql-test/t/func_regexp.test +++ b/mysql-test/t/func_regexp.test @@ -6,28 +6,9 @@ drop table if exists t1; --enable_warnings -create table t1 (s1 char(64),s2 char(64)); +set names latin1; +--source include/ctype_regex.inc -insert into t1 values('aaa','aaa'); -insert into t1 values('aaa|qqq','qqq'); -insert into t1 values('gheis','^[^a-dXYZ]+$'); -insert into t1 values('aab','^aa?b'); -insert into t1 values('Baaan','^Ba*n'); -insert into t1 values('aaa','qqq|aaa'); -insert into t1 values('qqq','qqq|aaa'); - -insert into t1 values('bbb','qqq|aaa'); -insert into t1 values('bbb','qqq'); -insert into t1 values('aaa','aba'); - -insert into t1 values(null,'abc'); -insert into t1 values('def',null); -insert into t1 values(null,null); -insert into t1 values('ghi','ghi['); - -select HIGH_PRIORITY s1 regexp s2 from t1; - -drop table t1; # # This test a bug in regexp on Alpha diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 86eb10d50b0..51b3e8cda6b 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4225,6 +4225,51 @@ void Item_func_like::cleanup() #ifdef USE_REGEX +bool +Item_func_regex::regcomp(bool send_error) +{ + char buff[MAX_FIELD_WIDTH]; + String tmp(buff,sizeof(buff),&my_charset_bin); + String *res= args[1]->val_str(&tmp); + int error; + + if (args[1]->null_value) + return TRUE; + + if (regex_compiled) + { + if (!stringcmp(res, &prev_regexp)) + return FALSE; + prev_regexp.copy(*res); + my_regfree(&preg); + regex_compiled= 0; + } + + if (cmp_collation.collation != regex_lib_charset) + { + /* Convert UCS2 strings to UTF8 */ + uint dummy_errors; + if (conv.copy(res->ptr(), res->length(), res->charset(), + regex_lib_charset, &dummy_errors)) + return TRUE; + res= &conv; + } + + if ((error= my_regcomp(&preg, res->c_ptr(), + regex_lib_flags, regex_lib_charset))) + { + if (send_error) + { + (void) my_regerror(error, &preg, buff, sizeof(buff)); + my_error(ER_REGEXP_ERROR, MYF(0), buff); + } + return TRUE; + } + regex_compiled= 1; + return FALSE; +} + + bool Item_func_regex::fix_fields(THD *thd, Item **ref) { @@ -4241,34 +4286,33 @@ Item_func_regex::fix_fields(THD *thd, Item **ref) if (agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV, 1)) return TRUE; + regex_lib_flags= (cmp_collation.collation->state & + (MY_CS_BINSORT | MY_CS_CSSORT)) ? + REG_EXTENDED | REG_NOSUB : + REG_EXTENDED | REG_NOSUB | REG_ICASE; + /* + If the case of UCS2 and other non-ASCII character sets, + we will convert patterns and strings to UTF8. + */ + regex_lib_charset= (cmp_collation.collation->mbminlen > 1) ? + &my_charset_utf8_general_ci : + cmp_collation.collation; + used_tables_cache=args[0]->used_tables() | args[1]->used_tables(); not_null_tables_cache= (args[0]->not_null_tables() | args[1]->not_null_tables()); const_item_cache=args[0]->const_item() && args[1]->const_item(); if (!regex_compiled && args[1]->const_item()) { - char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff),&my_charset_bin); - String *res=args[1]->val_str(&tmp); if (args[1]->null_value) { // Will always return NULL maybe_null=1; return FALSE; } - int error; - if ((error= my_regcomp(&preg,res->c_ptr(), - ((cmp_collation.collation->state & - (MY_CS_BINSORT | MY_CS_CSSORT)) ? - REG_EXTENDED | REG_NOSUB : - REG_EXTENDED | REG_NOSUB | REG_ICASE), - cmp_collation.collation))) - { - (void) my_regerror(error,&preg,buff,sizeof(buff)); - my_error(ER_REGEXP_ERROR, MYF(0), buff); + if (regcomp(TRUE)) return TRUE; - } - regex_compiled=regex_is_const=1; - maybe_null=args[0]->maybe_null; + regex_is_const= 1; + maybe_null= args[0]->maybe_null; } else maybe_null=1; @@ -4281,47 +4325,25 @@ longlong Item_func_regex::val_int() { DBUG_ASSERT(fixed == 1); char buff[MAX_FIELD_WIDTH]; - String *res, tmp(buff,sizeof(buff),&my_charset_bin); + String tmp(buff,sizeof(buff),&my_charset_bin); + String *res= args[0]->val_str(&tmp); - res=args[0]->val_str(&tmp); - if (args[0]->null_value) - { - null_value=1; + if ((null_value= (args[0]->null_value || + (!regex_is_const && regcomp(FALSE))))) return 0; - } - if (!regex_is_const) - { - char buff2[MAX_FIELD_WIDTH]; - String *res2, tmp2(buff2,sizeof(buff2),&my_charset_bin); - res2= args[1]->val_str(&tmp2); - if (args[1]->null_value) + if (cmp_collation.collation != regex_lib_charset) + { + /* Convert UCS2 strings to UTF8 */ + uint dummy_errors; + if (conv.copy(res->ptr(), res->length(), res->charset(), + regex_lib_charset, &dummy_errors)) { - null_value=1; + null_value= 1; return 0; } - if (!regex_compiled || stringcmp(res2,&prev_regexp)) - { - prev_regexp.copy(*res2); - if (regex_compiled) - { - my_regfree(&preg); - regex_compiled=0; - } - if (my_regcomp(&preg,res2->c_ptr_safe(), - ((cmp_collation.collation->state & - (MY_CS_BINSORT | MY_CS_CSSORT)) ? - REG_EXTENDED | REG_NOSUB : - REG_EXTENDED | REG_NOSUB | REG_ICASE), - cmp_collation.collation)) - { - null_value=1; - return 0; - } - regex_compiled=1; - } + res= &conv; } - null_value=0; return my_regexec(&preg,res->c_ptr_safe(),0,(my_regmatch_t*) 0,0) ? 0 : 1; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 8410c66b034..11851e9a4e4 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1313,6 +1313,10 @@ class Item_func_regex :public Item_bool_func bool regex_is_const; String prev_regexp; DTCollation cmp_collation; + CHARSET_INFO *regex_lib_charset; + int regex_lib_flags; + String conv; + bool regcomp(bool send_error); public: Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b), regex_compiled(0),regex_is_const(0) {} From 4c21617d4a188de89833ceb0714de0c70fa963da Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 9 Oct 2007 13:53:39 +0500 Subject: [PATCH 029/136] Bug#27287 extractvalue() (and updatexml()) extremely slow for large XML Performance improvements made. ExtractValue for large XML values is now much faster (about 2000 times faster of 1Mb-long XML values). sql/item_xmlfunc.cc: Performance improvement for huge XML values: 1. Avoid reallocs - reserve extra memory: using String::reserve() + String::q_append() instead of String::append() 2. Parent is now not searched through the all previous nodes in backward direction. Instead, we do the following: - we introduce data->parent - a new member in MY_XML_USER_DATA - when entering a new tag/attribute node, we remember offset of the current node in data->parent - when leaving a tag/attribute node, we change data->parent to offset of the parent of the current node. --- sql/item_xmlfunc.cc | 60 ++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 15be9c97b6e..d0dbab16b1c 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -2611,35 +2611,27 @@ typedef struct uint level; String *pxml; // parsed XML uint pos[MAX_LEVEL]; // Tag position stack + uint parent; // Offset of the parent of the current node } MY_XML_USER_DATA; -/* - Find the parent node - - SYNOPSYS - Find the parent node, i.e. a tag or attrubute node on the given level. - - RETURN - 1 - success - 0 - failure -*/ -static uint xml_parent_tag(MY_XML_NODE *items, uint nitems, uint level) +static bool +append_node(String *str, MY_XML_NODE *node) { - if (!nitems) - return 0; - - MY_XML_NODE *p, *last= &items[nitems-1]; - for (p= last; p >= items; p--) - { - if (p->level == level && - (p->type == MY_XML_NODE_TAG || - p->type == MY_XML_NODE_ATTR)) - { - return p - items; - } - } - return 0; + /* + If "str" doesn't have space for a new node, + it will allocate two times more space that it has had so far. + (2*len+512) is a heuristic value, + which gave the best performance during tests. + The ideas behind this formula are: + - It allows to have a very small number of reallocs: + about 10 reallocs on a 1Mb-long XML value. + - At the same time, it avoids excessive memory use. + */ + if (str->reserve(sizeof(MY_XML_NODE), 2 * str->length() + 512)) + return TRUE; + str->q_append((const char*) node, sizeof(MY_XML_NODE)); + return FALSE; } @@ -2661,19 +2653,17 @@ extern "C" int xml_enter(MY_XML_PARSER *st,const char *attr, size_t len); int xml_enter(MY_XML_PARSER *st,const char *attr, size_t len) { MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data; - MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr(); uint numnodes= data->pxml->length() / sizeof(MY_XML_NODE); - uint parent= xml_parent_tag(nodes, numnodes, data->level - 1); MY_XML_NODE node; + node.parent= data->parent; // Set parent for the new node to old parent + data->parent= numnodes; // Remember current node as new parent data->pos[data->level]= numnodes; node.level= data->level++; node.type= st->current_node_type; // TAG or ATTR node.beg= attr; node.end= attr + len; - node.parent= parent; - data->pxml->append((const char*) &node, sizeof(MY_XML_NODE)); - return MY_XML_OK; + return append_node(data->pxml, &node) ? MY_XML_ERROR : MY_XML_OK; } @@ -2694,18 +2684,14 @@ extern "C" int xml_value(MY_XML_PARSER *st,const char *attr, size_t len); int xml_value(MY_XML_PARSER *st,const char *attr, size_t len) { MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data; - MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr(); - uint numnodes= data->pxml->length() / sizeof(MY_XML_NODE); - uint parent= xml_parent_tag(nodes, numnodes, data->level - 1); MY_XML_NODE node; + node.parent= data->parent; // Set parent for the new text node to old parent node.level= data->level; node.type= MY_XML_NODE_TEXT; node.beg= attr; node.end= attr + len; - node.parent= parent; - data->pxml->append((const char*) &node, sizeof(MY_XML_NODE)); - return MY_XML_OK; + return append_node(data->pxml, &node) ? MY_XML_ERROR : MY_XML_OK; } @@ -2730,6 +2716,7 @@ int xml_leave(MY_XML_PARSER *st,const char *attr, size_t len) data->level--; MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr(); + data->parent= nodes[data->parent].parent; nodes+= data->pos[data->level]; nodes->tagend= st->cur; @@ -2760,6 +2747,7 @@ String *Item_xml_str_func::parse_xml(String *raw_xml, String *parsed_xml_buf) p.flags= MY_XML_FLAG_RELATIVE_NAMES | MY_XML_FLAG_SKIP_TEXT_NORMALIZATION; user_data.level= 0; user_data.pxml= parsed_xml_buf; + user_data.parent= 0; my_xml_set_enter_handler(&p, xml_enter); my_xml_set_value_handler(&p, xml_value); my_xml_set_leave_handler(&p, xml_leave); From e8e20954e6dd610cb1400eb411195861e652f67e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 10 Oct 2007 18:10:54 +0200 Subject: [PATCH 030/136] BUG#29046: rpl_stm_mystery22 unstable Problem: rpl_stm_mystery22 is unstable. Reason: At one place, the test case *should* wait until the SQL thread on the slave receives an error, but instead it waits until the SQL thread stops. The SQL thread may stop before the error flag is set, so that when the test case continues to execute, the error flag is not set. Fix: Introduce the subroutine mysql-test/include/wait_for_slave_sql_error.inc, which waits until there is an error in the sql thread of the slave. Re-commit: fixed one logical error and two smaller things noted by Mats. mysql-test/suite/rpl/t/rpl_stm_mystery22.test: Use the new wait_for_slave_sql_error.inc instead of wait_for_slave_to_stop. There may be a delay from when the slave stops to when Last_SQL_Errno is set, so it is not safe to merely wait until the slave stops. mysql-test/include/wait_for_slave_sql_error.inc: New BitKeeper file ``mysql-test/include/wait_for_slave_sql_error.inc'' This is a subroutine that waits until the sql thread on the slave receives an error, as indicated by Last_SQL_Errno in "SHOW SLAVE STATUS". --- .../include/wait_for_slave_sql_error.inc | 33 +++++++++++++++++++ mysql-test/suite/rpl/t/rpl_stm_mystery22.test | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 mysql-test/include/wait_for_slave_sql_error.inc diff --git a/mysql-test/include/wait_for_slave_sql_error.inc b/mysql-test/include/wait_for_slave_sql_error.inc new file mode 100644 index 00000000000..6780edbe2f0 --- /dev/null +++ b/mysql-test/include/wait_for_slave_sql_error.inc @@ -0,0 +1,33 @@ +################################################### +#Author: Sven +#Date: 2007-10-09 +#Purpose: Wait until the slave has an error in the +# sql thread, as indicated by +# "SHOW SLAVE STATUS", or at most 30 +# seconds. +#Details: +# 1) Fill in and setup variables +# 2) loop, looking for sql error on slave +# 3) If it loops too long, die. +#################################################### +connection slave; +let $row_number= 1; +let $run= 1; +let $counter= 300; + +while ($run) +{ + let $sql_result= query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, $row_number); + let $run= `SELECT '$sql_result' = '0'`; + if ($run) { + real_sleep 0.1; + if (!$counter){ + --echo "Failed while waiting for slave to produce an error in its sql thread" + --replace_result $MASTER_MYPORT MASTER_PORT + --replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 # + query_vertical SHOW SLAVE STATUS; + exit; + } + dec $counter; + } +} diff --git a/mysql-test/suite/rpl/t/rpl_stm_mystery22.test b/mysql-test/suite/rpl/t/rpl_stm_mystery22.test index 017593fdfba..b43a734fffc 100644 --- a/mysql-test/suite/rpl/t/rpl_stm_mystery22.test +++ b/mysql-test/suite/rpl/t/rpl_stm_mystery22.test @@ -28,7 +28,7 @@ insert into t1 values(NULL,'new'); save_master_pos; connection slave; # wait until the slave tries to run the query, fails and aborts slave thread -wait_for_slave_to_stop; +source include/wait_for_slave_sql_error.inc; select * from t1 order by n; delete from t1 where n = 2; --disable_warnings From 06fb8c2d1009fe6d285fd29ab9080b2b040a3d60 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 11 Oct 2007 18:18:05 +0200 Subject: [PATCH 031/136] BUG#29549 (Endians: test failures on Solaris): Refactoring code to add parameter to pack() and unpack() functions with purpose of indicating if data should be packed in little-endian or native order. Using new functions to always pack data for binary log in little-endian order. The purpose of this refactoring is to allow proper implementation of endian-agnostic pack() and unpack() functions. Eliminating several versions of virtual pack() and unpack() functions in favor for one single virtual function which is overridden in subclasses. Implementing pack() and unpack() functions for some field types that packed data in native format regardless of the value of the st_table_share::db_low_byte_first flag. The field types that were packed in native format regardless are: Field_real, Field_decimal, Field_tiny, Field_short, Field_medium, Field_long, Field_longlong, and Field_blob. Before the patch, row-based logging wrote the rows incorrectly on big-endian machines where the storage engine defined its own low_byte_first() to be FALSE on big-endian machines (the default is TRUE), while little-endian machines wrote the fields in correct order. The only known storage engine that does this is NDB. In effect, this means that row-based replication from or to a big-endian machine where the table was using NDB as storage engine failed if the other engine was either non-NDB or on a little-endian machine. With this patch, row-based logging is now always done in little-endian order, while ORDER BY uses the native order if the storage engine defines low_byte_first() to return FALSE for big-endian machines. In addition, the max_data_length() function available in Field_blob was generalized to the entire Field hierarchy to give the maximum number of bytes that Field::pack() will write. mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test: Sorting by columns that produces deterministic order. mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result: Result change. mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result: Result change. mysql-test/suite/rpl/r/rpl_row_extraColmaster_ndb.result: Result change. mysql-test/suite/rpl/t/disabled.def: Enabling tests. mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test: Adding missing sync_slave_with_master causing slave to keep tables after shutdown. mysql-test/suite/rpl_ndb/t/disabled.def: Enabling tests. mysql-test/suite/rpl_ndb/t/rpl_ndb_innodb2ndb-slave.opt: Adding --new option mysql-test/suite/rpl_ndb/t/rpl_ndb_innodb2ndb.test: Adding have_log_bin. mysql-test/suite/rpl_ndb/t/rpl_ndb_myisam2ndb-slave.opt: Adding --new option mysql-test/suite/rpl_ndb/t/rpl_ndb_myisam2ndb.test: Adding have_log_bin mysql-test/t/partition.test: Adding have_archive, since that is used in the test. sql/field.cc: Eliminating all two-argument pack() and unpack() functions and moving functionality into the four-argument version. The four argument version is introduced so that it is possible to avoid using the storage engine default when writing and reading the packed format (the unpacked format still uses the storage engine's default). This is used by row-based replication to write the fields in a storage engine- and endian-agnostic format. Packing integral and floating-point numbers in little-endian format (if requested). Using pad_char for the field instead of spaces (0x20) when unpacking. Adding some Doxygen documentation. --- Adding max_data_length() to denote the maximum number of bytes that pack() will write. Adding casts to remove warnings for debug printouts. sql/field.h: Eliminating all virtual pack() and unpack() functions except the four- argument version, which now is the function that shall be overridden. The two-argument versions are convenience functions, to prevent changes to code that uses these. Adding code to pack integer numbers and floating-point numbers in little-endian format, if requested. --- Adding max_data_length() to denote the maximum number of bytes that pack() will write. sql/log.cc: Removing debug printout causing crash when starting NDB on Solaris. sql/log_event.cc: Adding missing #ifndef causing compile failure. Adding debug printouts. sql/rpl_record.cc: Debriding code. Using new pack() and unpack() functions to always pack fields little-endian. Adding debug printouts. --- Using max_data_length() when packing field into row. Adding casts to debug printouts. sql/sql_show.cc: Adding code that causes crash on Solaris machines since printf() cannot handle NULL values for strings properly. mysql-test/suite/rpl_ndb/r/rpl_ndb_innodb2ndb.result: New BitKeeper file ``mysql-test/suite/rpl_ndb/r/rpl_ndb_innodb2ndb.result'' mysql-test/suite/rpl_ndb/r/rpl_ndb_myisam2ndb.result: New BitKeeper file ``mysql-test/suite/rpl_ndb/r/rpl_ndb_myisam2ndb.result'' --- .../extra/rpl_tests/rpl_extraMaster_Col.test | 2 +- .../rpl/r/rpl_extraColmaster_innodb.result | Bin 38226 -> 38226 bytes .../rpl/r/rpl_extraColmaster_myisam.result | Bin 38226 -> 38226 bytes .../rpl/r/rpl_row_extraColmaster_ndb.result | Bin 19129 -> 19129 bytes mysql-test/suite/rpl/t/disabled.def | 1 - .../suite/rpl/t/rpl_row_mysqlbinlog.test | 1 + .../suite/rpl_ndb/r/rpl_ndb_innodb2ndb.result | 855 ++++++++++++++++++ .../suite/rpl_ndb/r/rpl_ndb_myisam2ndb.result | 855 ++++++++++++++++++ mysql-test/suite/rpl_ndb/t/disabled.def | 2 - .../rpl_ndb/t/rpl_ndb_innodb2ndb-slave.opt | 2 +- .../suite/rpl_ndb/t/rpl_ndb_innodb2ndb.test | 10 +- .../rpl_ndb/t/rpl_ndb_myisam2ndb-slave.opt | 2 +- .../suite/rpl_ndb/t/rpl_ndb_myisam2ndb.test | 7 +- mysql-test/t/partition.test | 3 +- sql/field.cc | 407 ++++++--- sql/field.h | 271 +++++- sql/log.cc | 3 - sql/log_event.cc | 4 + sql/rpl_record.cc | 54 +- sql/sql_show.cc | 6 +- 20 files changed, 2251 insertions(+), 234 deletions(-) create mode 100644 mysql-test/suite/rpl_ndb/r/rpl_ndb_innodb2ndb.result create mode 100644 mysql-test/suite/rpl_ndb/r/rpl_ndb_myisam2ndb.result diff --git a/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test b/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test index 26b1e6d5ba0..a03aa337c2b 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test @@ -466,7 +466,7 @@ binary data'; select * from t2 order by f1; select * from t3 order by f1; select * from t4 order by f1; - select * from t31 order by f1; + select * from t31 order by f3; connection master; diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result index 189066179255c33b7d56e0fdfd8a3893dda3535c..ef6e2a6de25a11ce8c9b48e9bd4a0ab8e0380089 100644 GIT binary patch delta 27 dcmcb#is{lSrVXZUlVyXYHwU=6c|jQqSpb}X3M&8r delta 27 ecmcb#is{lSrVXZUlW+A)Zw_#C^MW!KvH$?ISqvQj diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result index 5bc1a13b1078a054d99dfef348ad74e85295e302..475ea4cdcbaab56b53f74844b68bcae4aaa0d753 100644 GIT binary patch delta 27 dcmcb#is{lSrVXZUlVyXYHwU=6c|jQqSpb}X3M&8r delta 27 ecmcb#is{lSrVXZUlW+A)Zw_#C^MW!KvH$?ISqvQj diff --git a/mysql-test/suite/rpl/r/rpl_row_extraColmaster_ndb.result b/mysql-test/suite/rpl/r/rpl_row_extraColmaster_ndb.result index 0b1f2e6c8bf9514ef53ef326dde109d3a78bdea8..fb83c5088e502338e8db678565120f65b47dcba1 100644 GIT binary patch delta 82 zcmdlvm2u}(#tna6C;ySTNkkg2>I5jyxFNF)lG3G4E$Si`eO*qr?ON&Y} Xz!IjMX_;wIwi#z}X2s@Uw=@<2Nf{Ui delta 86 zcmdlvm2u}(#tna6Cm(Yab~fcq%Slow_byte_first is dependent on how the + packed data is going to be used: for local use, e.g., temporary + store on disk or in memory, use the native format since that is + faster. For data that is going to be transfered to other machines + (e.g., when writing data to the binary log), data should always be + stored in little-endian format. + + @note The default method for packing fields just copy the raw bytes + of the record into the destination, but never more than + max_length characters. + + @param to + Pointer to memory area where representation of field should be put. + + @param from + Pointer to memory area where record representation of field is + stored. + + @param max_length + Maximum length of the field, as given in the column definition. For + example, for CHAR(1000), the max_length + is 1000. This information is sometimes needed to decide how to pack + the data. + + @param low_byte_first + @c TRUE if integers should be stored little-endian, @c FALSE if + native format should be used. Note that for little-endian machines, + the value of this flag is a moot point since the native format is + little-endian. +*/ +uchar * +Field::pack(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) +{ + uint32 length= pack_length(); + set_if_smaller(length, max_length); + memcpy(to, from, length); + return to+length; +} + /** Unpack a field from row data. - This method is used to unpack a field from a master whose size - of the field is less than that of the slave. - + This method is used to unpack a field from a master whose size of + the field is less than that of the slave. + + The param_data parameter is a two-byte integer (stored + in the least significant 16 bits of the unsigned integer) usually + consisting of two parts: the real type in the most significant byte + and a original pack length in the least significant byte. + + The exact layout of the param_data field is given by + the Table_map_log_event::save_field_metadata(). + + This is the default method for unpacking a field. It just copies + the memory block in byte order (of original pack length bytes or + length of field, whichever is smaller). + @param to Destination of the data @param from Source of the data - @param param_data Pack length of the field data + @param param_data Real type and original pack length of the field + data + + @param low_byte_first + If this flag is @c true, all composite entities (e.g., lengths) + should be unpacked in little-endian format; otherwise, the entities + are unpacked in native order. @return New pointer into memory based on from + length of the data */ -const uchar *Field::unpack(uchar* to, - const uchar *from, - uint param_data) +const uchar * +Field::unpack(uchar* to, const uchar *from, uint param_data, + bool low_byte_first __attribute__((unused))) { uint length=pack_length(); int from_type= 0; @@ -1399,19 +1464,18 @@ const uchar *Field::unpack(uchar* to, from_type= (param_data & 0xff00) >> 8U; // real_type. param_data= param_data & 0x00ff; // length. } + + if ((param_data == 0) || + (length == param_data) || + (from_type != real_type())) + { + memcpy(to, from, length); + return from+length; + } + uint len= (param_data && (param_data < length)) ? param_data : length; - /* - If the length is the same, use old unpack method. - If the param_data is 0, use the old unpack method. - This is possible if the table map was generated from a down-level - master or if the data was not available on the master. - If the real_types are not the same, use the old unpack method. - */ - if ((length == param_data) || - (param_data == 0) || - (from_type != real_type())) - return(unpack(to, from)); + memcpy(to, from, param_data > length ? length : len); return from+len; } @@ -2714,10 +2778,15 @@ uint Field_new_decimal::is_equal(Create_field *new_field) @return New pointer into memory based on from + length of the data */ -const uchar *Field_new_decimal::unpack(uchar* to, - const uchar *from, - uint param_data) +const uchar * +Field_new_decimal::unpack(uchar* to, + const uchar *from, + uint param_data, + bool low_byte_first) { + if (param_data == 0) + return Field::unpack(to, from, param_data, low_byte_first); + uint from_precision= (param_data & 0xff00) >> 8U; uint from_decimal= param_data & 0x00ff; uint length=pack_length(); @@ -3857,6 +3926,49 @@ void Field_longlong::sql_type(String &res) const } +/* + Floating-point numbers + */ + +uchar * +Field_real::pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first) +{ + DBUG_ENTER("Field_real::pack"); + DBUG_ASSERT(max_length >= pack_length()); + DBUG_PRINT("debug", ("pack_length(): %u", pack_length())); +#ifdef WORDS_BIGENDIAN + if (low_byte_first != table->s->db_low_byte_first) + { + const uchar *dptr= from + pack_length(); + while (dptr-- > from) + *to++ = *dptr; + DBUG_RETURN(to); + } + else +#endif + DBUG_RETURN(Field::pack(to, from, max_length, low_byte_first)); +} + +const uchar * +Field_real::unpack(uchar *to, const uchar *from, + uint param_data, bool low_byte_first) +{ + DBUG_ENTER("Field_real::unpack"); + DBUG_PRINT("debug", ("pack_length(): %u", pack_length())); +#ifdef WORDS_BIGENDIAN + if (low_byte_first != table->s->db_low_byte_first) + { + const uchar *dptr= from + pack_length(); + while (dptr-- > from) + *to++ = *dptr; + DBUG_RETURN(from + pack_length()); + } + else +#endif + DBUG_RETURN(Field::unpack(to, from, param_data, low_byte_first)); +} + /**************************************************************************** single precision float ****************************************************************************/ @@ -6211,6 +6323,11 @@ int Field_longstr::store_decimal(const my_decimal *d) return store(str.ptr(), str.length(), str.charset()); } +uint32 Field_longstr::max_data_length() const +{ + return field_length + (field_length > 255 ? 2 : 1); +} + double Field_string::val_real(void) { @@ -6355,7 +6472,9 @@ void Field_string::sql_type(String &res) const } -uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length) +uchar *Field_string::pack(uchar *to, const uchar *from, + uint max_length, + bool low_byte_first __attribute__((unused))) { uint length= min(field_length,max_length); uint local_char_length= max_length/field_charset->mbmaxlen; @@ -6363,11 +6482,15 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length) local_char_length= my_charpos(field_charset, from, from+length, local_char_length); set_if_smaller(length, local_char_length); - while (length && from[length-1] == ' ') + while (length && from[length-1] == field_charset->pad_char) length--; + + // Length always stored little-endian *to++= (uchar) length; if (field_length > 255) *to++= (uchar) (length >> 8); + + // Store the actual bytes of the string memcpy(to, from, length); return to+length; } @@ -6389,34 +6512,27 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length) @return New pointer into memory based on from + length of the data */ -const uchar *Field_string::unpack(uchar *to, - const uchar *from, - uint param_data) -{ - uint from_len= param_data & 0x00ff; // length. - uint length= 0; - uint f_length; - f_length= (from_len < field_length) ? from_len : field_length; - DBUG_ASSERT(f_length <= 255); - length= (uint) *from++; - bitmap_set_bit(table->write_set,field_index); - store((const char *)from, length, system_charset_info); - return from+length; -} - - -const uchar *Field_string::unpack(uchar *to, const uchar *from) +const uchar * +Field_string::unpack(uchar *to, + const uchar *from, + uint param_data, + bool low_byte_first __attribute__((unused))) { + uint from_length= + param_data ? min(param_data & 0x00ff, field_length) : field_length; uint length; - if (field_length > 255) + + if (from_length > 255) { length= uint2korr(from); from+= 2; } else length= (uint) *from++; - memcpy(to, from, (int) length); - bfill(to+length, field_length - length, ' '); + + memcpy(to, from, length); + // Pad the string with the pad character of the fields charset + bfill(to + length, field_length - length, field_charset->pad_char); return from+length; } @@ -6796,22 +6912,30 @@ uint32 Field_varstring::data_length() Here the number of length bytes are depending on the given max_length */ -uchar *Field_varstring::pack(uchar *to, const uchar *from, uint max_length) +uchar *Field_varstring::pack(uchar *to, const uchar *from, + uint max_length, + bool low_byte_first __attribute__((unused))) { uint length= length_bytes == 1 ? (uint) *from : uint2korr(from); set_if_smaller(max_length, field_length); if (length > max_length) length=max_length; - *to++= (char) (length & 255); + + /* Length always stored little-endian */ + *to++= length & 0xFF; if (max_length > 255) - *to++= (char) (length >> 8); - if (length) + *to++= (length >> 8) & 0xFF; + + /* Store bytes of string */ + if (length > 0) memcpy(to, from+length_bytes, length); return to+length; } -uchar *Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length) +uchar * +Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length, + bool low_byte_first __attribute__((unused))) { uint length= length_bytes == 1 ? (uint) *key : uint2korr(key); uint local_char_length= ((field_charset->mbmaxlen > 1) ? @@ -6850,8 +6974,9 @@ uchar *Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length) Pointer to end of 'key' (To the next key part if multi-segment key) */ -const uchar *Field_varstring::unpack_key(uchar *to, const uchar *key, - uint max_length) +const uchar * +Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length, + bool low_byte_first __attribute__((unused))) { /* get length of the blob key */ uint32 length= *key++; @@ -6880,8 +7005,9 @@ const uchar *Field_varstring::unpack_key(uchar *to, const uchar *key, end of key storage */ -uchar *Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, - uint max_length) +uchar * +Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) { /* Key length is always stored as 2 bytes */ uint length= uint2korr(from); @@ -6901,6 +7027,9 @@ uchar *Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, This method is used to unpack a varstring field from a master whose size of the field is less than that of the slave. + + @note + The string length is always packed little-endian. @param to Destination of the data @param from Source of the data @@ -6908,9 +7037,10 @@ uchar *Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, @return New pointer into memory based on from + length of the data */ -const uchar *Field_varstring::unpack(uchar *to, - const uchar *from, - uint param_data) +const uchar * +Field_varstring::unpack(uchar *to, const uchar *from, + uint param_data, + bool low_byte_first __attribute__((unused))) { uint length; uint l_bytes= (param_data && (param_data < field_length)) ? @@ -6922,28 +7052,7 @@ const uchar *Field_varstring::unpack(uchar *to, if (length_bytes == 2) to[1]= 0; } - else - { - length= uint2korr(from); - to[0]= *from++; - to[1]= *from++; - } - if (length) - memcpy(to+ length_bytes, from, length); - return from+length; -} - - -/* - unpack field packed with Field_varstring::pack() -*/ - -const uchar *Field_varstring::unpack(uchar *to, const uchar *from) -{ - uint length; - if (length_bytes == 1) - length= (uint) (*to= *from++); - else + else /* l_bytes == 2 */ { length= uint2korr(from); to[0]= *from++; @@ -7192,9 +7301,9 @@ void Field_blob::store_length(uchar *i_ptr, } -uint32 Field_blob::get_length(const uchar *pos, bool low_byte_first) +uint32 Field_blob::get_length(const uchar *pos, uint packlength_arg, bool low_byte_first) { - switch (packlength) { + switch (packlength_arg) { case 1: return (uint32) pos[0]; case 2: @@ -7608,28 +7717,37 @@ void Field_blob::sql_type(String &res) const } } - -uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length) +uchar *Field_blob::pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first) { + DBUG_ENTER("Field_blob::pack"); + DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx;" + " max_length: %u; low_byte_first: %d", + (ulong) to, (ulong) from, + max_length, low_byte_first)); + DBUG_DUMP("record", from, table->s->reclength); uchar *save= ptr; ptr= (uchar*) from; uint32 length=get_length(); // Length of from string - if (length > max_length) - { - ptr=to; - length=max_length; - store_length(length); // Store max length - ptr= (uchar*) from; - } - else - memcpy(to,from,packlength); // Copy length - if (length) + + /* + Store max length, which will occupy packlength bytes. If the max + length given is smaller than the actual length of the blob, we + just store the initial bytes of the blob. + */ + store_length(to, packlength, min(length, max_length), low_byte_first); + + /* + Store the actual blob data, which will occupy 'length' bytes. + */ + if (length > 0) { get_ptr((uchar**) &from); memcpy(to+packlength, from,length); } ptr=save; // Restore org row pointer - return to+packlength+length; + DBUG_DUMP("packed", to, packlength + length); + DBUG_RETURN(to+packlength+length); } @@ -7644,28 +7762,26 @@ uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length) @param to Destination of the data @param from Source of the data - @param param_data @return New pointer into memory based on from + length of the data */ const uchar *Field_blob::unpack(uchar *to, const uchar *from, - uint param_data) + uint param_data, + bool low_byte_first) { - return unpack(to, from); -} - - -const uchar *Field_blob::unpack(uchar *to, const uchar *from) -{ - memcpy(to,from,packlength); - uint32 length=get_length(from); - from+=packlength; - if (length) - memcpy_fixed(to+packlength, &from, sizeof(from)); - else - bzero(to+packlength,sizeof(from)); - return from+length; + DBUG_ENTER("Field_blob::unpack"); + DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx;" + " param_data: %u; low_byte_first: %d", + (ulong) to, (ulong) from, param_data, low_byte_first)); + uint const master_packlength= + param_data > 0 ? param_data & 0xFF : packlength; + uint32 const length= get_length(from, master_packlength, low_byte_first); + DBUG_DUMP("packed", from, length + master_packlength); + store(reinterpret_cast(from) + master_packlength, + length, field_charset); + DBUG_DUMP("record", to, table->s->reclength); + DBUG_RETURN(from + master_packlength + length); } /* Keys for blobs are like keys on varchars */ @@ -7715,7 +7831,9 @@ int Field_blob::pack_cmp(const uchar *b, uint key_length_arg, /* Create a packed key that will be used for storage from a MySQL row */ -uchar *Field_blob::pack_key(uchar *to, const uchar *from, uint max_length) +uchar * +Field_blob::pack_key(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) { uchar *save= ptr; ptr= (uchar*) from; @@ -7760,8 +7878,9 @@ uchar *Field_blob::pack_key(uchar *to, const uchar *from, uint max_length) Pointer into 'from' past the last byte copied from packed key. */ -const uchar *Field_blob::unpack_key(uchar *to, const uchar *from, - uint max_length) +const uchar * +Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) { /* get length of the blob key */ uint32 length= *from++; @@ -7784,8 +7903,9 @@ const uchar *Field_blob::unpack_key(uchar *to, const uchar *from, /* Create a packed key that will be used for storage from a MySQL key */ -uchar *Field_blob::pack_key_from_key_image(uchar *to, const uchar *from, - uint max_length) +uchar * +Field_blob::pack_key_from_key_image(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) { uint length=uint2korr(from); if (length > max_length) @@ -8672,9 +8792,11 @@ void Field_bit::sql_type(String &res) const } -uchar *Field_bit::pack(uchar *to, const uchar *from, uint max_length) +uchar * +Field_bit::pack(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) { - DBUG_ASSERT(max_length); + DBUG_ASSERT(max_length > 0); uint length; if (bit_len > 0) { @@ -8709,28 +8831,44 @@ uchar *Field_bit::pack(uchar *to, const uchar *from, uint max_length) /** Unpack a bit field from row data. - This method is used to unpack a bit field from a master whose size + This method is used to unpack a bit field from a master whose size of the field is less than that of the slave. - + @param to Destination of the data @param from Source of the data @param param_data Bit length (upper) and length (lower) values @return New pointer into memory based on from + length of the data */ -const uchar *Field_bit::unpack(uchar *to, - const uchar *from, - uint param_data) +const uchar * +Field_bit::unpack(uchar *to, const uchar *from, uint param_data, + bool low_byte_first __attribute__((unused))) { uint const from_len= (param_data >> 8U) & 0x00ff; uint const from_bit_len= param_data & 0x00ff; /* - If the master and slave have the same sizes, then use the old - unpack() method. + If the parameter data is zero (i.e., undefined), or if the master + and slave have the same sizes, then use the old unpack() method. */ - if ((from_bit_len == bit_len) && - (from_len == bytes_in_rec)) - return(unpack(to, from)); + if (param_data == 0 || + (from_bit_len == bit_len) && (from_len == bytes_in_rec)) + { + if (bit_len > 0) + { + /* + set_rec_bits is a macro, don't put the post-increment in the + argument since that might cause strange side-effects. + + For the choice of the second argument, see the explanation for + Field_bit::pack(). + */ + set_rec_bits(*from, bit_ptr + (to - ptr), bit_ofs, bit_len); + from++; + } + memcpy(to, from, bytes_in_rec); + return from + bytes_in_rec; + } + /* We are converting a smaller bit field to a larger one here. To do that, we first need to construct a raw value for the original @@ -8758,25 +8896,6 @@ const uchar *Field_bit::unpack(uchar *to, } -const uchar *Field_bit::unpack(uchar *to, const uchar *from) -{ - if (bit_len > 0) - { - /* - set_rec_bits is a macro, don't put the post-increment in the - argument since that might cause strange side-effects. - - For the choice of the second argument, see the explanation for - Field_bit::pack(). - */ - set_rec_bits(*from, bit_ptr + (to - ptr), bit_ofs, bit_len); - from++; - } - memcpy(to, from, bytes_in_rec); - return from + bytes_in_rec; -} - - void Field_bit::set_default() { if (bit_len > 0) diff --git a/sql/field.h b/sql/field.h index 60f6fc19d76..37a0cdae070 100644 --- a/sql/field.h +++ b/sql/field.h @@ -157,6 +157,17 @@ public: */ virtual uint32 data_length() { return pack_length(); } virtual uint32 sort_length() const { return pack_length(); } + + /** + Get the maximum size of the data in packed format. + + @return Maximum data length of the field when packed using the + Field::pack() function. + */ + virtual uint32 max_data_length() const { + return pack_length(); + }; + virtual int reset(void) { bzero(ptr,pack_length()); return 0; } virtual void reset_fields() {} virtual void set_default() @@ -339,32 +350,45 @@ public: return str; } virtual bool send_binary(Protocol *protocol); - virtual uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0) + + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); + /** + @overload Field::pack(uchar*, const uchar*, uint, bool) + */ + uchar *pack(uchar *to, const uchar *from) { - uint32 length=pack_length(); - memcpy(to,from,length); - return to+length; + DBUG_ENTER("Field::pack"); + uchar *result= this->pack(to, from, UINT_MAX, table->s->db_low_byte_first); + DBUG_RETURN(result); } - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); - virtual const uchar *unpack(uchar* to, const uchar *from) + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first); + /** + @overload Field::unpack(uchar*, const uchar*, uint, bool) + */ + const uchar *unpack(uchar* to, const uchar *from) { - uint length=pack_length(); - memcpy(to,from,length); - return from+length; + DBUG_ENTER("Field::unpack"); + const uchar *result= unpack(to, from, 0U, table->s->db_low_byte_first); + DBUG_RETURN(result); } - virtual uchar *pack_key(uchar* to, const uchar *from, uint max_length) + + virtual uchar *pack_key(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) { - return pack(to,from,max_length); + return pack(to, from, max_length, low_byte_first); } virtual uchar *pack_key_from_key_image(uchar* to, const uchar *from, - uint max_length) + uint max_length, bool low_byte_first) { - return pack(to,from,max_length); + return pack(to, from, max_length, low_byte_first); } virtual const uchar *unpack_key(uchar* to, const uchar *from, - uint max_length) + uint max_length, bool low_byte_first) { - return unpack(to,from); + return unpack(to, from, max_length, low_byte_first); } virtual uint packed_col_length(const uchar *to, uint length) { return length;} @@ -536,6 +560,7 @@ public: {} int store_decimal(const my_decimal *d); + uint32 max_data_length() const; }; /* base class for float and double and decimal (old one) */ @@ -556,6 +581,10 @@ public: int truncate(double *nr, double max_length); uint32 max_display_length() { return field_length; } uint size_of() const { return sizeof(*this); } + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first); + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first); }; @@ -584,6 +613,16 @@ public: void overflow(bool negative); bool zero_pack() const { return 0; } void sql_type(String &str) const; + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + return Field::unpack(to, from, param_data, low_byte_first); + } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + return Field::pack(to, from, max_length, low_byte_first); + } }; @@ -629,7 +668,8 @@ public: uint size_of() const { return sizeof(*this); } uint32 pack_length() const { return (uint32) bin_size; } uint is_equal(Create_field *new_field); - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first); }; @@ -660,6 +700,20 @@ public: uint32 pack_length() const { return 1; } void sql_type(String &str) const; uint32 max_display_length() { return 4; } + + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + *to= *from; + return to + 1; + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + *to= *from; + return from + 1; + } }; @@ -695,8 +749,47 @@ public: uint32 pack_length() const { return 2; } void sql_type(String &str) const; uint32 max_display_length() { return 6; } -}; + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + int16 val; +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + val = sint2korr(from); + else +#endif + shortget(val, from); + +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + int2store(to, val); + else +#endif + shortstore(to, val); + return to + sizeof(val); + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + int16 val; +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + val = sint2korr(from); + else +#endif + shortget(val, from); + +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + int2store(to, val); + else +#endif + shortstore(to, val); + return from + sizeof(val); + } +}; class Field_medium :public Field_num { public: @@ -725,6 +818,18 @@ public: uint32 pack_length() const { return 3; } void sql_type(String &str) const; uint32 max_display_length() { return 8; } + + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + return Field::pack(to, from, max_length, low_byte_first); + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + return Field::unpack(to, from, param_data, low_byte_first); + } }; @@ -760,6 +865,45 @@ public: uint32 pack_length() const { return 4; } void sql_type(String &str) const; uint32 max_display_length() { return MY_INT32_NUM_DECIMAL_DIGITS; } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + int32 val; +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + val = sint4korr(from); + else +#endif + longget(val, from); + +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + int4store(to, val); + else +#endif + longstore(to, val); + return to + sizeof(val); + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + int32 val; +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + val = sint4korr(from); + else +#endif + longget(val, from); + +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + int4store(to, val); + else +#endif + longstore(to, val); + return from + sizeof(val); + } }; @@ -802,6 +946,45 @@ public: void sql_type(String &str) const; bool can_be_compared_as_longlong() const { return TRUE; } uint32 max_display_length() { return 20; } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + int64 val; +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + val = sint8korr(from); + else +#endif + longlongget(val, from); + +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + int8store(to, val); + else +#endif + longlongstore(to, val); + return to + sizeof(val); + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + int64 val; +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + val = sint8korr(from); + else +#endif + longlongget(val, from); + +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + int8store(to, val); + else +#endif + longlongstore(to, val); + return from + sizeof(val); + } }; #endif @@ -1176,9 +1359,10 @@ public: int cmp(const uchar *,const uchar *); void sort_string(uchar *buff,uint length); void sql_type(String &str) const; - uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0); - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); - const uchar *unpack(uchar* to, const uchar *from); + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first); int pack_cmp(const uchar *a,const uchar *b,uint key_length, my_bool insert_or_update); int pack_cmp(const uchar *b,uint key_length,my_bool insert_or_update); @@ -1250,13 +1434,15 @@ public: uint get_key_image(uchar *buff,uint length, imagetype type); void set_key_image(const uchar *buff,uint length); void sql_type(String &str) const; - uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0); - uchar *pack_key(uchar *to, const uchar *from, uint max_length); + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); + uchar *pack_key(uchar *to, const uchar *from, uint max_length, bool low_byte_first); uchar *pack_key_from_key_image(uchar* to, const uchar *from, - uint max_length); - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); - const uchar *unpack(uchar* to, const uchar *from); - const uchar *unpack_key(uchar* to, const uchar *from, uint max_length); + uint max_length, bool low_byte_first); + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first); + const uchar *unpack_key(uchar* to, const uchar *from, + uint max_length, bool low_byte_first); int pack_cmp(const uchar *a, const uchar *b, uint key_length, my_bool insert_or_update); int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update); @@ -1346,7 +1532,7 @@ public: uint32 pack_length_no_ptr() const { return (uint32) (packlength); } uint32 sort_length() const; - inline uint32 max_data_length() const + virtual uint32 max_data_length() const { return (uint32) (((ulonglong) 1 << (packlength*8)) -1); } @@ -1374,13 +1560,13 @@ public: @retval The length in the row plus the size of the data. */ uint32 get_packed_size(const uchar *ptr_arg, bool low_byte_first) - {return packlength + get_length(ptr_arg, low_byte_first);} + {return packlength + get_length(ptr_arg, packlength, low_byte_first);} inline uint32 get_length(uint row_offset= 0) - { return get_length(ptr+row_offset, table->s->db_low_byte_first); } - uint32 get_length(const uchar *ptr, bool low_byte_first); + { return get_length(ptr+row_offset, this->packlength, table->s->db_low_byte_first); } + uint32 get_length(const uchar *ptr, uint packlength, bool low_byte_first); uint32 get_length(const uchar *ptr_arg) - { return get_length(ptr_arg, table->s->db_low_byte_first); } + { return get_length(ptr_arg, this->packlength, table->s->db_low_byte_first); } void put_length(uchar *pos, uint32 length); inline void get_ptr(uchar **str) { @@ -1421,13 +1607,16 @@ public: memcpy_fixed(ptr+packlength,&tmp,sizeof(char*)); return 0; } - uchar *pack(uchar *to, const uchar *from, uint max_length= ~(uint) 0); - uchar *pack_key(uchar *to, const uchar *from, uint max_length); + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); + uchar *pack_key(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); uchar *pack_key_from_key_image(uchar* to, const uchar *from, - uint max_length); - virtual const uchar *unpack(uchar *to, const uchar *from, uint param_data); - const uchar *unpack(uchar *to, const uchar *from); - const uchar *unpack_key(uchar* to, const uchar *from, uint max_length); + uint max_length, bool low_byte_first); + virtual const uchar *unpack(uchar *to, const uchar *from, + uint param_data, bool low_byte_first); + const uchar *unpack_key(uchar* to, const uchar *from, + uint max_length, bool low_byte_first); int pack_cmp(const uchar *a, const uchar *b, uint key_length, my_bool insert_or_update); int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update); @@ -1572,6 +1761,7 @@ public: enum_field_types type() const { return MYSQL_TYPE_BIT; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; } uint32 key_length() const { return (uint32) (field_length + 7) / 8; } + uint32 max_data_length() const { return (field_length + 7) / 8; } uint32 max_display_length() { return field_length; } uint size_of() const { return sizeof(*this); } Item_result result_type () const { return INT_RESULT; } @@ -1602,9 +1792,10 @@ public: uint32 pack_length() const { return (uint32) (field_length + 7) / 8; } uint32 pack_length_in_rec() const { return bytes_in_rec; } void sql_type(String &str) const; - uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0); - virtual const uchar *unpack(uchar *to, const uchar *from, uint param_data); - const uchar *unpack(uchar* to, const uchar *from); + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); + virtual const uchar *unpack(uchar *to, const uchar *from, + uint param_data, bool low_byte_first); virtual void set_default(); Field *new_key_field(MEM_ROOT *root, struct st_table *new_table, diff --git a/sql/log.cc b/sql/log.cc index dcf27161f1a..4d1ef9eed9f 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3571,9 +3571,6 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) (!binlog_filter->db_ok(local_db))) { VOID(pthread_mutex_unlock(&LOCK_log)); - DBUG_PRINT("info",("OPTION_BIN_LOG is %s, db_ok('%s') == %d", - (thd->options & OPTION_BIN_LOG) ? "set" : "clear", - local_db, binlog_filter->db_ok(local_db))); DBUG_RETURN(0); } #endif /* HAVE_REPLICATION */ diff --git a/sql/log_event.cc b/sql/log_event.cc index cfac7df21a8..cf4bb229b2f 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5697,7 +5697,9 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, *description_event) : Log_event(buf, description_event), m_row_count(0), +#ifndef MYSQL_CLIENT m_table(NULL), +#endif m_rows_buf(0), m_rows_cur(0), m_rows_end(0), m_curr_row(NULL), m_curr_row_end(NULL), m_key(NULL) @@ -6168,6 +6170,8 @@ int Rows_log_event::do_apply_event(RELAY_LOG_INFO const *rli) unpack_current_row(rli); // at this moment m_curr_row_end should be set + DBUG_PRINT("debug", ("m_curr_row_end: 0x%lx; m_curr_row: 0x%lx; m_rows_end: 0x%lx", + m_curr_row_end, m_curr_row, m_rows_end)); DBUG_ASSERT(error || m_curr_row_end != NULL); DBUG_ASSERT(error || m_curr_row < m_curr_row_end); DBUG_ASSERT(error || m_curr_row_end <= m_rows_end); diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index de4f6e0c337..dbfe7902ee9 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -65,6 +65,8 @@ pack_row(TABLE *table, MY_BITMAP const* cols, my_ptrdiff_t const rec_offset= record - table->record[0]; my_ptrdiff_t const def_offset= table->s->default_values - table->record[0]; + DBUG_ENTER("pack_row"); + /* We write the null bits and the packed records using one pass through all the fields. The null bytes are written little-endian, @@ -96,26 +98,14 @@ pack_row(TABLE *table, MY_BITMAP const* cols, For big-endian machines, we have to make sure that the length is stored in little-endian format, since this is the format used for the binlog. - - We do this by setting the db_low_byte_first, which is used - inside some store_length() to decide what order to write the - bytes in. - - In reality, db_log_byte_first is only set for legacy table - type Isam, but in the event of a bug, we need to guarantee - the endianess when writing to the binlog. - - This is currently broken for NDB due to BUG#29549, so we - will fix it when NDB has fixed their way of handling BLOBs. */ -#if 0 - bool save= table->s->db_low_byte_first; - table->s->db_low_byte_first= TRUE; -#endif - pack_ptr= field->pack(pack_ptr, field->ptr + offset); -#if 0 - table->s->db_low_byte_first= save; -#endif + const uchar *old_pack_ptr= pack_ptr; + pack_ptr= field->pack(pack_ptr, field->ptr + offset, + field->max_data_length(), TRUE); + DBUG_PRINT("debug", ("field: %s; pack_ptr: 0x%lx;" + " pack_ptr':0x%lx; bytes: %d", + field->field_name, (ulong) old_pack_ptr, + (ulong) pack_ptr, pack_ptr - old_pack_ptr)); } null_mask <<= 1; @@ -143,8 +133,8 @@ pack_row(TABLE *table, MY_BITMAP const* cols, packed data. If it doesn't, something is very wrong. */ DBUG_ASSERT(null_ptr == row_data + null_byte_count); - - return static_cast(pack_ptr - row_data); + DBUG_DUMP("row_data", row_data, pack_ptr - row_data); + DBUG_RETURN(static_cast(pack_ptr - row_data)); } #endif @@ -242,18 +232,14 @@ unpack_row(RELAY_LOG_INFO const *rli, Use the master's size information if available else call normal unpack operation. */ -#if 0 - bool save= table->s->db_low_byte_first; - table->s->db_low_byte_first= TRUE; -#endif uint16 const metadata= tabledef->field_metadata(i); - if (tabledef && metadata) - pack_ptr= f->unpack(f->ptr, pack_ptr, metadata); - else - pack_ptr= f->unpack(f->ptr, pack_ptr); -#if 0 - table->s->db_low_byte_first= save; -#endif + uchar const *const old_pack_ptr= pack_ptr; + pack_ptr= f->unpack(f->ptr, pack_ptr, metadata, TRUE); + DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;" + " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", + f->field_name, metadata, + (ulong) old_pack_ptr, (ulong) pack_ptr, + pack_ptr - old_pack_ptr)); } null_mask <<= 1; @@ -265,6 +251,7 @@ unpack_row(RELAY_LOG_INFO const *rli, throw away master's extra fields */ uint max_cols= min(tabledef->size(), cols->n_bits); + DBUG_PRINT("debug", ("Master has %u fields, slave %u", tabledef->size(), cols->n_bits)); for (; i < max_cols; i++) { if (bitmap_is_set(cols, i)) @@ -279,6 +266,7 @@ unpack_row(RELAY_LOG_INFO const *rli, if (!((null_bits & null_mask) && tabledef->maybe_null(i))) pack_ptr+= tabledef->calc_field_size(i, (uchar *) pack_ptr); + DBUG_PRINT("debug", ("pack_ptr: 0x%lx", (ulong) pack_ptr)); null_mask <<= 1; } } @@ -289,6 +277,8 @@ unpack_row(RELAY_LOG_INFO const *rli, */ DBUG_ASSERT(null_ptr == row_data + master_null_byte_count); + DBUG_DUMP("row_data", row_data, pack_ptr - row_data); + *row_end = pack_ptr; if (master_reclength) { diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bb4f5107df8..49910e75286 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -29,6 +29,8 @@ #include "event_data_objects.h" #include +#define STR_OR_NIL(S) ((S) ? (S) : "") + #ifdef WITH_PARTITION_STORAGE_ENGINE #include "ha_partition.h" #endif @@ -3096,8 +3098,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) schema_table_idx= get_schema_table_idx(schema_table); get_lookup_field_values(thd, cond, tables, &lookup_field_vals); DBUG_PRINT("INDEX VALUES",("db_name='%s', table_name='%s'", - lookup_field_vals.db_value.str, - lookup_field_vals.table_value.str)); + STR_OR_NIL(lookup_field_vals.db_value.str), + STR_OR_NIL(lookup_field_vals.table_value.str))); if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value) { From b3b01cf48b6ab3139ee782ac91cf804a3efb7f2a Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 12 Oct 2007 18:22:31 +0200 Subject: [PATCH 032/136] BUG#29549 (Endians: rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb and rpl_ndb_mix_innodb failed on): Post-merge fixes. Setting write bit before calling Field::store() since the function asserts that the write bit has been set. sql/field.cc: Setting bit in write set to prevent assertion from throwing when calling Field::store(). --- sql/field.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/field.cc b/sql/field.cc index a872beab726..29a4fcc1947 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7962,6 +7962,7 @@ const uchar *Field_blob::unpack(uchar *to, param_data > 0 ? param_data & 0xFF : packlength; uint32 const length= get_length(from, master_packlength, low_byte_first); DBUG_DUMP("packed", from, length + master_packlength); + bitmap_set_bit(table->write_set, field_index); store(reinterpret_cast(from) + master_packlength, length, field_charset); DBUG_DUMP("record", to, table->s->reclength); From c8b6d1050933f0b9b18367c421702c9f16907de5 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 13 Oct 2007 15:49:42 +0300 Subject: [PATCH 033/136] Bug #29136 erred multi-delete on trans table does not rollback the statement similar to bug_27716, but it was stressed on in the synopsis on that there is another side of the artifact affecting behaviour in transaction. Fixed with deploying multi_delete::send_error() - otherwise never called - and refining its logic to perform binlogging job if needed. The changeset includes the following side effects: - added tests to check bug_23333's scenarios on the mixture of tables for multi_update; - fixes bug@30763 with two-liner patch and a test coinciding to one added for bug_23333. mysql-test/r/innodb.result: results changed mysql-test/r/mix_innodb_myisam_binlog.result: results changed mysql-test/r/multi_update.result: results changed mysql-test/t/innodb.test: trans table specific test added mysql-test/t/mix_innodb_myisam_binlog.test: multi-update and multi-delete of mixure of ta and not-ta tables tests added (relates to bug_23333). mysql-test/t/multi_update.test: testing another branch of mult-delete: send_eof() (binloggin there), send_error (early return) sql/sql_class.h: a new flag to designate the fact the statement's error has been handled. The flag is checked by ::send_error() methods (multi_update and _delete classes) sql/sql_delete.cc: expanding multi_delete::send_error to 1. early return if error_handled == t 2. binlogging locally if there was a non-trans table modified side effect sql/sql_parse.cc: adding multi_update::send_error which can perform binlogging and rollback job in needed sql/sql_update.cc: issues relating to 1. bug_27716 with zeroing of `updated' to serve as the flag of early return from send_error(). The flag is changed to be a new member error_handled; also moved outside binlogging branch. The reason for this change is that bug_23333 fixes were pushed after the bug_27716's and they left this flaw (also no test coverage). 2. bug_30763 with assertion on trans_safe. I decide to make 2 liner fix for that bug here instead of to remove those two assertions. This new bug test case is the same as for multi-update on the mixure of tables. The rational for this fix: presumption for mutli_update::trans_safe to be set to zero at multi_update::multi_update or multi_update::initialize_tables() is incorrect. trans_safe := false should happen only when a non-transactional table gets modified. Therefore, at initialization the member must be be set to true. --- mysql-test/r/innodb.result | 17 ++++- mysql-test/r/mix_innodb_myisam_binlog.result | 52 ++++++++++++-- mysql-test/r/multi_update.result | 24 ++++++- mysql-test/t/innodb.test | 32 +++++++++ mysql-test/t/mix_innodb_myisam_binlog.test | 76 ++++++++++++++++++-- mysql-test/t/multi_update.test | 34 +++++++++ sql/sql_class.h | 10 +++ sql/sql_delete.cc | 29 ++++++-- sql/sql_parse.cc | 7 ++ sql/sql_update.cc | 22 +++--- 10 files changed, 274 insertions(+), 29 deletions(-) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 6082a30bce3..38b26425ec8 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1119,6 +1119,19 @@ show master status /* there must be no UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 98 drop table t1, t2; +drop table if exists t1, t2; +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +create trigger trg_del_t2 after delete on t2 for each row +insert into t1 values (1); +insert into t1 values (1); +insert into t2 values (1),(2); +delete t2 from t2; +ERROR 23000: Duplicate entry '1' for key 1 +select count(*) from t2 /* must be 2 as restored after rollback caused by the error */; +count(*) +2 +drop table t1, t2; create table t1 (a int, b int) engine=innodb; insert into t1 values(20,null); select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on @@ -1792,10 +1805,10 @@ Variable_name Value Innodb_page_size 16384 show status like "Innodb_rows_deleted"; Variable_name Value -Innodb_rows_deleted 72 +Innodb_rows_deleted 73 show status like "Innodb_rows_inserted"; Variable_name Value -Innodb_rows_inserted 29732 +Innodb_rows_inserted 29734 show status like "Innodb_rows_updated"; Variable_name Value Innodb_rows_updated 29532 diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index 5d5726c9689..89ee82e9655 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -351,7 +351,7 @@ drop function if exists bug27417; drop table if exists t1,t2; CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); -create function bug27417(n int) +create function bug27417(n int) RETURNS int(11) begin insert into t1 values (null); @@ -393,7 +393,9 @@ count(*) drop table t1,t2; CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM; +CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb; +CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; insert into t2 values (1); reset master; insert into t2 values (bug27417(1)); @@ -427,6 +429,31 @@ master-bin.000001 190 select count(*) from t1 /* must be 2 */; count(*) 2 +delete from t3; +delete from t4; +insert into t3 values (1,1); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */; +ERROR 23000: Duplicate entry '2' for key 1 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 301 +select count(*) from t1 /* must be 4 */; +count(*) +4 +delete from t1; +delete from t3; +delete from t4; +insert into t3 values (1,1),(2,2); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t3,t4 SET t3.a=t4.a + bug27417(1); +ERROR 23000: Duplicate entry '2' for key 1 +select count(*) from t1 /* must be 1 */; +count(*) +1 +drop table t4; delete from t1; delete from t2; delete from t3; @@ -443,6 +470,23 @@ master-bin.000001 246 select count(*) from t1 /* must be 1 */; count(*) 1 +drop trigger trg_del; +delete from t1; +delete from t2; +delete from t5; +create trigger trg_del_t2 after delete on t2 for each row +insert into t1 values (1); +insert into t2 values (2),(3); +insert into t5 values (1),(2); +reset master; +delete t2.* from t2,t5 where t2.a=t5.a + 1; +ERROR 23000: Duplicate entry '1' for key 1 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 274 +select count(*) from t1 /* must be 1 */; +count(*) +1 delete from t1; create table t4 (a int default 0, b int primary key) engine=innodb; insert into t4 values (0, 17); @@ -458,7 +502,7 @@ count(*) show master status /* the offset must denote there is the query */; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 376 -drop trigger trg_del; -drop table t1,t2,t3,t4; +drop trigger trg_del_t2; +drop table t1,t2,t3,t4,t5; drop function bug27417; end of tests diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 0f624e3ee8d..d95036090a5 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -545,7 +545,7 @@ a b 4 4 show master status /* there must be the UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 189 +master-bin.000001 260 delete from t1; delete from t2; insert into t1 values (1,2),(3,4),(4,4); @@ -555,6 +555,26 @@ UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; ERROR 23000: Duplicate entry '4' for key 1 show master status /* there must be the UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 204 +master-bin.000001 275 drop table t1, t2; +drop table if exists t1, t2, t3; +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)); +CREATE TABLE t3 (a int, PRIMARY KEY (a)) ENGINE=MyISAM; +create trigger trg_del_t3 before delete on t3 for each row insert into t1 values (1); +insert into t2 values (1),(2); +insert into t3 values (1),(2); +reset master; +delete t3.* from t2,t3 where t2.a=t3.a; +ERROR 23000: Duplicate entry '1' for key 1 +select count(*) from t1 /* must be 1 */; +count(*) +1 +select count(*) from t3 /* must be 1 */; +count(*) +1 +show binlog events from 98; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 98 Query 1 # use `test`; delete t3.* from t2,t3 where t2.a=t3.a +drop table t1, t2, t3; end of tests diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 04dfa1d0836..d045bad39f7 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -792,6 +792,38 @@ show master status /* there must be no UPDATE query event */; # cleanup bug#27716 drop table t1, t2; +# +# Bug #29136 erred multi-delete on trans table does not rollback +# + +# prepare +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +create trigger trg_del_t2 after delete on t2 for each row + insert into t1 values (1); +insert into t1 values (1); +insert into t2 values (1),(2); + + +# exec cases A, B - see multi_update.test + +# A. send_error() w/o send_eof() branch + +--error ER_DUP_ENTRY +delete t2 from t2; + +# check + +select count(*) from t2 /* must be 2 as restored after rollback caused by the error */; + +# cleanup bug#29136 + +drop table t1, t2; + + # # Testing of IFNULL # diff --git a/mysql-test/t/mix_innodb_myisam_binlog.test b/mysql-test/t/mix_innodb_myisam_binlog.test index e1740bda03e..e0ce802254a 100644 --- a/mysql-test/t/mix_innodb_myisam_binlog.test +++ b/mysql-test/t/mix_innodb_myisam_binlog.test @@ -347,7 +347,7 @@ CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); delimiter |; -create function bug27417(n int) +create function bug27417(n int) RETURNS int(11) begin insert into t1 values (null); @@ -385,13 +385,17 @@ drop table t1,t2; # # Bug#23333 using the patch (and the test) for bug#27471 +# # throughout the bug tests # t1 - non-trans side effects gatherer; # t2 - transactional table; # + CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM; +CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb; +CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; # @@ -434,7 +438,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); select count(*) from t1 /* must be 2 */; # -# UPDATE (multi-update see bug#27716) +# UPDATE inc multi-update # # prepare @@ -450,9 +454,48 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); show master status /* the offset must denote there is the query */; select count(*) from t1 /* must be 2 */; +## multi_update::send_eof() branch + +# prepare + delete from t3; + delete from t4; + insert into t3 values (1,1); + insert into t4 values (1,1),(2,2); + + reset master; + +# execute + --error ER_DUP_ENTRY + UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */; + +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 4 */; + +## send_error() branch of multi_update + +# prepare + delete from t1; + delete from t3; + delete from t4; + insert into t3 values (1,1),(2,2); + insert into t4 values (1,1),(2,2); + + reset master; + +# execute + --error ER_DUP_ENTRY + UPDATE t3,t4 SET t3.a=t4.a + bug27417(1); + +# check + select count(*) from t1 /* must be 1 */; + +# cleanup + drop table t4; + # -# DELETE (for multi-delete see Bug #29136) +# DELETE incl multi-delete # # prepare @@ -472,6 +515,27 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); show master status /* the offset must denote there is the query */; select count(*) from t1 /* must be 1 */; +# cleanup + drop trigger trg_del; + +# prepare + delete from t1; + delete from t2; + delete from t5; + create trigger trg_del_t2 after delete on t2 for each row + insert into t1 values (1); + insert into t2 values (2),(3); + insert into t5 values (1),(2); + reset master; + +# execute + --error ER_DUP_ENTRY + delete t2.* from t2,t5 where t2.a=t5.a + 1; + +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 1 */; + # # LOAD DATA @@ -496,8 +560,8 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # -drop trigger trg_del; -drop table t1,t2,t3,t4; +drop trigger trg_del_t2; +drop table t1,t2,t3,t4,t5; drop function bug27417; diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 84e6a444d47..37cdfcf5f26 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -574,4 +574,38 @@ show master status /* there must be the UPDATE query event */; # cleanup bug#27716 drop table t1, t2; +# +# Bug #29136 erred multi-delete on trans table does not rollback +# + +# prepare +--disable_warnings +drop table if exists t1, t2, t3; +--enable_warnings +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)); +CREATE TABLE t3 (a int, PRIMARY KEY (a)) ENGINE=MyISAM; +create trigger trg_del_t3 before delete on t3 for each row insert into t1 values (1); + +insert into t2 values (1),(2); +insert into t3 values (1),(2); +reset master; + +# exec cases B, A - see innodb.test + +# B. send_eof() and send_error() afterward + +--error ER_DUP_ENTRY +delete t3.* from t2,t3 where t2.a=t3.a; + +# check +select count(*) from t1 /* must be 1 */; +select count(*) from t3 /* must be 1 */; +# the query must be in binlog (no surprise though) +source include/show_binlog_events.inc; + +# cleanup bug#29136 +drop table t1, t2, t3; + + --echo end of tests diff --git a/sql/sql_class.h b/sql/sql_class.h index a96000a0598..457c8c87fc8 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2356,6 +2356,11 @@ class multi_delete :public select_result_interceptor /* True if at least one table we delete from is not transactional */ bool normal_tables; bool delete_while_scanning; + /* + error handling (rollback and binlogging) can happen in send_eof() + so that afterward send_error() needs to find out that. + */ + bool error_handled; public: multi_delete(TABLE_LIST *dt, uint num_of_tables); @@ -2391,6 +2396,11 @@ class multi_update :public select_result_interceptor /* True if the update operation has made a change in a transactional table */ bool transactional_tables; bool ignore; + /* + error handling (rollback and binlogging) can happen in send_eof() + so that afterward send_error() needs to find out that. + */ + bool error_handled; public: multi_update(TABLE_LIST *ut, TABLE_LIST *leaves_list, diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 7555219f5d8..add37c8c552 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -504,7 +504,7 @@ bool mysql_multi_delete_prepare(THD *thd) multi_delete::multi_delete(TABLE_LIST *dt, uint num_of_tables_arg) : delete_tables(dt), deleted(0), found(0), num_of_tables(num_of_tables_arg), error(0), - do_delete(0), transactional_tables(0), normal_tables(0) + do_delete(0), transactional_tables(0), normal_tables(0), error_handled(0) { tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables); } @@ -685,12 +685,14 @@ void multi_delete::send_error(uint errcode,const char *err) /* First send error what ever it is ... */ my_message(errcode, err, MYF(0)); - /* If nothing deleted return */ - if (!deleted) + /* the error was handled or nothing deleted and no side effects return */ + if (error_handled || + !thd->transaction.stmt.modified_non_trans_table && !deleted) DBUG_VOID_RETURN; /* Something already deleted so we have to invalidate cache */ - query_cache_invalidate3(thd, delete_tables, 1); + if (deleted) + query_cache_invalidate3(thd, delete_tables, 1); /* If rows from the first table only has been deleted and it is @@ -710,12 +712,29 @@ void multi_delete::send_error(uint errcode,const char *err) */ error= 1; send_eof(); + DBUG_ASSERT(error_handled); + DBUG_VOID_RETURN; + } + + if (thd->transaction.stmt.modified_non_trans_table) + { + /* + there is only side effects; to binlog with the error + */ + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query, thd->query_length, + transactional_tables, FALSE); + mysql_bin_log.write(&qinfo); + } + thd->transaction.all.modified_non_trans_table= true; } DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); DBUG_VOID_RETURN; } + /* Do delete from other tables. Returns values: @@ -832,6 +851,8 @@ bool multi_delete::send_eof() if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; } + if (local_error != 0) + error_handled= TRUE; // to force early leave from ::send_error() /* Commit or rollback the current SQL statement */ if (transactional_tables) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f4ee2ffc0f7..77695f47b1f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3701,6 +3701,13 @@ end_with_restore_list: SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE, del_result, unit, select_lex); + res|= thd->net.report_error; + if (unlikely(res)) + { + /* If we had a another error reported earlier then this will be ignored */ + del_result->send_error(ER_UNKNOWN_ERROR, "Execution of the query failed"); + del_result->abort(); + } delete del_result; } else diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 3f38ad8b33c..f3695976508 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -994,8 +994,8 @@ multi_update::multi_update(TABLE_LIST *table_list, :all_tables(table_list), leaves(leaves_list), update_tables(0), tmp_tables(0), updated(0), found(0), fields(field_list), values(value_list), table_count(0), copy_field(0), - handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0), - transactional_tables(1), ignore(ignore_arg) + handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(1), + transactional_tables(1), ignore(ignore_arg), error_handled(0) {} @@ -1202,7 +1202,6 @@ multi_update::initialize_tables(JOIN *join) if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join)) DBUG_RETURN(1); main_table=join->join_tab->table; - trans_safe= transactional_tables= main_table->file->has_transactions(); table_to_update= 0; /* Any update has at least one pair (field, value) */ @@ -1484,12 +1483,14 @@ void multi_update::send_error(uint errcode,const char *err) /* First send error what ever it is ... */ my_error(errcode, MYF(0), err); - /* If nothing updated return */ - if (updated == 0) /* the counter might be reset in send_eof */ - return; /* and then the query has been binlogged */ + /* the error was handled or nothing deleted and no side effects return */ + if (error_handled || + !thd->transaction.stmt.modified_non_trans_table && !updated) + return; /* Something already updated so we have to invalidate cache */ - query_cache_invalidate3(thd, update_tables, 1); + if (updated) + query_cache_invalidate3(thd, update_tables, 1); /* If all tables that has been updated are trans safe then just do rollback. If not attempt to do remaining updates. @@ -1525,8 +1526,7 @@ void multi_update::send_error(uint errcode,const char *err) transactional_tables, FALSE); mysql_bin_log.write(&qinfo); } - if (!trans_safe) - thd->transaction.all.modified_non_trans_table= TRUE; + thd->transaction.all.modified_non_trans_table= TRUE; } DBUG_ASSERT(trans_safe || !updated || thd->transaction.stmt.modified_non_trans_table); @@ -1739,8 +1739,6 @@ bool multi_update::send_eof() { if (local_error == 0) thd->clear_error(); - else - updated= 0; /* if there's an error binlog it here not in ::send_error */ Query_log_event qinfo(thd, thd->query, thd->query_length, transactional_tables, FALSE); if (mysql_bin_log.write(&qinfo) && trans_safe) @@ -1749,6 +1747,8 @@ bool multi_update::send_eof() if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; } + if (local_error != 0) + error_handled= TRUE; // to force early leave from ::send_error() if (transactional_tables) { From bf9eb0f0d71f741d1ab9ff5375892d93b53c01d4 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 13 Oct 2007 23:12:50 +0300 Subject: [PATCH 034/136] manual merge for bug_29136, bug#29309. mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test: manual merge from 5.0 mysql-test/r/innodb.result: results changed mysql-test/r/multi_update.result: results changed mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result: manual merge: results re-recorded mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: results changed mysql-test/suite/manual/r/rpl_replication_delay.result: results recorded for 5.1 mysql-test/t/innodb.test: removing bug27716 regression test as one exists in binlog suite already. mysql-test/t/multi_update.test: manual merge plus refining for execution in both binlog_format. sql/log_event.cc: bloody manual merge; the fact that an event is artificial is encode with setting timestamp argument to zero. rli's last_master_timestamp won't be updated in stmt_done in such case. sql/rpl_rli.cc: simulation and the real fixing code. Don't update last_master_timestamp with zero. sql/sql_delete.cc: manual merge --- .../mix_innodb_myisam_side_effects.test | 74 +++++++++++++++++-- mysql-test/r/innodb.result | 17 ++++- mysql-test/r/multi_update.result | 23 +++++- .../r/binlog_row_mix_innodb_myisam.result | 59 +++++++++++++-- .../r/binlog_stm_mix_innodb_myisam.result | 59 +++++++++++++-- .../manual/r/rpl_replication_delay.result | 31 ++++++-- mysql-test/t/innodb.test | 39 ---------- mysql-test/t/multi_update.test | 8 +- sql/log_event.cc | 28 ++++++- sql/rpl_rli.cc | 10 ++- sql/sql_delete.cc | 6 +- 11 files changed, 278 insertions(+), 76 deletions(-) diff --git a/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test b/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test index 6c961c4694d..03514bfdb55 100644 --- a/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test +++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test @@ -126,7 +126,9 @@ drop table t1,t2; # CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM; +CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb; +CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; # @@ -169,7 +171,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); select count(*) from t1 /* must be 2 */; # -# UPDATE (multi-update see bug#27716) +# UPDATE inc multi-update # # prepare @@ -185,9 +187,48 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); source include/show_binlog_events.inc; # must be events of the query select count(*) from t1 /* must be 2 */; +## multi_update::send_eof() branch + +# prepare + delete from t3; + delete from t4; + insert into t3 values (1,1); + insert into t4 values (1,1),(2,2); + + reset master; + +# execute + --error ER_DUP_ENTRY + UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */; + +# check + source include/show_binlog_events.inc; # the offset must denote there is the query + select count(*) from t1 /* must be 4 */; + +## send_error() branch of multi_update + +# prepare + delete from t1; + delete from t3; + delete from t4; + insert into t3 values (1,1),(2,2); + insert into t4 values (1,1),(2,2); + + reset master; + +# execute + --error ER_DUP_ENTRY + UPDATE t3,t4 SET t3.a=t4.a + bug27417(1); + +# check + select count(*) from t1 /* must be 1 */; + +# cleanup + drop table t4; + # -# DELETE (for multi-delete see Bug #29136) +# DELETE incl multi-delete # # prepare @@ -203,6 +244,27 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # execute --error ER_DUP_ENTRY delete from t2; +# check + source include/show_binlog_events.inc; # the offset must denote there is the query + select count(*) from t1 /* must be 1 */; + +# cleanup + drop trigger trg_del; + +# prepare + delete from t1; + delete from t2; + delete from t5; + create trigger trg_del_t2 after delete on t2 for each row + insert into t1 values (1); + insert into t2 values (2),(3); + insert into t5 values (1),(2); + reset master; + +# execute + --error ER_DUP_ENTRY + delete t2.* from t2,t5 where t2.a=t5.a + 1; + # check source include/show_binlog_events.inc; # must be events of the query select count(*) from t1 /* must be 1 */; @@ -229,6 +291,8 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # # bug#23333 cleanup # -drop trigger trg_del; -drop table t1,t2,t3,t4; + + +drop trigger trg_del_t2; +drop table t1,t2,t3,t4,t5; drop function bug27417; diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index d0b67e90afb..e1cc365f5c3 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1086,6 +1086,19 @@ n d 1 30 2 20 drop table t1,t2; +drop table if exists t1, t2; +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +create trigger trg_del_t2 after delete on t2 for each row +insert into t1 values (1); +insert into t1 values (1); +insert into t2 values (1),(2); +delete t2 from t2; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +select count(*) from t2 /* must be 2 as restored after rollback caused by the error */; +count(*) +2 +drop table t1, t2; create table t1 (a int, b int) engine=innodb; insert into t1 values(20,null); select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on @@ -1751,10 +1764,10 @@ Variable_name Value Innodb_page_size 16384 show status like "Innodb_rows_deleted"; Variable_name Value -Innodb_rows_deleted 70 +Innodb_rows_deleted 71 show status like "Innodb_rows_inserted"; Variable_name Value -Innodb_rows_inserted 1083 +Innodb_rows_inserted 1085 show status like "Innodb_rows_updated"; Variable_name Value Innodb_rows_updated 886 diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 55e47756312..0bc01e95d2d 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -614,6 +614,7 @@ CREATE TABLE `t2` ( `b` int(11) default NULL, PRIMARY KEY (`a`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; +set @sav_binlog_format= @@session.binlog_format; set @@session.binlog_format= mixed; insert into t1 values (1,1),(2,2); insert into t2 values (1,1),(4,4); @@ -626,7 +627,7 @@ a b 4 4 show master status /* there must be the UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 197 +master-bin.000001 268 delete from t1; delete from t2; insert into t1 values (1,2),(3,4),(4,4); @@ -636,6 +637,24 @@ UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; ERROR 23000: Duplicate entry '4' for key 'PRIMARY' show master status /* there must be the UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 212 +master-bin.000001 283 drop table t1, t2; +set @@session.binlog_format= @sav_binlog_format; +drop table if exists t1, t2, t3; +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)); +CREATE TABLE t3 (a int, PRIMARY KEY (a)) ENGINE=MyISAM; +create trigger trg_del_t3 before delete on t3 for each row insert into t1 values (1); +insert into t2 values (1),(2); +insert into t3 values (1),(2); +reset master; +delete t3.* from t2,t3 where t2.a=t3.a; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +select count(*) from t1 /* must be 1 */; +count(*) +1 +select count(*) from t3 /* must be 1 */; +count(*) +1 +drop table t1, t2, t3; end of tests 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 8022f2b1e10..f69d5717a1f 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 @@ -520,7 +520,9 @@ count(*) drop table t1,t2; CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM; +CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb; +CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; insert into t2 values (1); reset master; insert into t2 values (bug27417(1)); @@ -559,6 +561,33 @@ master-bin.000001 # Query # # use `test`; update t3 set b=b+bug27417(1) select count(*) from t1 /* must be 2 */; count(*) 2 +delete from t3; +delete from t4; +insert into t3 values (1,1); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */; +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Query # # use `test`; UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */ +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 4 */; +count(*) +4 +delete from t1; +delete from t3; +delete from t4; +insert into t3 values (1,1),(2,2); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t3,t4 SET t3.a=t4.a + bug27417(1); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +select count(*) from t1 /* must be 1 */; +count(*) +1 +drop table t4; delete from t1; delete from t2; delete from t3; @@ -571,12 +600,30 @@ delete from t2; ERROR 23000: Duplicate entry '1' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Intvar # # INSERT_ID=9 master-bin.000001 # Query # # use `test`; delete from t2 master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) 1 +drop trigger trg_del; +delete from t1; +delete from t2; +delete from t5; +create trigger trg_del_t2 after delete on t2 for each row +insert into t1 values (1); +insert into t2 values (2),(3); +insert into t5 values (1),(2); +reset master; +delete t2.* from t2,t5 where t2.a=t5.a + 1; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; delete t2.* from t2,t5 where t2.a=t5.a + 1 +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 1 */; +count(*) +1 delete from t1; create table t4 (a int default 0, b int primary key) engine=innodb; insert into t4 values (0, 17); @@ -591,11 +638,11 @@ count(*) 2 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12 -master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=1 master-bin.000001 # Query # # use `test`; ROLLBACK -drop trigger trg_del; -drop table t1,t2,t3,t4; +drop trigger trg_del_t2; +drop table t1,t2,t3,t4,t5; drop function bug27417; 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 9c580b2312e..c15478bc826 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 @@ -494,7 +494,9 @@ count(*) drop table t1,t2; CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM; +CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb; +CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; insert into t2 values (1); reset master; insert into t2 values (bug27417(1)); @@ -533,6 +535,33 @@ master-bin.000001 # Query # # use `test`; update t3 set b=b+bug27417(1) select count(*) from t1 /* must be 2 */; count(*) 2 +delete from t3; +delete from t4; +insert into t3 values (1,1); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */; +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Query # # use `test`; UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */ +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 4 */; +count(*) +4 +delete from t1; +delete from t3; +delete from t4; +insert into t3 values (1,1),(2,2); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t3,t4 SET t3.a=t4.a + bug27417(1); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +select count(*) from t1 /* must be 1 */; +count(*) +1 +drop table t4; delete from t1; delete from t2; delete from t3; @@ -545,12 +574,30 @@ delete from t2; ERROR 23000: Duplicate entry '1' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Intvar # # INSERT_ID=9 master-bin.000001 # Query # # use `test`; delete from t2 master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) 1 +drop trigger trg_del; +delete from t1; +delete from t2; +delete from t5; +create trigger trg_del_t2 after delete on t2 for each row +insert into t1 values (1); +insert into t2 values (2),(3); +insert into t5 values (1),(2); +reset master; +delete t2.* from t2,t5 where t2.a=t5.a + 1; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; delete t2.* from t2,t5 where t2.a=t5.a + 1 +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 1 */; +count(*) +1 delete from t1; create table t4 (a int default 0, b int primary key) engine=innodb; insert into t4 values (0, 17); @@ -565,13 +612,13 @@ count(*) 2 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12 -master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=1 master-bin.000001 # Query # # use `test`; ROLLBACK -drop trigger trg_del; -drop table t1,t2,t3,t4; +drop trigger trg_del_t2; +drop table t1,t2,t3,t4,t5; drop function bug27417; set @@session.binlog_format=@@global.binlog_format; end of tests diff --git a/mysql-test/suite/manual/r/rpl_replication_delay.result b/mysql-test/suite/manual/r/rpl_replication_delay.result index 22447a30cba..a8fa6ce8265 100644 --- a/mysql-test/suite/manual/r/rpl_replication_delay.result +++ b/mysql-test/suite/manual/r/rpl_replication_delay.result @@ -11,7 +11,7 @@ Master_User root Master_Port 9306 Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 98 +Read_Master_Log_Pos 106 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -26,7 +26,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 98 +Exec_Master_Log_Pos 106 Relay_Log_Space # Until_Condition None Until_Log_File @@ -38,6 +38,11 @@ Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master 0 +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error drop table if exists t1; Warnings: Note 1051 Unknown table 't1' @@ -52,7 +57,7 @@ Master_User root Master_Port 9306 Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 359 +Read_Master_Log_Pos 367 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -67,7 +72,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 271 +Exec_Master_Log_Pos 279 Relay_Log_Space # Until_Condition None Until_Log_File @@ -78,7 +83,12 @@ Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key -Seconds_Behind_Master 10 +Seconds_Behind_Master 9 +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error unlock tables; flush logs /* this time rli->last_master_timestamp is not affected */; lock table t1 write; @@ -90,7 +100,7 @@ Master_User root Master_Port 9306 Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 447 +Read_Master_Log_Pos 455 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -105,7 +115,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 359 +Exec_Master_Log_Pos 367 Relay_Log_Space # Until_Condition None Until_Log_File @@ -116,6 +126,11 @@ Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key -Seconds_Behind_Master 6 +Seconds_Behind_Master 7 +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error unlock tables; drop table t1; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 63682ab96eb..c7fe033fd36 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -753,45 +753,6 @@ select * from t1; select * from t2; drop table t1,t2; -# -# Bug#27716 multi-update did partially and has not binlogged -# - -CREATE TABLE `t1` ( - `a` int(11) NOT NULL auto_increment, - `b` int(11) default NULL, - PRIMARY KEY (`a`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; - -CREATE TABLE `t2` ( - `a` int(11) NOT NULL auto_increment, - `b` int(11) default NULL, - PRIMARY KEY (`a`) -) ENGINE=INNODB DEFAULT CHARSET=latin1 ; - -# A. testing multi_update::send_eof() execution branch -insert into t1 values (1,1),(2,2); -insert into t2 values (1,1),(4,4); -reset master; ---error ER_DUP_ENTRY -UPDATE t2,t1 SET t2.a=t1.a+2; -# check -select * from t2 /* must be (3,1), (4,4) */; -show master status /* there must no UPDATE in binlog */; - -# B. testing multi_update::send_error() execution branch -delete from t1; -delete from t2; -insert into t1 values (1,2),(3,4),(4,4); -insert into t2 values (1,2),(3,4),(4,4); -reset master; ---error ER_DUP_ENTRY -UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; -show master status /* there must be no UPDATE query event */; - -# cleanup bug#27716 -drop table t1, t2; - # # Bug #29136 erred multi-delete on trans table does not rollback # diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 8b8132df84a..331663dceb5 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -588,6 +588,7 @@ CREATE TABLE `t2` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; # as the test is about to see erroed queries in binlog +set @sav_binlog_format= @@session.binlog_format; set @@session.binlog_format= mixed; @@ -614,6 +615,7 @@ show master status /* there must be the UPDATE query event */; # cleanup bug#27716 drop table t1, t2; +set @@session.binlog_format= @sav_binlog_format; # # Bug #29136 erred multi-delete on trans table does not rollback @@ -642,11 +644,13 @@ delete t3.* from t2,t3 where t2.a=t3.a; # check select count(*) from t1 /* must be 1 */; select count(*) from t3 /* must be 1 */; -# the query must be in binlog (no surprise though) -source include/show_binlog_events.inc; # cleanup bug#29136 drop table t1, t2, t3; +# +# Add further tests from here +# + --echo end of tests diff --git a/sql/log_event.cc b/sql/log_event.cc index 31309694c1a..ec4d6820cca 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -558,8 +558,32 @@ int Log_event::do_update_pos(Relay_log_info *rli) Matz: I don't think we will need this check with this refactoring. */ if (rli) - rli->stmt_done(log_pos, when); - + { + /* + bug#29309 simulation: resetting the flag to force + wrong behaviour of artificial event to update + rli->last_master_timestamp for only one time - + the first FLUSH LOGS in the test. + */ + DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp", + if (debug_not_change_ts_if_art_event == 1 + && is_artificial_event()) + { + debug_not_change_ts_if_art_event= 0; + }); +#ifndef DBUG_OFF + rli->stmt_done(log_pos, + is_artificial_event() && + debug_not_change_ts_if_art_event > 0 ? 0 : when); +#else + rli->stmt_done(log_pos, is_artificial_event()? 0 : when); +#endif + DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp", + if (debug_not_change_ts_if_art_event == 0) + { + debug_not_change_ts_if_art_event= 2; + }); + } return 0; // Cannot fail currently } diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 867d55a60a3..15d7d97affd 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1082,6 +1082,9 @@ bool Relay_log_info::cached_charset_compare(char *charset) const void Relay_log_info::stmt_done(my_off_t event_master_log_pos, time_t event_creation_time) { +#ifndef DBUG_OFF + extern uint debug_not_change_ts_if_art_event; +#endif clear_flag(IN_STMT); /* @@ -1121,7 +1124,12 @@ void Relay_log_info::stmt_done(my_off_t event_master_log_pos, is that value may take some time to display in Seconds_Behind_Master - not critical). */ - last_master_timestamp= event_creation_time; +#ifndef DBUG_OFF + if (!(event_creation_time == 0 && debug_not_change_ts_if_art_event > 0)) +#else + if (event_creation_time != 0) +#endif + last_master_timestamp= event_creation_time; } } diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index aad0514b10b..b4b877b9a37 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -758,9 +758,9 @@ void multi_delete::send_error(uint errcode,const char *err) */ if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); - mysql_bin_log.write(&qinfo); + thd->binlog_query(THD::ROW_QUERY_TYPE, + thd->query, thd->query_length, + transactional_tables, FALSE); } thd->transaction.all.modified_non_trans_table= true; } From 1590fa13ff044c1c779a11b716394fc76453424e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 16 Oct 2007 15:22:44 +0500 Subject: [PATCH 035/136] After merge fix: Adjusting SHOW CREATE TABLE output from 5.0 to 5.1 format mysql-test/r/ctype_uca.result: Adjusting SHOW CREATE TABLE output mysql-test/r/ctype_ucs.result: Adjusting SHOW CREATE TABLE output mysql-test/r/ctype_utf8.result: Adjusting SHOW CREATE TABLE output mysql-test/r/func_regexp.result: Adjusting SHOW CREATE TABLE output --- mysql-test/r/ctype_uca.result | 4 ++-- mysql-test/r/ctype_ucs.result | 4 ++-- mysql-test/r/ctype_utf8.result | 4 ++-- mysql-test/r/func_regexp.result | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result index ada7ace9696..4980b179c4b 100644 --- a/mysql-test/r/ctype_uca.result +++ b/mysql-test/r/ctype_uca.result @@ -2763,8 +2763,8 @@ select null, null; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `s1` varchar(64) character set ucs2 collate ucs2_unicode_ci default NULL, - `s2` varchar(64) character set ucs2 collate ucs2_unicode_ci default NULL + `s1` varchar(64) CHARACTER SET ucs2 COLLATE ucs2_unicode_ci DEFAULT NULL, + `s2` varchar(64) CHARACTER SET ucs2 COLLATE ucs2_unicode_ci DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 delete from t1; insert into t1 values('aaa','aaa'); diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 709a097d823..dab49cdd8bb 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -931,8 +931,8 @@ select null, null; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `s1` varchar(64) character set ucs2 default NULL, - `s2` varchar(64) character set ucs2 default NULL + `s1` varchar(64) CHARACTER SET ucs2 DEFAULT NULL, + `s2` varchar(64) CHARACTER SET ucs2 DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 delete from t1; insert into t1 values('aaa','aaa'); diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 0981f72b0c1..3575a07d83c 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -276,8 +276,8 @@ select null, null; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `s1` varchar(64) character set utf8 default NULL, - `s2` varchar(64) character set utf8 default NULL + `s1` varchar(64) CHARACTER SET utf8 DEFAULT NULL, + `s2` varchar(64) CHARACTER SET utf8 DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 delete from t1; insert into t1 values('aaa','aaa'); diff --git a/mysql-test/r/func_regexp.result b/mysql-test/r/func_regexp.result index c3851e51207..dca73244780 100644 --- a/mysql-test/r/func_regexp.result +++ b/mysql-test/r/func_regexp.result @@ -8,8 +8,8 @@ select null, null; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `s1` varchar(64) default NULL, - `s2` varchar(64) default NULL + `s1` varchar(64) DEFAULT NULL, + `s2` varchar(64) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 delete from t1; insert into t1 values('aaa','aaa'); From 828801bbaa670ab141ffc4bcb437e17d88097a99 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 16 Oct 2007 23:19:39 +0400 Subject: [PATCH 036/136] Fix for non-deterministic behavior of SELECTs and VIEWs mysql-test/suite/rpl/include/rpl_mixed_check_select.inc: Added ORDER BY for SELECT mysql-test/suite/rpl/include/rpl_mixed_check_view.inc: Added ORDER BY for VIEW mysql-test/suite/rpl/include/rpl_mixed_dml.inc: Added ORDER BY for SELECT mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result: Updated result file --- .../rpl/include/rpl_mixed_check_select.inc | 8 +- .../rpl/include/rpl_mixed_check_view.inc | 4 +- .../suite/rpl/include/rpl_mixed_dml.inc | 8 +- .../suite/rpl/r/rpl_innodb_mixed_dml.result | 152 +++++++++--------- 4 files changed, 86 insertions(+), 86 deletions(-) diff --git a/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc b/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc index 5d3b80e077b..b3e0cefbbd7 100644 --- a/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc +++ b/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc @@ -7,15 +7,15 @@ --echo ==========MASTER========== SELECT COUNT(*) FROM t1; -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; SELECT COUNT(*) FROM t2; -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; sync_slave_with_master; --echo ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; SELECT COUNT(*) FROM t2; -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; connection master; diff --git a/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc b/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc index 43feedfe64a..a9f7ad8cd68 100644 --- a/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc +++ b/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc @@ -7,11 +7,11 @@ --echo ==========MASTER========== SHOW CREATE VIEW v1; -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; sync_slave_with_master; --echo ==========SLAVE=========== USE test_rpl; SHOW CREATE VIEW v1; -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; connection master; diff --git a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc index 96dfdbed541..d596df31b99 100644 --- a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc +++ b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc @@ -54,7 +54,7 @@ DELETE FROM t2 WHERE a = 2; --exec cp ./suite/rpl/data/rpl_mixed.dat $MYSQLTEST_VARDIR/tmp/ LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ; --exec rm $MYSQLTEST_VARDIR/tmp/rpl_mixed.dat -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; --source suite/rpl/include/rpl_mixed_check_select.inc --source suite/rpl/include/rpl_mixed_clear_tables.inc @@ -75,7 +75,7 @@ DELETE FROM t1 WHERE a = 2; --echo --echo ******************** SELECT ******************** INSERT INTO t1 VALUES(1, 't1, text 1'); -SELECT * FROM t1 WHERE b <> UUID(); +SELECT * FROM t1 WHERE b <> UUID() ORDER BY a; --source suite/rpl/include/rpl_mixed_clear_tables.inc # JOIN @@ -85,8 +85,8 @@ INSERT INTO t1 VALUES(1, 'CCC'); INSERT INTO t1 VALUES(2, 'DDD'); INSERT INTO t2 VALUES(1, 'DDD'); INSERT INTO t2 VALUES(2, 'CCC'); -SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a; -SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a ORDER BY t1.a,t2.a; +SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b ORDER BY t1.a,t2.a; --source suite/rpl/include/rpl_mixed_clear_tables.inc # UNION 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 19c5299df25..0e11d132cc4 100644 --- a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result +++ b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result @@ -41,26 +41,26 @@ DELETE FROM t2 WHERE b <> UUID(); SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 2 t1, text 2 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 2 t1, text 2 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DELETE FROM t1; DELETE FROM t2; @@ -76,13 +76,13 @@ DELETE FROM t2 WHERE a = 2; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 t2, text 1 ==========SLAVE=========== @@ -90,13 +90,13 @@ USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 t2, text 1 DELETE FROM t1; @@ -104,7 +104,7 @@ DELETE FROM t2; ******************** LOAD DATA INFILE ******************** LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ; -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 10 line A 20 line B @@ -113,7 +113,7 @@ a b SELECT COUNT(*) FROM t1; COUNT(*) 3 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 10 line A 20 line B @@ -121,14 +121,14 @@ a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 3 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 10 line A 20 line B @@ -136,7 +136,7 @@ a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DELETE FROM t1; DELETE FROM t2; @@ -153,35 +153,35 @@ DELETE FROM t1 WHERE a = 2; SELECT COUNT(*) FROM t1; COUNT(*) 2 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 11 3 t1, text 33 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 2 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 11 3 t1, text 33 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DELETE FROM t1; DELETE FROM t2; ******************** SELECT ******************** INSERT INTO t1 VALUES(1, 't1, text 1'); -SELECT * FROM t1 WHERE b <> UUID(); +SELECT * FROM t1 WHERE b <> UUID() ORDER BY a; a b 1 t1, text 1 DELETE FROM t1; @@ -192,11 +192,11 @@ INSERT INTO t1 VALUES(1, 'CCC'); INSERT INTO t1 VALUES(2, 'DDD'); INSERT INTO t2 VALUES(1, 'DDD'); INSERT INTO t2 VALUES(2, 'CCC'); -SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a ORDER BY t1.a,t2.a; a b a b 1 CCC 1 DDD 2 DDD 2 CCC -SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b; +SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b ORDER BY t1.a,t2.a; a b a b 1 CCC 2 CCC 2 DDD 1 DDD @@ -219,50 +219,50 @@ INSERT INTO t1 VALUES(1, 't1, text 1'); SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b TRUNCATE t1; ==========MASTER========== SELECT COUNT(*) FROM t1; COUNT(*) 0 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 0 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DELETE FROM t1; DELETE FROM t2; @@ -275,13 +275,13 @@ UPDATE t1 SET b = 't1, text 1 updated' WHERE a = 1; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 updated SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 t2, text 1 ==========SLAVE=========== @@ -289,13 +289,13 @@ USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 updated SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 t2, text 1 UPDATE t1, t2 SET t1.b = 'test', t2.b = 'test'; @@ -303,13 +303,13 @@ UPDATE t1, t2 SET t1.b = 'test', t2.b = 'test'; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 test ==========SLAVE=========== @@ -317,13 +317,13 @@ USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 test DELETE FROM t1; @@ -349,26 +349,26 @@ COMMIT; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b START TRANSACTION; INSERT INTO t1 VALUES (2, 'rollback'); @@ -377,26 +377,26 @@ ROLLBACK; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b START TRANSACTION; INSERT INTO t1 VALUES (3, 'before savepoint s1'); @@ -407,27 +407,27 @@ ROLLBACK TO SAVEPOINT s1; SELECT COUNT(*) FROM t1; COUNT(*) 2 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start 3 before savepoint s1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b START TRANSACTION; INSERT INTO t1 VALUES (5, 'before savepoint s2'); @@ -441,7 +441,7 @@ DELETE FROM t1 WHERE a = 7; SELECT COUNT(*) FROM t1; COUNT(*) 4 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start 3 before savepoint s1 @@ -450,14 +450,14 @@ a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 4 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start 3 before savepoint s1 @@ -466,7 +466,7 @@ a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DELETE FROM t1; DELETE FROM t2; @@ -610,28 +610,28 @@ DELETE FROM t1 WHERE a = 202; SELECT COUNT(*) FROM t1; COUNT(*) 2 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 100 test 201 test SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 2 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 100 test 201 test SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ALTER PROCEDURE p1 COMMENT 'p1'; DROP PROCEDURE p1; @@ -649,13 +649,13 @@ INSERT INTO t1 VALUES (1, 'test'); SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 test ==========SLAVE=========== @@ -663,13 +663,13 @@ USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 test DELETE FROM t1; @@ -694,51 +694,51 @@ test_rpl e1 @ SYSTEM RECURRING NULL 1 # # NULL SLAVESIDE_DISABLED 1 latin1 latin SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========MASTER========== SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ALTER EVENT e1 RENAME TO e2; ==========MASTER========== @@ -754,26 +754,26 @@ test_rpl e2 @ SYSTEM RECURRING NULL 1 # # NULL SLAVESIDE_DISABLED 1 latin1 latin SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DROP EVENT e2; ==========MASTER========== @@ -795,7 +795,7 @@ CREATE VIEW v2 AS SELECT * FROM t1 WHERE b <> UUID(); SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 1) latin1 latin1_swedish_ci -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; a b 1 test1 ==========SLAVE=========== @@ -803,7 +803,7 @@ USE test_rpl; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 1) latin1 latin1_swedish_ci -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; a b 1 test1 ALTER VIEW v1 AS SELECT * FROM t1 WHERE a = 2; @@ -811,7 +811,7 @@ ALTER VIEW v1 AS SELECT * FROM t1 WHERE a = 2; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 2) latin1 latin1_swedish_ci -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; a b 2 test2 ==========SLAVE=========== @@ -819,7 +819,7 @@ USE test_rpl; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 2) latin1 latin1_swedish_ci -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; a b 2 test2 DROP VIEW v1; From f3cd8a91b0f5da08e4e68bf819acf604f46d4c93 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 17 Oct 2007 06:50:03 +0200 Subject: [PATCH 037/136] Eliminating some valgrind warnings resulting from that some storage engines do not set the unused null bits (i.e., the filler bits and the X bit) correctly. Also adding some casts to debug printouts to eliminate compiler warnings. sql/ha_ndbcluster.cc: Changing debug enter names to use full names for member functions. sql/records.cc: Emptying records before starting to read records since some engines do not set the unused null bits, leading to valgrind errors. sql/rpl_record.cc: Adding casts to debug printouts to eliminate compiler warnings. --- sql/ha_ndbcluster.cc | 110 +++++++++++++++++++++---------------------- sql/records.cc | 2 + sql/rpl_record.cc | 5 +- 3 files changed, 60 insertions(+), 57 deletions(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index b2152fbb906..21267f4901a 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -411,7 +411,7 @@ Ndb *ha_ndbcluster::get_ndb() void ha_ndbcluster::set_rec_per_key() { - DBUG_ENTER("ha_ndbcluster::get_status_const"); + DBUG_ENTER("ha_ndbcluster::set_rec_per_key"); for (uint i=0 ; i < table_share->keys ; i++) { table->key_info[i].rec_per_key[table->key_info[i].key_parts-1]= 1; @@ -558,7 +558,7 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans) THD *thd= current_thd; int res; NdbError err= trans->getNdbError(); - DBUG_ENTER("ndb_err"); + DBUG_ENTER("ha_ndbcluster::ndb_err"); set_ndb_err(thd, err); @@ -695,7 +695,7 @@ static bool field_type_forces_var_part(enum_field_types type) bool ha_ndbcluster::set_hidden_key(NdbOperation *ndb_op, uint fieldnr, const uchar *field_ptr) { - DBUG_ENTER("set_hidden_key"); + DBUG_ENTER("ha_ndbcluster::set_hidden_key"); DBUG_RETURN(ndb_op->equal(fieldnr, (char*)field_ptr) != 0); } @@ -708,7 +708,7 @@ int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field, uint fieldnr, const uchar *field_ptr) { uint32 pack_len= field->pack_length(); - DBUG_ENTER("set_ndb_key"); + DBUG_ENTER("ha_ndbcluster::set_ndb_key"); DBUG_PRINT("enter", ("%d: %s, ndb_type: %u, len=%d", fieldnr, field->field_name, field->type(), pack_len)); @@ -731,7 +731,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, { const uchar* field_ptr= field->ptr + row_offset; uint32 pack_len= field->pack_length(); - DBUG_ENTER("set_ndb_value"); + DBUG_ENTER("ha_ndbcluster::set_ndb_value"); DBUG_PRINT("enter", ("%d: %s type: %u len=%d is_null=%s", fieldnr, field->field_name, field->type(), pack_len, field->is_null(row_offset) ? "Y" : "N")); @@ -934,7 +934,7 @@ int get_ndb_blobs_value(TABLE* table, NdbValue* value_array, int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field, uint fieldnr, uchar* buf) { - DBUG_ENTER("get_ndb_value"); + DBUG_ENTER("ha_ndbcluster::get_ndb_value"); DBUG_PRINT("enter", ("fieldnr: %d flags: %o", fieldnr, (int)(field != NULL ? field->flags : 0))); @@ -985,7 +985,7 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field, */ int ha_ndbcluster::get_ndb_partition_id(NdbOperation *ndb_op) { - DBUG_ENTER("get_ndb_partition_id"); + DBUG_ENTER("ha_ndbcluster::get_ndb_partition_id"); DBUG_RETURN(ndb_op->getValue(NdbDictionary::Column::FRAGMENT, (char *)&m_part_id) == NULL); } @@ -1044,7 +1044,7 @@ int ha_ndbcluster::get_metadata(const char *path) NDBDICT *dict= ndb->getDictionary(); const NDBTAB *tab; int error; - DBUG_ENTER("get_metadata"); + DBUG_ENTER("ha_ndbcluster::get_metadata"); DBUG_PRINT("enter", ("m_tabname: %s, path: %s", m_tabname, path)); DBUG_ASSERT(m_table == NULL); @@ -1463,7 +1463,7 @@ void ha_ndbcluster::release_metadata(THD *thd, Ndb *ndb) { uint i; - DBUG_ENTER("release_metadata"); + DBUG_ENTER("ha_ndbcluster::release_metadata"); DBUG_PRINT("enter", ("m_tabname: %s", m_tabname)); NDBDICT *dict= ndb->getDictionary(); @@ -1604,7 +1604,7 @@ int ha_ndbcluster::set_primary_key(NdbOperation *op, const uchar *key) KEY* key_info= table->key_info + table_share->primary_key; KEY_PART_INFO* key_part= key_info->key_part; KEY_PART_INFO* end= key_part+key_info->key_parts; - DBUG_ENTER("set_primary_key"); + DBUG_ENTER("ha_ndbcluster::set_primary_key"); for (; key_part != end; key_part++) { @@ -1626,7 +1626,7 @@ int ha_ndbcluster::set_primary_key_from_record(NdbOperation *op, const uchar *re KEY* key_info= table->key_info + table_share->primary_key; KEY_PART_INFO* key_part= key_info->key_part; KEY_PART_INFO* end= key_part+key_info->key_parts; - DBUG_ENTER("set_primary_key_from_record"); + DBUG_ENTER("ha_ndbcluster::set_primary_key_from_record"); for (; key_part != end; key_part++) { @@ -1645,7 +1645,7 @@ int ha_ndbcluster::set_index_key_from_record(NdbOperation *op, KEY_PART_INFO* key_part= key_info->key_part; KEY_PART_INFO* end= key_part+key_info->key_parts; uint i; - DBUG_ENTER("set_index_key_from_record"); + DBUG_ENTER("ha_ndbcluster::set_index_key_from_record"); for (i= 0; key_part != end; key_part++, i++) { @@ -1684,7 +1684,7 @@ inline int ha_ndbcluster::define_read_attrs(uchar* buf, NdbOperation* op) { uint i; - DBUG_ENTER("define_read_attrs"); + DBUG_ENTER("ha_ndbcluster::define_read_attrs"); // Define attributes to read for (i= 0; i < table_share->fields; i++) @@ -1731,7 +1731,7 @@ int ha_ndbcluster::pk_read(const uchar *key, uint key_len, uchar *buf, NdbOperation *op; int res; - DBUG_ENTER("pk_read"); + DBUG_ENTER("ha_ndbcluster::pk_read"); DBUG_PRINT("enter", ("key_len: %u", key_len)); DBUG_DUMP("key", key, key_len); m_write_op= FALSE; @@ -1798,7 +1798,7 @@ int ha_ndbcluster::complemented_read(const uchar *old_data, uchar *new_data, uint no_fields= table_share->fields, i; NdbTransaction *trans= m_active_trans; NdbOperation *op; - DBUG_ENTER("complemented_read"); + DBUG_ENTER("ha_ndbcluster::complemented_read"); m_write_op= FALSE; if (bitmap_is_set_all(table->read_set)) @@ -1964,7 +1964,7 @@ int ha_ndbcluster::peek_indexed_rows(const uchar *record, const NdbOperation *first, *last; uint i; int res; - DBUG_ENTER("peek_indexed_rows"); + DBUG_ENTER("ha_ndbcluster::peek_indexed_rows"); NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); @@ -2104,7 +2104,7 @@ int ha_ndbcluster::unique_index_read(const uchar *key, inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) { - DBUG_ENTER("fetch_next"); + DBUG_ENTER("ha_ndbcluster::fetch_next"); int local_check; NdbTransaction *trans= m_active_trans; @@ -2213,7 +2213,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) inline int ha_ndbcluster::next_result(uchar *buf) { int res; - DBUG_ENTER("next_result"); + DBUG_ENTER("ha_ndbcluster::next_result"); if (!m_active_cursor) DBUG_RETURN(HA_ERR_END_OF_FILE); @@ -2256,7 +2256,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op, uint tot_len; uint i, j; - DBUG_ENTER("set_bounds"); + DBUG_ENTER("ha_ndbcluster::set_bounds"); DBUG_PRINT("info", ("key_parts=%d", key_parts)); for (j= 0; j <= 1; j++) @@ -2543,7 +2543,7 @@ int ha_ndbcluster::unique_index_scan(const KEY* key_info, NdbTransaction *trans= m_active_trans; part_id_range part_spec; - DBUG_ENTER("unique_index_scan"); + DBUG_ENTER("ha_ndbcluster::unique_index_scan"); DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname)); NdbOperation::LockMode lm= @@ -2617,7 +2617,7 @@ int ha_ndbcluster::full_table_scan(uchar *buf) NdbTransaction *trans= m_active_trans; part_id_range part_spec; - DBUG_ENTER("full_table_scan"); + DBUG_ENTER("ha_ndbcluster::full_table_scan"); DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname)); m_write_op= FALSE; @@ -2950,7 +2950,7 @@ int ha_ndbcluster::update_row(const uchar *old_data, uchar *new_data) longlong func_value; bool pk_update= (table_share->primary_key != MAX_KEY && key_cmp(table_share->primary_key, old_data, new_data)); - DBUG_ENTER("update_row"); + DBUG_ENTER("ha_ndbcluster::update_row"); m_write_op= TRUE; /* @@ -3154,7 +3154,7 @@ int ha_ndbcluster::delete_row(const uchar *record) NdbOperation *op; uint32 part_id; int error; - DBUG_ENTER("delete_row"); + DBUG_ENTER("ha_ndbcluster::delete_row"); m_write_op= TRUE; ha_statistic_increment(&SSV::ha_delete_count); @@ -3434,7 +3434,7 @@ void ha_ndbcluster::unpack_record(uchar *buf) void ha_ndbcluster::print_results() { - DBUG_ENTER("print_results"); + DBUG_ENTER("ha_ndbcluster::print_results"); #ifndef DBUG_OFF @@ -3701,7 +3701,7 @@ int ha_ndbcluster::read_range_next() int ha_ndbcluster::rnd_init(bool scan) { NdbScanOperation *cursor= m_active_cursor; - DBUG_ENTER("rnd_init"); + DBUG_ENTER("ha_ndbcluster::rnd_init"); DBUG_PRINT("enter", ("scan: %d", scan)); // Check if scan is to be restarted if (cursor) @@ -3721,7 +3721,7 @@ int ha_ndbcluster::rnd_init(bool scan) int ha_ndbcluster::close_scan() { NdbTransaction *trans= m_active_trans; - DBUG_ENTER("close_scan"); + DBUG_ENTER("ha_ndbcluster::close_scan"); m_multi_cursor= 0; if (!m_active_cursor && !m_multi_cursor) @@ -3770,14 +3770,14 @@ int ha_ndbcluster::close_scan() int ha_ndbcluster::rnd_end() { - DBUG_ENTER("rnd_end"); + DBUG_ENTER("ha_ndbcluster::rnd_end"); DBUG_RETURN(close_scan()); } int ha_ndbcluster::rnd_next(uchar *buf) { - DBUG_ENTER("rnd_next"); + DBUG_ENTER("ha_ndbcluster::rnd_next"); ha_statistic_increment(&SSV::ha_read_rnd_next_count); if (!m_active_cursor) @@ -3795,7 +3795,7 @@ int ha_ndbcluster::rnd_next(uchar *buf) int ha_ndbcluster::rnd_pos(uchar *buf, uchar *pos) { - DBUG_ENTER("rnd_pos"); + DBUG_ENTER("ha_ndbcluster::rnd_pos"); ha_statistic_increment(&SSV::ha_read_rnd_count); // The primary key for the record is stored in pos // Perform a pk_read using primary key "index" @@ -3847,7 +3847,7 @@ void ha_ndbcluster::position(const uchar *record) uchar *buff; uint key_length; - DBUG_ENTER("position"); + DBUG_ENTER("ha_ndbcluster::position"); if (table_share->primary_key != MAX_KEY) { @@ -3931,7 +3931,7 @@ void ha_ndbcluster::position(const uchar *record) int ha_ndbcluster::info(uint flag) { int result= 0; - DBUG_ENTER("info"); + DBUG_ENTER("ha_ndbcluster::info"); DBUG_PRINT("enter", ("flag: %d", flag)); if (flag & HA_STATUS_POS) @@ -4032,7 +4032,7 @@ void ha_ndbcluster::get_dynamic_partition_info(PARTITION_INFO *stat_info, int ha_ndbcluster::extra(enum ha_extra_function operation) { - DBUG_ENTER("extra"); + DBUG_ENTER("ha_ndbcluster::extra"); switch (operation) { case HA_EXTRA_IGNORE_DUP_KEY: /* Dup keys don't rollback everything*/ DBUG_PRINT("info", ("HA_EXTRA_IGNORE_DUP_KEY")); @@ -4125,7 +4125,7 @@ void ha_ndbcluster::start_bulk_insert(ha_rows rows) int bytes, batch; const NDBTAB *tab= m_table; - DBUG_ENTER("start_bulk_insert"); + DBUG_ENTER("ha_ndbcluster::start_bulk_insert"); DBUG_PRINT("enter", ("rows: %d", (int)rows)); m_rows_inserted= (ha_rows) 0; @@ -4174,7 +4174,7 @@ int ha_ndbcluster::end_bulk_insert() { int error= 0; - DBUG_ENTER("end_bulk_insert"); + DBUG_ENTER("ha_ndbcluster::end_bulk_insert"); // Check if last inserts need to be flushed if (m_bulk_insert_not_flushed) { @@ -4215,7 +4215,7 @@ int ha_ndbcluster::end_bulk_insert() int ha_ndbcluster::extra_opt(enum ha_extra_function operation, ulong cache_size) { - DBUG_ENTER("extra_opt"); + DBUG_ENTER("ha_ndbcluster::extra_opt"); DBUG_PRINT("enter", ("cache_size: %lu", cache_size)); DBUG_RETURN(extra(operation)); } @@ -4257,7 +4257,7 @@ THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type) { - DBUG_ENTER("store_lock"); + DBUG_ENTER("ha_ndbcluster::store_lock"); if (lock_type != TL_IGNORE && m_lock.type == TL_UNLOCK) { @@ -4375,7 +4375,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) { int error=0; NdbTransaction* trans= NULL; - DBUG_ENTER("external_lock"); + DBUG_ENTER("ha_ndbcluster::external_lock"); /* Check that this handler instance has a connection @@ -4591,7 +4591,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) void ha_ndbcluster::unlock_row() { - DBUG_ENTER("unlock_row"); + DBUG_ENTER("ha_ndbcluster::unlock_row"); DBUG_PRINT("info", ("Unlocking row")); m_lock_tuple= FALSE; @@ -4609,7 +4609,7 @@ void ha_ndbcluster::unlock_row() int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type) { int error=0; - DBUG_ENTER("start_stmt"); + DBUG_ENTER("ha_ndbcluster::start_stmt"); PRINT_OPTION_FLAGS(thd); Thd_ndb *thd_ndb= get_thd_ndb(thd); @@ -5446,7 +5446,7 @@ int ha_ndbcluster::create_handler_files(const char *file, size_t length, pack_length; int error= 0; - DBUG_ENTER("create_handler_files"); + DBUG_ENTER("ha_ndbcluster::create_handler_files"); if (action_flag != CHF_INDEX_FLAG) { @@ -6131,7 +6131,7 @@ void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment, { int cache_size; Uint64 auto_value; - DBUG_ENTER("get_auto_increment"); + DBUG_ENTER("ha_ndbcluster::get_auto_increment"); DBUG_PRINT("enter", ("m_tabname: %s", m_tabname)); Ndb *ndb= get_ndb(); @@ -6238,7 +6238,7 @@ ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg): { int i; - DBUG_ENTER("ha_ndbcluster"); + DBUG_ENTER("ha_ndbcluster::ha_ndbcluster"); m_tabname[0]= '\0'; m_dbname[0]= '\0'; @@ -6271,7 +6271,7 @@ ha_ndbcluster::~ha_ndbcluster() { THD *thd= current_thd; Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb; - DBUG_ENTER("~ha_ndbcluster"); + DBUG_ENTER("ha_ndbcluster::~ha_ndbcluster"); if (m_share) { @@ -6426,7 +6426,7 @@ void ha_ndbcluster::set_part_info(partition_info *part_info) int ha_ndbcluster::close(void) { - DBUG_ENTER("close"); + DBUG_ENTER("ha_ndbcluster::close"); THD *thd= table->in_use; Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb; /* ndb_share reference handler free */ @@ -6442,7 +6442,7 @@ int ha_ndbcluster::close(void) Thd_ndb* ha_ndbcluster::seize_thd_ndb() { Thd_ndb *thd_ndb; - DBUG_ENTER("seize_thd_ndb"); + DBUG_ENTER("ha_ndbcluster::seize_thd_ndb"); thd_ndb= new Thd_ndb(); if (thd_ndb == NULL) @@ -6468,7 +6468,7 @@ Thd_ndb* ha_ndbcluster::seize_thd_ndb() void ha_ndbcluster::release_thd_ndb(Thd_ndb* thd_ndb) { - DBUG_ENTER("release_thd_ndb"); + DBUG_ENTER("ha_ndbcluster::release_thd_ndb"); delete thd_ndb; DBUG_VOID_RETURN; } @@ -6498,7 +6498,7 @@ Ndb* check_ndb_in_thd(THD* thd) int ha_ndbcluster::check_ndb_connection(THD* thd) { Ndb *ndb; - DBUG_ENTER("check_ndb_connection"); + DBUG_ENTER("ha_ndbcluster::check_ndb_connection"); if (!(ndb= check_ndb_in_thd(thd))) DBUG_RETURN(HA_ERR_NO_CONNECTION); @@ -7549,7 +7549,7 @@ ha_ndbcluster::records_in_range(uint inx, key_range *min_key, uint key_length= key_info->key_length; NDB_INDEX_TYPE idx_type= get_index_type(inx); - DBUG_ENTER("records_in_range"); + DBUG_ENTER("ha_ndbcluster::records_in_range"); // Prevent partial read of hash indexes by returning HA_POS_ERROR if ((idx_type == UNIQUE_INDEX || idx_type == PRIMARY_KEY_INDEX) && ((min_key && min_key->length < key_length) || @@ -8509,7 +8509,7 @@ int ha_ndbcluster::write_ndb_file(const char *name) bool error=1; char path[FN_REFLEN]; - DBUG_ENTER("write_ndb_file"); + DBUG_ENTER("ha_ndbcluster::write_ndb_file"); DBUG_PRINT("enter", ("name: %s", name)); (void)strxnmov(path, FN_REFLEN-1, @@ -8553,7 +8553,7 @@ ha_ndbcluster::null_value_index_search(KEY_MULTI_RANGE *ranges, KEY_MULTI_RANGE *end_range, HANDLER_BUFFER *buffer) { - DBUG_ENTER("null_value_index_search"); + DBUG_ENTER("ha_ndbcluster::null_value_index_search"); KEY* key_info= table->key_info + active_index; KEY_MULTI_RANGE *range= ranges; ulong reclength= table->s->reclength; @@ -8948,7 +8948,7 @@ found_next: int ha_ndbcluster::setup_recattr(const NdbRecAttr* curr) { - DBUG_ENTER("setup_recattr"); + DBUG_ENTER("ha_ndbcluster::setup_recattr"); Field **field, **end; NdbValue *value= m_value; @@ -9319,7 +9319,7 @@ const COND* ha_ndbcluster::cond_push(const COND *cond) { - DBUG_ENTER("cond_push"); + DBUG_ENTER("ha_ndbcluster::cond_push"); if (!m_cond) m_cond= new ha_ndbcluster_cond; if (!m_cond) @@ -9554,7 +9554,7 @@ int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info) uint i; int error= 0; bool unsigned_flag= part_info->part_expr->unsigned_flag; - DBUG_ENTER("set_range_data"); + DBUG_ENTER("ha_ndbcluster::set_range_data"); if (!range_data) { @@ -9593,7 +9593,7 @@ int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info) uint32 *part_id, i; int error= 0; bool unsigned_flag= part_info->part_expr->unsigned_flag; - DBUG_ENTER("set_list_data"); + DBUG_ENTER("ha_ndbcluster::set_list_data"); if (!list_data) { @@ -9924,7 +9924,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, int error; const char *errmsg; Ndb *ndb; - DBUG_ENTER("ha_ndbcluster::alter_tablespace"); + DBUG_ENTER("alter_tablespace"); LINT_INIT(errmsg); ndb= check_ndb_in_thd(thd); diff --git a/sql/records.cc b/sql/records.cc index 81c26da4b4d..0bf815e4073 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -55,6 +55,7 @@ static int rr_index(READ_RECORD *info); void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, bool print_error, uint idx) { + empty_record(table); bzero((char*) info,sizeof(*info)); info->table= table; info->file= table->file; @@ -161,6 +162,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, } else { + empty_record(table); info->record= table->record[0]; info->ref_length= table->file->ref_length; } diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 71cc431890b..061f931436f 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -105,7 +105,8 @@ pack_row(TABLE *table, MY_BITMAP const* cols, DBUG_PRINT("debug", ("field: %s; pack_ptr: 0x%lx;" " pack_ptr':0x%lx; bytes: %d", field->field_name, (ulong) old_pack_ptr, - (ulong) pack_ptr, pack_ptr - old_pack_ptr)); + (ulong) pack_ptr, + (int) (pack_ptr - old_pack_ptr))); } null_mask <<= 1; @@ -239,7 +240,7 @@ unpack_row(Relay_log_info const *rli, " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", f->field_name, metadata, (ulong) old_pack_ptr, (ulong) pack_ptr, - pack_ptr - old_pack_ptr)); + (int) (pack_ptr - old_pack_ptr))); } null_mask <<= 1; From 3f284594be3988a8e24d579444033f3884b8ead5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 17 Oct 2007 09:29:11 +0200 Subject: [PATCH 038/136] Removing debug variables from non-debug builds. sql/rpl_record.cc: Turning of declaration of debug variables in non-debug builds. --- sql/rpl_record.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 061f931436f..ed0dc82cf01 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -99,7 +99,9 @@ pack_row(TABLE *table, MY_BITMAP const* cols, length is stored in little-endian format, since this is the format used for the binlog. */ +#ifndef DBUG_OFF const uchar *old_pack_ptr= pack_ptr; +#endif pack_ptr= field->pack(pack_ptr, field->ptr + offset, field->max_data_length(), TRUE); DBUG_PRINT("debug", ("field: %s; pack_ptr: 0x%lx;" @@ -234,7 +236,9 @@ unpack_row(Relay_log_info const *rli, normal unpack operation. */ uint16 const metadata= tabledef->field_metadata(i); +#ifndef DBUG_OFF uchar const *const old_pack_ptr= pack_ptr; +#endif pack_ptr= f->unpack(f->ptr, pack_ptr, metadata, TRUE); DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;" " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", From 74ef292dc2480e617a6fde4feea7e6595ddbc837 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 19 Oct 2007 14:18:41 +0200 Subject: [PATCH 039/136] BUG#28618 (Skipping into the middle of a group with SQL_SLAVE_SKIP_COUNTER is possible): When skipping the beginning of a transaction starting with BEGIN, the OPTION_BEGIN flag was not set correctly, which caused the slave to not recognize that it was inside a group. This patch sets the OPTION_BEGIN flag for BEGIN, COMMIT, ROLLBACK, and XID events. It also adds checks if inside a group before decreasing the slave skip counter to zero. Begin_query_log_event was not marked that it could not end a group, which is now corrected. mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test: Correcting slave skip counter to get the correct behaviour. mysql-test/suite/rpl/r/rpl_slave_skip.result: Result change. mysql-test/suite/rpl/t/rpl_slave_skip.test: Adding tests to check that skipping works for transactions: - Skipping one group with BEGIN first - Skipping two groups with BEGIN first - Skipping one group without BEGIN first but with AUTOCOMMIT=0 - LOAD DATA INFILE under statement-based replication mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result: Result change. sql/log_event.cc: Adding checks if we're in a group when the slave skip counter is 1. In that case, we should keep going. Adding helping member function Log_event::continue_group() denoting that this event cannot end a group, and if the skip counter indicates that the group ends after this event, it should not decrease the skip counter. Query_log_event will change the OPTION_BEGIN flag for BEGIN, COMMIT, and ROLLBACK, even when skipping because of a positive skip count, and Xid_log_event will also affect the OPTION_BEGIN flag, even when being skipped. Begin_load_query_log_event cannot end a group, so it is marked to continue the group. sql/log_event.h: Adding helper function Log_event::continue_group(). sql/rpl_rli.h: Adding Relay_log_info::get_flag() to get the value of a replication flag. sql/slave.cc: Adding debug output and changing debug message. mysql-test/suite/rpl/data/rpl_bug28618.dat: New BitKeeper file ``mysql-test/suite/rpl/data/rpl_bug28618.dat'' mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt: New BitKeeper file ``mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt'' --- .../extra/rpl_tests/rpl_extraSlave_Col.test | 4 +- mysql-test/suite/rpl/data/rpl_bug28618.dat | 3 + mysql-test/suite/rpl/r/rpl_slave_skip.result | 208 +++++++++++++++ .../suite/rpl/t/rpl_slave_skip-slave.opt | 1 + mysql-test/suite/rpl/t/rpl_slave_skip.test | 239 ++++++++++++++++++ .../suite/rpl_ndb/r/rpl_ndb_extraCol.result | 2 +- sql/log_event.cc | 81 ++++-- sql/log_event.h | 25 ++ sql/rpl_rli.h | 12 + sql/slave.cc | 5 +- 10 files changed, 560 insertions(+), 20 deletions(-) create mode 100644 mysql-test/suite/rpl/data/rpl_bug28618.dat create mode 100644 mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt diff --git a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test index a4ac55cc2e8..72013fe7ce8 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test @@ -736,7 +736,7 @@ connection slave; --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 4 # 7 # 8 # 9 # 16 # 22 # 23 # 33 # 35 # 36 # --query_vertical SHOW SLAVE STATUS -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; --echo *** Try to insert in master **** @@ -744,6 +744,8 @@ connection master; INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2); SELECT * FROM t15 ORDER BY c1; +#SHOW BINLOG EVENTS; + --echo *** Try to select from slave **** sync_slave_with_master; --replace_column 7 CURRENT_TIMESTAMP diff --git a/mysql-test/suite/rpl/data/rpl_bug28618.dat b/mysql-test/suite/rpl/data/rpl_bug28618.dat new file mode 100644 index 00000000000..b800c4dd39d --- /dev/null +++ b/mysql-test/suite/rpl/data/rpl_bug28618.dat @@ -0,0 +1,3 @@ +1|master only +2|master only +3|master only diff --git a/mysql-test/suite/rpl/r/rpl_slave_skip.result b/mysql-test/suite/rpl/r/rpl_slave_skip.result index 8e492fe4732..f89fa34e319 100644 --- a/mysql-test/suite/rpl/r/rpl_slave_skip.result +++ b/mysql-test/suite/rpl/r/rpl_slave_skip.result @@ -142,3 +142,211 @@ Last_SQL_Errno 0 Last_SQL_Error **** On Master **** DROP TABLE t1, t2; +SET SESSION BINLOG_FORMAT=ROW; +SET AUTOCOMMIT=0; +CREATE TABLE t1 (a INT, b VARCHAR(20)) ENGINE=myisam; +CREATE TABLE t2 (a INT, b VARCHAR(20)) ENGINE=myisam; +CREATE TABLE t3 (a INT, b VARCHAR(20)) ENGINE=myisam; +INSERT INTO t1 VALUES (1,'master/slave'); +INSERT INTO t2 VALUES (1,'master/slave'); +INSERT INTO t3 VALUES (1,'master/slave'); +CREATE TRIGGER tr1 AFTER UPDATE on t1 FOR EACH ROW +BEGIN +INSERT INTO t2 VALUES (NEW.a,NEW.b); +DELETE FROM t2 WHERE a < NEW.a; +END| +CREATE TRIGGER tr2 AFTER INSERT on t2 FOR EACH ROW +BEGIN +UPDATE t3 SET a =2, b = 'master only'; +END| +**** On Slave **** +STOP SLAVE; +**** On Master **** +UPDATE t1 SET a = 2, b = 'master only' WHERE a = 1; +DROP TRIGGER tr1; +DROP TRIGGER tr2; +INSERT INTO t1 VALUES (3,'master/slave'); +INSERT INTO t2 VALUES (3,'master/slave'); +INSERT INTO t3 VALUES (3,'master/slave'); +SELECT * FROM t1 ORDER BY a; +a b +2 master only +3 master/slave +SELECT * FROM t2 ORDER BY a; +a b +2 master only +3 master/slave +SELECT * FROM t3 ORDER BY a; +a b +2 master only +3 master/slave +*** On Slave *** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +SELECT * FROM t1 ORDER BY a; +a b +1 master/slave +3 master/slave +SELECT * FROM t2 ORDER BY a; +a b +1 master/slave +3 master/slave +SELECT * FROM t3 ORDER BY a; +a b +1 master/slave +3 master/slave +DROP TABLE t1, t2, t3; +**** Case 2: Row binlog format and transactional tables **** +*** On Master *** +CREATE TABLE t4 (a INT, b VARCHAR(20)) ENGINE=innodb; +CREATE TABLE t5 (a INT, b VARCHAR(20)) ENGINE=innodb; +CREATE TABLE t6 (a INT, b VARCHAR(20)) ENGINE=innodb; +**** On Slave **** +STOP SLAVE; +*** On Master *** +BEGIN; +INSERT INTO t4 VALUES (2, 'master only'); +INSERT INTO t5 VALUES (2, 'master only'); +INSERT INTO t6 VALUES (2, 'master only'); +COMMIT; +BEGIN; +INSERT INTO t4 VALUES (3, 'master/slave'); +INSERT INTO t5 VALUES (3, 'master/slave'); +INSERT INTO t6 VALUES (3, 'master/slave'); +COMMIT; +SELECT * FROM t4 ORDER BY a; +a b +2 master only +3 master/slave +SELECT * FROM t5 ORDER BY a; +a b +2 master only +3 master/slave +SELECT * FROM t6 ORDER BY a; +a b +2 master only +3 master/slave +*** On Slave *** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +SELECT * FROM t4 ORDER BY a; +a b +3 master/slave +SELECT * FROM t5 ORDER BY a; +a b +3 master/slave +SELECT * FROM t6 ORDER BY a; +a b +3 master/slave +**** On Slave **** +STOP SLAVE; +*** On Master *** +BEGIN; +INSERT INTO t4 VALUES (6, 'master only'); +INSERT INTO t5 VALUES (6, 'master only'); +INSERT INTO t6 VALUES (6, 'master only'); +COMMIT; +BEGIN; +INSERT INTO t4 VALUES (7, 'master only'); +INSERT INTO t5 VALUES (7, 'master only'); +INSERT INTO t6 VALUES (7, 'master only'); +COMMIT; +SELECT * FROM t4 ORDER BY a; +a b +2 master only +3 master/slave +6 master only +7 master only +SELECT * FROM t5 ORDER BY a; +a b +2 master only +3 master/slave +6 master only +7 master only +SELECT * FROM t6 ORDER BY a; +a b +2 master only +3 master/slave +6 master only +7 master only +*** On Slave *** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=10; +START SLAVE; +SELECT * FROM t4 ORDER BY a; +a b +3 master/slave +SELECT * FROM t5 ORDER BY a; +a b +3 master/slave +SELECT * FROM t6 ORDER BY a; +a b +3 master/slave +STOP SLAVE; +SET AUTOCOMMIT=0; +INSERT INTO t4 VALUES (4, 'master only'); +INSERT INTO t5 VALUES (4, 'master only'); +INSERT INTO t6 VALUES (4, 'master only'); +COMMIT; +INSERT INTO t4 VALUES (5, 'master/slave'); +INSERT INTO t5 VALUES (5, 'master/slave'); +INSERT INTO t6 VALUES (5, 'master/slave'); +COMMIT; +SELECT * FROM t4 ORDER BY a; +a b +2 master only +3 master/slave +4 master only +5 master/slave +6 master only +7 master only +SELECT * FROM t5 ORDER BY a; +a b +2 master only +3 master/slave +4 master only +5 master/slave +6 master only +7 master only +SELECT * FROM t6 ORDER BY a; +a b +2 master only +3 master/slave +4 master only +5 master/slave +6 master only +7 master only +*** On Slave *** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +SELECT * FROM t4 ORDER BY a; +a b +3 master/slave +5 master/slave +SELECT * FROM t5 ORDER BY a; +a b +3 master/slave +5 master/slave +SELECT * FROM t6 ORDER BY a; +a b +3 master/slave +5 master/slave +DROP TABLE t4, t5, t6; +**** Case 3: Statement logging format and LOAD DATA with non-transactional table **** +*** On Master *** +CREATE TABLE t10 (a INT, b VARCHAR(20)) ENGINE=myisam; +*** On Slave *** +STOP SLAVE; +*** On Master *** +SET SESSION BINLOG_FORMAT=STATEMENT; +LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/rpl_bug28618.dat' INTO TABLE t10 FIELDS TERMINATED BY '|'; +SELECT * FROM t10 ORDER BY a; +a b +1 master only +2 master only +3 master only +*** On Slave *** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +SELECT * FROM t10 ORDER BY a; +a b +DROP TABLE t10; diff --git a/mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt b/mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt new file mode 100644 index 00000000000..627becdbfb5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt @@ -0,0 +1 @@ +--innodb diff --git a/mysql-test/suite/rpl/t/rpl_slave_skip.test b/mysql-test/suite/rpl/t/rpl_slave_skip.test index b19d6a2730b..6783098fd7c 100644 --- a/mysql-test/suite/rpl/t/rpl_slave_skip.test +++ b/mysql-test/suite/rpl/t/rpl_slave_skip.test @@ -1,7 +1,9 @@ source include/master-slave.inc; +source include/have_innodb.inc; --echo **** On Slave **** connection slave; +source include/have_innodb.inc; STOP SLAVE; --echo **** On Master **** @@ -69,3 +71,240 @@ query_vertical SHOW SLAVE STATUS; connection master; DROP TABLE t1, t2; sync_slave_with_master; + +# +# More tests for BUG#28618 +# +# Case 1. +# ROW binlog format and non-transactional tables. +# Create the group of events via triggers and try to skip +# some items of that group. +# + +connection master; +SET SESSION BINLOG_FORMAT=ROW; +SET AUTOCOMMIT=0; + +CREATE TABLE t1 (a INT, b VARCHAR(20)) ENGINE=myisam; +CREATE TABLE t2 (a INT, b VARCHAR(20)) ENGINE=myisam; +CREATE TABLE t3 (a INT, b VARCHAR(20)) ENGINE=myisam; + +INSERT INTO t1 VALUES (1,'master/slave'); +INSERT INTO t2 VALUES (1,'master/slave'); +INSERT INTO t3 VALUES (1,'master/slave'); + +DELIMITER |; + +CREATE TRIGGER tr1 AFTER UPDATE on t1 FOR EACH ROW +BEGIN + INSERT INTO t2 VALUES (NEW.a,NEW.b); + DELETE FROM t2 WHERE a < NEW.a; +END| + +CREATE TRIGGER tr2 AFTER INSERT on t2 FOR EACH ROW +BEGIN + UPDATE t3 SET a =2, b = 'master only'; +END| + +DELIMITER ;| + +--echo **** On Slave **** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; +UPDATE t1 SET a = 2, b = 'master only' WHERE a = 1; +DROP TRIGGER tr1; +DROP TRIGGER tr2; +INSERT INTO t1 VALUES (3,'master/slave'); +INSERT INTO t2 VALUES (3,'master/slave'); +INSERT INTO t3 VALUES (3,'master/slave'); + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; + +save_master_pos; + +--echo *** On Slave *** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; + +connection master; +DROP TABLE t1, t2, t3; +sync_slave_with_master; + +--echo **** Case 2: Row binlog format and transactional tables **** + +# Create the transaction and try to skip some +# queries from one. + +--echo *** On Master *** +connection master; +CREATE TABLE t4 (a INT, b VARCHAR(20)) ENGINE=innodb; +CREATE TABLE t5 (a INT, b VARCHAR(20)) ENGINE=innodb; +CREATE TABLE t6 (a INT, b VARCHAR(20)) ENGINE=innodb; + +--echo **** On Slave **** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo *** On Master *** +connection master; +BEGIN; +INSERT INTO t4 VALUES (2, 'master only'); +INSERT INTO t5 VALUES (2, 'master only'); +INSERT INTO t6 VALUES (2, 'master only'); +COMMIT; + +BEGIN; +INSERT INTO t4 VALUES (3, 'master/slave'); +INSERT INTO t5 VALUES (3, 'master/slave'); +INSERT INTO t6 VALUES (3, 'master/slave'); +COMMIT; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +save_master_pos; + +--echo *** On Slave *** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +# Test skipping two groups + +--echo **** On Slave **** +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo *** On Master *** +connection master; +BEGIN; +INSERT INTO t4 VALUES (6, 'master only'); +INSERT INTO t5 VALUES (6, 'master only'); +INSERT INTO t6 VALUES (6, 'master only'); +COMMIT; + +BEGIN; +INSERT INTO t4 VALUES (7, 'master only'); +INSERT INTO t5 VALUES (7, 'master only'); +INSERT INTO t6 VALUES (7, 'master only'); +COMMIT; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +save_master_pos; + +--echo *** On Slave *** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=10; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +# +# And the same, but with autocommit = 0 +# +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +connection master; +SET AUTOCOMMIT=0; + +INSERT INTO t4 VALUES (4, 'master only'); +INSERT INTO t5 VALUES (4, 'master only'); +INSERT INTO t6 VALUES (4, 'master only'); +COMMIT; + +INSERT INTO t4 VALUES (5, 'master/slave'); +INSERT INTO t5 VALUES (5, 'master/slave'); +INSERT INTO t6 VALUES (5, 'master/slave'); +COMMIT; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +save_master_pos; + +--echo *** On Slave *** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +connection master; +DROP TABLE t4, t5, t6; +sync_slave_with_master; + +--echo **** Case 3: Statement logging format and LOAD DATA with non-transactional table **** + +# LOAD DATA creates two events in binary log for statement binlog format. +# Try to skip the first. + +--echo *** On Master *** +connection master; +CREATE TABLE t10 (a INT, b VARCHAR(20)) ENGINE=myisam; + +--echo *** On Slave *** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo *** On Master *** +connection master; +SET SESSION BINLOG_FORMAT=STATEMENT; +exec cp ./suite/rpl/data/rpl_bug28618.dat $MYSQLTEST_VARDIR/tmp/; +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/rpl_bug28618.dat' INTO TABLE t10 FIELDS TERMINATED BY '|'; +remove_file $MYSQLTEST_VARDIR/tmp/rpl_bug28618.dat; + +SELECT * FROM t10 ORDER BY a; + +save_master_pos; + +--echo *** On Slave *** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t10 ORDER BY a; + +connection master; +DROP TABLE t10; +sync_slave_with_master; + diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result index 2327dc7ee81..6f040d2e6ad 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result @@ -707,7 +707,7 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1060 Last_SQL_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5' -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; *** Try to insert in master **** INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2); diff --git a/sql/log_event.cc b/sql/log_event.cc index 7e5cfd6a7a4..0e877252ce8 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -570,7 +570,8 @@ Log_event::do_shall_skip(Relay_log_info *rli) (ulong) server_id, (ulong) ::server_id, rli->replicate_same_server_id, rli->slave_skip_counter)); - if (server_id == ::server_id && !rli->replicate_same_server_id) + if (server_id == ::server_id && !rli->replicate_same_server_id || + rli->slave_skip_counter == 1 && rli->is_in_group()) return EVENT_SKIP_IGNORE; else if (rli->slave_skip_counter > 0) return EVENT_SKIP_COUNT; @@ -1227,6 +1228,16 @@ void Log_event::print_timestamp(IO_CACHE* file, time_t* ts) #endif /* MYSQL_CLIENT */ +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) +inline Log_event::enum_skip_reason +Log_event::continue_group(Relay_log_info *rli) +{ + if (rli->slave_skip_counter == 1) + return Log_event::EVENT_SKIP_IGNORE; + return Log_event::do_shall_skip(rli); +} +#endif + /************************************************************************** Query_log_event methods **************************************************************************/ @@ -2235,6 +2246,30 @@ int Query_log_event::do_update_pos(Relay_log_info *rli) } +Log_event::enum_skip_reason +Query_log_event::do_shall_skip(Relay_log_info *rli) +{ + DBUG_ENTER("Query_log_event::do_shall_skip"); + DBUG_PRINT("debug", ("query: %s; q_len: %d", query, q_len)); + DBUG_ASSERT(query && q_len > 0); + + if (rli->slave_skip_counter > 0) + { + if (strcmp("BEGIN", query) == 0) + { + thd->options|= OPTION_BEGIN; + DBUG_RETURN(Log_event::continue_group(rli)); + } + + if (strcmp("COMMIT", query) == 0 || strcmp("ROLLBACK", query) == 0) + { + thd->options&= ~OPTION_BEGIN; + DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); + } + } + DBUG_RETURN(Log_event::do_shall_skip(rli)); +} + #endif @@ -3871,10 +3906,7 @@ Intvar_log_event::do_shall_skip(Relay_log_info *rli) that we do not change the value of the slave skip counter since it will be decreased by the following insert event. */ - if (rli->slave_skip_counter == 1) - return Log_event::EVENT_SKIP_IGNORE; - else - return Log_event::do_shall_skip(rli); + return continue_group(rli); } #endif @@ -3970,10 +4002,7 @@ Rand_log_event::do_shall_skip(Relay_log_info *rli) that we do not change the value of the slave skip counter since it will be decreased by the following insert event. */ - if (rli->slave_skip_counter == 1) - return Log_event::EVENT_SKIP_IGNORE; - else - return Log_event::do_shall_skip(rli); + return continue_group(rli); } #endif /* !MYSQL_CLIENT */ @@ -4049,6 +4078,17 @@ int Xid_log_event::do_apply_event(Relay_log_info const *rli) "COMMIT /* implicit, from Xid_log_event */"); return end_trans(thd, COMMIT); } + +Log_event::enum_skip_reason +Xid_log_event::do_shall_skip(Relay_log_info *rli) +{ + DBUG_ENTER("Xid_log_event::do_shall_skip"); + if (rli->slave_skip_counter > 0) { + thd->options&= ~OPTION_BEGIN; + DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); + } + DBUG_RETURN(Log_event::do_shall_skip(rli)); +} #endif /* !MYSQL_CLIENT */ @@ -4427,10 +4467,7 @@ User_var_log_event::do_shall_skip(Relay_log_info *rli) that we do not change the value of the slave skip counter since it will be decreased by the following insert event. */ - if (rli->slave_skip_counter == 1) - return Log_event::EVENT_SKIP_IGNORE; - else - return Log_event::do_shall_skip(rli); + return continue_group(rli); } #endif /* !MYSQL_CLIENT */ @@ -5366,6 +5403,19 @@ int Begin_load_query_log_event::get_create_or_append() const #endif /* defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) +Log_event::enum_skip_reason +Begin_load_query_log_event::do_shall_skip(Relay_log_info *rli) +{ + /* + If the slave skip counter is 1, then we should not start executing + on the next event. + */ + return continue_group(rli); +} +#endif + + /************************************************************************** Execute_load_query_log_event methods **************************************************************************/ @@ -6870,10 +6920,7 @@ Table_map_log_event::do_shall_skip(Relay_log_info *rli) If the slave skip counter is 1, then we should not start executing on the next event. */ - if (rli->slave_skip_counter == 1) - return Log_event::EVENT_SKIP_IGNORE; - else - return Log_event::do_shall_skip(rli); + return continue_group(rli); } int Table_map_log_event::do_update_pos(Relay_log_info *rli) diff --git a/sql/log_event.h b/sql/log_event.h index 05d4c70042f..9321860a062 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -870,6 +870,25 @@ public: protected: + /** + Helper function to ignore an event w.r.t. the slave skip counter. + + This function can be used inside do_shall_skip() for functions + that cannot end a group. If the slave skip counter is 1 when + seeing such an event, the event shall be ignored, the counter + left intact, and processing continue with the next event. + + A typical usage is: + @code + enum_skip_reason do_shall_skip(Relay_log_info *rli) { + return continue_group(rli); + } + @endcode + + @return Skip reason + */ + enum_skip_reason continue_group(Relay_log_info *rli); + /** Primitive to apply an event to the database. @@ -1086,6 +1105,7 @@ public: public: /* !!! Public in this patch to allow old usage */ #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) + virtual enum_skip_reason do_shall_skip(Relay_log_info *rli); virtual int do_apply_event(Relay_log_info const *rli); virtual int do_update_pos(Relay_log_info *rli); @@ -1559,6 +1579,7 @@ class Xid_log_event: public Log_event private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) virtual int do_apply_event(Relay_log_info const *rli); + enum_skip_reason do_shall_skip(Relay_log_info *rli); #endif }; @@ -1937,6 +1958,10 @@ public: *description_event); ~Begin_load_query_log_event() {} Log_event_type get_type_code() { return BEGIN_LOAD_QUERY_EVENT; } +private: +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) + virtual enum_skip_reason do_shall_skip(Relay_log_info *rli); +#endif }; diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 10ecf1a43d4..a3a57ad4ce9 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -365,6 +365,18 @@ public: m_flags |= (1UL << flag); } + /** + Get the value of a replication state flag. + + @param flag Flag to get value of + + @return @c true if the flag was set, @c false otherwise. + */ + bool get_flag(enum_state_flag flag) + { + return m_flags & (1UL << flag); + } + /** Clear the value of a replication state flag. diff --git a/sql/slave.cc b/sql/slave.cc index fcbd4eb841b..570bf57d212 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1853,10 +1853,13 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) // EVENT_SKIP_NOT, "not skipped", // EVENT_SKIP_IGNORE, - "skipped because event originated from this server", + "skipped because event should be ignored", // EVENT_SKIP_COUNT "skipped because event skip counter was non-zero" }; + DBUG_PRINT("info", ("OPTION_BEGIN: %d; IN_STMT: %d", + thd->options & OPTION_BEGIN ? 1 : 0, + rli->get_flag(Relay_log_info::IN_STMT))); DBUG_PRINT("skip_event", ("%s event was %s", ev->get_type_str(), explain[reason])); #endif From 0b1c0f3173cd14181ece774cdbbf68dddedf35a7 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 20 Oct 2007 18:19:55 +0200 Subject: [PATCH 040/136] Bug#31702 (Missing row on slave causes assertion failure under row-based replication): When replicating an update pair (before image, after image) under row-based replication, and the before image is not found on the slave, the after image was not discared, and was hence read as a before image for the next row. Eventually, this lead to an after image being read outside the block of rows in the event, causing an assertion to fire. This patch fixes this by reading the after image in the event that the row was not found on the slave, adds some extra debug assertion to catch future errors earlier, and also adds a few non-debug checks to prevent reading outside the block of the event. include/my_base.h: Adding error code HA_ERR_CORRUPT_EVENT. mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result: Result change. mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test: Adding test to try to use row-based replication to replicate an update of a row that doesn't exist on the slave. We should get an apropriate error and the slave should stop. sql/log_event.cc: Adding debug printouts. Adding code to Update_rows_log_event::do_exec_row() so that the after image is read (and ignored) in the event of an error in finding the row. This is necessary so that the second pair of images is read correctly for the next update pair. Changing logic for ignoring errors to not include update events, since a "key not found" error or a "record changed" error is not idempotent for updates, just for deletes and inserts. sql/log_event.h: Adding debug assertions to check that row reading is within the events block of rows. --- include/my_base.h | 8 ++-- .../suite/rpl/r/rpl_row_basic_11bugs.result | 31 ++++++++++++++++ .../suite/rpl/t/rpl_row_basic_11bugs.test | 37 +++++++++++++++++++ sql/log_event.cc | 27 +++++++++++--- sql/log_event.h | 24 +++++++++++- 5 files changed, 117 insertions(+), 10 deletions(-) diff --git a/include/my_base.h b/include/my_base.h index 339554979a8..e65a04bb16d 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -407,9 +407,11 @@ enum ha_base_keytype { #define HA_ERR_RECORD_IS_THE_SAME 169 /* row not actually updated : new values same as the old values */ -#define HA_ERR_LOGGING_IMPOSSIBLE 170 /* It is not possible to log this - statement */ -#define HA_ERR_LAST 170 /*Copy last error nr.*/ +#define HA_ERR_LOGGING_IMPOSSIBLE 170 /* It is not possible to log this + statement */ +#define HA_ERR_CORRUPT_EVENT 171 /* The event was corrupt, leading to + illegal data being read */ +#define HA_ERR_LAST 171 /*Copy last error nr.*/ /* Add error numbers before HA_ERR_LAST and change it accordingly. */ #define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1) diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result index 7dc9926522b..5ad9ba7ced0 100644 --- a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result +++ b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result @@ -242,3 +242,34 @@ a b 3 1 4 4 drop table t1,t2; +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; +**** On Master **** +SET SESSION BINLOG_FORMAT=ROW; +CREATE TABLE t1 (a INT PRIMARY KEY, b SET('master','slave')); +INSERT INTO t1 VALUES (1,'master,slave'), (2,'master,slave'); +**** On Slave **** +UPDATE t1 SET a = 5, b = 'slave' WHERE a = 1; +SELECT * FROM t1 ORDER BY a; +a b +2 master,slave +5 slave +**** On Master **** +UPDATE t1 SET a = 5, b = 'master' WHERE a = 1; +SELECT * FROM t1 ORDER BY a; +a b +2 master,slave +5 master +**** On Slave **** +Last_SQL_Error +Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' +SELECT * FROM t1 ORDER BY a; +a b +2 master,slave +5 slave +DROP TABLE t1; +**** On Master **** +DROP TABLE t1; diff --git a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test index fb43664f121..f6180de52a4 100644 --- a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test +++ b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test @@ -223,3 +223,40 @@ connection master; drop table t1,t2; sync_slave_with_master; + +# +# BUG#31702: Missing row on slave causes assertion failure under +# row-based replication +# + +disable_query_log; +source include/master-slave-reset.inc; +enable_query_log; + +--echo **** On Master **** +connection master; +SET SESSION BINLOG_FORMAT=ROW; +CREATE TABLE t1 (a INT PRIMARY KEY, b SET('master','slave')); +INSERT INTO t1 VALUES (1,'master,slave'), (2,'master,slave'); +--echo **** On Slave **** +sync_slave_with_master; +UPDATE t1 SET a = 5, b = 'slave' WHERE a = 1; +SELECT * FROM t1 ORDER BY a; +--echo **** On Master **** +connection master; +UPDATE t1 SET a = 5, b = 'master' WHERE a = 1; +save_master_pos; +SELECT * FROM t1 ORDER BY a; +--echo **** On Slave **** +connection slave; +source include/wait_for_slave_sql_error.inc; +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; +SELECT * FROM t1 ORDER BY a; +DROP TABLE t1; + +--echo **** On Master **** +connection master; +DROP TABLE t1; diff --git a/sql/log_event.cc b/sql/log_event.cc index ec4d6820cca..fd7e3e5db6b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6173,14 +6173,19 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) table->in_use = old_thd; switch (error) { - /* Some recoverable errors */ - case HA_ERR_RECORD_CHANGED: - case HA_ERR_KEY_NOT_FOUND: /* Idempotency support: OK if - tuple does not exist */ - error= 0; case 0: break; + /* Some recoverable errors */ + case HA_ERR_RECORD_CHANGED: + case HA_ERR_KEY_NOT_FOUND: /* Idempotency support: OK if + tuple does not exist */ + if (get_type_code() != UPDATE_ROWS_EVENT) + { + error= 0; + break; + } + /* Fall through in the event that we have an update event */ default: rli->report(ERROR_LEVEL, thd->net.last_errno, "Error in %s event: row application failed. %s", @@ -6197,6 +6202,10 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) m_curr_row_end. */ + DBUG_PRINT("info", ("error: %d", error)); + DBUG_PRINT("info", ("curr_row: 0x%lu; curr_row_end: 0x%lu; rows_end: 0x%lu", + (ulong) m_curr_row, (ulong) m_curr_row_end, (ulong) m_rows_end)); + if (!m_curr_row_end && !error) unpack_current_row(rli); @@ -7931,7 +7940,15 @@ Update_rows_log_event::do_exec_row(const Relay_log_info *const rli) int error= find_row(rli); if (error) + { + /* + We need to read the second image in the event of error to be + able to skip to the next pair of updates + */ + m_curr_row= m_curr_row_end; + unpack_current_row(rli); return error; + } /* This is the situation after locating BI: diff --git a/sql/log_event.h b/sql/log_event.h index 05d4c70042f..226ebc02712 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -37,6 +37,23 @@ #include "rpl_reporting.h" #endif +/** + Either assert or return an error. + + In debug build, the condition will be checked, but in non-debug + builds, the error code given will be returned instead. + + @param COND Condition to check + @param ERRNO Error number to return in non-debug builds +*/ +#ifdef DBUG_OFF +#define ASSERT_OR_RETURN_ERROR(COND, ERRNO) \ + do { if (!(COND)) return ERRNO; } while (0) +#else +#define ASSERT_OR_RETURN_ERROR(COND, ERRNO) \ + DBUG_ASSERT(COND) +#endif + #define LOG_READ_EOF -1 #define LOG_READ_BOGUS -2 #define LOG_READ_IO -3 @@ -2316,8 +2333,11 @@ protected: int unpack_current_row(const Relay_log_info *const rli) { DBUG_ASSERT(m_table); - return ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, - &m_curr_row_end, &m_master_reclength); + ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT); + int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, + &m_curr_row_end, &m_master_reclength); + ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT); + return result; } #endif From 219e6a6438a531802b331c69e697eec83ba8648c Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 20 Oct 2007 20:16:12 +0200 Subject: [PATCH 041/136] BUG#24860 (Incorrect SLAVE_TRANSACTION_RETRIES code can result in slave stuck): If a temporary error occured inside a group on an event that was not the first event of the group, the slave could get stuck because the retry counter is reset whenever an event was executed successfully. This patch only reset the retry counter when an entire group has been successfully executed, or failed with a non-transient error. sql/slave.cc: Adding debug printouts to every place where Relay_log_info::trans_retries is changed and to has_temporary_error() to print the error when returning. Adding debug variable all_errors_are_temporary_errors to make all errors for slave thread temporary errors. Adding code so that the Relay_log_info::trans_retries is only reset when an entire group was sucessfully executed, or a non-temporary error occured. mysql-test/suite/rpl/r/rpl_temporary_errors.result: New BitKeeper file ``mysql-test/suite/rpl/r/rpl_temporary_errors.result'' mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt: New BitKeeper file ``mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt'' mysql-test/suite/rpl/t/rpl_temporary_errors.test: New BitKeeper file ``mysql-test/suite/rpl/t/rpl_temporary_errors.test'' --- .../suite/rpl/r/rpl_temporary_errors.result | 81 +++++++++++++++++++ .../rpl/t/rpl_temporary_errors-slave.opt | 3 + .../suite/rpl/t/rpl_temporary_errors.test | 29 +++++++ sql/slave.cc | 26 ++++-- 4 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_temporary_errors.result create mode 100644 mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt create mode 100644 mysql-test/suite/rpl/t/rpl_temporary_errors.test diff --git a/mysql-test/suite/rpl/r/rpl_temporary_errors.result b/mysql-test/suite/rpl/r/rpl_temporary_errors.result new file mode 100644 index 00000000000..31c8930ec4f --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_temporary_errors.result @@ -0,0 +1,81 @@ +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; +**** On Master **** +SET SESSION BINLOG_FORMAT=ROW; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4); +**** On Slave **** +SHOW STATUS LIKE 'Slave_retried_transactions'; +Variable_name Value +Slave_retried_transactions 0 +UPDATE t1 SET a = 5, b = 47 WHERE a = 1; +SELECT * FROM t1; +a b +5 47 +2 2 +3 3 +4 4 +**** On Master **** +UPDATE t1 SET a = 5, b = 5 WHERE a = 1; +SELECT * FROM t1; +a b +5 5 +2 2 +3 3 +4 4 +**** On Slave **** +SHOW STATUS LIKE 'Slave_retried_transactions'; +Variable_name Value +Slave_retried_transactions 2 +SELECT * FROM t1; +a b +5 47 +2 2 +3 3 +4 4 +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_PORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 408 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table # +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 1032 +Last_Error Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' +Skip_Counter 0 +Exec_Master_Log_Pos 318 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +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 No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 1032 +Last_SQL_Error Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' +DROP TABLE t1; +**** On Master **** +DROP TABLE t1; diff --git a/mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt b/mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt new file mode 100644 index 00000000000..80c171170f6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt @@ -0,0 +1,3 @@ +--loose-debug="+d,all_errors_are_temporary_errors" --slave-transaction-retries=2 + + diff --git a/mysql-test/suite/rpl/t/rpl_temporary_errors.test b/mysql-test/suite/rpl/t/rpl_temporary_errors.test new file mode 100644 index 00000000000..0ca515fff40 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporary_errors.test @@ -0,0 +1,29 @@ +source include/master-slave.inc; + +--echo **** On Master **** +connection master; +SET SESSION BINLOG_FORMAT=ROW; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4); +--echo **** On Slave **** +sync_slave_with_master; +SHOW STATUS LIKE 'Slave_retried_transactions'; +UPDATE t1 SET a = 5, b = 47 WHERE a = 1; +SELECT * FROM t1; +--echo **** On Master **** +connection master; +UPDATE t1 SET a = 5, b = 5 WHERE a = 1; +save_master_pos; +SELECT * FROM t1; +#SHOW BINLOG EVENTS; +--echo **** On Slave **** +connection slave; +source include/wait_for_slave_sql_to_stop.inc; +SHOW STATUS LIKE 'Slave_retried_transactions'; +SELECT * FROM t1; +source include/show_slave_status.inc; +DROP TABLE t1; + +--echo **** On Master **** +connection master; +DROP TABLE t1; diff --git a/sql/slave.cc b/sql/slave.cc index 9780ae70c5b..169cf897e6a 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1714,7 +1714,14 @@ static int has_temporary_error(THD *thd) DBUG_ENTER("has_temporary_error"); if (thd->is_fatal_error) + { + DBUG_PRINT("info", ("thd->net.last_errno: %s", ER(thd->net.last_errno))); DBUG_RETURN(0); + } + + DBUG_EXECUTE_IF("all_errors_are_temporary_errors", + if (thd->net.last_errno) + thd->net.last_errno= ER_LOCK_DEADLOCK;); /* Temporary error codes: @@ -1723,7 +1730,10 @@ static int has_temporary_error(THD *thd) */ if (thd->net.last_errno == ER_LOCK_DEADLOCK || thd->net.last_errno == ER_LOCK_WAIT_TIMEOUT) + { + DBUG_PRINT("info", ("thd->net.last_errno: %s", ER(thd->net.last_errno))); DBUG_RETURN(1); + } #ifdef HAVE_NDB_BINLOG /* @@ -1905,7 +1915,8 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) } if (slave_trans_retries) { - if (exec_res && has_temporary_error(thd)) + int temp_err; + if (exec_res && (temp_err= has_temporary_error(thd))) { const char *errmsg; /* @@ -1953,15 +1964,19 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) "the slave_transaction_retries variable.", slave_trans_retries); } - else if (!((thd->options & OPTION_BEGIN) && opt_using_transactions)) + else if (exec_res && !temp_err || + (opt_using_transactions && + rli->group_relay_log_pos == rli->event_relay_log_pos)) { /* - Only reset the retry counter if the event succeeded or - failed with a non-transient error. On a successful event, - the execution will proceed as usual; in the case of a + Only reset the retry counter if the entire group succeeded + or failed with a non-transient error. On a successful + event, the execution will proceed as usual; in the case of a non-transient error, the slave will stop with an error. */ rli->trans_retries= 0; // restart from fresh + DBUG_PRINT("info", ("Resetting retry counter, rli->trans_retries: %d", + rli->trans_retries)); } } DBUG_RETURN(exec_res); @@ -2450,6 +2465,7 @@ pthread_handler_t handle_slave_sql(void *arg) rli->ignore_log_space_limit= 0; pthread_mutex_unlock(&rli->log_space_lock); rli->trans_retries= 0; // start from "no error" + DBUG_PRINT("info", ("rli->trans_retries: %d", rli->trans_retries)); if (init_relay_log_pos(rli, rli->group_relay_log_name, From 6cfd9a4fc3d7b629d848f9be083b1bdbd2c5e45f Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 21 Oct 2007 18:37:37 +0300 Subject: [PATCH 042/136] Bug #26199 Replication Failure on Slave when using stored procs with bit-type parameters. The value of the actual argument of BIT-type-arg stored procedure was binlogged as non-escaped sequence of bytes corresponding to internal representation of the bit value. The patch enforces binlogging of the bit-argument as a valid literal: prefixing the quoted bytes sequence with _binary. Note, that behaviour of Item_field::var_str for field_type() of MYSQL_TYPE_BIT is exceptional in that the returned string contains the binary representation even though result_type() of the item is INT_RESULT. mysql-test/r/rpl_sp_effects.result: testing stored function and procedure called with BIT-arg. mysql-test/t/rpl_sp_effects.test: results changed sql/sp_head.cc: Treating BIT field type specially to for its value to be prefixed and quoted. --- mysql-test/r/rpl_sp_effects.result | 41 ++++++++++++++++++++++++ mysql-test/t/rpl_sp_effects.test | 51 ++++++++++++++++++++++++++++++ sql/sp_head.cc | 5 +-- 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/rpl_sp_effects.result b/mysql-test/r/rpl_sp_effects.result index bf8128d9385..70b2338d187 100644 --- a/mysql-test/r/rpl_sp_effects.result +++ b/mysql-test/r/rpl_sp_effects.result @@ -213,3 +213,44 @@ drop table t1; drop function f1; drop function f2; drop procedure p1; +create table t2 (b BIT(7)); +create procedure sp_bug26199(bitvalue BIT(7)) +begin +insert into t2 set b = bitvalue; +end // +create function sf_bug26199(b BIT(7)) returns int +begin +insert into t2 values(b); +return 0; +end// +call sp_bug26199(b'1110'); +call sp_bug26199('\0'); +select sf_bug26199(b'1111111'); +sf_bug26199(b'1111111') +0 +select sf_bug26199(b'101111111'); +sf_bug26199(b'101111111') +0 +Warnings: +Warning 1264 Out of range value adjusted for column 'b' at row 1 +select sf_bug26199('\''); +sf_bug26199('\'') +0 +select hex(b) from t2; +hex(b) +E +0 +7F +7F +27 +select hex(b) from t2; +hex(b) +E +0 +7F +7F +27 +drop table t2; +drop procedure sp_bug26199; +drop function sf_bug26199; +end of the tests diff --git a/mysql-test/t/rpl_sp_effects.test b/mysql-test/t/rpl_sp_effects.test index 9da5723b993..f18710efa37 100644 --- a/mysql-test/t/rpl_sp_effects.test +++ b/mysql-test/t/rpl_sp_effects.test @@ -195,9 +195,60 @@ sync_slave_with_master; connection slave; select 'slave', a from t1; +# +# cleanup +# + connection master; drop table t1; drop function f1; drop function f2; drop procedure p1; sync_slave_with_master; + +# +# bug#26199 Replication Failure on Slave when using stored procs +# with bit-type parameters + +connection master; + +create table t2 (b BIT(7)); +delimiter //; +create procedure sp_bug26199(bitvalue BIT(7)) +begin + insert into t2 set b = bitvalue; +end // + +create function sf_bug26199(b BIT(7)) returns int +begin + insert into t2 values(b); + return 0; +end// + +DELIMITER ;// + + + +call sp_bug26199(b'1110'); +call sp_bug26199('\0'); +select sf_bug26199(b'1111111'); +select sf_bug26199(b'101111111'); +select sf_bug26199('\''); +select hex(b) from t2; + +sync_slave_with_master; +#connection slave; +select hex(b) from t2; + +# +# cleanup bug#26199 +# +connection master; +drop table t2; +drop procedure sp_bug26199; +drop function sf_bug26199; + +sync_slave_with_master; + + +--echo end of the tests diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 5ad6625efb8..1843406b862 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -100,8 +100,9 @@ sp_get_item_value(THD *thd, Item *item, String *str) case REAL_RESULT: case INT_RESULT: case DECIMAL_RESULT: - return item->val_str(str); - + if (item->field_type() != MYSQL_TYPE_BIT) + return item->val_str(str); + else {/* Bit type is handled as binary string */} case STRING_RESULT: { String *result= item->val_str(str); From dcd1d492ba4b5c2e543bc1a4b3c2c10281cc7f99 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 22 Oct 2007 10:32:35 +0200 Subject: [PATCH 043/136] Post-merge fixes. mysql-test/suite/rpl/r/rpl_extraCol_innodb.result: Result change mysql-test/suite/rpl/r/rpl_extraCol_myisam.result: Result change --- mysql-test/suite/rpl/r/rpl_extraCol_innodb.result | 3 ++- mysql-test/suite/rpl/r/rpl_extraCol_myisam.result | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result index fe5a5b28682..38e76a3c877 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result @@ -707,7 +707,7 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1060 Last_SQL_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5' -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; *** Try to insert in master **** INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2); @@ -723,6 +723,7 @@ c1 c2 c3 c4 c5 c6 c7 1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP 2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP 3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +5 2.00 Replication Testing b1b1b1b1b1b1b1b1 Buda 2 CURRENT_TIMESTAMP *** DROP TABLE t15 *** DROP TABLE t15; *** Create t16 on slave *** diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result index e70a2efaf29..2228c68b271 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result @@ -707,7 +707,7 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1060 Last_SQL_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5' -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; *** Try to insert in master **** INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2); @@ -723,6 +723,7 @@ c1 c2 c3 c4 c5 c6 c7 1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP 2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP 3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +5 2.00 Replication Testing b1b1b1b1b1b1b1b1 Buda 2 CURRENT_TIMESTAMP *** DROP TABLE t15 *** DROP TABLE t15; *** Create t16 on slave *** From ba7570b11099894bd6a80f4729da290c9c47b00c Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 22 Oct 2007 21:45:21 +0300 Subject: [PATCH 044/136] Bug #30594 rpl.rpl_skip_error is nondeterministic Non-determinism in the tests was due to results of SBR are different from those gained with row binlog format. Because tests effectively verify skipping only ER_DUP_ENTRY it is explicitly required to run the test on in mixed and stmt binlog format. ER_DUP_ENTRY is automatically ignored when happened in RBR because of implicit rule favoring reentrant reading from binlog rule which means that a Write_rows_log_event overwrites a slave's row if the one has the same primary key. If future we might have skipping error due to applying of row-based events. The comments added saying a new file would be needed for that: rpl_row_skip_error or smth. mysql-test/suite/rpl/r/rpl_skip_error.result: new results mysql-test/suite/rpl/t/rpl_skip_error-slave.opt: wrong error code that can not happen in the test removed. mysql-test/suite/rpl/t/rpl_skip_error.test: enforcing the test is to skip only errors due to SBR. The current test does not check anything for RBR as ignorable ER_DUP_ENTRY does make sense only for SBR. --- mysql-test/suite/rpl/r/rpl_skip_error.result | 3 +-- mysql-test/suite/rpl/t/rpl_skip_error-slave.opt | 2 +- mysql-test/suite/rpl/t/rpl_skip_error.test | 8 ++++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_skip_error.result b/mysql-test/suite/rpl/r/rpl_skip_error.result index 525909387b3..ed4c4a6b3bb 100644 --- a/mysql-test/suite/rpl/r/rpl_skip_error.result +++ b/mysql-test/suite/rpl/r/rpl_skip_error.result @@ -29,8 +29,7 @@ select * from t1; a 1 2 -3 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 786 # # master-bin.000001 Yes Yes 0 0 786 # None 0 No # No 0 0 +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 851 # # master-bin.000001 Yes Yes 0 0 851 # None 0 No # No 0 0 drop table t1; diff --git a/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt b/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt index c84171976a1..a8f5deaa30b 100644 --- a/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt +++ b/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt @@ -1 +1 @@ ---slave-skip-error=1062,1582 +--slave-skip-error=1062 diff --git a/mysql-test/suite/rpl/t/rpl_skip_error.test b/mysql-test/suite/rpl/t/rpl_skip_error.test index b68b637b3b0..72d434d9c9b 100644 --- a/mysql-test/suite/rpl/t/rpl_skip_error.test +++ b/mysql-test/suite/rpl/t/rpl_skip_error.test @@ -3,6 +3,14 @@ ######################################### # Note that errors are ignored by opt file. source include/master-slave.inc; +source include/have_binlog_format_mixed_or_statement.inc; + +# +# Bug #30594 +# Skipping error due to applying Row-based repliation events +# should be checked with another test file +# consider names like rpl_row_skip_error +# create table t1 (n int not null primary key); save_master_pos; From 47bed4d45d517b6bfe4bc016ea76a2ddeb86226f Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Oct 2007 12:08:33 +0500 Subject: [PATCH 045/136] Bug#31081 server crash in regexp function Additional fix for valgrind warning --- sql/item_cmpfunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 51b3e8cda6b..59e11b81c17 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4255,7 +4255,7 @@ Item_func_regex::regcomp(bool send_error) res= &conv; } - if ((error= my_regcomp(&preg, res->c_ptr(), + if ((error= my_regcomp(&preg, res->c_ptr_safe(), regex_lib_flags, regex_lib_charset))) { if (send_error) From 4a08f392145264021ad20908157072fbdc653908 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Oct 2007 16:02:37 +0200 Subject: [PATCH 046/136] BUG#31702 (Missing row on slave causes assertion failure under row-based replication): Incremental patch to enable idempotency support for update events again. The final handling of errors will be done in BUG#31609, and until then the handling of errors should be consistent between the different types of changes. mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result: Result change. mysql-test/suite/rpl/r/rpl_temporary_errors.result: Result change. mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test: Changing test to assume idempotency handling of update event. mysql-test/suite/rpl/t/rpl_temporary_errors.test: Changing test to assume idempotency handling of update event. sql/log_event.cc: Incremental patch to enable idempotency support for the update events again. The real error handling will be implemented in BUG#31609. --- mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result | 2 +- mysql-test/suite/rpl/r/rpl_temporary_errors.result | 14 +++++++------- mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test | 4 +--- mysql-test/suite/rpl/t/rpl_temporary_errors.test | 4 +--- sql/log_event.cc | 9 +++------ 5 files changed, 13 insertions(+), 20 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result index 5ad9ba7ced0..c3fd663fad8 100644 --- a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result +++ b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result @@ -265,7 +265,7 @@ a b 5 master **** On Slave **** Last_SQL_Error -Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' + SELECT * FROM t1 ORDER BY a; a b 2 master,slave diff --git a/mysql-test/suite/rpl/r/rpl_temporary_errors.result b/mysql-test/suite/rpl/r/rpl_temporary_errors.result index 31c8930ec4f..5c681683b08 100644 --- a/mysql-test/suite/rpl/r/rpl_temporary_errors.result +++ b/mysql-test/suite/rpl/r/rpl_temporary_errors.result @@ -30,7 +30,7 @@ a b **** On Slave **** SHOW STATUS LIKE 'Slave_retried_transactions'; Variable_name Value -Slave_retried_transactions 2 +Slave_retried_transactions 0 SELECT * FROM t1; a b 5 47 @@ -49,17 +49,17 @@ Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 Slave_IO_Running Yes -Slave_SQL_Running No +Slave_SQL_Running Yes Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1032 -Last_Error Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' +Last_Errno 0 +Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 318 +Exec_Master_Log_Pos 408 Relay_Log_Space # Until_Condition None Until_Log_File @@ -74,8 +74,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1032 -Last_SQL_Error Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' +Last_SQL_Errno 0 +Last_SQL_Error DROP TABLE t1; **** On Master **** DROP TABLE t1; diff --git a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test index f6180de52a4..07fe763eb3c 100644 --- a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test +++ b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test @@ -245,11 +245,9 @@ SELECT * FROM t1 ORDER BY a; --echo **** On Master **** connection master; UPDATE t1 SET a = 5, b = 'master' WHERE a = 1; -save_master_pos; SELECT * FROM t1 ORDER BY a; --echo **** On Slave **** -connection slave; -source include/wait_for_slave_sql_error.inc; +sync_slave_with_master; let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1); disable_query_log; eval SELECT "$last_error" AS Last_SQL_Error; diff --git a/mysql-test/suite/rpl/t/rpl_temporary_errors.test b/mysql-test/suite/rpl/t/rpl_temporary_errors.test index 0ca515fff40..6a57f3cc167 100644 --- a/mysql-test/suite/rpl/t/rpl_temporary_errors.test +++ b/mysql-test/suite/rpl/t/rpl_temporary_errors.test @@ -13,12 +13,10 @@ SELECT * FROM t1; --echo **** On Master **** connection master; UPDATE t1 SET a = 5, b = 5 WHERE a = 1; -save_master_pos; SELECT * FROM t1; #SHOW BINLOG EVENTS; --echo **** On Slave **** -connection slave; -source include/wait_for_slave_sql_to_stop.inc; +sync_slave_with_master; SHOW STATUS LIKE 'Slave_retried_transactions'; SELECT * FROM t1; source include/show_slave_status.inc; diff --git a/sql/log_event.cc b/sql/log_event.cc index fd7e3e5db6b..5864433ec05 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6180,12 +6180,9 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) case HA_ERR_RECORD_CHANGED: case HA_ERR_KEY_NOT_FOUND: /* Idempotency support: OK if tuple does not exist */ - if (get_type_code() != UPDATE_ROWS_EVENT) - { - error= 0; - break; - } - /* Fall through in the event that we have an update event */ + error= 0; + break; + default: rli->report(ERROR_LEVEL, thd->net.last_errno, "Error in %s event: row application failed. %s", From f8f8c0282aa2dcf37e9d0b600b0216159a181338 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 25 Oct 2007 11:58:18 +0200 Subject: [PATCH 047/136] WL#4078: Document binary format of binlog entries Documented some binlog events using doxygen. More will be done later. Also fixed typos in other comments and added remarks about dubious code. Only comments are affected, there is no change to the actual code. sql/log_event.cc: Fixed typos in some comments. Added remarks (as comments) about questionable code. sql/log_event.h: Documented the binary format of following binlog events: Log_event Query_log_event Muted_query_log_event Slave_log_event (partial) Load_log_event Intvar_log_event Rand_log_event Rotate_log_event (partial) sql/sql_class.h: Fixed typo in comment. --- sql/log_event.cc | 29 +- sql/log_event.h | 989 +++++++++++++++++++++++++++++++++++++++++------ sql/sql_class.h | 12 +- 3 files changed, 898 insertions(+), 132 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index c0fbfb1000d..e5a26d48af9 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1328,6 +1328,11 @@ static void write_str_with_code_and_len(char **dst, const char *src, bool Query_log_event::write(IO_CACHE* file) { + /** + @todo if catalog can be of length FN_REFLEN==512, then we are not + replicating it correctly, since the length is stored in a byte + /sven + */ uchar buf[QUERY_HEADER_LEN+ 1+4+ // code of flags2 and flags2 1+8+ // code of sql_mode and sql_mode @@ -1554,6 +1559,10 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, time(&end_time); exec_time = (ulong) (end_time - thd_arg->start_time); + /** + @todo this means that if we have no catalog, then it is replicated + as an existing catalog of length zero. is that safe? /sven + */ catalog_len = (catalog) ? (uint32) strlen(catalog) : 0; /* status_vars_len is set just before writing the event */ db_len = (db) ? (uint32) strlen(db) : 0; @@ -1563,7 +1572,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, /* If we don't use flags2 for anything else than options contained in thd_arg->options, it would be more efficient to flags2=thd_arg->options - (OPTIONS_WRITTEN_TO_BINLOG would be used only at reading time). + (OPTIONS_WRITTEN_TO_BIN_LOG would be used only at reading time). But it's likely that we don't want to use 32 bits for 3 bits; in the future we will probably want to reclaim the 29 bits. So we need the &. */ @@ -1764,6 +1773,11 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, DBUG_VOID_RETURN; if (catalog_len) // If catalog is given { + /** + @todo we should clean up and do only copy_str_and_move; it + works for both cases. Then we can remove the catalog_nz + flag. /sven + */ if (likely(catalog_nz)) // true except if event comes from 5.0.0|1|2|3. copy_str_and_move(&catalog, &start, catalog_len); else @@ -1776,6 +1790,13 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, if (time_zone_len) copy_str_and_move(&time_zone_str, &start, time_zone_len); + /** + if time_zone_len or catalog_len are 0, then time_zone and catalog + are uninitialized at this point. shouldn't they point to the + zero-length null-terminated strings we allocated space for in the + my_alloc call above? /sven + */ + /* A 2nd variable part; this is common to all versions */ memcpy((char*) start, end, data_len); // Copy db and query start[data_len]= '\0'; // End query with \0 (For safetly) @@ -2836,7 +2857,7 @@ uint Load_log_event::get_query_buffer_length() 21 + sql_ex.field_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'" 23 + sql_ex.enclosed_len*4 + 2 + // " OPTIONALLY ENCLOSED BY 'str'" 12 + sql_ex.escaped_len*4 + 2 + // " ESCAPED BY 'str'" - 21 + sql_ex.line_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'" + 21 + sql_ex.line_term_len*4 + 2 + // " LINES TERMINATED BY 'str'" 19 + sql_ex.line_start_len*4 + 2 + // " LINES STARTING BY 'str'" 15 + 22 + // " IGNORE xxx LINES" 3 + (num_fields-1)*2 + field_block_len; // " (field1, field2, ...)" @@ -5654,6 +5675,10 @@ bool sql_ex_info::write_data(IO_CACHE* file) } else { + /** + @todo This is sensitive to field padding. We should write a + char[7], not an old_sql_ex. /sven + */ old_sql_ex old_ex; old_ex.field_term= *field_term; old_ex.enclosed= *enclosed; diff --git a/sql/log_event.h b/sql/log_event.h index f1f90aee69f..ab2424d8466 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -18,8 +18,10 @@ @{ @file - - Binary log event definitions. + + @brief Binary log event definitions. This includes generic code + common to all types of log events, as well as specific code for each + type of log event. */ @@ -411,15 +413,19 @@ struct sql_ex_info #define LOG_EVENT_BINLOG_IN_USE_F 0x1 -/* - If the query depends on the thread (for example: TEMPORARY TABLE). - Currently this is used by mysqlbinlog to know it must print - SET @@PSEUDO_THREAD_ID=xx; before the query (it would not hurt to print it - for every query but this would be slow). +/** + @def LOG_EVENT_THREAD_SPECIFIC_F + + If the query depends on the thread (for example: TEMPORARY TABLE). + Currently this is used by mysqlbinlog to know it must print + SET @@PSEUDO_THREAD_ID=xx; before the query (it would not hurt to print it + for every query but this would be slow). */ #define LOG_EVENT_THREAD_SPECIFIC_F 0x4 -/* +/** + @def LOG_EVENT_SUPPRESS_USE_F + Suppress the generation of 'USE' statements before the actual statement. This flag should be set for any events that does not need the current database set to function correctly. Most notable cases @@ -438,23 +444,26 @@ struct sql_ex_info */ #define LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F 0x10 -/* - OPTIONS_WRITTEN_TO_BIN_LOG are the bits of thd->options which must be - written to the binlog. OPTIONS_WRITTEN_TO_BINLOG could be written - into the Format_description_log_event, so that if later we don't want - to replicate a variable we did replicate, or the contrary, it's - doable. But it should not be too hard to decide once for all of what - we replicate and what we don't, among the fixed 32 bits of - thd->options. - I (Guilhem) have read through every option's usage, and it looks like - OPTION_AUTO_IS_NULL and OPTION_NO_FOREIGN_KEYS are the only ones - which alter how the query modifies the table. It's good to replicate - OPTION_RELAXED_UNIQUE_CHECKS too because otherwise, the slave may - insert data slower than the master, in InnoDB. - OPTION_BIG_SELECTS is not needed (the slave thread runs with - max_join_size=HA_POS_ERROR) and OPTION_BIG_TABLES is not needed - either, as the manual says (because a too big in-memory temp table is - automatically written to disk). +/** + @def OPTIONS_WRITTEN_TO_BIN_LOG + + OPTIONS_WRITTEN_TO_BIN_LOG are the bits of thd->options which must + be written to the binlog. OPTIONS_WRITTEN_TO_BIN_LOG could be + written into the Format_description_log_event, so that if later we + don't want to replicate a variable we did replicate, or the + contrary, it's doable. But it should not be too hard to decide once + for all of what we replicate and what we don't, among the fixed 32 + bits of thd->options. + + I (Guilhem) have read through every option's usage, and it looks + like OPTION_AUTO_IS_NULL and OPTION_NO_FOREIGN_KEYS are the only + ones which alter how the query modifies the table. It's good to + replicate OPTION_RELAXED_UNIQUE_CHECKS too because otherwise, the + slave may insert data slower than the master, in InnoDB. + OPTION_BIG_SELECTS is not needed (the slave thread runs with + max_join_size=HA_POS_ERROR) and OPTION_BIG_TABLES is not needed + either, as the manual says (because a too big in-memory temp table + is automatically written to disk). */ #define OPTIONS_WRITTEN_TO_BIN_LOG \ (OPTION_AUTO_IS_NULL | OPTION_NO_FOREIGN_KEY_CHECKS | \ @@ -469,6 +478,11 @@ struct sql_ex_info #endif #undef EXPECTED_OPTIONS /* You shouldn't use this one */ +/** + @enum Log_event_type + + Enumeration type for the different types of log events. +*/ enum Log_event_type { /* @@ -629,13 +643,90 @@ typedef struct st_print_event_info #endif -/***************************************************************************** - - Log_event class +/** + @class Log_event This is the abstract base class for binary log events. + + @section Log_event_binary_format Binary Format - ****************************************************************************/ + Any Log_event saved on disk consists of the following three + components. + + @li Common-Header + @li Post-Header + @li Body + + The Common-Header, documented below, always has the same form and + length within one version of MySQL. Each event type specifies a + form and length of the Post-Header common to all events of the type. + The Body may be of different form and length even for different + events of the same type. The binary formats of Post-Header and Body + are documented separately in each subclass. The binary format of + Common-Header is as follows. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Common-Header
NameFormat
Description
timestamp4 byte unsigned integerThe number of seconds since 1970. +
type1 byte enumerationSee enum #Log_event_type.
master_id4 byte integerServer ID of the server that created the event.
total_size4 byte integerThe total size of this event, in bytes. In other words, this + is the sum of the sizes of Common-Header, Post-Header, and Body. +
master_position4 byte integerThe position of the next event in the master binary log, in + bytes from the beginning of the file. +
flags2 byte bitfieldSee Log_event::flags.
+ + Summing up the numbers above, we see that the total size of the + common header is 19 bytes. + + @subsection Log_event_endianness_and_string_formats Endianness and String Formats + + All numbers, whether they are 16-, 32-, or 64-bit, are stored in + little endian, i.e., the least significant byte first. + + Strings are stored in various formats. The format of each string is + documented separately. +*/ class Log_event { public: @@ -709,8 +800,8 @@ public: */ uint32 server_id; - /* - Some 16 flags. Look above for LOG_EVENT_TIME_F, + /** + Some 16 flags. See the definitions above for LOG_EVENT_TIME_F, LOG_EVENT_FORCED_ROTATE_F, LOG_EVENT_THREAD_SPECIFIC_F, and LOG_EVENT_SUPPRESS_USE_F for notes. */ @@ -986,6 +1077,7 @@ protected: #endif }; + /* One class for each type of event. Two constructors for each class: @@ -999,13 +1091,332 @@ protected: mysqlbinlog. This constructor must be format-tolerant. */ -/***************************************************************************** +/** + @class Query_log_event + + Logs SQL queries. - Query Log Event class + @section Query_log_event_binary_format Binary format - Logs SQL queries + The Post-Header has five components: - ****************************************************************************/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Post-Header for Query_log_event
NameSize
Description
slave_proxy_id4 byte unsigned integerAn integer identifying the client thread, which is unique on + the server. (Note, however, that two threads on different servers + may have the same slave_proxy_id.) This is used when a client + thread creates a temporary table. Temporary tables are local to + the client, and the slave_proxy_id is used to distinguish + temporary tables belonging to different clients. +
exec_time4 byte integer???TODO
db_len1 byte integerThe length of the name of the currently selected + database. +
error_code2 byte integerError code generated by the master. If the master fails, the + slave will fail with the same error code, except for the error + codes ER_DB_CREATE_EXISTS==1007 and ER_DB_DROP_EXISTS==1008. +
status_vars_len2 byte integerThe length of the status_vars block of the Body, in bytes. See + below. +
Post-Header-For-Derived0 bytesThis field is only written by the subclass + Execute_load_query_log_event. In this base class, it takes 0 + bytes. See separate documentation for + Execute_load_query_log_event. +
+ + The Body has the following components: + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Body for Query_log_event
NameSize
Description
status_varsvariable lengthZero or more status variables. Each status variable consists + of one byte identifying the variable stored, followed by the value + of the variable. The possible variables are listed separately in + the table below. MySQL always writes events in the order defined + below; however, it is capable of reading them in any order. +
dbdb_len+1The currently selected database, as a null-terminated string. + + (The trailing zero is redundant since the length is already known; + it is db_len from Post-Header.) +
queryvariable length string without trailing zero, extending to the + end of the event (determined by the length field of the + Common-Header) + The SQL query.
+ + The following table lists the status variables that may appear in + the status_vars field. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Status variables for Query_log_event
Status variable1-byte identifierSize
Description
flags2Q_FLAGS2_CODE == 04 byte bitfieldThe flags in thd->options, binary AND-ed with + OPTIONS_WRITTEN_TO_BIN_LOG. The thd->options bitfield contains + options for SELECT. OPTIONS_WRITTEN identifies those options that + need to be written to the binlog (not all do). Specifically, + OPTIONS_WRITTEN_TO_BIN_LOG equals (OPTION_AUTO_IS_NULL | + OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS | + OPTION_NOT_AUTOCOMMIT), or 0x0c084000 in hex. + + These flags correspond to the SQL variables SQL_AUTO_IS_NULL, + FOREIGN_KEY_CHECKS, UNIQUE_CHECKS, and AUTOCOMMIT, documented in + the "SET Syntax" section of the MySQL Manual. + + This field is always written to the binlog in version >= 5.0, and + never written in version < 5.0. +
sql_modeQ_SQL_MODE_CODE == 18 byte integerThe sql_mode variable. See the section "SQL Modes" in the + MySQL manual, and see mysql_priv.h for a list of the possible + flags. Currently (2007-10-04), the following flags are available: +
+    MODE_REAL_AS_FLOAT==0x1
+    MODE_PIPES_AS_CONCAT==0x2
+    MODE_ANSI_QUOTES==0x4
+    MODE_IGNORE_SPACE==0x8
+    MODE_NOT_USED==0x10
+    MODE_ONLY_FULL_GROUP_BY==0x20
+    MODE_NO_UNSIGNED_SUBTRACTION==0x40
+    MODE_NO_DIR_IN_CREATE==0x80
+    MODE_POSTGRESQL==0x100
+    MODE_ORACLE==0x200
+    MODE_MSSQL==0x400
+    MODE_DB2==0x800
+    MODE_MAXDB==0x1000
+    MODE_NO_KEY_OPTIONS==0x2000
+    MODE_NO_TABLE_OPTIONS==0x4000
+    MODE_NO_FIELD_OPTIONS==0x8000
+    MODE_MYSQL323==0x10000
+    MODE_MYSQL323==0x20000
+    MODE_MYSQL40==0x40000
+    MODE_ANSI==0x80000
+    MODE_NO_AUTO_VALUE_ON_ZERO==0x100000
+    MODE_NO_BACKSLASH_ESCAPES==0x200000
+    MODE_STRICT_TRANS_TABLES==0x400000
+    MODE_STRICT_ALL_TABLES==0x800000
+    MODE_NO_ZERO_IN_DATE==0x1000000
+    MODE_NO_ZERO_DATE==0x2000000
+    MODE_INVALID_DATES==0x4000000
+    MODE_ERROR_FOR_DIVISION_BY_ZERO==0x8000000
+    MODE_TRADITIONAL==0x10000000
+    MODE_NO_AUTO_CREATE_USER==0x20000000
+    MODE_HIGH_NOT_PRECEDENCE==0x40000000
+    MODE_PAD_CHAR_TO_FULL_LENGTH==0x80000000
+    
+ All these flags are replicated from the server. However, all + flags except MODE_NO_DIR_IN_CREATE are honored by the slave; the + slave always preserves its old value of MODE_NO_DIR_IN_CREATE. + For a rationale, see comment in Query_log_event::do_apply_event in + log_event.cc. + + This field is always written to the binlog. +
catalogQ_CATALOG_NZ_CODE == 6Variable-length string: the length in bytes (1 byte) followed + by the characters (at most 255 bytes) + Stores the client's current catalog. Every database belongs + to a catalog, the same way that every table belongs to a + database. Currently, there is only one catalog, 'std'. + + This field is written if the length of the catalog is > 0; + otherwise it is not written. +
auto_incrementQ_AUTO_INCREMENT == 3two 2 byte unsigned integers, totally 2+2=4 bytesThe two variables auto_increment_increment and + auto_increment_offset, in that order. For more information, see + "System variables" in the MySQL manual. + + This field is written if auto_increment>1; otherwise it is not + written. +
charsetQ_CHARSET_CODE == 4three 2-byte unsigned integers (i.e., 6 bytes)The three variables character_set_client, + collation_connection, and collation_server, in that order. + `character_set_client' is a code identifying the character set and + collation used by the client to encode the query. + `collation_connection' identifies the character set and collation + that the master converts the query to when it receives it; this is + useful when comparing literal strings. `collation_server' is the + default character set and collation used when a new database is + created. + + See also "Connection Character Sets and Collations" in the MySQL + 5.1 manual. + + All three variables are codes identifying a (character set, + collation) pair. To see which codes map to which pairs, run the + query "SELECT id, character_set_name, collation_name FROM + COLLATIONS". + + Cf. Q_CHARSET_DATABASE_NUMBER below. + + This field is always written. +
time_zoneQ_TIME_ZONE_CODE == 5Variable-length string: the length in bytes (1 byte) followed + by the characters (at most 255 bytes). + The time_zone of the master. + + See also "System Variables" and "MySQL Server Time Zone Support" + in the MySQL manual. + + This field is written if the length of the time zone string is > + 0; otherwise, it is not written. +
lc_time_names_numberQ_LC_TIME_NAMES_CODE == 72 byte integerA code identifying a table of month and day names. The + mapping from codes to languages is defined in sql_locale.cc. + + This field is written if it is != 0, i.e., if the locale is not + en_US. +
charset_database_numberQ_CHARSET_DATABASE_NUMBER == 82 byte integerThe value of the collation_database system variable (in the + source code stored in thd->variables.collation_database), which + holds the code for a (character set, collation) pair as described + above (see Q_CHARSET_CODE). + + `collation_database' was used in old versions (???WHEN). Its + value was loaded when issuing a "use db" command and could be + changed by issuing a "SET collation_database=xxx" command. It + used to affect the "LOAD DATA INFILE" and "CREATE TABLE" commands. + + In newer versions, "CREATE TABLE" has been changed to take the + character set from the database of the created table, rather than + the database of the current database. This makes a difference + when creating a table in another database than the current one. + "LOAD DATA INFILE" has not yet changed to do this, but there are + plans to eventually do it, and to make collation_database + read-only. + + This field is written if it is not 0. +
+ + @subsection Query_log_event_notes_on_previous_versions Notes on Previous Versions + + @li Status vars were introduced in version 5.0. To read earlier + versions correctly, check the length of the Post-Header. + + @li The status variable Q_CATALOG_CODE == 2 existed in MySQL 5.0.x, + where 0<=x<=3. It was identical to Q_CATALOG_CODE, except that the + string had a trailing '\0'. The '\0' was removed in 5.0.4 since it + was redundant (the string length is stored before the string). The + Q_CATALOG_CODE will never be written by a new master, but can still + be understood by a new slave. + + @li See Q_CHARSET_DATABASE_NUMBER in the table above. + +*/ class Query_log_event: public Log_event { protected: @@ -1063,7 +1474,7 @@ public: /* 'flags2' is a second set of flags (on top of those in Log_event), for session variables. These are thd->options which is & against a mask - (OPTIONS_WRITTEN_TO_BINLOG). + (OPTIONS_WRITTEN_TO_BIN_LOG). flags2_inited helps make a difference between flags2==0 (3.23 or 4.x master, we don't know flags2, so use the slave server's global options) and flags2==0 (5.0 master, we know this has a meaning of flags all down which @@ -1133,13 +1544,16 @@ public: /* !!! Public in this patch to allow old usage */ }; -/***************************************************************************** +/** + @class Muted_query_log_event - Muted Query Log Event class + Pretends to log SQL queries, but doesn't actually do so. - Pretends to Log SQL queries, but doesn't actually do so. + @section Muted_query_log_event_binary_format Binary Format - ****************************************************************************/ + This log event is not stored, and thus the binary format is 0 bytes + long. Note that not even the Common-Header is stored. +*/ class Muted_query_log_event: public Query_log_event { public: @@ -1156,14 +1570,54 @@ public: #ifdef HAVE_REPLICATION -/***************************************************************************** +/** + @class Slave_log_event - Slave Log Event class Note that this class is currently not used at all; no code writes a - Slave_log_event (though some code in repl_failsafe.cc reads Slave_log_event). - So it's not a problem if this code is not maintained. + Slave_log_event (though some code in repl_failsafe.cc reads + Slave_log_event). So it's not a problem if this code is not + maintained. - ****************************************************************************/ + @section Slave_log_event_binary_format Binary Format + + This event type has no Post-Header. The Body has the following + four components. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Body for Slave_log_event
NameSize
Description
master_pos8 byte integer???TODO +
master_port2 byte integer???TODO
master_hostnull-terminated string???TODO
master_lognull-terminated string???TODO
+*/ class Slave_log_event: public Log_event { protected: @@ -1202,11 +1656,202 @@ private: #endif /* HAVE_REPLICATION */ -/***************************************************************************** +/** + @class Load_log_event - Load Log Event class + This log event corresponds to a "LOAD DATA INFILE" SQL query on the + following form: - ****************************************************************************/ + @verbatim + (1) USE db; + (2) LOAD DATA [LOCAL] INFILE 'file_name' + (3) [REPLACE | IGNORE] + (4) INTO TABLE 'table_name' + (5) [FIELDS + (6) [TERMINATED BY 'field_term'] + (7) [[OPTIONALLY] ENCLOSED BY 'enclosed'] + (8) [ESCAPED BY 'escaped'] + (9) ] + (10) [LINES + (11) [TERMINATED BY 'line_term'] + (12) [LINES STARTING BY 'line_start'] + (13) ] + (14) [IGNORE skip_lines LINES] + (15) (field_1, field_2, ..., field_n)@endverbatim + + @section Load_log_event_binary_format Binary Format + + The Post-Header consists of the following six components. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Post-Header for Load_log_event
NameSize
Description
slave_proxy_id4 byte unsigned integerAn integer identifying the client thread, which is unique on + the server. (Note, however, that the same slave_proxy_id may + appear on different servers.) This is used when a client thread + creates a temporary table. Temporary tables are local to the + client, and the slave_proxy_id is used to distinguish temporary + tables belonging to different clients. +
exec_time4 byte unsigned integer???TODO
skip_lines4 byte unsigned integerThe number on line (14) above, if present, or 0 if line (14) + is left out. +
table_name_len1 byte unsigned integerThe length of 'table_name' on line (4) above.
db_len1 byte unsigned integerThe length of 'db' on line (1) above.
num_fields4 byte unsigned integerThe number n of fields on line (15) above.
+ + The Body contains the following components. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Body of Load_log_event
NameSize
Description
sql_exvariable lengthDescribes the part of the query on lines (3) and + (5)–(13) above. More precisely, it stores the five strings + (on lines) field_term (6), enclosed (7), escaped (8), line_term + (11), and line_start (12); as well as a bitfield indicating the + presence of the keywords REPLACE (3), IGNORE (3), and OPTIONALLY + (7). + + The data is stored in one of two formats, called "old" and "new". + The type field of Common-Header determines which of these two + formats is used: type LOAD_EVENT means that the old format is + used, and type NEW_LOAD_EVENT means that the new format is used. + When MySQL writes a Load_log_event, it uses the new format if at + least one of the five strings is two or more bytes long. + Otherwise (i.e., if all strings are 0 or 1 bytes long), the old + format is used. + + The new and old format differ in the way the five strings are + stored. + +
    +
  • In the new format, the strings are stored in the order + field_term, enclosed, escaped, line_term, line_start. Each string + consists of a length (1 byte), followed by a sequence of + characters (0-255 bytes). Finally, a boolean combination of the + following flags is stored in 1 byte: REPLACE_FLAG==0x4, + IGNORE_FLAG==0x8, and OPT_ENCLOSED_FLAG==0x2. If a flag is set, + it indicates the presence of the corresponding keyword in the SQL + query. + +
  • In the old format, we know that each string has length 0 or + 1. Therefore, only the first byte of each string is stored. The + order of the strings is the same as in the new format. These five + bytes are followed by the same 1-byte bitfield as in the new + format. Finally, a 1 byte bitfield called empty_flags is stored. + The low 5 bits of empty_flags indicate which of the five strings + have length 0. For each of the following flags that is set, the + corresponding string has length 0; for the flags that are not set, + the string has length 1: FIELD_TERM_EMPTY==0x1, + ENCLOSED_EMPTY==0x2, LINE_TERM_EMPTY==0x4, LINE_START_EMPTY==0x8, + ESCAPED_EMPTY==0x10. +
+ + Thus, the size of the new format is 6 bytes + the sum of the sizes + of the five strings. The size of the old format is always 7 + bytes. +
field_lensnum_fields 1-byte unsigned integersAn array of num_fields integers representing the length of + each field in the query. (num_fields is from the Post-Header). +
fieldsnum_fields null-terminated stringsAn array of num_fields null-terminated strings, each + representing a field in the query. (The trailing zero is + redundant, since the length are stored in the num_fields array.) + The total length of all strings equals to the sum of all + field_lens, plus num_fields bytes for all the trailing zeros. +
table_namenull-terminated string of length table_len+1 bytesThe 'table_name' from the query, as a null-terminated string. + (The trailing zero is actually redundant since the table_len is + known from Post-Header.) +
dbnull-terminated string of length db_len+1 bytesThe 'db' from the query, as a null-terminated string. + (The trailing zero is actually redundant since the db_len is known + from Post-Header.) +
file_namevariable length string without trailing zero, extending to the + end of the event (determined by the length field of the + Common-Header) + The 'file_name' from the query. +
+ + @subsection Load_log_event_notes_on_previous_versions Notes on Previous Versions + +*/ class Load_log_event: public Log_event { private: @@ -1313,9 +1958,8 @@ public: /* !!! Public in this patch to allow old usage */ extern char server_version[SERVER_VERSION_LENGTH]; -/***************************************************************************** - - Start Log Event_v3 class +/** + @class Start_log_event_v3 Start_log_event_v3 is the Start_log_event of binlog format 3 (MySQL 3.23 and 4.x). @@ -1325,8 +1969,8 @@ extern char server_version[SERVER_VERSION_LENGTH]; MySQL 5.0 whenever it starts sending a new binlog if the requested position is >4 (otherwise if ==4 the event will be sent naturally). - ****************************************************************************/ - + @section Start_log_event_v3_binary_format Binary Format +*/ class Start_log_event_v3: public Log_event { public: @@ -1409,10 +2053,14 @@ protected: }; -/* - For binlog version 4. - This event is saved by threads which read it, as they need it for future - use (to decode the ordinary events). +/** + @class Format_description_log_event + + For binlog version 4. + This event is saved by threads which read it, as they need it for future + use (to decode the ordinary events). + + @section Format_description_log_event_binary_format Binary Format */ class Format_description_log_event: public Start_log_event_v3 @@ -1466,13 +2114,41 @@ protected: }; -/***************************************************************************** +/** + @class Intvar_log_event - Intvar Log Event class + Logs special variables related to auto_increment values. - Logs special variables such as auto_increment values + @section Intvar_log_event_binary_format Binary Format - ****************************************************************************/ + The Post-Header has two components: + + + + + + + + + + + + + + + + + + + + + + +
Post-Header for Intvar_log_event
NameSize
Description
Type1 byte enumerationOne byte identifying the type of variable stored. Currently, + two identifiers are supported: LAST_INSERT_ID_EVENT==1 and + INSERT_ID_EVENT==2. +
value8 byte unsigned integerThe value of the variable.
+*/ class Intvar_log_event: public Log_event { @@ -1511,16 +2187,24 @@ private: }; -/***************************************************************************** - - Rand Log Event class +/** + @class Rand_log_event Logs random seed used by the next RAND(), and by PASSWORD() in 4.1.0. 4.1.1 does not need it (it's repeatable again) so this event needn't be written in 4.1.1 for PASSWORD() (but the fact that it is written is just a waste, it does not cause bugs). - ****************************************************************************/ + @section Rand_log_event_binary_format Binary Format + This event type has no Post-Header. The Body of this event type has + two components: + + @li seed1 (8 bytes): 64 bit random seed1. + @li seed2 (8 bytes): 64 bit random seed2. + + The state of the random number generation consists of 128 bits, + which are stored internally as two 64-bit numbers. +*/ class Rand_log_event: public Log_event { @@ -1557,14 +2241,14 @@ private: #endif }; -/***************************************************************************** - - Xid Log Event class +/** + @class Xid_log_event Logs xid of the transaction-to-be-committed in the 2pc protocol. Has no meaning in replication, slaves ignore it. - ****************************************************************************/ + @section Xid_log_event_binary_format Binary Format +*/ #ifdef MYSQL_CLIENT typedef ulonglong my_xid; // this line is the same as in handler.h #endif @@ -1600,14 +2284,14 @@ private: #endif }; -/***************************************************************************** - - User var Log Event class +/** + @class User_var_log_event Every time a query uses the value of a user variable, a User_var_log_event is written before the Query_log_event, to set the user variable. - ****************************************************************************/ + @section User_var_log_event_binary_format Binary Format +*/ class User_var_log_event: public Log_event { @@ -1649,11 +2333,14 @@ private: }; -/***************************************************************************** +/** + @class Stop_log_event - Stop Log Event class + @section Stop_log_event_binary_format Binary Format - ****************************************************************************/ + The Post-Header and Body for this event type are empty; it only has + the Common-Header. +*/ class Stop_log_event: public Log_event { public: @@ -1689,13 +2376,54 @@ private: #endif }; -/***************************************************************************** - - Rotate Log Event class +/** + @class Rotate_log_event This will be deprecated when we move to using sequence ids. - ****************************************************************************/ + @section Rotate_log_event_binary_format Binary Format + + The Post-Header has one component: + + + + + + + + + + + + + + + + +
Post-Header for Rotate_log_event
NameSize
Description
pos8 byte integer???TODO
+ + The Body has one component: + + + + + + + + + + + + + + + + +
Body for Rotate_log_event
NameSize
Description
new_log_identvariable length string without trailing zero, extending to the + end of the event (determined by the length field of the + Common-Header) + ???TODO
+*/ class Rotate_log_event: public Log_event { @@ -1742,9 +2470,11 @@ private: /* the classes below are for the new LOAD DATA INFILE logging */ -/***************************************************************************** - Create File Log Event class - ****************************************************************************/ +/** + @class Create_file_log_event + + @section Create_file_log_event_binary_format Binary Format +*/ class Create_file_log_event: public Load_log_event { @@ -1813,11 +2543,11 @@ private: }; -/***************************************************************************** +/** + @class Append_block_log_event - Append Block Log Event class - - ****************************************************************************/ + @section Append_block_log_event_binary_format Binary Format +*/ class Append_block_log_event: public Log_event { @@ -1868,11 +2598,11 @@ private: }; -/***************************************************************************** +/** + @class Delete_file_log_event - Delete File Log Event class - - ****************************************************************************/ + @section Delete_file_log_event_binary_format Binary Format +*/ class Delete_file_log_event: public Log_event { @@ -1909,11 +2639,11 @@ private: }; -/***************************************************************************** +/** + @class Execute_load_log_event - Execute Load Log Event class - - ****************************************************************************/ + @section Delete_file_log_event_binary_format Binary Format +*/ class Execute_load_log_event: public Log_event { @@ -1949,15 +2679,15 @@ private: }; -/*************************************************************************** - - Begin load query Log Event class +/** + @class Begin_load_query_log_event Event for the first block of file to be loaded, its only difference from Append_block event is that this event creates or truncates existing file before writing data. -****************************************************************************/ + @section Begin_load_query_log_event_binary_format Binary Format +*/ class Begin_load_query_log_event: public Append_block_log_event { public: @@ -1988,15 +2718,15 @@ private: enum enum_load_dup_handling { LOAD_DUP_ERROR= 0, LOAD_DUP_IGNORE, LOAD_DUP_REPLACE }; -/**************************************************************************** - - Execute load query Log Event class +/** + @class Execute_load_query_log_event Event responsible for LOAD DATA execution, it similar to Query_log_event but before executing the query it substitutes original filename in LOAD DATA query with name of temporary file. -****************************************************************************/ + @section Execute_load_query_log_event_binary_format Binary Format +*/ class Execute_load_query_log_event: public Query_log_event { public: @@ -2048,6 +2778,11 @@ private: #ifdef MYSQL_CLIENT +/** + @class Unknown_log_event + + @section Unknown_log_event_binary_format Binary Format +*/ class Unknown_log_event: public Log_event { public: @@ -2068,14 +2803,14 @@ public: #endif char *str_to_hex(char *to, const char *from, uint len); -/***************************************************************************** - - Table map log event class +/** + @class Table_map_log_event Create a mapping from a (database name, table name) couple to a table identifier (an integer number). - ****************************************************************************/ + @section Table_map_log_event_binary_format Binary Format +*/ class Table_map_log_event : public Log_event { public: @@ -2185,9 +2920,8 @@ private: }; -/***************************************************************************** - - Row level log event class. +/** + @class Rows_log_event Common base class for all row-containing log events. @@ -2197,7 +2931,8 @@ private: - Write data header and data body to an IO_CACHE. - Provide an interface for adding an individual row to the event. - ****************************************************************************/ + @section Rows_log_event_binary_format Binary Format +*/ class Rows_log_event : public Log_event @@ -2428,15 +3163,15 @@ private: friend class Old_rows_log_event; }; -/***************************************************************************** - - Write row log event class +/** + @class Write_rows_log_event Log row insertions and updates. The event contain several insert/update rows for a table. Note that each event contains only rows for one table. - ****************************************************************************/ + @section Write_rows_log_event_binary_format Binary Format +*/ class Write_rows_log_event : public Rows_log_event { public: @@ -2483,9 +3218,8 @@ private: }; -/***************************************************************************** - - Update rows log event class +/** + @class Update_rows_log_event Log row updates with a before image. The event contain several update rows for a table. Note that each event contains only rows for @@ -2494,7 +3228,8 @@ private: Also note that the row data consists of pairs of row data: one row for the old data and one row for the new data. - ****************************************************************************/ + @section Update_rows_log_event_binary_format Binary Format +*/ class Update_rows_log_event : public Rows_log_event { public: @@ -2556,9 +3291,8 @@ protected: #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ }; -/***************************************************************************** - - Delete rows log event class. +/** + @class Delete_rows_log_event Log row deletions. The event contain several delete rows for a table. Note that each event contains only rows for one table. @@ -2575,7 +3309,8 @@ protected: Row_reader Extract the rows from the event. - ****************************************************************************/ + @section Delete_rows_log_event_binary_format Binary Format +*/ class Delete_rows_log_event : public Rows_log_event { public: @@ -2625,6 +3360,8 @@ protected: #include "log_event_old.h" /** + @class Incident_log_event + Class representing an incident, an occurance out of the ordinary, that happened on the master. @@ -2636,7 +3373,7 @@ protected: Incident event format Symbol - Size
(bytes) + Size
(bytes) Description @@ -2655,7 +3392,9 @@ protected: The message, if present. Not null terminated. - */ + + @section Delete_rows_log_event_binary_format Binary Format +*/ class Incident_log_event : public Log_event { public: #ifndef MYSQL_CLIENT diff --git a/sql/sql_class.h b/sql/sql_class.h index 1b07ab08d32..2084fbcb7ed 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1263,14 +1263,16 @@ public: We follow this logic: - when stmt starts, first_successful_insert_id_in_prev_stmt contains the first insert id successfully inserted by the previous stmt. - - as stmt makes progress, handler::insert_id_for_cur_row changes; every - time get_auto_increment() is called, auto_inc_intervals_for_binlog is - augmented with the reserved interval (if statement-based binlogging). + - as stmt makes progress, handler::insert_id_for_cur_row changes; + every time get_auto_increment() is called, + auto_inc_intervals_in_cur_stmt_for_binlog is augmented with the + reserved interval (if statement-based binlogging). - at first successful insertion of an autogenerated value, first_successful_insert_id_in_cur_stmt is set to handler::insert_id_for_cur_row. - - when stmt goes to binlog, auto_inc_intervals_for_binlog is - binlogged if non-empty. + - when stmt goes to binlog, + auto_inc_intervals_in_cur_stmt_for_binlog is binlogged if + non-empty. - when stmt ends, first_successful_insert_id_in_prev_stmt is set to first_successful_insert_id_in_cur_stmt. */ From 1b56c5d7306e7d7666c1e00d1f0fd4e9230c1b48 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 26 Oct 2007 16:11:20 +0200 Subject: [PATCH 048/136] Bug#28772 rpl_row_until fails in pushbuild mysql-test/suite/rpl/t/rpl_row_until.test: - Add a "wait_for_slave_to_stop.inc" after the two "stop slave" commands after wich we want to show the slaves status mysql-test/suite/rpl/t/rpl_stm_until.test: - Add a "wait_for_slave_to_stop.inc" after the two "stop slave" commands after wich we want to show the slaves status --- mysql-test/suite/rpl/t/rpl_row_until.test | 4 ++++ mysql-test/suite/rpl/t/rpl_stm_until.test | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/mysql-test/suite/rpl/t/rpl_row_until.test b/mysql-test/suite/rpl/t/rpl_row_until.test index 9464e5cfadd..610eec305df 100644 --- a/mysql-test/suite/rpl/t/rpl_row_until.test +++ b/mysql-test/suite/rpl/t/rpl_row_until.test @@ -13,6 +13,8 @@ save_master_pos; connection slave; sync_with_master; stop slave; +# Make sure the slave sql and io thread has stopped +--source include/wait_for_slave_to_stop.inc connection master; # create some events on master @@ -52,6 +54,8 @@ save_master_pos; connection slave; sync_with_master; stop slave; +# Make sure the slave sql and io thread has stopped +--source include/wait_for_slave_to_stop.inc # this should stop immediately as we are already there start slave until master_log_file='master-bin.000001', master_log_pos=740; diff --git a/mysql-test/suite/rpl/t/rpl_stm_until.test b/mysql-test/suite/rpl/t/rpl_stm_until.test index 98e7e0e5eac..c8d3cb1823d 100644 --- a/mysql-test/suite/rpl/t/rpl_stm_until.test +++ b/mysql-test/suite/rpl/t/rpl_stm_until.test @@ -12,6 +12,8 @@ save_master_pos; connection slave; sync_with_master; stop slave; +# Make sure the slave sql and io thread has stopped +--source include/wait_for_slave_to_stop.inc connection master; # create some events on master @@ -51,6 +53,8 @@ save_master_pos; connection slave; sync_with_master; stop slave; +# Make sure the slave sql and io thread has stopped +--source include/wait_for_slave_to_stop.inc # this should stop immediately as we are already there start slave until master_log_file='master-bin.000001', master_log_pos=776; From f01321fd090b5e22898e571ccae9a2be9574d297 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 26 Oct 2007 18:52:58 +0200 Subject: [PATCH 049/136] BUG#12691 (Exec_master_log_pos corrupted with SQL_SLAVE_SKIP_COUNTER): Adding code to keep skipping events while inside a transaction. Execution will start just after the transaction has been skipped. sql/slave.cc: Adding code to set the thd->options flag for the slave SQL thread even when BEGIN, ROLLBACK, COMMIT, and XID events are being skipped. Adding code to not decrease the slave skip counter from 1 to 0 if we are inside a transaction. This will keep the counter at 1, and keep skipping events, until a transaction terminator is read. At that point, the slave skip counter will be decreased to 0, and events will be read and executed instead of read and skipped. mysql-test/r/rpl_slave_skip.result: New BitKeeper file ``mysql-test/r/rpl_slave_skip.result'' mysql-test/t/rpl_slave_skip-slave.opt: New BitKeeper file ``mysql-test/t/rpl_slave_skip-slave.opt'' mysql-test/t/rpl_slave_skip.test: New BitKeeper file ``mysql-test/t/rpl_slave_skip.test'' --- mysql-test/r/rpl_slave_skip.result | 144 ++++++++++++++++++ mysql-test/t/rpl_slave_skip-slave.opt | 1 + mysql-test/t/rpl_slave_skip.test | 203 ++++++++++++++++++++++++++ sql/slave.cc | 56 ++++++- 4 files changed, 401 insertions(+), 3 deletions(-) create mode 100644 mysql-test/r/rpl_slave_skip.result create mode 100644 mysql-test/t/rpl_slave_skip-slave.opt create mode 100644 mysql-test/t/rpl_slave_skip.test diff --git a/mysql-test/r/rpl_slave_skip.result b/mysql-test/r/rpl_slave_skip.result new file mode 100644 index 00000000000..a59ac3eb884 --- /dev/null +++ b/mysql-test/r/rpl_slave_skip.result @@ -0,0 +1,144 @@ +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; +**** On Master **** +CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=INNODB; +CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MYISAM; +==== Skipping normal transactions ==== +**** On Slave **** +STOP SLAVE; +**** On Master **** +BEGIN; +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; +BEGIN; +INSERT INTO t1 VALUES (4, 'master,slave'); +INSERT INTO t1 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, 'master,slave'); +COMMIT; +SELECT * FROM t1 ORDER BY a; +a b +1 master +2 master +3 master +4 master,slave +5 master,slave +6 master,slave +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +SELECT * FROM t1 ORDER BY a; +a b +4 master,slave +5 master,slave +6 master,slave +**** On Master **** +DELETE FROM t1; +==== Skipping two normal transactions ==== +**** On Slave **** +STOP SLAVE; +**** On Master **** +BEGIN; +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; +BEGIN; +INSERT INTO t1 VALUES (4, 'master'); +INSERT INTO t1 VALUES (5, 'master'); +INSERT INTO t1 VALUES (6, 'master'); +COMMIT; +BEGIN; +INSERT INTO t1 VALUES (7, 'master,slave'); +INSERT INTO t1 VALUES (8, 'master,slave'); +INSERT INTO t1 VALUES (9, 'master,slave'); +COMMIT; +SELECT * FROM t1 ORDER BY a; +a b +1 master +2 master +3 master +4 master +5 master +6 master +7 master,slave +8 master,slave +9 master,slave +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8; +START SLAVE; +SELECT * FROM t1 ORDER BY a; +a b +7 master,slave +8 master,slave +9 master,slave +**** On Master **** +DELETE FROM t1; +==== Skipping without autocommit ==== +**** On Slave **** +STOP SLAVE; +**** On Master **** +SET AUTOCOMMIT=0; +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; +INSERT INTO t1 VALUES (4, 'master,slave'); +INSERT INTO t1 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, 'master,slave'); +COMMIT; +SELECT * FROM t1 ORDER BY a; +a b +1 master +2 master +3 master +4 master,slave +5 master,slave +6 master,slave +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +SELECT * FROM t1 ORDER BY a; +a b +4 master,slave +5 master,slave +6 master,slave +==== Rollback of transaction with non-transactional change ==== +**** On Master **** +DELETE FROM t1; +SET AUTOCOMMIT=1; +**** On Slave **** +STOP SLAVE; +**** On Master **** +BEGIN; +INSERT INTO t1 VALUES (1, ''); +INSERT INTO t2 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, ''); +ROLLBACK; +BEGIN; +INSERT INTO t1 VALUES (4, ''); +INSERT INTO t2 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, ''); +ROLLBACK; +SELECT * FROM t1 ORDER BY a; +a b +SELECT * FROM t2 ORDER BY a; +a b +2 master +5 master,slave +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +SELECT * FROM t1 ORDER BY a; +a b +SELECT * FROM t2 ORDER BY a; +a b +5 master,slave +==== Cleanup ==== +**** On Master **** +DROP TABLE t1, t2; diff --git a/mysql-test/t/rpl_slave_skip-slave.opt b/mysql-test/t/rpl_slave_skip-slave.opt new file mode 100644 index 00000000000..627becdbfb5 --- /dev/null +++ b/mysql-test/t/rpl_slave_skip-slave.opt @@ -0,0 +1 @@ +--innodb diff --git a/mysql-test/t/rpl_slave_skip.test b/mysql-test/t/rpl_slave_skip.test new file mode 100644 index 00000000000..04aafc51129 --- /dev/null +++ b/mysql-test/t/rpl_slave_skip.test @@ -0,0 +1,203 @@ +source include/have_innodb.inc; +source include/master-slave.inc; + +# This test is for checking that the use of SQL_SLAVE_SKIP_COUNTER +# behaves as expected, i.e., that it is guaranteed to skip an entire +# group and not start executing in the middle of a transaction. + +# We are checking the correct behaviour when using both a +# transactional and non-transactional table. The non-transactional +# table comes into play when rolling back a transaction containing a +# write to this table. In that case, the transaction should still be +# written to the binary log, and the slave will apply it and then roll +# it back to get the non-transactional change into the table. + +--echo **** On Master **** +CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=INNODB; +CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MYISAM; + +--echo ==== Skipping normal transactions ==== + +--echo **** On Slave **** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; + +BEGIN; +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; + +BEGIN; +INSERT INTO t1 VALUES (4, 'master,slave'); +INSERT INTO t1 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, 'master,slave'); +COMMIT; + +save_master_pos; + +SELECT * FROM t1 ORDER BY a; + +# This will skip a begin event and the first INSERT of the +# transaction, and it should keep skipping until it has reached the +# transaction terminator. + +--echo **** On Slave **** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; +SELECT * FROM t1 ORDER BY a; + +--echo **** On Master **** +connection master; +DELETE FROM t1; +sync_slave_with_master; + +--echo ==== Skipping two normal transactions ==== + +--echo **** On Slave **** +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; + +BEGIN; +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; + +BEGIN; +INSERT INTO t1 VALUES (4, 'master'); +INSERT INTO t1 VALUES (5, 'master'); +INSERT INTO t1 VALUES (6, 'master'); +COMMIT; + +BEGIN; +INSERT INTO t1 VALUES (7, 'master,slave'); +INSERT INTO t1 VALUES (8, 'master,slave'); +INSERT INTO t1 VALUES (9, 'master,slave'); +COMMIT; + +save_master_pos; + +SELECT * FROM t1 ORDER BY a; + +# This will skip a begin event and the first INSERT of the +# transaction, and it should keep skipping until it has reached the +# transaction terminator. + +--echo **** On Slave **** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; +SELECT * FROM t1 ORDER BY a; + +--echo **** On Master **** +connection master; +DELETE FROM t1; +sync_slave_with_master; + +--echo ==== Skipping without autocommit ==== + +# Testing without using autocommit instead. It should still write a +# BEGIN event, so the behaviour should be the same + +--echo **** On Slave **** +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; +SET AUTOCOMMIT=0; + +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; + +INSERT INTO t1 VALUES (4, 'master,slave'); +INSERT INTO t1 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, 'master,slave'); +COMMIT; + +save_master_pos; + +SELECT * FROM t1 ORDER BY a; + +# This will skip a begin event and the first INSERT of the +# transaction, and it should keep skipping until it has reached the +# transaction terminator. + +--echo **** On Slave **** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; +SELECT * FROM t1 ORDER BY a; + +# Testing with a non-transactional table in the transaction. This will +# log a ROLLBACK as a transaction terminator, which is a normal Query +# log event. + +--echo ==== Rollback of transaction with non-transactional change ==== + +--echo **** On Master **** +connection master; +DELETE FROM t1; +SET AUTOCOMMIT=1; + +--echo **** On Slave **** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; +disable_warnings; +BEGIN; +INSERT INTO t1 VALUES (1, ''); +INSERT INTO t2 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, ''); +ROLLBACK; + +BEGIN; +INSERT INTO t1 VALUES (4, ''); +INSERT INTO t2 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, ''); +ROLLBACK; +enable_warnings; + +save_master_pos; + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--echo **** On Slave **** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--echo ==== Cleanup ==== + +--echo **** On Master **** +connection master; +DROP TABLE t1, t2; +sync_slave_with_master; diff --git a/sql/slave.cc b/sql/slave.cc index c1b0d655bea..1375b7279c2 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3279,7 +3279,43 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) now the relay log starts with its Format_desc, has a Rotate etc). */ - DBUG_PRINT("info",("type_code=%d, server_id=%d",type_code,ev->server_id)); + DBUG_PRINT("info",("type_code: %d; server_id: %d; slave_skip_counter: %d", + type_code, ev->server_id, rli->slave_skip_counter)); + + /* + If the slave skip counter is positive, we still need to set the + OPTION_BEGIN flag correctly and not skip the log events that + start or end a transaction. If we do this, the slave will not + notice that it is inside a transaction, and happily start + executing from inside the transaction. + + Note that the code block below is strictly 5.0. + */ +#if MYSQL_VERSION_ID < 50100 + if (unlikely(rli->slave_skip_counter > 0)) + { + switch (type_code) + { + case QUERY_EVENT: + { + Query_log_event* const qev= (Query_log_event*) ev; + DBUG_PRINT("info", ("QUERY_EVENT { query: '%s', q_len: %u }", + qev->query, qev->q_len)); + if (memcmp("BEGIN", qev->query, qev->q_len+1) == 0) + thd->options|= OPTION_BEGIN; + else if (memcmp("COMMIT", qev->query, qev->q_len+1) == 0 || + memcmp("ROLLBACK", qev->query, qev->q_len+1) == 0) + thd->options&= ~OPTION_BEGIN; + } + break; + + case XID_EVENT: + DBUG_PRINT("info", ("XID_EVENT")); + thd->options&= ~OPTION_BEGIN; + break; + } + } +#endif if ((ev->server_id == (uint32) ::server_id && !replicate_same_server_id && @@ -3301,6 +3337,9 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) flush_relay_log_info(rli); } + DBUG_PRINT("info", ("thd->options: %s", + (thd->options & OPTION_BEGIN) ? "OPTION_BEGIN" : "")) + /* Protect against common user error of setting the counter to 1 instead of 2 while recovering from an insert which used auto_increment, @@ -3311,6 +3350,15 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) type_code == RAND_EVENT || type_code == USER_VAR_EVENT) && rli->slave_skip_counter == 1) && +#if MYSQL_VERSION_ID < 50100 + /* + Decrease the slave skip counter only if we are not inside + a transaction or the slave skip counter is more than + 1. The slave skip counter will be decreased from 1 to 0 + when reaching the final ROLLBACK, COMMIT, or XID_EVENT. + */ + (!(thd->options & OPTION_BEGIN) || rli->slave_skip_counter > 1) && +#endif /* The events from ourselves which have something to do with the relay log itself must be skipped, true, but they mustn't decrement @@ -3321,8 +3369,10 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) would not be skipped. */ !(ev->server_id == (uint32) ::server_id && - (type_code == ROTATE_EVENT || type_code == STOP_EVENT || - type_code == START_EVENT_V3 || type_code == FORMAT_DESCRIPTION_EVENT))) + (type_code == ROTATE_EVENT || + type_code == STOP_EVENT || + type_code == START_EVENT_V3 || + type_code == FORMAT_DESCRIPTION_EVENT))) --rli->slave_skip_counter; pthread_mutex_unlock(&rli->data_lock); delete ev; From 95f3db7be1b3425b47f34090f33c7eeb52f97703 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 29 Oct 2007 15:20:59 +0200 Subject: [PATCH 050/136] Bug #27571 asynchronousity in setting mysql_`query`::error and Query_log_event::error_code A query can perform completely having the local var error of mysql_$query zero, where $query in insert, update, delete, load, and be binlogged with error_code e.g KILLED_QUERY while there is no reason do to so. That can happen because Query_log_event consults thd->killed flag to evaluate error_code. Fixed with implementing a scheme suggested and partly implemented at time of bug@22725 work-on. error_status is cached immediatly after the control leaves the main rows-loop and that instance always corresponds to `error' the local of mysql_$query functions. The cached value is passed to Query_log_event constructor, not the default thd->killed which can be changed in between of the caching and the constructing. mysql-test/r/binlog_killed.result: results changed mysql-test/t/binlog_killed.test: Demonstrating that effective killing during rows-loop execution leads to the speficied actions: binlogging with the error for a query modified a not-transactional table or rolling back effects for transactional table; fixing possible non-determinism with ID when query_log_enabled; leave commented out tests for multi-update,delete due to another bug; removing an obsolete tests template; changing system rm to --remove_file. sql/log_event.cc: adding killed status arg sql/log_event.h: added killed status arg sql/sql_delete.cc: deploying the update part patch for delete, multi-delete sql/sql_insert.cc: deploying the update-part patch for insert..select sql/sql_load.cc: deploying the update-part patch for load data. simulation added. sql/sql_update.cc: Impementing the fix as described in the comments left by bug@22725. Also simulation of killing after the loop that would affect binlogging in the old code. mysql-test/t/binlog_killed_bug27571-master.opt: post rows-loop killing simulation's options mysql-test/t/binlog_killed_bug27571.test: Checking that if killing happens inbetween of the end of rows loop and recording into binlog that will not lead to recording any error incl the killed error. mysql-test/t/binlog_killed_simulate-master.opt: simulation options mysql-test/t/binlog_killed_simulate.test: tests for a query (update is choosen) being killed after the row-loop; load data killed within the loop - effective killed error in the event is gained. --- mysql-test/r/binlog_killed.result | 106 ++++++ mysql-test/t/binlog_killed.test | 333 ++++++++++-------- .../t/binlog_killed_bug27571-master.opt | 1 + mysql-test/t/binlog_killed_bug27571.test | 68 ++++ .../t/binlog_killed_simulate-master.opt | 1 + mysql-test/t/binlog_killed_simulate.test | 65 ++++ sql/log_event.cc | 11 +- sql/log_event.h | 10 +- sql/sql_delete.cc | 18 +- sql/sql_insert.cc | 3 +- sql/sql_load.cc | 26 +- sql/sql_update.cc | 70 ++-- 12 files changed, 509 insertions(+), 203 deletions(-) create mode 100644 mysql-test/t/binlog_killed_bug27571-master.opt create mode 100644 mysql-test/t/binlog_killed_bug27571.test create mode 100644 mysql-test/t/binlog_killed_simulate-master.opt create mode 100644 mysql-test/t/binlog_killed_simulate.test diff --git a/mysql-test/r/binlog_killed.result b/mysql-test/r/binlog_killed.result index ba4f38fb4c1..ddd80283eca 100644 --- a/mysql-test/r/binlog_killed.result +++ b/mysql-test/r/binlog_killed.result @@ -9,4 +9,110 @@ insert into t2 values (null, null), (null, get_lock("a", 10)); select @result /* must be zero either way */; @result 0 +delete from t1; +delete from t2; +insert into t1 values (1,1),(2,2); +begin; +update t1 set b=11 where a=2; +update t1 set b=b+10; +kill query ID; +rollback; +ERROR 70100: Query execution was interrupted +select * from t1 /* must be the same as before (1,1),(2,2) */; +a b +1 1 +2 2 +begin; +delete from t1 where a=2; +delete from t1 where a=2; +kill query ID; +rollback; +ERROR 70100: Query execution was interrupted +select * from t1 /* must be the same as before (1,1),(2,2) */; +a b +1 1 +2 2 +drop table if exists t4; +create table t4 (a int, b int) engine=innodb; +insert into t4 values (3, 3); +begin; +insert into t1 values (3, 3); +begin; +insert into t1 select * from t4 for update; +kill query ID; +rollback; +ERROR 70100: Query execution was interrupted +rollback; +select * from t1 /* must be the same as before (1,1),(2,2) */; +a b +1 1 +2 2 +drop table t4; +create function bug27563(n int) +RETURNS int(11) +DETERMINISTIC +begin +if n > 1 then +select get_lock("a", 10) into @a; +end if; +return n; +end| +delete from t2; +insert into t2 values (1,1), (2,2); +reset master; +select get_lock("a", 20); +get_lock("a", 20) +1 +update t2 set b=b + bug27563(b) order by a; +kill query ID; +ERROR 70100: Query execution was interrupted +select * from t2 /* must be (1,2), (2,2) */; +a b +1 2 +2 2 +show master status /* must have the update event more to FD */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 211 +select +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null +1 +select 0 /* must return 0 to mean the killed query is in */; +0 +0 +select RELEASE_LOCK("a"); +RELEASE_LOCK("a") +1 +delete from t2; +insert into t2 values (1,1), (2,2); +reset master; +select get_lock("a", 20); +get_lock("a", 20) +1 +delete from t2 where a=1 or a=bug27563(2) order by a; +kill query ID; +ERROR 70100: Query execution was interrupted +select * from t2 /* must be (1,2), (2,2) */; +a b +1 1 +2 2 +show master status /* must have the update event more to FD */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 98 +select +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null +1 +select 0 /* must return 0 to mean the killed query is in */; +0 +0 +select RELEASE_LOCK("a"); +RELEASE_LOCK("a") +1 +drop function bug27563; drop table t1,t2,t3; +end of the tests diff --git a/mysql-test/t/binlog_killed.test b/mysql-test/t/binlog_killed.test index 034895f17cb..0e35e46c845 100644 --- a/mysql-test/t/binlog_killed.test +++ b/mysql-test/t/binlog_killed.test @@ -55,194 +55,239 @@ enable_result_log; select @result /* must be zero either way */; -# the functions are either *insensitive* to killing or killing can cause -# strange problmes with the error propagation out of SF's stack -# Bug#27563, Bug#27565, BUG#24971 + +--remove_file $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog + # -# TODO: use if's block as regression test for the bugs or remove +# bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code # -if (0) -{ + +# checking that killing inside of select loops is safe as before +# killing after the loop can be only simulated - another test + +delete from t1; +delete from t2; +insert into t1 values (1,1),(2,2); +let $ID= `select connection_id()`; + +# +# simple update +# +connection con1; +begin; update t1 set b=11 where a=2; + +connection con2; +send update t1 set b=b+10; + +connection con1; +--replace_result $ID ID +eval kill query $ID; +rollback; + +connection con2; +--error ER_QUERY_INTERRUPTED +reap; +select * from t1 /* must be the same as before (1,1),(2,2) */; + +# +# multi update +# commented out as Bug #31807 multi-update,delete killing does not report with ER_QUERY_INTERRUPTED +# in the way +# +# connection con1; +# begin; update t1 set b=b+10; + +# connection con2; +# send update t1 as t_1,t1 as t_2 set t_1.b=11 where t_2.a=2; + +# connection con1; +# --replace_result $ID ID +# eval kill query $ID; +# rollback; + +# disable_abort_on_error; + +# connection con2; +# --error HY000,ER_QUERY_INTERRUPTED +# reap; +# select * from t1 /* must be the same as before (1,1),(2,2) */; + +# enable_abort_on_error; +# +# simple delete +# +connection con1; +begin; delete from t1 where a=2; + +connection con2; +send delete from t1 where a=2; + +connection con1; +--replace_result $ID ID +eval kill query $ID; +rollback; + +connection con2; +--error ER_QUERY_INTERRUPTED +reap; +select * from t1 /* must be the same as before (1,1),(2,2) */; + +# +# multi delete +# the same as for multi-update +# +# connection con1; +# begin; delete from t1 where a=2; + +# connection con2; +# send delete t1 from t1 where t1.a=2; + +# connection con1; +# --replace_result $ID ID +# eval kill query $ID; +# rollback; + +# connection con2; +# --error 0,ER_QUERY_INTERRUPTED +# reap; +# select * from t1 /* must be the same as before (1,1),(2,2) */; +# +# insert select +# +connection con1; +--disable_warnings +drop table if exists t4; +--enable_warnings +create table t4 (a int, b int) engine=innodb; +insert into t4 values (3, 3); +begin; insert into t1 values (3, 3); + +connection con2; +begin; +send insert into t1 select * from t4 for update; + +connection con1; +--replace_result $ID ID +eval kill query $ID; +rollback; + +connection con2; +--error ER_QUERY_INTERRUPTED +reap; +rollback; +select * from t1 /* must be the same as before (1,1),(2,2) */; + +drop table t4; # cleanup for the sub-case + +### +## non-ta table case: killing must be recorded in binlog +### delimiter |; -create function bug27563() +create function bug27563(n int) RETURNS int(11) DETERMINISTIC begin - select get_lock("a", 10) into @a; - return 1; + if n > 1 then + select get_lock("a", 10) into @a; + end if; + return n; end| delimiter ;| -# the function is sensitive to killing requiring innodb though with wrong client error -# TO FIX in BUG#27565; TODO: remove --error 1105 afterwards -delimiter |; -create function bug27565() -RETURNS int(11) -DETERMINISTIC -begin - select a from t1 where a=1 into @a for update; - return 1; -end| -delimiter ;| +# +# update +# +delete from t2; +insert into t2 values (1,1), (2,2); reset master; - - -### ta table case: killing causes rollback - -# A. autocommit ON connection con1; select get_lock("a", 20); connection con2; let $ID= `select connection_id()`; -send insert into t1 values (bug27563(),1); +send update t2 set b=b + bug27563(b) order by a; connection con1; +--replace_result $ID ID eval kill query $ID; connection con2; -# todo (re-record test): after bugs 27563,27565 got fixed affected rows will report zero ---enable_info -# todo: remove 0 return after fixing Bug#27563 ---error 0,ER_QUERY_INTERRUPTED -reap; ### pb: wrong error ---disable_info -###--replace_column 2 # 5 # -### show binlog events from 98 /* nothing in binlog unless Bug#27563 */; -show master status /* must be only FD event unless Bug#27563 */; -select count(*) from t1 /* must be zero unless Bug#27563 */; - -# M. multi-statement-ta -connection con2; -let $ID= `select connection_id()`; -begin; -send insert into t1 values (bug27563(),1); - -connection con1; -eval kill query $ID; -connection con2; -# todo (re-record test): after bugs 27563,27565 got fixed affected rows will report zero ---enable_info -# todo: remove 0 return after fixing Bug#27563 ---error 0,ER_QUERY_INTERRUPTED +--error ER_QUERY_INTERRUPTED reap; ---disable_info -select count(*) from t1 /* must be zero unless Bug#27563 */; -commit; +select * from t2 /* must be (1,2), (2,2) */; +show master status /* must have the update event more to FD */; +# a proof the query is binlogged with an error -### non-ta table case: killing must be recorded in binlog - -reset master; - -connection con2; -let $ID= `select connection_id()`; -send insert into t2 values (bug27563(),1); - -connection con1; -eval kill query $ID; - -connection con2; -# todo: remove 0 return after fixing Bug#27563 ---error 0,ER_QUERY_INTERRUPTED -reap; -select count(*) from t2 /* must be one */; -#show binlog events from 98 /* must have the insert on non-ta table */; -show master status /* must have the insert event more to FD */; -# the value of the error flag of KILLED_QUERY is tested further +--exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval select +(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +let $error_code= `select @a like "%#%error_code=0%" /* must return 0*/`; +eval select $error_code /* must return 0 to mean the killed query is in */; +# cleanup for the sub-case connection con1; select RELEASE_LOCK("a"); +--remove_file $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog -### test with effective killing of SF() - -delete from t1; -delete from t2; -insert into t1 values (1,1); -insert into t2 values (1,1); - -# -# Bug#27565 -# test where KILL is propagated as error to the top level -# still another bug with the error message to the user -# todo: fix reexecute the result file after fixing -# -begin; update t1 set b=0 where a=1; - -connection con2; -let $ID= `select connection_id()`; -send update t2 set b=bug27565()-1 where a=1; - -connection con1; -eval kill query $ID; -commit; - -connection con2; -# todo: fix Bug #27565 killed query of SF() is not reported correctly and -# remove 1105 (wrong) -#--error ER_QUERY_INTERRUPTED ---error 1105,ER_QUERY_INTERRUPTED -reap; ### pb: wrong error -select * from t1 /* must be: (1,0) */; -select * from t2 /* must be as before: (1,1) */; - -## bug#22725 with effective and propagating killing # -# top-level ta-table -connection con1; -delete from t3; -reset master; -begin; update t1 set b=0 where a=1; +# delete +# -connection con2; -let $ID= `select connection_id()`; -# the query won't perform completely since the function gets interrupted -send insert into t3 values (0,0),(1,bug27565()); - -connection con1; -eval kill query $ID; -rollback; - -connection con2; -# todo: fix Bug #27565 killed query of SF() is not reported correctly and -# remove 1105 (wrong) -#--error ER_QUERY_INTERRUPTED ---error 1105,ER_QUERY_INTERRUPTED -reap; ### pb: wrong error -select count(*) from t3 /* must be zero */; -show master status /* nothing in binlog */; - -# top-level non-ta-table -connection con1; delete from t2; +insert into t2 values (1,1), (2,2); reset master; -begin; update t1 set b=0 where a=1; +connection con1; +select get_lock("a", 20); connection con2; let $ID= `select connection_id()`; -# the query won't perform completely since the function gets intrurrupted -send insert into t2 values (0,0),(1,bug27565()) /* non-ta t2 */; +send delete from t2 where a=1 or a=bug27563(2) order by a; connection con1; +--replace_result $ID ID eval kill query $ID; -rollback; connection con2; -# todo: fix Bug #27565 killed query of SF() is not reported correctly and -# remove 1105 (wrong) -#--error ER_QUERY_INTERRUPTED ---error 1105,ER_QUERY_INTERRUPTED -reap; ### pb: wrong error +--error ER_QUERY_INTERRUPTED +reap; +select * from t2 /* must be (1,2), (2,2) */; +show master status /* must have the update event more to FD */; -select count(*) from t2 /* count must be one */; -show master status /* insert into non-ta must be in binlog */; +# a proof the query is binlogged with an error + +--exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval select +(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +let $error_code= `select @a like "%#%error_code=0%" /* must return 0*/`; +eval select $error_code /* must return 0 to mean the killed query is in */; + +# cleanup for the sub-case +connection con1; +select RELEASE_LOCK("a"); +--remove_file $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog + +# +# load data - see simulation tests +# + + +# bug#27571 cleanup drop function bug27563; -drop function bug27565; -} -system rm $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog ; + +# +# common cleanup +# drop table t1,t2,t3; +--echo end of the tests diff --git a/mysql-test/t/binlog_killed_bug27571-master.opt b/mysql-test/t/binlog_killed_bug27571-master.opt new file mode 100644 index 00000000000..d269cf246d5 --- /dev/null +++ b/mysql-test/t/binlog_killed_bug27571-master.opt @@ -0,0 +1 @@ +--loose-debug=d,stop_after_row_loop_done diff --git a/mysql-test/t/binlog_killed_bug27571.test b/mysql-test/t/binlog_killed_bug27571.test new file mode 100644 index 00000000000..6fa3c6d256f --- /dev/null +++ b/mysql-test/t/binlog_killed_bug27571.test @@ -0,0 +1,68 @@ +--source include/have_innodb.inc +--source include/not_embedded.inc +--source include/have_log_bin.inc + +# +# bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code +# +# Checking that if killing happens inbetween of the end of rows loop and +# recording into binlog that will not lead to recording any error incl +# the killed error. +# + +connect (looser, localhost, root,,); +connect (killer, localhost, root,,); + +create table t1 (a int auto_increment, b int, PRIMARY KEY (a)) ENGINE=InnoDB; + +delete from t1; +insert into t1 values (1,1),(2,2); +reset master; + +connection looser; +let $ID= `select connection_id()`; +send update t1 set b=11 where a=2; + +connection killer; +sleep 1; # let 1 second for the update to get to the sleeping point +--replace_result $ID ID +eval kill query $ID; + +connection looser; +--error 0 # zero even though the query must be got killed while it was sleepin for 5 secs +reap; + +# +# this is another possible artifact. The killed error was not caught +# as that is logical as killing was not effective: +# data are ok and well as binlog event is without killed error (further). +# The reason of the following `show error' is to prove that +# killing simulation was effective +# +show errors; + +connection killer; + +# nothing is rolled back + +select * from t1 where a=2 /* must be 11 */; + +# a proof the query is binlogged with an error + +--exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval select +(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +let $error_code= `select @a like "%#%error_code=0%"`; + +eval select $error_code /* must return 1*/; + +# +# cleanup +# + +drop table t1; + +--echo end of the tests diff --git a/mysql-test/t/binlog_killed_simulate-master.opt b/mysql-test/t/binlog_killed_simulate-master.opt new file mode 100644 index 00000000000..90c70ecee29 --- /dev/null +++ b/mysql-test/t/binlog_killed_simulate-master.opt @@ -0,0 +1 @@ +--loose-debug=d,simulate_kill_bug27571 diff --git a/mysql-test/t/binlog_killed_simulate.test b/mysql-test/t/binlog_killed_simulate.test new file mode 100644 index 00000000000..d6234d1bfd7 --- /dev/null +++ b/mysql-test/t/binlog_killed_simulate.test @@ -0,0 +1,65 @@ +# +# bug#27571 asynchronous setting mysql_$query()'s local error and +# Query_log_event::error_code +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +# +# Checking that killing upon successful row-loop does not affect binlogging +# + +create table t1 (a int) engine=MyISAM; +insert into t1 set a=1; +reset master; + +update t1 set a=2 /* will be "killed" after work has been done */; + +# a proof the query is binlogged with no error + +--exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval select +(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +let $error_code= `select @a like "%#%error_code=0%" /* must return 1 */`; +eval select $error_code /* must return 1 as query completed before got killed*/; + +# cleanup for the sub-case +system rm $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog; + + +# +# Checking that killing inside of row-loop for LOAD DATA into +# non-transactional table affects binlogging +# + +create table t2 (a int, b int) ENGINE=MyISAM; +reset master; +--error ER_QUERY_INTERRUPTED +load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */; + + +# a proof the query is binlogged with an error + +source include/show_binlog_events.inc; + +--exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval select +(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +let $error_code= `select @a like "%#%error_code=0%" /* must return 0*/`; +eval select $error_code /* must return 0 to mean the killed query is in */; + +# cleanup for the sub-case +system rm $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog; + + +drop table t1,t2; + +--echo end of the tests diff --git a/sql/log_event.cc b/sql/log_event.cc index 3899e772bf8..da616adbb09 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4994,12 +4994,13 @@ int Begin_load_query_log_event::get_create_or_append() const #ifndef MYSQL_CLIENT Execute_load_query_log_event:: Execute_load_query_log_event(THD* thd_arg, const char* query_arg, - ulong query_length_arg, uint fn_pos_start_arg, - uint fn_pos_end_arg, - enum_load_dup_handling dup_handling_arg, - bool using_trans, bool suppress_use): + ulong query_length_arg, uint fn_pos_start_arg, + uint fn_pos_end_arg, + enum_load_dup_handling dup_handling_arg, + bool using_trans, bool suppress_use, + THD::killed_state killed_err_arg): Query_log_event(thd_arg, query_arg, query_length_arg, using_trans, - suppress_use), + suppress_use, killed_err_arg), file_id(thd_arg->file_id), fn_pos_start(fn_pos_start_arg), fn_pos_end(fn_pos_end_arg), dup_handling(dup_handling_arg) { diff --git a/sql/log_event.h b/sql/log_event.h index 04aac5d08fc..5b065a33dd1 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1619,10 +1619,12 @@ public: #ifndef MYSQL_CLIENT Execute_load_query_log_event(THD* thd, const char* query_arg, - ulong query_length, uint fn_pos_start_arg, - uint fn_pos_end_arg, - enum_load_dup_handling dup_handling_arg, - bool using_trans, bool suppress_use); + ulong query_length, uint fn_pos_start_arg, + uint fn_pos_end_arg, + enum_load_dup_handling dup_handling_arg, + bool using_trans, bool suppress_use, + THD::killed_state + killed_err_arg= THD::KILLED_NO_VALUE); #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol); int exec_event(struct st_relay_log_info* rli); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index add37c8c552..a28a39a769d 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -38,6 +38,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ha_rows deleted; uint usable_index= MAX_KEY; SELECT_LEX *select_lex= &thd->lex->select_lex; + THD::killed_state killed_status= THD::NOT_KILLED; DBUG_ENTER("mysql_delete"); if (open_and_lock_tables(thd, table_list)) @@ -280,8 +281,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, else table->file->unlock_row(); // Row failed selection, release lock on it } - if (thd->killed && !error) - error= 1; // Aborted + killed_status= thd->killed; + error= (killed_status == THD::NOT_KILLED)? error : 1; thd->proc_info="end"; end_read_record(&info); free_io_cache(table); // Will not do any harm @@ -326,7 +327,7 @@ cleanup: if (error < 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); + transactional_table, FALSE, killed_status); if (mysql_bin_log.write(&qinfo) && transactional_table) error=1; } @@ -729,7 +730,8 @@ void multi_delete::send_error(uint errcode,const char *err) } thd->transaction.all.modified_non_trans_table= true; } - DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); + DBUG_ASSERT(!normal_tables || !deleted || + thd->transaction.stmt.modified_non_trans_table); DBUG_VOID_RETURN; } @@ -817,6 +819,7 @@ int multi_delete::do_deletes() bool multi_delete::send_eof() { + THD::killed_state killed_status= THD::NOT_KILLED; thd->proc_info="deleting from reference tables"; /* Does deletes for the last n - 1 tables, returns 0 if ok */ @@ -824,7 +827,7 @@ bool multi_delete::send_eof() /* compute a total error to know if something failed */ local_error= local_error || error; - + killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed; /* reset used flags */ thd->proc_info="end"; @@ -836,7 +839,8 @@ bool multi_delete::send_eof() { query_cache_invalidate3(thd, delete_tables, 1); } - DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); + DBUG_ASSERT(!normal_tables || !deleted || + thd->transaction.stmt.modified_non_trans_table); if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table) { if (mysql_bin_log.is_open()) @@ -844,7 +848,7 @@ bool multi_delete::send_eof() if (local_error == 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); + transactional_tables, FALSE, killed_status); if (mysql_bin_log.write(&qinfo) && !normal_tables) local_error=1; // Log write failed: roll back the SQL statement } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index d33e8509eaf..c5f6575b756 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2936,6 +2936,7 @@ bool select_insert::send_eof() { int error, error2; bool changed, transactional_table= table->file->has_transactions(); + THD::killed_state killed_status= thd->killed; DBUG_ENTER("select_insert::send_eof"); error= (!thd->prelocked_mode) ? table->file->end_bulk_insert():0; @@ -2964,7 +2965,7 @@ bool select_insert::send_eof() if (!error) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); + transactional_table, FALSE, killed_status); mysql_bin_log.write(&qinfo); } if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error) diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 0dc02ac4a68..d687ceff393 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -85,7 +85,8 @@ static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, #ifndef EMBEDDED_LIBRARY static bool write_execute_load_query_log_event(THD *thd, bool duplicates, bool ignore, - bool transactional_table); + bool transactional_table, + THD::killed_state killed_status); #endif /* EMBEDDED_LIBRARY */ /* @@ -135,6 +136,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, char *tdb= thd->db ? thd->db : db; // Result is never null ulong skip_lines= ex->skip_lines; bool transactional_table; + THD::killed_state killed_status= THD::NOT_KILLED; DBUG_ENTER("mysql_load"); #ifdef EMBEDDED_LIBRARY @@ -404,7 +406,16 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, free_blobs(table); /* if pack_blob was used */ table->copy_blobs=0; thd->count_cuted_fields= CHECK_FIELD_IGNORE; - + /* + simulated killing in the middle of per-row loop + must be effective for binlogging + */ + DBUG_EXECUTE_IF("simulate_kill_bug27571", + { + error=1; + thd->killed= THD::KILL_QUERY; + };); + killed_status= (error == 0)? THD::NOT_KILLED : thd->killed; /* We must invalidate the table in query cache before binlog writing and ha_autocommit_... @@ -446,7 +457,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, { if (thd->transaction.stmt.modified_non_trans_table) write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table); + ignore, transactional_table, + killed_status); else { Delete_file_log_event d(thd, db, transactional_table); @@ -477,7 +489,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, read_info.end_io_cache(); if (lf_info.wrote_create_file) write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table); + ignore, transactional_table, + killed_status); } #endif /*!EMBEDDED_LIBRARY*/ if (transactional_table) @@ -504,7 +517,8 @@ err: /* 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) + bool transactional_table, + THD::killed_state killed_err_arg) { Execute_load_query_log_event e(thd, thd->query, thd->query_length, @@ -512,7 +526,7 @@ static bool write_execute_load_query_log_event(THD *thd, (char*)thd->lex->fname_end - (char*)thd->query, (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE : (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR), - transactional_table, FALSE); + transactional_table, FALSE, killed_err_arg); return mysql_bin_log.write(&e); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index f3695976508..14c34b6e0f1 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -134,6 +134,7 @@ int mysql_update(THD *thd, SELECT_LEX *select_lex= &thd->lex->select_lex; bool need_reopen; List all_fields; + THD::killed_state killed_status= THD::NOT_KILLED; DBUG_ENTER("mysql_update"); LINT_INIT(timestamp_query_id); @@ -519,43 +520,26 @@ int mysql_update(THD *thd, table->file->unlock_row(); thd->row_count++; } + /* + Caching the killed status to pass as the arg to query event constuctor; + The cached value can not change whereas the killed status can + (externally) since this point and change of the latter won't affect + binlogging. + It's assumed that if an error was set in combination with an effective + killed status then the error is due to killing. + */ + killed_status= thd->killed; // get the status of the volatile + // simulated killing after the loop must be ineffective for binlogging + DBUG_EXECUTE_IF("simulate_kill_bug27571", + { + thd->killed= THD::KILL_QUERY; + };); + error= (killed_status == THD::NOT_KILLED)? error : 1; + if (!transactional_table && updated > 0) thd->transaction.stmt.modified_non_trans_table= TRUE; - - /* - todo bug#27571: to avoid asynchronization of `error' and - `error_code' of binlog event constructor - - The concept, which is a bit different for insert(!), is to - replace `error' assignment with the following lines - - killed_status= thd->killed; // get the status of the volatile - - Notice: thd->killed is type of "state" whereas the lhs has - "status" the suffix which translates according to WordNet: a state - at a particular time - at the time of the end of per-row loop in - our case. Binlogging ops are conducted with the status. - - error= (killed_status == THD::NOT_KILLED)? error : 1; - - which applies to most mysql_$query functions. - Event's constructor will accept `killed_status' as an argument: - - Query_log_event qinfo(..., killed_status); - - thd->killed might be changed after killed_status had got cached and this - won't affect binlogging event but other effects remain. - - Open issue: In a case the error happened not because of KILLED - - and then KILLED was caught later still within the loop - we shall - do something to avoid binlogging of incorrect ER_SERVER_SHUTDOWN - error_code. - */ - - if (thd->killed && !error) - error= 1; // Aborted end_read_record(&info); free_io_cache(table); // If ORDER BY delete select; @@ -587,7 +571,7 @@ int mysql_update(THD *thd, if (error < 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); + transactional_table, FALSE, killed_status); if (mysql_bin_log.write(&qinfo) && transactional_table) error=1; // Rollback update } @@ -1522,6 +1506,11 @@ void multi_update::send_error(uint errcode,const char *err) */ if (mysql_bin_log.is_open()) { + /* + THD::killed status might not have been set ON at time of an error + got caught and if happens later the killed error is written + into repl event. + */ Query_log_event qinfo(thd, thd->query, thd->query_length, transactional_tables, FALSE); mysql_bin_log.write(&qinfo); @@ -1709,10 +1698,19 @@ err2: bool multi_update::send_eof() { char buff[STRING_BUFFER_USUAL_SIZE]; + THD::killed_state killed_status= THD::NOT_KILLED; thd->proc_info="updating reference tables"; - /* Does updates for the last n - 1 tables, returns 0 if ok */ + /* + Does updates for the last n - 1 tables, returns 0 if ok; + error takes into account killed status gained in do_updates() + */ int local_error = (table_count) ? do_updates(0) : 0; + /* + if local_error is not set ON until after do_updates() then + later carried out killing should not affect binlogging. + */ + killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed; thd->proc_info= "end"; /* We must invalidate the query cache before binlog writing and @@ -1740,7 +1738,7 @@ bool multi_update::send_eof() if (local_error == 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); + transactional_tables, FALSE, killed_status); if (mysql_bin_log.write(&qinfo) && trans_safe) local_error= 1; // Rollback update } From 356bdcb7c47e9fc848281687f725b1783194594a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 30 Oct 2007 13:49:42 +0200 Subject: [PATCH 051/136] Manual merge 5.0-rpl -> 5.1-rpl. involved bug#12691, bug#27571 mysql-test/suite/rpl/r/rpl_sp_effects.result: results changed sql/slave.cc: pended manual merge done (mats) sql/sql_delete.cc: manual merge sql/sql_insert.cc: manual merge sql/sql_load.cc: manual merge sql/sql_update.cc: manual merge. --- mysql-test/suite/rpl/r/rpl_sp_effects.result | 41 ++++++ sql/slave.cc | 79 ++-------- sql/sql_delete.cc | 25 +--- sql/sql_insert.cc | 26 +--- sql/sql_load.cc | 49 +------ sql/sql_update.cc | 145 ++----------------- 6 files changed, 71 insertions(+), 294 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_sp_effects.result b/mysql-test/suite/rpl/r/rpl_sp_effects.result index c2c44b06972..a39d189aa3a 100644 --- a/mysql-test/suite/rpl/r/rpl_sp_effects.result +++ b/mysql-test/suite/rpl/r/rpl_sp_effects.result @@ -235,4 +235,45 @@ drop table t1; drop function f1; drop function f2; drop procedure p1; +create table t2 (b BIT(7)); +create procedure sp_bug26199(bitvalue BIT(7)) +begin +insert into t2 set b = bitvalue; +end // +create function sf_bug26199(b BIT(7)) returns int +begin +insert into t2 values(b); +return 0; +end// +call sp_bug26199(b'1110'); +call sp_bug26199('\0'); +select sf_bug26199(b'1111111'); +sf_bug26199(b'1111111') +0 +select sf_bug26199(b'101111111'); +sf_bug26199(b'101111111') +0 +Warnings: +Warning 1264 Out of range value for column 'b' at row 1 +select sf_bug26199('\''); +sf_bug26199('\'') +0 +select hex(b) from t2; +hex(b) +E +0 +7F +7F +27 +select hex(b) from t2; +hex(b) +E +0 +7F +7F +27 +drop table t2; +drop procedure sp_bug26199; +drop function sf_bug26199; SET GLOBAL log_bin_trust_function_creators = 0; +end of the tests diff --git a/sql/slave.cc b/sql/slave.cc index a3ac0c2f34f..9ea7732aa92 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1804,70 +1804,6 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) int const type_code= ev->get_type_code(); int exec_res= 0; - /* - */ - -<<<<<<< gca sql/slave.cc 1.241.1.61 - DBUG_PRINT("info",("type_code=%d, server_id=%d",type_code,ev->server_id)); - - if ((ev->server_id == (uint32) ::server_id && - !replicate_same_server_id && - type_code != FORMAT_DESCRIPTION_EVENT) || - (rli->slave_skip_counter && - type_code != ROTATE_EVENT && type_code != STOP_EVENT && - type_code != START_EVENT_V3 && type_code!= FORMAT_DESCRIPTION_EVENT)) - { - DBUG_PRINT("info", ("event skipped")); - if (thd->options & OPTION_BEGIN) - rli->inc_event_relay_log_pos(); - else - { - rli->inc_group_relay_log_pos((type_code == ROTATE_EVENT || - type_code == STOP_EVENT || - type_code == FORMAT_DESCRIPTION_EVENT) ? - LL(0) : ev->log_pos, - 1/* skip lock*/); - flush_relay_log_info(rli); - } - - /* - Protect against common user error of setting the counter to 1 - instead of 2 while recovering from an insert which used auto_increment, - rand or user var. - */ - if (rli->slave_skip_counter && - !((type_code == INTVAR_EVENT || - type_code == RAND_EVENT || - type_code == USER_VAR_EVENT) && - rli->slave_skip_counter == 1) && - /* - The events from ourselves which have something to do with the relay - log itself must be skipped, true, but they mustn't decrement - rli->slave_skip_counter, because the user is supposed to not see - these events (they are not in the master's binlog) and if we - decremented, START SLAVE would for example decrement when it sees - the Rotate, so the event which the user probably wanted to skip - would not be skipped. - */ - !(ev->server_id == (uint32) ::server_id && - (type_code == ROTATE_EVENT || type_code == STOP_EVENT || - type_code == START_EVENT_V3 || type_code == FORMAT_DESCRIPTION_EVENT))) - --rli->slave_skip_counter; - pthread_mutex_unlock(&rli->data_lock); - delete ev; - return 0; // avoid infinite update loops - } - pthread_mutex_unlock(&rli->data_lock); -<<<<<<< local sql/slave.cc 1.321 - DBUG_PRINT("exec_event",("%s(type_code: %d; server_id: %d)", - ev->get_type_str(), type_code, ev->server_id)); - DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu", - FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT), - FLAGSTR(thd->options, OPTION_BEGIN), - rli->last_event_start_time)); - - - /* Execute the event to change the database and update the binary log coordinates, but first we set some data that is needed for @@ -1891,10 +1827,15 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) log (remember that now the relay log starts with its Format_desc, has a Rotate etc). */ -<<<<<<< remote sql/slave.cc 1.241.1.62 + DBUG_PRINT("info",("type_code: %d; server_id: %d; slave_skip_counter: %d", type_code, ev->server_id, rli->slave_skip_counter)); + DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu", + FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT), + FLAGSTR(thd->options, OPTION_BEGIN), + rli->last_event_start_time)); + /* If the slave skip counter is positive, we still need to set the OPTION_BEGIN flag correctly and not skip the log events that @@ -1951,7 +1892,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) } DBUG_PRINT("info", ("thd->options: %s", - (thd->options & OPTION_BEGIN) ? "OPTION_BEGIN" : "")) + (thd->options & OPTION_BEGIN) ? "OPTION_BEGIN" : "")); /* Protect against common user error of setting the counter to 1 @@ -1991,8 +1932,6 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) delete ev; return 0; // avoid infinite update loops } - pthread_mutex_unlock(&rli->data_lock); ->>>>>>> thd->server_id = ev->server_id; // use the original server id for logging thd->set_time(); // time the query @@ -2132,7 +2071,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) non-transient error, the slave will stop with an error. */ rli->trans_retries= 0; // restart from fresh - DBUG_PRINT("info", ("Resetting retry counter, rli->trans_retries: %d", + DBUG_PRINT("info", ("Resetting retry counter, rli->trans_retries: %lu", rli->trans_retries)); } } @@ -2622,7 +2561,7 @@ pthread_handler_t handle_slave_sql(void *arg) rli->ignore_log_space_limit= 0; pthread_mutex_unlock(&rli->log_space_lock); rli->trans_retries= 0; // start from "no error" - DBUG_PRINT("info", ("rli->trans_retries: %d", rli->trans_retries)); + DBUG_PRINT("info", ("rli->trans_retries: %lu", rli->trans_retries)); if (init_relay_log_pos(rli, rli->group_relay_log_name, diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 33d19852371..81bfaadd4ce 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -352,12 +352,6 @@ cleanup: { if (error < 0) thd->clear_error(); -<<<<<<< gca sql/sql_delete.cc 1.144.1.57 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); - if (mysql_bin_log.write(&qinfo) && transactional_table) -<<<<<<< local sql/sql_delete.cc 1.230 - /* [binlog]: If 'handler::delete_all_rows()' was called and the storage engine does not inject the rows itself, we replicate @@ -366,15 +360,10 @@ cleanup: */ int log_result= thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - transactional_table, FALSE); + transactional_table, FALSE, killed_status); if (log_result && transactional_table) { -<<<<<<< remote sql/sql_delete.cc 1.144.1.58 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE, killed_status); - if (mysql_bin_log.write(&qinfo) && transactional_table) ->>>>>>> error=1; } } @@ -902,21 +891,11 @@ bool multi_delete::send_eof() { if (local_error == 0) thd->clear_error(); -<<<<<<< gca sql/sql_delete.cc 1.144.1.57 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); - if (mysql_bin_log.write(&qinfo) && !normal_tables) -<<<<<<< local sql/sql_delete.cc 1.230 if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - transactional_tables, FALSE) && + transactional_tables, FALSE, killed_status) && !normal_tables) { -<<<<<<< remote sql/sql_delete.cc 1.144.1.58 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE, killed_status); - if (mysql_bin_log.write(&qinfo) && !normal_tables) ->>>>>>> local_error=1; // Log write failed: roll back the SQL statement } } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index a631a82be1e..2f255b82fde 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3084,19 +3084,11 @@ void select_insert::send_error(uint errcode,const char *err) bool select_insert::send_eof() { -<<<<<<< gca sql/sql_insert.cc 1.146.1.105 - int error, error2; - bool changed, transactional_table= table->file->has_transactions(); -<<<<<<< local sql/sql_insert.cc 1.300 int error; bool const trans_table= table->file->has_transactions(); ulonglong id; bool changed; -<<<<<<< remote sql/sql_insert.cc 1.146.1.106 - int error, error2; - bool changed, transactional_table= table->file->has_transactions(); THD::killed_state killed_status= thd->killed; ->>>>>>> DBUG_ENTER("select_insert::send_eof"); DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'", trans_table, table->file->table_type())); @@ -3129,17 +3121,9 @@ bool select_insert::send_eof() { if (!error) thd->clear_error(); -<<<<<<< gca sql/sql_insert.cc 1.146.1.105 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); - mysql_bin_log.write(&qinfo); - } - if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error) - error=error2; -<<<<<<< local sql/sql_insert.cc 1.300 thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - trans_table, FALSE); + trans_table, FALSE, killed_status); } /* We will call ha_autocommit_or_rollback() also for @@ -3155,14 +3139,6 @@ bool select_insert::send_eof() } table->file->ha_release_auto_increment(); -<<<<<<< remote sql/sql_insert.cc 1.146.1.106 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE, killed_status); - mysql_bin_log.write(&qinfo); - } - if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error) - error=error2; ->>>>>>> if (error) { table->file->print_error(error,MYF(0)); diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 3a4df7ccc9b..c96fbb80b0c 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -430,12 +430,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (mysql_bin_log.is_open()) { { -<<<<<<< gca sql/sql_load.cc 1.78.1.39 - if (thd->transaction.stmt.modified_non_trans_table) - write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table); - else -<<<<<<< local sql/sql_load.cc 1.131 /* Make sure last block (the one which caused the error) gets logged. This is needed because otherwise after write of (to @@ -461,17 +455,11 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, read_info.end_io_cache(); /* If the file was not empty, wrote_create_file is true */ if (lf_info.wrote_create_file) -<<<<<<< remote sql/sql_load.cc 1.78.1.40 - if (thd->transaction.stmt.modified_non_trans_table) - write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table, - killed_status); - else ->>>>>>> { if (thd->transaction.stmt.modified_non_trans_table) write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table); + ignore, transactional_table, + killed_status); else { Delete_file_log_event d(thd, db, transactional_table); @@ -497,16 +485,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (mysql_bin_log.is_open()) { /* -<<<<<<< gca sql/sql_load.cc 1.78.1.39 - As already explained above, we need to call end_io_cache() or the last - block will be logged only after Execute_load_query_log_event (which is - wrong), when read_info is destroyed. - */ - read_info.end_io_cache(); - if (lf_info.wrote_create_file) - write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table); -<<<<<<< local sql/sql_load.cc 1.131 We need to do the job that is normally done inside binlog_query() here, which is to ensure that the pending event is written before tables are unlocked and before any other @@ -526,21 +504,10 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, read_info.end_io_cache(); if (lf_info.wrote_create_file) { - write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table); + write_execute_load_query_log_event(thd, handle_duplicates, ignore, + transactional_table,killed_status); } } -<<<<<<< remote sql/sql_load.cc 1.78.1.40 - As already explained above, we need to call end_io_cache() or the last - block will be logged only after Execute_load_query_log_event (which is - wrong), when read_info is destroyed. - */ - read_info.end_io_cache(); - if (lf_info.wrote_create_file) - write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table, - killed_status); ->>>>>>> } #endif /*!EMBEDDED_LIBRARY*/ if (transactional_table) @@ -577,14 +544,8 @@ static bool write_execute_load_query_log_event(THD *thd, (char*)thd->lex->fname_end - (char*)thd->query, (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE : (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR), -<<<<<<< gca sql/sql_load.cc 1.78.1.39 - transactional_table, FALSE); -<<<<<<< local sql/sql_load.cc 1.131 - transactional_table, FALSE); - e.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F; -<<<<<<< remote sql/sql_load.cc 1.78.1.40 transactional_table, FALSE, killed_err_arg); ->>>>>>> + e.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F; return mysql_bin_log.write(&e); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index f07437f044f..6f7719b5127 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -200,18 +200,10 @@ int mysql_update(THD *thd, SQL_SELECT *select; READ_RECORD info; SELECT_LEX *select_lex= &thd->lex->select_lex; -<<<<<<< gca sql/sql_update.cc 1.154.2.70 - bool need_reopen; - List all_fields; -<<<<<<< local sql/sql_update.cc 1.258 bool need_reopen; ulonglong id; List all_fields; -<<<<<<< remote sql/sql_update.cc 1.154.2.71 - bool need_reopen; - List all_fields; THD::killed_state killed_status= THD::NOT_KILLED; ->>>>>>> DBUG_ENTER("mysql_update"); for ( ; ; ) @@ -722,10 +714,7 @@ int mysql_update(THD *thd, table->file->unlock_row(); thd->row_count++; } -<<<<<<< gca sql/sql_update.cc 1.154.2.70 -<<<<<<< local sql/sql_update.cc 1.258 dup_key_found= 0; -<<<<<<< remote sql/sql_update.cc 1.154.2.71 /* Caching the killed status to pass as the arg to query event constuctor; The cached value can not change whereas the killed status can @@ -742,81 +731,9 @@ int mysql_update(THD *thd, };); error= (killed_status == THD::NOT_KILLED)? error : 1; ->>>>>>> - - if (!transactional_table && updated > 0) - thd->transaction.stmt.modified_non_trans_table= TRUE; - -<<<<<<< gca sql/sql_update.cc 1.154.2.70 - - /* - todo bug#27571: to avoid asynchronization of `error' and - `error_code' of binlog event constructor - - The concept, which is a bit different for insert(!), is to - replace `error' assignment with the following lines - - killed_status= thd->killed; // get the status of the volatile - - Notice: thd->killed is type of "state" whereas the lhs has - "status" the suffix which translates according to WordNet: a state - at a particular time - at the time of the end of per-row loop in - our case. Binlogging ops are conducted with the status. - - error= (killed_status == THD::NOT_KILLED)? error : 1; - - which applies to most mysql_$query functions. - Event's constructor will accept `killed_status' as an argument: - - Query_log_event qinfo(..., killed_status); - - thd->killed might be changed after killed_status had got cached and this - won't affect binlogging event but other effects remain. - - Open issue: In a case the error happened not because of KILLED - - and then KILLED was caught later still within the loop - we shall - do something to avoid binlogging of incorrect ER_SERVER_SHUTDOWN - error_code. - */ - - if (thd->killed && !error) - error= 1; // Aborted -<<<<<<< local sql/sql_update.cc 1.258 - - /* - todo bug#27571: to avoid asynchronization of `error' and - `error_code' of binlog event constructor - - The concept, which is a bit different for insert(!), is to - replace `error' assignment with the following lines - - killed_status= thd->killed; // get the status of the volatile - - Notice: thd->killed is type of "state" whereas the lhs has - "status" the suffix which translates according to WordNet: a state - at a particular time - at the time of the end of per-row loop in - our case. Binlogging ops are conducted with the status. - - error= (killed_status == THD::NOT_KILLED)? error : 1; - - which applies to most mysql_$query functions. - Event's constructor will accept `killed_status' as an argument: - - Query_log_event qinfo(..., killed_status); - - thd->killed might be changed after killed_status had got cached and this - won't affect binlogging event but other effects remain. - - Open issue: In a case the error happened not because of KILLED - - and then KILLED was caught later still within the loop - we shall - do something to avoid binlogging of incorrect ER_SERVER_SHUTDOWN - error_code. - */ - - if (thd->killed && !error) - error= 1; // Aborted - else if (will_batch && - (loc_error= table->file->exec_bulk_update(&dup_key_found))) + if (error && + will_batch && + (loc_error= table->file->exec_bulk_update(&dup_key_found))) /* An error has occurred when a batched update was performed and returned an error indication. It cannot be an allowed duplicate key error since @@ -838,8 +755,10 @@ int mysql_update(THD *thd, if (will_batch) table->file->end_bulk_update(); table->file->try_semi_consistent_read(0); -<<<<<<< remote sql/sql_update.cc 1.154.2.71 ->>>>>>> + + if (!transactional_table && updated > 0) + thd->transaction.stmt.modified_non_trans_table= TRUE; + end_read_record(&info); delete select; thd->proc_info= "end"; @@ -869,25 +788,13 @@ int mysql_update(THD *thd, { if (error < 0) thd->clear_error(); -<<<<<<< gca sql/sql_update.cc 1.154.2.70 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); - if (mysql_bin_log.write(&qinfo) && transactional_table) - error=1; // Rollback update -<<<<<<< local sql/sql_update.cc 1.258 if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - transactional_table, FALSE) && + transactional_table, FALSE, killed_status) && transactional_table) { error=1; // Rollback update } -<<<<<<< remote sql/sql_update.cc 1.154.2.71 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE, killed_status); - if (mysql_bin_log.write(&qinfo) && transactional_table) - error=1; // Rollback update ->>>>>>> } if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; @@ -1829,24 +1736,14 @@ void multi_update::send_error(uint errcode,const char *err) */ if (mysql_bin_log.is_open()) { -<<<<<<< gca sql/sql_update.cc 1.154.2.70 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); - mysql_bin_log.write(&qinfo); -<<<<<<< local sql/sql_update.cc 1.258 - thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, - transactional_tables, FALSE); -<<<<<<< remote sql/sql_update.cc 1.154.2.71 /* THD::killed status might not have been set ON at time of an error got caught and if happens later the killed error is written into repl event. */ - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); - mysql_bin_log.write(&qinfo); ->>>>>>> + thd->binlog_query(THD::ROW_QUERY_TYPE, + thd->query, thd->query_length, + transactional_tables, FALSE); } thd->transaction.all.modified_non_trans_table= TRUE; } @@ -2039,13 +1936,9 @@ err2: bool multi_update::send_eof() { char buff[STRING_BUFFER_USUAL_SIZE]; -<<<<<<< gca sql/sql_update.cc 1.154.2.70 -<<<<<<< local sql/sql_update.cc 1.258 ulonglong id; - DBUG_ENTER("multi_update::send_eof"); -<<<<<<< remote sql/sql_update.cc 1.154.2.71 THD::killed_state killed_status= THD::NOT_KILLED; ->>>>>>> + DBUG_ENTER("multi_update::send_eof"); thd->proc_info="updating reference tables"; /* @@ -2084,25 +1977,13 @@ bool multi_update::send_eof() { if (local_error == 0) thd->clear_error(); -<<<<<<< gca sql/sql_update.cc 1.154.2.70 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); - if (mysql_bin_log.write(&qinfo) && trans_safe) - local_error= 1; // Rollback update -<<<<<<< local sql/sql_update.cc 1.258 if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - transactional_tables, FALSE) && + transactional_tables, FALSE, killed_status) && trans_safe) { local_error= 1; // Rollback update } -<<<<<<< remote sql/sql_update.cc 1.154.2.71 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE, killed_status); - if (mysql_bin_log.write(&qinfo) && trans_safe) - local_error= 1; // Rollback update ->>>>>>> } if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; From fcff3b5a8d5db3ff0c8f9b3cbfc5645c81ca4c48 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 30 Oct 2007 14:08:37 +0100 Subject: [PATCH 052/136] manual merge BitKeeper/deleted/.del-rpl_slave_skip-slave.opt: Delete: mysql-test/t/rpl_slave_skip-slave.opt BitKeeper/deleted/.del-rpl_slave_skip.test: Delete: mysql-test/t/rpl_slave_skip.test BitKeeper/deleted/.del-rpl_slave_skip.result: Delete: mysql-test/r/rpl_slave_skip.result --- mysql-test/r/rpl_slave_skip.result | 144 ------------------ mysql-test/t/rpl_slave_skip-slave.opt | 1 - mysql-test/t/rpl_slave_skip.test | 203 -------------------------- sql/slave.cc | 113 +------------- 4 files changed, 8 insertions(+), 453 deletions(-) delete mode 100644 mysql-test/r/rpl_slave_skip.result delete mode 100644 mysql-test/t/rpl_slave_skip-slave.opt delete mode 100644 mysql-test/t/rpl_slave_skip.test diff --git a/mysql-test/r/rpl_slave_skip.result b/mysql-test/r/rpl_slave_skip.result deleted file mode 100644 index a59ac3eb884..00000000000 --- a/mysql-test/r/rpl_slave_skip.result +++ /dev/null @@ -1,144 +0,0 @@ -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; -**** On Master **** -CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=INNODB; -CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MYISAM; -==== Skipping normal transactions ==== -**** On Slave **** -STOP SLAVE; -**** On Master **** -BEGIN; -INSERT INTO t1 VALUES (1, 'master'); -INSERT INTO t1 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, 'master'); -COMMIT; -BEGIN; -INSERT INTO t1 VALUES (4, 'master,slave'); -INSERT INTO t1 VALUES (5, 'master,slave'); -INSERT INTO t1 VALUES (6, 'master,slave'); -COMMIT; -SELECT * FROM t1 ORDER BY a; -a b -1 master -2 master -3 master -4 master,slave -5 master,slave -6 master,slave -**** On Slave **** -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; -SELECT * FROM t1 ORDER BY a; -a b -4 master,slave -5 master,slave -6 master,slave -**** On Master **** -DELETE FROM t1; -==== Skipping two normal transactions ==== -**** On Slave **** -STOP SLAVE; -**** On Master **** -BEGIN; -INSERT INTO t1 VALUES (1, 'master'); -INSERT INTO t1 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, 'master'); -COMMIT; -BEGIN; -INSERT INTO t1 VALUES (4, 'master'); -INSERT INTO t1 VALUES (5, 'master'); -INSERT INTO t1 VALUES (6, 'master'); -COMMIT; -BEGIN; -INSERT INTO t1 VALUES (7, 'master,slave'); -INSERT INTO t1 VALUES (8, 'master,slave'); -INSERT INTO t1 VALUES (9, 'master,slave'); -COMMIT; -SELECT * FROM t1 ORDER BY a; -a b -1 master -2 master -3 master -4 master -5 master -6 master -7 master,slave -8 master,slave -9 master,slave -**** On Slave **** -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8; -START SLAVE; -SELECT * FROM t1 ORDER BY a; -a b -7 master,slave -8 master,slave -9 master,slave -**** On Master **** -DELETE FROM t1; -==== Skipping without autocommit ==== -**** On Slave **** -STOP SLAVE; -**** On Master **** -SET AUTOCOMMIT=0; -INSERT INTO t1 VALUES (1, 'master'); -INSERT INTO t1 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, 'master'); -COMMIT; -INSERT INTO t1 VALUES (4, 'master,slave'); -INSERT INTO t1 VALUES (5, 'master,slave'); -INSERT INTO t1 VALUES (6, 'master,slave'); -COMMIT; -SELECT * FROM t1 ORDER BY a; -a b -1 master -2 master -3 master -4 master,slave -5 master,slave -6 master,slave -**** On Slave **** -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; -SELECT * FROM t1 ORDER BY a; -a b -4 master,slave -5 master,slave -6 master,slave -==== Rollback of transaction with non-transactional change ==== -**** On Master **** -DELETE FROM t1; -SET AUTOCOMMIT=1; -**** On Slave **** -STOP SLAVE; -**** On Master **** -BEGIN; -INSERT INTO t1 VALUES (1, ''); -INSERT INTO t2 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, ''); -ROLLBACK; -BEGIN; -INSERT INTO t1 VALUES (4, ''); -INSERT INTO t2 VALUES (5, 'master,slave'); -INSERT INTO t1 VALUES (6, ''); -ROLLBACK; -SELECT * FROM t1 ORDER BY a; -a b -SELECT * FROM t2 ORDER BY a; -a b -2 master -5 master,slave -**** On Slave **** -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; -SELECT * FROM t1 ORDER BY a; -a b -SELECT * FROM t2 ORDER BY a; -a b -5 master,slave -==== Cleanup ==== -**** On Master **** -DROP TABLE t1, t2; diff --git a/mysql-test/t/rpl_slave_skip-slave.opt b/mysql-test/t/rpl_slave_skip-slave.opt deleted file mode 100644 index 627becdbfb5..00000000000 --- a/mysql-test/t/rpl_slave_skip-slave.opt +++ /dev/null @@ -1 +0,0 @@ ---innodb diff --git a/mysql-test/t/rpl_slave_skip.test b/mysql-test/t/rpl_slave_skip.test deleted file mode 100644 index 04aafc51129..00000000000 --- a/mysql-test/t/rpl_slave_skip.test +++ /dev/null @@ -1,203 +0,0 @@ -source include/have_innodb.inc; -source include/master-slave.inc; - -# This test is for checking that the use of SQL_SLAVE_SKIP_COUNTER -# behaves as expected, i.e., that it is guaranteed to skip an entire -# group and not start executing in the middle of a transaction. - -# We are checking the correct behaviour when using both a -# transactional and non-transactional table. The non-transactional -# table comes into play when rolling back a transaction containing a -# write to this table. In that case, the transaction should still be -# written to the binary log, and the slave will apply it and then roll -# it back to get the non-transactional change into the table. - ---echo **** On Master **** -CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=INNODB; -CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MYISAM; - ---echo ==== Skipping normal transactions ==== - ---echo **** On Slave **** -sync_slave_with_master; -STOP SLAVE; -source include/wait_for_slave_to_stop.inc; - ---echo **** On Master **** -connection master; - -BEGIN; -INSERT INTO t1 VALUES (1, 'master'); -INSERT INTO t1 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, 'master'); -COMMIT; - -BEGIN; -INSERT INTO t1 VALUES (4, 'master,slave'); -INSERT INTO t1 VALUES (5, 'master,slave'); -INSERT INTO t1 VALUES (6, 'master,slave'); -COMMIT; - -save_master_pos; - -SELECT * FROM t1 ORDER BY a; - -# This will skip a begin event and the first INSERT of the -# transaction, and it should keep skipping until it has reached the -# transaction terminator. - ---echo **** On Slave **** -connection slave; -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; -source include/wait_for_slave_to_start.inc; -sync_with_master; -SELECT * FROM t1 ORDER BY a; - ---echo **** On Master **** -connection master; -DELETE FROM t1; -sync_slave_with_master; - ---echo ==== Skipping two normal transactions ==== - ---echo **** On Slave **** -connection slave; -STOP SLAVE; -source include/wait_for_slave_to_stop.inc; - ---echo **** On Master **** -connection master; - -BEGIN; -INSERT INTO t1 VALUES (1, 'master'); -INSERT INTO t1 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, 'master'); -COMMIT; - -BEGIN; -INSERT INTO t1 VALUES (4, 'master'); -INSERT INTO t1 VALUES (5, 'master'); -INSERT INTO t1 VALUES (6, 'master'); -COMMIT; - -BEGIN; -INSERT INTO t1 VALUES (7, 'master,slave'); -INSERT INTO t1 VALUES (8, 'master,slave'); -INSERT INTO t1 VALUES (9, 'master,slave'); -COMMIT; - -save_master_pos; - -SELECT * FROM t1 ORDER BY a; - -# This will skip a begin event and the first INSERT of the -# transaction, and it should keep skipping until it has reached the -# transaction terminator. - ---echo **** On Slave **** -connection slave; -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8; -START SLAVE; -source include/wait_for_slave_to_start.inc; -sync_with_master; -SELECT * FROM t1 ORDER BY a; - ---echo **** On Master **** -connection master; -DELETE FROM t1; -sync_slave_with_master; - ---echo ==== Skipping without autocommit ==== - -# Testing without using autocommit instead. It should still write a -# BEGIN event, so the behaviour should be the same - ---echo **** On Slave **** -connection slave; -STOP SLAVE; -source include/wait_for_slave_to_stop.inc; - ---echo **** On Master **** -connection master; -SET AUTOCOMMIT=0; - -INSERT INTO t1 VALUES (1, 'master'); -INSERT INTO t1 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, 'master'); -COMMIT; - -INSERT INTO t1 VALUES (4, 'master,slave'); -INSERT INTO t1 VALUES (5, 'master,slave'); -INSERT INTO t1 VALUES (6, 'master,slave'); -COMMIT; - -save_master_pos; - -SELECT * FROM t1 ORDER BY a; - -# This will skip a begin event and the first INSERT of the -# transaction, and it should keep skipping until it has reached the -# transaction terminator. - ---echo **** On Slave **** -connection slave; -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; -source include/wait_for_slave_to_start.inc; -sync_with_master; -SELECT * FROM t1 ORDER BY a; - -# Testing with a non-transactional table in the transaction. This will -# log a ROLLBACK as a transaction terminator, which is a normal Query -# log event. - ---echo ==== Rollback of transaction with non-transactional change ==== - ---echo **** On Master **** -connection master; -DELETE FROM t1; -SET AUTOCOMMIT=1; - ---echo **** On Slave **** -sync_slave_with_master; -STOP SLAVE; -source include/wait_for_slave_to_stop.inc; - ---echo **** On Master **** -connection master; -disable_warnings; -BEGIN; -INSERT INTO t1 VALUES (1, ''); -INSERT INTO t2 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, ''); -ROLLBACK; - -BEGIN; -INSERT INTO t1 VALUES (4, ''); -INSERT INTO t2 VALUES (5, 'master,slave'); -INSERT INTO t1 VALUES (6, ''); -ROLLBACK; -enable_warnings; - -save_master_pos; - -SELECT * FROM t1 ORDER BY a; -SELECT * FROM t2 ORDER BY a; - ---echo **** On Slave **** -connection slave; -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; -source include/wait_for_slave_to_start.inc; -sync_with_master; - -SELECT * FROM t1 ORDER BY a; -SELECT * FROM t2 ORDER BY a; - ---echo ==== Cleanup ==== - ---echo **** On Master **** -connection master; -DROP TABLE t1, t2; -sync_slave_with_master; diff --git a/sql/slave.cc b/sql/slave.cc index 9ea7732aa92..79437dda67f 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1804,6 +1804,14 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) int const type_code= ev->get_type_code(); int exec_res= 0; + DBUG_PRINT("exec_event",("%s(type_code: %d; server_id: %d)", + ev->get_type_str(), type_code, ev->server_id)); + DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu", + FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT), + FLAGSTR(thd->options, OPTION_BEGIN), + rli->last_event_start_time)); + + /* Execute the event to change the database and update the binary log coordinates, but first we set some data that is needed for @@ -1828,111 +1836,6 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) has a Rotate etc). */ - DBUG_PRINT("info",("type_code: %d; server_id: %d; slave_skip_counter: %d", - type_code, ev->server_id, rli->slave_skip_counter)); - - DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu", - FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT), - FLAGSTR(thd->options, OPTION_BEGIN), - rli->last_event_start_time)); - - /* - If the slave skip counter is positive, we still need to set the - OPTION_BEGIN flag correctly and not skip the log events that - start or end a transaction. If we do this, the slave will not - notice that it is inside a transaction, and happily start - executing from inside the transaction. - - Note that the code block below is strictly 5.0. - */ -#if MYSQL_VERSION_ID < 50100 - if (unlikely(rli->slave_skip_counter > 0)) - { - switch (type_code) - { - case QUERY_EVENT: - { - Query_log_event* const qev= (Query_log_event*) ev; - DBUG_PRINT("info", ("QUERY_EVENT { query: '%s', q_len: %u }", - qev->query, qev->q_len)); - if (memcmp("BEGIN", qev->query, qev->q_len+1) == 0) - thd->options|= OPTION_BEGIN; - else if (memcmp("COMMIT", qev->query, qev->q_len+1) == 0 || - memcmp("ROLLBACK", qev->query, qev->q_len+1) == 0) - thd->options&= ~OPTION_BEGIN; - } - break; - - case XID_EVENT: - DBUG_PRINT("info", ("XID_EVENT")); - thd->options&= ~OPTION_BEGIN; - break; - } - } -#endif - - if ((ev->server_id == (uint32) ::server_id && - !replicate_same_server_id && - type_code != FORMAT_DESCRIPTION_EVENT) || - (rli->slave_skip_counter && - type_code != ROTATE_EVENT && type_code != STOP_EVENT && - type_code != START_EVENT_V3 && type_code!= FORMAT_DESCRIPTION_EVENT)) - { - DBUG_PRINT("info", ("event skipped")); - if (thd->options & OPTION_BEGIN) - rli->inc_event_relay_log_pos(); - else - { - rli->inc_group_relay_log_pos((type_code == ROTATE_EVENT || - type_code == STOP_EVENT || - type_code == FORMAT_DESCRIPTION_EVENT) ? - LL(0) : ev->log_pos, - 1/* skip lock*/); - flush_relay_log_info(rli); - } - - DBUG_PRINT("info", ("thd->options: %s", - (thd->options & OPTION_BEGIN) ? "OPTION_BEGIN" : "")); - - /* - Protect against common user error of setting the counter to 1 - instead of 2 while recovering from an insert which used auto_increment, - rand or user var. - */ - if (rli->slave_skip_counter && - !((type_code == INTVAR_EVENT || - type_code == RAND_EVENT || - type_code == USER_VAR_EVENT) && - rli->slave_skip_counter == 1) && -#if MYSQL_VERSION_ID < 50100 - /* - Decrease the slave skip counter only if we are not inside - a transaction or the slave skip counter is more than - 1. The slave skip counter will be decreased from 1 to 0 - when reaching the final ROLLBACK, COMMIT, or XID_EVENT. - */ - (!(thd->options & OPTION_BEGIN) || rli->slave_skip_counter > 1) && -#endif - /* - The events from ourselves which have something to do with the relay - log itself must be skipped, true, but they mustn't decrement - rli->slave_skip_counter, because the user is supposed to not see - these events (they are not in the master's binlog) and if we - decremented, START SLAVE would for example decrement when it sees - the Rotate, so the event which the user probably wanted to skip - would not be skipped. - */ - !(ev->server_id == (uint32) ::server_id && - (type_code == ROTATE_EVENT || - type_code == STOP_EVENT || - type_code == START_EVENT_V3 || - type_code == FORMAT_DESCRIPTION_EVENT))) - --rli->slave_skip_counter; - pthread_mutex_unlock(&rli->data_lock); - delete ev; - return 0; // avoid infinite update loops - } - thd->server_id = ev->server_id; // use the original server id for logging thd->set_time(); // time the query thd->lex->current_select= 0; From eb191861e3dcb5550be8a0ff1e260b8946d29d64 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 30 Oct 2007 21:17:19 +0100 Subject: [PATCH 053/136] BUG#19958 (RBR idempotency issue for UPDATE and DELETE): The rpl_trigger test case indicated a problem with idempotency support when run under row-based replication, which this patch fixes. However, despite this, the test is not designed for execution under row-based replication and hence rpl_trigger.test is not executed under row-based replication. The problem is that the test expects triggers to be executed when the slave updates rows on the slave, and this is (deliberately) not done with row-based replication. sql/log_event.cc: Adding function to print symbolic name of handler errors for debug purposes. Ignoring some more error messages to provide full idempotency support for update and delete operations. mysql-test/suite/rpl/r/rpl_idempotency.result: New BitKeeper file ``mysql-test/suite/rpl/r/rpl_idempotency.result'' mysql-test/suite/rpl/t/rpl_idempotency.test: New BitKeeper file ``mysql-test/suite/rpl/t/rpl_idempotency.test'' --- mysql-test/suite/rpl/r/rpl_idempotency.result | 71 +++++++++++++++++ mysql-test/suite/rpl/t/rpl_idempotency.test | 79 +++++++++++++++++++ sql/log_event.cc | 71 ++++++++++++++++- 3 files changed, 217 insertions(+), 4 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_idempotency.result create mode 100644 mysql-test/suite/rpl/t/rpl_idempotency.test diff --git a/mysql-test/suite/rpl/r/rpl_idempotency.result b/mysql-test/suite/rpl/r/rpl_idempotency.result new file mode 100644 index 00000000000..f17fbd82c44 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_idempotency.result @@ -0,0 +1,71 @@ +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 (a INT PRIMARY KEY); +CREATE TABLE t2 (a INT); +INSERT INTO t1 VALUES (-1),(-2),(-3); +INSERT INTO t2 VALUES (-1),(-2),(-3); +DELETE FROM t1 WHERE a = -2; +DELETE FROM t2 WHERE a = -2; +DELETE FROM t1 WHERE a = -2; +DELETE FROM t2 WHERE a = -2; +SELECT * FROM t1 ORDER BY a; +a +-3 +-1 +SELECT * FROM t2 ORDER BY a; +a +-3 +-1 +SELECT * FROM t1 ORDER BY a; +a +-3 +-1 +SELECT * FROM t2 ORDER BY a; +a +-3 +-1 +Last_SQL_Error +0 +INSERT IGNORE INTO t1 VALUES (-2); +INSERT IGNORE INTO t1 VALUES (-2); +SELECT * FROM t1 ORDER BY a; +a +-3 +-2 +-1 +SELECT * FROM t1 ORDER BY a; +a +-3 +-2 +-1 +Last_SQL_Error +0 +UPDATE t1 SET a = 1 WHERE a = -1; +UPDATE t2 SET a = 1 WHERE a = -1; +UPDATE t1 SET a = 1 WHERE a = -1; +UPDATE t2 SET a = 1 WHERE a = -1; +SELECT * FROM t1 ORDER BY a; +a +-3 +-2 +1 +SELECT * FROM t2 ORDER BY a; +a +-3 +1 +SELECT * FROM t1 ORDER BY a; +a +-3 +-2 +1 +SELECT * FROM t2 ORDER BY a; +a +-3 +1 +Last_SQL_Error +0 +DROP TABLE t1, t2; diff --git a/mysql-test/suite/rpl/t/rpl_idempotency.test b/mysql-test/suite/rpl/t/rpl_idempotency.test new file mode 100644 index 00000000000..44956b7b459 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_idempotency.test @@ -0,0 +1,79 @@ +# Testing various forms of idempotency for replication that should +# work the same way under statement based as under row based. + +source include/master-slave.inc; + +connection master; +CREATE TABLE t1 (a INT PRIMARY KEY); +CREATE TABLE t2 (a INT); +INSERT INTO t1 VALUES (-1),(-2),(-3); +INSERT INTO t2 VALUES (-1),(-2),(-3); +sync_slave_with_master; + +# A delete for a row that does not exist, the statement is +# deliberately written to be idempotent for statement-based +# replication as well. We test this towards both a table with a +# primary key and without a primary key. + +connection slave; +DELETE FROM t1 WHERE a = -2; +DELETE FROM t2 WHERE a = -2; +connection master; +DELETE FROM t1 WHERE a = -2; +DELETE FROM t2 WHERE a = -2; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +sync_slave_with_master; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; + +# An insert of a row that already exists. Since we are replacing the +# row if it already exists, the most apropriate representation is +# INSERT IGNORE. We only test this towards a table with a primary key, +# since the other case does not make sense. + +INSERT IGNORE INTO t1 VALUES (-2); +connection master; +INSERT IGNORE INTO t1 VALUES (-2); +SELECT * FROM t1 ORDER BY a; +sync_slave_with_master; +SELECT * FROM t1 ORDER BY a; +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; + +# BUG#19958: RBR idempotency issue for UPDATE and DELETE + +# Statement-based and row-based replication have different behaviour +# when updating a row with an explicit WHERE-clause that matches +# exactly one row (or no row at all). For statement-based replication, +# the statement is idempotent since the first time it is executed, it +# will update exactly one row, and the second time it will not update +# any row at all. This was not the case for row-based replication, so +# we test under both row-based and statement-based replication both +# for tables with and without primary keys. + +connection slave; +UPDATE t1 SET a = 1 WHERE a = -1; +UPDATE t2 SET a = 1 WHERE a = -1; +connection master; +UPDATE t1 SET a = 1 WHERE a = -1; +UPDATE t2 SET a = 1 WHERE a = -1; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +sync_slave_with_master; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; + +connection master; +DROP TABLE t1, t2; +sync_slave_with_master; diff --git a/sql/log_event.cc b/sql/log_event.cc index c0fbfb1000d..3dcc4535d94 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -36,6 +36,63 @@ #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") +#ifndef MYSQL_CLIENT +static const char *HA_ERR(int i) +{ + switch (i) { + case HA_ERR_KEY_NOT_FOUND: return "HA_ERR_KEY_NOT_FOUND"; + case HA_ERR_FOUND_DUPP_KEY: return "HA_ERR_FOUND_DUPP_KEY"; + case HA_ERR_RECORD_CHANGED: return "HA_ERR_RECORD_CHANGED"; + case HA_ERR_WRONG_INDEX: return "HA_ERR_WRONG_INDEX"; + case HA_ERR_CRASHED: return "HA_ERR_CRASHED"; + case HA_ERR_WRONG_IN_RECORD: return "HA_ERR_WRONG_IN_RECORD"; + case HA_ERR_OUT_OF_MEM: return "HA_ERR_OUT_OF_MEM"; + case HA_ERR_NOT_A_TABLE: return "HA_ERR_NOT_A_TABLE"; + case HA_ERR_WRONG_COMMAND: return "HA_ERR_WRONG_COMMAND"; + case HA_ERR_OLD_FILE: return "HA_ERR_OLD_FILE"; + case HA_ERR_NO_ACTIVE_RECORD: return "HA_ERR_NO_ACTIVE_RECORD"; + case HA_ERR_RECORD_DELETED: return "HA_ERR_RECORD_DELETED"; + case HA_ERR_RECORD_FILE_FULL: return "HA_ERR_RECORD_FILE_FULL"; + case HA_ERR_INDEX_FILE_FULL: return "HA_ERR_INDEX_FILE_FULL"; + case HA_ERR_END_OF_FILE: return "HA_ERR_END_OF_FILE"; + case HA_ERR_UNSUPPORTED: return "HA_ERR_UNSUPPORTED"; + case HA_ERR_TO_BIG_ROW: return "HA_ERR_TO_BIG_ROW"; + case HA_WRONG_CREATE_OPTION: return "HA_WRONG_CREATE_OPTION"; + case HA_ERR_FOUND_DUPP_UNIQUE: return "HA_ERR_FOUND_DUPP_UNIQUE"; + case HA_ERR_UNKNOWN_CHARSET: return "HA_ERR_UNKNOWN_CHARSET"; + case HA_ERR_WRONG_MRG_TABLE_DEF: return "HA_ERR_WRONG_MRG_TABLE_DEF"; + case HA_ERR_CRASHED_ON_REPAIR: return "HA_ERR_CRASHED_ON_REPAIR"; + case HA_ERR_CRASHED_ON_USAGE: return "HA_ERR_CRASHED_ON_USAGE"; + case HA_ERR_LOCK_WAIT_TIMEOUT: return "HA_ERR_LOCK_WAIT_TIMEOUT"; + case HA_ERR_LOCK_TABLE_FULL: return "HA_ERR_LOCK_TABLE_FULL"; + case HA_ERR_READ_ONLY_TRANSACTION: return "HA_ERR_READ_ONLY_TRANSACTION"; + case HA_ERR_LOCK_DEADLOCK: return "HA_ERR_LOCK_DEADLOCK"; + case HA_ERR_CANNOT_ADD_FOREIGN: return "HA_ERR_CANNOT_ADD_FOREIGN"; + case HA_ERR_NO_REFERENCED_ROW: return "HA_ERR_NO_REFERENCED_ROW"; + case HA_ERR_ROW_IS_REFERENCED: return "HA_ERR_ROW_IS_REFERENCED"; + case HA_ERR_NO_SAVEPOINT: return "HA_ERR_NO_SAVEPOINT"; + case HA_ERR_NON_UNIQUE_BLOCK_SIZE: return "HA_ERR_NON_UNIQUE_BLOCK_SIZE"; + case HA_ERR_NO_SUCH_TABLE: return "HA_ERR_NO_SUCH_TABLE"; + case HA_ERR_TABLE_EXIST: return "HA_ERR_TABLE_EXIST"; + case HA_ERR_NO_CONNECTION: return "HA_ERR_NO_CONNECTION"; + case HA_ERR_NULL_IN_SPATIAL: return "HA_ERR_NULL_IN_SPATIAL"; + case HA_ERR_TABLE_DEF_CHANGED: return "HA_ERR_TABLE_DEF_CHANGED"; + case HA_ERR_NO_PARTITION_FOUND: return "HA_ERR_NO_PARTITION_FOUND"; + case HA_ERR_RBR_LOGGING_FAILED: return "HA_ERR_RBR_LOGGING_FAILED"; + case HA_ERR_DROP_INDEX_FK: return "HA_ERR_DROP_INDEX_FK"; + case HA_ERR_FOREIGN_DUPLICATE_KEY: return "HA_ERR_FOREIGN_DUPLICATE_KEY"; + case HA_ERR_TABLE_NEEDS_UPGRADE: return "HA_ERR_TABLE_NEEDS_UPGRADE"; + case HA_ERR_TABLE_READONLY: return "HA_ERR_TABLE_READONLY"; + case HA_ERR_AUTOINC_READ_FAILED: return "HA_ERR_AUTOINC_READ_FAILED"; + case HA_ERR_AUTOINC_ERANGE: return "HA_ERR_AUTOINC_ERANGE"; + case HA_ERR_GENERIC: return "HA_ERR_GENERIC"; + case HA_ERR_RECORD_IS_THE_SAME: return "HA_ERR_RECORD_IS_THE_SAME"; + case HA_ERR_LOGGING_IMPOSSIBLE: return "HA_ERR_LOGGING_IMPOSSIBLE"; + case HA_ERR_CORRUPT_EVENT: return "HA_ERR_CORRUPT_EVENT"; + } +} +#endif + /* Cache that will automatically be written to a dedicated file on destruction. @@ -6228,8 +6285,11 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) /* Some recoverable errors */ case HA_ERR_RECORD_CHANGED: - case HA_ERR_KEY_NOT_FOUND: /* Idempotency support: OK if - tuple does not exist */ + case HA_ERR_RECORD_DELETED: + case HA_ERR_KEY_NOT_FOUND: + case HA_ERR_END_OF_FILE: + /* Idempotency support: OK if tuple does not exist */ + DBUG_PRINT("info", ("error: %s", HA_ERR(error))); error= 0; break; @@ -7467,6 +7527,9 @@ static bool record_compare(TABLE *table) records. Check that the other engines also return correct records. */ + DBUG_DUMP("record[0]", table->record[0], table->s->reclength); + DBUG_DUMP("record[1]", table->record[1], table->s->reclength); + bool result= FALSE; uchar saved_x[2], saved_filler[2]; @@ -7555,7 +7618,7 @@ record_compare_exit: int Rows_log_event::find_row(const Relay_log_info *rli) { - DBUG_ENTER("find_row"); + DBUG_ENTER("Rows_log_event::find_row"); DBUG_ASSERT(m_table && m_table->in_use != NULL); @@ -7784,7 +7847,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) DBUG_DUMP("record found", table->record[0], table->s->reclength); table->file->ha_rnd_end(); - DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == 0); + DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == HA_ERR_RECORD_DELETED || error == 0); DBUG_RETURN(error); } From d2048efb851fe8aec697a26a4f708f5a511c7c2f Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 31 Oct 2007 10:45:31 +0100 Subject: [PATCH 054/136] Post-merge fixes to handle some test failures. mysql-test/suite/rpl/r/rpl_innodb_bug28430.result: Result file change. mysql-test/suite/rpl/t/rpl_innodb_bug28430.test: Include file show_slave_status.inc should be used for portable SHOW SLAVE STATUS. --- .../suite/rpl/r/rpl_innodb_bug28430.result | 16 ++++++++-------- mysql-test/suite/rpl/t/rpl_innodb_bug28430.test | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result b/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result index fb2782ed9f4..c46b4016715 100644 --- a/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result +++ b/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result @@ -114,30 +114,30 @@ Create Table CREATE TABLE `byrange_tbl` ( `filler` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (id) SUBPARTITION BY HASH (id) SUBPARTITIONS 2 (PARTITION pa1 VALUES LESS THAN (10) ENGINE = InnoDB, PARTITION pa2 VALUES LESS THAN (20) ENGINE = InnoDB, PARTITION pa3 VALUES LESS THAN (30) ENGINE = InnoDB, PARTITION pa4 VALUES LESS THAN (40) ENGINE = InnoDB, PARTITION pa5 VALUES LESS THAN (50) ENGINE = InnoDB, PARTITION pa6 VALUES LESS THAN (60) ENGINE = InnoDB, PARTITION pa7 VALUES LESS THAN (70) ENGINE = InnoDB, PARTITION pa8 VALUES LESS THAN (80) ENGINE = InnoDB, PARTITION pa9 VALUES LESS THAN (90) ENGINE = InnoDB, PARTITION pa10 VALUES LESS THAN (100) ENGINE = InnoDB, PARTITION pa11 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ -show slave status; -Slave_IO_State Waiting for master to send event +SHOW SLAVE STATUS; +Slave_IO_State # Master_Host 127.0.0.1 Master_User root Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 Read_Master_Log_Pos 945470 -Relay_Log_File slave-relay-bin.000003 -Relay_Log_Pos 945616 +Relay_Log_File # +Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 Slave_IO_Running Yes Slave_SQL_Running Yes Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table -Replicate_Ignore_Table +Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 Exec_Master_Log_Pos 945470 -Relay_Log_Space 945771 +Relay_Log_Space # Until_Condition None Until_Log_File Until_Log_Pos 0 @@ -149,8 +149,8 @@ Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No -Last_IO_Errno 0 -Last_IO_Error +Last_IO_Errno # +Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error SELECT count(*) "Slave norm" FROM test.regular_tbl; diff --git a/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test index fe3881ab08f..aa56d0a106a 100644 --- a/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test +++ b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test @@ -136,7 +136,7 @@ SELECT count(*) as "Master byrange" FROM test.byrange_tbl; connection slave; show create table test.byrange_tbl; --replace_column 4 MASTER_PORT 33 # -show slave status; +source include/show_slave_status.inc; SELECT count(*) "Slave norm" FROM test.regular_tbl; SELECT count(*) "Slave bykey" FROM test.bykey_tbl; SELECT count(*) "Slave byrange" FROM test.byrange_tbl; From ffdf36f29e364728f9880e5a841c8ba42ddbf6b1 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 31 Oct 2007 11:48:49 +0200 Subject: [PATCH 055/136] bug#27571 merging. Fixing offsets and moving tests to the corrent destination. Removing wrong (local temp) tests. mysql-test/suite/binlog/t/binlog_killed_simulate-master.opt: Rename: mysql-test/t/binlog_killed_simulate-master.opt -> mysql-test/suite/binlog/t/binlog_killed_simulate-master.opt BitKeeper/deleted/.del-binlog_killed_bug27571.test: Delete: mysql-test/t/binlog_killed_bug27571.test BitKeeper/deleted/.del-binlog_killed_bug27571-master.opt: Delete: mysql-test/t/binlog_killed_bug27571-master.opt mysql-test/suite/binlog/r/binlog_killed.result: results changed mysql-test/suite/binlog/t/binlog_killed.test: binlog offset made 5.1 specific mysql-test/suite/binlog/t/binlog_killed_simulate.test: binlog offset + guard to run the test with stmt/mixed format mysql-test/suite/binlog/r/binlog_killed_simulate.result: new results file --- .../suite/binlog/r/binlog_killed.result | 13 ++-- .../binlog/r/binlog_killed_simulate.result | 33 +++++++++ mysql-test/suite/binlog/t/binlog_killed.test | 10 +-- .../t/binlog_killed_simulate-master.opt | 0 .../binlog}/t/binlog_killed_simulate.test | 7 +- .../t/binlog_killed_bug27571-master.opt | 1 - mysql-test/t/binlog_killed_bug27571.test | 68 ------------------- 7 files changed, 51 insertions(+), 81 deletions(-) create mode 100644 mysql-test/suite/binlog/r/binlog_killed_simulate.result rename mysql-test/{ => suite/binlog}/t/binlog_killed_simulate-master.opt (100%) rename mysql-test/{ => suite/binlog}/t/binlog_killed_simulate.test (83%) delete mode 100644 mysql-test/t/binlog_killed_bug27571-master.opt delete mode 100644 mysql-test/t/binlog_killed_bug27571.test diff --git a/mysql-test/suite/binlog/r/binlog_killed.result b/mysql-test/suite/binlog/r/binlog_killed.result index ddd80283eca..60b2ff6cfc4 100644 --- a/mysql-test/suite/binlog/r/binlog_killed.result +++ b/mysql-test/suite/binlog/r/binlog_killed.result @@ -70,9 +70,10 @@ select * from t2 /* must be (1,2), (2,2) */; a b 1 2 2 2 -show master status /* must have the update event more to FD */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 211 +must have the update event more to FD +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; update t2 set b=b + bug27563(b) order by a select (@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) is not null; @@ -98,9 +99,9 @@ select * from t2 /* must be (1,2), (2,2) */; a b 1 1 2 2 -show master status /* must have the update event more to FD */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 98 +must have the update event more to FD +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info select (@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) is not null; diff --git a/mysql-test/suite/binlog/r/binlog_killed_simulate.result b/mysql-test/suite/binlog/r/binlog_killed_simulate.result new file mode 100644 index 00000000000..f6a5ddade51 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_killed_simulate.result @@ -0,0 +1,33 @@ +drop table if exists t1,t2; +create table t1 (a int) engine=MyISAM; +insert into t1 set a=1; +reset master; +update t1 set a=2 /* will be "killed" after work has been done */; +select +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null +1 +select 1 /* must return 1 as query completed before got killed*/; +1 +1 +create table t2 (a int, b int) ENGINE=MyISAM; +reset master; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */; +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=1;block_len=12 +master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */ ;file_id=1 +select +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null +1 +select 0 /* must return 0 to mean the killed query is in */; +0 +0 +drop table t1,t2; +end of the tests diff --git a/mysql-test/suite/binlog/t/binlog_killed.test b/mysql-test/suite/binlog/t/binlog_killed.test index 89028d1c6b7..792b7a3dc57 100644 --- a/mysql-test/suite/binlog/t/binlog_killed.test +++ b/mysql-test/suite/binlog/t/binlog_killed.test @@ -216,11 +216,12 @@ connection con2; --error ER_QUERY_INTERRUPTED reap; select * from t2 /* must be (1,2), (2,2) */; -show master status /* must have the update event more to FD */; +--echo must have the update event more to FD +source include/show_binlog_events.inc; # a proof the query is binlogged with an error ---exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--exec $MYSQL_BINLOG --start-position=106 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval select (@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) @@ -256,11 +257,12 @@ connection con2; --error ER_QUERY_INTERRUPTED reap; select * from t2 /* must be (1,2), (2,2) */; -show master status /* must have the update event more to FD */; +--echo must have the update event more to FD +source include/show_binlog_events.inc; # a proof the query is binlogged with an error ---exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--exec $MYSQL_BINLOG --start-position=106 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval select (@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) diff --git a/mysql-test/t/binlog_killed_simulate-master.opt b/mysql-test/suite/binlog/t/binlog_killed_simulate-master.opt similarity index 100% rename from mysql-test/t/binlog_killed_simulate-master.opt rename to mysql-test/suite/binlog/t/binlog_killed_simulate-master.opt diff --git a/mysql-test/t/binlog_killed_simulate.test b/mysql-test/suite/binlog/t/binlog_killed_simulate.test similarity index 83% rename from mysql-test/t/binlog_killed_simulate.test rename to mysql-test/suite/binlog/t/binlog_killed_simulate.test index d6234d1bfd7..772736d89e9 100644 --- a/mysql-test/t/binlog_killed_simulate.test +++ b/mysql-test/suite/binlog/t/binlog_killed_simulate.test @@ -1,3 +1,4 @@ +-- source include/have_binlog_format_mixed_or_statement.inc # # bug#27571 asynchronous setting mysql_$query()'s local error and # Query_log_event::error_code @@ -18,8 +19,10 @@ reset master; update t1 set a=2 /* will be "killed" after work has been done */; # a proof the query is binlogged with no error - ---exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +#todo: introduce a suite private macro that provides numeric values +# for some constants like the offset of the first real event +# that is different between severs versions. +--exec $MYSQL_BINLOG --start-position=106 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval select (@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) diff --git a/mysql-test/t/binlog_killed_bug27571-master.opt b/mysql-test/t/binlog_killed_bug27571-master.opt deleted file mode 100644 index d269cf246d5..00000000000 --- a/mysql-test/t/binlog_killed_bug27571-master.opt +++ /dev/null @@ -1 +0,0 @@ ---loose-debug=d,stop_after_row_loop_done diff --git a/mysql-test/t/binlog_killed_bug27571.test b/mysql-test/t/binlog_killed_bug27571.test deleted file mode 100644 index 6fa3c6d256f..00000000000 --- a/mysql-test/t/binlog_killed_bug27571.test +++ /dev/null @@ -1,68 +0,0 @@ ---source include/have_innodb.inc ---source include/not_embedded.inc ---source include/have_log_bin.inc - -# -# bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code -# -# Checking that if killing happens inbetween of the end of rows loop and -# recording into binlog that will not lead to recording any error incl -# the killed error. -# - -connect (looser, localhost, root,,); -connect (killer, localhost, root,,); - -create table t1 (a int auto_increment, b int, PRIMARY KEY (a)) ENGINE=InnoDB; - -delete from t1; -insert into t1 values (1,1),(2,2); -reset master; - -connection looser; -let $ID= `select connection_id()`; -send update t1 set b=11 where a=2; - -connection killer; -sleep 1; # let 1 second for the update to get to the sleeping point ---replace_result $ID ID -eval kill query $ID; - -connection looser; ---error 0 # zero even though the query must be got killed while it was sleepin for 5 secs -reap; - -# -# this is another possible artifact. The killed error was not caught -# as that is logical as killing was not effective: -# data are ok and well as binlog event is without killed error (further). -# The reason of the following `show error' is to prove that -# killing simulation was effective -# -show errors; - -connection killer; - -# nothing is rolled back - -select * from t1 where a=2 /* must be 11 */; - -# a proof the query is binlogged with an error - ---exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog ---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR -eval select -(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR -let $error_code= `select @a like "%#%error_code=0%"`; - -eval select $error_code /* must return 1*/; - -# -# cleanup -# - -drop table t1; - ---echo end of the tests From 496bac71c42a5428527f8d1d919c919dcee6cb45 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 31 Oct 2007 14:01:01 -0500 Subject: [PATCH 056/136] rpl_extraSlave_Col.test: Corrected issues found in preparing to push code mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test: Corrected issues found in preparing to push code --- mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test index 3ad178e7610..6fa2c9ac1b5 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test @@ -920,7 +920,10 @@ sync_slave_with_master; #### Clean Up #### --disable_warnings --disable_query_log +connection master; DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t14a,t15,t16,t17; +sync_slave_with_master; +connection master; --enable_query_log --enable_warnings From cc0e54656714fec37cd74e03fe781f7571ed194e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 31 Oct 2007 21:09:52 +0100 Subject: [PATCH 057/136] BUG#28086 (SBR of USER() becomes corrupted on slave): Marking statements containing USER() or CURRENT_USER() as unsafe, causing them to switch to using row-based logging in MIXED mode and generate a warning in STATEMENT mode. mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result: Result change. mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test: Adding test to check that USER() and CURRENT_USER() cause a switch to row-based logging. sql/sql_yacc.yy: Setting statements containing USER() or CURRENT_USER() to be unsafe. --- .../rpl/r/rpl_switch_stm_row_mixed.result | 68 +++++++++++++++++++ .../suite/rpl/t/rpl_switch_stm_row_mixed.test | 36 ++++++++++ sql/sql_yacc.yy | 2 + 3 files changed, 106 insertions(+) diff --git a/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result b/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result index c3f0c07b92c..8ed9ff5dc2f 100644 --- a/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result +++ b/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result @@ -405,6 +405,26 @@ CREATE TABLE t12 (data LONG); LOCK TABLES t12 WRITE; INSERT INTO t12 VALUES(UUID()); UNLOCK TABLES; +CREATE FUNCTION my_user() +RETURNS CHAR(64) +BEGIN +DECLARE user CHAR(64); +SELECT USER() INTO user; +RETURN user; +END $$ +CREATE FUNCTION my_current_user() +RETURNS CHAR(64) +BEGIN +DECLARE user CHAR(64); +SELECT CURRENT_USER() INTO user; +RETURN user; +END $$ +DROP TABLE IF EXISTS t13; +CREATE TABLE t13 (data CHAR(64)); +INSERT INTO t13 VALUES (USER()); +INSERT INTO t13 VALUES (my_user()); +INSERT INTO t13 VALUES (CURRENT_USER()); +INSERT INTO t13 VALUES (my_current_user()); show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # drop database if exists mysqltest1 @@ -709,6 +729,30 @@ master-bin.000001 # Query # # use `mysqltest1`; DROP TABLE IF EXISTS t12 master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE t12 (data LONG) master-bin.000001 # Table_map # # table_id: # (mysqltest1.t12) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION my_user() +RETURNS CHAR(64) +BEGIN +DECLARE user CHAR(64); +SELECT USER() INTO user; +RETURN user; +END +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION my_current_user() +RETURNS CHAR(64) +BEGIN +DECLARE user CHAR(64); +SELECT CURRENT_USER() INTO user; +RETURN user; +END +master-bin.000001 # Query # # use `mysqltest1`; DROP TABLE IF EXISTS t13 +master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE t13 (data CHAR(64)) +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # drop database if exists mysqltest1 @@ -1013,5 +1057,29 @@ master-bin.000001 # Query # # use `mysqltest1`; DROP TABLE IF EXISTS t12 master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE t12 (data LONG) master-bin.000001 # Table_map # # table_id: # (mysqltest1.t12) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION my_user() +RETURNS CHAR(64) +BEGIN +DECLARE user CHAR(64); +SELECT USER() INTO user; +RETURN user; +END +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION my_current_user() +RETURNS CHAR(64) +BEGIN +DECLARE user CHAR(64); +SELECT CURRENT_USER() INTO user; +RETURN user; +END +master-bin.000001 # Query # # use `mysqltest1`; DROP TABLE IF EXISTS t13 +master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE t13 (data CHAR(64)) +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F drop database mysqltest1; set global binlog_format =@my_binlog_format; diff --git a/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test b/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test index b0012827db8..05dcb91ca28 100644 --- a/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test +++ b/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test @@ -518,6 +518,42 @@ CREATE TABLE t12 (data LONG); LOCK TABLES t12 WRITE; INSERT INTO t12 VALUES(UUID()); UNLOCK TABLES; +sync_slave_with_master; + +# +# BUG#28086: SBR of USER() becomes corrupted on slave +# + +connection master; + +# Just to get something that is non-trivial, albeit still simple, we +# stuff the result of USER() and CURRENT_USER() into a variable. +--delimiter $$ +CREATE FUNCTION my_user() + RETURNS CHAR(64) +BEGIN + DECLARE user CHAR(64); + SELECT USER() INTO user; + RETURN user; +END $$ +--delimiter ; + +--delimiter $$ +CREATE FUNCTION my_current_user() + RETURNS CHAR(64) +BEGIN + DECLARE user CHAR(64); + SELECT CURRENT_USER() INTO user; + RETURN user; +END $$ +--delimiter ; + +DROP TABLE IF EXISTS t13; +CREATE TABLE t13 (data CHAR(64)); +INSERT INTO t13 VALUES (USER()); +INSERT INTO t13 VALUES (my_user()); +INSERT INTO t13 VALUES (CURRENT_USER()); +INSERT INTO t13 VALUES (my_current_user()); source include/show_binlog_events.inc; sync_slave_with_master; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 109e8f5434f..bb25d9c4c7f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6745,6 +6745,7 @@ function_call_keyword: | CURRENT_USER optional_braces { $$= new (YYTHD->mem_root) Item_func_current_user(Lex->current_context()); + Lex->set_stmt_unsafe(); Lex->safe_to_cache_query= 0; } | DATE_SYM '(' expr ')' @@ -6790,6 +6791,7 @@ function_call_keyword: | USER '(' ')' { $$= new (YYTHD->mem_root) Item_func_user(); + Lex->set_stmt_unsafe(); Lex->safe_to_cache_query=0; } | YEAR_SYM '(' expr ')' From 0ac501c79a5ca496cd5eb2139688afd136777988 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 Nov 2007 14:00:38 +0200 Subject: [PATCH 058/136] Bug #31554 rpl.rpl_truncate_2myisam test failure: wrong master binlog file name Actually, the failure happened with 3innodb as well. Most probably the reason is in failing to delete a binlog file on __NT__ so that that master increments the index of the binlog file. The test results hide valueable warning that windows could generate about that. The scope of this fix is to make sure we have such warning and to lessen chances for binlog file being held at time of closing. The dump thread is getting a good chance to leave and release the file for its successful deletion. We shall watch over the two tests as regression is not excluded. In that case we would have an extra info possibly explaining why __NT__ env can not close/delete the file. However, regardless of that reason, there is alwasy workaround to mask out non-deterministic binlog index number. mysql-test/extra/rpl_tests/rpl_truncate_helper.test: enable warnings for other than DROP queries; wait for slave's full stop which ensures io thread left and that will be regarded by dump thread to leave and close the binlog file; relocating reset master to the end of the test so that the caller of this helper should start with the binlog name which has not yet been affected/reset since its creation. mysql-test/suite/rpl/r/rpl_truncate_2myisam.result: results changed mysql-test/suite/rpl/r/rpl_truncate_3innodb.result: results changed --- .../extra/rpl_tests/rpl_truncate_helper.test | 14 ++++--- .../suite/rpl/r/rpl_truncate_2myisam.result | 42 +++++++++++++++++++ .../suite/rpl/r/rpl_truncate_3innodb.result | 42 +++++++++++++++++++ 3 files changed, 92 insertions(+), 6 deletions(-) diff --git a/mysql-test/extra/rpl_tests/rpl_truncate_helper.test b/mysql-test/extra/rpl_tests/rpl_truncate_helper.test index 64a8de7c6a0..76db74acfa1 100644 --- a/mysql-test/extra/rpl_tests/rpl_truncate_helper.test +++ b/mysql-test/extra/rpl_tests/rpl_truncate_helper.test @@ -1,17 +1,16 @@ - ---disable_query_log ---disable_warnings connection slave; STOP SLAVE; +source include/wait_for_slave_to_stop.inc; connection master; +--disable_warnings DROP TABLE IF EXISTS t1; -RESET MASTER; +--enable_warnings connection slave; +--disable_warnings DROP TABLE IF EXISTS t1; +--enable_warnings RESET SLAVE; START SLAVE; ---enable_warnings ---enable_query_log --echo **** On Master **** connection master; @@ -38,3 +37,6 @@ connection master; DROP TABLE t1; let $SERVER_VERSION=`select version()`; source include/show_binlog_events.inc; + +connection master; +RESET MASTER; diff --git a/mysql-test/suite/rpl/r/rpl_truncate_2myisam.result b/mysql-test/suite/rpl/r/rpl_truncate_2myisam.result index c7ef28ba56b..7eee31dab7a 100644 --- a/mysql-test/suite/rpl/r/rpl_truncate_2myisam.result +++ b/mysql-test/suite/rpl/r/rpl_truncate_2myisam.result @@ -4,6 +4,11 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=STATEMENT; SET GLOBAL BINLOG_FORMAT=STATEMENT; @@ -31,10 +36,17 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1 master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=MIXED; SET GLOBAL BINLOG_FORMAT=MIXED; @@ -62,10 +74,17 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1 master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=ROW; SET GLOBAL BINLOG_FORMAT=ROW; @@ -93,11 +112,18 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1 master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=STATEMENT; SET GLOBAL BINLOG_FORMAT=STATEMENT; @@ -125,10 +151,17 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Query # # use `test`; DELETE FROM t1 master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=MIXED; SET GLOBAL BINLOG_FORMAT=MIXED; @@ -156,10 +189,17 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Query # # use `test`; DELETE FROM t1 master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=ROW; SET GLOBAL BINLOG_FORMAT=ROW; @@ -188,9 +228,11 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM 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 # Delete_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; diff --git a/mysql-test/suite/rpl/r/rpl_truncate_3innodb.result b/mysql-test/suite/rpl/r/rpl_truncate_3innodb.result index 7ce48c2e983..a6580a5685b 100644 --- a/mysql-test/suite/rpl/r/rpl_truncate_3innodb.result +++ b/mysql-test/suite/rpl/r/rpl_truncate_3innodb.result @@ -4,6 +4,11 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=STATEMENT; SET GLOBAL BINLOG_FORMAT=STATEMENT; @@ -31,12 +36,19 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1 master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=MIXED; SET GLOBAL BINLOG_FORMAT=MIXED; @@ -64,12 +76,19 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1 master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=ROW; SET GLOBAL BINLOG_FORMAT=ROW; @@ -97,6 +116,7 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F @@ -104,6 +124,12 @@ master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1 master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=STATEMENT; SET GLOBAL BINLOG_FORMAT=STATEMENT; @@ -131,12 +157,19 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DELETE FROM t1 master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=MIXED; SET GLOBAL BINLOG_FORMAT=MIXED; @@ -164,12 +197,19 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DELETE FROM t1 master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=ROW; SET GLOBAL BINLOG_FORMAT=ROW; @@ -198,6 +238,7 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F @@ -206,3 +247,4 @@ master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; From 88e560b078a3fabb92578e2aa450ab43ce51329a Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 3 Nov 2007 00:32:17 +0300 Subject: [PATCH 059/136] WL#3949. Added an option for support "combinations" of mysqld arguments for a suite mysql-test/lib/mtr_cases.pl: updated mtr_cases.pl mysql-test/mysql-test-run.pl: updated mtr --- mysql-test/lib/mtr_cases.pl | 99 ++++++++++++++++++++++++++++++++++++ mysql-test/mysql-test-run.pl | 5 ++ 2 files changed, 104 insertions(+) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 3d5752b4ec8..992d645f038 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -214,17 +214,44 @@ sub collect_one_suite($$) mtr_verbose("Collecting: $suite"); + my $combination_file= "combinations"; + my $combinations = []; + my $suitedir= "$::glob_mysql_test_dir"; # Default + my $combination_file= "$::glob_mysql_test_dir/$combination_file"; if ( $suite ne "main" ) { $suitedir= mtr_path_exists("$suitedir/suite/$suite", "$suitedir/$suite"); mtr_verbose("suitedir: $suitedir"); + $combination_file= "$suitedir/$combination_file"; } my $testdir= "$suitedir/t"; my $resdir= "$suitedir/r"; + if (!@::opt_combination) + { + # Read combinations file + if ( open(COMB,$combination_file) ) + { + while () + { + chomp; + s/\ +/ /g; + push (@$combinations, $_) unless ($_ eq ''); + } + close COMB; + } + } + else + { + # take the combination from command-line + @$combinations = @::opt_combination; + } + # Remember last element position + my $begin_index = $#{@$cases} + 1; + # ---------------------------------------------------------------------- # Build a hash of disabled testcases for this suite # ---------------------------------------------------------------------- @@ -335,6 +362,78 @@ sub collect_one_suite($$) closedir TESTDIR; } + # ---------------------------------------------------------------------- + # Proccess combinations only if new tests were added + # ---------------------------------------------------------------------- + if ($combinations && $begin_index <= $#{@$cases}) + { + my $end_index = $#{@$cases}; + my $is_copy; + # Keep original master/slave options + my @orig_opts; + for (my $idx = $begin_index; $idx <= $end_index; $idx++) + { + foreach my $param (('master_opt','slave_opt','slave_mi')) + { + @{$orig_opts[$idx]{$param}} = @{$cases->[$idx]->{$param}}; + } + } + my $comb_index = 1; + # Copy original test cases + foreach my $comb_set (@$combinations) + { + for (my $idx = $begin_index; $idx <= $end_index; $idx++) + { + my $test = $cases->[$idx]; + my $copied_test = {}; + foreach my $param (keys %{$test}) + { + # Scalar. Copy as is. + $copied_test->{$param} = $test->{$param}; + # Array. Copy reference instead itself + if ($param =~ /(master_opt|slave_opt|slave_mi)/) + { + my $new_arr = []; + @$new_arr = @{$orig_opts[$idx]{$param}}; + $copied_test->{$param} = $new_arr; + } + elsif ($param =~ /(comment|combinations)/) + { + $copied_test->{$param} = ''; + } + } + if ($is_copy) + { + push(@$cases, $copied_test); + $test = $cases->[$#{@$cases}]; + } + foreach my $comb_opt (split(/ /,$comb_set)) + { + push(@{$test->{'master_opt'}},$comb_opt); + push(@{$test->{'slave_opt'}},$comb_opt); + # Enable rpl if added option is --binlog-format and test case supports that + if ($comb_opt =~ /^--binlog-format=.+$/) + { + my @opt_pairs = split(/=/, $comb_opt); + if ($test->{'binlog_format'} =~ /^$opt_pairs[1]$/ || $test->{'binlog_format'} eq '') + { + $test->{'skip'} = 0; + $test->{'comment'} = ''; + } + else + { + $test->{'skip'} = 1; + $test->{'comment'} = "Requiring binlog format '$test->{'binlog_format'}'";; + } + } + } + $test->{'combination'} = $comb_set; + } + $is_copy = 1; + $comb_index++; + } + } + return $cases; } diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index eda268bcedf..11dbfbd14a8 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -164,6 +164,8 @@ our $opt_bench= 0; our $opt_small_bench= 0; our $opt_big_test= 0; +our @opt_combination; + our @opt_extra_mysqld_opt; our $opt_compress; @@ -529,6 +531,7 @@ sub command_line_setup () { 'skip-im' => \$opt_skip_im, 'skip-test=s' => \$opt_skip_test, 'big-test' => \$opt_big_test, + 'combination=s' => \@opt_combination, # Specify ports 'master_port=i' => \$opt_master_myport, @@ -5134,6 +5137,8 @@ Options to control what test suites or cases to run skip-im Don't start IM, and skip the IM test cases big-test Set the environment variable BIG_TEST, which can be checked from test cases. + combination="ARG1 .. ARG2" Specify a set of "mysqld" arguments for one + combination. Options that specify ports From b7cdb978d95d8078416d7591b617190d5cfde215 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Nov 2007 17:20:10 +0200 Subject: [PATCH 060/136] Bug #28597 Replication doesn't start after upgrading to 5.1.18 Since bug@20166, which replaced the binlog file name generating to base on pidfile_name instead of the previous glob_hostname, the binlog file name suddenly started to be stored solely in the absolute path format, including a case when --log-bin option meant a relative path. What's more serious, the path for binlog file can lead unrequestedly to pid-file directory so that after any proper fix for this bug there might be similar to the bug report consequences for one who upgrades from post-fix-bug@20166-pre-fix-bug@28597 to post-fix-bug@28597. Fixed with preserving`pidfile_name' (intr.by bug@20166) but stripping off its directory part. This restores the original logics of storing the names in compatible with --log-bin option format and with the requirement for --log-bin ralative path to corresond to the data directory. Side effects for this fix: effective fixing bug@27070, refining its test; ensuring no overrun for buff can happen anymore (Bug#31836 insufficient space reserved for the suffix of relay log file name); bug#31837 --remove_file $MYSQLTEST_VARDIR/tmp/bug14157.sql missed in rpl_temporary.test; fixes Bug@28603 Invalid log-bin default location; mysql-test/t/rpl_dual_pos_advance.test: After correcting the logics of log file name composing workaround for Bug #27070 server logs are created unrequested and in wrong directory is removed. mysql-test/t/rpl_temporary.test: remaining temp file of the test removed sql/log.cc: stripping off the directory part of `pidfile_name' for binlog name generating (which fixes two more bugs on wrong binlog file location); ensuring no overrun for buff can happen anymore (Bug #31836 insufficient space reserved for the suffix of relay log file name); --- mysql-test/t/rpl_dual_pos_advance.test | 6 ------ mysql-test/t/rpl_temporary.test | 2 ++ sql/log.cc | 11 ++++------- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/mysql-test/t/rpl_dual_pos_advance.test b/mysql-test/t/rpl_dual_pos_advance.test index 074aeec63b1..518fa9df885 100644 --- a/mysql-test/t/rpl_dual_pos_advance.test +++ b/mysql-test/t/rpl_dual_pos_advance.test @@ -106,9 +106,3 @@ connection slave; sync_with_master; # End of 4.1 tests - -# Cleanup -# The A->B->A replication causes the master to start writing relay logs -# in var/run, remove them -remove_file $MYSQLTEST_VARDIR/run/master-relay-bin.000001; -remove_file $MYSQLTEST_VARDIR/run/master-relay-bin.index; diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test index d09049af217..a7a15aebe7a 100644 --- a/mysql-test/t/rpl_temporary.test +++ b/mysql-test/t/rpl_temporary.test @@ -211,6 +211,8 @@ select * from t1; connection master; drop table t1; +--remove_file $MYSQLTEST_VARDIR/tmp/bug14157.sql + # Delete the anonymous users source include/delete_anonymous_users.inc; diff --git a/sql/log.cc b/sql/log.cc index e9aa273676a..af03cecd462 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -448,13 +448,10 @@ const char *MYSQL_LOG::generate_name(const char *log_name, { if (!log_name || !log_name[0]) { - /* - TODO: The following should be using fn_format(); We just need to - first change fn_format() to cut the file name if it's too long. - */ - strmake(buff, pidfile_name,FN_REFLEN-5); - strmov(fn_ext(buff),suffix); - return (const char *)buff; + strmake(buff, pidfile_name, FN_REFLEN - strlen(suffix) - 1); + return (const char *) + fn_format(buff, buff, "", suffix, MYF(MY_REPLACE_EXT|MY_REPLACE_DIR)); + } // get rid of extension if the log is binary to avoid problems if (strip_ext) From 5672c2e57ca82b5a446dd8d2d39caa9f23a6bb72 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Nov 2007 22:10:25 +0200 Subject: [PATCH 061/136] bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code refining tests as they appear to be non-deterministic. mysql-test/suite/binlog/r/binlog_killed.result: results changed mysql-test/suite/binlog/t/binlog_killed.test: restructuring the test to deliver more deterministic outcome. order-by for update and delete did not guaratee the order of scanning. --error are masked with zero in order to catch more info if killing really will happen to be non-deterministic on some platform (witnessed something like that on dl145j) mysql-test/suite/binlog/t/binlog_killed_simulate.test: important guard added --- .../suite/binlog/r/binlog_killed.result | 93 ++++++++++--------- mysql-test/suite/binlog/t/binlog_killed.test | 50 ++++++---- .../binlog/t/binlog_killed_simulate.test | 1 + 3 files changed, 83 insertions(+), 61 deletions(-) diff --git a/mysql-test/suite/binlog/r/binlog_killed.result b/mysql-test/suite/binlog/r/binlog_killed.result index 60b2ff6cfc4..9e8f9828d9f 100644 --- a/mysql-test/suite/binlog/r/binlog_killed.result +++ b/mysql-test/suite/binlog/r/binlog_killed.result @@ -17,8 +17,7 @@ update t1 set b=11 where a=2; update t1 set b=b+10; kill query ID; rollback; -ERROR 70100: Query execution was interrupted -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; a b 1 1 2 2 @@ -27,8 +26,7 @@ delete from t1 where a=2; delete from t1 where a=2; kill query ID; rollback; -ERROR 70100: Query execution was interrupted -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; a b 1 1 2 2 @@ -41,67 +39,45 @@ begin; insert into t1 select * from t4 for update; kill query ID; rollback; -ERROR 70100: Query execution was interrupted rollback; select * from t1 /* must be the same as before (1,1),(2,2) */; a b 1 1 2 2 drop table t4; +create table t4 (a int, b int) ENGINE=MyISAM /* for killing update and delete */; create function bug27563(n int) RETURNS int(11) DETERMINISTIC begin -if n > 1 then +if @b > 0 then select get_lock("a", 10) into @a; +else +set @b= 1; end if; return n; end| -delete from t2; -insert into t2 values (1,1), (2,2); +delete from t4; +insert into t4 values (1,1), (1,1); reset master; select get_lock("a", 20); get_lock("a", 20) 1 -update t2 set b=b + bug27563(b) order by a; +set @b= 0; +update t4 set b=b + bug27563(b); kill query ID; -ERROR 70100: Query execution was interrupted -select * from t2 /* must be (1,2), (2,2) */; -a b -1 2 -2 2 -must have the update event more to FD -show binlog events from ; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # use `test`; update t2 set b=b + bug27563(b) order by a -select -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null -1 -select 0 /* must return 0 to mean the killed query is in */; -0 -0 -select RELEASE_LOCK("a"); -RELEASE_LOCK("a") -1 -delete from t2; -insert into t2 values (1,1), (2,2); -reset master; -select get_lock("a", 20); -get_lock("a", 20) -1 -delete from t2 where a=1 or a=bug27563(2) order by a; -kill query ID; -ERROR 70100: Query execution was interrupted -select * from t2 /* must be (1,2), (2,2) */; +select * from t4 order by b /* must be (1,1), (1,2) */; a b 1 1 -2 2 -must have the update event more to FD +1 2 +select @b /* must be 1 at the end of a stmt calling bug27563() */; +@b +1 +must have the update query event more to FD show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # User var # # @`b`=0 +master-bin.000001 # Query # # use `test`; update t4 set b=b + bug27563(b) select (@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) is not null; @@ -114,6 +90,39 @@ select 0 /* must return 0 to mean the killed query is in */; select RELEASE_LOCK("a"); RELEASE_LOCK("a") 1 +delete from t4; +insert into t4 values (1,1), (2,2); +reset master; +select get_lock("a", 20); +get_lock("a", 20) +1 +set @b= 0; +delete from t4 where b=bug27563(1) or b=bug27563(2); +kill query ID; +select count(*) from t4 /* must be 1 */; +count(*) +1 +select @b /* must be 1 at the end of a stmt calling bug27563() */; +@b +1 +must have the delete query event more to FD +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # User var # # @`b`=0 +master-bin.000001 # Query # # use `test`; delete from t4 where b=bug27563(1) or b=bug27563(2) +select +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null +1 +select 0 /* must return 0 to mean the killed query is in */; +0 +0 +select RELEASE_LOCK("a"); +RELEASE_LOCK("a") +1 +drop table t4; drop function bug27563; drop table t1,t2,t3; end of the tests diff --git a/mysql-test/suite/binlog/t/binlog_killed.test b/mysql-test/suite/binlog/t/binlog_killed.test index 792b7a3dc57..4c2e6fbdc3c 100644 --- a/mysql-test/suite/binlog/t/binlog_killed.test +++ b/mysql-test/suite/binlog/t/binlog_killed.test @@ -68,7 +68,6 @@ select @result /* must be zero either way */; delete from t1; delete from t2; insert into t1 values (1,1),(2,2); -let $ID= `select connection_id()`; # # simple update @@ -77,6 +76,7 @@ connection con1; begin; update t1 set b=11 where a=2; connection con2; +let $ID= `select connection_id()`; send update t1 set b=b+10; connection con1; @@ -85,9 +85,9 @@ eval kill query $ID; rollback; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; # # multi update @@ -120,6 +120,7 @@ connection con1; begin; delete from t1 where a=2; connection con2; +let $ID= `select connection_id()`; send delete from t1 where a=2; connection con1; @@ -128,9 +129,9 @@ eval kill query $ID; rollback; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; # # multi delete @@ -163,6 +164,7 @@ insert into t4 values (3, 3); begin; insert into t1 values (3, 3); connection con2; +let $ID= `select connection_id()`; begin; send insert into t1 select * from t4 for update; @@ -172,7 +174,7 @@ eval kill query $ID; rollback; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; rollback; select * from t1 /* must be the same as before (1,1),(2,2) */; @@ -182,13 +184,17 @@ drop table t4; # cleanup for the sub-case ### ## non-ta table case: killing must be recorded in binlog ### +create table t4 (a int, b int) ENGINE=MyISAM /* for killing update and delete */; + delimiter |; create function bug27563(n int) RETURNS int(11) DETERMINISTIC begin - if n > 1 then + if @b > 0 then select get_lock("a", 10) into @a; + else + set @b= 1; end if; return n; end| @@ -198,25 +204,27 @@ delimiter ;| # update # -delete from t2; -insert into t2 values (1,1), (2,2); +delete from t4; +insert into t4 values (1,1), (1,1); reset master; connection con1; select get_lock("a", 20); connection con2; let $ID= `select connection_id()`; -send update t2 set b=b + bug27563(b) order by a; +set @b= 0; +send update t4 set b=b + bug27563(b); connection con1; --replace_result $ID ID eval kill query $ID; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; -select * from t2 /* must be (1,2), (2,2) */; ---echo must have the update event more to FD +select * from t4 order by b /* must be (1,1), (1,2) */; +select @b /* must be 1 at the end of a stmt calling bug27563() */; +--echo must have the update query event more to FD source include/show_binlog_events.inc; # a proof the query is binlogged with an error @@ -239,25 +247,27 @@ select RELEASE_LOCK("a"); # delete # -delete from t2; -insert into t2 values (1,1), (2,2); +delete from t4; +insert into t4 values (1,1), (2,2); reset master; connection con1; select get_lock("a", 20); connection con2; let $ID= `select connection_id()`; -send delete from t2 where a=1 or a=bug27563(2) order by a; +set @b= 0; +send delete from t4 where b=bug27563(1) or b=bug27563(2); connection con1; --replace_result $ID ID eval kill query $ID; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; -select * from t2 /* must be (1,2), (2,2) */; ---echo must have the update event more to FD +select count(*) from t4 /* must be 1 */; +select @b /* must be 1 at the end of a stmt calling bug27563() */; +--echo must have the delete query event more to FD source include/show_binlog_events.inc; # a proof the query is binlogged with an error @@ -276,6 +286,8 @@ connection con1; select RELEASE_LOCK("a"); --remove_file $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +drop table t4; + # # load data - see simulation tests # diff --git a/mysql-test/suite/binlog/t/binlog_killed_simulate.test b/mysql-test/suite/binlog/t/binlog_killed_simulate.test index 772736d89e9..2121a90dc8c 100644 --- a/mysql-test/suite/binlog/t/binlog_killed_simulate.test +++ b/mysql-test/suite/binlog/t/binlog_killed_simulate.test @@ -1,3 +1,4 @@ +-- source include/have_debug.inc -- source include/have_binlog_format_mixed_or_statement.inc # # bug#27571 asynchronous setting mysql_$query()'s local error and From cfc6ae2893c27bd13d34481555fe63e430cb51de Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Nov 2007 11:53:47 +0200 Subject: [PATCH 062/136] bug#27571 non-deterministic tests execution on some platforms. mysql-test/suite/binlog/r/binlog_killed.result: results changed mysql-test/suite/binlog/t/binlog_killed.test: correcting the prev test's cleanup; increasing time to wait by to be killed query; adding the masking out error due to Bug@32140 wrong error code caught when an SF() call is interruped with KILL query --- mysql-test/suite/binlog/r/binlog_killed.result | 5 ++++- mysql-test/suite/binlog/t/binlog_killed.test | 8 +++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/binlog/r/binlog_killed.result b/mysql-test/suite/binlog/r/binlog_killed.result index 9e8f9828d9f..3cd21e3bca1 100644 --- a/mysql-test/suite/binlog/r/binlog_killed.result +++ b/mysql-test/suite/binlog/r/binlog_killed.result @@ -9,6 +9,9 @@ insert into t2 values (null, null), (null, get_lock("a", 10)); select @result /* must be zero either way */; @result 0 +select RELEASE_LOCK("a"); +RELEASE_LOCK("a") +1 delete from t1; delete from t2; insert into t1 values (1,1),(2,2); @@ -51,7 +54,7 @@ RETURNS int(11) DETERMINISTIC begin if @b > 0 then -select get_lock("a", 10) into @a; +select get_lock("a", 20) into @a; else set @b= 1; end if; diff --git a/mysql-test/suite/binlog/t/binlog_killed.test b/mysql-test/suite/binlog/t/binlog_killed.test index 4c2e6fbdc3c..4810246437f 100644 --- a/mysql-test/suite/binlog/t/binlog_killed.test +++ b/mysql-test/suite/binlog/t/binlog_killed.test @@ -57,6 +57,8 @@ select @result /* must be zero either way */; --remove_file $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog +connection con1; +select RELEASE_LOCK("a"); # # bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code @@ -192,7 +194,7 @@ RETURNS int(11) DETERMINISTIC begin if @b > 0 then - select get_lock("a", 10) into @a; + select get_lock("a", 20) into @a; else set @b= 1; end if; @@ -220,7 +222,7 @@ connection con1; eval kill query $ID; connection con2; ---error 0,ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED,ER_SP_PROC_TABLE_CORRUPT reap; select * from t4 order by b /* must be (1,1), (1,2) */; select @b /* must be 1 at the end of a stmt calling bug27563() */; @@ -263,7 +265,7 @@ connection con1; eval kill query $ID; connection con2; ---error 0,ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED,ER_SP_PROC_TABLE_CORRUPT reap; select count(*) from t4 /* must be 1 */; select @b /* must be 1 at the end of a stmt calling bug27563() */; From 214b2f714734df19d470e0fdb696ec2599b505d6 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Nov 2007 13:08:37 +0200 Subject: [PATCH 063/136] bug#27571 non-deterministic tests refining. This particular patch tested on two archs. mysql-test/suite/binlog/t/binlog_killed.test: deploying synchronization of killing with reaching the explected state of the prey's connection. --- mysql-test/suite/binlog/t/binlog_killed.test | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/binlog/t/binlog_killed.test b/mysql-test/suite/binlog/t/binlog_killed.test index 4810246437f..c8809648098 100644 --- a/mysql-test/suite/binlog/t/binlog_killed.test +++ b/mysql-test/suite/binlog/t/binlog_killed.test @@ -218,11 +218,15 @@ set @b= 0; send update t4 set b=b + bug27563(b); connection con1; +let $wait_condition= select count(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock'; +source include/wait_condition.inc; +select count(*) FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock'; + --replace_result $ID ID eval kill query $ID; connection con2; ---error 0,ER_QUERY_INTERRUPTED,ER_SP_PROC_TABLE_CORRUPT +--error ER_QUERY_INTERRUPTED reap; select * from t4 order by b /* must be (1,1), (1,2) */; select @b /* must be 1 at the end of a stmt calling bug27563() */; @@ -261,11 +265,14 @@ set @b= 0; send delete from t4 where b=bug27563(1) or b=bug27563(2); connection con1; +let $wait_condition= select count(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock'; +source include/wait_condition.inc; +select count(*) FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock'; --replace_result $ID ID eval kill query $ID; connection con2; ---error 0,ER_QUERY_INTERRUPTED,ER_SP_PROC_TABLE_CORRUPT +--error ER_QUERY_INTERRUPTED reap; select count(*) from t4 /* must be 1 */; select @b /* must be 1 at the end of a stmt calling bug27563() */; From 3cc49bbe74960f4d6d552d9350a6b1b43bac6d99 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Nov 2007 13:53:26 +0200 Subject: [PATCH 064/136] bug#27571 commit is specific for 5.0 to eliminated non-deterministic tests. Those tests run only in 5.1 env where there is a necessary devices such as processlist table of info_schema. mysql-test/r/binlog_killed.result: results changed mysql-test/t/binlog_killed.test: removing non-deterministic part of the test mysql-test/t/binlog_killed_simulate.test: adding the guard same as for 5.1 version --- mysql-test/r/binlog_killed.result | 76 +-------------- mysql-test/t/binlog_killed.test | 118 +++-------------------- mysql-test/t/binlog_killed_simulate.test | 1 + 3 files changed, 19 insertions(+), 176 deletions(-) diff --git a/mysql-test/r/binlog_killed.result b/mysql-test/r/binlog_killed.result index ddd80283eca..eaafc9727cd 100644 --- a/mysql-test/r/binlog_killed.result +++ b/mysql-test/r/binlog_killed.result @@ -9,6 +9,9 @@ insert into t2 values (null, null), (null, get_lock("a", 10)); select @result /* must be zero either way */; @result 0 +select RELEASE_LOCK("a"); +RELEASE_LOCK("a") +1 delete from t1; delete from t2; insert into t1 values (1,1),(2,2); @@ -17,8 +20,7 @@ update t1 set b=11 where a=2; update t1 set b=b+10; kill query ID; rollback; -ERROR 70100: Query execution was interrupted -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; a b 1 1 2 2 @@ -27,8 +29,7 @@ delete from t1 where a=2; delete from t1 where a=2; kill query ID; rollback; -ERROR 70100: Query execution was interrupted -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; a b 1 1 2 2 @@ -41,78 +42,11 @@ begin; insert into t1 select * from t4 for update; kill query ID; rollback; -ERROR 70100: Query execution was interrupted rollback; select * from t1 /* must be the same as before (1,1),(2,2) */; a b 1 1 2 2 drop table t4; -create function bug27563(n int) -RETURNS int(11) -DETERMINISTIC -begin -if n > 1 then -select get_lock("a", 10) into @a; -end if; -return n; -end| -delete from t2; -insert into t2 values (1,1), (2,2); -reset master; -select get_lock("a", 20); -get_lock("a", 20) -1 -update t2 set b=b + bug27563(b) order by a; -kill query ID; -ERROR 70100: Query execution was interrupted -select * from t2 /* must be (1,2), (2,2) */; -a b -1 2 -2 2 -show master status /* must have the update event more to FD */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 211 -select -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null -1 -select 0 /* must return 0 to mean the killed query is in */; -0 -0 -select RELEASE_LOCK("a"); -RELEASE_LOCK("a") -1 -delete from t2; -insert into t2 values (1,1), (2,2); -reset master; -select get_lock("a", 20); -get_lock("a", 20) -1 -delete from t2 where a=1 or a=bug27563(2) order by a; -kill query ID; -ERROR 70100: Query execution was interrupted -select * from t2 /* must be (1,2), (2,2) */; -a b -1 1 -2 2 -show master status /* must have the update event more to FD */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 98 -select -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null -1 -select 0 /* must return 0 to mean the killed query is in */; -0 -0 -select RELEASE_LOCK("a"); -RELEASE_LOCK("a") -1 -drop function bug27563; drop table t1,t2,t3; end of the tests diff --git a/mysql-test/t/binlog_killed.test b/mysql-test/t/binlog_killed.test index 0e35e46c845..f8ba7c00f48 100644 --- a/mysql-test/t/binlog_killed.test +++ b/mysql-test/t/binlog_killed.test @@ -57,6 +57,8 @@ select @result /* must be zero either way */; --remove_file $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog +connection con1; +select RELEASE_LOCK("a"); # # bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code @@ -68,7 +70,6 @@ select @result /* must be zero either way */; delete from t1; delete from t2; insert into t1 values (1,1),(2,2); -let $ID= `select connection_id()`; # # simple update @@ -77,6 +78,7 @@ connection con1; begin; update t1 set b=11 where a=2; connection con2; +let $ID= `select connection_id()`; send update t1 set b=b+10; connection con1; @@ -85,9 +87,9 @@ eval kill query $ID; rollback; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; # # multi update @@ -120,6 +122,7 @@ connection con1; begin; delete from t1 where a=2; connection con2; +let $ID= `select connection_id()`; send delete from t1 where a=2; connection con1; @@ -128,9 +131,9 @@ eval kill query $ID; rollback; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; # # multi delete @@ -163,6 +166,7 @@ insert into t4 values (3, 3); begin; insert into t1 values (3, 3); connection con2; +let $ID= `select connection_id()`; begin; send insert into t1 select * from t4 for update; @@ -172,7 +176,7 @@ eval kill query $ID; rollback; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; rollback; select * from t1 /* must be the same as before (1,1),(2,2) */; @@ -182,106 +186,10 @@ drop table t4; # cleanup for the sub-case ### ## non-ta table case: killing must be recorded in binlog ### -delimiter |; -create function bug27563(n int) -RETURNS int(11) -DETERMINISTIC -begin - if n > 1 then - select get_lock("a", 10) into @a; - end if; - return n; -end| -delimiter ;| -# -# update -# - -delete from t2; -insert into t2 values (1,1), (2,2); -reset master; -connection con1; -select get_lock("a", 20); - -connection con2; -let $ID= `select connection_id()`; -send update t2 set b=b + bug27563(b) order by a; - -connection con1; ---replace_result $ID ID -eval kill query $ID; - -connection con2; ---error ER_QUERY_INTERRUPTED -reap; -select * from t2 /* must be (1,2), (2,2) */; -show master status /* must have the update event more to FD */; - -# a proof the query is binlogged with an error - ---exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog ---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR -eval select -(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR -let $error_code= `select @a like "%#%error_code=0%" /* must return 0*/`; -eval select $error_code /* must return 0 to mean the killed query is in */; - -# cleanup for the sub-case -connection con1; -select RELEASE_LOCK("a"); ---remove_file $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog - -# -# delete -# - -delete from t2; -insert into t2 values (1,1), (2,2); -reset master; -connection con1; -select get_lock("a", 20); - -connection con2; -let $ID= `select connection_id()`; -send delete from t2 where a=1 or a=bug27563(2) order by a; - -connection con1; ---replace_result $ID ID -eval kill query $ID; - -connection con2; ---error ER_QUERY_INTERRUPTED -reap; -select * from t2 /* must be (1,2), (2,2) */; -show master status /* must have the update event more to FD */; - -# a proof the query is binlogged with an error - ---exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog ---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR -eval select -(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR -let $error_code= `select @a like "%#%error_code=0%" /* must return 0*/`; -eval select $error_code /* must return 0 to mean the killed query is in */; - -# cleanup for the sub-case -connection con1; -select RELEASE_LOCK("a"); ---remove_file $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog - -# -# load data - see simulation tests -# - - -# bug#27571 cleanup - -drop function bug27563; +# In order to be deterministic the test needs INFORMATION_SCHEMA.PROCESSLIST +# which is not available on 5.0 at this time. +# Therefore, skip this part on 5.0. # diff --git a/mysql-test/t/binlog_killed_simulate.test b/mysql-test/t/binlog_killed_simulate.test index d6234d1bfd7..670cd756803 100644 --- a/mysql-test/t/binlog_killed_simulate.test +++ b/mysql-test/t/binlog_killed_simulate.test @@ -1,3 +1,4 @@ +-- source include/have_debug.inc # # bug#27571 asynchronous setting mysql_$query()'s local error and # Query_log_event::error_code From 86e07400b7b4107c2f97fbb7335de47ddada0c65 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Nov 2007 15:11:59 +0200 Subject: [PATCH 065/136] bug#27571 removing extra tests (on 5.1 that's been already done) BitKeeper/deleted/.del-binlog_killed_bug27571-master.opt: Delete: mysql-test/t/binlog_killed_bug27571-master.opt BitKeeper/deleted/.del-binlog_killed_bug27571.test: Delete: mysql-test/t/binlog_killed_bug27571.test --- .../t/binlog_killed_bug27571-master.opt | 1 - mysql-test/t/binlog_killed_bug27571.test | 68 ------------------- 2 files changed, 69 deletions(-) delete mode 100644 mysql-test/t/binlog_killed_bug27571-master.opt delete mode 100644 mysql-test/t/binlog_killed_bug27571.test diff --git a/mysql-test/t/binlog_killed_bug27571-master.opt b/mysql-test/t/binlog_killed_bug27571-master.opt deleted file mode 100644 index d269cf246d5..00000000000 --- a/mysql-test/t/binlog_killed_bug27571-master.opt +++ /dev/null @@ -1 +0,0 @@ ---loose-debug=d,stop_after_row_loop_done diff --git a/mysql-test/t/binlog_killed_bug27571.test b/mysql-test/t/binlog_killed_bug27571.test deleted file mode 100644 index 6fa3c6d256f..00000000000 --- a/mysql-test/t/binlog_killed_bug27571.test +++ /dev/null @@ -1,68 +0,0 @@ ---source include/have_innodb.inc ---source include/not_embedded.inc ---source include/have_log_bin.inc - -# -# bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code -# -# Checking that if killing happens inbetween of the end of rows loop and -# recording into binlog that will not lead to recording any error incl -# the killed error. -# - -connect (looser, localhost, root,,); -connect (killer, localhost, root,,); - -create table t1 (a int auto_increment, b int, PRIMARY KEY (a)) ENGINE=InnoDB; - -delete from t1; -insert into t1 values (1,1),(2,2); -reset master; - -connection looser; -let $ID= `select connection_id()`; -send update t1 set b=11 where a=2; - -connection killer; -sleep 1; # let 1 second for the update to get to the sleeping point ---replace_result $ID ID -eval kill query $ID; - -connection looser; ---error 0 # zero even though the query must be got killed while it was sleepin for 5 secs -reap; - -# -# this is another possible artifact. The killed error was not caught -# as that is logical as killing was not effective: -# data are ok and well as binlog event is without killed error (further). -# The reason of the following `show error' is to prove that -# killing simulation was effective -# -show errors; - -connection killer; - -# nothing is rolled back - -select * from t1 where a=2 /* must be 11 */; - -# a proof the query is binlogged with an error - ---exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog ---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR -eval select -(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR -let $error_code= `select @a like "%#%error_code=0%"`; - -eval select $error_code /* must return 1*/; - -# -# cleanup -# - -drop table t1; - ---echo end of the tests From d8c4501b281b436c8a450d86495d7ee0ff58a389 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Nov 2007 16:25:32 +0200 Subject: [PATCH 066/136] bug#27571 fixing tests mysql-test/r/binlog_killed_simulate.result: the new tests' result --- mysql-test/r/binlog_killed_simulate.result | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 mysql-test/r/binlog_killed_simulate.result diff --git a/mysql-test/r/binlog_killed_simulate.result b/mysql-test/r/binlog_killed_simulate.result new file mode 100644 index 00000000000..a21ac5b1e32 --- /dev/null +++ b/mysql-test/r/binlog_killed_simulate.result @@ -0,0 +1,33 @@ +drop table if exists t1,t2; +create table t1 (a int) engine=MyISAM; +insert into t1 set a=1; +reset master; +update t1 set a=2 /* will be "killed" after work has been done */; +select +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null +1 +select 1 /* must return 1 as query completed before got killed*/; +1 +1 +create table t2 (a int, b int) ENGINE=MyISAM; +reset master; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */; +ERROR 70100: Query execution was interrupted +show binlog events from 98; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 98 Begin_load_query 1 # ;file_id=1;block_len=12 +master-bin.000001 133 Execute_load_query 1 # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */ ;file_id=1 +select +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null +1 +select 0 /* must return 0 to mean the killed query is in */; +0 +0 +drop table t1,t2; +end of the tests From 8d4fdc5cda9be1fe9c2343adf5e2c40ad30e3795 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Nov 2007 16:32:55 +0200 Subject: [PATCH 067/136] results from 5.0 is not needed BitKeeper/deleted/.del-binlog_killed_simulate.result: Delete: mysql-test/r/binlog_killed_simulate.result --- mysql-test/r/binlog_killed_simulate.result | 33 ---------------------- 1 file changed, 33 deletions(-) delete mode 100644 mysql-test/r/binlog_killed_simulate.result diff --git a/mysql-test/r/binlog_killed_simulate.result b/mysql-test/r/binlog_killed_simulate.result deleted file mode 100644 index a21ac5b1e32..00000000000 --- a/mysql-test/r/binlog_killed_simulate.result +++ /dev/null @@ -1,33 +0,0 @@ -drop table if exists t1,t2; -create table t1 (a int) engine=MyISAM; -insert into t1 set a=1; -reset master; -update t1 set a=2 /* will be "killed" after work has been done */; -select -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null -1 -select 1 /* must return 1 as query completed before got killed*/; -1 -1 -create table t2 (a int, b int) ENGINE=MyISAM; -reset master; -load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */; -ERROR 70100: Query execution was interrupted -show binlog events from 98; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 98 Begin_load_query 1 # ;file_id=1;block_len=12 -master-bin.000001 133 Execute_load_query 1 # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */ ;file_id=1 -select -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null -1 -select 0 /* must return 0 to mean the killed query is in */; -0 -0 -drop table t1,t2; -end of the tests From 657dca9367c9759edae15420a558f261ce07c99a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Nov 2007 17:51:32 +0100 Subject: [PATCH 068/136] BUG#12092 (FOUND_ROWS() not replicated): In BUG#30244 added FOUND_ROWS() as an unsafe function, but that works only in mixed mode under 5.1. There is a workaround that can be used in statement-based mode either under 5.0 or 5.1 where the result of FOUND_ROWS() is stored into a user vari- able and used that way instead. This will replicate correctly even under statement-based replication, since it will write a User_var entry to the binary log. For some other cases, the value has to be passed explicitly. This patch adds tests to demonstrate that the workarounds docu- mented for statement-based replication works as advertised, and does more extensive tests for cases that does not work under sta- tement-based replication actually work under mixed mode by switch- ing to row-based replication. mysql-test/include/reset_master_and_slave.inc: New BitKeeper file ``mysql-test/include/reset_master_and_slave.inc'' mysql-test/suite/rpl/r/rpl_found_rows.result: New BitKeeper file ``mysql-test/suite/rpl/r/rpl_found_rows.result'' mysql-test/suite/rpl/t/rpl_found_rows.test: New BitKeeper file ``mysql-test/suite/rpl/t/rpl_found_rows.test'' --- mysql-test/include/reset_master_and_slave.inc | 10 + mysql-test/suite/rpl/r/rpl_found_rows.result | 228 ++++++++++++++++ mysql-test/suite/rpl/t/rpl_found_rows.test | 251 ++++++++++++++++++ 3 files changed, 489 insertions(+) create mode 100644 mysql-test/include/reset_master_and_slave.inc create mode 100644 mysql-test/suite/rpl/r/rpl_found_rows.result create mode 100644 mysql-test/suite/rpl/t/rpl_found_rows.test diff --git a/mysql-test/include/reset_master_and_slave.inc b/mysql-test/include/reset_master_and_slave.inc new file mode 100644 index 00000000000..c2d4120ddc9 --- /dev/null +++ b/mysql-test/include/reset_master_and_slave.inc @@ -0,0 +1,10 @@ +--echo **** Resetting master and slave **** +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; +RESET SLAVE; +connection master; +RESET MASTER; +connection slave; +START SLAVE; +source include/wait_for_slave_to_start.inc; diff --git a/mysql-test/suite/rpl/r/rpl_found_rows.result b/mysql-test/suite/rpl/r/rpl_found_rows.result new file mode 100644 index 00000000000..cec5071eecd --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_found_rows.result @@ -0,0 +1,228 @@ +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; +==== 0. Setting it all up ==== +SET BINLOG_FORMAT=STATEMENT; +**** On Master **** +CREATE TABLE t1 (a INT); +CREATE TABLE logtbl (sect INT, test INT, count INT); +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +#### 1. Using statement mode #### +==== 1.1. Simple test ==== +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +SELECT FOUND_ROWS() INTO @a; +INSERT INTO logtbl VALUES(1,1,@a); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +a +1 +SELECT FOUND_ROWS() INTO @a; +INSERT INTO logtbl VALUES(1,2,@a); +SELECT * FROM logtbl WHERE sect = 1; +sect test count +1 1 183 +1 2 3 +**** On Slave **** +SELECT * FROM logtbl WHERE sect = 1; +sect test count +1 1 183 +1 2 3 +==== 1.2. Stored procedure ==== +**** On Master **** +CREATE PROCEDURE calc_and_log(sect INT, test INT) BEGIN +DECLARE cnt INT; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +SELECT FOUND_ROWS() INTO cnt; +INSERT INTO logtbl VALUES(sect,test,cnt); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +SELECT FOUND_ROWS() INTO cnt; +INSERT INTO logtbl VALUES(sect,test+1,cnt); +END $$ +CALL calc_and_log(2,1); +a +1 +a +7 +CREATE PROCEDURE just_log(sect INT, test INT, found_rows INT) BEGIN +INSERT INTO logtbl VALUES (sect,test,found_rows); +END $$ +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +SELECT FOUND_ROWS() INTO @found_rows; +CALL just_log(2,3,@found_rows); +SELECT * FROM logtbl WHERE sect = 2; +sect test count +2 1 3 +2 2 183 +2 3 183 +**** On Slave **** +SELECT * FROM logtbl WHERE sect = 2; +sect test count +2 1 3 +2 2 183 +2 3 183 +==== 1.3. Stored functions ==== +**** On Master **** +CREATE FUNCTION log_rows(sect INT, test INT, found_rows INT) +RETURNS INT +BEGIN +INSERT INTO logtbl VALUES(sect,test,found_rows); +RETURN found_rows; +END $$ +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +SELECT FOUND_ROWS() INTO @found_rows; +SELECT log_rows(3,1,@found_rows), log_rows(3,2,@found_rows); +log_rows(3,1,@found_rows) log_rows(3,2,@found_rows) +183 183 +SELECT * FROM logtbl WHERE sect = 3; +sect test count +3 1 183 +3 2 183 +**** On Slave **** +SELECT * FROM logtbl WHERE sect = 3; +sect test count +3 1 183 +3 2 183 +==== 1.9. Cleanup ==== +**** On Master **** +DELETE FROM logtbl; +DROP PROCEDURE just_log; +DROP PROCEDURE calc_and_log; +DROP FUNCTION log_rows; +**** Resetting master and slave **** +STOP SLAVE; +RESET SLAVE; +RESET MASTER; +START SLAVE; +#### 2. Using mixed mode #### +==== 2.1. Checking a procedure ==== +**** On Master **** +SET BINLOG_FORMAT=MIXED; +CREATE PROCEDURE just_log(sect INT, test INT) BEGIN +INSERT INTO logtbl VALUES (sect,test,FOUND_ROWS()); +END $$ +**** On Master 1 **** +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +CALL just_log(1,1); +**** On Master **** +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +CALL just_log(1,2); +**** On Master 1 **** +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +a +1 +CALL just_log(1,3); +**** On Master **** +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +CALL just_log(1,4); +SELECT * FROM logtbl WHERE sect = 1; +sect test count +1 1 183 +1 2 183 +1 3 3 +1 4 183 +**** On Slave **** +SELECT * FROM logtbl WHERE sect = 1; +sect test count +1 1 183 +1 2 183 +1 3 3 +1 4 183 +==== 2.1. Checking a stored function ==== +**** On Master **** +CREATE FUNCTION log_rows(sect INT, test INT) +RETURNS INT +BEGIN +DECLARE found_rows INT; +SELECT FOUND_ROWS() INTO found_rows; +INSERT INTO logtbl VALUES(sect,test,found_rows); +RETURN found_rows; +END $$ +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +a +1 +SELECT log_rows(2,1), log_rows(2,2); +log_rows(2,1) log_rows(2,2) +3 3 +CREATE TABLE t2 (a INT, b INT); +CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW +BEGIN +INSERT INTO logtbl VALUES (NEW.a, NEW.b, FOUND_ROWS()); +END $$ +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +a +1 +INSERT INTO t2 VALUES (2,3), (2,4); +DROP TRIGGER t2_tr; +CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW +BEGIN +DECLARE dummy INT; +SELECT log_rows(NEW.a, NEW.b) INTO dummy; +END $$ +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +INSERT INTO t2 VALUES (2,5), (2,6); +DROP TRIGGER t2_tr; +CREATE PROCEDURE log_me_inner(sect INT, test INT) +BEGIN +DECLARE dummy INT; +SELECT log_rows(sect, test) INTO dummy; +SELECT log_rows(sect, test+1) INTO dummy; +END $$ +CREATE PROCEDURE log_me(sect INT, test INT) +BEGIN +CALL log_me_inner(sect,test); +END $$ +CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW +BEGIN +CALL log_me(NEW.a, NEW.b); +END $$ +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +INSERT INTO t2 VALUES (2,5), (2,6); +SELECT * FROM logtbl WHERE sect = 2; +sect test count +2 1 3 +2 2 3 +2 3 3 +2 4 3 +2 5 183 +2 6 183 +2 5 183 +2 6 0 +2 6 183 +2 7 0 +SELECT * FROM logtbl WHERE sect = 2; +sect test count +2 1 3 +2 2 3 +2 3 3 +2 4 3 +2 5 183 +2 6 183 +2 5 183 +2 6 0 +2 6 183 +2 7 0 +DROP TABLE t1, logtbl; diff --git a/mysql-test/suite/rpl/t/rpl_found_rows.test b/mysql-test/suite/rpl/t/rpl_found_rows.test new file mode 100644 index 00000000000..5d67b2ba6b7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_found_rows.test @@ -0,0 +1,251 @@ +source include/master-slave.inc; + +# It is not possible to replicate FOUND_ROWS() using statement-based +# replication, but there is a workaround that stores the result of +# FOUND_ROWS() into a user variable and then replicates this instead. + +# The purpose of this test case is to test that the workaround +# function properly even when inside stored programs (i.e., stored +# routines and triggers). + +--echo ==== 0. Setting it all up ==== + +SET BINLOG_FORMAT=STATEMENT; + +--echo **** On Master **** +connection master; +CREATE TABLE t1 (a INT); +CREATE TABLE logtbl (sect INT, test INT, count INT); + +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; + +--echo #### 1. Using statement mode #### + +--echo ==== 1.1. Simple test ==== + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; + +# Instead of +# INSERT INTO logtbl VALUES(1, 1, FOUND_ROWS()); +# we write +SELECT FOUND_ROWS() INTO @a; +INSERT INTO logtbl VALUES(1,1,@a); + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +# Instead of +# INSERT INTO logtbl VALUES(1, 2, FOUND_ROWS()); +# we write +SELECT FOUND_ROWS() INTO @a; +INSERT INTO logtbl VALUES(1,2,@a); + +SELECT * FROM logtbl WHERE sect = 1; +--echo **** On Slave **** +sync_slave_with_master; +SELECT * FROM logtbl WHERE sect = 1; + +--echo ==== 1.2. Stored procedure ==== + +# Here we do both the calculation and the logging. We also do it twice +# to make sure that there are no limitations on how many times it can +# be used. + +--echo **** On Master **** +connection master; +--delimiter $$ +CREATE PROCEDURE calc_and_log(sect INT, test INT) BEGIN + DECLARE cnt INT; + SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; + SELECT FOUND_ROWS() INTO cnt; + INSERT INTO logtbl VALUES(sect,test,cnt); + SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; + SELECT FOUND_ROWS() INTO cnt; + INSERT INTO logtbl VALUES(sect,test+1,cnt); +END $$ +--delimiter ; + +CALL calc_and_log(2,1); + +--delimiter $$ +CREATE PROCEDURE just_log(sect INT, test INT, found_rows INT) BEGIN + INSERT INTO logtbl VALUES (sect,test,found_rows); +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +SELECT FOUND_ROWS() INTO @found_rows; +CALL just_log(2,3,@found_rows); + +SELECT * FROM logtbl WHERE sect = 2; +--echo **** On Slave **** +sync_slave_with_master; +SELECT * FROM logtbl WHERE sect = 2; + +--echo ==== 1.3. Stored functions ==== +--echo **** On Master **** +connection master; +--delimiter $$ +CREATE FUNCTION log_rows(sect INT, test INT, found_rows INT) + RETURNS INT +BEGIN + INSERT INTO logtbl VALUES(sect,test,found_rows); + RETURN found_rows; +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +SELECT FOUND_ROWS() INTO @found_rows; +SELECT log_rows(3,1,@found_rows), log_rows(3,2,@found_rows); + +SELECT * FROM logtbl WHERE sect = 3; +--echo **** On Slave **** +sync_slave_with_master; +SELECT * FROM logtbl WHERE sect = 3; + +--echo ==== 1.9. Cleanup ==== +--echo **** On Master **** +connection master; +DELETE FROM logtbl; +DROP PROCEDURE just_log; +DROP PROCEDURE calc_and_log; +DROP FUNCTION log_rows; +sync_slave_with_master; + +source include/reset_master_and_slave.inc; + +--echo #### 2. Using mixed mode #### + +--echo ==== 2.1. Checking a procedure ==== + +--echo **** On Master **** +connection master; +SET BINLOG_FORMAT=MIXED; + +# We will now check some stuff that will not work in statement-based +# replication, but which should cause the binary log to switch to +# row-based logging. + +--delimiter $$ +CREATE PROCEDURE just_log(sect INT, test INT) BEGIN + INSERT INTO logtbl VALUES (sect,test,FOUND_ROWS()); +END $$ +--delimiter ; +sync_slave_with_master; + +--echo **** On Master 1 **** +connection master1; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +CALL just_log(1,1); + +--echo **** On Master **** +connection master; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +CALL just_log(1,2); + +--echo **** On Master 1 **** + +connection master1; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +CALL just_log(1,3); +sync_slave_with_master; + +--echo **** On Master **** +connection master; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +CALL just_log(1,4); +sync_slave_with_master; + +connection master; +SELECT * FROM logtbl WHERE sect = 1; +--echo **** On Slave **** +sync_slave_with_master; +SELECT * FROM logtbl WHERE sect = 1; + +--echo ==== 2.1. Checking a stored function ==== +--echo **** On Master **** +connection master; +--delimiter $$ +CREATE FUNCTION log_rows(sect INT, test INT) + RETURNS INT +BEGIN + DECLARE found_rows INT; + SELECT FOUND_ROWS() INTO found_rows; + INSERT INTO logtbl VALUES(sect,test,found_rows); + RETURN found_rows; +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +SELECT log_rows(2,1), log_rows(2,2); + +CREATE TABLE t2 (a INT, b INT); + +# Trying with referencing FOUND_ROWS() directly in the trigger. + +--delimiter $$ +CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW +BEGIN + INSERT INTO logtbl VALUES (NEW.a, NEW.b, FOUND_ROWS()); +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +INSERT INTO t2 VALUES (2,3), (2,4); + +# Referencing FOUND_ROWS() indirectly. + +DROP TRIGGER t2_tr; + +--delimiter $$ +CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW +BEGIN + DECLARE dummy INT; + SELECT log_rows(NEW.a, NEW.b) INTO dummy; +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +INSERT INTO t2 VALUES (2,5), (2,6); + +# Putting FOUND_ROWS() even lower in the call chain. + +connection master; +DROP TRIGGER t2_tr; + +--delimiter $$ +CREATE PROCEDURE log_me_inner(sect INT, test INT) +BEGIN + DECLARE dummy INT; + SELECT log_rows(sect, test) INTO dummy; + SELECT log_rows(sect, test+1) INTO dummy; +END $$ + +CREATE PROCEDURE log_me(sect INT, test INT) +BEGIN + CALL log_me_inner(sect,test); +END $$ +--delimiter ; + +--delimiter $$ +CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW +BEGIN + CALL log_me(NEW.a, NEW.b); +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +INSERT INTO t2 VALUES (2,5), (2,6); + +SELECT * FROM logtbl WHERE sect = 2; +sync_slave_with_master; +SELECT * FROM logtbl WHERE sect = 2; + +connection master; +DROP TABLE t1, logtbl; +sync_slave_with_master; + From febb420146bb64b20302c92e796c35a124dd1378 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Nov 2007 20:09:45 +0200 Subject: [PATCH 069/136] bug#27571 tests fixing: refreshing the results file. mysql-test/suite/binlog/r/binlog_killed.result: results changed --- mysql-test/suite/binlog/r/binlog_killed.result | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mysql-test/suite/binlog/r/binlog_killed.result b/mysql-test/suite/binlog/r/binlog_killed.result index 3cd21e3bca1..35b1eaea4b7 100644 --- a/mysql-test/suite/binlog/r/binlog_killed.result +++ b/mysql-test/suite/binlog/r/binlog_killed.result @@ -68,7 +68,11 @@ get_lock("a", 20) 1 set @b= 0; update t4 set b=b + bug27563(b); +select count(*) FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock'; +count(*) +1 kill query ID; +ERROR 70100: Query execution was interrupted select * from t4 order by b /* must be (1,1), (1,2) */; a b 1 1 @@ -101,7 +105,11 @@ get_lock("a", 20) 1 set @b= 0; delete from t4 where b=bug27563(1) or b=bug27563(2); +select count(*) FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock'; +count(*) +1 kill query ID; +ERROR 70100: Query execution was interrupted select count(*) from t4 /* must be 1 */; count(*) 1 From 0c1a085cca92ce1cbb48cd76eedf65a2130617dc Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Nov 2007 20:31:40 +0200 Subject: [PATCH 070/136] bug#27571 refining non-deterministic tests. The new Bug@32148 is in the way. Adjuting the tests to be somehow useful. mysql-test/r/binlog_killed.result: results changed mysql-test/t/binlog_killed.test: refining the tests as killing is inherently non-deterministic; leaving todos. --- mysql-test/r/binlog_killed.result | 4 ++++ mysql-test/t/binlog_killed.test | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/mysql-test/r/binlog_killed.result b/mysql-test/r/binlog_killed.result index eaafc9727cd..e04cc192876 100644 --- a/mysql-test/r/binlog_killed.result +++ b/mysql-test/r/binlog_killed.result @@ -17,18 +17,22 @@ delete from t2; insert into t1 values (1,1),(2,2); begin; update t1 set b=11 where a=2; +begin; update t1 set b=b+10; kill query ID; rollback; +rollback; select * from t1 order by a /* must be the same as before (1,1),(2,2) */; a b 1 1 2 2 begin; delete from t1 where a=2; +begin; delete from t1 where a=2; kill query ID; rollback; +rollback; select * from t1 order by a /* must be the same as before (1,1),(2,2) */; a b 1 1 diff --git a/mysql-test/t/binlog_killed.test b/mysql-test/t/binlog_killed.test index f8ba7c00f48..af78adf0abc 100644 --- a/mysql-test/t/binlog_killed.test +++ b/mysql-test/t/binlog_killed.test @@ -79,6 +79,7 @@ begin; update t1 set b=11 where a=2; connection con2; let $ID= `select connection_id()`; +begin; send update t1 set b=b+10; connection con1; @@ -86,9 +87,18 @@ connection con1; eval kill query $ID; rollback; +# Bug #32148 killi query may be ineffective +# forced to comment out the test's outcome +# and mask out ineffective ER_QUERY_INTERRUPTED +# todo1: revert back upon fixing bug#32148 +# todo2: the tests need refining in that +# killing should wait till the victim requested +# its lock (wait_condition available in 5.1 tests) + connection con2; --error 0,ER_QUERY_INTERRUPTED reap; +rollback; select * from t1 order by a /* must be the same as before (1,1),(2,2) */; # @@ -123,6 +133,7 @@ begin; delete from t1 where a=2; connection con2; let $ID= `select connection_id()`; +begin; send delete from t1 where a=2; connection con1; @@ -133,8 +144,11 @@ rollback; connection con2; --error 0,ER_QUERY_INTERRUPTED reap; +rollback; +# todo1,2 above select * from t1 order by a /* must be the same as before (1,1),(2,2) */; + # # multi delete # the same as for multi-update @@ -178,6 +192,7 @@ rollback; connection con2; --error 0,ER_QUERY_INTERRUPTED reap; +# todo 1,2 above rollback; select * from t1 /* must be the same as before (1,1),(2,2) */; From c5df4b3092d1dc4b66100b42e277fe708ad3c19d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Nov 2007 12:55:28 +0400 Subject: [PATCH 071/136] BUG#31277 - myisamchk --unpack corrupts a table With certain data sets (when compressed record length gets bigger than uncompressed) myisamchk --unpack may corrupt data file. Fixed that record length was wrongly restored from compressed table. myisam/mi_check.c: With compressed tables compressed record length may be bigger than pack_reclength, thus we may allocate insufficient memory for record buffer. Let single function allocate record buffer, performing needed record length calculations. Still, it is not doable with parallel repair, as it allocates needed record buffers at once. For parellel repair added better record length calculation. myisam/mi_open.c: When calculating record buffer size, take into account that compressed record length may be bigger than uncompressed. myisam/mi_packrec.c: With certain data set share->max_pack_length (compressed record length) may be bigger than share->base.pack_reclength (packed record length). set_if_bigger(pack_reclength, max_pack_length) in this case causes myisamchk --unpack to write extra garbage, whereas pack_reclength remains the same in new index file. As a result we get unreadable table. myisam/myisamchk.c: With compressed tables compressed record length may be bigger than pack_reclength, thus we may allocate insufficient memory for record buffer. Let single function allocate record buffer, performing needed record length calculations. mysql-test/mysql-test-run.pl: Environment variables to execute myisamchk and myisampack. mysql-test/r/myisampack.result: New BitKeeper file ``mysql-test/r/myisampack.result'' mysql-test/t/myisampack.test: New BitKeeper file ``mysql-test/t/myisampack.test'' --- myisam/mi_check.c | 39 ++++++++++++++++++---------------- myisam/mi_open.c | 7 ++++-- myisam/mi_packrec.c | 1 - myisam/myisamchk.c | 7 +++--- mysql-test/mysql-test-run.pl | 15 +++++++++++++ mysql-test/r/myisampack.result | 29 +++++++++++++++++++++++++ mysql-test/t/myisampack.test | 33 ++++++++++++++++++++++++++++ 7 files changed, 107 insertions(+), 24 deletions(-) create mode 100644 mysql-test/r/myisampack.result create mode 100644 mysql-test/t/myisampack.test diff --git a/myisam/mi_check.c b/myisam/mi_check.c index ce8fb04874e..0b786ca5332 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -940,7 +940,7 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) ha_rows records,del_blocks; my_off_t used,empty,pos,splits,start_recpos, del_length,link_used,start_block; - byte *record,*to; + byte *record= 0, *to; char llbuff[22],llbuff2[22],llbuff3[22]; ha_checksum intern_record_checksum; ha_checksum key_checksum[MI_MAX_POSSIBLE_KEY]; @@ -957,7 +957,7 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) puts("- check record links"); } - if (!(record= (byte*) my_malloc(info->s->base.pack_reclength,MYF(0)))) + if (!mi_alloc_rec_buff(info, -1, &record)) { mi_check_print_error(param,"Not enough memory for record"); DBUG_RETURN(-1); @@ -1364,12 +1364,12 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) printf("Lost space: %12s Linkdata: %10s\n", llstr(empty,llbuff),llstr(link_used,llbuff2)); } - my_free((gptr) record,MYF(0)); + my_free(mi_get_rec_buff_ptr(info, record), MYF(0)); DBUG_RETURN (error); err: mi_check_print_error(param,"got error: %d when reading datafile at record: %s",my_errno, llstr(records,llbuff)); err2: - my_free((gptr) record,MYF(0)); + my_free(mi_get_rec_buff_ptr(info, record), MYF(0)); param->testflag|=T_RETRY_WITHOUT_QUICK; DBUG_RETURN(1); } /* chk_data_link */ @@ -1428,8 +1428,7 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, MYF(MY_WME | MY_WAIT_IF_FULL))) goto err; info->opt_flag|=WRITE_CACHE_USED; - if (!(sort_param.record=(byte*) my_malloc((uint) share->base.pack_reclength, - MYF(0))) || + if (!mi_alloc_rec_buff(info, -1, &sort_param.record) || !mi_alloc_rec_buff(info, -1, &sort_param.rec_buff)) { mi_check_print_error(param, "Not enough memory for extra record"); @@ -1631,7 +1630,8 @@ err: } my_free(mi_get_rec_buff_ptr(info, sort_param.rec_buff), MYF(MY_ALLOW_ZERO_PTR)); - my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mi_get_rec_buff_ptr(info, sort_param.record), + MYF(MY_ALLOW_ZERO_PTR)); my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR)); VOID(end_io_cache(¶m->read_cache)); info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); @@ -2129,8 +2129,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, info->opt_flag|=WRITE_CACHE_USED; info->rec_cache.file=info->dfile; /* for sort_delete_record */ - if (!(sort_param.record=(byte*) my_malloc((uint) share->base.pack_reclength, - MYF(0))) || + if (!mi_alloc_rec_buff(info, -1, &sort_param.record) || !mi_alloc_rec_buff(info, -1, &sort_param.rec_buff)) { mi_check_print_error(param, "Not enough memory for extra record"); @@ -2415,7 +2414,8 @@ err: my_free(mi_get_rec_buff_ptr(info, sort_param.rec_buff), MYF(MY_ALLOW_ZERO_PTR)); - my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mi_get_rec_buff_ptr(info, sort_param.record), + MYF(MY_ALLOW_ZERO_PTR)); my_free((gptr) sort_info.key_block,MYF(MY_ALLOW_ZERO_PTR)); my_free((gptr) sort_info.ft_buf, MYF(MY_ALLOW_ZERO_PTR)); my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR)); @@ -2493,6 +2493,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, SORT_INFO sort_info; ulonglong key_map=share->state.key_map; pthread_attr_t thr_attr; + ulong max_pack_reclength; DBUG_ENTER("mi_repair_parallel"); start_records=info->state->records; @@ -2649,10 +2650,13 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, del=info->state->del; param->glob_crc=0; - + /* for compressed tables */ + max_pack_reclength= share->base.pack_reclength; + if (share->options & HA_OPTION_COMPRESS_RECORD) + set_if_bigger(max_pack_reclength, share->max_pack_length); if (!(sort_param=(MI_SORT_PARAM *) my_malloc((uint) share->base.keys * - (sizeof(MI_SORT_PARAM) + share->base.pack_reclength), + (sizeof(MI_SORT_PARAM) + max_pack_reclength), MYF(MY_ZEROFILL)))) { mi_check_print_error(param,"Not enough memory for key!"); @@ -2704,7 +2708,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, sort_param[i].max_pos=sort_param[i].pos=share->pack.header_length; sort_param[i].record= (((char *)(sort_param+share->base.keys))+ - (share->base.pack_reclength * i)); + (max_pack_reclength * i)); if (!mi_alloc_rec_buff(info, -1, &sort_param[i].rec_buff)) { mi_check_print_error(param,"Not enough memory!"); @@ -4320,7 +4324,7 @@ err: void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, my_bool repair_only) { - byte *record; + byte *record= 0; DBUG_ENTER("update_auto_increment_key"); if (!info->s->base.auto_key || @@ -4340,8 +4344,7 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, We have to use an allocated buffer instead of info->rec_buff as _mi_put_key_in_record() may use info->rec_buff */ - if (!(record= (byte*) my_malloc((uint) info->s->base.pack_reclength, - MYF(0)))) + if (!mi_alloc_rec_buff(info, -1, &record)) { mi_check_print_error(param,"Not enough memory for extra record"); DBUG_VOID_RETURN; @@ -4353,7 +4356,7 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, if (my_errno != HA_ERR_END_OF_FILE) { mi_extra(info,HA_EXTRA_NO_KEYREAD,0); - my_free((char*) record, MYF(0)); + my_free(mi_get_rec_buff_ptr(info, record), MYF(0)); mi_check_print_error(param,"%d when reading last record",my_errno); DBUG_VOID_RETURN; } @@ -4369,7 +4372,7 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, set_if_bigger(info->s->state.auto_increment,auto_increment); } mi_extra(info,HA_EXTRA_NO_KEYREAD,0); - my_free((char*) record, MYF(0)); + my_free(mi_get_rec_buff_ptr(info, record), MYF(0)); update_state_info(param, info, UPDATE_AUTO_INC); DBUG_VOID_RETURN; } diff --git a/myisam/mi_open.c b/myisam/mi_open.c index b007eb63e63..7543bdf2bf1 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -659,8 +659,11 @@ byte *mi_alloc_rec_buff(MI_INFO *info, ulong length, byte **buf) /* to simplify initial init of info->rec_buf in mi_open and mi_extra */ if (length == (ulong) -1) { - length= max(info->s->base.pack_reclength, - info->s->base.max_key_length); + if (info->s->options & HA_OPTION_COMPRESS_RECORD) + length= max(info->s->base.pack_reclength, info->s->max_pack_length); + else + length= info->s->base.pack_reclength; + length= max(length, info->s->base.max_key_length); /* Avoid unnecessary realloc */ if (newptr && length == old_length) return newptr; diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c index 51b0222e876..e931cc770ed 100644 --- a/myisam/mi_packrec.c +++ b/myisam/mi_packrec.c @@ -164,7 +164,6 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys) share->pack.header_length= uint4korr(header+4); share->min_pack_length=(uint) uint4korr(header+8); share->max_pack_length=(uint) uint4korr(header+12); - set_if_bigger(share->base.pack_reclength,share->max_pack_length); elements=uint4korr(header+16); intervall_length=uint4korr(header+20); trees=uint2korr(header+24); diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index a259fbf2c19..34b89967ca7 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -1543,8 +1543,8 @@ static int mi_sort_records(MI_CHECK *param, mi_check_print_error(param,"Not enough memory for key block"); goto err; } - if (!(sort_param.record=(byte*) my_malloc((uint) share->base.pack_reclength, - MYF(0)))) + + if (!mi_alloc_rec_buff(info, -1, &sort_param.record)) { mi_check_print_error(param,"Not enough memory for record"); goto err; @@ -1639,7 +1639,8 @@ err: { my_afree((gptr) temp_buff); } - my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mi_get_rec_buff_ptr(info, sort_param.record), + MYF(MY_ALLOW_ZERO_PTR)); info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); VOID(end_io_cache(&info->rec_cache)); my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR)); diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 6df64ced2f9..d60bb4663f2 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1880,6 +1880,21 @@ sub environment_setup () { ($lib_udf_example ? dirname($lib_udf_example) : "") . ($ENV{'LD_LIBRARY_PATH'} ? ":$ENV{'LD_LIBRARY_PATH'}" : ""); + # ---------------------------------------------------- + # Setup env so childs can execute myisampack and myisamchk + # ---------------------------------------------------- + $ENV{'MYISAMCHK'}= mtr_native_path(mtr_exe_exists( + vs_config_dirs('storage/myisam', 'myisamchk'), + vs_config_dirs('myisam', 'myisamchk'), + "$path_client_bindir/myisamchk", + "$glob_basedir/storage/myisam/myisamchk", + "$glob_basedir/myisam/myisamchk")); + $ENV{'MYISAMPACK'}= mtr_native_path(mtr_exe_exists( + vs_config_dirs('storage/myisam', 'myisampack'), + vs_config_dirs('myisam', 'myisampack'), + "$path_client_bindir/myisampack", + "$glob_basedir/storage/myisam/myisampack", + "$glob_basedir/myisam/myisampack")); # ---------------------------------------------------- # We are nice and report a bit about our settings diff --git a/mysql-test/r/myisampack.result b/mysql-test/r/myisampack.result new file mode 100644 index 00000000000..5f39d318234 --- /dev/null +++ b/mysql-test/r/myisampack.result @@ -0,0 +1,29 @@ +CREATE TABLE t1(c1 DOUBLE, c2 DOUBLE, c3 DOUBLE, c4 DOUBLE, c5 DOUBLE, +c6 DOUBLE, c7 DOUBLE, c8 DOUBLE, c9 DOUBLE, a INT PRIMARY KEY); +INSERT INTO t1 VALUES +(-3.31168791059336e-06,-3.19054655887874e-06,-1.06528081684847e-05,-1.227278240089e-06,-1.66718069164799e-06,-2.59038972510885e-06,-2.83145227805303e-06,-4.09678491270648e-07,-2.22610091291797e-06,6), +(0.0030743000272545,2.53222044316438e-05,2.78674650061845e-05,1.95914465544536e-05,1.7347572525984e-05,1.87513810069614e-05,1.69882826885005e-05,2.44449336987598e-05,1.89914629921774e-05,9), +(2.85229319423495e-05,3.05970988282259e-05,3.77161100113133e-05,2.3055238978766e-05,2.08241267364615e-05,2.28009504270553e-05,2.12070165658947e-05,2.84350091565409e-05,2.3366822910704e-05,3), +(0,0,0,0,0,0,0,0,0,12), +(3.24544577570754e-05,3.44619021870993e-05,4.37561613201124e-05,2.57556808726748e-05,2.3195354640561e-05,2.58532400758869e-05,2.34934241667179e-05,3.1621640063232e-05,2.58229982746189e-05,19), +(2.53222044316438e-05,0.00445071933455582,2.97447268116016e-05,2.12379514059868e-05,1.86777776502663e-05,2.0170058676712e-05,1.8946030385445e-05,2.66040037173511e-05,2.09161899668946e-05,20), +(3.03462382611645e-05,3.26517930083994e-05,3.5242025468662e-05,2.53219745106391e-05,2.24384532945004e-05,2.4052346047657e-05,2.23865572957053e-05,3.1634313969082e-05,2.48285463481801e-05,21), +(1.95914465544536e-05,2.12379514059868e-05,2.27808649037128e-05,0.000341724375366877,1.4512761275113e-05,1.56475828693953e-05,1.44372366441415e-05,2.07952121981765e-05,1.61488256935919e-05,28), +(1.7347572525984e-05,1.86777776502663e-05,2.04116907052727e-05,1.4512761275113e-05,0.000432162526082388,1.38116514014465e-05,1.2712914948904e-05,1.82503165178506e-05,1.43043075345922e-05,30), +(1.68339762136661e-05,1.77836497166611e-05,2.36328309295222e-05,1.30183423732016e-05,1.18674654241553e-05,1.32467273128652e-05,1.24581739117775e-05,1.55624190959406e-05,1.33010638508213e-05,31), +(1.89643062824415e-05,2.06997140070717e-05,2.29045490159364e-05,1.57918175731019e-05,1.39864987449492e-05,1.50580274578455e-05,1.45908734129609e-05,1.95329296993327e-05,1.5814709481221e-05,32), +(1.69882826885005e-05,1.8946030385445e-05,2.00820439721439e-05,1.44372366441415e-05,1.2712914948904e-05,1.35209686474184e-05,0.00261563314789896,1.78285095864627e-05,1.46699314500019e-05,34), +(2.0278186540684e-05,2.18923409729654e-05,2.39981539939738e-05,1.71774589459438e-05,1.54654355357383e-05,1.62731485707636e-05,1.49253140625051e-05,2.18229800160297e-05,1.71923561673718e-05,35), +(2.44449336987598e-05,2.66040037173511e-05,2.84860148925308e-05,2.07952121981765e-05,1.82503165178506e-05,1.97667730441441e-05,1.78285095864627e-05,0.00166478601822712,2.0299952103232e-05,36), +(1.89914629921774e-05,2.09161899668946e-05,2.26026841007872e-05,1.61488256935919e-05,1.43043075345922e-05,1.52609063290127e-05,1.46699314500019e-05,2.0299952103232e-05,0.00306670170971682,39), +(0,0,0,0,0,0,0,0,0,41), +(0,0,0,0,0,0,0,0,0,17), +(0,0,0,0,0,0,0,0,0,18), +(2.51880677333017e-05,2.63051795435778e-05,2.79874748974906e-05,2.02888886670845e-05,1.8178636318197e-05,1.91308527003585e-05,1.83260023644133e-05,2.4422300558171e-05,1.96411467520551e-05,44), +(2.22402118719591e-05,2.37546284320705e-05,2.58463051055541e-05,1.83391609130854e-05,1.6300720519646e-05,1.74559091886791e-05,1.63733785575587e-05,2.26616253279828e-05,1.79541237435621e-05,45), +(3.01092775359837e-05,3.23865212934412e-05,4.09444584045994e-05,0,2.15470966302776e-05,2.39082636344032e-05,2.28296706429177e-05,2.9007671511595e-05,2.44201138973326e-05,46); +FLUSH TABLES; +CHECK TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; diff --git a/mysql-test/t/myisampack.test b/mysql-test/t/myisampack.test new file mode 100644 index 00000000000..6598af6318a --- /dev/null +++ b/mysql-test/t/myisampack.test @@ -0,0 +1,33 @@ +# +# BUG#31277 - myisamchk --unpack corrupts a table +# +CREATE TABLE t1(c1 DOUBLE, c2 DOUBLE, c3 DOUBLE, c4 DOUBLE, c5 DOUBLE, + c6 DOUBLE, c7 DOUBLE, c8 DOUBLE, c9 DOUBLE, a INT PRIMARY KEY); +INSERT INTO t1 VALUES +(-3.31168791059336e-06,-3.19054655887874e-06,-1.06528081684847e-05,-1.227278240089e-06,-1.66718069164799e-06,-2.59038972510885e-06,-2.83145227805303e-06,-4.09678491270648e-07,-2.22610091291797e-06,6), +(0.0030743000272545,2.53222044316438e-05,2.78674650061845e-05,1.95914465544536e-05,1.7347572525984e-05,1.87513810069614e-05,1.69882826885005e-05,2.44449336987598e-05,1.89914629921774e-05,9), +(2.85229319423495e-05,3.05970988282259e-05,3.77161100113133e-05,2.3055238978766e-05,2.08241267364615e-05,2.28009504270553e-05,2.12070165658947e-05,2.84350091565409e-05,2.3366822910704e-05,3), +(0,0,0,0,0,0,0,0,0,12), +(3.24544577570754e-05,3.44619021870993e-05,4.37561613201124e-05,2.57556808726748e-05,2.3195354640561e-05,2.58532400758869e-05,2.34934241667179e-05,3.1621640063232e-05,2.58229982746189e-05,19), +(2.53222044316438e-05,0.00445071933455582,2.97447268116016e-05,2.12379514059868e-05,1.86777776502663e-05,2.0170058676712e-05,1.8946030385445e-05,2.66040037173511e-05,2.09161899668946e-05,20), +(3.03462382611645e-05,3.26517930083994e-05,3.5242025468662e-05,2.53219745106391e-05,2.24384532945004e-05,2.4052346047657e-05,2.23865572957053e-05,3.1634313969082e-05,2.48285463481801e-05,21), +(1.95914465544536e-05,2.12379514059868e-05,2.27808649037128e-05,0.000341724375366877,1.4512761275113e-05,1.56475828693953e-05,1.44372366441415e-05,2.07952121981765e-05,1.61488256935919e-05,28), +(1.7347572525984e-05,1.86777776502663e-05,2.04116907052727e-05,1.4512761275113e-05,0.000432162526082388,1.38116514014465e-05,1.2712914948904e-05,1.82503165178506e-05,1.43043075345922e-05,30), +(1.68339762136661e-05,1.77836497166611e-05,2.36328309295222e-05,1.30183423732016e-05,1.18674654241553e-05,1.32467273128652e-05,1.24581739117775e-05,1.55624190959406e-05,1.33010638508213e-05,31), +(1.89643062824415e-05,2.06997140070717e-05,2.29045490159364e-05,1.57918175731019e-05,1.39864987449492e-05,1.50580274578455e-05,1.45908734129609e-05,1.95329296993327e-05,1.5814709481221e-05,32), +(1.69882826885005e-05,1.8946030385445e-05,2.00820439721439e-05,1.44372366441415e-05,1.2712914948904e-05,1.35209686474184e-05,0.00261563314789896,1.78285095864627e-05,1.46699314500019e-05,34), +(2.0278186540684e-05,2.18923409729654e-05,2.39981539939738e-05,1.71774589459438e-05,1.54654355357383e-05,1.62731485707636e-05,1.49253140625051e-05,2.18229800160297e-05,1.71923561673718e-05,35), +(2.44449336987598e-05,2.66040037173511e-05,2.84860148925308e-05,2.07952121981765e-05,1.82503165178506e-05,1.97667730441441e-05,1.78285095864627e-05,0.00166478601822712,2.0299952103232e-05,36), +(1.89914629921774e-05,2.09161899668946e-05,2.26026841007872e-05,1.61488256935919e-05,1.43043075345922e-05,1.52609063290127e-05,1.46699314500019e-05,2.0299952103232e-05,0.00306670170971682,39), +(0,0,0,0,0,0,0,0,0,41), +(0,0,0,0,0,0,0,0,0,17), +(0,0,0,0,0,0,0,0,0,18), +(2.51880677333017e-05,2.63051795435778e-05,2.79874748974906e-05,2.02888886670845e-05,1.8178636318197e-05,1.91308527003585e-05,1.83260023644133e-05,2.4422300558171e-05,1.96411467520551e-05,44), +(2.22402118719591e-05,2.37546284320705e-05,2.58463051055541e-05,1.83391609130854e-05,1.6300720519646e-05,1.74559091886791e-05,1.63733785575587e-05,2.26616253279828e-05,1.79541237435621e-05,45), +(3.01092775359837e-05,3.23865212934412e-05,4.09444584045994e-05,0,2.15470966302776e-05,2.39082636344032e-05,2.28296706429177e-05,2.9007671511595e-05,2.44201138973326e-05,46); +FLUSH TABLES; +--exec $MYISAMPACK -s $MYSQLTEST_VARDIR/master-data/test/t1 +--exec $MYISAMCHK -srq $MYSQLTEST_VARDIR/master-data/test/t1 +--exec $MYISAMCHK -s --unpack $MYSQLTEST_VARDIR/master-data/test/t1 +CHECK TABLE t1 EXTENDED; +DROP TABLE t1; From 2f0444e0d95a541a04516e0a63aee93966d06a65 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Nov 2007 15:23:57 +0100 Subject: [PATCH 072/136] Adding return value, which is not used, and wrapped debug function in DBUG_OFF #ifdefs to eliminate two warnings in replication tree. --- sql/log_event.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 77cf719fde5..7c0de27cd87 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -36,7 +36,7 @@ #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") -#ifndef MYSQL_CLIENT +#if !defined(MYSQL_CLIENT) && !defined(DBUG_OFF) static const char *HA_ERR(int i) { switch (i) { @@ -90,6 +90,7 @@ static const char *HA_ERR(int i) case HA_ERR_LOGGING_IMPOSSIBLE: return "HA_ERR_LOGGING_IMPOSSIBLE"; case HA_ERR_CORRUPT_EVENT: return "HA_ERR_CORRUPT_EVENT"; } + return ""; } #endif From 0aad12d4983b565012c94746fa164a721c6b7c29 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Nov 2007 18:12:21 +0100 Subject: [PATCH 073/136] Second attempt at getting rid of warnings in replication tree. --- sql/log_event.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 7c0de27cd87..508d8377ae1 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -36,7 +36,7 @@ #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") -#if !defined(MYSQL_CLIENT) && !defined(DBUG_OFF) +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) && !defined(DBUG_OFF) && !defined(_lint) static const char *HA_ERR(int i) { switch (i) { From 007b16864f41e3b884d504649a46755a1e405a01 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Nov 2007 09:25:03 +0100 Subject: [PATCH 074/136] Fixing test case to not print warnings causing a result mismatch for rpl_trigger. mysql-test/suite/rpl/t/rpl_trigger.test: Disabling warnings to prevent different result files for MIXED and STATEMENT mode. --- mysql-test/suite/rpl/t/rpl_trigger.test | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mysql-test/suite/rpl/t/rpl_trigger.test b/mysql-test/suite/rpl/t/rpl_trigger.test index 9f5f6fc9b4c..4a496ea4923 100644 --- a/mysql-test/suite/rpl/t/rpl_trigger.test +++ b/mysql-test/suite/rpl/t/rpl_trigger.test @@ -316,8 +316,13 @@ SELECT * FROM t2; # 2. Check that the trigger is non-SUID on the slave; # 3. Check that the trigger can be activated on the slave. +# +# We disable warnings here since it affects the result file in +# different ways depending on the mode being used. +disable_warnings; INSERT INTO t1 VALUES(2); +enable_warnings; SELECT * FROM t1; SELECT * FROM t2; From dc34f9285f8a7dd23ce9c0ddc20cb7f23e1c3cf0 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Nov 2007 10:10:15 +0200 Subject: [PATCH 075/136] Bug #31170 rpl_innodb_bug28430 fails: varying timing, ports, and log use Non-deterministic parameters of SHOW SLAVE STATUS are masked out by means of using the standard include-macro. The masked-out parameters are not needed by the logics of the original tests. What is need to demonstre that replication is not stopped remains. mysql-test/suite/rpl/r/rpl_innodb_bug28430.result: results changed mysql-test/suite/rpl/t/rpl_innodb_bug28430.test: using the standard macro that takes care of masking out env specific values --- .../suite/rpl/r/rpl_innodb_bug28430.result | 16 ++++++++-------- mysql-test/suite/rpl/t/rpl_innodb_bug28430.test | 3 +-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result b/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result index fb2782ed9f4..c46b4016715 100644 --- a/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result +++ b/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result @@ -114,30 +114,30 @@ Create Table CREATE TABLE `byrange_tbl` ( `filler` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (id) SUBPARTITION BY HASH (id) SUBPARTITIONS 2 (PARTITION pa1 VALUES LESS THAN (10) ENGINE = InnoDB, PARTITION pa2 VALUES LESS THAN (20) ENGINE = InnoDB, PARTITION pa3 VALUES LESS THAN (30) ENGINE = InnoDB, PARTITION pa4 VALUES LESS THAN (40) ENGINE = InnoDB, PARTITION pa5 VALUES LESS THAN (50) ENGINE = InnoDB, PARTITION pa6 VALUES LESS THAN (60) ENGINE = InnoDB, PARTITION pa7 VALUES LESS THAN (70) ENGINE = InnoDB, PARTITION pa8 VALUES LESS THAN (80) ENGINE = InnoDB, PARTITION pa9 VALUES LESS THAN (90) ENGINE = InnoDB, PARTITION pa10 VALUES LESS THAN (100) ENGINE = InnoDB, PARTITION pa11 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ -show slave status; -Slave_IO_State Waiting for master to send event +SHOW SLAVE STATUS; +Slave_IO_State # Master_Host 127.0.0.1 Master_User root Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 Read_Master_Log_Pos 945470 -Relay_Log_File slave-relay-bin.000003 -Relay_Log_Pos 945616 +Relay_Log_File # +Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 Slave_IO_Running Yes Slave_SQL_Running Yes Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table -Replicate_Ignore_Table +Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 Exec_Master_Log_Pos 945470 -Relay_Log_Space 945771 +Relay_Log_Space # Until_Condition None Until_Log_File Until_Log_Pos 0 @@ -149,8 +149,8 @@ Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No -Last_IO_Errno 0 -Last_IO_Error +Last_IO_Errno # +Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error SELECT count(*) "Slave norm" FROM test.regular_tbl; diff --git a/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test index fe3881ab08f..80d8a8ee6c6 100644 --- a/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test +++ b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test @@ -135,8 +135,7 @@ SELECT count(*) as "Master byrange" FROM test.byrange_tbl; --sync_slave_with_master connection slave; show create table test.byrange_tbl; ---replace_column 4 MASTER_PORT 33 # -show slave status; +source include/show_slave_status.inc; SELECT count(*) "Slave norm" FROM test.regular_tbl; SELECT count(*) "Slave bykey" FROM test.bykey_tbl; SELECT count(*) "Slave byrange" FROM test.byrange_tbl; From 1aa12b229e4e25a3f551ff590557b3ea3d8b7006 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Nov 2007 09:13:47 +0100 Subject: [PATCH 076/136] Fixing some tests to make the replication team tree green. mysql-test/suite/rpl/r/rpl_found_rows.result: Result change. mysql-test/suite/rpl/t/rpl_found_rows.test: Adding ORDER BY to avoid order dependencies. Setting BINLOG_FORMAT=MIXED; for all master clients: one were missing. Dropping procedures that polluted later test results. --- mysql-test/suite/rpl/r/rpl_found_rows.result | 29 ++++++++++++-------- mysql-test/suite/rpl/t/rpl_found_rows.test | 25 ++++++++++------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_found_rows.result b/mysql-test/suite/rpl/r/rpl_found_rows.result index cec5071eecd..7e757a1d141 100644 --- a/mysql-test/suite/rpl/r/rpl_found_rows.result +++ b/mysql-test/suite/rpl/r/rpl_found_rows.result @@ -28,12 +28,12 @@ a 1 SELECT FOUND_ROWS() INTO @a; INSERT INTO logtbl VALUES(1,2,@a); -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; sect test count 1 1 183 1 2 3 **** On Slave **** -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; sect test count 1 1 183 1 2 3 @@ -61,13 +61,13 @@ a 7 SELECT FOUND_ROWS() INTO @found_rows; CALL just_log(2,3,@found_rows); -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; sect test count 2 1 3 2 2 183 2 3 183 **** On Slave **** -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; sect test count 2 1 3 2 2 183 @@ -87,12 +87,12 @@ SELECT FOUND_ROWS() INTO @found_rows; SELECT log_rows(3,1,@found_rows), log_rows(3,2,@found_rows); log_rows(3,1,@found_rows) log_rows(3,2,@found_rows) 183 183 -SELECT * FROM logtbl WHERE sect = 3; +SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test; sect test count 3 1 183 3 2 183 **** On Slave **** -SELECT * FROM logtbl WHERE sect = 3; +SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test; sect test count 3 1 183 3 2 183 @@ -115,6 +115,7 @@ CREATE PROCEDURE just_log(sect INT, test INT) BEGIN INSERT INTO logtbl VALUES (sect,test,FOUND_ROWS()); END $$ **** On Master 1 **** +SET BINLOG_FORMAT=MIXED; SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; a 7 @@ -134,14 +135,14 @@ SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; a 7 CALL just_log(1,4); -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; sect test count 1 1 183 1 2 183 1 3 3 1 4 183 **** On Slave **** -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; sect test count 1 1 183 1 2 183 @@ -201,28 +202,32 @@ SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; a 7 INSERT INTO t2 VALUES (2,5), (2,6); -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; sect test count 2 1 3 2 2 3 2 3 3 2 4 3 2 5 183 -2 6 183 2 5 183 +2 6 183 2 6 0 2 6 183 2 7 0 -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; sect test count 2 1 3 2 2 3 2 3 3 2 4 3 2 5 183 -2 6 183 2 5 183 +2 6 183 2 6 0 2 6 183 2 7 0 DROP TABLE t1, logtbl; +DROP PROCEDURE just_log; +DROP PROCEDURE log_me; +DROP PROCEDURE log_me_inner; +DROP FUNCTION log_rows; diff --git a/mysql-test/suite/rpl/t/rpl_found_rows.test b/mysql-test/suite/rpl/t/rpl_found_rows.test index 5d67b2ba6b7..f868061c951 100644 --- a/mysql-test/suite/rpl/t/rpl_found_rows.test +++ b/mysql-test/suite/rpl/t/rpl_found_rows.test @@ -44,10 +44,10 @@ SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; SELECT FOUND_ROWS() INTO @a; INSERT INTO logtbl VALUES(1,2,@a); -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; --echo **** On Slave **** sync_slave_with_master; -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; --echo ==== 1.2. Stored procedure ==== @@ -81,10 +81,10 @@ SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; SELECT FOUND_ROWS() INTO @found_rows; CALL just_log(2,3,@found_rows); -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; --echo **** On Slave **** sync_slave_with_master; -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; --echo ==== 1.3. Stored functions ==== --echo **** On Master **** @@ -102,10 +102,10 @@ SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; SELECT FOUND_ROWS() INTO @found_rows; SELECT log_rows(3,1,@found_rows), log_rows(3,2,@found_rows); -SELECT * FROM logtbl WHERE sect = 3; +SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test; --echo **** On Slave **** sync_slave_with_master; -SELECT * FROM logtbl WHERE sect = 3; +SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test; --echo ==== 1.9. Cleanup ==== --echo **** On Master **** @@ -139,6 +139,7 @@ sync_slave_with_master; --echo **** On Master 1 **** connection master1; +SET BINLOG_FORMAT=MIXED; SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; CALL just_log(1,1); @@ -161,10 +162,10 @@ CALL just_log(1,4); sync_slave_with_master; connection master; -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; --echo **** On Slave **** sync_slave_with_master; -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; --echo ==== 2.1. Checking a stored function ==== --echo **** On Master **** @@ -241,11 +242,15 @@ END $$ SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; INSERT INTO t2 VALUES (2,5), (2,6); -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; sync_slave_with_master; -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; connection master; DROP TABLE t1, logtbl; +DROP PROCEDURE just_log; +DROP PROCEDURE log_me; +DROP PROCEDURE log_me_inner; +DROP FUNCTION log_rows; sync_slave_with_master; From e7c56ceb8b825b090b3fb1f0673835a5cdc5bcd6 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Nov 2007 11:02:51 +0100 Subject: [PATCH 077/136] BUG#31552 (Replication breaks when deleting rows from out-of-sync table without PK): Pushing test case for bug only. Bug already fixed as a result of the patch for BUG#19958. mysql-test/extra/rpl_tests/rpl_row_basic.test: Adding test to see that no error is given on slave when deleting rows that don't exist on table without primary key. mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result: Result change. mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result: Result change. mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result: Result change. --- mysql-test/extra/rpl_tests/rpl_row_basic.test | 36 ++++++++++++++++--- .../suite/rpl/r/rpl_row_basic_2myisam.result | 19 ++++++++++ .../suite/rpl/r/rpl_row_basic_3innodb.result | 19 ++++++++++ .../suite/rpl_ndb/r/rpl_row_basic_7ndb.result | 19 ++++++++++ 4 files changed, 88 insertions(+), 5 deletions(-) diff --git a/mysql-test/extra/rpl_tests/rpl_row_basic.test b/mysql-test/extra/rpl_tests/rpl_row_basic.test index 6de254d9931..c35a53f15bc 100644 --- a/mysql-test/extra/rpl_tests/rpl_row_basic.test +++ b/mysql-test/extra/rpl_tests/rpl_row_basic.test @@ -215,11 +215,36 @@ sync_slave_with_master; --echo --- on slave --- SELECT * FROM t8 ORDER BY a; -# -# Test conflicting operations when changing in a table referenced by a -# foreign key. We'll reuse the above table and just add a table that -# references it. -# +# BUG#31552: Replication breaks when deleting rows from out-of-sync +# table without PK + +--echo **** Test for BUG#31552 **** + +--echo **** On Master **** +# Clean up t1 so that we can use it. +connection master; +DELETE FROM t1; +sync_slave_with_master; + +# Just to get a clean binary log +source include/reset_master_and_slave.inc; + +--echo **** On Master **** +connection master; +INSERT INTO t1 VALUES ('K','K'), ('L','L'), ('M','M'); +--echo **** On Master **** +sync_slave_with_master; +DELETE FROM t1 WHERE C1 = 'L'; + +connection master; +DELETE FROM t1; +query_vertical SELECT COUNT(*) FROM t1 ORDER BY c1,c2; +sync_slave_with_master; +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; +query_vertical SELECT COUNT(*) FROM t1 ORDER BY c1,c2; # # cleanup @@ -227,3 +252,4 @@ SELECT * FROM t8 ORDER BY a; connection master; DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8; +sync_slave_with_master; diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result b/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result index a6877b27b95..2efe3a3e486 100644 --- a/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result +++ b/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result @@ -415,4 +415,23 @@ a b c 2 4 8 3 6 9 99 99 99 +**** Test for BUG#31552 **** +**** On Master **** +DELETE FROM t1; +**** Resetting master and slave **** +STOP SLAVE; +RESET SLAVE; +RESET MASTER; +START SLAVE; +**** On Master **** +INSERT INTO t1 VALUES ('K','K'), ('L','L'), ('M','M'); +**** On Master **** +DELETE FROM t1 WHERE C1 = 'L'; +DELETE FROM t1; +SELECT COUNT(*) FROM t1 ORDER BY c1,c2; +COUNT(*) 0 +Last_SQL_Error +0 +SELECT COUNT(*) FROM t1 ORDER BY c1,c2; +COUNT(*) 0 DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8; diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result b/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result index 4c6ec627db5..fc78abfbe2e 100644 --- a/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result +++ b/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result @@ -415,4 +415,23 @@ a b c 2 4 8 3 6 9 99 99 99 +**** Test for BUG#31552 **** +**** On Master **** +DELETE FROM t1; +**** Resetting master and slave **** +STOP SLAVE; +RESET SLAVE; +RESET MASTER; +START SLAVE; +**** On Master **** +INSERT INTO t1 VALUES ('K','K'), ('L','L'), ('M','M'); +**** On Master **** +DELETE FROM t1 WHERE C1 = 'L'; +DELETE FROM t1; +SELECT COUNT(*) FROM t1 ORDER BY c1,c2; +COUNT(*) 0 +Last_SQL_Error +0 +SELECT COUNT(*) FROM t1 ORDER BY c1,c2; +COUNT(*) 0 DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result b/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result index 5519e0dcd0c..abd5bad8e49 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result @@ -415,4 +415,23 @@ a b c 2 4 8 3 6 9 99 99 99 +**** Test for BUG#31552 **** +**** On Master **** +DELETE FROM t1; +**** Resetting master and slave **** +STOP SLAVE; +RESET SLAVE; +RESET MASTER; +START SLAVE; +**** On Master **** +INSERT INTO t1 VALUES ('K','K'), ('L','L'), ('M','M'); +**** On Master **** +DELETE FROM t1 WHERE C1 = 'L'; +DELETE FROM t1; +SELECT COUNT(*) FROM t1 ORDER BY c1,c2; +COUNT(*) 0 +Last_SQL_Error +0 +SELECT COUNT(*) FROM t1 ORDER BY c1,c2; +COUNT(*) 0 DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8; From 5eafd5b12291c30179b4249c2c6b9decca6d5bdd Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Nov 2007 16:05:01 +0400 Subject: [PATCH 078/136] BUG#29083 - test suite times out on OS X 64bit - also in older releases The "mysql client in mysqld"(which is used by replication and federated) should use alarms instead of setting socket timeout value if the rest of the server uses alarm. By always calling 'my_net_set_write_timeout' or 'net_set_read_timeout' when changing the timeout value(s), the selection whether to use alarms or timeouts will be handled by ifdef's in those two functions. This is minimal backport of patch for BUG#26664, which was pushed to 5.0 and up. Affects 4.1 only. include/mysql_com.h: Move the net_set_*_timeout function declarations to mysql_com.h sql-common/client.c: Use my_net_read_timeout or my_net_write_timeout when setting the timeouts sql/mysql_priv.h: Move the net_set_*_timeout function declarations to mysql_com.h --- include/mysql_com.h | 5 +++++ sql-common/client.c | 6 ++---- sql/mysql_priv.h | 3 --- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/mysql_com.h b/include/mysql_com.h index 56c7f7d2ab5..daeb540c7c8 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -291,6 +291,11 @@ my_bool net_write_command(NET *net,unsigned char command, int net_real_write(NET *net,const char *packet,unsigned long len); unsigned long my_net_read(NET *net); +#ifdef _global_h +void net_set_write_timeout(NET *net, uint timeout); +void net_set_read_timeout(NET *net, uint timeout); +#endif + /* The following function is not meant for normal usage Currently it's used internally by manager.c diff --git a/sql-common/client.c b/sql-common/client.c index bf9c7252283..82a2f9d7bd0 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1884,13 +1884,11 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, /* If user set read_timeout, let it override the default */ if (mysql->options.read_timeout) - net->read_timeout= mysql->options.read_timeout; - vio_timeout(net->vio, 0, net->read_timeout); + net_set_read_timeout(net, mysql->options.read_timeout); /* If user set write_timeout, let it override the default */ if (mysql->options.write_timeout) - net->write_timeout= mysql->options.write_timeout; - vio_timeout(net->vio, 1, net->write_timeout); + net_set_write_timeout(net, mysql->options.write_timeout); if (mysql->options.max_allowed_packet) net->max_packet_size= mysql->options.max_allowed_packet; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b5100c15473..b6170ba35f9 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -59,9 +59,6 @@ void kill_one_thread(THD *thd, ulong id); bool net_request_file(NET* net, const char* fname); char* query_table_status(THD *thd,const char *db,const char *table_name); -void net_set_write_timeout(NET *net, uint timeout); -void net_set_read_timeout(NET *net, uint timeout); - #define x_free(A) { my_free((gptr) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); } #define safeFree(x) { if(x) { my_free((gptr) x,MYF(0)); x = NULL; } } #define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1)) From dc91bc74c75f3f3e6a506dd6b20dc6c066af53ae Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Nov 2007 13:43:09 +0100 Subject: [PATCH 079/136] BUG#31793 (log event corruption causes crash): When running mysqlbinlog on a 64-bit machine with a corrupt relay log, it causes mysqlbinlog to crash. In this case, the crash is caused because a request for 18446744073709534806U bytes is issued, which apparantly can be served on a 64-bit machine (speculatively, I assume) but this causes the memcpy() issued later to copy the data to segfault. The request for the number of bytes is caused by a computation of data_len - server_vars_len where server_vars_len is corrupt in such a sense that it is > data_len. This causes a wrap-around, with the the data_len given above. This patch adds a check that if server_vars_len is greater than data_len before the substraction, and aborts reading the event in that case marking the event as invalid. It also adds checks to see that reading the server variables does not go outside the bounds of the available space, giving a limited amount of integrity check. mysql-test/r/mysqlbinlog.result: Result change. mysql-test/t/mysqlbinlog.test: Adding test that it fails gracefully for a corrupt relay log. sql/log_event.cc: Adding check that status var length does not cause wrap-around when performing subtraction. Extending get_str_len_and_pointer() to check that the string can actually be read without reading outside bounds. Adding checks when reading server variables from the Query- log_event so that the variable can really be read. Abort reading and mark the event as invalid otherwise. mysql-test/std_data/corrupt-relay-bin.000624: BitKeeper file /home/mats/devel/b31793-mysql-5.0-rpl/mysql-test/std_data/corrupt-relay-bin.000624 --- mysql-test/r/mysqlbinlog.result | 1 + mysql-test/std_data/corrupt-relay-bin.000624 | Bin 0 -> 91418 bytes mysql-test/t/mysqlbinlog.test | 4 + sql/log_event.cc | 95 ++++++++++++++++--- 4 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 mysql-test/std_data/corrupt-relay-bin.000624 diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index d16a4c39a11..9f001c293de 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -325,4 +325,5 @@ flush logs; drop table t1; 1 drop table t1; +shell> mysqlbinlog std_data/corrupt-relay-bin.000624 > var/tmp/bug31793.sql End of 5.0 tests diff --git a/mysql-test/std_data/corrupt-relay-bin.000624 b/mysql-test/std_data/corrupt-relay-bin.000624 new file mode 100644 index 0000000000000000000000000000000000000000..21b4901211c939eff162cc9e3d12ea56240c0b65 GIT binary patch literal 91418 zcmdsg2Y_8wwe}E-6-7`~RJ@O;Z-P#e)5}0YPP=hPW)fy5U=WQd0|};?48~vqpCCnw z4a5ebf>IQbA}9g^3W|Ufp9NIj14SP{`eQ-F!u!@fXP>fXpSkzk%Z>NuDq%8vW^vB` zR$ptc{m+$aH+=gWFIn)yn@0Nj-qP3Cw-W#K_3hGU&Q@j{)~tyQlM|aaZC<-&V%AZc z*3DYC@hG-l_Qzh%?tRbh+p}*MeD>_?TiCbDK8)Orp#J*wmu9|yXZH2_ZCl>HZWf+k zwxTMUrI_>}^rQ43@h5%|U3mr`WG<-B_{{72`VIi;RqPSI{LW|d|IkbD#r(d$o%r8( z`L{m$U!NZ>7#g8p-Iadzl~|^K`ub)Z^t^jMKwqR}Uy0v!*za?)yY=(9@T-EHSB zldBWjqtPO7JnCD!Vavqk$=cctlN)QJQLuP4tj#4K=Qri<3q#IK&?Ky zczAi>jVvA+3cN*ZeSER-4fZqR%a-8Bu{Ja^9*vB%FO%;@W8=%mqVe&ekp*Ln!qD)N z(P(UJXz|GYwRfyocg)0=+Du0usP$`#V$V{QS*l%AltEn`RNVf7nyI*>g!&^l%>ONIQo3z~#^Y@1qivuu zPekKY_>Z^@4NkU~(a^1F&~Qw`1AA|{rfQm|okIgCs)j3rBl-Zr@mm=j$FrqRwgJb* zJI}6xdWP~P_{**Iojy*sIvh))(XquNwV6wol30Y0o#nx3gnxw@+xEM4OE*l_k95~| z6wS8HFs#=@$ICa$hK7_^j+6feAV(bUkUX7fpT78rh=aP zd8g8Izv&~fsn|Zx?OCQ78is1C^|}=(fnxZI9=JOGrKpzK@VQB;*4cBPi~VM5u&=MO ziMym+iaFU1NwH?@ieWe*MA$M+Pjy3EsT&Y&*Q?usrB;$+UzFlkV?$;zDQ^8Wx<`st z9fnxS$C()012x@-VK6na&xshjE*T0#BikYx>s6-_)6ct6FxDgwuQ;8S-oGv8tL-8W zuB-Zv=V@N3N1<*RifK8%6?uMLa}9`enLNznE+0Mjz3jR7-JWtBhH7Z*j^l?`5L&Jg zd5UiaKG@p#>XELX^uONRAsTU^(YXt#K&IF?rli zvrTFJHM&QRiypVs8pj^DX=n};-9{ew%nuRg+%F0-i+|YCC2bgoK!!#f|8TO^nW|gS zD8@hJ8^J4rQdMTV_><=orPW==+`w)O&Z&tVMi zWNNEoNEs{|3Kq^xoF+KVQzJ+*fXoG-<6^8h8XdBfzQ;nz7_B%mU9uPfD~lix^%mhr zW}3RA>bB$B0|*jbg!h($uXICoVB815>=Y&T6N%yBXao)%ez`;+4(R*SmZXtn-$!XD zue>GO$y8Y$z?Qz2IGOmVX`LP!2n!OvPC?ig01Pq^IN4t2Yn7tI>AVHgGVv3JV(7Y~ zxJAZR4b{YNkMtMu_|V4)k6UDT+|HKBSx7#W@%Tz&yiz=}P?D3ajz@E$WJ9k*vXNxI z3vBfed+`}{k*zZ0)%t7nj=Ho=ayp?2Y}Ev7$<-z8TPozgI-8j4j)bWW`lV3vcEtS?Tk_ji<%Xkz6xHM#l@jx=w)=kn;It0mb)LfDtaLCowZ$Cq5yfHx| z^?*oSz2;n6x~L6DcSz=u!~q;9yW^mdhSRa}a5PJGY%(5}X=!juO3)~HBwNp;Enh7| z<7;f`Lv5gOa5);BY%il>Qrs}5oCs$brd+X9RaY%aZlK<1I2jfy(^@D$;Fpo1ETFOL z`Gm%iGBoD1r5Vsv$!A*2LH0OLprH?HlvX#PpA=LR zVJ=DwKZIohM;v&=$C+fVIN$T;Hs_d4t5-};)KKUiu5Fo^tSucKn%lp1>(<#@S8Q3c zcEeGV8#ip)xMgzos*UUCY~3_#^|lRjR&7K>!iLE?D>hHAUA1mv4zbi6RhgrjbG%Xd zi>koZDYos*UNgCV9bPDm#)8qIC6r#6+ds6S=5JhC^H*$s+r;K0`nS}^)@+>EGEfUv zY@XOw3-R@aBl;(6W0S|MU%74qzfI4^k{u|N&sA*;+mfY6=F&dqOHXq%7RRP)g9_Xu zyT7(|&BW%3+S=7~(;Y2v@?D=NPF^FkxzGIqEuGYc&3#PdQMqYW*;s9ei)vO5kM+yi1- z9ynMqvo2);EXrUjT1miGkc~$#Bs4xKla2rQA}y_LLpB~4Wh2w_oNO`4RcU~ zY_Jv{6r~Uq*oYuB+caFbKuJyp-(gnQb*ZYDglnmJT*{)^8UH=+Z`k_2zBGXT3jVS) zvjDAc98>lJ)n>+_FY8cZ-zl_0Wi1~Xd^x03bOnO$xU;D;lBwa`TNeY* z@FL=#Gej|`LgC-p(#I1q2M6qjZ_e*%qk?7{bzKQe%W`bpusjb900uJXq3UUVU4c5w zUMVM5%p*!06|TIPUg>k&^SQkUHZinp4QVacGgQ~sL&MSQW~c`E4jhUG&rPAs@7Z&I zw~ZX}h^SUGLFQz8S&)nFS`L45*AUw~EShA_g`z0TkB*HT$u!H6ad$0^^Mgx?SAHO} zKf&={wsd?Oa14uZWIhKc+skmskw8P?j%|yUYy>~L7qhRIk{xYF)r-%kA zqf@>@OGXmQY!_t&{bOsM>8g$e`L;seaY7#*x~_t3wPSbJ%GrzmpylC#fbag&7S*(ZFm(=h+ahvM)N>sI62u~=6;pZ zCYe@OpkW40b5Nnmg{j%drzj2ukB)1aj>6pvR{UXNp|Iv)<1tWD1k6)*(N<$I9y-6j!7iVINBJ0u@B+&Z_}oqmf%qcD{o^S##g?82Kv=@MfrQYnipib}6Tc)So3+++vef};&M&bn-M3tH zdZ_5Nbde~eiew!PuxJTVl|Y^ebK~Qd>1#ZMt-A1Nw!|2e%_fe*f6)){hnqd9-ZNyfW$>jVVwzR1YIe%}toO80( z*{XZ+C_9#wDqh1hp>3cg$exg!clmel2Bdl?Y9;~vky(On(g z+^n*TVxxsNvyzNYK|HR$ozVD$OgtWEOY_N8%V#J8jqyl@%jXflx&tN;beOm4SA|W zp@TpsI)OAtwNv9^Q(IOsRgx6vXme8Aaqpc3$Lw3<%vEZ1S^f7eS~|K7mt;^>RT&(d z><$P=+~aZM1R15E2$>kB_%vAzML07H(A?>-6z(InOp0NH5TRN=`UA0iuRat`s zC)>+#Ojo@|X%?MwwhMcK>a}K?hLy`Q=yXo5q@m;M(v|lcd zXgS&HXfzek1`X$c$%43&h&B?1d>?GcKiHd9+y+a1shp)a*$%Ok=7fP6grV-B=S&YZo94@Drmy;z8lm5_ zQj)|KS&AI1*lTY6HM)nTO8nf^u>wn>EYG0$t~x-*RZp;`_qD-Q z7nE}qC)**e^4y^A_}Bz9)ICQx@P((iK2D(Ha3@-ED{+-3a#dCmZ2dL5hpVQwe(}^z zas!c8aB-lK!rE9_6|7&u7un+hVybyEUt}R$dS@HH$QKf(N?n{RpUcU1h^Z6{?elJg z(#xy0OjTn2()1xz6}U)8 zBZ=m+Tw`hhkqFKzn+2!ps9z9Uc?nw;g22zQrGFrOn0zW1(vDB?NXce}G)}fUTXhc} zW%*n-EX6{K3M0{C+fkuz^W-lHkWdDQ{va*!VXN85nFG!*DpOPXVlH@?_-aVTR}ZqK-QkoZpUTQ=l?X_dLgZwt^Hui%f+H@n z@@x!<=1__~nfI^YSiPR5bPa`$ZL6AtKc|dow0}*AEJ_eb{W(fmZDvaYZMccgP7q1S zW+^L9wwDnp(YvXCWx_XQde<~{n|hXHPJ6+-`pzSS#)wQl`hG)8Z)ih4jxCoDPPUiP z5K`=|pFu2G!oz+`+rC6Zgif=*@PBEE2By#lTelznHNT@H0Tc}bo$jajO8Pu6F5?`nVRKf zdl`-rHOt*w8%K%>1A;}>O~Rm2Ze-vwLSw1S=pDtD#@aA?uM>@4RyX5hdm0USlNhV> zqe%>x!qC+dIFXAIGp5L-Xb4SW1+#bE?+A~>WO)3AE&TyWg;x76W{G%Y(!t60G#*l~ zkfy`L^Kea<4Z)=@7z}I3yuw1}uz<$F|DVuUCYn4l9VfD-$u^vj(?rverFb~mUPglz zk1`va&cn4B9Eh24;Rm87-PLpp6-~$GO93mQ52u;jEDEJ`vKTd$WNe0N?f1ss$ z8-ScD0+NXbC)>+_$c;xXiq%ze%yk`uL0rAWcofiB`$yXHH_OoYLcG)l8fS`VWX9vo z3E5soqhV4(SLreV&BFZ|G=D4=57upL&c5NjeX@h3L1dH?Kt$|HhaO0QnbP={z_Z9I=7W+`{SqC(pTDus810Y zJJb7|Y)><`G-ybyFm(o?I~YNOX<>|ynmb1=1Puk&e*7uI<3ln$2L47%SGIx2St1^p zqTytF8V_mEka$NnSD;Sm(l1< z=JG}VBt#b6CYk%Nh%NoOjY|FJMMN_B;ADFl5xF5&;wTQnVJqwsTusGnyV8R`1#NZS z(}c#542_?$B@Ob?OahRoiZ=Yxax^&E9TW}2!i--G)1pJim{AY&PA6X*x<#{g+68DV zl%cVPEm2m#RWzQ7w%XP?5&8=qx}JGXA1n35_Kp8dSOa9$TU-R0s`hTjwixI+g80RkiE7=HUuV z9do_wL16muc!R)0x;D!ia%O}-R;=9ZvKzh9>^5}MdF4}2Ioax5^vq2?)o?0}?h9+M z7isfO2M*Mz5RTAiP|M=J@QITy^t5oCSYEO4b` zdokzobUri|*$L^;*-M^7Vmu~lCMvM}nk^mQhJ;@xB9awYIN6>?gfd{6dMFfFFboI- zn=G4B38+8P3GhOJ1vcBJNflEJ_kqtNK;9?=WGh>GM;m}#UJeK++tYwhxwimF{U7;cH0xoKkamW>;huU$Q`bzrZ_*2dqQ zoY*qC9M@G%;)bd%@zSb|n^!NNT)TcEyOo69zzFZfp;RO^2JXJbN%(B@QvHI{dh}vx zKkmlsKF)dpEghY`bLZ_~WYmqoH|maq6BoXMvtu|W>*8Vq%g3yJt1h*J zYWzy+a}U3eo;x>(qVvxkScV@sx@8%fK^FkHZr#MmH`UM`zaDCS*>h9Ko#uK^X3zbc zHWb3OqC&_#c}})E>voULY_6tcP}UdGRqDu3Q&PHr4`P*1%hdDUFQTQFwt>d=A{tqR zkCW|XG%PBamfW$3^sYk(+@YQEm5l=^nRZqw!KK-ev2FC?#>HIdr-0zmd z!O8YA9P+F~oOs7YXbw)c^Q;3}smO&)dfDQvgS7s=7s2u2@5OoE)E-idboq;E>Dr_Y zf_>|}j*XyH^*{@asBU;BMz8rk?jeXm$5bN4tcOkM*#F0#`;ScyqLO7qZxY!k^MX0q zUS=ctq&CJzxM>SKWKt^&OI|rR+@7)#>S@d)X18`@dPN~c?e9(8^7(|33P$feY^kpe zHG7u`2nC7H+d+u#*aMGP3CuQyvC)>-MR7`}X5doE+(Eo(No)}#T zd4|QtRW9si8%eiwL9X}NhgjvXgo_GjEM-f7X+zQeKtv;RpE%iGMx$u2isC)>+#l%1gF zX8|y?i4Fh&kLgcP7lP}-R}mn0%K$lsE%D&G6+ph8#xy0F>6ujBB_|qVZ~`)YJ#EalgVzf<6;isPft)6 znCi?|6I0zUW2*17C7St|d@4)%gCZK4(&c2UGgbGXQB=Cz1ZLey7|jNoM@pAmT|mIm zh=U~L6ez=6fMef(BRC$H!Lf`j@wwpmsmgHtM1&*rNI2PEhNCDP1vuzJM_k*@A`Cbr zlmg5$I)xJ^1vD<*kI;DT?SfxRCh!rq#M6SUpm9yP#^q$IqtTScZJb}MpmBdGW2#u= zw*DI3BjeLBRdSV?1{tSw8R!VrN;(h=OtsT%iK(71W2yt$(&9EW?!zJ)nP0`pR%fd2 zK|}DX3RN{6HMVR6XDhj1OlAV9PPkV4#X2V3F|7>%Tyel>MSk~6PY z%j)O1f)ZMSv%Zdw)Xy7sa>%4SY2`>?Bk`+#l<-x$JDFeA`fGF#Up1C;l?Ahg>L?~V zw-JE=NOSBE5hNx|+sVANX)fX_0OBYF$UGS!Ti6mW zAL6Gf19EM7EXK)J2c)T3tZ^MuzLQL!r$#LC(ta=URpzC&{u8o{8kKRHzs$r1txG_S{c5d1i`4Eajra6?#g>Me%jmoNRSr=yon*7b+OGgMolJ zsY6_(A)s`%%zl@1(Y*$-N+@y>rHNi((h|+nNj{ZT(?3NtGH;5L?P)Y1rc$m>#=_uA z9ys`{a0M{3{EBemwqPn&S+wbO86M}dC0>rkPgTa_8|9{gldXLPEU0c4BQd994 zk*zXQ(fVt2yO0-51roCf10%SS-fI;%#-|ZI@4d!%rj$yC1__XbA|PbD zcRGNUh7&-rbDg){cBn>v=vp|CZrN%*KnFP;0dqq=QXIcz;-T1Ud@XzKbGB!*jA`TU z0~fh#14rmXFY+TFK`VykI-%w{boqf)I~RS9Ke6Y2R~rJblPCaLMvIf}WdSJhT-A8m zmWp$B)agdeGAcSF zFRc5f;x)xZgY)Q>oHn@VS>;^B$?l+BL?cOT$8yL)!ufKV64p#!^z?&h%SS~nBG2_U zwzNwdXgps;BQt88Y%ilRb%b8ljDhAu3<$GnFc{34gIgSWOMV-GyjTPzQ?i_FF9T9kvbo$h3nerg!@=Srj)O~YnZ9kLWH0pzjYDNGH(p z;ioFcb$f|$WWvG8_A(qr;Yf35u?ON(t%A*5#Xx?Hi_V>|DbIR*FCsJ!m!YvsotBoi zAsqiMqLI}sIN4rCqcb&&H!YxT-ylQeY__zb4MaYhOk_wy)T{8{x*Pvsh+;yvIwH^9 zL1zPPRIWbrB-PkpNS4u!EaZ2oW@e>zbRp z7)4bG8o9%`cp(9Dg$$5W+0uL4konh$fMhn2lkH_drn8C23mTYRO3h@3hGdSCn<`sw z6Mw#l(6~y5#><9jX>%KB>{pHkC%Xfpp-_$x2|~?QF^GWGWn4GD+`5tb{Hv*XjdHzTw1P>=_;n&vkYL?!#mRPvuNs%1Wjk4N5a-q9 zeAW7EbP->%3lOHxE8y`IZctzsDLd#$cJ16{FY(D{jcz)d65qaJjQHw08DAaBmM(0= zx#|}I$!s|%Tb-}E2axG(Ij&AHs3(LfOel1i81d6YhW(;(LgNM*8V|Fj%i2KW1tJ<* z@`sb{Wi+Ns{^%}lvBzv$=INqF5S#VHmX{}goI?qYZ_D7=!j>*=1CG7R;oxL@8IIy` zm10A+ikrdElgHq|MPaU!o7Z0)u2KjDZ#|6QxLF3rj5pE}uRr0-%D&b0#xy0Y&E^@!1Mxk0Ee-aqvnrs#ld+4(a}MixVx3)SAM`Nw|h*K(?Og^uAu#RDz_i3t&pUA-<7mPBZ%k& z)zo<@S4<~DGnuWco?;r1b=}wex*uXlQ-s@4jp?L3eeVBa&;6yu{%@D(w!Fykbi-AH zAhayc39P{KkcW)wKITfU8lReSUVP7zmoaC z<>iA{P7tf?a))Hz#9?fSCVeKK%6`g%ax^&E9SRL=&`<}p_$nM!ax|PI02;W<)Uopy znwFz+@sWha5*Zr5VoS@~Kx3hZM%LiK$@VfDf|YN5&R`+waNrt3WW9(8Y1u!qrQD2* z&TCo24{@VU;3@T}jz(`yu{=`?l_*5TFi>6jH4FKcZ)&rgvzA_o-(ZL@E6cSfa#B_` z=VW`DlcvmVHwQIkP@_?52AYjEl*(CV7jxSUi;ZcBbBX-y0CEshGVLcGO}qX+86(Yo z8!hE->FhisX_{}$avfH>dp1?73HNPq!`%abIOrcX2Na zqBYlzEVZsicA&fPn+z*z%B}nII@<63w&!z4IOTv-8aQOBYASff2ysOUq*&MSkE`en zpPK~tH|)7-c4YFYEV#?c1(%cEfdn@fs!&p}#X~>yHW0U*E($IIvW+eAxCY;-49JbL z1VTKkhm)-iNK-^h^@{P*@_&C;kVP$vSYVnxa|6BXsZZ3Q5w^tI?m6y^#Fy-Fw`uZD?sl; zc~UG5mv`Mv&z(CW+<80Z`3`Qysw;lo#>r_P3N{Rb$oE{hL>B&N_}nDM^VxIra2emI zEXFsLi!mqLAu(dz+=DyB2LM~sWn^VDWY%yxpL;uyYb;zsvO zjLYM-!zYR3KPCz>G1XaYiO(a%H!3sLY8e{wPy|l4I#cxs8YUbin_YndG%Uk%2$`sG!9+KMxW}t8Y~(L7S4>lpyfm1Kz(%a z@bbVLSv)cnc#G&eXcQ2$~}(b)L%v1ojJXk@_{ePc8_WGQ`beA$u+e+d?k zhRer?hNFQci}5?S0Bir+q240=$V~LFV+0p+w*$JP<2aszB)X0}zA&K+tPCdtRcUpg zpJ)sZMg4csZo{w`%pG(E3X zu6mmYN0x8oWUF&k_rTGaeB-6>CPaK0B9E{oO1HF%$al)+oRh7NNKHAT*|>|;``<~JDWj^*YYqgc-A3|2DZotX$9+~V&Hrs}JPR%Bw7lM3YfiSa{W4l&tWtcj1Da!Gdj25KW59C z+VI50=9aAM0QTrF7(@Sk3BL_dCF#pVrkqa=v1&J{Ax zFxPWcT&p=y%MAKl+D@3-Xn8Oi;a}n0ERscAqBdw+gYa@{Th~l%o~W%|J(t>i*v1y> z0O9c@m+zLz<#B9@>Hw|E<;~@C$;oy|E*lpVD#+y;Q7*IavGv#J9=R-rk3#X4-Go6^ zfn*j&Q^nU${3kKhIWnfYk1g%j22*{voT)h34lz~ZWOoIo+EmU|t-nUMGL;Z^#Z1L2 z`skQON+Rdf(L4`T)_M556NstKmoe4;C(;rn=vviOx0N#$C)**WYMkk-z*KKNeg-xo zH~ee{Hsn`qQ(AwGVCmTS;^Am?`O-1`fe@2>M#Tk$l(j52%~`7KGUWdHj&vwbSd&%MRHb-8FK!f{u}u^?%I3eCxe%@I zPWOl$UOV5LTBs6n2aBaT4AdG;hgvvzsskN0=n}+lj|i9OtU8$_>xVL-JC`ld7}HjT z?idk|tf`5UtuA!kgGbS>auuki=h}3aU5$=XJEj^L&7@@?KZVfvFBuvGr_$1&+d$*k zax^&E9TW|NU7m_MDtS3*m35gc@GL{AK|1b(wB^4|(3me7|Ena8vb4rxmh8s*)(`#1 zI<|9-vdD-cORZq$MdLSk?VF z?{wOazssccXKd-DHXN4Y%cYf*t-h5#p*s!AMdMaf=02jM7za`j7&nyGS!WU&FS{#F z38oTBb?INRrPH=&JGAF`b;r~q%!=|A)pIq6Ci#bT3w2Ml7R%eAwb(eP3G&*9=#^-y zZL1deT_P7{6R|njUgjcse?v05*u-G~i*6j#bqq}_v=yrgwHV9$8;M%8U~&g zxSkeSPCf8ZVu~;;%}0NR7NAj2T0NS={~x9OrU`$o^8Xnk|JOk2Kt_#|?PdP&Oe%lt z$7tK%@?6L7MySelhiK)^0lS_}Xsk@o zD9H7<*i!Bqv(D=y%kxyvx1f7485Av{A*#k`V1i+DpkqDx^kPx2pJdNX!wFlJ>kpT6 z5huIja8a7EjjzPERTonTSS+I}iVD-v1Q#tlhq&lCnM{9xE$!0=8XpnS$h-_rwwKYM z&>)wi1003Imf>QYA|+T{T-bzbX^?`+=UprsXFMhEa{ng?kN=e6vG*rw$!`OX(?mS7 zmLE>Gm+>$Zlq>SZFtvDo35`A^9*84U)5Uc46pwhIkZV&KO-zKX`xNc^CuM5(HJ_%X zT%UR8)hsf2j<4ysWWY8&7xx+=Xm{#$%W^T9*$QxhUiSWJ;z@M-9$?R%yCtpj&+V$A ztKv+$7b%_{1vpUYo4TrbwiPHLjtn$>Zt6gM>1Sxa|JdYl0kVi7F#d7P}}t>9$P-lVCWqtB%+KUd^_LgNCqWI!DypK1F+ zWoUe+91Tu(M@0kYxbZ)-4oEyA4UE)ds*TFgc=9|#IR&&&@+;e4{cKeLtz-r80d9sKh5u zIN9o4#4BA(mr`{r-))gAYIzM~@SHUgwQ;JNk`pKAiNcWe0JZ)a-ILcV_5kHJBP-y+ zU1bw#OboNngrU&uSI|wneV$nU^P)5mS9xq{_cnCX`7$_M7M5_b)w!yB;IImwl29?k z$rHzZr8&OjC>7v1>k9OHOa>}P4?LxaVBOGF|mf{ zJeQjBZL=tNoFY;5I7 z07kw<&%Iqw*4v?Lhjo-lFd)WIeZ|7$mAX^MAi2ncb#6`oPGQf@Z@9)QRJP97iUN>% z+?;GL3&1oUx2YI58k~|AIzz#@&SreP2QDI3`GLs&q>f&CF)cl-4Rv&lh{nrd(M)F5 zIN4rCqgeLg=`lSXRE>m~Vw2s&-3%5hB4!y@cIKx)6fD|Nm(YIyPzJ^4*b)!@@l%xr zC`sl`zjHQtgOY!R%fd2LE{-KYZVX~xr`9`gA9>V*wUNZK;%jh zk<9*avb~H*Q9h=Gb+~eZjd0gBoUqi(uKy^Y@xWIJjX%lIct6b@F zvenUOO6fLEmQ+x>H^`VOR=TafM)!z$1EwOSOIZQjvW84%etIqZtF(o@z*OoL#5qsM zm}(tc;>qwJ^ykI+3Ze1XSy<(LGF6OhCbs7ivSylC$~k2#{dO ziN6x}Fit?BZbXOB3S4#4Rm4?)6}gH6zJso&r9HQ2po;vfUDusRQ9|2N>KZa2mKKJ( z8R@3w*UhHVvB$FK<`@08A`Q2QY?K*1PPV!Gs zPmySai@sCNMV#!8!$rmPE1ma5))m?ZM@vz(!?cAaxM;6$5UcdvBP7izZ7{-?_HV<9 z{h^3P7FKYwy^IF#49xcph+ZuED_xtNpFv8;U^594+h8D34s6(jtSR~M3%*H+%#b1S zAY0;TO#D=3NA~V=pM#UFj!09EY~y@r1)t+yk+HJuLF=#46UHJrmlYp9(G3j!vYW{c zKJ_hPs$FDEWnNE9JjdJ$Q{7X}RGe&wn5uEIx&l+(Co)y$$hQ6(-NRHxM^;o;%#n?i zm1^j^ksbD9fjA1R5=VB)jl??7l5y1s*%F<~OForV)z3sYvYay~Tb--A2aaZQ&bWND zXvgI_=lj1+P%M-|vG+~1#Lti6%gRvvT!bRC#xy0>T;U+nY%=!CUKv-YT}4rDx&30al7A2 zO!XESQ@w#Ly|0bP=K&FoOk;Ag)tRb$(CAD-<-FSnkrgsTe#Vym(S|$mu!snGcX4AD zC)>-26urANO^L?t8g2kYZor`ME}9a4cJi93Q>rCDYIIU7PgW-(=7I>FwEViW4lM7e=@+EDThfeT?)- z(=l~E^a90E!qQXCX~aNz+9%j^AKiwx@;gy#Guz0?R#!gVBeg}_Sjc=Bj;33hPG`Ev zHX62)8*`LoJ}Aj6mhcX~n|OSWdnHGjPh?A90UNRYxCXX>W-E$j)lT3@XF+GBFiy6Y z;V4m}Y|IfFgLTVvsdlRCaO91q=AHlK9zx?SGBozOmzJ(<0}V?=BWuOxWP2HnvR3SL z>XfP5ae;gKR_wx%(6#r`t{<5ILfT5?aZk*B>;Y*RU=s87OaoWEVc}ny`+!r8DTL@% zhqJ8=;NUJsBDqQ4Lu+={xsdnx>W^p}Ps(j$>Ty2Gmj2L2K=i1n^fN8P$@Vf|7qv{W zRI1~oiiv4Dq-8W0L+M#LE(wTA3-0rNOlX`bqCu|16Kv_J1PyFk=UpBXH{ao=J9s=1 zF6CBq+@pnKWnn$CFis)xN(TZJTnF_h^h*5FLws2|Zh5kti#XXGhl_Y-IPMHb+z4r> zn^H8J<|g3I(Iy=J6Mjlte!a|A-N2SEZo^iMinc0~X-;;>K_hkKQd4ChR}To#P>ue+ zrtYoT^L|3(Mp358tsZ7e{MN2kWaDq5Y-CA5PPUiP=u8su3l9(?H^~tBC0jbBjX>uw zA|hF!!^!qCBE>)l+DaQVl)*$>VS+0f&5|S_0v(+uzBEh%>c1d3ZV}-iqxUFV$~6vm z-smZ6sCXC|gbKAD;hr|QSalWmZAYq$;iw7}K~}~~)k6~Jiyo+6p1h>-rSz%J3ms2h zYRuRJH+k|hhk3Dt_P1XWjz5>-c*TRXlxwo=JdR#q*@1>k4Vq3>HF7Mk4i`qZea)$> zN9eZw`AHyqDc3yr|o^<78TV;XT%xOmeG)}ZtNV+~PYPBrs+WKpBPx_|l z$rno-C^}PHKULv%cwx9ewwZ3IXFo(7zuSG1rpJISo!Ewr*>(4OJ^<={siU0@ui|8@ zGgbGXQS4jEDcNKo1BQx|jj>G)?c=$VJ7@|f*NhgYWYf-hnDBUx43B%+(mQ}hGubp* zrr~)a9+?-$$@VfHf)~aCLG=nK;P@0~Gt+!3Of=9;6IX$zMxVkL`~`zFC5XK4*M!J? z86p#GiH3i+ipcHdY8PZnCq0#D#8>t8J;sDBHSoz~6n-!T^7p$;8ndRpDyLJPLJDh_ jn@0NjUXN|rXM*0GHi$l(C)TalHf!bD4YOg*EY18s!pkWV literal 0 HcmV?d00001 diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 451eef17108..c83fe94f2eb 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -237,4 +237,8 @@ let $c= `select $a=$b`; --echo $c drop table t1; +echo shell> mysqlbinlog std_data/corrupt-relay-bin.000624 > var/tmp/bug31793.sql; +error 1; +exec $MYSQL_BINLOG $MYSQL_TEST_DIR/std_data/corrupt-relay-bin.000624 > $MYSQLTEST_VARDIR/tmp/bug31793.sql; + --echo End of 5.0 tests diff --git a/sql/log_event.cc b/sql/log_event.cc index 3899e772bf8..0e257bf7f6c 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1400,17 +1400,46 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, /* 2 utility functions for the next method */ -/* - Get the pointer for a string (src) that contains the length in - the first byte. Set the output string (dst) to the string value - and place the length of the string in the byte after the string. +/** + Read a string with length from memory. + + This function reads the string-with-length stored at + src and extract the length into *len and + a pointer to the start of the string into *dst. The + string can then be copied using memcpy() with the + number of bytes given in *len. + + @param src Pointer to variable holding a pointer to the memory to + read the string from. + @param dst Pointer to variable holding a pointer where the actual + string starts. Starting from this position, the string + can be copied using @c memcpy(). + @param len Pointer to variable where the length will be stored. + @param end One-past-the-end of the memory where the string is + stored. + + @return Zero if the entire string can be copied successfully, + @c UINT_MAX if the length could not be read from memory + (that is, if *src >= end), otherwise the + number of bytes that are missing to read the full + string, which happends *dst + *len >= end. */ -static void get_str_len_and_pointer(const Log_event::Byte **src, - const char **dst, - uint *len) +static int +get_str_len_and_pointer(const Log_event::Byte **src, + const char **dst, + uint *len, + const Log_event::Byte *end) { - if ((*len= **src)) - *dst= (char *)*src + 1; // Will be copied later + if (*src >= end) + return -1; // Will be UINT_MAX in two-complement arithmetics + uint length= **src; + if (length > 0) + { + if (*src + length >= end) + return *src + length - end; // Number of bytes missing + *dst= (char *)*src + 1; // Will be copied later + } + *len= length; (*src)+= *len + 1; } @@ -1424,6 +1453,23 @@ static void copy_str_and_move(const char **src, *(*dst)++= 0; } + +/** + Macro to check that there is enough space to read from memory. + + @param PTR Pointer to memory + @param END End of memory + @param CNT Number of bytes that should be read. + */ +#define CHECK_SPACE(PTR,END,CNT) \ + do { \ + DBUG_ASSERT((PTR) + (CNT) <= (END)); \ + if ((PTR) + (CNT) > (END)) { \ + query= 0; \ + DBUG_VOID_RETURN; \ + } \ + } while (0) + /* Query_log_event::Query_log_event() This is used by the SQL slave thread to prepare the event before execution. @@ -1475,6 +1521,17 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, if (tmp) { status_vars_len= uint2korr(buf + Q_STATUS_VARS_LEN_OFFSET); + /* + Check if status variable length is corrupt and will lead to very + wrong data. We could be even more strict and require data_len to + be even bigger, but this will suffice to catch most corruption + errors that can lead to a crash. + */ + if (status_vars_len >= min(data_len + 1, MAX_SIZE_LOG_EVENT_STATUS)) + { + query= 0; + DBUG_VOID_RETURN; + } data_len-= status_vars_len; DBUG_PRINT("info", ("Query_log_event has status_vars_len: %u", (uint) status_vars_len)); @@ -1494,6 +1551,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, { switch (*pos++) { case Q_FLAGS2_CODE: + CHECK_SPACE(pos, end, 4); flags2_inited= 1; flags2= uint4korr(pos); DBUG_PRINT("info",("In Query_log_event, read flags2: %lu", (ulong) flags2)); @@ -1504,6 +1562,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, #ifndef DBUG_OFF char buff[22]; #endif + CHECK_SPACE(pos, end, 8); sql_mode_inited= 1; sql_mode= (ulong) uint8korr(pos); // QQ: Fix when sql_mode is ulonglong DBUG_PRINT("info",("In Query_log_event, read sql_mode: %s", @@ -1512,15 +1571,21 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, break; } case Q_CATALOG_NZ_CODE: - get_str_len_and_pointer(&pos, &catalog, &catalog_len); + if (get_str_len_and_pointer(&pos, &catalog, &catalog_len, end)) + { + query= 0; + DBUG_VOID_RETURN; + } break; case Q_AUTO_INCREMENT: + CHECK_SPACE(pos, end, 4); auto_increment_increment= uint2korr(pos); auto_increment_offset= uint2korr(pos+2); pos+= 4; break; case Q_CHARSET_CODE: { + CHECK_SPACE(pos, end, 6); charset_inited= 1; memcpy(charset, pos, 6); pos+= 6; @@ -1528,20 +1593,28 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, } case Q_TIME_ZONE_CODE: { - get_str_len_and_pointer(&pos, &time_zone_str, &time_zone_len); + if (get_str_len_and_pointer(&pos, &time_zone_str, &time_zone_len, end)) + { + query= 0; + DBUG_VOID_RETURN; + } break; } case Q_CATALOG_CODE: /* for 5.0.x where 0<=x<=3 masters */ + CHECK_SPACE(pos, end, 1); if ((catalog_len= *pos)) catalog= (char*) pos+1; // Will be copied later + CHECK_SPACE(pos, end, catalog_len + 2); pos+= catalog_len+2; // leap over end 0 catalog_nz= 0; // catalog has end 0 in event break; case Q_LC_TIME_NAMES_CODE: + CHECK_SPACE(pos, end, 2); lc_time_names_number= uint2korr(pos); pos+= 2; break; case Q_CHARSET_DATABASE_CODE: + CHECK_SPACE(pos, end, 2); charset_database_number= uint2korr(pos); pos+= 2; break; From b3c4bc6e7dbc1811a2cf11dae822dc9166d9b36b Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 12 Nov 2007 22:02:12 +0100 Subject: [PATCH 080/136] BUG#31793 (log event corruption causes crash): Corrections to get_str_len_and_pointer(). sql/log_event.cc: Adding missing return at end of get_str_len_and_pointer() and correcting computation of missing bytes. --- sql/log_event.cc | 47 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index f2b7fcbd236..5c3fcf2f86b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1436,11 +1436,12 @@ get_str_len_and_pointer(const Log_event::Byte **src, if (length > 0) { if (*src + length >= end) - return *src + length - end; // Number of bytes missing + return *src + length - end + 1; // Number of bytes missing *dst= (char *)*src + 1; // Will be copied later } *len= length; - (*src)+= *len + 1; + *src+= length + 1; + return 0; } static void copy_str_and_move(const char **src, @@ -1454,6 +1455,23 @@ static void copy_str_and_move(const char **src, } +static char const *code_name(int code) { + char buf[255]; + switch (code) { + case Q_FLAGS2_CODE: return "Q_FLAGS2_CODE"; + case Q_SQL_MODE_CODE: return "Q_SQL_MODE_CODE"; + case Q_CATALOG_CODE: return "Q_CATALOG_CODE"; + case Q_AUTO_INCREMENT: return "Q_AUTO_INCREMENT"; + case Q_CHARSET_CODE: return "Q_CHARSET_CODE"; + case Q_TIME_ZONE_CODE: return "Q_TIME_ZONE_CODE"; + case Q_CATALOG_NZ_CODE: return "Q_CATALOG_NZ_CODE"; + case Q_LC_TIME_NAMES_CODE: return "Q_LC_TIME_NAMES_CODE"; + case Q_CHARSET_DATABASE_CODE: return "Q_CHARSET_DATABASE_CODE"; + } + sprintf(buf, "CODE#%d", code); + return buf; +} + /** Macro to check that there is enough space to read from memory. @@ -1461,13 +1479,15 @@ static void copy_str_and_move(const char **src, @param END End of memory @param CNT Number of bytes that should be read. */ -#define CHECK_SPACE(PTR,END,CNT) \ - do { \ - DBUG_ASSERT((PTR) + (CNT) <= (END)); \ - if ((PTR) + (CNT) > (END)) { \ - query= 0; \ - DBUG_VOID_RETURN; \ - } \ +#define CHECK_SPACE(PTR,END,CNT) \ + do { \ + DBUG_PRINT("info", ("Read %s", code_name(pos[-1]))); \ + DBUG_ASSERT((PTR) + (CNT) <= (END)); \ + if ((PTR) + (CNT) > (END)) { \ + DBUG_PRINT("info", ("query= 0")); \ + query= 0; \ + DBUG_VOID_RETURN; \ + } \ } while (0) /* @@ -1527,8 +1547,10 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, be even bigger, but this will suffice to catch most corruption errors that can lead to a crash. */ - if (status_vars_len >= min(data_len + 1, MAX_SIZE_LOG_EVENT_STATUS)) + if (status_vars_len > min(data_len, MAX_SIZE_LOG_EVENT_STATUS)) { + DBUG_PRINT("info", ("status_vars_len: %d; data_len: %d; query= 0", + status_vars_len, data_len)); query= 0; DBUG_VOID_RETURN; } @@ -1571,8 +1593,11 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, break; } case Q_CATALOG_NZ_CODE: + DBUG_PRINT("info", ("case Q_CATALOG_NZ_CODE; pos: 0x%lx; end: 0x%lx", + pos, end)); if (get_str_len_and_pointer(&pos, &catalog, &catalog_len, end)) { + DBUG_PRINT("info", ("query= 0")); query= 0; DBUG_VOID_RETURN; } @@ -1595,6 +1620,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, { if (get_str_len_and_pointer(&pos, &time_zone_str, &time_zone_len, end)) { + DBUG_PRINT("info", ("Q_TIME_ZONE_CODE: query= 0")); query= 0; DBUG_VOID_RETURN; } @@ -2124,6 +2150,7 @@ end: */ thd->catalog= 0; thd->set_db(NULL, 0); /* will free the current database */ + DBUG_PRINT("info", ("end: query= 0")); thd->query= 0; // just to be sure thd->query_length= 0; VOID(pthread_mutex_unlock(&LOCK_thread_count)); From 8cc379ebab5412846c5add52f9a4e3fdb32aa54a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 13 Nov 2007 09:01:42 +0100 Subject: [PATCH 081/136] Fixes to eliminate warnings. --- sql/log_event.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 5c3fcf2f86b..13c15924210 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1455,8 +1455,10 @@ static void copy_str_and_move(const char **src, } -static char const *code_name(int code) { - char buf[255]; +static char const * +code_name(int code) +{ + static char buf[255]; switch (code) { case Q_FLAGS2_CODE: return "Q_FLAGS2_CODE"; case Q_SQL_MODE_CODE: return "Q_SQL_MODE_CODE"; @@ -1549,7 +1551,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, */ if (status_vars_len > min(data_len, MAX_SIZE_LOG_EVENT_STATUS)) { - DBUG_PRINT("info", ("status_vars_len: %d; data_len: %d; query= 0", + DBUG_PRINT("info", ("status_vars_len (%u) > data_len (%lu); query= 0", status_vars_len, data_len)); query= 0; DBUG_VOID_RETURN; @@ -1594,7 +1596,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, } case Q_CATALOG_NZ_CODE: DBUG_PRINT("info", ("case Q_CATALOG_NZ_CODE; pos: 0x%lx; end: 0x%lx", - pos, end)); + (ulong) pos, (ulong) end)); if (get_str_len_and_pointer(&pos, &catalog, &catalog_len, end)) { DBUG_PRINT("info", ("query= 0")); From c1b3466f799bf68b1f5151a2656b91ca1aea85e8 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 13 Nov 2007 09:43:29 +0100 Subject: [PATCH 082/136] Elimination of warning for unused function code_name() in non-debug mode. --- sql/log_event.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/log_event.cc b/sql/log_event.cc index 13c15924210..d22973d12a3 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1455,6 +1455,7 @@ static void copy_str_and_move(const char **src, } +#ifndef DBUG_OFF static char const * code_name(int code) { @@ -1473,6 +1474,7 @@ code_name(int code) sprintf(buf, "CODE#%d", code); return buf; } +#endif /** Macro to check that there is enough space to read from memory. From 706a8b09ae1c208adcf79d19309fcf8127973b63 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 14 Nov 2007 12:02:20 +0100 Subject: [PATCH 083/136] Bug#4692 - DISABLE/ENABLE KEYS waste a space Post-pushbuild fix Added a purecov comment and a test for coverage of parallel enable keys. myisam/mi_check.c: Bug#4692 - DISABLE/ENABLE KEYS waste a space Added purecov comment. mysql-test/r/myisam.result: Bug#4692 - DISABLE/ENABLE KEYS waste a space Added test result. mysql-test/t/myisam.test: Bug#4692 - DISABLE/ENABLE KEYS waste a space Added test for coverage of parallel enable keys. --- myisam/mi_check.c | 2 +- mysql-test/r/myisam.result | 8 ++++++++ mysql-test/t/myisam.test | 6 ++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/myisam/mi_check.c b/myisam/mi_check.c index ba308f75d24..04bb0271fa3 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -1487,7 +1487,7 @@ static int mi_drop_all_indexes(MI_CHECK *param, MI_INFO *info, my_bool force) /* Remove all key blocks of this index file from key cache. */ if ((error= flush_key_blocks(share->key_cache, share->kfile, FLUSH_IGNORE_CHANGED))) - goto end; + goto end; /* purecov: inspected */ /* Clear index root block pointers. */ for (i= 0; i < share->base.keys; i++) diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 176d0e97012..56933f45fbf 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -1830,5 +1830,13 @@ ALTER TABLE t1 ENABLE KEYS; SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +# Enable keys with parallel repair +SET @@myisam_repair_threads=2; +ALTER TABLE t1 DISABLE KEYS; +ALTER TABLE t1 ENABLE KEYS; +SET @@myisam_repair_threads=1; +CHECK TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check status OK DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index ad223dc2664..80c7a92c12f 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -1185,6 +1185,12 @@ SHOW TABLE STATUS LIKE 't1'; #--exec ls -log var/master-data/test/t1.MYI #--exec myisamchk -dvv var/master-data/test/t1.MYI #--exec myisamchk -iev var/master-data/test/t1.MYI +--echo # Enable keys with parallel repair +SET @@myisam_repair_threads=2; +ALTER TABLE t1 DISABLE KEYS; +ALTER TABLE t1 ENABLE KEYS; +SET @@myisam_repair_threads=1; +CHECK TABLE t1 EXTENDED; DROP TABLE t1; --echo End of 5.0 tests From b04cd27c9dd36af0104487439547cff4f0c79be3 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 14 Nov 2007 14:04:33 +0100 Subject: [PATCH 084/136] Reverting changes to debug printouts to ha_ndbcluster.cc. sql/ha_ndbcluster.cc: Reverting previous changes done to DBUG_ENTER strings. --- sql/ha_ndbcluster.cc | 110 +++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 5fe688acfcd..436710e3dee 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -416,7 +416,7 @@ Ndb *ha_ndbcluster::get_ndb() void ha_ndbcluster::set_rec_per_key() { - DBUG_ENTER("ha_ndbcluster::set_rec_per_key"); + DBUG_ENTER("ha_ndbcluster::get_status_const"); for (uint i=0 ; i < table_share->keys ; i++) { table->key_info[i].rec_per_key[table->key_info[i].key_parts-1]= 1; @@ -563,7 +563,7 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans) THD *thd= current_thd; int res; NdbError err= trans->getNdbError(); - DBUG_ENTER("ha_ndbcluster::ndb_err"); + DBUG_ENTER("ndb_err"); set_ndb_err(thd, err); @@ -700,7 +700,7 @@ static bool field_type_forces_var_part(enum_field_types type) bool ha_ndbcluster::set_hidden_key(NdbOperation *ndb_op, uint fieldnr, const uchar *field_ptr) { - DBUG_ENTER("ha_ndbcluster::set_hidden_key"); + DBUG_ENTER("set_hidden_key"); DBUG_RETURN(ndb_op->equal(fieldnr, (char*)field_ptr) != 0); } @@ -713,7 +713,7 @@ int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field, uint fieldnr, const uchar *field_ptr) { uint32 pack_len= field->pack_length(); - DBUG_ENTER("ha_ndbcluster::set_ndb_key"); + DBUG_ENTER("set_ndb_key"); DBUG_PRINT("enter", ("%d: %s, ndb_type: %u, len=%d", fieldnr, field->field_name, field->type(), pack_len)); @@ -736,7 +736,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, { const uchar* field_ptr= field->ptr + row_offset; uint32 pack_len= field->pack_length(); - DBUG_ENTER("ha_ndbcluster::set_ndb_value"); + DBUG_ENTER("set_ndb_value"); DBUG_PRINT("enter", ("%d: %s type: %u len=%d is_null=%s", fieldnr, field->field_name, field->type(), pack_len, field->is_null(row_offset) ? "Y" : "N")); @@ -939,7 +939,7 @@ int get_ndb_blobs_value(TABLE* table, NdbValue* value_array, int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field, uint fieldnr, uchar* buf) { - DBUG_ENTER("ha_ndbcluster::get_ndb_value"); + DBUG_ENTER("get_ndb_value"); DBUG_PRINT("enter", ("fieldnr: %d flags: %o", fieldnr, (int)(field != NULL ? field->flags : 0))); @@ -990,7 +990,7 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field, */ int ha_ndbcluster::get_ndb_partition_id(NdbOperation *ndb_op) { - DBUG_ENTER("ha_ndbcluster::get_ndb_partition_id"); + DBUG_ENTER("get_ndb_partition_id"); DBUG_RETURN(ndb_op->getValue(NdbDictionary::Column::FRAGMENT, (char *)&m_part_id) == NULL); } @@ -1049,7 +1049,7 @@ int ha_ndbcluster::get_metadata(const char *path) NDBDICT *dict= ndb->getDictionary(); const NDBTAB *tab; int error; - DBUG_ENTER("ha_ndbcluster::get_metadata"); + DBUG_ENTER("get_metadata"); DBUG_PRINT("enter", ("m_tabname: %s, path: %s", m_tabname, path)); DBUG_ASSERT(m_table == NULL); @@ -1468,7 +1468,7 @@ void ha_ndbcluster::release_metadata(THD *thd, Ndb *ndb) { uint i; - DBUG_ENTER("ha_ndbcluster::release_metadata"); + DBUG_ENTER("release_metadata"); DBUG_PRINT("enter", ("m_tabname: %s", m_tabname)); NDBDICT *dict= ndb->getDictionary(); @@ -1609,7 +1609,7 @@ int ha_ndbcluster::set_primary_key(NdbOperation *op, const uchar *key) KEY* key_info= table->key_info + table_share->primary_key; KEY_PART_INFO* key_part= key_info->key_part; KEY_PART_INFO* end= key_part+key_info->key_parts; - DBUG_ENTER("ha_ndbcluster::set_primary_key"); + DBUG_ENTER("set_primary_key"); for (; key_part != end; key_part++) { @@ -1631,7 +1631,7 @@ int ha_ndbcluster::set_primary_key_from_record(NdbOperation *op, const uchar *re KEY* key_info= table->key_info + table_share->primary_key; KEY_PART_INFO* key_part= key_info->key_part; KEY_PART_INFO* end= key_part+key_info->key_parts; - DBUG_ENTER("ha_ndbcluster::set_primary_key_from_record"); + DBUG_ENTER("set_primary_key_from_record"); for (; key_part != end; key_part++) { @@ -1670,7 +1670,7 @@ int ha_ndbcluster::set_index_key_from_record(NdbOperation *op, KEY_PART_INFO* key_part= key_info->key_part; KEY_PART_INFO* end= key_part+key_info->key_parts; uint i; - DBUG_ENTER("ha_ndbcluster::set_index_key_from_record"); + DBUG_ENTER("set_index_key_from_record"); for (i= 0; key_part != end; key_part++, i++) { @@ -1709,7 +1709,7 @@ inline int ha_ndbcluster::define_read_attrs(uchar* buf, NdbOperation* op) { uint i; - DBUG_ENTER("ha_ndbcluster::define_read_attrs"); + DBUG_ENTER("define_read_attrs"); // Define attributes to read for (i= 0; i < table_share->fields; i++) @@ -1756,7 +1756,7 @@ int ha_ndbcluster::pk_read(const uchar *key, uint key_len, uchar *buf, NdbOperation *op; int res; - DBUG_ENTER("ha_ndbcluster::pk_read"); + DBUG_ENTER("pk_read"); DBUG_PRINT("enter", ("key_len: %u", key_len)); DBUG_DUMP("key", key, key_len); m_write_op= FALSE; @@ -1823,7 +1823,7 @@ int ha_ndbcluster::complemented_read(const uchar *old_data, uchar *new_data, uint no_fields= table_share->fields, i; NdbTransaction *trans= m_active_trans; NdbOperation *op; - DBUG_ENTER("ha_ndbcluster::complemented_read"); + DBUG_ENTER("complemented_read"); m_write_op= FALSE; if (bitmap_is_set_all(table->read_set)) @@ -1989,7 +1989,7 @@ int ha_ndbcluster::peek_indexed_rows(const uchar *record, const NdbOperation *first, *last; uint i; int res; - DBUG_ENTER("ha_ndbcluster::peek_indexed_rows"); + DBUG_ENTER("peek_indexed_rows"); NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); @@ -2134,7 +2134,7 @@ int ha_ndbcluster::unique_index_read(const uchar *key, inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) { - DBUG_ENTER("ha_ndbcluster::fetch_next"); + DBUG_ENTER("fetch_next"); int local_check; NdbTransaction *trans= m_active_trans; @@ -2243,7 +2243,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) inline int ha_ndbcluster::next_result(uchar *buf) { int res; - DBUG_ENTER("ha_ndbcluster::next_result"); + DBUG_ENTER("next_result"); if (!m_active_cursor) DBUG_RETURN(HA_ERR_END_OF_FILE); @@ -2286,7 +2286,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op, uint tot_len; uint i, j; - DBUG_ENTER("ha_ndbcluster::set_bounds"); + DBUG_ENTER("set_bounds"); DBUG_PRINT("info", ("key_parts=%d", key_parts)); for (j= 0; j <= 1; j++) @@ -2573,7 +2573,7 @@ int ha_ndbcluster::unique_index_scan(const KEY* key_info, NdbTransaction *trans= m_active_trans; part_id_range part_spec; - DBUG_ENTER("ha_ndbcluster::unique_index_scan"); + DBUG_ENTER("unique_index_scan"); DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname)); NdbOperation::LockMode lm= @@ -2647,7 +2647,7 @@ int ha_ndbcluster::full_table_scan(uchar *buf) NdbTransaction *trans= m_active_trans; part_id_range part_spec; - DBUG_ENTER("ha_ndbcluster::full_table_scan"); + DBUG_ENTER("full_table_scan"); DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname)); m_write_op= FALSE; @@ -2980,7 +2980,7 @@ int ha_ndbcluster::update_row(const uchar *old_data, uchar *new_data) longlong func_value; bool pk_update= (table_share->primary_key != MAX_KEY && key_cmp(table_share->primary_key, old_data, new_data)); - DBUG_ENTER("ha_ndbcluster::update_row"); + DBUG_ENTER("update_row"); m_write_op= TRUE; /* @@ -3185,7 +3185,7 @@ int ha_ndbcluster::delete_row(const uchar *record) NdbOperation *op; uint32 part_id; int error; - DBUG_ENTER("ha_ndbcluster::delete_row"); + DBUG_ENTER("delete_row"); m_write_op= TRUE; ha_statistic_increment(&SSV::ha_delete_count); @@ -3465,7 +3465,7 @@ void ha_ndbcluster::unpack_record(uchar *buf) void ha_ndbcluster::print_results() { - DBUG_ENTER("ha_ndbcluster::print_results"); + DBUG_ENTER("print_results"); #ifndef DBUG_OFF @@ -3732,7 +3732,7 @@ int ha_ndbcluster::read_range_next() int ha_ndbcluster::rnd_init(bool scan) { NdbScanOperation *cursor= m_active_cursor; - DBUG_ENTER("ha_ndbcluster::rnd_init"); + DBUG_ENTER("rnd_init"); DBUG_PRINT("enter", ("scan: %d", scan)); // Check if scan is to be restarted if (cursor) @@ -3752,7 +3752,7 @@ int ha_ndbcluster::rnd_init(bool scan) int ha_ndbcluster::close_scan() { NdbTransaction *trans= m_active_trans; - DBUG_ENTER("ha_ndbcluster::close_scan"); + DBUG_ENTER("close_scan"); m_multi_cursor= 0; if (!m_active_cursor && !m_multi_cursor) @@ -3801,14 +3801,14 @@ int ha_ndbcluster::close_scan() int ha_ndbcluster::rnd_end() { - DBUG_ENTER("ha_ndbcluster::rnd_end"); + DBUG_ENTER("rnd_end"); DBUG_RETURN(close_scan()); } int ha_ndbcluster::rnd_next(uchar *buf) { - DBUG_ENTER("ha_ndbcluster::rnd_next"); + DBUG_ENTER("rnd_next"); ha_statistic_increment(&SSV::ha_read_rnd_next_count); if (!m_active_cursor) @@ -3826,7 +3826,7 @@ int ha_ndbcluster::rnd_next(uchar *buf) int ha_ndbcluster::rnd_pos(uchar *buf, uchar *pos) { - DBUG_ENTER("ha_ndbcluster::rnd_pos"); + DBUG_ENTER("rnd_pos"); ha_statistic_increment(&SSV::ha_read_rnd_count); // The primary key for the record is stored in pos // Perform a pk_read using primary key "index" @@ -3878,7 +3878,7 @@ void ha_ndbcluster::position(const uchar *record) uchar *buff; uint key_length; - DBUG_ENTER("ha_ndbcluster::position"); + DBUG_ENTER("position"); if (table_share->primary_key != MAX_KEY) { @@ -3962,7 +3962,7 @@ void ha_ndbcluster::position(const uchar *record) int ha_ndbcluster::info(uint flag) { int result= 0; - DBUG_ENTER("ha_ndbcluster::info"); + DBUG_ENTER("info"); DBUG_PRINT("enter", ("flag: %d", flag)); if (flag & HA_STATUS_POS) @@ -4063,7 +4063,7 @@ void ha_ndbcluster::get_dynamic_partition_info(PARTITION_INFO *stat_info, int ha_ndbcluster::extra(enum ha_extra_function operation) { - DBUG_ENTER("ha_ndbcluster::extra"); + DBUG_ENTER("extra"); switch (operation) { case HA_EXTRA_IGNORE_DUP_KEY: /* Dup keys don't rollback everything*/ DBUG_PRINT("info", ("HA_EXTRA_IGNORE_DUP_KEY")); @@ -4156,7 +4156,7 @@ void ha_ndbcluster::start_bulk_insert(ha_rows rows) int bytes, batch; const NDBTAB *tab= m_table; - DBUG_ENTER("ha_ndbcluster::start_bulk_insert"); + DBUG_ENTER("start_bulk_insert"); DBUG_PRINT("enter", ("rows: %d", (int)rows)); m_rows_inserted= (ha_rows) 0; @@ -4205,7 +4205,7 @@ int ha_ndbcluster::end_bulk_insert() { int error= 0; - DBUG_ENTER("ha_ndbcluster::end_bulk_insert"); + DBUG_ENTER("end_bulk_insert"); // Check if last inserts need to be flushed if (m_bulk_insert_not_flushed) { @@ -4246,7 +4246,7 @@ int ha_ndbcluster::end_bulk_insert() int ha_ndbcluster::extra_opt(enum ha_extra_function operation, ulong cache_size) { - DBUG_ENTER("ha_ndbcluster::extra_opt"); + DBUG_ENTER("extra_opt"); DBUG_PRINT("enter", ("cache_size: %lu", cache_size)); DBUG_RETURN(extra(operation)); } @@ -4288,7 +4288,7 @@ THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type) { - DBUG_ENTER("ha_ndbcluster::store_lock"); + DBUG_ENTER("store_lock"); if (lock_type != TL_IGNORE && m_lock.type == TL_UNLOCK) { @@ -4506,7 +4506,7 @@ int ha_ndbcluster::init_handler_for_statement(THD *thd, Thd_ndb *thd_ndb) int ha_ndbcluster::external_lock(THD *thd, int lock_type) { int error=0; - DBUG_ENTER("ha_ndbcluster::external_lock"); + DBUG_ENTER("external_lock"); /* Check that this handler instance has a connection @@ -4619,7 +4619,7 @@ error: void ha_ndbcluster::unlock_row() { - DBUG_ENTER("ha_ndbcluster::unlock_row"); + DBUG_ENTER("unlock_row"); DBUG_PRINT("info", ("Unlocking row")); m_lock_tuple= FALSE; @@ -4637,7 +4637,7 @@ void ha_ndbcluster::unlock_row() int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type) { int error=0; - DBUG_ENTER("ha_ndbcluster::start_stmt"); + DBUG_ENTER("start_stmt"); Thd_ndb *thd_ndb= get_thd_ndb(thd); transaction_checks(thd); @@ -5480,7 +5480,7 @@ int ha_ndbcluster::create_handler_files(const char *file, size_t length, pack_length; int error= 0; - DBUG_ENTER("ha_ndbcluster::create_handler_files"); + DBUG_ENTER("create_handler_files"); if (action_flag != CHF_INDEX_FLAG) { @@ -6165,7 +6165,7 @@ void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment, { int cache_size; Uint64 auto_value; - DBUG_ENTER("ha_ndbcluster::get_auto_increment"); + DBUG_ENTER("get_auto_increment"); DBUG_PRINT("enter", ("m_tabname: %s", m_tabname)); Ndb *ndb= get_ndb(); @@ -6272,7 +6272,7 @@ ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg): { int i; - DBUG_ENTER("ha_ndbcluster::ha_ndbcluster"); + DBUG_ENTER("ha_ndbcluster"); m_tabname[0]= '\0'; m_dbname[0]= '\0'; @@ -6305,7 +6305,7 @@ ha_ndbcluster::~ha_ndbcluster() { THD *thd= current_thd; Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb; - DBUG_ENTER("ha_ndbcluster::~ha_ndbcluster"); + DBUG_ENTER("~ha_ndbcluster"); if (m_share) { @@ -6460,7 +6460,7 @@ void ha_ndbcluster::set_part_info(partition_info *part_info) int ha_ndbcluster::close(void) { - DBUG_ENTER("ha_ndbcluster::close"); + DBUG_ENTER("close"); THD *thd= table->in_use; Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb; /* ndb_share reference handler free */ @@ -6476,7 +6476,7 @@ int ha_ndbcluster::close(void) Thd_ndb* ha_ndbcluster::seize_thd_ndb() { Thd_ndb *thd_ndb; - DBUG_ENTER("ha_ndbcluster::seize_thd_ndb"); + DBUG_ENTER("seize_thd_ndb"); thd_ndb= new Thd_ndb(); if (thd_ndb == NULL) @@ -6502,7 +6502,7 @@ Thd_ndb* ha_ndbcluster::seize_thd_ndb() void ha_ndbcluster::release_thd_ndb(Thd_ndb* thd_ndb) { - DBUG_ENTER("ha_ndbcluster::release_thd_ndb"); + DBUG_ENTER("release_thd_ndb"); delete thd_ndb; DBUG_VOID_RETURN; } @@ -6532,7 +6532,7 @@ Ndb* check_ndb_in_thd(THD* thd) int ha_ndbcluster::check_ndb_connection(THD* thd) { Ndb *ndb; - DBUG_ENTER("ha_ndbcluster::check_ndb_connection"); + DBUG_ENTER("check_ndb_connection"); if (!(ndb= check_ndb_in_thd(thd))) DBUG_RETURN(HA_ERR_NO_CONNECTION); @@ -7583,7 +7583,7 @@ ha_ndbcluster::records_in_range(uint inx, key_range *min_key, uint key_length= key_info->key_length; NDB_INDEX_TYPE idx_type= get_index_type(inx); - DBUG_ENTER("ha_ndbcluster::records_in_range"); + DBUG_ENTER("records_in_range"); // Prevent partial read of hash indexes by returning HA_POS_ERROR if ((idx_type == UNIQUE_INDEX || idx_type == PRIMARY_KEY_INDEX) && ((min_key && min_key->length < key_length) || @@ -8543,7 +8543,7 @@ int ha_ndbcluster::write_ndb_file(const char *name) bool error=1; char path[FN_REFLEN]; - DBUG_ENTER("ha_ndbcluster::write_ndb_file"); + DBUG_ENTER("write_ndb_file"); DBUG_PRINT("enter", ("name: %s", name)); (void)strxnmov(path, FN_REFLEN-1, @@ -8587,7 +8587,7 @@ ha_ndbcluster::null_value_index_search(KEY_MULTI_RANGE *ranges, KEY_MULTI_RANGE *end_range, HANDLER_BUFFER *buffer) { - DBUG_ENTER("ha_ndbcluster::null_value_index_search"); + DBUG_ENTER("null_value_index_search"); KEY* key_info= table->key_info + active_index; KEY_MULTI_RANGE *range= ranges; ulong reclength= table->s->reclength; @@ -8982,7 +8982,7 @@ found_next: int ha_ndbcluster::setup_recattr(const NdbRecAttr* curr) { - DBUG_ENTER("ha_ndbcluster::setup_recattr"); + DBUG_ENTER("setup_recattr"); Field **field, **end; NdbValue *value= m_value; @@ -9353,7 +9353,7 @@ const COND* ha_ndbcluster::cond_push(const COND *cond) { - DBUG_ENTER("ha_ndbcluster::cond_push"); + DBUG_ENTER("cond_push"); if (!m_cond) m_cond= new ha_ndbcluster_cond; if (!m_cond) @@ -9588,7 +9588,7 @@ int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info) uint i; int error= 0; bool unsigned_flag= part_info->part_expr->unsigned_flag; - DBUG_ENTER("ha_ndbcluster::set_range_data"); + DBUG_ENTER("set_range_data"); if (!range_data) { @@ -9627,7 +9627,7 @@ int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info) uint32 *part_id, i; int error= 0; bool unsigned_flag= part_info->part_expr->unsigned_flag; - DBUG_ENTER("ha_ndbcluster::set_list_data"); + DBUG_ENTER("set_list_data"); if (!list_data) { @@ -9958,7 +9958,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, int error; const char *errmsg; Ndb *ndb; - DBUG_ENTER("alter_tablespace"); + DBUG_ENTER("ha_ndbcluster::alter_tablespace"); LINT_INIT(errmsg); ndb= check_ndb_in_thd(thd); From 8f798dffea964598eed2a02ed6cfcb7ba7c0fb6e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 14 Nov 2007 21:08:59 +0100 Subject: [PATCH 085/136] Post-merge fixes. sql/sql_delete.cc: Correcting merge error. --- sql/sql_delete.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index d80f1fe0d13..509e736f6e7 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -309,7 +309,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->file->unlock_row(); // Row failed selection, release lock on it } killed_status= thd->killed; - if (killed_status == THD::NOT_KILLED || thd->is_error()) + if (killed_status != THD::NOT_KILLED || thd->is_error()) error= 1; // Aborted if (will_batch && (loc_error= table->file->end_bulk_delete())) { From 62d3c3d3a1c7ceed7170913189dd0e4437f2d37e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 15 Nov 2007 11:36:50 +0100 Subject: [PATCH 086/136] Bug#22351 - handler::index_next_same() call to key_cmp_if_same() uses the wrong buffer Post-pushbuild fix Added test case for better coverage. mysql-test/r/partition.result: Bug#22351 - handler::index_next_same() call to key_cmp_if_same() uses the wrong buffer Added test result mysql-test/t/partition.test: Bug#22351 - handler::index_next_same() call to key_cmp_if_same() uses the wrong buffer Added test case --- mysql-test/r/partition.result | 7 +++++++ mysql-test/t/partition.test | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index aa6a64ac76e..b0ba901907f 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -289,6 +289,13 @@ select * from t1 where a = 4; a b 4 4 drop table t1; +CREATE TABLE t1 (c1 INT, c2 INT, PRIMARY KEY USING BTREE (c1,c2)) ENGINE=MEMORY +PARTITION BY KEY(c2,c1) PARTITIONS 4; +INSERT INTO t1 VALUES (0,0),(1,1),(2,2),(3,3),(4,4),(5,5),(6,6); +SELECT * FROM t1 WHERE c1 = 4; +c1 c2 +4 4 +DROP TABLE t1; CREATE TABLE t1 (a int) PARTITION BY LIST (a) PARTITIONS 1 diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index f986215ee89..8114b85c0f9 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -372,6 +372,16 @@ select * from t1 where a = 4; drop table t1; +# +# Bug#22351 - handler::index_next_same() call to key_cmp_if_same() +# uses the wrong buffer +# +CREATE TABLE t1 (c1 INT, c2 INT, PRIMARY KEY USING BTREE (c1,c2)) ENGINE=MEMORY + PARTITION BY KEY(c2,c1) PARTITIONS 4; +INSERT INTO t1 VALUES (0,0),(1,1),(2,2),(3,3),(4,4),(5,5),(6,6); +SELECT * FROM t1 WHERE c1 = 4; +DROP TABLE t1; + # # Bug #13438: Engine clause in PARTITION clause causes crash # From c8450b278d7f049e0afa49624c52e0f61b541126 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 15 Nov 2007 20:25:43 +0100 Subject: [PATCH 087/136] Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Bug 26867 - LOCK TABLES + REPAIR + merge table result in memory/cpu hogging Bug 26377 - Deadlock with MERGE and FLUSH TABLE Bug 25038 - Waiting TRUNCATE Bug 25700 - merge base tables get corrupted by optimize/analyze/repair table Bug 30275 - Merge tables: flush tables or unlock tables causes server to crash Bug 19627 - temporary merge table locking Bug 27660 - Falcon: merge table possible Bug 30273 - merge tables: Can't lock file (errno: 155) The problems were: Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table 1. A thread trying to lock a MERGE table performs busy waiting while REPAIR TABLE or a similar table administration task is ongoing on one or more of its MyISAM tables. 2. A thread trying to lock a MERGE table performs busy waiting until all threads that did REPAIR TABLE or similar table administration tasks on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK TABLES. The difference against problem #1 is that the busy waiting takes place *after* the administration task. It is terminated by UNLOCK TABLES only. 3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the lock. This does *not* require a MERGE table. The first FLUSH TABLES can be replaced by any statement that requires other threads to reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke the problem. Bug 26867 - LOCK TABLES + REPAIR + merge table result in memory/cpu hogging Trying DML on a MERGE table, which has a child locked and repaired by another thread, made an infinite loop in the server. Bug 26377 - Deadlock with MERGE and FLUSH TABLE Locking a MERGE table and its children in parent-child order and flushing the child deadlocked the server. Bug 25038 - Waiting TRUNCATE Truncating a MERGE child, while the MERGE table was in use, let the truncate fail instead of waiting for the table to become free. Bug 25700 - merge base tables get corrupted by optimize/analyze/repair table Repairing a child of an open MERGE table corrupted the child. It was necessary to FLUSH the child first. Bug 30275 - Merge tables: flush tables or unlock tables causes server to crash Flushing and optimizing locked MERGE children crashed the server. Bug 19627 - temporary merge table locking Use of a temporary MERGE table with non-temporary children could corrupt the children. Temporary tables are never locked. So we do now prohibit non-temporary chidlren of a temporary MERGE table. Bug 27660 - Falcon: merge table possible It was possible to create a MERGE table with non-MyISAM children. Bug 30273 - merge tables: Can't lock file (errno: 155) This was a Windows-only bug. Table administration statements sometimes failed with "Can't lock file (errno: 155)". These bugs are fixed by a new implementation of MERGE table open. When opening a MERGE table in open_tables() we do now add the child tables to the list of tables to be opened by open_tables() (the "query_list"). The children are not opened in the handler at this stage. After opening the parent, open_tables() opens each child from the now extended query_list. When the last child is opened, we remove the children from the query_list again and attach the children to the parent. This behaves similar to the old open. However it does not open the MyISAM tables directly, but grabs them from the already open children. When closing a MERGE table in close_thread_table() we detach the children only. Closing of the children is done implicitly because they are in thd->open_tables. For more detail see the comment at the top of ha_myisammrg.cc. Changed from open_ltable() to open_and_lock_tables() in all places that can be relevant for MERGE tables. The latter can handle tables added to the list on the fly. When open_ltable() was used in a loop over a list of tables, the list must be temporarily terminated after every table for open_and_lock_tables(). table_list->required_type is set to FRMTYPE_TABLE to avoid open of special tables. Handling of derived tables is suppressed. These details are handled by the new function open_n_lock_single_table(), which has nearly the same signature as open_ltable() and can replace it in most cases. In reopen_tables() some of the tables open by a thread can be closed and reopened. When a MERGE child is affected, the parent must be closed and reopened too. Closing of the parent is forced before the first child is closed. Reopen happens in the order of thd->open_tables. MERGE parents do not attach their children automatically at open. This is done after all tables are reopened. So all children are open when attaching them. Special lock handling like mysql_lock_abort() or mysql_lock_remove() needs to be suppressed for MERGE children or forwarded to the parent. This depends on the situation. In loops over all open tables one suppresses child lock handling. When a single table is touched, forwarding is done. Behavioral changes: =================== This patch changes the behavior of temporary MERGE tables. Temporary MERGE must have temporary children. The old behavior was wrong. A temporary table is not locked. Hence even non-temporary children were not locked. See Bug 19627 - temporary merge table locking. You cannot change the union list of a non-temporary MERGE table when LOCK TABLES is in effect. The following does *not* work: CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...; LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE; ALTER TABLE m1 ... UNION=(t1,t2) ...; However, you can do this with a temporary MERGE table. You cannot create a MERGE table with CREATE ... SELECT, neither as a temporary MERGE table, nor as a non-temporary MERGE table. CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...; Gives error message: table is not BASE TABLE. include/my_base.h: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added HA_EXTRA_ATTACH_CHILDREN and HA_EXTRA_DETACH_CHILDREN. include/myisammrg.h: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added element 'children_attached' to MYRG_INFO. Added declarations for myrg_parent_open(), myrg_attach_children() and myrg_detach_children() for the new MERGE table open approach. mysql-test/extra/binlog_tests/blackhole.test: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Preliminarily added new error message with a comment. mysql-test/r/create.result: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Fixed test result. mysql-test/r/delayed.result: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Moved test result from here to merge.result. mysql-test/r/merge.result: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Fixed/added test result. mysql-test/r/myisam.result: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Moved test result for bug 8306 from here to merge.result. mysql-test/suite/binlog/r/binlog_stm_blackhole.result: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Fixed test result. mysql-test/t/create.test: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Fixed error number. mysql-test/t/delayed.test: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Moved test from here to merge.test. mysql-test/t/merge.test: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Fixed test for new temporary MERGE table behavior. Exchanged error numbers by symbolic codes. Added tests. Included are tests for bugs 8306 (moved from myisam.test), 26379, 19627, 25038, 25700, 26377, 26867, 27660, 30275, and 30273. Fixed changes resulting from disabled CREATE...SELECT. Integrated tests moved from delayed.test and myisam.test to here. mysql-test/t/myisam.test: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Moved test for bug 8306 from here to merge.test. mysys/thr_lock.c: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added code to let the owner of a high priority lock (TL_WRITE_ONLY) to bypass its own lock. sql/ha_ndbcluster_binlog.cc: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added 'thd' argument to init_tmp_table_share(). sql/handler.cc: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added 'thd' argument to init_tmp_table_share(). sql/mysql_priv.h: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Removed declaration of check_merge_table_access(). It is now static in sql_parse.cc. Added declaration for fix_merge_after_open(). Renamed open_and_lock_tables() to open_and_lock_tables_derived() with additional parameter 'derived'. Added inline functions simple_open_n_lock_tables() and open_and_lock_tables(), which call open_and_lock_tables_derived() and add the argument for 'derived'. Added new function open_n_lock_single_table(), which can be used as an replacement for open_ltable() in most situations. Internally it calls simple_open_n_lock_tables() so hat it is appropriate for MERGE tables. Added 'thd' argument to init_tmp_table_share(). sql/slave.cc: ug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added comment. sql/sql_base.cc: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Defined new functions add_merge_table_list(), attach_merge_children(), detach_merge_children(), and fix_merge_after_open() for the new MERGE table open approach. Added calls of the new functions to close_handle_and_leave_table_as_lock(), close_thread_tables(), close_thread_table(), unlink_open_table(), reopen_name_locked_table(), reopen_table(), drop_locked_tables(), close_temporary_table(), and open_tables() respectively. Prevented special lock handling of merge children (like mysql_lock_remove, mysql_lock_merge or mysql_lock_abort) at many places. Some of these calls are forwarded to the parent table instead. Added code to set thd->some_tables_deleted for every thread that has a table open that we are flushing. Added code for MERGE tables to unlink_open_table(). Added MERGE children to the list of unusable tables in open_table(). Added MERGE table handling to reopen_table(). Added lock handling and closing of a parent before the children in close_data_files_and_morph_locks(). Added code for re-attaching children in reopen_tables(). Added MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN to the locking flags and error reporting after mysql_lock_tables() in reopen_tables(). Added lock handling and closing of a parent before the children in close_old_data_files(). Added lock handling and detaching in drop_locked_tables(). Added code for removing the children list from the statement list to prepare for a repetition in open_tables(). Added new function open_n_lock_single_table(), which can be used as an replacement for open_ltable() in most situations. Internally it calls simple_open_n_lock_tables() so hat it is appropriate for MERGE tables. Disabled use of open_ltable() for MERGE tables. Removed function simple_open_n_lock_tables(). It is now inline declared in mysql_priv.h. Renamed open_and_lock_tables() to open_and_lock_tables_derived() with additional parameter 'derived'. open_and_lock_tables() is now inline declared in mysql_priv.h. Added a check for end-of-list in two loops in lock_tables(). Added 'thd' argument to init_tmp_table_share(). sql/sql_insert.cc: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Changed from open_ltable() to open_n_lock_single_table() in handle_delayed_insert(). Reestablished LEX settings after lex initialization. Added 'thd' argument to init_tmp_table_share(). sql/sql_parse.cc: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Made check_merge_table_access() a static function. Disabled use of CREATE...SELECT for MERGE tables. sql/sql_partition.cc: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Fixed comment typo. sql/sql_select.cc: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added 'thd' argument to init_tmp_table_share(). sql/sql_table.cc: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Optimized use of mysql_ha_flush() in mysql_rm_table_part2(). Disabled the use of MERGE tables with prepare_for_restore() and prepare_for_repair(). Changed from open_ltable() to open_n_lock_single_table() in mysql_alter_table() and mysql_checksum_table(). Disabled change of child list under LOCK TABLES. Initialized table_list->table in mysql_recreate_table(). sql/sql_trigger.cc: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added code for allowing CREATE TRIGGER under LOCK TABLE, to be able to test it with MERGE tables. sql/table.cc: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added 'thd' argument to init_tmp_table_share(). Setting table_map_id from query_id in init_tmp_table_share(). Added member function TABLE::is_children_attached(). sql/table.h: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added access method get_table_def_version() to TABLE_SHARE. Added elements for MERGE tables to TABLE and TABLE_LIST. storage/myisam/ha_myisam.cc: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added an unrelated comment to the function comment of table2myisam(). storage/myisam/ha_myisam.h: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added new member function MI_INFO::file_ptr(). storage/myisammrg/ha_myisammrg.cc: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added callback functions to support parent open and children attach of MERGE tables. Changed ha_myisammrg::open() to initialize storage engine structures and create a list of child tables only. Child tables are not opened. Added ha_myisammrg::attach_children(), which does now the main part of MERGE open. Added ha_myisammrg::detach_children(). Added calls to ::attach_children() and ::detach_children() to ::extra() on HA_EXTRA_ATTACH_CHILDREN and HA_EXTRA_DETACH_CHILDREN respectively. Added a check for matching TEMPORARY type for children against parent. Added a check for table def version. Added support for thd->open_options to attach_children(). Changed child path name generation for temporary tables so that it does nothing special for temporary tables. storage/myisammrg/ha_myisammrg.h: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added elements to class ha_myisammrg to support the new open approach. Changed empty destructor definition to a declaration. Implemented in ha_myisammrg.cc. Added declaration for methods attach_children() and detach_children(). Added definition for method table_ptr() for use with callback functions. storage/myisammrg/myrg_close.c: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added a check to avoid closing of MyISAM tables when the child tables are not attached. Added freeing of rec_per_key_part when the child tables are not attached. storage/myisammrg/myrg_extra.c: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Some ::extra() functions and ::reset() can be called when children are detached. storage/myisammrg/myrg_open.c: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Kept old myrg_open() for MERGE use independent from MySQL. Removed an always true condition in myrg_open(). Set children_attached for independent MERGE use in myrg_open(). Added myrg_parent_open(), myrg_attach_children(), and myrg_detach_children() for the new MERGE table open approach. mysql-test/r/merge-big.result: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table New test result mysql-test/t/merge-big.test: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table New test case --- include/my_base.h | 8 +- include/myisammrg.h | 9 + mysql-test/extra/binlog_tests/blackhole.test | 9 + mysql-test/r/create.result | 2 +- mysql-test/r/delayed.result | 5 - mysql-test/r/merge-big.result | 77 ++ mysql-test/r/merge.result | 1094 ++++++++++++++++- mysql-test/r/myisam.result | 18 - .../binlog/r/binlog_stm_blackhole.result | 1 + mysql-test/t/create.test | 2 +- mysql-test/t/delayed.test | 8 - mysql-test/t/merge-big.test | 150 +++ mysql-test/t/merge.test | 847 ++++++++++++- mysql-test/t/myisam.test | 26 - mysys/thr_lock.c | 39 +- sql/ha_ndbcluster_binlog.cc | 2 +- sql/handler.cc | 11 +- sql/mysql_priv.h | 24 +- sql/slave.cc | 6 + sql/sql_base.cc | 1072 ++++++++++++++-- sql/sql_insert.cc | 14 +- sql/sql_parse.cc | 73 +- sql/sql_partition.cc | 2 +- sql/sql_select.cc | 2 +- sql/sql_table.cc | 80 +- sql/sql_trigger.cc | 44 +- sql/table.cc | 29 +- sql/table.h | 33 + storage/myisam/ha_myisam.cc | 4 + storage/myisam/ha_myisam.h | 4 + storage/myisammrg/ha_myisammrg.cc | 670 ++++++++-- storage/myisammrg/ha_myisammrg.h | 9 +- storage/myisammrg/myrg_close.c | 34 +- storage/myisammrg/myrg_extra.c | 4 + storage/myisammrg/myrg_open.c | 334 ++++- 35 files changed, 4417 insertions(+), 329 deletions(-) create mode 100644 mysql-test/r/merge-big.result create mode 100644 mysql-test/t/merge-big.test diff --git a/include/my_base.h b/include/my_base.h index 339554979a8..f79ff8805b9 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -187,7 +187,13 @@ enum ha_extra_function { Inform handler that an "INSERT...ON DUPLICATE KEY UPDATE" will be executed. This condition is unset by HA_EXTRA_NO_IGNORE_DUP_KEY. */ - HA_EXTRA_INSERT_WITH_UPDATE + HA_EXTRA_INSERT_WITH_UPDATE, + /* + Orders MERGE handler to attach or detach its child tables. Used at + begin and end of a statement. + */ + HA_EXTRA_ATTACH_CHILDREN, + HA_EXTRA_DETACH_CHILDREN }; /* The following is parameter to ha_panic() */ diff --git a/include/myisammrg.h b/include/myisammrg.h index eed50bebaee..0cf3aa222b3 100644 --- a/include/myisammrg.h +++ b/include/myisammrg.h @@ -69,6 +69,8 @@ typedef struct st_myrg_info uint merge_insert_method; uint tables,options,reclength,keys; my_bool cache_in_use; + /* If MERGE children attached to parent. See top comment in ha_myisammrg.cc */ + my_bool children_attached; LIST open_list; QUEUE by_key; ulong *rec_per_key_part; /* for sql optimizing */ @@ -80,6 +82,13 @@ typedef struct st_myrg_info extern int myrg_close(MYRG_INFO *file); extern int myrg_delete(MYRG_INFO *file,const uchar *buff); extern MYRG_INFO *myrg_open(const char *name,int mode,int wait_if_locked); +extern MYRG_INFO *myrg_parent_open(const char *parent_name, + int (*callback)(void*, const char*), + void *callback_param); +extern int myrg_attach_children(MYRG_INFO *m_info, int handle_locking, + MI_INFO *(*callback)(void*), + void *callback_param); +extern int myrg_detach_children(MYRG_INFO *m_info); extern int myrg_panic(enum ha_panic_function function); extern int myrg_rfirst(MYRG_INFO *file,uchar *buf,int inx); extern int myrg_rlast(MYRG_INFO *file,uchar *buf,int inx); diff --git a/mysql-test/extra/binlog_tests/blackhole.test b/mysql-test/extra/binlog_tests/blackhole.test index 1ca59955d76..df2295af4ff 100644 --- a/mysql-test/extra/binlog_tests/blackhole.test +++ b/mysql-test/extra/binlog_tests/blackhole.test @@ -134,6 +134,15 @@ drop table t1,t2,t3; # table # CREATE TABLE t1(a INT) ENGINE=BLACKHOLE; +# NOTE: After exchanging open_ltable() by open_and_lock_tables() in +# handle_delayed_insert() to fix problems with MERGE tables (Bug#26379), +# problems with INSERT DELAYED and BLACKHOLE popped up. open_ltable() +# does not check if the binlogging capabilities of the statement and the +# table match. So the below used to succeed. But since INSERT DELAYED +# switches to row-based logging in mixed-mode and BLACKHOLE cannot do +# row-based logging, it could not really work. Until this problem is +# correctly fixed, we have that error here. +--error ER_BINLOG_LOGGING_IMPOSSIBLE INSERT DELAYED INTO t1 VALUES(1); DROP TABLE t1; diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index ca3b344af53..73a9dba4e69 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -594,7 +594,7 @@ create table t1 (a int); create table t1 select * from t1; ERROR HY000: You can't specify target table 't1' for update in FROM clause create table t2 union = (t1) select * from t1; -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: 'test.t2' is not BASE TABLE flush tables with read lock; unlock tables; drop table t1; diff --git a/mysql-test/r/delayed.result b/mysql-test/r/delayed.result index c520ab52ab3..92a20630d77 100644 --- a/mysql-test/r/delayed.result +++ b/mysql-test/r/delayed.result @@ -250,11 +250,6 @@ SELECT HEX(a) FROM t1; HEX(a) 1 DROP TABLE t1; -CREATE TABLE t1(c1 INT) ENGINE=MyISAM; -CREATE TABLE t2(c1 INT) ENGINE=MERGE UNION=(t1); -INSERT DELAYED INTO t2 VALUES(1); -ERROR HY000: Table storage engine for 't2' doesn't have this option -DROP TABLE t1, t2; DROP TABLE IF EXISTS t1,t2; SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO'; CREATE TABLE `t1` ( diff --git a/mysql-test/r/merge-big.result b/mysql-test/r/merge-big.result new file mode 100644 index 00000000000..82fedc1df73 --- /dev/null +++ b/mysql-test/r/merge-big.result @@ -0,0 +1,77 @@ +drop table if exists t1,t2,t3,t4,t5,t6; +# +# Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE +# corrupts a MERGE table +# Problem #3 +# +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM; +LOCK TABLE t1 WRITE; +# connection con1 +SET SESSION debug="+d,sleep_open_and_lock_after_open"; +INSERT INTO t1 VALUES (1); +# connection default +# Let INSERT go into thr_multi_lock(). +# Kick INSERT out of thr_multi_lock(). +FLUSH TABLES; +# Let INSERT go through open_tables() where it sleeps. +# Unlock and close table and wait for con1 to close too. +FLUSH TABLES; +# This should give no result. +SELECT * FROM t1; +c1 +UNLOCK TABLES; +# connection con1 +SET SESSION debug="-d,sleep_open_and_lock_after_open"; +# connection default +DROP TABLE t1; +# +# Extra tests for Bug#26379 - Combination of FLUSH TABLE and +# REPAIR TABLE corrupts a MERGE table +# +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE t3 (c1 INT); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (3); +# +# CREATE ... SELECT +# try to access parent from another thread. +# +# connection con1 +SET SESSION debug="+d,sleep_create_select_before_lock"; +CREATE TABLE t4 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1,t2) +INSERT_METHOD=FIRST SELECT * FROM t3; +# connection default +# Now try to access the parent. +# If 3 is in table, SELECT had to wait. +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +# connection con1 +SET SESSION debug="-d,sleep_create_select_before_lock"; +# connection default +# Cleanup for next test. +DROP TABLE t4; +DELETE FROM t1 WHERE c1 != 1; +# +# CREATE ... SELECT +# try to access child from another thread. +# +# connection con1 +SET SESSION debug="+d,sleep_create_select_before_lock"; +CREATE TABLE t4 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1,t2) +INSERT_METHOD=FIRST SELECT * FROM t3; +# connection default +# Now try to access a child. +# If 3 is in table, SELECT had to wait. +SELECT * FROM t1 ORDER BY c1; +c1 +1 +3 +# connection con1 +SET SESSION debug="-d,sleep_create_select_before_lock"; +# connection default +DROP TABLE t1, t2, t3, t4; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index d6e19107ec4..74441db2512 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -584,9 +584,7 @@ insert into t1 values (1); insert into t2 values (2); create temporary table t3 (a int not null) ENGINE=MERGE UNION=(t1,t2); select * from t3; -a -1 -2 +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist create temporary table t4 (a int not null); create temporary table t5 (a int not null); insert into t4 values (1); @@ -597,6 +595,54 @@ a 1 2 drop table t6, t3, t1, t2, t4, t5; +create temporary table t1 (a int not null); +create temporary table t2 (a int not null); +insert into t1 values (1); +insert into t2 values (2); +create table t3 (a int not null) ENGINE=MERGE UNION=(t1,t2); +select * from t3; +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +drop table t3, t2, t1; +create table t1 (a int not null); +create temporary table t2 (a int not null); +insert into t1 values (1); +insert into t2 values (2); +create table t3 (a int not null) ENGINE=MERGE UNION=(t1,t2); +select * from t3; +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +drop table t3; +create temporary table t3 (a int not null) ENGINE=MERGE UNION=(t1,t2); +select * from t3; +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +drop table t3, t2, t1; +# CREATE...SELECT is not implemented for MERGE tables. +CREATE TEMPORARY TABLE t1 (c1 INT NOT NULL); +CREATE TEMPORARY TABLE t2 (c1 INT NOT NULL); +CREATE TABLE t3 (c1 INT NOT NULL); +INSERT INTO t3 VALUES (3), (33); +LOCK TABLES t3 READ; +CREATE TEMPORARY TABLE t4 (c1 INT NOT NULL) ENGINE=MERGE UNION=(t1,t2) +INSERT_METHOD=LAST SELECT * FROM t3; +ERROR HY000: 'test.t4' is not BASE TABLE +SELECT * FROM t4; +ERROR HY000: Table 't4' was not locked with LOCK TABLES +UNLOCK TABLES; +CREATE TEMPORARY TABLE t4 (c1 INT NOT NULL) ENGINE=MERGE UNION=(t1,t2) +INSERT_METHOD=LAST; +INSERT INTO t4 SELECT * FROM t3; +# Alter temporary MERGE table. +ALTER TABLE t4 UNION=(t1); +LOCK TABLES t4 WRITE; +# Alter temporary MERGE table under LOCk tables. +ALTER TABLE t4 UNION=(t1,t2); +UNLOCK TABLES; +# MERGE table and function. +CREATE FUNCTION f1 () RETURNS INT RETURN (SELECT max(c1) FROM t3); +SELECT * FROM t4 WHERE c1 < f1(); +c1 +3 +DROP FUNCTION f1; +DROP TABLE t4, t3, t2, t1; CREATE TABLE t1 ( fileset_id tinyint(3) unsigned NOT NULL default '0', file_code varchar(32) NOT NULL default '', @@ -650,11 +696,11 @@ create table t2 (a int); insert into t1 values (0); insert into t2 values (1); create table t3 engine=merge union=(t1, t2) select * from t1; -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: 'test.t3' is not BASE TABLE create table t3 engine=merge union=(t1, t2) select * from t2; -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: 'test.t3' is not BASE TABLE create table t3 engine=merge union=(t1, t2) select (select max(a) from t2); -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: 'test.t3' is not BASE TABLE drop table t1, t2; create table t1 ( a double(14,4), @@ -784,7 +830,7 @@ ERROR HY000: Unable to open underlying table which is differently defined or of DROP TABLE t1, t2; CREATE TABLE t2(a INT) ENGINE=MERGE UNION=(t3); SELECT * FROM t2; -ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +ERROR 42S02: Table 'test.t3' doesn't exist DROP TABLE t2; CREATE TABLE t1(a INT, b TEXT); CREATE TABLE tm1(a TEXT, b INT) ENGINE=MERGE UNION=(t1); @@ -849,20 +895,17 @@ drop table t2; drop table t1; CREATE TABLE tm1(a INT) ENGINE=MERGE UNION=(t1, t2); SELECT * FROM tm1; -ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +ERROR 42S02: Table 'test.t1' doesn't exist CHECK TABLE tm1; Table Op Msg_type Msg_text -test.tm1 check Error Table 'test.t1' is differently defined or of non-MyISAM type or doesn't exist -test.tm1 check Error Table 'test.t2' is differently defined or of non-MyISAM type or doesn't exist -test.tm1 check Error Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +test.tm1 check Error Table 'test.t1' doesn't exist test.tm1 check error Corrupt CREATE TABLE t1(a INT); SELECT * FROM tm1; -ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +ERROR 42S02: Table 'test.t2' doesn't exist CHECK TABLE tm1; Table Op Msg_type Msg_text -test.tm1 check Error Table 'test.t2' is differently defined or of non-MyISAM type or doesn't exist -test.tm1 check Error Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +test.tm1 check Error Table 'test.t2' doesn't exist test.tm1 check error Corrupt CREATE TABLE t2(a BLOB); SELECT * FROM tm1; @@ -885,3 +928,1026 @@ CREATE TABLE IF NOT EXISTS t1 SELECT * FROM t2; ERROR HY000: You can't specify target table 't1' for update in FROM clause DROP TABLE t1, t2; End of 5.0 tests +create table t1 (c1 int, index(c1)); +create table t2 (c1 int, index(c1)) engine=merge union=(t1); +insert into t1 values (1); +flush tables; +select * from t2; +c1 +1 +flush tables; +truncate table t1; +insert into t1 values (1); +flush tables; +select * from t2; +c1 +1 +truncate table t1; +insert into t1 values (1); +drop table t1,t2; +# +# Extra tests for TRUNCATE. +# +# Truncate MERGE table. +CREATE TABLE t1 (c1 INT, INDEX(c1)); +CREATE TABLE t2 (c1 INT, INDEX(c1)); +CREATE TABLE t3 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t1,t2); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +SELECT * FROM t3; +c1 +1 +2 +TRUNCATE TABLE t3; +SELECT * FROM t3; +c1 +# +# Truncate child table. +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +TRUNCATE TABLE t1; +SELECT * FROM t3; +c1 +2 +# +# Truncate MERGE table under locked tables. +LOCK TABLE t1 WRITE, t2 WRITE, t3 WRITE; +INSERT INTO t1 VALUES (1); +TRUNCATE TABLE t3; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +SELECT * FROM t3; +c1 +1 +2 +# +# Truncate child table under locked tables. +TRUNCATE TABLE t1; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +SELECT * FROM t3; +c1 +1 +2 +UNLOCK TABLES; +DROP TABLE t1, t2, t3; +# +# Truncate temporary MERGE table. +CREATE TEMPORARY TABLE t1 (c1 INT, INDEX(c1)); +CREATE TEMPORARY TABLE t2 (c1 INT, INDEX(c1)); +CREATE TEMPORARY TABLE t3 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t1,t2); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +SELECT * FROM t3; +c1 +1 +2 +TRUNCATE TABLE t3; +SELECT * FROM t3; +c1 +# +# Truncate temporary child table. +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +TRUNCATE TABLE t1; +SELECT * FROM t3; +c1 +2 +# +# Truncate temporary MERGE table under locked tables. +INSERT INTO t1 VALUES (1); +CREATE TABLE t4 (c1 INT, INDEX(c1)); +LOCK TABLE t4 WRITE; +TRUNCATE TABLE t3; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +SELECT * FROM t3; +c1 +1 +2 +# +# Truncate temporary child table under locked tables. +TRUNCATE TABLE t1; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +SELECT * FROM t3; +c1 +1 +2 +UNLOCK TABLES; +DROP TABLE t1, t2, t3, t4; +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM; +CREATE TABLE t2 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1) INSERT_METHOD= LAST; +REPAIR TABLE t1; +INSERT INTO t2 VALUES (1); +Table Op Msg_type Msg_text +test.t1 repair status OK +DROP TABLE t1, t2; +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM; +CREATE TABLE t2 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1) INSERT_METHOD= LAST; +LOCK TABLE t1 WRITE; +INSERT INTO t2 VALUES (1); +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair status OK +UNLOCK TABLES; +DROP TABLE t1, t2; +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM; +LOCK TABLE t1 WRITE; +INSERT INTO t1 VALUES (1); +FLUSH TABLES; +FLUSH TABLES; +SELECT * FROM t1; +c1 +UNLOCK TABLES; +DROP TABLE t1; +# +# Extra tests for Bug#26379 - Combination of FLUSH TABLE and +# REPAIR TABLE corrupts a MERGE table +# +# CREATE ... SELECT is disabled for MERGE tables. +# +CREATE TABLE t1(c1 INT); +INSERT INTO t1 VALUES (1); +CREATE TABLE t2 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1) INSERT_METHOD=LAST; +CREATE TABLE t3 ENGINE=MRG_MYISAM INSERT_METHOD=LAST SELECT * FROM t2; +ERROR HY000: Table 't3' is read only +SHOW CREATE TABLE t3; +ERROR 42S02: Table 'test.t3' doesn't exist +CREATE TABLE t3 ENGINE=MRG_MYISAM UNION=(t1) INSERT_METHOD=LAST +SELECT * FROM t2; +ERROR HY000: 'test.t3' is not BASE TABLE +SHOW CREATE TABLE t3; +ERROR 42S02: Table 'test.t3' doesn't exist +DROP TABLE t1, t2; +# +# CREATE ... LIKE +# +# 1. Create like. +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE t3 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (3); +CREATE TABLE t4 LIKE t3; +SHOW CREATE TABLE t4; +Table Create Table +t4 CREATE TABLE `t4` ( + `c1` int(11) DEFAULT NULL +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=() +INSERT INTO t4 VALUES (4); +ERROR HY000: Table 't4' is read only +DROP TABLE t4; +# +# 1. Create like with locked tables. +LOCK TABLES t3 WRITE, t2 WRITE, t1 WRITE; +CREATE TABLE t4 LIKE t3; +SHOW CREATE TABLE t4; +ERROR HY000: Table 't4' was not locked with LOCK TABLES +INSERT INTO t4 VALUES (4); +ERROR HY000: Table 't4' was not locked with LOCK TABLES +UNLOCK TABLES; +SHOW CREATE TABLE t4; +Table Create Table +t4 CREATE TABLE `t4` ( + `c1` int(11) DEFAULT NULL +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=() +INSERT INTO t4 VALUES (4); +ERROR HY000: Table 't4' is read only +DROP TABLE t4; +# +# Rename child. +# +# 1. Normal rename of non-MERGE table. +CREATE TABLE t4 (c1 INT); +INSERT INTO t4 VALUES (4); +SELECT * FROM t4 ORDER BY c1; +c1 +4 +RENAME TABLE t4 TO t5; +SELECT * FROM t5 ORDER BY c1; +c1 +4 +RENAME TABLE t5 TO t4; +SELECT * FROM t4 ORDER BY c1; +c1 +4 +DROP TABLE t4; +# +# 2. Normal rename. +SELECT * FROM t3 ORDER BY c1; +c1 +1 +2 +3 +RENAME TABLE t2 TO t5; +SELECT * FROM t3 ORDER BY c1; +ERROR 42S02: Table 'test.t2' doesn't exist +RENAME TABLE t5 TO t2; +SELECT * FROM t3 ORDER BY c1; +c1 +1 +2 +3 +# +# 3. Normal rename with locked tables. +LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE; +SELECT * FROM t3 ORDER BY c1; +c1 +1 +2 +3 +RENAME TABLE t2 TO t5; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +SELECT * FROM t3 ORDER BY c1; +c1 +1 +2 +3 +RENAME TABLE t5 TO t2; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +SELECT * FROM t3 ORDER BY c1; +c1 +1 +2 +3 +UNLOCK TABLES; +# +# 4. Alter table rename. +ALTER TABLE t2 RENAME TO t5; +SELECT * FROM t3 ORDER BY c1; +ERROR 42S02: Table 'test.t2' doesn't exist +ALTER TABLE t5 RENAME TO t2; +SELECT * FROM t3 ORDER BY c1; +c1 +1 +2 +3 +# +# 5. Alter table rename with locked tables. +LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE; +ALTER TABLE t2 RENAME TO t5; +SELECT * FROM t3 ORDER BY c1; +ERROR HY000: Table 't3' was not locked with LOCK TABLES +ALTER TABLE t5 RENAME TO t2; +ERROR HY000: Table 't5' was not locked with LOCK TABLES +UNLOCK TABLES; +ALTER TABLE t5 RENAME TO t2; +SELECT * FROM t3 ORDER BY c1; +c1 +1 +2 +3 +# +# Rename parent. +# +# 1. Normal rename with locked tables. +LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE; +SELECT * FROM t3 ORDER BY c1; +c1 +1 +2 +3 +RENAME TABLE t3 TO t5; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +SELECT * FROM t3 ORDER BY c1; +c1 +1 +2 +3 +RENAME TABLE t5 TO t3; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +SELECT * FROM t3 ORDER BY c1; +c1 +1 +2 +3 +# +# 5. Alter table rename with locked tables. +ALTER TABLE t3 RENAME TO t5; +SELECT * FROM t5 ORDER BY c1; +ERROR HY000: Table 't5' was not locked with LOCK TABLES +ALTER TABLE t5 RENAME TO t3; +ERROR HY000: Table 't5' was not locked with LOCK TABLES +UNLOCK TABLES; +ALTER TABLE t5 RENAME TO t3; +SELECT * FROM t3 ORDER BY c1; +c1 +1 +2 +3 +DROP TABLE t1, t2, t3; +# +# Drop locked tables. +# +# 1. Drop parent. +CREATE TABLE t1 (c1 INT, INDEX(c1)); +CREATE TABLE t2 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t1) +INSERT_METHOD=LAST; +LOCK TABLES t1 WRITE, t2 WRITE; +INSERT INTO t1 VALUES (1); +DROP TABLE t2; +SELECT * FROM t2; +ERROR HY000: Table 't2' was not locked with LOCK TABLES +SELECT * FROM t1; +c1 +1 +UNLOCK TABLES; +# 2. Drop child. +CREATE TABLE t2 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t1) +INSERT_METHOD=LAST; +LOCK TABLES t1 WRITE, t2 WRITE; +INSERT INTO t1 VALUES (1); +DROP TABLE t1; +SELECT * FROM t2; +ERROR 42S02: Table 'test.t1' doesn't exist +SELECT * FROM t1; +ERROR 42S02: Table 'test.t1' doesn't exist +UNLOCK TABLES; +DROP TABLE t2; +# +# ALTER TABLE. Change child list. +# +CREATE TABLE t1 (c1 INT, INDEX(c1)); +CREATE TABLE t2 (c1 INT, INDEX(c1)); +CREATE TABLE t3 (c1 INT, INDEX(c1)); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (3); +CREATE TABLE t4 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t3,t2) +INSERT_METHOD=LAST; +# Shrink child list. +ALTER TABLE t4 UNION=(t3); +SHOW CREATE TABLE t4; +Table Create Table +t4 CREATE TABLE `t4` ( + `c1` int(11) DEFAULT NULL, + KEY `c1` (`c1`) +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t3`) +SELECT * FROM t4 ORDER BY c1; +c1 +3 +# Extend child list. +ALTER TABLE t4 UNION=(t3,t2); +SHOW CREATE TABLE t4; +Table Create Table +t4 CREATE TABLE `t4` ( + `c1` int(11) DEFAULT NULL, + KEY `c1` (`c1`) +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t3`,`t2`) +SELECT * FROM t4 ORDER BY c1; +c1 +2 +3 +# +# ALTER TABLE under LOCK TABLES. Change child list. +# +LOCK TABLES t4 WRITE, t3 WRITE, t2 WRITE; +# Shrink child list. +ALTER TABLE t4 UNION=(t3); +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +# Extend child list within locked tables. +ALTER TABLE t4 UNION=(t3,t2); +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +# Extend child list beyond locked tables. +ALTER TABLE t4 UNION=(t3,t2,t1); +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +SHOW CREATE TABLE t4; +Table Create Table +t4 CREATE TABLE `t4` ( + `c1` int(11) DEFAULT NULL, + KEY `c1` (`c1`) +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t3`,`t2`) +SELECT * FROM t4 ORDER BY c1; +c1 +2 +3 +UNLOCK TABLES; +DROP TABLE t4; +# +# ALTER TABLE under LOCK TABLES. Grave change, table re-creation. +# +CREATE TABLE t4 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t1,t2,t3) +INSERT_METHOD=LAST; +# Lock parent first and then children. +LOCK TABLES t4 WRITE, t3 WRITE, t2 WRITE, t1 WRITE; +ALTER TABLE t4 DROP INDEX c1, ADD UNIQUE INDEX (c1); +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +ALTER TABLE t2 DROP INDEX c1, ADD UNIQUE INDEX (c1); +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +UNLOCK TABLES; +# Lock children first and then parent. +LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE, t4 WRITE; +ALTER TABLE t4 DROP INDEX c1, ADD UNIQUE INDEX (c1); +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +ALTER TABLE t2 DROP INDEX c1, ADD UNIQUE INDEX (c1); +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +UNLOCK TABLES; +# Lock parent between children. +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +ALTER TABLE t4 DROP INDEX c1, ADD UNIQUE INDEX (c1); +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +ALTER TABLE t2 DROP INDEX c1, ADD UNIQUE INDEX (c1); +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +UNLOCK TABLES; +DROP TABLE t1, t2, t3, t4; +# +# ALTER TABLE under LOCK TABLES. Simple change, no re-creation. +# +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE t3 (c1 INT); +CREATE TABLE t4 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1,t2,t3) +INSERT_METHOD=LAST; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (3); +# Lock parent first and then children. +LOCK TABLES t4 WRITE, t3 WRITE, t2 WRITE, t1 WRITE; +ALTER TABLE t4 ALTER COLUMN c1 SET DEFAULT 44; +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +ALTER TABLE t2 ALTER COLUMN c1 SET DEFAULT 22; +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +UNLOCK TABLES; +# Lock children first and then parent. +LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE, t4 WRITE; +ALTER TABLE t4 ALTER COLUMN c1 SET DEFAULT 44; +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +ALTER TABLE t2 ALTER COLUMN c1 SET DEFAULT 22; +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +UNLOCK TABLES; +# Lock parent between children. +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +ALTER TABLE t4 ALTER COLUMN c1 SET DEFAULT 44; +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +ALTER TABLE t2 ALTER COLUMN c1 SET DEFAULT 22; +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +UNLOCK TABLES; +# +# FLUSH TABLE under LOCK TABLES. +# +# Lock parent first and then children. +LOCK TABLES t4 WRITE, t3 WRITE, t2 WRITE, t1 WRITE; +FLUSH TABLE t4; +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +FLUSH TABLE t2; +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +FLUSH TABLES; +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +UNLOCK TABLES; +# Lock children first and then parent. +LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE, t4 WRITE; +FLUSH TABLE t4; +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +FLUSH TABLE t2; +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +FLUSH TABLES; +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +UNLOCK TABLES; +# Lock parent between children. +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +FLUSH TABLE t4; +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +FLUSH TABLE t2; +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +FLUSH TABLES; +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +UNLOCK TABLES; +# +# Triggers +# +# Trigger on parent +DELETE FROM t4 WHERE c1 = 4; +CREATE TRIGGER t4_ai AFTER INSERT ON t4 FOR EACH ROW SET @a=1; +SET @a=0; +INSERT INTO t4 VALUES (4); +SELECT @a; +@a +1 +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +DROP TRIGGER t4_ai; +# Trigger on parent under LOCK TABLES +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +CREATE TRIGGER t4_ai AFTER INSERT ON t4 FOR EACH ROW SET @a=1; +SET @a=0; +INSERT INTO t4 VALUES (4); +SELECT @a; +@a +1 +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +4 +DROP TRIGGER t4_ai; +UNLOCK TABLES; +# +# Trigger on child +DELETE FROM t4 WHERE c1 = 4; +CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW SET @a=1; +SET @a=0; +INSERT INTO t4 VALUES (4); +SELECT @a; +@a +0 +INSERT INTO t3 VALUES (33); +SELECT @a; +@a +1 +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +33 +DROP TRIGGER t3_ai; +# Trigger on child under LOCK TABLES +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW SET @a=1; +SET @a=0; +INSERT INTO t4 VALUES (4); +SELECT @a; +@a +0 +INSERT INTO t3 VALUES (33); +SELECT @a; +@a +1 +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +4 +33 +33 +DELETE FROM t4 WHERE c1 = 33; +DROP TRIGGER t3_ai; +# +# Trigger with table use on child +DELETE FROM t4 WHERE c1 = 4; +CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW INSERT INTO t2 VALUES(22); +INSERT INTO t4 VALUES (4); +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +INSERT INTO t3 VALUES (33); +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +22 +33 +DELETE FROM t4 WHERE c1 = 22; +DELETE FROM t4 WHERE c1 = 33; +DROP TRIGGER t3_ai; +# Trigger with table use on child under LOCK TABLES +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW INSERT INTO t2 VALUES(22); +INSERT INTO t4 VALUES (4); +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +4 +INSERT INTO t3 VALUES (33); +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +4 +22 +33 +DROP TRIGGER t3_ai; +DELETE FROM t4 WHERE c1 = 22; +DELETE FROM t4 WHERE c1 = 33; +UNLOCK TABLES; +# +# Repair +# +REPAIR TABLE t4; +Table Op Msg_type Msg_text +test.t4 repair note The storage engine for the table doesn't support repair +REPAIR TABLE t2; +Table Op Msg_type Msg_text +test.t2 repair status OK +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +4 +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +REPAIR TABLE t4; +Table Op Msg_type Msg_text +test.t4 repair note The storage engine for the table doesn't support repair +REPAIR TABLE t2; +Table Op Msg_type Msg_text +test.t2 repair status OK +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +4 +UNLOCK TABLES; +# +# Optimize +# +OPTIMIZE TABLE t4; +Table Op Msg_type Msg_text +test.t4 optimize note The storage engine for the table doesn't support optimize +OPTIMIZE TABLE t2; +Table Op Msg_type Msg_text +test.t2 optimize status OK +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +4 +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +OPTIMIZE TABLE t4; +Table Op Msg_type Msg_text +test.t4 optimize note The storage engine for the table doesn't support optimize +OPTIMIZE TABLE t2; +Table Op Msg_type Msg_text +test.t2 optimize status Table is already up to date +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +4 +UNLOCK TABLES; +# +# Checksum +# +CHECKSUM TABLE t4; +Table Checksum +test.t4 46622073 +CHECKSUM TABLE t2; +Table Checksum +test.t2 3700403066 +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +4 +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +CHECKSUM TABLE t4; +Table Checksum +test.t4 46622073 +CHECKSUM TABLE t2; +Table Checksum +test.t2 3700403066 +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +4 +UNLOCK TABLES; +# +# Insert delayed +# +INSERT DELAYED INTO t4 VALUES(44); +DELETE FROM t4 WHERE c1 = 44; +INSERT DELAYED INTO t3 VALUES(33); +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +4 +33 +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +INSERT DELAYED INTO t4 VALUES(444); +Got one of the listed errors +INSERT DELAYED INTO t3 VALUES(333); +Got one of the listed errors +SELECT * FROM t4 ORDER BY c1; +c1 +1 +2 +3 +4 +4 +33 +UNLOCK TABLES; +DROP TABLE t1, t2, t3, t4; +# +# Recursive inclusion of merge tables in their union clauses. +# +CREATE TABLE t1 (c1 INT, INDEX(c1)); +CREATE TABLE t2 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t1) +INSERT_METHOD=LAST; +CREATE TABLE t3 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t2,t1) +INSERT_METHOD=LAST; +ALTER TABLE t2 UNION=(t3,t1); +SELECT * FROM t2; +ERROR HY000: Table 't3' is differently defined or of non-MyISAM type or doesn't exist +DROP TABLE t1, t2, t3; +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM; +CREATE TABLE t2 (c1 INT) ENGINE= MyISAM; +CREATE TABLE t3 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1, t2); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +SELECT * FROM t3; +c1 +1 +2 +TRUNCATE TABLE t1; +SELECT * FROM t3; +c1 +2 +DROP TABLE t1, t2, t3; +CREATE TABLE t1 (id INTEGER, grp TINYINT, id_rev INTEGER); +SET @rnd_max= 2147483647; +SET @rnd= RAND(); +SET @id = CAST(@rnd * @rnd_max AS UNSIGNED); +SET @id_rev= @rnd_max - @id; +SET @grp= CAST(127.0 * @rnd AS UNSIGNED); +INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev); +SET @rnd= RAND(); +SET @id = CAST(@rnd * @rnd_max AS UNSIGNED); +SET @id_rev= @rnd_max - @id; +SET @grp= CAST(127.0 * @rnd AS UNSIGNED); +INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev); +SET @rnd= RAND(); +SET @id = CAST(@rnd * @rnd_max AS UNSIGNED); +SET @id_rev= @rnd_max - @id; +SET @grp= CAST(127.0 * @rnd AS UNSIGNED); +INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev); +SET @rnd= RAND(); +SET @id = CAST(@rnd * @rnd_max AS UNSIGNED); +SET @id_rev= @rnd_max - @id; +SET @grp= CAST(127.0 * @rnd AS UNSIGNED); +INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev); +SET @rnd= RAND(); +SET @id = CAST(@rnd * @rnd_max AS UNSIGNED); +SET @id_rev= @rnd_max - @id; +SET @grp= CAST(127.0 * @rnd AS UNSIGNED); +INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev); +SET @rnd= RAND(); +SET @id = CAST(@rnd * @rnd_max AS UNSIGNED); +SET @id_rev= @rnd_max - @id; +SET @grp= CAST(127.0 * @rnd AS UNSIGNED); +INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev); +SET @rnd= RAND(); +SET @id = CAST(@rnd * @rnd_max AS UNSIGNED); +SET @id_rev= @rnd_max - @id; +SET @grp= CAST(127.0 * @rnd AS UNSIGNED); +INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev); +SET @rnd= RAND(); +SET @id = CAST(@rnd * @rnd_max AS UNSIGNED); +SET @id_rev= @rnd_max - @id; +SET @grp= CAST(127.0 * @rnd AS UNSIGNED); +INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev); +SET @rnd= RAND(); +SET @id = CAST(@rnd * @rnd_max AS UNSIGNED); +SET @id_rev= @rnd_max - @id; +SET @grp= CAST(127.0 * @rnd AS UNSIGNED); +INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev); +SET @rnd= RAND(); +SET @id = CAST(@rnd * @rnd_max AS UNSIGNED); +SET @id_rev= @rnd_max - @id; +SET @grp= CAST(127.0 * @rnd AS UNSIGNED); +INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev); +set @@read_buffer_size=2*1024*1024; +CREATE TABLE t2 SELECT * FROM t1; +INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; +INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; +INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; +INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; +INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; +CREATE TABLE t3 (id INTEGER, grp TINYINT, id_rev INTEGER) +ENGINE= MRG_MYISAM UNION= (t1, t2); +SELECT COUNT(*) FROM t1; +COUNT(*) +130 +SELECT COUNT(*) FROM t2; +COUNT(*) +80 +SELECT COUNT(*) FROM t3; +COUNT(*) +210 +SELECT COUNT(DISTINCT a1.id) FROM t3 AS a1, t3 AS a2 +WHERE a1.id = a2.id GROUP BY a2.grp; +TRUNCATE TABLE t1; +SELECT COUNT(*) FROM t1; +COUNT(*) +0 +SELECT COUNT(*) FROM t2; +COUNT(*) +80 +SELECT COUNT(*) FROM t3; +COUNT(*) +80 +DROP TABLE t1, t2, t3; +CREATE TABLE t1 (c1 INT) ENGINE=MyISAM; +CREATE TABLE t2 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1) INSERT_METHOD=LAST; +INSERT INTO t2 VALUES (1); +SELECT * FROM t2; +c1 +1 +LOCK TABLES t2 WRITE, t1 WRITE; +FLUSH TABLES; +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair status OK +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair status OK +UNLOCK TABLES; +CHECK TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check status OK +LOCK TABLES t2 WRITE, t1 WRITE; +SELECT * FROM t2; +c1 +1 +LOCK TABLES t2 WRITE, t1 WRITE; +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair status OK +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair status OK +UNLOCK TABLES; +CHECK TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1, t2; +CREATE TABLE t1 ( a INT ) ENGINE=MyISAM; +CREATE TABLE m1 ( a INT ) ENGINE=MRG_MYISAM UNION=(t1); +LOCK TABLES t1 WRITE, m1 WRITE; +FLUSH TABLE t1; +UNLOCK TABLES; +DROP TABLE m1, t1; +CREATE TABLE t1 ( a INT ) ENGINE=MyISAM; +CREATE TABLE m1 ( a INT ) ENGINE=MRG_MYISAM UNION=(t1); +LOCK TABLES m1 WRITE, t1 WRITE; +FLUSH TABLE t1; +UNLOCK TABLES; +DROP TABLE m1, t1; +CREATE TABLE t1 (c1 INT, c2 INT) ENGINE= MyISAM; +CREATE TABLE t2 (c1 INT, c2 INT) ENGINE= MyISAM; +CREATE TABLE t3 (c1 INT, c2 INT) ENGINE= MRG_MYISAM UNION(t1, t2); +INSERT INTO t1 VALUES (1, 1); +INSERT INTO t2 VALUES (2, 2); +SELECT * FROM t3; +c1 c2 +1 1 +2 2 +ALTER TABLE t1 ENGINE= MEMORY; +INSERT INTO t1 VALUES (0, 0); +SELECT * FROM t3; +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +DROP TABLE t1, t2, t3; +CREATE TABLE t1 (c1 INT, KEY(c1)); +CREATE TABLE t2 (c1 INT, KEY(c1)) ENGINE=MRG_MYISAM UNION=(t1) +INSERT_METHOD=FIRST; +LOCK TABLE t1 WRITE, t2 WRITE; +FLUSH TABLES t2, t1; +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status Table is already up to date +FLUSH TABLES t1; +UNLOCK TABLES; +FLUSH TABLES; +INSERT INTO t1 VALUES (1); +LOCK TABLE t1 WRITE, t2 WRITE; +FLUSH TABLES t2, t1; +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +FLUSH TABLES t1; +UNLOCK TABLES; +DROP TABLE t1, t2; +CREATE TABLE t1 (ID INT) ENGINE=MYISAM; +CREATE TABLE m1 (ID INT) ENGINE=MRG_MYISAM UNION=(t1) INSERT_METHOD=FIRST; +INSERT INTO t1 VALUES (); +INSERT INTO m1 VALUES (); +LOCK TABLE t1 WRITE, m1 WRITE; +FLUSH TABLES m1, t1; +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +FLUSH TABLES m1, t1; +UNLOCK TABLES; +DROP TABLE t1, m1; diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 50fbe89db52..353d66b1ad5 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -606,24 +606,6 @@ select count(*) from t1 where a is null; count(*) 2 drop table t1; -create table t1 (c1 int, index(c1)); -create table t2 (c1 int, index(c1)) engine=merge union=(t1); -insert into t1 values (1); -flush tables; -select * from t2; -c1 -1 -flush tables; -truncate table t1; -insert into t1 values (1); -flush tables; -select * from t2; -c1 -1 -truncate table t1; -ERROR HY000: MyISAM table 't1' is in use (most likely by a MERGE table). Try FLUSH TABLES. -insert into t1 values (1); -drop table t1,t2; create table t1 (c1 int, c2 varchar(4) not null default '', key(c2(3))) default charset=utf8; insert into t1 values (1,'A'), (2, 'B'), (3, 'A'); diff --git a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result index a1c83ffc73d..a79642a9204 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result +++ b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result @@ -124,6 +124,7 @@ master-bin.000001 # Query # # use `test`; replace into t1 select * from t3 drop table t1,t2,t3; CREATE TABLE t1(a INT) ENGINE=BLACKHOLE; INSERT DELAYED INTO t1 VALUES(1); +ERROR HY000: Binary logging not possible. Message: Row-based format required for this statement, but not allowed by this combination of engines DROP TABLE t1; CREATE TABLE t1(a INT, b INT) ENGINE=BLACKHOLE; DELETE FROM t1 WHERE a=10; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 023e55ea418..45ee4c1c88d 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -483,7 +483,7 @@ drop table t1,t2; create table t1 (a int); --error 1093 create table t1 select * from t1; ---error 1093 +--error ER_WRONG_OBJECT create table t2 union = (t1) select * from t1; flush tables with read lock; unlock tables; diff --git a/mysql-test/t/delayed.test b/mysql-test/t/delayed.test index 03b4f8b3013..a0e25509ba2 100644 --- a/mysql-test/t/delayed.test +++ b/mysql-test/t/delayed.test @@ -243,14 +243,6 @@ FLUSH TABLE t1; SELECT HEX(a) FROM t1; DROP TABLE t1; -# -# Bug#26464 - insert delayed + update + merge = corruption -# -CREATE TABLE t1(c1 INT) ENGINE=MyISAM; -CREATE TABLE t2(c1 INT) ENGINE=MERGE UNION=(t1); ---error 1031 -INSERT DELAYED INTO t2 VALUES(1); -DROP TABLE t1, t2; # # Bug#27358 INSERT DELAYED does not honour SQL_MODE of the client # diff --git a/mysql-test/t/merge-big.test b/mysql-test/t/merge-big.test new file mode 100644 index 00000000000..eddcbb59ed4 --- /dev/null +++ b/mysql-test/t/merge-big.test @@ -0,0 +1,150 @@ +# +# Test of MERGE tables with multisession and many waits. +# +# This test takes rather long time so let us run it only in --big-test mode +--source include/big_test.inc +# We are using some debug-only features in this test +--source include/have_debug.inc + +--disable_warnings +drop table if exists t1,t2,t3,t4,t5,t6; +--enable_warnings + +--echo # +--echo # Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE +--echo # corrupts a MERGE table +--echo # Problem #3 +--echo # +# Two FLUSH TABLES within a LOCK TABLES segment could invalidate the lock. +# This did *not* require a MERGE table. +# +# To increase reproducibility it was necessary to enter a sleep of 2 +# seconds at the end of wait_for_tables() after unlock of LOCK_open. In +# 5.0 and 5.1 the sleep must be inserted in open_and_lock_tables() after +# open_tables() instead. wait_for_tables() is not used in this case. The +# problem was that FLUSH TABLES releases LOCK_open while having unlocked +# and closed all tables. When this happened while a thread was in the +# loop in mysql_lock_tables() right after wait_for_tables() +# (open_tables()) and before retrying to lock, the thread got the lock. +# And it did not notice that the table needed a refresh after the +# [re-]open. So it executed its statement on the table. +# +# The first FLUSH TABLES kicked the INSERT out of thr_multi_lock() and +# let it wait in wait_for_tables() (open_table()). The second FLUSH +# TABLES must happen while the INSERT was on its way from +# wait_for_tables() (open_table()) to the next call of thr_multi_lock(). +# This needed to be supported by a sleep to make it repeatable. +# +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM; +LOCK TABLE t1 WRITE; +#SELECT NOW(); + --echo # connection con1 + connect (con1,localhost,root,,); + let $con1_id= `SELECT CONNECTION_ID()`; + SET SESSION debug="+d,sleep_open_and_lock_after_open"; + send INSERT INTO t1 VALUES (1); +--echo # connection default +connection default; +--echo # Let INSERT go into thr_multi_lock(). +let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE ID = $con1_id AND STATE = 'Locked'; +--source include/wait_condition.inc +#SELECT NOW(); +--echo # Kick INSERT out of thr_multi_lock(). +FLUSH TABLES; +#SELECT NOW(); +--echo # Let INSERT go through open_tables() where it sleeps. +let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE ID = $con1_id AND STATE = 'DBUG sleep'; +--source include/wait_condition.inc +#SELECT NOW(); +--echo # Unlock and close table and wait for con1 to close too. +FLUSH TABLES; +#SELECT NOW(); +--echo # This should give no result. +SELECT * FROM t1; +#SELECT NOW(); +UNLOCK TABLES; + --echo # connection con1 + connection con1; + reap; + SET SESSION debug="-d,sleep_open_and_lock_after_open"; + disconnect con1; +--echo # connection default +connection default; +DROP TABLE t1; + +--echo # +--echo # Extra tests for Bug#26379 - Combination of FLUSH TABLE and +--echo # REPAIR TABLE corrupts a MERGE table +--echo # +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE t3 (c1 INT); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (3); +--echo # +--echo # CREATE ... SELECT +--echo # try to access parent from another thread. +--echo # +#SELECT NOW(); + --echo # connection con1 + connect (con1,localhost,root,,); + let $con1_id= `SELECT CONNECTION_ID()`; + SET SESSION debug="+d,sleep_create_select_before_lock"; + send CREATE TABLE t4 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1,t2) + INSERT_METHOD=FIRST SELECT * FROM t3; +--echo # connection default +connection default; +# wait for the other query to start executing +let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE ID = $con1_id AND STATE = 'DBUG sleep'; +--source include/wait_condition.inc +#SELECT NOW(); +--echo # Now try to access the parent. +--echo # If 3 is in table, SELECT had to wait. +SELECT * FROM t4 ORDER BY c1; +#SELECT NOW(); + --echo # connection con1 + connection con1; + reap; + #SELECT NOW(); + SET SESSION debug="-d,sleep_create_select_before_lock"; + disconnect con1; +--echo # connection default +connection default; +--echo # Cleanup for next test. +DROP TABLE t4; +DELETE FROM t1 WHERE c1 != 1; +--echo # +--echo # CREATE ... SELECT +--echo # try to access child from another thread. +--echo # +#SELECT NOW(); + --echo # connection con1 + connect (con1,localhost,root,,); + let $con1_id= `SELECT CONNECTION_ID()`; + SET SESSION debug="+d,sleep_create_select_before_lock"; + send CREATE TABLE t4 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1,t2) + INSERT_METHOD=FIRST SELECT * FROM t3; +--echo # connection default +connection default; +# wait for the other query to start executing +let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE ID = $con1_id AND STATE = 'DBUG sleep'; +--source include/wait_condition.inc +#SELECT NOW(); +--echo # Now try to access a child. +--echo # If 3 is in table, SELECT had to wait. +SELECT * FROM t1 ORDER BY c1; +#SELECT NOW(); + --echo # connection con1 + connection con1; + reap; + #SELECT NOW(); + SET SESSION debug="-d,sleep_create_select_before_lock"; + disconnect con1; +--echo # connection default +connection default; +DROP TABLE t1, t2, t3, t4; diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index a50588b1e78..cd4e732b954 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -221,6 +221,7 @@ create table t2 (a int not null); insert into t1 values (1); insert into t2 values (2); create temporary table t3 (a int not null) ENGINE=MERGE UNION=(t1,t2); +--error ER_WRONG_MRG_TABLE select * from t3; create temporary table t4 (a int not null); create temporary table t5 (a int not null); @@ -229,6 +230,58 @@ insert into t5 values (2); create temporary table t6 (a int not null) ENGINE=MERGE UNION=(t4,t5); select * from t6; drop table t6, t3, t1, t2, t4, t5; +# +# Bug#19627 - temporary merge table locking +# MERGE table and its children must match in temporary type. +# Forbid temporary merge on non-temporary children: shown above. +# Forbid non-temporary merge on temporary children: +create temporary table t1 (a int not null); +create temporary table t2 (a int not null); +insert into t1 values (1); +insert into t2 values (2); +create table t3 (a int not null) ENGINE=MERGE UNION=(t1,t2); +--error ER_WRONG_MRG_TABLE +select * from t3; +drop table t3, t2, t1; +# Forbid children mismatch in temporary: +create table t1 (a int not null); +create temporary table t2 (a int not null); +insert into t1 values (1); +insert into t2 values (2); +create table t3 (a int not null) ENGINE=MERGE UNION=(t1,t2); +--error ER_WRONG_MRG_TABLE +select * from t3; +drop table t3; +create temporary table t3 (a int not null) ENGINE=MERGE UNION=(t1,t2); +--error ER_WRONG_MRG_TABLE +select * from t3; +drop table t3, t2, t1; +--echo # CREATE...SELECT is not implemented for MERGE tables. +CREATE TEMPORARY TABLE t1 (c1 INT NOT NULL); +CREATE TEMPORARY TABLE t2 (c1 INT NOT NULL); +CREATE TABLE t3 (c1 INT NOT NULL); +INSERT INTO t3 VALUES (3), (33); +LOCK TABLES t3 READ; +--error ER_WRONG_OBJECT +CREATE TEMPORARY TABLE t4 (c1 INT NOT NULL) ENGINE=MERGE UNION=(t1,t2) + INSERT_METHOD=LAST SELECT * FROM t3; +--error ER_TABLE_NOT_LOCKED +SELECT * FROM t4; +UNLOCK TABLES; +CREATE TEMPORARY TABLE t4 (c1 INT NOT NULL) ENGINE=MERGE UNION=(t1,t2) + INSERT_METHOD=LAST; +INSERT INTO t4 SELECT * FROM t3; +--echo # Alter temporary MERGE table. +ALTER TABLE t4 UNION=(t1); +LOCK TABLES t4 WRITE; +--echo # Alter temporary MERGE table under LOCk tables. +ALTER TABLE t4 UNION=(t1,t2); +UNLOCK TABLES; +--echo # MERGE table and function. +CREATE FUNCTION f1 () RETURNS INT RETURN (SELECT max(c1) FROM t3); +SELECT * FROM t4 WHERE c1 < f1(); +DROP FUNCTION f1; +DROP TABLE t4, t3, t2, t1; # # testing merge::records_in_range and optimizer @@ -284,11 +337,11 @@ create table t1 (a int); create table t2 (a int); insert into t1 values (0); insert into t2 values (1); ---error 1093 +--error ER_WRONG_OBJECT create table t3 engine=merge union=(t1, t2) select * from t1; ---error 1093 +--error ER_WRONG_OBJECT create table t3 engine=merge union=(t1, t2) select * from t2; ---error 1093 +--error ER_WRONG_OBJECT create table t3 engine=merge union=(t1, t2) select (select max(a) from t2); drop table t1, t2; @@ -403,7 +456,7 @@ CREATE TABLE t2(a INT) ENGINE=MERGE UNION=(t1); SELECT * FROM t2; DROP TABLE t1, t2; CREATE TABLE t2(a INT) ENGINE=MERGE UNION=(t3); ---error 1168 +--error ER_NO_SUCH_TABLE SELECT * FROM t2; DROP TABLE t2; @@ -495,11 +548,11 @@ drop table t1; # CREATE TABLE fails # CREATE TABLE tm1(a INT) ENGINE=MERGE UNION=(t1, t2); ---error 1168 +--error ER_NO_SUCH_TABLE SELECT * FROM tm1; CHECK TABLE tm1; CREATE TABLE t1(a INT); ---error 1168 +--error ER_NO_SUCH_TABLE SELECT * FROM tm1; CHECK TABLE tm1; CREATE TABLE t2(a BLOB); @@ -526,3 +579,785 @@ CREATE TABLE IF NOT EXISTS t1 SELECT * FROM t2; DROP TABLE t1, t2; --echo End of 5.0 tests + +# +# Bug #8306: TRUNCATE leads to index corruption +# +create table t1 (c1 int, index(c1)); +create table t2 (c1 int, index(c1)) engine=merge union=(t1); +insert into t1 values (1); +# Close all tables. +flush tables; +# Open t2 and (implicitly) t1. +select * from t2; +# Truncate after flush works (unless another threads reopens t2 in between). +flush tables; +truncate table t1; +insert into t1 values (1); +# Close all tables. +flush tables; +# Open t2 and (implicitly) t1. +select * from t2; +# Truncate t1, wich was not recognized as open without the bugfix. +# After fix for Bug#8306 and before fix for Bug#26379, +# it should fail with a table-in-use error message, otherwise succeed. +truncate table t1; +# The insert used to fail on the crashed table. +insert into t1 values (1); +drop table t1,t2; +--echo # +--echo # Extra tests for TRUNCATE. +--echo # +--echo # Truncate MERGE table. +CREATE TABLE t1 (c1 INT, INDEX(c1)); +CREATE TABLE t2 (c1 INT, INDEX(c1)); +CREATE TABLE t3 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t1,t2); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +SELECT * FROM t3; +TRUNCATE TABLE t3; +SELECT * FROM t3; +--echo # +--echo # Truncate child table. +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +TRUNCATE TABLE t1; +SELECT * FROM t3; +--echo # +--echo # Truncate MERGE table under locked tables. +LOCK TABLE t1 WRITE, t2 WRITE, t3 WRITE; +INSERT INTO t1 VALUES (1); +--error ER_LOCK_OR_ACTIVE_TRANSACTION +TRUNCATE TABLE t3; +SELECT * FROM t3; +--echo # +--echo # Truncate child table under locked tables. +--error ER_LOCK_OR_ACTIVE_TRANSACTION +TRUNCATE TABLE t1; +SELECT * FROM t3; +UNLOCK TABLES; +DROP TABLE t1, t2, t3; +--echo # +--echo # Truncate temporary MERGE table. +CREATE TEMPORARY TABLE t1 (c1 INT, INDEX(c1)); +CREATE TEMPORARY TABLE t2 (c1 INT, INDEX(c1)); +CREATE TEMPORARY TABLE t3 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t1,t2); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +SELECT * FROM t3; +TRUNCATE TABLE t3; +SELECT * FROM t3; +--echo # +--echo # Truncate temporary child table. +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +TRUNCATE TABLE t1; +SELECT * FROM t3; +--echo # +--echo # Truncate temporary MERGE table under locked tables. +INSERT INTO t1 VALUES (1); +CREATE TABLE t4 (c1 INT, INDEX(c1)); +LOCK TABLE t4 WRITE; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +TRUNCATE TABLE t3; +SELECT * FROM t3; +--echo # +--echo # Truncate temporary child table under locked tables. +--error ER_LOCK_OR_ACTIVE_TRANSACTION +TRUNCATE TABLE t1; +SELECT * FROM t3; +UNLOCK TABLES; +DROP TABLE t1, t2, t3, t4; + +# +# Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table +# Preparation +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); +connection default; +# +# Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table +# Problem #1 +# A thread trying to lock a MERGE table performed busy waiting while +# REPAIR TABLE or a similar table administration task was ongoing on one or +# more of its MyISAM tables. +# To allow for observability it was necessary to enter a multi-second sleep +# in mysql_admin_table() after remove_table_from_cache(), which comes after +# mysql_abort_lock(). The sleep faked a long running operation. One could +# watch a high CPU load during the sleep time. +# The problem was that mysql_abort_lock() upgrades the write lock to +# TL_WRITE_ONLY. This lock type persisted until the final unlock at the end +# of the administration task. The effect of TL_WRITE_ONLY is to reject any +# attempt to lock the table. The trying thread must close the table and wait +# until it is no longer used. Unfortunately there is no way to detect that +# one of the MyISAM tables of a MERGE table is in use. When trying to lock +# the MERGE table, all MyISAM tables are locked. If one fails on +# TL_WRITE_ONLY, all locks are aborted and wait_for_tables() is entered. +# But this doesn't see the MERGE table as used, so it seems appropriate to +# retry a lock... +# +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM; +CREATE TABLE t2 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1) INSERT_METHOD= LAST; +send REPAIR TABLE t1; + connection con1; + sleep 1; # let repair run into its sleep + INSERT INTO t2 VALUES (1); +connection default; +reap; +DROP TABLE t1, t2; +# +# Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table +# Problem #2 +# A thread trying to lock a MERGE table performed busy waiting until all +# threads that did REPAIR TABLE or similar table administration tasks on +# one or more of its MyISAM tables in LOCK TABLES segments did +# UNLOCK TABLES. +# The difference against problem #1 is that the busy waiting took place +# *after* the administration task. It was terminated by UNLOCK TABLES only. +# +# This is the same test case as for +# Bug#26867 - LOCK TABLES + REPAIR + merge table result in memory/cpu hogging +# +# +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM; +CREATE TABLE t2 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1) INSERT_METHOD= LAST; +LOCK TABLE t1 WRITE; + connection con1; + send INSERT INTO t2 VALUES (1); +connection default; +sleep 1; # Let INSERT go into thr_multi_lock(). +REPAIR TABLE t1; +sleep 2; # con1 performs busy waiting during this sleep. +UNLOCK TABLES; + connection con1; + reap; +connection default; +DROP TABLE t1, t2; +# +# Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table +# Problem #3 +# Two FLUSH TABLES within a LOCK TABLES segment could invalidate the lock. +# This did *not* require a MERGE table. +# To increase reproducibility it was necessary to enter a sleep of 2 seconds +# at the end of wait_for_tables() after unlock of LOCK_open. In 5.0 and 5.1 +# the sleep must be inserted in open_and_lock_tables() after open_tables() +# instead. wait_for_tables() is not used in this case. +# The problem was that FLUSH TABLES releases LOCK_open while having unlocked +# and closed all tables. When this happened while a thread was in the loop in +# mysql_lock_tables() right after wait_for_tables() and before retrying to +# lock, the thread got the lock. (Translate to similar code places in 5.0 +# and 5.1). And it did not notice that the table needed a refresh. So it +# executed its statement on the table. +# The first FLUSH TABLES kicked the INSERT out of thr_multi_lock() and let +# it wait in wait_for_tables(). (open_table() in 5.0 and 5.1). The second +# FLUSH TABLES must happen while the INSERT was on its way from +# wait_for_tables() to the next call of thr_multi_lock(). This needed to be +# supported by a sleep to make it repeatable. +# +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM; +LOCK TABLE t1 WRITE; + connection con1; + send INSERT INTO t1 VALUES (1); +connection default; +sleep 1; # Let INSERT go into thr_multi_lock(). +FLUSH TABLES; +sleep 1; # Let INSERT go through wait_for_tables() where it sleeps. +FLUSH TABLES; +# This should give no result. But it will with sleep(2) at the right place. +SELECT * FROM t1; +UNLOCK TABLES; + connection con1; + reap; +connection default; +DROP TABLE t1; +# +# Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table +# Cleanup +disconnect con1; +disconnect con2; +# +--echo # +--echo # Extra tests for Bug#26379 - Combination of FLUSH TABLE and +--echo # REPAIR TABLE corrupts a MERGE table +# +--echo # +--echo # CREATE ... SELECT is disabled for MERGE tables. +--echo # +CREATE TABLE t1(c1 INT); +INSERT INTO t1 VALUES (1); +CREATE TABLE t2 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1) INSERT_METHOD=LAST; +--error ER_OPEN_AS_READONLY +CREATE TABLE t3 ENGINE=MRG_MYISAM INSERT_METHOD=LAST SELECT * FROM t2; +--error ER_NO_SUCH_TABLE +SHOW CREATE TABLE t3; +--error ER_WRONG_OBJECT +CREATE TABLE t3 ENGINE=MRG_MYISAM UNION=(t1) INSERT_METHOD=LAST + SELECT * FROM t2; +--error ER_NO_SUCH_TABLE +SHOW CREATE TABLE t3; +DROP TABLE t1, t2; +# +--echo # +--echo # CREATE ... LIKE +--echo # +--echo # 1. Create like. +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE t3 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (3); +CREATE TABLE t4 LIKE t3; +SHOW CREATE TABLE t4; +--error ER_OPEN_AS_READONLY +INSERT INTO t4 VALUES (4); +DROP TABLE t4; +--echo # +--echo # 1. Create like with locked tables. +LOCK TABLES t3 WRITE, t2 WRITE, t1 WRITE; +CREATE TABLE t4 LIKE t3; +--error ER_TABLE_NOT_LOCKED +SHOW CREATE TABLE t4; +--error ER_TABLE_NOT_LOCKED +INSERT INTO t4 VALUES (4); +UNLOCK TABLES; +SHOW CREATE TABLE t4; +--error ER_OPEN_AS_READONLY +INSERT INTO t4 VALUES (4); +DROP TABLE t4; +# +--echo # +--echo # Rename child. +--echo # +--echo # 1. Normal rename of non-MERGE table. +CREATE TABLE t4 (c1 INT); +INSERT INTO t4 VALUES (4); +SELECT * FROM t4 ORDER BY c1; +RENAME TABLE t4 TO t5; +SELECT * FROM t5 ORDER BY c1; +RENAME TABLE t5 TO t4; +SELECT * FROM t4 ORDER BY c1; +DROP TABLE t4; +--echo # +--echo # 2. Normal rename. +SELECT * FROM t3 ORDER BY c1; +RENAME TABLE t2 TO t5; +--error ER_NO_SUCH_TABLE +SELECT * FROM t3 ORDER BY c1; +RENAME TABLE t5 TO t2; +SELECT * FROM t3 ORDER BY c1; +--echo # +--echo # 3. Normal rename with locked tables. +LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE; +SELECT * FROM t3 ORDER BY c1; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +RENAME TABLE t2 TO t5; +SELECT * FROM t3 ORDER BY c1; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +RENAME TABLE t5 TO t2; +SELECT * FROM t3 ORDER BY c1; +UNLOCK TABLES; +--echo # +--echo # 4. Alter table rename. +ALTER TABLE t2 RENAME TO t5; +--error ER_NO_SUCH_TABLE +SELECT * FROM t3 ORDER BY c1; +ALTER TABLE t5 RENAME TO t2; +SELECT * FROM t3 ORDER BY c1; +--echo # +--echo # 5. Alter table rename with locked tables. +LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE; +ALTER TABLE t2 RENAME TO t5; +--error ER_TABLE_NOT_LOCKED +SELECT * FROM t3 ORDER BY c1; +--error ER_TABLE_NOT_LOCKED +ALTER TABLE t5 RENAME TO t2; +UNLOCK TABLES; +ALTER TABLE t5 RENAME TO t2; +SELECT * FROM t3 ORDER BY c1; +# +--echo # +--echo # Rename parent. +--echo # +--echo # 1. Normal rename with locked tables. +LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE; +SELECT * FROM t3 ORDER BY c1; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +RENAME TABLE t3 TO t5; +SELECT * FROM t3 ORDER BY c1; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +RENAME TABLE t5 TO t3; +SELECT * FROM t3 ORDER BY c1; +--echo # +--echo # 5. Alter table rename with locked tables. +ALTER TABLE t3 RENAME TO t5; +--error ER_TABLE_NOT_LOCKED +SELECT * FROM t5 ORDER BY c1; +--error ER_TABLE_NOT_LOCKED +ALTER TABLE t5 RENAME TO t3; +UNLOCK TABLES; +ALTER TABLE t5 RENAME TO t3; +SELECT * FROM t3 ORDER BY c1; +DROP TABLE t1, t2, t3; +# +--echo # +--echo # Drop locked tables. +--echo # +--echo # 1. Drop parent. +CREATE TABLE t1 (c1 INT, INDEX(c1)); +CREATE TABLE t2 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t1) + INSERT_METHOD=LAST; +LOCK TABLES t1 WRITE, t2 WRITE; +INSERT INTO t1 VALUES (1); +DROP TABLE t2; +--error ER_TABLE_NOT_LOCKED +SELECT * FROM t2; +SELECT * FROM t1; +UNLOCK TABLES; +--echo # 2. Drop child. +CREATE TABLE t2 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t1) + INSERT_METHOD=LAST; +LOCK TABLES t1 WRITE, t2 WRITE; +INSERT INTO t1 VALUES (1); +DROP TABLE t1; +--error ER_NO_SUCH_TABLE +SELECT * FROM t2; +--error ER_NO_SUCH_TABLE +SELECT * FROM t1; +UNLOCK TABLES; +DROP TABLE t2; +# +--echo # +--echo # ALTER TABLE. Change child list. +--echo # +CREATE TABLE t1 (c1 INT, INDEX(c1)); +CREATE TABLE t2 (c1 INT, INDEX(c1)); +CREATE TABLE t3 (c1 INT, INDEX(c1)); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (3); +CREATE TABLE t4 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t3,t2) + INSERT_METHOD=LAST; +--echo # Shrink child list. +ALTER TABLE t4 UNION=(t3); +SHOW CREATE TABLE t4; +SELECT * FROM t4 ORDER BY c1; +--echo # Extend child list. +ALTER TABLE t4 UNION=(t3,t2); +SHOW CREATE TABLE t4; +SELECT * FROM t4 ORDER BY c1; +# +--echo # +--echo # ALTER TABLE under LOCK TABLES. Change child list. +--echo # +LOCK TABLES t4 WRITE, t3 WRITE, t2 WRITE; +--echo # Shrink child list. +--error ER_LOCK_OR_ACTIVE_TRANSACTION +ALTER TABLE t4 UNION=(t3); +--echo # Extend child list within locked tables. +--error ER_LOCK_OR_ACTIVE_TRANSACTION +ALTER TABLE t4 UNION=(t3,t2); +--echo # Extend child list beyond locked tables. +--error ER_LOCK_OR_ACTIVE_TRANSACTION +ALTER TABLE t4 UNION=(t3,t2,t1); +SHOW CREATE TABLE t4; +SELECT * FROM t4 ORDER BY c1; +UNLOCK TABLES; +DROP TABLE t4; +# +--echo # +--echo # ALTER TABLE under LOCK TABLES. Grave change, table re-creation. +--echo # +CREATE TABLE t4 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t1,t2,t3) + INSERT_METHOD=LAST; +--echo # Lock parent first and then children. +LOCK TABLES t4 WRITE, t3 WRITE, t2 WRITE, t1 WRITE; +ALTER TABLE t4 DROP INDEX c1, ADD UNIQUE INDEX (c1); +SELECT * FROM t4 ORDER BY c1; +ALTER TABLE t2 DROP INDEX c1, ADD UNIQUE INDEX (c1); +SELECT * FROM t4 ORDER BY c1; +UNLOCK TABLES; +--echo # Lock children first and then parent. +LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE, t4 WRITE; +ALTER TABLE t4 DROP INDEX c1, ADD UNIQUE INDEX (c1); +SELECT * FROM t4 ORDER BY c1; +ALTER TABLE t2 DROP INDEX c1, ADD UNIQUE INDEX (c1); +SELECT * FROM t4 ORDER BY c1; +UNLOCK TABLES; +--echo # Lock parent between children. +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +ALTER TABLE t4 DROP INDEX c1, ADD UNIQUE INDEX (c1); +SELECT * FROM t4 ORDER BY c1; +ALTER TABLE t2 DROP INDEX c1, ADD UNIQUE INDEX (c1); +SELECT * FROM t4 ORDER BY c1; +UNLOCK TABLES; +DROP TABLE t1, t2, t3, t4; +# +--echo # +--echo # ALTER TABLE under LOCK TABLES. Simple change, no re-creation. +--echo # +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE t3 (c1 INT); +CREATE TABLE t4 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1,t2,t3) + INSERT_METHOD=LAST; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (3); +--echo # Lock parent first and then children. +LOCK TABLES t4 WRITE, t3 WRITE, t2 WRITE, t1 WRITE; +ALTER TABLE t4 ALTER COLUMN c1 SET DEFAULT 44; +SELECT * FROM t4 ORDER BY c1; +ALTER TABLE t2 ALTER COLUMN c1 SET DEFAULT 22; +SELECT * FROM t4 ORDER BY c1; +UNLOCK TABLES; +--echo # Lock children first and then parent. +LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE, t4 WRITE; +ALTER TABLE t4 ALTER COLUMN c1 SET DEFAULT 44; +SELECT * FROM t4 ORDER BY c1; +ALTER TABLE t2 ALTER COLUMN c1 SET DEFAULT 22; +SELECT * FROM t4 ORDER BY c1; +UNLOCK TABLES; +--echo # Lock parent between children. +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +ALTER TABLE t4 ALTER COLUMN c1 SET DEFAULT 44; +SELECT * FROM t4 ORDER BY c1; +ALTER TABLE t2 ALTER COLUMN c1 SET DEFAULT 22; +SELECT * FROM t4 ORDER BY c1; +UNLOCK TABLES; +# +--echo # +--echo # FLUSH TABLE under LOCK TABLES. +--echo # +--echo # Lock parent first and then children. +LOCK TABLES t4 WRITE, t3 WRITE, t2 WRITE, t1 WRITE; +FLUSH TABLE t4; +SELECT * FROM t4 ORDER BY c1; +FLUSH TABLE t2; +SELECT * FROM t4 ORDER BY c1; +FLUSH TABLES; +SELECT * FROM t4 ORDER BY c1; +UNLOCK TABLES; +--echo # Lock children first and then parent. +LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE, t4 WRITE; +FLUSH TABLE t4; +SELECT * FROM t4 ORDER BY c1; +FLUSH TABLE t2; +SELECT * FROM t4 ORDER BY c1; +FLUSH TABLES; +SELECT * FROM t4 ORDER BY c1; +UNLOCK TABLES; +--echo # Lock parent between children. +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +FLUSH TABLE t4; +SELECT * FROM t4 ORDER BY c1; +FLUSH TABLE t2; +SELECT * FROM t4 ORDER BY c1; +FLUSH TABLES; +SELECT * FROM t4 ORDER BY c1; +UNLOCK TABLES; +# +--echo # +--echo # Triggers +--echo # +--echo # Trigger on parent +DELETE FROM t4 WHERE c1 = 4; +CREATE TRIGGER t4_ai AFTER INSERT ON t4 FOR EACH ROW SET @a=1; +SET @a=0; +INSERT INTO t4 VALUES (4); +SELECT @a; +SELECT * FROM t4 ORDER BY c1; +DROP TRIGGER t4_ai; +--echo # Trigger on parent under LOCK TABLES +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +CREATE TRIGGER t4_ai AFTER INSERT ON t4 FOR EACH ROW SET @a=1; +SET @a=0; +INSERT INTO t4 VALUES (4); +SELECT @a; +SELECT * FROM t4 ORDER BY c1; +DROP TRIGGER t4_ai; +UNLOCK TABLES; +--echo # +--echo # Trigger on child +DELETE FROM t4 WHERE c1 = 4; +CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW SET @a=1; +SET @a=0; +INSERT INTO t4 VALUES (4); +SELECT @a; +INSERT INTO t3 VALUES (33); +SELECT @a; +SELECT * FROM t4 ORDER BY c1; +DROP TRIGGER t3_ai; +--echo # Trigger on child under LOCK TABLES +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW SET @a=1; +SET @a=0; +INSERT INTO t4 VALUES (4); +SELECT @a; +INSERT INTO t3 VALUES (33); +SELECT @a; +SELECT * FROM t4 ORDER BY c1; +DELETE FROM t4 WHERE c1 = 33; +DROP TRIGGER t3_ai; +--echo # +--echo # Trigger with table use on child +DELETE FROM t4 WHERE c1 = 4; +CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW INSERT INTO t2 VALUES(22); +INSERT INTO t4 VALUES (4); +SELECT * FROM t4 ORDER BY c1; +INSERT INTO t3 VALUES (33); +SELECT * FROM t4 ORDER BY c1; +DELETE FROM t4 WHERE c1 = 22; +DELETE FROM t4 WHERE c1 = 33; +DROP TRIGGER t3_ai; +--echo # Trigger with table use on child under LOCK TABLES +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW INSERT INTO t2 VALUES(22); +INSERT INTO t4 VALUES (4); +SELECT * FROM t4 ORDER BY c1; +INSERT INTO t3 VALUES (33); +SELECT * FROM t4 ORDER BY c1; +DROP TRIGGER t3_ai; +DELETE FROM t4 WHERE c1 = 22; +DELETE FROM t4 WHERE c1 = 33; +UNLOCK TABLES; +# +--echo # +--echo # Repair +--echo # +REPAIR TABLE t4; +REPAIR TABLE t2; +SELECT * FROM t4 ORDER BY c1; +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +REPAIR TABLE t4; +REPAIR TABLE t2; +SELECT * FROM t4 ORDER BY c1; +UNLOCK TABLES; +# +--echo # +--echo # Optimize +--echo # +OPTIMIZE TABLE t4; +OPTIMIZE TABLE t2; +SELECT * FROM t4 ORDER BY c1; +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +OPTIMIZE TABLE t4; +OPTIMIZE TABLE t2; +SELECT * FROM t4 ORDER BY c1; +UNLOCK TABLES; +# +--echo # +--echo # Checksum +--echo # +CHECKSUM TABLE t4; +CHECKSUM TABLE t2; +SELECT * FROM t4 ORDER BY c1; +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +CHECKSUM TABLE t4; +CHECKSUM TABLE t2; +SELECT * FROM t4 ORDER BY c1; +UNLOCK TABLES; +# +--echo # +--echo # Insert delayed +--echo # +# See also Bug#26464 - insert delayed + update + merge = corruption +# Succeeds in embedded server - is converted to normal insert +# Fails in normal server, ps-protocol - not supported by engine +# Fails in normal server, normal protocol - not a base table +--error 0, ER_ILLEGAL_HA, ER_WRONG_OBJECT +INSERT DELAYED INTO t4 VALUES(44); +# Get rid of row in embedded server +DELETE FROM t4 WHERE c1 = 44; +INSERT DELAYED INTO t3 VALUES(33); + let $wait_cmd= SHOW STATUS LIKE 'Not_flushed_delayed_rows'; + let $run= query_get_value($wait_cmd, Value, 1); + while ($run) + { + let $run= query_get_value($wait_cmd, Value, 1); + } +SELECT * FROM t4 ORDER BY c1; +LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE; +--error ER_DELAYED_INSERT_TABLE_LOCKED, ER_ILLEGAL_HA +INSERT DELAYED INTO t4 VALUES(444); +--error ER_DELAYED_INSERT_TABLE_LOCKED, ER_ILLEGAL_HA +INSERT DELAYED INTO t3 VALUES(333); +SELECT * FROM t4 ORDER BY c1; +UNLOCK TABLES; +DROP TABLE t1, t2, t3, t4; +# +--echo # +--echo # Recursive inclusion of merge tables in their union clauses. +--echo # +CREATE TABLE t1 (c1 INT, INDEX(c1)); +CREATE TABLE t2 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t1) + INSERT_METHOD=LAST; +CREATE TABLE t3 (c1 INT, INDEX(c1)) ENGINE=MRG_MYISAM UNION=(t2,t1) + INSERT_METHOD=LAST; +ALTER TABLE t2 UNION=(t3,t1); +--error ER_ADMIN_WRONG_MRG_TABLE +SELECT * FROM t2; +DROP TABLE t1, t2, t3; + + +# +# Bug#25038 - Waiting TRUNCATE +# +# Show that truncate of child table after use of parent table works. +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM; +CREATE TABLE t2 (c1 INT) ENGINE= MyISAM; +CREATE TABLE t3 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1, t2); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +SELECT * FROM t3; +TRUNCATE TABLE t1; +SELECT * FROM t3; +DROP TABLE t1, t2, t3; +# +# Show that truncate of child table waits while parent table is used. +# (test partly borrowed from count_distinct3.) +CREATE TABLE t1 (id INTEGER, grp TINYINT, id_rev INTEGER); +SET @rnd_max= 2147483647; +let $1 = 10; +while ($1) +{ + SET @rnd= RAND(); + SET @id = CAST(@rnd * @rnd_max AS UNSIGNED); + SET @id_rev= @rnd_max - @id; + SET @grp= CAST(127.0 * @rnd AS UNSIGNED); + INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev); + dec $1; +} +set @@read_buffer_size=2*1024*1024; +CREATE TABLE t2 SELECT * FROM t1; +INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; +INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; +INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; +INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; +INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; +CREATE TABLE t3 (id INTEGER, grp TINYINT, id_rev INTEGER) + ENGINE= MRG_MYISAM UNION= (t1, t2); +SELECT COUNT(*) FROM t1; +SELECT COUNT(*) FROM t2; +SELECT COUNT(*) FROM t3; +connect (con1,localhost,root,,); + # As t3 contains random numbers, results are different from test to test. + # That's okay, because we test only that select doesn't yield an + # error. Note, that --disable_result_log doesn't suppress error output. + --disable_result_log + send SELECT COUNT(DISTINCT a1.id) FROM t3 AS a1, t3 AS a2 + WHERE a1.id = a2.id GROUP BY a2.grp; +connection default; +sleep 1; +TRUNCATE TABLE t1; + connection con1; + reap; + --enable_result_log + disconnect con1; +connection default; +SELECT COUNT(*) FROM t1; +SELECT COUNT(*) FROM t2; +SELECT COUNT(*) FROM t3; +DROP TABLE t1, t2, t3; + +# +# Bug#25700 - merge base tables get corrupted by optimize/analyze/repair table +# +# Using FLUSH TABLES before REPAIR. +CREATE TABLE t1 (c1 INT) ENGINE=MyISAM; +CREATE TABLE t2 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1) INSERT_METHOD=LAST; +INSERT INTO t2 VALUES (1); +SELECT * FROM t2; +LOCK TABLES t2 WRITE, t1 WRITE; +FLUSH TABLES; +REPAIR TABLE t1; +CHECK TABLE t1; +REPAIR TABLE t1; +UNLOCK TABLES; +CHECK TABLE t1 EXTENDED; +# +# Not using FLUSH TABLES before REPAIR. +LOCK TABLES t2 WRITE, t1 WRITE; +SELECT * FROM t2; +LOCK TABLES t2 WRITE, t1 WRITE; +REPAIR TABLE t1; +CHECK TABLE t1; +REPAIR TABLE t1; +UNLOCK TABLES; +CHECK TABLE t1 EXTENDED; +DROP TABLE t1, t2; + +# +# Bug#26377 - Deadlock with MERGE and FLUSH TABLE +# +CREATE TABLE t1 ( a INT ) ENGINE=MyISAM; +CREATE TABLE m1 ( a INT ) ENGINE=MRG_MYISAM UNION=(t1); +# Lock t1 first. This did always work. +LOCK TABLES t1 WRITE, m1 WRITE; +FLUSH TABLE t1; +UNLOCK TABLES; +DROP TABLE m1, t1; +# +CREATE TABLE t1 ( a INT ) ENGINE=MyISAM; +CREATE TABLE m1 ( a INT ) ENGINE=MRG_MYISAM UNION=(t1); +# Lock m1 first. This did deadlock. +LOCK TABLES m1 WRITE, t1 WRITE; +FLUSH TABLE t1; +UNLOCK TABLES; +DROP TABLE m1, t1; + +# +# Bug#27660 - Falcon: merge table possible +# +# Normal MyISAM MERGE operation. +CREATE TABLE t1 (c1 INT, c2 INT) ENGINE= MyISAM; +CREATE TABLE t2 (c1 INT, c2 INT) ENGINE= MyISAM; +CREATE TABLE t3 (c1 INT, c2 INT) ENGINE= MRG_MYISAM UNION(t1, t2); +INSERT INTO t1 VALUES (1, 1); +INSERT INTO t2 VALUES (2, 2); +SELECT * FROM t3; +# Try an unsupported engine. +ALTER TABLE t1 ENGINE= MEMORY; +INSERT INTO t1 VALUES (0, 0); +# Before fixing, this succeeded, but (0, 0) was missing. +--error 1168 +SELECT * FROM t3; +DROP TABLE t1, t2, t3; + +# +# Bug#30275 - Merge tables: flush tables or unlock tables causes server to crash +# +CREATE TABLE t1 (c1 INT, KEY(c1)); +CREATE TABLE t2 (c1 INT, KEY(c1)) ENGINE=MRG_MYISAM UNION=(t1) + INSERT_METHOD=FIRST; +LOCK TABLE t1 WRITE, t2 WRITE; +FLUSH TABLES t2, t1; +OPTIMIZE TABLE t1; +FLUSH TABLES t1; +UNLOCK TABLES; +# +FLUSH TABLES; +INSERT INTO t1 VALUES (1); +LOCK TABLE t1 WRITE, t2 WRITE; +FLUSH TABLES t2, t1; +OPTIMIZE TABLE t1; +FLUSH TABLES t1; +UNLOCK TABLES; +DROP TABLE t1, t2; + +# +# Test derived from test program for +# Bug#30273 - merge tables: Can't lock file (errno: 155) +# +CREATE TABLE t1 (ID INT) ENGINE=MYISAM; +CREATE TABLE m1 (ID INT) ENGINE=MRG_MYISAM UNION=(t1) INSERT_METHOD=FIRST; +INSERT INTO t1 VALUES (); +INSERT INTO m1 VALUES (); +LOCK TABLE t1 WRITE, m1 WRITE; +FLUSH TABLES m1, t1; +OPTIMIZE TABLE t1; +FLUSH TABLES m1, t1; +UNLOCK TABLES; +DROP TABLE t1, m1; + diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 43c40ab8966..cadab8b3b70 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -575,32 +575,6 @@ explain select count(*) from t1 where a is null; select count(*) from t1 where a is null; drop table t1; -# -# Bug #8306: TRUNCATE leads to index corruption -# -create table t1 (c1 int, index(c1)); -create table t2 (c1 int, index(c1)) engine=merge union=(t1); -insert into t1 values (1); -# Close all tables. -flush tables; -# Open t2 and (implicitly) t1. -select * from t2; -# Truncate after flush works (unless another threads reopens t2 in between). -flush tables; -truncate table t1; -insert into t1 values (1); -# Close all tables. -flush tables; -# Open t2 and (implicitly) t1. -select * from t2; -# Truncate t1, wich was not recognized as open without the bugfix. -# Now, it should fail with a table-in-use error message. ---error 1105 -truncate table t1; -# The insert used to fail on the crashed table. -insert into t1 values (1); -drop table t1,t2; - # # bug9188 - Corruption Can't open file: 'table.MYI' (errno: 145) # diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index a81ed925562..7f7be4835a5 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -396,6 +396,7 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, struct timespec wait_timeout; enum enum_thr_lock_result result= THR_LOCK_ABORTED; my_bool can_deadlock= test(data->owner->info->n_cursors); + DBUG_ENTER("wait_for_lock"); if (!in_wait_list) { @@ -431,13 +432,21 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, if the predicate is true. */ if (data->cond == 0) - break; - if (rc == ETIMEDOUT || rc == ETIME) { - result= THR_LOCK_WAIT_TIMEOUT; + DBUG_PRINT("thr_lock", ("lock granted/aborted")); break; } + if (rc == ETIMEDOUT || rc == ETIME) + { + /* purecov: begin inspected */ + DBUG_PRINT("thr_lock", ("lock timed out")); + result= THR_LOCK_WAIT_TIMEOUT; + break; + /* purecov: end */ + } } + DBUG_PRINT("thr_lock", ("aborted: %d in_wait_list: %d", + thread_var->abort, in_wait_list)); if (data->cond || data->type == TL_UNLOCK) { @@ -453,6 +462,7 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, } else { + DBUG_PRINT("thr_lock", ("lock aborted")); check_locks(data->lock, "aborted wait_for_lock", 0); } } @@ -471,7 +481,7 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, thread_var->current_mutex= 0; thread_var->current_cond= 0; pthread_mutex_unlock(&thread_var->mutex); - return result; + DBUG_RETURN(result); } @@ -509,7 +519,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, and the read lock is not TL_READ_NO_INSERT */ - DBUG_PRINT("lock",("write locked by thread: 0x%lx", + DBUG_PRINT("lock",("write locked 1 by thread: 0x%lx", lock->write.data->owner->info->thread_id)); if (thr_lock_owner_equal(data->owner, lock->write.data->owner) || (lock->write.data->type <= TL_WRITE_DELAYED && @@ -598,10 +608,14 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, { if (lock->write.data->type == TL_WRITE_ONLY) { - /* We are not allowed to get a lock in this case */ - data->type=TL_UNLOCK; - result= THR_LOCK_ABORTED; /* Can't wait for this one */ - goto end; + /* Allow lock owner to bypass TL_WRITE_ONLY. */ + if (!thr_lock_owner_equal(data->owner, lock->write.data->owner)) + { + /* We are not allowed to get a lock in this case */ + data->type=TL_UNLOCK; + result= THR_LOCK_ABORTED; /* Can't wait for this one */ + goto end; + } } /* @@ -631,10 +645,8 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; } - /* purecov: begin inspected */ - DBUG_PRINT("lock",("write locked by thread: 0x%lx", + DBUG_PRINT("lock",("write locked 2 by thread: 0x%lx", lock->write.data->owner->info->thread_id)); - /* purecov: end */ } else { @@ -669,7 +681,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, goto end; } } - DBUG_PRINT("lock",("write locked by thread: 0x%lx type: %d", + DBUG_PRINT("lock",("write locked 3 by thread: 0x%lx type: %d", lock->read.data->owner->info->thread_id, data->type)); } wait_queue= &lock->write_wait; @@ -683,6 +695,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, lock_owner= lock->read.data ? lock->read.data : lock->write.data; if (lock_owner && lock_owner->owner->info == owner->info) { + DBUG_PRINT("lock",("deadlock")); result= THR_LOCK_DEADLOCK; goto end; } diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 55af0c38aed..be75eff2575 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -321,7 +321,7 @@ ndbcluster_binlog_open_table(THD *thd, NDB_SHARE *share, DBUG_ENTER("ndbcluster_binlog_open_table"); safe_mutex_assert_owner(&LOCK_open); - init_tmp_table_share(table_share, share->db, 0, share->table_name, + init_tmp_table_share(thd, table_share, share->db, 0, share->table_name, share->key); if ((error= open_table_def(thd, table_share, 0))) { diff --git a/sql/handler.cc b/sql/handler.cc index 8a2355c8a87..a4926071598 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2643,7 +2643,7 @@ int ha_create_table(THD *thd, const char *path, TABLE_SHARE share; DBUG_ENTER("ha_create_table"); - init_tmp_table_share(&share, db, 0, table_name, path); + init_tmp_table_share(thd, &share, db, 0, table_name, path); if (open_table_def(thd, &share, 0) || open_table_from_share(thd, &share, "", 0, (uint) READ_ALL, 0, &table, TRUE)) @@ -2709,7 +2709,7 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name) if (error) DBUG_RETURN(2); - init_tmp_table_share(&share, db, 0, name, path); + init_tmp_table_share(thd, &share, db, 0, name, path); if (open_table_def(thd, &share, 0)) { DBUG_RETURN(3); @@ -3717,11 +3717,12 @@ int handler::ha_reset() int handler::ha_write_row(uchar *buf) { int error; + DBUG_ENTER("handler::ha_write_row"); if (unlikely(error= write_row(buf))) - return error; + DBUG_RETURN(error); if (unlikely(error= binlog_log_row(table, 0, buf))) - return error; - return 0; + DBUG_RETURN(error); /* purecov: inspected */ + DBUG_RETURN(0); } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 12838317646..2663de0b16a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -686,7 +686,6 @@ bool check_single_table_access(THD *thd, ulong privilege, bool check_routine_access(THD *thd,ulong want_access,char *db,char *name, bool is_proc, bool no_errors); bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table); -bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list); bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc); bool multi_update_precheck(THD *thd, TABLE_LIST *tables); bool multi_delete_precheck(THD *thd, TABLE_LIST *tables); @@ -1148,6 +1147,9 @@ TABLE *table_cache_insert_placeholder(THD *thd, const char *key, bool lock_table_name_if_not_cached(THD *thd, const char *db, const char *table_name, TABLE **table); TABLE *find_locked_table(THD *thd, const char *db,const char *table_name); +void detach_merge_children(TABLE *table, bool clear_refs); +bool fix_merge_after_open(TABLE_LIST *old_child_list, TABLE_LIST **old_last, + TABLE_LIST *new_child_list, TABLE_LIST **new_last); bool reopen_table(TABLE *table); bool reopen_tables(THD *thd,bool get_locks,bool in_refresh); void close_data_files_and_morph_locks(THD *thd, const char *db, @@ -1398,8 +1400,21 @@ int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond); int open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags); -int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables); -bool open_and_lock_tables(THD *thd,TABLE_LIST *tables); +/* open_and_lock_tables with optional derived handling */ +bool open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, bool derived); +/* simple open_and_lock_tables without derived handling */ +inline bool simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables) +{ + return open_and_lock_tables_derived(thd, tables, FALSE); +} +/* open_and_lock_tables with derived handling */ +inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) +{ + return open_and_lock_tables_derived(thd, tables, TRUE); +} +/* simple open_and_lock_tables without derived handling for single table */ +TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l, + thr_lock_type lock_type); bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags); int lock_tables(THD *thd, TABLE_LIST *tables, uint counter, bool *need_reopen); int decide_logging_format(THD *thd, TABLE_LIST *tables); @@ -1976,7 +1991,8 @@ int format_number(uint inputflag,uint max_length,char * pos,uint length, /* table.cc */ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key, uint key_length); -void init_tmp_table_share(TABLE_SHARE *share, const char *key, uint key_length, +void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key, + uint key_length, const char *table_name, const char *path); void free_table_share(TABLE_SHARE *share); int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags); diff --git a/sql/slave.cc b/sql/slave.cc index 2512954f805..6c130627b14 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1013,6 +1013,12 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, goto err; // mysql_parse took care of the error send thd->proc_info = "Opening master dump table"; + /* + Note: If this function starts to fail for MERGE tables, + change the next two lines to these: + tables.table= NULL; // was set by mysql_rm_table() + if (!open_n_lock_single_table(thd, &tables, TL_WRITE)) + */ tables.lock_type = TL_WRITE; if (!open_ltable(thd, &tables, TL_WRITE, 0)) { diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 66d0cda2155..24b5998b380 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -684,6 +684,9 @@ TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name) to open the table thd->killed will be set if we run out of memory + + If closing a MERGE child, the calling function has to take care for + closing the parent too, if necessary. */ @@ -712,6 +715,12 @@ void close_handle_and_leave_table_as_lock(TABLE *table) share->tmp_table= INTERNAL_TMP_TABLE; // for intern_close_table() } + /* + When closing a MERGE parent or child table, detach the children first. + Do not clear child table references to allow for reopen. + */ + if (table->child_l || table->parent) + detach_merge_children(table, FALSE); table->file->close(); table->db_stat= 0; // Mark file closed release_table_share(table->s, RELEASE_NORMAL); @@ -812,6 +821,10 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild) void intern_close_table(TABLE *table) { // Free all structures DBUG_ENTER("intern_close_table"); + DBUG_PRINT("tcache", ("table: '%s'.'%s' 0x%lx", + table->s ? table->s->db.str : "?", + table->s ? table->s->table_name.str : "?", + (long) table)); free_io_cache(table); delete table->triggers; @@ -835,6 +848,9 @@ static void free_cache_entry(TABLE *table) { DBUG_ENTER("free_cache_entry"); + /* Assert that MERGE children are not attached before final close. */ + DBUG_ASSERT(!table->is_children_attached()); + intern_close_table(table); if (!table->in_use) { @@ -901,6 +917,54 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, pthread_mutex_lock(&oldest_unused_share->mutex); VOID(hash_delete(&table_def_cache, (uchar*) oldest_unused_share)); } + DBUG_PRINT("tcache", ("incremented global refresh_version to: %lu", + refresh_version)); + if (if_wait_for_refresh) + { + /* + Other threads could wait in a loop in open_and_lock_tables(), + trying to lock one or more of our tables. + + If they wait for the locks in thr_multi_lock(), their lock + request is aborted. They loop in open_and_lock_tables() and + enter open_table(). Here they notice the table is refreshed and + wait for COND_refresh. Then they loop again in + open_and_lock_tables() and this time open_table() succeeds. At + this moment, if we (the FLUSH TABLES thread) are scheduled and + on another FLUSH TABLES enter close_cached_tables(), they could + awake while we sleep below, waiting for others threads (us) to + close their open tables. If this happens, the other threads + would find the tables unlocked. They would get the locks, one + after the other, and could do their destructive work. This is an + issue if we have LOCK TABLES in effect. + + The problem is that the other threads passed all checks in + open_table() before we refresh the table. + + The fix for this problem is to set some_tables_deleted for all + threads with open tables. These threads can still get their + locks, but will immediately release them again after checking + this variable. They will then loop in open_and_lock_tables() + again. There they will wait until we update all tables version + below. + + Setting some_tables_deleted is done by remove_table_from_cache() + in the other branch. + + In other words (reviewer suggestion): You need this setting of + some_tables_deleted for the case when table was opened and all + related checks were passed before incrementing refresh_version + (which you already have) but attempt to lock the table happened + after the call to close_old_data_files() i.e. after removal of + current thread locks. + */ + for (uint idx=0 ; idx < open_cache.records ; idx++) + { + TABLE *table=(TABLE*) hash_element(&open_cache,idx); + if (table->in_use) + table->in_use->some_tables_deleted= 1; + } + } } else { @@ -1073,6 +1137,14 @@ static void mark_temp_tables_as_free_for_reuse(THD *thd) { table->query_id= 0; table->file->ha_reset(); + /* + Detach temporary MERGE children from temporary parent to allow new + attach at next open. Do not do the detach, if close_thread_tables() + is called from a sub-statement. The temporary table might still be + used in the top-level statement. + */ + if (table->child_l || table->parent) + detach_merge_children(table, TRUE); } } } @@ -1170,9 +1242,17 @@ static void close_open_tables(THD *thd) void close_thread_tables(THD *thd) { + TABLE *table; prelocked_mode_type prelocked_mode= thd->prelocked_mode; DBUG_ENTER("close_thread_tables"); +#ifdef EXTRA_DEBUG + DBUG_PRINT("tcache", ("open tables:")); + for (table= thd->open_tables; table; table= table->next) + DBUG_PRINT("tcache", ("table: '%s'.'%s' 0x%lx", table->s->db.str, + table->s->table_name.str, (long) table)); +#endif + /* We are assuming here that thd->derived_tables contains ONLY derived tables for this substatement. i.e. instead of approach which uses @@ -1186,7 +1266,7 @@ void close_thread_tables(THD *thd) */ if (thd->derived_tables) { - TABLE *table, *next; + TABLE *next; /* Close all derived tables generated in queries like SELECT * FROM (SELECT * FROM t1) @@ -1266,6 +1346,13 @@ void close_thread_tables(THD *thd) if (!thd->active_transaction()) thd->transaction.xid_state.xid.null(); + /* + Note that we need to hold LOCK_open while changing the + open_tables list. Another thread may work on it. + (See: remove_table_from_cache(), mysql_wait_completed_table()) + Closing a MERGE child before the parent would be fatal if the + other thread tries to abort the MERGE lock in between. + */ if (thd->open_tables) close_open_tables(thd); @@ -1292,8 +1379,17 @@ bool close_thread_table(THD *thd, TABLE **table_ptr) DBUG_ENTER("close_thread_table"); DBUG_ASSERT(table->key_read == 0); DBUG_ASSERT(!table->file || table->file->inited == handler::NONE); + DBUG_PRINT("tcache", ("table: '%s'.'%s' 0x%lx", table->s->db.str, + table->s->table_name.str, (long) table)); *table_ptr=table->next; + /* + When closing a MERGE parent or child table, detach the children first. + Clear child table references to force new assignment at next open. + */ + if (table->child_l || table->parent) + detach_merge_children(table, TRUE); + if (table->needs_reopen_or_name_lock() || thd->version != refresh_version || !table->db_stat) { @@ -1308,6 +1404,9 @@ bool close_thread_table(THD *thd, TABLE **table_ptr) */ DBUG_ASSERT(!table->open_placeholder); + /* Assert that MERGE children are not attached in unused_tables. */ + DBUG_ASSERT(!table->is_children_attached()); + /* Free memory and reset for next loop */ table->file->ha_reset(); table->in_use=0; @@ -1729,6 +1828,8 @@ int drop_temporary_table(THD *thd, TABLE_LIST *table_list) { TABLE *table; DBUG_ENTER("drop_temporary_table"); + DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'", + table_list->db, table_list->table_name)); if (!(table= find_temporary_table(thd, table_list))) DBUG_RETURN(1); @@ -1756,6 +1857,24 @@ int drop_temporary_table(THD *thd, TABLE_LIST *table_list) void close_temporary_table(THD *thd, TABLE *table, bool free_share, bool delete_table) { + DBUG_ENTER("close_temporary_table"); + DBUG_PRINT("tmptable", ("closing table: '%s'.'%s' 0x%lx alias: '%s'", + table->s->db.str, table->s->table_name.str, + (long) table, table->alias)); + + /* + When closing a MERGE parent or child table, detach the children + first. Clear child table references as MERGE table cannot be + reopened after final close of one of its tables. + + This is necessary here because it is sometimes called with attached + tables and without prior close_thread_tables(). E.g. in + mysql_alter_table(), mysql_rm_table_part2(), mysql_truncate(), + drop_open_table(). + */ + if (table->child_l || table->parent) + detach_merge_children(table, TRUE); + if (table->prev) { table->prev->next= table->next; @@ -1782,6 +1901,7 @@ void close_temporary_table(THD *thd, TABLE *table, slave_open_temp_tables--; } close_temporary(table, free_share, delete_table); + DBUG_VOID_RETURN; } @@ -1797,6 +1917,8 @@ void close_temporary(TABLE *table, bool free_share, bool delete_table) { handlerton *table_type= table->s->db_type(); DBUG_ENTER("close_temporary"); + DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'", + table->s->db.str, table->s->table_name.str)); free_io_cache(table); closefrm(table, 0); @@ -1843,6 +1965,9 @@ bool rename_temporary_table(THD* thd, TABLE *table, const char *db, static void relink_unused(TABLE *table) { + /* Assert that MERGE children are not attached in unused_tables. */ + DBUG_ASSERT(!table->is_children_attached()); + if (table != unused_tables) { table->prev->next=table->next; /* Remove from unused list */ @@ -1857,6 +1982,77 @@ static void relink_unused(TABLE *table) } +/** + @brief Prepare an open merge table for close. + + @param[in] thd thread context + @param[in] table table to prepare + @param[in,out] prev_pp pointer to pointer of previous table + + @detail + If the table is a MERGE parent, just detach the children. + If the table is a MERGE child, close the parent (incl. detach). +*/ + +static void unlink_open_merge(THD *thd, TABLE *table, TABLE ***prev_pp) +{ + DBUG_ENTER("unlink_open_merge"); + + if (table->parent) + { + /* + If MERGE child, close parent too. Closing includes detaching. + + This is used for example in ALTER TABLE t1 RENAME TO t5 under + LOCK TABLES where t1 is a MERGE child: + CREATE TABLE t1 (c1 INT); + CREATE TABLE t2 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1); + LOCK TABLES t1 WRITE, t2 WRITE; + ALTER TABLE t1 RENAME TO t5; + */ + TABLE *parent= table->parent; + TABLE **prv_p; + + /* Find parent in open_tables list. */ + for (prv_p= &thd->open_tables; + *prv_p && (*prv_p != parent); + prv_p= &(*prv_p)->next) {} + if (*prv_p) + { + /* Special treatment required if child follows parent in list. */ + if (*prev_pp == &parent->next) + *prev_pp= prv_p; + /* + Remove parent from open_tables list and close it. + This includes detaching and hence clearing parent references. + */ + close_thread_table(thd, prv_p); + } + } + else if (table->child_l) + { + /* + When closing a MERGE parent, detach the children first. It is + not necessary to clear the child or parent table reference of + this table because the TABLE is freed. But we need to clear + the child or parent references of the other belonging tables + so that they cannot be moved into the unused_tables chain with + these pointers set. + + This is used for example in ALTER TABLE t2 RENAME TO t5 under + LOCK TABLES where t2 is a MERGE parent: + CREATE TABLE t1 (c1 INT); + CREATE TABLE t2 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1); + LOCK TABLES t1 WRITE, t2 WRITE; + ALTER TABLE t2 RENAME TO t5; + */ + detach_merge_children(table, TRUE); + } + + DBUG_VOID_RETURN; +} + + /** @brief Remove all instances of table from thread's open list and table cache. @@ -1868,7 +2064,7 @@ static void relink_unused(TABLE *table) FALSE - otherwise @note When unlock parameter is FALSE or current thread doesn't have - any tables locked with LOCK TABLES tables are assumed to be + any tables locked with LOCK TABLES, tables are assumed to be not locked (for example already unlocked). */ @@ -1876,31 +2072,45 @@ void unlink_open_table(THD *thd, TABLE *find, bool unlock) { char key[MAX_DBKEY_LENGTH]; uint key_length= find->s->table_cache_key.length; - TABLE *list, **prev, *next; + TABLE *list, **prev; DBUG_ENTER("unlink_open_table"); safe_mutex_assert_owner(&LOCK_open); - list= thd->open_tables; - prev= &thd->open_tables; memcpy(key, find->s->table_cache_key.str, key_length); - for (; list ; list=next) + /* + Note that we need to hold LOCK_open while changing the + open_tables list. Another thread may work on it. + (See: remove_table_from_cache(), mysql_wait_completed_table()) + Closing a MERGE child before the parent would be fatal if the + other thread tries to abort the MERGE lock in between. + */ + for (prev= &thd->open_tables; *prev; ) { - next=list->next; + list= *prev; + if (list->s->table_cache_key.length == key_length && !memcmp(list->s->table_cache_key.str, key, key_length)) { if (unlock && thd->locked_tables) - mysql_lock_remove(thd, thd->locked_tables, list, TRUE); + mysql_lock_remove(thd, thd->locked_tables, + list->parent ? list->parent : list, TRUE); + + /* Prepare MERGE table for close. Close parent if necessary. */ + unlink_open_merge(thd, list, &prev); + + /* Remove table from open_tables list. */ + *prev= list->next; + /* Close table. */ VOID(hash_delete(&open_cache,(uchar*) list)); // Close table } else { - *prev=list; // put in use list + /* Step to next entry in open_tables list. */ prev= &list->next; } } - *prev=0; + // Notify any 'refresh' threads broadcast_refresh(); DBUG_VOID_RETURN; @@ -2383,9 +2593,14 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table->s->table_name.str); DBUG_RETURN(0); } + /* + When looking for a usable TABLE, ignore MERGE children, as they + belong to their parent and cannot be used explicitly. + */ if (!my_strcasecmp(system_charset_info, table->alias, alias) && table->query_id != thd->query_id && /* skip tables already used */ - !(thd->prelocked_mode && table->query_id)) + !(thd->prelocked_mode && table->query_id) && + !table->parent) { int distance= ((int) table->reginfo.lock_type - (int) table_list->lock_type); @@ -2534,6 +2749,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table= (TABLE*) hash_next(&open_cache, (uchar*) key, key_length, &state)) { + DBUG_PRINT("tcache", ("in_use table: '%s'.'%s' 0x%lx", table->s->db.str, + table->s->table_name.str, (long) table)); /* Here we flush tables marked for flush. Normally, table->s->version contains the value of @@ -2622,6 +2839,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, } if (table) { + DBUG_PRINT("tcache", ("unused table: '%s'.'%s' 0x%lx", table->s->db.str, + table->s->table_name.str, (long) table)); /* Unlink the table from "unused_tables" list. */ if (table == unused_tables) { // First unused @@ -2637,6 +2856,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, { /* Insert a new TABLE instance into the open cache */ int error; + DBUG_PRINT("tcache", ("opening new table")); /* Free cache if too big */ while (open_cache.records > table_cache_size && unused_tables) VOID(hash_delete(&open_cache,(uchar*) unused_tables)); /* purecov: tested */ @@ -2703,7 +2923,9 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_RETURN(0); // VIEW } - DBUG_PRINT("info", ("inserting table 0x%lx into the cache", (long) table)); + DBUG_PRINT("info", ("inserting table '%s'.'%s' 0x%lx into the cache", + table->s->db.str, table->s->table_name.str, + (long) table)); VOID(my_hash_insert(&open_cache,(uchar*) table)); } @@ -2793,9 +3015,12 @@ bool reopen_table(TABLE *table) TABLE_LIST table_list; THD *thd= table->in_use; DBUG_ENTER("reopen_table"); + DBUG_PRINT("tcache", ("table: '%s'.'%s' 0x%lx", table->s->db.str, + table->s->table_name.str, (long) table)); DBUG_ASSERT(table->s->ref_count == 0); DBUG_ASSERT(!table->sort.io_cache); + DBUG_ASSERT(!table->children_attached); #ifdef EXTRA_DEBUG if (table->db_stat) @@ -2836,6 +3061,17 @@ bool reopen_table(TABLE *table) tmp.next= table->next; tmp.prev= table->prev; + /* Preserve MERGE parent. */ + tmp.parent= table->parent; + /* Fix MERGE child list and check for unchanged union. */ + if ((table->child_l || tmp.child_l) && + fix_merge_after_open(table->child_l, table->child_last_l, + tmp.child_l, tmp.child_last_l)) + { + VOID(closefrm(&tmp, 1)); // close file, free everything + goto end; + } + delete table->triggers; if (table->file) VOID(closefrm(table, 1)); // close file, free everything @@ -2857,6 +3093,11 @@ bool reopen_table(TABLE *table) } if (table->triggers) table->triggers->set_table(table); + /* + Do not attach MERGE children here. The children might be reopened + after the parent. Attach children after reopening all tables that + require reopen. See for example reopen_tables(). + */ broadcast_refresh(); error=0; @@ -2909,7 +3150,22 @@ void close_data_files_and_morph_locks(THD *thd, const char *db, !strcmp(table->s->db.str, db)) { if (thd->locked_tables) - mysql_lock_remove(thd, thd->locked_tables, table, TRUE); + { + if (table->parent) + { + /* + If MERGE child, need to reopen parent too. This means that + the first child to be closed will detach all children from + the parent and close it. OTOH in most cases a MERGE table + won't have multiple children with the same db.table_name. + */ + mysql_lock_remove(thd, thd->locked_tables, table->parent, TRUE); + table->parent->open_placeholder= 1; + close_handle_and_leave_table_as_lock(table->parent); + } + else + mysql_lock_remove(thd, thd->locked_tables, table, TRUE); + } table->open_placeholder= 1; close_handle_and_leave_table_as_lock(table); } @@ -2918,6 +3174,62 @@ void close_data_files_and_morph_locks(THD *thd, const char *db, } +/** + @brief Reattach MERGE children after reopen. + + @param[in] thd thread context + @param[in,out] err_tables_p pointer to pointer of tables in error + + @return status + @retval FALSE OK, err_tables_p unchanged + @retval TRUE Error, err_tables_p contains table(s) +*/ + +static bool reattach_merge(THD *thd, TABLE **err_tables_p) +{ + TABLE *table; + TABLE *next; + TABLE **prv_p= &thd->open_tables; + bool error= FALSE; + DBUG_ENTER("reattach_merge"); + + for (table= thd->open_tables; table; table= next) + { + next= table->next; + DBUG_PRINT("tcache", ("check table: '%s'.'%s' 0x%lx next: 0x%lx", + table->s->db.str, table->s->table_name.str, + (long) table, (long) next)); + /* Reattach children for MERGE tables with "closed data files" only. */ + if (table->child_l && !table->children_attached) + { + DBUG_PRINT("tcache", ("MERGE parent, attach children")); + if(table->file->extra(HA_EXTRA_ATTACH_CHILDREN)) + { + my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias); + error= TRUE; + /* Remove table from open_tables. */ + *prv_p= next; + if (next) + prv_p= &next->next; + /* Stack table on error list. */ + table->next= *err_tables_p; + *err_tables_p= table; + continue; + } + else + { + table->children_attached= TRUE; + DBUG_PRINT("myrg", ("attached parent: '%s'.'%s' 0x%lx", + table->s->db.str, + table->s->table_name.str, (long) table)); + } + } + prv_p= &table->next; + } + DBUG_RETURN(error); +} + + /** @brief Reopen all tables with closed data files. @@ -2942,7 +3254,9 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh) { TABLE *table,*next,**prev; TABLE **tables,**tables_ptr; // For locks + TABLE *err_tables= NULL; bool error=0, not_used; + bool merge_table_found= FALSE; DBUG_ENTER("reopen_tables"); if (!thd->open_tables) @@ -2951,10 +3265,15 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh) safe_mutex_assert_owner(&LOCK_open); if (get_locks) { - /* The ptr is checked later */ + /* + The ptr is checked later + Do not handle locks of MERGE children. + */ uint opens=0; for (table= thd->open_tables; table ; table=table->next) - opens++; + if (!table->parent) + opens++; + DBUG_PRINT("tcache", ("open tables to lock: %u", opens)); tables= (TABLE**) my_alloca(sizeof(TABLE*)*opens); } else @@ -2966,17 +3285,37 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh) { uint db_stat=table->db_stat; next=table->next; + DBUG_PRINT("tcache", ("open table: '%s'.'%s' 0x%lx " + "parent: 0x%lx db_stat: %u", + table->s->db.str, table->s->table_name.str, + (long) table, (long) table->parent, db_stat)); + if (table->child_l && !db_stat) + merge_table_found= TRUE; if (!tables || (!db_stat && reopen_table(table))) { my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias); + /* + If we could not allocate 'tables', we may close open tables + here. If a MERGE table is affected, detach the children first. + It is not necessary to clear the child or parent table reference + of this table because the TABLE is freed. But we need to clear + the child or parent references of the other belonging tables so + that they cannot be moved into the unused_tables chain with + these pointers set. + */ + if (table->child_l || table->parent) + detach_merge_children(table, TRUE); VOID(hash_delete(&open_cache,(uchar*) table)); error=1; } else { + DBUG_PRINT("tcache", ("opened. need lock: %d", + get_locks && !db_stat && !table->parent)); *prev= table; prev= &table->next; - if (get_locks && !db_stat) + /* Do not handle locks of MERGE children. */ + if (get_locks && !db_stat && !table->parent) *tables_ptr++= table; // need new lock on this if (in_refresh) { @@ -2985,25 +3324,52 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh) } } } + *prev=0; + /* + When all tables are open again, we can re-attach MERGE children to + their parents. All TABLE objects are still present. + */ + DBUG_PRINT("tcache", ("re-attaching MERGE tables: %d", merge_table_found)); + if (!error && merge_table_found && reattach_merge(thd, &err_tables)) + { + while (err_tables) + { + VOID(hash_delete(&open_cache, (uchar*) err_tables)); + err_tables= err_tables->next; + } + } + DBUG_PRINT("tcache", ("open tables to lock: %u", + (uint) (tables_ptr - tables))); if (tables != tables_ptr) // Should we get back old locks { MYSQL_LOCK *lock; - /* We should always get these locks */ + /* + We should always get these locks. Anyway, we must not go into + wait_for_tables() as it tries to acquire LOCK_open, which is + already locked. + */ thd->some_tables_deleted=0; if ((lock= mysql_lock_tables(thd, tables, (uint) (tables_ptr - tables), - 0, ¬_used))) + MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, ¬_used))) { thd->locked_tables=mysql_lock_merge(thd->locked_tables,lock); } else + { + /* + This case should only happen if there is a bug in the reopen logic. + Need to issue error message to have a reply for the application. + Not exactly what happened though, but close enough. + */ + my_error(ER_LOCK_DEADLOCK, MYF(0)); error=1; + } } if (get_locks && tables) { my_afree((uchar*) tables); } broadcast_refresh(); - *prev=0; DBUG_RETURN(error); } @@ -3030,6 +3396,11 @@ void close_old_data_files(THD *thd, TABLE *table, bool morph_locks, for (; table ; table=table->next) { + DBUG_PRINT("tcache", ("checking table: '%s'.'%s' 0x%lx", + table->s->db.str, table->s->table_name.str, + (long) table)); + DBUG_PRINT("tcache", ("needs refresh: %d is open: %u", + table->needs_reopen_or_name_lock(), table->db_stat)); /* Reopen marked for flush. */ @@ -3041,13 +3412,33 @@ void close_old_data_files(THD *thd, TABLE *table, bool morph_locks, if (morph_locks) { /* - Wake up threads waiting for table-level lock on this table - so they won't sneak in when we will temporarily remove our - lock on it. This will also give them a chance to close their - instances of this table. + Forward lock handling to MERGE parent. But unlock parent + once only. */ - mysql_lock_abort(thd, table, TRUE); - mysql_lock_remove(thd, thd->locked_tables, table, TRUE); + TABLE *ulcktbl= table->parent ? table->parent : table; + if (ulcktbl->lock_count) + { + /* + Wake up threads waiting for table-level lock on this table + so they won't sneak in when we will temporarily remove our + lock on it. This will also give them a chance to close their + instances of this table. + */ + mysql_lock_abort(thd, ulcktbl, TRUE); + mysql_lock_remove(thd, thd->locked_tables, ulcktbl, TRUE); + ulcktbl->lock_count= 0; + } + if ((ulcktbl != table) && ulcktbl->db_stat) + { + /* + Close the parent too. Note that parent can come later in + the list of tables. It will then be noticed as closed and + as a placeholder. When this happens, do not clear the + placeholder flag. See the branch below ("***"). + */ + ulcktbl->open_placeholder= 1; + close_handle_and_leave_table_as_lock(ulcktbl); + } /* We want to protect the table from concurrent DDL operations (like RENAME TABLE) until we will re-open and re-lock it. @@ -3056,7 +3447,7 @@ void close_old_data_files(THD *thd, TABLE *table, bool morph_locks, } close_handle_and_leave_table_as_lock(table); } - else if (table->open_placeholder) + else if (table->open_placeholder && !morph_locks) { /* We come here only in close-for-back-off scenario. So we have to @@ -3064,8 +3455,11 @@ void close_old_data_files(THD *thd, TABLE *table, bool morph_locks, in case of concurrent execution of CREATE TABLE t1 SELECT * FROM t2 and RENAME TABLE t2 TO t1). In close-for-re-open scenario we will probably want to let it stay. + + Note "***": We must not enter this branch if the placeholder + flag has been set because of a former close through a child. + See above the comment that refers to this note. */ - DBUG_ASSERT(!morph_locks); table->open_placeholder= 0; } } @@ -3186,13 +3580,29 @@ TABLE *drop_locked_tables(THD *thd,const char *db, const char *table_name) prev= &thd->open_tables; DBUG_ENTER("drop_locked_tables"); + /* + Note that we need to hold LOCK_open while changing the + open_tables list. Another thread may work on it. + (See: remove_table_from_cache(), mysql_wait_completed_table()) + Closing a MERGE child before the parent would be fatal if the + other thread tries to abort the MERGE lock in between. + */ for (table= thd->open_tables; table ; table=next) { next=table->next; if (!strcmp(table->s->table_name.str, table_name) && !strcmp(table->s->db.str, db)) { - mysql_lock_remove(thd, thd->locked_tables, table, TRUE); + /* If MERGE child, forward lock handling to parent. */ + mysql_lock_remove(thd, thd->locked_tables, + table->parent ? table->parent : table, TRUE); + /* + When closing a MERGE parent or child table, detach the children first. + Clear child table references in case this object is opened again. + */ + if (table->child_l || table->parent) + detach_merge_children(table, TRUE); + if (!found) { found= table; @@ -3241,7 +3651,8 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name) if (!strcmp(table->s->table_name.str, table_name) && !strcmp(table->s->db.str, db)) { - mysql_lock_abort(thd,table, TRUE); + /* If MERGE child, forward lock handling to parent. */ + mysql_lock_abort(thd, table->parent ? table->parent : table, TRUE); break; } } @@ -3272,7 +3683,8 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name) share->table_map_id is given a value that with a high certainty is not used by any other table (the only case where a table id can be reused is on wrap-around, which means more than 4 billion table - shares open at the same time). + share opens have been executed while one table was open all the + time). share->table_map_id is not ~0UL. */ @@ -3511,6 +3923,340 @@ err: } +/** + @brief Add list of MERGE children to a TABLE_LIST list. + + @param[in] tlist the parent TABLE_LIST object just opened + + @return status + @retval 0 OK + @retval != 0 Error + + @detail + When a MERGE parent table has just been opened, insert the + TABLE_LIST chain from the MERGE handle into the table list used for + opening tables for this statement. This lets the children be opened + too. +*/ + +static int add_merge_table_list(TABLE_LIST *tlist) +{ + TABLE *parent= tlist->table; + TABLE_LIST *child_l; + DBUG_ENTER("add_merge_table_list"); + DBUG_PRINT("myrg", ("table: '%s'.'%s' 0x%lx", parent->s->db.str, + parent->s->table_name.str, (long) parent)); + + /* Must not call this with attached children. */ + DBUG_ASSERT(!parent->children_attached); + /* Must not call this with children list in place. */ + DBUG_ASSERT(tlist->next_global != parent->child_l); + /* Prevent inclusion of another MERGE table. Could make infinite recursion. */ + if (tlist->parent_l) + { + my_error(ER_ADMIN_WRONG_MRG_TABLE, MYF(0), tlist->alias); + DBUG_RETURN(1); + } + + /* Fix children.*/ + for (child_l= parent->child_l; ; child_l= child_l->next_global) + { + /* + Note: child_l->table may still be set if this parent was taken + from the unused_tables chain. Ignore this fact here. The + reference will be replaced by the handler in + ::extra(HA_EXTRA_ATTACH_CHILDREN). + */ + + /* Set lock type. */ + child_l->lock_type= tlist->lock_type; + + /* Set parent reference. */ + child_l->parent_l= tlist; + + /* Break when this was the last child. */ + if (&child_l->next_global == parent->child_last_l) + break; + } + + /* Insert children into the table list. */ + *parent->child_last_l= tlist->next_global; + tlist->next_global= parent->child_l; + + /* + Do not fix the prev_global pointers. We will remove the + chain soon anyway. + */ + + DBUG_RETURN(0); +} + + +/** + @brief Attach MERGE children to the parent. + + @param[in] tlist the child TABLE_LIST object just opened + + @return status + @retval 0 OK + @retval != 0 Error + + @note + This is called when the last MERGE child has just been opened, let + the handler attach the MyISAM tables to the MERGE table. Remove + MERGE TABLE_LIST chain from the statement list so that it cannot be + changed or freed. +*/ + +static int attach_merge_children(TABLE_LIST *tlist) +{ + TABLE *parent= tlist->parent_l->table; + int error; + DBUG_ENTER("attach_merge_children"); + DBUG_PRINT("myrg", ("table: '%s'.'%s' 0x%lx", parent->s->db.str, + parent->s->table_name.str, (long) parent)); + + /* Must not call this with attached children. */ + DBUG_ASSERT(!parent->children_attached); + /* Must call this with children list in place. */ + DBUG_ASSERT(tlist->parent_l->next_global == parent->child_l); + + /* Attach MyISAM tables to MERGE table. */ + error= parent->file->extra(HA_EXTRA_ATTACH_CHILDREN); + + /* + Remove children from the table list. Even in case of an error. + This should prevent tampering with them. + */ + tlist->parent_l->next_global= *parent->child_last_l; + + /* + Do not fix the last childs next_global pointer. It is needed for + stepping to the next table in the enclosing loop in open_tables(). + Do not fix prev_global pointers. We did not set them. + */ + + if (error) + { + DBUG_PRINT("error", ("attaching MERGE children failed: %d", my_errno)); + parent->file->print_error(error, MYF(0)); + DBUG_RETURN(1); + } + + parent->children_attached= TRUE; + DBUG_PRINT("myrg", ("attached parent: '%s'.'%s' 0x%lx", parent->s->db.str, + parent->s->table_name.str, (long) parent)); + + /* + Note that we have the cildren in the thd->open_tables list at this + point. + */ + + DBUG_RETURN(0); +} + + +/** + @brief Detach MERGE children from the parent. + + @note + Call this before the first table of a MERGE table (parent or child) + is closed. + + When closing thread tables at end of statement, both parent and + children are in thd->open_tables and will be closed. In most cases + the children will be closed before the parent. They are opened after + the parent and thus stacked into thd->open_tables before it. + + To avoid that we touch a closed children in any way, we must detach + the children from the parent when the first belonging table is + closed (parent or child). + + All references to the children should be removed on handler level + and optionally on table level. + + @note + Assure that you call it for a MERGE parent or child only. + Either table->child_l or table->parent must be set. + + @param[in] table the TABLE object of the parent + @param[in] clear_refs if to clear TABLE references + this must be true when called from + close_thread_tables() to enable fresh + open in open_tables() + it must be false when called in preparation + for reopen_tables() +*/ + +void detach_merge_children(TABLE *table, bool clear_refs) +{ + TABLE_LIST *child_l; + TABLE *parent= table->child_l ? table : table->parent; + bool first_detach; + DBUG_ENTER("detach_merge_children"); + /* + Either table->child_l or table->parent must be set. Parent must have + child_l set. + */ + DBUG_ASSERT(parent && parent->child_l); + DBUG_PRINT("myrg", ("table: '%s'.'%s' 0x%lx clear_refs: %d", + table->s->db.str, table->s->table_name.str, + (long) table, clear_refs)); + DBUG_PRINT("myrg", ("parent: '%s'.'%s' 0x%lx", parent->s->db.str, + parent->s->table_name.str, (long) parent)); + + /* + In a open_tables() loop it can happen that not all tables have their + children attached yet. Also this is called for every child and the + parent from close_thread_tables(). + */ + if ((first_detach= parent->children_attached)) + { + VOID(parent->file->extra(HA_EXTRA_DETACH_CHILDREN)); + parent->children_attached= FALSE; + DBUG_PRINT("myrg", ("detached parent: '%s'.'%s' 0x%lx", parent->s->db.str, + parent->s->table_name.str, (long) parent)); + } + else + DBUG_PRINT("myrg", ("parent is already detached")); + + if (clear_refs) + { + /* In any case clear the own parent reference. (***) */ + table->parent= NULL; + + /* + On the first detach, clear all references. If this table is the + parent, we still may need to clear the child references. The first + detach might not have done this. + */ + if (first_detach || (table == parent)) + { + /* Clear TABLE references to force new assignment at next open. */ + for (child_l= parent->child_l; ; child_l= child_l->next_global) + { + /* + Do not DBUG_ASSERT(child_l->table); open_tables might be + incomplete. + + Clear the parent reference of the children only on the first + detach. The children might already be closed. They will clear + it themseves when this function is called for them with + 'clear_refs' true. See above "(***)". + */ + if (first_detach && child_l->table) + child_l->table->parent= NULL; + + /* Clear the table reference to force new assignment at next open. */ + child_l->table= NULL; + + /* Break when this was the last child. */ + if (&child_l->next_global == parent->child_last_l) + break; + } + } + } + + DBUG_VOID_RETURN; +} + + +/** + @brief Fix MERGE children after open. + + @param[in] old_child_list first list member from original table + @param[in] old_last pointer to &next_global of last list member + @param[in] new_child_list first list member from freshly opened table + @param[in] new_last pointer to &next_global of last list member + + @return mismatch + @retval FALSE OK, no mismatch + @retval TRUE Error, lists mismatch + + @detail + Main action is to copy TABLE reference for each member of original + child list to new child list. After a fresh open these references + are NULL. Assign the old children to the new table. Some of them + might also be reopened or will be reopened soon. + + Other action is to verify that the table definition with respect to + the UNION list did not change. + + @note + This function terminates the child list if the respective '*_last' + pointer is non-NULL. Do not call it from a place where the list is + embedded in another list and this would break it. + + Terminating the list is required for example in the first + reopen_table() after open_tables(). open_tables() requires the end + of the list not to be terminated because other tables could follow + behind the child list. + + If a '*_last' pointer is NULL, the respective list is assumed to be + NULL terminated. +*/ + +bool fix_merge_after_open(TABLE_LIST *old_child_list, TABLE_LIST **old_last, + TABLE_LIST *new_child_list, TABLE_LIST **new_last) +{ + bool mismatch= FALSE; + DBUG_ENTER("fix_merge_after_open"); + DBUG_PRINT("myrg", ("old last addr: 0x%lx new last addr: 0x%lx", + (long) old_last, (long) new_last)); + + /* Terminate the lists for easier check of list end. */ + if (old_last) + *old_last= NULL; + if (new_last) + *new_last= NULL; + + for (;;) + { + DBUG_PRINT("myrg", ("old list item: 0x%lx new list item: 0x%lx", + (long) old_child_list, (long) new_child_list)); + /* Break if one of the list is at its end. */ + if (!old_child_list || !new_child_list) + break; + /* Old table has references to child TABLEs. */ + DBUG_ASSERT(old_child_list->table); + /* New table does not yet have references to child TABLEs. */ + DBUG_ASSERT(!new_child_list->table); + DBUG_PRINT("myrg", ("old table: '%s'.'%s' new table: '%s'.'%s'", + old_child_list->db, old_child_list->table_name, + new_child_list->db, new_child_list->table_name)); + /* Child db.table names must match. */ + if (strcmp(old_child_list->table_name, new_child_list->table_name) || + strcmp(old_child_list->db, new_child_list->db)) + break; + /* + Copy TABLE reference. Child TABLE objects are still in place + though not necessarily open yet. + */ + DBUG_PRINT("myrg", ("old table ref: 0x%lx replaces new table ref: 0x%lx", + (long) old_child_list->table, + (long) new_child_list->table)); + new_child_list->table= old_child_list->table; + /* Step both lists. */ + old_child_list= old_child_list->next_global; + new_child_list= new_child_list->next_global; + } + DBUG_PRINT("myrg", ("end of list, mismatch: %d", mismatch)); + /* + If the list pointers are not both NULL after the loop, then the + lists differ. If the are both identical, but not NULL, then they + have at least one table in common and hence the rest of the list + would be identical too. But in this case the loop woul run until the + list end, where both pointers would become NULL. + */ + if (old_child_list != new_child_list) + mismatch= TRUE; + if (mismatch) + my_error(ER_TABLE_DEF_CHANGED, MYF(0)); + + DBUG_RETURN(mismatch); +} + + /* Open all tables in list @@ -3541,7 +4287,7 @@ err: int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) { - TABLE_LIST *tables; + TABLE_LIST *tables= NULL; bool refresh; int result=0; MEM_ROOT new_frm_mem; @@ -3601,6 +4347,9 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) */ for (tables= *start; tables ;tables= tables->next_global) { + DBUG_PRINT("tcache", ("opening table: '%s'.'%s' item: 0x%lx", + tables->db, tables->table_name, (long) tables)); + safe_to_ignore_table= FALSE; /* @@ -3652,6 +4401,10 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) else tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags); } + else + DBUG_PRINT("tcache", ("referenced table: '%s'.'%s' 0x%lx", + tables->db, tables->table_name, + (long) tables->table)); if (!tables->table) { @@ -3683,6 +4436,19 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) goto process_view_routines; } + /* + If in a MERGE table open, we need to remove the children list + from statement table list before restarting. Otherwise the list + will be inserted another time. + */ + if (tables->parent_l) + { + TABLE_LIST *parent_l= tables->parent_l; + /* The parent table should be correctly open at this point. */ + DBUG_ASSERT(parent_l->table); + parent_l->next_global= *parent_l->table->child_last_l; + } + if (refresh) // Refresh in progress { /* @@ -3751,6 +4517,24 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) thd->update_lock_default : tables->lock_type; tables->table->grant= tables->grant; + /* Attach MERGE children if not locked already. */ + DBUG_PRINT("tcache", ("is parent: %d is child: %d", + test(tables->table->child_l), + test(tables->parent_l))); + DBUG_PRINT("tcache", ("in lock tables: %d in prelock mode: %d", + test(thd->locked_tables), test(thd->prelocked_mode))); + if (((!thd->locked_tables && !thd->prelocked_mode) || + tables->table->s->tmp_table) && + ((tables->table->child_l && + add_merge_table_list(tables)) || + (tables->parent_l && + (&tables->next_global == tables->parent_l->table->child_last_l) && + attach_merge_children(tables)))) + { + result= -1; + goto err; + } + process_view_routines: /* Again we may need cache all routines used by this view and add @@ -3783,6 +4567,18 @@ process_view_routines: if (query_tables_last_own) thd->lex->mark_as_requiring_prelocking(query_tables_last_own); + if (result && tables) + { + /* + Some functions determine success as (tables->table != NULL). + tables->table is in thd->open_tables. It won't go lost. If the + error happens on a MERGE child, clear the parents TABLE reference. + */ + if (tables->parent_l) + tables->parent_l->table= NULL; + tables->table= NULL; + } + DBUG_PRINT("tcache", ("returning: %d", result)); DBUG_RETURN(result); } @@ -3822,6 +4618,63 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table, } +/** + @brief Open and lock one table + + @param[in] thd thread handle + @param[in] table_l table to open is first table in this list + @param[in] lock_type lock to use for table + + @return table + @retval != NULL OK, opened table returned + @retval NULL Error + + @note + If ok, the following are also set: + table_list->lock_type lock_type + table_list->table table + + @note + If table_l is a list, not a single table, the list is temporarily + broken. + + @detail + This function is meant as a replacement for open_ltable() when + MERGE tables can be opened. open_ltable() cannot open MERGE tables. + + There may be more differences between open_n_lock_single_table() and + open_ltable(). One known difference is that open_ltable() does + neither call decide_logging_format() nor handle some other logging + and locking issues because it does not call lock_tables(). +*/ + +TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l, + thr_lock_type lock_type) +{ + TABLE_LIST *save_next_global; + DBUG_ENTER("open_n_lock_single_table"); + + /* Remember old 'next' pointer. */ + save_next_global= table_l->next_global; + /* Break list. */ + table_l->next_global= NULL; + + /* Set requested lock type. */ + table_l->lock_type= lock_type; + /* Allow to open real tables only. */ + table_l->required_type= FRMTYPE_TABLE; + + /* Open the table. */ + if (simple_open_n_lock_tables(thd, table_l)) + table_l->table= NULL; /* Just to be sure. */ + + /* Restore list. */ + table_l->next_global= save_next_global; + + DBUG_RETURN(table_l->table); +} + + /* Open and lock one table @@ -3863,6 +4716,17 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type, if (table) { + if (table->child_l) + { + /* A MERGE table must not come here. */ + /* purecov: begin tested */ + my_error(ER_WRONG_OBJECT, MYF(0), table->s->db.str, + table->s->table_name.str, "BASE TABLE"); + table= 0; + goto end; + /* purecov: end */ + } + table_list->lock_type= lock_type; table_list->table= table; table->grant= table_list->grant; @@ -3880,56 +4744,21 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type, table= 0; } } + + end: thd->proc_info=0; DBUG_RETURN(table); } /* - Open all tables in list and locks them for read without derived - tables processing. + Open all tables in list, locks them and optionally process derived tables. SYNOPSIS - simple_open_n_lock_tables() - thd - thread handler - tables - list of tables for open&locking - - RETURN - 0 - ok - -1 - error - - NOTE - The lock will automaticaly be freed by close_thread_tables() -*/ - -int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables) -{ - uint counter; - bool need_reopen; - DBUG_ENTER("simple_open_n_lock_tables"); - - for ( ; ; ) - { - if (open_tables(thd, &tables, &counter, 0)) - DBUG_RETURN(-1); - if (!lock_tables(thd, tables, counter, &need_reopen)) - break; - if (!need_reopen) - DBUG_RETURN(-1); - close_tables_for_reopen(thd, &tables); - } - DBUG_RETURN(0); -} - - -/* - Open all tables in list, locks them and process derived tables - tables processing. - - SYNOPSIS - open_and_lock_tables() + open_and_lock_tables_derived() thd - thread handler tables - list of tables for open&locking + derived - if to handle derived tables RETURN FALSE - ok @@ -3937,27 +4766,43 @@ int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables) NOTE The lock will automaticaly be freed by close_thread_tables() + + NOTE + There are two convenience functions: + - simple_open_n_lock_tables(thd, tables) without derived handling + - open_and_lock_tables(thd, tables) with derived handling + Both inline functions call open_and_lock_tables_derived() with + the third argument set appropriately. */ -bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) +bool open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, bool derived) { uint counter; bool need_reopen; - DBUG_ENTER("open_and_lock_tables"); + DBUG_ENTER("open_and_lock_tables_derived"); + DBUG_PRINT("enter", ("derived handling: %d", derived)); for ( ; ; ) { if (open_tables(thd, &tables, &counter, 0)) DBUG_RETURN(-1); + + DBUG_EXECUTE_IF("sleep_open_and_lock_after_open", { + const char *old_proc_info= thd->proc_info; + thd->proc_info= "DBUG sleep"; + my_sleep(6000000); + thd->proc_info= old_proc_info;}); + if (!lock_tables(thd, tables, counter, &need_reopen)) break; if (!need_reopen) DBUG_RETURN(-1); close_tables_for_reopen(thd, &tables); } - if (mysql_handle_derived(thd->lex, &mysql_derived_prepare) || - (thd->fill_derived_tables() && - mysql_handle_derived(thd->lex, &mysql_derived_filling))) + if (derived && + (mysql_handle_derived(thd->lex, &mysql_derived_prepare) || + (thd->fill_derived_tables() && + mysql_handle_derived(thd->lex, &mysql_derived_filling)))) DBUG_RETURN(TRUE); /* purecov: inspected */ DBUG_RETURN(0); } @@ -4271,7 +5116,17 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) thd->lock= 0; thd->in_lock_tables=0; - for (table= tables; table != first_not_own; table= table->next_global) + /* + When open_and_lock_tables() is called for a single table out of + a table list, the 'next_global' chain is temporarily broken. We + may not find 'first_not_own' before the end of the "list". + Look for example at those places where open_n_lock_single_table() + is called. That function implements the temporary breaking of + a table list for opening a single table. + */ + for (table= tables; + table && table != first_not_own; + table= table->next_global) { if (!table->placeholder()) { @@ -4298,7 +5153,17 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) else { TABLE_LIST *first_not_own= thd->lex->first_not_own_table(); - for (table= tables; table != first_not_own; table= table->next_global) + /* + When open_and_lock_tables() is called for a single table out of + a table list, the 'next_global' chain is temporarily broken. We + may not find 'first_not_own' before the end of the "list". + Look for example at those places where open_n_lock_single_table() + is called. That function implements the temporary breaking of + a table list for opening a single table. + */ + for (table= tables; + table && table != first_not_own; + table= table->next_global) { if (!table->placeholder() && check_lock_and_start_stmt(thd, table->table, table->lock_type)) @@ -4401,7 +5266,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db, saved_cache_key= strmov(tmp_path, path)+1; memcpy(saved_cache_key, cache_key, key_length); - init_tmp_table_share(share, saved_cache_key, key_length, + init_tmp_table_share(thd, share, saved_cache_key, key_length, strend(saved_cache_key)+1, tmp_path); if (open_table_def(thd, share, 0) || @@ -4434,6 +5299,8 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db, slave_open_temp_tables++; } tmp_table->pos_in_table_list= 0; + DBUG_PRINT("tmptable", ("opened table: '%s'.'%s' 0x%lx", tmp_table->s->db.str, + tmp_table->s->table_name.str, (long) tmp_table)); DBUG_RETURN(tmp_table); } @@ -7112,7 +7979,7 @@ my_bool mysql_rm_tmp_tables(void) /* We should cut file extention before deleting of table */ memcpy(filePathCopy, filePath, filePath_len - ext_len); filePathCopy[filePath_len - ext_len]= 0; - init_tmp_table_share(&share, "", 0, "", filePathCopy); + init_tmp_table_share(thd, &share, "", 0, "", filePathCopy); if (!open_table_def(thd, &share, 0) && ((handler_file= get_new_handler(&share, thd->mem_root, share.db_type())))) @@ -7214,7 +8081,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, TABLE_SHARE *share; bool result= 0, signalled= 0; DBUG_ENTER("remove_table_from_cache"); - DBUG_PRINT("enter", ("Table: '%s.%s' flags: %u", db, table_name, flags)); + DBUG_PRINT("enter", ("table: '%s'.'%s' flags: %u", db, table_name, flags)); key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1; for (;;) @@ -7229,6 +8096,8 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, &state)) { THD *in_use; + DBUG_PRINT("tcache", ("found table: '%s'.'%s' 0x%lx", table->s->db.str, + table->s->table_name.str, (long) table)); table->s->version=0L; /* Free when thread is ready */ if (!(in_use=table->in_use)) @@ -7267,13 +8136,19 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, } /* Now we must abort all tables locks used by this thread - as the thread may be waiting to get a lock for another table + as the thread may be waiting to get a lock for another table. + Note that we need to hold LOCK_open while going through the + list. So that the other thread cannot change it. The other + thread must also hold LOCK_open whenever changing the + open_tables list. Aborting the MERGE lock after a child was + closed and before the parent is closed would be fatal. */ for (TABLE *thd_table= in_use->open_tables; thd_table ; thd_table= thd_table->next) { - if (thd_table->db_stat) // If table is open + /* Do not handle locks of MERGE children. */ + if (thd_table->db_stat && !thd_table->parent) // If table is open signalled|= mysql_lock_abort_for_thread(thd, thd_table); } } @@ -7476,7 +8351,9 @@ int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->old_lock_type= lpt->table->reginfo.lock_type; VOID(pthread_mutex_lock(&LOCK_open)); - mysql_lock_abort(lpt->thd, lpt->table, TRUE); + /* If MERGE child, forward lock handling to parent. */ + mysql_lock_abort(lpt->thd, lpt->table->parent ? lpt->table->parent : + lpt->table, TRUE); VOID(remove_table_from_cache(lpt->thd, lpt->db, lpt->table_name, flags)); VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_RETURN(0); @@ -7497,14 +8374,18 @@ int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) We also downgrade locks after the upgrade to WRITE_ONLY */ +/* purecov: begin unused */ void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt) { VOID(pthread_mutex_lock(&LOCK_open)); remove_table_from_cache(lpt->thd, lpt->db, lpt->table_name, RTFC_WAIT_OTHER_THREAD_FLAG); VOID(pthread_mutex_unlock(&LOCK_open)); - mysql_lock_downgrade_write(lpt->thd, lpt->table, lpt->old_lock_type); + /* If MERGE child, forward lock handling to parent. */ + mysql_lock_downgrade_write(lpt->thd, lpt->table->parent ? lpt->table->parent : + lpt->table, lpt->old_lock_type); } +/* purecov: end */ /* @@ -7570,13 +8451,19 @@ void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table } /* Now we must abort all tables locks used by this thread - as the thread may be waiting to get a lock for another table + as the thread may be waiting to get a lock for another table. + Note that we need to hold LOCK_open while going through the + list. So that the other thread cannot change it. The other + thread must also hold LOCK_open whenever changing the + open_tables list. Aborting the MERGE lock after a child was + closed and before the parent is closed would be fatal. */ for (TABLE *thd_table= in_use->open_tables; thd_table ; thd_table= thd_table->next) { - if (thd_table->db_stat) // If table is open + /* Do not handle locks of MERGE children. */ + if (thd_table->db_stat && !thd_table->parent) // If table is open mysql_lock_abort_for_thread(lpt->thd, thd_table); } } @@ -7586,8 +8473,10 @@ void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table those in use for removal after completion. Now we also need to abort all that are locked and are not progressing due to being locked by our lock. We don't upgrade our lock here. + If MERGE child, forward lock handling to parent. */ - mysql_lock_abort(lpt->thd, my_table, FALSE); + mysql_lock_abort(lpt->thd, my_table->parent ? my_table->parent : my_table, + FALSE); VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_VOID_RETURN; } @@ -7846,6 +8735,13 @@ void close_performance_schema_table(THD *thd, Open_tables_state *backup) pthread_mutex_lock(&LOCK_open); found_old_table= false; + /* + Note that we need to hold LOCK_open while changing the + open_tables list. Another thread may work on it. + (See: remove_table_from_cache(), mysql_wait_completed_table()) + Closing a MERGE child before the parent would be fatal if the + other thread tries to abort the MERGE lock in between. + */ while (thd->open_tables) found_old_table|= close_thread_table(thd, &thd->open_tables); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 11e70a2e5da..dabdbd5a030 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2273,7 +2273,17 @@ pthread_handler_t handle_delayed_insert(void *arg) parsed using a lex, that depends on initialized thd->lex. */ lex_start(thd); - if (!(di->table=open_ltable(thd, &di->table_list, TL_WRITE_DELAYED, 0))) + thd->lex->sql_command= SQLCOM_INSERT; // For innodb::store_lock() + /* + Statement-based replication of INSERT DELAYED has problems with RAND() + and user vars, so in mixed mode we go to row-based. + */ + thd->lex->set_stmt_unsafe(); + thd->set_current_stmt_binlog_row_based_if_mixed(); + + /* Open table */ + if (!(di->table= open_n_lock_single_table(thd, &di->table_list, + TL_WRITE_DELAYED))) { thd->fatal_error(); // Abort waiting inserts goto err; @@ -3309,7 +3319,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, tmp_table.alias= 0; tmp_table.timestamp_field= 0; tmp_table.s= &share; - init_tmp_table_share(&share, "", 0, "", ""); + init_tmp_table_share(thd, &share, "", 0, "", ""); tmp_table.s->db_create_options=0; tmp_table.s->blob_ptr_size= portable_sizeof_char_ptr; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7e194ac76dc..01bb18592a1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -470,6 +470,46 @@ end: } +/** + @brief Check access privs for a MERGE table and fix children lock types. + + @param[in] thd thread handle + @param[in] db database name + @param[in,out] table_list list of child tables (merge_list) + lock_type and optionally db set per table + + @return status + @retval 0 OK + @retval != 0 Error + + @detail + This function is used for write access to MERGE tables only + (CREATE TABLE, ALTER TABLE ... UNION=(...)). Set TL_WRITE for + every child. Set 'db' for every child if not present. +*/ + +static bool check_merge_table_access(THD *thd, char *db, + TABLE_LIST *table_list) +{ + int error= 0; + + if (table_list) + { + /* Check that all tables use the current database */ + TABLE_LIST *tlist; + + for (tlist= table_list; tlist; tlist= tlist->next_local) + { + if (!tlist->db || !tlist->db[0]) + tlist->db= db; /* purecov: inspected */ + } + error= check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL, + table_list,0); + } + return error; +} + + /* This works because items are allocated with sql_alloc() */ void free_items(Item *item) @@ -2254,6 +2294,19 @@ mysql_execute_command(THD *thd) select_lex->options|= SELECT_NO_UNLOCK; unit->set_limit(select_lex); + /* + Disable non-empty MERGE tables with CREATE...SELECT. Too + complicated. See Bug #26379. Empty MERGE tables are read-only + and don't allow CREATE...SELECT anyway. + */ + if (create_info.used_fields & HA_CREATE_USED_UNION) + { + my_error(ER_WRONG_OBJECT, MYF(0), create_table->db, + create_table->table_name, "BASE TABLE"); + res= 1; + goto end_with_restore_list; + } + if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE)) { lex->link_first_table_back(create_table, link_to_local); @@ -5094,26 +5147,6 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table) } -bool check_merge_table_access(THD *thd, char *db, - TABLE_LIST *table_list) -{ - int error=0; - if (table_list) - { - /* Check that all tables use the current database */ - TABLE_LIST *tmp; - for (tmp= table_list; tmp; tmp= tmp->next_local) - { - if (!tmp->db || !tmp->db[0]) - tmp->db=db; - } - error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL, - table_list,0); - } - return error; -} - - /**************************************************************************** Check stack size; Send error if there isn't enough stack to continue ****************************************************************************/ diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ad9eec1906a..94b58bf913f 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4951,7 +4951,7 @@ the generated partition syntax in a correct manner. We use the old partitioning also for the new table. We do this by assigning the partition_info from the table loaded in - open_ltable to the partition_info struct used by mysql_create_table + open_table to the partition_info struct used by mysql_create_table later in this method. Case IIb: diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 862948e48a4..c6c21dccc37 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9608,7 +9608,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, table->keys_in_use_for_query.init(); table->s= share; - init_tmp_table_share(share, "", 0, tmpname, tmpname); + init_tmp_table_share(thd, share, "", 0, tmpname, tmpname); share->blob_field= blob_field; share->blob_ptr_size= mi_portable_sizeof_char_ptr; share->db_low_byte_first=1; // True for HEAP and MyISAM diff --git a/sql/sql_table.cc b/sql/sql_table.cc index bf4a02ae5cc..91acd8d20a3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1556,13 +1556,18 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, /* Don't give warnings for not found errors, as we already generate notes */ thd->no_warnings_for_error= 1; + /* Remove the tables from the HANDLER list, if they are in it. */ + mysql_ha_flush(thd, tables, MYSQL_HA_CLOSE_FINAL, 1); + for (table= tables; table; table= table->next_local) { char *db=table->db; handlerton *table_type; enum legacy_db_type frm_db_type; - mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL, 1); + DBUG_PRINT("table", ("table_l: '%s'.'%s' table: 0x%lx s: 0x%lx", + table->db, table->table_name, (long) table->table, + table->table ? (long) table->table->s : (long) -1)); error= drop_temporary_table(thd, table); @@ -1690,6 +1695,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, wrong_tables.append(','); wrong_tables.append(String(table->table_name,system_charset_info)); } + DBUG_PRINT("table", ("table: 0x%lx s: 0x%lx", (long) table->table, + table->table ? (long) table->table->s : (long) -1)); } /* It's safe to unlock LOCK_open: we have an exclusive lock @@ -3836,6 +3843,8 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table, DBUG_RETURN(send_check_errmsg(thd, table, "restore", "Failed to open partially restored table")); } + /* A MERGE table must not come here. */ + DBUG_ASSERT(!table->table || !table->table->child_l); pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(0); } @@ -3878,6 +3887,10 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, table= &tmp_table; pthread_mutex_unlock(&LOCK_open); } + + /* A MERGE table must not come here. */ + DBUG_ASSERT(!table->child_l); + /* REPAIR TABLE ... USE_FRM for temporary tables makes little sense. */ @@ -4032,6 +4045,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, char* db = table->db; bool fatal_error=0; + DBUG_PRINT("admin", ("table: '%s'.'%s'", table->db, table->table_name)); + DBUG_PRINT("admin", ("extra_open_options: %u", extra_open_options)); strxmov(table_name, db, ".", table->table_name, NullS); thd->open_options|= extra_open_options; table->lock_type= lock_type; @@ -4062,16 +4077,24 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, table->next_local= save_next_local; thd->open_options&= ~extra_open_options; } + DBUG_PRINT("admin", ("table: 0x%lx", (long) table->table)); + if (prepare_func) { + DBUG_PRINT("admin", ("calling prepare_func")); switch ((*prepare_func)(thd, table, check_opt)) { case 1: // error, message written to net ha_autocommit_or_rollback(thd, 1); close_thread_tables(thd); + DBUG_PRINT("admin", ("simple error, admin next table")); continue; case -1: // error, message could be written to net + /* purecov: begin inspected */ + DBUG_PRINT("admin", ("severe error, stop")); goto err; + /* purecov: end */ default: // should be 0 otherwise + DBUG_PRINT("admin", ("prepare_func succeeded")); ; } } @@ -4086,6 +4109,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, */ if (!table->table) { + DBUG_PRINT("admin", ("open table failed")); if (!thd->warn_list.elements) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, ER_CHECK_NO_SUCH_TABLE, ER(ER_CHECK_NO_SUCH_TABLE)); @@ -4100,14 +4124,17 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, if (table->view) { + DBUG_PRINT("admin", ("calling view_operator_func")); result_code= (*view_operator_func)(thd, table); goto send_result; } if ((table->table->db_stat & HA_READ_ONLY) && open_for_modify) { + /* purecov: begin inspected */ char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE]; uint length; + DBUG_PRINT("admin", ("sending error message")); protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); protocol->store(operator_name, system_charset_info); @@ -4122,11 +4149,13 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, if (protocol->write()) goto err; continue; + /* purecov: end */ } /* Close all instances of the table to allow repair to rename files */ if (lock_type == TL_WRITE && table->table->s->version) { + DBUG_PRINT("admin", ("removing table from cache")); pthread_mutex_lock(&LOCK_open); const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_open, "Waiting to get writelock"); @@ -4146,6 +4175,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, if (table->table->s->crashed && operator_func == &handler::ha_check) { + /* purecov: begin inspected */ + DBUG_PRINT("admin", ("sending crashed warning")); protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); protocol->store(operator_name, system_charset_info); @@ -4154,6 +4185,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, system_charset_info); if (protocol->write()) goto err; + /* purecov: end */ } if (operator_func == &handler::ha_repair && @@ -4164,6 +4196,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, HA_ADMIN_NEEDS_ALTER)) { my_bool save_no_send_ok= thd->net.no_send_ok; + DBUG_PRINT("admin", ("recreating table")); ha_autocommit_or_rollback(thd, 1); close_thread_tables(thd); tmp_disable_binlog(thd); // binlogging is done by caller if wanted @@ -4176,7 +4209,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, } + DBUG_PRINT("admin", ("calling operator_func '%s'", operator_name)); result_code = (table->table->file->*operator_func)(thd, check_opt); + DBUG_PRINT("admin", ("operator_func returned: %d", result_code)); send_result: @@ -5834,10 +5869,25 @@ view_err: start_waiting_global_read_lock(thd); DBUG_RETURN(error); } - if (!(table=open_ltable(thd, table_list, TL_WRITE_ALLOW_READ, 0))) + + if (!(table= open_n_lock_single_table(thd, table_list, TL_WRITE_ALLOW_READ))) DBUG_RETURN(TRUE); table->use_all_columns(); + /* + Prohibit changing of the UNION list of a non-temporary MERGE table + under LOCK tables. It would be quite difficult to reuse a shrinked + set of tables from the old table or to open a new TABLE object for + an extended list and verify that they belong to locked tables. + */ + if (thd->locked_tables && + (create_info->used_fields & HA_CREATE_USED_UNION) && + (table->s->tmp_table == NO_TMP_TABLE)) + { + my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); + DBUG_RETURN(TRUE); + } + /* Check that we are not trying to rename to an existing table */ if (new_name) { @@ -6305,6 +6355,7 @@ view_err: goto err; /* Open the table if we need to copy the data. */ + DBUG_PRINT("info", ("need_copy_table: %u", need_copy_table)); if (need_copy_table != ALTER_TABLE_METADATA_ONLY) { if (table->s->tmp_table) @@ -6328,6 +6379,10 @@ view_err: } if (!new_table) goto err1; + /* + Note: In case of MERGE table, we do not attach children. We do not + copy data for MERGE tables. Only the children have data. + */ } /* Copy the data if necessary. */ @@ -6335,6 +6390,10 @@ view_err: thd->cuted_fields=0L; thd->proc_info="copy to tmp table"; copied=deleted=0; + /* + We do not copy data for MERGE tables. Only the children have data. + MERGE tables have HA_NO_COPY_ON_ALTER set. + */ if (new_table && !(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER)) { /* We don't want update TIMESTAMP fields during ALTER TABLE. */ @@ -6472,7 +6531,10 @@ view_err: if (new_table) { - /* Close the intermediate table that will be the new table */ + /* + Close the intermediate table that will be the new table. + Note that MERGE tables do not have their children attached here. + */ intern_close_table(new_table); my_free(new_table,MYF(0)); } @@ -6565,6 +6627,7 @@ view_err: /* Now we have to inform handler that new .FRM file is in place. To do this we need to obtain a handler object for it. + NO need to tamper with MERGE tables. The real open is done later. */ TABLE *t_table; if (new_name != table_name || new_db != db) @@ -6632,7 +6695,7 @@ view_err: /* For the alter table to be properly flushed to the logs, we have to open the new table. If not, we get a problem on server - shutdown. + shutdown. But we do not need to attach MERGE children. */ char path[FN_REFLEN]; TABLE *t_table; @@ -6962,6 +7025,12 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list) Alter_info alter_info; DBUG_ENTER("mysql_recreate_table"); + DBUG_ASSERT(!table_list->next_global); + /* + table_list->table has been closed and freed. Do not reference + uninitialized data. open_tables() could fail. + */ + table_list->table= NULL; bzero((char*) &create_info, sizeof(create_info)); create_info.db_type= 0; @@ -6993,6 +7062,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); + /* Open one table after the other to keep lock time as short as possible. */ for (table= tables; table; table= table->next_local) { char table_name[NAME_LEN*2+2]; @@ -7000,7 +7070,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, strxmov(table_name, table->db ,".", table->table_name, NullS); - t= table->table= open_ltable(thd, table, TL_READ, 0); + t= table->table= open_n_lock_single_table(thd, table, TL_READ); thd->clear_error(); // these errors shouldn't get client protocol->prepare_for_resend(); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index ce26b025430..53f799fff1c 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -436,13 +436,37 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) if (lock_table_names(thd, tables)) goto end; - /* We also don't allow creation of triggers on views. */ - tables->required_type= FRMTYPE_TABLE; - - if (reopen_name_locked_table(thd, tables, TRUE)) + /* + If the table is under LOCK TABLES, lock_table_names() does not set + tables->table. Find the table in open_tables. + */ + if (!tables->table && thd->locked_tables) { - unlock_table_name(thd, tables); + for (table= thd->open_tables; + table && (strcmp(table->s->table_name.str, tables->table_name) || + strcmp(table->s->db.str, tables->db)); + table= table->next) {} + tables->table= table; + } + if (!tables->table) + { + /* purecov: begin inspected */ + my_error(ER_TABLE_NOT_LOCKED, MYF(0), tables->alias); goto end; + /* purecov: end */ + } + + /* No need to reopen the table if it is locked with LOCK TABLES. */ + if (!thd->locked_tables || (tables->table->in_use != thd)) + { + /* We also don't allow creation of triggers on views. */ + tables->required_type= FRMTYPE_TABLE; + + if (reopen_name_locked_table(thd, tables, TRUE)) + { + unlock_table_name(thd, tables); + goto end; + } } table= tables->table; @@ -462,6 +486,16 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) table->triggers->create_trigger(thd, tables, &stmt_query): table->triggers->drop_trigger(thd, tables, &stmt_query)); + /* Under LOCK TABLES we must reopen the table to activate the trigger. */ + if (!result && thd->locked_tables) + { + close_data_files_and_morph_locks(thd, table->s->db.str, + table->s->table_name.str); + thd->in_lock_tables= 1; + result= reopen_tables(thd, 1, 0); + thd->in_lock_tables= 0; + } + end: if (!result) diff --git a/sql/table.cc b/sql/table.cc index c3ddb809b9e..2143faaff5c 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -329,6 +329,7 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key, SYNOPSIS init_tmp_table_share() + thd thread handle share Share to fill key Table_cache_key, as generated from create_table_def_key. must start with db name. @@ -346,7 +347,7 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key, use key_length= 0 as neither table_cache_key or key_length will be used). */ -void init_tmp_table_share(TABLE_SHARE *share, const char *key, +void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key, uint key_length, const char *table_name, const char *path) { @@ -373,9 +374,14 @@ void init_tmp_table_share(TABLE_SHARE *share, const char *key, anyway to be able to catch errors. */ share->table_map_version= ~(ulonglong)0; - share->table_map_id= ~0UL; share->cached_row_logging_check= -1; + /* + table_map_id is also used for MERGE tables to suppress repeated + compatibility checks. + */ + share->table_map_id= (ulong) thd->query_id; + DBUG_VOID_RETURN; } @@ -4477,6 +4483,25 @@ void st_table::mark_columns_needed_for_insert() mark_auto_increment_column(); } + +/** + @brief Check if this is part of a MERGE table with attached children. + + @return status + @retval TRUE children are attached + @retval FALSE no MERGE part or children not attached + + @detail + A MERGE table consists of a parent TABLE and zero or more child + TABLEs. Each of these TABLEs is called a part of a MERGE table. +*/ + +bool st_table::is_children_attached(void) +{ + return((child_l && children_attached) || + (parent && parent->children_attached)); +} + /* Cleanup this table for re-execution. diff --git a/sql/table.h b/sql/table.h index 2bbd71b70c6..7bf0f6bb792 100644 --- a/sql/table.h +++ b/sql/table.h @@ -431,6 +431,12 @@ typedef struct st_table_share { return (table_category == TABLE_CATEGORY_PERFORMANCE); } + + inline ulong get_table_def_version() + { + return table_map_id; + } + } TABLE_SHARE; @@ -455,6 +461,11 @@ struct st_table { #endif struct st_table *next, *prev; + /* For the below MERGE related members see top comment in ha_myisammrg.cc */ + struct st_table *parent; /* Set in MERGE child. Ptr to parent */ + TABLE_LIST *child_l; /* Set in MERGE parent. List of children */ + TABLE_LIST **child_last_l; /* Set in MERGE parent. End of list */ + THD *in_use; /* Which thread uses this */ Field **field; /* Pointer to fields */ @@ -622,6 +633,8 @@ struct st_table { my_bool insert_or_update; /* Can be used by the handler */ my_bool alias_name_used; /* true if table_name is alias */ my_bool get_fields_in_item_tree; /* Signal to fix_field */ + /* If MERGE children attached to parent. See top comment in ha_myisammrg.cc */ + my_bool children_attached; REGINFO reginfo; /* field connections */ MEM_ROOT mem_root; @@ -673,6 +686,7 @@ struct st_table { */ inline bool needs_reopen_or_name_lock() { return s->version != refresh_version; } + bool is_children_attached(void); }; enum enum_schema_table_state @@ -996,6 +1010,8 @@ struct TABLE_LIST (non-zero only for merged underlying tables of a view). */ TABLE_LIST *referencing_view; + /* Ptr to parent MERGE table list item. See top comment in ha_myisammrg.cc */ + TABLE_LIST *parent_l; /* Security context (non-zero only for tables which belong to view with SQL SECURITY DEFINER) @@ -1176,6 +1192,20 @@ struct TABLE_LIST */ bool process_index_hints(TABLE *table); + /* Access MERGE child def version. See top comment in ha_myisammrg.cc */ + inline ulong get_child_def_version() + { + return child_def_version; + } + inline void set_child_def_version(ulong version) + { + child_def_version= version; + } + inline void init_child_def_version() + { + child_def_version= ~0UL; + } + private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); @@ -1183,6 +1213,9 @@ private: Cleanup for re-execution in a prepared statement or a stored procedure. */ + + /* Remembered MERGE child def version. See top comment in ha_myisammrg.cc */ + ulong child_def_version; }; class Item; diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index ca4c40547ee..dcedcf03f65 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -119,6 +119,10 @@ static void mi_check_print_msg(MI_CHECK *param, const char* msg_type, definition for further use in mi_create or for a check for underlying table conformance in merge engine. + The caller needs to free *recinfo_out after use. Since *recinfo_out + and *keydef_out are allocated with a my_multi_malloc, *keydef_out + is freed automatically when *recinfo_out is freed. + RETURN VALUE 0 OK !0 error code diff --git a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h index e8594fc9039..ca44ae9ad87 100644 --- a/storage/myisam/ha_myisam.h +++ b/storage/myisam/ha_myisam.h @@ -140,4 +140,8 @@ class ha_myisam: public handler *engine_callback, ulonglong *engine_data); #endif + MI_INFO *file_ptr(void) + { + return file; + } }; diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index 8a914e8a2de..f91b0dc7a92 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -14,6 +14,82 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* + MyISAM MERGE tables + + A MyISAM MERGE table is kind of a union of zero or more MyISAM tables. + + Besides the normal form file (.frm) a MERGE table has a meta file + (.MRG) with a list of tables. These are paths to the MyISAM table + files. The last two components of the path contain the database name + and the table name respectively. + + When a MERGE table is open, there exists an TABLE object for the MERGE + table itself and a TABLE object for each of the MyISAM tables. For + abbreviated writing, I call the MERGE table object "parent" and the + MyISAM table objects "children". + + A MERGE table is almost always opened through open_and_lock_tables() + and hence through open_tables(). When the parent appears in the list + of tables to open, the initial open of the handler does nothing but + read the meta file and collect a list of TABLE_LIST objects for the + children. This list is attached to the parent TABLE object as + TABLE::child_l. The end of the children list is saved in + TABLE::child_last_l. + + Back in open_tables(), add_merge_table_list() is called. It updates + each list member with the lock type and a back pointer to the parent + TABLE_LIST object TABLE_LIST::parent_l. The list is then inserted in + the list of tables to open, right behind the parent. Consequently, + open_tables() opens the children, one after the other. The TABLE + references of the TABLE_LIST objects are implicitly set to the open + tables. The children are opened as independent MyISAM tables, right as + if they are used by the SQL statement. + + TABLE_LIST::parent_l is required to find the parent 1. when the last + child has been opened and children are to be attached, and 2. when an + error happens during child open and the child list must be removed + from the queuery list. In these cases the current child does not have + TABLE::parent set or does not have a TABLE at all respectively. + + When the last child is open, attach_merge_children() is called. It + removes the list of children from the open list. Then the children are + "attached" to the parent. All required references between parent and + children are set up. + + The MERGE storage engine sets up an array with references to the + low-level MyISAM table objects (MI_INFO). It remembers the state of + the table in MYRG_INFO::children_attached. + + Every child TABLE::parent references the parent TABLE object. That way + TABLE objects belonging to a MERGE table can be identified. + TABLE::parent is required because the parent and child TABLE objects + can live longer than the parent TABLE_LIST object. So the path + child->pos_in_table_list->parent_l->table can be broken. + + If necessary, the compatibility of parent and children is checked. + This check is necessary when any of the objects are reopend. This is + detected by comparing the current table def version against the + remembered child def version. On parent open, the list members are + initialized to an "impossible"/"undefined" version value. So the check + is always executed on the first attach. + + The version check is done in myisammrg_attach_children_callback(), + which is called for every child. ha_myisammrg::attach_children() + initializes 'need_compat_check' to FALSE and + myisammrg_attach_children_callback() sets it ot TRUE if a table + def version mismatches the remembered child def version. + + Finally the parent TABLE::children_attached is set. + + --- + + On parent open the storage engine structures are allocated and initialized. + They stay with the open table until its final close. + + +*/ + #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation #endif @@ -22,14 +98,11 @@ #include "mysql_priv.h" #include #include +#include "../myisam/ha_myisam.h" #include "ha_myisammrg.h" #include "myrg_def.h" -/***************************************************************************** -** MyISAM MERGE tables -*****************************************************************************/ - static handler *myisammrg_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root) @@ -38,10 +111,23 @@ static handler *myisammrg_create_handler(handlerton *hton, } +/** + @brief Constructor +*/ + ha_myisammrg::ha_myisammrg(handlerton *hton, TABLE_SHARE *table_arg) :handler(hton, table_arg), file(0) {} + +/** + @brief Destructor +*/ + +ha_myisammrg::~ha_myisammrg(void) +{} + + static const char *ha_myisammrg_exts[] = { ".MRG", NullS @@ -89,25 +175,311 @@ const char *ha_myisammrg::index_type(uint key_number) } -int ha_myisammrg::open(const char *name, int mode, uint test_if_locked) -{ - MI_KEYDEF *keyinfo; - MI_COLUMNDEF *recinfo; - MYRG_TABLE *u_table; - uint recs; - uint keys= table->s->keys; - int error; - char name_buff[FN_REFLEN]; +/** + @brief Callback function for open of a MERGE parent table. - DBUG_PRINT("info", ("ha_myisammrg::open")); - if (!(file=myrg_open(fn_format(name_buff,name,"","", - MY_UNPACK_FILENAME|MY_APPEND_EXT), - mode, test_if_locked))) + @detail This function adds a TABLE_LIST object for a MERGE child table + to a list of tables of the parent TABLE object. It is called for + each child table. + + The list of child TABLE_LIST objects is kept in the TABLE object of + the parent for the whole life time of the MERGE table. It is + inserted in the statement list behind the MERGE parent TABLE_LIST + object when the MERGE table is opened. It is removed from the + statement list after the last child is opened. + + All memeory used for the child TABLE_LIST objects and the strings + referred by it are taken from the parent TABLE::mem_root. Thus they + are all freed implicitly at the final close of the table. + + TABLE::child_l -> TABLE_LIST::next_global -> TABLE_LIST::next_global + # # ^ # ^ + # # | # | + # # +--------- TABLE_LIST::prev_global + # # | + # |<--- TABLE_LIST::prev_global | + # | + TABLE::child_last_l -----------------------------------------+ + + @param[in] callback_param data pointer as given to myrg_parent_open() + @param[in] filename file name of MyISAM table + without extension. + + @return status + @retval 0 OK + @retval != 0 Error +*/ + +static int myisammrg_parent_open_callback(void *callback_param, + const char *filename) +{ + ha_myisammrg *ha_myrg; + TABLE *parent; + TABLE_LIST *child_l; + const char *db; + const char *table_name; + uint dirlen; + char dir_path[FN_REFLEN]; + DBUG_ENTER("myisammrg_parent_open_callback"); + + /* Extract child table name and database name from filename. */ + dirlen= dirname_length(filename); + if (dirlen >= FN_REFLEN) { - DBUG_PRINT("info", ("ha_myisammrg::open exit %d", my_errno)); - return (my_errno ? my_errno : -1); + /* purecov: begin inspected */ + DBUG_PRINT("error", ("name too long: '%.64s'", filename)); + my_errno= ENAMETOOLONG; + DBUG_RETURN(1); + /* purecov: end */ } - DBUG_PRINT("info", ("ha_myisammrg::open myrg_extrafunc...")); + table_name= filename + dirlen; + dirlen--; /* Strip off trailing '/'. */ + memcpy(dir_path, filename, dirlen); + dir_path[dirlen]= '\0'; + db= base_name(dir_path); + dirlen-= db - dir_path; /* This is now the length of 'db'. */ + DBUG_PRINT("myrg", ("open: '%s'.'%s'", db, table_name)); + + ha_myrg= (ha_myisammrg*) callback_param; + parent= ha_myrg->table_ptr(); + + /* Get a TABLE_LIST object. */ + if (!(child_l= (TABLE_LIST*) alloc_root(&parent->mem_root, + sizeof(TABLE_LIST)))) + { + /* purecov: begin inspected */ + DBUG_PRINT("error", ("my_malloc error: %d", my_errno)); + DBUG_RETURN(1); + /* purecov: end */ + } + bzero((char*) child_l, sizeof(TABLE_LIST)); + + /* Set database (schema) name. */ + child_l->db_length= dirlen; + child_l->db= strmake_root(&parent->mem_root, db, dirlen); + /* Set table name. */ + child_l->table_name_length= strlen(table_name); + child_l->table_name= strmake_root(&parent->mem_root, table_name, + child_l->table_name_length); + /* Convert to lowercase if required. */ + if (lower_case_table_names && child_l->table_name_length) + child_l->table_name_length= my_casedn_str(files_charset_info, + child_l->table_name); + /* Set alias. */ + child_l->alias= child_l->table_name; + + /* Initialize table map to 'undefined'. */ + child_l->init_child_def_version(); + + /* Link TABLE_LIST object into the parent list. */ + if (!parent->child_last_l) + { + /* Initialize parent->child_last_l when handling first child. */ + parent->child_last_l= &parent->child_l; + } + *parent->child_last_l= child_l; + child_l->prev_global= parent->child_last_l; + parent->child_last_l= &child_l->next_global; + + DBUG_RETURN(0); +} + + +/** + @brief Callback function for attaching a MERGE child table. + + @detail This function retrieves the MyISAM table handle from the + next child table. It is called for each child table. + + @param[in] callback_param data pointer as given to + myrg_attach_children() + + @return pointer to open MyISAM table structure + @retval !=NULL OK, returning pointer + @retval NULL, my_errno == 0 Ok, no more child tables + @retval NULL, my_errno != 0 error +*/ + +static MI_INFO *myisammrg_attach_children_callback(void *callback_param) +{ + ha_myisammrg *ha_myrg; + TABLE *parent; + TABLE *child; + TABLE_LIST *child_l; + MI_INFO *myisam; + DBUG_ENTER("myisammrg_attach_children_callback"); + + my_errno= 0; + ha_myrg= (ha_myisammrg*) callback_param; + parent= ha_myrg->table_ptr(); + + /* Get child list item. */ + child_l= ha_myrg->next_child_attach; + if (!child_l) + { + DBUG_PRINT("myrg", ("No more children to attach")); + DBUG_RETURN(NULL); + } + child= child_l->table; + DBUG_PRINT("myrg", ("child table: '%s'.'%s' 0x%lx", child->s->db.str, + child->s->table_name.str, (long) child)); + /* + Prepare for next child. Used as child_l in next call to this function. + We cannot rely on a NULL-terminated chain. + */ + if (&child_l->next_global == parent->child_last_l) + { + DBUG_PRINT("myrg", ("attaching last child")); + ha_myrg->next_child_attach= NULL; + } + else + ha_myrg->next_child_attach= child_l->next_global; + + /* Set parent reference. */ + child->parent= parent; + + /* + Do a quick compatibility check. The table def version is set when + the table share is created. The child def version is copied + from the table def version after a sucessful compatibility check. + We need to repeat the compatibility check only if a child is opened + from a different share than last time it was used with this MERGE + table. + */ + DBUG_PRINT("myrg", ("table_def_version last: %lu current: %lu", + (ulong) child_l->get_child_def_version(), + (ulong) child->s->get_table_def_version())); + if (child_l->get_child_def_version() != child->s->get_table_def_version()) + ha_myrg->need_compat_check= TRUE; + + /* + If parent is temporary, children must be temporary too and vice + versa. This check must be done for every child on every open because + the table def version can overlap between temporary and + non-temporary tables. We need to detect the case where a + non-temporary table has been replaced with a temporary table of the + same version. Or vice versa. A very unlikely case, but it could + happen. + */ + if (child->s->tmp_table != parent->s->tmp_table) + { + DBUG_PRINT("error", ("temporary table mismatch parent: %d child: %d", + parent->s->tmp_table, child->s->tmp_table)); + my_errno= HA_ERR_WRONG_MRG_TABLE_DEF; + goto err; + } + + /* Extract the MyISAM table structure pointer from the handler object. */ + if ((child->file->ht->db_type != DB_TYPE_MYISAM) || + !(myisam= ((ha_myisam*) child->file)->file_ptr())) + { + DBUG_PRINT("error", ("no MyISAM handle for child table: '%s'.'%s' 0x%lx", + child->s->db.str, child->s->table_name.str, + (long) child)); + my_errno= HA_ERR_WRONG_MRG_TABLE_DEF; + } + DBUG_PRINT("myrg", ("MyISAM handle: 0x%lx my_errno: %d", + (long) myisam, my_errno)); + + err: + DBUG_RETURN(my_errno ? NULL : myisam); +} + + +/** + @brief Open a MERGE parent table, not its children. + + @detail This function initializes the MERGE storage engine structures + and adds a child list of TABLE_LIST to the parent TABLE. + + @param[in] name MERGE table path name + @param[in] mode read/write mode, unused + @param[in] test_if_locked open flags + + @return status + @retval 0 OK + @retval -1 Error, my_errno gives reason +*/ + +int ha_myisammrg::open(const char *name, int mode __attribute__((unused)), + uint test_if_locked) +{ + DBUG_ENTER("ha_myisammrg::open"); + DBUG_PRINT("myrg", ("name: '%s' table: 0x%lx", name, (long) table)); + DBUG_PRINT("myrg", ("test_if_locked: %u", test_if_locked)); + + /* Save for later use. */ + this->test_if_locked= test_if_locked; + + /* retrieve children table list. */ + my_errno= 0; + if (!(file= myrg_parent_open(name, myisammrg_parent_open_callback, this))) + { + DBUG_PRINT("error", ("my_errno %d", my_errno)); + DBUG_RETURN(my_errno ? my_errno : -1); + } + DBUG_PRINT("myrg", ("MYRG_INFO: 0x%lx", (long) file)); + DBUG_RETURN(0); +} + + +/** + @brief Attach children to a MERGE table. + + @detail Let the storage engine attach its children through a callback + function. Check table definitions for consistency. + + @note Special thd->open_options may be in effect. We can make use of + them in attach. I.e. we use HA_OPEN_FOR_REPAIR to report the names + of mismatching child tables. We cannot transport these options in + ha_myisammrg::test_if_locked because they may change after the + parent is opened. The parent is kept open in the table cache over + multiple statements and can be used by other threads. Open options + can change over time. + + @return status + @retval 0 OK + @retval != 0 Error, my_errno gives reason +*/ + +int ha_myisammrg::attach_children(void) +{ + MYRG_TABLE *u_table; + MI_COLUMNDEF *recinfo; + MI_KEYDEF *keyinfo; + uint recs; + uint keys= table->s->keys; + int error; + DBUG_ENTER("ha_myisammrg::attach_children"); + DBUG_PRINT("myrg", ("table: '%s'.'%s' 0x%lx", table->s->db.str, + table->s->table_name.str, (long) table)); + DBUG_PRINT("myrg", ("test_if_locked: %u", this->test_if_locked)); + DBUG_ASSERT(!this->file->children_attached); + + /* + Initialize variables that are used, modified, and/or set by + myisammrg_attach_children_callback(). + 'next_child_attach' traverses the chain of TABLE_LIST objects + that has been compiled during myrg_parent_open(). Every call + to myisammrg_attach_children_callback() moves the pointer to + the next object. + 'need_compat_check' is set by myisammrg_attach_children_callback() + if a child fails the table def version check. + 'my_errno' is set by myisammrg_attach_children_callback() in + case of an error. + */ + next_child_attach= table->child_l; + need_compat_check= FALSE; + my_errno= 0; + + if (myrg_attach_children(this->file, this->test_if_locked | + current_thd->open_options, + myisammrg_attach_children_callback, this)) + { + DBUG_PRINT("error", ("my_errno %d", my_errno)); + DBUG_RETURN(my_errno ? my_errno : -1); + } + DBUG_PRINT("myrg", ("calling myrg_extrafunc")); myrg_extrafunc(file, query_cache_invalidate_by_MyISAM_filename_ref); if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED || test_if_locked == HA_OPEN_ABORT_IF_LOCKED)) @@ -116,69 +488,147 @@ int ha_myisammrg::open(const char *name, int mode, uint test_if_locked) if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED)) myrg_extra(file,HA_EXTRA_WAIT_LOCK,0); - if (table->s->reclength != stats.mean_rec_length && stats.mean_rec_length) + /* + The compatibility check is required only if one or more children do + not match their table def version from the last check. This will + always happen at the first attach because the reference child def + version is initialized to 'undefined' at open. + */ + DBUG_PRINT("myrg", ("need_compat_check: %d", need_compat_check)); + if (need_compat_check) { - DBUG_PRINT("error",("reclength: %lu mean_rec_length: %lu", - table->s->reclength, stats.mean_rec_length)); - if (test_if_locked & HA_OPEN_FOR_REPAIR) - myrg_print_wrong_table(file->open_tables->table->filename); - error= HA_ERR_WRONG_MRG_TABLE_DEF; - goto err; - } - if ((error= table2myisam(table, &keyinfo, &recinfo, &recs))) - { - /* purecov: begin inspected */ - DBUG_PRINT("error", ("Failed to convert TABLE object to MyISAM " - "key and column definition")); - goto err; - /* purecov: end */ - } - for (u_table= file->open_tables; u_table < file->end_table; u_table++) - { - if (check_definition(keyinfo, recinfo, keys, recs, - u_table->table->s->keyinfo, u_table->table->s->rec, - u_table->table->s->base.keys, - u_table->table->s->base.fields, false)) + TABLE_LIST *child_l; + + if (table->s->reclength != stats.mean_rec_length && stats.mean_rec_length) { - error= HA_ERR_WRONG_MRG_TABLE_DEF; + DBUG_PRINT("error",("reclength: %lu mean_rec_length: %lu", + table->s->reclength, stats.mean_rec_length)); if (test_if_locked & HA_OPEN_FOR_REPAIR) - myrg_print_wrong_table(u_table->table->filename); - else + myrg_print_wrong_table(file->open_tables->table->filename); + error= HA_ERR_WRONG_MRG_TABLE_DEF; + goto err; + } + /* + Both recinfo and keyinfo are allocated by my_multi_malloc(), thus + only recinfo must be freed. + */ + if ((error= table2myisam(table, &keyinfo, &recinfo, &recs))) + { + /* purecov: begin inspected */ + DBUG_PRINT("error", ("failed to convert TABLE object to MyISAM " + "key and column definition")); + goto err; + /* purecov: end */ + } + for (u_table= file->open_tables; u_table < file->end_table; u_table++) + { + if (check_definition(keyinfo, recinfo, keys, recs, + u_table->table->s->keyinfo, u_table->table->s->rec, + u_table->table->s->base.keys, + u_table->table->s->base.fields, false)) { - my_free((uchar*) recinfo, MYF(0)); - goto err; + DBUG_PRINT("error", ("table definition mismatch: '%s'", + u_table->table->filename)); + error= HA_ERR_WRONG_MRG_TABLE_DEF; + if (!(this->test_if_locked & HA_OPEN_FOR_REPAIR)) + { + my_free((uchar*) recinfo, MYF(0)); + goto err; + } + myrg_print_wrong_table(u_table->table->filename); } } + my_free((uchar*) recinfo, MYF(0)); + if (error == HA_ERR_WRONG_MRG_TABLE_DEF) + goto err; + + /* All checks passed so far. Now update child def version. */ + for (child_l= table->child_l; ; child_l= child_l->next_global) + { + child_l->set_child_def_version( + child_l->table->s->get_table_def_version()); + + if (&child_l->next_global == table->child_last_l) + break; + } } - my_free((uchar*) recinfo, MYF(0)); - if (error == HA_ERR_WRONG_MRG_TABLE_DEF) - goto err; #if !defined(BIG_TABLES) || SIZEOF_OFF_T == 4 /* Merge table has more than 2G rows */ if (table->s->crashed) { + DBUG_PRINT("error", ("MERGE table marked crashed")); error= HA_ERR_WRONG_MRG_TABLE_DEF; goto err; } #endif - return (0); + DBUG_RETURN(0); + err: - myrg_close(file); - file=0; - return (my_errno= error); + myrg_detach_children(file); + DBUG_RETURN(my_errno= error); } + +/** + @brief Detach all children from a MERGE table. + + @note Detach must not touch the children in any way. + They may have been closed at ths point already. + All references to the children should be removed. + + @return status + @retval 0 OK + @retval != 0 Error, my_errno gives reason +*/ + +int ha_myisammrg::detach_children(void) +{ + DBUG_ENTER("ha_myisammrg::detach_children"); + DBUG_ASSERT(this->file && this->file->children_attached); + + if (myrg_detach_children(this->file)) + { + /* purecov: begin inspected */ + DBUG_PRINT("error", ("my_errno %d", my_errno)); + DBUG_RETURN(my_errno ? my_errno : -1); + /* purecov: end */ + } + DBUG_RETURN(0); +} + + +/** + @brief Close a MERGE parent table, not its children. + + @note The children are expected to be closed separately by the caller. + + @return status + @retval 0 OK + @retval != 0 Error, my_errno gives reason +*/ + int ha_myisammrg::close(void) { - return myrg_close(file); + int rc; + DBUG_ENTER("ha_myisammrg::close"); + /* + Children must not be attached here. Unless the MERGE table has no + children. In this case children_attached is always true. + */ + DBUG_ASSERT(!this->file->children_attached || !this->file->tables); + rc= myrg_close(file); + file= 0; + DBUG_RETURN(rc); } int ha_myisammrg::write_row(uchar * buf) { + DBUG_ENTER("ha_myisammrg::write_row"); + DBUG_ASSERT(this->file->children_attached); ha_statistic_increment(&SSV::ha_write_count); if (file->merge_insert_method == MERGE_INSERT_DISABLED || !file->tables) - return (HA_ERR_TABLE_READONLY); + DBUG_RETURN(HA_ERR_TABLE_READONLY); if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) table->timestamp_field->set_time(); @@ -186,13 +636,14 @@ int ha_myisammrg::write_row(uchar * buf) { int error; if ((error= update_auto_increment())) - return error; + DBUG_RETURN(error); /* purecov: inspected */ } - return myrg_write(file,buf); + DBUG_RETURN(myrg_write(file,buf)); } int ha_myisammrg::update_row(const uchar * old_data, uchar * new_data) { + DBUG_ASSERT(this->file->children_attached); ha_statistic_increment(&SSV::ha_update_count); if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) table->timestamp_field->set_time(); @@ -201,6 +652,7 @@ int ha_myisammrg::update_row(const uchar * old_data, uchar * new_data) int ha_myisammrg::delete_row(const uchar * buf) { + DBUG_ASSERT(this->file->children_attached); ha_statistic_increment(&SSV::ha_delete_count); return myrg_delete(file,buf); } @@ -209,6 +661,7 @@ int ha_myisammrg::index_read_map(uchar * buf, const uchar * key, key_part_map keypart_map, enum ha_rkey_function find_flag) { + DBUG_ASSERT(this->file->children_attached); ha_statistic_increment(&SSV::ha_read_key_count); int error=myrg_rkey(file,buf,active_index, key, keypart_map, find_flag); table->status=error ? STATUS_NOT_FOUND: 0; @@ -219,6 +672,7 @@ int ha_myisammrg::index_read_idx_map(uchar * buf, uint index, const uchar * key, key_part_map keypart_map, enum ha_rkey_function find_flag) { + DBUG_ASSERT(this->file->children_attached); ha_statistic_increment(&SSV::ha_read_key_count); int error=myrg_rkey(file,buf,index, key, keypart_map, find_flag); table->status=error ? STATUS_NOT_FOUND: 0; @@ -228,6 +682,7 @@ int ha_myisammrg::index_read_idx_map(uchar * buf, uint index, const uchar * key, int ha_myisammrg::index_read_last_map(uchar *buf, const uchar *key, key_part_map keypart_map) { + DBUG_ASSERT(this->file->children_attached); ha_statistic_increment(&SSV::ha_read_key_count); int error=myrg_rkey(file,buf,active_index, key, keypart_map, HA_READ_PREFIX_LAST); @@ -237,6 +692,7 @@ int ha_myisammrg::index_read_last_map(uchar *buf, const uchar *key, int ha_myisammrg::index_next(uchar * buf) { + DBUG_ASSERT(this->file->children_attached); ha_statistic_increment(&SSV::ha_read_next_count); int error=myrg_rnext(file,buf,active_index); table->status=error ? STATUS_NOT_FOUND: 0; @@ -245,6 +701,7 @@ int ha_myisammrg::index_next(uchar * buf) int ha_myisammrg::index_prev(uchar * buf) { + DBUG_ASSERT(this->file->children_attached); ha_statistic_increment(&SSV::ha_read_prev_count); int error=myrg_rprev(file,buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; @@ -253,6 +710,7 @@ int ha_myisammrg::index_prev(uchar * buf) int ha_myisammrg::index_first(uchar * buf) { + DBUG_ASSERT(this->file->children_attached); ha_statistic_increment(&SSV::ha_read_first_count); int error=myrg_rfirst(file, buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; @@ -261,6 +719,7 @@ int ha_myisammrg::index_first(uchar * buf) int ha_myisammrg::index_last(uchar * buf) { + DBUG_ASSERT(this->file->children_attached); ha_statistic_increment(&SSV::ha_read_last_count); int error=myrg_rlast(file, buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; @@ -271,6 +730,7 @@ int ha_myisammrg::index_next_same(uchar * buf, const uchar *key __attribute__((unused)), uint length __attribute__((unused))) { + DBUG_ASSERT(this->file->children_attached); ha_statistic_increment(&SSV::ha_read_next_count); int error=myrg_rnext_same(file,buf); table->status=error ? STATUS_NOT_FOUND: 0; @@ -280,12 +740,14 @@ int ha_myisammrg::index_next_same(uchar * buf, int ha_myisammrg::rnd_init(bool scan) { + DBUG_ASSERT(this->file->children_attached); return myrg_reset(file); } int ha_myisammrg::rnd_next(uchar *buf) { + DBUG_ASSERT(this->file->children_attached); ha_statistic_increment(&SSV::ha_read_rnd_next_count); int error=myrg_rrnd(file, buf, HA_OFFSET_ERROR); table->status=error ? STATUS_NOT_FOUND: 0; @@ -295,6 +757,7 @@ int ha_myisammrg::rnd_next(uchar *buf) int ha_myisammrg::rnd_pos(uchar * buf, uchar *pos) { + DBUG_ASSERT(this->file->children_attached); ha_statistic_increment(&SSV::ha_read_rnd_count); int error=myrg_rrnd(file, buf, my_get_ptr(pos,ref_length)); table->status=error ? STATUS_NOT_FOUND: 0; @@ -303,6 +766,7 @@ int ha_myisammrg::rnd_pos(uchar * buf, uchar *pos) void ha_myisammrg::position(const uchar *record) { + DBUG_ASSERT(this->file->children_attached); ulonglong row_position= myrg_position(file); my_store_ptr(ref, ref_length, (my_off_t) row_position); } @@ -311,6 +775,7 @@ void ha_myisammrg::position(const uchar *record) ha_rows ha_myisammrg::records_in_range(uint inx, key_range *min_key, key_range *max_key) { + DBUG_ASSERT(this->file->children_attached); return (ha_rows) myrg_records_in_range(file, (int) inx, min_key, max_key); } @@ -318,6 +783,7 @@ ha_rows ha_myisammrg::records_in_range(uint inx, key_range *min_key, int ha_myisammrg::info(uint flag) { MYMERGE_INFO mrg_info; + DBUG_ASSERT(this->file->children_attached); (void) myrg_status(file,&mrg_info,flag); /* The following fails if one has not compiled MySQL with -DBIG_TABLES @@ -387,6 +853,23 @@ int ha_myisammrg::info(uint flag) int ha_myisammrg::extra(enum ha_extra_function operation) { + if (operation == HA_EXTRA_ATTACH_CHILDREN) + { + int rc= attach_children(); + if (!rc) + (void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL + return(rc); + } + else if (operation == HA_EXTRA_DETACH_CHILDREN) + { + /* + Note that detach must not touch the children in any way. + They may have been closed at ths point already. + */ + int rc= detach_children(); + return(rc); + } + /* As this is just a mapping, we don't have to force the underlying tables to be closed */ if (operation == HA_EXTRA_FORCE_REOPEN || @@ -404,6 +887,7 @@ int ha_myisammrg::reset(void) int ha_myisammrg::extra_opt(enum ha_extra_function operation, ulong cache_size) { + DBUG_ASSERT(this->file->children_attached); if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_WRITE_CACHE) return 0; return myrg_extra(file, operation, (void*) &cache_size); @@ -411,11 +895,13 @@ int ha_myisammrg::extra_opt(enum ha_extra_function operation, ulong cache_size) int ha_myisammrg::external_lock(THD *thd, int lock_type) { + DBUG_ASSERT(this->file->children_attached); return myrg_lock_database(file,lock_type); } uint ha_myisammrg::lock_count(void) const { + DBUG_ASSERT(this->file->children_attached); return file->tables; } @@ -425,6 +911,7 @@ THR_LOCK_DATA **ha_myisammrg::store_lock(THD *thd, enum thr_lock_type lock_type) { MYRG_TABLE *open_table; + DBUG_ASSERT(this->file->children_attached); for (open_table=file->open_tables ; open_table != file->end_table ; @@ -519,47 +1006,50 @@ int ha_myisammrg::create(const char *name, register TABLE *form, uint dirlgt= dirname_length(name); DBUG_ENTER("ha_myisammrg::create"); + /* Allocate a table_names array in thread mem_root. */ if (!(table_names= (const char**) thd->alloc((create_info->merge_list.elements+1) * sizeof(char*)))) DBUG_RETURN(HA_ERR_OUT_OF_MEM); + + /* Create child path names. */ for (pos= table_names; tables; tables= tables->next_local) { const char *table_name; - TABLE *tbl= 0; - if (create_info->options & HA_LEX_CREATE_TMP_TABLE) - tbl= find_temporary_table(thd, tables); - if (!tbl) - { - /* - Construct the path to the MyISAM table. Try to meet two conditions: - 1.) Allow to include MyISAM tables from different databases, and - 2.) allow for moving DATADIR around in the file system. - The first means that we need paths in the .MRG file. The second - means that we should not have absolute paths in the .MRG file. - The best, we can do, is to use 'mysql_data_home', which is '.' - in mysqld and may be an absolute path in an embedded server. - This means that it might not be possible to move the DATADIR of - an embedded server without changing the paths in the .MRG file. - */ - uint length= build_table_filename(buff, sizeof(buff), - tables->db, tables->table_name, "", 0); - /* - If a MyISAM table is in the same directory as the MERGE table, - we use the table name without a path. This means that the - DATADIR can easily be moved even for an embedded server as long - as the MyISAM tables are from the same database as the MERGE table. - */ - if ((dirname_length(buff) == dirlgt) && ! memcmp(buff, name, dirlgt)) - table_name= tables->table_name; - else - if (! (table_name= thd->strmake(buff, length))) - DBUG_RETURN(HA_ERR_OUT_OF_MEM); - } + + /* + Construct the path to the MyISAM table. Try to meet two conditions: + 1.) Allow to include MyISAM tables from different databases, and + 2.) allow for moving DATADIR around in the file system. + The first means that we need paths in the .MRG file. The second + means that we should not have absolute paths in the .MRG file. + The best, we can do, is to use 'mysql_data_home', which is '.' + in mysqld and may be an absolute path in an embedded server. + This means that it might not be possible to move the DATADIR of + an embedded server without changing the paths in the .MRG file. + + Do the same even for temporary tables. MERGE children are now + opened through the table cache. They are opened by db.table_name, + not by their path name. + */ + uint length= build_table_filename(buff, sizeof(buff), + tables->db, tables->table_name, "", 0); + /* + If a MyISAM table is in the same directory as the MERGE table, + we use the table name without a path. This means that the + DATADIR can easily be moved even for an embedded server as long + as the MyISAM tables are from the same database as the MERGE table. + */ + if ((dirname_length(buff) == dirlgt) && ! memcmp(buff, name, dirlgt)) + table_name= tables->table_name; else - table_name= tbl->s->path.str; + if (! (table_name= thd->strmake(buff, length))) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */ + *pos++= table_name; } *pos=0; + + /* Create a MERGE meta file from the table_names array. */ DBUG_RETURN(myrg_create(fn_format(buff,name,"","", MY_RESOLVE_SYMLINKS| MY_UNPACK_FILENAME|MY_APPEND_EXT), @@ -642,7 +1132,7 @@ static int myisammrg_init(void *p) myisammrg_hton->db_type= DB_TYPE_MRG_MYISAM; myisammrg_hton->create= myisammrg_create_handler; myisammrg_hton->panic= myisammrg_panic; - myisammrg_hton->flags= HTON_CAN_RECREATE|HTON_NO_PARTITION; + myisammrg_hton->flags= HTON_NO_PARTITION; return 0; } diff --git a/storage/myisammrg/ha_myisammrg.h b/storage/myisammrg/ha_myisammrg.h index 91aabe277f7..977c45d1435 100644 --- a/storage/myisammrg/ha_myisammrg.h +++ b/storage/myisammrg/ha_myisammrg.h @@ -27,8 +27,12 @@ class ha_myisammrg: public handler MYRG_INFO *file; public: + TABLE_LIST *next_child_attach; /* next child to attach */ + uint test_if_locked; /* flags from ::open() */ + bool need_compat_check; /* if need compatibility check */ + ha_myisammrg(handlerton *hton, TABLE_SHARE *table_arg); - ~ha_myisammrg() {} + ~ha_myisammrg(); const char *table_type() const { return "MRG_MyISAM"; } const char **bas_ext() const; const char *index_type(uint key_number); @@ -53,6 +57,8 @@ class ha_myisammrg: public handler { return ulonglong2double(stats.data_file_length) / IO_SIZE + file->tables; } int open(const char *name, int mode, uint test_if_locked); + int attach_children(void); + int detach_children(void); int close(void); int write_row(uchar * buf); int update_row(const uchar * old_data, uchar * new_data); @@ -85,6 +91,7 @@ class ha_myisammrg: public handler void update_create_info(HA_CREATE_INFO *create_info); void append_create_info(String *packet); MYRG_INFO *myrg_info() { return file; } + TABLE *table_ptr() { return table; } bool check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes); int check(THD* thd, HA_CHECK_OPT* check_opt); }; diff --git a/storage/myisammrg/myrg_close.c b/storage/myisammrg/myrg_close.c index baae24634b3..b402a35a253 100644 --- a/storage/myisammrg/myrg_close.c +++ b/storage/myisammrg/myrg_close.c @@ -23,9 +23,37 @@ int myrg_close(MYRG_INFO *info) MYRG_TABLE *file; DBUG_ENTER("myrg_close"); - for (file=info->open_tables ; file != info->end_table ; file++) - if ((new_error=mi_close(file->table))) - error=new_error; + /* + Assume that info->children_attached means that this is called from + direct use of MERGE, not from a MySQL server. In this case the + children must be closed and info->rec_per_key_part is part of the + 'info' multi_alloc. + If info->children_attached is false, this is called from a MySQL + server. Children are closed independently but info->rec_per_key_part + must be freed. + Just in case of a server panic (myrg_panic()) info->children_attached + might be true. We would close the children though they should be + closed independently and info->rec_per_key_part is not freed. + This should be acceptable for a panic. + In case of a MySQL server and no children, children_attached is + always true. In this case no rec_per_key_part has been allocated. + So it is correct to use the branch where an empty list of tables is + (not) closed. + */ + if (info->children_attached) + { + for (file= info->open_tables; file != info->end_table; file++) + { + /* purecov: begin inspected */ + if ((new_error= mi_close(file->table))) + error= new_error; + else + file->table= NULL; + /* purecov: end */ + } + } + else + my_free((uchar*) info->rec_per_key_part, MYF(MY_ALLOW_ZERO_PTR)); delete_queue(&info->by_key); pthread_mutex_lock(&THR_LOCK_open); myrg_open_list=list_delete(myrg_open_list,&info->open_list); diff --git a/storage/myisammrg/myrg_extra.c b/storage/myisammrg/myrg_extra.c index a1e6e3f8d4d..3d14f6a56e6 100644 --- a/storage/myisammrg/myrg_extra.c +++ b/storage/myisammrg/myrg_extra.c @@ -29,6 +29,8 @@ int myrg_extra(MYRG_INFO *info,enum ha_extra_function function, DBUG_ENTER("myrg_extra"); DBUG_PRINT("info",("function: %lu", (ulong) function)); + if (!info->children_attached) + DBUG_RETURN(1); if (function == HA_EXTRA_CACHE) { info->cache_in_use=1; @@ -73,6 +75,8 @@ int myrg_reset(MYRG_INFO *info) MYRG_TABLE *file; DBUG_ENTER("myrg_reset"); + if (!info->children_attached) + DBUG_RETURN(1); info->cache_in_use=0; info->current_table=0; info->last_used_table= info->open_tables; diff --git a/storage/myisammrg/myrg_open.c b/storage/myisammrg/myrg_open.c index 500d3a29327..6fb1888f84d 100644 --- a/storage/myisammrg/myrg_open.c +++ b/storage/myisammrg/myrg_open.c @@ -26,8 +26,14 @@ open a MyISAM MERGE table if handle_locking is 0 then exit with error if some table is locked if handle_locking is 1 then wait if table is locked -*/ + NOTE: This function is not used in the MySQL server. It is for + MERGE use independent from MySQL. Currently there is some code + duplication between myrg_open() and myrg_parent_open() + + myrg_attach_children(). Please duplicate changes in these + functions or make common sub-functions. +*/ +/* purecov: begin unused */ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) { @@ -107,13 +113,11 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) key_parts*sizeof(long), MYF(MY_WME|MY_ZEROFILL)))) goto err; - if (files) - { - m_info->open_tables=(MYRG_TABLE *) (m_info+1); - m_info->rec_per_key_part=(ulong *) (m_info->open_tables+files); - m_info->tables= files; - files= 0; - } + DBUG_ASSERT(files); + m_info->open_tables=(MYRG_TABLE *) (m_info+1); + m_info->rec_per_key_part=(ulong *) (m_info->open_tables+files); + m_info->tables= files; + files= 0; m_info->reclength=isam->s->base.reclength; min_keys= isam->s->base.keys; errpos=3; @@ -163,6 +167,7 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) /* this works ok if the table list is empty */ m_info->end_table=m_info->open_tables+files; m_info->last_used_table=m_info->open_tables; + m_info->children_attached= TRUE; VOID(my_close(fd,MYF(0))); end_io_cache(&file); @@ -189,3 +194,316 @@ err: my_errno=save_errno; DBUG_RETURN (NULL); } +/* purecov: end */ + + +/** + @brief Open parent table of a MyISAM MERGE table. + + @detail Open MERGE meta file to get the table name paths for the child + tables. Count the children. Allocate and initialize MYRG_INFO + structure. Call a callback function for each child table. + + @param[in] parent_name merge table name path as "database/table" + @param[in] callback function to call for each child table + @param[in] callback_param data pointer to give to the callback + + @return MYRG_INFO pointer + @retval != NULL OK + @retval NULL Error + + @note: Currently there is some code duplication between myrg_open() + and myrg_parent_open() + myrg_attach_children(). Please duplicate + changes in these functions or make common sub-functions. +*/ + +MYRG_INFO *myrg_parent_open(const char *parent_name, + int (*callback)(void*, const char*), + void *callback_param) +{ + MYRG_INFO *m_info; + int rc; + int errpos; + int save_errno; + int insert_method; + uint length; + uint dir_length; + uint child_count; + size_t name_buff_length; + File fd; + IO_CACHE file_cache; + char parent_name_buff[FN_REFLEN * 2]; + char child_name_buff[FN_REFLEN]; + DBUG_ENTER("myrg_parent_open"); + + rc= 1; + errpos= 0; + bzero((char*) &file_cache, sizeof(file_cache)); + + /* Open MERGE meta file. */ + if ((fd= my_open(fn_format(parent_name_buff, parent_name, "", MYRG_NAME_EXT, + MY_UNPACK_FILENAME|MY_APPEND_EXT), + O_RDONLY | O_SHARE, MYF(0))) < 0) + goto err; /* purecov: inspected */ + errpos= 1; + + if (init_io_cache(&file_cache, fd, 4 * IO_SIZE, READ_CACHE, 0, 0, + MYF(MY_WME | MY_NABP))) + goto err; /* purecov: inspected */ + errpos= 2; + + /* Count children. Determine insert method. */ + child_count= 0; + insert_method= 0; + while ((length= my_b_gets(&file_cache, child_name_buff, FN_REFLEN - 1))) + { + /* Remove line terminator. */ + if (child_name_buff[length - 1] == '\n') + child_name_buff[--length]= '\0'; + + /* Skip empty lines. */ + if (!child_name_buff[0]) + continue; /* purecov: inspected */ + + /* Skip comments, but evaluate insert method. */ + if (child_name_buff[0] == '#') + { + if (!strncmp(child_name_buff + 1, "INSERT_METHOD=", 14)) + { + /* Compare buffer with global methods list: merge_insert_method. */ + insert_method= find_type(child_name_buff + 15, + &merge_insert_method, 2); + } + continue; + } + + /* Count the child. */ + child_count++; + } + + /* Allocate MERGE parent table structure. */ + if (!(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO) + + child_count * sizeof(MYRG_TABLE), + MYF(MY_WME | MY_ZEROFILL)))) + goto err; /* purecov: inspected */ + errpos= 3; + m_info->open_tables= (MYRG_TABLE*) (m_info + 1); + m_info->tables= child_count; + m_info->merge_insert_method= insert_method > 0 ? insert_method : 0; + /* This works even if the table list is empty. */ + m_info->end_table= m_info->open_tables + child_count; + if (!child_count) + { + /* Do not attach/detach an empty child list. */ + m_info->children_attached= TRUE; + } + + /* Call callback for each child. */ + dir_length= dirname_part(parent_name_buff, parent_name, &name_buff_length); + my_b_seek(&file_cache, 0); + while ((length= my_b_gets(&file_cache, child_name_buff, FN_REFLEN - 1))) + { + /* Remove line terminator. */ + if (child_name_buff[length - 1] == '\n') + child_name_buff[--length]= '\0'; + + /* Skip empty lines and comments. */ + if (!child_name_buff[0] || (child_name_buff[0] == '#')) + continue; + + if (!has_path(child_name_buff)) + { + VOID(strmake(parent_name_buff + dir_length, child_name_buff, + sizeof(parent_name_buff) - 1 - dir_length)); + VOID(cleanup_dirname(child_name_buff, parent_name_buff)); + } + else + fn_format(child_name_buff, child_name_buff, "", "", 0); + DBUG_PRINT("info", ("child: '%s'", child_name_buff)); + + /* Callback registers child with handler table. */ + if ((rc= (*callback)(callback_param, child_name_buff))) + goto err; /* purecov: inspected */ + } + + end_io_cache(&file_cache); + VOID(my_close(fd, MYF(0))); + + m_info->open_list.data= (void*) m_info; + pthread_mutex_lock(&THR_LOCK_open); + myrg_open_list= list_add(myrg_open_list, &m_info->open_list); + pthread_mutex_unlock(&THR_LOCK_open); + + DBUG_RETURN(m_info); + + /* purecov: begin inspected */ + err: + save_errno= my_errno; + switch (errpos) { + case 3: + my_free((char*) m_info, MYF(0)); + /* Fall through */ + case 2: + end_io_cache(&file_cache); + /* Fall through */ + case 1: + VOID(my_close(fd, MYF(0))); + } + my_errno= save_errno; + DBUG_RETURN (NULL); + /* purecov: end */ +} + + +/** + @brief Attach children to a MyISAM MERGE parent table. + + @detail Call a callback function for each child table. + The callback returns the MyISAM table handle of the child table. + Check table definition match. + + @param[in] m_info MERGE parent table structure + @param[in] handle_locking if contains HA_OPEN_FOR_REPAIR, warn about + incompatible child tables, but continue + @param[in] callback function to call for each child table + @param[in] callback_param data pointer to give to the callback + + @return status + @retval 0 OK + @retval != 0 Error + + @note: Currently there is some code duplication between myrg_open() + and myrg_parent_open() + myrg_attach_children(). Please duplicate + changes in these functions or make common sub-functions. +*/ + +int myrg_attach_children(MYRG_INFO *m_info, int handle_locking, + MI_INFO *(*callback)(void*), + void *callback_param) +{ + ulonglong file_offset; + MI_INFO *myisam; + int rc; + int errpos; + int save_errno; + uint idx; + uint child_nr; + uint key_parts; + uint min_keys; + DBUG_ENTER("myrg_attach_children"); + DBUG_PRINT("myrg", ("handle_locking: %d", handle_locking)); + + rc= 1; + errpos= 0; + file_offset= 0; + LINT_INIT(key_parts); + min_keys= 0; + child_nr= 0; + while ((myisam= (*callback)(callback_param))) + { + DBUG_PRINT("myrg", ("child_nr: %u table: '%s'", + child_nr, myisam->filename)); + DBUG_ASSERT(child_nr < m_info->tables); + + /* Special handling when the first child is attached. */ + if (!child_nr) + { + m_info->reclength= myisam->s->base.reclength; + min_keys= myisam->s->base.keys; + key_parts= myisam->s->base.key_parts; + if (!m_info->rec_per_key_part) + { + if(!(m_info->rec_per_key_part= (ulong*) + my_malloc(key_parts * sizeof(long), MYF(MY_WME|MY_ZEROFILL)))) + goto err; /* purecov: inspected */ + errpos= 1; + } + } + + /* Add MyISAM table info. */ + m_info->open_tables[child_nr].table= myisam; + m_info->open_tables[child_nr].file_offset= (my_off_t) file_offset; + file_offset+= myisam->state->data_file_length; + + /* Check table definition match. */ + if (m_info->reclength != myisam->s->base.reclength) + { + DBUG_PRINT("error", ("definition mismatch table: '%s' repair: %d", + myisam->filename, + (handle_locking & HA_OPEN_FOR_REPAIR))); + my_errno= HA_ERR_WRONG_MRG_TABLE_DEF; + if (handle_locking & HA_OPEN_FOR_REPAIR) + { + myrg_print_wrong_table(myisam->filename); + continue; + } + goto err; + } + + m_info->options|= myisam->s->options; + m_info->records+= myisam->state->records; + m_info->del+= myisam->state->del; + m_info->data_file_length+= myisam->state->data_file_length; + if (min_keys > myisam->s->base.keys) + min_keys= myisam->s->base.keys; /* purecov: inspected */ + for (idx= 0; idx < key_parts; idx++) + m_info->rec_per_key_part[idx]+= (myisam->s->state.rec_per_key_part[idx] / + m_info->tables); + child_nr++; + } + + if (my_errno == HA_ERR_WRONG_MRG_TABLE_DEF) + goto err; + if (sizeof(my_off_t) == 4 && file_offset > (ulonglong) (ulong) ~0L) + { + my_errno= HA_ERR_RECORD_FILE_FULL; + goto err; + } + /* Don't mark table readonly, for ALTER TABLE ... UNION=(...) to work */ + m_info->options&= ~(HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA); + m_info->keys= min_keys; + m_info->last_used_table= m_info->open_tables; + m_info->children_attached= TRUE; + DBUG_RETURN(0); + +err: + save_errno= my_errno; + switch (errpos) { + case 1: + my_free((char*) m_info->rec_per_key_part, MYF(0)); + m_info->rec_per_key_part= NULL; + } + my_errno= save_errno; + DBUG_RETURN(1); +} + + +/** + @brief Detach children from a MyISAM MERGE parent table. + + @param[in] m_info MERGE parent table structure + + @note Detach must not touch the children in any way. + They may have been closed at ths point already. + All references to the children should be removed. + + @return status + @retval 0 OK +*/ + +int myrg_detach_children(MYRG_INFO *m_info) +{ + DBUG_ENTER("myrg_detach_children"); + if (m_info->tables) + { + /* Do not attach/detach an empty child list. */ + m_info->children_attached= FALSE; + bzero((char*) m_info->open_tables, m_info->tables * sizeof(MYRG_TABLE)); + } + m_info->records= 0; + m_info->del= 0; + m_info->data_file_length= 0; + m_info->options= 0; + DBUG_RETURN(0); +} + From 211383388e65e4cacb371fac9c56eed86bb396c5 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 16 Nov 2007 15:55:22 +0100 Subject: [PATCH 088/136] Bug#32435: DROP DATABASE statement writes changes to mysql.proc table under RBR When replicating a DROP DATABASE statement with a database holding stored procedures, the changes to the mysql.proc table was recorded in the binary log under row-based replication. With this patch, the thread uses statement-logging format for the duration of the DROP DATABASE statement. The logging format is (already) reset at the end of the statement, so no additional code for resetting the logging format is necessary. sql/sql_db.cc: Clearing the row-based statement flag for the DROP DATABASE statement since it should always be replicated as a statement. mysql-test/extra/binlog_tests/database.test: New BitKeeper file ``mysql-test/extra/binlog_tests/database.test'' mysql-test/suite/binlog/r/binlog_database.result: New BitKeeper file ``mysql-test/suite/binlog/r/binlog_database.result'' mysql-test/suite/binlog/t/binlog_database.test: New BitKeeper file ``mysql-test/suite/binlog/t/binlog_database.test'' --- mysql-test/extra/binlog_tests/database.test | 15 +++++ .../suite/binlog/r/binlog_database.result | 56 +++++++++++++++++++ .../suite/binlog/t/binlog_database.test | 12 ++++ sql/sql_db.cc | 7 +++ 4 files changed, 90 insertions(+) create mode 100644 mysql-test/extra/binlog_tests/database.test create mode 100644 mysql-test/suite/binlog/r/binlog_database.result create mode 100644 mysql-test/suite/binlog/t/binlog_database.test diff --git a/mysql-test/extra/binlog_tests/database.test b/mysql-test/extra/binlog_tests/database.test new file mode 100644 index 00000000000..11a8f53a6d7 --- /dev/null +++ b/mysql-test/extra/binlog_tests/database.test @@ -0,0 +1,15 @@ +source include/have_log_bin.inc; +source include/not_embedded.inc; + +# Checking that the drop of a database does not replicate anything in +# addition to the drop of the database + +reset master; +create database testing_1; +use testing_1; +create table t1 (a int); +create function sf1 (a int) returns int return a+1; +create trigger tr1 before insert on t1 for each row insert into t2 values (2*new.a); +create procedure sp1 (a int) insert into t1 values(a); +drop database testing_1; +source include/show_binlog_events.inc; diff --git a/mysql-test/suite/binlog/r/binlog_database.result b/mysql-test/suite/binlog/r/binlog_database.result new file mode 100644 index 00000000000..7deffb86244 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_database.result @@ -0,0 +1,56 @@ +set binlog_format=statement; +reset master; +create database testing_1; +use testing_1; +create table t1 (a int); +create function sf1 (a int) returns int return a+1; +create trigger tr1 before insert on t1 for each row insert into t2 values (2*new.a); +create procedure sp1 (a int) insert into t1 values(a); +drop database testing_1; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # create database testing_1 +master-bin.000001 # Query # # use `testing_1`; create table t1 (a int) +master-bin.000001 # Query # # use `testing_1`; CREATE DEFINER=`root`@`localhost` function sf1 (a int) returns int return a+1 +master-bin.000001 # Query # # use `testing_1`; CREATE DEFINER=`root`@`localhost` trigger tr1 before insert on t1 for each row insert into t2 values (2*new.a) +master-bin.000001 # Query # # use `testing_1`; CREATE DEFINER=`root`@`localhost` procedure sp1 (a int) insert into t1 values(a) +master-bin.000001 # Query # # drop database testing_1 +set binlog_format=mixed; +reset master; +create database testing_1; +use testing_1; +create table t1 (a int); +create function sf1 (a int) returns int return a+1; +create trigger tr1 before insert on t1 for each row insert into t2 values (2*new.a); +create procedure sp1 (a int) insert into t1 values(a); +drop database testing_1; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # create database testing_1 +master-bin.000001 # Query # # use `testing_1`; create table t1 (a int) +master-bin.000001 # Query # # use `testing_1`; CREATE DEFINER=`root`@`localhost` function sf1 (a int) returns int return a+1 +master-bin.000001 # Query # # use `testing_1`; CREATE DEFINER=`root`@`localhost` trigger tr1 before insert on t1 for each row insert into t2 values (2*new.a) +master-bin.000001 # Query # # use `testing_1`; CREATE DEFINER=`root`@`localhost` procedure sp1 (a int) insert into t1 values(a) +master-bin.000001 # Query # # drop database testing_1 +set binlog_format=row; +reset master; +create database testing_1; +use testing_1; +create table t1 (a int); +create function sf1 (a int) returns int return a+1; +create trigger tr1 before insert on t1 for each row insert into t2 values (2*new.a); +create procedure sp1 (a int) insert into t1 values(a); +drop database testing_1; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # create database testing_1 +master-bin.000001 # Query # # use `testing_1`; create table t1 (a int) +master-bin.000001 # Query # # use `testing_1`; CREATE DEFINER=`root`@`localhost` function sf1 (a int) returns int return a+1 +master-bin.000001 # Query # # use `testing_1`; CREATE DEFINER=`root`@`localhost` trigger tr1 before insert on t1 for each row insert into t2 values (2*new.a) +master-bin.000001 # Query # # use `testing_1`; CREATE DEFINER=`root`@`localhost` procedure sp1 (a int) insert into t1 values(a) +master-bin.000001 # Query # # drop database testing_1 +show databases; +Database +information_schema +mysql +test diff --git a/mysql-test/suite/binlog/t/binlog_database.test b/mysql-test/suite/binlog/t/binlog_database.test new file mode 100644 index 00000000000..ee236b4e5ea --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_database.test @@ -0,0 +1,12 @@ +# A wrapper to test that dropping a database is binlogged +# correctly. We test all three modes in the same file to avoid +# unecessary server restarts. + +set binlog_format=statement; +source extra/binlog_tests/database.test; +set binlog_format=mixed; +source extra/binlog_tests/database.test; +set binlog_format=row; +source extra/binlog_tests/database.test; + +show databases; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index abbf2131957..ad4e0d803eb 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -883,6 +883,13 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); + /* + This statement will be replicated as a statement, even when using + row-based replication. The flag will be reset at the end of the + statement. + */ + thd->clear_current_stmt_binlog_row_based(); + length= build_table_filename(path, sizeof(path), db, "", "", 0); strmov(path+length, MY_DB_OPT_FILE); // Append db option file name del_dbopt(path); // Remove dboption hash entry From 7622b4233c0c52a177a3b9b5306238619f023aa9 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 16 Nov 2007 18:05:30 +0100 Subject: [PATCH 089/136] Bug#32443 - trigger.test produces warnings files Wrong syntax for mysqltest commands was used in test file. Fixed test. mysql-test/r/trigger.result: Bug#32443 - trigger.test produces warnings files Fixed test result mysql-test/t/trigger.test: Bug#32443 - trigger.test produces warnings files Fixed test --- mysql-test/r/trigger.result | 2 -- mysql-test/t/trigger.test | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 47ffc90e3cd..d322d4cda76 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -1979,8 +1979,6 @@ a drop table table_25411_a; drop table table_25411_b; DROP TRIGGER IF EXISTS trg; -Warnings: -Note 1360 Trigger does not exist SHOW CREATE TRIGGER trg; ERROR HY000: Trigger does not exist End of 5.1 tests. diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 1c98a0f8d29..e1037d8bf9c 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -2250,9 +2250,9 @@ drop table table_25411_b; # Bug #31866: MySQL Server crashes on SHOW CREATE TRIGGER statement # ---disable-warnings +--disable_warnings DROP TRIGGER IF EXISTS trg; ---enable-warnings +--enable_warnings --error ER_TRG_DOES_NOT_EXIST SHOW CREATE TRIGGER trg; From 011eb3dffe068db46ea4144eee242a4f2b203cf8 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 17 Nov 2007 11:20:50 +0400 Subject: [PATCH 090/136] Fix for bug #32260: User variables in query cause server crash Problem: there's no guarantee that the user variable item's result_field is assigned when we're adjusting its table read map. Fix: check the result_field before using it. mysql-test/r/user_var.result: Fix for bug #32260: User variables in query cause server crash - test result. mysql-test/t/user_var.test: Fix for bug #32260: User variables in query cause server crash - test case. sql/item_func.cc: Fix for bug #32260: User variables in query cause server crash - using the result_field ensure it is set. --- mysql-test/r/user_var.result | 11 +++++++++++ mysql-test/t/user_var.test | 21 +++++++++++++++++++++ sql/item_func.cc | 3 ++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 6fd7b39f226..431134b03c7 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -353,3 +353,14 @@ select @a:=f4, count(f4) from t1 group by 1 desc; 2.6 1 1.6 4 drop table t1; +create table t1(a int); +insert into t1 values(5),(4),(4),(3),(2),(2),(2),(1); +set @rownum := 0; +set @rank := 0; +set @prev_score := NULL; +select @rownum := @rownum + 1 as row, +@rank := IF(@prev_score!=a, @rownum, @rank) as rank, +@prev_score := a as score +from t1 order by score desc; +drop table t1; +End of 5.1 tests diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index 3a3e8f88f83..a2f12bb495c 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -237,3 +237,24 @@ select @a:=f2, count(f2) from t1 group by 1 desc; select @a:=f3, count(f3) from t1 group by 1 desc; select @a:=f4, count(f4) from t1 group by 1 desc; drop table t1; + +# +# Bug #32260: User variables in query cause server crash +# +create table t1(a int); +insert into t1 values(5),(4),(4),(3),(2),(2),(2),(1); +set @rownum := 0; +set @rank := 0; +set @prev_score := NULL; +# Disable the result log as we assign a value to a user variable in one part +# of a statement and use the same variable in other part of the same statement, +# so we can get unexpected results. +--disable_result_log +select @rownum := @rownum + 1 as row, + @rank := IF(@prev_score!=a, @rownum, @rank) as rank, + @prev_score := a as score +from t1 order by score desc; +--enable_result_log +drop table t1; + +--echo End of 5.1 tests diff --git a/sql/item_func.cc b/sql/item_func.cc index ec0ecc89394..0b98d5c77dc 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3842,7 +3842,8 @@ Item_func_set_user_var::fix_length_and_dec() bool Item_func_set_user_var::register_field_in_read_map(uchar *arg) { TABLE *table= (TABLE *) arg; - if (result_field->table == table || !table) + if (result_field && + (!table || result_field->table == table)) bitmap_set_bit(result_field->table->read_set, result_field->field_index); return 0; } From 5f4bb8429e9a883bf77c2a5d42d81d43fea19e3a Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 18 Nov 2007 20:28:37 +0100 Subject: [PATCH 091/136] Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Post-pushbuild fix for a Valgrind warning. mysql-test/r/merge.result: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Fixed test result. mysql-test/t/merge.test: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Removed unnecessary statements from test. sql/sql_trigger.cc: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Fixed usage of db and table_name for close_data_files_and_morph_locks(). --- mysql-test/r/merge.result | 4 ---- mysql-test/t/merge.test | 2 -- sql/sql_trigger.cc | 7 +++++-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 74441db2512..ba1680f2cac 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -1875,10 +1875,6 @@ CHECK TABLE t1 EXTENDED; Table Op Msg_type Msg_text test.t1 check status OK LOCK TABLES t2 WRITE, t1 WRITE; -SELECT * FROM t2; -c1 -1 -LOCK TABLES t2 WRITE, t1 WRITE; REPAIR TABLE t1; Table Op Msg_type Msg_text test.t1 repair status OK diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index cd4e732b954..3b71dc6fde1 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -1279,8 +1279,6 @@ CHECK TABLE t1 EXTENDED; # # Not using FLUSH TABLES before REPAIR. LOCK TABLES t2 WRITE, t1 WRITE; -SELECT * FROM t2; -LOCK TABLES t2 WRITE, t1 WRITE; REPAIR TABLE t1; CHECK TABLE t1; REPAIR TABLE t1; diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 53f799fff1c..3129bd81572 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -489,8 +489,11 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) /* Under LOCK TABLES we must reopen the table to activate the trigger. */ if (!result && thd->locked_tables) { - close_data_files_and_morph_locks(thd, table->s->db.str, - table->s->table_name.str); + /* + Must not use table->s->db.str or table->s->table_name.str here. + The strings are used in a loop even after the share may be freed. + */ + close_data_files_and_morph_locks(thd, tables->db, tables->table_name); thd->in_lock_tables= 1; result= reopen_tables(thd, 1, 0); thd->in_lock_tables= 0; From f2a631f0dcd87d6d53ae0293bfb70364ca30dc4d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 21 Nov 2007 08:01:00 +0400 Subject: [PATCH 092/136] Fix for bug #32021: Using Date 000-00-01 in WHERE causes wrong result Problem: caching 00000000-00000099 dates as integer values we're improperly shifting them up twice in the get_datetime_value(). Fix: don't shift cached DATETIME values up for the second time. mysql-test/r/type_date.result: Fix for bug #32021: Using Date 000-00-01 in WHERE causes wrong result - test result. mysql-test/t/type_date.test: Fix for bug #32021: Using Date 000-00-01 in WHERE causes wrong result - test case. sql/item.h: Fix for bug #32021: Using Date 000-00-01 in WHERE causes wrong result - Item_cache::field_type() method added. - new Item_cache(enum_field_types) and Item_cache_int(enum_field_types) constructors added. sql/item_cmpfunc.cc: Fix for bug #32021: Using Date 000-00-01 in WHERE causes wrong result - don't shift cached DATETIME values for the second time in the get_datetime_value(): creating new Item_cache_int set DATETIME filed type, check the type before shifting. --- mysql-test/r/type_date.result | 7 +++++++ mysql-test/t/type_date.test | 10 ++++++++++ sql/item.h | 17 ++++++++++++++++- sql/item_cmpfunc.cc | 9 ++++++--- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/type_date.result b/mysql-test/r/type_date.result index 904db1a14d0..392260edb55 100644 --- a/mysql-test/r/type_date.result +++ b/mysql-test/r/type_date.result @@ -224,3 +224,10 @@ ERROR 22007: Incorrect date value: '0000-00-00' for column 'a' at row 1 SET SQL_MODE=DEFAULT; DROP TABLE t1,t2; End of 5.0 tests +create table t1 (a date, primary key (a))engine=memory; +insert into t1 values ('0000-01-01'), ('0000-00-01'), ('0001-01-01'); +select * from t1 where a between '0000-00-01' and '0000-00-02'; +a +0000-00-01 +drop table t1; +End of 5.1 tests diff --git a/mysql-test/t/type_date.test b/mysql-test/t/type_date.test index b21f21d2f3d..14854406eb8 100644 --- a/mysql-test/t/type_date.test +++ b/mysql-test/t/type_date.test @@ -194,3 +194,13 @@ SET SQL_MODE=DEFAULT; DROP TABLE t1,t2; --echo End of 5.0 tests + +# +# Bug#32021: Using Date 000-00-01 in WHERE causes wrong result +# +create table t1 (a date, primary key (a))engine=memory; +insert into t1 values ('0000-01-01'), ('0000-00-01'), ('0001-01-01'); +select * from t1 where a between '0000-00-01' and '0000-00-02'; +drop table t1; + +--echo End of 5.1 tests diff --git a/sql/item.h b/sql/item.h index 6990d9ed021..379eb8a24be 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2620,8 +2620,20 @@ class Item_cache: public Item protected: Item *example; table_map used_table_map; + enum enum_field_types cached_field_type; public: - Item_cache(): example(0), used_table_map(0) {fixed= 1; null_value= 1;} + Item_cache(): + example(0), used_table_map(0), cached_field_type(MYSQL_TYPE_STRING) + { + fixed= 1; + null_value= 1; + } + Item_cache(enum_field_types field_type_arg): + example(0), used_table_map(0), cached_field_type(field_type_arg) + { + fixed= 1; + null_value= 1; + } void set_used_tables(table_map map) { used_table_map= map; } @@ -2637,6 +2649,7 @@ public: }; virtual void store(Item *)= 0; enum Type type() const { return CACHE_ITEM; } + enum_field_types field_type() const { return cached_field_type; } static Item_cache* get_cache(const Item *item); table_map used_tables() const { return used_table_map; } virtual void keep_array() {} @@ -2652,6 +2665,8 @@ protected: longlong value; public: Item_cache_int(): Item_cache(), value(0) {} + Item_cache_int(enum_field_types field_type_arg): + Item_cache(field_type_arg), value(0) {} void store(Item *item); void store(Item *item, longlong val_arg); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 639788d65bc..883e48f3d50 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -933,12 +933,15 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, { value= item->val_int(); *is_null= item->null_value; + enum_field_types f_type= item->field_type(); /* Item_date_add_interval may return MYSQL_TYPE_STRING as the result field type. To detect that the DATE value has been returned we - compare it with 1000000L - any DATE value should be less than it. + compare it with 100000000L - any DATE value should be less than it. + Don't shift cached DATETIME values up for the second time. */ - if (item->field_type() == MYSQL_TYPE_DATE || value < 100000000L) + if (f_type == MYSQL_TYPE_DATE || + (f_type != MYSQL_TYPE_DATETIME && value < 100000000L)) value*= 1000000L; } else @@ -975,7 +978,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, if (item->const_item() && cache_arg && (item->type() != Item::FUNC_ITEM || ((Item_func*)item)->functype() != Item_func::GUSERVAR_FUNC)) { - Item_cache_int *cache= new Item_cache_int(); + Item_cache_int *cache= new Item_cache_int(MYSQL_TYPE_DATETIME); /* Mark the cache as non-const to prevent re-caching. */ cache->set_used_tables(1); cache->store(item, value); From 18851d9ea771499f5e84267d2ed5c16768942f86 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 21 Nov 2007 11:11:22 +0400 Subject: [PATCH 093/136] Fix for bug #30495: optimize table t1,t2,t3 extended errors Problem: we have CHECK TABLE options allowed (by accident?) for ANALYZE/OPTIMIZE TABLE. Fix: disable them. Note: it might require additional fixes in 5.1/6.0 mysql-test/r/analyze.result: Fix for bug #30495: optimize table t1,t2,t3 extended errors - test result. mysql-test/t/analyze.test: Fix for bug #30495: optimize table t1,t2,t3 extended errors - test case. sql/sql_yacc.yy: Fix for bug #30495: optimize table t1,t2,t3 extended errors - opt_mi_check_type (CHECK TABLE options) removed from analyze: and optimize: --- mysql-test/r/analyze.result | 8 ++++++++ mysql-test/t/analyze.test | 14 +++++++++++++- sql/sql_yacc.yy | 4 ++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/analyze.result b/mysql-test/r/analyze.result index 7b476c3cca2..c3dbb846402 100644 --- a/mysql-test/r/analyze.result +++ b/mysql-test/r/analyze.result @@ -56,3 +56,11 @@ show index from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 a 1 a A 5 NULL NULL YES BTREE drop table t1; +End of 4.1 tests +create table t1(a int); +analyze table t1 extended; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'extended' at line 1 +optimize table t1 extended; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'extended' at line 1 +drop table t1; +End of 5.0 tests diff --git a/mysql-test/t/analyze.test b/mysql-test/t/analyze.test index 7c9830bb468..0903db1eca4 100644 --- a/mysql-test/t/analyze.test +++ b/mysql-test/t/analyze.test @@ -72,4 +72,16 @@ analyze table t1; show index from t1; drop table t1; -# End of 4.1 tests +--echo End of 4.1 tests + +# +# Bug #30495: optimize table t1,t2,t3 extended errors +# +create table t1(a int); +--error 1064 +analyze table t1 extended; +--error 1064 +optimize table t1 extended; +drop table t1; + +--echo End of 5.0 tests diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 3401bf739b3..92b8b96378f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3921,7 +3921,7 @@ analyze: lex->no_write_to_binlog= $2; lex->check_opt.init(); } - table_list opt_mi_check_type + table_list {} ; @@ -3966,7 +3966,7 @@ optimize: lex->no_write_to_binlog= $2; lex->check_opt.init(); } - table_list opt_mi_check_type + table_list {} ; From 961cc887bfae0551682ca3f2db7d92147aafd7e4 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 21 Nov 2007 16:00:09 +0400 Subject: [PATCH 094/136] Fix for bug #32557: order by updatexml causes assertion in filesort Problem: even if an Item_xml_str_func successor returns NULL, it doesn't have a corresponding property (maybe_null) set, that leads to a failed assertion. Fix: set nullability property of Item_xml_str_func. mysql-test/r/xml.result: Fix for bug #32557: order by updatexml causes assertion in filesort - test result. mysql-test/t/xml.test: Fix for bug #32557: order by updatexml causes assertion in filesort - test case. sql/item_xmlfunc.h: Fix for bug #32557: order by updatexml causes assertion in filesort - set Item_xml_str_func::maybe_null. --- mysql-test/r/xml.result | 7 +++++++ mysql-test/t/xml.test | 8 ++++++++ sql/item_xmlfunc.h | 12 ++++++++++-- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/xml.result b/mysql-test/r/xml.result index d98173dbe15..56c884343e3 100644 --- a/mysql-test/r/xml.result +++ b/mysql-test/r/xml.result @@ -1022,4 +1022,11 @@ NULL NULL NULL select updatexml(NULL, NULL, NULL); updatexml(NULL, NULL, NULL) NULL +CREATE TABLE t1(a INT NOT NULL); +INSERT INTO t1 VALUES (0), (0); +SELECT 1 FROM t1 ORDER BY(UPDATEXML(a, '1', '1')); +1 +1 +1 +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/xml.test b/mysql-test/t/xml.test index 6c7d9af1b63..5ca9c7afd76 100644 --- a/mysql-test/t/xml.test +++ b/mysql-test/t/xml.test @@ -543,4 +543,12 @@ select updatexml(NULL, NULL, 1), updatexml(1, NULL, NULL), updatexml(NULL, 1, NULL); select updatexml(NULL, NULL, NULL); +# +# Bug #32557: order by updatexml causes assertion in filesort +# +CREATE TABLE t1(a INT NOT NULL); +INSERT INTO t1 VALUES (0), (0); +SELECT 1 FROM t1 ORDER BY(UPDATEXML(a, '1', '1')); +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/sql/item_xmlfunc.h b/sql/item_xmlfunc.h index 278c98baf7c..dadbb5ccf42 100644 --- a/sql/item_xmlfunc.h +++ b/sql/item_xmlfunc.h @@ -28,8 +28,16 @@ protected: String tmp_value, pxml; Item *nodeset_func; public: - Item_xml_str_func(Item *a, Item *b): Item_str_func(a,b) {} - Item_xml_str_func(Item *a, Item *b, Item *c): Item_str_func(a,b,c) {} + Item_xml_str_func(Item *a, Item *b): + Item_str_func(a,b) + { + maybe_null= TRUE; + } + Item_xml_str_func(Item *a, Item *b, Item *c): + Item_str_func(a,b,c) + { + maybe_null= TRUE; + } void fix_length_and_dec(); String *parse_xml(String *raw_xml, String *parsed_xml_buf); }; From 0c2dac2a8bfc41e09b127d7f011dcdd4a22a5b88 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 21 Nov 2007 20:53:44 +0400 Subject: [PATCH 095/136] Fix for bug #32558: group by null-returning expression with rollup causes crash Problem: setting Item_func_rollup_const::null_value property to argument's null_value before (without) the argument evaluation may result in a crash due to wrong null_value. Fix: use is_null() to set Item_func_rollup_const::null_value instead as it evaluates the argument if necessary and returns a proper value. mysql-test/r/olap.result: Fix for bug #32558: group by null-returning expression with rollup causes crash - test result. mysql-test/t/olap.test: Fix for bug #32558: group by null-returning expression with rollup causes crash - test case. sql/item_func.h: Fix for bug #32558: group by null-returning expression with rollup causes crash - use args[0]->is_null() to obtain Item_func_rollup_const::null_value instead of args[0]->null_value as it's not set in advance in case of constant functions. --- mysql-test/r/olap.result | 8 ++++++++ mysql-test/t/olap.test | 9 +++++++++ sql/item_func.h | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index a1d66b11f58..ad04e7304c9 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -726,3 +726,11 @@ count(a) 3 drop table t1; ############################################################## +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES(0); +SELECT 1 FROM t1 GROUP BY (DATE(NULL)) WITH ROLLUP; +1 +1 +1 +DROP TABLE t1; +End of 5.0 tests diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 1ac99d9c39f..d1e40024733 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -367,3 +367,12 @@ select count(a) from t1 group by null with rollup; drop table t1; --echo ############################################################## +# +# Bug #32558: group by null-returning expression with rollup causes crash +# +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES(0); +SELECT 1 FROM t1 GROUP BY (DATE(NULL)) WITH ROLLUP; +DROP TABLE t1; + +--echo End of 5.0 tests diff --git a/sql/item_func.h b/sql/item_func.h index a31294c0395..a5e162f344f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -782,7 +782,7 @@ public: max_length= args[0]->max_length; decimals=args[0]->decimals; /* The item could be a NULL constant. */ - null_value= args[0]->null_value; + null_value= args[0]->is_null(); } }; From 68321feb177131dcd6571c0132808f3841c9635d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 22 Nov 2007 21:39:28 +0100 Subject: [PATCH 096/136] Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Post-pushbuild fix. The merge test failed on Windows. The MoveFile() function returned the error code ERROR_ACCESS_DENIED. The fix is to use a different name for the file to be deleted. This is the same trick as we use for the error code ERROR_ALREADY_EXISTS. Added ERROR_ACCESS_DENIED to the list of error codes that require to change the name of the file to be deleted. mysys/my_delete.c: Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added ERROR_ACCESS_DENIED to the list of error codes that require to change the name of the file to be deleted. --- mysys/my_delete.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mysys/my_delete.c b/mysys/my_delete.c index bac3e2513e1..cff00bf7e08 100644 --- a/mysys/my_delete.c +++ b/mysys/my_delete.c @@ -56,16 +56,20 @@ int nt_share_delete(const char *name, myf MyFlags) ulong cnt; DBUG_ENTER("nt_share_delete"); DBUG_PRINT("my",("name %s MyFlags %d", name, MyFlags)); - + for (cnt= GetTickCount(); cnt; cnt--) { sprintf(buf, "%s.%08X.deleted", name, cnt); if (MoveFile(name, buf)) break; - + if ((errno= GetLastError()) == ERROR_ALREADY_EXISTS) continue; - + + /* This happened during tests with MERGE tables. */ + if (errno == ERROR_ACCESS_DENIED) + continue; + DBUG_PRINT("warning", ("Failed to rename %s to %s, errno: %d", name, buf, errno)); break; From e5a17f5c306db31db3a7e4c94582e8130d3f8a27 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 12:06:55 +0100 Subject: [PATCH 097/136] Bug#32651 - grant_cache.test fails Disabled test case --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 9d6a9b57e9a..dece10e5b5a 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -16,3 +16,4 @@ im_daemon_life_cycle : Bug#20294: Instance manager tests fail randomly im_options_set : Bug#20294: Instance manager tests fail randomly im_options_unset : Bug#20294: Instance manager tests fail randomly im_utils : Bug#20294: Instance manager tests fail randomly +grant_cache : Bug#32651: grant_cache.test fails From a309637579c1187829d17bed6fd0e869a883cb8d Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 12:28:36 +0100 Subject: [PATCH 098/136] BUG#31277 - myisamchk --unpack corrupts a table Fixed a compiler warning on win64 --- myisam/mi_packrec.c | 2 +- mysql-test/r/bdb_notembedded.result | 35 -------------------------- mysql-test/t/bdb_notembedded.test | 38 ----------------------------- 3 files changed, 1 insertion(+), 74 deletions(-) delete mode 100644 mysql-test/r/bdb_notembedded.result delete mode 100644 mysql-test/t/bdb_notembedded.test diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c index 389def395cb..81fc4d046e7 100644 --- a/myisam/mi_packrec.c +++ b/myisam/mi_packrec.c @@ -563,7 +563,7 @@ static void fill_quick_table(uint16 *table, uint bits, uint max_bits, */ value|= (max_bits - bits) << 8 | IS_CHAR; - for (end= table + ((uint) 1 << bits); table < end; table++) + for (end= table + ((my_ptrdiff_t) 1 << bits); table < end; table++) { *table= (uint16) value; } diff --git a/mysql-test/r/bdb_notembedded.result b/mysql-test/r/bdb_notembedded.result deleted file mode 100644 index 14cb5fad915..00000000000 --- a/mysql-test/r/bdb_notembedded.result +++ /dev/null @@ -1,35 +0,0 @@ -set autocommit=1; -reset master; -create table bug16206 (a int); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 -f n Query 1 n use `test`; create table bug16206 (a int) -f n Query 1 n use `test`; insert into bug16206 values(1) -f n Query 1 n use `test`; insert into bug16206 values(2) -drop table bug16206; -reset master; -create table bug16206 (a int) engine= bdb; -insert into bug16206 values(0); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -insert into bug16206 values(3); -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 -f n Query 1 n use `test`; create table bug16206 (a int) engine= bdb -f n Query 1 n use `test`; insert into bug16206 values(0) -f n Query 1 n use `test`; insert into bug16206 values(1) -f n Query 1 n use `test`; BEGIN -f n Query 1 n use `test`; insert into bug16206 values(2) -f n Query 1 n use `test`; COMMIT -f n Query 1 n use `test`; insert into bug16206 values(3) -drop table bug16206; -set autocommit=0; -End of 5.0 tests diff --git a/mysql-test/t/bdb_notembedded.test b/mysql-test/t/bdb_notembedded.test deleted file mode 100644 index 24e64ebbfb2..00000000000 --- a/mysql-test/t/bdb_notembedded.test +++ /dev/null @@ -1,38 +0,0 @@ --- source include/not_embedded.inc --- source include/have_bdb.inc - -# -# Bug #16206: Superfluous COMMIT event in binlog when updating BDB in autocommit mode -# -set autocommit=1; - -let $VERSION=`select version()`; - -reset master; -create table bug16206 (a int); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; ---replace_result $VERSION VERSION ---replace_column 1 f 2 n 5 n -show binlog events; -drop table bug16206; - -reset master; -create table bug16206 (a int) engine= bdb; -insert into bug16206 values(0); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -insert into bug16206 values(3); ---replace_result $VERSION VERSION ---replace_column 1 f 2 n 5 n -show binlog events; -drop table bug16206; - -set autocommit=0; - - ---echo End of 5.0 tests From 850fed3e2a9af7db411af189b10572b78cf8fbb0 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 12:51:14 +0100 Subject: [PATCH 099/136] Post-merge fixes. mysql-test/r/innodb.result: Result change. mysql-test/suite/rpl/r/rpl_binlog_grant.result: Result change. mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result: Result change. mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result: Result change. mysql-test/suite/rpl/t/disabled.def: Enabling some tests. mysql-test/suite/rpl/t/rpl_binlog_grant.test: Adding missing master-slave.inc, causing previous tests to pollute the binary log. mysql-test/suite/rpl_ndb/t/disabled.def: Enabling some tests. --- mysql-test/r/innodb.result | 2 +- .../suite/rpl/r/rpl_binlog_grant.result | 6 ++++ .../rpl/r/rpl_extraColmaster_innodb.result | 30 +++++++++---------- .../rpl/r/rpl_extraColmaster_myisam.result | 30 +++++++++---------- mysql-test/suite/rpl/t/disabled.def | 3 -- mysql-test/suite/rpl/t/rpl_binlog_grant.test | 1 + mysql-test/suite/rpl_ndb/t/disabled.def | 8 ++--- 7 files changed, 41 insertions(+), 39 deletions(-) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index e144589f80c..4379959b60d 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1730,7 +1730,7 @@ Variable_name Value Innodb_rows_deleted 70 show status like "Innodb_rows_inserted"; Variable_name Value -Innodb_rows_inserted 1084 +Innodb_rows_inserted 1082 show status like "Innodb_rows_updated"; Variable_name Value Innodb_rows_updated 885 diff --git a/mysql-test/suite/rpl/r/rpl_binlog_grant.result b/mysql-test/suite/rpl/r/rpl_binlog_grant.result index 43a21913cf6..72dc58effa1 100644 --- a/mysql-test/suite/rpl/r/rpl_binlog_grant.result +++ b/mysql-test/suite/rpl/r/rpl_binlog_grant.result @@ -1,3 +1,9 @@ +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 d1; create database d1; use d1; diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result index a7d9e12aabd..af460ded1e7 100644 --- a/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result @@ -440,7 +440,7 @@ f1 f2 f3 f4 select * from t4 order by f1; f1 f2 f3 f4 1 1 1 first -select * from t31 order by f1; +select * from t31 order by f3; f1 f2 f3 f4 1 1 1 first 1 1 2 second @@ -563,7 +563,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 Skip_Counter 0 Exec_Master_Log_Pos # @@ -581,7 +581,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -638,7 +638,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 Skip_Counter 0 Exec_Master_Log_Pos # @@ -656,7 +656,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -1580,7 +1580,7 @@ f1 f2 f3 f4 select * from t4 order by f1; f1 f2 f3 f4 1 1 1 first -select * from t31 order by f1; +select * from t31 order by f3; f1 f2 f3 f4 1 1 1 first 1 1 2 second @@ -1703,7 +1703,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 Skip_Counter 0 Exec_Master_Log_Pos # @@ -1721,7 +1721,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -1778,7 +1778,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 Skip_Counter 0 Exec_Master_Log_Pos # @@ -1796,7 +1796,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -2720,7 +2720,7 @@ f1 f2 f3 f4 select * from t4 order by f1; f1 f2 f3 f4 1 1 1 first -select * from t31 order by f1; +select * from t31 order by f3; f1 f2 f3 f4 1 1 1 first 1 1 2 second @@ -2843,7 +2843,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 Skip_Counter 0 Exec_Master_Log_Pos # @@ -2861,7 +2861,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -2918,7 +2918,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 Skip_Counter 0 Exec_Master_Log_Pos # @@ -2936,7 +2936,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result index a8762d447d6..f0613c16825 100644 --- a/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result +++ b/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result @@ -440,7 +440,7 @@ f1 f2 f3 f4 select * from t4 order by f1; f1 f2 f3 f4 1 1 1 first -select * from t31 order by f1; +select * from t31 order by f3; f1 f2 f3 f4 1 1 1 first 1 1 2 second @@ -563,7 +563,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 Skip_Counter 0 Exec_Master_Log_Pos # @@ -581,7 +581,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -638,7 +638,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 Skip_Counter 0 Exec_Master_Log_Pos # @@ -656,7 +656,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -1580,7 +1580,7 @@ f1 f2 f3 f4 select * from t4 order by f1; f1 f2 f3 f4 1 1 1 first -select * from t31 order by f1; +select * from t31 order by f3; f1 f2 f3 f4 1 1 1 first 1 1 2 second @@ -1703,7 +1703,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 Skip_Counter 0 Exec_Master_Log_Pos # @@ -1721,7 +1721,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -1778,7 +1778,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 Skip_Counter 0 Exec_Master_Log_Pos # @@ -1796,7 +1796,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -2720,7 +2720,7 @@ f1 f2 f3 f4 select * from t4 order by f1; f1 f2 f3 f4 1 1 1 first -select * from t31 order by f1; +select * from t31 order by f3; f1 f2 f3 f4 1 1 1 first 1 1 2 second @@ -2843,7 +2843,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 Skip_Counter 0 Exec_Master_Log_Pos # @@ -2861,7 +2861,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -2918,7 +2918,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 Skip_Counter 0 Exec_Master_Log_Pos # @@ -2936,7 +2936,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index e9aeb31efe9..42c9c390153 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -11,7 +11,4 @@ ############################################################################## rpl_ddl : BUG#26418 2007-03-01 mleich Slave out of sync after CREATE/DROP TEMPORARY TABLE + ROLLBACK on master -rpl_auto_increment_11932 : Bug#29809 2007-07-16 ingo Slave SQL errors in warnings file rpl_stm_extraColmaster_ndb : WL#3915 : Statement-based replication not supported in ndb. Enable test when supported. -rpl_extraColmaster_innodb : BUG#30854 : Tables name show as binary in slave err msg on vm-win2003-64-b and Solaris -rpl_extraColmaster_myisam : BUG#30854 diff --git a/mysql-test/suite/rpl/t/rpl_binlog_grant.test b/mysql-test/suite/rpl/t/rpl_binlog_grant.test index 42af33c2e05..e95f69a3f99 100644 --- a/mysql-test/suite/rpl/t/rpl_binlog_grant.test +++ b/mysql-test/suite/rpl/t/rpl_binlog_grant.test @@ -1,3 +1,4 @@ +source include/master-slave.inc; -- source include/have_innodb.inc -- source include/not_embedded.inc -- source include/have_binlog_format_mixed_or_statement.inc diff --git a/mysql-test/suite/rpl_ndb/t/disabled.def b/mysql-test/suite/rpl_ndb/t/disabled.def index 3832fe49cb9..ed5dac5b720 100644 --- a/mysql-test/suite/rpl_ndb/t/disabled.def +++ b/mysql-test/suite/rpl_ndb/t/disabled.def @@ -11,12 +11,10 @@ ############################################################################## -rpl_ndb_2innodb : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb failed on Solaris for pack_length issue -rpl_ndb_2myisam : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb failed on Solaris for pack_length issue -rpl_ndb_2other : BUG#21842 2007-08-30 tsmith test has never worked on bigendian (sol10-sparc-a, powermacg5 -rpl_ndb_dd_partitions : BUG#19259 2006-04-21 rpl_ndb_dd_partitions fails on s/AMD +rpl_ndb_2innodb : Bug #32648 Test failure between NDB Cluster and other engines +rpl_ndb_2myisam : Bug #32648 Test failure between NDB Cluster and other engines +rpl_ndb_2other : Bug #32648 Test failure between NDB Cluster and other engines rpl_ndb_ddl : BUG#28798 2007-05-31 lars Valgrind failure in NDB -rpl_ndb_mix_innodb : BUG#28123 rpl_ndb_mix_innodb.test casue slave to core on sol10-sparc-a rpl_ndb_ctype_ucs2_def : BUG#27404 util thd mysql_parse sig11 when mysqld default multibyte charset rpl_ndb_extraColMaster : BUG#30854 : Tables name show as binary in slave err msg on vm-win2003-64-b and Solaris From 4d9f4895c654aa7337da0646dd57799f71b0052d Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 12:52:29 +0100 Subject: [PATCH 100/136] BUG#31277 - myisamchk --unpack corrupts a table Fixed a compiler warning on win64. Backport from 5.1. --- myisam/mi_packrec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c index 389def395cb..523cdadbbd3 100644 --- a/myisam/mi_packrec.c +++ b/myisam/mi_packrec.c @@ -563,7 +563,7 @@ static void fill_quick_table(uint16 *table, uint bits, uint max_bits, */ value|= (max_bits - bits) << 8 | IS_CHAR; - for (end= table + ((uint) 1 << bits); table < end; table++) + for (end= table + (uint) (((uint) 1 << bits)); table < end; table++) { *table= (uint16) value; } From a5761be26a46cb9c76c42817e5e39eca50fbe407 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 12:54:05 +0100 Subject: [PATCH 101/136] Bug#32653 - rpl_log.test fails randomly Disabled test case --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index dece10e5b5a..c45f4b35ac1 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -17,3 +17,4 @@ im_options_set : Bug#20294: Instance manager tests fail randomly im_options_unset : Bug#20294: Instance manager tests fail randomly im_utils : Bug#20294: Instance manager tests fail randomly grant_cache : Bug#32651: grant_cache.test fails +rpl_log : Bug#32653: rpl_log.test fails randomly From 7ae4cfaf37bf9c437518b4ebfee105eec9622cab Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 13:03:38 +0100 Subject: [PATCH 102/136] Bug#32654: rpl_view.test fails randomly Disabled test case --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index c45f4b35ac1..f77f73f419e 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -18,3 +18,4 @@ im_options_unset : Bug#20294: Instance manager tests fail randomly im_utils : Bug#20294: Instance manager tests fail randomly grant_cache : Bug#32651: grant_cache.test fails rpl_log : Bug#32653: rpl_log.test fails randomly +rpl_view : Bug#32654: rpl_view.test fails randomly From 1f57bfb8d1ed7f4cbe4a3410752903106cc8d34c Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 16:30:06 +0400 Subject: [PATCH 103/136] Fix for bug #32560: crash with interval function and count(*) Problem: INTERVAL function implementation doesn't handle NULL range values. Fix: skip NULL ranges looking for a proper one. mysql-test/r/func_set.result: Fix for bug #32560: crash with interval function and count(*) - test result. mysql-test/t/func_set.test: Fix for bug #32560: crash with interval function and count(*) - test case. sql/item_cmpfunc.cc: Fix for bug #32560: crash with interval function and count(*) - skip NULL ranges calculating INTERVAL(...). --- mysql-test/r/func_set.result | 30 +++++++++++++++++++++++++++++ mysql-test/t/func_set.test | 19 +++++++++++++++++- sql/item_cmpfunc.cc | 37 ++++++++++++++++++++++++------------ 3 files changed, 73 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/func_set.result b/mysql-test/r/func_set.result index aa71cee0752..ef5526ca13e 100644 --- a/mysql-test/r/func_set.result +++ b/mysql-test/r/func_set.result @@ -73,3 +73,33 @@ find_in_set(binary 'a', 'A,B,C') select find_in_set('1','3,1,'); find_in_set('1','3,1,') 2 +End of 4.1 tests +SELECT INTERVAL(0.0, NULL); +INTERVAL(0.0, NULL) +1 +SELECT INTERVAL(0.0, CAST(NULL AS DECIMAL)); +INTERVAL(0.0, CAST(NULL AS DECIMAL)) +1 +SELECT INTERVAL(0.0, CAST(DATE(NULL) AS DECIMAL)); +INTERVAL(0.0, CAST(DATE(NULL) AS DECIMAL)) +1 +SELECT INTERVAL(0.0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); +INTERVAL(0.0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) +8 +SELECT INTERVAL(0.0, CAST(NULL AS DECIMAL), CAST(NULL AS DECIMAL), +CAST(NULL AS DECIMAL), CAST(NULL AS DECIMAL), CAST(NULL AS DECIMAL), +CAST(NULL AS DECIMAL), CAST(NULL AS DECIMAL), CAST(NULL AS DECIMAL)); +INTERVAL(0.0, CAST(NULL AS DECIMAL), CAST(NULL AS DECIMAL), +CAST(NULL AS DECIMAL), CAST(NULL AS DECIMAL), CAST(NULL AS DECIMAL), +CAST(NULL AS DECIMAL), CAST(NULL AS DECIMAL), CAST(NULL AS DECIMAL)) +8 +SELECT INTERVAL(0.0, CAST(DATE(NULL) AS DECIMAL), CAST(DATE(NULL) AS DECIMAL), +CAST(DATE(NULL) AS DECIMAL), CAST(DATE(NULL) AS DECIMAL), +CAST(DATE(NULL) AS DECIMAL), CAST(DATE(NULL) AS DECIMAL), +CAST(DATE(NULL) AS DECIMAL), CAST(DATE(NULL) AS DECIMAL)); +INTERVAL(0.0, CAST(DATE(NULL) AS DECIMAL), CAST(DATE(NULL) AS DECIMAL), +CAST(DATE(NULL) AS DECIMAL), CAST(DATE(NULL) AS DECIMAL), +CAST(DATE(NULL) AS DECIMAL), CAST(DATE(NULL) AS DECIMAL), +CAST(DATE(NULL) AS DECIMAL), CAST(DATE(NULL) AS DECIMAL)) +8 +End of 5.0 tests diff --git a/mysql-test/t/func_set.test b/mysql-test/t/func_set.test index 710b9b90a05..e4fde6e0e0e 100644 --- a/mysql-test/t/func_set.test +++ b/mysql-test/t/func_set.test @@ -54,4 +54,21 @@ select find_in_set(binary 'a', 'A,B,C'); # select find_in_set('1','3,1,'); -# End of 4.1 tests +--echo End of 4.1 tests + +# +# Bug #32560: crash with interval function and count(*) +# +SELECT INTERVAL(0.0, NULL); +SELECT INTERVAL(0.0, CAST(NULL AS DECIMAL)); +SELECT INTERVAL(0.0, CAST(DATE(NULL) AS DECIMAL)); +SELECT INTERVAL(0.0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); +SELECT INTERVAL(0.0, CAST(NULL AS DECIMAL), CAST(NULL AS DECIMAL), + CAST(NULL AS DECIMAL), CAST(NULL AS DECIMAL), CAST(NULL AS DECIMAL), + CAST(NULL AS DECIMAL), CAST(NULL AS DECIMAL), CAST(NULL AS DECIMAL)); +SELECT INTERVAL(0.0, CAST(DATE(NULL) AS DECIMAL), CAST(DATE(NULL) AS DECIMAL), + CAST(DATE(NULL) AS DECIMAL), CAST(DATE(NULL) AS DECIMAL), + CAST(DATE(NULL) AS DECIMAL), CAST(DATE(NULL) AS DECIMAL), + CAST(DATE(NULL) AS DECIMAL), CAST(DATE(NULL) AS DECIMAL)); + +--echo End of 5.0 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 85ec8fa40d6..b608da958cc 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1638,24 +1638,27 @@ bool Item_func_opt_neg::eq(const Item *item, bool binary_cmp) const void Item_func_interval::fix_length_and_dec() { + uint rows= row->cols(); + use_decimal_comparison= (row->element_index(0)->result_type() == DECIMAL_RESULT) || (row->element_index(0)->result_type() == INT_RESULT); - if (row->cols() > 8) + if (rows > 8) { - bool consts=1; + bool not_null_consts= TRUE; - for (uint i=1 ; consts && i < row->cols() ; i++) + for (uint i= 1; not_null_consts && i < rows; i++) { - consts&= row->element_index(i)->const_item(); + Item *el= row->element_index(i); + not_null_consts&= el->const_item() & !el->is_null(); } - if (consts && + if (not_null_consts && (intervals= - (interval_range*) sql_alloc(sizeof(interval_range)*(row->cols()-1)))) + (interval_range*) sql_alloc(sizeof(interval_range) * (rows - 1)))) { if (use_decimal_comparison) { - for (uint i=1 ; i < row->cols(); i++) + for (uint i= 1; i < rows; i++) { Item *el= row->element_index(i); interval_range *range= intervals + (i-1); @@ -1680,7 +1683,7 @@ void Item_func_interval::fix_length_and_dec() } else { - for (uint i=1 ; i < row->cols(); i++) + for (uint i= 1; i < rows; i++) { intervals[i-1].dbl= row->element_index(i)->val_real(); } @@ -1771,12 +1774,22 @@ longlong Item_func_interval::val_int() ((el->result_type() == DECIMAL_RESULT) || (el->result_type() == INT_RESULT))) { - my_decimal e_dec_buf, *e_dec= row->element_index(i)->val_decimal(&e_dec_buf); + my_decimal e_dec_buf, *e_dec= el->val_decimal(&e_dec_buf); + /* Skip NULL ranges. */ + if (el->null_value) + continue; if (my_decimal_cmp(e_dec, dec) > 0) - return i-1; + return i - 1; + } + else + { + double val= el->val_real(); + /* Skip NULL ranges. */ + if (el->null_value) + continue; + if (val > value) + return i - 1; } - else if (row->element_index(i)->val_real() > value) - return i-1; } return i-1; } From d21f4bb2799545a17718a344c88ce38543492f54 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 15:30:04 +0100 Subject: [PATCH 104/136] Bug#32659 - ndb_dd_backuprestore.test fails randomly Disabled test case --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index a39de913659..33ea46bd31e 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -15,3 +15,4 @@ concurrent_innodb : BUG#21579 2006-08-11 mleich innodb_concurrent random ctype_big5 : BUG#26711 2007-06-21 Lars Test has never worked on Double Whopper federated_transactions : Bug#29523 Transactions do not work +ndb_dd_backuprestore : Bug#32659 ndb_dd_backuprestore.test fails randomly \ No newline at end of file From 24b9c28d931e60b16f6f0fc3a64ef2bce886364a Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 16:02:51 +0100 Subject: [PATCH 105/136] Bug#32661 - Compiler warning in client/mysql.cc Compiler warned about possible use of uninitialized variable 'warnings' in com_go(). Added LINT_INIT for 'warnings'. client/mysql.cc: Bug#32661 - Compiler warning in client/mysql.cc Added LINT_INIT for 'warnings'. --- client/mysql.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/client/mysql.cc b/client/mysql.cc index 2d4b2bcc373..5191b25a682 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2158,6 +2158,7 @@ com_go(String *buffer,char *line __attribute__((unused))) ulong timer, warnings; uint error= 0; int err= 0; + LINT_INIT(warnings); interrupted_query= 0; if (!status.batch) From 6ef4d0d581214fb4c773974478d8e2a60c7459f1 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 16:32:51 +0100 Subject: [PATCH 106/136] Bug#32663 binlog_multi_engine.test fails randomly Disabled test case --- mysql-test/t/disabled.def | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 33ea46bd31e..703e02b5d40 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -15,4 +15,5 @@ concurrent_innodb : BUG#21579 2006-08-11 mleich innodb_concurrent random ctype_big5 : BUG#26711 2007-06-21 Lars Test has never worked on Double Whopper federated_transactions : Bug#29523 Transactions do not work -ndb_dd_backuprestore : Bug#32659 ndb_dd_backuprestore.test fails randomly \ No newline at end of file +ndb_dd_backuprestore : Bug#32659 ndb_dd_backuprestore.test fails randomly +binlog_multi_engine : Bug#32663 binlog_multi_engine.test fails randomly From f3e51c7484e28357f50a4bf4088ef90dc0d2eea4 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 16:53:31 +0100 Subject: [PATCH 107/136] Bug#32664 - events.test fails randomly Disabled test case --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 703e02b5d40..c2810627d42 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -17,3 +17,4 @@ ctype_big5 : BUG#26711 2007-06-21 Lars Test has never worked on Do federated_transactions : Bug#29523 Transactions do not work ndb_dd_backuprestore : Bug#32659 ndb_dd_backuprestore.test fails randomly binlog_multi_engine : Bug#32663 binlog_multi_engine.test fails randomly +events : Bug#32664 events.test fails randomly From f38b123447f21646eec6d902467f93547abaae0a Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 17:05:16 +0100 Subject: [PATCH 108/136] Bug#29830 Test case 'events_scheduling' fails on Mac OS X and Windows Disabled the test case --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index c2810627d42..51339ba716d 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -18,3 +18,4 @@ federated_transactions : Bug#29523 Transactions do not work ndb_dd_backuprestore : Bug#32659 ndb_dd_backuprestore.test fails randomly binlog_multi_engine : Bug#32663 binlog_multi_engine.test fails randomly events : Bug#32664 events.test fails randomly +events_scheduling : Bug#29830 Test case 'events_scheduling' fails on Mac OS X and Windows From 2eec53cabfb4e843d5edb065c93e235636176ad0 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 17:47:22 +0100 Subject: [PATCH 109/136] Bug#32667 lowercase_table3.test reports to error log Disabled test case --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 51339ba716d..6a4e6464699 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -19,3 +19,4 @@ ndb_dd_backuprestore : Bug#32659 ndb_dd_backuprestore.test fails randomly binlog_multi_engine : Bug#32663 binlog_multi_engine.test fails randomly events : Bug#32664 events.test fails randomly events_scheduling : Bug#29830 Test case 'events_scheduling' fails on Mac OS X and Windows +lowercase_table3 : Bug#32667 lowercase_table3.test reports to error log From 4fb517b4e37d4e0bc1a30eefd3d68544d36253f2 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 17:54:19 +0100 Subject: [PATCH 110/136] Bug#32668 - rpl_row_charset_innodb.test fails Disabled test case --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 6a4e6464699..bae49ca4d29 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -20,3 +20,4 @@ binlog_multi_engine : Bug#32663 binlog_multi_engine.test fails randomly events : Bug#32664 events.test fails randomly events_scheduling : Bug#29830 Test case 'events_scheduling' fails on Mac OS X and Windows lowercase_table3 : Bug#32667 lowercase_table3.test reports to error log +rpl_row_charset_innodb : Bug#32668 rpl_row_charset_innodb.test fails From 1121538d75700698dd174bb1b5ed539822f05a0e Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 18:05:45 +0100 Subject: [PATCH 111/136] Bug#32668 - rpl_row_charset_innodb.test fails The test case fails on "vanilla" and "no_innodb" builds. These builds do not include InnoDB. The test case requires InnoDB. Added requirement for InnoDB into the test case, so that it does not start on those builds. mysql-test/suite/rpl/t/rpl_row_charset_innodb.test: Bug#32668 - rpl_row_charset_innodb.test fails Added requirement for InnoDB. --- mysql-test/suite/rpl/t/rpl_row_charset_innodb.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/rpl/t/rpl_row_charset_innodb.test b/mysql-test/suite/rpl/t/rpl_row_charset_innodb.test index 1465500d0eb..2d48af65581 100644 --- a/mysql-test/suite/rpl/t/rpl_row_charset_innodb.test +++ b/mysql-test/suite/rpl/t/rpl_row_charset_innodb.test @@ -4,6 +4,7 @@ ######################################################## -- source include/not_ndb_default.inc -- source include/have_binlog_format_row.inc +-- source include/have_innodb.inc -- source include/master-slave.inc let $engine_type=innodb; -- source extra/rpl_tests/rpl_row_charset.test From 72e2d553c8dd9be3d41ea6e69deac043831407b5 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 18:27:05 +0100 Subject: [PATCH 112/136] Bug#32668 rpl_row_charset_innodb.test fails Re-enabled test case after fix --- mysql-test/t/disabled.def | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index bae49ca4d29..6a4e6464699 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -20,4 +20,3 @@ binlog_multi_engine : Bug#32663 binlog_multi_engine.test fails randomly events : Bug#32664 events.test fails randomly events_scheduling : Bug#29830 Test case 'events_scheduling' fails on Mac OS X and Windows lowercase_table3 : Bug#32667 lowercase_table3.test reports to error log -rpl_row_charset_innodb : Bug#32668 rpl_row_charset_innodb.test fails From 4b20fc0f6deebe88735094e77120e07b88c4a2c3 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 23:21:37 +0100 Subject: [PATCH 113/136] Bug#32661 - Compiler warning in client/mysql.cc The initialization to zero via LINT_INIT made mysql.test fail. print_warnings() was suppressed where it should not. Fixed initialization so that it fakes warnings. client/mysql.cc: Bug#32661 - Compiler warning in client/mysql.cc Fixed initialization so that it fakes warnings. --- client/mysql.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 5191b25a682..df17e3c5ae1 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2155,10 +2155,10 @@ com_go(String *buffer,char *line __attribute__((unused))) { char buff[200], time_buff[32], *pos; MYSQL_RES *result; - ulong timer, warnings; + ulong timer; + ulong warnings= 1; /* Pre-initialize. See Bug #32661. */ uint error= 0; int err= 0; - LINT_INIT(warnings); interrupted_query= 0; if (!status.batch) From 0e758d9d7e5cb68cceba30157fb05e065316083d Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 14:48:49 +0100 Subject: [PATCH 114/136] BUG#31277 - myisamchk --unpack corrupts a table Another try to fix a compiler warning on win64. --- myisam/mi_packrec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c index 523cdadbbd3..81fc4d046e7 100644 --- a/myisam/mi_packrec.c +++ b/myisam/mi_packrec.c @@ -563,7 +563,7 @@ static void fill_quick_table(uint16 *table, uint bits, uint max_bits, */ value|= (max_bits - bits) << 8 | IS_CHAR; - for (end= table + (uint) (((uint) 1 << bits)); table < end; table++) + for (end= table + ((my_ptrdiff_t) 1 << bits); table < end; table++) { *table= (uint16) value; } From af34d3577ece90dc4c47c0ff36b08bef9b6401e0 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 14:49:41 +0100 Subject: [PATCH 115/136] Bug#32357 - ndb_backup_print test fails sometimes in pushbuild Disabled test case --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index f77f73f419e..018e8ad520b 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -19,3 +19,4 @@ im_utils : Bug#20294: Instance manager tests fail randomly grant_cache : Bug#32651: grant_cache.test fails rpl_log : Bug#32653: rpl_log.test fails randomly rpl_view : Bug#32654: rpl_view.test fails randomly +ndb_backup_print : Bug#32357: ndb_backup_print test fails sometimes in pushbuild From 72cafd4787294a61c41ba1d8e94403393f02e241 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 15:36:23 +0100 Subject: [PATCH 116/136] Disabling failing test that has been reported as bug. mysql-test/suite/rpl_ndb/t/disabled.def: Disabling failing test. --- mysql-test/suite/rpl_ndb/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/rpl_ndb/t/disabled.def b/mysql-test/suite/rpl_ndb/t/disabled.def index ed5dac5b720..60bfa559953 100644 --- a/mysql-test/suite/rpl_ndb/t/disabled.def +++ b/mysql-test/suite/rpl_ndb/t/disabled.def @@ -17,6 +17,7 @@ rpl_ndb_2other : Bug #32648 Test failure between NDB Cluster and oth rpl_ndb_ddl : BUG#28798 2007-05-31 lars Valgrind failure in NDB rpl_ndb_ctype_ucs2_def : BUG#27404 util thd mysql_parse sig11 when mysqld default multibyte charset rpl_ndb_extraColMaster : BUG#30854 : Tables name show as binary in slave err msg on vm-win2003-64-b and Solaris +rpl_ndb_mix_innodb : Bug #32720 Test rpl_ndb_mix_innodb fails on SPARC and PowerPC # the below testcase have been reworked to avoid the bug, test contains comment, keep bug open From a5abc7b95c9da1ead7c3a9e74fd3bfadd027d9ea Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 15:40:08 +0100 Subject: [PATCH 117/136] Bug#29149: Test "kill" fails on Windows Disabled test case. --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 49308c464ec..5492da589ef 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -23,3 +23,4 @@ lowercase_table3 : Bug#32667 lowercase_table3.test reports to error log rpl_log : Bug#32653: rpl_log.test fails randomly rpl_view : Bug#32654: rpl_view.test fails randomly ndb_backup_print : Bug#32357: ndb_backup_print test fails sometimes in pushbuild +kill : Bug#29149: Test "kill" fails on Windows From 7fbe64676ee98b45b40ecb21fbfc59ce009cad7c Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 16:04:29 +0100 Subject: [PATCH 118/136] Bug#32723: grant3.test fails Disabled test case. --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 5492da589ef..374da09797c 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -24,3 +24,4 @@ rpl_log : Bug#32653: rpl_log.test fails randomly rpl_view : Bug#32654: rpl_view.test fails randomly ndb_backup_print : Bug#32357: ndb_backup_print test fails sometimes in pushbuild kill : Bug#29149: Test "kill" fails on Windows +grant3 : Bug#32723: grant3.test fails From dd7fe26c6a06fe5b4052afc3e68ce3a0b6eaf4ea Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 16:12:14 +0100 Subject: [PATCH 119/136] Bug#32724: innodb_mysql.test fails randomly Disabled test case. --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 374da09797c..4b3c25bf157 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -25,3 +25,4 @@ rpl_view : Bug#32654: rpl_view.test fails randomly ndb_backup_print : Bug#32357: ndb_backup_print test fails sometimes in pushbuild kill : Bug#29149: Test "kill" fails on Windows grant3 : Bug#32723: grant3.test fails +innodb_mysql : Bug#32724: innodb_mysql.test fails randomly From 4e419773b66b804324825f75c648bb9009afa6d1 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 16:17:26 +0100 Subject: [PATCH 120/136] Bug#30751: rpl_ndb_multi missing row in output Disabled the test case. --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 4b3c25bf157..3ea65879e46 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -26,3 +26,4 @@ ndb_backup_print : Bug#32357: ndb_backup_print test fails sometimes in pushb kill : Bug#29149: Test "kill" fails on Windows grant3 : Bug#32723: grant3.test fails innodb_mysql : Bug#32724: innodb_mysql.test fails randomly +rpl_ndb_multi : Bug#30751: rpl_ndb_multi missing row in output From 75ea7c7e668bbd4709cfbf694c6541bb5ceda0c4 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 16:19:34 +0100 Subject: [PATCH 121/136] Disable combinations processing until next version --- mysql-test/lib/mtr_cases.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 992d645f038..4ef247af3a0 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -365,7 +365,7 @@ sub collect_one_suite($$) # ---------------------------------------------------------------------- # Proccess combinations only if new tests were added # ---------------------------------------------------------------------- - if ($combinations && $begin_index <= $#{@$cases}) + if (0 and $combinations && $begin_index <= $#{@$cases}) { my $end_index = $#{@$cases}; my $is_copy; From aa2030d6477a98cb0f15b6c78e31327adce812fc Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 16:20:37 +0100 Subject: [PATCH 122/136] Disabling testcases that have warnings that PB cannot handle. --- mysql-test/suite/rpl/t/disabled.def | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index 42c9c390153..6169b6a7d23 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -12,3 +12,5 @@ rpl_ddl : BUG#26418 2007-03-01 mleich Slave out of sync after CREATE/DROP TEMPORARY TABLE + ROLLBACK on master rpl_stm_extraColmaster_ndb : WL#3915 : Statement-based replication not supported in ndb. Enable test when supported. +rpl_extraColmaster_innodb : 2007-11-26 mats Disabled because it shows warnings that cannot be supressed +rpl_extraColmaster_myisam : 2007-11-26 mats Disabled because it shows warnings that cannot be supressed From a440fd39efc45c200c7cfce3d2272ec40ed862da Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 16:31:35 +0100 Subject: [PATCH 123/136] Add suppressions for expected warning messages that appears in slave's error log when running rpl_extraColmaster_*.test --- mysql-test/lib/mtr_report.pl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index 7ac292a516c..8b004a0c6c8 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -346,7 +346,15 @@ sub mtr_report_stats ($) { # BUG#29839 - lowercase_table3.test: Cannot find table test/T1 # from the internal data dictiona - /Cannot find table test\/BUG29839 from the internal data dictionary/ + /Cannot find table test\/BUG29839 from the internal data dictionary/ or + + # rpl_extrColmaster_*.test, the slave thread produces warnings + # when it get updates to a table that has more columns on the + # master + /Slave: Unknown column 'c7' in 't15' Error_code: 1054/ or + /Slave: Can't DROP 'c7'.* 1091/ or + /Slave: Key column 'c6'.* 1072/ + ) { next; # Skip these lines From bc60aa322814e1505ffe9da3d3a6d4675379828b Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 16:45:58 +0100 Subject: [PATCH 124/136] Fix warning about possibly uninitialized variable "warnings" --- client/mysql.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysql.cc b/client/mysql.cc index 1e6207aab51..9fdb532155a 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2166,7 +2166,7 @@ com_go(String *buffer,char *line __attribute__((unused))) { char buff[200], time_buff[32], *pos; MYSQL_RES *result; - ulong timer, warnings; + ulong timer, warnings= 0; uint error= 0; int err= 0; From 23f2d8739b2613c0bef9e2c775fa5d74e3517f51 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 17:31:53 +0100 Subject: [PATCH 125/136] Moved disabling of tests to the respective suites. --- mysql-test/suite/binlog/t/disabled.def | 1 + mysql-test/suite/ndb/t/disabled.def | 2 ++ mysql-test/suite/rpl/t/disabled.def | 2 ++ mysql-test/t/disabled.def | 6 ------ 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/binlog/t/disabled.def b/mysql-test/suite/binlog/t/disabled.def index 888298bbb09..a6e73fa31d8 100644 --- a/mysql-test/suite/binlog/t/disabled.def +++ b/mysql-test/suite/binlog/t/disabled.def @@ -9,3 +9,4 @@ # Do not use any TAB characters for whitespace. # ############################################################################## +binlog_multi_engine : Bug#32663 binlog_multi_engine.test fails randomly diff --git a/mysql-test/suite/ndb/t/disabled.def b/mysql-test/suite/ndb/t/disabled.def index f876039a042..2f07bb052ca 100644 --- a/mysql-test/suite/ndb/t/disabled.def +++ b/mysql-test/suite/ndb/t/disabled.def @@ -16,3 +16,5 @@ ndb_partition_error2 : HF is not sure if the test can work as internded on all # the below testcase have been reworked to avoid the bug, test contains comment, keep bug open #ndb_binlog_ddl_multi : BUG#18976 2006-04-10 kent CRBR: multiple binlog, second binlog may miss schema log events #ndb_binlog_discover : bug#21806 2006-08-24 +ndb_backup_print : Bug#32357: ndb_backup_print test fails sometimes in pushbuild +ndb_dd_backuprestore : Bug#32659 ndb_dd_backuprestore.test fails randomly diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index 426bf93ae97..51cd869b188 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -15,3 +15,5 @@ rpl_invoked_features : BUG#29020 2007-06-21 Lars Non-deterministic test case rpl_auto_increment_11932 : Bug#29809 2007-07-16 ingo Slave SQL errors in warnings file rpl_extraColmaster_innodb : BUG#30854 : Tables name show as binary in slave err msg on vm-win2003-64-b and Solaris rpl_extraColmaster_myisam : BUG#30854 +rpl_view : Bug#32654: rpl_view.test fails randomly +rpl_ndb_multi : Bug#30751: rpl_ndb_multi missing row in output diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 3ea65879e46..0d6f9c039eb 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -15,15 +15,9 @@ concurrent_innodb : BUG#21579 2006-08-11 mleich innodb_concurrent random ctype_big5 : BUG#26711 2007-06-21 Lars Test has never worked on Double Whopper federated_transactions : Bug#29523 Transactions do not work -ndb_dd_backuprestore : Bug#32659 ndb_dd_backuprestore.test fails randomly -binlog_multi_engine : Bug#32663 binlog_multi_engine.test fails randomly events : Bug#32664 events.test fails randomly events_scheduling : Bug#29830 Test case 'events_scheduling' fails on Mac OS X and Windows lowercase_table3 : Bug#32667 lowercase_table3.test reports to error log -rpl_log : Bug#32653: rpl_log.test fails randomly -rpl_view : Bug#32654: rpl_view.test fails randomly -ndb_backup_print : Bug#32357: ndb_backup_print test fails sometimes in pushbuild kill : Bug#29149: Test "kill" fails on Windows grant3 : Bug#32723: grant3.test fails innodb_mysql : Bug#32724: innodb_mysql.test fails randomly -rpl_ndb_multi : Bug#30751: rpl_ndb_multi missing row in output From 6cbb7d2f7674c8bc559e18abf36668d9b5b6b3b5 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 19:16:23 +0100 Subject: [PATCH 126/136] Bug#20830 - INSERT DELAYED does not honour SET INSERT_ID Bug#20627 - INSERT DELAYED does not honour auto_increment_* variables Fixed wrong variable assignment. --- mysql-test/r/delayed.result | 16 ++++++++-------- mysql-test/t/delayed.test | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/mysql-test/r/delayed.result b/mysql-test/r/delayed.result index b37679847be..ff333d88fef 100644 --- a/mysql-test/r/delayed.result +++ b/mysql-test/r/delayed.result @@ -73,13 +73,13 @@ a 13 DROP TABLE t1; SET @bug20627_old_auto_increment_offset= -@@auto_increment_offset= 2; +@@auto_increment_offset; SET @bug20627_old_auto_increment_increment= -@@auto_increment_increment= 3; +@@auto_increment_increment; SET @bug20627_old_session_auto_increment_offset= -@@session.auto_increment_offset= 4; +@@session.auto_increment_offset; SET @bug20627_old_session_auto_increment_increment= -@@session.auto_increment_increment= 5; +@@session.auto_increment_increment; SET @@auto_increment_offset= 2; SET @@auto_increment_increment= 3; SET @@session.auto_increment_offset= 4; @@ -116,13 +116,13 @@ SET @@session.auto_increment_offset= SET @@session.auto_increment_increment= @bug20627_old_session_auto_increment_increment; SET @bug20830_old_auto_increment_offset= -@@auto_increment_offset= 2; +@@auto_increment_offset; SET @bug20830_old_auto_increment_increment= -@@auto_increment_increment= 3; +@@auto_increment_increment; SET @bug20830_old_session_auto_increment_offset= -@@session.auto_increment_offset= 4; +@@session.auto_increment_offset; SET @bug20830_old_session_auto_increment_increment= -@@session.auto_increment_increment= 5; +@@session.auto_increment_increment; SET @@auto_increment_offset= 2; SET @@auto_increment_increment= 3; SET @@session.auto_increment_offset= 4; diff --git a/mysql-test/t/delayed.test b/mysql-test/t/delayed.test index 13615c8c269..b09472d3485 100644 --- a/mysql-test/t/delayed.test +++ b/mysql-test/t/delayed.test @@ -103,13 +103,13 @@ DROP TABLE t1; # Bug#20627 - INSERT DELAYED does not honour auto_increment_* variables # SET @bug20627_old_auto_increment_offset= - @@auto_increment_offset= 2; + @@auto_increment_offset; SET @bug20627_old_auto_increment_increment= - @@auto_increment_increment= 3; + @@auto_increment_increment; SET @bug20627_old_session_auto_increment_offset= - @@session.auto_increment_offset= 4; + @@session.auto_increment_offset; SET @bug20627_old_session_auto_increment_increment= - @@session.auto_increment_increment= 5; + @@session.auto_increment_increment; SET @@auto_increment_offset= 2; SET @@auto_increment_increment= 3; SET @@session.auto_increment_offset= 4; @@ -151,13 +151,13 @@ SET @@session.auto_increment_increment= # Bug#20830 - INSERT DELAYED does not honour SET INSERT_ID # SET @bug20830_old_auto_increment_offset= - @@auto_increment_offset= 2; + @@auto_increment_offset; SET @bug20830_old_auto_increment_increment= - @@auto_increment_increment= 3; + @@auto_increment_increment; SET @bug20830_old_session_auto_increment_offset= - @@session.auto_increment_offset= 4; + @@session.auto_increment_offset; SET @bug20830_old_session_auto_increment_increment= - @@session.auto_increment_increment= 5; + @@session.auto_increment_increment; SET @@auto_increment_offset= 2; SET @@auto_increment_increment= 3; SET @@session.auto_increment_offset= 4; From 835dcc09710f12302e8cbdeaece18a03cc8081f4 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 19:42:07 +0100 Subject: [PATCH 127/136] Revert --- client/mysql.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysql.cc b/client/mysql.cc index 9fdb532155a..1e6207aab51 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2166,7 +2166,7 @@ com_go(String *buffer,char *line __attribute__((unused))) { char buff[200], time_buff[32], *pos; MYSQL_RES *result; - ulong timer, warnings= 0; + ulong timer, warnings; uint error= 0; int err= 0; From 53cf19216fb06d794fbdab56f2fb34b3e327b66b Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 19:50:43 +0100 Subject: [PATCH 128/136] Bug#25146 Some warnings/errors not shown when using --show-warnings - Additional patch to fix compiler warnings client/mysql.cc: Initialize warnings to 0 to avid compiler warning Call 'print_warnings' also when error occured mysql-test/r/mysql.result: Change test to make is possible to see that second set of warnings are from second invocation of mysql mysql-test/t/mysql.test: Change test to make is possible to see that second set of warnings are from second invocation of mysql --- client/mysql.cc | 5 +++-- mysql-test/r/mysql.result | 2 +- mysql-test/t/mysql.test | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 1e6207aab51..b102c80655a 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2166,7 +2166,7 @@ com_go(String *buffer,char *line __attribute__((unused))) { char buff[200], time_buff[32], *pos; MYSQL_RES *result; - ulong timer, warnings; + ulong timer, warnings= 0; uint error= 0; int err= 0; @@ -2316,7 +2316,8 @@ com_go(String *buffer,char *line __attribute__((unused))) end: - if (show_warnings == 1 && warnings >= 1) /* Show warnings if any */ + /* Show warnings if any or error occured */ + if (show_warnings == 1 && (warnings >= 1 || error)) print_warnings(); if (!error && !status.batch && diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index a70cad308d9..a4d96c1c243 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -184,7 +184,7 @@ End of 5.0 tests WARNING: --server-arg option not supported in this configuration. Warning (Code 1286): Unknown table engine 'nonexistent' Warning (Code 1266): Using storage engine MyISAM for table 't2' -Warning (Code 1286): Unknown table engine 'nonexistent' +Warning (Code 1286): Unknown table engine 'nonexistent2' Warning (Code 1266): Using storage engine MyISAM for table 't2' Error (Code 1050): Table 't2' already exists drop tables t1, t2; diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index 05710f44f46..528337da77b 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -312,7 +312,7 @@ remove_file $MYSQLTEST_VARDIR/tmp/bug29323.sql; # This should fail, with warnings as well --error 1 ---exec $MYSQL --show-warnings test -e "create table t2 (id int) engine=nonexistent" +--exec $MYSQL --show-warnings test -e "create table t2 (id int) engine=nonexistent2" drop tables t1, t2; From ec3976ed3ee3b6db83a9284dfc5830c71d1a19a9 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Nov 2007 20:05:52 +0100 Subject: [PATCH 129/136] Remove disabling of testcases --- mysql-test/suite/rpl/t/disabled.def | 2 -- 1 file changed, 2 deletions(-) diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index 6169b6a7d23..42c9c390153 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -12,5 +12,3 @@ rpl_ddl : BUG#26418 2007-03-01 mleich Slave out of sync after CREATE/DROP TEMPORARY TABLE + ROLLBACK on master rpl_stm_extraColmaster_ndb : WL#3915 : Statement-based replication not supported in ndb. Enable test when supported. -rpl_extraColmaster_innodb : 2007-11-26 mats Disabled because it shows warnings that cannot be supressed -rpl_extraColmaster_myisam : 2007-11-26 mats Disabled because it shows warnings that cannot be supressed From 8784957e14fee127c0b8ca094031f2b74e55e359 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 Nov 2007 09:25:45 +0100 Subject: [PATCH 130/136] Bug#32754 - InnoDB tests do not prepare or clean up correctly Some test cases were missing preparation to deal with failed predecessor test cases. Added preparation (drop table if exists) to some test cases. mysql-test/include/innodb_rollback_on_timeout.inc: Bug#32754 - InnoDB tests do not prepare or clean up correctly Added preparation (drop table if exists). mysql-test/r/innodb-semi-consistent.result: Bug#32754 - InnoDB tests do not prepare or clean up correctly Fixed test result. mysql-test/r/innodb-ucs2.result: Bug#32754 - InnoDB tests do not prepare or clean up correctly Fixed test result. mysql-test/r/innodb_mysql.result: Bug#32754 - InnoDB tests do not prepare or clean up correctly Fixed test result. mysql-test/r/innodb_timeout_rollback.result: Bug#32754 - InnoDB tests do not prepare or clean up correctly Fixed test result. mysql-test/t/innodb-semi-consistent.test: Bug#32754 - InnoDB tests do not prepare or clean up correctly Added preparation (drop table if exists). mysql-test/t/innodb-ucs2.test: Bug#32754 - InnoDB tests do not prepare or clean up correctly Added preparation (drop table if exists). --- mysql-test/include/innodb_rollback_on_timeout.inc | 4 ++++ mysql-test/r/innodb-semi-consistent.result | 1 + mysql-test/r/innodb-ucs2.result | 1 + mysql-test/r/innodb_mysql.result | 3 +++ mysql-test/r/innodb_timeout_rollback.result | 1 + mysql-test/t/innodb-semi-consistent.test | 4 ++++ mysql-test/t/innodb-ucs2.test | 4 ++++ 7 files changed, 18 insertions(+) diff --git a/mysql-test/include/innodb_rollback_on_timeout.inc b/mysql-test/include/innodb_rollback_on_timeout.inc index 73c7374c79e..6be47397e4b 100644 --- a/mysql-test/include/innodb_rollback_on_timeout.inc +++ b/mysql-test/include/innodb_rollback_on_timeout.inc @@ -2,6 +2,10 @@ # Bug #24200: Provide backwards compatibility mode for 4.x "rollback on # transaction timeout" # +--disable_warnings +drop table if exists t1; +--enable_warnings + show variables like 'innodb_rollback_on_timeout'; create table t1 (a int unsigned not null primary key) engine = innodb; insert into t1 values (1); diff --git a/mysql-test/r/innodb-semi-consistent.result b/mysql-test/r/innodb-semi-consistent.result index ad7b70d0497..f1139390f20 100644 --- a/mysql-test/r/innodb-semi-consistent.result +++ b/mysql-test/r/innodb-semi-consistent.result @@ -1,3 +1,4 @@ +drop table if exists t1; set session transaction isolation level read committed; create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; insert into t1 values (1),(2),(3),(4),(5),(6),(7); diff --git a/mysql-test/r/innodb-ucs2.result b/mysql-test/r/innodb-ucs2.result index a1c73c912b2..b6bff7d5f42 100644 --- a/mysql-test/r/innodb-ucs2.result +++ b/mysql-test/r/innodb-ucs2.result @@ -1,3 +1,4 @@ +drop table if exists t1, t2; create table t1 ( a int, b char(10), c char(10), filler char(10), primary key(a, b(2)), unique key (a, c(2)) ) character set utf8 engine = innodb; diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 3f9e9b404f0..75bca880305 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -389,6 +389,7 @@ id select_type table type possible_keys key key_len ref rows Extra SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5'; name dept DROP TABLE t1; +drop table if exists t1; show variables like 'innodb_rollback_on_timeout'; Variable_name Value innodb_rollback_on_timeout OFF @@ -451,6 +452,7 @@ tes 1234 drop table test; set global query_cache_type=@save_qcache_type; set global query_cache_size=@save_qcache_size; +drop table if exists t1; show variables like 'innodb_rollback_on_timeout'; Variable_name Value innodb_rollback_on_timeout OFF @@ -775,6 +777,7 @@ EXPLAIN SELECT SQL_BIG_RESULT b, SUM(c) FROM t1 GROUP BY b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 128 Using filesort DROP TABLE t1; +drop table if exists t1; show variables like 'innodb_rollback_on_timeout'; Variable_name Value innodb_rollback_on_timeout OFF diff --git a/mysql-test/r/innodb_timeout_rollback.result b/mysql-test/r/innodb_timeout_rollback.result index b25a2bbd815..e2da6ba8af7 100644 --- a/mysql-test/r/innodb_timeout_rollback.result +++ b/mysql-test/r/innodb_timeout_rollback.result @@ -1,3 +1,4 @@ +drop table if exists t1; show variables like 'innodb_rollback_on_timeout'; Variable_name Value innodb_rollback_on_timeout ON diff --git a/mysql-test/t/innodb-semi-consistent.test b/mysql-test/t/innodb-semi-consistent.test index 7a9231b508f..c33126b93ff 100644 --- a/mysql-test/t/innodb-semi-consistent.test +++ b/mysql-test/t/innodb-semi-consistent.test @@ -1,6 +1,10 @@ -- source include/not_embedded.inc -- source include/have_innodb.inc +--disable_warnings +drop table if exists t1; +--enable_warnings + # basic tests of semi-consistent reads connect (a,localhost,root,,); diff --git a/mysql-test/t/innodb-ucs2.test b/mysql-test/t/innodb-ucs2.test index 6647a9d0845..7b91ef37d3f 100644 --- a/mysql-test/t/innodb-ucs2.test +++ b/mysql-test/t/innodb-ucs2.test @@ -1,6 +1,10 @@ -- source include/have_innodb.inc -- source include/have_ucs2.inc +--disable_warnings +drop table if exists t1, t2; +--enable_warnings + # # BUG 14056 Column prefix index on UTF-8 primary key column causes: Can't find record.. # From 42853d172c45dc50eaea6b9a4563e96e5515f5bf Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 Nov 2007 12:28:08 +0400 Subject: [PATCH 131/136] after-merge fix: - archive test/result adjusted. - OPTIMIZE/ANALYZE PARTITION EXTENDED test case added. mysql-test/r/archive.result: after-merge fix: - archive test/result adjusted. mysql-test/r/partition.result: after-merge fix: - test case added. mysql-test/t/archive.test: after-merge fix: - archive test/result adjusted. mysql-test/t/partition.test: after-merge fix: - test case added. --- mysql-test/r/archive.result | 2 +- mysql-test/r/partition.result | 10 ++++++++++ mysql-test/t/archive.test | 2 +- mysql-test/t/partition.test | 15 +++++++++++++++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index 77d3cba63d5..edd49988a5f 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -2619,7 +2619,7 @@ auto fld1 companynr fld3 fld4 fld5 fld6 INSERT INTO t2 VALUES (2,011401,37,'breaking','dreaded','Steinberg','W'); INSERT INTO t2 VALUES (3,011402,37,'Romans','scholastics','jarring',''); INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); -OPTIMIZE TABLE t2 EXTENDED; +OPTIMIZE TABLE t2; Table Op Msg_type Msg_text test.t2 optimize status OK SELECT * FROM t2; diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 2b8c79b4563..7c25e948d6c 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -1297,4 +1297,14 @@ create table t1 partition by key(s1) partitions 3; insert into t1 values (null,null); drop table t1; +CREATE TABLE t1(a int) +PARTITION BY RANGE (a) ( +PARTITION p1 VALUES LESS THAN (10), +PARTITION p2 VALUES LESS THAN (20) +); +ALTER TABLE t1 OPTIMIZE PARTITION p1 EXTENDED; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'EXTENDED' at line 1 +ALTER TABLE t1 ANALYZE PARTITION p1 EXTENDED; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'EXTENDED' at line 1 +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index f8eff10e30a..a1158dbfd3b 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1320,7 +1320,7 @@ SELECT * FROM t2; INSERT INTO t2 VALUES (2,011401,37,'breaking','dreaded','Steinberg','W'); INSERT INTO t2 VALUES (3,011402,37,'Romans','scholastics','jarring',''); INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); -OPTIMIZE TABLE t2 EXTENDED; +OPTIMIZE TABLE t2; SELECT * FROM t2; REPAIR TABLE t2; SELECT * FROM t2; diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index 68eff608879..f2fed63c833 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -1541,4 +1541,19 @@ while ($cnt) --enable_query_log drop table t1; + +# +# Bug #30495: optimize table t1,t2,t3 extended errors +# +CREATE TABLE t1(a int) +PARTITION BY RANGE (a) ( + PARTITION p1 VALUES LESS THAN (10), + PARTITION p2 VALUES LESS THAN (20) +); +--error 1064 +ALTER TABLE t1 OPTIMIZE PARTITION p1 EXTENDED; +--error 1064 +ALTER TABLE t1 ANALYZE PARTITION p1 EXTENDED; +DROP TABLE t1; + --echo End of 5.1 tests From 54953ec25cdb1340be98f400eb31f53f3c49bf55 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 Nov 2007 11:02:00 +0100 Subject: [PATCH 132/136] Disabling several tests that fail and reported as errors. mysql-test/suite/ndb/t/disabled.def: Disabling failing tests. mysql-test/suite/rpl/t/disabled.def: Disabling failing tests. mysql-test/suite/rpl/t/rpl_ssl.test: Disabling part of test that fails. --- mysql-test/suite/ndb/t/disabled.def | 1 + mysql-test/suite/rpl/t/disabled.def | 1 + mysql-test/suite/rpl/t/rpl_ssl.test | 7 ++++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/ndb/t/disabled.def b/mysql-test/suite/ndb/t/disabled.def index f876039a042..e1539700803 100644 --- a/mysql-test/suite/ndb/t/disabled.def +++ b/mysql-test/suite/ndb/t/disabled.def @@ -12,6 +12,7 @@ partition_03ndb : BUG#16385 2006-03-24 mikael Partitions: crash when updating a range partitioned NDB table ndb_partition_error2 : HF is not sure if the test can work as internded on all the platforms +ndb_binlog_basic : Bug #32759 2007-11-27 mats ndb_binlog_basic assert failure 'thd->transaction.stmt.modified_non_trans_table' # the below testcase have been reworked to avoid the bug, test contains comment, keep bug open #ndb_binlog_ddl_multi : BUG#18976 2006-04-10 kent CRBR: multiple binlog, second binlog may miss schema log events diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index 42c9c390153..b57c77b6ef5 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -12,3 +12,4 @@ rpl_ddl : BUG#26418 2007-03-01 mleich Slave out of sync after CREATE/DROP TEMPORARY TABLE + ROLLBACK on master rpl_stm_extraColmaster_ndb : WL#3915 : Statement-based replication not supported in ndb. Enable test when supported. +rpl_innodb_bug28430 : Bug #32247 2007-11-27 mats Test reports wrong value of "AUTO_INCREMENT" (on a partitioned InnoDB table) diff --git a/mysql-test/suite/rpl/t/rpl_ssl.test b/mysql-test/suite/rpl/t/rpl_ssl.test index c1b7bc2097b..be730b35c13 100644 --- a/mysql-test/suite/rpl/t/rpl_ssl.test +++ b/mysql-test/suite/rpl/t/rpl_ssl.test @@ -42,6 +42,10 @@ select * from t1; # Do the same thing a number of times disable_query_log; disable_result_log; +# 2007-11-27 mats Bug #32756 Starting and stopping the slave in a loop can lose rows +# After discussions with Engineering, I'm disabling this part of the test to avoid it causing +# red trees. +disable_parsing; let $i= 100; while ($i) { @@ -54,7 +58,8 @@ while ($i) stop slave; dec $i; } -start slave; +enable_parsing; +START SLAVE; enable_query_log; enable_result_log; connection master; From ae5ff26d853066b3196f1bbe941edd5a6c5799ce Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 Nov 2007 17:28:55 +0100 Subject: [PATCH 133/136] Bug#8693 Test 'rpl_log_pos' fails sometimes Disabled the test case. --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 018e8ad520b..0f736265209 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -20,3 +20,4 @@ grant_cache : Bug#32651: grant_cache.test fails rpl_log : Bug#32653: rpl_log.test fails randomly rpl_view : Bug#32654: rpl_view.test fails randomly ndb_backup_print : Bug#32357: ndb_backup_print test fails sometimes in pushbuild +rpl_log_pos : Bug#8693 Test 'rpl_log_pos' fails sometimes From 1a73853c04c907ec72e4e333b609d6d5b1068fe8 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 Nov 2007 21:30:00 +0400 Subject: [PATCH 134/136] after-merge fixup: archive test/result adjusted. --- mysql-test/r/archive.result | 2 +- mysql-test/t/archive.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index a0b13b14b17..0fc43f58908 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -2618,7 +2618,7 @@ auto fld1 companynr fld3 fld4 fld5 fld6 INSERT INTO t2 VALUES (2,011401,37,'breaking','dreaded','Steinberg','W'); INSERT INTO t2 VALUES (3,011402,37,'Romans','scholastics','jarring',''); INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); -OPTIMIZE TABLE t2 EXTENDED; +OPTIMIZE TABLE t2; Table Op Msg_type Msg_text test.t2 optimize status OK SELECT * FROM t2; diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index 2d29cab041d..14a124a96bc 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1317,7 +1317,7 @@ SELECT * FROM t2; INSERT INTO t2 VALUES (2,011401,37,'breaking','dreaded','Steinberg','W'); INSERT INTO t2 VALUES (3,011402,37,'Romans','scholastics','jarring',''); INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); -OPTIMIZE TABLE t2 EXTENDED; +OPTIMIZE TABLE t2; SELECT * FROM t2; REPAIR TABLE t2; SELECT * FROM t2; From 7991e6a61dac3dd741e25712d51701b1c6537cc7 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 28 Nov 2007 09:48:06 +0100 Subject: [PATCH 135/136] Bug#29149 Test "kill" fails on Windows Disabled test case. --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 0f736265209..297b6e70f39 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -21,3 +21,4 @@ rpl_log : Bug#32653: rpl_log.test fails randomly rpl_view : Bug#32654: rpl_view.test fails randomly ndb_backup_print : Bug#32357: ndb_backup_print test fails sometimes in pushbuild rpl_log_pos : Bug#8693 Test 'rpl_log_pos' fails sometimes +kill : Bug#29149 Test "kill" fails on Windows From c0ecd863b87afec0d73a946cdcaa84e0d92cfe38 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 28 Nov 2007 10:00:23 +0100 Subject: [PATCH 136/136] Bug#8693 Test 'rpl_log_pos' fails sometimes Moved disabling to rpl suite. Bug#32801 wait_timeout.test fails randomly Disabled test case. mysql-test/suite/rpl/t/disabled.def: Bug#8693 Test 'rpl_log_pos' fails sometimes Moved disabling to rpl suite. --- mysql-test/suite/rpl/t/disabled.def | 1 + mysql-test/t/disabled.def | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index 4e95ac1f74a..20c3ccf0486 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -15,3 +15,4 @@ rpl_stm_extraColmaster_ndb : WL#3915 : Statement-based replication not supported rpl_innodb_bug28430 : Bug #32247 2007-11-27 mats Test reports wrong value of "AUTO_INCREMENT" (on a partitioned InnoDB table) rpl_view : Bug#32654: rpl_view.test fails randomly rpl_ndb_multi : Bug#30751: rpl_ndb_multi missing row in output +rpl_log_pos : Bug#8693 Test 'rpl_log_pos' fails sometimes diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 50a30ce0e77..2fcec0ea623 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -21,4 +21,4 @@ lowercase_table3 : Bug#32667 lowercase_table3.test reports to error log kill : Bug#29149: Test "kill" fails on Windows grant3 : Bug#32723: grant3.test fails innodb_mysql : Bug#32724: innodb_mysql.test fails randomly -rpl_log_pos : Bug#8693 Test 'rpl_log_pos' fails sometimes +wait_timeout : Bug#32801 wait_timeout.test fails randomly