1 | /* Copyright (c) 2007, 2013, 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 as published by |
5 | the Free Software Foundation; version 2 of the License. |
6 | |
7 | This program is distributed in the hope that it will be useful, |
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | GNU General Public License for more details. |
11 | |
12 | You should have received a copy of the GNU General Public License |
13 | along with this program; if not, write to the Free Software |
14 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ |
15 | |
16 | #ifndef LOG_EVENT_OLD_H |
17 | #define LOG_EVENT_OLD_H |
18 | |
19 | /* |
20 | Need to include this file at the proper position of log_event.h |
21 | */ |
22 | |
23 | |
24 | /** |
25 | @file |
26 | |
27 | @brief This file contains classes handling old formats of row-based |
28 | binlog events. |
29 | */ |
30 | /* |
31 | Around 2007-10-31, I made these classes completely separated from |
32 | the new classes (before, there was a complex class hierarchy |
33 | involving multiple inheritance; see BUG#31581), by simply copying |
34 | and pasting the entire contents of Rows_log_event into |
35 | Old_rows_log_event and the entire contents of |
36 | {Write|Update|Delete}_rows_log_event into |
37 | {Write|Update|Delete}_rows_log_event_old. For clarity, I will keep |
38 | the comments marking which code was cut-and-pasted for some time. |
39 | With the classes collapsed into one, there is probably some |
40 | redundancy (maybe some methods can be simplified and/or removed), |
41 | but we keep them this way for now. /Sven |
42 | */ |
43 | |
44 | /* These classes are based on the v1 RowsHeaderLen */ |
45 | #undef ROWS_HEADER_LEN |
46 | #define ROWS_HEADER_LEN_V1 |
47 | |
48 | /** |
49 | @class Old_rows_log_event |
50 | |
51 | Base class for the three types of row-based events |
52 | {Write|Update|Delete}_row_log_event_old, with event type codes |
53 | PRE_GA_{WRITE|UPDATE|DELETE}_ROWS_EVENT. These events are never |
54 | created any more, except when reading a relay log created by an old |
55 | server. |
56 | */ |
57 | class Old_rows_log_event : public Log_event |
58 | { |
59 | /********** BEGIN CUT & PASTE FROM Rows_log_event **********/ |
60 | public: |
61 | /** |
62 | Enumeration of the errors that can be returned. |
63 | */ |
64 | enum enum_error |
65 | { |
66 | ERR_OPEN_FAILURE = -1, /**< Failure to open table */ |
67 | ERR_OK = 0, /**< No error */ |
68 | ERR_TABLE_LIMIT_EXCEEDED = 1, /**< No more room for tables */ |
69 | ERR_OUT_OF_MEM = 2, /**< Out of memory */ |
70 | ERR_BAD_TABLE_DEF = 3, /**< Table definition does not match */ |
71 | ERR_RBR_TO_SBR = 4 /**< daisy-chanining RBR to SBR not allowed */ |
72 | }; |
73 | |
74 | /* |
75 | These definitions allow you to combine the flags into an |
76 | appropriate flag set using the normal bitwise operators. The |
77 | implicit conversion from an enum-constant to an integer is |
78 | accepted by the compiler, which is then used to set the real set |
79 | of flags. |
80 | */ |
81 | enum enum_flag |
82 | { |
83 | /* Last event of a statement */ |
84 | STMT_END_F = (1U << 0), |
85 | |
86 | /* Value of the OPTION_NO_FOREIGN_KEY_CHECKS flag in thd->options */ |
87 | NO_FOREIGN_KEY_CHECKS_F = (1U << 1), |
88 | |
89 | /* Value of the OPTION_RELAXED_UNIQUE_CHECKS flag in thd->options */ |
90 | RELAXED_UNIQUE_CHECKS_F = (1U << 2), |
91 | |
92 | /** |
93 | Indicates that rows in this event are complete, that is contain |
94 | values for all columns of the table. |
95 | */ |
96 | COMPLETE_ROWS_F = (1U << 3) |
97 | }; |
98 | |
99 | typedef uint16 flag_set; |
100 | |
101 | /* Special constants representing sets of flags */ |
102 | enum |
103 | { |
104 | RLE_NO_FLAGS = 0U |
105 | }; |
106 | |
107 | virtual ~Old_rows_log_event(); |
108 | |
109 | void set_flags(flag_set flags_arg) { m_flags |= flags_arg; } |
110 | void clear_flags(flag_set flags_arg) { m_flags &= ~flags_arg; } |
111 | flag_set get_flags(flag_set flags_arg) const { return m_flags & flags_arg; } |
112 | |
113 | #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) |
114 | virtual void pack_info(Protocol *protocol); |
115 | #endif |
116 | |
117 | #ifdef MYSQL_CLIENT |
118 | /* not for direct call, each derived has its own ::print() */ |
119 | virtual bool print(FILE *file, PRINT_EVENT_INFO *print_event_info)= 0; |
120 | #endif |
121 | |
122 | #ifndef MYSQL_CLIENT |
123 | int add_row_data(uchar *data, size_t length) |
124 | { |
125 | return do_add_row_data(data,length); |
126 | } |
127 | #endif |
128 | |
129 | /* Member functions to implement superclass interface */ |
130 | virtual int get_data_size(); |
131 | |
132 | MY_BITMAP const *get_cols() const { return &m_cols; } |
133 | size_t get_width() const { return m_width; } |
134 | ulong get_table_id() const { return m_table_id; } |
135 | |
136 | #ifndef MYSQL_CLIENT |
137 | virtual bool (); |
138 | virtual bool write_data_body(); |
139 | virtual const char *get_db() { return m_table->s->db.str; } |
140 | #endif |
141 | /* |
142 | Check that malloc() succeeded in allocating memory for the rows |
143 | buffer and the COLS vector. Checking that an Update_rows_log_event_old |
144 | is valid is done in the Update_rows_log_event_old::is_valid() |
145 | function. |
146 | */ |
147 | virtual bool is_valid() const |
148 | { |
149 | return m_rows_buf && m_cols.bitmap; |
150 | } |
151 | bool is_part_of_group() { return 1; } |
152 | |
153 | uint m_row_count; /* The number of rows added to the event */ |
154 | |
155 | protected: |
156 | /* |
157 | The constructors are protected since you're supposed to inherit |
158 | this class, not create instances of this class. |
159 | */ |
160 | #ifndef MYSQL_CLIENT |
161 | Old_rows_log_event(THD*, TABLE*, ulong table_id, |
162 | MY_BITMAP const *cols, bool is_transactional); |
163 | #endif |
164 | Old_rows_log_event(const char *row_data, uint event_len, |
165 | Log_event_type event_type, |
166 | const Format_description_log_event *description_event); |
167 | |
168 | #ifdef MYSQL_CLIENT |
169 | bool print_helper(FILE *, PRINT_EVENT_INFO *, char const *const name); |
170 | #endif |
171 | |
172 | #ifndef MYSQL_CLIENT |
173 | virtual int do_add_row_data(uchar *data, size_t length); |
174 | #endif |
175 | |
176 | #ifndef MYSQL_CLIENT |
177 | TABLE *m_table; /* The table the rows belong to */ |
178 | #endif |
179 | ulong m_table_id; /* Table ID */ |
180 | MY_BITMAP m_cols; /* Bitmap denoting columns available */ |
181 | ulong m_width; /* The width of the columns bitmap */ |
182 | |
183 | ulong m_master_reclength; /* Length of record on master side */ |
184 | |
185 | /* Bit buffers in the same memory as the class */ |
186 | uint32 m_bitbuf[128/(sizeof(uint32)*8)]; |
187 | uint32 m_bitbuf_ai[128/(sizeof(uint32)*8)]; |
188 | |
189 | uchar *m_rows_buf; /* The rows in packed format */ |
190 | uchar *m_rows_cur; /* One-after the end of the data */ |
191 | uchar *m_rows_end; /* One-after the end of the allocated space */ |
192 | |
193 | flag_set m_flags; /* Flags for row-level events */ |
194 | |
195 | /* helper functions */ |
196 | |
197 | #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) |
198 | const uchar *m_curr_row; /* Start of the row being processed */ |
199 | const uchar *m_curr_row_end; /* One-after the end of the current row */ |
200 | uchar *m_key; /* Buffer to keep key value during searches */ |
201 | |
202 | int find_row(rpl_group_info *); |
203 | int write_row(rpl_group_info *, const bool); |
204 | |
205 | // Unpack the current row into m_table->record[0] |
206 | int unpack_current_row(rpl_group_info *rgi) |
207 | { |
208 | DBUG_ASSERT(m_table); |
209 | ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT); |
210 | return ::unpack_row(rgi, m_table, m_width, m_curr_row, &m_cols, |
211 | &m_curr_row_end, &m_master_reclength, m_rows_end); |
212 | } |
213 | #endif |
214 | |
215 | private: |
216 | |
217 | #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) |
218 | virtual int do_apply_event(rpl_group_info *rgi); |
219 | virtual int do_update_pos(rpl_group_info *rgi); |
220 | virtual enum_skip_reason do_shall_skip(rpl_group_info *rgi); |
221 | |
222 | /* |
223 | Primitive to prepare for a sequence of row executions. |
224 | |
225 | DESCRIPTION |
226 | |
227 | Before doing a sequence of do_prepare_row() and do_exec_row() |
228 | calls, this member function should be called to prepare for the |
229 | entire sequence. Typically, this member function will allocate |
230 | space for any buffers that are needed for the two member |
231 | functions mentioned above. |
232 | |
233 | RETURN VALUE |
234 | |
235 | The member function will return 0 if all went OK, or a non-zero |
236 | error code otherwise. |
237 | */ |
238 | virtual |
239 | int do_before_row_operations(const Slave_reporting_capability *const log) = 0; |
240 | |
241 | /* |
242 | Primitive to clean up after a sequence of row executions. |
243 | |
244 | DESCRIPTION |
245 | |
246 | After doing a sequence of do_prepare_row() and do_exec_row(), |
247 | this member function should be called to clean up and release |
248 | any allocated buffers. |
249 | |
250 | The error argument, if non-zero, indicates an error which happened during |
251 | row processing before this function was called. In this case, even if |
252 | function is successful, it should return the error code given in the argument. |
253 | */ |
254 | virtual |
255 | int do_after_row_operations(const Slave_reporting_capability *const log, |
256 | int error) = 0; |
257 | |
258 | /* |
259 | Primitive to do the actual execution necessary for a row. |
260 | |
261 | DESCRIPTION |
262 | The member function will do the actual execution needed to handle a row. |
263 | The row is located at m_curr_row. When the function returns, |
264 | m_curr_row_end should point at the next row (one byte after the end |
265 | of the current row). |
266 | |
267 | RETURN VALUE |
268 | 0 if execution succeeded, 1 if execution failed. |
269 | |
270 | */ |
271 | virtual int do_exec_row(rpl_group_info *rgi) = 0; |
272 | #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ |
273 | |
274 | /********** END OF CUT & PASTE FROM Rows_log_event **********/ |
275 | protected: |
276 | |
277 | #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) |
278 | |
279 | int do_apply_event(Old_rows_log_event*, rpl_group_info *rgi); |
280 | |
281 | /* |
282 | Primitive to prepare for a sequence of row executions. |
283 | |
284 | DESCRIPTION |
285 | |
286 | Before doing a sequence of do_prepare_row() and do_exec_row() |
287 | calls, this member function should be called to prepare for the |
288 | entire sequence. Typically, this member function will allocate |
289 | space for any buffers that are needed for the two member |
290 | functions mentioned above. |
291 | |
292 | RETURN VALUE |
293 | |
294 | The member function will return 0 if all went OK, or a non-zero |
295 | error code otherwise. |
296 | */ |
297 | virtual int do_before_row_operations(TABLE *table) = 0; |
298 | |
299 | /* |
300 | Primitive to clean up after a sequence of row executions. |
301 | |
302 | DESCRIPTION |
303 | |
304 | After doing a sequence of do_prepare_row() and do_exec_row(), |
305 | this member function should be called to clean up and release |
306 | any allocated buffers. |
307 | */ |
308 | virtual int do_after_row_operations(TABLE *table, int error) = 0; |
309 | |
310 | /* |
311 | Primitive to prepare for handling one row in a row-level event. |
312 | |
313 | DESCRIPTION |
314 | |
315 | The member function prepares for execution of operations needed for one |
316 | row in a row-level event by reading up data from the buffer containing |
317 | the row. No specific interpretation of the data is normally done here, |
318 | since SQL thread specific data is not available: that data is made |
319 | available for the do_exec function. |
320 | |
321 | A pointer to the start of the next row, or NULL if the preparation |
322 | failed. Currently, preparation cannot fail, but don't rely on this |
323 | behavior. |
324 | |
325 | RETURN VALUE |
326 | Error code, if something went wrong, 0 otherwise. |
327 | */ |
328 | virtual int do_prepare_row(THD*, rpl_group_info*, TABLE*, |
329 | uchar const *row_start, |
330 | uchar const **row_end) = 0; |
331 | |
332 | /* |
333 | Primitive to do the actual execution necessary for a row. |
334 | |
335 | DESCRIPTION |
336 | The member function will do the actual execution needed to handle a row. |
337 | |
338 | RETURN VALUE |
339 | 0 if execution succeeded, 1 if execution failed. |
340 | |
341 | */ |
342 | virtual int do_exec_row(TABLE *table) = 0; |
343 | |
344 | #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ |
345 | }; |
346 | |
347 | |
348 | /** |
349 | @class Write_rows_log_event_old |
350 | |
351 | Old class for binlog events that write new rows to a table (event |
352 | type code PRE_GA_WRITE_ROWS_EVENT). Such events are never produced |
353 | by this version of the server, but they may be read from a relay log |
354 | created by an old server. New servers create events of class |
355 | Write_rows_log_event (event type code WRITE_ROWS_EVENT) instead. |
356 | */ |
357 | class Write_rows_log_event_old : public Old_rows_log_event |
358 | { |
359 | /********** BEGIN CUT & PASTE FROM Write_rows_log_event **********/ |
360 | public: |
361 | #if !defined(MYSQL_CLIENT) |
362 | Write_rows_log_event_old(THD*, TABLE*, ulong table_id, |
363 | MY_BITMAP const *cols, bool is_transactional); |
364 | #endif |
365 | #ifdef HAVE_REPLICATION |
366 | Write_rows_log_event_old(const char *buf, uint event_len, |
367 | const Format_description_log_event *description_event); |
368 | #endif |
369 | #if !defined(MYSQL_CLIENT) |
370 | static bool binlog_row_logging_function(THD *thd, TABLE *table, |
371 | bool is_transactional, |
372 | const uchar *before_record |
373 | __attribute__((unused)), |
374 | const uchar *after_record) |
375 | { |
376 | return thd->binlog_write_row(table, is_transactional, after_record); |
377 | } |
378 | #endif |
379 | |
380 | private: |
381 | #ifdef MYSQL_CLIENT |
382 | bool print(FILE *file, PRINT_EVENT_INFO *print_event_info); |
383 | #endif |
384 | |
385 | #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) |
386 | virtual int do_before_row_operations(const Slave_reporting_capability *const); |
387 | virtual int do_after_row_operations(const Slave_reporting_capability *const,int); |
388 | virtual int do_exec_row(rpl_group_info *); |
389 | #endif |
390 | /********** END OF CUT & PASTE FROM Write_rows_log_event **********/ |
391 | |
392 | public: |
393 | enum |
394 | { |
395 | /* Support interface to THD::binlog_prepare_pending_rows_event */ |
396 | TYPE_CODE = PRE_GA_WRITE_ROWS_EVENT |
397 | }; |
398 | |
399 | private: |
400 | virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; } |
401 | |
402 | #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) |
403 | // use old definition of do_apply_event() |
404 | virtual int do_apply_event(rpl_group_info *rgi) |
405 | { return Old_rows_log_event::do_apply_event(this, rgi); } |
406 | |
407 | // primitives for old version of do_apply_event() |
408 | virtual int do_before_row_operations(TABLE *table); |
409 | virtual int do_after_row_operations(TABLE *table, int error); |
410 | virtual int do_prepare_row(THD*, rpl_group_info*, TABLE*, |
411 | uchar const *row_start, uchar const **row_end); |
412 | virtual int do_exec_row(TABLE *table); |
413 | |
414 | #endif |
415 | }; |
416 | |
417 | |
418 | /** |
419 | @class Update_rows_log_event_old |
420 | |
421 | Old class for binlog events that modify existing rows to a table |
422 | (event type code PRE_GA_UPDATE_ROWS_EVENT). Such events are never |
423 | produced by this version of the server, but they may be read from a |
424 | relay log created by an old server. New servers create events of |
425 | class Update_rows_log_event (event type code UPDATE_ROWS_EVENT) |
426 | instead. |
427 | */ |
428 | class Update_rows_log_event_old : public Old_rows_log_event |
429 | { |
430 | /********** BEGIN CUT & PASTE FROM Update_rows_log_event **********/ |
431 | public: |
432 | #ifndef MYSQL_CLIENT |
433 | Update_rows_log_event_old(THD*, TABLE*, ulong table_id, |
434 | MY_BITMAP const *cols, |
435 | bool is_transactional); |
436 | #endif |
437 | |
438 | #ifdef HAVE_REPLICATION |
439 | Update_rows_log_event_old(const char *buf, uint event_len, |
440 | const Format_description_log_event *description_event); |
441 | #endif |
442 | |
443 | #if !defined(MYSQL_CLIENT) |
444 | static bool binlog_row_logging_function(THD *thd, TABLE *table, |
445 | bool is_transactional, |
446 | MY_BITMAP *cols, |
447 | uint fields, |
448 | const uchar *before_record, |
449 | const uchar *after_record) |
450 | { |
451 | return thd->binlog_update_row(table, is_transactional, |
452 | before_record, after_record); |
453 | } |
454 | #endif |
455 | |
456 | protected: |
457 | #ifdef MYSQL_CLIENT |
458 | bool print(FILE *file, PRINT_EVENT_INFO *print_event_info); |
459 | #endif |
460 | |
461 | #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) |
462 | virtual int do_before_row_operations(const Slave_reporting_capability *const); |
463 | virtual int do_after_row_operations(const Slave_reporting_capability *const,int); |
464 | virtual int do_exec_row(rpl_group_info *); |
465 | #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ |
466 | /********** END OF CUT & PASTE FROM Update_rows_log_event **********/ |
467 | |
468 | uchar *m_after_image, *m_memory; |
469 | |
470 | public: |
471 | enum |
472 | { |
473 | /* Support interface to THD::binlog_prepare_pending_rows_event */ |
474 | TYPE_CODE = PRE_GA_UPDATE_ROWS_EVENT |
475 | }; |
476 | |
477 | private: |
478 | virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; } |
479 | |
480 | #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) |
481 | // use old definition of do_apply_event() |
482 | virtual int do_apply_event(rpl_group_info *rgi) |
483 | { return Old_rows_log_event::do_apply_event(this, rgi); } |
484 | |
485 | // primitives for old version of do_apply_event() |
486 | virtual int do_before_row_operations(TABLE *table); |
487 | virtual int do_after_row_operations(TABLE *table, int error); |
488 | virtual int do_prepare_row(THD*, rpl_group_info*, TABLE*, |
489 | uchar const *row_start, uchar const **row_end); |
490 | virtual int do_exec_row(TABLE *table); |
491 | #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ |
492 | }; |
493 | |
494 | |
495 | /** |
496 | @class Delete_rows_log_event_old |
497 | |
498 | Old class for binlog events that delete existing rows from a table |
499 | (event type code PRE_GA_DELETE_ROWS_EVENT). Such events are never |
500 | produced by this version of the server, but they may be read from a |
501 | relay log created by an old server. New servers create events of |
502 | class Delete_rows_log_event (event type code DELETE_ROWS_EVENT) |
503 | instead. |
504 | */ |
505 | class Delete_rows_log_event_old : public Old_rows_log_event |
506 | { |
507 | /********** BEGIN CUT & PASTE FROM Update_rows_log_event **********/ |
508 | public: |
509 | #ifndef MYSQL_CLIENT |
510 | Delete_rows_log_event_old(THD*, TABLE*, ulong, |
511 | MY_BITMAP const *cols, bool is_transactional); |
512 | #endif |
513 | #ifdef HAVE_REPLICATION |
514 | Delete_rows_log_event_old(const char *buf, uint event_len, |
515 | const Format_description_log_event *description_event); |
516 | #endif |
517 | #if !defined(MYSQL_CLIENT) |
518 | static bool binlog_row_logging_function(THD *thd, TABLE *table, |
519 | bool is_transactional, |
520 | MY_BITMAP *cols, |
521 | uint fields, |
522 | const uchar *before_record, |
523 | const uchar *after_record |
524 | __attribute__((unused))) |
525 | { |
526 | return thd->binlog_delete_row(table, is_transactional, before_record); |
527 | } |
528 | #endif |
529 | |
530 | protected: |
531 | #ifdef MYSQL_CLIENT |
532 | bool print(FILE *file, PRINT_EVENT_INFO *print_event_info); |
533 | #endif |
534 | |
535 | #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) |
536 | virtual int do_before_row_operations(const Slave_reporting_capability *const); |
537 | virtual int do_after_row_operations(const Slave_reporting_capability *const,int); |
538 | virtual int do_exec_row(rpl_group_info *); |
539 | #endif |
540 | /********** END CUT & PASTE FROM Delete_rows_log_event **********/ |
541 | |
542 | uchar *m_after_image, *m_memory; |
543 | |
544 | public: |
545 | enum |
546 | { |
547 | /* Support interface to THD::binlog_prepare_pending_rows_event */ |
548 | TYPE_CODE = PRE_GA_DELETE_ROWS_EVENT |
549 | }; |
550 | |
551 | private: |
552 | virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; } |
553 | |
554 | #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) |
555 | // use old definition of do_apply_event() |
556 | virtual int do_apply_event(rpl_group_info *rgi) |
557 | { return Old_rows_log_event::do_apply_event(this, rgi); } |
558 | |
559 | // primitives for old version of do_apply_event() |
560 | virtual int do_before_row_operations(TABLE *table); |
561 | virtual int do_after_row_operations(TABLE *table, int error); |
562 | virtual int do_prepare_row(THD*, rpl_group_info*, TABLE*, |
563 | uchar const *row_start, uchar const **row_end); |
564 | virtual int do_exec_row(TABLE *table); |
565 | #endif |
566 | }; |
567 | |
568 | |
569 | #endif |
570 | |