1
/* Copyright (C) 2001-2004 DRIZZLE AB
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.
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.
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 */
18
TODO: print the catalog (some USE catalog.db ????).
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.
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
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.
33
#include <libdrizzle/my_time.h>
34
#include <drizzled/global.h>
35
#include <mysys/my_sys.h>
36
#include <mystrings/m_string.h>
37
#include <libdrizzle/drizzle.h>
38
#include <libdrizzle/errmsg.h>
39
#include <mysys/my_getopt.h>
40
/* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */
41
#include <drizzled/mysql_priv.h>
42
#include <drizzled/log_event.h>
43
#include <libdrizzle/sql_common.h>
46
enum options_drizzlebinlog
48
OPT_CHARSETS_DIR=256, OPT_BASE64_OUTPUT_MODE,
49
OPT_DEBUG_CHECK, OPT_DEBUG_INFO, OPT_DRIZZLE_PROTOCOL,
50
OPT_SERVER_ID, OPT_SET_CHARSET, OPT_START_DATETIME,
51
OPT_START_POSITION, OPT_STOP_DATETIME, OPT_STOP_POSITION,
55
#define BIN_LOG_HEADER_SIZE 4
56
#define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4)
59
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
61
char server_version[SERVER_VERSION_LENGTH];
64
// needed by net_serv.c
65
ulong bytes_sent = 0L, bytes_received = 0L;
66
ulong drizzled_net_retry_count = 10L;
67
ulong open_files_limit;
69
static uint opt_protocol= 0;
70
static FILE *result_file;
72
static const char *load_default_groups[]= { "drizzlebinlog","client",0 };
74
static void error(const char *format, ...) __attribute__((format(printf, 1, 2)));
75
static void warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
77
static bool one_database=0, to_last_remote_log= 0, disable_log_bin= 0;
78
static bool opt_hexdump= 0;
79
const char *base64_output_mode_names[]= {"NEVER", "AUTO", "ALWAYS", NullS};
80
TYPELIB base64_output_mode_typelib=
81
{ array_elements(base64_output_mode_names) - 1, "",
82
base64_output_mode_names, NULL };
83
static enum_base64_output_mode opt_base64_output_mode= BASE64_OUTPUT_UNSPEC;
84
static const char *opt_base64_output_mode_str= NullS;
85
static const char* database= 0;
86
static bool force_opt= 0, short_form= 0, remote_opt= 0;
87
static bool debug_info_flag, debug_check_flag;
88
static bool force_if_open_opt= 1;
89
static uint64_t offset = 0;
90
static const char* host = 0;
92
static uint my_end_arg;
93
static const char* sock= 0;
94
static const char* user = 0;
95
static char* pass = 0;
96
static char *charset= 0;
98
static uint64_t start_position, stop_position;
99
#define start_position_mot ((my_off_t)start_position)
100
#define stop_position_mot ((my_off_t)stop_position)
102
static char *start_datetime_str, *stop_datetime_str;
103
static my_time_t start_datetime= 0, stop_datetime= MY_TIME_T_MAX;
104
static uint64_t rec_count= 0;
105
static short binlog_flags = 0;
106
static DRIZZLE *drizzle= NULL;
107
static const char* dirname_for_local_load= 0;
110
Pointer to the Format_description_log_event of the currently active binlog.
112
This will be changed each time a new Format_description_log_event is
113
found in the binlog. It is finally destroyed at program termination.
115
static Format_description_log_event* glob_description_event= NULL;
118
Exit status for functions in this file.
121
/** No error occurred and execution should continue. */
123
/** An error occurred and execution should stop. */
125
/** No error occurred but execution should stop. */
129
static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
130
const char* logname);
131
static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
132
const char* logname);
133
static Exit_status dump_log_entries(const char* logname);
134
static Exit_status safe_connect();
137
class Load_log_processor
139
char target_dir_name[FN_REFLEN];
140
int target_dir_name_len;
143
When we see first event corresponding to some LOAD DATA statement in
144
binlog, we create temporary file to store data to be loaded.
145
We add name of this file to file_names array using its file_id as index.
146
If we have Create_file event (i.e. we have binary log in pre-5.0.3
147
format) we also store save event object to be able which is needed to
148
emit LOAD DATA statement when we will meet Exec_load_data event.
149
If we have Begin_load_query event we simply store 0 in
150
File_name_record::event field.
152
struct File_name_record
155
Create_file_log_event *event;
158
@todo Should be a map (e.g., a hash map), not an array. With the
159
present implementation, the number of elements in this array is
160
about the number of files loaded since the server started, which
161
may be big after a few years. We should be able to use existing
162
library data structures for this. /Sven
164
DYNAMIC_ARRAY file_names;
167
Looks for a non-existing filename by adding a numerical suffix to
168
the given base name, creates the generated file, and returns the
169
filename by modifying the filename argument.
171
@param[in,out] filename Base filename
173
@param[in,out] file_name_end Pointer to last character of
174
filename. The numerical suffix will be written to this position.
175
Note that there must be a least five bytes of allocated memory
178
@retval -1 Error (can't find new filename).
179
@retval >=0 Found file.
181
File create_unique_file(char *filename, char *file_name_end)
184
/* If we have to try more than 1000 times, something is seriously wrong */
185
for (uint version= 0; version<1000; version++)
187
sprintf(file_name_end,"-%x",version);
188
if ((res= my_create(filename,0,
189
O_CREAT|O_EXCL|O_BINARY|O_WRONLY,MYF(0)))!=-1)
196
Load_log_processor() {}
197
~Load_log_processor() {}
201
return init_dynamic_array(&file_names, sizeof(File_name_record),
202
100,100 CALLER_INFO);
205
void init_by_dir_name(const char *dir)
207
target_dir_name_len= (convert_dirname(target_dir_name, dir, NullS) -
210
void init_by_cur_dir()
212
if (my_getwd(target_dir_name,sizeof(target_dir_name),MYF(MY_WME)))
214
target_dir_name_len= strlen(target_dir_name);
218
File_name_record *ptr= (File_name_record *)file_names.buffer;
219
File_name_record *end= ptr + file_names.elements;
220
for (; ptr < end; ptr++)
224
my_free(ptr->fname, MYF(MY_WME));
226
memset((char *)ptr, 0, sizeof(File_name_record));
230
delete_dynamic(&file_names);
234
Obtain Create_file event for LOAD DATA statement by its file_id
235
and remove it from this Load_log_processor's list of events.
237
Checks whether we have already seen a Create_file_log_event with
238
the given file_id. If yes, returns a pointer to the event and
239
removes the event from array describing active temporary files.
240
From this moment, the caller is responsible for freeing the memory
241
occupied by the event.
243
@param[in] file_id File id identifying LOAD DATA statement.
245
@return Pointer to Create_file_log_event, or NULL if we have not
246
seen any Create_file_log_event with this file_id.
248
Create_file_log_event *grab_event(uint file_id)
250
File_name_record *ptr;
251
Create_file_log_event *res;
253
if (file_id >= file_names.elements)
255
ptr= dynamic_element(&file_names, file_id, File_name_record*);
256
if ((res= ptr->event))
257
memset((char *)ptr, 0, sizeof(File_name_record));
262
Obtain file name of temporary file for LOAD DATA statement by its
263
file_id and remove it from this Load_log_processor's list of events.
265
@param[in] file_id Identifier for the LOAD DATA statement.
267
Checks whether we have already seen Begin_load_query event for
268
this file_id. If yes, returns the file name of the corresponding
269
temporary file and removes the filename from the array of active
270
temporary files. From this moment, the caller is responsible for
271
freeing the memory occupied by this name.
273
@return String with the name of the temporary file, or NULL if we
274
have not seen any Begin_load_query_event with this file_id.
276
char *grab_fname(uint file_id)
278
File_name_record *ptr;
281
if (file_id >= file_names.elements)
283
ptr= dynamic_element(&file_names, file_id, File_name_record*);
287
memset((char *)ptr, 0, sizeof(File_name_record));
291
Exit_status process(Create_file_log_event *ce);
292
Exit_status process(Begin_load_query_log_event *ce);
293
Exit_status process(Append_block_log_event *ae);
294
File prepare_new_file_for_old_format(Load_log_event *le, char *filename);
295
Exit_status load_old_format_file(NET* net, const char *server_fname,
296
uint server_fname_len, File file);
297
Exit_status process_first_event(const char *bname, uint blen,
299
uint block_len, uint file_id,
300
Create_file_log_event *ce);
305
Creates and opens a new temporary file in the directory specified by previous call to init_by_dir_name() or init_by_cur_dir().
307
@param[in] le The basename of the created file will start with the
308
basename of the file pointed to by this Load_log_event.
310
@param[out] filename Buffer to save the filename in.
312
@return File handle >= 0 on success, -1 on error.
314
File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le,
321
fn_format(filename, le->fname, target_dir_name, "", MY_REPLACE_DIR);
322
len= strlen(filename);
323
tail= filename + len;
325
if ((file= create_unique_file(filename,tail)) < 0)
327
error("Could not construct local filename %s.",filename);
331
le->set_fname_outside_temp_buf(filename,len+strlen(tail));
338
Reads a file from a server and saves it locally.
340
@param[in,out] net The server to read from.
342
@param[in] server_fname The name of the file that the server should
345
@param[in] server_fname_len The length of server_fname.
347
@param[in,out] file The file to write to.
349
@retval ERROR_STOP An error occurred - the program should terminate.
350
@retval OK_CONTINUE No error, the program should continue.
352
Exit_status Load_log_processor::load_old_format_file(NET* net,
353
const char*server_fname,
354
uint server_fname_len,
357
uchar buf[FN_REFLEN+1];
359
memcpy(buf + 1, server_fname, server_fname_len + 1);
360
if (my_net_write(net, buf, server_fname_len +2) || net_flush(net))
362
error("Failed requesting the remote dump of %s.", server_fname);
368
ulong packet_len = my_net_read(net);
371
if (my_net_write(net, (uchar*) "", 0) || net_flush(net))
373
error("Failed sending the ack packet.");
377
we just need to send something, as the server will read but
378
not examine the packet - this is because drizzle_load() sends
379
an OK when it is done
383
else if (packet_len == packet_error)
385
error("Failed reading a packet during the dump of %s.", server_fname);
389
if (packet_len > UINT_MAX)
391
error("Illegal length of packet read from net.");
394
if (my_write(file, (uchar*) net->read_pos,
395
(uint) packet_len, MYF(MY_WME|MY_NABP)))
404
Process the first event in the sequence of events representing a
407
Creates a temporary file to be used in LOAD DATA and writes first
408
block of data to it. Registers its file name (and optional
409
Create_file event) in the array of active temporary files.
411
@param bname Base name for temporary file to be created.
412
@param blen Base name length.
413
@param block First block of data to be loaded.
414
@param block_len First block length.
415
@param file_id Identifies the LOAD DATA statement.
416
@param ce Pointer to Create_file event object if we are processing
419
@retval ERROR_STOP An error occurred - the program should terminate.
420
@retval OK_CONTINUE No error, the program should continue.
422
Exit_status Load_log_processor::process_first_event(const char *bname,
427
Create_file_log_event *ce)
429
uint full_len= target_dir_name_len + blen + 9 + 9 + 1;
430
Exit_status retval= OK_CONTINUE;
433
File_name_record rec;
436
if (!(fname= (char*) my_malloc(full_len,MYF(MY_WME))))
438
error("Out of memory.");
443
memcpy(fname, target_dir_name, target_dir_name_len);
444
ptr= fname + target_dir_name_len;
445
memcpy(ptr,bname,blen);
447
ptr+= sprintf(ptr, "-%x", file_id);
449
if ((file= create_unique_file(fname,ptr)) < 0)
451
error("Could not construct local filename %s%s.",
452
target_dir_name,bname);
460
if (set_dynamic(&file_names, (uchar*)&rec, file_id))
462
error("Out of memory.");
468
ce->set_fname_outside_temp_buf(fname, strlen(fname));
470
if (my_write(file, (uchar*)block, block_len, MYF(MY_WME|MY_NABP)))
472
error("Failed writing to file.");
475
if (my_close(file, MYF(MY_WME)))
477
error("Failed closing file.");
485
Process the given Create_file_log_event.
487
@see Load_log_processor::process_first_event(const char*,uint,const char*,uint,uint,Create_file_log_event*)
489
@param ce Create_file_log_event to process.
491
@retval ERROR_STOP An error occurred - the program should terminate.
492
@retval OK_CONTINUE No error, the program should continue.
494
Exit_status Load_log_processor::process(Create_file_log_event *ce)
496
const char *bname= ce->fname + dirname_length(ce->fname);
497
uint blen= ce->fname_len - (bname-ce->fname);
499
return process_first_event(bname, blen, ce->block, ce->block_len,
505
Process the given Begin_load_query_log_event.
507
@see Load_log_processor::process_first_event(const char*,uint,const char*,uint,uint,Create_file_log_event*)
509
@param ce Begin_load_query_log_event to process.
511
@retval ERROR_STOP An error occurred - the program should terminate.
512
@retval OK_CONTINUE No error, the program should continue.
514
Exit_status Load_log_processor::process(Begin_load_query_log_event *blqe)
516
return process_first_event("SQL_LOAD_MB", 11, blqe->block, blqe->block_len,
522
Process the given Append_block_log_event.
524
Appends the chunk of the file contents specified by the event to the
525
file created by a previous Begin_load_query_log_event or
526
Create_file_log_event.
528
If the file_id for the event does not correspond to any file
529
previously registered through a Begin_load_query_log_event or
530
Create_file_log_event, this member function will print a warning and
531
return OK_CONTINUE. It is safe to return OK_CONTINUE, because no
532
query will be written for this event. We should not print an error
533
and fail, since the missing file_id could be because a (valid)
534
--start-position has been specified after the Begin/Create event but
535
before this Append event.
537
@param ae Append_block_log_event to process.
539
@retval ERROR_STOP An error occurred - the program should terminate.
541
@retval OK_CONTINUE No error, the program should continue.
543
Exit_status Load_log_processor::process(Append_block_log_event *ae)
546
const char* fname= ((ae->file_id < file_names.elements) ?
547
dynamic_element(&file_names, ae->file_id,
548
File_name_record*)->fname : 0);
553
Exit_status retval= OK_CONTINUE;
554
if (((file= my_open(fname,
555
O_APPEND|O_BINARY|O_WRONLY,MYF(MY_WME))) < 0))
557
error("Failed opening file %s", fname);
560
if (my_write(file,(uchar*)ae->block,ae->block_len,MYF(MY_WME|MY_NABP)))
562
error("Failed writing to file %s", fname);
565
if (my_close(file,MYF(MY_WME)))
567
error("Failed closing file %s", fname);
574
There is no Create_file event (a bad binlog or a big
575
--start-position). Assuming it's a big --start-position, we just do
576
nothing and print a warning.
578
warning("Ignoring Append_block as there is no "
579
"Create_file event for file_id: %u", ae->file_id);
584
static Load_log_processor load_processor;
588
Replace windows-style backslashes by forward slashes so it can be
589
consumed by the drizzle client, which requires Unix path.
591
@todo This is only useful under windows, so may be ifdef'ed out on
594
@todo If a Create_file_log_event contains a filename with a
595
backslash (valid under unix), then we have problems under windows.
598
@param[in,out] fname Filename to modify. The filename is modified
601
static void convert_path_to_forward_slashes(char *fname)
613
Indicates whether the given database should be filtered out,
614
according to the --database=X option.
616
@param log_dbname Name of database.
618
@return nonzero if the database with the given name should be
619
filtered out, 0 otherwise.
621
static bool shall_skip_database(const char *log_dbname)
623
return one_database &&
624
(log_dbname != NULL) &&
625
strcmp(log_dbname, database);
630
Prints the given event in base64 format.
632
The header is printed to the head cache and the body is printed to
633
the body cache of the print_event_info structure. This allows all
634
base64 events corresponding to the same statement to be joined into
635
one BINLOG statement.
637
@param[in] ev Log_event to print.
638
@param[in,out] result_file FILE to which the output will be written.
639
@param[in,out] print_event_info Parameters and context state
640
determining how to print.
642
@retval ERROR_STOP An error occurred - the program should terminate.
643
@retval OK_CONTINUE No error, the program should continue.
646
write_event_header_and_base64(Log_event *ev, FILE *result_file,
647
PRINT_EVENT_INFO *print_event_info)
649
IO_CACHE *head= &print_event_info->head_cache;
650
IO_CACHE *body= &print_event_info->body_cache;
653
/* Write header and base64 output to cache */
654
ev->print_header(head, print_event_info, false);
655
ev->print_base64(body, print_event_info, false);
657
/* Read data from cache and write to result file */
658
if (copy_event_cache_to_file_and_reinit(head, result_file) ||
659
copy_event_cache_to_file_and_reinit(body, result_file))
661
error("Error writing event to file.");
669
Print the given event, and either delete it or delegate the deletion
672
The deletion may be delegated in two cases: (1) the event is a
673
Format_description_log_event, and is saved in
674
glob_description_event; (2) the event is a Create_file_log_event,
675
and is saved in load_processor.
677
@param[in,out] print_event_info Parameters and context state
678
determining how to print.
679
@param[in] ev Log_event to process.
680
@param[in] pos Offset from beginning of binlog file.
681
@param[in] logname Name of input binlog.
683
@retval ERROR_STOP An error occurred - the program should terminate.
684
@retval OK_CONTINUE No error, the program should continue.
685
@retval OK_STOP No error, but the end of the specified range of
686
events to process has been reached and the program should terminate.
688
Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
689
my_off_t pos, const char *logname)
692
Log_event_type ev_type= ev->get_type_code();
694
print_event_info->short_form= short_form;
695
Exit_status retval= OK_CONTINUE;
698
Format events are not concerned by --offset and such, we always need to
699
read them to be able to process the wanted events.
701
if (((rec_count >= offset) && ((my_time_t)(ev->when) >= start_datetime)) || (ev_type == FORMAT_DESCRIPTION_EVENT))
703
if (ev_type != FORMAT_DESCRIPTION_EVENT)
706
We have found an event after start_datetime, from now on print
707
everything (in case the binlog has timestamps increasing and
708
decreasing, we do this to avoid cutting the middle).
711
offset= 0; // print everything and protect against cycling rec_count
713
if (server_id && (server_id != ev->server_id))
714
/* skip just this event, continue processing the log. */
716
if (((my_time_t)(ev->when) >= stop_datetime)
717
|| (pos >= stop_position_mot))
719
/* end the program */
724
fprintf(result_file, "# at %s\n",llstr(pos,ll_buff));
727
print_event_info->hexdump_from= 0; /* Disabled */
729
print_event_info->hexdump_from= pos;
731
print_event_info->base64_output_mode= opt_base64_output_mode;
735
if (shall_skip_database(((Query_log_event*)ev)->db))
737
if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
739
if ((retval= write_event_header_and_base64(ev, result_file,
740
print_event_info)) !=
745
ev->print(result_file, print_event_info);
748
case CREATE_FILE_EVENT:
750
Create_file_log_event* ce= (Create_file_log_event*)ev;
752
We test if this event has to be ignored. If yes, we don't save
753
this event; this will have the good side-effect of ignoring all
754
related Append_block and Exec_load.
755
Note that Load event from 3.23 is not tested.
757
if (shall_skip_database(ce->db))
758
goto end; // Next event
760
We print the event, but with a leading '#': this is just to inform
761
the user of the original command; the command we want to execute
762
will be a derivation of this original command (we will change the
763
filename and use LOCAL), prepared in the 'case EXEC_LOAD_EVENT'
766
if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
768
if ((retval= write_event_header_and_base64(ce, result_file,
769
print_event_info)) !=
774
ce->print(result_file, print_event_info, true);
776
// If this binlog is not 3.23 ; why this test??
777
if (glob_description_event->binlog_version >= 3)
780
transfer the responsibility for destroying the event to
784
if ((retval= load_processor.process(ce)) != OK_CONTINUE)
790
case APPEND_BLOCK_EVENT:
792
Append_block_log_events can safely print themselves even if
793
the subsequent call load_processor.process fails, because the
794
output of Append_block_log_event::print is only a comment.
796
ev->print(result_file, print_event_info);
797
if ((retval= load_processor.process((Append_block_log_event*) ev)) !=
802
case EXEC_LOAD_EVENT:
804
ev->print(result_file, print_event_info);
805
Execute_load_log_event *exv= (Execute_load_log_event*)ev;
806
Create_file_log_event *ce= load_processor.grab_event(exv->file_id);
808
if ce is 0, it probably means that we have not seen the Create_file
809
event (a bad binlog, or most probably --start-position is after the
810
Create_file event). Print a warning comment.
815
We must not convert earlier, since the file is used by
816
my_open() in Load_log_processor::append().
818
convert_path_to_forward_slashes((char*) ce->fname);
819
ce->print(result_file, print_event_info, true);
820
my_free((char*)ce->fname,MYF(MY_WME));
824
warning("Ignoring Execute_load_log_event as there is no "
825
"Create_file event for file_id: %u", exv->file_id);
828
case FORMAT_DESCRIPTION_EVENT:
829
delete glob_description_event;
830
glob_description_event= (Format_description_log_event*) ev;
831
print_event_info->common_header_len=
832
glob_description_event->common_header_len;
833
ev->print(result_file, print_event_info);
834
ev->temp_buf= 0; // as the event ref is zeroed
836
We don't want this event to be deleted now, so let's hide it (I
837
(Guilhem) should later see if this triggers a non-serious Valgrind
838
error). Not serious error, because we will free description_event
842
if (!force_if_open_opt &&
843
(glob_description_event->flags & LOG_EVENT_BINLOG_IN_USE_F))
845
error("Attempting to dump binlog '%s', which was not closed properly. "
846
"Most probably, drizzled is still writing it, or it crashed. "
847
"Rerun with --force-if-open to ignore this problem.", logname);
851
case BEGIN_LOAD_QUERY_EVENT:
852
ev->print(result_file, print_event_info);
853
if ((retval= load_processor.process((Begin_load_query_log_event*) ev)) !=
857
case EXECUTE_LOAD_QUERY_EVENT:
859
Execute_load_query_log_event *exlq= (Execute_load_query_log_event*)ev;
860
char *fname= load_processor.grab_fname(exlq->file_id);
862
if (!shall_skip_database(exlq->db))
866
convert_path_to_forward_slashes(fname);
867
exlq->print(result_file, print_event_info, fname);
870
warning("Ignoring Execute_load_query since there is no "
871
"Begin_load_query event for file_id: %u", exlq->file_id);
875
my_free(fname, MYF(MY_WME));
878
case TABLE_MAP_EVENT:
879
case WRITE_ROWS_EVENT:
880
case DELETE_ROWS_EVENT:
881
case UPDATE_ROWS_EVENT:
882
case PRE_GA_WRITE_ROWS_EVENT:
883
case PRE_GA_DELETE_ROWS_EVENT:
884
case PRE_GA_UPDATE_ROWS_EVENT:
886
These events must be printed in base64 format, if printed.
887
base64 format requires a FD event to be safe, so if no FD
888
event has been printed, we give an error. Except if user
889
passed --short-form, because --short-form disables printing
892
if (!print_event_info->printed_fd_event && !short_form)
894
const char* type_str= ev->get_type_str();
895
if (opt_base64_output_mode == BASE64_OUTPUT_NEVER)
896
error("--base64-output=never specified, but binlog contains a "
897
"%s event which must be printed in base64.",
900
error("malformed binlog: it does not contain any "
901
"Format_description_log_event. I now found a %s event, which "
902
"is not safe to process without a "
903
"Format_description_log_event.",
909
ev->print(result_file, print_event_info);
920
Destroy the log_event object. If reading from a remote host,
921
set the temp_buf to NULL so that memory isn't freed twice.
933
static struct my_option my_long_options[] =
935
{"help", '?', "Display this help and exit.",
936
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
937
{"base64-output", OPT_BASE64_OUTPUT_MODE,
938
"Determine when the output statements should be base64-encoded BINLOG "
939
"statements: 'never' disables it and works only for binlogs without "
940
"row-based events; 'auto' is the default and prints base64 only when "
941
"necessary (i.e., for row-based events and format description events); "
942
"'always' prints base64 whenever possible. 'always' is for debugging "
943
"only and should not be used in a production system. The default is "
944
"'auto'. --base64-output is a short form for --base64-output=always."
945
,(char**) &opt_base64_output_mode_str,
946
(char**) &opt_base64_output_mode_str,
947
0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
949
drizzlebinlog needs charsets knowledge, to be able to convert a charset
950
number found in binlog to a charset name (to be able to print things
952
SET @`a`:=_cp850 0x4DFC6C6C6572 COLLATE `cp850_general_ci`;
954
{"character-sets-dir", OPT_CHARSETS_DIR,
955
"Directory where character sets are.", (char**) &charsets_dir,
956
(char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
957
{"database", 'd', "List entries for just this database (local log only).",
958
(char**) &database, (char**) &database, 0, GET_STR_ALLOC, REQUIRED_ARG,
960
{"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .",
961
(char**) &debug_check_flag, (char**) &debug_check_flag, 0,
962
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
963
{"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
964
(char**) &debug_info_flag, (char**) &debug_info_flag,
965
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
966
{"disable-log-bin", 'D', "Disable binary log. This is useful, if you "
967
"enabled --to-last-log and are sending the output to the same DRIZZLE server. "
968
"This way you could avoid an endless loop. You would also like to use it "
969
"when restoring after a crash to avoid duplication of the statements you "
970
"already have. NOTE: you will need a SUPER privilege to use this option.",
971
(char**) &disable_log_bin, (char**) &disable_log_bin, 0, GET_BOOL,
972
NO_ARG, 0, 0, 0, 0, 0, 0},
973
{"force-if-open", 'F', "Force if binlog was not closed properly.",
974
(char**) &force_if_open_opt, (char**) &force_if_open_opt, 0, GET_BOOL, NO_ARG,
976
{"force-read", 'f', "Force reading unknown binlog events.",
977
(char**) &force_opt, (char**) &force_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
979
{"hexdump", 'H', "Augment output with hexadecimal and ASCII event dump.",
980
(char**) &opt_hexdump, (char**) &opt_hexdump, 0, GET_BOOL, NO_ARG,
982
{"host", 'h', "Get the binlog from server.", (char**) &host, (char**) &host,
983
0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
984
{"local-load", 'l', "Prepare local temporary files for LOAD DATA INFILE in the specified directory.",
985
(char**) &dirname_for_local_load, (char**) &dirname_for_local_load, 0,
986
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
987
{"offset", 'o', "Skip the first N entries.", (char**) &offset, (char**) &offset,
988
0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
989
{"password", 'p', "Password to connect to remote server.",
990
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
991
{"port", 'P', "Port number to use for connection or 0 for default to, in "
992
"order of preference, my.cnf, $MYSQL_TCP_PORT, "
993
#if MYSQL_PORT_DEFAULT == 0
996
"built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
997
(char**) &port, (char**) &port, 0, GET_INT, REQUIRED_ARG,
999
{"position", 'j', "Deprecated. Use --start-position instead.",
1000
(char**) &start_position, (char**) &start_position, 0, GET_ULL,
1001
REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE,
1002
/* COM_BINLOG_DUMP accepts only 4 bytes for the position */
1003
(uint64_t)(~(uint32_t)0), 0, 0, 0},
1004
{"protocol", OPT_DRIZZLE_PROTOCOL,
1005
"The protocol of connection (tcp,socket,pipe,memory).",
1006
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1007
{"read-from-remote-server", 'R', "Read binary logs from a Drizzle server",
1008
(char**) &remote_opt, (char**) &remote_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
1010
{"result-file", 'r', "Direct output to a given file.", 0, 0, 0, GET_STR,
1011
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1012
{"server-id", OPT_SERVER_ID,
1013
"Extract only binlog entries created by the server having the given id.",
1014
(char**) &server_id, (char**) &server_id, 0, GET_ULONG,
1015
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1016
{"set-charset", OPT_SET_CHARSET,
1017
"Add 'SET NAMES character_set' to the output.", (char**) &charset,
1018
(char**) &charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1019
{"short-form", 's', "Just show regular queries: no extra info and no "
1020
"row-based events. This is for testing only, and should not be used in "
1021
"production systems. If you want to suppress base64-output, consider "
1022
"using --base64-output=never instead.",
1023
(char**) &short_form, (char**) &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
1025
{"socket", 'S', "Socket file to use for connection.",
1026
(char**) &sock, (char**) &sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0,
1028
{"start-datetime", OPT_START_DATETIME,
1029
"Start reading the binlog at first event having a datetime equal or "
1030
"posterior to the argument; the argument must be a date and time "
1031
"in the local time zone, in any format accepted by the Drizzle server "
1032
"for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 "
1033
"(you should probably use quotes for your shell to set it properly).",
1034
(char**) &start_datetime_str, (char**) &start_datetime_str,
1035
0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1036
{"start-position", OPT_START_POSITION,
1037
"Start reading the binlog at position N. Applies to the first binlog "
1038
"passed on the command line.",
1039
(char**) &start_position, (char**) &start_position, 0, GET_ULL,
1040
REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE,
1041
/* COM_BINLOG_DUMP accepts only 4 bytes for the position */
1042
(uint64_t)(~(uint32_t)0), 0, 0, 0},
1043
{"stop-datetime", OPT_STOP_DATETIME,
1044
"Stop reading the binlog at first event having a datetime equal or "
1045
"posterior to the argument; the argument must be a date and time "
1046
"in the local time zone, in any format accepted by the Drizzle server "
1047
"for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 "
1048
"(you should probably use quotes for your shell to set it properly).",
1049
(char**) &stop_datetime_str, (char**) &stop_datetime_str,
1050
0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1051
{"stop-position", OPT_STOP_POSITION,
1052
"Stop reading the binlog at position N. Applies to the last binlog "
1053
"passed on the command line.",
1054
(char**) &stop_position, (char**) &stop_position, 0, GET_ULL,
1055
REQUIRED_ARG, (uint64_t)(~(my_off_t)0), BIN_LOG_HEADER_SIZE,
1056
(uint64_t)(~(my_off_t)0), 0, 0, 0},
1057
{"to-last-log", 't', "Requires -R. Will not stop at the end of the \
1058
requested binlog but rather continue printing until the end of the last \
1059
binlog of the DRIZZLE server. If you send the output to the same DRIZZLE server, \
1060
that may lead to an endless loop.",
1061
(char**) &to_last_remote_log, (char**) &to_last_remote_log, 0, GET_BOOL,
1062
NO_ARG, 0, 0, 0, 0, 0, 0},
1063
{"user", 'u', "Connect to the remote server as username.",
1064
(char**) &user, (char**) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0,
1066
{"version", 'V', "Print version and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
1068
{"open_files_limit", OPT_OPEN_FILES_LIMIT,
1069
"Used to reserve file descriptors for usage by this program",
1070
(char**) &open_files_limit, (char**) &open_files_limit, 0, GET_ULONG,
1071
REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0},
1072
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
1077
Auxiliary function used by error() and warning().
1079
Prints the given text (normally "WARNING: " or "ERROR: "), followed
1080
by the given vprintf-style string, followed by a newline.
1082
@param format Printf-style format string.
1083
@param args List of arguments for the format string.
1084
@param msg Text to print before the string.
1086
static void error_or_warning(const char *format, va_list args, const char *msg)
1088
fprintf(stderr, "%s: ", msg);
1089
vfprintf(stderr, format, args);
1090
fprintf(stderr, "\n");
1094
Prints a message to stderr, prefixed with the text "ERROR: " and
1095
suffixed with a newline.
1097
@param format Printf-style format string, followed by printf
1100
static void error(const char *format,...)
1103
va_start(args, format);
1104
error_or_warning(format, args, "ERROR");
1110
This function is used in log_event.cc to report errors.
1112
@param format Printf-style format string, followed by printf
1115
static void sql_print_error(const char *format,...)
1118
va_start(args, format);
1119
error_or_warning(format, args, "ERROR");
1124
Prints a message to stderr, prefixed with the text "WARNING: " and
1125
suffixed with a newline.
1127
@param format Printf-style format string, followed by printf
1130
static void warning(const char *format,...)
1133
va_start(args, format);
1134
error_or_warning(format, args, "WARNING");
1139
Frees memory for global variables in this file.
1141
static void cleanup()
1143
my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
1144
my_free((char*) database, MYF(MY_ALLOW_ZERO_PTR));
1145
my_free((char*) host, MYF(MY_ALLOW_ZERO_PTR));
1146
my_free((char*) user, MYF(MY_ALLOW_ZERO_PTR));
1147
my_free((char*) dirname_for_local_load, MYF(MY_ALLOW_ZERO_PTR));
1149
delete glob_description_event;
1151
drizzle_close(drizzle);
1154
static void print_version()
1156
printf("%s Ver 3.3 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE);
1162
puts("By Monty and Sasha, for your professional use\n\
1163
This software comes with NO WARRANTY: This is free software,\n\
1164
and you are welcome to modify and redistribute it under the GPL license\n");
1167
Dumps a DRIZZLE binary log in a format usable for viewing or for piping to\n\
1168
the Drizzle command line client\n\n");
1169
printf("Usage: %s [options] log-files\n", my_progname);
1170
my_print_help(my_long_options);
1171
my_print_variables(my_long_options);
1175
static my_time_t convert_str_to_timestamp(const char* str)
1178
DRIZZLE_TIME l_time;
1179
long dummy_my_timezone;
1180
bool dummy_in_dst_time_gap;
1181
/* We require a total specification (date AND time) */
1182
if (str_to_datetime(str, strlen(str), &l_time, 0, &was_cut) !=
1183
DRIZZLE_TIMESTAMP_DATETIME || was_cut)
1185
error("Incorrect date and time argument: %s", str);
1189
Note that Feb 30th, Apr 31st cause no error messages and are mapped to
1190
the next existing day, like in drizzled. Maybe this could be changed when
1191
drizzled is changed too (with its "strict" mode?).
1194
my_system_gmt_sec(&l_time, &dummy_my_timezone, &dummy_in_dst_time_gap);
1198
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
1201
bool tty_password=0;
1209
my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
1210
char *start=argument;
1211
pass= my_strdup(argument,MYF(MY_FAE));
1212
while (*argument) *argument++= 'x'; /* Destroy argument */
1214
start[1]=0; /* Cut length of argument */
1220
if (!(result_file = my_fopen(argument, O_WRONLY | O_BINARY, MYF(MY_WME))))
1226
case OPT_DRIZZLE_PROTOCOL:
1227
opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
1230
case OPT_START_DATETIME:
1231
start_datetime= convert_str_to_timestamp(start_datetime_str);
1233
case OPT_STOP_DATETIME:
1234
stop_datetime= convert_str_to_timestamp(stop_datetime_str);
1236
case OPT_BASE64_OUTPUT_MODE:
1237
if (argument == NULL)
1238
opt_base64_output_mode= BASE64_OUTPUT_ALWAYS;
1241
opt_base64_output_mode= (enum_base64_output_mode)
1242
(find_type_or_exit(argument, &base64_output_mode_typelib, opt->name)-1);
1253
pass= get_tty_password(NullS);
1259
static int parse_args(int *argc, char*** argv)
1263
result_file = stdout;
1264
load_defaults("my",load_default_groups,argc,argv);
1265
if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
1267
if (debug_info_flag)
1268
my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
1269
if (debug_check_flag)
1270
my_end_arg= MY_CHECK_ERROR;
1276
Create and initialize the global drizzle object, and connect to the
1279
@retval ERROR_STOP An error occurred - the program should terminate.
1280
@retval OK_CONTINUE No error, the program should continue.
1282
static Exit_status safe_connect()
1284
drizzle= drizzle_create(NULL);
1288
error("Failed on drizzle_create.");
1293
drizzle_options(drizzle, DRIZZLE_OPT_PROTOCOL, (char*) &opt_protocol);
1294
if (!drizzle_connect(drizzle, host, user, pass, 0, port, sock, 0))
1296
error("Failed on connect: %s", drizzle_error(drizzle));
1299
drizzle->reconnect= 1;
1305
High-level function for dumping a named binlog.
1307
This function calls dump_remote_log_entries() or
1308
dump_local_log_entries() to do the job.
1310
@param[in] logname Name of input binlog.
1312
@retval ERROR_STOP An error occurred - the program should terminate.
1313
@retval OK_CONTINUE No error, the program should continue.
1314
@retval OK_STOP No error, but the end of the specified range of
1315
events to process has been reached and the program should terminate.
1317
static Exit_status dump_log_entries(const char* logname)
1320
PRINT_EVENT_INFO print_event_info;
1322
if (!print_event_info.init_ok())
1325
Set safe delimiter, to dump things
1326
like CREATE PROCEDURE safely
1328
fprintf(result_file, "DELIMITER /*!*/;\n");
1329
strmov(print_event_info.delimiter, "/*!*/;");
1331
rc= (remote_opt ? dump_remote_log_entries(&print_event_info, logname) :
1332
dump_local_log_entries(&print_event_info, logname));
1334
/* Set delimiter back to semicolon */
1335
fprintf(result_file, "DELIMITER ;\n");
1336
strmov(print_event_info.delimiter, ";");
1342
When reading a remote binlog, this function is used to grab the
1343
Format_description_log_event in the beginning of the stream.
1345
This is not as smart as check_header() (used for local log); it will
1346
not work for a binlog which mixes format. TODO: fix this.
1348
@retval ERROR_STOP An error occurred - the program should terminate.
1349
@retval OK_CONTINUE No error, the program should continue.
1351
static Exit_status check_master_version()
1353
DRIZZLE_RES* res = 0;
1355
const char* version;
1357
if (drizzle_query(drizzle, "SELECT VERSION()") ||
1358
!(res = drizzle_store_result(drizzle)))
1360
error("Could not find server version: "
1361
"Query failed when checking master version: %s", drizzle_error(drizzle));
1364
if (!(row = drizzle_fetch_row(res)))
1366
error("Could not find server version: "
1367
"Master returned no rows for SELECT VERSION().");
1371
if (!(version = row[0]))
1373
error("Could not find server version: "
1374
"Master reported NULL for the version.");
1378
delete glob_description_event;
1381
glob_description_event= new Format_description_log_event(1);
1384
glob_description_event= new Format_description_log_event(3);
1389
The server is soon going to send us its Format_description log
1390
event, unless it is a 5.0 server with 3.23 or 4.0 binlogs.
1391
So we first assume that this is 4.0 (which is enough to read the
1392
Format_desc event if one comes).
1394
glob_description_event= new Format_description_log_event(3);
1397
glob_description_event= NULL;
1398
error("Could not find server version: "
1399
"Master reported unrecognized Drizzle version '%s'.", version);
1402
if (!glob_description_event || !glob_description_event->is_valid())
1404
error("Failed creating Format_description_log_event; out of memory?");
1408
drizzle_free_result(res);
1412
drizzle_free_result(res);
1418
Requests binlog dump from a remote server and prints the events it
1421
@param[in,out] print_event_info Parameters and context state
1422
determining how to print.
1423
@param[in] logname Name of input binlog.
1425
@retval ERROR_STOP An error occurred - the program should terminate.
1426
@retval OK_CONTINUE No error, the program should continue.
1427
@retval OK_STOP No error, but the end of the specified range of
1428
events to process has been reached and the program should terminate.
1430
static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
1431
const char* logname)
1438
my_off_t old_off= start_position_mot;
1439
char fname[FN_REFLEN+1];
1440
Exit_status retval= OK_CONTINUE;
1444
Even if we already read one binlog (case of >=2 binlogs on command line),
1445
we cannot re-use the same connection as before, because it is now dead
1446
(COM_BINLOG_DUMP kills the thread when it finishes).
1448
if ((retval= safe_connect()) != OK_CONTINUE)
1452
if ((retval= check_master_version()) != OK_CONTINUE)
1456
COM_BINLOG_DUMP accepts only 4 bytes for the position, so we are forced to
1459
int4store(buf, (uint32_t)start_position);
1460
int2store(buf + BIN_LOG_HEADER_SIZE, binlog_flags);
1462
size_t tlen = strlen(logname);
1463
if (tlen > UINT_MAX)
1465
error("Log name too long.");
1468
logname_len = (uint) tlen;
1469
int4store(buf + 6, 0);
1470
memcpy(buf + 10, logname, logname_len);
1471
if (simple_command(drizzle, COM_BINLOG_DUMP, buf, logname_len + 10, 1))
1473
error("Got fatal error sending the log dump command.");
1479
const char *error_msg;
1482
len= cli_safe_read(drizzle);
1483
if (len == packet_error)
1485
error("Got error reading packet from server: %s", drizzle_error(drizzle));
1488
if (len < 8 && net->read_pos[0] == 254)
1489
break; // end of data
1490
if (!(ev= Log_event::read_log_event((const char*) net->read_pos + 1 ,
1491
len - 1, &error_msg,
1492
glob_description_event)))
1494
error("Could not construct log event object: %s", error_msg);
1498
If reading from a remote host, ensure the temp_buf for the
1499
Log_event class is pointing to the incoming stream.
1502
ev->register_temp_buf((char*) net->read_pos + 1);
1504
Log_event_type type= ev->get_type_code();
1505
if (glob_description_event->binlog_version >= 3 ||
1506
(type != LOAD_EVENT && type != CREATE_FILE_EVENT))
1509
If this is a Rotate event, maybe it's the end of the requested binlog;
1510
in this case we are done (stop transfer).
1511
This is suitable for binlogs, not relay logs (but for now we don't read
1512
relay logs remotely because the server is not able to do that). If one
1513
day we read relay logs remotely, then we will have a problem with the
1514
detection below: relay logs contain Rotate events which are about the
1515
binlogs, so which would trigger the end-detection below.
1517
if (type == ROTATE_EVENT)
1519
Rotate_log_event *rev= (Rotate_log_event *)ev;
1521
If this is a fake Rotate event, and not about our log, we can stop
1522
transfer. If this a real Rotate event (so it's not about our log,
1523
it's in our log describing the next log), we print it (because it's
1524
part of our log) and then we will stop when we receive the fake one
1529
if (!to_last_remote_log)
1531
if ((rev->ident_len != logname_len) ||
1532
memcmp(rev->new_log_ident, logname, logname_len))
1534
return(OK_CONTINUE);
1537
Otherwise, this is a fake Rotate for our log, at the very
1538
beginning for sure. Skip it, because it was not in the original
1539
log. If we are running with to_last_remote_log, we print it,
1540
because it serves as a useful marker between binlogs then.
1544
len= 1; // fake Rotate, so don't increment old_off
1547
else if (type == FORMAT_DESCRIPTION_EVENT)
1550
This could be an fake Format_description_log_event that server
1551
(5.0+) automatically sends to a slave on connect, before sending
1552
a first event at the requested position. If this is the case,
1553
don't increment old_off. Real Format_description_log_event always
1554
starts from BIN_LOG_HEADER_SIZE position.
1556
if (old_off != BIN_LOG_HEADER_SIZE)
1557
len= 1; // fake event, don't increment old_off
1559
Exit_status retval= process_event(print_event_info, ev, old_off, logname);
1560
if (retval != OK_CONTINUE)
1565
Load_log_event *le= (Load_log_event*)ev;
1566
const char *old_fname= le->fname;
1567
uint old_len= le->fname_len;
1571
if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0)
1574
retval= process_event(print_event_info, ev, old_off, logname);
1575
if (retval != OK_CONTINUE)
1577
my_close(file,MYF(MY_WME));
1580
retval= load_processor.load_old_format_file(net,old_fname,old_len,file);
1581
my_close(file,MYF(MY_WME));
1582
if (retval != OK_CONTINUE)
1586
Let's adjust offset for remote log as for local log to produce
1587
similar text and to have --stop-position to work identically.
1592
return(OK_CONTINUE);
1597
Reads the @c Format_description_log_event from the beginning of a
1600
The @c Format_description_log_event is only read if it is outside
1601
the range specified with @c --start-position; otherwise, it will be
1602
seen later. If this is an old binlog, a fake @c
1603
Format_description_event is created. This also prints a @c
1604
Format_description_log_event to the output, unless we reach the
1605
--start-position range. In this case, it is assumed that a @c
1606
Format_description_log_event will be found when reading events the
1609
@param file The file to which a @c Format_description_log_event will
1612
@param[in,out] print_event_info Parameters and context state
1613
determining how to print.
1615
@param[in] logname Name of input binlog.
1617
@retval ERROR_STOP An error occurred - the program should terminate.
1618
@retval OK_CONTINUE No error, the program should continue.
1619
@retval OK_STOP No error, but the end of the specified range of
1620
events to process has been reached and the program should terminate.
1622
static Exit_status check_header(IO_CACHE* file,
1623
PRINT_EVENT_INFO *print_event_info,
1624
const char* logname)
1626
uchar header[BIN_LOG_HEADER_SIZE];
1627
uchar buf[PROBE_HEADER_LEN];
1628
uint64_t tmp_pos, pos;
1630
delete glob_description_event;
1631
if (!(glob_description_event= new Format_description_log_event(3)))
1633
error("Failed creating Format_description_log_event; out of memory?");
1637
pos= my_b_tell(file);
1638
my_b_seek(file, (my_off_t)0);
1639
if (my_b_read(file, header, sizeof(header)))
1641
error("Failed reading header; probably an empty file.");
1644
if (memcmp(header, BINLOG_MAGIC, sizeof(header)))
1646
error("File is not a binary log file.");
1651
Imagine we are running with --start-position=1000. We still need
1652
to know the binlog format's. So we still need to find, if there is
1653
one, the Format_desc event, or to know if this is a 3.23
1654
binlog. So we need to first read the first events of the log,
1655
those around offset 4. Even if we are reading a 3.23 binlog from
1656
the start (no --start-position): we need to know the header length
1657
(which is 13 in 3.23, 19 in 4.x) to be able to successfully print
1658
the first event (Start_log_event_v3). So even in this case, we
1659
need to "probe" the first bytes of the log *before* we do a real
1660
read_log_event(). Because read_log_event() needs to know the
1661
header's length to work fine.
1665
tmp_pos= my_b_tell(file); /* should be 4 the first time */
1666
if (my_b_read(file, buf, sizeof(buf)))
1670
error("Could not read entry at offset %"PRIu64": "
1671
"Error in log format or read error.", tmp_pos);
1675
Otherwise this is just EOF : this log currently contains 0-2
1676
events. Maybe it's going to be filled in the next
1677
milliseconds; then we are going to have a problem if this a
1678
3.23 log (imagine we are locally reading a 3.23 binlog which
1679
is being written presently): we won't know it in
1680
read_log_event() and will fail(). Similar problems could
1681
happen with hot relay logs if --start-position is used (but a
1682
--start-position which is posterior to the current size of the log).
1683
These are rare problems anyway (reading a hot log + when we
1684
read the first events there are not all there yet + when we
1685
read a bit later there are more events + using a strange
1692
/* always test for a Start_v3, even if no --start-position */
1693
if (buf[EVENT_TYPE_OFFSET] == START_EVENT_V3)
1695
/* This is 3.23 or 4.x */
1696
if (uint4korr(buf + EVENT_LEN_OFFSET) <
1697
(LOG_EVENT_MINIMAL_HEADER_LEN + START_V3_HEADER_LEN))
1699
/* This is 3.23 (format 1) */
1700
delete glob_description_event;
1701
if (!(glob_description_event= new Format_description_log_event(1)))
1703
error("Failed creating Format_description_log_event; "
1710
else if (tmp_pos >= start_position)
1712
else if (buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT)
1715
Format_description_log_event *new_description_event;
1716
my_b_seek(file, tmp_pos); /* seek back to event's start */
1717
if (!(new_description_event= (Format_description_log_event*)
1718
Log_event::read_log_event(file, glob_description_event)))
1719
/* EOF can't be hit here normally, so it's a real error */
1721
error("Could not read a Format_description_log_event event at "
1722
"offset %"PRIu64"; this could be a log format error or read error.",
1726
if (opt_base64_output_mode == BASE64_OUTPUT_AUTO
1727
|| opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
1730
process_event will delete *description_event and set it to
1731
the new one, so we should not do it ourselves in this
1734
Exit_status retval= process_event(print_event_info,
1735
new_description_event, tmp_pos,
1737
if (retval != OK_CONTINUE)
1742
delete glob_description_event;
1743
glob_description_event= new_description_event;
1746
else if (buf[EVENT_TYPE_OFFSET] == ROTATE_EVENT)
1749
my_b_seek(file, tmp_pos); /* seek back to event's start */
1750
if (!(ev= Log_event::read_log_event(file, glob_description_event)))
1752
/* EOF can't be hit here normally, so it's a real error */
1753
error("Could not read a Rotate_log_event event at offset "
1755
" this could be a log format error or read error.",
1765
my_b_seek(file, pos);
1771
Reads a local binlog and prints the events it sees.
1773
@param[in] logname Name of input binlog.
1775
@param[in,out] print_event_info Parameters and context state
1776
determining how to print.
1778
@retval ERROR_STOP An error occurred - the program should terminate.
1779
@retval OK_CONTINUE No error, the program should continue.
1780
@retval OK_STOP No error, but the end of the specified range of
1781
events to process has been reached and the program should terminate.
1783
static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
1784
const char* logname)
1787
IO_CACHE cache,*file= &cache;
1788
uchar tmp_buff[BIN_LOG_HEADER_SIZE];
1789
Exit_status retval= OK_CONTINUE;
1791
if (logname && strcmp(logname, "-") != 0)
1793
/* read from normal file */
1794
if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
1796
if (init_io_cache(file, fd, 0, READ_CACHE, start_position_mot, 0,
1797
MYF(MY_WME | MY_NABP)))
1799
my_close(fd, MYF(MY_WME));
1802
if ((retval= check_header(file, print_event_info, logname)) != OK_CONTINUE)
1807
if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
1808
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
1810
error("Failed to init IO cache.");
1813
if ((retval= check_header(file, print_event_info, logname)) != OK_CONTINUE)
1817
/* skip 'start_position' characters from stdin */
1818
uchar buff[IO_SIZE];
1819
my_off_t length,tmp;
1820
for (length= start_position_mot ; length > 0 ; length-=tmp)
1822
tmp=min(length,sizeof(buff));
1823
if (my_b_read(file, buff, (uint) tmp))
1825
error("Failed reading from file.");
1832
if (!glob_description_event || !glob_description_event->is_valid())
1834
error("Invalid Format_description log event; could be out of memory.");
1838
if (!start_position && my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE))
1840
error("Failed reading from file.");
1846
my_off_t old_off = my_b_tell(file);
1848
Log_event* ev = Log_event::read_log_event(file, glob_description_event);
1852
if binlog wasn't closed properly ("in use" flag is set) don't complain
1853
about a corruption, but treat it as EOF and move to the next binlog.
1855
if (glob_description_event->flags & LOG_EVENT_BINLOG_IN_USE_F)
1857
else if (file->error)
1859
error("Could not read entry at offset %s: "
1860
"Error in log format or read error.",
1861
llstr(old_off,llbuff));
1864
// file->error == 0 means EOF, that's OK, we break in this case
1867
if ((retval= process_event(print_event_info, ev, old_off, logname)) !=
1879
my_close(fd, MYF(MY_WME));
1885
int main(int argc, char** argv)
1887
char **defaults_argv;
1888
Exit_status retval= OK_CONTINUE;
1889
uint64_t save_stop_position;
1892
init_time(); // for time functions
1894
parse_args(&argc, (char***)&argv);
1900
free_defaults(defaults_argv);
1904
if (opt_base64_output_mode == BASE64_OUTPUT_UNSPEC)
1905
opt_base64_output_mode= BASE64_OUTPUT_AUTO;
1907
my_set_max_open_files(open_files_limit);
1911
if (!dirname_for_local_load)
1913
if (init_tmpdir(&tmpdir, 0))
1915
dirname_for_local_load= my_strdup(my_tmpdir(&tmpdir), MY_WME);
1918
if (load_processor.init())
1920
if (dirname_for_local_load)
1921
load_processor.init_by_dir_name(dirname_for_local_load);
1923
load_processor.init_by_cur_dir();
1925
fprintf(result_file,
1926
"/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n");
1928
if (disable_log_bin)
1929
fprintf(result_file,
1930
"/*!32316 SET @OLD_SQL_LOG_BIN=@@SQL_LOG_BIN, SQL_LOG_BIN=0*/;\n");
1933
In drizzlebinlog|drizzle, don't want Drizzle to be disconnected after each
1934
transaction (which would be the case with GLOBAL.COMPLETION_TYPE==2).
1936
fprintf(result_file,
1937
"/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,"
1938
"COMPLETION_TYPE=0*/;\n");
1941
fprintf(result_file,
1942
"\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
1943
"\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
1944
"\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
1945
"\n/*!40101 SET NAMES %s */;\n", charset);
1947
for (save_stop_position= stop_position, stop_position= ~(my_off_t)0 ;
1950
if (argc == 0) // last log, --stop-position applies
1951
stop_position= save_stop_position;
1952
if ((retval= dump_log_entries(*argv++)) != OK_CONTINUE)
1955
// For next log, --start-position does not apply
1956
start_position= BIN_LOG_HEADER_SIZE;
1960
Issue a ROLLBACK in case the last printed binlog was crashed and had half
1963
fprintf(result_file,
1964
"# End of log file\nROLLBACK /* added by drizzlebinlog */;\n"
1965
"/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;\n");
1966
if (disable_log_bin)
1967
fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n");
1970
fprintf(result_file,
1971
"/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"
1972
"/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"
1973
"/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n");
1976
free_tmpdir(&tmpdir);
1977
if (result_file != stdout)
1978
my_fclose(result_file, MYF(0));
1980
free_defaults(defaults_argv);
1981
my_free_open_file_info();
1982
load_processor.destroy();
1985
exit(retval == ERROR_STOP ? 1 : 0);
1989
We must include this here as it's compiled with different options for
1993
#include <drizzled/log_event.cc>