Commit e0fc25e9 authored by unknown's avatar unknown

Bug#23619 Incorrectly escaped multibyte characters in binary log break replication

Problem: when embedding a character string with introducer with charset X
into a SQL query which is generally in character set Y, the string constants
were escaped according to their own character set (i.e.X), then after reading
such a "mixed" query from binlog, the string constants were unescaped
using character set of the query (i.e. Y), instead of X, which gave wrong
results or even syntax errors with tricky charsets (e.g. sjis)
Fix: when embedding a string constant of charset X into a query of charset Y,
the string constant is now escaped according to character Y, instead of
its own character set X.


mysql-test/r/ctype_cp932_binlog.result:
  Fixing test results.
sql/log_event.cc:
  Using character set "csinfo" instead of the string character set.
sql/sp_head.cc:
  - adding "thd" argument to sp_get_item_value()
    to have access to thd->variables.character_set_client
  - using character_set_client for escaping, instead of
    the string character set
mysql-test/r/rpl_charset_sjis.result:
  Adding test case
mysql-test/t/rpl_charset_sjis.test:
  Adding test case
parent a39b8a06
...@@ -41,6 +41,6 @@ IN ind DECIMAL(10,2)) ...@@ -41,6 +41,6 @@ IN ind DECIMAL(10,2))
BEGIN BEGIN
INSERT INTO t4 VALUES (ins1, ins2, ind); INSERT INTO t4 VALUES (ins1, ins2, ind);
END END
master-bin.000001 801 Query 1 1006 use `test`; INSERT INTO t4 VALUES ( NAME_CONST('ins1',_latin1'Foo\'s a Bar'), NAME_CONST('ins2',_cp932 0xED40ED41ED42), NAME_CONST('ind',47.93)) master-bin.000001 801 Query 1 1017 use `test`; INSERT INTO t4 VALUES ( NAME_CONST('ins1',_latin1 0x466F6F2773206120426172), NAME_CONST('ins2',_cp932 0xED40ED41ED42), NAME_CONST('ind',47.93))
master-bin.000001 1006 Query 1 1092 use `test`; DROP PROCEDURE bug18293 master-bin.000001 1017 Query 1 1103 use `test`; DROP PROCEDURE bug18293
master-bin.000001 1092 Query 1 1168 use `test`; DROP TABLE t4 master-bin.000001 1103 Query 1 1179 use `test`; DROP TABLE t4
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
drop table if exists t1;
drop procedure if exists p1;
create table t1 (a varchar(255) character set sjis);
create procedure p1 (in a varchar(255) character set sjis) insert into t1 values (a);
SET NAMES binary;
CALL p1 ('–\\');
select "--- on master ---";
--- on master ---
--- on master ---
select hex(a) from t1 ;
hex(a)
965C
select "--- on slave ---";
--- on slave ---
--- on slave ---
select hex(a) from t1;
hex(a)
965C
drop table t1;
drop procedure p1;
source include/have_sjis.inc;
source include/master-slave.inc;
--disable_warnings
drop table if exists t1;
drop procedure if exists p1;
--enable_warnings
create table t1 (a varchar(255) character set sjis);
create procedure p1 (in a varchar(255) character set sjis) insert into t1 values (a);
SET NAMES binary;
CALL p1 ('\\');
select "--- on master ---";
select hex(a) from t1 ;
sync_slave_with_master;
connection slave;
select "--- on slave ---";
select hex(a) from t1;
connection master;
drop table t1;
drop procedure p1;
sync_slave_with_master;
connection master;
# End of 5.0 tests
...@@ -261,7 +261,7 @@ append_query_string(CHARSET_INFO *csinfo, ...@@ -261,7 +261,7 @@ append_query_string(CHARSET_INFO *csinfo,
else else
{ {
*ptr++= '\''; *ptr++= '\'';
ptr+= escape_string_for_mysql(from->charset(), ptr, 0, ptr+= escape_string_for_mysql(csinfo, ptr, 0,
from->ptr(), from->length()); from->ptr(), from->length());
*ptr++='\''; *ptr++='\'';
} }
......
...@@ -93,7 +93,7 @@ sp_map_item_type(enum enum_field_types type) ...@@ -93,7 +93,7 @@ sp_map_item_type(enum enum_field_types type)
*/ */
static String * static String *
sp_get_item_value(Item *item, String *str) sp_get_item_value(THD *thd, Item *item, String *str)
{ {
Item_result result_type= item->result_type(); Item_result result_type= item->result_type();
...@@ -113,15 +113,16 @@ sp_get_item_value(Item *item, String *str) ...@@ -113,15 +113,16 @@ sp_get_item_value(Item *item, String *str)
{ {
char buf_holder[STRING_BUFFER_USUAL_SIZE]; char buf_holder[STRING_BUFFER_USUAL_SIZE];
String buf(buf_holder, sizeof(buf_holder), result->charset()); String buf(buf_holder, sizeof(buf_holder), result->charset());
CHARSET_INFO *cs= thd->variables.character_set_client;
/* We must reset length of the buffer, because of String specificity. */ /* We must reset length of the buffer, because of String specificity. */
buf.length(0); buf.length(0);
buf.append('_'); buf.append('_');
buf.append(result->charset()->csname); buf.append(result->charset()->csname);
if (result->charset()->escape_with_backslash_is_dangerous) if (cs->escape_with_backslash_is_dangerous)
buf.append(' '); buf.append(' ');
append_query_string(result->charset(), result, &buf); append_query_string(cs, result, &buf);
str->copy(buf); str->copy(buf);
return str; return str;
...@@ -862,7 +863,7 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) ...@@ -862,7 +863,7 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
val= (*splocal)->this_item(); val= (*splocal)->this_item();
DBUG_PRINT("info", ("print %p", val)); DBUG_PRINT("info", ("print %p", val));
str_value= sp_get_item_value(val, &str_value_holder); str_value= sp_get_item_value(thd, val, &str_value_holder);
if (str_value) if (str_value)
res|= qbuf.append(*str_value); res|= qbuf.append(*str_value);
else else
...@@ -1456,7 +1457,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, ...@@ -1456,7 +1457,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
if (arg_no) if (arg_no)
binlog_buf.append(','); binlog_buf.append(',');
str_value= sp_get_item_value(nctx->get_item(arg_no), str_value= sp_get_item_value(thd, nctx->get_item(arg_no),
&str_value_holder); &str_value_holder);
if (str_value) if (str_value)
......
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