summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbar@mysql.com/bar.myoffice.izhnet.ru <>2008-02-29 17:56:50 +0400
committerbar@mysql.com/bar.myoffice.izhnet.ru <>2008-02-29 17:56:50 +0400
commitf83cc8e6db90c96db1eb336f690b8a2af3d49e94 (patch)
tree383fd33306f77670825adcb8b08abae9dff732cc
parentef9579619d12a6d9034cfbdfdd90cbd6e5a314b9 (diff)
downloadmariadb-git-f83cc8e6db90c96db1eb336f690b8a2af3d49e94.tar.gz
Bug#23924 general_log truncates queries with character set introducers.
Problem: logging of utf8-incompatible binary strings didn't work Fix: hex-encoding of incompatible sequences.
-rw-r--r--mysql-test/r/log_tables.result11
-rw-r--r--mysql-test/t/log_tables.test10
-rw-r--r--sql/field.cc11
-rw-r--r--sql/field.h2
-rw-r--r--sql/log.cc1
-rw-r--r--sql/sql_string.cc62
-rw-r--r--sql/sql_string.h3
7 files changed, 100 insertions, 0 deletions
diff --git a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result
index 0a7634df85a..2a4cee9fbbc 100644
--- a/mysql-test/r/log_tables.result
+++ b/mysql-test/r/log_tables.result
@@ -107,6 +107,17 @@ Database Table In_use Name_locked
SET GLOBAL GENERAL_LOG=ON;
SET GLOBAL SLOW_QUERY_LOG=ON;
truncate table mysql.general_log;
+set names binary;
+select _koi8r'ΤΕΣΤ' as test;
+test
+ΤΕΣΤ
+select * from mysql.general_log;
+event_time user_host thread_id server_id command_type argument
+TIMESTAMP USER_HOST THREAD_ID 1 Query set names binary
+TIMESTAMP USER_HOST THREAD_ID 1 Query select _koi8r'\xD4\xC5\xD3\xD4' as test
+TIMESTAMP USER_HOST THREAD_ID 1 Query select * from mysql.general_log
+set names utf8;
+truncate table mysql.general_log;
set names utf8;
create table bug16905 (s char(15) character set utf8 default 'пусто');
insert into bug16905 values ('Π½ΠΎΠ²ΠΎΠ΅');
diff --git a/mysql-test/t/log_tables.test b/mysql-test/t/log_tables.test
index 0c986c6d63a..3047d16d3b6 100644
--- a/mysql-test/t/log_tables.test
+++ b/mysql-test/t/log_tables.test
@@ -131,6 +131,16 @@ SET GLOBAL GENERAL_LOG=ON;
SET GLOBAL SLOW_QUERY_LOG=ON;
#
+# Bug#23924 general_log truncates queries with character set introducers.
+#
+truncate table mysql.general_log;
+set names binary;
+select _koi8r'ΤΕΣΤ' as test;
+--replace_column 1 TIMESTAMP 2 USER_HOST 3 THREAD_ID
+select * from mysql.general_log;
+set names utf8;
+
+#
# Bug #16905 Log tables: unicode statements are logged incorrectly
#
diff --git a/sql/field.cc b/sql/field.cc
index 88fac96df89..fb14b4d5c77 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -7644,6 +7644,17 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
if (value.alloc(new_length))
goto oom_error;
+
+ if (f_is_hex_escape(flags))
+ {
+ copy_length= my_copy_with_hex_escaping(field_charset,
+ (char*) value.ptr(), new_length,
+ from, length);
+ Field_blob::store_length(copy_length);
+ tmp= value.ptr();
+ bmove(ptr + packlength, (uchar*) &tmp, sizeof(char*));
+ return 0;
+ }
/*
"length" is OK as "nchars" argument to well_formed_copy_nchars as this
is never used to limit the length of the data. The cut of long data
diff --git a/sql/field.h b/sql/field.h
index 38a0b1d5bbd..2e8a27e579a 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -2069,6 +2069,7 @@ int set_field_to_null_with_conversions(Field *field, bool no_conversions);
#define FIELDFLAG_NO_DEFAULT 16384 /* sql */
#define FIELDFLAG_SUM ((uint) 32768)// predit: +#fieldflag
#define FIELDFLAG_MAYBE_NULL ((uint) 32768)// sql
+#define FIELDFLAG_HEX_ESCAPE ((uint) 0x10000)
#define FIELDFLAG_PACK_SHIFT 3
#define FIELDFLAG_DEC_SHIFT 8
#define FIELDFLAG_MAX_DEC 31
@@ -2094,3 +2095,4 @@ int set_field_to_null_with_conversions(Field *field, bool no_conversions);
#define f_maybe_null(x) (x & FIELDFLAG_MAYBE_NULL)
#define f_no_default(x) (x & FIELDFLAG_NO_DEFAULT)
#define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR)
+#define f_is_hex_escape(x) ((x) & FIELDFLAG_HEX_ESCAPE)
diff --git a/sql/log.cc b/sql/log.cc
index 9b5b2ae5a6c..328aaa45f3f 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -418,6 +418,7 @@ bool Log_to_csv_event_handler::
A positive return value in store() means truncation.
Still logging a message in the log in this case.
*/
+ table->field[5]->flags|= FIELDFLAG_HEX_ESCAPE;
if (table->field[5]->store(sql_text, sql_text_len, client_cs) < 0)
goto err;
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 7fa3786c382..34b310931d6 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -840,6 +840,68 @@ outp:
}
+/**
+ Copy string with HEX-encoding of "bad" characters.
+
+ @details This functions copies the string pointed by "src"
+ to the string pointed by "dst". Not more than "srclen" bytes
+ are read from "src". Any sequences of bytes representing
+ a not-well-formed substring (according to cs) are hex-encoded,
+ and all well-formed substrings (according to cs) are copied as is.
+ Not more than "dstlen" bytes are written to "dst". The number
+ of bytes written to "dst" is returned.
+
+ @param cs character set pointer of the destination string
+ @param[out] dst destination string
+ @param dstlen size of dst
+ @param src source string
+ @param srclen length of src
+
+ @retval result length
+*/
+
+size_t
+my_copy_with_hex_escaping(CHARSET_INFO *cs,
+ char *dst, size_t dstlen,
+ const char *src, size_t srclen)
+{
+ const char *srcend= src + srclen;
+ char *dst0= dst;
+
+ for ( ; src < srcend ; )
+ {
+ size_t chlen;
+ if ((chlen= my_ismbchar(cs, src, srcend)))
+ {
+ if (dstlen < chlen)
+ break; /* purecov: inspected */
+ memcpy(dst, src, chlen);
+ src+= chlen;
+ dst+= chlen;
+ dstlen-= chlen;
+ }
+ else if (*src & 0x80)
+ {
+ if (dstlen < 4)
+ break; /* purecov: inspected */
+ *dst++= '\\';
+ *dst++= 'x';
+ *dst++= _dig_vec_upper[((unsigned char) *src) >> 4];
+ *dst++= _dig_vec_upper[((unsigned char) *src) & 15];
+ src++;
+ dstlen-= 4;
+ }
+ else
+ {
+ if (dstlen < 1)
+ break; /* purecov: inspected */
+ *dst++= *src++;
+ dstlen--;
+ }
+ }
+ return dst - dst0;
+}
+
/*
copy a string,
with optional character set conversion,
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 128ed749b5f..b4d76a1779a 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -37,6 +37,9 @@ uint32 well_formed_copy_nchars(CHARSET_INFO *to_cs,
const char **well_formed_error_pos,
const char **cannot_convert_error_pos,
const char **from_end_pos);
+size_t my_copy_with_hex_escaping(CHARSET_INFO *cs,
+ char *dst, size_t dstlen,
+ const char *src, size_t srclen);
class String
{