summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <ramil/ram@mysql.com/ramil.myoffice.izhnet.ru>2007-03-29 11:06:15 +0500
committerunknown <ramil/ram@mysql.com/ramil.myoffice.izhnet.ru>2007-03-29 11:06:15 +0500
commitdf99063599fb02e2b79b6ddf1b4b758c414ce229 (patch)
tree3c1a57c8db1a90caecbbf724533ecc2b1788d0ce
parentdb9af0d82239e2ff016d565e54f2f541f05bb9a3 (diff)
parent86010101e294559d83d0c99def8160eddcf4ce55 (diff)
downloadmariadb-git-df99063599fb02e2b79b6ddf1b4b758c414ce229.tar.gz
Merge mysql.com:/home/ram/work/mysql-5.0-maint
into mysql.com:/home/ram/work/b26359/b26359.5.0 mysql-test/r/strict.result: Auto merged mysql-test/t/strict.test: Auto merged sql/field.cc: Auto merged sql/field.h: Auto merged
-rw-r--r--mysql-test/r/strict.result41
-rw-r--r--mysql-test/r/type_date.result2
-rw-r--r--mysql-test/r/type_year.result12
-rw-r--r--mysql-test/t/strict.test50
-rw-r--r--mysql-test/t/type_year.test10
-rw-r--r--sql/field.cc363
-rw-r--r--sql/field.h7
7 files changed, 259 insertions, 226 deletions
diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result
index 3ba9771f12d..636a00a4343 100644
--- a/mysql-test/r/strict.result
+++ b/mysql-test/r/strict.result
@@ -1346,3 +1346,44 @@ t1 CREATE TABLE `t1` (
`i` int(11) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='123456789*123456789*123456789*123456789*123456789*123456789*'
drop table t1;
+set sql_mode= 'traditional';
+create table t1(col1 tinyint, col2 tinyint unsigned,
+col3 smallint, col4 smallint unsigned,
+col5 mediumint, col6 mediumint unsigned,
+col7 int, col8 int unsigned,
+col9 bigint, col10 bigint unsigned);
+insert into t1(col1) values('-');
+ERROR HY000: Incorrect integer value: '-' for column 'col1' at row 1
+insert into t1(col2) values('+');
+ERROR HY000: Incorrect integer value: '+' for column 'col2' at row 1
+insert into t1(col3) values('-');
+ERROR HY000: Incorrect integer value: '-' for column 'col3' at row 1
+insert into t1(col4) values('+');
+ERROR HY000: Incorrect integer value: '+' for column 'col4' at row 1
+insert into t1(col5) values('-');
+ERROR HY000: Incorrect integer value: '-' for column 'col5' at row 1
+insert into t1(col6) values('+');
+ERROR HY000: Incorrect integer value: '+' for column 'col6' at row 1
+insert into t1(col7) values('-');
+ERROR HY000: Incorrect integer value: '-' for column 'col7' at row 1
+insert into t1(col8) values('+');
+ERROR HY000: Incorrect integer value: '+' for column 'col8' at row 1
+insert into t1(col9) values('-');
+ERROR HY000: Incorrect integer value: '-' for column 'col9' at row 1
+insert into t1(col10) values('+');
+ERROR HY000: Incorrect integer value: '+' for column 'col10' at row 1
+drop table t1;
+set sql_mode='traditional';
+create table t1(a year);
+insert into t1 values ('-');
+ERROR HY000: Incorrect integer value: '-' for column 'a' at row 1
+insert into t1 values ('+');
+ERROR HY000: Incorrect integer value: '+' for column 'a' at row 1
+insert into t1 values ('');
+ERROR HY000: Incorrect integer value: '' for column 'a' at row 1
+insert into t1 values ('2000a');
+ERROR 01000: Data truncated for column 'a' at row 1
+insert into t1 values ('2E3x');
+ERROR 01000: Data truncated for column 'a' at row 1
+drop table t1;
+End of 5.0 tests
diff --git a/mysql-test/r/type_date.result b/mysql-test/r/type_date.result
index ed15293bb45..644d4d971c6 100644
--- a/mysql-test/r/type_date.result
+++ b/mysql-test/r/type_date.result
@@ -99,7 +99,7 @@ DROP TABLE t1, t2, t3;
CREATE TABLE t1 (y YEAR);
INSERT INTO t1 VALUES ('abc');
Warnings:
-Warning 1264 Out of range value adjusted for column 'y' at row 1
+Warning 1366 Incorrect integer value: 'abc' for column 'y' at row 1
SELECT * FROM t1;
y
0000
diff --git a/mysql-test/r/type_year.result b/mysql-test/r/type_year.result
index 84b688429db..e52947455c8 100644
--- a/mysql-test/r/type_year.result
+++ b/mysql-test/r/type_year.result
@@ -34,3 +34,15 @@ select if(y = now(), 1, 0) from t1;
if(y = now(), 1, 0)
1
drop table t1;
+create table t1(a year);
+insert into t1 values (2000.5), ('2000.5'), ('2001a'), ('2.001E3');
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 3
+select * from t1;
+a
+2001
+2001
+2001
+2001
+drop table t1;
+End of 5.0 tests
diff --git a/mysql-test/t/strict.test b/mysql-test/t/strict.test
index 65744068711..5e4d956527b 100644
--- a/mysql-test/t/strict.test
+++ b/mysql-test/t/strict.test
@@ -1200,3 +1200,53 @@ create table t1 (i int)
comment '123456789*123456789*123456789*123456789*123456789*123456789*';
show create table t1;
drop table t1;
+
+#
+# Bug #26359: Strings becoming truncated and converted to numbers under STRICT mode
+#
+set sql_mode= 'traditional';
+create table t1(col1 tinyint, col2 tinyint unsigned,
+ col3 smallint, col4 smallint unsigned,
+ col5 mediumint, col6 mediumint unsigned,
+ col7 int, col8 int unsigned,
+ col9 bigint, col10 bigint unsigned);
+--error 1366
+insert into t1(col1) values('-');
+--error 1366
+insert into t1(col2) values('+');
+--error 1366
+insert into t1(col3) values('-');
+--error 1366
+insert into t1(col4) values('+');
+--error 1366
+insert into t1(col5) values('-');
+--error 1366
+insert into t1(col6) values('+');
+--error 1366
+insert into t1(col7) values('-');
+--error 1366
+insert into t1(col8) values('+');
+--error 1366
+insert into t1(col9) values('-');
+--error 1366
+insert into t1(col10) values('+');
+drop table t1;
+
+#
+# Bug #27176: Assigning a string to an year column has unexpected results
+#
+set sql_mode='traditional';
+create table t1(a year);
+--error 1366
+insert into t1 values ('-');
+--error 1366
+insert into t1 values ('+');
+--error 1366
+insert into t1 values ('');
+--error 1265
+insert into t1 values ('2000a');
+--error 1265
+insert into t1 values ('2E3x');
+drop table t1;
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/type_year.test b/mysql-test/t/type_year.test
index 9744da24c02..0e174a556d6 100644
--- a/mysql-test/t/type_year.test
+++ b/mysql-test/t/type_year.test
@@ -21,4 +21,12 @@ insert into t1 values (now());
select if(y = now(), 1, 0) from t1;
drop table t1;
-# End of 4.1 tests
+#
+# Bug #27176: Assigning a string to an year column has unexpected results
+#
+create table t1(a year);
+insert into t1 values (2000.5), ('2000.5'), ('2001a'), ('2.001E3');
+select * from t1;
+drop table t1;
+
+--echo End of 5.0 tests
diff --git a/sql/field.cc b/sql/field.cc
index 152c1bdc364..f80bf12db92 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -964,6 +964,31 @@ static Item_result field_types_result_type [FIELDTYPE_NUM]=
/*
+ Test if the given string contains important data:
+ not spaces for character string,
+ or any data for binary string.
+
+ SYNOPSIS
+ test_if_important_data()
+ cs Character set
+ str String to test
+ strend String end
+
+ RETURN
+ FALSE - If string does not have important data
+ TRUE - If string has some important data
+*/
+
+static bool
+test_if_important_data(CHARSET_INFO *cs, const char *str, const char *strend)
+{
+ if (cs != &my_charset_bin)
+ str+= cs->cset->scan(cs, str, strend, MY_SEQ_SPACES);
+ return (str < strend);
+}
+
+
+/*
Detect Item_result by given field type of UNION merge result
SYNOPSIS
@@ -1052,64 +1077,113 @@ void Field_num::prepend_zeros(String *value)
}
/*
- Test if given number is a int (or a fixed format float with .000)
+ Test if given number is a int.
SYNOPSIS
- test_if_int()
+ Field_num::check_int
+ cs Character set
str String to test
end Pointer to char after last used digit
- cs Character set
+ length String length
+ error Error returned by strntoull10rnd()
- NOTES
- This is called after one has called my_strntol() or similar function.
- This is only used to give warnings in ALTER TABLE or LOAD DATA...
-
- TODO
- Make this multi-byte-character safe
+ NOTE
+ This is called after one has called strntoull10rnd() function.
RETURN
- 0 OK
- 1 error. A warning is pushed if field_name != 0
+ 0 ok
+ 1 error: empty string or wrong integer.
+ 2 error: garbage at the end of string.
*/
-bool Field::check_int(const char *str, int length, const char *int_end,
- CHARSET_INFO *cs)
+int Field_num::check_int(CHARSET_INFO *cs, const char *str, int length,
+ const char *int_end, int error)
{
- const char *end;
- if (str == int_end)
+ /* Test if we get an empty string or wrong integer */
+ if (str == int_end || error == MY_ERRNO_EDOM)
{
char buff[128];
- String tmp(buff,(uint32) sizeof(buff), system_charset_info);
+ String tmp(buff, (uint32) sizeof(buff), system_charset_info);
tmp.copy(str, length, system_charset_info);
push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
"integer", tmp.c_ptr(), field_name,
(ulong) table->in_use->row_count);
- return 1; // Empty string
+ return 1;
}
- end= str+length;
- if ((str= int_end) == end)
- return 0; // OK; All digits was used
+ /* Test if we have garbage at the end of the given string. */
+ if (test_if_important_data(cs, int_end, str + length))
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
+ return 2;
+ }
+ return 0;
+}
- /* Allow end .0000 */
- if (*str == '.')
+
+/*
+ Conver a string to an integer then check bounds.
+
+ SYNOPSIS
+ Field_num::get_int
+ cs Character set
+ from String to convert
+ len Length of the string
+ rnd OUT longlong value
+ unsigned_max max unsigned value
+ signed_min min signed value
+ signed_max max signed value
+
+ DESCRIPTION
+ The function calls strntoull10rnd() to get an integer value then
+ check bounds and errors returned. In case of any error a warning
+ is raised.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+bool Field_num::get_int(CHARSET_INFO *cs, const char *from, uint len,
+ longlong *rnd, ulonglong unsigned_max,
+ longlong signed_min, longlong signed_max)
+{
+ char *end;
+ int error;
+
+ *rnd= (longlong) cs->cset->strntoull10rnd(cs, from, len, unsigned_flag, &end,
+ &error);
+ if (unsigned_flag)
{
- for (str++ ; str != end && *str == '0'; str++)
- ;
+
+ if (((ulonglong) *rnd > unsigned_max) && (*rnd= (longlong) unsigned_max) ||
+ error == MY_ERRNO_ERANGE)
+ {
+ goto out_of_range;
+ }
}
- /* Allow end space */
- for ( ; str != end ; str++)
+ else
{
- if (!my_isspace(cs,*str))
+ if (*rnd < signed_min)
{
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
- return 1;
+ *rnd= signed_min;
+ goto out_of_range;
+ }
+ else if (*rnd > signed_max)
+ {
+ *rnd= signed_max;
+ goto out_of_range;
}
}
+ if (table->in_use->count_cuted_fields && check_int(cs, from, len, end, error))
+ return 1;
return 0;
-}
+out_of_range:
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+ return 1;
+}
/*
Process decimal library return codes and issue warnings for overflow and
@@ -2506,45 +2580,11 @@ void Field_new_decimal::sql_type(String &str) const
int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs)
{
- char *end;
int error;
-
- if (unsigned_flag)
- {
- ulonglong tmp= cs->cset->strntoull10rnd(cs, from, len, 1, &end, &error);
- if (error == MY_ERRNO_ERANGE || tmp > 255)
- {
- set_if_smaller(tmp, 255);
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
- ptr[0]= (char) tmp;
- }
- else
- {
- longlong tmp= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error);
- if (tmp < -128)
- {
- tmp= -128;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (tmp >= 128)
- {
- tmp= 127;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
- ptr[0]= (char) tmp;
- }
+ longlong rnd;
+
+ error= get_int(cs, from, len, &rnd, 255, -128, 127);
+ ptr[0]= unsigned_flag ? (char) (ulonglong) rnd : (char) rnd;
return error;
}
@@ -2709,59 +2749,20 @@ void Field_tiny::sql_type(String &res) const
int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
{
- char *end;
+ int store_tmp;
int error;
-
- if (unsigned_flag)
- {
- ulonglong tmp= cs->cset->strntoull10rnd(cs, from, len, 1, &end, &error);
- if (error == MY_ERRNO_ERANGE || tmp > UINT_MAX16)
- {
- set_if_smaller(tmp, UINT_MAX16);
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
+ longlong rnd;
+
+ error= get_int(cs, from, len, &rnd, UINT_MAX16, INT_MIN16, INT_MAX16);
+ store_tmp= unsigned_flag ? (int) (ulonglong) rnd : (int) rnd;
#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- int2store(ptr,tmp);
- }
- else
-#endif
- shortstore(ptr,(short) tmp);
+ if (table->s->db_low_byte_first)
+ {
+ int2store(ptr, store_tmp);
}
else
- {
- longlong tmp= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error);
- if (tmp < INT_MIN16)
- {
- tmp= INT_MIN16;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (tmp > INT_MAX16)
- {
- tmp=INT_MAX16;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- int2store(ptr,tmp);
- }
- else
#endif
- shortstore(ptr,(short) tmp);
- }
+ shortstore(ptr, (short) store_tmp);
return error;
}
@@ -2989,45 +2990,13 @@ void Field_short::sql_type(String &res) const
int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs)
{
- char *end;
+ int store_tmp;
int error;
-
- if (unsigned_flag)
- {
- ulonglong tmp= cs->cset->strntoull10rnd(cs, from, len, 1, &end, &error);
- if (error == MY_ERRNO_ERANGE || tmp > UINT_MAX24)
- {
- set_if_smaller(tmp, UINT_MAX24);
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
- int3store(ptr,tmp);
- }
- else
- {
- longlong tmp= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error);
- if (tmp < INT_MIN24)
- {
- tmp= INT_MIN24;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (tmp > INT_MAX24)
- {
- tmp=INT_MAX24;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
- int3store(ptr,tmp);
- }
+ longlong rnd;
+
+ error= get_int(cs, from, len, &rnd, UINT_MAX24, INT_MIN24, INT_MAX24);
+ store_tmp= unsigned_flag ? (int) (ulonglong) rnd : (int) rnd;
+ int3store(ptr, store_tmp);
return error;
}
@@ -3206,45 +3175,10 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
{
long store_tmp;
int error;
- char *end;
-
- if (unsigned_flag)
- {
- ulonglong tmp= cs->cset->strntoull10rnd(cs, from, len, 1, &end, &error);
- if (error == MY_ERRNO_ERANGE || tmp > (ulonglong) UINT_MAX32)
- {
- set_if_smaller(tmp, (ulonglong) UINT_MAX32);
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
- store_tmp= (long) tmp;
- }
- else
- {
- longlong tmp= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error);
- if (tmp < INT_MIN32)
- {
- tmp= INT_MIN32;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (tmp > INT_MAX32)
- {
- tmp=INT_MAX32;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
- store_tmp= (long) tmp;
- }
-
+ longlong rnd;
+
+ error= get_int(cs, from, len, &rnd, UINT_MAX32, INT_MIN32, INT_MAX32);
+ store_tmp= unsigned_flag ? (long) (ulonglong) rnd : (long) rnd;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
{
@@ -3490,7 +3424,8 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
+ else if (table->in_use->count_cuted_fields &&
+ check_int(cs, from, len, end, error))
error= 1;
else
error= 0;
@@ -5008,16 +4943,25 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
{
char *end;
int error;
- long nr= my_strntol(cs, from, len, 10, &end, &error);
+ longlong nr= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error);
- if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155 || error)
+ if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155 ||
+ error == MY_ERRNO_ERANGE)
{
*ptr=0;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
return 1;
}
- if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
+ if (table->in_use->count_cuted_fields &&
+ (error= check_int(cs, from, len, end, error)))
+ {
+ if (error == 1) /* empty or incorrect string */
+ {
+ *ptr= 0;
+ return 1;
+ }
error= 1;
+ }
if (nr != 0 || len != 4)
{
@@ -5907,31 +5851,6 @@ report_data_too_long(Field_str *field)
}
-/*
- Test if the given string contains important data:
- not spaces for character string,
- or any data for binary string.
-
- SYNOPSIS
- test_if_important_data()
- cs Character set
- str String to test
- strend String end
-
- RETURN
- FALSE - If string does not have important data
- TRUE - If string has some important data
-*/
-
-static bool
-test_if_important_data(CHARSET_INFO *cs, const char *str, const char *strend)
-{
- if (cs != &my_charset_bin)
- str+= cs->cset->scan(cs, str, strend, MY_SEQ_SPACES);
- return (str < strend);
-}
-
-
/* Copy a string and fill with space */
int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
diff --git a/sql/field.h b/sql/field.h
index 0f30f5332ff..eb00899cf54 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -306,8 +306,6 @@ public:
virtual void set_derivation(enum Derivation derivation_arg) { }
bool set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code,
int cuted_increment);
- bool check_int(const char *str, int length, const char *int_end,
- CHARSET_INFO *cs);
void set_datetime_warning(MYSQL_ERROR::enum_warning_level, uint code,
const char *str, uint str_len,
timestamp_type ts_type, int cuted_increment);
@@ -369,6 +367,11 @@ public:
bool eq_def(Field *field);
int store_decimal(const my_decimal *);
my_decimal *val_decimal(my_decimal *);
+ int check_int(CHARSET_INFO *cs, const char *str, int length,
+ const char *int_end, int error);
+ bool get_int(CHARSET_INFO *cs, const char *from, uint len,
+ longlong *rnd, ulonglong unsigned_max,
+ longlong signed_min, longlong signed_max);
};