List:Commits« Previous MessageNext Message »
From:Georgi Kodinov Date:October 5 2010 8:12am
Subject:bzr commit into mysql-5.1-bugteam branch (Georgi.Kodinov:3519)
View as plain text  
#At file:///home/kgeorge/mysql/work/merge-5.1-bugteam/ based on revid:vasil.dimov@stripped

 3519 Georgi Kodinov	2010-10-05 [merge]
      merged mysql-5.1 into mysql-5.1-bugteam

    modified:
      configure.in
      mysql-test/collections/default.experimental
      mysql-test/r/gis.result
      mysql-test/r/join.result
      mysql-test/r/timezone2.result
      mysql-test/r/user_var.result
      mysql-test/suite/innodb/r/innodb-autoinc.result
      mysql-test/suite/innodb/r/innodb_mysql.result
      mysql-test/suite/innodb/t/innodb-autoinc.test
      mysql-test/suite/innodb/t/innodb_mysql.test
      mysql-test/suite/innodb_plugin/r/innodb-autoinc.result
      mysql-test/suite/innodb_plugin/t/innodb-autoinc.test
      mysql-test/suite/rpl/t/disabled.def
      mysql-test/t/gis.test
      mysql-test/t/join.test
      mysql-test/t/timezone2.test
      mysql-test/t/user_var.test
      sql/field.cc
      sql/item_func.cc
      sql/item_func.h
      sql/item_geofunc.h
      sql/sql_select.cc
      sql/sql_select.h
      sql/sql_string.h
      sql/tztime.cc
      storage/innobase/dict/dict0load.c
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/include/db0err.h
      storage/innobase/include/dict0dict.h
      storage/innobase/include/dict0dict.ic
      storage/innobase/include/dict0load.h
      storage/innobase/include/dict0mem.h
      storage/innobase/include/que0que.h
      storage/innobase/row/row0mysql.c
      storage/innodb_plugin/ChangeLog
      storage/innodb_plugin/btr/btr0cur.c
      storage/innodb_plugin/dict/dict0load.c
      storage/innodb_plugin/handler/ha_innodb.cc
      storage/innodb_plugin/include/btr0cur.h
      storage/innodb_plugin/include/db0err.h
      storage/innodb_plugin/include/dict0dict.h
      storage/innodb_plugin/include/dict0dict.ic
      storage/innodb_plugin/include/dict0load.h
      storage/innodb_plugin/include/dict0mem.h
      storage/innodb_plugin/include/que0que.h
      storage/innodb_plugin/row/row0merge.c
      storage/innodb_plugin/row/row0mysql.c
      storage/innodb_plugin/row/row0upd.c
=== modified file 'configure.in'
--- a/configure.in	2010-08-19 15:18:58 +0000
+++ b/configure.in	2010-09-28 08:33:22 +0000
@@ -12,7 +12,7 @@ dnl
 dnl When changing the major version number please also check the switch
 dnl statement in mysqlbinlog::check_master_version().  You may also need
 dnl to update version.c in ndb.
-AC_INIT([MySQL Server], [5.1.51], [], [mysql])
+AC_INIT([MySQL Server], [5.1.52], [], [mysql])
 
 AC_CONFIG_SRCDIR([sql/mysqld.cc])
 AC_CANONICAL_SYSTEM

=== modified file 'mysql-test/collections/default.experimental'
--- a/mysql-test/collections/default.experimental	2010-08-27 21:58:46 +0000
+++ b/mysql-test/collections/default.experimental	2010-09-07 20:16:10 +0000
@@ -45,3 +45,6 @@ parts.partition_syntax_ndb              
 parts.partition_value_ndb                # joro : NDB tests marked as experimental as agreed with bochklin
 main.mysqlhotcopy_myisam                 # horst: due to bug#54129
 main.mysqlhotcopy_archive                # horst: due to bug#54129
+main.gis-rtree                           # svoj: due to BUG#38965
+main.type_float                          # svoj: due to BUG#38965
+main.type_newdecimal                     # svoj: due to BUG#38965

=== modified file 'mysql-test/r/gis.result'
--- a/mysql-test/r/gis.result	2010-08-30 07:51:46 +0000
+++ b/mysql-test/r/gis.result	2010-09-09 09:40:17 +0000
@@ -707,10 +707,7 @@ numgeometries(b) IS NULL, numinteriorrin
 area(b) IS NULL, glength(b) IS NULL, srid(b) IS NULL, x(b) IS NULL, 
 y(b) IS NULL
 from t1;
-geometryfromtext(b) IS NULL	geometryfromwkb(b) IS NULL	astext(b) IS NULL	aswkb(b) IS NULL	geometrytype(b) IS NULL	centroid(b) IS NULL	envelope(b) IS NULL	startpoint(b) IS NULL	endpoint(b) IS NULL	exteriorring(b) IS NULL	pointn(b, 1) IS NULL	geometryn(b, 1) IS NULL	interiorringn(b, 1) IS NULL	multipoint(b) IS NULL	isempty(b) IS NULL	issimple(b) IS NULL	isclosed(b) IS NULL	dimension(b) IS NULL	numgeometries(b) IS NULL	numinteriorrings(b) IS NULL	numpoints(b) IS NULL	area(b) IS NULL	glength(b) IS NULL	srid(b) IS NULL	x(b) IS NULL	y(b) IS NULL
-1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1
-1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1
-1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1
+ERROR 22007: Illegal non geometric '`test`.`t1`.`b`' value found during parsing
 select 
 within(b, b) IS NULL, contains(b, b) IS NULL, overlaps(b, b) IS NULL, 
 equals(b, b) IS NULL, disjoint(b, b) IS NULL, touches(b, b) IS NULL, 
@@ -725,10 +722,7 @@ point(b, b) IS NULL, linestring(b) IS NU
 multilinestring(b) IS NULL, multipolygon(b) IS NULL, 
 geometrycollection(b) IS NULL
 from t1;
-point(b, b) IS NULL	linestring(b) IS NULL	polygon(b) IS NULL	multipoint(b) IS NULL	multilinestring(b) IS NULL	multipolygon(b) IS NULL	geometrycollection(b) IS NULL
-0	1	1	1	1	1	1
-1	1	1	1	1	1	1
-0	1	1	1	1	1	1
+ERROR 22007: Illegal non geometric '`test`.`t1`.`b`' value found during parsing
 drop table t1;
 CREATE TABLE t1(a POINT) ENGINE=MyISAM;
 INSERT INTO t1 VALUES (NULL);
@@ -1010,53 +1004,9 @@ f5	datetime	YES		NULL	
 drop view v1;
 drop table t1;
 SELECT MultiPoint(12345,'');
-MultiPoint(12345,'')
-NULL
-SELECT MultiPoint(123451,'');
-MultiPoint(123451,'')
-NULL
-SELECT MultiPoint(1234512,'');
-MultiPoint(1234512,'')
-NULL
-SELECT MultiPoint(12345123,'');
-MultiPoint(12345123,'')
-NULL
-SELECT MultiLineString(12345,'');
-MultiLineString(12345,'')
-NULL
-SELECT MultiLineString(123451,'');
-MultiLineString(123451,'')
-NULL
-SELECT MultiLineString(1234512,'');
-MultiLineString(1234512,'')
-NULL
-SELECT MultiLineString(12345123,'');
-MultiLineString(12345123,'')
-NULL
-SELECT LineString(12345,'');
-LineString(12345,'')
-NULL
-SELECT LineString(123451,'');
-LineString(123451,'')
-NULL
-SELECT LineString(1234512,'');
-LineString(1234512,'')
-NULL
-SELECT LineString(12345123,'');
-LineString(12345123,'')
-NULL
-SELECT Polygon(12345,'');
-Polygon(12345,'')
-NULL
-SELECT Polygon(123451,'');
-Polygon(123451,'')
-NULL
-SELECT Polygon(1234512,'');
-Polygon(1234512,'')
-NULL
-SELECT Polygon(12345123,'');
-Polygon(12345123,'')
-NULL
+ERROR 22007: Illegal non geometric '12345' value found during parsing
+SELECT 1 FROM (SELECT GREATEST(1,GEOMETRYCOLLECTION('00000','00000')) b FROM DUAL) AS d WHERE (LINESTRING(d.b));
+ERROR 22007: Illegal non geometric ''00000'' value found during parsing
 #
 # BUG#51875: crash when loading data into geometry function polyfromwkb
 #

=== modified file 'mysql-test/r/join.result'
--- a/mysql-test/r/join.result	2010-04-26 20:46:52 +0000
+++ b/mysql-test/r/join.result	2010-09-07 13:43:00 +0000
@@ -1184,4 +1184,40 @@ NULL
 NULL
 1
 DROP TABLE t1, t2, mm1;
+#
+# Bug #54468: crash after item's print() function when ordering/grouping 
+#             by subquery
+#
+CREATE TABLE t1(a INT, b INT);
+INSERT INTO t1 VALUES (), ();
+SELECT 1 FROM t1
+GROUP BY
+GREATEST(t1.a,
+(SELECT 1 FROM
+(SELECT t1.b FROM t1,t1 t2
+ORDER BY t1.a, t1.a LIMIT 1) AS d)
+);
+1
+1
+DROP TABLE t1;
+#
+# Bug #53544: Server hangs during JOIN query in stored procedure called
+#             twice in a row
+#
+CREATE TABLE t1(c INT);
+INSERT INTO t1 VALUES (1), (2);
+PREPARE stmt FROM "SELECT t2.c AS f1 FROM t1 LEFT JOIN
+                                        t1 t2 ON t1.c=t2.c RIGHT JOIN
+                                        t1 t3 ON t1.c=t3.c 
+                   GROUP BY f1;";
+EXECUTE stmt;
+f1
+1
+2
+EXECUTE stmt;
+f1
+1
+2
+DEALLOCATE PREPARE stmt;
+DROP TABLE t1;
 End of 5.1 tests

=== modified file 'mysql-test/r/timezone2.result'
--- a/mysql-test/r/timezone2.result	2009-05-15 12:57:51 +0000
+++ b/mysql-test/r/timezone2.result	2010-08-06 19:29:37 +0000
@@ -296,4 +296,16 @@ CONVERT_TZ(NOW(), 'UTC', 'Europe/Moscow'
 UPDATE t1 SET t = CONVERT_TZ(t, 'UTC', 'Europe/Moscow');
 UNLOCK TABLES;
 DROP TABLE t1;
+#
+# Bug #55424: convert_tz crashes when fed invalid data
+#
+CREATE TABLE t1 (a SET('x') NOT NULL);
+INSERT INTO t1 VALUES ('');
+SELECT CONVERT_TZ(1, a, 1) FROM t1;
+CONVERT_TZ(1, a, 1)
+NULL
+SELECT CONVERT_TZ(1, 1, a) FROM t1;
+CONVERT_TZ(1, 1, a)
+NULL
+DROP TABLE t1;
 End of 5.1 tests

=== modified file 'mysql-test/r/user_var.result'
--- a/mysql-test/r/user_var.result	2009-12-22 10:38:33 +0000
+++ b/mysql-test/r/user_var.result	2010-08-13 11:18:46 +0000
@@ -430,4 +430,21 @@ CREATE TRIGGER t_after_insert AFTER INSE
 INSERT INTO t1 VALUES (1);
 INSERT INTO t1 VALUES (1);
 DROP TABLE t1;
+CREATE TABLE t1(a INT);
+INSERT INTO t1 VALUES (0),(0);
+# BUG#55615 : should not crash
+SELECT (@a:=(SELECT @a:=1 FROM t1 LIMIT 1)) AND COUNT(1) FROM t1 GROUP BY @a;
+(@a:=(SELECT @a:=1 FROM t1 LIMIT 1)) AND COUNT(1)
+1
+1
+# BUG#55564 : should not crash
+SELECT IF(
+@v:=LEAST((SELECT 1 FROM t1 t2 LEFT JOIN t1 ON (@v) GROUP BY t1.a), a),
+count(*), 1) 
+FROM t1 GROUP BY a LIMIT 1;
+IF(
+@v:=LEAST((SELECT 1 FROM t1 t2 LEFT JOIN t1 ON (@v) GROUP BY t1.a), a),
+count(*), 1)
+1
+DROP TABLE t1;
 End of 5.1 tests

=== modified file 'mysql-test/suite/innodb/r/innodb-autoinc.result'
--- a/mysql-test/suite/innodb/r/innodb-autoinc.result	2010-04-12 11:56:24 +0000
+++ b/mysql-test/suite/innodb/r/innodb-autoinc.result	2010-08-05 09:24:34 +0000
@@ -1244,3 +1244,16 @@ t1	CREATE TABLE `t1` (
   PRIMARY KEY (`c1`)
 ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
 DROP TABLE t1;
+DROP TABLE IF EXISTS t1;
+Warnings:
+Note	1051	Unknown table 't1'
+CREATE TABLE t1(c1 BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (18446744073709551615);
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `c1` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=18446744073709551615 DEFAULT CHARSET=latin1
+DROP TABLE t1;

=== modified file 'mysql-test/suite/innodb/r/innodb_mysql.result'
--- a/mysql-test/suite/innodb/r/innodb_mysql.result	2010-09-01 17:38:34 +0000
+++ b/mysql-test/suite/innodb/r/innodb_mysql.result	2010-10-05 08:11:56 +0000
@@ -2508,6 +2508,18 @@ ALTER TABLE t1 COMMENT 'test';
 UNLOCK TABLES;
 DROP TABLE t1;
 #
+# Bug#55826: create table .. select crashes with when KILL_BAD_DATA 
+#  is returned
+#
+CREATE TABLE t1(a INT) ENGINE=innodb;
+INSERT INTO t1 VALUES (0);
+SET SQL_MODE='STRICT_ALL_TABLES';
+CREATE TABLE t2 
+SELECT LEAST((SELECT '' FROM t1),NOW()) FROM `t1`;
+ERROR 22007: Incorrect datetime value: '' for column 'NOW()' at row 1
+DROP TABLE t1;
+SET SQL_MODE=DEFAULT;
+#
 # Bug#55580: segfault in read_view_sees_trx_id
 #
 CREATE TABLE t1 (a INT) ENGINE=Innodb;

=== modified file 'mysql-test/suite/innodb/t/innodb-autoinc.test'
--- a/mysql-test/suite/innodb/t/innodb-autoinc.test	2010-04-12 11:56:24 +0000
+++ b/mysql-test/suite/innodb/t/innodb-autoinc.test	2010-08-05 09:24:34 +0000
@@ -662,3 +662,15 @@ INSERT INTO  t1 VALUES (1), (2), (-68511
 SELECT * FROM t1;
 SHOW CREATE TABLE t1;
 DROP TABLE t1;
+
+##
+# 55277: Failing assertion: auto_inc > 0
+#
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1(c1 BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (18446744073709551615);
+# Restart the server
+-- source include/restart_mysqld.inc
+SHOW CREATE TABLE t1;
+DROP TABLE t1;

=== modified file 'mysql-test/suite/innodb/t/innodb_mysql.test'
--- a/mysql-test/suite/innodb/t/innodb_mysql.test	2010-10-03 17:37:58 +0000
+++ b/mysql-test/suite/innodb/t/innodb_mysql.test	2010-10-05 08:11:56 +0000
@@ -748,9 +748,23 @@ DROP TABLE t1;
 
 
 --echo #
---echo # Bug#55580: segfault in read_view_sees_trx_id
+--echo # Bug#55826: create table .. select crashes with when KILL_BAD_DATA 
+--echo #  is returned
 --echo #
+CREATE TABLE t1(a INT) ENGINE=innodb;
+INSERT INTO t1 VALUES (0);
+SET SQL_MODE='STRICT_ALL_TABLES';
+--error ER_TRUNCATED_WRONG_VALUE
+CREATE TABLE t2 
+  SELECT LEAST((SELECT '' FROM t1),NOW()) FROM `t1`;
+DROP TABLE t1;  
+SET SQL_MODE=DEFAULT;
+
+
 
+--echo #
+--echo # Bug#55580: segfault in read_view_sees_trx_id
+--echo #
 CREATE TABLE t1 (a INT) ENGINE=Innodb;
 CREATE TABLE t2 (a INT) ENGINE=Innodb;
 INSERT INTO t1 VALUES (1),(2);

=== modified file 'mysql-test/suite/innodb_plugin/r/innodb-autoinc.result'
--- a/mysql-test/suite/innodb_plugin/r/innodb-autoinc.result	2010-04-09 12:56:51 +0000
+++ b/mysql-test/suite/innodb_plugin/r/innodb-autoinc.result	2010-08-16 00:12:22 +0000
@@ -1244,3 +1244,16 @@ t1	CREATE TABLE `t1` (
   PRIMARY KEY (`c1`)
 ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
 DROP TABLE t1;
+DROP TABLE IF EXISTS t1;
+Warnings:
+Note	1051	Unknown table 't1'
+CREATE TABLE t1(c1 BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (18446744073709551615);
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `c1` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=18446744073709551615 DEFAULT CHARSET=latin1
+DROP TABLE t1;

=== modified file 'mysql-test/suite/innodb_plugin/t/innodb-autoinc.test'
--- a/mysql-test/suite/innodb_plugin/t/innodb-autoinc.test	2010-08-06 09:35:17 +0000
+++ b/mysql-test/suite/innodb_plugin/t/innodb-autoinc.test	2010-08-20 12:08:01 +0000
@@ -665,6 +665,18 @@ SELECT * FROM t1;
 SHOW CREATE TABLE t1;
 DROP TABLE t1;
 
+##
+# 55277: Failing assertion: auto_inc > 0
+#
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1(c1 BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (18446744073709551615);
+# Restart the server
+-- source include/restart_mysqld.inc
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
 #
 # restore environment to the state it was before this test execution
 #

=== modified file 'mysql-test/suite/rpl/t/disabled.def'
--- a/mysql-test/suite/rpl/t/disabled.def	2010-02-27 15:08:53 +0000
+++ b/mysql-test/suite/rpl/t/disabled.def	2010-09-10 10:49:57 +0000
@@ -11,3 +11,4 @@
 ##############################################################################
 
 rpl_row_create_table : Bug#51574 Feb 27 2010 andrei failed different way than earlier with bug#45576
+rpl_log_pos : BUG#55675 Sep 10 2010 27 2010 alfranio rpl.rpl_log_pos fails sporadically with error binlog truncated in the middle

=== modified file 'mysql-test/t/gis.test'
--- a/mysql-test/t/gis.test	2010-08-30 07:51:46 +0000
+++ b/mysql-test/t/gis.test	2010-09-07 11:34:18 +0000
@@ -401,6 +401,7 @@ create table t1 (a int, b blob);
 insert into t1 values (1, ''), (2, NULL), (3, '1');
 select * from t1;
 
+--error ER_ILLEGAL_VALUE_FOR_TYPE
 select
   geometryfromtext(b) IS NULL, geometryfromwkb(b) IS NULL, astext(b) IS NULL, 
   aswkb(b) IS NULL, geometrytype(b) IS NULL, centroid(b) IS NULL,
@@ -419,6 +420,7 @@ select 
   intersects(b, b) IS NULL, crosses(b, b) IS NULL
 from t1;
 
+--error ER_ILLEGAL_VALUE_FOR_TYPE
 select 
   point(b, b) IS NULL, linestring(b) IS NULL, polygon(b) IS NULL, multipoint(b) IS NULL, 
   multilinestring(b) IS NULL, multipolygon(b) IS NULL, 
@@ -702,25 +704,35 @@ drop table t1;
 # Bug#44684: valgrind reports invalid reads in 
 # Item_func_spatial_collection::val_str
 #
+--error ER_ILLEGAL_VALUE_FOR_TYPE
 SELECT MultiPoint(12345,'');
-SELECT MultiPoint(123451,'');
-SELECT MultiPoint(1234512,'');
-SELECT MultiPoint(12345123,'');
-
-SELECT MultiLineString(12345,'');
-SELECT MultiLineString(123451,'');
-SELECT MultiLineString(1234512,'');
-SELECT MultiLineString(12345123,'');
-
-SELECT LineString(12345,'');
-SELECT LineString(123451,'');
-SELECT LineString(1234512,'');
-SELECT LineString(12345123,'');
-
-SELECT Polygon(12345,'');
-SELECT Polygon(123451,'');
-SELECT Polygon(1234512,'');
-SELECT Polygon(12345123,'');
+#SELECT MultiPoint(123451,'');
+#SELECT MultiPoint(1234512,'');
+#SELECT MultiPoint(12345123,'');
+
+--error ER_ILLEGAL_VALUE_FOR_TYPE
+#SELECT MultiLineString(12345,'');
+#SELECT MultiLineString(123451,'');
+#SELECT MultiLineString(1234512,'');
+#SELECT MultiLineString(12345123,'');
+
+--error ER_ILLEGAL_VALUE_FOR_TYPE
+#SELECT LineString(12345,'');
+#SELECT LineString(123451,'');
+#SELECT LineString(1234512,'');
+#SELECT LineString(12345123,'');
+
+--error ER_ILLEGAL_VALUE_FOR_TYPE
+#SELECT Polygon(12345,'');
+#SELECT Polygon(123451,'');
+#SELECT Polygon(1234512,'');
+#SELECT Polygon(12345123,'');
+
+#
+# Bug55531 crash with conversions of geometry types / strings
+#
+--error ER_ILLEGAL_VALUE_FOR_TYPE
+SELECT 1 FROM (SELECT GREATEST(1,GEOMETRYCOLLECTION('00000','00000')) b FROM DUAL) AS d WHERE (LINESTRING(d.b));
 
 
 --echo #

=== modified file 'mysql-test/t/join.test'
--- a/mysql-test/t/join.test	2010-04-26 20:46:52 +0000
+++ b/mysql-test/t/join.test	2010-09-07 13:43:00 +0000
@@ -851,4 +851,74 @@ ENGINE=MERGE  UNION=(t1,t2);
 SELECT t1.a FROM mm1,t1;
 DROP TABLE t1, t2, mm1;
 
+#--echo #
+#--echo # Bug #55568: user variable assignments crash server when used within
+#--echo #             query
+#--echo #
+#
+#
+# This test case is invalidated because of fix of bug 55531
+# The reason is that {1} is not a valid geometric collection.
+#
+#CREATE TABLE t1 (a INT);
+
+#INSERT INTO t1 VALUES (0), (1);
+
+#let $i=2;
+#while ($i)
+#{
+#  SELECT MULTIPOINT(
+#    1,
+#    (
+#      SELECT MULTIPOINT(
+#        MULTIPOINT(
+#          1,
+#          (SELECT COUNT(*) FROM (SELECT 1 FROM t1 GROUP BY a,a) d)
+#        )
+#      ) FROM t1
+#    )
+#  ) != COUNT(*) q FROM t1 GROUP BY a;
+#  dec $i;
+#}
+#
+#DROP TABLE t1;
+
+--echo #
+--echo # Bug #54468: crash after item's print() function when ordering/grouping 
+--echo #             by subquery
+--echo #
+
+CREATE TABLE t1(a INT, b INT);
+INSERT INTO t1 VALUES (), ();
+
+SELECT 1 FROM t1
+GROUP BY
+GREATEST(t1.a,
+         (SELECT 1 FROM
+          (SELECT t1.b FROM t1,t1 t2
+           ORDER BY t1.a, t1.a LIMIT 1) AS d)
+        );
+
+DROP TABLE t1;
+
+--echo #
+--echo # Bug #53544: Server hangs during JOIN query in stored procedure called
+--echo #             twice in a row
+--echo #
+
+CREATE TABLE t1(c INT);
+
+INSERT INTO t1 VALUES (1), (2);
+
+PREPARE stmt FROM "SELECT t2.c AS f1 FROM t1 LEFT JOIN
+                                        t1 t2 ON t1.c=t2.c RIGHT JOIN
+                                        t1 t3 ON t1.c=t3.c 
+                   GROUP BY f1;";
+
+EXECUTE stmt;
+EXECUTE stmt;
+
+DEALLOCATE PREPARE stmt;
+DROP TABLE t1;
+
 --echo End of 5.1 tests

=== modified file 'mysql-test/t/timezone2.test'
--- a/mysql-test/t/timezone2.test	2008-07-10 16:09:39 +0000
+++ b/mysql-test/t/timezone2.test	2010-08-06 19:29:37 +0000
@@ -273,5 +273,14 @@ UNLOCK TABLES;
 
 DROP TABLE t1;
 
+--echo #
+--echo # Bug #55424: convert_tz crashes when fed invalid data
+--echo #
+
+CREATE TABLE t1 (a SET('x') NOT NULL);
+INSERT INTO t1 VALUES ('');
+SELECT CONVERT_TZ(1, a, 1) FROM t1;
+SELECT CONVERT_TZ(1, 1, a) FROM t1;
+DROP TABLE t1;
 
 --echo End of 5.1 tests

=== modified file 'mysql-test/t/user_var.test'
--- a/mysql-test/t/user_var.test	2009-12-22 10:38:33 +0000
+++ b/mysql-test/t/user_var.test	2010-08-13 11:18:46 +0000
@@ -328,4 +328,22 @@ INSERT INTO t1 VALUES (1);
 INSERT INTO t1 VALUES (1);
 DROP TABLE t1;
 
+#
+# Bug #55615: debug assertion after using variable in assignment and
+# referred to
+# Bug #55564: crash with user variables, assignments, joins...
+#
+
+CREATE TABLE t1(a INT);
+INSERT INTO t1 VALUES (0),(0);
+--echo # BUG#55615 : should not crash
+SELECT (@a:=(SELECT @a:=1 FROM t1 LIMIT 1)) AND COUNT(1) FROM t1 GROUP BY @a;
+--echo # BUG#55564 : should not crash
+SELECT IF(
+  @v:=LEAST((SELECT 1 FROM t1 t2 LEFT JOIN t1 ON (@v) GROUP BY t1.a), a),
+  count(*), 1) 
+FROM t1 GROUP BY a LIMIT 1;
+
+DROP TABLE t1;
+
 --echo End of 5.1 tests

=== modified file 'sql/field.cc'
--- a/sql/field.cc	2010-07-20 18:07:36 +0000
+++ b/sql/field.cc	2010-09-07 09:37:46 +0000
@@ -1535,7 +1535,7 @@ void Field::make_field(Send_field *field
   }
   else
     field->org_table_name= field->db_name= "";
-  if (orig_table)
+  if (orig_table && orig_table->alias)
   {
     field->table_name= orig_table->alias;
     field->org_col_name= field_name;
@@ -4561,7 +4561,7 @@ String *Field_double::val_str(String *va
 #endif
     doubleget(nr,ptr);
 
-  uint to_length=max(field_length, DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE);
+  uint to_length= DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE;
   val_buffer->alloc(to_length);
   char *to=(char*) val_buffer->ptr();
 

=== modified file 'sql/item_func.cc'
--- a/sql/item_func.cc	2010-08-16 13:43:21 +0000
+++ b/sql/item_func.cc	2010-10-05 08:11:56 +0000
@@ -2263,7 +2263,7 @@ void Item_func_min_max::fix_length_and_d
     stored to the value pointer, if latter is provided.
 
   RETURN
-   0	If one of arguments is NULL
+   0	If one of arguments is NULL or there was a execution error
    #	index of the least/greatest argument
 */
 
@@ -2277,6 +2277,14 @@ uint Item_func_min_max::cmp_datetimes(ul
     Item **arg= args + i;
     bool is_null;
     longlong res= get_datetime_value(thd, &arg, 0, datetime_item, &is_null);
+
+    /* Check if we need to stop (because of error or KILL)  and stop the loop */
+    if (thd->is_error())
+    {
+      null_value= 1;
+      return 0;
+    }
+
     if ((null_value= args[i]->null_value))
       return 0;
     if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0)
@@ -2305,6 +2313,12 @@ String *Item_func_min_max::val_str(Strin
     if (null_value)
       return 0;
     str_res= args[min_max_idx]->val_str(str);
+    if (args[min_max_idx]->null_value)
+    {
+      // check if the call to val_str() above returns a NULL value
+      null_value= 1;
+      return NULL;
+    }
     str_res->set_charset(collation.collation);
     return str_res;
   }
@@ -4263,6 +4277,14 @@ longlong Item_func_set_user_var::val_int
   return entry->val_int(&null_value);
 }
 
+bool Item_func_set_user_var::val_bool_result()
+{
+  DBUG_ASSERT(fixed == 1);
+  check(TRUE);
+  update();					// Store expression
+  return entry->val_int(&null_value) != 0;
+}
+
 String *Item_func_set_user_var::str_result(String *str)
 {
   DBUG_ASSERT(fixed == 1);

=== modified file 'sql/item_func.h'
--- a/sql/item_func.h	2010-01-13 10:28:42 +0000
+++ b/sql/item_func.h	2010-08-13 11:18:46 +0000
@@ -1353,6 +1353,7 @@ public:
   my_decimal *val_decimal(my_decimal *);
   double val_result();
   longlong val_int_result();
+  bool val_bool_result();
   String *str_result(String *str);
   my_decimal *val_decimal_result(my_decimal *);
   bool is_null_result();

=== modified file 'sql/item_geofunc.h'
--- a/sql/item_geofunc.h	2008-02-22 10:30:33 +0000
+++ b/sql/item_geofunc.h	2010-09-09 09:40:17 +0000
@@ -175,6 +175,21 @@ public:
     item_type=it;
   }
   String *val_str(String *);
+  void fix_length_and_dec()
+  {
+    for (unsigned int i= 0; i < arg_count; ++i)
+    {
+      if (args[i]->fixed && args[i]->field_type() != MYSQL_TYPE_GEOMETRY)
+      {
+        String str;
+        args[i]->print(&str, QT_ORDINARY);
+        str.append('\0');
+        my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "non geometric",
+                 str.ptr());
+      }
+    }
+  }
+ 
   const char *func_name() const { return "multipoint"; }
 };
 

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2010-09-13 14:07:50 +0000
+++ b/sql/sql_select.cc	2010-10-05 08:11:56 +0000
@@ -2387,13 +2387,8 @@ JOIN::destroy()
 
   cleanup(1);
  /* Cleanup items referencing temporary table columns */
-  if (!tmp_all_fields3.is_empty())
-  {
-    List_iterator_fast<Item> it(tmp_all_fields3);
-    Item *item;
-    while ((item= it++))
-      item->cleanup();
-  }
+  cleanup_item_list(tmp_all_fields1);
+  cleanup_item_list(tmp_all_fields3);
   if (exec_tmp_table1)
     free_tmp_table(thd, exec_tmp_table1);
   if (exec_tmp_table2)
@@ -2404,6 +2399,19 @@ JOIN::destroy()
   DBUG_RETURN(error);
 }
 
+
+void JOIN::cleanup_item_list(List<Item> &items) const
+{
+  if (!items.is_empty())
+  {
+    List_iterator_fast<Item> it(items);
+    Item *item;
+    while ((item= it++))
+      item->cleanup();
+  }
+}
+
+
 /**
   An entry point to single-unit select (a select without UNION).
 
@@ -8886,10 +8894,10 @@ simplify_joins(JOIN *join, List<TABLE_LI
     
   /* Flatten nested joins that can be flattened. */
   TABLE_LIST *right_neighbor= NULL;
-  bool fix_name_res= FALSE;
   li.rewind();
   while ((table= li++))
   {
+    bool fix_name_res= FALSE;
     nested_join= table->nested_join;
     if (nested_join && !table->on_expr)
     {

=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h	2010-08-13 08:07:39 +0000
+++ b/sql/sql_select.h	2010-08-24 10:44:15 +0000
@@ -577,6 +577,7 @@ private:
   */
   bool implicit_grouping; 
   bool make_simple_join(JOIN *join, TABLE *tmp_table);
+  void cleanup_item_list(List<Item> &items) const;
 };
 
 

=== modified file 'sql/sql_string.h'
--- a/sql/sql_string.h	2009-07-31 17:14:52 +0000
+++ b/sql/sql_string.h	2010-08-06 19:29:37 +0000
@@ -97,7 +97,7 @@ public:
   inline uint32 alloced_length() const { return Alloced_length;}
   inline char& operator [] (uint32 i) const { return Ptr[i]; }
   inline void length(uint32 len) { str_length=len ; }
-  inline bool is_empty() { return (str_length == 0); }
+  inline bool is_empty() const { return (str_length == 0); }
   inline void mark_as_const() { Alloced_length= 0;}
   inline const char *ptr() const { return Ptr; }
   inline char *c_ptr()

=== modified file 'sql/tztime.cc'
--- a/sql/tztime.cc	2009-06-17 14:56:44 +0000
+++ b/sql/tztime.cc	2010-08-06 19:29:37 +0000
@@ -2259,7 +2259,7 @@ my_tz_find(THD *thd, const String *name)
   DBUG_PRINT("enter", ("time zone name='%s'",
                        name ? ((String *)name)->c_ptr_safe() : "NULL"));
 
-  if (!name)
+  if (!name || name->is_empty())
     DBUG_RETURN(0);
 
   VOID(pthread_mutex_lock(&tz_LOCK));

=== modified file 'storage/innobase/dict/dict0load.c'
--- a/storage/innobase/dict/dict0load.c	2010-06-29 02:41:37 +0000
+++ b/storage/innobase/dict/dict0load.c	2010-08-04 10:11:33 +0000
@@ -864,16 +864,27 @@ err_exit:
 
 	err = dict_load_indexes(table, heap);
 
+	/* Initialize table foreign_child value. Its value could be
+	changed when dict_load_foreigns() is called below */
+	table->fk_max_recusive_level = 0;
+
 	/* If the force recovery flag is set, we open the table irrespective
 	of the error condition, since the user may want to dump data from the
 	clustered index. However we load the foreign key information only if
 	all indexes were loaded. */
 	if (err == DB_SUCCESS) {
-		err = dict_load_foreigns(table->name, TRUE);
+		err = dict_load_foreigns(table->name, TRUE, TRUE);
+
+		if (err != DB_SUCCESS) {
+			dict_table_remove_from_cache(table);
+			table = NULL;
+		}
 	} else if (!srv_force_recovery) {
 		dict_table_remove_from_cache(table);
 		table = NULL;
 	}
+
+	table->fk_max_recusive_level = 0;
 #if 0
 	if (err != DB_SUCCESS && table != NULL) {
 
@@ -1095,8 +1106,12 @@ dict_load_foreign(
 				/* out: DB_SUCCESS or error code */
 	const char*	id,	/* in: foreign constraint id as a
 				null-terminated string */
-	ibool		check_charsets)
+	ibool		check_charsets,
 				/* in: TRUE=check charset compatibility */
+	ibool		check_recursive)
+				/* in: Whether to record the foreign table
+				parent count to avoid unlimited recursive
+				load of chained foreign tables */
 {
 	dict_foreign_t*	foreign;
 	dict_table_t*	sys_foreign;
@@ -1110,6 +1125,8 @@ dict_load_foreign(
 	ulint		len;
 	ulint		n_fields_and_type;
 	mtr_t		mtr;
+	dict_table_t*	for_table;
+	dict_table_t*	ref_table;
 
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 
@@ -1194,11 +1211,54 @@ dict_load_foreign(
 
 	dict_load_foreign_cols(id, foreign);
 
-	/* If the foreign table is not yet in the dictionary cache, we
-	have to load it so that we are able to make type comparisons
-	in the next function call. */
+	ref_table = dict_table_check_if_in_cache_low(
+			foreign->referenced_table_name);
 
-	dict_table_get_low(foreign->foreign_table_name);
+	/* We could possibly wind up in a deep recursive calls if
+	we call dict_table_get_low() again here if there
+	is a chain of tables concatenated together with
+	foreign constraints. In such case, each table is
+	both a parent and child of the other tables, and
+	act as a "link" in such table chains.
+	To avoid such scenario, we would need to check the
+	number of ancesters the current table has. If that
+	exceeds DICT_FK_MAX_CHAIN_LEN, we will stop loading
+	the child table.
+	Foreign constraints are loaded in a Breath First fashion,
+	that is, the index on FOR_NAME is scanned first, and then
+	index on REF_NAME. So foreign constrains in which
+	current table is a child (foreign table) are loaded first,
+	and then those constraints where current table is a
+	parent (referenced) table.
+	Thus we could check the parent (ref_table) table's
+	reference count (fk_max_recusive_level) to know how deep the
+	recursive call is. If the parent table (ref_table) is already
+	loaded, and its fk_max_recusive_level is larger than
+	DICT_FK_MAX_CHAIN_LEN, we will stop the recursive loading
+	by skipping loading the child table. It will not affect foreign
+	constraint check for DMLs since child table will be loaded
+	at that time for the constraint check. */
+	if (!ref_table
+	    || ref_table->fk_max_recusive_level < DICT_FK_MAX_RECURSIVE_LOAD) {
+
+		/* If the foreign table is not yet in the dictionary cache, we
+		have to load it so that we are able to make type comparisons
+		in the next function call. */
+
+		for_table = dict_table_get_low(foreign->foreign_table_name);
+
+		if (for_table && ref_table && check_recursive) {
+			/* This is to record the longest chain of ancesters
+			this table has, if the parent has more ancesters
+			than this table has, record it after add 1 (for this
+			parent */
+			if (ref_table->fk_max_recusive_level
+			    >= for_table->fk_max_recusive_level) {
+				for_table->fk_max_recusive_level =
+					 ref_table->fk_max_recusive_level + 1;
+			}
+		}
+	}
 
 	/* Note that there may already be a foreign constraint object in
 	the dictionary cache for this constraint: then the following
@@ -1223,6 +1283,8 @@ dict_load_foreigns(
 /*===============*/
 					/* out: DB_SUCCESS or error code */
 	const char*	table_name,	/* in: table name */
+	ibool		check_recursive,/* in: Whether to check recursive
+					load of tables chained by FK */
 	ibool		check_charsets)	/* in: TRUE=check charset
 					compatibility */
 {
@@ -1324,7 +1386,7 @@ loop:
 
 	/* Load the foreign constraint definition to the dictionary cache */
 
-	err = dict_load_foreign(id, check_charsets);
+	err = dict_load_foreign(id, check_charsets, check_recursive);
 
 	if (err != DB_SUCCESS) {
 		btr_pcur_close(&pcur);
@@ -1352,6 +1414,11 @@ load_next_index:
 
 		mtr_start(&mtr);
 
+		/* Switch to scan index on REF_NAME, fk_max_recusive_level
+		already been updated when scanning FOR_NAME index, no need to
+		update again */
+		check_recursive = FALSE;
+
 		goto start_load;
 	}
 

=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc	2010-09-14 15:25:41 +0000
+++ b/storage/innobase/handler/ha_innodb.cc	2010-10-05 08:11:56 +0000
@@ -765,6 +765,16 @@ convert_error_code_to_mysql(
 
 		my_error(ER_QUERY_INTERRUPTED, MYF(0));
 		return(-1);
+	} else if (error == DB_FOREIGN_EXCEED_MAX_CASCADE) {
+		push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+				    HA_ERR_ROW_IS_REFERENCED,
+				    "InnoDB: Cannot delete/update "
+				    "rows with cascading foreign key "
+				    "constraints that exceed max "
+				    "depth of %d. Please "
+				    "drop extra constraints and try "
+				    "again", DICT_FK_MAX_RECURSIVE_LOAD);
+		return(-1);
     	} else {
     		return(-1);			// Unknown error
     	}
@@ -2712,12 +2722,19 @@ ha_innobase::innobase_initialize_autoinc
 		err = row_search_max_autoinc(index, col_name, &read_auto_inc);
 
 		switch (err) {
-		case DB_SUCCESS:
+		case DB_SUCCESS: {
+			ulonglong	col_max_value;
+
+			col_max_value = innobase_get_int_col_max_value(field);
+
 			/* At the this stage we do not know the increment
-			or the offset, so use a default increment of 1. */
-			auto_inc = read_auto_inc + 1;
-			break;
+			nor the offset, so use a default increment of 1. */
+
+			auto_inc = innobase_next_autoinc(
+				read_auto_inc, 1, 1, col_max_value);
 
+			break;
+		}
 		case DB_RECORD_NOT_FOUND:
 			ut_print_timestamp(stderr);
 			fprintf(stderr, "  InnoDB: MySQL and InnoDB data "
@@ -2943,8 +2960,6 @@ retry:
 	/* Init table lock structure */
 	thr_lock_data_init(&share->lock,&lock,(void*) 0);
 
-	info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
-
 	/* Only if the table has an AUTOINC column. */
 	if (prebuilt->table != NULL && table->found_next_number_field != NULL) {
 		dict_table_autoinc_lock(prebuilt->table);
@@ -2961,6 +2976,8 @@ retry:
 		dict_table_autoinc_unlock(prebuilt->table);
 	}
 
+	info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
+
 	DBUG_RETURN(0);
 }
 

=== modified file 'storage/innobase/include/db0err.h'
--- a/storage/innobase/include/db0err.h	2010-08-06 09:49:22 +0000
+++ b/storage/innobase/include/db0err.h	2010-09-02 00:43:02 +0000
@@ -73,10 +73,13 @@ Created 5/24/1996 Heikki Tuuri
 					a later version of the engine. */
 #define DB_INTERRUPTED		49	/* the query has been interrupted with
 					"KILL QUERY N;" */
-#define DB_FOREIGN_NO_INDEX	50	/* the child (foreign) table does not
+#define DB_FOREIGN_EXCEED_MAX_CASCADE 50/* Foreign key constraint related
+					cascading delete/update exceeds
+					maximum allowed depth */
+#define DB_FOREIGN_NO_INDEX	51	/* the child (foreign) table does not
 					have an index that contains the
 					foreign keys as its prefix columns */
-#define DB_REFERENCING_NO_INDEX	51	/* the parent (referencing) table does
+#define DB_REFERENCING_NO_INDEX	52	/* the parent (referencing) table does
 					not have an index that contains the
 					foreign keys as its prefix columns */
 

=== modified file 'storage/innobase/include/dict0dict.h'
--- a/storage/innobase/include/dict0dict.h	2010-05-14 13:02:28 +0000
+++ b/storage/innobase/include/dict0dict.h	2010-08-25 03:42:33 +0000
@@ -588,6 +588,22 @@ dict_table_is_comp_noninline(
 					/* out: TRUE if table uses the
 					compact page format */
 	const dict_table_t*	table);	/* in: table */
+/*********************************************************************//**
+Obtain exclusive locks on all index trees of the table. This is to prevent
+accessing index trees while InnoDB is updating internal metadata for
+operations such as truncate tables. */
+UNIV_INLINE
+void
+dict_table_x_lock_indexes(
+/*======================*/
+	dict_table_t*	table);	/* in: table */
+/*********************************************************************//**
+Release the exclusive locks on all index tree. */
+UNIV_INLINE
+void
+dict_table_x_unlock_indexes(
+/*========================*/
+	dict_table_t*	table);	/* in: table */
 /************************************************************************
 Checks if a column is in the ordering columns of the clustered index of a
 table. Column prefixes are treated like whole columns. */

=== modified file 'storage/innobase/include/dict0dict.ic'
--- a/storage/innobase/include/dict0dict.ic	2007-06-01 06:01:15 +0000
+++ b/storage/innobase/include/dict0dict.ic	2010-08-25 03:42:33 +0000
@@ -298,6 +298,48 @@ dict_table_is_comp(
 	return(UNIV_LIKELY(table->flags & DICT_TF_COMPACT));
 }
 
+/*********************************************************************//**
+Obtain exclusive locks on all index trees of the table. This is to prevent
+accessing index trees while InnoDB is updating internal metadata for
+operations such as truncate tables. */
+UNIV_INLINE
+void
+dict_table_x_lock_indexes(
+/*======================*/
+	dict_table_t*	table)	/* in: table */
+{
+	dict_index_t*   index;
+
+	ut_a(table);
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	/* Loop through each index of the table and lock them */
+	for (index = dict_table_get_first_index(table);
+	     index != NULL;
+	     index = dict_table_get_next_index(index)) {
+		rw_lock_x_lock(dict_index_get_lock(index));
+	}
+}
+
+/*********************************************************************//**
+Release the exclusive locks on all index tree. */
+UNIV_INLINE
+void
+dict_table_x_unlock_indexes(
+/*========================*/
+	dict_table_t*	table)	/* in: table */
+{
+	dict_index_t*   index;
+
+	ut_a(table);
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	for (index = dict_table_get_first_index(table);
+	     index != NULL;
+	     index = dict_table_get_next_index(index)) {
+		rw_lock_x_unlock(dict_index_get_lock(index));
+	}
+}
 /************************************************************************
 Gets the number of fields in the internal representation of an index,
 including fields added by the dictionary system. */

=== modified file 'storage/innobase/include/dict0load.h'
--- a/storage/innobase/include/dict0load.h	2006-02-21 12:37:54 +0000
+++ b/storage/innobase/include/dict0load.h	2010-08-04 10:11:33 +0000
@@ -82,6 +82,8 @@ dict_load_foreigns(
 /*===============*/
 					/* out: DB_SUCCESS or error code */
 	const char*	table_name,	/* in: table name */
+	ibool		check_recursive,/* in: Whether to check recursive
+					load of tables chained by FK */
 	ibool		check_charsets);/* in: TRUE=check charsets
 					compatibility */
 /************************************************************************

=== modified file 'storage/innobase/include/dict0mem.h'
--- a/storage/innobase/include/dict0mem.h	2008-10-23 04:30:32 +0000
+++ b/storage/innobase/include/dict0mem.h	2010-08-04 10:11:33 +0000
@@ -283,6 +283,21 @@ a foreign key constraint is enforced, th
 #define DICT_FOREIGN_ON_DELETE_NO_ACTION 16
 #define DICT_FOREIGN_ON_UPDATE_NO_ACTION 32
 
+/** Tables could be chained together with Foreign key constraint. When
+first load the parent table, we would load all of its descedents.
+This could result in rescursive calls and out of stack error eventually.
+DICT_FK_MAX_RECURSIVE_LOAD defines the maximum number of recursive loads,
+when exceeded, the child table will not be loaded. It will be loaded when
+the foreign constraint check needs to be run. */
+#define DICT_FK_MAX_RECURSIVE_LOAD	250
+
+/** Similarly, when tables are chained together with foreign key constraints
+with on cascading delete/update clause, delete from parent table could
+result in recursive cascading calls. This defines the maximum number of
+such cascading deletes/updates allowed. When exceeded, the delete from
+parent table will fail, and user has to drop excessive foreign constraint
+before proceeds. */
+#define FK_MAX_CASCADE_DEL		300
 
 /* Data structure for a database table */
 struct dict_table_struct{
@@ -339,6 +354,12 @@ struct dict_table_struct{
 				NOT allowed until this count gets to zero;
 				MySQL does NOT itself check the number of
 				open handles at drop */
+	unsigned	fk_max_recusive_level:8;
+				/*!< maximum recursive level we support when
+				loading tables chained together with FK
+				constraints. If exceeds this level, we will
+				stop loading child table into memory along with
+				its parent table */
 	ulint		n_foreign_key_checks_running;
 				/* count of how many foreign key check
 				operations are currently being performed

=== modified file 'storage/innobase/include/que0que.h'
--- a/storage/innobase/include/que0que.h	2006-06-08 06:08:23 +0000
+++ b/storage/innobase/include/que0que.h	2010-08-04 10:11:33 +0000
@@ -367,6 +367,9 @@ struct que_thr_struct{
 					thus far */
 	ulint		lock_state;	/* lock state of thread (table or
 					row) */
+	ulint		fk_cascade_depth; /*!< maximum cascading call depth
+					supported for foreign key constraint
+					related delete/updates */
 };
 
 #define QUE_THR_MAGIC_N		8476583

=== modified file 'storage/innobase/row/row0mysql.c'
--- a/storage/innobase/row/row0mysql.c	2010-09-30 12:48:44 +0000
+++ b/storage/innobase/row/row0mysql.c	2010-10-05 08:11:56 +0000
@@ -555,6 +555,12 @@ handle_new_error:
 		      "forcing-recovery.html"
 		      " for help.\n", stderr);
 
+	} else if (err == DB_FOREIGN_EXCEED_MAX_CASCADE) {
+		fprintf(stderr, "InnoDB: Cannot delete/update rows with"
+			" cascading foreign key constraints that exceed max"
+			" depth of %lu\n"
+			"Please drop excessive foreign constraints"
+			" and try again\n", (ulong) DICT_FK_MAX_RECURSIVE_LOAD);
 	} else {
 		fprintf(stderr, "InnoDB: unknown error code %lu\n",
 			(ulong) err);
@@ -1406,11 +1412,15 @@ row_update_for_mysql(
 run_again:
 	thr->run_node = node;
 	thr->prev_node = node;
+	thr->fk_cascade_depth = 0;
 
 	row_upd_step(thr);
 
 	err = trx->error_state;
 
+	/* Reset fk_cascade_depth back to 0 */
+	thr->fk_cascade_depth = 0;
+
 	if (err != DB_SUCCESS) {
 		que_thr_stop_for_mysql(thr);
 
@@ -1602,6 +1612,12 @@ row_update_cascade_for_mysql(
 	trx_t*	trx;
 
 	trx = thr_get_trx(thr);
+
+	thr->fk_cascade_depth++;
+
+	if (thr->fk_cascade_depth > FK_MAX_CASCADE_DEL) {
+		return (DB_FOREIGN_EXCEED_MAX_CASCADE);
+	}
 run_again:
 	thr->run_node = node;
 	thr->prev_node = node;
@@ -2134,7 +2150,7 @@ row_table_add_foreign_constraints(
 
 	if (err == DB_SUCCESS) {
 		/* Check that also referencing constraints are ok */
-		err = dict_load_foreigns(name, TRUE);
+		err = dict_load_foreigns(name, FALSE, TRUE);
 	}
 
 	if (err != DB_SUCCESS) {
@@ -2819,6 +2835,15 @@ row_truncate_table_for_mysql(
 
 	trx->table_id = table->id;
 
+	/* Lock all index trees for this table, as we will
+	truncate the table/index and possibly change their metadata.
+	All DML/DDL are blocked by table level lock, with
+	a few exceptions such as queries into information schema
+	about the table, MySQL could try to access index stats
+	for this kind of query, we need to use index locks to
+	sync up */
+	dict_table_x_lock_indexes(table);
+
 	/* scan SYS_INDEXES for all indexes of the table */
 	heap = mem_heap_create(800);
 
@@ -2891,6 +2916,10 @@ next_rec:
 
 	mem_heap_free(heap);
 
+	/* Done with index truncation, release index tree locks,
+	subsequent work relates to table level metadata change */
+	dict_table_x_unlock_indexes(table);
+
 	new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
 
 	info = pars_info_create();
@@ -3883,7 +3912,8 @@ end:
 		an ALTER, not in a RENAME. */
 
 		err = dict_load_foreigns(
-			new_name, old_is_tmp ? trx->check_foreigns : TRUE);
+			new_name, FALSE,
+			old_is_tmp ? trx->check_foreigns : TRUE);
 
 		if (err != DB_SUCCESS) {
 			ut_print_timestamp(stderr);

=== modified file 'storage/innodb_plugin/ChangeLog'
--- a/storage/innodb_plugin/ChangeLog	2010-10-04 10:06:41 +0000
+++ b/storage/innodb_plugin/ChangeLog	2010-10-05 08:11:56 +0000
@@ -14,6 +14,19 @@
 
 2010-08-03	The InnoDB Team
 
+	* include/dict0dict.h, include/dict0dict.ic, row/row0mysql.c:
+	Fix bug #54678, InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
+
+2010-08-03	The InnoDB Team
+
+	* dict/dict0load.c, handler/ha_innodb.cc, include/db0err.h,
+	include/dict0load.h, include/dict0mem.h, include/que0que.h,
+	row/row0merge.c, row/row0mysql.c:
+	Fix Bug#54582 stack overflow when opening many tables linked
+	with foreign keys at once
+
+2010-08-03	The InnoDB Team
+
 	* include/ut0mem.h, ut/ut0mem.c:
 	Fix Bug #55627 segv in ut_free pars_lexer_close innobase_shutdown
 	innodb-use-sys-malloc=0
@@ -23,6 +36,7 @@
 	* handler/ha_innodb.cc
 	Fix Bug #55382 Assignment with SELECT expressions takes unexpected
 	S locks in READ COMMITTED
+>>>>>>> MERGE-SOURCE
 
 2010-07-27	The InnoDB Team
 

=== modified file 'storage/innodb_plugin/btr/btr0cur.c'
--- a/storage/innodb_plugin/btr/btr0cur.c	2010-09-14 18:33:02 +0000
+++ b/storage/innodb_plugin/btr/btr0cur.c	2010-10-05 08:11:56 +0000
@@ -3483,9 +3483,10 @@ btr_cur_set_ownership_of_extern_field(
 Marks not updated extern fields as not-owned by this record. The ownership
 is transferred to the updated record which is inserted elsewhere in the
 index tree. In purge only the owner of externally stored field is allowed
-to free the field. */
+to free the field.
+@return TRUE if BLOB ownership was transferred */
 UNIV_INTERN
-void
+ibool
 btr_cur_mark_extern_inherited_fields(
 /*=================================*/
 	page_zip_des_t*	page_zip,/*!< in/out: compressed page whose uncompressed
@@ -3499,13 +3500,14 @@ btr_cur_mark_extern_inherited_fields(
 	ulint	n;
 	ulint	j;
 	ulint	i;
+	ibool	change_ownership = FALSE;
 
 	ut_ad(rec_offs_validate(rec, NULL, offsets));
 	ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
 
 	if (!rec_offs_any_extern(offsets)) {
 
-		return;
+		return(FALSE);
 	}
 
 	n = rec_offs_n_fields(offsets);
@@ -3528,10 +3530,14 @@ btr_cur_mark_extern_inherited_fields(
 
 			btr_cur_set_ownership_of_extern_field(
 				page_zip, rec, index, offsets, i, FALSE, mtr);
+
+			change_ownership = TRUE;
 updated:
 			;
 		}
 	}
+
+	return(change_ownership);
 }
 
 /*******************************************************************//**

=== modified file 'storage/innodb_plugin/dict/dict0load.c'
--- a/storage/innodb_plugin/dict/dict0load.c	2010-09-07 05:41:37 +0000
+++ b/storage/innodb_plugin/dict/dict0load.c	2010-10-05 08:11:56 +0000
@@ -1009,16 +1009,27 @@ err_exit:
 
 	err = dict_load_indexes(table, heap);
 
+	/* Initialize table foreign_child value. Its value could be
+	changed when dict_load_foreigns() is called below */
+	table->fk_max_recusive_level = 0;
+
 	/* If the force recovery flag is set, we open the table irrespective
 	of the error condition, since the user may want to dump data from the
 	clustered index. However we load the foreign key information only if
 	all indexes were loaded. */
 	if (err == DB_SUCCESS) {
-		err = dict_load_foreigns(table->name, TRUE);
+		err = dict_load_foreigns(table->name, TRUE, TRUE);
+
+		if (err != DB_SUCCESS) {
+			dict_table_remove_from_cache(table);
+			table = NULL;
+		}
 	} else if (!srv_force_recovery) {
 		dict_table_remove_from_cache(table);
 		table = NULL;
 	}
+
+	table->fk_max_recusive_level = 0;
 #if 0
 	if (err != DB_SUCCESS && table != NULL) {
 
@@ -1240,8 +1251,12 @@ dict_load_foreign(
 /*==============*/
 	const char*	id,	/*!< in: foreign constraint id as a
 				null-terminated string */
-	ibool		check_charsets)
+	ibool		check_charsets,
 				/*!< in: TRUE=check charset compatibility */
+	ibool		check_recursive)
+				/*!< in: Whether to record the foreign table
+				parent count to avoid unlimited recursive
+				load of chained foreign tables */
 {
 	dict_foreign_t*	foreign;
 	dict_table_t*	sys_foreign;
@@ -1255,6 +1270,8 @@ dict_load_foreign(
 	ulint		len;
 	ulint		n_fields_and_type;
 	mtr_t		mtr;
+	dict_table_t*	for_table;
+	dict_table_t*	ref_table;
 
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 
@@ -1339,11 +1356,54 @@ dict_load_foreign(
 
 	dict_load_foreign_cols(id, foreign);
 
-	/* If the foreign table is not yet in the dictionary cache, we
-	have to load it so that we are able to make type comparisons
-	in the next function call. */
+	ref_table = dict_table_check_if_in_cache_low(
+			foreign->referenced_table_name);
 
-	dict_table_get_low(foreign->foreign_table_name);
+	/* We could possibly wind up in a deep recursive calls if
+	we call dict_table_get_low() again here if there
+	is a chain of tables concatenated together with
+	foreign constraints. In such case, each table is
+	both a parent and child of the other tables, and
+	act as a "link" in such table chains.
+	To avoid such scenario, we would need to check the
+	number of ancesters the current table has. If that
+	exceeds DICT_FK_MAX_CHAIN_LEN, we will stop loading
+	the child table.
+	Foreign constraints are loaded in a Breath First fashion,
+	that is, the index on FOR_NAME is scanned first, and then
+	index on REF_NAME. So foreign constrains in which
+	current table is a child (foreign table) are loaded first,
+	and then those constraints where current table is a
+	parent (referenced) table.
+	Thus we could check the parent (ref_table) table's
+	reference count (fk_max_recusive_level) to know how deep the
+	recursive call is. If the parent table (ref_table) is already
+	loaded, and its fk_max_recusive_level is larger than
+	DICT_FK_MAX_CHAIN_LEN, we will stop the recursive loading
+	by skipping loading the child table. It will not affect foreign
+	constraint check for DMLs since child table will be loaded
+	at that time for the constraint check. */
+	if (!ref_table
+	    || ref_table->fk_max_recusive_level < DICT_FK_MAX_RECURSIVE_LOAD) {
+
+		/* If the foreign table is not yet in the dictionary cache, we
+		have to load it so that we are able to make type comparisons
+		in the next function call. */
+
+		for_table = dict_table_get_low(foreign->foreign_table_name);
+
+		if (for_table && ref_table && check_recursive) {
+			/* This is to record the longest chain of ancesters
+			this table has, if the parent has more ancesters
+			than this table has, record it after add 1 (for this
+			parent */
+			if (ref_table->fk_max_recusive_level
+			    >= for_table->fk_max_recusive_level) {
+				for_table->fk_max_recusive_level =
+					 ref_table->fk_max_recusive_level + 1;
+			}
+		}
+	}
 
 	/* Note that there may already be a foreign constraint object in
 	the dictionary cache for this constraint: then the following
@@ -1368,6 +1428,8 @@ ulint
 dict_load_foreigns(
 /*===============*/
 	const char*	table_name,	/*!< in: table name */
+	ibool		check_recursive,/*!< in: Whether to check recursive
+					load of tables chained by FK */
 	ibool		check_charsets)	/*!< in: TRUE=check charset
 					compatibility */
 {
@@ -1469,7 +1531,7 @@ loop:
 
 	/* Load the foreign constraint definition to the dictionary cache */
 
-	err = dict_load_foreign(id, check_charsets);
+	err = dict_load_foreign(id, check_charsets, check_recursive);
 
 	if (err != DB_SUCCESS) {
 		btr_pcur_close(&pcur);
@@ -1497,6 +1559,11 @@ load_next_index:
 
 		mtr_start(&mtr);
 
+		/* Switch to scan index on REF_NAME, fk_max_recusive_level
+		already been updated when scanning FOR_NAME index, no need to
+		update again */
+		check_recursive = FALSE;
+
 		goto start_load;
 	}
 

=== modified file 'storage/innodb_plugin/handler/ha_innodb.cc'
--- a/storage/innodb_plugin/handler/ha_innodb.cc	2010-09-15 15:10:10 +0000
+++ b/storage/innodb_plugin/handler/ha_innodb.cc	2010-10-05 08:11:56 +0000
@@ -767,6 +767,19 @@ convert_error_code_to_mysql(
 	case DB_INTERRUPTED:
 		my_error(ER_QUERY_INTERRUPTED, MYF(0));
 		/* fall through */
+
+	case DB_FOREIGN_EXCEED_MAX_CASCADE:
+		push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+				    HA_ERR_ROW_IS_REFERENCED,
+				    "InnoDB: Cannot delete/update "
+				    "rows with cascading foreign key "
+				    "constraints that exceed max "
+				    "depth of %d. Please "
+				    "drop extra constraints and try "
+				    "again", DICT_FK_MAX_RECURSIVE_LOAD);
+
+		/* fall through */
+
 	case DB_ERROR:
 	default:
 		return(-1); /* unspecified error */
@@ -3348,12 +3361,19 @@ ha_innobase::innobase_initialize_autoinc
 		err = row_search_max_autoinc(index, col_name, &read_auto_inc);
 
 		switch (err) {
-		case DB_SUCCESS:
+		case DB_SUCCESS: {
+			ulonglong	col_max_value;
+
+			col_max_value = innobase_get_int_col_max_value(field);
+
 			/* At the this stage we do not know the increment
-			or the offset, so use a default increment of 1. */
-			auto_inc = read_auto_inc + 1;
-			break;
+			nor the offset, so use a default increment of 1. */
 
+			auto_inc = innobase_next_autoinc(
+				read_auto_inc, 1, 1, col_max_value);
+
+			break;
+		}
 		case DB_RECORD_NOT_FOUND:
 			ut_print_timestamp(stderr);
 			fprintf(stderr, "  InnoDB: MySQL and InnoDB data "
@@ -3648,8 +3668,6 @@ retry:
 			dict_table_get_format(prebuilt->table));
 	}
 
-	info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
-
 	/* Only if the table has an AUTOINC column. */
 	if (prebuilt->table != NULL && table->found_next_number_field != NULL) {
 		dict_table_autoinc_lock(prebuilt->table);
@@ -3666,6 +3684,8 @@ retry:
 		dict_table_autoinc_unlock(prebuilt->table);
 	}
 
+	info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
+
 	DBUG_RETURN(0);
 }
 

=== modified file 'storage/innodb_plugin/include/btr0cur.h'
--- a/storage/innodb_plugin/include/btr0cur.h	2010-06-29 12:55:18 +0000
+++ b/storage/innodb_plugin/include/btr0cur.h	2010-08-05 09:18:17 +0000
@@ -468,9 +468,10 @@ btr_estimate_number_of_different_key_val
 Marks not updated extern fields as not-owned by this record. The ownership
 is transferred to the updated record which is inserted elsewhere in the
 index tree. In purge only the owner of externally stored field is allowed
-to free the field. */
+to free the field.
+@return TRUE if BLOB ownership was transferred */
 UNIV_INTERN
-void
+ibool
 btr_cur_mark_extern_inherited_fields(
 /*=================================*/
 	page_zip_des_t*	page_zip,/*!< in/out: compressed page whose uncompressed

=== modified file 'storage/innodb_plugin/include/db0err.h'
--- a/storage/innodb_plugin/include/db0err.h	2010-06-02 10:37:14 +0000
+++ b/storage/innodb_plugin/include/db0err.h	2010-08-04 10:11:33 +0000
@@ -94,6 +94,9 @@ enum db_err {
 
 	DB_PRIMARY_KEY_IS_NULL,		/* a column in the PRIMARY KEY
 					was found to be NULL */
+	DB_FOREIGN_EXCEED_MAX_CASCADE,	/* Foreign key constraint related
+					cascading delete/update exceeds
+					maximum allowed depth */
 
 	/* The following are partial failure codes */
 	DB_FAIL = 1000,

=== modified file 'storage/innodb_plugin/include/dict0dict.h'
--- a/storage/innodb_plugin/include/dict0dict.h	2010-05-14 13:08:15 +0000
+++ b/storage/innodb_plugin/include/dict0dict.h	2010-08-04 10:37:44 +0000
@@ -680,6 +680,22 @@ ulint
 dict_table_zip_size(
 /*================*/
 	const dict_table_t*	table);	/*!< in: table */
+/*********************************************************************//**
+Obtain exclusive locks on all index trees of the table. This is to prevent
+accessing index trees while InnoDB is updating internal metadata for
+operations such as truncate tables. */
+UNIV_INLINE
+void
+dict_table_x_lock_indexes(
+/*======================*/
+	dict_table_t*	table);	/*!< in: table */
+/*********************************************************************//**
+Release the exclusive locks on all index tree. */
+UNIV_INLINE
+void
+dict_table_x_unlock_indexes(
+/*========================*/
+	dict_table_t*	table);	/*!< in: table */
 /********************************************************************//**
 Checks if a column is in the ordering columns of the clustered index of a
 table. Column prefixes are treated like whole columns.

=== modified file 'storage/innodb_plugin/include/dict0dict.ic'
--- a/storage/innodb_plugin/include/dict0dict.ic	2009-05-25 09:52:29 +0000
+++ b/storage/innodb_plugin/include/dict0dict.ic	2010-08-04 10:37:44 +0000
@@ -452,6 +452,48 @@ dict_table_zip_size(
 	return(dict_table_flags_to_zip_size(table->flags));
 }
 
+/*********************************************************************//**
+Obtain exclusive locks on all index trees of the table. This is to prevent
+accessing index trees while InnoDB is updating internal metadata for
+operations such as truncate tables. */
+UNIV_INLINE
+void
+dict_table_x_lock_indexes(
+/*======================*/
+	dict_table_t*	table)	/*!< in: table */
+{
+	dict_index_t*   index;
+
+	ut_a(table);
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	/* Loop through each index of the table and lock them */
+	for (index = dict_table_get_first_index(table);
+	     index != NULL;
+	     index = dict_table_get_next_index(index)) {
+		rw_lock_x_lock(dict_index_get_lock(index));
+	}
+}
+
+/*********************************************************************//**
+Release the exclusive locks on all index tree. */
+UNIV_INLINE
+void
+dict_table_x_unlock_indexes(
+/*========================*/
+	dict_table_t*	table)	/*!< in: table */
+{
+	dict_index_t*   index;
+
+	ut_a(table);
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	for (index = dict_table_get_first_index(table);
+	     index != NULL;
+	     index = dict_table_get_next_index(index)) {
+		rw_lock_x_unlock(dict_index_get_lock(index));
+	}
+}
 /********************************************************************//**
 Gets the number of fields in the internal representation of an index,
 including fields added by the dictionary system.

=== modified file 'storage/innodb_plugin/include/dict0load.h'
--- a/storage/innodb_plugin/include/dict0load.h	2009-05-25 09:52:29 +0000
+++ b/storage/innodb_plugin/include/dict0load.h	2010-08-04 10:11:33 +0000
@@ -97,6 +97,8 @@ ulint
 dict_load_foreigns(
 /*===============*/
 	const char*	table_name,	/*!< in: table name */
+	ibool		check_recursive,/*!< in: Whether to check recursive
+					load of tables chained by FK */
 	ibool		check_charsets);/*!< in: TRUE=check charsets
 					compatibility */
 /********************************************************************//**

=== modified file 'storage/innodb_plugin/include/dict0mem.h'
--- a/storage/innodb_plugin/include/dict0mem.h	2010-06-22 16:30:43 +0000
+++ b/storage/innodb_plugin/include/dict0mem.h	2010-08-04 10:11:33 +0000
@@ -112,6 +112,21 @@ ROW_FORMAT=REDUNDANT. */
 						in table->flags. */
 /* @} */
 
+/** Tables could be chained together with Foreign key constraint. When
+first load the parent table, we would load all of its descedents.
+This could result in rescursive calls and out of stack error eventually.
+DICT_FK_MAX_RECURSIVE_LOAD defines the maximum number of recursive loads,
+when exceeded, the child table will not be loaded. It will be loaded when
+the foreign constraint check needs to be run. */
+#define DICT_FK_MAX_RECURSIVE_LOAD	250
+
+/** Similarly, when tables are chained together with foreign key constraints
+with on cascading delete/update clause, delete from parent table could
+result in recursive cascading calls. This defines the maximum number of
+such cascading deletes/updates allowed. When exceeded, the delete from
+parent table will fail, and user has to drop excessive foreign constraint
+before proceeds. */
+#define FK_MAX_CASCADE_DEL		300
 
 /**********************************************************************//**
 Creates a table memory object.
@@ -434,6 +449,12 @@ struct dict_table_struct{
 				NOT allowed until this count gets to zero;
 				MySQL does NOT itself check the number of
 				open handles at drop */
+	unsigned	fk_max_recusive_level:8;
+				/*!< maximum recursive level we support when
+				loading tables chained together with FK
+				constraints. If exceeds this level, we will
+				stop loading child table into memory along with
+				its parent table */
 	ulint		n_foreign_key_checks_running;
 				/*!< count of how many foreign key check
 				operations are currently being performed

=== modified file 'storage/innodb_plugin/include/que0que.h'
--- a/storage/innodb_plugin/include/que0que.h	2010-02-20 16:45:41 +0000
+++ b/storage/innodb_plugin/include/que0que.h	2010-08-04 10:11:33 +0000
@@ -381,6 +381,9 @@ struct que_thr_struct{
 					thus far */
 	ulint		lock_state;	/*!< lock state of thread (table or
 					row) */
+	ulint		fk_cascade_depth; /*!< maximum cascading call depth
+					supported for foreign key constraint
+					related delete/updates */
 };
 
 #define QUE_THR_MAGIC_N		8476583

=== modified file 'storage/innodb_plugin/row/row0merge.c'
--- a/storage/innodb_plugin/row/row0merge.c	2010-06-29 12:55:18 +0000
+++ b/storage/innodb_plugin/row/row0merge.c	2010-08-04 10:11:33 +0000
@@ -2395,7 +2395,7 @@ row_merge_rename_tables(
 		goto err_exit;
 	}
 
-	err = dict_load_foreigns(old_name, TRUE);
+	err = dict_load_foreigns(old_name, FALSE, TRUE);
 
 	if (err != DB_SUCCESS) {
 err_exit:

=== modified file 'storage/innodb_plugin/row/row0mysql.c'
--- a/storage/innodb_plugin/row/row0mysql.c	2010-09-30 12:48:44 +0000
+++ b/storage/innodb_plugin/row/row0mysql.c	2010-10-05 08:11:56 +0000
@@ -576,6 +576,13 @@ handle_new_error:
 		      "InnoDB: " REFMAN "forcing-recovery.html"
 		      " for help.\n", stderr);
 		break;
+	case DB_FOREIGN_EXCEED_MAX_CASCADE:
+		fprintf(stderr, "InnoDB: Cannot delete/update rows with"
+			" cascading foreign key constraints that exceed max"
+			" depth of %lu\n"
+			"Please drop excessive foreign constraints"
+			" and try again\n", (ulong) DICT_FK_MAX_RECURSIVE_LOAD);
+		break;
 	default:
 		fprintf(stderr, "InnoDB: unknown error code %lu\n",
 			(ulong) err);
@@ -1381,11 +1388,15 @@ row_update_for_mysql(
 run_again:
 	thr->run_node = node;
 	thr->prev_node = node;
+	thr->fk_cascade_depth = 0;
 
 	row_upd_step(thr);
 
 	err = trx->error_state;
 
+	/* Reset fk_cascade_depth back to 0 */
+	thr->fk_cascade_depth = 0;
+
 	if (err != DB_SUCCESS) {
 		que_thr_stop_for_mysql(thr);
 
@@ -1581,6 +1592,12 @@ row_update_cascade_for_mysql(
 	trx_t*	trx;
 
 	trx = thr_get_trx(thr);
+
+	thr->fk_cascade_depth++;
+
+	if (thr->fk_cascade_depth > FK_MAX_CASCADE_DEL) {
+		return (DB_FOREIGN_EXCEED_MAX_CASCADE);
+	}
 run_again:
 	thr->run_node = node;
 	thr->prev_node = node;
@@ -2061,7 +2078,7 @@ row_table_add_foreign_constraints(
 					      name, reject_fks);
 	if (err == DB_SUCCESS) {
 		/* Check that also referencing constraints are ok */
-		err = dict_load_foreigns(name, TRUE);
+		err = dict_load_foreigns(name, FALSE, TRUE);
 	}
 
 	if (err != DB_SUCCESS) {
@@ -2754,6 +2771,15 @@ row_truncate_table_for_mysql(
 
 	trx->table_id = table->id;
 
+	/* Lock all index trees for this table, as we will
+	truncate the table/index and possibly change their metadata.
+	All DML/DDL are blocked by table level lock, with
+	a few exceptions such as queries into information schema
+	about the table, MySQL could try to access index stats
+	for this kind of query, we need to use index locks to
+	sync up */
+	dict_table_x_lock_indexes(table);
+
 	if (table->space && !table->dir_path_of_temp_table) {
 		/* Discard and create the single-table tablespace. */
 		ulint	space	= table->space;
@@ -2770,6 +2796,7 @@ row_truncate_table_for_mysql(
 			    || fil_create_new_single_table_tablespace(
 				    space, table->name, FALSE, flags,
 				    FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
+				dict_table_x_unlock_indexes(table);
 				ut_print_timestamp(stderr);
 				fprintf(stderr,
 					"  InnoDB: TRUNCATE TABLE %s failed to"
@@ -2873,6 +2900,10 @@ next_rec:
 
 	mem_heap_free(heap);
 
+	/* Done with index truncation, release index tree locks,
+	subsequent work relates to table level metadata change */
+	dict_table_x_unlock_indexes(table);
+
 	dict_hdr_get_new_id(&new_id, NULL, NULL);
 
 	info = pars_info_create();
@@ -3920,7 +3951,7 @@ end:
 		an ALTER, not in a RENAME. */
 
 		err = dict_load_foreigns(
-			new_name, !old_is_tmp || trx->check_foreigns);
+			new_name, FALSE, !old_is_tmp || trx->check_foreigns);
 
 		if (err != DB_SUCCESS) {
 			ut_print_timestamp(stderr);

=== modified file 'storage/innodb_plugin/row/row0upd.c'
--- a/storage/innodb_plugin/row/row0upd.c	2010-06-29 13:00:58 +0000
+++ b/storage/innodb_plugin/row/row0upd.c	2010-08-05 09:18:17 +0000
@@ -1598,6 +1598,7 @@ row_upd_clust_rec_by_insert(
 	dict_table_t*	table;
 	dtuple_t*	entry;
 	ulint		err;
+	ibool		change_ownership = FALSE;
 
 	ut_ad(node);
 	ut_ad(dict_index_is_clust(index));
@@ -1630,9 +1631,9 @@ row_upd_clust_rec_by_insert(
 		index = dict_table_get_first_index(table);
 		offsets = rec_get_offsets(rec, index, offsets_,
 					  ULINT_UNDEFINED, &heap);
-		btr_cur_mark_extern_inherited_fields(
-			btr_cur_get_page_zip(btr_cur),
-			rec, index, offsets, node->update, mtr);
+		change_ownership = btr_cur_mark_extern_inherited_fields(
+			btr_cur_get_page_zip(btr_cur), rec, index, offsets,
+			node->update, mtr);
 		if (check_ref) {
 			/* NOTE that the following call loses
 			the position of pcur ! */
@@ -1661,10 +1662,11 @@ row_upd_clust_rec_by_insert(
 
 	row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id);
 
-	if (node->upd_ext) {
+	if (change_ownership) {
 		/* If we return from a lock wait, for example, we may have
 		extern fields marked as not-owned in entry (marked in the
-		if-branch above). We must unmark them. */
+		if-branch above). We must unmark them, take the ownership
+		back. */
 
 		btr_cur_unmark_dtuple_extern_fields(entry);
 


Attachment: [text/bzr-bundle] bzr/georgi.kodinov@oracle.com-20101005081156-t2ey5tw36wk62n2k.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (Georgi.Kodinov:3519) Georgi Kodinov5 Oct