mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
MDEV-34634 Types mismatch when cloning items causes debug assertion
New runtime diagnostic introduced with MDEV-34490 has detected that `Item_int_with_ref` incorrectly returns an instance of its ancestor class `Item_int`. This commit fixes that. In addition, this commit reverts a part of the diagnostic related to `clone_item()` checks. As it turned out, `clone_item()` is not required to return an object of the same class as the cloned one. For example, look at `Item_param::clone_item()`: it can return objects of `Item_null`, `Item_int`, `Item_string`, etc, depending on the object state. So the runtime type diagnostic is not applicable to `clone_item()` and is disabled with this commit. As the similar diagnostic failures are expected to appear again in the future, this commit introduces a new test file in the main suite: item_types.test, and new test cases may be added to this file Reviewer: Oleksandr Byelkin <sanja@mariadb.com>
This commit is contained in:
parent
b8f92ade57
commit
c91aeb3771
5 changed files with 71 additions and 44 deletions
16
mysql-test/main/item_types.result
Normal file
16
mysql-test/main/item_types.result
Normal file
|
@ -0,0 +1,16 @@
|
|||
#
|
||||
# MDEV-34634 Types mismatch when cloning items causes debug assertion
|
||||
#
|
||||
CREATE TABLE t1 (a DATETIME);
|
||||
SET optimizer_switch='derived_merge=off';
|
||||
SELECT * FROM (SELECT * FROM t1) AS t1 WHERE a='';
|
||||
a
|
||||
Warnings:
|
||||
Warning 1292 Truncated incorrect datetime value: ''
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (c YEAR);
|
||||
CREATE TABLE t2 (c INT);
|
||||
SELECT * FROM t1 JOIN t2 ON t1.c=t2.c WHERE t1.c<=>5;
|
||||
c c
|
||||
DROP TABLE t1, t2;
|
||||
SET optimizer_switch=default;
|
15
mysql-test/main/item_types.test
Normal file
15
mysql-test/main/item_types.test
Normal file
|
@ -0,0 +1,15 @@
|
|||
--echo #
|
||||
--echo # MDEV-34634 Types mismatch when cloning items causes debug assertion
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a DATETIME);
|
||||
SET optimizer_switch='derived_merge=off';
|
||||
SELECT * FROM (SELECT * FROM t1) AS t1 WHERE a='';
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 (c YEAR);
|
||||
CREATE TABLE t2 (c INT);
|
||||
SELECT * FROM t1 JOIN t2 ON t1.c=t2.c WHERE t1.c<=>5;
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
SET optimizer_switch=default;
|
24
sql/item.cc
24
sql/item.cc
|
@ -3847,7 +3847,7 @@ void Item_decimal::set_decimal_value(my_decimal *value_par)
|
|||
}
|
||||
|
||||
|
||||
Item *Item_decimal::do_clone_const_item(THD *thd) const
|
||||
Item *Item_decimal::clone_item(THD *thd) const
|
||||
{
|
||||
return new (thd->mem_root) Item_decimal(thd, name.str, &decimal_value, decimals,
|
||||
max_length);
|
||||
|
@ -3868,7 +3868,7 @@ my_decimal *Item_float::val_decimal(my_decimal *decimal_value)
|
|||
}
|
||||
|
||||
|
||||
Item *Item_float::do_clone_const_item(THD *thd) const
|
||||
Item *Item_float::clone_item(THD *thd) const
|
||||
{
|
||||
return new (thd->mem_root) Item_float(thd, name.str, value, decimals,
|
||||
max_length);
|
||||
|
@ -4032,7 +4032,7 @@ Item *Item_null::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
|
|||
return this;
|
||||
}
|
||||
|
||||
Item *Item_null::do_clone_const_item(THD *thd) const
|
||||
Item *Item_null::clone_item(THD *thd) const
|
||||
{
|
||||
return new (thd->mem_root) Item_null(thd, name.str);
|
||||
}
|
||||
|
@ -4873,7 +4873,7 @@ Item *Item_param::value_clone_item(THD *thd) const
|
|||
/* see comments in the header file */
|
||||
|
||||
Item *
|
||||
Item_param::do_clone_const_item(THD *thd) const
|
||||
Item_param::clone_item(THD *thd) const
|
||||
{
|
||||
// There's no "default". See comments in Item_param::save_in_field().
|
||||
switch (state) {
|
||||
|
@ -6953,7 +6953,7 @@ int Item_string::save_in_field(Field *field, bool no_conversions)
|
|||
}
|
||||
|
||||
|
||||
Item *Item_string::do_clone_const_item(THD *thd) const
|
||||
Item *Item_string::clone_item(THD *thd) const
|
||||
{
|
||||
LEX_CSTRING val;
|
||||
str_value.get_value(&val);
|
||||
|
@ -7017,7 +7017,7 @@ int Item_int::save_in_field(Field *field, bool no_conversions)
|
|||
}
|
||||
|
||||
|
||||
Item *Item_int::do_clone_const_item(THD *thd) const
|
||||
Item *Item_int::clone_item(THD *thd) const
|
||||
{
|
||||
return new (thd->mem_root) Item_int(thd, name.str, value, max_length, unsigned_flag);
|
||||
}
|
||||
|
@ -7046,7 +7046,7 @@ int Item_decimal::save_in_field(Field *field, bool no_conversions)
|
|||
}
|
||||
|
||||
|
||||
Item *Item_int_with_ref::do_clone_const_item(THD *thd) const
|
||||
Item *Item_int_with_ref::clone_item(THD *thd) const
|
||||
{
|
||||
DBUG_ASSERT(ref->const_item());
|
||||
/*
|
||||
|
@ -7142,7 +7142,7 @@ Item *Item_uint::neg(THD *thd)
|
|||
}
|
||||
|
||||
|
||||
Item *Item_uint::do_clone_const_item(THD *thd) const
|
||||
Item *Item_uint::clone_item(THD *thd) const
|
||||
{
|
||||
return new (thd->mem_root) Item_uint(thd, name.str, value, max_length);
|
||||
}
|
||||
|
@ -7380,7 +7380,7 @@ void Item_date_literal::print(String *str, enum_query_type query_type)
|
|||
}
|
||||
|
||||
|
||||
Item *Item_date_literal::do_clone_const_item(THD *thd) const
|
||||
Item *Item_date_literal::clone_item(THD *thd) const
|
||||
{
|
||||
return new (thd->mem_root) Item_date_literal(thd, &cached_time);
|
||||
}
|
||||
|
@ -7405,7 +7405,7 @@ void Item_datetime_literal::print(String *str, enum_query_type query_type)
|
|||
}
|
||||
|
||||
|
||||
Item *Item_datetime_literal::do_clone_const_item(THD *thd) const
|
||||
Item *Item_datetime_literal::clone_item(THD *thd) const
|
||||
{
|
||||
return new (thd->mem_root) Item_datetime_literal(thd, &cached_time, decimals);
|
||||
}
|
||||
|
@ -7430,7 +7430,7 @@ void Item_time_literal::print(String *str, enum_query_type query_type)
|
|||
}
|
||||
|
||||
|
||||
Item *Item_time_literal::do_clone_const_item(THD *thd) const
|
||||
Item *Item_time_literal::clone_item(THD *thd) const
|
||||
{
|
||||
return new (thd->mem_root) Item_time_literal(thd, &cached_time, decimals);
|
||||
}
|
||||
|
@ -10389,7 +10389,7 @@ void Item_cache_temporal::store_packed(longlong val_arg, Item *example_arg)
|
|||
}
|
||||
|
||||
|
||||
Item *Item_cache_temporal::do_clone_const_item(THD *thd) const
|
||||
Item *Item_cache_temporal::clone_item(THD *thd) const
|
||||
{
|
||||
Item_cache *tmp= type_handler()->Item_get_cache(thd, this);
|
||||
Item_cache_temporal *item= static_cast<Item_cache_temporal*>(tmp);
|
||||
|
|
56
sql/item.h
56
sql/item.h
|
@ -1698,21 +1698,17 @@ public:
|
|||
}
|
||||
|
||||
/*
|
||||
Clones the constant item
|
||||
Clones the constant item (not necessary returning the same item type)
|
||||
|
||||
Return value:
|
||||
- pointer to a clone of the Item
|
||||
- nullptr if the item is not clonable */
|
||||
Item *clone_const_item(THD *thd) const
|
||||
{
|
||||
Item *clone= do_clone_const_item(thd);
|
||||
if (clone)
|
||||
{
|
||||
// Make sure the clone is of same type as this item
|
||||
DBUG_ASSERT(typeid(*clone) == typeid(*this));
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
- nullptr if the item is not clonable
|
||||
|
||||
Note: the clone may have item type different from this
|
||||
(i.e., instance of another basic constant class may be returned).
|
||||
For real clones look at build_clone()/get_copy() methods
|
||||
*/
|
||||
virtual Item *clone_item(THD *thd) const { return nullptr; }
|
||||
|
||||
virtual cond_result eq_cmp_result() const { return COND_OK; }
|
||||
inline uint float_length(uint decimals_par) const
|
||||
|
@ -2588,12 +2584,6 @@ protected:
|
|||
deep copies (clones) of the item where possible
|
||||
*/
|
||||
virtual Item* do_build_clone(THD *thd) const = 0;
|
||||
|
||||
/*
|
||||
Service function for public method clone_const_item(). See comments for
|
||||
clone_const_item() above
|
||||
*/
|
||||
virtual Item *do_clone_const_item(THD *thd) const { return nullptr; }
|
||||
};
|
||||
|
||||
MEM_ROOT *get_thd_memroot(THD *thd);
|
||||
|
@ -3820,7 +3810,7 @@ public:
|
|||
const Type_handler *type_handler() const override
|
||||
{ return &type_handler_null; }
|
||||
bool basic_const_item() const override { return true; }
|
||||
Item *do_clone_const_item(THD *thd) const override;
|
||||
Item *clone_item(THD *thd) const override;
|
||||
bool const_is_null() const override { return true; }
|
||||
bool is_null() override { return true; }
|
||||
|
||||
|
@ -4270,7 +4260,7 @@ public:
|
|||
basic_const_item returned TRUE.
|
||||
*/
|
||||
Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override;
|
||||
Item *do_clone_const_item(THD *thd) const override;
|
||||
Item *clone_item(THD *thd) const override;
|
||||
void set_param_type_and_swap_value(Item_param *from);
|
||||
|
||||
Rewritable_query_parameter *get_rewritable_query_parameter() override
|
||||
|
@ -4369,7 +4359,7 @@ public:
|
|||
String *val_str(String*) override;
|
||||
int save_in_field(Field *field, bool no_conversions) override;
|
||||
bool is_order_clause_position() const override { return true; }
|
||||
Item *do_clone_const_item(THD *thd) const override;
|
||||
Item *clone_item(THD *thd) const override;
|
||||
void print(String *str, enum_query_type query_type) override;
|
||||
Item *neg(THD *thd) override;
|
||||
uint decimal_precision() const override
|
||||
|
@ -4417,7 +4407,7 @@ public:
|
|||
Item_uint(THD *thd, ulonglong i): Item_int(thd, i, 10) {}
|
||||
Item_uint(THD *thd, const char *str_arg, longlong i, uint length);
|
||||
double val_real() override { return ulonglong2double((ulonglong)value); }
|
||||
Item *do_clone_const_item(THD *thd) const override;
|
||||
Item *clone_item(THD *thd) const override;
|
||||
Item *neg(THD *thd) override;
|
||||
uint decimal_precision() const override { return max_length; }
|
||||
Item *do_get_copy(THD *thd) const override
|
||||
|
@ -4468,7 +4458,7 @@ public:
|
|||
const my_decimal *const_ptr_my_decimal() const override
|
||||
{ return &decimal_value; }
|
||||
int save_in_field(Field *field, bool no_conversions) override;
|
||||
Item *do_clone_const_item(THD *thd) const override;
|
||||
Item *clone_item(THD *thd) const override;
|
||||
void print(String *str, enum_query_type query_type) override
|
||||
{
|
||||
decimal_value.to_string(&str_value);
|
||||
|
@ -4521,7 +4511,7 @@ public:
|
|||
}
|
||||
String *val_str(String*) override;
|
||||
my_decimal *val_decimal(my_decimal *) override;
|
||||
Item *do_clone_const_item(THD *thd) const override;
|
||||
Item *clone_item(THD *thd) const override;
|
||||
Item *neg(THD *thd) override;
|
||||
void print(String *str, enum_query_type query_type) override;
|
||||
Item *do_get_copy(THD *thd) const override
|
||||
|
@ -4644,7 +4634,7 @@ public:
|
|||
int save_in_field(Field *field, bool no_conversions) override;
|
||||
const Type_handler *type_handler() const override
|
||||
{ return &type_handler_varchar; }
|
||||
Item *do_clone_const_item(THD *thd) const override;
|
||||
Item *clone_item(THD *thd) const override;
|
||||
Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override
|
||||
{
|
||||
return const_charset_converter(thd, tocs, true);
|
||||
|
@ -5067,7 +5057,7 @@ public:
|
|||
{
|
||||
return cached_time.get_mysql_time();
|
||||
}
|
||||
Item *do_clone_const_item(THD *thd) const override;
|
||||
Item *clone_item(THD *thd) const override;
|
||||
longlong val_int() override
|
||||
{
|
||||
return update_null() ? 0 : cached_time.to_longlong();
|
||||
|
@ -5117,7 +5107,7 @@ public:
|
|||
{
|
||||
return cached_time.get_mysql_time();
|
||||
}
|
||||
Item *do_clone_const_item(THD *thd) const override;
|
||||
Item *clone_item(THD *thd) const override;
|
||||
longlong val_int() override { return cached_time.to_longlong(); }
|
||||
double val_real() override { return cached_time.to_double(); }
|
||||
String *val_str(String *to) override
|
||||
|
@ -5168,7 +5158,7 @@ public:
|
|||
{
|
||||
return cached_time.get_mysql_time();
|
||||
}
|
||||
Item *do_clone_const_item(THD *thd) const override;
|
||||
Item *clone_item(THD *thd) const override;
|
||||
longlong val_int() override
|
||||
{
|
||||
return update_null() ? 0 : cached_time.to_longlong();
|
||||
|
@ -5256,6 +5246,9 @@ public:
|
|||
cached_time.copy_to_mysql_time(ltime);
|
||||
return (null_value= false);
|
||||
}
|
||||
Item *do_get_copy(THD *thd) const override
|
||||
{ return get_item_copy<Item_datetime_literal_for_invalid_dates>(thd, this); }
|
||||
Item *do_build_clone(THD *thd) const override { return get_copy(thd); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -6299,8 +6292,11 @@ public:
|
|||
{
|
||||
return ref->save_in_field(field, no_conversions);
|
||||
}
|
||||
Item *do_clone_const_item(THD *thd) const override;
|
||||
Item *clone_item(THD *thd) const override;
|
||||
Item *real_item() override { return ref; }
|
||||
Item *do_get_copy(THD *thd) const override
|
||||
{ return get_item_copy<Item_int_with_ref>(thd, this); }
|
||||
Item *do_build_clone(THD *thd) const override { return get_copy(thd); }
|
||||
};
|
||||
|
||||
#ifdef MYSQL_SERVER
|
||||
|
@ -7209,7 +7205,7 @@ public:
|
|||
is a constant and need not be optimized further.
|
||||
Important when storing packed datetime values.
|
||||
*/
|
||||
Item *do_clone_const_item(THD *thd) const override;
|
||||
Item *clone_item(THD *thd) const override;
|
||||
Item *convert_to_basic_const_item(THD *thd) override;
|
||||
virtual Item *make_literal(THD *) =0;
|
||||
};
|
||||
|
|
|
@ -16632,7 +16632,7 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list,
|
|||
if (can_change_cond_ref_to_const(func, right_item, left_item,
|
||||
field_value_owner, field, value))
|
||||
{
|
||||
Item *tmp=value->clone_const_item(thd);
|
||||
Item *tmp=value->clone_item(thd);
|
||||
if (tmp)
|
||||
{
|
||||
tmp->collation.set(right_item->collation);
|
||||
|
@ -16662,7 +16662,7 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list,
|
|||
else if (can_change_cond_ref_to_const(func, left_item, right_item,
|
||||
field_value_owner, field, value))
|
||||
{
|
||||
Item *tmp= value->clone_const_item(thd);
|
||||
Item *tmp= value->clone_item(thd);
|
||||
if (tmp)
|
||||
{
|
||||
tmp->collation.set(left_item->collation);
|
||||
|
|
Loading…
Reference in a new issue