From dc8d5bc7ba7e73cd0f651c3fabc921fe3b00a2f8 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 14:41:41 +0100 Subject: [PATCH] BUG#32580 (mysqlbinlog cannot read binlog event generated by user variable usage): The client program 'mysqlbinlog' crashed when trying to print a User_var_log_event holding a floating-point value since the format specifier for my_b_printf() does not support floating-point format specifiers. This patch prints the floating-point number to an internal buffer, and then writes that buffer to the output instead. mysql-test/r/mysqlbinlog.result: Result file change. mysql-test/t/mysqlbinlog.test: Adding test that mysqlbinlog can write and read back User_var_log_event for real, decimal, integer, and string. These are the only types supported for user variables. sql/log_event.cc: Using my_sprintf() to print floating-point value of User_var_log_event value to a character buffer and then to the real output, since my_b_printf() does not support floating-point format. Also adding macro to give buffer size needed for printing floating-point numbers in %g format. --- mysql-test/r/mysqlbinlog.result | 25 +++++++++++++++++++++++++ mysql-test/t/mysqlbinlog.test | 27 +++++++++++++++++++++++++++ sql/log_event.cc | 14 +++++++++++++- 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index 1deb9401aa1..cb3a4ff34ab 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -351,4 +351,29 @@ a b 1 root@localhost DROP DATABASE mysqltest1; DROP USER untrusted@localhost; +BUG#32580: mysqlbinlog cannot read binlog event with user variables +USE test; +SET BINLOG_FORMAT = STATEMENT; +FLUSH LOGS; +CREATE TABLE t1 (a_real FLOAT, an_int INT, a_decimal DECIMAL(5,2), a_string CHAR(32)); +SET @a_real = rand(20) * 1000; +SET @an_int = 1000; +SET @a_decimal = CAST(rand(19) * 999 AS DECIMAL(5,2)); +SET @a_string = 'Just a test'; +INSERT INTO t1 VALUES (@a_real, @an_int, @a_decimal, @a_string); +FLUSH LOGS; +SELECT * FROM t1; +a_real 158.883 +an_int 1000 +a_decimal 907.79 +a_string Just a test +DROP TABLE t1; +>> mysqlbinlog var/log/master-bin.000019 > var/tmp/bug32580.sql +>> mysql test < var/tmp/bug32580.sql +SELECT * FROM t1; +a_real 158.883 +an_int 1000 +a_decimal 907.79 +a_string Just a test +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index edaf07a64db..de34b85cf03 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -278,4 +278,31 @@ connection default; DROP DATABASE mysqltest1; DROP USER untrusted@localhost; +--echo BUG#32580: mysqlbinlog cannot read binlog event with user variables + +# Testing that various kinds of events can be read and restored properly. + +connection default; +USE test; +SET BINLOG_FORMAT = STATEMENT; +FLUSH LOGS; +CREATE TABLE t1 (a_real FLOAT, an_int INT, a_decimal DECIMAL(5,2), a_string CHAR(32)); +SET @a_real = rand(20) * 1000; +SET @an_int = 1000; +SET @a_decimal = CAST(rand(19) * 999 AS DECIMAL(5,2)); +SET @a_string = 'Just a test'; +INSERT INTO t1 VALUES (@a_real, @an_int, @a_decimal, @a_string); +FLUSH LOGS; +query_vertical SELECT * FROM t1; +DROP TABLE t1; + +echo >> mysqlbinlog var/log/master-bin.000019 > var/tmp/bug32580.sql; +exec $MYSQL_BINLOG $MYSQLTEST_VARDIR/log/master-bin.000019 > $MYSQLTEST_VARDIR/tmp/bug32580.sql; +echo >> mysql test < var/tmp/bug32580.sql; +exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/bug32580.sql; +remove_file $MYSQLTEST_VARDIR/tmp/bug32580.sql; + +query_vertical SELECT * FROM t1; +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/sql/log_event.cc b/sql/log_event.cc index 9ad85be8a91..d1ad9211d63 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -36,6 +36,16 @@ #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") + +/* + Size of buffer for printing a double in format %.g + + optional '-' + optional zero + '.' + PREC digits + 'e' + sign + + exponent digits + '\0' +*/ +#define FMT_G_BUFSIZE(PREC) (3 + (PREC) + 5 + 1) + + #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) && !defined(DBUG_OFF) && !defined(_lint) static const char *HA_ERR(int i) { @@ -4404,8 +4414,10 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) switch (type) { case REAL_RESULT: double real_val; + char real_buf[FMT_G_BUFSIZE(14)]; float8get(real_val, val); - my_b_printf(&cache, ":=%.14g%s\n", real_val, print_event_info->delimiter); + my_sprintf(real_buf, (real_buf, "%.14g", real_val)); + my_b_printf(&cache, ":=%s%s\n", real_buf, print_event_info->delimiter); break; case INT_RESULT: char int_buf[22];