Commit d3d3cef8 authored by igor@rurik.mysql.com's avatar igor@rurik.mysql.com

Fixed bug #21493: crash for the second execution of a function

containing a select statement that uses an aggregating IN subquery.
Added a parameter to the function fix_prepare_information 
to restore correctly the having clause for the second execution.
Saved andor structure of the having conditions at the proper moment
before any calls of split_sum_func2 that could modify the having structure
adding new Item_ref objects. (These additions, are produced not with 
the statement mem_root, but rather with the execution mem_root.)
parent aa7ae805
...@@ -5256,4 +5256,67 @@ a ...@@ -5256,4 +5256,67 @@ a
1 1
use test| use test|
drop table t3| drop table t3|
CREATE TABLE t3 (
Member_ID varchar(15) NOT NULL,
PRIMARY KEY (Member_ID)
)|
CREATE TABLE t4 (
ID int(10) unsigned NOT NULL auto_increment,
Member_ID varchar(15) NOT NULL default '',
Action varchar(12) NOT NULL,
Action_Date datetime NOT NULL,
Track varchar(15) default NULL,
User varchar(12) default NULL,
Date_Updated timestamp NOT NULL default CURRENT_TIMESTAMP on update
CURRENT_TIMESTAMP,
PRIMARY KEY (ID),
KEY Action (Action),
KEY Action_Date (Action_Date)
)|
INSERT INTO t3(Member_ID) VALUES
('111111'), ('222222'), ('333333'), ('444444'), ('555555'), ('666666')|
INSERT INTO t4(Member_ID, Action, Action_Date, Track) VALUES
('111111', 'Disenrolled', '2006-03-01', 'CAD' ),
('111111', 'Enrolled', '2006-03-01', 'CAD' ),
('111111', 'Disenrolled', '2006-07-03', 'CAD' ),
('222222', 'Enrolled', '2006-03-07', 'CAD' ),
('222222', 'Enrolled', '2006-03-07', 'CHF' ),
('222222', 'Disenrolled', '2006-08-02', 'CHF' ),
('333333', 'Enrolled', '2006-03-01', 'CAD' ),
('333333', 'Disenrolled', '2006-03-01', 'CAD' ),
('444444', 'Enrolled', '2006-03-01', 'CAD' ),
('555555', 'Disenrolled', '2006-03-01', 'CAD' ),
('555555', 'Enrolled', '2006-07-21', 'CAD' ),
('555555', 'Disenrolled', '2006-03-01', 'CHF' ),
('666666', 'Enrolled', '2006-02-09', 'CAD' ),
('666666', 'Enrolled', '2006-05-12', 'CHF' ),
('666666', 'Disenrolled', '2006-06-01', 'CAD' )|
DROP FUNCTION IF EXISTS bug21493|
Warnings:
Note 1305 FUNCTION bug21493 does not exist
CREATE FUNCTION bug21493(paramMember VARCHAR(15)) RETURNS varchar(45)
BEGIN
DECLARE tracks VARCHAR(45);
SELECT GROUP_CONCAT(Track SEPARATOR ', ') INTO tracks FROM t4
WHERE Member_ID=paramMember AND Action='Enrolled' AND
(Track,Action_Date) IN (SELECT Track, MAX(Action_Date) FROM t4
WHERE Member_ID=paramMember GROUP BY Track);
RETURN tracks;
END|
SELECT bug21493('111111')|
bug21493('111111')
NULL
SELECT bug21493('222222')|
bug21493('222222')
CAD
SELECT bug21493(Member_ID) FROM t3|
bug21493(Member_ID)
NULL
CAD
CAD
CAD
CAD
CHF
DROP FUNCTION bug21493|
DROP TABLE t3,t4|
drop table t1,t2; drop table t1,t2;
...@@ -6188,6 +6188,73 @@ select * from (select 1 as a) as t1 natural join (select * from test.t3) as t2| ...@@ -6188,6 +6188,73 @@ select * from (select 1 as a) as t1 natural join (select * from test.t3) as t2|
use test| use test|
drop table t3| drop table t3|
#
# BUG#21493: Crash on the second call of a procedure containing
# a select statement that uses an IN aggregating subquery
#
CREATE TABLE t3 (
Member_ID varchar(15) NOT NULL,
PRIMARY KEY (Member_ID)
)|
CREATE TABLE t4 (
ID int(10) unsigned NOT NULL auto_increment,
Member_ID varchar(15) NOT NULL default '',
Action varchar(12) NOT NULL,
Action_Date datetime NOT NULL,
Track varchar(15) default NULL,
User varchar(12) default NULL,
Date_Updated timestamp NOT NULL default CURRENT_TIMESTAMP on update
CURRENT_TIMESTAMP,
PRIMARY KEY (ID),
KEY Action (Action),
KEY Action_Date (Action_Date)
)|
INSERT INTO t3(Member_ID) VALUES
('111111'), ('222222'), ('333333'), ('444444'), ('555555'), ('666666')|
INSERT INTO t4(Member_ID, Action, Action_Date, Track) VALUES
('111111', 'Disenrolled', '2006-03-01', 'CAD' ),
('111111', 'Enrolled', '2006-03-01', 'CAD' ),
('111111', 'Disenrolled', '2006-07-03', 'CAD' ),
('222222', 'Enrolled', '2006-03-07', 'CAD' ),
('222222', 'Enrolled', '2006-03-07', 'CHF' ),
('222222', 'Disenrolled', '2006-08-02', 'CHF' ),
('333333', 'Enrolled', '2006-03-01', 'CAD' ),
('333333', 'Disenrolled', '2006-03-01', 'CAD' ),
('444444', 'Enrolled', '2006-03-01', 'CAD' ),
('555555', 'Disenrolled', '2006-03-01', 'CAD' ),
('555555', 'Enrolled', '2006-07-21', 'CAD' ),
('555555', 'Disenrolled', '2006-03-01', 'CHF' ),
('666666', 'Enrolled', '2006-02-09', 'CAD' ),
('666666', 'Enrolled', '2006-05-12', 'CHF' ),
('666666', 'Disenrolled', '2006-06-01', 'CAD' )|
#--disable_warnings
DROP FUNCTION IF EXISTS bug21493|
#--enable_warnings
CREATE FUNCTION bug21493(paramMember VARCHAR(15)) RETURNS varchar(45)
BEGIN
DECLARE tracks VARCHAR(45);
SELECT GROUP_CONCAT(Track SEPARATOR ', ') INTO tracks FROM t4
WHERE Member_ID=paramMember AND Action='Enrolled' AND
(Track,Action_Date) IN (SELECT Track, MAX(Action_Date) FROM t4
WHERE Member_ID=paramMember GROUP BY Track);
RETURN tracks;
END|
SELECT bug21493('111111')|
SELECT bug21493('222222')|
SELECT bug21493(Member_ID) FROM t3|
DROP FUNCTION bug21493|
DROP TABLE t3,t4|
# #
# BUG#NNNN: New bug synopsis # BUG#NNNN: New bug synopsis
# #
......
...@@ -342,6 +342,7 @@ cleanup: ...@@ -342,6 +342,7 @@ cleanup:
*/ */
bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
{ {
Item *fake_conds= 0;
SELECT_LEX *select_lex= &thd->lex->select_lex; SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_prepare_delete"); DBUG_ENTER("mysql_prepare_delete");
...@@ -367,7 +368,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) ...@@ -367,7 +368,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
} }
select_lex->fix_prepare_information(thd, conds); select_lex->fix_prepare_information(thd, conds, &fake_conds);
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
......
...@@ -993,7 +993,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, ...@@ -993,7 +993,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
update_non_unique_table_error(table_list, "INSERT", duplicate); update_non_unique_table_error(table_list, "INSERT", duplicate);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
select_lex->fix_prepare_information(thd, &fake_conds); select_lex->fix_prepare_information(thd, &fake_conds, &fake_conds);
select_lex->first_execution= 0; select_lex->first_execution= 0;
} }
if (duplic == DUP_UPDATE || duplic == DUP_REPLACE) if (duplic == DUP_UPDATE || duplic == DUP_REPLACE)
......
...@@ -2155,15 +2155,25 @@ static void fix_prepare_info_in_table_list(THD *thd, TABLE_LIST *tbl) ...@@ -2155,15 +2155,25 @@ static void fix_prepare_info_in_table_list(THD *thd, TABLE_LIST *tbl)
/* /*
fix some structures at the end of preparation Save WHERE/HAVING/ON clauses and replace them with disposable copies
SYNOPSIS SYNOPSIS
st_select_lex::fix_prepare_information st_select_lex::fix_prepare_information
thd thread handler thd thread handler
conds pointer on conditions which will be used for execution statement conds in/out pointer to WHERE condition to be met at execution
having_conds in/out pointer to HAVING condition to be met at execution
DESCRIPTION
The passed WHERE and HAVING are to be saved for the future executions.
This function saves it, and returns a copy which can be thrashed during
this execution of the statement. By saving/thrashing here we mean only
AND/OR trees.
The function also calls fix_prepare_info_in_table_list that saves all
ON expressions.
*/ */
void st_select_lex::fix_prepare_information(THD *thd, Item **conds) void st_select_lex::fix_prepare_information(THD *thd, Item **conds,
Item **having_conds)
{ {
if (!thd->stmt_arena->is_conventional() && first_execution) if (!thd->stmt_arena->is_conventional() && first_execution)
{ {
...@@ -2173,6 +2183,11 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds) ...@@ -2173,6 +2183,11 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds)
prep_where= *conds; prep_where= *conds;
*conds= where= prep_where->copy_andor_structure(thd); *conds= where= prep_where->copy_andor_structure(thd);
} }
if (*having_conds)
{
prep_having= *having_conds;
*having_conds= having= prep_having->copy_andor_structure(thd);
}
fix_prepare_info_in_table_list(thd, (TABLE_LIST *)table_list.first); fix_prepare_info_in_table_list(thd, (TABLE_LIST *)table_list.first);
} }
} }
......
...@@ -656,7 +656,7 @@ public: ...@@ -656,7 +656,7 @@ public:
void print(THD *thd, String *str); void print(THD *thd, String *str);
static void print_order(String *str, ORDER *order); static void print_order(String *str, ORDER *order);
void print_limit(THD *thd, String *str); void print_limit(THD *thd, String *str);
void fix_prepare_information(THD *thd, Item **conds); void fix_prepare_information(THD *thd, Item **conds, Item **having_conds);
/* /*
Destroy the used execution plan (JOIN) of this subtree (this Destroy the used execution plan (JOIN) of this subtree (this
SELECT_LEX and all nested SELECT_LEXes and SELECT_LEX_UNITs). SELECT_LEX and all nested SELECT_LEXes and SELECT_LEX_UNITs).
......
...@@ -382,12 +382,14 @@ JOIN::prepare(Item ***rref_pointer_array, ...@@ -382,12 +382,14 @@ JOIN::prepare(Item ***rref_pointer_array,
if ((res= subselect->select_transformer(this)) != if ((res= subselect->select_transformer(this)) !=
Item_subselect::RES_OK) Item_subselect::RES_OK)
{ {
select_lex->fix_prepare_information(thd, &conds); select_lex->fix_prepare_information(thd, &conds, &having);
DBUG_RETURN((res == Item_subselect::RES_ERROR)); DBUG_RETURN((res == Item_subselect::RES_ERROR));
} }
} }
} }
select_lex->fix_prepare_information(thd, &conds, &having);
if (having && having->with_sum_func) if (having && having->with_sum_func)
having->split_sum_func2(thd, ref_pointer_array, all_fields, having->split_sum_func2(thd, ref_pointer_array, all_fields,
&having, TRUE); &having, TRUE);
...@@ -499,7 +501,6 @@ JOIN::prepare(Item ***rref_pointer_array, ...@@ -499,7 +501,6 @@ JOIN::prepare(Item ***rref_pointer_array,
if (alloc_func_list()) if (alloc_func_list())
goto err; goto err;
select_lex->fix_prepare_information(thd, &conds);
DBUG_RETURN(0); // All OK DBUG_RETURN(0); // All OK
err: err:
...@@ -618,7 +619,6 @@ JOIN::optimize() ...@@ -618,7 +619,6 @@ JOIN::optimize()
build_bitmap_for_nested_joins(join_list, 0); build_bitmap_for_nested_joins(join_list, 0);
sel->prep_where= conds ? conds->copy_andor_structure(thd) : 0; sel->prep_where= conds ? conds->copy_andor_structure(thd) : 0;
sel->prep_having= having ? having->copy_andor_structure(thd) : 0;
if (arena) if (arena)
thd->restore_active_arena(arena, &backup); thd->restore_active_arena(arena, &backup);
......
...@@ -606,6 +606,7 @@ err: ...@@ -606,6 +606,7 @@ err:
bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
Item **conds, uint order_num, ORDER *order) Item **conds, uint order_num, ORDER *order)
{ {
Item *fake_conds= 0;
TABLE *table= table_list->table; TABLE *table= table_list->table;
TABLE_LIST tables; TABLE_LIST tables;
List<Item> all_fields; List<Item> all_fields;
...@@ -645,7 +646,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, ...@@ -645,7 +646,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
} }
select_lex->fix_prepare_information(thd, conds); select_lex->fix_prepare_information(thd, conds, &fake_conds);
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
......
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