log_event.cc 17.8 KB
Newer Older
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/* 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"
#endif /* MYSQL_CLIENT */


static void pretty_print_char(FILE* file, int c)
{
  fputc('\'', file);
29 30 31 32 33 34 35 36 37 38 39 40
  switch(c) {
  case '\n': fprintf(file, "\\n"); break;
  case '\r': fprintf(file, "\\r"); break;
  case '\\': fprintf(file, "\\\\"); break;
  case '\b': fprintf(file, "\\b"); break;
  case '\'': fprintf(file, "\\'"); break;
  case 0   : fprintf(file, "\\0"); break;
  default:
    fputc(c, file);
    break;
  }
  fputc('\'', file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
41 42
}

43
int Query_log_event::write(IO_CACHE* file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
44 45 46 47
{
  return query ? Log_event::write(file) : -1; 
}

48
int Log_event::write(IO_CACHE* file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
49
{
50
  return (write_header(file) || write_data(file)) ? -1 : 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
51 52
}

53
int Log_event::write_header(IO_CACHE* file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
54 55
{
  // make sure to change this when the header gets bigger
56
  char buf[LOG_EVENT_HEADER_LEN];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
57
  char* pos = buf;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
58
  int4store(pos, (ulong) when); // timestamp
bk@work.mysql.com's avatar
bk@work.mysql.com committed
59 60
  pos += 4;
  *pos++ = get_type_code(); // event type code
61 62
  int4store(pos, server_id);
  pos += 4;
63 64
  long tmp=get_data_size() + LOG_EVENT_HEADER_LEN;
  int4store(pos, tmp);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
65
  pos += 4;
66
  return (my_b_write(file, (byte*) buf, (uint) (pos - buf)));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
67 68 69 70
}

#ifndef MYSQL_CLIENT

71
int Log_event::read_log_event(IO_CACHE* file, String* packet,
72
			      pthread_mutex_t* log_lock)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
73 74 75
{
  ulong data_len;
  char buf[LOG_EVENT_HEADER_LEN];
76
  if (log_lock)
77
    pthread_mutex_lock(log_lock);
78 79 80
  if (my_b_read(file, (byte*) buf, sizeof(buf)))
  {
    if (log_lock) pthread_mutex_unlock(log_lock);
81 82 83
    // 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
84 85
    if(!file->error) return LOG_READ_EOF;
    return file->error > 0 ? LOG_READ_TRUNC: LOG_READ_IO;
86
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
87
  data_len = uint4korr(buf + EVENT_LEN_OFFSET);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
88
  if (data_len < LOG_EVENT_HEADER_LEN || data_len > max_allowed_packet)
89 90
  {
    if (log_lock) pthread_mutex_unlock(log_lock);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
91 92
    return (data_len < LOG_EVENT_HEADER_LEN) ? LOG_READ_BOGUS :
      LOG_READ_TOO_LARGE;
93
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
94 95
  packet->append(buf, sizeof(buf));
  data_len -= LOG_EVENT_HEADER_LEN;
96 97 98
  if (data_len)
  {
    if (packet->append(file, data_len))
99 100 101
    {
      if(log_lock)
	pthread_mutex_unlock(log_lock);
102 103 104
      // here we should never hit eof in a non-error condtion
      // eof means we are reading the event partially, which should
      // never happen
105
      return file->error >= 0 ? LOG_READ_TRUNC: LOG_READ_IO;
106
    }
107 108
  }
  if (log_lock) pthread_mutex_unlock(log_lock);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
109 110 111 112 113
  return 0;
}

#endif // MYSQL_CLIENT

114 115 116 117 118
#ifndef MYSQL_CLIENT
#define UNLOCK_MUTEX if(log_lock) pthread_mutex_unlock(log_lock);
#else
#define UNLOCK_MUTEX
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
119

120 121
// allocates memory - the caller is responsible for clean-up
#ifndef MYSQL_CLIENT
122
Log_event* Log_event::read_log_event(IO_CACHE* file, pthread_mutex_t* log_lock)
123 124 125
#else
Log_event* Log_event::read_log_event(IO_CACHE* file)
#endif  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
126 127
{
  time_t timestamp;
128 129 130
  uint32 server_id;
  
  char buf[LOG_EVENT_HEADER_LEN-4];
131
#ifndef MYSQL_CLIENT  
132
  if(log_lock) pthread_mutex_lock(log_lock);
133
#endif  
134 135
  if (my_b_read(file, (byte *) buf, sizeof(buf)))
  {
136
    UNLOCK_MUTEX
137 138
    return NULL;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
139
  timestamp = uint4korr(buf);
140 141
  server_id = uint4korr(buf + 5);
  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
142 143 144 145
  switch(buf[EVENT_TYPE_OFFSET])
  {
  case QUERY_EVENT:
  {
146
    Query_log_event* q = new Query_log_event(file, timestamp, server_id);
147
    UNLOCK_MUTEX
bk@work.mysql.com's avatar
bk@work.mysql.com committed
148 149 150
    if (!q->query)
    {
      delete q;
151
      q=NULL;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
152 153 154 155 156 157
    }
    return q;
  }
  
  case LOAD_EVENT:
  {
158
    Load_log_event* l = new Load_log_event(file, timestamp, server_id);
159
    UNLOCK_MUTEX
bk@work.mysql.com's avatar
bk@work.mysql.com committed
160 161 162
    if (!l->table_name)
    {
      delete l;
163
      l=NULL;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
164 165 166 167 168 169 170
    }
    return l;
  }


  case ROTATE_EVENT:
  {
171
    Rotate_log_event* r = new Rotate_log_event(file, timestamp, server_id);
172
    UNLOCK_MUTEX
bk@work.mysql.com's avatar
bk@work.mysql.com committed
173 174 175
    if (!r->new_log_ident)
    {
      delete r;
176
      r=NULL;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
177 178 179 180 181 182
    }
    return r;
  }

  case INTVAR_EVENT:
  {
183
    Intvar_log_event* e = new Intvar_log_event(file, timestamp, server_id);
184
    UNLOCK_MUTEX
bk@work.mysql.com's avatar
bk@work.mysql.com committed
185 186 187
    if (e->type == INVALID_INT_EVENT)
    {
      delete e;
188
      e=NULL;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
189 190 191 192
    }
    return e;
  }
  
193 194 195
  case START_EVENT:
    {
      Start_log_event* e = new Start_log_event(file, timestamp, server_id);
196
      UNLOCK_MUTEX
197 198 199 200 201
      return e;
    }	  
  case STOP_EVENT:
    {
      Stop_log_event* e = new Stop_log_event(file, timestamp, server_id);
202
      UNLOCK_MUTEX
203 204 205
      return e;
    }
  default:
206
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
207 208
  }

209
  // default
210
  UNLOCK_MUTEX
bk@work.mysql.com's avatar
bk@work.mysql.com committed
211 212 213
  return NULL;
}

214
Log_event* Log_event::read_log_event(const char* buf, int event_len)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
215
{
216 217 218 219
  if(event_len < EVENT_LEN_OFFSET ||
     (uint)event_len != uint4korr(buf+EVENT_LEN_OFFSET))
    return NULL; // general sanity check - will fail on a partial read
  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
220 221 222 223
  switch(buf[EVENT_TYPE_OFFSET])
  {
  case QUERY_EVENT:
  {
224
    Query_log_event* q = new Query_log_event(buf, event_len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
225 226 227 228 229 230 231 232 233 234 235
    if (!q->query)
    {
      delete q;
      return NULL;
    }

    return q;
  }

  case LOAD_EVENT:
  {
236
    Load_log_event* l = new Load_log_event(buf, event_len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
237 238 239 240 241 242 243 244 245 246 247
    if (!l->table_name)
    {
      delete l;
      return NULL;
    }

    return l;
  }

  case ROTATE_EVENT:
  {
248
    Rotate_log_event* r = new Rotate_log_event(buf, event_len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
249 250 251 252 253 254 255 256
    if (!r->new_log_ident)
    {
      delete r;
      return NULL;
    }

    return r;
  }
257 258 259
  case START_EVENT:  return  new Start_log_event(buf);
  case STOP_EVENT:  return  new Stop_log_event(buf);
  case INTVAR_EVENT:  return  new Intvar_log_event(buf);
260 261
  default:
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
262
  }
263
  return NULL;  // default value
bk@work.mysql.com's avatar
bk@work.mysql.com committed
264 265
}

266 267 268 269
void Log_event::print_header(FILE* file)
{
  fputc('#', file);
  print_timestamp(file);
270
  fprintf(file, " server id  %d ", server_id); 
271 272
}

273
void Log_event::print_timestamp(FILE* file, time_t* ts)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
274
{
275 276 277 278 279 280 281 282 283 284 285 286 287 288
  struct tm tm_tmp;
  if (!ts)
  {
    ts = &when;
  }
  localtime_r(ts,&tm_tmp);

  fprintf(file,"%02d%02d%02d %2d:%02d:%02d",
	  tm_tmp.tm_year % 100,
	  tm_tmp.tm_mon+1,
	  tm_tmp.tm_mday,
	  tm_tmp.tm_hour,
	  tm_tmp.tm_min,
	  tm_tmp.tm_sec);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
289 290 291
}


292
void Start_log_event::print(FILE* file, bool short_form, char* last_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
293 294 295 296
{
  if (short_form)
    return;

297 298 299 300 301
  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);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
302 303 304
  fflush(file);
}

305
void Stop_log_event::print(FILE* file, bool short_form, char* last_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
306 307 308 309
{
  if (short_form)
    return;

310
  print_header(file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
311 312 313 314
  fprintf(file, "\tStop\n");
  fflush(file);
}

315
void Rotate_log_event::print(FILE* file, bool short_form, char* last_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
316 317 318 319
{
  if (short_form)
    return;

320
  print_header(file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
321 322 323 324 325 326 327 328
  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, "\n");
  fflush(file);
}

329
Rotate_log_event::Rotate_log_event(IO_CACHE* file, time_t when_arg,
330 331
				   uint32 server_id):
  Log_event(when_arg, 0, 0, server_id),new_log_ident(NULL),alloced(0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
332 333 334 335
{
  char *tmp_ident;
  char buf[4];

336
  if (my_b_read(file, (byte*) buf, sizeof(buf)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
337 338 339
    return;
  ulong event_len;
  event_len = uint4korr(buf);
340
  if (event_len < ROTATE_EVENT_OVERHEAD)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
341 342 343 344 345
    return;

  ident_len = (uchar)(event_len - ROTATE_EVENT_OVERHEAD);
  if (!(tmp_ident = (char*) my_malloc((uint)ident_len, MYF(MY_WME))))
    return;
346
  if (my_b_read( file, (byte*) tmp_ident, (uint) ident_len))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
347 348 349 350 351 352 353 354 355
  {
    my_free((gptr) tmp_ident, MYF(0));
    return;
  }

  new_log_ident = tmp_ident;
  alloced = 1;
}

356 357 358 359 360 361 362 363
Start_log_event::Start_log_event(const char* buf) :Log_event(buf)
{
  buf += EVENT_LEN_OFFSET + 4; // skip even length
  binlog_version = uint2korr(buf);
  memcpy(server_version, buf + 2, sizeof(server_version));
  created = uint4korr(buf + 2 + sizeof(server_version));
}

364 365 366 367 368 369 370 371 372
int Start_log_event::write_data(IO_CACHE* file)
{
  char buff[sizeof(server_version)+2+4];
  int2store(buff,binlog_version);
  memcpy(buff+2,server_version,sizeof(server_version));
  int4store(buff+2+sizeof(server_version),created);
  return (my_b_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0);
}

373
Rotate_log_event::Rotate_log_event(const char* buf, int event_len):
bk@work.mysql.com's avatar
bk@work.mysql.com committed
374 375
  Log_event(buf),new_log_ident(NULL),alloced(0)
{
376 377 378
  // the caller will ensure that event_len is what we have at
  // EVENT_LEN_OFFSET
  if(event_len < ROTATE_EVENT_OVERHEAD)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
379 380 381 382 383 384 385 386 387 388
    return;

  ident_len = (uchar)(event_len - ROTATE_EVENT_OVERHEAD);
  if (!(new_log_ident = (char*) my_memdup((byte*) buf + LOG_EVENT_HEADER_LEN,
					  (uint) ident_len, MYF(MY_WME))))
    return;

  alloced = 1;
}

389
int Rotate_log_event::write_data(IO_CACHE* file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
390
{
391
  return my_b_write(file, (byte*) new_log_ident, (uint) ident_len) ? -1 :0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
392 393
}

394
Query_log_event::Query_log_event(IO_CACHE* file, time_t when_arg,
395 396
				 uint32 server_id):
  Log_event(when_arg,0,0,server_id),data_buf(0),query(NULL),db(NULL)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
397 398 399
{
  char buf[QUERY_HEADER_LEN + 4];
  ulong data_len;
400
  if (my_b_read(file, (byte*) buf, sizeof(buf)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
401 402 403 404 405 406 407 408 409
    return;				// query == NULL will tell the
					// caller there was a problem
  data_len = uint4korr(buf);
  if (data_len < QUERY_EVENT_OVERHEAD)
    return;				// tear-drop attack protection :)

  data_len -= QUERY_EVENT_OVERHEAD;
  exec_time = uint4korr(buf + 8);
  db_len = (uint)buf[12];
410
  error_code = uint2korr(buf + 13);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
411
  
412
  /* Allocate one byte extra for end \0 */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
413 414
  if (!(data_buf = (char*) my_malloc(data_len+1, MYF(MY_WME))))
    return;
415
  if (my_b_read( file, (byte*) data_buf, data_len))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
416 417 418 419 420 421 422 423 424 425
  {
    my_free((gptr) data_buf, MYF(0));
    data_buf = 0;
    return;
  }

  thread_id = uint4korr(buf + 4);
  db = data_buf;
  query=data_buf + db_len + 1;
  q_len = data_len - 1 - db_len;
426
  *((char*) query + q_len) = 0;			// Safety
bk@work.mysql.com's avatar
bk@work.mysql.com committed
427 428
}

429
Query_log_event::Query_log_event(const char* buf, int event_len):
bk@work.mysql.com's avatar
bk@work.mysql.com committed
430 431
  Log_event(buf),data_buf(0), query(NULL), db(NULL)
{
432
  if ((uint)event_len < QUERY_EVENT_OVERHEAD)
433
    return;				
bk@work.mysql.com's avatar
bk@work.mysql.com committed
434 435
  ulong data_len;
  buf += EVENT_LEN_OFFSET;
436
  data_len = event_len - QUERY_EVENT_OVERHEAD;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
437 438

  exec_time = uint4korr(buf + 8);
439
  error_code = uint2korr(buf + 13);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
440

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

444
  memcpy(data_buf, buf + QUERY_HEADER_LEN + 4, data_len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
445 446 447 448 449 450 451 452
  thread_id = uint4korr(buf + 4);
  db = data_buf;
  db_len = (uint)buf[12];
  query=data_buf + db_len + 1;
  q_len = data_len - 1 - db_len;
  *((char*)query+q_len) = 0;
}

453
void Query_log_event::print(FILE* file, bool short_form, char* last_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
454
{
455
  char buff[40],*end;				// Enough for SET TIMESTAMP
bk@work.mysql.com's avatar
bk@work.mysql.com committed
456 457
  if (!short_form)
  {
458
    print_header(file);
459 460
    fprintf(file, "\tQuery\tthread_id=%lu\texec_time=%lu\terror_code=%d\n",
	    (ulong) thread_id, (ulong) exec_time, error_code);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
461 462
  }

463 464 465 466
  bool same_db = 0;

  if(db && last_db)
    {
467
      if(!(same_db = !memcmp(last_db, db, db_len + 1)))
468 469 470 471
        memcpy(last_db, db, db_len + 1);
    }
  
  if (db && db[0] && !same_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
472
    fprintf(file, "use %s;\n", db);
473 474 475 476
  end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10);
  *end++=';';
  *end++='\n';
  my_fwrite(file, (byte*) buff, (uint) (end-buff),MYF(MY_NABP | MY_WME));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
477 478 479 480
  my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
  fprintf(file, ";\n");
}

481
int Query_log_event::write_data(IO_CACHE* file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
482
{
483
  if (!query) return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
484 485 486 487 488 489 490 491
  
  char buf[QUERY_HEADER_LEN]; 
  char* pos = buf;
  int4store(pos, thread_id);
  pos += 4;
  int4store(pos, exec_time);
  pos += 4;
  *pos++ = (char)db_len;
492 493
  int2store(pos, error_code);
  pos += 2;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
494

495 496 497
  return (my_b_write(file, (byte*) buf, (uint)(pos - buf)) ||
	  my_b_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) ||
	  my_b_write(file, (byte*) query, q_len)) ? -1 : 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
498 499
}

500
Intvar_log_event:: Intvar_log_event(IO_CACHE* file, time_t when_arg,
501 502
				    uint32 server_id)
  :Log_event(when_arg,0,0,server_id), type(INVALID_INT_EVENT)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
503
{
504 505 506 507 508 509
  char buf[9+4];
  if (!my_b_read(file, (byte*) buf, sizeof(buf)))
  {
    type = buf[4];
    val = uint8korr(buf+1+4);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
510 511 512 513 514 515 516 517 518
}

Intvar_log_event::Intvar_log_event(const char* buf):Log_event(buf)
{
  buf += LOG_EVENT_HEADER_LEN;
  type = buf[0];
  val = uint8korr(buf+1);
}

519
int Intvar_log_event::write_data(IO_CACHE* file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
520 521 522 523
{
  char buf[9];
  buf[0] = type;
  int8store(buf + 1, val);
524
  return my_b_write(file, (byte*) buf, sizeof(buf));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
525 526
}

527
void Intvar_log_event::print(FILE* file, bool short_form, char* last_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
528 529 530 531
{
  char llbuff[22];
  if(!short_form)
  {
532
    print_header(file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
    fprintf(file, "\tIntvar\n");
  }

  fprintf(file, "SET ");
  switch(type)
  {
  case LAST_INSERT_ID_EVENT:
    fprintf(file, "LAST_INSERT_ID = ");
    break;
  case INSERT_ID_EVENT:
    fprintf(file, "INSERT_ID = ");
    break;
  }
  fprintf(file, "%s;\n", llstr(val,llbuff));
  fflush(file);
  
}

551
int Load_log_event::write_data(IO_CACHE* file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
552 553 554 555 556 557 558 559 560
{
  char buf[LOAD_HEADER_LEN];
  int4store(buf, thread_id);
  int4store(buf + 4, exec_time);
  int4store(buf + 8, skip_lines);
  buf[12] = (char)table_name_len;
  buf[13] = (char)db_len;
  int4store(buf + 14, num_fields);
  
561 562
  if(my_b_write(file, (byte*)buf, sizeof(buf)) ||
     my_b_write(file, (byte*)&sql_ex, sizeof(sql_ex)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
563 564
    return 1;

565 566 567 568 569 570 571 572 573
  if (num_fields && fields && field_lens)
  {
    if(my_b_write(file, (byte*)field_lens, num_fields) ||
       my_b_write(file, (byte*)fields, field_block_len))
      return 1;
  }
  if(my_b_write(file, (byte*)table_name, table_name_len + 1) ||
     my_b_write(file, (byte*)db, db_len + 1) ||
     my_b_write(file, (byte*)fname, fname_len))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
574 575 576 577
    return 1;
  return 0;
}

578
Load_log_event::Load_log_event(IO_CACHE* file, time_t when, uint32 server_id):
579 580
  Log_event(when,0,0,server_id),data_buf(0),num_fields(0),
  fields(0),field_lens(0),field_block_len(0),
bk@work.mysql.com's avatar
bk@work.mysql.com committed
581 582 583 584
  table_name(0),db(0),fname(0)
{
  char buf[LOAD_HEADER_LEN + 4];
  ulong data_len;
585 586
  if (my_b_read(file, (byte*)buf, sizeof(buf)) ||
      my_b_read(file, (byte*)&sql_ex, sizeof(sql_ex)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
587 588
    return;

589 590
  data_len = uint4korr(buf) - LOAD_EVENT_OVERHEAD;
  if (!(data_buf = (char*)my_malloc(data_len + 1, MYF(MY_WME))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
591
    return;
592
  if (my_b_read(file, (byte*)data_buf, data_len))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
593
    return;
594
  copy_log_event(buf,data_len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
595 596
}

597
Load_log_event::Load_log_event(const char* buf, int event_len):
598
  Log_event(buf),data_buf(0),num_fields(0),fields(0),
599
  field_lens(0),field_block_len(0),
bk@work.mysql.com's avatar
bk@work.mysql.com committed
600 601 602 603
  table_name(0),db(0),fname(0)
{
  ulong data_len;

604
  if((uint)event_len < (LOAD_EVENT_OVERHEAD + LOG_EVENT_HEADER_LEN))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
605 606
    return;
  buf += EVENT_LEN_OFFSET;
607
  memcpy(&sql_ex, buf + LOAD_HEADER_LEN + 4, sizeof(sql_ex));
608
  data_len = event_len;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
609
  
610 611 612 613 614 615 616 617
  if(!(data_buf = (char*)my_malloc(data_len + 1, MYF(MY_WME))))
    return;
  memcpy(data_buf, buf + 22 + sizeof(sql_ex), data_len);
  copy_log_event(buf, data_len);
}

void Load_log_event::copy_log_event(const char *buf, ulong data_len)
{
bk@work.mysql.com's avatar
bk@work.mysql.com committed
618 619 620 621 622 623 624
  thread_id = uint4korr(buf+4);
  exec_time = uint4korr(buf+8);
  skip_lines = uint4korr(buf + 12);
  table_name_len = (uint)buf[16];
  db_len = (uint)buf[17];
  num_fields = uint4korr(buf + 18);
	  
625
  if (num_fields > data_len) // simple sanity check against corruption
bk@work.mysql.com's avatar
bk@work.mysql.com committed
626 627
    return;

628
  field_lens = (uchar*) data_buf;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
629
  uint i;
630 631 632 633
  for (i = 0; i < num_fields; i++)
  {
    field_block_len += (uint)field_lens[i] + 1;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
634 635 636 637 638 639
  fields = (char*)field_lens + num_fields;
  
  *((char*)data_buf+data_len) = 0;
  table_name  = fields + field_block_len;
  db = table_name + table_name_len + 1;
  fname = db + db_len + 1;
640 641
  fname_len = data_len - 2 - db_len - table_name_len - num_fields -
    field_block_len;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
642 643 644
}


645
void Load_log_event::print(FILE* file, bool short_form, char* last_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
646 647 648
{
  if (!short_form)
  {
649
    print_header(file);
650
    fprintf(file, "\tQuery\tthread_id=%ld\texec_time=%ld\n",
bk@work.mysql.com's avatar
bk@work.mysql.com committed
651 652 653
	    thread_id, exec_time);
  }

654 655 656 657
  bool same_db = 0;

  if(db && last_db)
    {
658
      if(!(same_db = !memcmp(last_db, db, db_len + 1)))
659 660 661 662
        memcpy(last_db, db, db_len + 1);
    }
  
  if(db && db[0] && !same_db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
    fprintf(file, "use %s;\n", db);

  fprintf(file, "LOAD DATA INFILE '%s' ", fname);

  if(sql_ex.opt_flags && REPLACE_FLAG )
    fprintf(file," REPLACE ");
  else if(sql_ex.opt_flags && IGNORE_FLAG )
    fprintf(file," IGNORE ");
  
  fprintf(file, "INTO TABLE %s ", table_name);
  if(!(sql_ex.empty_flags & FIELD_TERM_EMPTY))
  {
    fprintf(file, " FIELDS TERMINATED BY ");
    pretty_print_char(file, sql_ex.field_term);
  }

  if(!(sql_ex.empty_flags & ENCLOSED_EMPTY))
  {
    if(sql_ex.opt_flags && OPT_ENCLOSED_FLAG )
      fprintf(file," OPTIONALLY ");
    fprintf(file, " ENCLOSED BY ");
    pretty_print_char(file, sql_ex.enclosed);
  }
     
  if(!(sql_ex.empty_flags & ESCAPED_EMPTY))
  {
    fprintf(file, " ESCAPED BY ");
    pretty_print_char(file, sql_ex.escaped);
  }
     
  if(!(sql_ex.empty_flags & LINE_TERM_EMPTY))
  {
    fprintf(file," LINES TERMINATED BY ");
    pretty_print_char(file, sql_ex.line_term);
  }

  if(!(sql_ex.empty_flags & LINE_START_EMPTY))
  {
    fprintf(file," LINES STARTING BY ");
    pretty_print_char(file, sql_ex.line_start);
  }
     
  if((int)skip_lines > 0)
monty@donna.mysql.fi's avatar
monty@donna.mysql.fi committed
706
    fprintf(file, " IGNORE %ld LINES ", (long) skip_lines);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
707

708 709 710 711 712 713
  if (num_fields)
  {
    uint i;
    const char* field = fields;
    fprintf( file, " (");
    for(i = 0; i < num_fields; i++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
714
    {
715 716 717
      if(i)
	fputc(',', file);
      fprintf(file, field);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
718
	  
719
      field += field_lens[i]  + 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
720
    }
721 722
    fputc(')', file);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741

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

#ifndef MYSQL_CLIENT

void Load_log_event::set_fields(List<Item> &fields)
{
  uint i;
  const char* field = this->fields;
  for(i = 0; i < num_fields; i++)
    {
      fields.push_back(new Item_field(db, table_name, field));	  
      field += field_lens[i]  + 1;
    }
  
}

#endif