Skip to content
  • Sven Sandberg's avatar
    45424a31
    Bug#18145032: NO EMPTY TRANSACTION IS CREATED FOR A FILTERED CREATE TEMPORARY TABLE WITH GTIDS · 45424a31
    Sven Sandberg authored
    Bug#18095502: NO EMPTY TRANSACTION IS CREATED FOR REPLICATE-IGNORE-DB OR REPLICATE-DO-DB
    
    Background:
    When gtid_mode=on, and a transaction is filtered out on the slave,
    the GTID of the transaction is still logged on the slave as a so-called
    empty transaction (just a GTID followed by BEGIN and then COMMIT). This
    is necessary to prevent the transaction from being re-transmitted next
    time the slave reconnects or does a fail-over.
    
    Symptom:
     1. If a CREATE TEMPORARY TABLE or DROP TEMPORARY TABLE statement was
        filtered out, no empty transaction was generated.
     2. If the slave has a database filter (--replicate-[do|ignore]-db),
        no empty transaction was generated.
    
    Analysis:
     1. Empty transactions are normally generated after a committing statement
        ends, i.e., after an explicit COMMIT statement or after a statement that
        causes an implicit commit.
    
        However, CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE have very
        special semantics when it comes to implicit commit. The statements do
        not have the implicit commit flag set and will not commit an ongoing
        transaction. However, they cannot be rolled back.
    
        So when executed out of transactional context, they effectively perform
        a commit after execution.
    
        When GTID_MODE=ON, these statements are only allowed outside
        transactional context, and they are not written to the binary log
        within BEGIN/COMMIT statements. Therefore, when such a statement
        has been executed and filtered out, an empty transaction must be
        explicitly committed.
    
        The reason for the bug is that the current condition for checking
        if empty transaction should be generated is that
        stmt_causes_implicit_commit returns true.
    
     2. Empty transactions are generated in mysql_parse. However,
        database filters were evaluated before mysql_parse was even
        called.
    
    Fix:
     1. When checking if an empty transaction should be generated, also check
        explicitly for CREATE/DROP TEMPORARY.
    
     2. Move database filter checking into mysql_parse.
    
    Further bugs:
     3. In the special case that a statement has an 'unexpected' error code
        according to the check in log_event.cc:unexpected_error_code(),
        mysql_parse() is not executed and instead mysql_test_parse_for_slave()
        is executed. This is for the sole purpose of parsing without executing,
        so that an error is only generated on the slave for non-filtered
        tables. Thus, when moving the filter rule checking from
        do_apply_event() into mysql_parse(), we also need to perform the same
        check in mysql_test_parse_for_slave().
    
    Test framework fixes:
    - To ease testing of this and other GTID-related bugs, I added the
      test framework files gtid_step_reset.inc and gtid_step_assert.inc.
      gtid_step_assert.inc asserts that the statements executed since
      last gtid_step_reset.inc generated a given number of GTIDs. This
      in turn needed some extra functions in gtid_utils.inc, and I also
      cleaned up and simplified gtid_utils a little and added a test
      case for it.
    - Small improvement in mysql-test/include/wait_for_slave_sql_to_stop.inc
      to allow comments after the error code(s).
    45424a31
    Bug#18145032: NO EMPTY TRANSACTION IS CREATED FOR A FILTERED CREATE TEMPORARY TABLE WITH GTIDS
    Sven Sandberg authored
    Bug#18095502: NO EMPTY TRANSACTION IS CREATED FOR REPLICATE-IGNORE-DB OR REPLICATE-DO-DB
    
    Background:
    When gtid_mode=on, and a transaction is filtered out on the slave,
    the GTID of the transaction is still logged on the slave as a so-called
    empty transaction (just a GTID followed by BEGIN and then COMMIT). This
    is necessary to prevent the transaction from being re-transmitted next
    time the slave reconnects or does a fail-over.
    
    Symptom:
     1. If a CREATE TEMPORARY TABLE or DROP TEMPORARY TABLE statement was
        filtered out, no empty transaction was generated.
     2. If the slave has a database filter (--replicate-[do|ignore]-db),
        no empty transaction was generated.
    
    Analysis:
     1. Empty transactions are normally generated after a committing statement
        ends, i.e., after an explicit COMMIT statement or after a statement that
        causes an implicit commit.
    
        However, CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE have very
        special semantics when it comes to implicit commit. The statements do
        not have the implicit commit flag set and will not commit an ongoing
        transaction. However, they cannot be rolled back.
    
        So when executed out of transactional context, they effectively perform
        a commit after execution.
    
        When GTID_MODE=ON, these statements are only allowed outside
        transactional context, and they are not written to the binary log
        within BEGIN/COMMIT statements. Therefore, when such a statement
        has been executed and filtered out, an empty transaction must be
        explicitly committed.
    
        The reason for the bug is that the current condition for checking
        if empty transaction should be generated is that
        stmt_causes_implicit_commit returns true.
    
     2. Empty transactions are generated in mysql_parse. However,
        database filters were evaluated before mysql_parse was even
        called.
    
    Fix:
     1. When checking if an empty transaction should be generated, also check
        explicitly for CREATE/DROP TEMPORARY.
    
     2. Move database filter checking into mysql_parse.
    
    Further bugs:
     3. In the special case that a statement has an 'unexpected' error code
        according to the check in log_event.cc:unexpected_error_code(),
        mysql_parse() is not executed and instead mysql_test_parse_for_slave()
        is executed. This is for the sole purpose of parsing without executing,
        so that an error is only generated on the slave for non-filtered
        tables. Thus, when moving the filter rule checking from
        do_apply_event() into mysql_parse(), we also need to perform the same
        check in mysql_test_parse_for_slave().
    
    Test framework fixes:
    - To ease testing of this and other GTID-related bugs, I added the
      test framework files gtid_step_reset.inc and gtid_step_assert.inc.
      gtid_step_assert.inc asserts that the statements executed since
      last gtid_step_reset.inc generated a given number of GTIDs. This
      in turn needed some extra functions in gtid_utils.inc, and I also
      cleaned up and simplified gtid_utils a little and added a test
      case for it.
    - Small improvement in mysql-test/include/wait_for_slave_sql_to_stop.inc
      to allow comments after the error code(s).
Loading