Commit 8ec6cf2c authored by unknown's avatar unknown

UCS2 support in ENUM and SET, which also fixes:

Bug #5174 SHOW CREATE TABLE hangs up if the table contains half-with katakana enum values
UCS2 values are stored in HEX encoding in FRM file

parent 678fff40
...@@ -525,3 +525,59 @@ use test; ...@@ -525,3 +525,59 @@ use test;
SET TIMESTAMP=10000; SET TIMESTAMP=10000;
insert into t2 values (@v); insert into t2 values (@v);
drop table t2; drop table t2;
set names latin1;
create table t1 (a enum('x','y','z') character set ucs2);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` enum('x','y','z') character set ucs2 default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
insert into t1 values ('x');
insert into t1 values ('y');
insert into t1 values ('z');
select a, hex(a) from t1 order by a;
a hex(a)
x 0078
y 0079
z 007A
alter table t1 change a a enum('x','y','z','d','e','','','') character set ucs2;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` enum('x','y','z','d','e','','','') character set ucs2 default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
insert into t1 values ('D');
insert into t1 values ('E ');
insert into t1 values ('');
insert into t1 values ('');
insert into t1 values ('');
select a, hex(a) from t1 order by a;
a hex(a)
x 0078
y 0079
z 007A
d 0064
e 0065
00E4
00F6
00FC
drop table t1;
create table t1 (a set ('x','y','z','','','') character set ucs2);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` set('x','y','z','','','') character set ucs2 default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
insert into t1 values ('x');
insert into t1 values ('y');
insert into t1 values ('z');
insert into t1 values ('x,y');
insert into t1 values ('x,y,z,,,');
select a, hex(a) from t1 order by a;
a hex(a)
x 0078
y 0079
x,y 0078002C0079
z 007A
x,y,z,,, 0078002C0079002C007A002C00E4002C00F6002C00FC
drop table t1;
...@@ -343,3 +343,34 @@ show binlog events from 79; ...@@ -343,3 +343,34 @@ show binlog events from 79;
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
--exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001 --exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001
drop table t2; drop table t2;
#
# Check that ucs2 works with ENUM and SET type
#
set names latin1;
create table t1 (a enum('x','y','z') character set ucs2);
show create table t1;
insert into t1 values ('x');
insert into t1 values ('y');
insert into t1 values ('z');
select a, hex(a) from t1 order by a;
alter table t1 change a a enum('x','y','z','d','e','','','') character set ucs2;
show create table t1;
insert into t1 values ('D');
insert into t1 values ('E ');
insert into t1 values ('');
insert into t1 values ('');
insert into t1 values ('');
select a, hex(a) from t1 order by a;
drop table t1;
create table t1 (a set ('x','y','z','','','') character set ucs2);
show create table t1;
insert into t1 values ('x');
insert into t1 values ('y');
insert into t1 values ('z');
insert into t1 values ('x,y');
insert into t1 values ('x,y,z,,,');
select a, hex(a) from t1 order by a;
drop table t1;
...@@ -5529,8 +5529,7 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) ...@@ -5529,8 +5529,7 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
} }
/* Remove end space */ /* Remove end space */
while (length > 0 && my_isspace(system_charset_info,from[length-1])) length= field_charset->cset->lengthsp(field_charset, from, length);
length--;
uint tmp=find_type2(typelib, from, length, field_charset); uint tmp=find_type2(typelib, from, length, field_charset);
if (!tmp) if (!tmp)
{ {
...@@ -5632,7 +5631,7 @@ String *Field_enum::val_str(String *val_buffer __attribute__((unused)), ...@@ -5632,7 +5631,7 @@ String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
val_ptr->set("", 0, field_charset); val_ptr->set("", 0, field_charset);
else else
val_ptr->set((const char*) typelib->type_names[tmp-1], val_ptr->set((const char*) typelib->type_names[tmp-1],
(uint) strlen(typelib->type_names[tmp-1]), typelib->type_lengths[tmp-1],
field_charset); field_charset);
return val_ptr; return val_ptr;
} }
...@@ -5669,13 +5668,14 @@ void Field_enum::sql_type(String &res) const ...@@ -5669,13 +5668,14 @@ void Field_enum::sql_type(String &res) const
res.append("enum("); res.append("enum(");
bool flag=0; bool flag=0;
for (const char **pos= typelib->type_names; *pos; pos++) uint *len= typelib->type_lengths;
for (const char **pos= typelib->type_names; *pos; pos++, len++)
{ {
uint dummy_errors; uint dummy_errors;
if (flag) if (flag)
res.append(','); res.append(',');
/* convert to res.charset() == utf8, then quote */ /* convert to res.charset() == utf8, then quote */
enum_item.copy(*pos, strlen(*pos), charset(), res.charset(), &dummy_errors); enum_item.copy(*pos, *len, charset(), res.charset(), &dummy_errors);
append_unescaped(&res, enum_item.ptr(), enum_item.length()); append_unescaped(&res, enum_item.ptr(), enum_item.length());
flag= 1; flag= 1;
} }
...@@ -5760,9 +5760,9 @@ String *Field_set::val_str(String *val_buffer, ...@@ -5760,9 +5760,9 @@ String *Field_set::val_str(String *val_buffer,
if (tmp & 1) if (tmp & 1)
{ {
if (val_buffer->length()) if (val_buffer->length())
val_buffer->append(field_separator); val_buffer->append(&field_separator, 1, &my_charset_latin1);
String str(typelib->type_names[bitnr], String str(typelib->type_names[bitnr],
(uint) strlen(typelib->type_names[bitnr]), typelib->type_lengths[bitnr],
field_charset); field_charset);
val_buffer->append(str); val_buffer->append(str);
} }
...@@ -5782,13 +5782,14 @@ void Field_set::sql_type(String &res) const ...@@ -5782,13 +5782,14 @@ void Field_set::sql_type(String &res) const
res.append("set("); res.append("set(");
bool flag=0; bool flag=0;
for (const char **pos= typelib->type_names; *pos; pos++) uint *len= typelib->type_lengths;
for (const char **pos= typelib->type_names; *pos; pos++, len++)
{ {
uint dummy_errors; uint dummy_errors;
if (flag) if (flag)
res.append(','); res.append(',');
/* convert to res.charset() == utf8, then quote */ /* convert to res.charset() == utf8, then quote */
set_item.copy(*pos, strlen(*pos), charset(), res.charset(), &dummy_errors); set_item.copy(*pos, *len, charset(), res.charset(), &dummy_errors);
append_unescaped(&res, set_item.ptr(), set_item.length()); append_unescaped(&res, set_item.ptr(), set_item.length());
flag= 1; flag= 1;
} }
......
...@@ -2320,17 +2320,6 @@ String *Item_func_hex::val_str(String *str) ...@@ -2320,17 +2320,6 @@ String *Item_func_hex::val_str(String *str)
return &tmp_value; return &tmp_value;
} }
inline int hexchar_to_int(char c)
{
if (c <= '9' && c >= '0')
return c-'0';
c|=32;
if (c <= 'f' && c >= 'a')
return c-'a'+10;
return -1;
}
/* Convert given hex string to a binary string */ /* Convert given hex string to a binary string */
String *Item_func_unhex::val_str(String *str) String *Item_func_unhex::val_str(String *str)
......
...@@ -1200,6 +1200,23 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr) ...@@ -1200,6 +1200,23 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
} }
/*
SYNOPSYS
hexchar_to_int()
convert a hex digit into number
*/
inline int hexchar_to_int(char c)
{
if (c <= '9' && c >= '0')
return c-'0';
c|=32;
if (c <= 'f' && c >= 'a')
return c-'a'+10;
return -1;
}
/* /*
Some functions that are different in the embedded library and the normal Some functions that are different in the embedded library and the normal
server server
......
...@@ -53,8 +53,22 @@ ulonglong find_set(TYPELIB *lib, const char *str, uint length, CHARSET_INFO *cs, ...@@ -53,8 +53,22 @@ ulonglong find_set(TYPELIB *lib, const char *str, uint length, CHARSET_INFO *cs,
{ {
const char *pos= start; const char *pos= start;
uint var_len; uint var_len;
int mblen= 1;
for (; pos != end && *pos != field_separator; pos++) ; if (cs && cs->mbminlen > 1)
{
for ( ; pos < end; pos+= mblen)
{
my_wc_t wc;
if ((mblen= cs->cset->mb_wc(cs, &wc, (const uchar *) pos,
(const uchar *) end)) < 1)
mblen= 1; // Not to hang on a wrong multibyte sequence
if (wc == (my_wc_t) field_separator)
break;
}
}
else
for (; pos != end && *pos != field_separator; pos++) ;
var_len= (uint) (pos - start); var_len= (uint) (pos - start);
uint find= cs ? find_type2(lib, start, var_len, cs) : uint find= cs ? find_type2(lib, start, var_len, cs) :
find_type(lib, start, var_len, (bool) 0); find_type(lib, start, var_len, (bool) 0);
...@@ -66,9 +80,9 @@ ulonglong find_set(TYPELIB *lib, const char *str, uint length, CHARSET_INFO *cs, ...@@ -66,9 +80,9 @@ ulonglong find_set(TYPELIB *lib, const char *str, uint length, CHARSET_INFO *cs,
} }
else else
found|= ((longlong) 1 << (find - 1)); found|= ((longlong) 1 << (find - 1));
if (pos == end) if (pos >= end)
break; break;
start= pos + 1; start= pos + mblen;
} }
} }
return found; return found;
......
...@@ -485,6 +485,23 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -485,6 +485,23 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
charset= outparam->table_charset; charset= outparam->table_charset;
bzero((char*) &comment, sizeof(comment)); bzero((char*) &comment, sizeof(comment));
} }
if (interval_nr && charset->mbminlen > 1)
{
/* Unescape UCS2 intervals from HEX notation */
TYPELIB *interval= outparam->intervals + interval_nr - 1;
for (uint pos= 0; pos < interval->count; pos++)
{
char *from, *to;
for (from= to= (char*) interval->type_names[pos]; *from; )
{
*to++= (char) (hexchar_to_int(*from++) << 4) +
hexchar_to_int(*from++);
}
interval->type_lengths[pos] /= 2;
}
}
*field_ptr=reg_field= *field_ptr=reg_field=
make_field(record+recpos, make_field(record+recpos,
(uint32) field_length, (uint32) field_length,
......
...@@ -423,6 +423,28 @@ static bool pack_header(uchar *forminfo, enum db_type table_type, ...@@ -423,6 +423,28 @@ static bool pack_header(uchar *forminfo, enum db_type table_type,
if (field->interval) if (field->interval)
{ {
uint old_int_count=int_count; uint old_int_count=int_count;
if (field->charset->mbminlen > 1)
{
/* Escape UCS2 intervals using HEX notation */
for (uint pos= 0; pos < field->interval->count; pos++)
{
char *dst;
uint length= field->interval->type_lengths[pos], hex_length;
const char *src= field->interval->type_names[pos];
const char *srcend= src + length;
hex_length= length * 2;
field->interval->type_lengths[pos]= hex_length;
field->interval->type_names[pos]= dst= sql_alloc(hex_length + 1);
for ( ; src < srcend; src++)
{
*dst++= _dig_vec_upper[((uchar) *src) >> 4];
*dst++= _dig_vec_upper[((uchar) *src) & 15];
}
*dst= '\0';
}
}
field->interval_id=get_interval_id(&int_count,create_fields,field); field->interval_id=get_interval_id(&int_count,create_fields,field);
if (old_int_count != int_count) if (old_int_count != int_count)
{ {
......
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