1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-07 00:04:31 +03:00

Bug #42849: innodb crash with varying time_zone on partitioned

timestamp primary key 
 
Since TIMESTAMP values are adjusted by the current time zone  
settings in both numeric and string contexts, using any 
expressions involving TIMESTAMP values as a  
(sub)partitioning function leads to undeterministic behavior of  
partitioned tables. The effect may vary depending on a storage  
engine, it can be either incorrect data being retrieved or  
stored, or an assertion failure. The root cause of this is the  
fact that the calculated partition ID may differ from a  
previously calculated ID for the same data due to timezone  
adjustments of the partitioning expression value. 
 
Fixed by disabling any expressions involving TIMESTAMP values  
to be used in partitioning functions with the follwing two 
exceptions: 
 
1. Creating or altering into a partitioned table that violates 
the above rule is not allowed, but opening existing such tables 
results in a warning rather than an error so that such tables 
could be fixed. 
 
2. UNIX_TIMESTAMP() is the only way to get a 
timezone-independent value from a TIMESTAMP column, because it 
returns the internal representation (a time_t value) of a 
TIMESTAMP argument verbatim. So UNIX_TIMESTAMP(timestamp_column)
is allowed and should be used to fix existing tables if one 
wants to use TIMESTAMP columns with partitioning.
This commit is contained in:
Alexey Kopytov
2009-12-13 23:29:50 +03:00
parent 13f7a81b37
commit a8cfe3d4f7
11 changed files with 743 additions and 25 deletions

View File

@@ -869,6 +869,8 @@ int check_signed_flag(partition_info *part_info)
part_info Reference to partitioning data structure
is_sub_part Is the table subpartitioned as well
is_field_to_be_setup Flag if we are to set-up field arrays
is_create_table_ind Indicator of whether openfrm was called as part of
CREATE or ALTER TABLE
RETURN VALUE
TRUE An error occurred, something was wrong with the
@@ -891,8 +893,9 @@ int check_signed_flag(partition_info *part_info)
on the field object.
*/
bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
bool is_sub_part, bool is_field_to_be_setup)
static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
bool is_sub_part, bool is_field_to_be_setup,
bool is_create_table_ind)
{
partition_info *part_info= table->part_info;
uint dir_length, home_dir_length;
@@ -982,10 +985,31 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
thd->where= save_where;
if (unlikely(func_expr->const_item()))
{
my_error(ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
clear_field_flag(table);
goto end;
}
/*
We don't allow creating partitions with timezone-dependent expressions as
a (sub)partitioning function, but we want to allow such expressions when
opening existing tables for easier maintenance. This exception should be
deprecated at some point in future so that we always throw an error.
*/
if (func_expr->walk(&Item::is_timezone_dependent_processor,
0, NULL))
{
if (is_create_table_ind)
{
my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
goto end;
}
else
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR,
ER(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR));
}
if ((!is_sub_part) && (error= check_signed_flag(part_info)))
goto end;
result= FALSE;
@@ -1593,7 +1617,8 @@ bool fix_partition_func(THD *thd, TABLE *table,
else
{
if (unlikely(fix_fields_part_func(thd, part_info->subpart_expr,
table, TRUE, TRUE)))
table, TRUE, TRUE,
is_create_table_ind)))
goto end;
if (unlikely(part_info->subpart_expr->result_type() != INT_RESULT))
{
@@ -1621,7 +1646,8 @@ bool fix_partition_func(THD *thd, TABLE *table,
else
{
if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
table, FALSE, TRUE)))
table, FALSE, TRUE,
is_create_table_ind)))
goto end;
if (unlikely(part_info->part_expr->result_type() != INT_RESULT))
{
@@ -1635,7 +1661,8 @@ bool fix_partition_func(THD *thd, TABLE *table,
{
const char *error_str;
if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
table, FALSE, TRUE)))
table, FALSE, TRUE,
is_create_table_ind)))
goto end;
if (part_info->part_type == RANGE_PARTITION)
{