mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
aggregate functions check during substitution made only for single row subselects (BUG#4400)
restoring current senect pointer before PS rexecution (backport from 5.0) removed spaces at lines ends mysql-test/r/subselect.result: Aggregate function comparation with ALL/ANY/SOME subselect test mysql-test/t/subselect.test: Aggregate function comparation with ALL/ANY/SOME subselect test sql/item_subselect.cc: removed spaces at lines ends aggregate functions check during substitution made only for single row subselects sql/item_subselect.h: removed spaces at lines ends sql/sql_prepare.cc: restoring current senect pointer before PS rexecution (backport from 5.0)
This commit is contained in:
@ -1891,3 +1891,11 @@ abc b
|
|||||||
3 4
|
3 4
|
||||||
deallocate prepare stmt1;
|
deallocate prepare stmt1;
|
||||||
DROP TABLE t1, t2, t3;
|
DROP TABLE t1, t2, t3;
|
||||||
|
CREATE TABLE `t1` ( `a` int(11) default NULL) ENGINE=MyISAM DEFAULT CHARSET=latin1;
|
||||||
|
insert into t1 values (1);
|
||||||
|
CREATE TABLE `t2` ( `b` int(11) default NULL, `a` int(11) default NULL) ENGINE=MyISAM DEFAULT CHARSET=latin1;
|
||||||
|
insert into t2 values (1,2);
|
||||||
|
select t000.a, count(*) `C` FROM t1 t000 GROUP BY t000.a HAVING count(*) > ALL (SELECT count(*) FROM t2 t001 WHERE t001.a=1);
|
||||||
|
a C
|
||||||
|
1 1
|
||||||
|
drop table t1,t2;
|
||||||
|
@ -1212,3 +1212,13 @@ execute stmt1;
|
|||||||
select * from t3;
|
select * from t3;
|
||||||
deallocate prepare stmt1;
|
deallocate prepare stmt1;
|
||||||
DROP TABLE t1, t2, t3;
|
DROP TABLE t1, t2, t3;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Aggregate function comparation with ALL/ANY/SOME subselect
|
||||||
|
#
|
||||||
|
CREATE TABLE `t1` ( `a` int(11) default NULL) ENGINE=MyISAM DEFAULT CHARSET=latin1;
|
||||||
|
insert into t1 values (1);
|
||||||
|
CREATE TABLE `t2` ( `b` int(11) default NULL, `a` int(11) default NULL) ENGINE=MyISAM DEFAULT CHARSET=latin1;
|
||||||
|
insert into t2 values (1,2);
|
||||||
|
select t000.a, count(*) `C` FROM t1 t000 GROUP BY t000.a HAVING count(*) > ALL (SELECT count(*) FROM t2 t001 WHERE t001.a=1);
|
||||||
|
drop table t1,t2;
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
subselect Item
|
subselect Item
|
||||||
|
|
||||||
SUBSELECT TODO:
|
SUBSELECT TODO:
|
||||||
@ -41,7 +41,7 @@ Item_subselect::Item_subselect():
|
|||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
/*
|
/*
|
||||||
item value is NULL if select_subselect not changed this value
|
item value is NULL if select_subselect not changed this value
|
||||||
(i.e. some rows will be found returned)
|
(i.e. some rows will be found returned)
|
||||||
*/
|
*/
|
||||||
null_value= 1;
|
null_value= 1;
|
||||||
@ -114,7 +114,7 @@ Item_subselect::~Item_subselect()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Item_subselect::trans_res
|
Item_subselect::trans_res
|
||||||
Item_subselect::select_transformer(JOIN *join)
|
Item_subselect::select_transformer(JOIN *join)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("Item_subselect::select_transformer");
|
DBUG_ENTER("Item_subselect::select_transformer");
|
||||||
DBUG_RETURN(RES_OK);
|
DBUG_RETURN(RES_OK);
|
||||||
@ -148,11 +148,11 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
|
|||||||
if (have_to_be_excluded)
|
if (have_to_be_excluded)
|
||||||
engine->exclude();
|
engine->exclude();
|
||||||
substitution= 0;
|
substitution= 0;
|
||||||
thd->where= "checking transformed subquery";
|
thd->where= "checking transformed subquery";
|
||||||
if (!(*ref)->fixed)
|
if (!(*ref)->fixed)
|
||||||
ret= (*ref)->fix_fields(thd, tables, ref);
|
ret= (*ref)->fix_fields(thd, tables, ref);
|
||||||
// We can't substitute aggregate functions (like (SELECT (max(i)))
|
// We can't substitute aggregate functions like "SELECT (max(i))"
|
||||||
if ((*ref)->with_sum_func)
|
if (substype() == SINGLEROW_SUBS && (*ref)->with_sum_func)
|
||||||
{
|
{
|
||||||
my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0));
|
my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0));
|
||||||
return 1;
|
return 1;
|
||||||
@ -161,7 +161,7 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
|
|||||||
}
|
}
|
||||||
// Is it one field subselect?
|
// Is it one field subselect?
|
||||||
if (engine->cols() > max_columns)
|
if (engine->cols() > max_columns)
|
||||||
{
|
{
|
||||||
my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
|
my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -199,7 +199,7 @@ bool Item_subselect::exec()
|
|||||||
return (res);
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
Item::Type Item_subselect::type() const
|
Item::Type Item_subselect::type() const
|
||||||
{
|
{
|
||||||
return SUBSELECT_ITEM;
|
return SUBSELECT_ITEM;
|
||||||
}
|
}
|
||||||
@ -277,7 +277,7 @@ Item_maxmin_subselect::Item_maxmin_subselect(Item_subselect *parent,
|
|||||||
*/
|
*/
|
||||||
used_tables_cache= parent->get_used_tables_cache();
|
used_tables_cache= parent->get_used_tables_cache();
|
||||||
const_item_cache= parent->get_const_item_cache();
|
const_item_cache= parent->get_const_item_cache();
|
||||||
|
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
|
|||||||
{
|
{
|
||||||
if (changed)
|
if (changed)
|
||||||
return RES_OK;
|
return RES_OK;
|
||||||
|
|
||||||
SELECT_LEX *select_lex= join->select_lex;
|
SELECT_LEX *select_lex= join->select_lex;
|
||||||
Statement backup;
|
Statement backup;
|
||||||
|
|
||||||
@ -314,10 +314,10 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
|
|||||||
TODO: solve above problem
|
TODO: solve above problem
|
||||||
*/
|
*/
|
||||||
!(select_lex->item_list.head()->type() == FIELD_ITEM ||
|
!(select_lex->item_list.head()->type() == FIELD_ITEM ||
|
||||||
select_lex->item_list.head()->type() == REF_ITEM)
|
select_lex->item_list.head()->type() == REF_ITEM)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
have_to_be_excluded= 1;
|
have_to_be_excluded= 1;
|
||||||
if (join->thd->lex->describe)
|
if (join->thd->lex->describe)
|
||||||
{
|
{
|
||||||
@ -355,7 +355,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
|
|||||||
return RES_REDUCE;
|
return RES_REDUCE;
|
||||||
}
|
}
|
||||||
return RES_OK;
|
return RES_OK;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
if (stmt)
|
if (stmt)
|
||||||
thd->restore_backup_item_arena(stmt, &backup);
|
thd->restore_backup_item_arena(stmt, &backup);
|
||||||
@ -418,7 +418,7 @@ void Item_singlerow_subselect::bring_value()
|
|||||||
exec();
|
exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
double Item_singlerow_subselect::val()
|
double Item_singlerow_subselect::val()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
if (!exec() && !value->null_value)
|
if (!exec() && !value->null_value)
|
||||||
@ -433,7 +433,7 @@ double Item_singlerow_subselect::val()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
longlong Item_singlerow_subselect::val_int()
|
longlong Item_singlerow_subselect::val_int()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
if (!exec() && !value->null_value)
|
if (!exec() && !value->null_value)
|
||||||
@ -448,7 +448,7 @@ longlong Item_singlerow_subselect::val_int()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String *Item_singlerow_subselect::val_str (String *str)
|
String *Item_singlerow_subselect::val_str (String *str)
|
||||||
{
|
{
|
||||||
if (!exec() && !value->null_value)
|
if (!exec() && !value->null_value)
|
||||||
{
|
{
|
||||||
@ -553,7 +553,7 @@ double Item_exists_subselect::val()
|
|||||||
return (double) value;
|
return (double) value;
|
||||||
}
|
}
|
||||||
|
|
||||||
longlong Item_exists_subselect::val_int()
|
longlong Item_exists_subselect::val_int()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
if (exec())
|
if (exec())
|
||||||
@ -590,7 +590,7 @@ double Item_in_subselect::val()
|
|||||||
return (double) value;
|
return (double) value;
|
||||||
}
|
}
|
||||||
|
|
||||||
longlong Item_in_subselect::val_int()
|
longlong Item_in_subselect::val_int()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
if (exec())
|
if (exec())
|
||||||
@ -842,7 +842,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
|
|||||||
{
|
{
|
||||||
// it is single select without tables => possible optimization
|
// it is single select without tables => possible optimization
|
||||||
item= func->create(left_expr, item);
|
item= func->create(left_expr, item);
|
||||||
// fix_field of item will be done in time of substituting
|
// fix_field of item will be done in time of substituting
|
||||||
substitution= item;
|
substitution= item;
|
||||||
have_to_be_excluded= 1;
|
have_to_be_excluded= 1;
|
||||||
if (thd->lex->describe)
|
if (thd->lex->describe)
|
||||||
@ -885,7 +885,7 @@ Item_in_subselect::row_value_transformer(JOIN *join)
|
|||||||
|
|
||||||
thd->where= "row IN/ALL/ANY subquery";
|
thd->where= "row IN/ALL/ANY subquery";
|
||||||
if (stmt)
|
if (stmt)
|
||||||
thd->set_n_backup_item_arena(stmt, &backup);
|
thd->set_n_backup_item_arena(stmt, &backup);
|
||||||
|
|
||||||
SELECT_LEX *select_lex= join->select_lex;
|
SELECT_LEX *select_lex= join->select_lex;
|
||||||
|
|
||||||
@ -926,7 +926,7 @@ Item_in_subselect::row_value_transformer(JOIN *join)
|
|||||||
List_iterator_fast<Item> li(select_lex->item_list);
|
List_iterator_fast<Item> li(select_lex->item_list);
|
||||||
for (uint i= 0; i < n; i++)
|
for (uint i= 0; i < n; i++)
|
||||||
{
|
{
|
||||||
Item *func= new Item_ref_null_helper(this,
|
Item *func= new Item_ref_null_helper(this,
|
||||||
select_lex->ref_pointer_array+i,
|
select_lex->ref_pointer_array+i,
|
||||||
(char *) "<no matter>",
|
(char *) "<no matter>",
|
||||||
(char *) "<list ref>");
|
(char *) "<list ref>");
|
||||||
@ -1108,7 +1108,7 @@ int subselect_single_select_engine::prepare()
|
|||||||
(ORDER*) select_lex->order_list.first,
|
(ORDER*) select_lex->order_list.first,
|
||||||
(ORDER*) select_lex->group_list.first,
|
(ORDER*) select_lex->group_list.first,
|
||||||
select_lex->having,
|
select_lex->having,
|
||||||
(ORDER*) 0, select_lex,
|
(ORDER*) 0, select_lex,
|
||||||
select_lex->master_unit()))
|
select_lex->master_unit()))
|
||||||
return 1;
|
return 1;
|
||||||
thd->lex->current_select= save_select;
|
thd->lex->current_select= save_select;
|
||||||
|
@ -47,7 +47,7 @@ protected:
|
|||||||
/* old engine if engine was changed */
|
/* old engine if engine was changed */
|
||||||
subselect_engine *old_engine;
|
subselect_engine *old_engine;
|
||||||
/* cache of used external tables */
|
/* cache of used external tables */
|
||||||
table_map used_tables_cache;
|
table_map used_tables_cache;
|
||||||
/* allowed number of columns (1 for single value subqueries) */
|
/* allowed number of columns (1 for single value subqueries) */
|
||||||
uint max_columns;
|
uint max_columns;
|
||||||
/* work with 'substitution' */
|
/* work with 'substitution' */
|
||||||
@ -69,17 +69,17 @@ public:
|
|||||||
|
|
||||||
virtual subs_type substype() { return UNKNOWN_SUBS; }
|
virtual subs_type substype() { return UNKNOWN_SUBS; }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We need this method, because some compilers do not allow 'this'
|
We need this method, because some compilers do not allow 'this'
|
||||||
pointer in constructor initialization list, but we need pass pointer
|
pointer in constructor initialization list, but we need pass pointer
|
||||||
to subselect Item class to select_subselect classes constructor.
|
to subselect Item class to select_subselect classes constructor.
|
||||||
*/
|
*/
|
||||||
virtual void init (st_select_lex *select_lex,
|
virtual void init (st_select_lex *select_lex,
|
||||||
select_subselect *result);
|
select_subselect *result);
|
||||||
|
|
||||||
~Item_subselect();
|
~Item_subselect();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
virtual void reset()
|
virtual void reset()
|
||||||
{
|
{
|
||||||
null_value= 1;
|
null_value= 1;
|
||||||
}
|
}
|
||||||
@ -275,7 +275,7 @@ public:
|
|||||||
}
|
}
|
||||||
virtual ~subselect_engine() {}; // to satisfy compiler
|
virtual ~subselect_engine() {}; // to satisfy compiler
|
||||||
virtual void cleanup()= 0;
|
virtual void cleanup()= 0;
|
||||||
|
|
||||||
// set_thd should be called before prepare()
|
// set_thd should be called before prepare()
|
||||||
void set_thd(THD *thd_arg) { thd= thd_arg; }
|
void set_thd(THD *thd_arg) { thd= thd_arg; }
|
||||||
THD * get_thd() { return thd; }
|
THD * get_thd() { return thd; }
|
||||||
|
@ -1706,6 +1706,7 @@ static void reset_stmt_for_execute(Prepared_statement *stmt)
|
|||||||
unit->reinit_exec_mechanism();
|
unit->reinit_exec_mechanism();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stmt->lex->current_select= &stmt->lex->select_lex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user