diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 1f032faaa40..1a3289b2618 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -488,13 +488,35 @@ d date YES NULL e varchar(1) YES NULL f datetime YES NULL g time YES NULL -h longblob YES NULL +h blob YES NULL dd time YES NULL select * from t2; a b c d e f g h dd 1 -7 7 2000-01-01 b 2000-01-01 00:00:00 05:04:03 yet another binary data 02:00:00 2 -2 2 1825-12-14 a 2003-01-01 03:02:01 04:03:02 binary data 02:00:00 drop table t1, t2; +CREATE TABLE t1 ( +c_tinytext tinytext, +c_text text, +c_mediumtext mediumtext, +c_longtext longtext +); +CREATE TABLE t2 AS SELECT +ifnull(c_tinytext, CAST('yet another binary data' AS BINARY)), +ifnull(c_text, CAST('yet another binary data' AS BINARY)), +ifnull(c_mediumtext, CAST('yet another binary data' AS BINARY)), +ifnull(c_longtext, CAST('yet another binary data' AS BINARY)) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `ifnull(c_tinytext, CAST('yet another binary data' AS BINARY))` tinyblob DEFAULT NULL, + `ifnull(c_text, CAST('yet another binary data' AS BINARY))` blob DEFAULT NULL, + `ifnull(c_mediumtext, CAST('yet another binary data' AS BINARY))` mediumblob DEFAULT NULL, + `ifnull(c_longtext, CAST('yet another binary data' AS BINARY))` longblob DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; create table t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float(3,2), g double(4,3), h decimal(5,4), i year, j date, k timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, l datetime, m enum('a','b'), n set('a','b'), o char(10)); create table t2 select ifnull(a,a), ifnull(b,b), ifnull(c,c), ifnull(d,d), ifnull(e,e), ifnull(f,f), ifnull(g,g), ifnull(h,h), ifnull(i,i), ifnull(j,j), ifnull(k,k), ifnull(l,l), ifnull(m,m), ifnull(n,n), ifnull(o,o) from t1; show create table t2; diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 573799ff6e5..f6a88d49579 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -11184,5 +11184,21 @@ SET NAMES utf8; CREATE TABLE t1 (a SET('a,bü')); ERROR 22007: Illegal set 'a,bü' value found during parsing # +# MDEV-12607 Hybrid functions create wrong VARBINARY length when mixing character and binary data +# +SET sql_mode=''; +SET NAMES utf8; +CREATE OR REPLACE TABLE t1 AS SELECT COALESCE('ßa',_binary 'a'); +SELECT * FROM t1; +COALESCE('ßa',_binary 'a') +ßa +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `COALESCE('ßa',_binary 'a')` varbinary(6) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +SET sql_mode=DEFAULT; +# # End of 10.3 tests # diff --git a/mysql-test/r/func_hybrid_type.result b/mysql-test/r/func_hybrid_type.result index edb3a553492..dfc552cc58c 100644 --- a/mysql-test/r/func_hybrid_type.result +++ b/mysql-test/r/func_hybrid_type.result @@ -3500,5 +3500,17 @@ t2 CREATE TABLE `t2` ( DROP TABLE t2; DROP TABLE t1; # +# MDEV-12601 Hybrid functions create a column of an impossible type DOUBLE(256,4) +# +CREATE TABLE t1 (a DOUBLE(255,4),b DOUBLE(255,3)); +CREATE TABLE t2 AS SELECT COALESCE(a,b) FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `COALESCE(a,b)` double(255,4) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +# # End of 10.3 tests # diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 4194a6359c6..8a1302c9b5c 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -4661,3 +4661,20 @@ DROP TABLE t1; # # End of 10.1 tests # +# +# Start of 10.3 tests +# +# +# MDEV-12592 Illegal mix of collations with the HEX function +# +SET NAMES utf8; +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1); +INSERT INTO t1 VALUES (0x09),('a'); +SELECT IF(a<' ',HEX(a),a) FROM t1 ORDER BY a; +IF(a<' ',HEX(a),a) +09 +a +DROP TABLE t1; +# +# End of 10.3 tests +# diff --git a/mysql-test/r/func_weight_string.result b/mysql-test/r/func_weight_string.result index 04fd9962218..5fa78c861a9 100644 --- a/mysql-test/r/func_weight_string.result +++ b/mysql-test/r/func_weight_string.result @@ -57,7 +57,7 @@ create table t1 select weight_string(repeat('t',66000)) as w; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `w` longblob DEFAULT NULL + `w` mediumblob DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; select weight_string(NULL); diff --git a/mysql-test/r/gis-debug.result b/mysql-test/r/gis-debug.result index 889ee5c9513..1516c3d5089 100644 --- a/mysql-test/r/gis-debug.result +++ b/mysql-test/r/gis-debug.result @@ -381,11 +381,11 @@ POINT(0,0) MOD '0' LIMIT 0; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `POINT(0,0)+'0'` longtext DEFAULT NULL, - `POINT(0,0)-'0'` longtext DEFAULT NULL, - `POINT(0,0)*'0'` longtext DEFAULT NULL, - `POINT(0,0)/'0'` longtext DEFAULT NULL, - `POINT(0,0) MOD '0'` longtext DEFAULT NULL + `POINT(0,0)+'0'` tinytext DEFAULT NULL, + `POINT(0,0)-'0'` tinytext DEFAULT NULL, + `POINT(0,0)*'0'` tinytext DEFAULT NULL, + `POINT(0,0)/'0'` tinytext DEFAULT NULL, + `POINT(0,0) MOD '0'` tinytext DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; CREATE TABLE t1 AS SELECT @@ -394,8 +394,8 @@ CREATE TABLE t1 AS SELECT SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `'0'+POINT(0,0)` longtext DEFAULT NULL, - `'0'*POINT(0,0)` longtext DEFAULT NULL + `'0'+POINT(0,0)` tinytext DEFAULT NULL, + `'0'*POINT(0,0)` tinytext DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; CREATE TABLE t1 AS SELECT '0'-POINT(0,0) LIMIT 0; diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 77150ee3142..fdc0e1e6368 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -709,7 +709,7 @@ def test t1 t1 g g 255 4294967295 0 Y 144 0 63 g select asbinary(g) from t1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def asbinary(g) 252 4294967295 0 Y 128 0 63 +def asbinary(g) 251 4294967295 0 Y 128 0 63 asbinary(g) drop table t1; create table t1 (a TEXT, b GEOMETRY NOT NULL, SPATIAL KEY(b)); @@ -4030,65 +4030,65 @@ DROP TABLE t1; # CREATE TABLE t1 (a GEOMETRY); SELECT POINT(1,1) + 1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '+' +ERROR HY000: Illegal parameter data types geometry and int for operation '+' SELECT POINT(1,1) - 1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '-' +ERROR HY000: Illegal parameter data types geometry and int for operation '-' SELECT POINT(1,1) * 1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '*' +ERROR HY000: Illegal parameter data types geometry and int for operation '*' SELECT POINT(1,1) / 1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '/' +ERROR HY000: Illegal parameter data types geometry and int for operation '/' SELECT POINT(1,1) MOD 1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '%' +ERROR HY000: Illegal parameter data types geometry and int for operation '%' SELECT 1 + POINT(1,1); -ERROR HY000: Illegal parameter data types bigint and geometry for operation '+' +ERROR HY000: Illegal parameter data types int and geometry for operation '+' SELECT 1 - POINT(1,1); -ERROR HY000: Illegal parameter data types bigint and geometry for operation '-' +ERROR HY000: Illegal parameter data types int and geometry for operation '-' SELECT 1 * POINT(1,1); -ERROR HY000: Illegal parameter data types bigint and geometry for operation '*' +ERROR HY000: Illegal parameter data types int and geometry for operation '*' SELECT 1 / POINT(1,1); -ERROR HY000: Illegal parameter data types bigint and geometry for operation '/' +ERROR HY000: Illegal parameter data types int and geometry for operation '/' SELECT 1 MOD POINT(1,1); -ERROR HY000: Illegal parameter data types bigint and geometry for operation '%' +ERROR HY000: Illegal parameter data types int and geometry for operation '%' SELECT a + 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '+' +ERROR HY000: Illegal parameter data types geometry and int for operation '+' SELECT a - 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '-' +ERROR HY000: Illegal parameter data types geometry and int for operation '-' SELECT a * 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '*' +ERROR HY000: Illegal parameter data types geometry and int for operation '*' SELECT a / 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '/' +ERROR HY000: Illegal parameter data types geometry and int for operation '/' SELECT a MOD 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '%' +ERROR HY000: Illegal parameter data types geometry and int for operation '%' SELECT 1 + a FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '+' +ERROR HY000: Illegal parameter data types int and geometry for operation '+' SELECT 1 - a FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '-' +ERROR HY000: Illegal parameter data types int and geometry for operation '-' SELECT 1 * a FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '*' +ERROR HY000: Illegal parameter data types int and geometry for operation '*' SELECT 1 / a FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '/' +ERROR HY000: Illegal parameter data types int and geometry for operation '/' SELECT 1 MOD a FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '%' +ERROR HY000: Illegal parameter data types int and geometry for operation '%' SELECT COALESCE(a) + 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '+' +ERROR HY000: Illegal parameter data types geometry and int for operation '+' SELECT COALESCE(a) - 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '-' +ERROR HY000: Illegal parameter data types geometry and int for operation '-' SELECT COALESCE(a) * 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '*' +ERROR HY000: Illegal parameter data types geometry and int for operation '*' SELECT COALESCE(a) / 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '/' +ERROR HY000: Illegal parameter data types geometry and int for operation '/' SELECT COALESCE(a) MOD 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '%' +ERROR HY000: Illegal parameter data types geometry and int for operation '%' SELECT 1 + COALESCE(a) FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '+' +ERROR HY000: Illegal parameter data types int and geometry for operation '+' SELECT 1 - COALESCE(a) FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '-' +ERROR HY000: Illegal parameter data types int and geometry for operation '-' SELECT 1 * COALESCE(a) FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '*' +ERROR HY000: Illegal parameter data types int and geometry for operation '*' SELECT 1 / COALESCE(a) FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '/' +ERROR HY000: Illegal parameter data types int and geometry for operation '/' SELECT 1 MOD COALESCE(a) FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '%' +ERROR HY000: Illegal parameter data types int and geometry for operation '%' DROP TABLE t1; # # MDEV-12514 Split Item_temporal_func::fix_length_and_dec() diff --git a/mysql-test/r/metadata.result b/mysql-test/r/metadata.result index 3db3bcd450f..d31b2c5efe0 100644 --- a/mysql-test/r/metadata.result +++ b/mysql-test/r/metadata.result @@ -76,12 +76,12 @@ def aaa @arg00 @arg00 8 20 1 Y 32768 0 63 1 select 1 union select 1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def 1 1 8 20 1 N 32769 0 63 +def 1 1 3 11 1 N 32769 0 63 1 1 select * from (select 1 union select 1) aaa; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def aaa 1 1 8 20 1 N 32769 0 63 +def aaa 1 1 3 11 1 N 32769 0 63 1 1 drop table t1; diff --git a/mysql-test/r/null.result b/mysql-test/r/null.result index 0ff5c3243d8..8bbdfb2f90b 100644 --- a/mysql-test/r/null.result +++ b/mysql-test/r/null.result @@ -575,8 +575,14 @@ c_float FLOAT, c_double DOUBLE, c_decimal103 DECIMAL(10,3), c_varchar10 VARCHAR(10), +c_tinytext TINYTEXT, c_text TEXT, +c_mediumtext MEDIUMTEXT, +c_longtext LONGTEXT, +c_tinyblob TINYBLOB, c_blob BLOB, +c_mediumblob MEDIUMBLOB, +c_longblob LONGBLOB, c_enum ENUM('one','two','tree'), c_datetime3 DATETIME(3), c_timestamp3 TIMESTAMP(3), @@ -899,6 +905,45 @@ t2 CREATE TABLE `t2` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; CREATE TABLE t2 AS SELECT +NULLIF(c_tinytext, 1), +NULLIF(c_tinytext, c_smallint), +NULLIF(c_tinytext, c_tinyint), +NULLIF(c_tinytext, c_int), +NULLIF(c_tinytext, c_bigint), +NULLIF(c_tinytext, c_float), +NULLIF(c_tinytext, c_double), +NULLIF(c_tinytext, c_decimal103), +NULLIF(c_tinytext, c_varchar10), +NULLIF(c_tinytext, c_text), +NULLIF(c_tinytext, c_blob), +NULLIF(c_tinytext, c_enum), +NULLIF(c_tinytext, c_datetime3), +NULLIF(c_tinytext, c_timestamp3), +NULLIF(c_tinytext, c_date), +NULLIF(c_tinytext, c_time) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `NULLIF(c_tinytext, 1)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_smallint)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_tinyint)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_int)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_bigint)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_float)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_double)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_decimal103)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_varchar10)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_text)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_blob)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_enum)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_datetime3)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_timestamp3)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_date)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_time)` tinytext DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t2 AS SELECT NULLIF(c_text, 1), NULLIF(c_text, c_smallint), NULLIF(c_text, c_tinyint), @@ -919,22 +964,139 @@ FROM t1; SHOW CREATE TABLE t2; Table Create Table t2 CREATE TABLE `t2` ( - `NULLIF(c_text, 1)` longtext DEFAULT NULL, - `NULLIF(c_text, c_smallint)` longtext DEFAULT NULL, - `NULLIF(c_text, c_tinyint)` longtext DEFAULT NULL, - `NULLIF(c_text, c_int)` longtext DEFAULT NULL, - `NULLIF(c_text, c_bigint)` longtext DEFAULT NULL, - `NULLIF(c_text, c_float)` longtext DEFAULT NULL, - `NULLIF(c_text, c_double)` longtext DEFAULT NULL, - `NULLIF(c_text, c_decimal103)` longtext DEFAULT NULL, - `NULLIF(c_text, c_varchar10)` longtext DEFAULT NULL, - `NULLIF(c_text, c_text)` longtext DEFAULT NULL, - `NULLIF(c_text, c_blob)` longtext DEFAULT NULL, - `NULLIF(c_text, c_enum)` longtext DEFAULT NULL, - `NULLIF(c_text, c_datetime3)` longtext DEFAULT NULL, - `NULLIF(c_text, c_timestamp3)` longtext DEFAULT NULL, - `NULLIF(c_text, c_date)` longtext DEFAULT NULL, - `NULLIF(c_text, c_time)` longtext DEFAULT NULL + `NULLIF(c_text, 1)` text DEFAULT NULL, + `NULLIF(c_text, c_smallint)` text DEFAULT NULL, + `NULLIF(c_text, c_tinyint)` text DEFAULT NULL, + `NULLIF(c_text, c_int)` text DEFAULT NULL, + `NULLIF(c_text, c_bigint)` text DEFAULT NULL, + `NULLIF(c_text, c_float)` text DEFAULT NULL, + `NULLIF(c_text, c_double)` text DEFAULT NULL, + `NULLIF(c_text, c_decimal103)` text DEFAULT NULL, + `NULLIF(c_text, c_varchar10)` text DEFAULT NULL, + `NULLIF(c_text, c_text)` text DEFAULT NULL, + `NULLIF(c_text, c_blob)` text DEFAULT NULL, + `NULLIF(c_text, c_enum)` text DEFAULT NULL, + `NULLIF(c_text, c_datetime3)` text DEFAULT NULL, + `NULLIF(c_text, c_timestamp3)` text DEFAULT NULL, + `NULLIF(c_text, c_date)` text DEFAULT NULL, + `NULLIF(c_text, c_time)` text DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t2 AS SELECT +NULLIF(c_mediumtext, 1), +NULLIF(c_mediumtext, c_smallint), +NULLIF(c_mediumtext, c_tinyint), +NULLIF(c_mediumtext, c_int), +NULLIF(c_mediumtext, c_bigint), +NULLIF(c_mediumtext, c_float), +NULLIF(c_mediumtext, c_double), +NULLIF(c_mediumtext, c_decimal103), +NULLIF(c_mediumtext, c_varchar10), +NULLIF(c_mediumtext, c_text), +NULLIF(c_mediumtext, c_blob), +NULLIF(c_mediumtext, c_enum), +NULLIF(c_mediumtext, c_datetime3), +NULLIF(c_mediumtext, c_timestamp3), +NULLIF(c_mediumtext, c_date), +NULLIF(c_mediumtext, c_time) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `NULLIF(c_mediumtext, 1)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_smallint)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_tinyint)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_int)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_bigint)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_float)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_double)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_decimal103)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_varchar10)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_text)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_blob)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_enum)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_datetime3)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_timestamp3)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_date)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_time)` mediumtext DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t2 AS SELECT +NULLIF(c_longtext, 1), +NULLIF(c_longtext, c_smallint), +NULLIF(c_longtext, c_tinyint), +NULLIF(c_longtext, c_int), +NULLIF(c_longtext, c_bigint), +NULLIF(c_longtext, c_float), +NULLIF(c_longtext, c_double), +NULLIF(c_longtext, c_decimal103), +NULLIF(c_longtext, c_varchar10), +NULLIF(c_longtext, c_text), +NULLIF(c_longtext, c_blob), +NULLIF(c_longtext, c_enum), +NULLIF(c_longtext, c_datetime3), +NULLIF(c_longtext, c_timestamp3), +NULLIF(c_longtext, c_date), +NULLIF(c_longtext, c_time) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `NULLIF(c_longtext, 1)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_smallint)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_tinyint)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_int)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_bigint)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_float)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_double)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_decimal103)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_varchar10)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_text)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_blob)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_enum)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_datetime3)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_timestamp3)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_date)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_time)` longtext DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t2 AS SELECT +NULLIF(c_tinyblob, 1), +NULLIF(c_tinyblob, c_smallint), +NULLIF(c_tinyblob, c_tinyint), +NULLIF(c_tinyblob, c_int), +NULLIF(c_tinyblob, c_bigint), +NULLIF(c_tinyblob, c_float), +NULLIF(c_tinyblob, c_double), +NULLIF(c_tinyblob, c_decimal103), +NULLIF(c_tinyblob, c_varchar10), +NULLIF(c_tinyblob, c_text), +NULLIF(c_tinyblob, c_blob), +NULLIF(c_tinyblob, c_enum), +NULLIF(c_tinyblob, c_datetime3), +NULLIF(c_tinyblob, c_timestamp3), +NULLIF(c_tinyblob, c_date), +NULLIF(c_tinyblob, c_time) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `NULLIF(c_tinyblob, 1)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_smallint)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_tinyint)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_int)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_bigint)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_float)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_double)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_decimal103)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_varchar10)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_text)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_blob)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_enum)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_datetime3)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_timestamp3)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_date)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_time)` tinyblob DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; CREATE TABLE t2 AS SELECT @@ -958,22 +1120,100 @@ FROM t1; SHOW CREATE TABLE t2; Table Create Table t2 CREATE TABLE `t2` ( - `NULLIF(c_blob, 1)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_smallint)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_tinyint)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_int)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_bigint)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_float)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_double)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_decimal103)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_varchar10)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_text)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_blob)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_enum)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_datetime3)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_timestamp3)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_date)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_time)` longblob DEFAULT NULL + `NULLIF(c_blob, 1)` blob DEFAULT NULL, + `NULLIF(c_blob, c_smallint)` blob DEFAULT NULL, + `NULLIF(c_blob, c_tinyint)` blob DEFAULT NULL, + `NULLIF(c_blob, c_int)` blob DEFAULT NULL, + `NULLIF(c_blob, c_bigint)` blob DEFAULT NULL, + `NULLIF(c_blob, c_float)` blob DEFAULT NULL, + `NULLIF(c_blob, c_double)` blob DEFAULT NULL, + `NULLIF(c_blob, c_decimal103)` blob DEFAULT NULL, + `NULLIF(c_blob, c_varchar10)` blob DEFAULT NULL, + `NULLIF(c_blob, c_text)` blob DEFAULT NULL, + `NULLIF(c_blob, c_blob)` blob DEFAULT NULL, + `NULLIF(c_blob, c_enum)` blob DEFAULT NULL, + `NULLIF(c_blob, c_datetime3)` blob DEFAULT NULL, + `NULLIF(c_blob, c_timestamp3)` blob DEFAULT NULL, + `NULLIF(c_blob, c_date)` blob DEFAULT NULL, + `NULLIF(c_blob, c_time)` blob DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t2 AS SELECT +NULLIF(c_mediumblob, 1), +NULLIF(c_mediumblob, c_smallint), +NULLIF(c_mediumblob, c_tinyint), +NULLIF(c_mediumblob, c_int), +NULLIF(c_mediumblob, c_bigint), +NULLIF(c_mediumblob, c_float), +NULLIF(c_mediumblob, c_double), +NULLIF(c_mediumblob, c_decimal103), +NULLIF(c_mediumblob, c_varchar10), +NULLIF(c_mediumblob, c_text), +NULLIF(c_mediumblob, c_blob), +NULLIF(c_mediumblob, c_enum), +NULLIF(c_mediumblob, c_datetime3), +NULLIF(c_mediumblob, c_timestamp3), +NULLIF(c_mediumblob, c_date), +NULLIF(c_mediumblob, c_time) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `NULLIF(c_mediumblob, 1)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_smallint)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_tinyint)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_int)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_bigint)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_float)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_double)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_decimal103)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_varchar10)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_text)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_blob)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_enum)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_datetime3)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_timestamp3)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_date)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_time)` mediumblob DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t2 AS SELECT +NULLIF(c_longblob, 1), +NULLIF(c_longblob, c_smallint), +NULLIF(c_longblob, c_tinyint), +NULLIF(c_longblob, c_int), +NULLIF(c_longblob, c_bigint), +NULLIF(c_longblob, c_float), +NULLIF(c_longblob, c_double), +NULLIF(c_longblob, c_decimal103), +NULLIF(c_longblob, c_varchar10), +NULLIF(c_longblob, c_text), +NULLIF(c_longblob, c_blob), +NULLIF(c_longblob, c_enum), +NULLIF(c_longblob, c_datetime3), +NULLIF(c_longblob, c_timestamp3), +NULLIF(c_longblob, c_date), +NULLIF(c_longblob, c_time) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `NULLIF(c_longblob, 1)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_smallint)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_tinyint)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_int)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_bigint)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_float)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_double)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_decimal103)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_varchar10)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_text)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_blob)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_enum)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_datetime3)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_timestamp3)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_date)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_time)` longblob DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; CREATE TABLE t2 AS SELECT diff --git a/mysql-test/r/sp-row.result b/mysql-test/r/sp-row.result index 687e6629b8d..1f33f11a519 100644 --- a/mysql-test/r/sp-row.result +++ b/mysql-test/r/sp-row.result @@ -2052,8 +2052,8 @@ CALL p1(); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `var` varchar(255) DEFAULT NULL, - `rec.var` varchar(255) DEFAULT NULL + `var` tinytext DEFAULT NULL, + `rec.var` tinytext DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; DROP PROCEDURE p1; @@ -2092,8 +2092,8 @@ CALL p1(); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `var` varchar(255) CHARACTER SET utf8 DEFAULT NULL, - `rec.var` varchar(255) CHARACTER SET utf8 DEFAULT NULL + `var` text CHARACTER SET utf8 DEFAULT NULL, + `rec.var` text CHARACTER SET utf8 DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; DROP PROCEDURE p1; diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index 0ead4ec9aa2..2911e58fd88 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -1019,3 +1019,52 @@ cast('-0.0' as decimal(5,1)) < 0 # # End of 5.5 tests # +# +# Start of 10.3 tests +# +# +# MDEV-9217 Split Item::tmp_table_field_from_field_type() into virtual methods in Type_handler +# +# This creates the old DECIMAL. Will be fixed in MDEV-12574. +CREATE TABLE t1 AS SELECT MAX(a) FROM t1dec102; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `MAX(a)` decimal(10,2)/*old*/ DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 AS SELECT COALESCE(a) FROM t1dec102; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `COALESCE(a)` decimal(10,2) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (a BIGINT); +CREATE TABLE t2 AS SELECT a FROM t1dec102 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` decimal(21,2) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +CREATE TABLE t1 (a MEDIUMINT); +CREATE TABLE t2 AS SELECT a FROM t1dec102 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` decimal(10,2) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +CREATE TABLE t1 (a YEAR); +CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT a FROM t1dec102; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` decimal(10,2) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +DROP TABLE t1dec102; diff --git a/mysql-test/r/type_enum.result b/mysql-test/r/type_enum.result index 6ad75339847..02d71c6bd9f 100644 --- a/mysql-test/r/type_enum.result +++ b/mysql-test/r/type_enum.result @@ -1803,13 +1803,18 @@ id c1 + 0 c1 4 0 DROP TABLE t1; End of 4.1 tests -create table t1(f1 set('a','b'), index(f1)); +SET sql_mode=''; +create table t1(f1 enum('a','b'), index(f1)); insert into t1 values(''),(''),('a'),('b'); +Warnings: +Warning 1265 Data truncated for column 'f1' at row 1 +Warning 1265 Data truncated for column 'f1' at row 2 select * from t1 where f1=''; f1 drop table t1; +SET sql_mode=DEFAULT; CREATE TABLE t1 (c1 ENUM('a', '', 'b')); INSERT INTO t1 (c1) VALUES ('b'); INSERT INTO t1 (c1) VALUES (''); @@ -2219,3 +2224,90 @@ SELECT * FROM t1; a DROP TABLE t1; +# +# Start of 10.3 tests +# +# +# MDEV-12432 Range optimizer for ENUM and SET does not return "Impossible WHERE" in some case +# +CREATE TABLE t1 (a ENUM('a','b','c','1'),KEY(a)); +INSERT INTO t1 VALUES ('a'),('b'),('c'),('1'); +EXPLAIN SELECT * FROM t1 WHERE a='xx'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='99999999'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a=100.1e0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a=100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a=100.1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='100'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='1x'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='1.0'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='1.1'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +DROP TABLE t1; +# +# MDEV-12656 Crash in CREATE..SELECT..UNION with a ENUM column and NULL +# +CREATE TABLE t1 (a ENUM('a')); +# non-UNION + table column +CREATE TABLE t2 AS SELECT (SELECT a FROM t1); +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `(SELECT a FROM t1)` varchar(1) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +# UNION + table column +CREATE TABLE t2 AS SELECT (SELECT a FROM t1 UNION SELECT NULL); +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `(SELECT a FROM t1 UNION SELECT NULL)` varchar(1) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +# UNION + SP variable +CREATE PROCEDURE p1() +BEGIN +DECLARE va ENUM('a'); +CREATE TABLE t2 AS SELECT (SELECT va FROM t1 UNION SELECT NULL); +SHOW CREATE TABLE t2; +DROP TABLE t2; +END; +$$ +CALL p1(); +Table Create Table +t2 CREATE TABLE `t2` ( + `(SELECT va FROM t1 UNION SELECT NULL)` varchar(1) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP PROCEDURE p1; +# UNION + anchored SP variable +CREATE PROCEDURE p1() +BEGIN +DECLARE va TYPE OF t1.a; +CREATE TABLE t2 AS SELECT (SELECT va FROM t1 UNION SELECT NULL); +SHOW CREATE TABLE t2; +DROP TABLE t2; +END; +$$ +CALL p1(); +Table Create Table +t2 CREATE TABLE `t2` ( + `(SELECT va FROM t1 UNION SELECT NULL)` varchar(1) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP PROCEDURE p1; +DROP TABLE t1; diff --git a/mysql-test/r/type_set.result b/mysql-test/r/type_set.result index 742ee5a33e9..1258de317ec 100644 --- a/mysql-test/r/type_set.result +++ b/mysql-test/r/type_set.result @@ -316,3 +316,39 @@ DROP TABLE t1; # # End of 10.1 tests # +# +# Start of 10.3 tests +# +# +# MDEV-12432 Range optimizer for ENUM and SET does not return "Impossible WHERE" in some case +# +CREATE TABLE t1 (a SET('a','b','c','1'),KEY(a)); +INSERT INTO t1 VALUES ('a'),('b'),('c'),('1'); +EXPLAIN SELECT * FROM t1 WHERE a='xx'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='99999999'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a=100.1e0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a=100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a=100.1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='100'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='1x'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='1.0'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='1.1'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +DROP TABLE t1; diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result index 8e0da59d247..cf4f6df4b04 100644 --- a/mysql-test/r/type_timestamp.result +++ b/mysql-test/r/type_timestamp.result @@ -992,5 +992,25 @@ a b DROP TABLE t1; SET @@timestamp=DEFAULT; # +# MDEV-12582 Wrong data type for CREATE..SELECT MAX(COALESCE(timestamp_column)) +# +CREATE TABLE t1 (a TIMESTAMP); +CREATE TABLE t2 AS SELECT +MAX(a), +COALESCE(a), +COALESCE(MAX(a)), +MAX(COALESCE(a)) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `MAX(a)` timestamp NULL DEFAULT NULL, + `COALESCE(a)` timestamp NULL DEFAULT NULL, + `COALESCE(MAX(a))` timestamp NULL DEFAULT NULL, + `MAX(COALESCE(a))` timestamp NULL DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +# # End of 10.3 tests # diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index fe456e2aa80..9949defebf7 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -852,7 +852,7 @@ select * from t1; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `1` bigint(20) NOT NULL DEFAULT 0 + `1` int(11) NOT NULL DEFAULT 0 ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 select _latin1"test" union select _latin2"testt" ; @@ -1449,6 +1449,28 @@ t2 CREATE TABLE `t2` ( `f8` mediumtext CHARACTER SET utf8 DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1, t2; +CREATE TABLE t1 +( +c_varchar varchar(1) character set utf8 collate utf8_general_ci, +c_tinytext tinytext, +c_text text, +c_mediumtext mediumtext, +c_longtext longtext +); +CREATE TABLE t2 AS +SELECT c_tinytext, c_text, c_mediumtext, c_longtext FROM t1 +UNION +SELECT c_varchar, c_varchar, c_varchar, c_varchar FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `c_tinytext` text CHARACTER SET utf8 DEFAULT NULL, + `c_text` mediumtext CHARACTER SET utf8 DEFAULT NULL, + `c_mediumtext` longtext CHARACTER SET utf8 DEFAULT NULL, + `c_longtext` longtext CHARACTER SET utf8 DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; (select avg(1)) union (select avg(1)) union (select avg(1)) union (select avg(1)) union (select avg(1)) union (select avg(1)) union (select avg(1)) union (select avg(1)) union (select avg(1)) union @@ -2156,3 +2178,33 @@ WHERE t1_2.b NOT IN ( SELECT 4 UNION ALL SELECT 5 ); a b a b 1 1 1 1 DROP TABLE t1; +# +# Start of 10.3 tests +# +# +# MDEV-12619 UNION creates excessive integer column types for integer literals +# +CREATE TABLE t1 AS SELECT 1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `1` int(1) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE OR REPLACE TABLE t1 AS SELECT 1 UNION SELECT 1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `1` int(11) NOT NULL DEFAULT 0 +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE OR REPLACE TABLE t1 AS SELECT * FROM (SELECT 1 UNION SELECT 1) AS t0; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `1` int(11) NOT NULL DEFAULT 0 +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +# +# End of 10.3 tests +# diff --git a/mysql-test/suite/compat/oracle/r/sp-row.result b/mysql-test/suite/compat/oracle/r/sp-row.result index 5712bce3cee..6526b3e1ec3 100644 --- a/mysql-test/suite/compat/oracle/r/sp-row.result +++ b/mysql-test/suite/compat/oracle/r/sp-row.result @@ -2129,8 +2129,8 @@ CALL p1(); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE "t1" ( - "var" varchar(255) DEFAULT NULL, - "rec.var" varchar(255) DEFAULT NULL + "var" tinytext DEFAULT NULL, + "rec.var" tinytext DEFAULT NULL ) DROP TABLE t1; DROP PROCEDURE p1; @@ -2169,8 +2169,8 @@ CALL p1(); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE "t1" ( - "var" varchar(255) CHARACTER SET utf8 DEFAULT NULL, - "rec.var" varchar(255) CHARACTER SET utf8 DEFAULT NULL + "var" text CHARACTER SET utf8 DEFAULT NULL, + "rec.var" text CHARACTER SET utf8 DEFAULT NULL ) DROP TABLE t1; DROP PROCEDURE p1; diff --git a/mysql-test/suite/innodb_gis/r/1.result b/mysql-test/suite/innodb_gis/r/1.result index 31579a18ea0..3ab57babc43 100644 --- a/mysql-test/suite/innodb_gis/r/1.result +++ b/mysql-test/suite/innodb_gis/r/1.result @@ -681,7 +681,7 @@ def test t1 t1 g g 255 4294967295 0 Y 144 0 63 g select ST_asbinary(g) from t1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def ST_asbinary(g) 252 4294967295 0 Y 128 0 63 +def ST_asbinary(g) 251 4294967295 0 Y 128 0 63 ST_asbinary(g) drop table t1; create table t1 (a TEXT, b GEOMETRY NOT NULL, INDEX(b(5))); diff --git a/mysql-test/suite/innodb_gis/r/create_spatial_index.result b/mysql-test/suite/innodb_gis/r/create_spatial_index.result index 572e3ac0d14..9629fa03fef 100644 --- a/mysql-test/suite/innodb_gis/r/create_spatial_index.result +++ b/mysql-test/suite/innodb_gis/r/create_spatial_index.result @@ -1238,7 +1238,7 @@ Table Op Msg_type Msg_text test.tab check status OK DROP TABLE tab; CREATE TABLE tab(c1 POINT NOT NULL,CONSTRAINT tab_const check(c1 > 0) ) ENGINE=InnoDB; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '>' +ERROR HY000: Illegal parameter data types geometry and int for operation '>' CREATE TABLE tab(c1 POINT NOT NULL,CONSTRAINT tab_const check(CAST(c1 AS BINARY) > 0) ) ENGINE=InnoDB; CREATE SPATIAL INDEX idx1 ON tab(c1) ; SHOW CREATE TABLE tab; diff --git a/mysql-test/suite/innodb_gis/r/gis.result b/mysql-test/suite/innodb_gis/r/gis.result index 4257413f816..beb411505f9 100644 --- a/mysql-test/suite/innodb_gis/r/gis.result +++ b/mysql-test/suite/innodb_gis/r/gis.result @@ -681,7 +681,7 @@ def test t1 t1 g g 255 4294967295 0 Y 144 0 63 g select ST_asbinary(g) from t1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def ST_asbinary(g) 252 4294967295 0 Y 128 0 63 +def ST_asbinary(g) 251 4294967295 0 Y 128 0 63 ST_asbinary(g) drop table t1; create table t1 (a TEXT, b GEOMETRY NOT NULL, SPATIAL KEY(b)); diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 6461204f06e..bd89f220060 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -402,6 +402,22 @@ explain t2; select * from t2; drop table t1, t2; +CREATE TABLE t1 ( + c_tinytext tinytext, + c_text text, + c_mediumtext mediumtext, + c_longtext longtext +); +CREATE TABLE t2 AS SELECT + ifnull(c_tinytext, CAST('yet another binary data' AS BINARY)), + ifnull(c_text, CAST('yet another binary data' AS BINARY)), + ifnull(c_mediumtext, CAST('yet another binary data' AS BINARY)), + ifnull(c_longtext, CAST('yet another binary data' AS BINARY)) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + create table t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float(3,2), g double(4,3), h decimal(5,4), i year, j date, k timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, l datetime, m enum('a','b'), n set('a','b'), o char(10)); create table t2 select ifnull(a,a), ifnull(b,b), ifnull(c,c), ifnull(d,d), ifnull(e,e), ifnull(f,f), ifnull(g,g), ifnull(h,h), ifnull(i,i), ifnull(j,j), ifnull(k,k), ifnull(l,l), ifnull(m,m), ifnull(n,n), ifnull(o,o) from t1; show create table t2; diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 5e747bc4b3c..b191b27d367 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -2109,6 +2109,18 @@ SET NAMES utf8; --error ER_ILLEGAL_VALUE_FOR_TYPE CREATE TABLE t1 (a SET('a,bü')); +--echo # +--echo # MDEV-12607 Hybrid functions create wrong VARBINARY length when mixing character and binary data +--echo # +SET sql_mode=''; +SET NAMES utf8; +CREATE OR REPLACE TABLE t1 AS SELECT COALESCE('ßa',_binary 'a'); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +SET sql_mode=DEFAULT; + + --echo # --echo # End of 10.3 tests --echo # diff --git a/mysql-test/t/func_hybrid_type.test b/mysql-test/t/func_hybrid_type.test index 2efbdbe0451..918320a68c5 100644 --- a/mysql-test/t/func_hybrid_type.test +++ b/mysql-test/t/func_hybrid_type.test @@ -500,6 +500,16 @@ SHOW CREATE TABLE t2; DROP TABLE t2; DROP TABLE t1; +--echo # +--echo # MDEV-12601 Hybrid functions create a column of an impossible type DOUBLE(256,4) +--echo # + +CREATE TABLE t1 (a DOUBLE(255,4),b DOUBLE(255,3)); +CREATE TABLE t2 AS SELECT COALESCE(a,b) FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + --echo # --echo # End of 10.3 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index bc5b112e949..b3f6b4faf49 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -1806,3 +1806,23 @@ DROP TABLE t1; --echo # --echo # End of 10.1 tests --echo # + + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-12592 Illegal mix of collations with the HEX function +--echo # + +SET NAMES utf8; +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1); +INSERT INTO t1 VALUES (0x09),('a'); +SELECT IF(a<' ',HEX(a),a) FROM t1 ORDER BY a; +DROP TABLE t1; + + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/mysql-test/t/null.test b/mysql-test/t/null.test index 3de35a74a73..403790356ce 100644 --- a/mysql-test/t/null.test +++ b/mysql-test/t/null.test @@ -414,8 +414,14 @@ CREATE TABLE t1 c_double DOUBLE, c_decimal103 DECIMAL(10,3), c_varchar10 VARCHAR(10), + c_tinytext TINYTEXT, c_text TEXT, + c_mediumtext MEDIUMTEXT, + c_longtext LONGTEXT, + c_tinyblob TINYBLOB, c_blob BLOB, + c_mediumblob MEDIUMBLOB, + c_longblob LONGBLOB, c_enum ENUM('one','two','tree'), c_datetime3 DATETIME(3), c_timestamp3 TIMESTAMP(3), @@ -596,6 +602,27 @@ FROM t1; SHOW CREATE TABLE t2; DROP TABLE t2; +CREATE TABLE t2 AS SELECT + NULLIF(c_tinytext, 1), + NULLIF(c_tinytext, c_smallint), + NULLIF(c_tinytext, c_tinyint), + NULLIF(c_tinytext, c_int), + NULLIF(c_tinytext, c_bigint), + NULLIF(c_tinytext, c_float), + NULLIF(c_tinytext, c_double), + NULLIF(c_tinytext, c_decimal103), + NULLIF(c_tinytext, c_varchar10), + NULLIF(c_tinytext, c_text), + NULLIF(c_tinytext, c_blob), + NULLIF(c_tinytext, c_enum), + NULLIF(c_tinytext, c_datetime3), + NULLIF(c_tinytext, c_timestamp3), + NULLIF(c_tinytext, c_date), + NULLIF(c_tinytext, c_time) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + CREATE TABLE t2 AS SELECT NULLIF(c_text, 1), NULLIF(c_text, c_smallint), @@ -617,7 +644,70 @@ FROM t1; SHOW CREATE TABLE t2; DROP TABLE t2; -# QQ: this should probably create BLOB instead of LONGBLOB +CREATE TABLE t2 AS SELECT + NULLIF(c_mediumtext, 1), + NULLIF(c_mediumtext, c_smallint), + NULLIF(c_mediumtext, c_tinyint), + NULLIF(c_mediumtext, c_int), + NULLIF(c_mediumtext, c_bigint), + NULLIF(c_mediumtext, c_float), + NULLIF(c_mediumtext, c_double), + NULLIF(c_mediumtext, c_decimal103), + NULLIF(c_mediumtext, c_varchar10), + NULLIF(c_mediumtext, c_text), + NULLIF(c_mediumtext, c_blob), + NULLIF(c_mediumtext, c_enum), + NULLIF(c_mediumtext, c_datetime3), + NULLIF(c_mediumtext, c_timestamp3), + NULLIF(c_mediumtext, c_date), + NULLIF(c_mediumtext, c_time) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +CREATE TABLE t2 AS SELECT + NULLIF(c_longtext, 1), + NULLIF(c_longtext, c_smallint), + NULLIF(c_longtext, c_tinyint), + NULLIF(c_longtext, c_int), + NULLIF(c_longtext, c_bigint), + NULLIF(c_longtext, c_float), + NULLIF(c_longtext, c_double), + NULLIF(c_longtext, c_decimal103), + NULLIF(c_longtext, c_varchar10), + NULLIF(c_longtext, c_text), + NULLIF(c_longtext, c_blob), + NULLIF(c_longtext, c_enum), + NULLIF(c_longtext, c_datetime3), + NULLIF(c_longtext, c_timestamp3), + NULLIF(c_longtext, c_date), + NULLIF(c_longtext, c_time) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + + +CREATE TABLE t2 AS SELECT + NULLIF(c_tinyblob, 1), + NULLIF(c_tinyblob, c_smallint), + NULLIF(c_tinyblob, c_tinyint), + NULLIF(c_tinyblob, c_int), + NULLIF(c_tinyblob, c_bigint), + NULLIF(c_tinyblob, c_float), + NULLIF(c_tinyblob, c_double), + NULLIF(c_tinyblob, c_decimal103), + NULLIF(c_tinyblob, c_varchar10), + NULLIF(c_tinyblob, c_text), + NULLIF(c_tinyblob, c_blob), + NULLIF(c_tinyblob, c_enum), + NULLIF(c_tinyblob, c_datetime3), + NULLIF(c_tinyblob, c_timestamp3), + NULLIF(c_tinyblob, c_date), + NULLIF(c_tinyblob, c_time) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + CREATE TABLE t2 AS SELECT NULLIF(c_blob, 1), NULLIF(c_blob, c_smallint), @@ -639,6 +729,49 @@ FROM t1; SHOW CREATE TABLE t2; DROP TABLE t2; +CREATE TABLE t2 AS SELECT + NULLIF(c_mediumblob, 1), + NULLIF(c_mediumblob, c_smallint), + NULLIF(c_mediumblob, c_tinyint), + NULLIF(c_mediumblob, c_int), + NULLIF(c_mediumblob, c_bigint), + NULLIF(c_mediumblob, c_float), + NULLIF(c_mediumblob, c_double), + NULLIF(c_mediumblob, c_decimal103), + NULLIF(c_mediumblob, c_varchar10), + NULLIF(c_mediumblob, c_text), + NULLIF(c_mediumblob, c_blob), + NULLIF(c_mediumblob, c_enum), + NULLIF(c_mediumblob, c_datetime3), + NULLIF(c_mediumblob, c_timestamp3), + NULLIF(c_mediumblob, c_date), + NULLIF(c_mediumblob, c_time) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +CREATE TABLE t2 AS SELECT + NULLIF(c_longblob, 1), + NULLIF(c_longblob, c_smallint), + NULLIF(c_longblob, c_tinyint), + NULLIF(c_longblob, c_int), + NULLIF(c_longblob, c_bigint), + NULLIF(c_longblob, c_float), + NULLIF(c_longblob, c_double), + NULLIF(c_longblob, c_decimal103), + NULLIF(c_longblob, c_varchar10), + NULLIF(c_longblob, c_text), + NULLIF(c_longblob, c_blob), + NULLIF(c_longblob, c_enum), + NULLIF(c_longblob, c_datetime3), + NULLIF(c_longblob, c_timestamp3), + NULLIF(c_longblob, c_date), + NULLIF(c_longblob, c_time) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + + # QQ: this should probably create a ENUM column instead of VARCHAR(4) CREATE TABLE t2 AS SELECT NULLIF(c_enum, 1), diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 777bb2f23e5..51fa3bb7461 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -612,3 +612,46 @@ select cast('-0.0' as decimal(5,1)) < 0; --echo # --echo # End of 5.5 tests --echo # + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-9217 Split Item::tmp_table_field_from_field_type() into virtual methods in Type_handler +--echo # + +let $MYSQLD_DATADIR= `select @@datadir`; + +--copy_file std_data/old_decimal/t1dec102.frm $MYSQLD_DATADIR/test/t1dec102.frm +--copy_file std_data/old_decimal/t1dec102.MYD $MYSQLD_DATADIR/test/t1dec102.MYD +--copy_file std_data/old_decimal/t1dec102.MYI $MYSQLD_DATADIR/test/t1dec102.MYI + +--echo # This creates the old DECIMAL. Will be fixed in MDEV-12574. +CREATE TABLE t1 AS SELECT MAX(a) FROM t1dec102; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 AS SELECT COALESCE(a) FROM t1dec102; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 (a BIGINT); +CREATE TABLE t2 AS SELECT a FROM t1dec102 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + +CREATE TABLE t1 (a MEDIUMINT); +CREATE TABLE t2 AS SELECT a FROM t1dec102 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + +CREATE TABLE t1 (a YEAR); +CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT a FROM t1dec102; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + +DROP TABLE t1dec102; diff --git a/mysql-test/t/type_enum.test b/mysql-test/t/type_enum.test index 105da427219..a79335960bc 100644 --- a/mysql-test/t/type_enum.test +++ b/mysql-test/t/type_enum.test @@ -179,10 +179,12 @@ DROP TABLE t1; # # Bug#28729: Field_enum wrongly reported an error while storing an empty string. # -create table t1(f1 set('a','b'), index(f1)); +SET sql_mode=''; +create table t1(f1 enum('a','b'), index(f1)); insert into t1 values(''),(''),('a'),('b'); select * from t1 where f1=''; drop table t1; +SET sql_mode=DEFAULT; # # Bug#29360: Confluence of the special 0 enum value with the normal empty string @@ -454,3 +456,65 @@ SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR ALTER TABLE t1 MODIFY a ENUM('2001','2002'); SELECT * FROM t1; DROP TABLE t1; + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-12432 Range optimizer for ENUM and SET does not return "Impossible WHERE" in some case +--echo # + +CREATE TABLE t1 (a ENUM('a','b','c','1'),KEY(a)); +INSERT INTO t1 VALUES ('a'),('b'),('c'),('1'); +EXPLAIN SELECT * FROM t1 WHERE a='xx'; +EXPLAIN SELECT * FROM t1 WHERE a='99999999'; +EXPLAIN SELECT * FROM t1 WHERE a=100.1e0; +EXPLAIN SELECT * FROM t1 WHERE a=100; +EXPLAIN SELECT * FROM t1 WHERE a=100.1; +EXPLAIN SELECT * FROM t1 WHERE a='100'; +EXPLAIN SELECT * FROM t1 WHERE a='1x'; +EXPLAIN SELECT * FROM t1 WHERE a='1.0'; +EXPLAIN SELECT * FROM t1 WHERE a='1.1'; +DROP TABLE t1; + +--echo # +--echo # MDEV-12656 Crash in CREATE..SELECT..UNION with a ENUM column and NULL +--echo # + +CREATE TABLE t1 (a ENUM('a')); +--echo # non-UNION + table column +CREATE TABLE t2 AS SELECT (SELECT a FROM t1); +SHOW CREATE TABLE t2; +DROP TABLE t2; +--echo # UNION + table column +CREATE TABLE t2 AS SELECT (SELECT a FROM t1 UNION SELECT NULL); +SHOW CREATE TABLE t2; +DROP TABLE t2; +--echo # UNION + SP variable +DELIMITER $$; +CREATE PROCEDURE p1() +BEGIN + DECLARE va ENUM('a'); + CREATE TABLE t2 AS SELECT (SELECT va FROM t1 UNION SELECT NULL); + SHOW CREATE TABLE t2; + DROP TABLE t2; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +--echo # UNION + anchored SP variable +DELIMITER $$; +CREATE PROCEDURE p1() +BEGIN + DECLARE va TYPE OF t1.a; + CREATE TABLE t2 AS SELECT (SELECT va FROM t1 UNION SELECT NULL); + SHOW CREATE TABLE t2; + DROP TABLE t2; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; diff --git a/mysql-test/t/type_set.test b/mysql-test/t/type_set.test index 7a79cd12f70..8c26d5a4366 100644 --- a/mysql-test/t/type_set.test +++ b/mysql-test/t/type_set.test @@ -218,3 +218,25 @@ DROP TABLE t1; --echo # --echo # End of 10.1 tests --echo # + + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-12432 Range optimizer for ENUM and SET does not return "Impossible WHERE" in some case +--echo # + +CREATE TABLE t1 (a SET('a','b','c','1'),KEY(a)); +INSERT INTO t1 VALUES ('a'),('b'),('c'),('1'); +EXPLAIN SELECT * FROM t1 WHERE a='xx'; +EXPLAIN SELECT * FROM t1 WHERE a='99999999'; +EXPLAIN SELECT * FROM t1 WHERE a=100.1e0; +EXPLAIN SELECT * FROM t1 WHERE a=100; +EXPLAIN SELECT * FROM t1 WHERE a=100.1; +EXPLAIN SELECT * FROM t1 WHERE a='100'; +EXPLAIN SELECT * FROM t1 WHERE a='1x'; +EXPLAIN SELECT * FROM t1 WHERE a='1.0'; +EXPLAIN SELECT * FROM t1 WHERE a='1.1'; +DROP TABLE t1; diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test index 058d5687819..6d81a86331a 100644 --- a/mysql-test/t/type_timestamp.test +++ b/mysql-test/t/type_timestamp.test @@ -587,6 +587,22 @@ SELECT * FROM t1 WHERE TIME'10:20:30' BETWEEN a and b; DROP TABLE t1; SET @@timestamp=DEFAULT; +--echo # +--echo # MDEV-12582 Wrong data type for CREATE..SELECT MAX(COALESCE(timestamp_column)) +--echo # + +CREATE TABLE t1 (a TIMESTAMP); +CREATE TABLE t2 AS SELECT + MAX(a), + COALESCE(a), + COALESCE(MAX(a)), + MAX(COALESCE(a)) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + + --echo # --echo # End of 10.3 tests --echo # diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index e0c011e3d20..04ab71588be 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -889,6 +889,22 @@ create table t2 as select *, f6 as f8 from t1 union select *, f7 from t1; show create table t2; drop table t1, t2; +CREATE TABLE t1 +( + c_varchar varchar(1) character set utf8 collate utf8_general_ci, + c_tinytext tinytext, + c_text text, + c_mediumtext mediumtext, + c_longtext longtext +); +CREATE TABLE t2 AS +SELECT c_tinytext, c_text, c_mediumtext, c_longtext FROM t1 +UNION +SELECT c_varchar, c_varchar, c_varchar, c_varchar FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + # # Bug#18175: Union select over 129 tables with a sum function fails. # @@ -1507,3 +1523,27 @@ SELECT * FROM t1 t1_1 LEFT JOIN t1 t1_2 ON ( t1_2.b = t1_1.a ) WHERE t1_2.b NOT IN ( SELECT 4 UNION ALL SELECT 5 ); DROP TABLE t1; + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-12619 UNION creates excessive integer column types for integer literals +--echo # + +CREATE TABLE t1 AS SELECT 1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE OR REPLACE TABLE t1 AS SELECT 1 UNION SELECT 1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE OR REPLACE TABLE t1 AS SELECT * FROM (SELECT 1 UNION SELECT 1) AS t0; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/sql/field.cc b/sql/field.cc index 9215a6b8e60..8b4aac93a9c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -125,7 +125,7 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]= //MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_VARCHAR, //MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24 - MYSQL_TYPE_DECIMAL, MYSQL_TYPE_DECIMAL, + MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_NEWDECIMAL, //MYSQL_TYPE_DATE MYSQL_TYPE_TIME MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR, //MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR @@ -520,7 +520,7 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]= /* MYSQL_TYPE_YEAR -> */ { //MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY - MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, + MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_TINY, //MYSQL_TYPE_SHORT MYSQL_TYPE_LONG MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG, //MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE @@ -1256,14 +1256,14 @@ bool Field::can_optimize_group_min_max(const Item_bool_func *cond, /* - This covers all numeric types, ENUM, SET, BIT + This covers all numeric types, BIT */ bool Field::can_optimize_range(const Item_bool_func *cond, const Item *item, bool is_eq_func) const { DBUG_ASSERT(cmp_type() != TIME_RESULT); // Handled in Field_temporal - DBUG_ASSERT(cmp_type() != STRING_RESULT); // Handled in Field_longstr + DBUG_ASSERT(cmp_type() != STRING_RESULT); // Handled in Field_str descendants return item->cmp_type() != TIME_RESULT; } @@ -2003,15 +2003,15 @@ bool Field_num::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) Field_str::Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const LEX_CSTRING *field_name_arg, - CHARSET_INFO *charset_arg) + const DTCollation &collation) :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) { - field_charset= charset_arg; - if (charset_arg->state & MY_CS_BINSORT) + field_charset= collation.collation; + if (collation.collation->state & MY_CS_BINSORT) flags|=BINARY_FLAG; - field_derivation= DERIVATION_IMPLICIT; - field_repertoire= my_charset_repertoire(charset_arg); + field_derivation= collation.derivation; + field_repertoire= collation.repertoire; } @@ -2912,67 +2912,6 @@ Field_new_decimal::Field_new_decimal(uchar *ptr_arg, } -Field_new_decimal::Field_new_decimal(uint32 len_arg, - bool maybe_null_arg, - const LEX_CSTRING *name, - uint8 dec_arg, - bool unsigned_arg) - :Field_num((uchar*) 0, len_arg, - maybe_null_arg ? (uchar*) "": 0, 0, - NONE, name, dec_arg, 0, unsigned_arg) -{ - precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg); - set_if_smaller(precision, DECIMAL_MAX_PRECISION); - DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) && - (dec <= DECIMAL_MAX_SCALE)); - bin_size= my_decimal_get_binary_size(precision, dec); -} - - -Field *Field_new_decimal::create_from_item(MEM_ROOT *mem_root, Item *item) -{ - uint8 dec= item->decimals; - uint8 intg= item->decimal_precision() - dec; - uint32 len= item->max_char_length(); - DBUG_ASSERT (item->result_type() == DECIMAL_RESULT); - - /* - Trying to put too many digits overall in a DECIMAL(prec,dec) - will always throw a warning. We must limit dec to - DECIMAL_MAX_SCALE however to prevent an assert() later. - */ - - if (dec > 0) - { - signed int overflow; - - dec= MY_MIN(dec, DECIMAL_MAX_SCALE); - - /* - If the value still overflows the field with the corrected dec, - we'll throw out decimals rather than integers. This is still - bad and of course throws a truncation warning. - +1: for decimal point - */ - - const int required_length= - my_decimal_precision_to_length(intg + dec, dec, - item->unsigned_flag); - - overflow= required_length - len; - - if (overflow > 0) - dec= MY_MAX(0, dec - overflow); // too long, discard fract - else - /* Corrected value fits. */ - len= required_length; - } - return new (mem_root) - Field_new_decimal(len, item->maybe_null, &item->name, - dec, item->unsigned_flag); -} - - int Field_new_decimal::reset(void) { store_value(&decimal_zero); @@ -7817,10 +7756,10 @@ Field_blob::Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, TABLE_SHARE *share, uint blob_pack_length, - CHARSET_INFO *cs) + const DTCollation &collation) :Field_longstr(ptr_arg, BLOB_PACK_LENGTH_TO_MAX_LENGH(blob_pack_length), null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, - cs), + collation), packlength(blob_pack_length) { DBUG_ASSERT(blob_pack_length <= 4); // Only pack lengths 1-4 supported currently @@ -8237,6 +8176,22 @@ void Field_blob::sort_string(uchar *to,uint length) } +/* + Return the data type handler, according to packlength. + Implemented in field.cc rather than in field.h + to avoid exporting type_handler_xxx with MYSQL_PLUGIN_IMPORT. +*/ +const Type_handler *Field_blob::type_handler() const +{ + switch (packlength) { + case 1: return &type_handler_tiny_blob; + case 2: return &type_handler_blob; + case 3: return &type_handler_medium_blob; + } + return &type_handler_long_blob; +} + + void Field_blob::sql_type(String &res) const { const char *str; @@ -8638,12 +8593,16 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) { tmp=0; set_warning(WARN_DATA_TRUNCATED, 1); + err= 1; } - if (!get_thd()->count_cuted_fields) + if (!get_thd()->count_cuted_fields && !length) err= 0; } else + { set_warning(WARN_DATA_TRUNCATED, 1); + err= 1; + } } store_type((ulonglong) tmp); return err; @@ -8817,6 +8776,7 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) { tmp=0; set_warning(WARN_DATA_TRUNCATED, 1); + err= 1; } } else if (got_warning) @@ -9055,12 +9015,17 @@ uint Field_num::is_equal(Create_field *new_field) } +bool Field_enum::can_optimize_range(const Item_bool_func *cond, + const Item *item, + bool is_eq_func) const +{ + return item->cmp_type() != TIME_RESULT; +} + + bool Field_enum::can_optimize_keypart_ref(const Item_bool_func *cond, const Item *item) const { - DBUG_ASSERT(cmp_type() == INT_RESULT); - DBUG_ASSERT(result_type() == STRING_RESULT); - switch (item->cmp_type()) { case TIME_RESULT: @@ -10717,7 +10682,7 @@ uint32 Field_blob::char_length() const case 3: return 16777215; case 4: - return (uint32) 4294967295U; + return (uint32) UINT_MAX32; default: DBUG_ASSERT(0); // we should never go here return 0; @@ -10770,7 +10735,7 @@ uint32 Field_blob::max_display_length() case 3: return 16777215 * field_charset->mbmaxlen; case 4: - return (uint32) 4294967295U; + return (uint32) UINT_MAX32; default: DBUG_ASSERT(0); // we should never go here return 0; diff --git a/sql/field.h b/sql/field.h index f576db82bdc..fb0ca6092c3 100644 --- a/sql/field.h +++ b/sql/field.h @@ -525,27 +525,6 @@ inline bool is_temporal_type(enum_field_types type) } -/** - Tests if field type is temporal and has time part, - i.e. represents TIME, DATETIME or TIMESTAMP types in SQL. - - @param type Field type, as returned by field->type(). - @retval true If field type is temporal type with time part. - @retval false If field type is not temporal type with time part. -*/ -inline bool is_temporal_type_with_time(enum_field_types type) -{ - switch (type) - { - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIMESTAMP: - return true; - default: - return false; - } -} - enum enum_vcol_info_type { VCOL_GENERATED_VIRTUAL, VCOL_GENERATED_STORED, @@ -872,11 +851,13 @@ public: to be quoted when used in constructing an SQL query. */ virtual bool str_needs_quotes() { return FALSE; } - virtual Item_result result_type () const=0; - virtual Item_result cmp_type () const { return result_type(); } - virtual const Type_handler *cast_to_int_type_handler() const + Item_result result_type () const { - return Type_handler::get_handler_by_field_type(type()); + return type_handler()->result_type(); + } + Item_result cmp_type () const + { + return type_handler()->cmp_type(); } static bool type_can_have_key_part(enum_field_types); static enum_field_types field_type_merge(enum_field_types, enum_field_types); @@ -992,8 +973,15 @@ public: virtual bool zero_pack() const { return 1; } virtual enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } virtual uint32 key_length() const { return pack_length(); } - virtual enum_field_types type() const =0; - virtual enum_field_types real_type() const { return type(); } + virtual const Type_handler *type_handler() const= 0; + virtual enum_field_types type() const + { + return type_handler()->field_type(); + } + virtual enum_field_types real_type() const + { + return type_handler()->real_field_type(); + } virtual enum_field_types binlog_type() const { /* @@ -1318,9 +1306,6 @@ public: virtual enum Derivation derivation(void) const { return DERIVATION_IMPLICIT; } virtual uint repertoire(void) const { return MY_REPERTOIRE_UNICODE30; } - virtual void set_derivation(enum Derivation derivation_arg, - uint repertoire_arg) - { } virtual int set_time() { return 1; } bool set_warning(Sql_condition::enum_warning_level, unsigned int code, int cuted_increment) const; @@ -1610,7 +1595,6 @@ public: uchar null_bit_arg, utype unireg_check_arg, const LEX_CSTRING *field_name_arg, uint8 dec_arg, bool zero_arg, bool unsigned_arg); - enum Item_result result_type () const { return INT_RESULT; } enum Derivation derivation(void) const { return DERIVATION_NUMERIC; } uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; } CHARSET_INFO *charset(void) const { return &my_charset_numeric; } @@ -1672,8 +1656,8 @@ public: const Item_equal *item_equal); Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, - const LEX_CSTRING *field_name_arg, CHARSET_INFO *charset); - Item_result result_type () const { return STRING_RESULT; } + const LEX_CSTRING *field_name_arg, + const DTCollation &collation); uint decimals() const { return NOT_FIXED_DEC; } int save_in_field(Field *to) { return save_in_field_str(to); } bool memcpy_field_possible(const Field *from) const @@ -1693,12 +1677,6 @@ public: uint repertoire(void) const { return field_repertoire; } CHARSET_INFO *charset(void) const { return field_charset; } enum Derivation derivation(void) const { return field_derivation; } - void set_derivation(enum Derivation derivation_arg, - uint repertoire_arg) - { - field_derivation= derivation_arg; - field_repertoire= repertoire_arg; - } bool binary() const { return field_charset == &my_charset_bin; } uint32 max_display_length() { return field_length; } friend class Create_field; @@ -1740,9 +1718,10 @@ protected: public: Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, - const LEX_CSTRING *field_name_arg, CHARSET_INFO *charset_arg) + const LEX_CSTRING *field_name_arg, + const DTCollation &collation) :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, - field_name_arg, charset_arg) + field_name_arg, collation) {} int store_decimal(const my_decimal *d); @@ -1781,7 +1760,6 @@ public: field_name_arg, dec_arg, zero_arg, unsigned_arg), not_fixed(dec_arg >= FLOATING_POINT_DECIMALS) {} - Item_result result_type () const { return REAL_RESULT; } Copy_func *get_copy_func(const Field *from) const { return do_field_real; @@ -1818,7 +1796,7 @@ public: unireg_check_arg, field_name_arg, dec_arg, zero_arg, unsigned_arg) {} - enum_field_types type() const { return MYSQL_TYPE_DECIMAL;} + const Type_handler *type_handler() const { return &type_handler_olddecimal; } enum ha_base_keytype key_type() const { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; } Copy_func *get_copy_func(const Field *from) const @@ -1863,12 +1841,8 @@ public: enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, uint8 dec_arg, bool zero_arg, bool unsigned_arg); - Field_new_decimal(uint32 len_arg, bool maybe_null_arg, - const LEX_CSTRING *field_name_arg, uint8 dec_arg, - bool unsigned_arg); - enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;} + const Type_handler *type_handler() const { return &type_handler_newdecimal; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } - Item_result result_type () const { return DECIMAL_RESULT; } Copy_func *get_copy_func(const Field *from) const { // if (from->real_type() == MYSQL_TYPE_BIT) // QQ: why? @@ -1918,7 +1892,6 @@ public: uint16 mflags, int *order_var); uint is_equal(Create_field *new_field); virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data); - static Field *create_from_item(MEM_ROOT *root, Item *); Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item); }; @@ -1933,7 +1906,7 @@ public: unireg_check_arg, field_name_arg, 0, zero_arg,unsigned_arg) {} - enum_field_types type() const { return MYSQL_TYPE_TINY;} + const Type_handler *type_handler() const { return &type_handler_tiny; } enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -1983,7 +1956,7 @@ public: :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg, 0, 0, unsigned_arg) {} - enum_field_types type() const { return MYSQL_TYPE_SHORT;} + const Type_handler *type_handler() const { return &type_handler_short; } enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;} int store(const char *to,uint length,CHARSET_INFO *charset); @@ -2018,7 +1991,7 @@ public: unireg_check_arg, field_name_arg, 0, zero_arg,unsigned_arg) {} - enum_field_types type() const { return MYSQL_TYPE_INT24;} + const Type_handler *type_handler() const { return &type_handler_int24; } enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -2058,7 +2031,7 @@ public: :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg,0,0,unsigned_arg) {} - enum_field_types type() const { return MYSQL_TYPE_LONG;} + const Type_handler *type_handler() const { return &type_handler_long; } enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -2104,7 +2077,7 @@ public: :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg,0,0,unsigned_arg) {} - enum_field_types type() const { return MYSQL_TYPE_LONGLONG;} + const Type_handler *type_handler() const { return &type_handler_longlong; } enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -2158,7 +2131,7 @@ public: if (dec_arg >= FLOATING_POINT_DECIMALS) dec_arg= NOT_FIXED_DEC; } - enum_field_types type() const { return MYSQL_TYPE_FLOAT;} + const Type_handler *type_handler() const { return &type_handler_float; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); @@ -2209,7 +2182,7 @@ public: if (dec_arg >= FLOATING_POINT_DECIMALS) dec_arg= NOT_FIXED_DEC; } - enum_field_types type() const { return MYSQL_TYPE_DOUBLE;} + const Type_handler *type_handler() const { return &type_handler_double; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); @@ -2242,11 +2215,11 @@ class Field_null :public Field_str { public: Field_null(uchar *ptr_arg, uint32 len_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, - CHARSET_INFO *cs) + const DTCollation &collation) :Field_str(ptr_arg, len_arg, null, 1, - unireg_check_arg, field_name_arg, cs) + unireg_check_arg, field_name_arg, collation) {} - enum_field_types type() const { return MYSQL_TYPE_NULL;} + const Type_handler *type_handler() const { return &type_handler_null; } Copy_func *get_copy_func(const Field *from) const { return do_field_string; @@ -2296,7 +2269,6 @@ public: :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) { flags|= BINARY_FLAG; } - Item_result result_type () const { return STRING_RESULT; } int store_hex_hybrid(const char *str, uint length) { return store(str, length, &my_charset_bin); @@ -2317,7 +2289,6 @@ public: CHARSET_INFO *charset(void) const { return &my_charset_numeric; } CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; } bool binary() const { return true; } - enum Item_result cmp_type () const { return TIME_RESULT; } bool val_bool() { return val_real() != 0e0; } uint is_equal(Create_field *new_field); bool eq_def(const Field *field) const @@ -2394,7 +2365,7 @@ public: enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, TABLE_SHARE *share); - enum_field_types type() const { return MYSQL_TYPE_TIMESTAMP;} + const Type_handler *type_handler() const { return &type_handler_timestamp; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); @@ -2528,7 +2499,7 @@ public: Field_timestamp_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, share, dec_arg) {} - enum_field_types real_type() const { return MYSQL_TYPE_TIMESTAMP2; } + const Type_handler *type_handler() const { return &type_handler_timestamp2; } enum_field_types binlog_type() const { return MYSQL_TYPE_TIMESTAMP2; } uint32 pack_length() const { @@ -2559,14 +2530,19 @@ public: :Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, 1, 1) {} - enum_field_types type() const { return MYSQL_TYPE_YEAR;} + const Type_handler *type_handler() const { return &type_handler_year; } Copy_func *get_copy_func(const Field *from) const { if (eq_def(from)) return get_identical_copy_func(); switch (from->cmp_type()) { case STRING_RESULT: + { + const Type_handler *handler= from->type_handler(); + if (handler == &type_handler_enum || handler == &type_handler_set) + return do_field_int; return do_field_string; + } case TIME_RESULT: return do_field_temporal; case DECIMAL_RESULT: @@ -2604,7 +2580,7 @@ public: enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg) :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) {} - enum_field_types type() const { return MYSQL_TYPE_DATE;} + const Type_handler *type_handler() const { return &type_handler_date; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) @@ -2640,8 +2616,7 @@ public: :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) {} - enum_field_types type() const { return MYSQL_TYPE_DATE;} - enum_field_types real_type() const { return MYSQL_TYPE_NEWDATE; } + const Type_handler *type_handler() const { return &type_handler_newdate; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; } int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; } double val_real(void); @@ -2679,7 +2654,7 @@ public: :Field_temporal(ptr_arg, length_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg), curdays(0) {} - enum_field_types type() const { return MYSQL_TYPE_TIME;} + const Type_handler *type_handler() const { return &type_handler_time; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; } Copy_func *get_copy_func(const Field *from) const { @@ -2791,7 +2766,7 @@ public: { DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); } - enum_field_types real_type() const { return MYSQL_TYPE_TIME2; } + const Type_handler *type_handler() const { return &type_handler_time2; } enum_field_types binlog_type() const { return MYSQL_TYPE_TIME2; } uint32 pack_length() const { @@ -2833,7 +2808,7 @@ public: unireg_check == TIMESTAMP_DNUN_FIELD) flags|= ON_UPDATE_NOW_FLAG; } - enum_field_types type() const { return MYSQL_TYPE_DATETIME;} + const Type_handler *type_handler() const { return &type_handler_datetime; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; } double val_real(void); longlong val_int(void); @@ -2950,7 +2925,7 @@ public: :Field_datetime_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, dec_arg) {} - enum_field_types real_type() const { return MYSQL_TYPE_DATETIME2; } + const Type_handler *type_handler() const { return &type_handler_datetime2; } enum_field_types binlog_type() const { return MYSQL_TYPE_DATETIME2; } uint32 pack_length() const { @@ -3028,29 +3003,35 @@ class Field_string :public Field_longstr { public: Warn_filter_string(const THD *thd, const Field_string *field); }; + bool is_var_string() const + { + return can_alter_field_type && + orig_table && + (orig_table->s->db_create_options & HA_OPTION_PACK_RECORD) && + field_length >= 4 && + orig_table->s->frm_version < FRM_VER_TRUE_VARCHAR; + } public: bool can_alter_field_type; Field_string(uchar *ptr_arg, uint32 len_arg,uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, - CHARSET_INFO *cs) + const DTCollation &collation) :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, cs), + unireg_check_arg, field_name_arg, collation), can_alter_field_type(1) {}; Field_string(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, - CHARSET_INFO *cs) + const DTCollation &collation) :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, - NONE, field_name_arg, cs), + NONE, field_name_arg, collation), can_alter_field_type(1) {}; - enum_field_types type() const + const Type_handler *type_handler() const { - return ((can_alter_field_type && orig_table && - orig_table->s->db_create_options & HA_OPTION_PACK_RECORD && - field_length >= 4) && - orig_table->s->frm_version < FRM_VER_TRUE_VARCHAR ? - MYSQL_TYPE_VAR_STRING : MYSQL_TYPE_STRING); + if (is_var_string()) + return &type_handler_var_string; + return &type_handler_string; } enum ha_base_keytype key_type() const { return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; } @@ -3092,7 +3073,6 @@ public: uint packed_col_length(const uchar *to, uint length); uint max_packed_col_length(uint max_length); uint size_of() const { return sizeof(*this); } - enum_field_types real_type() const { return MYSQL_TYPE_STRING; } bool has_charset(void) const { return charset() == &my_charset_bin ? FALSE : TRUE; } Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); @@ -3123,24 +3103,24 @@ public: uint32 len_arg, uint length_bytes_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, - TABLE_SHARE *share, CHARSET_INFO *cs) + TABLE_SHARE *share, const DTCollation &collation) :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, cs), + unireg_check_arg, field_name_arg, collation), length_bytes(length_bytes_arg) { share->varchar_fields++; } Field_varstring(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, - TABLE_SHARE *share, CHARSET_INFO *cs) + TABLE_SHARE *share, const DTCollation &collation) :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, - NONE, field_name_arg, cs), + NONE, field_name_arg, collation), length_bytes(len_arg < 256 ? 1 :2) { share->varchar_fields++; } - enum_field_types type() const { return MYSQL_TYPE_VARCHAR; } + const Type_handler *type_handler() const { return &type_handler_varchar; } enum ha_base_keytype key_type() const; uint row_pack_length() const { return field_length; } bool zero_pack() const { return 0; } @@ -3184,7 +3164,6 @@ public: uint max_packed_col_length(uint max_length); uint32 data_length(); uint size_of() const { return sizeof(*this); } - enum_field_types real_type() const { return MYSQL_TYPE_VARCHAR; } bool has_charset(void) const { return charset() == &my_charset_bin ? FALSE : TRUE; } Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); @@ -3224,20 +3203,21 @@ protected: public: Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, - TABLE_SHARE *share, uint blob_pack_length, CHARSET_INFO *cs); + TABLE_SHARE *share, uint blob_pack_length, + const DTCollation &collation); Field_blob(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, - CHARSET_INFO *cs) + const DTCollation &collation) :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, - NONE, field_name_arg, cs), + NONE, field_name_arg, collation), packlength(4) { flags|= BLOB_FLAG; } Field_blob(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, - CHARSET_INFO *cs, bool set_packlength) + const DTCollation &collation, bool set_packlength) :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, - NONE, field_name_arg, cs) + NONE, field_name_arg, collation) { flags|= BLOB_FLAG; packlength= 4; @@ -3252,8 +3232,24 @@ public: :Field_longstr((uchar*) 0, 0, (uchar*) "", 0, NONE, &temp_lex_str, system_charset_info), packlength(packlength_arg) {} + const Type_handler *type_handler() const; /* Note that the default copy constructor is used, in clone() */ - enum_field_types type() const { return MYSQL_TYPE_BLOB;} + enum_field_types type() const + { + /* + We cannot return type_handler()->field_type() here. + Some pieces of the code (e.g. in engines) rely on the fact + that Field::type(), Field::real_type() and Item_field::field_type() + return MYSQL_TYPE_BLOB for all blob variants. + We should eventually fix all such code pieces to expect + all BLOB type codes. + */ + return MYSQL_TYPE_BLOB; + } + enum_field_types real_type() const + { + return MYSQL_TYPE_BLOB; + } enum ha_base_keytype key_type() const { return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; } Copy_func *get_copy_func(const Field *from) const @@ -3438,12 +3434,19 @@ public: :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, share, blob_pack_length, &my_charset_bin) { geom_type= geom_type_arg; srid= field_srid; } - Field_geom(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, - TABLE_SHARE *share, enum geometry_type geom_type_arg) - :Field_blob(len_arg, maybe_null_arg, field_name_arg, &my_charset_bin) - { geom_type= geom_type_arg; srid= 0; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; } - enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; } + const Type_handler *type_handler() const + { + return &type_handler_geometry; + } + enum_field_types type() const + { + return MYSQL_TYPE_GEOMETRY; + } + enum_field_types real_type() const + { + return MYSQL_TYPE_GEOMETRY; + } bool can_optimize_range(const Item_bool_func *cond, const Item *item, bool is_eq_func) const; @@ -3492,20 +3495,15 @@ public: enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, uint packlength_arg, TYPELIB *typelib_arg, - CHARSET_INFO *charset_arg) + const DTCollation &collation) :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, charset_arg), + unireg_check_arg, field_name_arg, collation), packlength(packlength_arg),typelib(typelib_arg) { flags|=ENUM_FLAG; } Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); - enum_field_types type() const { return MYSQL_TYPE_STRING; } - enum Item_result cmp_type () const { return INT_RESULT; } - const Type_handler *cast_to_int_type_handler() const - { - return &type_handler_longlong; - } + const Type_handler *type_handler() const { return &type_handler_enum; } enum ha_base_keytype key_type() const; Copy_func *get_copy_func(const Field *from) const { @@ -3546,7 +3544,6 @@ public: void store_type(ulonglong value); void sql_type(String &str) const; uint size_of() const { return sizeof(*this); } - enum_field_types real_type() const { return MYSQL_TYPE_ENUM; } uint pack_length_from_metadata(uint field_metadata) { return (field_metadata & 0x00ff); } uint row_pack_length() const { return pack_length(); } @@ -3576,6 +3573,9 @@ public: */ return false; } + bool can_optimize_range(const Item_bool_func *cond, + const Item *item, + bool is_eq_func) const; private: int do_save_field_metadata(uchar *first_byte); uint is_equal(Create_field *new_field); @@ -3588,12 +3588,12 @@ public: uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, uint32 packlength_arg, - TYPELIB *typelib_arg, CHARSET_INFO *charset_arg) + TYPELIB *typelib_arg, const DTCollation &collation) :Field_enum(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, packlength_arg, - typelib_arg,charset_arg), - empty_set_string("", 0, charset_arg) + typelib_arg, collation), + empty_set_string("", 0, collation.collation) { flags=(flags & ~ENUM_FLAG) | SET_FLAG; } @@ -3606,7 +3606,7 @@ public: String *val_str(String*,String *); void sql_type(String &str) const; uint size_of() const { return sizeof(*this); } - enum_field_types real_type() const { return MYSQL_TYPE_SET; } + const Type_handler *type_handler() const { return &type_handler_set; } bool has_charset(void) const { return TRUE; } private: const String empty_set_string; @@ -3636,13 +3636,12 @@ public: Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg); - enum_field_types type() const { return MYSQL_TYPE_BIT; } + const Type_handler *type_handler() const { return &type_handler_bit; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; } uint32 key_length() const { return (uint32) (field_length + 7) / 8; } uint32 max_data_length() const { return (field_length + 7) / 8; } uint32 max_display_length() { return field_length; } uint size_of() const { return sizeof(*this); } - Item_result result_type () const { return INT_RESULT; } int reset(void) { bzero(ptr, bytes_in_rec); if (bit_ptr && (bit_len > 0)) // reset odd bits among null bits diff --git a/sql/item.cc b/sql/item.cc index 8e671e80c7e..8274ab30d3c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -518,7 +518,7 @@ Item::Item(THD *thd): tables. */ Item::Item(THD *thd, Item *item): - Type_std_attributes(item), + Type_all_attributes(item), join_tab_idx(item->join_tab_idx), is_expensive_cache(-1), rsize(0), @@ -2348,9 +2348,9 @@ void my_coll_agg_error(Item** args, uint count, const char *fname, } -bool Item_func_or_sum::agg_item_collations(DTCollation &c, const char *fname, - Item **av, uint count, - uint flags, int item_sep) +bool Type_std_attributes::agg_item_collations(DTCollation &c, const char *fname, + Item **av, uint count, + uint flags, int item_sep) { uint i; Item **arg; @@ -2395,10 +2395,10 @@ bool Item_func_or_sum::agg_item_collations(DTCollation &c, const char *fname, } -bool Item_func_or_sum::agg_item_set_converter(const DTCollation &coll, - const char *fname, - Item **args, uint nargs, - uint flags, int item_sep) +bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll, + const char *fname, + Item **args, uint nargs, + uint flags, int item_sep) { Item **arg, *safe_args[2]= {NULL, NULL}; @@ -3780,7 +3780,7 @@ bool Item_param::set_from_item(THD *thd, Item *item) } } struct st_value tmp; - if (!item->store(&tmp, 0)) + if (!item->save_in_value(&tmp)) { unsigned_flag= item->unsigned_flag; switch (item->cmp_type()) { @@ -5834,24 +5834,6 @@ error: } -const Type_handler *Item_field::real_type_handler() const -{ - /* - Item_field::field_type ask Field_type() but sometimes field return - a different type, like for enum/set, so we need to ask real type. - */ - if (field->is_created_from_null_item) - return &type_handler_null; - /* work around about varchar type field detection */ - enum_field_types type= field->real_type(); - // TODO: We should add Field::real_type_handler() eventually - if (type == MYSQL_TYPE_STRING && field->type() == MYSQL_TYPE_VAR_STRING) - type= MYSQL_TYPE_VAR_STRING; - return Type_handler::get_handler_by_real_type(type); - -} - - /* @brief Mark virtual columns as used in a partitioning expression @@ -6216,178 +6198,6 @@ bool Item::eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs) } -/** - Create a field to hold a string value from an item. - - If too_big_for_varchar() create a blob @n - If max_length > 0 create a varchar @n - If max_length == 0 create a CHAR(0) - - @param table Table for which the field is created -*/ - -Field *Item::make_string_field(TABLE *table) -{ - Field *field; - MEM_ROOT *mem_root= table->in_use->mem_root; - DBUG_ASSERT(collation.collation); - /* - Note: the following check is repeated in - subquery_types_allow_materialization(): - */ - if (too_big_for_varchar()) - field= new (mem_root) - Field_blob(max_length, maybe_null, &name, - collation.collation, TRUE); - /* Item_type_holder holds the exact type, do not change it */ - else if (max_length > 0 && - (type() != Item::TYPE_HOLDER || field_type() != MYSQL_TYPE_STRING)) - field= new (mem_root) - Field_varstring(max_length, maybe_null, &name, table->s, - collation.collation); - else - field= new (mem_root) - Field_string(max_length, maybe_null, &name, collation.collation); - if (field) - field->init(table); - return field; -} - - -/** - Create a field based on field_type of argument. - - This is used to create a field for - - IFNULL(x,something) - - time functions - - prepared statement placeholders - - SP variables with data type references: DECLARE a t1.a%TYPE; - - @retval - NULL error - @retval - \# Created field -*/ - -Field *Item::tmp_table_field_from_field_type(TABLE *table, - bool fixed_length, - bool set_blob_packlength) -{ - /* - The field functions defines a field to be not null if null_ptr is not 0 - */ - uchar *null_ptr= maybe_null ? (uchar*) "" : 0; - Field *field; - MEM_ROOT *mem_root= table->in_use->mem_root; - - switch (field_type()) { - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_NEWDECIMAL: - field= Field_new_decimal::create_from_item(mem_root, this); - break; - case MYSQL_TYPE_TINY: - field= new (mem_root) - Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name, 0, unsigned_flag); - break; - case MYSQL_TYPE_SHORT: - field= new (mem_root) - Field_short((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name, 0, unsigned_flag); - break; - case MYSQL_TYPE_LONG: - field= new (mem_root) - Field_long((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name, 0, unsigned_flag); - break; -#ifdef HAVE_LONG_LONG - case MYSQL_TYPE_LONGLONG: - field= new (mem_root) - Field_longlong((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name, 0, unsigned_flag); - break; -#endif - case MYSQL_TYPE_FLOAT: - field= new (mem_root) - Field_float((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name, decimals, 0, unsigned_flag); - break; - case MYSQL_TYPE_DOUBLE: - field= new (mem_root) - Field_double((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name, decimals, 0, unsigned_flag); - break; - case MYSQL_TYPE_INT24: - field= new (mem_root) - Field_medium((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name, 0, unsigned_flag); - break; - case MYSQL_TYPE_NEWDATE: - case MYSQL_TYPE_DATE: - field= new (mem_root) - Field_newdate(0, null_ptr, 0, Field::NONE, &name); - break; - case MYSQL_TYPE_TIME: - field= new_Field_time(mem_root, 0, null_ptr, 0, Field::NONE, &name, - decimals); - break; - case MYSQL_TYPE_TIMESTAMP: - field= new_Field_timestamp(mem_root, 0, null_ptr, 0, - Field::NONE, &name, 0, decimals); - break; - case MYSQL_TYPE_DATETIME: - field= new_Field_datetime(mem_root, 0, null_ptr, 0, Field::NONE, - &name, decimals); - break; - case MYSQL_TYPE_YEAR: - field= new (mem_root) - Field_year((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name); - break; - case MYSQL_TYPE_BIT: - field= new (mem_root) - Field_bit_as_char(NULL, max_length, null_ptr, 0, Field::NONE, - &name); - break; - default: - /* This case should never be chosen */ - DBUG_ASSERT(0); - /* If something goes awfully wrong, it's better to get a string than die */ - case MYSQL_TYPE_NULL: - case MYSQL_TYPE_STRING: - if (fixed_length && !too_big_for_varchar()) - { - field= new (mem_root) - Field_string(max_length, maybe_null, &name, collation.collation); - break; - } - /* Fall through to make_string_field() */ - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_SET: - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_VARCHAR: - return make_string_field(table); - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - field= new (mem_root) - Field_blob(max_length, maybe_null, &name, - collation.collation, set_blob_packlength); - break; // Blob handled outside of case -#ifdef HAVE_SPATIAL - case MYSQL_TYPE_GEOMETRY: - field= new (mem_root) - Field_geom(max_length, maybe_null, &name, table->s, - get_geometry_type()); -#endif /* HAVE_SPATIAL */ - } - if (field) - field->init(table); - return field; -} - - /* ARGSUSED */ void Item_field::make_field(THD *thd, Send_field *tmp_field) { @@ -8945,7 +8755,7 @@ bool Item_default_value::fix_fields(THD *thd, Item **items) real_arg= arg->real_item(); if (real_arg->type() != FIELD_ITEM) { - my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name); + my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name.str); goto error; } @@ -9715,9 +9525,8 @@ Item_cache_temporal::Item_cache_temporal(THD *thd, enum_field_types field_type_arg): Item_cache_int(thd, field_type_arg) { - if (mysql_type_to_time_type(Item_cache_temporal::field_type()) == - MYSQL_TIMESTAMP_ERROR) - set_handler_by_field_type(MYSQL_TYPE_DATETIME); + if (mysql_timestamp_type() == MYSQL_TIMESTAMP_ERROR) + set_handler(&type_handler_datetime2); } @@ -9825,7 +9634,7 @@ bool Item_cache_temporal::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) } unpack_time(value, ltime); - ltime->time_type= mysql_type_to_time_type(field_type()); + ltime->time_type= mysql_timestamp_type(); if (ltime->time_type == MYSQL_TIMESTAMP_TIME) { ltime->hour+= (ltime->month*32+ltime->day)*24; @@ -10267,7 +10076,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item) if (aggregate_for_result(item_type_handler)) { my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), - Item_type_holder::type_handler()->name().ptr(), + Item_type_holder::real_type_handler()->name().ptr(), item_type_handler->name().ptr(), "UNION"); DBUG_RETURN(true); @@ -10375,6 +10184,14 @@ bool Item_type_holder::join_types(THD *thd, Item *item) }; maybe_null|= item->maybe_null; get_full_info(item); + /* + Adjust data type for union, e.g.: + - convert type_handler_null to type_handler_string + - convert type_handler_olddecimal to type_handler_newdecimal + - adjust varchar/blob according to max_length + */ + set_handler(Item_type_holder:: + real_type_handler()->type_handler_for_union(this)); /* Remember decimal integer part to be used in DECIMAL_RESULT handleng */ prev_decimal_int_part= decimal_int_part(); @@ -10385,56 +10202,6 @@ bool Item_type_holder::join_types(THD *thd, Item *item) } -/** - Make temporary table field according collected information about type - of UNION result. - - @param table temporary table for which we create fields - - @return - created field -*/ - -Field *Item_type_holder::make_field_by_type(TABLE *table) -{ - /* - The field functions defines a field to be not null if null_ptr is not 0 - */ - uchar *null_ptr= maybe_null ? (uchar*) "" : 0; - Field *field; - - switch (Item_type_holder::real_type_handler()->real_field_type()) { - case MYSQL_TYPE_ENUM: - { - DBUG_ASSERT(enum_set_typelib); - field= new Field_enum((uchar *) 0, max_length, null_ptr, 0, - Field::NONE, &name, - get_enum_pack_length(enum_set_typelib->count), - enum_set_typelib, collation.collation); - if (field) - field->init(table); - return field; - } - case MYSQL_TYPE_SET: - { - DBUG_ASSERT(enum_set_typelib); - field= new Field_set((uchar *) 0, max_length, null_ptr, 0, - Field::NONE, &name, - get_set_pack_length(enum_set_typelib->count), - enum_set_typelib, collation.collation); - if (field) - field->init(table); - return field; - } - case MYSQL_TYPE_NULL: - return make_string_field(table); - default: - break; - } - return tmp_table_field_from_field_type(table, false, true); -} - - /** Get full information from Item about enum/set fields to be able to create them later. diff --git a/sql/item.h b/sql/item.h index 826f7f3f4fe..acad8d5c89f 100644 --- a/sql/item.h +++ b/sql/item.h @@ -483,7 +483,7 @@ public: class Item: public Value_source, - public Type_std_attributes + public Type_all_attributes { void operator=(Item &); /** @@ -536,10 +536,22 @@ protected: SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param); - virtual Field *make_string_field(TABLE *table); - Field *tmp_table_field_from_field_type(TABLE *table, - bool fixed_length, - bool set_blob_packlength); + /** + Create a field based on field_type of argument. + This is used to create a field for + - IFNULL(x,something) + - time functions + - prepared statement placeholders + - SP variables with data type references: DECLARE a TYPE OF t1.a; + @retval NULL error + @retval !NULL on success + */ + Field *tmp_table_field_from_field_type(TABLE *table) + { + const Type_handler *h= type_handler()->type_handler_for_tmp_table(this); + 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); void push_note_converted_to_negative_complement(THD *thd); @@ -664,54 +676,9 @@ public: */ virtual inline void quick_fix_field() { fixed= 1; } - bool store(struct st_value *value, ulonglong fuzzydate) + bool save_in_value(struct st_value *value) { - switch (cmp_type()) { - case INT_RESULT: - { - value->m_type= unsigned_flag ? DYN_COL_UINT : DYN_COL_INT; - value->value.m_longlong= val_int(); - break; - } - case REAL_RESULT: - { - value->m_type= DYN_COL_DOUBLE; - value->value.m_double= val_real(); - break; - } - case DECIMAL_RESULT: - { - value->m_type= DYN_COL_DECIMAL; - my_decimal *dec= val_decimal(&value->m_decimal); - if (dec != &value->m_decimal && !null_value) - my_decimal2decimal(dec, &value->m_decimal); - break; - } - case STRING_RESULT: - { - value->m_type= DYN_COL_STRING; - String *str= val_str(&value->m_string); - if (str != &value->m_string && !null_value) - value->m_string.set(str->ptr(), str->length(), str->charset()); - break; - } - case TIME_RESULT: - { - value->m_type= DYN_COL_DATETIME; - get_date(&value->value.m_time, fuzzydate); - break; - } - case ROW_RESULT: - DBUG_ASSERT(false); - null_value= true; - break; - } - if (null_value) - { - value->m_type= DYN_COL_NULL; - return true; - } - return false; + return type_handler()->Item_save_in_value(this, value); } /* Function returns 1 on overflow and -1 on fatal errors */ @@ -1150,10 +1117,7 @@ public: */ uint decimal_scale() const { - return decimals < NOT_FIXED_DEC ? decimals : - is_temporal_type_with_time(field_type()) ? - TIME_SECOND_PART_DIGITS : - MY_MIN(max_length, DECIMAL_MAX_SCALE); + return type_handler()->Item_decimal_scale(this); } /* Returns how many digits a divisor adds into a division result. @@ -1174,10 +1138,7 @@ public: */ uint divisor_precision_increment() const { - return decimals < NOT_FIXED_DEC ? decimals : - is_temporal_type_with_time(field_type()) ? - TIME_SECOND_PART_DIGITS : - decimals; + return type_handler()->Item_divisor_precision_increment(this); } /** TIME or DATETIME precision of the item: 0..6 @@ -1745,6 +1706,8 @@ public: } virtual Field::geometry_type get_geometry_type() const { return Field::GEOM_GEOMETRY; }; + uint uint_geometry_type() const + { return get_geometry_type(); } String *check_well_formed_result(String *str, bool send_error= 0); bool eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs); bool too_big_for_varchar() const @@ -2263,7 +2226,7 @@ public: based on result_type(), which is less exact. */ Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table, false, true); } + { return tmp_table_field_from_field_type(table); } }; @@ -2639,19 +2602,29 @@ public: fast_field_copier setup_fast_field_copier(Field *field); table_map used_tables() const; table_map all_used_tables() const; + const Type_handler *type_handler() const + { + const Type_handler *handler= field->type_handler(); + return handler->type_handler_for_item_field(); + } enum Item_result result_type () const { return field->result_type(); } const Type_handler *cast_to_int_type_handler() const { - return field->cast_to_int_type_handler(); + return field->type_handler()->cast_to_int_type_handler(); } enum_field_types field_type() const { return field->type(); } - const Type_handler *real_type_handler() const; + const Type_handler *real_type_handler() const + { + if (field->is_created_from_null_item) + return &type_handler_null; + return field->type_handler(); + } enum_monotonicity_info get_monotonicity_info() const { return MONOTONIC_STRICT_INCREASING; @@ -3187,6 +3160,17 @@ public: enum Type type() const { return INT_ITEM; } enum Item_result result_type () const { return INT_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } + 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; + } + 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; } double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; } my_decimal *val_decimal(my_decimal *); @@ -3645,7 +3629,14 @@ public: Item_partition_func_safe_string(thd, name_arg, safe_strlen(name_arg), &my_charset_bin) { max_length= length; } enum Type type() const { return TYPE_HOLDER; } - enum_field_types field_type() const { return MYSQL_TYPE_BLOB; } + enum_field_types field_type() const + { + return Item_blob::type_handler()->field_type(); + } + const Type_handler *type_handler() const + { + return Type_handler::blob_type_handler(max_length); + } const Type_handler *real_type_handler() const { // Should not be called, Item_blob is used for SHOW purposes only. @@ -3653,7 +3644,7 @@ public: return &type_handler_varchar; } Field *create_field_for_schema(THD *thd, TABLE *table) - { return tmp_table_field_from_field_type(table, false, true); } + { return tmp_table_field_from_field_type(table); } }; @@ -3690,6 +3681,10 @@ public: unsigned_flag=1; } enum_field_types field_type() const { return int_field_type; } + const Type_handler *type_handler() const + { + return Type_handler::get_handler_by_field_type(int_field_type); + } }; @@ -4068,80 +4063,31 @@ class Item_func_or_sum: public Item_result_field, public Item_args, public Used_tables_and_const_cache { - bool agg_item_collations(DTCollation &c, const char *name, - Item **items, uint nitems, - uint flags, int item_sep); - bool agg_item_set_converter(const DTCollation &coll, const char *fname, - Item **args, uint nargs, - uint flags, int item_sep); protected: - /* - Collect arguments' character sets together. - We allow to apply automatic character set conversion in some cases. - The conditions when conversion is possible are: - - arguments A and B have different charsets - - A wins according to coercibility rules - (i.e. a column is stronger than a string constant, - an explicit COLLATE clause is stronger than a column) - - character set of A is either superset for character set of B, - or B is a string constant which can be converted into the - character set of A without data loss. - - If all of the above is true, then it's possible to convert - B into the character set of A, and then compare according - to the collation of A. - - For functions with more than two arguments: - - collect(A,B,C) ::= collect(collect(A,B),C) - - Since this function calls THD::change_item_tree() on the passed Item ** - pointers, it is necessary to pass the original Item **'s, not copies. - Otherwise their values will not be properly restored (see BUG#20769). - If the items are not consecutive (eg. args[2] and args[5]), use the - item_sep argument, ie. - - agg_item_charsets(coll, fname, &args[2], 2, flags, 3) - */ bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems, uint flags, int item_sep) { - if (agg_item_collations(c, func_name(), items, nitems, flags, item_sep)) - return true; - - return agg_item_set_converter(c, func_name(), items, nitems, - flags, item_sep); + return Type_std_attributes::agg_arg_charsets(c, func_name(), + items, nitems, + flags, item_sep); } - /* - Aggregate arguments for string result, e.g: CONCAT(a,b) - - convert to @@character_set_connection if all arguments are numbers - - allow DERIVATION_NONE - */ bool agg_arg_charsets_for_string_result(DTCollation &c, Item **items, uint nitems, int item_sep= 1) { - uint flags= MY_COLL_ALLOW_SUPERSET_CONV | - MY_COLL_ALLOW_COERCIBLE_CONV | - MY_COLL_ALLOW_NUMERIC_CONV; - return agg_arg_charsets(c, items, nitems, flags, item_sep); + return Type_std_attributes:: + agg_arg_charsets_for_string_result(c, func_name(), + items, nitems, item_sep); } - /* - Aggregate arguments for string result, when some comparison - is involved internally, e.g: REPLACE(a,b,c) - - convert to @@character_set_connection if all arguments are numbers - - disallow DERIVATION_NONE - */ bool agg_arg_charsets_for_string_result_with_comparison(DTCollation &c, Item **items, uint nitems, int item_sep= 1) { - uint flags= MY_COLL_ALLOW_SUPERSET_CONV | - MY_COLL_ALLOW_COERCIBLE_CONV | - MY_COLL_ALLOW_NUMERIC_CONV | - MY_COLL_DISALLOW_NONE; - return agg_arg_charsets(c, items, nitems, flags, item_sep); + return Type_std_attributes:: + agg_arg_charsets_for_string_result_with_comparison(c, func_name(), + items, nitems, + item_sep); } /* @@ -4153,13 +4099,10 @@ protected: Item **items, uint nitems, int item_sep= 1) { - uint flags= MY_COLL_ALLOW_SUPERSET_CONV | - MY_COLL_ALLOW_COERCIBLE_CONV | - MY_COLL_DISALLOW_NONE; - return agg_arg_charsets(c, items, nitems, flags, item_sep); + return Type_std_attributes:: + agg_arg_charsets_for_comparison(c, func_name(), items, nitems, item_sep); } - public: // This method is used by Arg_comparator bool agg_arg_charsets_for_comparison(CHARSET_INFO **cs, Item **a, Item **b) @@ -5879,11 +5822,12 @@ public: Item_type_holder(THD*, Item*); const Type_handler *type_handler() const - { return Type_handler_hybrid_field_type::type_handler(); } + { + const Type_handler *handler= Type_handler_hybrid_field_type::type_handler(); + return handler->type_handler_for_item_field(); + } enum_field_types field_type() const { return Type_handler_hybrid_field_type::field_type(); } - enum_field_types real_field_type() const - { return Type_handler_hybrid_field_type::real_field_type(); } enum Item_result result_type () const { /* @@ -5902,16 +5846,22 @@ public: } const Type_handler *real_type_handler() const { - return Item_type_holder::type_handler(); + return Type_handler_hybrid_field_type::type_handler(); } enum Type type() const { return TYPE_HOLDER; } + TYPELIB *get_typelib() const { return enum_set_typelib; } double val_real(); longlong val_int(); my_decimal *val_decimal(my_decimal *); String *val_str(String*); bool join_types(THD *thd, Item *); - Field *make_field_by_type(TABLE *table); + Field *create_tmp_field(bool group, TABLE *table) + { + return Item_type_holder::real_type_handler()-> + make_and_init_table_field(&name, Record_addr(maybe_null), + *this, table); + } Field::geometry_type get_geometry_type() const { return geometry_type; }; Item* get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 6d2135db91e..6712b98dbc3 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2577,7 +2577,7 @@ Item_func_nullif::fix_length_and_dec() thd->change_item_tree(&args[0], m_cache); thd->change_item_tree(&args[2], m_cache); } - set_handler_by_field_type(args[2]->field_type()); + set_handler(args[2]->type_handler()); collation.set(args[2]->collation); decimals= args[2]->decimals; unsigned_flag= args[2]->unsigned_flag; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index a94105b352d..6a6adb28ebd 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1057,7 +1057,7 @@ public: } const char *func_name() const { return "ifnull"; } Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table, false, false); } + { return tmp_table_field_from_field_type(table); } table_map not_null_tables() const { return 0; } uint decimal_precision() const diff --git a/sql/item_func.cc b/sql/item_func.cc index ab2f354f371..03d7c075e1b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -592,99 +592,6 @@ void Item_udf_func::fix_num_length_and_dec() } -/** - Set max_length/decimals of function if function is fixed point and - result length/precision depends on argument ones. -*/ - -void Item_func::count_decimal_length(Item **item, uint nitems) -{ - int max_int_part= 0; - decimals= 0; - unsigned_flag= 1; - for (uint i=0 ; i < nitems ; i++) - { - set_if_bigger(decimals, item[i]->decimals); - set_if_bigger(max_int_part, item[i]->decimal_int_part()); - set_if_smaller(unsigned_flag, item[i]->unsigned_flag); - } - int precision= MY_MIN(max_int_part + decimals, DECIMAL_MAX_PRECISION); - fix_char_length(my_decimal_precision_to_length_no_truncation(precision, - decimals, - unsigned_flag)); -} - - -/** - Set max_length of if it is maximum length of its arguments. -*/ - -void Item_func::count_only_length(Item **item, uint nitems) -{ - uint32 char_length= 0; - unsigned_flag= 0; - for (uint i= 0; i < nitems ; i++) - { - set_if_bigger(char_length, item[i]->max_char_length()); - set_if_bigger(unsigned_flag, item[i]->unsigned_flag); - } - fix_char_length(char_length); -} - - -/** - Set max_length/decimals of function if function is floating point and - result length/precision depends on argument ones. -*/ - -void Item_func::count_real_length(Item **items, uint nitems) -{ - uint32 length= 0; - decimals= 0; - max_length= 0; - unsigned_flag= false; - for (uint i=0 ; i < nitems ; i++) - { - if (decimals < FLOATING_POINT_DECIMALS) - { - set_if_bigger(decimals, items[i]->decimals); - /* Will be ignored if items[i]->decimals >= FLOATING_POINT_DECIMALS */ - set_if_bigger(length, (items[i]->max_length - items[i]->decimals)); - } - set_if_bigger(max_length, items[i]->max_length); - } - if (decimals < FLOATING_POINT_DECIMALS) - { - max_length= length; - length+= decimals; - if (length < max_length) // If previous operation gave overflow - max_length= UINT_MAX32; - else - max_length= length; - } -} - - -/** - Calculate max_length and decimals for string functions. - - @param field_type Field type. - @param items Argument array. - @param nitems Number of arguments. - - @retval False on success, true on error. -*/ -bool Item_func::count_string_length(Item **items, uint nitems) -{ - DBUG_ASSERT(!is_temporal_type(field_type())); - if (agg_arg_charsets_for_string_result(collation, items, nitems, 1)) - return true; - count_only_length(items, nitems); - decimals= max_length ? NOT_FIXED_DEC : 0; - return false; -} - - void Item_func::signal_divide_by_null() { THD *thd= current_thd; @@ -890,7 +797,7 @@ String *Item_func_hybrid_field_type::val_str_from_date_op(String *str) if (date_op_with_null_check(<ime) || (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH))) return (String *) 0; - ltime.time_type= mysql_type_to_time_type(field_type()); + ltime.time_type= mysql_timestamp_type(); str->length(my_TIME_to_str(<ime, const_cast(str->ptr()), decimals)); str->set_charset(&my_charset_bin); DBUG_ASSERT(!null_value); @@ -902,7 +809,7 @@ double Item_func_hybrid_field_type::val_real_from_date_op() MYSQL_TIME ltime; if (date_op_with_null_check(<ime)) return 0; - ltime.time_type= mysql_type_to_time_type(field_type()); + ltime.time_type= mysql_timestamp_type(); return TIME_to_double(<ime); } @@ -911,7 +818,7 @@ longlong Item_func_hybrid_field_type::val_int_from_date_op() MYSQL_TIME ltime; if (date_op_with_null_check(<ime)) return 0; - ltime.time_type= mysql_type_to_time_type(field_type()); + ltime.time_type= mysql_timestamp_type(); return TIME_to_ulonglong(<ime); } @@ -924,7 +831,7 @@ Item_func_hybrid_field_type::val_decimal_from_date_op(my_decimal *dec) my_decimal_set_zero(dec); return 0; } - ltime.time_type= mysql_type_to_time_type(field_type()); + ltime.time_type= mysql_timestamp_type(); return date2my_decimal(<ime, dec); } @@ -2255,8 +2162,8 @@ void Item_func_int_val::fix_length_and_dec_int_or_decimal() { ulonglong tmp_max_length= (ulonglong ) args[0]->max_length - (args[0]->decimals ? args[0]->decimals + 1 : 0) + 2; - max_length= tmp_max_length > (ulonglong) 4294967295U ? - (uint32) 4294967295U : (uint32) tmp_max_length; + max_length= tmp_max_length > (ulonglong) UINT_MAX32 ? + (uint32) UINT_MAX32 : (uint32) tmp_max_length; uint tmp= float_length(decimals); set_if_smaller(max_length,tmp); decimals= 0; diff --git a/sql/item_func.h b/sql/item_func.h index e16b3bd8fa6..33f671c179a 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -42,44 +42,8 @@ protected: uint allowed_arg_cols; String *val_str_from_val_str_ascii(String *str, String *str2); - void count_only_length(Item **item, uint nitems); - void count_real_length(Item **item, uint nitems); - void count_decimal_length(Item **item, uint nitems); - bool count_string_length(Item **item, uint nitems); - uint count_max_decimals(Item **item, uint nitems) - { - uint res= 0; - for (uint i= 0; i < nitems; i++) - set_if_bigger(res, item[i]->decimals); - return res; - } virtual bool check_allowed_arg_cols(uint argno); public: - void aggregate_attributes_int(Item **items, uint nitems) - { - collation.set_numeric(); - count_only_length(items, nitems); - decimals= 0; - } - void aggregate_attributes_real(Item **items, uint nitems) - { - collation.set_numeric(); - count_real_length(items, nitems); - } - void aggregate_attributes_decimal(Item **items, uint nitems) - { - collation.set_numeric(); - count_decimal_length(items, nitems); - } - bool aggregate_attributes_string(Item **item, uint nitems) - { - return count_string_length(item, nitems); - } - void aggregate_attributes_temporal(uint int_part_length, - Item **item, uint nitems) - { - fix_attributes_temporal(int_part_length, count_max_decimals(item, nitems)); - } table_map not_null_tables_cache; @@ -208,7 +172,7 @@ public: { return result_type() != STRING_RESULT ? create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS) : - tmp_table_field_from_field_type(table, false, false); + tmp_table_field_from_field_type(table); } Item *get_tmp_table_item(THD *thd); @@ -2255,12 +2219,6 @@ public: bool update(); bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); - Field *create_field_for_create_select(TABLE *table) - { - return result_type() != STRING_RESULT ? - create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS) : - tmp_table_field_from_field_type(table, false, true); - } table_map used_tables() const { return used_tables_cache | RAND_TABLE_BIT; @@ -2302,6 +2260,14 @@ public: my_decimal *val_decimal(my_decimal*); String *val_str(String* str); void fix_length_and_dec(); + Field *create_field_for_create_select(TABLE *table) + { + return cmp_type() == STRING_RESULT ? + 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); + } virtual void print(String *str, enum_query_type query_type); /* We must always return variables as strings to guard against selects of type @@ -2655,7 +2621,7 @@ public: { return result_type() != STRING_RESULT ? sp_result_field : - tmp_table_field_from_field_type(table, false, false); + tmp_table_field_from_field_type(table); } void make_field(THD *thd, Send_field *tmp_field); diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index e361793f77d..8a61ab583c9 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -40,20 +40,11 @@ #include "opt_range.h" -Field *Item_geometry_func::create_field_for_create_select(TABLE *t_arg) -{ - Field *result; - if ((result= new Field_geom(max_length, maybe_null, &name, t_arg->s, - get_geometry_type()))) - result->init(t_arg); - return result; -} - void Item_geometry_func::fix_length_and_dec() { collation.set(&my_charset_bin); decimals=0; - max_length= (uint32) 4294967295U; + max_length= (uint32) UINT_MAX32; maybe_null= 1; } @@ -206,7 +197,7 @@ String *Item_func_as_wkt::val_str_ascii(String *str) void Item_func_as_wkt::fix_length_and_dec() { collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); - max_length=MAX_BLOB_WIDTH; + max_length= (uint32) UINT_MAX32; maybe_null= 1; } diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index a164f9dec89..b6a49a38743 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -40,7 +40,6 @@ public: Item_geometry_func(THD *thd, List &list): Item_str_func(thd, list) {} void fix_length_and_dec(); enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; } - Field *create_field_for_create_select(TABLE *table); }; class Item_func_geometry_from_text: public Item_geometry_func @@ -101,7 +100,7 @@ public: Item_func_as_wkb(THD *thd, Item *a): Item_geometry_func(thd, a) {} const char *func_name() const { return "st_aswkb"; } String *val_str(String *); - enum_field_types field_type() const { return MYSQL_TYPE_BLOB; } + enum_field_types field_type() const { return MYSQL_TYPE_LONG_BLOB; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } }; diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 58bd6c99f80..6fdee625749 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -1074,7 +1074,7 @@ public: } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); decimals=0; fix_char_length(args[0]->max_length * 2); m_arg0_type_handler= args[0]->type_handler(); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index d95240d6d6d..6d510253259 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1202,51 +1202,15 @@ void Item_sum_hybrid::setup_hybrid(THD *thd, Item *item, Item *value_arg) Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table) { - Field *field; - MEM_ROOT *mem_root; - if (args[0]->type() == Item::FIELD_ITEM) { - field= ((Item_field*) args[0])->field; + Field *field= ((Item_field*) args[0])->field; if ((field= create_tmp_field_from_field(table->in_use, field, &name, table, NULL))) field->flags&= ~NOT_NULL_FLAG; return field; } - - /* - DATE/TIME fields have STRING_RESULT result types. - In order to preserve field type, it's needed to handle DATE/TIME - fields creations separately. - */ - mem_root= table->in_use->mem_root; - switch (args[0]->field_type()) { - case MYSQL_TYPE_DATE: - { - field= new (mem_root) - Field_newdate(0, maybe_null ? (uchar*)"" : 0, 0, Field::NONE, - &name); - break; - } - case MYSQL_TYPE_TIME: - { - field= new_Field_time(mem_root, 0, maybe_null ? (uchar*)"" : 0, 0, - Field::NONE, &name, decimals); - break; - } - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_DATETIME: - { - field= new_Field_datetime(mem_root, 0, maybe_null ? (uchar*)"" : 0, 0, - Field::NONE, &name, decimals); - break; - } - default: - return Item_sum::create_tmp_field(group, table); - } - if (field) - field->init(table); - return field; + return Item_sum::create_tmp_field(group, table); } @@ -1669,8 +1633,6 @@ Item *Item_sum_avg::copy_or_same(THD* thd) Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table) { - Field *field; - MEM_ROOT *mem_root= table->in_use->mem_root; if (group) { @@ -1679,21 +1641,15 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table) The easiest way is to do this is to store both value in a string and unpack on access. */ - field= new (mem_root) + Field *field= new (table->in_use->mem_root) Field_string(((Item_sum_avg::result_type() == DECIMAL_RESULT) ? - dec_bin_size : sizeof(double)) + sizeof(longlong), + dec_bin_size : sizeof(double)) + sizeof(longlong), 0, &name, &my_charset_bin); + if (field) + field->init(table); + return field; } - else if (Item_sum_avg::result_type() == DECIMAL_RESULT) - field= Field_new_decimal::create_from_item(mem_root, this); - else - { - field= new (mem_root) Field_double(max_length, maybe_null, &name, - decimals, TRUE); - } - if (field) - field->init(table); - return field; + return tmp_table_field_from_field_type(table); } @@ -3362,24 +3318,6 @@ void Item_func_group_concat::cleanup() } -Field *Item_func_group_concat::make_string_field(TABLE *table_arg) -{ - Field *field; - DBUG_ASSERT(collation.collation); - - if (too_big_for_varchar()) - field= new Field_blob(max_length, - maybe_null, &name, collation.collation, TRUE); - else - field= new Field_varstring(max_length, - maybe_null, &name, table_arg->s, collation.collation); - - if (field) - field->init(table_arg); - return field; -} - - Item *Item_func_group_concat::copy_or_same(THD* thd) { return new (thd->mem_root) Item_func_group_concat(thd, this); diff --git a/sql/item_sum.h b/sql/item_sum.h index 039ae0de1a8..33ee83f147b 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1636,9 +1636,6 @@ class Item_func_group_concat : public Item_sum friend int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)), void* item_arg); -protected: - virtual Field *make_string_field(TABLE *table); - public: Item_func_group_concat(THD *thd, Name_resolution_context *context_arg, bool is_distinct, List *is_select, diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index d637fa12ad1..a7f131f384b 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1532,7 +1532,7 @@ String *Item_temporal_hybrid_func::val_str_ascii(String *str) /* Check that the returned timestamp type matches to the function type */ DBUG_ASSERT(field_type() == MYSQL_TYPE_STRING || ltime.time_type == MYSQL_TIMESTAMP_NONE || - mysql_type_to_time_type(field_type()) == ltime.time_type); + ltime.time_type == mysql_timestamp_type()); return str; } @@ -3226,7 +3226,7 @@ void Item_func_str_to_date::fix_length_and_dec() } } } - cached_timestamp_type= mysql_type_to_time_type(field_type()); + cached_timestamp_type= mysql_timestamp_type(); } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 5caeea489f6..d52eeba1f15 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -536,7 +536,7 @@ public: my_decimal *val_decimal(my_decimal *decimal_value) { return val_decimal_from_date(decimal_value); } Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table, false, false); } + { return tmp_table_field_from_field_type(table); } int save_in_field(Field *field, bool no_conversions) { return save_date_in_field(field, no_conversions); } }; @@ -1018,7 +1018,7 @@ class Item_extract :public Item_int_func return true; } Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table, false, false); } + { return tmp_table_field_from_field_type(table); } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 881e6de6085..b7b06080121 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -7926,7 +7926,9 @@ Item_func_like::get_mm_leaf(RANGE_OPT_PARAM *param, if (!(res= value->val_str(&tmp))) DBUG_RETURN(&null_element); - if (field->cmp_type() != STRING_RESULT) + if (field->cmp_type() != STRING_RESULT || + field->type_handler() == &type_handler_enum || + field->type_handler() == &type_handler_set) DBUG_RETURN(0); /* @@ -8022,19 +8024,31 @@ Item_bool_func::get_mm_leaf(RANGE_OPT_PARAM *param, goto end; err= value->save_in_field_no_warnings(field, 1); - if (err == 2 && field->cmp_type() == STRING_RESULT) - { - if (type == EQ_FUNC || type == EQUAL_FUNC) - { - tree= new (alloc) SEL_ARG(field, 0, 0); - tree->type= SEL_ARG::IMPOSSIBLE; - } - else - tree= NULL; /* Cannot infer anything */ - goto end; - } if (err > 0) { + if (field->type_handler() == &type_handler_enum || + field->type_handler() == &type_handler_set) + { + if (type == EQ_FUNC || type == EQUAL_FUNC) + { + tree= new (alloc) SEL_ARG(field, 0, 0); + tree->type= SEL_ARG::IMPOSSIBLE; + } + goto end; + } + + if (err == 2 && field->cmp_type() == STRING_RESULT) + { + if (type == EQ_FUNC || type == EQUAL_FUNC) + { + tree= new (alloc) SEL_ARG(field, 0, 0); + tree->type= SEL_ARG::IMPOSSIBLE; + } + else + tree= NULL; /* Cannot infer anything */ + goto end; + } + if (field->cmp_type() != value->result_type()) { if ((type == EQ_FUNC || type == EQUAL_FUNC) && diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index b5808ea9315..b18fb8f2ae5 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -843,34 +843,9 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs) all_are_fields &= (outer->real_item()->type() == Item::FIELD_ITEM && inner->real_item()->type() == Item::FIELD_ITEM); total_key_length += inner->max_length; - if (outer->cmp_type() != inner->cmp_type()) + if (!inner->type_handler()->subquery_type_allows_materialization(inner, + outer)) DBUG_RETURN(FALSE); - switch (outer->cmp_type()) { - case STRING_RESULT: - if (!(outer->collation.collation == inner->collation.collation)) - DBUG_RETURN(FALSE); - // Materialization does not work with BLOB columns - if (inner->field_type() == MYSQL_TYPE_BLOB || - inner->field_type() == MYSQL_TYPE_GEOMETRY) - DBUG_RETURN(FALSE); - /* - Materialization also is unable to work when create_tmp_table() will - create a blob column because item->max_length is too big. - The following check is copied from Item::make_string_field(): - */ - if (inner->too_big_for_varchar()) - { - DBUG_RETURN(FALSE); - } - break; - case TIME_RESULT: - if (mysql_type_to_time_type(outer->field_type()) != - mysql_type_to_time_type(inner->field_type())) - DBUG_RETURN(FALSE); - default: - /* suitable for materialization */ - break; - } } /* diff --git a/sql/partition_info.cc b/sql/partition_info.cc index ab4a1cc0360..322fc4e1e93 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1922,7 +1922,7 @@ void partition_info::report_part_expr_error(bool use_subpart_expr) !(type == HASH_PARTITION && list_of_fields)) { my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0), - item_field->name); + item_field->name.str); DBUG_VOID_RETURN; } } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f61e1f0885e..b586cd138de 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2352,6 +2352,26 @@ bool THD::convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) } +Item_string *THD::make_string_literal(const char *str, size_t length, + uint repertoire) +{ + if (!charset_is_collation_connection && + (repertoire != MY_REPERTOIRE_ASCII || + !my_charset_is_ascii_based(variables.collation_connection))) + { + LEX_STRING to; + if (convert_string(&to, variables.collation_connection, + str, length, variables.character_set_client)) + return NULL; + str= to.str; + length= to.length; + } + return new (mem_root) Item_string(this, str, length, + variables.collation_connection, + DERIVATION_COERCIBLE, repertoire); +} + + /* Update some cache variables when character set changes */ @@ -3114,7 +3134,7 @@ int select_export::send_data(List &items) ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, ER_THD(thd, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), "string", printable_buff, - item->name, static_cast(row_count)); + item->name.str, static_cast(row_count)); } else if (copier.source_end_pos() < res->ptr() + res->length()) { diff --git a/sql/sql_class.h b/sql/sql_class.h index f8be4a61513..6d84905515b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3427,6 +3427,20 @@ public: bool convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs); + /* + Create a string literal with optional client->connection conversion. + @param str - the string in the client character set + @param length - length of the string + @param repertoire - the repertoire of the string + */ + Item_string *make_string_literal(const char *str, size_t length, + uint repertoire); + Item_string *make_string_literal(const Lex_string_with_metadata_st &str) + { + uint repertoire= str.repertoire(variables.character_set_client); + return make_string_literal(str.str, str.length, repertoire); + } + void add_changed_table(TABLE *table); void add_changed_table(const char *key, long key_length); CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 5ffb9d4cb79..e763f8938ee 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -749,6 +749,9 @@ public: /* UNION methods */ bool prepare(THD *thd, select_result *result, ulong additional_options); + bool prepare_join(THD *thd, SELECT_LEX *sl, select_result *result, + ulong additional_options, + bool is_union_select); bool optimize(); bool exec(); bool exec_recursive(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 18cdaf58019..2239c917cd5 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15880,22 +15880,9 @@ Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length) break; } case TIME_RESULT: - new_field= tmp_table_field_from_field_type(table, true, false); - break; - case STRING_RESULT: - DBUG_ASSERT(collation.collation); - /* - GEOMETRY fields have STRING_RESULT result type. - To preserve type they needed to be handled separately. - */ - if (field_type() == MYSQL_TYPE_GEOMETRY) - new_field= tmp_table_field_from_field_type(table, true, false); - else - new_field= make_string_field(table); - new_field->set_derivation(collation.derivation, collation.repertoire); - break; case DECIMAL_RESULT: - new_field= Field_new_decimal::create_from_item(mem_root, this); + case STRING_RESULT: + new_field= tmp_table_field_from_field_type(table); break; case ROW_RESULT: // This case should never be choosen @@ -15981,7 +15968,7 @@ Field *Item::create_field_for_schema(THD *thd, TABLE *table) field->init(table); return field; } - return tmp_table_field_from_field_type(table, false, false); + return tmp_table_field_from_field_type(table); } @@ -16032,6 +16019,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, } switch (type) { + case Item::TYPE_HOLDER: case Item::SUM_FUNC_ITEM: { result= item->create_tmp_field(group, table); @@ -16161,11 +16149,6 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, return create_tmp_field_from_item(thd, item, table, (make_copy_field ? 0 : copy_func), modify_item); - case Item::TYPE_HOLDER: - result= ((Item_type_holder *)item)->make_field_by_type(table); - result->set_derivation(item->collation.derivation, - item->collation.repertoire); - return result; default: // Dosen't have to be stored return 0; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 2f4993f0437..1fbd631b754 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5439,7 +5439,7 @@ static void store_column_type(TABLE *table, Field *field, CHARSET_INFO *cs, field->real_type() == MYSQL_TYPE_STRING) // For binary type { uint32 octet_max_length= field->max_display_length(); - if (is_blob && octet_max_length != (uint32) 4294967295U) + if (is_blob && octet_max_length != (uint32) UINT_MAX32) octet_max_length /= field->charset()->mbmaxlen; longlong char_max_len= is_blob ? (longlong) octet_max_length / field->charset()->mbminlen : diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 12f60cc03f0..f4659a69fc3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7368,7 +7368,7 @@ blob_length_by_type(enum_field_types type) case MYSQL_TYPE_MEDIUM_BLOB: return 16777215; case MYSQL_TYPE_LONG_BLOB: - return 4294967295U; + return (uint) UINT_MAX32; default: DBUG_ASSERT(0); // we should never go here return 0; diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 43c27372546..23cfe20e5e6 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -21,39 +21,44 @@ #include "item.h" #include "log.h" -static Type_handler_tiny type_handler_tiny; -static Type_handler_short type_handler_short; -static Type_handler_long type_handler_long; -static Type_handler_int24 type_handler_int24; -static Type_handler_year type_handler_year; -static Type_handler_time type_handler_time; -static Type_handler_date type_handler_date; -static Type_handler_timestamp type_handler_timestamp; -static Type_handler_timestamp2 type_handler_timestamp2; -static Type_handler_olddecimal type_handler_olddecimal; -static Type_handler_tiny_blob type_handler_tiny_blob; -static Type_handler_medium_blob type_handler_medium_blob; -static Type_handler_long_blob type_handler_long_blob; -static Type_handler_blob type_handler_blob; - +Type_handler_row type_handler_row; Type_handler_null type_handler_null; -Type_handler_row type_handler_row; -Type_handler_string type_handler_string; -Type_handler_varchar type_handler_varchar; + +Type_handler_tiny type_handler_tiny; +Type_handler_short type_handler_short; +Type_handler_long type_handler_long; +Type_handler_int24 type_handler_int24; Type_handler_longlong type_handler_longlong; Type_handler_float type_handler_float; Type_handler_double type_handler_double; -Type_handler_newdecimal type_handler_newdecimal; -Type_handler_datetime type_handler_datetime; Type_handler_bit type_handler_bit; -Type_handler_enum type_handler_enum; -Type_handler_set type_handler_set; +Type_handler_olddecimal type_handler_olddecimal; +Type_handler_newdecimal type_handler_newdecimal; + +Type_handler_year type_handler_year; +Type_handler_time type_handler_time; +Type_handler_date type_handler_date; +Type_handler_timestamp type_handler_timestamp; +Type_handler_timestamp2 type_handler_timestamp2; +Type_handler_datetime type_handler_datetime; Type_handler_time2 type_handler_time2; Type_handler_newdate type_handler_newdate; Type_handler_datetime2 type_handler_datetime2; +Type_handler_enum type_handler_enum; +Type_handler_set type_handler_set; + +Type_handler_string type_handler_string; +Type_handler_var_string type_handler_var_string; +Type_handler_varchar type_handler_varchar; + +Type_handler_tiny_blob type_handler_tiny_blob; +Type_handler_medium_blob type_handler_medium_blob; +Type_handler_long_blob type_handler_long_blob; +Type_handler_blob type_handler_blob; + #ifdef HAVE_SPATIAL Type_handler_geometry type_handler_geometry; #endif @@ -80,9 +85,18 @@ bool Type_handler_data::init() m_type_aggregator_for_result.add(&type_handler_geometry, &type_handler_geometry, &type_handler_geometry) || + m_type_aggregator_for_result.add(&type_handler_geometry, + &type_handler_tiny_blob, + &type_handler_long_blob) || m_type_aggregator_for_result.add(&type_handler_geometry, &type_handler_blob, &type_handler_long_blob) || + m_type_aggregator_for_result.add(&type_handler_geometry, + &type_handler_medium_blob, + &type_handler_long_blob) || + m_type_aggregator_for_result.add(&type_handler_geometry, + &type_handler_long_blob, + &type_handler_long_blob) || m_type_aggregator_for_result.add(&type_handler_geometry, &type_handler_varchar, &type_handler_long_blob) || @@ -115,6 +129,126 @@ void Type_std_attributes::set(const Field *field) } +uint Type_std_attributes::count_max_decimals(Item **item, uint nitems) +{ + uint res= 0; + for (uint i= 0; i < nitems; i++) + set_if_bigger(res, item[i]->decimals); + return res; +} + + +/** + Set max_length/decimals of function if function is fixed point and + result length/precision depends on argument ones. +*/ + +void Type_std_attributes::count_decimal_length(Item **item, uint nitems) +{ + int max_int_part= 0; + decimals= 0; + unsigned_flag= 1; + for (uint i=0 ; i < nitems ; i++) + { + set_if_bigger(decimals, item[i]->decimals); + set_if_bigger(max_int_part, item[i]->decimal_int_part()); + set_if_smaller(unsigned_flag, item[i]->unsigned_flag); + } + int precision= MY_MIN(max_int_part + decimals, DECIMAL_MAX_PRECISION); + fix_char_length(my_decimal_precision_to_length_no_truncation(precision, + decimals, + unsigned_flag)); +} + + +/** + Set max_length of if it is maximum length of its arguments. +*/ + +void Type_std_attributes::count_only_length(Item **item, uint nitems) +{ + uint32 char_length= 0; + unsigned_flag= 0; + for (uint i= 0; i < nitems ; i++) + { + set_if_bigger(char_length, item[i]->max_char_length()); + set_if_bigger(unsigned_flag, item[i]->unsigned_flag); + } + fix_char_length(char_length); +} + + +void Type_std_attributes::count_octet_length(Item **item, uint nitems) +{ + max_length= 0; + unsigned_flag= 0; + for (uint i= 0; i < nitems ; i++) + { + set_if_bigger(max_length, item[i]->max_length); + set_if_bigger(unsigned_flag, item[i]->unsigned_flag); + } +} + + +/** + Set max_length/decimals of function if function is floating point and + result length/precision depends on argument ones. +*/ + +void Type_std_attributes::count_real_length(Item **items, uint nitems) +{ + uint32 length= 0; + decimals= 0; + max_length= 0; + unsigned_flag= false; + for (uint i=0 ; i < nitems ; i++) + { + if (decimals < FLOATING_POINT_DECIMALS) + { + set_if_bigger(decimals, items[i]->decimals); + /* Will be ignored if items[i]->decimals >= FLOATING_POINT_DECIMALS */ + set_if_bigger(length, (items[i]->max_length - items[i]->decimals)); + } + set_if_bigger(max_length, items[i]->max_length); + } + if (decimals < FLOATING_POINT_DECIMALS) + { + max_length= length; + length+= decimals; + if (length < max_length) // If previous operation gave overflow + max_length= UINT_MAX32; + else + max_length= length; + } + // Corner case: COALESCE(DOUBLE(255,4), DOUBLE(255,3)) -> FLOAT(255, 4) + set_if_smaller(max_length, MAX_FIELD_CHARLENGTH); +} + + +/** + Calculate max_length and decimals for string functions. + + @param field_type Field type. + @param items Argument array. + @param nitems Number of arguments. + + @retval False on success, true on error. +*/ +bool Type_std_attributes::count_string_length(const char *func_name, + Item **items, uint nitems) +{ + if (agg_arg_charsets_for_string_result(collation, func_name, + items, nitems, 1)) + return true; + if (collation.collation == &my_charset_bin) + count_octet_length(items, nitems); + else + count_only_length(items, nitems); + decimals= max_length ? NOT_FIXED_DEC : 0; + return false; +} + + /** This method is used by: - Item_user_var_as_out_param::field_type() @@ -140,6 +274,36 @@ Type_handler::string_type_handler(uint max_octet_length) } +const Type_handler * +Type_handler::varstring_type_handler(const Item *item) +{ + if (!item->max_length) + return &type_handler_string; + if (item->too_big_for_varchar()) + return blob_type_handler(item->max_length); + return &type_handler_varchar; +} + + +const Type_handler * +Type_handler::blob_type_handler(uint max_octet_length) +{ + if (max_octet_length <= 255) + return &type_handler_tiny_blob; + if (max_octet_length <= 65535) + return &type_handler_blob; + if (max_octet_length <= 16777215) + return &type_handler_medium_blob; + return &type_handler_long_blob; +} + + +const Type_handler * +Type_handler::blob_type_handler(const Item *item) +{ + return blob_type_handler(item->max_length); +} + /** This method is used by: - Item_sum_hybrid, e.g. MAX(item), MIN(item). @@ -222,6 +386,7 @@ const Name Type_handler_null::m_name_null(C_STRING_WITH_LEN("null")); const Name Type_handler_string::m_name_char(C_STRING_WITH_LEN("char")), + Type_handler_var_string::m_name_var_string(C_STRING_WITH_LEN("varchar")), Type_handler_varchar::m_name_varchar(C_STRING_WITH_LEN("varchar")), Type_handler_tiny_blob::m_name_tinyblob(C_STRING_WITH_LEN("tinyblob")), Type_handler_medium_blob::m_name_mediumblob(C_STRING_WITH_LEN("mediumblob")), @@ -303,6 +468,30 @@ const Type_handler *Type_handler_row::type_handler_for_comparison() const return &type_handler_row; } +/***************************************************************************/ + +const Type_handler *Type_handler_enum::type_handler_for_item_field() const +{ + return &type_handler_string; +} + + +const Type_handler *Type_handler_enum::cast_to_int_type_handler() const +{ + return &type_handler_longlong; +} + + +const Type_handler *Type_handler_set::type_handler_for_item_field() const +{ + return &type_handler_string; +} + + +const Type_handler *Type_handler_set::cast_to_int_type_handler() const +{ + return &type_handler_longlong; +} /***************************************************************************/ @@ -1152,6 +1341,446 @@ Field *Type_handler_set::make_conversion_table_field(TABLE *table, ((const Field_enum*) target)->typelib, target->charset()); } +/*************************************************************************/ +Field *Type_handler::make_and_init_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + Field *field= make_table_field(name, addr, attr, table); + if (field) + field->init(table); + return field; +} + + +Field *Type_handler_tiny::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_tiny(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); +} + + +Field *Type_handler_short::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_short(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); +} + + +Field *Type_handler_int24::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_medium(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, + 0/*zerofill*/, attr.unsigned_flag); +} + + +Field *Type_handler_long::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_long(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); +} + + +Field *Type_handler_longlong::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_longlong(addr.ptr, attr.max_length, + addr.null_ptr, addr.null_bit, + Field::NONE, name, + 0/*zerofill*/, attr.unsigned_flag); +} + + +Field *Type_handler_float::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_float(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, + attr.decimals, 0/*zerofill*/, attr.unsigned_flag); +} + + +Field *Type_handler_double::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_double(addr.ptr, attr.max_length, + addr.null_ptr, addr.null_bit, + Field::NONE, name, + attr.decimals, 0/*zerofill*/, attr.unsigned_flag); +} + + +Field * +Type_handler_olddecimal::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + /* + Currently make_table_field() is used for Item purpose only. + On Item level we have type_handler_newdecimal only. + For now we have DBUG_ASSERT(0). + It will be removed when we reuse Type_handler::make_table_field() + in make_field() in field.cc, to open old tables with old decimal. + */ + DBUG_ASSERT(0); + return new (table->in_use->mem_root) + Field_decimal(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, attr.decimals, + 0/*zerofill*/,attr.unsigned_flag); +} + + +Field * +Type_handler_newdecimal::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + uint8 dec= attr.decimals; + uint8 intg= attr.decimal_precision() - dec; + uint32 len= attr.max_char_length(); + + /* + Trying to put too many digits overall in a DECIMAL(prec,dec) + will always throw a warning. We must limit dec to + DECIMAL_MAX_SCALE however to prevent an assert() later. + */ + + if (dec > 0) + { + signed int overflow; + + dec= MY_MIN(dec, DECIMAL_MAX_SCALE); + + /* + If the value still overflows the field with the corrected dec, + we'll throw out decimals rather than integers. This is still + bad and of course throws a truncation warning. + +1: for decimal point + */ + + const int required_length= + my_decimal_precision_to_length(intg + dec, dec, attr.unsigned_flag); + + overflow= required_length - len; + + if (overflow > 0) + dec= MY_MAX(0, dec - overflow); // too long, discard fract + else + /* Corrected value fits. */ + len= required_length; + } + return new (table->in_use->mem_root) + Field_new_decimal(addr.ptr, len, addr.null_ptr, addr.null_bit, + Field::NONE, name, + dec, 0/*zerofill*/, attr.unsigned_flag); +} + + +Field *Type_handler_year::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_year(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name); +} + + +Field *Type_handler_null::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_null(addr.ptr, attr.max_length, + Field::NONE, name, attr.collation.collation); +} + + +Field *Type_handler_timestamp::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new_Field_timestamp(table->in_use->mem_root, + addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, table->s, attr.decimals); +} + + +Field *Type_handler_timestamp2::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + /* + Will be changed to "new Field_timestampf" when we reuse + make_table_field() for make_field() purposes in field.cc. + */ + return new_Field_timestamp(table->in_use->mem_root, + addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, table->s, attr.decimals); +} + + +Field *Type_handler_newdate::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_newdate(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name); +} + + +Field *Type_handler_date::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + /* + DBUG_ASSERT will be removed when we reuse make_table_field() + for make_field() in field.cc + */ + DBUG_ASSERT(0); + return new (table->in_use->mem_root) + Field_date(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name); +} + + +Field *Type_handler_time::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new_Field_time(table->in_use->mem_root, + addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, attr.decimals); +} + + +Field *Type_handler_time2::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + + +{ + /* + Will be changed to "new Field_timef" when we reuse + make_table_field() for make_field() purposes in field.cc. + */ + return new_Field_time(table->in_use->mem_root, + addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, attr.decimals); +} + + +Field *Type_handler_datetime::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new_Field_datetime(table->in_use->mem_root, + addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, attr.decimals); +} + + +Field *Type_handler_datetime2::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + /* + Will be changed to "new Field_datetimef" when we reuse + make_table_field() for make_field() purposes in field.cc. + */ + return new_Field_datetime(table->in_use->mem_root, + addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, attr.decimals); +} + + +Field *Type_handler_bit::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_bit_as_char(addr.ptr, attr.max_length, + addr.null_ptr, addr.null_bit, + Field::NONE, name); +} + + +Field *Type_handler_string::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_string(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, attr.collation); +} + + +Field *Type_handler_varchar::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_varstring(addr.ptr, attr.max_length, + HA_VARCHAR_PACKLENGTH(attr.max_length), + addr.null_ptr, addr.null_bit, + Field::NONE, name, + table->s, attr.collation); +} + + +Field *Type_handler_tiny_blob::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, table->s, + 1, attr.collation); +} + + +Field *Type_handler_blob::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, table->s, + 2, attr.collation); +} + + +Field * +Type_handler_medium_blob::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, table->s, + 3, attr.collation); +} + + +Field *Type_handler_long_blob::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, table->s, + 4, attr.collation); +} + + + +#ifdef HAVE_SPATIAL +Field *Type_handler_geometry::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_geom(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, table->s, 4, + (Field::geometry_type) attr.uint_geometry_type(), + 0); +} +#endif + + +Field *Type_handler_enum::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + TYPELIB *typelib= attr.get_typelib(); + DBUG_ASSERT(typelib); + return new (table->in_use->mem_root) + Field_enum(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, + get_enum_pack_length(typelib->count), typelib, + attr.collation); +} + + +Field *Type_handler_set::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + TYPELIB *typelib= attr.get_typelib(); + DBUG_ASSERT(typelib); + return new (table->in_use->mem_root) + Field_set(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, + get_enum_pack_length(typelib->count), typelib, + attr.collation); +} + /*************************************************************************/ uint32 Type_handler_decimal_result::max_display_length(const Item *item) const @@ -1436,7 +2065,18 @@ bool Type_handler_string_result:: Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item **items, uint nitems) const { - return func->aggregate_attributes_string(items, nitems); + return func->aggregate_attributes_string(func->func_name(), items, nitems); +} + + +bool Type_handler_blob_common:: + Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const +{ + if (func->aggregate_attributes_string(func->func_name(), items, nitems)) + return true; + func->set_handler(blob_type_handler(func->max_length)); + return false; } @@ -3187,3 +3827,204 @@ uint Type_handler_string_result::Item_temporal_precision(Item *item, } /***************************************************************************/ + +uint Type_handler::Item_decimal_scale(const Item *item) const +{ + return item->decimals < NOT_FIXED_DEC ? + item->decimals : + MY_MIN(item->max_length, DECIMAL_MAX_SCALE); +} + +uint Type_handler_temporal_result:: + Item_decimal_scale_with_seconds(const Item *item) const +{ + return item->decimals < NOT_FIXED_DEC ? + item->decimals : + TIME_SECOND_PART_DIGITS; +} + +uint Type_handler::Item_divisor_precision_increment(const Item *item) const +{ + return item->decimals; +} + +uint Type_handler_temporal_result:: + Item_divisor_precision_increment_with_seconds(const Item *item) const +{ + return item->decimals < NOT_FIXED_DEC ? + item->decimals : + TIME_SECOND_PART_DIGITS; +} + +/***************************************************************************/ + +bool Type_handler_real_result:: + subquery_type_allows_materialization(const Item *inner, + const Item *outer) const +{ + DBUG_ASSERT(inner->cmp_type() == REAL_RESULT); + return outer->cmp_type() == REAL_RESULT; +} + + +bool Type_handler_int_result:: + subquery_type_allows_materialization(const Item *inner, + const Item *outer) const +{ + DBUG_ASSERT(inner->cmp_type() == INT_RESULT); + return outer->cmp_type() == INT_RESULT; +} + + +bool Type_handler_decimal_result:: + subquery_type_allows_materialization(const Item *inner, + const Item *outer) const +{ + DBUG_ASSERT(inner->cmp_type() == DECIMAL_RESULT); + return outer->cmp_type() == DECIMAL_RESULT; +} + + +bool Type_handler_string_result:: + subquery_type_allows_materialization(const Item *inner, + const Item *outer) const +{ + DBUG_ASSERT(inner->cmp_type() == STRING_RESULT); + return outer->cmp_type() == STRING_RESULT && + outer->collation.collation == inner->collation.collation && + /* + Materialization also is unable to work when create_tmp_table() will + create a blob column because item->max_length is too big. + The following test is copied from varstring_type_handler(). + */ + !inner->too_big_for_varchar(); +} + + +bool Type_handler_temporal_result:: + subquery_type_allows_materialization(const Item *inner, + const Item *outer) const +{ + DBUG_ASSERT(inner->cmp_type() == TIME_RESULT); + return mysql_timestamp_type() == + outer->type_handler()->mysql_timestamp_type(); +} + +/***************************************************************************/ + + +const Type_handler * +Type_handler_null::type_handler_for_tmp_table(const Item *item) const +{ + return &type_handler_string; +} + + +const Type_handler * +Type_handler_null::type_handler_for_union(const Item *item) const +{ + return &type_handler_string; +} + + +const Type_handler * +Type_handler_olddecimal::type_handler_for_tmp_table(const Item *item) const +{ + return &type_handler_newdecimal; +} + +const Type_handler * +Type_handler_olddecimal::type_handler_for_union(const Item *item) const +{ + return &type_handler_newdecimal; +} + + +/***************************************************************************/ + +bool Type_handler::check_null(const Item *item, st_value *value) const +{ + if (item->null_value) + { + value->m_type= DYN_COL_NULL; + return true; + } + return false; +} + + +bool Type_handler_null:: + Item_save_in_value(Item *item, st_value *value) const +{ + value->m_type= DYN_COL_NULL; + return true; +} + + +bool Type_handler_row:: + Item_save_in_value(Item *item, st_value *value) const +{ + DBUG_ASSERT(0); + value->m_type= DYN_COL_NULL; + return true; +} + + +bool Type_handler_int_result:: + Item_save_in_value(Item *item, st_value *value) const +{ + value->m_type= item->unsigned_flag ? DYN_COL_UINT : DYN_COL_INT; + value->value.m_longlong= item->val_int(); + return check_null(item, value); +} + + +bool Type_handler_real_result:: + Item_save_in_value(Item *item, st_value *value) const +{ + value->m_type= DYN_COL_DOUBLE; + value->value.m_double= item->val_real(); + return check_null(item, value); +} + + +bool Type_handler_decimal_result:: + Item_save_in_value(Item *item, st_value *value) const +{ + value->m_type= DYN_COL_DECIMAL; + my_decimal *dec= item->val_decimal(&value->m_decimal); + if (dec != &value->m_decimal && !item->null_value) + my_decimal2decimal(dec, &value->m_decimal); + return check_null(item, value); +} + + +bool Type_handler_string_result:: + Item_save_in_value(Item *item, st_value *value) const +{ + value->m_type= DYN_COL_STRING; + String *str= item->val_str(&value->m_string); + if (str != &value->m_string && !item->null_value) + value->m_string.set(str->ptr(), str->length(), str->charset()); + return check_null(item, value); +} + + +bool Type_handler_temporal_with_date:: + Item_save_in_value(Item *item, st_value *value) const +{ + value->m_type= DYN_COL_DATETIME; + item->get_date(&value->value.m_time, sql_mode_for_dates(current_thd)); + return check_null(item, value); +} + + +bool Type_handler_time_common:: + Item_save_in_value(Item *item, st_value *value) const +{ + value->m_type= DYN_COL_DATETIME; + item->get_time(&value->value.m_time); + return check_null(item, value); +} + +/***************************************************************************/ diff --git a/sql/sql_type.h b/sql/sql_type.h index 21b8e75db11..c61142d0a7b 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -60,9 +60,9 @@ class Item_func_div; class Item_func_mod; class cmp_item; class in_vector; -class Type_std_attributes; class Sort_param; class Arg_comparator; +struct st_value; struct TABLE; struct SORT_FIELD_ATTR; @@ -130,6 +130,21 @@ public: derivation= DERIVATION_NONE; repertoire= MY_REPERTOIRE_UNICODE30; } + DTCollation(CHARSET_INFO *collation_arg) + { + /* + This constructor version is used in combination with Field constructors, + to pass "CHARSET_INFO" instead of the full DTCollation. + Therefore, derivation is set to DERIVATION_IMPLICIT, which is the + proper derivation for table fields. + We should eventually remove all code pieces that pass "CHARSET_INFO" + (e.g. in storage engine sources) and fix to pass the full DTCollation + instead. Then, this constructor can be removed. + */ + collation= collation_arg; + derivation= DERIVATION_IMPLICIT; + repertoire= my_charset_repertoire(collation_arg); + } DTCollation(CHARSET_INFO *collation_arg, Derivation derivation_arg) { collation= collation_arg; @@ -311,6 +326,155 @@ public: { fix_attributes_temporal(MAX_DATETIME_WIDTH, dec); } + + void count_only_length(Item **item, uint nitems); + void count_octet_length(Item **item, uint nitems); + void count_real_length(Item **item, uint nitems); + void count_decimal_length(Item **item, uint nitems); + bool count_string_length(const char *func_name, Item **item, uint nitems); + uint count_max_decimals(Item **item, uint nitems); + + void aggregate_attributes_int(Item **items, uint nitems) + { + collation.set_numeric(); + count_only_length(items, nitems); + decimals= 0; + } + void aggregate_attributes_real(Item **items, uint nitems) + { + collation.set_numeric(); + count_real_length(items, nitems); + } + void aggregate_attributes_decimal(Item **items, uint nitems) + { + collation.set_numeric(); + count_decimal_length(items, nitems); + } + bool aggregate_attributes_string(const char *func_name, + Item **item, uint nitems) + { + return count_string_length(func_name, item, nitems); + } + void aggregate_attributes_temporal(uint int_part_length, + Item **item, uint nitems) + { + fix_attributes_temporal(int_part_length, count_max_decimals(item, nitems)); + } + + bool agg_item_collations(DTCollation &c, const char *name, + Item **items, uint nitems, + uint flags, int item_sep); + bool agg_item_set_converter(const DTCollation &coll, const char *fname, + Item **args, uint nargs, + uint flags, int item_sep); + + /* + Collect arguments' character sets together. + We allow to apply automatic character set conversion in some cases. + The conditions when conversion is possible are: + - arguments A and B have different charsets + - A wins according to coercibility rules + (i.e. a column is stronger than a string constant, + an explicit COLLATE clause is stronger than a column) + - character set of A is either superset for character set of B, + or B is a string constant which can be converted into the + character set of A without data loss. + + If all of the above is true, then it's possible to convert + B into the character set of A, and then compare according + to the collation of A. + + For functions with more than two arguments: + + collect(A,B,C) ::= collect(collect(A,B),C) + + Since this function calls THD::change_item_tree() on the passed Item ** + pointers, it is necessary to pass the original Item **'s, not copies. + Otherwise their values will not be properly restored (see BUG#20769). + If the items are not consecutive (eg. args[2] and args[5]), use the + item_sep argument, ie. + + agg_item_charsets(coll, fname, &args[2], 2, flags, 3) + */ + bool agg_arg_charsets(DTCollation &c, const char *func_name, + Item **items, uint nitems, + uint flags, int item_sep) + { + if (agg_item_collations(c, func_name, items, nitems, flags, item_sep)) + return true; + return agg_item_set_converter(c, func_name, items, nitems, flags, item_sep); + } + /* + Aggregate arguments for string result, e.g: CONCAT(a,b) + - convert to @@character_set_connection if all arguments are numbers + - allow DERIVATION_NONE + */ + bool agg_arg_charsets_for_string_result(DTCollation &c, const char *func_name, + Item **items, uint nitems, + int item_sep) + { + uint flags= MY_COLL_ALLOW_SUPERSET_CONV | + MY_COLL_ALLOW_COERCIBLE_CONV | + MY_COLL_ALLOW_NUMERIC_CONV; + return agg_arg_charsets(c, func_name, items, nitems, flags, item_sep); + } + /* + Aggregate arguments for string result, when some comparison + is involved internally, e.g: REPLACE(a,b,c) + - convert to @@character_set_connection if all arguments are numbers + - disallow DERIVATION_NONE + */ + bool agg_arg_charsets_for_string_result_with_comparison(DTCollation &c, + const char *func_name, + Item **items, + uint nitems, + int item_sep) + { + uint flags= MY_COLL_ALLOW_SUPERSET_CONV | + MY_COLL_ALLOW_COERCIBLE_CONV | + MY_COLL_ALLOW_NUMERIC_CONV | + MY_COLL_DISALLOW_NONE; + return agg_arg_charsets(c, func_name, items, nitems, flags, item_sep); + } + + /* + Aggregate arguments for comparison, e.g: a=b, a LIKE b, a RLIKE b + - don't convert to @@character_set_connection if all arguments are numbers + - don't allow DERIVATION_NONE + */ + bool agg_arg_charsets_for_comparison(DTCollation &c, + const char *func_name, + Item **items, uint nitems, + int item_sep) + { + uint flags= MY_COLL_ALLOW_SUPERSET_CONV | + MY_COLL_ALLOW_COERCIBLE_CONV | + MY_COLL_DISALLOW_NONE; + return agg_arg_charsets(c, func_name, items, nitems, flags, item_sep); + } + +}; + + +class Type_all_attributes: public Type_std_attributes +{ +public: + Type_all_attributes() + :Type_std_attributes() + { } + Type_all_attributes(const Type_all_attributes *other) + :Type_std_attributes(other) + { } + // Returns total number of decimal digits + virtual uint decimal_precision() const= 0; + /* + Field::geometry_type is not visible here. + Let's use an "uint" wrapper for now. Later when we move Field_geom + into a plugin, this method will be replaced to some generic + datatype indepented method. + */ + virtual uint uint_geometry_type() const= 0; + virtual TYPELIB *get_typelib() const { return NULL; } }; @@ -327,6 +491,31 @@ public: }; +class Record_addr +{ +public: + uchar *ptr; // Position to field in record + /** + Byte where the @c NULL bit is stored inside a record. If this Field is a + @c NOT @c NULL field, this member is @c NULL. + */ + uchar *null_ptr; + uchar null_bit; // Bit used to test null bit + Record_addr(uchar *ptr_arg, + uchar *null_ptr_arg, + uchar null_bit_arg) + :ptr(ptr_arg), + null_ptr(null_ptr_arg), + null_bit(null_bit_arg) + { } + Record_addr(bool maybe_null) + :ptr(NULL), + null_ptr(maybe_null ? (uchar*) "" : 0), + null_bit(0) + { } +}; + + class Type_handler { protected: @@ -341,8 +530,19 @@ protected: Item_func_or_sum_illegal_param(const char *name) const; bool Item_func_or_sum_illegal_param(const Item_func_or_sum *) const; + bool check_null(const Item *item, st_value *value) const; public: + static const Type_handler *blob_type_handler(uint max_octet_length); static const Type_handler *string_type_handler(uint max_octet_length); + /** + Return a string type handler for Item + If too_big_for_varchar() returns a BLOB variant, according to length. + If max_length > 0 create a VARCHAR(n) + If max_length == 0 create a CHAR(0) + @param item - the Item to get the handler to. + */ + static const Type_handler *varstring_type_handler(const Item *item); + static const Type_handler *blob_type_handler(const Item *item); static const Type_handler *get_handler_by_field_type(enum_field_types type); static const Type_handler *get_handler_by_real_type(enum_field_types type); static const Type_handler *get_handler_by_cmp_type(Item_result type); @@ -367,6 +567,10 @@ public: virtual enum_field_types real_field_type() const { return field_type(); } virtual Item_result result_type() const= 0; virtual Item_result cmp_type() const= 0; + virtual enum_mysql_timestamp_type mysql_timestamp_type() const + { + return MYSQL_TIMESTAMP_ERROR; + } /** Prepared statement long data: Check whether this parameter data type is compatible with long data. @@ -375,6 +579,22 @@ public: */ virtual bool is_param_long_data_type() const { return false; } virtual const Type_handler *type_handler_for_comparison() const= 0; + virtual const Type_handler *type_handler_for_item_field() const + { + return this; + } + virtual const Type_handler *type_handler_for_tmp_table(const Item *) const + { + return this; + } + virtual const Type_handler *type_handler_for_union(const Item *) const + { + return this; + } + virtual const Type_handler *cast_to_int_type_handler() const + { + return this; + } virtual CHARSET_INFO *charset_for_protocol(const Item *item) const; virtual const Type_handler* type_handler_adjusted_to_max_octet_length(uint max_octet_length, @@ -391,6 +611,12 @@ public: } 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; + /* + Returns how many digits a divisor adds into a division result. + See Item::divisor_precision_increment() in item.h for more comments. + */ + virtual uint Item_divisor_precision_increment(const Item *) const; /** Makes a temporary table Field to handle numeric aggregate functions, e.g. SUM(DISTINCT expr), AVG(DISTINCT expr), etc. @@ -427,6 +653,14 @@ public: virtual Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const= 0; + virtual Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const= 0; + Field *make_and_init_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; virtual void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const= 0; @@ -435,6 +669,7 @@ public: SORT_FIELD_ATTR *attr) const= 0; virtual uint32 max_display_length(const Item *item) const= 0; + virtual bool Item_save_in_value(Item *item, st_value *value) const= 0; virtual int Item_save_in_field(Item *item, Field *field, bool no_conversions) const= 0; @@ -480,6 +715,9 @@ public: Item *target_expr, Item *target_value, Item_bool_func2 *source, Item *source_expr, Item *source_const) const= 0; + virtual bool + subquery_type_allows_materialization(const Item *inner, + const Item *outer) const= 0; virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0; virtual bool set_comparator_func(Arg_comparator *cmp) const= 0; virtual bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, @@ -605,6 +843,12 @@ public: return ROW_RESULT; } const Type_handler *type_handler_for_comparison() const; + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) const + { + DBUG_ASSERT(0); + return false; + } Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const { DBUG_ASSERT(0); @@ -617,6 +861,14 @@ public: DBUG_ASSERT(0); return NULL; } + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + { + DBUG_ASSERT(0); + return NULL; + } void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const @@ -633,6 +885,7 @@ public: DBUG_ASSERT(0); return 0; } + bool Item_save_in_value(Item *item, st_value *value) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const { DBUG_ASSERT(0); @@ -834,11 +1087,14 @@ public: Item_result cmp_type() const { return REAL_RESULT; } virtual ~Type_handler_real_result() {} const Type_handler *type_handler_for_comparison() const; + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) const; void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const; void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) 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_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; @@ -889,6 +1145,8 @@ public: Item_result cmp_type() const { return DECIMAL_RESULT; } virtual ~Type_handler_decimal_result() {}; const Type_handler *type_handler_for_comparison() const; + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) const; Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const; void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const; @@ -896,6 +1154,7 @@ public: const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; uint32 max_display_length(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_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; @@ -943,12 +1202,15 @@ public: Item_result cmp_type() const { return INT_RESULT; } virtual ~Type_handler_int_result() {} const Type_handler *type_handler_for_comparison() const; + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) const; Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const; void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const; void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) 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_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; @@ -991,6 +1253,9 @@ public: class Type_handler_temporal_result: public Type_handler { +protected: + uint Item_decimal_scale_with_seconds(const Item *item) const; + uint Item_divisor_precision_increment_with_seconds(const Item *) const; public: Item_result result_type() const { return STRING_RESULT; } Item_result cmp_type() const { return TIME_RESULT; } @@ -1005,6 +1270,8 @@ public: Item *target_expr, Item *target_value, Item_bool_func2 *source, Item *source_expr, Item *source_const) const; + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const; @@ -1072,6 +1339,7 @@ public: { return Item_temporal_precision(item, false); } + bool Item_save_in_value(Item *item, st_value *value) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; String *print_item_value(THD *thd, Item *item, String *str) const { @@ -1081,6 +1349,8 @@ public: Item *target_expr, Item *target_value, Item_bool_func2 *source, Item *source_expr, Item *source_const) const; + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, @@ -1156,6 +1426,10 @@ public: uint32 max_display_length(const Item *item) const { return 4; } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1169,6 +1443,10 @@ public: uint32 max_display_length(const Item *item) const { return 6; } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1185,6 +1463,10 @@ public: } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1198,6 +1480,10 @@ public: uint32 max_display_length(const Item *item) const { return 20; } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1211,6 +1497,10 @@ public: uint32 max_display_length(const Item *item) const { return 8; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1224,6 +1514,10 @@ public: uint32 max_display_length(const Item *item) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1241,6 +1535,10 @@ public: } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1255,6 +1553,10 @@ public: Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1268,6 +1570,10 @@ public: uint32 max_display_length(const Item *item) const { return 53; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1278,7 +1584,20 @@ public: virtual ~Type_handler_time_common() { } const Name name() const { return m_name_time; } enum_field_types field_type() const { return MYSQL_TYPE_TIME; } + enum_mysql_timestamp_type mysql_timestamp_type() const + { + return MYSQL_TIMESTAMP_TIME; + } + uint Item_decimal_scale(const Item *item) const + { + return Item_decimal_scale_with_seconds(item); + } + uint Item_divisor_precision_increment(const Item *item) const + { + return Item_divisor_precision_increment_with_seconds(item); + } const Type_handler *type_handler_for_comparison() 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; String *print_item_value(THD *thd, Item *item, String *str) const; bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, @@ -1294,6 +1613,10 @@ public: virtual ~Type_handler_time() {} Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1304,6 +1627,10 @@ public: enum_field_types real_field_type() const { return MYSQL_TYPE_TIME2; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1312,6 +1639,7 @@ class Type_handler_temporal_with_date: public Type_handler_temporal_result public: virtual ~Type_handler_temporal_with_date() {} const Type_handler *type_handler_for_comparison() 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; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const; in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const; @@ -1325,6 +1653,10 @@ public: virtual ~Type_handler_date_common() {} const Name name() const { return m_name_date; } enum_field_types field_type() const { return MYSQL_TYPE_DATE; } + enum_mysql_timestamp_type mysql_timestamp_type() const + { + return MYSQL_TIMESTAMP_DATE; + } 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; @@ -1336,6 +1668,10 @@ public: virtual ~Type_handler_date() {} Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1343,8 +1679,13 @@ class Type_handler_newdate: public Type_handler_date_common { public: virtual ~Type_handler_newdate() {} + enum_field_types real_field_type() const { return MYSQL_TYPE_NEWDATE; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1355,6 +1696,18 @@ public: virtual ~Type_handler_datetime_common() {} const Name name() const { return m_name_datetime; } enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } + enum_mysql_timestamp_type mysql_timestamp_type() const + { + return MYSQL_TIMESTAMP_DATETIME; + } + uint Item_decimal_scale(const Item *item) const + { + return Item_decimal_scale_with_seconds(item); + } + uint Item_divisor_precision_increment(const Item *item) const + { + return Item_divisor_precision_increment_with_seconds(item); + } 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; @@ -1367,6 +1720,10 @@ public: virtual ~Type_handler_datetime() {} Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1377,6 +1734,10 @@ public: enum_field_types real_field_type() const { return MYSQL_TYPE_DATETIME2; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1387,6 +1748,18 @@ public: virtual ~Type_handler_timestamp_common() {} const Name name() const { return m_name_timestamp; } enum_field_types field_type() const { return MYSQL_TYPE_TIMESTAMP; } + enum_mysql_timestamp_type mysql_timestamp_type() const + { + return MYSQL_TIMESTAMP_DATETIME; + } + uint Item_decimal_scale(const Item *item) const + { + return Item_decimal_scale_with_seconds(item); + } + uint Item_divisor_precision_increment(const Item *item) const + { + return Item_divisor_precision_increment_with_seconds(item); + } 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; @@ -1399,6 +1772,10 @@ public: virtual ~Type_handler_timestamp() {} Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1409,6 +1786,10 @@ public: enum_field_types real_field_type() const { return MYSQL_TYPE_TIMESTAMP2; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1419,8 +1800,14 @@ public: virtual ~Type_handler_olddecimal() {} const Name name() const { return m_name_decimal; } enum_field_types field_type() const { return MYSQL_TYPE_DECIMAL; } + const Type_handler *type_handler_for_tmp_table(const Item *item) const; + const Type_handler *type_handler_for_union(const Item *item) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1433,6 +1820,10 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1444,9 +1835,16 @@ public: const Name name() const { return m_name_null; } enum_field_types field_type() const { return MYSQL_TYPE_NULL; } const Type_handler *type_handler_for_comparison() const; + const Type_handler *type_handler_for_tmp_table(const Item *item) const; + const Type_handler *type_handler_for_union(const Item *) const; uint32 max_display_length(const Item *item) const { return 0; } + bool Item_save_in_value(Item *item, st_value *value) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1458,8 +1856,36 @@ public: const Name name() const { return m_name_char; } enum_field_types field_type() const { return MYSQL_TYPE_STRING; } bool is_param_long_data_type() const { return true; } + const Type_handler *type_handler_for_tmp_table(const Item *item) const + { + return varstring_type_handler(item); + } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; +}; + + +/* Old varchar */ +class Type_handler_var_string: public Type_handler_string +{ + static const Name m_name_var_string; +public: + virtual ~Type_handler_var_string() {} + const Name name() const { return m_name_var_string; } + enum_field_types field_type() const { return MYSQL_TYPE_VAR_STRING; } + enum_field_types real_field_type() const { return MYSQL_TYPE_STRING; } + const Type_handler *type_handler_for_tmp_table(const Item *item) const + { + return varstring_type_handler(item); + } + const Type_handler *type_handler_for_union(const Item *item) const + { + return varstring_type_handler(item); + } }; @@ -1470,9 +1896,21 @@ public: virtual ~Type_handler_varchar() {} const Name name() const { return m_name_varchar; } enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } + const Type_handler *type_handler_for_tmp_table(const Item *item) const + { + return varstring_type_handler(item); + } + const Type_handler *type_handler_for_union(const Item *item) const + { + return varstring_type_handler(item); + } bool is_param_long_data_type() const { return true; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1480,7 +1918,22 @@ class Type_handler_blob_common: public Type_handler_string_result { public: virtual ~Type_handler_blob_common() { } + const Type_handler *type_handler_for_tmp_table(const Item *item) const + { + return blob_type_handler(item); + } + const Type_handler *type_handler_for_union(const Item *item) const + { + return blob_type_handler(item); + } + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) const + { + return false; // Materialization does not work with BLOB columns + } bool is_param_long_data_type() const { return true; } + bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const; }; @@ -1493,6 +1946,10 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_TINY_BLOB; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1505,6 +1962,10 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_MEDIUM_BLOB; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1517,6 +1978,10 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_LONG_BLOB; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1529,6 +1994,10 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_BLOB; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1542,8 +2011,18 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; } bool is_param_long_data_type() const { return true; } const Type_handler *type_handler_for_comparison() const; + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) const + { + return false; // Materialization does not work with GEOMETRY columns + } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; + bool is_traditional_type() const { return false; @@ -1576,10 +2055,16 @@ class Type_handler_enum: public Type_handler_string_result public: virtual ~Type_handler_enum() {} const Name name() const { return m_name_enum; } - enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } + enum_field_types field_type() const { return MYSQL_TYPE_STRING; } virtual enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; } + const Type_handler *type_handler_for_item_field() const; + const Type_handler *cast_to_int_type_handler() const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1589,10 +2074,16 @@ class Type_handler_set: public Type_handler_string_result public: virtual ~Type_handler_set() {} const Name name() const { return m_name_set; } - enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } + enum_field_types field_type() const { return MYSQL_TYPE_STRING; } virtual enum_field_types real_field_type() const { return MYSQL_TYPE_SET; } + const Type_handler *type_handler_for_item_field() const; + const Type_handler *cast_to_int_type_handler() const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1628,6 +2119,10 @@ public: } Item_result result_type() const { return m_type_handler->result_type(); } Item_result cmp_type() const { return m_type_handler->cmp_type(); } + enum_mysql_timestamp_type mysql_timestamp_type() const + { + return m_type_handler->mysql_timestamp_type(); + } void set_handler(const Type_handler *other) { m_type_handler= other; @@ -1671,24 +2166,49 @@ public: }; -extern Type_handler_row type_handler_row; -extern Type_handler_null type_handler_null; -extern Type_handler_string type_handler_string; -extern Type_handler_varchar type_handler_varchar; -extern Type_handler_longlong type_handler_longlong; -extern Type_handler_float type_handler_float; -extern Type_handler_double type_handler_double; -extern Type_handler_newdecimal type_handler_newdecimal; -extern Type_handler_datetime type_handler_datetime; -extern Type_handler_longlong type_handler_longlong; -extern Type_handler_bit type_handler_bit; -extern Type_handler_enum type_handler_enum; -extern Type_handler_set type_handler_set; +extern Type_handler_row type_handler_row; +extern Type_handler_null type_handler_null; -extern Type_handler_time2 type_handler_time2; +extern Type_handler_float type_handler_float; +extern Type_handler_double type_handler_double; + +extern Type_handler_bit type_handler_bit; + +extern Type_handler_enum type_handler_enum; +extern Type_handler_set type_handler_set; + +extern Type_handler_string type_handler_string; +extern Type_handler_var_string type_handler_var_string; +extern Type_handler_varchar type_handler_varchar; + +extern Type_handler_tiny_blob type_handler_tiny_blob; +extern Type_handler_medium_blob type_handler_medium_blob; +extern Type_handler_long_blob type_handler_long_blob; +extern Type_handler_blob type_handler_blob; + +extern Type_handler_tiny type_handler_tiny; +extern Type_handler_short type_handler_short; +extern Type_handler_int24 type_handler_int24; +extern Type_handler_long type_handler_long; +extern Type_handler_longlong type_handler_longlong; + +extern Type_handler_newdecimal type_handler_newdecimal; +extern Type_handler_olddecimal type_handler_olddecimal; + +extern Type_handler_year type_handler_year; extern Type_handler_newdate type_handler_newdate; +extern Type_handler_date type_handler_date; +extern Type_handler_time type_handler_time; +extern Type_handler_time2 type_handler_time2; +extern Type_handler_datetime type_handler_datetime; extern Type_handler_datetime2 type_handler_datetime2; +extern Type_handler_timestamp type_handler_timestamp; +extern Type_handler_timestamp2 type_handler_timestamp2; +extern Type_handler_tiny_blob type_handler_tiny_blob; +extern Type_handler_blob type_handler_blob; +extern Type_handler_medium_blob type_handler_medium_blob; +extern Type_handler_long_blob type_handler_long_blob; class Type_aggregator { diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 4fb522c6b30..243bc5c989f 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -636,6 +636,59 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg, } +bool st_select_lex_unit::prepare_join(THD *thd_arg, SELECT_LEX *sl, + select_result *tmp_result, + ulong additional_options, + bool is_union_select) +{ + DBUG_ENTER("st_select_lex_unit::prepare_join"); + bool can_skip_order_by; + sl->options|= SELECT_NO_UNLOCK; + JOIN *join= new JOIN(thd_arg, sl->item_list, + (sl->options | thd_arg->variables.option_bits | + additional_options), + tmp_result); + if (!join) + DBUG_RETURN(true); + + thd_arg->lex->current_select= sl; + + can_skip_order_by= is_union_select && !(sl->braces && sl->explicit_limit); + + saved_error= join->prepare(sl->table_list.first, + sl->with_wild, + sl->where, + (can_skip_order_by ? 0 : + sl->order_list.elements) + + sl->group_list.elements, + can_skip_order_by ? + NULL : sl->order_list.first, + can_skip_order_by, + sl->group_list.first, + sl->having, + (is_union_select ? NULL : + thd_arg->lex->proc_list.first), + sl, this); + + /* There are no * in the statement anymore (for PS) */ + sl->with_wild= 0; + last_procedure= join->procedure; + + if (saved_error || (saved_error= thd_arg->is_fatal_error)) + DBUG_RETURN(true); + /* + Remove all references from the select_lex_units to the subqueries that + are inside the ORDER BY clause. + */ + if (can_skip_order_by) + { + for (ORDER *ord= (ORDER *)sl->order_list.first; ord; ord= ord->next) + { + (*ord->item)->walk(&Item::eliminate_subselect_processor, FALSE, NULL); + } + } + DBUG_RETURN(false); +} bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, @@ -747,15 +800,22 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, tmp_result= sel_result; sl->context.resolve_in_select_list= TRUE; + + if (!is_union_select && !is_recursive) + { + if (prepare_join(thd_arg, first_sl, tmp_result, additional_options, + is_union_select)) + goto err; + types= first_sl->item_list; + goto cont; + } for (;sl; sl= sl->next_select()) - { - bool can_skip_order_by; - sl->options|= SELECT_NO_UNLOCK; - JOIN *join= new JOIN(thd_arg, sl->item_list, - (sl->options | thd_arg->variables.option_bits | - additional_options), - tmp_result); + { + if (prepare_join(thd_arg, sl, tmp_result, additional_options, + is_union_select)) + goto err; + /* setup_tables_done_option should be set only for very first SELECT, because it protect from secont setup_tables call for select-like non @@ -763,53 +823,12 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, SELECT (for union it can be only INSERT ... SELECT). */ additional_options&= ~OPTION_SETUP_TABLES_DONE; - if (!join) - goto err; - - thd_arg->lex->current_select= sl; - - can_skip_order_by= is_union_select && !(sl->braces && sl->explicit_limit); - - saved_error= join->prepare(sl->table_list.first, - sl->with_wild, - sl->where, - (can_skip_order_by ? 0 : - sl->order_list.elements) + - sl->group_list.elements, - can_skip_order_by ? - NULL : sl->order_list.first, - can_skip_order_by, - sl->group_list.first, - sl->having, - (is_union_select ? NULL : - thd_arg->lex->proc_list.first), - sl, this); - - /* There are no * in the statement anymore (for PS) */ - sl->with_wild= 0; - last_procedure= join->procedure; - - if (saved_error || (saved_error= thd_arg->is_fatal_error)) - goto err; - /* - Remove all references from the select_lex_units to the subqueries that - are inside the ORDER BY clause. - */ - if (can_skip_order_by) - { - for (ORDER *ord= (ORDER *)sl->order_list.first; ord; ord= ord->next) - { - (*ord->item)->walk(&Item::eliminate_subselect_processor, FALSE, NULL); - } - } /* Use items list of underlaid select for derived tables to preserve information about fields lengths and exact types */ - if (!is_union_select && !is_recursive) - types= first_sl->item_list; - else if (sl == first_sl) + if (sl == first_sl) { if (is_recursive) { @@ -846,6 +865,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, Item *type, *item_tmp; while ((type= tp++, item_tmp= it++)) { + DBUG_ASSERT(item_tmp->fixed); if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp)) DBUG_RETURN(TRUE); } @@ -878,6 +898,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } } +cont: /* If the query is using select_union_direct, we have postponed preparation of the underlying select_result until column types diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 447d80b8b00..af597c48264 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -156,7 +156,7 @@ bool check_duplicate_names(THD *thd, List &item_list, bool gen_unique_view DBUG_RETURN(FALSE); err: - my_error(ER_DUP_FIELDNAME, MYF(0), item->name); + my_error(ER_DUP_FIELDNAME, MYF(0), item->name.str); DBUG_RETURN(TRUE); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e60d48a3bea..8cc1de8184d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -13713,27 +13713,7 @@ load_data_set_elem: text_literal: TEXT_STRING { - LEX_CSTRING tmp; - CHARSET_INFO *cs_con= thd->variables.collation_connection; - CHARSET_INFO *cs_cli= thd->variables.character_set_client; - uint repertoire= $1.repertoire(cs_cli); - if (thd->charset_is_collation_connection || - (repertoire == MY_REPERTOIRE_ASCII && - my_charset_is_ascii_based(cs_con))) - tmp= $1; - else - { - LEX_STRING to; - if (thd->convert_string(&to, cs_con, $1.str, $1.length, cs_cli)) - MYSQL_YYABORT; - tmp.str= to.str; - tmp.length= to.length; - } - $$= new (thd->mem_root) Item_string(thd, tmp.str, tmp.length, - cs_con, - DERIVATION_COERCIBLE, - repertoire); - if ($$ == NULL) + if (!($$= thd->make_string_literal($1))) MYSQL_YYABORT; } | NCHAR_STRING diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 9d9e088772e..452c22d41fd 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -13837,27 +13837,7 @@ load_data_set_elem: text_literal: TEXT_STRING { - LEX_CSTRING tmp; - CHARSET_INFO *cs_con= thd->variables.collation_connection; - CHARSET_INFO *cs_cli= thd->variables.character_set_client; - uint repertoire= $1.repertoire(cs_cli); - if (thd->charset_is_collation_connection || - (repertoire == MY_REPERTOIRE_ASCII && - my_charset_is_ascii_based(cs_con))) - tmp= $1; - else - { - LEX_STRING to; - if (thd->convert_string(&to, cs_con, $1.str, $1.length, cs_cli)) - MYSQL_YYABORT; - tmp.str= to.str; - tmp.length= to.length; - } - $$= new (thd->mem_root) Item_string(thd, tmp.str, tmp.length, - cs_con, - DERIVATION_COERCIBLE, - repertoire); - if ($$ == NULL) + if (!($$= thd->make_string_literal($1))) MYSQL_YYABORT; } | NCHAR_STRING