diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index d25227a4ce7..3e5ac95c34f 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -1334,6 +1334,126 @@ t1 CREATE TABLE `t1` ( PARTITION `pn` CURRENT ENGINE = DEFAULT_ENGINE) drop tables t1; # +# MDEV-27328 Change of SYSTEM_TIME partitioning options is not possible without data copy +# +create or replace table t1 (f int) with system versioning +partition by hash(f); +alter table t1 partition by system_time; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f` int(11) DEFAULT NULL +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME +PARTITIONS 2 +create or replace table t1 (f int) with system versioning +partition by system_time; +alter table t1 partition by hash(f); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f` int(11) DEFAULT NULL +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY HASH (`f`) +create or replace table t1 (x int) with system versioning; +alter table t1 partition by system_time; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `x` int(11) DEFAULT NULL +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME +PARTITIONS 2 +create or replace table t1 (x int) with system versioning +partition by system_time limit 100 partitions 4; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `x` int(11) DEFAULT NULL +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME LIMIT 100 +PARTITIONS 4 +alter table t1 add partition partitions 2; +alter table t1 partition by system_time; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `x` int(11) DEFAULT NULL +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME +PARTITIONS 6 +alter table t1 partition by system_time limit 33; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `x` int(11) DEFAULT NULL +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME LIMIT 33 +PARTITIONS 6 +set timestamp= unix_timestamp('2000-01-01 00:00:00'); +insert t1 values (0); +set timestamp= unix_timestamp('2000-01-01 00:10:00'); +update t1 set x= x + 1; +set timestamp= unix_timestamp('2000-01-01 01:00:00'); +update t1 set x= x + 1; +set timestamp= unix_timestamp('2000-01-01 01:30:00'); +update t1 set x= x + 1; +set timestamp= unix_timestamp('2000-01-01 02:00:00'); +update t1 set x= x + 1; +alter table t1 partition by system_time interval 1 hour +starts '2000-01-01 00:00:00'; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `x` int(11) DEFAULT NULL +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' +PARTITIONS 6 +select * from t1 partition (p0); +x +0 +select * from t1 partition (p1); +x +1 +2 +select * from t1 partition (p2); +x +3 +select * from t1 partition (pn); +x +4 +set timestamp= default; +alter table t1 partition by system_time limit 1; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `x` int(11) DEFAULT NULL +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME LIMIT 1 +PARTITIONS 6 +update t1 set x= x + 1; +update t1 set x= x + 1; +select * from t1 partition (p0); +x +0 +select * from t1 partition (p1); +x +1 +2 +select * from t1 partition (p2); +x +3 +select * from t1 partition (p3); +x +4 +select * from t1 partition (p4); +x +5 +select * from t1 partition (pn); +x +6 +drop table t1; +# # End of 10.5 tests # SET GLOBAL innodb_stats_persistent=@save_persistent; diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index d940f3e75e8..5e209bb7969 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -1157,6 +1157,76 @@ drop tables t1; --disable_prepare_warnings +--echo # +--echo # MDEV-27328 Change of SYSTEM_TIME partitioning options is not possible without data copy +--echo # +create or replace table t1 (f int) with system versioning +partition by hash(f); +alter table t1 partition by system_time; +--replace_result $default_engine DEFAULT_ENGINE +show create table t1; + +create or replace table t1 (f int) with system versioning +partition by system_time; +alter table t1 partition by hash(f); +--replace_result $default_engine DEFAULT_ENGINE +show create table t1; + +create or replace table t1 (x int) with system versioning; +alter table t1 partition by system_time; +--replace_result $default_engine DEFAULT_ENGINE +show create table t1; + +create or replace table t1 (x int) with system versioning +partition by system_time limit 100 partitions 4; +--replace_result $default_engine DEFAULT_ENGINE +show create table t1; +alter table t1 add partition partitions 2; +alter table t1 partition by system_time; +--replace_result $default_engine DEFAULT_ENGINE +show create table t1; +alter table t1 partition by system_time limit 33; +--replace_result $default_engine DEFAULT_ENGINE +show create table t1; +set timestamp= unix_timestamp('2000-01-01 00:00:00'); +insert t1 values (0); +set timestamp= unix_timestamp('2000-01-01 00:10:00'); +update t1 set x= x + 1; +set timestamp= unix_timestamp('2000-01-01 01:00:00'); +update t1 set x= x + 1; +set timestamp= unix_timestamp('2000-01-01 01:30:00'); +update t1 set x= x + 1; +set timestamp= unix_timestamp('2000-01-01 02:00:00'); +update t1 set x= x + 1; + +# When we switch to INTERVAL we must reorganize partitions. +# Otherwise pruning won't work correctly. +alter table t1 partition by system_time interval 1 hour +starts '2000-01-01 00:00:00'; +--replace_result $default_engine DEFAULT_ENGINE +show create table t1; +select * from t1 partition (p0); +select * from t1 partition (p1); +select * from t1 partition (p2); +select * from t1 partition (pn); +set timestamp= default; + +# When we switch to LIMIT we probably don't want to reorganize old partitions. +# Note: reorganize for LIMIT is broken, it pushes all history into first partition. +# TODO: MDEV-27337 +alter table t1 partition by system_time limit 1; +--replace_result $default_engine DEFAULT_ENGINE +show create table t1; +update t1 set x= x + 1; +update t1 set x= x + 1; +select * from t1 partition (p0); +select * from t1 partition (p1); +select * from t1 partition (p2); +select * from t1 partition (p3); +select * from t1 partition (p4); +select * from t1 partition (pn); + +drop table t1; --echo # --echo # End of 10.5 tests --echo # diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 548a9ed6f67..4342b403acd 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -419,8 +419,6 @@ bool partition_info::set_up_default_partitions(THD *thd, handler *file, const char *error_string; if (part_type == RANGE_PARTITION) error_string= "RANGE"; - else if (part_type == VERSIONING_PARTITION) - error_string= "SYSTEM_TIME"; else error_string= "LIST"; my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_string); diff --git a/sql/partition_info.h b/sql/partition_info.h index f2b54d14a49..525eedd310f 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -46,13 +46,22 @@ struct Vers_part_info : public Sql_alloc { interval.type= INTERVAL_LAST; } - Vers_part_info(Vers_part_info &src) : + Vers_part_info(const Vers_part_info &src) : interval(src.interval), limit(src.limit), now_part(NULL), hist_part(NULL) { } + Vers_part_info& operator= (const Vers_part_info &src) + { + interval= src.interval; + limit= src.limit; + auto_hist= src.auto_hist; + now_part= src.now_part; + hist_part= src.hist_part; + return *this; + } bool initialized() { if (now_part) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 9a4a0d0be28..ff4fad6906a 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5058,6 +5058,10 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), "LIST", "IN"); } + /* + Adding history partitions to non-history partitioning or + non-history parittions to history partitioning is prohibited. + */ else if (thd->work_part_info->part_type == VERSIONING_PARTITION || tab_part_info->part_type == VERSIONING_PARTITION) { @@ -5340,6 +5344,7 @@ that are reorganised. { if (el->type == partition_element::CURRENT) { + /* now_part is always last partition, we add it to the end of partitions list. */ it.remove(); now_part= el; } @@ -5967,11 +5972,35 @@ the generated partition syntax in a correct manner. { partition_info *part_info= thd->work_part_info; bool is_native_partitioned= FALSE; + if (tab_part_info && tab_part_info->part_type == VERSIONING_PARTITION && + tab_part_info != part_info && part_info->part_type == VERSIONING_PARTITION && + part_info->num_parts == 0) + { + if (part_info->vers_info->interval.is_set() && + /* TODO: equivalent intervals like 1 hour and 60 mins should be considered equal */ + memcmp(&part_info->vers_info->interval, + &tab_part_info->vers_info->interval, + sizeof(Vers_part_info::interval))) + { + /* If interval is changed we can not do fast alter */ + tab_part_info= tab_part_info->get_clone(thd); + } + else + { + /* NOTE: fast_alter_partition_table() works on existing TABLE data. */ + *fast_alter_table= true; + table->mark_table_for_reopen(); + } + *tab_part_info->vers_info= *part_info->vers_info; + thd->work_part_info= part_info= tab_part_info; + *partition_changed= true; + } + /* Need to cater for engine types that can handle partition without using the partition handler. */ - if (part_info != tab_part_info) + else if (part_info != tab_part_info) { if (part_info->fix_parser_data(thd)) {