|
|
|
@ -1661,18 +1661,48 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, |
|
|
|
|
|
|
|
/* 2 utility functions for the next method */ |
|
|
|
|
|
|
|
/*
|
|
|
|
Get the pointer for a string (src) that contains the length in |
|
|
|
the first byte. Set the output string (dst) to the string value |
|
|
|
and place the length of the string in the byte after the string. |
|
|
|
/**
|
|
|
|
Read a string with length from memory. |
|
|
|
|
|
|
|
This function reads the string-with-length stored at |
|
|
|
<code>src</code> and extract the length into <code>*len</code> and |
|
|
|
a pointer to the start of the string into <code>*dst</code>. The |
|
|
|
string can then be copied using <code>memcpy()</code> with the |
|
|
|
number of bytes given in <code>*len</code>. |
|
|
|
|
|
|
|
@param src Pointer to variable holding a pointer to the memory to |
|
|
|
read the string from. |
|
|
|
@param dst Pointer to variable holding a pointer where the actual |
|
|
|
string starts. Starting from this position, the string |
|
|
|
can be copied using @c memcpy(). |
|
|
|
@param len Pointer to variable where the length will be stored. |
|
|
|
@param end One-past-the-end of the memory where the string is |
|
|
|
stored. |
|
|
|
|
|
|
|
@return Zero if the entire string can be copied successfully, |
|
|
|
@c UINT_MAX if the length could not be read from memory |
|
|
|
(that is, if <code>*src >= end</code>), otherwise the |
|
|
|
number of bytes that are missing to read the full |
|
|
|
string, which happends <code>*dst + *len >= end</code>. |
|
|
|
*/ |
|
|
|
static void get_str_len_and_pointer(const Log_event::Byte **src, |
|
|
|
const char **dst, |
|
|
|
uint *len) |
|
|
|
{ |
|
|
|
if ((*len= **src)) |
|
|
|
*dst= (char *)*src + 1; // Will be copied later
|
|
|
|
(*src)+= *len + 1; |
|
|
|
static int |
|
|
|
get_str_len_and_pointer(const Log_event::Byte **src, |
|
|
|
const char **dst, |
|
|
|
uint *len, |
|
|
|
const Log_event::Byte *end) |
|
|
|
{ |
|
|
|
if (*src >= end) |
|
|
|
return -1; // Will be UINT_MAX in two-complement arithmetics
|
|
|
|
uint length= **src; |
|
|
|
if (length > 0) |
|
|
|
{ |
|
|
|
if (*src + length >= end) |
|
|
|
return *src + length - end + 1; // Number of bytes missing
|
|
|
|
*dst= (char *)*src + 1; // Will be copied later
|
|
|
|
} |
|
|
|
*len= length; |
|
|
|
*src+= length + 1; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static void copy_str_and_move(const char **src, |
|
|
|
@ -1685,6 +1715,46 @@ static void copy_str_and_move(const char **src, |
|
|
|
*(*dst)++= 0; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifndef DBUG_OFF
|
|
|
|
static char const * |
|
|
|
code_name(int code) |
|
|
|
{ |
|
|
|
static char buf[255]; |
|
|
|
switch (code) { |
|
|
|
case Q_FLAGS2_CODE: return "Q_FLAGS2_CODE"; |
|
|
|
case Q_SQL_MODE_CODE: return "Q_SQL_MODE_CODE"; |
|
|
|
case Q_CATALOG_CODE: return "Q_CATALOG_CODE"; |
|
|
|
case Q_AUTO_INCREMENT: return "Q_AUTO_INCREMENT"; |
|
|
|
case Q_CHARSET_CODE: return "Q_CHARSET_CODE"; |
|
|
|
case Q_TIME_ZONE_CODE: return "Q_TIME_ZONE_CODE"; |
|
|
|
case Q_CATALOG_NZ_CODE: return "Q_CATALOG_NZ_CODE"; |
|
|
|
case Q_LC_TIME_NAMES_CODE: return "Q_LC_TIME_NAMES_CODE"; |
|
|
|
case Q_CHARSET_DATABASE_CODE: return "Q_CHARSET_DATABASE_CODE"; |
|
|
|
} |
|
|
|
sprintf(buf, "CODE#%d", code); |
|
|
|
return buf; |
|
|
|
} |
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
Macro to check that there is enough space to read from memory. |
|
|
|
|
|
|
|
@param PTR Pointer to memory |
|
|
|
@param END End of memory |
|
|
|
@param CNT Number of bytes that should be read. |
|
|
|
*/ |
|
|
|
#define CHECK_SPACE(PTR,END,CNT) \
|
|
|
|
do { \ |
|
|
|
DBUG_PRINT("info", ("Read %s", code_name(pos[-1]))); \ |
|
|
|
DBUG_ASSERT((PTR) + (CNT) <= (END)); \ |
|
|
|
if ((PTR) + (CNT) > (END)) { \ |
|
|
|
DBUG_PRINT("info", ("query= 0")); \ |
|
|
|
query= 0; \ |
|
|
|
DBUG_VOID_RETURN; \ |
|
|
|
} \ |
|
|
|
} while (0) |
|
|
|
|
|
|
|
/*
|
|
|
|
Query_log_event::Query_log_event() |
|
|
|
This is used by the SQL slave thread to prepare the event before execution. |
|
|
|
@ -1737,6 +1807,19 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, |
|
|
|
if (tmp) |
|
|
|
{ |
|
|
|
status_vars_len= uint2korr(buf + Q_STATUS_VARS_LEN_OFFSET); |
|
|
|
/*
|
|
|
|
Check if status variable length is corrupt and will lead to very |
|
|
|
wrong data. We could be even more strict and require data_len to |
|
|
|
be even bigger, but this will suffice to catch most corruption |
|
|
|
errors that can lead to a crash. |
|
|
|
*/ |
|
|
|
if (status_vars_len > min(data_len, MAX_SIZE_LOG_EVENT_STATUS)) |
|
|
|
{ |
|
|
|
DBUG_PRINT("info", ("status_vars_len (%u) > data_len (%lu); query= 0", |
|
|
|
status_vars_len, data_len)); |
|
|
|
query= 0; |
|
|
|
DBUG_VOID_RETURN; |
|
|
|
} |
|
|
|
data_len-= status_vars_len; |
|
|
|
DBUG_PRINT("info", ("Query_log_event has status_vars_len: %u", |
|
|
|
(uint) status_vars_len)); |
|
|
|
@ -1756,6 +1839,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, |
|
|
|
{ |
|
|
|
switch (*pos++) { |
|
|
|
case Q_FLAGS2_CODE: |
|
|
|
CHECK_SPACE(pos, end, 4); |
|
|
|
flags2_inited= 1; |
|
|
|
flags2= uint4korr(pos); |
|
|
|
DBUG_PRINT("info",("In Query_log_event, read flags2: %lu", (ulong) flags2)); |
|
|
|
@ -1766,6 +1850,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, |
|
|
|
#ifndef DBUG_OFF
|
|
|
|
char buff[22]; |
|
|
|
#endif
|
|
|
|
CHECK_SPACE(pos, end, 8); |
|
|
|
sql_mode_inited= 1; |
|
|
|
sql_mode= (ulong) uint8korr(pos); // QQ: Fix when sql_mode is ulonglong
|
|
|
|
DBUG_PRINT("info",("In Query_log_event, read sql_mode: %s", |
|
|
|
@ -1774,15 +1859,24 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, |
|
|
|
break; |
|
|
|
} |
|
|
|
case Q_CATALOG_NZ_CODE: |
|
|
|
get_str_len_and_pointer(&pos, &catalog, &catalog_len); |
|
|
|
DBUG_PRINT("info", ("case Q_CATALOG_NZ_CODE; pos: 0x%lx; end: 0x%lx", |
|
|
|
(ulong) pos, (ulong) end)); |
|
|
|
if (get_str_len_and_pointer(&pos, &catalog, &catalog_len, end)) |
|
|
|
{ |
|
|
|
DBUG_PRINT("info", ("query= 0")); |
|
|
|
query= 0; |
|
|
|
DBUG_VOID_RETURN; |
|
|
|
} |
|
|
|
break; |
|
|
|
case Q_AUTO_INCREMENT: |
|
|
|
CHECK_SPACE(pos, end, 4); |
|
|
|
auto_increment_increment= uint2korr(pos); |
|
|
|
auto_increment_offset= uint2korr(pos+2); |
|
|
|
pos+= 4; |
|
|
|
break; |
|
|
|
case Q_CHARSET_CODE: |
|
|
|
{ |
|
|
|
CHECK_SPACE(pos, end, 6); |
|
|
|
charset_inited= 1; |
|
|
|
memcpy(charset, pos, 6); |
|
|
|
pos+= 6; |
|
|
|
@ -1790,20 +1884,29 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, |
|
|
|
} |
|
|
|
case Q_TIME_ZONE_CODE: |
|
|
|
{ |
|
|
|
get_str_len_and_pointer(&pos, &time_zone_str, &time_zone_len); |
|
|
|
if (get_str_len_and_pointer(&pos, &time_zone_str, &time_zone_len, end)) |
|
|
|
{ |
|
|
|
DBUG_PRINT("info", ("Q_TIME_ZONE_CODE: query= 0")); |
|
|
|
query= 0; |
|
|
|
DBUG_VOID_RETURN; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case Q_CATALOG_CODE: /* for 5.0.x where 0<=x<=3 masters */ |
|
|
|
CHECK_SPACE(pos, end, 1); |
|
|
|
if ((catalog_len= *pos)) |
|
|
|
catalog= (char*) pos+1; // Will be copied later
|
|
|
|
CHECK_SPACE(pos, end, catalog_len + 2); |
|
|
|
pos+= catalog_len+2; // leap over end 0
|
|
|
|
catalog_nz= 0; // catalog has end 0 in event
|
|
|
|
break; |
|
|
|
case Q_LC_TIME_NAMES_CODE: |
|
|
|
CHECK_SPACE(pos, end, 2); |
|
|
|
lc_time_names_number= uint2korr(pos); |
|
|
|
pos+= 2; |
|
|
|
break; |
|
|
|
case Q_CHARSET_DATABASE_CODE: |
|
|
|
CHECK_SPACE(pos, end, 2); |
|
|
|
charset_database_number= uint2korr(pos); |
|
|
|
pos+= 2; |
|
|
|
break; |
|
|
|
@ -2317,6 +2420,7 @@ end: |
|
|
|
*/ |
|
|
|
thd->catalog= 0; |
|
|
|
thd->set_db(NULL, 0); /* will free the current database */ |
|
|
|
DBUG_PRINT("info", ("end: query= 0")); |
|
|
|
thd->query= 0; // just to be sure
|
|
|
|
thd->query_length= 0; |
|
|
|
VOID(pthread_mutex_unlock(&LOCK_thread_count)); |
|
|
|
|