~linuxjedi/drizzle/trunk-bug-667053

« back to all changes in this revision

Viewing changes to client/mysqlbinlog.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#ifdef __NETWARE__
 
928
  {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.",
 
929
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
930
#endif
 
931
  {"base64-output", OPT_BASE64_OUTPUT_MODE,
 
932
   "Determine when the output statements should be base64-encoded BINLOG "
 
933
   "statements: 'never' disables it and works only for binlogs without "
 
934
   "row-based events; 'auto' is the default and prints base64 only when "
 
935
   "necessary (i.e., for row-based events and format description events); "
 
936
   "'always' prints base64 whenever possible. 'always' is for debugging "
 
937
   "only and should not be used in a production system. The default is "
 
938
   "'auto'. --base64-output is a short form for --base64-output=always."
 
939
   ,(uchar**) &opt_base64_output_mode_str,
 
940
   (uchar**) &opt_base64_output_mode_str,
 
941
   0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
942
  /*
 
943
    mysqlbinlog needs charsets knowledge, to be able to convert a charset
 
944
    number found in binlog to a charset name (to be able to print things
 
945
    like this:
 
946
    SET @`a`:=_cp850 0x4DFC6C6C6572 COLLATE `cp850_general_ci`;
 
947
  */
 
948
  {"character-sets-dir", OPT_CHARSETS_DIR,
 
949
   "Directory where character sets are.", (uchar**) &charsets_dir,
 
950
   (uchar**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
951
  {"database", 'd', "List entries for just this database (local log only).",
 
952
   (uchar**) &database, (uchar**) &database, 0, GET_STR_ALLOC, REQUIRED_ARG,
 
953
   0, 0, 0, 0, 0, 0},
 
954
#ifndef DBUG_OFF
 
955
  {"debug", '#', "Output debug log.", (uchar**) &default_dbug_option,
 
956
   (uchar**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
957
#endif
 
958
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .",
 
959
   (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0,
 
960
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
961
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
 
962
   (uchar**) &debug_info_flag, (uchar**) &debug_info_flag,
 
963
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
964
  {"disable-log-bin", 'D', "Disable binary log. This is useful, if you "
 
965
    "enabled --to-last-log and are sending the output to the same MySQL server. "
 
966
    "This way you could avoid an endless loop. You would also like to use it "
 
967
    "when restoring after a crash to avoid duplication of the statements you "
 
968
    "already have. NOTE: you will need a SUPER privilege to use this option.",
 
969
   (uchar**) &disable_log_bin, (uchar**) &disable_log_bin, 0, GET_BOOL,
 
970
   NO_ARG, 0, 0, 0, 0, 0, 0},
 
971
  {"force-if-open", 'F', "Force if binlog was not closed properly.",
 
972
   (uchar**) &force_if_open_opt, (uchar**) &force_if_open_opt, 0, GET_BOOL, NO_ARG,
 
973
   1, 0, 0, 0, 0, 0},
 
974
  {"force-read", 'f', "Force reading unknown binlog events.",
 
975
   (uchar**) &force_opt, (uchar**) &force_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
 
976
   0, 0},
 
977
  {"hexdump", 'H', "Augment output with hexadecimal and ASCII event dump.",
 
978
   (uchar**) &opt_hexdump, (uchar**) &opt_hexdump, 0, GET_BOOL, NO_ARG,
 
979
   0, 0, 0, 0, 0, 0},
 
980
  {"host", 'h', "Get the binlog from server.", (uchar**) &host, (uchar**) &host,
 
981
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
982
  {"local-load", 'l', "Prepare local temporary files for LOAD DATA INFILE in the specified directory.",
 
983
   (uchar**) &dirname_for_local_load, (uchar**) &dirname_for_local_load, 0,
 
984
   GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
985
  {"offset", 'o', "Skip the first N entries.", (uchar**) &offset, (uchar**) &offset,
 
986
   0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
987
  {"password", 'p', "Password to connect to remote server.",
 
988
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
989
  {"port", 'P', "Port number to use for connection or 0 for default to, in "
 
990
   "order of preference, my.cnf, $MYSQL_TCP_PORT, "
 
991
#if MYSQL_PORT_DEFAULT == 0
 
992
   "/etc/services, "
 
993
#endif
 
994
   "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
 
995
   (uchar**) &port, (uchar**) &port, 0, GET_INT, REQUIRED_ARG,
 
996
   0, 0, 0, 0, 0, 0},
 
997
  {"position", 'j', "Deprecated. Use --start-position instead.",
 
998
   (uchar**) &start_position, (uchar**) &start_position, 0, GET_ULL,
 
999
   REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE,
 
1000
   /* COM_BINLOG_DUMP accepts only 4 bytes for the position */
 
1001
   (ulonglong)(~(uint32)0), 0, 0, 0},
 
1002
  {"protocol", OPT_MYSQL_PROTOCOL,
 
1003
   "The protocol of connection (tcp,socket,pipe,memory).",
 
1004
   0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
1005
  {"read-from-remote-server", 'R', "Read binary logs from a MySQL server",
 
1006
   (uchar**) &remote_opt, (uchar**) &remote_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
 
1007
   0, 0},
 
1008
  {"result-file", 'r', "Direct output to a given file.", 0, 0, 0, GET_STR,
 
1009
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
1010
  {"server-id", OPT_SERVER_ID,
 
1011
   "Extract only binlog entries created by the server having the given id.",
 
1012
   (uchar**) &server_id, (uchar**) &server_id, 0, GET_ULONG,
 
1013
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
1014
  {"set-charset", OPT_SET_CHARSET,
 
1015
   "Add 'SET NAMES character_set' to the output.", (uchar**) &charset,
 
1016
   (uchar**) &charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
1017
  {"short-form", 's', "Just show regular queries: no extra info and no "
 
1018
   "row-based events. This is for testing only, and should not be used in "
 
1019
   "production systems. If you want to suppress base64-output, consider "
 
1020
   "using --base64-output=never instead.",
 
1021
   (uchar**) &short_form, (uchar**) &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
 
1022
   0, 0},
 
1023
  {"socket", 'S', "Socket file to use for connection.",
 
1024
   (uchar**) &sock, (uchar**) &sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 
 
1025
   0, 0},
 
1026
  {"start-datetime", OPT_START_DATETIME,
 
1027
   "Start reading the binlog at first event having a datetime equal or "
 
1028
   "posterior to the argument; the argument must be a date and time "
 
1029
   "in the local time zone, in any format accepted by the MySQL server "
 
1030
   "for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 "
 
1031
   "(you should probably use quotes for your shell to set it properly).",
 
1032
   (uchar**) &start_datetime_str, (uchar**) &start_datetime_str,
 
1033
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
1034
  {"start-position", OPT_START_POSITION,
 
1035
   "Start reading the binlog at position N. Applies to the first binlog "
 
1036
   "passed on the command line.",
 
1037
   (uchar**) &start_position, (uchar**) &start_position, 0, GET_ULL,
 
1038
   REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE,
 
1039
   /* COM_BINLOG_DUMP accepts only 4 bytes for the position */
 
1040
   (ulonglong)(~(uint32)0), 0, 0, 0},
 
1041
  {"stop-datetime", OPT_STOP_DATETIME,
 
1042
   "Stop reading the binlog at first event having a datetime equal or "
 
1043
   "posterior to the argument; the argument must be a date and time "
 
1044
   "in the local time zone, in any format accepted by the MySQL server "
 
1045
   "for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 "
 
1046
   "(you should probably use quotes for your shell to set it properly).",
 
1047
   (uchar**) &stop_datetime_str, (uchar**) &stop_datetime_str,
 
1048
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
1049
  {"stop-position", OPT_STOP_POSITION,
 
1050
   "Stop reading the binlog at position N. Applies to the last binlog "
 
1051
   "passed on the command line.",
 
1052
   (uchar**) &stop_position, (uchar**) &stop_position, 0, GET_ULL,
 
1053
   REQUIRED_ARG, (ulonglong)(~(my_off_t)0), BIN_LOG_HEADER_SIZE,
 
1054
   (ulonglong)(~(my_off_t)0), 0, 0, 0},
 
1055
  {"to-last-log", 't', "Requires -R. Will not stop at the end of the \
 
1056
requested binlog but rather continue printing until the end of the last \
 
1057
binlog of the MySQL server. If you send the output to the same MySQL server, \
 
1058
that may lead to an endless loop.",
 
1059
   (uchar**) &to_last_remote_log, (uchar**) &to_last_remote_log, 0, GET_BOOL,
 
1060
   NO_ARG, 0, 0, 0, 0, 0, 0},
 
1061
  {"user", 'u', "Connect to the remote server as username.",
 
1062
   (uchar**) &user, (uchar**) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0,
 
1063
   0, 0},
 
1064
  {"version", 'V', "Print version and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
 
1065
   0, 0, 0, 0, 0},
 
1066
  {"open_files_limit", OPT_OPEN_FILES_LIMIT,
 
1067
   "Used to reserve file descriptors for usage by this program",
 
1068
   (uchar**) &open_files_limit, (uchar**) &open_files_limit, 0, GET_ULONG,
 
1069
   REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0},
 
1070
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 
1071
};
 
1072
 
 
1073
 
 
1074
/**
 
1075
  Auxiliary function used by error() and warning().
 
1076
 
 
1077
  Prints the given text (normally "WARNING: " or "ERROR: "), followed
 
1078
  by the given vprintf-style string, followed by a newline.
 
1079
 
 
1080
  @param format Printf-style format string.
 
1081
  @param args List of arguments for the format string.
 
1082
  @param msg Text to print before the string.
 
1083
*/
 
1084
static void error_or_warning(const char *format, va_list args, const char *msg)
 
1085
{
 
1086
  fprintf(stderr, "%s: ", msg);
 
1087
  vfprintf(stderr, format, args);
 
1088
  fprintf(stderr, "\n");
 
1089
}
 
1090
 
 
1091
/**
 
1092
  Prints a message to stderr, prefixed with the text "ERROR: " and
 
1093
  suffixed with a newline.
 
1094
 
 
1095
  @param format Printf-style format string, followed by printf
 
1096
  varargs.
 
1097
*/
 
1098
static void error(const char *format,...)
 
1099
{
 
1100
  va_list args;
 
1101
  va_start(args, format);
 
1102
  error_or_warning(format, args, "ERROR");
 
1103
  va_end(args);
 
1104
}
 
1105
 
 
1106
 
 
1107
/**
 
1108
  This function is used in log_event.cc to report errors.
 
1109
 
 
1110
  @param format Printf-style format string, followed by printf
 
1111
  varargs.
 
1112
*/
 
1113
static void sql_print_error(const char *format,...)
 
1114
{
 
1115
  va_list args;
 
1116
  va_start(args, format);
 
1117
  error_or_warning(format, args, "ERROR");
 
1118
  va_end(args);
 
1119
}
 
1120
 
 
1121
/**
 
1122
  Prints a message to stderr, prefixed with the text "WARNING: " and
 
1123
  suffixed with a newline.
 
1124
 
 
1125
  @param format Printf-style format string, followed by printf
 
1126
  varargs.
 
1127
*/
 
1128
static void warning(const char *format,...)
 
1129
{
 
1130
  va_list args;
 
1131
  va_start(args, format);
 
1132
  error_or_warning(format, args, "WARNING");
 
1133
  va_end(args);
 
1134
}
 
1135
 
 
1136
/**
 
1137
  Frees memory for global variables in this file.
 
1138
*/
 
1139
static void cleanup()
 
1140
{
 
1141
  my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
 
1142
  my_free((char*) database, MYF(MY_ALLOW_ZERO_PTR));
 
1143
  my_free((char*) host, MYF(MY_ALLOW_ZERO_PTR));
 
1144
  my_free((char*) user, MYF(MY_ALLOW_ZERO_PTR));
 
1145
  my_free((char*) dirname_for_local_load, MYF(MY_ALLOW_ZERO_PTR));
 
1146
 
 
1147
  delete glob_description_event;
 
1148
  if (mysql)
 
1149
    mysql_close(mysql);
 
1150
}
 
1151
 
 
1152
#include <help_start.h>
 
1153
 
 
1154
static void print_version()
 
1155
{
 
1156
  printf("%s Ver 3.3 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE);
 
1157
  NETWARE_SET_SCREEN_MODE(1);
 
1158
}
 
1159
 
 
1160
 
 
1161
static void usage()
 
1162
{
 
1163
  print_version();
 
1164
  puts("By Monty and Sasha, for your professional use\n\
 
1165
This software comes with NO WARRANTY:  This is free software,\n\
 
1166
and you are welcome to modify and redistribute it under the GPL license\n");
 
1167
 
 
1168
  printf("\
 
1169
Dumps a MySQL binary log in a format usable for viewing or for piping to\n\
 
1170
the mysql command line client\n\n");
 
1171
  printf("Usage: %s [options] log-files\n", my_progname);
 
1172
  my_print_help(my_long_options);
 
1173
  my_print_variables(my_long_options);
 
1174
}
 
1175
 
 
1176
 
 
1177
static my_time_t convert_str_to_timestamp(const char* str)
 
1178
{
 
1179
  int was_cut;
 
1180
  MYSQL_TIME l_time;
 
1181
  long dummy_my_timezone;
 
1182
  my_bool dummy_in_dst_time_gap;
 
1183
  /* We require a total specification (date AND time) */
 
1184
  if (str_to_datetime(str, strlen(str), &l_time, 0, &was_cut) !=
 
1185
      MYSQL_TIMESTAMP_DATETIME || was_cut)
 
1186
  {
 
1187
    error("Incorrect date and time argument: %s", str);
 
1188
    exit(1);
 
1189
  }
 
1190
  /*
 
1191
    Note that Feb 30th, Apr 31st cause no error messages and are mapped to
 
1192
    the next existing day, like in mysqld. Maybe this could be changed when
 
1193
    mysqld is changed too (with its "strict" mode?).
 
1194
  */
 
1195
  return
 
1196
    my_system_gmt_sec(&l_time, &dummy_my_timezone, &dummy_in_dst_time_gap);
 
1197
}
 
1198
 
 
1199
#include <help_end.h>
 
1200
 
 
1201
extern "C" my_bool
 
1202
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
 
1203
               char *argument)
 
1204
{
 
1205
  bool tty_password=0;
 
1206
  switch (optid) {
 
1207
#ifdef __NETWARE__
 
1208
  case OPT_AUTO_CLOSE:
 
1209
    setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
 
1210
    break;
 
1211
#endif
 
1212
#ifndef DBUG_OFF
 
1213
  case '#':
 
1214
    DBUG_PUSH(argument ? argument : default_dbug_option);
 
1215
    break;
 
1216
#endif
 
1217
  case 'd':
 
1218
    one_database = 1;
 
1219
    break;
 
1220
  case 'p':
 
1221
    if (argument)
 
1222
    {
 
1223
      my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
 
1224
      char *start=argument;
 
1225
      pass= my_strdup(argument,MYF(MY_FAE));
 
1226
      while (*argument) *argument++= 'x';               /* Destroy argument */
 
1227
      if (*start)
 
1228
        start[1]=0;                             /* Cut length of argument */
 
1229
    }
 
1230
    else
 
1231
      tty_password=1;
 
1232
    break;
 
1233
  case 'r':
 
1234
    if (!(result_file = my_fopen(argument, O_WRONLY | O_BINARY, MYF(MY_WME))))
 
1235
      exit(1);
 
1236
    break;
 
1237
  case 'R':
 
1238
    remote_opt= 1;
 
1239
    break;
 
1240
  case OPT_MYSQL_PROTOCOL:
 
1241
    opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
 
1242
                                    opt->name);
 
1243
    break;
 
1244
  case OPT_START_DATETIME:
 
1245
    start_datetime= convert_str_to_timestamp(start_datetime_str);
 
1246
    break;
 
1247
  case OPT_STOP_DATETIME:
 
1248
    stop_datetime= convert_str_to_timestamp(stop_datetime_str);
 
1249
    break;
 
1250
  case OPT_BASE64_OUTPUT_MODE:
 
1251
    if (argument == NULL)
 
1252
      opt_base64_output_mode= BASE64_OUTPUT_ALWAYS;
 
1253
    else
 
1254
    {
 
1255
      opt_base64_output_mode= (enum_base64_output_mode)
 
1256
        (find_type_or_exit(argument, &base64_output_mode_typelib, opt->name)-1);
 
1257
    }
 
1258
    break;
 
1259
  case 'V':
 
1260
    print_version();
 
1261
    exit(0);
 
1262
  case '?':
 
1263
    usage();
 
1264
    exit(0);
 
1265
  }
 
1266
  if (tty_password)
 
1267
    pass= get_tty_password(NullS);
 
1268
 
 
1269
  return 0;
 
1270
}
 
1271
 
 
1272
 
 
1273
static int parse_args(int *argc, char*** argv)
 
1274
{
 
1275
  int ho_error;
 
1276
 
 
1277
  result_file = stdout;
 
1278
  load_defaults("my",load_default_groups,argc,argv);
 
1279
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
 
1280
    exit(ho_error);
 
1281
  if (debug_info_flag)
 
1282
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
 
1283
  if (debug_check_flag)
 
1284
    my_end_arg= MY_CHECK_ERROR;
 
1285
  return 0;
 
1286
}
 
1287
 
 
1288
 
 
1289
/**
 
1290
  Create and initialize the global mysql object, and connect to the
 
1291
  server.
 
1292
 
 
1293
  @retval ERROR_STOP An error occurred - the program should terminate.
 
1294
  @retval OK_CONTINUE No error, the program should continue.
 
1295
*/
 
1296
static Exit_status safe_connect()
 
1297
{
 
1298
  mysql= mysql_init(NULL);
 
1299
 
 
1300
  if (!mysql)
 
1301
  {
 
1302
    error("Failed on mysql_init.");
 
1303
    return ERROR_STOP;
 
1304
  }
 
1305
 
 
1306
  if (opt_protocol)
 
1307
    mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol);
 
1308
  if (!mysql_real_connect(mysql, host, user, pass, 0, port, sock, 0))
 
1309
  {
 
1310
    error("Failed on connect: %s", mysql_error(mysql));
 
1311
    return ERROR_STOP;
 
1312
  }
 
1313
  mysql->reconnect= 1;
 
1314
  return OK_CONTINUE;
 
1315
}
 
1316
 
 
1317
 
 
1318
/**
 
1319
  High-level function for dumping a named binlog.
 
1320
 
 
1321
  This function calls dump_remote_log_entries() or
 
1322
  dump_local_log_entries() to do the job.
 
1323
 
 
1324
  @param[in] logname Name of input binlog.
 
1325
 
 
1326
  @retval ERROR_STOP An error occurred - the program should terminate.
 
1327
  @retval OK_CONTINUE No error, the program should continue.
 
1328
  @retval OK_STOP No error, but the end of the specified range of
 
1329
  events to process has been reached and the program should terminate.
 
1330
*/
 
1331
static Exit_status dump_log_entries(const char* logname)
 
1332
{
 
1333
  Exit_status rc;
 
1334
  PRINT_EVENT_INFO print_event_info;
 
1335
 
 
1336
  if (!print_event_info.init_ok())
 
1337
    return ERROR_STOP;
 
1338
  /*
 
1339
     Set safe delimiter, to dump things
 
1340
     like CREATE PROCEDURE safely
 
1341
  */
 
1342
  fprintf(result_file, "DELIMITER /*!*/;\n");
 
1343
  strmov(print_event_info.delimiter, "/*!*/;");
 
1344
 
 
1345
  rc= (remote_opt ? dump_remote_log_entries(&print_event_info, logname) :
 
1346
       dump_local_log_entries(&print_event_info, logname));
 
1347
 
 
1348
  /* Set delimiter back to semicolon */
 
1349
  fprintf(result_file, "DELIMITER ;\n");
 
1350
  strmov(print_event_info.delimiter, ";");
 
1351
  return rc;
 
1352
}
 
1353
 
 
1354
 
 
1355
/**
 
1356
  When reading a remote binlog, this function is used to grab the
 
1357
  Format_description_log_event in the beginning of the stream.
 
1358
  
 
1359
  This is not as smart as check_header() (used for local log); it will
 
1360
  not work for a binlog which mixes format. TODO: fix this.
 
1361
 
 
1362
  @retval ERROR_STOP An error occurred - the program should terminate.
 
1363
  @retval OK_CONTINUE No error, the program should continue.
 
1364
*/
 
1365
static Exit_status check_master_version()
 
1366
{
 
1367
  MYSQL_RES* res = 0;
 
1368
  MYSQL_ROW row;
 
1369
  const char* version;
 
1370
 
 
1371
  if (mysql_query(mysql, "SELECT VERSION()") ||
 
1372
      !(res = mysql_store_result(mysql)))
 
1373
  {
 
1374
    error("Could not find server version: "
 
1375
          "Query failed when checking master version: %s", mysql_error(mysql));
 
1376
    return ERROR_STOP;
 
1377
  }
 
1378
  if (!(row = mysql_fetch_row(res)))
 
1379
  {
 
1380
    error("Could not find server version: "
 
1381
          "Master returned no rows for SELECT VERSION().");
 
1382
    goto err;
 
1383
  }
 
1384
 
 
1385
  if (!(version = row[0]))
 
1386
  {
 
1387
    error("Could not find server version: "
 
1388
          "Master reported NULL for the version.");
 
1389
    goto err;
 
1390
  }
 
1391
 
 
1392
  delete glob_description_event;
 
1393
  switch (*version) {
 
1394
  case '3':
 
1395
    glob_description_event= new Format_description_log_event(1);
 
1396
    break;
 
1397
  case '4':
 
1398
    glob_description_event= new Format_description_log_event(3);
 
1399
    break;
 
1400
  case '5':
 
1401
  case '6':
 
1402
    /*
 
1403
      The server is soon going to send us its Format_description log
 
1404
      event, unless it is a 5.0 server with 3.23 or 4.0 binlogs.
 
1405
      So we first assume that this is 4.0 (which is enough to read the
 
1406
      Format_desc event if one comes).
 
1407
    */
 
1408
    glob_description_event= new Format_description_log_event(3);
 
1409
    break;
 
1410
  default:
 
1411
    glob_description_event= NULL;
 
1412
    error("Could not find server version: "
 
1413
          "Master reported unrecognized MySQL version '%s'.", version);
 
1414
    goto err;
 
1415
  }
 
1416
  if (!glob_description_event || !glob_description_event->is_valid())
 
1417
  {
 
1418
    error("Failed creating Format_description_log_event; out of memory?");
 
1419
    goto err;
 
1420
  }
 
1421
 
 
1422
  mysql_free_result(res);
 
1423
  return OK_CONTINUE;
 
1424
 
 
1425
err:
 
1426
  mysql_free_result(res);
 
1427
  return ERROR_STOP;
 
1428
}
 
1429
 
 
1430
 
 
1431
/**
 
1432
  Requests binlog dump from a remote server and prints the events it
 
1433
  receives.
 
1434
 
 
1435
  @param[in,out] print_event_info Parameters and context state
 
1436
  determining how to print.
 
1437
  @param[in] logname Name of input binlog.
 
1438
 
 
1439
  @retval ERROR_STOP An error occurred - the program should terminate.
 
1440
  @retval OK_CONTINUE No error, the program should continue.
 
1441
  @retval OK_STOP No error, but the end of the specified range of
 
1442
  events to process has been reached and the program should terminate.
 
1443
*/
 
1444
static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
 
1445
                                           const char* logname)
 
1446
 
 
1447
{
 
1448
  uchar buf[128];
 
1449
  ulong len;
 
1450
  uint logname_len;
 
1451
  NET* net;
 
1452
  my_off_t old_off= start_position_mot;
 
1453
  char fname[FN_REFLEN+1];
 
1454
  Exit_status retval= OK_CONTINUE;
 
1455
  DBUG_ENTER("dump_remote_log_entries");
 
1456
 
 
1457
  /*
 
1458
    Even if we already read one binlog (case of >=2 binlogs on command line),
 
1459
    we cannot re-use the same connection as before, because it is now dead
 
1460
    (COM_BINLOG_DUMP kills the thread when it finishes).
 
1461
  */
 
1462
  if ((retval= safe_connect()) != OK_CONTINUE)
 
1463
    DBUG_RETURN(retval);
 
1464
  net= &mysql->net;
 
1465
 
 
1466
  if ((retval= check_master_version()) != OK_CONTINUE)
 
1467
    DBUG_RETURN(retval);
 
1468
 
 
1469
  /*
 
1470
    COM_BINLOG_DUMP accepts only 4 bytes for the position, so we are forced to
 
1471
    cast to uint32.
 
1472
  */
 
1473
  int4store(buf, (uint32)start_position);
 
1474
  int2store(buf + BIN_LOG_HEADER_SIZE, binlog_flags);
 
1475
 
 
1476
  size_t tlen = strlen(logname);
 
1477
  if (tlen > UINT_MAX) 
 
1478
  {
 
1479
    error("Log name too long.");
 
1480
    DBUG_RETURN(ERROR_STOP);
 
1481
  }
 
1482
  logname_len = (uint) tlen;
 
1483
  int4store(buf + 6, 0);
 
1484
  memcpy(buf + 10, logname, logname_len);
 
1485
  if (simple_command(mysql, COM_BINLOG_DUMP, buf, logname_len + 10, 1))
 
1486
  {
 
1487
    error("Got fatal error sending the log dump command.");
 
1488
    DBUG_RETURN(ERROR_STOP);
 
1489
  }
 
1490
 
 
1491
  for (;;)
 
1492
  {
 
1493
    const char *error_msg;
 
1494
    Log_event *ev;
 
1495
 
 
1496
    len= cli_safe_read(mysql);
 
1497
    if (len == packet_error)
 
1498
    {
 
1499
      error("Got error reading packet from server: %s", mysql_error(mysql));
 
1500
      DBUG_RETURN(ERROR_STOP);
 
1501
    }
 
1502
    if (len < 8 && net->read_pos[0] == 254)
 
1503
      break; // end of data
 
1504
    DBUG_PRINT("info",( "len: %lu  net->read_pos[5]: %d\n",
 
1505
                        len, net->read_pos[5]));
 
1506
    if (!(ev= Log_event::read_log_event((const char*) net->read_pos + 1 ,
 
1507
                                        len - 1, &error_msg,
 
1508
                                        glob_description_event)))
 
1509
    {
 
1510
      error("Could not construct log event object: %s", error_msg);
 
1511
      DBUG_RETURN(ERROR_STOP);
 
1512
    }   
 
1513
    /*
 
1514
      If reading from a remote host, ensure the temp_buf for the
 
1515
      Log_event class is pointing to the incoming stream.
 
1516
    */
 
1517
    if (remote_opt)
 
1518
      ev->register_temp_buf((char*) net->read_pos + 1); 
 
1519
 
 
1520
    Log_event_type type= ev->get_type_code();
 
1521
    if (glob_description_event->binlog_version >= 3 ||
 
1522
        (type != LOAD_EVENT && type != CREATE_FILE_EVENT))
 
1523
    {
 
1524
      /*
 
1525
        If this is a Rotate event, maybe it's the end of the requested binlog;
 
1526
        in this case we are done (stop transfer).
 
1527
        This is suitable for binlogs, not relay logs (but for now we don't read
 
1528
        relay logs remotely because the server is not able to do that). If one
 
1529
        day we read relay logs remotely, then we will have a problem with the
 
1530
        detection below: relay logs contain Rotate events which are about the
 
1531
        binlogs, so which would trigger the end-detection below.
 
1532
      */
 
1533
      if (type == ROTATE_EVENT)
 
1534
      {
 
1535
        Rotate_log_event *rev= (Rotate_log_event *)ev;
 
1536
        /*
 
1537
          If this is a fake Rotate event, and not about our log, we can stop
 
1538
          transfer. If this a real Rotate event (so it's not about our log,
 
1539
          it's in our log describing the next log), we print it (because it's
 
1540
          part of our log) and then we will stop when we receive the fake one
 
1541
          soon.
 
1542
        */
 
1543
        if (rev->when == 0)
 
1544
        {
 
1545
          if (!to_last_remote_log)
 
1546
          {
 
1547
            if ((rev->ident_len != logname_len) ||
 
1548
                memcmp(rev->new_log_ident, logname, logname_len))
 
1549
            {
 
1550
              DBUG_RETURN(OK_CONTINUE);
 
1551
            }
 
1552
            /*
 
1553
              Otherwise, this is a fake Rotate for our log, at the very
 
1554
              beginning for sure. Skip it, because it was not in the original
 
1555
              log. If we are running with to_last_remote_log, we print it,
 
1556
              because it serves as a useful marker between binlogs then.
 
1557
            */
 
1558
            continue;
 
1559
          }
 
1560
          len= 1; // fake Rotate, so don't increment old_off
 
1561
        }
 
1562
      }
 
1563
      else if (type == FORMAT_DESCRIPTION_EVENT)
 
1564
      {
 
1565
        /*
 
1566
          This could be an fake Format_description_log_event that server
 
1567
          (5.0+) automatically sends to a slave on connect, before sending
 
1568
          a first event at the requested position.  If this is the case,
 
1569
          don't increment old_off. Real Format_description_log_event always
 
1570
          starts from BIN_LOG_HEADER_SIZE position.
 
1571
        */
 
1572
        if (old_off != BIN_LOG_HEADER_SIZE)
 
1573
          len= 1;         // fake event, don't increment old_off
 
1574
      }
 
1575
      Exit_status retval= process_event(print_event_info, ev, old_off, logname);
 
1576
      if (retval != OK_CONTINUE)
 
1577
        DBUG_RETURN(retval);
 
1578
    }
 
1579
    else
 
1580
    {
 
1581
      Load_log_event *le= (Load_log_event*)ev;
 
1582
      const char *old_fname= le->fname;
 
1583
      uint old_len= le->fname_len;
 
1584
      File file;
 
1585
      Exit_status retval;
 
1586
 
 
1587
      if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0)
 
1588
        DBUG_RETURN(ERROR_STOP);
 
1589
 
 
1590
      retval= process_event(print_event_info, ev, old_off, logname);
 
1591
      if (retval != OK_CONTINUE)
 
1592
      {
 
1593
        my_close(file,MYF(MY_WME));
 
1594
        DBUG_RETURN(retval);
 
1595
      }
 
1596
      retval= load_processor.load_old_format_file(net,old_fname,old_len,file);
 
1597
      my_close(file,MYF(MY_WME));
 
1598
      if (retval != OK_CONTINUE)
 
1599
        DBUG_RETURN(retval);
 
1600
    }
 
1601
    /*
 
1602
      Let's adjust offset for remote log as for local log to produce
 
1603
      similar text and to have --stop-position to work identically.
 
1604
    */
 
1605
    old_off+= len-1;
 
1606
  }
 
1607
 
 
1608
  DBUG_RETURN(OK_CONTINUE);
 
1609
}
 
1610
 
 
1611
 
 
1612
/**
 
1613
  Reads the @c Format_description_log_event from the beginning of a
 
1614
  local input file.
 
1615
 
 
1616
  The @c Format_description_log_event is only read if it is outside
 
1617
  the range specified with @c --start-position; otherwise, it will be
 
1618
  seen later.  If this is an old binlog, a fake @c
 
1619
  Format_description_event is created.  This also prints a @c
 
1620
  Format_description_log_event to the output, unless we reach the
 
1621
  --start-position range.  In this case, it is assumed that a @c
 
1622
  Format_description_log_event will be found when reading events the
 
1623
  usual way.
 
1624
 
 
1625
  @param file The file to which a @c Format_description_log_event will
 
1626
  be printed.
 
1627
 
 
1628
  @param[in,out] print_event_info Parameters and context state
 
1629
  determining how to print.
 
1630
 
 
1631
  @param[in] logname Name of input binlog.
 
1632
 
 
1633
  @retval ERROR_STOP An error occurred - the program should terminate.
 
1634
  @retval OK_CONTINUE No error, the program should continue.
 
1635
  @retval OK_STOP No error, but the end of the specified range of
 
1636
  events to process has been reached and the program should terminate.
 
1637
*/
 
1638
static Exit_status check_header(IO_CACHE* file,
 
1639
                                PRINT_EVENT_INFO *print_event_info,
 
1640
                                const char* logname)
 
1641
{
 
1642
  uchar header[BIN_LOG_HEADER_SIZE];
 
1643
  uchar buf[PROBE_HEADER_LEN];
 
1644
  my_off_t tmp_pos, pos;
 
1645
 
 
1646
  delete glob_description_event;
 
1647
  if (!(glob_description_event= new Format_description_log_event(3)))
 
1648
  {
 
1649
    error("Failed creating Format_description_log_event; out of memory?");
 
1650
    return ERROR_STOP;
 
1651
  }
 
1652
 
 
1653
  pos= my_b_tell(file);
 
1654
  my_b_seek(file, (my_off_t)0);
 
1655
  if (my_b_read(file, header, sizeof(header)))
 
1656
  {
 
1657
    error("Failed reading header; probably an empty file.");
 
1658
    return ERROR_STOP;
 
1659
  }
 
1660
  if (memcmp(header, BINLOG_MAGIC, sizeof(header)))
 
1661
  {
 
1662
    error("File is not a binary log file.");
 
1663
    return ERROR_STOP;
 
1664
  }
 
1665
 
 
1666
  /*
 
1667
    Imagine we are running with --start-position=1000. We still need
 
1668
    to know the binlog format's. So we still need to find, if there is
 
1669
    one, the Format_desc event, or to know if this is a 3.23
 
1670
    binlog. So we need to first read the first events of the log,
 
1671
    those around offset 4.  Even if we are reading a 3.23 binlog from
 
1672
    the start (no --start-position): we need to know the header length
 
1673
    (which is 13 in 3.23, 19 in 4.x) to be able to successfully print
 
1674
    the first event (Start_log_event_v3). So even in this case, we
 
1675
    need to "probe" the first bytes of the log *before* we do a real
 
1676
    read_log_event(). Because read_log_event() needs to know the
 
1677
    header's length to work fine.
 
1678
  */
 
1679
  for(;;)
 
1680
  {
 
1681
    tmp_pos= my_b_tell(file); /* should be 4 the first time */
 
1682
    if (my_b_read(file, buf, sizeof(buf)))
 
1683
    {
 
1684
      if (file->error)
 
1685
      {
 
1686
        error("Could not read entry at offset %llu: "
 
1687
              "Error in log format or read error.", (ulonglong)tmp_pos);
 
1688
        return ERROR_STOP;
 
1689
      }
 
1690
      /*
 
1691
        Otherwise this is just EOF : this log currently contains 0-2
 
1692
        events.  Maybe it's going to be filled in the next
 
1693
        milliseconds; then we are going to have a problem if this a
 
1694
        3.23 log (imagine we are locally reading a 3.23 binlog which
 
1695
        is being written presently): we won't know it in
 
1696
        read_log_event() and will fail().  Similar problems could
 
1697
        happen with hot relay logs if --start-position is used (but a
 
1698
        --start-position which is posterior to the current size of the log).
 
1699
        These are rare problems anyway (reading a hot log + when we
 
1700
        read the first events there are not all there yet + when we
 
1701
        read a bit later there are more events + using a strange
 
1702
        --start-position).
 
1703
      */
 
1704
      break;
 
1705
    }
 
1706
    else
 
1707
    {
 
1708
      DBUG_PRINT("info",("buf[EVENT_TYPE_OFFSET=%d]=%d",
 
1709
                         EVENT_TYPE_OFFSET, buf[EVENT_TYPE_OFFSET]));
 
1710
      /* always test for a Start_v3, even if no --start-position */
 
1711
      if (buf[EVENT_TYPE_OFFSET] == START_EVENT_V3)
 
1712
      {
 
1713
        /* This is 3.23 or 4.x */
 
1714
        if (uint4korr(buf + EVENT_LEN_OFFSET) < 
 
1715
            (LOG_EVENT_MINIMAL_HEADER_LEN + START_V3_HEADER_LEN))
 
1716
        {
 
1717
          /* This is 3.23 (format 1) */
 
1718
          delete glob_description_event;
 
1719
          if (!(glob_description_event= new Format_description_log_event(1)))
 
1720
          {
 
1721
            error("Failed creating Format_description_log_event; "
 
1722
                  "out of memory?");
 
1723
            return ERROR_STOP;
 
1724
          }
 
1725
        }
 
1726
        break;
 
1727
      }
 
1728
      else if (tmp_pos >= start_position)
 
1729
        break;
 
1730
      else if (buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT)
 
1731
      {
 
1732
        /* This is 5.0 */
 
1733
        Format_description_log_event *new_description_event;
 
1734
        my_b_seek(file, tmp_pos); /* seek back to event's start */
 
1735
        if (!(new_description_event= (Format_description_log_event*) 
 
1736
              Log_event::read_log_event(file, glob_description_event)))
 
1737
          /* EOF can't be hit here normally, so it's a real error */
 
1738
        {
 
1739
          error("Could not read a Format_description_log_event event at "
 
1740
                "offset %llu; this could be a log format error or read error.",
 
1741
                (ulonglong)tmp_pos);
 
1742
          return ERROR_STOP;
 
1743
        }
 
1744
        if (opt_base64_output_mode == BASE64_OUTPUT_AUTO
 
1745
            || opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
 
1746
        {
 
1747
          /*
 
1748
            process_event will delete *description_event and set it to
 
1749
            the new one, so we should not do it ourselves in this
 
1750
            case.
 
1751
          */
 
1752
          Exit_status retval= process_event(print_event_info,
 
1753
                                            new_description_event, tmp_pos,
 
1754
                                            logname);
 
1755
          if (retval != OK_CONTINUE)
 
1756
            return retval;
 
1757
        }
 
1758
        else
 
1759
        {
 
1760
          delete glob_description_event;
 
1761
          glob_description_event= new_description_event;
 
1762
        }
 
1763
        DBUG_PRINT("info",("Setting description_event"));
 
1764
      }
 
1765
      else if (buf[EVENT_TYPE_OFFSET] == ROTATE_EVENT)
 
1766
      {
 
1767
        Log_event *ev;
 
1768
        my_b_seek(file, tmp_pos); /* seek back to event's start */
 
1769
        if (!(ev= Log_event::read_log_event(file, glob_description_event)))
 
1770
        {
 
1771
          /* EOF can't be hit here normally, so it's a real error */
 
1772
          error("Could not read a Rotate_log_event event at offset %llu;"
 
1773
                " this could be a log format error or read error.",
 
1774
                (ulonglong)tmp_pos);
 
1775
          return ERROR_STOP;
 
1776
        }
 
1777
        delete ev;
 
1778
      }
 
1779
      else
 
1780
        break;
 
1781
    }
 
1782
  }
 
1783
  my_b_seek(file, pos);
 
1784
  return OK_CONTINUE;
 
1785
}
 
1786
 
 
1787
 
 
1788
/**
 
1789
  Reads a local binlog and prints the events it sees.
 
1790
 
 
1791
  @param[in] logname Name of input binlog.
 
1792
 
 
1793
  @param[in,out] print_event_info Parameters and context state
 
1794
  determining how to print.
 
1795
 
 
1796
  @retval ERROR_STOP An error occurred - the program should terminate.
 
1797
  @retval OK_CONTINUE No error, the program should continue.
 
1798
  @retval OK_STOP No error, but the end of the specified range of
 
1799
  events to process has been reached and the program should terminate.
 
1800
*/
 
1801
static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
 
1802
                                          const char* logname)
 
1803
{
 
1804
  File fd = -1;
 
1805
  IO_CACHE cache,*file= &cache;
 
1806
  uchar tmp_buff[BIN_LOG_HEADER_SIZE];
 
1807
  Exit_status retval= OK_CONTINUE;
 
1808
 
 
1809
  if (logname && strcmp(logname, "-") != 0)
 
1810
  {
 
1811
    /* read from normal file */
 
1812
    if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
 
1813
      return ERROR_STOP;
 
1814
    if (init_io_cache(file, fd, 0, READ_CACHE, start_position_mot, 0,
 
1815
                      MYF(MY_WME | MY_NABP)))
 
1816
    {
 
1817
      my_close(fd, MYF(MY_WME));
 
1818
      return ERROR_STOP;
 
1819
    }
 
1820
    if ((retval= check_header(file, print_event_info, logname)) != OK_CONTINUE)
 
1821
      goto end;
 
1822
  }
 
1823
  else
 
1824
  {
 
1825
    /* read from stdin */
 
1826
    /*
 
1827
      Windows opens stdin in text mode by default. Certain characters
 
1828
      such as CTRL-Z are interpeted as events and the read() method
 
1829
      will stop. CTRL-Z is the EOF marker in Windows. to get past this
 
1830
      you have to open stdin in binary mode. Setmode() is used to set
 
1831
      stdin in binary mode. Errors on setting this mode result in 
 
1832
      halting the function and printing an error message to stderr.
 
1833
    */
 
1834
#if defined (__WIN__) || (_WIN64)
 
1835
    if (_setmode(fileno(stdin), O_BINARY) == -1)
 
1836
    {
 
1837
      error("Could not set binary mode on stdin.");
 
1838
      return ERROR_STOP;
 
1839
    }
 
1840
#endif 
 
1841
    if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
 
1842
                      0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
 
1843
    {
 
1844
      error("Failed to init IO cache.");
 
1845
      return ERROR_STOP;
 
1846
    }
 
1847
    if ((retval= check_header(file, print_event_info, logname)) != OK_CONTINUE)
 
1848
      goto end;
 
1849
    if (start_position)
 
1850
    {
 
1851
      /* skip 'start_position' characters from stdin */
 
1852
      uchar buff[IO_SIZE];
 
1853
      my_off_t length,tmp;
 
1854
      for (length= start_position_mot ; length > 0 ; length-=tmp)
 
1855
      {
 
1856
        tmp=min(length,sizeof(buff));
 
1857
        if (my_b_read(file, buff, (uint) tmp))
 
1858
        {
 
1859
          error("Failed reading from file.");
 
1860
          goto err;
 
1861
        }
 
1862
      }
 
1863
    }
 
1864
  }
 
1865
 
 
1866
  if (!glob_description_event || !glob_description_event->is_valid())
 
1867
  {
 
1868
    error("Invalid Format_description log event; could be out of memory.");
 
1869
    goto err;
 
1870
  }
 
1871
 
 
1872
  if (!start_position && my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE))
 
1873
  {
 
1874
    error("Failed reading from file.");
 
1875
    goto err;
 
1876
  }
 
1877
  for (;;)
 
1878
  {
 
1879
    char llbuff[21];
 
1880
    my_off_t old_off = my_b_tell(file);
 
1881
 
 
1882
    Log_event* ev = Log_event::read_log_event(file, glob_description_event);
 
1883
    if (!ev)
 
1884
    {
 
1885
      /*
 
1886
        if binlog wasn't closed properly ("in use" flag is set) don't complain
 
1887
        about a corruption, but treat it as EOF and move to the next binlog.
 
1888
      */
 
1889
      if (glob_description_event->flags & LOG_EVENT_BINLOG_IN_USE_F)
 
1890
        file->error= 0;
 
1891
      else if (file->error)
 
1892
      {
 
1893
        error("Could not read entry at offset %s: "
 
1894
              "Error in log format or read error.",
 
1895
              llstr(old_off,llbuff));
 
1896
        goto err;
 
1897
      }
 
1898
      // file->error == 0 means EOF, that's OK, we break in this case
 
1899
      goto end;
 
1900
    }
 
1901
    if ((retval= process_event(print_event_info, ev, old_off, logname)) !=
 
1902
        OK_CONTINUE)
 
1903
      goto end;
 
1904
  }
 
1905
 
 
1906
  /* NOTREACHED */
 
1907
 
 
1908
err:
 
1909
  retval= ERROR_STOP;
 
1910
 
 
1911
end:
 
1912
  if (fd >= 0)
 
1913
    my_close(fd, MYF(MY_WME));
 
1914
  end_io_cache(file);
 
1915
  return retval;
 
1916
}
 
1917
 
 
1918
 
 
1919
int main(int argc, char** argv)
 
1920
{
 
1921
  char **defaults_argv;
 
1922
  Exit_status retval= OK_CONTINUE;
 
1923
  ulonglong save_stop_position;
 
1924
  MY_INIT(argv[0]);
 
1925
  DBUG_ENTER("main");
 
1926
  DBUG_PROCESS(argv[0]);
 
1927
 
 
1928
  init_time(); // for time functions
 
1929
 
 
1930
  parse_args(&argc, (char***)&argv);
 
1931
  defaults_argv=argv;
 
1932
 
 
1933
  if (!argc)
 
1934
  {
 
1935
    usage();
 
1936
    free_defaults(defaults_argv);
 
1937
    exit(1);
 
1938
  }
 
1939
 
 
1940
  if (opt_base64_output_mode == BASE64_OUTPUT_UNSPEC)
 
1941
    opt_base64_output_mode= BASE64_OUTPUT_AUTO;
 
1942
 
 
1943
  my_set_max_open_files(open_files_limit);
 
1944
 
 
1945
  MY_TMPDIR tmpdir;
 
1946
  tmpdir.list= 0;
 
1947
  if (!dirname_for_local_load)
 
1948
  {
 
1949
    if (init_tmpdir(&tmpdir, 0))
 
1950
      exit(1);
 
1951
    dirname_for_local_load= my_strdup(my_tmpdir(&tmpdir), MY_WME);
 
1952
  }
 
1953
 
 
1954
  if (load_processor.init())
 
1955
    exit(1);
 
1956
  if (dirname_for_local_load)
 
1957
    load_processor.init_by_dir_name(dirname_for_local_load);
 
1958
  else
 
1959
    load_processor.init_by_cur_dir();
 
1960
 
 
1961
  fprintf(result_file,
 
1962
          "/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n");
 
1963
 
 
1964
  if (disable_log_bin)
 
1965
    fprintf(result_file,
 
1966
            "/*!32316 SET @OLD_SQL_LOG_BIN=@@SQL_LOG_BIN, SQL_LOG_BIN=0*/;\n");
 
1967
 
 
1968
  /*
 
1969
    In mysqlbinlog|mysql, don't want mysql to be disconnected after each
 
1970
    transaction (which would be the case with GLOBAL.COMPLETION_TYPE==2).
 
1971
  */
 
1972
  fprintf(result_file,
 
1973
          "/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,"
 
1974
          "COMPLETION_TYPE=0*/;\n");
 
1975
 
 
1976
  if (charset)
 
1977
    fprintf(result_file,
 
1978
            "\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
 
1979
            "\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
 
1980
            "\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"  
 
1981
            "\n/*!40101 SET NAMES %s */;\n", charset);
 
1982
 
 
1983
  for (save_stop_position= stop_position, stop_position= ~(my_off_t)0 ;
 
1984
       (--argc >= 0) ; )
 
1985
  {
 
1986
    if (argc == 0) // last log, --stop-position applies
 
1987
      stop_position= save_stop_position;
 
1988
    if ((retval= dump_log_entries(*argv++)) != OK_CONTINUE)
 
1989
      break;
 
1990
 
 
1991
    // For next log, --start-position does not apply
 
1992
    start_position= BIN_LOG_HEADER_SIZE;
 
1993
  }
 
1994
 
 
1995
  /*
 
1996
    Issue a ROLLBACK in case the last printed binlog was crashed and had half
 
1997
    of transaction.
 
1998
  */
 
1999
  fprintf(result_file,
 
2000
          "# End of log file\nROLLBACK /* added by mysqlbinlog */;\n"
 
2001
          "/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;\n");
 
2002
  if (disable_log_bin)
 
2003
    fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n");
 
2004
 
 
2005
  if (charset)
 
2006
    fprintf(result_file,
 
2007
            "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"
 
2008
            "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"
 
2009
            "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n");
 
2010
 
 
2011
  if (tmpdir.list)
 
2012
    free_tmpdir(&tmpdir);
 
2013
  if (result_file != stdout)
 
2014
    my_fclose(result_file, MYF(0));
 
2015
  cleanup();
 
2016
  free_defaults(defaults_argv);
 
2017
  my_free_open_file_info();
 
2018
  load_processor.destroy();
 
2019
  /* We cannot free DBUG, it is used in global destructors after exit(). */
 
2020
  my_end(my_end_arg | MY_DONT_FREE_DBUG);
 
2021
 
 
2022
  exit(retval == ERROR_STOP ? 1 : 0);
 
2023
  /* Keep compilers happy. */
 
2024
  DBUG_RETURN(retval == ERROR_STOP ? 1 : 0);
 
2025
}
 
2026
 
 
2027
/*
 
2028
  We must include this here as it's compiled with different options for
 
2029
  the server
 
2030
*/
 
2031
 
 
2032
#include "my_decimal.h"
 
2033
#include "decimal.c"
 
2034
#include "my_decimal.cc"
 
2035
#include "log_event.cc"
 
2036