Commit 1ed34fed authored by unknown's avatar unknown

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.


mysql-test/r/log_tables.result:
  Adding test
mysql-test/t/log_tables.test:
  Adding test
sql/field.cc:
  Copying with hex escaping
sql/field.h:
  New field flag
sql/log.cc:
  Marking the column "general_log.argument" as hex-escaping field.
sql/sql_string.cc:
  New function to copy strings with hex-encoding of incompatible characters.
sql/sql_string.h:
  Prototype for the new function
parent 2583c281
......@@ -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 ('новое');
......
......@@ -130,6 +130,16 @@ show open tables;
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
#
......
......@@ -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
......
......@@ -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)
......@@ -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;
......
......@@ -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,
......
......@@ -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
{
......
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