1 /* Copyright (c) 2014, 2021, Oracle and/or its affiliates.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #include "statement_events.h"
24 #include <algorithm>
25 #include <string>
26 
27 namespace binary_log
28 {
29 
30 /******************************************************************************
31                      Query_event methods
32 ******************************************************************************/
33 /**
34   The simplest constructor that could possibly work.  This is used for
35   creating static objects that have a special meaning and are invisible
36   to the log.
37 */
Query_event(Log_event_type type_arg)38 Query_event::Query_event(Log_event_type type_arg)
39 : Binary_log_event(type_arg),
40   query(0), db(0), user(0), user_len(0), host(0), host_len(0),
41   db_len(0), q_len(0)
42 {
43 }
44 
45 /**
46   The constructor used by MySQL master to create a query event, to be
47   written to the binary log.
48 */
Query_event(const char * query_arg,const char * catalog_arg,const char * db_arg,uint32_t query_length,unsigned long thread_id_arg,unsigned long long sql_mode_arg,unsigned long auto_increment_increment_arg,unsigned long auto_increment_offset_arg,unsigned int number,unsigned long long table_map_for_update_arg,int errcode,unsigned int db_arg_len,unsigned int catalog_arg_len)49 Query_event::Query_event(const char* query_arg, const char* catalog_arg,
50                          const char* db_arg, uint32_t query_length,
51                          unsigned long thread_id_arg,
52                          unsigned long long sql_mode_arg,
53                          unsigned long auto_increment_increment_arg,
54                          unsigned long auto_increment_offset_arg,
55                          unsigned int number,
56                          unsigned long long table_map_for_update_arg,
57                          int errcode,
58                          unsigned int db_arg_len, unsigned int catalog_arg_len)
59 : Binary_log_event(QUERY_EVENT),
60   query(query_arg), db(db_arg), catalog(catalog_arg),
61   user(0), user_len(0), host(0), host_len(0),
62   thread_id(thread_id_arg), db_len(0), error_code(errcode),
63   status_vars_len(0), q_len(query_length),
64   flags2_inited(1), sql_mode_inited(1), charset_inited(1),
65   sql_mode(sql_mode_arg),
66   auto_increment_increment(static_cast<uint16_t>(auto_increment_increment_arg)),
67   auto_increment_offset(static_cast<uint16_t>(auto_increment_offset_arg)),
68   time_zone_len(0), lc_time_names_number(number),
69   charset_database_number(0),
70   table_map_for_update(table_map_for_update_arg),
71   master_data_written(0), explicit_defaults_ts(TERNARY_UNSET),
72   mts_accessed_dbs(0)
73 {
74 }
75 
76 /**
77   Utility function for the Query_event constructor.
78   The function copies n bytes from the source string and moves the
79   destination pointer by the number of bytes copied.
80 
81   @param dst Pointer to the buffer into which the string is to be copied
82   @param src Source string
83   @param len The number of bytes to be copied
84 */
copy_str_and_move(Log_event_header::Byte ** dst,const char ** src,size_t len)85 static void copy_str_and_move(Log_event_header::Byte **dst,
86                               const char** src,
87                               size_t len)
88 {
89   memcpy(*dst, *src, len);
90   *src= reinterpret_cast<const char*>(*dst);
91   (*dst)+= len;
92   *(*dst)++= 0;
93 }
94 
95 
96 /**
97    Macro to check that there is enough space to read from memory.
98 
99    @param PTR Pointer to memory
100    @param END End of memory
101    @param CNT Number of bytes that should be read.
102 */
103 #define CHECK_SPACE(PTR,END,CNT)                      \
104   do {                                                \
105     BAPI_ASSERT((PTR) + (CNT) <= (END));              \
106     if ((PTR) + (CNT) > (END)) {                      \
107       query= 0;                                       \
108       return;                               \
109     }                                                 \
110   } while (0)
111 
112 
113 /**
114   The event occurs when an updating statement is done.
115 */
Query_event(const char * buf,unsigned int event_len,const Format_description_event * description_event,Log_event_type event_type)116 Query_event::Query_event(const char* buf, unsigned int event_len,
117                          const Format_description_event *description_event,
118                          Log_event_type event_type)
119 : Binary_log_event(&buf, description_event->binlog_version,
120                    description_event->server_version),
121   query(0), db(0), catalog(0), time_zone_str(0),
122   user(0), user_len(0), host(0), host_len(0),
123   db_len(0), status_vars_len(0), q_len(0),
124   flags2_inited(0), sql_mode_inited(0), charset_inited(0),
125   auto_increment_increment(1), auto_increment_offset(1),
126   time_zone_len(0), catalog_len(0), lc_time_names_number(0),
127   charset_database_number(0), table_map_for_update(0), master_data_written(0),
128   explicit_defaults_ts(TERNARY_UNSET),
129   mts_accessed_dbs(OVER_MAX_DBS_IN_EVENT_MTS)
130 {
131   //buf is advanced in Binary_log_event constructor to point to
132   //beginning of post-header
133   uint32_t tmp;
134   uint8_t common_header_len, post_header_len;
135   Log_event_header::Byte *start;
136   const Log_event_header::Byte *end;
137 
138   query_data_written= 0;
139 
140   common_header_len= description_event->common_header_len;
141   post_header_len= description_event->post_header_len[event_type - 1];
142 
143   /*
144     We test if the event's length is sensible, and if so we compute data_len.
145     We cannot rely on QUERY_HEADER_LEN here as it would not be format-tolerant.
146     We use QUERY_HEADER_MINIMAL_LEN which is the same for 3.23, 4.0 & 5.0.
147   */
148   if (event_len < (unsigned int)(common_header_len + post_header_len))
149     return;
150   data_len= event_len - (common_header_len + post_header_len);
151 
152   memcpy(&thread_id, buf + Q_THREAD_ID_OFFSET, sizeof(thread_id));
153   thread_id= le32toh(thread_id);
154   memcpy(&query_exec_time, buf + Q_EXEC_TIME_OFFSET, sizeof(query_exec_time));
155   query_exec_time= le32toh(query_exec_time);
156 
157   db_len= (unsigned char)buf[Q_DB_LEN_OFFSET];
158    // TODO: add a check of all *_len vars
159   memcpy(&error_code, buf + Q_ERR_CODE_OFFSET, sizeof(error_code));
160   error_code= le16toh(error_code);
161 
162   /*
163     5.0 format starts here.
164     Depending on the format, we may or not have affected/warnings etc
165     The remnent post-header to be parsed has length:
166   */
167   tmp= post_header_len - QUERY_HEADER_MINIMAL_LEN;
168   if (tmp)
169   {
170     memcpy(&status_vars_len, buf + Q_STATUS_VARS_LEN_OFFSET,
171            sizeof(status_vars_len));
172     status_vars_len= le16toh(status_vars_len);
173     /*
174       Check if status variable length is corrupt and will lead to very
175       wrong data. We could be even more strict and require data_len to
176       be even bigger, but this will suffice to catch most corruption
177       errors that can lead to a crash.
178     */
179     if (status_vars_len >
180         std::min<unsigned long>(data_len, MAX_SIZE_LOG_EVENT_STATUS))
181     {
182       query= 0;
183       return;
184     }
185     data_len-= status_vars_len;
186     tmp-= 2;
187   }
188   else
189   {
190     /*
191       server version < 5.0 / binlog_version < 4 master's event is
192       relay-logged with storing the original size of the event in
193       Q_MASTER_DATA_WRITTEN_CODE status variable.
194       The size is to be restored at reading Q_MASTER_DATA_WRITTEN_CODE-marked
195       event from the relay log.
196     */
197     BAPI_ASSERT(description_event->binlog_version < 4);
198     master_data_written= header()->data_written;
199   }
200   /*
201     We have parsed everything we know in the post header for QUERY_EVENT,
202     the rest of post header is either comes from older version MySQL or
203     dedicated to derived events (e.g. Execute_load_query...)
204   */
205 
206   /* variable-part: the status vars; only in MySQL 5.0  */
207   start= (Log_event_header::Byte*) (buf + post_header_len);
208   end= (const Log_event_header::Byte*) (start + status_vars_len);
209   for (const Log_event_header::Byte* pos= start; pos < end;)
210   {
211     switch (*pos++) {
212     case Q_FLAGS2_CODE:
213       CHECK_SPACE(pos, end, 4);
214       flags2_inited= 1;
215       memcpy(&flags2, pos, sizeof(flags2));
216       flags2= le32toh(flags2);
217       pos+= 4;
218       break;
219     case Q_SQL_MODE_CODE:
220     {
221       CHECK_SPACE(pos, end, 8);
222       sql_mode_inited= 1;
223       memcpy(&sql_mode, pos, sizeof(sql_mode));
224       sql_mode= le64toh(sql_mode);
225       pos+= 8;
226       break;
227     }
228     case Q_CATALOG_NZ_CODE:
229       if ((catalog_len= *pos))
230         catalog= (const char*) (pos + 1);
231       CHECK_SPACE(pos, end, catalog_len + 1);
232       pos+= catalog_len + 1;
233       break;
234     case Q_AUTO_INCREMENT:
235       CHECK_SPACE(pos, end, 4);
236       memcpy(&auto_increment_increment, pos, sizeof(auto_increment_increment));
237       auto_increment_increment= le16toh(auto_increment_increment);
238       memcpy(&auto_increment_offset, pos + 2, sizeof(auto_increment_offset));
239       auto_increment_offset= le16toh(auto_increment_offset);
240       pos+= 4;
241       break;
242     case Q_CHARSET_CODE:
243     {
244       CHECK_SPACE(pos, end, 6);
245       charset_inited= 1;
246       memcpy(charset, pos, 6);
247       pos+= 6;
248       break;
249     }
250     case Q_TIME_ZONE_CODE:
251     {
252       if ((time_zone_len= *pos))
253         time_zone_str= (const char*)(pos + 1);
254       pos+= time_zone_len + 1;
255       break;
256     }
257     case Q_CATALOG_CODE: /* for 5.0.x where 0<=x<=3 masters */
258       CHECK_SPACE(pos, end, 1);
259       if ((catalog_len= *pos))
260         catalog= (const char*) (pos+1);
261       CHECK_SPACE(pos, end, catalog_len + 2);
262       pos+= catalog_len + 2; // leap over end 0
263       break;
264     case Q_LC_TIME_NAMES_CODE:
265       CHECK_SPACE(pos, end, 2);
266       memcpy(&lc_time_names_number, pos, sizeof(lc_time_names_number));
267       lc_time_names_number= le16toh(lc_time_names_number);
268       pos+= 2;
269       break;
270     case Q_CHARSET_DATABASE_CODE:
271       CHECK_SPACE(pos, end, 2);
272       memcpy(&charset_database_number, pos, sizeof(lc_time_names_number));
273       charset_database_number= le16toh(charset_database_number);
274       pos+= 2;
275       break;
276     case Q_TABLE_MAP_FOR_UPDATE_CODE:
277       CHECK_SPACE(pos, end, 8);
278       memcpy(&table_map_for_update, pos, sizeof(table_map_for_update));
279       table_map_for_update= le64toh(table_map_for_update);
280       pos+= 8;
281       break;
282     case Q_MASTER_DATA_WRITTEN_CODE:
283       CHECK_SPACE(pos, end, 4);
284       memcpy(&master_data_written, pos, sizeof(master_data_written));
285       master_data_written= le32toh(static_cast<uint32_t>(master_data_written));
286       header()->data_written= master_data_written;
287       pos+= 4;
288       break;
289     case Q_MICROSECONDS:
290     {
291       CHECK_SPACE(pos, end, 3);
292       uint32_t temp_usec= 0;
293       memcpy(&temp_usec, pos, 3);
294       header()->when.tv_usec= le32toh(temp_usec);
295       pos+= 3;
296 break;
297     }
298     case Q_INVOKER:
299     {
300       CHECK_SPACE(pos, end, 1);
301       user_len= *pos++;
302       CHECK_SPACE(pos, end, user_len);
303       user= (const char*)pos;
304       if (user_len == 0)
305         user= (const char *)"";
306       pos+= user_len;
307 
308       CHECK_SPACE(pos, end, 1);
309       host_len= *pos++;
310       CHECK_SPACE(pos, end, host_len);
311       host= (const char*)pos;
312       if (host_len == 0)
313         host= (const char *)"";
314       pos+= host_len;
315       break;
316     }
317     case Q_UPDATED_DB_NAMES:
318     {
319       unsigned char i= 0;
320 #ifndef NDEBUG
321       bool is_corruption_injected= false;
322 #endif
323 
324       CHECK_SPACE(pos, end, 1);
325       mts_accessed_dbs= *pos++;
326       /*
327          Notice, the following check is positive also in case of
328          the master's MAX_DBS_IN_EVENT_MTS > the slave's one and the event
329          contains e.g the master's MAX_DBS_IN_EVENT_MTS db:s.
330       */
331       if (mts_accessed_dbs > MAX_DBS_IN_EVENT_MTS)
332       {
333         mts_accessed_dbs= OVER_MAX_DBS_IN_EVENT_MTS;
334         break;
335       }
336 
337       BAPI_ASSERT(mts_accessed_dbs != 0);
338 
339       for (i= 0; i < mts_accessed_dbs && pos < start + status_vars_len; i++)
340       {
341         #ifndef NDEBUG
342         /*
343           This is specific to mysql test run on the server
344           for the keyword "query_log_event_mts_corrupt_db_names"
345         */
346         if (binary_log_debug::debug_query_mts_corrupt_db_names)
347         {
348           if (mts_accessed_dbs == 2)
349           {
350             BAPI_ASSERT(pos[sizeof("d?") - 1] == 0);
351             ((char*) pos)[sizeof("d?") - 1]= 'a';
352             is_corruption_injected= true;
353           }
354         }
355         #endif
356         strncpy(mts_accessed_db_names[i], (char*) pos,
357                 std::min<unsigned long>(NAME_LEN, start + status_vars_len - pos));
358         mts_accessed_db_names[i][NAME_LEN - 1]= 0;
359         pos+= 1 + strlen((const char*) pos);
360       }
361       if (i != mts_accessed_dbs
362 #ifndef NDEBUG
363           || is_corruption_injected
364 #endif
365           )
366         return;
367       break;
368     }
369     case Q_EXPLICIT_DEFAULTS_FOR_TIMESTAMP:
370     {
371       CHECK_SPACE(pos, end, 1);
372       explicit_defaults_ts= *pos++ == 0 ? TERNARY_OFF : TERNARY_ON;
373       break;
374     }
375     default:
376       /* That's why you must write status vars in growing order of code */
377       pos= (const unsigned char*) end;         // Break loop
378     }
379   }
380   if (catalog_len)                             // If catalog is given
381     query_data_written+= catalog_len + 1;
382   if (time_zone_len)
383     query_data_written+= time_zone_len + 1;
384   if (user_len > 0)
385     query_data_written+= user_len + 1;
386   if (host_len > 0)
387     query_data_written+= host_len + 1;
388 
389   /*
390     if time_zone_len or catalog_len are 0, then time_zone and catalog
391     are uninitialized at this point.  shouldn't they point to the
392     zero-length null-terminated strings we allocated space for in the
393     my_alloc call above? /sven
394   */
395 
396   /* A 2nd variable part; this is common to all versions */
397   query_data_written+= data_len + 1;
398   db= (const char* )end;
399   q_len= data_len - db_len -1;
400   query= (const char *)(end + db_len + 1);
401 
402   unsigned int max_length;
403   max_length= (event_len - (((end + db_len + 1) - start) +
404                             (post_header_len + common_header_len)));
405   if (q_len != max_length)
406   {
407     q_len= 0;
408     query= NULL;
409   }
410 
411   return;
412 }
413 
414 /**
415   Layout for the data buffer is as follows
416   <pre>
417   +--------+-----------+------+------+---------+----+-------+----+
418   | catlog | time_zone | user | host | db name | \0 | Query | \0 |
419   +--------+-----------+------+------+---------+----+-------+----+
420   </pre>
421 */
fill_data_buf(Log_event_header::Byte * buf,unsigned long buf_len)422 int Query_event::fill_data_buf(Log_event_header::Byte* buf,
423                                unsigned long buf_len)
424 {
425   if (!buf)
426     return 0;
427   /* We need to check the buffer size */
428   if (buf_len < catalog_len + 1 + time_zone_len +
429                 1 + user_len+ 1 + host_len+ 1 + data_len )
430     return 0;
431 
432   if (data_len && (data_len < db_len ||
433                    data_len < q_len ||
434                    data_len != (db_len + q_len + 1)))
435     return 0;
436 
437   unsigned char* start= buf;
438   /*
439     Note: catalog_len is one less than "catalog.length()"
440     if Q_CATALOG flag is set
441    */
442   if (catalog_len)                                  // If catalog is given
443     /*
444       This covers both the cases, where the catalog_nz flag is set of unset.
445       The end 0 will be a part of the string catalog in the second case,
446       hence using catalog.length() instead of catalog_len makes the flags
447       catalog_nz redundant.
448      */
449     copy_str_and_move(&start, &catalog, catalog_len);
450   if (time_zone_len > 0)
451     copy_str_and_move(&start, &time_zone_str, time_zone_len);
452   if (user_len > 0)
453     copy_str_and_move(&start, &user, user_len);
454   if (host_len > 0)
455     copy_str_and_move(&start, &host, host_len);
456   if (data_len)
457   {
458     if (db_len >0 && db)
459       copy_str_and_move(&start, &db, db_len);
460     if (q_len > 0 && query)
461       copy_str_and_move(&start, &query, q_len);
462   }
463   return 1;
464 }
465 
466 /**
467   The constructor for User_var_event.
468 */
469 User_var_event::
User_var_event(const char * buf,unsigned int event_len,const Format_description_event * description_event)470 User_var_event(const char* buf, unsigned int event_len,
471                const Format_description_event* description_event)
472   :Binary_log_event(&buf, description_event->binlog_version,
473                     description_event->server_version)
474 {
475   //buf is advanced in Binary_log_event constructor to point to
476   //beginning of post-header
477   bool error= false;
478   const char* buf_start= buf - description_event->common_header_len;
479   /* The Post-Header is empty. The Variable Data part begins immediately. */
480   const char *start= buf_start;
481   buf+= description_event->post_header_len[USER_VAR_EVENT-1];
482 
483   memcpy(&name_len, buf, 4);
484   name_len= le32toh(name_len);
485   /* Avoid reading out of buffer */
486   if ((buf - buf_start) + UV_NAME_LEN_SIZE + name_len > event_len)
487   {
488     error= true;
489     goto err;
490   }
491 
492   name= (char *) buf + UV_NAME_LEN_SIZE;
493   /*
494     We don't know yet is_null value, so we must assume that name_len
495     may have the bigger value possible, is_null= True and there is no
496     payload for val, or even that name_len is 0.
497   */
498   if (!valid_buffer_range<unsigned int>(name_len, buf_start, name,
499                                         event_len - UV_VAL_IS_NULL))
500   {
501     error= true;
502     goto err;
503   }
504 
505   buf+= UV_NAME_LEN_SIZE + name_len;
506   is_null= (bool) *buf;
507   flags= User_var_event::UNDEF_F;    // defaults to UNDEF_F
508   if (is_null)
509   {
510     type= STRING_TYPE;
511     /*
512     *my_charset_bin.number= 63, and my_charset_bin is defined in server
513     *so replacing it with its value.
514     */
515     charset_number= 63;
516     val_len= 0;
517     val= 0;
518   }
519 
520   else
521   {
522     if (!valid_buffer_range<unsigned int>(UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE
523                                           + UV_CHARSET_NUMBER_SIZE +
524                                           UV_VAL_LEN_SIZE, buf_start, buf,
525                                           event_len))
526     {
527       error= true;
528       goto err;
529     }
530 
531     type= (Value_type) buf[UV_VAL_IS_NULL];
532      memcpy(&charset_number, buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE,
533             sizeof(charset_number));
534     charset_number= le32toh(charset_number);
535     memcpy(&val_len, (buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
536            UV_CHARSET_NUMBER_SIZE), sizeof(val_len));
537     val_len= le32toh(val_len);
538     val= (char *) (buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
539                    UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE);
540 
541     if (!valid_buffer_range<unsigned int>(val_len, buf_start, val, event_len))
542     {
543       error= true;
544       goto err;
545     }
546 
547     /**
548       We need to check if this is from an old server
549       that did not pack information for flags.
550       We do this by checking if there are extra bytes
551       after the packed value. If there are we take the
552       extra byte and it's value is assumed to contain
553       the flags value.
554 
555       Old events will not have this extra byte, thence,
556       we keep the flags set to UNDEF_F.
557     */
558   size_t bytes_read= ((val + val_len) - start);
559   if (bytes_read > event_len)
560   {
561     error= true;
562     goto err;
563   }
564 #ifndef NDEBUG
565   bool old_pre_checksum_fd= description_event->is_version_before_checksum();
566   bool checksum_verify= (old_pre_checksum_fd ||
567                          (description_event->footer()->checksum_alg ==
568                           BINLOG_CHECKSUM_ALG_OFF));
569   size_t data_written= (header()->data_written- checksum_verify);
570   BAPI_ASSERT(((bytes_read == data_written) ? false : true) ||
571               ((bytes_read == data_written - 1) ? false : true));
572 #endif
573     if ((header()->data_written - bytes_read) > 0)
574     {
575       flags= (unsigned int) *(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
576                               UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE +
577                               val_len);
578     }
579   }
580 err:
581   if (error)
582     name= 0;
583 }
584 
585 /**
586   Constructor receives a packet from the MySQL master or the binary
587   log and decodes it to create an Intvar_event.
588   Written every time a statement uses an AUTO_INCREMENT column or the
589   LAST_INSERT_ID() function; precedes other events for the statement.
590   This is written only before a QUERY_EVENT and is not used with row-based
591   logging. An INTVAR_EVENT is written with a "subtype" in the event data part:
592 
593   * INSERT_ID_EVENT indicates the value to use for an AUTO_INCREMENT column in
594     the next statement.
595 
596   * LAST_INSERT_ID_EVENT indicates the value to use for the LAST_INSERT_ID()
597     function in the next statement.
598 */
Intvar_event(const char * buf,const Format_description_event * description_event)599 Intvar_event::Intvar_event(const char* buf,
600                            const Format_description_event* description_event)
601 : Binary_log_event(&buf, description_event->binlog_version,
602                    description_event->server_version)
603 {
604   //buf is advanced in Binary_log_event constructor to point to
605   //beginning of post-header
606   /* The Post-Header is empty. The Varible Data part begins immediately. */
607   buf+= description_event->post_header_len[INTVAR_EVENT - 1];
608   type= buf[I_TYPE_OFFSET];
609   memcpy(&val, buf + I_VAL_OFFSET, 8);
610   val= le64toh(val);
611 }
612 
Rand_event(const char * buf,const Format_description_event * description_event)613 Rand_event::Rand_event(const char* buf,
614                        const Format_description_event* description_event)
615   :Binary_log_event(&buf, description_event->binlog_version,
616                     description_event->server_version)
617 {
618   //buf is advanced in Binary_log_event constructor to point to
619   //beginning of post-header
620   /*
621    We step to the post-header despite it being empty because it could later be
622    filled with something and we have to support that case.
623    The Variable Data part begins immediately.
624   */
625   buf+= description_event->post_header_len[RAND_EVENT - 1];
626   memcpy(&seed1, buf + RAND_SEED1_OFFSET, 8);
627   seed1= le64toh(seed1);
628   memcpy(&seed2, buf + RAND_SEED2_OFFSET, 8);
629   seed2= le64toh(seed2);
630 }
631 
632 #ifndef HAVE_MYSYS
print_event_info(std::ostream & info)633 void Query_event::print_event_info(std::ostream& info)
634 {
635   if (memcmp(query, "BEGIN", 5) != 0 &&
636       memcmp(query, "COMMIT", 6) != 0)
637   {
638     info << "use `" << db << "`; ";
639   }
640   info << query;
641 }
642 
print_long_info(std::ostream & info)643 void Query_event::print_long_info(std::ostream& info)
644 {
645   info << "Timestamp: " << header()->when.tv_sec;
646   info << "\tThread id: " << (int)thread_id;
647   info << "\tExec time: " << (int)query_exec_time;
648   info << "\nDatabase: " << db;
649   info << "\tQuery: ";
650   this->print_event_info(info);
651 }
652 
print_event_info(std::ostream & info)653 void User_var_event::print_event_info(std::ostream& info)
654 {
655   info << "@`" << name << "`=";
656   if(type == STRING_TYPE)
657     info  << val;
658   else
659     info << "<Binary encoded value>";
660   //TODO: value is binary encoded, requires decoding
661 }
662 
print_long_info(std::ostream & info)663 void User_var_event::print_long_info(std::ostream& info)
664 {
665   info << "Timestamp: " << header()->when.tv_sec;
666   info << "\tType: "
667        << get_value_type_string(static_cast<Value_type>(type));
668   info << "\n";
669   this->print_event_info(info);
670 }
671 
print_event_info(std::ostream & info)672 void Intvar_event::print_event_info(std::ostream& info)
673 {
674   info << get_var_type_string();
675   info << "\tValue: " << val;
676 }
677 
print_long_info(std::ostream & info)678 void Intvar_event::print_long_info(std::ostream& info)
679 {
680   info << "Timestamp: " << header()->when.tv_sec;
681   info << "\t";
682   this->print_event_info(info);
683 }
684 
print_event_info(std::ostream & info)685 void Rand_event::print_event_info(std::ostream& info)
686 {
687   info << " SEED1 is " << seed1;
688   info << " SEED2 is " << seed2;
689 }
print_long_info(std::ostream & info)690 void Rand_event::print_long_info(std::ostream& info)
691 {
692   info << "Timestamp: " << header()->when.tv_sec;
693   info << "\t";
694   this->print_event_info(info);
695 }
696 
697 #endif
698 }//end namespace
699 
700