~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzlebinlog.cc

  • Committer: Monty Taylor
  • Date: 2008-10-06 04:45:56 UTC
  • mfrom: (438.1.13 drizzle)
  • Revision ID: monty@inaugust.com-20081006044556-5urk8k3yhnnl3o1p
Merged in from trunk.

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