List:Commits« Previous MessageNext Message »
From:Hakan Kuecuekyilmaz Date:September 20 2008 6:30am
Subject:bzr commit into mysql-6.0-falcon branch (hky:2828)
View as plain text  
#At file:///home/hakan/work/mysql/mysql-6.0-falcon-team-to-merge/

 2828 Hakan Kuecuekyilmaz	2008-09-20 [merge]
      Merge.
added:
  mysql-test/r/test_wl4435.result
  sql/records.h
  sql/transaction.cc
  sql/transaction.h
modified:
  .bzr-mysql/default.conf
  .bzrignore
  client/Makefile.am
  include/mysql.h
  include/mysql.h.pp
  include/mysql_com.h
  libmysql/client_settings.h
  libmysql/libmysql.c
  libmysql/libmysql.def
  libmysqld/CMakeLists.txt
  libmysqld/Makefile.am
  libmysqld/lib_sql.cc
  libmysqld/libmysqld.def
  mysql-test/r/events_bugs.result
  mysql-test/r/ps.result
  mysql-test/suite/falcon/r/falcon_bug_34164.result
  mysql-test/t/events_bugs.test
  mysql-test/t/ps.test
  sql/CMakeLists.txt
  sql/Makefile.am
  sql/backup/backup_test.cc
  sql/backup/be_snapshot.cc
  sql/backup/kernel.cc
  sql/events.cc
  sql/field.cc
  sql/field.h
  sql/handler.cc
  sql/handler.h
  sql/item.cc
  sql/item.h
  sql/lock.cc
  sql/log_event.cc
  sql/log_event_old.cc
  sql/mysql_priv.h
  sql/procedure.h
  sql/protocol.cc
  sql/protocol.h
  sql/records.cc
  sql/repl_failsafe.cc
  sql/rpl_injector.cc
  sql/rpl_injector.h
  sql/rpl_rli.cc
  sql/rpl_tblmap.cc
  sql/rpl_tblmap.h
  sql/set_var.cc
  sql/slave.cc
  sql/sp_head.cc
  sql/sql_acl.cc
  sql/sql_base.cc
  sql/sql_cache.h
  sql/sql_class.cc
  sql/sql_class.h
  sql/sql_cursor.cc
  sql/sql_do.cc
  sql/sql_error.cc
  sql/sql_handler.cc
  sql/sql_help.cc
  sql/sql_insert.cc
  sql/sql_lex.cc
  sql/sql_lex.h
  sql/sql_parse.cc
  sql/sql_partition.cc
  sql/sql_prepare.cc
  sql/sql_profile.cc
  sql/sql_repl.cc
  sql/sql_select.cc
  sql/sql_select.h
  sql/sql_show.cc
  sql/sql_table.cc
  sql/sql_yacc.yy
  sql/structs.h
  sql/table.cc
  sql/table.h
  storage/falcon/BDB.cpp
  storage/falcon/InfoTable.h
  storage/falcon/ha_falcon.cpp
  storage/falcon/ha_falcon.h
  storage/innobase/handler/ha_innodb.cc
  storage/maria/ha_maria.cc
  tests/mysql_client_test.c

=== modified file '.bzr-mysql/default.conf'
--- a/.bzr-mysql/default.conf	2008-09-11 18:36:05 +0000
+++ b/.bzr-mysql/default.conf	2008-09-16 17:58:49 +0000
@@ -1,5 +1,5 @@
-[MYSQL]
-tree_location = bzr+ssh://bk-internal.mysql.com/bzrroot/server/mysql-6.0-falcon
-post_commit_to = commits@stripped
-post_push_to = commits@stripped
-tree_name = mysql-6.0-falcon
+[MYSQL]
+tree_location = bzr+ssh://bk-internal.mysql.com/bzrroot/server/mysql-6.0-falcon
+post_commit_to = commits@stripped
+post_push_to = commits@stripped
+tree_name = mysql-6.0-falcon

=== modified file '.bzrignore'
--- a/.bzrignore	2008-08-26 10:20:41 +0000
+++ b/.bzrignore	2008-09-12 09:22:46 +0000
@@ -1891,3 +1891,5 @@ zlib/*.vcproj
 extra/libevent/event-config.h
 libmysqld/ddl_blocker.cc
 libmysqld/mdl.cc
+client/transaction.h
+libmysqld/transaction.cc

=== modified file 'client/Makefile.am'
--- a/client/Makefile.am	2008-08-20 16:21:14 +0000
+++ b/client/Makefile.am	2008-09-04 18:30:34 +0000
@@ -107,7 +107,8 @@ sql_src=log_event.h mysql_priv.h rpl_con
 	rpl_utility.h rpl_tblmap.h rpl_tblmap.cc \
 	log_event.cc my_decimal.h my_decimal.cc \
 	log_event_old.h log_event_old.cc \
-	rpl_record_old.h rpl_record_old.cc
+	rpl_record_old.h rpl_record_old.cc \
+	transaction.h
 strings_src=decimal.c dtoa.c
 
 link_sources:

=== modified file 'include/mysql.h'
--- a/include/mysql.h	2007-11-26 19:11:48 +0000
+++ b/include/mysql.h	2008-08-07 17:52:43 +0000
@@ -714,6 +714,7 @@ my_bool STDCALL mysql_rollback(MYSQL * m
 my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode);
 my_bool STDCALL mysql_more_results(MYSQL *mysql);
 int STDCALL mysql_next_result(MYSQL *mysql);
+int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt);
 void STDCALL mysql_close(MYSQL *sock);
 
 

=== modified file 'include/mysql.h.pp'
--- a/include/mysql.h.pp	2008-08-20 07:07:09 +0000
+++ b/include/mysql.h.pp	2008-09-12 08:38:48 +0000
@@ -612,4 +612,5 @@ my_bool mysql_rollback(MYSQL * mysql);
 my_bool mysql_autocommit(MYSQL * mysql, my_bool auto_mode);
 my_bool mysql_more_results(MYSQL *mysql);
 int mysql_next_result(MYSQL *mysql);
+int mysql_stmt_next_result(MYSQL_STMT *stmt);
 void mysql_close(MYSQL *sock);

=== modified file 'include/mysql_com.h'
--- a/include/mysql_com.h	2008-06-17 20:04:19 +0000
+++ b/include/mysql_com.h	2008-08-07 17:52:43 +0000
@@ -154,6 +154,7 @@ enum enum_server_command
 #define CLIENT_SECURE_CONNECTION 32768  /* New 4.1 authentication */
 #define CLIENT_MULTI_STATEMENTS (1UL << 16) /* Enable/disable multi-stmt support */
 #define CLIENT_MULTI_RESULTS    (1UL << 17) /* Enable/disable multi-results */
+#define CLIENT_PS_MULTI_RESULTS (1UL << 18) /* Multi-results in PS-protocol */
 
 #define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30)
 #define CLIENT_REMEMBER_OPTIONS (1UL << 31)
@@ -177,6 +178,7 @@ enum enum_server_command
                            CLIENT_SECURE_CONNECTION | \
                            CLIENT_MULTI_STATEMENTS | \
                            CLIENT_MULTI_RESULTS | \
+                           CLIENT_PS_MULTI_RESULTS | \
                            CLIENT_SSL_VERIFY_SERVER_CERT | \
                            CLIENT_REMEMBER_OPTIONS)
 
@@ -221,6 +223,11 @@ enum enum_server_command
 #define SERVER_QUERY_WAS_SLOW           2048
 
 /**
+  To mark ResultSet containing output parameter values.
+*/
+#define SERVER_PS_OUT_PARAMS            4096
+
+/**
   Server status flags that must be cleared when starting
   execution of a new SQL statement.
   Flags from this set are only added to the

=== modified file 'libmysql/client_settings.h'
--- a/libmysql/client_settings.h	2007-09-29 19:31:08 +0000
+++ b/libmysql/client_settings.h	2008-08-07 17:52:43 +0000
@@ -16,9 +16,13 @@
 extern uint		mysql_port;
 extern char *	mysql_unix_port;
 
-#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG |	  \
-                             CLIENT_TRANSACTIONS | \
-			     CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION)
+#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | \
+                             CLIENT_LONG_FLAG |     \
+                             CLIENT_TRANSACTIONS |  \
+                             CLIENT_PROTOCOL_41 | \
+                             CLIENT_SECURE_CONNECTION | \
+                             CLIENT_MULTI_RESULTS | \
+                             CLIENT_PS_MULTI_RESULTS)
 
 sig_handler my_pipe_sig_handler(int sig);
 void read_user_name(char *name);

=== modified file 'libmysql/libmysql.c'
--- a/libmysql/libmysql.c	2008-06-17 20:04:19 +0000
+++ b/libmysql/libmysql.c	2008-08-07 17:52:43 +0000
@@ -1725,6 +1725,8 @@ static void alloc_stmt_fields(MYSQL_STMT
   MEM_ROOT *alloc= &stmt->mem_root;
   MYSQL *mysql= stmt->mysql;
 
+  DBUG_ASSERT(mysql->field_count);
+
   stmt->field_count= mysql->field_count;
 
   /*
@@ -1746,6 +1748,7 @@ static void alloc_stmt_fields(MYSQL_STMT
 	 field= stmt->fields;
        field && fields < end; fields++, field++)
   {
+    field->catalog  = strdup_root(alloc,fields->catalog);
     field->db       = strdup_root(alloc,fields->db);
     field->table    = strdup_root(alloc,fields->table);
     field->org_table= strdup_root(alloc,fields->org_table);
@@ -2484,6 +2487,33 @@ static void reinit_result_set_metadata(M
 }
 
 
+static void prepare_to_fetch_result(MYSQL_STMT *stmt)
+{
+  if (stmt->server_status & SERVER_STATUS_CURSOR_EXISTS)
+  {
+    stmt->mysql->status= MYSQL_STATUS_READY;
+    stmt->read_row_func= stmt_read_row_from_cursor;
+  }
+  else if (stmt->flags & CURSOR_TYPE_READ_ONLY)
+  {
+    /*
+      This is a single-row result set, a result set with no rows, EXPLAIN,
+      SHOW VARIABLES, or some other command which either a) bypasses the
+      cursors framework in the server and writes rows directly to the
+      network or b) is more efficient if all (few) result set rows are
+      precached on client and server's resources are freed.
+    */
+    mysql_stmt_store_result(stmt);
+  }
+  else
+  {
+    stmt->mysql->unbuffered_fetch_owner= &stmt->unbuffered_fetch_cancelled;
+    stmt->unbuffered_fetch_cancelled= FALSE;
+    stmt->read_row_func= stmt_read_row_unbuffered;
+  }
+}
+
+
 /*
   Send placeholders data to server (if there are placeholders)
   and execute prepared statement.
@@ -2551,28 +2581,7 @@ int STDCALL mysql_stmt_execute(MYSQL_STM
   if (mysql->field_count)
   {
     reinit_result_set_metadata(stmt);
-    if (stmt->server_status & SERVER_STATUS_CURSOR_EXISTS)
-    {
-      mysql->status= MYSQL_STATUS_READY;
-      stmt->read_row_func= stmt_read_row_from_cursor;
-    }
-    else if (stmt->flags & CURSOR_TYPE_READ_ONLY)
-    {
-      /*
-        This is a single-row result set, a result set with no rows, EXPLAIN,
-        SHOW VARIABLES, or some other command which either a) bypasses the
-        cursors framework in the server and writes rows directly to the
-        network or b) is more efficient if all (few) result set rows are
-        precached on client and server's resources are freed.
-      */
-      mysql_stmt_store_result(stmt);
-    }
-    else
-    {
-      stmt->mysql->unbuffered_fetch_owner= &stmt->unbuffered_fetch_cancelled;
-      stmt->unbuffered_fetch_cancelled= FALSE;
-      stmt->read_row_func= stmt_read_row_unbuffered;
-    }
+    prepare_to_fetch_result(stmt);
   }
   DBUG_RETURN(test(stmt->last_errno));
 }
@@ -4831,6 +4840,46 @@ int STDCALL mysql_next_result(MYSQL *mys
 }
 
 
+int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt)
+{
+  MYSQL *mysql= stmt->mysql;
+  int rc;
+  DBUG_ENTER("mysql_stmt_next_result");
+
+  if (!mysql)
+    DBUG_RETURN(1);
+
+  if (stmt->last_errno)
+    DBUG_RETURN(stmt->last_errno);
+
+  if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
+  {
+    if (reset_stmt_handle(stmt, RESET_STORE_RESULT))
+      DBUG_RETURN(1);
+  }
+
+  rc= mysql_next_result(mysql);
+
+  if (rc)
+    DBUG_RETURN(rc);
+
+  stmt->state= MYSQL_STMT_EXECUTE_DONE;
+  stmt->bind_result_done= FALSE;
+
+  if (mysql->field_count)
+  {
+    alloc_stmt_fields(stmt);
+    prepare_to_fetch_result(stmt);
+  }
+  else
+  {
+    stmt->field_count= mysql->field_count;
+  }
+
+  DBUG_RETURN(0);
+}
+
+
 MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql)
 {
   return (*mysql->methods->use_result)(mysql);

=== modified file 'libmysql/libmysql.def'
--- a/libmysql/libmysql.def	2007-12-04 15:27:44 +0000
+++ b/libmysql/libmysql.def	2008-08-11 10:03:45 +0000
@@ -142,3 +142,4 @@ EXPORTS
 	mysql_get_character_set_info
 	get_defaults_options
 	modify_defaults_file
+        mysql_stmt_next_result

=== modified file 'libmysqld/CMakeLists.txt'
--- a/libmysqld/CMakeLists.txt	2008-07-09 07:12:43 +0000
+++ b/libmysqld/CMakeLists.txt	2008-08-08 01:33:43 +0000
@@ -203,6 +203,7 @@ SET(LIBMYSQLD_SOURCES emb_qcache.cc libm
            ../sql/scheduler.cc ../sql/sql_audit.cc
            ../sql/ddl_blocker.cc ../sql/si_objects.cc
            ../sql/event_parse_data.cc ../sql/mdl.cc
+           ../sql/transaction.cc
            ${GEN_SOURCES}
            ${LIB_SOURCES})
 

=== modified file 'libmysqld/Makefile.am'
--- a/libmysqld/Makefile.am	2008-07-09 07:12:43 +0000
+++ b/libmysqld/Makefile.am	2008-08-08 01:33:43 +0000
@@ -78,8 +78,7 @@ sqlsources = derror.cc field.cc field_co
 	sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
 	parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
 	rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
-	debug_sync.cc \
-	sql_tablespace.cc \
+	debug_sync.cc sql_tablespace.cc transaction.cc \
 	rpl_injector.cc my_user.c partition_info.cc \
 	sql_servers.cc ddl_blocker.cc si_objects.cc sql_audit.cc \
         event_parse_data.cc mdl.cc

=== modified file 'libmysqld/lib_sql.cc'
--- a/libmysqld/lib_sql.cc	2008-08-13 19:17:28 +0000
+++ b/libmysqld/lib_sql.cc	2008-09-04 18:30:34 +0000
@@ -870,7 +870,7 @@ void Protocol_text::remove_last_row()
 }
 
 
-bool Protocol::send_fields(List<Item> *list, uint flags)
+bool Protocol::send_result_set_metadata(List<Item> *list, uint flags)
 {
   List_iterator_fast<Item> it(*list);
   Item                     *item;
@@ -879,7 +879,7 @@ bool Protocol::send_fields(List<Item> *l
   CHARSET_INFO             *thd_cs= thd->variables.character_set_results;
   CHARSET_INFO             *cs= system_charset_info;
   MYSQL_DATA               *data;
-  DBUG_ENTER("send_fields");
+  DBUG_ENTER("send_result_set_metadata");
 
   if (!thd->mysql)            // bootstrap file handling
     DBUG_RETURN(0);
@@ -972,7 +972,7 @@ bool Protocol::send_fields(List<Item> *l
   if (flags & SEND_EOF)
     write_eof_packet(thd, thd->server_status, thd->total_warn_count);
 
-  DBUG_RETURN(prepare_for_send(list));
+  DBUG_RETURN(prepare_for_send(list->elements));
  err:
   my_error(ER_OUT_OF_RESOURCES, MYF(0));        /* purecov: inspected */
   DBUG_RETURN(1);				/* purecov: inspected */

=== modified file 'libmysqld/libmysqld.def'
--- a/libmysqld/libmysqld.def	2007-12-04 15:27:44 +0000
+++ b/libmysqld/libmysqld.def	2008-08-11 10:03:45 +0000
@@ -170,3 +170,4 @@ EXPORTS
 	my_charset_bin
 	my_charset_same
 	modify_defaults_file
+        mysql_stmt_next_result

=== modified file 'mysql-test/r/events_bugs.result'
--- a/mysql-test/r/events_bugs.result	2008-02-19 14:09:52 +0000
+++ b/mysql-test/r/events_bugs.result	2008-09-12 19:34:30 +0000
@@ -736,3 +736,5 @@ select name from mysql.event where name 
 name
 drop event e1;
 DROP DATABASE events_test;
+# restore the defeault
+SET GLOBAL event_scheduler = 'on';

=== modified file 'mysql-test/r/ps.result'
--- a/mysql-test/r/ps.result	2008-07-24 10:00:56 +0000
+++ b/mysql-test/r/ps.result	2008-08-07 17:52:43 +0000
@@ -2920,4 +2920,165 @@ execute stmt;
 Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status	Originator	character_set_client	collation_connection	Database Collation
 drop table t1;
 deallocate prepare stmt;
+
 End of 5.1 tests.
+
+#
+# WL#4435: Support OUT-parameters in prepared statements.
+#
+
+DROP PROCEDURE IF EXISTS p_string;
+DROP PROCEDURE IF EXISTS p_double;
+DROP PROCEDURE IF EXISTS p_int;
+DROP PROCEDURE IF EXISTS p_decimal;
+
+CREATE PROCEDURE p_string(
+IN v0 INT,
+OUT v1 CHAR(32),
+IN v2 CHAR(32),
+INOUT v3 CHAR(32))
+BEGIN
+SET v0 = -1;
+SET v1 = 'test_v1';
+SET v2 = 'n/a';
+SET v3 = 'test_v3';
+END|
+
+CREATE PROCEDURE p_double(
+IN v0 INT,
+OUT v1 DOUBLE(4, 2),
+IN v2 DOUBLE(4, 2),
+INOUT v3 DOUBLE(4, 2))
+BEGIN
+SET v0 = -1;
+SET v1 = 12.34;
+SET v2 = 98.67;
+SET v3 = 56.78;
+END|
+
+CREATE PROCEDURE p_int(
+IN v0 CHAR(10),
+OUT v1 INT,
+IN v2 INT,
+INOUT v3 INT)
+BEGIN
+SET v0 = 'n/a';
+SET v1 = 1234;
+SET v2 = 9876;
+SET v3 = 5678;
+END|
+
+CREATE PROCEDURE p_decimal(
+IN v0 INT,
+OUT v1 DECIMAL(4, 2),
+IN v2 DECIMAL(4, 2),
+INOUT v3 DECIMAL(4, 2))
+BEGIN
+SET v0 = -1;
+SET v1 = 12.34;
+SET v2 = 98.67;
+SET v3 = 56.78;
+END|
+
+PREPARE stmt_str FROM 'CALL p_string(?, ?, ?, ?)';
+PREPARE stmt_dbl FROM 'CALL p_double(?, ?, ?, ?)';
+PREPARE stmt_int FROM 'CALL p_int(?, ?, ?, ?)';
+PREPARE stmt_dec FROM 'CALL p_decimal(?, ?, ?, ?)';
+
+SET @x_str_1 = NULL;
+SET @x_str_2 = NULL;
+SET @x_str_3 = NULL;
+SET @x_dbl_1 = NULL;
+SET @x_dbl_2 = NULL;
+SET @x_dbl_3 = NULL;
+SET @x_int_1 = NULL;
+SET @x_int_2 = NULL;
+SET @x_int_3 = NULL;
+SET @x_dec_1 = NULL;
+SET @x_dec_2 = NULL;
+SET @x_dec_3 = NULL;
+
+-- Testing strings...
+
+EXECUTE stmt_str USING @x_int_1, @x_str_1, @x_str_2, @x_str_3;
+SELECT @x_int_1, @x_str_1, @x_str_2, @x_str_3;
+@x_int_1	@x_str_1	@x_str_2	@x_str_3
+NULL	test_v1	NULL	test_v3
+
+EXECUTE stmt_str USING @x_int_1, @x_str_1, @x_str_2, @x_str_3;
+SELECT @x_int_1, @x_str_1, @x_str_2, @x_str_3;
+@x_int_1	@x_str_1	@x_str_2	@x_str_3
+NULL	test_v1	NULL	test_v3
+
+-- Testing doubles...
+
+EXECUTE stmt_dbl USING @x_int_1, @x_dbl_1, @x_dbl_2, @x_dbl_3;
+SELECT @x_int_1, @x_dbl_1, @x_dbl_2, @x_dbl_3;
+@x_int_1	@x_dbl_1	@x_dbl_2	@x_dbl_3
+NULL	12.34	NULL	56.78
+
+EXECUTE stmt_dbl USING @x_int_1, @x_dbl_1, @x_dbl_2, @x_dbl_3;
+SELECT @x_int_1, @x_dbl_1, @x_dbl_2, @x_dbl_3;
+@x_int_1	@x_dbl_1	@x_dbl_2	@x_dbl_3
+NULL	12.34	NULL	56.78
+
+-- Testing ints...
+
+EXECUTE stmt_int USING @x_str_1, @x_int_1, @x_int_2, @x_int_3;
+SELECT @x_str_1, @x_int_1, @x_int_2, @x_int_3;
+@x_str_1	@x_int_1	@x_int_2	@x_int_3
+test_v1	1234	NULL	5678
+
+EXECUTE stmt_int USING @x_str_1, @x_int_1, @x_int_2, @x_int_3;
+SELECT @x_str_1, @x_int_1, @x_int_2, @x_int_3;
+@x_str_1	@x_int_1	@x_int_2	@x_int_3
+test_v1	1234	NULL	5678
+
+-- Testing decs...
+
+EXECUTE stmt_dec USING @x_int_1, @x_dec_1, @x_dec_2, @x_dec_3;
+SELECT @x_int_1, @x_dec_1, @x_dec_2, @x_dec_3;
+@x_int_1	@x_dec_1	@x_dec_2	@x_dec_3
+1234	12.34	NULL	56.78
+
+EXECUTE stmt_dec USING @x_int_1, @x_dec_1, @x_dec_2, @x_dec_3;
+SELECT @x_int_1, @x_dec_1, @x_dec_2, @x_dec_3;
+@x_int_1	@x_dec_1	@x_dec_2	@x_dec_3
+1234	12.34	NULL	56.78
+
+DEALLOCATE PREPARE stmt_str;
+DEALLOCATE PREPARE stmt_dbl;
+DEALLOCATE PREPARE stmt_int;
+DEALLOCATE PREPARE stmt_dec;
+
+DROP PROCEDURE p_string;
+DROP PROCEDURE p_double;
+DROP PROCEDURE p_int;
+DROP PROCEDURE p_decimal;
+
+DROP PROCEDURE IF EXISTS p1;
+DROP PROCEDURE IF EXISTS p2;
+
+CREATE PROCEDURE p1(OUT v1 CHAR(10))
+SET v1 = 'test1';
+
+CREATE PROCEDURE p2(OUT v2 CHAR(10))
+BEGIN
+SET @query = 'CALL p1(?)';
+PREPARE stmt1 FROM @query;
+EXECUTE stmt1 USING @u1;
+DEALLOCATE PREPARE stmt1;
+SET v2 = @u1;
+END|
+
+CALL p2(@a);
+SELECT @a;
+@a
+test1
+
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+
+# End of WL#4435.
+
+End of 6.0 tests.

=== added file 'mysql-test/r/test_wl4435.result'
--- a/mysql-test/r/test_wl4435.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/test_wl4435.result	2008-08-07 17:52:43 +0000
@@ -0,0 +1,114 @@
+
+exec_counter: 0
+num_fields: 4
+  - 0: name: 'a1'/'a1'; table: 't1'/'t1'; db: 'client_test_db'; catalog: 'def'; length: 11; max_length: 0; type: 3; decimals: 0
+  - 1: name: 'a2'/'a2'; table: 't1'/'t1'; db: 'client_test_db'; catalog: 'def'; length: 32; max_length: 0; type: 254; decimals: 0
+  - 2: name: 'a3'/'a3'; table: 't1'/'t1'; db: 'client_test_db'; catalog: 'def'; length: 4; max_length: 0; type: 5; decimals: 2
+  - 3: name: 'a4'/'a4'; table: 't1'/'t1'; db: 'client_test_db'; catalog: 'def'; length: 5; max_length: 0; type: 246; decimals: 1
+Data:
+  int: 1; str: '11'; dbl: 12.340000; dec: '56.7';
+  int: 2; str: '12'; dbl: 56.780000; dec: '90.1';
+  int: 3; str: '13'; dbl: 23.450000; dec: '67.8';
+EOF
+mysql_stmt_next_result(): 0; field_count: 5
+num_fields: 5
+  - 0: name: 'b0'/'b0'; table: 't2'/'t2'; db: 'client_test_db'; catalog: 'def'; length: 11; max_length: 0; type: 3; decimals: 0
+  - 1: name: 'b1'/'b1'; table: 't2'/'t2'; db: 'client_test_db'; catalog: 'def'; length: 11; max_length: 0; type: 3; decimals: 0
+  - 2: name: 'b2'/'b2'; table: 't2'/'t2'; db: 'client_test_db'; catalog: 'def'; length: 32; max_length: 0; type: 254; decimals: 0
+  - 3: name: 'b3'/'b3'; table: 't2'/'t2'; db: 'client_test_db'; catalog: 'def'; length: 4; max_length: 0; type: 5; decimals: 2
+  - 4: name: 'b4'/'b4'; table: 't2'/'t2'; db: 'client_test_db'; catalog: 'def'; length: 5; max_length: 0; type: 246; decimals: 1
+Data:
+  int: 100; int: 10; str: '110'; dbl: 70.700000; dec: '10.1';
+  int: 200; int: 20; str: '120'; dbl: 80.800000; dec: '20.2';
+  int: 300; int: 30; str: '130'; dbl: 90.900000; dec: '30.3';
+EOF
+mysql_stmt_next_result(): 0; field_count: 8
+num_fields: 8
+  - 0: name: 'v_str_1'/'v_str_1'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 32; max_length: 0; type: 254; decimals: 0
+  - 1: name: 'v_dbl_1'/'v_dbl_1'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 4; max_length: 0; type: 5; decimals: 2
+  - 2: name: 'v_dec_1'/'v_dec_1'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 8; max_length: 0; type: 246; decimals: 3
+  - 3: name: 'v_int_1'/'v_int_1'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 11; max_length: 0; type: 3; decimals: 0
+  - 4: name: 'v_str_2'/'v_str_2'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 64; max_length: 0; type: 254; decimals: 0
+  - 5: name: 'v_dbl_2'/'v_dbl_2'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 5; max_length: 0; type: 5; decimals: 3
+  - 6: name: 'v_dec_2'/'v_dec_2'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 9; max_length: 0; type: 246; decimals: 4
+  - 7: name: 'v_int_2'/'v_int_2'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 11; max_length: 0; type: 3; decimals: 0
+Data:
+  str: 'test_1'; dbl: 12.340000; dec: '567.891'; int: 2345; str: 'test_2'; dbl: 67.891000; dec: '234.6789'; int: 6789;
+EOF
+mysql_stmt_next_result(): 0; field_count: 0
+
+exec_counter: 1
+num_fields: 4
+  - 0: name: 'a1'/'a1'; table: 't1'/'t1'; db: 'client_test_db'; catalog: 'def'; length: 11; max_length: 0; type: 3; decimals: 0
+  - 1: name: 'a2'/'a2'; table: 't1'/'t1'; db: 'client_test_db'; catalog: 'def'; length: 32; max_length: 0; type: 254; decimals: 0
+  - 2: name: 'a3'/'a3'; table: 't1'/'t1'; db: 'client_test_db'; catalog: 'def'; length: 4; max_length: 0; type: 5; decimals: 2
+  - 3: name: 'a4'/'a4'; table: 't1'/'t1'; db: 'client_test_db'; catalog: 'def'; length: 5; max_length: 0; type: 246; decimals: 1
+Data:
+  int: 1; str: '11'; dbl: 12.340000; dec: '56.7';
+  int: 2; str: '12'; dbl: 56.780000; dec: '90.1';
+  int: 3; str: '13'; dbl: 23.450000; dec: '67.8';
+EOF
+mysql_stmt_next_result(): 0; field_count: 5
+num_fields: 5
+  - 0: name: 'b0'/'b0'; table: 't2'/'t2'; db: 'client_test_db'; catalog: 'def'; length: 11; max_length: 0; type: 3; decimals: 0
+  - 1: name: 'b1'/'b1'; table: 't2'/'t2'; db: 'client_test_db'; catalog: 'def'; length: 11; max_length: 0; type: 3; decimals: 0
+  - 2: name: 'b2'/'b2'; table: 't2'/'t2'; db: 'client_test_db'; catalog: 'def'; length: 32; max_length: 0; type: 254; decimals: 0
+  - 3: name: 'b3'/'b3'; table: 't2'/'t2'; db: 'client_test_db'; catalog: 'def'; length: 4; max_length: 0; type: 5; decimals: 2
+  - 4: name: 'b4'/'b4'; table: 't2'/'t2'; db: 'client_test_db'; catalog: 'def'; length: 5; max_length: 0; type: 246; decimals: 1
+Data:
+  int: 100; int: 10; str: '110'; dbl: 70.700000; dec: '10.1';
+  int: 200; int: 20; str: '120'; dbl: 80.800000; dec: '20.2';
+  int: 300; int: 30; str: '130'; dbl: 90.900000; dec: '30.3';
+EOF
+mysql_stmt_next_result(): 0; field_count: 8
+num_fields: 8
+  - 0: name: 'v_str_1'/'v_str_1'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 32; max_length: 0; type: 254; decimals: 0
+  - 1: name: 'v_dbl_1'/'v_dbl_1'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 4; max_length: 0; type: 5; decimals: 2
+  - 2: name: 'v_dec_1'/'v_dec_1'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 8; max_length: 0; type: 246; decimals: 3
+  - 3: name: 'v_int_1'/'v_int_1'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 11; max_length: 0; type: 3; decimals: 0
+  - 4: name: 'v_str_2'/'v_str_2'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 64; max_length: 0; type: 254; decimals: 0
+  - 5: name: 'v_dbl_2'/'v_dbl_2'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 5; max_length: 0; type: 5; decimals: 3
+  - 6: name: 'v_dec_2'/'v_dec_2'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 9; max_length: 0; type: 246; decimals: 4
+  - 7: name: 'v_int_2'/'v_int_2'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 11; max_length: 0; type: 3; decimals: 0
+Data:
+  str: 'test_1'; dbl: 12.340000; dec: '567.891'; int: 2345; str: 'test_2'; dbl: 67.891000; dec: '234.6789'; int: 6789;
+EOF
+mysql_stmt_next_result(): 0; field_count: 0
+
+exec_counter: 2
+num_fields: 4
+  - 0: name: 'a1'/'a1'; table: 't1'/'t1'; db: 'client_test_db'; catalog: 'def'; length: 11; max_length: 0; type: 3; decimals: 0
+  - 1: name: 'a2'/'a2'; table: 't1'/'t1'; db: 'client_test_db'; catalog: 'def'; length: 32; max_length: 0; type: 254; decimals: 0
+  - 2: name: 'a3'/'a3'; table: 't1'/'t1'; db: 'client_test_db'; catalog: 'def'; length: 4; max_length: 0; type: 5; decimals: 2
+  - 3: name: 'a4'/'a4'; table: 't1'/'t1'; db: 'client_test_db'; catalog: 'def'; length: 5; max_length: 0; type: 246; decimals: 1
+Data:
+  int: 1; str: '11'; dbl: 12.340000; dec: '56.7';
+  int: 2; str: '12'; dbl: 56.780000; dec: '90.1';
+  int: 3; str: '13'; dbl: 23.450000; dec: '67.8';
+EOF
+mysql_stmt_next_result(): 0; field_count: 5
+num_fields: 5
+  - 0: name: 'b0'/'b0'; table: 't2'/'t2'; db: 'client_test_db'; catalog: 'def'; length: 11; max_length: 0; type: 3; decimals: 0
+  - 1: name: 'b1'/'b1'; table: 't2'/'t2'; db: 'client_test_db'; catalog: 'def'; length: 11; max_length: 0; type: 3; decimals: 0
+  - 2: name: 'b2'/'b2'; table: 't2'/'t2'; db: 'client_test_db'; catalog: 'def'; length: 32; max_length: 0; type: 254; decimals: 0
+  - 3: name: 'b3'/'b3'; table: 't2'/'t2'; db: 'client_test_db'; catalog: 'def'; length: 4; max_length: 0; type: 5; decimals: 2
+  - 4: name: 'b4'/'b4'; table: 't2'/'t2'; db: 'client_test_db'; catalog: 'def'; length: 5; max_length: 0; type: 246; decimals: 1
+Data:
+  int: 100; int: 10; str: '110'; dbl: 70.700000; dec: '10.1';
+  int: 200; int: 20; str: '120'; dbl: 80.800000; dec: '20.2';
+  int: 300; int: 30; str: '130'; dbl: 90.900000; dec: '30.3';
+EOF
+mysql_stmt_next_result(): 0; field_count: 8
+num_fields: 8
+  - 0: name: 'v_str_1'/'v_str_1'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 32; max_length: 0; type: 254; decimals: 0
+  - 1: name: 'v_dbl_1'/'v_dbl_1'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 4; max_length: 0; type: 5; decimals: 2
+  - 2: name: 'v_dec_1'/'v_dec_1'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 8; max_length: 0; type: 246; decimals: 3
+  - 3: name: 'v_int_1'/'v_int_1'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 11; max_length: 0; type: 3; decimals: 0
+  - 4: name: 'v_str_2'/'v_str_2'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 64; max_length: 0; type: 254; decimals: 0
+  - 5: name: 'v_dbl_2'/'v_dbl_2'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 5; max_length: 0; type: 5; decimals: 3
+  - 6: name: 'v_dec_2'/'v_dec_2'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 9; max_length: 0; type: 246; decimals: 4
+  - 7: name: 'v_int_2'/'v_int_2'; table: 'p1'/'p1'; db: 'client_test_db'; catalog: 'def'; length: 11; max_length: 0; type: 3; decimals: 0
+Data:
+  str: 'test_1'; dbl: 12.340000; dec: '567.891'; int: 2345; str: 'test_2'; dbl: 67.891000; dec: '234.6789'; int: 6789;
+EOF
+mysql_stmt_next_result(): 0; field_count: 0

=== modified file 'mysql-test/suite/falcon/r/falcon_bug_34164.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_34164.result	2008-03-06 17:31:28 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_34164.result	2008-09-12 08:52:36 +0000
@@ -29,6 +29,8 @@ a	b
 Warnings:
 Warning	1568	Falcon does not support SERIALIZABLE ISOLATION, using REPEATABLE READ instead.
 UPDATE t1 SET b = 11 WHERE a = 1;
+Warnings:
+Warning	1568	Falcon does not support SERIALIZABLE ISOLATION, using REPEATABLE READ instead.
 # Establish connection conn2 (user = root)
 USE test2;
 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
@@ -48,12 +50,16 @@ UPDATE t1 SET b = 111 WHERE a = 1;
 # Switch to conn1
 COMMIT;
 # Switch to conn2
+Warnings:
+Warning	1568	Falcon does not support SERIALIZABLE ISOLATION, using REPEATABLE READ instead.
 SELECT * FROM t1;
 a	b
 1	111
 2	2
 3	3
 4	4
+Warnings:
+Warning	1568	Falcon does not support SERIALIZABLE ISOLATION, using REPEATABLE READ instead.
 COMMIT;
 # Switch to conn1
 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
@@ -73,6 +79,8 @@ a	b
 Warnings:
 Warning	1568	Falcon does not support READ UNCOMMITTED ISOLATION, using REPEATABLE READ instead.
 UPDATE t1 SET b = 22 WHERE a = 2;
+Warnings:
+Warning	1568	Falcon does not support READ UNCOMMITTED ISOLATION, using REPEATABLE READ instead.
 # Switch to conn2
 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
 SHOW VARIABLES LIKE 'tx_isolation';
@@ -91,12 +99,16 @@ UPDATE t1 SET b = 222 WHERE a = 2;
 # Switch to conn1
 COMMIT;
 # Switch to conn2
+Warnings:
+Warning	1568	Falcon does not support READ UNCOMMITTED ISOLATION, using REPEATABLE READ instead.
 SELECT * FROM t1;
 a	b
 1	111
 2	222
 3	3
 4	4
+Warnings:
+Warning	1568	Falcon does not support READ UNCOMMITTED ISOLATION, using REPEATABLE READ instead.
 COMMIT;
 # Switch to default connection
 SET GLOBAL FALCON_CONSISTENT_READ=ON;
@@ -119,6 +131,8 @@ a	b
 Warnings:
 Warning	1568	Falcon does not support SERIALIZABLE ISOLATION, using REPEATABLE READ instead.
 UPDATE t1 SET b = 33 WHERE a = 3;
+Warnings:
+Warning	1568	Falcon does not support SERIALIZABLE ISOLATION, using REPEATABLE READ instead.
 # Establish connection conn4 (user = root)
 USE test2;
 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
@@ -145,6 +159,8 @@ a	b
 2	222
 3	3
 4	4
+Warnings:
+Warning	1568	Falcon does not support SERIALIZABLE ISOLATION, using REPEATABLE READ instead.
 COMMIT;
 # Switch to conn3
 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
@@ -164,6 +180,8 @@ a	b
 Warnings:
 Warning	1568	Falcon does not support READ UNCOMMITTED ISOLATION, using REPEATABLE READ instead.
 UPDATE t1 SET b = 44 WHERE a = 4;
+Warnings:
+Warning	1568	Falcon does not support READ UNCOMMITTED ISOLATION, using REPEATABLE READ instead.
 # Switch to conn4
 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
 SHOW VARIABLES LIKE 'tx_isolation';
@@ -189,6 +207,8 @@ a	b
 2	222
 3	33
 4	4
+Warnings:
+Warning	1568	Falcon does not support READ UNCOMMITTED ISOLATION, using REPEATABLE READ instead.
 COMMIT;
 SELECT * FROM t1;
 a	b

=== modified file 'mysql-test/t/events_bugs.test'
--- a/mysql-test/t/events_bugs.test	2008-02-07 10:47:39 +0000
+++ b/mysql-test/t/events_bugs.test	2008-09-12 19:34:30 +0000
@@ -120,6 +120,14 @@ select event_schema, event_name, sql_mod
 --echo "Let's check whether we change the sql_mode on ALTER EVENT"
 set sql_mode='traditional';
 alter event e_16407 do select 1;
+
+# wait for it to stop or we will get very spurious test failures
+let $wait_condition=
+    select count(*) = 0
+    from information_schema.processlist
+    where db = 'events_test' and info not like '%processlist%';
+--source include/wait_condition.inc
+
 select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
 drop event e_16407;
 
@@ -970,5 +978,7 @@ let $wait_condition=
 --source include/wait_condition.inc
 
 DROP DATABASE events_test;
+--echo # restore the defeault
+SET GLOBAL event_scheduler = 'on';
 
 # THIS MUST BE THE LAST LINE in this file.

=== modified file 'mysql-test/t/ps.test'
--- a/mysql-test/t/ps.test	2008-05-21 10:17:29 +0000
+++ b/mysql-test/t/ps.test	2008-08-07 17:52:43 +0000
@@ -2998,5 +2998,209 @@ execute stmt;
 drop table t1;
 deallocate prepare stmt;
 
+###########################################################################
 
+--echo 
 --echo End of 5.1 tests.
+
+###########################################################################
+
+--echo
+--echo #
+--echo # WL#4435: Support OUT-parameters in prepared statements.
+--echo #
+--echo
+
+# The idea of this test case is to check that
+#   - OUT-parameters of four allowed types (string, double, int, decimal) work
+#     properly;
+#   - INOUT and OUT parameters work properly;
+#   - A mix of IN and OUT parameters work properly;
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS p_string;
+DROP PROCEDURE IF EXISTS p_double;
+DROP PROCEDURE IF EXISTS p_int;
+DROP PROCEDURE IF EXISTS p_decimal;
+--enable_warnings
+
+delimiter |;
+
+--echo
+CREATE PROCEDURE p_string(
+  IN v0 INT,
+  OUT v1 CHAR(32),
+  IN v2 CHAR(32),
+  INOUT v3 CHAR(32))
+BEGIN
+  SET v0 = -1;
+  SET v1 = 'test_v1';
+  SET v2 = 'n/a';
+  SET v3 = 'test_v3';
+END|
+
+--echo
+CREATE PROCEDURE p_double(
+  IN v0 INT,
+  OUT v1 DOUBLE(4, 2),
+  IN v2 DOUBLE(4, 2),
+  INOUT v3 DOUBLE(4, 2))
+BEGIN
+  SET v0 = -1;
+  SET v1 = 12.34;
+  SET v2 = 98.67;
+  SET v3 = 56.78;
+END|
+
+--echo
+CREATE PROCEDURE p_int(
+  IN v0 CHAR(10),
+  OUT v1 INT,
+  IN v2 INT,
+  INOUT v3 INT)
+BEGIN
+  SET v0 = 'n/a';
+  SET v1 = 1234;
+  SET v2 = 9876;
+  SET v3 = 5678;
+END|
+
+--echo
+CREATE PROCEDURE p_decimal(
+  IN v0 INT,
+  OUT v1 DECIMAL(4, 2),
+  IN v2 DECIMAL(4, 2),
+  INOUT v3 DECIMAL(4, 2))
+BEGIN
+  SET v0 = -1;
+  SET v1 = 12.34;
+  SET v2 = 98.67;
+  SET v3 = 56.78;
+END|
+
+delimiter ;|
+
+--echo
+PREPARE stmt_str FROM 'CALL p_string(?, ?, ?, ?)';
+PREPARE stmt_dbl FROM 'CALL p_double(?, ?, ?, ?)';
+PREPARE stmt_int FROM 'CALL p_int(?, ?, ?, ?)';
+PREPARE stmt_dec FROM 'CALL p_decimal(?, ?, ?, ?)';
+
+--echo
+SET @x_str_1 = NULL;
+SET @x_str_2 = NULL;
+SET @x_str_3 = NULL;
+SET @x_dbl_1 = NULL;
+SET @x_dbl_2 = NULL;
+SET @x_dbl_3 = NULL;
+SET @x_int_1 = NULL;
+SET @x_int_2 = NULL;
+SET @x_int_3 = NULL;
+SET @x_dec_1 = NULL;
+SET @x_dec_2 = NULL;
+SET @x_dec_3 = NULL;
+
+--echo
+--echo -- Testing strings...
+
+--echo
+EXECUTE stmt_str USING @x_int_1, @x_str_1, @x_str_2, @x_str_3;
+SELECT @x_int_1, @x_str_1, @x_str_2, @x_str_3;
+
+--echo
+EXECUTE stmt_str USING @x_int_1, @x_str_1, @x_str_2, @x_str_3;
+SELECT @x_int_1, @x_str_1, @x_str_2, @x_str_3;
+
+--echo
+--echo -- Testing doubles...
+
+--echo
+EXECUTE stmt_dbl USING @x_int_1, @x_dbl_1, @x_dbl_2, @x_dbl_3;
+SELECT @x_int_1, @x_dbl_1, @x_dbl_2, @x_dbl_3;
+
+--echo
+EXECUTE stmt_dbl USING @x_int_1, @x_dbl_1, @x_dbl_2, @x_dbl_3;
+SELECT @x_int_1, @x_dbl_1, @x_dbl_2, @x_dbl_3;
+
+--echo
+--echo -- Testing ints...
+
+--echo
+EXECUTE stmt_int USING @x_str_1, @x_int_1, @x_int_2, @x_int_3;
+SELECT @x_str_1, @x_int_1, @x_int_2, @x_int_3;
+
+--echo
+EXECUTE stmt_int USING @x_str_1, @x_int_1, @x_int_2, @x_int_3;
+SELECT @x_str_1, @x_int_1, @x_int_2, @x_int_3;
+
+--echo
+--echo -- Testing decs...
+
+--echo
+EXECUTE stmt_dec USING @x_int_1, @x_dec_1, @x_dec_2, @x_dec_3;
+SELECT @x_int_1, @x_dec_1, @x_dec_2, @x_dec_3;
+
+--echo
+EXECUTE stmt_dec USING @x_int_1, @x_dec_1, @x_dec_2, @x_dec_3;
+SELECT @x_int_1, @x_dec_1, @x_dec_2, @x_dec_3;
+
+--echo
+DEALLOCATE PREPARE stmt_str;
+DEALLOCATE PREPARE stmt_dbl;
+DEALLOCATE PREPARE stmt_int;
+DEALLOCATE PREPARE stmt_dec;
+
+--echo
+DROP PROCEDURE p_string;
+DROP PROCEDURE p_double;
+DROP PROCEDURE p_int;
+DROP PROCEDURE p_decimal;
+
+#
+# Another test case for WL#4435: check out parameters in Dynamic SQL.
+#
+
+--echo
+--disable_warnings
+DROP PROCEDURE IF EXISTS p1;
+DROP PROCEDURE IF EXISTS p2;
+--enable_warnings
+
+--echo
+
+CREATE PROCEDURE p1(OUT v1 CHAR(10))
+  SET v1 = 'test1';
+
+--echo
+
+delimiter |;
+CREATE PROCEDURE p2(OUT v2 CHAR(10))
+BEGIN
+  SET @query = 'CALL p1(?)';
+  PREPARE stmt1 FROM @query;
+  EXECUTE stmt1 USING @u1;
+  DEALLOCATE PREPARE stmt1;
+
+  SET v2 = @u1;
+END|
+delimiter ;|
+
+--echo
+
+CALL p2(@a);
+SELECT @a;
+
+--echo
+
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+
+--echo
+--echo # End of WL#4435.
+
+###########################################################################
+
+--echo
+--echo End of 6.0 tests.
+
+###########################################################################

=== modified file 'sql/CMakeLists.txt'
--- a/sql/CMakeLists.txt	2008-07-09 07:12:43 +0000
+++ b/sql/CMakeLists.txt	2008-08-08 01:33:43 +0000
@@ -75,7 +75,7 @@ ADD_EXECUTABLE(mysqld
                sql_tablespace.cc events.cc ../sql-common/my_user.c 
                partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc
                rpl_rli.cc rpl_mi.cc sql_servers.cc sql_audit.cc
-               sql_connect.cc scheduler.cc 
+               sql_connect.cc scheduler.cc transaction.cc
                ddl_blocker.cc si_objects.cc
                sql_profile.cc event_parse_data.cc mdl.cc
                ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc

=== modified file 'sql/Makefile.am'
--- a/sql/Makefile.am	2008-07-09 07:12:43 +0000
+++ b/sql/Makefile.am	2008-08-11 12:40:09 +0000
@@ -87,9 +87,9 @@ noinst_HEADERS =	item.h item_func.h item
 			sql_plugin.h authors.h event_parse_data.h \
 			event_data_objects.h event_scheduler.h \
 			sql_partition.h partition_info.h partition_element.h \
-			probes.h sql_audit.h \
+			probes.h sql_audit.h transaction.h \
 			contributors.h sql_servers.h ddl_blocker.h \
-			si_objects.h sql_plist.h mdl.h
+			si_objects.h sql_plist.h mdl.h records.h
 
 mysqld_SOURCES =	sql_lex.cc sql_handler.cc sql_partition.cc \
 			item.cc item_sum.cc item_buff.cc item_func.cc \
@@ -136,7 +136,7 @@ mysqld_SOURCES =	sql_lex.cc sql_handler.
 			sql_builtin.cc sql_tablespace.cc partition_info.cc \
 			sql_servers.cc sql_audit.cc sha2.cc \
 			ddl_blocker.cc si_objects.cc event_parse_data.cc \
-			mdl.cc
+			mdl.cc transaction.cc
 
 if HAVE_DTRACE
   mysqld_SOURCES += probes.d

=== modified file 'sql/backup/backup_test.cc'
--- a/sql/backup/backup_test.cc	2008-08-20 13:23:10 +0000
+++ b/sql/backup/backup_test.cc	2008-09-05 14:16:07 +0000
@@ -42,7 +42,7 @@ int execute_backup_test_command(THD *thd
   field_list.push_back(new Item_empty_string("name", 5));
   field_list.push_back(new Item_empty_string("type", 4));
   field_list.push_back(new Item_empty_string("serialization", 13));
-  protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
+  protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
 
   //obs::ObjIterator *it= obs::get_databases(thd);
   List_iterator<LEX_STRING> it(*db_list);

=== modified file 'sql/backup/be_snapshot.cc'
--- a/sql/backup/be_snapshot.cc	2008-07-07 12:51:56 +0000
+++ b/sql/backup/be_snapshot.cc	2008-08-08 19:58:37 +0000
@@ -44,6 +44,7 @@
 #include "backup_engine.h"
 #include "be_snapshot.h"
 #include "backup_aux.h"
+#include "transaction.h"
 
 namespace snapshot_backup {
 
@@ -72,8 +73,8 @@ result_t Backup::cleanup()
     locking_thd->lock_state= LOCK_DONE; // set lock done so destructor won't wait
     if (m_trans_start)
     {
-      ha_autocommit_or_rollback(locking_thd->m_thd, 0);
-      end_active_trans(locking_thd->m_thd);
+      trans_commit_stmt(locking_thd->m_thd);
+      trans_commit_implicit(locking_thd->m_thd);
       m_trans_start= FALSE;
     }
     if (tables_open)
@@ -102,9 +103,10 @@ result_t Backup::lock()
     state. 
   */
   locking_thd->m_thd->lex->sql_command= SQLCOM_SELECT; 
-  locking_thd->m_thd->lex->start_transaction_opt|=
+  locking_thd->m_thd->lex->start_transaction_opt=
     MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT;
-  int res= begin_trans(locking_thd->m_thd);
+  int res= trans_begin(locking_thd->m_thd,
+                       locking_thd->m_thd->lex->start_transaction_opt);
   if (res)
     DBUG_RETURN(ERROR);
   m_trans_start= TRUE;

=== modified file 'sql/backup/kernel.cc'
--- a/sql/backup/kernel.cc	2008-09-11 16:28:29 +0000
+++ b/sql/backup/kernel.cc	2008-09-16 17:58:49 +0000
@@ -84,6 +84,7 @@
 #include "be_nodata.h"
 #include "ddl_blocker.h"
 #include "backup_progress.h"
+#include "transaction.h"
 
 
 /** 
@@ -299,9 +300,7 @@ int send_reply(Backup_restore_ctx &conte
   // FIXME: detect errors if  reported.
   // FIXME: error logging.
   field_list.push_back(new Item_empty_string(STRING_WITH_LEN("backup_id")));
-  // FIXME: detect errors if  reported.
-  // FIXME: error logging.
-  protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
+  protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
 
   /*
     Send field data.
@@ -804,8 +803,8 @@ int Backup_restore_ctx::close()
   */
   if (m_thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
   {
-    ha_autocommit_or_rollback(m_thd, 0);
-    end_active_trans(m_thd);
+    trans_commit_stmt(m_thd);
+    trans_commit_implicit(m_thd);
   }
 
   // unlock tables if they are still locked

=== modified file 'sql/events.cc'
--- a/sql/events.cc	2008-07-26 16:38:20 +0000
+++ b/sql/events.cc	2008-08-07 17:52:43 +0000
@@ -682,7 +682,7 @@ send_show_create_event(THD *thd, Event_t
   field_list.push_back(
     new Item_empty_string("Database Collation", MY_CS_NAME_SIZE));
 
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 

=== modified file 'sql/field.cc'
--- a/sql/field.cc	2008-07-25 17:21:55 +0000
+++ b/sql/field.cc	2008-08-10 14:49:52 +0000
@@ -1775,7 +1775,7 @@ bool Field::optimize_range(uint idx, uin
 }
 
 
-Field *Field::new_field(MEM_ROOT *root, struct st_table *new_table,
+Field *Field::new_field(MEM_ROOT *root, TABLE *new_table,
                         bool keep_type __attribute__((unused)))
 {
   Field *tmp;
@@ -1796,7 +1796,7 @@ Field *Field::new_field(MEM_ROOT *root, 
 }
 
 
-Field *Field::new_key_field(MEM_ROOT *root, struct st_table *new_table,
+Field *Field::new_key_field(MEM_ROOT *root, TABLE *new_table,
                             uchar *new_ptr, uchar *new_null_ptr,
                             uint new_null_bit)
 {
@@ -1813,7 +1813,7 @@ Field *Field::new_key_field(MEM_ROOT *ro
 
 /* This is used to generate a field in TABLE from TABLE_SHARE */
 
-Field *Field::clone(MEM_ROOT *root, struct st_table *new_table)
+Field *Field::clone(MEM_ROOT *root, TABLE *new_table)
 {
   Field *tmp;
   if ((tmp= (Field*) memdup_root(root,(char*) this,size_of())))
@@ -6778,7 +6778,7 @@ uint Field_string::get_key_image(uchar *
 }
 
 
-Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table,
+Field *Field_string::new_field(MEM_ROOT *root, TABLE *new_table,
                                bool keep_type)
 {
   Field *field;
@@ -7334,7 +7334,7 @@ int Field_varstring::cmp_binary(const uc
 }
 
 
-Field *Field_varstring::new_field(MEM_ROOT *root, struct st_table *new_table,
+Field *Field_varstring::new_field(MEM_ROOT *root, TABLE *new_table,
                                   bool keep_type)
 {
   Field_varstring *res= (Field_varstring*) Field::new_field(root, new_table,
@@ -7346,7 +7346,7 @@ Field *Field_varstring::new_field(MEM_RO
 
 
 Field *Field_varstring::new_key_field(MEM_ROOT *root,
-                                      struct st_table *new_table,
+                                      TABLE *new_table,
                                       uchar *new_ptr, uchar *new_null_ptr,
                                       uint new_null_bit)
 {
@@ -8468,7 +8468,7 @@ void Field_enum::sql_type(String &res) c
 }
 
 
-Field *Field_enum::new_field(MEM_ROOT *root, struct st_table *new_table,
+Field *Field_enum::new_field(MEM_ROOT *root, TABLE *new_table,
                              bool keep_type)
 {
   Field_enum *res= (Field_enum*) Field::new_field(root, new_table, keep_type);
@@ -8751,7 +8751,7 @@ Field_bit::do_last_null_byte() const
 
 
 Field *Field_bit::new_key_field(MEM_ROOT *root,
-                                struct st_table *new_table,
+                                TABLE *new_table,
                                 uchar *new_ptr, uchar *new_null_ptr,
                                 uint new_null_bit)
 {

=== modified file 'sql/field.h'
--- a/sql/field.h	2008-08-28 11:17:29 +0000
+++ b/sql/field.h	2008-09-04 18:30:34 +0000
@@ -59,8 +59,8 @@ public:
     Note that you can use table->in_use as replacement for current_thd member 
     only inside of val_*() and store() members (e.g. you can't use it in cons)
   */
-  struct st_table *table;		// Pointer for table
-  struct st_table *orig_table;		// Pointer to original table
+  TABLE *table;                                 // Pointer for table
+  TABLE *orig_table;                            // Pointer to original table
   const char	**table_name, *field_name;
   LEX_STRING	comment;
   /* Bitmap of indexes that start with this field */
@@ -321,12 +321,12 @@ public:
   */
   virtual bool can_be_compared_as_longlong() const { return FALSE; }
   virtual void free() {}
-  virtual Field *new_field(MEM_ROOT *root, struct st_table *new_table,
+  virtual Field *new_field(MEM_ROOT *root, TABLE *new_table,
                            bool keep_type);
-  virtual Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
+  virtual Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
                                uchar *new_ptr, uchar *new_null_ptr,
                                uint new_null_bit);
-  Field *clone(MEM_ROOT *mem_root, struct st_table *new_table);
+  Field *clone(MEM_ROOT *mem_root, TABLE *new_table);
   inline void move_field(uchar *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg)
   {
     ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg;
@@ -1547,7 +1547,7 @@ public:
   enum_field_types real_type() const { return MYSQL_TYPE_STRING; }
   bool has_charset(void) const
   { return charset() == &my_charset_bin ? FALSE : TRUE; }
-  Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type);
+  Field *new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
   virtual uint get_key_image(uchar *buff,uint length, imagetype type);
 private:
   int do_save_field_metadata(uchar *first_byte);
@@ -1635,8 +1635,8 @@ public:
   enum_field_types real_type() const { return MYSQL_TYPE_VARCHAR; }
   bool has_charset(void) const
   { return charset() == &my_charset_bin ? FALSE : TRUE; }
-  Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type);
-  Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
+  Field *new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
+  Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
                        uchar *new_ptr, uchar *new_null_ptr,
                        uint new_null_bit);
   uint is_equal(Create_field *new_field);
@@ -1867,7 +1867,7 @@ public:
   {
       flags|=ENUM_FLAG;
   }
-  Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type);
+  Field *new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
   enum_field_types type() const { return MYSQL_TYPE_STRING; }
   enum Item_result cmp_type () const { return INT_RESULT; }
   enum Item_result cast_to_int_type () const { return INT_RESULT; }
@@ -2000,7 +2000,7 @@ public:
                               uint param_data, bool low_byte_first);
   virtual void set_default();
 
-  Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
+  Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
                        uchar *new_ptr, uchar *new_null_ptr,
                        uint new_null_bit);
   void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg)
@@ -2123,7 +2123,7 @@ public:
   A class for sending info to the client
 */
 
-class Send_field {
+class Send_field :public Sql_alloc {
  public:
   const char *db_name;
   const char *table_name,*org_table_name;

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	2008-09-03 14:40:19 +0000
+++ b/sql/handler.cc	2008-09-04 18:30:34 +0000
@@ -27,6 +27,7 @@
 #include "rpl_filter.h"
 #include <myisampack.h>
 #include "myisam.h"
+#include "transaction.h"
 
 #ifdef WITH_PARTITION_STORAGE_ENGINE
 #include "ha_partition.h"
@@ -816,16 +817,16 @@ void ha_close_connection(THD* thd)
   a transaction in a given engine is read-write and will not
   involve the two-phase commit protocol!
 
-  At the end of a statement, server call
-  ha_autocommit_or_rollback() is invoked. This call in turn
-  invokes handlerton::prepare() for every involved engine.
-  Prepare is followed by a call to handlerton::commit_one_phase()
-  If a one-phase commit will suffice, handlerton::prepare() is not
-  invoked and the server only calls handlerton::commit_one_phase().
-  At statement commit, the statement-related read-write engine
-  flag is propagated to the corresponding flag in the normal
-  transaction.  When the commit is complete, the list of registered
-  engines is cleared.
+  At the end of a statement, server call trans_commit_stmt is
+  invoked. This call in turn invokes handlerton::prepare()
+  for every involved engine. Prepare is followed by a call
+  to handlerton::commit_one_phase() If a one-phase commit
+  will suffice, handlerton::prepare() is not invoked and
+  the server only calls handlerton::commit_one_phase().
+  At statement commit, the statement-related read-write
+  engine flag is propagated to the corresponding flag in the
+  normal transaction.  When the commit is complete, the list
+  of registered engines is cleared.
 
   Rollback is handled in a similar fashion.
 
@@ -836,7 +837,7 @@ void ha_close_connection(THD* thd)
   do not "register" in thd->transaction lists, and thus do not
   modify the transaction state. Besides, each DDL in
   MySQL is prefixed with an implicit normal transaction commit
-  (a call to end_active_trans()), and thus leaves nothing
+  (a call to trans_commit_implicit()), and thus leaves nothing
   to modify.
   However, as it has been pointed out with CREATE TABLE .. SELECT,
   some DDL statements can start a *new* transaction.
@@ -1277,42 +1278,6 @@ int ha_rollback_trans(THD *thd, bool all
   DBUG_RETURN(error);
 }
 
-/**
-  This is used to commit or rollback a single statement depending on
-  the value of error.
-
-  @note
-    Note that if the autocommit is on, then the following call inside
-    InnoDB will commit or rollback the whole transaction (= the statement). The
-    autocommit mechanism built into InnoDB is based on counting locks, but if
-    the user has used LOCK TABLES then that mechanism does not know to do the
-    commit.
-*/
-int ha_autocommit_or_rollback(THD *thd, int error)
-{
-  DBUG_ENTER("ha_autocommit_or_rollback");
-
-  if (thd->transaction.stmt.ha_list)
-  {
-    if (!error)
-    {
-      if (ha_commit_trans(thd, 0))
-	error=1;
-    }
-    else 
-    {
-      (void) ha_rollback_trans(thd, 0);
-      if (thd->transaction_rollback_request && !thd->in_sub_stmt)
-        (void) ha_rollback(thd);
-    }
-
-    thd->variables.tx_isolation=thd->session_tx_isolation;
-  }
-
-  DBUG_RETURN(error);
-}
-
-
 struct xahton_st {
   XID *xid;
   int result;
@@ -1584,7 +1549,7 @@ bool mysql_xa_recover(THD *thd)
   field_list.push_back(new Item_int("bqual_length", 0, MY_INT32_NUM_DECIMAL_DIGITS));
   field_list.push_back(new Item_empty_string("data",XIDDATASIZE));
 
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(1);
 
@@ -3317,7 +3282,7 @@ int ha_enable_transaction(THD *thd, bool
       So, let's commit an open transaction (if any) now.
     */
     if (!(error= ha_commit_trans(thd, 0)))
-      error= end_trans(thd, COMMIT);
+      error= trans_commit_implicit(thd);
   }
   DBUG_RETURN(error);
 }
@@ -5053,7 +5018,7 @@ bool ha_show_status(THD *thd, handlerton
   field_list.push_back(new Item_empty_string("Name",FN_REFLEN));
   field_list.push_back(new Item_empty_string("Status",10));
 
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     return TRUE;
 

=== modified file 'sql/handler.h'
--- a/sql/handler.h	2008-09-11 18:36:05 +0000
+++ b/sql/handler.h	2008-09-16 17:58:49 +0000
@@ -572,7 +572,8 @@ class st_alter_tablespace : public Sql_a
 
 /* The handler for a table type.  Will be included in the TABLE structure */
 
-struct st_table;
+struct TABLE;
+struct TABLE_SHARE;
 
 /*
   Make sure that the order of schema_tables and enum_schema_tables are the same.
@@ -615,8 +616,6 @@ enum enum_schema_tables
   SCH_VIEWS
 };
 
-typedef struct st_table TABLE;
-typedef struct st_table_share TABLE_SHARE;
 struct st_foreign_key_info;
 typedef struct st_foreign_key_info FOREIGN_KEY_INFO;
 typedef bool (stat_print_fn)(THD *thd, const char *type, uint type_len,
@@ -691,6 +690,7 @@ struct handler_iterator {
   void *buffer;
 };
 
+class handler;
 /*
   handlerton is a singleton structure - one instance per storage engine -
   to provide access to storage engine functionality that works on the
@@ -1386,8 +1386,8 @@ class handler :public Sql_alloc
 public:
   typedef ulonglong Table_flags;
 protected:
-  struct st_table_share *table_share;   /* The table definition */
-  struct st_table *table;               /* The current open table */
+  TABLE_SHARE *table_share;   /* The table definition */
+  TABLE *table;               /* The current open table */
   Table_flags cached_table_flags;       /* Set on init() and open() */
 
   ha_rows estimation_rows_to_insert;
@@ -2457,10 +2457,6 @@ extern TYPELIB tx_isolation_typelib;
 extern TYPELIB myisam_stats_method_typelib;
 extern ulong total_ha, total_ha_2pc;
 
-       /* Wrapper functions */
-#define ha_commit(thd) (ha_commit_trans((thd), TRUE))
-#define ha_rollback(thd) (ha_rollback_trans((thd), TRUE))
-
 /* lookups */
 handlerton *ha_default_handlerton(THD *thd);
 plugin_ref ha_resolve_by_name(THD *thd, const LEX_STRING *name);
@@ -2537,13 +2533,12 @@ int ha_release_temporary_latches(THD *th
 int ha_start_consistent_snapshot(THD *thd);
 int ha_commit_or_rollback_by_xid(XID *xid, bool commit);
 int ha_commit_one_phase(THD *thd, bool all);
+int ha_commit_trans(THD *thd, bool all);
 int ha_rollback_trans(THD *thd, bool all);
 int ha_prepare(THD *thd);
 int ha_recover(HASH *commit_list);
 
 /* transactions: these functions never call handlerton functions directly */
-int ha_commit_trans(THD *thd, bool all);
-int ha_autocommit_or_rollback(THD *thd, int error);
 int ha_enable_transaction(THD *thd, bool on);
 
 /* savepoints */

=== modified file 'sql/item.cc'
--- a/sql/item.cc	2008-08-20 18:05:57 +0000
+++ b/sql/item.cc	2008-09-04 18:30:34 +0000
@@ -2515,7 +2515,8 @@ Item_param::Item_param(uint pos_in_query
   param_type(MYSQL_TYPE_VARCHAR),
   pos_in_query(pos_in_query_arg),
   set_param_func(default_set_param_func),
-  limit_clause_param(FALSE)
+  limit_clause_param(FALSE),
+  m_out_param_info(NULL)
 {
   name= (char*) "?";
   /* 
@@ -2596,6 +2597,17 @@ void Item_param::set_decimal(const char 
   DBUG_VOID_RETURN;
 }
 
+void Item_param::set_decimal(const my_decimal *dv)
+{
+  state= DECIMAL_VALUE;
+
+  my_decimal2decimal(dv, &decimal_value);
+
+  decimals= (uint8) decimal_value.frac;
+  unsigned_flag= !decimal_value.sign();
+  max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
+                                             decimals, unsigned_flag);
+}
 
 /**
   Set parameter value from MYSQL_TIME value.
@@ -3217,6 +3229,158 @@ Item_param::set_param_type_and_swap_valu
   str_value_ptr.swap(src->str_value_ptr);
 }
 
+
+/**
+  This operation is intended to store some item value in Item_param to be
+  used later.
+
+  @param thd    thread context
+  @param ctx    stored procedure runtime context
+  @param it     a pointer to an item in the tree
+
+  @return Error status
+    @retval TRUE on error
+    @retval FALSE on success
+*/
+
+bool
+Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
+{
+  Item *value= *it;
+
+  if (value->is_null())
+  {
+    set_null();
+    return FALSE;
+  }
+
+  null_value= FALSE;
+
+  switch (value->result_type()) {
+  case STRING_RESULT:
+  {
+    char str_buffer[STRING_BUFFER_USUAL_SIZE];
+    String sv_buffer(str_buffer, sizeof(str_buffer), &my_charset_bin);
+    String *sv= value->val_str(&sv_buffer);
+
+    if (!sv)
+      return TRUE;
+
+    set_str(sv->c_ptr_safe(), sv->length());
+    str_value_ptr.set(str_value.ptr(),
+                      str_value.length(),
+                      str_value.charset());
+    collation.set(str_value.charset(), DERIVATION_COERCIBLE);
+    decimals= 0;
+    param_type= MYSQL_TYPE_STRING;
+
+    break;
+  }
+
+  case REAL_RESULT:
+    set_double(value->val_real());
+      param_type= MYSQL_TYPE_DOUBLE;
+    break;
+
+  case INT_RESULT:
+    set_int(value->val_int(), value->max_length);
+    param_type= MYSQL_TYPE_LONG;
+    break;
+
+  case DECIMAL_RESULT:
+  {
+    my_decimal dv_buf;
+    my_decimal *dv= value->val_decimal(&dv_buf);
+
+    if (!dv)
+      return TRUE;
+
+    set_decimal(dv);
+    param_type= MYSQL_TYPE_NEWDECIMAL;
+
+    break;
+  }
+
+  default:
+    /* That can not happen. */
+
+    DBUG_ASSERT(TRUE);  // Abort in debug mode.
+
+    set_null();         // Set to NULL in release mode.
+    return FALSE;
+  }
+
+  item_result_type= value->result_type();
+  item_type= value->type();
+  return FALSE;
+}
+
+
+/**
+  Setter of Item_param::m_out_param_info.
+
+  m_out_param_info is used to store information about store routine
+  OUT-parameters, such as stored routine name, database, stored routine
+  variable name. It is supposed to be set in sp_head::execute() after
+  Item_param::set_value() is called.
+*/
+
+void
+Item_param::set_out_param_info(Send_field *info)
+{
+  m_out_param_info= info;
+}
+
+
+/**
+  Getter of Item_param::m_out_param_info.
+
+  m_out_param_info is used to store information about store routine
+  OUT-parameters, such as stored routine name, database, stored routine
+  variable name. It is supposed to be retrieved in
+  Protocol_binary::send_out_parameters() during creation of OUT-parameter
+  result set.
+*/
+
+const Send_field *
+Item_param::get_out_param_info() const
+{
+  return m_out_param_info;
+}
+
+
+/**
+  Fill meta-data information for the corresponding column in a result set.
+  If this is an OUT-parameter of a stored procedure, preserve meta-data of
+  stored-routine variable.
+
+  @param field container for meta-data to be filled
+*/
+
+void Item_param::make_field(Send_field *field)
+{
+  Item::make_field(field);
+
+  if (!m_out_param_info)
+    return;
+
+  /*
+    This is an OUT-parameter of stored procedure. We should use
+    OUT-parameter info to fill out the names.
+  */
+
+  field->db_name= m_out_param_info->db_name;
+  field->table_name= m_out_param_info->table_name;
+  field->org_table_name= m_out_param_info->org_table_name;
+  field->col_name= m_out_param_info->col_name;
+  field->org_col_name= m_out_param_info->org_col_name;
+  field->length= m_out_param_info->length;
+  field->charsetnr= m_out_param_info->charsetnr;
+  field->flags= m_out_param_info->flags;
+  field->decimals= m_out_param_info->decimals;
+  field->type= m_out_param_info->type;
+}
+
 /****************************************************************************
   Item_copy_string
 ****************************************************************************/
@@ -3250,7 +3414,7 @@ my_decimal *Item_copy_string::val_decima
 
 
 /*
-  Functions to convert item to field (for send_fields)
+  Functions to convert item to field (for send_result_set_metadata)
 */
 
 /* ARGSUSED */

=== modified file 'sql/item.h'
--- a/sql/item.h	2008-08-20 10:29:58 +0000
+++ b/sql/item.h	2008-09-04 18:30:34 +0000
@@ -443,6 +443,11 @@ public:
       TRUE if error has occured.
   */
   virtual bool set_value(THD *thd, sp_rcontext *ctx, Item **it)= 0;
+
+  virtual void set_out_param_info(Send_field *info) {}
+
+  virtual const Send_field *get_out_param_info() const
+  { return NULL; }
 };
 
 
@@ -1609,7 +1614,8 @@ public:
 
 /* Item represents one placeholder ('?') of prepared statement */
 
-class Item_param :public Item
+class Item_param :public Item,
+                  private Settable_routine_parameter
 {
   char cnvbuf[MAX_FIELD_WIDTH];
   String cnvstr;
@@ -1697,6 +1703,7 @@ public:
   void set_int(longlong i, uint32 max_length_arg);
   void set_double(double i);
   void set_decimal(const char *str, ulong length);
+  void set_decimal(const my_decimal *dv);
   bool set_str(const char *str, ulong length);
   bool set_longdata(const char *str, ulong length);
   void set_time(MYSQL_TIME *tm, timestamp_type type, uint32 max_length_arg);
@@ -1746,6 +1753,25 @@ public:
   /** Item is a argument to a limit clause. */
   bool limit_clause_param;
   void set_param_type_and_swap_value(Item_param *from);
+
+private:
+  virtual inline Settable_routine_parameter *
+    get_settable_routine_parameter()
+  {
+    return this;
+  }
+
+  virtual bool set_value(THD *thd, sp_rcontext *ctx, Item **it);
+
+  virtual void set_out_param_info(Send_field *info);
+
+public:
+  virtual const Send_field *get_out_param_info() const;
+
+  virtual void make_field(Send_field *field);
+
+private:
+  Send_field *m_out_param_info;
 };
 
 
@@ -2098,7 +2124,7 @@ public:
 
 /**
   Item_empty_string -- is a utility class to put an item into List<Item>
-  which is then used in protocol.send_fields() when sending SHOW output to
+  which is then used in protocol.send_result_set_metadata() when sending SHOW output to
   the client.
 */
 

=== modified file 'sql/lock.cc'
--- a/sql/lock.cc	2008-07-09 07:12:43 +0000
+++ b/sql/lock.cc	2008-08-08 01:33:43 +0000
@@ -74,6 +74,7 @@
 */
 
 #include "mysql_priv.h"
+#include "transaction.h"
 #include <hash.h>
 #include <assert.h>
 
@@ -1440,7 +1441,7 @@ int try_transactional_lock(THD *thd, TAB
 
  err:
   /* We need to explicitly commit if autocommit mode is active. */
-  (void) ha_autocommit_or_rollback(thd, 0);
+  trans_commit_stmt(thd);
   /* Close the tables. The locks (if taken) persist in the storage engines. */
   close_tables_for_reopen(thd, &table_list, FALSE);
   thd->in_lock_tables= FALSE;

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2008-08-28 09:59:54 +0000
+++ b/sql/log_event.cc	2008-09-04 18:30:34 +0000
@@ -31,6 +31,7 @@
 #include "rpl_filter.h"
 #include "rpl_utility.h"
 #include "rpl_record.h"
+#include "transaction.h"
 #include <my_dir.h>
 
 #endif /* MYSQL_CLIENT */
@@ -5093,7 +5094,7 @@ int Xid_log_event::do_apply_event(Relay_
   /* For a slave Xid_log_event is COMMIT */
   general_log_print(thd, COM_QUERY,
                     "COMMIT /* implicit, from Xid_log_event */");
-  return end_trans(thd, COMMIT);
+  return trans_commit(thd);
 }
 
 Log_event::enum_skip_reason
@@ -7417,7 +7418,7 @@ Rows_log_event::do_update_pos(Relay_log_
       are involved, commit the transaction and flush the pending event to the
       binlog.
     */
-    error= ha_autocommit_or_rollback(thd, 0);
+    error= trans_commit_stmt(thd);
 
     /*
       Now what if this is not a transactional engine? we still need to

=== modified file 'sql/log_event_old.cc'
--- a/sql/log_event_old.cc	2008-06-28 11:00:59 +0000
+++ b/sql/log_event_old.cc	2008-08-08 01:33:43 +0000
@@ -6,6 +6,7 @@
 #endif
 #include "log_event_old.h"
 #include "rpl_record_old.h"
+#include "transaction.h"
 
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
 
@@ -1827,7 +1828,7 @@ Old_rows_log_event::do_update_pos(Relay_
       are involved, commit the transaction and flush the pending event to the
       binlog.
     */
-    error= ha_autocommit_or_rollback(thd, 0);
+    error= trans_commit_stmt(thd);
 
     /*
       Now what if this is not a transactional engine? we still need to

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2008-09-11 16:28:29 +0000
+++ b/sql/mysql_priv.h	2008-09-16 17:58:49 +0000
@@ -688,8 +688,6 @@ enum enum_parsing_place
   IN_ON
 };
 
-struct st_table;
-
 class THD;
 
 enum enum_check_fields
@@ -890,15 +888,6 @@ bool parse_sql(THD *thd,
                Parser_state *parser_state,
                Object_creation_ctx *creation_ctx);
 
-enum enum_mysql_completiontype {
-  ROLLBACK_RELEASE=-2, ROLLBACK=1,  ROLLBACK_AND_CHAIN=7,
-  COMMIT_RELEASE=-1,   COMMIT=0,    COMMIT_AND_CHAIN=6
-};
-
-bool begin_trans(THD *thd);
-bool end_active_trans(THD *thd);
-int end_trans(THD *thd, enum enum_mysql_completiontype completion);
-
 Item *negate_expression(THD *thd, Item *expr);
 
 /* log.cc */
@@ -928,6 +917,7 @@ bool general_log_write(THD *thd, enum en
 #include "tztime.h"
 #ifdef MYSQL_SERVER
 #include "sql_servers.h"
+#include "records.h"
 #include "opt_range.h"
 
 #ifdef HAVE_QUERY_CACHE

=== modified file 'sql/procedure.h'
--- a/sql/procedure.h	2008-03-21 15:48:28 +0000
+++ b/sql/procedure.h	2008-08-07 17:52:43 +0000
@@ -23,7 +23,7 @@
 #define PROC_NO_SORT 1				/**< Bits in flags */
 #define PROC_GROUP   2				/**< proc must have group */
 
-/* Procedure items used by procedures to store values for send_fields */
+/* Procedure items used by procedures to store values for send_result_set_metadata */
 
 class Item_proc :public Item
 {

=== modified file 'sql/protocol.cc'
--- a/sql/protocol.cc	2008-08-11 19:37:53 +0000
+++ b/sql/protocol.cc	2008-09-04 18:30:34 +0000
@@ -68,7 +68,7 @@ bool Protocol_binary::net_store_data(con
   exactly one byte to store length. It allows not to use
   the "convert" member as a temporary buffer, conversion
   is done directly to the "packet" member.
-  The limit 251 is good enough to optimize send_fields()
+  The limit 251 is good enough to optimize send_result_set_metadata()
   because column, table, database names fit into this limit.
 */
 
@@ -246,7 +246,7 @@ static uchar eof_buff[1]= { (uchar) 254 
 
   @param thd		Thread handler
   @param no_flush	Set to 1 if there will be more data to the client,
-                    like in send_fields().
+                        like in send_result_set_metadata().
 */    
 
 void
@@ -562,16 +562,16 @@ bool Protocol::flush()
     1	Error  (Note that in this case the error is not sent to the
     client)
 */
-bool Protocol::send_fields(List<Item> *list, uint flags)
+bool Protocol::send_result_set_metadata(List<Item> *list, uint flags)
 {
   List_iterator_fast<Item> it(*list);
   Item *item;
-  uchar buff[80];
+  uchar buff[MAX_FIELD_WIDTH];
   String tmp((char*) buff,sizeof(buff),&my_charset_bin);
   Protocol_text prot(thd);
   String *local_packet= prot.storage_packet();
   CHARSET_INFO *thd_charset= thd->variables.character_set_results;
-  DBUG_ENTER("send_fields");
+  DBUG_ENTER("send_result_set_metadata");
 
   if (flags & SEND_NUM_ROWS)
   {				// Packet with number of elements
@@ -704,7 +704,7 @@ bool Protocol::send_fields(List<Item> *l
     */
     write_eof_packet(thd, &thd->net, thd->server_status, thd->total_warn_count);
   }
-  DBUG_RETURN(prepare_for_send(list));
+  DBUG_RETURN(prepare_for_send(list->elements));
 
 err:
   my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES),
@@ -723,6 +723,38 @@ bool Protocol::write()
 
 
 /**
+  Send one result set row.
+
+  @param row_items a collection of column values for that row
+
+  @return Error status.
+    @retval TRUE  Error.
+    @retval FALSE Success.
+*/
+
+bool Protocol::send_result_set_row(List<Item> *row_items)
+{
+  char buffer[MAX_FIELD_WIDTH];
+  String str_buffer(buffer, sizeof (buffer), &my_charset_bin);
+  List_iterator_fast<Item> it(*row_items);
+
+  DBUG_ENTER("Protocol::send_result_set_row");
+
+  for (Item *item= it++; item; item= it++)
+  {
+    if (item->send(this, &str_buffer) || thd->is_error())
+    {
+      this->free();				// Free used buffer
+      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
+      DBUG_RETURN(TRUE);
+    }
+  }
+
+  DBUG_RETURN(FALSE);
+}
+
+
+/**
   Send \\0 end terminated string.
 
   @param from	NullS or \\0 terminated string
@@ -1047,6 +1079,53 @@ bool Protocol_text::store_time(MYSQL_TIM
   return net_store_data((uchar*) buff, length);
 }
 
+/**
+  Assign OUT-parameters to user variables.
+
+  @param sp_params  List of PS/SP parameters (both input and output).
+
+  @return Error status.
+    @retval FALSE Success.
+    @retval TRUE  Error.
+*/
+
+bool Protocol_text::send_out_parameters(List<Item_param> *sp_params)
+{
+  DBUG_ASSERT(sp_params->elements ==
+              thd->lex->prepared_stmt_params.elements);
+
+  List_iterator_fast<Item_param> item_param_it(*sp_params);
+  List_iterator_fast<LEX_STRING> user_var_name_it(thd->lex->prepared_stmt_params);
+
+  while (true)
+  {
+    Item_param *item_param= item_param_it++;
+    LEX_STRING *user_var_name= user_var_name_it++;
+
+    if (!item_param || !user_var_name)
+      break;
+
+    if (!item_param->get_out_param_info())
+      continue; // It's an IN-parameter.
+
+    Item_func_set_user_var *suv=
+      new Item_func_set_user_var(*user_var_name, item_param);
+    /*
+      Item_func_set_user_var is not fixed after construction, call
+      fix_fields().
+    */
+    if (suv->fix_fields(thd, NULL))
+      return TRUE;
+
+    if (suv->check(FALSE))
+      return TRUE;
+
+    if (suv->update())
+      return TRUE;
+  }
+
+  return FALSE;
+}
 
 /****************************************************************************
   Functions to handle the binary protocol used with prepared statements
@@ -1067,14 +1146,13 @@ bool Protocol_text::store_time(MYSQL_TIM
    [..]..[[length]data]              data
 ****************************************************************************/
 
-bool Protocol_binary::prepare_for_send(List<Item> *item_list)
+bool Protocol_binary::prepare_for_send(uint num_columns)
 {
-  Protocol::prepare_for_send(item_list);
+  Protocol::prepare_for_send(num_columns);
   bit_fields= (field_count+9)/8;
-  if (packet->alloc(bit_fields+1))
-    return 1;
+  return packet->alloc(bit_fields+1);
+
   /* prepare_for_resend will be called after this one */
-  return 0;
 }
 
 
@@ -1262,3 +1340,80 @@ bool Protocol_binary::store_time(MYSQL_T
   buff[0]=(char) length;			// Length is stored first
   return packet->append(buff, length+1, PACKET_BUFFER_EXTRA_ALLOC);
 }
+
+/**
+  Send a result set with OUT-parameter values by means of PS-protocol.
+
+  @param sp_params  List of PS/SP parameters (both input and output).
+
+  @return Error status.
+    @retval FALSE Success.
+    @retval TRUE  Error.
+*/
+
+bool Protocol_binary::send_out_parameters(List<Item_param> *sp_params)
+{
+  if (!(thd->client_capabilities & CLIENT_PS_MULTI_RESULTS))
+  {
+    /* The client does not support OUT-parameters. */
+    return FALSE;
+  }
+
+  List<Item> out_param_lst;
+
+  {
+    List_iterator_fast<Item_param> item_param_it(*sp_params);
+
+    while (true)
+    {
+      Item_param *item_param= item_param_it++;
+
+      if (!item_param)
+        break;
+
+      if (!item_param->get_out_param_info())
+        continue; // It's an IN-parameter.
+
+      if (out_param_lst.push_back(item_param))
+        return TRUE;
+    }
+  }
+
+  if (!out_param_lst.elements)
+    return FALSE;
+
+  /*
+    We have to set SERVER_PS_OUT_PARAMS in THD::server_status, because it
+    is used in send_result_set_metadata().
+  */
+
+  thd->server_status|= SERVER_PS_OUT_PARAMS | SERVER_MORE_RESULTS_EXISTS;
+
+  /* Send meta-data. */
+  if (send_result_set_metadata(&out_param_lst, SEND_NUM_ROWS | SEND_EOF))
+    return TRUE;
+
+  /* Send data. */
+
+  prepare_for_resend();
+
+  if (send_result_set_row(&out_param_lst))
+    return TRUE;
+
+  if (write())
+    return TRUE;
+
+  /* Restore THD::server_status. */
+  thd->server_status&= ~SERVER_PS_OUT_PARAMS;
+
+  /*
+    Reset SERVER_MORE_RESULTS_EXISTS bit, because this is the last packet
+    for sure.
+  */
+  thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
+
+  /* Send EOF-packet. */
+  net_send_eof(thd, thd->server_status, 0);
+
+  return FALSE;
+}

=== modified file 'sql/protocol.h'
--- a/sql/protocol.h	2008-02-11 16:11:22 +0000
+++ b/sql/protocol.h	2008-08-07 17:52:43 +0000
@@ -20,6 +20,7 @@
 
 class i_string;
 class THD;
+class Item_param;
 typedef struct st_mysql_field MYSQL_FIELD;
 typedef struct st_mysql_rows MYSQL_ROWS;
 
@@ -53,7 +54,8 @@ public:
   void init(THD* thd_arg);
 
   enum { SEND_NUM_ROWS= 1, SEND_DEFAULTS= 2, SEND_EOF= 4 };
-  virtual bool send_fields(List<Item> *list, uint flags);
+  virtual bool send_result_set_metadata(List<Item> *list, uint flags);
+  bool send_result_set_row(List<Item> *row_items);
 
   bool store(I_List<i_string> *str_list);
   bool store(const char *from, CHARSET_INFO *cs);
@@ -71,9 +73,9 @@ public:
   inline bool store(String *str)
   { return store((char*) str->ptr(), str->length(), str->charset()); }
 
-  virtual bool prepare_for_send(List<Item> *item_list) 
+  virtual bool prepare_for_send(uint num_columns)
   {
-    field_count=item_list->elements;
+    field_count= num_columns;
     return 0;
   }
   virtual bool flush();
@@ -95,6 +97,8 @@ public:
   virtual bool store_date(MYSQL_TIME *time)=0;
   virtual bool store_time(MYSQL_TIME *time)=0;
   virtual bool store(Field *field)=0;
+
+  virtual bool send_out_parameters(List<Item_param> *sp_params)=0;
 #ifdef EMBEDDED_LIBRARY
   int begin_dataset();
   virtual void remove_last_row() {}
@@ -136,6 +140,8 @@ public:
   virtual bool store(float nr, uint32 decimals, String *buffer);
   virtual bool store(double from, uint32 decimals, String *buffer);
   virtual bool store(Field *field);
+
+  virtual bool send_out_parameters(List<Item_param> *sp_params);
 #ifdef EMBEDDED_LIBRARY
   void remove_last_row();
 #endif
@@ -150,7 +156,7 @@ private:
 public:
   Protocol_binary() {}
   Protocol_binary(THD *thd_arg) :Protocol(thd_arg) {}
-  virtual bool prepare_for_send(List<Item> *item_list);
+  virtual bool prepare_for_send(uint num_columns);
   virtual void prepare_for_resend();
 #ifdef EMBEDDED_LIBRARY
   virtual bool write();
@@ -171,6 +177,9 @@ public:
   virtual bool store(float nr, uint32 decimals, String *buffer);
   virtual bool store(double from, uint32 decimals, String *buffer);
   virtual bool store(Field *field);
+
+  virtual bool send_out_parameters(List<Item_param> *sp_params);
+
   virtual enum enum_protocol_type type() { return PROTOCOL_BINARY; };
 };
 

=== modified file 'sql/records.cc'
--- a/sql/records.cc	2008-07-17 19:55:18 +0000
+++ b/sql/records.cc	2008-08-11 12:40:09 +0000
@@ -13,6 +13,9 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
+#ifdef USE_PRAGMA_INTERFACE
+#pragma implementation /* gcc class implementation */
+#endif
 
 /**
   @file
@@ -21,8 +24,10 @@
   Functions for easy reading of records, possible through a cache
 */
 
+#include "records.h"
 #include "mysql_priv.h"
 
+
 static int rr_quick(READ_RECORD *info);
 int rr_sequential(READ_RECORD *info);
 static int rr_from_tempfile(READ_RECORD *info);

=== added file 'sql/records.h'
--- a/sql/records.h	1970-01-01 00:00:00 +0000
+++ b/sql/records.h	2008-09-12 09:09:27 +0000
@@ -0,0 +1,76 @@
+#ifndef SQL_RECORDS_H
+#define SQL_RECORDS_H 
+/* Copyright (C) 2008 Sun/MySQL
+
+   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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface                      /* gcc class implementation */
+#endif
+#include <my_global.h>                /* for uint typedefs */
+
+struct st_join_table;
+class handler;
+struct TABLE;
+class THD;
+class SQL_SELECT;
+
+/**
+  A context for reading through a single table using a chosen access method:
+  index read, scan, etc, use of cache, etc.
+
+  Use by:
+  READ_RECORD read_record;
+  init_read_record(&read_record, ...);
+  while (read_record.read_record())
+  {
+    ...
+  }
+  end_read_record();
+*/
+
+struct READ_RECORD
+{
+  typedef int (*Read_func)(READ_RECORD*);
+  typedef int (*Setup_func)(struct st_join_table*);
+
+  TABLE *table;                                 /* Head-form */
+  handler *file;
+  TABLE **forms;                                /* head and ref forms */
+  Read_func read_record;
+  THD *thd;
+  SQL_SELECT *select;
+  uint cache_records;
+  uint ref_length,struct_length,reclength,rec_cache_size,error_offset;
+  uint index;
+  uchar *ref_pos;				/* pointer to form->refpos */
+  uchar *record;
+  uchar *rec_buf;                /* to read field values  after filesort */
+  uchar	*cache,*cache_pos,*cache_end,*read_positions;
+  struct st_io_cache *io_cache;
+  bool print_error, ignore_not_found_rows;
+  struct st_join_table *do_insideout_scan;
+
+public:
+  READ_RECORD() {}
+};
+
+void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
+		      SQL_SELECT *select, int use_record_cache,
+                      bool print_errors, bool disable_rr_cache);
+void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
+                          bool print_error, uint idx);
+void end_read_record(READ_RECORD *info);
+
+#endif /* SQL_RECORDS_H */

=== modified file 'sql/repl_failsafe.cc'
--- a/sql/repl_failsafe.cc	2008-03-27 19:02:15 +0000
+++ b/sql/repl_failsafe.cc	2008-08-07 17:52:43 +0000
@@ -470,7 +470,7 @@ bool show_new_master(THD* thd)
     field_list.push_back(new Item_empty_string("Log_name", 20));
     field_list.push_back(new Item_return_int("Log_pos", 10,
 					     MYSQL_TYPE_LONGLONG));
-    if (protocol->send_fields(&field_list,
+    if (protocol->send_result_set_metadata(&field_list,
                               Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
       DBUG_RETURN(TRUE);
     protocol->prepare_for_resend();
@@ -664,7 +664,7 @@ bool show_slave_hosts(THD* thd)
   field_list.push_back(new Item_return_int("Master_id", 10,
 					   MYSQL_TYPE_LONG));
 
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 

=== modified file 'sql/rpl_injector.cc'
--- a/sql/rpl_injector.cc	2008-05-29 15:44:11 +0000
+++ b/sql/rpl_injector.cc	2008-08-08 01:33:43 +0000
@@ -15,6 +15,7 @@
 
 #include "mysql_priv.h" 
 #include "rpl_injector.h"
+#include "transaction.h"
 
 /*
   injector::transaction - member definitions
@@ -35,8 +36,7 @@ injector::transaction::transaction(MYSQL
   m_start_pos.m_file_name= my_strdup(log_info.log_file_name, MYF(0));
   m_start_pos.m_file_pos= log_info.pos;
 
-  m_thd->lex->start_transaction_opt= 0; /* for begin_trans() */
-  begin_trans(m_thd);
+  trans_begin(m_thd);
 
   thd->set_current_stmt_binlog_row_based();
 }
@@ -82,8 +82,8 @@ int injector::transaction::commit()
      is committed by committing the statement transaction
      explicitly.
    */
-   ha_autocommit_or_rollback(m_thd, 0);
-   end_trans(m_thd, COMMIT);
+   trans_commit_stmt(m_thd);
+   trans_commit(m_thd);
    DBUG_RETURN(0);
 }
 

=== modified file 'sql/rpl_injector.h'
--- a/sql/rpl_injector.h	2008-05-29 15:44:11 +0000
+++ b/sql/rpl_injector.h	2008-08-10 14:49:52 +0000
@@ -25,9 +25,8 @@
 /* Forward declarations */
 class handler;
 class MYSQL_BIN_LOG;
-struct st_table;
+struct TABLE;
 
-typedef st_table TABLE;
 
 /*
   Injector to inject rows into the MySQL server.

=== modified file 'sql/rpl_rli.cc'
--- a/sql/rpl_rli.cc	2008-06-28 11:00:59 +0000
+++ b/sql/rpl_rli.cc	2008-08-08 01:33:43 +0000
@@ -20,6 +20,7 @@
 #include <my_dir.h>    // For MY_STAT
 #include "sql_repl.h"  // For check_binlog_magic
 #include "rpl_utility.h"
+#include "transaction.h"
 
 static int count_relay_log_space(Relay_log_info* rli);
 
@@ -1162,8 +1163,8 @@ void Relay_log_info::cleanup_context(THD
   */
   if (error)
   {
-    ha_autocommit_or_rollback(thd, 1); // if a "statement transaction"
-    end_trans(thd, ROLLBACK); // if a "real transaction"
+    trans_rollback_stmt(thd); // if a "statement transaction"
+    trans_rollback(thd);      // if a "real transaction"
   }
   m_table_map.clear_tables();
   slave_close_thread_tables(thd);

=== modified file 'sql/rpl_tblmap.cc'
--- a/sql/rpl_tblmap.cc	2008-08-20 16:21:14 +0000
+++ b/sql/rpl_tblmap.cc	2008-09-04 18:30:34 +0000
@@ -53,7 +53,7 @@ table_mapping::~table_mapping()
   free_root(&m_mem_root, MYF(0));
 }
 
-TABLE* table_mapping::get_table(ulong table_id)
+TABLE *table_mapping::get_table(ulong table_id)
 {
   DBUG_ENTER("table_mapping::get_table(ulong)");
   DBUG_PRINT("enter", ("table_id: %lu", table_id));

=== modified file 'sql/rpl_tblmap.h'
--- a/sql/rpl_tblmap.h	2008-08-20 14:06:31 +0000
+++ b/sql/rpl_tblmap.h	2008-09-04 18:30:34 +0000
@@ -18,8 +18,7 @@
 
 /* Forward declarations */
 #ifndef MYSQL_CLIENT
-struct st_table;
-typedef st_table TABLE;
+struct TABLE;
 #else
 class Table_map_log_event;
 typedef Table_map_log_event TABLE;

=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc	2008-09-04 13:46:04 +0000
+++ b/sql/set_var.cc	2008-09-05 14:16:07 +0000
@@ -61,6 +61,7 @@
 #include <my_dir.h>
 
 #include "events.h"
+#include "transaction.h"
 
 /* WITH_NDBCLUSTER_STORAGE_ENGINE */
 #ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
@@ -3181,7 +3182,7 @@ static bool set_option_autocommit(THD *t
    */
   if (var->save_result.ulong_value != 0 &&
       (thd->options & OPTION_NOT_AUTOCOMMIT) &&
-      ha_commit(thd))
+      trans_commit(thd))
     return 1;
 
   if (var->save_result.ulong_value != 0)

=== modified file 'sql/slave.cc'
--- a/sql/slave.cc	2008-07-21 03:55:09 +0000
+++ b/sql/slave.cc	2008-08-08 01:39:23 +0000
@@ -34,6 +34,7 @@
 #include "sql_repl.h"
 #include "rpl_filter.h"
 #include "repl_failsafe.h"
+#include "transaction.h"
 #include <thr_alarm.h>
 #include <my_dir.h>
 #include <sql_common.h>
@@ -1240,7 +1241,7 @@ bool show_master_info(THD* thd, Master_i
   field_list.push_back(new Item_return_int("Last_SQL_Errno", 4, MYSQL_TYPE_LONG));
   field_list.push_back(new Item_empty_string("Last_SQL_Error", 20));
 
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 
@@ -1953,7 +1954,7 @@ static int exec_relay_log_event(THD* thd
           else
           {
             exec_res= 0;
-            end_trans(thd, ROLLBACK);
+            trans_rollback(thd);
             /* chance for concurrent connection to get more locks */
             safe_sleep(thd, min(rli->trans_retries, MAX_SLAVE_RETRY_PAUSE),
                        (CHECK_KILLED_FUNC)sql_slave_killed, (void*)rli);

=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	2008-08-20 10:29:58 +0000
+++ b/sql/sp_head.cc	2008-09-04 18:30:34 +0000
@@ -2010,6 +2010,16 @@ sp_head::execute_procedure(THD *thd, Lis
         err_status= TRUE;
         break;
       }
+
+      Send_field *out_param_info= new (thd->mem_root) Send_field();
+      nctx->get_item(i)->make_field(out_param_info);
+      out_param_info->db_name= m_db.str;
+      out_param_info->table_name= m_name.str;
+      out_param_info->org_table_name= m_name.str;
+      out_param_info->col_name= spvar->name.str;
+      out_param_info->org_col_name= spvar->name.str;
+
+      srp->set_out_param_info(out_param_info);
     }
   }
 
@@ -2418,7 +2428,7 @@ sp_head::show_create_routine(THD *thd, i
   fields.push_back(new Item_empty_string("Database Collation",
                                          MY_CS_NAME_SIZE));
 
-  if (protocol->send_fields(&fields,
+  if (protocol->send_result_set_metadata(&fields,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
   {
     DBUG_RETURN(TRUE);
@@ -2603,7 +2613,7 @@ sp_head::show_routine_code(THD *thd)
   // 1024 is for not to confuse old clients
   field_list.push_back(new Item_empty_string("Instruction",
                                              max(buffer.length(), 1024)));
-  if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
+  if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS |
                                          Protocol::SEND_EOF))
     DBUG_RETURN(1);
 

=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc	2008-08-07 03:05:33 +0000
+++ b/sql/sql_acl.cc	2008-08-12 16:46:23 +0000
@@ -4626,7 +4626,7 @@ bool mysql_show_grants(THD *thd,LEX_USER
   strxmov(buff,"Grants for ",lex_user->user.str,"@",
 	  lex_user->host.str,NullS);
   field_list.push_back(field);
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
   {
     pthread_mutex_unlock(&acl_cache->lock);

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2008-08-26 10:20:41 +0000
+++ b/sql/sql_base.cc	2008-09-04 18:30:34 +0000
@@ -21,6 +21,7 @@
 #include "sp_head.h"
 #include "sp.h"
 #include "sql_trigger.h"
+#include "transaction.h"
 #include <m_ctype.h>
 #include <my_dir.h>
 #include <hash.h>
@@ -1359,7 +1360,7 @@ void close_thread_tables(THD *thd,
   if (!(thd->state_flags & Open_tables_state::BACKUPS_AVAIL))
   {
     thd->main_da.can_overwrite_status= TRUE;
-    ha_autocommit_or_rollback(thd, thd->is_error());
+    thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
     thd->main_da.can_overwrite_status= FALSE;
 
     /*
@@ -2612,7 +2613,7 @@ bool open_table(THD *thd, TABLE_LIST *ta
           VIEW not really opened, only frm were read.
           Set 1 as a flag here
         */
-        table_list->view= (st_lex*)1;
+        table_list->view= (LEX*)1;
       }
       else
       {

=== modified file 'sql/sql_cache.h'
--- a/sql/sql_cache.h	2008-07-17 19:55:18 +0000
+++ b/sql/sql_cache.h	2008-08-10 14:49:52 +0000
@@ -65,7 +65,7 @@ struct Query_cache_query;
 struct Query_cache_result;
 class Query_cache;
 struct Query_cache_tls;
-struct st_lex;
+struct LEX;
 
 /**
   This class represents a node in the linked chain of queries
@@ -413,7 +413,7 @@ protected:
   */
   TABLE_COUNTER_TYPE is_cacheable(THD *thd, size_t query_len,
                                   const char *query,
-				  struct st_lex *lex, TABLE_LIST *tables_used,
+				  LEX *lex, TABLE_LIST *tables_used,
 				  uint8 *tables_type);
   TABLE_COUNTER_TYPE process_and_count_tables(THD *thd,
                                               TABLE_LIST *tables_used,

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2008-09-04 13:46:04 +0000
+++ b/sql/sql_class.cc	2008-09-05 14:16:07 +0000
@@ -42,6 +42,7 @@
 
 #include "sp_rcontext.h"
 #include "sp_cache.h"
+#include "transaction.h"
 
 /*
   The following is used to initialise Table_ident with a internal
@@ -848,7 +849,8 @@ void THD::cleanup(void)
   }
 #endif
   {
-    ha_rollback(this);
+    transaction.xid_state.xa_state= XA_NOTR;
+    trans_rollback(this);
     xid_cache_delete(&transaction.xid_state);
   }
   locked_tables_list.unlock_locked_tables(this);
@@ -1409,7 +1411,7 @@ int THD::send_explain_fields(select_resu
   }
   item->maybe_null= 1;
   field_list.push_back(new Item_empty_string("Extra", 255, cs));
-  return (result->send_fields(field_list,
+  return (result->send_result_set_metadata(field_list,
                               Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF));
 }
 
@@ -1555,10 +1557,10 @@ sql_exchange::sql_exchange(char *name, b
   cs= NULL;
 }
 
-bool select_send::send_fields(List<Item> &list, uint flags)
+bool select_send::send_result_set_metadata(List<Item> &list, uint flags)
 {
   bool res;
-  if (!(res= thd->protocol->send_fields(&list, flags)))
+  if (!(res= thd->protocol->send_result_set_metadata(&list, flags)))
     is_result_set_started= 1;
   return res;
 }
@@ -1601,10 +1603,13 @@ void select_send::cleanup()
 
 bool select_send::send_data(List<Item> &items)
 {
+  Protocol *protocol= thd->protocol;
+  DBUG_ENTER("select_send::send_data");
+
   if (unit->offset_limit_cnt)
   {						// using limit offset,count
     unit->offset_limit_cnt--;
-    return 0;
+    DBUG_RETURN(FALSE);
   }
 
   /*
@@ -1614,31 +1619,18 @@ bool select_send::send_data(List<Item> &
   */
   ha_release_temporary_latches(thd);
 
-  List_iterator_fast<Item> li(items);
-  Protocol *protocol= thd->protocol;
-  char buff[MAX_FIELD_WIDTH];
-  String buffer(buff, sizeof(buff), &my_charset_bin);
-  DBUG_ENTER("select_send::send_data");
-
   protocol->prepare_for_resend();
-  Item *item;
-  while ((item=li++))
-  {
-    if (item->send(protocol, &buffer) || thd->is_error())
-    {
-      protocol->free();				// Free used buffer
-      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
-      break;
-    }
-  }
-  if (thd->is_error())
+  if (protocol->send_result_set_row(&items))
   {
     protocol->remove_last_row();
-    DBUG_RETURN(1);
+    DBUG_RETURN(TRUE);
   }
+
   thd->sent_row_count++;
+
   if (thd->vio_ok())
     DBUG_RETURN(protocol->write());
+
   DBUG_RETURN(0);
 }
 

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2008-09-04 13:46:04 +0000
+++ b/sql/sql_class.h	2008-09-05 14:16:07 +0000
@@ -2458,7 +2458,7 @@ public:
   */
   virtual uint field_count(List<Item> &fields) const
   { return fields.elements; }
-  virtual bool send_fields(List<Item> &list, uint flags)=0;
+  virtual bool send_result_set_metadata(List<Item> &list, uint flags)=0;
   virtual bool send_data(List<Item> &items)=0;
   virtual bool initialize_tables (JOIN *join=0) { return 0; }
   virtual void send_error(uint errcode,const char *err);
@@ -2497,7 +2497,7 @@ class select_result_interceptor: public 
 public:
   select_result_interceptor() {}              /* Remove gcc warning */
   uint field_count(List<Item> &fields) const { return 0; }
-  bool send_fields(List<Item> &fields, uint flag) { return FALSE; }
+  bool send_result_set_metadata(List<Item> &fields, uint flag) { return FALSE; }
 };
 
 
@@ -2510,7 +2510,7 @@ class select_send :public select_result 
   bool is_result_set_started;
 public:
   select_send() :is_result_set_started(FALSE) {}
-  bool send_fields(List<Item> &list, uint flags);
+  bool send_result_set_metadata(List<Item> &list, uint flags);
   bool send_data(List<Item> &items);
   bool send_eof();
   virtual bool check_simple_select() const { return FALSE; }

=== modified file 'sql/sql_cursor.cc'
--- a/sql/sql_cursor.cc	2008-08-20 10:29:58 +0000
+++ b/sql/sql_cursor.cc	2008-09-04 18:30:34 +0000
@@ -88,7 +88,7 @@ class Materialized_cursor: public Server
 public:
   Materialized_cursor(select_result *result, TABLE *table);
 
-  int fill_item_list(THD *thd, List<Item> &send_fields);
+  int fill_item_list(THD *thd, List<Item> &send_result_set_metadata);
   virtual bool is_open() const { return table != 0; }
   virtual int open(JOIN *join __attribute__((unused)));
   virtual void fetch(ulong num_rows);
@@ -113,7 +113,7 @@ public:
   Materialized_cursor *materialized_cursor;
   Select_materialize(select_result *result_arg)
     :result(result_arg), materialized_cursor(0) {}
-  virtual bool send_fields(List<Item> &list, uint flags);
+  virtual bool send_result_set_metadata(List<Item> &list, uint flags);
 };
 
 
@@ -362,12 +362,12 @@ Sensitive_cursor::open(JOIN *join_arg)
   join->change_result(result);
   /*
     Send fields description to the client; server_status is sent
-    in 'EOF' packet, which follows send_fields().
-    We don't simply use SEND_EOF flag of send_fields because we also
+    in 'EOF' packet, which follows send_result_set_metadata().
+    We don't simply use SEND_EOF flag of send_result_set_metadata because we also
     want to flush the network buffer, which is done only in a standalone
     send_eof().
   */
-  result->send_fields(*join->fields, Protocol::SEND_NUM_ROWS);
+  result->send_result_set_metadata(*join->fields, Protocol::SEND_NUM_ROWS);
   thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
   result->send_eof();
   thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
@@ -551,14 +551,14 @@ Materialized_cursor::Materialized_cursor
   Preserve the original metadata that would be sent to the client.
 
   @param thd Thread identifier.
-  @param send_fields List of fields that would be sent.
+  @param send_result_set_metadata List of fields that would be sent.
 */
 
-int Materialized_cursor::fill_item_list(THD *thd, List<Item> &send_fields)
+int Materialized_cursor::fill_item_list(THD *thd, List<Item> &send_result_set_metadata)
 {
   Query_arena backup_arena;
   int rc;
-  List_iterator_fast<Item> it_org(send_fields);
+  List_iterator_fast<Item> it_org(send_result_set_metadata);
   List_iterator_fast<Item> it_dst(item_list);
   Item *item_org;
   Item *item_dst;
@@ -568,7 +568,7 @@ int Materialized_cursor::fill_item_list(
   if ((rc= table->fill_item_list(&item_list)))
     goto end;
 
-  DBUG_ASSERT(send_fields.elements == item_list.elements);
+  DBUG_ASSERT(send_result_set_metadata.elements == item_list.elements);
 
   /*
     Unless we preserve the original metadata, it will be lost,
@@ -607,17 +607,17 @@ int Materialized_cursor::open(JOIN *join
   {
     /*
       Now send the result set metadata to the client. We need to
-      do it here, as in Select_materialize::send_fields the items
-      for column types are not yet created (send_fields requires
+      do it here, as in Select_materialize::send_result_set_metadata the items
+      for column types are not yet created (send_result_set_metadata requires
       a list of items). The new types may differ from the original
       ones sent at prepare if some of them were altered by MySQL
       HEAP tables mechanism -- used when create_tmp_field_from_item
       may alter the original column type.
 
-      We can't simply supply SEND_EOF flag to send_fields, because
-      send_fields doesn't flush the network buffer.
+      We can't simply supply SEND_EOF flag to send_result_set_metadata, because
+      send_result_set_metadata doesn't flush the network buffer.
     */
-    rc= result->send_fields(item_list, Protocol::SEND_NUM_ROWS);
+    rc= result->send_result_set_metadata(item_list, Protocol::SEND_NUM_ROWS);
     thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
     result->send_eof();
     thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
@@ -700,7 +700,7 @@ Materialized_cursor::~Materialized_curso
  Select_materialize
 ****************************************************************************/
 
-bool Select_materialize::send_fields(List<Item> &list, uint flags)
+bool Select_materialize::send_result_set_metadata(List<Item> &list, uint flags)
 {
   DBUG_ASSERT(table == 0);
   if (create_result_table(unit->thd, unit->get_unit_column_types(),

=== modified file 'sql/sql_do.cc'
--- a/sql/sql_do.cc	2008-02-19 12:45:21 +0000
+++ b/sql/sql_do.cc	2008-08-08 01:33:43 +0000
@@ -17,6 +17,7 @@
 /* Execute DO statement */
 
 #include "mysql_priv.h"
+#include "transaction.h"
 
 bool mysql_do(THD *thd, List<Item> &values)
 {
@@ -36,7 +37,7 @@ bool mysql_do(THD *thd, List<Item> &valu
       will clear the error and the rollback in the end of
       dispatch_command() won't work.
     */
-    ha_autocommit_or_rollback(thd, thd->is_error());
+    trans_rollback_stmt(thd);
     thd->clear_error(); // DO always is OK
   }
   my_ok(thd);

=== modified file 'sql/sql_error.cc'
--- a/sql/sql_error.cc	2008-07-29 22:03:57 +0000
+++ b/sql/sql_error.cc	2008-08-12 16:46:23 +0000
@@ -216,7 +216,7 @@ bool mysqld_show_warnings(THD *thd, ulon
   field_list.push_back(new Item_return_int("Code",4, MYSQL_TYPE_LONG));
   field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE));
 
-  if (thd->protocol->send_fields(&field_list,
+  if (thd->protocol->send_result_set_metadata(&field_list,
                                  Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 

=== modified file 'sql/sql_handler.cc'
--- a/sql/sql_handler.cc	2008-06-20 13:11:20 +0000
+++ b/sql/sql_handler.cc	2008-08-07 17:52:43 +0000
@@ -539,7 +539,7 @@ retry:
                     tables->db, tables->alias, &it, 0))
     goto err;
 
-  protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
+  protocol->send_result_set_metadata(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
 
   /*
     In ::external_lock InnoDB resets the fields which tell it that
@@ -661,18 +661,11 @@ retry:
       continue;
     if (num_rows >= offset_limit_cnt)
     {
-      Item *item;
       protocol->prepare_for_resend();
-      it.rewind();
-      while ((item=it++))
-      {
-	if (item->send(thd->protocol, &buffer))
-	{
-	  protocol->free();                             // Free used
-	  my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
-	  goto err;
-	}
-      }
+
+      if (protocol->send_result_set_row(&list))
+        goto err;
+
       protocol->write();
     }
     num_rows++;

=== modified file 'sql/sql_help.cc'
--- a/sql/sql_help.cc	2008-07-17 18:26:55 +0000
+++ b/sql/sql_help.cc	2008-08-07 17:52:43 +0000
@@ -431,7 +431,7 @@ int send_answer_1(Protocol *protocol, St
   field_list.push_back(new Item_empty_string("description",1000));
   field_list.push_back(new Item_empty_string("example",1000));
 
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(1);
 
@@ -463,7 +463,7 @@ int send_answer_1(Protocol *protocol, St
    +-                    -+
 
   RETURN VALUES
-    result of protocol->send_fields
+    result of protocol->send_result_set_metadata
 */
 
 int send_header_2(Protocol *protocol, bool for_category)
@@ -474,7 +474,7 @@ int send_header_2(Protocol *protocol, bo
     field_list.push_back(new Item_empty_string("source_category_name",64));
   field_list.push_back(new Item_empty_string("name",64));
   field_list.push_back(new Item_empty_string("is_it_category",1));
-  DBUG_RETURN(protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
+  DBUG_RETURN(protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS |
                                                  Protocol::SEND_EOF));
 }
 

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2008-09-11 18:36:05 +0000
+++ b/sql/sql_insert.cc	2008-09-16 17:58:49 +0000
@@ -62,6 +62,7 @@
 #include "slave.h"
 #include "rpl_mi.h"
 #include "sql_audit.h"
+#include "transaction.h"
 
 #ifndef EMBEDDED_LIBRARY
 static bool delayed_get_table(THD *thd, TABLE_LIST *table_list);
@@ -2504,7 +2505,7 @@ pthread_handler_t handle_delayed_insert(
       */
       di->table->file->ha_release_auto_increment();
       mysql_unlock_tables(thd, lock);
-      ha_autocommit_or_rollback(thd, 0);
+      trans_commit_stmt(thd);
       di->group_count=0;
       mysql_audit_release(thd);
       pthread_mutex_lock(&di->mutex);
@@ -2525,7 +2526,7 @@ err:
     first call to ha_*_row() instead. Remove code that are used to
     cover for the case outlined above.
    */
-  ha_autocommit_or_rollback(thd, 1);
+  trans_rollback_stmt(thd);
 
 #ifndef __WIN__
 end:
@@ -3765,8 +3766,8 @@ bool select_create::send_eof()
     */
     if (!table->s->tmp_table)
     {
-      ha_autocommit_or_rollback(thd, 0);
-      end_active_trans(thd);
+      trans_commit_stmt(thd);
+      trans_commit_implicit(thd);
     }
 
     table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);

=== modified file 'sql/sql_lex.cc'
--- a/sql/sql_lex.cc	2008-07-15 16:29:51 +0000
+++ b/sql/sql_lex.cc	2008-08-10 14:49:52 +0000
@@ -2110,7 +2110,7 @@ void st_select_lex::print_limit(THD *thd
   to implement the clean up.
 */
 
-void st_lex::cleanup_lex_after_parse_error(THD *thd)
+void LEX::cleanup_lex_after_parse_error(THD *thd)
 {
   /*
     Delete sphead for the side effect of restoring of the original
@@ -2200,7 +2200,7 @@ void Query_tables_list::destroy_query_ta
   Initialize LEX object.
 
   SYNOPSIS
-    st_lex::st_lex()
+    LEX::LEX()
 
   NOTE
     LEX object initialized with this constructor can be used as part of
@@ -2210,7 +2210,7 @@ void Query_tables_list::destroy_query_ta
     for this.
 */
 
-st_lex::st_lex()
+LEX::LEX()
   :result(0),
    sql_command(SQLCOM_END), option_type(OPT_DEFAULT), is_lex_started(0)
 {
@@ -2227,7 +2227,7 @@ st_lex::st_lex()
   Check whether the merging algorithm can be used on this VIEW
 
   SYNOPSIS
-    st_lex::can_be_merged()
+    LEX::can_be_merged()
 
   DESCRIPTION
     We can apply merge algorithm if it is single SELECT view  with
@@ -2241,7 +2241,7 @@ st_lex::st_lex()
     TRUE  - merge algorithm can be used
 */
 
-bool st_lex::can_be_merged()
+bool LEX::can_be_merged()
 {
   // TODO: do not forget implement case when select_lex.table_list.elements==0
 
@@ -2278,19 +2278,19 @@ bool st_lex::can_be_merged()
   check if command can use VIEW with MERGE algorithm (for top VIEWs)
 
   SYNOPSIS
-    st_lex::can_use_merged()
+    LEX::can_use_merged()
 
   DESCRIPTION
     Only listed here commands can use merge algorithm in top level
     SELECT_LEX (for subqueries will be used merge algorithm if
-    st_lex::can_not_use_merged() is not TRUE).
+    LEX::can_not_use_merged() is not TRUE).
 
   RETURN
     FALSE - command can't use merged VIEWs
     TRUE  - VIEWs with MERGE algorithms can be used
 */
 
-bool st_lex::can_use_merged()
+bool LEX::can_use_merged()
 {
   switch (sql_command)
   {
@@ -2315,18 +2315,18 @@ bool st_lex::can_use_merged()
   Check if command can't use merged views in any part of command
 
   SYNOPSIS
-    st_lex::can_not_use_merged()
+    LEX::can_not_use_merged()
 
   DESCRIPTION
     Temporary table algorithm will be used on all SELECT levels for queries
-    listed here (see also st_lex::can_use_merged()).
+    listed here (see also LEX::can_use_merged()).
 
   RETURN
     FALSE - command can't use merged VIEWs
     TRUE  - VIEWs with MERGE algorithms can be used
 */
 
-bool st_lex::can_not_use_merged()
+bool LEX::can_not_use_merged()
 {
   switch (sql_command)
   {
@@ -2355,7 +2355,7 @@ bool st_lex::can_not_use_merged()
     FALSE no, we need data
 */
 
-bool st_lex::only_view_structure()
+bool LEX::only_view_structure()
 {
   switch (sql_command) {
   case SQLCOM_SHOW_CREATE:
@@ -2384,7 +2384,7 @@ bool st_lex::only_view_structure()
 */
 
 
-bool st_lex::need_correct_ident()
+bool LEX::need_correct_ident()
 {
   switch(sql_command)
   {
@@ -2414,7 +2414,7 @@ bool st_lex::need_correct_ident()
     VIEW_CHECK_CASCADED  CHECK OPTION CASCADED
 */
 
-uint8 st_lex::get_effective_with_check(TABLE_LIST *view)
+uint8 LEX::get_effective_with_check(TABLE_LIST *view)
 {
   if (view->select_lex->master_unit() == &unit &&
       which_check_option_applicable())
@@ -2443,7 +2443,7 @@ uint8 st_lex::get_effective_with_check(T
 */
 
 bool
-st_lex::copy_db_to(char **p_db, size_t *p_db_length) const
+LEX::copy_db_to(char **p_db, size_t *p_db_length) const
 {
   if (sphead)
   {
@@ -2515,7 +2515,7 @@ void st_select_lex_unit::set_limit(st_se
   clause.
 */
 
-void st_lex::set_trg_event_type_for_tables()
+void LEX::set_trg_event_type_for_tables()
 {
   uint8 new_trg_event_map= 0;
 
@@ -2658,7 +2658,7 @@ void st_lex::set_trg_event_type_for_tabl
       In this case link_to_local is set.
 
 */
-TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
+TABLE_LIST *LEX::unlink_first_table(bool *link_to_local)
 {
   TABLE_LIST *first;
   if ((first= query_tables))
@@ -2698,7 +2698,7 @@ TABLE_LIST *st_lex::unlink_first_table(b
   table list
 
   SYNOPSYS
-     st_lex::first_lists_tables_same()
+     LEX::first_lists_tables_same()
 
   NOTES
     In many cases (for example, usual INSERT/DELETE/...) the first table of
@@ -2709,7 +2709,7 @@ TABLE_LIST *st_lex::unlink_first_table(b
     the global list first.
 */
 
-void st_lex::first_lists_tables_same()
+void LEX::first_lists_tables_same()
 {
   TABLE_LIST *first_table= (TABLE_LIST*) select_lex.table_list.first;
   if (query_tables != first_table && first_table != 0)
@@ -2745,7 +2745,7 @@ void st_lex::first_lists_tables_same()
     global list
 */
 
-void st_lex::link_first_table_back(TABLE_LIST *first,
+void LEX::link_first_table_back(TABLE_LIST *first,
 				   bool link_to_local)
 {
   if (first)
@@ -2772,7 +2772,7 @@ void st_lex::link_first_table_back(TABLE
   cleanup lex for case when we open table by table for processing
 
   SYNOPSIS
-    st_lex::cleanup_after_one_table_open()
+    LEX::cleanup_after_one_table_open()
 
   NOTE
     This method is mostly responsible for cleaning up of selects lists and
@@ -2780,7 +2780,7 @@ void st_lex::link_first_table_back(TABLE
     to call Query_tables_list::reset_query_tables_list(FALSE).
 */
 
-void st_lex::cleanup_after_one_table_open()
+void LEX::cleanup_after_one_table_open()
 {
   /*
     thd->lex->derived_tables & additional units may be set if we open
@@ -2815,7 +2815,7 @@ void st_lex::cleanup_after_one_table_ope
       backup  Pointer to Query_tables_list instance to be used for backup
 */
 
-void st_lex::reset_n_backup_query_tables_list(Query_tables_list *backup)
+void LEX::reset_n_backup_query_tables_list(Query_tables_list *backup)
 {
   backup->set_query_tables_list(this);
   /*
@@ -2834,7 +2834,7 @@ void st_lex::reset_n_backup_query_tables
       backup  Pointer to Query_tables_list instance used for backup
 */
 
-void st_lex::restore_backup_query_tables_list(Query_tables_list *backup)
+void LEX::restore_backup_query_tables_list(Query_tables_list *backup)
 {
   this->destroy_query_tables_list();
   this->set_query_tables_list(backup);
@@ -2845,14 +2845,14 @@ void st_lex::restore_backup_query_tables
   Checks for usage of routines and/or tables in a parsed statement
 
   SYNOPSIS
-    st_lex:table_or_sp_used()
+    LEX:table_or_sp_used()
 
   RETURN
     FALSE  No routines and tables used
     TRUE   Either or both routines and tables are used.
 */
 
-bool st_lex::table_or_sp_used()
+bool LEX::table_or_sp_used()
 {
   DBUG_ENTER("table_or_sp_used");
 
@@ -3013,7 +3013,7 @@ bool st_select_lex::add_index_hint (THD 
   @retval  FALSE          No, not a management partition command
 */
 
-bool st_lex::is_partition_management() const
+bool LEX::is_partition_management() const
 {
   return (sql_command == SQLCOM_ALTER_TABLE &&
           (alter_info.flags == ALTER_ADD_PARTITION ||

=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h	2008-08-20 10:29:58 +0000
+++ b/sql/sql_lex.h	2008-09-04 18:30:34 +0000
@@ -390,7 +390,7 @@ public:
     Base class for st_select_lex (SELECT_LEX) & 
     st_select_lex_unit (SELECT_LEX_UNIT)
 */
-struct st_lex;
+struct LEX;
 class st_select_lex;
 class st_select_lex_unit;
 class st_select_lex_node {
@@ -460,7 +460,7 @@ public:
   virtual void set_lock_for_tables(thr_lock_type lock_type) {}
 
   friend class st_select_lex_unit;
-  friend bool mysql_new_select(struct st_lex *lex, bool move_down);
+  friend bool mysql_new_select(LEX *lex, bool move_down);
   friend bool mysql_make_view(THD *thd, File_parser *parser,
                               TABLE_LIST *table, uint flags);
 private:
@@ -585,7 +585,7 @@ public:
   /* Saved values of the WHERE and HAVING clauses*/
   Item::cond_result cond_value, having_value;
   /* point on lex in which it was created, used in view subquery detection */
-  st_lex *parent_lex;
+  LEX *parent_lex;
   enum olap_type olap;
   /* FROM clause - points to the beginning of the TABLE_LIST::next_local list. */
   SQL_LIST	      table_list;
@@ -953,7 +953,7 @@ extern const LEX_STRING null_lex_str;
   stored functions/triggers to this list in order to pre-open and lock
   them.
 
-  Also used by st_lex::reset_n_backup/restore_backup_query_tables_list()
+  Also used by LEX::reset_n_backup/restore_backup_query_tables_list()
   methods to save and restore this information.
 */
 
@@ -1513,7 +1513,7 @@ public:
 
 /* The state of the lex parsing. This is saved in the THD struct */
 
-typedef struct st_lex : public Query_tables_list
+struct LEX: public Query_tables_list
 {
   SELECT_LEX_UNIT unit;                         /* most upper unit */
   SELECT_LEX select_lex;                        /* first SELECT_LEX */
@@ -1757,9 +1757,9 @@ typedef struct st_lex : public Query_tab
   bool escape_used;
   bool is_lex_started; /* If lex_start() did run. For debugging. */
 
-  st_lex();
+  LEX();
 
-  virtual ~st_lex()
+  virtual ~LEX()
   {
     destroy_query_tables_list();
     plugin_unlock_list(NULL, (plugin_ref *)plugins.buffer, plugins.elements);
@@ -1801,7 +1801,7 @@ typedef struct st_lex : public Query_tab
     Is this update command where 'WHITH CHECK OPTION' clause is important
 
     SYNOPSIS
-      st_lex::which_check_option_applicable()
+      LEX::which_check_option_applicable()
 
     RETURN
       TRUE   have to take 'WHITH CHECK OPTION' clause into account
@@ -1873,7 +1873,7 @@ typedef struct st_lex : public Query_tab
     }
     return FALSE;
   }
-} LEX;
+};
 
 
 /**
@@ -1928,7 +1928,7 @@ public:
 };
 
 
-struct st_lex_local: public st_lex
+struct st_lex_local: public LEX
 {
   static void *operator new(size_t size) throw()
   {

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2008-09-04 13:46:04 +0000
+++ b/sql/sql_parse.cc	2008-09-05 14:16:07 +0000
@@ -29,6 +29,7 @@
 #include "sql_trigger.h"
 #include <ddl_blocker.h>
 #include "sql_audit.h"
+#include "transaction.h"
 
 #ifdef BACKUP_TEST
 #include "backup/backup_test.h"
@@ -97,65 +98,6 @@ const char *xa_state_names[]={
 
 extern DDL_blocker_class *DDL_blocker;
 
-bool end_active_trans(THD *thd)
-{
-  int error=0;
-  DBUG_ENTER("end_active_trans");
-  if (unlikely(thd->in_sub_stmt))
-  {
-    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
-    DBUG_RETURN(1);
-  }
-  if (thd->transaction.xid_state.xa_state != XA_NOTR)
-  {
-    my_error(ER_XAER_RMFAIL, MYF(0),
-             xa_state_names[thd->transaction.xid_state.xa_state]);
-    DBUG_RETURN(1);
-  }
-  if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
-		      OPTION_TABLE_LOCK))
-  {
-    DBUG_PRINT("info",("options: 0x%llx", thd->options));
-    /* Safety if one did "drop table" on locked tables */
-    if (!thd->locked_tables_mode)
-      thd->options&= ~OPTION_TABLE_LOCK;
-    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
-    if (ha_commit(thd))
-      error=1;
-#ifdef WITH_MARIA_STORAGE_ENGINE
-    ha_maria::implicit_commit(thd, TRUE);
-#endif
-  }
-  thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
-  thd->transaction.all.modified_non_trans_table= FALSE;
-  DBUG_RETURN(error);
-}
-
-
-bool begin_trans(THD *thd)
-{
-  int error=0;
-  if (unlikely(thd->in_sub_stmt))
-  {
-    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
-    return 1;
-  }
-
-  thd->locked_tables_list.unlock_locked_tables(thd);
-
-  if (end_active_trans(thd))
-    error= -1;
-  else
-  {
-    LEX *lex= thd->lex;
-    thd->options|= OPTION_BEGIN;
-    thd->server_status|= SERVER_STATUS_IN_TRANS;
-    if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
-      error= ha_start_consistent_snapshot(thd);
-  }
-  return error;
-}
-
 #ifdef HAVE_REPLICATION
 /**
   Returns true if all tables should be ignored.
@@ -216,9 +158,9 @@ static bool opt_implicit_commit(THD *thd
   if (!skip)
   {
     /* Commit or rollback the statement transaction. */
-    ha_autocommit_or_rollback(thd, thd->is_error());
+    thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
     /* Commit the normal transaction if one is active. */
-    res= end_active_trans(thd);
+    res= trans_commit_implicit(thd);
   }
 
   DBUG_RETURN(res);
@@ -643,81 +585,6 @@ void cleanup_items(Item *item)
   DBUG_VOID_RETURN;
 }
 
-/**
-  Ends the current transaction and (maybe) begin the next.
-
-  @param thd            Current thread
-  @param completion     Completion type
-
-  @retval
-    0   OK
-*/
-
-int end_trans(THD *thd, enum enum_mysql_completiontype completion)
-{
-  bool do_release= 0;
-  int res= 0;
-  DBUG_ENTER("end_trans");
-
-  if (unlikely(thd->in_sub_stmt))
-  {
-    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
-    DBUG_RETURN(1);
-  }
-  if (thd->transaction.xid_state.xa_state != XA_NOTR)
-  {
-    my_error(ER_XAER_RMFAIL, MYF(0),
-             xa_state_names[thd->transaction.xid_state.xa_state]);
-    DBUG_RETURN(1);
-  }
-  thd->lex->start_transaction_opt= 0; /* for begin_trans() */
-  switch (completion) {
-  case COMMIT:
-    /*
-     We don't use end_active_trans() here to ensure that this works
-     even if there is a problem with the OPTION_AUTO_COMMIT flag
-     (Which of course should never happen...)
-    */
-    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
-    res= ha_commit(thd);
-    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
-    thd->transaction.all.modified_non_trans_table= FALSE;
-    break;
-  case COMMIT_RELEASE:
-    do_release= 1; /* fall through */
-  case COMMIT_AND_CHAIN:
-    res= end_active_trans(thd);
-    if (!res && completion == COMMIT_AND_CHAIN)
-      res= begin_trans(thd);
-    break;
-  case ROLLBACK_RELEASE:
-    do_release= 1; /* fall through */
-  case ROLLBACK:
-  case ROLLBACK_AND_CHAIN:
-  {
-    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
-    if (ha_rollback(thd))
-      res= -1;
-    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
-    thd->transaction.all.modified_non_trans_table= FALSE;
-    if (!res && (completion == ROLLBACK_AND_CHAIN))
-      res= begin_trans(thd);
-    break;
-  }
-  default:
-    res= -1;
-    my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
-    DBUG_RETURN(-1);
-  }
-
-  if (res < 0)
-    my_error(thd->killed_errno(), MYF(0));
-  else if ((res == 0) && do_release)
-    thd->killed= THD::KILL_CONNECTION;
-
-  DBUG_RETURN(res);
-}
-
 #ifndef EMBEDDED_LIBRARY
 
 /**
@@ -1340,14 +1207,14 @@ bool dispatch_command(enum enum_server_c
     bool not_used;
     status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]);
     ulong options= (ulong) (uchar) packet[0];
-    if (end_active_trans(thd))
+    if (trans_commit_implicit(thd))
       break;
     if (check_global_access(thd,RELOAD_ACL))
       break;
     general_log_print(thd, command, NullS);
     if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, &not_used))
       break;
-    if (end_active_trans(thd))
+    if (trans_commit_implicit(thd))
       break;
     my_ok(thd);
     break;
@@ -1497,7 +1364,7 @@ bool dispatch_command(enum enum_server_c
 
   /* If commit fails, we should be able to reset the OK status. */
   thd->main_da.can_overwrite_status= TRUE;
-  ha_autocommit_or_rollback(thd, thd->is_error());
+  thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
   thd->main_da.can_overwrite_status= FALSE;
 
   thd->transaction.stmt.reset();
@@ -3432,7 +3299,7 @@ ddl_blocker_err:
     thd->locked_tables_list.unlock_locked_tables(thd);
     if (thd->options & OPTION_TABLE_LOCK)
     {
-      end_active_trans(thd);
+      trans_commit_implicit(thd);
       thd->options&= ~(OPTION_TABLE_LOCK);
     }
     if (thd->global_read_lock)
@@ -3486,7 +3353,7 @@ ddl_blocker_err:
       goto error;
     thd->locked_tables_list.unlock_locked_tables(thd);
     /* we must end the trasaction first, regardless of anything */
-    if (end_active_trans(thd))
+    if (trans_commit_implicit(thd))
       goto error;
 
     alloc_mdl_locks(all_tables, thd->locked_tables_list.locked_tables_root());
@@ -3509,8 +3376,8 @@ ddl_blocker_err:
         can free its locks if LOCK TABLES locked some tables before finding
         that it can't lock a table in its list
       */
-      ha_autocommit_or_rollback(thd, 1);
-      end_active_trans(thd);
+      trans_rollback_stmt(thd);
+      trans_commit_implicit(thd);
       thd->options&= ~(OPTION_TABLE_LOCK);
     }
     else
@@ -4003,129 +3870,52 @@ ddl_blocker_err:
     break;
 
   case SQLCOM_BEGIN:
-    if (thd->transaction.xid_state.xa_state != XA_NOTR)
-    {
-      my_error(ER_XAER_RMFAIL, MYF(0),
-               xa_state_names[thd->transaction.xid_state.xa_state]);
-      break;
-    }
     DEBUG_SYNC(thd, "before_begin_trans");
-    if (begin_trans(thd))
+    if (trans_begin(thd, lex->start_transaction_opt))
       goto error;
     my_ok(thd);
     break;
   case SQLCOM_COMMIT:
     DBUG_ASSERT(thd->lock == NULL ||
                 thd->locked_tables_mode == LTM_LOCK_TABLES);
-    if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
-                              lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
+    if (trans_commit(thd))
+      goto error;
+    /* Begin transaction with the same isolation level. */
+    if (lex->tx_chain && trans_begin(thd))
       goto error;
+    /* Disconnect the current client connection. */
+    if (lex->tx_release)
+      thd->killed= THD::KILL_CONNECTION;
     DEBUG_SYNC(thd, "after_commit");
     my_ok(thd);
     break;
   case SQLCOM_ROLLBACK:
     DBUG_ASSERT(thd->lock == NULL ||
                 thd->locked_tables_mode == LTM_LOCK_TABLES);
-    if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
-                              lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
+    if (trans_rollback(thd))
+      goto error;
+    /* Begin transaction with the same isolation level. */
+    if (lex->tx_chain && trans_begin(thd))
       goto error;
+    /* Disconnect the current client connection. */
+    if (lex->tx_release)
+      thd->killed= THD::KILL_CONNECTION;
     my_ok(thd);
     break;
   case SQLCOM_RELEASE_SAVEPOINT:
-  {
-    SAVEPOINT *sv;
-    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
-    {
-      if (my_strnncoll(system_charset_info,
-                       (uchar *)lex->ident.str, lex->ident.length,
-                       (uchar *)sv->name, sv->length) == 0)
-        break;
-    }
-    if (sv)
-    {
-      if (ha_release_savepoint(thd, sv))
-        res= TRUE; // cannot happen
-      else
-        my_ok(thd);
-      thd->transaction.savepoints=sv->prev;
-    }
-    else
-      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
+    if (trans_release_savepoint(thd, lex->ident))
+      goto error;
+    my_ok(thd);
     break;
-  }
   case SQLCOM_ROLLBACK_TO_SAVEPOINT:
-  {
-    SAVEPOINT *sv;
-    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
-    {
-      if (my_strnncoll(system_charset_info,
-                       (uchar *)lex->ident.str, lex->ident.length,
-                       (uchar *)sv->name, sv->length) == 0)
-        break;
-    }
-    if (sv)
-    {
-      if (ha_rollback_to_savepoint(thd, sv))
-        res= TRUE; // cannot happen
-      else
-      {
-        if (((thd->options & OPTION_KEEP_LOG) || 
-             thd->transaction.all.modified_non_trans_table) &&
-            !thd->slave_thread)
-          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                       ER_WARNING_NOT_COMPLETE_ROLLBACK,
-                       ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
-        my_ok(thd);
-      }
-      thd->transaction.savepoints=sv;
-    }
-    else
-      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
+    if (trans_rollback_to_savepoint(thd, lex->ident))
+      goto error;
+    my_ok(thd);
     break;
-  }
   case SQLCOM_SAVEPOINT:
-    if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ||
-          thd->in_sub_stmt) || !opt_using_transactions)
-      my_ok(thd);
-    else
-    {
-      SAVEPOINT **sv, *newsv;
-      for (sv=&thd->transaction.savepoints; *sv; sv=&(*sv)->prev)
-      {
-        if (my_strnncoll(system_charset_info,
-                         (uchar *)lex->ident.str, lex->ident.length,
-                         (uchar *)(*sv)->name, (*sv)->length) == 0)
-          break;
-      }
-      if (*sv) /* old savepoint of the same name exists */
-      {
-        newsv=*sv;
-        ha_release_savepoint(thd, *sv); // it cannot fail
-        *sv=(*sv)->prev;
-      }
-      else if ((newsv=(SAVEPOINT *) alloc_root(&thd->transaction.mem_root,
-                                               savepoint_alloc_size)) == 0)
-      {
-        my_error(ER_OUT_OF_RESOURCES, MYF(0));
-        break;
-      }
-      newsv->name=strmake_root(&thd->transaction.mem_root,
-                               lex->ident.str, lex->ident.length);
-      newsv->length=lex->ident.length;
-      /*
-        if we'll get an error here, don't add new savepoint to the list.
-        we'll lose a little bit of memory in transaction mem_root, but it'll
-        be free'd when transaction ends anyway
-      */
-      if (ha_savepoint(thd, newsv))
-        res= TRUE;
-      else
-      {
-        newsv->prev=thd->transaction.savepoints;
-        thd->transaction.savepoints=newsv;
-        my_ok(thd);
-      }
-    }
+    if (trans_savepoint(thd, lex->ident))
+      goto error;
+    my_ok(thd);
     break;
   case SQLCOM_CREATE_PROCEDURE:
   case SQLCOM_CREATE_SPFUNCTION:
@@ -4467,7 +4257,7 @@ create_sp_error:
                                  lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
           goto error;
 
-        if (end_active_trans(thd)) 
+        if (trans_commit_implicit(thd))
           goto error;
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
 	if (sp_automatic_privileges && !opt_noacl &&
@@ -4597,173 +4387,29 @@ create_sp_error:
     break;
   }
   case SQLCOM_XA_START:
-    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
-        thd->lex->xa_opt == XA_RESUME)
-    {
-      if (! thd->transaction.xid_state.xid.eq(thd->lex->xid))
-      {
-        my_error(ER_XAER_NOTA, MYF(0));
-        break;
-      }
-      thd->transaction.xid_state.xa_state=XA_ACTIVE;
-      my_ok(thd);
-      break;
-    }
-    if (thd->lex->xa_opt != XA_NONE)
-    { // JOIN is not supported yet. TODO
-      my_error(ER_XAER_INVAL, MYF(0));
-      break;
-    }
-    if (thd->transaction.xid_state.xa_state != XA_NOTR)
-    {
-      my_error(ER_XAER_RMFAIL, MYF(0),
-               xa_state_names[thd->transaction.xid_state.xa_state]);
-      break;
-    }
-    if (thd->locked_tables_mode || thd->active_transaction())
-    {
-      my_error(ER_XAER_OUTSIDE, MYF(0));
-      break;
-    }
-    if (xid_cache_search(thd->lex->xid))
-    {
-      my_error(ER_XAER_DUPID, MYF(0));
-      break;
-    }
-    DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
-    thd->transaction.xid_state.xa_state=XA_ACTIVE;
-    thd->transaction.xid_state.xid.set(thd->lex->xid);
-    xid_cache_insert(&thd->transaction.xid_state);
-    thd->transaction.all.modified_non_trans_table= FALSE;
-    thd->options= ((thd->options & ~(OPTION_KEEP_LOG)) | OPTION_BEGIN);
-    thd->server_status|= SERVER_STATUS_IN_TRANS;
+    if (trans_xa_start(thd))
+      goto error;
     my_ok(thd);
     break;
   case SQLCOM_XA_END:
-    /* fake it */
-    if (thd->lex->xa_opt != XA_NONE)
-    { // SUSPEND and FOR MIGRATE are not supported yet. TODO
-      my_error(ER_XAER_INVAL, MYF(0));
-      break;
-    }
-    if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
-    {
-      my_error(ER_XAER_RMFAIL, MYF(0),
-               xa_state_names[thd->transaction.xid_state.xa_state]);
-      break;
-    }
-    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
-    {
-      my_error(ER_XAER_NOTA, MYF(0));
-      break;
-    }
-    thd->transaction.xid_state.xa_state=XA_IDLE;
+    if (trans_xa_end(thd))
+      goto error;
     my_ok(thd);
     break;
   case SQLCOM_XA_PREPARE:
-    if (thd->transaction.xid_state.xa_state != XA_IDLE)
-    {
-      my_error(ER_XAER_RMFAIL, MYF(0),
-               xa_state_names[thd->transaction.xid_state.xa_state]);
-      break;
-    }
-    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
-    {
-      my_error(ER_XAER_NOTA, MYF(0));
-      break;
-    }
-    if (ha_prepare(thd))
-    {
-      my_error(ER_XA_RBROLLBACK, MYF(0));
-      xid_cache_delete(&thd->transaction.xid_state);
-      thd->transaction.xid_state.xa_state=XA_NOTR;
-      break;
-    }
-    thd->transaction.xid_state.xa_state=XA_PREPARED;
+    if (trans_xa_prepare(thd))
+      goto error;
     my_ok(thd);
     break;
   case SQLCOM_XA_COMMIT:
-    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
-    {
-      XID_STATE *xs=xid_cache_search(thd->lex->xid);
-      if (!xs || xs->in_thd)
-        my_error(ER_XAER_NOTA, MYF(0));
-      else
-      {
-        ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
-        xid_cache_delete(xs);
-        my_ok(thd);
-      }
-      break;
-    }
-    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
-        thd->lex->xa_opt == XA_ONE_PHASE)
-    {
-      int r;
-      if ((r= ha_commit(thd)))
-        my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
-      else
-        my_ok(thd);
-    }
-    else if (thd->transaction.xid_state.xa_state == XA_PREPARED &&
-             thd->lex->xa_opt == XA_NONE)
-    {
-      if (wait_if_global_read_lock(thd, 0, 0))
-      {
-        ha_rollback(thd);
-        my_error(ER_XAER_RMERR, MYF(0));
-      }
-      else
-      {
-        if (ha_commit_one_phase(thd, 1))
-          my_error(ER_XAER_RMERR, MYF(0));
-        else
-          my_ok(thd);
-        start_waiting_global_read_lock(thd);
-      }
-    }
-    else
-    {
-      my_error(ER_XAER_RMFAIL, MYF(0),
-               xa_state_names[thd->transaction.xid_state.xa_state]);
-      break;
-    }
-    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
-    thd->transaction.all.modified_non_trans_table= FALSE;
-    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
-    xid_cache_delete(&thd->transaction.xid_state);
-    thd->transaction.xid_state.xa_state=XA_NOTR;
+    if (trans_xa_commit(thd))
+      goto error;
+    my_ok(thd);
     break;
   case SQLCOM_XA_ROLLBACK:
-    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
-    {
-      XID_STATE *xs=xid_cache_search(thd->lex->xid);
-      if (!xs || xs->in_thd)
-        my_error(ER_XAER_NOTA, MYF(0));
-      else
-      {
-        ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
-        xid_cache_delete(xs);
-        my_ok(thd);
-      }
-      break;
-    }
-    if (thd->transaction.xid_state.xa_state != XA_IDLE &&
-        thd->transaction.xid_state.xa_state != XA_PREPARED)
-    {
-      my_error(ER_XAER_RMFAIL, MYF(0),
-               xa_state_names[thd->transaction.xid_state.xa_state]);
-      break;
-    }
-    if (ha_rollback(thd))
-      my_error(ER_XAER_RMERR, MYF(0));
-    else
-      my_ok(thd);
-    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
-    thd->transaction.all.modified_non_trans_table= FALSE;
-    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
-    xid_cache_delete(&thd->transaction.xid_state);
-    thd->transaction.xid_state.xa_state=XA_NOTR;
+    if (trans_xa_rollback(thd))
+      goto error;
+    my_ok(thd);
     break;
   case SQLCOM_XA_RECOVER:
     res= mysql_xa_recover(thd);

=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc	2008-08-11 19:37:53 +0000
+++ b/sql/sql_partition.cc	2008-09-04 18:30:34 +0000
@@ -37,6 +37,7 @@
 #include <errno.h>
 #include <m_ctype.h>
 #include "my_md5.h"
+#include "transaction.h"
 
 #ifdef WITH_PARTITION_STORAGE_ENGINE
 #include "ha_partition.h"
@@ -3966,8 +3967,8 @@ static int fast_end_partition(THD *thd, 
   if (!is_empty)
     query_cache_invalidate3(thd, table_list, 0);
 
-  error= ha_autocommit_or_rollback(thd, 0);
-  if (end_active_trans(thd))
+  error= trans_commit_stmt(thd);
+  if (trans_commit_implicit(thd))
     error= 1;
 
   if (error)

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	2008-07-15 16:29:51 +0000
+++ b/sql/sql_prepare.cc	2008-08-07 17:52:43 +0000
@@ -105,7 +105,7 @@ class Select_fetch_protocol_binary: publ
   Protocol_binary protocol;
 public:
   Select_fetch_protocol_binary(THD *thd);
-  virtual bool send_fields(List<Item> &list, uint flags);
+  virtual bool send_result_set_metadata(List<Item> &list, uint flags);
   virtual bool send_data(List<Item> &items);
   virtual bool send_eof();
 #ifdef EMBEDDED_LIBRARY
@@ -258,7 +258,7 @@ static bool send_prep_stmt(Prepared_stat
   error= my_net_write(net, buff, sizeof(buff));
   if (stmt->param_count && ! error)
   {
-    error= thd->protocol_text.send_fields((List<Item> *)
+    error= thd->protocol_text.send_result_set_metadata((List<Item> *)
                                           &stmt->lex->param_list,
                                           Protocol::SEND_EOF);
   }
@@ -1373,7 +1373,7 @@ static int mysql_test_select(Prepared_st
       unit->prepare call above.
     */
     if (send_prep_stmt(stmt, lex->result->field_count(fields)) ||
-        lex->result->send_fields(fields, Protocol::SEND_EOF) ||
+        lex->result->send_result_set_metadata(fields, Protocol::SEND_EOF) ||
         thd->protocol->flush())
       goto error;
     DBUG_RETURN(2);
@@ -2774,19 +2774,19 @@ Select_fetch_protocol_binary::Select_fet
   :protocol(thd_arg)
 {}
 
-bool Select_fetch_protocol_binary::send_fields(List<Item> &list, uint flags)
+bool Select_fetch_protocol_binary::send_result_set_metadata(List<Item> &list, uint flags)
 {
   bool rc;
   Protocol *save_protocol= thd->protocol;
 
   /*
-    Protocol::send_fields caches the information about column types:
+    Protocol::send_result_set_metadata caches the information about column types:
     this information is later used to send data. Therefore, the same
     dedicated Protocol object must be used for all operations with
     a cursor.
   */
   thd->protocol= &protocol;
-  rc= select_send::send_fields(list, flags);
+  rc= select_send::send_result_set_metadata(list, flags);
   thd->protocol= save_protocol;
 
   return rc;
@@ -3597,6 +3597,9 @@ bool Prepared_statement::execute(String 
   if (state == Query_arena::PREPARED)
     state= Query_arena::EXECUTED;
 
+  if (this->lex->sql_command == SQLCOM_CALL)
+    protocol->send_out_parameters(&this->lex->param_list);
+
   /*
     Log COM_EXECUTE to the general log. Note, that in case of SQL
     prepared statements this causes two records to be output:

=== modified file 'sql/sql_profile.cc'
--- a/sql/sql_profile.cc	2008-06-25 16:28:57 +0000
+++ b/sql/sql_profile.cc	2008-08-07 17:52:43 +0000
@@ -412,7 +412,7 @@ bool PROFILING::show_profiles()
                                            MYSQL_TYPE_DOUBLE));
   field_list.push_back(new Item_empty_string("Query", 40));
 
-  if (thd->protocol->send_fields(&field_list,
+  if (thd->protocol->send_result_set_metadata(&field_list,
                                  Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 

=== modified file 'sql/sql_repl.cc'
--- a/sql/sql_repl.cc	2008-08-22 06:48:55 +0000
+++ b/sql/sql_repl.cc	2008-09-04 18:30:34 +0000
@@ -1448,7 +1448,7 @@ bool mysql_show_binlog_events(THD* thd)
   DBUG_ENTER("mysql_show_binlog_events");
 
   Log_event::init_show_field_list(&field_list);
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 
@@ -1598,7 +1598,7 @@ bool show_binlog_info(THD* thd)
   field_list.push_back(new Item_empty_string("Binlog_Do_DB",255));
   field_list.push_back(new Item_empty_string("Binlog_Ignore_DB",255));
 
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
   protocol->prepare_for_resend();
@@ -1653,7 +1653,7 @@ bool show_binlogs(THD* thd)
   field_list.push_back(new Item_empty_string("Log_name", 255));
   field_list.push_back(new Item_return_int("File_size", 20,
                                            MYSQL_TYPE_LONGLONG));
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
   

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2008-08-28 11:17:29 +0000
+++ b/sql/sql_select.cc	2008-09-04 18:30:34 +0000
@@ -2289,7 +2289,7 @@ JOIN::exec()
 		      (zero_result_cause?zero_result_cause:"No tables used"));
     else
     {
-      result->send_fields(*columns_list,
+      result->send_result_set_metadata(*columns_list,
                           Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
       /*
         We have to test for 'conds' here as the WHERE may not be constant
@@ -2681,7 +2681,7 @@ JOIN::exec()
   }
   if (curr_join->group_list || curr_join->order)
   {
-    DBUG_PRINT("info",("Sorting for send_fields"));
+    DBUG_PRINT("info",("Sorting for send_result_set_metadata"));
     thd_proc_info(thd, "Sorting result");
     /* If we have already done the group, add HAVING to sorted table */
     if (curr_join->tmp_having && ! curr_join->group_list && 
@@ -2821,7 +2821,7 @@ JOIN::exec()
   {
     thd_proc_info(thd, "Sending data");
     DBUG_PRINT("info", ("%s", thd->proc_info));
-    result->send_fields((procedure ? curr_join->procedure_fields_list :
+    result->send_result_set_metadata((procedure ? curr_join->procedure_fields_list :
                          *curr_fields_list),
                         Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
     error= do_select(curr_join, curr_fields_list, NULL, procedure);
@@ -9021,7 +9021,7 @@ return_zero_rows(JOIN *join, select_resu
     if (having && having->val_int() == 0)
       send_row=0;
   }
-  if (!(result->send_fields(fields,
+  if (!(result->send_result_set_metadata(fields,
                               Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)))
   {
     if (send_row)
@@ -11641,7 +11641,7 @@ void setup_tmp_table_column_bitmaps(TABL
   Create a temp table according to a field list.
 
   Given field pointers are changed to point at tmp_table for
-  send_fields. The table object is self contained: it's
+  send_result_set_metadata. The table object is self contained: it's
   allocated in its own memory root, as well as Field objects
   created for table columns.
   This function will replace Item_sum items in 'fields' list with
@@ -17832,7 +17832,7 @@ int test_if_item_cache_changed(List<Cach
 
   Only FIELD_ITEM:s and FUNC_ITEM:s needs to be saved between groups.
   Change old item_field to use a new field with points at saved fieldvalue
-  This function is only called before use of send_fields.
+  This function is only called before use of send_result_set_metadata.
 
   @param thd                   THD pointer
   @param param                 temporary table parameters
@@ -18063,7 +18063,7 @@ bool JOIN::alloc_func_list()
   Initialize 'sum_funcs' array with all Item_sum objects.
 
   @param field_list        All items
-  @param send_fields       Items in select list
+  @param send_result_set_metadata       Items in select list
   @param before_group_by   Set to 1 if this is called before GROUP BY handling
   @param recompute         Set to TRUE if sum_funcs must be recomputed
 
@@ -18073,7 +18073,7 @@ bool JOIN::alloc_func_list()
     1  error
 */
 
-bool JOIN::make_sum_func_list(List<Item> &field_list, List<Item> &send_fields,
+bool JOIN::make_sum_func_list(List<Item> &field_list, List<Item> &send_result_set_metadata,
 			      bool before_group_by, bool recompute)
 {
   List_iterator_fast<Item> it(field_list);
@@ -18095,7 +18095,7 @@ bool JOIN::make_sum_func_list(List<Item>
   if (before_group_by && rollup.state == ROLLUP::STATE_INITED)
   {
     rollup.state= ROLLUP::STATE_READY;
-    if (rollup_make_fields(field_list, send_fields, &func))
+    if (rollup_make_fields(field_list, send_result_set_metadata, &func))
       DBUG_RETURN(TRUE);			// Should never happen
   }
   else if (rollup.state == ROLLUP::STATE_NONE)

=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h	2008-08-16 15:22:47 +0000
+++ b/sql/sql_select.h	2008-09-04 18:30:34 +0000
@@ -174,7 +174,6 @@ class SJ_TMP_TABLE;
 
 typedef enum_nested_loop_state
 (*Next_select_func)(JOIN *, struct st_join_table *, bool);
-typedef int (*Read_record_func)(struct st_join_table *tab);
 Next_select_func setup_end_select_func(JOIN *join);
 
 
@@ -210,7 +209,7 @@ typedef struct st_join_table {
   */
   uint          packed_info;
 
-  Read_record_func read_first_record;
+  READ_RECORD::Setup_func read_first_record;
   Next_select_func next_select;
   READ_RECORD	read_record;
   /* 
@@ -218,8 +217,8 @@ typedef struct st_join_table {
     if it is executed by an alternative full table scan when the left operand of
     the subquery predicate is evaluated to NULL.
   */  
-  Read_record_func save_read_first_record;/* to save read_first_record */ 
-  int (*save_read_record) (READ_RECORD *);/* to save read_record.read_record */
+  READ_RECORD::Setup_func save_read_first_record;/* to save read_first_record */
+  READ_RECORD::Read_func save_read_record;/* to save read_record.read_record */
   double	worst_seeks;
   key_map	const_keys;			/**< Keys with constant part */
   key_map	checked_keys;			/**< Keys checked in find_best */
@@ -648,7 +647,7 @@ public:
   bool alloc_func_list();
   bool flatten_subqueries();
   bool setup_subquery_materialization();
-  bool make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields,
+  bool make_sum_func_list(List<Item> &all_fields, List<Item> &send_result_set_metadata,
 			  bool before_group_by, bool recompute= FALSE);
 
   inline void set_items_ref_array(Item **ptr)

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2008-09-11 18:36:05 +0000
+++ b/sql/sql_show.cc	2008-09-16 17:58:49 +0000
@@ -216,7 +216,7 @@ bool mysqld_show_authors(THD *thd)
   field_list.push_back(new Item_empty_string("Location",40));
   field_list.push_back(new Item_empty_string("Comment",80));
 
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 
@@ -250,7 +250,7 @@ bool mysqld_show_contributors(THD *thd)
   field_list.push_back(new Item_empty_string("Location",40));
   field_list.push_back(new Item_empty_string("Comment",80));
 
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 
@@ -326,7 +326,7 @@ bool mysqld_show_privileges(THD *thd)
   field_list.push_back(new Item_empty_string("Context",15));
   field_list.push_back(new Item_empty_string("Comment",NAME_CHAR_LEN));
 
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 
@@ -563,7 +563,7 @@ mysqld_show_create(THD *thd, TABLE_LIST 
                                                max(buffer.length(),1024)));
   }
 
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
   protocol->prepare_for_resend();
@@ -641,7 +641,7 @@ bool mysqld_show_create_db(THD *thd, cha
   field_list.push_back(new Item_empty_string("Database",NAME_CHAR_LEN));
   field_list.push_back(new Item_empty_string("Create Database",1024));
 
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 
@@ -691,7 +691,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST 
   }
   restore_record(table, s->default_values);              // Get empty record
   table->use_all_columns();
-  if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS))
+  if (thd->protocol->send_result_set_metadata(&field_list, Protocol::SEND_DEFAULTS))
     DBUG_VOID_RETURN;
   my_eof(thd);
   DBUG_VOID_RETURN;
@@ -1657,7 +1657,7 @@ void mysqld_list_processes(THD *thd,cons
   field->maybe_null=1;
   field_list.push_back(field=new Item_empty_string("Info",max_query_length));
   field->maybe_null=1;
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_VOID_RETURN;
 
@@ -3145,7 +3145,7 @@ static int fill_schema_table_from_frm(TH
                      OPEN_VIEW_NO_PARSE,
                      thd->open_options, &tbl, &table_list, thd->mem_root))
       goto err_share;
-    table_list.view= (st_lex*) share->is_view;
+    table_list.view= (LEX*) share->is_view;
     res= schema_table->process_table(thd, &table_list, table,
                                      res, db_name, table_name);
     goto err_share;
@@ -3154,7 +3154,7 @@ static int fill_schema_table_from_frm(TH
   {
     tbl.s= share;
     table_list.table= &tbl;
-    table_list.view= (st_lex*) share->is_view;
+    table_list.view= (LEX*) share->is_view;
     res= schema_table->process_table(thd, &table_list, table,
                                      res, db_name, table_name);
   }
@@ -7215,7 +7215,7 @@ static bool show_create_trigger_impl(THD
   fields.push_back(new Item_empty_string("Database Collation",
                                          MY_CS_NAME_SIZE));
 
-  if (p->send_fields(&fields, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+  if (p->send_result_set_metadata(&fields, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     return TRUE;
 
   /* Send data. */

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2008-09-04 08:47:10 +0000
+++ b/sql/sql_table.cc	2008-09-04 20:00:04 +0000
@@ -22,6 +22,7 @@
 #include "sp_head.h"
 #include "sql_trigger.h"
 #include "sql_show.h"
+#include "transaction.h"
 
 #ifdef __WIN__
 #include <io.h>
@@ -4165,7 +4166,7 @@ static bool mysql_admin_table(THD* thd, 
   item->maybe_null = 1;
   field_list.push_back(item = new Item_empty_string("Msg_text", 255, cs));
   item->maybe_null = 1;
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 
@@ -4257,8 +4258,8 @@ static bool mysql_admin_table(THD* thd, 
       DBUG_PRINT("admin", ("calling prepare_func"));
       switch ((*prepare_func)(thd, table, check_opt)) {
       case  1:           // error, message written to net
-        ha_autocommit_or_rollback(thd, 1);
-        end_trans(thd, ROLLBACK);
+        trans_rollback_stmt(thd);
+        trans_rollback(thd);
         close_thread_tables(thd);
         DBUG_PRINT("admin", ("simple error, admin next table"));
         continue;
@@ -4316,8 +4317,8 @@ static bool mysql_admin_table(THD* thd, 
       length= my_snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY),
                           table_name);
       protocol->store(buff, length, system_charset_info);
-      ha_autocommit_or_rollback(thd, 0);
-      end_trans(thd, COMMIT);
+      trans_commit_stmt(thd);
+      trans_commit(thd);
       close_thread_tables(thd);
       lex->reset_query_tables_list(FALSE);
       table->table=0;				// For query cache
@@ -4366,7 +4367,7 @@ static bool mysql_admin_table(THD* thd, 
            HA_ADMIN_NEEDS_ALTER))
       {
         DBUG_PRINT("admin", ("recreating table"));
-        ha_autocommit_or_rollback(thd, 1);
+        trans_rollback_stmt(thd);
         close_thread_tables(thd);
         tmp_disable_binlog(thd); // binlogging is done by caller if wanted
         result_code= mysql_recreate_table(thd, table);
@@ -4480,13 +4481,13 @@ send_result_message:
         reopen the table and do ha_innobase::analyze() on it.
         We have to end the row, so analyze could return more rows.
       */
+      trans_commit_stmt(thd);
       protocol->store(STRING_WITH_LEN("note"), system_charset_info);
       protocol->store(STRING_WITH_LEN(
           "Table does not support optimize, doing recreate + analyze instead"),
                       system_charset_info);
       if (protocol->write())
         goto err;
-      ha_autocommit_or_rollback(thd, 0);
       close_thread_tables(thd);
       DBUG_PRINT("info", ("HA_ADMIN_TRY_ALTER, trying analyze..."));
       TABLE_LIST *save_next_local= table->next_local,
@@ -4503,7 +4504,7 @@ send_result_message:
       */
       if (thd->main_da.is_ok())
         thd->main_da.reset_diagnostics_area();
-      ha_autocommit_or_rollback(thd, 0);
+      trans_commit_stmt(thd);
       close_thread_tables(thd);
       if (!result_code) // recreation went ok
       {
@@ -4597,8 +4598,8 @@ send_result_message:
         query_cache_invalidate3(thd, table->table, 0);
       }
     }
-    ha_autocommit_or_rollback(thd, 0);
-    end_trans(thd, COMMIT);
+    trans_commit_stmt(thd);
+    trans_commit_implicit(thd);
     close_thread_tables(thd);
     table->table=0;				// For query cache
     if (protocol->write())
@@ -4609,8 +4610,8 @@ send_result_message:
   DBUG_RETURN(FALSE);
 
 err:
-  ha_autocommit_or_rollback(thd, 1);
-  end_trans(thd, ROLLBACK);
+  trans_rollback_stmt(thd);
+  trans_rollback(thd);
   close_thread_tables(thd);			// Shouldn't be needed
   if (table)
     table->table=0;
@@ -5102,15 +5103,15 @@ mysql_discard_or_import_tablespace(THD *
   query_cache_invalidate3(thd, table_list, 0);
 
   /* The ALTER TABLE is always in its own transaction */
-  error = ha_autocommit_or_rollback(thd, 0);
-  if (end_active_trans(thd))
+  error= trans_commit_stmt(thd);
+  if (trans_commit_implicit(thd))
     error=1;
   if (error)
     goto err;
   write_bin_log(thd, FALSE, thd->query, thd->query_length);
 
 err:
-  ha_autocommit_or_rollback(thd, error);
+  trans_rollback_stmt(thd);
   thd->tablespace_op=FALSE;
 
   if (error == 0)
@@ -5867,8 +5868,8 @@ mysql_fast_or_online_alter_table(THD *th
     wait_if_global_read_lock(), which could create a deadlock if called
     with LOCK_open.
   */
-  error= ha_autocommit_or_rollback(thd, 0);
-  if (ha_commit(thd))
+  error= trans_commit_stmt(thd);
+  if (trans_commit_implicit(thd))
     error= 1;
 
   if (error)
@@ -7001,8 +7002,8 @@ view_err:
   }
   else
   {
-    error= ha_autocommit_or_rollback(thd, 0);
-    if (end_active_trans(thd))
+    error= trans_commit_stmt(thd);
+    if (trans_commit_implicit(thd))
       error= 1;
   }
   thd->count_cuted_fields= CHECK_FIELD_IGNORE;
@@ -7446,9 +7447,9 @@ err:
     Ensure that the new table is saved properly to disk so that we
     can do a rename
   */
-  if (ha_autocommit_or_rollback(thd, 0))
+  if (trans_commit_stmt(thd))
     error=1;
-  if (end_active_trans(thd))
+  if (trans_commit_implicit(thd))
     error=1;
 
   thd->variables.sql_mode= save_sql_mode;
@@ -7513,7 +7514,7 @@ bool mysql_checksum_table(THD *thd, TABL
   field_list.push_back(item= new Item_int("Checksum", (longlong) 1,
                                           MY_INT64_NUM_DECIMAL_DIGITS));
   item->maybe_null= 1;
-  if (protocol->send_fields(&field_list,
+  if (protocol->send_result_set_metadata(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2008-08-22 11:16:08 +0000
+++ b/sql/sql_yacc.yy	2008-09-04 18:30:34 +0000
@@ -575,7 +575,7 @@ bool setup_select_in_parentheses(LEX *le
   struct sp_cond_type *spcondtype;
   struct { int vars, conds, hndlrs, curs; } spblock;
   sp_name *spname;
-  struct st_lex *lex;
+  LEX *lex;
   sp_head *sphead;
   struct p_elem_val *p_elem_value;
   enum index_hint_type index_hint;

=== modified file 'sql/structs.h'
--- a/sql/structs.h	2008-07-10 16:02:38 +0000
+++ b/sql/structs.h	2008-09-04 18:30:34 +0000
@@ -16,8 +16,9 @@
 
 /* The old structures from unireg */
 
-struct st_table;
+struct TABLE;
 class Field;
+class THD;
 
 typedef struct st_date_time_format {
   uchar positions[8];
@@ -100,7 +101,7 @@ typedef struct st_key {
   union {
     int  bdb_return_if_eq;
   } handler;
-  struct st_table *table;
+  TABLE *table;
   LEX_STRING comment;
 } KEY;
 
@@ -115,30 +116,6 @@ typedef struct st_reginfo {		/* Extra in
 } REGINFO;
 
 
-struct st_read_record;				/* For referense later */
-class SQL_SELECT;
-class THD;
-class handler;
-struct st_join_table;
-
-typedef struct st_read_record {			/* Parameter to read_record */
-  struct st_table *table;			/* Head-form */
-  handler *file;
-  struct st_table **forms;			/* head and ref forms */
-  int (*read_record)(struct st_read_record *);
-  THD *thd;
-  SQL_SELECT *select;
-  uint cache_records;
-  uint ref_length,struct_length,reclength,rec_cache_size,error_offset;
-  uint index;
-  uchar *ref_pos;				/* pointer to form->refpos */
-  uchar *record;
-  uchar *rec_buf;                /* to read field values  after filesort */
-  uchar	*cache,*cache_pos,*cache_end,*read_positions;
-  IO_CACHE *io_cache;
-  bool print_error, ignore_not_found_rows;
-} READ_RECORD;
-
 
 /*
   Originally MySQL used MYSQL_TIME structure inside server only, but since

=== modified file 'sql/table.cc'
--- a/sql/table.cc	2008-08-07 03:05:33 +0000
+++ b/sql/table.cc	2008-08-12 16:46:23 +0000
@@ -3019,7 +3019,7 @@ table_check_intact(TABLE *table, const u
   Create Item_field for each column in the table.
 
   SYNPOSIS
-    st_table::fill_item_list()
+    TABLE::fill_item_list()
       item_list          a pointer to an empty list used to store items
 
   DESCRIPTION
@@ -3032,7 +3032,7 @@ table_check_intact(TABLE *table, const u
     1                    out of memory
 */
 
-bool st_table::fill_item_list(List<Item> *item_list) const
+bool TABLE::fill_item_list(List<Item> *item_list) const
 {
   /*
     All Item_field's created using a direct pointer to a field
@@ -3052,7 +3052,7 @@ bool st_table::fill_item_list(List<Item>
   Fields of this table.
 
   SYNPOSIS
-    st_table::fill_item_list()
+    TABLE::fill_item_list()
       item_list          a non-empty list with Item_fields
 
   DESCRIPTION
@@ -3062,7 +3062,7 @@ bool st_table::fill_item_list(List<Item>
     is the same as the number of columns in the table.
 */
 
-void st_table::reset_item_list(List<Item> *item_list) const
+void TABLE::reset_item_list(List<Item> *item_list) const
 {
   List_iterator_fast<Item> it(*item_list);
   for (Field **ptr= field; *ptr; ptr++)
@@ -3988,7 +3988,7 @@ const char *Natural_join_column::db_name
     return table_ref->view_db.str;
 
   /*
-    Test that TABLE_LIST::db is the same as st_table_share::db to
+    Test that TABLE_LIST::db is the same as TABLE_SHARE::db to
     ensure consistency. An exception are I_S schema tables, which
     are inconsistent in this respect.
   */
@@ -4207,7 +4207,7 @@ const char *Field_iterator_table_ref::db
     return natural_join_it.column_ref()->db_name();
 
   /*
-    Test that TABLE_LIST::db is the same as st_table_share::db to
+    Test that TABLE_LIST::db is the same as TABLE_SHARE::db to
     ensure consistency. An exception are I_S schema tables, which
     are inconsistent in this respect.
   */
@@ -4379,7 +4379,7 @@ Field_iterator_table_ref::get_natural_co
 
 /* Reset all columns bitmaps */
 
-void st_table::clear_column_bitmaps()
+void TABLE::clear_column_bitmaps()
 {
   /*
     Reset column read/write usage. It's identical to:
@@ -4400,9 +4400,9 @@ void st_table::clear_column_bitmaps()
   key fields.
 */
 
-void st_table::prepare_for_position()
+void TABLE::prepare_for_position()
 {
-  DBUG_ENTER("st_table::prepare_for_position");
+  DBUG_ENTER("TABLE::prepare_for_position");
 
   if ((file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
       s->primary_key < MAX_KEY)
@@ -4421,14 +4421,14 @@ void st_table::prepare_for_position()
   NOTE:
     This changes the bitmap to use the tmp bitmap
     After this, you can't access any other columns in the table until
-    bitmaps are reset, for example with st_table::clear_column_bitmaps()
-    or st_table::restore_column_maps_after_mark_index()
+    bitmaps are reset, for example with TABLE::clear_column_bitmaps()
+    or TABLE::restore_column_maps_after_mark_index()
 */
 
-void st_table::mark_columns_used_by_index(uint index)
+void TABLE::mark_columns_used_by_index(uint index)
 {
   MY_BITMAP *bitmap= &tmp_set;
-  DBUG_ENTER("st_table::mark_columns_used_by_index");
+  DBUG_ENTER("TABLE::mark_columns_used_by_index");
 
   (void) file->extra(HA_EXTRA_KEYREAD);
   bitmap_clear_all(bitmap);
@@ -4449,9 +4449,9 @@ void st_table::mark_columns_used_by_inde
     when calling mark_columns_used_by_index
 */
 
-void st_table::restore_column_maps_after_mark_index()
+void TABLE::restore_column_maps_after_mark_index()
 {
-  DBUG_ENTER("st_table::restore_column_maps_after_mark_index");
+  DBUG_ENTER("TABLE::restore_column_maps_after_mark_index");
 
   key_read= 0;
   (void) file->extra(HA_EXTRA_NO_KEYREAD);
@@ -4465,7 +4465,7 @@ void st_table::restore_column_maps_after
   mark columns used by key, but don't reset other fields
 */
 
-void st_table::mark_columns_used_by_index_no_reset(uint index,
+void TABLE::mark_columns_used_by_index_no_reset(uint index,
                                                    MY_BITMAP *bitmap)
 {
   KEY_PART_INFO *key_part= key_info[index].key_part;
@@ -4484,7 +4484,7 @@ void st_table::mark_columns_used_by_inde
     always set and sometimes read.
 */
 
-void st_table::mark_auto_increment_column()
+void TABLE::mark_auto_increment_column()
 {
   DBUG_ASSERT(found_next_number_field);
   /*
@@ -4517,7 +4517,7 @@ void st_table::mark_auto_increment_colum
     retrieve the row again.
 */
 
-void st_table::mark_columns_needed_for_delete()
+void TABLE::mark_columns_needed_for_delete()
 {
   if (triggers)
     triggers->mark_fields_used(TRG_EVENT_DELETE);
@@ -4570,7 +4570,7 @@ void st_table::mark_columns_needed_for_d
     retrieve the row again.
 */
 
-void st_table::mark_columns_needed_for_update()
+void TABLE::mark_columns_needed_for_update()
 {
   DBUG_ENTER("mark_columns_needed_for_update");
   if (triggers)
@@ -4616,7 +4616,7 @@ void st_table::mark_columns_needed_for_u
   as changed.
 */
 
-void st_table::mark_columns_needed_for_insert()
+void TABLE::mark_columns_needed_for_insert()
 {
   if (triggers)
   {
@@ -4692,9 +4692,9 @@ Item_subselect *TABLE_LIST::containing_s
   DESCRIPTION
     The parser collects the index hints for each table in a "tagged list" 
     (TABLE_LIST::index_hints). Using the information in this tagged list
-    this function sets the members st_table::keys_in_use_for_query, 
-    st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by,
-    st_table::force_index and st_table::covering_keys.
+    this function sets the members TABLE::keys_in_use_for_query, 
+    TABLE::keys_in_use_for_group_by, TABLE::keys_in_use_for_order_by,
+    TABLE::force_index and TABLE::covering_keys.
 
     Current implementation of the runtime does not allow mixing FORCE INDEX
     and USE INDEX, so this is checked here. Then the FORCE INDEX list 

=== modified file 'sql/table.h'
--- a/sql/table.h	2008-09-11 18:36:05 +0000
+++ b/sql/table.h	2008-09-16 17:58:49 +0000
@@ -245,9 +245,9 @@ struct TABLE_share;
   instance of table share per one table in the database.
 */
 
-typedef struct st_table_share
+struct TABLE_SHARE
 {
-  st_table_share() {}                    /* Remove gcc warning */
+  TABLE_SHARE() {}                    /* Remove gcc warning */
 
   /** Category of this table. */
   TABLE_CATEGORY table_category;
@@ -259,8 +259,7 @@ typedef struct st_table_share
   TYPELIB fieldnames;			/* Pointer to fieldnames */
   TYPELIB *intervals;			/* pointer to interval info */
   pthread_mutex_t LOCK_ha_data;         /* To protect access to ha_data */
-  struct st_table_share *next,		/* Link to unused shares */
-    **prev;
+  TABLE_SHARE *next, **prev;            /* Link to unused shares */
 
   /*
     Doubly-linked (back-linked) lists of used and unused TABLE objects
@@ -550,7 +549,7 @@ typedef struct st_table_share
     return (tmp_table == SYSTEM_TMP_TABLE || is_view) ? 0 : table_map_id;
   }
 
-} TABLE_SHARE;
+};
 
 
 extern ulong refresh_version;
@@ -563,8 +562,9 @@ enum index_hint_type
   INDEX_HINT_FORCE
 };
 
-struct st_table {
-  st_table() {}                               /* Remove gcc warning */
+struct TABLE
+{
+  TABLE() {}                               /* Remove gcc warning */
 
   TABLE_SHARE	*s;
   handler	*file;
@@ -575,11 +575,11 @@ private:
      Declared as private to avoid direct manipulation with those objects.
      One should use methods of I_P_List template instead.
   */
-  struct st_table *share_next, **share_prev;
+  TABLE *share_next, **share_prev;
 
   friend struct TABLE_share;
 public:
-  struct st_table *next, *prev;
+  TABLE *next, *prev;
 
   THD	*in_use;                        /* Which thread uses this */
   Field **field;			/* Pointer to fields */
@@ -716,9 +716,7 @@ public:
   my_bool force_index;
   my_bool distinct,const_table,no_rows;
   my_bool key_read, no_keyread;
-  my_bool locked_by_logger;
   my_bool no_replicate;
-  my_bool locked_by_name;
   my_bool fulltext_searched;
   my_bool no_cache;
   /* To signal that the table is associated with a HANDLER statement */
@@ -729,7 +727,6 @@ public:
     Used only in the MODE_NO_AUTO_VALUE_ON_ZERO mode.
   */
   my_bool auto_increment_field_not_null;
-  my_bool insert_or_update;             /* Can be used by the handler */
   my_bool alias_name_used;		/* true if table_name is alias */
   my_bool get_fields_in_item_tree;      /* Signal to fix_field */
 
@@ -911,7 +908,6 @@ typedef struct st_schema_table
 /** The threshold size a blob field buffer before it is freed */
 #define MAX_TDC_BLOB_SIZE 65536
 
-struct st_lex;
 class select_union;
 class TMP_TABLE_PARAM;
 
@@ -991,6 +987,7 @@ public:
        ;
 */
 
+struct LEX;
 class Index_hint;
 struct TABLE_LIST
 {
@@ -1106,7 +1103,7 @@ struct TABLE_LIST
   TMP_TABLE_PARAM *schema_table_param;
   /* link to select_lex where this table was used */
   st_select_lex	*select_lex;
-  st_lex	*view;			/* link on VIEW lex for merging */
+  LEX *view;                    /* link on VIEW lex for merging */
   Field_translator *field_translation;	/* array of VIEW fields */
   /* pointer to element after last one in translation table above */
   Field_translator *field_translation_end;
@@ -1335,9 +1332,9 @@ struct TABLE_LIST
   Item_subselect *containing_subselect();
 
   /* 
-    Compiles the tagged hints list and fills up st_table::keys_in_use_for_query,
-    st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by,
-    st_table::force_index and st_table::covering_keys.
+    Compiles the tagged hints list and fills up TABLE::keys_in_use_for_query,
+    TABLE::keys_in_use_for_group_by, TABLE::keys_in_use_for_order_by,
+    TABLE::force_index and TABLE::covering_keys.
   */
   bool process_index_hints(TABLE *table);
 

=== added file 'sql/transaction.cc'
--- a/sql/transaction.cc	1970-01-01 00:00:00 +0000
+++ b/sql/transaction.cc	2008-08-12 22:30:55 +0000
@@ -0,0 +1,584 @@
+/* Copyright (C) 2008 Sun/MySQL
+
+   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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation                         // gcc: Class implementation
+#endif
+
+#include "transaction.h"
+#include "mysql_priv.h"
+
+#ifdef WITH_MARIA_STORAGE_ENGINE
+#include "../storage/maria/ha_maria.h"
+#endif
+
+/* Conditions under which the transaction state must not change. */
+static bool trans_check(THD *thd)
+{
+  enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+  DBUG_ENTER("trans_check");
+
+  if (unlikely(thd->in_sub_stmt))
+    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
+  if (xa_state != XA_NOTR)
+    my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+  else
+    DBUG_RETURN(FALSE);
+
+  DBUG_RETURN(TRUE);
+}
+
+
+/**
+  Begin a new transaction.
+
+  @note Beginning a transaction implicitly commits any current
+        transaction and releases existing locks.
+
+  @param thd     Current thread
+  @param flags   Transaction flags
+
+  @retval FALSE  Success
+  @retval TRUE   Failure
+*/
+
+bool trans_begin(THD *thd, uint flags)
+{
+  int res= FALSE;
+  DBUG_ENTER("trans_begin");
+
+  if (trans_check(thd))
+    DBUG_RETURN(TRUE);
+
+  thd->locked_tables_list.unlock_locked_tables(thd);
+
+  if (trans_commit_implicit(thd))
+    DBUG_RETURN(TRUE);
+
+  thd->options|= OPTION_BEGIN;
+  thd->server_status|= SERVER_STATUS_IN_TRANS;
+
+  if (flags & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
+    res= ha_start_consistent_snapshot(thd);
+
+  DBUG_RETURN(test(res));
+}
+
+
+/**
+  Commit the current transaction, making its changes permanent.
+
+  @param thd     Current thread
+
+  @retval FALSE  Success
+  @retval TRUE   Failure
+*/
+
+bool trans_commit(THD *thd)
+{
+  int res;
+  DBUG_ENTER("trans_commit");
+
+  if (trans_check(thd))
+    DBUG_RETURN(TRUE);
+
+  thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+  res= ha_commit_trans(thd, TRUE);
+  thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+  thd->transaction.all.modified_non_trans_table= FALSE;
+  thd->lex->start_transaction_opt= 0;
+
+  DBUG_RETURN(test(res));
+}
+
+
+/**
+  Implicitly commit the current transaction.
+
+  @note A implicit commit does not releases existing table locks.
+
+  @param thd     Current thread
+
+  @retval FALSE  Success
+  @retval TRUE   Failure
+*/
+
+bool trans_commit_implicit(THD *thd)
+{
+  bool res= FALSE;
+  DBUG_ENTER("trans_commit_implicit");
+
+  if (trans_check(thd))
+    DBUG_RETURN(TRUE);
+
+  if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
+                      OPTION_TABLE_LOCK))
+  {
+    /* Safety if one did "drop table" on locked tables */
+    if (!thd->locked_tables_mode)
+      thd->options&= ~OPTION_TABLE_LOCK;
+    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+    res= test(ha_commit_trans(thd, TRUE));
+#ifdef WITH_MARIA_STORAGE_ENGINE
+    ha_maria::implicit_commit(thd, TRUE);
+#endif
+  }
+
+  thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+  thd->transaction.all.modified_non_trans_table= FALSE;
+
+  DBUG_RETURN(res);
+}
+
+
+/**
+  Rollback the current transaction, canceling its changes.
+
+  @param thd     Current thread
+
+  @retval FALSE  Success
+  @retval TRUE   Failure
+*/
+
+bool trans_rollback(THD *thd)
+{
+  int res;
+  DBUG_ENTER("trans_rollback");
+
+  if (trans_check(thd))
+    DBUG_RETURN(TRUE);
+
+  thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+  res= ha_rollback_trans(thd, TRUE);
+  thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+  thd->transaction.all.modified_non_trans_table= FALSE;
+  thd->lex->start_transaction_opt= 0;
+
+  DBUG_RETURN(test(res));
+}
+
+
+/**
+  Commit the single statement transaction.
+
+  @note Note that if the autocommit is on, then the following call
+        inside InnoDB will commit or rollback the whole transaction
+        (= the statement). The autocommit mechanism built into InnoDB
+        is based on counting locks, but if the user has used LOCK
+        TABLES then that mechanism does not know to do the commit.
+
+  @param thd     Current thread
+
+  @retval FALSE  Success
+  @retval TRUE   Failure
+*/
+
+bool trans_commit_stmt(THD *thd)
+{
+  DBUG_ENTER("trans_commit_stmt");
+  int res= FALSE;
+  if (thd->transaction.stmt.ha_list)
+    res= ha_commit_trans(thd, FALSE);
+  DBUG_RETURN(test(res));
+}
+
+
+/**
+  Rollback the single statement transaction.
+
+  @param thd     Current thread
+
+  @retval FALSE  Success
+  @retval TRUE   Failure
+*/
+bool trans_rollback_stmt(THD *thd)
+{
+  DBUG_ENTER("trans_rollback_stmt");
+
+  if (thd->transaction.stmt.ha_list)
+  {
+    thd->transaction_rollback_request= FALSE;
+    ha_rollback_trans(thd, FALSE);
+    if (thd->transaction_rollback_request && !thd->in_sub_stmt)
+      ha_rollback_trans(thd, TRUE);
+  }
+
+  DBUG_RETURN(FALSE);
+}
+
+/* Find a named savepoint in the current transaction. */
+static SAVEPOINT **
+find_savepoint(THD *thd, LEX_STRING name)
+{
+  SAVEPOINT **sv= &thd->transaction.savepoints;
+
+  while (*sv)
+  {
+    if (my_strnncoll(system_charset_info, (uchar *) name.str, name.length,
+                     (uchar *) (*sv)->name, (*sv)->length) == 0)
+      break;
+    sv= &(*sv)->prev;
+  }
+
+  return sv;
+}
+
+
+/**
+  Set a named transaction savepoint.
+
+  @param thd    Current thread
+  @param name   Savepoint name
+
+  @retval FALSE  Success
+  @retval TRUE   Failure
+*/
+
+bool trans_savepoint(THD *thd, LEX_STRING name)
+{
+  SAVEPOINT **sv, *newsv;
+  DBUG_ENTER("trans_savepoint");
+
+  if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ||
+        thd->in_sub_stmt) || !opt_using_transactions)
+    DBUG_RETURN(FALSE);
+
+  sv= find_savepoint(thd, name);
+
+  if (*sv) /* old savepoint of the same name exists */
+  {
+    newsv= *sv;
+    ha_release_savepoint(thd, *sv);
+    *sv= (*sv)->prev;
+  }
+  else if ((newsv= (SAVEPOINT *) alloc_root(&thd->transaction.mem_root,
+                                            savepoint_alloc_size)) == NULL)
+  {
+    my_error(ER_OUT_OF_RESOURCES, MYF(0));
+    DBUG_RETURN(TRUE);
+  }
+
+  newsv->name= strmake_root(&thd->transaction.mem_root, name.str, name.length);
+  newsv->length= name.length;
+
+  /*
+    if we'll get an error here, don't add new savepoint to the list.
+    we'll lose a little bit of memory in transaction mem_root, but it'll
+    be free'd when transaction ends anyway
+  */
+  if (ha_savepoint(thd, newsv))
+    DBUG_RETURN(TRUE);
+
+  newsv->prev= thd->transaction.savepoints;
+  thd->transaction.savepoints= newsv;
+
+  DBUG_RETURN(FALSE);
+}
+
+
+/**
+  Rollback a transaction to the named savepoint.
+
+  @note Modifications that the current transaction made to
+        rows after the savepoint was set are undone in the
+        rollback.
+
+  @note Savepoints that were set at a later time than the
+        named savepoint are deleted.
+
+  @param thd    Current thread
+  @param name   Savepoint name
+
+  @retval FALSE  Success
+  @retval TRUE   Failure
+*/
+
+bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name)
+{
+  int res= FALSE;
+  SAVEPOINT *sv= *find_savepoint(thd, name);
+  DBUG_ENTER("trans_rollback_to_savepoint");
+
+  if (sv == NULL)
+  {
+    my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", name.str);
+    DBUG_RETURN(TRUE);
+  }
+
+  if (ha_rollback_to_savepoint(thd, sv))
+    res= TRUE;
+  else if (((thd->options & OPTION_KEEP_LOG) ||
+            thd->transaction.all.modified_non_trans_table) &&
+           !thd->slave_thread)
+    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                 ER_WARNING_NOT_COMPLETE_ROLLBACK,
+                 ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
+
+  thd->transaction.savepoints= sv;
+
+  DBUG_RETURN(test(res));
+}
+
+
+/**
+  Remove the named savepoint from the set of savepoints of
+  the current transaction.
+
+  @note No commit or rollback occurs. It is an error if the
+        savepoint does not exist.
+
+  @param thd    Current thread
+  @param name   Savepoint name
+
+  @retval FALSE  Success
+  @retval TRUE   Failure
+*/
+
+bool trans_release_savepoint(THD *thd, LEX_STRING name)
+{
+  int res= FALSE;
+  SAVEPOINT *sv= *find_savepoint(thd, name);
+  DBUG_ENTER("trans_release_savepoint");
+
+  if (sv == NULL)
+  {
+    my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", name.str);
+    DBUG_RETURN(TRUE);
+  }
+
+  if (ha_release_savepoint(thd, sv))
+    res= TRUE;
+
+  thd->transaction.savepoints= sv->prev;
+
+  DBUG_RETURN(test(res));
+}
+
+
+/**
+  Starts an XA transaction with the given xid value.
+
+  @param thd    Current thread
+
+  @retval FALSE  Success
+  @retval TRUE   Failure
+*/
+
+bool trans_xa_start(THD *thd)
+{
+  enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+  DBUG_ENTER("trans_xa_start");
+
+  if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_RESUME)
+  {
+    bool not_equal= !thd->transaction.xid_state.xid.eq(thd->lex->xid);
+    if (not_equal)
+      my_error(ER_XAER_NOTA, MYF(0));
+    else
+      thd->transaction.xid_state.xa_state= XA_ACTIVE;
+    DBUG_RETURN(not_equal);
+  }
+
+  /* TODO: JOIN is not supported yet. */
+  if (thd->lex->xa_opt != XA_NONE)
+    my_error(ER_XAER_INVAL, MYF(0));
+  else if (xa_state != XA_NOTR)
+    my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+  else if (thd->locked_tables_mode || thd->active_transaction())
+    my_error(ER_XAER_OUTSIDE, MYF(0));
+  else if (xid_cache_search(thd->lex->xid))
+    my_error(ER_XAER_DUPID, MYF(0));
+  else if (!trans_begin(thd))
+  {
+    DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
+    thd->transaction.xid_state.xa_state= XA_ACTIVE;
+    thd->transaction.xid_state.xid.set(thd->lex->xid);
+    xid_cache_insert(&thd->transaction.xid_state);
+    DBUG_RETURN(FALSE);
+  }
+
+  DBUG_RETURN(TRUE);
+}
+
+
+/**
+  Put a XA transaction in the IDLE state.
+
+  @param thd    Current thread
+
+  @retval FALSE  Success
+  @retval TRUE   Failure
+*/
+
+bool trans_xa_end(THD *thd)
+{
+  DBUG_ENTER("trans_xa_end");
+
+  /* TODO: SUSPEND and FOR MIGRATE are not supported yet. */
+  if (thd->lex->xa_opt != XA_NONE)
+    my_error(ER_XAER_INVAL, MYF(0));
+  else if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
+    my_error(ER_XAER_RMFAIL, MYF(0),
+             xa_state_names[thd->transaction.xid_state.xa_state]);
+  else if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
+    my_error(ER_XAER_NOTA, MYF(0));
+  else
+    thd->transaction.xid_state.xa_state= XA_IDLE;
+
+  DBUG_RETURN(thd->transaction.xid_state.xa_state != XA_IDLE);
+}
+
+
+/**
+  Put a XA transaction in the PREPARED state.
+
+  @param thd    Current thread
+
+  @retval FALSE  Success
+  @retval TRUE   Failure
+*/
+
+bool trans_xa_prepare(THD *thd)
+{
+  DBUG_ENTER("trans_xa_prepare");
+
+  if (thd->transaction.xid_state.xa_state != XA_IDLE)
+    my_error(ER_XAER_RMFAIL, MYF(0),
+             xa_state_names[thd->transaction.xid_state.xa_state]);
+  else if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
+    my_error(ER_XAER_NOTA, MYF(0));
+  else if (ha_prepare(thd))
+  {
+    xid_cache_delete(&thd->transaction.xid_state);
+    thd->transaction.xid_state.xa_state= XA_NOTR;
+    my_error(ER_XA_RBROLLBACK, MYF(0));
+  }
+  else
+    thd->transaction.xid_state.xa_state= XA_PREPARED;
+
+  DBUG_RETURN(thd->transaction.xid_state.xa_state != XA_PREPARED);
+}
+
+
+/**
+  Commit and terminate the a XA transaction.
+
+  @param thd    Current thread
+
+  @retval FALSE  Success
+  @retval TRUE   Failure
+*/
+
+bool trans_xa_commit(THD *thd)
+{
+  bool res= TRUE;
+  enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+  DBUG_ENTER("trans_xa_commit");
+
+  if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
+  {
+    XID_STATE *xs= xid_cache_search(thd->lex->xid);
+    bool not_found= !xs || xs->in_thd;
+    if (not_found)
+      my_error(ER_XAER_NOTA, MYF(0));
+    else
+    {
+      ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
+      xid_cache_delete(xs);
+    }
+    DBUG_RETURN(not_found);
+  }
+
+  if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE)
+  {
+    int r= ha_commit_trans(thd, TRUE);
+    if ((res= test(r)))
+      my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
+  }
+  else if (xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE)
+  {
+    if (wait_if_global_read_lock(thd, 0, 0))
+    {
+      ha_rollback_trans(thd, TRUE);
+      my_error(ER_XAER_RMERR, MYF(0));
+    }
+    else
+    {
+      res= test(ha_commit_one_phase(thd, 1));
+      if (res)
+        my_error(ER_XAER_RMERR, MYF(0));
+      start_waiting_global_read_lock(thd);
+    }
+  }
+  else
+    my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+
+  thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+  thd->transaction.all.modified_non_trans_table= FALSE;
+  thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+  xid_cache_delete(&thd->transaction.xid_state);
+  thd->transaction.xid_state.xa_state= XA_NOTR;
+
+  DBUG_RETURN(res);
+}
+
+
+/**
+  Roll back and terminate a XA transaction.
+
+  @param thd    Current thread
+
+  @retval FALSE  Success
+  @retval TRUE   Failure
+*/
+
+bool trans_xa_rollback(THD *thd)
+{
+  bool res= TRUE;
+  enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+  DBUG_ENTER("trans_xa_rollback");
+
+  if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
+  {
+    XID_STATE *xs= xid_cache_search(thd->lex->xid);
+    bool not_found= !xs || xs->in_thd;
+    if (not_found)
+      my_error(ER_XAER_NOTA, MYF(0));
+    else
+    {
+      ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
+      xid_cache_delete(xs);
+    }
+    DBUG_RETURN(not_found);
+  }
+
+  if (xa_state != XA_IDLE && xa_state != XA_PREPARED)
+  {
+    my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+    DBUG_RETURN(TRUE);
+  }
+
+  if ((res= test(ha_rollback_trans(thd, TRUE))))
+    my_error(ER_XAER_RMERR, MYF(0));
+
+  thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+  thd->transaction.all.modified_non_trans_table= FALSE;
+  thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+  xid_cache_delete(&thd->transaction.xid_state);
+  thd->transaction.xid_state.xa_state= XA_NOTR;
+
+  DBUG_RETURN(res);
+}

=== added file 'sql/transaction.h'
--- a/sql/transaction.h	1970-01-01 00:00:00 +0000
+++ b/sql/transaction.h	2008-08-12 22:30:55 +0000
@@ -0,0 +1,46 @@
+/* Copyright (C) 2008 Sun/MySQL
+
+   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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface                      /* gcc class implementation */
+#endif
+
+#ifndef TRANSACTION_H
+#define TRANSACTION_H
+
+#include <my_global.h>
+#include <m_string.h>
+
+class THD;
+
+bool trans_begin(THD *thd, uint flags= 0);
+bool trans_commit(THD *thd);
+bool trans_commit_implicit(THD *thd);
+bool trans_rollback(THD *thd);
+
+bool trans_commit_stmt(THD *thd);
+bool trans_rollback_stmt(THD *thd);
+
+bool trans_savepoint(THD *thd, LEX_STRING name);
+bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name);
+bool trans_release_savepoint(THD *thd, LEX_STRING name);
+
+bool trans_xa_start(THD *thd);
+bool trans_xa_end(THD *thd);
+bool trans_xa_prepare(THD *thd);
+bool trans_xa_commit(THD *thd);
+bool trans_xa_rollback(THD *thd);
+
+#endif /* TRANSACTION_H */

=== modified file 'storage/falcon/BDB.cpp'
--- a/storage/falcon/BDB.cpp	2008-09-04 14:49:10 +0000
+++ b/storage/falcon/BDB.cpp	2008-09-18 16:41:34 +0000
@@ -135,7 +135,7 @@ void Bdb::release()
 	if (cache->panicShutdown)
 		{
 		Thread *thread = Thread::getThread("Cache::fetchPage");
-		
+
 		if (thread->pageMarks == 0)
 			throw SQLError(RUNTIME_ERROR, "Emergency shut is underway");
 		}

=== modified file 'storage/falcon/InfoTable.h'
--- a/storage/falcon/InfoTable.h	2008-08-07 12:58:45 +0000
+++ b/storage/falcon/InfoTable.h	2008-09-16 17:58:49 +0000
@@ -25,7 +25,7 @@ typedef long long INT64;
 class THD;
 struct charset_info_st;
 struct TABLE_LIST;
-struct st_table;
+struct TABLE;
 
 class InfoTable
 {
@@ -57,7 +57,7 @@ public:
     virtual void    setNotNull(int column);
     
     int             error;
-    st_table        *table;
+    TABLE          *table;
     THD             *mySqlThread;
     charset_info_st *charSetInfo;
 };

=== modified file 'storage/falcon/ha_falcon.cpp'
--- a/storage/falcon/ha_falcon.cpp	2008-09-11 16:28:29 +0000
+++ b/storage/falcon/ha_falcon.cpp	2008-09-16 17:58:49 +0000
@@ -414,7 +414,7 @@ typedef longlong      dec2;
 // Construction/Destruction
 //////////////////////////////////////////////////////////////////////
 
-StorageInterface::StorageInterface(handlerton *hton, st_table_share *table_arg)
+StorageInterface::StorageInterface(handlerton *hton, TABLE_SHARE *table_arg)
   : handler(hton, table_arg)
 {
 	ref_length = sizeof(lastRecord);
@@ -1051,7 +1051,7 @@ int StorageInterface::delete_all_rows()
 		DBUG_RETURN(my_errno=HA_ERR_WRONG_COMMAND);
 
 	int ret = 0;
-	struct st_table_share *tableShare = table_share;
+	TABLE_SHARE *tableShare = table_share;
 	const char *tableName = tableShare->normalized_path.str;
 	
 	if (!storageShare)

=== modified file 'storage/falcon/ha_falcon.h'
--- a/storage/falcon/ha_falcon.h	2008-09-09 23:15:17 +0000
+++ b/storage/falcon/ha_falcon.h	2008-09-16 17:58:49 +0000
@@ -28,14 +28,14 @@ static const int TRANSACTION_WRITE_COMMI
 static const int TRANSACTION_CONSISTENT_READ  = 8;	// Dirty reads and non-repeatable reads are prevented; phantom reads can occur.   
 static const int TRANSACTION_SERIALIZABLE     = 16;	// Dirty reads, non-repeatable reads and phantom reads are prevented.
 
-struct st_table_share;
+struct TABLE_SHARE;
 class StorageIndexDesc;
 struct StorageBlob;
 
 class StorageInterface : public handler
 {
 public:
-	StorageInterface(handlerton *, st_table_share *table_arg);
+	StorageInterface(handlerton *, TABLE_SHARE *table_arg);
 	~StorageInterface(void);
 
 	virtual int		open(const char *name, int mode, uint test_if_locked);
@@ -180,7 +180,7 @@ public:
 	const char*			errorText;
 	THR_LOCK_DATA		lockData;			// MySQL lock
 	THD					*mySqlThread;
-	st_table_share		*share;
+	TABLE_SHARE *share;
 	uint				recordLength;
 	int					lastRecord;
 	int					nextRecord;

=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc	2008-08-21 23:38:19 +0000
+++ b/storage/innobase/handler/ha_innodb.cc	2008-09-04 18:30:34 +0000
@@ -3650,7 +3650,7 @@ calc_row_difference(
 	upd_t*		uvect,		/* in/out: update vector */
 	uchar*		old_row,	/* in: old row in MySQL format */
 	uchar*		new_row,	/* in: new row in MySQL format */
-	struct st_table* table,		/* in: table in MySQL data
+	TABLE*          table,		/* in: table in MySQL data
 					dictionary */
 	uchar*		upd_buff,	/* in: buffer to use */
 	ulint		buff_len,	/* in: buffer length */

=== modified file 'storage/maria/ha_maria.cc'
--- a/storage/maria/ha_maria.cc	2008-08-25 18:34:43 +0000
+++ b/storage/maria/ha_maria.cc	2008-09-04 18:30:34 +0000
@@ -2319,8 +2319,8 @@ int ha_maria::start_stmt(THD *thd, thr_l
 
   This can be considered a hack. When Maria loses HA_NO_TRANSACTIONS it will
   be participant in the connection's transaction and so the implicit commits
-  (ha_commit()) (like in end_active_trans()) will do the implicit commit
-  without need to call this function which can then be removed.
+  (ha_commit_trans()) (like in trans_commit_implicit()) will do the implicit
+  commit without need to call this function which can then be removed.
 
   @param  thd              THD object
   @param  new_trn          if a new transaction should be created; a new

=== modified file 'tests/mysql_client_test.c'
--- a/tests/mysql_client_test.c	2008-08-22 11:16:08 +0000
+++ b/tests/mysql_client_test.c	2008-09-15 20:37:25 +0000
@@ -1500,6 +1500,544 @@ static void test_prepare_simple()
   myquery(rc);
 }
 
+/************************************************************************/
+
+#define FILE_PATH_SIZE 4096
+#define CMD_BUFFER_SIZE 8192
+
+char mct_log_file_path[FILE_PATH_SIZE];
+FILE *mct_log_file;
+
+void mct_start_logging(const char *test_case_name)
+{
+  const char *tmp_dir= getenv("MYSQL_TMP_DIR");
+
+  if (!tmp_dir)
+  {
+    printf("Warning: MYSQL_TMP_DIR is not set. Logging is disabled.\n");
+    return;
+  }
+
+  /*
+    Path is: <tmp_dir>/<test_case_name>.out.log
+    10 is length of '/' + '.out.log' + \0
+  */
+
+  if (strlen(tmp_dir) + strlen(test_case_name) + 10 > FILE_PATH_SIZE)
+  {
+    printf("Warning: MYSQL_TMP_DIR is too long. Logging is disabled.\n");
+    return;
+  }
+
+  my_snprintf(mct_log_file_path, FILE_PATH_SIZE,
+              "%s/%s.out.log",
+              (const char *) tmp_dir,
+              (const char *) test_case_name);
+
+  mct_log_file= my_fopen(mct_log_file_path, O_WRONLY | O_BINARY, MYF(MY_WME));
+
+  if (!mct_log_file)
+  {
+    printf("Warning: can not open log file (%s): %s. Logging is disabled.\n",
+        (const char *) mct_log_file_path,
+        (const char *) strerror(errno));
+    return;
+  }
+}
+
+void mct_log(const char *format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  vprintf(format, args);
+  va_end(args);
+
+  if (mct_log_file)
+  {
+    va_list args;
+    va_start(args, format);
+    vfprintf(mct_log_file, format, args);
+    va_end(args);
+  }
+}
+
+int mct_check_result(const char *result_file_name)
+{
+  char diff_cmd[CMD_BUFFER_SIZE];
+
+  const char *test_dir= getenv("MYSQL_TEST_DIR");
+  char result_file_path[FILE_PATH_SIZE];
+
+  if (!mct_log_file)
+  {
+    printf("Warning: logging was disabled. Result checking is impossible.\n");
+    return 0;
+  }
+
+  if (!test_dir)
+  {
+    printf("Warning: MYSQL_TEST_DIR is not set. "
+           "Result checking is impossible.\n");
+    return 0;
+  }
+
+  /*
+    Path is: <test_dir>/<result_file_name>
+    2 is length of '/' + \0
+  */
+
+  if (strlen(test_dir) + strlen(result_file_name) + 2 > FILE_PATH_SIZE)
+  {
+    printf("Warning: MYSQL_TEST_DIR is too long. "
+           "Result checking is impossible.\n");
+    return 0;
+  }
+
+  my_snprintf(result_file_path, FILE_PATH_SIZE,
+              "%s/%s",
+              (const char *) test_dir,
+              (const char *) result_file_name);
+
+  my_fclose(mct_log_file, MYF(0));
+  mct_log_file= NULL;
+
+  my_snprintf(diff_cmd, CMD_BUFFER_SIZE, "diff -u '%s' '%s'",
+              (const char *) result_file_path,
+              (const char *) mct_log_file_path);
+
+  puts("");
+  fflush(stdout);
+  fflush(stderr);
+
+  return system(diff_cmd);
+}
+
+#define WL4435_NUM_PARAMS 10
+#define WL4435_STRING_SIZE 30
+
+static void test_wl4435()
+{
+  MYSQL_STMT *stmt;
+  int        rc;
+  char query[MAX_TEST_QUERY_LENGTH];
+
+  char       str_data[20][WL4435_STRING_SIZE];
+  double     dbl_data[20];
+  char       dec_data[20][WL4435_STRING_SIZE];
+  int        int_data[20];
+  ulong      str_length= WL4435_STRING_SIZE;
+  my_bool    is_null;
+  MYSQL_BIND ps_params[WL4435_NUM_PARAMS];
+
+  int exec_counter;
+
+  myheader("test_wl4435");
+  mct_start_logging("test_wl4435");
+
+  rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
+  myquery(rc);
+
+  rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p2");
+  myquery(rc);
+
+  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+  myquery(rc);
+
+  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t2");
+  myquery(rc);
+
+  rc= mysql_query(mysql, "CREATE TABLE t1(a1 INT, a2 CHAR(32), "
+                       "  a3 DOUBLE(4, 2), a4 DECIMAL(3, 1))");
+  myquery(rc);
+
+  rc= mysql_query(mysql, "CREATE TABLE t2(b0 INT, b1 INT, b2 CHAR(32), "
+                       "  b3 DOUBLE(4, 2), b4 DECIMAL(3, 1))");
+  myquery(rc);
+
+  rc= mysql_query(mysql, "INSERT INTO t1 VALUES"
+    "(1, '11', 12.34, 56.7), "
+    "(2, '12', 56.78, 90.1), "
+    "(3, '13', 23.45, 67.8)");
+  myquery(rc);
+
+  rc= mysql_query(mysql, "INSERT INTO t2 VALUES"
+    "(100, 10, '110', 70.70, 10.1), "
+    "(200, 20, '120', 80.80, 20.2), "
+    "(300, 30, '130', 90.90, 30.3)");
+  myquery(rc);
+
+  rc= mysql_query(mysql,
+    "CREATE PROCEDURE p1("
+    "   IN v0 INT, "
+    "   OUT v_str_1 CHAR(32), "
+    "   OUT v_dbl_1 DOUBLE(4, 2), "
+    "   OUT v_dec_1 DECIMAL(6, 3), "
+    "   OUT v_int_1 INT, "
+    "   IN v1 INT, "
+    "   INOUT v_str_2 CHAR(64), "
+    "   INOUT v_dbl_2 DOUBLE(5, 3), "
+    "   INOUT v_dec_2 DECIMAL(7, 4), "
+    "   INOUT v_int_2 INT)"
+    "BEGIN "
+    "   SET v0 = -1; "
+    "   SET v1 = -1; "
+    "   SET v_str_1 = 'test_1'; "
+    "   SET v_dbl_1 = 12.34; "
+    "   SET v_dec_1 = 567.891; "
+    "   SET v_int_1 = 2345; "
+    "   SET v_str_2 = 'test_2'; "
+    "   SET v_dbl_2 = 67.891; "
+    "   SET v_dec_2 = 234.6789; "
+    "   SET v_int_2 = 6789; "
+    "   SELECT * FROM t1; "
+    "   SELECT * FROM t2; "
+    "END");
+  myquery(rc);
+
+  rc= mysql_query(mysql,
+    "CREATE PROCEDURE p2("
+    "   IN i1 VARCHAR(255) CHARACTER SET koi8r, "
+    "   OUT o1 VARCHAR(255) CHARACTER SET cp1251, "
+    "   OUT o2 VARBINARY(255)) "
+    "BEGIN "
+    "   SET o1 = i1; "
+    "   SET o2 = i1; "
+    "END");
+  myquery(rc);
+
+  strmov(query, "CALL p1(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
+  stmt= mysql_simple_prepare(mysql, query);
+  check_stmt(stmt);
+
+  /* Init PS-parameters. */
+
+  bzero((char *) ps_params, sizeof (ps_params));
+
+  /* - v0 -- INT */
+
+  ps_params[0].buffer_type= MYSQL_TYPE_LONG;
+  ps_params[0].buffer= (char *) &int_data[0];
+  ps_params[0].length= 0;
+  ps_params[0].is_null= 0;
+
+  /* - v_str_1 -- CHAR(32) */
+
+  ps_params[1].buffer_type= MYSQL_TYPE_STRING;
+  ps_params[1].buffer= (char *) str_data[0];
+  ps_params[1].buffer_length= WL4435_STRING_SIZE;
+  ps_params[1].length= &str_length;
+  ps_params[1].is_null= 0;
+
+  /* - v_dbl_1 -- DOUBLE */
+
+  ps_params[2].buffer_type= MYSQL_TYPE_DOUBLE;
+  ps_params[2].buffer= (char *) &dbl_data[0];
+  ps_params[2].length= 0;
+  ps_params[2].is_null= 0;
+
+  /* - v_dec_1 -- DECIMAL */
+
+  ps_params[3].buffer_type= MYSQL_TYPE_NEWDECIMAL;
+  ps_params[3].buffer= (char *) dec_data[0];
+  ps_params[3].buffer_length= WL4435_STRING_SIZE;
+  ps_params[3].length= 0;
+  ps_params[3].is_null= 0;
+
+  /* - v_int_1 -- INT */
+
+  ps_params[4].buffer_type= MYSQL_TYPE_LONG;
+  ps_params[4].buffer= (char *) &int_data[0];
+  ps_params[4].length= 0;
+  ps_params[4].is_null= 0;
+
+  /* - v1 -- INT */
+
+  ps_params[5].buffer_type= MYSQL_TYPE_LONG;
+  ps_params[5].buffer= (char *) &int_data[0];
+  ps_params[5].length= 0;
+  ps_params[5].is_null= 0;
+
+  /* - v_str_2 -- CHAR(32) */
+
+  ps_params[6].buffer_type= MYSQL_TYPE_STRING;
+  ps_params[6].buffer= (char *) str_data[0];
+  ps_params[6].buffer_length= WL4435_STRING_SIZE;
+  ps_params[6].length= &str_length;
+  ps_params[6].is_null= 0;
+
+  /* - v_dbl_2 -- DOUBLE */
+
+  ps_params[7].buffer_type= MYSQL_TYPE_DOUBLE;
+  ps_params[7].buffer= (char *) &dbl_data[0];
+  ps_params[7].length= 0;
+  ps_params[7].is_null= 0;
+
+  /* - v_dec_2 -- DECIMAL */
+
+  ps_params[8].buffer_type= MYSQL_TYPE_DECIMAL;
+  ps_params[8].buffer= (char *) dec_data[0];
+  ps_params[8].buffer_length= WL4435_STRING_SIZE;
+  ps_params[8].length= 0;
+  ps_params[8].is_null= 0;
+
+  /* - v_int_2 -- INT */
+
+  ps_params[9].buffer_type= MYSQL_TYPE_LONG;
+  ps_params[9].buffer= (char *) &int_data[0];
+  ps_params[9].length= 0;
+  ps_params[9].is_null= 0;
+
+  /* Bind parameters. */
+
+  rc= mysql_stmt_bind_param(stmt, ps_params);
+
+  /* Execute! */
+
+  for (exec_counter= 0; exec_counter < 3; ++exec_counter)
+  {
+    int i;
+    int num_fields;
+    MYSQL_BIND *rs_bind;
+
+    mct_log("\nexec_counter: %d\n", (int) exec_counter);
+
+    rc= mysql_stmt_execute(stmt);
+    check_execute(stmt, rc);
+
+    while (1)
+    {
+      MYSQL_FIELD *fields;
+
+      MYSQL_RES *rs_metadata= mysql_stmt_result_metadata(stmt);
+
+      num_fields= mysql_num_fields(rs_metadata);
+      fields= mysql_fetch_fields(rs_metadata);
+
+      rs_bind= (MYSQL_BIND *) malloc(sizeof (MYSQL_BIND) * num_fields);
+      bzero(rs_bind, sizeof (MYSQL_BIND) * num_fields);
+
+      mct_log("num_fields: %d\n", (int) num_fields);
+
+      for (i = 0; i < num_fields; ++i)
+      {
+        mct_log("  - %d: name: '%s'/'%s'; table: '%s'/'%s'; "
+                   "db: '%s'; catalog: '%s'; length: %d; max_length: %d; "
+                   "type: %d; decimals: %d\n",
+                   (int) i,
+                   (const char *) fields[i].name,
+                   (const char *) fields[i].org_name,
+                   (const char *) fields[i].table,
+                   (const char *) fields[i].org_table,
+                   (const char *) fields[i].db,
+                   (const char *) fields[i].catalog,
+                   (int) fields[i].length,
+                   (int) fields[i].max_length,
+                   (int) fields[i].type,
+                   (int) fields[i].decimals);
+
+        rs_bind[i].buffer_type= fields[i].type;
+        rs_bind[i].is_null= &is_null;
+
+        switch (fields[i].type)
+        {
+          case MYSQL_TYPE_LONG:
+            rs_bind[i].buffer= (char *) &(int_data[i]);
+            rs_bind[i].buffer_length= sizeof (int_data);
+            break;
+
+          case MYSQL_TYPE_STRING:
+            rs_bind[i].buffer= (char *) str_data[i];
+            rs_bind[i].buffer_length= WL4435_STRING_SIZE;
+            rs_bind[i].length= &str_length;
+            break;
+
+          case MYSQL_TYPE_DOUBLE:
+            rs_bind[i].buffer= (char *) &dbl_data[i];
+            rs_bind[i].buffer_length= sizeof (dbl_data);
+            break;
+
+          case MYSQL_TYPE_NEWDECIMAL:
+            rs_bind[i].buffer= (char *) dec_data[i];
+            rs_bind[i].buffer_length= WL4435_STRING_SIZE;
+            rs_bind[i].length= &str_length;
+            break;
+
+          default:
+            fprintf(stderr, "ERROR: unexpected type: %d.\n", fields[i].type);
+            exit(1);
+        }
+      }
+
+      rc= mysql_stmt_bind_result(stmt, rs_bind);
+      check_execute(stmt, rc);
+
+      mct_log("Data:\n");
+
+      while (1)
+      {
+        int rc= mysql_stmt_fetch(stmt);
+
+        if (rc == 1 || rc == MYSQL_NO_DATA)
+          break;
+
+        mct_log(" ");
+
+        for (i = 0; i < num_fields; ++i)
+        {
+          switch (rs_bind[i].buffer_type)
+          {
+            case MYSQL_TYPE_LONG:
+              mct_log(" int: %ld;",
+                         (long) *((int *) rs_bind[i].buffer));
+              break;
+
+            case MYSQL_TYPE_STRING:
+              mct_log(" str: '%s';",
+                         (char *) rs_bind[i].buffer);
+              break;
+
+            case MYSQL_TYPE_DOUBLE:
+              mct_log(" dbl: %lf;",
+                         (double) *((double *) rs_bind[i].buffer));
+              break;
+
+            case MYSQL_TYPE_NEWDECIMAL:
+              mct_log(" dec: '%s';",
+                         (char *) rs_bind[i].buffer);
+              break;
+
+            default:
+              printf("  unexpected type (%d)\n",
+                rs_bind[i].buffer_type);
+          }
+        }
+        mct_log("\n");
+      }
+
+      mct_log("EOF\n");
+
+      rc= mysql_stmt_next_result(stmt);
+      mct_log("mysql_stmt_next_result(): %d; field_count: %d\n",
+              (int) rc, (int) mysql->field_count);
+
+      free(rs_bind);
+      mysql_free_result(rs_metadata);
+
+      if (rc > 0)
+      {
+        printf("Error: %s (errno: %d)\n",
+               mysql_error(mysql), mysql_errno(mysql));
+        DIE(rc > 0);
+      }
+
+      if (rc)
+        break;
+
+      if (!mysql->field_count)
+      {
+        /* This is the last OK-packet. No more resultsets. */
+        break;
+      }
+    }
+
+  }
+
+  mysql_stmt_close(stmt);
+
+  rc= mysql_commit(mysql);
+  myquery(rc);
+
+  rc= mct_check_result("r/test_wl4435.result");
+  mytest_r(rc);
+
+  /* i18n part of test case. */
+
+  {
+    const char *str_koi8r= "\xee\xd5\x2c\x20\xda\xc1\x20\xd2\xd9\xc2\xc1\xcc\xcb\xd5";
+    const char *str_cp1251= "\xcd\xf3\x2c\x20\xe7\xe0\x20\xf0\xfb\xe1\xe0\xeb\xea\xf3";
+    char o1_buffer[255];
+    ulong o1_length;
+    char o2_buffer[255];
+    ulong o2_length;
+
+    MYSQL_BIND rs_bind[2];
+
+    strmov(query, "CALL p2(?, ?, ?)");
+    stmt= mysql_simple_prepare(mysql, query);
+    check_stmt(stmt);
+
+    /* Init PS-parameters. */
+
+    bzero((char *) ps_params, sizeof (ps_params));
+
+    ps_params[0].buffer_type= MYSQL_TYPE_STRING;
+    ps_params[0].buffer= (char *) str_koi8r;
+    ps_params[0].buffer_length= strlen(str_koi8r);
+
+    ps_params[1].buffer_type= MYSQL_TYPE_STRING;
+    ps_params[1].buffer= o1_buffer;
+    ps_params[1].buffer_length= 0;
+
+    ps_params[2].buffer_type= MYSQL_TYPE_STRING;
+    ps_params[2].buffer= o2_buffer;
+    ps_params[2].buffer_length= 0;
+
+    /* Bind parameters. */
+
+    rc= mysql_stmt_bind_param(stmt, ps_params);
+    check_execute(stmt, rc);
+
+    /* Prevent converting to character_set_results. */
+
+    rc= mysql_query(mysql, "SET NAMES binary");
+    myquery(rc);
+
+    /* Execute statement. */
+
+    rc= mysql_stmt_execute(stmt);
+    check_execute(stmt, rc);
+
+    /* Bind result. */
+
+    bzero(rs_bind, sizeof (rs_bind));
+
+    rs_bind[0].buffer_type= MYSQL_TYPE_STRING;
+    rs_bind[0].buffer= o1_buffer;
+    rs_bind[0].buffer_length= sizeof (o1_buffer);
+    rs_bind[0].length= &o1_length;
+
+    rs_bind[1].buffer_type= MYSQL_TYPE_BLOB;
+    rs_bind[1].buffer= o2_buffer;
+    rs_bind[1].buffer_length= sizeof (o2_buffer);
+    rs_bind[1].length= &o2_length;
+
+    rc= mysql_stmt_bind_result(stmt, rs_bind);
+    check_execute(stmt, rc);
+
+    /* Fetch result. */
+
+    rc= mysql_stmt_fetch(stmt);
+    check_execute(stmt, rc);
+
+    /* Check result. */
+
+    DIE_UNLESS(o1_length == strlen(str_cp1251));
+    DIE_UNLESS(o2_length == strlen(str_koi8r));
+    DIE_UNLESS(!memcmp(o1_buffer, str_cp1251, o1_length));
+    DIE_UNLESS(!memcmp(o2_buffer, str_koi8r, o2_length));
+
+    rc= mysql_stmt_fetch(stmt);
+    DIE_UNLESS(rc == MYSQL_NO_DATA);
+
+    rc= mysql_stmt_next_result(stmt);
+    DIE_UNLESS(rc == 0 && mysql->field_count == 0);
+
+    mysql_stmt_close(stmt);
+
+    rc= mysql_commit(mysql);
+    myquery(rc);
+  }
+}
 
 /* Test simple prepare field results */
 
@@ -14495,9 +15033,8 @@ static void test_bug12001()
 
   /* Create connection that supports multi statements */
   if (!mysql_real_connect(mysql_local, opt_host, opt_user,
-                           opt_password, current_db, opt_port,
-                           opt_unix_socket, CLIENT_MULTI_STATEMENTS |
-                           CLIENT_MULTI_RESULTS))
+                          opt_password, current_db, opt_port,
+                          opt_unix_socket, CLIENT_MULTI_STATEMENTS))
   {
     fprintf(stdout, "\n mysql_real_connect() failed");
     exit(1);
@@ -15869,7 +16406,7 @@ static void test_bug15752()
   if (! mysql_real_connect(&mysql_local, opt_host, opt_user,
                            opt_password, current_db, opt_port,
                            opt_unix_socket,
-                           CLIENT_MULTI_STATEMENTS|CLIENT_MULTI_RESULTS))
+                           CLIENT_MULTI_STATEMENTS))
   {
     printf("Unable connect to MySQL server: %s\n", mysql_error(&mysql_local));
     DIE_UNLESS(0);
@@ -17831,6 +18368,7 @@ static void test_bug36004()
 
   query_int_variable(mysql, "@@warning_count", &warning_count);
   DIE_UNLESS(warning_count == 0);
+  mysql_stmt_close(stmt);
 
   DBUG_VOID_RETURN;
 }
@@ -18230,6 +18768,7 @@ static struct my_tests_st my_tests[]= {
   { "test_wl4166_4", test_wl4166_4 },
   { "test_bug36004", test_bug36004 },
   { "test_wl4284_1", test_wl4284_1 },
+  { "test_wl4435",   test_wl4435 },
   { "test_bug38486", test_bug38486 },
   { 0, 0 }
 };

Thread
bzr commit into mysql-6.0-falcon branch (hky:2828) Hakan Kuecuekyilmaz20 Sep