Commit e013bf9f authored by Alexander Barkov's avatar Alexander Barkov

The bug

MDEV-4489 "Replication of big5, cp932, gbk, sjis strings makes wrong values on slave"
has been fixed.

Problem:
String constants of some Asian charsets (big5,cp932,gbk,sjis)
can have backslash '\' (0x5C) in the second byte of multi-byte characters.
Replicating of such constants using the standard '\'-escaping is dangerous.
Therefore, constants of these charsets are replicated using hex notation:
INSERT INTO t1 (a) VALUES (0x815C);

However, 0xHHHH constants do not work well in some cases,
because they can behave as strings and as numbers, depending on context
(for example, depending on the data type of the column in an INSERT statement).

This SQL script was not replicated correctly with statement-based replication:

SET NAMES gbk;
PREPARE STMT FROM 'INSERT INTO t1 (a) VALUES (?)';
SET @A = '1';
EXECUTE STMT USING @A;

The INSERT statement was replicated as:
INSERT INTO t1 (a) VALUES (0x31);

'1' was correctly converted to the number 1 on master.
But the 0x31 constant was treated as number 49 on slave.

Fix:

1. Binary log now uses X'HHHH' instead of 0xHHHH constants.
2. The X'HHHH' constants now work always as strings, in all contexts.
This is the SQL standard compliant behaviour.

After the fix, the above statement is replicated as:
INSERT INTO t1 (a) VALUES (X'31');
X'31' is treated as string '1' on slave, and is correctly converted to 1.


modified:
  @ mysql-test/r/ctype_cp932_binlog_stm.result
  @ mysql-test/r/select.result
  @ mysql-test/r/select_jcl6.result
  @ mysql-test/r/select_pkeycache.result
  @ mysql-test/r/user_var-binlog.result
  @ mysql-test/r/varbinary.result
  @ mysql-test/suite/binlog/r/binlog_stm_ctype_ucs.result
  @ mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result
  @ mysql-test/suite/rpl/r/rpl_charset_sjis.result
  @ mysql-test/suite/rpl/r/rpl_mdev382.result
  @ mysql-test/suite/rpl/t/rpl_charset_sjis.test
  @ mysql-test/t/ctype_cp932_binlog_stm.test
  @ mysql-test/t/select.test
  @ mysql-test/t/varbinary.test
    Adding and updating tests

  @ sql/item.cc
  @ sql/item.h
  @ sql/sql_yacc.yy
  @ sql/sql_lex.cc
    Splitting the implementations of X'HH' and 0xHH constants into two
    separate classes. Fixing the parser to distinguish the two syntaxes.

  @ sql/log_event.cc
    Using X'HH' instead of 0xHH for binary logging for string constants
    of the "dangerous" charsets.

  @ sql/sql_string.h
    Adding a helped method String::append_hex().
parent da846a15
......@@ -10,7 +10,7 @@ show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; CREATE TABLE t1(f1 blob)
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES(0x8300)
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES(X'8300')
master-bin.000001 # Query # # COMMIT
SELECT HEX(f1) FROM t1;
HEX(f1)
......@@ -44,7 +44,7 @@ BEGIN
INSERT INTO t4 VALUES (ins1, ins2, ind);
END
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO t4 VALUES ( NAME_CONST('ins1',_latin1 0x466F6F2773206120426172 COLLATE 'latin1_swedish_ci'), NAME_CONST('ins2',_cp932 0xED40ED41ED42 COLLATE 'cp932_japanese_ci'), NAME_CONST('ind',47.93))
master-bin.000001 # Query # # use `test`; INSERT INTO t4 VALUES ( NAME_CONST('ins1',_latin1 X'466F6F2773206120426172' COLLATE 'latin1_swedish_ci'), NAME_CONST('ins2',_cp932 X'ED40ED41ED42' COLLATE 'cp932_japanese_ci'), NAME_CONST('ind',47.93))
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; DROP PROCEDURE bug18293
master-bin.000001 # Query # # use `test`; DROP TABLE `t4` /* generated by server */
......@@ -19491,5 +19491,38 @@ EFBFA4 FA55
EFBFA5 818F
DROP TABLE t1;
#
# Bug#MDEV-4489 Replication of big5, cp932, gbk, sjis strings makes wrong values on slave
#
SET NAMES cp932;
CREATE TABLE t1 (a INT);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
INSERT INTO t1 VALUES (0x31);
INSERT INTO t1 VALUES (X'31');
PREPARE stmt FROM 'INSERT INTO t1 (a) VALUES (?)';
SET @a='1';
SELECT charset(@a);
charset(@a)
cp932
EXECUTE stmt USING @a;
DROP PREPARE stmt;
DROP TABLE t1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT)
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (0x31)
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (X'31')
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO t1 (a) VALUES (X'31')
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
#
# End of 5.5 tests
#
......@@ -2921,8 +2921,8 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join)
DROP TABLE t1,t2;
select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0;
x'10' + 0 X'10' + 0 b'10' + 0 B'10' + 0
select x'3136' + 0, X'3136' + 0, b'10' + 0, B'10' + 0;
x'3136' + 0 X'3136' + 0 b'10' + 0 B'10' + 0
16 16 2 2
create table t1 (f1 varchar(6) default NULL, f2 int(6) primary key not null);
create table t2 (f3 varchar(5) not null, f4 varchar(5) not null, UNIQUE KEY UKEY (f3,f4));
......
......@@ -2932,8 +2932,8 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t1 hash_ALL NULL #hash#$hj 5 test.t2.a 5 Using where; Using join buffer (flat, BNLH join)
DROP TABLE t1,t2;
select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0;
x'10' + 0 X'10' + 0 b'10' + 0 B'10' + 0
select x'3136' + 0, X'3136' + 0, b'10' + 0, B'10' + 0;
x'3136' + 0 X'3136' + 0 b'10' + 0 B'10' + 0
16 16 2 2
create table t1 (f1 varchar(6) default NULL, f2 int(6) primary key not null);
create table t2 (f3 varchar(5) not null, f4 varchar(5) not null, UNIQUE KEY UKEY (f3,f4));
......
......@@ -2921,8 +2921,8 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join)
DROP TABLE t1,t2;
select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0;
x'10' + 0 X'10' + 0 b'10' + 0 B'10' + 0
select x'3136' + 0, X'3136' + 0, b'10' + 0, B'10' + 0;
x'3136' + 0 X'3136' + 0 b'10' + 0 B'10' + 0
16 16 2 2
create table t1 (f1 varchar(6) default NULL, f2 int(6) primary key not null);
create table t2 (f3 varchar(5) not null, f4 varchar(5) not null, UNIQUE KEY UKEY (f3,f4));
......
......@@ -9,12 +9,12 @@ insert into t1 values (@var1),(@var2);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
master-bin.000001 # User var # # @`a b`=_latin1 0x68656C6C6F COLLATE latin1_swedish_ci
master-bin.000001 # User var # # @`a b`=_latin1 X'68656C6C6F' COLLATE latin1_swedish_ci
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES(@`a b`)
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # BEGIN
master-bin.000001 # User var # # @`var1`=_latin1 0x273B616161 COLLATE latin1_swedish_ci
master-bin.000001 # User var # # @`var2`=_binary 0x61 COLLATE binary
master-bin.000001 # User var # # @`var1`=_latin1 X'273B616161' COLLATE latin1_swedish_ci
master-bin.000001 # User var # # @`var2`=_binary X'61' COLLATE binary
master-bin.000001 # Query # # use `test`; insert into t1 values (@var1),(@var2)
master-bin.000001 # Query # # COMMIT
flush logs;
......@@ -34,7 +34,7 @@ SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
SET @`a b`:=_latin1 0x68656C6C6F COLLATE `latin1_swedish_ci`/*!*/;
SET @`a b`:=_latin1 X'68656C6C6F' COLLATE `latin1_swedish_ci`/*!*/;
use `test`/*!*/;
SET TIMESTAMP=10000/*!*/;
INSERT INTO t1 VALUES(@`a b`)
......@@ -45,8 +45,8 @@ COMMIT
SET TIMESTAMP=10000/*!*/;
BEGIN
/*!*/;
SET @`var1`:=_latin1 0x273B616161 COLLATE `latin1_swedish_ci`/*!*/;
SET @`var2`:=_binary 0x61 COLLATE `binary`/*!*/;
SET @`var1`:=_latin1 X'273B616161' COLLATE `latin1_swedish_ci`/*!*/;
SET @`var2`:=_binary X'61' COLLATE `binary`/*!*/;
SET TIMESTAMP=10000/*!*/;
insert into t1 values (@var1),(@var2)
/*!*/;
......
......@@ -5,9 +5,62 @@ A 65 9223372036854775807 18446744073709551615
select 0x31+1,concat(0x31)+1,-0xf;
0x31+1 concat(0x31)+1 -0xf
50 2 -15
select x'31',X'ffff'+0;
x'31' X'ffff'+0
select x'31',0xffff+0;
x'31' 0xffff+0
1 65535
select X'FFFF'+0;
X'FFFF'+0
0
Warnings:
Warning 1292 Truncated incorrect DOUBLE value: '\xFF\xFF'
SELECT x'31'+0, 0x31+0;
x'31'+0 0x31+0
1 49
SELECT x'31'+0.1e0, 0x31+0.1e0;
x'31'+0.1e0 0x31+0.1e0
1.1 49.1
SELECT x'312E39'+0e0, 0x312E39+0e0;
x'312E39'+0e0 0x312E39+0e0
1.9 3223097
SELECT CAST(x'31' AS SIGNED), CAST(0x31 AS SIGNED);
CAST(x'31' AS SIGNED) CAST(0x31 AS SIGNED)
1 49
SELECT CAST(x'31' AS DECIMAL(10,1)), CAST(0x31 AS DECIMAL(10,1));
CAST(x'31' AS DECIMAL(10,1)) CAST(0x31 AS DECIMAL(10,1))
1.0 49.0
SELECT CAST(x'312E39' AS SIGNED), CAST(0x312E39 AS SIGNED);
CAST(x'312E39' AS SIGNED) CAST(0x312E39 AS SIGNED)
1 3223097
Warnings:
Warning 1292 Truncated incorrect INTEGER value: '1.9'
SELECT CAST(x'312E39' AS DECIMAL(10,1)), CAST(0x312E39 AS DECIMAL(10,1));
CAST(x'312E39' AS DECIMAL(10,1)) CAST(0x312E39 AS DECIMAL(10,1))
1.9 3223097.0
EXPLAIN EXTENDED SELECT X'FFFF', 0xFFFF;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select X'ffff' AS `X'FFFF'`,0xffff AS `0xFFFF`
CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (X'31'),(0x31);
INSERT INTO t1 VALUES (X'312E39'),(0x312E39);
SELECT * FROM t1;
a
1
49
2
3223097
DROP TABLE t1;
CREATE TABLE t1 (a DECIMAL(10,1));
INSERT INTO t1 VALUES (X'31'),(0x31);
INSERT INTO t1 VALUES (X'312E39'),(0x312E39);
SELECT * FROM t1;
a
1.0
49.0
1.9
3223097.0
DROP TABLE t1;
create table t1 (ID int(8) unsigned zerofill not null auto_increment,UNIQ bigint(21) unsigned zerofill not null,primary key (ID),unique (UNIQ) );
insert into t1 set UNIQ=0x38afba1d73e6a18a;
insert into t1 set UNIQ=123;
......@@ -104,8 +157,8 @@ A
select b'01000001';
b'01000001'
A
select x'41', 0+x'41';
x'41' 0+x'41'
select x'41', 0+x'3635';
x'41' 0+x'3635'
A 65
select N'abc', length(N'abc');
abc length(N'abc')
......
......@@ -6,7 +6,7 @@ insert into t2 values (@v);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
master-bin.000001 # User var # # @`v`=_ucs2 0x006100620063 COLLATE ucs2_general_ci
master-bin.000001 # User var # # @`v`=_ucs2 X'006100620063' COLLATE ucs2_general_ci
master-bin.000001 # Query # # use `test`; insert into t2 values (@v)
master-bin.000001 # Query # # COMMIT
flush logs;
......@@ -26,7 +26,7 @@ SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
SET @`v`:=_ucs2 0x006100620063 COLLATE `ucs2_general_ci`/*!*/;
SET @`v`:=_ucs2 X'006100620063' COLLATE `ucs2_general_ci`/*!*/;
use `test`/*!*/;
SET TIMESTAMP=10000/*!*/;
insert into t2 values (@v)
......
......@@ -946,10 +946,10 @@ show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Intvar # # INSERT_ID=10
master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci
master-bin.000001 # User var # # @`b`=_latin1 X'3135' COLLATE latin1_swedish_ci
master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=#
master-bin.000001 # Intvar # # INSERT_ID=10
master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci
master-bin.000001 # User var # # @`b`=_latin1 X'3135' COLLATE latin1_swedish_ci
master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t4` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a`, @`b`) SET `b`= @b + bug27417(2) ;file_id=#
master-bin.000001 # Query # # ROLLBACK
drop trigger trg_del_t2;
......
......@@ -20,4 +20,36 @@ hex(a)
965C
drop table t1;
drop procedure p1;
#
# Start of 5.5 tests
#
#
# Bug#MDEV-4489 Replication of big5, cp932, gbk, sjis strings makes wrong values on slave
#
--- on master ---
SET NAMES sjis;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0x31),(X'31'),('1');
PREPARE stmt FROM 'INSERT INTO t1 (a) VALUES (?)';
SET @a='1';
EXECUTE stmt USING @a;
DROP PREPARE stmt;
SELECT * FROM t1;
a
49
1
1
1
--- on slave ---
SELECT * FROM t1;
a
49
1
1
1
--- on master ---
DROP TABLE t1;
#
# End of 5.5 tests
#
include/rpl_end.inc
......@@ -245,7 +245,7 @@ master-bin.000001 # User var # # @`a``3`=9223372036854775807
master-bin.000001 # User var # # @`a``4`=18446744073709551615
master-bin.000001 # User var # # @`b```=-1.234560123456789e125
master-bin.000001 # User var # # @```c`=-1234501234567890123456789012345678901234567890123456789.0123456789
master-bin.000001 # User var # # @```d```=_latin1 0x78787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878 COLLATE latin1_swedish_ci
master-bin.000001 # User var # # @```d```=_latin1 X'78787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878' COLLATE latin1_swedish_ci
master-bin.000001 # Query # # use `db1``; select 'oops!'`; INSERT INTO t1 VALUES (@`a``1`+1, @`a``2`*100, @`a``3`-1, @`a``4`-1, @`b```/2, @```c`, substr(@```d```, 2, 98))
master-bin.000001 # Query # # COMMIT
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
......@@ -283,7 +283,7 @@ SET @`a``3`:=9223372036854775807/*!*/;
SET @`a``4`:=18446744073709551615/*!*/;
SET @`b```:=-1.2345601234568e+125/*!*/;
SET @```c`:=-1234501234567890123456789012345678901234567890123456789.0123456789/*!*/;
SET @```d```:=_latin1 0x78787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878 COLLATE `latin1_swedish_ci`/*!*/;
SET @```d```:=_latin1 X'78787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878' COLLATE `latin1_swedish_ci`/*!*/;
SET TIMESTAMP=1000000000/*!*/;
INSERT INTO t1 VALUES (@`a``1`+1, @`a``2`*100, @`a``3`-1, @`a``4`-1, @`b```/2, @```c`, substr(@```d```, 2, 98))
/*!*/;
......
......@@ -23,4 +23,37 @@ sync_slave_with_master;
connection master;
# End of 5.0 tests
--echo #
--echo # Start of 5.5 tests
--echo #
--echo #
--echo # Bug#MDEV-4489 Replication of big5, cp932, gbk, sjis strings makes wrong values on slave
--echo #
connection master;
--echo --- on master ---
SET NAMES sjis;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0x31),(X'31'),('1');
PREPARE stmt FROM 'INSERT INTO t1 (a) VALUES (?)';
SET @a='1';
EXECUTE stmt USING @a;
DROP PREPARE stmt;
SELECT * FROM t1;
sync_slave_with_master;
connection slave;
--echo --- on slave ---
SELECT * FROM t1;
connection master;
--echo --- on master ---
DROP TABLE t1;
sync_slave_with_master;
connection master;
--echo #
--echo # End of 5.5 tests
--echo #
--source include/rpl_end.inc
......@@ -141,6 +141,23 @@ SELECT HEX(a), HEX(CONVERT(a using cp932)) as b FROM t1 HAVING b<>'3F' ORDER BY
DROP TABLE t1;
--echo #
--echo # Bug#MDEV-4489 Replication of big5, cp932, gbk, sjis strings makes wrong values on slave
--echo #
let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
SET NAMES cp932;
CREATE TABLE t1 (a INT);
SHOW CREATE TABLE t1;
INSERT INTO t1 VALUES (0x31);
INSERT INTO t1 VALUES (X'31');
PREPARE stmt FROM 'INSERT INTO t1 (a) VALUES (?)';
SET @a='1';
SELECT charset(@a);
EXECUTE stmt USING @a;
DROP PREPARE stmt;
DROP TABLE t1;
--source include/show_binlog_events.inc
--echo #
--echo # End of 5.5 tests
......
......@@ -2493,7 +2493,7 @@ DROP TABLE t1,t2;
# Bug #10650
#
select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0;
select x'3136' + 0, X'3136' + 0, b'10' + 0, B'10' + 0;
#
# Bug #11398 Bug in field_conv() results in wrong result of join with index
......
......@@ -13,7 +13,30 @@ drop table if exists t1;
select 0x41,0x41+0,0x41 | 0x7fffffffffffffff | 0,0xffffffffffffffff | 0 ;
select 0x31+1,concat(0x31)+1,-0xf;
select x'31',X'ffff'+0;
select x'31',0xffff+0;
select X'FFFF'+0;
#
# Hex string vs hex hybrid
#
SELECT x'31'+0, 0x31+0;
SELECT x'31'+0.1e0, 0x31+0.1e0;
SELECT x'312E39'+0e0, 0x312E39+0e0;
SELECT CAST(x'31' AS SIGNED), CAST(0x31 AS SIGNED);
SELECT CAST(x'31' AS DECIMAL(10,1)), CAST(0x31 AS DECIMAL(10,1));
SELECT CAST(x'312E39' AS SIGNED), CAST(0x312E39 AS SIGNED);
SELECT CAST(x'312E39' AS DECIMAL(10,1)), CAST(0x312E39 AS DECIMAL(10,1));
EXPLAIN EXTENDED SELECT X'FFFF', 0xFFFF;
CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (X'31'),(0x31);
INSERT INTO t1 VALUES (X'312E39'),(0x312E39);
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 (a DECIMAL(10,1));
INSERT INTO t1 VALUES (X'31'),(0x31);
INSERT INTO t1 VALUES (X'312E39'),(0x312E39);
SELECT * FROM t1;
DROP TABLE t1;
#
# Test of hex constants in WHERE:
......@@ -115,7 +138,7 @@ select 0x41;
select b'01000001';
select x'41', 0+x'41';
select x'41', 0+x'3635';
select N'abc', length(N'abc');
......
......@@ -6125,17 +6125,8 @@ inline uint char_val(char X)
X-'a'+10);
}
Item_hex_string::Item_hex_string()
{
hex_string_init("", 0);
}
Item_hex_string::Item_hex_string(const char *str, uint str_length)
{
hex_string_init(str, str_length);
}
void Item_hex_string::hex_string_init(const char *str, uint str_length)
void Item_hex_constant::hex_string_init(const char *str, uint str_length)
{
max_length=(str_length+1)/2;
char *ptr=(char*) sql_alloc(max_length+1);
......@@ -6159,7 +6150,7 @@ void Item_hex_string::hex_string_init(const char *str, uint str_length)
unsigned_flag= 1;
}
longlong Item_hex_string::val_int()
longlong Item_hex_hybrid::val_int()
{
// following assert is redundant, because fixed=1 assigned in constructor
DBUG_ASSERT(fixed == 1);
......@@ -6173,17 +6164,7 @@ longlong Item_hex_string::val_int()
}
my_decimal *Item_hex_string::val_decimal(my_decimal *decimal_value)
{
// following assert is redundant, because fixed=1 assigned in constructor
DBUG_ASSERT(fixed == 1);
ulonglong value= (ulonglong)val_int();
int2my_decimal(E_DEC_FATAL_ERROR, value, TRUE, decimal_value);
return (decimal_value);
}
int Item_hex_string::save_in_field(Field *field, bool no_conversions)
int Item_hex_hybrid::save_in_field(Field *field, bool no_conversions)
{
field->set_notnull();
if (field->result_type() == STRING_RESULT)
......@@ -6216,22 +6197,27 @@ warn:
}
void Item_hex_string::print(String *str, enum_query_type query_type)
void Item_hex_hybrid::print(String *str, enum_query_type query_type)
{
char *end= (char*) str_value.ptr() + str_value.length(),
*ptr= end - min(str_value.length(), sizeof(longlong));
uint32 len= min(str_value.length(), sizeof(longlong));
const char *ptr= str_value.ptr() + str_value.length() - len;
str->append("0x");
for (; ptr != end ; ptr++)
{
str->append(_dig_vec_lower[((uchar) *ptr) >> 4]);
str->append(_dig_vec_lower[((uchar) *ptr) & 0x0F]);
}
str->append_hex(ptr, len);
}
bool Item_hex_string::eq(const Item *arg, bool binary_cmp) const
void Item_hex_string::print(String *str, enum_query_type query_type)
{
if (arg->basic_const_item() && arg->type() == type())
str->append("X'");
str->append_hex(str_value.ptr(), str_value.length());
str->append("'");
}
bool Item_hex_constant::eq(const Item *arg, bool binary_cmp) const
{
if (arg->basic_const_item() && arg->type() == type() &&
arg->cast_to_int_type() == cast_to_int_type())
{
if (binary_cmp)
return !stringcmp(&str_value, &arg->str_value);
......@@ -6241,7 +6227,7 @@ bool Item_hex_string::eq(const Item *arg, bool binary_cmp) const
}
Item *Item_hex_string::safe_charset_converter(CHARSET_INFO *tocs)
Item *Item_hex_constant::safe_charset_converter(CHARSET_INFO *tocs)
{
Item_string *conv;
String tmp, *str= val_str(&tmp);
......
......@@ -2730,36 +2730,112 @@ public:
};
class Item_hex_string: public Item_basic_constant
/**
Item_hex_constant -- a common class for hex literals: X'HHHH' and 0xHHHH
*/
class Item_hex_constant: public Item_basic_constant
{
private:
void hex_string_init(const char *str, uint str_length);
public:
Item_hex_string();
Item_hex_string(const char *str,uint str_length);
Item_hex_constant()
{
hex_string_init("", 0);
}
Item_hex_constant(const char *str, uint str_length)
{
hex_string_init(str, str_length);
}
enum Type type() const { return VARBIN_ITEM; }
enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
bool check_vcol_func_processor(uchar *arg) { return FALSE;}
bool basic_const_item() const { return 1; }
bool eq(const Item *item, bool binary_cmp) const;
String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; }
};
/**
Item_hex_hybrid -- is a class implementing 0xHHHH literals, e.g.:
SELECT 0x3132;
They can behave as numbers and as strings depending on context.
*/
class Item_hex_hybrid: public Item_hex_constant
{
public:
Item_hex_hybrid(): Item_hex_constant() {}
Item_hex_hybrid(const char *str, uint str_length):
Item_hex_constant(str, str_length) {}
double val_real()
{
DBUG_ASSERT(fixed == 1);
return (double) (ulonglong) Item_hex_string::val_int();
return (double) (ulonglong) Item_hex_hybrid::val_int();
}
longlong val_int();
bool basic_const_item() const { return 1; }
String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; }
my_decimal *val_decimal(my_decimal *);
my_decimal *val_decimal(my_decimal *decimal_value)
{
// following assert is redundant, because fixed=1 assigned in constructor
DBUG_ASSERT(fixed == 1);
ulonglong value= (ulonglong) Item_hex_hybrid::val_int();
int2my_decimal(E_DEC_FATAL_ERROR, value, TRUE, decimal_value);
return decimal_value;
}
int save_in_field(Field *field, bool no_conversions);
enum Item_result result_type () const { return STRING_RESULT; }
enum Item_result cast_to_int_type() const { return INT_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
virtual void print(String *str, enum_query_type query_type);
bool eq(const Item *item, bool binary_cmp) const;
virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
bool check_vcol_func_processor(uchar *arg) { return FALSE;}
private:
void hex_string_init(const char *str, uint str_length);
void print(String *str, enum_query_type query_type);
};
/**
Item_hex_string -- is a class implementing X'HHHH' literals, e.g.:
SELECT X'3132';
Unlike Item_hex_hybrid, X'HHHH' literals behave as strings in all contexts.
X'HHHH' are also used in replication of string constants in case of
"dangerous" charsets (sjis, cp932, big5, gbk) who can have backslash (0x5C)
as the second byte of a multi-byte character, so using '\' escaping for
these charsets is not desirable.
*/
class Item_hex_string: public Item_hex_constant
{
public:
Item_hex_string(): Item_hex_constant() {}
Item_hex_string(const char *str, uint str_length):
Item_hex_constant(str, str_length) {}
longlong val_int()
{
DBUG_ASSERT(fixed == 1);
return longlong_from_string_with_check(str_value.charset(),
str_value.ptr(),
str_value.ptr()+
str_value.length());
}
double val_real()
{
DBUG_ASSERT(fixed == 1);
return double_from_string_with_check(str_value.charset(),
str_value.ptr(),
str_value.ptr() +
str_value.length());
}
my_decimal *val_decimal(my_decimal *decimal_value)
{
return val_decimal_from_string(decimal_value);
}
int save_in_field(Field *field, bool no_conversions)
{
field->set_notnull();
return field->store(str_value.ptr(), str_value.length(),
collation.collation);
}
enum Item_result cast_to_int_type() const { return STRING_RESULT; }
void print(String *str, enum_query_type query_type);
};
class Item_bin_string: public Item_hex_string
class Item_bin_string: public Item_hex_hybrid
{
public:
Item_bin_string(const char *str,uint str_length);
......
......@@ -622,16 +622,18 @@ static inline int read_str(const char **buf, const char *buf_end,
/**
Transforms a string into "" or its expression in 0x... form.
Transforms a string into "" or its expression in X'HHHH' form.
*/
char *str_to_hex(char *to, const char *from, uint len)
{
if (len)
{
*to++= '0';
*to++= 'x';
*to++= 'X';
*to++= '\'';
to= octet2hex(to, from, len);
*to++= '\'';
*to= '\0';
}
else
to= strmov(to, "\"\"");
......@@ -652,7 +654,7 @@ append_query_string(THD *thd, CHARSET_INFO *csinfo,
{
char *beg, *ptr;
uint32 const orig_len= to->length();
if (to->reserve(orig_len + from->length()*2+3))
if (to->reserve(orig_len + from->length() * 2 + 4))
return 1;
beg= (char*) to->ptr() + to->length();
......@@ -6295,7 +6297,7 @@ void User_var_log_event::pack_info(THD *thd, Protocol* protocol)
buf.append(" "))
return;
old_len= buf.length();
if (buf.reserve(old_len + val_len*2 + 2 + sizeof(" COLLATE ") +
if (buf.reserve(old_len + val_len * 2 + 3 + sizeof(" COLLATE ") +
MY_CS_NAME_SIZE))
return;
beg= const_cast<char *>(buf.ptr()) + old_len;
......@@ -6563,7 +6565,8 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
char *hex_str;
CHARSET_INFO *cs;
hex_str= (char *)my_malloc(2*val_len+1+2,MYF(MY_WME)); // 2 hex digits / byte
// 2 hex digits / byte
hex_str= (char *) my_malloc(2 * val_len + 1 + 3, MYF(MY_WME));
if (!hex_str)
return;
str_to_hex(hex_str, val, val_len);
......
......@@ -1411,7 +1411,7 @@ int lex_one_token(void *arg, void *yythd)
yylval->lex_str=get_token(lip,
2, // skip x'
length-3); // don't count x' and last '
return (HEX_NUM);
return HEX_STRING;
case MY_LEX_BIN_NUMBER: // Found b'bin-string'
lip->yySkip(); // Accept opening '
......
......@@ -364,6 +364,16 @@ public:
}
return 0;
}
bool append_hex(const char *src, uint32 srclen)
{
for (const char *end= src + srclen ; src != end ; src++)
{
if (append(_dig_vec_lower[((uchar) *src) >> 4]) ||
append(_dig_vec_lower[((uchar) *src) & 0x0F]))
return true;
}
return false;
}
bool fill(uint32 max_length,char fill);
void strip_sp();
friend int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
......
......@@ -1021,6 +1021,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token HAVING /* SQL-2003-R */
%token HELP_SYM
%token HEX_NUM
%token HEX_STRING
%token HIGH_PRIORITY
%token HOST_SYM
%token HOSTS_SYM
......@@ -1448,7 +1449,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%left INTERVAL_SYM
%type <lex_str>
IDENT IDENT_QUOTED TEXT_STRING DECIMAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM
IDENT IDENT_QUOTED TEXT_STRING DECIMAL_NUM FLOAT_NUM NUM LONG_NUM
HEX_NUM HEX_STRING hex_num_or_string
LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text
IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
NCHAR_STRING opt_component key_cache_name
......@@ -5996,6 +5998,11 @@ now_or_signed_literal:
{ $$=$1; }
;
hex_num_or_string:
HEX_NUM {}
| HEX_STRING {}
;
charset:
CHAR_SYM SET {}
| CHARSET {}
......@@ -12261,7 +12268,7 @@ text_string:
}
| HEX_NUM
{
Item *tmp= new (YYTHD->mem_root) Item_hex_string($1.str, $1.length);
Item *tmp= new (YYTHD->mem_root) Item_hex_hybrid($1.str, $1.length);
if (tmp == NULL)
MYSQL_YYABORT;
/*
......@@ -12271,6 +12278,14 @@ text_string:
tmp->quick_fix_field();
$$= tmp->val_str((String*) 0);
}
| HEX_STRING
{
Item *tmp= new (YYTHD->mem_root) Item_hex_string($1.str, $1.length);
if (tmp == NULL)
MYSQL_YYABORT;
tmp->quick_fix_field();
$$= tmp->val_str((String*) 0);
}
| BIN_NUM
{
Item *tmp= new (YYTHD->mem_root) Item_bin_string($1.str, $1.length);
......@@ -12339,6 +12354,12 @@ literal:
MYSQL_YYABORT;
}
| HEX_NUM
{
$$ = new (YYTHD->mem_root) Item_hex_hybrid($1.str, $1.length);
if ($$ == NULL)
MYSQL_YYABORT;
}
| HEX_STRING
{
$$ = new (YYTHD->mem_root) Item_hex_string($1.str, $1.length);
if ($$ == NULL)
......@@ -12350,7 +12371,7 @@ literal:
if ($$ == NULL)
MYSQL_YYABORT;
}
| UNDERSCORE_CHARSET HEX_NUM
| UNDERSCORE_CHARSET hex_num_or_string
{
Item *tmp= new (YYTHD->mem_root) Item_hex_string($2.str, $2.length);
if (tmp == NULL)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment