diff options
Diffstat (limited to 'sql/opt_rewrite_remove_casefold.cc')
-rw-r--r-- | sql/opt_rewrite_remove_casefold.cc | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/sql/opt_rewrite_remove_casefold.cc b/sql/opt_rewrite_remove_casefold.cc new file mode 100644 index 00000000..bf45e1f0 --- /dev/null +++ b/sql/opt_rewrite_remove_casefold.cc @@ -0,0 +1,148 @@ +#ifdef USE_PRAGMA_IMPLEMENTATION +#pragma implementation // gcc: Class implementation +#endif + +#include "mariadb.h" +#include "sql_priv.h" +#include <m_ctype.h> +#include "sql_partition.h" +#include "sql_select.h" + +#include "opt_trace.h" + +/* + @brief + Check if passed item is "UCASE(table.colX)" where colX is either covered + by some index or is a part of partition expression. + + @return + Argument of the UCASE if passed item matches + NULL otherwise. +*/ + +static Item* is_upper_key_col(Item *item) +{ + Item_func_ucase *item_func; + if ((item_func= dynamic_cast<Item_func_ucase*>(item))) + { + Item *arg= item_func->arguments()[0]; + Item *arg_real= arg->real_item(); + if (arg_real->type() == Item::FIELD_ITEM) + { + if (dynamic_cast<const Type_handler_longstr*>(arg_real->type_handler())) + { + Field *field= ((Item_field*)arg_real)->field; + bool appl= (field->flags & PART_KEY_FLAG); + +#ifdef WITH_PARTITION_STORAGE_ENGINE + partition_info *part_info; + if (!appl && ((part_info= field->table->part_info))) + { + appl= bitmap_is_set(&part_info->full_part_field_set, + field->field_index); + } +#endif + if (appl) + { + /* + Make sure COERCIBILITY(UPPER(col))=COERCIBILITY(col) + */ + DBUG_ASSERT(arg->collation.derivation == + item_func->collation.derivation); + + /* Return arg, not arg_real. Do not walk into Item_ref objects */ + return arg; + } + } + } + } + return nullptr; +} + + +static void trace_upper_removal_rewrite(THD *thd, Item *old_item, Item *new_item) +{ + Json_writer_object trace_wrapper(thd); + Json_writer_object obj(thd, "sargable_casefold_removal"); + obj.add("before", old_item) + .add("after", new_item); +} + + +/* + @brief + Rewrite UPPER(key_varchar_col) = expr into key_varchar_col=expr + + @detail + UPPER() may occur on both sides of the equality. + UCASE() is a synonym of UPPER() so we handle it, too. +*/ + +Item* Item_func_eq::varchar_upper_cmp_transformer(THD *thd, uchar *arg) +{ + if (cmp.compare_type() == STRING_RESULT && + cmp.compare_collation()->state & MY_CS_UPPER_EQUAL_AS_EQUAL) + { + Item *arg0= arguments()[0]; + Item *arg1= arguments()[1]; + bool do_rewrite= false; + Item *tmp; + + // Try rewriting the left argument + if ((tmp= is_upper_key_col(arguments()[0]))) + { + arg0= tmp; + do_rewrite= true; + } + + // Try rewriting the right argument + if ((tmp= is_upper_key_col(arguments()[1]))) + { + arg1=tmp; + do_rewrite= true; + } + + if (do_rewrite) + { + Item *res= new (thd->mem_root) Item_func_eq(thd, arg0, arg1); + if (res && !res->fix_fields(thd, &res)) + { + trace_upper_removal_rewrite(thd, this, res); + return res; + } + } + } + return this; +} + + +/* + @brief + Rewrite "UPPER(key_col) IN (const-list)" into "key_col IN (const-list)" +*/ + +Item* Item_func_in::varchar_upper_cmp_transformer(THD *thd, uchar *arg) +{ + if (arg_types_compatible && + m_comparator.cmp_type() == STRING_RESULT && + cmp_collation.collation->state & MY_CS_UPPER_EQUAL_AS_EQUAL && + all_items_are_consts(args + 1, arg_count - 1)) + { + Item *arg0= arguments()[0]; + Item *tmp; + if ((tmp= is_upper_key_col(arg0))) + { + Item_func_in *cl= (Item_func_in*)build_clone(thd); + Item *res; + cl->arguments()[0]= tmp; + cl->walk(&Item::cleanup_excluding_const_fields_processor, 0, 0); + res= cl; + if (res->fix_fields(thd, &res)) + return this; + trace_upper_removal_rewrite(thd, this, res); + return res; + } + } + return this; +} + |