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:
@ -119,7 +119,6 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
|
|||||||
thd->current_stmt= stmt;
|
thd->current_stmt= stmt;
|
||||||
|
|
||||||
thd->store_globals(); // Fix if more than one connect
|
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
|
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
|
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;
|
LEX *old_lex= thd->lex, newlex;
|
||||||
thd->lex= &newlex;
|
thd->lex= &newlex;
|
||||||
newlex.current_select= NULL;
|
newlex.current_select= NULL;
|
||||||
lex_start(thd);
|
|
||||||
int res= ha_create_table_from_engine(thd, db, table_name);
|
int res= ha_create_table_from_engine(thd, db, table_name);
|
||||||
thd->lex= old_lex;
|
thd->lex= old_lex;
|
||||||
return res;
|
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 */
|
thd->thread_stack= (char*)&thd; /* remember where our stack is */
|
||||||
if (thd->store_globals())
|
if (thd->store_globals())
|
||||||
goto ndb_util_thread_fail;
|
goto ndb_util_thread_fail;
|
||||||
lex_start(thd);
|
|
||||||
thd->init_for_queries();
|
thd->init_for_queries();
|
||||||
thd->version=refresh_version;
|
thd->version=refresh_version;
|
||||||
thd->main_security_ctx.host_or_ip= "";
|
thd->main_security_ctx.host_or_ip= "";
|
||||||
|
@ -3669,7 +3669,6 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
|
|||||||
pthread_exit(0);
|
pthread_exit(0);
|
||||||
return NULL; // Avoid compiler warnings
|
return NULL; // Avoid compiler warnings
|
||||||
}
|
}
|
||||||
lex_start(thd);
|
|
||||||
|
|
||||||
thd->init_for_queries();
|
thd->init_for_queries();
|
||||||
thd->command= COM_DAEMON;
|
thd->command= COM_DAEMON;
|
||||||
|
@ -2121,7 +2121,6 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
|
|||||||
thd->cleanup();
|
thd->cleanup();
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
}
|
}
|
||||||
lex_start(thd);
|
|
||||||
|
|
||||||
if (thd_type == SLAVE_THD_SQL)
|
if (thd_type == SLAVE_THD_SQL)
|
||||||
thd_proc_info(thd, "Waiting for the next event in relay log");
|
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;
|
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()
|
thd->lex->sql_command= SQLCOM_INSERT; // For innodb::store_lock()
|
||||||
/*
|
/*
|
||||||
Statement-based replication of INSERT DELAYED has problems with RAND()
|
Statement-based replication of INSERT DELAYED has problems with RAND()
|
||||||
|
@ -932,6 +932,85 @@ int check_signed_flag(partition_info *part_info)
|
|||||||
return error;
|
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
|
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)
|
bool is_sub_part)
|
||||||
{
|
{
|
||||||
partition_info *part_info= table->part_info;
|
partition_info *part_info= table->part_info;
|
||||||
uint dir_length, home_dir_length;
|
|
||||||
bool result= TRUE;
|
bool result= TRUE;
|
||||||
TABLE_LIST tables;
|
|
||||||
TABLE_LIST *save_table_list, *save_first_table, *save_last_table;
|
|
||||||
int error;
|
int error;
|
||||||
Name_resolution_context *context;
|
|
||||||
const char *save_where;
|
const char *save_where;
|
||||||
char* db_name;
|
LEX *old_lex= thd->lex;
|
||||||
char db_name_string[FN_REFLEN];
|
LEX lex;
|
||||||
bool save_use_only_table_context;
|
|
||||||
DBUG_ENTER("fix_fields_part_func");
|
DBUG_ENTER("fix_fields_part_func");
|
||||||
|
|
||||||
/*
|
if (init_lex_with_single_table(thd, table, &lex))
|
||||||
Set-up the TABLE_LIST object to be a list with a single table
|
goto end;
|
||||||
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));
|
func_expr->walk(&Item::change_context_processor, 0,
|
||||||
tables.alias= tables.table_name= (char*) table->s->table_name.str;
|
(uchar*) &lex.select_lex.context);
|
||||||
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);
|
|
||||||
save_where= thd->where;
|
save_where= thd->where;
|
||||||
thd->where= "partition function";
|
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
|
that does this during val_int must be disallowed as partition
|
||||||
function.
|
function.
|
||||||
SEE Bug #21658
|
SEE Bug #21658
|
||||||
*/
|
|
||||||
/*
|
|
||||||
This is a tricky call to prepare for since it can have a large number
|
This is a tricky call to prepare for since it can have a large number
|
||||||
of interesting side effects, both desirable and undesirable.
|
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);
|
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))
|
if (unlikely(error))
|
||||||
{
|
{
|
||||||
DBUG_PRINT("info", ("Field in partition function not part of table"));
|
DBUG_PRINT("info", ("Field in partition function not part of table"));
|
||||||
clear_field_flag(table);
|
clear_field_flag(table);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
thd->where= save_where;
|
|
||||||
if (unlikely(func_expr->const_item()))
|
if (unlikely(func_expr->const_item()))
|
||||||
{
|
{
|
||||||
my_error(ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
|
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;
|
goto end;
|
||||||
result= set_up_field_array(table, is_sub_part);
|
result= set_up_field_array(table, is_sub_part);
|
||||||
end:
|
end:
|
||||||
table->get_fields_in_item_tree= FALSE;
|
end_lex_with_single_table(thd, table, old_lex);
|
||||||
table->map= 0; //Restore old value
|
#if !defined(DBUG_OFF)
|
||||||
|
func_expr->walk(&Item::change_context_processor, 0,
|
||||||
|
(uchar*) 0);
|
||||||
|
#endif
|
||||||
DBUG_RETURN(result);
|
DBUG_RETURN(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4109,26 +4142,13 @@ bool mysql_unpack_partition(THD *thd,
|
|||||||
LEX lex;
|
LEX lex;
|
||||||
DBUG_ENTER("mysql_unpack_partition");
|
DBUG_ENTER("mysql_unpack_partition");
|
||||||
|
|
||||||
thd->lex= &lex;
|
|
||||||
thd->variables.character_set_client= system_charset_info;
|
thd->variables.character_set_client= system_charset_info;
|
||||||
|
|
||||||
Parser_state parser_state(thd, part_buf, part_info_len);
|
Parser_state parser_state(thd, part_buf, part_info_len);
|
||||||
|
|
||||||
lex_start(thd);
|
if (init_lex_with_single_table(thd, table, &lex))
|
||||||
*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))
|
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
All Items created is put into a free list on the THD object. This list
|
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
|
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
|
Thus we move away the current list temporarily and start a new list that
|
||||||
we then save in the partition info structure.
|
we then save in the partition info structure.
|
||||||
*/
|
*/
|
||||||
|
*work_part_info_used= FALSE;
|
||||||
lex.part_info= new partition_info();/* Indicates MYSQLparse from this place */
|
lex.part_info= new partition_info();/* Indicates MYSQLparse from this place */
|
||||||
if (!lex.part_info)
|
if (!lex.part_info)
|
||||||
{
|
{
|
||||||
@ -4251,8 +4272,7 @@ bool mysql_unpack_partition(THD *thd,
|
|||||||
|
|
||||||
result= FALSE;
|
result= FALSE;
|
||||||
end:
|
end:
|
||||||
lex_end(thd->lex);
|
end_lex_with_single_table(thd, table, old_lex);
|
||||||
thd->lex= old_lex;
|
|
||||||
thd->variables.character_set_client= old_character_set_client;
|
thd->variables.character_set_client= old_character_set_client;
|
||||||
DBUG_RETURN(result);
|
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);
|
thd->restore_active_arena(&part_func_arena, &backup_arena);
|
||||||
goto partititon_err;
|
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;
|
outparam->part_info->is_auto_partitioned= share->auto_partitioned;
|
||||||
DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned));
|
DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned));
|
||||||
/* we should perform the fix_partition_func in either local or
|
/* we should perform the fix_partition_func in either local or
|
||||||
|
Reference in New Issue
Block a user