~drizzle-trunk/drizzle/development

206.3.1 by Patrick Galbraith
Most everything working with client rename
1
/* Copyright (C) 2001-2004 DRIZZLE AB
1 by brian
clean slate
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
206.3.1 by Patrick Galbraith
Most everything working with client rename
16
/*
1 by brian
clean slate
17
18
   TODO: print the catalog (some USE catalog.db ????).
19
206.3.1 by Patrick Galbraith
Most everything working with client rename
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.
1 by brian
clean slate
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
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
31
#define DRIZZLE_CLIENT
32
#undef DRIZZLE_SERVER
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
33
34
#include <map>
35
383.1.17 by Brian Aker
Cleanup of time code (moved into mysys)
36
#include <mysys/my_time.h>
212.5.39 by Monty Taylor
Phew. Moved my_base and my_global.
37
#include <drizzled/global.h>
212.5.13 by Monty Taylor
Moved my_sys/my_pthread/my_nosys and mysys_err to mysys.
38
#include <mysys/my_sys.h>
212.5.18 by Monty Taylor
Moved m_ctype, m_string and my_bitmap. Removed t_ctype.
39
#include <mystrings/m_string.h>
212.5.25 by Monty Taylor
Moved drizzle.h to libdrizzle.
40
#include <libdrizzle/drizzle.h>
212.5.41 by Monty Taylor
Moved errmsg.h.
41
#include <libdrizzle/errmsg.h>
212.5.21 by Monty Taylor
Moved my_getopt.h
42
#include <mysys/my_getopt.h>
1 by brian
clean slate
43
/* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */
212.5.45 by Monty Taylor
Removed excess AM_CPPFLAGS from the tree. Now the only thing that should be in the include path should be -I${top_srcdir} and -I${top_builddir}w
44
#include <drizzled/log_event.h>
212.5.31 by Monty Taylor
Moved sql_common.h and my_time.h to libdrizzle.
45
#include <libdrizzle/sql_common.h>
1 by brian
clean slate
46
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
47
using namespace std;
77.3.12 by Monty Taylor
Moved drizzlebinlog to binlog subdir of server. Eventually lets put
48
49
enum options_drizzlebinlog
50
{
51
  OPT_CHARSETS_DIR=256, OPT_BASE64_OUTPUT_MODE,
206.3.1 by Patrick Galbraith
Most everything working with client rename
52
  OPT_DEBUG_CHECK, OPT_DEBUG_INFO, OPT_DRIZZLE_PROTOCOL,
77.3.12 by Monty Taylor
Moved drizzlebinlog to binlog subdir of server. Eventually lets put
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
206.3.1 by Patrick Galbraith
Most everything working with client rename
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)
1 by brian
clean slate
63
64
char server_version[SERVER_VERSION_LENGTH];
297 by Brian Aker
Final ulong cleanup in clients
65
uint32_t server_id = 0;
1 by brian
clean slate
66
67
// needed by net_serv.c
297 by Brian Aker
Final ulong cleanup in clients
68
uint32_t bytes_sent = 0L, bytes_received = 0L;
69
uint32_t drizzled_net_retry_count = 10L;
70
uint32_t open_files_limit;
206.3.1 by Patrick Galbraith
Most everything working with client rename
71
uint test_flags = 0;
1 by brian
clean slate
72
static uint opt_protocol= 0;
73
static FILE *result_file;
74
206.3.1 by Patrick Galbraith
Most everything working with client rename
75
static const char *load_default_groups[]= { "drizzlebinlog","client",0 };
1 by brian
clean slate
76
212.5.26 by Monty Taylor
Removed my_attribute. Renaming __attribute__((format(x,y,z))) to ATTRIBUTE_FORMAT(x,y,z) is retarded. So we don't do it anymore.
77
static void error(const char *format, ...) __attribute__((format(printf, 1, 2)));
78
static void warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
1 by brian
clean slate
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", NullS};
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= NullS;
88
static const char* database= 0;
143 by Brian Aker
Bool cleanup.
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;
151 by Brian Aker
Ulonglong to uint64_t
92
static uint64_t offset = 0;
1 by brian
clean slate
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
151 by Brian Aker
Ulonglong to uint64_t
101
static uint64_t start_position, stop_position;
1 by brian
clean slate
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;
151 by Brian Aker
Ulonglong to uint64_t
107
static uint64_t rec_count= 0;
206.3.1 by Patrick Galbraith
Most everything working with client rename
108
static short binlog_flags = 0;
109
static DRIZZLE *drizzle= NULL;
1 by brian
clean slate
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.
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
148
    We add name of this file to file_names map using its file_id as index.
1 by brian
clean slate
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
  };
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
160
161
  map<unsigned int, File_name_record *> file_names;
1 by brian
clean slate
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
      {
206.3.1 by Patrick Galbraith
Most everything working with client rename
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;
1 by brian
clean slate
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, NullS) -
206.3.1 by Patrick Galbraith
Most everything working with client rename
199
          target_dir_name);
1 by brian
clean slate
200
    }
201
  void init_by_cur_dir()
202
    {
203
      if (my_getwd(target_dir_name,sizeof(target_dir_name),MYF(MY_WME)))
206.3.1 by Patrick Galbraith
Most everything working with client rename
204
  exit(1);
1 by brian
clean slate
205
      target_dir_name_len= strlen(target_dir_name);
206
    }
207
  void destroy()
208
  {
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
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++)
1 by brian
clean slate
212
    {
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
213
      File_name_record *record_to_delete = file_names[i->first];
214
      if (record_to_delete->fname)
1 by brian
clean slate
215
      {
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
216
        free(record_to_delete->fname);
217
        delete record_to_delete->event;
1 by brian
clean slate
218
      }
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
219
      file_names.erase(i->first);
1 by brian
clean slate
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
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
242
      if ((ptr= file_names[file_id]))
243
      {
244
        file_names.erase(file_id);
245
      }
246
      return ptr->event;
1 by brian
clean slate
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;
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
267
      char *res= NULL;
1 by brian
clean slate
268
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
269
      if ((ptr= file_names[file_id]))
1 by brian
clean slate
270
      {
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
271
        if (ptr->event != NULL)
272
        {
273
          res= ptr->fname;
274
          file_names.erase(file_id);
275
        }
1 by brian
clean slate
276
      }
277
      return res;
278
    }
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
279
1 by brian
clean slate
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,
206.3.1 by Patrick Galbraith
Most everything working with client rename
304
               char *filename)
1 by brian
clean slate
305
{
306
  uint len;
307
  char *tail;
308
  File file;
206.3.1 by Patrick Galbraith
Most everything working with client rename
309
1 by brian
clean slate
310
  fn_format(filename, le->fname, target_dir_name, "", MY_REPLACE_DIR);
311
  len= strlen(filename);
312
  tail= filename + len;
206.3.1 by Patrick Galbraith
Most everything working with client rename
313
1 by brian
clean slate
314
  if ((file= create_unique_file(filename,tail)) < 0)
315
  {
316
    error("Could not construct local filename %s.",filename);
317
    return -1;
318
  }
206.3.1 by Patrick Galbraith
Most everything working with client rename
319
1 by brian
clean slate
320
  le->set_fname_outside_temp_buf(filename,len+strlen(tail));
206.3.1 by Patrick Galbraith
Most everything working with client rename
321
1 by brian
clean slate
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
  }
206.3.1 by Patrick Galbraith
Most everything working with client rename
354
1 by brian
clean slate
355
  for (;;)
356
  {
297 by Brian Aker
Final ulong cleanup in clients
357
    uint32_t packet_len = my_net_read(net);
1 by brian
clean slate
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
      /*
206.3.1 by Patrick Galbraith
Most everything working with client rename
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
1 by brian
clean slate
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
    }
206.3.1 by Patrick Galbraith
Most everything working with client rename
377
1 by brian
clean slate
378
    if (packet_len > UINT_MAX)
379
    {
380
      error("Illegal length of packet read from net.");
381
      return ERROR_STOP;
382
    }
206.3.1 by Patrick Galbraith
Most everything working with client rename
383
    if (my_write(file, (uchar*) net->read_pos,
384
     (uint) packet_len, MYF(MY_WME|MY_NABP)))
1 by brian
clean slate
385
      return ERROR_STOP;
386
  }
206.3.1 by Patrick Galbraith
Most everything working with client rename
387
1 by brian
clean slate
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;
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
422
  File_name_record *rec;
142.1.2 by Patrick
All DBUG_x removed from client/
423
1 by brian
clean slate
424
425
  if (!(fname= (char*) my_malloc(full_len,MYF(MY_WME))))
426
  {
427
    error("Out of memory.");
428
    delete ce;
142.1.2 by Patrick
All DBUG_x removed from client/
429
    return(ERROR_STOP);
1 by brian
clean slate
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;
171.1.1 by Patrick Galbraith
Dar, I forgot to commit this earlier.
436
  ptr+= sprintf(ptr, "-%x", file_id);
1 by brian
clean slate
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;
142.1.2 by Patrick
All DBUG_x removed from client/
443
    return(ERROR_STOP);
1 by brian
clean slate
444
  }
445
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
446
  rec= (File_name_record *)malloc(sizeof(File_name_record));
447
  rec->fname= fname;
448
  rec->event= ce;
1 by brian
clean slate
449
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
450
  file_names[file_id]= rec;
1 by brian
clean slate
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
  }
142.1.2 by Patrick
All DBUG_x removed from client/
465
  return(retval);
1 by brian
clean slate
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
{
142.1.2 by Patrick
All DBUG_x removed from client/
530
373.1.4 by Monty Taylor
Replaced DYNAMIC_ARRAY with std::map in drizzlebinlog.
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
  }
1 by brian
clean slate
538
539
  if (fname)
540
  {
541
    File file;
542
    Exit_status retval= OK_CONTINUE;
543
    if (((file= my_open(fname,
206.3.1 by Patrick Galbraith
Most everything working with client rename
544
      O_APPEND|O_BINARY|O_WRONLY,MYF(MY_WME))) < 0))
1 by brian
clean slate
545
    {
546
      error("Failed opening file %s", fname);
142.1.2 by Patrick
All DBUG_x removed from client/
547
      return(ERROR_STOP);
1 by brian
clean slate
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
    }
142.1.2 by Patrick
All DBUG_x removed from client/
559
    return(retval);
1 by brian
clean slate
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);
142.1.2 by Patrick
All DBUG_x removed from client/
569
  return(OK_CONTINUE);
1 by brian
clean slate
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
206.3.1 by Patrick Galbraith
Most everything working with client rename
578
  consumed by the drizzle client, which requires Unix path.
1 by brian
clean slate
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;
142.1.2 by Patrick
All DBUG_x removed from client/
640
1 by brian
clean slate
641
642
  /* Write header and base64 output to cache */
163 by Brian Aker
Merge Monty's code.
643
  ev->print_header(head, print_event_info, false);
644
  ev->print_base64(body, print_event_info, false);
1 by brian
clean slate
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.");
142.1.2 by Patrick
All DBUG_x removed from client/
651
    return(ERROR_STOP);
1 by brian
clean slate
652
  }
142.1.2 by Patrick
All DBUG_x removed from client/
653
  return(OK_CONTINUE);
1 by brian
clean slate
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();
142.1.2 by Patrick
All DBUG_x removed from client/
682
1 by brian
clean slate
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
      /*
206.3.1 by Patrick Galbraith
Most everything working with client rename
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.
1 by brian
clean slate
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
163 by Brian Aker
Merge Monty's code.
763
        ce->print(result_file, print_event_info, true);
1 by brian
clean slate
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
      /*
206.3.1 by Patrick Galbraith
Most everything working with client rename
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.
1 by brian
clean slate
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);
206.3.1 by Patrick Galbraith
Most everything working with client rename
808
  ce->print(result_file, print_event_info, true);
809
  my_free((char*)ce->fname,MYF(MY_WME));
810
  delete ce;
1 by brian
clean slate
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. "
206.3.1 by Patrick Galbraith
Most everything working with client rename
835
              "Most probably, drizzled is still writing it, or it crashed. "
1 by brian
clean slate
836
              "Rerun with --force-if-open to ignore this problem.", logname);
142.1.2 by Patrick
All DBUG_x removed from client/
837
        return(ERROR_STOP);
1 by brian
clean slate
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)
206.3.1 by Patrick Galbraith
Most everything working with client rename
864
  my_free(fname, MYF(MY_WME));
1 by brian
clean slate
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
  }
142.1.2 by Patrick
All DBUG_x removed from client/
918
  return(retval);
1 by brian
clean slate
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."
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
934
   ,(char**) &opt_base64_output_mode_str,
935
   (char**) &opt_base64_output_mode_str,
1 by brian
clean slate
936
   0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
937
  /*
206.3.1 by Patrick Galbraith
Most everything working with client rename
938
    drizzlebinlog needs charsets knowledge, to be able to convert a charset
1 by brian
clean slate
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,
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
944
   "Directory where character sets are.", (char**) &charsets_dir,
945
   (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
946
  {"database", 'd', "List entries for just this database (local log only).",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
947
   (char**) &database, (char**) &database, 0, GET_STR_ALLOC, REQUIRED_ARG,
1 by brian
clean slate
948
   0, 0, 0, 0, 0, 0},
949
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
950
   (char**) &debug_check_flag, (char**) &debug_check_flag, 0,
1 by brian
clean slate
951
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
952
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
953
   (char**) &debug_info_flag, (char**) &debug_info_flag,
1 by brian
clean slate
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 "
206.3.1 by Patrick Galbraith
Most everything working with client rename
956
    "enabled --to-last-log and are sending the output to the same DRIZZLE server. "
1 by brian
clean slate
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.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
960
   (char**) &disable_log_bin, (char**) &disable_log_bin, 0, GET_BOOL,
1 by brian
clean slate
961
   NO_ARG, 0, 0, 0, 0, 0, 0},
962
  {"force-if-open", 'F', "Force if binlog was not closed properly.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
963
   (char**) &force_if_open_opt, (char**) &force_if_open_opt, 0, GET_BOOL, NO_ARG,
1 by brian
clean slate
964
   1, 0, 0, 0, 0, 0},
965
  {"force-read", 'f', "Force reading unknown binlog events.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
966
   (char**) &force_opt, (char**) &force_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
1 by brian
clean slate
967
   0, 0},
968
  {"hexdump", 'H', "Augment output with hexadecimal and ASCII event dump.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
969
   (char**) &opt_hexdump, (char**) &opt_hexdump, 0, GET_BOOL, NO_ARG,
1 by brian
clean slate
970
   0, 0, 0, 0, 0, 0},
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
971
  {"host", 'h', "Get the binlog from server.", (char**) &host, (char**) &host,
1 by brian
clean slate
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.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
974
   (char**) &dirname_for_local_load, (char**) &dirname_for_local_load, 0,
1 by brian
clean slate
975
   GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
976
  {"offset", 'o', "Skip the first N entries.", (char**) &offset, (char**) &offset,
1 by brian
clean slate
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 "
301 by Brian Aker
Clean up port startup
981
   "order of preference, my.cnf, $DRIZZLE_TCP_PORT, "
982
   "built-in default (" STRINGIFY_ARG(DRIZZLE_PORT) ").",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
983
   (char**) &port, (char**) &port, 0, GET_INT, REQUIRED_ARG,
1 by brian
clean slate
984
   0, 0, 0, 0, 0, 0},
985
  {"position", 'j', "Deprecated. Use --start-position instead.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
986
   (char**) &start_position, (char**) &start_position, 0, GET_ULL,
1 by brian
clean slate
987
   REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE,
988
   /* COM_BINLOG_DUMP accepts only 4 bytes for the position */
205 by Brian Aker
uint32 -> uin32_t
989
   (uint64_t)(~(uint32_t)0), 0, 0, 0},
206.3.1 by Patrick Galbraith
Most everything working with client rename
990
  {"protocol", OPT_DRIZZLE_PROTOCOL,
1 by brian
clean slate
991
   "The protocol of connection (tcp,socket,pipe,memory).",
992
   0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
206.3.1 by Patrick Galbraith
Most everything working with client rename
993
  {"read-from-remote-server", 'R', "Read binary logs from a Drizzle server",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
994
   (char**) &remote_opt, (char**) &remote_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
1 by brian
clean slate
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.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1000
   (char**) &server_id, (char**) &server_id, 0, GET_ULONG,
1 by brian
clean slate
1001
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1002
  {"set-charset", OPT_SET_CHARSET,
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
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},
1 by brian
clean slate
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.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1009
   (char**) &short_form, (char**) &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
1 by brian
clean slate
1010
   0, 0},
1011
  {"socket", 'S', "Socket file to use for connection.",
206.3.1 by Patrick Galbraith
Most everything working with client rename
1012
   (char**) &sock, (char**) &sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0,
1 by brian
clean slate
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 "
206.3.1 by Patrick Galbraith
Most everything working with client rename
1017
   "in the local time zone, in any format accepted by the Drizzle server "
1 by brian
clean slate
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).",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1020
   (char**) &start_datetime_str, (char**) &start_datetime_str,
1 by brian
clean slate
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.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1025
   (char**) &start_position, (char**) &start_position, 0, GET_ULL,
1 by brian
clean slate
1026
   REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE,
1027
   /* COM_BINLOG_DUMP accepts only 4 bytes for the position */
205 by Brian Aker
uint32 -> uin32_t
1028
   (uint64_t)(~(uint32_t)0), 0, 0, 0},
1 by brian
clean slate
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 "
206.3.1 by Patrick Galbraith
Most everything working with client rename
1032
   "in the local time zone, in any format accepted by the Drizzle server "
1 by brian
clean slate
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).",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1035
   (char**) &stop_datetime_str, (char**) &stop_datetime_str,
1 by brian
clean slate
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.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1040
   (char**) &stop_position, (char**) &stop_position, 0, GET_ULL,
151 by Brian Aker
Ulonglong to uint64_t
1041
   REQUIRED_ARG, (uint64_t)(~(my_off_t)0), BIN_LOG_HEADER_SIZE,
1042
   (uint64_t)(~(my_off_t)0), 0, 0, 0},
1 by brian
clean slate
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 \
206.3.1 by Patrick Galbraith
Most everything working with client rename
1045
binlog of the DRIZZLE server. If you send the output to the same DRIZZLE server, \
1 by brian
clean slate
1046
that may lead to an endless loop.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1047
   (char**) &to_last_remote_log, (char**) &to_last_remote_log, 0, GET_BOOL,
1 by brian
clean slate
1048
   NO_ARG, 0, 0, 0, 0, 0, 0},
1049
  {"user", 'u', "Connect to the remote server as username.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1050
   (char**) &user, (char**) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0,
1 by brian
clean slate
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",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
1056
   (char**) &open_files_limit, (char**) &open_files_limit, 0, GET_ULONG,
1 by brian
clean slate
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
*/
243.1.14 by Jay Pipes
* Ensured all drizzled/field/x.cc files to include mysql_priv.h
1101
static void sql_print_error(const char *format, ...) __attribute__((format(printf, 1, 2)));
1 by brian
clean slate
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
  my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
1131
  my_free((char*) database, MYF(MY_ALLOW_ZERO_PTR));
1132
  my_free((char*) host, MYF(MY_ALLOW_ZERO_PTR));
1133
  my_free((char*) user, MYF(MY_ALLOW_ZERO_PTR));
1134
  my_free((char*) dirname_for_local_load, MYF(MY_ALLOW_ZERO_PTR));
1135
1136
  delete glob_description_event;
206.3.1 by Patrick Galbraith
Most everything working with client rename
1137
  if (drizzle)
1138
    drizzle_close(drizzle);
1 by brian
clean slate
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("\
206.3.1 by Patrick Galbraith
Most everything working with client rename
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");
1 by brian
clean slate
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;
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
1165
  DRIZZLE_TIME l_time;
1 by brian
clean slate
1166
  long dummy_my_timezone;
93 by Brian Aker
Convert tztime.cc to bool from my_bool.
1167
  bool dummy_in_dst_time_gap;
1 by brian
clean slate
1168
  /* We require a total specification (date AND time) */
1169
  if (str_to_datetime(str, strlen(str), &l_time, 0, &was_cut) !=
236.1.24 by Monty Taylor
Renamed MYSQL_TIME to DRIZZLE_TIME.
1170
      DRIZZLE_TIMESTAMP_DATETIME || was_cut)
1 by brian
clean slate
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
206.3.1 by Patrick Galbraith
Most everything working with client rename
1177
    the next existing day, like in drizzled. Maybe this could be changed when
1178
    drizzled is changed too (with its "strict" mode?).
1 by brian
clean slate
1179
  */
1180
  return
1181
    my_system_gmt_sec(&l_time, &dummy_my_timezone, &dummy_in_dst_time_gap);
1182
}
1183
143 by Brian Aker
Bool cleanup.
1184
extern "C" bool
1 by brian
clean slate
1185
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
206.3.1 by Patrick Galbraith
Most everything working with client rename
1186
         char *argument)
1 by brian
clean slate
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
      my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
1197
      char *start=argument;
1198
      pass= my_strdup(argument,MYF(MY_FAE));
206.3.1 by Patrick Galbraith
Most everything working with client rename
1199
      while (*argument) *argument++= 'x';    /* Destroy argument */
1 by brian
clean slate
1200
      if (*start)
206.3.1 by Patrick Galbraith
Most everything working with client rename
1201
        start[1]=0;        /* Cut length of argument */
1 by brian
clean slate
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;
206.3.1 by Patrick Galbraith
Most everything working with client rename
1213
  case OPT_DRIZZLE_PROTOCOL:
1 by brian
clean slate
1214
    opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
1215
                                    opt->name);
1216
    break;
1217
  case OPT_START_DATETIME:
1218
    start_datetime= convert_str_to_timestamp(start_datetime_str);
1219
    break;
1220
  case OPT_STOP_DATETIME:
1221
    stop_datetime= convert_str_to_timestamp(stop_datetime_str);
1222
    break;
1223
  case OPT_BASE64_OUTPUT_MODE:
1224
    if (argument == NULL)
1225
      opt_base64_output_mode= BASE64_OUTPUT_ALWAYS;
1226
    else
1227
    {
1228
      opt_base64_output_mode= (enum_base64_output_mode)
1229
        (find_type_or_exit(argument, &base64_output_mode_typelib, opt->name)-1);
1230
    }
1231
    break;
1232
  case 'V':
1233
    print_version();
1234
    exit(0);
1235
  case '?':
1236
    usage();
1237
    exit(0);
1238
  }
1239
  if (tty_password)
1240
    pass= get_tty_password(NullS);
1241
1242
  return 0;
1243
}
1244
1245
1246
static int parse_args(int *argc, char*** argv)
1247
{
1248
  int ho_error;
1249
1250
  result_file = stdout;
1251
  load_defaults("my",load_default_groups,argc,argv);
1252
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
1253
    exit(ho_error);
1254
  if (debug_info_flag)
1255
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
1256
  if (debug_check_flag)
1257
    my_end_arg= MY_CHECK_ERROR;
1258
  return 0;
1259
}
1260
1261
1262
/**
206.3.1 by Patrick Galbraith
Most everything working with client rename
1263
  Create and initialize the global drizzle object, and connect to the
1 by brian
clean slate
1264
  server.
1265
1266
  @retval ERROR_STOP An error occurred - the program should terminate.
1267
  @retval OK_CONTINUE No error, the program should continue.
1268
*/
1269
static Exit_status safe_connect()
1270
{
202.2.4 by Monty Taylor
Merged from Patrick.
1271
  drizzle= drizzle_create(NULL);
1 by brian
clean slate
1272
206.3.1 by Patrick Galbraith
Most everything working with client rename
1273
  if (!drizzle)
1 by brian
clean slate
1274
  {
202.2.1 by Monty Taylor
Renamed mysql_init to drizzle_create.
1275
    error("Failed on drizzle_create.");
1 by brian
clean slate
1276
    return ERROR_STOP;
1277
  }
1278
1279
  if (opt_protocol)
206.3.1 by Patrick Galbraith
Most everything working with client rename
1280
    drizzle_options(drizzle, DRIZZLE_OPT_PROTOCOL, (char*) &opt_protocol);
1281
  if (!drizzle_connect(drizzle, host, user, pass, 0, port, sock, 0))
1 by brian
clean slate
1282
  {
206.3.1 by Patrick Galbraith
Most everything working with client rename
1283
    error("Failed on connect: %s", drizzle_error(drizzle));
1 by brian
clean slate
1284
    return ERROR_STOP;
1285
  }
206.3.1 by Patrick Galbraith
Most everything working with client rename
1286
  drizzle->reconnect= 1;
1 by brian
clean slate
1287
  return OK_CONTINUE;
1288
}
1289
1290
1291
/**
1292
  High-level function for dumping a named binlog.
1293
1294
  This function calls dump_remote_log_entries() or
1295
  dump_local_log_entries() to do the job.
1296
1297
  @param[in] logname Name of input binlog.
1298
1299
  @retval ERROR_STOP An error occurred - the program should terminate.
1300
  @retval OK_CONTINUE No error, the program should continue.
1301
  @retval OK_STOP No error, but the end of the specified range of
1302
  events to process has been reached and the program should terminate.
1303
*/
1304
static Exit_status dump_log_entries(const char* logname)
1305
{
1306
  Exit_status rc;
1307
  PRINT_EVENT_INFO print_event_info;
1308
1309
  if (!print_event_info.init_ok())
1310
    return ERROR_STOP;
1311
  /*
1312
     Set safe delimiter, to dump things
1313
     like CREATE PROCEDURE safely
1314
  */
1315
  fprintf(result_file, "DELIMITER /*!*/;\n");
266.1.21 by Monty Taylor
Removed references to strmov and strnmov
1316
  stpcpy(print_event_info.delimiter, "/*!*/;");
1 by brian
clean slate
1317
1318
  rc= (remote_opt ? dump_remote_log_entries(&print_event_info, logname) :
1319
       dump_local_log_entries(&print_event_info, logname));
1320
1321
  /* Set delimiter back to semicolon */
1322
  fprintf(result_file, "DELIMITER ;\n");
266.1.21 by Monty Taylor
Removed references to strmov and strnmov
1323
  stpcpy(print_event_info.delimiter, ";");
1 by brian
clean slate
1324
  return rc;
1325
}
1326
1327
1328
/**
1329
  When reading a remote binlog, this function is used to grab the
1330
  Format_description_log_event in the beginning of the stream.
206.3.1 by Patrick Galbraith
Most everything working with client rename
1331
1 by brian
clean slate
1332
  This is not as smart as check_header() (used for local log); it will
1333
  not work for a binlog which mixes format. TODO: fix this.
1334
1335
  @retval ERROR_STOP An error occurred - the program should terminate.
1336
  @retval OK_CONTINUE No error, the program should continue.
1337
*/
1338
static Exit_status check_master_version()
1339
{
206.3.1 by Patrick Galbraith
Most everything working with client rename
1340
  DRIZZLE_RES* res = 0;
1341
  DRIZZLE_ROW row;
1 by brian
clean slate
1342
  const char* version;
1343
206.3.1 by Patrick Galbraith
Most everything working with client rename
1344
  if (drizzle_query(drizzle, "SELECT VERSION()") ||
1345
      !(res = drizzle_store_result(drizzle)))
1 by brian
clean slate
1346
  {
1347
    error("Could not find server version: "
206.3.1 by Patrick Galbraith
Most everything working with client rename
1348
          "Query failed when checking master version: %s", drizzle_error(drizzle));
1 by brian
clean slate
1349
    return ERROR_STOP;
1350
  }
206.3.1 by Patrick Galbraith
Most everything working with client rename
1351
  if (!(row = drizzle_fetch_row(res)))
1 by brian
clean slate
1352
  {
1353
    error("Could not find server version: "
1354
          "Master returned no rows for SELECT VERSION().");
1355
    goto err;
1356
  }
1357
1358
  if (!(version = row[0]))
1359
  {
1360
    error("Could not find server version: "
1361
          "Master reported NULL for the version.");
1362
    goto err;
1363
  }
1364
1365
  delete glob_description_event;
1366
  switch (*version) {
1367
  case '3':
1368
    glob_description_event= new Format_description_log_event(1);
1369
    break;
1370
  case '4':
1371
    glob_description_event= new Format_description_log_event(3);
1372
    break;
1373
  case '5':
1374
  case '6':
1375
    /*
1376
      The server is soon going to send us its Format_description log
1377
      event, unless it is a 5.0 server with 3.23 or 4.0 binlogs.
1378
      So we first assume that this is 4.0 (which is enough to read the
1379
      Format_desc event if one comes).
1380
    */
1381
    glob_description_event= new Format_description_log_event(3);
1382
    break;
1383
  default:
1384
    glob_description_event= NULL;
1385
    error("Could not find server version: "
206.3.1 by Patrick Galbraith
Most everything working with client rename
1386
          "Master reported unrecognized Drizzle version '%s'.", version);
1 by brian
clean slate
1387
    goto err;
1388
  }
1389
  if (!glob_description_event || !glob_description_event->is_valid())
1390
  {
1391
    error("Failed creating Format_description_log_event; out of memory?");
1392
    goto err;
1393
  }
1394
206.3.1 by Patrick Galbraith
Most everything working with client rename
1395
  drizzle_free_result(res);
1 by brian
clean slate
1396
  return OK_CONTINUE;
1397
1398
err:
206.3.1 by Patrick Galbraith
Most everything working with client rename
1399
  drizzle_free_result(res);
1 by brian
clean slate
1400
  return ERROR_STOP;
1401
}
1402
1403
1404
/**
1405
  Requests binlog dump from a remote server and prints the events it
1406
  receives.
1407
1408
  @param[in,out] print_event_info Parameters and context state
1409
  determining how to print.
1410
  @param[in] logname Name of input binlog.
1411
1412
  @retval ERROR_STOP An error occurred - the program should terminate.
1413
  @retval OK_CONTINUE No error, the program should continue.
1414
  @retval OK_STOP No error, but the end of the specified range of
1415
  events to process has been reached and the program should terminate.
1416
*/
1417
static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
1418
                                           const char* logname)
1419
1420
{
1421
  uchar buf[128];
297 by Brian Aker
Final ulong cleanup in clients
1422
  uint32_t len;
1 by brian
clean slate
1423
  uint logname_len;
1424
  NET* net;
1425
  my_off_t old_off= start_position_mot;
1426
  char fname[FN_REFLEN+1];
1427
  Exit_status retval= OK_CONTINUE;
142.1.2 by Patrick
All DBUG_x removed from client/
1428
1 by brian
clean slate
1429
1430
  /*
1431
    Even if we already read one binlog (case of >=2 binlogs on command line),
1432
    we cannot re-use the same connection as before, because it is now dead
1433
    (COM_BINLOG_DUMP kills the thread when it finishes).
1434
  */
1435
  if ((retval= safe_connect()) != OK_CONTINUE)
142.1.2 by Patrick
All DBUG_x removed from client/
1436
    return(retval);
206.3.1 by Patrick Galbraith
Most everything working with client rename
1437
  net= &drizzle->net;
1 by brian
clean slate
1438
1439
  if ((retval= check_master_version()) != OK_CONTINUE)
142.1.2 by Patrick
All DBUG_x removed from client/
1440
    return(retval);
1 by brian
clean slate
1441
1442
  /*
1443
    COM_BINLOG_DUMP accepts only 4 bytes for the position, so we are forced to
205 by Brian Aker
uint32 -> uin32_t
1444
    cast to uint32_t.
1 by brian
clean slate
1445
  */
205 by Brian Aker
uint32 -> uin32_t
1446
  int4store(buf, (uint32_t)start_position);
1 by brian
clean slate
1447
  int2store(buf + BIN_LOG_HEADER_SIZE, binlog_flags);
1448
1449
  size_t tlen = strlen(logname);
206.3.1 by Patrick Galbraith
Most everything working with client rename
1450
  if (tlen > UINT_MAX)
1 by brian
clean slate
1451
  {
1452
    error("Log name too long.");
142.1.2 by Patrick
All DBUG_x removed from client/
1453
    return(ERROR_STOP);
1 by brian
clean slate
1454
  }
1455
  logname_len = (uint) tlen;
1456
  int4store(buf + 6, 0);
1457
  memcpy(buf + 10, logname, logname_len);
206.3.1 by Patrick Galbraith
Most everything working with client rename
1458
  if (simple_command(drizzle, COM_BINLOG_DUMP, buf, logname_len + 10, 1))
1 by brian
clean slate
1459
  {
1460
    error("Got fatal error sending the log dump command.");
142.1.2 by Patrick
All DBUG_x removed from client/
1461
    return(ERROR_STOP);
1 by brian
clean slate
1462
  }
1463
1464
  for (;;)
1465
  {
1466
    const char *error_msg;
1467
    Log_event *ev;
1468
206.3.1 by Patrick Galbraith
Most everything working with client rename
1469
    len= cli_safe_read(drizzle);
1 by brian
clean slate
1470
    if (len == packet_error)
1471
    {
206.3.1 by Patrick Galbraith
Most everything working with client rename
1472
      error("Got error reading packet from server: %s", drizzle_error(drizzle));
142.1.2 by Patrick
All DBUG_x removed from client/
1473
      return(ERROR_STOP);
1 by brian
clean slate
1474
    }
1475
    if (len < 8 && net->read_pos[0] == 254)
1476
      break; // end of data
1477
    if (!(ev= Log_event::read_log_event((const char*) net->read_pos + 1 ,
1478
                                        len - 1, &error_msg,
1479
                                        glob_description_event)))
1480
    {
1481
      error("Could not construct log event object: %s", error_msg);
142.1.2 by Patrick
All DBUG_x removed from client/
1482
      return(ERROR_STOP);
206.3.1 by Patrick Galbraith
Most everything working with client rename
1483
    }
1 by brian
clean slate
1484
    /*
1485
      If reading from a remote host, ensure the temp_buf for the
1486
      Log_event class is pointing to the incoming stream.
1487
    */
1488
    if (remote_opt)
206.3.1 by Patrick Galbraith
Most everything working with client rename
1489
      ev->register_temp_buf((char*) net->read_pos + 1);
1 by brian
clean slate
1490
1491
    Log_event_type type= ev->get_type_code();
1492
    if (glob_description_event->binlog_version >= 3 ||
1493
        (type != LOAD_EVENT && type != CREATE_FILE_EVENT))
1494
    {
1495
      /*
1496
        If this is a Rotate event, maybe it's the end of the requested binlog;
1497
        in this case we are done (stop transfer).
1498
        This is suitable for binlogs, not relay logs (but for now we don't read
1499
        relay logs remotely because the server is not able to do that). If one
1500
        day we read relay logs remotely, then we will have a problem with the
1501
        detection below: relay logs contain Rotate events which are about the
1502
        binlogs, so which would trigger the end-detection below.
1503
      */
1504
      if (type == ROTATE_EVENT)
1505
      {
1506
        Rotate_log_event *rev= (Rotate_log_event *)ev;
1507
        /*
1508
          If this is a fake Rotate event, and not about our log, we can stop
1509
          transfer. If this a real Rotate event (so it's not about our log,
1510
          it's in our log describing the next log), we print it (because it's
1511
          part of our log) and then we will stop when we receive the fake one
1512
          soon.
1513
        */
1514
        if (rev->when == 0)
1515
        {
1516
          if (!to_last_remote_log)
1517
          {
1518
            if ((rev->ident_len != logname_len) ||
1519
                memcmp(rev->new_log_ident, logname, logname_len))
1520
            {
142.1.2 by Patrick
All DBUG_x removed from client/
1521
              return(OK_CONTINUE);
1 by brian
clean slate
1522
            }
1523
            /*
1524
              Otherwise, this is a fake Rotate for our log, at the very
1525
              beginning for sure. Skip it, because it was not in the original
1526
              log. If we are running with to_last_remote_log, we print it,
1527
              because it serves as a useful marker between binlogs then.
1528
            */
1529
            continue;
1530
          }
1531
          len= 1; // fake Rotate, so don't increment old_off
1532
        }
1533
      }
1534
      else if (type == FORMAT_DESCRIPTION_EVENT)
1535
      {
1536
        /*
1537
          This could be an fake Format_description_log_event that server
1538
          (5.0+) automatically sends to a slave on connect, before sending
1539
          a first event at the requested position.  If this is the case,
1540
          don't increment old_off. Real Format_description_log_event always
1541
          starts from BIN_LOG_HEADER_SIZE position.
1542
        */
1543
        if (old_off != BIN_LOG_HEADER_SIZE)
1544
          len= 1;         // fake event, don't increment old_off
1545
      }
1546
      Exit_status retval= process_event(print_event_info, ev, old_off, logname);
1547
      if (retval != OK_CONTINUE)
142.1.2 by Patrick
All DBUG_x removed from client/
1548
        return(retval);
1 by brian
clean slate
1549
    }
1550
    else
1551
    {
1552
      Load_log_event *le= (Load_log_event*)ev;
1553
      const char *old_fname= le->fname;
1554
      uint old_len= le->fname_len;
1555
      File file;
1556
      Exit_status retval;
1557
1558
      if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0)
142.1.2 by Patrick
All DBUG_x removed from client/
1559
        return(ERROR_STOP);
1 by brian
clean slate
1560
1561
      retval= process_event(print_event_info, ev, old_off, logname);
1562
      if (retval != OK_CONTINUE)
1563
      {
1564
        my_close(file,MYF(MY_WME));
142.1.2 by Patrick
All DBUG_x removed from client/
1565
        return(retval);
1 by brian
clean slate
1566
      }
1567
      retval= load_processor.load_old_format_file(net,old_fname,old_len,file);
1568
      my_close(file,MYF(MY_WME));
1569
      if (retval != OK_CONTINUE)
142.1.2 by Patrick
All DBUG_x removed from client/
1570
        return(retval);
1 by brian
clean slate
1571
    }
1572
    /*
1573
      Let's adjust offset for remote log as for local log to produce
1574
      similar text and to have --stop-position to work identically.
1575
    */
1576
    old_off+= len-1;
1577
  }
1578
142.1.2 by Patrick
All DBUG_x removed from client/
1579
  return(OK_CONTINUE);
1 by brian
clean slate
1580
}
1581
1582
1583
/**
1584
  Reads the @c Format_description_log_event from the beginning of a
1585
  local input file.
1586
1587
  The @c Format_description_log_event is only read if it is outside
1588
  the range specified with @c --start-position; otherwise, it will be
1589
  seen later.  If this is an old binlog, a fake @c
1590
  Format_description_event is created.  This also prints a @c
1591
  Format_description_log_event to the output, unless we reach the
1592
  --start-position range.  In this case, it is assumed that a @c
1593
  Format_description_log_event will be found when reading events the
1594
  usual way.
1595
1596
  @param file The file to which a @c Format_description_log_event will
1597
  be printed.
1598
1599
  @param[in,out] print_event_info Parameters and context state
1600
  determining how to print.
1601
1602
  @param[in] logname Name of input binlog.
1603
1604
  @retval ERROR_STOP An error occurred - the program should terminate.
1605
  @retval OK_CONTINUE No error, the program should continue.
1606
  @retval OK_STOP No error, but the end of the specified range of
1607
  events to process has been reached and the program should terminate.
1608
*/
1609
static Exit_status check_header(IO_CACHE* file,
1610
                                PRINT_EVENT_INFO *print_event_info,
1611
                                const char* logname)
1612
{
1613
  uchar header[BIN_LOG_HEADER_SIZE];
1614
  uchar buf[PROBE_HEADER_LEN];
77.1.103 by Monty Taylor
Fixed some format strings to use PRIu64 for the uint64_t types.
1615
  uint64_t tmp_pos, pos;
1 by brian
clean slate
1616
1617
  delete glob_description_event;
1618
  if (!(glob_description_event= new Format_description_log_event(3)))
1619
  {
1620
    error("Failed creating Format_description_log_event; out of memory?");
1621
    return ERROR_STOP;
1622
  }
1623
1624
  pos= my_b_tell(file);
1625
  my_b_seek(file, (my_off_t)0);
1626
  if (my_b_read(file, header, sizeof(header)))
1627
  {
1628
    error("Failed reading header; probably an empty file.");
1629
    return ERROR_STOP;
1630
  }
1631
  if (memcmp(header, BINLOG_MAGIC, sizeof(header)))
1632
  {
1633
    error("File is not a binary log file.");
1634
    return ERROR_STOP;
1635
  }
1636
1637
  /*
1638
    Imagine we are running with --start-position=1000. We still need
1639
    to know the binlog format's. So we still need to find, if there is
1640
    one, the Format_desc event, or to know if this is a 3.23
1641
    binlog. So we need to first read the first events of the log,
1642
    those around offset 4.  Even if we are reading a 3.23 binlog from
1643
    the start (no --start-position): we need to know the header length
1644
    (which is 13 in 3.23, 19 in 4.x) to be able to successfully print
1645
    the first event (Start_log_event_v3). So even in this case, we
1646
    need to "probe" the first bytes of the log *before* we do a real
1647
    read_log_event(). Because read_log_event() needs to know the
1648
    header's length to work fine.
1649
  */
1650
  for(;;)
1651
  {
1652
    tmp_pos= my_b_tell(file); /* should be 4 the first time */
1653
    if (my_b_read(file, buf, sizeof(buf)))
1654
    {
1655
      if (file->error)
1656
      {
77.1.103 by Monty Taylor
Fixed some format strings to use PRIu64 for the uint64_t types.
1657
        error("Could not read entry at offset %"PRIu64": "
1658
              "Error in log format or read error.", tmp_pos);
1 by brian
clean slate
1659
        return ERROR_STOP;
1660
      }
1661
      /*
1662
        Otherwise this is just EOF : this log currently contains 0-2
1663
        events.  Maybe it's going to be filled in the next
1664
        milliseconds; then we are going to have a problem if this a
1665
        3.23 log (imagine we are locally reading a 3.23 binlog which
1666
        is being written presently): we won't know it in
1667
        read_log_event() and will fail().  Similar problems could
1668
        happen with hot relay logs if --start-position is used (but a
1669
        --start-position which is posterior to the current size of the log).
1670
        These are rare problems anyway (reading a hot log + when we
1671
        read the first events there are not all there yet + when we
1672
        read a bit later there are more events + using a strange
1673
        --start-position).
1674
      */
1675
      break;
1676
    }
1677
    else
1678
    {
1679
      /* always test for a Start_v3, even if no --start-position */
1680
      if (buf[EVENT_TYPE_OFFSET] == START_EVENT_V3)
1681
      {
1682
        /* This is 3.23 or 4.x */
206.3.1 by Patrick Galbraith
Most everything working with client rename
1683
        if (uint4korr(buf + EVENT_LEN_OFFSET) <
1 by brian
clean slate
1684
            (LOG_EVENT_MINIMAL_HEADER_LEN + START_V3_HEADER_LEN))
1685
        {
1686
          /* This is 3.23 (format 1) */
1687
          delete glob_description_event;
1688
          if (!(glob_description_event= new Format_description_log_event(1)))
1689
          {
1690
            error("Failed creating Format_description_log_event; "
1691
                  "out of memory?");
1692
            return ERROR_STOP;
1693
          }
1694
        }
1695
        break;
1696
      }
1697
      else if (tmp_pos >= start_position)
1698
        break;
1699
      else if (buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT)
1700
      {
1701
        /* This is 5.0 */
1702
        Format_description_log_event *new_description_event;
1703
        my_b_seek(file, tmp_pos); /* seek back to event's start */
206.3.1 by Patrick Galbraith
Most everything working with client rename
1704
        if (!(new_description_event= (Format_description_log_event*)
1 by brian
clean slate
1705
              Log_event::read_log_event(file, glob_description_event)))
1706
          /* EOF can't be hit here normally, so it's a real error */
1707
        {
1708
          error("Could not read a Format_description_log_event event at "
77.1.103 by Monty Taylor
Fixed some format strings to use PRIu64 for the uint64_t types.
1709
                "offset %"PRIu64"; this could be a log format error or read error.",
1710
                tmp_pos);
1 by brian
clean slate
1711
          return ERROR_STOP;
1712
        }
1713
        if (opt_base64_output_mode == BASE64_OUTPUT_AUTO
1714
            || opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
1715
        {
1716
          /*
1717
            process_event will delete *description_event and set it to
1718
            the new one, so we should not do it ourselves in this
1719
            case.
1720
          */
1721
          Exit_status retval= process_event(print_event_info,
1722
                                            new_description_event, tmp_pos,
1723
                                            logname);
1724
          if (retval != OK_CONTINUE)
1725
            return retval;
1726
        }
1727
        else
1728
        {
1729
          delete glob_description_event;
1730
          glob_description_event= new_description_event;
1731
        }
1732
      }
1733
      else if (buf[EVENT_TYPE_OFFSET] == ROTATE_EVENT)
1734
      {
1735
        Log_event *ev;
1736
        my_b_seek(file, tmp_pos); /* seek back to event's start */
1737
        if (!(ev= Log_event::read_log_event(file, glob_description_event)))
1738
        {
1739
          /* EOF can't be hit here normally, so it's a real error */
77.1.103 by Monty Taylor
Fixed some format strings to use PRIu64 for the uint64_t types.
1740
          error("Could not read a Rotate_log_event event at offset "
1741
                "%"PRIu64";"
1 by brian
clean slate
1742
                " this could be a log format error or read error.",
77.1.103 by Monty Taylor
Fixed some format strings to use PRIu64 for the uint64_t types.
1743
                tmp_pos);
1 by brian
clean slate
1744
          return ERROR_STOP;
1745
        }
1746
        delete ev;
1747
      }
1748
      else
1749
        break;
1750
    }
1751
  }
1752
  my_b_seek(file, pos);
1753
  return OK_CONTINUE;
1754
}
1755
1756
1757
/**
1758
  Reads a local binlog and prints the events it sees.
1759
1760
  @param[in] logname Name of input binlog.
1761
1762
  @param[in,out] print_event_info Parameters and context state
1763
  determining how to print.
1764
1765
  @retval ERROR_STOP An error occurred - the program should terminate.
1766
  @retval OK_CONTINUE No error, the program should continue.
1767
  @retval OK_STOP No error, but the end of the specified range of
1768
  events to process has been reached and the program should terminate.
1769
*/
1770
static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
1771
                                          const char* logname)
1772
{
1773
  File fd = -1;
1774
  IO_CACHE cache,*file= &cache;
1775
  uchar tmp_buff[BIN_LOG_HEADER_SIZE];
1776
  Exit_status retval= OK_CONTINUE;
1777
1778
  if (logname && strcmp(logname, "-") != 0)
1779
  {
1780
    /* read from normal file */
1781
    if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
1782
      return ERROR_STOP;
1783
    if (init_io_cache(file, fd, 0, READ_CACHE, start_position_mot, 0,
206.3.1 by Patrick Galbraith
Most everything working with client rename
1784
          MYF(MY_WME | MY_NABP)))
1 by brian
clean slate
1785
    {
1786
      my_close(fd, MYF(MY_WME));
1787
      return ERROR_STOP;
1788
    }
1789
    if ((retval= check_header(file, print_event_info, logname)) != OK_CONTINUE)
1790
      goto end;
1791
  }
1792
  else
1793
  {
1794
    if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
206.3.1 by Patrick Galbraith
Most everything working with client rename
1795
          0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
1 by brian
clean slate
1796
    {
1797
      error("Failed to init IO cache.");
1798
      return ERROR_STOP;
1799
    }
1800
    if ((retval= check_header(file, print_event_info, logname)) != OK_CONTINUE)
1801
      goto end;
1802
    if (start_position)
1803
    {
1804
      /* skip 'start_position' characters from stdin */
1805
      uchar buff[IO_SIZE];
1806
      my_off_t length,tmp;
1807
      for (length= start_position_mot ; length > 0 ; length-=tmp)
1808
      {
206.3.1 by Patrick Galbraith
Most everything working with client rename
1809
  tmp=min(length,sizeof(buff));
1810
  if (my_b_read(file, buff, (uint) tmp))
1 by brian
clean slate
1811
        {
1812
          error("Failed reading from file.");
1813
          goto err;
1814
        }
1815
      }
1816
    }
1817
  }
1818
1819
  if (!glob_description_event || !glob_description_event->is_valid())
1820
  {
1821
    error("Invalid Format_description log event; could be out of memory.");
1822
    goto err;
1823
  }
1824
1825
  if (!start_position && my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE))
1826
  {
1827
    error("Failed reading from file.");
1828
    goto err;
1829
  }
1830
  for (;;)
1831
  {
1832
    char llbuff[21];
1833
    my_off_t old_off = my_b_tell(file);
1834
1835
    Log_event* ev = Log_event::read_log_event(file, glob_description_event);
1836
    if (!ev)
1837
    {
1838
      /*
1839
        if binlog wasn't closed properly ("in use" flag is set) don't complain
1840
        about a corruption, but treat it as EOF and move to the next binlog.
1841
      */
1842
      if (glob_description_event->flags & LOG_EVENT_BINLOG_IN_USE_F)
1843
        file->error= 0;
1844
      else if (file->error)
1845
      {
1846
        error("Could not read entry at offset %s: "
1847
              "Error in log format or read error.",
1848
              llstr(old_off,llbuff));
1849
        goto err;
1850
      }
1851
      // file->error == 0 means EOF, that's OK, we break in this case
1852
      goto end;
1853
    }
1854
    if ((retval= process_event(print_event_info, ev, old_off, logname)) !=
1855
        OK_CONTINUE)
1856
      goto end;
1857
  }
1858
1859
  /* NOTREACHED */
1860
1861
err:
1862
  retval= ERROR_STOP;
1863
1864
end:
1865
  if (fd >= 0)
1866
    my_close(fd, MYF(MY_WME));
1867
  end_io_cache(file);
1868
  return retval;
1869
}
1870
1871
1872
int main(int argc, char** argv)
1873
{
1874
  char **defaults_argv;
1875
  Exit_status retval= OK_CONTINUE;
151 by Brian Aker
Ulonglong to uint64_t
1876
  uint64_t save_stop_position;
1 by brian
clean slate
1877
  MY_INIT(argv[0]);
1878
1879
  init_time(); // for time functions
1880
1881
  parse_args(&argc, (char***)&argv);
1882
  defaults_argv=argv;
1883
1884
  if (!argc)
1885
  {
1886
    usage();
1887
    free_defaults(defaults_argv);
1888
    exit(1);
1889
  }
1890
1891
  if (opt_base64_output_mode == BASE64_OUTPUT_UNSPEC)
1892
    opt_base64_output_mode= BASE64_OUTPUT_AUTO;
1893
1894
  my_set_max_open_files(open_files_limit);
1895
1896
  MY_TMPDIR tmpdir;
1897
  tmpdir.list= 0;
1898
  if (!dirname_for_local_load)
1899
  {
1900
    if (init_tmpdir(&tmpdir, 0))
1901
      exit(1);
1902
    dirname_for_local_load= my_strdup(my_tmpdir(&tmpdir), MY_WME);
1903
  }
1904
1905
  if (dirname_for_local_load)
1906
    load_processor.init_by_dir_name(dirname_for_local_load);
1907
  else
1908
    load_processor.init_by_cur_dir();
1909
1910
  fprintf(result_file,
206.3.1 by Patrick Galbraith
Most everything working with client rename
1911
    "/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n");
1 by brian
clean slate
1912
1913
  if (disable_log_bin)
1914
    fprintf(result_file,
1915
            "/*!32316 SET @OLD_SQL_LOG_BIN=@@SQL_LOG_BIN, SQL_LOG_BIN=0*/;\n");
1916
1917
  /*
206.3.1 by Patrick Galbraith
Most everything working with client rename
1918
    In drizzlebinlog|drizzle, don't want Drizzle to be disconnected after each
1 by brian
clean slate
1919
    transaction (which would be the case with GLOBAL.COMPLETION_TYPE==2).
1920
  */
1921
  fprintf(result_file,
1922
          "/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,"
1923
          "COMPLETION_TYPE=0*/;\n");
1924
1925
  if (charset)
1926
    fprintf(result_file,
1927
            "\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
1928
            "\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
206.3.1 by Patrick Galbraith
Most everything working with client rename
1929
            "\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
1 by brian
clean slate
1930
            "\n/*!40101 SET NAMES %s */;\n", charset);
1931
1932
  for (save_stop_position= stop_position, stop_position= ~(my_off_t)0 ;
1933
       (--argc >= 0) ; )
1934
  {
1935
    if (argc == 0) // last log, --stop-position applies
1936
      stop_position= save_stop_position;
1937
    if ((retval= dump_log_entries(*argv++)) != OK_CONTINUE)
1938
      break;
1939
1940
    // For next log, --start-position does not apply
1941
    start_position= BIN_LOG_HEADER_SIZE;
1942
  }
1943
1944
  /*
1945
    Issue a ROLLBACK in case the last printed binlog was crashed and had half
1946
    of transaction.
1947
  */
1948
  fprintf(result_file,
206.3.1 by Patrick Galbraith
Most everything working with client rename
1949
          "# End of log file\nROLLBACK /* added by drizzlebinlog */;\n"
1 by brian
clean slate
1950
          "/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;\n");
1951
  if (disable_log_bin)
1952
    fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n");
1953
1954
  if (charset)
1955
    fprintf(result_file,
1956
            "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"
1957
            "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"
1958
            "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n");
1959
1960
  if (tmpdir.list)
1961
    free_tmpdir(&tmpdir);
1962
  if (result_file != stdout)
1963
    my_fclose(result_file, MYF(0));
1964
  cleanup();
1965
  free_defaults(defaults_argv);
1966
  my_free_open_file_info();
1967
  load_processor.destroy();
51.3.5 by Jay Pipes
Merged in from trunk.
1968
  my_end(my_end_arg);
1 by brian
clean slate
1969
1970
  exit(retval == ERROR_STOP ? 1 : 0);
1971
}
1972
1973
/*
1974
  We must include this here as it's compiled with different options for
1975
  the server
1976
*/
1977
212.5.45 by Monty Taylor
Removed excess AM_CPPFLAGS from the tree. Now the only thing that should be in the include path should be -I${top_srcdir} and -I${top_builddir}w
1978
#include <drizzled/log_event.cc>
1 by brian
clean slate
1979