~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzlebinlog.cc

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