summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <lars@mysql.com/black.(none)>2006-11-13 12:44:53 +0100
committerunknown <lars@mysql.com/black.(none)>2006-11-13 12:44:53 +0100
commit181c9b4dd4c23c5ef4d8c2562c055e35b6267bfe (patch)
tree2e35d48c7436cf853a6515a4dccc4e72660d82f3
parent383fbde53239a9d4fd4e444a0b6d8942305f74f5 (diff)
parent7614eb0d1db4819ec6f1c3c59196d1dcb0d0c8d5 (diff)
downloadmariadb-git-181c9b4dd4c23c5ef4d8c2562c055e35b6267bfe.tar.gz
Merge mysql.com:/home/bkroot/mysql-5.0-rpl
into mysql.com:/home/bk/MERGE/mysql-5.0-merge BitKeeper/etc/collapsed: auto-union sql/mysql_priv.h: Auto merged sql/slave.cc: Auto merged
-rw-r--r--BitKeeper/etc/collapsed2
-rw-r--r--include/m_ctype.h12
-rw-r--r--myisam/mi_key.c15
-rw-r--r--myisam/mi_open.c2
-rw-r--r--mysql-test/include/strict_autoinc.inc4
-rw-r--r--mysql-test/r/ctype_recoding.result4
-rw-r--r--mysql-test/r/ctype_ucs.result22
-rw-r--r--mysql-test/r/ctype_utf8.result32
-rw-r--r--mysql-test/r/fulltext.result8
-rw-r--r--mysql-test/r/func_gconcat.result70
-rw-r--r--mysql-test/r/lowercase_table.result24
-rw-r--r--mysql-test/r/rpl_deadlock.result38
-rw-r--r--mysql-test/r/rpl_ignore_table.result16
-rw-r--r--mysql-test/r/strict_autoinc_1myisam.result1
-rw-r--r--mysql-test/r/strict_autoinc_2innodb.result1
-rw-r--r--mysql-test/r/strict_autoinc_3heap.result1
-rw-r--r--mysql-test/r/strict_autoinc_4bdb.result1
-rw-r--r--mysql-test/r/strict_autoinc_5ndb.result1
-rw-r--r--mysql-test/t/ctype_ucs.test17
-rw-r--r--mysql-test/t/ctype_utf8.test24
-rw-r--r--mysql-test/t/func_gconcat.test35
-rw-r--r--mysql-test/t/lowercase_table.test20
-rw-r--r--mysql-test/t/rpl_deadlock.test16
-rw-r--r--mysql-test/t/rpl_ignore_table-slave.opt2
-rw-r--r--mysql-test/t/rpl_ignore_table.test23
-rw-r--r--sql/field.cc354
-rw-r--r--sql/field.h7
-rw-r--r--sql/item.cc2
-rw-r--r--sql/item.h12
-rw-r--r--sql/item_sum.cc23
-rw-r--r--sql/mysql_priv.h11
-rw-r--r--sql/slave.cc21
-rw-r--r--sql/sql_parse.cc20
-rw-r--r--sql/sql_select.cc5
-rw-r--r--sql/sql_string.cc156
-rw-r--r--sql/sql_string.h8
-rw-r--r--strings/ctype-bin.c3
-rw-r--r--strings/ctype-mb.c24
-rw-r--r--strings/ctype-simple.c18
-rw-r--r--strings/ctype-ucs2.c8
-rw-r--r--strings/ctype-utf8.c135
41 files changed, 966 insertions, 232 deletions
diff --git a/BitKeeper/etc/collapsed b/BitKeeper/etc/collapsed
index 226f0f1a2e2..10bc7a2182a 100644
--- a/BitKeeper/etc/collapsed
+++ b/BitKeeper/etc/collapsed
@@ -15,5 +15,7 @@
45214442pBGT9KuZEGixBH71jTzbOA
45214a07hVsIGwvwa-WrO-jpeaSwVw
452a92d0-31-8wSzSfZi165fcGcXPA
+452c6c6dAjuNghfc1ObZ_UQ5SCl85g
+4538a7b0EbDHHkWPbIwxO6ZIDdg6Dg
454a7ef8gdvE_ddMlJyghvOAkKPNOQ
454f8960jsVT_kMKJtZ9OCgXoba0xQ
diff --git a/include/m_ctype.h b/include/m_ctype.h
index 35d2889bdd5..ffecadd9836 100644
--- a/include/m_ctype.h
+++ b/include/m_ctype.h
@@ -178,8 +178,8 @@ typedef struct my_charset_handler_st
unsigned char *s,unsigned char *e);
/* Functions for case and sort convertion */
- void (*caseup_str)(struct charset_info_st *, char *);
- void (*casedn_str)(struct charset_info_st *, char *);
+ uint (*caseup_str)(struct charset_info_st *, char *);
+ uint (*casedn_str)(struct charset_info_st *, char *);
uint (*caseup)(struct charset_info_st *, char *src, uint srclen,
char *dst, uint dstlen);
uint (*casedn)(struct charset_info_st *, char *src, uint srclen,
@@ -311,8 +311,8 @@ extern uint my_instr_simple(struct charset_info_st *,
/* Functions for 8bit */
-extern void my_caseup_str_8bit(CHARSET_INFO *, char *);
-extern void my_casedn_str_8bit(CHARSET_INFO *, char *);
+extern uint my_caseup_str_8bit(CHARSET_INFO *, char *);
+extern uint my_casedn_str_8bit(CHARSET_INFO *, char *);
extern uint my_caseup_8bit(CHARSET_INFO *, char *src, uint srclen,
char *dst, uint dstlen);
extern uint my_casedn_8bit(CHARSET_INFO *, char *src, uint srclen,
@@ -399,8 +399,8 @@ int my_mbcharlen_8bit(CHARSET_INFO *, uint c);
/* Functions for multibyte charsets */
-extern void my_caseup_str_mb(CHARSET_INFO *, char *);
-extern void my_casedn_str_mb(CHARSET_INFO *, char *);
+extern uint my_caseup_str_mb(CHARSET_INFO *, char *);
+extern uint my_casedn_str_mb(CHARSET_INFO *, char *);
extern uint my_caseup_mb(CHARSET_INFO *, char *src, uint srclen,
char *dst, uint dstlen);
extern uint my_casedn_mb(CHARSET_INFO *, char *src, uint srclen,
diff --git a/myisam/mi_key.c b/myisam/mi_key.c
index 01bd0c43119..c6f9799bd67 100644
--- a/myisam/mi_key.c
+++ b/myisam/mi_key.c
@@ -52,7 +52,7 @@ static int _mi_put_key_in_record(MI_INFO *info,uint keynr,byte *record);
uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
const byte *record, my_off_t filepos)
{
- byte *pos,*end;
+ byte *pos;
uchar *start;
reg1 HA_KEYSEG *keyseg;
my_bool is_ft= info->s->keyinfo[keynr].flag & HA_FULLTEXT;
@@ -107,18 +107,17 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
}
if (keyseg->flag & HA_SPACE_PACK)
{
- end= pos + length;
if (type != HA_KEYTYPE_NUM)
{
- while (end > pos && end[-1] == ' ')
- end--;
+ length= cs->cset->lengthsp(cs, pos, length);
}
else
{
+ byte *end= pos + length;
while (pos < end && pos[0] == ' ')
pos++;
+ length=(uint) (end-pos);
}
- length=(uint) (end-pos);
FIX_LENGTH(cs, pos, length, char_length);
store_key_length_inc(key,char_length);
memcpy((byte*) key,(byte*) pos,(size_t) char_length);
@@ -403,8 +402,10 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr,
pos= record+keyseg->start;
if (keyseg->type != (int) HA_KEYTYPE_NUM)
{
- memcpy(pos,key,(size_t) length);
- bfill(pos+length,keyseg->length-length,' ');
+ memcpy(pos,key,(size_t) length);
+ keyseg->charset->cset->fill(keyseg->charset,
+ pos + length, keyseg->length - length,
+ ' ');
}
else
{
diff --git a/myisam/mi_open.c b/myisam/mi_open.c
index a52ab5aad1f..bf20eb3f270 100644
--- a/myisam/mi_open.c
+++ b/myisam/mi_open.c
@@ -336,6 +336,8 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
goto err;
}
}
+ else if (pos->type == HA_KEYTYPE_BINARY)
+ pos->charset= &my_charset_bin;
}
if (share->keyinfo[i].flag & HA_SPATIAL)
{
diff --git a/mysql-test/include/strict_autoinc.inc b/mysql-test/include/strict_autoinc.inc
index 6960440f3a7..823efcc2040 100644
--- a/mysql-test/include/strict_autoinc.inc
+++ b/mysql-test/include/strict_autoinc.inc
@@ -2,6 +2,10 @@
# Test for strict-mode autoincrement
#
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
set @org_mode=@@sql_mode;
eval create table t1
(
diff --git a/mysql-test/r/ctype_recoding.result b/mysql-test/r/ctype_recoding.result
index 4e145346081..125e0edd1f9 100644
--- a/mysql-test/r/ctype_recoding.result
+++ b/mysql-test/r/ctype_recoding.result
@@ -171,8 +171,8 @@ create table t1 (a char(10) character set koi8r, b text character set koi8r);
insert into t1 values ('test','test');
insert into t1 values ('ÊÃÕË','ÊÃÕË');
Warnings:
-Warning 1265 Data truncated for column 'a' at row 1
-Warning 1265 Data truncated for column 'b' at row 1
+Warning 1366 Incorrect string value: '\xCA\xC3\xD5\xCB' for column 'a' at row 1
+Warning 1366 Incorrect string value: '\xCA\xC3\xD5\xCB' for column 'b' at row 1
drop table t1;
set names koi8r;
create table t1 (a char(10) character set cp1251);
diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result
index 76fcbbeb9f8..e32c1e8aae0 100644
--- a/mysql-test/r/ctype_ucs.result
+++ b/mysql-test/r/ctype_ucs.result
@@ -723,6 +723,28 @@ lily
river
drop table t1;
deallocate prepare stmt;
+create table t1 (
+a char(10) unicode not null,
+index a (a)
+) engine=myisam;
+insert into t1 values (repeat(0x201f, 10));
+insert into t1 values (repeat(0x2020, 10));
+insert into t1 values (repeat(0x2021, 10));
+explain select hex(a) from t1 order by a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 20 NULL 3 Using index
+select hex(a) from t1 order by a;
+hex(a)
+201F201F201F201F201F201F201F201F201F201F
+2020202020202020202020202020202020202020
+2021202120212021202120212021202120212021
+alter table t1 drop index a;
+select hex(a) from t1 order by a;
+hex(a)
+201F201F201F201F201F201F201F201F201F201F
+2020202020202020202020202020202020202020
+2021202120212021202120212021202120212021
+drop table t1;
CREATE TABLE t1 (id int, s char(5) CHARACTER SET ucs2 COLLATE ucs2_unicode_ci);
INSERT INTO t1 VALUES (1, 'ZZZZZ'), (1, 'ZZZ'), (2, 'ZZZ'), (2, 'ZZZZZ');
SELECT id, MIN(s) FROM t1 GROUP BY id;
diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index 00fd5a0c9aa..4eb74510c93 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -197,7 +197,7 @@ drop table t1;
create table t1 (s1 char(10) character set utf8);
insert into t1 values (0x41FF);
Warnings:
-Warning 1265 Data truncated for column 's1' at row 1
+Warning 1366 Incorrect string value: '\xFF' for column 's1' at row 1
select hex(s1) from t1;
hex(s1)
41
@@ -205,7 +205,7 @@ drop table t1;
create table t1 (s1 varchar(10) character set utf8);
insert into t1 values (0x41FF);
Warnings:
-Warning 1265 Data truncated for column 's1' at row 1
+Warning 1366 Incorrect string value: '\xFF' for column 's1' at row 1
select hex(s1) from t1;
hex(s1)
41
@@ -213,7 +213,7 @@ drop table t1;
create table t1 (s1 text character set utf8);
insert into t1 values (0x41FF);
Warnings:
-Warning 1265 Data truncated for column 's1' at row 1
+Warning 1366 Incorrect string value: '\xFF' for column 's1' at row 1
select hex(s1) from t1;
hex(s1)
41
@@ -1536,6 +1536,32 @@ set @a:=null;
execute my_stmt using @a;
a b
drop table if exists t1;
+drop table if exists t1;
+drop view if exists v1, v2;
+set names utf8;
+create table t1(col1 varchar(12) character set utf8 collate utf8_unicode_ci);
+insert into t1 values('t1_val');
+create view v1 as select 'v1_val' as col1;
+select coercibility(col1), collation(col1) from v1;
+coercibility(col1) collation(col1)
+4 utf8_general_ci
+create view v2 as select col1 from v1 union select col1 from t1;
+select coercibility(col1), collation(col1)from v2;
+coercibility(col1) collation(col1)
+2 utf8_unicode_ci
+2 utf8_unicode_ci
+drop view v1, v2;
+create view v1 as select 'v1_val' collate utf8_swedish_ci as col1;
+select coercibility(col1), collation(col1) from v1;
+coercibility(col1) collation(col1)
+0 utf8_swedish_ci
+create view v2 as select col1 from v1 union select col1 from t1;
+select coercibility(col1), collation(col1) from v2;
+coercibility(col1) collation(col1)
+0 utf8_swedish_ci
+0 utf8_swedish_ci
+drop view v1, v2;
+drop table t1;
CREATE TABLE t1 (
colA int(11) NOT NULL,
colB varchar(255) character set utf8 NOT NULL,
diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result
index 85894d5cb0e..7c9069791fa 100644
--- a/mysql-test/r/fulltext.result
+++ b/mysql-test/r/fulltext.result
@@ -372,10 +372,10 @@ t collation(t) FORMAT(MATCH t AGAINST ('Osnabruck'),6)
aus Osnabrück utf8_general_ci 1.591140
alter table t1 modify t varchar(200) collate latin1_german2_ci not null;
Warnings:
-Warning 1265 Data truncated for column 't' at row 3
-Warning 1265 Data truncated for column 't' at row 4
-Warning 1265 Data truncated for column 't' at row 5
-Warning 1265 Data truncated for column 't' at row 6
+Warning 1366 Incorrect string value: '\xD0\xAD\xD1\x82\xD0\xBE...' for column 't' at row 3
+Warning 1366 Incorrect string value: '\xD0\x9E\xD1\x82\xD0\xBB...' for column 't' at row 4
+Warning 1366 Incorrect string value: '\xD0\x9D\xD0\xB5 \xD0...' for column 't' at row 5
+Warning 1366 Incorrect string value: '\xD0\xB8 \xD0\xB1\xD1...' for column 't' at row 6
SELECT t, collation(t) FROM t1 WHERE MATCH t AGAINST ('Osnabrück');
t collation(t)
aus Osnabrück latin1_german2_ci
diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result
index 5dbbd891427..6989b89833b 100644
--- a/mysql-test/r/func_gconcat.result
+++ b/mysql-test/r/func_gconcat.result
@@ -658,3 +658,73 @@ GROUP_CONCAT(a) x
2 1,2
1 2,3
DROP TABLE t1;
+set names utf8;
+create table t1
+(
+x text character set utf8 not null,
+y integer not null
+);
+insert into t1 values (repeat('a', 1022), 0), (repeat(_utf8 0xc3b7, 4), 0);
+set group_concat_max_len= 1022 + 10;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1032 1031 1027 aaaaaaa,÷÷÷÷ C3B7C3B7C3B7
+set group_concat_max_len= 1022 + 9;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1031 1031 1027 aaaaaaa,÷÷÷÷ C3B7C3B7C3B7
+set group_concat_max_len= 1022 + 8;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1030 1029 1026 aaaaaaaa,÷÷÷ C3B7C3B7C3B7
+set group_concat_max_len= 1022 + 7;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1029 1029 1026 aaaaaaaa,÷÷÷ C3B7C3B7C3B7
+set group_concat_max_len= 1022 + 6;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1028 1027 1025 aaaaaaaaa,÷÷ 612CC3B7C3B7
+set group_concat_max_len= 1022 + 5;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1027 1027 1025 aaaaaaaaa,÷÷ 612CC3B7C3B7
+set group_concat_max_len= 1022 + 4;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1026 1025 1024 aaaaaaaaaa,÷ 6161612CC3B7
+set group_concat_max_len= 1022 + 3;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1025 1025 1024 aaaaaaaaaa,÷ 6161612CC3B7
+set group_concat_max_len= 1022 + 2;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1024 1023 1023 aaaaaaaaaaa, 61616161612C
+set group_concat_max_len= 1022 + 1;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1023 1023 1023 aaaaaaaaaaa, 61616161612C
+drop table t1;
+set group_concat_max_len=1024;
+set names latin1;
+create table t1 (f1 int unsigned, f2 varchar(255));
+insert into t1 values (1,repeat('a',255)),(2,repeat('b',255));
+select f2,group_concat(f1) from t1 group by f2;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def test t1 t1 f2 f2 253 255 255 Y 0 0 8
+def group_concat(f1) 252 1024 1 Y 128 0 63
+f2 group_concat(f1)
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1
+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 2
+drop table t1;
diff --git a/mysql-test/r/lowercase_table.result b/mysql-test/r/lowercase_table.result
index 7705961d08d..6df3cf61ddb 100644
--- a/mysql-test/r/lowercase_table.result
+++ b/mysql-test/r/lowercase_table.result
@@ -84,3 +84,27 @@ create table t2 like T1;
drop table t1, t2;
show tables;
Tables_in_test
+set names utf8;
+drop table if exists Ä°,Ä°Ä°;
+create table Ä° (s1 int);
+show create table Ä°;
+Table Create Table
+Ä° CREATE TABLE `i` (
+ `s1` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+show tables;
+Tables_in_test
+i
+drop table Ä°;
+create table Ä°Ä° (s1 int);
+show create table Ä°Ä°;
+Table Create Table
+Ä°Ä° CREATE TABLE `ii` (
+ `s1` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+show tables;
+Tables_in_test
+ii
+drop table Ä°Ä°;
+set names latin1;
+End of 5.0 tests
diff --git a/mysql-test/r/rpl_deadlock.result b/mysql-test/r/rpl_deadlock.result
index 541e12b806f..bea7fd81616 100644
--- a/mysql-test/r/rpl_deadlock.result
+++ b/mysql-test/r/rpl_deadlock.result
@@ -6,7 +6,7 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
create table t1 (a int not null, key(a)) engine=innodb;
create table t2 (a int not null, key(a)) engine=innodb;
-create table t3 (a int) engine=innodb;
+create table t3 (a int unique) engine=innodb;
create table t4 (a int) engine=innodb;
show variables like 'slave_transaction_retries';
Variable_name Value
@@ -35,14 +35,14 @@ begin;
select * from t1 for update;
a
start slave;
-insert into t2 values(22);
+insert into t2 values(201);
commit;
select * from t1;
a
1
select * from t2;
a
-22
+201
show slave status;
Slave_IO_State #
Master_Host 127.0.0.1
@@ -50,7 +50,7 @@ Master_User root
Master_Port MASTER_MYPORT
Connect_Retry 1
Master_Log_File master-bin.000001
-Read_Master_Log_Pos 18911
+Read_Master_Log_Pos 18918
Relay_Log_File #
Relay_Log_Pos #
Relay_Master_Log_File master-bin.000001
@@ -65,7 +65,7 @@ Replicate_Wild_Ignore_Table
Last_Errno 0
Last_Error
Skip_Counter 0
-Exec_Master_Log_Pos 18911
+Exec_Master_Log_Pos 18918
Relay_Log_Space #
Until_Condition None
Until_Log_File
@@ -78,12 +78,16 @@ Master_SSL_Cipher
Master_SSL_Key
Seconds_Behind_Master #
stop slave;
-change master to master_log_pos=532;
+delete from t3;
+change master to master_log_pos=539;
begin;
select * from t2 for update;
a
-22
+201
start slave;
+select count(*) from t3 /* must be zero */;
+count(*)
+0
commit;
select * from t1;
a
@@ -91,7 +95,7 @@ a
1
select * from t2;
a
-22
+201
show slave status;
Slave_IO_State #
Master_Host 127.0.0.1
@@ -99,7 +103,7 @@ Master_User root
Master_Port MASTER_MYPORT
Connect_Retry 1
Master_Log_File master-bin.000001
-Read_Master_Log_Pos 18911
+Read_Master_Log_Pos 18918
Relay_Log_File #
Relay_Log_Pos #
Relay_Master_Log_File master-bin.000001
@@ -114,7 +118,7 @@ Replicate_Wild_Ignore_Table
Last_Errno 0
Last_Error
Skip_Counter 0
-Exec_Master_Log_Pos 18911
+Exec_Master_Log_Pos 18918
Relay_Log_Space #
Until_Condition None
Until_Log_File
@@ -128,12 +132,16 @@ Master_SSL_Key
Seconds_Behind_Master #
set global max_relay_log_size=0;
stop slave;
-change master to master_log_pos=532;
+delete from t3;
+change master to master_log_pos=539;
begin;
select * from t2 for update;
a
-22
+201
start slave;
+select count(*) from t3 /* must be zero */;
+count(*)
+0
commit;
select * from t1;
a
@@ -142,7 +150,7 @@ a
1
select * from t2;
a
-22
+201
show slave status;
Slave_IO_State #
Master_Host 127.0.0.1
@@ -150,7 +158,7 @@ Master_User root
Master_Port MASTER_MYPORT
Connect_Retry 1
Master_Log_File master-bin.000001
-Read_Master_Log_Pos 18911
+Read_Master_Log_Pos 18918
Relay_Log_File #
Relay_Log_Pos #
Relay_Master_Log_File master-bin.000001
@@ -165,7 +173,7 @@ Replicate_Wild_Ignore_Table
Last_Errno 0
Last_Error
Skip_Counter 0
-Exec_Master_Log_Pos 18911
+Exec_Master_Log_Pos 18918
Relay_Log_Space #
Until_Condition None
Until_Log_File
diff --git a/mysql-test/r/rpl_ignore_table.result b/mysql-test/r/rpl_ignore_table.result
index 356a9dcb2f8..136cf5cc5eb 100644
--- a/mysql-test/r/rpl_ignore_table.result
+++ b/mysql-test/r/rpl_ignore_table.result
@@ -14,3 +14,19 @@ SELECT * FROM t4;
a
DROP TABLE t1;
DROP TABLE t4;
+DROP TABLE IF EXISTS t5;
+CREATE TABLE t5 (
+word varchar(50) collate utf8_unicode_ci NOT NULL default ''
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+SET @@session.character_set_client=33,@@session.collation_connection=192;
+CREATE TEMPORARY TABLE tmptbl504451f4258$1 (id INT NOT NULL) ENGINE=MEMORY;
+INSERT INTO t5 (word) VALUES ('TEST’');
+SELECT HEX(word) FROM t5;
+HEX(word)
+54455354E28099
+SELECT HEX(word) FROM t5;
+HEX(word)
+54455354E28099
+SELECT * FROM tmptbl504451f4258$1;
+ERROR 42S02: Table 'test.tmptbl504451f4258$1' doesn't exist
+DROP TABLE t5;
diff --git a/mysql-test/r/strict_autoinc_1myisam.result b/mysql-test/r/strict_autoinc_1myisam.result
index 5d3c2698cda..90a69bedc74 100644
--- a/mysql-test/r/strict_autoinc_1myisam.result
+++ b/mysql-test/r/strict_autoinc_1myisam.result
@@ -1,3 +1,4 @@
+drop table if exists t1;
set @org_mode=@@sql_mode;
create table t1
(
diff --git a/mysql-test/r/strict_autoinc_2innodb.result b/mysql-test/r/strict_autoinc_2innodb.result
index f1936ff4de3..8a5243173e4 100644
--- a/mysql-test/r/strict_autoinc_2innodb.result
+++ b/mysql-test/r/strict_autoinc_2innodb.result
@@ -1,3 +1,4 @@
+drop table if exists t1;
set @org_mode=@@sql_mode;
create table t1
(
diff --git a/mysql-test/r/strict_autoinc_3heap.result b/mysql-test/r/strict_autoinc_3heap.result
index aa0be270ac5..7dc48357c46 100644
--- a/mysql-test/r/strict_autoinc_3heap.result
+++ b/mysql-test/r/strict_autoinc_3heap.result
@@ -1,3 +1,4 @@
+drop table if exists t1;
set @org_mode=@@sql_mode;
create table t1
(
diff --git a/mysql-test/r/strict_autoinc_4bdb.result b/mysql-test/r/strict_autoinc_4bdb.result
index 73683b645e2..89c4d2537f5 100644
--- a/mysql-test/r/strict_autoinc_4bdb.result
+++ b/mysql-test/r/strict_autoinc_4bdb.result
@@ -1,3 +1,4 @@
+drop table if exists t1;
set @org_mode=@@sql_mode;
create table t1
(
diff --git a/mysql-test/r/strict_autoinc_5ndb.result b/mysql-test/r/strict_autoinc_5ndb.result
index d0d62d05b32..715f9a4b98b 100644
--- a/mysql-test/r/strict_autoinc_5ndb.result
+++ b/mysql-test/r/strict_autoinc_5ndb.result
@@ -1,3 +1,4 @@
+drop table if exists t1;
set @org_mode=@@sql_mode;
create table t1
(
diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test
index 6c814368c88..dedba4caf0f 100644
--- a/mysql-test/t/ctype_ucs.test
+++ b/mysql-test/t/ctype_ucs.test
@@ -455,6 +455,23 @@ drop table t1;
deallocate prepare stmt;
#
+# Bug#22052 Trailing spaces are not removed from UNICODE fields in an index
+#
+create table t1 (
+ a char(10) unicode not null,
+ index a (a)
+) engine=myisam;
+insert into t1 values (repeat(0x201f, 10));
+insert into t1 values (repeat(0x2020, 10));
+insert into t1 values (repeat(0x2021, 10));
+# make sure "index read" is used
+explain select hex(a) from t1 order by a;
+select hex(a) from t1 order by a;
+alter table t1 drop index a;
+select hex(a) from t1 order by a;
+drop table t1;
+
+#
# Bug #20076: server crashes for a query with GROUP BY if MIN/MAX aggregation
# over a 'ucs2' field uses a temporary table
#
diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index 812965d648a..71259dab0c9 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -1228,6 +1228,30 @@ set @a:=null;
execute my_stmt using @a;
drop table if exists t1;
+
+#
+# Bug#21505 Create view - illegal mix of collation for operation 'UNION'
+#
+--disable_warnings
+drop table if exists t1;
+drop view if exists v1, v2;
+--enable_warnings
+set names utf8;
+create table t1(col1 varchar(12) character set utf8 collate utf8_unicode_ci);
+insert into t1 values('t1_val');
+create view v1 as select 'v1_val' as col1;
+select coercibility(col1), collation(col1) from v1;
+create view v2 as select col1 from v1 union select col1 from t1;
+select coercibility(col1), collation(col1)from v2;
+drop view v1, v2;
+create view v1 as select 'v1_val' collate utf8_swedish_ci as col1;
+select coercibility(col1), collation(col1) from v1;
+create view v2 as select col1 from v1 union select col1 from t1;
+select coercibility(col1), collation(col1) from v2;
+drop view v1, v2;
+drop table t1;
+
+
#
# Bug#19960: Inconsistent results when joining
# InnoDB tables using partial UTF8 indexes
diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test
index 769f10277d4..610c93dfb0f 100644
--- a/mysql-test/t/func_gconcat.test
+++ b/mysql-test/t/func_gconcat.test
@@ -461,3 +461,38 @@ SELECT GROUP_CONCAT(a), x
GROUP BY x;
DROP TABLE t1;
+#
+# Bug#23451 GROUP_CONCAT truncates a multibyte utf8 character
+#
+set names utf8;
+create table t1
+(
+ x text character set utf8 not null,
+ y integer not null
+);
+insert into t1 values (repeat('a', 1022), 0), (repeat(_utf8 0xc3b7, 4), 0);
+let $1= 10;
+while ($1)
+{
+ eval set group_concat_max_len= 1022 + $1;
+ --disable_result_log
+ select @x:=group_concat(x) from t1 group by y;
+ --enable_result_log
+ select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+ dec $1;
+}
+drop table t1;
+set group_concat_max_len=1024;
+set names latin1;
+
+#
+# Bug#14169 type of group_concat() result changed to blob if tmp_table was used
+#
+create table t1 (f1 int unsigned, f2 varchar(255));
+insert into t1 values (1,repeat('a',255)),(2,repeat('b',255));
+--enable_metadata
+select f2,group_concat(f1) from t1 group by f2;
+--disable_metadata
+drop table t1;
+
+# End of 4.1 tests
diff --git a/mysql-test/t/lowercase_table.test b/mysql-test/t/lowercase_table.test
index 96437bc7636..31513f1bd06 100644
--- a/mysql-test/t/lowercase_table.test
+++ b/mysql-test/t/lowercase_table.test
@@ -85,3 +85,23 @@ drop table t1, t2;
show tables;
# End of 4.1 tests
+
+
+#
+# Bug#20404: SHOW CREATE TABLE fails with Turkish I
+#
+set names utf8;
+--disable_warnings
+drop table if exists Ä°,Ä°Ä°;
+--enable_warnings
+create table Ä° (s1 int);
+show create table Ä°;
+show tables;
+drop table Ä°;
+create table Ä°Ä° (s1 int);
+show create table Ä°Ä°;
+show tables;
+drop table Ä°Ä°;
+set names latin1;
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/rpl_deadlock.test b/mysql-test/t/rpl_deadlock.test
index 684cb54611c..6c5f942cec9 100644
--- a/mysql-test/t/rpl_deadlock.test
+++ b/mysql-test/t/rpl_deadlock.test
@@ -16,7 +16,8 @@ source include/master-slave.inc;
connection master;
create table t1 (a int not null, key(a)) engine=innodb;
create table t2 (a int not null, key(a)) engine=innodb;
-create table t3 (a int) engine=innodb;
+# requiring 'unique' for the timeout part of the test
+create table t3 (a int unique) engine=innodb;
create table t4 (a int) engine=innodb;
show variables like 'slave_transaction_retries';
sync_slave_with_master;
@@ -31,8 +32,7 @@ stop slave;
connection master;
begin;
# Let's keep BEGIN and the locked statement in two different relay logs.
-let $1=200;
-disable_query_log;
+let $1=200;disable_query_log;
while ($1)
{
eval insert into t3 values( $1 );
@@ -59,7 +59,7 @@ enable_query_log;
select * from t1 for update;
start slave;
--real_sleep 3 # hope that slave is blocked now
-insert into t2 values(22); # provoke deadlock, slave should be victim
+insert into t2 values(201); # provoke deadlock, slave should be victim
commit;
sync_with_master;
select * from t1; # check that slave succeeded finally
@@ -74,11 +74,13 @@ show slave status;
# 2) Test lock wait timeout
stop slave;
-change master to master_log_pos=532; # the BEGIN log event
+delete from t3;
+change master to master_log_pos=539; # the BEGIN log event
begin;
select * from t2 for update; # hold lock
start slave;
--real_sleep 10 # slave should have blocked, and be retrying
+select count(*) from t3 /* must be zero */; # replaying begins after rollback
commit;
sync_with_master;
select * from t1; # check that slave succeeded finally
@@ -97,11 +99,13 @@ set global max_relay_log_size=0;
# This is really copy-paste of 2) of above
stop slave;
-change master to master_log_pos=532;
+delete from t3;
+change master to master_log_pos=539;
begin;
select * from t2 for update;
start slave;
--real_sleep 10
+select count(*) from t3 /* must be zero */; # replaying begins after rollback
commit;
sync_with_master;
select * from t1;
diff --git a/mysql-test/t/rpl_ignore_table-slave.opt b/mysql-test/t/rpl_ignore_table-slave.opt
index cb49119bfcb..3aabbb2e0f5 100644
--- a/mysql-test/t/rpl_ignore_table-slave.opt
+++ b/mysql-test/t/rpl_ignore_table-slave.opt
@@ -1 +1 @@
---replicate-ignore-table=test.t1 --replicate-ignore-table=test.t2 --replicate-ignore-table=test.t3
+--replicate-ignore-table=test.t1 --replicate-ignore-table=test.t2 --replicate-ignore-table=test.t3 --replicate-wild-ignore-table=%.tmptbl%
diff --git a/mysql-test/t/rpl_ignore_table.test b/mysql-test/t/rpl_ignore_table.test
index bc651779208..b875075f71c 100644
--- a/mysql-test/t/rpl_ignore_table.test
+++ b/mysql-test/t/rpl_ignore_table.test
@@ -26,3 +26,26 @@ SELECT * FROM t4;
connection master;
DROP TABLE t1;
DROP TABLE t4;
+
+
+#
+# bug#22877 replication character sets get out of sync
+# using replicate-wild-ignore-table
+#
+--disable_warnings
+DROP TABLE IF EXISTS t5;
+--enable_warnings
+CREATE TABLE t5 (
+ word varchar(50) collate utf8_unicode_ci NOT NULL default ''
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+SET @@session.character_set_client=33,@@session.collation_connection=192;
+CREATE TEMPORARY TABLE tmptbl504451f4258$1 (id INT NOT NULL) ENGINE=MEMORY;
+INSERT INTO t5 (word) VALUES ('TEST’');
+SELECT HEX(word) FROM t5;
+sync_slave_with_master;
+connection slave;
+SELECT HEX(word) FROM t5;
+--error 1146
+SELECT * FROM tmptbl504451f4258$1;
+connection master;
+DROP TABLE t5;
diff --git a/sql/field.cc b/sql/field.cc
index ec97bc92d24..f04efc66dfd 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1399,6 +1399,7 @@ Field_str::Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
field_charset=charset;
if (charset->state & MY_CS_BINSORT)
flags|=BINARY_FLAG;
+ field_derivation= DERIVATION_IMPLICIT;
}
@@ -5783,37 +5784,148 @@ void Field_datetime::sql_type(String &res) const
** A string may be varchar or binary
****************************************************************************/
+/*
+ Report "not well formed" or "cannot convert" error
+ after storing a character string info a field.
+
+ SYNOPSIS
+ check_string_copy_error()
+ field - Field
+ well_formed_error_pos - where not well formed data was first met
+ cannot_convert_error_pos - where a not-convertable character was first met
+ end - end of the string
+
+ NOTES
+ As of version 5.0 both cases return the same error:
+
+ "Invalid string value: 'xxx' for column 't' at row 1"
+
+ Future versions will possibly introduce a new error message:
+
+ "Cannot convert character string: 'xxx' for column 't' at row 1"
+
+ RETURN
+ FALSE - If errors didn't happen
+ TRUE - If an error happened
+*/
+
+static bool
+check_string_copy_error(Field_str *field,
+ const char *well_formed_error_pos,
+ const char *cannot_convert_error_pos,
+ const char *end)
+{
+ const char *pos, *end_orig;
+ char tmp[64], *t;
+
+ if (!(pos= well_formed_error_pos) &&
+ !(pos= cannot_convert_error_pos))
+ return FALSE;
+
+ end_orig= end;
+ set_if_smaller(end, pos + 6);
+
+ for (t= tmp; pos < end; pos++)
+ {
+ if (((unsigned char) *pos) >= 0x20 &&
+ ((unsigned char) *pos) <= 0x7F)
+ {
+ *t++= *pos;
+ }
+ else
+ {
+ *t++= '\\';
+ *t++= 'x';
+ *t++= _dig_vec_upper[((unsigned char) *pos) >> 4];
+ *t++= _dig_vec_upper[((unsigned char) *pos) & 15];
+ }
+ }
+ if (end_orig > end)
+ {
+ *t++= '.';
+ *t++= '.';
+ *t++= '.';
+ }
+ *t= '\0';
+ push_warning_printf(field->table->in_use,
+ field->table->in_use->abort_on_warning ?
+ MYSQL_ERROR::WARN_LEVEL_ERROR :
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
+ ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
+ "string", tmp, field->field_name,
+ (ulong) field->table->in_use->row_count);
+ return TRUE;
+}
+
+
+
+/*
+ Send a truncation warning or a truncation error
+ after storing a too long character string info a field.
+
+ SYNOPSIS
+ report_data_too_long()
+ field - Field
+
+ RETURN
+ N/A
+*/
+
+inline void
+report_data_too_long(Field_str *field)
+{
+ if (field->table->in_use->abort_on_warning)
+ field->set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
+ else
+ field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
+}
+
+
+/*
+ Test if the given string contains important data:
+ not spaces for character string,
+ or any data for binary string.
+
+ SYNOPSIS
+ test_if_important_data()
+ cs Character set
+ str String to test
+ strend String end
+
+ RETURN
+ FALSE - If string does not have important data
+ TRUE - If string has some important data
+*/
+
+static bool
+test_if_important_data(CHARSET_INFO *cs, const char *str, const char *strend)
+{
+ if (cs != &my_charset_bin)
+ str+= cs->cset->scan(cs, str, strend, MY_SEQ_SPACES);
+ return (str < strend);
+}
+
+
/* Copy a string and fill with space */
int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
{
- int error= 0, well_formed_error;
- uint32 not_used;
- char buff[STRING_BUFFER_USUAL_SIZE];
- String tmpstr(buff,sizeof(buff), &my_charset_bin);
uint copy_length;
+ const char *well_formed_error_pos;
+ const char *cannot_convert_error_pos;
+ const char *from_end_pos;
/* See the comment for Field_long::store(long long) */
DBUG_ASSERT(table->in_use == current_thd);
- /* Convert character set if necessary */
- if (String::needs_conversion(length, cs, field_charset, &not_used))
- {
- uint conv_errors;
- tmpstr.copy(from, length, cs, field_charset, &conv_errors);
- from= tmpstr.ptr();
- length= tmpstr.length();
- if (conv_errors)
- error= 2;
- }
-
- /* Make sure we don't break a multibyte sequence or copy malformed data. */
- copy_length= field_charset->cset->well_formed_len(field_charset,
- from,from+length,
- field_length/
- field_charset->mbmaxlen,
- &well_formed_error);
- memmove(ptr, from, copy_length);
+ copy_length= well_formed_copy_nchars(field_charset,
+ ptr, field_length,
+ cs, from, length,
+ field_length / field_charset->mbmaxlen,
+ &well_formed_error_pos,
+ &cannot_convert_error_pos,
+ &from_end_pos);
/* Append spaces if the string was shorter than the field. */
if (copy_length < field_length)
@@ -5821,32 +5933,23 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
field_length-copy_length,
field_charset->pad_char);
+ if (check_string_copy_error(this, well_formed_error_pos,
+ cannot_convert_error_pos, from + length))
+ return 2;
+
/*
Check if we lost any important data (anything in a binary string,
or any non-space in others).
*/
- if ((copy_length < length) && table->in_use->count_cuted_fields)
+ if ((from_end_pos < from + length) && table->in_use->count_cuted_fields)
{
- if (binary())
- error= 2;
- else
+ if (test_if_important_data(field_charset, from_end_pos, from + length))
{
- const char *end=from+length;
- from+= copy_length;
- from+= field_charset->cset->scan(field_charset, from, end,
- MY_SEQ_SPACES);
- if (from != end)
- error= 2;
+ report_data_too_long(this);
+ return 2;
}
}
- if (error)
- {
- if (table->in_use->abort_on_warning)
- set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
- else
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
- }
- return error;
+ return 0;
}
@@ -6179,58 +6282,35 @@ Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table,
int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
{
- uint32 not_used, copy_length;
- char buff[STRING_BUFFER_USUAL_SIZE];
- String tmpstr(buff,sizeof(buff), &my_charset_bin);
- int error_code= 0, well_formed_error;
- enum MYSQL_ERROR::enum_warning_level level= MYSQL_ERROR::WARN_LEVEL_WARN;
+ uint copy_length;
+ const char *well_formed_error_pos;
+ const char *cannot_convert_error_pos;
+ const char *from_end_pos;
+
+ copy_length= well_formed_copy_nchars(field_charset,
+ ptr + length_bytes, field_length,
+ cs, from, length,
+ field_length / field_charset->mbmaxlen,
+ &well_formed_error_pos,
+ &cannot_convert_error_pos,
+ &from_end_pos);
- /* Convert character set if necessary */
- if (String::needs_conversion(length, cs, field_charset, &not_used))
- {
- uint conv_errors;
- tmpstr.copy(from, length, cs, field_charset, &conv_errors);
- from= tmpstr.ptr();
- length= tmpstr.length();
- if (conv_errors)
- error_code= WARN_DATA_TRUNCATED;
- }
- /*
- Make sure we don't break a multibyte sequence
- as well as don't copy a malformed data.
- */
- copy_length= field_charset->cset->well_formed_len(field_charset,
- from,from+length,
- field_length/
- field_charset->mbmaxlen,
- &well_formed_error);
- memmove(ptr + length_bytes, from, copy_length);
if (length_bytes == 1)
*ptr= (uchar) copy_length;
else
int2store(ptr, copy_length);
+ if (check_string_copy_error(this, well_formed_error_pos,
+ cannot_convert_error_pos, from + length))
+ return 2;
+
// Check if we lost something other than just trailing spaces
- if ((copy_length < length) && table->in_use->count_cuted_fields &&
- !error_code)
- {
- if (!binary())
- {
- const char *end= from + length;
- from+= copy_length;
- from+= field_charset->cset->scan(field_charset, from, end, MY_SEQ_SPACES);
- /* If we lost only spaces then produce a NOTE, not a WARNING */
- if (from == end)
- level= MYSQL_ERROR::WARN_LEVEL_NOTE;
- }
- error_code= WARN_DATA_TRUNCATED;
- }
- if (error_code)
+ if ((from_end_pos < from + length) && table->in_use->count_cuted_fields)
{
- if (level == MYSQL_ERROR::WARN_LEVEL_WARN &&
- table->in_use->abort_on_warning)
- error_code= ER_DATA_TOO_LONG;
- set_warning(level, error_code, 1);
+ if (test_if_important_data(field_charset, from_end_pos, from + length))
+ report_data_too_long(this);
+ else /* If we lost only spaces then produce a NOTE, not a WARNING */
+ set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1);
return 2;
}
return 0;
@@ -6812,68 +6892,70 @@ void Field_blob::put_length(char *pos, uint32 length)
int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
{
- int error= 0, well_formed_error;
+ uint copy_length, new_length;
+ const char *well_formed_error_pos;
+ const char *cannot_convert_error_pos;
+ const char *from_end_pos, *tmp;
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String tmpstr(buff,sizeof(buff), &my_charset_bin);
+
if (!length)
{
bzero(ptr,Field_blob::pack_length());
+ return 0;
}
- else
- {
- bool was_conversion;
- char buff[STRING_BUFFER_USUAL_SIZE];
- String tmpstr(buff,sizeof(buff), &my_charset_bin);
- uint copy_length;
- uint32 not_used;
- /* Convert character set if necessary */
- if ((was_conversion= String::needs_conversion(length, cs, field_charset,
- &not_used)))
- {
- uint conv_errors;
- if (tmpstr.copy(from, length, cs, field_charset, &conv_errors))
- {
- /* Fatal OOM error */
- bzero(ptr,Field_blob::pack_length());
- return -1;
- }
- from= tmpstr.ptr();
- length= tmpstr.length();
- if (conv_errors)
- error= 2;
- }
-
- copy_length= max_data_length();
- /*
- copy_length is OK as last argument to well_formed_len as this is never
- used to limit the length of the data. The cut of long data is done with
- the 'min()' call below.
- */
- copy_length= field_charset->cset->well_formed_len(field_charset,
- from,from +
- min(length, copy_length),
- copy_length,
- &well_formed_error);
- if (copy_length < length)
- error= 2;
- Field_blob::store_length(copy_length);
- if (was_conversion || table->copy_blobs || copy_length <= MAX_FIELD_WIDTH)
- { // Must make a copy
- if (from != value.ptr()) // For valgrind
- {
- value.copy(from,copy_length,charset());
- from=value.ptr();
- }
+ if (from == value.ptr())
+ {
+ uint32 dummy_offset;
+ if (!String::needs_conversion(length, cs, field_charset, &dummy_offset))
+ {
+ Field_blob::store_length(length);
+ bmove(ptr+packlength,(char*) &from,sizeof(char*));
+ return 0;
}
- bmove(ptr+packlength,(char*) &from,sizeof(char*));
+ if (tmpstr.copy(from, length, cs))
+ goto oom_error;
+ from= tmpstr.ptr();
}
- if (error)
+
+ new_length= min(max_data_length(), field_charset->mbmaxlen * length);
+ if (value.alloc(new_length))
+ goto oom_error;
+
+ /*
+ "length" is OK as "nchars" argument to well_formed_copy_nchars as this
+ is never used to limit the length of the data. The cut of long data
+ is done with the new_length value.
+ */
+ copy_length= well_formed_copy_nchars(field_charset,
+ (char*) value.ptr(), new_length,
+ cs, from, length,
+ length,
+ &well_formed_error_pos,
+ &cannot_convert_error_pos,
+ &from_end_pos);
+
+ Field_blob::store_length(copy_length);
+ tmp= value.ptr();
+ bmove(ptr+packlength,(char*) &tmp,sizeof(char*));
+
+ if (check_string_copy_error(this, well_formed_error_pos,
+ cannot_convert_error_pos, from + length))
+ return 2;
+
+ if (copy_length < length)
{
- if (table->in_use->abort_on_warning)
- set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
- else
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
+ report_data_too_long(this);
+ return 2;
}
+
return 0;
+
+oom_error:
+ /* Fatal OOM error */
+ bzero(ptr,Field_blob::pack_length());
+ return -1;
}
diff --git a/sql/field.h b/sql/field.h
index b79c2bf77a8..0f845f6c2f9 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -302,6 +302,9 @@ public:
virtual CHARSET_INFO *sort_charset(void) const { return charset(); }
virtual bool has_charset(void) const { return FALSE; }
virtual void set_charset(CHARSET_INFO *charset) { }
+ virtual enum Derivation derivation(void) const
+ { return DERIVATION_IMPLICIT; }
+ virtual void set_derivation(enum Derivation derivation) { }
bool set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code,
int cuted_increment);
bool check_int(const char *str, int length, const char *int_end,
@@ -373,6 +376,7 @@ public:
class Field_str :public Field {
protected:
CHARSET_INFO *field_charset;
+ enum Derivation field_derivation;
public:
Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
@@ -387,6 +391,9 @@ public:
uint size_of() const { return sizeof(*this); }
CHARSET_INFO *charset(void) const { return field_charset; }
void set_charset(CHARSET_INFO *charset) { field_charset=charset; }
+ enum Derivation derivation(void) const { return field_derivation; }
+ virtual void set_derivation(enum Derivation derivation_arg)
+ { field_derivation= derivation_arg; }
bool binary() const { return field_charset == &my_charset_bin; }
uint32 max_length() { return field_length; }
friend class create_field;
diff --git a/sql/item.cc b/sql/item.cc
index d56ca95093b..f3081551299 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1622,7 +1622,7 @@ void Item_field::set_field(Field *field_par)
db_name= field_par->table->s->db;
alias_name_used= field_par->table->alias_name_used;
unsigned_flag=test(field_par->flags & UNSIGNED_FLAG);
- collation.set(field_par->charset(), DERIVATION_IMPLICIT);
+ collation.set(field_par->charset(), field_par->derivation());
fixed= 1;
}
diff --git a/sql/item.h b/sql/item.h
index 0cfb0b01fd8..b5490f9e814 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -27,19 +27,7 @@ class Item_field;
/*
"Declared Type Collation"
A combination of collation and its derivation.
-*/
-enum Derivation
-{
- DERIVATION_IGNORABLE= 5,
- DERIVATION_COERCIBLE= 4,
- DERIVATION_SYSCONST= 3,
- DERIVATION_IMPLICIT= 2,
- DERIVATION_NONE= 1,
- DERIVATION_EXPLICIT= 0
-};
-
-/*
Flags for collation aggregation modes:
MY_COLL_ALLOW_SUPERSET_CONV - allow conversion to a superset
MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 77c6e17607f..f1e0001c994 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -3001,6 +3001,7 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)),
String tmp2;
String *result= &item->result;
Item **arg= item->args, **arg_end= item->args + item->arg_count_field;
+ uint old_length= result->length();
if (item->no_appended)
item->no_appended= FALSE;
@@ -3035,8 +3036,22 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)),
/* stop if length of result more than max_length */
if (result->length() > item->max_length)
{
+ int well_formed_error;
+ CHARSET_INFO *cs= item->collation.collation;
+ const char *ptr= result->ptr();
+ uint add_length;
+ /*
+ It's ok to use item->result.length() as the fourth argument
+ as this is never used to limit the length of the data.
+ Cut is done with the third argument.
+ */
+ add_length= cs->cset->well_formed_len(cs,
+ ptr + old_length,
+ ptr + item->max_length,
+ result->length(),
+ &well_formed_error);
+ result->length(old_length + add_length);
item->count_cut_values++;
- result->length(item->max_length);
item->warning_for_row= TRUE;
return 1;
}
@@ -3226,8 +3241,7 @@ bool Item_func_group_concat::add()
we can dump the row here in case of GROUP_CONCAT(DISTINCT...)
instead of doing tree traverse later.
*/
- if (result.length() <= max_length &&
- !warning_for_row &&
+ if (!warning_for_row &&
(!tree || (el->count == 1 && distinct && !arg_count_order)))
dump_leaf_key(table->record[0] + table->s->null_bytes, 1, this);
@@ -3296,7 +3310,8 @@ bool Item_func_group_concat::setup(THD *thd)
DBUG_RETURN(TRUE);
/* We'll convert all blobs to varchar fields in the temporary table */
- tmp_table_param->convert_blob_length= max_length;
+ tmp_table_param->convert_blob_length= max_length *
+ collation.collation->mbmaxlen;
/* Push all not constant fields to the list and create a temp table */
always_null= 0;
for (uint i= 0; i < arg_count_field; i++)
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index cd6c2a73ccc..ac0b9f56567 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -96,6 +96,17 @@ extern CHARSET_INFO *system_charset_info, *files_charset_info ;
extern CHARSET_INFO *national_charset_info, *table_alias_charset;
+enum Derivation
+{
+ DERIVATION_IGNORABLE= 5,
+ DERIVATION_COERCIBLE= 4,
+ DERIVATION_SYSCONST= 3,
+ DERIVATION_IMPLICIT= 2,
+ DERIVATION_NONE= 1,
+ DERIVATION_EXPLICIT= 0
+};
+
+
typedef struct my_locale_st
{
const char *name;
diff --git a/sql/slave.cc b/sql/slave.cc
index e3497a4f0ac..25ea918f02f 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -3347,9 +3347,9 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
const char *errmsg;
/*
We were in a transaction which has been rolled back because of a
- deadlock (currently, InnoDB deadlock detected by InnoDB) or lock
- wait timeout (innodb_lock_wait_timeout exceeded); let's seek back to
- BEGIN log event and retry it all again.
+ Sonera deadlock. if lock wait timeout (innodb_lock_wait_timeout exceeded)
+ there is no rollback since 5.0.13 (ref: manual).
+ let's seek back to BEGIN log event and retry it all again.
We have to not only seek but also
a) init_master_info(), to seek back to hot relay log's start for later
(for when we will come back to this hot log after re-processing the
@@ -3371,6 +3371,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
else
{
exec_res= 0;
+ end_trans(thd, ROLLBACK);
/* chance for concurrent connection to get more locks */
safe_sleep(thd, min(rli->trans_retries, MAX_SLAVE_RETRY_PAUSE),
(CHECK_KILLED_FUNC)sql_slave_killed, (void*)rli);
@@ -3388,9 +3389,17 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
"the slave_transaction_retries variable.",
slave_trans_retries);
}
- if (!((thd->options & OPTION_BEGIN) && opt_using_transactions))
- rli->trans_retries= 0; // restart from fresh
- }
+ else if (!((thd->options & OPTION_BEGIN) && opt_using_transactions))
+ {
+ /*
+ Only reset the retry counter if the event succeeded or
+ failed with a non-transient error. On a successful event,
+ the execution will proceed as usual; in the case of a
+ non-transient error, the slave will stop with an error.
+ */
+ rli->trans_retries= 0; // restart from fresh
+ }
+ }
return exec_res;
}
else
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 3a107c2296c..e3ee9f340cf 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2503,7 +2503,23 @@ mysql_execute_command(THD *thd)
{
/* we warn the slave SQL thread */
my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
- reset_one_shot_variables(thd);
+ if (thd->one_shot_set)
+ {
+ /*
+ It's ok to check thd->one_shot_set here:
+
+ The charsets in a MySQL 5.0 slave can change by both a binlogged
+ SET ONE_SHOT statement and the event-internal charset setting,
+ and these two ways to change charsets do not seems to work
+ together.
+
+ At least there seems to be problems in the rli cache for
+ charsets if we are using ONE_SHOT. Note that this is normally no
+ problem because either the >= 5.0 slave reads a 4.1 binlog (with
+ ONE_SHOT) *or* or 5.0 binlog (without ONE_SHOT) but never both."
+ */
+ reset_one_shot_variables(thd);
+ }
DBUG_RETURN(0);
}
}
@@ -6121,7 +6137,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->alias= alias_str;
if (lower_case_table_names && table->table.length)
- my_casedn_str(files_charset_info, table->table.str);
+ table->table.length= my_casedn_str(files_charset_info, table->table.str);
ptr->table_name=table->table.str;
ptr->table_name_length=table->table.length;
ptr->lock_type= lock_type;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 75cfff4cbb6..abadd0697ac 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -8560,6 +8560,7 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
item->collation.collation);
else
new_field= item->make_string_field(table);
+ new_field->set_derivation(item->collation.derivation);
break;
case DECIMAL_RESULT:
new_field= new Field_new_decimal(item->max_length, maybe_null, item->name,
@@ -8735,7 +8736,9 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
(make_copy_field ? 0 : copy_func),
modify_item, convert_blob_length);
case Item::TYPE_HOLDER:
- return ((Item_type_holder *)item)->make_field_by_type(table);
+ result= ((Item_type_holder *)item)->make_field_by_type(table);
+ result->set_derivation(item->collation.derivation);
+ return result;
default: // Dosen't have to be stored
return 0;
}
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 7aaca809113..85ff1fddc45 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -854,6 +854,162 @@ outp:
}
+/*
+ copy a string,
+ with optional character set conversion,
+ with optional left padding (for binary -> UCS2 conversion)
+
+ SYNOPSIS
+ well_formed_copy_nhars()
+ to Store result here
+ to_length Maxinum length of "to" string
+ to_cs Character set of "to" string
+ from Copy from here
+ from_length Length of from string
+ from_cs From character set
+ nchars Copy not more that nchars characters
+ well_formed_error_pos Return position when "from" is not well formed
+ or NULL otherwise.
+ cannot_convert_error_pos Return position where a not convertable
+ character met, or NULL otherwise.
+ from_end_pos Return position where scanning of "from"
+ string stopped.
+ NOTES
+
+ RETURN
+ length of bytes copied to 'to'
+*/
+
+
+uint32
+well_formed_copy_nchars(CHARSET_INFO *to_cs,
+ char *to, uint to_length,
+ CHARSET_INFO *from_cs,
+ const char *from, uint from_length,
+ uint nchars,
+ const char **well_formed_error_pos,
+ const char **cannot_convert_error_pos,
+ const char **from_end_pos)
+{
+ uint res;
+
+ if ((to_cs == &my_charset_bin) ||
+ (from_cs == &my_charset_bin) ||
+ (to_cs == from_cs) ||
+ my_charset_same(from_cs, to_cs))
+ {
+ if (to_length < to_cs->mbminlen || !nchars)
+ {
+ *from_end_pos= from;
+ *cannot_convert_error_pos= NULL;
+ *well_formed_error_pos= NULL;
+ return 0;
+ }
+
+ if (to_cs == &my_charset_bin)
+ {
+ res= min(min(nchars, to_length), from_length);
+ memmove(to, from, res);
+ *from_end_pos= from + res;
+ *well_formed_error_pos= NULL;
+ *cannot_convert_error_pos= NULL;
+ }
+ else
+ {
+ int well_formed_error;
+ uint from_offset;
+
+ if ((from_offset= (from_length % to_cs->mbminlen)) &&
+ (from_cs == &my_charset_bin))
+ {
+ /*
+ Copying from BINARY to UCS2 needs to prepend zeros sometimes:
+ INSERT INTO t1 (ucs2_column) VALUES (0x01);
+ 0x01 -> 0x0001
+ */
+ uint pad_length= to_cs->mbminlen - from_offset;
+ bzero(to, pad_length);
+ memmove(to + pad_length, from, from_offset);
+ nchars--;
+ from+= from_offset;
+ from_length-= from_offset;
+ to+= to_cs->mbminlen;
+ to_length-= to_cs->mbminlen;
+ }
+
+ set_if_smaller(from_length, to_length);
+ res= to_cs->cset->well_formed_len(to_cs, from, from + from_length,
+ nchars, &well_formed_error);
+ memmove(to, from, res);
+ *from_end_pos= from + res;
+ *well_formed_error_pos= well_formed_error ? from + res : NULL;
+ *cannot_convert_error_pos= NULL;
+ if (from_offset)
+ res+= to_cs->mbminlen;
+ }
+ }
+ else
+ {
+ int cnvres;
+ my_wc_t wc;
+ int (*mb_wc)(struct charset_info_st *, my_wc_t *,
+ const uchar *, const uchar *)= from_cs->cset->mb_wc;
+ int (*wc_mb)(struct charset_info_st *, my_wc_t,
+ uchar *s, uchar *e)= to_cs->cset->wc_mb;
+ const uchar *from_end= (const uchar*) from + from_length;
+ uchar *to_end= (uchar*) to + to_length;
+ char *to_start= to;
+ *well_formed_error_pos= NULL;
+ *cannot_convert_error_pos= NULL;
+
+ for ( ; nchars; nchars--)
+ {
+ const char *from_prev= from;
+ if ((cnvres= (*mb_wc)(from_cs, &wc, (uchar*) from, from_end)) > 0)
+ from+= cnvres;
+ else if (cnvres == MY_CS_ILSEQ)
+ {
+ if (!*well_formed_error_pos)
+ *well_formed_error_pos= from;
+ from++;
+ wc= '?';
+ }
+ else if (cnvres > MY_CS_TOOSMALL)
+ {
+ /*
+ A correct multibyte sequence detected
+ But it doesn't have Unicode mapping.
+ */
+ if (!*cannot_convert_error_pos)
+ *cannot_convert_error_pos= from;
+ from+= (-cnvres);
+ wc= '?';
+ }
+ else
+ break; // Not enough characters
+
+outp:
+ if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0)
+ to+= cnvres;
+ else if (cnvres == MY_CS_ILUNI && wc != '?')
+ {
+ if (!*cannot_convert_error_pos)
+ *cannot_convert_error_pos= from_prev;
+ wc= '?';
+ goto outp;
+ }
+ else
+ break;
+ }
+ *from_end_pos= from;
+ res= to - to_start;
+ }
+ return (uint32) res;
+}
+
+
+
+
void String::print(String *str)
{
char *st= (char*)Ptr, *end= st+str_length;
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 0659f684afe..09b8478adf8 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -32,6 +32,14 @@ String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
const char *from, uint32 from_length,
CHARSET_INFO *from_cs, uint *errors);
+uint32 well_formed_copy_nchars(CHARSET_INFO *to_cs,
+ char *to, uint to_length,
+ CHARSET_INFO *from_cs,
+ const char *from, uint from_length,
+ uint nchars,
+ const char **well_formed_error_pos,
+ const char **cannot_convert_error_pos,
+ const char **from_end_pos);
class String
{
diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c
index 0bd5a1fda76..3e8b05580f6 100644
--- a/strings/ctype-bin.c
+++ b/strings/ctype-bin.c
@@ -211,9 +211,10 @@ static int my_strnncollsp_8bit_bin(CHARSET_INFO * cs __attribute__((unused)),
/* This function is used for all conversion functions */
-static void my_case_str_bin(CHARSET_INFO *cs __attribute__((unused)),
+static uint my_case_str_bin(CHARSET_INFO *cs __attribute__((unused)),
char *str __attribute__((unused)))
{
+ return 0;
}
static uint my_case_bin(CHARSET_INFO *cs __attribute__((unused)),
diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c
index 394111be3bc..3ef245015d7 100644
--- a/strings/ctype-mb.c
+++ b/strings/ctype-mb.c
@@ -21,40 +21,44 @@
#ifdef USE_MB
-void my_caseup_str_mb(CHARSET_INFO * cs, char *str)
+uint my_caseup_str_mb(CHARSET_INFO * cs, char *str)
{
register uint32 l;
- register uchar *map=cs->to_upper;
+ register uchar *map= cs->to_upper;
+ char *str_orig= str;
while (*str)
{
/* Pointing after the '\0' is safe here. */
- if ((l=my_ismbchar(cs, str, str + cs->mbmaxlen)))
- str+=l;
+ if ((l= my_ismbchar(cs, str, str + cs->mbmaxlen)))
+ str+= l;
else
{
- *str=(char) map[(uchar)*str];
+ *str= (char) map[(uchar)*str];
str++;
}
}
+ return str - str_orig;
}
-void my_casedn_str_mb(CHARSET_INFO * cs, char *str)
+uint my_casedn_str_mb(CHARSET_INFO * cs, char *str)
{
register uint32 l;
- register uchar *map=cs->to_lower;
+ register uchar *map= cs->to_lower;
+ char *str_orig= str;
while (*str)
{
/* Pointing after the '\0' is safe here. */
- if ((l=my_ismbchar(cs, str, str + cs->mbmaxlen)))
- str+=l;
+ if ((l= my_ismbchar(cs, str, str + cs->mbmaxlen)))
+ str+= l;
else
{
- *str=(char) map[(uchar)*str];
+ *str= (char) map[(uchar)*str];
str++;
}
}
+ return str - str_orig;
}
uint my_caseup_mb(CHARSET_INFO * cs, char *src, uint srclen,
diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c
index e40a1948dcf..7484f3c0d92 100644
--- a/strings/ctype-simple.c
+++ b/strings/ctype-simple.c
@@ -188,20 +188,26 @@ int my_strnncollsp_simple(CHARSET_INFO * cs, const uchar *a, uint a_length,
}
-void my_caseup_str_8bit(CHARSET_INFO * cs,char *str)
+uint my_caseup_str_8bit(CHARSET_INFO * cs,char *str)
{
- register uchar *map=cs->to_upper;
- while ((*str = (char) map[(uchar) *str]) != 0)
+ register uchar *map= cs->to_upper;
+ char *str_orig= str;
+ while ((*str= (char) map[(uchar) *str]) != 0)
str++;
+ return str - str_orig;
}
-void my_casedn_str_8bit(CHARSET_INFO * cs,char *str)
+
+uint my_casedn_str_8bit(CHARSET_INFO * cs,char *str)
{
- register uchar *map=cs->to_lower;
- while ((*str = (char) map[(uchar)*str]) != 0)
+ register uchar *map= cs->to_lower;
+ char *str_orig= str;
+ while ((*str= (char) map[(uchar) *str]) != 0)
str++;
+ return str - str_orig;
}
+
uint my_caseup_8bit(CHARSET_INFO * cs, char *src, uint srclen,
char *dst __attribute__((unused)),
uint dstlen __attribute__((unused)))
diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c
index 4a60220f73e..3c69a314b45 100644
--- a/strings/ctype-ucs2.c
+++ b/strings/ctype-ucs2.c
@@ -159,13 +159,13 @@ static void my_hash_sort_ucs2(CHARSET_INFO *cs, const uchar *s, uint slen,
}
-static void my_caseup_str_ucs2(CHARSET_INFO * cs __attribute__((unused)),
+static uint my_caseup_str_ucs2(CHARSET_INFO * cs __attribute__((unused)),
char * s __attribute__((unused)))
{
+ return 0;
}
-
static uint my_casedn_ucs2(CHARSET_INFO *cs, char *src, uint srclen,
char *dst __attribute__((unused)),
uint dstlen __attribute__((unused)))
@@ -188,9 +188,11 @@ static uint my_casedn_ucs2(CHARSET_INFO *cs, char *src, uint srclen,
return srclen;
}
-static void my_casedn_str_ucs2(CHARSET_INFO *cs __attribute__((unused)),
+
+static uint my_casedn_str_ucs2(CHARSET_INFO *cs __attribute__((unused)),
char * s __attribute__((unused)))
{
+ return 0;
}
diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c
index ae2c04fb068..a21fe4961ec 100644
--- a/strings/ctype-utf8.c
+++ b/strings/ctype-utf8.c
@@ -2045,6 +2045,52 @@ static int my_utf8_uni(CHARSET_INFO *cs __attribute__((unused)),
return MY_CS_ILSEQ;
}
+
+/*
+ The same as above, but without range check
+ for example, for a null-terminated string
+*/
+static int my_utf8_uni_no_range(CHARSET_INFO *cs __attribute__((unused)),
+ my_wc_t * pwc, const uchar *s)
+{
+ unsigned char c;
+
+ c= s[0];
+ if (c < 0x80)
+ {
+ *pwc = c;
+ return 1;
+ }
+
+ if (c < 0xc2)
+ return MY_CS_ILSEQ;
+
+ if (c < 0xe0)
+ {
+ if (!((s[1] ^ 0x80) < 0x40))
+ return MY_CS_ILSEQ;
+
+ *pwc = ((my_wc_t) (c & 0x1f) << 6) | (my_wc_t) (s[1] ^ 0x80);
+ return 2;
+ }
+
+ if (c < 0xf0)
+ {
+ if (!((s[1] ^ 0x80) < 0x40 &&
+ (s[2] ^ 0x80) < 0x40 &&
+ (c >= 0xe1 || s[1] >= 0xa0)))
+ return MY_CS_ILSEQ;
+
+ *pwc= ((my_wc_t) (c & 0x0f) << 12) |
+ ((my_wc_t) (s[1] ^ 0x80) << 6) |
+ (my_wc_t) (s[2] ^ 0x80);
+
+ return 3;
+ }
+ return MY_CS_ILSEQ;
+}
+
+
static int my_uni_utf8 (CHARSET_INFO *cs __attribute__((unused)) ,
my_wc_t wc, uchar *r, uchar *e)
{
@@ -2091,6 +2137,34 @@ static int my_uni_utf8 (CHARSET_INFO *cs __attribute__((unused)) ,
}
+/*
+ The same as above, but without range check.
+*/
+static int my_uni_utf8_no_range(CHARSET_INFO *cs __attribute__((unused)),
+ my_wc_t wc, uchar *r)
+{
+ int count;
+
+ if (wc < 0x80)
+ count= 1;
+ else if (wc < 0x800)
+ count= 2;
+ else if (wc < 0x10000)
+ count= 3;
+ else
+ return MY_CS_ILUNI;
+
+ switch (count)
+ {
+ /* Fall through all cases!!! */
+ case 3: r[2]= (uchar) (0x80 | (wc & 0x3f)); wc= wc >> 6; wc |= 0x800;
+ case 2: r[1]= (uchar) (0x80 | (wc & 0x3f)); wc= wc >> 6; wc |= 0xc0;
+ case 1: r[0]= (uchar) wc;
+ }
+ return count;
+}
+
+
static uint my_caseup_utf8(CHARSET_INFO *cs, char *src, uint srclen,
char *dst, uint dstlen)
{
@@ -2141,10 +2215,26 @@ static void my_hash_sort_utf8(CHARSET_INFO *cs, const uchar *s, uint slen,
}
-static void my_caseup_str_utf8(CHARSET_INFO * cs, char * s)
+static uint my_caseup_str_utf8(CHARSET_INFO *cs, char *src)
{
- uint len= (uint) strlen(s);
- my_caseup_utf8(cs, s, len, s, len);
+ my_wc_t wc;
+ int srcres, dstres;
+ char *dst= src, *dst0= src;
+ MY_UNICASE_INFO **uni_plane= cs->caseinfo;
+ DBUG_ASSERT(cs->caseup_multiply == 1);
+
+ while (*src &&
+ (srcres= my_utf8_uni_no_range(cs, &wc, (uchar *) src)) > 0)
+ {
+ int plane= (wc>>8) & 0xFF;
+ wc= uni_plane[plane] ? uni_plane[plane][wc & 0xFF].toupper : wc;
+ if ((dstres= my_uni_utf8_no_range(cs, wc, (uchar*) dst)) <= 0)
+ break;
+ src+= srcres;
+ dst+= dstres;
+ }
+ *dst= '\0';
+ return (uint) (dst - dst0);
}
@@ -2170,10 +2260,43 @@ static uint my_casedn_utf8(CHARSET_INFO *cs, char *src, uint srclen,
return (uint) (dst - dst0);
}
-static void my_casedn_str_utf8(CHARSET_INFO *cs, char * s)
+
+static uint my_casedn_str_utf8(CHARSET_INFO *cs, char *src)
{
- uint len= (uint) strlen(s);
- my_casedn_utf8(cs, s, len, s, len);
+ my_wc_t wc;
+ int srcres, dstres;
+ char *dst= src, *dst0= src;
+ MY_UNICASE_INFO **uni_plane= cs->caseinfo;
+ DBUG_ASSERT(cs->casedn_multiply == 1);
+
+ while (*src &&
+ (srcres= my_utf8_uni_no_range(cs, &wc, (uchar *) src)) > 0)
+ {
+ int plane= (wc>>8) & 0xFF;
+ wc= uni_plane[plane] ? uni_plane[plane][wc & 0xFF].tolower : wc;
+ if ((dstres= my_uni_utf8_no_range(cs, wc, (uchar*) dst)) <= 0)
+ break;
+ src+= srcres;
+ dst+= dstres;
+ }
+
+ /*
+ In rare cases lower string can be shorter than
+ the original string, for example:
+
+ "U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE"
+ (which is 0xC4B0 in utf8, i.e. two bytes)
+
+ is converted into
+
+ "U+0069 LATIN SMALL LETTER I"
+ (which is 0x69 in utf8, i.e. one byte)
+
+ So, we need to put '\0' terminator after converting.
+ */
+
+ *dst= '\0';
+ return (uint) (dst - dst0);
}