Commit 786af341 authored by bar@bar.mysql.r18.ru's avatar bar@bar.mysql.r18.ru

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.
parent da8ab7dd
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;
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;
......
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
......
......@@ -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))
......
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