#At file:///work/bzr/5.0-42037/ based on revid:azundris@stripped
2728 Gleb Shchepa 2009-01-29
Bug #42037: Queries containing a subquery with DISTINCT and
ORDER BY could cause a server crash
Dependent subqueries like
SELECT COUNT(*) FROM t1, t2 WHERE t2.b
IN (SELECT DISTINCT t2.b FROM t2 WHERE t2.b = t1.a)
hogged memory or even caused server crash on tables with
significant number of rows (for example, this query failed
on 1000 of records in every table and 50M of free
virtual memory).
Subselect engine resets JOIN structure of dependent inner
query on every row of outer table. In this case restore_tmp()
reset tmp_join->join_tab_reexec and tmp_join->table_reexec
methods to NULL pointers and the next call to make_simple_join()
reallocated them again and again.
The make_simple_join() function has been modified to
JOIN class method to store join_tab_reexec and
table_reexec values in the parent join only
(make_simple_join of tmp_join may access these values
via 'this' pointer of the parent JOIN).
NOTE: this patch doesn't include standard test case (this is
"out of memory" bug). See bug #42037 page for test cases.
modified:
sql/sql_select.cc
sql/sql_select.h
per-file messages:
sql/sql_select.cc
Bug #42037: Queries containing a subquery with DISTINCT and
ORDER BY could cause a server crash
The make_simple_join() function has been modified to
JOIN class method to store join_tab_reexec and
table_reexec values in the parent join only
(make_simple_join of tmp_join may access these values
via 'this' pointer of the parent JOIN).
sql/sql_select.h
Bug #42037: Queries containing a subquery with DISTINCT and
ORDER BY could cause a server crash
The make_simple_join() function has been modified to
JOIN class method.
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2008-12-24 15:24:11 +0000
+++ b/sql/sql_select.cc 2009-01-29 17:05:03 +0000
@@ -78,7 +78,6 @@ static store_key *get_store_key(THD *thd
KEYUSE *keyuse, table_map used_tables,
KEY_PART_INFO *key_part, char *key_buff,
uint maybe_null);
-static bool make_simple_join(JOIN *join,TABLE *tmp_table);
static void make_outerjoin_info(JOIN *join);
static bool make_join_select(JOIN *join,SQL_SELECT *select,COND *item);
static void make_join_readinfo(JOIN *join, ulonglong options);
@@ -5414,37 +5413,33 @@ store_val_in_field(Field *field, Item *i
}
-static bool
-make_simple_join(JOIN *join,TABLE *tmp_table)
+/**
+ @brief Make simple join
+
+ @param join 'this' or this->tmp_join, to build simple join there
+ @param tmp_table temporary table
+
+ @retval FALSE success
+ @retval TRUE error occurred
+*/
+bool
+JOIN::make_simple_join(JOIN *join, TABLE *tmp_table)
{
- TABLE **tableptr;
- JOIN_TAB *join_tab;
- DBUG_ENTER("make_simple_join");
+ DBUG_ENTER("JOIN::make_simple_join");
/*
Reuse TABLE * and JOIN_TAB if already allocated by a previous call
to this function through JOIN::exec (may happen for sub-queries).
*/
- if (!join->table_reexec)
- {
- if (!(join->table_reexec= (TABLE**) join->thd->alloc(sizeof(TABLE*))))
- DBUG_RETURN(TRUE); /* purecov: inspected */
- if (join->tmp_join)
- join->tmp_join->table_reexec= join->table_reexec;
- }
- if (!join->join_tab_reexec)
- {
- if (!(join->join_tab_reexec=
- (JOIN_TAB*) join->thd->alloc(sizeof(JOIN_TAB))))
- DBUG_RETURN(TRUE); /* purecov: inspected */
- if (join->tmp_join)
- join->tmp_join->join_tab_reexec= join->join_tab_reexec;
- }
- tableptr= join->table_reexec;
- join_tab= join->join_tab_reexec;
+ if (!table_reexec &&
+ !(table_reexec= (TABLE**) thd->alloc(sizeof(TABLE*))))
+ DBUG_RETURN(TRUE); /* purecov: inspected */
+ if (!join_tab_reexec &&
+ !(join_tab_reexec= (JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB))))
+ DBUG_RETURN(TRUE); /* purecov: inspected */
- join->join_tab=join_tab;
- join->table=tableptr; tableptr[0]=tmp_table;
+ join->join_tab= join_tab_reexec;
+ join->table=table_reexec; table_reexec[0]=tmp_table;
join->tables=1;
join->const_tables=0;
join->const_table_map=0;
@@ -5457,24 +5452,25 @@ make_simple_join(JOIN *join,TABLE *tmp_t
join->row_limit=join->unit->select_limit_cnt;
join->do_send_rows = (join->row_limit) ? 1 : 0;
- join_tab->cache.buff=0; /* No caching */
- join_tab->table=tmp_table;
- join_tab->select=0;
- join_tab->select_cond=0;
- join_tab->quick=0;
- join_tab->type= JT_ALL; /* Map through all records */
- join_tab->keys.init();
- join_tab->keys.set_all(); /* test everything in quick */
- join_tab->info=0;
- join_tab->on_expr_ref=0;
- join_tab->last_inner= 0;
- join_tab->first_unmatched= 0;
- join_tab->ref.key = -1;
- join_tab->not_used_in_distinct=0;
- join_tab->read_first_record= join_init_read_record;
- join_tab->join=join;
- join_tab->ref.key_parts= 0;
- bzero((char*) &join_tab->read_record,sizeof(join_tab->read_record));
+ join_tab_reexec->cache.buff=0; /* No caching */
+ join_tab_reexec->table=tmp_table;
+ join_tab_reexec->select=0;
+ join_tab_reexec->select_cond=0;
+ join_tab_reexec->quick=0;
+ join_tab_reexec->type= JT_ALL; /* Map through all records */
+ join_tab_reexec->keys.init();
+ join_tab_reexec->keys.set_all(); /* test everything in quick */
+ join_tab_reexec->info=0;
+ join_tab_reexec->on_expr_ref=0;
+ join_tab_reexec->last_inner= 0;
+ join_tab_reexec->first_unmatched= 0;
+ join_tab_reexec->ref.key = -1;
+ join_tab_reexec->not_used_in_distinct=0;
+ join_tab_reexec->read_first_record= join_init_read_record;
+ join_tab_reexec->join=join;
+ join_tab_reexec->ref.key_parts= 0;
+ bzero((char*) &join_tab_reexec->read_record,
+ sizeof(join_tab_reexec->read_record));
tmp_table->status=0;
tmp_table->null_row=0;
DBUG_RETURN(FALSE);
=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h 2008-12-24 15:24:11 +0000
+++ b/sql/sql_select.h 2009-01-29 17:05:03 +0000
@@ -476,6 +476,8 @@ public:
return (unit == &thd->lex->unit && (unit->fake_select_lex == 0 ||
select_lex == unit->fake_select_lex));
}
+private:
+ bool make_simple_join(JOIN *join, TABLE *tmp_table);
};
| Thread |
|---|
| • bzr commit into mysql-5.0-bugteam branch (gshchepa:2728) Bug#42037 | Gleb Shchepa | 29 Jan |