mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Bug#32115: Bad use of Name_resolution_context from current LEX in partitioning
port from mysql-next (5.4?) to mysql-next-mr-bugfixes (5.5/5.6?) 3477 Mikael Ronstrom 2009-07-29 Bug#32115, made use of local lex object to avoid side effects of opening partitioned tables 3478 Mikael Ronstrom 2009-07-29 Bug#32115, added an extra test in debug builds to ensure no dangling pointers to the old lex object is still around 3479 Mikael Ronstrom 2009-07-29 Bug#32115, Removed an assert that was no longer needed 3480 Mikael Ronstrom 2009-08-05 Bug#32115, fixed review comments 3481 Mikael Ronstrom 2009-08-07 Bug#32115, remove now obsolete lex_start calls
This commit is contained in:
@ -932,6 +932,85 @@ int check_signed_flag(partition_info *part_info)
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize lex object for use in fix_fields and parsing.
|
||||
|
||||
SYNOPSIS
|
||||
init_lex_with_single_table()
|
||||
@param thd The thread object
|
||||
@param table The table object
|
||||
@return Operation status
|
||||
@retval TRUE An error occurred, memory allocation error
|
||||
@retval 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, LEX *lex)
|
||||
{
|
||||
TABLE_LIST *table_list;
|
||||
Table_ident *table_ident;
|
||||
SELECT_LEX *select_lex= &lex->select_lex;
|
||||
Name_resolution_context *context= &select_lex->context;
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
thd->lex= lex;
|
||||
lex_start(thd);
|
||||
context->init();
|
||||
if ((!(table_ident= new Table_ident(thd,
|
||||
table->s->table_name,
|
||||
table->s->db, TRUE))) ||
|
||||
(!(table_list= select_lex->add_table_to_list(thd,
|
||||
table_ident,
|
||||
NULL,
|
||||
0))))
|
||||
return TRUE;
|
||||
context->resolve_in_table_list_only(table_list);
|
||||
lex->use_only_table_context= TRUE;
|
||||
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()
|
||||
@param thd The thread object
|
||||
@param table The table object
|
||||
@param 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 void
|
||||
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
|
||||
@ -972,55 +1051,18 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
|
||||
bool is_sub_part)
|
||||
{
|
||||
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");
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
if (init_lex_with_single_table(thd, table, &lex))
|
||||
goto end;
|
||||
|
||||
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";
|
||||
/*
|
||||
@ -1035,30 +1077,18 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
|
||||
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"));
|
||||
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));
|
||||
@ -1069,8 +1099,11 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
|
||||
goto end;
|
||||
result= set_up_field_array(table, is_sub_part);
|
||||
end:
|
||||
table->get_fields_in_item_tree= FALSE;
|
||||
table->map= 0; //Restore old value
|
||||
end_lex_with_single_table(thd, table, old_lex);
|
||||
#if !defined(DBUG_OFF)
|
||||
func_expr->walk(&Item::change_context_processor, 0,
|
||||
(uchar*) 0);
|
||||
#endif
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
@ -4109,26 +4142,13 @@ bool mysql_unpack_partition(THD *thd,
|
||||
LEX lex;
|
||||
DBUG_ENTER("mysql_unpack_partition");
|
||||
|
||||
thd->lex= &lex;
|
||||
thd->variables.character_set_client= system_charset_info;
|
||||
|
||||
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.
|
||||
Also, we need to make sure there even is a select -- if the statement
|
||||
was a "USE ...", current_select will be NULL, but we may still end up
|
||||
here if we try to log to a partitioned table. This is currently
|
||||
unsupported, but should still fail rather than crash!
|
||||
*/
|
||||
if (!(thd->lex->current_select= old_lex->current_select))
|
||||
if (init_lex_with_single_table(thd, table, &lex))
|
||||
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
|
||||
@ -4138,6 +4158,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)
|
||||
{
|
||||
@ -4251,8 +4272,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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user