summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/ctype_utf8.result43
-rw-r--r--mysql-test/t/ctype_utf8.test35
-rw-r--r--sql/field_conv.cc32
3 files changed, 108 insertions, 2 deletions
diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index 380cf2f227d..d76d89d5630 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -1480,6 +1480,49 @@ aa
xxx
yyy
DROP TABLE t1;
+create table t1 (
+a varchar(26) not null
+) default character set utf8;
+insert into t1 (a) values ('abcdefghijklmnopqrstuvwxyz');
+select * from t1;
+a
+abcdefghijklmnopqrstuvwxyz
+alter table t1 change a a varchar(20) character set utf8 not null;
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+select * from t1;
+a
+abcdefghijklmnopqrst
+alter table t1 change a a char(15) character set utf8 not null;
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+select * from t1;
+a
+abcdefghijklmno
+alter table t1 change a a char(10) character set utf8 not null;
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+select * from t1;
+a
+abcdefghij
+alter table t1 change a a varchar(5) character set utf8 not null;
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+select * from t1;
+a
+abcde
+drop table t1;
+create table t1 (
+a varchar(4000) not null
+) default character set utf8;
+insert into t1 values (repeat('a',4000));
+alter table t1 change a a varchar(3000) character set utf8 not null;
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+select length(a) from t1;
+length(a)
+3000
+drop table t1;
set names utf8;
select hex(char(1 using utf8));
hex(char(1 using utf8))
diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index c0060b7b813..7db651a2a24 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -1194,6 +1194,41 @@ SELECT DISTINCT id FROM t1 ORDER BY id;
DROP TABLE t1;
#
+# Bug#20095 Changing length of VARCHAR field with UTF8
+# collation does not truncate values
+#
+create table t1 (
+ a varchar(26) not null
+) default character set utf8;
+insert into t1 (a) values ('abcdefghijklmnopqrstuvwxyz');
+select * from t1;
+# varchar to varchar
+alter table t1 change a a varchar(20) character set utf8 not null;
+select * from t1;
+# varchar to char
+alter table t1 change a a char(15) character set utf8 not null;
+select * from t1;
+# char to char
+alter table t1 change a a char(10) character set utf8 not null;
+select * from t1;
+# char to varchar
+alter table t1 change a a varchar(5) character set utf8 not null;
+select * from t1;
+drop table t1;
+
+#
+# Check that do_varstring2_mb produces a warning
+#
+create table t1 (
+ a varchar(4000) not null
+) default character set utf8;
+insert into t1 values (repeat('a',4000));
+alter table t1 change a a varchar(3000) character set utf8 not null;
+select length(a) from t1;
+drop table t1;
+
+
+#
# Bug#10504: Character set does not support traditional mode
# Bug#14146: CHAR(...USING ...) and CONVERT(CHAR(...) USING...)
# produce different results
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index a718a402897..9771cbc12b1 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -433,6 +433,26 @@ static void do_varstring1(Copy_field *copy)
}
+static void do_varstring1_mb(Copy_field *copy)
+{
+ int well_formed_error;
+ CHARSET_INFO *cs= copy->from_field->charset();
+ uint from_length= (uint) *(uchar*) copy->from_ptr;
+ const char *from_ptr= copy->from_ptr + 1;
+ uint to_char_length= (copy->to_length - 1) / cs->mbmaxlen;
+ uint length= cs->cset->well_formed_len(cs, from_ptr, from_ptr + from_length,
+ to_char_length, &well_formed_error);
+ if (length < from_length)
+ {
+ if (current_thd->count_cuted_fields)
+ copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ WARN_DATA_TRUNCATED, 1);
+ }
+ *(uchar*) copy->to_ptr= (uchar) length;
+ memcpy(copy->to_ptr + 1, from_ptr, length);
+}
+
+
static void do_varstring2(Copy_field *copy)
{
uint length=uint2korr(copy->from_ptr);
@@ -458,6 +478,12 @@ static void do_varstring2_mb(Copy_field *copy)
const char *from_beg= copy->from_ptr + HA_KEY_BLOB_LENGTH;
uint length= cs->cset->well_formed_len(cs, from_beg, from_beg + from_length,
char_length, &well_formed_error);
+ if (length < from_length)
+ {
+ if (current_thd->count_cuted_fields)
+ copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ WARN_DATA_TRUNCATED, 1);
+ }
int2store(copy->to_ptr, length);
memcpy(copy->to_ptr+HA_KEY_BLOB_LENGTH, from_beg, length);
}
@@ -633,8 +659,10 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
return do_field_string;
if (to_length != from_length)
return (((Field_varstring*) to)->length_bytes == 1 ?
- do_varstring1 : (from->charset()->mbmaxlen == 1 ?
- do_varstring2 : do_varstring2_mb));
+ (from->charset()->mbmaxlen == 1 ? do_varstring1 :
+ do_varstring1_mb) :
+ (from->charset()->mbmaxlen == 1 ? do_varstring2 :
+ do_varstring2_mb));
}
else if (to_length < from_length)
return (from->charset()->mbmaxlen == 1 ?