log_event.cc 61.1 KB
Newer Older
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


#ifndef MYSQL_CLIENT
#ifdef __GNUC__
#pragma implementation				// gcc: Class implementation
#endif
#include  "mysql_priv.h"
23
#include "slave.h"
24
#include <my_dir.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
25 26
#endif /* MYSQL_CLIENT */

27 28
#include <assert.h>

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
29 30 31 32 33
inline int my_b_safe_write(IO_CACHE* file, const byte *buf,
			   int len)
{
  /*
    Sasha: We are not writing this with the ? operator to avoid hitting
34 35 36
    a possible compiler bug. At least gcc 2.95 cannot deal with 
    several layers of ternary operators that evaluated comma(,) operator
    expressions inside - I do have a test case if somebody wants it
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
37
  */
38
  if (file->type == SEQ_READ_APPEND)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
39 40 41
    return my_b_append(file, buf,len);
  return my_b_write(file, buf,len);
}
42

43
#ifdef MYSQL_CLIENT
44
static void pretty_print_str(FILE* file, char* str, int len)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
45
{
46
  char* end = str + len;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
47
  fputc('\'', file);
48 49
  while (str < end)
  {
50
    char c;
51 52 53 54 55 56 57 58 59 60 61 62
    switch ((c=*str++)) {
    case '\n': fprintf(file, "\\n"); break;
    case '\r': fprintf(file, "\\r"); break;
    case '\\': fprintf(file, "\\\\"); break;
    case '\b': fprintf(file, "\\b"); break;
    case '\t': fprintf(file, "\\t"); break;
    case '\'': fprintf(file, "\\'"); break;
    case 0   : fprintf(file, "\\0"); break;
    default:
      fputc(c, file);
      break;
    }
63 64
  }
  fputc('\'', file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
65
}
66
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
67

68 69
#ifndef MYSQL_CLIENT

70 71 72 73 74
inline int ignored_error_code(int err_code)
{
  return use_slave_mask && bitmap_is_set(&slave_error_mask, err_code);
}

75

76
static void pretty_print_str(String* packet, char* str, int len)
77
{
78
  char* end = str + len;
79
  packet->append('\'');
80 81 82
  while (str < end)
  {
    char c;
83
    switch ((c=*str++)) {
84 85 86 87 88 89 90 91 92 93 94
    case '\n': packet->append( "\\n"); break;
    case '\r': packet->append( "\\r"); break;
    case '\\': packet->append( "\\\\"); break;
    case '\b': packet->append( "\\b"); break;
    case '\t': packet->append( "\\t"); break;
    case '\'': packet->append( "\\'"); break;
    case 0   : packet->append( "\\0"); break;
    default:
      packet->append((char)c);
      break;
    }
95 96 97 98
  }
  packet->append('\'');
}

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
99

100 101 102
static inline char* slave_load_file_stem(char*buf, uint file_id,
					 int event_server_id)
{
103
  fn_format(buf,"SQL_LOAD-",slave_load_tmpdir,"",0); /* 4+32); */
104 105 106 107 108 109 110 111
  buf = strend(buf);
  buf = int10_to_str(::server_id, buf, 10);
  *buf++ = '-';
  buf = int10_to_str(event_server_id, buf, 10);
  *buf++ = '-';
  return int10_to_str(file_id, buf, 10);
}

112 113 114 115
#endif

const char* Log_event::get_type_str()
{
116
  switch(get_type_code()) {
117 118 119 120 121 122
  case START_EVENT:  return "Start";
  case STOP_EVENT:   return "Stop";
  case QUERY_EVENT:  return "Query";
  case ROTATE_EVENT: return "Rotate";
  case INTVAR_EVENT: return "Intvar";
  case LOAD_EVENT:   return "Load";
123
  case NEW_LOAD_EVENT:   return "New_load";
124
  case SLAVE_EVENT:  return "Slave";
125 126 127 128
  case CREATE_FILE_EVENT: return "Create_file";
  case APPEND_BLOCK_EVENT: return "Append_block";
  case DELETE_FILE_EVENT: return "Delete_file";
  case EXEC_LOAD_EVENT: return "Exec_load";
129 130 131 132 133
  default: /* impossible */ return "Unknown";
  }
}

#ifndef MYSQL_CLIENT
134 135 136
Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
  :temp_buf(0), exec_time(0), cached_event_len(0), flags(flags_arg), 
   thd(thd_arg)
137
{
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
  server_id = thd->server_id;
  when = thd->start_time;
  log_pos = thd->log_pos;
  cache_stmt= (using_trans &&
	       (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)));
}


Log_event::Log_event()
  :temp_buf(0), exec_time(0), cached_event_len(0), flags(0), cache_stmt(0),
   thd(0)
{
  server_id = ::server_id;
  when = time(NULL);
  log_pos=0;
153
}
154

155 156 157 158 159 160 161 162
/*
  Delete all temporary files used for SQL_LOAD.

  TODO
  - When we get a 'server start' event, we should only remove
    the files associated with the server id that just started.
    Easily fixable by adding server_id as a prefix to the log files.
*/
163

164 165 166 167 168 169 170 171
static void cleanup_load_tmpdir()
{
  MY_DIR *dirp;
  FILEINFO *file;
  uint i;
  if (!(dirp=my_dir(slave_load_tmpdir,MYF(MY_WME))))
    return;

172
  for (i=0 ; i < (uint)dirp->number_off_files; i++)
173 174
  {
    file=dirp->dir_entry+i;
175
    if (is_prefix(file->name,"SQL_LOAD-"))
176
      my_delete(file->name, MYF(0));
177 178 179 180 181
  }

  my_dirend(dirp);
}

182 183
#endif

184
Log_event::Log_event(const char* buf, bool old_format)
185
  :temp_buf(0), cached_event_len(0), cache_stmt(0)
186 187 188
{
  when = uint4korr(buf);
  server_id = uint4korr(buf + SERVER_ID_OFFSET);
189 190
  if (old_format)
  {
191
    log_pos=0;
192 193 194 195
    flags=0;
  }
  else
  {
196
    log_pos = uint4korr(buf + LOG_POS_OFFSET);
197 198
    flags = uint2korr(buf + FLAGS_OFFSET);
  }
199 200 201 202 203 204 205 206
#ifndef MYSQL_CLIENT
  thd = 0;
#endif  
}


#ifndef MYSQL_CLIENT

207
int Log_event::exec_event(struct st_relay_log_info* rli)
208
{
209 210 211 212 213 214 215 216 217 218 219 220 221
  /*
    rli is null when (as far as I (Guilhem) know)
    the caller is
    Load_log_event::exec_event *and* that one is called from
    Execute_load_log_event::exec_event. 
    In this case, we don't do anything here ;
    Execute_load_log_event::exec_event will call Log_event::exec_event
    again later with the proper rli.
    Strictly speaking, if we were sure that rli is null
    only in the case discussed above, 'if (rli)' is useless here.
    But as we are not 100% sure, keep it for now.
  */
  if (rli)  
222
  {
223 224 225 226 227 228 229
    if (rli->inside_transaction)
      rli->inc_pending(get_event_len());
    else
    {
      rli->inc_pos(get_event_len(),log_pos);
      flush_relay_log_info(rli);
    }
230 231 232
  }
  return 0;
}
233 234 235 236 237 238 239 240

void Log_event::pack_info(String* packet)
{
  net_store_data(packet, "", 0);
}

void Query_log_event::pack_info(String* packet)
{
241 242 243
  char buf[256];
  String tmp(buf, sizeof(buf));
  tmp.length(0);
244
  if (db && db_len)
245 246 247 248 249 250
  {
   tmp.append("use ");
   tmp.append(db, db_len);
   tmp.append("; ", 2);
  }

251
  if (query && q_len)
252 253 254 255 256 257
    tmp.append(query, q_len);
  net_store_data(packet, (char*)tmp.ptr(), tmp.length());
}

void Start_log_event::pack_info(String* packet)
{
258 259 260
  char buf1[256];
  String tmp(buf1, sizeof(buf1));
  tmp.length(0);
261 262 263 264 265 266 267 268 269 270 271
  char buf[22];

  tmp.append("Server ver: ");
  tmp.append(server_version);
  tmp.append(", Binlog ver: ");
  tmp.append(llstr(binlog_version, buf));
  net_store_data(packet, tmp.ptr(), tmp.length());
}

void Load_log_event::pack_info(String* packet)
{
272 273 274
  char buf[256];
  String tmp(buf, sizeof(buf));
  tmp.length(0);
275
  if (db && db_len)
276 277 278 279 280 281 282
  {
   tmp.append("use ");
   tmp.append(db, db_len);
   tmp.append("; ", 2);
  }

  tmp.append("LOAD DATA INFILE '");
283
  tmp.append(fname, fname_len);
284
  tmp.append("' ", 2);
285
  if (sql_ex.opt_flags & REPLACE_FLAG)
286
    tmp.append(" REPLACE ");
287
  else if (sql_ex.opt_flags & IGNORE_FLAG)
288 289 290 291
    tmp.append(" IGNORE ");
  
  tmp.append("INTO TABLE ");
  tmp.append(table_name);
292
  if (sql_ex.field_term_len)
293 294
  {
    tmp.append(" FIELDS TERMINATED BY ");
295
    pretty_print_str(&tmp, sql_ex.field_term, sql_ex.field_term_len);
296 297
  }

298
  if (sql_ex.enclosed_len)
299
  {
300
    if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG )
301 302
      tmp.append(" OPTIONALLY ");
    tmp.append( " ENCLOSED BY ");
303
    pretty_print_str(&tmp, sql_ex.enclosed, sql_ex.enclosed_len);
304 305
  }
     
306
  if (sql_ex.escaped_len)
307 308
  {
    tmp.append( " ESCAPED BY ");
309
    pretty_print_str(&tmp, sql_ex.escaped, sql_ex.escaped_len);
310 311
  }
     
312
  bool line_lexem_added= false;
313
  if (sql_ex.line_term_len)
314 315
  {
    tmp.append(" LINES TERMINATED BY ");
316
    pretty_print_str(&tmp, sql_ex.line_term, sql_ex.line_term_len);
317
    line_lexem_added= true;
318 319
  }

320
  if (sql_ex.line_start_len)
321
  {
322 323 324
    if (!line_lexem_added)
      tmp.append(" LINES");
    tmp.append(" STARTING BY ");
325
    pretty_print_str(&tmp, sql_ex.line_start, sql_ex.line_start_len);
326 327 328 329 330 331 332 333 334 335
  }
     
  if ((int)skip_lines > 0)
    tmp.append( " IGNORE %ld LINES ", (long) skip_lines);

  if (num_fields)
  {
    uint i;
    const char* field = fields;
    tmp.append(" (");
336
    for (i = 0; i < num_fields; i++)
337
    {
338
      if (i)
339 340 341 342 343 344 345 346 347 348 349 350 351
	tmp.append(" ,");
      tmp.append( field);
	  
      field += field_lens[i]  + 1;
    }
    tmp.append(')');
  }

  net_store_data(packet, tmp.ptr(), tmp.length());
}

void Rotate_log_event::pack_info(String* packet)
{
352
  char buf1[256], buf[22];
353 354
  String tmp(buf1, sizeof(buf1));
  tmp.length(0);
355
  tmp.append(new_log_ident, ident_len);
356 357
  tmp.append(";pos=");
  tmp.append(llstr(pos,buf));
358
  if (flags & LOG_EVENT_FORCED_ROTATE_F)
359 360
    tmp.append("; forced by master");
  net_store_data(packet, tmp.ptr(), tmp.length());
361 362 363 364
}

void Intvar_log_event::pack_info(String* packet)
{
365
  char buf1[256], buf[22];
366 367
  String tmp(buf1, sizeof(buf1));
  tmp.length(0);
368 369 370 371 372 373
  tmp.append(get_var_type_name());
  tmp.append('=');
  tmp.append(llstr(val, buf));
  net_store_data(packet, tmp.ptr(), tmp.length());
}

nick@mysql.com's avatar
nick@mysql.com committed
374 375
void Rand_log_event::pack_info(String* packet)
{
376 377 378 379 380 381
  char buf1[256], *pos;
  pos=strmov(buf1,"rand_seed1=");
  pos=int10_to_str((long) seed1, pos, 10);
  pos=strmov(pos, ",rand_seed2=");
  pos=int10_to_str((long) seed2, pos, 10);
  net_store_data(packet, buf1, (uint) (pos-buf1));
nick@mysql.com's avatar
nick@mysql.com committed
382 383
}

384 385
void Slave_log_event::pack_info(String* packet)
{
386
  char buf1[256], buf[22], *end;
387 388
  String tmp(buf1, sizeof(buf1));
  tmp.length(0);
389 390 391
  tmp.append("host=");
  tmp.append(master_host);
  tmp.append(",port=");
392 393
  end= int10_to_str((long) master_port, buf, 10);
  tmp.append(buf, (uint32) (end-buf));
394 395 396 397 398
  tmp.append(",log=");
  tmp.append(master_log);
  tmp.append(",pos=");
  tmp.append(llstr(master_pos,buf));
  net_store_data(packet, tmp.ptr(), tmp.length());
399 400 401 402 403 404 405 406 407
}


void Log_event::init_show_field_list(List<Item>* field_list)
{
  field_list->push_back(new Item_empty_string("Log_name", 20));
  field_list->push_back(new Item_empty_string("Pos", 20));
  field_list->push_back(new Item_empty_string("Event_type", 20));
  field_list->push_back(new Item_empty_string("Server_id", 20));
408
  field_list->push_back(new Item_empty_string("Orig_log_pos", 20));
409 410 411
  field_list->push_back(new Item_empty_string("Info", 20));
}

nick@mysql.com's avatar
nick@mysql.com committed
412 413 414
/*
 * only called by SHOW BINLOG EVENTS
 */
415
int Log_event::net_send(THD* thd_arg, const char* log_name, my_off_t pos)
416
{
417
  String* packet = &thd_arg->packet;
418 419 420 421 422 423 424
  const char* p = strrchr(log_name, FN_LIBCHAR);
  const char* event_type;
  if (p)
    log_name = p + 1;
  
  packet->length(0);
  net_store_data(packet, log_name, strlen(log_name));
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
425
  net_store_data(packet, (longlong) pos);
426 427 428
  event_type = get_type_str();
  net_store_data(packet, event_type, strlen(event_type));
  net_store_data(packet, server_id);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
429
  net_store_data(packet, (longlong) log_pos);
430
  pack_info(packet);
431
  return my_net_write(&thd_arg->net, (char*) packet->ptr(), packet->length());
432 433
}

434 435
#endif /* MYSQL_CLIENT */

436

437
int Query_log_event::write(IO_CACHE* file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
438 439 440 441
{
  return query ? Log_event::write(file) : -1; 
}

442

443
int Log_event::write(IO_CACHE* file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
444
{
445
  return (write_header(file) || write_data(file)) ? -1 : 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
446 447
}

448

449
int Log_event::write_header(IO_CACHE* file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
450
{
451
  char buf[LOG_EVENT_HEADER_LEN];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
452
  char* pos = buf;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
453
  int4store(pos, (ulong) when); // timestamp
bk@work.mysql.com's avatar
bk@work.mysql.com committed
454 455
  pos += 4;
  *pos++ = get_type_code(); // event type code
456 457
  int4store(pos, server_id);
  pos += 4;
458 459
  long tmp=get_data_size() + LOG_EVENT_HEADER_LEN;
  int4store(pos, tmp);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
460
  pos += 4;
461
  int4store(pos, log_pos);
462 463 464
  pos += 4;
  int2store(pos, flags);
  pos += 2;
465
  return (my_b_safe_write(file, (byte*) buf, (uint) (pos - buf)));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
466 467 468 469
}

#ifndef MYSQL_CLIENT

470
int Log_event::read_log_event(IO_CACHE* file, String* packet,
471
			      pthread_mutex_t* log_lock)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
472 473
{
  ulong data_len;
474
  int result=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
475
  char buf[LOG_EVENT_HEADER_LEN];
476
  DBUG_ENTER("read_log_event");
477

478
  if (log_lock)
479
    pthread_mutex_lock(log_lock);
480 481
  if (my_b_read(file, (byte*) buf, sizeof(buf)))
  {
482 483 484 485 486
    /*
      If the read hits eof, we must report it as eof so the caller
      will know it can go into cond_wait to be woken up on the next
      update to the log.
    */
487
    DBUG_PRINT("error",("file->error: %d", file->error));
488 489 490
    if (!file->error)
      result= LOG_READ_EOF;
    else
491
      result= (file->error > 0 ? LOG_READ_TRUNC : LOG_READ_IO);
492
    goto end;
493
  }
494
  data_len= uint4korr(buf + EVENT_LEN_OFFSET);
495 496
  if (data_len < LOG_EVENT_HEADER_LEN ||
      data_len > current_thd->variables.max_allowed_packet)
497
  {
498
    DBUG_PRINT("error",("data_len: %ld", data_len));
499 500 501
    result= ((data_len < LOG_EVENT_HEADER_LEN) ? LOG_READ_BOGUS :
	     LOG_READ_TOO_LARGE);
    goto end;
502
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
503
  packet->append(buf, sizeof(buf));
504
  data_len-= LOG_EVENT_HEADER_LEN;
505 506 507
  if (data_len)
  {
    if (packet->append(file, data_len))
508
    {
509
      /*
510 511
	Here we should never hit EOF in a non-error condition.
	EOF means we are reading the event partially, which should
512 513 514 515
	never happen.
      */
      result= file->error >= 0 ? LOG_READ_TRUNC: LOG_READ_IO;
      /* Implicit goto end; */
516
    }
517
  }
518 519 520 521

end:
  if (log_lock)
    pthread_mutex_unlock(log_lock);
522
  DBUG_RETURN(result);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
523 524 525 526
}

#endif // MYSQL_CLIENT

527
#ifndef MYSQL_CLIENT
528 529
#define UNLOCK_MUTEX if (log_lock) pthread_mutex_unlock(log_lock);
#define LOCK_MUTEX if (log_lock) pthread_mutex_lock(log_lock);
530
#define max_allowed_packet current_thd->variables.max_allowed_packet
531
#else
532
#define UNLOCK_MUTEX
533 534 535
#define LOCK_MUTEX
#endif

536 537
// allocates memory - the caller is responsible for clean-up
#ifndef MYSQL_CLIENT
538 539 540
Log_event* Log_event::read_log_event(IO_CACHE* file,
				     pthread_mutex_t* log_lock,
				     bool old_format)
541
#else
542
Log_event* Log_event::read_log_event(IO_CACHE* file, bool old_format)
543
#endif  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
544
{
545
  char head[LOG_EVENT_HEADER_LEN];
546 547
  uint header_size= old_format ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;

548
  LOCK_MUTEX;
549
  if (my_b_read(file, (byte *) head, header_size))
550
  {
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
551
    UNLOCK_MUTEX;
552
    return 0;
553
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
554

555
  uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
556 557 558
  char *buf= 0;
  const char *error= 0;
  Log_event *res=  0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
559

560
  if (data_len > max_allowed_packet)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
561
  {
562 563
    error = "Event too big";
    goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
564 565
  }

566
  if (data_len < header_size)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
567
  {
568 569
    error = "Event too small";
    goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
570
  }
571 572 573

  // some events use the extra byte to null-terminate strings
  if (!(buf = my_malloc(data_len+1, MYF(MY_WME))))
574 575 576
  {
    error = "Out of memory";
    goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
577
  }
578
  buf[data_len] = 0;
579
  memcpy(buf, head, header_size);
580
  if (my_b_read(file, (byte*) buf + header_size, data_len - header_size))
581 582 583 584
  {
    error = "read error";
    goto err;
  }
585
  if ((res = read_log_event(buf, data_len, &error, old_format)))
586
    res->register_temp_buf(buf);
587

588
err:
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
589
  UNLOCK_MUTEX;
590
  if (error)
591
  {
592 593
    sql_print_error("Error in Log_event::read_log_event(): '%s', \
data_len=%d,event_type=%d",error,data_len,head[EVENT_TYPE_OFFSET]);
594
    my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
595 596 597 598 599 600 601 602 603
    /*
      The SQL slave thread will check if file->error<0 to know
      if there was an I/O error. Even if there is no "low-level" I/O errors
      with 'file', any of the high-level above errors is worrying
      enough to stop the SQL thread now ; as we are skipping the current event,
      going on with reading and successfully executing other events can
      only corrupt the slave's databases. So stop.
    */
    file->error= -1;
604
  }
605
  return res;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
606 607
}

608

609
Log_event* Log_event::read_log_event(const char* buf, int event_len,
610
				     const char **error, bool old_format)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
611
{
612
  if (event_len < EVENT_LEN_OFFSET ||
613 614 615
      (uint) event_len != uint4korr(buf+EVENT_LEN_OFFSET))
  {
    *error="Sanity check failed";		// Needed to free buffer
616
    return NULL; // general sanity check - will fail on a partial read
617
  }
618
  
619 620
  Log_event* ev = NULL;
  
621
  switch(buf[EVENT_TYPE_OFFSET]) {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
622
  case QUERY_EVENT:
623
    ev  = new Query_log_event(buf, event_len, old_format);
624
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
625
  case LOAD_EVENT:
626 627
    ev = new Create_file_log_event(buf, event_len, old_format);
    break;
628
  case NEW_LOAD_EVENT:
629
    ev = new Load_log_event(buf, event_len, old_format);
630
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
631
  case ROTATE_EVENT:
632
    ev = new Rotate_log_event(buf, event_len, old_format);
633
    break;
634
  case SLAVE_EVENT:
635 636 637
    ev = new Slave_log_event(buf, event_len);
    break;
  case CREATE_FILE_EVENT:
638
    ev = new Create_file_log_event(buf, event_len, old_format);
639 640 641 642 643 644 645 646 647 648 649
    break;
  case APPEND_BLOCK_EVENT:
    ev = new Append_block_log_event(buf, event_len);
    break;
  case DELETE_FILE_EVENT:
    ev = new Delete_file_log_event(buf, event_len);
    break;
  case EXEC_LOAD_EVENT:
    ev = new Execute_load_log_event(buf, event_len);
    break;
  case START_EVENT:
650
    ev = new Start_log_event(buf, old_format);
651 652
    break;
  case STOP_EVENT:
653
    ev = new Stop_log_event(buf, old_format);
654 655
    break;
  case INTVAR_EVENT:
656
    ev = new Intvar_log_event(buf, old_format);
657
    break;
nick@mysql.com's avatar
nick@mysql.com committed
658 659 660
  case RAND_EVENT:
    ev = new Rand_log_event(buf, old_format);
    break;
661 662
  default:
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
663
  }
664
  if (!ev || !ev->is_valid())
665 666
  {
    delete ev;
667 668 669 670 671 672 673 674 675
#ifdef MYSQL_CLIENT
    if (!force_opt)
    {
      *error= "Found invalid event in binary log";
      return 0;
    }
    ev= new Unknown_log_event(buf, old_format);
#else
    *error= "Found invalid event in binary log";
676
    return 0;
677
#endif
678 679 680
  }
  ev->cached_event_len = event_len;
  return ev;  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
681 682
}

683

684
#ifdef MYSQL_CLIENT
685 686
void Log_event::print_header(FILE* file)
{
687
  char llbuff[22];
688 689
  fputc('#', file);
  print_timestamp(file);
690
  fprintf(file, " server id %d  log_pos %s ", server_id,
691
	  llstr(log_pos,llbuff)); 
692 693
}

694
void Log_event::print_timestamp(FILE* file, time_t* ts)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
695
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
696
  struct tm *res;
697 698
  if (!ts)
    ts = &when;
699 700
#ifdef MYSQL_SERVER				// This is always false
  struct tm tm_tmp;
monty@work.mysql.com's avatar
monty@work.mysql.com committed
701
  localtime_r(ts,(res= &tm_tmp));
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
702
#else
703
  res=localtime(ts);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
704
#endif
705 706

  fprintf(file,"%02d%02d%02d %2d:%02d:%02d",
707 708 709 710 711 712
	  res->tm_year % 100,
	  res->tm_mon+1,
	  res->tm_mday,
	  res->tm_hour,
	  res->tm_min,
	  res->tm_sec);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
713 714 715
}


716
void Start_log_event::print(FILE* file, bool short_form, char* last_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
717 718 719 720
{
  if (short_form)
    return;

721 722 723
  print_header(file);
  fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version,
	  server_version);
724
  print_timestamp(file, &created);
725
  fputc('\n', file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
726 727 728
  fflush(file);
}

729
void Stop_log_event::print(FILE* file, bool short_form, char* last_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
730 731 732 733
{
  if (short_form)
    return;

734
  print_header(file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
735 736 737 738
  fprintf(file, "\tStop\n");
  fflush(file);
}

739
void Rotate_log_event::print(FILE* file, bool short_form, char* last_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
740
{
741
  char buf[22];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
742 743 744
  if (short_form)
    return;

745
  print_header(file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
746 747 748 749
  fprintf(file, "\tRotate to ");
  if (new_log_ident)
    my_fwrite(file, (byte*) new_log_ident, (uint)ident_len, 
	      MYF(MY_NABP | MY_WME));
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
750 751 752 753
  fprintf(file, "  pos: %s", llstr(pos, buf));
  if (flags & LOG_EVENT_FORCED_ROTATE_F)
    fprintf(file,"  forced by master");
  fputc('\n', file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
754 755 756
  fflush(file);
}

757 758
#endif /* #ifdef MYSQL_CLIENT */

759

760
Start_log_event::Start_log_event(const char* buf,
761 762
				 bool old_format)
  :Log_event(buf, old_format)
763
{
764 765 766
  buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
  binlog_version = uint2korr(buf+ST_BINLOG_VER_OFFSET);
  memcpy(server_version, buf+ST_SERVER_VER_OFFSET,
767
	 ST_SERVER_VER_LEN);
768
  created = uint4korr(buf+ST_CREATED_OFFSET);
769 770
}

771 772
int Start_log_event::write_data(IO_CACHE* file)
{
773 774 775 776
  char buff[START_HEADER_LEN];
  int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
  memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
  int4store(buff + ST_CREATED_OFFSET,created);
777
  return (my_b_safe_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0);
778 779
}

780

781
Rotate_log_event::Rotate_log_event(const char* buf, int event_len,
782 783
				   bool old_format)
  :Log_event(buf, old_format),new_log_ident(NULL),alloced(0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
784
{
785
  // The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET
786 787
  int header_size = (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
  uint ident_offset;
788
  if (event_len < header_size)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
789
    return;
790 791 792
  buf += header_size;
  if (old_format)
  {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
793
    ident_len = (uint)(event_len - OLD_HEADER_LEN);
794 795 796 797 798
    pos = 4;
    ident_offset = 0;
  }
  else
  {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
799
    ident_len = (uint)(event_len - ROTATE_EVENT_OVERHEAD);
800 801 802
    pos = uint8korr(buf + R_POS_OFFSET);
    ident_offset = ROTATE_HEADER_LEN;
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
803
  set_if_smaller(ident_len,FN_REFLEN-1);
804 805 806 807
  if (!(new_log_ident= my_strdup_with_length((byte*) buf +
					     ident_offset,
					     (uint) ident_len,
					     MYF(MY_WME))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
808 809 810 811
    return;
  alloced = 1;
}

812

813
int Rotate_log_event::write_data(IO_CACHE* file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
814
{
815 816
  char buf[ROTATE_HEADER_LEN];
  int8store(buf, pos + R_POS_OFFSET);
817 818
  return (my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) ||
	  my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
819 820
}

821

822 823
#ifndef MYSQL_CLIENT
Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
824
				 ulong query_length, bool using_trans)
825 826
  :Log_event(thd_arg, 0, using_trans), data_buf(0), query(query_arg),
   db(thd_arg->db), q_len((uint32) query_length),
827
  error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno),
828
  thread_id(thd_arg->thread_id)
829 830 831 832 833 834
{
  time_t end_time;
  time(&end_time);
  exec_time = (ulong) (end_time  - thd->start_time);
  db_len = (db) ? (uint32) strlen(db) : 0;
}
835 836
#endif

837
Query_log_event::Query_log_event(const char* buf, int event_len,
838 839
				 bool old_format)
  :Log_event(buf, old_format),data_buf(0), query(NULL), db(NULL)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
840 841
{
  ulong data_len;
842 843 844 845 846 847 848 849 850 851 852 853 854 855
  if (old_format)
  {
    if ((uint)event_len < OLD_HEADER_LEN + QUERY_HEADER_LEN)
      return;				
    data_len = event_len - (QUERY_HEADER_LEN + OLD_HEADER_LEN);
    buf += OLD_HEADER_LEN;
  }
  else
  {
    if ((uint)event_len < QUERY_EVENT_OVERHEAD)
      return;				
    data_len = event_len - QUERY_EVENT_OVERHEAD;
    buf += LOG_EVENT_HEADER_LEN;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
856

857 858
  exec_time = uint4korr(buf + Q_EXEC_TIME_OFFSET);
  error_code = uint2korr(buf + Q_ERR_CODE_OFFSET);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
859

860
  if (!(data_buf = (char*) my_malloc(data_len + 1, MYF(MY_WME))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
861 862
    return;

863 864
  memcpy(data_buf, buf + Q_DATA_OFFSET, data_len);
  thread_id = uint4korr(buf + Q_THREAD_ID_OFFSET);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
865
  db = data_buf;
866
  db_len = (uint)buf[Q_DB_LEN_OFFSET];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
867 868 869 870 871
  query=data_buf + db_len + 1;
  q_len = data_len - 1 - db_len;
  *((char*)query+q_len) = 0;
}

872

873 874
#ifdef MYSQL_CLIENT

875
void Query_log_event::print(FILE* file, bool short_form, char* last_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
876
{
877
  char buff[40],*end;				// Enough for SET TIMESTAMP
bk@work.mysql.com's avatar
bk@work.mysql.com committed
878 879
  if (!short_form)
  {
880
    print_header(file);
881 882
    fprintf(file, "\tQuery\tthread_id=%lu\texec_time=%lu\terror_code=%d\n",
	    (ulong) thread_id, (ulong) exec_time, error_code);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
883 884
  }

885 886
  bool same_db = 0;

887
  if (db && last_db)
888 889 890 891
  {
    if (!(same_db = !memcmp(last_db, db, db_len + 1)))
      memcpy(last_db, db, db_len + 1);
  }
892 893
  
  if (db && db[0] && !same_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
894
    fprintf(file, "use %s;\n", db);
895 896 897 898
  end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10);
  *end++=';';
  *end++='\n';
  my_fwrite(file, (byte*) buff, (uint) (end-buff),MYF(MY_NABP | MY_WME));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
899 900 901
  my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
  fprintf(file, ";\n");
}
902 903
#endif

904

905
int Query_log_event::write_data(IO_CACHE* file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
906
{
907 908
  if (!query)
    return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
909 910
  
  char buf[QUERY_HEADER_LEN]; 
911 912
  int4store(buf + Q_THREAD_ID_OFFSET, thread_id);
  int4store(buf + Q_EXEC_TIME_OFFSET, exec_time);
913
  buf[Q_DB_LEN_OFFSET] = (char) db_len;
914
  int2store(buf + Q_ERR_CODE_OFFSET, error_code);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
915

916 917 918
  return (my_b_safe_write(file, (byte*) buf, QUERY_HEADER_LEN) ||
	  my_b_safe_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) ||
	  my_b_safe_write(file, (byte*) query, q_len)) ? -1 : 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
919 920
}

921 922
Intvar_log_event::Intvar_log_event(const char* buf, bool old_format)
  :Log_event(buf, old_format)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
923
{
924
  buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
925 926
  type = buf[I_TYPE_OFFSET];
  val = uint8korr(buf+I_VAL_OFFSET);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
927 928
}

929 930
const char* Intvar_log_event::get_var_type_name()
{
931
  switch(type) {
932 933 934 935 936 937
  case LAST_INSERT_ID_EVENT: return "LAST_INSERT_ID";
  case INSERT_ID_EVENT: return "INSERT_ID";
  default: /* impossible */ return "UNKNOWN";
  }
}

938
int Intvar_log_event::write_data(IO_CACHE* file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
939 940
{
  char buf[9];
941 942
  buf[I_TYPE_OFFSET] = type;
  int8store(buf + I_VAL_OFFSET, val);
943
  return my_b_safe_write(file, (byte*) buf, sizeof(buf));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
944 945
}

946
#ifdef MYSQL_CLIENT
947
void Intvar_log_event::print(FILE* file, bool short_form, char* last_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
948 949
{
  char llbuff[22];
950 951 952
  const char *msg;
  LINT_INIT(msg);

953
  if (!short_form)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
954
  {
955
    print_header(file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
956 957 958 959
    fprintf(file, "\tIntvar\n");
  }

  fprintf(file, "SET ");
960
  switch (type) {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
961
  case LAST_INSERT_ID_EVENT:
962
    msg="LAST_INSERT_ID";
bk@work.mysql.com's avatar
bk@work.mysql.com committed
963 964
    break;
  case INSERT_ID_EVENT:
965
    msg="INSERT_ID";
bk@work.mysql.com's avatar
bk@work.mysql.com committed
966 967
    break;
  }
968
  fprintf(file, "%s=%s;\n", msg, llstr(val,llbuff));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
969 970
  fflush(file);
}
971
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
972

nick@mysql.com's avatar
nick@mysql.com committed
973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996
/*****************************************************************************
 *
 *  Rand log event
 *
 ****************************************************************************/
Rand_log_event::Rand_log_event(const char* buf, bool old_format)
  :Log_event(buf, old_format)
{
  buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
  seed1 = uint8korr(buf+RAND_SEED1_OFFSET);
  seed2 = uint8korr(buf+RAND_SEED2_OFFSET);
}

int Rand_log_event::write_data(IO_CACHE* file)
{
  char buf[16];
  int8store(buf + RAND_SEED1_OFFSET, seed1);
  int8store(buf + RAND_SEED2_OFFSET, seed2);
  return my_b_safe_write(file, (byte*) buf, sizeof(buf));
}

#ifdef MYSQL_CLIENT
void Rand_log_event::print(FILE* file, bool short_form, char* last_db)
{
997
  char llbuff[22],llbuff2[22];
nick@mysql.com's avatar
nick@mysql.com committed
998 999 1000 1001 1002
  if (!short_form)
  {
    print_header(file);
    fprintf(file, "\tRand\n");
  }
1003
  fprintf(file, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s;\n",
1004
	  llstr(seed1, llbuff),llstr(seed2, llbuff2));
nick@mysql.com's avatar
nick@mysql.com committed
1005 1006 1007
  fflush(file);
}
#endif
1008

1009
int Load_log_event::write_data_header(IO_CACHE* file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1010 1011
{
  char buf[LOAD_HEADER_LEN];
1012 1013 1014 1015 1016 1017
  int4store(buf + L_THREAD_ID_OFFSET, thread_id);
  int4store(buf + L_EXEC_TIME_OFFSET, exec_time);
  int4store(buf + L_SKIP_LINES_OFFSET, skip_lines);
  buf[L_TBL_LEN_OFFSET] = (char)table_name_len;
  buf[L_DB_LEN_OFFSET] = (char)db_len;
  int4store(buf + L_NUM_FIELDS_OFFSET, num_fields);
1018
  return my_b_safe_write(file, (byte*)buf, LOAD_HEADER_LEN);
1019
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1020

1021 1022
int Load_log_event::write_data_body(IO_CACHE* file)
{
1023 1024
  if (sql_ex.write_data(file))
    return 1;
1025 1026
  if (num_fields && fields && field_lens)
  {
1027 1028
    if (my_b_safe_write(file, (byte*)field_lens, num_fields) ||
	my_b_safe_write(file, (byte*)fields, field_block_len))
1029 1030
      return 1;
  }
1031 1032 1033
  return (my_b_safe_write(file, (byte*)table_name, table_name_len + 1) ||
	  my_b_safe_write(file, (byte*)db, db_len + 1) ||
	  my_b_safe_write(file, (byte*)fname, fname_len));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1034 1035
}

1036

1037

1038 1039
static bool write_str(IO_CACHE *file, char *str, byte length)
{
1040 1041
  return (my_b_safe_write(file, &length, 1) ||
	  my_b_safe_write(file, (byte*) str, (int) length));
1042
}
1043

1044

1045 1046 1047 1048
int sql_ex_info::write_data(IO_CACHE* file)
{
  if (new_format())
  {
1049 1050 1051 1052 1053
    return (write_str(file, field_term, field_term_len) ||
	    write_str(file, enclosed,   enclosed_len) ||
	    write_str(file, line_term,  line_term_len) ||
	    write_str(file, line_start, line_start_len) ||
	    write_str(file, escaped,    escaped_len) ||
1054
	    my_b_safe_write(file,(byte*) &opt_flags,1));
1055 1056 1057 1058
  }
  else
  {
    old_sql_ex old_ex;
1059 1060 1061 1062 1063 1064 1065
    old_ex.field_term= *field_term;
    old_ex.enclosed=   *enclosed;
    old_ex.line_term=  *line_term;
    old_ex.line_start= *line_start;
    old_ex.escaped=    *escaped;
    old_ex.opt_flags=  opt_flags;
    old_ex.empty_flags=empty_flags;
1066
    return my_b_safe_write(file, (byte*) &old_ex, sizeof(old_ex));
1067 1068 1069
  }
}

1070

1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
static inline int read_str(char * &buf, char *buf_end, char * &str,
			   uint8 &len)
{
  if (buf + (uint) (uchar) *buf >= buf_end)
    return 1;
  len = (uint8) *buf;
  str= buf+1;
  buf+= (uint) len+1;
  return 0;
}
1081

1082

1083 1084 1085 1086 1087
char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format)
{
  cached_new_format = use_new_format;
  if (use_new_format)
  {
1088
    empty_flags=0;
1089 1090 1091 1092 1093 1094
    /*
      The code below assumes that buf will not disappear from
      under our feet during the lifetime of the event. This assumption
      holds true in the slave thread if the log is in new format, but is not
      the case when we have old format because we will be reusing net buffer
      to read the actual file before we write out the Create_file event.
1095
    */
1096 1097 1098 1099 1100 1101
    if (read_str(buf, buf_end, field_term, field_term_len) ||
	read_str(buf, buf_end, enclosed,   enclosed_len) ||
	read_str(buf, buf_end, line_term,  line_term_len) ||
	read_str(buf, buf_end, line_start, line_start_len) ||
	read_str(buf, buf_end, escaped,	   escaped_len))
      return 0;
1102 1103 1104 1105
    opt_flags = *buf++;
  }
  else
  {
1106
    field_term_len= enclosed_len= line_term_len= line_start_len= escaped_len=1;
1107 1108 1109 1110 1111 1112 1113
    field_term = buf++;			// Use first byte in string
    enclosed=	 buf++;
    line_term=   buf++;
    line_start=  buf++;
    escaped=     buf++;
    opt_flags =  *buf++;
    empty_flags= *buf++;
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
    if (empty_flags & FIELD_TERM_EMPTY)
      field_term_len=0;
    if (empty_flags & ENCLOSED_EMPTY)
      enclosed_len=0;
    if (empty_flags & LINE_TERM_EMPTY)
      line_term_len=0;
    if (empty_flags & LINE_START_EMPTY)
      line_start_len=0;
    if (empty_flags & ESCAPED_EMPTY)
      escaped_len=0;
1124 1125 1126 1127 1128
  }
  return buf;
}


1129
#ifndef MYSQL_CLIENT
1130
Load_log_event::Load_log_event(THD* thd_arg, sql_exchange* ex,
1131
			       const char* db_arg, const char* table_name_arg,
1132
			       List<Item>& fields_arg,
1133 1134
			       enum enum_duplicates handle_dup,
			       bool using_trans)
monty@butch's avatar
merge  
monty@butch committed
1135
  :Log_event(thd_arg, 0, using_trans),thread_id(thd_arg->thread_id),
1136
  num_fields(0),fields(0),
1137 1138
  field_lens(0),field_block_len(0),
  table_name(table_name_arg ? table_name_arg : ""),
1139
  db(db_arg), fname(ex->file_name)
1140 1141 1142
{
  time_t end_time;
  time(&end_time);
1143
  exec_time = (ulong) (end_time  - thd_arg->start_time);
1144 1145 1146
  /* db can never be a zero pointer in 4.0 */
  db_len = (uint32) strlen(db);
  table_name_len = (uint32) strlen(table_name);
1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159
  fname_len = (fname) ? (uint) strlen(fname) : 0;
  sql_ex.field_term = (char*) ex->field_term->ptr();
  sql_ex.field_term_len = (uint8) ex->field_term->length();
  sql_ex.enclosed = (char*) ex->enclosed->ptr();
  sql_ex.enclosed_len = (uint8) ex->enclosed->length();
  sql_ex.line_term = (char*) ex->line_term->ptr();
  sql_ex.line_term_len = (uint8) ex->line_term->length();
  sql_ex.line_start = (char*) ex->line_start->ptr();
  sql_ex.line_start_len = (uint8) ex->line_start->length();
  sql_ex.escaped = (char*) ex->escaped->ptr();
  sql_ex.escaped_len = (uint8) ex->escaped->length();
  sql_ex.opt_flags = 0;
  sql_ex.cached_new_format = -1;
1160
    
1161
  if (ex->dumpfile)
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1162
    sql_ex.opt_flags|= DUMPFILE_FLAG;
1163
  if (ex->opt_enclosed)
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1164
    sql_ex.opt_flags|= OPT_ENCLOSED_FLAG;
1165

1166
  sql_ex.empty_flags = 0;
1167

1168
  switch (handle_dup) {
1169 1170
  case DUP_IGNORE: sql_ex.opt_flags|= IGNORE_FLAG; break;
  case DUP_REPLACE: sql_ex.opt_flags|= REPLACE_FLAG; break;
1171 1172
  case DUP_ERROR: break;	
  }
1173

1174
  if (!ex->field_term->length())
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1175
    sql_ex.empty_flags|= FIELD_TERM_EMPTY;
1176
  if (!ex->enclosed->length())
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1177
    sql_ex.empty_flags|= ENCLOSED_EMPTY;
1178
  if (!ex->line_term->length())
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1179
    sql_ex.empty_flags|= LINE_TERM_EMPTY;
1180
  if (!ex->line_start->length())
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1181
    sql_ex.empty_flags|= LINE_START_EMPTY;
1182
  if (!ex->escaped->length())
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1183
    sql_ex.empty_flags|= ESCAPED_EMPTY;
1184
    
1185
  skip_lines = ex->skip_lines;
1186

1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
  List_iterator<Item> li(fields_arg);
  field_lens_buf.length(0);
  fields_buf.length(0);
  Item* item;
  while ((item = li++))
  {
    num_fields++;
    uchar len = (uchar) strlen(item->name);
    field_block_len += len + 1;
    fields_buf.append(item->name, len + 1);
    field_lens_buf.append((char*)&len, 1);
1198 1199
  }

1200 1201 1202 1203
  field_lens = (const uchar*)field_lens_buf.ptr();
  fields = fields_buf.ptr();
}

1204 1205
#endif

1206 1207 1208 1209 1210
/*
  The caller must do buf[event_len] = 0 before he starts using the
  constructed event.
*/

1211
Load_log_event::Load_log_event(const char* buf, int event_len,
1212 1213
			       bool old_format)
  :Log_event(buf, old_format),num_fields(0),fields(0),
1214
  field_lens(0),field_block_len(0),
1215
  table_name(0),db(0),fname(0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1216
{
1217
  if (!event_len) // derived class, will call copy_log_event() itself
1218
    return;
1219
  copy_log_event(buf, event_len, old_format);
1220 1221
}

1222 1223
int Load_log_event::copy_log_event(const char *buf, ulong event_len,
				   bool old_format)
1224
{
1225
  uint data_len;
1226
  char* buf_end = (char*)buf + event_len;
1227 1228
  uint header_len= old_format ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
  const char* data_head = buf + header_len;
1229 1230 1231 1232 1233 1234
  thread_id = uint4korr(data_head + L_THREAD_ID_OFFSET);
  exec_time = uint4korr(data_head + L_EXEC_TIME_OFFSET);
  skip_lines = uint4korr(data_head + L_SKIP_LINES_OFFSET);
  table_name_len = (uint)data_head[L_TBL_LEN_OFFSET];
  db_len = (uint)data_head[L_DB_LEN_OFFSET];
  num_fields = uint4korr(data_head + L_NUM_FIELDS_OFFSET);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1235
	  
1236
  int body_offset = ((buf[EVENT_TYPE_OFFSET] == LOAD_EVENT) ?
1237
		     LOAD_HEADER_LEN + header_len :
1238
		     get_data_body_offset());
1239
  
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1240
  if ((int) event_len < body_offset)
1241
    return 1;
1242 1243 1244 1245
  /*
    Sql_ex.init() on success returns the pointer to the first byte after
    the sql_ex structure, which is the start of field lengths array.
  */
1246 1247 1248 1249 1250 1251
  if (!(field_lens=(uchar*)sql_ex.init((char*)buf + body_offset,
		  buf_end,
		  buf[EVENT_TYPE_OFFSET] != LOAD_EVENT)))
    return 1;
  
  data_len = event_len - body_offset;
1252
  if (num_fields > data_len) // simple sanity check against corruption
1253
    return 1;
1254
  for (uint i = 0; i < num_fields; i++)
1255
    field_block_len += (uint)field_lens[i] + 1;
1256

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1257 1258 1259 1260
  fields = (char*)field_lens + num_fields;
  table_name  = fields + field_block_len;
  db = table_name + table_name_len + 1;
  fname = db + db_len + 1;
1261 1262
  fname_len = strlen(fname);
  // null termination is accomplished by the caller doing buf[event_len]=0
1263
  return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1264 1265
}

1266
#ifdef MYSQL_CLIENT
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1267

1268
void Load_log_event::print(FILE* file, bool short_form, char* last_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1269 1270 1271
{
  if (!short_form)
  {
1272
    print_header(file);
1273
    fprintf(file, "\tQuery\tthread_id=%ld\texec_time=%ld\n",
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1274 1275 1276
	    thread_id, exec_time);
  }

1277
  bool same_db = 0;
1278 1279 1280 1281 1282
  if (db && last_db)
  {
    if (!(same_db = !memcmp(last_db, db, db_len + 1)))
      memcpy(last_db, db, db_len + 1);
  }
1283
  
1284
  if (db && db[0] && !same_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1285 1286
    fprintf(file, "use %s;\n", db);

1287
  fprintf(file, "LOAD DATA INFILE '%-*s' ", fname_len, fname);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1288

1289
  if (sql_ex.opt_flags & REPLACE_FLAG )
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1290
    fprintf(file," REPLACE ");
1291
  else if (sql_ex.opt_flags & IGNORE_FLAG )
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1292 1293 1294
    fprintf(file," IGNORE ");
  
  fprintf(file, "INTO TABLE %s ", table_name);
1295
  if (sql_ex.field_term)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1296 1297
  {
    fprintf(file, " FIELDS TERMINATED BY ");
1298
    pretty_print_str(file, sql_ex.field_term, sql_ex.field_term_len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1299 1300
  }

1301
  if (sql_ex.enclosed)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1302
  {
1303
    if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG )
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1304 1305
      fprintf(file," OPTIONALLY ");
    fprintf(file, " ENCLOSED BY ");
1306
    pretty_print_str(file, sql_ex.enclosed, sql_ex.enclosed_len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1307 1308
  }
     
1309
  if (sql_ex.escaped)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1310 1311
  {
    fprintf(file, " ESCAPED BY ");
1312
    pretty_print_str(file, sql_ex.escaped, sql_ex.escaped_len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1313 1314
  }
     
1315
  bool line_lexem_added= false;
1316
  if (sql_ex.line_term)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1317 1318
  {
    fprintf(file," LINES TERMINATED BY ");
1319
    pretty_print_str(file, sql_ex.line_term, sql_ex.line_term_len);
1320
    line_lexem_added= true;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1321 1322
  }

1323
  if (sql_ex.line_start)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1324
  {
1325 1326 1327
    if (!line_lexem_added)
      fprintf(file," LINES");
    fprintf(file," STARTING BY ");
1328
    pretty_print_str(file, sql_ex.line_start, sql_ex.line_start_len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1329 1330
  }
     
1331
  if ((int)skip_lines > 0)
monty@donna.mysql.fi's avatar
monty@donna.mysql.fi committed
1332
    fprintf(file, " IGNORE %ld LINES ", (long) skip_lines);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1333

1334 1335 1336 1337
  if (num_fields)
  {
    uint i;
    const char* field = fields;
1338 1339
    fprintf(file, " (");
    for (i = 0; i < num_fields; i++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1340
    {
1341
      if (i)
1342 1343
	fputc(',', file);
      fprintf(file, field);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1344
	  
1345
      field += field_lens[i]  + 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1346
    }
1347 1348
    fputc(')', file);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1349 1350 1351 1352

  fprintf(file, ";\n");
}

1353 1354
#endif /* #ifdef MYSQL_CLIENT */

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1355 1356
#ifndef MYSQL_CLIENT

1357
void Log_event::set_log_pos(MYSQL_LOG* log)
1358 1359 1360 1361 1362
{
  if (!log_pos)
    log_pos = my_b_tell(&log->log_file);
}

1363

1364
void Load_log_event::set_fields(List<Item> &field_list)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1365 1366
{
  uint i;
1367 1368
  const char *field= fields;
  for (i= 0; i < num_fields; i++)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1369
  {
1370 1371
    field_list.push_back(new Item_field(db, table_name, field));	  
    field+= field_lens[i]  + 1;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1372
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1373 1374
}

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1375

1376 1377
Slave_log_event::Slave_log_event(THD* thd_arg,
				 struct st_relay_log_info* rli):
1378
  Log_event(thd_arg,0,0),mem_pool(0),master_host(0)
1379
{
1380
  DBUG_ENTER("Slave_log_event");
1381
  if (!rli->inited)				// QQ When can this happen ?
1382
    DBUG_VOID_RETURN;
1383 1384
  
  MASTER_INFO* mi = rli->mi;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1385
  // TODO: re-write this better without holding both locks at the same time
1386 1387
  pthread_mutex_lock(&mi->data_lock);
  pthread_mutex_lock(&rli->data_lock);
1388
  master_host_len = strlen(mi->host);
1389
  master_log_len = strlen(rli->master_log_name);
1390
  // on OOM, just do not initialize the structure and print the error
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1391 1392
  if ((mem_pool = (char*)my_malloc(get_data_size() + 1,
				   MYF(MY_WME))))
1393
  {
1394
    master_host = mem_pool + SL_MASTER_HOST_OFFSET ;
1395 1396
    memcpy(master_host, mi->host, master_host_len + 1);
    master_log = master_host + master_host_len + 1;
1397
    memcpy(master_log, rli->master_log_name, master_log_len + 1);
1398
    master_port = mi->port;
1399
    master_pos = rli->master_log_pos;
1400 1401
    DBUG_PRINT("info", ("master_log: %s  pos: %d", master_log,
			(ulong) master_pos));
1402 1403 1404
  }
  else
    sql_print_error("Out of memory while recording slave event");
1405 1406
  pthread_mutex_unlock(&rli->data_lock);
  pthread_mutex_unlock(&mi->data_lock);
1407
  DBUG_VOID_RETURN;
1408 1409
}

1410
#endif /* ! MYSQL_CLIENT */
1411 1412 1413 1414 1415 1416 1417


Slave_log_event::~Slave_log_event()
{
  my_free(mem_pool, MYF(MY_ALLOW_ZERO_PTR));
}

1418 1419
#ifdef MYSQL_CLIENT

1420
void Slave_log_event::print(FILE* file, bool short_form, char* last_db)
1421 1422
{
  char llbuff[22];
1423
  if (short_form)
1424 1425 1426
    return;
  print_header(file);
  fputc('\n', file);
1427 1428
  fprintf(file, "Slave: master_host: '%s'  master_port: %d  \
master_log: '%s'  master_pos: %s\n",
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1429
	  master_host, master_port, master_log, llstr(master_pos, llbuff));
1430 1431
}

1432
#endif /* MYSQL_CLIENT */
1433

1434 1435
int Slave_log_event::get_data_size()
{
1436
  return master_host_len + master_log_len + 1 + SL_MASTER_HOST_OFFSET;
1437 1438 1439 1440
}

int Slave_log_event::write_data(IO_CACHE* file)
{
1441 1442
  int8store(mem_pool + SL_MASTER_POS_OFFSET, master_pos);
  int2store(mem_pool + SL_MASTER_PORT_OFFSET, master_port);
1443
  // log and host are already there
1444
  return my_b_safe_write(file, (byte*)mem_pool, get_data_size());
1445 1446
}

1447

1448 1449
void Slave_log_event::init_from_mem_pool(int data_size)
{
1450 1451 1452
  master_pos = uint8korr(mem_pool + SL_MASTER_POS_OFFSET);
  master_port = uint2korr(mem_pool + SL_MASTER_PORT_OFFSET);
  master_host = mem_pool + SL_MASTER_HOST_OFFSET;
1453 1454
  master_host_len = strlen(master_host);
  // safety
1455
  master_log = master_host + master_host_len + 1;
1456
  if (master_log > mem_pool + data_size)
1457 1458 1459 1460 1461 1462 1463
  {
    master_host = 0;
    return;
  }
  master_log_len = strlen(master_log);
}

1464 1465
Slave_log_event::Slave_log_event(const char* buf, int event_len)
  :Log_event(buf,0),mem_pool(0),master_host(0)
1466
{
1467
  event_len -= LOG_EVENT_HEADER_LEN;
1468
  if (event_len < 0)
1469
    return;
1470
  if (!(mem_pool = (char*) my_malloc(event_len + 1, MYF(MY_WME))))
1471
    return;
1472
  memcpy(mem_pool, buf + LOG_EVENT_HEADER_LEN, event_len);
1473 1474 1475
  mem_pool[event_len] = 0;
  init_from_mem_pool(event_len);
}
1476 1477

#ifndef MYSQL_CLIENT
1478 1479 1480 1481 1482 1483 1484
Create_file_log_event::
Create_file_log_event(THD* thd_arg, sql_exchange* ex,
		      const char* db_arg, const char* table_name_arg,
		      List<Item>& fields_arg, enum enum_duplicates handle_dup,
		      char* block_arg, uint block_len_arg, bool using_trans)
  :Load_log_event(thd_arg,ex,db_arg,table_name_arg,fields_arg,handle_dup,
		  using_trans),
1485 1486
   fake_base(0),block(block_arg),block_len(block_len_arg),
   file_id(thd_arg->file_id = mysql_bin_log.next_file_id())
1487
{
1488
  sql_ex.force_new_format();
1489 1490 1491
}
#endif

1492 1493 1494 1495 1496
int Create_file_log_event::write_data_body(IO_CACHE* file)
{
  int res;
  if ((res = Load_log_event::write_data_body(file)) || fake_base)
    return res;
1497 1498
  return (my_b_safe_write(file, (byte*) "", 1) ||
	  my_b_safe_write(file, (byte*) block, block_len));
1499 1500 1501
}

int Create_file_log_event::write_data_header(IO_CACHE* file)
1502
{
1503 1504 1505
  int res;
  if ((res = Load_log_event::write_data_header(file)) || fake_base)
    return res;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1506
  byte buf[CREATE_FILE_HEADER_LEN];
1507
  int4store(buf + CF_FILE_ID_OFFSET, file_id);
1508
  return my_b_safe_write(file, buf, CREATE_FILE_HEADER_LEN);
1509 1510 1511 1512 1513 1514 1515 1516 1517
}

int Create_file_log_event::write_base(IO_CACHE* file)
{
  int res;
  fake_base = 1; // pretend we are Load event
  res = write(file);
  fake_base = 0;
  return res;
1518 1519
}

1520
Create_file_log_event::Create_file_log_event(const char* buf, int len,
1521 1522
					     bool old_format)
  :Load_log_event(buf,0,old_format),fake_base(0),block(0),inited_from_old(0)
1523
{
1524
  int block_offset;
1525
  if (copy_log_event(buf,len,old_format))
1526
    return;
1527 1528 1529 1530
  if (!old_format)
  {
    file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN +
			+ LOAD_HEADER_LEN + CF_FILE_ID_OFFSET);
1531 1532 1533
    // + 1 for \0 terminating fname  
    block_offset = (LOG_EVENT_HEADER_LEN + Load_log_event::get_data_size() +
		    CREATE_FILE_HEADER_LEN + 1);
1534 1535 1536 1537 1538 1539 1540 1541 1542 1543
    if (len < block_offset)
      return;
    block = (char*)buf + block_offset;
    block_len = len - block_offset;
  }
  else
  {
    sql_ex.force_new_format();
    inited_from_old = 1;
  }
1544
}
1545 1546


1547
#ifdef MYSQL_CLIENT
1548 1549
void Create_file_log_event::print(FILE* file, bool short_form,
				  char* last_db)
1550
{
1551 1552
  if (short_form)
    return;
1553
  Load_log_event::print(file, 1, last_db);
1554
  fprintf(file, " file_id: %d  block_len: %d\n", file_id, block_len);
1555 1556 1557 1558 1559 1560
}
#endif

#ifndef MYSQL_CLIENT
void Create_file_log_event::pack_info(String* packet)
{
1561
  char buf1[256],buf[22], *end;
1562 1563 1564 1565 1566
  String tmp(buf1, sizeof(buf1));
  tmp.length(0);
  tmp.append("db=");
  tmp.append(db, db_len);
  tmp.append(";table=");
1567
  tmp.append(table_name, table_name_len);
1568
  tmp.append(";file_id=");
1569 1570
  end= int10_to_str((long) file_id, buf, 10);
  tmp.append(buf, (uint32) (end-buf));
1571
  tmp.append(";block_len=");
1572 1573 1574
  end= int10_to_str((long) block_len, buf, 10);
  tmp.append(buf, (uint32) (end-buf));
  net_store_data(packet, (char*) tmp.ptr(), tmp.length());
1575 1576 1577 1578 1579
}
#endif  

#ifndef MYSQL_CLIENT  
Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg,
1580 1581 1582 1583
					       uint block_len_arg,
					       bool using_trans)
  :Log_event(thd_arg,0, using_trans), block(block_arg),
   block_len(block_len_arg), file_id(thd_arg->file_id)
1584 1585 1586 1587
{
}
#endif  
  
1588 1589
Append_block_log_event::Append_block_log_event(const char* buf, int len)
  :Log_event(buf, 0),block(0)
1590
{
1591
  if ((uint)len < APPEND_BLOCK_EVENT_OVERHEAD)
1592 1593 1594 1595 1596 1597 1598 1599
    return;
  file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET);
  block = (char*)buf + APPEND_BLOCK_EVENT_OVERHEAD;
  block_len = len - APPEND_BLOCK_EVENT_OVERHEAD;
}

int Append_block_log_event::write_data(IO_CACHE* file)
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1600
  byte buf[APPEND_BLOCK_HEADER_LEN];
1601
  int4store(buf + AB_FILE_ID_OFFSET, file_id);
1602 1603
  return (my_b_safe_write(file, buf, APPEND_BLOCK_HEADER_LEN) ||
	  my_b_safe_write(file, (byte*) block, block_len));
1604 1605 1606
}

#ifdef MYSQL_CLIENT  
1607 1608
void Append_block_log_event::print(FILE* file, bool short_form,
				   char* last_db)
1609 1610 1611 1612 1613
{
  if (short_form)
    return;
  print_header(file);
  fputc('\n', file);
1614
  fprintf(file, "#Append_block: file_id: %d  block_len: %d\n",
1615 1616 1617
	  file_id, block_len);
}
#endif  
1618

1619 1620 1621 1622
#ifndef MYSQL_CLIENT
void Append_block_log_event::pack_info(String* packet)
{
  char buf1[256];
1623 1624
  sprintf(buf1, ";file_id=%u;block_len=%u", file_id, block_len);
  net_store_data(packet, buf1);
1625 1626
}

1627 1628
Delete_file_log_event::Delete_file_log_event(THD* thd_arg, bool using_trans)
  :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id)
1629 1630 1631 1632
{
}
#endif  

1633 1634 1635

Delete_file_log_event::Delete_file_log_event(const char* buf, int len)
  :Log_event(buf, 0),file_id(0)
1636
{
1637
  if ((uint)len < DELETE_FILE_EVENT_OVERHEAD)
1638 1639 1640 1641
    return;
  file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET);
}

1642

1643 1644
int Delete_file_log_event::write_data(IO_CACHE* file)
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1645
 byte buf[DELETE_FILE_HEADER_LEN];
1646
 int4store(buf + DF_FILE_ID_OFFSET, file_id);
1647
 return my_b_safe_write(file, buf, DELETE_FILE_HEADER_LEN);
1648 1649 1650
}

#ifdef MYSQL_CLIENT  
1651 1652
void Delete_file_log_event::print(FILE* file, bool short_form,
				  char* last_db)
1653 1654 1655 1656 1657
{
  if (short_form)
    return;
  print_header(file);
  fputc('\n', file);
1658
  fprintf(file, "#Delete_file: file_id=%u\n", file_id);
1659 1660
}
#endif  
1661

1662 1663 1664
#ifndef MYSQL_CLIENT
void Delete_file_log_event::pack_info(String* packet)
{
1665 1666 1667
  char buf1[64];
  sprintf(buf1, ";file_id=%u", (uint) file_id);
  net_store_data(packet, buf1);
1668 1669 1670
}
#endif  

1671

1672
#ifndef MYSQL_CLIENT  
1673 1674
Execute_load_log_event::Execute_load_log_event(THD* thd_arg, bool using_trans)
  :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id)
1675 1676 1677 1678
{
}
#endif  
  
1679 1680
Execute_load_log_event::Execute_load_log_event(const char* buf, int len)
  :Log_event(buf, 0), file_id(0)
1681
{
1682
  if ((uint)len < EXEC_LOAD_EVENT_OVERHEAD)
1683 1684 1685 1686 1687 1688
    return;
  file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + EL_FILE_ID_OFFSET);
}

int Execute_load_log_event::write_data(IO_CACHE* file)
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1689 1690
  byte buf[EXEC_LOAD_HEADER_LEN];
  int4store(buf + EL_FILE_ID_OFFSET, file_id);
1691
  return my_b_safe_write(file, buf, EXEC_LOAD_HEADER_LEN);
1692 1693 1694
}

#ifdef MYSQL_CLIENT  
1695 1696
void Execute_load_log_event::print(FILE* file, bool short_form,
				   char* last_db)
1697 1698 1699 1700 1701 1702 1703
{
  if (short_form)
    return;
  print_header(file);
  fputc('\n', file);
  fprintf(file, "#Exec_load: file_id=%d\n",
	  file_id);
1704 1705
}
#endif  
1706 1707 1708
#ifndef MYSQL_CLIENT
void Execute_load_log_event::pack_info(String* packet)
{
1709 1710 1711
  char buf[64];
  sprintf(buf, ";file_id=%u", (uint) file_id);
  net_store_data(packet, buf);
1712 1713 1714
}
#endif

1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725
#ifdef MYSQL_CLIENT
void Unknown_log_event::print(FILE* file, bool short_form, char* last_db)
{
  if (short_form)
    return;
  print_header(file);
  fputc('\n', file);
  fprintf(file, "# %s", "Unknown event\n");
}
#endif  

1726
#ifndef MYSQL_CLIENT
1727
int Query_log_event::exec_event(struct st_relay_log_info* rli)
1728 1729 1730 1731
{
  int expected_error,actual_error = 0;
  init_sql_alloc(&thd->mem_root, 8192,0);
  thd->db = rewrite_db((char*)db);
1732 1733 1734 1735 1736 1737 1738 1739

  /*
    InnoDB internally stores the master log position it has processed so far;
    position to store is really pos + pending + event_len
    since we must store the pos of the END of the current log event
  */
  rli->event_len= get_event_len();

1740 1741 1742 1743
  if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
  {
    thd->set_time((time_t)when);
    thd->current_tablenr = 0;
1744
    thd->query_length= q_len;
1745
    VOID(pthread_mutex_lock(&LOCK_thread_count));
1746
    thd->query = (char*)query;
1747 1748 1749 1750 1751
    thd->query_id = query_id++;
    VOID(pthread_mutex_unlock(&LOCK_thread_count));
    thd->query_error = 0;			// clear error
    thd->net.last_errno = 0;
    thd->net.last_error[0] = 0;
1752
    thd->slave_proxy_id = thread_id;		// for temp tables
1753
	
1754 1755 1756 1757
    /*
      Sanity check to make sure the master did not get a really bad
      error on the query.
    */
1758 1759
    if (ignored_error_code((expected_error = error_code)) ||
	!check_expected_error(thd,rli,expected_error))
1760
    {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1761 1762
      mysql_log.write(thd,COM_QUERY,"%s",thd->query);
      DBUG_PRINT("query",("%s",thd->query));
1763
      mysql_parse(thd, thd->query, q_len);
1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776

      /*
	Set a flag if we are inside an transaction so that we can restart
	the transaction from the start if we are killed

	This will only be done if we are supporting transactional tables
	in the slave.
      */
      if (!strcmp(thd->query,"BEGIN"))
	rli->inside_transaction= opt_using_transactions;
      else if (!strcmp(thd->query,"COMMIT"))
	rli->inside_transaction=0;

1777 1778
      if ((expected_error != (actual_error = thd->net.last_errno)) &&
	  expected_error &&
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
1779 1780
	  !ignored_error_code(actual_error) &&
	  !ignored_error_code(expected_error))
1781 1782
      {
	const char* errmsg = "Slave: did not get the expected error\
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1783
 running query from master - expected: '%s' (%d), got '%s' (%d)"; 
1784 1785
	sql_print_error(errmsg, ER_SAFE(expected_error),
			expected_error,
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1786
			actual_error ? thd->net.last_error: "no error",
1787 1788 1789
			actual_error);
	thd->query_error = 1;
      }
1790 1791
      else if (expected_error == actual_error ||
	       ignored_error_code(actual_error))
1792 1793
      {
	thd->query_error = 0;
1794 1795
	*rli->last_slave_error = 0;
	rli->last_slave_errno = 0;
1796 1797 1798 1799 1800
      }
    }
    else
    {
      // master could be inconsistent, abort and tell DBA to check/fix it
1801
      VOID(pthread_mutex_lock(&LOCK_thread_count));
1802
      thd->db = thd->query = 0;
1803
      VOID(pthread_mutex_unlock(&LOCK_thread_count));
1804
      thd->variables.convert_set = 0;
1805 1806 1807 1808 1809
      close_thread_tables(thd);
      free_root(&thd->mem_root,0);
      return 1;
    }
  }
1810
  thd->db= 0;				// prevent db from being freed
1811
  VOID(pthread_mutex_lock(&LOCK_thread_count));
1812
  thd->query= 0;			// just to be sure
1813
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
1814
  // assume no convert for next query unless set explictly
1815
  thd->variables.convert_set = 0;
1816 1817 1818 1819
  close_thread_tables(thd);
      
  if (thd->query_error || thd->fatal_error)
  {
1820
    slave_print_error(rli,actual_error, "error '%s' on query '%s'",
1821 1822
		      actual_error ? thd->net.last_error :
		      "unexpected success or fatal error", query);
1823 1824 1825 1826
    free_root(&thd->mem_root,0);
    return 1;
  }
  free_root(&thd->mem_root,0);
1827
  return Log_event::exec_event(rli); 
1828 1829
}

1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854
/*
  Does the data loading job when executing a LOAD DATA on the slave

  SYNOPSIS
    Load_log_event::exec_event
      net  
      rli                             
      use_rli_only_for_errors	  - if set to 1, rli is provided to 
                                  Load_log_event::exec_event only for this 
				  function to have RPL_LOG_NAME and 
				  rli->last_slave_error, both being used by 
				  error reports. rli's position advancing
				  is skipped (done by the caller which is
				  Execute_load_log_event::exec_event).
				  - if set to 0, rli is provided for full use,
				  i.e. for error reports and position
				  advancing.

  DESCRIPTION
    Does the data loading job when executing a LOAD DATA on the slave
 
  RETURN VALUE
    0           Success                                                 
    1    	Failure
*/
1855

1856 1857
int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, 
			       bool use_rli_only_for_errors)
1858 1859 1860
{
  init_sql_alloc(&thd->mem_root, 8192,0);
  thd->db = rewrite_db((char*)db);
1861 1862
  DBUG_ASSERT(thd->query == 0);
  thd->query = 0;				// Should not be needed
1863 1864
  thd->query_error = 0;
	    
1865
  if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
1866 1867 1868 1869 1870 1871 1872 1873 1874 1875
  {
    thd->set_time((time_t)when);
    thd->current_tablenr = 0;
    VOID(pthread_mutex_lock(&LOCK_thread_count));
    thd->query_id = query_id++;
    VOID(pthread_mutex_unlock(&LOCK_thread_count));

    TABLE_LIST tables;
    bzero((char*) &tables,sizeof(tables));
    tables.db = thd->db;
1876
    tables.alias = tables.real_name = (char*)table_name;
1877
    tables.lock_type = TL_WRITE;
1878
    tables.updating= 1;
1879
    // the table will be opened in mysql_load    
1880
    if (table_rules_on && !tables_ok(thd, &tables))
1881
    {
1882
      // TODO: this is a bug - this needs to be moved to the I/O thread
1883 1884 1885 1886 1887 1888
      if (net)
        skip_load_data_infile(net);
    }
    else
    {
      char llbuff[22];
1889
      enum enum_duplicates handle_dup;
1890
      if (sql_ex.opt_flags & REPLACE_FLAG)
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1891
	handle_dup= DUP_REPLACE;
1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909
      else if (sql_ex.opt_flags & IGNORE_FLAG)
        handle_dup= DUP_IGNORE;
      else
        /*
          Note that when replication is running fine, if it was DUP_ERROR on the 
          master then we could choose DUP_IGNORE here, because if DUP_ERROR
          suceeded on master, and data is identical on the master and slave,
          then there should be no uniqueness errors on slave, so DUP_IGNORE is
          the same as DUP_ERROR. But in the unlikely case of uniqueness errors
          (because the data on the master and slave happen to be different (user
          error or bug), we want LOAD DATA to print an error message on the
          slave to discover the problem.

          If reading from net (a 3.23 master), mysql_load() will change this
          to DUP_IGNORE.
        */
        handle_dup= DUP_ERROR;

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1910
      sql_exchange ex((char*)fname, sql_ex.opt_flags & DUMPFILE_FLAG);
1911 1912 1913 1914 1915
      String field_term(sql_ex.field_term,sql_ex.field_term_len);
      String enclosed(sql_ex.enclosed,sql_ex.enclosed_len);
      String line_term(sql_ex.line_term,sql_ex.line_term_len);
      String line_start(sql_ex.line_start,sql_ex.line_start_len);
      String escaped(sql_ex.escaped,sql_ex.escaped_len);
1916 1917 1918 1919 1920
      ex.field_term= &field_term;
      ex.enclosed= &enclosed;
      ex.line_term= &line_term;
      ex.line_start= &line_start;
      ex.escaped= &escaped;
1921 1922
	    
      ex.opt_enclosed = (sql_ex.opt_flags & OPT_ENCLOSED_FLAG);
1923
      if (sql_ex.empty_flags & FIELD_TERM_EMPTY)
1924
	ex.field_term->length(0);
1925

1926
      ex.skip_lines = skip_lines;
1927 1928
      List<Item> field_list;
      set_fields(field_list);
1929
      thd->slave_proxy_id = thread_id;
1930 1931 1932 1933
      if (net)
      {
	// mysql_load will use thd->net to read the file
	thd->net.vio = net->vio;
1934 1935 1936
	/*
	  Make sure the client does not get confused about the packet sequence
	*/
1937 1938
	thd->net.pkt_nr = net->pkt_nr;
      }
1939
      if (mysql_load(thd, &ex, &tables, field_list, handle_dup, net != 0,
1940
		     TL_WRITE))
1941
	thd->query_error = 1;
1942
      if (thd->cuted_fields)
1943 1944 1945 1946
	/* 
	   log_pos is the position of the LOAD
	   event in the master log
	*/
1947
	sql_print_error("Slave: load data infile at position %s in log \
1948
'%s' produced %d warning(s)", llstr(log_pos,llbuff), RPL_LOG_NAME, 
1949
			thd->cuted_fields );
1950
      if (net)
1951
        net->pkt_nr= thd->net.pkt_nr;
1952 1953 1954 1955
    }
  }
  else
  {
1956 1957 1958 1959 1960
    /*
      We will just ask the master to send us /dev/null if we do not
      want to load the data.
      TODO: this a bug - needs to be done in I/O thread
    */
1961 1962 1963 1964 1965
    if (net)
      skip_load_data_infile(net);
  }
	    
  thd->net.vio = 0; 
1966
  thd->db= 0;					// prevent db from being freed
1967
  close_thread_tables(thd);
1968
  if (thd->query_error)
1969
  {
1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980
    /* this err/sql_errno code is copy-paste from send_error() */
    const char *err;
    int sql_errno;
    if ((err=thd->net.last_error)[0])
      sql_errno=thd->net.last_errno;
    else
    {
      sql_errno=ER_UNKNOWN_ERROR;
      err=ER(sql_errno);       
    }
    slave_print_error(rli,sql_errno,
1981
		      "Error '%s' running load data infile",
1982
		      err);
1983 1984 1985 1986 1987
    free_root(&thd->mem_root,0);
    return 1;
  }
  free_root(&thd->mem_root,0);
	    
1988
  if (thd->fatal_error)
1989
  {
1990
    sql_print_error("Fatal error running LOAD DATA INFILE ");
1991 1992 1993
    return 1;
  }

1994
  return ( use_rli_only_for_errors ? 0 : Log_event::exec_event(rli) ); 
1995 1996
}

1997

1998 1999 2000 2001 2002 2003
/*
  The master started

  IMPLEMENTATION
    - To handle the case where the master died without a stop event,
      we clean up all temporary tables + locks that we got.
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2004 2005 2006 2007
      However, we don't clean temporary tables if the master was 3.23
      (this is because a 3.23 master writes a Start_log_event at every
      binlog rotation; if we were not careful we would remove temp tables
      on the slave when FLUSH LOGS is issued on the master). 
2008 2009 2010 2011 2012 2013 2014 2015

  TODO
    - Remove all active user locks
    - If we have an active transaction at this point, the master died
      in the middle while writing the transaction to the binary log.
      In this case we should stop the slave.
*/

2016
int Start_log_event::exec_event(struct st_relay_log_info* rli)
2017
{
2018
  if (!rli->mi->old_format)
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2019 2020 2021 2022 2023 2024 2025 2026 2027
  {
    /* 
       If 4.0 master, all temporary tables have been deleted on the master; 
       if 3.23 master, this is far from sure.
    */
    close_temporary_tables(thd);
    /*
      If we have old format, load_tmpdir is cleaned up by the I/O thread
    */
2028
    cleanup_load_tmpdir();
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2029
  }
2030
  return Log_event::exec_event(rli);
2031 2032
}

2033

2034 2035 2036 2037 2038 2039 2040 2041
/*
  The master stopped. Clean up all temporary tables + locks that the
  master may have set.

  TODO
    - Remove all active user locks
*/

2042
int Stop_log_event::exec_event(struct st_relay_log_info* rli)
2043
{
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2044 2045 2046 2047 2048 2049 2050 2051
  /*
    do not clean up immediately after rotate event;
    QQ: this should be a useless test: the only case when it is false is when
    shutdown occured just after FLUSH LOGS. It has nothing to do with Rotate?
    By the way, immediately after a Rotate
    the I/O thread does not write the Stop to the relay log,
    so we won't come here in that case.
  */
2052
  if (rli->master_log_pos > BIN_LOG_HEADER_SIZE) 
2053 2054
  {
    close_temporary_tables(thd);
2055
    cleanup_load_tmpdir();
2056
  }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2057 2058
  /*
    We do not want to update master_log pos because we get a rotate event
2059 2060
    before stop, so by now master_log_name is set to the next log.
    If we updated it, we will have incorrect master coordinates and this
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2061
    could give false triggers in MASTER_POS_WAIT() that we have reached
2062
    the target position when in fact we have not.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2063
  */
2064 2065
  rli->inc_pos(get_event_len(), 0);  
  flush_relay_log_info(rli);
2066 2067 2068
  return 0;
}

2069 2070 2071 2072 2073

/*
  Got a rotate log even from the master

  IMPLEMENTATION
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2074 2075
    This is mainly used so that we can later figure out the logname and
    position for the master.
2076

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2077 2078
    We can't rotate the slave as this will cause infinitive rotations
    in a A -> B -> A setup.
2079 2080

  RETURN VALUES
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2081 2082
    0	ok
 */
2083 2084
  

2085
int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
2086
{
2087
  char* log_name = rli->master_log_name;
2088 2089
  DBUG_ENTER("Rotate_log_event::exec_event");

2090
  pthread_mutex_lock(&rli->data_lock);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2091
  memcpy(log_name, new_log_ident, ident_len+1);
2092 2093
  rli->master_log_pos = pos;
  rli->relay_log_pos += get_event_len();
2094
  DBUG_PRINT("info", ("master_log_pos: %d", (ulong) rli->master_log_pos));
2095
  pthread_mutex_unlock(&rli->data_lock);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2096
  pthread_cond_broadcast(&rli->data_cond);
2097
  flush_relay_log_info(rli);
2098
  DBUG_RETURN(0);
2099 2100
}

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2101

2102
int Intvar_log_event::exec_event(struct st_relay_log_info* rli)
2103
{
2104
  switch (type) {
2105 2106 2107 2108 2109 2110 2111 2112
  case LAST_INSERT_ID_EVENT:
    thd->last_insert_id_used = 1;
    thd->last_insert_id = val;
    break;
  case INSERT_ID_EVENT:
    thd->next_insert_id = val;
    break;
  }
2113
  rli->inc_pending(get_event_len());
2114 2115 2116
  return 0;
}

nick@mysql.com's avatar
nick@mysql.com committed
2117 2118
int Rand_log_event::exec_event(struct st_relay_log_info* rli)
{
2119 2120
  thd->rand.seed1 = (ulong) seed1;
  thd->rand.seed2 = (ulong) seed2;
nick@mysql.com's avatar
nick@mysql.com committed
2121 2122 2123 2124
  rli->inc_pending(get_event_len());
  return 0;
}

2125
int Slave_log_event::exec_event(struct st_relay_log_info* rli)
2126
{
2127
  if (mysql_bin_log.is_open())
2128
    mysql_bin_log.write(this);
2129
  return Log_event::exec_event(rli);
2130 2131
}

2132
int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
2133 2134
{
  char fname_buf[FN_REFLEN+10];
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2135
  char *p;
2136 2137 2138
  int fd = -1;
  IO_CACHE file;
  int error = 1;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2139

2140
  bzero((char*)&file, sizeof(file));
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2141 2142
  p = slave_load_file_stem(fname_buf, file_id, server_id);
  strmov(p, ".info");			// strmov takes less code than memcpy
2143 2144 2145 2146 2147
  if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC,
		    MYF(MY_WME))) < 0 ||
      init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0,
		    MYF(MY_WME|MY_NABP)))
  {
2148
    slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf);
2149 2150 2151 2152
    goto err;
  }
  
  // a trick to avoid allocating another buffer
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2153
  strmov(p, ".data");
2154 2155 2156 2157
  fname = fname_buf;
  fname_len = (uint)(p-fname) + 5;
  if (write_base(&file))
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2158
    strmov(p, ".info"); // to have it right in the error message
2159
    slave_print_error(rli,my_errno, "Could not write to file '%s'", fname_buf);
2160 2161 2162 2163 2164 2165 2166 2167 2168
    goto err;
  }
  end_io_cache(&file);
  my_close(fd, MYF(0));
  
  // fname_buf now already has .data, not .info, because we did our trick
  if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC,
		    MYF(MY_WME))) < 0)
  {
2169
    slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf);
2170 2171
    goto err;
  }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2172
  if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
2173
  {
2174
    slave_print_error(rli,my_errno, "Write to '%s' failed", fname_buf);
2175 2176 2177 2178
    goto err;
  }
  if (mysql_bin_log.is_open())
    mysql_bin_log.write(this);
2179 2180
  error=0;					// Everything is ok

2181 2182 2183 2184 2185
err:
  if (error)
    end_io_cache(&file);
  if (fd >= 0)
    my_close(fd, MYF(0));
2186
  return error ? 1 : Log_event::exec_event(rli);
2187 2188
}

2189
int Delete_file_log_event::exec_event(struct st_relay_log_info* rli)
2190 2191
{
  char fname[FN_REFLEN+10];
2192
  char *p= slave_load_file_stem(fname, file_id, server_id);
2193
  memcpy(p, ".data", 6);
2194
  (void) my_delete(fname, MYF(MY_WME));
2195
  memcpy(p, ".info", 6);
2196
  (void) my_delete(fname, MYF(MY_WME));
2197 2198
  if (mysql_bin_log.is_open())
    mysql_bin_log.write(this);
2199
  return Log_event::exec_event(rli);
2200 2201
}

2202
int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
2203 2204
{
  char fname[FN_REFLEN+10];
2205 2206
  char *p= slave_load_file_stem(fname, file_id, server_id);
  int fd;
2207
  int error = 1;
2208

2209 2210 2211
  memcpy(p, ".data", 6);
  if ((fd = my_open(fname, O_WRONLY|O_APPEND|O_BINARY, MYF(MY_WME))) < 0)
  {
2212
    slave_print_error(rli,my_errno, "Could not open file '%s'", fname);
2213 2214
    goto err;
  }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2215
  if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
2216
  {
2217
    slave_print_error(rli,my_errno, "Write to '%s' failed", fname);
2218 2219 2220 2221 2222
    goto err;
  }
  if (mysql_bin_log.is_open())
    mysql_bin_log.write(this);
  error=0;
2223

2224 2225 2226
err:
  if (fd >= 0)
    my_close(fd, MYF(0));
2227
  return error ? error : Log_event::exec_event(rli);
2228 2229
}

2230
int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
2231 2232
{
  char fname[FN_REFLEN+10];
2233 2234
  char *p= slave_load_file_stem(fname, file_id, server_id);
  int fd;
2235
  int error = 1;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2236
  ulong save_options;
2237 2238
  IO_CACHE file;
  Load_log_event* lev = 0;
2239

2240 2241 2242 2243 2244
  memcpy(p, ".info", 6);
  if ((fd = my_open(fname, O_RDONLY|O_BINARY, MYF(MY_WME))) < 0 ||
      init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0,
		    MYF(MY_WME|MY_NABP)))
  {
2245
    slave_print_error(rli,my_errno, "Could not open file '%s'", fname);
2246 2247
    goto err;
  }
2248 2249
  if (!(lev = (Load_log_event*)Log_event::read_log_event(&file,
							 (pthread_mutex_t*)0,
2250 2251
							 (bool)0)) ||
      lev->get_type_code() != NEW_LOAD_EVENT)
2252
  {
2253
    slave_print_error(rli,0, "File '%s' appears corrupted", fname);
2254 2255
    goto err;
  }
2256 2257 2258 2259 2260 2261
  /*
    We want to disable binary logging in slave thread because we need the file
    events to appear in the same order as they do on the master relative to
    other events, so that we can preserve ascending order of log sequence
    numbers - needed to handle failover .
  */
2262
  save_options = thd->options;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2263
  thd->options &= ~ (ulong) (OPTION_BIN_LOG);
2264
  lev->thd = thd;
2265 2266 2267 2268 2269
  /*
    lev->exec_event should use rli only for errors
    i.e. should not advance rli's position
  */
  if (lev->exec_event(0,rli,1)) 
2270
  {
2271
    slave_print_error(rli,my_errno, "Failed executing load from '%s'", fname);
2272 2273 2274 2275
    thd->options = save_options;
    goto err;
  }
  thd->options = save_options;
2276
  (void) my_delete(fname, MYF(MY_WME));
2277
  memcpy(p, ".data", 6);
2278
  (void) my_delete(fname, MYF(MY_WME));
2279 2280 2281
  if (mysql_bin_log.is_open())
    mysql_bin_log.write(this);
  error = 0;
2282

2283 2284 2285
err:
  delete lev;
  if (fd >= 0)
2286
  {
2287
    my_close(fd, MYF(0));
2288 2289
    end_io_cache(&file);
  }
2290
  return error ? error : Log_event::exec_event(rli);
2291 2292
}

2293
#endif /* !MYSQL_CLIENT */