Skip to content
/ server Public
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions mysql-test/main/subselect4.result
Original file line number Diff line number Diff line change
Expand Up @@ -3373,4 +3373,50 @@ CREATE TABLE t(c INT);
SELECT (SELECT 0 GROUP BY c HAVING (SELECT c)) FROM t GROUP BY c;
(SELECT 0 GROUP BY c HAVING (SELECT c))
DROP TABLE t;
#
# MDEV-35168 subselects with outer references to derived tables may be incorrectly evaluated as constant
#
create table t1 (a int);
insert into t1 (a) values (5);
select 1 as one from
(
t1 as t2 left join
(
select 0 as c1
from t1
) as dt1
on dt1.c1 = t2.a
)
where exists
(
select 1 from t1
where dt1.c1 <> t1.a
);
one
create view v1 as ( select 0 as c1 from t1 );
select 1 as one from
(
t1 left join v1
on v1.c1 = t1.a
)
where exists
(
select 1 from t1
where v1.c1 <> t1.a
);
one
with cte1 as ( select 0 as c1 from t1 )
select 1 as one from
(
t1 left join cte1
on cte1.c1 = t1.a
)
where exists
(
select 1 from t1
where cte1.c1 <> t1.a
);
one
drop view v1;
drop table t1;
# End of 10.11 tests
50 changes: 50 additions & 0 deletions mysql-test/main/subselect4.test
Original file line number Diff line number Diff line change
Expand Up @@ -2695,4 +2695,54 @@ CREATE TABLE t(c INT);
SELECT (SELECT 0 GROUP BY c HAVING (SELECT c)) FROM t GROUP BY c;
DROP TABLE t;

--echo #
--echo # MDEV-35168 subselects with outer references to derived tables may be incorrectly evaluated as constant
--echo #

create table t1 (a int);
insert into t1 (a) values (5);

select 1 as one from
(
t1 as t2 left join
(
select 0 as c1
from t1
) as dt1
on dt1.c1 = t2.a
)
where exists
(
select 1 from t1
where dt1.c1 <> t1.a
);

create view v1 as ( select 0 as c1 from t1 );

select 1 as one from
(
t1 left join v1
on v1.c1 = t1.a
)
where exists
(
select 1 from t1
where v1.c1 <> t1.a
);

with cte1 as ( select 0 as c1 from t1 )
select 1 as one from
(
t1 left join cte1
on cte1.c1 = t1.a
)
where exists
(
select 1 from t1
where cte1.c1 <> t1.a
);

drop view v1;
drop table t1;

--echo # End of 10.11 tests
15 changes: 15 additions & 0 deletions sql/item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3274,6 +3274,21 @@ bool Item_field::enumerate_field_refs_processor(void *arg)
return FALSE;
}


bool Item_direct_view_ref::enumerate_table_refs_processor(void *arg)
{
Field_fixer *ff= (Field_fixer*)arg;
st_select_lex *cmp= ff->new_parent->get_merged_into();

// our table is resolved in the select of interest
if (null_ref_table &&
null_ref_table != NO_NULL_TABLE &&
null_ref_table->pos_in_table_list->select_lex == cmp)
ff->used_tables |= null_ref_table->map;
return FALSE;
}


bool Item_field::update_table_bitmaps_processor(void *arg)
{
update_table_bitmaps();
Expand Down
22 changes: 22 additions & 0 deletions sql/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -2303,6 +2303,7 @@ class Item :public Value_source,
virtual bool update_table_bitmaps_processor(void *arg) { return 0; }

virtual bool enumerate_field_refs_processor(void *arg) { return 0; }
virtual bool enumerate_table_refs_processor(void *arg) { return 0; }
virtual bool mark_as_eliminated_processor(void *arg) { return 0; }
virtual bool eliminate_subselect_processor(void *arg) { return 0; }
virtual bool view_used_tables_processor(void *arg) { return 0; }
Expand Down Expand Up @@ -6342,6 +6343,7 @@ class Item_direct_view_ref :public Item_direct_ref
set_null_ref_table();
}

bool enumerate_table_refs_processor(void *arg) override;
bool fix_fields(THD *, Item **) override;
bool eq(const Item *item, const Eq_config &config) const override;
Item *get_tmp_table_item(THD *thd) override
Expand Down Expand Up @@ -8351,4 +8353,24 @@ inline void TABLE::use_all_stored_columns()
bitmap_clear_bit(read_set, (*vf)->field_index);
}


class Field_fixer: public Field_enumerator
{
public:
table_map used_tables; /* Collect used_tables here */
st_select_lex *new_parent; /* Select we're in */
void visit_field(Item_field *item) override
{
//for (TABLE_LIST *tbl= new_parent->leaf_tables; tbl; tbl= tbl->next_local)
//{
// if (tbl->table == field->table)
// {
used_tables|= item->field->table->map;
// return;
// }
//}
//used_tables |= OUTER_REF_TABLE_BIT;
}
};

#endif /* SQL_ITEM_INCLUDED */
28 changes: 8 additions & 20 deletions sql/item_subselect.cc
Original file line number Diff line number Diff line change
Expand Up @@ -469,26 +469,6 @@ void Item_subselect::fix_after_pullout(st_select_lex *new_parent,
}


class Field_fixer: public Field_enumerator
{
public:
table_map used_tables; /* Collect used_tables here */
st_select_lex *new_parent; /* Select we're in */
void visit_field(Item_field *item) override
{
//for (TABLE_LIST *tbl= new_parent->leaf_tables; tbl; tbl= tbl->next_local)
//{
// if (tbl->table == field->table)
// {
used_tables|= item->field->table->map;
// return;
// }
//}
//used_tables |= OUTER_REF_TABLE_BIT;
}
};


/*
Recalculate used_tables_cache
*/
Expand Down Expand Up @@ -538,6 +518,14 @@ void Item_subselect::recalc_used_tables(st_select_lex *new_parent,
fixer.used_tables= 0;
fixer.new_parent= new_parent;
upper->item->walk(&Item::enumerate_field_refs_processor, 0, &fixer);
/*
An reference (that can be null) might refer to a constant item
(that isn't and can't be null).
We need to update the table map to include tables that might be
null to avoid this subselect being marked as constant.
This information is in the Item_direct_view_ref wrapper.
*/
upper->item->walk(&Item::enumerate_table_refs_processor, 0, &fixer);
used_tables_cache |= fixer.used_tables;
upper->item->walk(&Item::update_table_bitmaps_processor, FALSE, NULL);
/*
Expand Down
10 changes: 10 additions & 0 deletions sql/sql_lex.h
Original file line number Diff line number Diff line change
Expand Up @@ -1714,6 +1714,16 @@ class st_select_lex: public st_select_lex_node
TABLE_LIST *find_table(THD *thd,
const LEX_CSTRING *db_name,
const LEX_CSTRING *table_name);

st_select_lex *get_merged_into()
{
st_select_lex *ret= this;

while(ret->merged_into)
ret= ret->merged_into;

return ret;
}
};
typedef class st_select_lex SELECT_LEX;

Expand Down