List:Internals« Previous MessageNext Message »
From:lars Date:April 8 2005 1:27pm
Subject:bk commit into 5.1 tree (mysqldev:1.1854)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of mysqldev. When mysqldev 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.1854 05/04/08 13:27:31 mysqldev@stripped +34 -0
  Merge

  sql/ha_ndbcluster.cc
    1.200 05/04/08 11:24:23 mysqldev@stripped +0 -0
    Auto merged

  sql/sql_table.cc
    1.230 05/04/08 11:24:26 mysqldev@stripped +0 -0
    Auto merged

  sql/handler.h
    1.134 05/04/08 11:24:24 mysqldev@stripped +0 -0
    Auto merged

  sql/handler.cc
    1.155 05/04/08 11:24:24 mysqldev@stripped +0 -0
    Auto merged

  sql/ha_ndbcluster.h
    1.85 05/04/08 11:24:23 mysqldev@stripped +0 -0
    Auto merged

  sql/sql_update.cc
    1.153 05/04/08 11:24:26 mysqldev@stripped +0 -0
    Auto merged

  sql/sql_union.cc
    1.115 05/04/08 11:24:26 mysqldev@stripped +0 -0
    Auto merged

  sql/sql_insert.cc
    1.146 05/04/08 11:24:25 mysqldev@stripped +0 -0
    Auto merged

  sql/sql_class.h
    1.229 05/04/08 11:24:25 mysqldev@stripped +0 -0
    Auto merged

  sql/sql_class.cc
    1.175 05/04/08 11:24:25 mysqldev@stripped +0 -0
    Auto merged

  sql/sql_acl.h
    1.35 05/04/08 11:24:25 mysqldev@stripped +0 -0
    Auto merged

  sql/sql_acl.cc
    1.136 05/04/08 11:24:25 mysqldev@stripped +0 -0
    Auto merged

  sql/slave.cc
    1.244 05/04/08 11:24:25 mysqldev@stripped +0 -1
    Auto merged

  sql/mysqld.cc
    1.446 05/04/08 11:24:24 mysqldev@stripped +0 -0
    Auto merged

  sql/mysql_priv.h
    1.285 05/04/08 11:24:24 mysqldev@stripped +0 -0
    Auto merged

  sql/log_event.h
    1.110 05/04/08 11:24:24 mysqldev@stripped +0 -0
    Auto merged

  sql/log_event.cc
    1.172 05/04/08 11:24:24 mysqldev@stripped +0 -0
    Auto merged

  sql/log.cc
    1.160 05/04/08 11:24:24 mysqldev@stripped +0 -0
    Auto merged

  sql/item_sum.cc
    1.136 05/04/08 11:24:24 mysqldev@stripped +0 -0
    Auto merged

  scripts/mysql_fix_privilege_tables.sql
    1.17 05/04/08 11:24:23 mysqldev@stripped +0 -0
    Auto merged

  scripts/mysql_create_system_tables.sh
    1.20 05/04/08 11:24:23 mysqldev@stripped +0 -0
    Auto merged

  ndb/src/kernel/blocks/dbdict/Dbdict.cpp
    1.44 05/04/08 11:24:23 mysqldev@stripped +0 -0
    Auto merged

  mysql-test/t/user_var.test
    1.26 05/04/08 11:24:23 mysqldev@stripped +0 -0
    Auto merged

  mysql-test/t/ctype_ucs.test
    1.29 05/04/08 11:24:23 mysqldev@stripped +0 -0
    Auto merged

  mysql-test/r/user_var.result
    1.32 05/04/08 11:24:23 mysqldev@stripped +0 -0
    Auto merged

  mysql-test/r/show_check.result
    1.65 05/04/08 11:24:23 mysqldev@stripped +0 -0
    Auto merged

  mysql-test/r/rpl_timezone.result
    1.13 05/04/08 11:24:22 mysqldev@stripped +0 -0
    Auto merged

  mysql-test/r/rpl_temporary.result
    1.22 05/04/08 11:24:22 mysqldev@stripped +0 -0
    Auto merged

  mysql-test/r/ps_1general.result
    1.32 05/04/08 11:24:22 mysqldev@stripped +0 -0
    Auto merged

  mysql-test/r/information_schema.result
    1.41 05/04/08 11:24:22 mysqldev@stripped +0 -0
    Auto merged

  mysql-test/r/ctype_ucs.result
    1.36 05/04/08 11:24:22 mysqldev@stripped +0 -0
    Auto merged

  mysql-test/mysql-test-run.sh
    1.256 05/04/08 11:24:22 mysqldev@stripped +0 -0
    Auto merged

  configure.in
    1.256 05/04/08 11:24:22 mysqldev@stripped +0 -0
    Auto merged

  BitKeeper/etc/logging_ok
    1.282 05/04/08 11:24:14 mysqldev@stripped +0 -0
    auto-union

# 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:	mysqldev
# Host:	production.mysql.com
# Root:	/data0/mysqldev/lars/RESYNC

--- 1.255/configure.in	2005-04-05 18:18:05 +02:00
+++ 1.256/configure.in	2005-04-08 11:24:22 +02:00
@@ -19,7 +19,6 @@
 NDB_VERSION_MAJOR=5
 NDB_VERSION_MINOR=1
 NDB_VERSION_BUILD=0
-NDB_VERSION_STATUS="alpha"
 
 # Set all version vars based on $VERSION. How do we do this more elegant ?
 # Remember that regexps needs to quote [ and ] since this is run through m4
@@ -38,6 +37,7 @@
 sinclude(config/ac-macros/compiler_flag.m4)
 sinclude(config/ac-macros/ha_archive.m4)
 sinclude(config/ac-macros/ha_berkeley.m4)
+sinclude(config/ac-macros/ha_blackhole.m4)
 sinclude(config/ac-macros/ha_example.m4)
 sinclude(config/ac-macros/ha_federated.m4)
 sinclude(config/ac-macros/ha_innodb.m4)
@@ -353,7 +353,8 @@
   then
     if $CXX -v 2>&1 | grep 'version 3' > /dev/null 2>&1
     then
-      CXXFLAGS="$CXXFLAGS -DUSE_MYSYS_NEW -DDEFINE_CXA_PURE_VIRTUAL"
+     # Statically link the language support function's found in libsupc++.a
+     LIBS="$LIBS -lsupc++"
     fi
   fi
 fi
@@ -2373,11 +2374,13 @@
 AC_SUBST(readline_link)
 AC_SUBST(readline_h_ln_cmd)
 
+MYSQL_CHECK_BIG_TABLES
 MYSQL_CHECK_BDB
 MYSQL_CHECK_INNODB
 MYSQL_CHECK_EXAMPLEDB
 MYSQL_CHECK_ARCHIVEDB
 MYSQL_CHECK_CSVDB
+MYSQL_CHECK_BLACKHOLEDB
 MYSQL_CHECK_NDBCLUSTER
 MYSQL_CHECK_FEDERATED
 

--- 1.255/mysql-test/mysql-test-run.sh	2005-03-22 12:30:42 +01:00
+++ 1.256/mysql-test/mysql-test-run.sh	2005-04-08 11:24:22 +02:00
@@ -222,6 +222,7 @@
 EXTRA_MASTER_OPT=""
 EXTRA_MYSQL_TEST_OPT=""
 EXTRA_MYSQLDUMP_OPT=""
+EXTRA_MYSQLSHOW_OPT=""
 EXTRA_MYSQLBINLOG_OPT=""
 USE_RUNNING_SERVER=0
 USE_NDBCLUSTER=@USE_NDBCLUSTER@
@@ -238,7 +239,7 @@
 SLEEP_TIME_FOR_FIRST_MASTER=400		# Enough time to create innodb tables
 SLEEP_TIME_FOR_SECOND_MASTER=400
 SLEEP_TIME_FOR_FIRST_SLAVE=400
-SLEEP_TIME_FOR_SECOND_SLAVE=30
+SLEEP_TIME_FOR_SECOND_SLAVE=300
 CHARACTER_SET=latin1
 DBUSER=""
 START_WAIT_TIMEOUT=10
@@ -453,6 +454,8 @@
        --debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysqltest.trace"
       EXTRA_MYSQLDUMP_OPT="$EXTRA_MYSQLDUMP_OPT \
        --debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysqldump.trace"
+      EXTRA_MYSQLSHOW_OPT="$EXTRA_MYSQLSHOW_OPT \
+       --debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysqlshow.trace"
       EXTRA_MYSQLBINLOG_OPT="$EXTRA_MYSQLBINLOG_OPT \
        --debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysqlbinlog.trace"
      
EXTRA_MYSQL_CLIENT_TEST_OPT="--debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysql_client_test.trace"
@@ -556,6 +559,11 @@
  else
    MYSQL_DUMP="$BASEDIR/client/mysqldump"
  fi
+ if [ -f "$BASEDIR/client/.libs/mysqlshow" ] ; then
+   MYSQL_SHOW="$BASEDIR/client/.libs/mysqlshow"
+ else
+   MYSQL_SHOW="$BASEDIR/client/mysqlshow"
+ fi
  if [ -f "$BASEDIR/client/.libs/mysqlbinlog" ] ; then
    MYSQL_BINLOG="$BASEDIR/client/.libs/mysqlbinlog"
  else
@@ -627,6 +635,7 @@
  fi
  MYSQL_TEST="$CLIENT_BINDIR/mysqltest"
  MYSQL_DUMP="$CLIENT_BINDIR/mysqldump"
+ MYSQL_SHOW="$CLIENT_BINDIR/mysqlshow"
  MYSQL_BINLOG="$CLIENT_BINDIR/mysqlbinlog"
  MYSQLADMIN="$CLIENT_BINDIR/mysqladmin"
  WAIT_PID="$CLIENT_BINDIR/mysql_waitpid"
@@ -697,10 +706,11 @@
 
 MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST --no-defaults --testcase --user=root
--socket=$MASTER_MYSOCK --port=$MYSQL_TCP_PORT --silent $EXTRA_MYSQL_CLIENT_TEST_OPT"
 MYSQL_DUMP="$MYSQL_DUMP --no-defaults -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD
$EXTRA_MYSQLDUMP_OPT"
+MYSQL_SHOW="$MYSQL_SHOW -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD
$EXTRA_MYSQLSHOW_OPT"
 MYSQL_BINLOG="$MYSQL_BINLOG --no-defaults --local-load=$MYSQL_TMP_DIR 
--character-sets-dir=$CHARSETSDIR $EXTRA_MYSQLBINLOG_OPT"
 MYSQL_FIX_SYSTEM_TABLES="$MYSQL_FIX_SYSTEM_TABLES --no-defaults --host=localhost
--port=$MASTER_MYPORT --socket=$MASTER_MYSOCK --user=root --password=$DBPASSWD
--basedir=$BASEDIR --bindir=$CLIENT_BINDIR --verbose"
 MYSQL="$MYSQL --host=localhost --port=$MASTER_MYPORT --socket=$MASTER_MYSOCK --user=root
--password=$DBPASSWD"
-export MYSQL MYSQL_DUMP MYSQL_BINLOG MYSQL_FIX_SYSTEM_TABLES
+export MYSQL MYSQL_DUMP MYSQL_SHOW MYSQL_BINLOG MYSQL_FIX_SYSTEM_TABLES
 export CLIENT_BINDIR MYSQL_CLIENT_TEST CHARSETSDIR
 export NDB_TOOLS_DIR
 export NDB_MGM
@@ -731,7 +741,7 @@
   XTERM=`which xterm`
 fi
 
-export MYSQL MYSQL_DUMP MYSQL_BINLOG MYSQL_FIX_SYSTEM_TABLES CLIENT_BINDIR MASTER_MYSOCK
+export MYSQL MYSQL_DUMP MYSQL_SHOW MYSQL_BINLOG MYSQL_FIX_SYSTEM_TABLES CLIENT_BINDIR
MASTER_MYSOCK
 
 #++
 # Function Definitions

--- 1.154/sql/handler.cc	2005-03-30 15:00:27 +02:00
+++ 1.155/sql/handler.cc	2005-04-08 11:24:24 +02: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"
@@ -1738,6 +1739,13 @@
     #   Error
 */
 
+#ifdef USE_PREPARE_CODE
+int handler::prepare_delete_table(const char *name)
+{
+  return 0;
+}
+#endif
+
 int handler::delete_table(const char *name)
 {
   int error= 0;
@@ -1760,6 +1768,13 @@
 }
 
 
+#ifdef USE_PREPARE_CODE
+int handler::prepare_rename_table(const char * from, const char * to)
+{
+  return 0;
+}
+#endif
+
 int handler::rename_table(const char * from, const char * to)
 {
   DBUG_ENTER("handler::rename_table");
@@ -2400,4 +2415,125 @@
     *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
+  DBUG_PRINT("info", ("Writing row to actual handler"));
+  if (int error = write_row(buf)) {
+    DBUG_PRINT("exit", ("error = %d", error));
+    DBUG_RETURN(error);
+  }
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+  DBUG_PRINT("info", ("Writing row to THD"));
+  if (table->s->tmp_table == NO_TMP_TABLE 
+      && !this->is_injective()) 
+  {
+    bitvector const cols(table->s->fields, true);
+    thd->write_row(table, cols, buf);
+  }
+#endif
+  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);
+  }
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+  if (table->s->tmp_table == NO_TMP_TABLE
+      && !this->is_injective()) 
+  {
+    bitvector const cols(table->s->fields, true);
+    thd->update_row(table, cols, old_data, new_data);
+  }
+#endif
+  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);
+  }
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+  if (table->s->tmp_table == NO_TMP_TABLE
+      && !this->is_injective()) 
+  {
+    bitvector const cols(table->s->fields, true);
+    thd->delete_row(table, cols, buf);
+  }
+#endif
+  DBUG_PRINT("exit", ("error = %d", 0));
+  DBUG_RETURN(0);
+}    
+  
+int handler::
+ha_stmt_begin() 
+{ 
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+  return current_thd->transaction_begin(); 
+#else
+  return 0;
+#endif
+}
+
+int handler::
+ha_stmt_end()
+{ 
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+  return current_thd->transaction_end(); 
+#else
+  return 0;
+#endif
 }

--- 1.133/sql/handler.h	2005-03-25 21:38:03 +01:00
+++ 1.134/sql/handler.h	2005-04-08 11:24:24 +02: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,7 @@
 } HANDLER_BUFFER;
 
 
+
 class handler :public Sql_alloc
 {
  protected:
@@ -543,11 +547,21 @@
   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();
+
+  /*
+    If the handler does it's own injection of the rows, this member function
+    should return 'true'. An alternative would be to use a set of replication
+    flags, which might be implemented to be faster.
+  */
+  virtual bool is_injective() const { return false; }
+
   virtual int index_read(byte * buf, const byte * key,
 			 uint key_len, enum ha_rkey_function find_flag)
    { return  HA_ERR_WRONG_COMMAND; }
@@ -698,9 +712,14 @@
     default rename_table() and delete_table() rename/delete files with a
     given name and extensions from bas_ext()
   */
-  virtual int rename_table(const char *from, const char *to);
+#define USE_PREPARE_CODE
+#ifdef USE_PREPARE_CODE
+  virtual int prepare_rename_table(const char *from, const char *to);  
+  virtual int prepare_delete_table(const char *name);
+#endif
+  virtual int rename_table(const char *from, const char *to);  
   virtual int delete_table(const char *name);
-  
+
   virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0;
 
   /* lock_count() can be more than one if the table is a MERGE */
@@ -732,7 +751,7 @@
  {
    return memcmp(ref1, ref2, ref_length);
  }
- 
+
  /*
    Condition pushdown to storage engines
  */
@@ -766,6 +785,18 @@
      Pops the top if condition stack, if stack is not empty
  */
  virtual void cond_pop() { return; };
+
+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; }
 };
 
 	/* Some extern variables used with handlers */

--- 1.135/sql/item_sum.cc	2005-03-30 15:57:49 +02:00
+++ 1.136/sql/item_sum.cc	2005-04-08 11:24:24 +02:00
@@ -2370,7 +2370,7 @@
     */
     return tree->unique_add(table->record[0] + table->s->null_bytes);
   }
-  if ((error= table->file->write_row(table->record[0])) &&
+  if ((error= table->file->ha_write_row(table->record[0])) &&
       error != HA_ERR_FOUND_DUPP_KEY &&
       error != HA_ERR_FOUND_DUPP_UNIQUE)
     return TRUE;

--- 1.159/sql/log.cc	2005-04-01 22:17:22 +02:00
+++ 1.160/sql/log.cc	2005-04-08 11:24:24 +02:00
@@ -348,8 +348,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
@@ -410,6 +411,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;
 }
 
@@ -1550,9 +1552,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);
 
@@ -1583,15 +1591,21 @@
 
 #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 0
+    // Disabled writing directly to the log, since it doesn't work right now.
+    if (opt_using_transactions && thd && event_info->can_be_cached())
+#else
     if (opt_using_transactions && thd)
+#endif
     {
       IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot];
 
@@ -1686,6 +1700,7 @@
 
     if (file == &log_file) // we are writing to the real log (disk)
     {
+      DBUG_PRINT("info", ("Flushing cache %p", file));
       if (flush_io_cache(file) || sync_binlog(file))
 	goto err;
     }
@@ -2244,6 +2259,61 @@
   DBUG_VOID_RETURN;
 }
 
+
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+
+ulong MYSQL_LOG::
+get_table_id(TABLE* table)
+{
+  DBUG_ENTER("MYSQL_LOG::get_table_id(TABLE*)");
+  DBUG_PRINT("enter", ("table=%p", table)); 
+  DBUG_ASSERT(table != NULL);
+
+  // 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 == table_mapping::NO_TABLE) {
+    // 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++;
+
+    // There is one reserved number that cannot be used.
+    if (tid == table_mapping::NO_TABLE)
+	tid = m_next_table_id++;
+	
+    m_table_map->set_table(tid, table);
+  }
+  DBUG_PRINT("return", ("table_id=%d", tid));
+  DBUG_RETURN(tid);
+}
+
+int MYSQL_LOG::
+is_table_mapped(TABLE* table) const
+{
+  DBUG_ASSERT(table != NULL);
+
+  // 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);
+  return m_table_map->get_table_id(table) != table_mapping::NO_TABLE;
+}
+
+void MYSQL_LOG::
+clear_table_mappings()
+{
+  DBUG_ASSERT(m_table_map != NULL);
+  m_table_map->clear_tables();
+}
+
+#endif // !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
 
 #ifdef __NT__
 void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,

--- 1.171/sql/log_event.cc	2005-04-01 13:40:13 +02:00
+++ 1.172/sql/log_event.cc	2005-04-08 11:24:24 +02:00
@@ -21,6 +21,7 @@
 #endif
 #include  "mysql_priv.h"
 #include "slave.h"
+#include "rpl_filter.h"
 #include <my_dir.h>
 #endif /* MYSQL_CLIENT */
 
@@ -510,8 +511,6 @@
   field_list->push_back(new Item_empty_string("Info", 20));
 }
 
-#endif /* !MYSQL_CLIENT */
-
 
 /*
   Log_event::write()
@@ -599,7 +598,6 @@
 
 */
 
-#ifndef MYSQL_CLIENT
 int Log_event::read_log_event(IO_CACHE* file, String* packet,
 			      pthread_mutex_t* log_lock)
 {
@@ -981,6 +979,7 @@
 }
 #endif
 
+#ifndef MYSQL_CLIENT
 
 /*
   Query_log_event::write()
@@ -998,7 +997,8 @@
             1+8+           // code of sql_mode and sql_mode
             1+1+FN_REFLEN+ // code of catalog and catalog length and catalog
             1+4+           // code of autoinc and the 2 autoinc variables
-            1+6            // code of charset and charset
+            1+6+           // code of charset and charset
+            1+1+MAX_TIME_ZONE_NAME_LENGTH // code of tz and tz length and tz name
             ], *start, *start_of_status;
   ulong event_length;
 
@@ -1055,37 +1055,40 @@
   start_of_status= start= buf+QUERY_HEADER_LEN;
   if (flags2_inited)
   {
-    *(start++)= Q_FLAGS2_CODE;
+    *start++= Q_FLAGS2_CODE;
     int4store(start, flags2);
     start+= 4;
   }
   if (sql_mode_inited)
   {
-    *(start++)= Q_SQL_MODE_CODE;
+    *start++= Q_SQL_MODE_CODE;
     int8store(start, (ulonglong)sql_mode);
     start+= 8;
   }
-  if (catalog_len >= 0) // i.e. "catalog inited" (false for 4.0 events)
+  if (catalog_len) // i.e. "catalog inited" (false for 4.0 events)
   {
-    *(start++)= Q_CATALOG_CODE;
-    *(start++)= (uchar) catalog_len;
+    *start++= Q_CATALOG_NZ_CODE;
+    *start++= (uchar) catalog_len;
     bmove(start, catalog, catalog_len);
     start+= catalog_len;
     /*
-      We write a \0 at the end. As we also have written the length, it's
-      apparently useless; but in fact it enables us to just do
-      catalog= a_pointer_to_the_buffer_of_the_read_event
-      later in the slave SQL thread.
-      If we didn't have the \0, we would need to memdup to build the catalog in
-      the slave SQL thread. 
-      And still the interest of having the length too is that in the slave SQL
-      thread we immediately know at which position the catalog ends (no need to
-      search for '\0'. In other words: length saves search, \0 saves mem alloc,
-      at the cost of 1 redundant byte on the disk.
-      Note that this is only a fix until we change 'catalog' to LEX_STRING
-      (then we won't need the \0).
+      In 5.0.x where x<4 masters we used to store the end zero here. This was
+      a waste of one byte so we don't do it in x>=4 masters. We change code to
+      Q_CATALOG_NZ_CODE, because re-using the old code would make x<4 slaves
+      of this x>=4 master segfault (expecting a zero when there is
+      none). Remaining compatibility problems are: the older slave will not
+      find the catalog; but it is will not crash, and it's not an issue
+      that it does not find the catalog as catalogs were not used in these
+      older MySQL versions (we store it in binlog and read it from relay log
+      but do nothing useful with it). What is an issue is that the older slave
+      will stop processing the Q_* blocks (and jumps to the db/query) as soon
+      as it sees unknown Q_CATALOG_NZ_CODE; so it will not be able to read
+      Q_AUTO_INCREMENT*, Q_CHARSET and so replication will fail silently in
+      various ways. Documented that you should not mix alpha/beta versions if
+      they are not exactly the same version, with example of 5.0.3->5.0.2 and
+      5.0.4->5.0.3. If replication is from older to new, the new will
+      recognize Q_CATALOG_CODE and have no problem.
     */
-    *(start++)= '\0';
   }
   if (auto_increment_increment != 1)
   {
@@ -1096,15 +1099,24 @@
   }
   if (charset_inited)
   {
-    *(start++)= Q_CHARSET_CODE;
+    *start++= Q_CHARSET_CODE;
     memcpy(start, charset, 6);
     start+= 6;
   }
+  if (time_zone_len)
+  {
+    /* In the TZ sys table, column Name is of length 64 so this should be ok */
+    DBUG_ASSERT(time_zone_len <= MAX_TIME_ZONE_NAME_LENGTH);
+    *start++= Q_TIME_ZONE_CODE;
+    *start++= time_zone_len;
+    memcpy(start, time_zone_str, time_zone_len);
+    start+= time_zone_len;
+  }
   /*
     Here there could be code like
     if (command-line-option-which-says-"log_this_variable" && inited)
     {
-    *(start++)= Q_THIS_VARIABLE_CODE;
+    *start++= Q_THIS_VARIABLE_CODE;
     int4store(start, this_variable);
     start+= 4;
     }
@@ -1133,8 +1145,6 @@
 /*
   Query_log_event::Query_log_event()
 */
-
-#ifndef MYSQL_CLIENT
 Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
 				 ulong query_length, bool using_trans,
 				 bool suppress_use)
@@ -1175,6 +1185,18 @@
   int2store(charset, thd_arg->variables.character_set_client->number);
   int2store(charset+2, thd_arg->variables.collation_connection->number);
   int2store(charset+4, thd_arg->variables.collation_server->number);
+  if (thd_arg->time_zone_used)
+  {
+    /*
+      Note that our event becomes dependent on the Time_zone object
+      representing the time zone. Fortunately such objects are never deleted
+      or changed during mysqld's lifetime.
+    */
+    time_zone_len= thd_arg->variables.time_zone->get_name()->length();
+    time_zone_str= thd_arg->variables.time_zone->get_name()->ptr();
+  }
+  else
+    time_zone_len= 0;
   DBUG_PRINT("info",("Query_log_event has flags2=%lu sql_mode=%lu",flags2,sql_mode));
 }
 #endif /* MYSQL_CLIENT */
@@ -1188,15 +1210,18 @@
 Query_log_event::Query_log_event(const char* buf, uint event_len,
                                  const Format_description_log_event *description_event,
                                  Log_event_type event_type)
-  :Log_event(buf, description_event), data_buf(0), query(NullS), catalog(NullS), 
+  :Log_event(buf, description_event), data_buf(0), query(NullS),
    db(NullS), catalog_len(0), status_vars_len(0),
    flags2_inited(0), sql_mode_inited(0), charset_inited(0),
-   auto_increment_increment(1), auto_increment_offset(1)
+   auto_increment_increment(1), auto_increment_offset(1),
+   time_zone_len(0)
 {
   ulong data_len;
   uint32 tmp;
   uint8 common_header_len, post_header_len;
-  const char *start, *end;
+  char *start;
+  const char *end;
+  bool catalog_nz= 1;
   DBUG_ENTER("Query_log_event::Query_log_event(char*,...)");
 
   common_header_len= description_event->common_header_len;
@@ -1216,7 +1241,7 @@
   
   slave_proxy_id= thread_id = uint4korr(buf + Q_THREAD_ID_OFFSET);
   exec_time = uint4korr(buf + Q_EXEC_TIME_OFFSET);
-  db_len = (uint)buf[Q_DB_LEN_OFFSET];
+  db_len = (uint)buf[Q_DB_LEN_OFFSET]; // TODO: add a check of all *_len vars
   error_code = uint2korr(buf + Q_ERR_CODE_OFFSET);
 
   /*
@@ -1242,7 +1267,7 @@
   /* variable-part: the status vars; only in MySQL 5.0  */
   
   start= (char*) (buf+post_header_len);
-  end= (char*) (start+status_vars_len);
+  end= (const char*) (start+status_vars_len);
   for (const uchar* pos= (const uchar*) start; pos < (const uchar*) end;)
   {
     switch (*pos++) {
@@ -1264,11 +1289,10 @@
       pos+= 8;
       break;
     }
-    case Q_CATALOG_CODE:
-      catalog_len= *pos;
-      if (catalog_len)
-        catalog= (char*) pos+1;                           // Will be copied later
-      pos+= catalog_len+2;
+    case Q_CATALOG_NZ_CODE:
+      if ((catalog_len= *pos))
+        catalog= (char*) pos+1;                 // Will be copied later
+      pos+= catalog_len+1;
       break;
     case Q_AUTO_INCREMENT:
       auto_increment_increment= uint2korr(pos);
@@ -1282,32 +1306,60 @@
       pos+= 6;
       break;
     }
+    case Q_TIME_ZONE_CODE:
+    {
+      if ((time_zone_len= *pos))
+        time_zone_str= (char *)(pos+1);
+      pos+= time_zone_len+1;
+      break;
+    }
+    case Q_CATALOG_CODE: /* for 5.0.x where 0<=x<=3 masters */
+      if ((catalog_len= *pos))
+        catalog= (char*) pos+1;                           // Will be copied later
+      pos+= catalog_len+2; // leap over end 0
+      catalog_nz= 0; // catalog has end 0 in event
+      break;
     default:
       /* That's why you must write status vars in growing order of code */
       DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\
  code: %u), skipping the rest of them", (uint) *(pos-1)));
-      pos= (const uchar*) end;                         // Break look
+      pos= (const uchar*) end;                         // Break loop
     }
   }
   
-  /* A 2nd variable part; this is common to all versions */ 
-  
-  if (!(start= data_buf = (char*) my_malloc(catalog_len + data_len +2, MYF(MY_WME))))
+  if (!(start= data_buf = (char*) my_malloc(catalog_len + 1 +
+                                            time_zone_len + 1 +
+                                            data_len + 1, MYF(MY_WME))))
     DBUG_VOID_RETURN;
-  if (catalog)                                  // If catalog is given
+  if (catalog_len)                                  // If catalog is given
+  {
+    if (likely(catalog_nz)) // true except if event comes from 5.0.0|1|2|3.
+    {
+      memcpy(start, catalog, catalog_len);
+      catalog= start;
+      start+= catalog_len;
+      *start++= 0;
+    }
+    else
+    {
+      memcpy(start, catalog, catalog_len+1); // copy end 0
+      catalog= start;
+      start+= catalog_len+1;
+    }
+  }
+  if (time_zone_len)
   {
-    memcpy((char*) start, catalog, catalog_len+1);      // Copy name and end \0
-    catalog= start;
-    start+= catalog_len+1;
+    memcpy(start, time_zone_str, time_zone_len);
+    time_zone_str= start;
+    start+= time_zone_len;
+    *start++= 0;
   }
+  /* A 2nd variable part; this is common to all versions */ 
   memcpy((char*) start, end, data_len);          // Copy db and query
-  ((char*) start)[data_len]= '\0';              // End query with \0 (For safetly)
+  start[data_len]= '\0';              // End query with \0 (For safetly)
   db= start;
   query= start + db_len + 1;
   q_len= data_len - db_len -1;
-  /* This is used to detect wrong parsing. Could be removed in the future. */
-  DBUG_PRINT("info", ("catalog: '%s'  len: %u   db: '%s'  len:  %u  q_len: %lu",
-                      catalog, (uint) catalog_len, db, (uint) db_len,q_len));
   DBUG_VOID_RETURN;
 }
 
@@ -1415,6 +1467,8 @@
     last_event_info->auto_increment_offset=    auto_increment_offset;
   }
 
+  /* TODO: print the catalog when we feature SET CATALOG */
+
   if (likely(charset_inited))
   {
     if (unlikely(!last_event_info->charset_inited)) /* first Query event */
@@ -1435,6 +1489,14 @@
       memcpy(last_event_info->charset, charset, 6);
     }
   }
+  if (time_zone_len)
+  {
+    if (bcmp(last_event_info->time_zone_str, time_zone_str, time_zone_len+1))
+    {
+      fprintf(file,"SET @@session.time_zone='%s';\n", time_zone_str);
+      memcpy(last_event_info->time_zone_str, time_zone_str, time_zone_len+1);
+    }
+  }
 }
 
 
@@ -1468,9 +1530,9 @@
     alloced block (see Query_log_event::exec_event()). Same for thd->db.
     Thank you.
   */
-  thd->catalog= (char*) catalog;
+  thd->catalog= catalog_len ? (char *) catalog : (char *)"";
   thd->db_length= db_len;
-  thd->db= (char*) rewrite_db(db, &thd->db_length);
+  thd->db= (char *) rpl_filter->get_rewrite_db(db, &thd->db_length);
   thd->variables.auto_increment_increment= auto_increment_increment;
   thd->variables.auto_increment_offset=    auto_increment_offset;
 
@@ -1489,7 +1551,7 @@
 
   clear_all_errors(thd, rli);
 
-  if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
+  if (rpl_filter->db_ok(thd->db))
   {
     thd->set_time((time_t)when);
     thd->query_length= q_len_arg;
@@ -1538,20 +1600,28 @@
                 get_charset(uint2korr(charset+4), MYF(MY_WME))))
           {
             /*
-              We updated the thd->variables with nonsensical values (0), and the
-              thread is not guaranteed to terminate now (as it may be configured
-              to ignore EE_UNKNOWN_CHARSET);if we're going to execute a next
-              statement we'll have a new charset info with it, so no problem to
-              have stored 0 in thd->variables. But we invalidate cached
-              charset to force a check next time (otherwise if next time
-              charset is unknown again we won't detect it).
+              We updated the thd->variables with nonsensical values (0). Let's
+              set them to something safe (i.e. which avoids crash), and we'll
+              stop with EE_UNKNOWN_CHARSET in compare_errors (unless set to
+              ignore this error).
             */
-            rli->cached_charset_invalidate();
+            set_slave_thread_default_charset(thd, rli);
             goto compare_errors;
           }
           thd->update_charset(); // for the charset change to take effect
         }
       }
+      if (time_zone_len)
+      {
+        String tmp(time_zone_str, time_zone_len, &my_charset_bin);
+        if (!(thd->variables.time_zone=
+              my_tz_find_with_opening_tz_tables(thd, &tmp)))
+        {
+          my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), tmp.c_ptr());
+          thd->variables.time_zone= global_system_variables.time_zone;
+          goto compare_errors;
+        }
+      }
 
       /* Execute the query (note that we bypass dispatch_command()) */
       mysql_parse(thd, thd->query, thd->query_length);
@@ -1776,6 +1846,7 @@
   Start_log_event_v3::write()
 */
 
+#ifndef MYSQL_CLIENT
 bool Start_log_event_v3::write(IO_CACHE* file)
 {
   char buff[START_V3_HEADER_LEN];
@@ -1785,6 +1856,7 @@
   return (write_header(file, sizeof(buff)) ||
           my_b_safe_write(file, (byte*) buff, sizeof(buff)));
 }
+#endif
 
 
 /*
@@ -2004,7 +2076,7 @@
   DBUG_VOID_RETURN;
 }
 
-
+#ifndef MYSQL_CLIENT
 bool Format_description_log_event::write(IO_CACHE* file)
 {
   /*
@@ -2021,6 +2093,7 @@
   return (write_header(file, sizeof(buff)) ||
           my_b_safe_write(file, buff, sizeof(buff)));
 }
+#endif
 
 /*
   SYNOPSIS
@@ -2041,6 +2114,7 @@
   delete rli->relay_log.description_event_for_exec;
   rli->relay_log.description_event_for_exec= this;
 
+#ifdef USING_TRANSACTIONS
   /*
     As a transaction NEVER spans on 2 or more binlogs:
     if we have an active transaction at this point, the master died
@@ -2062,6 +2136,7 @@
                       "to its binary log.");
     end_trans(thd, ROLLBACK);
   }
+#endif
   /*
     If this event comes from ourselves, there is no cleaning task to perform,
     we don't call Start_log_event_v3::exec_event() (this was just to update the
@@ -2237,6 +2312,8 @@
 #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
 
 
+#ifndef MYSQL_CLIENT
+
 /*
   Load_log_event::write_data_header()
 */
@@ -2278,7 +2355,6 @@
   Load_log_event::Load_log_event()
 */
 
-#ifndef MYSQL_CLIENT
 Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex,
 			       const char *db_arg, const char *table_name_arg,
 			       List<Item> &fields_arg,
@@ -2598,7 +2674,7 @@
 			       bool use_rli_only_for_errors)
 {
   thd->db_length= db_len;
-  thd->db= (char*) rewrite_db(db, &thd->db_length);
+  thd->db= (char *) rpl_filter->get_rewrite_db(db, &thd->db_length);
   DBUG_ASSERT(thd->query == 0);
   thd->query_length= 0;                         // Should not be needed
   thd->query_error= 0;
@@ -2627,7 +2703,7 @@
     al. Another way is do the filtering in the I/O thread (more efficient: no
     disk writes at all).
   */
-  if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
+  if (rpl_filter->db_ok(thd->db))
   {
     thd->set_time((time_t)when);
     VOID(pthread_mutex_lock(&LOCK_thread_count));
@@ -2649,7 +2725,7 @@
     tables.updating= 1;
 
     // the table will be opened in mysql_load    
-    if (table_rules_on && !tables_ok(thd, &tables))
+    if (rpl_filter->is_on() && !rpl_filter->tables_ok(thd->db,
&tables))
     {
       // TODO: this is a bug - this needs to be moved to the I/O thread
       if (net)
@@ -2892,6 +2968,7 @@
   Rotate_log_event::write()
 */
 
+#ifndef MYSQL_CLIENT
 bool Rotate_log_event::write(IO_CACHE* file)
 {
   char buf[ROTATE_HEADER_LEN];
@@ -2900,7 +2977,7 @@
           my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) ||
           my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len));
 }
-
+#endif
 
 /*
   Rotate_log_event::exec_event()
@@ -2958,17 +3035,10 @@
       master is 4.0 then the events are in the slave's format (conversion).
     */
     set_slave_thread_options(thd);
+    set_slave_thread_default_charset(thd, rli);
     thd->variables.sql_mode= global_system_variables.sql_mode;
     thd->variables.auto_increment_increment=
       thd->variables.auto_increment_offset= 1;
-    thd->variables.character_set_client=
-      global_system_variables.character_set_client;
-    thd->variables.collation_connection=
-      global_system_variables.collation_connection;
-    thd->variables.collation_server=
-      global_system_variables.collation_server;
-    thd->update_charset();
-    rli->cached_charset_invalidate();
   }
   pthread_mutex_unlock(&rli->data_lock);
   pthread_cond_broadcast(&rli->data_cond);
@@ -3030,6 +3100,7 @@
   Intvar_log_event::write()
 */
 
+#ifndef MYSQL_CLIENT
 bool Intvar_log_event::write(IO_CACHE* file)
 {
   byte buf[9];
@@ -3038,6 +3109,7 @@
   return (write_header(file, sizeof(buf)) ||
           my_b_safe_write(file, buf, sizeof(buf)));
 }
+#endif
 
 
 /*
@@ -3122,6 +3194,7 @@
 }
 
 
+#ifndef MYSQL_CLIENT
 bool Rand_log_event::write(IO_CACHE* file)
 {
   byte buf[16];
@@ -3130,6 +3203,7 @@
   return (write_header(file, sizeof(buf)) ||
           my_b_safe_write(file, buf, sizeof(buf)));
 }
+#endif
 
 
 #ifdef MYSQL_CLIENT
@@ -3193,11 +3267,13 @@
 }
 
 
+#ifndef MYSQL_CLIENT
 bool Xid_log_event::write(IO_CACHE* file)
 {
   return write_header(file, sizeof(xid)) ||
          my_b_safe_write(file, (byte*) &xid, sizeof(xid));
 }
+#endif
 
 
 #ifdef MYSQL_CLIENT
@@ -3331,6 +3407,7 @@
 }
 
 
+#ifndef MYSQL_CLIENT
 bool User_var_log_event::write(IO_CACHE* file)
 {
   char buf[UV_NAME_LEN_SIZE];
@@ -3365,7 +3442,7 @@
       dec->fix_buffer_pointer();
       buf2[0]= (char)(dec->intg + dec->frac);
       buf2[1]= (char)dec->frac;
-      decimal2bin((decimal*)val, buf2+2, buf2[0], buf2[1]);
+      decimal2bin((decimal_t*)val, buf2+2, buf2[0], buf2[1]);
       val_len= decimal_bin_size(buf2[0], buf2[1]) + 2;
       break;
     }
@@ -3390,6 +3467,7 @@
 	  my_b_safe_write(file, (byte*) buf1, buf1_length) ||
 	  my_b_safe_write(file, (byte*) pos, val_len));
 }
+#endif
 
 
 /*
@@ -3432,8 +3510,8 @@
       int str_len= sizeof(str_buf) - 1;
       int precision= (int)val[0];
       int scale= (int)val[1];
-      decimal_digit dec_buf[10];
-      decimal dec;
+      decimal_digit_t dec_buf[10];
+      decimal_t dec;
       dec.len= 10;
       dec.buf= dec_buf;
 
@@ -3663,6 +3741,7 @@
 }
 
 
+#ifndef MYSQL_CLIENT
 bool Slave_log_event::write(IO_CACHE* file)
 {
   ulong event_length= get_data_size();
@@ -3673,6 +3752,7 @@
   return (write_header(file, event_length) ||
           my_b_safe_write(file, (byte*) mem_pool, event_length));
 }
+#endif
 
 
 void Slave_log_event::init_from_mem_pool(int data_size)
@@ -3799,7 +3879,6 @@
   sql_ex.force_new_format();
   DBUG_VOID_RETURN;
 }
-#endif /* !MYSQL_CLIENT */
 
 
 /*
@@ -3844,6 +3923,7 @@
   return res;
 }
 
+#endif /* !MYSQL_CLIENT */
 
 /*
   Create_file_log_event ctor
@@ -3976,8 +4056,10 @@
   strmov(p, ".info");			// strmov takes less code than memcpy
   strnmov(proc_info, "Making temp file ", 17); // no end 0
   thd->proc_info= proc_info;
-  if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC,
-		    MYF(MY_WME))) < 0 ||
+  my_delete(fname_buf, MYF(0)); // old copy may exist already
+  if ((fd= my_create(fname_buf, CREATE_MODE,
+		     O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
+		     MYF(MY_WME))) < 0 ||
       init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0,
 		    MYF(MY_WME|MY_NABP)))
   {
@@ -4001,8 +4083,10 @@
   my_close(fd, MYF(0));
   
   // fname_buf now already has .data, not .info, because we did our trick
-  if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC,
-		    MYF(MY_WME))) < 0)
+  my_delete(fname_buf, MYF(0)); // old copy may exist already
+  if ((fd= my_create(fname_buf, CREATE_MODE,
+		     O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
+		     MYF(MY_WME))) < 0)
   {
     slave_print_error(rli,my_errno, "Error in Create_file event: could not open file
'%s'", fname_buf);
     goto err;
@@ -4071,6 +4155,7 @@
   Append_block_log_event::write()
 */
 
+#ifndef MYSQL_CLIENT
 bool Append_block_log_event::write(IO_CACHE* file)
 {
   byte buf[APPEND_BLOCK_HEADER_LEN];
@@ -4079,6 +4164,7 @@
           my_b_safe_write(file, buf, APPEND_BLOCK_HEADER_LEN) ||
 	  my_b_safe_write(file, (byte*) block, block_len));
 }
+#endif
 
 
 /*
@@ -4116,12 +4202,12 @@
 
 
 /*
-  Append_block_log_event::get_open_mode()
+  Append_block_log_event::get_create_or_append()
 */
 
-int Append_block_log_event::get_open_mode() const
+int Append_block_log_event::get_create_or_append() const
 {
-  return O_WRONLY | O_APPEND | O_BINARY;
+  return 0; /* append to the file, fail if not exists */
 }
 
 /*
@@ -4139,7 +4225,21 @@
   memcpy(p, ".data", 6);
   strnmov(proc_info, "Making temp file ", 17); // no end 0
   thd->proc_info= proc_info;
-  if ((fd = my_open(fname, get_open_mode(), MYF(MY_WME))) < 0)
+  if (get_create_or_append())
+  {
+    my_delete(fname, MYF(0)); // old copy may exist already
+    if ((fd= my_create(fname, CREATE_MODE,
+		       O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
+		       MYF(MY_WME))) < 0)
+    {
+      slave_print_error(rli, my_errno,
+			"Error in %s event: could not create file '%s'",
+			get_type_str(), fname);
+      goto err;
+    }
+  }
+  else if ((fd = my_open(fname, O_WRONLY | O_APPEND | O_BINARY | O_NOFOLLOW,
+                         MYF(MY_WME))) < 0)
   {
     slave_print_error(rli, my_errno,
                       "Error in %s event: could not open file '%s'",
@@ -4200,6 +4300,7 @@
   Delete_file_log_event::write()
 */
 
+#ifndef MYSQL_CLIENT
 bool Delete_file_log_event::write(IO_CACHE* file)
 {
  byte buf[DELETE_FILE_HEADER_LEN];
@@ -4207,6 +4308,7 @@
  return (write_header(file, sizeof(buf)) ||
          my_b_safe_write(file, buf, sizeof(buf)));
 }
+#endif
 
 
 /*
@@ -4294,6 +4396,7 @@
   Execute_load_log_event::write()
 */
 
+#ifndef MYSQL_CLIENT
 bool Execute_load_log_event::write(IO_CACHE* file)
 {
   byte buf[EXEC_LOAD_HEADER_LEN];
@@ -4301,6 +4404,7 @@
   return (write_header(file, sizeof(buf)) || 
           my_b_safe_write(file, buf, sizeof(buf)));
 }
+#endif
 
 
 /*
@@ -4348,7 +4452,8 @@
   Load_log_event* lev = 0;
 
   memcpy(p, ".info", 6);
-  if ((fd = my_open(fname, O_RDONLY|O_BINARY, MYF(MY_WME))) < 0 ||
+  if ((fd = my_open(fname, O_RDONLY | O_BINARY | O_NOFOLLOW,
+                    MYF(MY_WME))) < 0 ||
       init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0,
 		    MYF(MY_WME|MY_NABP)))
   {
@@ -4447,9 +4552,9 @@
 
 
 #if defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Begin_load_query_log_event::get_open_mode() const
+int Begin_load_query_log_event::get_create_or_append() const
 {
-  return O_CREAT | O_WRONLY | O_BINARY | O_TRUNC;
+  return 1; /* create the file */
 }
 #endif /* defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
 
@@ -4504,6 +4609,7 @@
 }
 
 
+#ifndef MYSQL_CLIENT
 bool
 Execute_load_query_log_event::write_post_header_for_derived(IO_CACHE* file)
 {
@@ -4514,6 +4620,7 @@
   *(buf + 4 + 4 + 4)= (char)dup_handling;
   return my_b_safe_write(file, (byte*) buf, EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN);
 }
+#endif
 
 
 #ifdef MYSQL_CLIENT
@@ -4624,7 +4731,12 @@
   /* Forging file name for deletion in same buffer */
   *fname_end= 0;
 
-  (void) my_delete(fname, MYF(MY_WME));
+  /*
+    If there was an error the slave is going to stop, leave the
+    file so that we can re-execute this event at START SLAVE.
+  */
+  if (!error)
+    (void) my_delete(fname, MYF(MY_WME));
 
   my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
   return error;

--- 1.109/sql/log_event.h	2005-04-01 13:32:29 +02:00
+++ 1.110/sql/log_event.h	2005-04-08 11:24:24 +02:00
@@ -243,9 +243,24 @@
 /* these are codes, not offsets; not more than 256 values (1 byte). */
 #define Q_FLAGS2_CODE           0
 #define Q_SQL_MODE_CODE         1
+#ifndef TO_BE_DELETED
+/*
+  Q_CATALOG_CODE is catalog with end zero stored; it is used only by MySQL
+  5.0.x where 0<=x<=3.
+*/
 #define Q_CATALOG_CODE          2
+#endif
 #define Q_AUTO_INCREMENT	3
 #define Q_CHARSET_CODE          4
+#define Q_TIME_ZONE_CODE        5
+/*
+  Q_CATALOG_NZ_CODE is catalog withOUT end zero stored; it is used by MySQL
+  5.0.x where x>=4. Saves one byte in every Query_log_event in binlog,
+  compared to Q_CATALOG_CODE. The reason we didn't simply re-use
+  Q_CATALOG_CODE is that then a 5.0.3 slave of this 5.0.x (x>=4) master would
+  crash (segfault etc) because it would expect a 0 when there is none.
+*/
+#define Q_CATALOG_NZ_CODE       6
 
 /* Intvar event post-header */
 
@@ -468,6 +483,7 @@
   ulong auto_increment_increment, auto_increment_offset;
   bool charset_inited;
   char charset[6]; // 3 variables, each of them storable in 2 bytes
+  char time_zone_str[MAX_TIME_ZONE_NAME_LENGTH];
   st_last_event_info()
     :flags2_inited(0), sql_mode_inited(0),
      auto_increment_increment(1),auto_increment_offset(1), charset_inited(0)
@@ -479,6 +495,7 @@
       */
       bzero(db, sizeof(db));
       bzero(charset, sizeof(charset));
+      bzero(time_zone_str, sizeof(time_zone_str));
     }
 } LAST_EVENT_INFO;
 #endif
@@ -603,6 +620,7 @@
     my_free((gptr) ptr, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
   }
 
+#ifndef MYSQL_CLIENT
   bool write_header(IO_CACHE* file, ulong data_length);
   virtual bool write(IO_CACHE* file)
   {
@@ -610,13 +628,14 @@
             write_data_header(file) ||
             write_data_body(file));
   }
-  virtual bool is_artificial_event() { return 0; }
   virtual bool write_data_header(IO_CACHE* file)
   { return 0; }
   virtual bool write_data_body(IO_CACHE* file __attribute__((unused)))
   { return 0; }
+#endif
   virtual Log_event_type get_type_code() = 0;
   virtual bool is_valid() const = 0;
+  virtual bool is_artificial_event() { return 0; }
   inline bool get_cache_stmt() { return cache_stmt; }
   Log_event(const char* buf, const Format_description_log_event* description_event);
   virtual ~Log_event() { free_temp_buf();}
@@ -744,7 +763,7 @@
     concerned) from here.
   */
 
-  int catalog_len;			// <= 255 char; -1 means uninited
+  uint catalog_len;			// <= 255 char; 0 means uninited
 
   /*
     We want to be able to store a variable number of N-bit status vars:
@@ -786,6 +805,8 @@
   ulong sql_mode;
   ulong auto_increment_increment, auto_increment_offset;
   char charset[6];
+  uint time_zone_len; /* 0 means uninited */
+  const char *time_zone_str;
 
 #ifndef MYSQL_CLIENT
 
@@ -809,12 +830,13 @@
   ~Query_log_event()
   {
     if (data_buf)
-    {
       my_free((gptr) data_buf, MYF(0));
-    }
   }
   Log_event_type get_type_code() { return QUERY_EVENT; }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+  virtual bool write_post_header_for_derived(IO_CACHE* file) { return FALSE; }
+#endif
   bool is_valid() const { return query != 0; }
 
   /*
@@ -823,7 +845,6 @@
   */
   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
@@ -862,7 +883,9 @@
   int get_data_size();
   bool is_valid() const { return master_host != 0; }
   Log_event_type get_type_code() { return SLAVE_EVENT; }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
 };
 
 #endif /* HAVE_REPLICATION */
@@ -957,8 +980,10 @@
   {
     return sql_ex.new_format() ? NEW_LOAD_EVENT: LOAD_EVENT;
   }
+#ifndef MYSQL_CLIENT
   bool write_data_header(IO_CACHE* file);
   bool write_data_body(IO_CACHE* file);
+#endif
   bool is_valid() const { return table_name != 0; }
   int get_data_size()
   {
@@ -1034,7 +1059,9 @@
                      const Format_description_log_event* description_event);
   ~Start_log_event_v3() {}
   Log_event_type get_type_code() { return START_EVENT_V3;}
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   bool is_valid() const { return 1; }
   int get_data_size()
   {
@@ -1076,7 +1103,9 @@
                                const Format_description_log_event* description_event);
   ~Format_description_log_event() { my_free((gptr)post_header_len, MYF(0)); }
   Log_event_type get_type_code() { return FORMAT_DESCRIPTION_EVENT;}
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   bool is_valid() const
   {
     return ((common_header_len >= ((binlog_version==1) ? OLD_HEADER_LEN :
@@ -1126,7 +1155,9 @@
   Log_event_type get_type_code() { return INTVAR_EVENT;}
   const char* get_var_type_name();
   int get_data_size() { return  9; /* sizeof(type) + sizeof(val) */;}
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   bool is_valid() const { return 1; }
 };
 
@@ -1164,7 +1195,9 @@
   ~Rand_log_event() {}
   Log_event_type get_type_code() { return RAND_EVENT;}
   int get_data_size() { return 16; /* sizeof(ulonglong) * 2*/ }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   bool is_valid() const { return 1; }
 };
 
@@ -1199,7 +1232,9 @@
   ~Xid_log_event() {}
   Log_event_type get_type_code() { return XID_EVENT;}
   int get_data_size() { return sizeof(xid); }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   bool is_valid() const { return 1; }
 };
 
@@ -1241,7 +1276,9 @@
   User_var_log_event(const char* buf, const Format_description_log_event*
description_event);
   ~User_var_log_event() {}
   Log_event_type get_type_code() { return USER_VAR_EVENT;}
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   bool is_valid() const { return 1; }
 };
 
@@ -1311,7 +1348,9 @@
   Log_event_type get_type_code() { return ROTATE_EVENT;}
   int get_data_size() { return  ident_len + ROTATE_HEADER_LEN;}
   bool is_valid() const { return new_log_ident != 0; }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
 };
 
 
@@ -1371,6 +1410,7 @@
 	    4 + 1 + block_len);
   }
   bool is_valid() const { return inited_from_old || block != 0; }
+#ifndef MYSQL_CLIENT
   bool write_data_header(IO_CACHE* file);
   bool write_data_body(IO_CACHE* file);
   /*
@@ -1378,6 +1418,7 @@
     write it as Load event - used on the slave
   */
   bool write_base(IO_CACHE* file);
+#endif
 };
 
 
@@ -1412,7 +1453,7 @@
 #ifdef HAVE_REPLICATION
   int exec_event(struct st_relay_log_info* rli);
   void pack_info(Protocol* protocol);
-  virtual int get_open_mode() const;
+  virtual int get_create_or_append() const;
 #endif /* HAVE_REPLICATION */
 #else
   void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
@@ -1424,7 +1465,9 @@
   Log_event_type get_type_code() { return APPEND_BLOCK_EVENT;}
   int get_data_size() { return  block_len + APPEND_BLOCK_HEADER_LEN ;}
   bool is_valid() const { return block != 0; }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   const char* get_db() { return db; }
 };
 
@@ -1458,7 +1501,9 @@
   Log_event_type get_type_code() { return DELETE_FILE_EVENT;}
   int get_data_size() { return DELETE_FILE_HEADER_LEN ;}
   bool is_valid() const { return file_id != 0; }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   const char* get_db() { return db; }
 };
 
@@ -1491,7 +1536,9 @@
   Log_event_type get_type_code() { return EXEC_LOAD_EVENT;}
   int get_data_size() { return  EXEC_LOAD_HEADER_LEN ;}
   bool is_valid() const { return file_id != 0; }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   const char* get_db() { return db; }
 };
 
@@ -1514,7 +1561,7 @@
                              bool using_trans);
 #ifdef HAVE_REPLICATION
   Begin_load_query_log_event(THD* thd);
-  int get_open_mode() const;
+  int get_create_or_append() const;
 #endif /* HAVE_REPLICATION */
 #endif
   Begin_load_query_log_event(const char* buf, uint event_len,
@@ -1579,7 +1626,9 @@
   bool is_valid() const { return Query_log_event::is_valid() && file_id != 0; }
 
   ulong get_post_header_size_for_derived();
+#ifndef MYSQL_CLIENT
   bool write_post_header_for_derived(IO_CACHE* file);
+#endif
  };
 
 

--- 1.284/sql/mysql_priv.h	2005-04-01 22:17:23 +02:00
+++ 1.285/sql/mysql_priv.h	2005-04-08 11:24:24 +02:00
@@ -1076,6 +1076,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.445/sql/mysqld.cc	2005-04-05 05:26:15 +02:00
+++ 1.446/sql/mysqld.cc	2005-04-08 11:24:24 +02:00
@@ -19,6 +19,7 @@
 #include <my_dir.h>
 #include "slave.h"
 #include "sql_repl.h"
+#include "rpl_filter.h"
 #include "repl_failsafe.h"
 #include "stacktrace.h"
 #include "mysqld_suffix.h"
@@ -400,12 +401,10 @@
 FILE *bootstrap_file;
 int bootstrap_error;
 
-I_List<i_string_pair> replicate_rewrite_db;
-I_List<i_string> replicate_do_db, replicate_ignore_db;
-// allow the user to tell us which db to replicate and which to ignore
-I_List<i_string> binlog_do_db, binlog_ignore_db;
 I_List<THD> threads,thread_cache;
 I_List<NAMED_LIST> key_caches;
+Rpl_filter* rpl_filter;
+Rpl_filter* binlog_filter;
 
 struct system_variables global_system_variables;
 struct system_variables max_system_variables;
@@ -423,6 +422,7 @@
 SHOW_COMP_OPTION have_raid, have_openssl, have_symlink, have_query_cache;
 SHOW_COMP_OPTION have_geometry, have_rtree_keys;
 SHOW_COMP_OPTION have_crypt, have_compress;
+SHOW_COMP_OPTION have_blackhole_db;
 
 /* Thread specific variables */
 
@@ -1016,12 +1016,9 @@
   free_max_user_conn();
 #ifdef HAVE_REPLICATION
   end_slave_list();
-  free_list(&replicate_do_db);
-  free_list(&replicate_ignore_db);
-  free_list(&binlog_do_db);
-  free_list(&binlog_ignore_db);
-  free_list(&replicate_rewrite_db);
 #endif
+  delete binlog_filter;
+  delete rpl_filter;
 #ifdef HAVE_OPENSSL
   if (ssl_acceptor_fd)
     my_free((gptr) ssl_acceptor_fd, MYF(MY_ALLOW_ZERO_PTR));
@@ -2973,9 +2970,16 @@
 int main(int argc, char **argv)
 #endif
 {
-
   DEBUGGER_OFF;
 
+  rpl_filter= new Rpl_filter;
+  binlog_filter= new Rpl_filter;
+  if (!rpl_filter || !binlog_filter) 
+  {
+    sql_perror("Could not allocate replication and binlog filters");
+    exit(1);
+  }
+
   MY_INIT(argv[0]);		// init my_sys library & pthreads
 
 #ifdef _CUSTOMSTARTUPCONFIG_
@@ -3137,8 +3141,17 @@
 #endif
   if (opt_bootstrap) /* If running with bootstrap, do not start replication. */
     opt_skip_slave_start= 1;
-  /* init_slave() must be called after the thread keys are created */
-  init_slave();
+  /*
+    init_slave() must be called after the thread keys are created.
+    Some parts of the code (e.g. SHOW STATUS LIKE 'slave_running' and other
+    places) assume that active_mi != 0, so let's fail if it's 0 (out of
+    memory); a message has already been printed.
+  */
+  if (init_slave() && !active_mi)
+  {
+    end_thr_alarm(1);				// Don't allow alarms
+    unireg_abort(1);
+  }
 
   if (opt_bootstrap)
   {
@@ -3312,10 +3325,10 @@
 
 int main(int argc, char **argv)
 {
-
-  /* When several instances are running on the same machine, we
-     need to have an  unique  named  hEventShudown  through the
-     application PID e.g.: MySQLShutdown1890; MySQLShutdown2342
+  /*
+    When several instances are running on the same machine, we
+    need to have an  unique  named  hEventShudown  through the
+    application PID e.g.: MySQLShutdown1890; MySQLShutdown2342
   */
   int10_to_str((int) GetCurrentProcessId(),strmov(shutdown_event_name,
                                                   "MySQLShutdown"), 10);
@@ -3894,10 +3907,19 @@
   char *suffix_pos;
   char connect_number_char[22], *p;
   const char *errmsg= 0;
+  SECURITY_ATTRIBUTES *sa_event= 0, *sa_mapping= 0;
   my_thread_init();
   DBUG_ENTER("handle_connections_shared_memorys");
   DBUG_PRINT("general",("Waiting for allocated shared memory."));
 
+  if (my_security_attr_create(&sa_event, &errmsg,
+                              GENERIC_ALL, SYNCHRONIZE | EVENT_MODIFY_STATE))
+    goto error;
+
+  if (my_security_attr_create(&sa_mapping, &errmsg,
+                             GENERIC_ALL, FILE_MAP_READ | FILE_MAP_WRITE))
+    goto error;
+
   /*
     The name of event and file-mapping events create agree next rule:
       shared_memory_base_name+unique_part
@@ -3907,22 +3929,22 @@
   */
   suffix_pos= strxmov(tmp,shared_memory_base_name,"_",NullS);
   strmov(suffix_pos, "CONNECT_REQUEST");
-  if ((smem_event_connect_request= CreateEvent(0,FALSE,FALSE,tmp)) == 0)
+  if ((smem_event_connect_request= CreateEvent(sa_event,
+                                               FALSE, FALSE, tmp)) == 0)
   {
     errmsg= "Could not create request event";
     goto error;
   }
   strmov(suffix_pos, "CONNECT_ANSWER");
-  if ((event_connect_answer= CreateEvent(0,FALSE,FALSE,tmp)) == 0)
+  if ((event_connect_answer= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
   {
     errmsg="Could not create answer event";
     goto error;
   }
   strmov(suffix_pos, "CONNECT_DATA");
-  if ((handle_connect_file_map= CreateFileMapping(INVALID_HANDLE_VALUE,0,
-						   PAGE_READWRITE,
-						   0,sizeof(connect_number),
-						   tmp)) == 0)
+  if ((handle_connect_file_map=
+       CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping,
+                         PAGE_READWRITE, 0, sizeof(connect_number), tmp)) == 0)
   {
     errmsg= "Could not create file mapping";
     goto error;
@@ -3967,10 +3989,9 @@
     suffix_pos= strxmov(tmp,shared_memory_base_name,"_",connect_number_char,
 			 "_",NullS);
     strmov(suffix_pos, "DATA");
-    if ((handle_client_file_map= CreateFileMapping(INVALID_HANDLE_VALUE,0,
-						    PAGE_READWRITE,0,
-						    smem_buffer_length,
-						    tmp)) == 0)
+    if ((handle_client_file_map=
+         CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping,
+                           PAGE_READWRITE, 0, smem_buffer_length, tmp)) == 0)
     {
       errmsg= "Could not create file mapping";
       goto errorconn;
@@ -3983,31 +4004,33 @@
       goto errorconn;
     }
     strmov(suffix_pos, "CLIENT_WROTE");
-    if ((event_client_wrote= CreateEvent(0, FALSE, FALSE, tmp)) == 0)
+    if ((event_client_wrote= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
     {
       errmsg= "Could not create client write event";
       goto errorconn;
     }
     strmov(suffix_pos, "CLIENT_READ");
-    if ((event_client_read= CreateEvent(0, FALSE, FALSE, tmp)) == 0)
+    if ((event_client_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
     {
       errmsg= "Could not create client read event";
       goto errorconn;
     }
     strmov(suffix_pos, "SERVER_READ");
-    if ((event_server_read= CreateEvent(0, FALSE, FALSE, tmp)) == 0)
+    if ((event_server_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
     {
       errmsg= "Could not create server read event";
       goto errorconn;
     }
     strmov(suffix_pos, "SERVER_WROTE");
-    if ((event_server_wrote= CreateEvent(0, FALSE, FALSE, tmp)) == 0)
+    if ((event_server_wrote= CreateEvent(sa_event,
+                                         FALSE, FALSE, tmp)) == 0)
     {
       errmsg= "Could not create server write event";
       goto errorconn;
     }
     strmov(suffix_pos, "CONNECTION_CLOSED");
-    if ((event_conn_closed= CreateEvent(0, TRUE , FALSE, tmp)) == 0)
+    if ((event_conn_closed= CreateEvent(sa_event,
+                                        TRUE, FALSE, tmp)) == 0)
     {
       errmsg= "Could not create closed connection event";
       goto errorconn;
@@ -4082,6 +4105,8 @@
     strxmov(buff, "Can't create shared memory service: ", errmsg, ".", NullS);
     sql_perror(buff);
   }
+  my_security_attr_free(sa_event);
+  my_security_attr_free(sa_mapping);
   if (handle_connect_map)	UnmapViewOfFile(handle_connect_map);
   if (handle_connect_file_map)	CloseHandle(handle_connect_file_map);
   if (event_connect_answer)	CloseHandle(event_connect_answer);
@@ -5243,7 +5268,7 @@
    "Max number of errors/warnings to store for a statement.",
    (gptr*) &global_system_variables.max_error_count,
    (gptr*) &max_system_variables.max_error_count,
-   0, GET_ULONG, REQUIRED_ARG, DEFAULT_ERROR_COUNT, 1, 65535, 0, 1, 0},
+   0, GET_ULONG, REQUIRED_ARG, DEFAULT_ERROR_COUNT, 0, 65535, 0, 1, 0},
   {"max_heap_table_size", OPT_MAX_HEP_TABLE_SIZE,
    "Don't allow creation of heap tables bigger than this.",
    (gptr*) &global_system_variables.max_heap_table_size,
@@ -5707,7 +5732,8 @@
   {"Select_range_check",       (char*) offsetof(STATUS_VAR, select_range_check_count),
SHOW_LONG_STATUS},
   {"Select_scan",	       (char*) offsetof(STATUS_VAR, select_scan_count),
SHOW_LONG_STATUS},
   {"Slave_open_temp_tables",   (char*) &slave_open_temp_tables, SHOW_LONG},
-  {"Slave_running",            (char*) 0, SHOW_SLAVE_RUNNING},
+  {"Slave_running",            (char*) 0,                       SHOW_SLAVE_RUNNING},
+  {"Slave_retried_transactions",(char*) 0,                     
SHOW_SLAVE_RETRIED_TRANS},
   {"Slow_launch_threads",      (char*) &slow_launch_threads,    SHOW_LONG},
   {"Slow_queries",             (char*) offsetof(STATUS_VAR, long_query_count),
SHOW_LONG_STATUS},
   {"Sort_merge_passes",	       (char*) offsetof(STATUS_VAR, filesort_merge_passes),
SHOW_LONG_STATUS},
@@ -5901,13 +5927,6 @@
     exit(1);
   multi_keycache_init(); /* set key_cache_hash.default_value = dflt_key_cache */
 
-  /* Initialize structures that is used when processing options */
-  replicate_rewrite_db.empty();
-  replicate_do_db.empty();
-  replicate_ignore_db.empty();
-  binlog_do_db.empty();
-  binlog_ignore_db.empty();
-
   /* Set directory paths */
   strmake(language, LANGUAGE, sizeof(language)-1);
   strmake(mysql_real_data_home, get_relative_path(DATADIR),
@@ -5972,6 +5991,11 @@
 #else
   have_archive_db= SHOW_OPTION_NO;
 #endif
+#ifdef HAVE_BLACKHOLE_DB
+  have_blackhole_db= SHOW_OPTION_YES;
+#else
+  have_blackhole_db= SHOW_OPTION_NO;
+#endif
 #ifdef HAVE_FEDERATED_DB
   have_federated_db= SHOW_OPTION_YES;
 #else
@@ -6162,14 +6186,12 @@
   }
   case (int)OPT_REPLICATE_IGNORE_DB:
   {
-    i_string *db = new i_string(argument);
-    replicate_ignore_db.push_back(db);
+    rpl_filter->add_ignore_db(argument);
     break;
   }
   case (int)OPT_REPLICATE_DO_DB:
   {
-    i_string *db = new i_string(argument);
-    replicate_do_db.push_back(db);
+    rpl_filter->add_do_db(argument);
     break;
   }
   case (int)OPT_REPLICATE_REWRITE_DB:
@@ -6202,15 +6224,13 @@
       exit(1);
     }
 
-    i_string_pair *db_pair = new i_string_pair(key, val);
-    replicate_rewrite_db.push_back(db_pair);
+    rpl_filter->add_db_rewrite(key, val);
     break;
   }
 
   case (int)OPT_BINLOG_IGNORE_DB:
   {
-    i_string *db = new i_string(argument);
-    binlog_ignore_db.push_back(db);
+    binlog_filter->add_ignore_db(argument);
     break;
   }
   case OPT_BINLOG_FORMAT:
@@ -6235,58 +6255,43 @@
 
   case (int)OPT_BINLOG_DO_DB:
   {
-    i_string *db = new i_string(argument);
-    binlog_do_db.push_back(db);
+    binlog_filter->add_do_db(argument);
     break;
   }
   case (int)OPT_REPLICATE_DO_TABLE:
   {
-    if (!do_table_inited)
-      init_table_rule_hash(&replicate_do_table, &do_table_inited);
-    if (add_table_rule(&replicate_do_table, argument))
+    if (rpl_filter->add_do_table(argument))
     {
       fprintf(stderr, "Could not add do table rule '%s'!\n", argument);
       exit(1);
     }
-    table_rules_on = 1;
     break;
   }
   case (int)OPT_REPLICATE_WILD_DO_TABLE:
   {
-    if (!wild_do_table_inited)
-      init_table_rule_array(&replicate_wild_do_table,
-			    &wild_do_table_inited);
-    if (add_wild_table_rule(&replicate_wild_do_table, argument))
+    if (rpl_filter->add_wild_do_table(argument))
     {
       fprintf(stderr, "Could not add do table rule '%s'!\n", argument);
       exit(1);
     }
-    table_rules_on = 1;
     break;
   }
   case (int)OPT_REPLICATE_WILD_IGNORE_TABLE:
   {
-    if (!wild_ignore_table_inited)
-      init_table_rule_array(&replicate_wild_ignore_table,
-			    &wild_ignore_table_inited);
-    if (add_wild_table_rule(&replicate_wild_ignore_table, argument))
+    if (rpl_filter->add_wild_ignore_table(argument))
     {
       fprintf(stderr, "Could not add ignore table rule '%s'!\n", argument);
       exit(1);
     }
-    table_rules_on = 1;
     break;
   }
   case (int)OPT_REPLICATE_IGNORE_TABLE:
   {
-    if (!ignore_table_inited)
-      init_table_rule_hash(&replicate_ignore_table, &ignore_table_inited);
-    if (add_table_rule(&replicate_ignore_table, argument))
+    if (rpl_filter->add_ignore_table(argument))
     {
       fprintf(stderr, "Could not add ignore table rule '%s'!\n", argument);
       exit(1);
     }
-    table_rules_on = 1;
     break;
   }
 #endif /* HAVE_REPLICATION */

--- 1.243/sql/slave.cc	2005-04-01 13:32:30 +02:00
+++ 1.244/sql/slave.cc	2005-04-08 11:24:25 +02:00
@@ -22,12 +22,14 @@
 #include <myisam.h>
 #include "slave.h"
 #include "sql_repl.h"
+#include "rpl_filter.h"
 #include "repl_failsafe.h"
 #include <thr_alarm.h>
 #include <my_dir.h>
 #include <sql_common.h>
 #include "rpl_tblmap.h"
 
+#define MAX_SLAVE_RETRY_PAUSE 5
 bool use_slave_mask = 0;
 MY_BITMAP slave_error_mask;
 
@@ -36,11 +38,7 @@
 volatile bool slave_sql_running = 0, slave_io_running = 0;
 char* slave_load_tmpdir = 0;
 MASTER_INFO *active_mi;
-HASH replicate_do_table, replicate_ignore_table;
-DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table;
-bool do_table_inited = 0, ignore_table_inited = 0;
-bool wild_do_table_inited = 0, wild_ignore_table_inited = 0;
-bool table_rules_on= 0, replicate_same_server_id;
+bool replicate_same_server_id;
 ulonglong relay_log_space_limit = 0;
 
 /*
@@ -194,20 +192,6 @@
 }
 
 
-static void free_table_ent(TABLE_RULE_ENT* e)
-{
-  my_free((gptr) e, MYF(0));
-}
-
-
-static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
-			   my_bool not_used __attribute__((unused)))
-{
-  *len = e->key_len;
-  return (byte*)e->db;
-}
-
-
 /*
   Open the given relay log
 
@@ -809,228 +793,6 @@
 }
 
 
-void init_table_rule_hash(HASH* h, bool* h_inited)
-{
-  hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0,
-	    (hash_get_key) get_table_key,
-	    (hash_free_key) free_table_ent, 0);
-  *h_inited = 1;
-}
-
-
-void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited)
-{
-  my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE,
-		     TABLE_RULE_ARR_SIZE);
-  *a_inited = 1;
-}
-
-
-static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
-{
-  uint i;
-  const char* key_end = key + len;
-  
-  for (i = 0; i < a->elements; i++)
-    {
-      TABLE_RULE_ENT* e ;
-      get_dynamic(a, (gptr)&e, i);
-      if (!my_wildcmp(system_charset_info, key, key_end, 
-                            (const char*)e->db,
-			    (const char*)(e->db + e->key_len),
-			    '\\',wild_one,wild_many))
-	return e;
-    }
-  
-  return 0;
-}
-
-
-/*
-  Checks whether tables match some (wild_)do_table and (wild_)ignore_table
-  rules (for replication)
-
-  SYNOPSIS
-    tables_ok()
-    thd             thread (SQL slave thread normally)
-    tables          list of tables to check
-
-  NOTES
-    Note that changing the order of the tables in the list can lead to
-    different results. Note also the order of precedence of the do/ignore 
-    rules (see code below). For that reason, users should not set conflicting 
-    rules because they may get unpredicted results (precedence order is
-    explained in the manual).
-    If no table of the list is marked "updating" (so far this can only happen
-    if the statement is a multi-delete (SQLCOM_DELETE_MULTI) and the "tables"
-    is the tables in the FROM): then we always return 0, because there is no
-    reason we play this statement on this slave if it updates nothing. In the
-    case of SQLCOM_DELETE_MULTI, there will be a second call to tables_ok(),
-    with tables having "updating==TRUE" (those after the DELETE), so this
-    second call will make the decision (because
-    all_tables_not_ok() = !tables_ok(1st_list) && !tables_ok(2nd_list)).
-
-    Thought which arose from a question of a big customer "I want to include
-    all tables like "abc.%" except the "%.EFG"". This can't be done now. If we
-    supported Perl regexps we could do it with this pattern: /^abc\.(?!EFG)/
-    (I could not find an equivalent in the regex library MySQL uses).
-
-  RETURN VALUES
-    0           should not be logged/replicated
-    1           should be logged/replicated                  
-*/
-
-bool tables_ok(THD* thd, TABLE_LIST* tables)
-{
-  bool some_tables_updating= 0;
-  DBUG_ENTER("tables_ok");
-
-  for (; tables; tables= tables->next_global)
-  {
-    char hash_key[2*NAME_LEN+2];
-    char *end;
-    uint len;
-
-    if (!tables->updating) 
-      continue;
-    some_tables_updating= 1;
-    end= strmov(hash_key, tables->db ? tables->db : thd->db);
-    *end++= '.';
-    len= (uint) (strmov(end, tables->table_name) - hash_key);
-    if (do_table_inited) // if there are any do's
-    {
-      if (hash_search(&replicate_do_table, (byte*) hash_key, len))
-	DBUG_RETURN(1);
-    }
-    if (ignore_table_inited) // if there are any ignores
-    {
-      if (hash_search(&replicate_ignore_table, (byte*) hash_key, len))
-	DBUG_RETURN(0); 
-    }
-    if (wild_do_table_inited && find_wild(&replicate_wild_do_table,
-					  hash_key, len))
-      DBUG_RETURN(1);
-    if (wild_ignore_table_inited && find_wild(&replicate_wild_ignore_table,
-					      hash_key, len))
-      DBUG_RETURN(0);
-  }
-
-  /*
-    If no table was to be updated, ignore statement (no reason we play it on
-    slave, slave is supposed to replicate _changes_ only).
-    If no explicit rule found and there was a do list, do not replicate.
-    If there was no do list, go ahead
-  */
-  DBUG_RETURN(some_tables_updating &&
-              !do_table_inited && !wild_do_table_inited);
-}
-
-
-/*
-  Checks whether a db matches wild_do_table and wild_ignore_table
-  rules (for replication)
-
-  SYNOPSIS
-    db_ok_with_wild_table()
-    db		name of the db to check.
-		Is tested with check_db_name() before calling this function.
-
-  NOTES
-    Here is the reason for this function.
-    We advise users who want to exclude a database 'db1' safely to do it
-    with replicate_wild_ignore_table='db1.%' instead of binlog_ignore_db or
-    replicate_ignore_db because the two lasts only check for the selected db,
-    which won't work in that case:
-    USE db2;
-    UPDATE db1.t SET ... #this will be replicated and should not
-    whereas replicate_wild_ignore_table will work in all cases.
-    With replicate_wild_ignore_table, we only check tables. When
-    one does 'DROP DATABASE db1', tables are not involved and the
-    statement will be replicated, while users could expect it would not (as it
-    rougly means 'DROP db1.first_table, DROP db1.second_table...').
-    In other words, we want to interpret 'db1.%' as "everything touching db1".
-    That is why we want to match 'db1' against 'db1.%' wild table rules.
-
-  RETURN VALUES
-    0           should not be logged/replicated
-    1           should be logged/replicated
- */
-
-int db_ok_with_wild_table(const char *db)
-{
-  char hash_key[NAME_LEN+2];
-  char *end;
-  int len;
-  end= strmov(hash_key, db);
-  *end++= '.';
-  len= end - hash_key ;
-  if (wild_do_table_inited && find_wild(&replicate_wild_do_table,
-                                        hash_key, len))
-    return 1;
-  if (wild_ignore_table_inited && find_wild(&replicate_wild_ignore_table,
-                                            hash_key, len))
-    return 0;
-  
-  /*
-    If no explicit rule found and there was a do list, do not replicate.
-    If there was no do list, go ahead
-  */
-  return !wild_do_table_inited;
-}
-
-
-int add_table_rule(HASH* h, const char* table_spec)
-{
-  const char* dot = strchr(table_spec, '.');
-  if (!dot) return 1;
-  // len is always > 0 because we know the there exists a '.'
-  uint len = (uint)strlen(table_spec);
-  TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
-						 + len, MYF(MY_WME));
-  if (!e) return 1;
-  e->db = (char*)e + sizeof(TABLE_RULE_ENT);
-  e->tbl_name = e->db + (dot - table_spec) + 1;
-  e->key_len = len;
-  memcpy(e->db, table_spec, len);
-  (void)my_hash_insert(h, (byte*)e);
-  return 0;
-}
-
-
-/*
-  Add table expression with wildcards to dynamic array
-*/
-
-int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
-{
-  const char* dot = strchr(table_spec, '.');
-  if (!dot) return 1;
-  uint len = (uint)strlen(table_spec);
-  TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
-						 + len, MYF(MY_WME));
-  if (!e) return 1;
-  e->db = (char*)e + sizeof(TABLE_RULE_ENT);
-  e->tbl_name = e->db + (dot - table_spec) + 1;
-  e->key_len = len;
-  memcpy(e->db, table_spec, len);
-  insert_dynamic(a, (gptr)&e);
-  return 0;
-}
-
-
-static void free_string_array(DYNAMIC_ARRAY *a)
-{
-  uint i;
-  for (i = 0; i < a->elements; i++)
-    {
-      char* p;
-      get_dynamic(a, (gptr) &p, i);
-      my_free(p, MYF(MY_WME));
-    }
-  delete_dynamic(a);
-}
-
-
 #ifdef NOT_USED_YET
 static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/)
 {
@@ -1066,14 +828,6 @@
     */
     terminate_slave_threads(active_mi,SLAVE_FORCE_ALL);
     end_master_info(active_mi);
-    if (do_table_inited)
-      hash_free(&replicate_do_table);
-    if (ignore_table_inited)
-      hash_free(&replicate_ignore_table);
-    if (wild_do_table_inited)
-      free_string_array(&replicate_wild_do_table);
-    if (wild_ignore_table_inited)
-      free_string_array(&replicate_wild_ignore_table);
     delete active_mi;
     active_mi= 0;
   }
@@ -1153,24 +907,6 @@
 }
 
 
-const char *rewrite_db(const char* db, uint32 *new_len)
-{
-  if (replicate_rewrite_db.is_empty() || !db)
-    return db;
-  I_List_iterator<i_string_pair> it(replicate_rewrite_db);
-  i_string_pair* tmp;
-
-  while ((tmp=it++))
-  {
-    if (!strcmp(tmp->key, db))
-    {
-      *new_len= (uint32)strlen(tmp->val);
-      return tmp->val;
-    }
-  }
-  return db;
-}
-
 /*
   From other comments and tests in code, it looks like
   sometimes Query_log_event and Load_log_event can have db == 0
@@ -1183,60 +919,6 @@
   return (db ? db : "");
 }
 
-/*
-  Checks whether a db matches some do_db and ignore_db rules
-  (for logging or replication)
-
-  SYNOPSIS
-    db_ok()
-    db              name of the db to check
-    do_list         either binlog_do_db or replicate_do_db
-    ignore_list     either binlog_ignore_db or replicate_ignore_db
-
-  RETURN VALUES
-    0           should not be logged/replicated
-    1           should be logged/replicated                  
-*/
-
-int db_ok(const char* db, I_List<i_string> &do_list,
-	  I_List<i_string> &ignore_list )
-{
-  if (do_list.is_empty() && ignore_list.is_empty())
-    return 1; // ok to replicate if the user puts no constraints
-
-  /*
-    If the user has specified restrictions on which databases to replicate
-    and db was not selected, do not replicate.
-  */
-  if (!db)
-    return 0;
-
-  if (!do_list.is_empty()) // if the do's are not empty
-  {
-    I_List_iterator<i_string> it(do_list);
-    i_string* tmp;
-
-    while ((tmp=it++))
-    {
-      if (!strcmp(tmp->ptr, db))
-	return 1; // match
-    }
-    return 0;
-  }
-  else // there are some elements in the don't, otherwise we cannot get here
-  {
-    I_List_iterator<i_string> it(ignore_list);
-    i_string* tmp;
-
-    while ((tmp=it++))
-    {
-      if (!strcmp(tmp->ptr, db))
-	return 0; // match
-    }
-    return 1;
-  }
-}
-
 
 static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
 				 const char *default_val)
@@ -1457,11 +1139,10 @@
     such check will broke everything for them. (And now everything will 
     work for them because by default both their master and slave will have 
     'SYSTEM' time zone).
-
-    TODO: when the new replication of timezones is sorted out with Dmitri,
-    change >= '4' to == '4'.
+    This check is only necessary for 4.x masters (and < 5.0.4 masters but
+    those were alpha).
   */
-  if ((*mysql->server_version >= '4') &&
+  if ((*mysql->server_version == '4') &&
       !mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) &&
       (master_res= mysql_store_result(mysql)))
   {
@@ -2246,48 +1927,6 @@
 }
 
 
-/*
-  Builds a String from a HASH of TABLE_RULE_ENT. Cannot be used for any other 
-  hash, as it assumes that the hash entries are TABLE_RULE_ENT.
-
-  SYNOPSIS
-    table_rule_ent_hash_to_str()
-    s               pointer to the String to fill
-    h               pointer to the HASH to read
-
-  RETURN VALUES
-    none
-*/
-
-void table_rule_ent_hash_to_str(String* s, HASH* h)
-{
-  s->length(0);
-  for (uint i=0 ; i < h->records ; i++)
-  {
-    TABLE_RULE_ENT* e= (TABLE_RULE_ENT*) hash_element(h, i);
-    if (s->length())
-      s->append(',');
-    s->append(e->db,e->key_len);
-  }
-}
-
-/*
-  Mostly the same thing as above
-*/
-
-void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a)
-{
-  s->length(0);
-  for (uint i=0 ; i < a->elements ; i++)
-  {
-    TABLE_RULE_ENT* e;
-    get_dynamic(a, (gptr)&e, i);
-    if (s->length())
-      s->append(',');
-    s->append(e->db,e->key_len);
-  }
-}
-
 bool show_master_info(THD* thd, MASTER_INFO* mi)
 {
   // TODO: fix this for multi-master
@@ -2382,23 +2021,18 @@
     protocol->store(mi->rli.group_master_log_name, &my_charset_bin);
     protocol->store(mi->slave_running ? "Yes":"No", &my_charset_bin);
     protocol->store(mi->rli.slave_running ? "Yes":"No", &my_charset_bin);
-    protocol->store(&replicate_do_db);
-    protocol->store(&replicate_ignore_db);
-    /*
-      We can't directly use some protocol->store for 
-      replicate_*_table,
-      as Protocol doesn't know the TABLE_RULE_ENT struct.
-      We first build Strings and then pass them to protocol->store.
-    */
+    protocol->store(rpl_filter->get_do_db());
+    protocol->store(rpl_filter->get_ignore_db());
+
     char buf[256];
     String tmp(buf, sizeof(buf), &my_charset_bin);
-    table_rule_ent_hash_to_str(&tmp, &replicate_do_table);
+    rpl_filter->get_do_table(&tmp);
     protocol->store(&tmp);
-    table_rule_ent_hash_to_str(&tmp, &replicate_ignore_table);
+    rpl_filter->get_ignore_table(&tmp);
     protocol->store(&tmp);
-    table_rule_ent_dynamic_array_to_str(&tmp, &replicate_wild_do_table);
+    rpl_filter->get_wild_do_table(&tmp);
     protocol->store(&tmp);
-    table_rule_ent_dynamic_array_to_str(&tmp, &replicate_wild_ignore_table);
+    rpl_filter->get_wild_ignore_table(&tmp);
     protocol->store(&tmp);
 
     protocol->store((uint32) mi->rli.last_slave_errno);
@@ -2530,7 +2164,7 @@
    ignore_log_space_limit(0), last_master_timestamp(0), slave_skip_counter(0),
    abort_pos_wait(0), slave_run_id(0), sql_thd(0), last_slave_errno(0),
    inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE),
-   until_log_pos(0)
+   until_log_pos(0), retried_trans(0)
 {
   group_relay_log_name[0]= event_relay_log_name[0]=
     group_master_log_name[0]= 0;
@@ -2770,6 +2404,18 @@
   thd->variables.completion_type= 0;
 }
 
+void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO *rli)
+{
+  thd->variables.character_set_client=
+    global_system_variables.character_set_client;
+  thd->variables.collation_connection=
+    global_system_variables.collation_connection;
+  thd->variables.collation_server=
+    global_system_variables.collation_server;
+  thd->update_charset();
+  rli->cached_charset_invalidate();
+}
+
 /*
   init_slave_thread()
 */
@@ -3250,9 +2896,8 @@
           init_master_info()).
           b) init_relay_log_pos(), because the BEGIN may be an older relay log.
         */
-        if (rli->trans_retries--)
+        if (rli->trans_retries < slave_trans_retries)
         {
-          sql_print_information("Slave SQL thread retries transaction");
           if (init_master_info(rli->mi, 0, 0, 0, SLAVE_SQL))
             sql_print_error("Failed to initialize the master info structure");
           else if (init_relay_log_pos(rli,
@@ -3264,8 +2909,16 @@
           else
           {
             exec_res= 0;
-            sleep(2); // chance for concurrent connection to get more locks
-          }
+	    /* chance for concurrent connection to get more locks */
+            safe_sleep(thd, min(rli->trans_retries, MAX_SLAVE_RETRY_PAUSE),
+		       (CHECK_KILLED_FUNC)sql_slave_killed, (void*)rli);
+            pthread_mutex_lock(&rli->data_lock); // because of SHOW STATUS
+	    rli->trans_retries++;
+            rli->retried_trans++;
+            pthread_mutex_unlock(&rli->data_lock);
+            DBUG_PRINT("info", ("Slave retries transaction "
+                                "rli->trans_retries: %lu", rli->trans_retries));
+	  }
         }
         else
           sql_print_error("Slave SQL thread retried transaction %lu time(s) "
@@ -3274,8 +2927,8 @@
                           slave_trans_retries);
       }
       if (!((thd->options & OPTION_BEGIN) && opt_using_transactions))
-        rli->trans_retries= slave_trans_retries; // restart from fresh
-    }
+         rli->trans_retries= 0; // restart from fresh
+     }
     return exec_res;
   }
   else
@@ -3690,7 +3343,7 @@
   pthread_mutex_lock(&rli->log_space_lock);
   rli->ignore_log_space_limit= 0;
   pthread_mutex_unlock(&rli->log_space_lock);
-  rli->trans_retries= slave_trans_retries; // start from "no error"
+  rli->trans_retries= 0; // start from "no error"
 
   if (init_relay_log_pos(rli,
 			 rli->group_relay_log_name,
@@ -3845,10 +3498,8 @@
 
   if (unlikely(!cev->is_valid()))
     DBUG_RETURN(1);
-  /*
-    TODO: fix to honor table rules, not only db rules
-  */
-  if (!db_ok(cev->db, replicate_do_db, replicate_ignore_db))
+
+  if (!rpl_filter->db_ok(cev->db))
   {
     skip_load_data_infile(net);
     DBUG_RETURN(0);

--- 1.135/sql/sql_acl.cc	2005-04-01 13:32:31 +02:00
+++ 1.136/sql/sql_acl.cc	2005-04-08 11:24:25 +02:00
@@ -27,9 +27,6 @@
 
 #include "mysql_priv.h"
 #include "hash_filo.h"
-#ifdef HAVE_REPLICATION
-#include "sql_repl.h" //for tables_ok()
-#endif
 #include <m_ctype.h>
 #include <stdarg.h>
 #include "sp_head.h"
@@ -241,7 +238,7 @@
 
   DBUG_PRINT("info",("user table fields: %d, password length: %d",
 		     table->s->fields, table->field[2]->field_length));
-  
+
   pthread_mutex_lock(&LOCK_global_system_variables);
   if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH)
   {
@@ -325,6 +322,12 @@
       if (table->s->fields <= 33 && (user.access & ALTER_ACL))
         user.access|= ALTER_PROC_ACL;
 
+      /*
+        pre 5.0.3 did not have CREATE_USER_ACL
+      */
+      if (table->s->fields <= 36 && (user.access & GRANT_ACL))
+        user.access|= CREATE_USER_ACL;
+
       user.sort= get_sort(2,user.host.hostname,user.user);
       user.hostname_length= (user.host.hostname ?
                              (uint) strlen(user.host.hostname) : 0);
@@ -1093,6 +1096,9 @@
 
 /*
   Get privilege for a host, user and db combination
+
+  as db_is_pattern changes the semantics of comparison,
+  acl_cache is not used if db_is_pattern is set.
 */
 
 ulong acl_get(const char *host, const char *ip,
@@ -1112,7 +1118,7 @@
     db=tmp_db;
   }
   key_length=(uint) (end-key);
-  if ((entry=(acl_entry*) acl_cache->search(key,key_length)))
+  if (!db_is_pattern && (entry=(acl_entry*)
acl_cache->search(key,key_length)))
   {
     db_access=entry->access;
     VOID(pthread_mutex_unlock(&acl_cache->lock));
@@ -1161,7 +1167,8 @@
   }
 exit:
   /* Save entry in cache for quick retrieval */
-  if ((entry= (acl_entry*) malloc(sizeof(acl_entry)+key_length)))
+  if (!db_is_pattern &&
+      (entry= (acl_entry*) malloc(sizeof(acl_entry)+key_length)))
   {
     entry->access=(db_access & host_access);
     entry->length=key_length;
@@ -1499,7 +1506,7 @@
     GRANT and REVOKE are applied the slave in/exclusion rules as they are
     some kind of updates to the mysql.% tables.
   */
-  if (thd->slave_thread && table_rules_on)
+  if (thd->slave_thread && rpl_filter->is_on())
   {
     /*
       The tables must be marked "updating" so that tables_ok() takes them into
@@ -1507,7 +1514,7 @@
     */
     tables.updating= 1;
     /* Thanks to bzero, tables.next==0 */
-    if (!tables_ok(0, &tables))
+    if (!rpl_filter->tables_ok(0, &tables))
       DBUG_RETURN(0);
   }
 #endif
@@ -1543,18 +1550,26 @@
 }
 
 
-/* Return 1 if we are allowed to create new users */
+/*
+  Return 1 if we are allowed to create new users
+  the logic here is: INSERT_ACL is sufficient.
+  It's also a requirement in opt_safe_user_create,
+  otherwise CREATE_USER_ACL is enough.
+*/
 
 static bool test_if_create_new_users(THD *thd)
 {
-  bool create_new_users=1;    // Assume that we are allowed to create new users
-  if (opt_safe_user_create && !(thd->master_access & INSERT_ACL))
+  bool create_new_users= test(thd->master_access & INSERT_ACL) ||
+                         (!opt_safe_user_create &&
+                          test(thd->master_access & CREATE_USER_ACL));
+  if (!create_new_users)
   {
     TABLE_LIST tl;
     ulong db_access;
     bzero((char*) &tl,sizeof(tl));
     tl.db=	   (char*) "mysql";
     tl.table_name=  (char*) "user";
+    create_new_users= 1;
 
     db_access=acl_get(thd->host, thd->ip,
 		      thd->priv_user, tl.db, 0);
@@ -1574,7 +1589,7 @@
 
 static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
 			      ulong rights, bool revoke_grant,
-			      bool create_user)
+			      bool can_create_user, bool no_auto_create)
 {
   int error = -1;
   bool old_row_exists=0;
@@ -1616,8 +1631,8 @@
       goto end;
     }
     /*
-      There are four options which affect the process of creation of 
-      a new user(mysqld option --safe-create-user, 'insert' privilege
+      There are four options which affect the process of creation of
+      a new user (mysqld option --safe-create-user, 'insert' privilege
       on 'mysql.user' table, using 'GRANT' with 'IDENTIFIED BY' and
       SQL_MODE flag NO_AUTO_CREATE_USER). Below is the simplified rule
       how it should work.
@@ -1625,11 +1640,17 @@
       else if (identified_by) => create
       else if (no_auto_create_user) => reject
       else create
+
+      see also test_if_create_new_users()
     */
-    else if (((thd->variables.sql_mode & MODE_NO_AUTO_CREATE_USER) &&
-              !password_len) || !create_user)
+    else if (!password_len && no_auto_create)
     {
-      my_error(ER_NO_PERMISSION_TO_CREATE_USER, MYF(0),
+      my_error(ER_PASSWORD_NO_MATCH, MYF(0), combo.user.str, combo.host.str);
+      goto end;
+    }
+    else if (!can_create_user)
+    {
+      my_error(ER_CANT_CREATE_USER_WITH_GRANT, MYF(0),
                thd->user, thd->host_or_ip);
       goto end;
     }
@@ -2670,14 +2691,14 @@
     GRANT and REVOKE are applied the slave in/exclusion rules as they are
     some kind of updates to the mysql.% tables.
   */
-  if (thd->slave_thread && table_rules_on)
+  if (thd->slave_thread && rpl_filter->is_on())
   {
     /*
       The tables must be marked "updating" so that tables_ok() takes them into
       account in tests.
     */
     tables[0].updating= tables[1].updating= tables[2].updating= 1;
-    if (!tables_ok(0, tables))
+    if (!rpl_filter->tables_ok(0, tables))
       DBUG_RETURN(FALSE);
   }
 #endif
@@ -2710,7 +2731,9 @@
     /* Create user if needed */
     pthread_mutex_lock(&acl_cache->lock);
     error=replace_user_table(thd, tables[0].table, *Str,
-			     0, revoke_grant, create_new_users);
+			     0, revoke_grant, create_new_users,
+                             test(thd->variables.sql_mode &
+                                  MODE_NO_AUTO_CREATE_USER));
     pthread_mutex_unlock(&acl_cache->lock);
     if (error)
     {
@@ -2873,14 +2896,14 @@
     GRANT and REVOKE are applied the slave in/exclusion rules as they are
     some kind of updates to the mysql.% tables.