List:Commits« Previous MessageNext Message »
From:Luis Soares Date:February 18 2012 11:16pm
Subject:bzr push into mysql-trunk-wl3584 branch (luis.soares:3656 to 3657)
View as plain text  
 3657 Luis Soares	2012-02-18 [merge]
      Merging mysql-trunk --> mysql-trunk-wl3584.
      
      Manually resolved conflicts
      ===========================
      Text conflict in sql/sql_class.cc

    added:
      mysql-test/suite/binlog/r/binlog_server_start_options.result
      mysql-test/suite/binlog/t/binlog_server_start_options.test
      mysql-test/suite/innodb/r/innodb-blob.result
      mysql-test/suite/innodb/t/innodb-blob.test
      sql/md5.cc
      sql/sha1.cc
    modified:
      include/my_md5.h
      include/sha1.h
      libmysql/CMakeLists.txt
      mysql-test/r/type_newdecimal.result
      mysql-test/r/type_temporal_fractional.result
      mysql-test/t/type_newdecimal.test
      mysql-test/t/type_temporal_fractional.test
      mysys/CMakeLists.txt
      mysys/md5.c
      mysys/mf_format.c
      mysys/sha1.c
      sql/CMakeLists.txt
      sql/handler.cc
      sql/item.h
      sql/item_func.cc
      sql/item_func.h
      sql/item_strfunc.cc
      sql/mysqld.cc
      sql/opt_range.cc
      sql/password.c
      sql/rpl_info_factory.cc
      sql/sql_class.cc
      sql/sql_plugin.cc
      sql/sys_vars.cc
      sql/table.cc
      storage/innobase/btr/btr0btr.cc
      storage/innobase/btr/btr0cur.cc
      storage/innobase/buf/buf0dblwr.cc
      storage/innobase/fsp/fsp0fsp.cc
      storage/innobase/ibuf/ibuf0ibuf.cc
      storage/innobase/include/btr0btr.h
      storage/innobase/include/btr0cur.h
      storage/innobase/include/btr0cur.ic
      storage/innobase/include/fsp0fsp.h
      storage/innobase/include/mtr0mtr.h
      storage/innobase/include/mtr0mtr.ic
      storage/innobase/include/trx0rec.ic
      storage/innobase/include/trx0undo.h
      storage/innobase/include/univ.i
      storage/innobase/mtr/mtr0mtr.cc
      storage/innobase/row/row0ins.cc
      storage/innobase/row/row0upd.cc
      storage/innobase/srv/srv0start.cc
      storage/innobase/trx/trx0rec.cc
      storage/innobase/trx/trx0trx.cc
      storage/innobase/trx/trx0undo.cc
 3656 Luis Soares	2012-02-18
      WL#3584
      
      The rpl_gtid_stress_failover fails in MTS mode with messages:
      
      "1201: Could not initialize master info structure; more error 
      messages can be found in the MySQL error log"
      
      and 
      
      "Error looking for file after ./mysqld-relay-bin.000004."
      
      These are the symptoms of BUG#12995174 in mysql-trunk. Disabling 
      the test case in MTS mode until this is fixed in mysql-trunk.

    modified:
      mysql-test/suite/rpl/t/rpl_gtid_stress_failover.test
=== modified file 'include/my_md5.h'
--- a/include/my_md5.h	2009-09-23 21:32:31 +0000
+++ b/include/my_md5.h	2012-02-17 10:30:31 +0000
@@ -22,6 +22,36 @@
  * $FreeBSD: src/contrib/cvs/lib/md5.h,v 1.2 1999/12/11 15:10:02 peter Exp $
  */
 
+#if defined(HAVE_YASSL) || defined(HAVE_OPENSSL)
+/*
+  Use MD5 implementation provided by the SSL libraries.
+*/
+
+#if defined(HAVE_YASSL)
+
+C_MODE_START
+
+void my_md5_hash(char *digest, const char *buf, int len);
+
+C_MODE_END
+
+#else /* HAVE_YASSL */
+
+#include <openssl/md5.h>
+
+#define MY_MD5_HASH(digest, buf, len) \
+do { \
+  MD5_CTX ctx; \
+  MD5_Init (&ctx); \
+  MD5_Update (&ctx, buf, len); \
+  MD5_Final (digest, &ctx); \
+} while (0)
+
+#endif /* HAVE_YASSL */
+
+#else /* HAVE_YASSL || HAVE_OPENSSL */
+/* Fallback to the MySQL's implementation. */
+
 /* Unlike previous versions of this code, uint32 need not be exactly
    32 bits, merely 32 bits or more.  Choosing a data type which is 32
    bits instead of 64 is not important; speed is considerably more
@@ -35,18 +65,15 @@ typedef struct {
   unsigned char in[64];
 } my_MD5Context;
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+C_MODE_START
+
 void my_MD5Init (my_MD5Context *context);
 void my_MD5Update (my_MD5Context *context,
                    unsigned char const *buf, unsigned len);
 void my_MD5Final (unsigned char digest[16],
                   my_MD5Context *context);
 
-#ifdef __cplusplus
-}
-#endif
+C_MODE_END
 
 #define MY_MD5_HASH(digest,buf,len) \
 do { \
@@ -56,4 +83,12 @@ do { \
   my_MD5Final (digest, &ctx); \
 } while (0)
 
-#endif /* MY_MD__INCLUDED */
+#endif /* defined(HAVE_YASSL) || defined(HAVE_OPENSSL) */
+
+C_MODE_START
+
+void compute_md5_hash(char *digest, const char *buf, int len);
+
+C_MODE_END
+
+#endif /* MY_MD5_INCLUDED */

=== modified file 'include/sha1.h'
--- a/include/sha1.h	2011-06-30 15:46:53 +0000
+++ b/include/sha1.h	2012-02-17 10:30:31 +0000
@@ -64,6 +64,28 @@
   Internet Society. 
 */
 
+#define SHA1_HASH_SIZE 20 /* Hash size in bytes */
+
+/*
+  Use SHA1 implementation provided by the SSL libraries if available.
+*/
+
+#if defined(HAVE_YASSL)
+
+C_MODE_START
+
+void mysql_sha1_yassl(uint8 *digest, const char *buf, int len);
+void mysql_sha1_multi_yassl(uint8 *digest, const char *buf1, int len1,
+                            const char *buf2, int len2);
+
+C_MODE_END
+
+#elif defined(HAVE_OPENSSL)
+
+#include <openssl/sha.h>
+#define SHA1_CONTEXT SHA_CTX
+
+# else
 
 enum sha_result_codes
 {
@@ -73,8 +95,6 @@ enum sha_result_codes
   SHA_STATE_ERROR	/* called Input after Result */
 };
 
-#define SHA1_HASH_SIZE 20 /* Hash size in bytes */
-
 /*
   This structure will hold context information for the SHA-1
   hashing operation
@@ -90,8 +110,11 @@ typedef struct SHA1_CONTEXT
   uint8 Message_Block[64];	/* 512-bit message blocks      */
 } SHA1_CONTEXT;
 
+#endif  /* HAVE_YASSL */
+
+#ifndef HAVE_YASSL
 /*
-  Function Prototypes
+  Function Prototypes (shared by MySQL & OpenSSL's SHA1 implementation )
 */
 
 C_MODE_START
@@ -102,4 +125,14 @@ int mysql_sha1_result(SHA1_CONTEXT* , ui
 
 C_MODE_END
 
-#endif /* SHA__INCLUDED */
+#endif /* HAVE_YASSL */
+
+C_MODE_START
+
+void compute_sha1_hash(uint8 *digest, const char *buf, int len);
+void compute_sha1_hash_multi(uint8 *digest, const char *buf1, int len1,
+                             const char *buf2, int len2);
+
+C_MODE_END
+
+#endif /* SHA1_INCLUDED */

=== modified file 'libmysql/CMakeLists.txt'
--- a/libmysql/CMakeLists.txt	2012-02-16 10:52:45 +0000
+++ b/libmysql/CMakeLists.txt	2012-02-17 10:30:31 +0000
@@ -145,6 +145,8 @@ SET(CLIENT_SOURCES
   ../sql-common/client_plugin.c 
   ../sql/net_serv.cc
   ../sql-common/pack.c 
+  ../sql/md5.cc
+  ../sql/sha1.cc
   ../sql/password.c
   ../sql/my_rnd.cc
 )

=== modified file 'mysql-test/r/type_newdecimal.result'
--- a/mysql-test/r/type_newdecimal.result	2011-11-21 11:58:25 +0000
+++ b/mysql-test/r/type_newdecimal.result	2012-02-17 13:55:18 +0000
@@ -1988,3 +1988,27 @@ SELECT d1 * d2 FROM t1;
 d1 * d2
 0
 DROP TABLE t1;
+#
+# Start of 5.6 tests
+#
+#
+# Bug#13375823 - FSP(DECIMAL) RESULT DIFFERENCE WITH QUERY USING UNION ALL
+#
+CREATE TABLE t1 (a DECIMAL(20,3) NOT NULL);
+INSERT INTO t1 VALUES (20000716055804.035);
+INSERT INTO t1 VALUES (20080821000000.000);
+INSERT INTO t1 VALUES (0);
+SELECT GREATEST(a, 1323) FROM t1;
+GREATEST(a, 1323)
+20000716055804.035
+20080821000000.000
+1323.000
+(SELECT GREATEST(a, 1323) FROM t1) UNION ALL (SELECT GREATEST(a, 1323) FROM t1 LIMIT 0);
+GREATEST(a, 1323)
+20000716055804.035
+20080821000000.000
+1323.000
+DROP TABLE t1;
+#
+# End of 5.6 tests
+#

=== modified file 'mysql-test/r/type_temporal_fractional.result'
--- a/mysql-test/r/type_temporal_fractional.result	2012-02-13 06:26:52 +0000
+++ b/mysql-test/r/type_temporal_fractional.result	2012-02-17 13:55:18 +0000
@@ -17178,4 +17178,82 @@ Warning	1292	Incorrect datetime value: '
 Warning	1292	Incorrect datetime value: '-0.1111111111'
 Warning	1292	Incorrect datetime value: '-0.1111111'
 Warning	1292	Incorrect datetime value: '-0.1111111111'
+#
+# Bug#13375823 - FSP(DECIMAL) RESULT DIFFERENCE WITH QUERY USING UNION ALL
+#
+CREATE TABLE t1 (a DATETIME(3) NOT NULL);
+INSERT INTO t1 VALUES ('2000-07-16 05:58:04.035');
+INSERT INTO t1 VALUES ('2008-08-21 00:00:00.000');
+INSERT INTO t1 VALUES ('0000-00-00 00:00:00.000');
+# Testing INT number
+SELECT GREATEST(a, 1323) FROM t1;
+GREATEST(a, 1323)
+20000716055804.035
+20080821000000.000
+1323.000
+(SELECT GREATEST(a, 1323) FROM t1) UNION ALL (SELECT GREATEST(a, 1323) FROM t1 LIMIT 0);
+GREATEST(a, 1323)
+20000716055804.035
+20080821000000.000
+1323.000
+SELECT LEAST(a, 1323) FROM t1;
+LEAST(a, 1323)
+1323.000
+1323.000
+0.000
+(SELECT LEAST(a, 1323) FROM t1) UNION ALL (SELECT LEAST(a, 1323) FROM t1 LIMIT 0);
+LEAST(a, 1323)
+1323.000
+1323.000
+0.000
+# Testing DECIMAL number 
+SELECT GREATEST(a, 1323.123456) FROM t1;
+GREATEST(a, 1323.123456)
+20000716055804.035000
+20080821000000.000000
+1323.123456
+(SELECT GREATEST(a, 1323.123456) FROM t1) UNION ALL (SELECT GREATEST(a, 1323.123456) FROM t1 LIMIT 0);
+GREATEST(a, 1323.123456)
+20000716055804.035000
+20080821000000.000000
+1323.123456
+SELECT LEAST(a, 1323.123456) FROM t1;
+LEAST(a, 1323.123456)
+1323.123456
+1323.123456
+0.000000
+(SELECT LEAST(a, 1323.123456) FROM t1) UNION ALL (SELECT LEAST(a, 1323.123456) FROM t1 LIMIT 0);
+LEAST(a, 1323.123456)
+1323.123456
+1323.123456
+0.000000
+# Testing REAL number
+SELECT GREATEST(a, 1323e0) FROM t1;
+GREATEST(a, 1323e0)
+20000716055804.035
+20080821000000
+1323
+(SELECT GREATEST(a, 1323e0) FROM t1) UNION ALL (SELECT GREATEST(a, 1323e0) FROM t1 LIMIT 0);
+GREATEST(a, 1323e0)
+20000716055804.035
+20080821000000
+1323
+SELECT LEAST(a, 1323e0) FROM t1;
+LEAST(a, 1323e0)
+1323
+1323
+0
+(SELECT LEAST(a, 1323e0) FROM t1) UNION ALL (SELECT LEAST(a, 1323e0) FROM t1 LIMIT 0);
+LEAST(a, 1323e0)
+1323
+1323
+0
+DROP TABLE t1;
+# Make sure precision of 6 fractional digits does not get lost
+CREATE TABLE t1 (a DATETIME(6));
+INSERT INTO t1 VALUES ('2001-01-01 01:01:01.123456');
+SELECT GREATEST(a,10), LEAST(a,10) FROM t1;
+GREATEST(a,10)	LEAST(a,10)
+20010101010101.123456	10.000000
+DROP TABLE t1;
 # End of 5.6 tests

=== added file 'mysql-test/suite/binlog/r/binlog_server_start_options.result'
--- a/mysql-test/suite/binlog/r/binlog_server_start_options.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/r/binlog_server_start_options.result	2012-02-17 06:34:47 +0000
@@ -0,0 +1 @@
+End of test binlog.binlog_server_start_options.test

=== added file 'mysql-test/suite/binlog/t/binlog_server_start_options.test'
--- a/mysql-test/suite/binlog/t/binlog_server_start_options.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/t/binlog_server_start_options.test	2012-02-17 06:34:47 +0000
@@ -0,0 +1,119 @@
+############################################################
+# Tests startup options for mysql server pertaining binlog 
+# This test doesnot require (as of now) to be run for all 
+# the binlogging format as server startup in the cases
+# below are independent of the format. We therefore run this
+# test in only statement format.
+############################################################
+--source include/have_binlog_format_statement.inc
+
+#------------------------------------------------------------------#
+# BUG 11766817 - 60030: CRASH ON MYSQLD STARTUP WHEN USING LOG-BIN #
+#------------------------------------------------------------------#
+
+#fetch the basedir from the already started server
+--let MYSQL_BASEDIR= `select @@basedir`
+
+--perl
+  use strict;
+  my $vardir= $ENV{'MYSQLTEST_VARDIR'} or die ('MYSQLTEST_VARDIR not set! Aborting!\n');
+  my $cnf1= $vardir.'cnf_1.cnf';
+  my $basedir=  $ENV{'MYSQL_BASEDIR'} or die "Basedir not set";
+
+# check if mysqld exists in basedir/sql folder or in basedir/bin 
+  my $share_folder =$basedir."/sql/share/";
+  if(-e $share_folder)
+  {
+   $basedir=$basedir."/sql/";
+  }
+
+#create a new datadir if there is none else remove and create a new one.
+  unless(-e $basedir."/data")
+  {
+    mkdir($basedir."/data", 0777) or die "Can't make data directory: $!";
+  }
+  else
+  {
+# Ideally this section should not execute as this means that the default
+# datadir exists which is not possible in the current scenario.
+    use File::Path;
+    rmtree($basedir."/data");
+    use strict;
+    mkdir($basedir."/data", 0777) or die "Can't make data directory: $!";
+  }
+
+#create cnf_1 file
+  my $content= "[mysqld]\n";
+  $content.="basedir=$basedir\n";
+  $content.="socket=socket-5620.sock\n";
+  $content.="log-error=error.log\n";
+  $content.="port=5620\n";
+  $content.="user=root\n";
+  $content.="core\n";
+  $content.="log-bin\n";
+  open(FILE_CNF, ">$cnf1") or die("Unable to create $cnf1: $!\n");
+  print FILE_CNF $content;
+  close(FILE_CNF);
+
+#export the cnf path to mtr
+  open(FILE_INC, '>include/cnf_include.inc');
+  print FILE_INC '--let $CNF1'." = $cnf1\n";
+  close(FILE_INC);
+EOF
+
+--source include/cnf_include.inc  
+--error 1
+--exec $MYSQLD --defaults-file=$CNF1
+
+#--------------------------------------------------------------------------------------------#
+# BUG 12929941 - SEGFAULT IN STRMAKE/CONVERT_DIRNAME WHEN USING --RELAY-LOG=SLAVE-RELAY-BIN  #
+#--------------------------------------------------------------------------------------------#
+
+--perl
+  use strict;
+
+# Initialize the variables
+  my $vardir= $ENV{'MYSQLTEST_VARDIR'} or die ('MYSQLTEST_VARDIR not set! Aborting!\n');
+  my $basedir=  $ENV{'MYSQL_BASEDIR'} or die "Basedir not set: $!\n";
+
+# check if mysqld exists in basedir/sql folder or in basedir/bin 
+  my $share_folder =$basedir."/sql/share/\0";
+  if(-e $share_folder)
+  {
+   $basedir=$basedir."/sql/";
+  }
+
+#create cnf_2 file.
+  my $cnf2= $vardir.'cnf_2.cnf';
+  my $content= "[mysqld]\n";
+  $content.="basedir=$basedir\n";
+  $content.="port=5620\n";
+  $content.="core\n";
+  open(FILE_CNF, ">$cnf2") or die("Unable to create $cnf2: $!\n");
+  print FILE_CNF $content;
+  close(FILE_CNF);
+
+#export the cnf path and "actual basedir" to mtr
+  open(FILE_INC, '>include/cnf_include.inc');
+  print FILE_INC '--let $CNF2'." = $cnf2\n";
+  print FILE_INC '--let REAL_BASEDIR'."=$basedir\n";
+  close(FILE_INC);
+EOF
+
+--source include/cnf_include.inc
+--error 1
+--exec $MYSQLD --defaults-file=$CNF2 --relay-log=slave-relay-bin
+
+#cleanup
+--perl
+  use File::Path;
+  my $basedir= $ENV{'REAL_BASEDIR'};
+  rmtree($basedir."/data/");
+EOF
+
+--remove_file include/cnf_include.inc
+--remove_file $CNF1
+--remove_file $CNF2
+
+--echo End of test binlog.binlog_server_start_options.test
+

=== added file 'mysql-test/suite/innodb/r/innodb-blob.result'
--- a/mysql-test/suite/innodb/r/innodb-blob.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/r/innodb-blob.result	2012-02-17 09:58:18 +0000
@@ -0,0 +1,119 @@
+CREATE TABLE t1 (a INT PRIMARY KEY, b TEXT) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b TEXT, c TEXT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1,REPEAT('a',30000)),(2,REPEAT('b',40000));
+SET DEBUG_SYNC='before_row_upd_extern SIGNAL have_latch WAIT_FOR go1';
+BEGIN;
+UPDATE t1 SET a=a+2;
+ROLLBACK;
+BEGIN;
+UPDATE t1 SET b=CONCAT(b,'foo');
+SET DEBUG_SYNC='now WAIT_FOR have_latch';
+SELECT a, RIGHT(b,20) FROM t1;
+SET DEBUG_SYNC='now SIGNAL go1';
+a	RIGHT(b,20)
+1	aaaaaaaaaaaaaaaaaaaa
+2	bbbbbbbbbbbbbbbbbbbb
+SET DEBUG='+d,row_ins_extern_checkpoint';
+SET DEBUG_SYNC='before_row_ins_extern_latch SIGNAL rec_not_blob WAIT_FOR crash';
+ROLLBACK;
+BEGIN;
+INSERT INTO t1 VALUES (3,REPEAT('c',50000));
+SET DEBUG_SYNC='now WAIT_FOR rec_not_blob';
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT @@tx_isolation;
+@@tx_isolation
+READ-UNCOMMITTED
+SELECT a, RIGHT(b,20) FROM t1;
+a	RIGHT(b,20)
+1	aaaaaaaaaaaaaaaaaaaa
+2	bbbbbbbbbbbbbbbbbbbb
+SELECT a FROM t1;
+a
+1
+2
+3
+SET DEBUG='+d,crash_commit_before';
+INSERT INTO t2 VALUES (42);
+ERROR HY000: Lost connection to MySQL server during query
+ERROR HY000: Lost connection to MySQL server during query
+CHECK TABLE t1;
+Table	Op	Msg_type	Msg_text
+test.t1	check	status	OK
+INSERT INTO t3 VALUES
+(1,REPEAT('d',7000),REPEAT('e',100)),
+(2,REPEAT('g',7000),REPEAT('h',100));
+SET DEBUG_SYNC='before_row_upd_extern SIGNAL have_latch WAIT_FOR go';
+UPDATE t3 SET c=REPEAT('f',3000) WHERE a=1;
+SET DEBUG_SYNC='now WAIT_FOR have_latch';
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT @@tx_isolation;
+@@tx_isolation
+READ-UNCOMMITTED
+SELECT a, RIGHT(b,20), RIGHT(c,20) FROM t3;
+SET DEBUG_SYNC='now SIGNAL go';
+a	RIGHT(b,20)	RIGHT(c,20)
+1	dddddddddddddddddddd	ffffffffffffffffffff
+2	gggggggggggggggggggg	hhhhhhhhhhhhhhhhhhhh
+CHECK TABLE t1,t2,t3;
+Table	Op	Msg_type	Msg_text
+test.t1	check	status	OK
+test.t2	check	status	OK
+test.t3	check	status	OK
+BEGIN;
+INSERT INTO t2 VALUES (347);
+SET DEBUG='+d,row_upd_extern_checkpoint';
+SET DEBUG_SYNC='before_row_upd_extern SIGNAL have_latch WAIT_FOR crash';
+UPDATE t3 SET c=REPEAT('i',3000) WHERE a=2;
+SET DEBUG_SYNC='now WAIT_FOR have_latch';
+SELECT info FROM information_schema.processlist
+WHERE state = 'debug sync point: before_row_upd_extern';
+info
+UPDATE t3 SET c=REPEAT('i',3000) WHERE a=2
+SET DEBUG='+d,crash_commit_before';
+COMMIT;
+ERROR HY000: Lost connection to MySQL server during query
+ERROR HY000: Lost connection to MySQL server during query
+CHECK TABLE t1,t2,t3;
+Table	Op	Msg_type	Msg_text
+test.t1	check	status	OK
+test.t2	check	status	OK
+test.t3	check	status	OK
+SELECT a, RIGHT(b,20), RIGHT(c,20) FROM t3;
+a	RIGHT(b,20)	RIGHT(c,20)
+1	dddddddddddddddddddd	ffffffffffffffffffff
+2	gggggggggggggggggggg	hhhhhhhhhhhhhhhhhhhh
+SELECT a FROM t3;
+a
+1
+2
+BEGIN;
+INSERT INTO t2 VALUES (33101);
+SET DEBUG='+d,row_upd_extern_checkpoint';
+SET DEBUG_SYNC='after_row_upd_extern SIGNAL have_latch WAIT_FOR crash';
+UPDATE t3 SET c=REPEAT('j',3000) WHERE a=2;
+SET DEBUG_SYNC='now WAIT_FOR have_latch';
+SELECT info FROM information_schema.processlist
+WHERE state = 'debug sync point: after_row_upd_extern';
+info
+UPDATE t3 SET c=REPEAT('j',3000) WHERE a=2
+SET DEBUG='+d,crash_commit_before';
+COMMIT;
+ERROR HY000: Lost connection to MySQL server during query
+ERROR HY000: Lost connection to MySQL server during query
+CHECK TABLE t1,t2,t3;
+Table	Op	Msg_type	Msg_text
+test.t1	check	status	OK
+test.t2	check	status	OK
+test.t3	check	status	OK
+SELECT a, RIGHT(b,20), RIGHT(c,20) FROM t3;
+a	RIGHT(b,20)	RIGHT(c,20)
+1	dddddddddddddddddddd	ffffffffffffffffffff
+2	gggggggggggggggggggg	hhhhhhhhhhhhhhhhhhhh
+SELECT a FROM t3;
+a
+1
+2
+SELECT * FROM t2;
+a
+DROP TABLE t1,t2,t3;

=== added file 'mysql-test/suite/innodb/t/innodb-blob.test'
--- a/mysql-test/suite/innodb/t/innodb-blob.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/t/innodb-blob.test	2012-02-17 09:58:18 +0000
@@ -0,0 +1,216 @@
+# Bug#13721257 RACE CONDITION IN UPDATES OR INSERTS OF WIDE RECORDS
+# Test what happens when a record is inserted or updated so that some
+# columns are stored off-page.
+
+--source include/have_innodb.inc
+
+# DEBUG_SYNC must be compiled in.
+--source include/have_debug_sync.inc
+
+# Valgrind would complain about memory leaks when we crash on purpose.
+--source include/not_valgrind.inc
+# Embedded server does not support crashing
+--source include/not_embedded.inc
+# Avoid CrashReporter popup on Mac
+--source include/not_crashrep.inc
+
+CREATE TABLE t1 (a INT PRIMARY KEY, b TEXT) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b TEXT, c TEXT) ENGINE=InnoDB;
+
+INSERT INTO t1 VALUES (1,REPEAT('a',30000)),(2,REPEAT('b',40000));
+SET DEBUG_SYNC='before_row_upd_extern SIGNAL have_latch WAIT_FOR go1';
+BEGIN;
+# This will not block, because it will not store new BLOBs.
+UPDATE t1 SET a=a+2;
+ROLLBACK;
+BEGIN;
+--send
+UPDATE t1 SET b=CONCAT(b,'foo');
+
+connect (con1,localhost,root,,);
+SET DEBUG_SYNC='now WAIT_FOR have_latch';
+
+# this one should block due to the clustered index tree and leaf page latches
+--send
+SELECT a, RIGHT(b,20) FROM t1;
+
+connect (con2,localhost,root,,);
+
+# Check that the above SELECT is blocked
+let $wait_condition=
+  select count(*) = 1 from information_schema.processlist
+  where state = 'Sending data' and
+        info = 'SELECT a, RIGHT(b,20) FROM t1';
+--source include/wait_condition.inc
+
+SET DEBUG_SYNC='now SIGNAL go1';
+
+connection con1;
+reap;
+connection default;
+reap;
+SET DEBUG='+d,row_ins_extern_checkpoint';
+SET DEBUG_SYNC='before_row_ins_extern_latch SIGNAL rec_not_blob WAIT_FOR crash';
+ROLLBACK;
+BEGIN;
+--send
+INSERT INTO t1 VALUES (3,REPEAT('c',50000));
+
+connection con1;
+SET DEBUG_SYNC='now WAIT_FOR rec_not_blob';
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT @@tx_isolation;
+
+# this one should see (3,NULL_BLOB)
+SELECT a, RIGHT(b,20) FROM t1;
+SELECT a FROM t1;
+
+# Request a crash, and restart the server.
+SET DEBUG='+d,crash_commit_before';
+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--error 2013
+INSERT INTO t2 VALUES (42);
+
+disconnect con1;
+disconnect con2;
+connection default;
+# This connection should notice the crash as well.
+--error 2013
+reap;
+
+# Write file to make mysql-test-run.pl restart the server
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+--disable_reconnect
+
+CHECK TABLE t1;
+
+INSERT INTO t3 VALUES
+       (1,REPEAT('d',7000),REPEAT('e',100)),
+       (2,REPEAT('g',7000),REPEAT('h',100));
+SET DEBUG_SYNC='before_row_upd_extern SIGNAL have_latch WAIT_FOR go';
+# This should move column b off-page.
+--send
+UPDATE t3 SET c=REPEAT('f',3000) WHERE a=1;
+
+connect (con1,localhost,root,,);
+SET DEBUG_SYNC='now WAIT_FOR have_latch';
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT @@tx_isolation;
+
+# this one should block
+-- send
+SELECT a, RIGHT(b,20), RIGHT(c,20) FROM t3;
+
+connect (con2,localhost,root,,);
+
+# Check that the above SELECT is blocked
+let $wait_condition=
+  select count(*) = 1 from information_schema.processlist
+  where state = 'Sending data' and
+        info = 'SELECT a, RIGHT(b,20), RIGHT(c,20) FROM t3';
+--source include/wait_condition.inc
+
+SET DEBUG_SYNC='now SIGNAL go';
+
+connection con1;
+reap;
+disconnect con1;
+
+connection default;
+reap;
+
+CHECK TABLE t1,t2,t3;
+
+connection con2;
+BEGIN;
+INSERT INTO t2 VALUES (347);
+connection default;
+
+# The row_upd_extern_checkpoint was removed in Bug#13721257,
+# because the mini-transaction of the B-tree modification would
+# remain open while we are writing the off-page columns and are
+# stuck in the DEBUG_SYNC. A checkpoint involves a flush, which
+# would wait for the buffer-fix to cease.
+SET DEBUG='+d,row_upd_extern_checkpoint';
+SET DEBUG_SYNC='before_row_upd_extern SIGNAL have_latch WAIT_FOR crash';
+# This should move column b off-page.
+--send
+UPDATE t3 SET c=REPEAT('i',3000) WHERE a=2;
+
+connection con2;
+SET DEBUG_SYNC='now WAIT_FOR have_latch';
+
+# Check that the above UPDATE is blocked
+SELECT info FROM information_schema.processlist
+WHERE state = 'debug sync point: before_row_upd_extern';
+
+# Request a crash, and restart the server.
+SET DEBUG='+d,crash_commit_before';
+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--error 2013
+COMMIT;
+
+disconnect con2;
+connection default;
+# This connection should notice the crash as well.
+--error 2013
+reap;
+
+# Write file to make mysql-test-run.pl restart the server
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+--disable_reconnect
+
+CHECK TABLE t1,t2,t3;
+SELECT a, RIGHT(b,20), RIGHT(c,20) FROM t3;
+SELECT a FROM t3;
+
+connect (con2,localhost,root,,);
+BEGIN;
+INSERT INTO t2 VALUES (33101);
+connection default;
+
+# The row_upd_extern_checkpoint was removed in Bug#13721257,
+# because the mini-transaction of the B-tree modification would
+# remain open while we are writing the off-page columns and are
+# stuck in the DEBUG_SYNC. A checkpoint involves a flush, which
+# would wait for the buffer-fix to cease.
+SET DEBUG='+d,row_upd_extern_checkpoint';
+SET DEBUG_SYNC='after_row_upd_extern SIGNAL have_latch WAIT_FOR crash';
+# This should move column b off-page.
+--send
+UPDATE t3 SET c=REPEAT('j',3000) WHERE a=2;
+
+connection con2;
+SET DEBUG_SYNC='now WAIT_FOR have_latch';
+
+# Check that the above UPDATE is blocked
+SELECT info FROM information_schema.processlist
+WHERE state = 'debug sync point: after_row_upd_extern';
+
+# Request a crash, and restart the server.
+SET DEBUG='+d,crash_commit_before';
+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--error 2013
+COMMIT;
+
+disconnect con2;
+connection default;
+# This connection should notice the crash as well.
+--error 2013
+reap;
+
+# Write file to make mysql-test-run.pl restart the server
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+--disable_reconnect
+
+CHECK TABLE t1,t2,t3;
+SELECT a, RIGHT(b,20), RIGHT(c,20) FROM t3;
+SELECT a FROM t3;
+
+SELECT * FROM t2;
+
+DROP TABLE t1,t2,t3;

=== modified file 'mysql-test/t/type_newdecimal.test'
--- a/mysql-test/t/type_newdecimal.test	2011-10-14 09:40:10 +0000
+++ b/mysql-test/t/type_newdecimal.test	2012-02-17 13:55:18 +0000
@@ -1570,3 +1570,22 @@ SELECT d1 * d2 FROM t1;
 
 DROP TABLE t1;
 
+
+--echo #
+--echo # Start of 5.6 tests
+--echo #
+
+--echo #
+--echo # Bug#13375823 - FSP(DECIMAL) RESULT DIFFERENCE WITH QUERY USING UNION ALL
+--echo #
+CREATE TABLE t1 (a DECIMAL(20,3) NOT NULL);
+INSERT INTO t1 VALUES (20000716055804.035);
+INSERT INTO t1 VALUES (20080821000000.000);
+INSERT INTO t1 VALUES (0);
+SELECT GREATEST(a, 1323) FROM t1;
+(SELECT GREATEST(a, 1323) FROM t1) UNION ALL (SELECT GREATEST(a, 1323) FROM t1 LIMIT 0);
+DROP TABLE t1;
+
+--echo #
+--echo # End of 5.6 tests
+--echo #

=== modified file 'mysql-test/t/type_temporal_fractional.test'
--- a/mysql-test/t/type_temporal_fractional.test	2012-02-02 10:58:18 +0000
+++ b/mysql-test/t/type_temporal_fractional.test	2012-02-17 13:55:18 +0000
@@ -7635,4 +7635,34 @@ SELECT
   CAST(-0.1111111111 AS DATE);
 
 
+--echo #
+--echo # Bug#13375823 - FSP(DECIMAL) RESULT DIFFERENCE WITH QUERY USING UNION ALL
+--echo #
+CREATE TABLE t1 (a DATETIME(3) NOT NULL);
+INSERT INTO t1 VALUES ('2000-07-16 05:58:04.035');
+INSERT INTO t1 VALUES ('2008-08-21 00:00:00.000');
+INSERT INTO t1 VALUES ('0000-00-00 00:00:00.000');
+--echo # Testing INT number
+SELECT GREATEST(a, 1323) FROM t1;
+(SELECT GREATEST(a, 1323) FROM t1) UNION ALL (SELECT GREATEST(a, 1323) FROM t1 LIMIT 0);
+SELECT LEAST(a, 1323) FROM t1;
+(SELECT LEAST(a, 1323) FROM t1) UNION ALL (SELECT LEAST(a, 1323) FROM t1 LIMIT 0);
+--echo # Testing DECIMAL number 
+SELECT GREATEST(a, 1323.123456) FROM t1;
+(SELECT GREATEST(a, 1323.123456) FROM t1) UNION ALL (SELECT GREATEST(a, 1323.123456) FROM t1 LIMIT 0);
+SELECT LEAST(a, 1323.123456) FROM t1;
+(SELECT LEAST(a, 1323.123456) FROM t1) UNION ALL (SELECT LEAST(a, 1323.123456) FROM t1 LIMIT 0);
+--echo # Testing REAL number
+SELECT GREATEST(a, 1323e0) FROM t1;
+(SELECT GREATEST(a, 1323e0) FROM t1) UNION ALL (SELECT GREATEST(a, 1323e0) FROM t1 LIMIT 0);
+SELECT LEAST(a, 1323e0) FROM t1;
+(SELECT LEAST(a, 1323e0) FROM t1) UNION ALL (SELECT LEAST(a, 1323e0) FROM t1 LIMIT 0);
+DROP TABLE t1;
+
+--echo # Make sure precision of 6 fractional digits does not get lost
+CREATE TABLE t1 (a DATETIME(6));
+INSERT INTO t1 VALUES ('2001-01-01 01:01:01.123456');
+SELECT GREATEST(a,10), LEAST(a,10) FROM t1;
+DROP TABLE t1;
+
 --echo # End of 5.6 tests

=== modified file 'mysys/CMakeLists.txt'
--- a/mysys/CMakeLists.txt	2011-10-11 04:27:52 +0000
+++ b/mysys/CMakeLists.txt	2012-02-17 10:30:31 +0000
@@ -15,6 +15,10 @@
 
 INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/mysys)
 
+IF(SSL_DEFINES)
+ADD_DEFINITIONS(${SSL_DEFINES})
+ENDIF()
+
 SET(MYSYS_SOURCES  array.c charset-def.c charset.c checksum.c default.c
 				errors.c hash.c list.c md5.c mf_cache.c mf_dirname.c mf_fn_ext.c
 				mf_format.c mf_getdate.c mf_iocache.c mf_iocache2.c mf_keycache.c 

=== modified file 'mysys/md5.c'
--- a/mysys/md5.c	2009-03-09 18:57:03 +0000
+++ b/mysys/md5.c	2012-02-17 10:30:31 +0000
@@ -38,6 +38,11 @@
    copyright in any changes I have made; this code remains in the
    public domain.  */
 
+/*
+  Skip entirely if built with OpenSSL/YaSSL support.
+*/
+#if !defined(HAVE_OPENSSL) && !defined(HAVE_YASSL)
+
 #include <my_global.h>
 #include <m_string.h>
 #include "my_md5.h"
@@ -323,3 +328,5 @@ main (int argc, char **argv)
   return 0;
 }
 #endif /* TEST */
+
+#endif /* !defined(HAVE_OPENSSL) && !defined(HAVE_YASSL) */

=== modified file 'mysys/mf_format.c'
--- a/mysys/mf_format.c	2011-08-29 12:08:58 +0000
+++ b/mysys/mf_format.c	2012-02-17 06:34:47 +0000
@@ -40,11 +40,13 @@ char * fn_format(char * to, const char *
   name+=(length=dirname_part(dev, (startpos=(char *) name), &dev_length));
   if (length == 0 || (flag & MY_REPLACE_DIR))
   {
+    DBUG_ASSERT(dir != NULL);
     /* Use given directory */
     convert_dirname(dev,dir,NullS);		/* Fix to this OS */
   }
   else if ((flag & MY_RELATIVE_PATH) && !test_if_hard_path(dev))
   {
+    DBUG_ASSERT(dir != NULL);
     /* Put 'dir' before the given path */
     strmake(buff,dev,sizeof(buff)-1);
     pos=convert_dirname(dev,dir,NullS);

=== modified file 'mysys/sha1.c'
--- a/mysys/sha1.c	2011-06-30 15:50:45 +0000
+++ b/mysys/sha1.c	2012-02-17 10:30:31 +0000
@@ -84,6 +84,41 @@
 #include "sha1.h"
 
 /*
+  Skip entire file if built with YaSSL.
+*/
+#ifndef HAVE_YASSL
+
+#ifdef HAVE_OPENSSL
+
+/*
+  Wrapper for OpenSSL SH1 methods.
+*/
+
+int mysql_sha1_reset(SHA1_CONTEXT *context)
+{
+  return SHA1_Init(context);
+}
+
+
+int mysql_sha1_input(SHA1_CONTEXT *context, const uint8 *message_array,
+                     unsigned length)
+{
+  return SHA1_Update(context, message_array, length);
+}
+
+
+int mysql_sha1_result(SHA1_CONTEXT *context,
+                      uint8 Message_Digest[SHA1_HASH_SIZE])
+{
+  return SHA1_Final(Message_Digest, context);
+}
+
+#else /* HAVE_OPENSSL */
+/*
+  Native MySQL SHA1 implementation.
+*/
+
+/*
   Define the SHA1 circular left shift macro
 */
 
@@ -420,3 +455,6 @@ static void SHA1PadMessage(SHA1_CONTEXT
 
   SHA1ProcessMessageBlock(context);
 }
+#endif /* HAVE_OPENSSL */
+
+#endif /* HAVE_YASSL */

=== modified file 'sql/CMakeLists.txt'
--- a/sql/CMakeLists.txt	2012-02-16 23:25:47 +0000
+++ b/sql/CMakeLists.txt	2012-02-18 22:51:38 +0000
@@ -69,6 +69,7 @@ SET(SQL_SHARED_SOURCES
   keycaches.cc
   lock.cc
   log.cc
+  md5.cc
   mdl.cc
   mf_iocache.cc
   my_decimal.cc
@@ -89,6 +90,7 @@ SET(SQL_SHARED_SOURCES
   rpl_handler.cc
   scheduler.cc 
   set_var.cc 
+  sha1.cc
   sha2.cc
   signal_handler.cc
   sp.cc

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	2012-02-16 23:25:47 +0000
+++ b/sql/handler.cc	2012-02-18 22:51:38 +0000
@@ -4626,7 +4626,8 @@ handler::multi_range_read_info_const(uin
     else
     {
       DBUG_EXECUTE_IF("crash_records_in_range", DBUG_SUICIDE(););
-      DBUG_ASSERT(min_endp || max_endp);
+      // Fails - reintroduce when fixed
+      // DBUG_ASSERT(min_endp || max_endp);
       if (HA_POS_ERROR == (rows= this->records_in_range(keyno, min_endp, 
                                                         max_endp)))
       {

=== modified file 'sql/item.h'
--- a/sql/item.h	2012-02-02 13:44:26 +0000
+++ b/sql/item.h	2012-02-17 13:55:18 +0000
@@ -666,6 +666,15 @@ public:
       return REAL_RESULT; 
     return result_type();
   }
+  /**
+    Similar to result_type() but makes DATE, DATETIME, TIMESTAMP
+    pretend to be numbers rather than strings.
+  */
+  inline enum Item_result temporal_with_date_as_number_result_type() const
+  {
+    return is_temporal_with_date() ? 
+           (decimals ? DECIMAL_RESULT : INT_RESULT) : result_type();
+  }
   virtual Item_result cast_to_int_type() const { return result_type(); }
   virtual enum_field_types string_field_type() const;
   virtual enum_field_types field_type() const;

=== modified file 'sql/item_func.cc'
--- a/sql/item_func.cc	2012-02-17 19:46:49 +0000
+++ b/sql/item_func.cc	2012-02-18 22:51:38 +0000
@@ -2703,12 +2703,13 @@ double Item_func_units::val_real()
 
 void Item_func_min_max::fix_length_and_dec()
 {
+  uint string_arg_count= 0;
   int max_int_part=0;
   bool datetime_found= FALSE;
   decimals=0;
   max_length=0;
   maybe_null=0;
-  cmp_type=args[0]->result_type();
+  cmp_type= args[0]->temporal_with_date_as_number_result_type();
 
   for (uint i=0 ; i < arg_count ; i++)
   {
@@ -2717,7 +2718,10 @@ void Item_func_min_max::fix_length_and_d
     set_if_bigger(max_int_part, args[i]->decimal_int_part());
     if (args[i]->maybe_null)
       maybe_null=1;
-    cmp_type=item_cmp_type(cmp_type,args[i]->result_type());
+    cmp_type= item_cmp_type(cmp_type,
+                            args[i]->temporal_with_date_as_number_result_type());
+    if (args[i]->result_type() == STRING_RESULT)
+     string_arg_count++;
     if (args[i]->result_type() != ROW_RESULT &&
         args[i]->is_temporal_with_date())
     {
@@ -2726,8 +2730,10 @@ void Item_func_min_max::fix_length_and_d
         datetime_item= args[i];
     }
   }
-  if (cmp_type == STRING_RESULT)
+  
+  if (string_arg_count == arg_count)
   {
+    // We compare as strings only if all arguments were strings.
     agg_arg_charsets_for_string_result_with_comparison(collation,
                                                        args, arg_count);
     if (datetime_found)
@@ -3106,6 +3112,15 @@ my_decimal *Item_func_min_max::val_decim
       break;
     }
   }
+  
+  if (res)
+  {
+    /*
+      Need this to make val_str() always return fixed
+      number of fractional digits, according to "decimals".
+    */
+    my_decimal_round(E_DEC_FATAL_ERROR, res, decimals, false, res);
+  }
   return res;
 }
 

=== modified file 'sql/item_func.h'
--- a/sql/item_func.h	2012-02-08 15:49:24 +0000
+++ b/sql/item_func.h	2012-02-18 22:51:38 +0000
@@ -961,7 +961,18 @@ public:
   bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
   bool get_time(MYSQL_TIME *ltime);  
   void fix_length_and_dec();
-  enum Item_result result_type () const { return cmp_type; }
+  enum Item_result result_type () const
+  {
+    /*
+      If we compare as dates, then:
+      - field_type is MYSQL_TYPE_VARSTRING, MYSQL_TYPE_DATETIME
+        or MYSQL_TYPE_DATE.
+      - cmp_type is INT_RESULT or DECIMAL_RESULT,
+        depending on the amount of fractional digits.
+      We need to return STRING_RESULT in this case instead of cmp_type.
+    */
+    return compare_as_dates ? STRING_RESULT : cmp_type;
+  }
   enum Item_result cast_to_int_type () const
   {
     /*

=== modified file 'sql/item_strfunc.cc'
--- a/sql/item_strfunc.cc	2012-02-16 23:25:47 +0000
+++ b/sql/item_strfunc.cc	2012-02-18 22:51:38 +0000
@@ -181,7 +181,7 @@ String *Item_func_md5::val_str_ascii(Str
     uchar digest[16];
 
     null_value=0;
-    MY_MD5_HASH(digest,(uchar *) sptr->ptr(), sptr->length());
+    compute_md5_hash((char *) digest, (const char *) sptr->ptr(), sptr->length());
     if (str->alloc(32))				// Ensure that memory is free
     {
       null_value=1;
@@ -217,16 +217,11 @@ String *Item_func_sha::val_str_ascii(Str
   str->set_charset(&my_charset_bin);
   if (sptr)  /* If we got value different from NULL */
   {
-    SHA1_CONTEXT context;  /* Context used to generate SHA1 hash */
     /* Temporary buffer to store 160bit digest */
     uint8 digest[SHA1_HASH_SIZE];
-    mysql_sha1_reset(&context);  /* We do not have to check for error here */
-    /* No need to check error as the only case would be too long message */
-    mysql_sha1_input(&context,
-                     (const uchar *) sptr->ptr(), sptr->length());
-    /* Ensure that memory is free and we got result */
-    if (!( str->alloc(SHA1_HASH_SIZE*2) ||
-           (mysql_sha1_result(&context,digest))))
+    compute_sha1_hash(digest, (const char *) sptr->ptr(), sptr->length());
+    /* Ensure that memory is free */
+    if (!(str->alloc(SHA1_HASH_SIZE * 2)))
     {
       array_to_hex((char *) str->ptr(), digest, SHA1_HASH_SIZE);
       str->length((uint)  SHA1_HASH_SIZE*2);

=== added file 'sql/md5.cc'
--- a/sql/md5.cc	1970-01-01 00:00:00 +0000
+++ b/sql/md5.cc	2012-02-17 10:30:31 +0000
@@ -0,0 +1,68 @@
+/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+
+/**
+  @file
+
+  @brief
+  Wrapper functions for OpenSSL, YaSSL and MySQL's MD5
+  implementations. Also provides a Compatibility layer
+  to make available YaSSL's MD5 implementation.
+*/
+
+#include <my_global.h>
+#include <my_md5.h>
+
+#ifdef HAVE_YASSL
+
+#include "md5.hpp"
+
+/**
+  Compute MD5 message digest.
+
+  @param digest [out]  Computed MD5 digest
+  @param buf    [in]   Message to be computed
+  @param len    [in]   Length of the message
+
+  @return              void
+*/
+void my_md5_hash(char *digest, const char *buf, int len)
+{
+  TaoCrypt::MD5 hasher;
+  hasher.Update((TaoCrypt::byte *) buf, len);
+  hasher.Final((TaoCrypt::byte *) digest);
+}
+#endif /* HAVE_YASSL */
+
+
+/**
+    Wrapper function to compute MD5 message digest.
+
+    @param digest [out]  Computed MD5 digest
+    @param buf    [in]   Message to be computed
+    @param len    [in]   Length of the message
+
+    @return              void
+*/
+void compute_md5_hash(char *digest, const char *buf, int len)
+{
+#ifdef HAVE_YASSL
+  my_md5_hash(digest, buf, len);
+#else
+  MY_MD5_HASH((unsigned char *) digest, (unsigned char const *) buf, len);
+#endif /* HAVE_YASSL */
+}
+

=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc	2012-02-16 23:25:47 +0000
+++ b/sql/mysqld.cc	2012-02-18 22:51:38 +0000
@@ -3214,6 +3214,15 @@ rpl_make_log_name(const char *opt,
   const char *base= opt ? opt : def;
   unsigned int options=
     MY_REPLACE_EXT | MY_UNPACK_FILENAME | MY_SAFE_PATH;
+
+  /* mysql_real_data_home_ptr  may be null if no value of datadir has been
+     specified through command-line or througha cnf file. If that is the 
+     case we make mysql_real_data_home_ptr point to mysql_real_data_home
+     which, in that case holds the default path for data-dir.
+  */ 
+  if(mysql_real_data_home_ptr == NULL)
+    mysql_real_data_home_ptr= mysql_real_data_home;
+
   if (fn_format(buff, base, mysql_real_data_home_ptr, ext, options))
     DBUG_RETURN(strdup(buff));
   else
@@ -4294,6 +4303,10 @@ a file name for --log-bin-index option",
   if (ha_init_errors())
     DBUG_RETURN(1);
 
+  if (opt_ignore_builtin_innodb)
+    sql_print_warning("ignore-builtin-innodb is ignored "
+                      "and will be removed in future releases.");
+
   if (plugin_init(&remaining_argc, remaining_argv,
                   (opt_noacl ? PLUGIN_INIT_SKIP_PLUGIN_TABLE : 0) |
                   (opt_help ? PLUGIN_INIT_SKIP_INITIALIZATION : 0)))

=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc	2012-02-16 15:15:41 +0000
+++ b/sql/opt_range.cc	2012-02-17 08:50:19 +0000
@@ -4825,7 +4825,8 @@ static double ror_scan_selectivity(const
                      rec_per_key[tuple_arg->part]))    // (3)
       {
         DBUG_EXECUTE_IF("crash_records_in_range", DBUG_SUICIDE(););
-        DBUG_ASSERT(min_range.length > 0);
+        // Fails - reintroduce when fixed
+        // DBUG_ASSERT(min_range.length > 0);
         records= (table->file->
                   records_in_range(scan->keynr, &min_range, &max_range));
       }

=== modified file 'sql/password.c'
--- a/sql/password.c	2012-02-16 10:52:45 +0000
+++ b/sql/password.c	2012-02-17 10:30:31 +0000
@@ -399,6 +399,29 @@ my_crypt(char *to, const uchar *s1, cons
     *to++= *s1++ ^ *s2++;
 }
 
+/**
+  Compute two stage SHA1 hash of the password :
+
+    hash_stage1=sha1("password")
+    hash_stage2=sha1(hash_stage1)
+
+  @param password    [IN]   Password string.
+  @param pass_len    [IN]   Length of the password.
+  @param hash_stage1 [OUT]  sha1(password)
+  @param hash_stage2 [OUT]  sha1(hash_stage1)
+*/
+
+inline static
+void compute_two_stage_sha1_hash(const char *password, size_t pass_len,
+                                 uint8 *hash_stage1, uint8 *hash_stage2)
+{
+  /* Stage 1: hash password */
+  compute_sha1_hash(hash_stage1, password, pass_len);
+
+  /* Stage 2 : hash first stage's output. */
+  compute_sha1_hash(hash_stage2, (const char *) hash_stage1, SHA1_HASH_SIZE);
+}
+
 
 /*
     MySQL 4.1.1 password hashing: SHA conversion (see RFC 2289, 3174) twice
@@ -416,18 +439,11 @@ my_crypt(char *to, const uchar *s1, cons
 void my_make_scrambled_password(char *to, const char *password,
                                 size_t pass_len)
 {
-  SHA1_CONTEXT sha1_context;
   uint8 hash_stage2[SHA1_HASH_SIZE];
 
-  mysql_sha1_reset(&sha1_context);
-  /* stage 1: hash password */
-  mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) pass_len);
-  mysql_sha1_result(&sha1_context, (uint8 *) to);
-  /* stage 2: hash stage1 output */
-  mysql_sha1_reset(&sha1_context);
-  mysql_sha1_input(&sha1_context, (uint8 *) to, SHA1_HASH_SIZE);
-  /* separate buffer is used to pass 'to' in octet2hex */
-  mysql_sha1_result(&sha1_context, hash_stage2);
+  /* Two stage SHA1 hash of the password. */
+  compute_two_stage_sha1_hash(password, pass_len, (uint8 *) to, hash_stage2);
+
   /* convert hash_stage2 to hex string */
   *to++= PVERSION41_CHAR;
   octet2hex(to, (const char*) hash_stage2, SHA1_HASH_SIZE);
@@ -471,24 +487,16 @@ void make_scrambled_password(char *to, c
 void
 scramble(char *to, const char *message, const char *password)
 {
-  SHA1_CONTEXT sha1_context;
   uint8 hash_stage1[SHA1_HASH_SIZE];
   uint8 hash_stage2[SHA1_HASH_SIZE];
 
-  mysql_sha1_reset(&sha1_context);
-  /* stage 1: hash password */
-  mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) strlen(password));
-  mysql_sha1_result(&sha1_context, hash_stage1);
-  /* stage 2: hash stage 1; note that hash_stage2 is stored in the database */
-  mysql_sha1_reset(&sha1_context);
-  mysql_sha1_input(&sha1_context, hash_stage1, SHA1_HASH_SIZE);
-  mysql_sha1_result(&sha1_context, hash_stage2);
+  /* Two stage SHA1 hash of the password. */
+  compute_two_stage_sha1_hash(password, strlen(password), hash_stage1,
+                              hash_stage2);
+
   /* create crypt string as sha1(message, hash_stage2) */;
-  mysql_sha1_reset(&sha1_context);
-  mysql_sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH);
-  mysql_sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
-  /* xor allows 'from' and 'to' overlap: lets take advantage of it */
-  mysql_sha1_result(&sha1_context, (uint8 *) to);
+  compute_sha1_hash_multi((uint8 *) to, message, SCRAMBLE_LENGTH,
+                          (const char *) hash_stage2, SHA1_HASH_SIZE);
   my_crypt(to, (const uchar *) to, hash_stage1, SCRAMBLE_LENGTH);
 }
 
@@ -517,21 +525,18 @@ my_bool
 check_scramble(const uchar *scramble_arg, const char *message,
                const uint8 *hash_stage2)
 {
-  SHA1_CONTEXT sha1_context;
   uint8 buf[SHA1_HASH_SIZE];
   uint8 hash_stage2_reassured[SHA1_HASH_SIZE];
 
-  mysql_sha1_reset(&sha1_context);
   /* create key to encrypt scramble */
-  mysql_sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH);
-  mysql_sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
-  mysql_sha1_result(&sha1_context, buf);
+  compute_sha1_hash_multi(buf, message, SCRAMBLE_LENGTH,
+                          (const char *) hash_stage2, SHA1_HASH_SIZE);
   /* encrypt scramble */
-    my_crypt((char *) buf, buf, scramble_arg, SCRAMBLE_LENGTH);
+  my_crypt((char *) buf, buf, scramble_arg, SCRAMBLE_LENGTH);
+
   /* now buf supposedly contains hash_stage1: so we can get hash_stage2 */
-  mysql_sha1_reset(&sha1_context);
-  mysql_sha1_input(&sha1_context, buf, SHA1_HASH_SIZE);
-  mysql_sha1_result(&sha1_context, hash_stage2_reassured);
+  compute_sha1_hash(hash_stage2_reassured, (const char *) buf, SHA1_HASH_SIZE);
+
   return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE);
 }
 

=== modified file 'sql/rpl_info_factory.cc'
--- a/sql/rpl_info_factory.cc	2011-12-13 12:13:37 +0000
+++ b/sql/rpl_info_factory.cc	2012-02-17 18:30:34 +0000
@@ -387,7 +387,13 @@ bool Rpl_info_factory::decide_repository
   DBUG_ENTER("Rpl_info_factory::decide_repository");
 
   if (option == INFO_REPOSITORY_DUMMY)
+  {
+    delete (*handler_src);
+    *handler_src= NULL;
+    info->set_rpl_info_handler(*handler_dest);
+    info->set_rpl_info_type(option);
     DBUG_RETURN(FALSE);
+  }
 
   DBUG_ASSERT((*handler_src) != NULL && (*handler_dest) != NULL &&
               (*handler_src) != (*handler_dest));

=== added file 'sql/sha1.cc'
--- a/sql/sha1.cc	1970-01-01 00:00:00 +0000
+++ b/sql/sha1.cc	2012-02-17 10:30:31 +0000
@@ -0,0 +1,121 @@
+/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+
+/**
+  @file
+
+  @brief
+  Wrapper functions for OpenSSL, YaSSL and MySQL's SHA1
+  implementations. Also provides a Compatibility layer
+  to make available YaSSL's SHA1 implementation.
+*/
+
+#include <my_global.h>
+#include <sha1.h>
+
+#ifdef HAVE_YASSL
+#include "sha.hpp"
+
+/**
+  Compute SHA1 message digest using YaSSL.
+
+  @param digest [out]  Computed SHA1 digest
+  @param buf    [in]   Message to be computed
+  @param len    [in]   Length of the message
+
+  @return              void
+*/
+void mysql_sha1_yassl(uint8 *digest, const char *buf, int len)
+{
+  TaoCrypt::SHA hasher;
+  hasher.Update((const TaoCrypt::byte *) buf, len);
+  hasher.Final ((TaoCrypt::byte *) digest);
+}
+
+/**
+  Compute SHA1 message digest for two messages in order to
+  emulate sha1(msg1, msg2) using YaSSL.
+
+  @param digest [out]  Computed SHA1 digest
+  @param buf1   [in]   First message
+  @param len1   [in]   Length of first message
+  @param buf2   [in]   Second message
+  @param len2   [in]   Length of second message
+
+  @return              void
+*/
+void mysql_sha1_multi_yassl(uint8 *digest, const char *buf1, int len1,
+                            const char *buf2, int len2)
+{
+  TaoCrypt::SHA hasher;
+  hasher.Update((const TaoCrypt::byte *) buf1, len1);
+  hasher.Update((const TaoCrypt::byte *) buf2, len2);
+  hasher.Final((TaoCrypt::byte *) digest);
+}
+
+#endif /* HAVE_YASSL */
+
+
+/**
+  Wrapper function to compute SHA1 message digest.
+
+  @param digest [out]  Computed SHA1 digest
+  @param buf    [in]   Message to be computed
+  @param len    [in]   Length of the message
+
+  @return              void
+*/
+void compute_sha1_hash(uint8 *digest, const char *buf, int len)
+{
+#ifdef HAVE_YASSL
+  mysql_sha1_yassl(digest, buf, len);
+#else
+  SHA1_CONTEXT sha1_context;
+
+  mysql_sha1_reset(&sha1_context);
+  mysql_sha1_input(&sha1_context, (const uint8 *) buf, len);
+  mysql_sha1_result(&sha1_context, digest);
+#endif /* HAVE_YASSL */
+}
+
+
+/**
+  Wrapper function to compute SHA1 message digest for
+  two messages in order to emulate sha1(msg1, msg2).
+
+  @param digest [out]  Computed SHA1 digest
+  @param buf1   [in]   First message
+  @param len1   [in]   Length of first message
+  @param buf2   [in]   Second message
+  @param len2   [in]   Length of second message
+
+  @return              void
+*/
+void compute_sha1_hash_multi(uint8 *digest, const char *buf1, int len1,
+                             const char *buf2, int len2)
+{
+#ifdef HAVE_YASSL
+  mysql_sha1_multi_yassl(digest, buf1, len1, buf2, len2);
+#else
+  SHA1_CONTEXT sha1_context;
+
+  mysql_sha1_reset(&sha1_context);
+  mysql_sha1_input(&sha1_context, (const uint8 *) buf1, len1);
+  mysql_sha1_input(&sha1_context, (const uint8 *) buf2, len2);
+  mysql_sha1_result(&sha1_context, digest);
+#endif /* HAVE_YASSL */
+}
+

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2012-02-16 23:25:47 +0000
+++ b/sql/sql_class.cc	2012-02-18 22:51:38 +0000
@@ -1422,6 +1422,7 @@ THD::~THD()
 #ifndef EMBEDDED_LIBRARY
   if (rli_fake)
   {
+    rli_fake->end_info();
     delete rli_fake;
     rli_fake= NULL;
   }

=== modified file 'sql/sql_plugin.cc'
--- a/sql/sql_plugin.cc	2012-02-16 09:51:14 +0000
+++ b/sql/sql_plugin.cc	2012-02-17 13:18:29 +0000
@@ -1300,10 +1300,6 @@ int plugin_init(int *argc, char **argv,
     }
     for (plugin= *builtins; plugin->info; plugin++)
     {
-      if (opt_ignore_builtin_innodb &&
-          !my_strnncoll(&my_charset_latin1, (const uchar*) plugin->name,
-                        6, (const uchar*) "InnoDB", 6))
-        continue;
       memset(&tmp, 0, sizeof(tmp));
       tmp.plugin= plugin;
       tmp.name.str= (char *)plugin->name;

=== modified file 'sql/sys_vars.cc'
--- a/sql/sys_vars.cc	2012-02-16 23:25:47 +0000
+++ b/sql/sys_vars.cc	2012-02-18 22:51:38 +0000
@@ -1246,6 +1246,7 @@ static Sys_var_charptr Sys_ft_stopword_f
 
 static Sys_var_mybool Sys_ignore_builtin_innodb(
        "ignore_builtin_innodb",
+       "IGNORED. This option will be removed in future releases. "
        "Disable initialization of builtin InnoDB plugin",
        READ_ONLY GLOBAL_VAR(opt_ignore_builtin_innodb),
        CMD_LINE(OPT_ARG), DEFAULT(FALSE));

=== modified file 'sql/table.cc'
--- a/sql/table.cc	2012-02-02 13:44:26 +0000
+++ b/sql/table.cc	2012-02-17 10:30:31 +0000
@@ -3532,7 +3532,8 @@ void TABLE::reset_item_list(List<Item> *
 void  TABLE_LIST::calc_md5(char *buffer)
 {
   uchar digest[16];
-  MY_MD5_HASH(digest, (uchar *) select_stmt.str, select_stmt.length);
+  compute_md5_hash((char *) digest, (const char *) select_stmt.str,
+                   select_stmt.length);
   sprintf((char *) buffer,
 	    "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
 	    digest[0], digest[1], digest[2], digest[3],

=== modified file 'storage/innobase/btr/btr0btr.cc'
--- a/storage/innobase/btr/btr0btr.cc	2012-02-02 10:44:07 +0000
+++ b/storage/innobase/btr/btr0btr.cc	2012-02-17 09:58:18 +0000
@@ -928,9 +928,12 @@ btr_page_alloc_for_ibuf(
 /**************************************************************//**
 Allocates a new file page to be used in an index tree. NOTE: we assume
 that the caller has made the reservation for free extents!
-@return	allocated page number, FIL_NULL if out of space */
-static __attribute__((nonnull(1,5), warn_unused_result))
-ulint
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
+static __attribute__((nonnull, warn_unused_result))
+buf_block_t*
 btr_page_alloc_low(
 /*===============*/
 	dict_index_t*	index,		/*!< in: index */
@@ -941,13 +944,12 @@ btr_page_alloc_low(
 					in the tree */
 	mtr_t*		mtr,		/*!< in/out: mini-transaction
 					for the allocation */
-	mtr_t*		init_mtr)	/*!< in/out: mini-transaction
-					in which the page should be
-					initialized (may be the same
-					as mtr), or NULL if it should
-					not be initialized (the page
-					at hint was previously freed
-					in mtr) */
+	mtr_t*		init_mtr)	/*!< in/out: mtr or another
+					mini-transaction in which the
+					page should be initialized.
+					If init_mtr!=mtr, but the page
+					is already X-latched in mtr, do
+					not initialize the page. */
 {
 	fseg_header_t*	seg_header;
 	page_t*		root;
@@ -972,7 +974,10 @@ btr_page_alloc_low(
 /**************************************************************//**
 Allocates a new file page to be used in an index tree. NOTE: we assume
 that the caller has made the reservation for free extents!
-@return	new allocated block, x-latched; NULL if out of space */
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
 UNIV_INTERN
 buf_block_t*
 btr_page_alloc(
@@ -990,33 +995,19 @@ btr_page_alloc(
 					the page */
 {
 	buf_block_t*	new_block;
-	ulint		new_page_no;
 
 	if (dict_index_is_ibuf(index)) {
 
 		return(btr_page_alloc_for_ibuf(index, mtr));
 	}
 
-	new_page_no = btr_page_alloc_low(
+	new_block = btr_page_alloc_low(
 		index, hint_page_no, file_direction, level, mtr, init_mtr);
 
-	if (new_page_no == FIL_NULL) {
-
-		return(NULL);
-	}
-
-	new_block = buf_page_get(dict_index_get_space(index),
-				 dict_table_zip_size(index->table),
-				 new_page_no, RW_X_LATCH, init_mtr);
-	buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW);
-
-	if (mtr->freed_clust_leaf) {
-		mtr_memo_release(mtr, new_block, MTR_MEMO_FREE_CLUST_LEAF);
-		ut_ad(!mtr_memo_contains(mtr, new_block,
-					 MTR_MEMO_FREE_CLUST_LEAF));
+	if (new_block) {
+		buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW);
 	}
 
-	ut_ad(btr_freed_leaves_validate(mtr));
 	return(new_block);
 }
 
@@ -1156,139 +1147,9 @@ btr_page_free(
 
 	ut_ad(fil_page_get_type(block->frame) == FIL_PAGE_INDEX);
 	btr_page_free_low(index, block, level, mtr);
-
-	/* The handling of MTR_MEMO_FREE_CLUST_LEAF assumes this. */
-	ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
-
-	if (level == 0 && dict_index_is_clust(index)) {
-		/* We may have to call btr_mark_freed_leaves() to
-		temporarily mark the block nonfree for invoking
-		btr_store_big_rec_extern_fields_func() after an
-		update. Remember that the block was freed. */
-		mtr->freed_clust_leaf = TRUE;
-		mtr_memo_push(mtr, block, MTR_MEMO_FREE_CLUST_LEAF);
-	}
-
-	ut_ad(btr_freed_leaves_validate(mtr));
 }
 
 /**************************************************************//**
-Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free.
-For invoking btr_store_big_rec_extern_fields() after an update,
-we must temporarily mark freed clustered index pages allocated, so
-that off-page columns will not be allocated from them. Between the
-btr_store_big_rec_extern_fields() and mtr_commit() we have to
-mark the pages free again, so that no pages will be leaked. */
-UNIV_INTERN
-void
-btr_mark_freed_leaves(
-/*==================*/
-	dict_index_t*	index,	/*!< in/out: clustered index */
-	mtr_t*		mtr,	/*!< in/out: mini-transaction */
-	ibool		nonfree)/*!< in: TRUE=mark nonfree, FALSE=mark freed */
-{
-	/* This is loosely based on mtr_memo_release(). */
-
-	ulint	offset;
-
-	ut_ad(dict_index_is_clust(index));
-	ut_ad(mtr->magic_n == MTR_MAGIC_N);
-	ut_ad(mtr->state == MTR_ACTIVE);
-
-	if (!mtr->freed_clust_leaf) {
-		return;
-	}
-
-	offset = dyn_array_get_data_size(&mtr->memo);
-
-	while (offset > 0) {
-		mtr_memo_slot_t*	slot;
-		buf_block_t*		block;
-
-		offset -= sizeof *slot;
-
-		slot = static_cast<mtr_memo_slot_t*>(
-			dyn_array_get_element(&mtr->memo, offset));
-
-		if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) {
-			continue;
-		}
-
-		/* Because btr_page_alloc() does invoke
-		mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all
-		blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the
-		memo must still be clustered index leaf tree pages. */
-		block = static_cast<buf_block_t*>(slot->object);
-		ut_a(buf_block_get_space(block)
-		     == dict_index_get_space(index));
-		ut_a(fil_page_get_type(buf_block_get_frame(block))
-		     == FIL_PAGE_INDEX);
-		ut_a(page_is_leaf(buf_block_get_frame(block)));
-
-		if (nonfree) {
-			/* Allocate the same page again. */
-			ulint	page_no;
-			page_no = btr_page_alloc_low(
-				index, buf_block_get_page_no(block),
-				FSP_NO_DIR, 0, mtr, NULL);
-			ut_a(page_no == buf_block_get_page_no(block));
-		} else {
-			/* Assert that the page is allocated and free it. */
-			btr_page_free_low(index, block, 0, mtr);
-		}
-	}
-
-	ut_ad(btr_freed_leaves_validate(mtr));
-}
-
-#ifdef UNIV_DEBUG
-/**************************************************************//**
-Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF.
-@see btr_mark_freed_leaves()
-@return TRUE */
-UNIV_INTERN
-ibool
-btr_freed_leaves_validate(
-/*======================*/
-	mtr_t*	mtr)	/*!< in: mini-transaction */
-{
-	ulint	offset;
-
-	ut_ad(mtr->magic_n == MTR_MAGIC_N);
-	ut_ad(mtr->state == MTR_ACTIVE);
-
-	offset = dyn_array_get_data_size(&mtr->memo);
-
-	while (offset > 0) {
-		const mtr_memo_slot_t*	slot;
-		const buf_block_t*	block;
-
-		offset -= sizeof *slot;
-
-		slot = static_cast<const mtr_memo_slot_t*>(
-                        dyn_array_get_element(&mtr->memo, offset));
-
-		if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) {
-			continue;
-		}
-
-		ut_a(mtr->freed_clust_leaf);
-		/* Because btr_page_alloc() does invoke
-		mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all
-		blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the
-		memo must still be clustered index leaf tree pages. */
-		block = static_cast<const buf_block_t*>(slot->object);
-
-		ut_a(fil_page_get_type(buf_block_get_frame(block))
-		     == FIL_PAGE_INDEX);
-		ut_a(page_is_leaf(buf_block_get_frame(block)));
-	}
-
-	return(TRUE);
-}
-#endif /* UNIV_DEBUG */
-
-/**************************************************************//**
 Sets the child node file address in a node pointer. */
 UNIV_INLINE
 void
@@ -1525,16 +1386,12 @@ btr_create(
 		/* Allocate then the next page to the segment: it will be the
 		tree root page */
 
-		page_no = fseg_alloc_free_page(buf_block_get_frame(
-						       ibuf_hdr_block)
-					       + IBUF_HEADER
-					       + IBUF_TREE_SEG_HEADER,
-					       IBUF_TREE_ROOT_PAGE_NO,
-					       FSP_UP, mtr);
-		ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
-
-		block = buf_page_get(space, zip_size, page_no,
-				     RW_X_LATCH, mtr);
+		block = fseg_alloc_free_page(
+			buf_block_get_frame(ibuf_hdr_block)
+			+ IBUF_HEADER + IBUF_TREE_SEG_HEADER,
+			IBUF_TREE_ROOT_PAGE_NO,
+			FSP_UP, mtr);
+		ut_ad(buf_block_get_page_no(block) == IBUF_TREE_ROOT_PAGE_NO);
 	} else {
 #ifdef UNIV_BLOB_DEBUG
 		if ((type & DICT_CLUSTERED) && !index->blobs) {

=== modified file 'storage/innobase/btr/btr0cur.cc'
--- a/storage/innobase/btr/btr0cur.cc	2012-01-26 11:57:53 +0000
+++ b/storage/innobase/btr/btr0cur.cc	2012-02-17 09:58:18 +0000
@@ -3907,7 +3907,7 @@ btr_cur_set_ownership_of_extern_field(
 	if (page_zip) {
 		mach_write_to_1(data + local_len + BTR_EXTERN_LEN, byte_val);
 		page_zip_write_blob_ptr(page_zip, rec, index, offsets, i, mtr);
-	} else if (UNIV_LIKELY(mtr != NULL)) {
+	} else if (mtr != NULL) {
 
 		mlog_write_ulint(data + local_len + BTR_EXTERN_LEN, byte_val,
 				 MLOG_1BYTE, mtr);
@@ -4139,9 +4139,9 @@ The fields are stored on pages allocated
 file segment of the index tree.
 @return	DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
 UNIV_INTERN
-ulint
-btr_store_big_rec_extern_fields_func(
-/*=================================*/
+enum db_err
+btr_store_big_rec_extern_fields(
+/*============================*/
 	dict_index_t*	index,		/*!< in: index of rec; the index tree
 					MUST be X-latched */
 	buf_block_t*	rec_block,	/*!< in/out: block containing rec */
@@ -4152,44 +4152,35 @@ btr_store_big_rec_extern_fields_func(
 					this function returns */
 	const big_rec_t*big_rec_vec,	/*!< in: vector containing fields
 					to be stored externally */
-
-#ifdef UNIV_DEBUG
-	mtr_t*		local_mtr,	/*!< in: mtr containing the
-					latch to rec and to the tree */
-#endif /* UNIV_DEBUG */
-#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
-	ibool		update_in_place,/*! in: TRUE if the record is updated
-					in place (not delete+insert) */
-#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
-	mtr_t*		alloc_mtr)	/*!< in/out: in an insert, NULL;
-					in an update, local_mtr for
-					allocating BLOB pages and
-					updating BLOB pointers; alloc_mtr
-					must not have freed any leaf pages */
+	mtr_t*		btr_mtr,	/*!< in: mtr containing the
+					latches to the clustered index */
+	enum blob_op	op)		/*! in: operation code */
 {
-	ulint	rec_page_no;
-	byte*	field_ref;
-	ulint	extern_len;
-	ulint	store_len;
-	ulint	page_no;
-	ulint	space_id;
-	ulint	zip_size;
-	ulint	prev_page_no;
-	ulint	hint_page_no;
-	ulint	i;
-	mtr_t	mtr;
-	mem_heap_t* heap = NULL;
+	ulint		rec_page_no;
+	byte*		field_ref;
+	ulint		extern_len;
+	ulint		store_len;
+	ulint		page_no;
+	ulint		space_id;
+	ulint		zip_size;
+	ulint		prev_page_no;
+	ulint		hint_page_no;
+	ulint		i;
+	mtr_t		mtr;
+	mtr_t*		alloc_mtr;
+	mem_heap_t*	heap = NULL;
 	page_zip_des_t*	page_zip;
-	z_stream c_stream;
+	z_stream	c_stream;
+	buf_block_t**	freed_pages	= NULL;
+	ulint		n_freed_pages	= 0;
+	enum db_err	error		= DB_SUCCESS;
 
 	ut_ad(rec_offs_validate(rec, index, offsets));
 	ut_ad(rec_offs_any_extern(offsets));
-	ut_ad(local_mtr);
-	ut_ad(!alloc_mtr || alloc_mtr == local_mtr);
-	ut_ad(!update_in_place || alloc_mtr);
-	ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index),
+	ut_ad(btr_mtr);
+	ut_ad(mtr_memo_contains(btr_mtr, dict_index_get_lock(index),
 				MTR_MEMO_X_LOCK));
-	ut_ad(mtr_memo_contains(local_mtr, rec_block, MTR_MEMO_PAGE_X_FIX));
+	ut_ad(mtr_memo_contains(btr_mtr, rec_block, MTR_MEMO_PAGE_X_FIX));
 	ut_ad(buf_block_get_frame(rec_block) == page_align(rec));
 	ut_a(dict_index_is_clust(index));
 
@@ -4202,25 +4193,6 @@ btr_store_big_rec_extern_fields_func(
 	rec_page_no = buf_block_get_page_no(rec_block);
 	ut_a(fil_page_get_type(page_align(rec)) == FIL_PAGE_INDEX);
 
-	if (alloc_mtr) {
-		/* Because alloc_mtr will be committed after
-		mtr, it is possible that the tablespace has been
-		extended when the B-tree record was updated or
-		inserted, or it will be extended while allocating
-		pages for big_rec.
-
-		TODO: In mtr (not alloc_mtr), write a redo log record
-		about extending the tablespace to its current size,
-		and remember the current size. Whenever the tablespace
-		grows as pages are allocated, write further redo log
-		records to mtr. (Currently tablespace extension is not
-		covered by the redo log. If it were, the record would
-		only be written to alloc_mtr, which is committed after
-		mtr.) */
-	} else {
-		alloc_mtr = &mtr;
-	}
-
 	if (page_zip) {
 		int	err;
 
@@ -4237,6 +4209,43 @@ btr_store_big_rec_extern_fields_func(
 		ut_a(err == Z_OK);
 	}
 
+	if (btr_blob_op_is_update(op)) {
+		/* Avoid reusing pages that have been previously freed
+		in btr_mtr. */
+		if (btr_mtr->n_freed_pages) {
+			if (heap == NULL) {
+				heap = mem_heap_create(
+					btr_mtr->n_freed_pages
+					* sizeof *freed_pages);
+			}
+
+			freed_pages = static_cast<buf_block_t**>(
+				mem_heap_alloc(
+					heap,
+					btr_mtr->n_freed_pages
+					* sizeof *freed_pages));
+			n_freed_pages = 0;
+		}
+
+		/* Because btr_mtr will be committed after mtr, it is
+		possible that the tablespace has been extended when
+		the B-tree record was updated or inserted, or it will
+		be extended while allocating pages for big_rec.
+
+		TODO: In mtr (not btr_mtr), write a redo log record
+		about extending the tablespace to its current size,
+		and remember the current size. Whenever the tablespace
+		grows as pages are allocated, write further redo log
+		records to mtr. (Currently tablespace extension is not
+		covered by the redo log. If it were, the record would
+		only be written to btr_mtr, which is committed after
+		mtr.) */
+		alloc_mtr = btr_mtr;
+	} else {
+		/* Use the local mtr for allocations. */
+		alloc_mtr = &mtr;
+	}
+
 #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
 	/* All pointers to externally stored columns in the record
 	must either be zero or they must be pointers to inherited
@@ -4251,7 +4260,7 @@ btr_store_big_rec_extern_fields_func(
 		/* Either this must be an update in place,
 		or the BLOB must be inherited, or the BLOB pointer
 		must be zero (will be written in this function). */
-		ut_a(update_in_place
+		ut_a(op == BTR_STORE_UPDATE
 		     || (field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_INHERITED_FLAG)
 		     || !memcmp(field_ref, field_ref_zero,
 				BTR_EXTERN_FIELD_REF_SIZE));
@@ -4280,7 +4289,8 @@ btr_store_big_rec_extern_fields_func(
 			int	err = deflateReset(&c_stream);
 			ut_a(err == Z_OK);
 
-			c_stream.next_in = (Bytef*) big_rec_vec->fields[i].data;
+			c_stream.next_in = (Bytef*)
+				big_rec_vec->fields[i].data;
 			c_stream.avail_in = extern_len;
 		}
 
@@ -4296,18 +4306,24 @@ btr_store_big_rec_extern_fields_func(
 				hint_page_no = prev_page_no + 1;
 			}
 
+alloc_another:
 			block = btr_page_alloc(index, hint_page_no,
 					       FSP_NO_DIR, 0, alloc_mtr, &mtr);
 			if (UNIV_UNLIKELY(block == NULL)) {
-
 				mtr_commit(&mtr);
+				error = DB_OUT_OF_FILE_SPACE;
+				goto func_exit;
+			}
 
-				if (page_zip) {
-					deflateEnd(&c_stream);
-					mem_heap_free(heap);
-				}
-
-				return(DB_OUT_OF_FILE_SPACE);
+			if (rw_lock_get_x_lock_count(&block->lock) > 1) {
+				/* This page must have been freed in
+				btr_mtr previously. Put it aside, and
+				allocate another page for the BLOB data. */
+				ut_ad(alloc_mtr == btr_mtr);
+				ut_ad(btr_blob_op_is_update(op));
+				ut_ad(n_freed_pages < btr_mtr->n_freed_pages);
+				freed_pages[n_freed_pages++] = block;
+				goto alloc_another;
 			}
 
 			page_no = buf_block_get_page_no(block);
@@ -4564,8 +4580,23 @@ next_zip_page:
 		}
 	}
 
+func_exit:
 	if (page_zip) {
 		deflateEnd(&c_stream);
+	}
+
+	if (n_freed_pages) {
+		ulint	i;
+
+		ut_ad(alloc_mtr == btr_mtr);
+		ut_ad(btr_blob_op_is_update(op));
+
+		for (i = 0; i < n_freed_pages; i++) {
+			btr_page_free_low(index, freed_pages[i], 0, alloc_mtr);
+		}
+	}
+
+	if (heap != NULL) {
 		mem_heap_free(heap);
 	}
 
@@ -4586,7 +4617,7 @@ next_zip_page:
 		ut_a(!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG));
 	}
 #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
-	return(DB_SUCCESS);
+	return(error);
 }
 
 /*******************************************************************//**

=== modified file 'storage/innobase/buf/buf0dblwr.cc'
--- a/storage/innobase/buf/buf0dblwr.cc	2012-02-02 10:44:07 +0000
+++ b/storage/innobase/buf/buf0dblwr.cc	2012-02-17 14:51:29 +0000
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -163,9 +163,7 @@ buf_dblwr_create(void)
 /*==================*/
 {
 	buf_block_t*	block2;
-#ifdef UNIV_SYNC_DEBUG
 	buf_block_t*	new_block;
-#endif /* UNIV_SYNC_DEBUG */
 	byte*	doublewrite;
 	byte*	fseg_header;
 	ulint	page_no;
@@ -242,10 +240,9 @@ start_again:
 
 	for (i = 0; i < 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE
 		     + FSP_EXTENT_SIZE / 2; i++) {
-		page_no = fseg_alloc_free_page(fseg_header,
-					       prev_page_no + 1,
-					       FSP_UP, &mtr);
-		if (page_no == FIL_NULL) {
+		new_block = fseg_alloc_free_page(
+			fseg_header, prev_page_no + 1, FSP_UP, &mtr);
+		if (new_block == NULL) {
 			fprintf(stderr,
 				"InnoDB: Cannot create doublewrite"
 				" buffer: you must\n"
@@ -266,13 +263,8 @@ start_again:
 		the page position in the tablespace, then the page
 		has not been written to in doublewrite. */
 
-#ifdef UNIV_SYNC_DEBUG
-		new_block =
-#endif /* UNIV_SYNC_DEBUG */
-		buf_page_get(TRX_SYS_SPACE, 0, page_no,
-			     RW_X_LATCH, &mtr);
-		buf_block_dbg_add_level(new_block,
-					SYNC_NO_ORDER_CHECK);
+		ut_ad(rw_lock_get_x_lock_count(&new_block->lock) == 1);
+		page_no = buf_block_get_page_no(new_block);
 
 		if (i == FSP_EXTENT_SIZE / 2) {
 			ut_a(page_no == FSP_EXTENT_SIZE);

=== modified file 'storage/innobase/fsp/fsp0fsp.cc'
--- a/storage/innobase/fsp/fsp0fsp.cc	2011-12-12 12:55:18 +0000
+++ b/storage/innobase/fsp/fsp0fsp.cc	2012-02-17 09:58:18 +0000
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -139,28 +139,31 @@ fsp_fill_free_list(
 Allocates a single free page from a segment. This function implements
 the intelligent allocation strategy which tries to minimize file space
 fragmentation.
-@return	the allocated page number, FIL_NULL if no page could be allocated */
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
 static
-ulint
+buf_block_t*
 fseg_alloc_free_page_low(
 /*=====================*/
 	ulint		space,	/*!< in: space */
 	ulint		zip_size,/*!< in: compressed page size in bytes
 				or 0 for uncompressed pages */
 	fseg_inode_t*	seg_inode, /*!< in/out: segment inode */
-	ulint		hint,	/*!< in: hint of which page would be desirable */
+	ulint		hint,	/*!< in: hint of which page would be
+				desirable */
 	byte		direction, /*!< in: if the new page is needed because
 				of an index page split, and records are
 				inserted there in order, into which
 				direction they go alphabetically: FSP_DOWN,
 				FSP_UP, FSP_NO_DIR */
 	mtr_t*		mtr,	/*!< in/out: mini-transaction */
-	mtr_t*		init_mtr)/*!< in/out: mini-transaction in which the
-				page should be initialized
-				(may be the same as mtr), or NULL if it
-				should not be initialized (the page at hint
-				was previously freed in mtr) */
-	__attribute__((warn_unused_result, nonnull(3,6)));
+	mtr_t*		init_mtr)/*!< in/out: mtr or another mini-transaction
+				in which the page should be initialized.
+				If init_mtr!=mtr, but the page is already
+				latched in mtr, do not initialize the page. */
+	__attribute__((warn_unused_result, nonnull));
 #endif /* !UNIV_HOTBACKUP */
 
 /**********************************************************************//**
@@ -1369,10 +1372,63 @@ fsp_alloc_from_free_frag(
 }
 
 /**********************************************************************//**
+Gets a buffer block for an allocated page.
+
+NOTE: If init_mtr != mtr, the block will only be initialized if it was
+not previously x-latched. It is assumed that the block has been
+x-latched only by mtr, and freed in mtr in that case.
+
+@return block, initialized if init_mtr==mtr
+or rw_lock_x_lock_count(&block->lock) == 1 */
+static
+buf_block_t*
+fsp_page_create(
+/*============*/
+	ulint	space,		/*!< in: space id of the allocated page */
+	ulint	zip_size,	/*!< in: compressed page size in bytes
+				or 0 for uncompressed pages */
+	ulint	page_no,	/*!< in: page number of the allocated page */
+	mtr_t*	mtr,		/*!< in: mini-transaction of the allocation */
+	mtr_t*	init_mtr)	/*!< in: mini-transaction for initializing
+				the page */
+{
+	buf_block_t*	block
+		= buf_page_create(space, page_no, zip_size, init_mtr);
+#ifdef UNIV_SYNC_DEBUG
+	ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)
+	      == rw_lock_own(&block->lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+	/* Mimic buf_page_get(), but avoid the buf_pool->page_hash lookup. */
+	rw_lock_x_lock(&block->lock);
+	mutex_enter(&block->mutex);
+	buf_block_buf_fix_inc(block, __FILE__, __LINE__);
+	mutex_exit(&block->mutex);
+	mtr_memo_push(init_mtr, block, MTR_MEMO_PAGE_X_FIX);
+
+	if (init_mtr == mtr
+	    || rw_lock_get_x_lock_count(&block->lock) == 1) {
+
+		/* Initialize the page, unless it was already
+		X-latched in mtr. (In this case, we would want to
+		allocate another page that has not been freed in mtr.) */
+		ut_ad(init_mtr == mtr
+		      || !mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+
+		fsp_init_file_page(block, init_mtr);
+	}
+
+	return(block);
+}
+
+/**********************************************************************//**
 Allocates a single free page from a space. The page is marked as used.
-@return	the page offset, FIL_NULL if no page could be allocated */
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
 static __attribute__((nonnull, warn_unused_result))
-ulint
+buf_block_t*
 fsp_alloc_free_page(
 /*================*/
 	ulint	space,	/*!< in: space id */
@@ -1387,11 +1443,9 @@ fsp_alloc_free_page(
 	fsp_header_t*	header;
 	fil_addr_t	first;
 	xdes_t*		descr;
-	buf_block_t*	block;
 	ulint		free;
 	ulint		page_no;
 	ulint		space_size;
-	ibool		success;
 
 	ut_ad(mtr);
 	ut_ad(init_mtr);
@@ -1421,7 +1475,7 @@ fsp_alloc_free_page(
 			if (descr == NULL) {
 				/* No free space left */
 
-				return(FIL_NULL);
+				return(NULL);
 			}
 
 			xdes_set_state(descr, XDES_FREE_FRAG, mtr);
@@ -1466,31 +1520,17 @@ fsp_alloc_free_page(
 				" space size %lu. Page no %lu.\n",
 				(ulong) space, (ulong) space_size,
 				(ulong) page_no);
-			return(FIL_NULL);
+			return(NULL);
 		}
-		success = fsp_try_extend_data_file_with_pages(space, page_no,
-							      header, mtr);
-		if (!success) {
+		if (!fsp_try_extend_data_file_with_pages(space, page_no,
+							 header, mtr)) {
 			/* No disk space left */
-			return(FIL_NULL);
+			return(NULL);
 		}
 	}
 
 	fsp_alloc_from_free_frag(header, descr, free, mtr);
-
-	/* Initialize the allocated page to the buffer pool, so that it can
-	be obtained immediately with buf_page_get without need for a disk
-	read. */
-
-	buf_page_create(space, page_no, zip_size, init_mtr);
-
-	block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, init_mtr);
-	buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
-
-	/* Prior contents of the page should be ignored */
-	fsp_init_file_page(block, init_mtr);
-
-	return(page_no);
+	return(fsp_page_create(space, zip_size, page_no, mtr, init_mtr));
 }
 
 /**********************************************************************//**
@@ -1529,6 +1569,9 @@ fsp_free_page(
 		fputs("InnoDB: Dump of descriptor: ", stderr);
 		ut_print_buf(stderr, ((byte*) descr) - 50, 200);
 		putc('\n', stderr);
+		/* Crash in debug version, so that we get a core dump
+		of this corruption. */
+		ut_ad(0);
 
 		if (state == XDES_FREE) {
 			/* We put here some fault tolerance: if the page
@@ -1547,6 +1590,9 @@ fsp_free_page(
 			"InnoDB: Dump of descriptor: ", (ulong) page);
 		ut_print_buf(stderr, ((byte*) descr) - 50, 200);
 		putc('\n', stderr);
+		/* Crash in debug version, so that we get a core dump
+		of this corruption. */
+		ut_ad(0);
 
 		/* We put here some fault tolerance: if the page
 		is already free, return without doing anything! */
@@ -1581,6 +1627,8 @@ fsp_free_page(
 			    mtr);
 		fsp_free_extent(space, zip_size, page, mtr);
 	}
+
+	mtr->n_freed_pages++;
 }
 
 /**********************************************************************//**
@@ -1713,7 +1761,6 @@ fsp_alloc_seg_inode_page(
 	fseg_inode_t*	inode;
 	buf_block_t*	block;
 	page_t*		page;
-	ulint		page_no;
 	ulint		space;
 	ulint		zip_size;
 	ulint		i;
@@ -1724,15 +1771,15 @@ fsp_alloc_seg_inode_page(
 	zip_size = fsp_flags_get_zip_size(
 		mach_read_from_4(FSP_SPACE_FLAGS + space_header));
 
-	page_no = fsp_alloc_free_page(space, zip_size, 0, mtr, mtr);
+	block = fsp_alloc_free_page(space, zip_size, 0, mtr, mtr);
 
-	if (page_no == FIL_NULL) {
+	if (block == NULL) {
 
 		return(FALSE);
 	}
 
-	block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
 	buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
+	ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1);
 
 	block->check_index_page_at_flush = FALSE;
 
@@ -2133,19 +2180,20 @@ fseg_create_general(
 	}
 
 	if (page == 0) {
-		page = fseg_alloc_free_page_low(space, zip_size,
-						inode, 0, FSP_UP, mtr, mtr);
+		block = fseg_alloc_free_page_low(space, zip_size,
+						 inode, 0, FSP_UP, mtr, mtr);
 
-		if (page == FIL_NULL) {
+		if (block == NULL) {
 
 			fsp_free_seg_inode(space, zip_size, inode, mtr);
 
 			goto funct_exit;
 		}
 
-		block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
+		ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1);
+
 		header = byte_offset + buf_block_get_frame(block);
-		mlog_write_ulint(header - byte_offset + FIL_PAGE_TYPE,
+		mlog_write_ulint(buf_block_get_frame(block) + FIL_PAGE_TYPE,
 				 FIL_PAGE_TYPE_SYS, MLOG_2BYTES, mtr);
 	}
 
@@ -2319,8 +2367,10 @@ fseg_fill_free_list(
 Allocates a free extent for the segment: looks first in the free list of the
 segment, then tries to allocate from the space free list. NOTE that the extent
 returned still resides in the segment free list, it is not yet taken off it!
-@return allocated extent, still placed in the segment free list, NULL
-if could not be allocated */
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
 static
 xdes_t*
 fseg_alloc_free_extent(
@@ -2372,27 +2422,30 @@ fseg_alloc_free_extent(
 Allocates a single free page from a segment. This function implements
 the intelligent allocation strategy which tries to minimize file space
 fragmentation.
-@return	the allocated page number, FIL_NULL if no page could be allocated */
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
 static
-ulint
+buf_block_t*
 fseg_alloc_free_page_low(
 /*=====================*/
 	ulint		space,	/*!< in: space */
 	ulint		zip_size,/*!< in: compressed page size in bytes
 				or 0 for uncompressed pages */
 	fseg_inode_t*	seg_inode, /*!< in/out: segment inode */
-	ulint		hint,	/*!< in: hint of which page would be desirable */
+	ulint		hint,	/*!< in: hint of which page would be
+				desirable */
 	byte		direction, /*!< in: if the new page is needed because
 				of an index page split, and records are
 				inserted there in order, into which
 				direction they go alphabetically: FSP_DOWN,
 				FSP_UP, FSP_NO_DIR */
 	mtr_t*		mtr,	/*!< in/out: mini-transaction */
-	mtr_t*		init_mtr)/*!< in/out: mini-transaction in which the
-				page should be initialized
-				(may be the same as mtr), or NULL if it
-				should not be initialized (the page at hint
-				was previously freed in mtr) */
+	mtr_t*		init_mtr)/*!< in/out: mtr or another mini-transaction
+				in which the page should be initialized.
+				If init_mtr!=mtr, but the page is already
+				latched in mtr, do not initialize the page. */
 {
 	fsp_header_t*	space_header;
 	ulint		space_size;
@@ -2424,7 +2477,6 @@ fseg_alloc_free_page_low(
 	if (descr == NULL) {
 		/* Hint outside space or too high above free limit: reset
 		hint */
-		ut_a(init_mtr);
 		/* The file space header page is always allocated. */
 		hint = 0;
 		descr = xdes_get_descriptor(space, zip_size, hint, mtr);
@@ -2447,9 +2499,8 @@ take_hinted_page:
 		goto got_hinted_page;
 		/*-----------------------------------------------------------*/
 	} else if (xdes_get_state(descr, mtr) == XDES_FREE
-		   && (!init_mtr
-		       || ((reserved - used < reserved / FSEG_FILLFACTOR)
-			   && used >= FSEG_FRAG_LIMIT))) {
+		   && reserved - used < reserved / FSEG_FILLFACTOR
+		   && used >= FSEG_FRAG_LIMIT) {
 
 		/* 2. We allocate the free extent from space and can take
 		=========================================================
@@ -2469,18 +2520,6 @@ take_hinted_page:
 				    hint + FSP_EXTENT_SIZE, mtr);
 		goto take_hinted_page;
 		/*-----------------------------------------------------------*/
-	} else if (!init_mtr) {
-		ut_a(xdes_get_state(descr, mtr) == XDES_FREE_FRAG);
-		fsp_alloc_from_free_frag(space_header, descr,
-					 hint % FSP_EXTENT_SIZE, mtr);
-		ret_page = hint;
-		ret_descr = NULL;
-
-		/* Put the page in the fragment page array of the segment */
-		n = fseg_find_free_frag_page_slot(seg_inode, mtr);
-		ut_a(n != FIL_NULL);
-		fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr);
-		goto got_hinted_page;
 	} else if ((direction != FSP_NO_DIR)
 		   && ((reserved - used) < reserved / FSEG_FILLFACTOR)
 		   && (used >= FSEG_FRAG_LIMIT)
@@ -2527,7 +2566,7 @@ take_hinted_page:
 			first = flst_get_first(seg_inode + FSEG_FREE, mtr);
 		} else {
 			ut_error;
-			return(FIL_NULL);
+			return(NULL);
 		}
 
 		ret_descr = xdes_lst_get_descriptor(space, zip_size,
@@ -2539,23 +2578,23 @@ take_hinted_page:
 	} else if (used < FSEG_FRAG_LIMIT) {
 		/* 6. We allocate an individual page from the space
 		===================================================*/
-		ret_page = fsp_alloc_free_page(space, zip_size, hint,
-					       mtr, init_mtr);
-		ret_descr = NULL;
+		buf_block_t* block = fsp_alloc_free_page(
+			space, zip_size, hint, mtr, init_mtr);
 
-		if (ret_page != FIL_NULL) {
+		if (block != NULL) {
 			/* Put the page in the fragment page array of the
 			segment */
 			n = fseg_find_free_frag_page_slot(seg_inode, mtr);
-			ut_a(n != FIL_NULL);
+			ut_a(n != ULINT_UNDEFINED);
 
-			fseg_set_nth_frag_page_no(seg_inode, n, ret_page,
-						  mtr);
+			fseg_set_nth_frag_page_no(
+				seg_inode, n, buf_block_get_page_no(block),
+				mtr);
 		}
 
 		/* fsp_alloc_free_page() invoked fsp_init_file_page()
 		already. */
-		return(ret_page);
+		return(block);
 		/*-----------------------------------------------------------*/
 	} else {
 		/* 7. We allocate a new extent and take its first page
@@ -2573,7 +2612,7 @@ take_hinted_page:
 	if (ret_page == FIL_NULL) {
 		/* Page could not be allocated */
 
-		return(FIL_NULL);
+		return(NULL);
 	}
 
 	if (space != 0) {
@@ -2591,43 +2630,19 @@ take_hinted_page:
 					" the space size %lu. Page no %lu.\n",
 					(ulong) space, (ulong) space_size,
 					(ulong) ret_page);
-				return(FIL_NULL);
+				return(NULL);
 			}
 
 			success = fsp_try_extend_data_file_with_pages(
 				space, ret_page, space_header, mtr);
 			if (!success) {
 				/* No disk space left */
-				return(FIL_NULL);
+				return(NULL);
 			}
 		}
 	}
 
 got_hinted_page:
-	{
-		/* Initialize the allocated page to buffer pool, so that it
-		can be obtained immediately with buf_page_get without need
-		for a disk read */
-		buf_block_t*	block;
-		ulint		zip_size = fsp_flags_get_zip_size(
-			mach_read_from_4(FSP_SPACE_FLAGS + space_header));
-		mtr_t*		block_mtr = init_mtr ? init_mtr : mtr;
-
-		block = buf_page_create(space, ret_page, zip_size, block_mtr);
-		buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
-
-		if (UNIV_UNLIKELY(block != buf_page_get(space, zip_size,
-							ret_page, RW_X_LATCH,
-							block_mtr))) {
-			ut_error;
-		}
-
-		if (init_mtr) {
-			/* The prior contents of the page should be ignored */
-			fsp_init_file_page(block, init_mtr);
-		}
-	}
-
 	/* ret_descr == NULL if the block was allocated from free_frag
 	(XDES_FREE_FRAG) */
 	if (ret_descr != NULL) {
@@ -2643,20 +2658,28 @@ got_hinted_page:
 		fseg_mark_page_used(seg_inode, space, zip_size, ret_page, mtr);
 	}
 
-	return(ret_page);
+	return(fsp_page_create(
+		       space, fsp_flags_get_zip_size(
+			       mach_read_from_4(FSP_SPACE_FLAGS
+						+ space_header)),
+		       ret_page, mtr, init_mtr));
 }
 
 /**********************************************************************//**
 Allocates a single free page from a segment. This function implements
 the intelligent allocation strategy which tries to minimize file space
 fragmentation.
-@return	allocated page offset, FIL_NULL if no page could be allocated */
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
 UNIV_INTERN
-ulint
+buf_block_t*
 fseg_alloc_free_page_general(
 /*=========================*/
 	fseg_header_t*	seg_header,/*!< in/out: segment header */
-	ulint		hint,	/*!< in: hint of which page would be desirable */
+	ulint		hint,	/*!< in: hint of which page would be
+				desirable */
 	byte		direction,/*!< in: if the new page is needed because
 				of an index page split, and records are
 				inserted there in order, into which
@@ -2669,17 +2692,16 @@ fseg_alloc_free_page_general(
 				page */
 	mtr_t*		mtr,	/*!< in/out: mini-transaction */
 	mtr_t*		init_mtr)/*!< in/out: mtr or another mini-transaction
-				in which the page should be initialized,
-				or NULL if this is a "fake allocation" of
-				a page that was previously freed in mtr */
+				in which the page should be initialized.
+				If init_mtr!=mtr, but the page is already
+				latched in mtr, do not initialize the page. */
 {
 	fseg_inode_t*	inode;
 	ulint		space;
 	ulint		flags;
 	ulint		zip_size;
 	rw_lock_t*	latch;
-	ibool		success;
-	ulint		page_no;
+	buf_block_t*	block;
 	ulint		n_reserved;
 
 	space = page_get_space_id(page_align(seg_header));
@@ -2701,22 +2723,20 @@ fseg_alloc_free_page_general(
 
 	inode = fseg_inode_get(seg_header, space, zip_size, mtr);
 
-	if (!has_done_reservation) {
-		success = fsp_reserve_free_extents(&n_reserved, space, 2,
-						   FSP_NORMAL, mtr);
-		if (!success) {
-			return(FIL_NULL);
-		}
+	if (!has_done_reservation
+	    && !fsp_reserve_free_extents(&n_reserved, space, 2,
+					 FSP_NORMAL, mtr)) {
+		return(NULL);
 	}
 
-	page_no = fseg_alloc_free_page_low(space, zip_size,
-					   inode, hint, direction,
-					   mtr, init_mtr);
+	block = fseg_alloc_free_page_low(space, zip_size,
+					 inode, hint, direction,
+					 mtr, init_mtr);
 	if (!has_done_reservation) {
 		fil_space_release_free_extents(space, n_reserved);
 	}
 
-	return(page_no);
+	return(block);
 }
 
 /**********************************************************************//**
@@ -3223,6 +3243,8 @@ crash:
 			    descr + XDES_FLST_NODE, mtr);
 		fsp_free_extent(space, zip_size, page, mtr);
 	}
+
+	mtr->n_freed_pages++;
 }
 
 /**********************************************************************//**

=== modified file 'storage/innobase/ibuf/ibuf0ibuf.cc'
--- a/storage/innobase/ibuf/ibuf0ibuf.cc	2012-02-02 10:44:07 +0000
+++ b/storage/innobase/ibuf/ibuf0ibuf.cc	2012-02-17 09:58:18 +0000
@@ -2049,14 +2049,14 @@ ibool
 ibuf_add_free_page(void)
 /*====================*/
 {
-	mtr_t	mtr;
-	page_t*	header_page;
-	ulint	flags;
-	ulint	zip_size;
-	ulint	page_no;
-	page_t*	page;
-	page_t*	root;
-	page_t*	bitmap_page;
+	mtr_t		mtr;
+	page_t*		header_page;
+	ulint		flags;
+	ulint		zip_size;
+	buf_block_t*	block;
+	page_t*		page;
+	page_t*		root;
+	page_t*		bitmap_page;
 
 	mtr_start(&mtr);
 
@@ -2077,28 +2077,23 @@ ibuf_add_free_page(void)
 	of a deadlock. This is the reason why we created a special ibuf
 	header page apart from the ibuf tree. */
 
-	page_no = fseg_alloc_free_page(
+	block = fseg_alloc_free_page(
 		header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, 0, FSP_UP,
 		&mtr);
 
-	if (UNIV_UNLIKELY(page_no == FIL_NULL)) {
+	if (block == NULL) {
 		mtr_commit(&mtr);
 
 		return(FALSE);
-	} else {
-		buf_block_t*	block = buf_page_get(
-			IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr);
-
-		ibuf_enter(&mtr);
-
-		mutex_enter(&ibuf_mutex);
-
-		root = ibuf_tree_root_get(&mtr);
+	}
 
-		buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW);
+	ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1);
+	ibuf_enter(&mtr);
+	mutex_enter(&ibuf_mutex);
+	root = ibuf_tree_root_get(&mtr);
 
-		page = buf_block_get_frame(block);
-	}
+	buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW);
+	page = buf_block_get_frame(block);
 
 	/* Add the page to the free list and update the ibuf size data */
 
@@ -2115,12 +2110,13 @@ ibuf_add_free_page(void)
 	(level 2 page) */
 
 	bitmap_page = ibuf_bitmap_get_map_page(
-		IBUF_SPACE_ID, page_no, zip_size, &mtr);
+		IBUF_SPACE_ID, buf_block_get_page_no(block), zip_size, &mtr);
 
 	mutex_exit(&ibuf_mutex);
 
 	ibuf_bitmap_page_set_bits(
-		bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, TRUE, &mtr);
+		bitmap_page, buf_block_get_page_no(block), zip_size,
+		IBUF_BITMAP_IBUF, TRUE, &mtr);
 
 	ibuf_mtr_commit(&mtr);
 

=== modified file 'storage/innobase/include/btr0btr.h'
--- a/storage/innobase/include/btr0btr.h	2012-01-26 11:57:53 +0000
+++ b/storage/innobase/include/btr0btr.h	2012-02-17 09:58:18 +0000
@@ -577,7 +577,10 @@ btr_get_size(
 /**************************************************************//**
 Allocates a new file page to be used in an index tree. NOTE: we assume
 that the caller has made the reservation for free extents!
-@return	new allocated block, x-latched; NULL if out of space */
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
 UNIV_INTERN
 buf_block_t*
 btr_page_alloc(
@@ -616,33 +619,6 @@ btr_page_free_low(
 	buf_block_t*	block,	/*!< in: block to be freed, x-latched */
 	ulint		level,	/*!< in: page level */
 	mtr_t*		mtr);	/*!< in: mtr */
-/**************************************************************//**
-Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free.
-For invoking btr_store_big_rec_extern_fields() after an update,
-we must temporarily mark freed clustered index pages allocated, so
-that off-page columns will not be allocated from them. Between the
-btr_store_big_rec_extern_fields() and mtr_commit() we have to
-mark the pages free again, so that no pages will be leaked. */
-UNIV_INTERN
-void
-btr_mark_freed_leaves(
-/*==================*/
-	dict_index_t*	index,	/*!< in/out: clustered index */
-	mtr_t*		mtr,	/*!< in/out: mini-transaction */
-	ibool		nonfree)/*!< in: TRUE=mark nonfree, FALSE=mark freed */
-	UNIV_COLD __attribute__((nonnull));
-#ifdef UNIV_DEBUG
-/**************************************************************//**
-Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF.
-@see btr_mark_freed_leaves()
-@return TRUE */
-UNIV_INTERN
-ibool
-btr_freed_leaves_validate(
-/*======================*/
-	mtr_t*	mtr)	/*!< in: mini-transaction */
-	__attribute__((nonnull, warn_unused_result));
-#endif /* UNIV_DEBUG */
 #ifdef UNIV_BTR_PRINT
 /*************************************************************//**
 Prints size info of a B-tree. */

=== modified file 'storage/innobase/include/btr0cur.h'
--- a/storage/innobase/include/btr0cur.h	2011-11-22 11:21:45 +0000
+++ b/storage/innobase/include/btr0cur.h	2012-02-17 09:58:18 +0000
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -500,6 +500,27 @@ btr_cur_disown_inherited_fields(
 	const upd_t*	update,	/*!< in: update vector */
 	mtr_t*		mtr)	/*!< in/out: mini-transaction */
 	__attribute__((nonnull(2,3,4,5,6)));
+
+/** Operation code for btr_store_big_rec_extern_fields(). */
+enum blob_op {
+	/** Store off-page columns for a freshly inserted record */
+	BTR_STORE_INSERT = 0,
+	/** Store off-page columns for an insert by update */
+	BTR_STORE_INSERT_UPDATE,
+	/** Store off-page columns for an update */
+	BTR_STORE_UPDATE
+};
+
+/*******************************************************************//**
+Determine if an operation on off-page columns is an update.
+@return TRUE if op != BTR_STORE_INSERT */
+UNIV_INLINE
+ibool
+btr_blob_op_is_update(
+/*==================*/
+	enum blob_op	op)	/*!< in: operation */
+	__attribute__((warn_unused_result));
+
 /*******************************************************************//**
 Stores the fields in big_rec_vec to the tablespace and puts pointers to
 them in rec.  The extern flags in rec will have to be set beforehand.
@@ -507,58 +528,23 @@ The fields are stored on pages allocated
 file segment of the index tree.
 @return	DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
 UNIV_INTERN
-ulint
-btr_store_big_rec_extern_fields_func(
-/*=================================*/
+enum db_err
+btr_store_big_rec_extern_fields(
+/*============================*/
 	dict_index_t*	index,		/*!< in: index of rec; the index tree
 					MUST be X-latched */
 	buf_block_t*	rec_block,	/*!< in/out: block containing rec */
-	rec_t*		rec,		/*!< in: record */
+	rec_t*		rec,		/*!< in/out: record */
 	const ulint*	offsets,	/*!< in: rec_get_offsets(rec, index);
 					the "external storage" flags in offsets
 					will not correspond to rec when
 					this function returns */
 	const big_rec_t*big_rec_vec,	/*!< in: vector containing fields
 					to be stored externally */
-#ifdef UNIV_DEBUG
-	mtr_t*		local_mtr,	/*!< in: mtr containing the
-					latch to rec and to the tree */
-#endif /* UNIV_DEBUG */
-#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
-	ibool		update_in_place,/*! in: TRUE if the record is updated
-					in place (not delete+insert) */
-#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
-	mtr_t*		alloc_mtr)	/*!< in/out: in an insert, NULL;
-					in an update, local_mtr for
-					allocating BLOB pages and
-					updating BLOB pointers; alloc_mtr
-					must not have freed any leaf pages */
-	__attribute__((nonnull(1,2,3,4,5), warn_unused_result));
-
-/** Stores the fields in big_rec_vec to the tablespace and puts pointers to
-them in rec.  The extern flags in rec will have to be set beforehand.
-The fields are stored on pages allocated from leaf node
-file segment of the index tree.
-@param index	in: clustered index; MUST be X-latched by mtr
-@param b	in/out: block containing rec; MUST be X-latched by mtr
-@param rec	in/out: clustered index record
-@param offs	in: rec_get_offsets(rec, index);
-		the "external storage" flags in offsets will not be adjusted
-@param big	in: vector containing fields to be stored externally
-@param mtr	in: mini-transaction that holds x-latch on index and b
-@param upd	in: TRUE if the record is updated in place (not delete+insert)
-@param rmtr	in/out: in updates, the mini-transaction that holds rec
-@return	DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
-#ifdef UNIV_DEBUG
-# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \
-	btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,mtr,upd,rmtr)
-#elif defined UNIV_BLOB_LIGHT_DEBUG
-# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \
-	btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,upd,rmtr)
-#else
-# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \
-	btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,rmtr)
-#endif
+	mtr_t*		btr_mtr,	/*!< in: mtr containing the
+					latches to the clustered index */
+	enum blob_op	op)		/*! in: operation code */
+	__attribute__((nonnull, warn_unused_result));
 
 /*******************************************************************//**
 Frees the space in an externally stored field to the file space

=== modified file 'storage/innobase/include/btr0cur.ic'
--- a/storage/innobase/include/btr0cur.ic	2011-11-20 20:17:41 +0000
+++ b/storage/innobase/include/btr0cur.ic	2012-02-17 09:58:18 +0000
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -128,7 +128,7 @@ btr_cur_compress_recommendation(
 	btr_cur_t*	cursor,	/*!< in: btr cursor */
 	mtr_t*		mtr)	/*!< in: mtr */
 {
-	const page_t*		page;
+	const page_t*	page;
 
 	ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor),
 				MTR_MEMO_PAGE_X_FIX));
@@ -186,4 +186,25 @@ btr_cur_can_delete_without_compress(
 
 	return(TRUE);
 }
+
+/*******************************************************************//**
+Determine if an operation on off-page columns is an update.
+@return TRUE if op != BTR_STORE_INSERT */
+UNIV_INLINE
+ibool
+btr_blob_op_is_update(
+/*==================*/
+	enum blob_op	op)	/*!< in: operation */
+{
+	switch (op) {
+	case BTR_STORE_INSERT:
+		return(FALSE);
+	case BTR_STORE_INSERT_UPDATE:
+	case BTR_STORE_UPDATE:
+		return(TRUE);
+	}
+
+	ut_ad(0);
+	return(FALSE);
+}
 #endif /* !UNIV_HOTBACKUP */

=== modified file 'storage/innobase/include/fsp0fsp.h'
--- a/storage/innobase/include/fsp0fsp.h	2011-12-12 12:55:18 +0000
+++ b/storage/innobase/include/fsp0fsp.h	2012-02-17 09:58:18 +0000
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -461,7 +461,7 @@ file space fragmentation.
 				direction they go alphabetically: FSP_DOWN,
 				FSP_UP, FSP_NO_DIR
 @param[in/out] mtr		mini-transaction
-@return	the allocated page offset FIL_NULL if no page could be allocated */
+@return	X-latched block, or NULL if no page could be allocated */
 #define fseg_alloc_free_page(seg_header, hint, direction, mtr)		\
 	fseg_alloc_free_page_general(seg_header, hint, direction,	\
 				     FALSE, mtr, mtr)
@@ -469,13 +469,17 @@ file space fragmentation.
 Allocates a single free page from a segment. This function implements
 the intelligent allocation strategy which tries to minimize file space
 fragmentation.
-@return	allocated page offset, FIL_NULL if no page could be allocated */
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
 UNIV_INTERN
-ulint
+buf_block_t*
 fseg_alloc_free_page_general(
 /*=========================*/
 	fseg_header_t*	seg_header,/*!< in/out: segment header */
-	ulint		hint,	/*!< in: hint of which page would be desirable */
+	ulint		hint,	/*!< in: hint of which page would be
+				desirable */
 	byte		direction,/*!< in: if the new page is needed because
 				of an index page split, and records are
 				inserted there in order, into which
@@ -488,10 +492,10 @@ fseg_alloc_free_page_general(
 				page */
 	mtr_t*		mtr,	/*!< in/out: mini-transaction */
 	mtr_t*		init_mtr)/*!< in/out: mtr or another mini-transaction
-				in which the page should be initialized,
-				or NULL if this is a "fake allocation" of
-				a page that was previously freed in mtr */
-	__attribute__((warn_unused_result, nonnull(1,5)));
+				in which the page should be initialized.
+				If init_mtr!=mtr, but the page is already
+				latched in mtr, do not initialize the page. */
+	__attribute__((warn_unused_result, nonnull));
 /**********************************************************************//**
 Reserves free pages from a tablespace. All mini-transactions which may
 use several pages from the tablespace should call this function beforehand

=== modified file 'storage/innobase/include/mtr0mtr.h'
--- a/storage/innobase/include/mtr0mtr.h	2012-02-16 10:52:14 +0000
+++ b/storage/innobase/include/mtr0mtr.h	2012-02-17 09:58:18 +0000
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -50,11 +50,11 @@ first 3 values must be RW_S_LATCH, RW_X_
 #define	MTR_MEMO_PAGE_S_FIX	RW_S_LATCH
 #define	MTR_MEMO_PAGE_X_FIX	RW_X_LATCH
 #define	MTR_MEMO_BUF_FIX	RW_NO_LATCH
-#define MTR_MEMO_MODIFY		54
+#ifdef UNIV_DEBUG
+# define MTR_MEMO_MODIFY	54
+#endif /* UNIV_DEBUG */
 #define	MTR_MEMO_S_LOCK		55
 #define	MTR_MEMO_X_LOCK		56
-/** The mini-transaction freed a clustered index leaf page. */
-#define MTR_MEMO_FREE_CLUST_LEAF	57
 
 /** @name Log item types
 The log items are declared 'byte' so that the compiler can warn if val
@@ -377,15 +377,15 @@ struct mtr_struct{
 	unsigned	modifications:1;
 				/*!< TRUE if the mini-transaction
 				modified buffer pool pages */
-	unsigned	freed_clust_leaf:1;
-				/*!< TRUE if MTR_MEMO_FREE_CLUST_LEAF
-				was logged in the mini-transaction */
 	unsigned	made_dirty:1;
 				/*!< TRUE if mtr has made at least
 				one buffer pool page dirty */
 	ulint		n_log_recs;
 				/* count of how many page initial log records
 				have been written to the mtr log */
+	ulint		n_freed_pages;
+				/* number of pages that have been freed in
+				this mini-transaction */
 	ulint		log_mode; /* specifies which operations should be
 				logged; default value MTR_LOG_ALL */
 	lsn_t		start_lsn;/* start lsn of the possible log entry for

=== modified file 'storage/innobase/include/mtr0mtr.ic'
--- a/storage/innobase/include/mtr0mtr.ic	2011-11-30 10:34:38 +0000
+++ b/storage/innobase/include/mtr0mtr.ic	2012-02-17 09:58:18 +0000
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -55,9 +55,9 @@ mtr_start(
 	mtr->log_mode = MTR_LOG_ALL;
 	mtr->inside_ibuf = FALSE;
 	mtr->modifications = FALSE;
-	mtr->freed_clust_leaf = FALSE;
 	mtr->made_dirty = FALSE;
 	mtr->n_log_recs = 0;
+	mtr->n_freed_pages = 0;
 
 	ut_d(mtr->state = MTR_ACTIVE);
 	ut_d(mtr->magic_n = MTR_MAGIC_N);
@@ -78,8 +78,7 @@ mtr_memo_push(
 
 	ut_ad(object);
 	ut_ad(type >= MTR_MEMO_PAGE_S_FIX);
-	ut_ad(type <= MTR_MEMO_FREE_CLUST_LEAF);
-	ut_ad(type != MTR_MEMO_FREE_CLUST_LEAF || mtr->freed_clust_leaf);
+	ut_ad(type <= MTR_MEMO_X_LOCK);
 	ut_ad(mtr);
 	ut_ad(mtr->magic_n == MTR_MAGIC_N);
 	ut_ad(mtr->state == MTR_ACTIVE);

=== modified file 'storage/innobase/include/trx0rec.ic'
--- a/storage/innobase/include/trx0rec.ic	2011-11-08 10:32:23 +0000
+++ b/storage/innobase/include/trx0rec.ic	2012-02-17 09:58:18 +0000
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -107,6 +107,7 @@ trx_undo_rec_copy(
 
 	len = mach_read_from_2(undo_rec)
 		- ut_align_offset(undo_rec, UNIV_PAGE_SIZE);
+	ut_ad(len < UNIV_PAGE_SIZE);
 	return((trx_undo_rec_t*) mem_heap_dup(heap, undo_rec, len));
 }
 #endif /* !UNIV_HOTBACKUP */

=== modified file 'storage/innobase/include/trx0undo.h'
--- a/storage/innobase/include/trx0undo.h	2011-11-21 00:04:40 +0000
+++ b/storage/innobase/include/trx0undo.h	2012-02-17 09:58:18 +0000
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -194,16 +194,17 @@ trx_undo_get_first_rec(
 	mtr_t*	mtr);	/*!< in: mtr */
 /********************************************************************//**
 Tries to add a page to the undo log segment where the undo log is placed.
-@return	page number if success, else FIL_NULL */
+@return	X-latched block if success, else NULL */
 UNIV_INTERN
-ulint
+buf_block_t*
 trx_undo_add_page(
 /*==============*/
 	trx_t*		trx,	/*!< in: transaction */
 	trx_undo_t*	undo,	/*!< in: undo log memory object */
-	mtr_t*		mtr);	/*!< in: mtr which does not have a latch to any
+	mtr_t*		mtr)	/*!< in: mtr which does not have a latch to any
 				undo log page; the caller must have reserved
 				the rollback segment mutex */
+	__attribute__((nonnull, warn_unused_result));
 /********************************************************************//**
 Frees the last undo log page.
 The caller must hold the rollback segment mutex. */

=== modified file 'storage/innobase/include/univ.i'
--- a/storage/innobase/include/univ.i	2012-02-01 20:59:15 +0000
+++ b/storage/innobase/include/univ.i	2012-02-17 14:51:29 +0000
@@ -455,6 +455,8 @@ typedef unsigned long long int	ullint;
 /** The 'undefined' value for a ulint */
 #define ULINT_UNDEFINED		((ulint)(-1))
 
+#define ULONG_UNDEFINED		((ulong)(-1))
+
 /** The 'undefined' value for a ib_uint64_t */
 #define UINT64_UNDEFINED	((ib_uint64_t)(-1))
 

=== modified file 'storage/innobase/mtr/mtr0mtr.cc'
--- a/storage/innobase/mtr/mtr0mtr.cc	2012-02-16 10:52:14 +0000
+++ b/storage/innobase/mtr/mtr0mtr.cc	2012-02-17 09:58:18 +0000
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -87,11 +87,12 @@ mtr_memo_slot_release(
 			buf_page_release((buf_block_t*) object, type);
 		} else if (type == MTR_MEMO_S_LOCK) {
 			rw_lock_s_unlock((rw_lock_t*) object);
+#ifdef UNIV_DEBUG
 		} else if (type != MTR_MEMO_X_LOCK) {
-			ut_ad(type == MTR_MEMO_MODIFY
-			      || type == MTR_MEMO_FREE_CLUST_LEAF);
+			ut_ad(type == MTR_MEMO_MODIFY);
 			ut_ad(mtr_memo_contains(mtr, object,
 						MTR_MEMO_PAGE_X_FIX));
+#endif /* UNIV_DEBUG */
 		} else {
 			rw_lock_x_unlock((rw_lock_t*) object);
 		}

=== modified file 'storage/innobase/row/row0ins.cc'
--- a/storage/innobase/row/row0ins.cc	2012-02-16 13:59:09 +0000
+++ b/storage/innobase/row/row0ins.cc	2012-02-17 09:58:18 +0000
@@ -23,7 +23,6 @@ Insert into a table
 Created 4/20/1996 Heikki Tuuri
 *******************************************************/
 
-#include "my_global.h" /* HAVE_* */
 #include "m_string.h" /* for my_sys.h */
 #include "my_sys.h" /* DEBUG_SYNC_C */
 #include "row0ins.h"
@@ -2228,30 +2227,40 @@ row_ins_index_entry_low(
 			if (big_rec) {
 				ut_a(err == DB_SUCCESS);
 				/* Write out the externally stored
-				columns, but allocate the pages and
-				write the pointers using the
-				mini-transaction of the record update.
-				If any pages were freed in the update,
-				temporarily mark them allocated so
-				that off-page columns will not
-				overwrite them. We must do this,
-				because we will write the redo log for
-				the BLOB writes before writing the
-				redo log for the record update. Thus,
-				redo log application at crash recovery
-				will see BLOBs being written to free pages. */
-
-				btr_mark_freed_leaves(index, &mtr, TRUE);
+				columns while still x-latching
+				index->lock and block->lock. Allocate
+				pages for big_rec in the mtr that
+				modified the B-tree, but be sure to skip
+				any pages that were freed in mtr. We will
+				write out the big_rec pages before
+				committing the B-tree mini-transaction. If
+				the system crashes so that crash recovery
+				will not replay the mtr_commit(&mtr), the
+				big_rec pages will be left orphaned until
+				the pages are allocated for something else.
+
+				TODO: If the allocation extends the
+				tablespace, it will not be redo
+				logged, in either mini-transaction.
+				Tablespace extension should be
+				redo-logged in the big_rec
+				mini-transaction, so that recovery
+				will not fail when the big_rec was
+				written to the extended portion of the
+				file, in case the file was somehow
+				truncated in the crash. */
 
 				rec = btr_cur_get_rec(&cursor);
 				offsets = rec_get_offsets(
 					rec, index, NULL,
 					ULINT_UNDEFINED, &heap);
 
+				DEBUG_SYNC_C("before_row_ins_upd_extern");
 				err = btr_store_big_rec_extern_fields(
 					index, btr_cur_get_block(&cursor),
 					rec, offsets, big_rec, &mtr,
-					FALSE, &mtr);
+					BTR_STORE_INSERT_UPDATE);
+				DEBUG_SYNC_C("after_row_ins_upd_extern");
 				/* If writing big_rec fails (for
 				example, because of DB_OUT_OF_FILE_SPACE),
 				the record will be corrupted. Even if
@@ -2262,11 +2271,14 @@ row_ins_index_entry_low(
 				external storage. This non-update
 				would not have been written to the
 				undo log, and thus the record cannot
-				be rolled back. */
+				be rolled back.
+
+				However, because we have not executed
+				mtr_commit(mtr) yet, the update will
+				not be replayed in crash recovery, and
+				the following assertion failure will
+				effectively "roll back" the operation. */
 				ut_a(err == DB_SUCCESS);
-				/* Free the pages again
-				in order to avoid a leak. */
-				btr_mark_freed_leaves(index, &mtr, FALSE);
 				goto stored_big_rec;
 			}
 		} else {
@@ -2311,11 +2323,11 @@ function_exit:
 		offsets = rec_get_offsets(rec, index, NULL,
 					  ULINT_UNDEFINED, &heap);
 
-		DEBUG_SYNC_C("before_row_ins_upd_extern");
+		DEBUG_SYNC_C("before_row_ins_extern");
 		err = btr_store_big_rec_extern_fields(
 			index, btr_cur_get_block(&cursor),
-			rec, offsets, big_rec, &mtr, FALSE, NULL);
-		DEBUG_SYNC_C("after_row_ins_upd_extern");
+			rec, offsets, big_rec, &mtr, BTR_STORE_INSERT);
+		DEBUG_SYNC_C("after_row_ins_extern");
 
 stored_big_rec:
 		if (modify) {

=== modified file 'storage/innobase/row/row0upd.cc'
--- a/storage/innobase/row/row0upd.cc	2012-02-16 13:59:09 +0000
+++ b/storage/innobase/row/row0upd.cc	2012-02-17 09:58:18 +0000
@@ -23,7 +23,6 @@ Update of a row
 Created 12/27/1996 Heikki Tuuri
 *******************************************************/
 
-#include "my_global.h" /* HAVE_* */
 #include "m_string.h" /* for my_sys.h */
 #include "my_sys.h" /* DEBUG_SYNC_C */
 #include "row0upd.h"
@@ -2115,28 +2114,39 @@ row_upd_clust_rec(
 		BTR_NO_LOCKING_FLAG | BTR_KEEP_POS_FLAG, btr_cur,
 		&heap, &big_rec, node->update, node->cmpl_info, thr, mtr);
 	if (big_rec) {
-		ulint		offsets_[REC_OFFS_NORMAL_SIZE];
-		rec_t*		rec;
+		ulint	offsets_[REC_OFFS_NORMAL_SIZE];
+		rec_t*	rec;
 		rec_offs_init(offsets_);
 
 		ut_a(err == DB_SUCCESS);
-		/* Write out the externally stored columns, but
-		allocate the pages and write the pointers using the
-		mini-transaction of the record update. If any pages
-		were freed in the update, temporarily mark them
-		allocated so that off-page columns will not overwrite
-		them. We must do this, because we write the redo log
-		for the BLOB writes before writing the redo log for
-		the record update. */
+		/* Write out the externally stored
+		columns while still x-latching
+		index->lock and block->lock. Allocate
+		pages for big_rec in the mtr that
+		modified the B-tree, but be sure to skip
+		any pages that were freed in mtr. We will
+		write out the big_rec pages before
+		committing the B-tree mini-transaction. If
+		the system crashes so that crash recovery
+		will not replay the mtr_commit(&mtr), the
+		big_rec pages will be left orphaned until
+		the pages are allocated for something else.
+
+		TODO: If the allocation extends the tablespace, it
+		will not be redo logged, in either mini-transaction.
+		Tablespace extension should be redo-logged in the
+		big_rec mini-transaction, so that recovery will not
+		fail when the big_rec was written to the extended
+		portion of the file, in case the file was somehow
+		truncated in the crash. */
 
-		btr_mark_freed_leaves(index, mtr, TRUE);
 		rec = btr_cur_get_rec(btr_cur);
 		DEBUG_SYNC_C("before_row_upd_extern");
 		err = btr_store_big_rec_extern_fields(
 			index, btr_cur_get_block(btr_cur), rec,
 			rec_get_offsets(rec, index, offsets_,
 					ULINT_UNDEFINED, &heap),
-			big_rec, mtr, TRUE, mtr);
+			big_rec, mtr, BTR_STORE_UPDATE);
 		DEBUG_SYNC_C("after_row_upd_extern");
 		/* If writing big_rec fails (for example, because of
 		DB_OUT_OF_FILE_SPACE), the record will be corrupted.
@@ -2145,10 +2155,13 @@ row_upd_clust_rec(
 		that a non-updated column was selected for external
 		storage. This non-update would not have been written
 		to the undo log, and thus the record cannot be rolled
-		back. */
+		back.
+
+		However, because we have not executed mtr_commit(mtr)
+		yet, the update will not be replayed in crash
+		recovery, and the following assertion failure will
+		effectively "roll back" the operation. */
 		ut_a(err == DB_SUCCESS);
-		/* Free the pages again in order to avoid a leak. */
-		btr_mark_freed_leaves(index, mtr, FALSE);
 	}
 
 	mtr_commit(mtr);

=== modified file 'storage/innobase/srv/srv0start.cc'
--- a/storage/innobase/srv/srv0start.cc	2012-02-16 18:16:36 +0000
+++ b/storage/innobase/srv/srv0start.cc	2012-02-17 14:51:29 +0000
@@ -2181,7 +2181,7 @@ innobase_start_or_create_for_mysql(void)
 	if (srv_available_undo_logs == ULINT_UNDEFINED) {
 		/* Can only happen if force recovery is set. */
 		ut_a(srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
-		srv_undo_logs = ULINT_UNDEFINED;
+		srv_undo_logs = ULONG_UNDEFINED;
 	}
 
 	/* Create the thread which watches the timeouts for lock waits */

=== modified file 'storage/innobase/trx/trx0rec.cc'
--- a/storage/innobase/trx/trx0rec.cc	2012-01-26 11:57:53 +0000
+++ b/storage/innobase/trx/trx0rec.cc	2012-02-17 09:58:18 +0000
@@ -1204,6 +1204,7 @@ trx_undo_report_row_operation(
 	trx_t*		trx;
 	trx_undo_t*	undo;
 	ulint		page_no;
+	buf_block_t*	undo_block;
 	trx_rseg_t*	rseg;
 	mtr_t		mtr;
 	ulint		err		= DB_SUCCESS;
@@ -1231,67 +1232,70 @@ trx_undo_report_row_operation(
 	trx = thr_get_trx(thr);
 	rseg = trx->rseg;
 
-	mutex_enter(&(trx->undo_mutex));
+	mtr_start(&mtr);
+	mutex_enter(&trx->undo_mutex);
 
 	/* If the undo log is not assigned yet, assign one */
 
-	if (op_type == TRX_UNDO_INSERT_OP) {
+	switch (op_type) {
+	case TRX_UNDO_INSERT_OP:
+		undo = trx->insert_undo;
 
-		if (trx->insert_undo == NULL) {
+		if (undo == NULL) {
 
 			err = trx_undo_assign_undo(trx, TRX_UNDO_INSERT);
-		}
-
-		undo = trx->insert_undo;
+			undo = trx->insert_undo;
 
-		if (UNIV_UNLIKELY(!undo)) {
-			/* Did not succeed */
-			mutex_exit(&(trx->undo_mutex));
+			if (undo == NULL) {
+				/* Did not succeed */
+				ut_ad(err != DB_SUCCESS);
+				goto err_exit;
+			}
 
-			return(err);
+			ut_ad(err == DB_SUCCESS);
 		}
-	} else {
+		break;
+	default:
 		ut_ad(op_type == TRX_UNDO_MODIFY_OP);
 
-		if (trx->update_undo == NULL) {
+		undo = trx->update_undo;
 
+		if (undo == NULL) {
 			err = trx_undo_assign_undo(trx, TRX_UNDO_UPDATE);
+			undo = trx->update_undo;
 
+			if (undo == NULL) {
+				/* Did not succeed */
+				ut_ad(err != DB_SUCCESS);
+				goto err_exit;
+			}
 		}
 
-		undo = trx->update_undo;
-
-		if (UNIV_UNLIKELY(!undo)) {
-			/* Did not succeed */
-			mutex_exit(&(trx->undo_mutex));
-			return(err);
-		}
-
+		ut_ad(err == DB_SUCCESS);
 		offsets = rec_get_offsets(rec, index, offsets,
 					  ULINT_UNDEFINED, &heap);
 	}
 
 	page_no = undo->last_page_no;
-
-	mtr_start(&mtr);
+	undo_block = buf_page_get_gen(
+		undo->space, undo->zip_size, page_no, RW_X_LATCH,
+		undo->guess_block, BUF_GET, __FILE__, __LINE__, &mtr);
+	buf_block_dbg_add_level(undo_block, SYNC_TRX_UNDO_PAGE);
 
 	do {
-		buf_block_t*	undo_block;
 		page_t*		undo_page;
 		ulint		offset;
 
-		undo_block = buf_page_get_gen(undo->space, undo->zip_size,
-					      page_no, RW_X_LATCH,
-					      undo->guess_block, BUF_GET,
-					      __FILE__, __LINE__, &mtr);
-		buf_block_dbg_add_level(undo_block, SYNC_TRX_UNDO_PAGE);
-
 		undo_page = buf_block_get_frame(undo_block);
+		ut_ad(page_no == buf_block_get_page_no(undo_block));
 
-		if (op_type == TRX_UNDO_INSERT_OP) {
+		switch (op_type) {
+		case TRX_UNDO_INSERT_OP:
 			offset = trx_undo_page_report_insert(
 				undo_page, trx, index, clust_entry, &mtr);
-		} else {
+			break;
+		default:
+			ut_ad(op_type == TRX_UNDO_MODIFY_OP);
 			offset = trx_undo_page_report_modify(
 				undo_page, trx, index, rec, offsets, update,
 				cmpl_info, &mtr);
@@ -1363,12 +1367,12 @@ trx_undo_report_row_operation(
 		a pessimistic insert in a B-tree, and we must reserve the
 		counterpart of the tree latch, which is the rseg mutex. */
 
-		mutex_enter(&(rseg->mutex));
-
-		page_no = trx_undo_add_page(trx, undo, &mtr);
+		mutex_enter(&rseg->mutex);
+		undo_block = trx_undo_add_page(trx, undo, &mtr);
+		mutex_exit(&rseg->mutex);
 
-		mutex_exit(&(rseg->mutex));
-	} while (UNIV_LIKELY(page_no != FIL_NULL));
+		page_no = undo->last_page_no;
+	} while (undo_block != NULL);
 
 	/* Did not succeed: out of space */
 	err = DB_OUT_OF_FILE_SPACE;

=== modified file 'storage/innobase/trx/trx0trx.cc'
--- a/storage/innobase/trx/trx0trx.cc	2012-02-14 06:30:44 +0000
+++ b/storage/innobase/trx/trx0trx.cc	2012-02-17 00:56:47 +0000
@@ -624,7 +624,7 @@ UNIV_INLINE
 trx_rseg_t*
 trx_assign_rseg(
 /*============*/
-	ulint	max_undo_logs,	/*!< in: maximum number of UNDO logs to use */
+	ulong	max_undo_logs,	/*!< in: maximum number of UNDO logs to use */
 	ulint	n_tablespaces)	/*!< in: number of rollback tablespaces */
 {
 	ulint		i;
@@ -632,7 +632,7 @@ trx_assign_rseg(
 	static ulint	latest_rseg = 0;
 
 	if (srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO) {
-		ut_a(max_undo_logs == ULINT_UNDEFINED);
+		ut_a(max_undo_logs == ULONG_UNDEFINED);
 		return(NULL);
 	}
 

=== modified file 'storage/innobase/trx/trx0undo.cc'
--- a/storage/innobase/trx/trx0undo.cc	2011-12-19 08:43:28 +0000
+++ b/storage/innobase/trx/trx0undo.cc	2012-02-17 09:58:18 +0000
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -879,9 +879,9 @@ trx_undo_discard_latest_update_undo(
 #ifndef UNIV_HOTBACKUP
 /********************************************************************//**
 Tries to add a page to the undo log segment where the undo log is placed.
-@return	page number if success, else FIL_NULL */
+@return	X-latched block if success, else NULL */
 UNIV_INTERN
-ulint
+buf_block_t*
 trx_undo_add_page(
 /*==============*/
 	trx_t*		trx,	/*!< in: transaction */
@@ -891,11 +891,10 @@ trx_undo_add_page(
 				the rollback segment mutex */
 {
 	page_t*		header_page;
+	buf_block_t*	new_block;
 	page_t*		new_page;
 	trx_rseg_t*	rseg;
-	ulint		page_no;
 	ulint		n_reserved;
-	ibool		success;
 
 	ut_ad(mutex_own(&(trx->undo_mutex)));
 	ut_ad(mutex_own(&(trx->rseg->mutex)));
@@ -904,37 +903,37 @@ trx_undo_add_page(
 
 	if (rseg->curr_size == rseg->max_size) {
 
-		return(FIL_NULL);
+		return(NULL);
 	}
 
 	header_page = trx_undo_page_get(undo->space, undo->zip_size,
 					undo->hdr_page_no, mtr);
 
-	success = fsp_reserve_free_extents(&n_reserved, undo->space, 1,
-					   FSP_UNDO, mtr);
-	if (!success) {
+	if (!fsp_reserve_free_extents(&n_reserved, undo->space, 1,
+				      FSP_UNDO, mtr)) {
 
-		return(FIL_NULL);
+		return(NULL);
 	}
 
-	page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR
-					       + TRX_UNDO_FSEG_HEADER,
-					       undo->top_page_no + 1, FSP_UP,
-					       TRUE, mtr, mtr);
+	new_block = fseg_alloc_free_page_general(
+		TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER
+		+ header_page,
+		undo->top_page_no + 1, FSP_UP, TRUE, mtr, mtr);
 
 	fil_space_release_free_extents(undo->space, n_reserved);
 
-	if (page_no == FIL_NULL) {
+	if (new_block == NULL) {
 
 		/* No space left */
 
-		return(FIL_NULL);
+		return(NULL);
 	}
 
-	undo->last_page_no = page_no;
+	ut_ad(rw_lock_get_x_lock_count(&new_block->lock) == 1);
+	buf_block_dbg_add_level(new_block, SYNC_TRX_UNDO_PAGE);
+	undo->last_page_no = buf_block_get_page_no(new_block);
 
-	new_page = trx_undo_page_get(undo->space, undo->zip_size,
-				     page_no, mtr);
+	new_page = buf_block_get_frame(new_block);
 
 	trx_undo_page_init(new_page, undo->type, mtr);
 
@@ -943,7 +942,7 @@ trx_undo_add_page(
 	undo->size++;
 	rseg->curr_size++;
 
-	return(page_no);
+	return(new_block);
 }
 
 /********************************************************************//**

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk-wl3584 branch (luis.soares:3656 to 3657) Luis Soares20 Feb