Commit 85b73e22 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-12656 Crash in CREATE..SELECT..UNION with a ENUM column and NULL

parent 50b70e76
......@@ -2225,6 +2225,9 @@ 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));
......@@ -2257,3 +2260,54 @@ 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;
......
......@@ -457,6 +457,10 @@ 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 #
......@@ -473,3 +477,44 @@ 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;
......
......@@ -10072,7 +10072,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);
......@@ -10180,7 +10180,14 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
};
maybe_null|= item->maybe_null;
get_full_info(item);
set_handler(Item_type_holder::type_handler()->type_handler_for_union(this));
/*
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();
......
......@@ -2604,11 +2604,7 @@ class Item_field :public Item_ident
const Type_handler *type_handler() const
{
const Type_handler *handler= field->type_handler();
// This special code for ENUM and SET should eventually be removed
if (handler == &type_handler_enum ||
handler == &type_handler_set)
return &type_handler_string;
return field->type_handler();
return handler->type_handler_for_item_field();
}
enum Item_result result_type () const
{
......@@ -5792,7 +5788,10 @@ class Item_type_holder: public Item,
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 Item_result result_type () const
......@@ -5813,7 +5812,7 @@ class Item_type_holder: public Item,
}
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; }
......@@ -5825,7 +5824,7 @@ class Item_type_holder: public Item,
bool join_types(THD *thd, Item *);
Field *create_tmp_field(bool group, TABLE *table)
{
return Item_type_holder::type_handler()->
return Item_type_holder::real_type_handler()->
make_and_init_table_field(&name, Record_addr(maybe_null),
*this, table);
}
......
......@@ -470,12 +470,24 @@ const Type_handler *Type_handler_row::type_handler_for_comparison() const
/***************************************************************************/
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;
......
......@@ -579,6 +579,10 @@ class Type_handler
*/
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;
......@@ -2053,6 +2057,7 @@ class Type_handler_enum: public Type_handler_string_result
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;
......@@ -2071,6 +2076,7 @@ class Type_handler_set: public Type_handler_string_result
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment