diff options
author | Norvald H. Ryeng <norvald.ryeng@oracle.com> | 2012-06-18 09:20:12 +0200 |
---|---|---|
committer | Norvald H. Ryeng <norvald.ryeng@oracle.com> | 2012-06-18 09:20:12 +0200 |
commit | cac1cd88abc2a610b42b89e5d39029f75a760ec4 (patch) | |
tree | c4d5604331727c57642122db740aa74296fcc3ee /sql | |
parent | bc42eaf95283f66788a70acbed1d7368c784a9a1 (diff) | |
download | mariadb-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.cc | 2 | ||||
-rw-r--r-- | sql/sql_select.cc | 6 |
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; |