Below is the list of changes that have just been committed into a local
5.0 repository of cmiller. When cmiller does a push these changes
will be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2008-02-27 10:49:48-05:00, cmiller@stripped +3 -0
Bug#33048: Not able to recover binary/blob data correctly using \
mysqlbinlog
mysqlbinlog wrote to stdout query text exactly as sent to the server,
but some queries that can be inserted via the API are illegal or
impossible to send using the command-line "mysql" client (which is
why we have escape characters for special characters).
Now, make mysqlbinlog escape query characters (only CR for now) that
cannot be read via mysql client.
mysql-test/r/type_blob.result@stripped, 2008-02-27 10:49:46-05:00, cmiller@stripped +20 -0
Show that literal CR+NLs are preserved across mysqlbinlog|mysql .
mysql-test/t/type_blob.test@stripped, 2008-02-27 10:49:46-05:00, cmiller@stripped +36 -0
Show that literal CR+NLs are preserved across mysqlbinlog|mysql .
sql/log_event.cc@stripped, 2008-02-27 10:49:46-05:00, cmiller@stripped +34 -1
The mysqbinlog utility describes itself as "Dumps a MySQL binary log
in a format usable for viewing or for piping to the mysql command
line client", but that was untrue if the query contained a literal
carriage return and newline, as the client would consume the
carriage return.
diff -Nrup a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result
--- a/mysql-test/r/type_blob.result 2007-11-19 12:34:12 -05:00
+++ b/mysql-test/r/type_blob.result 2008-02-27 10:49:46 -05:00
@@ -821,4 +821,24 @@ LENGTH(c) CHAR_LENGTH(c)
65535 65535
65535 65535
DROP TABLE t;
+DROP DATABASE IF EXISTS dbbug33048;
+CREATE DATABASE dbbug33048;
+use dbbug33048;
+CREATE TABLE binfile (i int auto_increment primary key, bin_data LONGBLOB);
+FLUSH LOGS;
+INSERT InTO binfile (bin_data) values ('
+');
+SELECT 'good, have failing data' as descr, i FROM binfile where bin_data = concat(char(13), char(10));
+descr i
+good, have failing data 1
+SELECT bin_data INTO dumpfile 'bug33048-dump1' FROM binfile;
+FLUSH LOGS;
+DELETE FROM binfile;
+SELECT bin_data INTO dumpfile 'bug33048-dump2' FROM binfile;
+SELECT 'good, have failing data' as descr, i FROM binfile where bin_data = concat(char(13), char(10));
+descr i
+good, have failing data 1
+DROP TABLE binfile;
+use test;
+DROP DATABASE dbbug33048;
End of 5.0 tests
diff -Nrup a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test
--- a/mysql-test/t/type_blob.test 2007-11-19 12:34:12 -05:00
+++ b/mysql-test/t/type_blob.test 2008-02-27 10:49:46 -05:00
@@ -447,4 +447,40 @@ INSERT INTO t (c) VALUES (REPEAT('3',655
SELECT LENGTH(c), CHAR_LENGTH(c) FROM t;
DROP TABLE t;
+#
+# Bug#33048: Not able to recover binary/blob data correctly using mysqlbinlog
+#
+--disable_warnings
+DROP DATABASE IF EXISTS dbbug33048;
+--enable_warnings
+CREATE DATABASE dbbug33048;
+
+use dbbug33048;
+CREATE TABLE binfile (i int auto_increment primary key, bin_data LONGBLOB);
+
+FLUSH LOGS;
+let $crlf=`select x'0d0a'`;
+eval INSERT InTO binfile (bin_data) values ('$crlf');
+
+SELECT 'good, have failing data' as descr, i FROM binfile where bin_data = concat(char(13), char(10));
+
+SELECT bin_data INTO dumpfile 'bug33048-dump1' FROM binfile;
+FLUSH LOGS;
+DELETE FROM binfile;
+
+exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --database=dbbug33048 $MYSQLTEST_VARDIR/log/master-bin.000002 |$MYSQL dbbug33048;
+
+SELECT bin_data INTO dumpfile 'bug33048-dump2' FROM binfile;
+SELECT 'good, have failing data' as descr, i FROM binfile where bin_data = concat(char(13), char(10));
+
+diff_files $MYSQLTEST_VARDIR/master-data/dbbug33048/bug33048-dump1 $MYSQLTEST_VARDIR/master-data/dbbug33048/bug33048-dump2;
+
+remove_file $MYSQLTEST_VARDIR/master-data/dbbug33048/bug33048-dump1;
+remove_file $MYSQLTEST_VARDIR/master-data/dbbug33048/bug33048-dump2;
+
+DROP TABLE binfile;
+use test;
+DROP DATABASE dbbug33048;
+
+##
--echo End of 5.0 tests
diff -Nrup a/sql/log_event.cc b/sql/log_event.cc
--- a/sql/log_event.cc 2007-12-21 14:30:22 -05:00
+++ b/sql/log_event.cc 2008-02-27 10:49:46 -05:00
@@ -1858,10 +1858,43 @@ void Query_log_event::print_query_header
}
+/**
+ Write the provided event's header, then the (partially-escaped) query and
+ then a delimiter to the provided file handle.
+*/
void Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
+ const char *cursor= query, *cr_location;
+ reg1 uint32 distance_to_end= q_len;
+
print_query_header(file, print_event_info);
- my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
+
+ /*
+ Escape only special characters that cause problems. Currently, this is
+ only known to be carriage returns.
+
+ This is designed to be fast, but simple. If we ever need to escape other
+ characters, then it is probably best to allocate a string with lenth
+ 2*q_len, iterate over each character, copying it or its escaped value to
+ the destination string, then write the destination string once at the end.
+ */
+ while ((cr_location= (char *)memchr(cursor, '\r', distance_to_end)) != NULL)
+ {
+ reg2 uint32 distance_to_cr= cr_location - query;
+ /* Write up to the carriage return. */
+ if (distance_to_cr != 0)
+ my_fwrite(file, (byte*) cursor, distance_to_cr, MYF(MY_NABP | MY_WME));
+
+ /* Write the carriage return. */
+ my_fwrite(file, (byte*) "\\r", 2, MYF(MY_NABP | MY_WME));
+
+ /* Advance the cursor so that the rest looks like a new query */
+ distance_to_end= distance_to_end - (cr_location - cursor);
+ cursor= cr_location+1;
+ }
+
+ /* No problematic characters remain. Write the rest. */
+ my_fwrite(file, (byte*) cursor, distance_to_end, MYF(MY_NABP | MY_WME));
fprintf(file, "\n%s\n", print_event_info->delimiter);
}
#endif /* MYSQL_CLIENT */
| Thread |
|---|
| • bk commit into 5.0 tree (cmiller:1.2580) BUG#33048 | Chad MILLER | 27 Feb |