1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +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

@ -466,7 +466,7 @@ partitions 2
#
# Partition by range, constant partition function not allowed
#
--error ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE t1 (
a int not null,
b int not null,
@ -681,7 +681,7 @@ partition by list (a);
#
# Partition by list, constant partition function not allowed
#
--error ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE t1 (
a int not null,
b int not null,
@ -840,4 +840,364 @@ partition by range (a + (select count(*) from t1))
create table t1 (a char(10))
partition by hash (extractvalue(a,'a'));
--echo #
--echo # Bug #42849: innodb crash with varying time_zone on partitioned
--echo # timestamp primary key
--echo #
# A correctly partitioned table to test that trying to repartition it using
# timezone-dependent expression will throw an error.
CREATE TABLE old (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (UNIX_TIMESTAMP(a)) (
PARTITION p VALUES LESS THAN (1219089600),
PARTITION pmax VALUES LESS THAN MAXVALUE);
# Check that allowed arithmetic/math functions involving TIMESTAMP values result
# in ER_PARTITION_FUNC_NOT_ALLOWED_ERROR when used as a partitioning function
--error ER_PARTITION_FUNC_NOT_ALLOWED_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (a) (
PARTITION p VALUES LESS THAN (20080819),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_PARTITION_FUNC_NOT_ALLOWED_ERROR
ALTER TABLE old
PARTITION BY RANGE (a) (
PARTITION p VALUES LESS THAN (20080819),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (a+0) (
PARTITION p VALUES LESS THAN (20080819),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (a+0) (
PARTITION p VALUES LESS THAN (20080819),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (a % 2) (
PARTITION p VALUES LESS THAN (20080819),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (a % 2) (
PARTITION p VALUES LESS THAN (20080819),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (ABS(a)) (
PARTITION p VALUES LESS THAN (20080819),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (ABS(a)) (
PARTITION p VALUES LESS THAN (20080819),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (CEILING(a)) (
PARTITION p VALUES LESS THAN (20080819),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (CEILING(a)) (
PARTITION p VALUES LESS THAN (20080819),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (FLOOR(a)) (
PARTITION p VALUES LESS THAN (20080819),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (FLOOR(a)) (
PARTITION p VALUES LESS THAN (20080819),
PARTITION pmax VALUES LESS THAN MAXVALUE);
# Check that allowed date/time functions involving TIMESTAMP values result
# in ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR when used as a partitioning function
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (TO_DAYS(a)) (
PARTITION p VALUES LESS THAN (733638),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (TO_DAYS(a)) (
PARTITION p VALUES LESS THAN (733638),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (DAYOFYEAR(a)) (
PARTITION p VALUES LESS THAN (231),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (DAYOFYEAR(a)) (
PARTITION p VALUES LESS THAN (231),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (DAYOFMONTH(a)) (
PARTITION p VALUES LESS THAN (19),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (DAYOFMONTH(a)) (
PARTITION p VALUES LESS THAN (19),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (DAYOFWEEK(a)) (
PARTITION p VALUES LESS THAN (3),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (DAYOFWEEK(a)) (
PARTITION p VALUES LESS THAN (3),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (MONTH(a)) (
PARTITION p VALUES LESS THAN (8),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (MONTH(a)) (
PARTITION p VALUES LESS THAN (8),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (HOUR(a)) (
PARTITION p VALUES LESS THAN (17),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (HOUR(a)) (
PARTITION p VALUES LESS THAN (17),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (MINUTE(a)) (
PARTITION p VALUES LESS THAN (55),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (MINUTE(a)) (
PARTITION p VALUES LESS THAN (55),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (QUARTER(a)) (
PARTITION p VALUES LESS THAN (3),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (QUARTER(a)) (
PARTITION p VALUES LESS THAN (3),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (SECOND(a)) (
PARTITION p VALUES LESS THAN (7),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (SECOND(a)) (
PARTITION p VALUES LESS THAN (7),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (YEARWEEK(a)) (
PARTITION p VALUES LESS THAN (200833),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (YEARWEEK(a)) (
PARTITION p VALUES LESS THAN (200833),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (YEAR(a)) (
PARTITION p VALUES LESS THAN (2008),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (YEAR(a)) (
PARTITION p VALUES LESS THAN (2008),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (WEEKDAY(a)) (
PARTITION p VALUES LESS THAN (3),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (WEEKDAY(a)) (
PARTITION p VALUES LESS THAN (3),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (TIME_TO_SEC(a)) (
PARTITION p VALUES LESS THAN (64507),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (TIME_TO_SEC(a)) (
PARTITION p VALUES LESS THAN (64507),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (EXTRACT(DAY FROM a)) (
PARTITION p VALUES LESS THAN (18),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (EXTRACT(DAY FROM a)) (
PARTITION p VALUES LESS THAN (18),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL, b TIMESTAMP NOT NULL, PRIMARY KEY(a,b))
PARTITION BY RANGE (DATEDIFF(a, a)) (
PARTITION p VALUES LESS THAN (18),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (DATEDIFF(a, a)) (
PARTITION p VALUES LESS THAN (18),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (YEAR(a + 0)) (
PARTITION p VALUES LESS THAN (2008),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (YEAR(a + 0)) (
PARTITION p VALUES LESS THAN (2008),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (TO_DAYS(a + '2008-01-01')) (
PARTITION p VALUES LESS THAN (733638),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (TO_DAYS(a + '2008-01-01')) (
PARTITION p VALUES LESS THAN (733638),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY)
PARTITION BY RANGE (YEAR(a + '2008-01-01')) (
PARTITION p VALUES LESS THAN (2008),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (YEAR(a + '2008-01-01')) (
PARTITION p VALUES LESS THAN (2008),
PARTITION pmax VALUES LESS THAN MAXVALUE);
ALTER TABLE old ADD COLUMN b DATE;
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP, b DATE)
PARTITION BY RANGE (YEAR(a + b)) (
PARTITION p VALUES LESS THAN (2008),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (YEAR(a + b)) (
PARTITION p VALUES LESS THAN (2008),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP, b DATE)
PARTITION BY RANGE (TO_DAYS(a + b)) (
PARTITION p VALUES LESS THAN (733638),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (TO_DAYS(a + b)) (
PARTITION p VALUES LESS THAN (733638),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP, b date)
PARTITION BY RANGE (UNIX_TIMESTAMP(a + b)) (
PARTITION p VALUES LESS THAN (1219089600),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (UNIX_TIMESTAMP(a + b)) (
PARTITION p VALUES LESS THAN (1219089600),
PARTITION pmax VALUES LESS THAN MAXVALUE);
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
CREATE TABLE new (a TIMESTAMP, b TIMESTAMP)
PARTITION BY RANGE (UNIX_TIMESTAMP(a + b)) (
PARTITION p VALUES LESS THAN (1219089600),
PARTITION pmax VALUES LESS THAN MAXVALUE);
ALTER TABLE old MODIFY b TIMESTAMP;
--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
ALTER TABLE old
PARTITION BY RANGE (UNIX_TIMESTAMP(a + b)) (
PARTITION p VALUES LESS THAN (1219089600),
PARTITION pmax VALUES LESS THAN MAXVALUE);
DROP TABLE old;
--echo End of 5.1 tests