summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/log_event.cc141
-rw-r--r--sql/log_event.h14
-rw-r--r--sql/log_event_old.cc4
-rw-r--r--sql/rpl_record.cc16
-rw-r--r--sql/rpl_record.h3
-rw-r--r--sql/share/errmsg.txt2
-rw-r--r--sql/sql_binlog.cc7
7 files changed, 127 insertions, 60 deletions
diff --git a/sql/log_event.cc b/sql/log_event.cc
index df0d1e8a020..62e04336d29 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -99,27 +99,51 @@ static const char *HA_ERR(int i)
case HA_ERR_RECORD_IS_THE_SAME: return "HA_ERR_RECORD_IS_THE_SAME";
case HA_ERR_LOGGING_IMPOSSIBLE: return "HA_ERR_LOGGING_IMPOSSIBLE";
case HA_ERR_CORRUPT_EVENT: return "HA_ERR_CORRUPT_EVENT";
+ case HA_ERR_ROWS_EVENT_APPLY : return "HA_ERR_ROWS_EVENT_APPLY";
}
return 0;
}
/**
- macro to call from different branches of Rows_log_event::do_apply_event
+ Error reporting facility for Rows_log_event::do_apply_event
+
+ @param level error, warning or info
+ @param ha_error HA_ERR_ code
+ @param rli pointer to the active Relay_log_info instance
+ @param thd pointer to the slave thread's thd
+ @param table pointer to the event's table object
+ @param type the type of the event
+ @param log_name the master binlog file name
+ @param pos the master binlog file pos (the next after the event)
+
*/
static void inline slave_rows_error_report(enum loglevel level, int ha_error,
Relay_log_info const *rli, THD *thd,
TABLE *table, const char * type,
const char *log_name, ulong pos)
{
- const char *handler_error= HA_ERR(ha_error);
+ const char *handler_error= HA_ERR(ha_error);
+ char buff[MAX_SLAVE_ERRMSG], *slider;
+ const char *buff_end= buff + sizeof(buff);
+ uint len;
+ List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+ MYSQL_ERROR *err;
+ buff[0]= 0;
+
+ for (err= it++, slider= buff; err && slider < buff_end - 1;
+ slider += len, err= it++)
+ {
+ len= my_snprintf(slider, buff_end - slider,
+ " %s, Error_code: %d;", err->msg, err->code);
+ }
+
rli->report(level, thd->net.client_last_errno,
"Could not execute %s event on table %s.%s;"
- "%s%s handler error %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,
- thd->net.client_last_error[0] != 0 ? thd->net.client_last_error : "",
- thd->net.client_last_error[0] != 0 ? ";" : "",
+ buff,
handler_error == NULL? "<unknown>" : handler_error,
log_name, pos);
}
@@ -212,9 +236,9 @@ uint debug_not_change_ts_if_art_event= 1; // bug#29309 simulation
*/
#ifdef MYSQL_CLIENT
-static void pretty_print_str(IO_CACHE* cache, char* str, int len)
+static void pretty_print_str(IO_CACHE* cache, const char* str, int len)
{
- char* end = str + len;
+ const char* end = str + len;
my_b_printf(cache, "\'");
while (str < end)
{
@@ -277,9 +301,9 @@ inline int ignored_error_code(int err_code)
*/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-static char *pretty_print_str(char *packet, char *str, int len)
+static char *pretty_print_str(char *packet, const char *str, int len)
{
- char *end= str + len;
+ const char *end= str + len;
char *pos= packet;
*pos++= '\'';
while (str < end)
@@ -385,7 +409,7 @@ static void cleanup_load_tmpdir()
write_str()
*/
-static bool write_str(IO_CACHE *file, char *str, uint length)
+static bool write_str(IO_CACHE *file, const char *str, uint length)
{
uchar tmp[1];
tmp[0]= (uchar) length;
@@ -2957,18 +2981,63 @@ Format_description_log_event(const char* buf,
If post_header_len is null, it means malloc failed, and is_valid
will fail, so there is no need to do anything.
- The trees which have wrong event id's are:
- mysql-5.1-wl2325-5.0-drop6p13-alpha, mysql-5.1-wl2325-5.0-drop6,
- mysql-5.1-wl2325-5.0, mysql-5.1-wl2325-no-dd (`grep -C2
- BEGIN_LOAD_QUERY_EVENT /home/bk/ * /sql/log_event.h`). The
- corresponding version (`grep mysql, configure.in` in those trees)
- strings are 5.2.2-a_drop6p13-alpha, 5.2.2-a_drop6p13c,
- 5.1.5-a_drop5p20, 5.1.2-a_drop5p5.
+ The trees in which events have wrong id's are:
+
+ mysql-5.1-wl1012.old mysql-5.1-wl2325-5.0-drop6p13-alpha
+ mysql-5.1-wl2325-5.0-drop6 mysql-5.1-wl2325-5.0
+ mysql-5.1-wl2325-no-dd
+
+ (this was found by grepping for two lines in sequence where the
+ first matches "FORMAT_DESCRIPTION_EVENT," and the second matches
+ "TABLE_MAP_EVENT," in log_event.h in all trees)
+
+ In these trees, the following server_versions existed since
+ TABLE_MAP_EVENT was introduced:
+
+ 5.1.1-a_drop5p3 5.1.1-a_drop5p4 5.1.1-alpha
+ 5.1.2-a_drop5p10 5.1.2-a_drop5p11 5.1.2-a_drop5p12
+ 5.1.2-a_drop5p13 5.1.2-a_drop5p14 5.1.2-a_drop5p15
+ 5.1.2-a_drop5p16 5.1.2-a_drop5p16b 5.1.2-a_drop5p16c
+ 5.1.2-a_drop5p17 5.1.2-a_drop5p4 5.1.2-a_drop5p5
+ 5.1.2-a_drop5p6 5.1.2-a_drop5p7 5.1.2-a_drop5p8
+ 5.1.2-a_drop5p9 5.1.3-a_drop5p17 5.1.3-a_drop5p17b
+ 5.1.3-a_drop5p17c 5.1.4-a_drop5p18 5.1.4-a_drop5p19
+ 5.1.4-a_drop5p20 5.1.4-a_drop6p0 5.1.4-a_drop6p1
+ 5.1.4-a_drop6p2 5.1.5-a_drop5p20 5.2.0-a_drop6p3
+ 5.2.0-a_drop6p4 5.2.0-a_drop6p5 5.2.0-a_drop6p6
+ 5.2.1-a_drop6p10 5.2.1-a_drop6p11 5.2.1-a_drop6p12
+ 5.2.1-a_drop6p6 5.2.1-a_drop6p7 5.2.1-a_drop6p8
+ 5.2.2-a_drop6p13 5.2.2-a_drop6p13-alpha 5.2.2-a_drop6p13b
+ 5.2.2-a_drop6p13c
+
+ (this was found by grepping for "mysql," in all historical
+ versions of configure.in in the trees listed above).
+
+ There are 5.1.1-alpha versions that use the new event id's, so we
+ do not test that version string. So replication from 5.1.1-alpha
+ with the other event id's to a new version does not work.
+ Moreover, we can safely ignore the part after drop[56]. This
+ allows us to simplify the big list above to the following regexes:
+
+ 5\.1\.[1-5]-a_drop5.*
+ 5\.1\.4-a_drop6.*
+ 5\.2\.[0-2]-a_drop6.*
+
+ This is what we test for in the 'if' below.
*/
if (post_header_len &&
- (strncmp(server_version, "5.1.2-a_drop5", 13) == 0 ||
- strncmp(server_version, "5.1.5-a_drop5", 13) == 0 ||
- strncmp(server_version, "5.2.2-a_drop6", 13) == 0))
+ server_version[0] == '5' && server_version[1] == '.' &&
+ server_version[3] == '.' &&
+ strncmp(server_version + 5, "-a_drop", 7) == 0 &&
+ ((server_version[2] == '1' &&
+ server_version[4] >= '1' && server_version[4] <= '5' &&
+ server_version[12] == '5') ||
+ (server_version[2] == '1' &&
+ server_version[4] == '4' &&
+ server_version[12] == '6') ||
+ (server_version[2] == '2' &&
+ server_version[4] >= '0' && server_version[4] <= '2' &&
+ server_version[12] == '6')))
{
if (number_of_event_types != 22)
{
@@ -6026,7 +6095,8 @@ bool sql_ex_info::write_data(IO_CACHE* file)
sql_ex_info::init()
*/
-char *sql_ex_info::init(char *buf, char *buf_end, bool use_new_format)
+const char *sql_ex_info::init(const char *buf, const char *buf_end,
+ bool use_new_format)
{
cached_new_format = use_new_format;
if (use_new_format)
@@ -6039,12 +6109,11 @@ char *sql_ex_info::init(char *buf, char *buf_end, bool use_new_format)
the case when we have old format because we will be reusing net buffer
to read the actual file before we write out the Create_file event.
*/
- const char *ptr= buf;
- if (read_str(&ptr, buf_end, (const char **) &field_term, &field_term_len) ||
- read_str(&ptr, buf_end, (const char **) &enclosed, &enclosed_len) ||
- read_str(&ptr, buf_end, (const char **) &line_term, &line_term_len) ||
- read_str(&ptr, buf_end, (const char **) &line_start, &line_start_len) ||
- read_str(&ptr, buf_end, (const char **) &escaped, &escaped_len))
+ if (read_str(&buf, buf_end, &field_term, &field_term_len) ||
+ read_str(&buf, buf_end, &enclosed, &enclosed_len) ||
+ read_str(&buf, buf_end, &line_term, &line_term_len) ||
+ read_str(&buf, buf_end, &line_start, &line_start_len) ||
+ read_str(&buf, buf_end, &escaped, &escaped_len))
return 0;
opt_flags = *buf++;
}
@@ -7646,7 +7715,7 @@ Rows_log_event::write_row(const Relay_log_info *const rli,
/* fill table->record[0] with default values */
- if ((error= prepare_record(rli, table, m_width,
+ if ((error= prepare_record(table, m_width,
TRUE /* check if columns have def. values */)))
DBUG_RETURN(error);
@@ -7964,13 +8033,17 @@ int Rows_log_event::find_row(const Relay_log_info *rli)
DBUG_ASSERT(m_table && m_table->in_use != NULL);
TABLE *table= m_table;
- int error;
-
- /* unpack row - missing fields get default values */
+ int error= 0;
- // TODO: shall we check and report errors here?
- prepare_record(NULL,table,m_width,FALSE /* don't check errors */);
- error= unpack_current_row(rli);
+ /*
+ rpl_row_tabledefs.test specifies that
+ if the extra field on the slave does not have a default value
+ and this is okay with Delete or Update events.
+ Todo: fix wl3228 hld that requires defauls for all types of events
+ */
+
+ prepare_record(table, m_width, FALSE);
+ error= unpack_current_row(rli);
#ifndef DBUG_OFF
DBUG_PRINT("info",("looking for the following record"));
diff --git a/sql/log_event.h b/sql/log_event.h
index efb8675780e..59d58d47bad 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -152,11 +152,11 @@ struct old_sql_ex
struct sql_ex_info
{
sql_ex_info() {} /* Remove gcc warning */
- char* field_term;
- char* enclosed;
- char* line_term;
- char* line_start;
- char* escaped;
+ const char* field_term;
+ const char* enclosed;
+ const char* line_term;
+ const char* line_start;
+ const char* escaped;
int cached_new_format;
uint8 field_term_len,enclosed_len,line_term_len,line_start_len, escaped_len;
char opt_flags;
@@ -171,7 +171,7 @@ struct sql_ex_info
line_start_len + escaped_len + 6 : 7);
}
bool write_data(IO_CACHE* file);
- char* init(char* buf,char* buf_end,bool use_new_format);
+ const char* init(const char* buf, const char* buf_end, bool use_new_format);
bool new_format()
{
return ((cached_new_format != -1) ? cached_new_format :
@@ -3131,6 +3131,8 @@ protected:
ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT);
int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols,
&m_curr_row_end, &m_master_reclength);
+ if (m_curr_row_end > m_rows_end)
+ my_error(ER_SLAVE_CORRUPT_EVENT, MYF(0));
ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT);
return result;
}
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index 7621bdc6291..13f9763debe 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -2078,7 +2078,7 @@ Old_rows_log_event::write_row(const Relay_log_info *const rli,
/* fill table->record[0] with default values */
- if ((error= prepare_record(rli, table, m_width,
+ if ((error= prepare_record(table, m_width,
TRUE /* check if columns have def. values */)))
DBUG_RETURN(error);
@@ -2289,7 +2289,7 @@ int Old_rows_log_event::find_row(const Relay_log_info *rli)
/* unpack row - missing fields get default values */
// TODO: shall we check and report errors here?
- prepare_record(NULL,table,m_width,FALSE /* don't check errors */);
+ prepare_record(table, m_width, FALSE /* don't check errors */);
error= unpack_current_row(rli);
#ifndef DBUG_OFF
diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc
index eb32897f937..7c74dcba5a0 100644
--- a/sql/rpl_record.cc
+++ b/sql/rpl_record.cc
@@ -307,17 +307,15 @@ unpack_row(Relay_log_info const *rli,
If @c check is true, fields are explicitly initialized only if they have
default value or can be NULL. Otherwise error is reported.
- @param log Used to report errors.
@param table Table whose record[0] buffer is prepared.
@param skip Number of columns for which default value initialization
should be skipped.
@param check Indicates if errors should be checked when setting default
values.
- @returns 0 on success.
+ @returns 0 on success or a handler level error code
*/
-int prepare_record(const Slave_reporting_capability *const log,
- TABLE *const table,
+int prepare_record(TABLE *const table,
const uint skip, const bool check)
{
DBUG_ENTER("prepare_record");
@@ -337,14 +335,8 @@ int prepare_record(const Slave_reporting_capability *const log,
if (check && ((f->flags & mask) == mask))
{
- DBUG_ASSERT(log);
- error= ER_NO_DEFAULT_FOR_FIELD;
- log->report(ERROR_LEVEL, error,
- "Field `%s` of table `%s`.`%s` "
- "has no default value and cannot be NULL",
- f->field_name, table->s->db.str,
- table->s->table_name.str);
- my_error(error, MYF(0), f->field_name);
+ my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), f->field_name);
+ error = HA_ERR_ROWS_EVENT_APPLY;
}
else
f->set_default();
diff --git a/sql/rpl_record.h b/sql/rpl_record.h
index 0d6ceda7433..f9e64f0ab1d 100644
--- a/sql/rpl_record.h
+++ b/sql/rpl_record.h
@@ -30,8 +30,7 @@ int unpack_row(Relay_log_info const *rli,
uchar const **const row_end, ulong *const master_reclength);
// Fill table's record[0] with default values.
-int prepare_record(const Slave_reporting_capability *const, TABLE *const,
- const uint =0, const bool =FALSE);
+int prepare_record(TABLE *const, const uint =0, const bool =FALSE);
#endif
#endif
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 026a0023660..ee3a7e6080a 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -6119,3 +6119,5 @@ ER_SLAVE_AMBIGOUS_EXEC_MODE
ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT
eng "The BINLOG statement of type `%s` was not preceded by a format description BINLOG statement."
+ER_SLAVE_CORRUPT_EVENT
+ eng "Corrupted replication event was detected"
diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc
index 04f408453ea..4bfae16ba6d 100644
--- a/sql/sql_binlog.cc
+++ b/sql/sql_binlog.cc
@@ -152,14 +152,13 @@ void mysql_client_binlog_statement(THD* thd)
*/
if (!have_fd_event)
{
- if (bufptr[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT)
+ int type = bufptr[EVENT_TYPE_OFFSET];
+ if (type == FORMAT_DESCRIPTION_EVENT || type == START_EVENT_V3)
have_fd_event= TRUE;
else
{
my_error(ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT,
- MYF(0),
- Log_event::get_type_str(
- (Log_event_type)bufptr[EVENT_TYPE_OFFSET]));
+ MYF(0), Log_event::get_type_str((Log_event_type)type));
goto end;
}
}