summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/index_merge_myisam.result2
-rw-r--r--mysql-test/r/join_outer.result4
-rw-r--r--mysql-test/r/join_outer_jcl6.result4
-rw-r--r--mysql-test/r/range.result45
-rw-r--r--mysql-test/r/range_mrr_icp.result45
-rw-r--r--mysql-test/t/range.test32
-rw-r--r--sql/opt_range.cc101
-rw-r--r--sql/opt_range.h6
-rw-r--r--sql/sql_select.cc40
9 files changed, 241 insertions, 38 deletions
diff --git a/mysql-test/r/index_merge_myisam.result b/mysql-test/r/index_merge_myisam.result
index c907997573a..9820170aa59 100644
--- a/mysql-test/r/index_merge_myisam.result
+++ b/mysql-test/r/index_merge_myisam.result
@@ -74,7 +74,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 17 Using sort_union(i1,i2); Using where
explain select * from t0 where key2 = 45 or key1 <=> null;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t0 range i1,i2 i2 4 NULL 1 Using where
+1 SIMPLE t0 range i1,i2 i2 4 NULL 1 Using index condition
explain select * from t0 where key2 = 45 or key1 is not null;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL i1,i2 NULL NULL NULL 1024 Using where
diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result
index c4770182598..36c2f1898f8 100644
--- a/mysql-test/r/join_outer.result
+++ b/mysql-test/r/join_outer.result
@@ -2090,10 +2090,10 @@ SELECT t1.b, t2.c, t2.d FROM t2 LEFT JOIN t1 ON t2.c = t1.a
WHERE t1.pk BETWEEN 5 AND 6 AND t1.b IS NULL OR t1.b = 5
ORDER BY t1.b;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE t1 ref PRIMARY,idx idx 4 const 2 100.00 Using where; Using filesort
+1 SIMPLE t1 ref PRIMARY,idx idx 4 const 2 100.00 Using where
1 SIMPLE t2 ref c c 5 test.t1.a 2 100.00
Warnings:
-Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` join `test`.`t1` where ((`test`.`t2`.`c` = `test`.`t1`.`a`) and (((`test`.`t1`.`pk` between 5 and 6) and isnull(`test`.`t1`.`b`)) or (`test`.`t1`.`b` = 5))) order by `test`.`t1`.`b`
+Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` join `test`.`t1` where ((`test`.`t2`.`c` = `test`.`t1`.`a`) and (`test`.`t1`.`b` = 5)) order by `test`.`t1`.`b`
SELECT t1.b, t2.c, t2.d FROM t2 LEFT JOIN t1 ON t2.c = t1.a
WHERE t1.pk BETWEEN 5 AND 6 AND t1.b IS NULL OR t1.b = 5
ORDER BY t1.b;
diff --git a/mysql-test/r/join_outer_jcl6.result b/mysql-test/r/join_outer_jcl6.result
index 862fc194a7a..6f3da3efdd7 100644
--- a/mysql-test/r/join_outer_jcl6.result
+++ b/mysql-test/r/join_outer_jcl6.result
@@ -2101,10 +2101,10 @@ SELECT t1.b, t2.c, t2.d FROM t2 LEFT JOIN t1 ON t2.c = t1.a
WHERE t1.pk BETWEEN 5 AND 6 AND t1.b IS NULL OR t1.b = 5
ORDER BY t1.b;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE t1 ref PRIMARY,idx idx 4 const 2 100.00 Using where; Using filesort
+1 SIMPLE t1 ref PRIMARY,idx idx 4 const 2 100.00 Using where
1 SIMPLE t2 ref c c 5 test.t1.a 2 100.00
Warnings:
-Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` join `test`.`t1` where ((`test`.`t2`.`c` = `test`.`t1`.`a`) and (((`test`.`t1`.`pk` between 5 and 6) and isnull(`test`.`t1`.`b`)) or (`test`.`t1`.`b` = 5))) order by `test`.`t1`.`b`
+Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` join `test`.`t1` where ((`test`.`t2`.`c` = `test`.`t1`.`a`) and (`test`.`t1`.`b` = 5)) order by `test`.`t1`.`b`
SELECT t1.b, t2.c, t2.d FROM t2 LEFT JOIN t1 ON t2.c = t1.a
WHERE t1.pk BETWEEN 5 AND 6 AND t1.b IS NULL OR t1.b = 5
ORDER BY t1.b;
diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result
index f2ad42ebc8d..fe528e1b2e9 100644
--- a/mysql-test/r/range.result
+++ b/mysql-test/r/range.result
@@ -2196,3 +2196,48 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range a a 5 NULL 1 Using where; Using index
drop table t1,t2,t3;
+#
+# MDEV-6480: Remove conditions for which range optimizer returned SEL_ARG::IMPOSSIBLE.
+#
+create table t1(a int);
+insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t2 (a int, b int, c int, key(a), key(b));
+insert into t2
+select
+A.a + B.a* 10 + C.a * 100,
+A.a + B.a* 10 + C.a * 100,
+12345
+from
+t1 A, t1 B, t1 C;
+# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
+explain extended select * from t2 where (b > 25 and b < 15) or a<44;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 range a,b a 5 NULL 43 100.00 Using index condition
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`a` < 44)
+# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
+explain extended select * from t2 where a < 44 or (b > 25 and b < 15);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 range a,b a 5 NULL 43 100.00 Using index condition
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`a` < 44)
+# Here, conditions b will not be removed, because "c<44" is not sargable
+# and hence (b.. and .. b) part is not analyzed at all:
+explain extended select * from t2 where c < 44 or (b > 25 and b < 15);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL b NULL NULL NULL 1000 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where ((`test`.`t2`.`c` < 44) or ((`test`.`t2`.`b` > 25) and (`test`.`t2`.`b` < 15)))
+# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
+explain extended select * from t2 where (b > 25 and b < 15) or c < 44;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL b NULL NULL NULL 1000 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where ((`test`.`t2`.`c` < 44))
+# Try a case where both OR parts produce SEL_ARG::IMPOSSIBLE:
+explain extended select * from t2 where (b > 25 and b < 15) or (a>55 and a<44);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where 0
+drop table t1,t2;
diff --git a/mysql-test/r/range_mrr_icp.result b/mysql-test/r/range_mrr_icp.result
index 16b35448c50..62bea71173c 100644
--- a/mysql-test/r/range_mrr_icp.result
+++ b/mysql-test/r/range_mrr_icp.result
@@ -2198,4 +2198,49 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range a a 5 NULL 1 Using where; Using index
drop table t1,t2,t3;
+#
+# MDEV-6480: Remove conditions for which range optimizer returned SEL_ARG::IMPOSSIBLE.
+#
+create table t1(a int);
+insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t2 (a int, b int, c int, key(a), key(b));
+insert into t2
+select
+A.a + B.a* 10 + C.a * 100,
+A.a + B.a* 10 + C.a * 100,
+12345
+from
+t1 A, t1 B, t1 C;
+# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
+explain extended select * from t2 where (b > 25 and b < 15) or a<44;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 range a,b a 5 NULL 43 100.00 Using index condition; Rowid-ordered scan
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`a` < 44)
+# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
+explain extended select * from t2 where a < 44 or (b > 25 and b < 15);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 range a,b a 5 NULL 43 100.00 Using index condition; Rowid-ordered scan
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`a` < 44)
+# Here, conditions b will not be removed, because "c<44" is not sargable
+# and hence (b.. and .. b) part is not analyzed at all:
+explain extended select * from t2 where c < 44 or (b > 25 and b < 15);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL b NULL NULL NULL 1000 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where ((`test`.`t2`.`c` < 44) or ((`test`.`t2`.`b` > 25) and (`test`.`t2`.`b` < 15)))
+# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
+explain extended select * from t2 where (b > 25 and b < 15) or c < 44;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL b NULL NULL NULL 1000 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where ((`test`.`t2`.`c` < 44))
+# Try a case where both OR parts produce SEL_ARG::IMPOSSIBLE:
+explain extended select * from t2 where (b > 25 and b < 15) or (a>55 and a<44);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where 0
+drop table t1,t2;
set optimizer_switch=@mrr_icp_extra_tmp;
diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test
index 7b68f42c4cb..6249d2b5e4f 100644
--- a/mysql-test/t/range.test
+++ b/mysql-test/t/range.test
@@ -1745,3 +1745,35 @@ explain select * from t3, t2 where t2.a < t3.b and t3.a=1;
--echo # The second table should use 'range':
explain select * from t3, t2 where t3.b > t2.a and t3.a=1;
drop table t1,t2,t3;
+
+--echo #
+--echo # MDEV-6480: Remove conditions for which range optimizer returned SEL_ARG::IMPOSSIBLE.
+--echo #
+create table t1(a int);
+insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t2 (a int, b int, c int, key(a), key(b));
+insert into t2
+select
+ A.a + B.a* 10 + C.a * 100,
+ A.a + B.a* 10 + C.a * 100,
+ 12345
+from
+ t1 A, t1 B, t1 C;
+
+--echo # EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
+explain extended select * from t2 where (b > 25 and b < 15) or a<44;
+
+--echo # EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
+explain extended select * from t2 where a < 44 or (b > 25 and b < 15);
+
+--echo # Here, conditions b will not be removed, because "c<44" is not sargable
+--echo # and hence (b.. and .. b) part is not analyzed at all:
+explain extended select * from t2 where c < 44 or (b > 25 and b < 15);
+
+--echo # EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
+explain extended select * from t2 where (b > 25 and b < 15) or c < 44;
+
+--echo # Try a case where both OR parts produce SEL_ARG::IMPOSSIBLE:
+explain extended select * from t2 where (b > 25 and b < 15) or (a>55 and a<44);
+
+drop table t1,t2;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 2616e044025..b795411130d 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -829,6 +829,12 @@ public:
*/
bool remove_jump_scans;
+ /*
+ TRUE <=> Range analyzer should remove parts of condition that are found
+ to be always FALSE.
+ */
+ bool remove_false_where_parts;
+
/*
used_key_no -> table_key_no translation table. Only makes sense if
using_real_indexes==TRUE
@@ -908,7 +914,7 @@ static SEL_TREE * get_mm_parts(RANGE_OPT_PARAM *param,COND *cond_func,Field *fie
static SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param,COND *cond_func,Field *field,
KEY_PART *key_part,
Item_func::Functype type,Item *value);
-static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond);
+static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond);
static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts);
static ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
@@ -2941,7 +2947,8 @@ static int fill_used_fields_bitmap(PARAM *param)
int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
table_map prev_tables,
ha_rows limit, bool force_quick_range,
- bool ordered_output)
+ bool ordered_output,
+ bool remove_false_parts_of_where)
{
uint idx;
double scan_time;
@@ -3000,6 +3007,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
param.imerge_cost_buff_size= 0;
param.using_real_indexes= TRUE;
param.remove_jump_scans= TRUE;
+ param.remove_false_where_parts= remove_false_parts_of_where;
param.force_default_mrr= ordered_output;
param.possible_keys.clear_all();
@@ -3073,7 +3081,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
if (cond)
{
- if ((tree= get_mm_tree(&param,cond)))
+ if ((tree= get_mm_tree(&param, &cond)))
{
if (tree->type == SEL_TREE::IMPOSSIBLE)
{
@@ -3415,7 +3423,7 @@ double records_in_column_ranges(PARAM *param, uint idx,
TRUE otherwise
*/
-bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
+bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
{
uint keynr;
uint max_quick_key_parts= 0;
@@ -3425,7 +3433,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
table->cond_selectivity= 1.0;
- if (!cond || table_records == 0)
+ if (!*cond || table_records == 0)
DBUG_RETURN(FALSE);
if (table->pos_in_table_list->schema_table)
@@ -3529,6 +3537,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
param.old_root= thd->mem_root;
param.table= table;
param.is_ror_scan= FALSE;
+ param.remove_false_where_parts= true;
if (create_key_parts_for_pseudo_indexes(&param, used_fields))
goto free_alloc;
@@ -3606,7 +3615,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
ulong check_rows=
MY_MIN(thd->variables.optimizer_selectivity_sampling_limit,
(ulong) (table_records * SELECTIVITY_SAMPLING_SHARE));
- if (cond && check_rows > SELECTIVITY_SAMPLING_THRESHOLD &&
+ if (*cond && check_rows > SELECTIVITY_SAMPLING_THRESHOLD &&
thd->variables.optimizer_use_condition_selectivity > 4)
{
find_selective_predicates_list_processor_data *dt=
@@ -3617,8 +3626,8 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
DBUG_RETURN(TRUE);
dt->list.empty();
dt->table= table;
- if (cond->walk(&Item::find_selective_predicates_list_processor, 0,
- (uchar*) dt))
+ if ((*cond)->walk(&Item::find_selective_predicates_list_processor, 0,
+ (uchar*) dt))
DBUG_RETURN(TRUE);
if (dt->list.elements > 0)
{
@@ -3951,6 +3960,8 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
/* range_par->cond doesn't need initialization */
range_par->prev_tables= range_par->read_tables= 0;
range_par->current_table= table->map;
+ /* It should be possible to switch the following ON: */
+ range_par->remove_false_where_parts= false;
range_par->keys= 1; // one index
range_par->using_real_indexes= FALSE;
@@ -3967,7 +3978,7 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
SEL_TREE *tree;
int res;
- tree= get_mm_tree(range_par, pprune_cond);
+ tree= get_mm_tree(range_par, &pprune_cond);
if (!tree)
goto all_used;
@@ -7855,15 +7866,33 @@ static SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param,
DBUG_RETURN(ftree);
}
- /* make a select tree of all keys in condition */
+/*
+ make a select tree of all keys in condition
+
+ @param param Context
+ @param cond INOUT condition to perform range analysis on.
+
+ @detail
+ Range analysis may infer that some conditions are never true.
+ - If the condition is never true, SEL_TREE(type=IMPOSSIBLE) is returned
+ - if parts of condition are never true, the function may remove these parts
+ from the condition 'cond'. Sometimes, this will cause the condition to
+ be substituted for something else.
+
-static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
+ @return
+ NULL - Could not infer anything from condition cond.
+ SEL_TREE with type=IMPOSSIBLE - condition can never be true.
+*/
+
+static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
SEL_TREE *tree=0;
SEL_TREE *ftree= 0;
Item_field *field_item= 0;
bool inv= FALSE;
Item *value= 0;
+ Item *cond= *cond_ptr;
DBUG_ENTER("get_mm_tree");
if (cond->type() == Item::COND_ITEM)
@@ -7876,31 +7905,75 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
Item *item;
while ((item=li++))
{
- SEL_TREE *new_tree= get_mm_tree(param,item);
+ SEL_TREE *new_tree= get_mm_tree(param,li.ref());
if (param->statement_should_be_aborted())
DBUG_RETURN(NULL);
tree= tree_and(param,tree,new_tree);
if (tree && tree->type == SEL_TREE::IMPOSSIBLE)
+ {
+ /*
+ Do not remove 'item' from 'cond'. We return a SEL_TREE::IMPOSSIBLE
+ and that is sufficient for the caller to see that the whole
+ condition is never true.
+ */
break;
+ }
}
}
else
{ // COND OR
- tree= get_mm_tree(param,li++);
+ bool replace_cond= false;
+ Item *replacement_item= li++;
+ tree= get_mm_tree(param, li.ref());
if (param->statement_should_be_aborted())
DBUG_RETURN(NULL);
if (tree)
{
+ if (tree->type == SEL_TREE::IMPOSSIBLE &&
+ param->remove_false_where_parts)
+ {
+ /* See the other li.remove() call below */
+ li.remove();
+ if (((Item_cond*)cond)->argument_list()->elements <= 1)
+ replace_cond= true;
+ }
+
Item *item;
while ((item=li++))
{
- SEL_TREE *new_tree=get_mm_tree(param,item);
+ SEL_TREE *new_tree=get_mm_tree(param,li.ref());
if (new_tree == NULL || param->statement_should_be_aborted())
DBUG_RETURN(NULL);
tree= tree_or(param,tree,new_tree);
if (tree == NULL || tree->type == SEL_TREE::ALWAYS)
+ {
+ replacement_item= *li.ref();
break;
+ }
+
+ if (new_tree && new_tree->type == SEL_TREE::IMPOSSIBLE &&
+ param->remove_false_where_parts)
+ {
+ /*
+ This is a condition in form
+
+ cond = item1 OR ... OR item_i OR ... itemN
+
+ and item_i produces SEL_TREE(IMPOSSIBLE). We should remove item_i
+ from cond. This may cause 'cond' to become a degenerate,
+ one-way OR. In that case, we replace 'cond' with the remaining
+ item_i.
+ */
+ li.remove();
+ if (((Item_cond*)cond)->argument_list()->elements <= 1)
+ replace_cond= true;
+ }
+ else
+ replacement_item= *li.ref();
}
+
+ if (replace_cond)
+ *cond_ptr= replacement_item;
}
}
DBUG_RETURN(tree);
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 1ca245ea420..f602408ea82 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -994,7 +994,7 @@ class SQL_SELECT :public Sql_alloc {
{
key_map tmp;
tmp.set_all();
- return test_quick_select(thd, tmp, 0, limit, force_quick_range, FALSE) < 0;
+ return test_quick_select(thd, tmp, 0, limit, force_quick_range, FALSE, FALSE) < 0;
}
/*
RETURN
@@ -1011,7 +1011,7 @@ class SQL_SELECT :public Sql_alloc {
}
int test_quick_select(THD *thd, key_map keys, table_map prev_tables,
ha_rows limit, bool force_quick_range,
- bool ordered_output);
+ bool ordered_output, bool remove_false_parts_of_where);
};
@@ -1036,7 +1036,7 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
table_map read_tables, COND *conds,
bool allow_null_cond, int *error);
-bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond);
+bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond);
#ifdef WITH_PARTITION_STORAGE_ENGINE
bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 05c88a5f534..52f05e46e40 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -69,7 +69,7 @@ struct st_sargable_param;
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
static bool make_join_statistics(JOIN *join, List<TABLE_LIST> &leaves,
- COND *conds, DYNAMIC_ARRAY *keyuse);
+ DYNAMIC_ARRAY *keyuse);
static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
JOIN_TAB *join_tab,
uint tables, COND *conds,
@@ -1338,7 +1338,7 @@ TODO: make view to decide if it is possible to write to WHERE directly or make S
/* Calculate how to do the join */
THD_STAGE_INFO(thd, stage_statistics);
- if (make_join_statistics(this, select_lex->leaf_tables, conds, &keyuse) ||
+ if (make_join_statistics(this, select_lex->leaf_tables, &keyuse) ||
thd->is_fatal_error)
{
DBUG_PRINT("error",("Error: make_join_statistics() failed"));
@@ -3355,7 +3355,8 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
select->head=table;
table->reginfo.impossible_range=0;
if ((error= select->test_quick_select(thd, *(key_map *)keys,(table_map) 0,
- limit, 0, FALSE)) == 1)
+ limit, 0, FALSE,
+ TRUE /* remove_where_parts*/)) == 1)
DBUG_RETURN(select->quick->records);
if (error == -1)
{
@@ -3393,7 +3394,7 @@ typedef struct st_sargable_param
static bool
make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
- COND *conds, DYNAMIC_ARRAY *keyuse_array)
+ DYNAMIC_ARRAY *keyuse_array)
{
int error= 0;
TABLE *table;
@@ -3597,10 +3598,10 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
}
}
- if (conds || outer_join)
+ if (join->conds || outer_join)
{
if (update_ref_and_keys(join->thd, keyuse_array, stat, join->table_count,
- conds, ~outer_join, join->select_lex, &sargables))
+ join->conds, ~outer_join, join->select_lex, &sargables))
goto error;
/*
Keyparts without prefixes may be useful if this JOIN is a subquery, and
@@ -3844,8 +3845,9 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
}
join->impossible_where= false;
- if (conds && const_count)
- {
+ if (join->conds && const_count)
+ {
+ Item* &conds= join->conds;
conds->update_used_tables();
conds= remove_eq_conds(join->thd, conds, &join->cond_value);
if (conds && conds->type() == Item::COND_ITEM &&
@@ -3857,7 +3859,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
join->impossible_where= true;
conds=new Item_int((longlong) 0,1);
}
- join->conds= conds;
+
join->cond_equal= NULL;
if (conds)
{
@@ -3942,12 +3944,18 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
{
select= make_select(s->table, found_const_table_map,
found_const_table_map,
- *s->on_expr_ref ? *s->on_expr_ref : conds,
+ *s->on_expr_ref ? *s->on_expr_ref : join->conds,
1, &error);
if (!select)
goto error;
records= get_quick_record_count(join->thd, select, s->table,
&s->const_keys, join->row_limit);
+ /* Range analyzer could modify the condition. */
+ if (*s->on_expr_ref)
+ *s->on_expr_ref= select->cond;
+ else
+ join->conds= select->cond;
+
s->quick=select->quick;
s->needed_reg=select->needed_reg;
select->quick=0;
@@ -3958,7 +3966,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
if (join->thd->variables.optimizer_use_condition_selectivity > 1)
calculate_cond_selectivity_for_table(join->thd, s->table,
*s->on_expr_ref ?
- *s->on_expr_ref : conds);
+ s->on_expr_ref : &join->conds);
if (s->table->reginfo.impossible_range)
{
impossible_range= TRUE;
@@ -9658,7 +9666,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
OPTION_FOUND_ROWS ?
HA_POS_ERROR :
join->unit->select_limit_cnt), 0,
- FALSE) < 0)
+ FALSE, FALSE) < 0)
{
/*
Before reporting "Impossible WHERE" for the whole query
@@ -9672,7 +9680,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
OPTION_FOUND_ROWS ?
HA_POS_ERROR :
join->unit->select_limit_cnt),0,
- FALSE) < 0)
+ FALSE, FALSE) < 0)
DBUG_RETURN(1); // Impossible WHERE
}
else
@@ -18496,7 +18504,7 @@ test_if_quick_select(JOIN_TAB *tab)
tab->select->quick=0;
return tab->select->test_quick_select(tab->join->thd, tab->keys,
(table_map) 0, HA_POS_ERROR, 0,
- FALSE);
+ FALSE, /*remove where parts*/FALSE);
}
@@ -20169,7 +20177,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
OPTION_FOUND_ROWS) ?
HA_POS_ERROR :
tab->join->unit->select_limit_cnt,0,
- TRUE) <= 0;
+ TRUE, FALSE) <= 0;
if (res)
{
select->cond= save_cond;
@@ -20227,7 +20235,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
join->select_options & OPTION_FOUND_ROWS ?
HA_POS_ERROR :
join->unit->select_limit_cnt,
- TRUE, FALSE);
+ TRUE, FALSE, FALSE);
}
order_direction= best_key_direction;
/*