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:
Oleg Smirnov 2024-07-23 15:34:23 +07:00
parent b8f92ade57
commit c91aeb3771
5 changed files with 71 additions and 44 deletions

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

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

View file

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

View file

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

View file

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