diff options
Diffstat (limited to 'sql/item_cmpfunc.cc')
-rw-r--r-- | sql/item_cmpfunc.cc | 93 |
1 files changed, 91 insertions, 2 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index a65cbbf37d9..4f18d849461 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -35,6 +35,7 @@ #define PCRE2_STATIC 1 /* Important on Windows */ #include "pcre2.h" /* pcre2 header file */ +#include "my_json_writer.h" /* Compare row signature of two expressions @@ -417,9 +418,18 @@ bool Item_func::setup_args_and_comparator(THD *thd, Arg_comparator *cmp) if (args[0]->cmp_type() == STRING_RESULT && args[1]->cmp_type() == STRING_RESULT) { + Query_arena *arena, backup; + arena= thd->activate_stmt_arena_if_needed(&backup); + DTCollation tmp; - if (agg_arg_charsets_for_comparison(tmp, args, 2)) - return true; + bool ret= agg_arg_charsets_for_comparison(tmp, args, 2); + + if (arena) + thd->restore_active_arena(arena, &backup); + + if (ret) + return ret; + cmp->m_compare_collation= tmp.collation; } // Convert constants when compared to int/year field @@ -4341,6 +4351,56 @@ Item_func_in::fix_fields(THD *thd, Item **ref) } +Item *Item_func_in::in_predicate_to_equality_transformer(THD *thd, uchar *arg) +{ + if (!array || have_null || !all_items_are_consts(args + 1, arg_count - 1)) + return this; /* Transformation is not applicable */ + + /* + If all elements in the array of constant values are equal and there are + no NULLs in the list then clause + - "a IN (e1,..,en)" can be converted to "a = e1" + - "a NOT IN (e1,..,en)" can be converted to "a != e1". + This means an object of Item_func_in can be replaced with an object of + Item_func_eq for IN (e1,..,en) clause or Item_func_ne for + NOT IN (e1,...,en). + */ + + /* + Since the array is sorted it's enough to compare the first and the last + elements to tell whether all elements are equal + */ + if (array->compare_elems(0, array->used_count - 1)) + { + /* Not all elements are equal, transformation is not possible */ + return this; + } + + Json_writer_object trace_wrapper(thd); + trace_wrapper.add("transformation", "in_predicate_to_equality") + .add("before", this); + + Item *new_item= nullptr; + if (negated) + new_item= new (thd->mem_root) Item_func_ne(thd, args[0], args[1]); + else + new_item= new (thd->mem_root) Item_func_eq(thd, args[0], args[1]); + if (new_item) + { + new_item->set_name(thd, name); + if (new_item->fix_fields(thd, &new_item)) + { + /* + If there are any problems during fixing fields, there is no need to + return an error, just discard the transformation + */ + new_item= this; + } + } + trace_wrapper.add("after", new_item); + return new_item; +} + bool Item_func_in::eval_not_null_tables(void *opt_arg) { @@ -5162,6 +5222,35 @@ Item *Item_cond::transform(THD *thd, Item_transformer transformer, uchar *arg) /** + Transform an Item_cond object with a transformer callback function. + + This is like transform() but doesn't use change_item_tree(), + because top-level expression is stored in prep_where/prep_on anyway and + is restored from there, there is no need to use change_item_tree(). + + Furthermore, it can be actually harmful to use it, if build_equal_items() + had replaced Item_eq with Item_equal and deleted list_node with a pointer + to Item_eq. In this case rollback_item_tree_changes() would modify the + deleted list_node. +*/ +Item *Item_cond::top_level_transform(THD *thd, Item_transformer transformer, uchar *arg) +{ + DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare()); + + List_iterator<Item> li(list); + Item *item; + while ((item= li++)) + { + Item *new_item= item->top_level_transform(thd, transformer, arg); + if (!new_item) + return 0; + *li.ref()= new_item; + } + return Item_func::transform(thd, transformer, arg); +} + + +/** Compile Item_cond object with a processor and a transformer callback functions. |