Fixed bug#30059.

Server handles truncation for assignment of too-long values
into CHAR/VARCHAR/TEXT columns in a different ways when the
truncated characters are spaces:
1. CHAR(N) columns silently ignore end-space truncation;
2. TEXT columns post a truncation warning/error in the
   non-strict/strict mode.
3. VARCHAR columns always post a truncation note in
   any mode.

Space truncation processing has been synchronised over
CHAR/VARCHAR/TEXT columns: current behavior of VARCHAR
columns has been propagated as standard.

Binary-encoded string/BLOB columns are not affected.
parent e80794b3
...@@ -256,6 +256,7 @@ set @a=repeat(' ',20); ...@@ -256,6 +256,7 @@ set @a=repeat(' ',20);
insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a)); insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a));
Warnings: Warnings:
Note 1265 Data truncated for column 'v' at row 1 Note 1265 Data truncated for column 'v' at row 1
Note 1265 Data truncated for column 'c' at row 1
select concat('*',v,'*',c,'*',t,'*') from t1; select concat('*',v,'*',c,'*',t,'*') from t1;
concat('*',v,'*',c,'*',t,'*') concat('*',v,'*',c,'*',t,'*')
*+ *+*+ * *+ *+*+ *
......
...@@ -1901,6 +1901,7 @@ set @a=repeat(' ',20); ...@@ -1901,6 +1901,7 @@ set @a=repeat(' ',20);
insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a)); insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a));
Warnings: Warnings:
Note 1265 Data truncated for column 'v' at row 1 Note 1265 Data truncated for column 'v' at row 1
Note 1265 Data truncated for column 'c' at row 1
select concat('*',v,'*',c,'*',t,'*') from t1; select concat('*',v,'*',c,'*',t,'*') from t1;
concat('*',v,'*',c,'*',t,'*') concat('*',v,'*',c,'*',t,'*')
*+ *+*+ * *+ *+*+ *
......
...@@ -1104,6 +1104,7 @@ set @a=repeat(' ',20); ...@@ -1104,6 +1104,7 @@ set @a=repeat(' ',20);
insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a)); insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a));
Warnings: Warnings:
Note 1265 Data truncated for column 'v' at row 1 Note 1265 Data truncated for column 'v' at row 1
Note 1265 Data truncated for column 'c' at row 1
select concat('*',v,'*',c,'*',t,'*') from t1; select concat('*',v,'*',c,'*',t,'*') from t1;
concat('*',v,'*',c,'*',t,'*') concat('*',v,'*',c,'*',t,'*')
*+ *+*+ * *+ *+*+ *
......
...@@ -934,6 +934,8 @@ NULL NULL ...@@ -934,6 +934,8 @@ NULL NULL
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (col1 CHAR(5), col2 VARCHAR(6)); CREATE TABLE t1 (col1 CHAR(5), col2 VARCHAR(6));
INSERT INTO t1 VALUES ('hello', 'hello'),('he', 'he'),('hello ', 'hello '); INSERT INTO t1 VALUES ('hello', 'hello'),('he', 'he'),('hello ', 'hello ');
Warnings:
Note 1265 Data truncated for column 'col1' at row 3
INSERT INTO t1 (col1) VALUES ('hellobob'); INSERT INTO t1 (col1) VALUES ('hellobob');
ERROR 22001: Data too long for column 'col1' at row 1 ERROR 22001: Data too long for column 'col1' at row 1
INSERT INTO t1 (col2) VALUES ('hellobob'); INSERT INTO t1 (col2) VALUES ('hellobob');
......
...@@ -125,6 +125,7 @@ create table t1 (c char(2), vc varchar(2)); ...@@ -125,6 +125,7 @@ create table t1 (c char(2), vc varchar(2));
insert into t1 values(0x4120, 0x4120); insert into t1 values(0x4120, 0x4120);
insert into t1 values(0x412020, 0x412020); insert into t1 values(0x412020, 0x412020);
Warnings: Warnings:
Note 1265 Data truncated for column 'c' at row 1
Note 1265 Data truncated for column 'vc' at row 1 Note 1265 Data truncated for column 'vc' at row 1
drop table t1; drop table t1;
set @old_sql_mode= @@sql_mode, sql_mode= 'traditional'; set @old_sql_mode= @@sql_mode, sql_mode= 'traditional';
......
...@@ -298,4 +298,42 @@ DROP TABLE t3; ...@@ -298,4 +298,42 @@ DROP TABLE t3;
DROP PROCEDURE sp1; DROP PROCEDURE sp1;
DROP PROCEDURE sp2; DROP PROCEDURE sp2;
DROP PROCEDURE sp3; DROP PROCEDURE sp3;
create table t1 (c_char char(255), c_varchar varchar(255), c_tinytext tinytext);
create table t2 (c_tinyblob tinyblob);
set @c = repeat(' ', 256);
set @q = repeat('q', 256);
set sql_mode = '';
insert into t1 values(@c, @c, @c);
Warnings:
Note 1265 Data truncated for column 'c_char' at row 1
Note 1265 Data truncated for column 'c_varchar' at row 1
Note 1265 Data truncated for column 'c_tinytext' at row 1
insert into t2 values(@c);
Warnings:
Warning 1265 Data truncated for column 'c_tinyblob' at row 1
insert into t1 values(@q, @q, @q);
Warnings:
Warning 1265 Data truncated for column 'c_char' at row 1
Warning 1265 Data truncated for column 'c_varchar' at row 1
Warning 1265 Data truncated for column 'c_tinytext' at row 1
insert into t2 values(@q);
Warnings:
Warning 1265 Data truncated for column 'c_tinyblob' at row 1
set sql_mode = 'traditional';
insert into t1 values(@c, @c, @c);
Warnings:
Note 1265 Data truncated for column 'c_char' at row 1
Note 1265 Data truncated for column 'c_varchar' at row 1
Note 1265 Data truncated for column 'c_tinytext' at row 1
insert into t2 values(@c);
ERROR 22001: Data too long for column 'c_tinyblob' at row 1
insert into t1 values(@q, NULL, NULL);
ERROR 22001: Data too long for column 'c_char' at row 1
insert into t1 values(NULL, @q, NULL);
ERROR 22001: Data too long for column 'c_varchar' at row 1
insert into t1 values(NULL, NULL, @q);
ERROR 22001: Data too long for column 'c_tinytext' at row 1
insert into t2 values(@q);
ERROR 22001: Data too long for column 'c_tinyblob' at row 1
drop table t1, t2;
End of 5.0 tests End of 5.0 tests
...@@ -212,4 +212,37 @@ DROP PROCEDURE sp1; ...@@ -212,4 +212,37 @@ DROP PROCEDURE sp1;
DROP PROCEDURE sp2; DROP PROCEDURE sp2;
DROP PROCEDURE sp3; DROP PROCEDURE sp3;
#
# Bug#30059: End-space truncation warnings are inconsistent or incorrect
#
create table t1 (c_char char(255), c_varchar varchar(255), c_tinytext tinytext);
create table t2 (c_tinyblob tinyblob); # not affected by bug, for regression testing
set @c = repeat(' ', 256);
set @q = repeat('q', 256);
set sql_mode = '';
insert into t1 values(@c, @c, @c);
insert into t2 values(@c);
insert into t1 values(@q, @q, @q);
insert into t2 values(@q);
set sql_mode = 'traditional';
insert into t1 values(@c, @c, @c);
--error 1406
insert into t2 values(@c);
--error 1406
insert into t1 values(@q, NULL, NULL);
--error 1406
insert into t1 values(NULL, @q, NULL);
--error 1406
insert into t1 values(NULL, NULL, @q);
--error 1406
insert into t2 values(@q);
drop table t1, t2;
--echo End of 5.0 tests --echo End of 5.0 tests
...@@ -5861,26 +5861,41 @@ check_string_copy_error(Field_str *field, ...@@ -5861,26 +5861,41 @@ check_string_copy_error(Field_str *field,
} }
/* /*
Send a truncation warning or a truncation error Check if we lost any important data and send a truncation error/warning
after storing a too long character string info a field.
SYNOPSIS SYNOPSIS
report_data_too_long() Field_longstr::report_if_important_data()
field - Field ptr - Truncated rest of string
end - End of truncated string
RETURN RETURN VALUES
N/A 0 - None was truncated (or we don't count cut fields)
2 - Some bytes was truncated
NOTE
Check if we lost any important data (anything in a binary string,
or any non-space in others). If only trailing spaces was lost,
send a truncation note, otherwise send a truncation error.
*/ */
inline void int
report_data_too_long(Field_str *field) Field_longstr::report_if_important_data(const char *ptr, const char *end)
{ {
if (field->table->in_use->abort_on_warning) if ((ptr < end) && table->in_use->count_cuted_fields)
field->set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); {
if (test_if_important_data(field_charset, ptr, end))
{
if (table->in_use->abort_on_warning)
set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
else else
field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
}
else /* If we lost only spaces then produce a NOTE, not a WARNING */
set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1);
return 2;
}
return 0;
} }
...@@ -5914,19 +5929,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) ...@@ -5914,19 +5929,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
cannot_convert_error_pos, from + length)) cannot_convert_error_pos, from + length))
return 2; return 2;
/* return report_if_important_data(from_end_pos, from + length);
Check if we lost any important data (anything in a binary string,
or any non-space in others).
*/
if ((from_end_pos < from + length) && table->in_use->count_cuted_fields)
{
if (test_if_important_data(field_charset, from_end_pos, from + length))
{
report_data_too_long(this);
return 2;
}
}
return 0;
} }
...@@ -6385,16 +6388,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) ...@@ -6385,16 +6388,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
cannot_convert_error_pos, from + length)) cannot_convert_error_pos, from + length))
return 2; return 2;
// Check if we lost something other than just trailing spaces return report_if_important_data(from_end_pos, from + length);
if ((from_end_pos < from + length) && table->in_use->count_cuted_fields)
{
if (test_if_important_data(field_charset, from_end_pos, from + length))
report_data_too_long(this);
else /* If we lost only spaces then produce a NOTE, not a WARNING */
set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1);
return 2;
}
return 0;
} }
...@@ -7030,13 +7024,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) ...@@ -7030,13 +7024,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
cannot_convert_error_pos, from + length)) cannot_convert_error_pos, from + length))
return 2; return 2;
if (from_end_pos < from + length) return report_if_important_data(from_end_pos, from + length);
{
report_data_too_long(this);
return 2;
}
return 0;
oom_error: oom_error:
/* Fatal OOM error */ /* Fatal OOM error */
......
...@@ -454,6 +454,8 @@ public: ...@@ -454,6 +454,8 @@ public:
class Field_longstr :public Field_str class Field_longstr :public Field_str
{ {
protected:
int report_if_important_data(const char *ptr, const char *end);
public: public:
Field_longstr(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, Field_longstr(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg, uchar null_bit_arg, utype unireg_check_arg,
......
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