Fix: create table t1 (a char(10) character set cp1251) SELECT _koi8r'blabla' as a
The above query created a field of koi8r charset, not cp1251 Change: CREATE TABLE a (a CHAR(1) CHARACTER SET utf8) Length now means character length, not byte length. The above creates a field that guarantees can store a multibyte value 1 character long. For utf8 the above creates a field that can store 3 bytes.
This commit is contained in:
parent
f3f6e5e9b2
commit
0960c3eb26
21
mysql-test/r/ctype_mb.result
Normal file
21
mysql-test/r/ctype_mb.result
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
CREATE TABLE t1 SELECT _utf8'test' as c1, _utf8'тест' as c2;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`c1` char(4) character set utf8 NOT NULL default '',
|
||||||
|
`c2` char(4) character set utf8 NOT NULL default ''
|
||||||
|
) TYPE=MyISAM CHARSET=latin1
|
||||||
|
DELETE FROM t1;
|
||||||
|
ALTER TABLE t1 ADD c3 CHAR(4) CHARACTER SET utf8;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`c1` char(4) character set utf8 NOT NULL default '',
|
||||||
|
`c2` char(4) character set utf8 NOT NULL default '',
|
||||||
|
`c3` char(4) character set utf8 default NULL
|
||||||
|
) TYPE=MyISAM CHARSET=latin1
|
||||||
|
INSERT INTO t1 VALUES ('aaaabbbbccccdddd','aaaabbbbccccdddd','aaaabbbbccccdddd');
|
||||||
|
SELECT * FROM t1;
|
||||||
|
c1 c2 c3
|
||||||
|
aaaabbbbcccc aaaabbbbcccc aaaabbbbcccc
|
||||||
|
DROP TABLE t1;
|
@ -1,5 +1,19 @@
|
|||||||
SET CHARACTER SET koi8r;
|
SET CHARACTER SET koi8r;
|
||||||
DROP TABLE IF EXISTS ÔÁÂÌÉÃÁ;
|
DROP TABLE IF EXISTS ÔÁÂÌÉÃÁ;
|
||||||
|
SET CHARACTER SET koi8r;
|
||||||
|
CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp1251) SELECT _koi8r'ĐŇĎÂÁ' AS a;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`a` char(10) character set cp1251 default NULL
|
||||||
|
) TYPE=MyISAM CHARSET=latin1
|
||||||
|
SELECT a FROM t1;
|
||||||
|
a
|
||||||
|
ĐŇĎÂÁ
|
||||||
|
SELECT HEX(a) FROM t1;
|
||||||
|
HEX(a)
|
||||||
|
EFF0EEE1E0
|
||||||
|
DROP TABLE t1;
|
||||||
CREATE TABLE ÔÁÂÌÉÃÁ
|
CREATE TABLE ÔÁÂÌÉÃÁ
|
||||||
(
|
(
|
||||||
ÐÏÌÅ CHAR(32) CHARACTER SET koi8r NOT NULL
|
ÐÏÌÅ CHAR(32) CHARACTER SET koi8r NOT NULL
|
||||||
|
@ -41,9 +41,9 @@ create table t1 (version char(40)) select database(), user(), version() as 'vers
|
|||||||
show create table t1;
|
show create table t1;
|
||||||
Table Create Table
|
Table Create Table
|
||||||
t1 CREATE TABLE `t1` (
|
t1 CREATE TABLE `t1` (
|
||||||
`database()` char(102) character set utf8 NOT NULL default '',
|
`database()` char(34) character set utf8 NOT NULL default '',
|
||||||
`user()` char(231) character set utf8 NOT NULL default '',
|
`user()` char(77) character set utf8 NOT NULL default '',
|
||||||
`version` char(40) character set utf8 default NULL
|
`version` char(40) default NULL
|
||||||
) TYPE=MyISAM CHARSET=latin1
|
) TYPE=MyISAM CHARSET=latin1
|
||||||
drop table t1;
|
drop table t1;
|
||||||
select TRUE,FALSE,NULL;
|
select TRUE,FALSE,NULL;
|
||||||
|
8
mysql-test/t/ctype_mb.test
Normal file
8
mysql-test/t/ctype_mb.test
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
CREATE TABLE t1 SELECT _utf8'test' as c1, _utf8'тест' as c2;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
DELETE FROM t1;
|
||||||
|
ALTER TABLE t1 ADD c3 CHAR(4) CHARACTER SET utf8;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
INSERT INTO t1 VALUES ('aaaabbbbccccdddd','aaaabbbbccccdddd','aaaabbbbccccdddd');
|
||||||
|
SELECT * FROM t1;
|
||||||
|
DROP TABLE t1;
|
@ -4,6 +4,13 @@ SET CHARACTER SET koi8r;
|
|||||||
DROP TABLE IF EXISTS ÔÁÂÌÉÃÁ;
|
DROP TABLE IF EXISTS ÔÁÂÌÉÃÁ;
|
||||||
--enable_warnings
|
--enable_warnings
|
||||||
|
|
||||||
|
SET CHARACTER SET koi8r;
|
||||||
|
CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp1251) SELECT _koi8r'ÐÒÏÂÁ' AS a;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
SELECT a FROM t1;
|
||||||
|
SELECT HEX(a) FROM t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
CREATE TABLE ÔÁÂÌÉÃÁ
|
CREATE TABLE ÔÁÂÌÉÃÁ
|
||||||
(
|
(
|
||||||
ÐÏÌÅ CHAR(32) CHARACTER SET koi8r NOT NULL
|
ÐÏÌÅ CHAR(32) CHARACTER SET koi8r NOT NULL
|
||||||
|
24
sql/field.cc
24
sql/field.cc
@ -4012,7 +4012,7 @@ void Field_string::sql_type(String &res) const
|
|||||||
(table->db_options_in_use &
|
(table->db_options_in_use &
|
||||||
HA_OPTION_PACK_RECORD) ?
|
HA_OPTION_PACK_RECORD) ?
|
||||||
"varchar" : "char"),
|
"varchar" : "char"),
|
||||||
(int) field_length);
|
(int) field_length / charset()->mbmaxlen);
|
||||||
res.length(length);
|
res.length(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4178,7 +4178,7 @@ void Field_varstring::sql_type(String &res) const
|
|||||||
CHARSET_INFO *cs=res.charset();
|
CHARSET_INFO *cs=res.charset();
|
||||||
ulong length= cs->cset->snprintf(cs,(char*) res.ptr(),
|
ulong length= cs->cset->snprintf(cs,(char*) res.ptr(),
|
||||||
res.alloced_length(),"varchar(%u)",
|
res.alloced_length(),"varchar(%u)",
|
||||||
field_length);
|
field_length / charset()->mbmaxlen);
|
||||||
res.length(length);
|
res.length(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5267,6 +5267,26 @@ bool Field_num::eq_def(Field *field)
|
|||||||
** Handling of field and create_field
|
** Handling of field and create_field
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
void create_field::create_length_to_internal_length(void)
|
||||||
|
{
|
||||||
|
switch (sql_type)
|
||||||
|
{
|
||||||
|
case MYSQL_TYPE_TINY_BLOB:
|
||||||
|
case MYSQL_TYPE_MEDIUM_BLOB:
|
||||||
|
case MYSQL_TYPE_LONG_BLOB:
|
||||||
|
case MYSQL_TYPE_BLOB:
|
||||||
|
case MYSQL_TYPE_VAR_STRING:
|
||||||
|
case MYSQL_TYPE_STRING:
|
||||||
|
length*= charset->mbmaxlen;
|
||||||
|
pack_length= calc_pack_length(sql_type == FIELD_TYPE_VAR_STRING ?
|
||||||
|
FIELD_TYPE_STRING : sql_type, length);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* do nothing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Make a field from the .frm file info
|
Make a field from the .frm file info
|
||||||
*/
|
*/
|
||||||
|
@ -1066,6 +1066,7 @@ public:
|
|||||||
uint offset,pack_flag;
|
uint offset,pack_flag;
|
||||||
create_field() :after(0) {}
|
create_field() :after(0) {}
|
||||||
create_field(Field *field, Field *orig_field);
|
create_field(Field *field, Field *orig_field);
|
||||||
|
void create_length_to_internal_length(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -419,7 +419,7 @@ public:
|
|||||||
{
|
{
|
||||||
collation.set(cs, dv);
|
collation.set(cs, dv);
|
||||||
str_value.set(str,length,cs);
|
str_value.set(str,length,cs);
|
||||||
max_length=length;
|
max_length= str_value.numchars()*cs->mbmaxlen;
|
||||||
set_name(str, length, cs);
|
set_name(str, length, cs);
|
||||||
decimals=NOT_FIXED_DEC;
|
decimals=NOT_FIXED_DEC;
|
||||||
}
|
}
|
||||||
@ -428,7 +428,7 @@ public:
|
|||||||
{
|
{
|
||||||
collation.set(cs, dv);
|
collation.set(cs, dv);
|
||||||
str_value.set(str,length,cs);
|
str_value.set(str,length,cs);
|
||||||
max_length=length;
|
max_length= str_value.numchars()*cs->mbmaxlen;
|
||||||
set_name(name_par,0,cs);
|
set_name(name_par,0,cs);
|
||||||
decimals=NOT_FIXED_DEC;
|
decimals=NOT_FIXED_DEC;
|
||||||
}
|
}
|
||||||
|
@ -2078,10 +2078,20 @@ mysql_execute_command(THD *thd)
|
|||||||
res= mysql_create_like_table(thd, tables, &lex->create_info,
|
res= mysql_create_like_table(thd, tables, &lex->create_info,
|
||||||
(Table_ident *)lex->name);
|
(Table_ident *)lex->name);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
List_iterator<create_field> fields(lex->create_list);
|
||||||
|
create_field *field;
|
||||||
|
while ((field= fields++))
|
||||||
|
{
|
||||||
|
if (!field->charset)
|
||||||
|
field->charset= lex->create_info.table_charset;
|
||||||
|
field->create_length_to_internal_length();
|
||||||
|
}
|
||||||
res= mysql_create_table(thd,tables->db ? tables->db : thd->db,
|
res= mysql_create_table(thd,tables->db ? tables->db : thd->db,
|
||||||
tables->real_name, &lex->create_info,
|
tables->real_name, &lex->create_info,
|
||||||
lex->create_list,
|
lex->create_list,
|
||||||
lex->key_list,0,0,0); // do logging
|
lex->key_list,0,0,0); // do logging
|
||||||
|
}
|
||||||
if (!res)
|
if (!res)
|
||||||
send_ok(thd);
|
send_ok(thd);
|
||||||
}
|
}
|
||||||
@ -3791,7 +3801,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
|
|||||||
break;
|
break;
|
||||||
case FIELD_TYPE_STRING:
|
case FIELD_TYPE_STRING:
|
||||||
case FIELD_TYPE_VAR_STRING:
|
case FIELD_TYPE_VAR_STRING:
|
||||||
if (new_field->length < MAX_FIELD_WIDTH || default_value)
|
if (new_field->length <= MAX_FIELD_CHARLENGTH || default_value)
|
||||||
break;
|
break;
|
||||||
/* Convert long CHAR() and VARCHAR columns to TEXT or BLOB */
|
/* Convert long CHAR() and VARCHAR columns to TEXT or BLOB */
|
||||||
new_field->sql_type= FIELD_TYPE_BLOB;
|
new_field->sql_type= FIELD_TYPE_BLOB;
|
||||||
@ -3957,13 +3967,13 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_field->length >= MAX_FIELD_WIDTH ||
|
if (new_field->length > MAX_FIELD_CHARLENGTH ||
|
||||||
(!new_field->length && !(new_field->flags & BLOB_FLAG) &&
|
(!new_field->length && !(new_field->flags & BLOB_FLAG) &&
|
||||||
type != FIELD_TYPE_STRING &&
|
type != FIELD_TYPE_STRING &&
|
||||||
type != FIELD_TYPE_VAR_STRING && type != FIELD_TYPE_GEOMETRY))
|
type != FIELD_TYPE_VAR_STRING && type != FIELD_TYPE_GEOMETRY))
|
||||||
{
|
{
|
||||||
net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
|
net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
|
||||||
MAX_FIELD_WIDTH-1); /* purecov: inspected */
|
MAX_FIELD_CHARLENGTH); /* purecov: inspected */
|
||||||
DBUG_RETURN(1); /* purecov: inspected */
|
DBUG_RETURN(1); /* purecov: inspected */
|
||||||
}
|
}
|
||||||
type_modifier&= AUTO_INCREMENT_FLAG;
|
type_modifier&= AUTO_INCREMENT_FLAG;
|
||||||
|
@ -457,12 +457,14 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Field redefined */
|
/* Field redefined */
|
||||||
|
sql_field->sql_type= dup_field->sql_type;
|
||||||
|
sql_field->charset= dup_field->charset ? dup_field->charset : create_info->table_charset;
|
||||||
sql_field->length= dup_field->length;
|
sql_field->length= dup_field->length;
|
||||||
|
sql_field->pack_length= dup_field->pack_length;
|
||||||
|
sql_field->create_length_to_internal_length();
|
||||||
sql_field->decimals= dup_field->decimals;
|
sql_field->decimals= dup_field->decimals;
|
||||||
sql_field->flags= dup_field->flags;
|
sql_field->flags= dup_field->flags;
|
||||||
sql_field->pack_length= dup_field->pack_length;
|
|
||||||
sql_field->unireg_check= dup_field->unireg_check;
|
sql_field->unireg_check= dup_field->unireg_check;
|
||||||
sql_field->sql_type= dup_field->sql_type;
|
|
||||||
it2.remove(); // Remove first (create) definition
|
it2.remove(); // Remove first (create) definition
|
||||||
select_field_pos--;
|
select_field_pos--;
|
||||||
break;
|
break;
|
||||||
@ -480,10 +482,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
|
|||||||
while ((sql_field=it++))
|
while ((sql_field=it++))
|
||||||
{
|
{
|
||||||
if (!sql_field->charset)
|
if (!sql_field->charset)
|
||||||
sql_field->charset = create_info->table_charset ?
|
sql_field->charset = create_info->table_charset;
|
||||||
create_info->table_charset :
|
|
||||||
thd->variables.character_set_database;
|
|
||||||
|
|
||||||
switch (sql_field->sql_type) {
|
switch (sql_field->sql_type) {
|
||||||
case FIELD_TYPE_BLOB:
|
case FIELD_TYPE_BLOB:
|
||||||
case FIELD_TYPE_MEDIUM_BLOB:
|
case FIELD_TYPE_MEDIUM_BLOB:
|
||||||
@ -1891,18 +1890,42 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Full alter table */
|
/* Full alter table */
|
||||||
|
|
||||||
|
/* let new create options override the old ones */
|
||||||
|
if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
|
||||||
|
create_info->min_rows=table->min_rows;
|
||||||
|
if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
|
||||||
|
create_info->max_rows=table->max_rows;
|
||||||
|
if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
|
||||||
|
create_info->avg_row_length=table->avg_row_length;
|
||||||
|
if (!(used_fields & HA_CREATE_USED_CHARSET))
|
||||||
|
create_info->table_charset=table->table_charset;
|
||||||
|
|
||||||
restore_record(table,default_values); // Empty record for DEFAULT
|
restore_record(table,default_values); // Empty record for DEFAULT
|
||||||
List_iterator<Alter_drop> drop_it(drop_list);
|
List_iterator<Alter_drop> drop_it(drop_list);
|
||||||
List_iterator<create_field> def_it(fields);
|
List_iterator<create_field> def_it(fields);
|
||||||
List_iterator<Alter_column> alter_it(alter_list);
|
List_iterator<Alter_column> alter_it(alter_list);
|
||||||
List<create_field> create_list; // Add new fields here
|
List<create_field> create_list; // Add new fields here
|
||||||
List<Key> key_list; // Add new keys here
|
List<Key> key_list; // Add new keys here
|
||||||
|
create_field *def;
|
||||||
|
|
||||||
|
/*
|
||||||
|
For each column set charset to the table
|
||||||
|
default if the column charset hasn't been specified
|
||||||
|
explicitely. Change CREATE length into internal length
|
||||||
|
*/
|
||||||
|
def_it.rewind();
|
||||||
|
while ((def= def_it++))
|
||||||
|
{
|
||||||
|
if (!def->charset)
|
||||||
|
def->charset= create_info->table_charset;
|
||||||
|
def->create_length_to_internal_length();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
First collect all fields from table which isn't in drop_list
|
First collect all fields from table which isn't in drop_list
|
||||||
*/
|
*/
|
||||||
|
|
||||||
create_field *def;
|
|
||||||
Field **f_ptr,*field;
|
Field **f_ptr,*field;
|
||||||
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
|
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
|
||||||
{
|
{
|
||||||
@ -2121,16 +2144,6 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
|||||||
if (!create_info->comment)
|
if (!create_info->comment)
|
||||||
create_info->comment=table->comment;
|
create_info->comment=table->comment;
|
||||||
|
|
||||||
/* let new create options override the old ones */
|
|
||||||
if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
|
|
||||||
create_info->min_rows=table->min_rows;
|
|
||||||
if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
|
|
||||||
create_info->max_rows=table->max_rows;
|
|
||||||
if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
|
|
||||||
create_info->avg_row_length=table->avg_row_length;
|
|
||||||
if (!(used_fields & HA_CREATE_USED_CHARSET))
|
|
||||||
create_info->table_charset=table->table_charset;
|
|
||||||
|
|
||||||
table->file->update_create_info(create_info);
|
table->file->update_create_info(create_info);
|
||||||
if ((create_info->table_options &
|
if ((create_info->table_options &
|
||||||
(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
|
(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
|
||||||
|
@ -58,7 +58,12 @@
|
|||||||
#endif
|
#endif
|
||||||
#define MAX_HOSTNAME 61 /* len+1 in mysql.user */
|
#define MAX_HOSTNAME 61 /* len+1 in mysql.user */
|
||||||
|
|
||||||
#define MAX_FIELD_WIDTH 256 /* Max column width +1 */
|
#define MAX_MBWIDTH 3 /* Max multibyte sequence */
|
||||||
|
#define MAX_FIELD_CHARLENGTH 255
|
||||||
|
/* Max column width +1 */
|
||||||
|
#define MAX_FIELD_WIDTH (MAX_FIELD_CHARLENGTH*MAX_MBWIDTH+1)
|
||||||
|
|
||||||
|
|
||||||
#define MAX_TABLES (sizeof(table_map)*8-2) /* Max tables in join */
|
#define MAX_TABLES (sizeof(table_map)*8-2) /* Max tables in join */
|
||||||
#define OUTER_REF_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-2))
|
#define OUTER_REF_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-2))
|
||||||
#define RAND_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-1))
|
#define RAND_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-1))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user