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