diff options
Diffstat (limited to 'sql/log_event.cc')
-rw-r--r-- | sql/log_event.cc | 124 |
1 files changed, 105 insertions, 19 deletions
diff --git a/sql/log_event.cc b/sql/log_event.cc index 54d75449cd5..2657700435d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1130,13 +1130,18 @@ void Log_event::print_header(IO_CACHE* file, char emit_buf[256]; int const bytes_written= my_snprintf(emit_buf, sizeof(emit_buf), - "# %8.8lx %-48.48s |%s|\n# ", + "# %8.8lx %-48.48s |%s|\n", (unsigned long) (hexdump_from + (i & 0xfffffff0)), hex_string, char_string); DBUG_ASSERT(bytes_written >= 0); DBUG_ASSERT(static_cast<my_size_t>(bytes_written) < sizeof(emit_buf)); my_b_write(file, (byte*) emit_buf, bytes_written); } + /* + need a # to prefix the rest of printouts for example those of + Rows_log_event::print_helper(). + */ + my_b_write(file, "# ", 2); } DBUG_VOID_RETURN; } @@ -2240,6 +2245,8 @@ Start_log_event_v3::Start_log_event_v3(const char* buf, binlog_version= uint2korr(buf+ST_BINLOG_VER_OFFSET); memcpy(server_version, buf+ST_SERVER_VER_OFFSET, ST_SERVER_VER_LEN); + // prevent overrun if log is corrupted on disk + server_version[ST_SERVER_VER_LEN-1]= 0; created= uint4korr(buf+ST_CREATED_OFFSET); /* We use log_pos to mark if this was an artificial event or not */ artificial_event= (log_pos == 0); @@ -2363,6 +2370,8 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver) switch (binlog_ver) { case 4: /* MySQL 5.0 */ memcpy(server_version, ::server_version, ST_SERVER_VER_LEN); + DBUG_EXECUTE_IF("pretend_version_50034_in_binlog", + strmov(server_version, "5.0.34");); common_header_len= LOG_EVENT_HEADER_LEN; number_of_event_types= LOG_EVENT_TYPES; /* we'll catch my_malloc() error in is_valid() */ @@ -2453,6 +2462,7 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver) post_header_len= 0; /* will make is_valid() fail */ break; } + calc_server_version_split(); } @@ -2492,6 +2502,7 @@ Format_description_log_event(const char* buf, post_header_len= (uint8*) my_memdup((byte*)buf+ST_COMMON_HEADER_LEN_OFFSET+1, number_of_event_types* sizeof(*post_header_len), MYF(0)); + calc_server_version_split(); DBUG_VOID_RETURN; } @@ -2592,6 +2603,37 @@ int Format_description_log_event::exec_event(struct st_relay_log_info* rli) } #endif + +/** + Splits the event's 'server_version' string into three numeric pieces stored + into 'server_version_split': + X.Y.Zabc (X,Y,Z numbers, a not a digit) -> {X,Y,Z} + X.Yabc -> {X,Y,0} + Xabc -> {X,0,0} + 'server_version_split' is then used for lookups to find if the server which + created this event has some known bug. +*/ +void Format_description_log_event::calc_server_version_split() +{ + char *p= server_version, *r; + ulong number; + for (uint i= 0; i<=2; i++) + { + number= strtoul(p, &r, 10); + server_version_split[i]= (uchar)number; + DBUG_ASSERT(number < 256); // fit in uchar + p= r; + DBUG_ASSERT(!((i == 0) && (*r != '.'))); // should be true in practice + if (*r == '.') + p++; // skip the dot + } + DBUG_PRINT("info",("Format_description_log_event::server_version_split:" + " '%s' %d %d %d", server_version, + server_version_split[0], + server_version_split[1], server_version_split[2])); +} + + /************************************************************************** Load_log_event methods General note about Load_log_event: the binlogging of LOAD DATA INFILE is @@ -5762,15 +5804,45 @@ int Rows_log_event::exec_event(st_relay_log_info *rli) DBUG_RETURN(error); } } + + /* + When the open and locking succeeded, we check all tables to + ensure that they still have the correct type. + + We can use a down cast here since we know that every table added + to the tables_to_lock is a RPL_TABLE_LIST. + */ + + { + RPL_TABLE_LIST *ptr= static_cast<RPL_TABLE_LIST*>(rli->tables_to_lock); + for ( ; ptr ; ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global)) + { + if (ptr->m_tabledef.compatible_with(rli, ptr->table)) + { + mysql_unlock_tables(thd, thd->lock); + thd->lock= 0; + thd->query_error= 1; + rli->clear_tables_to_lock(); + DBUG_RETURN(ERR_BAD_TABLE_DEF); + } + } + } + /* - When the open and locking succeeded, we add all the tables to - the table map and remove them from tables to lock. + ... and then we add all the tables to the table map and remove + them from tables to lock. We also invalidate the query cache for all the tables, since they will now be changed. + + TODO [/Matz]: Maybe the query cache should not be invalidated + here? It might be that a table is not changed, even though it + was locked for the statement. We do know that each + Rows_log_event contain at least one row, so after processing one + Rows_log_event, we can invalidate the query cache for the + associated table. */ - TABLE_LIST *ptr; - for (ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global) + for (TABLE_LIST *ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global) { rli->m_table_map.set_table(ptr->table_id, ptr->table); } @@ -6041,7 +6113,7 @@ void Rows_log_event::print_helper(FILE *file, { bool const last_stmt_event= get_flags(STMT_END_F); print_header(head, print_event_info, !last_stmt_event); - my_b_printf(head, "\t%s: table id %lu", name, m_table_id); + my_b_printf(head, "\t%s: table id %lu\n", name, m_table_id); print_base64(body, print_event_info, !last_stmt_event); } @@ -6223,11 +6295,11 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli) thd->query_id= next_query_id(); pthread_mutex_unlock(&LOCK_thread_count); - TABLE_LIST *table_list; + RPL_TABLE_LIST *table_list; char *db_mem, *tname_mem; void *const memory= my_multi_malloc(MYF(MY_WME), - &table_list, sizeof(TABLE_LIST), + &table_list, sizeof(RPL_TABLE_LIST), &db_mem, NAME_LEN + 1, &tname_mem, NAME_LEN + 1, NULL); @@ -6273,11 +6345,27 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli) } /* - Open the table if it is not already open and add the table to table map. - Note that for any table that should not be replicated, a filter is needed. + Open the table if it is not already open and add the table to + table map. Note that for any table that should not be + replicated, a filter is needed. + + The creation of a new TABLE_LIST is used to up-cast the + table_list consisting of RPL_TABLE_LIST items. This will work + since the only case where the argument to open_tables() is + changed, is when thd->lex->query_tables == table_list, i.e., + when the statement requires prelocking. Since this is not + executed when a statement is executed, this case will not occur. + As a precaution, an assertion is added to ensure that the bad + case is not a fact. + + Either way, the memory in the list is *never* released + internally in the open_tables() function, hence we take a copy + of the pointer to make sure that it's not lost. */ uint count; - if ((error= open_tables(thd, &table_list, &count, 0))) + DBUG_ASSERT(thd->lex->query_tables != table_list); + TABLE_LIST *tmp_table_list= table_list; + if ((error= open_tables(thd, &tmp_table_list, &count, 0))) { if (thd->query_error || thd->is_fatal_error) { @@ -6304,14 +6392,12 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli) */ DBUG_ASSERT(m_table->in_use); - table_def const def(m_coltype, m_colcnt); - if (def.compatible_with(rli, m_table)) - { - thd->query_error= 1; - error= ERR_BAD_TABLE_DEF; - goto err; - /* purecov: end */ - } + /* + Use placement new to construct the table_def instance in the + memory allocated for it inside table_list. + */ + const table_def *const def= + new (&table_list->m_tabledef) table_def(m_coltype, m_colcnt); /* We record in the slave's information that the table should be |