Commit e14fd2b6 authored by unknown's avatar unknown

Bug #27363:

Validity checks for nested set functions
were not taking into account that the enclosed
set function may be on a nest level that is
lower than the nest level of the enclosing set
function.
Fixed by :
 - propagating max_sum_func_level
up the enclosing set functions chain.
 - updating the max_sum_func_level of the 
   enclosing set function when the enclosed set
   function is aggregated above or on the same
   nest level of as the level of the enclosing 
   set function.
 - updating the max_arg_level of the enclosing
   set function on a reference that refers to
   an item above or on the same nest level
   as the level of the enclosing set function.
 - Treating both Item_field and Item_ref as possibly
   referencing items from outer nest levels.


mysql-test/r/subselect.result:
  Bug #27363: test cases
mysql-test/t/subselect.test:
  Bug #27363: test cases
sql/item.cc:
  Bug #27363:
  Treat the reference as an outer reference for the
  enclosing set function even if it's referencing
  an item that is above the nest level of the
  enclosing set function.
  Consider both Item_field and Item_ref.
sql/item_sum.cc:
  Bug #27363: Use the enclosed set function aggregation
  level to mark the enclosing set function even 
  if it's aggregated on a level that is above the 
  nest level of the enclosing set function.
  Pass max_sum_func_level up the accending branch of the
  recursion because it must take into account each
  directly or indirectly nested set function.
parent 4430048e
set autocommit=1;
reset master;
create table bug16206 (a int);
insert into bug16206 values(1);
start transaction;
insert into bug16206 values(2);
commit;
show binlog events;
Log_name Pos Event_type Server_id End_log_pos Info
f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4
f n Query 1 n use `test`; create table bug16206 (a int)
f n Query 1 n use `test`; insert into bug16206 values(1)
f n Query 1 n use `test`; insert into bug16206 values(2)
drop table bug16206;
reset master;
create table bug16206 (a int) engine= bdb;
insert into bug16206 values(0);
insert into bug16206 values(1);
start transaction;
insert into bug16206 values(2);
commit;
insert into bug16206 values(3);
show binlog events;
Log_name Pos Event_type Server_id End_log_pos Info
f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4
f n Query 1 n use `test`; create table bug16206 (a int) engine= bdb
f n Query 1 n use `test`; insert into bug16206 values(0)
f n Query 1 n use `test`; insert into bug16206 values(1)
f n Query 1 n use `test`; BEGIN
f n Query 1 n use `test`; insert into bug16206 values(2)
f n Query 1 n use `test`; COMMIT
f n Query 1 n use `test`; insert into bug16206 values(3)
drop table bug16206;
set autocommit=0;
End of 5.0 tests
......@@ -3947,3 +3947,26 @@ WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a;
ERROR HY000: Invalid use of group function
SET @@sql_mode=default;
DROP TABLE t1;
CREATE TABLE t1 (a INT);
INSERT INTO t1 values (1),(1),(1),(1);
CREATE TABLE t2 (x INT);
INSERT INTO t1 values (1000),(1001),(1002);
SELECT SUM( (SELECT COUNT(a) FROM t2) ) FROM t1;
ERROR HY000: Invalid use of group function
SELECT SUM( (SELECT SUM(COUNT(a)) FROM t2) ) FROM t1;
ERROR HY000: Invalid use of group function
SELECT COUNT(1) FROM DUAL;
COUNT(1)
1
SELECT SUM( (SELECT AVG( (SELECT t1.a FROM t2) ) FROM DUAL) ) FROM t1;
ERROR HY000: Invalid use of group function
SELECT
SUM( (SELECT AVG( (SELECT COUNT(*) FROM t1 t HAVING t1.a < 12) ) FROM t2) )
FROM t1;
ERROR HY000: Invalid use of group function
SELECT t1.a as XXA,
SUM( (SELECT AVG( (SELECT COUNT(*) FROM t1 t HAVING XXA < 12) ) FROM t2) )
FROM t1;
ERROR HY000: Invalid use of group function
DROP TABLE t1,t2;
End of 5.0 tests.
-- source include/not_embedded.inc
-- source include/have_bdb.inc
#
# Bug #16206: Superfluous COMMIT event in binlog when updating BDB in autocommit mode
#
set autocommit=1;
let $VERSION=`select version()`;
reset master;
create table bug16206 (a int);
insert into bug16206 values(1);
start transaction;
insert into bug16206 values(2);
commit;
--replace_result $VERSION VERSION
--replace_column 1 f 2 n 5 n
show binlog events;
drop table bug16206;
reset master;
create table bug16206 (a int) engine= bdb;
insert into bug16206 values(0);
insert into bug16206 values(1);
start transaction;
insert into bug16206 values(2);
commit;
insert into bug16206 values(3);
--replace_result $VERSION VERSION
--replace_column 1 f 2 n 5 n
show binlog events;
drop table bug16206;
set autocommit=0;
--echo End of 5.0 tests
......@@ -2809,3 +2809,33 @@ SELECT a FROM t1 t0
SET @@sql_mode=default;
DROP TABLE t1;
#
# Bug #27363: nested aggregates in outer, subquery / sum(select
# count(outer))
#
CREATE TABLE t1 (a INT); INSERT INTO t1 values (1),(1),(1),(1);
CREATE TABLE t2 (x INT); INSERT INTO t1 values (1000),(1001),(1002);
--error ER_INVALID_GROUP_FUNC_USE
SELECT SUM( (SELECT COUNT(a) FROM t2) ) FROM t1;
--error ER_INVALID_GROUP_FUNC_USE
SELECT SUM( (SELECT SUM(COUNT(a)) FROM t2) ) FROM t1;
SELECT COUNT(1) FROM DUAL;
--error ER_INVALID_GROUP_FUNC_USE
SELECT SUM( (SELECT AVG( (SELECT t1.a FROM t2) ) FROM DUAL) ) FROM t1;
--error ER_INVALID_GROUP_FUNC_USE
SELECT
SUM( (SELECT AVG( (SELECT COUNT(*) FROM t1 t HAVING t1.a < 12) ) FROM t2) )
FROM t1;
--error ER_INVALID_GROUP_FUNC_USE
SELECT t1.a as XXA,
SUM( (SELECT AVG( (SELECT COUNT(*) FROM t1 t HAVING XXA < 12) ) FROM t2) )
FROM t1;
DROP TABLE t1,t2;
--echo End of 5.0 tests.
......@@ -3538,9 +3538,13 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
thd->restore_active_arena(arena, &backup);
fixed_as_field= 1;
}
/*
A reference is resolved to a nest level that's outer or the same as
the nest level of the enclosing set function : adjust the value of
max_arg_level for the function if it's needed.
*/
if (thd->lex->in_sum_func &&
thd->lex->in_sum_func->nest_level ==
thd->lex->current_select->nest_level)
thd->lex->in_sum_func->nest_level >= select->nest_level)
{
Item::Type ref_type= (*reference)->type();
set_if_bigger(thd->lex->in_sum_func->max_arg_level,
......@@ -5182,6 +5186,16 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
thd->change_item_tree(reference, fld);
mark_as_dependent(thd, last_checked_context->select_lex,
thd->lex->current_select, this, fld);
/*
A reference is resolved to a nest level that's outer or the same as
the nest level of the enclosing set function : adjust the value of
max_arg_level for the function if it's needed.
*/
if (thd->lex->in_sum_func &&
thd->lex->in_sum_func->nest_level >=
last_checked_context->select_lex->nest_level)
set_if_bigger(thd->lex->in_sum_func->max_arg_level,
last_checked_context->select_lex->nest_level);
return FALSE;
}
if (ref == 0)
......@@ -5195,6 +5209,16 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
DBUG_ASSERT(*ref && (*ref)->fixed);
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this, this);
/*
A reference is resolved to a nest level that's outer or the same as
the nest level of the enclosing set function : adjust the value of
max_arg_level for the function if it's needed.
*/
if (thd->lex->in_sum_func &&
thd->lex->in_sum_func->nest_level >=
last_checked_context->select_lex->nest_level)
set_if_bigger(thd->lex->in_sum_func->max_arg_level,
last_checked_context->select_lex->nest_level);
}
}
......
......@@ -175,13 +175,25 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref)
MYF(0));
return TRUE;
}
if (in_sum_func && in_sum_func->nest_level == nest_level)
if (in_sum_func)
{
/*
If the set function is nested adjust the value of
max_sum_func_level for the nesting set function.
We take into account only enclosed set functions that are to be
aggregated on the same level or above of the nest level of
the enclosing set function.
But we must always pass up the max_sum_func_level because it is
the maximum nested level of all directly and indirectly enclosed
set functions. We must do that even for set functions that are
aggregated inside of their enclosing set function's nest level
because the enclosing function may contain another enclosing
function that is to be aggregated outside or on the same level
as its parent's nest level.
*/
if (in_sum_func->nest_level >= aggr_level)
set_if_bigger(in_sum_func->max_sum_func_level, aggr_level);
set_if_bigger(in_sum_func->max_sum_func_level, max_sum_func_level);
}
update_used_tables();
thd->lex->in_sum_func= in_sum_func;
......
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