diff options
author | Alexander Barkov <bar@mariadb.org> | 2017-05-23 12:45:47 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2017-05-23 12:45:47 +0400 |
commit | d9304914bed2d6d45dbc9f43aa1e2f7ea3bbeb13 (patch) | |
tree | 75dd4ffb8bd8095ca7c2b666f2e0939e866ab623 | |
parent | 9b79888df82259743284501af5b156a18edc427f (diff) | |
download | mariadb-git-d9304914bed2d6d45dbc9f43aa1e2f7ea3bbeb13.tar.gz |
Fixing a few problems with data type and metadata for INT result functions (MDEV-12852, MDEV-12853, MDEV-12869)
This is a joint patch for:
MDEV-12852 Out-of-range errors when CAST(1-2 AS UNSIGNED
MDEV-12853 Out-of-range errors when CAST('-1' AS UNSIGNED
MDEV-12869 Wrong metadata for integer additive and multiplicative operators
1. Fixing all Item_func_numhybrid descendants to set the precise
data type handler (type_handler_long or type_handler_longlong)
at fix_fields() time. This fixes MDEV-12869.
2. Fixing Item_func_unsigned_typecast to set the precise data type handler
at fix_fields() time. This fixes MDEV-12852 and MDEV-12853.
This is done by:
- fixing Type_handler::Item_func_unsigned_fix_length_and_dec()
and Type_handler_string_result::Item_func_unsigned_fix_length_and_dec()
to properly detect situations when a negative epxression is converted
to UNSIGNED. In this case, length of the result is now always set to
MAX_BIGINT_WIDTH without trying to use args[0]->max_length, as very
short arguments can produce very long result in such conversion:
CAST(-1 AS UNSIGNED) -> 18446744073709551614
- adding a new virtual method "longlong Item::val_int_max() const",
to preserve the old behavior for expressions like this:
CAST(1 AS UNSIGNED)
to stay under the INT data type (instead of BIGINT) for small
positive integer literals. Using Item::unsigned_flag would not help,
because Item_int does not set unsigned_flag to "true" for positive
numbers.
3. Adding helper methods:
* Item::type_handler_long_or_longlong()
* Type_handler::type_handler_long_or_longlong()
and reusing them in a few places, to reduce code duplication.
4. Making reorganation in create_tmp_field() and
create_field_for_create_select() for Item_hybrid_func and descendants,
to reduce duplicate code. They all now have a similar behavior in
respect of creating fields. Only Item_func_user_var descendants have
a different behavior. So moving the default behvior to Item_hybrid_func,
and overriding behavior on Item_func_user_var level.
-rw-r--r-- | mysql-test/r/cast.result | 40 | ||||
-rw-r--r-- | mysql-test/r/create.result | 4 | ||||
-rw-r--r-- | mysql-test/r/metadata.result | 204 | ||||
-rw-r--r-- | mysql-test/t/cast.test | 26 | ||||
-rw-r--r-- | mysql-test/t/metadata.test | 112 | ||||
-rw-r--r-- | sql/item.h | 17 | ||||
-rw-r--r-- | sql/item_func.cc | 8 | ||||
-rw-r--r-- | sql/item_func.h | 45 | ||||
-rw-r--r-- | sql/item_timefunc.h | 7 | ||||
-rw-r--r-- | sql/sql_type.cc | 26 | ||||
-rw-r--r-- | sql/sql_type.h | 1 |
11 files changed, 451 insertions, 39 deletions
diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index 69979854d8e..3c9cbb18bcb 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -762,7 +762,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `CONCAT(CAST(REPEAT('9', 1000) AS SIGNED))` varchar(21) NOT NULL, - `CONCAT(CAST(REPEAT('9', 1000) AS UNSIGNED))` varchar(21) NOT NULL + `CONCAT(CAST(REPEAT('9', 1000) AS UNSIGNED))` varchar(20) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; # End of test for Bug#13581962, Bug#14096619 @@ -1130,3 +1130,41 @@ c LENGTH(c) DROP PROCEDURE p1; SET sql_mode=DEFAULT; +# +# MDEV-12852 Out-of-range errors when CAST(1-2 AS UNSIGNED +# +SET sql_mode=STRICT_ALL_TABLES; +CREATE TABLE t1 AS SELECT +CAST(-1 AS UNSIGNED), +CAST(1-2 AS UNSIGNED); +Warnings: +Note 1105 Cast to unsigned converted negative integer to it's positive complement +Note 1105 Cast to unsigned converted negative integer to it's positive complement +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `CAST(-1 AS UNSIGNED)` bigint(20) unsigned NOT NULL, + `CAST(1-2 AS UNSIGNED)` bigint(20) unsigned NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t1; +CAST(-1 AS UNSIGNED) CAST(1-2 AS UNSIGNED) +18446744073709551615 18446744073709551615 +DROP TABLE t1; +SET sql_mode=DEFAULT; +# +# MDEV-12853 Out-of-range errors when CAST('-1' AS UNSIGNED +# +SET sql_mode=STRICT_ALL_TABLES; +CREATE TABLE t1 AS SELECT CAST('-1' AS UNSIGNED); +Warnings: +Note 1105 Cast to unsigned converted negative integer to it's positive complement +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `CAST('-1' AS UNSIGNED)` bigint(20) unsigned NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t1; +CAST('-1' AS UNSIGNED) +18446744073709551615 +DROP TABLE t1; +SET sql_mode=DEFAULT; diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 1a3289b2618..798faaa1198 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -482,8 +482,8 @@ from t1; explain t2; Field Type Null Key Default Extra a int(11) YES NULL -b bigint(11) NO NULL -c bigint(10) unsigned NO NULL +b int(11) NO NULL +c int(10) unsigned NO NULL d date YES NULL e varchar(1) YES NULL f datetime YES NULL diff --git a/mysql-test/r/metadata.result b/mysql-test/r/metadata.result index 7e57fa74663..b4450e6925d 100644 --- a/mysql-test/r/metadata.result +++ b/mysql-test/r/metadata.result @@ -568,3 +568,207 @@ def test t1 t1 @:=1e0 @:=1e0 5 3 1 N 36865 31 63 @:=1e0 1 DROP TABLE t1; +# +# MDEV-12869 Wrong metadata for integer additive and multiplicative operators +# +SELECT +1+1, +11+1, +111+1, +1111+1, +11111+1, +111111+1, +1111111+1, +11111111+1, +111111111+1 LIMIT 0; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def 1+1 3 3 0 N 32897 0 63 +def 11+1 3 4 0 N 32897 0 63 +def 111+1 3 5 0 N 32897 0 63 +def 1111+1 3 6 0 N 32897 0 63 +def 11111+1 3 7 0 N 32897 0 63 +def 111111+1 3 8 0 N 32897 0 63 +def 1111111+1 3 9 0 N 32897 0 63 +def 11111111+1 8 10 0 N 32897 0 63 +def 111111111+1 8 11 0 N 32897 0 63 +1+1 11+1 111+1 1111+1 11111+1 111111+1 1111111+1 11111111+1 111111111+1 +SELECT +1-1, +11-1, +111-1, +1111-1, +11111-1, +111111-1, +1111111-1, +11111111-1, +111111111-1 LIMIT 0; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def 1-1 3 3 0 N 32897 0 63 +def 11-1 3 4 0 N 32897 0 63 +def 111-1 3 5 0 N 32897 0 63 +def 1111-1 3 6 0 N 32897 0 63 +def 11111-1 3 7 0 N 32897 0 63 +def 111111-1 3 8 0 N 32897 0 63 +def 1111111-1 3 9 0 N 32897 0 63 +def 11111111-1 8 10 0 N 32897 0 63 +def 111111111-1 8 11 0 N 32897 0 63 +1-1 11-1 111-1 1111-1 11111-1 111111-1 1111111-1 11111111-1 111111111-1 +SELECT +1*1, +11*1, +111*1, +1111*1, +11111*1, +111111*1, +1111111*1, +11111111*1, +111111111*1 LIMIT 0; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def 1*1 3 3 0 N 32897 0 63 +def 11*1 3 4 0 N 32897 0 63 +def 111*1 3 5 0 N 32897 0 63 +def 1111*1 3 6 0 N 32897 0 63 +def 11111*1 3 7 0 N 32897 0 63 +def 111111*1 3 8 0 N 32897 0 63 +def 1111111*1 3 9 0 N 32897 0 63 +def 11111111*1 8 10 0 N 32897 0 63 +def 111111111*1 8 11 0 N 32897 0 63 +1*1 11*1 111*1 1111*1 11111*1 111111*1 1111111*1 11111111*1 111111111*1 +SELECT +1 MOD 1, +11 MOD 1, +111 MOD 1, +1111 MOD 1, +11111 MOD 1, +111111 MOD 1, +1111111 MOD 1, +11111111 MOD 1, +111111111 MOD 1, +1111111111 MOD 1, +11111111111 MOD 1 LIMIT 0; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def 1 MOD 1 3 1 0 Y 32896 0 63 +def 11 MOD 1 3 2 0 Y 32896 0 63 +def 111 MOD 1 3 3 0 Y 32896 0 63 +def 1111 MOD 1 3 4 0 Y 32896 0 63 +def 11111 MOD 1 3 5 0 Y 32896 0 63 +def 111111 MOD 1 3 6 0 Y 32896 0 63 +def 1111111 MOD 1 3 7 0 Y 32896 0 63 +def 11111111 MOD 1 3 8 0 Y 32896 0 63 +def 111111111 MOD 1 3 9 0 Y 32896 0 63 +def 1111111111 MOD 1 8 10 0 Y 32896 0 63 +def 11111111111 MOD 1 8 11 0 Y 32896 0 63 +1 MOD 1 11 MOD 1 111 MOD 1 1111 MOD 1 11111 MOD 1 111111 MOD 1 1111111 MOD 1 11111111 MOD 1 111111111 MOD 1 1111111111 MOD 1 11111111111 MOD 1 +SELECT +-(1), +-(11), +-(111), +-(1111), +-(11111), +-(111111), +-(1111111), +-(11111111), +-(111111111) LIMIT 0; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def -(1) 3 2 0 N 32897 0 63 +def -(11) 3 3 0 N 32897 0 63 +def -(111) 3 4 0 N 32897 0 63 +def -(1111) 3 5 0 N 32897 0 63 +def -(11111) 3 6 0 N 32897 0 63 +def -(111111) 3 7 0 N 32897 0 63 +def -(1111111) 3 8 0 N 32897 0 63 +def -(11111111) 3 9 0 N 32897 0 63 +def -(111111111) 8 10 0 N 32897 0 63 +-(1) -(11) -(111) -(1111) -(11111) -(111111) -(1111111) -(11111111) -(111111111) +SELECT +ABS(1), +ABS(11), +ABS(111), +ABS(1111), +ABS(11111), +ABS(111111), +ABS(1111111), +ABS(11111111), +ABS(111111111), +ABS(1111111111) LIMIT 0; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def ABS(1) 3 1 0 N 32897 0 63 +def ABS(11) 3 2 0 N 32897 0 63 +def ABS(111) 3 3 0 N 32897 0 63 +def ABS(1111) 3 4 0 N 32897 0 63 +def ABS(11111) 3 5 0 N 32897 0 63 +def ABS(111111) 3 6 0 N 32897 0 63 +def ABS(1111111) 3 7 0 N 32897 0 63 +def ABS(11111111) 3 8 0 N 32897 0 63 +def ABS(111111111) 3 9 0 N 32897 0 63 +def ABS(1111111111) 8 10 0 N 32897 0 63 +ABS(1) ABS(11) ABS(111) ABS(1111) ABS(11111) ABS(111111) ABS(1111111) ABS(11111111) ABS(111111111) ABS(1111111111) +SELECT +CEILING(1), +CEILING(11), +CEILING(111), +CEILING(1111), +CEILING(11111), +CEILING(111111), +CEILING(1111111), +CEILING(11111111), +CEILING(111111111), +CEILING(1111111111) LIMIT 0; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def CEILING(1) 3 3 0 N 32897 0 63 +def CEILING(11) 3 4 0 N 32897 0 63 +def CEILING(111) 3 5 0 N 32897 0 63 +def CEILING(1111) 3 6 0 N 32897 0 63 +def CEILING(11111) 3 7 0 N 32897 0 63 +def CEILING(111111) 3 8 0 N 32897 0 63 +def CEILING(1111111) 3 9 0 N 32897 0 63 +def CEILING(11111111) 8 10 0 N 32897 0 63 +def CEILING(111111111) 8 11 0 N 32897 0 63 +def CEILING(1111111111) 8 12 0 N 32897 0 63 +CEILING(1) CEILING(11) CEILING(111) CEILING(1111) CEILING(11111) CEILING(111111) CEILING(1111111) CEILING(11111111) CEILING(111111111) CEILING(1111111111) +SELECT +FLOOR(1), +FLOOR(11), +FLOOR(111), +FLOOR(1111), +FLOOR(11111), +FLOOR(111111), +FLOOR(1111111), +FLOOR(11111111), +FLOOR(111111111), +FLOOR(1111111111) LIMIT 0; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def FLOOR(1) 3 3 0 N 32897 0 63 +def FLOOR(11) 3 4 0 N 32897 0 63 +def FLOOR(111) 3 5 0 N 32897 0 63 +def FLOOR(1111) 3 6 0 N 32897 0 63 +def FLOOR(11111) 3 7 0 N 32897 0 63 +def FLOOR(111111) 3 8 0 N 32897 0 63 +def FLOOR(1111111) 3 9 0 N 32897 0 63 +def FLOOR(11111111) 8 10 0 N 32897 0 63 +def FLOOR(111111111) 8 11 0 N 32897 0 63 +def FLOOR(1111111111) 8 12 0 N 32897 0 63 +FLOOR(1) FLOOR(11) FLOOR(111) FLOOR(1111) FLOOR(11111) FLOOR(111111) FLOOR(1111111) FLOOR(11111111) FLOOR(111111111) FLOOR(1111111111) +SELECT +ROUND(1), +ROUND(11), +ROUND(111), +ROUND(1111), +ROUND(11111), +ROUND(111111), +ROUND(1111111), +ROUND(11111111), +ROUND(111111111), +ROUND(1111111111) LIMIT 0; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def ROUND(1) 3 1 0 N 32897 0 63 +def ROUND(11) 3 2 0 N 32897 0 63 +def ROUND(111) 3 3 0 N 32897 0 63 +def ROUND(1111) 3 4 0 N 32897 0 63 +def ROUND(11111) 3 5 0 N 32897 0 63 +def ROUND(111111) 3 6 0 N 32897 0 63 +def ROUND(1111111) 3 7 0 N 32897 0 63 +def ROUND(11111111) 3 8 0 N 32897 0 63 +def ROUND(111111111) 3 9 0 N 32897 0 63 +def ROUND(1111111111) 8 10 0 N 32897 0 63 +ROUND(1) ROUND(11) ROUND(111) ROUND(1111) ROUND(11111) ROUND(111111) ROUND(1111111) ROUND(11111111) ROUND(111111111) ROUND(1111111111) diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test index e56433b3d54..17e8be839a8 100644 --- a/mysql-test/t/cast.test +++ b/mysql-test/t/cast.test @@ -561,3 +561,29 @@ CALL p1('8FFFFFFFFFFFFFFF'); DROP PROCEDURE p1; SET sql_mode=DEFAULT; + + +--echo # +--echo # MDEV-12852 Out-of-range errors when CAST(1-2 AS UNSIGNED +--echo # + +SET sql_mode=STRICT_ALL_TABLES; +CREATE TABLE t1 AS SELECT + CAST(-1 AS UNSIGNED), + CAST(1-2 AS UNSIGNED); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; +SET sql_mode=DEFAULT; + + +--echo # +--echo # MDEV-12853 Out-of-range errors when CAST('-1' AS UNSIGNED +--echo # + +SET sql_mode=STRICT_ALL_TABLES; +CREATE TABLE t1 AS SELECT CAST('-1' AS UNSIGNED); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; +SET sql_mode=DEFAULT; diff --git a/mysql-test/t/metadata.test b/mysql-test/t/metadata.test index 073f617dc16..d5d95cf7e8c 100644 --- a/mysql-test/t/metadata.test +++ b/mysql-test/t/metadata.test @@ -353,3 +353,115 @@ CREATE TABLE t1 AS SELECT @:=1e0; SELECT * FROM t1; DROP TABLE t1; --disable_metadata + +--echo # +--echo # MDEV-12869 Wrong metadata for integer additive and multiplicative operators +--echo # + +--enable_metadata +SELECT + 1+1, + 11+1, + 111+1, + 1111+1, + 11111+1, + 111111+1, + 1111111+1, + 11111111+1, + 111111111+1 LIMIT 0; + +SELECT + 1-1, + 11-1, + 111-1, + 1111-1, + 11111-1, + 111111-1, + 1111111-1, + 11111111-1, + 111111111-1 LIMIT 0; + +SELECT + 1*1, + 11*1, + 111*1, + 1111*1, + 11111*1, + 111111*1, + 1111111*1, + 11111111*1, + 111111111*1 LIMIT 0; + +SELECT + 1 MOD 1, + 11 MOD 1, + 111 MOD 1, + 1111 MOD 1, + 11111 MOD 1, + 111111 MOD 1, + 1111111 MOD 1, + 11111111 MOD 1, + 111111111 MOD 1, + 1111111111 MOD 1, + 11111111111 MOD 1 LIMIT 0; + +SELECT + -(1), + -(11), + -(111), + -(1111), + -(11111), + -(111111), + -(1111111), + -(11111111), + -(111111111) LIMIT 0; + +SELECT + ABS(1), + ABS(11), + ABS(111), + ABS(1111), + ABS(11111), + ABS(111111), + ABS(1111111), + ABS(11111111), + ABS(111111111), + ABS(1111111111) LIMIT 0; + +SELECT + CEILING(1), + CEILING(11), + CEILING(111), + CEILING(1111), + CEILING(11111), + CEILING(111111), + CEILING(1111111), + CEILING(11111111), + CEILING(111111111), + CEILING(1111111111) LIMIT 0; + +SELECT + FLOOR(1), + FLOOR(11), + FLOOR(111), + FLOOR(1111), + FLOOR(11111), + FLOOR(111111), + FLOOR(1111111), + FLOOR(11111111), + FLOOR(111111111), + FLOOR(1111111111) LIMIT 0; + +SELECT + ROUND(1), + ROUND(11), + ROUND(111), + ROUND(1111), + ROUND(11111), + ROUND(111111), + ROUND(1111111), + ROUND(11111111), + ROUND(111111111), + ROUND(1111111111) LIMIT 0; + +--disable_metadata diff --git a/sql/item.h b/sql/item.h index dd72d232cce..2700dfc1fe9 100644 --- a/sql/item.h +++ b/sql/item.h @@ -627,6 +627,11 @@ protected: return (null_value= item->get_date_with_conversion(ltime, fuzzydate)); } + const Type_handler *type_handler_long_or_longlong() const + { + return Type_handler::type_handler_long_or_longlong(max_char_length()); + } + public: /* Cache val_str() into the own buffer, e.g. to evaluate constant @@ -1210,6 +1215,10 @@ public: return const_item() ? type_handler()->Item_datetime_precision(this) : MY_MIN(decimals, TIME_SECOND_PART_DIGITS); } + virtual longlong val_int_min() const + { + return LONGLONG_MIN; + } /* Returns true if this is constant (during query execution, i.e. its value will not change until next fix_fields) and its value is known. @@ -3234,17 +3243,13 @@ public: Item_int(THD *thd, const char *str_arg, uint length=64); enum Type type() const { return INT_ITEM; } const Type_handler *type_handler() const - { - // The same condition is repeated in Item::create_tmp_field() - if (max_length > MY_INT32_NUM_DECIMAL_DIGITS - 2) - return &type_handler_longlong; - return &type_handler_long; - } + { return type_handler_long_or_longlong(); } Field *create_tmp_field(bool group, TABLE *table) { return tmp_table_field_from_field_type(table); } Field *create_field_for_create_select(TABLE *table) { return tmp_table_field_from_field_type(table); } longlong val_int() { DBUG_ASSERT(fixed == 1); return value; } + longlong val_int_min() const { DBUG_ASSERT(fixed == 1); return value; } double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; } my_decimal *val_decimal(my_decimal *); String *val_str(String*); diff --git a/sql/item_func.cc b/sql/item_func.cc index 95015d4e074..7b0d5532cbc 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1740,8 +1740,8 @@ my_decimal *Item_func_neg::decimal_op(my_decimal *decimal_value) void Item_func_neg::fix_length_and_dec_int() { - set_handler(&type_handler_longlong); max_length= args[0]->max_length + 1; + set_handler(type_handler_long_or_longlong()); /* If this is in integer context keep the context as integer if possible @@ -1834,9 +1834,9 @@ my_decimal *Item_func_abs::decimal_op(my_decimal *decimal_value) void Item_func_abs::fix_length_and_dec_int() { - set_handler(&type_handler_longlong); max_length= args[0]->max_length; unsigned_flag= args[0]->unsigned_flag; + set_handler(type_handler_long_or_longlong()); } @@ -2117,7 +2117,7 @@ void Item_func_int_val::fix_length_and_dec_int_or_decimal() else { unsigned_flag= args[0]->unsigned_flag; - set_handler(&type_handler_longlong); + set_handler(type_handler_long_or_longlong()); } } @@ -2308,9 +2308,9 @@ void Item_func_round::fix_arg_int() int length_can_increase= MY_TEST(!truncate && val1_is_negative); max_length= args[0]->max_length + length_can_increase; // Here we can keep INT_RESULT - set_handler(&type_handler_longlong); unsigned_flag= args[0]->unsigned_flag; decimals= 0; + set_handler(type_handler_long_or_longlong()); } else fix_length_and_dec_decimal(decimals_to_set); diff --git a/sql/item_func.h b/sql/item_func.h index 39a12e004e9..9055a9e5e98 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -396,6 +396,10 @@ public: :Item_func(thd, item), Type_handler_hybrid_field_type(item) { } const Type_handler *type_handler() const { return Type_handler_hybrid_field_type::type_handler(); } + Field *create_tmp_field(bool group, TABLE *table) + { return tmp_table_field_from_field_type(table); } + Field *create_field_for_create_select(TABLE *table) + { return tmp_table_field_from_field_type(table); } Field::geometry_type get_geometry_type() const { return Type_geometry_attributes::get_geometry_type(); }; void set_geometry_type(uint type) @@ -624,10 +628,6 @@ public: Item_func_case_expression(THD *thd, List<Item> &list): Item_func_hybrid_field_type(thd, list) { } - Field *create_tmp_field(bool group, TABLE *table) - { return tmp_table_field_from_field_type(table); } - Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table); } }; @@ -700,13 +700,14 @@ class Item_num_op :public Item_func_numhybrid unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag; result_precision(); decimals= 0; + set_handler(type_handler_long_or_longlong()); } void fix_length_and_dec_temporal() { set_handler(&type_handler_newdecimal); fix_length_and_dec_decimal(); if (decimals == 0) - set_handler(&type_handler_longlong); + set_handler(type_handler_long_or_longlong()); } bool need_parentheses_in_default() { return true; } }; @@ -839,15 +840,8 @@ public: unsigned_flag= 0; } const char *func_name() const { return "cast_as_signed"; } - const Type_handler *type_handler() const { return &type_handler_longlong; } - Field *create_tmp_field(bool group, TABLE *table) - { - return create_tmp_field_int(table, - MY_INT32_NUM_DECIMAL_DIGITS - 2 + - unsigned_flag); - } - Field *create_field_for_create_select(TABLE *table) - { return Item_func_signed::create_tmp_field(false, table); } + const Type_handler *type_handler() const + { return type_handler_long_or_longlong(); } longlong val_int() { longlong value= args[0]->val_int_signed_typecast(); @@ -899,6 +893,12 @@ public: unsigned_flag= 1; } const char *func_name() const { return "cast_as_unsigned"; } + const Type_handler *type_handler() const + { + if (max_char_length() <= MY_INT32_NUM_DECIMAL_DIGITS - 1) + return &type_handler_long; + return &type_handler_longlong; + } longlong val_int() { longlong value= args[0]->val_int_unsigned_typecast(); @@ -909,6 +909,7 @@ public: { args[0]->type_handler()->Item_func_unsigned_fix_length_and_dec(this); } + uint decimal_precision() const { return max_length; } virtual void print(String *str, enum_query_type query_type); Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_func_unsigned>(thd, mem_root, this); } @@ -1072,12 +1073,7 @@ public: const char *func_name() const { return "DIV"; } enum precedence precedence() const { return MUL_PRECEDENCE; } const Type_handler *type_handler() const - { - // The same condition is repeated in Item::create_tmp_field() - if (max_length > MY_INT32_NUM_DECIMAL_DIGITS - 2) - return &type_handler_longlong; - return &type_handler_long; - } + { return type_handler_long_or_longlong(); } void fix_length_and_dec(); void print(String *str, enum_query_type query_type) { @@ -1118,6 +1114,7 @@ public: max_length= MY_MAX(args[0]->max_length, args[1]->max_length); decimals= 0; unsigned_flag= args[0]->unsigned_flag; + set_handler(type_handler_long_or_longlong()); } bool check_partition_func_processor(void *int_arg) {return FALSE;} bool check_vcol_func_processor(void *arg) { return FALSE;} @@ -1469,10 +1466,6 @@ public: Item_func_min_max(THD *thd, List<Item> &list, int cmp_sign_arg): Item_hybrid_func(thd, list), cmp_sign(cmp_sign_arg) {} - Field *create_tmp_field(bool group, TABLE *table) - { return tmp_table_field_from_field_type(table); } - Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table); } String *val_str_native(String *str); double val_real_native(); longlong val_int_native(); @@ -2244,6 +2237,10 @@ public: Item_func_user_var(THD *thd, Item_func_user_var *item) :Item_hybrid_func(thd, item), m_var_entry(item->m_var_entry), name(item->name) { } + Field *create_tmp_field(bool group, TABLE *table) + { return Item::create_tmp_field(group, table); } + Field *create_field_for_create_select(TABLE *table) + { return Item::create_field_for_create_select(table); } bool check_vcol_func_processor(void *arg); }; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 55193bce207..2e7142336a4 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -155,7 +155,7 @@ public: return str; } const char *func_name() const { return "month"; } - const Type_handler *type_handler() const { return &type_handler_longlong; } + const Type_handler *type_handler() const { return &type_handler_long; } void fix_length_and_dec() { decimals= 0; @@ -449,7 +449,10 @@ public: decimals= dec; max_length=17 + (decimals ? decimals + 1 : 0); maybe_null= true; - set_handler_by_result_type(decimals ? DECIMAL_RESULT : INT_RESULT); + if (decimals) + set_handler(&type_handler_newdecimal); + else + set_handler(type_handler_long_or_longlong()); } double real_op() { DBUG_ASSERT(0); return 0; } String *str_op(String *str) { DBUG_ASSERT(0); return 0; } diff --git a/sql/sql_type.cc b/sql/sql_type.cc index d9c75fea9a7..504fab21845 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -528,6 +528,14 @@ Type_handler_hybrid_field_type::aggregate_for_result(const Type_handler *other) } +const Type_handler * +Type_handler::type_handler_long_or_longlong(uint max_char_length) +{ + if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS - 2) + return &type_handler_long; + return &type_handler_longlong; +} + /* This method is called for CASE (and its abbreviations) and LEAST/GREATEST when data type aggregation returned LONGLONG and there were some BIT @@ -4168,6 +4176,16 @@ bool Type_handler:: bool Type_handler:: Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const { + const Item *arg= item->arguments()[0]; + if (!arg->unsigned_flag && arg->val_int_min() < 0) + { + /* + Negative arguments produce long results: + CAST(1-2 AS UNSIGNED) -> 18446744073709551615 + */ + item->max_length= MAX_BIGINT_WIDTH; + return false; + } item->fix_length_and_dec_generic(); return false; } @@ -4184,6 +4202,14 @@ bool Type_handler_string_result:: bool Type_handler_string_result:: Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const { + const Item *arg= item->arguments()[0]; + if (!arg->unsigned_flag && // Not HEX hybrid + arg->max_char_length() > 1) // Can be negative + { + // String arguments can give long results: '-1' -> 18446744073709551614 + item->max_length= MAX_BIGINT_WIDTH; + return false; + } item->fix_length_and_dec_string(); return false; } diff --git a/sql/sql_type.h b/sql/sql_type.h index 374f250f443..aeaec7ff95f 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -564,6 +564,7 @@ public: static const Type_handler *blob_type_handler(uint max_octet_length); static const Type_handler *string_type_handler(uint max_octet_length); static const Type_handler *bit_and_int_mixture_handler(uint max_char_len); + static const Type_handler *type_handler_long_or_longlong(uint max_char_len); /** Return a string type handler for Item If too_big_for_varchar() returns a BLOB variant, according to length. |