WL#5404: Propagation of Rows_query log event

Affects: Server-5.6   —   Status: Complete

RATIONALE
=========
* Rows_query was introduced to record the original query for rows events
  in RBR, but the Rows query will be lost when replicating on slave or
  re-applying the statments dumped by mysqlbinlog. This worklog will fix
  that.


Requirements
============

1. The original SQL statement will be relayed by Rows_query log event
   in a replication chain if the '--binlog-rows-query-log-events'
   option is enabled.

2. The BINLOG '...' dumped by MYSQLBINLOG will be applied by MySQL
   server if the '--binlog-rows-query-log-events' option is enabled.

3. The Rows_query_log event will follow replication filtering rules
   as Rows_log event does. It will be relayed if slave filters out
   part Rows events or nothing from a rows statement. It will be
   filtered out if slave filters out all its Rows events.


PROPOSED SOLUTIONS
==================
  There are basically two solutions to that:

  1. Output original SQL statement using '#' comment, and also use a
     BINLOG statement to ship the Rows_query_log_event so that it can
     be applied by MySQL server as following:

     #100519 13:20:24 server id 1  end_log_pos 3913  Rows_query
     # original SQL statement
     BINLOG '...'

     The Slave SQL Thread will set the original SQL statement into
     current THD when executing the Rows_query log event and then 
     binlog it with its rows event. So that it can be relayed
     in a replication chain.

     Pro: It is consistent with Table_map event and Rows_log event
          as they are using the BINLOG '...' for the purpose.

  2. Use a variant of the special comments to construct Rows_query log
     event, that is, something like this:
     #100519 13:20:24 server id 1  end_log_pos 3913   Rows_query
     /*! original SQL statement */
     The special comment would automatically be ignored by anything that
     is not MySQL (this is the reason for the /*!*/ comment as well).

     The Slave SQL Thread will set the special comment into current THD
     and parse it when executing the Rows_query log event. So that it
     can be relayed in a replication chain.

     Pro: The special comment will be applied and relayed by itself.

     Con: The special comment will not work fine if the original SQL
          statement include version comment.
          The MySQL will introduce more syntax for special comment.           


  It's related to WL#4033 and BUG#50935.
  

SUMMARY
=======
* The solution one is taken, considering the pro and con of the two
  solutions.



RELAY AND APPLY INTERFACE
========================= 

  Rows_query_log_event::print will print BINLOG'...' with base64 format,
  So that the Rows_query_log_event can be applied by MySQL server.
  It was implemented in WL#4033 as following:
  Rows_query_log_event::print:
    my_b_printf(&cache, "\tRows_query\n");
    my_b_printf(&cache, "# %s\n", m_rows_query);
    //Print BINLOG'...'
    IO_CACHE *const body= &print_event_info->body_cache;
    print_base64(body, print_event_info, true);


  Rows_query_log_event::do_apply_event should set the original SQL statement
  into current THD.
  1. The slave SQL thread will call the interface to set query into THD when
     executing the event, and then binlog the event with its rows event. So
     that it will be relayed.
  2. The MySQL server will construct the Rows_query log event from BINLOG'...'
     statement and then call the interface to set query into THD and then
     binlog the event with its rows event when applying.

  The proposed method is the followings:
  1. Set the 'm_rows_query' member of Rows_query_log_event into THD directly,
     and delay to delete the Rows_query log event until all its rows event
     are executed.
     
     Pro: The 'query' memory space is easily freed when deleting the event.

     Con: Have to delay to delete the Rows_query log event until all its
          rows event are executed.

  2. Allocate space to save the query by thd->alloc and free it later

     Pro: The Rows_query log event will be deleted immediately after it
          is executed.

     Con: The allocated space is not easily freed. It will cause memory 
          leak easily.

  According the pros and cons, we decide to take the first method.
1. Set the 'm_rows_query' member of Rows_query_log_event into THD directly
   as the event is constructed from its BINLOG'...' statement by MySQl server
   when applying, and the slave SQL thread will get it from relay log.

   int Rows_query_log_event::do_apply_event(Relay_log_info const *rli)
   {
     /* Set query for writing Rows_query log event into binlog later.*/
     thd->set_query(m_rows_query, (uint32) strlen(m_rows_query));
   }


2. For the THD still hold the original SQL statement when binlogging
   the Rows_query log event, delay to delete the Rows_query log event
   until all its rows event are executed when delaying and applying.

   /* Delete the Rows_query log event after its last rows event are applied */
   if ((ev_type == WRITE_ROWS_EVENT || ev_type == DELETE_ROWS_EVENT ||
        ev_type == UPDATE_ROWS_EVENT) && rli->rows_query_ev != NULL &&
       ((Rows_log_event*) ev)->get_flags(Rows_log_event::STMT_END_F))
       {
         delete rli->rows_query_ev;
         rli->rows_query_ev= NULL;
       }

   /* Record the Rows_query log event until all its rows event are applied */
   if (ev_type == ROWS_QUERY_LOG_EVENT)
     rli->rows_query_ev= (Rows_query_log_event*) ev;