summaryrefslogtreecommitdiff
path: root/sql/log_event.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/log_event.cc')
-rw-r--r--sql/log_event.cc156
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;
/*