List:Commits« Previous MessageNext Message »
From:jani Date:March 1 2007 11:10pm
Subject:bk commit into 5.1 tree (jani:1.2466)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of jani. When jani 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@stripped, 2007-03-02 00:10:15+02:00, jani@stripped +42 -0
  Merge ua141d10.elisa.omakaista.fi:/home/my/bk/mysql-5.0-marvel
  into  ua141d10.elisa.omakaista.fi:/home/my/bk/mysql-5.1-marvel
  MERGE: 1.1810.2372.109

  BitKeeper/deleted/.del-ctype_cp932_notembedded.result~f8bc6ad0446e82e3@stripped, 2007-03-02
00:10:10+02:00, jani@stripped +0 -3
    Manual merge from 5.0
    MERGE: 1.1.1.2

  BitKeeper/deleted/.del-ctype_cp932_notembedded.result~f8bc6ad0446e82e3@stripped,
2007-03-01 23:01:58+02:00, jani@stripped +0 -0
    Merge rename: mysql-test/r/ctype_cp932_notembedded.result ->
BitKeeper/deleted/.del-ctype_cp932_notembedded.result~f8bc6ad0446e82e3

  BitKeeper/deleted/.del-ha_berkeley.cc@stripped, 2007-03-01 23:01:58+02:00,
jani@stripped +0 -0
    Auto merged
    MERGE: 1.151.9.2

  BitKeeper/deleted/.del-ha_berkeley.cc@stripped, 2007-03-01 23:01:58+02:00,
jani@stripped +0 -0
    Merge rename: sql/ha_berkeley.cc -> BitKeeper/deleted/.del-ha_berkeley.cc

  client/mysql_upgrade.c@stripped, 2007-03-02 00:10:10+02:00, jani@stripped
+0 -1
    Manual merge from 5.0
    MERGE: 1.6.1.12

  client/mysqltest.c@stripped, 2007-03-02 00:10:10+02:00, jani@stripped +0
-2
    Manual merge from 5.0
    MERGE: 1.155.9.88

  cmd-line-utils/readline/xmalloc.c@stripped, 2007-03-01 23:01:58+02:00,
jani@stripped +0 -3
    Auto merged
    MERGE: 1.8.1.1

  include/my_dbug.h@stripped, 2007-03-01 23:01:58+02:00, jani@stripped +0
-2
    Auto merged
    MERGE: 1.16.2.6

  mysql-test/extra/binlog_tests/ctype_cp932.test@stripped, 2007-03-01 23:01:59+02:00,
jani@stripped +0 -0
    Auto merged
    MERGE: 1.8.3.2

  mysql-test/extra/binlog_tests/ctype_cp932.test@stripped, 2007-03-01 23:01:58+02:00,
jani@stripped +0 -0
    Merge rename: mysql-test/t/ctype_cp932.test ->
mysql-test/extra/binlog_tests/ctype_cp932.test

  mysql-test/extra/binlog_tests/ctype_cp932_binlog.test@stripped, 2007-03-02 00:10:10+02:00,
jani@stripped +1 -1
    Manual merge from 5.0
    MERGE: 1.2.2.2

  mysql-test/extra/binlog_tests/ctype_cp932_binlog.test@stripped, 2007-03-01
23:01:58+02:00, jani@stripped +0 -0
    Merge rename: mysql-test/t/ctype_cp932_binlog.test ->
mysql-test/extra/binlog_tests/ctype_cp932_binlog.test

  mysql-test/r/binlog_stm_ctype_cp932.result@stripped, 2007-03-01 23:01:59+02:00,
jani@stripped +0 -0
    Auto merged
    MERGE: 1.6.3.2

  mysql-test/r/binlog_stm_ctype_cp932.result@stripped, 2007-03-01 23:01:58+02:00,
jani@stripped +0 -0
    Merge rename: mysql-test/r/ctype_cp932.result ->
mysql-test/r/binlog_stm_ctype_cp932.result

  mysql-test/r/binlog_stm_ctype_ucs.result@stripped, 2007-03-01 23:23:36+02:00,
jani@stripped +0 -9
    use local as change was independent of 5.1
    MERGE: 1.2.4.2

  mysql-test/r/binlog_stm_ctype_ucs.result@stripped, 2007-03-01 23:01:58+02:00,
jani@stripped +0 -0
    Merge rename: mysql-test/r/ctype_cp932_binlog.result ->
mysql-test/r/binlog_stm_ctype_ucs.result

  mysql-test/r/mysqlbinlog.result@stripped, 2007-03-01 23:01:59+02:00,
jani@stripped +0 -1
    Auto merged
    MERGE: 1.25.1.6

  mysql-test/r/rpl_insert_id.result@stripped, 2007-03-01 23:01:59+02:00,
jani@stripped +0 -0
    Auto merged
    MERGE: 1.12.3.9

  mysql-test/r/rpl_replicate_do.result@stripped, 2007-03-01 23:01:59+02:00,
jani@stripped +0 -0
    Auto merged
    MERGE: 1.30.1.4

  mysql-test/r/rpl_user_variables.result@stripped, 2007-03-01 23:01:59+02:00,
jani@stripped +0 -0
    Auto merged
    MERGE: 1.14.1.4

  mysql-test/t/disabled.def@stripped, 2007-03-02 00:10:10+02:00,
jani@stripped +0 -0
    Manual merge from 5.0
    MERGE: 1.2.4.23

  mysql-test/t/mysqlbinlog.test@stripped, 2007-03-01 23:01:59+02:00,
jani@stripped +0 -1
    Auto merged
    MERGE: 1.21.1.21

  mysql-test/t/rpl_insert_id.test@stripped, 2007-03-02 00:10:10+02:00,
jani@stripped +0 -0
    Manual merge from 5.0
    MERGE: 1.13.1.10

  mysql-test/t/rpl_replicate_do.test@stripped, 2007-03-01 23:01:59+02:00,
jani@stripped +0 -0
    Auto merged
    MERGE: 1.22.1.4

  mysql-test/t/rpl_user_variables.test@stripped, 2007-03-02 00:10:10+02:00,
jani@stripped +2 -1
    Manual merge from 5.0
    MERGE: 1.12.1.3

  mysql-test/valgrind.supp@stripped, 2007-03-02 00:10:10+02:00,
jani@stripped +0 -17
    Manual merge from 5.0
    MERGE: 1.3.1.5

  sql/field.cc@stripped, 2007-03-02 00:10:10+02:00, jani@stripped +0 -3
    Manual merge from 5.0
    MERGE: 1.256.1.85

  sql/ha_ndbcluster.cc@stripped, 2007-03-01 23:32:27+02:00, jani@stripped
+0 -22
    Debug changes already done.
    MERGE: 1.175.1.125

  sql/item_func.cc@stripped, 2007-03-01 23:01:59+02:00, jani@stripped +0
-0
    Auto merged
    MERGE: 1.270.1.55

  sql/log.cc@stripped, 2007-03-02 00:10:10+02:00, jani@stripped +1 -4
    Manual merge from 5.0
    MERGE: 1.158.1.47

  sql/log_event.cc@stripped, 2007-03-01 23:02:00+02:00, jani@stripped +0
-0
    Auto merged
    MERGE: 1.174.1.53

  sql/log_event.h@stripped, 2007-03-01 23:02:00+02:00, jani@stripped +0 -0
    Auto merged
    MERGE: 1.122.1.12

  sql/mysql_priv.h@stripped, 2007-03-02 00:10:10+02:00, jani@stripped +0
-9
    Manual merge from 5.0
    MERGE: 1.290.1.144

  sql/mysqld.cc@stripped, 2007-03-02 00:10:10+02:00, jani@stripped +0 -1
    Manual merge from 5.0
    MERGE: 1.439.1.153

  sql/slave.cc@stripped, 2007-03-02 00:10:10+02:00, jani@stripped +6 -10
    Manual merge from 5.0
    MERGE: 1.241.1.54

  sql/slave.h@stripped, 2007-03-01 23:02:00+02:00, jani@stripped +0 -0
    Auto merged
    MERGE: 1.85.1.15

  sql/sp_head.cc@stripped, 2007-03-02 00:10:10+02:00, jani@stripped +0 -0
    Manual merge from 5.0
    MERGE: 1.200.7.10

  sql/sql_class.cc@stripped, 2007-03-02 00:10:10+02:00, jani@stripped +1
-3
    Manual merge from 5.0
    MERGE: 1.223.1.38

  sql/sql_class.h@stripped, 2007-03-02 00:10:11+02:00, jani@stripped +0 -1
    Manual merge from 5.0
    MERGE: 1.230.1.91

  sql/sql_insert.cc@stripped, 2007-03-02 00:10:11+02:00, jani@stripped +1
-2
    Manual merge from 5.0
    MERGE: 1.146.1.74

  sql/sql_load.cc@stripped, 2007-03-01 23:02:01+02:00, jani@stripped +0 -0
    Auto merged
    MERGE: 1.78.1.29

  sql/sql_parse.cc@stripped, 2007-03-02 00:10:11+02:00, jani@stripped +0
-0
    Manual merge from 5.0
    MERGE: 1.426.1.179

  sql/sql_repl.cc@stripped, 2007-03-01 23:02:02+02:00, jani@stripped +0 -2
    Auto merged
    MERGE: 1.133.1.26

  sql/sql_trigger.cc@stripped, 2007-03-01 23:02:02+02:00, jani@stripped +0
-0
    Auto merged
    MERGE: 1.35.1.29

  sql/sql_trigger.h@stripped, 2007-03-01 23:02:02+02:00, jani@stripped +0
-0
    Auto merged
    MERGE: 1.19.1.7

  sql/sql_yacc.yy@stripped, 2007-03-02 00:10:11+02:00, jani@stripped +0 -1
    Manual merge from 5.0
    MERGE: 1.371.1.134

  storage/archive/ha_archive.cc@stripped, 2007-03-02 00:10:11+02:00,
jani@stripped +0 -3
    Manual merge from 5.0
    MERGE: 1.60.14.3

  storage/archive/ha_archive.cc@stripped, 2007-03-01 23:01:58+02:00,
jani@stripped +0 -0
    Merge rename: sql/ha_archive.cc -> storage/archive/ha_archive.cc

  support-files/compiler_warnings.supp@stripped, 2007-03-02 00:10:11+02:00,
jani@stripped +0 -56
    Manual merge from 5.0
    MERGE: 1.2.1.6

# 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:	jani
# Host:	ua141d10.elisa.omakaista.fi
# Root:	/home/my/bk/mysql-5.1-marvel/RESYNC

--- 1.374/sql/field.cc	2007-03-02 00:10:25 +02:00
+++ 1.375/sql/field.cc	2007-03-02 00:10:25 +02:00
@@ -7203,7 +7203,7 @@
                               cannot_convert_error_pos, from + length))
     return 2;
 
-  if (copy_length < length)
+  if (from_end_pos < from + length)
   {
     report_data_too_long(this);
     return 2;

--- 1.151.9.1/sql/ha_berkeley.cc	2007-03-02 00:10:25 +02:00
+++ 1.189/BitKeeper/deleted/.del-ha_berkeley.cc	2007-03-02 00:10:25 +02:00
@@ -24,7 +24,8 @@
     We will need an updated Berkeley DB version for this.
   - Killing threads that has got a 'deadlock'
   - SHOW TABLE STATUS should give more information about the table.
-  - Get a more accurate count of the number of rows (estimate_rows_upper_bound()).
+  - Get a more accurate count of the number of rows
+    (estimate_rows_upper_bound()).
     We could store the found number of rows when the table is scanned and
     then increment the counter for each attempted write.
   - We will need to extend the manager thread to makes checkpoints at
@@ -52,14 +53,17 @@
 
 #include "mysql_priv.h"
 
-#ifdef HAVE_BERKELEY_DB
 #include <m_ctype.h>
 #include <myisampack.h>
 #include <hash.h>
+
+#ifdef WITH_BERKELEY_STORAGE_ENGINE
 #include "ha_berkeley.h"
 #include "sql_manager.h"
 #include <stdarg.h>
 
+#include <mysql/plugin.h>
+
 #define HA_BERKELEY_ROWS_IN_TABLE 10000 /* to get optimization right */
 #define HA_BERKELEY_RANGE_COUNT   100
 #define HA_BERKELEY_MAX_ROWS	  10000000 /* Max rows in table */
@@ -71,13 +75,21 @@
 #define STATUS_ROW_COUNT_INIT	2
 #define STATUS_BDB_ANALYZE	4
 
+const u_int32_t bdb_DB_TXN_NOSYNC= DB_TXN_NOSYNC;
+const u_int32_t bdb_DB_RECOVER= DB_RECOVER;
+const u_int32_t bdb_DB_PRIVATE= DB_PRIVATE;
+const u_int32_t bdb_DB_DIRECT_DB= DB_DIRECT_DB;
+const u_int32_t bdb_DB_DIRECT_LOG= DB_DIRECT_LOG;
 const char *ha_berkeley_ext=".db";
 bool berkeley_shared_data=0;
-u_int32_t berkeley_init_flags= DB_PRIVATE | DB_RECOVER, berkeley_env_flags=0,
-          berkeley_lock_type=DB_LOCK_DEFAULT;
-ulong berkeley_cache_size, berkeley_log_buffer_size, berkeley_log_file_size=0;
+u_int32_t berkeley_init_flags= DB_PRIVATE | DB_RECOVER,
+          berkeley_env_flags= DB_LOG_AUTOREMOVE,
+          berkeley_lock_type= DB_LOCK_DEFAULT;
+ulong berkeley_log_buffer_size=0 , berkeley_log_file_size=0;
+ulonglong berkeley_cache_size= 0;
 char *berkeley_home, *berkeley_tmpdir, *berkeley_logdir;
 long berkeley_lock_scan_time=0;
+ulong berkeley_region_size=0, berkeley_cache_parts=1;
 ulong berkeley_trans_retry=1;
 ulong berkeley_max_lock;
 pthread_mutex_t bdb_mutex;
@@ -85,14 +97,21 @@
 static DB_ENV *db_env;
 static HASH bdb_open_tables;
 
+static const char berkeley_hton_name[]= "BerkeleyDB";
+static const int berkeley_hton_name_length=sizeof(berkeley_hton_name)-1;
+
 const char *berkeley_lock_names[] =
-{ "DEFAULT", "OLDEST","RANDOM","YOUNGEST",0 };
+{ "DEFAULT", "OLDEST", "RANDOM", "YOUNGEST", "EXPIRE", "MAXLOCKS",
+  "MAXWRITE", "MINLOCKS", "MINWRITE", 0 };
 u_int32_t berkeley_lock_types[]=
-{ DB_LOCK_DEFAULT, DB_LOCK_OLDEST, DB_LOCK_RANDOM };
+{ DB_LOCK_DEFAULT, DB_LOCK_OLDEST, DB_LOCK_RANDOM, DB_LOCK_YOUNGEST,
+  DB_LOCK_EXPIRE, DB_LOCK_MAXLOCKS, DB_LOCK_MAXWRITE, DB_LOCK_MINLOCKS,
+  DB_LOCK_MINWRITE };
 TYPELIB berkeley_lock_typelib= {array_elements(berkeley_lock_names)-1,"",
 				berkeley_lock_names, NULL};
 
-static void berkeley_print_error(const char *db_errpfx, char *buffer);
+static void berkeley_print_error(const DB_ENV *db_env, const char *db_errpfx,
+                                 const char *buffer);
 static byte* bdb_get_key(BDB_SHARE *share,uint *length,
 			 my_bool not_used __attribute__((unused)));
 static BDB_SHARE *get_share(const char *table_name, TABLE *table);
@@ -100,50 +119,53 @@
 		      bool mutex_is_locked);
 static int write_status(DB *status_block, char *buff, uint length);
 static void update_status(BDB_SHARE *share, TABLE *table);
-static void berkeley_noticecall(DB_ENV *db_env, db_notices notice);
 
 static int berkeley_close_connection(THD *thd);
 static int berkeley_commit(THD *thd, bool all);
 static int berkeley_rollback(THD *thd, bool all);
+static int berkeley_rollback_to_savepoint(THD* thd, void *savepoint);
+static int berkeley_savepoint(THD* thd, void *savepoint);
+static int berkeley_release_savepoint(THD* thd, void *savepoint);
+static handler *berkeley_create_handler(TABLE_SHARE *table,
+                                        MEM_ROOT *mem_root);
 
-handlerton berkeley_hton = {
-  "BerkeleyDB",
-  SHOW_OPTION_YES,
-  "Supports transactions and page-level locking", 
-  DB_TYPE_BERKELEY_DB,
-  berkeley_init,
-  0, /* slot */
-  0, /* savepoint size */
-  berkeley_close_connection,
-  NULL, /* savepoint_set */
-  NULL, /* savepoint_rollback */
-  NULL, /* savepoint_release */
-  berkeley_commit,
-  berkeley_rollback,
-  NULL, /* prepare */
-  NULL, /* recover */
-  NULL, /* commit_by_xid */
-  NULL, /* rollback_by_xid */
-  NULL, /* create_cursor_read_view */
-  NULL, /* set_cursor_read_view */
-  NULL, /* close_cursor_read_view */
-  HTON_CLOSE_CURSORS_AT_COMMIT
-};
+handlerton berkeley_hton;
+
+static handler *berkeley_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
+{
+  return new (mem_root) ha_berkeley(table);
+}
 
 typedef struct st_berkeley_trx_data {
   DB_TXN *all;
   DB_TXN *stmt;
+  DB_TXN *sp_level;
   uint bdb_lock_count;
 } berkeley_trx_data;
 
 /* General functions */
 
-bool berkeley_init(void)
+int berkeley_init(void)
 {
   DBUG_ENTER("berkeley_init");
 
+  berkeley_hton.state=SHOW_OPTION_YES;
+  berkeley_hton.db_type=DB_TYPE_BERKELEY_DB;
+  berkeley_hton.savepoint_offset=sizeof(DB_TXN *);
+  berkeley_hton.close_connection=berkeley_close_connection;
+  berkeley_hton.savepoint_set=berkeley_savepoint;
+  berkeley_hton.savepoint_rollback=berkeley_rollback_to_savepoint;
+  berkeley_hton.savepoint_release=berkeley_release_savepoint;
+  berkeley_hton.commit=berkeley_commit;
+  berkeley_hton.rollback=berkeley_rollback;
+  berkeley_hton.create=berkeley_create_handler;
+  berkeley_hton.panic=berkeley_end;
+  berkeley_hton.flush_logs=berkeley_flush_logs;
+  berkeley_hton.show_status=berkeley_show_status;
+  berkeley_hton.flags=HTON_CLOSE_CURSORS_AT_COMMIT | HTON_FLUSH_AFTER_RENAME;
+
   if (have_berkeley_db != SHOW_OPTION_YES)
-    goto error;
+    return 0; // nothing else to do
 
   if (!berkeley_tmpdir)
     berkeley_tmpdir=mysql_tmpdir;
@@ -173,7 +195,6 @@
     goto error;
   db_env->set_errcall(db_env,berkeley_print_error);
   db_env->set_errpfx(db_env,"bdb");
-  db_env->set_noticecall(db_env, berkeley_noticecall);
   db_env->set_tmp_dir(db_env, berkeley_tmpdir);
   db_env->set_data_dir(db_env, mysql_data_home);
   db_env->set_flags(db_env, berkeley_env_flags, 1);
@@ -182,13 +203,20 @@
 
   if (opt_endinfo)
     db_env->set_verbose(db_env,
-			DB_VERB_CHKPOINT | DB_VERB_DEADLOCK | DB_VERB_RECOVERY,
+			DB_VERB_DEADLOCK | DB_VERB_RECOVERY,
 			1);
 
-  db_env->set_cachesize(db_env, 0, berkeley_cache_size, 0);
+  if (berkeley_cache_size > (uint) ~0)
+    db_env->set_cachesize(db_env, berkeley_cache_size / (1024*1024L*1024L),
+                          berkeley_cache_size % (1024L*1024L*1024L),
+                          berkeley_cache_parts);
+  else
+    db_env->set_cachesize(db_env, 0, berkeley_cache_size, berkeley_cache_parts);
+
   db_env->set_lg_max(db_env, berkeley_log_file_size);
   db_env->set_lg_bsize(db_env, berkeley_log_buffer_size);
   db_env->set_lk_detect(db_env, berkeley_lock_type);
+  db_env->set_lg_regionmax(db_env, berkeley_region_size);
   if (berkeley_max_lock)
     db_env->set_lk_max(db_env, berkeley_max_lock);
 
@@ -213,18 +241,19 @@
 }
 
 
-bool berkeley_end(void)
+int berkeley_end(ha_panic_function type)
 {
-  int error;
+  int error= 0;
   DBUG_ENTER("berkeley_end");
-  if (!db_env)
-    return 1; /* purecov: tested */
-  berkeley_cleanup_log_files();
-  error=db_env->close(db_env,0);		// Error is logged
-  db_env=0;
-  hash_free(&bdb_open_tables);
-  pthread_mutex_destroy(&bdb_mutex);
-  DBUG_RETURN(error != 0);
+  if (db_env)
+  {
+    berkeley_cleanup_log_files();
+    error= db_env->close(db_env,0);		// Error is logged
+    db_env= 0;
+    hash_free(&bdb_open_tables);
+    pthread_mutex_destroy(&bdb_mutex);
+  }
+  DBUG_RETURN(error);
 }
 
 static int berkeley_close_connection(THD *thd)
@@ -258,7 +287,7 @@
   DBUG_PRINT("trans",("ending transaction %s", all ? "all" : "stmt"));
   berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
   DB_TXN **txn= all ? &trx->all : &trx->stmt;
-  int error=txn_commit(*txn,0);
+  int error= (*txn)->commit(*txn,0);
   *txn=0;
 #ifndef DBUG_OFF
   if (error)
@@ -273,13 +302,55 @@
   DBUG_PRINT("trans",("aborting transaction %s", all ? "all" : "stmt"));
   berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
   DB_TXN **txn= all ? &trx->all : &trx->stmt;
-  int error=txn_abort(*txn);
+  int error= (*txn)->abort(*txn);
   *txn=0;
   DBUG_RETURN(error);
 }
 
+static int berkeley_savepoint(THD* thd, void *savepoint)
+{
+  int error;
+  DB_TXN **save_txn= (DB_TXN**) savepoint;
+  DBUG_ENTER("berkeley_savepoint");
+  berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
+  if (!(error= db_env->txn_begin(db_env, trx->sp_level, save_txn, 0)))
+  {
+    trx->sp_level= *save_txn;
+  }
+  DBUG_RETURN(error);
+}
+
+static int berkeley_rollback_to_savepoint(THD* thd, void *savepoint)
+{
+  int error;
+  DB_TXN *parent, **save_txn= (DB_TXN**) savepoint;
+  DBUG_ENTER("berkeley_rollback_to_savepoint");
+  berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
+  parent= (*save_txn)->parent;
+  if (!(error= (*save_txn)->abort(*save_txn)))
+  {
+    trx->sp_level= parent;
+    error= berkeley_savepoint(thd, savepoint);
+  }
+  DBUG_RETURN(error);
+}
 
-int berkeley_show_logs(Protocol *protocol)
+static int berkeley_release_savepoint(THD* thd, void *savepoint)
+{
+  int error;
+  DB_TXN *parent, **save_txn= (DB_TXN**) savepoint;
+  DBUG_ENTER("berkeley_release_savepoint");
+  berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
+  parent= (*save_txn)->parent;
+  if (!(error= (*save_txn)->commit(*save_txn,0)))
+  {
+    trx->sp_level= parent;
+    *save_txn= 0;
+  }
+  DBUG_RETURN(error);
+}
+
+static bool berkeley_show_logs(THD *thd, stat_print_fn *stat_print)
 {
   char **all_logs, **free_logs, **a, **f;
   int error=1;
@@ -290,6 +361,7 @@
   init_sql_alloc(&show_logs_root, BDB_LOG_ALLOC_BLOCK_SIZE,
 		 BDB_LOG_ALLOC_BLOCK_SIZE);
   *root_ptr= &show_logs_root;
+  all_logs= free_logs= 0;
 
   if ((error= db_env->log_archive(db_env, &all_logs,
 				  DB_ARCH_ABS | DB_ARCH_LOG)) ||
@@ -306,50 +378,51 @@
   {
     for (a = all_logs, f = free_logs; *a; ++a)
     {
-      protocol->prepare_for_resend();
-      protocol->store(*a, system_charset_info);
-      protocol->store(STRING_WITH_LEN("BDB"), system_charset_info);
       if (f && *f && strcmp(*a, *f) == 0)
       {
-	f++;
-	protocol->store(SHOW_LOG_STATUS_FREE, system_charset_info);
+        f++;
+        if ((error= stat_print(thd, berkeley_hton_name,
+                               berkeley_hton_name_length, *a, strlen(*a),
+                               STRING_WITH_LEN(SHOW_LOG_STATUS_FREE))))
+          break;
       }
       else
-	protocol->store(SHOW_LOG_STATUS_INUSE, system_charset_info);
-
-      if (protocol->write())
       {
-	error=1;
-	goto err;
+        if ((error= stat_print(thd, berkeley_hton_name,
+                               berkeley_hton_name_length, *a, strlen(*a),
+                               STRING_WITH_LEN(SHOW_LOG_STATUS_INUSE))))
+          break;
       }
     }
   }
 err:
+  if (all_logs)
+    free(all_logs);
+  if (free_logs)
+    free(free_logs);
   free_root(&show_logs_root,MYF(0));
   *root_ptr= old_mem_root;
   DBUG_RETURN(error);
 }
 
-
-static void berkeley_print_error(const char *db_errpfx, char *buffer)
+bool berkeley_show_status(THD *thd, stat_print_fn *stat_print,
+                          enum ha_stat_type stat_type)
 {
-  sql_print_error("%s:  %s",db_errpfx,buffer); /* purecov: tested */
+  switch (stat_type) {
+  case HA_ENGINE_LOGS:
+    return berkeley_show_logs(thd, stat_print);
+  default:
+    return FALSE;
+  }
 }
 
-
-static void berkeley_noticecall(DB_ENV *db_env, db_notices notice)
+static void berkeley_print_error(const DB_ENV *db_env, const char *db_errpfx,
+                                 const char *buffer)
 {
-  switch (notice)
-  {
-  case DB_NOTICE_LOGFILE_CHANGED: /* purecov: tested */
-    pthread_mutex_lock(&LOCK_manager);
-    manager_status |= MANAGER_BERKELEY_LOG_CLEANUP;
-    pthread_mutex_unlock(&LOCK_manager);
-    pthread_cond_signal(&COND_manager);
-    break;
-  }
+  sql_print_error("%s:  %s",db_errpfx,buffer); /* purecov: tested */
 }
 
+
 void berkeley_cleanup_log_files(void)
 {
   DBUG_ENTER("berkeley_cleanup_log_files");
@@ -387,10 +460,10 @@
 ** Berkeley DB tables
 *****************************************************************************/
 
-ha_berkeley::ha_berkeley(TABLE *table_arg)
+ha_berkeley::ha_berkeley(TABLE_SHARE *table_arg)
   :handler(&berkeley_hton, table_arg), alloc_ptr(0), rec_buff(0), file(0),
   int_table_flags(HA_REC_NOT_IN_SEQ | HA_FAST_KEY_READ |
-                  HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_NOT_EXACT_COUNT |
+                  HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS |
                   HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED |
                   HA_CAN_GEOMETRY |
                   HA_AUTO_PART_KEY | HA_TABLE_SCAN_ON_INDEX),
@@ -414,13 +487,14 @@
                 | HA_READ_RANGE);
   for (uint i= all_parts ? 0 : part ; i <= part ; i++)
   {
-    if (table->key_info[idx].key_part[i].field->type() == FIELD_TYPE_BLOB)
+    KEY_PART_INFO *key_part= table_share->key_info[idx].key_part+i;
+    if (key_part->field->type() == FIELD_TYPE_BLOB)
     {
       /* We can't use BLOBS to shortcut sorts */
       flags&= ~(HA_READ_ORDER | HA_KEYREAD_ONLY | HA_READ_RANGE);
       break;
     }
-    switch (table->key_info[idx].key_part[i].field->key_type()) {
+    switch (key_part->field->key_type()) {
     case HA_KEYTYPE_TEXT:
     case HA_KEYTYPE_VARTEXT1:
     case HA_KEYTYPE_VARTEXT2:
@@ -428,8 +502,7 @@
         As BDB stores only one copy of equal strings, we can't use key read
         on these. Binary collations do support key read though.
       */
-      if (!(table->key_info[idx].key_part[i].field->charset()->state
-           & MY_CS_BINSORT))
+      if (!(key_part->field->charset()->state & MY_CS_BINSORT))
         flags&= ~HA_KEYREAD_ONLY;
       break;
     default:                                    // Keep compiler happy
@@ -567,7 +640,6 @@
   uint open_mode=(mode == O_RDONLY ? DB_RDONLY : 0) | DB_THREAD;
   uint max_key_length;
   int error;
-  TABLE_SHARE *table_share= table->s;
   DBUG_ENTER("ha_berkeley::open");
 
   /* Open primary key */
@@ -589,7 +661,7 @@
 			&key_buff2, max_key_length,
 			&primary_key_buff,
 			(hidden_primary_key ? 0 :
-			 table->key_info[table_share->primary_key].key_length),
+			 table_share->key_info[table_share->primary_key].key_length),
 			NullS)))
     DBUG_RETURN(1); /* purecov: inspected */
   if (!(rec_buff= (byte*) my_malloc((alloced_rec_buff_length=
@@ -632,10 +704,10 @@
 			  berkeley_cmp_packed_key));
     if (!hidden_primary_key)
       file->app_private= (void*) (table->key_info + table_share->primary_key);
-    if ((error= txn_begin(db_env, 0, (DB_TXN**) &transaction, 0)) ||
+    if ((error= db_env->txn_begin(db_env, NULL, (DB_TXN**) &transaction, 0)) ||
 	(error= (file->open(file, transaction,
 			    fn_format(name_buff, name, "", ha_berkeley_ext,
-				      2 | 4),
+				      MY_UNPACK_FILENAME|MY_APPEND_EXT),
 			    "main", DB_BTREE, open_mode, 0))) ||
 	(error= transaction->commit(transaction, 0)))
     {
@@ -648,7 +720,7 @@
 
     /* Open other keys;  These are part of the share structure */
     key_file[primary_key]=file;
-    key_type[primary_key]=DB_NOOVERWRITE;
+    key_type[primary_key]= hidden_primary_key ? 0 : DB_NOOVERWRITE;
 
     DB **ptr=key_file;
     for (uint i=0, used_keys=0; i < table_share->keys ; i++, ptr++)
@@ -671,7 +743,8 @@
 	  DBUG_PRINT("bdb",("Setting DB_DUP for key %u", i));
 	  (*ptr)->set_flags(*ptr, DB_DUP);
 	}
-	if ((error= txn_begin(db_env, 0, (DB_TXN**) &transaction, 0)) ||
+	if ((error= db_env->txn_begin(db_env, NULL, (DB_TXN**) &transaction,
+                                      0)) ||
 	    (error=((*ptr)->open(*ptr, transaction, name_buff, part, DB_BTREE,
 				 open_mode, 0))) ||
 	    (error= transaction->commit(transaction, 0)))
@@ -703,7 +776,7 @@
   transaction=0;
   cursor=0;
   key_read=0;
-  block_size=8192;				// Berkeley DB block size
+  stats.block_size=8192;                        // Berkeley DB block size
   share->fixed_length_row= !(table_share->db_create_options &
                              HA_OPTION_PACK_RECORD);
 
@@ -719,7 +792,7 @@
 
   my_free((char*) rec_buff,MYF(MY_ALLOW_ZERO_PTR));
   my_free(alloc_ptr,MYF(MY_ALLOW_ZERO_PTR));
-  ha_berkeley::extra(HA_EXTRA_RESET);		// current_row buffer
+  ha_berkeley::reset();                         // current_row buffer
   DBUG_RETURN(free_share(share,table, hidden_primary_key,0));
 }
 
@@ -745,9 +818,9 @@
 
 ulong ha_berkeley::max_row_length(const byte *buf)
 {
-  ulong length= table->s->reclength + table->s->fields*2;
+  ulong length= table_share->reclength + table_share->fields*2;
   uint *ptr, *end;
-  for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
+  for (ptr= table_share->blob_field, end=ptr + table_share->blob_fields ;
        ptr != end ;
        ptr++)
   {
@@ -774,25 +847,26 @@
   if (share->fixed_length_row)
   {
     row->data=(void*) record;
-    row->size= table->s->reclength+hidden_primary_key;
+    row->size= table_share->reclength+hidden_primary_key;
     if (hidden_primary_key)
     {
       if (new_row)
 	get_auto_primary_key(current_ident);
-      memcpy_fixed((char*) record+table->s->reclength, (char*) current_ident,
+      memcpy_fixed((char*) record+table_share->reclength,
+                   (char*) current_ident,
 		   BDB_HIDDEN_PRIMARY_KEY_LENGTH);
     }
     return 0;
   }
-  if (table->s->blob_fields)
+  if (table_share->blob_fields)
   {
     if (fix_rec_buff_for_blob(max_row_length(record)))
       return HA_ERR_OUT_OF_MEM; /* purecov: inspected */
   }
 
   /* Copy null bits */
-  memcpy(rec_buff, record, table->s->null_bytes);
-  ptr= rec_buff + table->s->null_bytes;
+  memcpy(rec_buff, record, table_share->null_bytes);
+  ptr= rec_buff + table_share->null_bytes;
 
   for (Field **field=table->field ; *field ; field++)
     ptr=(byte*) (*field)->pack((char*) ptr,
@@ -815,15 +889,17 @@
 void ha_berkeley::unpack_row(char *record, DBT *row)
 {
   if (share->fixed_length_row)
-    memcpy(record,(char*) row->data,table->s->reclength+hidden_primary_key);
+    memcpy(record,(char*) row->data,table_share->reclength+hidden_primary_key);
   else
   {
     /* Copy null bits */
+    my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
     const char *ptr= (const char*) row->data;
-    memcpy(record, ptr, table->s->null_bytes);
-    ptr+= table->s->null_bytes;
+    memcpy(record, ptr, table_share->null_bytes);
+    ptr+= table_share->null_bytes;
     for (Field **field=table->field ; *field ; field++)
       ptr= (*field)->unpack(record + (*field)->offset(), ptr);
+    dbug_tmp_restore_column_map(table->write_set, old_map);
   }
 }
 
@@ -881,6 +957,7 @@
   KEY *key_info=table->key_info+keynr;
   KEY_PART_INFO *key_part=key_info->key_part;
   KEY_PART_INFO *end=key_part+key_info->key_parts;
+  my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
   DBUG_ENTER("create_key");
 
   key->data=buff;
@@ -904,6 +981,7 @@
   }
   key->size= (u_int32_t) (buff  - (char*) key->data);
   DBUG_DUMP("key",(char*) key->data, key->size);
+  dbug_tmp_restore_column_map(table->write_set, old_map);
   DBUG_RETURN(key);
 }
 
@@ -921,6 +999,7 @@
   KEY *key_info=table->key_info+keynr;
   KEY_PART_INFO *key_part=key_info->key_part;
   KEY_PART_INFO *end=key_part+key_info->key_parts;
+  my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
   DBUG_ENTER("bdb:pack_key");
 
   bzero((char*) key,sizeof(*key));
@@ -948,6 +1027,7 @@
   }
   key->size= (u_int32_t) (buff  - (char*) key->data);
   DBUG_DUMP("key",(char*) key->data, key->size);
+  dbug_tmp_restore_column_map(table->write_set, old_map);
   DBUG_RETURN(key);
 }
 
@@ -970,7 +1050,7 @@
     DBUG_RETURN(error); /* purecov: inspected */
 
   table->insert_or_update= 1;                   // For handling of VARCHAR
-  if (table->s->keys + test(hidden_primary_key) == 1)
+  if (table_share->keys + test(hidden_primary_key) == 1)
   {
     error=file->put(file, transaction, create_key(&prim_key, primary_key,
 						  key_buff, record),
@@ -989,7 +1069,7 @@
 			    &row, key_type[primary_key])))
       {
 	changed_keys.set_bit(primary_key);
-	for (uint keynr=0 ; keynr < table->s->keys ; keynr++)
+	for (uint keynr=0 ; keynr < table_share->keys ; keynr++)
 	{
 	  if (keynr == primary_key)
 	    continue;
@@ -1017,7 +1097,7 @@
 	  {
 	    new_error = 0;
 	    for (uint keynr=0;
-                 keynr < table->s->keys+test(hidden_primary_key);
+                 keynr < table_share->keys+test(hidden_primary_key);
                  keynr++)
 	    {
 	      if (changed_keys.is_set(keynr))
@@ -1160,7 +1240,7 @@
      that one just put back the old value. */
   if (!changed_keys->is_clear_all())
   {
-    for (keynr=0 ; keynr < table->s->keys+test(hidden_primary_key) ; keynr++)
+    for (keynr=0 ; keynr < table_share->keys+test(hidden_primary_key) ; keynr++)
     {
       if (changed_keys->is_set(keynr))
       {
@@ -1189,8 +1269,8 @@
   DB_TXN *sub_trans;
   bool primary_key_changed;
   DBUG_ENTER("update_row");
-  LINT_INIT(error);
 
+  LINT_INIT(error);
   statistic_increment(table->in_use->status_var.ha_update_count,&LOCK_status);
   if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
     table->timestamp_field->set_time();
@@ -1225,7 +1305,7 @@
 				   using_ignore)))
     {
       // Update all other keys
-      for (uint keynr=0 ; keynr < table->s->keys ; keynr++)
+      for (uint keynr=0 ; keynr < table_share->keys ; keynr++)
       {
 	if (keynr == primary_key)
 	  continue;
@@ -1337,7 +1417,7 @@
 {
   int result = 0;
   for (uint keynr=0;
-       keynr < table->s->keys+test(hidden_primary_key);
+       keynr < table_share->keys+test(hidden_primary_key);
        keynr++)
   {
     if (keys->is_set(keynr))
@@ -1358,7 +1438,7 @@
 {
   int error;
   DBT row, prim_key;
-  key_map keys= table->s->keys_in_use;
+  key_map keys= table_share->keys_in_use;
   DBUG_ENTER("delete_row");
   statistic_increment(table->in_use->status_var.ha_delete_count,&LOCK_status);
 
@@ -1390,11 +1470,12 @@
 }
 
 
-int ha_berkeley::index_init(uint keynr)
+int ha_berkeley::index_init(uint keynr, bool sorted)
 {
   int error;
   DBUG_ENTER("ha_berkeley::index_init");
-  DBUG_PRINT("enter",("table: '%s'  key: %d", table->s->table_name, keynr));
+  DBUG_PRINT("enter",("table: '%s'  key: %d", table_share->table_name.str,
+                      keynr));
 
   /*
     Under some very rare conditions (like full joins) we may already have
@@ -1421,7 +1502,7 @@
   DBUG_ENTER("ha_berkely::index_end");
   if (cursor)
   {
-    DBUG_PRINT("enter",("table: '%s'", table->s->table_name));
+    DBUG_PRINT("enter",("table: '%s'", table_share->table_name.str));
     error=cursor->c_close(cursor);
     cursor=0;
   }
@@ -1668,7 +1749,7 @@
 {
   DBUG_ENTER("rnd_init");
   current_row.flags=DB_DBT_REALLOC;
-  DBUG_RETURN(index_init(primary_key));
+  DBUG_RETURN(index_init(primary_key, 0));
 }
 
 int ha_berkeley::rnd_end()
@@ -1770,20 +1851,21 @@
   DBUG_ENTER("ha_berkeley::info");
   if (flag & HA_STATUS_VARIABLE)
   {
-    records = share->rows + changed_rows; // Just to get optimisations right
-    deleted = 0;
+    // Just to get optimizations right
+    stats.records = share->rows + changed_rows;
+    stats.deleted = 0;
   }
   if ((flag & HA_STATUS_CONST) || version != share->version)
   {
     version=share->version;
-    for (uint i=0 ; i < table->s->keys ; i++)
+    for (uint i=0 ; i < table_share->keys ; i++)
     {
       table->key_info[i].rec_per_key[table->key_info[i].key_parts-1]=
 	share->rec_per_key[i];
     }
   }
   /* Don't return key if we got an error for the internal primary key */
-  if (flag & HA_STATUS_ERRKEY && last_dup_key < table->s->keys)
+  if (flag & HA_STATUS_ERRKEY && last_dup_key < table_share->keys)
     errkey= last_dup_key;
   DBUG_RETURN(0);
 }
@@ -1792,19 +1874,8 @@
 int ha_berkeley::extra(enum ha_extra_function operation)
 {
   switch (operation) {
-  case HA_EXTRA_RESET:
   case HA_EXTRA_RESET_STATE:
-    key_read=0;
-    using_ignore=0;
-    if (current_row.flags & (DB_DBT_MALLOC | DB_DBT_REALLOC))
-    {
-      current_row.flags=0;
-      if (current_row.data)
-      {
-	free(current_row.data);
-	current_row.data=0;
-      }
-    }
+    reset();
     break;
   case HA_EXTRA_KEYREAD:
     key_read=1;					// Query satisfied with key
@@ -1827,8 +1898,17 @@
 
 int ha_berkeley::reset(void)
 {
-  ha_berkeley::extra(HA_EXTRA_RESET);
-  key_read=0;					// Reset to state after open
+  key_read= 0;
+  using_ignore= 0;
+  if (current_row.flags & (DB_DBT_MALLOC | DB_DBT_REALLOC))
+  {
+    current_row.flags= 0;
+    if (current_row.data)
+    {
+      free(current_row.data);
+      current_row.data= 0;
+    }
+  }
   return 0;
 }
 
@@ -1854,6 +1934,8 @@
     if (!trx)
       DBUG_RETURN(1);
   }
+  if (trx->all == 0)
+    trx->sp_level= 0;
   if (lock_type != F_UNLCK)
   {
     if (!trx->bdb_lock_count++)
@@ -1867,17 +1949,18 @@
 	/* We have to start a master transaction */
 	DBUG_PRINT("trans",("starting transaction all:  options: 0x%lx",
                             (ulong) thd->options));
-        if ((error=txn_begin(db_env, 0, &trx->all, 0)))
+        if ((error= db_env->txn_begin(db_env, NULL, &trx->all, 0)))
 	{
           trx->bdb_lock_count--;        // We didn't get the lock
           DBUG_RETURN(error);
 	}
+        trx->sp_level= trx->all;
         trans_register_ha(thd, TRUE, &berkeley_hton);
 	if (thd->in_lock_tables)
 	  DBUG_RETURN(0);			// Don't create stmt trans
       }
       DBUG_PRINT("trans",("starting transaction stmt"));
-      if ((error=txn_begin(db_env, trx->all, &trx->stmt, 0)))
+      if ((error= db_env->txn_begin(db_env, trx->sp_level, &trx->stmt, 0)))
       {
 	/* We leave the possible master transaction open */
         trx->bdb_lock_count--;                  // We didn't get the lock
@@ -1902,7 +1985,7 @@
 	   We must in this case commit the work to keep the row locks
 	*/
 	DBUG_PRINT("trans",("commiting non-updating transaction"));
-        error= txn_commit(trx->stmt,0);
+        error= trx->stmt->commit(trx->stmt,0);
         trx->stmt= transaction= 0;
       }
     }
@@ -1931,7 +2014,7 @@
   if (!trx->stmt)
   {
     DBUG_PRINT("trans",("starting transaction stmt"));
-    error=txn_begin(db_env, trx->all, &trx->stmt, 0);
+    error= db_env->txn_begin(db_env, trx->sp_level, &trx->stmt, 0);
     trans_register_ha(thd, FALSE, &berkeley_hton);
   }
   transaction= trx->stmt;
@@ -2026,13 +2109,14 @@
   int error;
   DBUG_ENTER("ha_berkeley::create");
 
-  fn_format(name_buff,name,"", ha_berkeley_ext,2 | 4);
+  fn_format(name_buff,name,"", ha_berkeley_ext,
+            MY_UNPACK_FILENAME|MY_APPEND_EXT);
 
   /* Create the main table that will hold the real rows */
   if ((error= create_sub_table(name_buff,"main",DB_BTREE,0)))
     DBUG_RETURN(error); /* purecov: inspected */
 
-  primary_key= table->s->primary_key;
+  primary_key= form->s->primary_key;
   /* Create the keys */
   for (uint i=0; i < form->s->keys; i++)
   {
@@ -2040,7 +2124,7 @@
     {
       sprintf(part,"key%02d",index++);
       if ((error= create_sub_table(name_buff, part, DB_BTREE,
-				   (table->key_info[i].flags & HA_NOSAME) ? 0 :
+				   (form->key_info[i].flags & HA_NOSAME) ? 0 :
 				   DB_DUP)))
 	DBUG_RETURN(error); /* purecov: inspected */
     }
@@ -2056,7 +2140,7 @@
 				    "status", DB_BTREE, DB_CREATE, 0))))
     {
       char rec_buff[4+MAX_KEY*4];
-      uint length= 4+ table->s->keys*4;
+      uint length= 4+ form->s->keys*4;
       bzero(rec_buff, length);
       error= write_status(status_block, rec_buff, length);
       status_block->close(status_block,0);
@@ -2075,8 +2159,9 @@
   if ((error=db_create(&file, db_env, 0)))
     my_errno=error; /* purecov: inspected */
   else
-    error=file->remove(file,fn_format(name_buff,name,"",ha_berkeley_ext,2 | 4),
-		       NULL,0);
+    error=file->remove(file,fn_format(name_buff,name,"",ha_berkeley_ext,
+                                      MY_UNPACK_FILENAME|MY_APPEND_EXT),
+                       NULL,0);
   file=0;					// Safety
   DBUG_RETURN(error);
 }
@@ -2094,9 +2179,11 @@
   {
     /* On should not do a file->close() after rename returns */
     error= file->rename(file, 
-			fn_format(from_buff, from, "", ha_berkeley_ext, 2 | 4),
+			fn_format(from_buff, from, "", 
+                                  ha_berkeley_ext,
+                                  MY_UNPACK_FILENAME|MY_APPEND_EXT),
 			NULL, fn_format(to_buff, to, "", ha_berkeley_ext,
-					2 | 4), 0);
+                                        MY_UNPACK_FILENAME|MY_APPEND_EXT), 0);
   }
   return error;
 }
@@ -2110,7 +2197,7 @@
 
 double ha_berkeley::scan_time()
 {
-  return rows2double(records/3);
+  return rows2double(stats.records/3);
 }
 
 ha_rows ha_berkeley::records_in_range(uint keynr, key_range *start_key,
@@ -2163,27 +2250,40 @@
     end_pos=end_range.less;
   else
     end_pos=end_range.less+end_range.equal;
-  rows=(end_pos-start_pos)*records;
+  rows=(end_pos-start_pos)*stats.records;
   DBUG_PRINT("exit",("rows: %g",rows));
   DBUG_RETURN((ha_rows)(rows <= 1.0 ? 1 : rows));
 }
 
 
-ulonglong ha_berkeley::get_auto_increment()
+void ha_berkeley::get_auto_increment(ulonglong offset, ulonglong increment,
+                                     ulonglong nb_desired_values,
+                                     ulonglong *first_value,
+                                     ulonglong *nb_reserved_values)
 {
+  /* Ideally in case of real error (not "empty table") nr should be ~ULL(0) */
   ulonglong nr=1;				// Default if error or new key
   int error;
   (void) ha_berkeley::extra(HA_EXTRA_KEYREAD);
 
   /* Set 'active_index' */
-  ha_berkeley::index_init(table->s->next_number_index);
+  ha_berkeley::index_init(table_share->next_number_index, 0);
 
-  if (!table->s->next_number_key_offset)
+  if (!table_share->next_number_key_offset)
   {						// Autoincrement at key-start
     error=ha_berkeley::index_last(table->record[1]);
+    /* has taken read lock on page of max key so reserves to infinite  */
+    *nb_reserved_values= ULONGLONG_MAX;
   }
   else
   {
+    /*
+      MySQL needs to call us for next row: assume we are inserting ("a",null)
+      here, we return 3, and next this statement will want to insert ("b",null):
+      there is no reason why ("b",3+1) would be the good row to insert: maybe it
+      already exists, maybe 3+1 is too large...
+    */
+    *nb_reserved_values= 1;
     DBT row,old_key;
     bzero((char*) &row,sizeof(row));
     KEY *key_info= &table->key_info[active_index];
@@ -2191,7 +2291,7 @@
     /* Reading next available number for a sub key */
     ha_berkeley::create_key(&last_key, active_index,
 			    key_buff, table->record[0],
-			    table->s->next_number_key_offset);
+			    table_share->next_number_key_offset);
     /* Store for compare */
     memcpy(old_key.data=key_buff2, key_buff, (old_key.size=last_key.size));
     old_key.app_private=(void*) key_info;
@@ -2221,10 +2321,10 @@
   }
   if (!error)
     nr= (ulonglong)
-      table->next_number_field->val_int_offset(table->s->rec_buff_length)+1;
+      table->next_number_field->val_int_offset(table_share->rec_buff_length)+1;
   ha_berkeley::index_end();
   (void) ha_berkeley::extra(HA_EXTRA_NO_KEYREAD);
-  return nr;
+  *first_value= nr;
 }
 
 void ha_berkeley::print_error(int error, myf errflag)
@@ -2271,48 +2371,14 @@
   berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
   DBUG_ASSERT(trx);
 
-  /*
-   Original bdb documentation says:
-   "The DB->stat method cannot be transaction-protected.
-   For this reason, it should be called in a thread of
-   control that has no open cursors or active transactions."
-   So, let's check if there are any changes have been done since
-   the beginning of the transaction..
-  */
-
-  if (!db_env->txn_stat(db_env, &txn_stat_ptr, 0) &&
-      txn_stat_ptr && txn_stat_ptr->st_nactive>=2)
-  {
-    DB_TXN_ACTIVE *atxn_stmt= 0, *atxn_all= 0;
-
-    u_int32_t all_id= trx->all->id(trx->all);
-    u_int32_t stmt_id= trx->stmt->id(trx->stmt);
-
-    DB_TXN_ACTIVE *cur= txn_stat_ptr->st_txnarray;
-    DB_TXN_ACTIVE *end= cur + txn_stat_ptr->st_nactive;
-    for (; cur!=end && (!atxn_stmt || !atxn_all); cur++)
-    {
-      if (cur->txnid==all_id) atxn_all= cur;
-      if (cur->txnid==stmt_id) atxn_stmt= cur;
-    }
-
-    if (atxn_stmt && atxn_all &&
-	log_compare(&atxn_stmt->lsn,&atxn_all->lsn))
-    {
-      free(txn_stat_ptr);
-      return HA_ADMIN_REJECT;
-    }
-    free(txn_stat_ptr);
-  }
-
-  for (i=0 ; i < table->s->keys ; i++)
+  for (i=0 ; i < table_share->keys ; i++)
   {
     if (stat)
     {
       free(stat);
       stat=0;
     }
-    if ((key_file[i]->stat)(key_file[i], (void*) &stat, 0))
+    if ((key_file[i]->stat)(key_file[i], trx->all, (void*) &stat, 0))
       goto err; /* purecov: inspected */
     share->rec_per_key[i]= (stat->bt_ndata /
 			    (stat->bt_nkeys ? stat->bt_nkeys : 1));
@@ -2325,7 +2391,7 @@
       free(stat);
       stat=0;
     }
-    if ((file->stat)(file, (void*) &stat, 0))
+    if ((file->stat)(file, trx->all, (void*) &stat, 0))
       goto err; /* purecov: inspected */
   }
   pthread_mutex_lock(&share->mutex);
@@ -2380,7 +2446,8 @@
 			   (hidden_primary_key ? berkeley_cmp_hidden_key :
 			    berkeley_cmp_packed_key));
   tmp_file->app_private= (void*) (table->key_info+table->primary_key);
-  fn_format(name_buff,share->table_name,"", ha_berkeley_ext, 2 | 4);
+  fn_format(name_buff,share->table_name.str,"", ha_berkeley_ext,
+            MY_UNPACK_FILENAME|MY_APPEND_EXT);      
   if ((error=tmp_file->verify(tmp_file, name_buff, NullS, (FILE*) 0,
 			      hidden_primary_key ? 0 : DB_NOORDERCHK)))
   {
@@ -2454,7 +2521,7 @@
       share->rec_per_key = rec_per_key;
       share->table_name = tmp_name;
       share->table_name_length=length;
-      strmov(share->table_name,table_name);
+      strmov(share->table_name, table_name);
       share->key_file = key_file;
       share->key_type = key_type;
       if (my_hash_insert(&bdb_open_tables, (byte*) share))
@@ -2515,7 +2582,7 @@
     if (!(share->status & STATUS_PRIMARY_KEY_INIT))
     {
       (void) extra(HA_EXTRA_KEYREAD);
-      index_init(primary_key);
+      index_init(primary_key, 0);
       if (!index_last(table->record[1]))
 	share->auto_ident=uint5korr(current_ident);
       index_end();
@@ -2526,7 +2593,8 @@
       char name_buff[FN_REFLEN];
       uint open_mode= (((table->db_stat & HA_READ_ONLY) ? DB_RDONLY : 0)
 		       | DB_THREAD);
-      fn_format(name_buff, share->table_name,"", ha_berkeley_ext, 2 | 4);
+      fn_format(name_buff, share->table_name, "", ha_berkeley_ext,
+                MY_UNPACK_FILENAME|MY_APPEND_EXT);
       if (!db_create(&share->status_block, db_env, 0))
       {
 	if (share->status_block->open(share->status_block, NULL, name_buff,
@@ -2540,7 +2608,7 @@
     if (!(share->status & STATUS_ROW_COUNT_INIT) &&
share->status_block)
     {
       share->org_rows= share->rows=
-	table->s->max_rows ? table->s->max_rows : HA_BERKELEY_MAX_ROWS;
+	table_share->max_rows ? table_share->max_rows : HA_BERKELEY_MAX_ROWS;
       if (!share->status_block->cursor(share->status_block, 0, &cursor, 0))
       {
 	DBT row;
@@ -2555,7 +2623,7 @@
 	  uint i;
 	  uchar *pos=(uchar*) row.data;
 	  share->org_rows=share->rows=uint4korr(pos); pos+=4;
-	  for (i=0 ; i < table->s->keys ; i++)
+	  for (i=0 ; i < table_share->keys ; i++)
 	  {
 	    share->rec_per_key[i]=uint4korr(pos);
             pos+=4;
@@ -2607,8 +2675,9 @@
 	goto end; /* purecov: inspected */
       share->status_block->set_flags(share->status_block,0); /* purecov:
inspected */
       if (share->status_block->open(share->status_block, NULL,
-				    fn_format(name_buff,share->table_name,"",
-					      ha_berkeley_ext,2 | 4),
+				    fn_format(name_buff,share->table_name,
+                                              "", ha_berkeley_ext,
+                                              MY_UNPACK_FILENAME|MY_APPEND_EXT),
 				    "status", DB_BTREE,
 				    DB_THREAD | DB_CREATE, my_umask)) /* purecov: inspected */
 	goto end; /* purecov: inspected */
@@ -2620,7 +2689,7 @@
       {
 	int4store(pos,share->rec_per_key[i]); pos+=4;
       }
-      DBUG_PRINT("info",("updating status for %s",share->table_name));
+      DBUG_PRINT("info",("updating status for %s", share->table_name));
       (void) write_status(share->status_block, rec_buff,
 			  (uint) (pos-rec_buff));
       share->status&= ~STATUS_BDB_ANALYZE;
@@ -2650,7 +2719,7 @@
 
   int result;
   Field *field;
-  KEY *key_info=table->key_info+table->s->primary_key;
+  KEY *key_info=table->key_info+table_share->primary_key;
   KEY_PART_INFO *key_part=key_info->key_part;
   KEY_PART_INFO *end=key_part+key_info->key_parts;
 
@@ -2668,4 +2737,30 @@
   return 0;
 }
 
-#endif /* HAVE_BERKELEY_DB */
+
+bool ha_berkeley::check_if_incompatible_data(HA_CREATE_INFO *info,
+					     uint table_changes)
+{
+  if (table_changes < IS_EQUAL_YES)
+    return COMPATIBLE_DATA_NO;
+  return COMPATIBLE_DATA_YES;
+}
+
+struct st_mysql_storage_engine berkeley_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION, &berkeley_hton };
+
+mysql_declare_plugin(berkeley)
+{
+  MYSQL_STORAGE_ENGINE_PLUGIN,
+  &berkeley_storage_engine,
+  berkeley_hton_name,
+  "Sleepycat Software",
+  "Supports transactions and page-level locking",
+  berkeley_init, /* Plugin Init */
+  NULL, /* Plugin Deinit */
+  0x0100, /* 1.0 */
+  0
+}
+mysql_declare_plugin_end;
+
+#endif

--- 1.357/sql/item_func.cc	2007-03-02 00:10:25 +02:00
+++ 1.358/sql/item_func.cc	2007-03-02 00:10:25 +02:00
@@ -4220,7 +4220,14 @@
   user_var_entry *var_entry;
   var_entry= get_variable(&thd->user_vars, name, 0);
 
-  if (!(opt_bin_log && is_update_query(sql_command)))
+  /*
+    Any reference to user-defined variable which is done from stored
+    function or trigger affects their execution and the execution of the
+    calling statement. We must log all such variables even if they are 
+    not involved in table-updating statements.
+  */
+  if (!(opt_bin_log && 
+       (is_update_query(sql_command) || thd->in_sub_stmt)))
   {
     *out_entry= var_entry;
     return 0;

--- 1.257/sql/log.cc	2007-03-02 00:10:25 +02:00
+++ 1.258/sql/log.cc	2007-03-02 00:10:25 +02:00
@@ -3352,13 +3352,13 @@
   return err;
 }
 
-void MYSQL_BIN_LOG::start_union_events(THD *thd)
+void MYSQL_BIN_LOG::start_union_events(THD *thd, query_id_t query_id_param)
 {
   DBUG_ASSERT(!thd->binlog_evt_union.do_union);
   thd->binlog_evt_union.do_union= TRUE;
   thd->binlog_evt_union.unioned_events= FALSE;
   thd->binlog_evt_union.unioned_events_trans= FALSE;
-  thd->binlog_evt_union.first_query_id= thd->query_id;
+  thd->binlog_evt_union.first_query_id= query_id_param;
 }
 
 void MYSQL_BIN_LOG::stop_union_events(THD *thd)
@@ -4525,7 +4525,7 @@
       goto err;
     if (using_heuristic_recover())
       return 1;
-    if ((fd= my_create(logname, O_RDWR, 0, MYF(MY_WME))) < 0)
+    if ((fd= my_create(logname, CREATE_MODE, O_RDWR, MYF(MY_WME))) < 0)
       goto err;
     inited=1;
     file_length= opt_tc_log_size;

--- 1.267/sql/log_event.cc	2007-03-02 00:10:25 +02:00
+++ 1.268/sql/log_event.cc	2007-03-02 00:10:25 +02:00
@@ -1276,7 +1276,8 @@
             1+4+           // code of autoinc and the 2 autoinc variables
             1+6+           // code of charset and charset
             1+1+MAX_TIME_ZONE_NAME_LENGTH+ // code of tz and tz length and tz name
-            1+2            // code of lc_time_names and lc_time_names_number
+            1+2+           // code of lc_time_names and lc_time_names_number
+            1+2            // code of charset_database and charset_database_number
             ], *start, *start_of_status;
   ulong event_length;
 
@@ -1395,6 +1396,13 @@
     int2store(start, lc_time_names_number);
     start+= 2;
   }
+  if (charset_database_number)
+  {
+    DBUG_ASSERT(charset_database_number <= 0xFFFF);
+    *start++= Q_CHARSET_DATABASE_CODE;
+    int2store(start, charset_database_number);
+    start+= 2;
+  }
   /*
     Here there could be code like
     if (command-line-option-which-says-"log_this_variable" && inited)
@@ -1460,7 +1468,8 @@
    sql_mode(thd_arg->variables.sql_mode),
    auto_increment_increment(thd_arg->variables.auto_increment_increment),
    auto_increment_offset(thd_arg->variables.auto_increment_offset),
-   lc_time_names_number(thd_arg->variables.lc_time_names->number)
+   lc_time_names_number(thd_arg->variables.lc_time_names->number),
+   charset_database_number(0)
 {
   time_t end_time;
   time(&end_time);
@@ -1468,6 +1477,9 @@
   catalog_len = (catalog) ? (uint32) strlen(catalog) : 0;
   /* status_vars_len is set just before writing the event */
   db_len = (db) ? (uint32) strlen(db) : 0;
+  if (thd_arg->variables.collation_database != thd_arg->db_charset)
+    charset_database_number= thd_arg->variables.collation_database->number;
+  
   /*
     If we don't use flags2 for anything else than options contained in
     thd->options, it would be more efficient to flags2=thd_arg->options
@@ -1538,7 +1550,7 @@
    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),
-   time_zone_len(0), lc_time_names_number(0)
+   time_zone_len(0), lc_time_names_number(0), charset_database_number(0)
 {
   ulong data_len;
   uint32 tmp;
@@ -1643,6 +1655,10 @@
       lc_time_names_number= uint2korr(pos);
       pos+= 2;
       break;
+    case Q_CHARSET_DATABASE_CODE:
+      charset_database_number= uint2korr(pos);
+      pos+= 2;
+      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\
@@ -1841,6 +1857,16 @@
                 lc_time_names_number, print_event_info->delimiter);
     print_event_info->lc_time_names_number= lc_time_names_number;
   }
+  if (charset_database_number != print_event_info->charset_database_number)
+  {
+    if (charset_database_number)
+      fprintf(file, "SET @@session.collation_database=%d%s\n",
+              charset_database_number, print_event_info->delimiter);
+    else
+      fprintf(file, "SET @@session.collation_database=DEFAULT%s\n",
+              print_event_info->delimiter);
+    print_event_info->charset_database_number= charset_database_number;
+  }
 }
 
 
@@ -1996,7 +2022,21 @@
       }
       else
         thd->variables.lc_time_names= &my_locale_en_US;
-
+      if (charset_database_number)
+      {
+        CHARSET_INFO *cs;
+        if (!(cs= get_charset(charset_database_number, MYF(0))))
+        {
+          char buf[20];
+          int10_to_str((int) charset_database_number, buf, -10);
+          my_error(ER_UNKNOWN_COLLATION, MYF(0), buf);
+          goto compare_errors;
+        }
+        thd->variables.collation_database= cs;
+      }
+      else
+        thd->variables.collation_database= thd->db_charset;
+      
       /* Execute the query (note that we bypass dispatch_command()) */
       mysql_parse(thd, thd->query, thd->query_length);
 
@@ -2241,6 +2281,8 @@
   binlog_version= uint2korr(buf+ST_BINLOG_VER_OFFSET);
   memcpy(server_version, buf+ST_SERVER_VER_OFFSET,
 	 ST_SERVER_VER_LEN);
+  // prevent overrun if log is corrupted on disk
+  server_version[ST_SERVER_VER_LEN-1]= 0;
   created= uint4korr(buf+ST_CREATED_OFFSET);
   /* We use log_pos to mark if this was an artificial event or not */
   artificial_event= (log_pos == 0);
@@ -2364,6 +2406,8 @@
   switch (binlog_ver) {
   case 4: /* MySQL 5.0 */
     memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
+    DBUG_EXECUTE_IF("pretend_version_50034_in_binlog",
+                    strmov(server_version, "5.0.34"););
     common_header_len= LOG_EVENT_HEADER_LEN;
     number_of_event_types= LOG_EVENT_TYPES;
     /* we'll catch my_malloc() error in is_valid() */
@@ -2454,6 +2498,7 @@
     post_header_len= 0; /* will make is_valid() fail */
     break;
   }
+  calc_server_version_split();
 }
 
 
@@ -2493,6 +2538,7 @@
   post_header_len= (uint8*) my_memdup((byte*)buf+ST_COMMON_HEADER_LEN_OFFSET+1,
                                       number_of_event_types*
                                       sizeof(*post_header_len), MYF(0));
+  calc_server_version_split();
   DBUG_VOID_RETURN;
 }
 
@@ -2592,6 +2638,37 @@
   DBUG_RETURN(Start_log_event_v3::exec_event(rli));
 }
 #endif
+
+
+/**
+   Splits the event's 'server_version' string into three numeric pieces stored
+   into 'server_version_split':
+   X.Y.Zabc (X,Y,Z numbers, a not a digit) -> {X,Y,Z}
+   X.Yabc -> {X,Y,0}
+   Xabc -> {X,0,0}
+   'server_version_split' is then used for lookups to find if the server which
+   created this event has some known bug.
+*/
+void Format_description_log_event::calc_server_version_split()
+{
+  char *p= server_version, *r;
+  ulong number;
+  for (uint i= 0; i<=2; i++)
+  {
+    number= strtoul(p, &r, 10);
+    server_version_split[i]= (uchar)number;
+    DBUG_ASSERT(number < 256); // fit in uchar
+    p= r;
+    DBUG_ASSERT(!((i == 0) && (*r != '.'))); // should be true in practice
+    if (*r == '.')
+      p++; // skip the dot
+  }
+  DBUG_PRINT("info",("Format_description_log_event::server_version_split:"
+                     " '%s' %d %d %d", server_version,
+                     server_version_split[0],
+                     server_version_split[1], server_version_split[2]));
+}
+
 
   /**************************************************************************
         Load_log_event methods

--- 1.146/sql/log_event.h	2007-03-02 00:10:25 +02:00
+++ 1.147/sql/log_event.h	2007-03-02 00:10:25 +02:00
@@ -272,6 +272,7 @@
 
 #define Q_LC_TIME_NAMES_CODE    7
 
+#define Q_CHARSET_DATABASE_CODE 8
 /* Intvar event post-header */
 
 #define I_TYPE_OFFSET        0
@@ -533,10 +534,11 @@
   char charset[6]; // 3 variables, each of them storable in 2 bytes
   char time_zone_str[MAX_TIME_ZONE_NAME_LENGTH];
   uint lc_time_names_number;
+  uint charset_database_number;
   st_print_event_info()
     :flags2_inited(0), sql_mode_inited(0),
      auto_increment_increment(1),auto_increment_offset(1), charset_inited(0),
-     lc_time_names_number(0)
+     lc_time_names_number(0), charset_database_number(0)
     {
       /*
         Currently we only use static PRINT_EVENT_INFO objects, so zeroed at
@@ -846,6 +848,7 @@
   uint time_zone_len; /* 0 means uninited */
   const char *time_zone_str;
   uint lc_time_names_number; /* 0 means en_US */
+  uint charset_database_number;
 
 #ifndef MYSQL_CLIENT
 
@@ -1153,6 +1156,7 @@
   uint8 number_of_event_types;
   /* The list of post-headers' lengthes */
   uint8 *post_header_len;
+  uchar server_version_split[3];
 
   Format_description_log_event(uint8 binlog_ver, const char* server_ver=0);
 
@@ -1184,6 +1188,7 @@
     */
     return FORMAT_DESCRIPTION_HEADER_LEN;
   }
+  void calc_server_version_split();
 };
 
 

--- 1.486/sql/mysql_priv.h	2007-03-02 00:10:26 +02:00
+++ 1.487/sql/mysql_priv.h	2007-03-02 00:10:26 +02:00
@@ -96,14 +96,17 @@
 #define PREV_BITS(type,A)	((type) (((type) 1 << (A)) -1))
 #define all_bits_set(A,B) ((A) & (B) != (B))
 
-#define WARN_DEPRECATED(Thd,Ver,Old,New)                                  \
-  do {                                                                    \
-    DBUG_ASSERT(strncmp(Ver, MYSQL_SERVER_VERSION, sizeof(Ver)-1) >= 0);  \
-    push_warning_printf(((THD *)Thd), MYSQL_ERROR::WARN_LEVEL_WARN,       \
-                        ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX),       \
-                        (Old), (Ver), (New));                             \
+#define WARN_DEPRECATED(Thd,Ver,Old,New)                                             \
+  do {                                                                               \
+    DBUG_ASSERT(strncmp(Ver, MYSQL_SERVER_VERSION, sizeof(Ver)-1) > 0);              \
+    if (((gptr)Thd) != NULL)                                                         \
+      push_warning_printf(((THD *)Thd), MYSQL_ERROR::WARN_LEVEL_WARN,                \
+                        ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX),    \
+                        (Old), (Ver), (New));                                        \
+    else                                                                             \
+      sql_print_warning("The syntax %s is deprecated and will be removed "           \
+                        "in MySQL %s. Please use %s instead.", (Old), (Ver), (New)); \
   } while(0)
-
 
 extern CHARSET_INFO *system_charset_info, *files_charset_info ;
 extern CHARSET_INFO *national_charset_info, *table_alias_charset;

--- 1.622/sql/mysqld.cc	2007-03-02 00:10:26 +02:00
+++ 1.623/sql/mysqld.cc	2007-03-02 00:10:26 +02:00
@@ -367,6 +367,7 @@
 my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
 my_bool opt_log_slave_updates= 0;
 my_bool	opt_innodb;
+bool slave_warning_issued = false; 
 
 /*
   Legacy global handlerton. These will be removed (please do not add more).
@@ -3401,7 +3402,7 @@
                                (TC_LOG *) &tc_log_mmap) :
            (TC_LOG *) &tc_log_dummy);
 
-  if (tc_log->open(opt_bin_logname))
+  if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file))
   {
     sql_print_error("Can't init tc log");
     unireg_abort(1);
@@ -7602,6 +7603,29 @@
   case (int) OPT_STANDALONE:		/* Dummy option for NT */
     break;
 #endif
+  /*
+    The following change issues a deprecation warning if the slave
+    configuration is specified either in the my.cnf file or on
+    the command-line. See BUG#21490.
+  */
+  case OPT_MASTER_HOST:
+  case OPT_MASTER_USER:
+  case OPT_MASTER_PASSWORD:
+  case OPT_MASTER_PORT:
+  case OPT_MASTER_CONNECT_RETRY:
+  case OPT_MASTER_SSL:          
+  case OPT_MASTER_SSL_KEY:
+  case OPT_MASTER_SSL_CERT:       
+  case OPT_MASTER_SSL_CAPATH:
+  case OPT_MASTER_SSL_CIPHER:
+  case OPT_MASTER_SSL_CA:
+    if (!slave_warning_issued)                 //only show the warning once
+    {
+      slave_warning_issued = true;   
+      WARN_DEPRECATED(NULL, "5.2", "for replication startup options", 
+        "'CHANGE MASTER'");
+    }
+    break;
   case OPT_CONSOLE:
     if (opt_console)
       opt_error_log= 0;			// Force logs to stdout

--- 1.308/sql/slave.cc	2007-03-02 00:10:26 +02:00
+++ 1.309/sql/slave.cc	2007-03-02 00:10:26 +02:00
@@ -2205,11 +2205,16 @@
   THD_CHECK_SENTRY(thd);
   delete thd;
   pthread_mutex_unlock(&LOCK_thread_count);
-  mi->abort_slave = 0;
-  mi->slave_running = 0;
-  mi->io_thd = 0;
-  pthread_mutex_unlock(&mi->run_lock);
+  mi->abort_slave= 0;
+  mi->slave_running= 0;
+  mi->io_thd= 0;
+  /*
+    Note: the order of the two following calls (first broadcast, then unlock)
+    is important. Otherwise a killer_thread can execute between the calls and
+    delete the mi structure leading to a crash! (see BUG#25306 for details)
+   */ 
   pthread_cond_broadcast(&mi->stop_cond);       // tell the world we are done
+  pthread_mutex_unlock(&mi->run_lock);
   my_thread_end();
   pthread_exit(0);
   DBUG_RETURN(0);                               // Can't return anything here
@@ -2455,8 +2460,12 @@
   THD_CHECK_SENTRY(thd);
   delete thd;
   pthread_mutex_unlock(&LOCK_thread_count);
-  pthread_cond_broadcast(&rli->stop_cond);
-  // tell the world we are done
+ /*
+  Note: the order of the broadcast and unlock calls below (first broadcast, then unlock)
+  is important. Otherwise a killer_thread can execute between the calls and
+  delete the mi structure leading to a crash! (see BUG#25306 for details)
+ */ 
+  pthread_cond_broadcast(&rli->stop_cond); // tell the world we are done
   pthread_mutex_unlock(&rli->run_lock);
   my_thread_end();
   pthread_exit(0);
@@ -3652,6 +3661,70 @@
   DBUG_VOID_RETURN;
 }
 
+
+/**
+   Detects, based on master's version (as found in the relay log), if master
+   has a certain bug.
+   @param rli RELAY_LOG_INFO which tells the master's version
+   @param bug_id Number of the bug as found in bugs.mysql.com
+   @return TRUE if master has the bug, FALSE if it does not.
+*/
+bool rpl_master_has_bug(RELAY_LOG_INFO *rli, uint bug_id)
+{
+  struct st_version_range_for_one_bug {
+    uint        bug_id;
+    const uchar introduced_in[3]; // first version with bug
+    const uchar fixed_in[3];      // first version with fix
+  };
+  static struct st_version_range_for_one_bug versions_for_all_bugs[]=
+  {
+    {24432, { 5, 0, 24 }, { 5, 0, 38 } },
+    {24432, { 5, 1, 12 }, { 5, 1, 17 } }
+  };
+  const uchar *master_ver=
+    rli->relay_log.description_event_for_exec->server_version_split;
+
+ 
DBUG_ASSERT(sizeof(rli->relay_log.description_event_for_exec->server_version_split)
== 3);
+
+  for (uint i= 0;
+       i < sizeof(versions_for_all_bugs)/sizeof(*versions_for_all_bugs);i++)
+  {
+    const uchar *introduced_in= versions_for_all_bugs[i].introduced_in,
+      *fixed_in= versions_for_all_bugs[i].fixed_in;
+    if ((versions_for_all_bugs[i].bug_id == bug_id) &&
+        (memcmp(introduced_in, master_ver, 3) <= 0) &&
+        (memcmp(fixed_in,      master_ver, 3) >  0))
+    {
+      // a verbose message for the error log
+      slave_print_error(rli, ER_UNKNOWN_ERROR,
+                        "According to the master's version ('%s'),"
+                        " it is probable that master suffers from this bug:"
+                        " http://bugs.mysql.com/bug.php?id=%u"
+                        " and thus replicating the current binary log event"
+                        " may make the slave's data become different from the"
+                        " master's data."
+                        " To take no risk, slave refuses to replicate"
+                        " this event and stops."
+                        " We recommend that all updates be stopped on the"
+                        " master and slave, that the data of both be"
+                        " manually synchronized,"
+                        " that master's binary logs be deleted,"
+                        " that master be upgraded to a version at least"
+                        " equal to '%d.%d.%d'. Then replication can be"
+                        " restarted.",
+                        rli->relay_log.description_event_for_exec->server_version,
+                        bug_id,
+                        fixed_in[0], fixed_in[1], fixed_in[2]);
+      // a short message for SHOW SLAVE STATUS (message length constraints)
+      my_printf_error(ER_UNKNOWN_ERROR, "master may suffer from"
+                      " http://bugs.mysql.com/bug.php?id=%u"
+                      " so slave stops; check error log on slave"
+                      " for more info", MYF(0), bug_id);
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
 
 #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
 template class I_List_iterator<i_string>;

--- 1.315/sql/sql_class.cc	2007-03-02 00:10:26 +02:00
+++ 1.316/sql/sql_class.cc	2007-03-02 00:10:26 +02:00
@@ -996,6 +996,7 @@
   enclosed=   line_start= &my_empty_string;
   line_term=  &default_line_term;
   escaped=    &default_escaped;
+  cs= NULL;
 }
 
 bool select_send::send_fields(List<Item> &list, uint flags)
@@ -2155,9 +2156,11 @@
 
   if ((!lex->requires_prelocking() || is_update_query(lex->sql_command)) &&
       !current_stmt_binlog_row_based)
-  {
-    options&= ~OPTION_BIN_LOG;
-  }    
+    options&= ~OPTION_BIN_LOG;  
+
+  if ((backup->options & OPTION_BIN_LOG) &&
is_update_query(lex->sql_command))
+    mysql_bin_log.start_union_events(this, this->query_id);
+
   /* Disable result sets */
   client_capabilities &= ~CLIENT_MULTI_RESULTS;
   in_sub_stmt|= new_state;
@@ -2200,6 +2203,9 @@
   limit_found_rows= backup->limit_found_rows;
   sent_row_count=   backup->sent_row_count;
   client_capabilities= backup->client_capabilities;
+
+  if ((options & OPTION_BIN_LOG) && is_update_query(lex->sql_command))
+    mysql_bin_log.stop_union_events(this);
 
   /*
     The following is added to the old values as we are interested in the

--- 1.340/sql/sql_class.h	2007-03-02 00:10:26 +02:00
+++ 1.341/sql/sql_class.h	2007-03-02 00:10:26 +02:00
@@ -1656,6 +1656,7 @@
   bool opt_enclosed;
   bool dumpfile;
   ulong skip_lines;
+  CHARSET_INFO *cs;
   sql_exchange(char *name,bool dumpfile_flag);
 };
 

--- 1.250/sql/sql_insert.cc	2007-03-02 00:10:26 +02:00
+++ 1.251/sql/sql_insert.cc	2007-03-02 00:10:26 +02:00
@@ -58,6 +58,7 @@
 #include "sp_head.h"
 #include "sql_trigger.h"
 #include "sql_select.h"
+#include "slave.h"
 #include "sql_show.h"
 
 #ifndef EMBEDDED_LIBRARY
@@ -391,6 +392,27 @@
       (duplic == DUP_UPDATE))
     lock_type=TL_WRITE;
 #endif
+  if ((lock_type == TL_WRITE_DELAYED) &&
+      log_on && mysql_bin_log.is_open() &&
+      (values_list.elements > 1))
+  {
+    /*
+      Statement-based binary logging does not work in this case, because:
+      a) two concurrent statements may have their rows intermixed in the
+      queue, leading to autoincrement replication problems on slave (because
+      the values generated used for one statement don't depend only on the
+      value generated for the first row of this statement, so are not
+      replicable)
+      b) if first row of the statement has an error the full statement is
+      not binlogged, while next rows of the statement may be inserted.
+      c) if first row succeeds, statement is binlogged immediately with a
+      zero error code (i.e. "no error"), if then second row fails, query
+      will fail on slave too and slave will stop (wrongly believing that the
+      master got no error).
+      So we fallback to non-delayed INSERT.
+    */
+    lock_type= TL_WRITE;
+  }
   table_list->lock_type= lock_type;
 
 #ifndef EMBEDDED_LIBRARY
@@ -505,6 +527,14 @@
   thd->cuted_fields = 0L;
   table->next_number_field=table->found_next_number_field;
 
+#ifdef HAVE_REPLICATION
+  if (thd->slave_thread &&
+      (info.handle_duplicates == DUP_UPDATE) &&
+      (table->next_number_field != NULL) &&
+      rpl_master_has_bug(&active_mi->rli, 24432))
+    goto abort;
+#endif
+
   error=0;
   thd->proc_info="update";
   if (duplic != DUP_ERROR || ignore)
@@ -2559,6 +2589,15 @@
   }
   restore_record(table,s->default_values);		// Get empty record
   table->next_number_field=table->found_next_number_field;
+
+#ifdef HAVE_REPLICATION
+  if (thd->slave_thread &&
+      (info.handle_duplicates == DUP_UPDATE) &&
+      (table->next_number_field != NULL) &&
+      rpl_master_has_bug(&active_mi->rli, 24432))
+    DBUG_RETURN(1);
+#endif
+
   thd->cuted_fields=0;
   if (info.ignore || info.handle_duplicates != DUP_ERROR)
     table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);

--- 1.114/sql/sql_load.cc	2007-03-02 00:10:26 +02:00
+++ 1.115/sql/sql_load.cc	2007-03-02 00:10:26 +02:00
@@ -316,7 +316,8 @@
   info.handle_duplicates=handle_duplicates;
   info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
 
-  READ_INFO read_info(file,tot_length,thd->variables.collation_database,
+  READ_INFO read_info(file,tot_length,
+                      ex->cs ? ex->cs : thd->variables.collation_database,
 		      *field_term,*ex->line_start, *ex->line_term, *enclosed,
 		      info.escape_char, read_file_from_client, is_fifo);
   if (read_info.error)
@@ -458,7 +459,6 @@
   }
   sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted,
 	  (ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
-  send_ok(thd,info.copied+info.deleted,0L,name);
 
   if (!transactional_table)
     thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
@@ -494,6 +494,8 @@
   if (transactional_table)
     error=ha_autocommit_or_rollback(thd,error);
 
+  /* ok to client sent only after binlog write and engine commit */
+  send_ok(thd, info.copied + info.deleted, 0L, name);
 err:
   table->file->ha_release_auto_increment();
   if (thd->lock)

--- 1.629/sql/sql_parse.cc	2007-03-02 00:10:26 +02:00
+++ 1.630/sql/sql_parse.cc	2007-03-02 00:10:26 +02:00
@@ -25,6 +25,7 @@
 #include "sp_head.h"
 #include "sp.h"
 #include "sp_cache.h"
+#include "sql_trigger.h"
 #include "events.h"
 #include "event_data_objects.h"
 
@@ -1596,6 +1597,30 @@
 #ifdef HAVE_REPLICATION
   if (unlikely(thd->slave_thread))
   {
+    if (lex->sql_command == SQLCOM_DROP_TRIGGER)
+    {
+      /*
+        When dropping a trigger, we need to load its table name
+        before checking slave filter rules.
+      */
+      add_table_for_trigger(thd, thd->lex->spname, 1, &all_tables);
+      
+      if (!all_tables)
+      {
+        /*
+          If table name cannot be loaded,
+          it means the trigger does not exists possibly because
+          CREATE TRIGGER was previously skipped for this trigger
+          according to slave filtering rules.
+          Returning success without producing any errors in this case.
+        */
+        DBUG_RETURN(0);
+      }
+      
+      // force searching in slave.cc:tables_ok() 
+      all_tables->updating= 1;
+    }
+    
     /*
       Check if statment should be skipped because of slave filtering
       rules

--- 1.542/sql/sql_yacc.yy	2007-03-02 00:10:26 +02:00
+++ 1.543/sql/sql_yacc.yy	2007-03-02 00:10:26 +02:00
@@ -1067,6 +1067,7 @@
 	old_or_new_charset_name_or_default
 	collation_name
 	collation_name_or_default
+	opt_load_data_charset
 
 %type <variable> internal_variable_name
 
@@ -4662,6 +4663,10 @@
 	charset_name { $$=$1;   }
 	| DEFAULT    { $$=NULL; } ;
 
+opt_load_data_charset:
+	/* Empty */ { $$= NULL; }
+	| charset charset_name_or_default { $$= $2; }
+	;
 
 old_or_new_charset_name:
 	ident_or_text
@@ -8964,6 +8969,8 @@
           lex->update_list.empty();
           lex->value_list.empty();
         }
+        opt_load_data_charset
+	{ Lex->exchange->cs= $12; }
         opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec
         opt_load_data_set_spec
         {}

--- 1.60.14.2/sql/ha_archive.cc	2007-03-02 00:10:26 +02:00
+++ 1.130/storage/archive/ha_archive.cc	2007-03-02 00:10:26 +02:00
@@ -18,25 +18,27 @@
 #endif
 
 #include "mysql_priv.h"
+#include <myisam.h>
 
-#if defined(HAVE_ARCHIVE_DB)
 #include "ha_archive.h"
 #include <my_dir.h>
 
+#include <mysql/plugin.h>
+
 /*
   First, if you want to understand storage engines you should look at 
   ha_example.cc and ha_example.h. 
+
   This example was written as a test case for a customer who needed
   a storage engine without indexes that could compress data very well.
   So, welcome to a completely compressed storage engine. This storage
   engine only does inserts. No replace, deletes, or updates. All reads are 
-  complete table scans. Compression is done through gzip (bzip compresses
-  better, but only marginally, if someone asks I could add support for
-  it too, but beaware that it costs a lot more in CPU time then gzip).
+  complete table scans. Compression is done through a combination of packing
+  and making use of the zlib library
   
   We keep a file pointer open for each instance of ha_archive for each read
   but for writes we keep one open file handle just for that. We flush it
-  only if we have a read occur. gzip handles compressing lots of records
+  only if we have a read occur. azip handles compressing lots of records
   at once much better then doing lots of little records between writes.
   It is possible to not lock on writes but this would then mean we couldn't
   handle bulk inserts as well (that is if someone was trying to read at
@@ -63,8 +65,7 @@
   pool. For MyISAM its a question of how much the file system caches the
   MyISAM file. With enough free memory MyISAM is faster. Its only when the OS
   doesn't have enough memory to cache entire table that archive turns out 
-  to be any faster. For writes it is always a bit slower then MyISAM. It has no
-  internal limits though for row length.
+  to be any faster. 
 
   Examples between MyISAM (packed) and Archive.
 
@@ -79,95 +80,58 @@
 
 
   TODO:
-   Add bzip optional support.
    Allow users to set compression level.
-   Add truncate table command.
    Implement versioning, should be easy.
    Allow for errors, find a way to mark bad rows.
-   Talk to the gzip guys, come up with a writable format so that updates are doable
-     without switching to a block method.
    Add optional feature so that rows can be flushed at interval (which will cause less
      compression but may speed up ordered searches).
    Checkpoint the meta file to allow for faster rebuilds.
-   Dirty open (right now the meta file is repaired if a crash occured).
    Option to allow for dirty reads, this would lower the sync calls, which would make
      inserts a lot faster, but would mean highly arbitrary reads.
 
     -Brian
 */
-/*
-  Notes on file formats.
-  The Meta file is layed out as:
-  check - Just an int of 254 to make sure that the the file we are opening was
-          never corrupted.
-  version - The current version of the file format.
-  rows - This is an unsigned long long which is the number of rows in the data
-         file.
-  check point - Reserved for future use
-  dirty - Status of the file, whether or not its values are the latest. This
-          flag is what causes a repair to occur
-
-  The data file:
-  check - Just an int of 254 to make sure that the the file we are opening was
-          never corrupted.
-  version - The current version of the file format.
-  data - The data is stored in a "row +blobs" format.
-*/
 
-/* If the archive storage engine has been inited */
-static bool archive_inited= FALSE;
 /* Variables for archive share methods */
 pthread_mutex_t archive_mutex;
 static HASH archive_open_tables;
-static z_off_t max_zfile_size;
-static int zoffset_size;
 
 /* The file extension */
 #define ARZ ".ARZ"               // The data file
 #define ARN ".ARN"               // Files used during an optimize call
-#define ARM ".ARM"               // Meta file
-/*
-  uchar + uchar + ulonglong + ulonglong + uchar
-*/
-#define META_BUFFER_SIZE 19      // Size of the data used in the meta file
+#define ARM ".ARM"               // Meta file (deprecated)
+
 /*
   uchar + uchar
 */
 #define DATA_BUFFER_SIZE 2       // Size of the data used in the data file
 #define ARCHIVE_CHECK_HEADER 254 // The number we use to determine corruption
 
-/* 
+/* Static declarations for handerton */
+static handler *archive_create_handler(handlerton *hton, 
+                                       TABLE_SHARE *table, 
+                                       MEM_ROOT *mem_root);
+int archive_discover(handlerton *hton, THD* thd, const char *db, 
+                        const char *name,
+                        const void** frmblob, 
+                        uint* frmlen);
+
+/*
   Number of rows that will force a bulk insert.
 */
 #define ARCHIVE_MIN_ROWS_TO_USE_BULK_INSERT 2
 
+/*
+  Size of header used for row
+*/
+#define ARCHIVE_ROW_HEADER_SIZE 4
 
-
-/* dummy handlerton - only to have something to return from archive_db_init */
-handlerton archive_hton = {
-  "ARCHIVE",
-  SHOW_OPTION_YES,
-  "Archive storage engine", 
-  DB_TYPE_ARCHIVE_DB,
-  archive_db_init,
-  0,       /* slot */
-  0,       /* savepoint size. */
-  NULL,    /* close_connection */
-  NULL,    /* savepoint */
-  NULL,    /* rollback to savepoint */
-  NULL,    /* releas savepoint */
-  NULL,    /* commit */
-  NULL,    /* rollback */
-  NULL,    /* prepare */
-  NULL,    /* recover */
-  NULL,    /* commit_by_xid */
-  NULL,    /* rollback_by_xid */
-  NULL,    /* create_cursor_read_view */
-  NULL,    /* set_cursor_read_view */
-  NULL,    /* close_cursor_read_view */
-  HTON_NO_FLAGS
-};
-
+static handler *archive_create_handler(handlerton *hton,
+                                       TABLE_SHARE *table, 
+                                       MEM_ROOT *mem_root)
+{
+  return new (mem_root) ha_archive(hton, table);
+}
 
 /*
   Used for hash table that tracks open tables.
@@ -185,16 +149,25 @@
 
   SYNOPSIS
     archive_db_init()
-    void
+    void *
 
   RETURN
     FALSE       OK
     TRUE        Error
 */
 
-bool archive_db_init()
+int archive_db_init(void *p)
 {
   DBUG_ENTER("archive_db_init");
+  handlerton *archive_hton;
+
+  archive_hton= (handlerton *)p;
+  archive_hton->state= SHOW_OPTION_YES;
+  archive_hton->db_type= DB_TYPE_ARCHIVE_DB;
+  archive_hton->create= archive_create_handler;
+  archive_hton->flags= HTON_NO_FLAGS;
+  archive_hton->discover= archive_discover;
+
   if (pthread_mutex_init(&archive_mutex, MY_MUTEX_INIT_FAST))
     goto error;
   if (hash_init(&archive_open_tables, system_charset_info, 32, 0, 0,
@@ -204,23 +177,9 @@
   }
   else
   {
-    zoffset_size= 2 << ((zlibCompileFlags() >> 6) & 3);
-    switch (sizeof(z_off_t)) {
-    case 2:
-      max_zfile_size= INT_MAX16;
-      break;
-    case 8:
-      max_zfile_size= (z_off_t) LONGLONG_MAX;
-      break;
-    case 4:
-    default:
-      max_zfile_size= INT_MAX32;
-    }
-    archive_inited= TRUE;
     DBUG_RETURN(FALSE);
   }
 error:
-  have_archive_db= SHOW_OPTION_DISABLED;	// If we couldn't use handler
   DBUG_RETURN(TRUE);
 }
 
@@ -228,145 +187,112 @@
   Release the archive handler.
 
   SYNOPSIS
-    archive_db_end()
+    archive_db_done()
     void
 
   RETURN
     FALSE       OK
 */
 
-bool archive_db_end()
+int archive_db_done(void *p)
 {
-  if (archive_inited)
-  {
-    hash_free(&archive_open_tables);
-    VOID(pthread_mutex_destroy(&archive_mutex));
-  }
-  archive_inited= 0;
-  return FALSE;
+  hash_free(&archive_open_tables);
+  VOID(pthread_mutex_destroy(&archive_mutex));
+
+  return 0;
 }
 
-ha_archive::ha_archive(TABLE *table_arg)
-  :handler(&archive_hton, table_arg), delayed_insert(0), bulk_insert(0)
+
+ha_archive::ha_archive(handlerton *hton, TABLE_SHARE *table_arg)
+  :handler(hton, table_arg), delayed_insert(0), bulk_insert(0)
 {
   /* Set our original buffer from pre-allocated memory */
   buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info);
 
   /* The size of the offset value we will use for position() */
-  ref_length = zoffset_size;
-  DBUG_ASSERT(ref_length <= sizeof(z_off_t));
+  ref_length = sizeof(my_off_t);
 }
 
-/*
-  This method reads the header of a datafile and returns whether or not it was
successful.
-*/
-int ha_archive::read_data_header(gzFile file_to_read)
+int archive_discover(handlerton *hton, THD* thd, const char *db, 
+                        const char *name,
+                        const void** frmblob, 
+                        uint* frmlen)
 {
-  uchar data_buffer[DATA_BUFFER_SIZE];
-  DBUG_ENTER("ha_archive::read_data_header");
+  DBUG_ENTER("archive_discover");
+  DBUG_PRINT("archive_discover", ("db: %s, name: %s", db, name)); 
+  azio_stream frm_stream;
+  char az_file[FN_REFLEN];
+  char *frm_ptr;
+  MY_STAT file_stat; 
 
-  if (gzrewind(file_to_read) == -1)
-    DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+  fn_format(az_file, name, db, ARZ, MY_REPLACE_EXT | MY_UNPACK_FILENAME);
 
-  if (gzread(file_to_read, data_buffer, DATA_BUFFER_SIZE) != DATA_BUFFER_SIZE)
-    DBUG_RETURN(errno ? errno : -1);
-  
-  DBUG_PRINT("ha_archive::read_data_header", ("Check %u", data_buffer[0]));
-  DBUG_PRINT("ha_archive::read_data_header", ("Version %u", data_buffer[1]));
-  
-  if ((data_buffer[0] != (uchar)ARCHIVE_CHECK_HEADER) &&  
-      (data_buffer[1] != (uchar)ARCHIVE_VERSION))
-    DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+  if (!(my_stat(az_file, &file_stat, MYF(0))))
+    goto err;
 
-  DBUG_RETURN(0);
-}
+  if (!(azopen(&frm_stream, az_file, O_RDONLY|O_BINARY)))
+  {
+    if (errno == EROFS || errno == EACCES)
+      DBUG_RETURN(my_errno= errno);
+    DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+  }
 
-/*
-  This method writes out the header of a datafile and returns whether or not it was
successful.
-*/
-int ha_archive::write_data_header(gzFile file_to_write)
-{
-  uchar data_buffer[DATA_BUFFER_SIZE];
-  DBUG_ENTER("ha_archive::write_data_header");
+  if (frm_stream.frm_length == 0)
+    goto err;
 
-  data_buffer[0]= (uchar)ARCHIVE_CHECK_HEADER;
-  data_buffer[1]= (uchar)ARCHIVE_VERSION;
+  frm_ptr= (char *)my_malloc(sizeof(char) * frm_stream.frm_length, MYF(0));
+  azread_frm(&frm_stream, frm_ptr);
+  azclose(&frm_stream);
 
-  if (gzwrite(file_to_write, &data_buffer, DATA_BUFFER_SIZE) != 
-      DATA_BUFFER_SIZE)
-    goto error;
-  DBUG_PRINT("ha_archive::write_data_header", ("Check %u", (uint)data_buffer[0]));
-  DBUG_PRINT("ha_archive::write_data_header", ("Version %u", (uint)data_buffer[1]));
+  *frmlen= frm_stream.frm_length;
+  *frmblob= frm_ptr;
 
   DBUG_RETURN(0);
-error:
-  DBUG_RETURN(errno);
+err:
+  my_errno= 0;
+  DBUG_RETURN(1);
 }
 
 /*
-  This method reads the header of a meta file and returns whether or not it was
successful.
-  *rows will contain the current number of rows in the data file upon success.
+  This method reads the header of a datafile and returns whether or not it was
successful.
 */
-int ha_archive::read_meta_file(File meta_file, ha_rows *rows)
+int ha_archive::read_data_header(azio_stream *file_to_read)
 {
-  uchar meta_buffer[META_BUFFER_SIZE];
-  ulonglong check_point;
-
-  DBUG_ENTER("ha_archive::read_meta_file");
-
-  VOID(my_seek(meta_file, 0, MY_SEEK_SET, MYF(0)));
-  if (my_read(meta_file, (byte*)meta_buffer, META_BUFFER_SIZE, 0) != META_BUFFER_SIZE)
-    DBUG_RETURN(-1);
-  
-  /*
-    Parse out the meta data, we ignore version at the moment
-  */
-  *rows= (ha_rows)uint8korr(meta_buffer + 2);
-  check_point= uint8korr(meta_buffer + 10);
-
-  DBUG_PRINT("ha_archive::read_meta_file", ("Check %d", (uint)meta_buffer[0]));
-  DBUG_PRINT("ha_archive::read_meta_file", ("Version %d", (uint)meta_buffer[1]));
-  DBUG_PRINT("ha_archive::read_meta_file", ("Rows %lu", (ulong) *rows));
-  DBUG_PRINT("ha_archive::read_meta_file", ("Checkpoint %lu", (ulong) check_point));
-  DBUG_PRINT("ha_archive::read_meta_file", ("Dirty %d", (int)meta_buffer[18]));
+  int error;
+  unsigned long ret;
+  uchar data_buffer[DATA_BUFFER_SIZE];
+  DBUG_ENTER("ha_archive::read_data_header");
 
-  if ((meta_buffer[0] != (uchar)ARCHIVE_CHECK_HEADER) || 
-      ((bool)meta_buffer[18] == TRUE))
+  if (azrewind(file_to_read) == -1)
     DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
 
-  my_sync(meta_file, MYF(MY_WME));
+  if (file_to_read->version >= 3)
+    DBUG_RETURN(0);
+  /* Everything below this is just legacy to version 2< */
 
-  DBUG_RETURN(0);
-}
+  DBUG_PRINT("ha_archive", ("Reading legacy data header"));
 
-/*
-  This method writes out the header of a meta file and returns whether or not it was
successful.
-  By setting dirty you say whether or not the file represents the actual state of the
data file.
-  Upon ::open() we set to dirty, and upon ::close() we set to clean.
-*/
-int ha_archive::write_meta_file(File meta_file, ha_rows rows, bool dirty)
-{
-  uchar meta_buffer[META_BUFFER_SIZE];
-  ulonglong check_point= 0; //Reserved for the future
-
-  DBUG_ENTER("ha_archive::write_meta_file");
-
-  meta_buffer[0]= (uchar)ARCHIVE_CHECK_HEADER;
-  meta_buffer[1]= (uchar)ARCHIVE_VERSION;
-  int8store(meta_buffer + 2, (ulonglong)rows); 
-  int8store(meta_buffer + 10, check_point); 
-  *(meta_buffer + 18)= (uchar)dirty;
-  DBUG_PRINT("ha_archive::write_meta_file", ("Check %d", (uint)ARCHIVE_CHECK_HEADER));
-  DBUG_PRINT("ha_archive::write_meta_file", ("Version %d", (uint)ARCHIVE_VERSION));
-  DBUG_PRINT("ha_archive::write_meta_file", ("Rows %lu", (ulong)rows));
-  DBUG_PRINT("ha_archive::write_meta_file", ("Checkpoint %lu", (ulong) check_point));
-  DBUG_PRINT("ha_archive::write_meta_file", ("Dirty %d", (uint)dirty));
+  ret= azread(file_to_read, data_buffer, DATA_BUFFER_SIZE, &error);
 
-  VOID(my_seek(meta_file, 0, MY_SEEK_SET, MYF(0)));
-  if (my_write(meta_file, (byte *)meta_buffer, META_BUFFER_SIZE, 0) != META_BUFFER_SIZE)
-    DBUG_RETURN(-1);
+  if (ret != DATA_BUFFER_SIZE)
+  {
+    DBUG_PRINT("ha_archive", ("Reading, expected %d got %lu", 
+                              DATA_BUFFER_SIZE, ret));
+    DBUG_RETURN(1);
+  }
+
+  if (error)
+  {
+    DBUG_PRINT("ha_archive", ("Compression error (%d)", error));
+    DBUG_RETURN(1);
+  }
   
-  my_sync(meta_file, MYF(MY_WME));
+  DBUG_PRINT("ha_archive", ("Check %u", data_buffer[0]));
+  DBUG_PRINT("ha_archive", ("Version %u", data_buffer[1]));
+
+  if ((data_buffer[0] != (uchar)ARCHIVE_CHECK_HEADER) &&  
+      (data_buffer[1] != (uchar)ARCHIVE_VERSION))
+    DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
 
   DBUG_RETURN(0);
 }
@@ -381,9 +307,7 @@
 */
 ARCHIVE_SHARE *ha_archive::get_share(const char *table_name, int *rc)
 {
-  char meta_file_name[FN_REFLEN];
   uint length;
-  char *tmp_name;
   DBUG_ENTER("ha_archive::get_share");
 
   pthread_mutex_lock(&archive_mutex);
@@ -393,6 +317,9 @@
                                            (byte*) table_name,
                                            length)))
   {
+    char *tmp_name;
+    azio_stream archive_tmp;
+
     if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
                           &share, sizeof(*share),
                           &tmp_name, length+1,
@@ -408,31 +335,36 @@
     share->table_name= tmp_name;
     share->crashed= FALSE;
     share->archive_write_open= FALSE;
-    fn_format(share->data_file_name,table_name,"",ARZ,
-              MY_REPLACE_EXT|MY_UNPACK_FILENAME);
-    fn_format(meta_file_name,table_name,"",ARM,
-              MY_REPLACE_EXT|MY_UNPACK_FILENAME);
-    strmov(share->table_name,table_name);
+    fn_format(share->data_file_name, table_name, "",
+              ARZ, MY_REPLACE_EXT | MY_UNPACK_FILENAME);
+    strmov(share->table_name, table_name);
+    DBUG_PRINT("ha_archive", ("Data File %s", 
+                        share->data_file_name));
     /*
       We will use this lock for rows.
     */
     VOID(pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST));
-    if ((share->meta_file= my_open(meta_file_name, O_RDWR, MYF(0))) == -1)
-      share->crashed= TRUE;
     
     /*
-      After we read, we set the file to dirty. When we close, we will do the 
-      opposite. If the meta file will not open we assume it is crashed and
-      leave it up to the user to fix.
+      We read the meta file, but do not mark it dirty. Since we are not
+      doing a write we won't mark it dirty (and we won't open it for
+      anything but reading... open it for write and we will generate null
+      compression writes).
     */
-    if (read_meta_file(share->meta_file, &share->rows_recorded))
-      share->crashed= TRUE;
+    if (!(azopen(&archive_tmp, share->data_file_name, O_RDONLY|O_BINARY)))
+    {
+      DBUG_RETURN(NULL);
+    }
+    stats.auto_increment_value= archive_tmp.auto_increment;
+    share->rows_recorded= (ha_rows)archive_tmp.rows;
+    share->crashed= archive_tmp.dirty;
+    azclose(&archive_tmp);
 
     VOID(my_hash_insert(&archive_open_tables, (byte*) share));
     thr_lock_init(&share->lock);
   }
   share->use_count++;
-  DBUG_PRINT("info", ("archive table %.*s has %d open handles now", 
+  DBUG_PRINT("ha_archive", ("archive table %.*s has %d open handles now", 
                       share->table_name_length, share->table_name,
                       share->use_count));
   if (share->crashed)
@@ -451,9 +383,10 @@
 {
   int rc= 0;
   DBUG_ENTER("ha_archive::free_share");
-  DBUG_PRINT("info", ("archive table %.*s has %d open handles on entrance", 
-                      share->table_name_length, share->table_name,
-                      share->use_count));
+  DBUG_PRINT("ha_archive",
+             ("archive table %.*s has %d open handles on entrance", 
+              share->table_name_length, share->table_name,
+              share->use_count));
 
   pthread_mutex_lock(&archive_mutex);
   if (!--share->use_count)
@@ -461,15 +394,18 @@
     hash_delete(&archive_open_tables, (byte*) share);
     thr_lock_delete(&share->lock);
     VOID(pthread_mutex_destroy(&share->mutex));
-    if (share->crashed)
-      (void)write_meta_file(share->meta_file, share->rows_recorded, TRUE);
-    else
-      (void)write_meta_file(share->meta_file, share->rows_recorded, FALSE);
+    /* 
+      We need to make sure we don't reset the crashed state.
+      If we open a crashed file, wee need to close it as crashed unless
+      it has been repaired.
+      Since we will close the data down after this, we go on and count
+      the flush on close;
+    */
     if (share->archive_write_open)
-      if (gzclose(share->archive_write) == Z_ERRNO)
+    {
+      if (azclose(&(share->archive_write)))
         rc= 1;
-    if (my_close(share->meta_file, MYF(0)))
-      rc= 1;
+    }
     my_free((gptr) share, MYF(0));
   }
   pthread_mutex_unlock(&archive_mutex);
@@ -480,21 +416,20 @@
 int ha_archive::init_archive_writer()
 {
   DBUG_ENTER("ha_archive::init_archive_writer");
-  (void)write_meta_file(share->meta_file, share->rows_recorded, TRUE);
-
   /* 
     It is expensive to open and close the data files and since you can't have
     a gzip file that can be both read and written we keep a writer open
     that is shared amoung all open tables.
   */
-  if ((share->archive_write= gzopen(share->data_file_name, "ab")) == NULL)
+  if (!(azopen(&(share->archive_write), share->data_file_name, 
+               O_RDWR|O_BINARY)))
   {
+    DBUG_PRINT("ha_archive", ("Could not open archive write file"));
     share->crashed= TRUE;
     DBUG_RETURN(1);
   }
   share->archive_write_open= TRUE;
-  info(HA_STATUS_TIME);
-  share->approx_file_size= (ulong) data_file_length;
+
   DBUG_RETURN(0);
 }
 
@@ -504,7 +439,6 @@
 */
 static const char *ha_archive_exts[] = {
   ARZ,
-  ARM,
   NullS
 };
 
@@ -525,7 +459,7 @@
   int rc= 0;
   DBUG_ENTER("ha_archive::open");
 
-  DBUG_PRINT("info", ("archive table was opened for crash %s", 
+  DBUG_PRINT("ha_archive", ("archive table was opened for crash: %s", 
                       (open_options & HA_OPEN_FOR_REPAIR) ? "yes" : "no"));
   share= get_share(name, &rc);
 
@@ -541,16 +475,29 @@
     DBUG_RETURN(rc);
   }
 
-  thr_lock_data_init(&share->lock,&lock,NULL);
+  DBUG_ASSERT(share);
+
+
+  record_buffer= create_record_buffer(table->s->reclength + 
+                                      ARCHIVE_ROW_HEADER_SIZE);
+
+  if (!record_buffer)
+  {
+    free_share();
+    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+  }
+
+  thr_lock_data_init(&share->lock, &lock, NULL);
 
-  if ((archive= gzopen(share->data_file_name, "rb")) == NULL)
+  DBUG_PRINT("ha_archive", ("archive data_file_name %s", share->data_file_name));
+  if (!(azopen(&archive, share->data_file_name, O_RDONLY|O_BINARY)))
   {
     if (errno == EROFS || errno == EACCES)
       DBUG_RETURN(my_errno= errno);
     DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
   }
 
-  DBUG_PRINT("info", ("archive table was crashed %s", 
+  DBUG_PRINT("ha_archive", ("archive table was crashed %s", 
                       rc == HA_ERR_CRASHED_ON_USAGE ? "yes" : "no"));
   if (rc == HA_ERR_CRASHED_ON_USAGE && open_options & HA_OPEN_FOR_REPAIR)
   {
@@ -583,8 +530,10 @@
   int rc= 0;
   DBUG_ENTER("ha_archive::close");
 
+  destroy_record_buffer(record_buffer);
+
   /* First close stream */
-  if (gzclose(archive) == Z_ERRNO)
+  if (azclose(&archive))
     rc= 1;
   /* then also close share */
   rc|= free_share();
@@ -605,57 +554,120 @@
 int ha_archive::create(const char *name, TABLE *table_arg,
                        HA_CREATE_INFO *create_info)
 {
-  File create_file;  // We use to create the datafile and the metafile
   char name_buff[FN_REFLEN];
+  char linkname[FN_REFLEN];
   int error;
+  azio_stream create_stream;            /* Archive file we are working with */
+  File frm_file;                   /* File handler for readers */
+  MY_STAT file_stat;  // Stat information for the data file
+  byte *frm_ptr;
+
   DBUG_ENTER("ha_archive::create");
 
-  if ((create_file= my_create(fn_format(name_buff,name,"",ARM,
-                                        MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
-                              O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+  stats.auto_increment_value= (create_info->auto_increment_value ?
+                               create_info->auto_increment_value -1 :
+                               (ulonglong) 0);
+
+  for (uint key= 0; key < table_arg->s->keys; key++)
   {
-    error= my_errno;
-    goto error;
+    KEY *pos= table_arg->key_info+key;
+    KEY_PART_INFO *key_part=     pos->key_part;
+    KEY_PART_INFO *key_part_end= key_part + pos->key_parts;
+
+    for (; key_part != key_part_end; key_part++)
+    {
+      Field *field= key_part->field;
+
+      if (!(field->flags & AUTO_INCREMENT_FLAG))
+      {
+        error= -1;
+        DBUG_PRINT("ha_archive", ("Index error in creating archive table"));
+        goto error;
+      }
+    }
   }
-  write_meta_file(create_file, 0, FALSE);
-  my_close(create_file,MYF(0));
 
   /* 
     We reuse name_buff since it is available.
   */
-  if ((create_file= my_create(fn_format(name_buff,name,"",ARZ,
-                                        MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
-                              O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
-  {
-    error= my_errno;
-    goto error;
-  }
-  if ((archive= gzdopen(dup(create_file), "wb")) == NULL)
+  if (create_info->data_file_name && create_info->data_file_name[0] != '#')
   {
-    error= errno;
-    goto error2;
+    DBUG_PRINT("ha_archive", ("archive will create stream file %s", 
+                        create_info->data_file_name));
+                        
+    fn_format(name_buff, create_info->data_file_name, "", ARZ,
+              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
+    fn_format(linkname, name, "", ARZ,
+              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
   }
-  if (write_data_header(archive))
+  else
   {
-    error= errno;
-    goto error3;
+    fn_format(name_buff, name, "", ARZ,
+              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
+    linkname[0]= 0;
   }
 
-  if (gzclose(archive))
+  /*
+    There is a chance that the file was "discovered". In this case
+    just use whatever file is there.
+  */
+  if (!(my_stat(name_buff, &file_stat, MYF(0))))
   {
-    error= errno;
-    goto error2;
+    my_errno= 0;
+    if (!(azopen(&create_stream, name_buff, O_CREAT|O_RDWR|O_BINARY)))
+    {
+      error= errno;
+      goto error2;
+    }
+
+    if (linkname[0])
+      my_symlink(name_buff, linkname, MYF(0));
+    fn_format(name_buff, name, "", ".frm",
+              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
+
+    /*
+      Here is where we open up the frm and pass it to archive to store 
+    */
+    if ((frm_file= my_open(name_buff, O_RDONLY, MYF(0))) > 0)
+    {
+      if (!my_fstat(frm_file, &file_stat, MYF(MY_WME)))
+      {
+        frm_ptr= (byte *)my_malloc(sizeof(byte) * file_stat.st_size , MYF(0));
+        if (frm_ptr)
+        {
+          my_read(frm_file, frm_ptr, file_stat.st_size, MYF(0));
+          azwrite_frm(&create_stream, (char *)frm_ptr, file_stat.st_size);
+          my_free((gptr)frm_ptr, MYF(0));
+        }
+      }
+      my_close(frm_file, MYF(0));
+    }
+
+    if (create_info->comment.str)
+      azwrite_comment(&create_stream, create_info->comment.str, 
+                      create_info->comment.length);
+
+    /* 
+      Yes you need to do this, because the starting value 
+      for the autoincrement may not be zero.
+    */
+    create_stream.auto_increment= stats.auto_increment_value;
+    if (azclose(&create_stream))
+    {
+      error= errno;
+      goto error2;
+    }
   }
+  else
+    my_errno= 0;
+
+  DBUG_PRINT("ha_archive", ("Creating File %s", name_buff));
+  DBUG_PRINT("ha_archive", ("Creating Link %s", linkname));
 
-  my_close(create_file, MYF(0));
 
   DBUG_RETURN(0);
 
-error3:
-  /* We already have an error, so ignore results of gzclose. */
-  (void)gzclose(archive);
 error2:
-  my_close(create_file, MYF(0));
   delete_table(name);
 error:
   /* Return error number, if we got one */
@@ -665,51 +677,82 @@
 /*
   This is where the actual row is written out.
 */
-int ha_archive::real_write_row(byte *buf, gzFile writer)
+int ha_archive::real_write_row(byte *buf, azio_stream *writer)
 {
-  z_off_t written, total_row_length;
-  uint *ptr, *end;
+  my_off_t written;
+  unsigned int r_pack_length;
   DBUG_ENTER("ha_archive::real_write_row");
-  total_row_length= table->s->reclength;
-  for (ptr= table->s->blob_field, end= ptr + table->s->blob_fields;
-       ptr != end; ptr++)
-    total_row_length+= ((Field_blob*) table->field[*ptr])->get_length();
-  if (share->approx_file_size > max_zfile_size - total_row_length)
-  {
-    info(HA_STATUS_TIME);
-    share->approx_file_size= (ulong) data_file_length;
-    if (share->approx_file_size > max_zfile_size - total_row_length)
-      DBUG_RETURN(HA_ERR_RECORD_FILE_FULL);
-  }
-  share->approx_file_size+= total_row_length;
-  written= gzwrite(writer, buf, table->s->reclength);
-  DBUG_PRINT("ha_archive::real_write_row", ("Wrote %d bytes expected %lu", (int) written,
-                                            table->s->reclength));
+
+  /* We pack the row for writing */
+  r_pack_length= pack_row(buf);
+
+  written= azwrite(writer, record_buffer->buffer, r_pack_length);
+  if (written != r_pack_length)
+  {
+    DBUG_PRINT("ha_archive", ("Wrote %d bytes expected %d", 
+                                              (uint32) written, 
+                                              (uint32)r_pack_length));
+    DBUG_RETURN(-1);
+  }
+
   if (!delayed_insert || !bulk_insert)
     share->dirty= TRUE;
 
-  if (written != (z_off_t)table->s->reclength)
-    DBUG_RETURN(errno ? errno : -1);
-  /*
-    We should probably mark the table as damagaged if the record is written
-    but the blob fails.
-  */
-  for (ptr= table->s->blob_field, end= ptr + table->s->blob_fields ;
+  DBUG_RETURN(0);
+}
+
+
+/* 
+  Calculate max length needed for row. This includes
+  the bytes required for the length in the header.
+*/
+
+uint32 ha_archive::max_row_length(const byte *buf)
+{
+  uint32 length= (uint32)(table->s->reclength + table->s->fields*2);
+  length+= ARCHIVE_ROW_HEADER_SIZE;
+
+  uint *ptr, *end;
+  for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
        ptr != end ;
        ptr++)
   {
-    char *data_ptr;
-    uint32 size= ((Field_blob*) table->field[*ptr])->get_length();
+      length += 2 + ((Field_blob*)table->field[*ptr])->get_length();
+  }
 
-    if (size)
-    {
-      ((Field_blob*) table->field[*ptr])->get_ptr(&data_ptr);
-      written= gzwrite(writer, data_ptr, (unsigned)size);
-      if (written != (z_off_t)size)
-        DBUG_RETURN(errno ? errno : -1);
-    }
+  return length;
+}
+
+
+unsigned int ha_archive::pack_row(byte *record)
+{
+  byte *ptr;
+
+  DBUG_ENTER("ha_archive::pack_row");
+
+
+  if (fix_rec_buff(max_row_length(record)))
+    DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
+
+  /* Copy null bits */
+  memcpy(record_buffer->buffer+ARCHIVE_ROW_HEADER_SIZE, 
+         record, table->s->null_bytes);
+  ptr= record_buffer->buffer + table->s->null_bytes + ARCHIVE_ROW_HEADER_SIZE;
+
+  for (Field **field=table->field ; *field ; field++)
+  {
+    if (!((*field)->is_null()))
+      ptr=(byte*) (*field)->pack((char*) ptr,
+                                 (char*) record + (*field)->offset(record));
   }
-  DBUG_RETURN(0);
+
+  int4store(record_buffer->buffer, (int)(ptr - record_buffer->buffer -
+                                         ARCHIVE_ROW_HEADER_SIZE)); 
+  DBUG_PRINT("ha_archive",("Pack row length %u", (unsigned int)
+                           (ptr - record_buffer->buffer - 
+                             ARCHIVE_ROW_HEADER_SIZE)));
+
+  DBUG_RETURN((unsigned int) (ptr - record_buffer->buffer));
 }
 
 
@@ -725,50 +768,204 @@
 int ha_archive::write_row(byte *buf)
 {
   int rc;
+  byte *read_buf= NULL;
+  ulonglong temp_auto;
+  byte *record=  table->record[0];
   DBUG_ENTER("ha_archive::write_row");
 
   if (share->crashed)
+    DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+
+  if (!share->archive_write_open)
+    if (init_archive_writer())
       DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
 
-  statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status);
+  ha_statistic_increment(&SSV::ha_write_count);
   if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
     table->timestamp_field->set_time();
   pthread_mutex_lock(&share->mutex);
-  if (!share->archive_write_open)
-    if (init_archive_writer())
-      DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
 
-  /*
-    Varchar structures are constant in size but are not cleaned up request
-    to request. The following sets all unused space to null to improve
-    compression.
-  */
-  for (Field **field=table->field ; *field ; field++)
+  if (table->next_number_field && record == table->record[0])
   {
-    DBUG_PRINT("archive",("Pack is %d\n", (*field)->pack_length()));
-    DBUG_PRINT("archive",("MyPack is %d\n", (*field)->data_length((char*) buf +
(*field)->offset())));
-    if ((*field)->real_type() == MYSQL_TYPE_VARCHAR) 
+    KEY *mkey= &table->s->key_info[0]; // We only support one key right now
+    update_auto_increment();
+    temp_auto= table->next_number_field->val_int();
+
+    /*
+      We don't support decremening auto_increment. They make the performance
+      just cry.
+    */
+    if (temp_auto <= share->archive_write.auto_increment && 
+        mkey->flags & HA_NOSAME)
     {
-#ifndef DBUG_OFF
-      uint actual_length= (*field)->data_length((char*) buf + (*field)->offset());
-      uint offset= (*field)->offset() + actual_length + 
-        (actual_length > 255 ? 2 : 1);
-      DBUG_PRINT("archive",("Offset is %d -> %d\n", actual_length, offset));
-#endif
-      /*
-      if ((*field)->pack_length() + (*field)->offset() != offset)
-        bzero(buf + offset, (size_t)((*field)->pack_length() + (actual_length > 255
? 2 : 1) - (*field)->data_length));
+      rc= HA_ERR_FOUND_DUPP_KEY;
+      goto error;
+    }
+#ifdef DEAD_CODE
+    /*
+      Bad news, this will cause a search for the unique value which is very 
+      expensive since we will have to do a table scan which will lock up 
+      all other writers during this period. This could perhaps be optimized 
+      in the future.
     */
+    {
+      /* 
+        First we create a buffer that we can use for reading rows, and can pass
+        to get_row().
+      */
+      if (!(read_buf= (byte*) my_malloc(table->s->reclength, MYF(MY_WME))))
+      {
+        rc= HA_ERR_OUT_OF_MEM;
+        goto error;
+      }
+       /* 
+         All of the buffer must be written out or we won't see all of the
+         data 
+       */
+      azflush(&(share->archive_write), Z_SYNC_FLUSH);
+      /*
+        Set the position of the local read thread to the beginning postion.
+      */
+      if (read_data_header(&archive))
+      {
+        rc= HA_ERR_CRASHED_ON_USAGE;
+        goto error;
+      }
+
+      Field *mfield= table->next_number_field;
+
+      while (!(get_row(&archive, read_buf)))
+      {
+        if (!memcmp(read_buf + mfield->offset(record),
+                    table->next_number_field->ptr,
+                    mfield->max_display_length()))
+        {
+          rc= HA_ERR_FOUND_DUPP_KEY;
+          goto error;
+        }
+      }
+    }
+#endif
+    else
+    {
+      if (temp_auto > share->archive_write.auto_increment)
+        stats.auto_increment_value= share->archive_write.auto_increment= 
+          temp_auto;
     }
   }
 
+  /*
+    Notice that the global auto_increment has been increased.
+    In case of a failed row write, we will never try to reuse the value.
+  */
   share->rows_recorded++;
-  rc= real_write_row(buf, share->archive_write);
+  rc= real_write_row(buf,  &(share->archive_write));
+error:
   pthread_mutex_unlock(&share->mutex);
+  if (read_buf)
+    my_free((gptr) read_buf, MYF(0));
 
   DBUG_RETURN(rc);
 }
 
+
+void ha_archive::get_auto_increment(ulonglong offset, ulonglong increment,
+                                    ulonglong nb_desired_values,
+                                    ulonglong *first_value,
+                                    ulonglong *nb_reserved_values)
+{
+  *nb_reserved_values= 1;
+  *first_value= share->archive_write.auto_increment + 1;
+}
+
+/* Initialized at each key walk (called multiple times unlike rnd_init()) */
+int ha_archive::index_init(uint keynr, bool sorted)
+{
+  DBUG_ENTER("ha_archive::index_init");
+  active_index= keynr;
+  DBUG_RETURN(0);
+}
+
+
+/*
+  No indexes, so if we get a request for an index search since we tell
+  the optimizer that we have unique indexes, we scan
+*/
+int ha_archive::index_read(byte *buf, const byte *key,
+                             uint key_len, enum ha_rkey_function find_flag)
+{
+  int rc;
+  DBUG_ENTER("ha_archive::index_read");
+  rc= index_read_idx(buf, active_index, key, key_len, find_flag);
+  DBUG_RETURN(rc);
+}
+
+
+int ha_archive::index_read_idx(byte *buf, uint index, const byte *key,
+                                 uint key_len, enum ha_rkey_function find_flag)
+{
+  int rc= 0;
+  bool found= 0;
+  KEY *mkey= &table->s->key_info[index];
+  current_k_offset= mkey->key_part->offset;
+  current_key= key;
+  current_key_len= key_len;
+
+
+  DBUG_ENTER("ha_archive::index_read_idx");
+
+  /* 
+    All of the buffer must be written out or we won't see all of the
+    data 
+  */
+  pthread_mutex_lock(&share->mutex);
+  azflush(&(share->archive_write), Z_SYNC_FLUSH);
+  pthread_mutex_unlock(&share->mutex);
+
+  /*
+    Set the position of the local read thread to the beginning postion.
+  */
+  if (read_data_header(&archive))
+  {
+    rc= HA_ERR_CRASHED_ON_USAGE;
+    goto error;
+  }
+
+  while (!(get_row(&archive, buf)))
+  {
+    if (!memcmp(current_key, buf + current_k_offset, current_key_len))
+    {
+      found= 1;
+      break;
+    }
+  }
+
+  if (found)
+    DBUG_RETURN(0);
+
+error:
+  DBUG_RETURN(rc ? rc : HA_ERR_END_OF_FILE);
+}
+
+
+int ha_archive::index_next(byte * buf) 
+{ 
+  bool found= 0;
+
+  DBUG_ENTER("ha_archive::index_next");
+
+  while (!(get_row(&archive, buf)))
+  {
+    if (!memcmp(current_key, buf+current_k_offset, current_key_len))
+    {
+      found= 1;
+      break;
+    }
+  }
+
+  DBUG_RETURN(found ? 0 : HA_ERR_END_OF_FILE); 
+}
+
 /*
   All calls that need to scan the table start with this method. If we are told
   that it is a table scan we rewind the file to the beginning, otherwise
@@ -786,26 +983,27 @@
   if (scan)
   {
     scan_rows= share->rows_recorded;
-    DBUG_PRINT("info", ("archive will retrieve %lu rows", (ulong) scan_rows));
-    records= 0;
+    DBUG_PRINT("info", ("archive will retrieve %llu rows", 
+                        (unsigned long long) scan_rows));
+    stats.records= 0;
 
     /* 
       If dirty, we lock, and then reset/flush the data.
-      I found that just calling gzflush() doesn't always work.
+      I found that just calling azflush() doesn't always work.
     */
     if (share->dirty == TRUE)
     {
       pthread_mutex_lock(&share->mutex);
       if (share->dirty == TRUE)
       {
-        DBUG_PRINT("info", ("archive flushing out rows for scan"));
-        gzflush(share->archive_write, Z_SYNC_FLUSH);
+        DBUG_PRINT("ha_archive", ("archive flushing out rows for scan"));
+        azflush(&(share->archive_write), Z_SYNC_FLUSH);
         share->dirty= FALSE;
       }
       pthread_mutex_unlock(&share->mutex);
     }
 
-    if (read_data_header(archive))
+    if (read_data_header(&archive))
       DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
   }
 
@@ -817,25 +1015,133 @@
   This is the method that is used to read a row. It assumes that the row is 
   positioned where you want it.
 */
-int ha_archive::get_row(gzFile file_to_read, byte *buf)
+int ha_archive::get_row(azio_stream *file_to_read, byte *buf)
 {
-  int read; // Bytes read, gzread() returns int
-  uint *ptr, *end;
-  char *last;
-  size_t total_blob_length= 0;
+  int rc;
   DBUG_ENTER("ha_archive::get_row");
+  DBUG_PRINT("ha_archive", ("Picking version for get_row() %d -> %d", 
+                            (uchar)file_to_read->version, 
+                            ARCHIVE_VERSION));
+  if (file_to_read->version == ARCHIVE_VERSION)
+    rc= get_row_version3(file_to_read, buf);
+  else
+    rc= get_row_version2(file_to_read, buf);
+
+  DBUG_PRINT("ha_archive", ("Return %d\n", rc));
+
+  DBUG_RETURN(rc);
+}
+
+/* Reallocate buffer if needed */
+bool ha_archive::fix_rec_buff(unsigned int length)
+{
+  DBUG_ENTER("ha_archive::fix_rec_buff");
+  DBUG_PRINT("ha_archive", ("Fixing %u for %u", 
+                            length, record_buffer->length));
+  DBUG_ASSERT(record_buffer->buffer);
+
+  if (length > record_buffer->length)
+  {
+    byte *newptr;
+    if (!(newptr=(byte*) my_realloc((gptr) record_buffer->buffer, 
+                                    length,
+				    MYF(MY_ALLOW_ZERO_PTR))))
+      DBUG_RETURN(1);
+    record_buffer->buffer= newptr;
+    record_buffer->length= length;
+  }
+
+  DBUG_ASSERT(length <= record_buffer->length);
+
+  DBUG_RETURN(0);
+}
 
-  read= gzread(file_to_read, buf, table->s->reclength);
-  DBUG_PRINT("ha_archive::get_row", ("Read %d bytes expected %lu", (int) read,
-                                     table->s->reclength));
+int ha_archive::unpack_row(azio_stream *file_to_read, byte *record)
+{
+  DBUG_ENTER("ha_archive::unpack_row");
+
+  unsigned int read;
+  int error;
+  byte size_buffer[ARCHIVE_ROW_HEADER_SIZE];
+  unsigned int row_len;
+
+  /* First we grab the length stored */
+  read= azread(file_to_read, (byte *)size_buffer, ARCHIVE_ROW_HEADER_SIZE, &error);
 
-  if (read == Z_STREAM_ERROR)
+  if (error == Z_STREAM_ERROR ||  (read && read < ARCHIVE_ROW_HEADER_SIZE))
     DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
 
   /* If we read nothing we are at the end of the file */
+  if (read == 0 || read != ARCHIVE_ROW_HEADER_SIZE)
+    DBUG_RETURN(HA_ERR_END_OF_FILE);
+
+  row_len=  uint4korr(size_buffer);
+  DBUG_PRINT("ha_archive",("Unpack row length %u -> %u", row_len, 
+                           (unsigned int)table->s->reclength));
+  fix_rec_buff(row_len);
+  DBUG_ASSERT(row_len <= record_buffer->length);
+
+  read= azread(file_to_read, record_buffer->buffer, row_len, &error);
+
+  DBUG_ASSERT(row_len == read);
+
+  if (read != row_len || error)
+  {
+    DBUG_RETURN(-1);
+  }
+
+  /* Copy null bits */
+  const char *ptr= (const char*) record_buffer->buffer;
+  memcpy(record, ptr, table->s->null_bytes);
+  ptr+= table->s->null_bytes;
+  for (Field **field=table->field ; *field ; field++)
+    if (!((*field)->is_null()))
+    {
+      ptr= (*field)->unpack((char *)record + 
+                            (*field)->offset(table->record[0]), ptr);
+    }
+
+  DBUG_RETURN(0);
+}
+
+
+int ha_archive::get_row_version3(azio_stream *file_to_read, byte *buf)
+{
+  DBUG_ENTER("ha_archive::get_row_version3");
+
+  int returnable= unpack_row(file_to_read, buf);
+
+  DBUG_RETURN(returnable);
+}
+
+
+int ha_archive::get_row_version2(azio_stream *file_to_read, byte *buf)
+{
+  unsigned int read;
+  int error;
+  uint *ptr, *end;
+  char *last;
+  size_t total_blob_length= 0;
+  MY_BITMAP *read_set= table->read_set;
+  DBUG_ENTER("ha_archive::get_row_version2");
+
+  read= azread(file_to_read, (voidp)buf, table->s->reclength, &error);
+
+  /* If we read nothing we are at the end of the file */
   if (read == 0)
     DBUG_RETURN(HA_ERR_END_OF_FILE);
 
+  if (read != table->s->reclength)
+  {
+    DBUG_PRINT("ha_archive::get_row_version2", ("Read %u bytes expected %u", 
+                                                read, 
+                                                (unsigned
int)table->s->reclength));
+    DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+  }
+
+  if (error == Z_STREAM_ERROR || error == Z_DATA_ERROR )
+    DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+
   /* 
     If the record is the wrong size, the file is probably damaged, unless 
     we are dealing with a delayed insert or a bulk insert.
@@ -847,7 +1153,11 @@
   for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
        ptr != end ;
        ptr++)
-    total_blob_length += ((Field_blob*) table->field[*ptr])->get_length();
+  {
+    if (bitmap_is_set(read_set,
+                      (((Field_blob*) table->field[*ptr])->field_index)))
+        total_blob_length += ((Field_blob*) table->field[*ptr])->get_length();
+  }
 
   /* Adjust our row buffer if we need be */
   buffer.alloc(total_blob_length);
@@ -861,11 +1171,23 @@
     size_t size= ((Field_blob*) table->field[*ptr])->get_length();
     if (size)
     {
-      read= gzread(file_to_read, last, size);
-      if ((size_t) read != size)
-        DBUG_RETURN(HA_ERR_END_OF_FILE);
-      ((Field_blob*) table->field[*ptr])->set_ptr(size, last);
-      last += size;
+      if (bitmap_is_set(read_set,
+                        ((Field_blob*) table->field[*ptr])->field_index))
+      {
+        read= azread(file_to_read, last, size, &error);
+
+        if (error)
+          DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+
+        if ((size_t) read != size)
+          DBUG_RETURN(HA_ERR_END_OF_FILE);
+        ((Field_blob*) table->field[*ptr])->set_ptr(size, last);
+        last += size;
+      }
+      else
+      {
+        (void)azseek(file_to_read, size, SEEK_CUR);
+      }
     }
   }
   DBUG_RETURN(0);
@@ -889,14 +1211,13 @@
     DBUG_RETURN(HA_ERR_END_OF_FILE);
   scan_rows--;
 
-  statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
-		      &LOCK_status);
-  current_position= gztell(archive);
-  rc= get_row(archive, buf);
+  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
+  current_position= aztell(&archive);
+  rc= get_row(&archive, buf);
 
 
   if (rc != HA_ERR_END_OF_FILE)
-    records++;
+    stats.records++;
 
   DBUG_RETURN(rc);
 }
@@ -926,12 +1247,11 @@
 int ha_archive::rnd_pos(byte * buf, byte *pos)
 {
   DBUG_ENTER("ha_archive::rnd_pos");
-  statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
-		      &LOCK_status);
-  current_position= (z_off_t)my_get_ptr(pos, ref_length);
-  (void)gzseek(archive, current_position, SEEK_SET);
+  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
+  current_position= (my_off_t)my_get_ptr(pos, ref_length);
+  (void)azseek(&archive, current_position, SEEK_SET);
 
-  DBUG_RETURN(get_row(archive, buf));
+  DBUG_RETURN(get_row(&archive, buf));
 }
 
 /*
@@ -959,55 +1279,40 @@
 int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
 {
   DBUG_ENTER("ha_archive::optimize");
-  int rc;
-  gzFile writer;
+  int rc= 0;
+  azio_stream writer;
   char writer_filename[FN_REFLEN];
 
-  /* Open up the writer if we haven't yet */
-  if (!share->archive_write_open)
-    init_archive_writer();
-
-  /* Flush any waiting data */
-  gzflush(share->archive_write, Z_SYNC_FLUSH);
+  // now we close both our writer and our reader for the rename
+  if (share->archive_write_open)
+  {
+    azclose(&(share->archive_write));
+    share->archive_write_open= FALSE;
+  }
 
   /* Lets create a file to contain the new data */
   fn_format(writer_filename, share->table_name, "", ARN, 
-            MY_REPLACE_EXT|MY_UNPACK_FILENAME);
+            MY_REPLACE_EXT | MY_UNPACK_FILENAME);
 
-  if ((writer= gzopen(writer_filename, "wb")) == NULL)
+  if (!(azopen(&writer, writer_filename, O_CREAT|O_RDWR|O_BINARY)))
     DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); 
 
   /* 
     An extended rebuild is a lot more effort. We open up each row and re-record it. 
     Any dead rows are removed (aka rows that may have been partially recorded). 
-  */
 
-  if (check_opt->flags == T_EXTEND)
+    As of Archive format 3, this is the only type that is performed, before this
+    version it was just done on T_EXTEND
+  */
+  if (1)
   {
-    byte *buf; 
-
-    /* 
-      First we create a buffer that we can use for reading rows, and can pass
-      to get_row().
-    */
-    if (!(buf= (byte*) my_malloc(table->s->reclength, MYF(MY_WME))))
-    {
-      rc= HA_ERR_OUT_OF_MEM;
-      goto error;
-    }
+    DBUG_PRINT("ha_archive", ("archive extended rebuild"));
 
     /*
       Now we will rewind the archive file so that we are positioned at the 
       start of the file.
     */
-    rc= read_data_header(archive);
-    
-    /*
-      Assuming now error from rewinding the archive file, we now write out the 
-      new header for out data file.
-    */
-    if (!rc)
-      rc= write_data_header(writer);
+    rc= read_data_header(&archive);
 
     /* 
       On success of writing out the new header, we now fetch each row and
@@ -1016,58 +1321,55 @@
     if (!rc)
     {
       share->rows_recorded= 0;
-      while (!(rc= get_row(archive, buf)))
+      stats.auto_increment_value= share->archive_write.auto_increment= 0;
+      my_bitmap_map *org_bitmap= dbug_tmp_use_all_columns(table, table->read_set);
+
+      while (!(rc= get_row(&archive, table->record[0])))
       {
-        real_write_row(buf, writer);
-        share->rows_recorded++;
+        real_write_row(table->record[0], &writer);
+        /*
+          Long term it should be possible to optimize this so that
+          it is not called on each row.
+        */
+        if (table->found_next_number_field)
+        {
+          Field *field= table->found_next_number_field;
+          ulonglong auto_value=
+            (ulonglong) field->val_int((char*)(table->record[0] +
+                                               field->offset(table->record[0])));
+          if (share->archive_write.auto_increment < auto_value)
+            stats.auto_increment_value= share->archive_write.auto_increment=
+              auto_value;
+        }
       }
+
+      dbug_tmp_restore_column_map(table->read_set, org_bitmap);
+      share->rows_recorded= (ha_rows)writer.rows;
     }
-    DBUG_PRINT("info", ("recovered %lu archive rows",
-                        (ulong) share->rows_recorded));
 
-    my_free((char*)buf, MYF(0));
+    DBUG_PRINT("info", ("recovered %llu archive rows", 
+                        (unsigned long long)share->rows_recorded));
+
+    DBUG_PRINT("ha_archive", ("recovered %llu archive rows", 
+                        (unsigned long long)share->rows_recorded));
+
     if (rc && rc != HA_ERR_END_OF_FILE)
       goto error;
   } 
-  else
-  {
-    /* 
-      The quick method is to just read the data raw, and then compress it directly.
-    */
-    int read; // Bytes read, gzread() returns int
-    char block[IO_SIZE];
-    if (gzrewind(archive) == -1)
-    {
-      rc= HA_ERR_CRASHED_ON_USAGE;
-      goto error;
-    }
 
-    while ((read= gzread(archive, block, IO_SIZE)))
-      gzwrite(writer, block, read);
-  }
-
-  gzflush(writer, Z_SYNC_FLUSH);
+  azclose(&writer);
   share->dirty= FALSE;
-  gzclose(share->archive_write);
-  share->archive_write= writer; 
-
-  my_rename(writer_filename,share->data_file_name,MYF(0));
-
-  /*
-    Now we need to reopen our read descriptor since it has changed.
-  */
-  gzclose(archive);
-  if ((archive= gzopen(share->data_file_name, "rb")) == NULL)
-  {
-    rc= HA_ERR_CRASHED_ON_USAGE;
-    goto error;
-  }
+  
+  azclose(&archive);
 
+  // make the file we just wrote be our data file
+  rc = my_rename(writer_filename,share->data_file_name,MYF(0));
 
-  DBUG_RETURN(0); 
 
+  DBUG_RETURN(rc);
 error:
-  gzclose(writer);
+  DBUG_PRINT("ha_archive", ("Failed to recover, error was %d", rc));
+  azclose(&writer);
 
   DBUG_RETURN(rc); 
 }
@@ -1094,8 +1396,8 @@
     */
 
     if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
-         lock_type <= TL_WRITE) && !thd->in_lock_tables
-        && !thd->tablespace_op)
+         lock_type <= TL_WRITE) && !thd_in_lock_tables(thd)
+        && !thd_tablespace_op(thd))
       lock_type = TL_WRITE_ALLOW_WRITE;
 
     /* 
@@ -1106,7 +1408,7 @@
       concurrent inserts to t2. 
     */
 
-    if (lock_type == TL_READ_NO_INSERT && !thd->in_lock_tables) 
+    if (lock_type == TL_READ_NO_INSERT && !thd_in_lock_tables(thd)) 
       lock_type = TL_READ;
 
     lock.type=lock_type;
@@ -1117,6 +1419,31 @@
   return to;
 }
 
+void ha_archive::update_create_info(HA_CREATE_INFO *create_info)
+{
+  DBUG_ENTER("ha_archive::update_create_info");
+
+  ha_archive::info(HA_STATUS_AUTO);
+  if (create_info->used_fields & HA_CREATE_USED_AUTO)
+  {
+    /* 
+      Internally Archive keeps track of last used, not next used.
+      To make the output look like MyISAM we add 1 here.
+
+      This is not completely compatible with MYISAM though, since
+      MyISAM will record on "SHOW CREATE TABLE" the last position,
+      where we will report the original position the table was
+      created with.
+    */
+    create_info->auto_increment_value= stats.auto_increment_value + 1;
+  }
+
+  if (!(my_readlink(share->real_path, share->data_file_name, MYF(0))))
+    create_info->data_file_name= share->real_path;
+
+  DBUG_VOID_RETURN;
+}
+
 
 /*
   Hints for optimizer, see ha_tina for more information
@@ -1128,8 +1455,8 @@
     This should be an accurate number now, though bulk and delayed inserts can
     cause the number to be inaccurate.
   */
-  records= share->rows_recorded;
-  deleted= 0;
+  stats.records= share->rows_recorded;
+  stats.deleted= 0;
   /* Costs quite a bit more to get all information */
   if (flag & HA_STATUS_TIME)
   {
@@ -1137,14 +1464,20 @@
 
     VOID(my_stat(share->data_file_name, &file_stat, MYF(MY_WME)));
 
-    mean_rec_length= table->s->reclength + buffer.alloced_length();
-    data_file_length= file_stat.st_size;
-    create_time= file_stat.st_ctime;
-    update_time= file_stat.st_mtime;
-    max_data_file_length= share->rows_recorded * mean_rec_length;
+    stats.mean_rec_length= table->s->reclength + buffer.alloced_length();
+    stats.data_file_length= file_stat.st_size;
+    stats.create_time= file_stat.st_ctime;
+    stats.update_time= file_stat.st_mtime;
+    stats.max_data_file_length= share->rows_recorded * stats.mean_rec_length;
+  }
+  stats.delete_length= 0;
+  stats.index_file_length=0;
+
+  if (flag & HA_STATUS_AUTO)
+  {
+    azflush(&archive, Z_SYNC_FLUSH);
+    stats.auto_increment_value= archive.auto_increment;
   }
-  delete_length= 0;
-  index_file_length=0;
 
   DBUG_RETURN(0);
 }
@@ -1205,13 +1538,13 @@
 {
   int rc= 0;
   byte *buf; 
-  const char *old_proc_info=thd->proc_info;
+  const char *old_proc_info;
   ha_rows count= share->rows_recorded;
   DBUG_ENTER("ha_archive::check");
 
-  thd->proc_info= "Checking table";
+  old_proc_info= thd_proc_info(thd, "Checking table");
   /* Flush any waiting data */
-  gzflush(share->archive_write, Z_SYNC_FLUSH);
+  azflush(&(share->archive_write), Z_SYNC_FLUSH);
 
   /* 
     First we create a buffer that we can use for reading rows, and can pass
@@ -1225,15 +1558,15 @@
     start of the file.
   */
   if (!rc)
-    read_data_header(archive);
+    read_data_header(&archive);
 
   if (!rc)
-    while (!(rc= get_row(archive, buf)))
+    while (!(rc= get_row(&archive, buf)))
       count--;
 
   my_free((char*)buf, MYF(0));
 
-  thd->proc_info= old_proc_info;
+  thd_proc_info(thd, old_proc_info);
 
   if ((rc && rc != HA_ERR_END_OF_FILE) || count)  
   {
@@ -1258,4 +1591,54 @@
 
   DBUG_RETURN(repair(thd, &check_opt));
 }
-#endif /* HAVE_ARCHIVE_DB */
+
+archive_record_buffer *ha_archive::create_record_buffer(unsigned int length) 
+{
+  DBUG_ENTER("ha_archive::create_record_buffer");
+  archive_record_buffer *r;
+  if (!(r= 
+        (archive_record_buffer*) my_malloc(sizeof(archive_record_buffer),
+                                           MYF(MY_WME))))
+  {
+    DBUG_RETURN(NULL); /* purecov: inspected */
+  }
+  r->length= (int)length;
+
+  if (!(r->buffer= (byte*) my_malloc(r->length,
+                                    MYF(MY_WME))))
+  {
+    my_free((char*) r, MYF(MY_ALLOW_ZERO_PTR));
+    DBUG_RETURN(NULL); /* purecov: inspected */
+  }
+
+  DBUG_RETURN(r);
+}
+
+void ha_archive::destroy_record_buffer(archive_record_buffer *r) 
+{
+  DBUG_ENTER("ha_archive::destroy_record_buffer");
+  my_free((char*) r->buffer, MYF(MY_ALLOW_ZERO_PTR));
+  my_free((char*) r, MYF(MY_ALLOW_ZERO_PTR));
+  DBUG_VOID_RETURN;
+}
+
+struct st_mysql_storage_engine archive_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION };
+
+mysql_declare_plugin(archive)
+{
+  MYSQL_STORAGE_ENGINE_PLUGIN,
+  &archive_storage_engine,
+  "ARCHIVE",
+  "Brian Aker, MySQL AB",
+  "Archive storage engine",
+  PLUGIN_LICENSE_GPL,
+  archive_db_init, /* Plugin Init */
+  archive_db_done, /* Plugin Deinit */
+  0x0300 /* 3.0 */,
+  NULL,                       /* status variables                */
+  NULL,                       /* system variables                */
+  NULL                        /* config options                  */
+}
+mysql_declare_plugin_end;
+

--- 1.28/mysql-test/r/mysqlbinlog.result	2007-03-02 00:10:26 +02:00
+++ 1.29/mysql-test/r/mysqlbinlog.result	2007-03-02 00:10:26 +02:00
@@ -274,3 +274,60 @@
 1
 drop procedure p1;
 flush logs;
+create table t1 (a varchar(64) character set utf8);
+load data infile '../std_data_ln/loaddata6.dat' into table t1;
+set character_set_database=koi8r;
+load data infile '../std_data_ln/loaddata6.dat' into table t1;
+set character_set_database=latin1;
+load data infile '../std_data_ln/loaddata6.dat' into table t1;
+load data infile '../std_data_ln/loaddata6.dat' into table t1;
+set character_set_database=koi8r;
+load data infile '../std_data_ln/loaddata6.dat' into table t1;
+set character_set_database=latin1;
+load data infile '../std_data_ln/loaddata6.dat' into table t1;
+load data infile '../std_data_ln/loaddata6.dat' into table t1 character set koi8r;
+select hex(a) from t1;
+hex(a)
+C3BF
+D0AA
+C3BF
+C3BF
+D0AA
+C3BF
+D0AA
+drop table t1;
+flush logs;
+/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+DELIMITER /*!*/;
+use test/*!*/;
+SET TIMESTAMP=1000000000/*!*/;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1,
@@session.unique_checks=1/*!*/;
+SET @@session.sql_mode=0/*!*/;
+/*!\C latin1 *//*!*/;
+SET
@@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/;
+create table t1 (a varchar(64) character set utf8)/*!*/;
+SET TIMESTAMP=1000000000/*!*/;
+load data LOCAL INFILE 'MYSQL_TMP_DIR/SQL_LOAD_MB-6-0' INTO table t1/*!*/;
+SET TIMESTAMP=1000000000/*!*/;
+SET @@session.collation_database=7/*!*/;
+load data LOCAL INFILE 'MYSQL_TMP_DIR/SQL_LOAD_MB-7-0' INTO table t1/*!*/;
+SET TIMESTAMP=1000000000/*!*/;
+SET @@session.collation_database=DEFAULT/*!*/;
+load data LOCAL INFILE 'MYSQL_TMP_DIR/SQL_LOAD_MB-8-0' INTO table t1/*!*/;
+SET TIMESTAMP=1000000000/*!*/;
+load data LOCAL INFILE 'MYSQL_TMP_DIR/SQL_LOAD_MB-9-0' INTO table t1/*!*/;
+SET TIMESTAMP=1000000000/*!*/;
+SET @@session.collation_database=7/*!*/;
+load data LOCAL INFILE 'MYSQL_TMP_DIR/SQL_LOAD_MB-a-0' INTO table t1/*!*/;
+SET TIMESTAMP=1000000000/*!*/;
+SET @@session.collation_database=DEFAULT/*!*/;
+load data LOCAL INFILE 'MYSQL_TMP_DIR/SQL_LOAD_MB-b-0' INTO table t1/*!*/;
+SET TIMESTAMP=1000000000/*!*/;
+load data LOCAL INFILE 'MYSQL_TMP_DIR/SQL_LOAD_MB-c-0' INTO table t1 character set
koi8r/*!*/;
+SET TIMESTAMP=1000000000/*!*/;
+drop table t1/*!*/;
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;

--- 1.35/mysql-test/t/mysqlbinlog.test	2007-03-02 00:10:26 +02:00
+++ 1.36/mysql-test/t/mysqlbinlog.test	2007-03-02 00:10:26 +02:00
@@ -193,6 +193,30 @@
 --exec $MYSQL_BINLOG --help 2>&1 > /dev/null
 --enable_query_log
 
+#
+# Bug#15126 character_set_database is not replicated
+# (LOAD DATA INFILE need it)
+#
+
+flush logs;
+create table t1 (a varchar(64) character set utf8);
+load data infile '../std_data_ln/loaddata6.dat' into table t1;
+set character_set_database=koi8r;
+load data infile '../std_data_ln/loaddata6.dat' into table t1;
+set character_set_database=latin1;
+load data infile '../std_data_ln/loaddata6.dat' into table t1;
+load data infile '../std_data_ln/loaddata6.dat' into table t1;
+set character_set_database=koi8r;
+load data infile '../std_data_ln/loaddata6.dat' into table t1;
+set character_set_database=latin1;
+load data infile '../std_data_ln/loaddata6.dat' into table t1;
+load data infile '../std_data_ln/loaddata6.dat' into table t1 character set koi8r;
+select hex(a) from t1;
+drop table t1;
+flush logs;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+--exec $MYSQL_BINLOG --short-form $MYSQLTEST_VARDIR/log/master-bin.000011
+
 # End of 5.0 tests
 
 #

--- 1.83/sql/sql_trigger.cc	2007-03-02 00:10:26 +02:00
+++ 1.84/sql/sql_trigger.cc	2007-03-02 00:10:26 +02:00
@@ -106,10 +106,6 @@
 };
 
 
-static int
-add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
-                      TABLE_LIST ** table);
-
 class Handle_old_incorrect_sql_modes_hook: public Unknown_key_hook
 {
 private:
@@ -1180,7 +1176,7 @@
     1 Error
 */
 
-static int
+int
 add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
                       TABLE_LIST **table)
 {

--- 1.26/sql/sql_trigger.h	2007-03-02 00:10:26 +02:00
+++ 1.27/sql/sql_trigger.h	2007-03-02 00:10:26 +02:00
@@ -137,3 +137,7 @@
 
 extern const LEX_STRING trg_action_time_type_names[];
 extern const LEX_STRING trg_event_type_names[];
+
+int
+add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
+                      TABLE_LIST **table);

--- 1.19/mysql-test/r/rpl_user_variables.result	2007-03-02 00:10:26 +02:00
+++ 1.20/mysql-test/r/rpl_user_variables.result	2007-03-02 00:10:26 +02:00
@@ -80,4 +80,180 @@
 This is a test
 insert into t1 select * FROM (select @var1 union  select @var2) AS t2;
 drop table t1;
+End of 4.1 tests.
+DROP TABLE IF EXISTS t20;
+DROP TABLE IF EXISTS t21;
+DROP PROCEDURE IF EXISTS test.insert;
+CREATE TABLE t20 (a VARCHAR(20));
+CREATE TABLE t21 (a VARCHAR(20));
+CREATE PROCEDURE test.insert()
+BEGIN
+IF (@VAR)
+THEN
+INSERT INTO test.t20 VALUES ('SP_TRUE');
+ELSE
+INSERT INTO test.t20 VALUES ('SP_FALSE');
+END IF;
+END|
+CREATE TRIGGER test.insert_bi BEFORE INSERT
+ON test.t20 FOR EACH ROW
+BEGIN
+IF (@VAR)
+THEN
+INSERT INTO test.t21 VALUES ('TRIG_TRUE');
+ELSE
+INSERT INTO test.t21 VALUES ('TRIG_FALSE');
+END IF;
+END|
+SET @VAR=0;
+CALL test.insert();
+SET @VAR=1;
+CALL test.insert();
+On master: Check the tables for correct data
+SELECT * FROM t20;
+a
+SP_FALSE
+SP_TRUE
+SELECT * FROM t21;
+a
+TRIG_FALSE
+TRIG_TRUE
+On slave: Check the tables for correct data and it matches master
+SELECT * FROM t20;
+a
+SP_FALSE
+SP_TRUE
+SELECT * FROM t21;
+a
+TRIG_FALSE
+TRIG_TRUE
+DROP TABLE t20;
+DROP TABLE t21;
+DROP PROCEDURE test.insert;
+DROP TABLE IF EXISTS t1;
+DROP FUNCTION IF EXISTS test.square;
+CREATE TABLE t1 (i INT);
+CREATE FUNCTION test.square() RETURNS INTEGER DETERMINISTIC RETURN (@var * @var);
+SET @var = 1;
+INSERT INTO t1 VALUES (square());
+SET @var = 2;
+INSERT INTO t1 VALUES (square());
+SET @var = 3;
+INSERT INTO t1 VALUES (square());
+SET @var = 4;
+INSERT INTO t1 VALUES (square());
+SET @var = 5;
+INSERT INTO t1 VALUES (square());
+On master: Retrieve the values from the table
+SELECT * FROM t1;
+i
+1
+4
+9
+16
+25
+On slave: Retrieve the values from the table and verify they are the same as on master
+SELECT * FROM t1;
+i
+1
+4
+9
+16
+25
+DROP TABLE t1;
+DROP FUNCTION test.square;
+DROP TABLE IF EXISTS t1;
+DROP FUNCTION IF EXISTS f1;
+DROP FUNCTION IF EXISTS f2;
+CREATE TABLE t1(a int);
+CREATE FUNCTION f1() returns int deterministic
+BEGIN
+return @a;
+END |
+CREATE FUNCTION f2() returns int deterministic
+BEGIN
+IF (@b > 0) then
+SET @c = (@a + @b);
+else
+SET @c = (@a - 1);
+END if;
+return @c;
+END |
+SET @a=500;
+INSERT INTO t1 values(f1());
+SET @b = 125;
+SET @c = 1;
+INSERT INTO t1 values(f2());
+On master: Retrieve the values from the table
+SELECT * from t1;
+a
+500
+625
+On slave: Check the tables for correct data and it matches master
+SELECT * from t1;
+a
+500
+625
+DROP TABLE t1;
+DROP FUNCTION f1;
+DROP FUNCTION f2;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+CREATE TABLE t1 (i int);
+CREATE TABLE t2 (k int);
+CREATE trigger t1_bi before INSERT on t1 for each row
+BEGIN
+INSERT INTO t2 values (@a);
+SET @a:=42;
+INSERT INTO t2 values (@a);
+END |
+SET @a:=100;
+INSERT INTO t1 values (5);
+On master: Check to see that data was inserted correctly in both tables
+SELECT * from t1;
+i
+5
+SELECT * from t2;
+k
+100
+42
+On slave: Check the tables for correct data and it matches master
+SELECT * from t1;
+i
+5
+SELECT * from t2;
+k
+100
+42
+End of 5.0 tests.
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE IF EXISTS t1;
+DROP FUNCTION IF EXISTS f1;
+DROP FUNCTION IF EXISTS f2;
+CREATE TABLE t1 (i INT);
+CREATE FUNCTION f1() RETURNS INT RETURN @a;
+CREATE FUNCTION f2() RETURNS INT
+BEGIN
+INSERT INTO t1 VALUES (10 + @a);
+RETURN 0;
+END|
+SET @a:=123;
+SELECT f1(), f2();
+f1()	f2()
+123	0
+On master: Check to see that data was inserted correctly 
+INSERT INTO t1 VALUES(f1());
+SELECT * FROM t1;
+i
+133
+123
+On slave: Check the table for correct data and it matches master
+SELECT * FROM t1;
+i
+133
+123
+DROP FUNCTION f1;
+DROP FUNCTION f2;
+DROP TABLE t1;
 stop slave;

--- 1.18/mysql-test/t/rpl_user_variables.test	2007-03-02 00:10:26 +02:00
+++ 1.19/mysql-test/t/rpl_user_variables.test	2007-03-02 00:10:26 +02:00
@@ -54,4 +54,305 @@
 insert into t1 select * FROM (select @var1 union  select @var2) AS t2;
 drop table t1;
 sync_slave_with_master;
+save_master_pos;
+--echo End of 4.1 tests.
+
+# BUG#20141
+# The following tests ensure that if user-defined variables are used in SF/Triggers
+# that they are replicated correctly. These tests should be run in both SBR and RBR
+# modes.
+
+# This test uses a procedure that inserts data values based on the value of a 
+# user-defined variable. It also has a trigger that inserts data based on the
+# same variable. Successful test runs show that the @var is replicated 
+# properly and that the procedure and trigger insert the correct data on the
+# slave.
+#
+# The test of stored procedure was included for completeness. Replication of stored
+# procedures was not directly affected by BUG#20141.
+#
+# This test was constructed for BUG#20141
+
+--disable_warnings
+DROP TABLE IF EXISTS t20;
+DROP TABLE IF EXISTS t21;
+DROP PROCEDURE IF EXISTS test.insert;
+--enable_warnings
+
+CREATE TABLE t20 (a VARCHAR(20));
+CREATE TABLE t21 (a VARCHAR(20));
+DELIMITER |;
+
+# Create a procedure that uses the @var for flow control
+
+CREATE PROCEDURE test.insert()
+BEGIN
+  IF (@VAR)
+  THEN
+      INSERT INTO test.t20 VALUES ('SP_TRUE');
+  ELSE
+      INSERT INTO test.t20 VALUES ('SP_FALSE');
+  END IF;
+END|
+
+# Create a trigger that uses the @var for flow control
+
+CREATE TRIGGER test.insert_bi BEFORE INSERT
+    ON test.t20 FOR EACH ROW
+    BEGIN
+      IF (@VAR)
+      THEN
+        INSERT INTO test.t21 VALUES ('TRIG_TRUE');
+      ELSE
+        INSERT INTO test.t21 VALUES ('TRIG_FALSE');
+      END IF;
+    END|
+DELIMITER ;|
+
+sync_slave_with_master;
+connection master;
+
+# Set @var and call the procedure, repeat with different values
+
+SET @VAR=0;
+CALL test.insert();
+SET @VAR=1;
+CALL test.insert();
+
+--echo On master: Check the tables for correct data
+
+SELECT * FROM t20;
+SELECT * FROM t21;
+
+sync_slave_with_master;
+
+--echo On slave: Check the tables for correct data and it matches master
+
+SELECT * FROM t20;
+SELECT * FROM t21;
+connection master;
+
+# Cleanup
+
+DROP TABLE t20;
+DROP TABLE t21;
+DROP PROCEDURE test.insert;
+
+# This test uses a stored function that uses user-defined variables to return data
+# This test was constructed for BUG#20141
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP FUNCTION IF EXISTS test.square;
+--enable_warnings
+
+CREATE TABLE t1 (i INT);
+
+# Create function that returns a value from @var. In this case, the square function
+
+CREATE FUNCTION test.square() RETURNS INTEGER DETERMINISTIC RETURN (@var * @var);
+
+sync_slave_with_master;
+connection master;
+
+# Set the @var to different values and insert them into a table
+
+SET @var = 1;
+INSERT INTO t1 VALUES (square());
+SET @var = 2;
+INSERT INTO t1 VALUES (square());
+SET @var = 3;
+INSERT INTO t1 VALUES (square());
+SET @var = 4;
+INSERT INTO t1 VALUES (square());
+SET @var = 5;
+INSERT INTO t1 VALUES (square());
+
+--echo On master: Retrieve the values from the table
+
+SELECT * FROM t1;
+
+sync_slave_with_master;
+
+--echo On slave: Retrieve the values from the table and verify they are the same as on
master
+
+SELECT * FROM t1;
+
+connection master;
+
+# Cleanup
+
+DROP TABLE t1;
+DROP FUNCTION test.square;
+
+# This test uses stored functions that uses user-defined variables to return data
+# based on the use of @vars inside a function body.
+# This test was constructed for BUG#14914
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP FUNCTION IF EXISTS f1;
+DROP FUNCTION IF EXISTS f2;
+--enable_warnings
+
+CREATE TABLE t1(a int);
+DELIMITER |;
+
+# Create a function that simply returns the value of an @var.
+# Create a function that uses an @var for flow control, creates and uses another
+# @var and sets its value to a value based on another @var.
+
+CREATE FUNCTION f1() returns int deterministic
+BEGIN
+  return @a;
+END |
+
+CREATE FUNCTION f2() returns int deterministic
+BEGIN
+  IF (@b > 0) then
+    SET @c = (@a + @b);
+  else
+    SET @c = (@a - 1);
+  END if;
+  return @c;
+END |
+DELIMITER ;|
+
+sync_slave_with_master;
+connection master;
+
+# Set an @var to a value and insert data into a table using the first function.
+# Set two more @vars to some values and insert data into a table using the second
function.
+
+SET @a=500;
+INSERT INTO t1 values(f1());
+SET @b = 125;
+SET @c = 1;
+INSERT INTO t1 values(f2());
+
+sync_slave_with_master;
+
+--echo On master: Retrieve the values from the table
+
+SELECT * from t1;
+
+--echo On slave: Check the tables for correct data and it matches master
+
+SELECT * from t1;
+
+connection master;
+
+# Cleanup
+
+DROP TABLE t1;
+DROP FUNCTION f1;
+DROP FUNCTION f2;
+
+# This test uses a function that changes a user-defined variable in its body. This test
+# will ensure the @vars are replicated when needed and not interrupt the normal execution
+# of the function on the slave. This also applies to triggers.
+#
+# This test was constructed for BUG#25167
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+--enable_warnings
+CREATE TABLE t1 (i int);
+CREATE TABLE t2 (k int);
+DELIMITER |;
+
+# Create a trigger that inserts data into another table, changes the @var then inserts 
+# another row with the modified value.
+
+CREATE trigger t1_bi before INSERT on t1 for each row
+BEGIN
+  INSERT INTO t2 values (@a);
+  SET @a:=42;
+  INSERT INTO t2 values (@a);
+END |
+DELIMITER ;|
+
+sync_slave_with_master;
+connection master;
+
+# Set the @var to a value then insert data into first table.
+
+SET @a:=100;
+INSERT INTO t1 values (5);
+
+--echo On master: Check to see that data was inserted correctly in both tables
+
+SELECT * from t1;
+SELECT * from t2;
+
+sync_slave_with_master;
+
+--echo On slave: Check the tables for correct data and it matches master
+
+SELECT * from t1;
+SELECT * from t2;
+
+connection master;
+
+--echo End of 5.0 tests.
+
+# Cleanup
+
+DROP TABLE t1;
+DROP TABLE t2;
+
+# This test uses a stored function that uses user-defined variables to return data
+# The test ensures the value of the user-defined variable is replicated correctly
+# and in the correct order of assignment.
+# This test was constructed for BUG#20141
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP FUNCTION IF EXISTS f1;
+DROP FUNCTION IF EXISTS f2;
+--enable_warnings
+
+CREATE TABLE t1 (i INT);
+
+# Create two functions. One simply returns the user-defined variable. The other
+# returns a value based on the user-defined variable.
+
+CREATE FUNCTION f1() RETURNS INT RETURN @a;
+DELIMITER |;
+CREATE FUNCTION f2() RETURNS INT
+BEGIN
+  INSERT INTO t1 VALUES (10 + @a);
+  RETURN 0;
+END|
+DELIMITER ;|
+
+sync_slave_with_master;
+connection master;
+
+# Set the variable and execute the functions.
+
+SET @a:=123;
+SELECT f1(), f2();
+
+--echo On master: Check to see that data was inserted correctly 
+
+INSERT INTO t1 VALUES(f1());
+SELECT * FROM t1;
+
+sync_slave_with_master;
+
+--echo On slave: Check the table for correct data and it matches master
+
+SELECT * FROM t1;
+
+connection master;
+
+# Cleanup
+
+DROP FUNCTION f1;
+DROP FUNCTION f2;
+DROP TABLE t1;
+
+sync_slave_with_master;
 stop slave;

--- 1.2.4.1/mysql-test/r/ctype_cp932_binlog.result	2007-03-02 00:10:26 +02:00
+++ 1.11/mysql-test/r/binlog_stm_ctype_ucs.result	2007-03-02 00:10:26 +02:00
@@ -1,46 +1,27 @@
-drop table if exists t1;
-set names cp932;
-set character_set_database = cp932;
-RESET MASTER;
-CREATE TABLE t1(f1 blob);
-PREPARE stmt1 FROM 'INSERT INTO t1 VALUES(?)';
-SET @var1= x'8300';
-EXECUTE stmt1 USING @var1;
-SHOW BINLOG EVENTS FROM 98;
+SET TIMESTAMP=10000;
+create table t2 (c char(30)) charset=ucs2;
+set @v=convert('abc' using ucs2);
+reset master;
+insert into t2 values (@v);
+show binlog events from 102;
 Log_name	Pos	Event_type	Server_id	End_log_pos	Info
-master-bin.000001	98	Query	1	188	use `test`; CREATE TABLE t1(f1 blob)
-master-bin.000001	188	User var	1	227	@`var1`=_binary 0x8300 COLLATE binary
-master-bin.000001	227	Query	1	323	use `test`; INSERT INTO t1 VALUES(@'var1')
-SELECT HEX(f1) FROM t1;
-HEX(f1)
-8300
-DROP table t1;
-CREATE TABLE t4 (s1 CHAR(50) CHARACTER SET latin1,
-s2 CHAR(50) CHARACTER SET cp932,
-d DECIMAL(10,2))|
-CREATE PROCEDURE bug18293 (IN ins1 CHAR(50),
-IN ins2 CHAR(50) CHARACTER SET cp932,
-IN ind DECIMAL(10,2))
-BEGIN
-INSERT INTO t4 VALUES (ins1, ins2, ind);
-END|
-CALL bug18293("Foo's a Bar", _cp932 0xED40ED41ED42, 47.93)|
-SELECT HEX(s1),HEX(s2),d FROM t4|
-HEX(s1)	HEX(s2)	d
-466F6F2773206120426172	ED40ED41ED42	47.93
-DROP PROCEDURE bug18293|
-DROP TABLE t4|
-SHOW BINLOG EVENTS FROM 402|
-Log_name	Pos	Event_type	Server_id	End_log_pos	Info
-master-bin.000001	402	Query	1	568	use `test`; CREATE TABLE t4 (s1 CHAR(50) CHARACTER SET
latin1,
-s2 CHAR(50) CHARACTER SET cp932,
-d DECIMAL(10,2))
-master-bin.000001	568	Query	1	816	use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE
bug18293 (IN ins1 CHAR(50),
-IN ins2 CHAR(50) CHARACTER SET cp932,
-IN ind DECIMAL(10,2))
-BEGIN
-INSERT INTO t4 VALUES (ins1, ins2, ind);
-END
-master-bin.000001	816	Query	1	1035	use `test`; INSERT INTO t4 VALUES (
NAME_CONST('ins1',_latin1 0x466F6F2773206120426172),  NAME_CONST('ins2',_cp932
0xED40ED41ED42),  NAME_CONST('ind',47.93))
-master-bin.000001	1035	Query	1	1124	use `test`; DROP PROCEDURE bug18293
-master-bin.000001	1124	Query	1	1203	use `test`; DROP TABLE t4
+master-bin.000001	102	User var	1	142	@`v`=_ucs2 0x006100620063 COLLATE ucs2_general_ci
+master-bin.000001	142	Query	1	231	use `test`; insert into t2 values (@v)
+flush logs;
+/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+DELIMITER /*!*/;
+ROLLBACK/*!*/;
+SET @`v`:=_ucs2 0x006100620063 COLLATE `ucs2_general_ci`/*!*/;
+use test/*!*/;
+SET TIMESTAMP=10000/*!*/;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1,
@@session.unique_checks=1/*!*/;
+SET @@session.sql_mode=0/*!*/;
+/*!\C latin1 *//*!*/;
+SET
@@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/;
+insert into t2 values (@v)/*!*/;
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+drop table t2;

--- 1.2.2.1/mysql-test/t/ctype_cp932_binlog.test	2007-03-02 00:10:26 +02:00
+++ 1.7/mysql-test/extra/binlog_tests/ctype_cp932_binlog.test	2007-03-02 00:10:26 +02:00
@@ -26,32 +26,12 @@
 # code (and I have used it to test the fix) until there is some way to
 # exercise this code from mysql-test-run.
 EXECUTE stmt1 USING @var1;
-SHOW BINLOG EVENTS FROM 98;
+--replace_column 2 # 5 #
+--replace_regex /table_id: [0-9]+/table_id: #/
+SHOW BINLOG EVENTS FROM 102;
 SELECT HEX(f1) FROM t1;
 DROP table t1;
 # end test for bug#11338
 
 # End of 4.1 tests
 
-#
-# Bug#18293: Values in stored procedure written to binlog unescaped
-#
-
-delimiter |;
-CREATE TABLE t4 (s1 CHAR(50) CHARACTER SET latin1,
-                 s2 CHAR(50) CHARACTER SET cp932,
-                 d DECIMAL(10,2))|
-CREATE PROCEDURE bug18293 (IN ins1 CHAR(50),
-                           IN ins2 CHAR(50) CHARACTER SET cp932,
-                           IN ind DECIMAL(10,2))
-  BEGIN
-    INSERT INTO t4 VALUES (ins1, ins2, ind);
-  END|
-CALL bug18293("Foo's a Bar", _cp932 0xED40ED41ED42, 47.93)|
-SELECT HEX(s1),HEX(s2),d FROM t4|
-DROP PROCEDURE bug18293|
-DROP TABLE t4|
-SHOW BINLOG EVENTS FROM 402|
-delimiter ;|
-
-# End of 5.0 tests

--- 1.26/client/mysql_upgrade.c	2007-03-02 00:10:26 +02:00
+++ 1.27/client/mysql_upgrade.c	2007-03-02 00:10:26 +02:00
@@ -171,7 +171,7 @@
       }
 
       d= (extra_default_t *)my_malloc(sizeof(extra_default_t), 
-                           MYF(MY_FAE|MY_ZEROFILL));
+                                      MYF(MY_FAE | MY_ZEROFILL));
       d->id= id;
       d->name= opt->name;
       d->n_len= strlen(opt->name);
@@ -345,15 +345,17 @@
       }
       dynstr_set(&buf, NULL);
     }
-    if (dynstr_append_mem(&buf, "\n", 1)
-       || dynstr_append_mem(&buf, d->name, d->n_len)
-       || (d->v_len && (dynstr_append_mem(&buf, "=", 1)
-       || dynstr_append_mem(&buf, d->value, d->v_len))))
+    if (dynstr_append_mem(&buf, "\n", 1) ||
+        dynstr_append_mem(&buf, d->name, d->n_len) ||
+        (d->v_len && (dynstr_append_mem(&buf, "=", 1) ||
+                      dynstr_append_mem(&buf, d->value, d->v_len))))
     {
       ret= 1;
       goto error;
     }
     my_delete((gptr)d, MYF(0));
+    my_free((gptr) d, MYF(0));
+
     list_pop(extra_defaults);                   /* pop off the head */
   }
   if (my_write(defaults_file, buf.str, buf.length, MYF(MY_FNABP | MY_WME)))
@@ -451,10 +453,10 @@
   char *forced_extra_defaults;
   char *local_defaults_group_suffix;
   const char *script_line;
-  char *upgrade_defaults_path= 0;
+  char *upgrade_defaults_path= NULL; 
   char *defaults_to_use= NULL;
   int upgrade_defaults_created= 0;
-  
+  int no_defaults;
   char path[FN_REFLEN];
   DYNAMIC_STRING cmdline;
 
@@ -464,6 +466,10 @@
 #endif
 
   /* Check if we are forced to use specific defaults */
+  no_defaults= 0;
+  if (argc >= 2 && !strcmp(argv[1],"--no-defaults"))
+    no_defaults= 1;
+
   get_defaults_options(argc, argv,
                        &forced_defaults_file, &forced_extra_defaults,
                        &local_defaults_group_suffix);
@@ -578,7 +584,9 @@
   if (defaults_to_use)
   {
     dynstr_append(&cmdline, " ");
-    dynstr_append_os_quoted(&cmdline, "--defaults-extra-file=", 
+    dynstr_append_os_quoted(&cmdline,
+                            (no_defaults ? "--defaults-file=" :
+                             "--defaults-extra-file="),
                             defaults_to_use, NullS);
   }
 
@@ -652,7 +660,9 @@
   if (defaults_to_use)
   {
     dynstr_append(&cmdline, " ");
-    dynstr_append_os_quoted(&cmdline, "--defaults-extra-file=", 
+    dynstr_append_os_quoted(&cmdline,
+                            (no_defaults ? "--defaults-file=" :
+                             "--defaults-extra-file="),
                             defaults_to_use, NullS);
   }
   dynstr_append(&cmdline, " ");
@@ -684,6 +694,7 @@
   if (upgrade_defaults_created)
     my_delete(upgrade_defaults_path, MYF(0));
   
+  my_free(upgrade_defaults_path, MYF(MY_ALLOW_ZERO_PTR));
   my_end(info_flag ? MY_CHECK_ERROR : 0);
   return ret;
 }

--- 1.28/mysql-test/r/rpl_insert_id.result	2007-03-02 00:10:26 +02:00
+++ 1.29/mysql-test/r/rpl_insert_id.result	2007-03-02 00:10:26 +02:00
@@ -263,6 +263,64 @@
 2	100
 3	350
 drop table t1;
+CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b INT,
+UNIQUE(b));
+INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10;
+SELECT * FROM t1;
+a	b
+1	10
+2	2
+SELECT * FROM t1;
+a	b
+1	10
+2	2
+drop table t1;
+CREATE TABLE t1 (
+id bigint(20) unsigned NOT NULL auto_increment,
+field_1 int(10) unsigned NOT NULL,
+field_2 varchar(255) NOT NULL,
+field_3 varchar(255) NOT NULL,
+PRIMARY KEY (id),
+UNIQUE KEY field_1 (field_1, field_2)
+);
+CREATE TABLE t2 (
+field_a int(10) unsigned NOT NULL,
+field_b varchar(255) NOT NULL,
+field_c varchar(255) NOT NULL
+);
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (1, 'a', '1a');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (2, 'b', '2b');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (3, 'c', '3c');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (4, 'd', '4d');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (5, 'e', '5e');
+INSERT INTO t1 (field_1, field_2, field_3)
+SELECT t2.field_a, t2.field_b, t2.field_c
+FROM t2
+ON DUPLICATE KEY UPDATE
+t1.field_3 = t2.field_c;
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (6, 'f', '6f');
+INSERT INTO t1 (field_1, field_2, field_3)
+SELECT t2.field_a, t2.field_b, t2.field_c
+FROM t2
+ON DUPLICATE KEY UPDATE
+t1.field_3 = t2.field_c;
+SELECT * FROM t1;
+id	field_1	field_2	field_3
+1	1	a	1a
+2	2	b	2b
+3	3	c	3c
+4	4	d	4d
+5	5	e	5e
+6	6	f	6f
+SELECT * FROM t1;
+id	field_1	field_2	field_3
+1	1	a	1a
+2	2	b	2b
+3	3	c	3c
+4	4	d	4d
+5	5	e	5e
+6	6	f	6f
+drop table t1, t2;
 DROP PROCEDURE IF EXISTS p1;
 DROP TABLE IF EXISTS t1, t2;
 SELECT LAST_INSERT_ID(0);

--- 1.26/mysql-test/t/rpl_insert_id.test	2007-03-02 00:10:26 +02:00
+++ 1.27/mysql-test/t/rpl_insert_id.test	2007-03-02 00:10:26 +02:00
@@ -9,3 +9,56 @@
 -- source include/have_innodb.inc
 let $engine_type=innodb;
 -- source extra/rpl_tests/rpl_insert_id.test
+# BUG#24432 "INSERT... ON DUPLICATE KEY UPDATE skips auto_increment values"
+#
+
+# testcase with INSERT VALUES
+CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b INT,
+UNIQUE(b));
+INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10;
+SELECT * FROM t1;
+sync_slave_with_master;
+SELECT * FROM t1;
+connection master;
+drop table t1;
+
+# tescase with INSERT SELECT
+CREATE TABLE t1 (
+  id bigint(20) unsigned NOT NULL auto_increment,
+  field_1 int(10) unsigned NOT NULL,
+  field_2 varchar(255) NOT NULL,
+  field_3 varchar(255) NOT NULL,
+  PRIMARY KEY (id),
+  UNIQUE KEY field_1 (field_1, field_2)
+);
+CREATE TABLE t2 (
+  field_a int(10) unsigned NOT NULL,
+  field_b varchar(255) NOT NULL,
+  field_c varchar(255) NOT NULL
+);
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (1, 'a', '1a');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (2, 'b', '2b');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (3, 'c', '3c');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (4, 'd', '4d');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (5, 'e', '5e');
+# Updating table t1 based on values from table t2
+INSERT INTO t1 (field_1, field_2, field_3)
+SELECT t2.field_a, t2.field_b, t2.field_c
+FROM t2
+ON DUPLICATE KEY UPDATE
+t1.field_3 = t2.field_c;
+# Inserting new record into t2
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (6, 'f', '6f');
+# Updating t1 again
+INSERT INTO t1 (field_1, field_2, field_3)
+SELECT t2.field_a, t2.field_b, t2.field_c
+FROM t2
+ON DUPLICATE KEY UPDATE
+t1.field_3 = t2.field_c;
+SELECT * FROM t1;
+sync_slave_with_master;
+SELECT * FROM t1;
+connection master;
+drop table t1, t2;
+
+#

--- 1.1.1.1/mysql-test/r/ctype_cp932_notembedded.result	2007-03-02 00:10:26 +02:00
+++ 1.4/BitKeeper/deleted/.del-ctype_cp932_notembedded.result~f8bc6ad0446e82e3	2007-03-02
00:10:26 +02:00
@@ -6,11 +6,11 @@
 PREPARE stmt1 FROM 'INSERT INTO t1 VALUES(?)';
 SET @var1= x'8300';
 EXECUTE stmt1 USING @var1;
-SHOW BINLOG EVENTS FROM 98;
+SHOW BINLOG EVENTS FROM 102;
 Log_name	Pos	Event_type	Server_id	End_log_pos	Info
-master-bin.000001	98	Query	1	188	use `test`; CREATE TABLE t1(f1 blob)
-master-bin.000001	188	User var	1	227	@`var1`=_binary 0x8300 COLLATE binary
-master-bin.000001	227	Query	1	323	use `test`; INSERT INTO t1 VALUES(@'var1')
+master-bin.000001	102	Query	1	189	use `test`; CREATE TABLE t1(f1 blob)
+master-bin.000001	189	User var	1	228	@`var1`=_binary 0x8300 COLLATE binary
+master-bin.000001	228	Query	1	321	use `test`; INSERT INTO t1 VALUES(@'var1')
 SELECT HEX(f1) FROM t1;
 HEX(f1)
 8300

--- 1.252/sql/sp_head.cc	2007-03-02 00:10:26 +02:00
+++ 1.253/sql/sp_head.cc	2007-03-02 00:10:26 +02:00
@@ -1482,8 +1482,24 @@
 
   if (need_binlog_call)
   {
+    query_id_t q;
     reset_dynamic(&thd->user_var_events);
-    mysql_bin_log.start_union_events(thd);
+    /*
+      In case of artificially constructed events for function calls
+      we have separate union for each such event and hence can't use
+      query_id of real calling statement as the start of all these
+      unions (this will break logic of replication of user-defined
+      variables). So we use artifical value which is guaranteed to
+      be greater than all query_id's of all statements belonging
+      to previous events/unions.
+      Possible alternative to this is logging of all function invocations
+      as one select and not resetting THD::user_var_events before
+      each invocation.
+    */
+    VOID(pthread_mutex_lock(&LOCK_thread_count));
+    q= global_query_id;
+    VOID(pthread_mutex_unlock(&LOCK_thread_count));
+    mysql_bin_log.start_union_events(thd, q + 1);
     binlog_save_options= thd->options;
     thd->options&= ~OPTION_BIN_LOG;
   }

--- 1.104/sql/slave.h	2007-03-02 00:10:26 +02:00
+++ 1.105/sql/slave.h	2007-03-02 00:10:26 +02:00
@@ -159,6 +159,7 @@
 
 bool show_master_info(THD* thd, MASTER_INFO* mi);
 bool show_binlog_info(THD* thd);
+bool rpl_master_has_bug(RELAY_LOG_INFO *rli, uint bug_id);
 
 const char *print_slave_db_safe(const char *db);
 int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code);

--- 1.37/mysql-test/r/rpl_replicate_do.result	2007-03-02 00:10:26 +02:00
+++ 1.38/mysql-test/r/rpl_replicate_do.result	2007-03-02 00:10:26 +02:00
@@ -41,3 +41,37 @@
 ts
 2005-08-12 00:00:00
 drop table t1;
+*** master ***
+create table t1 (a int, b int);
+create trigger trg1 before insert on t1 for each row set new.b=2;
+create table t2 (a int, b int);
+create trigger trg2 before insert on t2 for each row set new.b=2;
+show tables;
+Tables_in_test
+t1
+t2
+show triggers;
+Trigger	Event	Table	Statement	Timing	Created	sql_mode	Definer
+trg1	INSERT	t1	set new.b=2	BEFORE	NULL		root@localhost
+trg2	INSERT	t2	set new.b=2	BEFORE	NULL		root@localhost
+*** slave ***
+show tables;
+Tables_in_test
+t1
+show triggers;
+Trigger	Event	Table	Statement	Timing	Created	sql_mode	Definer
+trg1	INSERT	t1	set new.b=2	BEFORE	NULL		root@localhost
+*** master ***
+drop trigger trg1;
+drop trigger trg2;
+show triggers;
+Trigger	Event	Table	Statement	Timing	Created	sql_mode	Definer
+*** slave ***
+show tables;
+Tables_in_test
+t1
+show triggers;
+Trigger	Event	Table	Statement	Timing	Created	sql_mode	Definer
+*** master ***
+drop table t1;
+drop table t2;

--- 1.29/mysql-test/t/rpl_replicate_do.test	2007-03-02 00:10:26 +02:00
+++ 1.30/mysql-test/t/rpl_replicate_do.test	2007-03-02 00:10:26 +02:00
@@ -58,3 +58,35 @@
 sync_slave_with_master;
 
 # End of 4.1 tests
+
+#
+# Bug#24478 DROP TRIGGER is not caught by replicate-*-table filters
+#
+--echo *** master ***
+connection master;
+create table t1 (a int, b int);
+create trigger trg1 before insert on t1 for each row set new.b=2;
+create table t2 (a int, b int);
+create trigger trg2 before insert on t2 for each row set new.b=2;
+show tables;
+show triggers;
+sync_slave_with_master;
+--echo *** slave ***
+connection slave;
+show tables;
+show triggers;
+--echo *** master ***
+connection master;
+drop trigger trg1;
+drop trigger trg2;
+show triggers;
+sync_slave_with_master;
+--echo *** slave ***
+connection slave;
+show tables;
+show triggers;
+--echo *** master ***
+connection master;
+drop table t1;
+drop table t2;
+sync_slave_with_master;

--- 1.161/sql/sql_repl.cc	2007-03-02 00:10:26 +02:00
+++ 1.162/sql/sql_repl.cc	2007-03-02 00:10:26 +02:00
@@ -886,12 +886,14 @@
 
 int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report )
 {
+  DBUG_ENTER("stop_slave");
+  
   int slave_errno;
   if (!thd)
     thd = current_thd;
 
   if (check_access(thd, SUPER_ACL, any_db,0,0,0,0))
-    return 1;
+    DBUG_RETURN(1);
   thd->proc_info = "Killing slave";
   int thread_mask;
   lock_slave_threads(mi);
@@ -925,12 +927,12 @@
   {
     if (net_report)
       my_message(slave_errno, ER(slave_errno), MYF(0));
-    return 1;
+    DBUG_RETURN(1);
   }
   else if (net_report)
     send_ok(thd);
 
-  return 0;
+  DBUG_RETURN(0);
 }
 
 
Thread
bk commit into 5.1 tree (jani:1.2466)jani1 Mar