List:Internals« Previous MessageNext Message »
From:Mats Kindahl Date:March 22 2005 7:44am
Subject:bk commit into 5.1 tree (mats:1.1797)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of mats. When mats does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.1797 05/03/22 08:44:16 mats@stripped +38 -0
  Merge with main 5.1 branch.

  sql/sql_select.cc
    1.302 05/03/22 08:44:12 mats@stripped +0 -0
    Merge with main 5.1 branch.

  sql/log_event.h
    1.107 05/03/22 08:44:12 mats@stripped +8 -8
    Merge with main 5.1 branch.

  sql/log_event.cc
    1.168 05/03/22 08:44:12 mats@stripped +11 -11
    Merge with main 5.1 branch.

  sql/item_sum.cc
    1.131 05/03/22 08:44:12 mats@stripped +0 -0
    Merge with main 5.1 branch.

  mysql-test/t/user_var.test
    1.24 05/03/22 08:44:12 mats@stripped +1 -2
    Merge with main 5.1 branch.

  mysql-test/t/rpl_user_variables.test
    1.12 05/03/22 08:44:12 mats@stripped +1 -2
    Merge with main 5.1 branch.

  mysql-test/t/rpl_until.test
    1.15 05/03/22 08:44:12 mats@stripped +3 -6
    Merge with main 5.1 branch.

  mysql-test/t/rpl_multi_query.test
    1.6 05/03/22 08:44:12 mats@stripped +1 -2
    Merge with main 5.1 branch.

  mysql-test/t/rpl_log_pos.test
    1.34 05/03/22 08:44:12 mats@stripped +1 -2
    Merge with main 5.1 branch.

  mysql-test/t/rpl_log.test
    1.26 05/03/22 08:44:12 mats@stripped +3 -6
    Merge with main 5.1 branch.

  mysql-test/t/rpl_loaddata_rule_s.test
    1.7 05/03/22 08:44:12 mats@stripped +1 -2
    Merge with main 5.1 branch.

  mysql-test/t/rpl_loaddata_rule_m.test
    1.9 05/03/22 08:44:12 mats@stripped +1 -2
    Merge with main 5.1 branch.

  mysql-test/t/rpl_error_ignored_table.test
    1.14 05/03/22 08:44:12 mats@stripped +1 -2
    Merge with main 5.1 branch.

  mysql-test/t/rpl_deadlock.test
    1.4 05/03/22 08:44:12 mats@stripped +2 -4
    Merge with main 5.1 branch.

  mysql-test/t/rpl_charset.test
    1.16 05/03/22 08:44:12 mats@stripped +1 -2
    Merge with main 5.1 branch.

  mysql-test/t/mysqlbinlog2.test
    1.5 05/03/22 08:44:12 mats@stripped +8 -16
    Merge with main 5.1 branch.

  mysql-test/t/mysqlbinlog.test
    1.16 05/03/22 08:44:12 mats@stripped +2 -4
    Merge with main 5.1 branch.

  mysql-test/t/mix_innodb_myisam_binlog.test
    1.14 05/03/22 08:44:12 mats@stripped +12 -24
    Merge with main 5.1 branch.

  mysql-test/t/ctype_ucs.test
    1.27 05/03/22 08:44:12 mats@stripped +1 -2
    Merge with main 5.1 branch.

  mysql-test/t/binlog.test
    1.5 05/03/22 08:44:12 mats@stripped +3 -6
    Merge with main 5.1 branch.

  sql/sql_update.cc
    1.151 05/03/22 08:25:38 mats@stripped +0 -0
    Auto merged

  sql/sql_udf.cc
    1.44 05/03/22 08:25:37 mats@stripped +0 -0
    Auto merged

  sql/sql_table.cc
    1.227 05/03/22 08:25:37 mats@stripped +0 -0
    Auto merged

  sql/sql_show.cc
    1.224 05/03/22 08:25:37 mats@stripped +0 -0
    Auto merged

  sql/sql_insert.cc
    1.145 05/03/22 08:25:36 mats@stripped +0 -0
    Auto merged

  sql/sql_delete.cc
    1.143 05/03/22 08:25:36 mats@stripped +0 -0
    Auto merged

  sql/sql_class.h
    1.227 05/03/22 08:25:36 mats@stripped +0 -0
    Auto merged

  sql/sql_class.cc
    1.172 05/03/22 08:25:36 mats@stripped +0 -0
    Auto merged

  sql/sql_acl.cc
    1.133 05/03/22 08:25:36 mats@stripped +0 -0
    Auto merged

  sql/sp.cc
    1.72 05/03/22 08:25:36 mats@stripped +0 -0
    Auto merged

  sql/slave.cc
    1.242 05/03/22 08:25:36 mats@stripped +0 -0
    Auto merged

  sql/mysqld.cc
    1.443 05/03/22 08:25:36 mats@stripped +0 -0
    Auto merged

  sql/mysql_priv.h
    1.280 05/03/22 08:25:35 mats@stripped +0 -0
    Auto merged

  sql/log.cc
    1.157 05/03/22 08:25:35 mats@stripped +0 -0
    Auto merged

  sql/handler.h
    1.131 05/03/22 08:25:35 mats@stripped +0 -0
    Auto merged

  sql/handler.cc
    1.149 05/03/22 08:25:35 mats@stripped +0 -0
    Auto merged

  sql/Makefile.am
    1.105 05/03/22 08:25:35 mats@stripped +0 -0
    Auto merged

  mysql-test/r/mysqlbinlog.result
    1.17 05/03/22 08:25:32 mats@stripped +0 -0
    Auto merged

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	mats
# Host:	romeo.kindahl.net
# Root:	/home/bk/w1012-mysql-5.1/RESYNC

--- 1.104/sql/Makefile.am	2005-03-21 19:24:55 +01:00
+++ 1.105/sql/Makefile.am	2005-03-22 08:25:35 +01:00
@@ -19,7 +19,7 @@
 MYSQLDATAdir =		$(localstatedir)
 MYSQLSHAREdir =		$(pkgdatadir)
 MYSQLBASEdir=		$(prefix)
-INCLUDES =		@MT_INCLUDES@ @ZLIB_INCLUDES@ \
+INCLUDES =		@ZLIB_INCLUDES@ \
 			@bdb_includes@ @innodb_includes@ @ndbcluster_includes@ \
 			-I$(top_srcdir)/include -I$(top_srcdir)/regex \
 			-I$(srcdir) $(openssl_includes) -I$(top_builddir)/include

--- 1.148/sql/handler.cc	2005-03-17 08:46:33 +01:00
+++ 1.149/sql/handler.cc	2005-03-22 08:25:35 +01:00
@@ -25,6 +25,7 @@
 #include "ha_heap.h"
 #include "ha_myisam.h"
 #include "ha_myisammrg.h"
+#include "bitvector.h"
 #ifdef HAVE_ISAM
 #include "ha_isam.h"
 #include "ha_isammrg.h"
@@ -2384,4 +2385,313 @@
     *ext= 0;
   }
   return &known_extensions;
+}
+
+int handler::
+ha_write_row(byte *buf) 
+{
+  DBUG_ENTER("ha_write_row");
+  DBUG_PRINT("enter", ("row: 0x%0x", buf));
+#ifndef DBUG_OFF
+  THD* thd = current_thd;
+  DBUG_PRINT("info", ("thd->query_id=%lu", thd->query_id));
+  for (size_t i = 0 ; i < table->s->fields ; ++i) 
+  {
+    DBUG_PRINT("info", ("Field '%s': query_id=%lu, offset=%d, ptr=%p",
+			table->field[i]->field_name,
+			table->field[i]->query_id,
+			table->field[i]->offset(),
+			table->field[i]->ptr));
+  }
+#endif
+  if (int error = write_row(buf)) {
+    DBUG_PRINT("exit", ("error = %d", error));
+    DBUG_RETURN(error);
+  }
+  bitvector const bv(table->s->fields, true);
+  m_row_writer.write_row(bv, buf);
+  DBUG_PRINT("exit", ("error = %d", 0));
+  DBUG_RETURN(0);
+}
+  
+int handler::
+ha_update_row(const byte *old_data, byte *new_data) 
+{
+  DBUG_ENTER("ha_update_row");
+  DBUG_PRINT("enter", ("before: 0x%0x; after: 0x%0x", old_data, new_data));
+#ifndef DBUG_OFF
+  THD* thd = current_thd;
+  DBUG_PRINT("info", ("thd->query_id=%lu", thd->query_id));
+  for (size_t i = 0 ; i < table->s->fields ; ++i) 
+  {
+    DBUG_PRINT("info", ("Field '%s': query_id=%lu, offset=%d, ptr=%p",
+			table->field[i]->field_name,
+			table->field[i]->query_id,
+			table->field[i]->offset(),
+			table->field[i]->ptr));
+  }
+#endif
+  if (int error = update_row(old_data, new_data)) {
+    DBUG_PRINT("exit", ("error = %d", error));
+    DBUG_RETURN(error);
+  }
+  bitvector const cols(table->s->fields, true);
+  m_row_writer.update_row(cols, old_data, new_data);
+  DBUG_PRINT("exit", ("error = %d", 0));
+  DBUG_RETURN(0);
+}
+  
+int handler::
+ha_delete_row(const byte *buf) 
+{
+  DBUG_ENTER("ha_delete_row");
+  DBUG_PRINT("enter", ("row: 0x%0x", buf));
+#ifndef DBUG_OFF
+  THD* thd = current_thd;
+  DBUG_PRINT("info", ("thd->query_id=%lu", thd->query_id));
+  for (size_t i = 0 ; i < table->s->fields ; ++i) 
+  {
+    DBUG_PRINT("info", ("Field '%s': query_id=%lu, offset=%d, ptr=%p",
+			table->field[i]->field_name,
+			table->field[i]->query_id,
+			table->field[i]->offset(),
+			table->field[i]->ptr));
+  }
+#endif
+  if (int error = delete_row(buf)) {
+    DBUG_PRINT("exit", ("error = %d", error));
+    DBUG_RETURN(error);
+  }
+  bitvector const cols(table->s->fields, true);
+  m_row_writer.delete_row(cols, buf);
+  DBUG_PRINT("exit", ("error = %d", 0));
+  DBUG_RETURN(0);
+}    
+  
+int handler::
+ha_stmt_begin() 
+{ 
+  return m_row_writer.transaction_begin(); 
+}
+
+int handler::
+ha_stmt_end()
+{ 
+  return m_row_writer.transaction_end(); 
+}
+
+
+/**************************************************************************
+	Row_rw_base member functions
+**************************************************************************/
+
+Row_rw_base::
+Row_rw_base(THD *thd, TABLE *table)
+  : m_thd(thd), m_table(table)
+{ 
+}
+
+size_t Row_rw_base::
+max_row_length(const byte * const record) const
+{
+  DBUG_ENTER("Row_rw_base::max_row_length");
+  DBUG_PRINT("enter", ("record = 0x%0x", record));
+
+  size_t length = m_table->s->reclength + 2 * m_table->s->fields;
+  uint* const beg = m_table->s->blob_field;
+  uint* const end = beg + m_table->s->blob_fields;
+
+  for (uint *ptr = beg ; ptr != end ; ++ptr)
+  {
+    Field_blob* const blob = (Field_blob*) m_table->field[*ptr];
+    length += blob->get_length(record + blob->offset()) + 2;
+  }
+
+  DBUG_RETURN(length);
+}
+
+size_t Row_rw_base::
+pack_row(byte *row_data, size_t max_size, const byte *record) const
+{
+  DBUG_ENTER("Row_rw_base::pack_row");
+  DBUG_PRINT("enter", ("row_data = %p, max_size = %lu, record = %p", 
+		       row_data, max_size, record));
+
+  byte *ptr = row_data;
+
+  bzero(row_data, max_size);
+
+  memcpy(row_data, record, m_table->s->null_bytes);
+  ptr += m_table->s->null_bytes;
+
+  for ( Field **field = m_table->field ; *field ; ++field) 
+  {
+    ptrdiff_t const offset = (*field)->offset();
+    ptr = (*field)->pack(ptr, record + offset);
+    DBUG_PRINT("info", ("Packing length %d field '%s' from %p to %p + %d", 
+			(*field)->field_length, (*field)->field_name, 
+			ptr, record, offset));
+  }
+
+  // ptrdiff_t is signed, size_t is unsigned. Check that the conversion
+  // will work correctly.
+  DBUG_ASSERT(ptr - row_data >= 0);
+  size_t const size = (size_t) (ptr - row_data);
+  DBUG_PRINT("return", ("size = %lu", size));
+  DBUG_RETURN(size);
+}
+
+/**************************************************************************
+	Row_writer member functions
+**************************************************************************/
+
+
+int Row_writer::
+write_row(bitvector const& cols, byte const *record) 
+{ 
+  DBUG_ENTER("Row_writer::write_row");
+  DBUG_PRINT("enter", ("cols = { size: %d, data = %p }; record = %p", 
+		       cols.size(), cols.data(), record));
+
+  if (!opt_binlog_row_level || !mysql_bin_log.is_open())
+    DBUG_RETURN(0);
+
+  THD* const thd = current_thd;
+
+  /* 
+     Pack records into format for transfer. We are allocating more
+     memory than needed, but that doesn't matter.
+  */
+  size_t const max_len = max_row_length(record);
+  byte* const row_data = my_malloc(max_len, MYF(MY_WME));
+  size_t const len     = pack_row(row_data, max_len, record);
+
+  Rows_log_event* const
+    ev = thd->prepare_pending<Write_rows_log_event>(m_table, m_server_id, cols, len);
+
+  if (ev == NULL)
+    DBUG_RETURN(1);
+
+  // add_row_data copies row_data to internal buffer
+  ev->add_row_data(row_data,len);
+
+  my_free(row_data, MYF(MY_WME));
+
+  DBUG_RETURN(0);
+}
+
+int Row_writer::
+update_row(bitvector const& cols,
+	   const byte *before_record, const byte *after_record)
+{ 
+  DBUG_ENTER("Row_writer::update_row");
+  DBUG_PRINT("enter", ("before: 0x%0x; after: 0x%0x", 
+		       before_record, after_record));
+
+  if (!opt_binlog_row_level || !mysql_bin_log.is_open())
+    DBUG_RETURN(0);
+
+  THD* const thd = current_thd;
+
+  size_t const before_maxlen = max_row_length(before_record);
+  size_t const after_maxlen  = max_row_length(after_record);
+
+  byte *before_row, *after_row;
+  byte* const memory = my_multi_malloc(MYF(MY_WME),
+				       &before_row, before_maxlen,
+				       &after_row, after_maxlen,
+				       NULL);
+
+  size_t const before_size = pack_row(before_row, before_maxlen, before_record);
+  size_t const after_size = pack_row(after_row, after_maxlen, after_record);
+  
+  Rows_log_event* const
+    ev = thd->prepare_pending<Update_rows_log_event>(m_table, 
+						     m_server_id, cols, 
+						     before_size + after_size);
+
+  if (ev == NULL)
+    DBUG_RETURN(1);
+
+  ev->add_row_data(before_row, before_size);
+  ev->add_row_data(after_row, after_size);
+
+  // add_row_data copies row_data to internal buffer
+  my_free(memory, MYF(MY_WME));
+
+  
+  DBUG_RETURN(0);
+}
+
+int Row_writer::
+delete_row(bitvector const& cols, byte const *record)
+{ 
+  DBUG_ENTER("Row_writer::delete_row");
+  DBUG_PRINT("enter", ("record = 0x%0x", record));
+
+  if (!opt_binlog_row_level || !mysql_bin_log.is_open())
+    DBUG_RETURN(0);
+
+  THD* const thd = current_thd;
+
+  /* 
+     Pack records into format for transfer. We are allocating more
+     memory than needed, but that doesn't matter.
+  */
+  size_t const max_len = max_row_length(record);
+  byte* const row_data = my_malloc(max_len, MYF(MY_WME));
+  size_t const len     = pack_row(row_data, max_len, record);
+
+  Rows_log_event* const
+    ev = thd->prepare_pending<Delete_rows_log_event>(m_table, 
+						     m_server_id, cols, len);
+
+  if (ev == NULL)
+    DBUG_RETURN(1);
+
+  ev->add_row_data(row_data, len);
+
+  // add_row_data copies row_data
+  my_free(row_data, MYF(MY_WME));
+
+  DBUG_RETURN(0);
+}
+
+int Row_writer::
+write_table_map()
+{
+  DBUG_ENTER("Row_writer::write_table_map()");
+  if (!opt_binlog_row_level || !mysql_bin_log.is_open())
+    DBUG_RETURN(0);
+
+  THD* const thd = current_thd;
+  ulong table_id = mysql_bin_log.get_table_id(m_table);
+  Table_map_log_event the_event(thd, m_table, table_id, m_has_trans);
+  if (mysql_bin_log.write(&the_event))
+    DBUG_RETURN(1);
+  DBUG_RETURN(0);
+}
+
+
+int Row_writer::
+flush_pending_event(bool stmt_end)
+{
+  DBUG_ENTER("Row_writer::flush_pending_event(bool)");
+  if (!opt_binlog_row_level || !mysql_bin_log.is_open())
+    DBUG_RETURN(0);
+
+  THD* const thd = current_thd;
+  /*
+    Mark the event as the last event of a statement if the stmt_end flag is
+    set. 
+  */
+  if (stmt_end) {
+    if (Rows_log_event* pending = thd->get_pending_event()) {
+      pending->set_flags(Rows_log_event::STMT_END_F);
+    }
+  }
+  
+  DBUG_PRINT("flush", ("thd = 0x%0x", thd));
+  int const error = thd->flush_and_set_pending_event(0);
+  DBUG_RETURN(error);
 }

--- 1.130/sql/handler.h	2005-03-13 21:58:00 +01:00
+++ 1.131/sql/handler.h	2005-03-22 08:25:35 +01:00
@@ -150,6 +150,9 @@
 /* Options of START TRANSACTION statement (and later of SET TRANSACTION stmt) */
 #define MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT 1
 
+// Forward declarations
+class bitvector;
+
 enum db_type
 {
   DB_TYPE_UNKNOWN=0,DB_TYPE_DIAB_ISAM=1,
@@ -406,6 +409,101 @@
 } HANDLER_BUFFER;
 
 
+class Rows_log_event;
+
+/*****************************************************************************
+
+ Row event reader/writer base class.
+
+ The row event reader/writer base class contain support utilities to
+ help the row reader and row writer to perform its tasks. 
+
+ The responsibilities are:
+ - Provide packing and unpacking utilities for subclasses.
+ 
+*****************************************************************************/
+
+class Row_rw_base {
+public:
+  Row_rw_base(THD *thd, TABLE *table);
+
+  virtual ~Row_rw_base() { }
+
+protected:
+  size_t max_row_length(const byte *data) const;
+  size_t pack_row(byte *row_data, size_t max_len, const byte *data) const;
+
+protected:
+  // These are declared 'const' since you're not supposed to change
+  // them for the lifetime of the object.
+  THD   *const m_thd;
+  TABLE *const m_table;
+};
+
+/*****************************************************************************
+
+  Row event writer class.
+
+  The row event writer serves as a facade to the real row-level
+  events. It takes care of writing row log events at the apropriate
+  times, creating new row-level events when needed and writes them to
+  the binary log when required.
+
+  RESPONSIBILITIES
+
+    - Keeping a mapping from tables to table ids.
+    - Packing rows for transmission to the slave.
+    - Creating events and store the received rows in the event.
+    - Keeping track of the size of the event and ensure that the events
+      are within correct bounds.
+    - Sending events to the binary log.
+
+  COLLABORATION
+
+    Write_rows_log_event  
+    Delete_rows_log_event  
+    Update_rows_log_event  
+
+ ****************************************************************************/
+
+class handler;
+
+class Row_writer : public Row_rw_base
+{
+public:
+  Row_writer(THD *thd, TABLE *table, bool has_trans)
+    : Row_rw_base(thd, table), m_has_trans(has_trans) 
+  { 
+  }
+
+  ~Row_writer() {}
+ 
+  int write_row(bitvector const& cols, 
+		const byte *buf);
+  int delete_row(bitvector const& cols, 
+		 const byte *buf);
+  int update_row(bitvector const& cols, 
+		 const byte *old_data, const byte *new_data);
+
+  void set_server_id(uint32 sid) { m_server_id = sid; }
+
+  int transaction_begin() { 
+    return write_table_map(); 
+  }
+
+  int transaction_end() { 
+    return flush_pending_event(true); 
+  }
+
+private:
+  int flush_pending_event(bool stmt_end);
+  int write_table_map();
+
+  uint32 m_server_id;
+  bool m_has_trans;
+};
+
+
 class handler :public Sql_alloc
 {
  protected:
@@ -473,7 +571,8 @@
     key_used_on_scan(MAX_KEY), active_index(MAX_KEY),
     ref_length(sizeof(my_off_t)), block_size(0),
     raid_type(0), ft_handler(0), inited(NONE), implicit_emptied(0),
-    pushed_cond(NULL)
+    pushed_cond(NULL),
+    m_row_writer(current_thd, table_arg, has_transactions())
     {}
   virtual ~handler(void) { /* TODO: DBUG_ASSERT(inited == NONE); */ }
   int ha_open(const char *name, int mode, int test_if_locked);
@@ -543,11 +642,14 @@
   uint get_index(void) const { return active_index; }
   virtual int open(const char *name, int mode, uint test_if_locked)=0;
   virtual int close(void)=0;
-  virtual int write_row(byte * buf) { return  HA_ERR_WRONG_COMMAND; }
-  virtual int update_row(const byte * old_data, byte * new_data)
-   { return  HA_ERR_WRONG_COMMAND; }
-  virtual int delete_row(const byte * buf)
-   { return  HA_ERR_WRONG_COMMAND; }
+
+  int ha_write_row(byte *buf);  
+  int ha_update_row(const byte *old_data, byte *new_data);
+  int ha_delete_row(const byte *buf);
+  
+  int ha_stmt_begin();
+  int ha_stmt_end();
+
   virtual int index_read(byte * buf, const byte * key,
 			 uint key_len, enum ha_rkey_function find_flag)
    { return  HA_ERR_WRONG_COMMAND; }
@@ -732,7 +834,7 @@
  {
    return memcmp(ref1, ref2, ref_length);
  }
- 
+
  /*
    Condition pushdown to storage engines
  */
@@ -766,6 +868,23 @@
      Pops the top if condition stack, if stack is not empty
  */
  virtual void cond_pop() { return; };
+
+  // This is a temporary solution
+  Row_writer* row_writer() { return &m_row_writer; }
+
+private:
+  /*
+    Row-level primitives for storage engines. 
+    These should be overridden by the storage engine class. To call
+    these methods, use the corresponding 'ha_*' method above.
+  */
+  virtual int write_row(byte * buf) { return  HA_ERR_WRONG_COMMAND; }
+  virtual int update_row(const byte * old_data, byte * new_data)
+  { return  HA_ERR_WRONG_COMMAND; }
+  virtual int delete_row(const byte * buf)
+  { return  HA_ERR_WRONG_COMMAND; }
+ 
+  Row_writer m_row_writer;
 };
 
 	/* Some extern variables used with handlers */

--- 1.156/sql/log.cc	2005-03-14 17:53:15 +01:00
+++ 1.157/sql/log.cc	2005-03-22 08:25:35 +01:00
@@ -347,8 +347,9 @@
 MYSQL_LOG::MYSQL_LOG()
   :bytes_written(0), last_time(0), query_start(0), name(0),
    file_id(1), open_count(1), log_type(LOG_CLOSED), write_error(0), inited(0),
-   need_start_event(1), prepared_xids(0), description_event_for_exec(0),
-   description_event_for_queue(0)
+   need_start_event(1), prepared_xids(0), 
+   m_table_map(NULL), m_next_table_id(0), 
+   description_event_for_exec(0), description_event_for_queue(0)
 {
   /*
     We don't want to initialize LOCK_Log here as such initialization depends on
@@ -409,6 +410,7 @@
   no_auto_events = no_auto_events_arg;
   max_size=max_size_arg;
   DBUG_PRINT("info",("log_type: %d max_size: %lu", log_type, max_size));
+
   DBUG_VOID_RETURN;
 }
 
@@ -1549,9 +1551,15 @@
 
 bool MYSQL_LOG::write(Log_event *event_info)
 {
-  THD *thd= event_info->thd;
+  THD *thd=event_info->thd;
   bool error= 1;
-  DBUG_ENTER("MYSQL_LOG::write(Log_event *)");
+  DBUG_ENTER("MYSQL_LOG::write(Log_event*)");
+  
+  /*
+    Let the event decide if it want to go to the binlog.
+  */
+  if (!event_info->write_to_binlog())
+    DBUG_RETURN(0);		// Silently succeed
 
   pthread_mutex_lock(&LOCK_log);
 
@@ -1581,15 +1589,16 @@
 
 #ifdef USING_TRANSACTIONS
     /*
-      Should we write to the binlog cache or to the binlog on disk?
-      Write to the binlog cache if:
-      - it is already not empty (meaning we're in a transaction; note that the
-     present event could be about a non-transactional table, but still we need
-     to write to the binlog cache in that case to handle updates to mixed
-     trans/non-trans table types the best possible in binlogging)
+      Should we write to the binlog cache or to the binlog on disk?  Write to
+      the binlog cache if the statement can be cached (can_be_cached() ==
+      true) and the binlog cache:
+      - is already not empty (meaning we're in a transaction; note that the
+        present event could be about a non-transactional table, but still we
+        need to write to the binlog cache in that case to handle updates to
+        mixed trans/non-trans table types the best possible in binlogging)
       - or if the event asks for it (cache_stmt == true).
     */
-    if (opt_using_transactions && thd)
+    if (opt_using_transactions && thd && event_info->can_be_cached())
     {
       IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot];
 
@@ -2293,6 +2302,29 @@
   DBUG_VOID_RETURN;
 }
 
+
+ulong MYSQL_LOG::
+get_table_id(TABLE* table)
+{
+  DBUG_ENTER("MYSQL_LOG::get_table_id(TABLE*)");
+  DBUG_PRINT("enter", ("table=%p", table)); 
+
+  // Have to create it here since it relies on my_malloc, which requires
+  // my_init() to have been executed prior to this.
+  if (m_table_map == NULL)
+    m_table_map = new table_mapping;
+
+  DBUG_ASSERT(m_table_map != NULL);
+  ulong tid = m_table_map->get_table_id(table);
+  if (tid == m_table_map->count()) {
+    // We can't use the number of tables in the list since the highest table
+    // id might be larger than the number of elements in the list. 
+    tid = m_next_table_id++;
+    m_table_map->set_table(tid, table);
+  }
+  DBUG_PRINT("return", ("table_id=%d", tid));
+  DBUG_RETURN(tid);
+}
 
 #ifdef __NT__
 void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,

--- 1.167/sql/log_event.cc	2005-03-21 19:24:55 +01:00
+++ 1.168/sql/log_event.cc	2005-03-22 08:44:12 +01:00
@@ -276,7 +276,9 @@
   case WRITE_ROWS_EVENT: return "Write_rows";
   case UPDATE_ROWS_EVENT: return "Update_rows";
   case DELETE_ROWS_EVENT: return "Delete_rows";
-  default: return "Unknown";				/* impossible */ 
+  case BEGIN_LOAD_QUERY_EVENT: return "Begin_load_query";
+  case EXECUTE_LOAD_QUERY_EVENT: return "Execute_load_query";
+  default: return "Unknown";				/* impossible */
   }
 }
 
@@ -794,10 +796,10 @@
 
   switch(buf[EVENT_TYPE_OFFSET]) {
   case QUERY_EVENT:
-    ev  = new Query_log_event(buf, event_len, description_event);
+    ev  = new Query_log_event(buf, event_len, description_event, QUERY_EVENT);
     break;
   case LOAD_EVENT:
-    ev = new Create_file_log_event(buf, event_len, description_event);
+    ev = new Load_log_event(buf, event_len, description_event);
     break;
   case NEW_LOAD_EVENT:
     ev = new Load_log_event(buf, event_len, description_event);
@@ -857,6 +859,12 @@
     ev = new Table_map_log_event(buf, event_len, description_event);
     break;
 #endif
+  case BEGIN_LOAD_QUERY_EVENT:
+    ev = new Begin_load_query_log_event(buf, event_len, description_event);
+    break;
+  case EXECUTE_LOAD_QUERY_EVENT:
+    ev = new Execute_load_query_log_event(buf, event_len, description_event);
+    break;
   default:
     DBUG_PRINT("error",("Unknown event code: %d",(int) buf[EVENT_TYPE_OFFSET]));
     ev= NULL;
@@ -1110,10 +1118,13 @@
     Calculate length of whole event
     The "1" below is the \0 in the db's length
   */
-  event_length= (uint) (start-buf) + db_len + 1 + q_len;
+  event_length= (uint) (start-buf) + get_post_header_size_for_derived() + db_len + 1 + q_len;
 
   return (write_header(file, event_length) ||
-          my_b_safe_write(file, (byte*) buf, (uint) (start-buf)) ||
+          my_b_safe_write(file, (byte*) buf, QUERY_HEADER_LEN) ||
+          write_post_header_for_derived(file) ||
+          my_b_safe_write(file, (byte*) start_of_status,
+                          (uint) (start-start_of_status)) ||
           my_b_safe_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) ||
           my_b_safe_write(file, (byte*) query, q_len)) ? 1 : 0;
 }
@@ -1175,7 +1186,8 @@
 */
 
 Query_log_event::Query_log_event(const char* buf, uint event_len,
-                                 const Format_description_log_event *description_event)
+                                 const Format_description_log_event *description_event,
+                                 Log_event_type event_type)
   :Log_event(buf, description_event), data_buf(0), query(NullS), catalog(NullS), 
    db(NullS), catalog_len(0), status_vars_len(0),
    flags2_inited(0), sql_mode_inited(0), charset_inited(0),
@@ -1188,7 +1200,7 @@
   DBUG_ENTER("Query_log_event::Query_log_event(char*,...)");
 
   common_header_len= description_event->common_header_len;
-  post_header_len= description_event->post_header_len[QUERY_EVENT-1]; 
+  post_header_len= description_event->post_header_len[event_type-1];
   DBUG_PRINT("info",("event_len=%ld, common_header_len=%d, post_header_len=%d",
                      event_len, common_header_len, post_header_len));
   
@@ -1221,13 +1233,12 @@
                         (uint) status_vars_len));
     tmp-= 2;
   }
-  /* we have parsed everything we know in the post header */
-#ifndef DBUG_OFF
-  if (tmp) /* this is probably a master newer than us */
-    DBUG_PRINT("info", ("Query_log_event has longer post header than we know\
-  (%d more bytes)", tmp));
-#endif
-  
+  /*
+    We have parsed everything we know in the post header for QUERY_EVENT,
+    the rest of post header is either comes from older version MySQL or
+    dedicated to derived events (e.g. Execute_load_query...)
+  */
+
   /* variable-part: the status vars; only in MySQL 5.0  */
   
   start= (char*) (buf+post_header_len);
@@ -1306,8 +1317,8 @@
 */
 
 #ifdef MYSQL_CLIENT
-void Query_log_event::print(FILE* file, bool short_form,
-                            LAST_EVENT_INFO* last_event_info)
+void Query_log_event::print_query_header(FILE* file, bool short_form,
+                                         LAST_EVENT_INFO* last_event_info)
 {
   // TODO: print the catalog ??
   char buff[40],*end;				// Enough for SET TIMESTAMP
@@ -1317,8 +1328,8 @@
   if (!short_form)
   {
     print_header(file);
-    fprintf(file, "\tQuery\tthread_id=%lu\texec_time=%lu\terror_code=%d\n",
-	    (ulong) thread_id, (ulong) exec_time, error_code);
+    fprintf(file, "\t%s\tthread_id=%lu\texec_time=%lu\terror_code=%d\n",
+	    get_type_str(), (ulong) thread_id, (ulong) exec_time, error_code);
   }
 
   if (!(flags & LOG_EVENT_SUPPRESS_USE_F) && db)
@@ -1424,7 +1435,13 @@
       memcpy(last_event_info->charset, charset, 6);
     }
   }
+}
+
 
+void Query_log_event::print(FILE* file, bool short_form,
+                            LAST_EVENT_INFO* last_event_info)
+{
+  print_query_header(file, short_form, last_event_info);
   my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
   fputs(";\n", file);
 }
@@ -1438,6 +1455,12 @@
 #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
 int Query_log_event::exec_event(struct st_relay_log_info* rli)
 {
+  return exec_event(rli, query, q_len);
+}
+
+
+int Query_log_event::exec_event(struct st_relay_log_info* rli, const char *query_arg, uint32 q_len_arg)
+{
   int expected_error,actual_error= 0;
   /*
     Colleagues: please never free(thd->catalog) in MySQL. This would lead to
@@ -1469,8 +1492,8 @@
   if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
   {
     thd->set_time((time_t)when);
-    thd->query_length= q_len;
-    thd->query = (char*)query;
+    thd->query_length= q_len_arg;
+    thd->query= (char*)query_arg;
     VOID(pthread_mutex_lock(&LOCK_thread_count));
     thd->query_id = next_query_id();
     VOID(pthread_mutex_unlock(&LOCK_thread_count));
@@ -1531,7 +1554,7 @@
       }
 
       /* Execute the query (note that we bypass dispatch_command()) */
-      mysql_parse(thd, thd->query, q_len);
+      mysql_parse(thd, thd->query, thd->query_length);
 
     }
     else
@@ -1543,7 +1566,7 @@
         we exit gracefully; otherwise we warn about the bad error and tell DBA
         to check/fix it.
       */
-      if (mysql_test_parse_for_slave(thd, thd->query, q_len))
+      if (mysql_test_parse_for_slave(thd, thd->query, thd->query_length))
         clear_all_errors(thd, rli);        /* Can ignore query */
       else
       {
@@ -1585,7 +1608,7 @@
 			expected_error,
 			actual_error ? thd->net.last_error: "no error",
 			actual_error,
-			print_slave_db_safe(db), query);
+			print_slave_db_safe(db), query_arg);
       thd->query_error= 1;
     }
     /*
@@ -1606,7 +1629,7 @@
 			"Error '%s' on query. Default database: '%s'. Query: '%s'",
 			(actual_error ? thd->net.last_error :
 			 "unexpected success or fatal error"),
-			print_slave_db_safe(thd->db), query);
+			print_slave_db_safe(thd->db), query_arg);
       thd->query_error= 1;
     }
 
@@ -1853,11 +1876,6 @@
     server starts or when FLUSH LOGS), or to create artificial events to parse
     binlogs from MySQL 3.23 or 4.x.
     When in a client, only the 2nd use is possible.
-
-  TODO
-    Update this code with the new event for LOAD DATA, once they are pushed (in
-    4.1 or 5.0). If it's in 5.0, only the "case 4" block should be updated.
-
 */
 
 Format_description_log_event::
@@ -1895,6 +1913,8 @@
       post_header_len[WRITE_ROWS_EVENT-1]  = ROWS_HEADER_LEN;
       post_header_len[UPDATE_ROWS_EVENT-1] = ROWS_HEADER_LEN;
       post_header_len[DELETE_ROWS_EVENT-1] = ROWS_HEADER_LEN;
+      post_header_len[BEGIN_LOAD_QUERY_EVENT-1]= post_header_len[APPEND_BLOCK_EVENT-1];
+      post_header_len[EXECUTE_LOAD_QUERY_EVENT-1]= EXECUTE_LOAD_QUERY_HEADER_LEN;
     }
     break;
 
@@ -2100,12 +2120,9 @@
 */
 
 #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Load_log_event::pack_info(Protocol *protocol)
+uint Load_log_event::get_query_buffer_length()
 {
-  char *buf, *pos;
-  uint buf_len;
-
-  buf_len=
+  return
     5 + db_len + 3 +                        // "use DB; "
     18 + fname_len + 2 +                    // "LOAD DATA INFILE 'file''"
     7 +					    // LOCAL
@@ -2118,11 +2135,15 @@
     19 + sql_ex.line_start_len*4 + 2 +      // " LINES STARTING BY 'str'"
     15 + 22 +                               // " IGNORE xxx  LINES"
     3 + (num_fields-1)*2 + field_block_len; // " (field1, field2, ...)"
+}
 
-  if (!(buf= my_malloc(buf_len, MYF(MY_WME))))
-    return;
-  pos= buf;
-  if (db && db_len)
+
+void Load_log_event::print_query(bool need_db, char *buf,
+                                 char **end, char **fn_start, char **fn_end)
+{
+  char *pos= buf;
+
+  if (need_db && db && db_len)
   {
     pos= strmov(pos, "use `");
     memcpy(pos, db, db_len);
@@ -2130,6 +2151,10 @@
   }
 
   pos= strmov(pos, "LOAD DATA ");
+
+  if (fn_start)
+    *fn_start= pos;
+
   if (check_fname_outside_temp_buf())
     pos= strmov(pos, "LOCAL ");
   pos= strmov(pos, "INFILE '");
@@ -2141,7 +2166,12 @@
   else if (sql_ex.opt_flags & IGNORE_FLAG)
     pos= strmov(pos, " IGNORE ");
 
-  pos= strmov(pos ,"INTO TABLE `");
+  pos= strmov(pos ,"INTO");
+
+  if (fn_end)
+    *fn_end= pos;
+
+  pos= strmov(pos ," TABLE `");
   memcpy(pos, table_name, table_name_len);
   pos+= table_name_len;
 
@@ -2190,7 +2220,18 @@
     *pos++= ')';
   }
 
-  protocol->store(buf, pos-buf, &my_charset_bin);
+  *end= pos;
+}
+
+
+void Load_log_event::pack_info(Protocol *protocol)
+{
+  char *buf, *end;
+
+  if (!(buf= my_malloc(get_query_buffer_length(), MYF(MY_WME))))
+    return;
+  print_query(TRUE, buf, &end, 0, 0);
+  protocol->store(buf, end-buf, &my_charset_bin);
   my_free(buf, MYF(0));
 }
 #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
@@ -2397,11 +2438,6 @@
   fname_len = strlen(fname);
   // null termination is accomplished by the caller doing buf[event_len]=0
 
-  /*
-    In 5.0 this event will have the same format, as we are planning to log LOAD
-    DATA INFILE in a completely different way (as a plain-text query) since 4.1
-    or 5.0 (Dmitri's WL#874)
-  */
   DBUG_RETURN(0);
 }
 
@@ -2561,7 +2597,6 @@
 int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, 
 			       bool use_rli_only_for_errors)
 {
-  char *load_data_query= 0;
   thd->db_length= db_len;
   thd->db= (char*) rewrite_db(db, &thd->db_length);
   DBUG_ASSERT(thd->query == 0);
@@ -2604,7 +2639,7 @@
       "data truncated" warning but which is absorbed and never gets to the
       error log); still we init it to avoid a Valgrind message.
     */
-    mysql_reset_errors(thd);
+    mysql_reset_errors(thd, 0);
 
     TABLE_LIST tables;
     bzero((char*) &tables,sizeof(tables));
@@ -2623,21 +2658,30 @@
     else
     {
       char llbuff[22];
+      char *end;
       enum enum_duplicates handle_dup;
       bool ignore= 0;
+      char *load_data_query;
+
       /*
-        Make a simplified LOAD DATA INFILE query, for the information of the
-        user in SHOW PROCESSLIST. Note that db is known in the 'db' column.
+        Forge LOAD DATA INFILE query which will be used in SHOW PROCESS LIST
+        and written to slave's binlog if binlogging is on.
       */
-      if ((load_data_query= (char *) my_alloca(18 + strlen(fname) + 14 +
-                                               strlen(tables.table_name) + 8)))
+      if (!(load_data_query= (char *)thd->alloc(get_query_buffer_length() + 1)))
       {
-        thd->query_length= (uint)(strxmov(load_data_query,
-                                          "LOAD DATA INFILE '", fname,
-                                          "' INTO TABLE `", tables.table_name,
-                                          "` <...>", NullS) - load_data_query);
-        thd->query= load_data_query;
+        /*
+          This will set thd->fatal_error in case of OOM. So we surely will notice
+          that something is wrong.
+        */
+        goto error;
       }
+
+      print_query(FALSE, load_data_query, &end, (char **)&thd->lex->fname_start,
+                  (char **)&thd->lex->fname_end);
+      *end= 0;
+      thd->query_length= end - load_data_query;
+      thd->query= load_data_query;
+
       if (sql_ex.opt_flags & REPLACE_FLAG)
 	handle_dup= DUP_REPLACE;
       else if (sql_ex.opt_flags & IGNORE_FLAG)
@@ -2683,6 +2727,7 @@
       List<Item> field_list;
       set_fields(thd->db,field_list);
       thd->variables.pseudo_thread_id= thread_id;
+      List<Item> set_fields;
       if (net)
       {
 	// mysql_load will use thd->net to read the file
@@ -2692,9 +2737,13 @@
 	*/
 	thd->net.pkt_nr = net->pkt_nr;
       }
-      if (mysql_load(thd, &ex, &tables, field_list, handle_dup, ignore,
-                     net != 0, TL_WRITE))
-	thd->query_error = 1;
+      /*
+        It is safe to use set_fields twice because we are not going to
+        update it inside mysql_load().
+      */
+      if (mysql_load(thd, &ex, &tables, field_list, set_fields, set_fields,
+                     handle_dup, ignore, net != 0))
+        thd->query_error= 1;
       if (thd->cuted_fields)
       {
 	/* log_pos is the position of the LOAD event in the master log */
@@ -2720,7 +2769,8 @@
     if (net)
       skip_load_data_infile(net);
   }
-	    
+
+error:
   thd->net.vio = 0; 
   char *save_db= thd->db;
   VOID(pthread_mutex_lock(&LOCK_thread_count));
@@ -2729,8 +2779,6 @@
   thd->query_length= thd->db_length= 0;
   VOID(pthread_mutex_unlock(&LOCK_thread_count));
   close_thread_tables(thd);
-  if (load_data_query)
-    my_afree(load_data_query);
   if (thd->query_error)
   {
     /* this err/sql_errno code is copy-paste from net_send_error() */
@@ -4045,8 +4093,8 @@
     return;
   print_header(file);
   fputc('\n', file);
-  fprintf(file, "#Append_block: file_id: %d  block_len: %d\n",
-	  file_id, block_len);
+  fprintf(file, "#%s: file_id: %d  block_len: %d\n",
+	  get_type_str(), file_id, block_len);
 }
 #endif /* MYSQL_CLIENT */
 
@@ -4065,14 +4113,21 @@
 			     block_len));
   protocol->store(buf, length, &my_charset_bin);
 }
-#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
 
 
 /*
+  Append_block_log_event::get_open_mode()
+*/
+
+int Append_block_log_event::get_open_mode() const
+{
+  return O_WRONLY | O_APPEND | O_BINARY;
+}
+
+/*
   Append_block_log_event::exec_event()
 */
 
-#if defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
 int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
 {
   char proc_info[17+FN_REFLEN+10], *fname= proc_info+17;
@@ -4084,14 +4139,18 @@
   memcpy(p, ".data", 6);
   strnmov(proc_info, "Making temp file ", 17); // no end 0
   thd->proc_info= proc_info;
-  if ((fd = my_open(fname, O_WRONLY|O_APPEND|O_BINARY, MYF(MY_WME))) < 0)
+  if ((fd = my_open(fname, get_open_mode(), MYF(MY_WME))) < 0)
   {
-    slave_print_error(rli,my_errno, "Error in Append_block event: could not open file '%s'", fname);
+    slave_print_error(rli, my_errno,
+                      "Error in %s event: could not open file '%s'",
+                      get_type_str(), fname);
     goto err;
   }
   if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
   {
-    slave_print_error(rli,my_errno, "Error in Append_block event: write to '%s' failed", fname);
+    slave_print_error(rli, my_errno,
+                      "Error in %s event: write to '%s' failed",
+                      get_type_str(), fname);
     goto err;
   }
   error=0;
@@ -4361,6 +4420,216 @@
 }
 
 #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
+
+
+/**************************************************************************
+	Begin_load_query_log_event methods
+**************************************************************************/
+
+#ifndef MYSQL_CLIENT
+Begin_load_query_log_event::
+Begin_load_query_log_event(THD* thd_arg, const char* db_arg, char* block_arg,
+                           uint block_len_arg, bool using_trans)
+  :Append_block_log_event(thd_arg, db_arg, block_arg, block_len_arg,
+                          using_trans)
+{
+   file_id= thd_arg->file_id= mysql_bin_log.next_file_id();
+}
+#endif
+
+
+Begin_load_query_log_event::
+Begin_load_query_log_event(const char* buf, uint len,
+                           const Format_description_log_event* desc_event)
+  :Append_block_log_event(buf, len, desc_event)
+{
+}
+
+
+#if defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+int Begin_load_query_log_event::get_open_mode() const
+{
+  return O_CREAT | O_WRONLY | O_BINARY | O_TRUNC;
+}
+#endif /* defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
+
+
+/**************************************************************************
+	Execute_load_query_log_event methods
+**************************************************************************/
+
+
+#ifndef MYSQL_CLIENT
+Execute_load_query_log_event::
+Execute_load_query_log_event(THD* thd_arg, const char* query_arg,
+                     ulong query_length_arg, uint fn_pos_start_arg,
+                     uint fn_pos_end_arg,
+                     enum_load_dup_handling dup_handling_arg,
+                     bool using_trans, bool suppress_use):
+  Query_log_event(thd_arg, query_arg, query_length_arg, using_trans,
+                  suppress_use),
+  file_id(thd_arg->file_id), fn_pos_start(fn_pos_start_arg),
+  fn_pos_end(fn_pos_end_arg), dup_handling(dup_handling_arg)
+{
+}
+#endif /* !MYSQL_CLIENT */
+
+
+Execute_load_query_log_event::
+Execute_load_query_log_event(const char* buf, uint event_len,
+                             const Format_description_log_event* desc_event):
+  Query_log_event(buf, event_len, desc_event, EXECUTE_LOAD_QUERY_EVENT),
+  file_id(0), fn_pos_start(0), fn_pos_end(0)
+{
+  if (!Query_log_event::is_valid())
+    return;
+
+  buf+= desc_event->common_header_len;
+
+  fn_pos_start= uint4korr(buf + ELQ_FN_POS_START_OFFSET);
+  fn_pos_end= uint4korr(buf + ELQ_FN_POS_END_OFFSET);
+  dup_handling= (enum_load_dup_handling)(*(buf + ELQ_DUP_HANDLING_OFFSET));
+
+  if (fn_pos_start > q_len || fn_pos_end > q_len ||
+      dup_handling > LOAD_DUP_REPLACE)
+    return;
+
+  file_id= uint4korr(buf + ELQ_FILE_ID_OFFSET);
+}
+
+
+ulong Execute_load_query_log_event::get_post_header_size_for_derived()
+{
+  return EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN;
+}
+
+
+bool
+Execute_load_query_log_event::write_post_header_for_derived(IO_CACHE* file)
+{
+  char buf[EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN];
+  int4store(buf, file_id);
+  int4store(buf + 4, fn_pos_start);
+  int4store(buf + 4 + 4, fn_pos_end);
+  *(buf + 4 + 4 + 4)= (char)dup_handling;
+  return my_b_safe_write(file, (byte*) buf, EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN);
+}
+
+
+#ifdef MYSQL_CLIENT
+void Execute_load_query_log_event::print(FILE* file, bool short_form,
+                                         LAST_EVENT_INFO* last_event_info)
+{
+  print(file, short_form, last_event_info, 0);
+}
+
+
+void Execute_load_query_log_event::print(FILE* file, bool short_form,
+                                         LAST_EVENT_INFO* last_event_info,
+                                         const char *local_fname)
+{
+  print_query_header(file, short_form, last_event_info);
+
+  if (local_fname)
+  {
+    my_fwrite(file, (byte*) query, fn_pos_start, MYF(MY_NABP | MY_WME));
+    fprintf(file, " LOCAL INFILE \'");
+    fprintf(file, local_fname);
+    fprintf(file, "\'");
+    if (dup_handling == LOAD_DUP_REPLACE)
+      fprintf(file, " REPLACE");
+    fprintf(file, " INTO");
+    my_fwrite(file, (byte*) query + fn_pos_end, q_len-fn_pos_end,
+        MYF(MY_NABP | MY_WME));
+    fprintf(file, ";\n");
+  }
+  else
+  {
+    my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
+    fprintf(file, ";\n");
+  }
+
+  if (!short_form)
+    fprintf(file, "# file_id: %d \n", file_id);
+}
+#endif
+
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void Execute_load_query_log_event::pack_info(Protocol *protocol)
+{
+  char *buf, *pos;
+  if (!(buf= my_malloc(9 + db_len + q_len + 10 + 21, MYF(MY_WME))))
+    return;
+  pos= buf;
+  if (db && db_len)
+  {
+    pos= strmov(buf, "use `");
+    memcpy(pos, db, db_len);
+    pos= strmov(pos+db_len, "`; ");
+  }
+  if (query && q_len)
+  {
+    memcpy(pos, query, q_len);
+    pos+= q_len;
+  }
+  pos= strmov(pos, " ;file_id=");
+  pos= int10_to_str((long) file_id, pos, 10);
+  protocol->store(buf, pos-buf, &my_charset_bin);
+  my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
+}
+
+
+int
+Execute_load_query_log_event::exec_event(struct st_relay_log_info* rli)
+{
+  char *p;
+  char *buf;
+  char *fname;
+  char *fname_end;
+  int error;
+
+  /* Replace filename and LOCAL keyword in query before executing it */
+  if (!(buf = my_malloc(q_len + 1 - (fn_pos_end - fn_pos_start) +
+                        (FN_REFLEN + 10) + 10 + 8 + 5, MYF(MY_WME))))
+  {
+    slave_print_error(rli, my_errno, "Not enough memory");
+    return 1;
+  }
+
+  p= buf;
+  memcpy(p, query, fn_pos_start);
+  p+= fn_pos_start;
+  fname= (p= strmake(p, " INFILE \'", 9));
+  p= slave_load_file_stem(p, file_id, server_id);
+  fname_end= (p= strmake(p, ".data", 5));
+  *(p++)='\'';
+  switch (dup_handling)
+  {
+  case LOAD_DUP_IGNORE:
+    p= strmake(p, " IGNORE", 7);
+    break;
+  case LOAD_DUP_REPLACE:
+    p= strmake(p, " REPLACE", 8);
+    break;
+  default:
+    /* Ordinary load data */
+    break;
+  }
+  p= strmake(p, " INTO", 5);
+  p= strmake(p, query+fn_pos_end, q_len-fn_pos_end);
+
+  error= Query_log_event::exec_event(rli, buf, p-buf);
+
+  /* Forging file name for deletion in same buffer */
+  *fname_end= 0;
+
+  (void) my_delete(fname, MYF(MY_WME));
+
+  my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
+  return error;
+}
+#endif
 
 
 /**************************************************************************

--- 1.106/sql/log_event.h	2005-03-21 19:24:55 +01:00
+++ 1.107/sql/log_event.h	2005-03-22 08:44:12 +01:00
@@ -170,10 +170,12 @@
 
   See the #defines below for the format specifics.
 
-  The events which really update data are Query_log_event and
-  Load_log_event/Create_file_log_event/Execute_load_log_event (these 3 act
-  together to replicate LOAD DATA INFILE, with the help of
-  Append_block_log_event which prepares temporary files to load into the table).
+  The events which really update data are Query_log_event,
+  Execute_load_query_log_event and old Load_log_event and
+  Execute_load_log_event events (Execute_load_query is used together with
+  Begin_load_query and Append_block events to replicate LOAD DATA INFILE.
+  Create_file/Append_block/Execute_load (which includes Load_log_event)
+  were used to replicate LOAD DATA before the 5.0.3).
 
  ****************************************************************************/
 
@@ -203,6 +205,8 @@
 #define FORMAT_DESCRIPTION_HEADER_LEN (START_V3_HEADER_LEN+1+LOG_EVENT_TYPES)
 #define ROWS_HEADER_LEN        6
 #define TABLE_MAP_HEADER_LEN   4
+#define EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN (4 + 4 + 4 + 1)
+#define EXECUTE_LOAD_QUERY_HEADER_LEN  (QUERY_HEADER_LEN + EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN)
 
 /*
    Event header offsets;
@@ -300,6 +304,12 @@
 #define RW_MAPID_OFFSET    0
 #define RW_FLAGS_OFFSET    4
 
+/* ELQ = "Execute Load Query" */
+#define ELQ_FILE_ID_OFFSET QUERY_HEADER_LEN
+#define ELQ_FN_POS_START_OFFSET ELQ_FILE_ID_OFFSET + 4
+#define ELQ_FN_POS_END_OFFSET ELQ_FILE_ID_OFFSET + 8
+#define ELQ_DUP_HANDLING_OFFSET ELQ_FILE_ID_OFFSET + 12
+
 /* 4 bytes which all binlogs should begin with */
 #define BINLOG_MAGIC        "\xfe\x62\x69\x6e"
 
@@ -407,6 +417,8 @@
   UPDATE_ROWS_EVENT,
   DELETE_ROWS_EVENT,
   XID_EVENT,
+  BEGIN_LOAD_QUERY_EVENT,
+  EXECUTE_LOAD_QUERY_EVENT,
 
   /*
     add new events here - right above this comment!
@@ -779,13 +791,17 @@
 #ifdef HAVE_REPLICATION
   void pack_info(Protocol* protocol);
   int exec_event(struct st_relay_log_info* rli);
+  int exec_event(struct st_relay_log_info* rli, const char *query_arg,
+                 uint32 q_len_arg);
 #endif /* HAVE_REPLICATION */
 #else
+  void print_query_header(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
   void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
 #endif
 
   Query_log_event(const char* buf, uint event_len,
-                  const Format_description_log_event *description_event);
+                  const Format_description_log_event *description_event,
+                  Log_event_type event_type);
   ~Query_log_event()
   {
     if (data_buf)
@@ -796,6 +812,14 @@
   Log_event_type get_type_code() { return QUERY_EVENT; }
   bool write(IO_CACHE* file);
   bool is_valid() const { return query != 0; }
+
+  /*
+    Returns number of bytes additionaly written to post header by derived
+    events (so far it is only Execute_load_query event).
+  */
+  virtual ulong get_post_header_size_for_derived() { return 0; }
+  /* Writes derived event-specific part of post header. */
+  virtual bool write_post_header_for_derived(IO_CACHE* file) { return FALSE; }
 };
 
 #ifdef HAVE_REPLICATION
@@ -847,6 +871,10 @@
  ****************************************************************************/
 class Load_log_event: public Log_event
 {
+private:
+  uint get_query_buffer_length();
+  void print_query(bool need_db, char *buf, char **end,
+                   char **fn_start, char **fn_end);
 protected:
   int copy_log_event(const char *buf, ulong event_len,
                      int body_offset, const Format_description_log_event* description_event);
@@ -1380,6 +1408,7 @@
 #ifdef HAVE_REPLICATION
   int exec_event(struct st_relay_log_info* rli);
   void pack_info(Protocol* protocol);
+  virtual int get_open_mode() const;
 #endif /* HAVE_REPLICATION */
 #else
   void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
@@ -1461,6 +1490,93 @@
   bool write(IO_CACHE* file);
   const char* get_db() { return db; }
 };
+
+
+/***************************************************************************
+
+  Begin load query Log Event class
+
+  Event for the first block of file to be loaded, its only difference from
+  Append_block event is that this event creates or truncates existing file
+  before writing data.
+
+****************************************************************************/
+class Begin_load_query_log_event: public Append_block_log_event
+{
+public:
+#ifndef MYSQL_CLIENT
+  Begin_load_query_log_event(THD* thd_arg, const char *db_arg,
+                             char* block_arg, uint block_len_arg,
+                             bool using_trans);
+#ifdef HAVE_REPLICATION
+  Begin_load_query_log_event(THD* thd);
+  int get_open_mode() const;
+#endif /* HAVE_REPLICATION */
+#endif
+  Begin_load_query_log_event(const char* buf, uint event_len,
+                             const Format_description_log_event* description_event);
+  ~Begin_load_query_log_event() {}
+  Log_event_type get_type_code() { return BEGIN_LOAD_QUERY_EVENT; }
+};
+
+
+/*
+  Elements of this enum describe how LOAD DATA handles duplicates.
+*/
+enum enum_load_dup_handling { LOAD_DUP_ERROR= 0, LOAD_DUP_IGNORE,
+                              LOAD_DUP_REPLACE };
+
+/****************************************************************************
+
+  Execute load query Log Event class
+
+  Event responsible for LOAD DATA execution, it similar to Query_log_event
+  but before executing the query it substitutes original filename in LOAD DATA
+  query with name of temporary file.
+
+****************************************************************************/
+class Execute_load_query_log_event: public Query_log_event
+{
+public:
+  uint file_id;       // file_id of temporary file
+  uint fn_pos_start;  // pointer to the part of the query that should
+                      // be substituted
+  uint fn_pos_end;    // pointer to the end of this part of query
+  /*
+    We have to store type of duplicate handling explicitly, because
+    for LOAD DATA it also depends on LOCAL option. And this part
+    of query will be rewritten during replication so this information
+    may be lost...
+  */
+  enum_load_dup_handling dup_handling;
+
+#ifndef MYSQL_CLIENT
+  Execute_load_query_log_event(THD* thd, const char* query_arg,
+                       ulong query_length, uint fn_pos_start_arg,
+                       uint fn_pos_end_arg,
+                       enum_load_dup_handling dup_handling_arg,
+                       bool using_trans, bool suppress_use);
+#ifdef HAVE_REPLICATION
+  void pack_info(Protocol* protocol);
+  int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
+#else
+  void print(FILE* file, bool short_form = 0,
+             LAST_EVENT_INFO* last_event_info= 0);
+  /* Prints the query as LOAD DATA LOCAL and with rewritten filename */
+  void print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info,
+             const char *local_fname);
+#endif
+  Execute_load_query_log_event(const char* buf, uint event_len,
+                               const Format_description_log_event *description_event);
+  ~Execute_load_query_log_event() {}
+
+  Log_event_type get_type_code() { return EXECUTE_LOAD_QUERY_EVENT; }
+  bool is_valid() const { return Query_log_event::is_valid() && file_id != 0; }
+
+  ulong get_post_header_size_for_derived();
+  bool write_post_header_for_derived(IO_CACHE* file);
+ };
 
 
 #ifdef MYSQL_CLIENT

--- 1.279/sql/mysql_priv.h	2005-03-17 08:46:33 +01:00
+++ 1.280/sql/mysql_priv.h	2005-03-22 08:25:35 +01:00
@@ -1063,6 +1063,8 @@
 extern ulong query_buff_size, thread_stack,thread_stack_min;
 extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit;
 extern ulong max_binlog_size, max_relay_log_size;
+extern my_bool opt_binlog_row_level;
+extern ulong opt_binlog_row_event_max_size; 
 extern ulong rpl_recovery_rank, thread_cache_size;
 extern ulong back_log;
 extern ulong specialflag, current_pid;

--- 1.442/sql/mysqld.cc	2005-03-18 02:16:29 +01:00
+++ 1.443/sql/mysqld.cc	2005-03-22 08:25:36 +01:00
@@ -321,6 +321,9 @@
 volatile bool mqh_used = 0;
 my_bool sp_automatic_privileges= 1;
 
+my_bool opt_binlog_row_level = FALSE; // Statement-level is default
+unsigned long opt_binlog_rows_event_max_size = 1024;
+
 #ifdef HAVE_INITGROUPS
 static bool calling_initgroups= FALSE; /* Used in SIGSEGV handler. */
 #endif
@@ -4127,6 +4130,7 @@
   OPT_SQL_BIN_UPDATE_SAME,     OPT_REPLICATE_DO_DB,
   OPT_REPLICATE_IGNORE_DB,     OPT_LOG_SLAVE_UPDATES,
   OPT_BINLOG_DO_DB,            OPT_BINLOG_IGNORE_DB,
+  OPT_BINLOG_FORMAT,           OPT_BINLOG_ROWS_EVENT_MAX_SIZE, 
   OPT_WANT_CORE,               OPT_CONCURRENT_INSERT,
   OPT_MEMLOCK,                 OPT_MYISAM_RECOVER,
   OPT_REPLICATE_REWRITE_DB,    OPT_SERVER_ID,
@@ -4335,12 +4339,27 @@
   {"bind-address", OPT_BIND_ADDRESS, "IP address to bind to.",
    (gptr*) &my_bind_addr_str, (gptr*) &my_bind_addr_str, 0, GET_STR,
    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+  {"binlog-format", OPT_BINLOG_FORMAT,
+   "Tell the master the form of logging to use: "
+   "either 'row' for row-level logging or "
+   "'statement' for statement-level logging.",
+   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },   
   {"binlog-do-db", OPT_BINLOG_DO_DB,
    "Tells the master it should log updates for the specified database, and exclude all others not explicitly mentioned.",
    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
   {"binlog-ignore-db", OPT_BINLOG_IGNORE_DB,
    "Tells the master that updates to the given database should not be logged tothe binary log.",
    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+  {"binlog-row-event-max-size", OPT_BINLOG_ROWS_EVENT_MAX_SIZE,
+   "The maximum size of a row-level event in bytes. "
+   "The value have to be an even multiple of 256.",
+   (gptr*) &opt_binlog_rows_event_max_size, 
+   (gptr*) &opt_binlog_rows_event_max_size, 0, 
+   GET_ULONG, REQUIRED_ARG, 
+   /* def_value */ 1024, /* min_value */  256, /* max_value */ ULONG_MAX, 
+   /* sub_size */     0, /* block_size */ 256, 
+   /* app_type */ 0
+  },
   {"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0,
    GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
   {"character-set-server", 'C', "Set the default character set.",
@@ -6194,6 +6213,26 @@
     binlog_ignore_db.push_back(db);
     break;
   }
+  case OPT_BINLOG_FORMAT:
+    if (strcmp(argument,"row") == 0) 
+    {
+      opt_binlog_row_level = TRUE;
+    }
+    else if (strcmp(argument, "statement") == 0) 
+    {
+      opt_binlog_row_level = FALSE;
+    }
+    else 
+    {
+      fprintf(stderr, 
+	      "Unknown binary log format: '%s' "
+	      "(Should be 'row' or 'statement')\n", 
+	      argument);
+      exit(1);
+    }
+
+    break;
+
   case (int)OPT_BINLOG_DO_DB:
   {
     i_string *db = new i_string(argument);

--- 1.241/sql/slave.cc	2005-03-09 13:02:37 +01:00
+++ 1.242/sql/slave.cc	2005-03-22 08:25:36 +01:00
@@ -26,6 +26,7 @@
 #include <thr_alarm.h>
 #include <my_dir.h>
 #include <sql_common.h>
+#include "rpl_tblmap.h"
 
 bool use_slave_mask = 0;
 MY_BITMAP slave_error_mask;
@@ -2534,7 +2535,6 @@
   group_relay_log_name[0]= event_relay_log_name[0]=
     group_master_log_name[0]= 0;
   last_slave_error[0]=0; until_log_name[0]= 0;
-
   bzero((char*) &info_file, sizeof(info_file));
   bzero((char*) &cache_buf, sizeof(cache_buf));
   cached_charset_invalidate();
@@ -3089,7 +3089,6 @@
           until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_GREATER);
 }
 
-
 void st_relay_log_info::cached_charset_invalidate()
 {
   /* Full of zeroes means uninitialized. */
@@ -3218,6 +3217,7 @@
       ev->when = time(NULL);
     ev->thd = thd;
     exec_res = ev->exec_event(rli);
+    DBUG_PRINT("info", ("exec_event result = %d", exec_res));
     DBUG_ASSERT(rli->sql_thd==thd);
     /*
        Format_description_log_event should not be deleted because it will be

--- 1.132/sql/sql_acl.cc	2005-03-18 02:16:30 +01:00
+++ 1.133/sql/sql_acl.cc	2005-03-22 08:25:36 +01:00
@@ -1530,7 +1530,7 @@
   }
   store_record(table,record[1]);
   table->field[2]->store(new_password, new_password_len, system_charset_info);
-  if ((error=table->file->update_row(table->record[1],table->record[0])))
+  if ((error=table->file->ha_update_row(table->record[1],table->record[0])))
   {
     table->file->print_error(error,MYF(0));	/* purecov: deadcode */
     goto end;					/* purecov: deadcode */
@@ -1733,14 +1733,14 @@
     */
     table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
     if (cmp_record(table,record[1]) &&
-	(error=table->file->update_row(table->record[1],table->record[0])))
+	(error=table->file->ha_update_row(table->record[1],table->record[0])))
     {						// This should never happen
       table->file->print_error(error,MYF(0));	/* purecov: deadcode */
       error= -1;				/* purecov: deadcode */
       goto end;					/* purecov: deadcode */
     }
   }
-  else if ((error=table->file->write_row(table->record[0]))) // insert
+  else if ((error=table->file->ha_write_row(table->record[0]))) // insert
   {						// This should never happen
     if (error && error != HA_ERR_FOUND_DUPP_KEY &&
 	error != HA_ERR_FOUND_DUPP_UNIQUE)	/* purecov: inspected */
@@ -1850,16 +1850,16 @@
     if (rights)
     {
       table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
-      if ((error=table->file->update_row(table->record[1],table->record[0])))
+      if ((error=table->file->ha_update_row(table->record[1],table->record[0])))
 	goto table_error;			/* purecov: deadcode */
     }
     else	/* must have been a revoke of all privileges */
     {
-      if ((error = table->file->delete_row(table->record[1])))
+      if ((error = table->file->ha_delete_row(table->record[1])))
 	goto table_error;			/* purecov: deadcode */
     }
   }
-  else if (rights && (error=table->file->write_row(table->record[0])))
+  else if (rights && (error=table->file->ha_write_row(table->record[0])))
   {
     if (error && error != HA_ERR_FOUND_DUPP_KEY) /* purecov: inspected */
       goto table_error; /* purecov: deadcode */
@@ -2220,9 +2220,9 @@
     if (old_row_exists)
     {
       if (privileges)
-	error=table->file->update_row(table->record[1],table->record[0]);
+	error=table->file->ha_update_row(table->record[1],table->record[0]);
       else
-	error=table->file->delete_row(table->record[1]);
+	error=table->file->ha_delete_row(table->record[1]);
       if (error)
       {
 	table->file->print_error(error,MYF(0)); /* purecov: inspected */
@@ -2237,7 +2237,7 @@
     }
     else					// new grant
     {
-      if ((error=table->file->write_row(table->record[0])))
+      if ((error=table->file->ha_write_row(table->record[0])))
       {
 	table->file->print_error(error,MYF(0)); /* purecov: inspected */
 	result= -1;				/* purecov: inspected */
@@ -2289,8 +2289,8 @@
 	if (privileges)
 	{
 	  int tmp_error;
-	  if ((tmp_error=table->file->update_row(table->record[1],
-						 table->record[0])))
+	  if ((tmp_error=table->file->ha_update_row(table->record[1],
+						    table->record[0])))
 	  {					/* purecov: deadcode */
 	    table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */
 	    result= -1;				/* purecov: deadcode */
@@ -2302,7 +2302,7 @@
 	else
 	{
 	  int tmp_error;
-	  if ((tmp_error = table->file->delete_row(table->record[1])))
+	  if ((tmp_error = table->file->ha_delete_row(table->record[1])))
 	  {					/* purecov: deadcode */
 	    table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */
 	    result= -1;				/* purecov: deadcode */
@@ -2409,15 +2409,15 @@
   {
     if (store_table_rights || store_col_rights)
     {
-      if ((error=table->file->update_row(table->record[1],table->record[0])))
+      if ((error=table->file->ha_update_row(table->record[1],table->record[0])))
 	goto table_error;			/* purecov: deadcode */
     }
-    else if ((error = table->file->delete_row(table->record[1])))
+    else if ((error = table->file->ha_delete_row(table->record[1])))
       goto table_error;				/* purecov: deadcode */
   }
   else
   {
-    error=table->file->write_row(table->record[0]);
+    error=table->file->ha_write_row(table->record[0]);
     if (error && error != HA_ERR_FOUND_DUPP_KEY)
       goto table_error;				/* purecov: deadcode */
   }
@@ -2521,15 +2521,15 @@
   {
     if (store_proc_rights)
     {
-      if ((error=table->file->update_row(table->record[1],table->record[0])))
+      if ((error=table->file->ha_update_row(table->record[1],table->record[0])))
 	goto table_error;
     }
-    else if ((error= table->file->delete_row(table->record[1])))
+    else if ((error= table->file->ha_delete_row(table->record[1])))
       goto table_error;
   }
   else
   {
-    error=table->file->write_row(table->record[0]);
+    error=table->file->ha_write_row(table->record[0]);
     if (error && error != HA_ERR_FOUND_DUPP_KEY)
       goto table_error;
   }
@@ -4294,13 +4294,13 @@
                       system_charset_info);
     user_field->store(user_to->user.str, user_to->user.length,
                       system_charset_info);
-    if ((error= table->file->update_row(table->record[1], table->record[0])))
+    if ((error= table->file->ha_update_row(table->record[1], table->record[0])))
       table->file->print_error(error, MYF(0));
   }
   else
   {
     /* delete */
-    if ((error=table->file->delete_row(table->record[0])))
+    if ((error=table->file->ha_delete_row(table->record[0])))
       table->file->print_error(error, MYF(0));
   }
 
@@ -5300,7 +5300,7 @@
     table->field[i++]->store(column, col_length, cs);
   table->field[i++]->store(priv, priv_length, cs);
   table->field[i]->store(is_grantable, strlen(is_grantable), cs);
-  table->file->write_row(table->record[0]);
+  table->file->ha_write_row(table->record[0]);
 }
 
 

--- 1.171/sql/sql_class.cc	2005-03-09 20:49:40 +01:00
+++ 1.172/sql/sql_class.cc	2005-03-22 08:25:36 +01:00
@@ -207,6 +207,7 @@
   ull=0;
   system_thread= cleanup_done= abort_on_warning= no_warnings_for_error= 0;
   peer_port= 0;					// For SHOW PROCESSLIST
+  transaction.m_pending_rows_event = 0;
 #ifdef	__WIN__
   real_id = 0;
 #endif
@@ -1804,4 +1805,129 @@
 void THD::set_status_var_init()
 {
   bzero((char*) &status_var, sizeof(status_var));
+}
+
+int THD::
+set_pending_event(Rows_log_event* ev) 
+{
+  DBUG_ENTER("THD::set_pending_event(Rows_log_event*)");
+  transaction.m_pending_rows_event = ev;
+  DBUG_RETURN(0);		// Ok
+}
+
+Rows_log_event* THD::
+get_pending_event() const 
+{
+  DBUG_ENTER("THD::get_pending_event()");
+  Rows_log_event* ev = transaction.m_pending_rows_event;
+  DBUG_RETURN(ev);
+}
+
+extern ulong opt_binlog_rows_event_max_size;
+
+/*
+  Template member function for ensuring that there is an rows log
+  event of the apropriate type before proceeding.
+
+  PRE CONDITION:
+    - Events of type 'RowEventT' have the type code 'type_code'.
+    
+  POST CONDITION:
+    If a non-NULL pointer is returned, the pending event for thread 'thd' will
+    be an event of type 'RowEventT' (which have the type code 'type_code')
+    will either empty or have enough space to hold 'needed' bytes.  In
+    addition, the columns bitvector will be correct for the row, meaning that
+    the pending event will be flushed if the columns in the event differ from
+    the columns suppled to the function.
+ */
+
+template <class RowsEventT>
+Rows_log_event* THD::
+prepare_pending(TABLE* table, uint32 server_id, 
+		bitvector const& cols, size_t needed) 
+{
+  // Fetch the type code for the RowsEventT template parameter
+  int const type_code = RowsEventT::TYPE_CODE;
+  DBUG_ENTER("THD::prepare_pending<RowsEventT>(TABLE*, ...)");
+  DBUG_PRINT("enter", ("table=%p (%s), type_code=%d, needed=%d", 
+		       table, table->s->table_name,
+		       type_code, needed));
+
+  Rows_log_event* pending = get_pending_event();
+
+  if (pending) 
+  {
+      DBUG_PRINT("info", ("pending=%p [type_code=%d, size=%d]",
+			  pending, 
+			  pending->get_type_code(),
+			  pending->get_data_size()));
+  }
+  else 
+  {
+      DBUG_PRINT("info", ("pending=%p", pending));
+  }
+
+  DBUG_PRINT("info", ("opt_binlog_rows_event_max_size=%d", 
+		      opt_binlog_rows_event_max_size));
+
+  // Check if the current event is non-NULL and a write-rows event. 
+  if (!pending
+      || pending->server_id != server_id
+      || pending->get_type_code() != type_code
+      || pending->get_data_size() + needed > opt_binlog_rows_event_max_size
+      || pending->get_cols() != cols) 
+  {
+    // If not, flush the event and create a new RowsEventT.
+    ulong const tid = mysql_bin_log.get_table_id(table);
+
+    Rows_log_event* const 
+	ev = new RowsEventT(this, table, tid, cols, 
+			    table->file->has_transactions());
+    ev->server_id = server_id; // I don't like this, it's too easy to forget. 
+    if (flush_and_set_pending_event(ev))
+      DBUG_RETURN(NULL);
+    DBUG_RETURN(ev);
+  }
+  DBUG_RETURN(pending);
+}
+
+/*
+  Instanciate the versions we need, we have -fno-implicit-template as
+  compiling option.
+*/
+
+template Rows_log_event* THD::
+prepare_pending<Write_rows_log_event>(TABLE*, uint32, bitvector const&, size_t);
+
+template Rows_log_event* THD::
+prepare_pending<Delete_rows_log_event>(TABLE*, uint32, bitvector const&, size_t);
+
+template Rows_log_event* THD::
+prepare_pending<Update_rows_log_event>(TABLE*, uint32, bitvector const&, size_t);
+
+
+int THD::
+flush_and_set_pending_event(Rows_log_event* event)
+{
+  DBUG_ENTER("THD::flush_and_set_event");
+  DBUG_PRINT("enter", ("thd = 0x%0x (%s event)", 
+		       this, 
+		       (event ? event->get_type_str() : "No")));
+
+  DBUG_ASSERT(opt_binlog_row_level);
+  DBUG_ASSERT(mysql_bin_log.is_open());
+  
+  if (Rows_log_event* pending = get_pending_event()) {
+    if (mysql_bin_log.write(pending)) {
+      DBUG_PRINT("exit", ("1"));
+      DBUG_RETURN(1);		// Something failed
+    }
+
+    delete pending;
+  }
+
+  set_pending_event(event);
+
+  DBUG_PRINT("exit", ("0"));
+  DBUG_RETURN(0);		// All OK
 }

--- 1.226/sql/sql_class.h	2005-03-15 15:11:40 +01:00
+++ 1.227/sql/sql_class.h	2005-03-22 08:25:36 +01:00
@@ -23,6 +23,8 @@
 
 // TODO: create log.h and move all the log header stuff there
 
+#include "rpl_tblmap.h"
+
 class Query_log_event;
 class Load_log_event;
 class Slave_log_event;
@@ -54,6 +56,9 @@
 #define TC_HEURISTIC_RECOVER_ROLLBACK 2
 extern uint tc_heuristic_recover;
 
+// Forward declaration
+class THD;
+
 /*
   Transaction Coordinator log - a base abstract class
   for two different implementations
@@ -234,6 +239,9 @@
   pthread_cond_t  COND_prep_xids;
   friend class Log_event;
 
+  table_mapping* m_table_map;
+  ulong m_next_table_id;
+
 public:
   MYSQL_LOG();
   /*
@@ -248,6 +256,10 @@
   void unlog(ulong cookie, my_xid xid);
   int recover(IO_CACHE *log, Format_description_log_event *fdle);
 
+  // This will return a table id for the table. If the table is not known, a
+  // new table id will be invented and returned. 
+  ulong get_table_id(TABLE* table);
+
   /*
      These describe the log's format. This is used only for relay logs.
      _for_exec is used by the SQL thread, _for_queue by the I/O thread. It's
@@ -1077,6 +1089,19 @@
   my_bool    tablespace_op;	/* This is TRUE in DISCARD/IMPORT TABLESPACE */
   /* container for handler's private per-connection data */
   void *ha_data[MAX_HA];
+
+  /*
+    Member functions to handle pending event for row-level logging.
+  */
+  Rows_log_event* get_pending_event() const;
+  int             set_pending_event(Rows_log_event* ev);
+  int             flush_and_set_pending_event(Rows_log_event*);
+
+  template <class RowsEventT>
+    Rows_log_event* 
+      prepare_pending(TABLE* table, uint32 server_id, 
+		      bitvector const& cols, size_t needed);
+
   struct st_transactions {
     SAVEPOINT *savepoints;
     THD_TRANS all;			// Trans since BEGIN WORK
@@ -1084,6 +1109,9 @@
     bool on;                            // see ha_enable_transaction()
     XID  xid;                           // transaction identifier
     enum xa_states xa_state;            // used by external XA only
+
+    Rows_log_event* m_pending_rows_event;
+
     /*
        Tables changed in transaction (that must be invalidated in query cache).
        List contain only transactional tables, that not invalidated in query

--- 1.142/sql/sql_delete.cc	2005-03-14 15:07:16 +01:00
+++ 1.143/sql/sql_delete.cc	2005-03-22 08:25:36 +01:00
@@ -98,7 +98,7 @@
 
   table->used_keys.clear_all();
   table->quick_keys.clear_all();		// Can't use 'only index'
-  select=make_select(table,0,0,conds,&error);
+  select=make_select(table, 0, 0, conds, 0, &error);
   if (error)
     DBUG_RETURN(TRUE);
   if ((select && select->check_quick(thd, safe_update, limit)) || !limit)

--- 1.144/sql/sql_insert.cc	2005-03-10 14:05:32 +01:00
+++ 1.145/sql/sql_insert.cc	2005-03-22 08:25:36 +01:00
@@ -313,6 +313,8 @@
                            (MODE_STRICT_TRANS_TABLES |
                             MODE_STRICT_ALL_TABLES)));
 
+  table->file->ha_stmt_begin();
+
   if (fields.elements && check_that_all_fields_are_given_values(thd, table))
   {
     /* thd->net.report_error is now set, which will abort the next loop */
@@ -404,6 +406,8 @@
       table->triggers->process_triggers(thd, TRG_EVENT_INSERT, TRG_ACTION_AFTER);
   }
 
+  table->file->ha_stmt_end();
+
   /*
     Now all rows are inserted.  Time to update logs and sends response to
     user
@@ -447,7 +451,7 @@
     if ((info.copied || info.deleted || info.updated) &&
 	(error <= 0 || !transactional_table))
     {
-      if (mysql_bin_log.is_open())
+      if (!opt_binlog_row_level && mysql_bin_log.is_open())
       {
         if (error <= 0)
           thd->clear_error();
@@ -743,10 +747,11 @@
   DBUG_ENTER("write_record");
 
   info->records++;
+
   if (info->handle_duplicates == DUP_REPLACE ||
       info->handle_duplicates == DUP_UPDATE)
   {
-    while ((error=table->file->write_row(table->record[0])))
+    while ((error=table->file->ha_write_row(table->record[0])))
     {
       uint key_nr;
       if (error != HA_WRITE_SKIP)
@@ -820,7 +825,7 @@
         if (res == VIEW_CHECK_ERROR)
           goto err;
 
-        if ((error=table->file->update_row(table->record[1],table->record[0])))
+        if ((error=table->file->ha_update_row(table->record[1],table->record[0])))
           goto err;
         info->updated++;
         break;
@@ -840,13 +845,13 @@
             (table->timestamp_field_type == TIMESTAMP_NO_AUTO_SET ||
              table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_BOTH))
         {
-          if ((error=table->file->update_row(table->record[1],
-					     table->record[0])))
+          if ((error=table->file->ha_update_row(table->record[1],
+						table->record[0])))
             goto err;
           info->deleted++;
           break;				/* Update logfile and count */
         }
-        else if ((error=table->file->delete_row(table->record[1])))
+        else if ((error=table->file->ha_delete_row(table->record[1])))
           goto err;
         info->deleted++;
         if (!table->file->has_transactions())
@@ -855,7 +860,7 @@
     }
     info->copied++;
   }
-  else if ((error=table->file->write_row(table->record[0])))
+  else if ((error=table->file->ha_write_row(table->record[0])))
   {
     if (!info->ignore ||
 	(error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE))

--- 1.301/sql/sql_select.cc	2005-03-20 08:03:35 +01:00
+++ 1.302/sql/sql_select.cc	2005-03-22 08:44:12 +01:00
@@ -8695,11 +8695,11 @@
   /* copy all old rows */
   while (!table->file->rnd_next(new_table.record[1]))
   {
-    if ((write_err=new_table.file->write_row(new_table.record[1])))
+    if ((write_err=new_table.file->ha_write_row(new_table.record[1])))
       goto err;
   }
   /* copy row that filled HEAP table */
-  if ((write_err=new_table.file->write_row(table->record[0])))
+  if ((write_err=new_table.file->ha_write_row(table->record[0])))
   {
     if (write_err != HA_ERR_FOUND_DUPP_KEY &&
 	write_err != HA_ERR_FOUND_DUPP_UNIQUE || !ignore_last_dupp_key_error)
@@ -9962,7 +9962,7 @@
     if (!join->having || join->having->val_int())
     {
       join->found_records++;
-      if ((error=table->file->write_row(table->record[0])))
+      if ((error=table->file->ha_write_row(table->record[0])))
       {
 	if (error == HA_ERR_FOUND_DUPP_KEY ||
 	    error == HA_ERR_FOUND_DUPP_UNIQUE)
@@ -10024,8 +10024,8 @@
   {						/* Update old record */
     restore_record(table,record[1]);
     update_tmptable_sum_func(join->sum_funcs,table);
-    if ((error=table->file->update_row(table->record[1],
-				       table->record[0])))
+    if ((error=table->file->ha_update_row(table->record[1],
+					  table->record[0])))
     {
       table->file->print_error(error,MYF(0));	/* purecov: inspected */
       DBUG_RETURN(-1);				/* purecov: inspected */
@@ -10048,7 +10048,7 @@
   }
   init_tmptable_sum_functions(join->sum_funcs);
   copy_funcs(join->tmp_table_param.items_to_copy);
-  if ((error=table->file->write_row(table->record[0])))
+  if ((error=table->file->ha_write_row(table->record[0])))
   {
     if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param,
 				error, 0))
@@ -10084,7 +10084,7 @@
   copy_fields(&join->tmp_table_param);		// Groups are copied twice.
   copy_funcs(join->tmp_table_param.items_to_copy);
 
-  if (!(error=table->file->write_row(table->record[0])))
+  if (!(error=table->file->ha_write_row(table->record[0])))
     join->send_records++;			// New group
   else
   {
@@ -10100,8 +10100,8 @@
     }
     restore_record(table,record[1]);
     update_tmptable_sum_func(join->sum_funcs,table);
-    if ((error=table->file->update_row(table->record[1],
-				       table->record[0])))
+    if ((error=table->file->ha_update_row(table->record[1],
+					  table->record[0])))
     {
       table->file->print_error(error,MYF(0));	/* purecov: inspected */
       DBUG_RETURN(-1);				/* purecov: inspected */
@@ -10990,7 +10990,7 @@
     }
     if (having && !having->val_int())
     {
-      if ((error=file->delete_row(record)))
+      if ((error=file->ha_delete_row(record)))
 	goto err;
       error=file->rnd_next(record);
       continue;
@@ -11017,7 +11017,7 @@
       }
       if (compare_record(table, first_field) == 0)
       {
-	if ((error=file->delete_row(record)))
+	if ((error=file->ha_delete_row(record)))
 	  goto err;
       }
       else if (!found)
@@ -11114,7 +11114,7 @@
     }
     if (having && !having->val_int())
     {
-      if ((error=file->delete_row(record)))
+      if ((error=file->ha_delete_row(record)))
 	goto err;
       continue;
     }
@@ -11131,7 +11131,7 @@
     if (hash_search(&hash, org_key_pos, key_length))
     {
       /* Duplicated found ; Remove the row */
-      if ((error=file->delete_row(record)))
+      if ((error=file->ha_delete_row(record)))
 	goto err;
     }
     else

--- 1.223/sql/sql_show.cc	2005-03-14 14:53:51 +01:00
+++ 1.224/sql/sql_show.cc	2005-03-22 08:25:37 +01:00
@@ -703,6 +703,17 @@
     packet->append(' ');
     packet->append(dir_type);
     packet->append(" DIRECTORY='", 12);
+#ifdef __WIN__
+    /* Convert \ to / to be able to create table on unix */
+    char *winfilename= (char*) thd->memdup(filename, length);
+    char *pos, *end;
+    for (pos= winfilename, end= pos+length ; pos < end ; pos++)
+    {
+      if (*pos == '\\')
+        *pos = '/';
+    }
+    filename= winfilename;
+#endif
     packet->append(filename, length);
     packet->append('\'');
   }
@@ -2481,13 +2492,8 @@
   definer= get_field(thd->mem_root, proc_table->field[11]);
   if (!full_access)
     full_access= !strcmp(sp_user, definer);
-  if (!full_access)
-  {
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-    if (check_some_routine_access(thd, (char * )sp_db, (char * )sp_name))
-      return;
-#endif
-  }
+  if (!full_access && check_some_routine_access(thd, sp_db, sp_name))
+    return;
 
   if (lex->orig_sql_command == SQLCOM_SHOW_STATUS_PROC &&
       proc_table->field[2]->val_int() == TYPE_ENUM_PROCEDURE ||
@@ -2499,36 +2505,30 @@
     if (!wild || !wild[0] || !wild_compare(sp_name, wild, 0))
     {
       table->field[3]->store(sp_name, strlen(sp_name), cs);
-      tmp_string.length(0);
       get_field(thd->mem_root, proc_table->field[3], &tmp_string);
       table->field[0]->store(tmp_string.ptr(), tmp_string.length(), cs);
       table->field[2]->store(sp_db, strlen(sp_db), cs);
-      tmp_string.length(0);
       get_field(thd->mem_root, proc_table->field[2], &tmp_string);
       table->field[4]->store(tmp_string.ptr(), tmp_string.length(), cs);
       if (proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION)
       {
-        tmp_string.length(0);
         get_field(thd->mem_root, proc_table->field[9], &tmp_string);
         table->field[5]->store(tmp_string.ptr(), tmp_string.length(), cs);
         table->field[5]->set_notnull();
       }
       if (full_access)
       {
-        tmp_string.length(0);
         get_field(thd->mem_root, proc_table->field[10], &tmp_string);
         table->field[7]->store(tmp_string.ptr(), tmp_string.length(), cs);
       }
       table->field[6]->store("SQL", 3, cs);
       table->field[10]->store("SQL", 3, cs);
-      tmp_string.length(0);
       get_field(thd->mem_root, proc_table->field[6], &tmp_string);
       table->field[11]->store(tmp_string.ptr(), tmp_string.length(), cs);
       if (proc_table->field[5]->val_int() == SP_CONTAINS_SQL)
       {
         table->field[12]->store("CONTAINS SQL", 12 , cs);
       }
-      tmp_string.length(0);
       get_field(thd->mem_root, proc_table->field[7], &tmp_string);
       table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs);
       bzero((char *)&time, sizeof(time));
@@ -2537,10 +2537,8 @@
       bzero((char *)&time, sizeof(time));
       ((Field_timestamp *) proc_table->field[13])->get_time(&time);
       table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
-      tmp_string.length(0);
       get_field(thd->mem_root, proc_table->field[14], &tmp_string);
       table->field[17]->store(tmp_string.ptr(), tmp_string.length(), cs);
-      tmp_string.length(0);
       get_field(thd->mem_root, proc_table->field[15], &tmp_string);
       table->field[18]->store(tmp_string.ptr(), tmp_string.length(), cs);
       table->field[19]->store(definer, strlen(definer), cs);

--- 1.226/sql/sql_table.cc	2005-03-17 08:46:36 +01:00
+++ 1.227/sql/sql_table.cc	2005-03-22 08:25:37 +01:00
@@ -3754,7 +3754,7 @@
     {
       copy_ptr->do_copy(copy_ptr);
     }
-    if ((error=to->file->write_row((byte*) to->record[0])))
+    if ((error=to->file->ha_write_row((byte*) to->record[0])))
     {
       if ((!ignore &&
 	   handle_duplicates != DUP_REPLACE) ||

--- 1.43/sql/sql_udf.cc	2005-03-14 14:53:51 +01:00
+++ 1.44/sql/sql_udf.cc	2005-03-22 08:25:37 +01:00
@@ -110,15 +110,15 @@
   */
   if (!tmp->func_init && !tmp->func_deinit && tmp->type != UDFTYPE_AGGREGATE)
   {
-    if (opt_allow_suspicious_udfs)
-      sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), nm);
-    else
+    if (!opt_allow_suspicious_udfs)
       return nm;
+    if (current_thd->variables.log_warnings)
+      sql_print_warning(ER(ER_CANT_FIND_DL_ENTRY), nm);
   }
-
   return 0;
 }
 
+
 extern "C" byte* get_hash_key(const byte *buff,uint *length,
 			      my_bool not_used __attribute__((unused)))
 {
@@ -127,9 +127,10 @@
   return (byte*) udf->name.str;
 }
 
+
 /*
-** Read all predeclared functions from mysql.func and accept all that
-** can be used.
+  Read all predeclared functions from mysql.func and accept all that
+  can be used.
 */
 
 void udf_init()

--- 1.150/sql/sql_update.cc	2005-03-14 14:53:51 +01:00
+++ 1.151/sql/sql_update.cc	2005-03-22 08:25:38 +01:00
@@ -219,7 +219,7 @@
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
   /* Check values */
   table_list->grant.want_privilege= table->grant.want_privilege=
-    (SELECT_ACL & ~~table->grant.privilege);
+    (SELECT_ACL & ~table->grant.privilege);
 #endif
   if (setup_fields(thd, 0, table_list, values, 1, 0, 0))
   {
@@ -229,7 +229,7 @@
 
   // Don't count on usage of 'only index' when calculating which key to use
   table->used_keys.clear_all();
-  select=make_select(table,0,0,conds,&error);
+  select= make_select(table, 0, 0, conds, 0, &error);
   if (error ||
       (select && select->check_quick(thd, safe_update, limit)) || !limit)
   {

--- 1.26/mysql-test/t/ctype_ucs.test	2005-03-14 15:07:16 +01:00
+++ 1.27/mysql-test/t/ctype_ucs.test	2005-03-22 08:44:12 +01:00
@@ -338,7 +338,8 @@
 set @v=convert('abc' using ucs2);
 reset master;
 insert into t2 values (@v);
-show binlog events from 100;
+--replace_column 2 # 5 #
+show binlog events from 102;
 # more important than SHOW BINLOG EVENTS, mysqlbinlog (where we
 # absolutely need variables names to be quoted and strings to be
 # escaped).

--- 1.16/mysql-test/r/mysqlbinlog.result	2005-03-16 02:32:40 +01:00
+++ 1.17/mysql-test/r/mysqlbinlog.result	2005-03-22 08:25:32 +01:00
@@ -149,11 +149,6 @@
 /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
 /*!40019 SET @@session.max_insert_delayed_threads=0*/;
 /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
-use test;
-SET TIMESTAMP=1108844556;
-BEGIN;
-SET TIMESTAMP=1108844555;
-insert t1 values (1);
 ROLLBACK;
 /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
 drop table t1, t2;

--- 1.15/mysql-test/t/mysqlbinlog.test	2005-03-14 15:07:16 +01:00
+++ 1.16/mysql-test/t/mysqlbinlog.test	2005-03-22 08:44:12 +01:00
@@ -24,7 +24,6 @@
 load data infile '../../std_data/words.dat' into table t1;
 load data infile '../../std_data/words.dat' into table t1;
 load data infile '../../std_data/words.dat' into table t1;
-load data infile '../../std_data/words.dat' into table t1;
 # simple query to show more in second binlog
 insert into t1 values ("Alas");
 flush logs;
@@ -61,7 +60,7 @@
 select "--- --position --" as "";
 --enable_query_log
 --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
---exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ --position=123 $MYSQL_TEST_DIR/var/log/master-bin.000002
+--exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ --position=236 $MYSQL_TEST_DIR/var/log/master-bin.000002
 
 # These are tests for remote binlog.
 # They should return the same as previous test.
@@ -93,7 +92,7 @@
 select "--- --position --" as "";
 --enable_query_log
 --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
---exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ --read-from-remote-server --position=123 --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002
+--exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ --read-from-remote-server --position=236 --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002
 
 # Bug#7853 (mysqlbinlog does not accept input from stdin)
 --disable_query_log

--- 1.14/mysql-test/t/rpl_until.test	2005-03-14 10:33:45 +01:00
+++ 1.15/mysql-test/t/rpl_until.test	2005-03-22 08:44:12 +01:00
@@ -24,7 +24,7 @@
 
 # try to replicate all queries until drop of t1
 connection slave;
-start slave until master_log_file='master-bin.000001', master_log_pos=308;
+start slave until master_log_file='master-bin.000001', master_log_pos=325;
 sleep 2;
 # here table should be still not deleted
 select * from t1;
@@ -42,7 +42,7 @@
 show slave status;
 
 # try replicate all until second insert to t2;
-start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=710;
+start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=751;
 sleep 4;
 select * from t2;
 --replace_result $MASTER_MYPORT MASTER_MYPORT
@@ -58,7 +58,7 @@
 stop slave;
 
 # this should stop immediately as we are already there
-start slave until master_log_file='master-bin.000001', master_log_pos=714;
+start slave until master_log_file='master-bin.000001', master_log_pos=787;
 # 2 is not enough when running with valgrind
 real_sleep 4
 # here the sql slave thread should be stopped
@@ -77,6 +77,6 @@
 start slave until relay_log_file='slave-relay-bin.000002';
 --error 1277
 start slave until relay_log_file='slave-relay-bin.000002', master_log_pos=565;
-
+# Warning should be given for second command
 start slave sql_thread;
-start slave until master_log_file='master-bin.000001', master_log_pos=714;
+start slave until master_log_file='master-bin.000001', master_log_pos=787;

--- 1.11/mysql-test/t/rpl_user_variables.test	2005-03-14 15:07:16 +01:00
+++ 1.12/mysql-test/t/rpl_user_variables.test	2005-03-22 08:44:12 +01:00
@@ -46,7 +46,8 @@
 connection slave;
 sync_with_master;
 select * from t1;
-show binlog events from 100;
+--replace_column 2 # 5 #
+show binlog events from 102;
 connection master;
 drop table t1;
 save_master_pos;

--- 1.13/mysql-test/t/mix_innodb_myisam_binlog.test	2005-03-14 15:07:16 +01:00
+++ 1.14/mysql-test/t/mix_innodb_myisam_binlog.test	2005-03-22 08:44:12 +01:00
@@ -27,7 +27,7 @@
 
 --replace_column 5 #
 --replace_result "xid=12" "xid=7"
-show binlog events from 100;
+show binlog events from 102;
 
 delete from t1;
 delete from t2;
@@ -40,7 +40,7 @@
 rollback;
 
 --replace_column 5 #
-show binlog events from 100;
+show binlog events from 102;
 
 delete from t1;
 delete from t2;
@@ -56,7 +56,7 @@
 
 --replace_column 5 #
 --replace_result "xid=45" "xid=24"
-show binlog events from 100;
+show binlog events from 102;
 
 delete from t1;
 delete from t2;
@@ -74,7 +74,7 @@
 
 --replace_column 5 #
 --replace_result "xid=67" "xid=36"
-show binlog events from 100;
+show binlog events from 102;
 
 # and when ROLLBACK is not explicit?
 delete from t1;
@@ -95,7 +95,7 @@
 # logging has been done, we use a user lock.
 select get_lock("a",10);
 --replace_column 5 #
-show binlog events from 100;
+show binlog events from 102;
 
 # and when not in a transact1on?
 delete from t1;
@@ -107,7 +107,7 @@
 
 --replace_column 5 #
 --replace_result "xid=116" "xid=59"
-show binlog events from 100;
+show binlog events from 102;
 
 # Check that when the query updat1ng the MyISAM table is the first in the
 # transaction, we log it immediately.
@@ -120,13 +120,13 @@
 insert into t2 select * from t1;
 --replace_column 5 #
 --replace_result "xid=130" "xid=65"
-show binlog events from 100;
+show binlog events from 102;
 insert into t1 values(11);
 commit;
 
 --replace_column 5 #
 --replace_result "xid=130" "xid=65" "xid=133" "xid=67"
-show binlog events from 100;
+show binlog events from 102;
 
 
 # Check that things work like before this BEGIN/ROLLBACK code was added,
@@ -145,7 +145,7 @@
 
 --replace_column 5 #
 --replace_result "xid=152" "xid=77"
-show binlog events from 100;
+show binlog events from 102;
 
 delete from t1;
 delete from t2;
@@ -157,7 +157,7 @@
 rollback;
 
 --replace_column 5 #
-show binlog events from 100;
+show binlog events from 102;
 
 delete from t1;
 delete from t2;
@@ -173,7 +173,7 @@
 
 --replace_column 5 #
 --replace_result "xid=184" "xid=93"
-show binlog events from 100;
+show binlog events from 102;
 
 delete from t1;
 delete from t2;
@@ -191,7 +191,7 @@
 
 --replace_column 5 #
 --replace_result "xid=205" "xid=104"
-show binlog events from 100;
+show binlog events from 102;
 
 # Test for BUG#5714, where a MyISAM update in the transaction used to
 # release row-level locks in InnoDB

--- 1.4/mysql-test/t/mysqlbinlog2.test	2005-03-14 15:07:16 +01:00
+++ 1.5/mysql-test/t/mysqlbinlog2.test	2005-03-22 08:44:12 +01:00
@@ -46,11 +46,11 @@
 --disable_query_log
 select "--- start-position --" as "";
 --enable_query_log
---exec $MYSQL_BINLOG --short-form --start-position=606 $MYSQL_TEST_DIR/var/log/master-bin.000001 
+--exec $MYSQL_BINLOG --short-form --start-position=608 $MYSQL_TEST_DIR/var/log/master-bin.000001 
 --disable_query_log
 select "--- stop-position --" as "";
 --enable_query_log
---exec $MYSQL_BINLOG --short-form --stop-position=606 $MYSQL_TEST_DIR/var/log/master-bin.000001 
+--exec $MYSQL_BINLOG --short-form --stop-position=608 $MYSQL_TEST_DIR/var/log/master-bin.000001 
 --disable_query_log
 select "--- start-datetime --" as "";
 --enable_query_log
@@ -75,11 +75,11 @@
 --disable_query_log
 select "--- start-position --" as "";
 --enable_query_log
---exec $MYSQL_BINLOG --short-form --start-position=606 $MYSQL_TEST_DIR/var/log/master-bin.000001 $MYSQL_TEST_DIR/var/log/master-bin.000002
+--exec $MYSQL_BINLOG --short-form --start-position=608 $MYSQL_TEST_DIR/var/log/master-bin.000001 $MYSQL_TEST_DIR/var/log/master-bin.000002
 --disable_query_log
 select "--- stop-position --" as "";
 --enable_query_log
---exec $MYSQL_BINLOG --short-form --stop-position=128 $MYSQL_TEST_DIR/var/log/master-bin.000001 $MYSQL_TEST_DIR/var/log/master-bin.000002
+--exec $MYSQL_BINLOG --short-form --stop-position=130 $MYSQL_TEST_DIR/var/log/master-bin.000001 $MYSQL_TEST_DIR/var/log/master-bin.000002
 --disable_query_log
 select "--- start-datetime --" as "";
 --enable_query_log
@@ -102,11 +102,11 @@
 --disable_query_log
 select "--- start-position --" as "";
 --enable_query_log
---exec $MYSQL_BINLOG --short-form --start-position=606 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 
+--exec $MYSQL_BINLOG --short-form --start-position=608 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 
 --disable_query_log
 select "--- stop-position --" as "";
 --enable_query_log
---exec $MYSQL_BINLOG --short-form --stop-position=606 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 
+--exec $MYSQL_BINLOG --short-form --stop-position=608 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 
 --disable_query_log
 select "--- start-datetime --" as "";
 --enable_query_log
@@ -129,11 +129,11 @@
 --disable_query_log
 select "--- start-position --" as "";
 --enable_query_log
---exec $MYSQL_BINLOG --short-form --start-position=606 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001  master-bin.000002
+--exec $MYSQL_BINLOG --short-form --start-position=608 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001  master-bin.000002
 --disable_query_log
 select "--- stop-position --" as "";
 --enable_query_log
---exec $MYSQL_BINLOG --short-form --stop-position=128 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001  master-bin.000002
+--exec $MYSQL_BINLOG --short-form --stop-position=130 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001  master-bin.000002
 --disable_query_log
 select "--- start-datetime --" as "";
 --enable_query_log

--- 1.15/mysql-test/t/rpl_charset.test	2005-03-14 15:07:16 +01:00
+++ 1.16/mysql-test/t/rpl_charset.test	2005-03-22 08:44:12 +01:00
@@ -107,7 +107,7 @@
 drop database mysqltest2;
 drop database mysqltest3;
 --replace_column 2 # 5 #
-show binlog events from 100;
+show binlog events from 102;
 sync_slave_with_master;
 
 # Check that we can change global.collation_server (since 5.0.3)

--- 1.3/mysql-test/t/rpl_deadlock.test	2005-03-16 02:32:41 +01:00
+++ 1.4/mysql-test/t/rpl_deadlock.test	2005-03-22 08:44:12 +01:00
@@ -68,7 +68,7 @@
 # 2) Test lock wait timeout
 
 stop slave;
-change master to master_log_pos=536; # the BEGIN log event
+change master to master_log_pos=540; # the BEGIN log event
 begin;
 select * from t2 for update; # hold lock
 start slave;
@@ -89,7 +89,7 @@
 
 # This is really copy-paste of 2) of above
 stop slave;
-change master to master_log_pos=536;
+change master to master_log_pos=540;
 begin;
 select * from t2 for update;
 start slave;

--- 1.13/mysql-test/t/rpl_error_ignored_table.test	2005-03-14 15:07:16 +01:00
+++ 1.14/mysql-test/t/rpl_error_ignored_table.test	2005-03-22 08:44:12 +01:00
@@ -48,7 +48,8 @@
 --error 0,1053;
 reap;
 connection master1;
-show binlog events from 100;
+--replace_column 2 # 5 #
+show binlog events from 102;
 save_master_pos;
 connection slave;
 # SQL slave thread should not have stopped (because table of the killed

--- 1.8/mysql-test/t/rpl_loaddata_rule_m.test	2005-03-14 15:07:16 +01:00
+++ 1.9/mysql-test/t/rpl_loaddata_rule_m.test	2005-03-22 08:44:12 +01:00
@@ -19,5 +19,9 @@
 create table t1(a int, b int, unique(b));
 use mysqltest;
 load data infile '../../std_data/rpl_loaddata.dat' into table test.t1;
-show binlog events from 100; # should be nothing
+# Starting from 5.0.3 LOAD DATA is replicated much in the same way as ordinary
+# query so "show binlog ..." should show two events (before 5.0.3 no events
+# were returned).
+--replace_column 2 # 5 #
+show binlog events from 102;
 drop database mysqltest;

--- 1.6/mysql-test/t/rpl_loaddata_rule_s.test	2005-03-14 15:07:16 +01:00
+++ 1.7/mysql-test/t/rpl_loaddata_rule_s.test	2005-03-22 08:44:12 +01:00
@@ -17,4 +17,4 @@
 connection slave;
 sync_with_master;
 select count(*) from t1; # check that LOAD was replicated
-show binlog events from 100; # should be nothing
+show binlog events from 102; # should be nothing

--- 1.5/mysql-test/t/rpl_multi_query.test	2005-03-16 02:32:41 +01:00
+++ 1.6/mysql-test/t/rpl_multi_query.test	2005-03-22 08:44:12 +01:00
@@ -24,6 +24,6 @@
 select * from mysqltest.t1;
 connection master;
 --replace_column 2 # 5 #
-show binlog events from 98;
+show binlog events from 102;
 drop database mysqltest;
 sync_slave_with_master;

--- 1.71/sql/sp.cc	2005-03-10 20:42:21 +01:00
+++ 1.72/sql/sp.cc	2005-03-22 08:25:36 +01:00
@@ -422,7 +422,7 @@
 	      system_charset_info);
 
     ret= SP_OK;
-    if (table->file->write_row(table->record[0]))
+    if (table->file->ha_write_row(table->record[0]))
       ret= SP_WRITE_ROW_FAILED;
   }
 
@@ -447,7 +447,7 @@
   ret= db_find_routine_aux(thd, type, name, TL_WRITE, &table, &opened);
   if (ret == SP_OK)
   {
-    if (table->file->delete_row(table->record[0]))
+    if (table->file->ha_delete_row(table->record[0]))
       ret= SP_DELETE_ROW_FAILED;
   }
 
@@ -483,7 +483,7 @@
       table->field[MYSQL_PROC_FIELD_COMMENT]->store(chistics->comment.str,
 						    chistics->comment.length,
 						    system_charset_info);
-    if ((table->file->update_row(table->record[1],table->record[0])))
+    if ((table->file->ha_update_row(table->record[1],table->record[0])))
       ret= SP_WRITE_ROW_FAILED;
   }
   if (opened)
@@ -708,7 +708,7 @@
     bool deleted= FALSE;
 
     do {
-      if (! table->file->delete_row(table->record[0]))
+      if (! table->file->ha_delete_row(table->record[0]))
 	deleted= TRUE;		/* We deleted something */
       else
       {

--- 1.33/mysql-test/t/rpl_log_pos.test	2005-03-14 15:07:16 +01:00
+++ 1.34/mysql-test/t/rpl_log_pos.test	2005-03-22 08:44:12 +01:00
@@ -38,7 +38,7 @@
 save_master_pos;
 connection slave;
 stop slave;
-change master to master_log_pos=100;
+change master to master_log_pos=102;
 start slave;
 sync_with_master;
 select * from t1;

--- 1.25/mysql-test/t/rpl_log.test	2005-03-14 15:07:16 +01:00
+++ 1.26/mysql-test/t/rpl_log.test	2005-03-22 08:44:12 +01:00
@@ -38,9 +38,9 @@
 drop table t1;
 --replace_result $VERSION VERSION
 show binlog events;
-show binlog events from 100 limit 1;
-show binlog events from 100 limit 2;
-show binlog events from 100 limit 2,1;
+show binlog events from 102 limit 1;
+show binlog events from 102 limit 2;
+show binlog events from 102 limit 2,1;
 flush logs;
 
 # We need an extra update before doing save_master_pos.

--- 1.23/mysql-test/t/user_var.test	2005-03-14 15:07:16 +01:00
+++ 1.24/mysql-test/t/user_var.test	2005-03-22 08:44:12 +01:00
@@ -108,7 +108,8 @@
 set @var1= "';aaa";
 SET @var2=char(ascii('a'));
 insert into t1 values (@var1),(@var2);
-show binlog events from 100;
+--replace_column 2 # 5 #
+show binlog events from 102;
 # more important than SHOW BINLOG EVENTS, mysqlbinlog (where we
 # absolutely need variables names to be quoted and strings to be
 # escaped).

--- 1.4/mysql-test/t/binlog.test	2005-03-16 21:12:22 +01:00
+++ 1.5/mysql-test/t/binlog.test	2005-03-22 08:44:12 +01:00
@@ -20,7 +20,7 @@
 # first COMMIT must be Query_log_event, second - Xid_log_event
 --replace_result "xid=18" "xid=11"
 --replace_column 2 # 5 #
-show binlog events from 98;
+show binlog events from 102;
 drop table t1,t2;
 
 #
@@ -42,7 +42,7 @@
 drop table t1;
 --replace_result "xid=29" "xid=18"
 --replace_column 2 # 5 #
-show binlog events in 'master-bin.000001' from 98;
+show binlog events in 'master-bin.000001' from 102;
 --replace_column 2 # 5 #
-show binlog events in 'master-bin.000002' from 98;
+show binlog events in 'master-bin.000002' from 102;
 
Thread
bk commit into 5.1 tree (mats:1.1797)Mats Kindahl22 Mar