From ed9e73077dd9562b77485fc034f5e3b7688b5dd0 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 30 Jan 2008 14:12:40 +0100 Subject: [PATCH] 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. mysql-test/suite/binlog/std_data/binlog_old_version_4_1.000001: New BitKeeper file ``mysql-test/suite/binlog/std_data/binlog_old_version_4_1.000001'' mysql-test/suite/binlog/r/binlog_old_versions.result: Updated result file. mysql-test/suite/binlog/t/binlog_old_versions.test: Added a test reading an old 4.1 binlog. sql/log_event.cc: 1. Added const keyword at the following places: - input buffer for pretty_print_str - input buffer for write_str - input buffer, end pointer, and return value from sql_ex_info::init 2. Fixed the bug by not taking a copy of buf before calling read_str in sql_ex_info::init(). sql/log_event.h: Added const keyword to fields of the sql_ex_info struct. Added const keyword to arguments and return value of sql_ex_info::init sql/sql_binlog.cc: The first BINLOG statement must describe the format for future BINLOG statements. Otherwise, we do not know how to read the BINLOG statement. Problem: only FORMAT_DESCRIPTION_EVENT is currently allowed as the first event. Binlogs from 4.1 begin with a START_EVENT_V3, which serves the same purpose. Fix: We now allow the first BINLOG statement to be a START_EVENT_V3, as well as a FORMAT_DESCRIPTION_EVENT. --- .../suite/binlog/r/binlog_old_versions.result | 10 ++++++++ .../std_data/binlog_old_version_4_1.000001 | Bin 0 -> 149436 bytes .../suite/binlog/t/binlog_old_versions.test | 15 +++++++++++ sql/log_event.cc | 24 +++++++++--------- sql/log_event.h | 12 ++++----- sql/sql_binlog.cc | 7 +++-- 6 files changed, 46 insertions(+), 22 deletions(-) create mode 100644 mysql-test/suite/binlog/std_data/binlog_old_version_4_1.000001 diff --git a/mysql-test/suite/binlog/r/binlog_old_versions.result b/mysql-test/suite/binlog/r/binlog_old_versions.result index a514f9278a6..77289252b4c 100644 --- a/mysql-test/suite/binlog/r/binlog_old_versions.result +++ b/mysql-test/suite/binlog/r/binlog_old_versions.result @@ -29,6 +29,16 @@ SELECT COUNT(*) FROM t3; COUNT(*) 17920 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) ==== SELECT * FROM t1 ORDER BY a; a b diff --git a/mysql-test/suite/binlog/std_data/binlog_old_version_4_1.000001 b/mysql-test/suite/binlog/std_data/binlog_old_version_4_1.000001 new file mode 100644 index 0000000000000000000000000000000000000000..66db9668d46eeb5a3659253091a62b79d718f0cb GIT binary patch literal 149436 zcmeI5O=}xh6oyA`3W=fJwu?dsx`-2!kgqOFt2V;8O&o}wK%m9USYt~>8Ntlh#QUzh z?KYeImqMYxqR@X)dfs#Aj+>eWX{1&A1f-dftQko;y7zg{*Znh}mY+UX@c`_RA zkJA0&*AGW&b0^)((rMY;Nb~e?l2u!u-@bM&9qn%K?2ghe(nn`Id&5WFS--UNyz#TW z`>gkLRzKZcozC9WhkC(vyZzq1{8h4{^If)E_|QqxU1($v`b(03UT9}`Z}en8-PzrL ztatxx`0(jyFWvg;)s6J((fp*k>X-XKFZ;}Hd;a<#e`!9pgXGQ6zinvSUFWGCocfZmteTwEo3@#ko5MWIvrW4lzR>+qqkH?PW!x6yxHm12vr4t`I_)oO?SSq=PzlB zN@ud4k8kw4Vea2euGi+pS-98J`CK30?(M^C<409-I<=SUiFQ|CUEKGVg~!8NYM+?; zSABlqXVj(4+zS0K_*SpBooSiPw0Cl-D{A8(NIT&??VkU+Jvi4#(qr=~KBV*OJ=zOx zXXba)OomX*YBz|Y8W(nDd!Q<_W}^2}RA&FWq;~vL7!gKf=716TD5W1)Rx=X$Si?wE z#_38EX|N5SewfaD7AyQaVLDq1vV5HJVJ0vPOyooZ6D>pP7?J&g0BbXY733a9gb}Um zGr)*2B8&(>5za;%2^*Y^I2$Lery7qn9&02%VUM1{IKUdP2CM;Vz#6b7im%xaunrj@ zniok0v2VfBieiA4d?NCR6r>M=OM9&f*KRZtqWC1Gd1jmq9U4A}o%zp&%*MqAjI;I9QN_na-&8Seb({B8&(l^3nk6&Zs+U zAE?J}%G|geblZ z4&+#qV{K#OqB&%MHDC=`1J-~wU=3Kawnvt?i#JfbXlP{V2*cb41_2dd4Oj!#$F$ok zvxeeDiWgf4W*)7b#xsVyK0w^ERAH>}(0Q4qy#f z1J-~wU=3K4ltxloM^PlDk(73-gdUhz`E8n6be0c*e-um-FFYrxvp$jq^oBur8``Q8*-3^d~x&P1I6Z zZX4m=yNonNEKv%3fHhzZSOeC8HDFCD2+qbeG(Rs;rcH&`x7*C)VFF7PlTTcKar+I+U<=^ zyHUJI@uJt_S^3Ab%x1zRGmCcPQ>KpPMh?%o#0$G~Rfc0k)SXdx)-THqb*2G?C_Yhq zqWDDd1>{528R`sm23XV3!3CGtNO=aRv!&)oz#6b7>_ONgggflFK-dGY2CM;Vz#6ay ztoyIR2Ur8vfHhzZSldY0;IXzMGnVgU`A$nC(!5AMkz5URw`ObD^Exq_q02hRCkku) zQZhuz5UUKa%Fr6h#Hhum7Jp?$juBx*7!eH}Xy_pQMjvacJ?LXiA8YzpcPgDe*8M7c z0BgV+um-FFYrvW^YQi2JP|+!kPHCr8D|@wwaa^)fjRfMprp&lVC(CzU95?`Lz#6ay ztO0Al8nC`NKYAWo$VQ_-5&en!c`q>{`vuXT$jso7k|ETY*?}e+PvZ5xwuR=!*#~uo zIzyeI&QNDUDDsKOCnBGSd?NCRx|jxGkA8|Aum-FFYrq`cB%lF~>@BPorfG?LOf=|xgn zzj!HN4Oj!#fHhzZSd)}SQd$R8G`TV~GMPDC!#WQdTF7jin`Di7Ma0gQ&Mm=+qVdEn zMuZVr7e1K*0ayaCG6Mpzmaivj$=2)}T>A-`&f+u{w@hbDXG~}IYoI@oCNicoOS`U^ z&O*9v(=ALK_B2`8V40@q&bQD=Ei18bH{7Ss41iFmlojWqq&7z{I-iM z>I`*;I@6G#ASu-zI2%!Cl3vbOsIx4$Z^HD~%I(`0n`^q3ml8;77^3%qK z?db+8X#hCVeCUW2x1bWieJ7+6RB|yz>NUZA`5L`08dN&eupmMLmCEBdX%gHgxKD8Z z-0^6?3w)4(wT4Gl^|ZXms?3^+8tusS2v~p(C%W)CN7IFmE`0swM>ikMu5{s}3twNz!iXf` zS$v3QA+2XKhCmcFZubMO#RIR3K0i7G=}hqF6JO JH`}o-%3l=-N?iZ| literal 0 HcmV?d00001 diff --git a/mysql-test/suite/binlog/t/binlog_old_versions.test b/mysql-test/suite/binlog/t/binlog_old_versions.test index 9fb7343e761..b2922809b1b 100644 --- a/mysql-test/suite/binlog/t/binlog_old_versions.test +++ b/mysql-test/suite/binlog/t/binlog_old_versions.test @@ -51,6 +51,21 @@ SELECT COUNT(*) FROM 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) ==== # In this version, it was not possible to switch between row-based and diff --git a/sql/log_event.cc b/sql/log_event.cc index 45478020a36..070e6ab4c12 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -212,9 +212,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 +277,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) @@ -388,7 +388,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; @@ -6011,7 +6011,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) @@ -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 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++; } diff --git a/sql/log_event.h b/sql/log_event.h index 31c1ab7173a..c85d620d831 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 : diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index 543b1af9fc0..778aa46149c 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -159,14 +159,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; } }