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