From 61aa2a72f85cb6b63b090affb0fd4b5db4cddb31 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 30 Jan 2006 14:33:15 +0200 Subject: [PATCH 1/5] BUG#13227 test case to examine that local slave's triggers that use select work ok even if they fire for replicated update. mysql-test/r/rpl_trigger.result: results are changed to account 13227 addon. mysql-test/t/rpl_trigger.test: BUG#13227 test case is added. --- mysql-test/r/rpl_trigger.result | 721 ++++++++++++++++++++++++++++++++ mysql-test/t/rpl_trigger.test | 98 ++++- 2 files changed, 818 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/rpl_trigger.result b/mysql-test/r/rpl_trigger.result index 7613f2547f0..ccd880c1e07 100644 --- a/mysql-test/r/rpl_trigger.result +++ b/mysql-test/r/rpl_trigger.result @@ -134,3 +134,724 @@ insert into test.t1 values (1); use test; drop table t1,t2; drop database other; +test case for BUG#13227 +------------------- +10 +------------------- +drop table if exists t110; +drop table if exists t210,t310; +create table t110 (f1 int) /* 2 replicate */; +insert into t110 values (-5); +insert into t110 values (-4); +insert into t110 values (-3); +insert into t110 values (-2); +insert into t110 values (-1); +select * from t110; +f1 +-5 +-4 +-3 +-2 +-1 +create trigger trg110 before update on t110 /* slave local */ +for each row +begin +DECLARE r integer; +SELECT f2 INTO r FROM t210 where f1=NEW.f1; +INSERT INTO t310 values (r); +end| +create table t210 (f1 int, f2 int) /* slave local */; +create table t310 (f3 int) /* slave local */; +insert into t210 values (5, 5*100); +insert into t210 values (4, 4*100); +insert into t210 values (3, 3*100); +insert into t210 values (2, 2*100); +insert into t210 values (1, 1*100); +select * from t210; +f1 f2 +5 500 +4 400 +3 300 +2 200 +1 100 +UPDATE t110 SET f1=5 where f1=-5; +SELECT * from t110 /* must be f1 5, 1 - 5 2 - 5 ... -1 */; +f1 +5 +-4 +-3 +-2 +-1 +SELECT * from t310 /* must be f3 5*100 */; +f3 +500 +UPDATE t110 SET f1=5 where f1=-5; +UPDATE t110 SET f1=4 where f1=-4; +UPDATE t110 SET f1=3 where f1=-3; +UPDATE t110 SET f1=2 where f1=-2; +UPDATE t110 SET f1=1 where f1=-1; +SELECT * from t110 /* must be f1 5 ... 1 */; +f1 +5 +4 +3 +2 +1 +SELECT * from t310 /* must be f3 5 * 100 ... 100 */; +f3 +500 +400 +300 +200 +100 +drop trigger trg110; +drop table t210,t310; +drop table t110; +------------------- +9 +------------------- +drop table if exists t19; +drop table if exists t29,t39; +create table t19 (f1 int) /* 2 replicate */; +insert into t19 values (-5); +insert into t19 values (-4); +insert into t19 values (-3); +insert into t19 values (-2); +insert into t19 values (-1); +select * from t19; +f1 +-5 +-4 +-3 +-2 +-1 +create trigger trg19 before update on t19 /* slave local */ +for each row +begin +DECLARE r integer; +SELECT f2 INTO r FROM t29 where f1=NEW.f1; +INSERT INTO t39 values (r); +end| +create table t29 (f1 int, f2 int) /* slave local */; +create table t39 (f3 int) /* slave local */; +insert into t29 values (5, 5*100); +insert into t29 values (4, 4*100); +insert into t29 values (3, 3*100); +insert into t29 values (2, 2*100); +insert into t29 values (1, 1*100); +select * from t29; +f1 f2 +5 500 +4 400 +3 300 +2 200 +1 100 +UPDATE t19 SET f1=5 where f1=-5; +SELECT * from t19 /* must be f1 5, 1 - 5 2 - 5 ... -1 */; +f1 +5 +-4 +-3 +-2 +-1 +SELECT * from t39 /* must be f3 5*100 */; +f3 +500 +UPDATE t19 SET f1=5 where f1=-5; +UPDATE t19 SET f1=4 where f1=-4; +UPDATE t19 SET f1=3 where f1=-3; +UPDATE t19 SET f1=2 where f1=-2; +UPDATE t19 SET f1=1 where f1=-1; +SELECT * from t19 /* must be f1 5 ... 1 */; +f1 +5 +4 +3 +2 +1 +SELECT * from t39 /* must be f3 5 * 100 ... 100 */; +f3 +500 +400 +300 +200 +100 +drop trigger trg19; +drop table t29,t39; +drop table t19; +------------------- +8 +------------------- +drop table if exists t18; +drop table if exists t28,t38; +create table t18 (f1 int) /* 2 replicate */; +insert into t18 values (-5); +insert into t18 values (-4); +insert into t18 values (-3); +insert into t18 values (-2); +insert into t18 values (-1); +select * from t18; +f1 +-5 +-4 +-3 +-2 +-1 +create trigger trg18 before update on t18 /* slave local */ +for each row +begin +DECLARE r integer; +SELECT f2 INTO r FROM t28 where f1=NEW.f1; +INSERT INTO t38 values (r); +end| +create table t28 (f1 int, f2 int) /* slave local */; +create table t38 (f3 int) /* slave local */; +insert into t28 values (5, 5*100); +insert into t28 values (4, 4*100); +insert into t28 values (3, 3*100); +insert into t28 values (2, 2*100); +insert into t28 values (1, 1*100); +select * from t28; +f1 f2 +5 500 +4 400 +3 300 +2 200 +1 100 +UPDATE t18 SET f1=5 where f1=-5; +SELECT * from t18 /* must be f1 5, 1 - 5 2 - 5 ... -1 */; +f1 +5 +-4 +-3 +-2 +-1 +SELECT * from t38 /* must be f3 5*100 */; +f3 +500 +UPDATE t18 SET f1=5 where f1=-5; +UPDATE t18 SET f1=4 where f1=-4; +UPDATE t18 SET f1=3 where f1=-3; +UPDATE t18 SET f1=2 where f1=-2; +UPDATE t18 SET f1=1 where f1=-1; +SELECT * from t18 /* must be f1 5 ... 1 */; +f1 +5 +4 +3 +2 +1 +SELECT * from t38 /* must be f3 5 * 100 ... 100 */; +f3 +500 +400 +300 +200 +100 +drop trigger trg18; +drop table t28,t38; +drop table t18; +------------------- +7 +------------------- +drop table if exists t17; +drop table if exists t27,t37; +create table t17 (f1 int) /* 2 replicate */; +insert into t17 values (-5); +insert into t17 values (-4); +insert into t17 values (-3); +insert into t17 values (-2); +insert into t17 values (-1); +select * from t17; +f1 +-5 +-4 +-3 +-2 +-1 +create trigger trg17 before update on t17 /* slave local */ +for each row +begin +DECLARE r integer; +SELECT f2 INTO r FROM t27 where f1=NEW.f1; +INSERT INTO t37 values (r); +end| +create table t27 (f1 int, f2 int) /* slave local */; +create table t37 (f3 int) /* slave local */; +insert into t27 values (5, 5*100); +insert into t27 values (4, 4*100); +insert into t27 values (3, 3*100); +insert into t27 values (2, 2*100); +insert into t27 values (1, 1*100); +select * from t27; +f1 f2 +5 500 +4 400 +3 300 +2 200 +1 100 +UPDATE t17 SET f1=5 where f1=-5; +SELECT * from t17 /* must be f1 5, 1 - 5 2 - 5 ... -1 */; +f1 +5 +-4 +-3 +-2 +-1 +SELECT * from t37 /* must be f3 5*100 */; +f3 +500 +UPDATE t17 SET f1=5 where f1=-5; +UPDATE t17 SET f1=4 where f1=-4; +UPDATE t17 SET f1=3 where f1=-3; +UPDATE t17 SET f1=2 where f1=-2; +UPDATE t17 SET f1=1 where f1=-1; +SELECT * from t17 /* must be f1 5 ... 1 */; +f1 +5 +4 +3 +2 +1 +SELECT * from t37 /* must be f3 5 * 100 ... 100 */; +f3 +500 +400 +300 +200 +100 +drop trigger trg17; +drop table t27,t37; +drop table t17; +------------------- +6 +------------------- +drop table if exists t16; +drop table if exists t26,t36; +create table t16 (f1 int) /* 2 replicate */; +insert into t16 values (-5); +insert into t16 values (-4); +insert into t16 values (-3); +insert into t16 values (-2); +insert into t16 values (-1); +select * from t16; +f1 +-5 +-4 +-3 +-2 +-1 +create trigger trg16 before update on t16 /* slave local */ +for each row +begin +DECLARE r integer; +SELECT f2 INTO r FROM t26 where f1=NEW.f1; +INSERT INTO t36 values (r); +end| +create table t26 (f1 int, f2 int) /* slave local */; +create table t36 (f3 int) /* slave local */; +insert into t26 values (5, 5*100); +insert into t26 values (4, 4*100); +insert into t26 values (3, 3*100); +insert into t26 values (2, 2*100); +insert into t26 values (1, 1*100); +select * from t26; +f1 f2 +5 500 +4 400 +3 300 +2 200 +1 100 +UPDATE t16 SET f1=5 where f1=-5; +SELECT * from t16 /* must be f1 5, 1 - 5 2 - 5 ... -1 */; +f1 +5 +-4 +-3 +-2 +-1 +SELECT * from t36 /* must be f3 5*100 */; +f3 +500 +UPDATE t16 SET f1=5 where f1=-5; +UPDATE t16 SET f1=4 where f1=-4; +UPDATE t16 SET f1=3 where f1=-3; +UPDATE t16 SET f1=2 where f1=-2; +UPDATE t16 SET f1=1 where f1=-1; +SELECT * from t16 /* must be f1 5 ... 1 */; +f1 +5 +4 +3 +2 +1 +SELECT * from t36 /* must be f3 5 * 100 ... 100 */; +f3 +500 +400 +300 +200 +100 +drop trigger trg16; +drop table t26,t36; +drop table t16; +------------------- +5 +------------------- +drop table if exists t15; +drop table if exists t25,t35; +create table t15 (f1 int) /* 2 replicate */; +insert into t15 values (-5); +insert into t15 values (-4); +insert into t15 values (-3); +insert into t15 values (-2); +insert into t15 values (-1); +select * from t15; +f1 +-5 +-4 +-3 +-2 +-1 +create trigger trg15 before update on t15 /* slave local */ +for each row +begin +DECLARE r integer; +SELECT f2 INTO r FROM t25 where f1=NEW.f1; +INSERT INTO t35 values (r); +end| +create table t25 (f1 int, f2 int) /* slave local */; +create table t35 (f3 int) /* slave local */; +insert into t25 values (5, 5*100); +insert into t25 values (4, 4*100); +insert into t25 values (3, 3*100); +insert into t25 values (2, 2*100); +insert into t25 values (1, 1*100); +select * from t25; +f1 f2 +5 500 +4 400 +3 300 +2 200 +1 100 +UPDATE t15 SET f1=5 where f1=-5; +SELECT * from t15 /* must be f1 5, 1 - 5 2 - 5 ... -1 */; +f1 +5 +-4 +-3 +-2 +-1 +SELECT * from t35 /* must be f3 5*100 */; +f3 +500 +UPDATE t15 SET f1=5 where f1=-5; +UPDATE t15 SET f1=4 where f1=-4; +UPDATE t15 SET f1=3 where f1=-3; +UPDATE t15 SET f1=2 where f1=-2; +UPDATE t15 SET f1=1 where f1=-1; +SELECT * from t15 /* must be f1 5 ... 1 */; +f1 +5 +4 +3 +2 +1 +SELECT * from t35 /* must be f3 5 * 100 ... 100 */; +f3 +500 +400 +300 +200 +100 +drop trigger trg15; +drop table t25,t35; +drop table t15; +------------------- +4 +------------------- +drop table if exists t14; +drop table if exists t24,t34; +create table t14 (f1 int) /* 2 replicate */; +insert into t14 values (-5); +insert into t14 values (-4); +insert into t14 values (-3); +insert into t14 values (-2); +insert into t14 values (-1); +select * from t14; +f1 +-5 +-4 +-3 +-2 +-1 +create trigger trg14 before update on t14 /* slave local */ +for each row +begin +DECLARE r integer; +SELECT f2 INTO r FROM t24 where f1=NEW.f1; +INSERT INTO t34 values (r); +end| +create table t24 (f1 int, f2 int) /* slave local */; +create table t34 (f3 int) /* slave local */; +insert into t24 values (5, 5*100); +insert into t24 values (4, 4*100); +insert into t24 values (3, 3*100); +insert into t24 values (2, 2*100); +insert into t24 values (1, 1*100); +select * from t24; +f1 f2 +5 500 +4 400 +3 300 +2 200 +1 100 +UPDATE t14 SET f1=5 where f1=-5; +SELECT * from t14 /* must be f1 5, 1 - 5 2 - 5 ... -1 */; +f1 +5 +-4 +-3 +-2 +-1 +SELECT * from t34 /* must be f3 5*100 */; +f3 +500 +UPDATE t14 SET f1=5 where f1=-5; +UPDATE t14 SET f1=4 where f1=-4; +UPDATE t14 SET f1=3 where f1=-3; +UPDATE t14 SET f1=2 where f1=-2; +UPDATE t14 SET f1=1 where f1=-1; +SELECT * from t14 /* must be f1 5 ... 1 */; +f1 +5 +4 +3 +2 +1 +SELECT * from t34 /* must be f3 5 * 100 ... 100 */; +f3 +500 +400 +300 +200 +100 +drop trigger trg14; +drop table t24,t34; +drop table t14; +------------------- +3 +------------------- +drop table if exists t13; +drop table if exists t23,t33; +create table t13 (f1 int) /* 2 replicate */; +insert into t13 values (-5); +insert into t13 values (-4); +insert into t13 values (-3); +insert into t13 values (-2); +insert into t13 values (-1); +select * from t13; +f1 +-5 +-4 +-3 +-2 +-1 +create trigger trg13 before update on t13 /* slave local */ +for each row +begin +DECLARE r integer; +SELECT f2 INTO r FROM t23 where f1=NEW.f1; +INSERT INTO t33 values (r); +end| +create table t23 (f1 int, f2 int) /* slave local */; +create table t33 (f3 int) /* slave local */; +insert into t23 values (5, 5*100); +insert into t23 values (4, 4*100); +insert into t23 values (3, 3*100); +insert into t23 values (2, 2*100); +insert into t23 values (1, 1*100); +select * from t23; +f1 f2 +5 500 +4 400 +3 300 +2 200 +1 100 +UPDATE t13 SET f1=5 where f1=-5; +SELECT * from t13 /* must be f1 5, 1 - 5 2 - 5 ... -1 */; +f1 +5 +-4 +-3 +-2 +-1 +SELECT * from t33 /* must be f3 5*100 */; +f3 +500 +UPDATE t13 SET f1=5 where f1=-5; +UPDATE t13 SET f1=4 where f1=-4; +UPDATE t13 SET f1=3 where f1=-3; +UPDATE t13 SET f1=2 where f1=-2; +UPDATE t13 SET f1=1 where f1=-1; +SELECT * from t13 /* must be f1 5 ... 1 */; +f1 +5 +4 +3 +2 +1 +SELECT * from t33 /* must be f3 5 * 100 ... 100 */; +f3 +500 +400 +300 +200 +100 +drop trigger trg13; +drop table t23,t33; +drop table t13; +------------------- +2 +------------------- +drop table if exists t12; +drop table if exists t22,t32; +create table t12 (f1 int) /* 2 replicate */; +insert into t12 values (-5); +insert into t12 values (-4); +insert into t12 values (-3); +insert into t12 values (-2); +insert into t12 values (-1); +select * from t12; +f1 +-5 +-4 +-3 +-2 +-1 +create trigger trg12 before update on t12 /* slave local */ +for each row +begin +DECLARE r integer; +SELECT f2 INTO r FROM t22 where f1=NEW.f1; +INSERT INTO t32 values (r); +end| +create table t22 (f1 int, f2 int) /* slave local */; +create table t32 (f3 int) /* slave local */; +insert into t22 values (5, 5*100); +insert into t22 values (4, 4*100); +insert into t22 values (3, 3*100); +insert into t22 values (2, 2*100); +insert into t22 values (1, 1*100); +select * from t22; +f1 f2 +5 500 +4 400 +3 300 +2 200 +1 100 +UPDATE t12 SET f1=5 where f1=-5; +SELECT * from t12 /* must be f1 5, 1 - 5 2 - 5 ... -1 */; +f1 +5 +-4 +-3 +-2 +-1 +SELECT * from t32 /* must be f3 5*100 */; +f3 +500 +UPDATE t12 SET f1=5 where f1=-5; +UPDATE t12 SET f1=4 where f1=-4; +UPDATE t12 SET f1=3 where f1=-3; +UPDATE t12 SET f1=2 where f1=-2; +UPDATE t12 SET f1=1 where f1=-1; +SELECT * from t12 /* must be f1 5 ... 1 */; +f1 +5 +4 +3 +2 +1 +SELECT * from t32 /* must be f3 5 * 100 ... 100 */; +f3 +500 +400 +300 +200 +100 +drop trigger trg12; +drop table t22,t32; +drop table t12; +------------------- +1 +------------------- +drop table if exists t11; +drop table if exists t21,t31; +create table t11 (f1 int) /* 2 replicate */; +insert into t11 values (-5); +insert into t11 values (-4); +insert into t11 values (-3); +insert into t11 values (-2); +insert into t11 values (-1); +select * from t11; +f1 +-5 +-4 +-3 +-2 +-1 +create trigger trg11 before update on t11 /* slave local */ +for each row +begin +DECLARE r integer; +SELECT f2 INTO r FROM t21 where f1=NEW.f1; +INSERT INTO t31 values (r); +end| +create table t21 (f1 int, f2 int) /* slave local */; +create table t31 (f3 int) /* slave local */; +insert into t21 values (5, 5*100); +insert into t21 values (4, 4*100); +insert into t21 values (3, 3*100); +insert into t21 values (2, 2*100); +insert into t21 values (1, 1*100); +select * from t21; +f1 f2 +5 500 +4 400 +3 300 +2 200 +1 100 +UPDATE t11 SET f1=5 where f1=-5; +SELECT * from t11 /* must be f1 5, 1 - 5 2 - 5 ... -1 */; +f1 +5 +-4 +-3 +-2 +-1 +SELECT * from t31 /* must be f3 5*100 */; +f3 +500 +UPDATE t11 SET f1=5 where f1=-5; +UPDATE t11 SET f1=4 where f1=-4; +UPDATE t11 SET f1=3 where f1=-3; +UPDATE t11 SET f1=2 where f1=-2; +UPDATE t11 SET f1=1 where f1=-1; +SELECT * from t11 /* must be f1 5 ... 1 */; +f1 +5 +4 +3 +2 +1 +SELECT * from t31 /* must be f3 5 * 100 ... 100 */; +f3 +500 +400 +300 +200 +100 +drop trigger trg11; +drop table t21,t31; +drop table t11; diff --git a/mysql-test/t/rpl_trigger.test b/mysql-test/t/rpl_trigger.test index fa6054372c7..f3db1cb5841 100644 --- a/mysql-test/t/rpl_trigger.test +++ b/mysql-test/t/rpl_trigger.test @@ -163,7 +163,103 @@ drop table t1,t2; drop database other; # -# End of test +# Test specific triggers including SELECT into var with replication +# BUG#13227: +# slave performs an update to the replicatable table, t1, +# and modifies its local data, t3, by mean of its local trigger that uses +# another local table t2. +# Expected values are commented into queries. +# +# Body of the test executes in a loop since the problem occurred randomly. +# + +let $max_rows=5; +let $rnd=10; + +--echo test case for BUG#13227 +while ($rnd) +{ + --echo ------------------- + echo $rnd; + --echo ------------------- + +### SETUP + +--disable_warnings + connection master; + eval drop table if exists t1$rnd; + connection slave; + eval drop table if exists t2$rnd,t3$rnd; +--enable_warnings + + connection master; + eval create table t1$rnd (f1 int) /* 2 replicate */; + let $i=$max_rows; + while ($i) + { + eval insert into t1$rnd values (-$i); + dec $i; + } + + sync_slave_with_master; +#connection slave; + eval select * from t1$rnd; + delimiter |; + eval create trigger trg1$rnd before update on t1$rnd /* slave local */ + for each row + begin + DECLARE r integer; + SELECT f2 INTO r FROM t2$rnd where f1=NEW.f1; + INSERT INTO t3$rnd values (r); + end| + delimiter ;| + eval create table t2$rnd (f1 int, f2 int) /* slave local */; + eval create table t3$rnd (f3 int) /* slave local */; + let $i=$max_rows; + while ($i) + { + eval insert into t2$rnd values ($i, $i*100); + dec $i; + } + +### Test + +#connection slave; + +# trigger works as specified when updates from slave + eval select * from t2$rnd; + eval UPDATE t1$rnd SET f1=$max_rows where f1=-$max_rows; + eval SELECT * from t1$rnd /* must be f1 $max_rows, 1 - $max_rows 2 - $max_rows ... -1 */; + eval SELECT * from t3$rnd /* must be f3 $max_rows*100 */; + + connection master; + let $i=$max_rows; + while ($i) + { + eval UPDATE t1$rnd SET f1=$i where f1=-$i; + dec $i; + } + + sync_slave_with_master; +#connection slave; + eval SELECT * from t1$rnd /* must be f1 $max_rows ... 1 */; + eval SELECT * from t3$rnd /* must be f3 $max_rows * 100 ... 100 */; + +### CLEANUP +#connection slave; + eval drop trigger trg1$rnd; + eval drop table t2$rnd,t3$rnd; + + connection master; + eval drop table t1$rnd; + + dec $rnd; +} + + + +# +# End of tests # save_master_pos; connection slave; From 4e9b14879bed3f15eff48bd4e45945b20c793f15 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 8 Feb 2006 15:12:48 +0300 Subject: [PATCH 2/5] Fixed bug#16752 Binary table files created in mysqld v4.1 caused buffer overrun and possibly server crash in mysqld v5.0. Reported MyISAM table was created in mysqld 4.1 and contains varchar field. When binary files of that table was moved to 5.0, mysqld treats that varchar field as a string field. In order to make grouping server calculates group buffer, and because that field is string server assumes it has fixed length and doesn't add space for length, but later that field is converted to varchar field. Due to this, when field values were actually copied, additional space for length bytes is taken and buffer overrun occurs, which may lead to server crash. The calc_group_buffer() function now reserves additional space for length bytes for VAR_STRING fields, like for VARCHAR fields. sql/sql_select.cc: Fixed bug#16752 Binary table files created in mysqld v4.1 caused buffer overrun and possibly server crash in mysqld v5.0. The calc_group_buffer() function now reserves additional space for length bytes for VAR_STRING fields, like for VARCHAR fields. --- sql/sql_select.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 63d46934555..aa2228ec0d8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12717,11 +12717,12 @@ calc_group_buffer(JOIN *join,ORDER *group) Field *field= group_item->get_tmp_table_field(); if (field) { - if (field->type() == FIELD_TYPE_BLOB) + enum_field_types type; + if ((type= field->type()) == FIELD_TYPE_BLOB) key_length+=MAX_BLOB_WIDTH; // Can't be used as a key - else if (field->type() == MYSQL_TYPE_VARCHAR) + else if (type == MYSQL_TYPE_VARCHAR || type == MYSQL_TYPE_VAR_STRING) key_length+= field->field_length + HA_KEY_BLOB_LENGTH; - else if (field->type() == FIELD_TYPE_BIT) + else if (type == FIELD_TYPE_BIT) { /* Bit is usually stored as a longlong key for group fields */ key_length+= 8; // Big enough From e025e47a76cb43cad54ff5bdc81a6717a8f3497f Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 16:23:09 +0200 Subject: [PATCH 3/5] BUG#16217 forced to introduce a separate mysql client command to adopt its internal charset to one associated with currently being handled query. To note such a query can come from interactive client either. There was a discussion within replication team and Monty who's suggestion won. It avoids straightforward parsing of all `set' queries that could affect client side character set. According to the idea, mysql client does not parse `set' queries but rather cares of `charset new_cs_name' command. This command is generated by mysqlbinlog in form of exclaiming comment (Lars' suggestion) so that enlightened clients like `mysql' knows what to do with it. Interactive human can switch between many multi-byte charsets during the session providing the command explicitly. To note that setting new internal mysql's charset does not trigger sending any `SET' sql statement to the server. client/mysql.cc: BUG#16217 revealed the problem of switching between charsets in mysql client. Such switching is necessary in a case when being scanned query consists of multi-byte chars and internal charset was initialized differently. mysql finds `/' escape and misiterprete it while in fact one could be a part of a multi-byte symbol like the bug page reported. This patch extends mysql `charset' command, '\C' shortcut. mysql-test/r/ctype_ucs_binlog.result: comment line generated by mysqlbinlog for processing of logs with multi-byte chars. mysql-test/r/mysql.result: results are altered due to #16217 mysql-test/r/mysqlbinlog.result: Results are altered due to #16217 mysql-test/r/mysqlbinlog2.result: commeted command for mysql client due to multi-byte binlog mysql-test/r/rpl_charset.result: commented command for mysql due to multi-byte binlogs mysql-test/r/rpl_timezone.result: commented command for mysql client due to multi-byte binlogs mysql-test/r/user_var-binlog.result: commented command for mysql client due to multi-byte binlogs mysql-test/t/mysql.test: Main test for mysql client is extended to check `charset' command. mysql-test/t/mysqlbinlog.test: Checking how /*! \C cs_name */ are added to the output of mysqlbinlog. The exclaiming comment is for further processing by mysql client. The added part mimics the failure to recover tables from binlog - see BUG#16217. sql/log_event.cc: Sending into output instructions for mysql client to switch internally to appropriate charset. mysql client is supposed to be invoked with --default-character-set= "to default character set of the server created the binlog". --- client/mysql.cc | 26 +++++++++++++++++++++- mysql-test/r/ctype_ucs_binlog.result | 1 + mysql-test/r/mysql.result | 10 +++++++++ mysql-test/r/mysqlbinlog.result | 25 ++++++++++++++++++++- mysql-test/r/mysqlbinlog2.result | 33 ++++++++++++++++++++++++++++ mysql-test/r/rpl_charset.result | 8 +++++++ mysql-test/r/rpl_timezone.result | 1 + mysql-test/r/user_var-binlog.result | 1 + mysql-test/t/mysql.test | 13 +++++++++++ mysql-test/t/mysqlbinlog.test | 19 +++++++++++++++- sql/log_event.cc | 5 +++++ 11 files changed, 139 insertions(+), 3 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 98af6561966..8d578aac58b 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -194,7 +194,7 @@ static int com_quit(String *str,char*), com_connect(String *str,char*), com_status(String *str,char*), com_use(String *str,char*), com_source(String *str, char*), com_rehash(String *str, char*), com_tee(String *str, char*), - com_notee(String *str, char*), + com_notee(String *str, char*), com_charset(String *str,char*), com_prompt(String *str, char*), com_delimiter(String *str, char*), com_warnings(String *str, char*), com_nowarnings(String *str, char*); @@ -268,6 +268,8 @@ static COMMANDS commands[] = { "Set outfile [to_outfile]. Append everything into given outfile." }, { "use", 'u', com_use, 1, "Use another database. Takes database name as argument." }, + { "charset", 'C', com_charset, 1, + "Switch to another charset. Might be needed for processing binlog with multi-byte charsets." }, { "warnings", 'W', com_warnings, 0, "Show warnings after every statement." }, { "nowarning", 'w', com_nowarnings, 0, @@ -1909,6 +1911,28 @@ com_clear(String *buffer,char *line __attribute__((unused))) return 0; } + /* ARGSUSED */ +static int +com_charset(String *buffer __attribute__((unused)), char *line) +{ + char buff[256], *param; + CHARSET_INFO * new_cs; + strmake(buff, line, sizeof(buff) - 1); + param= get_arg(buff, 0); + if (!param || !*param) + { + return put_info("Usage: \\C char_setname | charset charset_name", + INFO_ERROR, 0); + } + new_cs= get_charset_by_csname(param, MY_CS_PRIMARY, MYF(MY_WME)); + if (new_cs) + { + charset_info= new_cs; + put_info("Charset changed", INFO_INFO); + } + else put_info("Charset is not found", INFO_INFO); + return 0; +} /* Execute command diff --git a/mysql-test/r/ctype_ucs_binlog.result b/mysql-test/r/ctype_ucs_binlog.result index 14220a7df13..88912f98252 100644 --- a/mysql-test/r/ctype_ucs_binlog.result +++ b/mysql-test/r/ctype_ucs_binlog.result @@ -15,6 +15,7 @@ use test; SET TIMESTAMP=10000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t2 values (@v); # End of log file diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index 76faa12373a..611813d9c3f 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -59,3 +59,13 @@ database() test unlock tables; drop table t1; +ソ +ソ +c_cp932 +ソ +ソ +ソ +ソ +ソ +ソ +ソ diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index fda69b15fd1..50e4cc28d93 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -20,6 +20,7 @@ use test; SET TIMESTAMP=1000000000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; drop table if exists t1,t2; SET TIMESTAMP=1000000000; @@ -50,6 +51,7 @@ use test; SET TIMESTAMP=1000000000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values ("Alas"); # End of log file @@ -72,6 +74,7 @@ use test; SET TIMESTAMP=1000000000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values ("Alas"); # End of log file @@ -86,6 +89,7 @@ use test; SET TIMESTAMP=1000000000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; drop table if exists t1,t2; SET TIMESTAMP=1000000000; @@ -116,6 +120,7 @@ use test; SET TIMESTAMP=1000000000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values ("Alas"); # End of log file @@ -138,6 +143,7 @@ use test; SET TIMESTAMP=1000000000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values ("Alas"); # End of log file @@ -166,4 +172,21 @@ insert t1 values (1); # End of log file ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; -drop table t1, t2; +flush logs; +create table t3 (f text character set utf8); +create table t4 (f text character set cp932); +flush logs; +rename table t3 to t03, t4 to t04; +select HEX(f) from t03; +HEX(f) +E382BD +select HEX(f) from t3; +HEX(f) +E382BD +select HEX(f) from t04; +HEX(f) +835C +select HEX(f) from t4; +HEX(f) +835C +drop table t1, t2, t03, t04, t3, t4; diff --git a/mysql-test/r/mysqlbinlog2.result b/mysql-test/r/mysqlbinlog2.result index eb5fb4a87f8..4d6be811037 100644 --- a/mysql-test/r/mysqlbinlog2.result +++ b/mysql-test/r/mysqlbinlog2.result @@ -22,6 +22,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; @@ -52,6 +53,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "a"); SET INSERT_ID=2; @@ -78,6 +80,7 @@ use test; SET TIMESTAMP=1579609946; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "d"); SET INSERT_ID=5; @@ -95,6 +98,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; @@ -119,6 +123,7 @@ use test; SET TIMESTAMP=1579609944; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "c"); SET INSERT_ID=4; @@ -139,6 +144,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; @@ -159,6 +165,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; @@ -181,6 +188,7 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); # End of log file @@ -196,6 +204,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "a"); SET INSERT_ID=2; @@ -215,6 +224,7 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); # End of log file @@ -229,6 +239,7 @@ use test; SET TIMESTAMP=1579609946; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "d"); SET INSERT_ID=5; @@ -239,6 +250,7 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); # End of log file @@ -253,6 +265,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; @@ -284,6 +297,7 @@ use test; SET TIMESTAMP=1579609944; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "c"); SET INSERT_ID=4; @@ -297,6 +311,7 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); # End of log file @@ -311,6 +326,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; @@ -331,6 +347,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; @@ -361,6 +378,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "a"); SET INSERT_ID=2; @@ -387,6 +405,7 @@ use test; SET TIMESTAMP=1579609946; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "d"); SET INSERT_ID=5; @@ -404,6 +423,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; @@ -428,6 +448,7 @@ use test; SET TIMESTAMP=1579609944; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "c"); SET INSERT_ID=4; @@ -448,6 +469,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; @@ -468,6 +490,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; @@ -490,6 +513,7 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); # End of log file @@ -505,6 +529,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "a"); SET INSERT_ID=2; @@ -524,6 +549,7 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); # End of log file @@ -538,6 +564,7 @@ use test; SET TIMESTAMP=1579609946; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "d"); SET INSERT_ID=5; @@ -548,6 +575,7 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); # End of log file @@ -562,6 +590,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; @@ -593,6 +622,7 @@ use test; SET TIMESTAMP=1579609944; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "c"); SET INSERT_ID=4; @@ -606,6 +636,7 @@ use test; SET TIMESTAMP=1579609943; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; insert into t1 values(null, "f"); # End of log file @@ -620,6 +651,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; @@ -640,6 +672,7 @@ use test; SET TIMESTAMP=1579609942; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (a int auto_increment not null primary key, b char(3)); SET INSERT_ID=1; diff --git a/mysql-test/r/rpl_charset.result b/mysql-test/r/rpl_charset.result index 28f694a3933..e3e677ad0da 100644 --- a/mysql-test/r/rpl_charset.result +++ b/mysql-test/r/rpl_charset.result @@ -180,6 +180,7 @@ ROLLBACK; SET TIMESTAMP=1000000000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; drop database if exists mysqltest2; SET TIMESTAMP=1000000000; @@ -187,9 +188,11 @@ drop database if exists mysqltest3; SET TIMESTAMP=1000000000; create database mysqltest2 character set latin2; SET TIMESTAMP=1000000000; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=30; create database mysqltest3; SET TIMESTAMP=1000000000; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=64; drop database mysqltest3; SET TIMESTAMP=1000000000; @@ -199,6 +202,7 @@ SET TIMESTAMP=1000000000; create table t1 (a int auto_increment primary key, b varchar(100)); SET INSERT_ID=1; SET TIMESTAMP=1000000000; +/*!\C cp850 */; SET @@session.character_set_client=4,@@session.collation_connection=27,@@session.collation_server=64; insert into t1 (b) values(@@character_set_server); SET INSERT_ID=2; @@ -214,6 +218,7 @@ SET INSERT_ID=5; SET TIMESTAMP=1000000000; insert into t1 (b) values(@@collation_connection); SET TIMESTAMP=1000000000; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=5,@@session.collation_server=64; truncate table t1; SET INSERT_ID=1; @@ -224,6 +229,7 @@ SET TIMESTAMP=1000000000; insert into t1 (b) values(LEAST("Müller","Muffler")); SET INSERT_ID=3; SET TIMESTAMP=1000000000; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=31,@@session.collation_server=64; insert into t1 (b) values(@@collation_connection); SET INSERT_ID=4; @@ -241,9 +247,11 @@ SET TIMESTAMP=1000000000; drop database mysqltest3; use test; SET TIMESTAMP=1000000000; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=30; CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255)); SET TIMESTAMP=1000000000; +/*!\C koi8r */; SET @@session.character_set_client=7,@@session.collation_connection=51,@@session.collation_server=30; INSERT INTO t1 (c1, c2) VALUES ('îÕ, ÚÁ ÒÙÂÁÌËÕ','îÕ, ÚÁ ÒÙÂÁÌËÕ'); # End of log file diff --git a/mysql-test/r/rpl_timezone.result b/mysql-test/r/rpl_timezone.result index e1e6fa36be9..96a892f00fc 100644 --- a/mysql-test/r/rpl_timezone.result +++ b/mysql-test/r/rpl_timezone.result @@ -48,6 +48,7 @@ use test; SET TIMESTAMP=100000000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; create table t1 (t timestamp); SET TIMESTAMP=100000000; diff --git a/mysql-test/r/user_var-binlog.result b/mysql-test/r/user_var-binlog.result index 700ec7b09e0..d1555bb793f 100644 --- a/mysql-test/r/user_var-binlog.result +++ b/mysql-test/r/user_var-binlog.result @@ -21,6 +21,7 @@ use test; SET TIMESTAMP=10000; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; SET @@session.sql_mode=0; +/*!\C latin1 */; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; INSERT INTO t1 VALUES(@`a b`); SET @`var1`:=_latin1 0x273B616161 COLLATE `latin1_swedish_ci`; diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index 0783c043ef6..7a9a1ee3f60 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -41,3 +41,16 @@ lock tables t1 write; unlock tables; drop table t1; +# +# BUG#16217 - MySQL client misinterpretes multi-byte char as escape `\' +# + +# new command \C or charset +--exec $MYSQL --default-character-set=utf8 test -e "\C cp932 \g" +--exec $MYSQL --default-character-set=cp932 test -e "charset utf8;" + +# its usage to switch internally in mysql to requested charset +--exec $MYSQL --default-character-set=utf8 test -e "charset cp932; set @@session.character_set_client= cp932; select 'ƒ\'; create table t1 (c_cp932 TEXT CHARACTER SET cp932); insert into t1 values('ƒ\'); select * from t1; drop table t1;" +--exec $MYSQL --default-character-set=utf8 test -e "charset cp932; set character_set_client= cp932; select 'ƒ\'" +--exec $MYSQL --default-character-set=utf8 test -e "/*charset cp932 */; set character_set_client= cp932; select 'ƒ\'" +--exec $MYSQL --default-character-set=utf8 test -e "/*!\C cp932 */; set character_set_client= cp932; select 'ƒ\'" diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index f153a3eac6f..28074fba7e4 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -107,7 +107,24 @@ select "--- reading stdin --" as ""; --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR --exec $MYSQL_BINLOG --short-form --position=79 - < $MYSQL_TEST_DIR/std_data/trunc_binlog.000001 +# Bug#16217 (mysql client did not know how not switch its internal charset) +flush logs; +create table t3 (f text character set utf8); +create table t4 (f text character set cp932); +--exec $MYSQL --default-character-set=utf8 test -e "insert into t3 values(_utf8'ソ')" +--exec $MYSQL --default-character-set=cp932 test -e "insert into t4 values(_cp932'ƒ\');" +flush logs; +rename table t3 to t03, t4 to t04; +--exec $MYSQL_BINLOG --short-form $MYSQLTEST_VARDIR/log/master-bin.000004 | $MYSQL --default-character-set=utf8 +# original and recovered data must be equal +select HEX(f) from t03; +select HEX(f) from t3; +select HEX(f) from t04; +select HEX(f) from t4; + + + # clean up -drop table t1, t2; +drop table t1, t2, t03, t04, t3, t4; # End of 4.1 tests diff --git a/sql/log_event.cc b/sql/log_event.cc index a07411971ce..5ca7c00ee8f 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1551,6 +1551,11 @@ void Query_log_event::print_query_header(FILE* file, } if (unlikely(bcmp(print_event_info->charset, charset, 6))) { + CHARSET_INFO *cs_info= get_charset(uint2korr(charset), MYF(MY_WME)); + if (cs_info) + { + fprintf(file, "/*!\\C %s */;\n", cs_info->csname); /* for mysql client */ + } fprintf(file,"SET " "@@session.character_set_client=%d," "@@session.collation_connection=%d," From a68f171585da08a855df1958caab3264a4b74006 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 10 Feb 2006 15:12:27 +0200 Subject: [PATCH 4/5] BUG#16217 fix partly backported from 5.0. It is different in mysqlbinlog part. This changeset is assumed to stay in 4.1. client/mysql.cc: BUG#16217 forced to introduce a separate mysql client command. Feature is backported from 5.0, precisely ChangeSet 1.2034 06/02/09 16:23:09 aelkin@mysql.com (under second review at the moment) mysql-test/r/mysqlbinlog.result: changed in 5.0 mysql-test/t/mysqlbinlog.test: backported from 5.0. The last part of the test to mimic bug#16217 sql/log_event.cc: Inserting exclaiming comment command for mysql client made differently than in 5.0. Parsing still is cheap enough not to think to modify server code instead. --- client/mysql.cc | 26 +++++++++++++++++++++++++- mysql-test/r/mysqlbinlog.result | 19 ++++++++++++++++++- mysql-test/t/mysqlbinlog.test | 19 ++++++++++++++++++- sql/log_event.cc | 12 ++++++++++++ 4 files changed, 73 insertions(+), 3 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index d76195535a3..2f9031b84b8 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -190,7 +190,7 @@ static int com_quit(String *str,char*), com_connect(String *str,char*), com_status(String *str,char*), com_use(String *str,char*), com_source(String *str, char*), com_rehash(String *str, char*), com_tee(String *str, char*), - com_notee(String *str, char*), + com_notee(String *str, char*), com_charset(String *str,char*), com_prompt(String *str, char*), com_delimiter(String *str, char*); #ifdef USE_POPEN @@ -263,6 +263,8 @@ static COMMANDS commands[] = { "Set outfile [to_outfile]. Append everything into given outfile." }, { "use", 'u', com_use, 1, "Use another database. Takes database name as argument." }, + { "charset_name", 'C', com_charset, 1, + "Switch to another charset. Might be needed for processing binlog." }, /* Get bash-like expansion for some commands */ { "create table", 0, 0, 0, ""}, { "create database", 0, 0, 0, ""}, @@ -1850,6 +1852,28 @@ com_clear(String *buffer,char *line __attribute__((unused))) return 0; } + /* ARGSUSED */ +static int +com_charset(String *buffer __attribute__((unused)), char *line) +{ + char buff[256], *param; + CHARSET_INFO * new_cs; + strmake(buff, line, sizeof(buff) - 1); + param= get_arg(buff, 0); + if (!param || !*param) + { + return put_info("Usage: \\C char_setname | charset charset_name", + INFO_ERROR, 0); + } + new_cs= get_charset_by_csname(param, MY_CS_PRIMARY, MYF(MY_WME)); + if (new_cs) + { + charset_info= new_cs; + put_info("Charset changed", INFO_INFO); + } + else put_info("Charset is not found", INFO_INFO); + return 0; +} /* Execute command diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index e88ece6b361..adaf0dad56b 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -84,4 +84,21 @@ SET INSERT_ID=1; use test; SET TIMESTAMP=1000000000; insert into t1 values ("Alas"); -drop table t1, t2; +flush logs; +create table t3 (f text character set utf8); +create table t4 (f text character set cp932); +flush logs; +rename table t3 to t03, t4 to t04; +select HEX(f) from t03; +HEX(f) +E382BD +select HEX(f) from t3; +HEX(f) +E382BD +select HEX(f) from t04; +HEX(f) +835C +select HEX(f) from t4; +HEX(f) +835C +drop table t1, t2, t03, t04, t3, t4; diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 0f9faa5c337..871886331f6 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -98,7 +98,24 @@ select "--- --position --" as ""; --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR --exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ --read-from-remote-server --position=27 --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 + +# Bug#16217 (mysql client did not know how not switch its internal charset) +flush logs; +create table t3 (f text character set utf8); +create table t4 (f text character set cp932); +--exec $MYSQL --default-character-set=utf8 test -e "insert into t3 values(_utf8'ソ')" +--exec $MYSQL --default-character-set=cp932 test -e "insert into t4 values(_cp932'ƒ\');" +flush logs; +rename table t3 to t03, t4 to t04; +--exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000004 | $MYSQL --default-character-set=utf8 +# original and recovered data must be equal +select HEX(f) from t03; +select HEX(f) from t3; +select HEX(f) from t04; +select HEX(f) from t4; + + # clean up -drop table t1, t2; +drop table t1, t2, t03, t04, t3, t4; # End of 4.1 tests diff --git a/sql/log_event.cc b/sql/log_event.cc index 3f545df5776..19c32b2d28e 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -949,6 +949,7 @@ Query_log_event::Query_log_event(const char* buf, int event_len, void Query_log_event::print(FILE* file, bool short_form, char* last_db) { char buff[40],*end; // Enough for SET TIMESTAMP + const uint set_len= sizeof("SET ONE_SHOT CHARACTER_SET_CLIENT=") - 1; if (!short_form) { print_header(file); @@ -978,6 +979,17 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db) my_fwrite(file, (byte*) buff, (uint) (end-buff),MYF(MY_NABP | MY_WME)); if (flags & LOG_EVENT_THREAD_SPECIFIC_F) fprintf(file,"SET @@session.pseudo_thread_id=%lu;\n",(ulong)thread_id); + /* charset_name command for mysql client */ + if (!strncmp(query, "SET ONE_SHOT CHARACTER_SET_CLIENT=", set_len)) + { + char * endptr; + int cs_number= strtoul(query + set_len, &endptr, 10); + DBUG_ASSERT(*endptr == ','); + CHARSET_INFO *cs_info= get_charset(cs_number, MYF(MY_WME)); + if (cs_info) { + fprintf(file, "/*!\\C %s */;\n", cs_info->csname); + } + } my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME)); fprintf(file, ";\n"); } From 315a46138e881149e596d15b739995a9ae8b9ddf Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Feb 2006 16:22:37 +0300 Subject: [PATCH 5/5] Fixed bug#16272: IF function with decimal args can produce wrong result The Item_func_if::fix_length_and_dec() function when calculating length of result doesn't take into account unsigned_flag. But it is taken when calculating length of temporary field. This result in creating field that shorter than needed. Due to this, in the reported query 40.0 converted to 9.99. The function Item_func_if::fix_length_and_dec() now adds 1 to the max_length if the unsigned_flag isn't set. sql/item_cmpfunc.cc: Fixed bug#16272: IF function with decimal args can produce wrong result The function Item_func_if::fix_length_and_dec() now adds 1 to the max_length if the unsigned_flag isn't set. mysql-test/r/func_if.result: Added test case for bug#16272: IF function with decimal args can produce wrong result mysql-test/t/func_if.test: Added test case for bug#16272: IF function with decimal args can produce wrong result --- mysql-test/r/func_if.result | 7 +++++++ mysql-test/t/func_if.test | 8 ++++++++ sql/item_cmpfunc.cc | 3 ++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_if.result b/mysql-test/r/func_if.result index aee23b38ca5..eef380c8f52 100644 --- a/mysql-test/r/func_if.result +++ b/mysql-test/r/func_if.result @@ -121,3 +121,10 @@ a NULLIF(a,'') NULL NULL NULL DROP TABLE t1; +create table t1 (f1 int, f2 int); +insert into t1 values(1,1),(0,0); +select f1, f2, if(f1, 40.0, 5.00) from t1 group by f1 order by f2; +f1 f2 if(f1, 40.0, 5.00) +0 0 5.00 +1 1 40.00 +drop table t1; diff --git a/mysql-test/t/func_if.test b/mysql-test/t/func_if.test index 4e0f426c10b..beaa371f847 100644 --- a/mysql-test/t/func_if.test +++ b/mysql-test/t/func_if.test @@ -89,3 +89,11 @@ SELECT a, NULLIF(a,'') FROM t1 WHERE NULLIF(a,'') IS NULL; DROP TABLE t1; # End of 4.1 tests + +# +# Bug #16272 IF function with decimal args can produce wrong result +# +create table t1 (f1 int, f2 int); +insert into t1 values(1,1),(0,0); +select f1, f2, if(f1, 40.0, 5.00) from t1 group by f1 order by f2; +drop table t1; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index bb3f6e8b231..d812ce913c5 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1383,7 +1383,8 @@ Item_func_if::fix_length_and_dec() max_length= (cached_result_type == DECIMAL_RESULT || cached_result_type == INT_RESULT) ? (max(args[1]->max_length - args[1]->decimals, - args[2]->max_length - args[2]->decimals) + decimals) : + args[2]->max_length - args[2]->decimals) + decimals + + (unsigned_flag ? 0 : 1) ) : max(args[1]->max_length, args[2]->max_length); }