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;
|
||||
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 ÔÁÂÌÉÃÁ
|
||||
(
|
||||
ÐÏÌÅ 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;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`database()` char(102) character set utf8 NOT NULL default '',
|
||||
`user()` char(231) character set utf8 NOT NULL default '',
|
||||
`version` char(40) character set utf8 default NULL
|
||||
`database()` char(34) character set utf8 NOT NULL default '',
|
||||
`user()` char(77) character set utf8 NOT NULL default '',
|
||||
`version` char(40) default NULL
|
||||
) TYPE=MyISAM CHARSET=latin1
|
||||
drop table t1;
|
||||
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 ÔÁÂÌÉÃÁ;
|
||||
--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 ÔÁÂÌÉÃÁ
|
||||
(
|
||||
ÐÏÌÅ 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 &
|
||||
HA_OPTION_PACK_RECORD) ?
|
||||
"varchar" : "char"),
|
||||
(int) field_length);
|
||||
(int) field_length / charset()->mbmaxlen);
|
||||
res.length(length);
|
||||
}
|
||||
|
||||
@ -4178,7 +4178,7 @@ void Field_varstring::sql_type(String &res) const
|
||||
CHARSET_INFO *cs=res.charset();
|
||||
ulong length= cs->cset->snprintf(cs,(char*) res.ptr(),
|
||||
res.alloced_length(),"varchar(%u)",
|
||||
field_length);
|
||||
field_length / charset()->mbmaxlen);
|
||||
res.length(length);
|
||||
}
|
||||
|
||||
@ -5267,6 +5267,26 @@ bool Field_num::eq_def(Field *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
|
||||
*/
|
||||
|
@ -1066,6 +1066,7 @@ public:
|
||||
uint offset,pack_flag;
|
||||
create_field() :after(0) {}
|
||||
create_field(Field *field, Field *orig_field);
|
||||
void create_length_to_internal_length(void);
|
||||
};
|
||||
|
||||
|
||||
|
@ -419,7 +419,7 @@ public:
|
||||
{
|
||||
collation.set(cs, dv);
|
||||
str_value.set(str,length,cs);
|
||||
max_length=length;
|
||||
max_length= str_value.numchars()*cs->mbmaxlen;
|
||||
set_name(str, length, cs);
|
||||
decimals=NOT_FIXED_DEC;
|
||||
}
|
||||
@ -428,7 +428,7 @@ public:
|
||||
{
|
||||
collation.set(cs, dv);
|
||||
str_value.set(str,length,cs);
|
||||
max_length=length;
|
||||
max_length= str_value.numchars()*cs->mbmaxlen;
|
||||
set_name(name_par,0,cs);
|
||||
decimals=NOT_FIXED_DEC;
|
||||
}
|
||||
|
@ -2078,10 +2078,20 @@ mysql_execute_command(THD *thd)
|
||||
res= mysql_create_like_table(thd, tables, &lex->create_info,
|
||||
(Table_ident *)lex->name);
|
||||
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,
|
||||
tables->real_name, &lex->create_info,
|
||||
lex->create_list,
|
||||
lex->key_list,0,0,0); // do logging
|
||||
}
|
||||
if (!res)
|
||||
send_ok(thd);
|
||||
}
|
||||
@ -3791,7 +3801,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
|
||||
break;
|
||||
case FIELD_TYPE_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;
|
||||
/* Convert long CHAR() and VARCHAR columns to TEXT or 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) &&
|
||||
type != FIELD_TYPE_STRING &&
|
||||
type != FIELD_TYPE_VAR_STRING && type != FIELD_TYPE_GEOMETRY))
|
||||
{
|
||||
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 */
|
||||
}
|
||||
type_modifier&= AUTO_INCREMENT_FLAG;
|
||||
|
@ -457,12 +457,14 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
|
||||
else
|
||||
{
|
||||
/* 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->pack_length= dup_field->pack_length;
|
||||
sql_field->create_length_to_internal_length();
|
||||
sql_field->decimals= dup_field->decimals;
|
||||
sql_field->flags= dup_field->flags;
|
||||
sql_field->pack_length= dup_field->pack_length;
|
||||
sql_field->unireg_check= dup_field->unireg_check;
|
||||
sql_field->sql_type= dup_field->sql_type;
|
||||
it2.remove(); // Remove first (create) definition
|
||||
select_field_pos--;
|
||||
break;
|
||||
@ -480,10 +482,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
|
||||
while ((sql_field=it++))
|
||||
{
|
||||
if (!sql_field->charset)
|
||||
sql_field->charset = create_info->table_charset ?
|
||||
create_info->table_charset :
|
||||
thd->variables.character_set_database;
|
||||
|
||||
sql_field->charset = create_info->table_charset;
|
||||
switch (sql_field->sql_type) {
|
||||
case FIELD_TYPE_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 */
|
||||
|
||||
/* 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
|
||||
List_iterator<Alter_drop> drop_it(drop_list);
|
||||
List_iterator<create_field> def_it(fields);
|
||||
List_iterator<Alter_column> alter_it(alter_list);
|
||||
List<create_field> create_list; // Add new fields 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
|
||||
*/
|
||||
|
||||
create_field *def;
|
||||
Field **f_ptr,*field;
|
||||
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)
|
||||
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);
|
||||
if ((create_info->table_options &
|
||||
(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
|
||||
|
@ -58,7 +58,12 @@
|
||||
#endif
|
||||
#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 OUTER_REF_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-2))
|
||||
#define RAND_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-1))
|
||||
|
Loading…
x
Reference in New Issue
Block a user