diff options
author | Mats Kindahl <mats@sun.com> | 2008-11-03 18:50:49 +0100 |
---|---|---|
committer | Mats Kindahl <mats@sun.com> | 2008-11-03 18:50:49 +0100 |
commit | 5a897c8b4ee38e591c3955e848b5a0ba6b332fe8 (patch) | |
tree | 43a32b1d507d16a5462d3cf95bbb8ac8e0e54184 | |
parent | 32c9fe6bf5259e8144c2bb27f062d44bc3d4e610 (diff) | |
parent | ffbf00e6a2e06a1a4788cd3e27041a14ff8a0f3f (diff) | |
download | mariadb-git-5a897c8b4ee38e591c3955e848b5a0ba6b332fe8.tar.gz |
Merging with 5.1-5.1.29-rc
-rw-r--r-- | mysql-test/extra/rpl_tests/rpl_row_basic.test | 99 | ||||
-rw-r--r-- | mysql-test/r/alter_table.result | 12 | ||||
-rw-r--r-- | mysql-test/r/binlog_format_basic.result | 3 | ||||
-rw-r--r-- | mysql-test/r/xa.result | 20 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result | 57 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result | 57 | ||||
-rw-r--r-- | mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result | 57 | ||||
-rw-r--r-- | mysql-test/t/alter_table.test | 12 | ||||
-rw-r--r-- | mysql-test/t/binlog_format_basic.test | 7 | ||||
-rw-r--r-- | mysql-test/t/xa.test | 45 | ||||
-rw-r--r-- | sql/field.cc | 35 | ||||
-rw-r--r-- | sql/field.h | 2 | ||||
-rw-r--r-- | sql/handler.cc | 30 | ||||
-rw-r--r-- | sql/log_event.cc | 38 | ||||
-rw-r--r-- | sql/log_event_old.cc | 47 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 6 | ||||
-rw-r--r-- | sql/sql_class.h | 4 | ||||
-rw-r--r-- | sql/sql_parse.cc | 78 | ||||
-rw-r--r-- | zlib/gzio.c | 5 |
19 files changed, 568 insertions, 46 deletions
diff --git a/mysql-test/extra/rpl_tests/rpl_row_basic.test b/mysql-test/extra/rpl_tests/rpl_row_basic.test index 7cfbcdb4437..2106ccd8a85 100644 --- a/mysql-test/extra/rpl_tests/rpl_row_basic.test +++ b/mysql-test/extra/rpl_tests/rpl_row_basic.test @@ -471,3 +471,102 @@ source include/diff_tables.inc; connection master; drop table t1; sync_slave_with_master; + +# +# BUG#40004: Replication failure with no PK + no indexes +# + +# The test cases are taken from the bug report. It is difficult to +# produce a test case that generates a HA_ERR_RECORD_DELETED, so we go +# with the test cases we have. + +connection master; + +eval CREATE TABLE t1 (a int) ENGINE=$type; + +INSERT IGNORE INTO t1 VALUES (NULL); +INSERT INTO t1 ( a ) VALUES ( 0 ); +INSERT INTO t1 ( a ) VALUES ( 9 ); +INSERT INTO t1 ( a ) VALUES ( 2 ); +INSERT INTO t1 ( a ) VALUES ( 9 ); +INSERT INTO t1 ( a ) VALUES ( 5 ); + +UPDATE t1 SET a = 5 WHERE a = 9; +DELETE FROM t1 WHERE a < 6; +UPDATE t1 SET a = 9 WHERE a < 3; +INSERT INTO t1 ( a ) VALUES ( 3 ); +UPDATE t1 SET a = 0 WHERE a < 4; +UPDATE t1 SET a = 8 WHERE a < 5; + +sync_slave_with_master; + +let $diff_table_1=master:test.t1; +let $diff_table_2=slave:test.t1; +source include/diff_tables.inc; + +connection master; +drop table t1; +sync_slave_with_master; + +# +# Bug #39752: Replication failure on RBR + MyISAM + no PK +# + +# The test cases are taken from the bug report. It is difficult to +# produce a test case that generates a HA_ERR_RECORD_DELETED, so we go +# with the test cases we have. + +connection master; + +--disable_warnings +eval CREATE TABLE t1 (a bit) ENGINE=$type; +INSERT IGNORE INTO t1 VALUES (NULL); +INSERT INTO t1 ( a ) VALUES ( 0 ); +UPDATE t1 SET a = 0 WHERE a = 1 LIMIT 3; +INSERT INTO t1 ( a ) VALUES ( 5 ); +DELETE FROM t1 WHERE a < 2 LIMIT 4; +DELETE FROM t1 WHERE a < 9 LIMIT 4; +INSERT INTO t1 ( a ) VALUES ( 9 ); +UPDATE t1 SET a = 8 WHERE a = 0 LIMIT 6; +INSERT INTO t1 ( a ) VALUES ( 8 ); +UPDATE t1 SET a = 0 WHERE a < 6 LIMIT 0; +INSERT INTO t1 ( a ) VALUES ( 4 ); +INSERT INTO t1 ( a ) VALUES ( 3 ); +UPDATE t1 SET a = 0 WHERE a = 7 LIMIT 6; +DELETE FROM t1 WHERE a = 4 LIMIT 7; +UPDATE t1 SET a = 9 WHERE a < 2 LIMIT 9; +UPDATE t1 SET a = 0 WHERE a < 9 LIMIT 2; +DELETE FROM t1 WHERE a < 0 LIMIT 5; +INSERT INTO t1 ( a ) VALUES ( 5 ); +UPDATE t1 SET a = 4 WHERE a < 6 LIMIT 4; +INSERT INTO t1 ( a ) VALUES ( 5 ); +UPDATE t1 SET a = 9 WHERE a < 5 LIMIT 8; +DELETE FROM t1 WHERE a < 8 LIMIT 8; +INSERT INTO t1 ( a ) VALUES ( 6 ); +DELETE FROM t1 WHERE a < 6 LIMIT 7; +UPDATE t1 SET a = 7 WHERE a = 3 LIMIT 7; +UPDATE t1 SET a = 8 WHERE a = 0 LIMIT 6; +INSERT INTO t1 ( a ) VALUES ( 7 ); +DELETE FROM t1 WHERE a < 9 LIMIT 4; +INSERT INTO t1 ( a ) VALUES ( 7 ); +INSERT INTO t1 ( a ) VALUES ( 6 ); +UPDATE t1 SET a = 8 WHERE a = 3 LIMIT 4; +DELETE FROM t1 WHERE a = 2 LIMIT 9; +DELETE FROM t1 WHERE a = 1 LIMIT 4; +UPDATE t1 SET a = 4 WHERE a = 2 LIMIT 7; +INSERT INTO t1 ( a ) VALUES ( 0 ); +DELETE FROM t1 WHERE a < 3 LIMIT 0; +UPDATE t1 SET a = 8 WHERE a = 5 LIMIT 2; +INSERT INTO t1 ( a ) VALUES ( 1 ); +UPDATE t1 SET a = 9 WHERE a < 5 LIMIT 3; +--enable_warnings + +sync_slave_with_master; + +let $diff_table_1=master:test.t1; +let $diff_table_2=slave:test.t1; +source include/diff_tables.inc; + +connection master; +drop table t1; +sync_slave_with_master; diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index d6986f4a956..c6be8f243fc 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -1222,4 +1222,16 @@ ALTER TABLE t1 CHANGE d c varchar(10); affected rows: 0 info: Records: 0 Duplicates: 0 Warnings: 0 DROP TABLE t1; +CREATE TABLE t1(a INT AUTO_INCREMENT PRIMARY KEY, +b ENUM('a', 'b', 'c') NOT NULL); +INSERT INTO t1 (b) VALUES ('a'), ('c'), ('b'), ('b'), ('a'); +ALTER TABLE t1 MODIFY b ENUM('a', 'z', 'b', 'c') NOT NULL; +SELECT * FROM t1; +a b +1 a +2 c +3 b +4 b +5 a +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/r/binlog_format_basic.result b/mysql-test/r/binlog_format_basic.result index 3fee9bade7e..72ba35cd753 100644 --- a/mysql-test/r/binlog_format_basic.result +++ b/mysql-test/r/binlog_format_basic.result @@ -1,3 +1,6 @@ +SELECT @@GLOBAL.binlog_format; +@@GLOBAL.binlog_format +STATEMENT '#---------------------BS_STVARS_002_01----------------------#' SELECT COUNT(@@GLOBAL.binlog_format); COUNT(@@GLOBAL.binlog_format) diff --git a/mysql-test/r/xa.result b/mysql-test/r/xa.result index 5fb03d2378e..592cf07522b 100644 --- a/mysql-test/r/xa.result +++ b/mysql-test/r/xa.result @@ -55,3 +55,23 @@ select * from t1; a 20 drop table t1; +drop table if exists t1; +create table t1(a int, b int, c varchar(20), primary key(a)) engine = innodb; +insert into t1 values(1, 1, 'a'); +insert into t1 values(2, 2, 'b'); +xa start 'a','b'; +update t1 set c = 'aa' where a = 1; +xa start 'a','c'; +update t1 set c = 'bb' where a = 2; +update t1 set c = 'bb' where a = 2; +update t1 set c = 'aa' where a = 1; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +select count(*) from t1; +count(*) +2 +xa end 'a','c'; +ERROR XA102: XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected +xa rollback 'a','c'; +xa start 'a','c'; +drop table t1; +End of 5.0 tests 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 d9d96cf7eda..76ff8e15fdb 100644 --- a/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result +++ b/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result @@ -527,3 +527,60 @@ ERROR 23000: Duplicate entry '10' for key 'PRIMARY' INSERT INTO t1 VALUES (4); Comparing tables master:test.t1 and slave:test.t1 drop table t1; +CREATE TABLE t1 (a int) ENGINE='MYISAM' ; +INSERT IGNORE INTO t1 VALUES (NULL); +INSERT INTO t1 ( a ) VALUES ( 0 ); +INSERT INTO t1 ( a ) VALUES ( 9 ); +INSERT INTO t1 ( a ) VALUES ( 2 ); +INSERT INTO t1 ( a ) VALUES ( 9 ); +INSERT INTO t1 ( a ) VALUES ( 5 ); +UPDATE t1 SET a = 5 WHERE a = 9; +DELETE FROM t1 WHERE a < 6; +UPDATE t1 SET a = 9 WHERE a < 3; +INSERT INTO t1 ( a ) VALUES ( 3 ); +UPDATE t1 SET a = 0 WHERE a < 4; +UPDATE t1 SET a = 8 WHERE a < 5; +Comparing tables master:test.t1 and slave:test.t1 +drop table t1; +CREATE TABLE t1 (a bit) ENGINE='MYISAM' ; +INSERT IGNORE INTO t1 VALUES (NULL); +INSERT INTO t1 ( a ) VALUES ( 0 ); +UPDATE t1 SET a = 0 WHERE a = 1 LIMIT 3; +INSERT INTO t1 ( a ) VALUES ( 5 ); +DELETE FROM t1 WHERE a < 2 LIMIT 4; +DELETE FROM t1 WHERE a < 9 LIMIT 4; +INSERT INTO t1 ( a ) VALUES ( 9 ); +UPDATE t1 SET a = 8 WHERE a = 0 LIMIT 6; +INSERT INTO t1 ( a ) VALUES ( 8 ); +UPDATE t1 SET a = 0 WHERE a < 6 LIMIT 0; +INSERT INTO t1 ( a ) VALUES ( 4 ); +INSERT INTO t1 ( a ) VALUES ( 3 ); +UPDATE t1 SET a = 0 WHERE a = 7 LIMIT 6; +DELETE FROM t1 WHERE a = 4 LIMIT 7; +UPDATE t1 SET a = 9 WHERE a < 2 LIMIT 9; +UPDATE t1 SET a = 0 WHERE a < 9 LIMIT 2; +DELETE FROM t1 WHERE a < 0 LIMIT 5; +INSERT INTO t1 ( a ) VALUES ( 5 ); +UPDATE t1 SET a = 4 WHERE a < 6 LIMIT 4; +INSERT INTO t1 ( a ) VALUES ( 5 ); +UPDATE t1 SET a = 9 WHERE a < 5 LIMIT 8; +DELETE FROM t1 WHERE a < 8 LIMIT 8; +INSERT INTO t1 ( a ) VALUES ( 6 ); +DELETE FROM t1 WHERE a < 6 LIMIT 7; +UPDATE t1 SET a = 7 WHERE a = 3 LIMIT 7; +UPDATE t1 SET a = 8 WHERE a = 0 LIMIT 6; +INSERT INTO t1 ( a ) VALUES ( 7 ); +DELETE FROM t1 WHERE a < 9 LIMIT 4; +INSERT INTO t1 ( a ) VALUES ( 7 ); +INSERT INTO t1 ( a ) VALUES ( 6 ); +UPDATE t1 SET a = 8 WHERE a = 3 LIMIT 4; +DELETE FROM t1 WHERE a = 2 LIMIT 9; +DELETE FROM t1 WHERE a = 1 LIMIT 4; +UPDATE t1 SET a = 4 WHERE a = 2 LIMIT 7; +INSERT INTO t1 ( a ) VALUES ( 0 ); +DELETE FROM t1 WHERE a < 3 LIMIT 0; +UPDATE t1 SET a = 8 WHERE a = 5 LIMIT 2; +INSERT INTO t1 ( a ) VALUES ( 1 ); +UPDATE t1 SET a = 9 WHERE a < 5 LIMIT 3; +Comparing tables master:test.t1 and slave:test.t1 +drop table t1; 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 72c94ceb525..15673768180 100644 --- a/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result +++ b/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result @@ -527,3 +527,60 @@ ERROR 23000: Duplicate entry '10' for key 'PRIMARY' INSERT INTO t1 VALUES (4); Comparing tables master:test.t1 and slave:test.t1 drop table t1; +CREATE TABLE t1 (a int) ENGINE='INNODB' ; +INSERT IGNORE INTO t1 VALUES (NULL); +INSERT INTO t1 ( a ) VALUES ( 0 ); +INSERT INTO t1 ( a ) VALUES ( 9 ); +INSERT INTO t1 ( a ) VALUES ( 2 ); +INSERT INTO t1 ( a ) VALUES ( 9 ); +INSERT INTO t1 ( a ) VALUES ( 5 ); +UPDATE t1 SET a = 5 WHERE a = 9; +DELETE FROM t1 WHERE a < 6; +UPDATE t1 SET a = 9 WHERE a < 3; +INSERT INTO t1 ( a ) VALUES ( 3 ); +UPDATE t1 SET a = 0 WHERE a < 4; +UPDATE t1 SET a = 8 WHERE a < 5; +Comparing tables master:test.t1 and slave:test.t1 +drop table t1; +CREATE TABLE t1 (a bit) ENGINE='INNODB' ; +INSERT IGNORE INTO t1 VALUES (NULL); +INSERT INTO t1 ( a ) VALUES ( 0 ); +UPDATE t1 SET a = 0 WHERE a = 1 LIMIT 3; +INSERT INTO t1 ( a ) VALUES ( 5 ); +DELETE FROM t1 WHERE a < 2 LIMIT 4; +DELETE FROM t1 WHERE a < 9 LIMIT 4; +INSERT INTO t1 ( a ) VALUES ( 9 ); +UPDATE t1 SET a = 8 WHERE a = 0 LIMIT 6; +INSERT INTO t1 ( a ) VALUES ( 8 ); +UPDATE t1 SET a = 0 WHERE a < 6 LIMIT 0; +INSERT INTO t1 ( a ) VALUES ( 4 ); +INSERT INTO t1 ( a ) VALUES ( 3 ); +UPDATE t1 SET a = 0 WHERE a = 7 LIMIT 6; +DELETE FROM t1 WHERE a = 4 LIMIT 7; +UPDATE t1 SET a = 9 WHERE a < 2 LIMIT 9; +UPDATE t1 SET a = 0 WHERE a < 9 LIMIT 2; +DELETE FROM t1 WHERE a < 0 LIMIT 5; +INSERT INTO t1 ( a ) VALUES ( 5 ); +UPDATE t1 SET a = 4 WHERE a < 6 LIMIT 4; +INSERT INTO t1 ( a ) VALUES ( 5 ); +UPDATE t1 SET a = 9 WHERE a < 5 LIMIT 8; +DELETE FROM t1 WHERE a < 8 LIMIT 8; +INSERT INTO t1 ( a ) VALUES ( 6 ); +DELETE FROM t1 WHERE a < 6 LIMIT 7; +UPDATE t1 SET a = 7 WHERE a = 3 LIMIT 7; +UPDATE t1 SET a = 8 WHERE a = 0 LIMIT 6; +INSERT INTO t1 ( a ) VALUES ( 7 ); +DELETE FROM t1 WHERE a < 9 LIMIT 4; +INSERT INTO t1 ( a ) VALUES ( 7 ); +INSERT INTO t1 ( a ) VALUES ( 6 ); +UPDATE t1 SET a = 8 WHERE a = 3 LIMIT 4; +DELETE FROM t1 WHERE a = 2 LIMIT 9; +DELETE FROM t1 WHERE a = 1 LIMIT 4; +UPDATE t1 SET a = 4 WHERE a = 2 LIMIT 7; +INSERT INTO t1 ( a ) VALUES ( 0 ); +DELETE FROM t1 WHERE a < 3 LIMIT 0; +UPDATE t1 SET a = 8 WHERE a = 5 LIMIT 2; +INSERT INTO t1 ( a ) VALUES ( 1 ); +UPDATE t1 SET a = 9 WHERE a < 5 LIMIT 3; +Comparing tables master:test.t1 and slave:test.t1 +drop table t1; 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 2538358b4d3..ac8ca2b3bcd 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 @@ -527,3 +527,60 @@ ERROR 23000: Duplicate entry '10' for key 'PRIMARY' INSERT INTO t1 VALUES (4); Comparing tables master:test.t1 and slave:test.t1 drop table t1; +CREATE TABLE t1 (a int) ENGINE='NDB' ; +INSERT IGNORE INTO t1 VALUES (NULL); +INSERT INTO t1 ( a ) VALUES ( 0 ); +INSERT INTO t1 ( a ) VALUES ( 9 ); +INSERT INTO t1 ( a ) VALUES ( 2 ); +INSERT INTO t1 ( a ) VALUES ( 9 ); +INSERT INTO t1 ( a ) VALUES ( 5 ); +UPDATE t1 SET a = 5 WHERE a = 9; +DELETE FROM t1 WHERE a < 6; +UPDATE t1 SET a = 9 WHERE a < 3; +INSERT INTO t1 ( a ) VALUES ( 3 ); +UPDATE t1 SET a = 0 WHERE a < 4; +UPDATE t1 SET a = 8 WHERE a < 5; +Comparing tables master:test.t1 and slave:test.t1 +drop table t1; +CREATE TABLE t1 (a bit) ENGINE='NDB' ; +INSERT IGNORE INTO t1 VALUES (NULL); +INSERT INTO t1 ( a ) VALUES ( 0 ); +UPDATE t1 SET a = 0 WHERE a = 1 LIMIT 3; +INSERT INTO t1 ( a ) VALUES ( 5 ); +DELETE FROM t1 WHERE a < 2 LIMIT 4; +DELETE FROM t1 WHERE a < 9 LIMIT 4; +INSERT INTO t1 ( a ) VALUES ( 9 ); +UPDATE t1 SET a = 8 WHERE a = 0 LIMIT 6; +INSERT INTO t1 ( a ) VALUES ( 8 ); +UPDATE t1 SET a = 0 WHERE a < 6 LIMIT 0; +INSERT INTO t1 ( a ) VALUES ( 4 ); +INSERT INTO t1 ( a ) VALUES ( 3 ); +UPDATE t1 SET a = 0 WHERE a = 7 LIMIT 6; +DELETE FROM t1 WHERE a = 4 LIMIT 7; +UPDATE t1 SET a = 9 WHERE a < 2 LIMIT 9; +UPDATE t1 SET a = 0 WHERE a < 9 LIMIT 2; +DELETE FROM t1 WHERE a < 0 LIMIT 5; +INSERT INTO t1 ( a ) VALUES ( 5 ); +UPDATE t1 SET a = 4 WHERE a < 6 LIMIT 4; +INSERT INTO t1 ( a ) VALUES ( 5 ); +UPDATE t1 SET a = 9 WHERE a < 5 LIMIT 8; +DELETE FROM t1 WHERE a < 8 LIMIT 8; +INSERT INTO t1 ( a ) VALUES ( 6 ); +DELETE FROM t1 WHERE a < 6 LIMIT 7; +UPDATE t1 SET a = 7 WHERE a = 3 LIMIT 7; +UPDATE t1 SET a = 8 WHERE a = 0 LIMIT 6; +INSERT INTO t1 ( a ) VALUES ( 7 ); +DELETE FROM t1 WHERE a < 9 LIMIT 4; +INSERT INTO t1 ( a ) VALUES ( 7 ); +INSERT INTO t1 ( a ) VALUES ( 6 ); +UPDATE t1 SET a = 8 WHERE a = 3 LIMIT 4; +DELETE FROM t1 WHERE a = 2 LIMIT 9; +DELETE FROM t1 WHERE a = 1 LIMIT 4; +UPDATE t1 SET a = 4 WHERE a = 2 LIMIT 7; +INSERT INTO t1 ( a ) VALUES ( 0 ); +DELETE FROM t1 WHERE a < 3 LIMIT 0; +UPDATE t1 SET a = 8 WHERE a = 5 LIMIT 2; +INSERT INTO t1 ( a ) VALUES ( 1 ); +UPDATE t1 SET a = 9 WHERE a < 5 LIMIT 3; +Comparing tables master:test.t1 and slave:test.t1 +drop table t1; diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 662f9095810..c45c89095fa 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -947,4 +947,16 @@ ALTER TABLE t1 CHANGE d c varchar(10); --disable_info DROP TABLE t1; + +# +# Bug #23113: Different behavior on altering ENUM fields between 5.0 and 5.1 +# +CREATE TABLE t1(a INT AUTO_INCREMENT PRIMARY KEY, + b ENUM('a', 'b', 'c') NOT NULL); +INSERT INTO t1 (b) VALUES ('a'), ('c'), ('b'), ('b'), ('a'); +ALTER TABLE t1 MODIFY b ENUM('a', 'z', 'b', 'c') NOT NULL; +SELECT * FROM t1; +DROP TABLE t1; + + --echo End of 5.1 tests diff --git a/mysql-test/t/binlog_format_basic.test b/mysql-test/t/binlog_format_basic.test index e9dfade8f56..819ad047c1b 100644 --- a/mysql-test/t/binlog_format_basic.test +++ b/mysql-test/t/binlog_format_basic.test @@ -22,6 +22,13 @@ # # ############################################################################### +################################################################### +# BUG#39812: Make statement replication default for 5.1 (to match 5.0) +# We just verify that the default binlog_format is STATEMENT in 5.1. +# In 6.0, it should be MIXED. +################################################################### +SELECT @@GLOBAL.binlog_format; + --echo '#---------------------BS_STVARS_002_01----------------------#' #################################################################### # Displaying default value # diff --git a/mysql-test/t/xa.test b/mysql-test/t/xa.test index 0d564727fe3..591d7ac2c4d 100644 --- a/mysql-test/t/xa.test +++ b/mysql-test/t/xa.test @@ -74,3 +74,48 @@ xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'; select * from t1; drop table t1; +disconnect con1; + +# +# Bug#28323: Server crashed in xid cache operations +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1(a int, b int, c varchar(20), primary key(a)) engine = innodb; +insert into t1 values(1, 1, 'a'); +insert into t1 values(2, 2, 'b'); + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); + +--connection con1 +xa start 'a','b'; +update t1 set c = 'aa' where a = 1; +--connection con2 +xa start 'a','c'; +update t1 set c = 'bb' where a = 2; +--connection con1 +--send update t1 set c = 'bb' where a = 2 +--connection con2 +--sleep 1 +--error ER_LOCK_DEADLOCK +update t1 set c = 'aa' where a = 1; +select count(*) from t1; +--error ER_XA_RBDEADLOCK +xa end 'a','c'; +xa rollback 'a','c'; +--disconnect con2 + +connect (con3,localhost,root,,); +--connection con3 +xa start 'a','c'; + +--disconnect con1 +--disconnect con3 +--connection default +drop table t1; + +--echo End of 5.0 tests diff --git a/sql/field.cc b/sql/field.cc index 16bf0fdb070..a03beb4e8af 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -8783,28 +8783,43 @@ bool Field::eq_def(Field *field) return 1; } + /** @return returns 1 if the fields are equally defined */ + bool Field_enum::eq_def(Field *field) { if (!Field::eq_def(field)) return 0; - TYPELIB *from_lib=((Field_enum*) field)->typelib; + return compare_enum_values(((Field_enum*) field)->typelib); +} - if (typelib->count < from_lib->count) - return 0; - for (uint i=0 ; i < from_lib->count ; i++) + +bool Field_enum::compare_enum_values(TYPELIB *values) +{ + if (typelib->count != values->count) + return FALSE; + for (uint i= 0; i < typelib->count; i++) if (my_strnncoll(field_charset, - (const uchar*)typelib->type_names[i], - strlen(typelib->type_names[i]), - (const uchar*)from_lib->type_names[i], - strlen(from_lib->type_names[i]))) - return 0; - return 1; + (const uchar*) typelib->type_names[i], + typelib->type_lengths[i], + (const uchar*) values->type_names[i], + values->type_lengths[i])) + return FALSE; + return TRUE; +} + + +uint Field_enum::is_equal(Create_field *new_field) +{ + if (!Field_str::is_equal(new_field)) + return 0; + return compare_enum_values(new_field->interval); } + /** @return returns 1 if the fields are equally defined diff --git a/sql/field.h b/sql/field.h index aa69fea6bdd..81905cc64ae 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1853,6 +1853,8 @@ public: CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; } private: int do_save_field_metadata(uchar *first_byte); + bool compare_enum_values(TYPELIB *values); + uint is_equal(Create_field *new_field); }; diff --git a/sql/handler.cc b/sql/handler.cc index a988c34b7ca..9c70bd1a801 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1278,7 +1278,12 @@ int ha_rollback_trans(THD *thd, bool all) trans->ha_list= 0; trans->no_2pc=0; if (is_real_trans) - thd->transaction.xid_state.xid.null(); + { + if (thd->transaction_rollback_request) + thd->transaction.xid_state.rm_error= thd->main_da.sql_errno(); + else + thd->transaction.xid_state.xid.null(); + } if (all) { thd->variables.tx_isolation=thd->session_tx_isolation; @@ -2765,7 +2770,7 @@ int handler::check_collation_compatibility() { ulong mysql_version= table->s->mysql_version; - if (mysql_version < 50048) + if (mysql_version < 50124) { KEY *key= table->key_info; KEY *key_end= key + table->s->keys; @@ -2779,15 +2784,18 @@ int handler::check_collation_compatibility() continue; Field *field= table->field[key_part->fieldnr - 1]; uint cs_number= field->charset()->number; - if (mysql_version < 50048 && - (cs_number == 11 || /* ascii_general_ci - bug #29499, bug #27562 */ - cs_number == 41 || /* latin7_general_ci - bug #29461 */ - cs_number == 42 || /* latin7_general_cs - bug #29461 */ - cs_number == 20 || /* latin7_estonian_cs - bug #29461 */ - cs_number == 21 || /* latin2_hungarian_ci - bug #29461 */ - cs_number == 22 || /* koi8u_general_ci - bug #29461 */ - cs_number == 23 || /* cp1251_ukrainian_ci - bug #29461 */ - cs_number == 26)) /* cp1250_general_ci - bug #29461 */ + if ((mysql_version < 50048 && + (cs_number == 11 || /* ascii_general_ci - bug #29499, bug #27562 */ + cs_number == 41 || /* latin7_general_ci - bug #29461 */ + cs_number == 42 || /* latin7_general_cs - bug #29461 */ + cs_number == 20 || /* latin7_estonian_cs - bug #29461 */ + cs_number == 21 || /* latin2_hungarian_ci - bug #29461 */ + cs_number == 22 || /* koi8u_general_ci - bug #29461 */ + cs_number == 23 || /* cp1251_ukrainian_ci - bug #29461 */ + cs_number == 26)) || /* cp1250_general_ci - bug #29461 */ + (mysql_version < 50124 && + (cs_number == 33 || /* utf8_general_ci - bug #27877 */ + cs_number == 35))) /* ucs2_general_ci - bug #27877 */ return HA_ADMIN_NEEDS_UPGRADE; } } diff --git a/sql/log_event.cc b/sql/log_event.cc index f91ebf3823f..0d03593946d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -7203,6 +7203,9 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) error= do_exec_row(rli); + DBUG_PRINT("info", ("error: %s", HA_ERR(error))); + DBUG_ASSERT(error != HA_ERR_RECORD_DELETED); + table->in_use = old_thd; switch (error) { @@ -7218,11 +7221,13 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) case HA_ERR_TABLE_DEF_CHANGED: case HA_ERR_CANNOT_ADD_FOREIGN: - + which are not included into to the list. + + Note that HA_ERR_RECORD_DELETED is not in the list since + do_exec_row() should not return that error code. */ case HA_ERR_RECORD_CHANGED: - case HA_ERR_RECORD_DELETED: case HA_ERR_KEY_NOT_FOUND: case HA_ERR_END_OF_FILE: case HA_ERR_FOUND_DUPP_KEY: @@ -7231,7 +7236,6 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) case HA_ERR_NO_REFERENCED_ROW: case HA_ERR_ROW_IS_REFERENCED: - DBUG_PRINT("info", ("error: %s", HA_ERR(error))); if (bit_is_set(slave_exec_mode, SLAVE_EXEC_MODE_IDEMPOTENT) == 1) { if (global_system_variables.log_warnings) @@ -7254,7 +7258,6 @@ 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)); @@ -8269,6 +8272,8 @@ Rows_log_event::write_row(const Relay_log_info *const rli, if (error) { DBUG_PRINT("info",("rnd_pos() returns error %d",error)); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -8301,7 +8306,9 @@ Rows_log_event::write_row(const Relay_log_info *const rli, HA_READ_KEY_EXACT); if (error) { - DBUG_PRINT("info",("index_read_idx() returns error %d",error)); + DBUG_PRINT("info",("index_read_idx() returns %s", HA_ERR(error))); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -8574,6 +8581,8 @@ int Rows_log_event::find_row(const Relay_log_info *rli) if (error) { DBUG_PRINT("info",("rnd_pos returns error %d",error)); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); } DBUG_RETURN(error); @@ -8633,6 +8642,8 @@ int Rows_log_event::find_row(const Relay_log_info *rli) HA_READ_KEY_EXACT))) { DBUG_PRINT("info",("no record matching the key found in the table")); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); table->file->ha_index_end(); goto err; @@ -8690,8 +8701,11 @@ int Rows_log_event::find_row(const Relay_log_info *rli) 256U - (1U << table->s->last_null_bit_pos); } - if ((error= table->file->index_next(table->record[0]))) + while ((error= table->file->index_next(table->record[0]))) { + /* We just skip records that has already been deleted */ + if (error == HA_ERR_RECORD_DELETED) + continue; DBUG_PRINT("info",("no record matching the given row found")); table->file->print_error(error, MYF(0)); table->file->ha_index_end(); @@ -8722,14 +8736,22 @@ int Rows_log_event::find_row(const Relay_log_info *rli) /* Continue until we find the right record or have made a full loop */ do { + restart_rnd_next: error= table->file->rnd_next(table->record[0]); + DBUG_PRINT("info", ("error: %s", HA_ERR(error))); switch (error) { case 0: - case HA_ERR_RECORD_DELETED: break; + /* + If the record was deleted, we pick the next one without doing + any comparisons. + */ + case HA_ERR_RECORD_DELETED: + goto restart_rnd_next; + case HA_ERR_END_OF_FILE: if (++restart_count < 2) table->file->ha_rnd_init(1); @@ -8759,7 +8781,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 == HA_ERR_RECORD_DELETED || error == 0); + DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == 0); goto err; } ok: diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index c6b99b1bd69..75aa8722aa9 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -556,6 +556,9 @@ replace_record(THD *thd, TABLE *table, error= table->file->rnd_pos(table->record[1], table->file->dup_ref); if (error) { + DBUG_PRINT("info",("rnd_pos() returns error %d",error)); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -582,6 +585,9 @@ replace_record(THD *thd, TABLE *table, HA_READ_KEY_EXACT); if (error) { + DBUG_PRINT("info", ("index_read_idx() returns error %d", error)); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -787,11 +793,14 @@ static int find_and_fetch_row(TABLE *table, uchar *key) 256U - (1U << table->s->last_null_bit_pos); } - if ((error= table->file->index_next(table->record[1]))) + while ((error= table->file->index_next(table->record[1]))) { - table->file->print_error(error, MYF(0)); + /* We just skip records that has already been deleted */ + if (error == HA_ERR_RECORD_DELETED) + continue; + table->file->print_error(error, MYF(0)); table->file->ha_index_end(); - DBUG_RETURN(error); + DBUG_RETURN(error); } } @@ -812,6 +821,7 @@ static int find_and_fetch_row(TABLE *table, uchar *key) /* Continue until we find the right record or have made a full loop */ do { + restart_rnd_next: error= table->file->rnd_next(table->record[1]); DBUG_DUMP("record[0]", table->record[0], table->s->reclength); @@ -819,8 +829,14 @@ static int find_and_fetch_row(TABLE *table, uchar *key) switch (error) { case 0: + break; + + /* + If the record was deleted, we pick the next one without doing + any comparisons. + */ case HA_ERR_RECORD_DELETED: - break; + goto restart_rnd_next; case HA_ERR_END_OF_FILE: if (++restart_count < 2) @@ -1680,6 +1696,9 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) error= do_exec_row(rli); + DBUG_PRINT("info", ("error: %d", error)); + DBUG_ASSERT(error != HA_ERR_RECORD_DELETED); + table->in_use = old_thd; switch (error) { @@ -2100,6 +2119,8 @@ Old_rows_log_event::write_row(const Relay_log_info *const rli, if (error) { DBUG_PRINT("info",("rnd_pos() returns error %d",error)); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -2132,7 +2153,9 @@ Old_rows_log_event::write_row(const Relay_log_info *const rli, HA_READ_KEY_EXACT); if (error) { - DBUG_PRINT("info",("index_read_idx() returns error %d",error)); + DBUG_PRINT("info",("index_read_idx() returns error %d", error)); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -2288,6 +2311,8 @@ int Old_rows_log_event::find_row(const Relay_log_info *rli) if (error) { DBUG_PRINT("info",("rnd_pos returns error %d",error)); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); } DBUG_RETURN(error); @@ -2347,6 +2372,8 @@ int Old_rows_log_event::find_row(const Relay_log_info *rli) HA_READ_KEY_EXACT))) { DBUG_PRINT("info",("no record matching the key found in the table")); + if (error == HA_ERR_RECORD_DELETED) + error= HA_ERR_KEY_NOT_FOUND; table->file->print_error(error, MYF(0)); table->file->ha_index_end(); DBUG_RETURN(error); @@ -2404,8 +2431,11 @@ int Old_rows_log_event::find_row(const Relay_log_info *rli) 256U - (1U << table->s->last_null_bit_pos); } - if ((error= table->file->index_next(table->record[0]))) + while ((error= table->file->index_next(table->record[0]))) { + /* We just skip records that has already been deleted */ + if (error == HA_ERR_RECORD_DELETED) + continue; DBUG_PRINT("info",("no record matching the given row found")); table->file->print_error(error, MYF(0)); table->file->ha_index_end(); @@ -2436,14 +2466,17 @@ int Old_rows_log_event::find_row(const Relay_log_info *rli) /* Continue until we find the right record or have made a full loop */ do { + restart_rnd_next: error= table->file->rnd_next(table->record[0]); switch (error) { case 0: - case HA_ERR_RECORD_DELETED: break; + case HA_ERR_RECORD_DELETED: + goto restart_rnd_next; + case HA_ERR_END_OF_FILE: if (++restart_count < 2) table->file->ha_rnd_init(1); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 84eb5f5ba64..c6fa5366f46 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6128,6 +6128,12 @@ ER_LOAD_DATA_INVALID_COLUMN ER_LOG_PURGE_NO_FILE eng "Being purged log %s was not found" +ER_XA_RBTIMEOUT XA106 + eng "XA_RBTIMEOUT: Transaction branch was rolled back: took too long" + +ER_XA_RBDEADLOCK XA102 + eng "XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected" + ER_NEED_REPREPARE eng "Prepared statement needs to be re-prepared" diff --git a/sql/sql_class.h b/sql/sql_class.h index 7696882bbcc..f5cf31d1030 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -739,7 +739,7 @@ struct st_savepoint { Ha_trx_info *ha_list; }; -enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED}; +enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY}; extern const char *xa_state_names[]; typedef struct st_xid_state { @@ -747,6 +747,8 @@ typedef struct st_xid_state { XID xid; // transaction identifier enum xa_states xa_state; // used by external XA only bool in_thd; + /* Error reported by the Resource Manager (RM) to the Transaction Manager. */ + uint rm_error; } XID_STATE; extern pthread_mutex_t LOCK_xid_cache; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b083d93a801..704c16cfdec 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -83,9 +83,57 @@ const LEX_STRING command_name[]={ }; const char *xa_state_names[]={ - "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED" + "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED", "ROLLBACK ONLY" }; +/** + Mark a XA transaction as rollback-only if the RM unilaterally + rolled back the transaction branch. + + @note If a rollback was requested by the RM, this function sets + the appropriate rollback error code and transits the state + to XA_ROLLBACK_ONLY. + + @return TRUE if transaction was rolled back or if the transaction + state is XA_ROLLBACK_ONLY. FALSE otherwise. +*/ +static bool xa_trans_rolled_back(XID_STATE *xid_state) +{ + if (xid_state->rm_error) + { + switch (xid_state->rm_error) { + case ER_LOCK_WAIT_TIMEOUT: + my_error(ER_XA_RBTIMEOUT, MYF(0)); + break; + case ER_LOCK_DEADLOCK: + my_error(ER_XA_RBDEADLOCK, MYF(0)); + break; + default: + my_error(ER_XA_RBROLLBACK, MYF(0)); + } + xid_state->xa_state= XA_ROLLBACK_ONLY; + } + + return (xid_state->xa_state == XA_ROLLBACK_ONLY); +} + +/** + Rollback work done on behalf of at ransaction branch. +*/ +static bool xa_trans_rollback(THD *thd) +{ + bool status= test(ha_rollback(thd)); + + thd->options&= ~(ulong) OPTION_BEGIN; + thd->transaction.all.modified_non_trans_table= FALSE; + thd->server_status&= ~SERVER_STATUS_IN_TRANS; + xid_cache_delete(&thd->transaction.xid_state); + thd->transaction.xid_state.xa_state= XA_NOTR; + thd->transaction.xid_state.rm_error= 0; + + return status; +} + static void unlock_locked_tables(THD *thd) { if (thd->locked_tables) @@ -4505,6 +4553,7 @@ create_sp_error: } DBUG_ASSERT(thd->transaction.xid_state.xid.is_null()); thd->transaction.xid_state.xa_state=XA_ACTIVE; + thd->transaction.xid_state.rm_error= 0; thd->transaction.xid_state.xid.set(thd->lex->xid); xid_cache_insert(&thd->transaction.xid_state); thd->transaction.all.modified_non_trans_table= FALSE; @@ -4530,6 +4579,8 @@ create_sp_error: my_error(ER_XAER_NOTA, MYF(0)); break; } + if (xa_trans_rolled_back(&thd->transaction.xid_state)) + break; thd->transaction.xid_state.xa_state=XA_IDLE; my_ok(thd); break; @@ -4561,6 +4612,12 @@ create_sp_error: XID_STATE *xs=xid_cache_search(thd->lex->xid); if (!xs || xs->in_thd) my_error(ER_XAER_NOTA, MYF(0)); + else if (xa_trans_rolled_back(xs)) + { + ha_commit_or_rollback_by_xid(thd->lex->xid, 0); + xid_cache_delete(xs); + break; + } else { ha_commit_or_rollback_by_xid(thd->lex->xid, 1); @@ -4569,6 +4626,11 @@ create_sp_error: } break; } + if (xa_trans_rolled_back(&thd->transaction.xid_state)) + { + xa_trans_rollback(thd); + break; + } if (thd->transaction.xid_state.xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE) { @@ -4615,28 +4677,26 @@ create_sp_error: my_error(ER_XAER_NOTA, MYF(0)); else { + bool ok= !xa_trans_rolled_back(xs); ha_commit_or_rollback_by_xid(thd->lex->xid, 0); xid_cache_delete(xs); - my_ok(thd); + if (ok) + my_ok(thd); } break; } if (thd->transaction.xid_state.xa_state != XA_IDLE && - thd->transaction.xid_state.xa_state != XA_PREPARED) + thd->transaction.xid_state.xa_state != XA_PREPARED && + thd->transaction.xid_state.xa_state != XA_ROLLBACK_ONLY) { my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[thd->transaction.xid_state.xa_state]); break; } - if (ha_rollback(thd)) + if (xa_trans_rollback(thd)) my_error(ER_XAER_RMERR, MYF(0)); else my_ok(thd); - thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); - thd->transaction.all.modified_non_trans_table= FALSE; - thd->server_status&= ~SERVER_STATUS_IN_TRANS; - xid_cache_delete(&thd->transaction.xid_state); - thd->transaction.xid_state.xa_state=XA_NOTR; break; case SQLCOM_XA_RECOVER: res= mysql_xa_recover(thd); diff --git a/zlib/gzio.c b/zlib/gzio.c index 7e90f4928fc..ed4e77ca7e9 100644 --- a/zlib/gzio.c +++ b/zlib/gzio.c @@ -7,6 +7,11 @@ /* @(#) $Id$ */ +/* Need to be included "early" to control other headers */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + #include <stdio.h> #include "zutil.h" |