~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzlebinlog.cc

  • Committer: Monty Taylor
  • Date: 2008-08-02 00:06:32 UTC
  • mto: (236.1.42 codestyle)
  • mto: This revision was merged to the branch mainline in revision 261.
  • Revision ID: monty@inaugust.com-20080802000632-jsse0zdd9r6ic5ku
Actually turn gettext on...

Show diffs side-by-side

added added

removed removed

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