log_event.cc 84.8 KB
Newer Older
unknown's avatar
unknown 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>
unknown's avatar
unknown committed
25 26
#endif /* MYSQL_CLIENT */

27 28
#include <assert.h>

29 30
#define log_cs	my_charset_latin1

31 32 33 34 35
/*****************************************************************************

  my_b_safe_write()

 ****************************************************************************/
unknown's avatar
unknown committed
36 37 38 39 40
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
41 42 43
    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
unknown's avatar
unknown committed
44
  */
45
  if (file->type == SEQ_READ_APPEND)
unknown's avatar
unknown committed
46 47 48
    return my_b_append(file, buf,len);
  return my_b_write(file, buf,len);
}
49

50 51 52 53 54
/*****************************************************************************

  pretty_print_str()

 ****************************************************************************/
55
#ifdef MYSQL_CLIENT
56
static void pretty_print_str(FILE* file, char* str, int len)
unknown's avatar
unknown committed
57
{
58
  char* end = str + len;
unknown's avatar
unknown committed
59
  fputc('\'', file);
60 61
  while (str < end)
  {
unknown's avatar
unknown committed
62
    char c;
63 64 65 66 67 68 69 70 71 72 73 74
    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;
    }
75 76
  }
  fputc('\'', file);
unknown's avatar
unknown committed
77
}
78
#endif // MYSQL_CLIENT
unknown's avatar
unknown committed
79

80
/*****************************************************************************
unknown's avatar
unknown committed
81

82 83 84 85
  ignored_error_code()

 ****************************************************************************/
#ifndef MYSQL_CLIENT
86 87 88 89
inline int ignored_error_code(int err_code)
{
  return use_slave_mask && bitmap_is_set(&slave_error_mask, err_code);
}
90 91 92
#endif // !MYSQL_CLIENT

/*****************************************************************************
93

94
  pretty_print_str()
unknown's avatar
unknown committed
95

96 97
 ****************************************************************************/
#ifndef MYSQL_CLIENT
98
static char* pretty_print_str(char* packet, char* str, int len)
unknown's avatar
unknown committed
99
{
100
  char* end = str + len;
101 102
  char* pos= packet;
  *pos++= '\'';
103 104 105
  while (str < end)
  {
    char c;
106
    switch ((c=*str++)) {
107 108 109 110 111 112 113
    case '\n': pos= strmov(pos, "\\n"); break;
    case '\r': pos= strmov(pos, "\\r"); break;
    case '\\': pos= strmov(pos, "\\\\"); break;
    case '\b': pos= strmov(pos, "\\b"); break;
    case '\t': pos= strmov(pos, "\\t"); break;
    case '\'': pos= strmov(pos, "\\'"); break;
    case 0   : pos= strmov(pos, "\\0"); break;
114
    default:
115
      *pos++= (char)c;
116 117
      break;
    }
unknown's avatar
unknown committed
118
  }
119 120
  *pos++= '\'';
  return pos;
unknown's avatar
unknown committed
121
}
122 123 124
#endif // !MYSQL_CLIENT

/*****************************************************************************
unknown's avatar
unknown committed
125

126
  slave_load_file_stem()
unknown's avatar
unknown committed
127

128 129
 ****************************************************************************/
#ifndef MYSQL_CLIENT
130 131 132
static inline char* slave_load_file_stem(char*buf, uint file_id,
					 int event_server_id)
{
133
  fn_format(buf,"SQL_LOAD-",slave_load_tmpdir,"",0); /* 4+32); */
134 135 136 137 138 139 140
  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);
}
141
#endif // !MYSQL_CLIENT
142

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
/*****************************************************************************

  cleanup_load_tmpdir()

  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.

 ****************************************************************************/
#ifndef MYSQL_CLIENT
static void cleanup_load_tmpdir()
{
  MY_DIR *dirp;
  FILEINFO *file;
  uint i;
  if (!(dirp=my_dir(slave_load_tmpdir,MYF(MY_WME))))
    return;

  for (i=0 ; i < (uint)dirp->number_off_files; i++)
  {
    file=dirp->dir_entry+i;
    if (is_prefix(file->name,"SQL_LOAD-"))
      my_delete(file->name, MYF(0));
  }

  my_dirend(dirp);
}
#endif // !MYSQL_CLIENT

/*****************************************************************************

  write_str()

 ****************************************************************************/
static bool write_str(IO_CACHE *file, char *str, byte length)
{
  return (my_b_safe_write(file, &length, 1) ||
	  my_b_safe_write(file, (byte*) str, (int) length));
}

/*****************************************************************************

  read_str()

 ****************************************************************************/
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;
}


/*****************************************************************************
 *****************************************************************************

                               Log_event methods

 *****************************************************************************
 ****************************************************************************/
unknown's avatar
unknown committed
210

211 212 213 214 215
/*****************************************************************************

  Log_event::get_type_str()

 ****************************************************************************/
unknown's avatar
unknown committed
216 217
const char* Log_event::get_type_str()
{
218
  switch(get_type_code()) {
unknown's avatar
unknown committed
219 220 221 222 223 224
  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";
225
  case NEW_LOAD_EVENT:   return "New_load";
unknown's avatar
unknown committed
226
  case SLAVE_EVENT:  return "Slave";
227 228 229 230
  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";
231
  case RAND_EVENT: return "RAND";
unknown's avatar
unknown committed
232 233 234 235
  default: /* impossible */ return "Unknown";
  }
}

236 237 238 239 240
/*****************************************************************************

  Log_event::Log_event()

 ****************************************************************************/
unknown's avatar
unknown committed
241
#ifndef MYSQL_CLIENT
242 243 244
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)
245
{
unknown's avatar
unknown committed
246 247 248 249 250
  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)));
251 252 253 254 255 256 257
}


Log_event::Log_event()
  :temp_buf(0), exec_time(0), cached_event_len(0), flags(0), cache_stmt(0),
   thd(0)
{
unknown's avatar
unknown committed
258 259 260
  server_id=	::server_id;
  when=		time(NULL);
  log_pos=	0;
261
}
262
#endif // !MYSQL_CLIENT
263

264
/*****************************************************************************
265

266
  Log_event::Log_event()
267

268
 ****************************************************************************/
269
Log_event::Log_event(const char* buf, bool old_format)
270
  :temp_buf(0), cached_event_len(0), cache_stmt(0)
271 272 273
{
  when = uint4korr(buf);
  server_id = uint4korr(buf + SERVER_ID_OFFSET);
274 275
  if (old_format)
  {
276
    log_pos=0;
277 278 279 280
    flags=0;
  }
  else
  {
281
    log_pos = uint4korr(buf + LOG_POS_OFFSET);
282 283
    flags = uint2korr(buf + FLAGS_OFFSET);
  }
284 285 286 287 288 289 290 291
#ifndef MYSQL_CLIENT
  thd = 0;
#endif  
}


#ifndef MYSQL_CLIENT

292 293 294 295 296
/*****************************************************************************

  Log_event::exec_event()

 ****************************************************************************/
297
int Log_event::exec_event(struct st_relay_log_info* rli)
298
{
299 300 301 302 303 304 305 306 307 308 309 310 311
  /*
    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)  
312
  {
313 314 315 316 317 318 319
    if (rli->inside_transaction)
      rli->inc_pending(get_event_len());
    else
    {
      rli->inc_pos(get_event_len(),log_pos);
      flush_relay_log_info(rli);
    }
320 321 322
  }
  return 0;
}
unknown's avatar
unknown committed
323

324 325 326 327 328
/*****************************************************************************

  Log_event::pack_info()

 ****************************************************************************/
329
void Log_event::pack_info(Protocol *protocol)
unknown's avatar
unknown committed
330
{
331
  protocol->store("",0);
unknown's avatar
unknown committed
332 333
}

334
/*****************************************************************************
unknown's avatar
unknown committed
335

336
  Log_event::init_show_field_list()
unknown's avatar
unknown committed
337

338 339
 ****************************************************************************/
void Log_event::init_show_field_list(List<Item>* field_list)
unknown's avatar
unknown committed
340
{
341
  field_list->push_back(new Item_empty_string("Log_name", 20));
342 343
  field_list->push_back(new Item_return_int("Pos", 11,
					    MYSQL_TYPE_LONGLONG));
344
  field_list->push_back(new Item_empty_string("Event_type", 20));
345 346 347 348
  field_list->push_back(new Item_return_int("Server_id", 10,
					    MYSQL_TYPE_LONG));
  field_list->push_back(new Item_return_int("Orig_log_pos", 11,
					    MYSQL_TYPE_LONGLONG));
349
  field_list->push_back(new Item_empty_string("Info", 20));
unknown's avatar
unknown committed
350 351
}

352
/*****************************************************************************
unknown's avatar
unknown committed
353

354
  Log_event::net_send()
unknown's avatar
unknown committed
355

356
  Only called by SHOW BINLOG EVENTS
unknown's avatar
unknown committed
357

358
 ****************************************************************************/
359
int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos)
360
{
unknown's avatar
unknown committed
361 362
  const char *p= strrchr(log_name, FN_LIBCHAR);
  const char *event_type;
363 364 365
  if (p)
    log_name = p + 1;
  
366 367 368
  protocol->prepare_for_resend();
  protocol->store(log_name);
  protocol->store((ulonglong) pos);
369
  event_type = get_type_str();
370 371 372 373 374
  protocol->store(event_type, strlen(event_type));
  protocol->store((uint32) server_id);
  protocol->store((ulonglong) log_pos);
  pack_info(protocol);
  return protocol->write();
375 376
}
#endif // !MYSQL_CLIENT
unknown's avatar
unknown committed
377

378
/*****************************************************************************
unknown's avatar
unknown committed
379

380
  Log_event::write()
381

382
 ****************************************************************************/
383
int Log_event::write(IO_CACHE* file)
unknown's avatar
unknown committed
384
{
385
  return (write_header(file) || write_data(file)) ? -1 : 0;
unknown's avatar
unknown committed
386 387
}

388 389 390
/*****************************************************************************

  Log_event::write_header()
391

392
 ****************************************************************************/
393
int Log_event::write_header(IO_CACHE* file)
unknown's avatar
unknown committed
394
{
395
  char buf[LOG_EVENT_HEADER_LEN];
unknown's avatar
unknown committed
396
  char* pos = buf;
unknown's avatar
unknown committed
397
  int4store(pos, (ulong) when); // timestamp
unknown's avatar
unknown committed
398 399
  pos += 4;
  *pos++ = get_type_code(); // event type code
400 401
  int4store(pos, server_id);
  pos += 4;
402 403
  long tmp=get_data_size() + LOG_EVENT_HEADER_LEN;
  int4store(pos, tmp);
unknown's avatar
unknown committed
404
  pos += 4;
405
  int4store(pos, log_pos);
406 407 408
  pos += 4;
  int2store(pos, flags);
  pos += 2;
409
  return (my_b_safe_write(file, (byte*) buf, (uint) (pos - buf)));
unknown's avatar
unknown committed
410 411 412
}


413 414 415 416 417 418
/*****************************************************************************

  Log_event::read_log_event()

 ****************************************************************************/
#ifndef MYSQL_CLIENT
419
int Log_event::read_log_event(IO_CACHE* file, String* packet,
420
			      pthread_mutex_t* log_lock)
unknown's avatar
unknown committed
421 422
{
  ulong data_len;
423
  int result=0;
unknown's avatar
unknown committed
424
  char buf[LOG_EVENT_HEADER_LEN];
425
  DBUG_ENTER("read_log_event");
426

427
  if (log_lock)
428
    pthread_mutex_lock(log_lock);
429 430
  if (my_b_read(file, (byte*) buf, sizeof(buf)))
  {
431 432 433 434 435
    /*
      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.
    */
436
    DBUG_PRINT("error",("file->error: %d", file->error));
437 438 439
    if (!file->error)
      result= LOG_READ_EOF;
    else
440
      result= (file->error > 0 ? LOG_READ_TRUNC : LOG_READ_IO);
441
    goto end;
442
  }
443
  data_len= uint4korr(buf + EVENT_LEN_OFFSET);
unknown's avatar
unknown committed
444 445
  if (data_len < LOG_EVENT_HEADER_LEN ||
      data_len > current_thd->variables.max_allowed_packet)
446
  {
447
    DBUG_PRINT("error",("data_len: %ld", data_len));
448 449 450
    result= ((data_len < LOG_EVENT_HEADER_LEN) ? LOG_READ_BOGUS :
	     LOG_READ_TOO_LARGE);
    goto end;
451
  }
unknown's avatar
unknown committed
452
  packet->append(buf, sizeof(buf));
453
  data_len-= LOG_EVENT_HEADER_LEN;
454 455 456
  if (data_len)
  {
    if (packet->append(file, data_len))
457
    {
458
      /*
459 460
	Here we should never hit EOF in a non-error condition.
	EOF means we are reading the event partially, which should
461 462 463 464
	never happen.
      */
      result= file->error >= 0 ? LOG_READ_TRUNC: LOG_READ_IO;
      /* Implicit goto end; */
465
    }
466
  }
467 468 469 470

end:
  if (log_lock)
    pthread_mutex_unlock(log_lock);
471
  DBUG_RETURN(result);
unknown's avatar
unknown committed
472
}
473
#endif // !MYSQL_CLIENT
unknown's avatar
unknown committed
474

unknown's avatar
unknown committed
475
#ifndef MYSQL_CLIENT
unknown's avatar
unknown committed
476 477
#define UNLOCK_MUTEX if (log_lock) pthread_mutex_unlock(log_lock);
#define LOCK_MUTEX if (log_lock) pthread_mutex_lock(log_lock);
unknown's avatar
unknown committed
478
#define max_allowed_packet current_thd->variables.max_allowed_packet
479
#else
480
#define UNLOCK_MUTEX
481 482 483
#define LOCK_MUTEX
#endif

484 485 486 487 488 489 490
/*****************************************************************************

  Log_event::read_log_event()

  Allocates memory--the caller is responsible for clean-up

 ****************************************************************************/
unknown's avatar
unknown committed
491
#ifndef MYSQL_CLIENT
492 493 494
Log_event* Log_event::read_log_event(IO_CACHE* file,
				     pthread_mutex_t* log_lock,
				     bool old_format)
unknown's avatar
unknown committed
495
#else
496
Log_event* Log_event::read_log_event(IO_CACHE* file, bool old_format)
unknown's avatar
unknown committed
497
#endif  
unknown's avatar
unknown committed
498
{
499
  char head[LOG_EVENT_HEADER_LEN];
500 501
  uint header_size= old_format ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;

502
  LOCK_MUTEX;
503
  if (my_b_read(file, (byte *) head, header_size))
504
  {
unknown's avatar
unknown committed
505
    UNLOCK_MUTEX;
506
    return 0;
507
  }
unknown's avatar
unknown committed
508

509
  uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
510 511 512
  char *buf= 0;
  const char *error= 0;
  Log_event *res=  0;
unknown's avatar
unknown committed
513

514
  if (data_len > max_allowed_packet)
unknown's avatar
unknown committed
515
  {
516 517
    error = "Event too big";
    goto err;
unknown's avatar
unknown committed
518 519
  }

520
  if (data_len < header_size)
unknown's avatar
unknown committed
521
  {
522 523
    error = "Event too small";
    goto err;
unknown's avatar
unknown committed
524
  }
525 526 527

  // some events use the extra byte to null-terminate strings
  if (!(buf = my_malloc(data_len+1, MYF(MY_WME))))
528 529 530
  {
    error = "Out of memory";
    goto err;
unknown's avatar
unknown committed
531
  }
532
  buf[data_len] = 0;
533
  memcpy(buf, head, header_size);
534
  if (my_b_read(file, (byte*) buf + header_size, data_len - header_size))
535 536 537 538
  {
    error = "read error";
    goto err;
  }
539
  if ((res = read_log_event(buf, data_len, &error, old_format)))
540
    res->register_temp_buf(buf);
541

542
err:
unknown's avatar
unknown committed
543
  UNLOCK_MUTEX;
544
  if (error)
545
  {
546 547
    sql_print_error("Error in Log_event::read_log_event(): '%s', \
data_len=%d,event_type=%d",error,data_len,head[EVENT_TYPE_OFFSET]);
548 549
    my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
  }
550
  return res;
unknown's avatar
unknown committed
551 552
}

553 554 555
/*****************************************************************************

  Log_event::read_log_event()
556

557
 ****************************************************************************/
558
Log_event* Log_event::read_log_event(const char* buf, int event_len,
559
				     const char **error, bool old_format)
unknown's avatar
unknown committed
560
{
561
  if (event_len < EVENT_LEN_OFFSET ||
562 563 564
      (uint) event_len != uint4korr(buf+EVENT_LEN_OFFSET))
  {
    *error="Sanity check failed";		// Needed to free buffer
565
    return NULL; // general sanity check - will fail on a partial read
566
  }
567
  
568 569
  Log_event* ev = NULL;
  
570
  switch(buf[EVENT_TYPE_OFFSET]) {
unknown's avatar
unknown committed
571
  case QUERY_EVENT:
572
    ev  = new Query_log_event(buf, event_len, old_format);
573
    break;
unknown's avatar
unknown committed
574
  case LOAD_EVENT:
575
    ev = new Load_log_event(buf, event_len, old_format);
unknown's avatar
unknown committed
576
    break;
577
  case NEW_LOAD_EVENT:
578
    ev = new Load_log_event(buf, event_len, old_format);
579
    break;
unknown's avatar
unknown committed
580
  case ROTATE_EVENT:
581
    ev = new Rotate_log_event(buf, event_len, old_format);
582
    break;
unknown's avatar
unknown committed
583
  case SLAVE_EVENT:
584 585 586
    ev = new Slave_log_event(buf, event_len);
    break;
  case CREATE_FILE_EVENT:
unknown's avatar
unknown committed
587
    ev = new Create_file_log_event(buf, event_len, old_format);
588 589 590 591 592 593 594 595 596 597 598
    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:
599
    ev = new Start_log_event(buf, old_format);
600 601
    break;
  case STOP_EVENT:
602
    ev = new Stop_log_event(buf, old_format);
603 604
    break;
  case INTVAR_EVENT:
605
    ev = new Intvar_log_event(buf, old_format);
606
    break;
unknown's avatar
unknown committed
607 608 609
  case RAND_EVENT:
    ev = new Rand_log_event(buf, old_format);
    break;
610 611
  default:
    break;
unknown's avatar
unknown committed
612
  }
613
  if (!ev || !ev->is_valid())
614
  {
615
    *error= "Found invalid event in binary log";
616 617 618 619 620
    delete ev;
    return 0;
  }
  ev->cached_event_len = event_len;
  return ev;  
unknown's avatar
unknown committed
621 622
}

623
#ifdef MYSQL_CLIENT
624 625 626 627 628 629

/*****************************************************************************

  Log_event::print_header()

 ****************************************************************************/
630 631
void Log_event::print_header(FILE* file)
{
632
  char llbuff[22];
633 634
  fputc('#', file);
  print_timestamp(file);
635
  fprintf(file, " server id %d  log_pos %s ", server_id,
636
	  llstr(log_pos,llbuff)); 
637 638
}

639 640 641 642 643
/*****************************************************************************

  Log_event::print_timestamp()

 ****************************************************************************/
644
void Log_event::print_timestamp(FILE* file, time_t* ts)
unknown's avatar
unknown committed
645
{
unknown's avatar
unknown committed
646
  struct tm *res;
647 648
  if (!ts)
    ts = &when;
649 650
#ifdef MYSQL_SERVER				// This is always false
  struct tm tm_tmp;
unknown's avatar
unknown committed
651
  localtime_r(ts,(res= &tm_tmp));
unknown's avatar
unknown committed
652
#else
653
  res=localtime(ts);
unknown's avatar
unknown committed
654
#endif
655 656

  fprintf(file,"%02d%02d%02d %2d:%02d:%02d",
657 658 659 660 661 662
	  res->tm_year % 100,
	  res->tm_mon+1,
	  res->tm_mday,
	  res->tm_hour,
	  res->tm_min,
	  res->tm_sec);
unknown's avatar
unknown committed
663 664
}

665
#endif // MYSQL_CLIENT
unknown's avatar
unknown committed
666

667
/*****************************************************************************
unknown's avatar
unknown committed
668

669
  Log_event::set_log_pos()
unknown's avatar
unknown committed
670

671 672 673
 ****************************************************************************/
#ifndef MYSQL_CLIENT
void Log_event::set_log_pos(MYSQL_LOG* log)
unknown's avatar
unknown committed
674
{
675 676
  if (!log_pos)
    log_pos = my_b_tell(&log->log_file);
unknown's avatar
unknown committed
677
}
678
#endif // !MYSQL_CLIENT
unknown's avatar
unknown committed
679 680 681



682 683
/*****************************************************************************
 *****************************************************************************
684

685
                          Query_log_event methods
686

687 688
 *****************************************************************************
 ****************************************************************************/
689

690 691
#ifndef MYSQL_CLIENT
/*****************************************************************************
692

693
  Query_log_event::pack_info()
694

695
 ****************************************************************************/
696
void Query_log_event::pack_info(Protocol *protocol)
unknown's avatar
unknown committed
697
{
698 699 700 701
  char *buf, *pos;
  if (!(buf= my_malloc(9 + db_len + q_len, MYF(MY_WME))))
    return;
  pos= buf;    
702
  if (db && db_len)
703
  {
704 705 706 707
    pos= strmov(buf, "use `");
    memcpy(pos, db, db_len);
    pos+= db_len;
    pos= strmov(pos, "`; ");
708
  }
709
  if (query && q_len)
710 711 712 713 714 715
  {
    memcpy(pos, query, q_len);
    pos+= q_len;
  }
  protocol->store(buf, pos-buf);
  my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
716 717 718 719 720 721 722 723 724 725 726
}
#endif // !MYSQL_CLIENT

/*****************************************************************************

  Query_log_event::write()

 ****************************************************************************/
int Query_log_event::write(IO_CACHE* file)
{
  return query ? Log_event::write(file) : -1; 
unknown's avatar
unknown committed
727 728
}

729
/*****************************************************************************
730

731 732 733 734
  Query_log_event::write_data()

 ****************************************************************************/
int Query_log_event::write_data(IO_CACHE* file)
unknown's avatar
unknown committed
735
{
736 737 738 739 740 741 742 743 744 745 746 747
  if (!query)
    return -1;
  
  char buf[QUERY_HEADER_LEN]; 
  int4store(buf + Q_THREAD_ID_OFFSET, thread_id);
  int4store(buf + Q_EXEC_TIME_OFFSET, exec_time);
  buf[Q_DB_LEN_OFFSET] = (char) db_len;
  int2store(buf + Q_ERR_CODE_OFFSET, error_code);

  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;
unknown's avatar
unknown committed
748 749
}

750 751 752
/*****************************************************************************

  Query_log_event::Query_log_event()
753

754
 ****************************************************************************/
755 756
#ifndef MYSQL_CLIENT
Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
757
				 ulong query_length, bool using_trans)
unknown's avatar
unknown committed
758 759 760
  :Log_event(thd_arg, !thd_arg->lex.tmp_table_used ? 
	     0 : LOG_EVENT_THREAD_SPECIFIC_F, using_trans), 
   data_buf(0), query(query_arg),
761
   db(thd_arg->db), q_len((uint32) query_length),
762
  error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno),
763
  thread_id(thd_arg->thread_id)
764 765 766 767 768 769
{
  time_t end_time;
  time(&end_time);
  exec_time = (ulong) (end_time  - thd->start_time);
  db_len = (db) ? (uint32) strlen(db) : 0;
}
770 771 772
#endif // MYSQL_CLIENT

/*****************************************************************************
773

774 775 776
  Query_log_event::Query_log_event()

 ****************************************************************************/
777
Query_log_event::Query_log_event(const char* buf, int event_len,
unknown's avatar
unknown committed
778 779
				 bool old_format)
  :Log_event(buf, old_format),data_buf(0), query(NULL), db(NULL)
unknown's avatar
unknown committed
780 781
{
  ulong data_len;
782 783 784 785 786 787 788 789 790 791 792 793 794 795
  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;
  }
unknown's avatar
unknown committed
796

797 798
  exec_time = uint4korr(buf + Q_EXEC_TIME_OFFSET);
  error_code = uint2korr(buf + Q_ERR_CODE_OFFSET);
unknown's avatar
unknown committed
799

800
  if (!(data_buf = (char*) my_malloc(data_len + 1, MYF(MY_WME))))
unknown's avatar
unknown committed
801 802
    return;

803 804
  memcpy(data_buf, buf + Q_DATA_OFFSET, data_len);
  thread_id = uint4korr(buf + Q_THREAD_ID_OFFSET);
unknown's avatar
unknown committed
805
  db = data_buf;
806
  db_len = (uint)buf[Q_DB_LEN_OFFSET];
unknown's avatar
unknown committed
807 808 809 810 811
  query=data_buf + db_len + 1;
  q_len = data_len - 1 - db_len;
  *((char*)query+q_len) = 0;
}

812
/*****************************************************************************
813

814
  Query_log_event::print()
815

816 817
 ****************************************************************************/
#ifdef MYSQL_CLIENT
818
void Query_log_event::print(FILE* file, bool short_form, char* last_db)
unknown's avatar
unknown committed
819
{
820
  char buff[40],*end;				// Enough for SET TIMESTAMP
unknown's avatar
unknown committed
821 822
  if (!short_form)
  {
823
    print_header(file);
824 825
    fprintf(file, "\tQuery\tthread_id=%lu\texec_time=%lu\terror_code=%d\n",
	    (ulong) thread_id, (ulong) exec_time, error_code);
unknown's avatar
unknown committed
826 827
  }

828 829
  bool same_db = 0;

unknown's avatar
unknown committed
830
  if (db && last_db)
831 832 833 834
  {
    if (!(same_db = !memcmp(last_db, db, db_len + 1)))
      memcpy(last_db, db, db_len + 1);
  }
835 836
  
  if (db && db[0] && !same_db)
unknown's avatar
unknown committed
837
    fprintf(file, "use %s;\n", db);
838 839 840 841
  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));
unknown's avatar
unknown committed
842 843
  if (flags & LOG_EVENT_THREAD_SPECIFIC_F)
    fprintf(file,"SET @@session.pseudo_thread_id=%lu;\n",(ulong)thread_id);
unknown's avatar
unknown committed
844 845 846
  my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
  fprintf(file, ";\n");
}
847
#endif // MYSQL_CLIENT
848

849
/*****************************************************************************
unknown's avatar
unknown committed
850

851
  Query_log_event::exec_event()
unknown's avatar
unknown committed
852

853 854 855
 ****************************************************************************/
#ifndef MYSQL_CLIENT
int Query_log_event::exec_event(struct st_relay_log_info* rli)
unknown's avatar
unknown committed
856
{
857 858 859
  int expected_error,actual_error = 0;
  init_sql_alloc(&thd->mem_root, 8192,0);
  thd->db = rewrite_db((char*)db);
unknown's avatar
unknown committed
860

861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
  /*
    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();

  if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
  {
    thd->query = (char*)query;
    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));
unknown's avatar
unknown committed
876 877 878
    thd->query_error= 0;			// clear error
    thd->clear_error();
    
unknown's avatar
unknown committed
879
    thd->variables.pseudo_thread_id= thread_id;		// for temp tables
880 881 882 883 884 885 886 887 888 889 890
	
    /*
      Sanity check to make sure the master did not get a really bad
      error on the query.
    */
    if (ignored_error_code((expected_error = error_code)) ||
	!check_expected_error(thd,rli,expected_error))
    {
      mysql_log.write(thd,COM_QUERY,"%s",thd->query);
      DBUG_PRINT("query",("%s",thd->query));
      mysql_parse(thd, thd->query, q_len);
unknown's avatar
unknown committed
891

unknown's avatar
unknown committed
892 893 894
      /*
	Set a flag if we are inside an transaction so that we can restart
	the transaction from the start if we are killed
895

unknown's avatar
unknown committed
896 897 898 899 900 901 902
	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;
unknown's avatar
unknown committed
903

904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950
      DBUG_PRINT("info",("expected_error: %d  last_errno: %d",
			 expected_error, thd->net.last_errno));
      if ((expected_error != (actual_error= thd->net.last_errno)) &&
	  expected_error &&
	  !ignored_error_code(actual_error) &&
	  !ignored_error_code(expected_error))
      {
	const char* errmsg = "Slave: did not get the expected error\
 running query from master - expected: '%s' (%d), got '%s' (%d)"; 
	sql_print_error(errmsg, ER_SAFE(expected_error),
			expected_error,
			actual_error ? thd->net.last_error: "no error",
			actual_error);
	thd->query_error = 1;
      }
      else if (expected_error == actual_error ||
	       ignored_error_code(actual_error))
      {
	DBUG_PRINT("info",("error ignored"));
	thd->query_error = 0;
	*rli->last_slave_error = 0;
	rli->last_slave_errno = 0;
      }
    }
    else
    {
      // master could be inconsistent, abort and tell DBA to check/fix it
      thd->db = thd->query = 0;
      thd->variables.convert_set = 0;
      close_thread_tables(thd);
      free_root(&thd->mem_root,0);
      return 1;
    }
  }
  thd->db= 0;				// prevent db from being freed
  thd->query= 0;			// just to be sure
  // assume no convert for next query unless set explictly
  thd->variables.convert_set = 0;
  close_thread_tables(thd);
      
  if (thd->query_error || thd->fatal_error)
  {
    slave_print_error(rli,actual_error, "error '%s' on query '%s'",
		      actual_error ? thd->net.last_error :
		      "unexpected success or fatal error", query);
    free_root(&thd->mem_root,0);
    return 1;
unknown's avatar
unknown committed
951
  }
952 953
  free_root(&thd->mem_root,0);
  return Log_event::exec_event(rli); 
unknown's avatar
unknown committed
954
}
955
#endif // !MYSQL_CLIENT
unknown's avatar
unknown committed
956

unknown's avatar
unknown committed
957

958 959
/*****************************************************************************
 *****************************************************************************
960

961
                          Start_log_event methods
unknown's avatar
unknown committed
962

963 964
 *****************************************************************************
 ****************************************************************************/
unknown's avatar
unknown committed
965

unknown's avatar
unknown committed
966
/*****************************************************************************
967 968 969

  Start_log_event::pack_info()

unknown's avatar
unknown committed
970
 ****************************************************************************/
971
#ifndef MYSQL_CLIENT
972
void Start_log_event::pack_info(Protocol *protocol)
unknown's avatar
unknown committed
973
{
974 975 976 977 978 979
  char buf[12 + ST_SERVER_VER_LEN + 14 + 22], *pos;
  pos= strmov(buf, "Server ver: ");
  pos= strmov(pos, server_version);
  pos= strmov(pos, ", Binlog ver: ");
  pos=int10_to_str(binlog_version, pos, 10);
  protocol->store(buf, pos-buf);
unknown's avatar
unknown committed
980
}
981 982 983 984 985
#endif // !MYSQL_CLIENT

/*****************************************************************************

  Start_log_event::print()
unknown's avatar
unknown committed
986

987
 ****************************************************************************/
unknown's avatar
unknown committed
988
#ifdef MYSQL_CLIENT
989
void Start_log_event::print(FILE* file, bool short_form, char* last_db)
unknown's avatar
unknown committed
990
{
991 992 993 994 995 996 997 998
  if (short_form)
    return;

  print_header(file);
  fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version,
	  server_version);
  print_timestamp(file, (time_t*)&created);
  fputc('\n', file);
unknown's avatar
unknown committed
999 1000
  fflush(file);
}
1001
#endif // MYSQL_CLIENT
1002

1003
/*****************************************************************************
unknown's avatar
unknown committed
1004

1005 1006 1007 1008 1009 1010
  Start_log_event::Start_log_event()

 ****************************************************************************/
Start_log_event::Start_log_event(const char* buf,
				 bool old_format)
  :Log_event(buf, old_format)
1011
{
1012 1013 1014 1015 1016
  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,
	 ST_SERVER_VER_LEN);
  created = uint4korr(buf+ST_CREATED_OFFSET);
unknown's avatar
unknown committed
1017 1018
}

1019
/*****************************************************************************
1020

1021
  Start_log_event::write_data()
1022

1023 1024
 ****************************************************************************/
int Start_log_event::write_data(IO_CACHE* file)
1025
{
1026 1027 1028 1029 1030
  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);
  return (my_b_safe_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0);
1031
}
1032

1033
/*****************************************************************************
1034

1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
  Start_log_event::exec_event()

  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.

  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.

 ****************************************************************************/
#ifndef MYSQL_CLIENT
int Start_log_event::exec_event(struct st_relay_log_info* rli)
{
  /* All temporary tables was deleted on the master */
  close_temporary_tables(thd);
  /*
    If we have old format, load_tmpdir is cleaned up by the I/O thread
  */
  if (!rli->mi->old_format)
    cleanup_load_tmpdir();
  return Log_event::exec_event(rli);
}
#endif // !MYSQL_CLIENT


/*****************************************************************************
 *****************************************************************************

                          Load_log_event methods

 *****************************************************************************
 ****************************************************************************/

/*****************************************************************************

  Load_log_event::pack_info()

 ****************************************************************************/
#ifndef MYSQL_CLIENT
1079
void Load_log_event::pack_info(Protocol *protocol)
1080
{
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100
  char *buf, *pos;
  uint buf_len;

  buf_len= 
    5 + db_len + 3 +                        // "use DB; "
    18 + fname_len + 2 +                    // "LOAD DATA INFILE 'file''"
    9 +                                     // " REPLACE or IGNORE "
    11 + table_name_len +                   // "INTO TABLE table"
    21 + sql_ex.field_term_len*4 + 2 +      // " FIELDS TERMINATED BY 'str'"
    23 + sql_ex.enclosed_len*4 + 2 +        // " OPTIONALLY ENCLOSED BY 'str'"
    12 + sql_ex.escaped_len*4 + 2 +         // " ESCAPED BY 'str'"
    21 + sql_ex.line_term_len*4 + 2 +       // " FIELDS TERMINATED BY 'str'"
    19 + sql_ex.line_start_len*4 + 2 +      // " LINES STARTING BY 'str'" 
    15 + 22 +                               // " IGNORE xxx  LINES" 
    3 + (num_fields-1)*2 + field_block_len; // " (field1, field2, ...)"

  buf= my_malloc(buf_len, MYF(MY_WME));
  if (!buf)
    return;
  pos= buf;
1101
  if (db && db_len)
1102
  {
1103 1104 1105 1106
    pos= strmov(pos, "use `");
    memcpy(pos, db, db_len);
    pos+= db_len;  
    pos= strmov(pos, "`; ");
1107
  }
1108

1109 1110 1111 1112 1113
  pos= strmov(pos, "LOAD DATA INFILE '");
  memcpy(pos, fname, fname_len);
  pos+= fname_len;
  pos= strmov(pos, "' ");

1114
  if (sql_ex.opt_flags && REPLACE_FLAG )
1115
    pos= strmov(pos, " REPLACE ");
1116
  else if (sql_ex.opt_flags && IGNORE_FLAG )
1117 1118 1119 1120 1121 1122
    pos= strmov(pos, " IGNORE ");

  pos= strmov(pos ,"INTO TABLE ");
  memcpy(pos, table_name, table_name_len);
  pos+= table_name_len;

1123
  if (sql_ex.field_term_len)
1124
  {
1125 1126
    pos= strmov(pos, " FIELDS TERMINATED BY ");
    pos= pretty_print_str(pos, sql_ex.field_term, sql_ex.field_term_len);
1127 1128 1129 1130 1131
  }

  if (sql_ex.enclosed_len)
  {
    if (sql_ex.opt_flags && OPT_ENCLOSED_FLAG )
1132 1133 1134
      pos= strmov(pos, " OPTIONALLY ");
    pos= strmov(pos, " ENCLOSED BY ");
    pos= pretty_print_str(pos, sql_ex.enclosed, sql_ex.enclosed_len);
1135
  }
1136

1137 1138
  if (sql_ex.escaped_len)
  {
1139 1140
    pos= strmov(pos, " ESCAPED BY ");
    pos= pretty_print_str(pos, sql_ex.escaped, sql_ex.escaped_len);
1141
  }
1142

1143 1144
  if (sql_ex.line_term_len)
  {
1145 1146
    pos= strmov(pos, " LINES TERMINATED BY ");
    pos= pretty_print_str(pos, sql_ex.line_term, sql_ex.line_term_len);
1147 1148 1149 1150
  }

  if (sql_ex.line_start_len)
  {
1151 1152
    pos= strmov(pos, " LINES STARTING BY ");
    pos= pretty_print_str(pos, sql_ex.line_start, sql_ex.line_start_len);
1153
  }
1154

1155
  if ((int)skip_lines > 0)
1156 1157 1158 1159 1160
  {
    pos= strmov(pos, " IGNORE ");
    pos= longlong10_to_str((long) skip_lines, pos, 10);
    pos= strmov(pos," LINES ");    
  }
1161 1162 1163 1164 1165

  if (num_fields)
  {
    uint i;
    const char* field = fields;
1166
    pos= strmov(pos, " (");
1167 1168 1169
    for (i = 0; i < num_fields; i++)
    {
      if (i)
1170 1171 1172
        pos= strmov(pos, " ,");
      memcpy(pos, field, field_lens[i]);
      pos+= field_lens[i];
1173 1174
      field += field_lens[i]  + 1;
    }
1175
    *pos++= ')';
1176
  }
1177

1178 1179
  protocol->store(buf, pos-buf);
  my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
1180
}
1181
#endif // !MYSQL_CLIENT
1182

1183
/*****************************************************************************
1184

1185 1186 1187 1188
  Load_log_event::write_data_header()

 ****************************************************************************/
int Load_log_event::write_data_header(IO_CACHE* file)
1189
{
1190 1191 1192 1193 1194 1195 1196 1197
  char buf[LOAD_HEADER_LEN];
  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);
  return my_b_safe_write(file, (byte*)buf, LOAD_HEADER_LEN);
1198
}
1199

1200
/*****************************************************************************
1201

1202 1203 1204 1205
  Load_log_event::write_data_body()

 ****************************************************************************/
int Load_log_event::write_data_body(IO_CACHE* file)
1206
{
1207 1208 1209
  if (sql_ex.write_data(file))
    return 1;
  if (num_fields && fields && field_lens)
1210
  {
1211 1212 1213
    if (my_b_safe_write(file, (byte*)field_lens, num_fields) ||
	my_b_safe_write(file, (byte*)fields, field_block_len))
      return 1;
1214
  }
1215 1216 1217
  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));
1218 1219
}

1220 1221 1222
/*****************************************************************************

  Load_log_event::Load_log_event()
1223

1224
 ****************************************************************************/
1225
#ifndef MYSQL_CLIENT
unknown's avatar
unknown committed
1226 1227 1228
Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex,
			       const char *db_arg, const char *table_name_arg,
			       List<Item> &fields_arg,
unknown's avatar
unknown committed
1229 1230 1231 1232 1233 1234
			       enum enum_duplicates handle_dup,
			       bool using_trans)
  :Log_event(thd_arg, 0, using_trans), thread_id(thd_arg->thread_id),
   num_fields(0), fields(0), field_lens(0),field_block_len(0),
   table_name(table_name_arg ? table_name_arg : ""),
   db(db_arg), fname(ex->file_name)
unknown's avatar
unknown committed
1235 1236 1237
{
  time_t end_time;
  time(&end_time);
1238
  exec_time = (ulong) (end_time  - thd_arg->start_time);
1239 1240 1241
  /* db can never be a zero pointer in 4.0 */
  db_len = (uint32) strlen(db);
  table_name_len = (uint32) strlen(table_name);
unknown's avatar
unknown committed
1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254
  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;
1255
    
unknown's avatar
unknown committed
1256 1257 1258 1259
  if (ex->dumpfile)
    sql_ex.opt_flags |= DUMPFILE_FLAG;
  if (ex->opt_enclosed)
    sql_ex.opt_flags |= OPT_ENCLOSED_FLAG;
1260

unknown's avatar
unknown committed
1261
  sql_ex.empty_flags = 0;
1262

1263
  switch (handle_dup) {
unknown's avatar
unknown committed
1264 1265 1266 1267 1268 1269 1270 1271 1272
  case DUP_IGNORE:
    sql_ex.opt_flags |= IGNORE_FLAG;
    break;
  case DUP_REPLACE:
    sql_ex.opt_flags |= REPLACE_FLAG;
    break;
  case DUP_UPDATE:				// Impossible here
  case DUP_ERROR:
    break;	
unknown's avatar
unknown committed
1273
  }
1274

unknown's avatar
unknown committed
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284
  if (!ex->field_term->length())
    sql_ex.empty_flags |= FIELD_TERM_EMPTY;
  if (!ex->enclosed->length())
    sql_ex.empty_flags |= ENCLOSED_EMPTY;
  if (!ex->line_term->length())
    sql_ex.empty_flags |= LINE_TERM_EMPTY;
  if (!ex->line_start->length())
    sql_ex.empty_flags |= LINE_START_EMPTY;
  if (!ex->escaped->length())
    sql_ex.empty_flags |= ESCAPED_EMPTY;
1285
    
unknown's avatar
unknown committed
1286
  skip_lines = ex->skip_lines;
1287

unknown's avatar
unknown committed
1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
  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);
1299 1300
  }

unknown's avatar
unknown committed
1301 1302 1303
  field_lens = (const uchar*)field_lens_buf.ptr();
  fields = fields_buf.ptr();
}
1304
#endif // !MYSQL_CLIENT
unknown's avatar
unknown committed
1305

1306 1307 1308
/*****************************************************************************

  Load_log_event::Load_log_event()
1309

1310 1311 1312
  The caller must do buf[event_len] = 0 before he starts using the
  constructed event.

1313
 ****************************************************************************/
unknown's avatar
unknown committed
1314
Load_log_event::Load_log_event(const char *buf, int event_len,
1315 1316
			       bool old_format)
  :Log_event(buf, old_format),num_fields(0),fields(0),
unknown's avatar
unknown committed
1317 1318
   field_lens(0),field_block_len(0),
   table_name(0),db(0),fname(0)
unknown's avatar
unknown committed
1319
{
1320
  if (!event_len) // derived class, will call copy_log_event() itself
1321
    return;
1322
  copy_log_event(buf, event_len, old_format);
1323 1324
}

1325 1326 1327 1328 1329
/*****************************************************************************

  Load_log_event::copy_log_event()

 ****************************************************************************/
1330 1331
int Load_log_event::copy_log_event(const char *buf, ulong event_len,
				   bool old_format)
1332
{
1333
  uint data_len;
1334
  char* buf_end = (char*)buf + event_len;
1335
  uint header_len= old_format ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
1336
  const char* data_head = buf + header_len;
1337 1338 1339 1340 1341 1342
  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);
unknown's avatar
unknown committed
1343
	  
1344
  int body_offset = ((buf[EVENT_TYPE_OFFSET] == LOAD_EVENT) ?
1345
		     LOAD_HEADER_LEN + header_len :
1346
		     get_data_body_offset());
unknown's avatar
unknown committed
1347
  
unknown's avatar
unknown committed
1348
  if ((int) event_len < body_offset)
1349
    return 1;
1350 1351 1352 1353
  /*
    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.
  */
1354 1355 1356 1357 1358 1359
  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;
1360
  if (num_fields > data_len) // simple sanity check against corruption
1361
    return 1;
1362
  for (uint i = 0; i < num_fields; i++)
1363
    field_block_len += (uint)field_lens[i] + 1;
1364

unknown's avatar
unknown committed
1365 1366 1367 1368
  fields = (char*)field_lens + num_fields;
  table_name  = fields + field_block_len;
  db = table_name + table_name_len + 1;
  fname = db + db_len + 1;
1369 1370
  fname_len = strlen(fname);
  // null termination is accomplished by the caller doing buf[event_len]=0
1371
  return 0;
unknown's avatar
unknown committed
1372 1373
}

1374
/*****************************************************************************
unknown's avatar
unknown committed
1375

1376 1377 1378 1379
  Load_log_event::print()

 ****************************************************************************/
#ifdef MYSQL_CLIENT
1380
void Load_log_event::print(FILE* file, bool short_form, char* last_db)
unknown's avatar
unknown committed
1381 1382 1383
{
  if (!short_form)
  {
1384
    print_header(file);
1385
    fprintf(file, "\tQuery\tthread_id=%ld\texec_time=%ld\n",
unknown's avatar
unknown committed
1386 1387 1388
	    thread_id, exec_time);
  }

1389
  bool same_db = 0;
unknown's avatar
unknown committed
1390 1391 1392 1393 1394
  if (db && last_db)
  {
    if (!(same_db = !memcmp(last_db, db, db_len + 1)))
      memcpy(last_db, db, db_len + 1);
  }
1395
  
unknown's avatar
unknown committed
1396
  if (db && db[0] && !same_db)
unknown's avatar
unknown committed
1397 1398
    fprintf(file, "use %s;\n", db);

1399 1400 1401 1402
  fprintf(file, "LOAD ");
  if (check_fname_outside_temp_buf())
    fprintf(file, "LOCAL ");
  fprintf(file, "DATA INFILE '%-*s' ", fname_len, fname);
unknown's avatar
unknown committed
1403

unknown's avatar
unknown committed
1404
  if (sql_ex.opt_flags && REPLACE_FLAG )
unknown's avatar
unknown committed
1405
    fprintf(file," REPLACE ");
unknown's avatar
unknown committed
1406
  else if (sql_ex.opt_flags && IGNORE_FLAG )
unknown's avatar
unknown committed
1407 1408 1409
    fprintf(file," IGNORE ");
  
  fprintf(file, "INTO TABLE %s ", table_name);
unknown's avatar
unknown committed
1410
  if (sql_ex.field_term)
unknown's avatar
unknown committed
1411 1412
  {
    fprintf(file, " FIELDS TERMINATED BY ");
1413
    pretty_print_str(file, sql_ex.field_term, sql_ex.field_term_len);
unknown's avatar
unknown committed
1414 1415
  }

unknown's avatar
unknown committed
1416
  if (sql_ex.enclosed)
unknown's avatar
unknown committed
1417
  {
unknown's avatar
unknown committed
1418
    if (sql_ex.opt_flags && OPT_ENCLOSED_FLAG )
unknown's avatar
unknown committed
1419 1420
      fprintf(file," OPTIONALLY ");
    fprintf(file, " ENCLOSED BY ");
1421
    pretty_print_str(file, sql_ex.enclosed, sql_ex.enclosed_len);
unknown's avatar
unknown committed
1422 1423
  }
     
1424
  if (sql_ex.escaped)
unknown's avatar
unknown committed
1425 1426
  {
    fprintf(file, " ESCAPED BY ");
1427
    pretty_print_str(file, sql_ex.escaped, sql_ex.escaped_len);
unknown's avatar
unknown committed
1428 1429
  }
     
1430
  if (sql_ex.line_term)
unknown's avatar
unknown committed
1431 1432
  {
    fprintf(file," LINES TERMINATED BY ");
1433
    pretty_print_str(file, sql_ex.line_term, sql_ex.line_term_len);
unknown's avatar
unknown committed
1434 1435
  }

1436
  if (sql_ex.line_start)
unknown's avatar
unknown committed
1437 1438
  {
    fprintf(file," LINES STARTING BY ");
1439
    pretty_print_str(file, sql_ex.line_start, sql_ex.line_start_len);
unknown's avatar
unknown committed
1440 1441
  }
     
unknown's avatar
unknown committed
1442
  if ((int)skip_lines > 0)
unknown's avatar
unknown committed
1443
    fprintf(file, " IGNORE %ld LINES ", (long) skip_lines);
unknown's avatar
unknown committed
1444

1445 1446 1447 1448
  if (num_fields)
  {
    uint i;
    const char* field = fields;
1449 1450
    fprintf(file, " (");
    for (i = 0; i < num_fields; i++)
unknown's avatar
unknown committed
1451
    {
unknown's avatar
unknown committed
1452
      if (i)
1453 1454
	fputc(',', file);
      fprintf(file, field);
unknown's avatar
unknown committed
1455
	  
1456
      field += field_lens[i]  + 1;
unknown's avatar
unknown committed
1457
    }
1458 1459
    fputc(')', file);
  }
unknown's avatar
unknown committed
1460 1461 1462

  fprintf(file, ";\n");
}
1463 1464
#endif /* #ifdef MYSQL_CLIENT */

1465
/*****************************************************************************
1466

1467
  Load_log_event::set_fields()
1468

1469 1470
 ****************************************************************************/
#ifndef MYSQL_CLIENT
1471
void Load_log_event::set_fields(List<Item> &field_list)
unknown's avatar
unknown committed
1472 1473
{
  uint i;
unknown's avatar
unknown committed
1474
  const char* field = fields;
1475
  for (i= 0; i < num_fields; i++)
unknown's avatar
unknown committed
1476
  {
1477 1478
    field_list.push_back(new Item_field(db, table_name, field));	  
    field+= field_lens[i]  + 1;
unknown's avatar
unknown committed
1479
  }
unknown's avatar
unknown committed
1480
}
1481
#endif // !MYSQL_CLIENT
unknown's avatar
unknown committed
1482

1483
#ifndef MYSQL_CLIENT
unknown's avatar
unknown committed
1484

unknown's avatar
unknown committed
1485 1486
/*
  Does the data loading job when executing a LOAD DATA on the slave
1487

unknown's avatar
unknown committed
1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501
  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.
1502

unknown's avatar
unknown committed
1503 1504 1505 1506 1507 1508 1509
  DESCRIPTION
    Does the data loading job when executing a LOAD DATA on the slave
 
  RETURN VALUE
    0           Success                                                 
    1    	Failure
*/
1510

unknown's avatar
unknown committed
1511 1512
int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, 
			       bool use_rli_only_for_errors)
1513
{
1514 1515 1516 1517 1518 1519
  init_sql_alloc(&thd->mem_root, 8192,0);
  thd->db = rewrite_db((char*)db);
  thd->query = 0;
  thd->query_error = 0;
	    
  if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
1520
  {
1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546
    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;
    tables.alias = tables.real_name = (char*)table_name;
    tables.lock_type = TL_WRITE;
    // the table will be opened in mysql_load    
    if (table_rules_on && !tables_ok(thd, &tables))
    {
      // TODO: this is a bug - this needs to be moved to the I/O thread
      if (net)
        skip_load_data_infile(net);
    }
    else
    {
      char llbuff[22];
      enum enum_duplicates handle_dup = DUP_IGNORE;
      if (sql_ex.opt_flags && REPLACE_FLAG)
	handle_dup = DUP_REPLACE;
      sql_exchange ex((char*)fname, sql_ex.opt_flags &&
		      DUMPFILE_FLAG );
1547 1548 1549 1550 1551
      String field_term(sql_ex.field_term,sql_ex.field_term_len,log_cs);
      String enclosed(sql_ex.enclosed,sql_ex.enclosed_len,log_cs);
      String line_term(sql_ex.line_term,sql_ex.line_term_len,log_cs);
      String line_start(sql_ex.line_start,sql_ex.line_start_len,log_cs);
      String escaped(sql_ex.escaped,sql_ex.escaped_len, log_cs);
1552 1553 1554 1555 1556 1557

      ex.opt_enclosed = (sql_ex.opt_flags & OPT_ENCLOSED_FLAG);
      if (sql_ex.empty_flags & FIELD_TERM_EMPTY)
	ex.field_term->length(0);

      ex.skip_lines = skip_lines;
unknown's avatar
unknown committed
1558 1559
      List<Item> field_list;
      set_fields(field_list);
unknown's avatar
unknown committed
1560
      thd->variables.pseudo_thread_id= thd->thread_id;
1561 1562 1563 1564 1565 1566 1567 1568 1569
      if (net)
      {
	// mysql_load will use thd->net to read the file
	thd->net.vio = net->vio;
	/*
	  Make sure the client does not get confused about the packet sequence
	*/
	thd->net.pkt_nr = net->pkt_nr;
      }
unknown's avatar
unknown committed
1570
      if (mysql_load(thd, &ex, &tables, field_list, handle_dup, net != 0,
1571 1572 1573
		     TL_WRITE))
	thd->query_error = 1;
      if (thd->cuted_fields)
unknown's avatar
unknown committed
1574 1575 1576 1577 1578
      {
	/* 
	   log_pos is the position of the LOAD
	   event in the master log
	*/
1579
	sql_print_error("Slave: load data infile at position %s in log \
unknown's avatar
unknown committed
1580
'%s' produced %d warning(s)", llstr(log_pos,llbuff), RPL_LOG_NAME, 
1581
			thd->cuted_fields );
unknown's avatar
unknown committed
1582
      }
1583 1584 1585
      if (net)
        net->pkt_nr= thd->net.pkt_nr;
    }
1586 1587
  }
  else
1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620
  {
    /*
      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
    */
    if (net)
      skip_load_data_infile(net);
  }
	    
  thd->net.vio = 0; 
  thd->db= 0;					// prevent db from being freed
  close_thread_tables(thd);
  if (thd->query_error)
  {
    int sql_error = thd->net.last_errno;
    if (!sql_error)
      sql_error = ER_UNKNOWN_ERROR;
		
    slave_print_error(rli,sql_error,
		      "Slave: Error '%s' running load data infile ",
		      ER_SAFE(sql_error));
    free_root(&thd->mem_root,0);
    return 1;
  }
  free_root(&thd->mem_root,0);
	    
  if (thd->fatal_error)
  {
    sql_print_error("Slave: Fatal error running LOAD DATA INFILE ");
    return 1;
  }

unknown's avatar
unknown committed
1621
  return ( use_rli_only_for_errors ? 0 : Log_event::exec_event(rli) ); 
1622
}
1623
#endif // !MYSQL_CLIENT
1624 1625


1626 1627
/*****************************************************************************
 *****************************************************************************
1628

1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639
                          Rotate_log_event methods

 *****************************************************************************
 ****************************************************************************/

/*****************************************************************************

  Rotate_log_event::pack_info()

 ****************************************************************************/
#ifndef MYSQL_CLIENT
1640
void Rotate_log_event::pack_info(Protocol *protocol)
1641
{
1642 1643 1644 1645 1646 1647 1648 1649
  char *buf, *b_pos;
  if (!(buf= my_malloc(ident_len + 45, MYF(MY_WME))))
    return;
  b_pos= buf;
  memcpy(buf, new_log_ident, ident_len);
  b_pos+= ident_len;
  b_pos= strmov(b_pos, ";pos=");
  b_pos=int10_to_str(pos, b_pos, 10);
1650
  if (flags & LOG_EVENT_FORCED_ROTATE_F)
1651 1652 1653
    b_pos= strmov(b_pos ,"; forced by master");
  protocol->store(buf, b_pos-buf);
  my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
1654
}
1655
#endif // !MYSQL_CLIENT
1656

1657
/*****************************************************************************
1658

1659 1660 1661 1662 1663
  Rotate_log_event::print()

 ****************************************************************************/
#ifdef MYSQL_CLIENT
void Rotate_log_event::print(FILE* file, bool short_form, char* last_db)
1664
{
1665
  char buf[22];
unknown's avatar
unknown committed
1666
  if (short_form)
1667
    return;
1668

1669
  print_header(file);
1670 1671 1672 1673 1674 1675 1676
  fprintf(file, "\tRotate to ");
  if (new_log_ident)
    my_fwrite(file, (byte*) new_log_ident, (uint)ident_len, 
	      MYF(MY_NABP | MY_WME));
  fprintf(file, "  pos: %s", llstr(pos, buf));
  if (flags & LOG_EVENT_FORCED_ROTATE_F)
    fprintf(file,"  forced by master");
1677
  fputc('\n', file);
1678
  fflush(file);
1679
}
1680
#endif // MYSQL_CLIENT
1681

1682
/*****************************************************************************
1683

1684
  Rotate_log_event::Rotate_log_event()
1685

1686 1687 1688 1689
 ****************************************************************************/
Rotate_log_event::Rotate_log_event(const char* buf, int event_len,
				   bool old_format)
  :Log_event(buf, old_format),new_log_ident(NULL),alloced(0)
1690
{
1691 1692 1693 1694
  // The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET
  int header_size = (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
  uint ident_offset;
  if (event_len < header_size)
1695
    return;
1696 1697 1698 1699 1700 1701
  buf += header_size;
  if (old_format)
  {
    ident_len = (uint)(event_len - OLD_HEADER_LEN);
    pos = 4;
    ident_offset = 0;
1702
  }
1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713
  else
  {
    ident_len = (uint)(event_len - ROTATE_EVENT_OVERHEAD);
    pos = uint8korr(buf + R_POS_OFFSET);
    ident_offset = ROTATE_HEADER_LEN;
  }
  set_if_smaller(ident_len,FN_REFLEN-1);
  if (!(new_log_ident= my_strdup_with_length((byte*) buf +
					     ident_offset,
					     (uint) ident_len,
					     MYF(MY_WME))))
1714
    return;
1715
  alloced = 1;
1716
}
1717

1718
/*****************************************************************************
1719

1720
  Rotate_log_event::write_data()
1721

1722 1723
 ****************************************************************************/
int Rotate_log_event::write_data(IO_CACHE* file)
1724
{
1725 1726 1727 1728
  char buf[ROTATE_HEADER_LEN];
  int8store(buf, pos + R_POS_OFFSET);
  return (my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) ||
	  my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len));
1729 1730
}

1731
/*****************************************************************************
1732

1733 1734 1735
  Rotate_log_event::exec_event()

  Got a rotate log even from the master
1736

1737 1738 1739
  IMPLEMENTATION
    This is mainly used so that we can later figure out the logname and
    position for the master.
1740

1741 1742 1743 1744 1745 1746 1747 1748 1749
    We can't rotate the slave as this will cause infinitive rotations
    in a A -> B -> A setup.

  RETURN VALUES
    0	ok

 ****************************************************************************/
#ifndef MYSQL_CLIENT
int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
1750
{
1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762
  char* log_name = rli->master_log_name;
  DBUG_ENTER("Rotate_log_event::exec_event");

  pthread_mutex_lock(&rli->data_lock);
  memcpy(log_name, new_log_ident, ident_len+1);
  rli->master_log_pos = pos;
  rli->relay_log_pos += get_event_len();
  DBUG_PRINT("info", ("master_log_pos: %d", (ulong) rli->master_log_pos));
  pthread_mutex_unlock(&rli->data_lock);
  pthread_cond_broadcast(&rli->data_cond);
  flush_relay_log_info(rli);
  DBUG_RETURN(0);
1763
}
1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777
#endif // !MYSQL_CLIENT


/*****************************************************************************
 *****************************************************************************

                          Intvar_log_event methods

 *****************************************************************************
 ****************************************************************************/

/*****************************************************************************

  Intvar_log_event::pack_info()
1778

1779
 ****************************************************************************/
1780
#ifndef MYSQL_CLIENT
1781
void Intvar_log_event::pack_info(Protocol *protocol)
1782
{
1783 1784 1785 1786 1787
  char buf[64], *pos;
  pos= strmov(buf, get_var_type_name());
  *(pos++)='=';
  pos=int10_to_str(val, pos, -10);
  protocol->store(buf, pos-buf);
1788
}
1789
#endif // !MYSQL_CLIENT
1790

1791
/*****************************************************************************
unknown's avatar
unknown committed
1792

1793
  Intvar_log_event::Intvar_log_event()
1794

1795 1796 1797
 ****************************************************************************/
Intvar_log_event::Intvar_log_event(const char* buf, bool old_format)
  :Log_event(buf, old_format)
1798
{
1799 1800 1801
  buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
  type = buf[I_TYPE_OFFSET];
  val = uint8korr(buf+I_VAL_OFFSET);
1802 1803
}

1804
/*****************************************************************************
1805

1806 1807 1808 1809
  Intvar_log_event::get_var_type_name()

 ****************************************************************************/
const char* Intvar_log_event::get_var_type_name()
1810
{
1811 1812 1813 1814 1815
  switch(type) {
  case LAST_INSERT_ID_EVENT: return "LAST_INSERT_ID";
  case INSERT_ID_EVENT: return "INSERT_ID";
  default: /* impossible */ return "UNKNOWN";
  }
1816 1817
}

1818
/*****************************************************************************
unknown's avatar
unknown committed
1819

1820 1821 1822 1823
  Intvar_log_event::write_data()

 ****************************************************************************/
int Intvar_log_event::write_data(IO_CACHE* file)
1824
{
1825 1826 1827 1828
  char buf[9];
  buf[I_TYPE_OFFSET] = type;
  int8store(buf + I_VAL_OFFSET, val);
  return my_b_safe_write(file, (byte*) buf, sizeof(buf));
1829 1830
}

1831
/*****************************************************************************
1832

1833 1834 1835 1836 1837
  Intvar_log_event::print()

 ****************************************************************************/
#ifdef MYSQL_CLIENT
void Intvar_log_event::print(FILE* file, bool short_form, char* last_db)
1838
{
1839 1840 1841
  char llbuff[22];
  const char *msg;
  LINT_INIT(msg);
1842

1843 1844 1845 1846 1847
  if (!short_form)
  {
    print_header(file);
    fprintf(file, "\tIntvar\n");
  }
1848

1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859
  fprintf(file, "SET ");
  switch (type) {
  case LAST_INSERT_ID_EVENT:
    msg="LAST_INSERT_ID";
    break;
  case INSERT_ID_EVENT:
    msg="INSERT_ID";
    break;
  }
  fprintf(file, "%s=%s;\n", msg, llstr(val,llbuff));
  fflush(file);
1860
}
1861
#endif // MYSQL_CLIENT
1862

1863 1864 1865
/*****************************************************************************

  Intvar_log_event::exec_event()
1866

1867
 ****************************************************************************/
1868
#ifndef MYSQL_CLIENT
1869
int Intvar_log_event::exec_event(struct st_relay_log_info* rli)
1870
{
1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881
  switch (type) {
  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;
  }
  rli->inc_pending(get_event_len());
  return 0;
1882
}
1883
#endif // !MYSQL_CLIENT
1884

1885

1886 1887
/*****************************************************************************
 *****************************************************************************
unknown's avatar
unknown committed
1888

1889
                          Rand_log_event methods
1890

1891 1892
 *****************************************************************************
 ****************************************************************************/
unknown's avatar
unknown committed
1893

1894
/*****************************************************************************
1895

1896 1897 1898 1899
  Rand_log_event::pack_info()

 ****************************************************************************/
#ifndef MYSQL_CLIENT
1900
void Rand_log_event::pack_info(Protocol *protocol)
1901
{
unknown's avatar
unknown committed
1902 1903 1904 1905 1906
  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);
1907
  protocol->store(buf1, (uint) (pos-buf1));
1908
}
1909 1910 1911 1912 1913 1914 1915 1916 1917
#endif // !MYSQL_CLIENT

/*****************************************************************************

  Rand_log_event::Rand_log_event()

 ****************************************************************************/
Rand_log_event::Rand_log_event(const char* buf, bool old_format)
  :Log_event(buf, old_format)
1918
{
1919 1920 1921
  buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
  seed1 = uint8korr(buf+RAND_SEED1_OFFSET);
  seed2 = uint8korr(buf+RAND_SEED2_OFFSET);
1922 1923
}

1924 1925 1926 1927 1928 1929
/*****************************************************************************

  Rand_log_event::write_data()

 ****************************************************************************/
int Rand_log_event::write_data(IO_CACHE* file)
1930
{
1931 1932 1933 1934 1935
  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));
}
1936

1937
/*****************************************************************************
1938

1939 1940 1941 1942 1943 1944 1945 1946
  Rand_log_event::print()

 ****************************************************************************/
#ifdef MYSQL_CLIENT
void Rand_log_event::print(FILE* file, bool short_form, char* last_db)
{
  char llbuff[22];
  if (!short_form)
1947
  {
1948 1949
    print_header(file);
    fprintf(file, "\tRand\n");
1950
  }
unknown's avatar
unknown committed
1951 1952
  fprintf(file, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s;\n",
	  llstr(seed1, llbuff),llstr(seed2, llbuff));
1953
  fflush(file);
1954
}
1955
#endif // MYSQL_CLIENT
1956

1957
/*****************************************************************************
1958

1959 1960 1961 1962 1963
  Rand_log_event::exec_event()

 ****************************************************************************/
#ifndef MYSQL_CLIENT
int Rand_log_event::exec_event(struct st_relay_log_info* rli)
1964
{
unknown's avatar
unknown committed
1965 1966
  thd->rand.seed1= (ulong) seed1;
  thd->rand.seed2= (ulong) seed2;
1967 1968 1969 1970
  rli->inc_pending(get_event_len());
  return 0;
}
#endif // !MYSQL_CLIENT
1971

1972

1973 1974
/*****************************************************************************
 *****************************************************************************
1975

1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986
                          Slave_log_event methods

 *****************************************************************************
 ****************************************************************************/

/*****************************************************************************

  Slave_log_event::pack_info()

 ****************************************************************************/
#ifndef MYSQL_CLIENT
1987
void Slave_log_event::pack_info(Protocol *protocol)
1988
{
1989 1990 1991 1992 1993 1994 1995 1996 1997 1998
  char buf[256], *pos;
  pos= strmov(buf, "host=");
  pos= strnmov(pos, master_host, HOSTNAME_LENGTH);
  pos= strmov(pos, ",port=");
  pos= int10_to_str((long) master_port, pos, 10);
  pos= strmov(pos, ",log=");
  pos= strmov(pos, master_log);
  pos= strmov(pos, ",pos=");
  pos= int10_to_str(master_pos, pos, 10);
  protocol->store(buf, pos-buf);
1999 2000 2001 2002 2003 2004 2005 2006 2007 2008
}
#endif // !MYSQL_CLIENT

/*****************************************************************************

  Slave_log_event::Slave_log_event()

 ****************************************************************************/
#ifndef MYSQL_CLIENT
Slave_log_event::Slave_log_event(THD* thd_arg,
unknown's avatar
unknown committed
2009 2010
				 struct st_relay_log_info* rli)
  :Log_event(thd_arg, 0, 0), mem_pool(0), master_host(0)
2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024
{
  DBUG_ENTER("Slave_log_event");
  if (!rli->inited)				// QQ When can this happen ?
    DBUG_VOID_RETURN;
  
  MASTER_INFO* mi = rli->mi;
  // TODO: re-write this better without holding both locks at the same time
  pthread_mutex_lock(&mi->data_lock);
  pthread_mutex_lock(&rli->data_lock);
  master_host_len = strlen(mi->host);
  master_log_len = strlen(rli->master_log_name);
  // on OOM, just do not initialize the structure and print the error
  if ((mem_pool = (char*)my_malloc(get_data_size() + 1,
				   MYF(MY_WME))))
2025
  {
2026 2027 2028 2029 2030 2031 2032 2033
    master_host = mem_pool + SL_MASTER_HOST_OFFSET ;
    memcpy(master_host, mi->host, master_host_len + 1);
    master_log = master_host + master_host_len + 1;
    memcpy(master_log, rli->master_log_name, master_log_len + 1);
    master_port = mi->port;
    master_pos = rli->master_log_pos;
    DBUG_PRINT("info", ("master_log: %s  pos: %d", master_log,
			(ulong) master_pos));
2034
  }
2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108
  else
    sql_print_error("Out of memory while recording slave event");
  pthread_mutex_unlock(&rli->data_lock);
  pthread_mutex_unlock(&mi->data_lock);
  DBUG_VOID_RETURN;
}
#endif // !MYSQL_CLIENT

/*****************************************************************************

  Slave_log_event dtor

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

/*****************************************************************************

  Slave_log_event::print()

 ****************************************************************************/
#ifdef MYSQL_CLIENT
void Slave_log_event::print(FILE* file, bool short_form, char* last_db)
{
  char llbuff[22];
  if (short_form)
    return;
  print_header(file);
  fputc('\n', file);
  fprintf(file, "Slave: master_host: '%s'  master_port: %d  \
master_log: '%s'  master_pos: %s\n",
	  master_host, master_port, master_log, llstr(master_pos, llbuff));
}
#endif // MYSQL_CLIENT

/*****************************************************************************

  Slave_log_event::get_data_size()

 ****************************************************************************/
int Slave_log_event::get_data_size()
{
  return master_host_len + master_log_len + 1 + SL_MASTER_HOST_OFFSET;
}

/*****************************************************************************

  Slave_log_event::write_data()

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

/*****************************************************************************

  Slave_log_event::init_from_mem_pool()

 ****************************************************************************/
void Slave_log_event::init_from_mem_pool(int data_size)
{
  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;
  master_host_len = strlen(master_host);
  // safety
  master_log = master_host + master_host_len + 1;
  if (master_log > mem_pool + data_size)
2109
  {
2110 2111
    master_host = 0;
    return;
2112
  }
2113 2114
  master_log_len = strlen(master_log);
}
2115

2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131
/*****************************************************************************

  Slave_log_event::Slave_log_event()

 ****************************************************************************/
Slave_log_event::Slave_log_event(const char* buf, int event_len)
  :Log_event(buf,0),mem_pool(0),master_host(0)
{
  event_len -= LOG_EVENT_HEADER_LEN;
  if (event_len < 0)
    return;
  if (!(mem_pool = (char*) my_malloc(event_len + 1, MYF(MY_WME))))
    return;
  memcpy(mem_pool, buf + LOG_EVENT_HEADER_LEN, event_len);
  mem_pool[event_len] = 0;
  init_from_mem_pool(event_len);
2132 2133
}

2134
/*****************************************************************************
2135

2136
  Slave_log_event::exec_event()
2137

2138 2139 2140 2141 2142 2143 2144 2145 2146
 ****************************************************************************/
#ifndef MYSQL_CLIENT
int Slave_log_event::exec_event(struct st_relay_log_info* rli)
{
  if (mysql_bin_log.is_open())
    mysql_bin_log.write(this);
  return Log_event::exec_event(rli);
}
#endif // !MYSQL_CLIENT
2147 2148


2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170
/*****************************************************************************
 *****************************************************************************

                          Stop_log_event methods

 *****************************************************************************
 ****************************************************************************/

/*****************************************************************************

  Stop_log_event::print()

 ****************************************************************************/
#ifdef MYSQL_CLIENT
void Stop_log_event::print(FILE* file, bool short_form, char* last_db)
{
  if (short_form)
    return;

  print_header(file);
  fprintf(file, "\tStop\n");
  fflush(file);
2171
}
2172 2173 2174
#endif // MYSQL_CLIENT

/*****************************************************************************
2175

2176
  Stop_log_event::exec_event()
2177

2178 2179 2180 2181 2182 2183
  The master stopped. Clean up all temporary tables + locks that the
  master may have set.

  TODO
    - Remove all active user locks

2184 2185
 ****************************************************************************/
#ifndef MYSQL_CLIENT
2186
int Stop_log_event::exec_event(struct st_relay_log_info* rli)
2187
{
2188
  // do not clean up immediately after rotate event
2189
  if (rli->master_log_pos > BIN_LOG_HEADER_SIZE) 
2190 2191
  {
    close_temporary_tables(thd);
2192
    cleanup_load_tmpdir();
2193
  }
unknown's avatar
unknown committed
2194 2195
  /*
    We do not want to update master_log pos because we get a rotate event
2196 2197
    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
unknown's avatar
unknown committed
2198
    could give false triggers in MASTER_POS_WAIT() that we have reached
2199
    the target position when in fact we have not.
unknown's avatar
unknown committed
2200
  */
2201 2202
  rli->inc_pos(get_event_len(), 0);  
  flush_relay_log_info(rli);
2203 2204
  return 0;
}
2205
#endif // !MYSQL_CLIENT
2206

2207

2208 2209
/*****************************************************************************
 *****************************************************************************
2210

2211
                       Create_file_log_event methods
2212

2213 2214
 *****************************************************************************
 ****************************************************************************/
2215

2216
/*****************************************************************************
2217

2218 2219 2220 2221
  Create_file_log_event ctor

 ****************************************************************************/
#ifndef MYSQL_CLIENT
unknown's avatar
unknown committed
2222 2223 2224 2225 2226 2227 2228
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),
2229 2230
   fake_base(0),block(block_arg),block_len(block_len_arg),
   file_id(thd_arg->file_id = mysql_bin_log.next_file_id())
2231
{
2232 2233 2234
  sql_ex.force_new_format();
}
#endif // !MYSQL_CLIENT
2235

2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247
/*****************************************************************************

  Create_file_log_event::write_data_body()

 ****************************************************************************/
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;
  return (my_b_safe_write(file, (byte*) "", 1) ||
	  my_b_safe_write(file, (byte*) block, block_len));
2248 2249
}

2250 2251 2252
/*****************************************************************************

  Create_file_log_event::write_data_header()
unknown's avatar
unknown committed
2253

2254 2255
 ****************************************************************************/
int Create_file_log_event::write_data_header(IO_CACHE* file)
2256
{
2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306
  int res;
  if ((res = Load_log_event::write_data_header(file)) || fake_base)
    return res;
  byte buf[CREATE_FILE_HEADER_LEN];
  int4store(buf + CF_FILE_ID_OFFSET, file_id);
  return my_b_safe_write(file, buf, CREATE_FILE_HEADER_LEN);
}

/*****************************************************************************

  Create_file_log_event::write_base()

 ****************************************************************************/
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;
}

/*****************************************************************************

  Create_file_log_event ctor

 ****************************************************************************/
Create_file_log_event::Create_file_log_event(const char* buf, int len,
					     bool old_format)
  :Load_log_event(buf,0,old_format),fake_base(0),block(0),inited_from_old(0)
{
  int block_offset;
  if (copy_log_event(buf,len,old_format))
    return;
  if (!old_format)
  {
    file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN +
			+ LOAD_HEADER_LEN + CF_FILE_ID_OFFSET);
    // + 1 for \0 terminating fname  
    block_offset = (LOG_EVENT_HEADER_LEN + Load_log_event::get_data_size() +
		    CREATE_FILE_HEADER_LEN + 1);
    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;
2307 2308 2309
  }
}

2310 2311 2312 2313 2314 2315
/*****************************************************************************

  Create_file_log_event::print()

 ****************************************************************************/
#ifdef MYSQL_CLIENT
2316 2317
void Create_file_log_event::print(FILE* file, bool short_form, 
				  char* last_db, bool enable_local)
unknown's avatar
unknown committed
2318
{
2319
  if (short_form)
2320 2321 2322
  {
    if (enable_local && check_fname_outside_temp_buf())
      Load_log_event::print(file, 1, last_db);
2323
    return;
2324 2325 2326 2327 2328 2329 2330 2331 2332 2333
  }

  if (enable_local)
  {
    if (!check_fname_outside_temp_buf())
      fprintf(file, "#");
    Load_log_event::print(file, 1, last_db);
    fprintf(file, "#");
  }

2334
  fprintf(file, " file_id: %d  block_len: %d\n", file_id, block_len);
unknown's avatar
unknown committed
2335
}
2336 2337 2338 2339 2340 2341

void Create_file_log_event::print(FILE* file, bool short_form,
				  char* last_db)
{
  print(file,short_form,last_db,0);
}
2342
#endif // MYSQL_CLIENT
unknown's avatar
unknown committed
2343

2344 2345 2346 2347 2348 2349
/*****************************************************************************

  Create_file_log_event::pack_info()

 ****************************************************************************/
#ifndef MYSQL_CLIENT
2350
void Create_file_log_event::pack_info(Protocol *protocol)
2351
{
2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363
  char buf[NAME_LEN*2 + 30 + 21*2], *pos;
  pos= strmov(buf, "db=");
  memcpy(pos, db, db_len);
  pos+= db_len;
  pos= strmov(pos, ";table=");
  memcpy(pos, table_name, table_name_len);
  pos+= table_name_len;
  pos= strmov(pos, ";file_id=");
  pos= int10_to_str((long) file_id, pos, 10);
  pos= strmov(pos, ";block_len=");
  pos= int10_to_str((long) block_len, pos, 10);
  protocol->store(buf, pos-buf);
2364
}
2365 2366 2367 2368 2369
#endif // !MYSQL_CLIENT

/*****************************************************************************

  Create_file_log_event::exec_event()
2370

2371 2372
 ****************************************************************************/
#ifndef MYSQL_CLIENT
2373
int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
2374 2375
{
  char fname_buf[FN_REFLEN+10];
unknown's avatar
unknown committed
2376
  char *p;
2377 2378 2379
  int fd = -1;
  IO_CACHE file;
  int error = 1;
unknown's avatar
unknown committed
2380

2381
  bzero((char*)&file, sizeof(file));
unknown's avatar
unknown committed
2382 2383
  p = slave_load_file_stem(fname_buf, file_id, server_id);
  strmov(p, ".info");			// strmov takes less code than memcpy
2384 2385 2386 2387 2388
  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)))
  {
2389
    slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf);
2390 2391 2392 2393
    goto err;
  }
  
  // a trick to avoid allocating another buffer
unknown's avatar
unknown committed
2394
  strmov(p, ".data");
2395 2396 2397 2398
  fname = fname_buf;
  fname_len = (uint)(p-fname) + 5;
  if (write_base(&file))
  {
unknown's avatar
unknown committed
2399
    strmov(p, ".info"); // to have it right in the error message
2400
    slave_print_error(rli,my_errno, "Could not write to file '%s'", fname_buf);
2401 2402 2403 2404 2405 2406 2407 2408 2409
    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)
  {
2410
    slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf);
2411 2412
    goto err;
  }
unknown's avatar
unknown committed
2413
  if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
2414
  {
2415
    slave_print_error(rli,my_errno, "Write to '%s' failed", fname_buf);
2416 2417 2418 2419
    goto err;
  }
  if (mysql_bin_log.is_open())
    mysql_bin_log.write(this);
2420 2421
  error=0;					// Everything is ok

2422 2423 2424 2425 2426
err:
  if (error)
    end_io_cache(&file);
  if (fd >= 0)
    my_close(fd, MYF(0));
2427
  return error ? 1 : Log_event::exec_event(rli);
2428
}
2429
#endif // !MYSQL_CLIENT
2430

2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446

/*****************************************************************************
 *****************************************************************************

                       Append_block_log_event methods

 *****************************************************************************
 ****************************************************************************/

/*****************************************************************************

  Append_block_log_event ctor

 ****************************************************************************/
#ifndef MYSQL_CLIENT  
Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg,
unknown's avatar
unknown committed
2447 2448 2449 2450
					       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)
2451 2452
{
}
2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506
#endif // !MYSQL_CLIENT

/*****************************************************************************

  Append_block_log_event ctor

 ****************************************************************************/
Append_block_log_event::Append_block_log_event(const char* buf, int len)
  :Log_event(buf, 0),block(0)
{
  if ((uint)len < APPEND_BLOCK_EVENT_OVERHEAD)
    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;
}

/*****************************************************************************

  Append_block_log_event::write_data()

 ****************************************************************************/
int Append_block_log_event::write_data(IO_CACHE* file)
{
  byte buf[APPEND_BLOCK_HEADER_LEN];
  int4store(buf + AB_FILE_ID_OFFSET, file_id);
  return (my_b_safe_write(file, buf, APPEND_BLOCK_HEADER_LEN) ||
	  my_b_safe_write(file, (byte*) block, block_len));
}

/*****************************************************************************

  Append_block_log_event::print()

 ****************************************************************************/
#ifdef MYSQL_CLIENT  
void Append_block_log_event::print(FILE* file, bool short_form,
				   char* last_db)
{
  if (short_form)
    return;
  print_header(file);
  fputc('\n', file);
  fprintf(file, "#Append_block: file_id: %d  block_len: %d\n",
	  file_id, block_len);
}
#endif // MYSQL_CLIENT

/*****************************************************************************

  Append_block_log_event::pack_info()

 ****************************************************************************/
#ifndef MYSQL_CLIENT
2507
void Append_block_log_event::pack_info(Protocol *protocol)
2508 2509 2510 2511 2512 2513
{
  char buf[256];
  uint length;
  length= (uint) my_sprintf(buf,
			    (buf, ";file_id=%u;block_len=%u", file_id,
			     block_len));
2514
  protocol->store(buf, (int32) length);
2515 2516 2517 2518 2519 2520
}
#endif // !MYSQL_CLIENT

/*****************************************************************************

  Append_block_log_event::exec_event()
2521

2522 2523
 ****************************************************************************/
#ifndef MYSQL_CLIENT
2524
int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
2525 2526
{
  char fname[FN_REFLEN+10];
2527 2528
  char *p= slave_load_file_stem(fname, file_id, server_id);
  int fd;
2529
  int error = 1;
2530

2531 2532 2533
  memcpy(p, ".data", 6);
  if ((fd = my_open(fname, O_WRONLY|O_APPEND|O_BINARY, MYF(MY_WME))) < 0)
  {
2534
    slave_print_error(rli,my_errno, "Could not open file '%s'", fname);
2535 2536
    goto err;
  }
unknown's avatar
unknown committed
2537
  if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
2538
  {
2539
    slave_print_error(rli,my_errno, "Write to '%s' failed", fname);
2540 2541 2542 2543 2544
    goto err;
  }
  if (mysql_bin_log.is_open())
    mysql_bin_log.write(this);
  error=0;
2545

2546 2547 2548
err:
  if (fd >= 0)
    my_close(fd, MYF(0));
2549
  return error ? error : Log_event::exec_event(rli);
2550
}
2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567
#endif // !MYSQL_CLIENT


/*****************************************************************************
 *****************************************************************************

                       Delete_file_log_event methods

 *****************************************************************************
 ****************************************************************************/

/*****************************************************************************

  Delete_file_log_event ctor

 ****************************************************************************/
#ifndef MYSQL_CLIENT
unknown's avatar
unknown committed
2568 2569
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)
2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621
{
}
#endif // !MYSQL_CLIENT

/*****************************************************************************

  Delete_file_log_event ctor

 ****************************************************************************/
Delete_file_log_event::Delete_file_log_event(const char* buf, int len)
  :Log_event(buf, 0),file_id(0)
{
  if ((uint)len < DELETE_FILE_EVENT_OVERHEAD)
    return;
  file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET);
}

/*****************************************************************************

  Delete_file_log_event::write_data()

 ****************************************************************************/
int Delete_file_log_event::write_data(IO_CACHE* file)
{
 byte buf[DELETE_FILE_HEADER_LEN];
 int4store(buf + DF_FILE_ID_OFFSET, file_id);
 return my_b_safe_write(file, buf, DELETE_FILE_HEADER_LEN);
}

/*****************************************************************************

  Delete_file_log_event::print()

 ****************************************************************************/
#ifdef MYSQL_CLIENT  
void Delete_file_log_event::print(FILE* file, bool short_form,
				  char* last_db)
{
  if (short_form)
    return;
  print_header(file);
  fputc('\n', file);
  fprintf(file, "#Delete_file: file_id=%u\n", file_id);
}
#endif // MYSQL_CLIENT

/*****************************************************************************

  Delete_file_log_event::pack_info()

 ****************************************************************************/
#ifndef MYSQL_CLIENT
2622
void Delete_file_log_event::pack_info(Protocol *protocol)
2623 2624 2625 2626
{
  char buf[64];
  uint length;
  length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id));
2627
  protocol->store(buf, (int32) length);
2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665
}
#endif // !MYSQL_CLIENT

/*****************************************************************************

  Delete_file_log_event::exec_event()

 ****************************************************************************/
#ifndef MYSQL_CLIENT
int Delete_file_log_event::exec_event(struct st_relay_log_info* rli)
{
  char fname[FN_REFLEN+10];
  char *p= slave_load_file_stem(fname, file_id, server_id);
  memcpy(p, ".data", 6);
  (void) my_delete(fname, MYF(MY_WME));
  memcpy(p, ".info", 6);
  (void) my_delete(fname, MYF(MY_WME));
  if (mysql_bin_log.is_open())
    mysql_bin_log.write(this);
  return Log_event::exec_event(rli);
}
#endif // !MYSQL_CLIENT


/*****************************************************************************
 *****************************************************************************

                         Execute_load_log_event methods

 *****************************************************************************
 ****************************************************************************/

/*****************************************************************************

  Execute_load_log_event ctor

 ****************************************************************************/
#ifndef MYSQL_CLIENT  
unknown's avatar
unknown committed
2666 2667
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)
2668 2669 2670 2671 2672 2673 2674 2675 2676
{
}
#endif // !MYSQL_CLIENT
  
/*****************************************************************************

  Execute_load_log_event ctor

 ****************************************************************************/
unknown's avatar
unknown committed
2677 2678
Execute_load_log_event::Execute_load_log_event(const char* buf, int len)
  :Log_event(buf, 0), file_id(0)
2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720
{
  if ((uint)len < EXEC_LOAD_EVENT_OVERHEAD)
    return;
  file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + EL_FILE_ID_OFFSET);
}

/*****************************************************************************

  Execute_load_log_event::write_data()

 ****************************************************************************/
int Execute_load_log_event::write_data(IO_CACHE* file)
{
  byte buf[EXEC_LOAD_HEADER_LEN];
  int4store(buf + EL_FILE_ID_OFFSET, file_id);
  return my_b_safe_write(file, buf, EXEC_LOAD_HEADER_LEN);
}

/*****************************************************************************

  Execute_load_log_event::print()

 ****************************************************************************/
#ifdef MYSQL_CLIENT  
void Execute_load_log_event::print(FILE* file, bool short_form,
				   char* last_db)
{
  if (short_form)
    return;
  print_header(file);
  fputc('\n', file);
  fprintf(file, "#Exec_load: file_id=%d\n",
	  file_id);
}
#endif // MYSQL_CLIENT

/*****************************************************************************

  Execute_load_log_event::pack_info()

 ****************************************************************************/
#ifndef MYSQL_CLIENT
2721
void Execute_load_log_event::pack_info(Protocol *protocol)
2722 2723 2724 2725
{
  char buf[64];
  uint length;
  length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id));
2726
  protocol->store(buf, (int32) length);
2727 2728 2729 2730 2731 2732
}
#endif // !MYSQL_CLIENT

/*****************************************************************************

  Execute_load_log_event::exec_event()
2733

2734 2735
 ****************************************************************************/
#ifndef MYSQL_CLIENT
2736
int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
2737 2738
{
  char fname[FN_REFLEN+10];
2739 2740
  char *p= slave_load_file_stem(fname, file_id, server_id);
  int fd;
2741
  int error = 1;
unknown's avatar
unknown committed
2742
  ulong save_options;
2743 2744
  IO_CACHE file;
  Load_log_event* lev = 0;
2745

2746 2747 2748 2749 2750
  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)))
  {
2751
    slave_print_error(rli,my_errno, "Could not open file '%s'", fname);
2752 2753
    goto err;
  }
2754 2755
  if (!(lev = (Load_log_event*)Log_event::read_log_event(&file,
							 (pthread_mutex_t*)0,
2756 2757
							 (bool)0)) ||
      lev->get_type_code() != NEW_LOAD_EVENT)
2758
  {
2759
    slave_print_error(rli,0, "File '%s' appears corrupted", fname);
2760 2761
    goto err;
  }
unknown's avatar
unknown committed
2762 2763 2764 2765 2766 2767
  /*
    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 .
  */
2768
  save_options = thd->options;
unknown's avatar
unknown committed
2769
  thd->options &= ~ (ulong) (OPTION_BIN_LOG);
2770
  lev->thd = thd;
2771 2772 2773 2774 2775
  /*
    lev->exec_event should use rli only for errors
    i.e. should not advance rli's position
  */
  if (lev->exec_event(0,rli,1)) 
2776
  {
2777
    slave_print_error(rli,my_errno, "Failed executing load from '%s'", fname);
2778 2779 2780 2781
    thd->options = save_options;
    goto err;
  }
  thd->options = save_options;
2782
  (void) my_delete(fname, MYF(MY_WME));
2783
  memcpy(p, ".data", 6);
2784
  (void) my_delete(fname, MYF(MY_WME));
2785 2786 2787
  if (mysql_bin_log.is_open())
    mysql_bin_log.write(this);
  error = 0;
2788

2789 2790 2791
err:
  delete lev;
  if (fd >= 0)
2792
  {
2793
    my_close(fd, MYF(0));
2794 2795
    end_io_cache(&file);
  }
2796
  return error ? error : Log_event::exec_event(rli);
2797
}
2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893
#endif // !MYSQL_CLIENT


/*****************************************************************************
 *****************************************************************************

                           sql_ex_info methods

 *****************************************************************************
 ****************************************************************************/

/*****************************************************************************

  sql_ex_info::write_data()

 ****************************************************************************/
int sql_ex_info::write_data(IO_CACHE* file)
{
  if (new_format())
  {
    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) ||
	    my_b_safe_write(file,(byte*) &opt_flags,1));
  }
  else
  {
    old_sql_ex old_ex;
    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;
    return my_b_safe_write(file, (byte*) &old_ex, sizeof(old_ex));
  }
}

/*****************************************************************************

  sql_ex_info::init()

 ****************************************************************************/
char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format)
{
  cached_new_format = use_new_format;
  if (use_new_format)
  {
    empty_flags=0;
    /*
      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.
    */
    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;
    opt_flags = *buf++;
  }
  else
  {
    field_term_len= enclosed_len= line_term_len= line_start_len= escaped_len=1;
    field_term = buf++;			// Use first byte in string
    enclosed=	 buf++;
    line_term=   buf++;
    line_start=  buf++;
    escaped=     buf++;
    opt_flags =  *buf++;
    empty_flags= *buf++;
    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;
  }
  return buf;
}






2894