From c84bbeda7f42e940553aee5377f64d2452872138 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 22 May 2017 13:44:26 +0400 Subject: [PATCH] MDEV-12858 + MDEV+12859 + MDEV-12862 - a join patch fixing a few data type problems with CREATE..SELECT MDEV-12858 Out-of-range error for CREATE..SELECT unsigned_int_column+1 MDEV-12859 Out-of-range error for CREATE..SELECT @a:=EXTRACT(MINUTE_MICROSECOND FROM..) MDEV-12862 Data type of @a:=1e0 depends on the session character set 1. Moving a part of Item::create_tmp_field() into a new helper method Item::create_tmp_field_int() and reusing it in Item::create_tmp_field() and Item_func_signed::create_tmp_field(). Fixing the code in Item::create_tmp_field_int() to call Type_handler::make_table_field() instead of doing "new Field_long[long]" directly. This change revealed a problem reported in MDEV-12862. 2. Changing the "long vs longlong" cut-off length for - Item_func::create_tmp_field() - Item_sum::create_tmp_field() - Item_func_get_user_var::create_tmp_field() from MY_INT32_NUM_DECIMAL_DIGITS to (MY_INT32_NUM_DECIMAL_DIGITS - 2). This fixes MDEV-12858. After this change, the "convert_int_length" parameter to Item::create_tmp_field() is not needed any more, because (MY_INT32_NUM_DECIMAL_DIGITS - 2) is always passed. So removing the "convert_int_length" parameter. 3. Fixing Item::create_tmp_field() to pass max_char_length() instead of max_length to the constructor of Field_double(). This fixes MDEV-12862. 4. Additionally, fixing - Type_handler_{tiny|short|int24|long|longlong}::make_table_field() - Type_handler_{float|double}::make_table_field() to pass max_char_length() instead of max_length to Field contructors. This is needed by the change (1). 5. Adding new tests, and recording new correct results in the old tests in: - mysql-test/r/type_ranges.result - storage/tokudb/mysql-test/tokudb/r/type_ranges.result --- mysql-test/r/func_math.result | 18 ++++++++++++ mysql-test/r/metadata.result | 19 +++++++++++++ mysql-test/r/type_ranges.result | 2 +- mysql-test/r/user_var.result | 19 +++++++++++++ mysql-test/t/func_math.test | 15 ++++++++++ mysql-test/t/metadata.test | 15 ++++++++++ mysql-test/t/user_var.test | 15 ++++++++++ sql/item.h | 11 ++------ sql/item_func.h | 10 +++---- sql/item_sum.h | 2 +- sql/sql_select.cc | 28 +++++++++---------- sql/sql_type.cc | 19 ++++++++----- .../mysql-test/tokudb/r/type_ranges.result | 2 +- 13 files changed, 136 insertions(+), 39 deletions(-) diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index c681505a676..d86db4ce89f 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -877,3 +877,21 @@ d09 222222222 d10 2222222222 DROP TABLE t1; SET sql_mode=DEFAULT; +# +# MDEV-12858 Out-of-range error for CREATE..SELECT unsigned_int_column+1 +# +SET sql_mode=STRICT_ALL_TABLES; +CREATE OR REPLACE TABLE t1 (a INT UNSIGNED NOT NULL); +INSERT INTO t1 VALUES (0xFFFFFFFF); +CREATE OR REPLACE TABLE t2 AS SELECT a+1 AS a FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` bigint(11) unsigned NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT a, HEX(a) FROM t2; +a HEX(a) +4294967296 100000000 +DROP TABLE t2; +DROP TABLE t1; +SET sql_mode=DEFAULT; diff --git a/mysql-test/r/metadata.result b/mysql-test/r/metadata.result index c378a48ee56..b588a6a9525 100644 --- a/mysql-test/r/metadata.result +++ b/mysql-test/r/metadata.result @@ -549,3 +549,22 @@ def d09 3 9 9 Y 32896 0 63 def d10 8 10 10 Y 32896 0 63 d0l d09 d10 2 222222222 2222222222 +# +# MDEV-12862 Data type of @a:=1e0 depends on the session character set +# +SET NAMES utf8; +CREATE TABLE t1 AS SELECT @:=1e0; +SELECT * FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 @:=1e0 @:=1e0 5 3 1 N 36865 31 63 +@:=1e0 +1 +DROP TABLE t1; +SET NAMES latin1; +CREATE TABLE t1 AS SELECT @:=1e0; +SELECT * FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 @:=1e0 @:=1e0 5 3 1 N 36865 31 63 +@:=1e0 +1 +DROP TABLE t1; diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result index fe7392c758f..784a394d8b5 100644 --- a/mysql-test/r/type_ranges.result +++ b/mysql-test/r/type_ranges.result @@ -272,7 +272,7 @@ drop table t2; create table t2 (primary key (auto)) select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1; show full columns from t2; Field Type Collation Null Key Default Extra Privileges Comment -auto int(11) unsigned NULL NO PRI NULL # +auto bigint(11) unsigned NULL NO PRI NULL # t1 int(1) NULL NO NULL # t2 varchar(1) latin1_swedish_ci NO NULL # t3 varchar(256) latin1_swedish_ci YES NULL # diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index e01d4f1a54b..0dd8b80a568 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -570,3 +570,22 @@ End of 5.5 tests # set @var= repeat('a',20000); 1 +# +# Start of 10.3 tests +# +# +# MDEV-12859 Out-of-range error for CREATE..SELECT @a:=EXTRACT(MINUTE_MICROSECOND FROM.. +# +SET sql_mode=STRICT_ALL_TABLES; +CREATE OR REPLACE TABLE t1 AS +SELECT @a:=EXTRACT(MINUTE_MICROSECOND FROM '2001-01-01 11:22:33.999999') AS c1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` bigint(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 +2233999999 +DROP TABLE t1; +SET sql_mode=DEFAULT; diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index fd000211145..ff8d6bba46d 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -640,3 +640,18 @@ SELECT * FROM t1; --horizontal_results DROP TABLE t1; SET sql_mode=DEFAULT; + + +--echo # +--echo # MDEV-12858 Out-of-range error for CREATE..SELECT unsigned_int_column+1 +--echo # + +SET sql_mode=STRICT_ALL_TABLES; +CREATE OR REPLACE TABLE t1 (a INT UNSIGNED NOT NULL); +INSERT INTO t1 VALUES (0xFFFFFFFF); +CREATE OR REPLACE TABLE t2 AS SELECT a+1 AS a FROM t1; +SHOW CREATE TABLE t2; +SELECT a, HEX(a) FROM t2; +DROP TABLE t2; +DROP TABLE t1; +SET sql_mode=DEFAULT; diff --git a/mysql-test/t/metadata.test b/mysql-test/t/metadata.test index 7c50dadea0b..073f617dc16 100644 --- a/mysql-test/t/metadata.test +++ b/mysql-test/t/metadata.test @@ -338,3 +338,18 @@ SELECT 222222222 DIV 1 AS d09, 2222222222 DIV 1 AS d10; --disable_metadata + + +--echo # +--echo # MDEV-12862 Data type of @a:=1e0 depends on the session character set +--echo # +--enable_metadata +SET NAMES utf8; +CREATE TABLE t1 AS SELECT @:=1e0; +SELECT * FROM t1; +DROP TABLE t1; +SET NAMES latin1; +CREATE TABLE t1 AS SELECT @:=1e0; +SELECT * FROM t1; +DROP TABLE t1; +--disable_metadata diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index 2c889c2cc0c..aae12ae4cbd 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -501,3 +501,18 @@ eval select $tmp < $tmp2; --enable_column_names --enable_query_log +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-12859 Out-of-range error for CREATE..SELECT @a:=EXTRACT(MINUTE_MICROSECOND FROM.. +--echo # + +SET sql_mode=STRICT_ALL_TABLES; +CREATE OR REPLACE TABLE t1 AS +SELECT @a:=EXTRACT(MINUTE_MICROSECOND FROM '2001-01-01 11:22:33.999999') AS c1; +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; +SET sql_mode=DEFAULT; diff --git a/sql/item.h b/sql/item.h index b3ed31d5bb1..dd72d232cce 100644 --- a/sql/item.h +++ b/sql/item.h @@ -582,7 +582,7 @@ protected: return h->make_and_init_table_field(&name, Record_addr(maybe_null), *this, table); } - Field *create_tmp_field(bool group, TABLE *table, uint convert_int_length); + Field *create_tmp_field_int(TABLE *table, uint convert_int_length); void push_note_converted_to_negative_complement(THD *thd); void push_note_converted_to_positive_complement(THD *thd); @@ -1637,14 +1637,7 @@ public: // used in row subselects to get value of elements virtual void bring_value() {} - virtual Field *create_tmp_field(bool group, TABLE *table) - { - /* - Values with MY_INT32_NUM_DECIMAL_DIGITS digits may or may not fit into - Field_long : make them Field_longlong. - */ - return create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS - 2); - } + virtual Field *create_tmp_field(bool group, TABLE *table); virtual Item_field *field_for_view_update() { return 0; } diff --git a/sql/item_func.h b/sql/item_func.h index 8dcf35720a0..39a12e004e9 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -171,7 +171,7 @@ public: Field *create_field_for_create_select(TABLE *table) { return result_type() != STRING_RESULT ? - create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS) : + Item::create_tmp_field(false, table) : tmp_table_field_from_field_type(table); } Item *get_tmp_table_item(THD *thd); @@ -842,9 +842,9 @@ public: const Type_handler *type_handler() const { return &type_handler_longlong; } Field *create_tmp_field(bool group, TABLE *table) { - return Item::create_tmp_field(false, table, - MY_INT32_NUM_DECIMAL_DIGITS - 2 + - unsigned_flag); + 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); } @@ -2352,7 +2352,7 @@ public: type_handler_long_blob.make_and_init_table_field(&(Item::name), Record_addr(maybe_null), *this, table) : - create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS); + create_tmp_field(false, table); } virtual void print(String *str, enum_query_type query_type); /* diff --git a/sql/item_sum.h b/sql/item_sum.h index c1485738b11..14a2fd0c0ec 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -510,7 +510,7 @@ public: Item *get_tmp_table_item(THD *thd); Field *create_tmp_field(bool group, TABLE *table) { - return Item::create_tmp_field(group, table, MY_INT32_NUM_DECIMAL_DIGITS); + return Item::create_tmp_field(group, table); } virtual bool collect_outer_ref_processor(void *param); bool init_sum_func_check(THD *thd); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index febbdf24799..a16ff79827f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15869,7 +15869,17 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field, } -Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length) +Field *Item::create_tmp_field_int(TABLE *table, uint convert_int_length) +{ + const Type_handler *h= &type_handler_long; + if (max_char_length() > convert_int_length) + h= &type_handler_longlong; + return h->make_and_init_table_field(&name, Record_addr(maybe_null), + *this, table); +} + + +Field *Item::create_tmp_field(bool group, TABLE *table) { Field *UNINIT_VAR(new_field); MEM_ROOT *mem_root= table->in_use->mem_root; @@ -15878,23 +15888,11 @@ Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length) case REAL_RESULT: { new_field= new (mem_root) - Field_double(max_length, maybe_null, &name, decimals, TRUE); + Field_double(max_char_length(), maybe_null, &name, decimals, TRUE); break; } case INT_RESULT: - { - /* - Select an integer type with the minimal fit precision. - convert_int_length is sign inclusive, don't consider the sign. - */ - if (max_char_length() > convert_int_length) - new_field= new (mem_root) - Field_longlong(max_char_length(), maybe_null, &name, unsigned_flag); - else - new_field= new (mem_root) - Field_long(max_char_length(), maybe_null, &name, unsigned_flag); - break; - } + return create_tmp_field_int(table, MY_INT32_NUM_DECIMAL_DIGITS - 2); case TIME_RESULT: case DECIMAL_RESULT: case STRING_RESULT: diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 7f560e9ff26..d9c75fea9a7 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -1946,7 +1946,8 @@ Field *Type_handler_tiny::make_table_field(const LEX_CSTRING *name, TABLE *table) const { return new (table->in_use->mem_root) - Field_tiny(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field_tiny(addr.ptr, attr.max_char_length(), + addr.null_ptr, addr.null_bit, Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); } @@ -1958,7 +1959,8 @@ Field *Type_handler_short::make_table_field(const LEX_CSTRING *name, { return new (table->in_use->mem_root) - Field_short(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field_short(addr.ptr, attr.max_char_length(), + addr.null_ptr, addr.null_bit, Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); } @@ -1969,7 +1971,8 @@ Field *Type_handler_int24::make_table_field(const LEX_CSTRING *name, TABLE *table) const { return new (table->in_use->mem_root) - Field_medium(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field_medium(addr.ptr, attr.max_char_length(), + addr.null_ptr, addr.null_bit, Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); } @@ -1981,7 +1984,8 @@ Field *Type_handler_long::make_table_field(const LEX_CSTRING *name, TABLE *table) const { return new (table->in_use->mem_root) - Field_long(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field_long(addr.ptr, attr.max_char_length(), + addr.null_ptr, addr.null_bit, Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); } @@ -1992,7 +1996,7 @@ Field *Type_handler_longlong::make_table_field(const LEX_CSTRING *name, TABLE *table) const { return new (table->in_use->mem_root) - Field_longlong(addr.ptr, attr.max_length, + Field_longlong(addr.ptr, attr.max_char_length(), addr.null_ptr, addr.null_bit, Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); @@ -2005,7 +2009,8 @@ Field *Type_handler_float::make_table_field(const LEX_CSTRING *name, TABLE *table) const { return new (table->in_use->mem_root) - Field_float(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field_float(addr.ptr, attr.max_char_length(), + addr.null_ptr, addr.null_bit, Field::NONE, name, attr.decimals, 0/*zerofill*/, attr.unsigned_flag); } @@ -2017,7 +2022,7 @@ Field *Type_handler_double::make_table_field(const LEX_CSTRING *name, TABLE *table) const { return new (table->in_use->mem_root) - Field_double(addr.ptr, attr.max_length, + Field_double(addr.ptr, attr.max_char_length(), addr.null_ptr, addr.null_bit, Field::NONE, name, attr.decimals, 0/*zerofill*/, attr.unsigned_flag); diff --git a/storage/tokudb/mysql-test/tokudb/r/type_ranges.result b/storage/tokudb/mysql-test/tokudb/r/type_ranges.result index 1c9cd769a14..38252e870df 100644 --- a/storage/tokudb/mysql-test/tokudb/r/type_ranges.result +++ b/storage/tokudb/mysql-test/tokudb/r/type_ranges.result @@ -273,7 +273,7 @@ drop table t2; create table t2 (primary key (auto)) select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1; show full columns from t2; Field Type Collation Null Key Default Extra Privileges Comment -auto int(11) unsigned NULL NO PRI NULL # +auto bigint(11) unsigned NULL NO PRI NULL # t1 int(1) NULL NO NULL # t2 varchar(1) latin1_swedish_ci NO NULL # t3 varchar(256) latin1_swedish_ci NO NULL #