~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2001-2004 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
/* 
17
18
   TODO: print the catalog (some USE catalog.db ????).
19
20
   Standalone program to read a MySQL binary log (or relay log);
21
   can read files produced by 3.23, 4.x, 5.0 servers. 
22
23
   Can read binlogs from 3.23/4.x/5.0 and relay logs from 4.x/5.0.
24
   Should be able to read any file of these categories, even with
25
   --start-position.
26
   An important fact: the Format_desc event of the log is at most the 3rd event
27
   of the log; if it is the 3rd then there is this combination:
28
   Format_desc_of_slave, Rotate_of_master, Format_desc_of_master.
29
*/
30
31
#define MYSQL_CLIENT
32
#undef MYSQL_SERVER
33
#include "client_priv.h"
34
#include <my_time.h>
35
/* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */
36
#include "mysql_priv.h" 
37
#include "log_event.h"
38
#include "sql_common.h"
39
40
#define BIN_LOG_HEADER_SIZE	4
41
#define PROBE_HEADER_LEN	(EVENT_LEN_OFFSET+4)
42
43
44
#define CLIENT_CAPABILITIES	(CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
45
46
char server_version[SERVER_VERSION_LENGTH];
47
ulong server_id = 0;
48
49
// needed by net_serv.c
50
ulong bytes_sent = 0L, bytes_received = 0L;
51
ulong mysqld_net_retry_count = 10L;
52
ulong open_files_limit;
53
uint test_flags = 0; 
54
static uint opt_protocol= 0;
55
static FILE *result_file;
56
57
#ifndef DBUG_OFF
58
static const char* default_dbug_option = "d:t:o,/tmp/mysqlbinlog.trace";
59
#endif
60
static const char *load_default_groups[]= { "mysqlbinlog","client",0 };
61
62
static void error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
63
static void warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
64
65
static bool one_database=0, to_last_remote_log= 0, disable_log_bin= 0;
66
static bool opt_hexdump= 0;
67
const char *base64_output_mode_names[]= {"NEVER", "AUTO", "ALWAYS", NullS};
68
TYPELIB base64_output_mode_typelib=
69
  { array_elements(base64_output_mode_names) - 1, "",
70
    base64_output_mode_names, NULL };
71
static enum_base64_output_mode opt_base64_output_mode= BASE64_OUTPUT_UNSPEC;
72
static const char *opt_base64_output_mode_str= NullS;
73
static const char* database= 0;
74
static my_bool force_opt= 0, short_form= 0, remote_opt= 0;
75
static my_bool debug_info_flag, debug_check_flag;
76
static my_bool force_if_open_opt= 1;
77
static ulonglong offset = 0;
78
static const char* host = 0;
79
static int port= 0;
80
static uint my_end_arg;
81
static const char* sock= 0;
82
static const char* user = 0;
83
static char* pass = 0;
84
static char *charset= 0;
85
86
static ulonglong start_position, stop_position;
87
#define start_position_mot ((my_off_t)start_position)
88
#define stop_position_mot  ((my_off_t)stop_position)
89
90
static char *start_datetime_str, *stop_datetime_str;
91
static my_time_t start_datetime= 0, stop_datetime= MY_TIME_T_MAX;
92
static ulonglong rec_count= 0;
93
static short binlog_flags = 0; 
94
static MYSQL* mysql = NULL;
95
static const char* dirname_for_local_load= 0;
96
97
/**
98
  Pointer to the Format_description_log_event of the currently active binlog.
99
100
  This will be changed each time a new Format_description_log_event is
101
  found in the binlog. It is finally destroyed at program termination.
102
*/
103
static Format_description_log_event* glob_description_event= NULL;
104
105
/**
106
  Exit status for functions in this file.
107
*/
108
enum Exit_status {
109
  /** No error occurred and execution should continue. */
110
  OK_CONTINUE= 0,
111
  /** An error occurred and execution should stop. */
112
  ERROR_STOP,
113
  /** No error occurred but execution should stop. */
114
  OK_STOP
115
};
116
117
static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
118
                                          const char* logname);
119
static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
120
                                           const char* logname);
121
static Exit_status dump_log_entries(const char* logname);
122
static Exit_status safe_connect();
123
124
125
class Load_log_processor
126
{
127
  char target_dir_name[FN_REFLEN];
128
  int target_dir_name_len;
129
130
  /*
131
    When we see first event corresponding to some LOAD DATA statement in
132
    binlog, we create temporary file to store data to be loaded.
133
    We add name of this file to file_names array using its file_id as index.
134
    If we have Create_file event (i.e. we have binary log in pre-5.0.3
135
    format) we also store save event object to be able which is needed to
136
    emit LOAD DATA statement when we will meet Exec_load_data event.
137
    If we have Begin_load_query event we simply store 0 in
138
    File_name_record::event field.
139
  */
140
  struct File_name_record
141
  {
142
    char *fname;
143
    Create_file_log_event *event;
144
  };
145
  /*
146
    @todo Should be a map (e.g., a hash map), not an array.  With the
147
    present implementation, the number of elements in this array is
148
    about the number of files loaded since the server started, which
149
    may be big after a few years.  We should be able to use existing
150
    library data structures for this. /Sven
151
  */
152
  DYNAMIC_ARRAY file_names;
153
154
  /**
155
    Looks for a non-existing filename by adding a numerical suffix to
156
    the given base name, creates the generated file, and returns the
157
    filename by modifying the filename argument.
158
159
    @param[in,out] filename Base filename
160
161
    @param[in,out] file_name_end Pointer to last character of
162
    filename.  The numerical suffix will be written to this position.
163
    Note that there must be a least five bytes of allocated memory
164
    after file_name_end.
165
166
    @retval -1 Error (can't find new filename).
167
    @retval >=0 Found file.
168
  */
169
  File create_unique_file(char *filename, char *file_name_end)
170
    {
171
      File res;
172
      /* If we have to try more than 1000 times, something is seriously wrong */
173
      for (uint version= 0; version<1000; version++)
174
      {
175
	sprintf(file_name_end,"-%x",version);
176
	if ((res= my_create(filename,0,
177
			    O_CREAT|O_EXCL|O_BINARY|O_WRONLY,MYF(0)))!=-1)
178
	  return res;
179
      }
180
      return -1;
181
    }
182
183
public:
184
  Load_log_processor() {}
185
  ~Load_log_processor() {}
186
187
  int init()
188
  {
189
    return init_dynamic_array(&file_names, sizeof(File_name_record),
190
			      100,100 CALLER_INFO);
191
  }
192
193
  void init_by_dir_name(const char *dir)
194
    {
195
      target_dir_name_len= (convert_dirname(target_dir_name, dir, NullS) -
196
			    target_dir_name);
197
    }
198
  void init_by_cur_dir()
199
    {
200
      if (my_getwd(target_dir_name,sizeof(target_dir_name),MYF(MY_WME)))
201
	exit(1);
202
      target_dir_name_len= strlen(target_dir_name);
203
    }
204
  void destroy()
205
  {
206
    File_name_record *ptr= (File_name_record *)file_names.buffer;
207
    File_name_record *end= ptr + file_names.elements;
208
    for (; ptr < end; ptr++)
209
    {
210
      if (ptr->fname)
211
      {
212
        my_free(ptr->fname, MYF(MY_WME));
213
        delete ptr->event;
214
        bzero((char *)ptr, sizeof(File_name_record));
215
      }
216
    }
217
218
    delete_dynamic(&file_names);
219
  }
220
221
  /**
222
    Obtain Create_file event for LOAD DATA statement by its file_id
223
    and remove it from this Load_log_processor's list of events.
224
225
    Checks whether we have already seen a Create_file_log_event with
226
    the given file_id.  If yes, returns a pointer to the event and
227
    removes the event from array describing active temporary files.
228
    From this moment, the caller is responsible for freeing the memory
229
    occupied by the event.
230
231
    @param[in] file_id File id identifying LOAD DATA statement.
232
233
    @return Pointer to Create_file_log_event, or NULL if we have not
234
    seen any Create_file_log_event with this file_id.
235
  */
236
  Create_file_log_event *grab_event(uint file_id)
237
    {
238
      File_name_record *ptr;
239
      Create_file_log_event *res;
240
241
      if (file_id >= file_names.elements)
242
        return 0;
243
      ptr= dynamic_element(&file_names, file_id, File_name_record*);
244
      if ((res= ptr->event))
245
        bzero((char *)ptr, sizeof(File_name_record));
246
      return res;
247
    }
248
249
  /**
250
    Obtain file name of temporary file for LOAD DATA statement by its
251
    file_id and remove it from this Load_log_processor's list of events.
252
253
    @param[in] file_id Identifier for the LOAD DATA statement.
254
255
    Checks whether we have already seen Begin_load_query event for
256
    this file_id. If yes, returns the file name of the corresponding
257
    temporary file and removes the filename from the array of active
258
    temporary files.  From this moment, the caller is responsible for
259
    freeing the memory occupied by this name.
260
261
    @return String with the name of the temporary file, or NULL if we
262
    have not seen any Begin_load_query_event with this file_id.
263
  */
264
  char *grab_fname(uint file_id)
265
    {
266
      File_name_record *ptr;
267
      char *res= 0;
268
269
      if (file_id >= file_names.elements)
270
        return 0;
271
      ptr= dynamic_element(&file_names, file_id, File_name_record*);
272
      if (!ptr->event)
273
      {
274
        res= ptr->fname;
275
        bzero((char *)ptr, sizeof(File_name_record));
276
      }
277
      return res;
278
    }
279
  Exit_status process(Create_file_log_event *ce);
280
  Exit_status process(Begin_load_query_log_event *ce);
281
  Exit_status process(Append_block_log_event *ae);
282
  File prepare_new_file_for_old_format(Load_log_event *le, char *filename);
283
  Exit_status load_old_format_file(NET* net, const char *server_fname,
284
                                   uint server_fname_len, File file);
285
  Exit_status process_first_event(const char *bname, uint blen,
286
                                  const uchar *block,
287
                                  uint block_len, uint file_id,
288
                                  Create_file_log_event *ce);
289
};
290
291
292
/**
293
  Creates and opens a new temporary file in the directory specified by previous call to init_by_dir_name() or init_by_cur_dir().
294
295
  @param[in] le The basename of the created file will start with the
296
  basename of the file pointed to by this Load_log_event.
297
298
  @param[out] filename Buffer to save the filename in.
299
300
  @return File handle >= 0 on success, -1 on error.
301
*/
302
File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le,
303
							 char *filename)
304
{
305
  uint len;
306
  char *tail;
307
  File file;
308
  
309
  fn_format(filename, le->fname, target_dir_name, "", MY_REPLACE_DIR);
310
  len= strlen(filename);
311
  tail= filename + len;
312
  
313
  if ((file= create_unique_file(filename,tail)) < 0)
314
  {
315
    error("Could not construct local filename %s.",filename);
316
    return -1;
317
  }
318
  
319
  le->set_fname_outside_temp_buf(filename,len+strlen(tail));
320
  
321
  return file;
322
}
323
324
325
/**
326
  Reads a file from a server and saves it locally.
327
328
  @param[in,out] net The server to read from.
329
330
  @param[in] server_fname The name of the file that the server should
331
  read.
332
333
  @param[in] server_fname_len The length of server_fname.
334
335
  @param[in,out] file The file to write to.
336
337
  @retval ERROR_STOP An error occurred - the program should terminate.
338
  @retval OK_CONTINUE No error, the program should continue.
339
*/
340
Exit_status Load_log_processor::load_old_format_file(NET* net,
341
                                                     const char*server_fname,
342
                                                     uint server_fname_len,
343
                                                     File file)
344
{
345
  uchar buf[FN_REFLEN+1];
346
  buf[0] = 0;
347
  memcpy(buf + 1, server_fname, server_fname_len + 1);
348
  if (my_net_write(net, buf, server_fname_len +2) || net_flush(net))
349
  {
350
    error("Failed requesting the remote dump of %s.", server_fname);
351
    return ERROR_STOP;
352
  }
353
  
354
  for (;;)
355
  {
356
    ulong packet_len = my_net_read(net);
357
    if (packet_len == 0)
358
    {
359
      if (my_net_write(net, (uchar*) "", 0) || net_flush(net))
360
      {
361
        error("Failed sending the ack packet.");
362
        return ERROR_STOP;
363
      }
364
      /*
365
	we just need to send something, as the server will read but
366
	not examine the packet - this is because mysql_load() sends 
367
	an OK when it is done
368
      */
369
      break;
370
    }
371
    else if (packet_len == packet_error)
372
    {
373
      error("Failed reading a packet during the dump of %s.", server_fname);
374
      return ERROR_STOP;
375
    }
376
    
377
    if (packet_len > UINT_MAX)
378
    {
379
      error("Illegal length of packet read from net.");
380
      return ERROR_STOP;
381
    }
382
    if (my_write(file, (uchar*) net->read_pos, 
383
		 (uint) packet_len, MYF(MY_WME|MY_NABP)))
384
      return ERROR_STOP;
385
  }
386
  
387
  return OK_CONTINUE;
388
}
389
390
391
/**
392
  Process the first event in the sequence of events representing a
393
  LOAD DATA statement.
394
395
  Creates a temporary file to be used in LOAD DATA and writes first
396
  block of data to it. Registers its file name (and optional
397
  Create_file event) in the array of active temporary files.
398
399
  @param bname Base name for temporary file to be created.
400
  @param blen Base name length.
401
  @param block First block of data to be loaded.
402
  @param block_len First block length.
403
  @param file_id Identifies the LOAD DATA statement.
404
  @param ce Pointer to Create_file event object if we are processing
405
  this type of event.
406
407
  @retval ERROR_STOP An error occurred - the program should terminate.
408
  @retval OK_CONTINUE No error, the program should continue.
409
*/
410
Exit_status Load_log_processor::process_first_event(const char *bname,
411
                                                    uint blen,
412
                                                    const uchar *block,
413
                                                    uint block_len,
414
                                                    uint file_id,
415
                                                    Create_file_log_event *ce)
416
{
417
  uint full_len= target_dir_name_len + blen + 9 + 9 + 1;
418
  Exit_status retval= OK_CONTINUE;
419
  char *fname, *ptr;
420
  File file;
421
  File_name_record rec;
422
  DBUG_ENTER("Load_log_processor::process_first_event");
423
424
  if (!(fname= (char*) my_malloc(full_len,MYF(MY_WME))))
425
  {
426
    error("Out of memory.");
427
    delete ce;
428
    DBUG_RETURN(ERROR_STOP);
429
  }
430
431
  memcpy(fname, target_dir_name, target_dir_name_len);
432
  ptr= fname + target_dir_name_len;
433
  memcpy(ptr,bname,blen);
434
  ptr+= blen;
435
  ptr+= my_sprintf(ptr, (ptr, "-%x", file_id));
436
437
  if ((file= create_unique_file(fname,ptr)) < 0)
438
  {
439
    error("Could not construct local filename %s%s.",
440
          target_dir_name,bname);
441
    delete ce;
442
    DBUG_RETURN(ERROR_STOP);
443
  }
444
445
  rec.fname= fname;
446
  rec.event= ce;
447
448
  if (set_dynamic(&file_names, (uchar*)&rec, file_id))
449
  {
450
    error("Out of memory.");
451
    delete ce;
452
    DBUG_RETURN(ERROR_STOP);
453
  }
454
455
  if (ce)
456
    ce->set_fname_outside_temp_buf(fname, strlen(fname));
457
458
  if (my_write(file, (uchar*)block, block_len, MYF(MY_WME|MY_NABP)))
459
  {
460
    error("Failed writing to file.");
461
    retval= ERROR_STOP;
462
  }
463
  if (my_close(file, MYF(MY_WME)))
464
  {
465
    error("Failed closing file.");
466
    retval= ERROR_STOP;
467
  }
468
  DBUG_RETURN(retval);
469
}
470
471
472
/**
473
  Process the given Create_file_log_event.
474
475
  @see Load_log_processor::process_first_event(const char*,uint,const char*,uint,uint,Create_file_log_event*)
476
477
  @param ce Create_file_log_event to process.
478
479
  @retval ERROR_STOP An error occurred - the program should terminate.
480
  @retval OK_CONTINUE No error, the program should continue.
481
*/
482
Exit_status  Load_log_processor::process(Create_file_log_event *ce)
483
{
484
  const char *bname= ce->fname + dirname_length(ce->fname);
485
  uint blen= ce->fname_len - (bname-ce->fname);
486
487
  return process_first_event(bname, blen, ce->block, ce->block_len,
488
                             ce->file_id, ce);
489
}
490
491
492
/**
493
  Process the given Begin_load_query_log_event.
494
495
  @see Load_log_processor::process_first_event(const char*,uint,const char*,uint,uint,Create_file_log_event*)
496
497
  @param ce Begin_load_query_log_event to process.
498
499
  @retval ERROR_STOP An error occurred - the program should terminate.
500
  @retval OK_CONTINUE No error, the program should continue.
501
*/
502
Exit_status Load_log_processor::process(Begin_load_query_log_event *blqe)
503
{
504
  return process_first_event("SQL_LOAD_MB", 11, blqe->block, blqe->block_len,
505
                             blqe->file_id, 0);
506
}
507
508
509
/**
510
  Process the given Append_block_log_event.
511
512
  Appends the chunk of the file contents specified by the event to the
513
  file created by a previous Begin_load_query_log_event or
514
  Create_file_log_event.
515
516
  If the file_id for the event does not correspond to any file
517
  previously registered through a Begin_load_query_log_event or
518
  Create_file_log_event, this member function will print a warning and
519
  return OK_CONTINUE.  It is safe to return OK_CONTINUE, because no
520
  query will be written for this event.  We should not print an error
521
  and fail, since the missing file_id could be because a (valid)
522
  --start-position has been specified after the Begin/Create event but
523
  before this Append event.
524
525
  @param ae Append_block_log_event to process.
526
527
  @retval ERROR_STOP An error occurred - the program should terminate.
528
529
  @retval OK_CONTINUE No error, the program should continue.
530
*/
531
Exit_status Load_log_processor::process(Append_block_log_event *ae)
532
{
533
  DBUG_ENTER("Load_log_processor::process");
534
  const char* fname= ((ae->file_id < file_names.elements) ?
535
                       dynamic_element(&file_names, ae->file_id,
536
                                       File_name_record*)->fname : 0);
537
538
  if (fname)
539
  {
540
    File file;
541
    Exit_status retval= OK_CONTINUE;
542
    if (((file= my_open(fname,
543
			O_APPEND|O_BINARY|O_WRONLY,MYF(MY_WME))) < 0))
544
    {
545
      error("Failed opening file %s", fname);
546
      DBUG_RETURN(ERROR_STOP);
547
    }
548
    if (my_write(file,(uchar*)ae->block,ae->block_len,MYF(MY_WME|MY_NABP)))
549
    {
550
      error("Failed writing to file %s", fname);
551
      retval= ERROR_STOP;
552
    }
553
    if (my_close(file,MYF(MY_WME)))
554
    {
555
      error("Failed closing file %s", fname);
556
      retval= ERROR_STOP;
557
    }
558
    DBUG_RETURN(retval);
559
  }
560
561
  /*
562
    There is no Create_file event (a bad binlog or a big
563
    --start-position). Assuming it's a big --start-position, we just do
564
    nothing and print a warning.
565
  */
566
  warning("Ignoring Append_block as there is no "
567
          "Create_file event for file_id: %u", ae->file_id);
568
  DBUG_RETURN(OK_CONTINUE);
569
}
570
571
572
static Load_log_processor load_processor;
573
574
575
/**
576
  Replace windows-style backslashes by forward slashes so it can be
577
  consumed by the mysql client, which requires Unix path.
578
579
  @todo This is only useful under windows, so may be ifdef'ed out on
580
  other systems.  /Sven
581
582
  @todo If a Create_file_log_event contains a filename with a
583
  backslash (valid under unix), then we have problems under windows.
584
  /Sven
585
586
  @param[in,out] fname Filename to modify. The filename is modified
587
  in-place.
588
*/
589
static void convert_path_to_forward_slashes(char *fname)
590
{
591
  while (*fname)
592
  {
593
    if (*fname == '\\')
594
      *fname= '/';
595
    fname++;
596
  }
597
}
598
599
600
/**
601
  Indicates whether the given database should be filtered out,
602
  according to the --database=X option.
603
604
  @param log_dbname Name of database.
605
606
  @return nonzero if the database with the given name should be
607
  filtered out, 0 otherwise.
608
*/
609
static bool shall_skip_database(const char *log_dbname)
610
{
611
  return one_database &&
612
         (log_dbname != NULL) &&
613
         strcmp(log_dbname, database);
614
}
615
616
617
/**
618
  Prints the given event in base64 format.
619
620
  The header is printed to the head cache and the body is printed to
621
  the body cache of the print_event_info structure.  This allows all
622
  base64 events corresponding to the same statement to be joined into
623
  one BINLOG statement.
624
625
  @param[in] ev Log_event to print.
626
  @param[in,out] result_file FILE to which the output will be written.
627
  @param[in,out] print_event_info Parameters and context state
628
  determining how to print.
629
630
  @retval ERROR_STOP An error occurred - the program should terminate.
631
  @retval OK_CONTINUE No error, the program should continue.
632
*/
633
static Exit_status
634
write_event_header_and_base64(Log_event *ev, FILE *result_file,
635
                              PRINT_EVENT_INFO *print_event_info)
636
{
637
  IO_CACHE *head= &print_event_info->head_cache;
638
  IO_CACHE *body= &print_event_info->body_cache;
639
  DBUG_ENTER("write_event_header_and_base64");
640
641
  /* Write header and base64 output to cache */
642
  ev->print_header(head, print_event_info, FALSE);
643
  ev->print_base64(body, print_event_info, FALSE);
644
645
  /* Read data from cache and write to result file */
646
  if (copy_event_cache_to_file_and_reinit(head, result_file) ||
647
      copy_event_cache_to_file_and_reinit(body, result_file))
648
  {
649
    error("Error writing event to file.");
650
    DBUG_RETURN(ERROR_STOP);
651
  }
652
  DBUG_RETURN(OK_CONTINUE);
653
}
654
655
656
/**
657
  Print the given event, and either delete it or delegate the deletion
658
  to someone else.
659
660
  The deletion may be delegated in two cases: (1) the event is a
661
  Format_description_log_event, and is saved in
662
  glob_description_event; (2) the event is a Create_file_log_event,
663
  and is saved in load_processor.
664
665
  @param[in,out] print_event_info Parameters and context state
666
  determining how to print.
667
  @param[in] ev Log_event to process.
668
  @param[in] pos Offset from beginning of binlog file.
669
  @param[in] logname Name of input binlog.
670
671
  @retval ERROR_STOP An error occurred - the program should terminate.
672
  @retval OK_CONTINUE No error, the program should continue.
673
  @retval OK_STOP No error, but the end of the specified range of
674
  events to process has been reached and the program should terminate.
675
*/
676
Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
677
                          my_off_t pos, const char *logname)
678
{
679
  char ll_buff[21];
680
  Log_event_type ev_type= ev->get_type_code();
681
  DBUG_ENTER("process_event");
682
  print_event_info->short_form= short_form;
683
  Exit_status retval= OK_CONTINUE;
684
685
  /*
686
    Format events are not concerned by --offset and such, we always need to
687
    read them to be able to process the wanted events.
688
  */
689
  if (((rec_count >= offset) && ((my_time_t)(ev->when) >= start_datetime)) || (ev_type == FORMAT_DESCRIPTION_EVENT))
690
  {
691
    if (ev_type != FORMAT_DESCRIPTION_EVENT)
692
    {
693
      /*
694
        We have found an event after start_datetime, from now on print
695
        everything (in case the binlog has timestamps increasing and
696
        decreasing, we do this to avoid cutting the middle).
697
      */
698
      start_datetime= 0;
699
      offset= 0; // print everything and protect against cycling rec_count
700
    }
701
    if (server_id && (server_id != ev->server_id))
702
      /* skip just this event, continue processing the log. */
703
      goto end;
704
    if (((my_time_t)(ev->when) >= stop_datetime)
705
        || (pos >= stop_position_mot))
706
    {
707
      /* end the program */
708
      retval= OK_STOP;
709
      goto end;
710
    }
711
    if (!short_form)
712
      fprintf(result_file, "# at %s\n",llstr(pos,ll_buff));
713
714
    if (!opt_hexdump)
715
      print_event_info->hexdump_from= 0; /* Disabled */
716
    else
717
      print_event_info->hexdump_from= pos;
718
719
    print_event_info->base64_output_mode= opt_base64_output_mode;
720
721
    DBUG_PRINT("debug", ("event_type: %s", ev->get_type_str()));
722
723
    switch (ev_type) {
724
    case QUERY_EVENT:
725
      if (shall_skip_database(((Query_log_event*)ev)->db))
726
        goto end;
727
      if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
728
      {
729
        if ((retval= write_event_header_and_base64(ev, result_file,
730
                                                   print_event_info)) !=
731
            OK_CONTINUE)
732
          goto end;
733
      }
734
      else
735
        ev->print(result_file, print_event_info);
736
      break;
737
738
    case CREATE_FILE_EVENT:
739
    {
740
      Create_file_log_event* ce= (Create_file_log_event*)ev;
741
      /*
742
        We test if this event has to be ignored. If yes, we don't save
743
        this event; this will have the good side-effect of ignoring all
744
        related Append_block and Exec_load.
745
        Note that Load event from 3.23 is not tested.
746
      */
747
      if (shall_skip_database(ce->db))
748
        goto end;                // Next event
749
      /*
750
	We print the event, but with a leading '#': this is just to inform 
751
	the user of the original command; the command we want to execute 
752
	will be a derivation of this original command (we will change the 
753
	filename and use LOCAL), prepared in the 'case EXEC_LOAD_EVENT' 
754
	below.
755
      */
756
      if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
757
      {
758
        if ((retval= write_event_header_and_base64(ce, result_file,
759
                                                   print_event_info)) !=
760
            OK_CONTINUE)
761
          goto end;
762
      }
763
      else
764
        ce->print(result_file, print_event_info, TRUE);
765
766
      // If this binlog is not 3.23 ; why this test??
767
      if (glob_description_event->binlog_version >= 3)
768
      {
769
        /*
770
          transfer the responsibility for destroying the event to
771
          load_processor
772
        */
773
        ev= NULL;
774
        if ((retval= load_processor.process(ce)) != OK_CONTINUE)
775
          goto end;
776
      }
777
      break;
778
    }
779
780
    case APPEND_BLOCK_EVENT:
781
      /*
782
        Append_block_log_events can safely print themselves even if
783
        the subsequent call load_processor.process fails, because the
784
        output of Append_block_log_event::print is only a comment.
785
      */
786
      ev->print(result_file, print_event_info);
787
      if ((retval= load_processor.process((Append_block_log_event*) ev)) !=
788
          OK_CONTINUE)
789
        goto end;
790
      break;
791
792
    case EXEC_LOAD_EVENT:
793
    {
794
      ev->print(result_file, print_event_info);
795
      Execute_load_log_event *exv= (Execute_load_log_event*)ev;
796
      Create_file_log_event *ce= load_processor.grab_event(exv->file_id);
797
      /*
798
	if ce is 0, it probably means that we have not seen the Create_file
799
	event (a bad binlog, or most probably --start-position is after the
800
	Create_file event). Print a warning comment.
801
      */
802
      if (ce)
803
      {
804
        /*
805
          We must not convert earlier, since the file is used by
806
          my_open() in Load_log_processor::append().
807
        */
808
        convert_path_to_forward_slashes((char*) ce->fname);
809
	ce->print(result_file, print_event_info, TRUE);
810
	my_free((char*)ce->fname,MYF(MY_WME));
811
	delete ce;
812
      }
813
      else
814
        warning("Ignoring Execute_load_log_event as there is no "
815
                "Create_file event for file_id: %u", exv->file_id);
816
      break;
817
    }
818
    case FORMAT_DESCRIPTION_EVENT:
819
      delete glob_description_event;
820
      glob_description_event= (Format_description_log_event*) ev;
821
      print_event_info->common_header_len=
822
        glob_description_event->common_header_len;
823
      ev->print(result_file, print_event_info);
824
      ev->temp_buf= 0; // as the event ref is zeroed
825
      /*
826
        We don't want this event to be deleted now, so let's hide it (I
827
        (Guilhem) should later see if this triggers a non-serious Valgrind
828
        error). Not serious error, because we will free description_event
829
        later.
830
      */
831
      ev= 0;
832
      if (!force_if_open_opt &&
833
          (glob_description_event->flags & LOG_EVENT_BINLOG_IN_USE_F))
834
      {
835
        error("Attempting to dump binlog '%s', which was not closed properly. "
836
              "Most probably, mysqld is still writing it, or it crashed. "
837
              "Rerun with --force-if-open to ignore this problem.", logname);
838
        DBUG_RETURN(ERROR_STOP);
839
      }
840
      break;
841
    case BEGIN_LOAD_QUERY_EVENT:
842
      ev->print(result_file, print_event_info);
843
      if ((retval= load_processor.process((Begin_load_query_log_event*) ev)) !=
844
          OK_CONTINUE)
845
        goto end;
846
      break;
847
    case EXECUTE_LOAD_QUERY_EVENT:
848
    {
849
      Execute_load_query_log_event *exlq= (Execute_load_query_log_event*)ev;
850
      char *fname= load_processor.grab_fname(exlq->file_id);
851
852
      if (!shall_skip_database(exlq->db))
853
      {
854
        if (fname)
855
        {
856
          convert_path_to_forward_slashes(fname);
857
          exlq->print(result_file, print_event_info, fname);
858
        }
859
        else
860
          warning("Ignoring Execute_load_query since there is no "
861
                  "Begin_load_query event for file_id: %u", exlq->file_id);
862
      }
863
864
      if (fname)
865
	my_free(fname, MYF(MY_WME));
866
      break;
867
    }
868
    case TABLE_MAP_EVENT:
869
    case WRITE_ROWS_EVENT:
870
    case DELETE_ROWS_EVENT:
871
    case UPDATE_ROWS_EVENT:
872
    case PRE_GA_WRITE_ROWS_EVENT:
873
    case PRE_GA_DELETE_ROWS_EVENT:
874
    case PRE_GA_UPDATE_ROWS_EVENT:
875
      /*
876
        These events must be printed in base64 format, if printed.
877
        base64 format requires a FD event to be safe, so if no FD
878
        event has been printed, we give an error.  Except if user
879
        passed --short-form, because --short-form disables printing
880
        row events.
881
      */
882
      if (!print_event_info->printed_fd_event && !short_form)
883
      {
884
        const char* type_str= ev->get_type_str();
885
        if (opt_base64_output_mode == BASE64_OUTPUT_NEVER)
886
          error("--base64-output=never specified, but binlog contains a "
887
                "%s event which must be printed in base64.",
888
                type_str);
889
        else
890
          error("malformed binlog: it does not contain any "
891
                "Format_description_log_event. I now found a %s event, which "
892
                "is not safe to process without a "
893
                "Format_description_log_event.",
894
                type_str);
895
        goto err;
896
      }
897
      /* FALL THROUGH */
898
    default:
899
      ev->print(result_file, print_event_info);
900
    }
901
  }
902
903
  goto end;
904
905
err:
906
  retval= ERROR_STOP;
907
end:
908
  rec_count++;
909
  /*
910
    Destroy the log_event object. If reading from a remote host,
911
    set the temp_buf to NULL so that memory isn't freed twice.
912
  */
913
  if (ev)
914
  {
915
    if (remote_opt)
916
      ev->temp_buf= 0;
917
    delete ev;
918
  }
919
  DBUG_RETURN(retval);
920
}
921
922
923
static struct my_option my_long_options[] =
924
{
925
  {"help", '?', "Display this help and exit.",
926
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
927
  {"base64-output", OPT_BASE64_OUTPUT_MODE,
928
   "Determine when the output statements should be base64-encoded BINLOG "
929
   "statements: 'never' disables it and works only for binlogs without "
930
   "row-based events; 'auto' is the default and prints base64 only when "
931
   "necessary (i.e., for row-based events and format description events); "
932
   "'always' prints base64 whenever possible. 'always' is for debugging "
933
   "only and should not be used in a production system. The default is "
934
   "'auto'. --base64-output is a short form for --base64-output=always."
935
   ,(uchar**) &opt_base64_output_mode_str,
936
   (uchar**) &opt_base64_output_mode_str,
937
   0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
938
  /*
939
    mysqlbinlog needs charsets knowledge, to be able to convert a charset
940
    number found in binlog to a charset name (to be able to print things
941
    like this:
942
    SET @`a`:=_cp850 0x4DFC6C6C6572 COLLATE `cp850_general_ci`;
943
  */
944
  {"character-sets-dir", OPT_CHARSETS_DIR,
945
   "Directory where character sets are.", (uchar**) &charsets_dir,
946
   (uchar**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
947
  {"database", 'd', "List entries for just this database (local log only).",
948
   (uchar**) &database, (uchar**) &database, 0, GET_STR_ALLOC, REQUIRED_ARG,
949
   0, 0, 0, 0, 0, 0},
950
#ifndef DBUG_OFF
951
  {"debug", '#', "Output debug log.", (uchar**) &default_dbug_option,
952
   (uchar**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
953
#endif
954
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .",
955
   (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0,
956
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
957
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
958
   (uchar**) &debug_info_flag, (uchar**) &debug_info_flag,
959
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
960
  {"disable-log-bin", 'D', "Disable binary log. This is useful, if you "
961
    "enabled --to-last-log and are sending the output to the same MySQL server. "
962
    "This way you could avoid an endless loop. You would also like to use it "
963
    "when restoring after a crash to avoid duplication of the statements you "
964
    "already have. NOTE: you will need a SUPER privilege to use this option.",
965
   (uchar**) &disable_log_bin, (uchar**) &disable_log_bin, 0, GET_BOOL,
966
   NO_ARG, 0, 0, 0, 0, 0, 0},
967
  {"force-if-open", 'F', "Force if binlog was not closed properly.",
968
   (uchar**) &force_if_open_opt, (uchar**) &force_if_open_opt, 0, GET_BOOL, NO_ARG,
969
   1, 0, 0, 0, 0, 0},
970
  {"force-read", 'f', "Force reading unknown binlog events.",
971
   (uchar**) &force_opt, (uchar**) &force_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
972
   0, 0},
973
  {"hexdump", 'H', "Augment output with hexadecimal and ASCII event dump.",
974
   (uchar**) &opt_hexdump, (uchar**) &opt_hexdump, 0, GET_BOOL, NO_ARG,
975
   0, 0, 0, 0, 0, 0},
976
  {"host", 'h', "Get the binlog from server.", (uchar**) &host, (uchar**) &host,
977
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
978
  {"local-load", 'l', "Prepare local temporary files for LOAD DATA INFILE in the specified directory.",
979
   (uchar**) &dirname_for_local_load, (uchar**) &dirname_for_local_load, 0,
980
   GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
981
  {"offset", 'o', "Skip the first N entries.", (uchar**) &offset, (uchar**) &offset,
982
   0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
983
  {"password", 'p', "Password to connect to remote server.",
984
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
985
  {"port", 'P', "Port number to use for connection or 0 for default to, in "
986
   "order of preference, my.cnf, $MYSQL_TCP_PORT, "
987
#if MYSQL_PORT_DEFAULT == 0
988
   "/etc/services, "
989
#endif
990
   "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
991
   (uchar**) &port, (uchar**) &port, 0, GET_INT, REQUIRED_ARG,
992
   0, 0, 0, 0, 0, 0},
993
  {"position", 'j', "Deprecated. Use --start-position instead.",
994
   (uchar**) &start_position, (uchar**) &start_position, 0, GET_ULL,
995
   REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE,
996
   /* COM_BINLOG_DUMP accepts only 4 bytes for the position */
997
   (ulonglong)(~(uint32)0), 0, 0, 0},
998
  {"protocol", OPT_MYSQL_PROTOCOL,
999
   "The protocol of connection (tcp,socket,pipe,memory).",
1000
   0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1001
  {"read-from-remote-server", 'R', "Read binary logs from a MySQL server",
1002
   (uchar**) &remote_opt, (uchar**) &remote_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
1003
   0, 0},
1004
  {"result-file", 'r', "Direct output to a given file.", 0, 0, 0, GET_STR,
1005
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1006
  {"server-id", OPT_SERVER_ID,
1007
   "Extract only binlog entries created by the server having the given id.",
1008
   (uchar**) &server_id, (uchar**) &server_id, 0, GET_ULONG,
1009
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1010
  {"set-charset", OPT_SET_CHARSET,
1011
   "Add 'SET NAMES character_set' to the output.", (uchar**) &charset,
1012
   (uchar**) &charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1013
  {"short-form", 's', "Just show regular queries: no extra info and no "
1014
   "row-based events. This is for testing only, and should not be used in "
1015
   "production systems. If you want to suppress base64-output, consider "
1016
   "using --base64-output=never instead.",
1017
   (uchar**) &short_form, (uchar**) &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
1018
   0, 0},
1019
  {"socket", 'S', "Socket file to use for connection.",
1020
   (uchar**) &sock, (uchar**) &sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 
1021
   0, 0},
1022
  {"start-datetime", OPT_START_DATETIME,
1023
   "Start reading the binlog at first event having a datetime equal or "
1024
   "posterior to the argument; the argument must be a date and time "
1025
   "in the local time zone, in any format accepted by the MySQL server "
1026
   "for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 "
1027
   "(you should probably use quotes for your shell to set it properly).",
1028
   (uchar**) &start_datetime_str, (uchar**) &start_datetime_str,
1029
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1030
  {"start-position", OPT_START_POSITION,
1031
   "Start reading the binlog at position N. Applies to the first binlog "
1032
   "passed on the command line.",
1033
   (uchar**) &start_position, (uchar**) &start_position, 0, GET_ULL,
1034
   REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE,
1035
   /* COM_BINLOG_DUMP accepts only 4 bytes for the position */
1036
   (ulonglong)(~(uint32)0), 0, 0, 0},
1037
  {"stop-datetime", OPT_STOP_DATETIME,
1038
   "Stop reading the binlog at first event having a datetime equal or "
1039
   "posterior to the argument; the argument must be a date and time "
1040
   "in the local time zone, in any format accepted by the MySQL server "
1041
   "for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 "
1042
   "(you should probably use quotes for your shell to set it properly).",
1043
   (uchar**) &stop_datetime_str, (uchar**) &stop_datetime_str,
1044
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1045
  {"stop-position", OPT_STOP_POSITION,
1046
   "Stop reading the binlog at position N. Applies to the last binlog "
1047
   "passed on the command line.",
1048
   (uchar**) &stop_position, (uchar**) &stop_position, 0, GET_ULL,
1049
   REQUIRED_ARG, (ulonglong)(~(my_off_t)0), BIN_LOG_HEADER_SIZE,
1050
   (ulonglong)(~(my_off_t)0), 0, 0, 0},
1051
  {"to-last-log", 't', "Requires -R. Will not stop at the end of the \
1052
requested binlog but rather continue printing until the end of the last \
1053
binlog of the MySQL server. If you send the output to the same MySQL server, \
1054
that may lead to an endless loop.",
1055
   (uchar**) &to_last_remote_log, (uchar**) &to_last_remote_log, 0, GET_BOOL,
1056
   NO_ARG, 0, 0, 0, 0, 0, 0},
1057
  {"user", 'u', "Connect to the remote server as username.",
1058
   (uchar**) &user, (uchar**) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0,
1059
   0, 0},
1060
  {"version", 'V', "Print version and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
1061
   0, 0, 0, 0, 0},
1062
  {"open_files_limit", OPT_OPEN_FILES_LIMIT,
1063
   "Used to reserve file descriptors for usage by this program",
1064
   (uchar**) &open_files_limit, (uchar**) &open_files_limit, 0, GET_ULONG,
1065
   REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0},
1066
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
1067
};
1068
1069
1070
/**
1071
  Auxiliary function used by error() and warning().
1072
1073
  Prints the given text (normally "WARNING: " or "ERROR: "), followed
1074
  by the given vprintf-style string, followed by a newline.
1075
1076
  @param format Printf-style format string.
1077
  @param args List of arguments for the format string.
1078
  @param msg Text to print before the string.
1079
*/
1080
static void error_or_warning(const char *format, va_list args, const char *msg)
1081
{
1082
  fprintf(stderr, "%s: ", msg);
1083
  vfprintf(stderr, format, args);
1084
  fprintf(stderr, "\n");
1085
}
1086
1087
/**
1088
  Prints a message to stderr, prefixed with the text "ERROR: " and
1089
  suffixed with a newline.
1090
1091
  @param format Printf-style format string, followed by printf
1092
  varargs.
1093
*/
1094
static void error(const char *format,...)
1095
{
1096
  va_list args;
1097
  va_start(args, format);
1098
  error_or_warning(format, args, "ERROR");
1099
  va_end(args);
1100
}
1101
1102
1103
/**
1104
  This function is used in log_event.cc to report errors.
1105
1106
  @param format Printf-style format string, followed by printf
1107
  varargs.
1108
*/
1109
static void sql_print_error(const char *format,...)
1110
{
1111
  va_list args;
1112
  va_start(args, format);
1113
  error_or_warning(format, args, "ERROR");
1114
  va_end(args);
1115
}
1116
1117
/**
1118
  Prints a message to stderr, prefixed with the text "WARNING: " and
1119
  suffixed with a newline.
1120
1121
  @param format Printf-style format string, followed by printf
1122
  varargs.
1123
*/
1124
static void warning(const char *format,...)
1125
{
1126
  va_list args;
1127
  va_start(args, format);
1128
  error_or_warning(format, args, "WARNING");
1129
  va_end(args);
1130
}
1131
1132
/**
1133
  Frees memory for global variables in this file.
1134
*/
1135
static void cleanup()
1136
{
1137
  my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
1138
  my_free((char*) database, MYF(MY_ALLOW_ZERO_PTR));
1139
  my_free((char*) host, MYF(MY_ALLOW_ZERO_PTR));
1140
  my_free((char*) user, MYF(MY_ALLOW_ZERO_PTR));
1141
  my_free((char*) dirname_for_local_load, MYF(MY_ALLOW_ZERO_PTR));
1142
1143
  delete glob_description_event;
1144
  if (mysql)
1145
    mysql_close(mysql);
1146
}
1147
1148
#include <help_start.h>
1149
1150
static void print_version()
1151
{
1152
  printf("%s Ver 3.3 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE);
1153
}
1154
1155
1156
static void usage()
1157
{
1158
  print_version();
1159
  puts("By Monty and Sasha, for your professional use\n\
1160
This software comes with NO WARRANTY:  This is free software,\n\
1161
and you are welcome to modify and redistribute it under the GPL license\n");
1162
1163
  printf("\
1164
Dumps a MySQL binary log in a format usable for viewing or for piping to\n\
1165
the mysql command line client\n\n");
1166
  printf("Usage: %s [options] log-files\n", my_progname);
1167
  my_print_help(my_long_options);
1168
  my_print_variables(my_long_options);
1169
}
1170
1171
1172
static my_time_t convert_str_to_timestamp(const char* str)
1173
{
1174
  int was_cut;
1175
  MYSQL_TIME l_time;
1176
  long dummy_my_timezone;
1177
  my_bool dummy_in_dst_time_gap;
1178
  /* We require a total specification (date AND time) */
1179
  if (str_to_datetime(str, strlen(str), &l_time, 0, &was_cut) !=
1180
      MYSQL_TIMESTAMP_DATETIME || was_cut)
1181
  {
1182
    error("Incorrect date and time argument: %s", str);
1183
    exit(1);
1184
  }
1185
  /*
1186
    Note that Feb 30th, Apr 31st cause no error messages and are mapped to
1187
    the next existing day, like in mysqld. Maybe this could be changed when
1188
    mysqld is changed too (with its "strict" mode?).
1189
  */
1190
  return
1191
    my_system_gmt_sec(&l_time, &dummy_my_timezone, &dummy_in_dst_time_gap);
1192
}
1193
1194
#include <help_end.h>
1195
1196
extern "C" my_bool
1197
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
1198
	       char *argument)
1199
{
1200
  bool tty_password=0;
1201
  switch (optid) {
1202
#ifndef DBUG_OFF
1203
  case '#':
1204
    DBUG_PUSH(argument ? argument : default_dbug_option);
1205
    break;
1206
#endif
1207
  case 'd':
1208
    one_database = 1;
1209
    break;
1210
  case 'p':
1211
    if (argument)
1212
    {
1213
      my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
1214
      char *start=argument;
1215
      pass= my_strdup(argument,MYF(MY_FAE));
1216
      while (*argument) *argument++= 'x';		/* Destroy argument */
1217
      if (*start)
1218
        start[1]=0;				/* Cut length of argument */
1219
    }
1220
    else
1221
      tty_password=1;
1222
    break;
1223
  case 'r':
1224
    if (!(result_file = my_fopen(argument, O_WRONLY | O_BINARY, MYF(MY_WME))))
1225
      exit(1);
1226
    break;
1227
  case 'R':
1228
    remote_opt= 1;
1229
    break;
1230
  case OPT_MYSQL_PROTOCOL:
1231
    opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
1232
                                    opt->name);
1233
    break;
1234
  case OPT_START_DATETIME:
1235
    start_datetime= convert_str_to_timestamp(start_datetime_str);
1236
    break;
1237
  case OPT_STOP_DATETIME:
1238
    stop_datetime= convert_str_to_timestamp(stop_datetime_str);
1239
    break;
1240
  case OPT_BASE64_OUTPUT_MODE:
1241
    if (argument == NULL)
1242
      opt_base64_output_mode= BASE64_OUTPUT_ALWAYS;
1243
    else
1244
    {
1245
      opt_base64_output_mode= (enum_base64_output_mode)
1246
        (find_type_or_exit(argument, &base64_output_mode_typelib, opt->name)-1);
1247
    }
1248
    break;
1249
  case 'V':
1250
    print_version();
1251
    exit(0);
1252
  case '?':
1253
    usage();
1254
    exit(0);
1255
  }
1256
  if (tty_password)
1257
    pass= get_tty_password(NullS);
1258
1259
  return 0;
1260
}
1261
1262
1263
static int parse_args(int *argc, char*** argv)
1264
{
1265
  int ho_error;
1266
1267
  result_file = stdout;
1268
  load_defaults("my",load_default_groups,argc,argv);
1269
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
1270
    exit(ho_error);
1271
  if (debug_info_flag)
1272
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
1273
  if (debug_check_flag)
1274
    my_end_arg= MY_CHECK_ERROR;
1275
  return 0;
1276
}
1277
1278
1279
/**
1280
  Create and initialize the global mysql object, and connect to the
1281
  server.
1282
1283
  @retval ERROR_STOP An error occurred - the program should terminate.
1284
  @retval OK_CONTINUE No error, the program should continue.
1285
*/
1286
static Exit_status safe_connect()
1287
{
1288
  mysql= mysql_init(NULL);
1289
1290
  if (!mysql)
1291
  {
1292
    error("Failed on mysql_init.");
1293
    return ERROR_STOP;
1294
  }
1295
1296
  if (opt_protocol)
1297
    mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol);
1298
  if (!mysql_real_connect(mysql, host, user, pass, 0, port, sock, 0))
1299
  {
1300
    error("Failed on connect: %s", mysql_error(mysql));
1301
    return ERROR_STOP;
1302
  }
1303
  mysql->reconnect= 1;
1304
  return OK_CONTINUE;
1305
}
1306
1307
1308
/**
1309
  High-level function for dumping a named binlog.
1310
1311
  This function calls dump_remote_log_entries() or
1312
  dump_local_log_entries() to do the job.
1313
1314
  @param[in] logname Name of input binlog.
1315
1316
  @retval ERROR_STOP An error occurred - the program should terminate.
1317
  @retval OK_CONTINUE No error, the program should continue.
1318
  @retval OK_STOP No error, but the end of the specified range of
1319
  events to process has been reached and the program should terminate.
1320
*/
1321
static Exit_status dump_log_entries(const char* logname)
1322
{
1323
  Exit_status rc;
1324
  PRINT_EVENT_INFO print_event_info;
1325
1326
  if (!print_event_info.init_ok())
1327
    return ERROR_STOP;
1328
  /*
1329
     Set safe delimiter, to dump things
1330
     like CREATE PROCEDURE safely
1331
  */
1332
  fprintf(result_file, "DELIMITER /*!*/;\n");
1333
  strmov(print_event_info.delimiter, "/*!*/;");
1334
1335
  rc= (remote_opt ? dump_remote_log_entries(&print_event_info, logname) :
1336
       dump_local_log_entries(&print_event_info, logname));
1337
1338
  /* Set delimiter back to semicolon */
1339
  fprintf(result_file, "DELIMITER ;\n");
1340
  strmov(print_event_info.delimiter, ";");
1341
  return rc;
1342
}
1343
1344
1345
/**
1346
  When reading a remote binlog, this function is used to grab the
1347
  Format_description_log_event in the beginning of the stream.
1348
  
1349
  This is not as smart as check_header() (used for local log); it will
1350
  not work for a binlog which mixes format. TODO: fix this.
1351
1352
  @retval ERROR_STOP An error occurred - the program should terminate.
1353
  @retval OK_CONTINUE No error, the program should continue.
1354
*/
1355
static Exit_status check_master_version()
1356
{
1357
  MYSQL_RES* res = 0;
1358
  MYSQL_ROW row;
1359
  const char* version;
1360
1361
  if (mysql_query(mysql, "SELECT VERSION()") ||
1362
      !(res = mysql_store_result(mysql)))
1363
  {
1364
    error("Could not find server version: "
1365
          "Query failed when checking master version: %s", mysql_error(mysql));
1366
    return ERROR_STOP;
1367
  }
1368
  if (!(row = mysql_fetch_row(res)))
1369
  {
1370
    error("Could not find server version: "
1371
          "Master returned no rows for SELECT VERSION().");
1372
    goto err;
1373
  }
1374
1375
  if (!(version = row[0]))
1376
  {
1377
    error("Could not find server version: "
1378
          "Master reported NULL for the version.");
1379
    goto err;
1380
  }
1381
1382
  delete glob_description_event;
1383
  switch (*version) {
1384
  case '3':
1385
    glob_description_event= new Format_description_log_event(1);
1386
    break;
1387
  case '4':
1388
    glob_description_event= new Format_description_log_event(3);
1389
    break;
1390
  case '5':
1391
  case '6':
1392
    /*
1393
      The server is soon going to send us its Format_description log
1394
      event, unless it is a 5.0 server with 3.23 or 4.0 binlogs.
1395
      So we first assume that this is 4.0 (which is enough to read the
1396
      Format_desc event if one comes).
1397
    */
1398
    glob_description_event= new Format_description_log_event(3);
1399
    break;
1400
  default:
1401
    glob_description_event= NULL;
1402
    error("Could not find server version: "
1403
          "Master reported unrecognized MySQL version '%s'.", version);
1404
    goto err;
1405
  }
1406
  if (!glob_description_event || !glob_description_event->is_valid())
1407
  {
1408
    error("Failed creating Format_description_log_event; out of memory?");
1409
    goto err;
1410
  }
1411
1412
  mysql_free_result(res);
1413
  return OK_CONTINUE;
1414
1415
err:
1416
  mysql_free_result(res);
1417
  return ERROR_STOP;
1418
}
1419
1420
1421
/**
1422
  Requests binlog dump from a remote server and prints the events it
1423
  receives.
1424
1425
  @param[in,out] print_event_info Parameters and context state
1426
  determining how to print.
1427
  @param[in] logname Name of input binlog.
1428
1429
  @retval ERROR_STOP An error occurred - the program should terminate.
1430
  @retval OK_CONTINUE No error, the program should continue.
1431
  @retval OK_STOP No error, but the end of the specified range of
1432
  events to process has been reached and the program should terminate.
1433
*/
1434
static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
1435
                                           const char* logname)
1436
1437
{
1438
  uchar buf[128];
1439
  ulong len;
1440
  uint logname_len;
1441
  NET* net;
1442
  my_off_t old_off= start_position_mot;
1443
  char fname[FN_REFLEN+1];
1444
  Exit_status retval= OK_CONTINUE;
1445
  DBUG_ENTER("dump_remote_log_entries");
1446
1447
  /*
1448
    Even if we already read one binlog (case of >=2 binlogs on command line),
1449
    we cannot re-use the same connection as before, because it is now dead
1450
    (COM_BINLOG_DUMP kills the thread when it finishes).
1451
  */
1452
  if ((retval= safe_connect()) != OK_CONTINUE)
1453
    DBUG_RETURN(retval);
1454
  net= &mysql->net;
1455
1456
  if ((retval= check_master_version()) != OK_CONTINUE)
1457
    DBUG_RETURN(retval);
1458
1459
  /*
1460
    COM_BINLOG_DUMP accepts only 4 bytes for the position, so we are forced to
1461
    cast to uint32.
1462
  */
1463
  int4store(buf, (uint32)start_position);
1464
  int2store(buf + BIN_LOG_HEADER_SIZE, binlog_flags);
1465
1466
  size_t tlen = strlen(logname);
1467
  if (tlen > UINT_MAX) 
1468
  {
1469
    error("Log name too long.");
1470
    DBUG_RETURN(ERROR_STOP);
1471
  }
1472
  logname_len = (uint) tlen;
1473
  int4store(buf + 6, 0);
1474
  memcpy(buf + 10, logname, logname_len);
1475
  if (simple_command(mysql, COM_BINLOG_DUMP, buf, logname_len + 10, 1))
1476
  {
1477
    error("Got fatal error sending the log dump command.");
1478
    DBUG_RETURN(ERROR_STOP);
1479
  }
1480
1481
  for (;;)
1482
  {
1483
    const char *error_msg;
1484
    Log_event *ev;
1485
1486
    len= cli_safe_read(mysql);
1487
    if (len == packet_error)
1488
    {
1489
      error("Got error reading packet from server: %s", mysql_error(mysql));
1490
      DBUG_RETURN(ERROR_STOP);
1491
    }
1492
    if (len < 8 && net->read_pos[0] == 254)
1493
      break; // end of data
1494
    DBUG_PRINT("info",( "len: %lu  net->read_pos[5]: %d\n",
1495
			len, net->read_pos[5]));
1496
    if (!(ev= Log_event::read_log_event((const char*) net->read_pos + 1 ,
1497
                                        len - 1, &error_msg,
1498
                                        glob_description_event)))
1499
    {
1500
      error("Could not construct log event object: %s", error_msg);
1501
      DBUG_RETURN(ERROR_STOP);
1502
    }   
1503
    /*
1504
      If reading from a remote host, ensure the temp_buf for the
1505
      Log_event class is pointing to the incoming stream.
1506
    */
1507
    if (remote_opt)
1508
      ev->register_temp_buf((char*) net->read_pos + 1); 
1509
1510
    Log_event_type type= ev->get_type_code();
1511
    if (glob_description_event->binlog_version >= 3 ||
1512
        (type != LOAD_EVENT && type != CREATE_FILE_EVENT))
1513
    {
1514
      /*
1515
        If this is a Rotate event, maybe it's the end of the requested binlog;
1516
        in this case we are done (stop transfer).
1517
        This is suitable for binlogs, not relay logs (but for now we don't read
1518
        relay logs remotely because the server is not able to do that). If one
1519
        day we read relay logs remotely, then we will have a problem with the
1520
        detection below: relay logs contain Rotate events which are about the
1521
        binlogs, so which would trigger the end-detection below.
1522
      */
1523
      if (type == ROTATE_EVENT)
1524
      {
1525
        Rotate_log_event *rev= (Rotate_log_event *)ev;
1526
        /*
1527
          If this is a fake Rotate event, and not about our log, we can stop
1528
          transfer. If this a real Rotate event (so it's not about our log,
1529
          it's in our log describing the next log), we print it (because it's
1530
          part of our log) and then we will stop when we receive the fake one
1531
          soon.
1532
        */
1533
        if (rev->when == 0)
1534
        {
1535
          if (!to_last_remote_log)
1536
          {
1537
            if ((rev->ident_len != logname_len) ||
1538
                memcmp(rev->new_log_ident, logname, logname_len))
1539
            {
1540
              DBUG_RETURN(OK_CONTINUE);
1541
            }
1542
            /*
1543
              Otherwise, this is a fake Rotate for our log, at the very
1544
              beginning for sure. Skip it, because it was not in the original
1545
              log. If we are running with to_last_remote_log, we print it,
1546
              because it serves as a useful marker between binlogs then.
1547
            */
1548
            continue;
1549
          }
1550
          len= 1; // fake Rotate, so don't increment old_off
1551
        }
1552
      }
1553
      else if (type == FORMAT_DESCRIPTION_EVENT)
1554
      {
1555
        /*
1556
          This could be an fake Format_description_log_event that server
1557
          (5.0+) automatically sends to a slave on connect, before sending
1558
          a first event at the requested position.  If this is the case,
1559
          don't increment old_off. Real Format_description_log_event always
1560
          starts from BIN_LOG_HEADER_SIZE position.
1561
        */
1562
        if (old_off != BIN_LOG_HEADER_SIZE)
1563
          len= 1;         // fake event, don't increment old_off
1564
      }
1565
      Exit_status retval= process_event(print_event_info, ev, old_off, logname);
1566
      if (retval != OK_CONTINUE)
1567
        DBUG_RETURN(retval);
1568
    }
1569
    else
1570
    {
1571
      Load_log_event *le= (Load_log_event*)ev;
1572
      const char *old_fname= le->fname;
1573
      uint old_len= le->fname_len;
1574
      File file;
1575
      Exit_status retval;
1576
1577
      if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0)
1578
        DBUG_RETURN(ERROR_STOP);
1579
1580
      retval= process_event(print_event_info, ev, old_off, logname);
1581
      if (retval != OK_CONTINUE)
1582
      {
1583
        my_close(file,MYF(MY_WME));
1584
        DBUG_RETURN(retval);
1585
      }
1586
      retval= load_processor.load_old_format_file(net,old_fname,old_len,file);
1587
      my_close(file,MYF(MY_WME));
1588
      if (retval != OK_CONTINUE)
1589
        DBUG_RETURN(retval);
1590
    }
1591
    /*
1592
      Let's adjust offset for remote log as for local log to produce
1593
      similar text and to have --stop-position to work identically.
1594
    */
1595
    old_off+= len-1;
1596
  }
1597
1598
  DBUG_RETURN(OK_CONTINUE);
1599
}
1600
1601
1602
/**
1603
  Reads the @c Format_description_log_event from the beginning of a
1604
  local input file.
1605
1606
  The @c Format_description_log_event is only read if it is outside
1607
  the range specified with @c --start-position; otherwise, it will be
1608
  seen later.  If this is an old binlog, a fake @c
1609
  Format_description_event is created.  This also prints a @c
1610
  Format_description_log_event to the output, unless we reach the
1611
  --start-position range.  In this case, it is assumed that a @c
1612
  Format_description_log_event will be found when reading events the
1613
  usual way.
1614
1615
  @param file The file to which a @c Format_description_log_event will
1616
  be printed.
1617
1618
  @param[in,out] print_event_info Parameters and context state
1619
  determining how to print.
1620
1621
  @param[in] logname Name of input binlog.
1622
1623
  @retval ERROR_STOP An error occurred - the program should terminate.
1624
  @retval OK_CONTINUE No error, the program should continue.
1625
  @retval OK_STOP No error, but the end of the specified range of
1626
  events to process has been reached and the program should terminate.
1627
*/
1628
static Exit_status check_header(IO_CACHE* file,
1629
                                PRINT_EVENT_INFO *print_event_info,
1630
                                const char* logname)
1631
{
1632
  uchar header[BIN_LOG_HEADER_SIZE];
1633
  uchar buf[PROBE_HEADER_LEN];
1634
  my_off_t tmp_pos, pos;
1635
1636
  delete glob_description_event;
1637
  if (!(glob_description_event= new Format_description_log_event(3)))
1638
  {
1639
    error("Failed creating Format_description_log_event; out of memory?");
1640
    return ERROR_STOP;
1641
  }
1642
1643
  pos= my_b_tell(file);
1644
  my_b_seek(file, (my_off_t)0);
1645
  if (my_b_read(file, header, sizeof(header)))
1646
  {
1647
    error("Failed reading header; probably an empty file.");
1648
    return ERROR_STOP;
1649
  }
1650
  if (memcmp(header, BINLOG_MAGIC, sizeof(header)))
1651
  {
1652
    error("File is not a binary log file.");
1653
    return ERROR_STOP;
1654
  }
1655
1656
  /*
1657
    Imagine we are running with --start-position=1000. We still need
1658
    to know the binlog format's. So we still need to find, if there is
1659
    one, the Format_desc event, or to know if this is a 3.23
1660
    binlog. So we need to first read the first events of the log,
1661
    those around offset 4.  Even if we are reading a 3.23 binlog from
1662
    the start (no --start-position): we need to know the header length
1663
    (which is 13 in 3.23, 19 in 4.x) to be able to successfully print
1664
    the first event (Start_log_event_v3). So even in this case, we
1665
    need to "probe" the first bytes of the log *before* we do a real
1666
    read_log_event(). Because read_log_event() needs to know the
1667
    header's length to work fine.
1668
  */
1669
  for(;;)
1670
  {
1671
    tmp_pos= my_b_tell(file); /* should be 4 the first time */
1672
    if (my_b_read(file, buf, sizeof(buf)))
1673
    {
1674
      if (file->error)
1675
      {
1676
        error("Could not read entry at offset %llu: "
1677
              "Error in log format or read error.", (ulonglong)tmp_pos);
1678
        return ERROR_STOP;
1679
      }
1680
      /*
1681
        Otherwise this is just EOF : this log currently contains 0-2
1682
        events.  Maybe it's going to be filled in the next
1683
        milliseconds; then we are going to have a problem if this a
1684
        3.23 log (imagine we are locally reading a 3.23 binlog which
1685
        is being written presently): we won't know it in
1686
        read_log_event() and will fail().  Similar problems could
1687
        happen with hot relay logs if --start-position is used (but a
1688
        --start-position which is posterior to the current size of the log).
1689
        These are rare problems anyway (reading a hot log + when we
1690
        read the first events there are not all there yet + when we
1691
        read a bit later there are more events + using a strange
1692
        --start-position).
1693
      */
1694
      break;
1695
    }
1696
    else
1697
    {
1698
      DBUG_PRINT("info",("buf[EVENT_TYPE_OFFSET=%d]=%d",
1699
                         EVENT_TYPE_OFFSET, buf[EVENT_TYPE_OFFSET]));
1700
      /* always test for a Start_v3, even if no --start-position */
1701
      if (buf[EVENT_TYPE_OFFSET] == START_EVENT_V3)
1702
      {
1703
        /* This is 3.23 or 4.x */
1704
        if (uint4korr(buf + EVENT_LEN_OFFSET) < 
1705
            (LOG_EVENT_MINIMAL_HEADER_LEN + START_V3_HEADER_LEN))
1706
        {
1707
          /* This is 3.23 (format 1) */
1708
          delete glob_description_event;
1709
          if (!(glob_description_event= new Format_description_log_event(1)))
1710
          {
1711
            error("Failed creating Format_description_log_event; "
1712
                  "out of memory?");
1713
            return ERROR_STOP;
1714
          }
1715
        }
1716
        break;
1717
      }
1718
      else if (tmp_pos >= start_position)
1719
        break;
1720
      else if (buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT)
1721
      {
1722
        /* This is 5.0 */
1723
        Format_description_log_event *new_description_event;
1724
        my_b_seek(file, tmp_pos); /* seek back to event's start */
1725
        if (!(new_description_event= (Format_description_log_event*) 
1726
              Log_event::read_log_event(file, glob_description_event)))
1727
          /* EOF can't be hit here normally, so it's a real error */
1728
        {
1729
          error("Could not read a Format_description_log_event event at "
1730
                "offset %llu; this could be a log format error or read error.",
1731
                (ulonglong)tmp_pos);
1732
          return ERROR_STOP;
1733
        }
1734
        if (opt_base64_output_mode == BASE64_OUTPUT_AUTO
1735
            || opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
1736
        {
1737
          /*
1738
            process_event will delete *description_event and set it to
1739
            the new one, so we should not do it ourselves in this
1740
            case.
1741
          */
1742
          Exit_status retval= process_event(print_event_info,
1743
                                            new_description_event, tmp_pos,
1744
                                            logname);
1745
          if (retval != OK_CONTINUE)
1746
            return retval;
1747
        }
1748
        else
1749
        {
1750
          delete glob_description_event;
1751
          glob_description_event= new_description_event;
1752
        }
1753
        DBUG_PRINT("info",("Setting description_event"));
1754
      }
1755
      else if (buf[EVENT_TYPE_OFFSET] == ROTATE_EVENT)
1756
      {
1757
        Log_event *ev;
1758
        my_b_seek(file, tmp_pos); /* seek back to event's start */
1759
        if (!(ev= Log_event::read_log_event(file, glob_description_event)))
1760
        {
1761
          /* EOF can't be hit here normally, so it's a real error */
1762
          error("Could not read a Rotate_log_event event at offset %llu;"
1763
                " this could be a log format error or read error.",
1764
                (ulonglong)tmp_pos);
1765
          return ERROR_STOP;
1766
        }
1767
        delete ev;
1768
      }
1769
      else
1770
        break;
1771
    }
1772
  }
1773
  my_b_seek(file, pos);
1774
  return OK_CONTINUE;
1775
}
1776
1777
1778
/**
1779
  Reads a local binlog and prints the events it sees.
1780
1781
  @param[in] logname Name of input binlog.
1782
1783
  @param[in,out] print_event_info Parameters and context state
1784
  determining how to print.
1785
1786
  @retval ERROR_STOP An error occurred - the program should terminate.
1787
  @retval OK_CONTINUE No error, the program should continue.
1788
  @retval OK_STOP No error, but the end of the specified range of
1789
  events to process has been reached and the program should terminate.
1790
*/
1791
static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
1792
                                          const char* logname)
1793
{
1794
  File fd = -1;
1795
  IO_CACHE cache,*file= &cache;
1796
  uchar tmp_buff[BIN_LOG_HEADER_SIZE];
1797
  Exit_status retval= OK_CONTINUE;
1798
1799
  if (logname && strcmp(logname, "-") != 0)
1800
  {
1801
    /* read from normal file */
1802
    if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
1803
      return ERROR_STOP;
1804
    if (init_io_cache(file, fd, 0, READ_CACHE, start_position_mot, 0,
1805
		      MYF(MY_WME | MY_NABP)))
1806
    {
1807
      my_close(fd, MYF(MY_WME));
1808
      return ERROR_STOP;
1809
    }
1810
    if ((retval= check_header(file, print_event_info, logname)) != OK_CONTINUE)
1811
      goto end;
1812
  }
1813
  else
1814
  {
1815
    if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
1816
		      0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
1817
    {
1818
      error("Failed to init IO cache.");
1819
      return ERROR_STOP;
1820
    }
1821
    if ((retval= check_header(file, print_event_info, logname)) != OK_CONTINUE)
1822
      goto end;
1823
    if (start_position)
1824
    {
1825
      /* skip 'start_position' characters from stdin */
1826
      uchar buff[IO_SIZE];
1827
      my_off_t length,tmp;
1828
      for (length= start_position_mot ; length > 0 ; length-=tmp)
1829
      {
1830
	tmp=min(length,sizeof(buff));
1831
	if (my_b_read(file, buff, (uint) tmp))
1832
        {
1833
          error("Failed reading from file.");
1834
          goto err;
1835
        }
1836
      }
1837
    }
1838
  }
1839
1840
  if (!glob_description_event || !glob_description_event->is_valid())
1841
  {
1842
    error("Invalid Format_description log event; could be out of memory.");
1843
    goto err;
1844
  }
1845
1846
  if (!start_position && my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE))
1847
  {
1848
    error("Failed reading from file.");
1849
    goto err;
1850
  }
1851
  for (;;)
1852
  {
1853
    char llbuff[21];
1854
    my_off_t old_off = my_b_tell(file);
1855
1856
    Log_event* ev = Log_event::read_log_event(file, glob_description_event);
1857
    if (!ev)
1858
    {
1859
      /*
1860
        if binlog wasn't closed properly ("in use" flag is set) don't complain
1861
        about a corruption, but treat it as EOF and move to the next binlog.
1862
      */
1863
      if (glob_description_event->flags & LOG_EVENT_BINLOG_IN_USE_F)
1864
        file->error= 0;
1865
      else if (file->error)
1866
      {
1867
        error("Could not read entry at offset %s: "
1868
              "Error in log format or read error.",
1869
              llstr(old_off,llbuff));
1870
        goto err;
1871
      }
1872
      // file->error == 0 means EOF, that's OK, we break in this case
1873
      goto end;
1874
    }
1875
    if ((retval= process_event(print_event_info, ev, old_off, logname)) !=
1876
        OK_CONTINUE)
1877
      goto end;
1878
  }
1879
1880
  /* NOTREACHED */
1881
1882
err:
1883
  retval= ERROR_STOP;
1884
1885
end:
1886
  if (fd >= 0)
1887
    my_close(fd, MYF(MY_WME));
1888
  end_io_cache(file);
1889
  return retval;
1890
}
1891
1892
1893
int main(int argc, char** argv)
1894
{
1895
  char **defaults_argv;
1896
  Exit_status retval= OK_CONTINUE;
1897
  ulonglong save_stop_position;
1898
  MY_INIT(argv[0]);
1899
  DBUG_ENTER("main");
1900
  DBUG_PROCESS(argv[0]);
1901
1902
  init_time(); // for time functions
1903
1904
  parse_args(&argc, (char***)&argv);
1905
  defaults_argv=argv;
1906
1907
  if (!argc)
1908
  {
1909
    usage();
1910
    free_defaults(defaults_argv);
1911
    exit(1);
1912
  }
1913
1914
  if (opt_base64_output_mode == BASE64_OUTPUT_UNSPEC)
1915
    opt_base64_output_mode= BASE64_OUTPUT_AUTO;
1916
1917
  my_set_max_open_files(open_files_limit);
1918
1919
  MY_TMPDIR tmpdir;
1920
  tmpdir.list= 0;
1921
  if (!dirname_for_local_load)
1922
  {
1923
    if (init_tmpdir(&tmpdir, 0))
1924
      exit(1);
1925
    dirname_for_local_load= my_strdup(my_tmpdir(&tmpdir), MY_WME);
1926
  }
1927
1928
  if (load_processor.init())
1929
    exit(1);
1930
  if (dirname_for_local_load)
1931
    load_processor.init_by_dir_name(dirname_for_local_load);
1932
  else
1933
    load_processor.init_by_cur_dir();
1934
1935
  fprintf(result_file,
1936
	  "/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n");
1937
1938
  if (disable_log_bin)
1939
    fprintf(result_file,
1940
            "/*!32316 SET @OLD_SQL_LOG_BIN=@@SQL_LOG_BIN, SQL_LOG_BIN=0*/;\n");
1941
1942
  /*
1943
    In mysqlbinlog|mysql, don't want mysql to be disconnected after each
1944
    transaction (which would be the case with GLOBAL.COMPLETION_TYPE==2).
1945
  */
1946
  fprintf(result_file,
1947
          "/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,"
1948
          "COMPLETION_TYPE=0*/;\n");
1949
1950
  if (charset)
1951
    fprintf(result_file,
1952
            "\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
1953
            "\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
1954
            "\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"  
1955
            "\n/*!40101 SET NAMES %s */;\n", charset);
1956
1957
  for (save_stop_position= stop_position, stop_position= ~(my_off_t)0 ;
1958
       (--argc >= 0) ; )
1959
  {
1960
    if (argc == 0) // last log, --stop-position applies
1961
      stop_position= save_stop_position;
1962
    if ((retval= dump_log_entries(*argv++)) != OK_CONTINUE)
1963
      break;
1964
1965
    // For next log, --start-position does not apply
1966
    start_position= BIN_LOG_HEADER_SIZE;
1967
  }
1968
1969
  /*
1970
    Issue a ROLLBACK in case the last printed binlog was crashed and had half
1971
    of transaction.
1972
  */
1973
  fprintf(result_file,
1974
          "# End of log file\nROLLBACK /* added by mysqlbinlog */;\n"
1975
          "/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;\n");
1976
  if (disable_log_bin)
1977
    fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n");
1978
1979
  if (charset)
1980
    fprintf(result_file,
1981
            "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"
1982
            "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"
1983
            "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n");
1984
1985
  if (tmpdir.list)
1986
    free_tmpdir(&tmpdir);
1987
  if (result_file != stdout)
1988
    my_fclose(result_file, MYF(0));
1989
  cleanup();
1990
  free_defaults(defaults_argv);
1991
  my_free_open_file_info();
1992
  load_processor.destroy();
1993
  /* We cannot free DBUG, it is used in global destructors after exit(). */
1994
  my_end(my_end_arg | MY_DONT_FREE_DBUG);
1995
1996
  exit(retval == ERROR_STOP ? 1 : 0);
1997
  /* Keep compilers happy. */
1998
  DBUG_RETURN(retval == ERROR_STOP ? 1 : 0);
1999
}
2000
2001
/*
2002
  We must include this here as it's compiled with different options for
2003
  the server
2004
*/
2005
2006
#include "my_decimal.h"
2007
#include "decimal.c"
2008
#include "my_decimal.cc"
2009
#include "log_event.cc"
2010