diff options
author | Lixun Peng <lixun@mariadb.org> | 2017-07-03 14:48:07 +0800 |
---|---|---|
committer | Lixun Peng <lixun@mariadb.org> | 2017-07-03 14:48:07 +0800 |
commit | 007d3ed90513fa21182b3059b4bb7278fc425bd5 (patch) | |
tree | 1c5bcc0052415dc00903671f87fa84281d016b4c /client/mysqlbinlog.cc | |
parent | 92f1837a27f4b78a3e6c74ca33c3052211069af5 (diff) | |
download | mariadb-git-007d3ed90513fa21182b3059b4bb7278fc425bd5.tar.gz |
MDEV-12067 flashback does not correcly revert update/replace statementsbb-10.2-MDEV-12067
Problem
-------
For one-statement contains multiple row events, Flashback didn't reverse the
sequence of row events inside one-statement.
Solution
--------
Using a new array 'events_in_stmt' to store the row events of one-statement,
when parsed the last one event, then print from the last one to the first one.
In the same time, fixed another bug, without -vv will not insert the table_map
into print_event_info->m_table_map, then change_to_flashback_event() will not
execute because of Table_map_log_event is empty.
Diffstat (limited to 'client/mysqlbinlog.cc')
-rw-r--r-- | client/mysqlbinlog.cc | 67 |
1 files changed, 64 insertions, 3 deletions
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 34e810f7b6b..584f6955453 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -68,6 +68,7 @@ CHARSET_INFO* system_charset_info= &my_charset_utf8_general_ci; /* Needed for Flashback */ DYNAMIC_ARRAY binlog_events; // Storing the events output string +DYNAMIC_ARRAY events_in_stmt; // Storing the events that in one statement String stop_event_string; // Storing the STOP_EVENT output string char server_version[SERVER_VERSION_LENGTH]; @@ -894,6 +895,25 @@ static bool print_row_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, print_event_info->m_table_map_ignored.get_table(table_id); bool skip_event= (ignored_map != NULL); + if (opt_flashback) + { + Rows_log_event *e= (Rows_log_event*) ev; + // The last Row_log_event will be the first event in Flashback + if (is_stmt_end) + e->clear_flags(Rows_log_event::STMT_END_F); + // The first Row_log_event will be the last event in Flashback + if (events_in_stmt.elements == 0) + e->set_flags(Rows_log_event::STMT_END_F); + // Update the temp_buf + e->update_flags(); + + if (insert_dynamic(&events_in_stmt, (uchar *) &ev)) + { + error("Out of memory: can't allocate memory to store the flashback events."); + exit(1); + } + } + /* end of statement check: i) destroy/free ignored maps @@ -945,7 +965,36 @@ static bool print_row_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, if (skip_event) return 0; - return print_base64(print_event_info, ev); + if (!opt_flashback) + return print_base64(print_event_info, ev); + else + { + if (is_stmt_end) + { + bool res= false; + Log_event *e= NULL; + + // Print the row_event from the last one to the first one + for (uint i= events_in_stmt.elements; i > 0; --i) + { + e= *(dynamic_element(&events_in_stmt, i - 1, Log_event**)); + res= res || print_base64(print_event_info, e); + } + // Copy all output into the Log_event + ev->output_buf.copy(e->output_buf); + // Delete Log_event + for (uint i= 0; i < events_in_stmt.elements-1; ++i) + { + e= *(dynamic_element(&events_in_stmt, i, Log_event**)); + delete e; + } + reset_dynamic(&events_in_stmt); + + return res; + } + } + + return 0; } @@ -1386,6 +1435,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, } if (print_base64(print_event_info, ev)) goto err; + if (opt_flashback) + reset_dynamic(&events_in_stmt); break; } case WRITE_ROWS_EVENT: @@ -1402,9 +1453,12 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, case DELETE_ROWS_COMPRESSED_EVENT_V1: { Rows_log_event *e= (Rows_log_event*) ev; + bool is_stmt_end= e->get_flags(Rows_log_event::STMT_END_F); if (print_row_event(print_event_info, ev, e->get_table_id(), e->get_flags(Rows_log_event::STMT_END_F))) goto err; + if (!is_stmt_end) + destroy_evt= FALSE; break; } case PRE_GA_WRITE_ROWS_EVENT: @@ -1412,9 +1466,12 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, case PRE_GA_UPDATE_ROWS_EVENT: { Old_rows_log_event *e= (Old_rows_log_event*) ev; + bool is_stmt_end= e->get_flags(Rows_log_event::STMT_END_F); if (print_row_event(print_event_info, ev, e->get_table_id(), e->get_flags(Old_rows_log_event::STMT_END_F))) goto err; + if (!is_stmt_end) + destroy_evt= FALSE; break; } case START_ENCRYPTION_EVENT: @@ -1459,7 +1516,7 @@ end: &my_charset_bin); else { - if (push_dynamic(&binlog_events, (uchar *) &tmp_str)) + if (insert_dynamic(&binlog_events, (uchar *) &tmp_str)) { error("Out of memory: can't allocate memory to store the flashback events."); exit(1); @@ -2915,9 +2972,12 @@ int main(int argc, char** argv) my_set_max_open_files(open_files_limit); if (opt_flashback) + { my_init_dynamic_array(&binlog_events, sizeof(LEX_STRING), 1024, 1024, MYF(0)); - + my_init_dynamic_array(&events_in_stmt, sizeof(Rows_log_event*), 1024, 1024, + MYF(0)); + } if (opt_stop_never) to_last_remote_log= TRUE; @@ -3031,6 +3091,7 @@ int main(int argc, char** argv) } fprintf(result_file, "COMMIT\n/*!*/;\n"); delete_dynamic(&binlog_events); + delete_dynamic(&events_in_stmt); } /* Set delimiter back to semicolon */ |