From 94e926acdf13fba15c0a1cfe19ea195093e71324 Mon Sep 17 00:00:00 2001
From: "heikki@hundin.mysql.fi" <>
Date: Sat, 22 Jun 2002 20:05:30 +0300
Subject: [PATCH] log.cc, handler.cc:   Add BEGIN andd COMMIT around
 transactions in the binlog

---
 sql/handler.cc | 31 +++++++++++++++++++++++++++++++
 sql/log.cc     | 40 ++++++++++++++++++++++++++++++++++++----
 2 files changed, 67 insertions(+), 4 deletions(-)

diff --git a/sql/handler.cc b/sql/handler.cc
index 098c3130de..564d91aa88 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -251,6 +251,7 @@ int ha_autocommit_or_rollback(THD *thd, int error)
     }
     else
       (void) ha_rollback_stmt(thd);
+      
     thd->tx_isolation=thd->session_tx_isolation;
   }
 #endif
@@ -309,6 +310,36 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
     if (trans == &thd->transaction.all && mysql_bin_log.is_open() &&
 	my_b_tell(&thd->transaction.trans_log))
     {
+      /* We write the command "COMMIT" as the last SQL command in the
+      binlog segment cached for this transaction */
+
+      int save_query_length = thd->query_length;
+
+      thd->query_length = 6; /* length of 'COMMIT'; note that we may come
+      				here because a DROP TABLE, for instance,
+      				makes an implicit commit, and then
+      				thd->query is not 'COMMIT'! */
+      
+      Query_log_event qinfo(thd, "COMMIT", TRUE);
+
+      /* When we come here, and the user wrapped the transaction into
+      BEGIN and COMMIT, then qinfo got above the field cache_stmt
+      erroneously set to 0. Let us set it to 1: */
+
+      qinfo.cache_stmt = 1;
+
+      /* Write the 'COMMIT' entry to the cache */
+
+      if (mysql_bin_log.write(&qinfo)) {
+	  my_error(ER_ERROR_DURING_COMMIT, MYF(0), 5000);
+	  error=1;
+      }
+
+      thd->query_length = save_query_length;
+      
+      /* Now we write the binlog segment cached for this transaction to
+      the real binlog */
+      
       mysql_bin_log.write(thd, &thd->transaction.trans_log);
       reinit_io_cache(&thd->transaction.trans_log,
 		      WRITE_CACHE, (my_off_t) 0, 0, 1);
diff --git a/sql/log.cc b/sql/log.cc
index f4284ac6ba..ee5818fc59 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -442,8 +442,8 @@ int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
 #ifdef HAVE_FTRUNCATE
   if (ftruncate(index_file,0))
   {
-    sql_print_error("Could not truncate the binlog index file \
-during log purge for write");
+    sql_print_error(
+"Could not truncate the binlog index file during log purge for write");
     error = LOG_INFO_FATAL;
     goto err;
   }
@@ -455,8 +455,8 @@ during log purge for write");
 			    O_CREAT | O_BINARY | O_RDWR | O_APPEND,
 			    MYF(MY_WME))))
   {
-    sql_print_error("Could not re-open the binlog index file \
-during log purge for write");
+    sql_print_error(
+"Could not re-open the binlog index file during log purge for write");
     error = LOG_INFO_FATAL;
     goto err;
   }
@@ -661,6 +661,38 @@ bool MYSQL_LOG::write(Query_log_event* event_info)
 
     error=1;
 
+    if (file == &thd->transaction.trans_log
+        && !my_b_tell(&thd->transaction.trans_log)) {
+
+      /* Add the "BEGIN" and "COMMIT" in the binlog around transactions
+      which may contain more than 1 SQL statement. If we run with
+      AUTOCOMMIT=1, then MySQL immediately writes each SQL statement to
+      the binlog when the statement has been completed. No need to add
+      "BEGIN" ... "COMMIT" around such statements. Otherwise, MySQL uses
+      thd->transaction.trans_log to cache the SQL statements until the
+      explicit commit, and at the commit writes the contents in .trans_log
+      to the binlog.
+
+      We write the "BEGIN" mark first in the buffer (.trans_log) where we
+      store the SQL statements for a transaction. At the transaction commit
+      we will add the "COMMIT mark and write the buffer to the binlog.
+      The function my_b_tell above returns != 0 if there already is data
+      in the buffer. */
+
+      int save_query_length = thd->query_length;
+
+      thd->query_length = 5; /* length of string BEGIN */
+
+      Query_log_event qinfo(thd, "BEGIN", TRUE);
+      
+      error = ((&qinfo)->write(file));
+
+      thd->query_length = save_query_length;
+      
+      if (error)
+        goto err;
+    }
+    
     if (thd->last_insert_id_used)
     {
       Intvar_log_event e((uchar)LAST_INSERT_ID_EVENT, thd->last_insert_id);
-- 
2.30.9