Commit 1a08b575 authored by unknown's avatar unknown

reporting empty result added in case of max/min optimisation of ALL/ANY/SOME subqueries

fixed null processing in NOT operation used in ALL subquery (Bug #6247)


mysql-test/r/subselect.result:
  new tests of ALL/ANY wiews
mysql-test/t/subselect.test:
  new tests of ALL/ANY wiews
sql/item_cmpfunc.cc:
  fixed special NOT ALL processing
  fixed processing max/min optimized subqueries with empty results (added methods to detect empty results) and special NOP operation to process them for SOME/ANY sobqueries
sql/item_cmpfunc.h:
  fixed processing max/min optimized subqueries with empty results (added methods to detect empty results) and special NOP operation to process them for SOME/ANY sobqueries
sql/item_subselect.cc:
  reporting empty result added for max/min subqueries
sql/item_subselect.h:
  reporting empty result added for max/min subqueries
sql/item_sum.cc:
  reporting empty result added fox max/min aggregate functions
sql/item_sum.h:
  reporting empty result added fox max/min aggregate functions
sql/sql_class.cc:
  reporting empty result added for max/min subqueries
sql/sql_parse.cc:
  reporting empty result added for max/min subqueries
sql/sql_union.cc:
  reporting empty result added for max/min subqueries
parent 83317e5b
......@@ -269,7 +269,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where
2 SUBQUERY t2 ALL NULL NULL NULL NULL 3
Warnings:
Note 1003 select test.t3.a AS `a` from test.t3 where (test.t3.a >= (select min(test.t2.b) from test.t2))
Note 1003 select test.t3.a AS `a` from test.t3 where <nop>((test.t3.a >= (select min(test.t2.b) from test.t2)))
select * from t3 where a >= all (select b from t2);
a
7
......@@ -1488,6 +1488,71 @@ id select_type table type possible_keys key key_len ref rows Extra
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
Note 1003 select test.t3.a AS `a` from test.t3 where <not>((test.t3.a < (select max(test.t2.b) from test.t2)))
select * from t3 where a >= some (select b from t2);
a
6
7
3
explain extended select * from t3 where a >= some (select b from t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
Note 1003 select test.t3.a AS `a` from test.t3 where <nop>((test.t3.a >= (select min(test.t2.b) from test.t2)))
select * from t3 where a >= all (select b from t2 group by 1);
a
6
7
3
explain extended select * from t3 where a >= all (select b from t2 group by 1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
Note 1003 select test.t3.a AS `a` from test.t3 where <not>((test.t3.a < <max>(select test.t2.b AS `b` from test.t2 group by test.t2.b)))
select * from t3 where a >= some (select b from t2 group by 1);
a
6
7
3
explain extended select * from t3 where a >= some (select b from t2 group by 1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
Note 1003 select test.t3.a AS `a` from test.t3 where <nop>((test.t3.a >= <min>(select test.t2.b AS `b` from test.t2 group by test.t2.b)))
select * from t3 where NULL >= any (select b from t2);
a
explain extended select * from t3 where NULL >= any (select b from t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
Note 1003 select test.t3.a AS `a` from test.t3
select * from t3 where NULL >= any (select b from t2 group by 1);
a
explain extended select * from t3 where NULL >= any (select b from t2 group by 1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
Note 1003 select test.t3.a AS `a` from test.t3
select * from t3 where NULL >= some (select b from t2);
a
explain extended select * from t3 where NULL >= some (select b from t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
Note 1003 select test.t3.a AS `a` from test.t3
select * from t3 where NULL >= some (select b from t2 group by 1);
a
explain extended select * from t3 where NULL >= some (select b from t2 group by 1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
Note 1003 select test.t3.a AS `a` from test.t3
insert into t2 values (2,2), (2,1), (3,3), (3,1);
select * from t3 where a > all (select max(b) from t2 group by a);
a
......@@ -1990,3 +2055,12 @@ ac
700
NULL
drop tables t1,t2;
create table t1 (s1 int);
insert into t1 values (1),(null);
select * from t1 where s1 < all (select s1 from t1);
s1
select s1, s1 < all (select s1 from t1) from t1;
s1 s1 < all (select s1 from t1)
1 0
NULL NULL
drop table t1;
......@@ -911,7 +911,20 @@ create table t3 (a int);
insert into t3 values (6),(7),(3);
select * from t3 where a >= all (select b from t2);
explain extended select * from t3 where a >= all (select b from t2);
select * from t3 where a >= some (select b from t2);
explain extended select * from t3 where a >= some (select b from t2);
select * from t3 where a >= all (select b from t2 group by 1);
explain extended select * from t3 where a >= all (select b from t2 group by 1);
select * from t3 where a >= some (select b from t2 group by 1);
explain extended select * from t3 where a >= some (select b from t2 group by 1);
select * from t3 where NULL >= any (select b from t2);
explain extended select * from t3 where NULL >= any (select b from t2);
select * from t3 where NULL >= any (select b from t2 group by 1);
explain extended select * from t3 where NULL >= any (select b from t2 group by 1);
select * from t3 where NULL >= some (select b from t2);
explain extended select * from t3 where NULL >= some (select b from t2);
select * from t3 where NULL >= some (select b from t2 group by 1);
explain extended select * from t3 where NULL >= some (select b from t2 group by 1);
#
# optimized static ALL/ANY with grouping
#
......@@ -1282,3 +1295,12 @@ INSERT INTO `t2` VALUES (6,5,12,7,'a'),(12,0,0,7,'a'),(12,1,0,7,'a'),(12,5,5,7,'
SELECT b.sc FROM (SELECT (SELECT a.access FROM t1 a WHERE a.map = op.map AND a.slave = op.pid AND a.master = 1) ac FROM t2 op WHERE op.id = 12 AND op.map = 0) b;
SELECT b.ac FROM (SELECT (SELECT a.access FROM t1 a WHERE a.map = op.map AND a.slave = op.pid AND a.master = 1) ac FROM t2 op WHERE op.id = 12 AND op.map = 0) b;
drop tables t1,t2;
#
# ALL/ANY with NULL
#
create table t1 (s1 int);
insert into t1 values (1),(null);
select * from t1 where s1 < all (select s1 from t1);
select s1, s1 < all (select s1 from t1) from t1;
drop table t1;
......@@ -106,7 +106,7 @@ longlong Item_func_not::val_int()
DBUG_ASSERT(fixed == 1);
double value=args[0]->val();
null_value=args[0]->null_value;
return !null_value && value == 0 ? 1 : 0;
return ((!null_value && value == 0) ? 1 : 0);
}
/*
......@@ -117,13 +117,23 @@ longlong Item_func_not_all::val_int()
{
DBUG_ASSERT(fixed == 1);
double value= args[0]->val();
if (abort_on_null)
{
null_value= 0;
return (args[0]->null_value || value == 0) ? 1 : 0;
}
/*
return TRUE if there was records in underlaying select in max/min
optimisation
*/
if (empty_underlying_subquery())
return 1;
null_value= args[0]->null_value;
return (!null_value && value == 0) ? 1 : 0;
return ((!null_value && value == 0) ? 1 : 0);
}
bool Item_func_not_all::empty_underlying_subquery()
{
return ((test_sum_item && !test_sum_item->any_value()) ||
(test_sub_item && !test_sub_item->any_value()));
}
void Item_func_not_all::print(String *str)
......@@ -134,6 +144,28 @@ void Item_func_not_all::print(String *str)
args[0]->print(str);
}
/*
special NOP for ALL subquery
*/
longlong Item_func_nop_all::val_int()
{
DBUG_ASSERT(fixed == 1);
double value= args[0]->val();
/*
return TRUE if there was records in underlaying select in max/min
optimisation
*/
if (empty_underlying_subquery())
return 1;
null_value= args[0]->null_value;
return (null_value || value == 0) ? 0 : 1;
}
/*
Convert a constant expression or string to an integer.
This is done when comparing DATE's of different formats and
......
......@@ -229,21 +229,43 @@ class Item_func_not :public Item_bool_func
Item *neg_transformer(THD *thd);
};
class Item_maxmin_subselect;
class Item_func_not_all :public Item_func_not
{
/* allow to check presence od values in max/min optimisation */
Item_sum_hybrid *test_sum_item;
Item_maxmin_subselect *test_sub_item;
bool abort_on_null;
public:
bool show;
Item_func_not_all(Item *a) :Item_func_not(a), abort_on_null(0), show(0) {}
Item_func_not_all(Item *a)
:Item_func_not(a), test_sum_item(0), test_sub_item(0), abort_on_null(0),
show(0)
{}
virtual void top_level_item() { abort_on_null= 1; }
bool top_level() { return abort_on_null; }
longlong val_int();
enum Functype functype() const { return NOT_ALL_FUNC; }
const char *func_name() const { return "<not>"; }
void print(String *str);
void set_sum_test(Item_sum_hybrid *item) { test_sum_item= item; };
void set_sub_test(Item_maxmin_subselect *item) { test_sub_item= item; };
bool empty_underlying_subquery();
};
class Item_func_nop_all :public Item_func_not_all
{
public:
Item_func_nop_all(Item *a) :Item_func_not_all(a) {}
longlong val_int();
const char *func_name() const { return "<nop>"; }
};
class Item_func_eq :public Item_bool_rowready_func2
{
public:
......
......@@ -271,7 +271,7 @@ Item_singlerow_subselect::Item_singlerow_subselect(st_select_lex *select_lex)
Item_maxmin_subselect::Item_maxmin_subselect(Item_subselect *parent,
st_select_lex *select_lex,
bool max_arg)
:Item_singlerow_subselect()
:Item_singlerow_subselect(), was_values(TRUE)
{
DBUG_ENTER("Item_maxmin_subselect::Item_maxmin_subselect");
max= max_arg;
......@@ -290,12 +290,26 @@ Item_maxmin_subselect::Item_maxmin_subselect(Item_subselect *parent,
DBUG_VOID_RETURN;
}
void Item_maxmin_subselect::cleanup()
{
/*
By default is is TRUE to avoid TRUE reporting by
Item_func_not_all/Item_func_nop_all if this item was never called.
Engine exec() set it to FALSE by reset_value_registration() call.
*/
was_values= TRUE;
}
void Item_maxmin_subselect::print(String *str)
{
str->append(max?"<max>":"<min>", 5);
Item_singlerow_subselect::print(str);
}
void Item_singlerow_subselect::reset()
{
null_value= 1;
......@@ -303,6 +317,7 @@ void Item_singlerow_subselect::reset()
value->null_value= 1;
}
Item_subselect::trans_res
Item_singlerow_subselect::select_transformer(JOIN *join)
{
......@@ -519,7 +534,7 @@ bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit)
Item_in_subselect::Item_in_subselect(Item * left_exp,
st_select_lex *select_lex):
Item_exists_subselect(), transformed(0), upper_not(0)
Item_exists_subselect(), transformed(0), upper_item(0)
{
DBUG_ENTER("Item_in_subselect::Item_in_subselect");
left_expr= left_exp;
......@@ -680,7 +695,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
NULL/IS NOT NULL functions). If so, we rewrite ALL/ANY with NOT EXISTS
later in this method.
*/
if ((abort_on_null || (upper_not && upper_not->top_level())) &&
if ((abort_on_null || (upper_item && upper_item->top_level())) &&
!select_lex->master_unit()->uncacheable && !func->eqne_op())
{
if (substitution)
......@@ -694,7 +709,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
!select_lex->with_sum_func &&
!(select_lex->next_select()))
{
Item *item;
Item_sum_hybrid *item;
if (func->l_op())
{
/*
......@@ -711,6 +726,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
*/
item= new Item_sum_min(*select_lex->ref_pointer_array);
}
if (upper_item)
upper_item->set_sum_test(item);
*select_lex->ref_pointer_array= item;
{
List_iterator<Item> it(select_lex->item_list);
......@@ -731,10 +748,13 @@ Item_in_subselect::single_value_transformer(JOIN *join,
}
else
{
Item_maxmin_subselect *item;
// remove LIMIT placed by ALL/ANY subquery
select_lex->master_unit()->global_parameters->select_limit=
HA_POS_ERROR;
subs= new Item_maxmin_subselect(this, select_lex, func->l_op());
subs= item= new Item_maxmin_subselect(this, select_lex, func->l_op());
if (upper_item)
upper_item->set_sub_test(item);
}
// left expression belong to outer select
SELECT_LEX *current= thd->lex->current_select, *up;
......@@ -1041,8 +1061,8 @@ Item_subselect::trans_res
Item_allany_subselect::select_transformer(JOIN *join)
{
transformed= 1;
if (upper_not)
upper_not->show= 1;
if (upper_item)
upper_item->show= 1;
return single_value_transformer(join, func);
}
......@@ -1247,6 +1267,7 @@ int subselect_single_select_engine::exec()
}
if (!executed)
{
item->reset_value_registration();
join->exec();
executed= 1;
join->thd->where= save_where;
......
......@@ -93,7 +93,7 @@ class Item_subselect :public Item_result_field
return null_value;
}
bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
bool exec();
virtual bool exec();
virtual void fix_length_and_dec();
table_map used_tables() const;
bool const_item() const;
......@@ -109,6 +109,11 @@ class Item_subselect :public Item_result_field
engine_changed= 1;
return eng == 0;
}
/*
Used by max/min subquery to initialize value presence registration
mechanism. Engine call this method before rexecution query.
*/
virtual void reset_value_registration() {}
friend class select_subselect;
friend class Item_in_optimizer;
......@@ -150,13 +155,20 @@ class Item_singlerow_subselect :public Item_subselect
};
/* used in static ALL/ANY optimisation */
class select_max_min_finder_subselect;
class Item_maxmin_subselect :public Item_singlerow_subselect
{
protected:
bool max;
bool was_values; // was checked at least some values
public:
Item_maxmin_subselect(Item_subselect *parent,
st_select_lex *select_lex, bool max);
void print(String *str);
void cleanup();
bool any_value() { return was_values; }
void register_value() { was_values= TRUE; }
void reset_value_registration() { was_values= FALSE; }
};
/* exists subselect */
......@@ -204,11 +216,11 @@ class Item_in_subselect :public Item_exists_subselect
bool abort_on_null;
bool transformed;
public:
Item_func_not_all *upper_not; // point on NOT before ALL subquery
Item_func_not_all *upper_item; // point on NOT/NOP before ALL/SOME subquery
Item_in_subselect(Item * left_expr, st_select_lex *select_lex);
Item_in_subselect()
:Item_exists_subselect(), abort_on_null(0), transformed(0), upper_not(0)
:Item_exists_subselect(), abort_on_null(0), transformed(0), upper_item(0)
{}
......@@ -249,7 +261,7 @@ class Item_allany_subselect :public Item_in_subselect
st_select_lex *select_lex, bool all);
// only ALL subquery has upper not
subs_type substype() { return upper_not?ALL_SUBS:ANY_SUBS; }
subs_type substype() { return all?ALL_SUBS:ANY_SUBS; }
trans_res select_transformer(JOIN *join);
void print(String *str);
};
......
......@@ -540,9 +540,22 @@ void Item_sum_hybrid::cleanup()
DBUG_ENTER("Item_sum_hybrid::cleanup");
Item_sum::cleanup();
used_table_cache= ~(table_map) 0;
/*
by default is is TRUE to avoid TRUE reporting by
Item_func_not_all/Item_func_nop_all if this item was never called.
no_rows_in_result() set it to FALSE if was not results found.
*/
was_values= TRUE;
DBUG_VOID_RETURN;
}
void Item_sum_hybrid::no_rows_in_result()
{
Item_sum::no_rows_in_result();
was_values= FALSE;
}
Item *Item_sum_min::copy_or_same(THD* thd)
{
......
......@@ -403,19 +403,22 @@ class Item_sum_hybrid :public Item_sum
int cmp_sign;
table_map used_table_cache;
CHARSET_INFO *cmp_charset;
bool was_values; // was checked at least some values (for max/min only)
public:
Item_sum_hybrid(Item *item_par,int sign)
:Item_sum(item_par), sum(0.0), sum_int(0),
hybrid_type(INT_RESULT), hybrid_field_type(FIELD_TYPE_LONGLONG),
cmp_sign(sign), used_table_cache(~(table_map) 0),
cmp_charset(&my_charset_bin)
cmp_charset(&my_charset_bin), was_values(TRUE)
{}
Item_sum_hybrid(THD *thd, Item_sum_hybrid *item):
Item_sum(thd, item), value(item->value),
sum(item->sum), sum_int(item->sum_int), hybrid_type(item->hybrid_type),
hybrid_field_type(item->hybrid_field_type),cmp_sign(item->cmp_sign),
used_table_cache(item->used_table_cache), cmp_charset(item->cmp_charset) {}
used_table_cache(item->used_table_cache), cmp_charset(item->cmp_charset),
was_values(TRUE)
{}
bool fix_fields(THD *, TABLE_LIST *, Item **);
table_map used_tables() const { return used_table_cache; }
bool const_item() const { return !used_table_cache; }
......@@ -434,6 +437,8 @@ class Item_sum_hybrid :public Item_sum
void min_max_update_real_field();
void min_max_update_int_field();
void cleanup();
bool any_value() { return was_values; }
void no_rows_in_result();
};
......
......@@ -1241,9 +1241,10 @@ bool select_singlerow_subselect::send_data(List<Item> &items)
bool select_max_min_finder_subselect::send_data(List<Item> &items)
{
DBUG_ENTER("select_max_min_finder_subselect::send_data");
Item_singlerow_subselect *it= (Item_singlerow_subselect *)item;
Item_maxmin_subselect *it= (Item_maxmin_subselect *)item;
List_iterator_fast<Item> li(items);
Item *val_item= li++;
it->register_value();
if (it->assigned())
{
cache->store(val_item);
......
......@@ -5114,9 +5114,9 @@ Item * all_any_subquery_creator(Item *left_expr,
Item_allany_subselect *it=
new Item_allany_subselect(left_expr, (*cmp)(all), select_lex, all);
if (all)
return it->upper_not= new Item_func_not_all(it); /* ALL */
return it->upper_item= new Item_func_not_all(it); /* ALL */
return it; /* ANY/SOME */
return it->upper_item= new Item_func_nop_all(it); /* ANY/SOME */
}
......
......@@ -394,6 +394,8 @@ int st_select_lex_unit::exec()
if (uncacheable || !item || !item->assigned() || describe)
{
if (item)
item->reset_value_registration();
if (optimized && item)
{
if (item->assigned())
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment