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