summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/rpl_charset.result199
-rw-r--r--mysql-test/r/rpl_server_id1.result5
-rw-r--r--mysql-test/r/rpl_user_variables.result12
-rw-r--r--mysql-test/r/user_var.result33
-rw-r--r--mysql-test/t/rpl_charset.test153
-rw-r--r--mysql-test/t/rpl_server_id1.test8
-rw-r--r--mysql-test/t/user_var.test21
-rw-r--r--sql/lex.h1
-rw-r--r--sql/log.cc34
-rw-r--r--sql/log_event.cc71
-rw-r--r--sql/set_var.cc123
-rw-r--r--sql/set_var.h56
-rw-r--r--sql/slave.cc83
-rw-r--r--sql/sql_class.cc1
-rw-r--r--sql/sql_class.h2
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_parse.cc42
-rw-r--r--sql/sql_yacc.yy4
18 files changed, 766 insertions, 84 deletions
diff --git a/mysql-test/r/rpl_charset.result b/mysql-test/r/rpl_charset.result
new file mode 100644
index 00000000000..6ba82d0dd2f
--- /dev/null
+++ b/mysql-test/r/rpl_charset.result
@@ -0,0 +1,199 @@
+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 database if exists test2;
+drop database if exists test3;
+create database test2 character set latin2;
+set @@character_set_server=latin5;
+create database test3;
+
+--- --master--
+show create database test2;
+Database Create Database
+test2 CREATE DATABASE `test2` /*!40100 DEFAULT CHARACTER SET latin2 */
+show create database test3;
+Database Create Database
+test3 CREATE DATABASE `test3` /*!40100 DEFAULT CHARACTER SET latin5 */
+
+--- --slave--
+show create database test2;
+Database Create Database
+test2 CREATE DATABASE `test2` /*!40100 DEFAULT CHARACTER SET latin2 */
+show create database test3;
+Database Create Database
+test3 CREATE DATABASE `test3` /*!40100 DEFAULT CHARACTER SET latin5 */
+set @@collation_server=armscii_bin;
+drop database test3;
+create database test3;
+
+--- --master--
+show create database test3;
+Database Create Database
+test3 CREATE DATABASE `test3` /*!40100 DEFAULT CHARACTER SET armscii8 COLLATE armscii_bin */
+
+--- --slave--
+show create database test3;
+Database Create Database
+test3 CREATE DATABASE `test3` /*!40100 DEFAULT CHARACTER SET armscii8 COLLATE armscii_bin */
+use test2;
+create table t1 (a int auto_increment primary key, b varchar(100));
+set character_set_client=cp850, collation_connection=latin2_croatian_ci;
+insert into t1 (b) values(@@character_set_server);
+insert into t1 (b) values(@@collation_server);
+insert into t1 (b) values(@@character_set_client);
+insert into t1 (b) values(@@character_set_connection);
+insert into t1 (b) values(@@collation_connection);
+
+--- --master--
+select * from t1 order by a;
+a b
+1 armscii8
+2 armscii_bin
+3 cp850
+4 latin2
+5 latin2_croatian_ci
+
+--- --slave--
+select * from test2.t1 order by a;
+a b
+1 armscii8
+2 armscii_bin
+3 cp850
+4 latin2
+5 latin2_croatian_ci
+set character_set_client=latin1, collation_connection=latin1_german1_ci;
+truncate table t1;
+insert into t1 (b) values(@@collation_connection);
+insert into t1 (b) values(LEAST("Müller","Muffler"));
+set collation_connection=latin1_german2_ci;
+insert into t1 (b) values(@@collation_connection);
+insert into t1 (b) values(LEAST("Müller","Muffler"));
+
+--- --master--
+select * from t1 order by a;
+a b
+1 latin1_german1_ci
+2 Muffler
+3 latin1_german2_ci
+4 Müller
+
+--- --slave--
+select * from test2.t1 order by a;
+a b
+1 latin1_german1_ci
+2 Muffler
+3 latin1_german2_ci
+4 Müller
+load data infile '../../std_data/words.dat' into table t1 (b);
+set @a= _cp850 'Müller' collate cp850_general_ci;
+truncate table t1;
+insert into t1 (b) values(collation(@a));
+
+--- --master--
+select * from t1 order by a;
+a b
+1 cp850_general_ci
+
+--- --slave--
+select * from test2.t1 order by a;
+a b
+1 cp850_general_ci
+drop database test2;
+drop database test3;
+show binlog events from 79;
+Log_name Pos Event_type Server_id Orig_log_pos Info
+master-bin.000001 79 Query 1 79 use `test`; create database test2 character set latin2
+master-bin.000001 156 Query 1 156 use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=8,COLLATION_DATABASE=8,COLLATION_SERVER=30
+master-bin.000001 290 Query 1 290 use `test`; create database test3
+master-bin.000001 346 Query 1 346 use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=8,COLLATION_DATABASE=8,COLLATION_SERVER=64
+master-bin.000001 480 Query 1 480 use `test`; drop database test3
+master-bin.000001 534 Query 1 534 use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=8,COLLATION_DATABASE=8,COLLATION_SERVER=64
+master-bin.000001 668 Query 1 668 use `test`; create database test3
+master-bin.000001 724 Query 1 724 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=8,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 859 Query 1 859 use `test2`; create table t1 (a int auto_increment primary key, b varchar(100))
+master-bin.000001 961 Query 1 961 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=4,COLLATION_CONNECTION=27,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 1097 Intvar 1 1097 INSERT_ID=1
+master-bin.000001 1125 Query 1 1125 use `test2`; insert into t1 (b) values(@@character_set_server)
+master-bin.000001 1210 Query 1 1210 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=4,COLLATION_CONNECTION=27,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 1346 Intvar 1 1346 INSERT_ID=2
+master-bin.000001 1374 Query 1 1374 use `test2`; insert into t1 (b) values(@@collation_server)
+master-bin.000001 1455 Query 1 1455 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=4,COLLATION_CONNECTION=27,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 1591 Intvar 1 1591 INSERT_ID=3
+master-bin.000001 1619 Query 1 1619 use `test2`; insert into t1 (b) values(@@character_set_client)
+master-bin.000001 1704 Query 1 1704 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=4,COLLATION_CONNECTION=27,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 1840 Intvar 1 1840 INSERT_ID=4
+master-bin.000001 1868 Query 1 1868 use `test2`; insert into t1 (b) values(@@character_set_connection)
+master-bin.000001 1957 Query 1 1957 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=4,COLLATION_CONNECTION=27,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 2093 Intvar 1 2093 INSERT_ID=5
+master-bin.000001 2121 Query 1 2121 use `test2`; insert into t1 (b) values(@@collation_connection)
+master-bin.000001 2206 Query 1 2206 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=5,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 2341 Query 1 2341 use `test2`; truncate table t1
+master-bin.000001 2394 Query 1 2394 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=5,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 2529 Intvar 1 2529 INSERT_ID=1
+master-bin.000001 2557 Query 1 2557 use `test2`; insert into t1 (b) values(@@collation_connection)
+master-bin.000001 2642 Query 1 2642 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=5,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 2777 Intvar 1 2777 INSERT_ID=2
+master-bin.000001 2805 Query 1 2805 use `test2`; insert into t1 (b) values(LEAST("Müller","Muffler"))
+master-bin.000001 2893 Query 1 2893 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 3029 Intvar 1 3029 INSERT_ID=3
+master-bin.000001 3057 Query 1 3057 use `test2`; insert into t1 (b) values(@@collation_connection)
+master-bin.000001 3142 Query 1 3142 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 3278 Intvar 1 3278 INSERT_ID=4
+master-bin.000001 3306 Query 1 3306 use `test2`; insert into t1 (b) values(LEAST("Müller","Muffler"))
+master-bin.000001 3394 Query 1 3394 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 3530 Intvar 1 3530 INSERT_ID=74
+master-bin.000001 3558 Create_file 1 3558 db=test2;table=t1;file_id=1;block_len=581
+master-bin.000001 4226 Query 1 4226 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 4362 Intvar 1 4362 INSERT_ID=5
+master-bin.000001 4390 Exec_load 1 4390 ;file_id=1
+master-bin.000001 4413 Query 1 4413 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 4549 Query 1 4549 use `test2`; truncate table t1
+master-bin.000001 4602 Query 1 4602 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 4738 Intvar 1 4738 INSERT_ID=1
+master-bin.000001 4766 User var 1 4766 @`a`=_cp850'Müller' COLLATE cp850_general_ci
+master-bin.000001 4806 Query 1 4806 use `test2`; insert into t1 (b) values(collation(@a))
+master-bin.000001 4882 Query 1 4882 use `test2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 5018 Query 1 5018 use `test2`; drop database test2
+master-bin.000001 5073 Query 1 5073 SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
+master-bin.000001 5204 Query 1 5204 drop database test3
+set global character_set_server=latin2;
+ERROR HY000: Binary logging and replication forbid changing the global server character set or collation
+set global character_set_server=latin2;
+ERROR HY000: Binary logging and replication forbid changing the global server character set or collation
+set one_shot @@character_set_server=latin5;
+set @@max_join_size=1000;
+select @@character_set_server;
+@@character_set_server
+latin5
+select @@character_set_server;
+@@character_set_server
+latin1
+set @@character_set_server=latin5;
+select @@character_set_server;
+@@character_set_server
+latin5
+select @@character_set_server;
+@@character_set_server
+latin5
+set one_shot max_join_size=10;
+ERROR HY000: The SET ONE_SHOT syntax is reserved for purposes internal to the MySQL server
+set character_set_client=9999999;
+ERROR 42000: Unknown character set: '9999999'
+set collation_server=9999998;
+ERROR HY000: Unknown collation: '9999998'
+use test;
+CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255));
+SET CHARACTER_SET_CLIENT=koi8r,
+CHARACTER_SET_CONNECTION=cp1251,
+CHARACTER_SET_RESULTS=koi8r;
+INSERT INTO t1 (c1, c2) VALUES ('îÕ, ÚÁ ÒÙÂÁÌËÕ','îÕ, ÚÁ ÒÙÂÁÌËÕ');
+select hex(c1), hex(c2) from t1;
+hex(c1) hex(c2)
+CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3
+select hex(c1), hex(c2) from t1;
+hex(c1) hex(c2)
+CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3
+drop table t1;
diff --git a/mysql-test/r/rpl_server_id1.result b/mysql-test/r/rpl_server_id1.result
index 8c383802de4..32e14b053d7 100644
--- a/mysql-test/r/rpl_server_id1.result
+++ b/mysql-test/r/rpl_server_id1.result
@@ -15,8 +15,5 @@ start slave;
insert into t1 values (1);
show status like "slave_running";
Variable_name Value
-Slave_running ON
-select * from t1;
-n
-1
+Slave_running OFF
drop table t1;
diff --git a/mysql-test/r/rpl_user_variables.result b/mysql-test/r/rpl_user_variables.result
index 71147772ac4..7bb5dc163ea 100644
--- a/mysql-test/r/rpl_user_variables.result
+++ b/mysql-test/r/rpl_user_variables.result
@@ -86,11 +86,11 @@ slave-bin.000001 313 Query 1 313 use `test`; insert into t1 values (@i1), (@i2),
slave-bin.000001 396 User var 2 396 @r1=12.5
slave-bin.000001 439 User var 2 439 @r2=-12.5
slave-bin.000001 482 Query 1 482 use `test`; insert into t1 values (@r1), (@r2)
-slave-bin.000001 551 User var 2 551 @s1='This is a test'
-slave-bin.000001 600 User var 2 600 @s2=''
-slave-bin.000001 635 User var 2 635 @s3='abc'def'
-slave-bin.000001 677 User var 2 677 @s4='abc\def'
-slave-bin.000001 719 User var 2 719 @s5='abc'def'
+slave-bin.000001 551 User var 2 551 @s1=_latin1'This is a test' COLLATE latin1_swedish_ci
+slave-bin.000001 600 User var 2 600 @s2=_latin1'' COLLATE latin1_swedish_ci
+slave-bin.000001 635 User var 2 635 @s3=_latin1'abc'def' COLLATE latin1_swedish_ci
+slave-bin.000001 677 User var 2 677 @s4=_latin1'abc\def' COLLATE latin1_swedish_ci
+slave-bin.000001 719 User var 2 719 @s5=_latin1'abc'def' COLLATE latin1_swedish_ci
slave-bin.000001 761 Query 1 761 use `test`; insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5)
slave-bin.000001 851 User var 2 851 @n1=NULL
slave-bin.000001 877 Query 1 877 use `test`; insert into t1 values (@n1)
@@ -99,7 +99,7 @@ slave-bin.000001 965 Query 1 965 use `test`; insert into t1 values (@n2)
slave-bin.000001 1027 Query 1 1027 use `test`; insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1)
slave-bin.000001 1115 User var 2 1115 @a=2
slave-bin.000001 1157 Query 1 1157 use `test`; insert into t1 values (@a+(@b:=@a+1))
-slave-bin.000001 1229 User var 2 1229 @q='abc'
+slave-bin.000001 1229 User var 2 1229 @q=_latin1'abc' COLLATE latin1_swedish_ci
slave-bin.000001 1266 Query 1 1266 use `test`; insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2'))
slave-bin.000001 1370 User var 2 1370 @a=5
slave-bin.000001 1412 Query 1 1412 use `test`; insert into t1 values (@a),(@a)
diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result
index a9351d2f1fb..605780a7280 100644
--- a/mysql-test/r/user_var.result
+++ b/mysql-test/r/user_var.result
@@ -162,3 +162,36 @@ charset(@a) collation(@a) coercibility(@a)
latin2 latin2_bin 0
select (@a:=_latin2'test' collate latin2_bin) = _latin2'TEST' collate latin2_general_ci;
ERROR HY000: Illegal mix of collations (latin2_bin,EXPLICIT) and (latin2_general_ci,EXPLICIT) for operation '='
+create table t1 (a varchar(50));
+reset master;
+SET TIMESTAMP=10000;
+SET @`a b`='hello';
+INSERT INTO t1 VALUES(@`a b`);
+set @var1= "';aaa";
+insert into t1 values (@var1);
+create table t2 (c char(30)) charset=ucs2;
+set @v=convert('abc' using ucs2);
+insert into t2 values (@v);
+show binlog events from 79;
+Log_name Pos Event_type Server_id Orig_log_pos Info
+master-bin.000001 79 User var 1 79 @`a b`=_latin1'hello' COLLATE latin1_swedish_ci
+master-bin.000001 120 Query 1 120 use `test`; INSERT INTO t1 VALUES(@`a b`)
+master-bin.000001 184 User var 1 184 @`var1`=_latin1'\';aaa' COLLATE latin1_swedish_ci
+master-bin.000001 226 Query 1 226 use `test`; insert into t1 values (@var1)
+master-bin.000001 290 Query 1 290 use `test`; create table t2 (c char(30)) charset=ucs2
+master-bin.000001 366 User var 1 366 @`v`=_ucs2'\0a\0b\0c' COLLATE ucs2_general_ci
+master-bin.000001 406 Query 1 406 use `test`; insert into t2 values (@v)
+/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+SET @`a b`:=_latin1'hello' COLLATE latin1_swedish_ci;
+use test;
+SET TIMESTAMP=10000;
+INSERT INTO t1 VALUES(@`a b`);
+SET @`var1`:=_latin1'\';aaa' COLLATE latin1_swedish_ci;
+SET TIMESTAMP=10000;
+insert into t1 values (@var1);
+SET TIMESTAMP=10000;
+create table t2 (c char(30)) charset=ucs2;
+SET @`v`:=_ucs2'\0a\0b\0c' COLLATE ucs2_general_ci;
+SET TIMESTAMP=10000;
+insert into t2 values (@v);
+drop table t1, t2;
diff --git a/mysql-test/t/rpl_charset.test b/mysql-test/t/rpl_charset.test
new file mode 100644
index 00000000000..c13b57a3108
--- /dev/null
+++ b/mysql-test/t/rpl_charset.test
@@ -0,0 +1,153 @@
+# Replication of character sets.
+# This test will fail if the server/client does not support enough charsets.
+
+# Remember that there currently exists
+# Bug #2326: Charset of table is determined by charset of db only if "USE db;"
+
+source include/master-slave.inc;
+--disable_warnings
+drop database if exists test2;
+drop database if exists test3;
+--enable_warnings
+
+create database test2 character set latin2;
+set @@character_set_server=latin5;
+create database test3;
+--disable_query_log
+select "--- --master--" as "";
+--enable_query_log
+show create database test2;
+show create database test3;
+sync_slave_with_master;
+--disable_query_log
+select "--- --slave--" as "";
+--enable_query_log
+show create database test2;
+show create database test3;
+
+connection master;
+set @@collation_server=armscii_bin;
+drop database test3;
+create database test3;
+--disable_query_log
+select "--- --master--" as "";
+--enable_query_log
+show create database test3;
+sync_slave_with_master;
+--disable_query_log
+select "--- --slave--" as "";
+--enable_query_log
+show create database test3;
+
+connection master;
+use test2;
+create table t1 (a int auto_increment primary key, b varchar(100));
+set character_set_client=cp850, collation_connection=latin2_croatian_ci;
+insert into t1 (b) values(@@character_set_server);
+insert into t1 (b) values(@@collation_server);
+# character_set_database and collation_database are not tested as they
+# are not replicated (Bar said that this variable may be removed shortly).
+insert into t1 (b) values(@@character_set_client);
+# collation_client does not exist
+insert into t1 (b) values(@@character_set_connection);
+insert into t1 (b) values(@@collation_connection);
+--disable_query_log
+select "--- --master--" as "";
+--enable_query_log
+select * from t1 order by a;
+sync_slave_with_master;
+--disable_query_log
+select "--- --slave--" as "";
+--enable_query_log
+select * from test2.t1 order by a;
+
+connection master;
+set character_set_client=latin1, collation_connection=latin1_german1_ci;
+truncate table t1;
+insert into t1 (b) values(@@collation_connection);
+insert into t1 (b) values(LEAST("Müller","Muffler"));
+set collation_connection=latin1_german2_ci;
+insert into t1 (b) values(@@collation_connection);
+insert into t1 (b) values(LEAST("Müller","Muffler"));
+--disable_query_log
+select "--- --master--" as "";
+--enable_query_log
+select * from t1 order by a;
+sync_slave_with_master;
+--disable_query_log
+select "--- --slave--" as "";
+--enable_query_log
+select * from test2.t1 order by a;
+
+# See if SET ONE_SHOT gets into binlog when LOAD DATA
+connection master;
+load data infile '../../std_data/words.dat' into table t1 (b);
+
+# See if user var is prefixed with collation in binlog and replicated well.
+# Note: replication of user variables is broken as far as derivation is
+# concerned. That's because when we store a user variable in the binlog,
+# we lose its derivation. So later on the slave, it's impossible to
+# know if the collation was explicit or not, so we use DERIVATION_NONE,
+# which provokes error messages (like 'Illegal mix of collation') when
+# we replay the master's INSERT/etc statements.
+set @a= _cp850 'Müller' collate cp850_general_ci;
+truncate table t1;
+insert into t1 (b) values(collation(@a));
+--disable_query_log
+select "--- --master--" as "";
+--enable_query_log
+select * from t1 order by a;
+sync_slave_with_master;
+--disable_query_log
+select "--- --slave--" as "";
+--enable_query_log
+select * from test2.t1 order by a;
+
+connection master;
+drop database test2;
+drop database test3;
+show binlog events from 79;
+sync_slave_with_master;
+
+# Check that we can't change global.collation_server
+
+error 1105;
+set global character_set_server=latin2;
+connection master;
+error 1105;
+set global character_set_server=latin2;
+
+# Check that SET ONE_SHOT is really one shot
+
+set one_shot @@character_set_server=latin5;
+set @@max_join_size=1000;
+select @@character_set_server;
+select @@character_set_server;
+set @@character_set_server=latin5;
+select @@character_set_server;
+select @@character_set_server;
+
+# ONE_SHOT on not charset/collation stuff is not allowed
+error 1105;
+set one_shot max_join_size=10;
+
+# Test of wrong character set numbers;
+error 1115;
+set character_set_client=9999999;
+error 1273;
+set collation_server=9999998;
+
+# This one was contributed by Sergey Petrunia (BUG#3943)
+
+use test;
+CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255));
+SET CHARACTER_SET_CLIENT=koi8r,
+ CHARACTER_SET_CONNECTION=cp1251,
+ CHARACTER_SET_RESULTS=koi8r;
+INSERT INTO t1 (c1, c2) VALUES ('îÕ, ÚÁ ÒÙÂÁÌËÕ','îÕ, ÚÁ ÒÙÂÁÌËÕ');
+select hex(c1), hex(c2) from t1;
+sync_slave_with_master;
+select hex(c1), hex(c2) from t1;
+connection master;
+drop table t1;
+sync_slave_with_master;
diff --git a/mysql-test/t/rpl_server_id1.test b/mysql-test/t/rpl_server_id1.test
index aefcb81c930..4d504325294 100644
--- a/mysql-test/t/rpl_server_id1.test
+++ b/mysql-test/t/rpl_server_id1.test
@@ -1,5 +1,8 @@
-# This test checks that a slave does not execute queries originating
-# from itself, by default.
+# This test checks that the slave I/O thread refuses to start if slave
+# and master have the same server id (because this is a useless setup,
+# and otherwise SHOW SLAVE STATUS shows progress but all queries are
+# ignored, which has caught our customers), unless
+# --replicate-same-server-id.
source include/master-slave.inc;
connection slave;
@@ -18,5 +21,4 @@ insert into t1 values (1);
# (when slave is its own master without --replicate-same-server-id)
sleep 2; # enough time for the event to be replicated (it should not)
show status like "slave_running";
-select * from t1;
drop table t1;
diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test
index a28b327cf58..601724e68c8 100644
--- a/mysql-test/t/user_var.test
+++ b/mysql-test/t/user_var.test
@@ -99,3 +99,24 @@ select (@a:=_latin2'test' collate latin2_bin) = _latin2'TEST';
select charset(@a),collation(@a),coercibility(@a);
--error 1267
select (@a:=_latin2'test' collate latin2_bin) = _latin2'TEST' collate latin2_general_ci;
+
+# Check that user variables are binlogged correctly (BUG#3875)
+create table t1 (a varchar(50));
+reset master;
+SET TIMESTAMP=10000;
+SET @`a b`='hello';
+INSERT INTO t1 VALUES(@`a b`);
+set @var1= "';aaa";
+insert into t1 values (@var1);
+create table t2 (c char(30)) charset=ucs2;
+set @v=convert('abc' using ucs2);
+insert into t2 values (@v);
+show binlog events from 79;
+# more important than SHOW BINLOG EVENTS, mysqlbinlog (where we
+# absolutely need variables names to be quoted and strings to be
+# escaped).
+--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
+--exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001
+drop table t1, t2;
+
+
diff --git a/sql/lex.h b/sql/lex.h
index e5bc537c213..f8ead8a8d2d 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -310,6 +310,7 @@ static SYMBOL symbols[] = {
{ "OFFSET", SYM(OFFSET_SYM)},
{ "OLD_PASSWORD", SYM(OLD_PASSWORD)},
{ "ON", SYM(ON)},
+ { "ONE_SHOT", SYM(ONE_SHOT_SYM)},
{ "OPEN", SYM(OPEN_SYM)},
{ "OPTIMIZE", SYM(OPTIMIZE)},
{ "OPTION", SYM(OPTION)},
diff --git a/sql/log.cc b/sql/log.cc
index 8df5ea5096b..e7a142230b1 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1231,6 +1231,40 @@ bool MYSQL_LOG::write(Log_event* event_info)
if (thd)
{
+#if MYSQL_VERSION_ID < 50000
+ /*
+ To make replication of charsets working in 4.1 we are writing values
+ of charset related variables before every statement in the binlog,
+ if values of those variables differ from global server-wide defaults.
+ We are using SET ONE_SHOT command so that the charset vars get reset
+ to default after the first non-SET statement.
+ In the next 5.0 this won't be needed as we will use the new binlog
+ format to store charset info.
+ */
+ if ((thd->variables.character_set_client->number !=
+ global_system_variables.collation_server->number) ||
+ (thd->variables.character_set_client->number !=
+ thd->variables.collation_connection->number) ||
+ (thd->variables.collation_server->number !=
+ thd->variables.collation_connection->number))
+ {
+ char buf[200];
+ int written= my_snprintf(buf, sizeof(buf)-1,
+ "SET ONE_SHOT CHARACTER_SET_CLIENT=%lu,\
+COLLATION_CONNECTION=%lu,COLLATION_DATABASE=%lu,COLLATION_SERVER=%lu",
+ thd->variables.character_set_client->number,
+ thd->variables.collation_connection->number,
+ thd->variables.collation_database->number,
+ thd->variables.collation_server->number);
+ Query_log_event e(thd, buf, written, 0);
+ e.set_log_pos(this);
+ if (e.write(file))
+ goto err;
+ }
+#endif
+
+ /* Add logging of timezones here */
+
if (thd->last_insert_id_used)
{
Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT,
diff --git a/sql/log_event.cc b/sql/log_event.cc
index fd65ec64a76..a76725a95e0 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -2176,7 +2176,7 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli)
void User_var_log_event::pack_info(Protocol* protocol)
{
char *buf= 0;
- uint val_offset= 2 + name_len;
+ uint val_offset= 4 + name_len;
uint event_len= val_offset;
if (is_null)
@@ -2200,16 +2200,21 @@ void User_var_log_event::pack_info(Protocol* protocol)
event_len= longlong10_to_str(uint8korr(val), buf + val_offset,-10)-buf;
break;
case STRING_RESULT:
- /*
- This is correct as pack_info is used for SHOW BINLOG command
- only. But be carefull this is may be incorrect in other cases as
- string may contain \ and '.
- */
- event_len= val_offset + 2 + val_len;
- buf= my_malloc(event_len, MYF(MY_WME));
- buf[val_offset]= '\'';
- memcpy(buf + val_offset + 1, val, val_len);
- buf[val_offset + val_len + 1]= '\'';
+ /* 15 is for 'COLLATE' and other chars */
+ buf= my_malloc(event_len+val_len*2+1+2*MY_CS_NAME_SIZE+15, MYF(MY_WME));
+ CHARSET_INFO *cs;
+ if (!(cs= get_charset(charset_number, MYF(0))))
+ {
+ strmov(buf+val_offset, "???");
+ event_len+= 3;
+ }
+ else
+ {
+ char *p= strxmov(buf + val_offset, "_", cs->csname, "'", NullS);
+ p+= escape_string_for_mysql(&my_charset_bin, p, val, val_len);
+ p= strxmov(p, "' COLLATE ", cs->name, NullS);
+ event_len= p-buf;
+ }
break;
case ROW_RESULT:
default:
@@ -2218,8 +2223,10 @@ void User_var_log_event::pack_info(Protocol* protocol)
}
}
buf[0]= '@';
- buf[1+name_len]= '=';
- memcpy(buf+1, name, name_len);
+ buf[1]= '`';
+ buf[2+name_len]= '`';
+ buf[3+name_len]= '=';
+ memcpy(buf+2, name, name_len);
protocol->store(buf, event_len, &my_charset_bin);
my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
}
@@ -2311,8 +2318,9 @@ void User_var_log_event::print(FILE* file, bool short_form, char* last_db)
fprintf(file, "\tUser_var\n");
}
- fprintf(file, "SET @");
+ fprintf(file, "SET @`");
my_fwrite(file, (byte*) name, (uint) (name_len), MYF(MY_NABP | MY_WME));
+ fprintf(file, "`");
if (is_null)
{
@@ -2332,7 +2340,36 @@ void User_var_log_event::print(FILE* file, bool short_form, char* last_db)
fprintf(file, ":=%s;\n", int_buf);
break;
case STRING_RESULT:
- fprintf(file, ":='%s';\n", val);
+ {
+ char *p;
+ if (!(p= (char *)my_alloca(2*val_len+1)))
+ break; // no error, as we are 'void'
+ escape_string_for_mysql(&my_charset_bin, p, val, val_len);
+#if MYSQL_VERSION_ID < 50000
+ /*
+ For proper behaviour when mysqlbinlog|mysql, we need to explicitely
+ specify the variable's collation. It will however cause problems when
+ people want to mysqlbinlog|mysql into another server not supporting the
+ character set. But there's not much to do about this and it's unlikely.
+ */
+ CHARSET_INFO *cs;
+ if (!(cs= get_charset(charset_number, MYF(0))))
+ /*
+ Generate an unusable command (=> syntax error) is probably the best
+ thing we can do here.
+ */
+ fprintf(file, ":=???;\n");
+ else
+ fprintf(file, ":=_%s'%s' COLLATE %s;\n", cs->csname, p, cs->name);
+#else
+ /*
+ In 5.0 we will have some SET CHARACTER_SET_ect automatically printed
+ for all events where it's needed.
+ */
+ fprintf(file, ":='%s';\n", p);
+#endif
+ my_afree(p);
+ }
break;
case ROW_RESULT:
default:
@@ -2353,7 +2390,9 @@ void User_var_log_event::print(FILE* file, bool short_form, char* last_db)
int User_var_log_event::exec_event(struct st_relay_log_info* rli)
{
Item *it= 0;
- CHARSET_INFO *charset= get_charset(charset_number, MYF(0));
+ CHARSET_INFO *charset;
+ if (!(charset= get_charset(charset_number, MYF(MY_WME))))
+ return 1;
LEX_STRING user_var_name;
user_var_name.str= name;
user_var_name.length= name_len;
diff --git a/sql/set_var.cc b/sql/set_var.cc
index b3b0153652b..7fdc10858dd 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -1708,19 +1708,31 @@ CHARSET_INFO *get_old_charset_by_name(const char *name)
bool sys_var_collation::check(THD *thd, set_var *var)
{
CHARSET_INFO *tmp;
- char buff[80];
- String str(buff,sizeof(buff), system_charset_info), *res;
- if (!(res=var->value->val_str(&str)))
+ if (var->value->result_type() == STRING_RESULT)
{
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, "NULL");
- return 1;
+ char buff[80];
+ String str(buff,sizeof(buff), system_charset_info), *res;
+ if (!(res=var->value->val_str(&str)))
+ {
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, "NULL");
+ return 1;
+ }
+ if (!(tmp=get_charset_by_name(res->c_ptr(),MYF(0))))
+ {
+ my_error(ER_UNKNOWN_COLLATION, MYF(0), res->c_ptr());
+ return 1;
+ }
}
-
- if (!(tmp=get_charset_by_name(res->c_ptr(),MYF(0))))
+ else // INT_RESULT
{
- my_error(ER_UNKNOWN_COLLATION, MYF(0), res->c_ptr());
- return 1;
+ if (!(tmp=get_charset(var->value->val_int(),MYF(0))))
+ {
+ char buf[20];
+ int10_to_str(var->value->val_int(), buf, -10);
+ my_error(ER_UNKNOWN_COLLATION, MYF(0), buf);
+ return 1;
+ }
}
var->save_result.charset= tmp; // Save for update
return 0;
@@ -1730,23 +1742,36 @@ bool sys_var_collation::check(THD *thd, set_var *var)
bool sys_var_character_set::check(THD *thd, set_var *var)
{
CHARSET_INFO *tmp;
- char buff[80];
- String str(buff,sizeof(buff), system_charset_info), *res;
- if (!(res=var->value->val_str(&str)))
- {
- if (!nullable)
+ if (var->value->result_type() == STRING_RESULT)
+ {
+ char buff[80];
+ String str(buff,sizeof(buff), system_charset_info), *res;
+ if (!(res=var->value->val_str(&str)))
{
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, "NULL");
+ if (!nullable)
+ {
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, "NULL");
+ return 1;
+ }
+ tmp= NULL;
+ }
+ else if (!(tmp=get_charset_by_csname(res->c_ptr(),MY_CS_PRIMARY,MYF(0))) &&
+ !(tmp=get_old_charset_by_name(res->c_ptr())))
+ {
+ my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), res->c_ptr());
return 1;
}
- tmp= NULL;
}
- else if (!(tmp=get_charset_by_csname(res->c_ptr(),MY_CS_PRIMARY,MYF(0))) &&
- !(tmp=get_old_charset_by_name(res->c_ptr())))
+ else // INT_RESULT
{
- my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), res->c_ptr());
- return 1;
+ if (!(tmp=get_charset(var->value->val_int(),MYF(0))))
+ {
+ char buf[20];
+ int10_to_str(var->value->val_int(), buf, -10);
+ my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), buf);
+ return 1;
+ }
}
var->save_result.charset= tmp; // Save for update
return 0;
@@ -1859,6 +1884,20 @@ void sys_var_character_set_server::set_default(THD *thd, enum_var_type type)
}
}
+#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50000)
+bool sys_var_character_set_server::check(THD *thd, set_var *var)
+{
+ if ((var->type == OPT_GLOBAL) &&
+ (mysql_bin_log.is_open() ||
+ active_mi->slave_running || active_mi->rli.slave_running))
+ {
+ my_printf_error(0, "Binary logging and replication forbid changing \
+the global server character set or collation", MYF(0));
+ return 1;
+ }
+ return sys_var_character_set::check(thd,var);
+}
+#endif
CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd,
enum_var_type type)
@@ -1952,6 +1991,20 @@ void sys_var_collation_database::set_default(THD *thd, enum_var_type type)
}
}
+#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50000)
+bool sys_var_collation_server::check(THD *thd, set_var *var)
+{
+ if ((var->type == OPT_GLOBAL) &&
+ (mysql_bin_log.is_open() ||
+ active_mi->slave_running || active_mi->rli.slave_running))
+ {
+ my_printf_error(0, "Binary logging and replication forbid changing \
+the global server character set or collation", MYF(0));
+ return 1;
+ }
+ return sys_var_collation::check(thd,var);
+}
+#endif
bool sys_var_collation_server::update(THD *thd, set_var *var)
{
@@ -2524,6 +2577,36 @@ int sql_set_variables(THD *thd, List<set_var_base> *var_list)
}
+/*
+ Say if all variables set by a SET support the ONE_SHOT keyword (currently,
+ only character set and collation do; later timezones will).
+
+ SYNOPSIS
+
+ not_all_support_one_shot
+ set_var List of variables to update
+
+ NOTES
+ It has a "not_" because it makes faster tests (no need to "!")
+
+ RETURN VALUE
+ 0 all variables of the list support ONE_SHOT
+ 1 at least one does not support ONE_SHOT
+*/
+
+bool not_all_support_one_shot(List<set_var_base> *var_list)
+{
+ List_iterator_fast<set_var_base> it(*var_list);
+ set_var_base *var;
+ while ((var= it++))
+ {
+ if (var->no_support_one_shot())
+ return 1;
+ }
+ return 0;
+}
+
+
/*****************************************************************************
Functions to handle SET mysql_internal_variable=const_expr
*****************************************************************************/
diff --git a/sql/set_var.h b/sql/set_var.h
index 699f320bbd9..64bdfdb718b 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -49,10 +49,20 @@ public:
const char *name;
sys_after_update_func after_update;
- sys_var(const char *name_arg) :name(name_arg),after_update(0)
- {}
+#if MYSQL_VERSION_ID < 50000
+ bool no_support_one_shot;
+#endif
+ sys_var(const char *name_arg)
+ :name(name_arg), after_update(0)
+#if MYSQL_VERSION_ID < 50000
+ , no_support_one_shot(1)
+#endif
+ {}
sys_var(const char *name_arg,sys_after_update_func func)
- :name(name_arg),after_update(func)
+ :name(name_arg), after_update(func)
+#if MYSQL_VERSION_ID < 50000
+ , no_support_one_shot(1)
+#endif
{}
virtual ~sys_var() {}
virtual bool check(THD *thd, set_var *var);
@@ -487,12 +497,17 @@ public:
class sys_var_collation :public sys_var_thd
{
public:
- sys_var_collation(const char *name_arg) :sys_var_thd(name_arg) {}
+ sys_var_collation(const char *name_arg) :sys_var_thd(name_arg)
+ {
+#if MYSQL_VERSION_ID < 50000
+ no_support_one_shot= 0;
+#endif
+ }
bool check(THD *thd, set_var *var);
SHOW_TYPE type() { return SHOW_CHAR; }
bool check_update_type(Item_result type)
{
- return type != STRING_RESULT; /* Only accept strings */
+ return ((type != STRING_RESULT) && (type != INT_RESULT));
}
bool check_default(enum_var_type type) { return 0; }
virtual void set_default(THD *thd, enum_var_type type)= 0;
@@ -502,13 +517,23 @@ class sys_var_character_set :public sys_var_thd
{
public:
bool nullable;
- sys_var_character_set(const char *name_arg) :sys_var_thd(name_arg)
- { nullable= 0; }
+ sys_var_character_set(const char *name_arg) :
+ sys_var_thd(name_arg)
+ {
+ nullable= 0;
+#if MYSQL_VERSION_ID < 50000
+ /*
+ In fact only almost all variables derived from sys_var_character_set
+ support ONE_SHOT; character_set_results doesn't. But that's good enough.
+ */
+ no_support_one_shot= 0;
+#endif
+ }
bool check(THD *thd, set_var *var);
SHOW_TYPE type() { return SHOW_CHAR; }
bool check_update_type(Item_result type)
{
- return type != STRING_RESULT; /* Only accept strings */
+ return ((type != STRING_RESULT) && (type != INT_RESULT));
}
bool check_default(enum_var_type type) { return 0; }
bool update(THD *thd, set_var *var);
@@ -541,6 +566,9 @@ class sys_var_character_set_server :public sys_var_character_set
public:
sys_var_character_set_server(const char *name_arg) :
sys_var_character_set(name_arg) {}
+#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50000)
+ bool check(THD *thd, set_var *var);
+#endif
void set_default(THD *thd, enum_var_type type);
CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type);
};
@@ -576,6 +604,9 @@ class sys_var_collation_server :public sys_var_collation
{
public:
sys_var_collation_server(const char *name_arg) :sys_var_collation(name_arg) {}
+#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50000)
+ bool check(THD *thd, set_var *var);
+#endif
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
@@ -689,7 +720,10 @@ public:
virtual int check(THD *thd)=0; /* To check privileges etc. */
virtual int update(THD *thd)=0; /* To set the value */
/* light check for PS */
- virtual int light_check(THD *thd) { return check(thd); }
+ virtual int light_check(THD *thd) { return check(thd); }
+#if MYSQL_VERSION_ID < 50000
+ virtual bool no_support_one_shot() { return 1; }
+#endif
};
@@ -731,6 +765,9 @@ public:
int check(THD *thd);
int update(THD *thd);
int light_check(THD *thd);
+#if MYSQL_VERSION_ID < 50000
+ bool no_support_one_shot() { return var->no_support_one_shot; }
+#endif
};
@@ -833,6 +870,7 @@ void set_var_init();
void set_var_free();
sys_var *find_sys_var(const char *str, uint length=0);
int sql_set_variables(THD *thd, List<set_var_base> *var_list);
+bool not_all_support_one_shot(List<set_var_base> *var_list);
void fix_delay_key_write(THD *thd, enum_var_type type);
ulong fix_sql_mode(ulong sql_mode);
extern sys_var_str sys_charset_system;
diff --git a/sql/slave.cc b/sql/slave.cc
index fa17a192b12..f88d828df1d 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -72,7 +72,7 @@ static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed,
static int request_table_dump(MYSQL* mysql, const char* db, const char* table);
static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
const char* table_name, bool overwrite);
-static int check_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi);
+static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi);
/*
@@ -1187,38 +1187,75 @@ slaves can't replicate a 5.0 or newer master.";
break;
}
- MYSQL_RES *master_clock_res;
- MYSQL_ROW master_clock_row;
- time_t slave_clock;
-
- if (mysql_real_query(mysql, "SELECT UNIX_TIMESTAMP()", 23))
- errmsg= "\"SELECT UNIX_TIMESTAMP()\" failed on master";
- else if (!(master_clock_res= mysql_store_result(mysql)))
+ /*
+ Compare the master and slave's clock. Do not die if master's clock is
+ unavailable (very old master not supporting UNIX_TIMESTAMP()?).
+ */
+ MYSQL_RES *master_res= 0;
+ MYSQL_ROW master_row;
+
+ if (!mysql_real_query(mysql, "SELECT UNIX_TIMESTAMP()", 23) &&
+ (master_res= mysql_store_result(mysql)) &&
+ (master_row= mysql_fetch_row(master_res)))
{
- errmsg= "Could not read the result of \"SELECT UNIX_TIMESTAMP()\" on \
-master";
+ mi->clock_diff_with_master=
+ (long) (time((time_t*) 0) - strtoul(master_row[0], 0, 10));
}
- else
+ else
{
- if (!(master_clock_row= mysql_fetch_row(master_clock_res)))
- errmsg= "Could not read a row from the result of \"SELECT \
-UNIX_TIMESTAMP()\" on master";
- else
- {
- slave_clock= time((time_t*) 0);
- mi->clock_diff_with_master= (long) (slave_clock -
- strtoul(master_clock_row[0], 0, 10));
- DBUG_PRINT("info",("slave_clock=%lu, master_clock=%s",
- slave_clock, master_clock_row[0]));
- }
- mysql_free_result(master_clock_res);
+ mi->clock_diff_with_master= 0; /* The "most sensible" value */
+ sql_print_error("Warning: \"SELECT UNIX_TIMESTAMP()\" failed on master, \
+do not trust column Seconds_Behind_Master of SHOW SLAVE STATUS");
+ }
+ if (master_res)
+ mysql_free_result(master_res);
+
+ /*
+ Check that the master's server id and ours are different. Because if they
+ are equal (which can result from a simple copy of master's datadir to slave,
+ thus copying some my.cnf), replication will work but all events will be
+ skipped.
+ Do not die if SHOW VARIABLES LIKE 'SERVER_ID' fails on master (very old
+ master?).
+ Note: we could have put a @@SERVER_ID in the previous SELECT
+ UNIX_TIMESTAMP() instead, but this would not have worked on 3.23 masters.
+ */
+ if (!mysql_real_query(mysql, "SHOW VARIABLES LIKE 'SERVER_ID'", 31) &&
+ (master_res= mysql_store_result(mysql)))
+ {
+ if ((master_row= mysql_fetch_row(master_res)) &&
+ (::server_id == strtoul(master_row[1], 0, 10)) &&
+ !replicate_same_server_id)
+ errmsg= "The slave I/O thread stops because master and slave have equal \
+MySQL server ids; these ids must be different for replication to work (or \
+the --replicate-same-server-id option must be used on slave but this does \
+not always make sense; please check the manual before using it).";
+ mysql_free_result(master_res);
+ }
+
+ /*
+ Check that the master's global character_set_server and ours are the same.
+ Not fatal if query fails (old master?).
+ */
+ if (!mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) &&
+ (master_res= mysql_store_result(mysql)))
+ {
+ if ((master_row= mysql_fetch_row(master_res)) &&
+ strcmp(master_row[0], global_system_variables.collation_server->name))
+ errmsg= "The slave I/O thread stops because master and slave have \
+different values for the COLLATION_SERVER global variable. The values must \
+be equal for replication to work";
+ mysql_free_result(master_res);
}
+ /* Add a timezones check here */
+
if (errmsg)
{
sql_print_error(errmsg);
return 1;
}
+
return 0;
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 9d368db0229..f2978edc033 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -181,6 +181,7 @@ THD::THD():user_time(0), current_statement(0), is_fatal_error(0),
current_linfo = 0;
slave_thread = 0;
variables.pseudo_thread_id= 0;
+ one_shot_set= 0;
file_id = 0;
warn_id= 0;
db_charset= global_system_variables.collation_database;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index d787dcabd00..676ee1b529f 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -801,7 +801,7 @@ public:
/* scramble - random string sent to client on handshake */
char scramble[SCRAMBLE_LENGTH+1];
- bool slave_thread;
+ bool slave_thread, one_shot_set;
bool locked, some_tables_deleted;
bool last_cuted_field;
bool no_errors, password, is_fatal_error;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 92ed53cf814..3884c8f2674 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -611,7 +611,7 @@ typedef struct st_lex
uint fk_delete_opt, fk_update_opt, fk_match_option;
uint slave_thd_opt;
uint8 describe;
- bool drop_if_exists, drop_temporary, local_file;
+ bool drop_if_exists, drop_temporary, local_file, one_shot_set;
bool in_comment, ignore_space, verbose, no_write_to_binlog;
bool derived_tables;
bool safe_to_cache_query;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 7596e37de93..b6e9bd3dd80 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2918,14 +2918,31 @@ unsent_create_error:
}
case SQLCOM_SET_OPTION:
+ {
+ List<set_var_base> *lex_var_list= &lex->var_list;
if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
(res= open_and_lock_tables(thd,tables))))
break;
- if (!(res= sql_set_variables(thd, &lex->var_list)))
+ if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
+ {
+ my_printf_error(0, "The SET ONE_SHOT syntax is reserved for \
+purposes internal to the MySQL server", MYF(0));
+ res= -1;
+ break;
+ }
+ if (!(res= sql_set_variables(thd, lex_var_list)))
+ {
+ /*
+ If the previous command was a SET ONE_SHOT, we don't want to forget
+ about the ONE_SHOT property of that SET. So we use a |= instead of = .
+ */
+ thd->one_shot_set|= lex->one_shot_set;
send_ok(thd);
+ }
if (thd->net.report_error)
res= -1;
break;
+ }
case SQLCOM_UNLOCK_TABLES:
unlock_locked_tables(thd);
@@ -3377,6 +3394,29 @@ unsent_create_error:
break;
}
thd->proc_info="query end"; // QQ
+ if (thd->one_shot_set)
+ {
+ /*
+ If this is a SET, do nothing. This is to allow mysqlbinlog to print
+ many SET commands (in this case we want the charset temp setting to
+ live until the real query). This is also needed so that SET
+ CHARACTER_SET_CLIENT... does not cancel itself immediately.
+ */
+ if (lex->sql_command != SQLCOM_SET_OPTION)
+ {
+ thd->variables.character_set_client=
+ global_system_variables.character_set_client;
+ thd->variables.collation_connection=
+ global_system_variables.collation_connection;
+ thd->variables.collation_database=
+ global_system_variables.collation_database;
+ thd->variables.collation_server=
+ global_system_variables.collation_server;
+ thd->update_charset();
+ /* Add timezone stuff here */
+ thd->one_shot_set= 0;
+ }
+ }
if (res < 0)
send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 6a40dc3c23a..04aab392285 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -316,6 +316,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token NUM
%token OFFSET_SYM
%token ON
+%token ONE_SHOT_SYM
%token OPEN_SYM
%token OPTION
%token OPTIONALLY
@@ -5002,6 +5003,7 @@ keyword:
| NVARCHAR_SYM {}
| OFFSET_SYM {}
| OLD_PASSWORD {}
+ | ONE_SHOT_SYM {}
| OPEN_SYM {}
| PACK_KEYS_SYM {}
| PARTIAL {}
@@ -5088,6 +5090,7 @@ set:
lex->sql_command= SQLCOM_SET_OPTION;
lex->option_type=OPT_SESSION;
lex->var_list.empty();
+ lex->one_shot_set= 0;
}
option_value_list
{}
@@ -5106,6 +5109,7 @@ option_type:
| GLOBAL_SYM { Lex->option_type= OPT_GLOBAL; }
| LOCAL_SYM { Lex->option_type= OPT_SESSION; }
| SESSION_SYM { Lex->option_type= OPT_SESSION; }
+ | ONE_SHOT_SYM { Lex->option_type= OPT_SESSION; Lex->one_shot_set= 1; }
;
opt_var_type: