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.cc124
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