#At file:///home/rl136806/mysql/repo/mysql-next-mr-opt-backporting/ based on revid:olav@stripped
3148 Roy Lyseng 2010-05-07
Bug#50089: Second call of procedure with view in subselect crashes server
The bug case contains a query that references a view.
Here is the view definition:
SELECT t1field AS v1_field
FROM t1 AS A
WHERE A.t1field IN (SELECT t1field FROM t1);
When expanding the view at prepare time, this select_lex graph is created:
VS1(A)
\
VS2(t1)
This is the query that is executed:
SELECT t1field FROM t1
WHERE t1field IN (SELECT * FROM v1);
At prepare time, the query is conceptually expanded to the following query:
SELECT t1field FROM t1
WHERE t1field IN (SELECT t1field AS v1_field
FROM t1 AS A
WHERE A.t1field IN (SELECT t1field FROM t1));
Here is the select_lex graph after view expansion:
S1(t1)
\
S2(A)
\
VS2(t1)
The contents of select_lex VS1 is merged with the query graph and VS1
is discarded after merging.
At first execution, semijoin conversion is performed, and the query is
transformed to:
SELECT t1_field FROM t1 semijoin t1 AS A
ON t1.t1_field = A.t1_field
WHERE A.t1_field IN (SELECT t1_field FROM t1));
Now, the select_lex object S2 is optimized away and the table A is added to S1.
Here is the select_lex graph after transformation:
S1(t1)
\
VS2(t1)
The master field of VS2 points to S1 after conversion.
However, the return_to field of VS2 still points to VS1.
First execution proceeds normally after this.
At second execution, all items in the transformed query are first re-resolved.
When re-resolving A.t1_field, function mark_select_range_as_dependent()
is called with VS1 as current_sel and S1 as last_select arguments.
Now, the master unit of VS1 does not have an "item", and we segfault.
Problem occurs when mark_select_range_as_dependent() is called with two
select_lex pointers that point into different query trees, one tree being
the main query tree, the other being the tree representing the view.
This problem is due to the fact that the function return_after_parsing() is
used to provide pointer to the select_lex object representing the outer
query specification of a subquery. However, the return_to field was not
properly updated in all situations. But it was also noticed that
outer_select() gives the same information as return_after_parsing(),
and the data used by this function is always kept up-to-date.
The bug was thus fixed by removing return_after_parsing() and associated data,
and replacing calls with outer_select().
Notice also that queries within procedures internally create
prepared statements, so the solution works equally well for procedures
as well as for prepared statements.
mysql-test/r/subselect_sj.result
Test result for Bug#50089
mysql-test/r/subselect_sj_jcl6.result
Test result for Bug#50089
mysql-test/t/subselect_sj.test
Test case for Bug#50089
sql/item_subselect.cc
Replaced references to return_after_parsing() with outer_select().
sql/sql_lex.cc
Removed function return_after_parsing() and data field return_to.
sql/sql_lex.h
Removed function return_after_parsing() and data field return_to.
sql/sql_parse.cc
Replaced reference to return_after_parsing() with outer_select().
sql/sql_select.cc
Replaced reference to return_after_parsing() with outer_select().
sql/sql_yacc.yy
Replaced reference to return_after_parsing() with outer_select().
revid:marc.alff@stripped@sun.com-20100310111425-7r30qg17f5z13ptd
modified:
mysql-test/r/subselect_sj.result
mysql-test/r/subselect_sj_jcl6.result
mysql-test/t/subselect_sj.test
sql/item_subselect.cc
sql/sql_lex.cc
sql/sql_lex.h
sql/sql_parse.cc
sql/sql_select.cc
sql/sql_yacc.yy
=== modified file 'mysql-test/r/subselect_sj.result'
--- a/mysql-test/r/subselect_sj.result 2010-05-07 11:31:49 +0000
+++ b/mysql-test/r/subselect_sj.result 2010-05-07 12:17:07 +0000
@@ -1221,3 +1221,58 @@ id select_type table type possible_keys
1 PRIMARY it2 ALL NULL NULL NULL NULL 20 Using where; End temporary
DROP TABLE ot1, it1, it2;
# End of BUG#38075
+#
+# BUG#50089: Second call of procedure with view in subselect crashes server
+#
+CREATE TABLE t1(t1field INTEGER, PRIMARY KEY(t1field));
+CREATE VIEW v1 AS
+SELECT t1field AS v1field
+FROM t1 A
+WHERE A.t1field IN (SELECT t1field FROM t1);
+INSERT INTO t1 VALUES(1),(2);
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+t1field
+1
+2
+EXPLAIN
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 2 Using where; Using index
+1 PRIMARY A eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
+4 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 Using index
+CREATE PROCEDURE p1()
+BEGIN
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+END|
+CALL p1;
+t1field
+1
+2
+CALL p1;
+t1field
+1
+2
+PREPARE stmt FROM
+"
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+";
+EXECUTE stmt;
+t1field
+1
+2
+EXECUTE stmt;
+t1field
+1
+2
+DROP PROCEDURE p1;
+DROP VIEW v1;
+DROP TABLE t1;
+# End of BUG#50089
=== modified file 'mysql-test/r/subselect_sj_jcl6.result'
--- a/mysql-test/r/subselect_sj_jcl6.result 2010-05-07 11:31:49 +0000
+++ b/mysql-test/r/subselect_sj_jcl6.result 2010-05-07 12:17:07 +0000
@@ -1225,6 +1225,61 @@ id select_type table type possible_keys
1 PRIMARY it2 ALL NULL NULL NULL NULL 20 Using where; End temporary; Using join buffer
DROP TABLE ot1, it1, it2;
# End of BUG#38075
+#
+# BUG#50089: Second call of procedure with view in subselect crashes server
+#
+CREATE TABLE t1(t1field INTEGER, PRIMARY KEY(t1field));
+CREATE VIEW v1 AS
+SELECT t1field AS v1field
+FROM t1 A
+WHERE A.t1field IN (SELECT t1field FROM t1);
+INSERT INTO t1 VALUES(1),(2);
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+t1field
+1
+2
+EXPLAIN
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 2 Using where; Using index
+1 PRIMARY A eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
+4 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 Using index
+CREATE PROCEDURE p1()
+BEGIN
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+END|
+CALL p1;
+t1field
+1
+2
+CALL p1;
+t1field
+1
+2
+PREPARE stmt FROM
+"
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+";
+EXECUTE stmt;
+t1field
+1
+2
+EXECUTE stmt;
+t1field
+1
+2
+DROP PROCEDURE p1;
+DROP VIEW v1;
+DROP TABLE t1;
+# End of BUG#50089
set join_cache_level=default;
show variables like 'join_cache_level';
Variable_name Value
=== modified file 'mysql-test/t/subselect_sj.test'
--- a/mysql-test/t/subselect_sj.test 2010-05-07 11:31:49 +0000
+++ b/mysql-test/t/subselect_sj.test 2010-05-07 12:17:07 +0000
@@ -900,3 +900,53 @@ WHERE int_nokey IN (SELECT it2.int_key
DROP TABLE ot1, it1, it2;
--echo # End of BUG#38075
+
+--echo #
+--echo # BUG#50089: Second call of procedure with view in subselect crashes server
+--echo #
+
+CREATE TABLE t1(t1field INTEGER, PRIMARY KEY(t1field));
+
+CREATE VIEW v1 AS
+ SELECT t1field AS v1field
+ FROM t1 A
+ WHERE A.t1field IN (SELECT t1field FROM t1);
+
+INSERT INTO t1 VALUES(1),(2);
+
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+
+EXPLAIN
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+
+delimiter |;
+CREATE PROCEDURE p1()
+ BEGIN
+ SELECT t1field
+ FROM t1
+ WHERE t1field IN (SELECT v1field FROM v1);
+ END|
+delimiter ;|
+
+CALL p1;
+CALL p1;
+
+PREPARE stmt FROM
+"
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+";
+
+EXECUTE stmt;
+EXECUTE stmt;
+
+DROP PROCEDURE p1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+--echo # End of BUG#50089
=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc 2010-05-02 19:14:50 +0000
+++ b/sql/item_subselect.cc 2010-05-07 12:17:07 +0000
@@ -1104,9 +1104,9 @@ Item_in_subselect::single_value_transfor
SELECT_LEX_UNIT *master_unit= select_lex->master_unit();
substitution= optimizer;
- SELECT_LEX *current= thd->lex->current_select, *up;
+ SELECT_LEX *current= thd->lex->current_select;
- thd->lex->current_select= up= current->return_after_parsing();
+ thd->lex->current_select= current->outer_select();
//optimizer never use Item **ref => we can pass 0 as parameter
if (!optimizer || optimizer->fix_left(thd, 0))
{
@@ -1391,8 +1391,8 @@ Item_in_subselect::row_value_transformer
SELECT_LEX_UNIT *master_unit= select_lex->master_unit();
substitution= optimizer;
- SELECT_LEX *current= thd->lex->current_select, *up;
- thd->lex->current_select= up= current->return_after_parsing();
+ SELECT_LEX *current= thd->lex->current_select;
+ thd->lex->current_select= current->outer_select();
//optimizer never use Item **ref => we can pass 0 as parameter
if (!optimizer || optimizer->fix_left(thd, 0))
{
@@ -1722,7 +1722,7 @@ Item_in_subselect::select_in_like_transf
goto err;
}
- thd->lex->current_select= up= current->return_after_parsing();
+ thd->lex->current_select= current->outer_select();
result= (!left_expr->fixed &&
left_expr->fix_fields(thd, optimizer->arguments()));
/* fix_fields can change reference to left_expr, we need reassign it */
=== modified file 'sql/sql_lex.cc'
--- a/sql/sql_lex.cc 2010-04-16 09:07:23 +0000
+++ b/sql/sql_lex.cc 2010-05-07 12:17:07 +0000
@@ -327,8 +327,7 @@ void lex_start(THD *thd)
lex->view_list.empty();
lex->prepared_stmt_params.empty();
lex->auxiliary_table_list.empty();
- lex->unit.next= lex->unit.master=
- lex->unit.link_next= lex->unit.return_to= 0;
+ lex->unit.next= lex->unit.master= lex->unit.link_next= 0;
lex->unit.prev= lex->unit.link_prev= 0;
lex->unit.slave= lex->unit.global_parameters= lex->current_select=
lex->all_selects_list= &lex->select_lex;
=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h 2010-04-16 09:07:23 +0000
+++ b/sql/sql_lex.h 2010-05-07 12:17:07 +0000
@@ -399,7 +399,6 @@ public:
virtual st_select_lex_unit* master_unit()= 0;
virtual st_select_lex* outer_select()= 0;
- virtual st_select_lex* return_after_parsing()= 0;
virtual bool set_braces(bool value);
virtual bool inc_in_sum_expr();
@@ -478,8 +477,6 @@ public:
global parameters for union
*/
st_select_lex *global_parameters;
- //node on wich we should return current_select pointer after parsing subquery
- st_select_lex *return_to;
/* LIMIT clause runtime counters */
ha_rows select_limit_cnt, offset_limit_cnt;
/* not NULL if unit used in subselect, point to subselect item */
@@ -507,7 +504,6 @@ public:
{
return my_reinterpret_cast(st_select_lex_unit*)(next);
}
- st_select_lex* return_after_parsing() { return return_to; }
void exclude_level();
void exclude_tree();
@@ -702,11 +698,6 @@ public:
{
return &link_next;
}
- st_select_lex* return_after_parsing()
- {
- return master_unit()->return_after_parsing();
- }
-
void mark_as_dependent(st_select_lex *last);
bool set_braces(bool value);
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2010-04-16 09:07:23 +0000
+++ b/sql/sql_parse.cc 2010-05-07 12:17:07 +0000
@@ -5559,7 +5559,6 @@ mysql_new_select(LEX *lex, bool move_dow
unit->include_down(lex->current_select);
unit->link_next= 0;
unit->link_prev= 0;
- unit->return_to= lex->current_select;
select_lex->include_down(unit);
/*
By default we assume that it is usual subselect and we have outer name
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2010-05-07 11:31:49 +0000
+++ b/sql/sql_select.cc 2010-05-07 12:17:07 +0000
@@ -619,7 +619,7 @@ JOIN::prepare(Item ***rref_pointer_array
}
SELECT_LEX *current= thd->lex->current_select;
- thd->lex->current_select= current->return_after_parsing();
+ thd->lex->current_select= current->outer_select();
char const *save_where= thd->where;
thd->where= "IN/ALL/ANY subquery";
=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy 2010-04-16 09:07:23 +0000
+++ b/sql/sql_yacc.yy 2010-05-07 12:17:07 +0000
@@ -13723,7 +13723,7 @@ subselect_end:
lex->pop_context();
SELECT_LEX *child= lex->current_select;
- lex->current_select = lex->current_select->return_after_parsing();
+ lex->current_select = lex->current_select->outer_select();
lex->nest_level--;
lex->current_select->n_child_sum_items += child->n_sum_items;
/*
Attachment: [text/bzr-bundle] bzr/roy.lyseng@sun.com-20100507121707-4rodtuem07qn03mi.bundle
| Thread |
|---|
| • bzr commit into mysql-next-mr-bugfixing branch (roy.lyseng:3148) Bug#50089 | Roy Lyseng | 7 May |