1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

MDEV-34123 CONCAT Function Returns Unexpected Empty Set in Query

Search conditions were evaluated using val_int(), which was wrong.
Fixing the code to use val_bool() instead.

Details:
- Adding a new item_base_t::IS_COND flag which marks Items used
  as <search condition> in WHERE, HAVING, JOIN ON, CASE WHEN clauses.
  The flag is at the parse time.
  These expressions must be evaluated using val_bool() rather than val_int().

  Note, the optimizer creates more Items which are used as search conditions.
  Most of these items are not marked with IS_COND yet. This is OK for now,
  but eventually these Items can also be fixed to have the flag.

- Adding a method Item::is_cond() which tests if the Item has the IS_COND flag.

- Implementing Item_cache_bool. It evaluates the cached expression using
  val_bool() rather than val_int().
  Overriding Type_handler_bool::Item_get_cache() to create Item_cache_bool.

- Implementing Item::save_bool_in_field(). It uses val_bool() rather than
  val_int() to evaluate the expression.

- Implementing Type_handler_bool::Item_save_in_field()
  using Item::save_bool_in_field().

- Fixing all Item_bool_func descendants to implement a virtual val_bool()
  rather than a virtual val_int().

- To find places where val_int() should be fixed to val_bool(), a few
  DBUG_ASSERT(!is_cond()) where added into val_int() implementations
  of selected (most frequent) classes:

  Item_field
  Item_str_func
  Item_datefunc
  Item_timefunc
  Item_datetimefunc
  Item_cache_bool
  Item_bool_func
  Item_func_hybrid_field_type
  Item_basic_constant descendants

- Fixing all places where DBUG_ASSERT() happened during an "mtr" run
  to use val_bool() instead of val_int().
This commit is contained in:
Alexander Barkov
2024-05-14 09:19:34 +04:00
committed by Oleksandr Byelkin
parent 6f6c1911dc
commit a931da82fa
52 changed files with 2098 additions and 151 deletions

View File

@@ -3212,7 +3212,7 @@ int JOIN::optimize_stage2()
having->update_used_tables();
if (having->const_item() && !having->is_expensive())
{
if (!having->val_int())
if (!having->val_bool())
{
having= const_cast<Item_bool_static*>(&Item_false);
zero_result_cause= "Impossible HAVING noticed after reading const tables";
@@ -4791,8 +4791,8 @@ void JOIN::exec_inner()
DBUG_ASSERT(error == 0);
if (cond_value != Item::COND_FALSE &&
having_value != Item::COND_FALSE &&
(!conds || conds->val_int()) &&
(!having || having->val_int()))
(!conds || conds->val_bool()) &&
(!having || having->val_bool()))
{
if (do_send_rows &&
(procedure ? (procedure->send_row(procedure_fields_list) ||
@@ -4825,11 +4825,11 @@ void JOIN::exec_inner()
*/
if (!zero_result_cause &&
exec_const_cond && !(select_options & SELECT_DESCRIBE) &&
!exec_const_cond->val_int())
!exec_const_cond->val_bool())
zero_result_cause= "Impossible WHERE noticed after reading const tables";
/*
We've called exec_const_cond->val_int(). This may have caused an error.
We've called exec_const_cond->val_bool(). This may have caused an error.
*/
if (unlikely(thd->is_error()))
{
@@ -12846,7 +12846,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
bool const_cond_result;
{
Json_writer_array a(thd, "computing_condition");
const_cond_result= const_cond->val_int() != 0;
const_cond_result= const_cond->val_bool() != 0;
}
if (!const_cond_result)
{
@@ -15992,7 +15992,7 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> *tables,
join->no_rows_in_result_called= 1;
while ((item= it++))
item->no_rows_in_result();
if (having && having->val_int() == 0)
if (having && having->val_bool() == false)
send_row=0;
}
@@ -17338,6 +17338,7 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels,
return 0;
eq_item->eval_not_null_tables(0);
eq_item->quick_fix_field();
eq_item->base_flags|= item_base_t::IS_COND;
}
current_sjm= field_sjm;
}
@@ -21780,7 +21781,7 @@ do_select(JOIN *join, Procedure *procedure)
sufficient to check only the condition pseudo_bits_cond.
*/
DBUG_ASSERT(join->outer_ref_cond == NULL);
if (!join->pseudo_bits_cond || join->pseudo_bits_cond->val_int())
if (!join->pseudo_bits_cond || join->pseudo_bits_cond->val_bool())
{
// HAVING will be checked by end_select
error= (*end_select)(join, 0, 0);
@@ -21841,7 +21842,7 @@ do_select(JOIN *join, Procedure *procedure)
JOIN_TAB *join_tab= join->join_tab +
(join->tables_list ? join->const_tables : 0);
if (join->outer_ref_cond && !join->outer_ref_cond->val_int())
if (join->outer_ref_cond && !join->outer_ref_cond->val_bool())
error= NESTED_LOOP_NO_MORE_ROWS;
else
error= join->first_select(join,join_tab,0);
@@ -22419,7 +22420,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
if (select_cond)
{
select_cond_result= MY_TEST(select_cond->val_int());
select_cond_result= MY_TEST(select_cond->val_bool());
/* check for errors evaluating the condition */
if (unlikely(join->thd->is_error()))
@@ -22815,7 +22816,7 @@ join_read_const_table(THD *thd, JOIN_TAB *tab, POSITION *pos)
(*tab->on_expr_ref)->update_used_tables();
DBUG_ASSERT((*tab->on_expr_ref)->const_item());
#endif
if ((table->null_row= MY_TEST((*tab->on_expr_ref)->val_int() == 0)))
if ((table->null_row= MY_TEST((*tab->on_expr_ref)->val_bool() == 0)))
mark_as_null_row(table);
}
if (!table->null_row && ! tab->join->mixed_implicit_grouping)
@@ -23571,7 +23572,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
/* Copy non-aggregated fields when loose index scan is used. */
copy_fields(&join->tmp_table_param);
}
if (join->having && join->having->val_int() == 0)
if (join->having && join->having->val_bool() == 0)
DBUG_RETURN(NESTED_LOOP_OK); // Didn't match having
if (join->procedure)
{
@@ -23762,7 +23763,7 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
while ((item= it++))
item->no_rows_in_result();
}
if (join->having && join->having->val_int() == 0)
if (join->having && join->having->val_bool() == 0)// TODO: tests
error= -1; // Didn't satisfy having
else
{
@@ -23872,7 +23873,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (copy_funcs(join_tab->tmp_table_param->items_to_copy, join->thd))
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
if (likely(!join_tab->having || join_tab->having->val_int()))
if (likely(!join_tab->having || join_tab->having->val_bool()))
{
int error;
join->found_records++;
@@ -24123,7 +24124,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
}
copy_sum_funcs(join->sum_funcs,
join->sum_funcs_end[send_group_parts]);
if (!join_tab->having || join_tab->having->val_int())
if (!join_tab->having || join_tab->having->val_bool())
{
int error= table->file->ha_write_tmp_row(table->record[0]);
if (unlikely(error) &&
@@ -26126,7 +26127,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field,
break;
goto err;
}
if (having && !having->val_int())
if (having && !having->val_bool())
{
if (unlikely((error= file->ha_delete_row(record))))
goto err;
@@ -26264,7 +26265,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
break;
goto err;
}
if (having && !having->val_int())
if (having && !having->val_bool())
{
if (unlikely((error= file->ha_delete_row(record))))
goto err;
@@ -28401,7 +28402,7 @@ int JOIN::rollup_send_data(uint idx)
int res= 0;
/* Get reference pointers to sum functions in place */
copy_ref_ptr_array(ref_ptrs, rollup.ref_pointer_arrays[i]);
if ((!having || having->val_int()))
if ((!having || having->val_bool()))
{
if (send_records < unit->lim.get_select_limit() && do_send_rows &&
(res= result->send_data_with_check(rollup.fields[i],