summaryrefslogtreecommitdiff
path: root/sql/opt_split.cc
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2021-03-23 20:54:54 -0700
committerIgor Babaev <igor@askmonty.org>2021-03-23 20:54:54 -0700
commit480a06718d137c9ee7784012ccb609b9e79ff08c (patch)
tree18180eab82208cf959f41839be2c9207d5644af1 /sql/opt_split.cc
parent7d5ec9f1aeec1ea8d00a0aa5bfec521948cfb8be (diff)
downloadmariadb-git-480a06718d137c9ee7784012ccb609b9e79ff08c.tar.gz
MDEV-25128 Wrong result from join with materialized semi-join and
splittable derived If one of joined tables of the processed query is a materialized derived table (or view or CTE) with GROUP BY clause then under some conditions it can be subject to split optimization. With this optimization new equalities are injected into the WHERE condition of the SELECT that specifies this derived table. The injected equalities are generated for all join orders with which the split optimization can employed. After the best join order has been chosen only certain of this equalities are really needed. The others can be safely removed. If it's not done and some of injected equalities involve expressions over semi-joins with look-up access then the query may return a wrong result set. This patch effectively removes equalities injected for split optimization that are needed only at the optimization stage and not needed for execution. Approved by serg@mariadb.com
Diffstat (limited to 'sql/opt_split.cc')
-rw-r--r--sql/opt_split.cc48
1 files changed, 42 insertions, 6 deletions
diff --git a/sql/opt_split.cc b/sql/opt_split.cc
index fd7836f55cc..c3a2d03a93b 100644
--- a/sql/opt_split.cc
+++ b/sql/opt_split.cc
@@ -236,6 +236,8 @@ public:
SplM_field_info *spl_fields;
/* The number of elements in the above list */
uint spl_field_cnt;
+ /* The list of equalities injected into WHERE for split optimization */
+ List<Item> inj_cond_list;
/* Contains the structures to generate all KEYUSEs for pushable equalities */
List<KEY_FIELD> added_key_fields;
/* The cache of evaluated execution plans for 'join' with pushed equalities */
@@ -1047,22 +1049,22 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(double record_count,
bool JOIN::inject_best_splitting_cond(table_map remaining_tables)
{
Item *inj_cond= 0;
- List<Item> inj_cond_list;
+ List<Item> *inj_cond_list= &spl_opt_info->inj_cond_list;
List_iterator<KEY_FIELD> li(spl_opt_info->added_key_fields);
KEY_FIELD *added_key_field;
while ((added_key_field= li++))
{
if (remaining_tables & added_key_field->val->used_tables())
continue;
- if (inj_cond_list.push_back(added_key_field->cond, thd->mem_root))
+ if (inj_cond_list->push_back(added_key_field->cond, thd->mem_root))
return true;
}
- DBUG_ASSERT(inj_cond_list.elements);
- switch (inj_cond_list.elements) {
+ DBUG_ASSERT(inj_cond_list->elements);
+ switch (inj_cond_list->elements) {
case 1:
- inj_cond= inj_cond_list.head(); break;
+ inj_cond= inj_cond_list->head(); break;
default:
- inj_cond= new (thd->mem_root) Item_cond_and(thd, inj_cond_list);
+ inj_cond= new (thd->mem_root) Item_cond_and(thd, *inj_cond_list);
if (!inj_cond)
return true;
}
@@ -1082,6 +1084,40 @@ bool JOIN::inject_best_splitting_cond(table_map remaining_tables)
/**
@brief
+ Test if equality is injected for split optimization
+
+ @param
+ eq_item equality to to test
+
+ @retval
+ true eq_item is equality injected for split optimization
+ false otherwise
+*/
+
+bool is_eq_cond_injected_for_split_opt(Item_func_eq *eq_item)
+{
+ Item *left_item= eq_item->arguments()[0]->real_item();
+ if (left_item->type() != Item::FIELD_ITEM)
+ return false;
+ Field *field= ((Item_field *) left_item)->field;
+ if (!field->table->reginfo.join_tab)
+ return false;
+ JOIN *join= field->table->reginfo.join_tab->join;
+ if (!join->spl_opt_info)
+ return false;
+ List_iterator_fast<Item> li(join->spl_opt_info->inj_cond_list);
+ Item *item;
+ while ((item= li++))
+ {
+ if (item == eq_item)
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ @brief
Fix the splitting chosen for a splittable table in the final query plan
@param