Commit 541883f9 authored by bar@mysql.com's avatar bar@mysql.com

Produce a "truncated" warning if a value cannot be converted

into the column character set on INSERT/UPDATE.
parent c8ba8c13
...@@ -349,6 +349,7 @@ alter table t1 change a a char(10) character set koi8r; ...@@ -349,6 +349,7 @@ alter table t1 change a a char(10) character set koi8r;
select a,hex(a) from t1; select a,hex(a) from t1;
a hex(a) a hex(a)
D4C5D3D4 D4C5D3D4
delete from t1;
show create table t1; show create table t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
......
...@@ -166,3 +166,11 @@ ERROR HY000: Invalid utf8 character string: ' ...@@ -166,3 +166,11 @@ ERROR HY000: Invalid utf8 character string: '
SET NAMES utf8; SET NAMES utf8;
CREATE TABLE `good` (a int); CREATE TABLE `good` (a int);
ERROR HY000: Invalid utf8 character string: '` (a int)' ERROR HY000: Invalid utf8 character string: '` (a int)'
set names latin1;
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
drop table t1;
...@@ -356,6 +356,11 @@ SELECT t, collation(t),MATCH t AGAINST ('Osnabruck') FROM t1 WHERE MATCH t AGAIN ...@@ -356,6 +356,11 @@ SELECT t, collation(t),MATCH t AGAINST ('Osnabruck') FROM t1 WHERE MATCH t AGAIN
t collation(t) MATCH t AGAINST ('Osnabruck') t collation(t) MATCH t AGAINST ('Osnabruck')
aus Osnabrck utf8_general_ci 1.591139793396 aus Osnabrck utf8_general_ci 1.591139793396
alter table t1 modify t varchar(200) collate latin1_german2_ci not null; 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
SELECT t, collation(t) FROM t1 WHERE MATCH t AGAINST ('Osnabrck'); SELECT t, collation(t) FROM t1 WHERE MATCH t AGAINST ('Osnabrck');
t collation(t) t collation(t)
aus Osnabrck latin1_german2_ci aus Osnabrck latin1_german2_ci
......
...@@ -207,6 +207,7 @@ alter table t1 change a a text character set cp1251; ...@@ -207,6 +207,7 @@ alter table t1 change a a text character set cp1251;
select a,hex(a) from t1; select a,hex(a) from t1;
alter table t1 change a a char(10) character set koi8r; alter table t1 change a a char(10) character set koi8r;
select a,hex(a) from t1; select a,hex(a) from t1;
delete from t1;
# #
# Test ALTER TABLE .. CHARACTER SET .. # Test ALTER TABLE .. CHARACTER SET ..
......
...@@ -121,3 +121,13 @@ CREATE TABLE `good ...@@ -121,3 +121,13 @@ CREATE TABLE `good
SET NAMES utf8; SET NAMES utf8;
--error 1300 --error 1300
CREATE TABLE `good` (a int); CREATE TABLE `good` (a int);
#
# Test that we produce a warnign when conversion loses data.
#
set names latin1;
create table t1 (a char(10) character set koi8r, b text character set koi8r);
insert into t1 values ('test','test');
insert into t1 values ('','');
drop table t1;
...@@ -4275,9 +4275,12 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) ...@@ -4275,9 +4275,12 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
/* Convert character set if nesessary */ /* Convert character set if nesessary */
if (String::needs_conversion(length, cs, field_charset, &not_used)) if (String::needs_conversion(length, cs, field_charset, &not_used))
{ {
tmpstr.copy(from, length, cs, field_charset); uint conv_errors;
tmpstr.copy(from, length, cs, field_charset, &conv_errors);
from= tmpstr.ptr(); from= tmpstr.ptr();
length= tmpstr.length(); length= tmpstr.length();
if (conv_errors)
error= 1;
} }
/* /*
...@@ -4300,11 +4303,11 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) ...@@ -4300,11 +4303,11 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
from+= field_charset->cset->scan(field_charset, from, end, from+= field_charset->cset->scan(field_charset, from, end,
MY_SEQ_SPACES); MY_SEQ_SPACES);
if (from != end) if (from != end)
{ error= 1;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
error=1;
}
} }
if (error)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
return error; return error;
} }
...@@ -4528,16 +4531,20 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) ...@@ -4528,16 +4531,20 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
/* Convert character set if nesessary */ /* Convert character set if nesessary */
if (String::needs_conversion(length, cs, field_charset, &not_used)) if (String::needs_conversion(length, cs, field_charset, &not_used))
{ {
tmpstr.copy(from, length, cs, field_charset); uint conv_errors;
tmpstr.copy(from, length, cs, field_charset, &conv_errors);
from= tmpstr.ptr(); from= tmpstr.ptr();
length= tmpstr.length(); length= tmpstr.length();
if (conv_errors)
error= 1;
} }
if (length > field_length) if (length > field_length)
{ {
length=field_length; length=field_length;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
error= 1; error= 1;
} }
if (error)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
memcpy(ptr+HA_KEY_BLOB_LENGTH,from,length); memcpy(ptr+HA_KEY_BLOB_LENGTH,from,length);
int2store(ptr, length); int2store(ptr, length);
return error; return error;
...@@ -4865,6 +4872,7 @@ void Field_blob::put_length(char *pos, uint32 length) ...@@ -4865,6 +4872,7 @@ void Field_blob::put_length(char *pos, uint32 length)
int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
{ {
int error= 0;
if (!length) if (!length)
{ {
bzero(ptr,Field_blob::pack_length()); bzero(ptr,Field_blob::pack_length());
...@@ -4881,9 +4889,12 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) ...@@ -4881,9 +4889,12 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
if ((was_conversion= String::needs_conversion(length, cs, field_charset, if ((was_conversion= String::needs_conversion(length, cs, field_charset,
&not_used))) &not_used)))
{ {
tmpstr.copy(from, length, cs, field_charset); uint conv_errors;
tmpstr.copy(from, length, cs, field_charset, &conv_errors);
from= tmpstr.ptr(); from= tmpstr.ptr();
length= tmpstr.length(); length= tmpstr.length();
if (conv_errors)
error= 1;
} }
copy_length= max_data_length(); copy_length= max_data_length();
...@@ -4897,8 +4908,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) ...@@ -4897,8 +4908,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
min(length, copy_length), min(length, copy_length),
copy_length); copy_length);
if (copy_length < length) if (copy_length < length)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1); error= 1;
Field_blob::store_length(copy_length); Field_blob::store_length(copy_length);
if (was_conversion || table->copy_blobs || copy_length <= MAX_FIELD_WIDTH) if (was_conversion || table->copy_blobs || copy_length <= MAX_FIELD_WIDTH)
{ // Must make a copy { // Must make a copy
...@@ -4910,6 +4920,8 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) ...@@ -4910,6 +4920,8 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
} }
bmove(ptr+packlength,(char*) &from,sizeof(char*)); bmove(ptr+packlength,(char*) &from,sizeof(char*));
} }
if (error)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
return 0; return 0;
} }
......
...@@ -331,19 +331,26 @@ bool String::set_or_copy_aligned(const char *str,uint32 arg_length, ...@@ -331,19 +331,26 @@ bool String::set_or_copy_aligned(const char *str,uint32 arg_length,
/* Copy with charset convertion */ /* Copy with charset convertion */
bool String::copy(const char *str, uint32 arg_length, bool String::copy(const char *str, uint32 arg_length,
CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) CHARSET_INFO *from_cs, CHARSET_INFO *to_cs, uint *errors)
{ {
uint32 offset; uint32 offset;
if (!needs_conversion(arg_length, from_cs, to_cs, &offset)) if (!needs_conversion(arg_length, from_cs, to_cs, &offset))
{
if (errors)
*errors= 0;
return copy(str, arg_length, to_cs); return copy(str, arg_length, to_cs);
}
if ((from_cs == &my_charset_bin) && offset) if ((from_cs == &my_charset_bin) && offset)
{
if (errors)
*errors= 0;
return copy_aligned(str, arg_length, offset, to_cs); return copy_aligned(str, arg_length, offset, to_cs);
}
uint32 new_length= to_cs->mbmaxlen*arg_length; uint32 new_length= to_cs->mbmaxlen*arg_length;
if (alloc(new_length)) if (alloc(new_length))
return TRUE; return TRUE;
str_length=copy_and_convert((char*) Ptr, new_length, to_cs, str_length=copy_and_convert((char*) Ptr, new_length, to_cs,
str, arg_length, from_cs); str, arg_length, from_cs, errors);
str_charset=to_cs; str_charset=to_cs;
return FALSE; return FALSE;
} }
...@@ -769,7 +776,8 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length) ...@@ -769,7 +776,8 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
uint32 uint32
copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
const char *from, uint32 from_length, CHARSET_INFO *from_cs) const char *from, uint32 from_length, CHARSET_INFO *from_cs,
uint *errors)
{ {
int cnvres; int cnvres;
my_wc_t wc; my_wc_t wc;
...@@ -780,6 +788,7 @@ copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, ...@@ -780,6 +788,7 @@ copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
const uchar *) = from_cs->cset->mb_wc; const uchar *) = from_cs->cset->mb_wc;
int (*wc_mb)(struct charset_info_st *, my_wc_t, uchar *s, uchar *e)= int (*wc_mb)(struct charset_info_st *, my_wc_t, uchar *s, uchar *e)=
to_cs->cset->wc_mb; to_cs->cset->wc_mb;
uint error_count= 0;
while (1) while (1)
{ {
...@@ -788,6 +797,7 @@ copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, ...@@ -788,6 +797,7 @@ copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
from+= cnvres; from+= cnvres;
else if (cnvres == MY_CS_ILSEQ) else if (cnvres == MY_CS_ILSEQ)
{ {
error_count++;
from++; from++;
wc= '?'; wc= '?';
} }
...@@ -799,12 +809,15 @@ copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, ...@@ -799,12 +809,15 @@ copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
to+= cnvres; to+= cnvres;
else if (cnvres == MY_CS_ILUNI && wc != '?') else if (cnvres == MY_CS_ILUNI && wc != '?')
{ {
error_count++;
wc= '?'; wc= '?';
goto outp; goto outp;
} }
else else
break; break;
} }
if (errors)
*errors= error_count;
return (uint32) (to - to_start); return (uint32) (to - to_start);
} }
......
...@@ -29,7 +29,7 @@ int sortcmp(const String *a,const String *b, CHARSET_INFO *cs); ...@@ -29,7 +29,7 @@ int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); 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, uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
const char *from, uint32 from_length, const char *from, uint32 from_length,
CHARSET_INFO *from_cs); CHARSET_INFO *from_cs, uint *errors= 0);
class String class String
{ {
...@@ -199,7 +199,7 @@ class String ...@@ -199,7 +199,7 @@ class String
CHARSET_INFO *cs); CHARSET_INFO *cs);
bool set_or_copy_aligned(const char *s, uint32 arg_length, CHARSET_INFO *cs); bool set_or_copy_aligned(const char *s, uint32 arg_length, CHARSET_INFO *cs);
bool copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom, bool copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom,
CHARSET_INFO *csto); CHARSET_INFO *csto, uint *errors= 0);
bool append(const String &s); bool append(const String &s);
bool append(const char *s); bool append(const char *s);
bool append(const char *s,uint32 arg_length); bool append(const char *s,uint32 arg_length);
......
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