1 /*
2 Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 /*
26
27 TODO: print the catalog (some USE catalog.db ????).
28
29 Standalone program to read a MySQL binary log (or relay log).
30
31 Should be able to read any file of these categories, even with
32 --start-position.
33 An important fact: the Format_desc event of the log is at most the 3rd event
34 of the log; if it is the 3rd then there is this combination:
35 Format_desc_of_slave, Rotate_of_master, Format_desc_of_master.
36 */
37
38 #define MYSQL_CLIENT
39 #undef MYSQL_SERVER
40 #include "client_priv.h"
41 #include "my_default.h"
42 #include <my_time.h>
43 #include <sslopt-vars.h>
44 #include <caching_sha2_passwordopt-vars.h>
45 /* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */
46 #include "query_options.h"
47 #include <signal.h>
48 #include <my_dir.h>
49
50 #include "prealloced_array.h"
51
52 /*
53 error() is used in macro BINLOG_ERROR which is invoked in
54 rpl_gtid.h, hence the early forward declaration.
55 */
56 static void error(const char *format, ...)
57 MY_ATTRIBUTE((format(printf, 1, 2)));
58 static void warning(const char *format, ...)
59 MY_ATTRIBUTE((format(printf, 1, 2)));
60
61 #include "rpl_gtid.h"
62 #include "log_event.h"
63 #include "log_event_old.h"
64 #include "sql_common.h"
65 #include "my_dir.h"
66 #include <welcome_copyright_notice.h> // ORACLE_WELCOME_COPYRIGHT_NOTICE
67 #include "sql_string.h"
68 #include "my_decimal.h"
69 #include "rpl_constants.h"
70
71 #include <algorithm>
72 #include <utility>
73 #include <map>
74
75 using std::min;
76 using std::max;
77
78 /*
79 Map containing the names of databases to be rewritten,
80 to a different one.
81 */
82 static
83 std::map<std::string, std::string> map_mysqlbinlog_rewrite_db;
84
85 /**
86 The function represents Log_event delete wrapper
87 to reset possibly active temp_buf member.
88 It's to be invoked in context where the member is
89 not bound with dynamically allocated memory and therefore can
90 be reset as simple as with plain assignment to NULL.
91
92 @param ev a pointer to Log_event instance
93 */
reset_temp_buf_and_delete(Log_event * ev)94 inline void reset_temp_buf_and_delete(Log_event *ev)
95 {
96 char *event_buf= ev->temp_buf;
97 ev->temp_buf= NULL;
98 delete ev;
99 my_free(event_buf);
100 }
101
102 static bool
rewrite_db(char ** buf,ulong * buf_size,uint offset_db,uint offset_len)103 rewrite_db(char **buf, ulong *buf_size,
104 uint offset_db, uint offset_len)
105 {
106 char* ptr= *buf;
107 char* old_db= ptr + offset_db;
108 uint old_db_len= (uint) ptr[offset_len];
109 std::map<std::string, std::string>::iterator new_db_it=
110 map_mysqlbinlog_rewrite_db.find(std::string(old_db, old_db_len));
111 if (new_db_it == map_mysqlbinlog_rewrite_db.end())
112 return false;
113 const char *new_db=new_db_it->second.c_str();
114 DBUG_ASSERT(new_db && new_db != old_db);
115
116 size_t new_db_len= strlen(new_db);
117
118 // Reallocate buffer if needed.
119 if (new_db_len > old_db_len)
120 {
121 char *new_buf= (char *) my_realloc(PSI_NOT_INSTRUMENTED, *buf,
122 *buf_size + new_db_len - old_db_len, MYF(0));
123 if (!new_buf)
124 return true;
125 *buf= new_buf;
126 }
127
128 // Move the tail of buffer to the correct place.
129 if (new_db_len != old_db_len)
130 memmove(*buf + offset_db + new_db_len,
131 *buf + offset_db + old_db_len,
132 *buf_size - (offset_db + old_db_len));
133
134 // Write new_db and new_db_len.
135 memcpy((*buf) + offset_db, new_db, new_db_len);
136 (*buf)[offset_len]= (char) new_db_len;
137
138 // Update event length in header.
139 int4store((*buf) + EVENT_LEN_OFFSET, (*buf_size) - old_db_len + new_db_len);
140
141 // finally update the event len argument
142 *buf_size= (*buf_size) - old_db_len + new_db_len;
143
144 return false;
145 }
146
147 /**
148 Replace the database by another database in the buffer of a
149 Table_map_log_event.
150
151 The TABLE_MAP event buffer structure :
152
153 Before Rewriting :
154
155 +-------------+-----------+----------+------+----------------+
156 |common_header|post_header|old_db_len|old_db|event data... |
157 +-------------+-----------+----------+------+----------------+
158
159 After Rewriting :
160
161 +-------------+-----------+----------+------+----------------+
162 |common_header|post_header|new_db_len|new_db|event data... |
163 +-------------+-----------+----------+------+----------------+
164
165 In case the new database name is longer than the old database
166 length, it will reallocate the buffer.
167
168 @param[in,out] buf Pointer to event buffer to be processed
169 @param[in,out] event_len Length of the event
170 @param[in] fde The Format_description_log_event
171
172 @retval false Success
173 @retval true Out of memory
174 */
175 bool
rewrite_db_in_buffer(char ** buf,ulong * event_len,const Format_description_log_event * fde)176 Table_map_log_event::rewrite_db_in_buffer(char **buf, ulong *event_len,
177 const Format_description_log_event *fde)
178 {
179 uint headers_len= fde->common_header_len +
180 fde->post_header_len[binary_log::TABLE_MAP_EVENT - 1];
181
182 return rewrite_db(buf, event_len, headers_len+1, headers_len);
183 }
184
185 /**
186 Replace the database by another database in the buffer of a
187 Query_log_event.
188
189 The QUERY_EVENT buffer structure:
190
191 Before Rewriting :
192
193 +-------------+-----------+-----------+------+------+
194 |common_header|post_header|status_vars|old_db|... |
195 +-------------+-----------+-----------+------+------+
196
197 After Rewriting :
198
199 +-------------+-----------+-----------+------+------+
200 |common_header|post_header|status_vars|new_db|... |
201 +-------------+-----------+-----------+------+------+
202
203 The db_len is inside the post header, more specifically:
204
205 +---------+---------+------+--------+--------+------+
206 |thread_id|exec_time|db_len|err_code|status_vars_len|
207 +---------+---------+------+--------+--------+------+
208
209 Thence we need to change the post header and the payload,
210 which is the one carrying the database name.
211
212 In case the new database name is longer than the old database
213 length, it will reallocate the buffer.
214
215 @param[in,out] buf Pointer to event buffer to be processed
216 @param[in,out] event_len Length of the event
217 @param[in] fde The Format_description_log_event
218
219 @retval false Success
220 @retval true Out of memory
221 */
222 bool
rewrite_db_in_buffer(char ** buf,ulong * event_len,const Format_description_log_event * fde)223 Query_log_event::rewrite_db_in_buffer(char **buf, ulong *event_len,
224 const Format_description_log_event *fde)
225 {
226 uint8 common_header_len= fde->common_header_len;
227 uint8 query_header_len= fde->post_header_len[binary_log::QUERY_EVENT-1];
228 char* ptr= *buf;
229 uint sv_len= 0;
230
231 DBUG_EXECUTE_IF("simulate_corrupt_event_len", *event_len=0;);
232 /* Error if the event content is too small */
233 if (*event_len < (common_header_len + query_header_len))
234 return true;
235
236 /* Check if there are status variables in the event */
237 if ((query_header_len - QUERY_HEADER_MINIMAL_LEN) > 0)
238 {
239 sv_len= uint2korr(ptr + common_header_len + Q_STATUS_VARS_LEN_OFFSET);
240 }
241
242 /* now we have a pointer to the position where the database is. */
243 uint offset_len= common_header_len + Q_DB_LEN_OFFSET;
244 uint offset_db= common_header_len + query_header_len + sv_len;
245
246 if ((uint)((*buf)[EVENT_TYPE_OFFSET]) == binary_log::EXECUTE_LOAD_QUERY_EVENT)
247 offset_db+= Binary_log_event::EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN;
248
249 return rewrite_db(buf, event_len, offset_db, offset_len);
250 }
251
252
253 static
rewrite_db_filter(char ** buf,ulong * event_len,const Format_description_log_event * fde)254 bool rewrite_db_filter(char **buf, ulong *event_len,
255 const Format_description_log_event *fde)
256 {
257 if (map_mysqlbinlog_rewrite_db.empty())
258 return false;
259
260 uint event_type= (uint)((*buf)[EVENT_TYPE_OFFSET]);
261
262 switch(event_type)
263 {
264 case binary_log::TABLE_MAP_EVENT:
265 return Table_map_log_event::rewrite_db_in_buffer(buf, event_len, fde);
266 case binary_log::QUERY_EVENT:
267 case binary_log::EXECUTE_LOAD_QUERY_EVENT:
268 return Query_log_event::rewrite_db_in_buffer(buf, event_len, fde);
269 default:
270 break;
271 }
272 return false;
273 }
274
275 /*
276 The character set used should be equal to the one used in mysqld.cc for
277 server rewrite-db
278 */
279 #define mysqld_charset &my_charset_latin1
280
281 #define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
282
283 char server_version[SERVER_VERSION_LENGTH];
284 ulong filter_server_id = 0;
285
286 /*
287 This strucure is used to store the event and the log postion of the events
288 which is later used to print the event details from correct log postions.
289 The Log_event *event is used to store the pointer to the current event and
290 the event_pos is used to store the current event log postion.
291 */
292 struct buff_event_info
293 {
294 Log_event *event;
295 my_off_t event_pos;
296 };
297
298 /*
299 One statement can result in a sequence of several events: Intvar_log_events,
300 User_var_log_events, and Rand_log_events, followed by one
301 Query_log_event. If statements are filtered out, the filter has to be
302 checked for the Query_log_event. So we have to buffer the Intvar,
303 User_var, and Rand events and their corresponding log postions until we see
304 the Query_log_event. This dynamic array buff_ev is used to buffer a structure
305 which stores such an event and the corresponding log position.
306 */
307 typedef Prealloced_array<buff_event_info, 16, true> Buff_ev;
308 Buff_ev *buff_ev(PSI_NOT_INSTRUMENTED);
309
310 // needed by net_serv.c
311 ulong bytes_sent = 0L, bytes_received = 0L;
312 ulong mysqld_net_retry_count = 10L;
313 ulong open_files_limit;
314 ulong opt_binlog_rows_event_max_size;
315 uint test_flags = 0;
316 static uint opt_protocol= 0;
317 static FILE *result_file;
318
319 #ifndef DBUG_OFF
320 static const char* default_dbug_option = "d:t:o,/tmp/mysqlbinlog.trace";
321 #endif
322 static const char *load_default_groups[]= { "mysqlbinlog","client",0 };
323
324 static my_bool one_database=0, disable_log_bin= 0;
325 static my_bool opt_hexdump= 0;
326 const char *base64_output_mode_names[]=
327 {"NEVER", "AUTO", "UNSPEC", "DECODE-ROWS", NullS};
328 TYPELIB base64_output_mode_typelib=
329 { array_elements(base64_output_mode_names) - 1, "",
330 base64_output_mode_names, NULL };
331 static enum_base64_output_mode opt_base64_output_mode= BASE64_OUTPUT_UNSPEC;
332 static char *opt_base64_output_mode_str= 0;
333 static my_bool opt_remote_alias= 0;
334 const char *remote_proto_names[]=
335 {"BINLOG-DUMP-NON-GTIDS", "BINLOG-DUMP-GTIDS", NullS};
336 TYPELIB remote_proto_typelib=
337 { array_elements(remote_proto_names) - 1, "",
338 remote_proto_names, NULL };
339 static enum enum_remote_proto {
340 BINLOG_DUMP_NON_GTID= 0,
341 BINLOG_DUMP_GTID= 1,
342 BINLOG_LOCAL= 2
343 } opt_remote_proto= BINLOG_LOCAL;
344 static char *opt_remote_proto_str= 0;
345 static char *database= 0;
346 static char *output_file= 0;
347 static char *rewrite= 0;
348 static my_bool force_opt= 0, short_form= 0, idempotent_mode= 0;
349 static my_bool debug_info_flag, debug_check_flag;
350 static my_bool force_if_open_opt= 1, raw_mode= 0;
351 static my_bool to_last_remote_log= 0, stop_never= 0;
352 static my_bool opt_verify_binlog_checksum= 1;
353 static ulonglong offset = 0;
354 static int64 stop_never_slave_server_id= -1;
355 static int64 connection_server_id= -1;
356 static char* host = 0;
357 static int port= 0;
358 static uint my_end_arg;
359 static const char* sock= 0;
360 static char *opt_plugin_dir= 0, *opt_default_auth= 0;
361 static my_bool opt_secure_auth= TRUE;
362
363 #if defined (_WIN32) && !defined (EMBEDDED_LIBRARY)
364 static char *shared_memory_base_name= 0;
365 #endif
366 static char* user = 0;
367 static char* pass = 0;
368 static char *opt_bind_addr = NULL;
369 static char *charset= 0;
370
371 static uint verbose= 0;
372
373 static ulonglong start_position, stop_position;
374 #define start_position_mot ((my_off_t)start_position)
375 #define stop_position_mot ((my_off_t)stop_position)
376
377 static char *start_datetime_str, *stop_datetime_str;
378 static my_time_t start_datetime= 0, stop_datetime= MY_TIME_T_MAX;
379 static ulonglong rec_count= 0;
380 static MYSQL* mysql = NULL;
381 static char* dirname_for_local_load= 0;
382 static uint opt_server_id_bits = 0;
383 static ulong opt_server_id_mask = 0;
384 Sid_map *global_sid_map= NULL;
385 Checkable_rwlock *global_sid_lock= NULL;
386 Gtid_set *gtid_set_included= NULL;
387 Gtid_set *gtid_set_excluded= NULL;
388
389 /**
390 Pointer to the Format_description_log_event of the currently active binlog.
391
392 This will be changed each time a new Format_description_log_event is
393 found in the binlog. It is finally destroyed at program termination.
394 */
395 static Format_description_log_event* glob_description_event= NULL;
396
397 /**
398 Exit status for functions in this file.
399 */
400 enum Exit_status {
401 /** No error occurred and execution should continue. */
402 OK_CONTINUE= 0,
403 /** An error occurred and execution should stop. */
404 ERROR_STOP,
405 /** No error occurred but execution should stop. */
406 OK_STOP
407 };
408
409 /*
410 Options that will be used to filter out events.
411 */
412 static char *opt_include_gtids_str= NULL,
413 *opt_exclude_gtids_str= NULL;
414 static my_bool opt_skip_gtids= 0;
415 static bool filter_based_on_gtids= false;
416
417 /* It is set to true when BEGIN is found, and false when the transaction ends. */
418 static bool in_transaction= false;
419 /* It is set to true when GTID is found, and false when the transaction ends. */
420 static bool seen_gtid= false;
421
422 static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
423 const char* logname);
424 static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
425 const char* logname);
426 static Exit_status dump_single_log(PRINT_EVENT_INFO *print_event_info,
427 const char* logname);
428 static Exit_status dump_multiple_logs(int argc, char **argv);
429 static Exit_status safe_connect();
430
431 struct buff_event_info buff_event;
432
433 class Load_log_processor
434 {
435 char target_dir_name[FN_REFLEN];
436 size_t target_dir_name_len;
437
438 /*
439 When we see first event corresponding to some LOAD DATA statement in
440 binlog, we create temporary file to store data to be loaded.
441 We add name of this file to file_names set using its file_id as index.
442 If we have Create_file event (i.e. we have binary log in pre-5.0.3
443 format) we also store save event object to be able which is needed to
444 emit LOAD DATA statement when we will meet Exec_load_data event.
445 If we have Begin_load_query event we simply store 0 in
446 File_name_record::event field.
447 */
448 struct File_name_record
449 {
450 char *fname;
451 Create_file_log_event *event;
452 };
453
454 typedef std::map<uint, File_name_record> File_names;
455 File_names file_names;
456
457 /**
458 Looks for a non-existing filename by adding a numerical suffix to
459 the given base name, creates the generated file, and returns the
460 filename by modifying the filename argument.
461
462 @param[in,out] filename Base filename
463
464 @param[in,out] file_name_end Pointer to last character of
465 filename. The numerical suffix will be written to this position.
466 Note that there must be a least five bytes of allocated memory
467 after file_name_end.
468
469 @retval -1 Error (can't find new filename).
470 @retval >=0 Found file.
471 */
create_unique_file(char * filename,char * file_name_end)472 File create_unique_file(char *filename, char *file_name_end)
473 {
474 File res;
475 /* If we have to try more than 1000 times, something is seriously wrong */
476 for (uint version= 0; version<1000; version++)
477 {
478 sprintf(file_name_end,"-%x",version);
479 if ((res= my_create(filename,0,
480 O_CREAT|O_EXCL|O_BINARY|O_WRONLY,MYF(0)))!=-1)
481 return res;
482 }
483 return -1;
484 }
485
486 public:
Load_log_processor()487 Load_log_processor() : file_names()
488 {}
~Load_log_processor()489 ~Load_log_processor() {}
490
init_by_dir_name(const char * dir)491 void init_by_dir_name(const char *dir)
492 {
493 target_dir_name_len= (convert_dirname(target_dir_name, dir, NullS) -
494 target_dir_name);
495 }
init_by_cur_dir()496 void init_by_cur_dir()
497 {
498 if (my_getwd(target_dir_name,sizeof(target_dir_name),MYF(MY_WME)))
499 exit(1);
500 target_dir_name_len= strlen(target_dir_name);
501 }
destroy()502 void destroy()
503 {
504 File_names::iterator iter= file_names.begin();
505 File_names::iterator end= file_names.end();
506 for (; iter != end; ++iter)
507 {
508 File_name_record *ptr= &iter->second;
509 if (ptr->fname)
510 {
511 my_free(ptr->fname);
512 delete ptr->event;
513 memset(ptr, 0, sizeof(File_name_record));
514 }
515 }
516
517 file_names.clear();
518 }
519
520 /**
521 Obtain Create_file event for LOAD DATA statement by its file_id
522 and remove it from this Load_log_processor's list of events.
523
524 Checks whether we have already seen a Create_file_log_event with
525 the given file_id. If yes, returns a pointer to the event and
526 removes the event from array describing active temporary files.
527 From this moment, the caller is responsible for freeing the memory
528 occupied by the event.
529
530 @param[in] file_id File id identifying LOAD DATA statement.
531
532 @return Pointer to Create_file_log_event, or NULL if we have not
533 seen any Create_file_log_event with this file_id.
534 */
grab_event(uint file_id)535 Create_file_log_event *grab_event(uint file_id)
536 {
537 File_name_record *ptr;
538 Create_file_log_event *res;
539
540 File_names::iterator it= file_names.find(file_id);
541 if (it == file_names.end())
542 return NULL;
543 ptr= &((*it).second);
544 if ((res= ptr->event))
545 memset(ptr, 0, sizeof(File_name_record));
546 return res;
547 }
548
549 /**
550 Obtain file name of temporary file for LOAD DATA statement by its
551 file_id and remove it from this Load_log_processor's list of events.
552
553 @param[in] file_id Identifier for the LOAD DATA statement.
554
555 Checks whether we have already seen Begin_load_query event for
556 this file_id. If yes, returns the file name of the corresponding
557 temporary file and removes the filename from the array of active
558 temporary files. From this moment, the caller is responsible for
559 freeing the memory occupied by this name.
560
561 @return String with the name of the temporary file, or NULL if we
562 have not seen any Begin_load_query_event with this file_id.
563 */
grab_fname(uint file_id)564 char *grab_fname(uint file_id)
565 {
566 File_name_record *ptr;
567 char *res= NULL;
568
569 File_names::iterator it= file_names.find(file_id);
570 if (it == file_names.end())
571 return NULL;
572 ptr= &((*it).second);
573 if (!ptr->event)
574 {
575 res= ptr->fname;
576 memset(ptr, 0, sizeof(File_name_record));
577 }
578 return res;
579 }
580 Exit_status process(Create_file_log_event *ce);
581 Exit_status process(Begin_load_query_log_event *ce);
582 Exit_status process(Append_block_log_event *ae);
583 File prepare_new_file_for_old_format(Load_log_event *le, char *filename);
584 Exit_status load_old_format_file(NET* net, const char *server_fname,
585 uint server_fname_len, File file);
586 Exit_status process_first_event(const char *bname, size_t blen,
587 const uchar *block,
588 size_t block_len, uint file_id,
589 Create_file_log_event *ce);
590 };
591
592
593 /**
594 Creates and opens a new temporary file in the directory specified by previous call to init_by_dir_name() or init_by_cur_dir().
595
596 @param[in] le The basename of the created file will start with the
597 basename of the file pointed to by this Load_log_event.
598
599 @param[out] filename Buffer to save the filename in.
600
601 @return File handle >= 0 on success, -1 on error.
602 */
prepare_new_file_for_old_format(Load_log_event * le,char * filename)603 File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le,
604 char *filename)
605 {
606 size_t len;
607 char *tail;
608 File file;
609
610 fn_format(filename, le->fname, target_dir_name, "", MY_REPLACE_DIR);
611 len= strlen(filename);
612 tail= filename + len;
613
614 if ((file= create_unique_file(filename,tail)) < 0)
615 {
616 error("Could not construct local filename %s.",filename);
617 return -1;
618 }
619
620 le->set_fname_outside_temp_buf(filename,len+(uint) strlen(tail));
621
622 return file;
623 }
624
625
626 /**
627 Reads a file from a server and saves it locally.
628
629 @param[in,out] net The server to read from.
630
631 @param[in] server_fname The name of the file that the server should
632 read.
633
634 @param[in] server_fname_len The length of server_fname.
635
636 @param[in,out] file The file to write to.
637
638 @retval ERROR_STOP An error occurred - the program should terminate.
639 @retval OK_CONTINUE No error, the program should continue.
640 */
load_old_format_file(NET * net,const char * server_fname,uint server_fname_len,File file)641 Exit_status Load_log_processor::load_old_format_file(NET* net,
642 const char*server_fname,
643 uint server_fname_len,
644 File file)
645 {
646 uchar buf[FN_REFLEN+1];
647 buf[0] = 0;
648 memcpy(buf + 1, server_fname, server_fname_len + 1);
649 if (my_net_write(net, buf, server_fname_len +2) || net_flush(net))
650 {
651 error("Failed requesting the remote dump of %s.", server_fname);
652 return ERROR_STOP;
653 }
654
655 for (;;)
656 {
657 ulong packet_len = my_net_read(net);
658 if (packet_len == 0)
659 {
660 if (my_net_write(net, (uchar*) "", 0) || net_flush(net))
661 {
662 error("Failed sending the ack packet.");
663 return ERROR_STOP;
664 }
665 /*
666 we just need to send something, as the server will read but
667 not examine the packet - this is because mysql_load() sends
668 an OK when it is done
669 */
670 break;
671 }
672 else if (packet_len == packet_error)
673 {
674 error("Failed reading a packet during the dump of %s.", server_fname);
675 return ERROR_STOP;
676 }
677
678 if (packet_len > UINT_MAX)
679 {
680 error("Illegal length of packet read from net.");
681 return ERROR_STOP;
682 }
683 if (my_write(file, (uchar*) net->read_pos,
684 (uint) packet_len, MYF(MY_WME|MY_NABP)))
685 return ERROR_STOP;
686 }
687
688 return OK_CONTINUE;
689 }
690
691
692 /**
693 Process the first event in the sequence of events representing a
694 LOAD DATA statement.
695
696 Creates a temporary file to be used in LOAD DATA and writes first
697 block of data to it. Registers its file name (and optional
698 Create_file event) in the array of active temporary files.
699
700 @param bname Base name for temporary file to be created.
701 @param blen Base name length.
702 @param block First block of data to be loaded.
703 @param block_len First block length.
704 @param file_id Identifies the LOAD DATA statement.
705 @param ce Pointer to Create_file event object if we are processing
706 this type of event.
707
708 @retval ERROR_STOP An error occurred - the program should terminate.
709 @retval OK_CONTINUE No error, the program should continue.
710 */
process_first_event(const char * bname,size_t blen,const uchar * block,size_t block_len,uint file_id,Create_file_log_event * ce)711 Exit_status Load_log_processor::process_first_event(const char *bname,
712 size_t blen,
713 const uchar *block,
714 size_t block_len,
715 uint file_id,
716 Create_file_log_event *ce)
717 {
718 size_t full_len= target_dir_name_len + blen + 9 + 9 + 1;
719 Exit_status retval= OK_CONTINUE;
720 char *fname, *ptr;
721 File file;
722 File_name_record rec;
723 DBUG_ENTER("Load_log_processor::process_first_event");
724
725 if (!(fname= (char*) my_malloc(PSI_NOT_INSTRUMENTED,
726 full_len,MYF(MY_WME))))
727 {
728 error("Out of memory.");
729 delete ce;
730 DBUG_RETURN(ERROR_STOP);
731 }
732
733 memcpy(fname, target_dir_name, target_dir_name_len);
734 ptr= fname + target_dir_name_len;
735 memcpy(ptr,bname,blen);
736 ptr+= blen;
737 ptr+= sprintf(ptr, "-%x", file_id);
738
739 if ((file= create_unique_file(fname,ptr)) < 0)
740 {
741 error("Could not construct local filename %s%s.",
742 target_dir_name,bname);
743 my_free(fname);
744 delete ce;
745 DBUG_RETURN(ERROR_STOP);
746 }
747
748 rec.fname= fname;
749 rec.event= ce;
750
751 /*
752 fname is freed in process_event()
753 after Execute_load_query_log_event or Execute_load_log_event
754 will have been processed, otherwise in Load_log_processor::destroy()
755 */
756 file_names[file_id]= rec;
757
758 if (ce)
759 ce->set_fname_outside_temp_buf(fname, (uint) strlen(fname));
760
761 if (my_write(file, (uchar*)block, block_len, MYF(MY_WME|MY_NABP)))
762 {
763 error("Failed writing to file.");
764 retval= ERROR_STOP;
765 }
766 if (my_close(file, MYF(MY_WME)))
767 {
768 error("Failed closing file.");
769 retval= ERROR_STOP;
770 }
771 DBUG_RETURN(retval);
772 }
773
774
775 /**
776 Process the given Create_file_log_event.
777
778 @see Load_log_processor::process_first_event(const char*,uint,const char*,uint,uint,Create_file_log_event*)
779
780 @param ce Create_file_log_event to process.
781
782 @retval ERROR_STOP An error occurred - the program should terminate.
783 @retval OK_CONTINUE No error, the program should continue.
784 */
process(Create_file_log_event * ce)785 Exit_status Load_log_processor::process(Create_file_log_event *ce)
786 {
787 const char *bname= ce->fname + dirname_length(ce->fname);
788 size_t blen= ce->fname_len - (bname-ce->fname);
789
790 return process_first_event(bname, blen, ce->block, ce->block_len,
791 ce->file_id, ce);
792 }
793
794
795 /**
796 Process the given Begin_load_query_log_event.
797
798 @see Load_log_processor::process_first_event(const char*,uint,const char*,uint,uint,Create_file_log_event*)
799
800 @param ce Begin_load_query_log_event to process.
801
802 @retval ERROR_STOP An error occurred - the program should terminate.
803 @retval OK_CONTINUE No error, the program should continue.
804 */
process(Begin_load_query_log_event * blqe)805 Exit_status Load_log_processor::process(Begin_load_query_log_event *blqe)
806 {
807 return process_first_event("SQL_LOAD_MB", 11, blqe->block, blqe->block_len,
808 blqe->file_id, 0);
809 }
810
811
812 /**
813 Process the given Append_block_log_event.
814
815 Appends the chunk of the file contents specified by the event to the
816 file created by a previous Begin_load_query_log_event or
817 Create_file_log_event.
818
819 If the file_id for the event does not correspond to any file
820 previously registered through a Begin_load_query_log_event or
821 Create_file_log_event, this member function will print a warning and
822 return OK_CONTINUE. It is safe to return OK_CONTINUE, because no
823 query will be written for this event. We should not print an error
824 and fail, since the missing file_id could be because a (valid)
825 --start-position has been specified after the Begin/Create event but
826 before this Append event.
827
828 @param ae Append_block_log_event to process.
829
830 @retval ERROR_STOP An error occurred - the program should terminate.
831
832 @retval OK_CONTINUE No error, the program should continue.
833 */
process(Append_block_log_event * ae)834 Exit_status Load_log_processor::process(Append_block_log_event *ae)
835 {
836 DBUG_ENTER("Load_log_processor::process");
837 File_names::iterator it= file_names.find(ae->file_id);
838 const char *fname= ((it != file_names.end()) ?
839 (*it).second.fname : NULL);
840
841 if (fname)
842 {
843 File file;
844 Exit_status retval= OK_CONTINUE;
845 if (((file= my_open(fname,
846 O_APPEND|O_BINARY|O_WRONLY,MYF(MY_WME))) < 0))
847 {
848 error("Failed opening file %s", fname);
849 DBUG_RETURN(ERROR_STOP);
850 }
851 if (my_write(file,(uchar*)ae->block,ae->block_len,MYF(MY_WME|MY_NABP)))
852 {
853 error("Failed writing to file %s", fname);
854 retval= ERROR_STOP;
855 }
856 if (my_close(file,MYF(MY_WME)))
857 {
858 error("Failed closing file %s", fname);
859 retval= ERROR_STOP;
860 }
861 DBUG_RETURN(retval);
862 }
863
864 /*
865 There is no Create_file event (a bad binlog or a big
866 --start-position). Assuming it's a big --start-position, we just do
867 nothing and print a warning.
868 */
869 warning("Ignoring Append_block as there is no "
870 "Create_file event for file_id: %u", ae->file_id);
871 DBUG_RETURN(OK_CONTINUE);
872 }
873
874
875 static Load_log_processor load_processor;
876
877
878 /**
879 Replace windows-style backslashes by forward slashes so it can be
880 consumed by the mysql client, which requires Unix path.
881
882 @todo This is only useful under windows, so may be ifdef'ed out on
883 other systems. /Sven
884
885 @todo If a Create_file_log_event contains a filename with a
886 backslash (valid under unix), then we have problems under windows.
887 /Sven
888
889 @param[in,out] fname Filename to modify. The filename is modified
890 in-place.
891 */
convert_path_to_forward_slashes(char * fname)892 static void convert_path_to_forward_slashes(char *fname)
893 {
894 while (*fname)
895 {
896 if (*fname == '\\')
897 *fname= '/';
898 fname++;
899 }
900 }
901
902
903 /**
904 Indicates whether the given database should be filtered out,
905 according to the --database=X option.
906
907 @param log_dbname Name of database.
908
909 @return nonzero if the database with the given name should be
910 filtered out, 0 otherwise.
911 */
shall_skip_database(const char * log_dbname)912 static bool shall_skip_database(const char *log_dbname)
913 {
914 return one_database &&
915 (log_dbname != NULL) &&
916 strcmp(log_dbname, database);
917 }
918
919
920 /**
921 Checks whether the given event should be filtered out,
922 according to the include-gtids, exclude-gtids and
923 skip-gtids options.
924
925 @param ev Pointer to the event to be checked.
926
927 @return true if the event should be filtered out,
928 false, otherwise.
929 */
shall_skip_gtids(Log_event * ev)930 static bool shall_skip_gtids(Log_event* ev)
931 {
932 bool filtered= false;
933
934 switch (ev->get_type_code())
935 {
936 case binary_log::GTID_LOG_EVENT:
937 case binary_log::ANONYMOUS_GTID_LOG_EVENT:
938 {
939 Gtid_log_event *gtid= (Gtid_log_event *) ev;
940 if (opt_include_gtids_str != NULL)
941 {
942 filtered= filtered ||
943 !gtid_set_included->contains_gtid(gtid->get_sidno(true),
944 gtid->get_gno());
945 }
946
947 if (opt_exclude_gtids_str != NULL)
948 {
949 filtered= filtered ||
950 gtid_set_excluded->contains_gtid(gtid->get_sidno(true),
951 gtid->get_gno());
952 }
953 filter_based_on_gtids= filtered;
954 filtered= filtered || opt_skip_gtids;
955 }
956 break;
957 /* Skip previous gtids if --skip-gtids is set. */
958 case binary_log::PREVIOUS_GTIDS_LOG_EVENT:
959 filtered= opt_skip_gtids;
960 break;
961
962 /*
963 Transaction boundaries reset the global filtering flag.
964
965 Since in the relay log a transaction can span multiple
966 log files, we do not reset filter_based_on_gtids flag when
967 processing control events (they can appear in the middle
968 of a transaction). But then, if:
969
970 FILE1: ... GTID BEGIN QUERY QUERY COMMIT ROTATE
971 FILE2: FD BEGIN QUERY QUERY COMMIT
972
973 Events on the second file would not be outputted, even
974 though they should.
975 */
976 case binary_log::XID_EVENT:
977 filtered= filter_based_on_gtids;
978 filter_based_on_gtids= false;
979 break;
980 case binary_log::QUERY_EVENT:
981 filtered= filter_based_on_gtids;
982 if (((Query_log_event *)ev)->ends_group())
983 filter_based_on_gtids= false;
984 break;
985
986 /*
987 Never skip STOP, FD, ROTATE, IGNORABLE or INCIDENT events.
988 SLAVE_EVENT and START_EVENT_V3 are there for completion.
989
990 Although in the binlog transactions do not span multiple
991 log files, in the relay-log, that can happen. As such,
992 we need to explicitly state that we do not filter these
993 events, because there is a chance that they appear in the
994 middle of a filtered transaction, e.g.:
995
996 FILE1: ... GTID BEGIN QUERY QUERY ROTATE
997 FILE2: FD QUERY QUERY COMMIT GTID BEGIN ...
998
999 In this case, ROTATE and FD events should be processed and
1000 outputted.
1001 */
1002 case binary_log::START_EVENT_V3: /* for completion */
1003 case binary_log::SLAVE_EVENT: /* for completion */
1004 case binary_log::STOP_EVENT:
1005 case binary_log::FORMAT_DESCRIPTION_EVENT:
1006 case binary_log::ROTATE_EVENT:
1007 case binary_log::IGNORABLE_LOG_EVENT:
1008 case binary_log::INCIDENT_EVENT:
1009 filtered= false;
1010 break;
1011 default:
1012 filtered= filter_based_on_gtids;
1013 break;
1014 }
1015
1016 return filtered;
1017 }
1018
1019 /**
1020 Print auxiliary statements ending a binary log (or a logical binary log
1021 within a sequence of relay logs; see below).
1022
1023 There are two kinds of log files which can be printed by mysqlbinlog
1024 binlog file - generated by mysql server when binlog is ON.
1025 relaylog file - generated by slave IO thread. It just stores binlog
1026 replicated from master with an extra header(FD event,
1027 Previous_gtid_log_event) and a tail(rotate event).
1028 when printing the events in relay logs, the purpose is to print
1029 the events generated by master, but not slave.
1030
1031 There are three types of FD events:
1032 - Slave FD event: has F_RELAY_LOG set and end_log_pos > 0
1033 - Real master FD event: has F_RELAY_LOG cleared and end_log_pos > 0
1034 - Fake master FD event: has F_RELAY_LOG cleared and end_log_pos == 0
1035
1036 (Two remarks:
1037
1038 - The server_id of a slave FD event is the slave's server_id, and
1039 the server_id of a master FD event (real or fake) is the
1040 master's server_id. But this does not help to distinguish the
1041 types in case replicate-same-server-id is enabled. So to
1042 determine the type of event we need to check the F_RELAY_LOG
1043 flag.
1044
1045 - A fake master FD event may be generated by master's dump
1046 thread (then it takes the first event of the binlog and sets
1047 end_log_pos=0), or by the slave (then it takes the last known
1048 real FD event and sets end_log_pos=0.) There is no way to
1049 distinguish master-generated fake master FD events from
1050 slave-generated fake master FD events.
1051 )
1052
1053 There are 8 cases where we rotate a relay log:
1054
1055 R1. After FLUSH [RELAY] LOGS
1056 R2. When mysqld receives SIGHUP
1057 R3. When relay log size grows too big
1058 R4. Immediately after START SLAVE
1059 R5. When slave IO thread reconnects without user doing
1060 START SLAVE/STOP SLAVE
1061 R6. When master dump thread starts a new binlog
1062 R7. CHANGE MASTER which deletes all relay logs
1063 R8. RESET SLAVE
1064
1065 (Remark: CHANGE MASTER which does not delete any relay log,
1066 does not cause any rotation at all.)
1067
1068 The 8 cases generate the three types of FD events as follows:
1069 - In all cases, a slave FD event is generated.
1070 - In cases R1 and R2, if the slave has been connected
1071 previously, the slave client thread that issues
1072 FLUSH (or the thread that handles the SIGHUP) generates a
1073 fake master FD event. If the slave has not been connected
1074 previously, there is no master FD event.
1075 - In case R3, the slave IO thread generates a fake master FD
1076 event.
1077 - In cases R4 and R5, if AUTOPOSITION=0 and MASTER_LOG_POS>4,
1078 the master dump thread generates a fake master FD event.
1079 - In cases R4 and R5, if AUTOPOSITION=1 or MASTER_LOG_POS<=4,
1080 the master dump thread generates a real master FD event.
1081 - In case R6, the master dump thread generates a real master FD
1082 event.
1083 - In cases R7 and R8, the slave does not generate any master FD
1084 event.
1085
1086 We define the term 'logical binlog' as a sequence of events in
1087 relay logs, such that a single logical binlog may span multiple
1088 relay log files, and any two logical binlogs are separated by a
1089 real master FD event.
1090
1091 A transaction's events will never be divided into two binlog files or
1092 two logical binlogs. But a transaction may span multiple relay logs, in which
1093 case a faked FD will appear in the middle of the transaction. they may be
1094 divided by fake master FD event and/or slave FD events.
1095
1096 * Example 1
1097
1098 relay-log.1
1099 ...
1100 GTID_NEXT=1
1101 BEGIN;
1102
1103 relay-log.2
1104 ...
1105 faked Format_description_event
1106 INSERT ...
1107 COMMIT;
1108
1109 For above case, it has only one logical binlog. The events
1110 in both relay-log.1 and relay-log.2 belong to the same logical binlog.
1111
1112 * Example 2
1113
1114 relay-log.1
1115 ...
1116 GTID_NEXT=1
1117 BEGIN; // It is a partial transaction at the end of logical binlog
1118
1119 relay-log.2
1120 ...
1121 real Format_description_event
1122 GTID_NEXT=1
1123 BEGIN;
1124 ...
1125
1126 For above case, it has two logical binlogs. Events in relay-log.1
1127 and relay-log.2 belong to two different logical binlog.
1128
1129 Logical binlog is handled in a similar way as a binlog file. At the end of a
1130 binlog file, at the end of a logical binlog or at the end of mysqlbinlog it should
1131 - rollback the last transaction if it is not complete
1132 - rollback the last gtid if the last event is a gtid_log_event
1133 - set gtid_next to AUTOMATIC
1134
1135 This function is called two places:
1136 - Before printing a real Format_description_log_event(excluding the
1137 first Format_description_log_event), while mysqlbinlog is in the middle
1138 of printing all log files(binlog or relaylog).
1139 - At the end of mysqlbinlog, just after printing all log files(binlog or
1140 relaylog).
1141
1142 @param[in|out] print_event_info Context state determining how to print.
1143 */
end_binlog(PRINT_EVENT_INFO * print_event_info)1144 void end_binlog(PRINT_EVENT_INFO *print_event_info)
1145 {
1146 if (in_transaction)
1147 {
1148 fprintf(result_file, "ROLLBACK /* added by mysqlbinlog */ %s\n",
1149 print_event_info->delimiter);
1150 }
1151 else if (seen_gtid && !opt_skip_gtids)
1152 {
1153 /*
1154 If we are here, then we have seen only GTID_LOG_EVENT
1155 of a transaction and did not see even a BEGIN event
1156 (in_transaction flag is false). So generate BEGIN event
1157 also along with ROLLBACK event.
1158 */
1159 fprintf(result_file,
1160 "BEGIN /*added by mysqlbinlog */ %s\n"
1161 "ROLLBACK /* added by mysqlbinlog */ %s\n",
1162 print_event_info->delimiter,
1163 print_event_info->delimiter);
1164 }
1165
1166 if (!opt_skip_gtids)
1167 fprintf(result_file, "%sAUTOMATIC' /* added by mysqlbinlog */ %s\n",
1168 Gtid_log_event::SET_STRING_PREFIX, print_event_info->delimiter);
1169
1170 seen_gtid= false;
1171 in_transaction= false;
1172 }
1173
1174 /**
1175 Print the given event, and either delete it or delegate the deletion
1176 to someone else.
1177
1178 The deletion may be delegated in these cases:
1179 (1) the event is a Format_description_log_event, and is saved in
1180 glob_description_event.
1181 (2) the event is a Create_file_log_event, and is saved in load_processor.
1182 (3) the event is an Intvar, Rand or User_var event, it will be kept until
1183 the subsequent Query_log_event.
1184 (4) the event is a Table_map_log_event, it will be kept until the subsequent
1185 Rows_log_event.
1186 @param[in,out] print_event_info Parameters and context state
1187 determining how to print.
1188 @param[in] ev Log_event to process.
1189 @param[in] pos Offset from beginning of binlog file.
1190 @param[in] logname Name of input binlog.
1191
1192 @retval ERROR_STOP An error occurred - the program should terminate.
1193 @retval OK_CONTINUE No error, the program should continue.
1194 @retval OK_STOP No error, but the end of the specified range of
1195 events to process has been reached and the program should terminate.
1196 */
process_event(PRINT_EVENT_INFO * print_event_info,Log_event * ev,my_off_t pos,const char * logname)1197 Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
1198 my_off_t pos, const char *logname)
1199 {
1200 char ll_buff[21];
1201 Log_event_type ev_type= ev->get_type_code();
1202 my_bool destroy_evt= TRUE;
1203 DBUG_ENTER("process_event");
1204 Exit_status retval= OK_CONTINUE;
1205 IO_CACHE *const head= &print_event_info->head_cache;
1206
1207 /*
1208 Format events are not concerned by --offset and such, we always need to
1209 read them to be able to process the wanted events.
1210 */
1211 if (((rec_count >= offset) &&
1212 ((my_time_t) (ev->common_header->when.tv_sec) >= start_datetime)) ||
1213 (ev_type == binary_log::FORMAT_DESCRIPTION_EVENT))
1214 {
1215 if (ev_type != binary_log::FORMAT_DESCRIPTION_EVENT)
1216 {
1217 /*
1218 We have found an event after start_datetime, from now on print
1219 everything (in case the binlog has timestamps increasing and
1220 decreasing, we do this to avoid cutting the middle).
1221 */
1222 start_datetime= 0;
1223 offset= 0; // print everything and protect against cycling rec_count
1224 /*
1225 Skip events according to the --server-id flag. However, don't
1226 skip format_description or rotate events, because they they
1227 are really "global" events that are relevant for the entire
1228 binlog, even if they have a server_id. Also, we have to read
1229 the format_description event so that we can parse subsequent
1230 events.
1231 */
1232 if (ev_type != binary_log::ROTATE_EVENT &&
1233 filter_server_id && (filter_server_id != ev->server_id))
1234 goto end;
1235 }
1236 if (((my_time_t) (ev->common_header->when.tv_sec) >= stop_datetime)
1237 || (pos >= stop_position_mot))
1238 {
1239 /* end the program */
1240 retval= OK_STOP;
1241 goto end;
1242 }
1243 if (!short_form)
1244 my_b_printf(&print_event_info->head_cache,
1245 "# at %s\n",llstr(pos,ll_buff));
1246
1247 if (!opt_hexdump)
1248 print_event_info->hexdump_from= 0; /* Disabled */
1249 else
1250 print_event_info->hexdump_from= pos;
1251
1252 DBUG_PRINT("debug", ("event_type: %s", ev->get_type_str()));
1253
1254 if (shall_skip_gtids(ev))
1255 goto end;
1256
1257 switch (ev_type) {
1258 case binary_log::QUERY_EVENT:
1259 {
1260 Query_log_event *qle= (Query_log_event*) ev;
1261 bool parent_query_skips=
1262 !qle->is_trans_keyword() && shall_skip_database(qle->db);
1263 bool ends_group= ((Query_log_event*) ev)->ends_group();
1264 bool starts_group= ((Query_log_event*) ev)->starts_group();
1265
1266 for (size_t i= 0; i < buff_ev->size(); i++)
1267 {
1268 buff_event_info pop_event_array= buff_ev->at(i);
1269 Log_event *temp_event= pop_event_array.event;
1270 my_off_t temp_log_pos= pop_event_array.event_pos;
1271 print_event_info->hexdump_from= (opt_hexdump ? temp_log_pos : 0);
1272 if (!parent_query_skips)
1273 temp_event->print(result_file, print_event_info);
1274 delete temp_event;
1275 }
1276
1277 print_event_info->hexdump_from= (opt_hexdump ? pos : 0);
1278 buff_ev->clear();
1279
1280 if (parent_query_skips)
1281 {
1282 /*
1283 Even though there would be no need to set the flag here,
1284 since parent_query_skips is never true when handling "COMMIT"
1285 statements in the Query_log_event, we still need to handle DDL,
1286 which causes a commit itself.
1287 */
1288
1289 if (seen_gtid && !in_transaction && !starts_group && !ends_group)
1290 {
1291 /*
1292 For DDLs, print the COMMIT right away.
1293 */
1294 fprintf(result_file, "COMMIT /* added by mysqlbinlog */%s\n", print_event_info->delimiter);
1295 print_event_info->skipped_event_in_transaction= false;
1296 in_transaction= false;
1297 seen_gtid= false;
1298 }
1299 else
1300 print_event_info->skipped_event_in_transaction= true;
1301 goto end;
1302 }
1303
1304 if (ends_group)
1305 {
1306 in_transaction= false;
1307 print_event_info->skipped_event_in_transaction= false;
1308 seen_gtid= false;
1309 }
1310 else if (starts_group)
1311 in_transaction= true;
1312 else
1313 {
1314 /*
1315 We are not in a transaction and are not seeing a BEGIN or
1316 COMMIT. So this is an implicitly committing DDL.
1317 */
1318 if (!in_transaction)
1319 seen_gtid= false;
1320 }
1321
1322 ev->print(result_file, print_event_info);
1323 if (head->error == -1)
1324 goto err;
1325 break;
1326 }
1327
1328 case binary_log::INTVAR_EVENT:
1329 {
1330 destroy_evt= FALSE;
1331 buff_event.event= ev;
1332 buff_event.event_pos= pos;
1333 buff_ev->push_back(buff_event);
1334 break;
1335 }
1336
1337 case binary_log::RAND_EVENT:
1338 {
1339 destroy_evt= FALSE;
1340 buff_event.event= ev;
1341 buff_event.event_pos= pos;
1342 buff_ev->push_back(buff_event);
1343 break;
1344 }
1345
1346 case binary_log::USER_VAR_EVENT:
1347 {
1348 destroy_evt= FALSE;
1349 buff_event.event= ev;
1350 buff_event.event_pos= pos;
1351 buff_ev->push_back(buff_event);
1352 break;
1353 }
1354
1355
1356 case binary_log::CREATE_FILE_EVENT:
1357 {
1358 Create_file_log_event* ce= (Create_file_log_event*)ev;
1359 /*
1360 We test if this event has to be ignored. If yes, we don't save
1361 this event; this will have the good side-effect of ignoring all
1362 related Append_block and Exec_load.
1363 Note that Load event from 3.23 is not tested.
1364 */
1365 if (shall_skip_database(ce->db))
1366 {
1367 print_event_info->skipped_event_in_transaction= true;
1368 goto end; // Next event
1369 }
1370 /*
1371 We print the event, but with a leading '#': this is just to inform
1372 the user of the original command; the command we want to execute
1373 will be a derivation of this original command (we will change the
1374 filename and use LOCAL), prepared in the 'case EXEC_LOAD_EVENT'
1375 below.
1376 */
1377 {
1378 ce->print(result_file, print_event_info, TRUE);
1379 if (head->error == -1)
1380 goto err;
1381 }
1382 // If this binlog is not 3.23 ; why this test??
1383 if (glob_description_event->binlog_version >= 3)
1384 {
1385 /*
1386 transfer the responsibility for destroying the event to
1387 load_processor
1388 */
1389 ev= NULL;
1390 if ((retval= load_processor.process(ce)) != OK_CONTINUE)
1391 goto end;
1392 }
1393 break;
1394 }
1395
1396 case binary_log::APPEND_BLOCK_EVENT:
1397 /*
1398 Append_block_log_events can safely print themselves even if
1399 the subsequent call load_processor.process fails, because the
1400 output of Append_block_log_event::print is only a comment.
1401 */
1402 ev->print(result_file, print_event_info);
1403 if (head->error == -1)
1404 goto err;
1405 if ((retval= load_processor.process((Append_block_log_event*) ev)) !=
1406 OK_CONTINUE)
1407 goto end;
1408 break;
1409
1410 case binary_log::EXEC_LOAD_EVENT:
1411 {
1412 ev->print(result_file, print_event_info);
1413 if (head->error == -1)
1414 goto err;
1415 Execute_load_log_event *exv= (Execute_load_log_event*)ev;
1416 Create_file_log_event *ce= load_processor.grab_event(exv->file_id);
1417 /*
1418 if ce is 0, it probably means that we have not seen the Create_file
1419 event (a bad binlog, or most probably --start-position is after the
1420 Create_file event). Print a warning comment.
1421 */
1422 if (ce)
1423 {
1424 /*
1425 We must not convert earlier, since the file is used by
1426 my_open() in Load_log_processor::append().
1427 */
1428 convert_path_to_forward_slashes((char*) ce->fname);
1429 ce->print(result_file, print_event_info, TRUE);
1430 my_free((void*)ce->fname);
1431 delete ce;
1432 if (head->error == -1)
1433 goto err;
1434 }
1435 else
1436 warning("Ignoring Execute_load_log_event as there is no "
1437 "Create_file event for file_id: %u", exv->file_id);
1438 break;
1439 }
1440 case binary_log::FORMAT_DESCRIPTION_EVENT:
1441 {
1442 delete glob_description_event;
1443 glob_description_event= (Format_description_log_event*) ev;
1444
1445 /*
1446 end_binlog is not called on faked fd and relay log's fd.
1447 Faked FD's log_pos is always 0.
1448 Faked FD happens in below cases:
1449 - first FD sent from master to slave if dump request's position is
1450 greater than 4(when using COM_BINLOG_DUMP, autoposition is 0).
1451 - Slave fakes a master's FD when rotating relay log through
1452 'FLUSH LOGS | FLUSH RELAY LOGS', or get the signal SIGHUP.
1453 */
1454 if (!ev->is_relay_log_event())
1455 {
1456 static bool is_first_fd= true;
1457
1458 /*
1459 Before starting next binlog or logical binlog, it should end the
1460 previous binlog first. For detail, see the comment of end_binlog().
1461 */
1462 if (ev->common_header->log_pos > 0 && !is_first_fd)
1463 end_binlog(print_event_info);
1464
1465 is_first_fd= false;
1466 }
1467
1468 print_event_info->common_header_len=
1469 glob_description_event->common_header_len;
1470 ev->print(result_file, print_event_info);
1471
1472 if (head->error == -1)
1473 goto err;
1474 ev->free_temp_buf();
1475 /*
1476 We don't want this event to be deleted now, so let's hide it (I
1477 (Guilhem) should later see if this triggers a non-serious Valgrind
1478 error). Not serious error, because we will free description_event
1479 later.
1480 */
1481 ev= 0;
1482 if (!force_if_open_opt &&
1483 (glob_description_event->common_header->flags &
1484 LOG_EVENT_BINLOG_IN_USE_F))
1485 {
1486 error("Attempting to dump binlog '%s', which was not closed properly. "
1487 "Most probably, mysqld is still writing it, or it crashed. "
1488 "Rerun with --force-if-open to ignore this problem.", logname);
1489 DBUG_RETURN(ERROR_STOP);
1490 }
1491 break;
1492 }
1493 case binary_log::BEGIN_LOAD_QUERY_EVENT:
1494 ev->print(result_file, print_event_info);
1495 if (head->error == -1)
1496 goto err;
1497 if ((retval= load_processor.process((Begin_load_query_log_event*) ev)) !=
1498 OK_CONTINUE)
1499 goto end;
1500 break;
1501 case binary_log::EXECUTE_LOAD_QUERY_EVENT:
1502 {
1503 Execute_load_query_log_event *exlq= (Execute_load_query_log_event*)ev;
1504 char *fname= load_processor.grab_fname(exlq->file_id);
1505 if (shall_skip_database(exlq->db))
1506 print_event_info->skipped_event_in_transaction= true;
1507 else
1508 {
1509 if (fname)
1510 {
1511 convert_path_to_forward_slashes(fname);
1512 exlq->print(result_file, print_event_info, fname);
1513 if (head->error == -1)
1514 {
1515 if (fname)
1516 my_free(fname);
1517 goto err;
1518 }
1519 }
1520 else
1521 warning("Ignoring Execute_load_query since there is no "
1522 "Begin_load_query event for file_id: %u", exlq->file_id);
1523 }
1524
1525 if (fname)
1526 my_free(fname);
1527 break;
1528 }
1529 case binary_log::TABLE_MAP_EVENT:
1530 {
1531 Table_map_log_event *map= ((Table_map_log_event *)ev);
1532 if (shall_skip_database(map->get_db_name()))
1533 {
1534 print_event_info->skipped_event_in_transaction= true;
1535 print_event_info->m_table_map_ignored.set_table(map->get_table_id(), map);
1536 destroy_evt= FALSE;
1537 goto end;
1538 }
1539 }
1540 // Fall through.
1541 case binary_log::ROWS_QUERY_LOG_EVENT:
1542 case binary_log::WRITE_ROWS_EVENT:
1543 case binary_log::DELETE_ROWS_EVENT:
1544 case binary_log::UPDATE_ROWS_EVENT:
1545 case binary_log::WRITE_ROWS_EVENT_V1:
1546 case binary_log::UPDATE_ROWS_EVENT_V1:
1547 case binary_log::DELETE_ROWS_EVENT_V1:
1548 case binary_log::PRE_GA_WRITE_ROWS_EVENT:
1549 case binary_log::PRE_GA_DELETE_ROWS_EVENT:
1550 case binary_log::PRE_GA_UPDATE_ROWS_EVENT:
1551 {
1552 bool stmt_end= FALSE;
1553 Table_map_log_event *ignored_map= NULL;
1554 if (ev_type == binary_log::WRITE_ROWS_EVENT ||
1555 ev_type == binary_log::DELETE_ROWS_EVENT ||
1556 ev_type == binary_log::UPDATE_ROWS_EVENT ||
1557 ev_type == binary_log::WRITE_ROWS_EVENT_V1 ||
1558 ev_type == binary_log::DELETE_ROWS_EVENT_V1 ||
1559 ev_type == binary_log::UPDATE_ROWS_EVENT_V1)
1560 {
1561 Rows_log_event *new_ev= (Rows_log_event*) ev;
1562 if (new_ev->get_flags(Rows_log_event::STMT_END_F))
1563 stmt_end= TRUE;
1564 ignored_map= print_event_info->m_table_map_ignored.get_table(new_ev->get_table_id());
1565 }
1566 else if (ev_type == binary_log::PRE_GA_WRITE_ROWS_EVENT ||
1567 ev_type == binary_log::PRE_GA_DELETE_ROWS_EVENT ||
1568 ev_type == binary_log::PRE_GA_UPDATE_ROWS_EVENT)
1569 {
1570 Old_rows_log_event *old_ev= (Old_rows_log_event*) ev;
1571 if (old_ev->get_flags(Rows_log_event::STMT_END_F))
1572 stmt_end= TRUE;
1573 ignored_map= print_event_info->m_table_map_ignored.get_table(old_ev->get_table_id());
1574 }
1575
1576 bool skip_event= (ignored_map != NULL);
1577 /*
1578 end of statement check:
1579 i) destroy/free ignored maps
1580 ii) if skip event
1581 a) set the unflushed_events flag to false
1582 b) since we are skipping the last event,
1583 append END-MARKER(') to body cache (if required)
1584 c) flush cache now
1585 */
1586 if (stmt_end)
1587 {
1588 /*
1589 Now is safe to clear ignored map (clear_tables will also
1590 delete original table map events stored in the map).
1591 */
1592 if (print_event_info->m_table_map_ignored.count() > 0)
1593 print_event_info->m_table_map_ignored.clear_tables();
1594
1595 /*
1596 One needs to take into account an event that gets
1597 filtered but was last event in the statement. If this is
1598 the case, previous rows events that were written into
1599 IO_CACHEs still need to be copied from cache to
1600 result_file (as it would happen in ev->print(...) if
1601 event was not skipped).
1602 */
1603 if (skip_event)
1604 {
1605 // set the unflushed_events flag to false
1606 print_event_info->have_unflushed_events= FALSE;
1607
1608 // append END-MARKER(') with delimiter
1609 IO_CACHE *const body_cache= &print_event_info->body_cache;
1610 if (my_b_tell(body_cache))
1611 my_b_printf(body_cache, "'%s\n", print_event_info->delimiter);
1612
1613 // flush cache
1614 if ((copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
1615 result_file, stop_never /* flush result_file */) ||
1616 copy_event_cache_to_file_and_reinit(&print_event_info->body_cache,
1617 result_file, stop_never /* flush result_file */) ||
1618 copy_event_cache_to_file_and_reinit(&print_event_info->footer_cache,
1619 result_file, stop_never /* flush result_file */)))
1620 goto err;
1621 }
1622 }
1623
1624 /* skip the event check */
1625 if (skip_event)
1626 {
1627 print_event_info->skipped_event_in_transaction= true;
1628 goto end;
1629 }
1630
1631 /*
1632 These events must be printed in base64 format, if printed.
1633 base64 format requires a FD event to be safe, so if no FD
1634 event has been printed, we give an error. Except if user
1635 passed --short-form, because --short-form disables printing
1636 row events.
1637 */
1638 if (!print_event_info->printed_fd_event && !short_form &&
1639 ev_type != binary_log::TABLE_MAP_EVENT &&
1640 ev_type != binary_log::ROWS_QUERY_LOG_EVENT &&
1641 opt_base64_output_mode != BASE64_OUTPUT_DECODE_ROWS)
1642 {
1643 const char* type_str= ev->get_type_str();
1644 if (opt_base64_output_mode == BASE64_OUTPUT_NEVER)
1645 error("--base64-output=never specified, but binlog contains a "
1646 "%s event which must be printed in base64.",
1647 type_str);
1648 else
1649 error("malformed binlog: it does not contain any "
1650 "Format_description_log_event. I now found a %s event, which "
1651 "is not safe to process without a "
1652 "Format_description_log_event.",
1653 type_str);
1654 goto err;
1655 }
1656
1657 ev->print(result_file, print_event_info);
1658 print_event_info->have_unflushed_events= TRUE;
1659 /* Flush head,body and footer cache to result_file */
1660 if (stmt_end)
1661 {
1662 print_event_info->have_unflushed_events= FALSE;
1663 if (copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
1664 result_file, stop_never /* flush result file */) ||
1665 copy_event_cache_to_file_and_reinit(&print_event_info->body_cache,
1666 result_file, stop_never /* flush result file */) ||
1667 copy_event_cache_to_file_and_reinit(&print_event_info->footer_cache,
1668 result_file, stop_never /* flush result file */))
1669 goto err;
1670 goto end;
1671 }
1672 break;
1673 }
1674 case binary_log::ANONYMOUS_GTID_LOG_EVENT:
1675 case binary_log::GTID_LOG_EVENT:
1676 {
1677 seen_gtid= true;
1678 if (print_event_info->skipped_event_in_transaction == true)
1679 fprintf(result_file, "COMMIT /* added by mysqlbinlog */%s\n", print_event_info->delimiter);
1680 print_event_info->skipped_event_in_transaction= false;
1681
1682 ev->print(result_file, print_event_info);
1683 if (head->error == -1)
1684 goto err;
1685 break;
1686 }
1687 case binary_log::XID_EVENT:
1688 {
1689 in_transaction= false;
1690 print_event_info->skipped_event_in_transaction= false;
1691 seen_gtid= false;
1692 ev->print(result_file, print_event_info);
1693 if (head->error == -1)
1694 goto err;
1695 break;
1696 }
1697 case binary_log::PREVIOUS_GTIDS_LOG_EVENT:
1698 if (one_database && !opt_skip_gtids)
1699 warning("The option --database has been used. It may filter "
1700 "parts of transactions, but will include the GTIDs in "
1701 "any case. If you want to exclude or include transactions, "
1702 "you should use the options --exclude-gtids or "
1703 "--include-gtids, respectively, instead.");
1704 /* fall through */
1705 default:
1706 ev->print(result_file, print_event_info);
1707 if (head->error == -1)
1708 goto err;
1709 }
1710 /* Flush head cache to result_file for every event */
1711 if (copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
1712 result_file, stop_never /* flush result_file */))
1713 goto err;
1714 }
1715
1716 goto end;
1717
1718 err:
1719 retval= ERROR_STOP;
1720 end:
1721 rec_count++;
1722 /* Destroy the log_event object. */
1723 if (ev)
1724 {
1725 if (destroy_evt) /* destroy it later if not set (ignored table map) */
1726 delete ev;
1727 }
1728 DBUG_RETURN(retval);
1729 }
1730
1731
1732 static struct my_option my_long_options[] =
1733 {
1734 {"help", '?', "Display this help and exit.",
1735 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
1736 {"base64-output", OPT_BASE64_OUTPUT_MODE,
1737 /* 'unspec' is not mentioned because it is just a placeholder. */
1738 "Determine when the output statements should be base64-encoded BINLOG "
1739 "statements: 'never' disables it and works only for binlogs without "
1740 "row-based events; 'decode-rows' decodes row events into commented pseudo-SQL "
1741 "statements if the --verbose option is also given; 'auto' prints base64 "
1742 "only when necessary (i.e., for row-based events and format description "
1743 "events). If no --base64-output[=name] option is given at all, the "
1744 "default is 'auto'.",
1745 &opt_base64_output_mode_str, &opt_base64_output_mode_str,
1746 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1747 {"bind-address", 0, "IP address to bind to.",
1748 (uchar**) &opt_bind_addr, (uchar**) &opt_bind_addr, 0, GET_STR,
1749 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1750 /*
1751 mysqlbinlog needs charsets knowledge, to be able to convert a charset
1752 number found in binlog to a charset name (to be able to print things
1753 like this:
1754 SET @`a`:=_cp850 0x4DFC6C6C6572 COLLATE `cp850_general_ci`;
1755 */
1756 {"character-sets-dir", OPT_CHARSETS_DIR,
1757 "Directory for character set files.", &charsets_dir,
1758 &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1759 {"database", 'd', "List entries for just this database (local log only).",
1760 &database, &database, 0, GET_STR_ALLOC, REQUIRED_ARG,
1761 0, 0, 0, 0, 0, 0},
1762 {"rewrite-db", OPT_REWRITE_DB, "Rewrite the row event to point so that "
1763 "it can be applied to a new database", &rewrite, &rewrite, 0,
1764 GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1765 #ifdef DBUG_OFF
1766 {"debug", '#', "This is a non-debug version. Catch this and exit.",
1767 0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
1768 {"debug-check", OPT_DEBUG_CHECK, "This is a non-debug version. Catch this and exit.",
1769 0, 0, 0,
1770 GET_DISABLED, NO_ARG, 0, 0, 0, 0, 0, 0},
1771 {"debug-info", OPT_DEBUG_INFO, "This is a non-debug version. Catch this and exit.", 0,
1772 0, 0, GET_DISABLED, NO_ARG, 0, 0, 0, 0, 0, 0},
1773 #else
1774 {"debug", '#', "Output debug log.", &default_dbug_option,
1775 &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
1776 {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .",
1777 &debug_check_flag, &debug_check_flag, 0,
1778 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1779 {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
1780 &debug_info_flag, &debug_info_flag,
1781 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1782 #endif
1783 {"default_auth", OPT_DEFAULT_AUTH,
1784 "Default authentication client-side plugin to use.",
1785 &opt_default_auth, &opt_default_auth, 0,
1786 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1787 {"disable-log-bin", 'D', "Disable binary log. This is useful, if you "
1788 "enabled --to-last-log and are sending the output to the same MySQL server. "
1789 "This way you could avoid an endless loop. You would also like to use it "
1790 "when restoring after a crash to avoid duplication of the statements you "
1791 "already have. NOTE: you will need a SUPER privilege to use this option.",
1792 &disable_log_bin, &disable_log_bin, 0, GET_BOOL,
1793 NO_ARG, 0, 0, 0, 0, 0, 0},
1794 {"force-if-open", 'F', "Force if binlog was not closed properly.",
1795 &force_if_open_opt, &force_if_open_opt, 0, GET_BOOL, NO_ARG,
1796 1, 0, 0, 0, 0, 0},
1797 {"force-read", 'f', "Force reading unknown binlog events.",
1798 &force_opt, &force_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
1799 0, 0},
1800 {"hexdump", 'H', "Augment output with hexadecimal and ASCII event dump.",
1801 &opt_hexdump, &opt_hexdump, 0, GET_BOOL, NO_ARG,
1802 0, 0, 0, 0, 0, 0},
1803 {"host", 'h', "Get the binlog from server.", &host, &host,
1804 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1805 {"idempotent", 'i', "Notify the server to use idempotent mode before "
1806 "applying Row Events", &idempotent_mode, &idempotent_mode, 0,
1807 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1808 {"local-load", 'l', "Prepare local temporary files for LOAD DATA INFILE in the specified directory.",
1809 &dirname_for_local_load, &dirname_for_local_load, 0,
1810 GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1811 {"offset", 'o', "Skip the first N entries.", &offset, &offset,
1812 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1813 {"password", 'p', "Password to connect to remote server.",
1814 0, 0, 0, GET_PASSWORD, OPT_ARG, 0, 0, 0, 0, 0, 0},
1815 {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
1816 &opt_plugin_dir, &opt_plugin_dir, 0,
1817 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1818 {"port", 'P', "Port number to use for connection or 0 for default to, in "
1819 "order of preference, my.cnf, $MYSQL_TCP_PORT, "
1820 #if MYSQL_PORT_DEFAULT == 0
1821 "/etc/services, "
1822 #endif
1823 "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
1824 &port, &port, 0, GET_INT, REQUIRED_ARG,
1825 0, 0, 0, 0, 0, 0},
1826 {"protocol", OPT_MYSQL_PROTOCOL,
1827 "The protocol to use for connection (tcp, socket, pipe, memory).",
1828 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1829 {"read-from-remote-server", 'R', "Read binary logs from a MySQL server. "
1830 "This is an alias for read-from-remote-master=BINLOG-DUMP-NON-GTIDS.",
1831 &opt_remote_alias, &opt_remote_alias, 0, GET_BOOL, NO_ARG,
1832 0, 0, 0, 0, 0, 0},
1833 {"read-from-remote-master", OPT_REMOTE_PROTO,
1834 "Read binary logs from a MySQL server through the COM_BINLOG_DUMP or "
1835 "COM_BINLOG_DUMP_GTID commands by setting the option to either "
1836 "BINLOG-DUMP-NON-GTIDS or BINLOG-DUMP-GTIDS, respectively. If "
1837 "--read-from-remote-master=BINLOG-DUMP-GTIDS is combined with "
1838 "--exclude-gtids, transactions can be filtered out on the master "
1839 "avoiding unnecessary network traffic.",
1840 &opt_remote_proto_str, &opt_remote_proto_str, 0, GET_STR, REQUIRED_ARG,
1841 0, 0, 0, 0, 0, 0},
1842 {"raw", OPT_RAW_OUTPUT, "Requires -R. Output raw binlog data instead of SQL "
1843 "statements, output is to log files.",
1844 &raw_mode, &raw_mode, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
1845 0, 0},
1846 {"result-file", 'r', "Direct output to a given file. With --raw this is a "
1847 "prefix for the file names.",
1848 &output_file, &output_file, 0, GET_STR, REQUIRED_ARG,
1849 0, 0, 0, 0, 0, 0},
1850 {"secure-auth", OPT_SECURE_AUTH, "Refuse client connecting to server if it"
1851 " uses old (pre-4.1.1) protocol. Deprecated. Always TRUE",
1852 &opt_secure_auth, &opt_secure_auth, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
1853 {"server-id", OPT_SERVER_ID,
1854 "Extract only binlog entries created by the server having the given id.",
1855 &filter_server_id, &filter_server_id, 0, GET_ULONG,
1856 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1857 {"server-id-bits", 0,
1858 "Set number of significant bits in server-id",
1859 &opt_server_id_bits, &opt_server_id_bits,
1860 /* Default + Max 32 bits, minimum 7 bits */
1861 0, GET_UINT, REQUIRED_ARG, 32, 7, 32, 0, 0, 0},
1862 {"set-charset", OPT_SET_CHARSET,
1863 "Add 'SET NAMES character_set' to the output.", &charset,
1864 &charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1865 #if defined (_WIN32) && !defined (EMBEDDED_LIBRARY)
1866 {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
1867 "Base name of shared memory.", &shared_memory_base_name,
1868 &shared_memory_base_name,
1869 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1870 #endif
1871 {"short-form", 's', "Just show regular queries: no extra info and no "
1872 "row-based events. This is for testing only, and should not be used in "
1873 "production systems. If you want to suppress base64-output, consider "
1874 "using --base64-output=never instead.",
1875 &short_form, &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
1876 0, 0},
1877 {"socket", 'S', "The socket file to use for connection.",
1878 &sock, &sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0,
1879 0, 0},
1880 #include <sslopt-longopts.h>
1881 #include <caching_sha2_passwordopt-longopts.h>
1882 {"start-datetime", OPT_START_DATETIME,
1883 "Start reading the binlog at first event having a datetime equal or "
1884 "posterior to the argument; the argument must be a date and time "
1885 "in the local time zone, in any format accepted by the MySQL server "
1886 "for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 "
1887 "(you should probably use quotes for your shell to set it properly).",
1888 &start_datetime_str, &start_datetime_str,
1889 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1890 {"start-position", 'j',
1891 "Start reading the binlog at position N. Applies to the first binlog "
1892 "passed on the command line.",
1893 &start_position, &start_position, 0, GET_ULL,
1894 REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE,
1895 /* COM_BINLOG_DUMP accepts only 4 bytes for the position */
1896 (ulonglong)(~(uint32)0), 0, 0, 0},
1897 {"stop-datetime", OPT_STOP_DATETIME,
1898 "Stop reading the binlog at first event having a datetime equal or "
1899 "posterior to the argument; the argument must be a date and time "
1900 "in the local time zone, in any format accepted by the MySQL server "
1901 "for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 "
1902 "(you should probably use quotes for your shell to set it properly).",
1903 &stop_datetime_str, &stop_datetime_str,
1904 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1905 {"stop-never", OPT_STOP_NEVER, "Wait for more data from the server "
1906 "instead of stopping at the end of the last log. Implicitly sets "
1907 "--to-last-log but instead of stopping at the end of the last log "
1908 "it continues to wait till the server disconnects.",
1909 &stop_never, &stop_never, 0,
1910 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1911 {"stop-never-slave-server-id", OPT_WAIT_SERVER_ID,
1912 "The slave server_id used for --read-from-remote-server --stop-never."
1913 " This option cannot be used together with connection-server-id.",
1914 &stop_never_slave_server_id, &stop_never_slave_server_id, 0,
1915 GET_LL, REQUIRED_ARG, -1, -1, 0xFFFFFFFFLL, 0, 0, 0},
1916 {"connection-server-id", OPT_CONNECTION_SERVER_ID,
1917 "The slave server_id used for --read-from-remote-server."
1918 " This option cannot be used together with stop-never-slave-server-id.",
1919 &connection_server_id, &connection_server_id, 0,
1920 GET_LL, REQUIRED_ARG, -1, -1, 0xFFFFFFFFLL, 0, 0, 0},
1921 {"stop-position", OPT_STOP_POSITION,
1922 "Stop reading the binlog at position N. Applies to the last binlog "
1923 "passed on the command line.",
1924 &stop_position, &stop_position, 0, GET_ULL,
1925 REQUIRED_ARG, (longlong)(~(my_off_t)0), BIN_LOG_HEADER_SIZE,
1926 (ulonglong)(~(my_off_t)0), 0, 0, 0},
1927 {"to-last-log", 't', "Requires -R. Will not stop at the end of the "
1928 "requested binlog but rather continue printing until the end of the last "
1929 "binlog of the MySQL server. If you send the output to the same MySQL "
1930 "server, that may lead to an endless loop.",
1931 &to_last_remote_log, &to_last_remote_log, 0, GET_BOOL,
1932 NO_ARG, 0, 0, 0, 0, 0, 0},
1933 {"user", 'u', "Connect to the remote server as username.",
1934 &user, &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0,
1935 0, 0},
1936 {"verbose", 'v', "Reconstruct pseudo-SQL statements out of row events. "
1937 "-v -v adds comments on column data types.",
1938 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
1939 {"version", 'V', "Print version and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
1940 0, 0, 0, 0, 0},
1941 {"open_files_limit", OPT_OPEN_FILES_LIMIT,
1942 "Used to reserve file descriptors for use by this program.",
1943 &open_files_limit, &open_files_limit, 0, GET_ULONG,
1944 REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0},
1945 {"verify-binlog-checksum", 'c', "Verify checksum binlog events.",
1946 (uchar**) &opt_verify_binlog_checksum, (uchar**) &opt_verify_binlog_checksum,
1947 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1948 {"binlog-row-event-max-size", OPT_BINLOG_ROWS_EVENT_MAX_SIZE,
1949 "The maximum size of a row-based binary log event in bytes. Rows will be "
1950 "grouped into events smaller than this size if possible. "
1951 "This value must be a multiple of 256.",
1952 &opt_binlog_rows_event_max_size,
1953 &opt_binlog_rows_event_max_size, 0,
1954 GET_ULONG, REQUIRED_ARG,
1955 /* def_value 4GB */ UINT_MAX, /* min_value */ 256,
1956 /* max_value */ ULONG_MAX, /* sub_size */ 0,
1957 /* block_size */ 256, /* app_type */ 0},
1958 {"skip-gtids", OPT_MYSQLBINLOG_SKIP_GTIDS,
1959 "Do not preserve Global Transaction Identifiers; instead make the server "
1960 "execute the transactions as if they were new.",
1961 &opt_skip_gtids, &opt_skip_gtids, 0,
1962 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1963 {"include-gtids", OPT_MYSQLBINLOG_INCLUDE_GTIDS,
1964 "Print events whose Global Transaction Identifiers "
1965 "were provided.",
1966 &opt_include_gtids_str, &opt_include_gtids_str, 0,
1967 GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1968 {"exclude-gtids", OPT_MYSQLBINLOG_EXCLUDE_GTIDS,
1969 "Print all events but those whose Global Transaction "
1970 "Identifiers were provided.",
1971 &opt_exclude_gtids_str, &opt_exclude_gtids_str, 0,
1972 GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1973 {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
1974 };
1975
1976
1977 /**
1978 Auxiliary function used by error() and warning().
1979
1980 Prints the given text (normally "WARNING: " or "ERROR: "), followed
1981 by the given vprintf-style string, followed by a newline.
1982
1983 @param format Printf-style format string.
1984 @param args List of arguments for the format string.
1985 @param msg Text to print before the string.
1986 */
error_or_warning(const char * format,va_list args,const char * msg)1987 static void error_or_warning(const char *format, va_list args, const char *msg)
1988 {
1989 fprintf(stderr, "%s: ", msg);
1990 vfprintf(stderr, format, args);
1991 fprintf(stderr, "\n");
1992 }
1993
1994 /**
1995 Prints a message to stderr, prefixed with the text "ERROR: " and
1996 suffixed with a newline.
1997
1998 @param format Printf-style format string, followed by printf
1999 varargs.
2000 */
error(const char * format,...)2001 static void error(const char *format,...)
2002 {
2003 va_list args;
2004 va_start(args, format);
2005 error_or_warning(format, args, "ERROR");
2006 va_end(args);
2007 }
2008
2009
2010 /**
2011 This function is used in log_event.cc to report errors.
2012
2013 @param format Printf-style format string, followed by printf
2014 varargs.
2015 */
sql_print_error(const char * format,...)2016 static void sql_print_error(const char *format,...)
2017 {
2018 va_list args;
2019 va_start(args, format);
2020 error_or_warning(format, args, "ERROR");
2021 va_end(args);
2022 }
2023
2024 /**
2025 Prints a message to stderr, prefixed with the text "WARNING: " and
2026 suffixed with a newline.
2027
2028 @param format Printf-style format string, followed by printf
2029 varargs.
2030 */
warning(const char * format,...)2031 static void warning(const char *format,...)
2032 {
2033 va_list args;
2034 va_start(args, format);
2035 error_or_warning(format, args, "WARNING");
2036 va_end(args);
2037 }
2038
2039 /**
2040 Frees memory for global variables in this file.
2041 */
cleanup()2042 static void cleanup()
2043 {
2044 my_free(pass);
2045 my_free(database);
2046 my_free(rewrite);
2047 my_free(host);
2048 my_free(user);
2049 my_free(dirname_for_local_load);
2050
2051 for (size_t i= 0; i < buff_ev->size(); i++)
2052 {
2053 buff_event_info pop_event_array= buff_ev->at(i);
2054 delete (pop_event_array.event);
2055 }
2056 delete buff_ev;
2057
2058 delete glob_description_event;
2059 if (mysql)
2060 mysql_close(mysql);
2061 }
2062
2063
print_version()2064 static void print_version()
2065 {
2066 printf("%s Ver 3.4 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE);
2067 }
2068
2069
usage()2070 static void usage()
2071 {
2072 print_version();
2073 puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"));
2074 printf("\
2075 Dumps a MySQL binary log in a format usable for viewing or for piping to\n\
2076 the mysql command line client.\n\n");
2077 printf("Usage: %s [options] log-files\n", my_progname);
2078 /*
2079 Turn default for zombies off so that the help on how to
2080 turn them off text won't show up.
2081 This is safe to do since it's followed by a call to exit().
2082 */
2083 for (struct my_option *optp= my_long_options; optp->name; optp++)
2084 {
2085 if (optp->id == OPT_SECURE_AUTH)
2086 {
2087 optp->def_value= 0;
2088 break;
2089 }
2090 }
2091 my_print_help(my_long_options);
2092 my_print_variables(my_long_options);
2093 }
2094
2095
convert_str_to_timestamp(const char * str)2096 static my_time_t convert_str_to_timestamp(const char* str)
2097 {
2098 MYSQL_TIME_STATUS status;
2099 MYSQL_TIME l_time;
2100 long dummy_my_timezone;
2101 my_bool dummy_in_dst_time_gap;
2102 /* We require a total specification (date AND time) */
2103 if (str_to_datetime(str, strlen(str), &l_time, 0, &status) ||
2104 l_time.time_type != MYSQL_TIMESTAMP_DATETIME || status.warnings)
2105 {
2106 error("Incorrect date and time argument: %s", str);
2107 exit(1);
2108 }
2109 /*
2110 Note that Feb 30th, Apr 31st cause no error messages and are mapped to
2111 the next existing day, like in mysqld. Maybe this could be changed when
2112 mysqld is changed too (with its "strict" mode?).
2113 */
2114 return
2115 my_system_gmt_sec(&l_time, &dummy_my_timezone, &dummy_in_dst_time_gap);
2116 }
2117
2118
2119 extern "C" my_bool
get_one_option(int optid,const struct my_option * opt MY_ATTRIBUTE ((unused)),char * argument)2120 get_one_option(int optid, const struct my_option *opt MY_ATTRIBUTE((unused)),
2121 char *argument)
2122 {
2123 bool tty_password=0;
2124 switch (optid) {
2125 #ifndef DBUG_OFF
2126 case '#':
2127 DBUG_PUSH(argument ? argument : default_dbug_option);
2128 break;
2129 #endif
2130 #include <sslopt-case.h>
2131 case 'd':
2132 one_database = 1;
2133 break;
2134 case OPT_REWRITE_DB:
2135 {
2136 char *from_db= argument, *p, *to_db;
2137 if (!(p= strstr(argument, "->")))
2138 {
2139 sql_print_error("Bad syntax in mysqlbinlog-rewrite-db - missing '->'!\n");
2140 return 1;
2141 }
2142 to_db= p + 2;
2143 while(p > argument && my_isspace(mysqld_charset, p[-1]))
2144 p--;
2145 *p= 0;
2146 if (!*from_db)
2147 {
2148 sql_print_error("Bad syntax in mysqlbinlog-rewrite-db - empty FROM db!\n");
2149 return 1;
2150 }
2151 while (*to_db && my_isspace(mysqld_charset, *to_db))
2152 to_db++;
2153 if (!*to_db)
2154 {
2155 sql_print_error("Bad syntax in mysqlbinlog-rewrite-db - empty TO db!\n");
2156 return 1;
2157 }
2158 /* Add the database to the mapping */
2159 map_mysqlbinlog_rewrite_db[from_db]= to_db;
2160 break;
2161 }
2162 case 'p':
2163 if (argument == disabled_my_option)
2164 argument= (char*) ""; // Don't require password
2165 if (argument)
2166 {
2167 my_free(pass);
2168 char *start=argument;
2169 pass= my_strdup(PSI_NOT_INSTRUMENTED,
2170 argument,MYF(MY_FAE));
2171 while (*argument) *argument++= 'x'; /* Destroy argument */
2172 if (*start)
2173 start[1]=0; /* Cut length of argument */
2174 }
2175 else
2176 tty_password=1;
2177 break;
2178 case 'R':
2179 opt_remote_alias= 1;
2180 opt_remote_proto= BINLOG_DUMP_NON_GTID;
2181 break;
2182 case OPT_REMOTE_PROTO:
2183 opt_remote_proto= (enum_remote_proto)
2184 (find_type_or_exit(argument, &remote_proto_typelib, opt->name) - 1);
2185 break;
2186 case OPT_MYSQL_PROTOCOL:
2187 opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
2188 opt->name);
2189 break;
2190 case OPT_START_DATETIME:
2191 start_datetime= convert_str_to_timestamp(start_datetime_str);
2192 break;
2193 case OPT_STOP_DATETIME:
2194 stop_datetime= convert_str_to_timestamp(stop_datetime_str);
2195 break;
2196 case OPT_BASE64_OUTPUT_MODE:
2197 opt_base64_output_mode= (enum_base64_output_mode)
2198 (find_type_or_exit(argument, &base64_output_mode_typelib, opt->name)-1);
2199 break;
2200 case 'v':
2201 if (argument == disabled_my_option)
2202 verbose= 0;
2203 else
2204 verbose++;
2205 break;
2206 case 'V':
2207 print_version();
2208 exit(0);
2209 case OPT_STOP_NEVER:
2210 /* wait-for-data implicitly sets to-last-log */
2211 to_last_remote_log= 1;
2212 break;
2213 case '?':
2214 usage();
2215 exit(0);
2216 case OPT_SECURE_AUTH:
2217 /* --secure-auth is a zombie option. */
2218 if (!opt_secure_auth)
2219 {
2220 fprintf(stderr, "mysqlbinlog: [ERROR] --skip-secure-auth is not supported.\n");
2221 exit(1);
2222 }
2223 else
2224 CLIENT_WARN_DEPRECATED_NO_REPLACEMENT("--secure-auth");
2225 break;
2226
2227 }
2228 if (tty_password)
2229 pass= get_tty_password(NullS);
2230
2231 return 0;
2232 }
2233
2234
parse_args(int * argc,char *** argv)2235 static int parse_args(int *argc, char*** argv)
2236 {
2237 int ho_error;
2238
2239 result_file = stdout;
2240 if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
2241 exit(ho_error);
2242 if (debug_info_flag)
2243 my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
2244 if (debug_check_flag)
2245 my_end_arg= MY_CHECK_ERROR;
2246 return 0;
2247 }
2248
2249
2250 /**
2251 Create and initialize the global mysql object, and connect to the
2252 server.
2253
2254 @retval ERROR_STOP An error occurred - the program should terminate.
2255 @retval OK_CONTINUE No error, the program should continue.
2256 */
safe_connect()2257 static Exit_status safe_connect()
2258 {
2259 /*
2260 A possible old connection's resources are reclaimed now
2261 at new connect attempt. The final safe_connect resources
2262 are mysql_closed at the end of program, explicitly.
2263 */
2264 mysql_close(mysql);
2265 mysql= mysql_init(NULL);
2266
2267 if (!mysql)
2268 {
2269 error("Failed on mysql_init.");
2270 return ERROR_STOP;
2271 }
2272
2273 SSL_SET_OPTIONS(mysql);
2274
2275 if (opt_plugin_dir && *opt_plugin_dir)
2276 mysql_options(mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);
2277
2278 if (opt_default_auth && *opt_default_auth)
2279 mysql_options(mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
2280
2281 if (opt_protocol)
2282 mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol);
2283 if (opt_bind_addr)
2284 mysql_options(mysql, MYSQL_OPT_BIND, opt_bind_addr);
2285 #if defined (_WIN32) && !defined (EMBEDDED_LIBRARY)
2286 if (shared_memory_base_name)
2287 mysql_options(mysql, MYSQL_SHARED_MEMORY_BASE_NAME,
2288 shared_memory_base_name);
2289 #endif
2290 mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
2291 mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
2292 "program_name", "mysqlbinlog");
2293 mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
2294 "_client_role", "binary_log_listener");
2295
2296 set_server_public_key(mysql);
2297 set_get_server_public_key_option(mysql);
2298
2299 if (!mysql_real_connect(mysql, host, user, pass, 0, port, sock, 0))
2300 {
2301 error("Failed on connect: %s", mysql_error(mysql));
2302 return ERROR_STOP;
2303 }
2304 mysql->reconnect= 1;
2305 return OK_CONTINUE;
2306 }
2307
2308
2309 /**
2310 High-level function for dumping a named binlog.
2311
2312 This function calls dump_remote_log_entries() or
2313 dump_local_log_entries() to do the job.
2314
2315 @param[in] logname Name of input binlog.
2316
2317 @retval ERROR_STOP An error occurred - the program should terminate.
2318 @retval OK_CONTINUE No error, the program should continue.
2319 @retval OK_STOP No error, but the end of the specified range of
2320 events to process has been reached and the program should terminate.
2321 */
dump_single_log(PRINT_EVENT_INFO * print_event_info,const char * logname)2322 static Exit_status dump_single_log(PRINT_EVENT_INFO *print_event_info,
2323 const char* logname)
2324 {
2325 DBUG_ENTER("dump_single_log");
2326
2327 Exit_status rc= OK_CONTINUE;
2328
2329 switch (opt_remote_proto)
2330 {
2331 case BINLOG_LOCAL:
2332 rc= dump_local_log_entries(print_event_info, logname);
2333 break;
2334 case BINLOG_DUMP_NON_GTID:
2335 case BINLOG_DUMP_GTID:
2336 rc= dump_remote_log_entries(print_event_info, logname);
2337 break;
2338 default:
2339 DBUG_ASSERT(0);
2340 break;
2341 }
2342 DBUG_RETURN(rc);
2343 }
2344
2345
dump_multiple_logs(int argc,char ** argv)2346 static Exit_status dump_multiple_logs(int argc, char **argv)
2347 {
2348 DBUG_ENTER("dump_multiple_logs");
2349 Exit_status rc= OK_CONTINUE;
2350
2351 PRINT_EVENT_INFO print_event_info;
2352 if (!print_event_info.init_ok())
2353 DBUG_RETURN(ERROR_STOP);
2354 /*
2355 Set safe delimiter, to dump things
2356 like CREATE PROCEDURE safely
2357 */
2358 if (!raw_mode)
2359 {
2360 fprintf(result_file, "DELIMITER /*!*/;\n");
2361 }
2362 my_stpcpy(print_event_info.delimiter, "/*!*/;");
2363
2364 print_event_info.verbose= short_form ? 0 : verbose;
2365 print_event_info.short_form= short_form;
2366 print_event_info.base64_output_mode= opt_base64_output_mode;
2367 print_event_info.skip_gtids= opt_skip_gtids;
2368
2369 // Dump all logs.
2370 my_off_t save_stop_position= stop_position;
2371 stop_position= ~(my_off_t)0;
2372 for (int i= 0; i < argc; i++)
2373 {
2374 if (i == argc - 1) // last log, --stop-position applies
2375 stop_position= save_stop_position;
2376 if ((rc= dump_single_log(&print_event_info, argv[i])) != OK_CONTINUE)
2377 break;
2378
2379 // For next log, --start-position does not apply
2380 start_position= BIN_LOG_HEADER_SIZE;
2381 }
2382
2383 if (!buff_ev->empty())
2384 warning("The range of printed events ends with an Intvar_event, "
2385 "Rand_event or User_var_event with no matching Query_log_event. "
2386 "This might be because the last statement was not fully written "
2387 "to the log, or because you are using a --stop-position or "
2388 "--stop-datetime that refers to an event in the middle of a "
2389 "statement. The event(s) from the partial statement have not been "
2390 "written to output. ");
2391
2392 else if (print_event_info.have_unflushed_events)
2393 warning("The range of printed events ends with a row event or "
2394 "a table map event that does not have the STMT_END_F "
2395 "flag set. This might be because the last statement "
2396 "was not fully written to the log, or because you are "
2397 "using a --stop-position or --stop-datetime that refers "
2398 "to an event in the middle of a statement. The event(s) "
2399 "from the partial statement have not been written to output.");
2400
2401 /* Set delimiter back to semicolon */
2402 if (!raw_mode)
2403 {
2404 if (print_event_info.skipped_event_in_transaction)
2405 fprintf(result_file, "COMMIT /* added by mysqlbinlog */%s\n",
2406 print_event_info.delimiter);
2407
2408 end_binlog(&print_event_info);
2409
2410 fprintf(result_file, "DELIMITER ;\n");
2411 my_stpcpy(print_event_info.delimiter, ";");
2412 }
2413 DBUG_RETURN(rc);
2414 }
2415
2416
2417 /**
2418 When reading a remote binlog, this function is used to grab the
2419 Format_description_log_event in the beginning of the stream.
2420
2421 This is not as smart as check_header() (used for local log); it will
2422 not work for a binlog which mixes format. TODO: fix this.
2423
2424 @retval ERROR_STOP An error occurred - the program should terminate.
2425 @retval OK_CONTINUE No error, the program should continue.
2426 */
check_master_version()2427 static Exit_status check_master_version()
2428 {
2429 DBUG_ENTER("check_master_version");
2430 MYSQL_RES* res = 0;
2431 MYSQL_ROW row;
2432 const char* version;
2433
2434 if (mysql_query(mysql, "SELECT VERSION()") ||
2435 !(res = mysql_store_result(mysql)))
2436 {
2437 error("Could not find server version: "
2438 "Query failed when checking master version: %s", mysql_error(mysql));
2439 DBUG_RETURN(ERROR_STOP);
2440 }
2441 if (!(row = mysql_fetch_row(res)))
2442 {
2443 error("Could not find server version: "
2444 "Master returned no rows for SELECT VERSION().");
2445 goto err;
2446 }
2447
2448 if (!(version = row[0]))
2449 {
2450 error("Could not find server version: "
2451 "Master reported NULL for the version.");
2452 goto err;
2453 }
2454 /*
2455 Make a notice to the server that this client
2456 is checksum-aware. It does not need the first fake Rotate
2457 necessary checksummed.
2458 That preference is specified below.
2459 */
2460 if (mysql_query(mysql, "SET @master_binlog_checksum='NONE'"))
2461 {
2462 error("Could not notify master about checksum awareness."
2463 "Master returned '%s'", mysql_error(mysql));
2464 goto err;
2465 }
2466 delete glob_description_event;
2467 switch (*version) {
2468 case '3':
2469 glob_description_event= new Format_description_log_event(1);
2470 break;
2471 case '4':
2472 glob_description_event= new Format_description_log_event(3);
2473 break;
2474 case '5':
2475 /*
2476 The server is soon going to send us its Format_description log
2477 event, unless it is a 5.0 server with 3.23 or 4.0 binlogs.
2478 So we first assume that this is 4.0 (which is enough to read the
2479 Format_desc event if one comes).
2480 */
2481 glob_description_event= new Format_description_log_event(3);
2482 break;
2483 default:
2484 glob_description_event= NULL;
2485 error("Could not find server version: "
2486 "Master reported unrecognized MySQL version '%s'.", version);
2487 goto err;
2488 }
2489 if (!glob_description_event || !glob_description_event->is_valid())
2490 {
2491 error("Failed creating Format_description_log_event; out of memory?");
2492 goto err;
2493 }
2494
2495 mysql_free_result(res);
2496 DBUG_RETURN(OK_CONTINUE);
2497
2498 err:
2499 mysql_free_result(res);
2500 DBUG_RETURN(ERROR_STOP);
2501 }
2502
2503
get_dump_flags()2504 static int get_dump_flags()
2505 {
2506 return stop_never ? 0 : BINLOG_DUMP_NON_BLOCK;
2507 }
2508
2509
2510 /**
2511 Requests binlog dump from a remote server and prints the events it
2512 receives.
2513
2514 @param[in,out] print_event_info Parameters and context state
2515 determining how to print.
2516 @param[in] logname Name of input binlog.
2517
2518 @retval ERROR_STOP An error occurred - the program should terminate.
2519 @retval OK_CONTINUE No error, the program should continue.
2520 @retval OK_STOP No error, but the end of the specified range of
2521 events to process has been reached and the program should terminate.
2522 */
dump_remote_log_entries(PRINT_EVENT_INFO * print_event_info,const char * logname)2523 static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
2524 const char* logname)
2525 {
2526 uchar *command_buffer= NULL;
2527 size_t command_size= 0;
2528 ulong len= 0;
2529 size_t logname_len= 0;
2530 uint server_id= 0;
2531 NET* net= NULL;
2532 my_off_t old_off= start_position_mot;
2533 char fname[FN_REFLEN + 1];
2534 char log_file_name[FN_REFLEN + 1];
2535 Exit_status retval= OK_CONTINUE;
2536 enum enum_server_command command= COM_END;
2537 char *event_buf= NULL;
2538 ulong event_len;
2539 DBUG_ENTER("dump_remote_log_entries");
2540
2541 fname[0]= log_file_name[0]= 0;
2542
2543 /*
2544 Even if we already read one binlog (case of >=2 binlogs on command line),
2545 we cannot re-use the same connection as before, because it is now dead
2546 (COM_BINLOG_DUMP kills the thread when it finishes).
2547 */
2548 if ((retval= safe_connect()) != OK_CONTINUE)
2549 DBUG_RETURN(retval);
2550 net= &mysql->net;
2551
2552 if ((retval= check_master_version()) != OK_CONTINUE)
2553 DBUG_RETURN(retval);
2554
2555 /*
2556 Fake a server ID to log continously. This will show as a
2557 slave on the mysql server.
2558 */
2559 if (to_last_remote_log && stop_never)
2560 {
2561 if (stop_never_slave_server_id == -1)
2562 server_id= 1;
2563 else
2564 server_id= static_cast<uint>(stop_never_slave_server_id);
2565 }
2566 else
2567 server_id= 0;
2568
2569 if (connection_server_id != -1)
2570 server_id= static_cast<uint>(connection_server_id);
2571
2572 size_t tlen = strlen(logname);
2573 if (tlen > UINT_MAX)
2574 {
2575 error("Log name too long.");
2576 DBUG_RETURN(ERROR_STOP);
2577 }
2578 const size_t BINLOG_NAME_INFO_SIZE= logname_len= tlen;
2579
2580 if (opt_remote_proto == BINLOG_DUMP_NON_GTID)
2581 {
2582 command= COM_BINLOG_DUMP;
2583 size_t allocation_size= ::BINLOG_POS_OLD_INFO_SIZE +
2584 BINLOG_NAME_INFO_SIZE + ::BINLOG_FLAGS_INFO_SIZE +
2585 ::BINLOG_SERVER_ID_INFO_SIZE + 1;
2586 if (!(command_buffer= (uchar *) my_malloc(PSI_NOT_INSTRUMENTED,
2587 allocation_size, MYF(MY_WME))))
2588 {
2589 error("Got fatal error allocating memory.");
2590 DBUG_RETURN(ERROR_STOP);
2591 }
2592 uchar* ptr_buffer= command_buffer;
2593
2594 /*
2595 COM_BINLOG_DUMP accepts only 4 bytes for the position, so
2596 we are forced to cast to uint32.
2597 */
2598 int4store(ptr_buffer, (uint32) start_position);
2599 ptr_buffer+= ::BINLOG_POS_OLD_INFO_SIZE;
2600 int2store(ptr_buffer, get_dump_flags());
2601 ptr_buffer+= ::BINLOG_FLAGS_INFO_SIZE;
2602 int4store(ptr_buffer, server_id);
2603 ptr_buffer+= ::BINLOG_SERVER_ID_INFO_SIZE;
2604 memcpy(ptr_buffer, logname, BINLOG_NAME_INFO_SIZE);
2605 ptr_buffer+= BINLOG_NAME_INFO_SIZE;
2606
2607 command_size= ptr_buffer - command_buffer;
2608 DBUG_ASSERT(command_size == (allocation_size - 1));
2609 }
2610 else
2611 {
2612 command= COM_BINLOG_DUMP_GTID;
2613
2614 global_sid_lock->rdlock();
2615
2616 // allocate buffer
2617 size_t encoded_data_size= gtid_set_excluded->get_encoded_length();
2618 size_t allocation_size=
2619 ::BINLOG_FLAGS_INFO_SIZE + ::BINLOG_SERVER_ID_INFO_SIZE +
2620 ::BINLOG_NAME_SIZE_INFO_SIZE + BINLOG_NAME_INFO_SIZE +
2621 ::BINLOG_POS_INFO_SIZE + ::BINLOG_DATA_SIZE_INFO_SIZE +
2622 encoded_data_size + 1;
2623 if (!(command_buffer= (uchar *) my_malloc(PSI_NOT_INSTRUMENTED,
2624 allocation_size, MYF(MY_WME))))
2625 {
2626 error("Got fatal error allocating memory.");
2627 global_sid_lock->unlock();
2628 DBUG_RETURN(ERROR_STOP);
2629 }
2630 uchar* ptr_buffer= command_buffer;
2631
2632 int2store(ptr_buffer, get_dump_flags());
2633 ptr_buffer+= ::BINLOG_FLAGS_INFO_SIZE;
2634 int4store(ptr_buffer, server_id);
2635 ptr_buffer+= ::BINLOG_SERVER_ID_INFO_SIZE;
2636 int4store(ptr_buffer, static_cast<uint32>(BINLOG_NAME_INFO_SIZE));
2637 ptr_buffer+= ::BINLOG_NAME_SIZE_INFO_SIZE;
2638 memcpy(ptr_buffer, logname, BINLOG_NAME_INFO_SIZE);
2639 ptr_buffer+= BINLOG_NAME_INFO_SIZE;
2640 int8store(ptr_buffer, start_position);
2641 ptr_buffer+= ::BINLOG_POS_INFO_SIZE;
2642 int4store(ptr_buffer, static_cast<uint32>(encoded_data_size));
2643 ptr_buffer+= ::BINLOG_DATA_SIZE_INFO_SIZE;
2644 gtid_set_excluded->encode(ptr_buffer);
2645 ptr_buffer+= encoded_data_size;
2646
2647 global_sid_lock->unlock();
2648
2649 command_size= ptr_buffer - command_buffer;
2650 DBUG_ASSERT(command_size == (allocation_size - 1));
2651 }
2652
2653 if (simple_command(mysql, command, command_buffer, command_size, 1))
2654 {
2655 error("Got fatal error sending the log dump command.");
2656 my_free(command_buffer);
2657 DBUG_RETURN(ERROR_STOP);
2658 }
2659 my_free(command_buffer);
2660
2661 for (;;)
2662 {
2663 const char *error_msg= NULL;
2664 Log_event *ev= NULL;
2665 Log_event_type type= binary_log::UNKNOWN_EVENT;
2666
2667 len= cli_safe_read(mysql, NULL);
2668 if (len == packet_error)
2669 {
2670 error("Got error reading packet from server: %s", mysql_error(mysql));
2671 DBUG_RETURN(ERROR_STOP);
2672 }
2673 if (len < 8 && net->read_pos[0] == 254)
2674 break; // end of data
2675 DBUG_PRINT("info",( "len: %lu net->read_pos[5]: %d\n",
2676 len, net->read_pos[5]));
2677 /*
2678 In raw mode We only need the full event details if it is a
2679 ROTATE_EVENT or FORMAT_DESCRIPTION_EVENT
2680 */
2681
2682 type= (Log_event_type) net->read_pos[1 + EVENT_TYPE_OFFSET];
2683
2684 /*
2685 Ignore HEARBEAT events. They can show up if mysqlbinlog is
2686 running with:
2687
2688 --read-from-remote-server
2689 --read-from-remote-master=BINLOG-DUMP-GTIDS'
2690 --stop-never
2691 --stop-never-slave-server-id
2692
2693 i.e., acting as a fake slave.
2694 */
2695 if (type == binary_log::HEARTBEAT_LOG_EVENT)
2696 continue;
2697 event_len= len - 1;
2698 if (!(event_buf = (char*) my_malloc(key_memory_log_event,
2699 event_len+1, MYF(0))))
2700 {
2701 error("Out of memory.");
2702 DBUG_RETURN(ERROR_STOP);
2703 }
2704 memcpy(event_buf, net->buff + 1, event_len);
2705 if (rewrite_db_filter(&event_buf, &event_len, glob_description_event))
2706 {
2707 error("Got a fatal error while applying rewrite db filter.");
2708 my_free(event_buf);
2709 DBUG_RETURN(ERROR_STOP);
2710 }
2711
2712 if (!raw_mode || (type == binary_log::ROTATE_EVENT) ||
2713 (type == binary_log::FORMAT_DESCRIPTION_EVENT))
2714 {
2715 if (!(ev= Log_event::read_log_event((const char*) event_buf,
2716 event_len, &error_msg,
2717 glob_description_event,
2718 opt_verify_binlog_checksum)))
2719 {
2720 error("Could not construct log event object: %s", error_msg);
2721 my_free(event_buf);
2722 DBUG_RETURN(ERROR_STOP);
2723 }
2724 ev->register_temp_buf(event_buf);
2725 }
2726 if (raw_mode || (type != binary_log::LOAD_EVENT))
2727 {
2728 /*
2729 If this is a Rotate event, maybe it's the end of the requested binlog;
2730 in this case we are done (stop transfer).
2731 This is suitable for binlogs, not relay logs (but for now we don't read
2732 relay logs remotely because the server is not able to do that). If one
2733 day we read relay logs remotely, then we will have a problem with the
2734 detection below: relay logs contain Rotate events which are about the
2735 binlogs, so which would trigger the end-detection below.
2736 */
2737 if (type == binary_log::ROTATE_EVENT)
2738 {
2739 Rotate_log_event *rev= (Rotate_log_event *)ev;
2740 /*
2741 If this is a fake Rotate event, and not about our log, we can stop
2742 transfer. If this a real Rotate event (so it's not about our log,
2743 it's in our log describing the next log), we print it (because it's
2744 part of our log) and then we will stop when we receive the fake one
2745 soon.
2746 */
2747 if (raw_mode)
2748 {
2749 if (output_file != 0)
2750 {
2751 my_snprintf(log_file_name, sizeof(log_file_name), "%s%s",
2752 output_file, rev->new_log_ident);
2753 }
2754 else
2755 {
2756 my_stpcpy(log_file_name, rev->new_log_ident);
2757 }
2758 }
2759
2760 if (rev->common_header->when.tv_sec == 0)
2761 {
2762 if (!to_last_remote_log)
2763 {
2764 if ((rev->ident_len != logname_len) ||
2765 memcmp(rev->new_log_ident, logname, logname_len))
2766 {
2767 reset_temp_buf_and_delete(rev);
2768 DBUG_RETURN(OK_CONTINUE);
2769 }
2770 /*
2771 Otherwise, this is a fake Rotate for our log, at the very
2772 beginning for sure. Skip it, because it was not in the original
2773 log. If we are running with to_last_remote_log, we print it,
2774 because it serves as a useful marker between binlogs then.
2775 */
2776 reset_temp_buf_and_delete(rev);
2777 continue;
2778 }
2779 /*
2780 Reset the value of '# at pos' field shown against first event of
2781 next binlog file (fake rotate) picked by mysqlbinlog --to-last-log
2782 */
2783 old_off= start_position_mot;
2784 len= 1; // fake Rotate, so don't increment old_off
2785 event_len= 0;
2786 }
2787 }
2788 else if (type == binary_log::FORMAT_DESCRIPTION_EVENT)
2789 {
2790 /*
2791 This could be an fake Format_description_log_event that server
2792 (5.0+) automatically sends to a slave on connect, before sending
2793 a first event at the requested position. If this is the case,
2794 don't increment old_off. Real Format_description_log_event always
2795 starts from BIN_LOG_HEADER_SIZE position.
2796 */
2797 // fake event when not in raw mode, don't increment old_off
2798 if ((old_off != BIN_LOG_HEADER_SIZE) && (!raw_mode))
2799 {
2800 len= 1;
2801 event_len= 0;
2802 }
2803 if (raw_mode)
2804 {
2805 if (result_file && (result_file != stdout))
2806 my_fclose(result_file, MYF(0));
2807 if (!(result_file = my_fopen(log_file_name, O_WRONLY | O_BINARY,
2808 MYF(MY_WME))))
2809 {
2810 error("Could not create log file '%s'", log_file_name);
2811 reset_temp_buf_and_delete(ev);
2812 DBUG_RETURN(ERROR_STOP);
2813 }
2814 DBUG_EXECUTE_IF("simulate_result_file_write_error_for_FD_event",
2815 DBUG_SET("+d,simulate_fwrite_error"););
2816 if (my_fwrite(result_file, (const uchar*) BINLOG_MAGIC,
2817 BIN_LOG_HEADER_SIZE, MYF(MY_NABP)))
2818 {
2819 error("Could not write into log file '%s'", log_file_name);
2820 reset_temp_buf_and_delete(ev);
2821 DBUG_RETURN(ERROR_STOP);
2822 }
2823 /*
2824 Need to handle these events correctly in raw mode too
2825 or this could get messy
2826 */
2827 delete glob_description_event;
2828 glob_description_event= (Format_description_log_event*) ev;
2829 print_event_info->common_header_len= glob_description_event->common_header_len;
2830 ev->temp_buf= 0;
2831 ev= 0;
2832 }
2833 }
2834
2835 if (type == binary_log::LOAD_EVENT)
2836 {
2837 DBUG_ASSERT(raw_mode);
2838 warning("Attempting to load a remote pre-4.0 binary log that contains "
2839 "LOAD DATA INFILE statements. The file will not be copied from "
2840 "the remote server. ");
2841 }
2842
2843 if (raw_mode)
2844 {
2845 DBUG_EXECUTE_IF("simulate_result_file_write_error",
2846 DBUG_SET("+d,simulate_fwrite_error"););
2847 if (my_fwrite(result_file, (const uchar*)event_buf, event_len,
2848 MYF(MY_NABP)))
2849 {
2850 error("Could not write into log file '%s'", log_file_name);
2851 retval= ERROR_STOP;
2852 }
2853 if (ev)
2854 reset_temp_buf_and_delete(ev);
2855 else
2856 my_free(event_buf);
2857
2858 /* Flush result_file after every event */
2859 fflush(result_file);
2860 }
2861 else
2862 {
2863 retval= process_event(print_event_info, ev, old_off, logname);
2864 }
2865
2866 if (retval != OK_CONTINUE)
2867 DBUG_RETURN(retval);
2868 }
2869 else
2870 {
2871 Load_log_event *le= (Load_log_event*)ev;
2872 const char *old_fname= le->fname;
2873 size_t old_len= le->fname_len;
2874 File file;
2875
2876 if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0)
2877 {
2878 reset_temp_buf_and_delete(ev);
2879 DBUG_RETURN(ERROR_STOP);
2880 }
2881
2882 retval= process_event(print_event_info, ev, old_off, logname);
2883 if (retval != OK_CONTINUE)
2884 {
2885 my_close(file,MYF(MY_WME));
2886 DBUG_RETURN(retval);
2887 }
2888 retval= load_processor.load_old_format_file(net,old_fname,old_len,file);
2889 my_close(file,MYF(MY_WME));
2890 if (retval != OK_CONTINUE)
2891 DBUG_RETURN(retval);
2892 }
2893 /*
2894 Let's adjust offset for remote log as for local log to produce
2895 similar text and to have --stop-position to work identically.
2896 */
2897 old_off+= len-1;
2898 }
2899
2900 DBUG_RETURN(OK_CONTINUE);
2901 }
2902
2903
2904 /**
2905 Reads the @c Format_description_log_event from the beginning of a
2906 local input file.
2907
2908 The @c Format_description_log_event is only read if it is outside
2909 the range specified with @c --start-position; otherwise, it will be
2910 seen later. If this is an old binlog, a fake @c
2911 Format_description_event is created. This also prints a @c
2912 Format_description_log_event to the output, unless we reach the
2913 --start-position range. In this case, it is assumed that a @c
2914 Format_description_log_event will be found when reading events the
2915 usual way.
2916
2917 @param file The file to which a @c Format_description_log_event will
2918 be printed.
2919
2920 @param[in,out] print_event_info Parameters and context state
2921 determining how to print.
2922
2923 @param[in] logname Name of input binlog.
2924
2925 @retval ERROR_STOP An error occurred - the program should terminate.
2926 @retval OK_CONTINUE No error, the program should continue.
2927 @retval OK_STOP No error, but the end of the specified range of
2928 events to process has been reached and the program should terminate.
2929 */
check_header(IO_CACHE * file,PRINT_EVENT_INFO * print_event_info,const char * logname)2930 static Exit_status check_header(IO_CACHE* file,
2931 PRINT_EVENT_INFO *print_event_info,
2932 const char* logname)
2933 {
2934 DBUG_ENTER("check_header");
2935 uchar header[BIN_LOG_HEADER_SIZE];
2936 uchar buf[LOG_EVENT_HEADER_LEN];
2937 my_off_t tmp_pos, pos;
2938 MY_STAT my_file_stat;
2939
2940 delete glob_description_event;
2941 if (!(glob_description_event= new Format_description_log_event(3)))
2942 {
2943 error("Failed creating Format_description_log_event; out of memory?");
2944 DBUG_RETURN(ERROR_STOP);
2945 }
2946
2947 pos= my_b_tell(file);
2948
2949 /* fstat the file to check if the file is a regular file. */
2950 if (my_fstat(file->file, &my_file_stat, MYF(0)) == -1)
2951 {
2952 error("Unable to stat the file.");
2953 DBUG_RETURN(ERROR_STOP);
2954 }
2955 if ((my_file_stat.st_mode & S_IFMT) == S_IFREG)
2956 my_b_seek(file, (my_off_t)0);
2957
2958 if (my_b_read(file, header, sizeof(header)))
2959 {
2960 error("Failed reading header; probably an empty file.");
2961 DBUG_RETURN(ERROR_STOP);
2962 }
2963 if (memcmp(header, BINLOG_MAGIC, sizeof(header)))
2964 {
2965 error("File is not a binary log file.");
2966 DBUG_RETURN(ERROR_STOP);
2967 }
2968
2969 /*
2970 Imagine we are running with --start-position=1000. We still need
2971 to know the binlog format's. So we still need to find, if there is
2972 one, the Format_desc event, or to know if this is a 3.23
2973 binlog. So we need to first read the first events of the log,
2974 those around offset 4. Even if we are reading a 3.23 binlog from
2975 the start (no --start-position): we need to know the header length
2976 (which is 13 in 3.23, 19 in 4.x) to be able to successfully print
2977 the first event (Start_log_event_v3). So even in this case, we
2978 need to "probe" the first bytes of the log *before* we do a real
2979 read_log_event(). Because read_log_event() needs to know the
2980 header's length to work fine.
2981 */
2982 for(;;)
2983 {
2984 tmp_pos= my_b_tell(file); /* should be 4 the first time */
2985 if (my_b_read(file, buf, sizeof(buf)))
2986 {
2987 if (file->error)
2988 {
2989 error("Could not read entry at offset %llu: "
2990 "Error in log format or read error.", (ulonglong)tmp_pos);
2991 DBUG_RETURN(ERROR_STOP);
2992 }
2993 /*
2994 Otherwise this is just EOF : this log currently contains 0-2
2995 events. Maybe it's going to be filled in the next
2996 milliseconds; then we are going to have a problem if this a
2997 3.23 log (imagine we are locally reading a 3.23 binlog which
2998 is being written presently): we won't know it in
2999 read_log_event() and will fail(). Similar problems could
3000 happen with hot relay logs if --start-position is used (but a
3001 --start-position which is posterior to the current size of the log).
3002 These are rare problems anyway (reading a hot log + when we
3003 read the first events there are not all there yet + when we
3004 read a bit later there are more events + using a strange
3005 --start-position).
3006 */
3007 break;
3008 }
3009 else
3010 {
3011 DBUG_PRINT("info",("buf[EVENT_TYPE_OFFSET=%d]=%d",
3012 EVENT_TYPE_OFFSET, buf[EVENT_TYPE_OFFSET]));
3013 /* always test for a Start_v3, even if no --start-position */
3014 if (buf[EVENT_TYPE_OFFSET] == binary_log::START_EVENT_V3)
3015 {
3016 /* This is 3.23 or 4.x */
3017 if (uint4korr(buf + EVENT_LEN_OFFSET) <
3018 (LOG_EVENT_MINIMAL_HEADER_LEN + Binary_log_event::START_V3_HEADER_LEN))
3019 {
3020 /* This is 3.23 (format 1) */
3021 delete glob_description_event;
3022 if (!(glob_description_event= new Format_description_log_event(1)))
3023 {
3024 error("Failed creating Format_description_log_event; "
3025 "out of memory?");
3026 DBUG_RETURN(ERROR_STOP);
3027 }
3028 }
3029 break;
3030 }
3031 else if (tmp_pos >= start_position)
3032 break;
3033 else if (buf[EVENT_TYPE_OFFSET] == binary_log::FORMAT_DESCRIPTION_EVENT)
3034 {
3035 /* This is 5.0 */
3036 Format_description_log_event *new_description_event;
3037 my_b_seek(file, tmp_pos); /* seek back to event's start */
3038 if (!(new_description_event= (Format_description_log_event*)
3039 Log_event::read_log_event(file, glob_description_event,
3040 opt_verify_binlog_checksum,
3041 rewrite_db_filter)))
3042 /* EOF can't be hit here normally, so it's a real error */
3043 {
3044 error("Could not read a Format_description_log_event event at "
3045 "offset %llu; this could be a log format error or read error.",
3046 (ulonglong)tmp_pos);
3047 DBUG_RETURN(ERROR_STOP);
3048 }
3049 if (opt_base64_output_mode == BASE64_OUTPUT_AUTO)
3050 {
3051 /*
3052 process_event will delete *description_event and set it to
3053 the new one, so we should not do it ourselves in this
3054 case.
3055 */
3056 Exit_status retval= process_event(print_event_info,
3057 new_description_event, tmp_pos,
3058 logname);
3059 if (retval != OK_CONTINUE)
3060 DBUG_RETURN(retval);
3061 }
3062 else
3063 {
3064 delete glob_description_event;
3065 glob_description_event= new_description_event;
3066 }
3067 DBUG_PRINT("info",("Setting description_event"));
3068 }
3069 else if (buf[EVENT_TYPE_OFFSET] == binary_log::PREVIOUS_GTIDS_LOG_EVENT)
3070 {
3071 // seek to end of event
3072 my_off_t end_pos= uint4korr(buf + EVENT_LEN_OFFSET);
3073 my_b_seek(file, tmp_pos + end_pos);
3074 }
3075 else if (buf[EVENT_TYPE_OFFSET] == binary_log::ROTATE_EVENT)
3076 {
3077 Log_event *ev;
3078 my_b_seek(file, tmp_pos); /* seek back to event's start */
3079 if (!(ev= Log_event::read_log_event(file, glob_description_event,
3080 opt_verify_binlog_checksum,
3081 rewrite_db_filter)))
3082 {
3083 /* EOF can't be hit here normally, so it's a real error */
3084 error("Could not read a Rotate_log_event event at offset %llu;"
3085 " this could be a log format error or read error.",
3086 (ulonglong)tmp_pos);
3087 DBUG_RETURN(ERROR_STOP);
3088 }
3089 delete ev;
3090 }
3091 else
3092 break;
3093 }
3094 }
3095 my_b_seek(file, pos);
3096 DBUG_RETURN(OK_CONTINUE);
3097 }
3098
3099
3100 /**
3101 Reads a local binlog and prints the events it sees.
3102
3103 @param[in] logname Name of input binlog.
3104
3105 @param[in,out] print_event_info Parameters and context state
3106 determining how to print.
3107
3108 @retval ERROR_STOP An error occurred - the program should terminate.
3109 @retval OK_CONTINUE No error, the program should continue.
3110 @retval OK_STOP No error, but the end of the specified range of
3111 events to process has been reached and the program should terminate.
3112 */
dump_local_log_entries(PRINT_EVENT_INFO * print_event_info,const char * logname)3113 static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
3114 const char* logname)
3115 {
3116 File fd = -1;
3117 IO_CACHE cache,*file= &cache;
3118 uchar tmp_buff[BIN_LOG_HEADER_SIZE];
3119 Exit_status retval= OK_CONTINUE;
3120
3121 if (logname && strcmp(logname, "-") != 0)
3122 {
3123 /* read from normal file */
3124 if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
3125 return ERROR_STOP;
3126 if (init_io_cache(file, fd, 0, READ_CACHE, start_position_mot, 0,
3127 MYF(MY_WME | MY_NABP)))
3128 {
3129 my_close(fd, MYF(MY_WME));
3130 return ERROR_STOP;
3131 }
3132 if ((retval= check_header(file, print_event_info, logname)) != OK_CONTINUE)
3133 goto end;
3134 }
3135 else
3136 {
3137 /* read from stdin */
3138 /*
3139 Windows opens stdin in text mode by default. Certain characters
3140 such as CTRL-Z are interpeted as events and the read() method
3141 will stop. CTRL-Z is the EOF marker in Windows. to get past this
3142 you have to open stdin in binary mode. Setmode() is used to set
3143 stdin in binary mode. Errors on setting this mode result in
3144 halting the function and printing an error message to stderr.
3145 */
3146 #if defined(_WIN32)
3147 if (_setmode(fileno(stdin), O_BINARY) == -1)
3148 {
3149 error("Could not set binary mode on stdin.");
3150 return ERROR_STOP;
3151 }
3152 #endif
3153 if (init_io_cache(file, my_fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
3154 0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
3155 {
3156 error("Failed to init IO cache.");
3157 return ERROR_STOP;
3158 }
3159 if ((retval= check_header(file, print_event_info, logname)) != OK_CONTINUE)
3160 goto end;
3161 if (start_position)
3162 {
3163 /* skip 'start_position' characters from stdin */
3164 uchar buff[IO_SIZE];
3165 my_off_t length,tmp;
3166 for (length= start_position_mot ; length > 0 ; length-=tmp)
3167 {
3168 tmp= min(static_cast<size_t>(length), sizeof(buff));
3169 if (my_b_read(file, buff, (uint) tmp))
3170 {
3171 error("Failed reading from file.");
3172 goto err;
3173 }
3174 }
3175 }
3176 }
3177
3178 if (!glob_description_event || !glob_description_event->is_valid())
3179 {
3180 error("Invalid Format_description log event; could be out of memory.");
3181 goto err;
3182 }
3183
3184 if (!start_position && my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE))
3185 {
3186 error("Failed reading from file.");
3187 goto err;
3188 }
3189 for (;;)
3190 {
3191 char llbuff[21];
3192 my_off_t old_off = my_b_tell(file);
3193
3194 Log_event* ev = Log_event::read_log_event(file, glob_description_event,
3195 opt_verify_binlog_checksum,
3196 rewrite_db_filter);
3197 if (!ev)
3198 {
3199 /*
3200 if binlog wasn't closed properly ("in use" flag is set) don't complain
3201 about a corruption, but treat it as EOF and move to the next binlog.
3202 */
3203 if (glob_description_event->common_header->flags &
3204 LOG_EVENT_BINLOG_IN_USE_F)
3205 file->error= 0;
3206 else if (file->error)
3207 {
3208 error("Could not read entry at offset %s: "
3209 "Error in log format or read error.",
3210 llstr(old_off,llbuff));
3211 goto err;
3212 }
3213 // file->error == 0 means EOF, that's OK, we break in this case
3214 goto end;
3215 }
3216 if ((retval= process_event(print_event_info, ev, old_off, logname)) !=
3217 OK_CONTINUE)
3218 goto end;
3219 }
3220
3221 /* NOTREACHED */
3222
3223 err:
3224 retval= ERROR_STOP;
3225
3226 end:
3227 if (fd >= 0)
3228 my_close(fd, MYF(MY_WME));
3229 /*
3230 Since the end_io_cache() writes to the
3231 file errors may happen.
3232 */
3233 if (end_io_cache(file))
3234 retval= ERROR_STOP;
3235
3236 return retval;
3237 }
3238
3239 /* Post processing of arguments to check for conflicts and other setups */
args_post_process(void)3240 static int args_post_process(void)
3241 {
3242 DBUG_ENTER("args_post_process");
3243
3244 if (opt_remote_alias && opt_remote_proto != BINLOG_DUMP_NON_GTID)
3245 {
3246 error("The option read-from-remote-server cannot be used when "
3247 "read-from-remote-master is defined and is not equal to "
3248 "BINLOG-DUMP-NON-GTIDS");
3249 DBUG_RETURN(ERROR_STOP);
3250 }
3251
3252 if (raw_mode)
3253 {
3254 if (one_database)
3255 warning("The --database option is ignored with --raw mode");
3256
3257 if (opt_remote_proto == BINLOG_LOCAL)
3258 {
3259 error("The --raw flag requires one of --read-from-remote-master or --read-from-remote-server");
3260 DBUG_RETURN(ERROR_STOP);
3261 }
3262
3263 if (opt_include_gtids_str != NULL)
3264 {
3265 error("You cannot use --include-gtids and --raw together.");
3266 DBUG_RETURN(ERROR_STOP);
3267 }
3268
3269 if (opt_remote_proto == BINLOG_DUMP_NON_GTID &&
3270 opt_exclude_gtids_str != NULL)
3271 {
3272 error("You cannot use both of --exclude-gtids and --raw together "
3273 "with one of --read-from-remote-server or "
3274 "--read-from-remote-master=BINLOG-DUMP-NON-GTID.");
3275 DBUG_RETURN(ERROR_STOP);
3276 }
3277
3278 if (stop_position != (ulonglong)(~(my_off_t)0))
3279 warning("The --stop-position option is ignored in raw mode");
3280
3281 if (stop_datetime != MY_TIME_T_MAX)
3282 warning("The --stop-datetime option is ignored in raw mode");
3283 }
3284 else if (output_file)
3285 {
3286 if (!(result_file = my_fopen(output_file, O_WRONLY | O_BINARY, MYF(MY_WME))))
3287 {
3288 error("Could not create log file '%s'", output_file);
3289 DBUG_RETURN(ERROR_STOP);
3290 }
3291 }
3292
3293 global_sid_lock->rdlock();
3294
3295 if (opt_include_gtids_str != NULL)
3296 {
3297 if (gtid_set_included->add_gtid_text(opt_include_gtids_str) !=
3298 RETURN_STATUS_OK)
3299 {
3300 error("Could not configure --include-gtids '%s'", opt_include_gtids_str);
3301 global_sid_lock->unlock();
3302 DBUG_RETURN(ERROR_STOP);
3303 }
3304 }
3305
3306 if (opt_exclude_gtids_str != NULL)
3307 {
3308 if (gtid_set_excluded->add_gtid_text(opt_exclude_gtids_str) !=
3309 RETURN_STATUS_OK)
3310 {
3311 error("Could not configure --exclude-gtids '%s'", opt_exclude_gtids_str);
3312 global_sid_lock->unlock();
3313 DBUG_RETURN(ERROR_STOP);
3314 }
3315 }
3316
3317 global_sid_lock->unlock();
3318
3319 if (connection_server_id == 0 && stop_never)
3320 error("Cannot set --server-id=0 when --stop-never is specified.");
3321 if (connection_server_id != -1 && stop_never_slave_server_id != -1)
3322 error("Cannot set --connection-server-id= %lld and"
3323 "--stop-never-slave-server-id= %lld. ", connection_server_id,
3324 stop_never_slave_server_id);
3325
3326 DBUG_RETURN(OK_CONTINUE);
3327 }
3328
3329 /**
3330 GTID cleanup destroys objects and reset their pointer.
3331 Function is reentrant.
3332 */
gtid_client_cleanup()3333 inline void gtid_client_cleanup()
3334 {
3335 delete global_sid_lock;
3336 delete global_sid_map;
3337 delete gtid_set_excluded;
3338 delete gtid_set_included;
3339 global_sid_lock= NULL;
3340 global_sid_map= NULL;
3341 gtid_set_excluded= NULL;
3342 gtid_set_included= NULL;
3343 }
3344
3345 /**
3346 GTID initialization.
3347
3348 @return true if allocation does not succeed
3349 false if OK
3350 */
gtid_client_init()3351 inline bool gtid_client_init()
3352 {
3353 bool res=
3354 (!(global_sid_lock= new Checkable_rwlock) ||
3355 !(global_sid_map= new Sid_map(global_sid_lock)) ||
3356 !(gtid_set_excluded= new Gtid_set(global_sid_map)) ||
3357 !(gtid_set_included= new Gtid_set(global_sid_map)));
3358 if (res)
3359 {
3360 gtid_client_cleanup();
3361 }
3362 return res;
3363 }
3364
main(int argc,char ** argv)3365 int main(int argc, char** argv)
3366 {
3367 char **defaults_argv;
3368 Exit_status retval= OK_CONTINUE;
3369 MY_INIT(argv[0]);
3370 DBUG_ENTER("main");
3371 DBUG_PROCESS(argv[0]);
3372
3373 my_init_time(); // for time functions
3374 tzset(); // set tzname
3375 /*
3376 A pointer of type Log_event can point to
3377 INTVAR
3378 USER_VAR
3379 RANDOM
3380 events.
3381 */
3382 buff_ev= new Buff_ev(PSI_NOT_INSTRUMENTED);
3383
3384 my_getopt_use_args_separator= TRUE;
3385 if (load_defaults("my", load_default_groups, &argc, &argv))
3386 exit(1);
3387 my_getopt_use_args_separator= FALSE;
3388 defaults_argv= argv;
3389
3390 parse_args(&argc, &argv);
3391
3392 if (!argc)
3393 {
3394 usage();
3395 free_defaults(defaults_argv);
3396 my_end(my_end_arg);
3397 exit(1);
3398 }
3399
3400 if (gtid_client_init())
3401 {
3402 error("Could not initialize GTID structuress.");
3403 exit(1);
3404 }
3405
3406 umask(((~my_umask) & 0666));
3407 /* Check for argument conflicts and do any post-processing */
3408 if (args_post_process() == ERROR_STOP)
3409 exit(1);
3410
3411 if (opt_base64_output_mode == BASE64_OUTPUT_UNSPEC)
3412 opt_base64_output_mode= BASE64_OUTPUT_AUTO;
3413
3414 opt_server_id_mask = (opt_server_id_bits == 32)?
3415 ~ ulong(0) : (1 << opt_server_id_bits) -1;
3416
3417 my_set_max_open_files(open_files_limit);
3418
3419 MY_TMPDIR tmpdir;
3420 tmpdir.list= 0;
3421 if (!dirname_for_local_load)
3422 {
3423 if (init_tmpdir(&tmpdir, 0))
3424 exit(1);
3425 dirname_for_local_load= my_strdup(PSI_NOT_INSTRUMENTED,
3426 my_tmpdir(&tmpdir), MY_WME);
3427 }
3428
3429 if (dirname_for_local_load)
3430 load_processor.init_by_dir_name(dirname_for_local_load);
3431 else
3432 load_processor.init_by_cur_dir();
3433
3434 if (!raw_mode)
3435 {
3436 fprintf(result_file, "/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;\n");
3437
3438 if (disable_log_bin)
3439 fprintf(result_file,
3440 "/*!32316 SET @OLD_SQL_LOG_BIN=@@SQL_LOG_BIN, SQL_LOG_BIN=0*/;\n");
3441
3442 /*
3443 In mysqlbinlog|mysql, don't want mysql to be disconnected after each
3444 transaction (which would be the case with GLOBAL.COMPLETION_TYPE==2).
3445 */
3446 fprintf(result_file,
3447 "/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,"
3448 "COMPLETION_TYPE=0*/;\n");
3449
3450 if (charset)
3451 fprintf(result_file,
3452 "\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
3453 "\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
3454 "\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
3455 "\n/*!40101 SET NAMES %s */;\n", charset);
3456 }
3457 /*
3458 In case '--idempotent' or '-i' options has been used, we will notify the
3459 server to use idempotent mode for the following events.
3460 */
3461 if (idempotent_mode)
3462 fprintf(result_file,
3463 "/*!50700 SET @@SESSION.RBR_EXEC_MODE=IDEMPOTENT*/;\n\n");
3464
3465 retval= dump_multiple_logs(argc, argv);
3466
3467 if (!raw_mode)
3468 {
3469 fprintf(result_file, "# End of log file\n");
3470
3471 fprintf(result_file,
3472 "/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;\n");
3473 if (disable_log_bin)
3474 fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n");
3475
3476 if (charset)
3477 fprintf(result_file,
3478 "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"
3479 "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"
3480 "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n");
3481
3482 fprintf(result_file, "/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;\n");
3483 }
3484
3485 /*
3486 We should unset the RBR_EXEC_MODE since the user may concatenate output of
3487 multiple runs of mysqlbinlog, all of which may not run in idempotent mode.
3488 */
3489 if (idempotent_mode)
3490 fprintf(result_file,
3491 "/*!50700 SET @@SESSION.RBR_EXEC_MODE=STRICT*/;\n");
3492
3493 if (tmpdir.list)
3494 free_tmpdir(&tmpdir);
3495 if (result_file && (result_file != stdout))
3496 my_fclose(result_file, MYF(0));
3497 cleanup();
3498
3499 if (defaults_argv)
3500 free_defaults(defaults_argv);
3501 my_free_open_file_info();
3502 load_processor.destroy();
3503 /* We cannot free DBUG, it is used in global destructors after exit(). */
3504 my_end(my_end_arg | MY_DONT_FREE_DBUG);
3505 gtid_client_cleanup();
3506
3507 exit(retval == ERROR_STOP ? 1 : 0);
3508 /* Keep compilers happy. */
3509 DBUG_RETURN(retval == ERROR_STOP ? 1 : 0);
3510 }
3511
3512 /*
3513 We must include this here as it's compiled with different options for
3514 the server
3515 */
3516
3517 #include "decimal.c"
3518 #include "my_decimal.cc"
3519 #include "log_event.cc"
3520 #include "log_event_old.cc"
3521 #include "rpl_utility.cc"
3522 #include "rpl_gtid_sid_map.cc"
3523 #include "rpl_gtid_misc.cc"
3524 #include "rpl_gtid_set.cc"
3525 #include "rpl_gtid_specification.cc"
3526 #include "rpl_tblmap.cc"
3527