Skip to content
/ server Public

Commit dfd28e5

Browse files
committed
MDEV-29114 Pruning depends on current timestamp for partition by SYSTEM_TIME
Wrong "fastpath" boundary conditions. The right boundary is open, the left boundary is closed. The condition range_value[loc_hist_id - 1] as left boundary must be checked with <= operator. The same with the right boundary range_value[loc_hist_id] as the correct way is to check it with > operator, the right boundary check was rewritten for clear understanding: ts < range_value[loc_hist_id] The below code confirms closed endpoint type for left boundary: if (range_value[loc_hist_id] <= ts) min_hist_id= loc_hist_id + 1; Also the endpoint type (closed for left, open for right) is confirmed by vers_set_hist_part() for DML: else if (vers_info->interval.is_set() && vers_info->hist_part->range_value <= thd->query_start()) and here (right boundary, rewritten for clarity): if (thd->query_start() < next->range_value) { error= false; break; }
1 parent 3c8a5ea commit dfd28e5

File tree

4 files changed

+115
-3
lines changed

4 files changed

+115
-3
lines changed

mysql-test/suite/versioning/r/partition.result

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3524,6 +3524,69 @@ alter table `t1` partition by system_time interval 7 year ;
35243524
ERROR 22003: TIMESTAMP value is out of range in 'INTERVAL'
35253525
drop table t1;
35263526
#
3527+
# MDEV-29114 ALTER puts row into different partition for system_time
3528+
# interval partitioning
3529+
#
3530+
# CREATE case
3531+
set timestamp= unix_timestamp('2000-01-01 00:00:00');
3532+
create or replace table t1 (x int) with system versioning
3533+
partition by system_time interval 1 hour (
3534+
partition p0 history, partition p1 history, partition pn current);
3535+
set timestamp= unix_timestamp('2000-01-01 00:00:00');
3536+
insert t1 values (0);
3537+
set timestamp= unix_timestamp('2000-01-01 00:10:00');
3538+
update t1 set x= 1;
3539+
set timestamp= unix_timestamp('2000-01-01 01:00:00');
3540+
update t1 set x= 2;
3541+
set timestamp= unix_timestamp('2000-01-01 01:30:00');
3542+
update t1 set x= 3;
3543+
# CREATE result: row 1 got into p1
3544+
select *, row_start, row_end from t1 partition (p0);
3545+
x row_start row_end
3546+
0 2000-01-01 00:00:00.000000 2000-01-01 00:10:00.000000
3547+
select *, row_start, row_end from t1 partition (p1);
3548+
x row_start row_end
3549+
1 2000-01-01 00:10:00.000000 2000-01-01 01:00:00.000000
3550+
2 2000-01-01 01:00:00.000000 2000-01-01 01:30:00.000000
3551+
flush tables;
3552+
# For CREATE pruning is affected by current timestamp, but SELECT works
3553+
# in any case since row 1 got into p1
3554+
set timestamp= unix_timestamp('2000-01-01 00:00:00');
3555+
explain partitions select * from t1 for system_time as of '2000-01-01 00:59:59';
3556+
id select_type table partitions type possible_keys key key_len ref rows Extra
3557+
1 SIMPLE t1 p0,p1,pn ALL NULL NULL NULL NULL 4 Using where
3558+
select * from t1 for system_time as of '2000-01-01 00:59:59';
3559+
x
3560+
1
3561+
set timestamp= unix_timestamp('2020-01-01 00:00:00');
3562+
explain partitions select * from t1 for system_time as of '2000-01-01 00:59:59';
3563+
id select_type table partitions type possible_keys key key_len ref rows Extra
3564+
1 SIMPLE t1 p0,p1,pn ALL NULL NULL NULL NULL 4 Using where
3565+
select * from t1 for system_time as of '2000-01-01 00:59:59';
3566+
x
3567+
1
3568+
# ALTER case
3569+
set timestamp= unix_timestamp('2000-01-01 00:00:00');
3570+
alter table t1
3571+
partition by system_time interval 1 hour (
3572+
partition p0 history, partition p1 history, partition pn current);
3573+
# ALTER result: row 1 got into p1
3574+
Select *, row_start, row_end from t1 partition (p0);
3575+
x row_start row_end
3576+
0 2000-01-01 00:00:00.000000 2000-01-01 00:10:00.000000
3577+
Select *, row_start, row_end from t1 partition (p1);
3578+
x row_start row_end
3579+
1 2000-01-01 00:10:00.000000 2000-01-01 01:00:00.000000
3580+
2 2000-01-01 01:00:00.000000 2000-01-01 01:30:00.000000
3581+
flush tables;
3582+
Explain partitions select * from t1 for system_time as of '2000-01-01 00:59:59';
3583+
id select_type table partitions type possible_keys key key_len ref rows Extra
3584+
1 SIMPLE t1 p0,p1,pn ALL NULL NULL NULL NULL 4 Using where
3585+
Select * from t1 for system_time as of '2000-01-01 00:59:59';
3586+
x
3587+
1
3588+
drop table t1;
3589+
#
35273590
# End of 10.11 tests
35283591
#
35293592
set global innodb_stats_persistent= @save_persistent;

mysql-test/suite/versioning/t/partition.test

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2768,6 +2768,52 @@ partition by system_time interval 1 month (
27682768
alter table `t1` partition by system_time interval 7 year ;
27692769
drop table t1;
27702770

2771+
--echo #
2772+
--echo # MDEV-29114 ALTER puts row into different partition for system_time
2773+
--echo # interval partitioning
2774+
--echo #
2775+
--echo # CREATE case
2776+
set timestamp= unix_timestamp('2000-01-01 00:00:00');
2777+
create or replace table t1 (x int) with system versioning
2778+
partition by system_time interval 1 hour (
2779+
partition p0 history, partition p1 history, partition pn current);
2780+
set timestamp= unix_timestamp('2000-01-01 00:00:00');
2781+
insert t1 values (0);
2782+
set timestamp= unix_timestamp('2000-01-01 00:10:00');
2783+
update t1 set x= 1;
2784+
set timestamp= unix_timestamp('2000-01-01 01:00:00');
2785+
update t1 set x= 2;
2786+
set timestamp= unix_timestamp('2000-01-01 01:30:00');
2787+
update t1 set x= 3;
2788+
2789+
--echo # CREATE result: row 1 got into p1
2790+
select *, row_start, row_end from t1 partition (p0);
2791+
select *, row_start, row_end from t1 partition (p1);
2792+
flush tables;
2793+
--echo # For CREATE pruning is affected by current timestamp, but SELECT works
2794+
--echo # in any case since row 1 got into p1
2795+
set timestamp= unix_timestamp('2000-01-01 00:00:00');
2796+
explain partitions select * from t1 for system_time as of '2000-01-01 00:59:59';
2797+
select * from t1 for system_time as of '2000-01-01 00:59:59';
2798+
set timestamp= unix_timestamp('2020-01-01 00:00:00');
2799+
explain partitions select * from t1 for system_time as of '2000-01-01 00:59:59';
2800+
select * from t1 for system_time as of '2000-01-01 00:59:59';
2801+
2802+
--echo # ALTER case
2803+
set timestamp= unix_timestamp('2000-01-01 00:00:00');
2804+
alter table t1
2805+
partition by system_time interval 1 hour (
2806+
partition p0 history, partition p1 history, partition pn current);
2807+
2808+
--echo # ALTER result: row 1 got into p1
2809+
Select *, row_start, row_end from t1 partition (p0);
2810+
Select *, row_start, row_end from t1 partition (p1);
2811+
flush tables;
2812+
Explain partitions select * from t1 for system_time as of '2000-01-01 00:59:59';
2813+
Select * from t1 for system_time as of '2000-01-01 00:59:59';
2814+
2815+
drop table t1;
2816+
27712817
--echo #
27722818
--echo # End of 10.11 tests
27732819
--echo #

sql/partition_info.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,7 @@ bool partition_info::vers_set_hist_part(THD *thd, uint *create_count)
831831
return 0;
832832
}
833833
else if (vers_info->interval.is_set() &&
834+
/* Left boundary is closed */
834835
vers_info->hist_part->range_value <= thd->query_start())
835836
{
836837
partition_element *next= NULL;
@@ -842,7 +843,8 @@ bool partition_info::vers_set_hist_part(THD *thd, uint *create_count)
842843
while ((next= it++) != vers_info->now_part)
843844
{
844845
vers_info->hist_part= next;
845-
if (next->range_value > thd->query_start())
846+
/* Right boundary is open */
847+
if (thd->query_start() < next->range_value)
846848
{
847849
error= false;
848850
break;

sql/sql_partition.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3511,13 +3511,14 @@ int vers_get_partition_id(partition_info *part_info, uint32 *part_id,
35113511
goto done; // fastpath
35123512

35133513
ts= row_end->get_timestamp(&unused);
3514-
if ((loc_hist_id == 0 || range_value[loc_hist_id - 1] < ts) &&
3515-
(loc_hist_id == max_hist_id || range_value[loc_hist_id] >= ts))
3514+
if ((loc_hist_id == 0 || range_value[loc_hist_id - 1] <= ts) &&
3515+
(loc_hist_id == max_hist_id || ts < range_value[loc_hist_id]))
35163516
goto done; // fastpath
35173517

35183518
while (max_hist_id > min_hist_id)
35193519
{
35203520
loc_hist_id= (max_hist_id + min_hist_id) / 2;
3521+
/* Left boundary is closed */
35213522
if (range_value[loc_hist_id] <= ts)
35223523
min_hist_id= loc_hist_id + 1;
35233524
else

0 commit comments

Comments
 (0)