1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-05 13:16:09 +03:00

MDEV-34189 Unexpected error on WHERE inet6col

normalize_cond() translated `WHERE col` into `WHERE col<>0`

But the opetator "not equal to 0" does not necessarily exists
for all data types.

For example, the query:

  SELECT * FROM t1 WHERE inet6col;

was translated to:

  SELECT * FROM t1 WHERE inet6col<>0;

which further failed with this error:

  ERROR : Illegal parameter data types inet6 and bigint for operation '<>'

This patch changes the translation from `col<>0` to `col IS TRUE`.
So now
  SELECT * FROM t1 WHERE inet6col;
gets translated to:
  SELECT * FROM t1 WHERE inet6col IS TRUE;

Details:
1. Implementing methods:
   - Field_longstr::val_bool()
   - Field_string::val_bool()
   - Item::val_int_from_val_str()
   If the input contains bad data,
   these methods raise a better error message:
     Truncated incorrect BOOLEAN value
   Before the change, the error was:
     Truncated incorrect DOUBLE value

2. Fixing normalize_cond() to generate Item_func_istrue/Item_func_isfalse
   instances instead of Item_func_ne/Item_func_eq

3. Making Item_func_truth sargable, so it uses the range optimizer.
   Implementing the following methods:
   - get_mm_tree(), get_mm_leaf(), add_key_fields() in Item_func_truth.
   - get_func_mm_tree(), for all Item_func_truth descendants.

4. Implementing the method negated_item() for all Item_func_truth
   descendants, so the negated item has a chance to be sargable:
   For example,
     WHERE NOT col IS NOT FALSE    -- this notation is not sargable
   is now translated to:
     WHERE col IS FALSE            -- this notation is sargable
This commit is contained in:
Alexander Barkov
2024-12-29 12:50:04 +04:00
parent d1ba623677
commit 5a8e6230d7
47 changed files with 1670 additions and 257 deletions

View File

@@ -8150,6 +8150,46 @@ SEL_TREE *Item_func_ne::get_func_mm_tree(RANGE_OPT_PARAM *param,
}
SEL_TREE *Item_func_istrue::get_func_mm_tree(RANGE_OPT_PARAM *param,
Field *field, Item *value)
{
DBUG_ENTER("Item_func_istrue::get_func_mm_tree");
// See comments in Item_func_ne::get_func_mm_tree()
if (param->using_real_indexes && is_field_an_unique_index(field))
DBUG_RETURN(NULL);
DBUG_RETURN(get_ne_mm_tree(param, field, value, value));
}
SEL_TREE *Item_func_isnotfalse::get_func_mm_tree(RANGE_OPT_PARAM *param,
Field *field, Item *value)
{
DBUG_ENTER("Item_func_notfalse::get_func_mm_tree");
// See comments in Item_func_ne::get_func_mm_tree()
if (param->using_real_indexes && is_field_an_unique_index(field))
DBUG_RETURN(NULL);
DBUG_RETURN(get_ne_mm_tree(param, field, value, value));
}
SEL_TREE *Item_func_isfalse::get_func_mm_tree(RANGE_OPT_PARAM *param,
Field *field,
Item *value)
{
DBUG_ENTER("Item_bool_isfalse::get_func_mm_tree");
DBUG_RETURN(get_mm_parts(param, field, EQ_FUNC, value));
}
SEL_TREE *Item_func_isnottrue::get_func_mm_tree(RANGE_OPT_PARAM *param,
Field *field,
Item *value)
{
DBUG_ENTER("Item_func_isnottrue::get_func_mm_tree");
DBUG_RETURN(get_mm_parts(param, field, EQ_FUNC, value));
}
SEL_TREE *Item_func_between::get_func_mm_tree(RANGE_OPT_PARAM *param,
Field *field, Item *value)
{
@@ -8926,6 +8966,38 @@ SEL_TREE *Item_func_in::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
}
SEL_TREE *Item_func_truth::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
DBUG_ENTER("Item_func_truth::get_mm_tree");
DBUG_ASSERT(arg_count == 1);
MEM_ROOT *old_root= param->thd->mem_root;
param->thd->mem_root= param->old_root;
Item *tmp= args[0]->type_handler()->create_boolean_false_item(param->thd);
param->thd->mem_root= old_root;
SEL_TREE *ftree= get_full_func_mm_tree_for_args(param, args[0], tmp);
if (!ftree)
goto err;
if (!affirmative) // x IS NOT {TRUE|FALSE}
{
/*
A non-affirmative boolean test works as follows:
- NULL IS NOT FALSE returns TRUE
- NULL IS NOT TRUE returns TRUE
Let's add the "x IS NULL" tree:
*/
SEL_TREE *ftree2= get_full_func_mm_tree_for_args(param, args[0], NULL);
if (!ftree2)
goto err;
ftree= tree_or(param, ftree, ftree2);
}
err:
if (!ftree)
ftree= Item_func::get_mm_tree(param, cond_ptr);
DBUG_RETURN(ftree);
}
SEL_TREE *Item_equal::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
DBUG_ENTER("Item_equal::get_mm_tree");
@@ -9294,6 +9366,28 @@ Item_func_null_predicate::get_mm_leaf(RANGE_OPT_PARAM *param,
}
SEL_ARG *
Item_func_truth::get_mm_leaf(RANGE_OPT_PARAM *param,
Field *field, KEY_PART *key_part,
Item_func::Functype type,
Item *value)
{
MEM_ROOT *alloc= param->mem_root;
DBUG_ENTER("Item_func_truth::get_mm_leaf");
if (value) // Affirmative: x IS {FALSE|TRUE}
DBUG_RETURN(Item_bool_func::get_mm_leaf(param, field, key_part,
type, value));
DBUG_ASSERT(!affirmative); // x IS NOT {FALSE|TRUE}
/*
No check for field->table->maybe_null.
See comments in Item_func_null_predicate::get_mm_leaf()
*/
if (!field->real_maybe_null())
DBUG_RETURN(&null_element);
DBUG_RETURN(new (alloc) SEL_ARG(field, is_null_string, is_null_string));
}
SEL_ARG *
Item_func_like::get_mm_leaf(RANGE_OPT_PARAM *param,
Field *field, KEY_PART *key_part,