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

ChangeSet@stripped, 2007-03-05 19:48:41+01:00, mats@romeo.(none) +14 -0
  Merge romeo.(none):/home/bkroot/mysql-5.1-new-rpl
  into  romeo.(none):/home/bk/b23171-mysql-5.1-new-rpl
  MERGE: 1.2390.1.21

  sql/item_xmlfunc.cc@stripped, 2007-03-05 18:01:11+01:00, mats@romeo.(none) +0 -0
    Auto merged
    MERGE: 1.25.1.1

  sql/lex.h@stripped, 2007-03-05 18:01:11+01:00, mats@romeo.(none) +0 -0
    Auto merged
    MERGE: 1.169.1.1

  sql/log.cc@stripped, 2007-03-05 19:48:36+01:00, mats@romeo.(none) +0 -7
    Manual merge with mysql-5.1-rpl
    MERGE: 1.253.1.10

  sql/log_event.cc@stripped, 2007-03-05 19:48:37+01:00, mats@romeo.(none) +0 -5
    Manual merge with mysql-5.1-rpl
    MERGE: 1.262.1.11

  sql/log_event.h@stripped, 2007-03-05 18:01:12+01:00, mats@romeo.(none) +0 -0
    Auto merged
    MERGE: 1.136.1.13

  sql/rpl_rli.cc@stripped, 2007-03-05 18:01:12+01:00, mats@romeo.(none) +0 -0
    Auto merged
    MERGE: 1.2.1.3

  sql/rpl_rli.h@stripped, 2007-03-05 18:01:12+01:00, mats@romeo.(none) +0 -0
    Auto merged
    MERGE: 1.7.1.2

  sql/rpl_utility.h@stripped, 2007-03-05 18:01:12+01:00, mats@romeo.(none) +0 -0
    Auto merged
    MERGE: 1.2.1.4

  sql/slave.cc@stripped, 2007-03-05 18:01:12+01:00, mats@romeo.(none) +0 -0
    Auto merged
    MERGE: 1.293.1.21

  sql/slave.h@stripped, 2007-03-05 18:01:12+01:00, mats@romeo.(none) +0 -0
    Auto merged
    MERGE: 1.102.1.5

  sql/sql_binlog.cc@stripped, 2007-03-05 19:48:37+01:00, mats@romeo.(none) +1 -2
    Manual merge with mysql-5.1-rpl
    MERGE: 1.8.1.1

  sql/sql_class.h@stripped, 2007-03-05 18:01:13+01:00, mats@romeo.(none) +0 -0
    Auto merged
    MERGE: 1.335.7.1

  sql/sql_load.cc@stripped, 2007-03-05 19:45:34+01:00, mats@romeo.(none) +2 -504
    Manual merge
    MERGE: 1.113.1.1

  sql/sql_yacc.yy@stripped, 2007-03-05 18:01:13+01:00, mats@romeo.(none) +0 -0
    Auto merged
    MERGE: 1.533.2.1

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

--- 1.170/sql/lex.h	2007-03-05 19:48:53 +01:00
+++ 1.171/sql/lex.h	2007-03-05 19:48:53 +01:00
@@ -222,7 +222,7 @@
   { "GLOBAL",		SYM(GLOBAL_SYM)},
   { "GRANT",		SYM(GRANT)},
   { "GRANTS",	        SYM(GRANTS)},
-  { "GROUP",		SYM(GROUP)},
+  { "GROUP",		SYM(GROUP_SYM)},
   { "HANDLER",		SYM(HANDLER_SYM)},
   { "HASH",		SYM(HASH_SYM)},
   { "HAVING",		SYM(HAVING)},

--- 1.256/sql/log.cc	2007-03-05 19:48:53 +01:00
+++ 1.257/sql/log.cc	2007-03-05 19:48:53 +01:00
@@ -31,15 +31,6 @@
 
 #include <mysql/plugin.h>
 
-/*
-  Define placement versions of operator new and operator delete since
-  we cannot be sure that the <new> include exists.
- */
-inline void *operator new(size_t, void *ptr) { return ptr; }
-inline void *operator new[](size_t, void *ptr) { return ptr; }
-inline void  operator delete(void*, void*) { /* Do nothing */ }
-inline void  operator delete[](void*, void*) { /* Do nothing */ }
-
 /* max size of the log message */
 #define MAX_LOG_BUFFER_SIZE 1024
 #define MAX_USER_HOST_SIZE 512
@@ -268,7 +259,7 @@
     table->table_name_length= 8;
     break;
   default:
-    DBUG_ASSERT(0);
+    assert(0);                                  // Impossible
   }
 
   /*
@@ -312,6 +303,7 @@
   {
     table->table->use_all_columns();
     table->table->locked_by_logger= TRUE;
+    table->table->no_replicate= TRUE;
   }
   /* restore thread settings */
   if (curr)
@@ -909,7 +901,7 @@
 
   my_time_t current_time;
   Security_context *sctx= thd->security_ctx;
-  uint message_buff_len= 0, user_host_len= 0;
+  uint user_host_len= 0;
   longlong query_time= 0, lock_time= 0;
 
   /*
@@ -1162,7 +1154,7 @@
     log_thd= table_log_handler->general_log_thd;
     break;
   default:
-    DBUG_ASSERT(0);
+    assert(0);                                  // Impossible
   }
 
   if (!(*tmp_opt))
@@ -1311,7 +1303,7 @@
     table= &slow_log;
     break;
   default:
-    DBUG_ASSERT(0);
+    assert(0);                                  // Impossible
   }
 
   /*
@@ -1544,18 +1536,16 @@
     do nothing.
     just pretend we can do 2pc, so that MySQL won't
     switch to 1pc.
-    real work will be done in TC_LOG_BINLOG::log()
+    real work will be done in MYSQL_BIN_LOG::log_xid()
   */
   return 0;
 }
 
 static int binlog_commit(handlerton *hton, THD *thd, bool all)
 {
-  int error= 0;
   DBUG_ENTER("binlog_commit");
   binlog_trx_data *const trx_data=
     (binlog_trx_data*) thd->ha_data[binlog_hton->slot];
-  IO_CACHE *trans_log= &trx_data->trans_log;
   DBUG_ASSERT(mysql_bin_log.is_open());
 
   /*
@@ -1566,7 +1556,7 @@
   if ((all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))) &&
       trx_data->empty())
   {
-    // we're here because trans_log was flushed in TC_LOG_BINLOG::log()
+    // we're here because trans_log was flushed in MYSQL_BIN_LOG::log_xid()
     trx_data->reset();
     DBUG_RETURN(0);
   }
@@ -1590,7 +1580,6 @@
   int error=0;
   binlog_trx_data *const trx_data=
     (binlog_trx_data*) thd->ha_data[binlog_hton->slot];
-  IO_CACHE *trans_log= &trx_data->trans_log;
   DBUG_ASSERT(mysql_bin_log.is_open());
 
   if (trx_data->empty()) {
@@ -1653,9 +1642,6 @@
 static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
 {
   DBUG_ENTER("binlog_savepoint_rollback");
-  binlog_trx_data *const trx_data=
-    (binlog_trx_data*) thd->ha_data[binlog_hton->slot];
-  IO_CACHE *trans_log= &trx_data->trans_log;
   DBUG_ASSERT(mysql_bin_log.is_open());
 
   /*
@@ -1666,7 +1652,7 @@
   if (unlikely(thd->options &
                (OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG)))
   {
-    int const error=
+    int error=
       thd->binlog_query(THD::STMT_QUERY_TYPE,
                         thd->query, thd->query_length, TRUE, FALSE);
     DBUG_RETURN(error);
@@ -1675,6 +1661,7 @@
   DBUG_RETURN(0);
 }
 
+
 int check_binlog_magic(IO_CACHE* log, const char** errmsg)
 {
   char magic[4];
@@ -1695,6 +1682,7 @@
   return 0;
 }
 
+
 File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg)
 {
   File file;
@@ -1753,7 +1741,7 @@
 
   /* Register EventMessageFile */
   dwError = RegSetValueEx(hRegKey, "EventMessageFile", 0, REG_EXPAND_SZ,
-                          (PBYTE) szPath, strlen(szPath)+1);
+                          (PBYTE) szPath, (DWORD) (strlen(szPath) + 1));
 
   /* Register supported event types */
   dwTypes= (EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
@@ -2201,7 +2189,6 @@
 
     if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
     {
-      Security_context *sctx= thd->security_ctx;
       if (current_time != last_time)
       {
         last_time= current_time;
@@ -2440,7 +2427,6 @@
                          bool null_created_arg)
 {
   File file= -1;
-  int open_flags = O_CREAT | O_BINARY;
   DBUG_ENTER("MYSQL_BIN_LOG::open");
   DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
 
@@ -2602,6 +2588,8 @@
     0	ok
 */
 
+#ifdef HAVE_REPLICATION
+
 static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset)
 {
   int bytes_read;
@@ -2635,6 +2623,7 @@
   DBUG_RETURN(1);
 }
 
+#endif /* HAVE_REPLICATION */
 
 /*
   Find the position in the log-index-file for the given log name
@@ -3127,8 +3116,6 @@
   pthread_mutex_unlock(&LOCK_index);
   DBUG_RETURN(error);
 }
-
-
 #endif /* HAVE_REPLICATION */
 
 
@@ -3252,7 +3239,6 @@
         We log the whole file name for log file as the user may decide
         to change base names at some point.
       */
-      THD *thd = current_thd; /* may be 0 if we are reacting to SIGHUP */
       Rotate_log_event r(new_name+dirname_length(new_name),
                          0, LOG_EVENT_OFFSET, 0);
       r.write(&log_file);
@@ -3367,13 +3353,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)
@@ -3706,14 +3692,14 @@
   */
   if (likely(is_open()))
   {
-    const char *local_db= event_info->get_db();
     IO_CACHE *file= &log_file;
 #ifdef HAVE_REPLICATION
     /*
-       In the future we need to add to the following if tests like
-       "do the involved tables match (to be implemented)
-        binlog_[wild_]{do|ignore}_table?" (WL#1049)"
+      In the future we need to add to the following if tests like
+      "do the involved tables match (to be implemented)
+      binlog_[wild_]{do|ignore}_table?" (WL#1049)"
     */
+    const char *local_db= event_info->get_db();
     if ((thd && !(thd->options & OPTION_BIN_LOG)) ||
 	(!binlog_filter->db_ok(local_db)))
     {
@@ -3902,7 +3888,7 @@
 #ifdef HAVE_REPLICATION
     if (expire_logs_days)
     {
-      long purge_time= time(0) - expire_logs_days*24*60*60;
+      long purge_time= (long) (time(0) - expire_logs_days*24*60*60);
       if (purge_time >= 0)
         purge_logs_before_date(purge_time);
     }
@@ -3989,8 +3975,6 @@
 
   if (likely(is_open()))                       // Should always be true
   {
-    uint length;
-
     /*
       We only bother to write to the binary log if there is anything
       to write.
@@ -4030,9 +4014,6 @@
       
       if (commit_event && commit_event->write(&log_file))
         goto err;
-#ifndef DBUG_OFF
-  DBUG_skip_commit:
-#endif
       if (flush_and_sync())
         goto err;
       DBUG_EXECUTE_IF("half_binlogged_transaction", abort(););
@@ -4692,21 +4673,34 @@
 }
 
 /*
-  all access to active page is serialized but it's not a problem, as
-  we're assuming that fsync() will be a main bottleneck.
-  That is, parallelizing writes to log pages we'll decrease number of
-  threads waiting for a page, but then all these threads will be waiting
-  for a fsync() anyway
+  Record that transaction XID is committed on the persistent storage
+
+  NOTES
+    This function is called in the middle of two-phase commit:
+    First all resources prepare the transaction, then tc_log->log() is called,
+    then all resources commit the transaction, then tc_log->unlog() is called.
+
+    All access to active page is serialized but it's not a problem, as
+    we're assuming that fsync() will be a main bottleneck.
+    That is, parallelizing writes to log pages we'll decrease number of
+    threads waiting for a page, but then all these threads will be waiting
+    for a fsync() anyway
+
+  IMPLEMENTATION
+   If tc_log == MYSQL_LOG then tc_log writes transaction to binlog and
+   records XID in a special Xid_log_event.
+   If tc_log = TC_LOG_MMAP then xid is written in a special memory-mapped
+   log.
 
   RETURN
-         0  - error
-  otherwise - "cookie", a number that will be passed as an argument
-              to unlog() call. tc_log can define it any way it wants,
-              and use for whatever purposes. TC_LOG_MMAP sets it
-              to the position in memory where xid was logged to.
+    0  Error
+    #  "cookie", a number that will be passed as an argument
+       to unlog() call. tc_log can define it any way it wants,
+       and use for whatever purposes. TC_LOG_MMAP sets it
+       to the position in memory where xid was logged to.
 */
 
-int TC_LOG_MMAP::log(THD *thd, my_xid xid)
+int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid)
 {
   int err;
   PAGE *p;
@@ -4815,6 +4809,7 @@
   erase xid from the page, update page free space counters/pointers.
   cookie points directly to the memory where xid was logged
 */
+
 void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
 {
   PAGE *p=pages+(cookie/tc_log_page_size);
@@ -5057,7 +5052,7 @@
          0  - error
          1  - success
 */
-int TC_LOG_BINLOG::log(THD *thd, my_xid xid)
+int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid)
 {
   DBUG_ENTER("TC_LOG_BINLOG::log");
   Xid_log_event xle(thd, xid);

--- 1.266/sql/log_event.cc	2007-03-05 19:48:53 +01:00
+++ 1.267/sql/log_event.cc	2007-03-05 19:48:53 +01:00
@@ -140,22 +140,6 @@
 }
 #endif /* MYSQL_CLIENT */
 
-#ifdef HAVE_purify
-static void
-valgrind_check_mem(void *ptr, size_t len)
-{
-  static volatile uchar dummy;
-  for (volatile uchar *p= (uchar*) ptr ; p != (uchar*) ptr + len ; ++p)
-  {
-    int const c = *p;
-    if (c < 128)
-      dummy= c + 1;
-    else
-      dummy = c - 1;
-  }
-}
-#endif
-
 #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
 
 static void clear_all_errors(THD *thd, struct st_relay_log_info *rli)
@@ -382,12 +366,14 @@
 }
 #endif
 
+
 /*
   Prints a "session_var=value" string. Used by mysqlbinlog to print some SET
   commands just before it prints a query.
 */
 
 #ifdef MYSQL_CLIENT
+
 static void print_set_option(IO_CACHE* file, uint32 bits_changed,
                              uint32 option, uint32 flags, const char* name,
                              bool* need_comma)
@@ -1158,13 +1144,18 @@
       char emit_buf[256];
       int const bytes_written=
         my_snprintf(emit_buf, sizeof(emit_buf),
-                    "# %8.8lx %-48.48s |%s|\n# ",
+                    "# %8.8lx %-48.48s |%s|\n",
                     (unsigned long) (hexdump_from + (i & 0xfffffff0)),
                     hex_string, char_string);
       DBUG_ASSERT(bytes_written >= 0);
       DBUG_ASSERT(static_cast<my_size_t>(bytes_written) < sizeof(emit_buf));
       my_b_write(file, (byte*) emit_buf, bytes_written);
     }
+    /*
+      need a # to prefix the rest of printouts for example those of
+      Rows_log_event::print_helper().
+    */
+    my_b_write(file, reinterpret_cast<const byte*>("# "), 2);
   }
   DBUG_VOID_RETURN;
 }
@@ -1176,7 +1167,6 @@
 {
   const uchar *ptr= (const uchar *)temp_buf;
   uint32 size= uint4korr(ptr + EVENT_LEN_OFFSET);
-
   DBUG_ENTER("Log_event::print_base64");
 
   size_t const tmp_str_sz= base64_needed_encoded_length((int) size);
@@ -1187,8 +1177,10 @@
     DBUG_VOID_RETURN;
   }
 
-  int const res= base64_encode(ptr, (size_t) size, tmp_str);
-  DBUG_ASSERT(res == 0);
+  if (base64_encode(ptr, (size_t) size, tmp_str))
+  {
+    DBUG_ASSERT(0);
+  }
 
   if (my_b_tell(file) == 0)
     my_b_printf(file, "\nBINLOG '\n");
@@ -1303,7 +1295,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;
 
@@ -1422,6 +1415,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)
@@ -1487,7 +1487,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);
@@ -1495,6 +1496,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
@@ -1565,7 +1569,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;
@@ -1670,6 +1674,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\
@@ -1868,6 +1876,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)
+      my_b_printf(file, "SET @@session.collation_database=%d%s\n",
+                  charset_database_number, print_event_info->delimiter);
+    else
+      my_b_printf(file, "SET @@session.collation_database=DEFAULT%s\n",
+                  print_event_info->delimiter);
+    print_event_info->charset_database_number= charset_database_number;
+  }
 }
 
 
@@ -2024,7 +2042,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);
 
@@ -3346,7 +3378,6 @@
       thd->main_lex.select_lex.context.resolve_in_table_list_only(&tables);
       set_fields(tables.db, field_list, &thd->main_lex.select_lex.context);
       thd->variables.pseudo_thread_id= thread_id;
-      List<Item> set_fields;
       if (net)
       {
 	// mysql_load will use thd->net to read the file
@@ -3357,10 +3388,11 @@
 	thd->net.pkt_nr = net->pkt_nr;
       }
       /*
-        It is safe to use set_fields twice because we are not going to
+        It is safe to use tmp_list twice because we are not going to
         update it inside mysql_load().
       */
-      if (mysql_load(thd, &ex, &tables, field_list, set_fields, set_fields,
+      List<Item> tmp_list;
+      if (mysql_load(thd, &ex, &tables, field_list, tmp_list, tmp_list,
                      handle_dup, ignore, net != 0))
         thd->query_error= 1;
       if (thd->cuted_fields)
@@ -5678,15 +5710,14 @@
   DBUG_ASSERT(m_rows_cur <= m_rows_end);
 
   /* The cast will always work since m_rows_cur <= m_rows_end */
-  if (static_cast<my_size_t>(m_rows_end - m_rows_cur) < length)
+  if (static_cast<my_size_t>(m_rows_end - m_rows_cur) <= length)
   {
     my_size_t const block_size= 1024;
-    my_ptrdiff_t const old_alloc= m_rows_end - m_rows_buf;
     my_ptrdiff_t const cur_size= m_rows_cur - m_rows_buf;
     my_ptrdiff_t const new_alloc= 
-        block_size * ((cur_size + length) / block_size + block_size - 1);
+        block_size * ((cur_size + length + block_size - 1) / block_size);
 
-    byte* const new_buf= (byte*)my_realloc((gptr)m_rows_buf, new_alloc,
+    byte* const new_buf= (byte*)my_realloc((gptr)m_rows_buf, (uint) new_alloc,
                                            MYF(MY_ALLOW_ZERO_PTR|MY_WME));
     if (unlikely(!new_buf))
       DBUG_RETURN(HA_ERR_OUT_OF_MEM);
@@ -5705,7 +5736,7 @@
     m_rows_end= m_rows_buf + new_alloc;
   }
 
-  DBUG_ASSERT(m_rows_cur + length < m_rows_end);
+  DBUG_ASSERT(m_rows_cur + length <= m_rows_end);
   memcpy(m_rows_cur, row_data, length);
   m_rows_cur+= length;
   m_row_count++;
@@ -5806,8 +5837,8 @@
     if (bitmap_is_set(cols, field_ptr -  begin_ptr))
     {
       DBUG_ASSERT((const char *)table->record[0] <= f->ptr);
-      DBUG_ASSERT(f->ptr < ((const char *)table->record[0] + table->s->reclength +
-                            (f->pack_length_in_rec() == 0)));
+      DBUG_ASSERT(f->ptr < (char*)(table->record[0] + table->s->reclength +
+                                   (f->pack_length_in_rec() == 0)));
 
       DBUG_PRINT("info", ("unpacking column '%s' to 0x%lx", f->field_name,
                           (long) f->ptr));
@@ -5918,9 +5949,26 @@
     {
       if (!need_reopen)
       {
-        slave_print_msg(ERROR_LEVEL, rli, error,
-                        "Error in %s event: when locking tables",
-                        get_type_str());
+        if (thd->query_error || thd->is_fatal_error)
+        {
+          /*
+            Error reporting borrowed from Query_log_event with many excessive
+            simplifications (we don't honour --slave-skip-errors)
+          */
+          uint actual_error= thd->net.last_errno;
+          slave_print_msg(ERROR_LEVEL, rli, actual_error,
+                          "Error '%s' in %s event: when locking tables",
+                          (actual_error ? thd->net.last_error :
+                           "unexpected success or fatal error"),
+                          get_type_str());
+          thd->is_fatal_error= 1;
+        }
+        else
+        {
+          slave_print_msg(ERROR_LEVEL, rli, error,
+                         "Error in %s event: when locking tables",
+                         get_type_str());
+        }
         const_cast<RELAY_LOG_INFO*>(rli)->clear_tables_to_lock();
         DBUG_RETURN(error);
       }
@@ -5939,12 +5987,10 @@
         need to add code to assert that is the case.
        */
       thd->binlog_flush_pending_rows_event(false);
-      close_tables_for_reopen(thd, &const_cast<RELAY_LOG_INFO*>(rli)->tables_to_lock);
+      TABLE_LIST *tables= rli->tables_to_lock;
+      close_tables_for_reopen(thd, &tables);
 
-      if ((error= open_tables(thd,
-                              &const_cast<RELAY_LOG_INFO*>(rli)->tables_to_lock,
-                              &const_cast<RELAY_LOG_INFO*>(rli)->tables_to_lock_count,
-                              0)))
+      if ((error= open_tables(thd, &tables, &rli->tables_to_lock_count, 0)))
       {
         if (thd->query_error || thd->is_fatal_error)
         {
@@ -5963,15 +6009,45 @@
         DBUG_RETURN(error);
       }
     }
+
     /*
-      When the open and locking succeeded, we add all the tables to
-      the table map and remove them from tables to lock.
+      When the open and locking succeeded, we check all tables to
+      ensure that they still have the correct type.
+
+      We can use a down cast here since we know that every table added
+      to the tables_to_lock is a RPL_TABLE_LIST.
+    */
+
+    {
+      RPL_TABLE_LIST *ptr= rli->tables_to_lock;
+      for ( ; ptr ; ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global))
+      {
+        if (ptr->m_tabledef.compatible_with(rli, ptr->table))
+        {
+          mysql_unlock_tables(thd, thd->lock);
+          thd->lock= 0;
+          thd->query_error= 1;
+          rli->clear_tables_to_lock();
+          DBUG_RETURN(ERR_BAD_TABLE_DEF);
+        }
+      }
+    }
+
+    /*
+      ... and then we add all the tables to the table map and remove
+      them from tables to lock.
 
       We also invalidate the query cache for all the tables, since
       they will now be changed.
+
+      TODO [/Matz]: Maybe the query cache should not be invalidated
+      here? It might be that a table is not changed, even though it
+      was locked for the statement.  We do know that each
+      Rows_log_event contain at least one row, so after processing one
+      Rows_log_event, we can invalidate the query cache for the
+      associated table.
      */
-    TABLE_LIST *ptr;
-    for (ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global)
+    for (TABLE_LIST *ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global)
     {
       const_cast<RELAY_LOG_INFO*>(rli)->m_table_map.set_table(ptr->table_id, ptr->table);
     }
@@ -6214,7 +6290,7 @@
                           sbuf_end - sbuf) ||
           my_b_safe_write(file, reinterpret_cast<byte*>(m_cols.bitmap),
                           no_bytes_in_map(&m_cols)) ||
-          my_b_safe_write(file, m_rows_buf, data_size));
+          my_b_safe_write(file, m_rows_buf, (uint) data_size));
 }
 #endif
 
@@ -6241,7 +6317,7 @@
   {
     bool const last_stmt_event= get_flags(STMT_END_F);
     print_header(head, print_event_info, !last_stmt_event);
-    my_b_printf(head, "\t%s: table id %lu", name, m_table_id);
+    my_b_printf(head, "\t%s: table id %lu\n", name, m_table_id);
     print_base64(body, print_event_info, !last_stmt_event);
   }
 
@@ -6423,11 +6499,11 @@
   thd->query_id= next_query_id();
   pthread_mutex_unlock(&LOCK_thread_count);
 
-  TABLE_LIST *table_list;
+  RPL_TABLE_LIST *table_list;
   char *db_mem, *tname_mem;
   void *const memory=
     my_multi_malloc(MYF(MY_WME),
-                    &table_list, sizeof(TABLE_LIST),
+                    &table_list, sizeof(RPL_TABLE_LIST),
                     &db_mem, NAME_LEN + 1,
                     &tname_mem, NAME_LEN + 1,
                     NULL);
@@ -6473,11 +6549,27 @@
     }
 
     /*
-      Open the table if it is not already open and add the table to table map.
-      Note that for any table that should not be replicated, a filter is needed.
+      Open the table if it is not already open and add the table to
+      table map.  Note that for any table that should not be
+      replicated, a filter is needed.
+
+      The creation of a new TABLE_LIST is used to up-cast the
+      table_list consisting of RPL_TABLE_LIST items. This will work
+      since the only case where the argument to open_tables() is
+      changed, is when thd->lex->query_tables == table_list, i.e.,
+      when the statement requires prelocking. Since this is not
+      executed when a statement is executed, this case will not occur.
+      As a precaution, an assertion is added to ensure that the bad
+      case is not a fact.
+
+      Either way, the memory in the list is *never* released
+      internally in the open_tables() function, hence we take a copy
+      of the pointer to make sure that it's not lost.
     */
     uint count;
-    if ((error= open_tables(thd, &table_list, &count, 0)))
+    DBUG_ASSERT(thd->lex->query_tables != table_list);
+    TABLE_LIST *tmp_table_list= table_list;
+    if ((error= open_tables(thd, &tmp_table_list, &count, 0)))
     {
       if (thd->query_error || thd->is_fatal_error)
       {
@@ -6504,14 +6596,17 @@
     */
     DBUG_ASSERT(m_table->in_use);
 
-    table_def const def(m_coltype, m_colcnt);
-    if (def.compatible_with(rli, m_table))
-    {
-      thd->query_error= 1;
-      error= ERR_BAD_TABLE_DEF;
-      goto err;
-      /* purecov: end */
-    }
+    /*
+      Use placement new to construct the table_def instance in the
+      memory allocated for it inside table_list.
+
+      The memory allocated by the table_def structure (i.e., not the
+      memory allocated *for* the table_def structure) is released
+      inside st_relay_log_info::clear_tables_to_lock() by calling the
+      table_def destructor explicitly.
+    */
+    new (&table_list->m_tabledef) table_def(m_coltype, m_colcnt);
+    table_list->m_tabledef_valid= TRUE;
 
     /*
       We record in the slave's information that the table should be
@@ -6562,8 +6657,8 @@
   DBUG_ASSERT(m_dblen < 128);
   DBUG_ASSERT(m_tbllen < 128);
 
-  byte const dbuf[]= { m_dblen };
-  byte const tbuf[]= { m_tbllen };
+  byte const dbuf[]= { (byte) m_dblen };
+  byte const tbuf[]= { (byte) m_tbllen };
 
   char cbuf[sizeof(m_colcnt)];
   char *const cbuf_end= net_store_length((char*) cbuf, (uint) m_colcnt);

--- 1.143/sql/log_event.h	2007-03-05 19:48:53 +01:00
+++ 1.144/sql/log_event.h	2007-03-05 19:48:53 +01: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
@@ -534,10 +535,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
@@ -547,16 +549,19 @@
       bzero(db, sizeof(db));
       bzero(charset, sizeof(charset));
       bzero(time_zone_str, sizeof(time_zone_str));
-      strcpy(delimiter, ";");
-      uint const flags = MYF(MY_WME | MY_NABP);
-      init_io_cache(&head_cache, -1, 0, WRITE_CACHE, 0L, FALSE, flags);
-      init_io_cache(&body_cache, -1, 0, WRITE_CACHE, 0L, FALSE, flags);
+      delimiter[0]= ';';
+      delimiter[1]= 0;
+      myf const flags = MYF(MY_WME | MY_NABP);
+      open_cached_file(&head_cache, NULL, NULL, 0, flags);
+      open_cached_file(&body_cache, NULL, NULL, 0, flags);
     }
 
   ~st_print_event_info() {
-    end_io_cache(&head_cache);
-    end_io_cache(&body_cache);
+    close_cached_file(&head_cache);
+    close_cached_file(&body_cache);
   }
+  bool init_ok() /* tells if construction was successful */
+    { return my_b_inited(&head_cache) && my_b_inited(&body_cache); }
 
 
   /* Settings on how to print the events */
@@ -993,6 +998,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
 
@@ -1970,14 +1976,17 @@
     TYPE_CODE = TABLE_MAP_EVENT
   };
 
+  /**
+     Enumeration of the errors that can be returned.
+   */
   enum enum_error
   {
-    ERR_OPEN_FAILURE = -1,                 /* Failure to open table */
-    ERR_OK = 0,                                  /* No error */
-    ERR_TABLE_LIMIT_EXCEEDED = 1,        /* No more room for tables */
-    ERR_OUT_OF_MEM = 2,                         /* Out of memory */
-    ERR_BAD_TABLE_DEF = 3,       /* Table definition does not match */
-    ERR_RBR_TO_SBR = 4    /* daisy-chanining RBR to SBR not allowed */
+    ERR_OPEN_FAILURE = -1,               /**< Failure to open table */
+    ERR_OK = 0,                                 /**< No error */
+    ERR_TABLE_LIMIT_EXCEEDED = 1,      /**< No more room for tables */
+    ERR_OUT_OF_MEM = 2,                         /**< Out of memory */
+    ERR_BAD_TABLE_DEF = 3,     /**< Table definition does not match */
+    ERR_RBR_TO_SBR = 4  /**< daisy-chanining RBR to SBR not allowed */
   };
 
   enum enum_flag
@@ -2061,7 +2070,7 @@
 
  Row level log event class.
 
- Common base class for all row-level log events.
+ Common base class for all row-containing log events.
 
  RESPONSIBILITIES
 
@@ -2075,6 +2084,19 @@
 class Rows_log_event : public Log_event
 {
 public:
+  /**
+     Enumeration of the errors that can be returned.
+   */
+  enum enum_error
+  {
+    ERR_OPEN_FAILURE = -1,               /**< Failure to open table */
+    ERR_OK = 0,                                 /**< No error */
+    ERR_TABLE_LIMIT_EXCEEDED = 1,      /**< No more room for tables */
+    ERR_OUT_OF_MEM = 2,                         /**< Out of memory */
+    ERR_BAD_TABLE_DEF = 3,     /**< Table definition does not match */
+    ERR_RBR_TO_SBR = 4  /**< daisy-chanining RBR to SBR not allowed */
+  };
+
   /*
     These definitions allow you to combine the flags into an
     appropriate flag set using the normal bitwise operators.  The
@@ -2082,7 +2104,6 @@
     accepted by the compiler, which is then used to set the real set
     of flags.
   */
-
   enum enum_flag
   {
     /* Last event of a statement */

--- 1.299/sql/slave.cc	2007-03-05 19:48:53 +01:00
+++ 1.300/sql/slave.cc	2007-03-05 19:48:53 +01:00
@@ -53,6 +53,7 @@
 */
 
 int disconnect_slave_event_count = 0, abort_slave_event_count = 0;
+int events_till_abort = -1;
 
 typedef enum { SLAVE_THD_IO, SLAVE_THD_SQL} SLAVE_THD_TYPE;
 
@@ -73,6 +74,7 @@
 static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
                                   const char* table_name, bool overwrite);
 static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi);
+static Log_event* next_event(RELAY_LOG_INFO* rli);
 
 /*
   Find out which replications threads are running
@@ -1295,7 +1297,7 @@
     rpl_filter->get_wild_ignore_table(&tmp);
     protocol->store(&tmp);
 
-    protocol->store((uint32) mi->rli.last_slave_errno);
+    protocol->store(mi->rli.last_slave_errno);
     protocol->store(mi->rli.last_slave_error, &my_charset_bin);
     protocol->store((uint32) mi->rli.slave_skip_counter);
     protocol->store((ulonglong) mi->rli.group_master_log_pos);
@@ -1326,12 +1328,12 @@
     if ((mi->slave_running == MYSQL_SLAVE_RUN_CONNECT) &&
         mi->rli.slave_running)
     {
-      long tmp= (long)((time_t)time((time_t*) 0)
-                               - mi->rli.last_master_timestamp)
-        - mi->clock_diff_with_master;
+      long time_diff= ((long)((time_t)time((time_t*) 0)
+                              - mi->rli.last_master_timestamp)
+                       - mi->clock_diff_with_master);
       /*
-        Apparently on some systems tmp can be <0. Here are possible reasons
-        related to MySQL:
+        Apparently on some systems time_diff can be <0. Here are possible
+        reasons related to MySQL:
         - the master is itself a slave of another master whose time is ahead.
         - somebody used an explicit SET TIMESTAMP on the master.
         Possible reason related to granularity-to-second of time functions
@@ -1349,8 +1351,8 @@
         last_master_timestamp == 0 (an "impossible" timestamp 1970) is a
         special marker to say "consider we have caught up".
       */
-      protocol->store((longlong)(mi->rli.last_master_timestamp ? max(0, tmp)
-                                 : 0));
+      protocol->store((longlong)(mi->rli.last_master_timestamp ?
+                                 max(0, time_diff) : 0));
     }
     else
       protocol->store_null();
@@ -1428,13 +1430,11 @@
 */
   thd->variables.max_allowed_packet= global_system_variables.max_allowed_packet
     + MAX_LOG_EVENT_HEADER;  /* note, incr over the global not session var */
-  thd->net.read_timeout = slave_net_timeout;
   thd->slave_thread = 1;
   set_slave_thread_options(thd);
   thd->client_capabilities = CLIENT_LOCAL_FILES;
-  thd->real_id=pthread_self();
   pthread_mutex_lock(&LOCK_thread_count);
-  thd->thread_id = thread_id++;
+  thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
   pthread_mutex_unlock(&LOCK_thread_count);
 
   if (init_thr_lock() || thd->store_globals())
@@ -1444,12 +1444,6 @@
     DBUG_RETURN(-1);
   }
 
-#if !defined(__WIN__) && !defined(__NETWARE__)
-  sigset_t set;
-  VOID(sigemptyset(&set));                      // Get mask in use
-  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
-
   if (thd_type == SLAVE_THD_SQL)
     thd->proc_info= "Waiting for the next event in relay log";
   else
@@ -2074,15 +2068,16 @@
 
     while (!io_slave_killed(thd,mi))
     {
-      bool suppress_warnings= 0;
+      ulong event_len;
+      suppress_warnings= 0;
       /*
          We say "waiting" because read_event() will wait if there's nothing to
          read. But if there's something to read, it will not wait. The
          important thing is to not confuse users by saying "reading" whereas
          we're in fact receiving nothing.
       */
-      thd->proc_info = "Waiting for master to send event";
-      ulong event_len = read_event(mysql, mi, &suppress_warnings);
+      thd->proc_info= "Waiting for master to send event";
+      event_len= read_event(mysql, mi, &suppress_warnings);
       if (io_slave_killed(thd,mi))
       {
         if (global_system_variables.log_warnings)
@@ -2233,11 +2228,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
@@ -2487,9 +2487,14 @@
   THD_CHECK_SENTRY(thd);
   delete thd;
   pthread_mutex_unlock(&LOCK_thread_count);
+ /*
+  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);
+  pthread_mutex_unlock(&rli->run_lock);  // tell the world we are done
+  
   my_thread_end();
   pthread_exit(0);
   DBUG_RETURN(0);                               // Can't return anything here
@@ -2888,6 +2893,8 @@
   pthread_mutex_t *log_lock= rli->relay_log.get_log_lock();
   DBUG_ENTER("queue_event");
 
+  LINT_INIT(inc_pos);
+
   if (mi->rli.relay_log.description_event_for_queue->binlog_version<4 &&
       buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT /* a way to escape */)
     DBUG_RETURN(queue_old_event(mi,buf,event_len));
@@ -3029,7 +3036,7 @@
 
 err:
   pthread_mutex_unlock(&mi->data_lock);
-  DBUG_PRINT("info", ("error=%d", error));
+  DBUG_PRINT("info", ("error: %d", error));
   DBUG_RETURN(error);
 }
 
@@ -3349,7 +3356,13 @@
         hot_log=0;                              // Using old binary log
       }
     }
-
+    /* 
+      As there is no guarantee that the relay is open (for example, an I/O
+      error during a write by the slave I/O thread may have closed it), we
+      have to test it.
+    */
+    if (!my_b_inited(cur_log))
+      goto err;
 #ifndef DBUG_OFF
     {
       /* This is an assertion which sometimes fails, let's try to track it */
@@ -3694,8 +3707,8 @@
   };
   static struct st_version_range_for_one_bug versions_for_all_bugs[]=
   {
-    {24432, { 5, 0, 24 }, { 5, 0, 36 } },
-    {24432, { 5, 1, 12 }, { 5, 1, 16 } }
+    {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;

--- 1.342/sql/sql_class.h	2007-03-05 19:48:53 +01:00
+++ 1.343/sql/sql_class.h	2007-03-05 19:48:53 +01:00
@@ -40,6 +40,7 @@
 { CHECK_FIELD_IGNORE, CHECK_FIELD_WARN, CHECK_FIELD_ERROR_FOR_NULL };
 enum enum_mark_columns
 { MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE};
+enum enum_filetype { FILETYPE_CSV, FILETYPE_XML };
 
 extern char internal_table_name[2];
 extern char empty_c_string[1];
@@ -1651,6 +1652,7 @@
 class sql_exchange :public Sql_alloc
 {
 public:
+  enum enum_filetype filetype; /* load XML, Added by Arnold & Erik */ 
   char *file_name;
   String *field_term,*enclosed,*line_term,*line_start,*escaped;
   bool opt_enclosed;

--- 1.544/sql/sql_yacc.yy	2007-03-05 19:48:53 +01:00
+++ 1.545/sql/sql_yacc.yy	2007-03-05 19:48:53 +01:00
@@ -926,6 +926,7 @@
 %token  WRITE_SYM                     /* SQL-2003-N */
 %token  X509_SYM
 %token  XA_SYM
+%token  XML_SYM                       /* Load XML Arnold/Erik */
 %token  XOR
 %token  YEAR_MONTH_SYM
 %token  YEAR_SYM                      /* SQL-2003-R */
@@ -1112,6 +1113,7 @@
 	statement sp_suid
 	sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
         load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
+        load_xml  opt_xml_rows_identified_by load_data_lines_or_rows
         definer view_replace_or_algorithm view_replace view_algorithm_opt
         view_algorithm view_or_trigger_or_sp_or_event
         view_or_trigger_or_sp_or_event_tail
@@ -8912,7 +8914,10 @@
 	  lex->select_lex.db= $2.str;
 	};
 
-/* import, export of files */
+/*
+   import, export of files
+   Load xml Arnold/Erik: Added LOAD XML_SYM part
+*/
 
 load:   LOAD DATA_SYM
         {
@@ -8927,6 +8932,19 @@
         load_data
         {}
         |
+        LOAD XML_SYM
+        {
+          LEX *lex=Lex;
+          if (lex->sphead)
+          {
+            my_error(ER_SP_BADSTATEMENT, MYF(0), "LOAD DATA");
+            YYABORT;
+          }
+          lex->fname_start= lex->ptr;
+        }
+        load_xml
+        {}
+        |
         LOAD TABLE_SYM table_ident FROM MASTER_SYM
         {
 	  LEX *lex=Lex;
@@ -8953,6 +8971,7 @@
 	  lex->ignore= 0;
 	  if (!(lex->exchange= new sql_exchange($4.str, 0)))
 	    YYABORT;
+          lex->exchange->filetype= FILETYPE_CSV;
         }
         opt_duplicate INTO
         {
@@ -8983,6 +9002,41 @@
                           "BACKUP/RESTORE DATABASE facility");
         };
 
+/* Load XML Added by Arnold/Erik -- */        
+load_xml:
+        load_data_lock opt_local INFILE TEXT_STRING_filesystem
+        {
+          LEX *lex=Lex;
+          lex->sql_command= SQLCOM_LOAD;
+          lex->lock_option= $1;
+          lex->local_file=  $2;
+          lex->duplicates= DUP_ERROR;
+          lex->ignore= 0;
+          if (!(lex->exchange= new sql_exchange($4.str, 0)))
+            YYABORT;
+          lex->exchange->filetype = FILETYPE_XML;
+        }
+        opt_duplicate INTO
+        {
+          LEX *lex=Lex;
+          lex->fname_end= lex->ptr;
+        }
+        TABLE_SYM table_ident
+        {
+          LEX *lex=Lex;
+          if (!Select->add_table_to_list(YYTHD, $10, NULL,
+                                         TL_OPTION_UPDATING,
+                                         lex->lock_option))
+          YYABORT;
+          lex->field_list.empty();
+          lex->update_list.empty();
+          lex->value_list.empty();
+        }
+        opt_xml_rows_identified_by opt_ignore_lines opt_field_or_var_spec
+        opt_load_data_set_spec
+        {};
+
+
 opt_local:
 	/* empty */	{ $$=0;}
 	| LOCAL_SYM	{ $$=1;};
@@ -9061,9 +9115,14 @@
             Lex->exchange->line_start= $3;
           };
 
+load_data_lines_or_rows:
+        LINES { }
+        | ROWS_SYM { }
+        ;
+
 opt_ignore_lines:
 	/* empty */
-        | IGNORE_SYM NUM LINES
+        | IGNORE_SYM NUM load_data_lines_or_rows
           {
             DBUG_ASSERT(Lex->exchange != 0);
             Lex->exchange->skip_lines= atol($2.str);
@@ -9091,6 +9150,11 @@
         /* empty */           { }
         | SET insert_update_list  { };
 
+opt_xml_rows_identified_by:
+        /* empty */ { }
+        | ROWS_SYM IDENTIFIED_SYM BY text_string
+          { Lex->exchange->line_term = $4; };
+
 
 /* Common definitions */
 
@@ -9893,6 +9957,7 @@
 	| WORK_SYM		{}
 	| X509_SYM		{}
 	| YEAR_SYM		{}
+	| XML_SYM		{}
 	;
 
 /* Option functions */

--- 1.26/sql/item_xmlfunc.cc	2007-03-05 19:48:53 +01:00
+++ 1.27/sql/item_xmlfunc.cc	2007-03-05 19:48:53 +01:00
@@ -577,7 +577,6 @@
   both_str.alloc(numnodes);
   char *both= (char*) both_str.ptr();
   bzero((void*)both, numnodes);
-  uint pos= 0;
   MY_XPATH_FLT *flt;
 
   fltbeg= (MY_XPATH_FLT*) s0->ptr();
@@ -1513,7 +1512,6 @@
 static int my_xpath_parse_LocationPath(MY_XPATH *xpath);
 static int my_xpath_parse_AbsoluteLocationPath(MY_XPATH *xpath);
 static int my_xpath_parse_RelativeLocationPath(MY_XPATH *xpath);
-static int my_xpath_parse_AbbreviatedAbsoluteLocationPath(MY_XPATH *xpath);
 static int my_xpath_parse_AbbreviatedStep(MY_XPATH *xpath);
 static int my_xpath_parse_Step(MY_XPATH *xpath);
 static int my_xpath_parse_AxisSpecifier(MY_XPATH *xpath);
@@ -1532,7 +1530,6 @@
 static int my_xpath_parse_AndExpr(MY_XPATH *xpath);
 static int my_xpath_parse_EqualityExpr(MY_XPATH *xpath);
 static int my_xpath_parse_VariableReference(MY_XPATH *xpath);
-static int my_xpath_parse_slash_opt_slash(MY_XPATH *xpath);
 
 
 /*
@@ -2767,7 +2764,6 @@
   }
 
   MY_XML_NODE *nodebeg= (MY_XML_NODE*) pxml.ptr();
-  MY_XML_NODE *nodeend= (MY_XML_NODE*) pxml.ptr() + pxml.length();
   MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) nodeset->ptr();
   MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (nodeset->ptr() + nodeset->length());
 

--- 1.6/sql/rpl_rli.cc	2007-03-05 19:48:53 +01:00
+++ 1.7/sql/rpl_rli.cc	2007-03-05 19:48:53 +01:00
@@ -18,6 +18,7 @@
 #include "rpl_rli.h"
 #include <my_dir.h>    // For MY_STAT
 #include "sql_repl.h"  // For check_binlog_magic
+#include "rpl_utility.h"
 
 static int count_relay_log_space(RELAY_LOG_INFO* rli);
 
@@ -1114,4 +1115,23 @@
   last_event_start_time= 0;
   DBUG_VOID_RETURN;
 }
+
+void st_relay_log_info::clear_tables_to_lock()
+{
+  while (tables_to_lock)
+  {
+    gptr to_free= reinterpret_cast<gptr>(tables_to_lock);
+    if (tables_to_lock->m_tabledef_valid)
+    {
+      tables_to_lock->m_tabledef.table_def::~table_def();
+      tables_to_lock->m_tabledef_valid= FALSE;
+    }
+    tables_to_lock=
+      static_cast<RPL_TABLE_LIST*>(tables_to_lock->next_global);
+    tables_to_lock_count--;
+    my_free(to_free, MYF(MY_WME));
+  }
+  DBUG_ASSERT(tables_to_lock == NULL && tables_to_lock_count == 0);
+}
+
 #endif

--- 1.11/sql/rpl_rli.h	2007-03-05 19:48:53 +01:00
+++ 1.12/sql/rpl_rli.h	2007-03-05 19:48:53 +01:00
@@ -20,6 +20,8 @@
 
 #include "rpl_tblmap.h"
 
+struct RPL_TABLE_LIST;
+
 
 /****************************************************************************
 
@@ -288,7 +290,7 @@
 	    group_relay_log_pos);
   }
 
-  TABLE_LIST *tables_to_lock;               /* RBR: Tables to lock  */
+  RPL_TABLE_LIST *tables_to_lock;           /* RBR: Tables to lock  */
   uint tables_to_lock_count;        /* RBR: Count of tables to lock */
   table_mapping m_table_map;      /* RBR: Mapping table-id to table */
 
@@ -302,16 +304,7 @@
   bool cached_charset_compare(char *charset) const;
 
   void cleanup_context(THD *, bool);
-  void clear_tables_to_lock() {
-    while (tables_to_lock)
-    {
-      char *to_free= reinterpret_cast<gptr>(tables_to_lock);
-      tables_to_lock= tables_to_lock->next_global;
-      tables_to_lock_count--;
-      my_free(to_free, MYF(MY_WME));
-    }
-    DBUG_ASSERT(tables_to_lock == NULL && tables_to_lock_count == 0);
-  }
+  void clear_tables_to_lock();
 
   /*
     Used by row-based replication to detect that it should not stop at

--- 1.10/sql/sql_binlog.cc	2007-03-05 19:48:53 +01:00
+++ 1.11/sql/sql_binlog.cc	2007-03-05 19:48:53 +01:00
@@ -171,7 +171,7 @@
         not used at all: the rli_fake instance is used only for error
         reporting.
        */
-      if (int err= ev->apply_event(thd->rli_fake))
+      if (IF_DBUG(int err= ) ev->apply_event(thd->rli_fake))
       {
         DBUG_PRINT("error", ("apply_event() returned: %d", err));
         /*

--- 1.4/sql/rpl_utility.h	2007-03-05 19:48:53 +01:00
+++ 1.5/sql/rpl_utility.h	2007-03-05 19:48:53 +01:00
@@ -22,104 +22,117 @@
 
 #include "mysql_priv.h"
 
+struct st_relay_log_info;
+typedef st_relay_log_info RELAY_LOG_INFO;
+
 uint32
-field_length_from_packed(enum_field_types const field_type, 
-                         byte const *const data);
+field_length_from_packed(enum_field_types field_type, byte const *data);
 
-/*
+/**
   A table definition from the master.
 
-  RESPONSIBILITIES
-
+  The responsibilities of this class is:
   - Extract and decode table definition data from the table map event
   - Check if table definition in table map is compatible with table
     definition on slave
 
-  DESCRIPTION
-
-    Currently, the only field type data available is an array of the
-    type operators that are present in the table map event.
+  Currently, the only field type data available is an array of the
+  type operators that are present in the table map event.
 
-  TODO
-
-    Add type operands to this structure to allow detection of
-    difference between, e.g., BIT(5) and BIT(10).
+  @todo Add type operands to this structure to allow detection of
+     difference between, e.g., BIT(5) and BIT(10).
  */
 
 class table_def
 {
 public:
-  /*
+  /**
     Convenience declaration of the type of the field type data in a
     table map event.
   */
   typedef unsigned char field_type;
 
-  /*
+  /**
     Constructor.
 
-    SYNOPSIS
-      table_def()
-      types Array of types
-      size  Number of elements in array 'types'
+    @param types Array of types
+    @param size  Number of elements in array 'types'
    */
   table_def(field_type *types, my_size_t size)
-    : m_type(types), m_size(size)
+    : m_type(new unsigned char [size]), m_size(size)
   {
+    if (m_type)
+      memcpy(m_type, types, size);
+    else
+      m_size= 0;
   }
 
-  /*
-    Return the number of fields there is type data for.
+  ~table_def() {
+    if (m_type)
+      delete [] m_type;
+#ifndef DBUG_OFF
+    m_type= 0;
+    m_size= 0;
+#endif
+  }
 
-    SYNOPSIS
-      size()
+  /**
+    Return the number of fields there is type data for.
 
-    RETURN VALUE
-      The number of fields that there is type data for.
+    @return The number of fields that there is type data for.
    */
   my_size_t size() const { return m_size; }
 
+
   /*
     Return a representation of the type data for one field.
 
-    SYNOPSIS
-      type()
-      i   Field index to return data for
+    @param index Field index to return data for
 
-    RETURN VALUE
-
-      Will return a representation of the type data for field
-      'i'. Currently, only the type identifier is returned.
+    @return Will return a representation of the type data for field
+    <code>index</code>. Currently, only the type identifier is
+    returned.
    */
-  field_type type(my_ptrdiff_t i) const { return m_type[i]; }
+  field_type type(my_ptrdiff_t index) const
+  {
+    DBUG_ASSERT(0 <= index);
+    DBUG_ASSERT(static_cast<my_size_t>(index) < m_size);
+    return m_type[index];
+  }
 
-  /*
+  /**
     Decide if the table definition is compatible with a table.
 
-    SYNOPSIS
-      compatible_with()
-      rli   Pointer to relay log info
-      table Pointer to table to compare with.
-
-    DESCRIPTION
-
-      Compare the definition with a table to see if it is compatible
-      with it.  A table definition is compatible with a table if:
+    Compare the definition with a table to see if it is compatible
+    with it.
 
+    A table definition is compatible with a table if:
       - the columns types of the table definition is a (not
         necessarily proper) prefix of the column type of the table, or
-
       - the other way around
 
-    RETURN VALUE
-      1  if the table definition is not compatible with 'table'
-      0  if the table definition is compatible with 'table'
+    @param rli   Pointer to relay log info
+    @param table Pointer to table to compare with.
+
+    @retval 1  if the table definition is not compatible with @c table
+    @retval 0  if the table definition is compatible with @c table
   */
   int compatible_with(RELAY_LOG_INFO const *rli, TABLE *table) const;
 
 private:
   my_size_t m_size;           // Number of elements in the types array
   field_type *m_type;                     // Array of type descriptors
+};
+
+/**
+   Extend the normal table list with a few new fields needed by the
+   slave thread, but nowhere else.
+ */
+struct RPL_TABLE_LIST
+  : public st_table_list
+{
+  bool m_tabledef_valid;
+  table_def m_tabledef;
 };
 
 #endif /* RPL_UTILITY_H */

--- 1.105/sql/slave.h	2007-03-05 19:48:53 +01:00
+++ 1.106/sql/slave.h	2007-03-05 19:48:53 +01:00
@@ -111,8 +111,6 @@
 #define MYSQL_SLAVE_RUN_NOT_CONNECT 1
 #define MYSQL_SLAVE_RUN_CONNECT     2
 
-static Log_event* next_event(RELAY_LOG_INFO* rli);
-
 #define RPL_LOG_NAME (rli->group_master_log_name[0] ? rli->group_master_log_name :\
  "FIRST")
 #define IO_RPL_LOG_NAME (mi->master_log_name[0] ? mi->master_log_name :\
Thread
bk commit into 5.1 tree (mats:1.2472)Mats Kindahl5 Mar