summaryrefslogtreecommitdiffstats
path: root/sql/opt_rewrite_remove_casefold.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/opt_rewrite_remove_casefold.cc')
-rw-r--r--sql/opt_rewrite_remove_casefold.cc148
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;
+}
+