1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

MDEV-12775 Reuse data type aggregation code for hybrid functions and UNION

Introducing a new class Type_holder (used internally in sql_union.cc),
to reuse exactly the same data type attribute aggregation Type_handler API
for hybrid functions and UNION.

This fixes a number of bugs in UNION:

- MDEV-9495 Wrong field type for a UNION of a signed and an unsigned INT expression
- MDEV-9497 UNION and COALESCE produce different field types for DECIMAL+INT
- MDEV-12594 UNION between fixed length double columns does not always preserve scale
- MDEV-12595 UNION converts INT to BIGINT
- MDEV-12599 UNION is not symmetric when mixing INT and CHAR

Details:

- sql_union.cc: Reusing attribute aggregation for UNION.
  Adding new methods:
  * st_select_lex_unit::join_union_type_handlers()
  * st_select_lex_unit::join_union_type_attributes()
  * st_select_lex_unit::join_union_item_types()
  Removing the old join_types()-based code.

- Changing Type_handler::Item_hybrid_func_fix_attributes()
  to accept "name", Type_handler_hybrid_field_type, Type_all_attributes
  as three separate parameters instead of a single Item_hybrid_func parameter,
  to make it possible to pass both Item_hybrid_func and Type_holder.

- Moving the former special GEOMETRY and ENUM/SET attribute aggregation code
  from Item_type_holder::join_types() to
  * Type_handler_typelib::Item_hybrid_func_fix_attributes().
  * Type_handler_geometry::Item_hybrid_func_fix_attrubutes().
  This makes GEOMETRY/ENUM/SET symmetric with all other data types
  (from the UNION point of view).
  Removing Item_type_holder::join_types() and Item_type_holder::get_full_info().

- Adding new methods into Type_all_attributes:
  * Type_all_attributes::set_geometry_type() and
    Item_hybrid_func::set_geometry_type().
  * Adding Type_all_attributes::get_typelib().
  * Adding Type_all_attributes::set_typelib().

- Adding Type_handler_typelib as a common parent for
  Type_handler_enum and Type_handler_set, to avoid code duplication: they have
  already had two common methods, and we're adding one more shared method.

- Adding Type_all_attributes::set_maybe_null(), as some type handlers
  may want to set maybe_null (e.g. Type_handler_geometry) during data type
  attribute aggregation.

- Changing Type_geometry_attributes() to accept Type_handler
  and Type_all_attributes as two separate parameters, instead
  of a single Item parameter, to make it possible to pass Type_holder.

- Adding Item_args::add_argument().

- Moving Item_args::alloc_arguments() from "protected" to "public".

- Moving Item_type_holder::Item_type_holder() from item.cc to item.h, as
  now it's very simple.
  Btw, this constructor should probably be eventually removed.
  It's now used only in sql_show.cc, which could be modified to use
  Item_return_decimal (for symmetry with Item_return_xxx created for all
  other data types). Or, another option: remove all Item_return_xxx and
  use Item_type_holder for all data types instead.

- storage/tokudb/mysql-test/tokudb/r/type_float.result
  Recording new results (MDEV-12594).

- mysql-test/r/cte_recursive.result
  Recording new results (MDEV-9497)

- mysql-test/r/subselect*.result
  Recording new results (MDEV-12595)

- mysql-test/r/metadata.result
  Recording new results (MDEV-9495)

- mysql-test/r/temp_table.result
  Recording new results (MDEV-12594)

- mysql-test/r/type_float.result
  Recording new results (MDEV-12594)
This commit is contained in:
Alexander Barkov
2017-05-10 15:29:48 +04:00
parent 7c44b8afb7
commit 705fc43eaa
21 changed files with 755 additions and 325 deletions

View File

@ -130,7 +130,7 @@ select t2.a+1 from t1,t2 where t1.a=t2.a
select * from t1;
show columns from v1;
Field Type Null Key Default Extra
a bigint(20) YES NULL
a bigint(12) YES NULL
# WITH RECURSIVE : types of t1 columns are determined by anchor parts
create view v2 as
with recursive

View File

@ -147,7 +147,7 @@ id data data
2 female no
select t1.id from t1 union select t2.id from t2;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def id id 1 4 1 Y 32768 0 63
def id id 246 4 1 Y 32768 0 63
id
1
2
@ -168,12 +168,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 3 11 1 N 32769 0 63
def 1 1 3 1 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 3 11 1 N 32769 0 63
def aaa 1 1 3 1 1 N 32769 0 63
1
1
drop table t1;

View File

@ -1260,7 +1260,7 @@ a
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` bigint(20) NOT NULL
`a` int(3) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 (a int);

View File

@ -1264,7 +1264,7 @@ a
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` bigint(20) NOT NULL
`a` int(3) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 (a int);

View File

@ -1267,7 +1267,7 @@ a
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` bigint(20) NOT NULL
`a` int(3) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 (a int);

View File

@ -1263,7 +1263,7 @@ a
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` bigint(20) NOT NULL
`a` int(3) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 (a int);

View File

@ -1266,7 +1266,7 @@ a
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` bigint(20) NOT NULL
`a` int(3) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 (a int);

View File

@ -1263,7 +1263,7 @@ a
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` bigint(20) NOT NULL
`a` int(3) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 (a int);

View File

@ -181,20 +181,20 @@ CREATE TABLE t2 ( c FLOAT(30,18) );
INSERT INTO t2 VALUES( 123456 );
SELECT AVG( c ) FROM t1 UNION SELECT 1;
AVG( c )
12139
1
12139.000000000000000000
1.000000000000000000
SELECT 1 UNION SELECT AVG( c ) FROM t1;
1
1
12139
1.000000000000000000
12139.000000000000000000
SELECT 1 UNION SELECT * FROM t2 UNION SELECT 1;
1
1
123456
1.000000000000000000
123456.000000000000000000
SELECT c/1 FROM t1 UNION SELECT 1;
c/1
12139
1
12139.000000000000000000
1.000000000000000000
DROP TABLE t1, t2;
create temporary table t1 (a int);
insert into t1 values (4711);

View File

@ -232,12 +232,12 @@ insert into t2 values ("1.23456780");
create table t3 select * from t2 union select * from t1;
select * from t3;
d
1.2345678
100000000
1.234567800
100000000.000000000
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
`d` double DEFAULT NULL
`d` double(18,9) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1, t2, t3;
create table t1 select 105213674794682365.00 + 0.0 x;

View File

@ -852,7 +852,7 @@ select * from t1;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`1` int(11) NOT NULL DEFAULT 0
`1` int(2) NOT NULL DEFAULT 0
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 select _latin1"test" union select _latin2"testt" ;
@ -1608,7 +1608,7 @@ NULL binary(0) YES NULL
CREATE TABLE t5 SELECT NULL UNION SELECT NULL;
DESC t5;
Field Type Null Key Default Extra
NULL binary(0) YES NULL
NULL null YES NULL
CREATE TABLE t6
SELECT * FROM (SELECT * FROM (SELECT NULL)a) b UNION SELECT a FROM t1;
DESC t6;
@ -2195,16 +2195,223 @@ 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
`1` int(1) 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
`1` int(1) NOT NULL DEFAULT 0
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
#
# MDEV-9495 Wrong field type for a UNION of a signed and an unsigned INT expression
#
CREATE TABLE t1 (a INT, b INT UNSIGNED);
INSERT INTO t1 VALUES (0x7FFFFFFF,0xFFFFFFFF);
CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT b FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` decimal(10,0) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SELECT * FROM t2 ORDER BY a;
a
2147483647
4294967295
DROP TABLE t2;
CREATE TABLE t2 AS SELECT COALESCE(a,b), COALESCE(b,a) FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`COALESCE(a,b)` decimal(10,0) DEFAULT NULL,
`COALESCE(b,a)` decimal(10,0) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SELECT * FROM t2;
COALESCE(a,b) COALESCE(b,a)
2147483647 4294967295
DROP TABLE t2;
DROP TABLE t1;
#
# MDEV-9497 UNION and COALESCE produce different field types for DECIMAL+INT
#
CREATE TABLE t1 AS SELECT COALESCE(10.1,CAST(10 AS UNSIGNED)) AS a;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` decimal(3,1) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE OR REPLACE TABLE t1 AS SELECT 10.1 AS a UNION SELECT CAST(10 AS UNSIGNED);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` decimal(3,1) NOT NULL DEFAULT 0.0
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
#
# MDEV-12594 UNION between fixed length double columns does not always preserve scale
#
CREATE TABLE t1 (a FLOAT(20,4), b FLOAT(20,3), c FLOAT(20,4));
INSERT INTO t1 VALUES (1111,2222,3333);
CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT a FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` float(20,4) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2;
CREATE OR REPLACE TABLE t2 SELECT a FROM t1 UNION SELECT c FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` float(20,4) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2;
CREATE OR REPLACE TABLE t2 SELECT b FROM t1 UNION SELECT b FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`b` float(20,3) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2;
CREATE OR REPLACE TABLE t2 SELECT c FROM t1 UNION SELECT c FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`c` float(20,4) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2;
CREATE OR REPLACE TABLE t2 SELECT c FROM t1 UNION SELECT a FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`c` float(20,4) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2;
CREATE OR REPLACE TABLE t2 AS SELECT a FROM t1 UNION SELECT b FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` float(21,4) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2;
CREATE OR REPLACE TABLE t2 AS SELECT b FROM t1 UNION SELECT a FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`b` float(21,4) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2;
DROP TABLE t1;
# Corner case
CREATE TABLE t1 (a FLOAT(255,4), b FLOAT(255,3));
INSERT INTO t1 VALUES (1111,2222);
CREATE OR REPLACE TABLE t2 AS SELECT b FROM t1 UNION SELECT a FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`b` float(255,4) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2;
DROP TABLE t1;
#
# MDEV-12595 UNION converts INT to BIGINT
#
CREATE TABLE t1 AS SELECT
1,
-1,
COALESCE(1,1),
COALESCE(-1,-1),
COALESCE(1,-1),
COALESCE(-1,1);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`1` int(1) NOT NULL,
`-1` int(2) NOT NULL,
`COALESCE(1,1)` int(1) NOT NULL,
`COALESCE(-1,-1)` int(2) NOT NULL,
`COALESCE(1,-1)` int(2) NOT NULL,
`COALESCE(-1,1)` int(2) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 AS SELECT 1 AS c1,1 AS c2,-1 AS c3,-1 AS c4 UNION SELECT 1,-1,1,-1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` int(1) NOT NULL DEFAULT 0,
`c2` int(2) NOT NULL DEFAULT 0,
`c3` int(2) NOT NULL DEFAULT 0,
`c4` int(2) NOT NULL DEFAULT 0
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
#
# MDEV-12599 UNION is not symmetric when mixing INT and CHAR
#
CREATE OR REPLACE TABLE t1 AS SELECT 1 AS c1, 'a' AS c2 UNION SELECT 'a', 1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(1) NOT NULL DEFAULT '',
`c2` varchar(1) NOT NULL DEFAULT ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE OR REPLACE TABLE t1 AS SELECT 11112222 AS c1, 'a' AS c2 UNION SELECT 'a', 11112222;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(8) NOT NULL DEFAULT '',
`c2` varchar(8) NOT NULL DEFAULT ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE OR REPLACE TABLE t1 AS SELECT 111122223333 AS c1, 'a' AS c2 UNION SELECT 'a', 111122223333;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(12) NOT NULL DEFAULT '',
`c2` varchar(12) NOT NULL DEFAULT ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE OR REPLACE TABLE t1 AS SELECT 1111222233334444 AS c1, 'a' AS c2 UNION SELECT 'a', 1111222233334444;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(16) NOT NULL DEFAULT '',
`c2` varchar(16) NOT NULL DEFAULT ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (a INT(3), b VARCHAR(1));
CREATE TABLE t2 AS SELECT a,b FROM t1 UNION SELECT b,a FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` varchar(11) DEFAULT NULL,
`b` varchar(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (a BIGINT(3), b VARCHAR(1));
CREATE TABLE t2 AS SELECT a,b FROM t1 UNION SELECT b,a FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` varchar(20) DEFAULT NULL,
`b` varchar(20) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (a BIGINT(12), b VARCHAR(1));
CREATE TABLE t2 AS SELECT a,b FROM t1 UNION SELECT b,a FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` varchar(20) DEFAULT NULL,
`b` varchar(20) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2;
DROP TABLE t1;
#
# End of 10.3 tests
#

View File

@ -1544,6 +1544,133 @@ CREATE OR REPLACE TABLE t1 AS SELECT * FROM (SELECT 1 UNION SELECT 1) AS t0;
SHOW CREATE TABLE t1;
DROP TABLE t1;
--echo #
--echo # MDEV-9495 Wrong field type for a UNION of a signed and an unsigned INT expression
--echo #
CREATE TABLE t1 (a INT, b INT UNSIGNED);
INSERT INTO t1 VALUES (0x7FFFFFFF,0xFFFFFFFF);
CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT b FROM t1;
SHOW CREATE TABLE t2;
SELECT * FROM t2 ORDER BY a;
DROP TABLE t2;
CREATE TABLE t2 AS SELECT COALESCE(a,b), COALESCE(b,a) FROM t1;
SHOW CREATE TABLE t2;
SELECT * FROM t2;
DROP TABLE t2;
DROP TABLE t1;
--echo #
--echo # MDEV-9497 UNION and COALESCE produce different field types for DECIMAL+INT
--echo #
CREATE TABLE t1 AS SELECT COALESCE(10.1,CAST(10 AS UNSIGNED)) AS a;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE OR REPLACE TABLE t1 AS SELECT 10.1 AS a UNION SELECT CAST(10 AS UNSIGNED);
SHOW CREATE TABLE t1;
DROP TABLE t1;
--echo #
--echo # MDEV-12594 UNION between fixed length double columns does not always preserve scale
--echo #
CREATE TABLE t1 (a FLOAT(20,4), b FLOAT(20,3), c FLOAT(20,4));
INSERT INTO t1 VALUES (1111,2222,3333);
CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT a FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2;
CREATE OR REPLACE TABLE t2 SELECT a FROM t1 UNION SELECT c FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2;
CREATE OR REPLACE TABLE t2 SELECT b FROM t1 UNION SELECT b FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2;
CREATE OR REPLACE TABLE t2 SELECT c FROM t1 UNION SELECT c FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2;
CREATE OR REPLACE TABLE t2 SELECT c FROM t1 UNION SELECT a FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2;
CREATE OR REPLACE TABLE t2 AS SELECT a FROM t1 UNION SELECT b FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2;
CREATE OR REPLACE TABLE t2 AS SELECT b FROM t1 UNION SELECT a FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2;
DROP TABLE t1;
--echo # Corner case
CREATE TABLE t1 (a FLOAT(255,4), b FLOAT(255,3));
INSERT INTO t1 VALUES (1111,2222);
CREATE OR REPLACE TABLE t2 AS SELECT b FROM t1 UNION SELECT a FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2;
DROP TABLE t1;
--echo #
--echo # MDEV-12595 UNION converts INT to BIGINT
--echo #
CREATE TABLE t1 AS SELECT
1,
-1,
COALESCE(1,1),
COALESCE(-1,-1),
COALESCE(1,-1),
COALESCE(-1,1);
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 AS SELECT 1 AS c1,1 AS c2,-1 AS c3,-1 AS c4 UNION SELECT 1,-1,1,-1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
--echo #
--echo # MDEV-12599 UNION is not symmetric when mixing INT and CHAR
--echo #
CREATE OR REPLACE TABLE t1 AS SELECT 1 AS c1, 'a' AS c2 UNION SELECT 'a', 1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE OR REPLACE TABLE t1 AS SELECT 11112222 AS c1, 'a' AS c2 UNION SELECT 'a', 11112222;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE OR REPLACE TABLE t1 AS SELECT 111122223333 AS c1, 'a' AS c2 UNION SELECT 'a', 111122223333;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE OR REPLACE TABLE t1 AS SELECT 1111222233334444 AS c1, 'a' AS c2 UNION SELECT 'a', 1111222233334444;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a INT(3), b VARCHAR(1));
CREATE TABLE t2 AS SELECT a,b FROM t1 UNION SELECT b,a FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (a BIGINT(3), b VARCHAR(1));
CREATE TABLE t2 AS SELECT a,b FROM t1 UNION SELECT b,a FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (a BIGINT(12), b VARCHAR(1));
CREATE TABLE t2 AS SELECT a,b FROM t1 UNION SELECT b,a FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2;
DROP TABLE t1;
--echo #
--echo # End of 10.3 tests
--echo #

View File

@ -9772,199 +9772,6 @@ void Item_cache_row::set_null()
};
Item_type_holder::Item_type_holder(THD *thd, Item *item)
:Item(thd, item),
Type_handler_hybrid_field_type(item->real_type_handler()),
Type_geometry_attributes(item),
enum_set_typelib(0)
{
DBUG_ASSERT(item->fixed);
maybe_null= item->maybe_null;
get_full_info(item);
DBUG_ASSERT(!decimals || result_type() != INT_RESULT);
prev_decimal_int_part= item->decimal_int_part();
}
/**
Find field type which can carry current Item_type_holder type and
type of given Item.
@param thd thread handler
@param item given item to join its parameters with this item ones
@retval
TRUE error - types are incompatible
@retval
FALSE OK
*/
bool Item_type_holder::join_types(THD *thd, Item *item)
{
uint max_length_orig= max_length;
uint decimals_orig= decimals;
DBUG_ENTER("Item_type_holder::join_types");
DBUG_PRINT("info:", ("was type %s len %d, dec %d name %s",
real_type_handler()->name().ptr(), max_length, decimals,
(name.str ? name.str : "<NULL>")));
DBUG_PRINT("info:", ("in type %s len %d, dec %d",
item->real_type_handler()->name().ptr(),
item->max_length, item->decimals));
const Type_handler *item_type_handler= item->real_type_handler();
if (aggregate_for_result(item_type_handler))
{
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
Item_type_holder::real_type_handler()->name().ptr(),
item_type_handler->name().ptr(),
"UNION");
DBUG_RETURN(true);
}
/*
At this point non-zero decimals in combination with integer data types
is possible in some cases:
SELECT * FROM (SELECT NULL) a UNION SELECT 1;
In the constructor Item_type_holder::Item_type_holder() the data type
handler was set to type_handler_null with decimals==NOT_FIXED_DEC.
After the above call for aggregate_for_result() for the literal 1
which is on the right side of the UNION, the data type handler
changes to type_handler_longlong, while decimals is still NOT_FIXED_DEC.
*/
if (result_type() == INT_RESULT)
decimals= 0;
else
decimals= MY_MAX(decimals, item->decimals);
Type_geometry_attributes::join(item);
if (result_type() == DECIMAL_RESULT)
{
decimals= MY_MIN(MY_MAX(decimals, item->decimals), DECIMAL_MAX_SCALE);
int item_int_part= item->decimal_int_part();
int item_prec = MY_MAX(prev_decimal_int_part, item_int_part) + decimals;
int precision= MY_MIN(item_prec, DECIMAL_MAX_PRECISION);
unsigned_flag&= item->unsigned_flag;
max_length= my_decimal_precision_to_length_no_truncation(precision,
decimals,
unsigned_flag);
}
switch (result_type())
{
case STRING_RESULT:
{
const char *old_cs, *old_derivation;
uint32 old_max_chars= max_length / collation.collation->mbmaxlen;
old_cs= collation.collation->name;
old_derivation= collation.derivation_name();
if (collation.aggregate(item->collation, MY_COLL_ALLOW_CONV))
{
my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0),
old_cs, old_derivation,
item->collation.collation->name,
item->collation.derivation_name(),
"UNION");
DBUG_RETURN(TRUE);
}
/*
To figure out max_length, we have to take into account possible
expansion of the size of the values because of character set
conversions.
*/
if (collation.collation != &my_charset_bin)
{
max_length= MY_MAX(old_max_chars * collation.collation->mbmaxlen,
item->max_display_length() /
item->collation.collation->mbmaxlen *
collation.collation->mbmaxlen);
}
else
set_if_bigger(max_length, item->max_display_length());
break;
}
case REAL_RESULT:
{
if (decimals != NOT_FIXED_DEC)
{
/*
For FLOAT(M,D)/DOUBLE(M,D) do not change precision
if both fields have the same M and D
*/
if (item->max_length != max_length_orig ||
item->decimals != decimals_orig)
{
int delta1= max_length_orig - decimals_orig;
int delta2= item->max_length - item->decimals;
max_length= MY_MAX(delta1, delta2) + decimals;
if (Item_type_holder::real_type_handler() == &type_handler_float &&
max_length > FLT_DIG + 2)
{
max_length= MAX_FLOAT_STR_LENGTH;
decimals= NOT_FIXED_DEC;
}
else if (Item_type_holder::real_type_handler() == &type_handler_double &&
max_length > DBL_DIG + 2)
{
max_length= MAX_DOUBLE_STR_LENGTH;
decimals= NOT_FIXED_DEC;
}
}
}
else
max_length= (Item_type_holder::field_type() == MYSQL_TYPE_FLOAT) ?
FLT_DIG+6 : DBL_DIG+7;
break;
}
default:
max_length= MY_MAX(max_length, item->max_display_length());
};
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();
DBUG_PRINT("info", ("become type: %s len: %u dec: %u",
real_type_handler()->name().ptr(),
max_length, (uint) decimals));
DBUG_RETURN(FALSE);
}
/**
Get full information from Item about enum/set fields to be able to create
them later.
@param item Item for information collection
*/
void Item_type_holder::get_full_info(Item *item)
{
if (Item_type_holder::real_type_handler() == &type_handler_enum ||
Item_type_holder::real_type_handler() == &type_handler_set)
{
TYPELIB *item_typelib= item->get_typelib();
/*
We can have enum/set type after merging only if we have one enum|set
field (or MIN|MAX(enum|set field)) and number of NULL fields
*/
DBUG_ASSERT(item->real_type_handler() == &type_handler_null ||
(enum_set_typelib && !item_typelib) ||
(!enum_set_typelib && item_typelib));
if (!enum_set_typelib)
{
enum_set_typelib= ((Field_enum*)((Item_field *) item->real_item())->field)->typelib;
}
}
}
double Item_type_holder::val_real()
{
DBUG_ASSERT(0); // should never be called

View File

@ -787,7 +787,13 @@ public:
{
return type_handler()->max_display_length(this);
}
virtual TYPELIB *get_typelib() const { return NULL; }
TYPELIB *get_typelib() const { return NULL; }
void set_maybe_null(bool maybe_null_arg) { maybe_null= maybe_null_arg; }
void set_typelib(TYPELIB *typelib)
{
// Non-field Items (e.g. hybrid functions) never have ENUM/SET types yet.
DBUG_ASSERT(0);
}
Item_cache* get_cache(THD *thd) const
{
return type_handler()->Item_get_cache(thd, this);
@ -1740,6 +1746,10 @@ public:
{ return Field::GEOM_GEOMETRY; };
uint uint_geometry_type() const
{ return get_geometry_type(); }
void set_geometry_type(uint type)
{
DBUG_ASSERT(0);
}
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
@ -1842,27 +1852,28 @@ class Type_geometry_attributes
{
uint m_geometry_type;
static const uint m_geometry_type_unknown= Field::GEOM_GEOMETRYCOLLECTION + 1;
void copy(const Item *item)
void copy(const Type_handler *handler, const Type_all_attributes *gattr)
{
// Ignore implicit NULLs
m_geometry_type= item->type_handler() == &type_handler_geometry ?
item->uint_geometry_type() :
m_geometry_type= handler == &type_handler_geometry ?
gattr->uint_geometry_type() :
m_geometry_type_unknown;
}
public:
Type_geometry_attributes()
:m_geometry_type(m_geometry_type_unknown)
{ }
Type_geometry_attributes(const Item *item)
Type_geometry_attributes(const Type_handler *handler,
const Type_all_attributes *gattr)
:m_geometry_type(m_geometry_type_unknown)
{
copy(item);
copy(handler, gattr);
}
void join(const Item *item)
{
// Ignore implicit NULLs
if (m_geometry_type == m_geometry_type_unknown)
copy(item);
copy(item->type_handler(), item);
else if (item->type_handler() == &type_handler_geometry)
{
m_geometry_type=
@ -1902,7 +1913,6 @@ class Item_args
protected:
Item **args, *tmp_arg[2];
uint arg_count;
bool alloc_arguments(THD *thd, uint count);
void set_arguments(THD *thd, List<Item> &list);
bool walk_args(Item_processor processor, bool walk_subquery, void *arg)
{
@ -1961,6 +1971,11 @@ public:
set_arguments(thd, list);
}
Item_args(THD *thd, const Item_args *other);
bool alloc_arguments(THD *thd, uint count);
void add_argument(Item *item)
{
args[arg_count++]= item;
}
inline Item **arguments() const { return args; }
inline uint argument_count() const { return arg_count; }
inline void remove_arguments() { arg_count=0; }
@ -3079,6 +3094,9 @@ public:
Field::geometry_type get_geometry_type() const
{ return Type_geometry_attributes::get_geometry_type(); };
void set_geometry_type(uint type)
{ Type_geometry_attributes::set_geometry_type(type); }
Item_param(THD *thd, const LEX_CSTRING *name_arg,
uint pos_in_query_arg, uint len_in_query_arg);
@ -5841,12 +5859,29 @@ class Item_type_holder: public Item,
{
protected:
TYPELIB *enum_set_typelib;
void get_full_info(Item *item);
/* It is used to count decimal precision in join_types */
int prev_decimal_int_part;
public:
Item_type_holder(THD*, Item*);
Item_type_holder(THD *thd, Item *item)
:Item(thd, item),
Type_handler_hybrid_field_type(item->real_type_handler()),
enum_set_typelib(0)
{
DBUG_ASSERT(item->fixed);
maybe_null= item->maybe_null;
}
Item_type_holder(THD *thd,
const LEX_CSTRING *name_arg,
const Type_handler *handler,
const Type_all_attributes *attr,
bool maybe_null_arg)
:Item(thd),
Type_handler_hybrid_field_type(handler),
Type_geometry_attributes(handler, attr),
enum_set_typelib(attr->get_typelib())
{
name= *name_arg;
Type_std_attributes::set(*attr);
maybe_null= maybe_null_arg;
}
const Type_handler *type_handler() const
{
@ -5864,7 +5899,6 @@ public:
longlong val_int();
my_decimal *val_decimal(my_decimal *);
String *val_str(String*);
bool join_types(THD *thd, Item *);
Field *create_tmp_field(bool group, TABLE *table)
{
return Item_type_holder::real_type_handler()->
@ -5875,6 +5909,10 @@ public:
{
return Type_geometry_attributes::get_geometry_type();
}
void set_geometry_type(uint type)
{
Type_geometry_attributes::set_geometry_type(type);
}
Item* get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; }
};

View File

@ -546,7 +546,9 @@ my_decimal *Item_func::val_decimal(my_decimal *decimal_value)
bool Item_hybrid_func::fix_attributes(Item **items, uint nitems)
{
bool rc= Item_hybrid_func::type_handler()->
Item_hybrid_func_fix_attributes(current_thd, this, items, nitems);
Item_hybrid_func_fix_attributes(current_thd,
func_name(), this, this,
items, nitems);
DBUG_ASSERT(!rc || current_thd->is_error());
return rc;
}

View File

@ -398,6 +398,10 @@ public:
{ return Type_handler_hybrid_field_type::type_handler(); }
Field::geometry_type get_geometry_type() const
{ return Type_geometry_attributes::get_geometry_type(); };
void set_geometry_type(uint type)
{
Type_geometry_attributes::set_geometry_type(type);
}
};

View File

@ -640,6 +640,14 @@ protected:
ulonglong found_rows_for_union;
bool saved_error;
bool prepare_join(THD *thd, SELECT_LEX *sl, select_result *result,
ulong additional_options,
bool is_union_select);
bool join_union_item_types(THD *thd, List<Item> &types, uint count);
bool join_union_type_handlers(THD *thd,
class Type_holder *holders, uint count);
bool join_union_type_attributes(THD *thd,
class Type_holder *holders, uint count);
public:
// Ensures that at least all members used during cleanup() are initialized.
st_select_lex_unit()
@ -749,9 +757,6 @@ 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();

View File

@ -482,29 +482,18 @@ const Type_handler *Type_handler_row::type_handler_for_comparison() const
/***************************************************************************/
const Type_handler *Type_handler_enum::type_handler_for_item_field() const
const Type_handler *Type_handler_typelib::type_handler_for_item_field() const
{
return &type_handler_string;
}
const Type_handler *Type_handler_enum::cast_to_int_type_handler() const
const Type_handler *Type_handler_typelib::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;
}
/***************************************************************************/
bool
@ -2080,7 +2069,10 @@ Type_handler_temporal_result::Item_get_cache(THD *thd, const Item *item) const
/*************************************************************************/
bool Type_handler_int_result::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
uint unsigned_flag= items[0]->unsigned_flag;
@ -2089,7 +2081,7 @@ bool Type_handler_int_result::
if (unsigned_flag != items[i]->unsigned_flag)
{
// Convert a mixture of signed and unsigned int to decimal
func->set_handler(&type_handler_newdecimal);
handler->set_handler(&type_handler_newdecimal);
func->aggregate_attributes_decimal(items, nitems);
return false;
}
@ -2100,7 +2092,10 @@ bool Type_handler_int_result::
bool Type_handler_real_result::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
func->aggregate_attributes_real(items, nitems);
@ -2109,7 +2104,10 @@ bool Type_handler_real_result::
bool Type_handler_decimal_result::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
func->aggregate_attributes_decimal(items, nitems);
@ -2118,26 +2116,59 @@ bool Type_handler_decimal_result::
bool Type_handler_string_result::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
return func->aggregate_attributes_string(func->func_name(), items, nitems);
return func->aggregate_attributes_string(func_name, items, nitems);
}
/*
We can have enum/set type after merging only if we have one enum|set
field (or MIN|MAX(enum|set field)) and number of NULL fields
*/
bool Type_handler_typelib::
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
TYPELIB *typelib= NULL;
for (uint i= 0; i < nitems; i++)
{
if ((typelib= items[i]->get_typelib()))
break;
}
DBUG_ASSERT(typelib); // There must be at least one typelib
func->set_typelib(typelib);
return func->aggregate_attributes_string(func_name, items, nitems);
}
bool Type_handler_blob_common::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
if (func->aggregate_attributes_string(func->func_name(), items, nitems))
if (func->aggregate_attributes_string(func_name, items, nitems))
return true;
func->set_handler(blob_type_handler(func->max_length));
handler->set_handler(blob_type_handler(func->max_length));
return false;
}
bool Type_handler_date_common::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
func->fix_attributes_date();
@ -2146,7 +2177,10 @@ bool Type_handler_date_common::
bool Type_handler_time_common::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
func->aggregate_attributes_temporal(MIN_TIME_WIDTH, items, nitems);
@ -2155,7 +2189,10 @@ bool Type_handler_time_common::
bool Type_handler_datetime_common::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
func->aggregate_attributes_temporal(MAX_DATETIME_WIDTH, items, nitems);
@ -2164,7 +2201,10 @@ bool Type_handler_datetime_common::
bool Type_handler_timestamp_common::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
func->aggregate_attributes_temporal(MAX_DATETIME_WIDTH, items, nitems);
@ -2173,11 +2213,14 @@ bool Type_handler_timestamp_common::
#ifdef HAVE_SPATIAL
bool Type_handler_geometry::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item_hybrid_func_fix_attributes(THD *thd,
const char *func_name,
Type_handler_hybrid_field_type *handler,
Type_all_attributes *func,
Item **items, uint nitems) const
{
DBUG_ASSERT(nitems > 0);
Type_geometry_attributes gattr(items[0]);
Type_geometry_attributes gattr(items[0]->type_handler(), items[0]);
for (uint i= 1; i < nitems; i++)
gattr.join(items[i]);
func->set_geometry_type(gattr.get_geometry_type());
@ -2185,7 +2228,7 @@ bool Type_handler_geometry::
func->unsigned_flag= false;
func->decimals= 0;
func->max_length= (uint32) UINT_MAX32;
func->maybe_null= true;
func->set_maybe_null(true);
return false;
}
#endif
@ -2202,7 +2245,8 @@ bool Type_handler::
with aggregating for CASE-alike functions (e.g. COALESCE)
for the majority of data type handlers.
*/
return Item_hybrid_func_fix_attributes(thd, func, items, nitems);
return Item_hybrid_func_fix_attributes(thd, func->func_name(),
func, func, items, nitems);
}

View File

@ -61,6 +61,7 @@ class Item_func_div;
class Item_func_mod;
class cmp_item;
class in_vector;
class Type_handler_hybrid_field_type;
class Sort_param;
class Arg_comparator;
struct st_value;
@ -468,6 +469,7 @@ public:
:Type_std_attributes(other)
{ }
virtual ~Type_all_attributes() {}
virtual void set_maybe_null(bool maybe_null_arg)= 0;
// Returns total number of decimal digits
virtual uint decimal_precision() const= 0;
/*
@ -477,7 +479,9 @@ public:
datatype indepented method.
*/
virtual uint uint_geometry_type() const= 0;
virtual TYPELIB *get_typelib() const { return NULL; }
virtual void set_geometry_type(uint type)= 0;
virtual TYPELIB *get_typelib() const= 0;
virtual void set_typelib(TYPELIB *typelib)= 0;
};
@ -774,7 +778,10 @@ public:
const Item *cmp) 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,
virtual bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items,
uint nitems) const= 0;
virtual bool Item_func_min_max_fix_attributes(THD *thd,
@ -973,7 +980,10 @@ public:
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) 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,
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const
{
DBUG_ASSERT(0);
@ -1181,7 +1191,10 @@ public:
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) 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,
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
Item **items, uint nitems) const;
@ -1251,7 +1264,10 @@ public:
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) 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,
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
@ -1313,7 +1329,10 @@ public:
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) 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,
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
@ -1466,7 +1485,10 @@ public:
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) 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,
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
@ -1755,7 +1777,10 @@ public:
}
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,
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
bool set_comparator_func(Arg_comparator *cmp) const;
@ -1822,7 +1847,10 @@ public:
}
uint Item_decimal_precision(const Item *item) const;
String *print_item_value(THD *thd, Item *item, String *str) const;
bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
};
@ -1879,7 +1907,10 @@ public:
return Item_send_datetime(item, protocol, buf);
}
String *print_item_value(THD *thd, Item *item, String *str) const;
bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
};
@ -1941,7 +1972,10 @@ public:
return Item_send_datetime(item, protocol, buf);
}
String *print_item_value(THD *thd, Item *item, String *str) const;
bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
};
@ -2123,7 +2157,10 @@ public:
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,
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
};
@ -2230,7 +2267,10 @@ public:
bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *h,
Type_all_attributes *attr,
Item **items, uint nitems) const;
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
@ -2250,16 +2290,28 @@ extern MYSQL_PLUGIN_IMPORT Type_handler_geometry type_handler_geometry;
#endif
class Type_handler_enum: public Type_handler_string_result
class Type_handler_typelib: public Type_handler_string_result
{
public:
virtual ~Type_handler_typelib() { }
enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
const Type_handler *type_handler_for_item_field() const;
const Type_handler *cast_to_int_type_handler() const;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
};
class Type_handler_enum: public Type_handler_typelib
{
static const Name m_name_enum;
public:
virtual ~Type_handler_enum() {}
const Name name() const { return m_name_enum; }
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,
@ -2269,16 +2321,13 @@ public:
};
class Type_handler_set: public Type_handler_string_result
class Type_handler_set: public Type_handler_typelib
{
static const Name m_name_set;
public:
virtual ~Type_handler_set() {}
const Name name() const { return m_name_set; }
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,

View File

@ -692,6 +692,179 @@ bool st_select_lex_unit::prepare_join(THD *thd_arg, SELECT_LEX *sl,
}
class Type_holder: public Sql_alloc,
public Item_args,
public Type_handler_hybrid_field_type,
public Type_all_attributes,
public Type_geometry_attributes
{
TYPELIB *m_typelib;
bool m_maybe_null;
public:
Type_holder()
:m_typelib(NULL),
m_maybe_null(false)
{ }
void set_maybe_null(bool maybe_null_arg) { m_maybe_null= maybe_null_arg; }
bool get_maybe_null() const { return m_maybe_null; }
uint decimal_precision() const
{
/*
Type_holder is not used directly to create fields, so
its virtual decimal_precision() is never called.
We should eventually extend create_result_table() to accept
an array of Type_holders directly, without having to allocate
Item_type_holder's and put them into List<Item>.
*/
DBUG_ASSERT(0);
return 0;
}
void set_geometry_type(uint type)
{
Type_geometry_attributes::set_geometry_type(type);
}
uint uint_geometry_type() const
{
return Type_geometry_attributes::get_geometry_type();
}
void set_typelib(TYPELIB *typelib)
{
m_typelib= typelib;
}
TYPELIB *get_typelib() const
{
return m_typelib;
}
bool aggregate_attributes(THD *thd)
{
for (uint i= 0; i < arg_count; i++)
m_maybe_null|= args[i]->maybe_null;
return
type_handler()->Item_hybrid_func_fix_attributes(thd,
"UNION", this, this,
args, arg_count);
}
};
/**
Aggregate data type handlers for the "count" leftmost UNION parts.
*/
bool st_select_lex_unit::join_union_type_handlers(THD *thd_arg,
Type_holder *holders,
uint count)
{
DBUG_ENTER("st_select_lex_unit::join_union_type_handlers");
SELECT_LEX *first_sl= first_select(), *sl= first_sl;
for (uint i= 0; i < count ; sl= sl->next_select(), i++)
{
Item *item;
List_iterator_fast<Item> it(sl->item_list);
for (uint pos= 0; (item= it++); pos++)
{
const Type_handler *item_type_handler= item->real_type_handler();
if (sl == first_sl)
holders[pos].set_handler(item_type_handler);
else
{
if (first_sl->item_list.elements != sl->item_list.elements)
{
my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
ER_THD(thd_arg, ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),
MYF(0));
DBUG_RETURN(true);
}
if (holders[pos].aggregate_for_result(item_type_handler))
{
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
holders[pos].type_handler()->name().ptr(),
item_type_handler->name().ptr(),
"UNION");
DBUG_RETURN(true);
}
}
}
}
DBUG_RETURN(false);
}
/**
Aggregate data type attributes for the "count" leftmost UNION parts.
*/
bool st_select_lex_unit::join_union_type_attributes(THD *thd_arg,
Type_holder *holders,
uint count)
{
DBUG_ENTER("st_select_lex_unit::join_union_type_attributes");
SELECT_LEX *sl, *first_sl= first_select();
uint item_pos;
for (uint pos= 0; pos < first_sl->item_list.elements; pos++)
{
if (holders[pos].alloc_arguments(thd_arg, count))
DBUG_RETURN(true);
}
for (item_pos= 0, sl= first_sl ;
item_pos < count;
sl= sl->next_select(), item_pos++)
{
Item *item_tmp;
List_iterator_fast<Item> itx(sl->item_list);
for (uint holder_pos= 0 ; (item_tmp= itx++); holder_pos++)
{
DBUG_ASSERT(item_tmp->fixed);
holders[holder_pos].add_argument(item_tmp);
}
}
for (uint pos= 0; pos < first_sl->item_list.elements; pos++)
{
if (holders[pos].aggregate_attributes(thd_arg))
DBUG_RETURN(true);
}
DBUG_RETURN(false);
}
/**
Join data types for the leftmost "count" UNION parts
and store corresponding Item_type_holder's into "types".
*/
bool st_select_lex_unit::join_union_item_types(THD *thd_arg,
List<Item> &types,
uint count)
{
DBUG_ENTER("st_select_lex_unit::join_union_select_list_types");
SELECT_LEX *first_sl= first_select();
Type_holder *holders;
if (!(holders= new (thd_arg->mem_root)
Type_holder[first_sl->item_list.elements]) ||
join_union_type_handlers(thd_arg, holders, count) ||
join_union_type_attributes(thd_arg, holders, count))
DBUG_RETURN(true);
types.empty();
List_iterator_fast<Item> it(first_sl->item_list);
Item *item_tmp;
for (uint pos= 0; (item_tmp= it++); pos++)
{
/* Error's in 'new' will be detected after loop */
types.push_back(new (thd_arg->mem_root)
Item_type_holder(thd_arg,
&item_tmp->name,
holders[pos].type_handler(),
&holders[pos]/*Type_all_attributes*/,
holders[pos].get_maybe_null()));
}
if (thd_arg->is_fatal_error)
DBUG_RETURN(true); // out of memory
DBUG_RETURN(false);
}
bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
ulong additional_options)
{
@ -699,6 +872,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
SELECT_LEX *sl, *first_sl= first_select();
bool is_recursive= with_element && with_element->is_recursive;
bool is_rec_result_table_created= false;
uint union_part_count= 0;
select_result *tmp_result;
bool is_union_select;
bool have_except= FALSE, have_intersect= FALSE;
@ -811,7 +985,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
goto cont;
}
for (;sl; sl= sl->next_select())
for (;sl; sl= sl->next_select(), union_part_count++)
{
if (prepare_join(thd_arg, sl, tmp_result, additional_options,
is_union_select))
@ -838,39 +1012,6 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (check_duplicate_names(thd, sl->item_list, 0))
goto err;
}
types.empty();
List_iterator_fast<Item> it(sl->item_list);
Item *item_tmp;
while ((item_tmp= it++))
{
/* Error's in 'new' will be detected after loop */
types.push_back(new (thd_arg->mem_root)
Item_type_holder(thd_arg, item_tmp));
}
if (thd_arg->is_fatal_error)
goto err; // out of memory
}
else
{
if (types.elements != sl->item_list.elements)
{
my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
ER_THD(thd, ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0));
goto err;
}
if (!is_rec_result_table_created)
{
List_iterator_fast<Item> it(sl->item_list);
List_iterator_fast<Item> tp(types);
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);
}
}
}
if (is_recursive)
{
@ -883,6 +1024,9 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
ulonglong create_options;
create_options= (first_sl->options | thd_arg->variables.option_bits |
TMP_TABLE_ALL_COLUMNS);
// Join data types for all non-recursive parts of a recursive UNION
if (join_union_item_types(thd, types, union_part_count + 1))
goto err;
if (union_result->create_result_table(thd, &types,
MY_TEST(union_distinct),
create_options, derived->alias,
@ -898,6 +1042,9 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
}
}
}
// In case of a non-recursive UNION, join data types for all UNION parts.
if (!is_recursive && join_union_item_types(thd, types, union_part_count))
goto err;
cont:
/*

View File

@ -233,12 +233,12 @@ insert into t2 values ("1.23456780");
create table t3 select * from t2 union select * from t1;
select * from t3;
d
1.2345678
100000000
1.234567800
100000000.000000000
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
`d` double DEFAULT NULL
`d` double(18,9) DEFAULT NULL
) ENGINE=ENGINE DEFAULT CHARSET=latin1
drop table t1, t2, t3;
create table t1 select 105213674794682365.00 + 0.0 x;