summaryrefslogtreecommitdiff
path: root/sql/sql_partition.cc
diff options
context:
space:
mode:
authormikael/pappa@dator5.(none) <>2006-08-22 16:52:25 -0400
committermikael/pappa@dator5.(none) <>2006-08-22 16:52:25 -0400
commiteaf68858ce827d40db7dfc42a4c3f57909e6be41 (patch)
tree4a600a40e15e6a0e54ebfe5ea6674c156ab12890 /sql/sql_partition.cc
parentddbdc16a217d5393d51ea325feac13c5a619aab3 (diff)
downloadmariadb-git-eaf68858ce827d40db7dfc42a4c3f57909e6be41.tar.gz
BUG#21658: Crash when creating table with item in prepared statement that allocates memory in fix_fields
We need to use an arena to indicate we are preparing a statement when loading partition function and parsing it as part of an open table.
Diffstat (limited to 'sql/sql_partition.cc')
-rw-r--r--sql/sql_partition.cc31
1 files changed, 24 insertions, 7 deletions
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 208f9a0837a..f5a30994f7d 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -868,9 +868,13 @@ int check_signed_flag(partition_info *part_info)
bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
bool is_sub_part, bool is_field_to_be_setup)
{
+ MEM_ROOT new_mem_root;
+ Query_arena partition_arena(&new_mem_root, Query_arena::INITIALIZED);
+ Query_arena backup_arena;
partition_info *part_info= table->part_info;
uint dir_length, home_dir_length;
bool result= TRUE;
+ bool is_prepare;
TABLE_LIST tables;
TABLE_LIST *save_table_list, *save_first_table, *save_last_table;
int error;
@@ -917,7 +921,25 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
func_expr->walk(&Item::change_context_processor, 0, (byte*) context);
save_where= thd->where;
thd->where= "partition function";
+ /*
+ In execution we must avoid the use of thd->change_item_tree since
+ we might release memory before statement is completed. We do this
+ by temporarily setting the stmt_arena->mem_root to be the mem_root
+ of the table object, this also ensures that any memory allocated
+ during fix_fields will not be released at end of execution of this
+ statement. Thus the item tree will remain valid also in subsequent
+ executions of this table object. We do however not at the moment
+ support allocations during execution of val_int so any item class
+ that does this during val_int must be disallowed as partition
+ function.
+ SEE Bug #21658
+ */
+ /*
+ This is a tricky call to prepare for since it can have a large number
+ of interesting side effects, both desirable and undesirable.
+ */
error= func_expr->fix_fields(thd, (Item**)0);
+
context->table_list= save_table_list;
context->first_name_resolution_table= save_first_table;
context->last_name_resolution_table= save_last_table;
@@ -1422,7 +1444,6 @@ bool fix_partition_func(THD *thd, TABLE *table,
DBUG_RETURN(TRUE);
}
}
- thd->free_list= part_info->item_free_list;
if (part_info->is_sub_partitioned())
{
DBUG_ASSERT(part_info->subpart_type == HASH_PARTITION);
@@ -1530,7 +1551,6 @@ bool fix_partition_func(THD *thd, TABLE *table,
set_up_range_analysis_info(part_info);
result= FALSE;
end:
- thd->free_list= thd_free_list;
thd->mark_used_columns= save_mark_used_columns;
DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
DBUG_RETURN(result);
@@ -3368,7 +3388,6 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
TABLE* table, bool is_create_table_ind,
handlerton *default_db_type)
{
- Item *thd_free_list= thd->free_list;
bool result= TRUE;
partition_info *part_info;
CHARSET_INFO *old_character_set_client= thd->variables.character_set_client;
@@ -3396,7 +3415,6 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
Thus we move away the current list temporarily and start a new list that
we then save in the partition info structure.
*/
- thd->free_list= NULL;
lex.part_info= new partition_info();/* Indicates MYSQLparse from this place */
if (!lex.part_info)
{
@@ -3409,6 +3427,7 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
if (MYSQLparse((void*)thd) || thd->is_fatal_error)
{
free_items(thd->free_list);
+ thd->free_list= NULL;
goto end;
}
/*
@@ -3477,7 +3496,6 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
if (!part_info->default_engine_type)
part_info->default_engine_type= default_db_type;
DBUG_ASSERT(part_info->default_engine_type == default_db_type);
- part_info->item_free_list= thd->free_list;
{
/*
@@ -3500,7 +3518,7 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
{
mem_alloc_error(part_func_len);
free_items(thd->free_list);
- part_info->item_free_list= 0;
+ thd->free_list= NULL;
goto end;
}
if (part_func_len)
@@ -3515,7 +3533,6 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
result= FALSE;
end:
lex_end(thd->lex);
- thd->free_list= thd_free_list;
thd->lex= old_lex;
thd->variables.character_set_client= old_character_set_client;
DBUG_RETURN(result);