summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2015-12-29 14:17:31 +0400
committerAlexander Barkov <bar@mariadb.org>2015-12-29 14:17:31 +0400
commite1b9be5417668b184893148adea5f1f0e3a8d00f (patch)
tree73a4b1035a07612863b227721e659038c3410744
parente126baafbc78f15c794082f0a93740d81041d038 (diff)
downloadmariadb-git-e1b9be5417668b184893148adea5f1f0e3a8d00f.tar.gz
MDEV-9319 ALTER from a bigger to a smaller blob type truncates too much data
-rw-r--r--mysql-test/r/ctype_utf8.result16
-rw-r--r--mysql-test/r/ctype_utf8mb4.result16
-rw-r--r--mysql-test/r/myisam-blob.result4
-rw-r--r--mysql-test/r/type_blob.result33
-rw-r--r--mysql-test/t/ctype_utf8.test11
-rw-r--r--mysql-test/t/ctype_utf8mb4.test12
-rw-r--r--mysql-test/t/type_blob.test25
-rw-r--r--sql/field.cc29
-rw-r--r--sql/field.h11
-rw-r--r--sql/field_conv.cc9
10 files changed, 152 insertions, 14 deletions
diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index 91dbe853a38..dfc872cc734 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -5804,5 +5804,21 @@ c0 c1 c2 c3 c4
2012-06-11 15:18:24 2012-06-11 15:18:24 2012-06-11 15:18:24 2012-06-11 15:18:24 2012-06-11 15:18:24
DROP TABLE t2, t1;
#
+# MDEV-9319 ALTER from a bigger to a smaller blob type truncates too much data
+#
+SET NAMES utf8;
+CREATE TABLE t1 (a TEXT CHARACTER SET utf8);
+INSERT INTO t1 VALUES (REPEAT('A',100));
+SELECT OCTET_LENGTH(a) FROM t1;
+OCTET_LENGTH(a)
+300
+ALTER TABLE t1 MODIFY a TINYTEXT CHARACTER SET utf8;
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+SELECT OCTET_LENGTH(a),a FROM t1;
+OCTET_LENGTH(a) a
+255 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+DROP TABLE t1;
+#
# End of 5.5 tests
#
diff --git a/mysql-test/r/ctype_utf8mb4.result b/mysql-test/r/ctype_utf8mb4.result
index 64556308de2..29749d3f07b 100644
--- a/mysql-test/r/ctype_utf8mb4.result
+++ b/mysql-test/r/ctype_utf8mb4.result
@@ -2606,6 +2606,22 @@ Warning 1292 Truncated incorrect INTEGER value: 'a'
DROP TABLE t1;
# End of test for Bug#13581962,Bug#14096619
#
+# MDEV-9319 ALTER from a bigger to a smaller blob type truncates too much data
+#
+SET NAMES utf8mb4;
+CREATE TABLE t1 (a TEXT CHARACTER SET utf8mb4);
+INSERT INTO t1 VALUES (REPEAT('😎',100));
+SELECT OCTET_LENGTH(a) FROM t1;
+OCTET_LENGTH(a)
+400
+ALTER TABLE t1 MODIFY a TINYTEXT CHARACTER SET utf8mb4;
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+SELECT OCTET_LENGTH(a),a FROM t1;
+OCTET_LENGTH(a) a
+252 😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎😎
+DROP TABLE t1;
+#
# End of 5.5 tests
#
#
diff --git a/mysql-test/r/myisam-blob.result b/mysql-test/r/myisam-blob.result
index 43db7c8badd..6b41a244621 100644
--- a/mysql-test/r/myisam-blob.result
+++ b/mysql-test/r/myisam-blob.result
@@ -29,9 +29,11 @@ select length(data) from t1;
length(data)
18874368
alter table t1 modify data blob;
+Warnings:
+Warning 1265 Data truncated for column 'data' at row 1
select length(data) from t1;
length(data)
-0
+65535
drop table t1;
CREATE TABLE t1 (data BLOB) ENGINE=myisam;
INSERT INTO t1 (data) VALUES (NULL);
diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result
index 723efbdcb23..f49b2a7d5ef 100644
--- a/mysql-test/r/type_blob.result
+++ b/mysql-test/r/type_blob.result
@@ -1000,9 +1000,42 @@ COUNT(*)
DROP FUNCTION f1;
DROP TABLE t1;
End of 5.1 tests
+#
+# Start of 5.5 tests
+#
CREATE TABLE t1 ( f1 blob, f2 blob );
INSERT INTO t1 VALUES ('','');
SELECT f1,f2,"found row" FROM t1 WHERE f1 = f2 ;
f1 f2 found row
found row
DROP TABLE t1;
+#
+# MDEV-9319 ALTER from a bigger to a smaller blob type truncates too much data
+#
+CREATE TABLE t1 (a MEDIUMBLOB);
+INSERT INTO t1 VALUES (REPEAT(0x61,128000));
+SELECT LENGTH(a) FROM t1;
+LENGTH(a)
+128000
+ALTER TABLE t1 MODIFY a BLOB;
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+SELECT LENGTH(a) FROM t1;
+LENGTH(a)
+65535
+DROP TABLE t1;
+CREATE TABLE t1 (a BLOB);
+INSERT INTO t1 VALUES (REPEAT(0x61,65000));
+SELECT LENGTH(a) FROM t1;
+LENGTH(a)
+65000
+ALTER TABLE t1 MODIFY a TINYBLOB;
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+SELECT LENGTH(a) FROM t1;
+LENGTH(a)
+255
+DROP TABLE t1;
+#
+# End of 5.5 tests
+#
diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index 8cd70e9261a..fd70292c6c8 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -1649,5 +1649,16 @@ SELECT * FROM t2;
DROP TABLE t2, t1;
--echo #
+--echo # MDEV-9319 ALTER from a bigger to a smaller blob type truncates too much data
+--echo #
+SET NAMES utf8;
+CREATE TABLE t1 (a TEXT CHARACTER SET utf8);
+INSERT INTO t1 VALUES (REPEAT('A',100));
+SELECT OCTET_LENGTH(a) FROM t1;
+ALTER TABLE t1 MODIFY a TINYTEXT CHARACTER SET utf8;
+SELECT OCTET_LENGTH(a),a FROM t1;
+DROP TABLE t1;
+
+--echo #
--echo # End of 5.5 tests
--echo #
diff --git a/mysql-test/t/ctype_utf8mb4.test b/mysql-test/t/ctype_utf8mb4.test
index fda20ca0ec5..66f5a3ba5ac 100644
--- a/mysql-test/t/ctype_utf8mb4.test
+++ b/mysql-test/t/ctype_utf8mb4.test
@@ -1827,6 +1827,18 @@ DROP TABLE t1;
--echo # End of test for Bug#13581962,Bug#14096619
--echo #
+--echo # MDEV-9319 ALTER from a bigger to a smaller blob type truncates too much data
+--echo #
+SET NAMES utf8mb4;
+CREATE TABLE t1 (a TEXT CHARACTER SET utf8mb4);
+INSERT INTO t1 VALUES (REPEAT('😎',100));
+SELECT OCTET_LENGTH(a) FROM t1;
+ALTER TABLE t1 MODIFY a TINYTEXT CHARACTER SET utf8mb4;
+SELECT OCTET_LENGTH(a),a FROM t1;
+DROP TABLE t1;
+
+
+--echo #
--echo # End of 5.5 tests
--echo #
diff --git a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test
index 66dd71d2305..d5f6fc6ed32 100644
--- a/mysql-test/t/type_blob.test
+++ b/mysql-test/t/type_blob.test
@@ -643,6 +643,10 @@ DROP TABLE t1;
--echo End of 5.1 tests
+--echo #
+--echo # Start of 5.5 tests
+--echo #
+
#
# Problem when comparing blobs #778901
#
@@ -651,3 +655,24 @@ CREATE TABLE t1 ( f1 blob, f2 blob );
INSERT INTO t1 VALUES ('','');
SELECT f1,f2,"found row" FROM t1 WHERE f1 = f2 ;
DROP TABLE t1;
+
+--echo #
+--echo # MDEV-9319 ALTER from a bigger to a smaller blob type truncates too much data
+--echo #
+CREATE TABLE t1 (a MEDIUMBLOB);
+INSERT INTO t1 VALUES (REPEAT(0x61,128000));
+SELECT LENGTH(a) FROM t1;
+ALTER TABLE t1 MODIFY a BLOB;
+SELECT LENGTH(a) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a BLOB);
+INSERT INTO t1 VALUES (REPEAT(0x61,65000));
+SELECT LENGTH(a) FROM t1;
+ALTER TABLE t1 MODIFY a TINYBLOB;
+SELECT LENGTH(a) FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # End of 5.5 tests
+--echo #
diff --git a/sql/field.cc b/sql/field.cc
index aeeacf7f88d..ceea0893a3f 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -7068,6 +7068,35 @@ uint32 Field_blob::get_length(const uchar *pos, uint packlength_arg)
}
+/**
+ Copy a value from another BLOB field of the same character set.
+ This method is used by Copy_field, e.g. during ALTER TABLE.
+*/
+int Field_blob::copy_value(Field_blob *from)
+{
+ DBUG_ASSERT(field_charset == from->charset());
+ int rc= 0;
+ uint32 length= from->get_length();
+ uchar *data;
+ from->get_ptr(&data);
+ if (packlength < from->packlength)
+ {
+ int well_formed_errors;
+ set_if_smaller(length, Field_blob::max_data_length());
+ length= field_charset->cset->well_formed_len(field_charset,
+ (const char *) data,
+ (const char *) data + length,
+ length, &well_formed_errors);
+ rc= report_if_important_data((const char *) data + length,
+ (const char *) data + from->get_length(),
+ true);
+ }
+ store_length(length);
+ bmove(ptr + packlength, (uchar*) &data, sizeof(char*));
+ return rc;
+}
+
+
int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
diff --git a/sql/field.h b/sql/field.h
index 4c79847228e..49f94179a92 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1830,6 +1830,11 @@ protected:
*/
String value;
+ void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number);
+ inline void store_length(uint32 number)
+ {
+ store_length(ptr, packlength, number);
+ }
public:
Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
@@ -1902,11 +1907,6 @@ public:
int reset(void) { bzero(ptr, packlength+sizeof(uchar*)); return 0; }
void reset_fields() { bzero((uchar*) &value,sizeof(value)); }
uint32 get_field_buffer_size(void) { return value.alloced_length(); }
- void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number);
- inline void store_length(uint32 number)
- {
- store_length(ptr, packlength, number);
- }
inline uint32 get_length(uint row_offset= 0)
{ return get_length(ptr+row_offset, this->packlength); }
uint32 get_length(const uchar *ptr, uint packlength);
@@ -1935,6 +1935,7 @@ public:
{
set_ptr_offset(0, length, data);
}
+ int copy_value(Field_blob *from);
uint get_key_image(uchar *buff,uint length, imagetype type);
void set_key_image(const uchar *buff,uint length);
void sql_type(String &str) const;
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index d24f31e4fa1..3fdc1639266 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -332,9 +332,7 @@ static void do_copy_next_number(Copy_field *copy)
static void do_copy_blob(Copy_field *copy)
{
- ulong length=((Field_blob*) copy->from_field)->get_length();
- ((Field_blob*) copy->to_field)->store_length(length);
- memcpy(copy->to_ptr, copy->from_ptr, sizeof(char*));
+ ((Field_blob*) copy->to_field)->copy_value(((Field_blob*) copy->from_field));
}
static void do_conv_blob(Copy_field *copy)
@@ -709,12 +707,7 @@ Copy_field::get_copy_func(Field *to,Field *from)
if (!(from->flags & BLOB_FLAG) || from->charset() != to->charset())
return do_conv_blob;
if (from_length != to_length)
- {
- // Correct pointer to point at char pointer
- to_ptr+= to_length - to->table->s->blob_ptr_size;
- from_ptr+= from_length- from->table->s->blob_ptr_size;
return do_copy_blob;
- }
}
else
{