Commit 652e799a authored by Alexander Barkov's avatar Alexander Barkov

MDEV-8502 DECIMAL accepts out of range DEFAULT values

MDEV-10277 Redundant NOTE when inserting '0.00001 ' into a DECIMAL(2,1) column
parent 305bbbce
......@@ -155,7 +155,7 @@ connection master;
f6 ENUM('a', 'b', 'c') default 'a',
f7 DECIMAL(17,9) default '1000.00',
f8 MEDIUMBLOB,
f9 NUMERIC(6,4) default '2000.00',
f9 NUMERIC(6,2) default '2000.00',
f10 VARCHAR(1024),
f11 BINARY(20) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
f12 SET('a', 'b', 'c') default 'b')
......@@ -178,7 +178,7 @@ connection master;
f5 DOUBLE DEFAULT '2.00',
f6 DECIMAL(17,9) default '1000.00',
f7 MEDIUMBLOB,
f8 NUMERIC(6,4) default '2000.00',
f8 NUMERIC(6,2) default '2000.00',
f9 VARCHAR(1024),
f10 BINARY(20) not null default '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
f11 CHAR(255))
......
......@@ -2151,5 +2151,95 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 6 const 1 Using where; Using index; Using filesort
DROP TABLE t1;
#
# MDEV-8502 DECIMAL accepts out of range DEFAULT values
#
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT 10000);
ERROR 42000: Invalid default value for 'a'
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT 10000.0);
ERROR 42000: Invalid default value for 'a'
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT 10000e0);
ERROR 42000: Invalid default value for 'a'
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT '10000.0');
ERROR 42000: Invalid default value for 'a'
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT '10000.1');
ERROR 42000: Invalid default value for 'a'
#
# MDEV-10277 Redundant NOTE when inserting '0.00001 ' into a DECIMAL(2,1) column
#
CREATE TABLE t1 (a DECIMAL(2,1));
INSERT INTO t1 VALUES ('0.00001 ');
Warnings:
Note 1265 Data truncated for column 'a' at row 1
INSERT INTO t1 VALUES ('1e-10000 ');
Warnings:
Note 1265 Data truncated for column 'a' at row 1
INSERT INTO t1 VALUES ('0.1 ');
Warnings:
Note 1265 Data truncated for column 'a' at row 1
INSERT INTO t1 VALUES ('0.111 ');
Warnings:
Note 1265 Data truncated for column 'a' at row 1
SELECT * FROM t1;
a
0.0
0.0
0.1
0.1
DROP TABLE t1;
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT '1e-10000');
Warnings:
Note 1265 Data truncated for column 'a' at row 1
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` decimal(2,1) DEFAULT '0.0'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT '0.1 ');
Warnings:
Note 1265 Data truncated for column 'a' at row 1
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` decimal(2,1) DEFAULT '0.1'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT '0.10001 ');
Warnings:
Note 1265 Data truncated for column 'a' at row 1
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` decimal(2,1) DEFAULT '0.1'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT '0.10001');
Warnings:
Note 1265 Data truncated for column 'a' at row 1
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` decimal(2,1) DEFAULT '0.1'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT 0.10001);
Warnings:
Note 1265 Data truncated for column 'a' at row 1
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` decimal(2,1) DEFAULT '0.1'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT 0.10001e0);
Warnings:
Note 1265 Data truncated for column 'a' at row 1
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` decimal(2,1) DEFAULT '0.1'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
#
# End of 10.1 tests
#
......@@ -96,13 +96,11 @@ f5 DOUBLE DEFAULT '2.00',
f6 ENUM('a', 'b', 'c') default 'a',
f7 DECIMAL(17,9) default '1000.00',
f8 MEDIUMBLOB,
f9 NUMERIC(6,4) default '2000.00',
f9 NUMERIC(6,2) default '2000.00',
f10 VARCHAR(1024),
f11 BINARY(20) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
f12 SET('a', 'b', 'c') default 'b')
ENGINE='InnoDB';
Warnings:
Warning 1264 Out of range value for column 'f9' at row 1
CREATE TABLE t3 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20),
/* extra */
......@@ -119,13 +117,11 @@ CREATE TABLE t4 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20),
f5 DOUBLE DEFAULT '2.00',
f6 DECIMAL(17,9) default '1000.00',
f7 MEDIUMBLOB,
f8 NUMERIC(6,4) default '2000.00',
f8 NUMERIC(6,2) default '2000.00',
f9 VARCHAR(1024),
f10 BINARY(20) not null default '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
f11 CHAR(255))
ENGINE='InnoDB';
Warnings:
Warning 1264 Out of range value for column 'f8' at row 1
CREATE TABLE t31 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20),
/* extra */
......@@ -184,9 +180,6 @@ INSERT into t2 values (2, 2, 2, 'second',
(3, 3, 3, 'third',
3.0, 'b', 3000.0003, 'f8: medium size blob', 3000, 'f10: some var char',
'01234567', 'c');
Warnings:
Warning 1264 Out of range value for column 'f9' at row 1
Warning 1264 Out of range value for column 'f9' at row 2
INSERT into t3 set f1=1, f2=1, f3=1, f4='first', f10='f10: some var char';
INSERT into t4 set f1=1, f2=1, f3=1, f4='first', f7='f7: medium size blob', f10='f10:
binary data';
......
......@@ -96,13 +96,11 @@ f5 DOUBLE DEFAULT '2.00',
f6 ENUM('a', 'b', 'c') default 'a',
f7 DECIMAL(17,9) default '1000.00',
f8 MEDIUMBLOB,
f9 NUMERIC(6,4) default '2000.00',
f9 NUMERIC(6,2) default '2000.00',
f10 VARCHAR(1024),
f11 BINARY(20) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
f12 SET('a', 'b', 'c') default 'b')
ENGINE='MyISAM';
Warnings:
Warning 1264 Out of range value for column 'f9' at row 1
CREATE TABLE t3 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20),
/* extra */
......@@ -119,13 +117,11 @@ CREATE TABLE t4 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20),
f5 DOUBLE DEFAULT '2.00',
f6 DECIMAL(17,9) default '1000.00',
f7 MEDIUMBLOB,
f8 NUMERIC(6,4) default '2000.00',
f8 NUMERIC(6,2) default '2000.00',
f9 VARCHAR(1024),
f10 BINARY(20) not null default '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
f11 CHAR(255))
ENGINE='MyISAM';
Warnings:
Warning 1264 Out of range value for column 'f8' at row 1
CREATE TABLE t31 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20),
/* extra */
......@@ -184,9 +180,6 @@ INSERT into t2 values (2, 2, 2, 'second',
(3, 3, 3, 'third',
3.0, 'b', 3000.0003, 'f8: medium size blob', 3000, 'f10: some var char',
'01234567', 'c');
Warnings:
Warning 1264 Out of range value for column 'f9' at row 1
Warning 1264 Out of range value for column 'f9' at row 2
INSERT into t3 set f1=1, f2=1, f3=1, f4='first', f10='f10: some var char';
INSERT into t4 set f1=1, f2=1, f3=1, f4='first', f7='f7: medium size blob', f10='f10:
binary data';
......
......@@ -1684,6 +1684,57 @@ INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
EXPLAIN SELECT * FROM t1 WHERE a='ax' ORDER BY a;
DROP TABLE t1;
--echo #
--echo # MDEV-8502 DECIMAL accepts out of range DEFAULT values
--echo #
--error ER_INVALID_DEFAULT
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT 10000);
--error ER_INVALID_DEFAULT
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT 10000.0);
--error ER_INVALID_DEFAULT
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT 10000e0);
--error ER_INVALID_DEFAULT
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT '10000.0');
--error ER_INVALID_DEFAULT
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT '10000.1');
--echo #
--echo # MDEV-10277 Redundant NOTE when inserting '0.00001 ' into a DECIMAL(2,1) column
--echo #
CREATE TABLE t1 (a DECIMAL(2,1));
INSERT INTO t1 VALUES ('0.00001 ');
INSERT INTO t1 VALUES ('1e-10000 ');
INSERT INTO t1 VALUES ('0.1 ');
INSERT INTO t1 VALUES ('0.111 ');
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT '1e-10000');
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT '0.1 ');
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT '0.10001 ');
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT '0.10001');
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT 0.10001);
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT 0.10001e0);
SHOW CREATE TABLE t1;
DROP TABLE t1;
--echo #
--echo # End of 10.1 tests
--echo #
......@@ -1477,10 +1477,12 @@ Value_source::Converter_string_to_number::check_edom_and_truncation(THD *thd,
*/
int Field_num::check_edom_and_truncation(const char *type, bool edom,
CHARSET_INFO *cs,
const char *str, uint length,
const char *end)
int Field_num::check_edom_and_important_data_truncation(const char *type,
bool edom,
CHARSET_INFO *cs,
const char *str,
uint length,
const char *end)
{
/* Test if we get an empty string or garbage */
if (edom)
......@@ -1495,12 +1497,23 @@ int Field_num::check_edom_and_truncation(const char *type, bool edom,
set_warning(WARN_DATA_TRUNCATED, 1);
return 2;
}
if (end < str + length)
set_note(WARN_DATA_TRUNCATED, 1);
return 0;
}
int Field_num::check_edom_and_truncation(const char *type, bool edom,
CHARSET_INFO *cs,
const char *str, uint length,
const char *end)
{
int rc= check_edom_and_important_data_truncation(type, edom,
cs, str, length, end);
if (!rc && end < str + length)
set_note(WARN_DATA_TRUNCATED, 1);
return rc;
}
/*
Conver a string to an integer then check bounds.
......@@ -3005,7 +3018,8 @@ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value,
If it does, stores the decimal in the buffer using binary format.
Otherwise sets maximal number that can be stored in the field.
@param decimal_value my_decimal
@param decimal_value my_decimal
@param [OUT] native_error the error returned by my_decimal2binary().
@retval
0 ok
......@@ -3013,7 +3027,8 @@ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value,
1 error
*/
bool Field_new_decimal::store_value(const my_decimal *decimal_value)
bool Field_new_decimal::store_value(const my_decimal *decimal_value,
int *native_error)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
int error= 0;
......@@ -3042,11 +3057,14 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value)
}
#endif
if (warn_if_overflow(my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
decimal_value, ptr, precision, dec)))
*native_error= my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
decimal_value, ptr, precision, dec);
if (*native_error == E_DEC_OVERFLOW)
{
my_decimal buff;
DBUG_PRINT("info", ("overflow"));
set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
set_value_on_overflow(&buff, decimal_value->sign());
my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, precision, dec);
error= 1;
......@@ -3057,6 +3075,16 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value)
}
bool Field_new_decimal::store_value(const my_decimal *decimal_value)
{
int native_error;
bool rc= store_value(decimal_value, &native_error);
if (!rc && native_error == E_DEC_TRUNCATED)
set_note(WARN_DATA_TRUNCATED, 1);
return rc;
}
int Field_new_decimal::store(const char *from, uint length,
CHARSET_INFO *charset_arg)
{
......@@ -3084,9 +3112,10 @@ int Field_new_decimal::store(const char *from, uint length,
if (thd->count_cuted_fields)
{
if (check_edom_and_truncation("decimal",
err && err != E_DEC_TRUNCATED,
charset_arg, from, length, end))
if (check_edom_and_important_data_truncation("decimal",
err && err != E_DEC_TRUNCATED,
charset_arg,
from, length, end))
{
if (!thd->abort_on_warning)
{
......@@ -3109,12 +3138,6 @@ int Field_new_decimal::store(const char *from, uint length,
}
DBUG_RETURN(1);
}
/*
E_DEC_TRUNCATED means minor truncation '1e-1000000000000' -> 0.0
A note should be enough.
*/
if (err == E_DEC_TRUNCATED)
set_note(WARN_DATA_TRUNCATED, 1);
}
#ifndef DBUG_OFF
......@@ -3122,7 +3145,21 @@ int Field_new_decimal::store(const char *from, uint length,
DBUG_PRINT("enter", ("value: %s",
dbug_decimal_as_string(dbug_buff, &decimal_value)));
#endif
store_value(&decimal_value);
int err2;
if (store_value(&decimal_value, &err2))
DBUG_RETURN(1);
/*
E_DEC_TRUNCATED means minor truncation, a note should be enough:
- in err: str2my_decimal() truncated '1e-1000000000000' to 0.0
- in err2: store_value() truncated 1.123 to 1.12, e.g. for DECIMAL(10,2)
Also, we send a note if a string had some trailing spaces: '1.12 '
*/
if (thd->count_cuted_fields &&
(err == E_DEC_TRUNCATED ||
err2 == E_DEC_TRUNCATED ||
end < from + length))
set_note(WARN_DATA_TRUNCATED, 1);
DBUG_RETURN(0);
}
......
......@@ -1471,6 +1471,10 @@ class Field: public Value_source
class Field_num :public Field {
protected:
int check_edom_and_important_data_truncation(const char *type, bool edom,
CHARSET_INFO *cs,
const char *str, uint length,
const char *end_of_num);
int check_edom_and_truncation(const char *type, bool edom,
CHARSET_INFO *cs,
const char *str, uint length,
......@@ -1708,6 +1712,7 @@ class Field_new_decimal :public Field_num {
Item_result result_type () const { return DECIMAL_RESULT; }
int reset(void);
bool store_value(const my_decimal *decimal_value);
bool store_value(const my_decimal *decimal_value, int *native_error);
void set_value_on_overflow(my_decimal *decimal_value, bool sign);
int store(const char *to, uint length, CHARSET_INFO *charset);
int store(double nr);
......
......@@ -96,13 +96,11 @@ f5 DOUBLE DEFAULT '2.00',
f6 ENUM('a', 'b', 'c') default 'a',
f7 DECIMAL(17,9) default '1000.00',
f8 MEDIUMBLOB,
f9 NUMERIC(6,4) default '2000.00',
f9 NUMERIC(6,2) default '2000.00',
f10 VARCHAR(1024),
f11 BINARY(20) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
f12 SET('a', 'b', 'c') default 'b')
ENGINE=TokuDB;
Warnings:
Warning 1264 Out of range value for column 'f9' at row 1
CREATE TABLE t3 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20),
/* extra */
......@@ -119,13 +117,11 @@ CREATE TABLE t4 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20),
f5 DOUBLE DEFAULT '2.00',
f6 DECIMAL(17,9) default '1000.00',
f7 MEDIUMBLOB,
f8 NUMERIC(6,4) default '2000.00',
f8 NUMERIC(6,2) default '2000.00',
f9 VARCHAR(1024),
f10 BINARY(20) not null default '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
f11 CHAR(255))
ENGINE=TokuDB;
Warnings:
Warning 1264 Out of range value for column 'f8' at row 1
CREATE TABLE t31 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20),
/* extra */
......@@ -184,9 +180,6 @@ INSERT into t2 values (2, 2, 2, 'second',
(3, 3, 3, 'third',
3.0, 'b', 3000.0003, 'f8: medium size blob', 3000, 'f10: some var char',
'01234567', 'c');
Warnings:
Warning 1264 Out of range value for column 'f9' at row 1
Warning 1264 Out of range value for column 'f9' at row 2
INSERT into t3 set f1=1, f2=1, f3=1, f4='first', f10='f10: some var char';
INSERT into t4 set f1=1, f2=1, f3=1, f4='first', f7='f7: medium size blob', f10='f10:
binary data';
......
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