|
|
|
@ -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);
|
|
|
|
|
}
|
|
|
|
|