Commit cd32f842 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-12770 Add Type_handler::decimal_precision() + MDEV-12769

This patch for MDEV-12770 is also fixing:

MDEV-12769 Arithmetic operators with temporal types create excessive column types
parent 18ad1768
......@@ -950,10 +950,10 @@ sec_to_time(1) + 0, from_unixtime(1) + 0;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`now() - now()` bigint(21) NOT NULL,
`curtime() - curtime()` bigint(12) NOT NULL,
`sec_to_time(1) + 0` bigint(12) DEFAULT NULL,
`from_unixtime(1) + 0` bigint(21) DEFAULT NULL
`now() - now()` bigint(16) NOT NULL,
`curtime() - curtime()` int(9) NOT NULL,
`sec_to_time(1) + 0` int(9) DEFAULT NULL,
`from_unixtime(1) + 0` bigint(16) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
SELECT SEC_TO_TIME(3300000);
......@@ -2054,11 +2054,11 @@ SEC_TO_TIME(1.123456)+0.1,
SEC_TO_TIME(1.1234567)+0.1;
SHOW COLUMNS FROM t1;
Field Type Null Key Default Extra
SEC_TO_TIME(1)+0.1 decimal(12,1) YES NULL
SEC_TO_TIME(1.1)+0.1 decimal(13,1) YES NULL
SEC_TO_TIME(1.12)+0.1 decimal(14,2) YES NULL
SEC_TO_TIME(1.123456)+0.1 decimal(18,6) YES NULL
SEC_TO_TIME(1.1234567)+0.1 decimal(18,6) YES NULL
SEC_TO_TIME(1)+0.1 decimal(9,1) YES NULL
SEC_TO_TIME(1.1)+0.1 decimal(9,1) YES NULL
SEC_TO_TIME(1.12)+0.1 decimal(10,2) YES NULL
SEC_TO_TIME(1.123456)+0.1 decimal(14,6) YES NULL
SEC_TO_TIME(1.1234567)+0.1 decimal(14,6) YES NULL
DROP TABLE t1;
CREATE TABLE t1 (a DATE) ENGINE=MyISAM;
INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23');
......
......@@ -131,18 +131,18 @@ show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` datetime(4) DEFAULT NULL,
`a+0` decimal(25,4) DEFAULT NULL,
`a-1` decimal(25,4) DEFAULT NULL,
`a*1` decimal(25,4) DEFAULT NULL,
`a/2` decimal(28,8) DEFAULT NULL
`a+0` decimal(19,4) DEFAULT NULL,
`a-1` decimal(19,4) DEFAULT NULL,
`a*1` decimal(19,4) DEFAULT NULL,
`a/2` decimal(22,8) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
`max(a)` datetime(4) DEFAULT NULL,
`min(a)` datetime(4) DEFAULT NULL,
`sum(a)` decimal(46,4) DEFAULT NULL,
`avg(a)` decimal(28,8) DEFAULT NULL
`sum(a)` decimal(40,4) DEFAULT NULL,
`avg(a)` decimal(22,8) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1, t2, t3;
create table t1 (f0_datetime datetime(0), f1_datetime datetime(1), f2_datetime datetime(2), f3_datetime datetime(3), f4_datetime datetime(4), f5_datetime datetime(5), f6_datetime datetime(6));
......
......@@ -221,7 +221,7 @@ MAX(t0)+1
101011
SHOW COLUMNS FROM t2;
Field Type Null Key Default Extra
MAX(t0)+1 bigint(12) YES NULL
MAX(t0)+1 int(9) YES NULL
DROP TABLE t2,t1;
CREATE TABLE t1 (t0 TIME);
INSERT INTO t1 VALUES ('10:10:10');
......@@ -234,7 +234,7 @@ MAX(t0)+1.1
101011.1
SHOW COLUMNS FROM t2;
Field Type Null Key Default Extra
MAX(t0)+1.1 decimal(12,1) YES NULL
MAX(t0)+1.1 decimal(9,1) YES NULL
DROP TABLE t2,t1;
CREATE TABLE t1 (t0 TIME);
INSERT INTO t1 VALUES ('10:10:10');
......@@ -260,7 +260,7 @@ MAX(t1)+1
101011.0
SHOW COLUMNS FROM t2;
Field Type Null Key Default Extra
MAX(t1)+1 decimal(13,1) YES NULL
MAX(t1)+1 decimal(9,1) YES NULL
DROP TABLE t2,t1;
CREATE TABLE t1 (t0 DATETIME);
INSERT INTO t1 VALUES ('2001-01-01 10:10:10');
......@@ -273,7 +273,7 @@ MAX(t0)+1
20010101101011
SHOW COLUMNS FROM t2;
Field Type Null Key Default Extra
MAX(t0)+1 bigint(21) YES NULL
MAX(t0)+1 bigint(16) YES NULL
DROP TABLE t2,t1;
CREATE TABLE t1 (t0 DATETIME);
INSERT INTO t1 VALUES ('2001-01-01 10:10:10');
......@@ -286,7 +286,7 @@ MAX(t0)+1.1
20010101101011.1
SHOW COLUMNS FROM t2;
Field Type Null Key Default Extra
MAX(t0)+1.1 decimal(21,1) YES NULL
MAX(t0)+1.1 decimal(16,1) YES NULL
DROP TABLE t2,t1;
CREATE TABLE t1 (t0 DATETIME);
INSERT INTO t1 VALUES ('2001-01-01 10:10:10');
......@@ -312,7 +312,7 @@ MAX(t1)+1
20010101101011.0
SHOW COLUMNS FROM t2;
Field Type Null Key Default Extra
MAX(t1)+1 decimal(22,1) YES NULL
MAX(t1)+1 decimal(16,1) YES NULL
DROP TABLE t2,t1;
#
# MDEV-4858 Wrong results for a huge unsigned value inserted into a TIME column
......
......@@ -145,18 +145,18 @@ show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` time(4) DEFAULT NULL,
`a+0` decimal(16,4) DEFAULT NULL,
`a-1` decimal(16,4) DEFAULT NULL,
`a*1` decimal(16,4) DEFAULT NULL,
`a/2` decimal(19,8) DEFAULT NULL
`a+0` decimal(12,4) DEFAULT NULL,
`a-1` decimal(12,4) DEFAULT NULL,
`a*1` decimal(12,4) DEFAULT NULL,
`a/2` decimal(15,8) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
`max(a)` time(4) DEFAULT NULL,
`min(a)` time(4) DEFAULT NULL,
`sum(a)` decimal(37,4) DEFAULT NULL,
`avg(a)` decimal(19,8) DEFAULT NULL
`sum(a)` decimal(33,4) DEFAULT NULL,
`avg(a)` decimal(15,8) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1, t2, t3;
create table t1 (f0_time time(0), f1_time time(1), f2_time time(2), f3_time time(3), f4_time time(4), f5_time time(5), f6_time time(6));
......
......@@ -131,18 +131,18 @@ show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` timestamp(4) NOT NULL DEFAULT current_timestamp(4) ON UPDATE current_timestamp(4),
`a+0` decimal(25,4) NOT NULL,
`a-1` decimal(25,4) NOT NULL,
`a*1` decimal(25,4) NOT NULL,
`a/2` decimal(28,8) DEFAULT NULL
`a+0` decimal(19,4) NOT NULL,
`a-1` decimal(19,4) NOT NULL,
`a*1` decimal(19,4) NOT NULL,
`a/2` decimal(22,8) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
`max(a)` timestamp(4) NULL DEFAULT NULL,
`min(a)` timestamp(4) NULL DEFAULT NULL,
`sum(a)` decimal(46,4) DEFAULT NULL,
`avg(a)` decimal(28,8) DEFAULT NULL
`sum(a)` decimal(40,4) DEFAULT NULL,
`avg(a)` decimal(22,8) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1, t2, t3;
create table t1 (f0_timestamp timestamp(0), f1_timestamp timestamp(1), f2_timestamp timestamp(2), f3_timestamp timestamp(3), f4_timestamp timestamp(4), f5_timestamp timestamp(5), f6_timestamp timestamp(6));
......
......@@ -541,28 +541,6 @@ Item::Item(THD *thd, Item *item):
}
uint Item::decimal_precision() const
{
Item_result restype= result_type();
if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT))
{
uint prec=
my_decimal_length_to_precision(max_char_length(), decimals,
unsigned_flag);
return MY_MIN(prec, DECIMAL_MAX_PRECISION);
}
uint res= max_char_length();
/*
Return at least one decimal digit, even if Item::max_char_length()
returned 0. This is important to avoid attempts to create fields of types
INT(0) or DECIMAL(0,0) when converting NULL or empty strings to INT/DECIMAL:
CREATE TABLE t1 AS SELECT CONVERT(NULL,SIGNED) AS a;
*/
return res ? MY_MIN(res, DECIMAL_MAX_PRECISION) : 1;
}
void Item::print_parenthesised(String *str, enum_query_type query_type,
enum precedence parent_prec)
{
......
......@@ -1143,7 +1143,10 @@ class Item: public Value_source,
inline uint float_length(uint decimals_par) const
{ return decimals < FLOATING_POINT_DECIMALS ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;}
/* Returns total number of decimal digits */
virtual uint decimal_precision() const;
virtual uint decimal_precision() const
{
return type_handler()->Item_decimal_precision(this);
}
/* Returns the number of integer part digits only */
inline int decimal_int_part() const
{ return my_decimal_int_part(decimal_precision(), decimals); }
......
......@@ -3953,6 +3953,62 @@ uint Type_handler_temporal_result::
/***************************************************************************/
uint Type_handler_string_result::Item_decimal_precision(const Item *item) const
{
uint res= item->max_char_length();
/*
Return at least one decimal digit, even if Item::max_char_length()
returned 0. This is important to avoid attempts to create fields of types
INT(0) or DECIMAL(0,0) when converting NULL or empty strings to INT/DECIMAL:
CREATE TABLE t1 AS SELECT CONVERT(NULL,SIGNED) AS a;
*/
return res ? MY_MIN(res, DECIMAL_MAX_PRECISION) : 1;
}
uint Type_handler_real_result::Item_decimal_precision(const Item *item) const
{
uint res= item->max_char_length();
return res ? MY_MIN(res, DECIMAL_MAX_PRECISION) : 1;
}
uint Type_handler_decimal_result::Item_decimal_precision(const Item *item) const
{
uint prec= my_decimal_length_to_precision(item->max_char_length(),
item->decimals,
item->unsigned_flag);
return MY_MIN(prec, DECIMAL_MAX_PRECISION);
}
uint Type_handler_int_result::Item_decimal_precision(const Item *item) const
{
uint prec= my_decimal_length_to_precision(item->max_char_length(),
item->decimals,
item->unsigned_flag);
return MY_MIN(prec, DECIMAL_MAX_PRECISION);
}
uint Type_handler_time_common::Item_decimal_precision(const Item *item) const
{
return 7 + MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
}
uint Type_handler_date_common::Item_decimal_precision(const Item *item) const
{
return 8;
}
uint Type_handler_datetime_common::Item_decimal_precision(const Item *item) const
{
return 14 + MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
}
uint Type_handler_timestamp_common::Item_decimal_precision(const Item *item) const
{
return 14 + MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
}
/***************************************************************************/
bool Type_handler_real_result::
subquery_type_allows_materialization(const Item *inner,
const Item *outer) const
......
......@@ -639,6 +639,7 @@ class Type_handler
virtual uint Item_time_precision(Item *item) const;
virtual uint Item_datetime_precision(Item *item) const;
virtual uint Item_decimal_scale(const Item *item) const;
virtual uint Item_decimal_precision(const Item *item) const= 0;
/*
Returns how many digits a divisor adds into a division result.
See Item::divisor_precision_increment() in item.h for more comments.
......@@ -935,6 +936,11 @@ class Type_handler_row: public Type_handler
DBUG_ASSERT(0);
return 0;
}
uint Item_decimal_precision(const Item *item) const
{
DBUG_ASSERT(0);
return DECIMAL_MAX_PRECISION;
}
bool Item_save_in_value(Item *item, st_value *value) const;
bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
{
......@@ -1156,6 +1162,7 @@ class Type_handler_real_result: public Type_handler_numeric
void sortlength(THD *thd,
const Type_std_attributes *item,
SORT_FIELD_ATTR *attr) const;
uint Item_decimal_precision(const Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
......@@ -1217,6 +1224,7 @@ class Type_handler_decimal_result: public Type_handler_numeric
const Type_std_attributes *item,
SORT_FIELD_ATTR *attr) const;
uint32 max_display_length(const Item *item) const;
uint Item_decimal_precision(const Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
{
......@@ -1278,6 +1286,7 @@ class Type_handler_int_result: public Type_handler_numeric
void sortlength(THD *thd,
const Type_std_attributes *item,
SORT_FIELD_ATTR *attr) const;
uint Item_decimal_precision(const Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
......@@ -1408,6 +1417,7 @@ class Type_handler_string_result: public Type_handler
{
return Item_temporal_precision(item, false);
}
uint Item_decimal_precision(const Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
{
......@@ -1703,6 +1713,7 @@ class Type_handler_time_common: public Type_handler_temporal_result
{
return Item_decimal_scale_with_seconds(item);
}
uint Item_decimal_precision(const Item *item) const;
uint Item_divisor_precision_increment(const Item *item) const
{
return Item_divisor_precision_increment_with_seconds(item);
......@@ -1780,6 +1791,7 @@ class Type_handler_date_common: public Type_handler_temporal_with_date
{
return MYSQL_TIMESTAMP_DATE;
}
uint Item_decimal_precision(const Item *item) const;
String *print_item_value(THD *thd, Item *item, String *str) const;
bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item **items, uint nitems) const;
......@@ -1828,6 +1840,7 @@ class Type_handler_datetime_common: public Type_handler_temporal_with_date
{
return Item_decimal_scale_with_seconds(item);
}
uint Item_decimal_precision(const Item *item) const;
uint Item_divisor_precision_increment(const Item *item) const
{
return Item_divisor_precision_increment_with_seconds(item);
......@@ -1889,6 +1902,7 @@ class Type_handler_timestamp_common: public Type_handler_temporal_with_date
{
return Item_decimal_scale_with_seconds(item);
}
uint Item_decimal_precision(const Item *item) const;
uint Item_divisor_precision_increment(const Item *item) const
{
return Item_divisor_precision_increment_with_seconds(item);
......
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