Commit d8d8efc8 authored by Mattias Jonsson's avatar Mattias Jonsson

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
parent 176cabc1
......@@ -119,7 +119,6 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
thd->current_stmt= stmt;
thd->store_globals(); // Fix if more than one connect
lex_start(thd);
/*
We have to call free_old_query before we start to fill mysql->fields
for new query. In the case of embedded server we collect field data
......
......@@ -6952,7 +6952,6 @@ int ndb_create_table_from_engine(THD *thd, const char *db,
LEX *old_lex= thd->lex, newlex;
thd->lex= &newlex;
newlex.current_select= NULL;
lex_start(thd);
int res= ha_create_table_from_engine(thd, db, table_name);
thd->lex= old_lex;
return res;
......@@ -9272,7 +9271,6 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
thd->thread_stack= (char*)&thd; /* remember where our stack is */
if (thd->store_globals())
goto ndb_util_thread_fail;
lex_start(thd);
thd->init_for_queries();
thd->version=refresh_version;
thd->main_security_ctx.host_or_ip= "";
......
......@@ -3669,7 +3669,6 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
pthread_exit(0);
return NULL; // Avoid compiler warnings
}
lex_start(thd);
thd->init_for_queries();
thd->command= COM_DAEMON;
......
......@@ -2121,7 +2121,6 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
thd->cleanup();
DBUG_RETURN(-1);
}
lex_start(thd);
if (thd_type == SLAVE_THD_SQL)
thd_proc_info(thd, "Waiting for the next event in relay log");
......
......@@ -2308,12 +2308,6 @@ static void handle_delayed_insert_impl(THD *thd, Delayed_insert *di)
goto err;
}
/*
Open table requires an initialized lex in case the table is
partitioned. The .frm file contains a partial SQL string which is
parsed using a lex, that depends on initialized thd->lex.
*/
lex_start(thd);
thd->lex->sql_command= SQLCOM_INSERT; // For innodb::store_lock()
/*
Statement-based replication of INSERT DELAYED has problems with RAND()
......
......@@ -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.
*/
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;
if (init_lex_with_single_table(thd, table, &lex))
goto end;
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);
}
......
......@@ -1830,8 +1830,6 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
thd->restore_active_arena(&part_func_arena, &backup_arena);
goto partititon_err;
}
/* fix_partition_func needs thd->lex set up. TODO: fix! */
DBUG_ASSERT(thd->lex->is_lex_started);
outparam->part_info->is_auto_partitioned= share->auto_partitioned;
DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned));
/* we should perform the fix_partition_func in either local or
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment