1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +03:00

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

This commit is contained in:
Alexander Barkov
2017-05-02 11:39:20 +04:00
parent 50b70e765b
commit 85b73e2254
6 changed files with 133 additions and 10 deletions

View File

@ -2225,6 +2225,9 @@ a
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
#
@ -2257,3 +2260,54 @@ EXPLAIN SELECT * FROM t1 WHERE a='1.1';
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;

View File

@ -457,6 +457,10 @@ ALTER TABLE t1 MODIFY a ENUM('2001','2002');
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
@ -473,3 +477,44 @@ EXPLAIN SELECT * FROM t1 WHERE a='1x';
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;

View File

@ -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();

View File

@ -2604,11 +2604,7 @@ public:
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 @@ 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 Item_result result_type () const
@ -5813,7 +5812,7 @@ 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; }
@ -5825,7 +5824,7 @@ public:
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);
}

View File

@ -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;

View File

@ -579,6 +579,10 @@ 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;
@ -2053,6 +2057,7 @@ public:
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 @@ public:
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;