#At file:///home/mikael/mysql_clones/mysql-6.0-bugteam-bug32115/
3477 Mikael Ronstrom 2009-07-29
Bug#32115, made use of local lex object to avoid side effects of opening partitioned
tables
modified:
sql/sql_partition.cc
=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc 2009-07-08 12:17:27 +0000
+++ b/sql/sql_partition.cc 2009-07-29 14:06:35 +0000
@@ -859,6 +859,84 @@ int check_signed_flag(partition_info *pa
return error;
}
+/*
+ Initialize lex object for use in fix_fields and parsing.
+
+ SYNOPSIS
+ init_lex_with_single_table()
+ thd The thread object
+ table The table object
+ RETURN VALUE
+ TRUE An error occurred, memory allocation error
+ FALSE Ok
+
+ DESCRIPTION
+ This function is used to initialize a lex object on the
+ stack for use by fix_fields and for parsing. In order to
+ work properly it also needs to initialize the
+ Name_resolution_context object of the lexer.
+ Finally it needs to set a couple of variables to ensure
+ proper functioning of fix_fields.
+*/
+
+static int
+init_lex_with_single_table(THD *thd, TABLE *table)
+{
+ TABLE_LIST *table_list;
+ Table_ident *table_ident;
+ LEX *lex= thd->lex;
+ /*
+ We will call the parser to create a part_info struct based on the
+ partition string stored in the frm file.
+ We will use a local lex object for this purpose. However we also
+ need to set the Name_resolution_object for this lex object. We
+ do this by using add_table_to_list where we add the table that
+ we're working with to the Name_resolution_context.
+ */
+ lex_start(thd);
+ lex->select_lex.context.init();
+ if ((!(table_ident= new Table_ident(thd,
+ table->s->table_name,
+ table->s->db, TRUE))) ||
+ (!(table_list= lex->select_lex.add_table_to_list(thd,
+ table_ident,
+ NULL,
+ 0))))
+ return TRUE;
+ lex->select_lex.context.table_list=
+ lex->select_lex.context.first_name_resolution_table= table_list;
+ lex->use_only_table_context= TRUE;
+ lex->select_lex.cur_pos_in_select_list= UNDEF_POS;
+ table->map= 1; //To ensure correct calculation of const item
+ table->get_fields_in_item_tree= TRUE;
+ table_list->table= table;
+ return FALSE;
+}
+
+/*
+ End use of local lex with single table
+
+ SYNOPSIS
+ end_lex_with_single_table()
+ thd The thread object
+ table The table object
+ old_lex The real lex object connected to THD
+
+ DESCRIPTION
+ This function restores the real lex object after calling
+ init_lex_with_single_table and also restores some table
+ variables temporarily set.
+*/
+
+static int
+end_lex_with_single_table(THD *thd, TABLE *table, LEX *old_lex)
+{
+ LEX *lex= thd->lex;
+ table->map= 0;
+ table->get_fields_in_item_tree= FALSE;
+ lex_end(lex);
+ thd->lex= old_lex;
+}
/*
The function uses a new feature in fix_fields where the flag
@@ -900,18 +978,20 @@ bool fix_fields_part_func(THD *thd, Item
bool is_sub_part, bool is_field_to_be_setup)
{
partition_info *part_info= table->part_info;
- uint dir_length, home_dir_length;
bool result= TRUE;
- TABLE_LIST tables;
- TABLE_LIST *save_table_list, *save_first_table, *save_last_table;
int error;
- Name_resolution_context *context;
const char *save_where;
- char* db_name;
- char db_name_string[FN_REFLEN];
- bool save_use_only_table_context;
+ LEX *old_lex= thd->lex;
+ LEX lex;
DBUG_ENTER("fix_fields_part_func");
+ thd->lex= &lex;
+ if (init_lex_with_single_table(thd, table))
+ {
+ mem_alloc_error(sizeof(Table_ident));
+ goto end;
+ }
+
if (part_info->fixed)
{
if (!(is_sub_part || (error= check_signed_flag(part_info))))
@@ -919,43 +999,8 @@ bool fix_fields_part_func(THD *thd, Item
goto end;
}
- /*
- Set-up the TABLE_LIST object to be a list with a single table
- Set the object to zero to create NULL pointers and set alias
- and real name to table name and get database name from file name.
- TODO: Consider generalizing or refactoring Lex::add_table_to_list() so
- it can be used in all places where we create TABLE_LIST objects.
- Also consider creating appropriate constructors for TABLE_LIST.
- */
-
- bzero((void*)&tables, sizeof(TABLE_LIST));
- tables.alias= tables.table_name= (char*) table->s->table_name.str;
- tables.table= table;
- tables.next_local= 0;
- tables.next_name_resolution_table= 0;
- /*
- Cache the table in Item_fields. All the tables can be cached except
- the trigger pseudo table.
- */
- tables.cacheable_table= TRUE;
- context= thd->lex->current_context();
- tables.select_lex= context->select_lex;
- strmov(db_name_string, table->s->normalized_path.str);
- dir_length= dirname_length(db_name_string);
- db_name_string[dir_length - 1]= 0;
- home_dir_length= dirname_length(db_name_string);
- db_name= &db_name_string[home_dir_length];
- tables.db= db_name;
-
- table->map= 1; //To ensure correct calculation of const item
- table->get_fields_in_item_tree= TRUE;
- save_table_list= context->table_list;
- save_first_table= context->first_name_resolution_table;
- save_last_table= context->last_name_resolution_table;
- context->table_list= &tables;
- context->first_name_resolution_table= &tables;
- context->last_name_resolution_table= NULL;
- func_expr->walk(&Item::change_context_processor, 0, (uchar*) context);
+ func_expr->walk(&Item::change_context_processor, 0,
+ (uchar*) &lex.select_lex.context);
save_where= thd->where;
thd->where= "partition function";
/*
@@ -970,23 +1015,12 @@ bool fix_fields_part_func(THD *thd, Item
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.
*/
-
- save_use_only_table_context= thd->lex->use_only_table_context;
- thd->lex->use_only_table_context= TRUE;
- thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
-
error= func_expr->fix_fields(thd, (Item**)&func_expr);
- thd->lex->use_only_table_context= save_use_only_table_context;
-
- context->table_list= save_table_list;
- context->first_name_resolution_table= save_first_table;
- context->last_name_resolution_table= save_last_table;
if (unlikely(error))
{
DBUG_PRINT("info", ("Field in partition function not part of table"));
@@ -994,7 +1028,6 @@ bool fix_fields_part_func(THD *thd, Item
clear_field_flag(table);
goto end;
}
- thd->where= save_where;
if (unlikely(func_expr->const_item()))
{
my_error(ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
@@ -1009,8 +1042,7 @@ bool fix_fields_part_func(THD *thd, Item
if (!is_sub_part)
part_info->fixed= TRUE;
end:
- table->get_fields_in_item_tree= FALSE;
- table->map= 0; //Restore old value
+ end_lex_with_single_table(thd, table, old_lex);
DBUG_RETURN(result);
}
@@ -3809,16 +3841,11 @@ bool mysql_unpack_partition(THD *thd,
Parser_state parser_state(thd, part_buf, part_info_len);
- lex_start(thd);
- *work_part_info_used= false;
- /*
- We need to use the current SELECT_LEX since I need to keep the
- Name_resolution_context object which is referenced from the
- Item_field objects.
- This is not a nice solution since if the parser uses current_select
- for anything else it will corrupt the current LEX object.
- */
- thd->lex->current_select= old_lex->current_select;
+ if (init_lex_with_single_table(thd, table))
+ {
+ mem_alloc_error(sizeof(Table_ident));
+ goto end;
+ }
/*
All Items created is put into a free list on the THD object. This list
is used to free all Item objects after completing a query. We don't
@@ -3828,6 +3855,7 @@ bool mysql_unpack_partition(THD *thd,
Thus we move away the current list temporarily and start a new list that
we then save in the partition info structure.
*/
+ *work_part_info_used= false;
lex.part_info= new partition_info();/* Indicates MYSQLparse from this place */
if (!lex.part_info)
{
@@ -3941,8 +3969,7 @@ bool mysql_unpack_partition(THD *thd,
result= FALSE;
end:
- lex_end(thd->lex);
- thd->lex= old_lex;
+ end_lex_with_single_table(thd, table, old_lex);
thd->variables.character_set_client= old_character_set_client;
DBUG_RETURN(result);
}