diff options
Diffstat (limited to 'sql/log_event.cc')
-rw-r--r-- | sql/log_event.cc | 156 |
1 files changed, 108 insertions, 48 deletions
diff --git a/sql/log_event.cc b/sql/log_event.cc index 6f83e5f4db2..c5935b86df9 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -158,16 +158,21 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error, " %s, Error_code: %d;", err->get_message_text(), err->get_sql_errno()); } - - rli->report(level, thd->is_error()? thd->stmt_da->sql_errno() : 0, - "Could not execute %s event on table %s.%s;" - "%s handler error %s; " - "the event's master log %s, end_log_pos %lu", - type, table->s->db.str, - table->s->table_name.str, - buff, - handler_error == NULL? "<unknown>" : handler_error, - log_name, pos); + + if (ha_error != 0) + rli->report(level, thd->is_error() ? thd->stmt_da->sql_errno() : 0, + "Could not execute %s event on table %s.%s;" + "%s handler error %s; " + "the event's master log %s, end_log_pos %lu", + type, table->s->db.str, table->s->table_name.str, + buff, handler_error == NULL ? "<unknown>" : handler_error, + log_name, pos); + else + rli->report(level, thd->is_error() ? thd->stmt_da->sql_errno() : 0, + "Could not execute %s event on table %s.%s;" + "%s the event's master log %s, end_log_pos %lu", + type, table->s->db.str, table->s->table_name.str, + buff, log_name, pos); } #endif @@ -1238,7 +1243,7 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len, break; #ifdef HAVE_REPLICATION case SLAVE_EVENT: /* can never happen (unused event) */ - ev = new Slave_log_event(buf, event_len); + ev = new Slave_log_event(buf, event_len, description_event); break; #endif /* HAVE_REPLICATION */ case CREATE_FILE_EVENT: @@ -1326,8 +1331,10 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len, (because constructor is "void") ; so instead we leave the pointer we wanted to allocate (e.g. 'query') to 0 and we test it in is_valid(). Same for Format_description_log_event, member 'post_header_len'. + + SLAVE_EVENT is never used, so it should not be read ever. */ - if (!ev || !ev->is_valid()) + if (!ev || !ev->is_valid() || (event_type == SLAVE_EVENT)) { DBUG_PRINT("error",("Found invalid event in binary log")); @@ -2324,7 +2331,7 @@ bool Query_log_event::write(IO_CACHE* file) start+= 4; } - if (thd && thd->is_current_user_used()) + if (thd && thd->need_binlog_invoker()) { LEX_STRING user; LEX_STRING host; @@ -2961,7 +2968,12 @@ void Query_log_event::print_query_header(IO_CACHE* file, error_code); } - if (!(flags & LOG_EVENT_SUPPRESS_USE_F) && db) + if ((flags & LOG_EVENT_SUPPRESS_USE_F)) + { + if (!is_trans_keyword()) + print_event_info->db[0]= '\0'; + } + else if (db) { different_db= memcmp(print_event_info->db, db, db_len + 1); if (different_db) @@ -3233,7 +3245,8 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, if (is_trans_keyword() || rpl_filter->db_ok(thd->db)) { thd->set_time((time_t)when); - thd->set_query_and_id((char*)query_arg, q_len_arg, next_query_id()); + thd->set_query_and_id((char*)query_arg, q_len_arg, + thd->charset(), next_query_id()); thd->variables.pseudo_thread_id= thread_id; // for temp tables DBUG_PRINT("query",("%s", thd->query())); @@ -3285,6 +3298,18 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, goto compare_errors; } thd->update_charset(); // for the charset change to take effect + /* + Reset thd->query_string.cs to the newly set value. + Note, there is a small flaw here. For a very short time frame + if the new charset is different from the old charset and + if another thread executes "SHOW PROCESSLIST" after + the above thd->set_query_and_id() and before this thd->set_query(), + and if the current query has some non-ASCII characters, + the another thread may see some '?' marks in the PROCESSLIST + result. This should be acceptable now. This is a reminder + to fix this if any refactoring happens here sometime. + */ + thd->set_query((char*) query_arg, q_len_arg, thd->charset()); } } if (time_zone_len) @@ -3345,6 +3370,8 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, if (!parser_state.init(thd, thd->query(), thd->query_length())) { mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); + /* Finalize server status flags after executing a statement. */ + thd->update_server_status(); log_slow_statement(thd); } @@ -3419,7 +3446,8 @@ compare_errors: rli->report(ERROR_LEVEL, 0, "\ Query caused different errors on master and slave. \ -Error on master: '%s' (%d), Error on slave: '%s' (%d). \ +Error on master: message (format)='%s' error code=%d ; \ +Error on slave: actual message='%s', error code=%d. \ Default database: '%s'. Query: '%s'", ER_SAFE(expected_error), expected_error, @@ -3505,7 +3533,7 @@ end: */ thd->catalog= 0; thd->set_db(NULL, 0); /* will free the current database */ - thd->set_query(NULL, 0); + thd->reset_query(); DBUG_PRINT("info", ("end: query= 0")); /* As a disk space optimization, future masters will not log an event for @@ -4742,7 +4770,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, new_db.str= (char *) rpl_filter->get_rewrite_db(db, &new_db.length); thd->set_db(new_db.str, new_db.length); DBUG_ASSERT(thd->query() == 0); - thd->set_query_inner(NULL, 0); // Should not be needed + thd->reset_query_inner(); // Should not be needed thd->is_slave_error= 0; clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); @@ -4936,7 +4964,7 @@ error: const char *remember_db= thd->db; thd->catalog= 0; thd->set_db(NULL, 0); /* will free the current database */ - thd->set_query(NULL, 0); + thd->reset_query(); thd->stmt_da->can_overwrite_status= TRUE; thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); thd->stmt_da->can_overwrite_status= FALSE; @@ -4953,6 +4981,8 @@ error: */ if (! thd->in_multi_stmt_transaction_mode()) thd->mdl_context.release_transactional_locks(); + else + thd->mdl_context.release_statement_locks(); DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error", thd->is_slave_error= 0; thd->is_fatal_error= 1;); @@ -6111,8 +6141,12 @@ void Slave_log_event::init_from_mem_pool(int data_size) /** This code is not used, so has not been updated to be format-tolerant. */ -Slave_log_event::Slave_log_event(const char* buf, uint event_len) - :Log_event(buf,0) /*unused event*/ ,mem_pool(0),master_host(0) +/* We are using description_event so that slave does not crash on Log_event + constructor */ +Slave_log_event::Slave_log_event(const char* buf, + uint event_len, + const Format_description_log_event* description_event) + :Log_event(buf,description_event),mem_pool(0),master_host(0) { if (event_len < LOG_EVENT_HEADER_LEN) return; @@ -7711,6 +7745,14 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) // Do event specific preparations error= do_before_row_operations(rli); + /* + Bug#56662 Assertion failed: next_insert_id == 0, file handler.cc + Don't allow generation of auto_increment value when processing + rows event by setting 'MODE_NO_AUTO_VALUE_ON_ZERO'. + */ + ulong saved_sql_mode= thd->variables.sql_mode; + thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO; + // row processing loop while (error == 0 && m_curr_row < m_rows_end) @@ -7773,6 +7815,11 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) thd->transaction.stmt.modified_non_trans_table= TRUE; } // row processing loop + /* + Restore the sql_mode after the rows event is processed. + */ + thd->variables.sql_mode= saved_sql_mode; + {/** The following failure injecion works in cooperation with tests setting @@global.debug= 'd,stop_slave_middle_group'. @@ -7811,19 +7858,16 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) /Sven */ thd->reset_current_stmt_binlog_format_row(); - const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error); thd->is_slave_error= 1; DBUG_RETURN(error); } - if (get_flags(STMT_END_F)) - if ((error= rows_event_stmt_cleanup(rli, thd))) - rli->report(ERROR_LEVEL, error, - "Error in %s event: commit of row events failed, " - "table `%s`.`%s`", - get_type_str(), m_table->s->db.str, - m_table->s->table_name.str); - + if (get_flags(STMT_END_F) && (error= rows_event_stmt_cleanup(rli, thd))) + slave_rows_error_report(ERROR_LEVEL, + thd->is_error() ? 0 : error, + rli, thd, table, + get_type_str(), + RPL_LOG_NAME, (ulong) log_pos); DBUG_RETURN(error); } @@ -8502,6 +8546,8 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli) m_field_metadata, m_field_metadata_size, m_null_bits, m_flags); table_list->m_tabledef_valid= TRUE; + table_list->m_conv_table= NULL; + table_list->open_type= OT_BASE_ONLY; /* We record in the slave's information that the table should be @@ -8606,7 +8652,7 @@ void Table_map_log_event::pack_info(Protocol *protocol) #ifdef MYSQL_CLIENT -void Table_map_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info) +void Table_map_log_event::print(FILE *, PRINT_EVENT_INFO *print_event_info) { if (!print_event_info->short_form) { @@ -8843,16 +8889,11 @@ Rows_log_event::write_row(const Relay_log_info *const rli, int UNINIT_VAR(keynum); auto_afree_ptr<char> key(NULL); - /* fill table->record[0] with default values */ - bool abort_on_warnings= (rli->sql_thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)); - if ((error= prepare_record(table, m_width, - table->file->ht->db_type != DB_TYPE_NDBCLUSTER, - abort_on_warnings, m_curr_row == m_rows_buf))) - DBUG_RETURN(error); - + prepare_record(table, m_width, + table->file->ht->db_type != DB_TYPE_NDBCLUSTER); + /* unpack row into table->record[0] */ - if ((error= unpack_current_row(rli, abort_on_warnings))) + if ((error= unpack_current_row(rli))) DBUG_RETURN(error); if (m_curr_row == m_rows_buf) @@ -9117,7 +9158,19 @@ static bool record_compare(TABLE *table) } } - if (table->s->blob_fields + table->s->varchar_fields == 0) + /** + Compare full record only if: + - there are no blob fields (otherwise we would also need + to compare blobs contents as well); + - there are no varchar fields (otherwise we would also need + to compare varchar contents as well); + - there are no null fields, otherwise NULLed fields + contents (i.e., the don't care bytes) may show arbitrary + values, depending on how each engine handles internally. + */ + if ((table->s->blob_fields + + table->s->varchar_fields + + table->s->null_fields) == 0) { result= cmp_record(table,record[1]); goto record_compare_exit; @@ -9132,13 +9185,22 @@ static bool record_compare(TABLE *table) goto record_compare_exit; } - /* Compare updated fields */ + /* Compare fields */ for (Field **ptr=table->field ; *ptr ; ptr++) { - if ((*ptr)->cmp_binary_offset(table->s->rec_buff_length)) + + /** + We only compare field contents that are not null. + NULL fields (i.e., their null bits) were compared + earlier. + */ + if (!(*(ptr))->is_null()) { - result= TRUE; - goto record_compare_exit; + if ((*ptr)->cmp_binary_offset(table->s->rec_buff_length)) + { + result= TRUE; + goto record_compare_exit; + } } } @@ -9703,11 +9765,9 @@ Update_rows_log_event::do_exec_row(const Relay_log_info *const rli) store_record(m_table,record[1]); - bool abort_on_warnings= (rli->sql_thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)); m_curr_row= m_curr_row_end; /* this also updates m_curr_row_end */ - if ((error= unpack_current_row(rli, abort_on_warnings))) + if ((error= unpack_current_row(rli))) return error; /* |