List:Commits« Previous MessageNext Message »
From:Mats Kindahl Date:November 3 2008 6:51pm
Subject:bzr commit into mysql-5.1 branch (mats:2775)
View as plain text  
#At file:///home/bzr/bugs/b40360-5.1/

 2775 Mats Kindahl	2008-11-03 [merge]
      Merging with 5.1-5.1.29-rc
modified:
  mysql-test/extra/rpl_tests/rpl_row_basic.test
  mysql-test/r/alter_table.result
  mysql-test/r/binlog_format_basic.result
  mysql-test/r/xa.result
  mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result
  mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result
  mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result
  mysql-test/t/alter_table.test
  mysql-test/t/binlog_format_basic.test
  mysql-test/t/xa.test
  sql/field.cc
  sql/field.h
  sql/handler.cc
  sql/log_event.cc
  sql/log_event_old.cc
  sql/share/errmsg.txt
  sql/sql_class.h
  sql/sql_parse.cc
  zlib/gzio.c

=== modified file 'mysql-test/extra/rpl_tests/rpl_row_basic.test'
--- a/mysql-test/extra/rpl_tests/rpl_row_basic.test	2008-09-03 20:04:07 +0000
+++ b/mysql-test/extra/rpl_tests/rpl_row_basic.test	2008-10-29 20:37:51 +0000
@@ -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;

=== modified file 'mysql-test/r/alter_table.result'
--- a/mysql-test/r/alter_table.result	2008-06-17 14:12:21 +0000
+++ b/mysql-test/r/alter_table.result	2008-10-24 08:00:03 +0000
@@ -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

=== modified file 'mysql-test/r/binlog_format_basic.result'
--- a/mysql-test/r/binlog_format_basic.result	2008-04-10 13:14:28 +0000
+++ b/mysql-test/r/binlog_format_basic.result	2008-10-22 14:00:45 +0000
@@ -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)

=== modified file 'mysql-test/r/xa.result'
--- a/mysql-test/r/xa.result	2005-10-05 17:58:16 +0000
+++ b/mysql-test/r/xa.result	2008-10-21 21:02:26 +0000
@@ -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

=== modified file 'mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result'
--- a/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result	2008-09-03 20:04:07 +0000
+++ b/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result	2008-10-20 18:50:08 +0000
@@ -527,3 +527,60 @@ ERROR 23000: Duplicate entry '10' for ke
 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;

=== modified file 'mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result'
--- a/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result	2008-09-03 20:04:07 +0000
+++ b/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result	2008-10-20 18:50:08 +0000
@@ -527,3 +527,60 @@ ERROR 23000: Duplicate entry '10' for ke
 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;

=== modified file 'mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result'
--- a/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result	2008-09-03 20:52:54 +0000
+++ b/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result	2008-10-20 18:50:08 +0000
@@ -527,3 +527,60 @@ ERROR 23000: Duplicate entry '10' for ke
 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;

=== modified file 'mysql-test/t/alter_table.test'
--- a/mysql-test/t/alter_table.test	2008-06-17 14:12:21 +0000
+++ b/mysql-test/t/alter_table.test	2008-10-24 08:00:03 +0000
@@ -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

=== modified file 'mysql-test/t/binlog_format_basic.test'
--- a/mysql-test/t/binlog_format_basic.test	2008-04-10 13:14:28 +0000
+++ b/mysql-test/t/binlog_format_basic.test	2008-10-22 14:00:45 +0000
@@ -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                                       #

=== modified file 'mysql-test/t/xa.test'
--- a/mysql-test/t/xa.test	2007-02-26 10:49:24 +0000
+++ b/mysql-test/t/xa.test	2008-10-21 21:02:26 +0000
@@ -74,3 +74,48 @@ xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
 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

=== modified file 'sql/field.cc'
--- a/sql/field.cc	2008-09-20 14:52:34 +0000
+++ b/sql/field.cc	2008-10-24 08:00:03 +0000
@@ -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

=== modified file 'sql/field.h'
--- a/sql/field.h	2008-09-20 14:52:34 +0000
+++ b/sql/field.h	2008-10-24 08:00:03 +0000
@@ -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);
 };
 
 

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	2008-10-08 13:52:57 +0000
+++ b/sql/handler.cc	2008-10-31 10:02:06 +0000
@@ -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_compatibili
 {
   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_compatibili
           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;
       }  
     }  

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2008-10-07 13:21:17 +0000
+++ b/sql/log_event.cc	2008-10-20 18:50:08 +0000
@@ -7203,6 +7203,9 @@ int Rows_log_event::do_apply_event(Relay
 
       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
 
         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
       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
        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_lo
       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_lo
                                              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
     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
                                             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
           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
     /* 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
       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:

=== modified file 'sql/log_event_old.cc'
--- a/sql/log_event_old.cc	2008-05-12 17:50:53 +0000
+++ b/sql/log_event_old.cc	2008-10-20 18:50:08 +0000
@@ -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 *tab
           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 *tab
     /* 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 *tab
 
       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(R
 
       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 Rela
       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 Rela
                                              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 R
     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 R
                                             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 R
           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 R
     /* 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);

=== modified file 'sql/share/errmsg.txt'
--- a/sql/share/errmsg.txt	2008-08-06 14:20:41 +0000
+++ b/sql/share/errmsg.txt	2008-10-21 20:28:01 +0000
@@ -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"
 

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2008-10-09 10:39:42 +0000
+++ b/sql/sql_class.h	2008-10-21 20:28:01 +0000
@@ -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;

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2008-10-08 11:37:13 +0000
+++ b/sql/sql_parse.cc	2008-10-21 20:28:01 +0000
@@ -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);

=== modified file 'zlib/gzio.c'
--- a/zlib/gzio.c	2008-08-13 16:44:05 +0000
+++ b/zlib/gzio.c	2008-10-13 12:23:39 +0000
@@ -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"

Thread
bzr commit into mysql-5.1 branch (mats:2775) Mats Kindahl3 Nov