mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-36716 A case expression with ROW arguments in THEN crashes
The patch for SYS_REFCURSOR (MDEV-20034) overrode these methods: - Item_func_case_searched::check_arguments() - Item_func_if::check_arguments() to validate WHEN-style arguments (e.g. args[0] in case of IF) for being able to return a boolean result. However, this unintentionally removed the test for the THEN-style arguments that they are not expressions of the ROW data type. This led to a crash inside Type_handler_hybrid_field_type::aggregate_for_result on a DBUG_ASSERT that arguments are not of the ROW data type. Fix: The fix restores blocking ROW expressions in the not supported cases, to avoid the DBUG_ASSERT and to raise an SQL error instead. Blocking ROW_RESULT expressions is done per Item_func_case_expression descendant individually, instead of blocking any ROW_RESULT arguments at the Item_func_case_expression level. The fix is done taking into account the upcoming patch for associative arrays (MDEV-34319). It should be possible to pass associative array expressions into some hybrid type functions, where ROW type expressions are not possible. As a side effect, some lecagy ER_OPERAND_COLUMNS changed to a newer ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION Changes in the top affected class Item_func_case_expression: - item_func.h: Overriding Item_func_case_expression::check_arguments() to return false, without checking any arguments. Descendant validate arguments in a various different ways. No needs to block all non-scalar data type at this level, to prevent disallowing associative arrays. Changes in descendants: - item_cmpfunc.cc: Adding a test in Item_func_case_simple::aggregate_switch_and_when_arguments() preventing passing ROW_RESULT expression in predicant and WHEN in a simple CASE: CASE predicant WHEN when1 THEN .. WHEN when2 THEN .. END; This is not supported yet. Should be preferrably fixed before MDEV-34319. - item_cmpfunc.cc: Calling args[0]->type_handler()->Item_hybrid_func_fix_attributes() from Item_func_nullif::fix_length_and_dec(). This prevents a ROW expression to be passed to args[0] of NULLIF(). But will allow to pass associative arrays. args[1] is still only checked to be comparable with args[0]. No needs to add additional tests for it. - item_cmpfunc.h: Adding a call for Item_hybrid_func_fix_attributes() in Item_func_case_abbreviation2::cache_type_info(). This prevents calling the descendant functions with a ROW expression in combination with an explicit NULL in the THEN-style arguments (but will allow to pass associative arrays): IFNULL(row_expression, NULL) IFNULL(NULL, row_expression) IF(switch, row_expression, NULL) IF(switch, NULL, row_expression) NVL2(switch, row_expression, NULL) NVL2(switch, NULL, row_expression) Adding a THD* argument into involved methods. - item_cmpfunc.h: Overriding Item_func_case_abbreviation2_switch::check_arguments() to check that the first argument in IF() and NVL2() can return bool. Removing Item_func_if::check_arguments(), as it become redundant. - sql_type.cc: Fixing sql_type.cc not to disallow items[0] with ROW_RESULT. This makes it call Item_hybrid_func_fix_attributes() at the end, which block ROW arguments into THEN-style arguments of hybrid functions. But this will allow to pass Type_handler_assoc_array expressions. - sql_type.cc: Changing Type_handler_row::Item_hybrid_func_fix_attributes to raise the ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION error instead of the DBUG_ASSERT.
This commit is contained in:
@ -232,8 +232,13 @@ public:
|
||||
const Type_handler *b)
|
||||
const override
|
||||
{
|
||||
DBUG_ASSERT(a == &type_handler_row);
|
||||
DBUG_ASSERT(b == &type_handler_row);
|
||||
/*
|
||||
Allowed combinations:
|
||||
ROW+ROW, NULL+ROW, ROW+NULL
|
||||
*/
|
||||
DBUG_ASSERT(a == &type_handler_row || a == &type_handler_null);
|
||||
DBUG_ASSERT(b == &type_handler_row || b == &type_handler_null);
|
||||
DBUG_ASSERT(a == &type_handler_row || b == &type_handler_row);
|
||||
return &type_handler_row;
|
||||
}
|
||||
const Type_handler *aggregate_for_min_max(const Type_handler *a,
|
||||
@ -1893,19 +1898,16 @@ aggregate_for_result(const LEX_CSTRING &funcname, Item **items, uint nitems,
|
||||
bool treat_bit_as_number)
|
||||
{
|
||||
bool bit_and_non_bit_mixture_found= false;
|
||||
uint32 max_display_length;
|
||||
if (!nitems || items[0]->result_type() == ROW_RESULT)
|
||||
if (!nitems)
|
||||
{
|
||||
DBUG_ASSERT(0);
|
||||
set_handler(&type_handler_null);
|
||||
return true;
|
||||
}
|
||||
set_handler(items[0]->type_handler());
|
||||
max_display_length= items[0]->max_display_length();
|
||||
for (uint i= 1 ; i < nitems ; i++)
|
||||
{
|
||||
const Type_handler *cur= items[i]->type_handler();
|
||||
set_if_bigger(max_display_length, items[i]->max_display_length());
|
||||
uint bit_count= (type_handler() == &type_handler_bit) +
|
||||
(cur == &type_handler_bit);
|
||||
uint null_count= (type_handler() == &type_handler_null) +
|
||||
@ -1926,7 +1928,12 @@ aggregate_for_result(const LEX_CSTRING &funcname, Item **items, uint nitems,
|
||||
}
|
||||
}
|
||||
if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_slonglong)
|
||||
{
|
||||
uint32 max_display_length= items[0]->max_display_length();
|
||||
for (uint i= 1; i < nitems ; i++)
|
||||
set_if_bigger(max_display_length, items[i]->max_display_length());
|
||||
set_handler(Type_handler::bit_and_int_mixture_handler(max_display_length));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -4899,6 +4906,20 @@ bool Type_handler_timestamp_common::
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Type_handler_row::
|
||||
Item_hybrid_func_fix_attributes(THD *thd,
|
||||
const LEX_CSTRING &opname,
|
||||
Type_handler_hybrid_field_type *,
|
||||
Type_all_attributes *atrr,
|
||||
Item **items, uint nitems)
|
||||
const
|
||||
{
|
||||
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
|
||||
name().ptr(), opname.str);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool Type_handler::
|
||||
|
Reference in New Issue
Block a user