summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorNorvald H. Ryeng <norvald.ryeng@oracle.com>2012-06-18 09:20:12 +0200
committerNorvald H. Ryeng <norvald.ryeng@oracle.com>2012-06-18 09:20:12 +0200
commitcac1cd88abc2a610b42b89e5d39029f75a760ec4 (patch)
treec4d5604331727c57642122db740aa74296fcc3ee /sql
parentbc42eaf95283f66788a70acbed1d7368c784a9a1 (diff)
downloadmariadb-git-cac1cd88abc2a610b42b89e5d39029f75a760ec4.tar.gz
Bug#13003736 CRASH IN ITEM_REF::WALK WITH SUBQUERIES
Problem: Some queries with subqueries and a HAVING clause that consists only of a column not in the select or grouping lists causes the server to crash. During parsing, an Item_ref is constructed for the HAVING column. The name of the column is resolved when JOIN::prepare calls fix_fields() on its having clause. Since the column is not mentioned in the select or grouping lists, a ref pointer is not found and a new Item_field is created instead. The Item_ref is replaced by the Item_field in the tree of HAVING clauses. Since the tree consists only of this item, the pointer that is updated is JOIN::having. However, st_select_lex::having still points to the Item_ref as the root of the tree of HAVING clauses. The bug is triggered when doing filesort for create_sort_index(). When find_all_keys() calls select->cond->walk() it eventually reaches Item_subselect::walk() where it continues to walk the having clauses from lex->having. This means that it finds the Item_ref instead of the new Item_field, and Item_ref::walk() tries to dereference the ref pointer, which is still null. The crash is reproducible only in 5.5, but the problem lies latent in 5.1 and trunk as well. Fix: After calling fix_fields on the having clause in JOIN::prepare(), set select_lex::having to point to the same item as JOIN::having. This patch also fixes a bug in 5.1 and 5.5 that is triggered if the query is executed as a prepared statement. The Item_field is created in the runtime arena when the query is prepared, and the pointer to the item is saved by st_select_lex::fix_prepare_information() and brought back as a dangling pointer when the query is executed, after the runtime arena has been reclaimed. Fix: Backport fix from trunk that switches to the permanent arena before calling Item_ref::fix_fields() in JOIN::prepare(). sql/item.cc: Set context when creating Item_field. sql/sql_select.cc: Switch to permanent arena and update select_lex->having.
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc2
-rw-r--r--sql/sql_select.cc6
2 files changed, 7 insertions, 1 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 90bfb0d2852..356fe4827c8 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -6010,7 +6010,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
if (from_field != not_found_field)
{
Item_field* fld;
- if (!(fld= new Item_field(from_field)))
+ if (!(fld= new Item_field(thd, last_checked_context, from_field)))
goto error;
thd->change_item_tree(reference, fld);
mark_as_dependent(thd, last_checked_context->select_lex,
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 7c3d2de22bc..f2007f609e0 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -528,6 +528,8 @@ JOIN::prepare(Item ***rref_pointer_array,
if (having)
{
+ Query_arena backup, *arena;
+ arena= thd->activate_stmt_arena_if_needed(&backup);
nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
thd->where="having clause";
thd->lex->allow_sum_func|= 1 << select_lex_arg->nest_level;
@@ -536,6 +538,10 @@ JOIN::prepare(Item ***rref_pointer_array,
(having->fix_fields(thd, &having) ||
having->check_cols(1)));
select_lex->having_fix_field= 0;
+ select_lex->having= having;
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+
if (having_fix_rc || thd->is_error())
DBUG_RETURN(-1); /* purecov: inspected */
thd->lex->allow_sum_func= save_allow_sum_func;