Commit 30cd549e authored by sven@riska.(none)'s avatar sven@riska.(none)

BUG#34141: mysqlbinlog cannot read 4.1 binlogs containing load data infile

Main problem: mysql 5.1 cannot read binlogs from 4.1.
Subproblem 1: There is a mistake in sql_ex_info::init. The read_str()
function updates its first argument to point to the next character to
read. However, it is applied only to a copy of the buffer pointer, so the
real buffer pointer is not updated.
Fix 1: do not take a copy of the buffer pointer. The copy was needed
because sql_ex_info::init does not use the const attribute on some of its
arguments. So we add the const attribute, too.
Subproblem 2: The first BINLOG statement is asserted to be a
FORMAT_DESCRIPTION_LOG_EVENT, but 4.1 binlogs begin with START_EVENT_V3.
Fix 2: allow START_EVENT_V3 too.
parent 1cb0eae2
...@@ -29,6 +29,16 @@ SELECT COUNT(*) FROM t3; ...@@ -29,6 +29,16 @@ SELECT COUNT(*) FROM t3;
COUNT(*) COUNT(*)
17920 17920
DROP TABLE t1, t2, t3; DROP TABLE t1, t2, t3;
==== Read binlog from version 4.1 ====
SELECT * FROM t1 ORDER BY a;
a b
0 last_insert_id
4 four
190243 random
SELECT COUNT(*) FROM t3;
COUNT(*)
17920
DROP TABLE t1, t3;
==== Read binlog from alcatel tree (mysql-5.1-wl2325-5.0-drop6) ==== ==== Read binlog from alcatel tree (mysql-5.1-wl2325-5.0-drop6) ====
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
a b a b
......
...@@ -51,6 +51,21 @@ SELECT COUNT(*) FROM t3; ...@@ -51,6 +51,21 @@ SELECT COUNT(*) FROM t3;
DROP TABLE t1, t2, t3; DROP TABLE t1, t2, t3;
--echo ==== Read binlog from version 4.1 ====
# In this version, neither row-based binlogging nor Xid events
# existed, so the binlog was generated without the "row-based tests"
# part and the "get xid event" part, and it does not create table t2.
# Read binlog.
--exec $MYSQL_BINLOG suite/binlog/std_data/binlog_old_version_4_1.000001 | $MYSQL
# Show result.
SELECT * FROM t1 ORDER BY a;
SELECT COUNT(*) FROM t3;
# Reset.
DROP TABLE t1, t3;
--echo ==== Read binlog from alcatel tree (mysql-5.1-wl2325-5.0-drop6) ==== --echo ==== Read binlog from alcatel tree (mysql-5.1-wl2325-5.0-drop6) ====
# In this version, it was not possible to switch between row-based and # In this version, it was not possible to switch between row-based and
......
...@@ -212,9 +212,9 @@ uint debug_not_change_ts_if_art_event= 1; // bug#29309 simulation ...@@ -212,9 +212,9 @@ uint debug_not_change_ts_if_art_event= 1; // bug#29309 simulation
*/ */
#ifdef MYSQL_CLIENT #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, "\'"); my_b_printf(cache, "\'");
while (str < end) while (str < end)
{ {
...@@ -277,9 +277,9 @@ inline int ignored_error_code(int err_code) ...@@ -277,9 +277,9 @@ inline int ignored_error_code(int err_code)
*/ */
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) #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; char *pos= packet;
*pos++= '\''; *pos++= '\'';
while (str < end) while (str < end)
...@@ -388,7 +388,7 @@ static void cleanup_load_tmpdir() ...@@ -388,7 +388,7 @@ static void cleanup_load_tmpdir()
write_str() 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]; uchar tmp[1];
tmp[0]= (uchar) length; tmp[0]= (uchar) length;
...@@ -6011,7 +6011,8 @@ bool sql_ex_info::write_data(IO_CACHE* file) ...@@ -6011,7 +6011,8 @@ bool sql_ex_info::write_data(IO_CACHE* file)
sql_ex_info::init() 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; cached_new_format = use_new_format;
if (use_new_format) if (use_new_format)
...@@ -6024,12 +6025,11 @@ char *sql_ex_info::init(char *buf, char *buf_end, bool use_new_format) ...@@ -6024,12 +6025,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 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. to read the actual file before we write out the Create_file event.
*/ */
const char *ptr= buf; if (read_str(&buf, buf_end, &field_term, &field_term_len) ||
if (read_str(&ptr, buf_end, (const char **) &field_term, &field_term_len) || read_str(&buf, buf_end, &enclosed, &enclosed_len) ||
read_str(&ptr, buf_end, (const char **) &enclosed, &enclosed_len) || read_str(&buf, buf_end, &line_term, &line_term_len) ||
read_str(&ptr, buf_end, (const char **) &line_term, &line_term_len) || read_str(&buf, buf_end, &line_start, &line_start_len) ||
read_str(&ptr, buf_end, (const char **) &line_start, &line_start_len) || read_str(&buf, buf_end, &escaped, &escaped_len))
read_str(&ptr, buf_end, (const char **) &escaped, &escaped_len))
return 0; return 0;
opt_flags = *buf++; opt_flags = *buf++;
} }
......
...@@ -152,11 +152,11 @@ struct old_sql_ex ...@@ -152,11 +152,11 @@ struct old_sql_ex
struct sql_ex_info struct sql_ex_info
{ {
sql_ex_info() {} /* Remove gcc warning */ sql_ex_info() {} /* Remove gcc warning */
char* field_term; const char* field_term;
char* enclosed; const char* enclosed;
char* line_term; const char* line_term;
char* line_start; const char* line_start;
char* escaped; const char* escaped;
int cached_new_format; int cached_new_format;
uint8 field_term_len,enclosed_len,line_term_len,line_start_len, escaped_len; uint8 field_term_len,enclosed_len,line_term_len,line_start_len, escaped_len;
char opt_flags; char opt_flags;
...@@ -171,7 +171,7 @@ struct sql_ex_info ...@@ -171,7 +171,7 @@ struct sql_ex_info
line_start_len + escaped_len + 6 : 7); line_start_len + escaped_len + 6 : 7);
} }
bool write_data(IO_CACHE* file); 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() bool new_format()
{ {
return ((cached_new_format != -1) ? cached_new_format : return ((cached_new_format != -1) ? cached_new_format :
......
...@@ -159,14 +159,13 @@ void mysql_client_binlog_statement(THD* thd) ...@@ -159,14 +159,13 @@ void mysql_client_binlog_statement(THD* thd)
*/ */
if (!have_fd_event) 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; have_fd_event= TRUE;
else else
{ {
my_error(ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT, my_error(ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT,
MYF(0), MYF(0), Log_event::get_type_str((Log_event_type)type));
Log_event::get_type_str(
(Log_event_type)bufptr[EVENT_TYPE_OFFSET]));
goto end; goto end;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment