Fixed the bug mdev-12845.
This patch fills in a serious flaw in the code that supports condition pushdown into materialized views / derived tables. If a predicate happened to contain a reference to a mergeable view / derived table and it does not depended directly on the target materialized view / derived table then the predicate was not considered as a subject to pusdown to this view / derived table.
This commit is contained in:
parent
a8131e71f9
commit
9f3622191d
@ -554,7 +554,7 @@ EXPLAIN SELECT * FROM (SELECT * FROM t1) AS table1,
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 system NULL NULL NULL NULL 1
|
||||
1 PRIMARY <derived3> ref key0 key0 5 const 0
|
||||
3 DERIVED t2 ALL NULL NULL NULL NULL 2 Using temporary
|
||||
3 DERIVED t2 ALL NULL NULL NULL NULL 2 Using where; Using temporary
|
||||
Warnings:
|
||||
Note 1249 Select 4 was reduced during optimization
|
||||
DROP TABLE t1, t2;
|
||||
|
@ -7234,6 +7234,7 @@ EXPLAIN
|
||||
"materialized": {
|
||||
"query_block": {
|
||||
"select_id": 5,
|
||||
"having_condition": "s > 2",
|
||||
"filesort": {
|
||||
"sort_key": "t4.d",
|
||||
"temporary_table": {
|
||||
@ -7605,6 +7606,7 @@ EXPLAIN
|
||||
"materialized": {
|
||||
"query_block": {
|
||||
"select_id": 3,
|
||||
"having_condition": "s < 50",
|
||||
"filesort": {
|
||||
"sort_key": "t3.a",
|
||||
"temporary_table": {
|
||||
@ -7755,9 +7757,14 @@ EXPLAIN
|
||||
"select_id": 4,
|
||||
"table": {
|
||||
"table_name": "t",
|
||||
"access_type": "ALL",
|
||||
"access_type": "range",
|
||||
"possible_keys": ["PRIMARY"],
|
||||
"key": "PRIMARY",
|
||||
"key_length": "4",
|
||||
"used_key_parts": ["pk"],
|
||||
"rows": 2,
|
||||
"filtered": 100
|
||||
"filtered": 100,
|
||||
"index_condition": "t.pk > 2"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8447,3 +8454,221 @@ WHERE row <> order_number;
|
||||
row order_number
|
||||
14 51
|
||||
DROP TABLE sales_documents;
|
||||
#
|
||||
# MDEV-12845: pushdown from merged derived using equalities
|
||||
#
|
||||
create table t1 (a int);
|
||||
insert into t1 values
|
||||
(4), (8), (5), (3), (10), (2), (7);
|
||||
create table t2 (b int, c int);
|
||||
insert into t2 values
|
||||
(2,1), (5,2), (2,2), (4,1), (4,3),
|
||||
(5,3), (2,4), (4,6), (2,1);
|
||||
create view v1 as
|
||||
select b, sum(c) as s from t2 group by b;
|
||||
create view v2 as
|
||||
select distinct b, c from t2;
|
||||
create view v3 as
|
||||
select b, max(c) as m from t2 group by b;
|
||||
select b
|
||||
from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
|
||||
where b > 2;
|
||||
b
|
||||
4
|
||||
5
|
||||
explain format=json select b
|
||||
from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
|
||||
where b > 2;
|
||||
EXPLAIN
|
||||
{
|
||||
"query_block": {
|
||||
"select_id": 1,
|
||||
"table": {
|
||||
"table_name": "t1",
|
||||
"access_type": "ALL",
|
||||
"rows": 7,
|
||||
"filtered": 100,
|
||||
"attached_condition": "t1.a > 2 and t1.a is not null"
|
||||
},
|
||||
"table": {
|
||||
"table_name": "<derived3>",
|
||||
"access_type": "ref",
|
||||
"possible_keys": ["key0"],
|
||||
"key": "key0",
|
||||
"key_length": "5",
|
||||
"used_key_parts": ["b"],
|
||||
"ref": ["test.t1.a"],
|
||||
"rows": 2,
|
||||
"filtered": 100,
|
||||
"materialized": {
|
||||
"query_block": {
|
||||
"select_id": 3,
|
||||
"filesort": {
|
||||
"sort_key": "t2.b",
|
||||
"temporary_table": {
|
||||
"table": {
|
||||
"table_name": "t2",
|
||||
"access_type": "ALL",
|
||||
"rows": 9,
|
||||
"filtered": 100,
|
||||
"attached_condition": "t2.b > 2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
select a
|
||||
from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
|
||||
where a > 2;
|
||||
a
|
||||
4
|
||||
5
|
||||
explain format=json select a
|
||||
from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
|
||||
where a > 2;
|
||||
EXPLAIN
|
||||
{
|
||||
"query_block": {
|
||||
"select_id": 1,
|
||||
"table": {
|
||||
"table_name": "t1",
|
||||
"access_type": "ALL",
|
||||
"rows": 7,
|
||||
"filtered": 100,
|
||||
"attached_condition": "t1.a > 2 and t1.a is not null"
|
||||
},
|
||||
"table": {
|
||||
"table_name": "<derived3>",
|
||||
"access_type": "ref",
|
||||
"possible_keys": ["key0"],
|
||||
"key": "key0",
|
||||
"key_length": "5",
|
||||
"used_key_parts": ["b"],
|
||||
"ref": ["test.t1.a"],
|
||||
"rows": 2,
|
||||
"filtered": 100,
|
||||
"materialized": {
|
||||
"query_block": {
|
||||
"select_id": 3,
|
||||
"filesort": {
|
||||
"sort_key": "t2.b",
|
||||
"temporary_table": {
|
||||
"table": {
|
||||
"table_name": "t2",
|
||||
"access_type": "ALL",
|
||||
"rows": 9,
|
||||
"filtered": 100,
|
||||
"attached_condition": "t2.b > 2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
select a
|
||||
from ( select t1.a, v2.b, v2.c from t1, v2 where t1.a = v2.b ) as t
|
||||
where a > 2;
|
||||
a
|
||||
4
|
||||
4
|
||||
4
|
||||
5
|
||||
5
|
||||
explain format=json select a
|
||||
from ( select t1.a, v2.b, v2.c from t1, v2 where t1.a = v2.b ) as t
|
||||
where a > 2;
|
||||
EXPLAIN
|
||||
{
|
||||
"query_block": {
|
||||
"select_id": 1,
|
||||
"table": {
|
||||
"table_name": "t1",
|
||||
"access_type": "ALL",
|
||||
"rows": 7,
|
||||
"filtered": 100,
|
||||
"attached_condition": "t1.a > 2 and t1.a is not null"
|
||||
},
|
||||
"table": {
|
||||
"table_name": "<derived3>",
|
||||
"access_type": "ref",
|
||||
"possible_keys": ["key0"],
|
||||
"key": "key0",
|
||||
"key_length": "5",
|
||||
"used_key_parts": ["b"],
|
||||
"ref": ["test.t1.a"],
|
||||
"rows": 2,
|
||||
"filtered": 100,
|
||||
"materialized": {
|
||||
"query_block": {
|
||||
"select_id": 3,
|
||||
"temporary_table": {
|
||||
"table": {
|
||||
"table_name": "t2",
|
||||
"access_type": "ALL",
|
||||
"rows": 9,
|
||||
"filtered": 100,
|
||||
"attached_condition": "t2.b > 2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
select a
|
||||
from ( select t1.a, v3.b, v3.m from t1, v3 where t1.a = v3.m ) as t
|
||||
where a > 2;
|
||||
a
|
||||
4
|
||||
3
|
||||
explain format=json select a
|
||||
from ( select t1.a, v3.b, v3.m from t1, v3 where t1.a = v3.m ) as t
|
||||
where a > 2;
|
||||
EXPLAIN
|
||||
{
|
||||
"query_block": {
|
||||
"select_id": 1,
|
||||
"table": {
|
||||
"table_name": "t1",
|
||||
"access_type": "ALL",
|
||||
"rows": 7,
|
||||
"filtered": 100,
|
||||
"attached_condition": "t1.a > 2 and t1.a is not null"
|
||||
},
|
||||
"table": {
|
||||
"table_name": "<derived3>",
|
||||
"access_type": "ref",
|
||||
"possible_keys": ["key0"],
|
||||
"key": "key0",
|
||||
"key_length": "5",
|
||||
"used_key_parts": ["m"],
|
||||
"ref": ["test.t1.a"],
|
||||
"rows": 2,
|
||||
"filtered": 100,
|
||||
"materialized": {
|
||||
"query_block": {
|
||||
"select_id": 3,
|
||||
"having_condition": "m > 2",
|
||||
"filesort": {
|
||||
"sort_key": "t2.b",
|
||||
"temporary_table": {
|
||||
"table": {
|
||||
"table_name": "t2",
|
||||
"access_type": "ALL",
|
||||
"rows": 9,
|
||||
"filtered": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
drop view v1,v2,v3;
|
||||
drop table t1,t2;
|
||||
|
@ -900,7 +900,7 @@ EXPLAIN
|
||||
"access_type": "ALL",
|
||||
"rows": 11,
|
||||
"filtered": 100,
|
||||
"attached_condition": "t1.f1 in (2,3)"
|
||||
"attached_condition": "t1.f1 < 7 and t1.f1 in (2,3)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1107,7 +1107,7 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 system NULL NULL NULL NULL 1
|
||||
1 PRIMARY t2 ref a a 4 const 1 Using index
|
||||
1 PRIMARY <derived2> ref key0 key0 8 const,const 1
|
||||
2 DERIVED t3 ALL NULL NULL NULL NULL 12 Using temporary; Using filesort
|
||||
2 DERIVED t3 ALL NULL NULL NULL NULL 12 Using where; Using temporary; Using filesort
|
||||
SELECT * FROM t1, t2, v1 WHERE t2.a=t1.a AND t2.a=v1.a AND t2.a=v1.b;
|
||||
a a a b
|
||||
c c c c
|
||||
|
@ -1452,3 +1452,60 @@ SELECT * FROM
|
||||
WHERE row <> order_number;
|
||||
|
||||
DROP TABLE sales_documents;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-12845: pushdown from merged derived using equalities
|
||||
--echo #
|
||||
|
||||
create table t1 (a int);
|
||||
insert into t1 values
|
||||
(4), (8), (5), (3), (10), (2), (7);
|
||||
|
||||
create table t2 (b int, c int);
|
||||
insert into t2 values
|
||||
(2,1), (5,2), (2,2), (4,1), (4,3),
|
||||
(5,3), (2,4), (4,6), (2,1);
|
||||
|
||||
create view v1 as
|
||||
select b, sum(c) as s from t2 group by b;
|
||||
|
||||
create view v2 as
|
||||
select distinct b, c from t2;
|
||||
|
||||
create view v3 as
|
||||
select b, max(c) as m from t2 group by b;
|
||||
|
||||
let $q1=
|
||||
select b
|
||||
from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
|
||||
where b > 2;
|
||||
|
||||
eval $q1;
|
||||
eval explain format=json $q1;
|
||||
|
||||
let $q2=
|
||||
select a
|
||||
from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
|
||||
where a > 2;
|
||||
|
||||
eval $q2;
|
||||
eval explain format=json $q2;
|
||||
|
||||
let $q3=
|
||||
select a
|
||||
from ( select t1.a, v2.b, v2.c from t1, v2 where t1.a = v2.b ) as t
|
||||
where a > 2;
|
||||
|
||||
eval $q3;
|
||||
eval explain format=json $q3;
|
||||
|
||||
let $q4=
|
||||
select a
|
||||
from ( select t1.a, v3.b, v3.m from t1, v3 where t1.a = v3.m ) as t
|
||||
where a > 2;
|
||||
|
||||
eval $q4;
|
||||
eval explain format=json $q4;
|
||||
|
||||
drop view v1,v2,v3;
|
||||
drop table t1,t2;
|
||||
|
305
sql/item.cc
305
sql/item.cc
@ -7120,121 +7120,182 @@ Item *Item_field::update_value_transformer(THD *thd, uchar *select_arg)
|
||||
}
|
||||
|
||||
|
||||
Item *Item_field::derived_field_transformer_for_having(THD *thd, uchar *arg)
|
||||
static
|
||||
Item *get_field_item_for_having(THD *thd, Item *item, st_select_lex *sel)
|
||||
{
|
||||
st_select_lex *sl= (st_select_lex *)arg;
|
||||
table_map map= sl->master_unit()->derived->table->map;
|
||||
if (!((Item_field*)this)->item_equal)
|
||||
{
|
||||
if (used_tables() == map)
|
||||
{
|
||||
Item_ref *rf=
|
||||
new (thd->mem_root) Item_ref(thd, &sl->context,
|
||||
NullS, NullS,
|
||||
((Item_field*) this)->field_name);
|
||||
if (!rf)
|
||||
return 0;
|
||||
return rf;
|
||||
}
|
||||
}
|
||||
DBUG_ASSERT(item->type() == Item::FIELD_ITEM ||
|
||||
(item->type() == Item::REF_ITEM &&
|
||||
((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF));
|
||||
Item_field *field_item= NULL;
|
||||
table_map map= sel->master_unit()->derived->table->map;
|
||||
Item_equal *item_equal= item->get_item_equal();
|
||||
if (!item_equal)
|
||||
field_item= (Item_field *)(item->real_item());
|
||||
else
|
||||
{
|
||||
Item_equal *cond= (Item_equal *) ((Item_field*)this)->item_equal;
|
||||
Item_equal_fields_iterator li(*cond);
|
||||
Item *item;
|
||||
while ((item=li++))
|
||||
Item_equal_fields_iterator li(*item_equal);
|
||||
Item *equal_item;
|
||||
while ((equal_item= li++))
|
||||
{
|
||||
if (item->used_tables() == map && item->real_item()->type() == FIELD_ITEM)
|
||||
if (equal_item->used_tables() == map)
|
||||
{
|
||||
Item_ref *rf=
|
||||
new (thd->mem_root) Item_ref(thd, &sl->context,
|
||||
NullS, NullS,
|
||||
((Item_field*) (item->real_item()))->field_name);
|
||||
if (!rf)
|
||||
return 0;
|
||||
return rf;
|
||||
field_item= (Item_field *)(equal_item->real_item());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
if (field_item)
|
||||
{
|
||||
Item_ref *ref= new (thd->mem_root) Item_ref(thd, &sel->context,
|
||||
NullS, NullS,
|
||||
field_item->field_name);
|
||||
return ref;
|
||||
}
|
||||
DBUG_ASSERT(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
Item *Item_field::derived_field_transformer_for_having(THD *thd, uchar *arg)
|
||||
{
|
||||
st_select_lex *sel= (st_select_lex *)arg;
|
||||
table_map tab_map= sel->master_unit()->derived->table->map;
|
||||
if (item_equal && !(item_equal->used_tables() & tab_map))
|
||||
return this;
|
||||
if (!item_equal && used_tables() != tab_map)
|
||||
return this;
|
||||
return get_field_item_for_having(thd, this, sel);
|
||||
}
|
||||
|
||||
|
||||
Item *Item_direct_view_ref::derived_field_transformer_for_having(THD *thd,
|
||||
uchar *arg)
|
||||
{
|
||||
st_select_lex *sel= (st_select_lex *)arg;
|
||||
table_map tab_map= sel->master_unit()->derived->table->map;
|
||||
if (item_equal && !(item_equal->used_tables() & tab_map))
|
||||
return this;
|
||||
if (!item_equal && used_tables() != tab_map)
|
||||
return this;
|
||||
return get_field_item_for_having(thd, this, sel);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
Item *find_producing_item(Item *item, st_select_lex *sel)
|
||||
{
|
||||
DBUG_ASSERT(item->type() == Item::FIELD_ITEM ||
|
||||
(item->type() == Item::REF_ITEM &&
|
||||
((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF));
|
||||
Item *producing_item;
|
||||
Item_field *field_item= NULL;
|
||||
Item_equal *item_equal= item->get_item_equal();
|
||||
table_map tab_map= sel->master_unit()->derived->table->map;
|
||||
if (item->used_tables() == tab_map)
|
||||
field_item= (Item_field *) (item->real_item());
|
||||
if (!field_item && item_equal)
|
||||
{
|
||||
Item_equal_fields_iterator it(*item_equal);
|
||||
Item *equal_item;
|
||||
while ((equal_item= it++))
|
||||
{
|
||||
if (equal_item->used_tables() == tab_map)
|
||||
{
|
||||
field_item= (Item_field *) (equal_item->real_item());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
List_iterator_fast<Item> li(sel->item_list);
|
||||
if (field_item)
|
||||
{
|
||||
uint field_no= field_item->field->field_index;
|
||||
for (uint i= 0; i <= field_no; i++)
|
||||
producing_item= li++;
|
||||
return producing_item;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Item *Item_field::derived_field_transformer_for_where(THD *thd, uchar *arg)
|
||||
{
|
||||
Item *producing_item;
|
||||
st_select_lex *sl= (st_select_lex *)arg;
|
||||
List_iterator_fast<Item> li(sl->item_list);
|
||||
table_map map= sl->master_unit()->derived->table->map;
|
||||
if (used_tables() == map)
|
||||
{
|
||||
uint field_no= ((Item_field*) this)->field->field_index;
|
||||
for (uint i= 0; i <= field_no; i++)
|
||||
producing_item= li++;
|
||||
st_select_lex *sel= (st_select_lex *)arg;
|
||||
Item *producing_item= find_producing_item(this, sel);
|
||||
if (producing_item)
|
||||
return producing_item->build_clone(thd, thd->mem_root);
|
||||
}
|
||||
else if (((Item_field*)this)->item_equal)
|
||||
return this;
|
||||
}
|
||||
|
||||
Item *Item_direct_view_ref::derived_field_transformer_for_where(THD *thd,
|
||||
uchar *arg)
|
||||
{
|
||||
if (item_equal)
|
||||
{
|
||||
Item_equal *cond= (Item_equal *) ((Item_field*)this)->item_equal;
|
||||
Item_equal_fields_iterator it(*cond);
|
||||
Item *item;
|
||||
while ((item=it++))
|
||||
{
|
||||
if (item->used_tables() == map && item->real_item()->type() == FIELD_ITEM)
|
||||
{
|
||||
Item_field *field_item= (Item_field *) (item->real_item());
|
||||
li.rewind();
|
||||
uint field_no= field_item->field->field_index;
|
||||
for (uint i= 0; i <= field_no; i++)
|
||||
producing_item= li++;
|
||||
return producing_item->build_clone(thd, thd->mem_root);
|
||||
}
|
||||
}
|
||||
st_select_lex *sel= (st_select_lex *)arg;
|
||||
Item *producing_item= find_producing_item(this, sel);
|
||||
DBUG_ASSERT (producing_item != NULL);
|
||||
return producing_item->build_clone(thd, thd->mem_root);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
static
|
||||
Grouping_tmp_field *find_matching_grouping_field(Item *item,
|
||||
st_select_lex *sel)
|
||||
{
|
||||
DBUG_ASSERT(item->type() == Item::FIELD_ITEM ||
|
||||
(item->type() == Item::REF_ITEM &&
|
||||
((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF));
|
||||
List_iterator<Grouping_tmp_field> li(sel->grouping_tmp_fields);
|
||||
Grouping_tmp_field *gr_field;
|
||||
Item_field *field_item= (Item_field *) (item->real_item());
|
||||
while ((gr_field= li++))
|
||||
{
|
||||
if (field_item->field == gr_field->tmp_field)
|
||||
return gr_field;
|
||||
}
|
||||
Item_equal *item_equal= item->get_item_equal();
|
||||
if (item_equal)
|
||||
{
|
||||
Item_equal_fields_iterator it(*item_equal);
|
||||
Item *equal_item;
|
||||
while ((equal_item= it++))
|
||||
{
|
||||
field_item= (Item_field *) (equal_item->real_item());
|
||||
li.rewind();
|
||||
while ((gr_field= li++))
|
||||
{
|
||||
if (field_item->field == gr_field->tmp_field)
|
||||
return gr_field;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
Item *Item_field::derived_grouping_field_transformer_for_where(THD *thd,
|
||||
uchar *arg)
|
||||
{
|
||||
st_select_lex *sl= (st_select_lex *)arg;
|
||||
List_iterator<Grouping_tmp_field> li(sl->grouping_tmp_fields);
|
||||
Grouping_tmp_field *field;
|
||||
table_map map= sl->master_unit()->derived->table->map;
|
||||
if (used_tables() == map)
|
||||
{
|
||||
while ((field=li++))
|
||||
{
|
||||
if (((Item_field*) this)->field == field->tmp_field)
|
||||
return field->producing_item->build_clone(thd, thd->mem_root);
|
||||
}
|
||||
}
|
||||
else if (((Item_field*)this)->item_equal)
|
||||
{
|
||||
Item_equal *cond= (Item_equal *) ((Item_field*)this)->item_equal;
|
||||
Item_equal_fields_iterator it(*cond);
|
||||
Item *item;
|
||||
while ((item=it++))
|
||||
{
|
||||
if (item->used_tables() == map && item->real_item()->type() == FIELD_ITEM)
|
||||
{
|
||||
Item_field *field_item= (Item_field *) (item->real_item());
|
||||
li.rewind();
|
||||
while ((field=li++))
|
||||
{
|
||||
if (field_item->field == field->tmp_field)
|
||||
{
|
||||
return field->producing_item->build_clone(thd, thd->mem_root);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
st_select_lex *sel= (st_select_lex *)arg;
|
||||
Grouping_tmp_field *gr_field= find_matching_grouping_field(this, sel);
|
||||
if (gr_field)
|
||||
return gr_field->producing_item->build_clone(thd, thd->mem_root);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
Item *
|
||||
Item_direct_view_ref::derived_grouping_field_transformer_for_where(THD *thd,
|
||||
uchar *arg)
|
||||
{
|
||||
if (!item_equal)
|
||||
return this;
|
||||
st_select_lex *sel= (st_select_lex *)arg;
|
||||
Grouping_tmp_field *gr_field= find_matching_grouping_field(this, sel);
|
||||
return gr_field->producing_item->build_clone(thd, thd->mem_root);
|
||||
}
|
||||
|
||||
void Item_field::print(String *str, enum_query_type query_type)
|
||||
{
|
||||
if (field && field->table->const_table &&
|
||||
@ -8702,6 +8763,32 @@ Item *Item_direct_view_ref::replace_equal_field(THD *thd, uchar *arg)
|
||||
}
|
||||
|
||||
|
||||
bool Item_direct_view_ref::excl_dep_on_table(table_map tab_map)
|
||||
{
|
||||
table_map used= used_tables();
|
||||
if (used & OUTER_REF_TABLE_BIT)
|
||||
return false;
|
||||
if (!(used & ~tab_map))
|
||||
return true;
|
||||
if (item_equal)
|
||||
{
|
||||
DBUG_ASSERT(real_item()->type() == Item::FIELD_ITEM);
|
||||
return item_equal->used_tables() & tab_map;
|
||||
}
|
||||
return (*ref)->excl_dep_on_table(tab_map);
|
||||
}
|
||||
|
||||
bool Item_direct_view_ref::excl_dep_on_grouping_fields(st_select_lex *sel)
|
||||
{
|
||||
if (item_equal)
|
||||
{
|
||||
DBUG_ASSERT(real_item()->type() == Item::FIELD_ITEM);
|
||||
return find_matching_grouping_field(this, sel) != NULL;
|
||||
}
|
||||
return (*ref)->excl_dep_on_grouping_fields(sel);
|
||||
}
|
||||
|
||||
|
||||
bool Item_default_value::eq(const Item *item, bool binary_cmp) const
|
||||
{
|
||||
return item->type() == DEFAULT_VALUE_ITEM &&
|
||||
@ -10613,46 +10700,16 @@ const char *dbug_print_unit(SELECT_LEX_UNIT *un)
|
||||
|
||||
#endif /*DBUG_OFF*/
|
||||
|
||||
bool Item_field::exclusive_dependence_on_table_processor(void *map)
|
||||
bool Item_field::excl_dep_on_table(table_map tab_map)
|
||||
{
|
||||
table_map tab_map= *((table_map *) map);
|
||||
return !((used_tables() == tab_map ||
|
||||
(item_equal && item_equal->used_tables() & tab_map)));
|
||||
return used_tables() == tab_map ||
|
||||
(item_equal && (item_equal->used_tables() & tab_map));
|
||||
}
|
||||
|
||||
bool Item_field::exclusive_dependence_on_grouping_fields_processor(void *arg)
|
||||
bool
|
||||
Item_field::excl_dep_on_grouping_fields(st_select_lex *sel)
|
||||
{
|
||||
st_select_lex *sl= (st_select_lex *)arg;
|
||||
List_iterator<Grouping_tmp_field> li(sl->grouping_tmp_fields);
|
||||
Grouping_tmp_field *field;
|
||||
table_map map= sl->master_unit()->derived->table->map;
|
||||
if (used_tables() == map)
|
||||
{
|
||||
while ((field=li++))
|
||||
{
|
||||
if (((Item_field*) this)->field == field->tmp_field)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (((Item_field*)this)->item_equal)
|
||||
{
|
||||
Item_equal *cond= (Item_equal *) ((Item_field*)this)->item_equal;
|
||||
Item_equal_fields_iterator it(*cond);
|
||||
Item *item;
|
||||
while ((item=it++))
|
||||
{
|
||||
if (item->used_tables() == map && item->real_item()->type() == FIELD_ITEM)
|
||||
{
|
||||
li.rewind();
|
||||
while ((field=li++))
|
||||
{
|
||||
if (((Item_field *)(item->real_item()))->field == field->tmp_field)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return find_matching_grouping_field(this, sel) != NULL;
|
||||
}
|
||||
|
||||
void Item::register_in(THD *thd)
|
||||
|
66
sql/item.h
66
sql/item.h
@ -1580,8 +1580,20 @@ public:
|
||||
virtual bool limit_index_condition_pushdown_processor(void *arg) { return 0; }
|
||||
virtual bool exists2in_processor(void *arg) { return 0; }
|
||||
virtual bool find_selective_predicates_list_processor(void *arg) { return 0; }
|
||||
virtual bool exclusive_dependence_on_table_processor(void *arg) { return 0; }
|
||||
virtual bool exclusive_dependence_on_grouping_fields_processor(void *arg) { return 0; }
|
||||
|
||||
/*
|
||||
TRUE if the expression depends only on the table indicated by tab_map
|
||||
or can be converted to such an exression using equalities.
|
||||
Not to be used for AND/OR formulas.
|
||||
*/
|
||||
virtual bool excl_dep_on_table(table_map tab_map) { return false; }
|
||||
/*
|
||||
TRUE if the expression depends only on grouping fields of sel
|
||||
or can be converted to such an exression using equalities.
|
||||
Not to be used for AND/OR formulas.
|
||||
*/
|
||||
virtual bool excl_dep_on_grouping_fields(st_select_lex *sel) { return false; }
|
||||
|
||||
virtual bool switch_to_nullable_fields_processor(void *arg) { return 0; }
|
||||
virtual bool find_function_processor (void *arg) { return 0; }
|
||||
/*
|
||||
@ -2633,8 +2645,8 @@ public:
|
||||
Item *derived_field_transformer_for_where(THD *thd, uchar *arg);
|
||||
Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg);
|
||||
virtual void print(String *str, enum_query_type query_type);
|
||||
bool exclusive_dependence_on_table_processor(void *map);
|
||||
bool exclusive_dependence_on_grouping_fields_processor(void *arg);
|
||||
bool excl_dep_on_table(table_map tab_map);
|
||||
bool excl_dep_on_grouping_fields(st_select_lex *sel);
|
||||
bool cleanup_excluding_fields_processor(void *arg)
|
||||
{ return field ? 0 : cleanup_processor(arg); }
|
||||
bool cleanup_excluding_const_fields_processor(void *arg)
|
||||
@ -3853,6 +3865,28 @@ protected:
|
||||
}
|
||||
bool transform_args(THD *thd, Item_transformer transformer, uchar *arg);
|
||||
void propagate_equal_fields(THD *, const Item::Context &, COND_EQUAL *);
|
||||
bool excl_dep_on_table(table_map tab_map)
|
||||
{
|
||||
for (uint i= 0; i < arg_count; i++)
|
||||
{
|
||||
if (args[i]->const_item())
|
||||
continue;
|
||||
if (!args[i]->excl_dep_on_table(tab_map))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool excl_dep_on_grouping_fields(st_select_lex *sel)
|
||||
{
|
||||
for (uint i= 0; i < arg_count; i++)
|
||||
{
|
||||
if (args[i]->const_item())
|
||||
continue;
|
||||
if (!args[i]->excl_dep_on_grouping_fields(sel))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
Item_args(void)
|
||||
:args(NULL), arg_count(0)
|
||||
@ -4321,10 +4355,15 @@ public:
|
||||
}
|
||||
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
|
||||
{ return get_item_copy<Item_ref>(thd, mem_root, this); }
|
||||
bool exclusive_dependence_on_table_processor(void *map)
|
||||
{ return depended_from != NULL; }
|
||||
bool exclusive_dependence_on_grouping_fields_processor(void *arg)
|
||||
{ return depended_from != NULL; }
|
||||
bool excl_dep_on_table(table_map tab_map)
|
||||
{
|
||||
table_map used= used_tables();
|
||||
if (used & OUTER_REF_TABLE_BIT)
|
||||
return false;
|
||||
return (used == tab_map) || (*ref)->excl_dep_on_table(tab_map);
|
||||
}
|
||||
bool excl_dep_on_grouping_fields(st_select_lex *sel)
|
||||
{ return (*ref)->excl_dep_on_grouping_fields(sel); }
|
||||
bool cleanup_excluding_fields_processor(void *arg)
|
||||
{
|
||||
Item *item= real_item();
|
||||
@ -4621,13 +4660,20 @@ public:
|
||||
return (*ref)->walk(processor, walk_subquery, arg) ||
|
||||
(this->*processor)(arg);
|
||||
}
|
||||
bool view_used_tables_processor(void *arg)
|
||||
bool view_used_tables_processor(void *arg)
|
||||
{
|
||||
TABLE_LIST *view_arg= (TABLE_LIST *) arg;
|
||||
if (view_arg == view)
|
||||
view_arg->view_used_tables|= (*ref)->used_tables();
|
||||
return 0;
|
||||
}
|
||||
bool excl_dep_on_table(table_map tab_map);
|
||||
bool excl_dep_on_grouping_fields(st_select_lex *sel);
|
||||
Item *derived_field_transformer_for_having(THD *thd, uchar *arg);
|
||||
Item *derived_field_transformer_for_where(THD *thd, uchar *arg);
|
||||
Item *derived_grouping_field_transformer_for_where(THD *thd,
|
||||
uchar *arg);
|
||||
|
||||
void save_val(Field *to)
|
||||
{
|
||||
if (check_null_ref())
|
||||
@ -4709,6 +4755,8 @@ public:
|
||||
item_equal= NULL;
|
||||
Item_direct_ref::cleanup();
|
||||
}
|
||||
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
|
||||
{ return get_item_copy<Item_direct_view_ref>(thd, mem_root, this); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -2395,6 +2395,14 @@ public:
|
||||
void set_context_field(Item_field *ctx_field) { context_field= ctx_field; }
|
||||
void set_link_equal_fields(bool flag) { link_equal_fields= flag; }
|
||||
Item* get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; }
|
||||
/*
|
||||
This does not comply with the specification of the virtual method,
|
||||
but Item_equal items are processed distinguishly anyway
|
||||
*/
|
||||
bool excl_dep_on_table(table_map tab_map)
|
||||
{
|
||||
return used_tables() & tab_map;
|
||||
}
|
||||
friend class Item_equal_fields_iterator;
|
||||
bool count_sargable_conds(void *arg);
|
||||
friend class Item_equal_iterator<List_iterator_fast,Item>;
|
||||
|
@ -316,6 +316,19 @@ public:
|
||||
return this;
|
||||
}
|
||||
|
||||
bool excl_dep_on_table(table_map tab_map)
|
||||
{
|
||||
if (used_tables() & OUTER_REF_TABLE_BIT)
|
||||
return false;
|
||||
return !(used_tables() & ~tab_map) ||
|
||||
Item_args::excl_dep_on_table(tab_map);
|
||||
}
|
||||
|
||||
bool excl_dep_on_grouping_fields(st_select_lex *sel)
|
||||
{
|
||||
return Item_args::excl_dep_on_grouping_fields(sel);
|
||||
}
|
||||
|
||||
/*
|
||||
We assume the result of any function that has a TIMESTAMP argument to be
|
||||
timezone-dependent, since a TIMESTAMP value in both numeric and string
|
||||
|
@ -126,6 +126,16 @@ public:
|
||||
return this;
|
||||
}
|
||||
|
||||
bool excl_dep_on_table(table_map tab_map)
|
||||
{
|
||||
return Item_args::excl_dep_on_table(tab_map);
|
||||
}
|
||||
|
||||
bool excl_dep_on_grouping_fields(st_select_lex *sel)
|
||||
{
|
||||
return Item_args::excl_dep_on_grouping_fields(sel);
|
||||
}
|
||||
|
||||
bool check_vcol_func_processor(void *arg) {return FALSE; }
|
||||
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
|
||||
{ return get_item_copy<Item_row>(thd, mem_root, this); }
|
||||
|
@ -1246,7 +1246,7 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
|
||||
Item *cond_over_grouping_fields;
|
||||
sl->collect_grouping_fields(thd);
|
||||
sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy,
|
||||
&Item::exclusive_dependence_on_grouping_fields_processor);
|
||||
derived);
|
||||
cond_over_grouping_fields=
|
||||
sl->build_cond_for_grouping_fields(thd, extracted_cond_copy, true);
|
||||
|
||||
@ -1285,7 +1285,8 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
|
||||
if (!extracted_cond_copy)
|
||||
continue;
|
||||
|
||||
extracted_cond_copy->walk(&Item::cleanup_processor, 0, 0);
|
||||
extracted_cond_copy->walk(&Item::cleanup_excluding_const_fields_processor,
|
||||
0, 0);
|
||||
sl->cond_pushed_into_having= extracted_cond_copy;
|
||||
}
|
||||
thd->lex->current_select= save_curr_select;
|
||||
|
@ -5006,8 +5006,9 @@ void st_select_lex::collect_grouping_fields(THD *thd)
|
||||
from cond.
|
||||
*/
|
||||
|
||||
void st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond,
|
||||
Item_processor check_processor)
|
||||
void
|
||||
st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond,
|
||||
TABLE_LIST *derived)
|
||||
{
|
||||
cond->clear_extraction_flag();
|
||||
if (cond->type() == Item::COND_ITEM)
|
||||
@ -5020,7 +5021,7 @@ void st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond,
|
||||
Item *item;
|
||||
while ((item=li++))
|
||||
{
|
||||
check_cond_extraction_for_grouping_fields(item, check_processor);
|
||||
check_cond_extraction_for_grouping_fields(item, derived);
|
||||
if (item->get_extraction_flag() != NO_EXTRACTION_FL)
|
||||
{
|
||||
count++;
|
||||
@ -5041,10 +5042,12 @@ void st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond,
|
||||
item->clear_extraction_flag();
|
||||
}
|
||||
}
|
||||
else
|
||||
cond->set_extraction_flag(cond->walk(check_processor,
|
||||
0, (uchar *) this) ?
|
||||
NO_EXTRACTION_FL : FULL_EXTRACTION_FL);
|
||||
else
|
||||
{
|
||||
int fl= cond->excl_dep_on_grouping_fields(this) ?
|
||||
FULL_EXTRACTION_FL : NO_EXTRACTION_FL;
|
||||
cond->set_extraction_flag(fl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1139,7 +1139,7 @@ public:
|
||||
bool check_subqueries_with_recursive_references();
|
||||
void collect_grouping_fields(THD *thd);
|
||||
void check_cond_extraction_for_grouping_fields(Item *cond,
|
||||
Item_processor processor);
|
||||
TABLE_LIST *derived);
|
||||
Item *build_cond_for_grouping_fields(THD *thd, Item *cond,
|
||||
bool no_to_clones);
|
||||
|
||||
|
@ -8128,8 +8128,7 @@ void TABLE_LIST::check_pushable_cond_for_table(Item *cond)
|
||||
item->clear_extraction_flag();
|
||||
}
|
||||
}
|
||||
else if (cond->walk(&Item::exclusive_dependence_on_table_processor,
|
||||
0, (void *) &tab_map))
|
||||
else if (!cond->excl_dep_on_table(tab_map))
|
||||
cond->set_extraction_flag(NO_EXTRACTION_FL);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user