From 391353b4aad5aeb8d09246f391140c8290135b4f Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Mon, 25 May 2026 14:16:21 +1000 Subject: [PATCH 1/2] MDEV-15621 [refactor] Partitioning cleanup change p_column_list_val::fixed to a bool remove redundant end label in partition_info::fix_column_value_functions --- sql/partition_element.h | 2 +- sql/partition_info.cc | 19 +++++++------------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/sql/partition_element.h b/sql/partition_element.h index 795a7a1d56fb2..205df4344b7bf 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -69,7 +69,7 @@ typedef struct p_column_list_val uint partition_id; bool max_value; // MAXVALUE for RANGE type or DEFAULT value for LIST type bool null_value; - char fixed; + bool fixed; } part_column_list_val; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 7666997dc5eca..a6320dc489dd9 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -2166,7 +2166,7 @@ int partition_info::fix_partition_values(THD *thd, } part_elem->range_value= val->value; } - col_val->fixed= 2; + col_val->fixed= TRUE; DBUG_RETURN(FALSE); } @@ -2219,12 +2219,11 @@ bool partition_info::fix_column_value_functions(THD *thd, uint part_id) { uint n_columns= part_field_list.elements; - bool result= FALSE; uint i; part_column_list_val *col_val= val->col_val_array; DBUG_ENTER("partition_info::fix_column_value_functions"); - if (col_val->fixed > 1) + if (col_val->fixed) { DBUG_RETURN(FALSE); } @@ -2247,8 +2246,7 @@ bool partition_info::fix_column_value_functions(THD *thd, if (!(column_item= get_column_item(column_item, field))) { - result= TRUE; - goto end; + DBUG_RETURN(TRUE); } Sql_mode_instant_set sms(thd, 0); save_got_warning= thd->got_warning; @@ -2257,22 +2255,19 @@ bool partition_info::fix_column_value_functions(THD *thd, thd->got_warning) { my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0)); - result= TRUE; - goto end; + DBUG_RETURN(TRUE); } thd->got_warning= save_got_warning; if (!(val_ptr= (uchar*) thd->memdup(field->ptr, len))) { - result= TRUE; - goto end; + DBUG_RETURN(TRUE); } col_val->column_value= val_ptr; } } - col_val->fixed= 2; + col_val->fixed= TRUE; } -end: - DBUG_RETURN(result); + DBUG_RETURN(FALSE); } From 0ee340c9747ec692af53fde2e45e45f0e8fb511b Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Mon, 25 May 2026 16:14:47 +1000 Subject: [PATCH 2/2] MDEV-15621 Auto add RANGE COLUMNS partitions by interval Allow auto partitioning by interval in PARTITION BY RANGE COLUMNS PARTITION BY RANGE COLUMNS (col_name) INTERVAL interval [AUTO] ( PARTITION partition_name VALUES LESS THAN (value) [, PARTITION partition_name VALUES LESS THAN (value) ... ] ) where - col_name is the name of one column of type DATE or DATETIME - at least one partition is supplied - INTERVAL interval is a time interval When performing DML on such a table, it will first add partitions by the specified interval until the partition covers the current time. Partition addition will not cause an implicit commit like DDL normally does. The partitions are named pN. Otherwise the table behaves exactly the same as a normal RANGE COLUMNS partitioned table. --- .../main/partition_range_interval.result | 1142 +++++++++++++++++ mysql-test/main/partition_range_interval.test | 412 ++++++ sql/partition_info.cc | 157 ++- sql/partition_info.h | 19 +- sql/share/errmsg-utf8.txt | 6 + sql/sql_base.cc | 116 +- sql/sql_base.h | 4 +- sql/sql_partition.cc | 130 +- sql/sql_yacc.yy | 34 +- sql/table.h | 2 + 10 files changed, 2008 insertions(+), 14 deletions(-) create mode 100644 mysql-test/main/partition_range_interval.result create mode 100644 mysql-test/main/partition_range_interval.test diff --git a/mysql-test/main/partition_range_interval.result b/mysql-test/main/partition_range_interval.result new file mode 100644 index 0000000000000..f3a4e8be222fe --- /dev/null +++ b/mysql-test/main/partition_range_interval.result @@ -0,0 +1,1142 @@ +# simple case showing partitions added in INSERT +set timestamp= unix_timestamp('2026-05-02 00:00:00'); +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p0 VALUES LESS THAN ('2026-04-20') +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-20') ENGINE = InnoDB) +insert into t1 values ('2026-05-01'); +select * from t1; +c +2026-05-01 00:00:00 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-20') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-21 00:00:00') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-04-22 00:00:00') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-04-23 00:00:00') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-04-24 00:00:00') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-04-25 00:00:00') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-04-26 00:00:00') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-04-27 00:00:00') ENGINE = InnoDB, + PARTITION `p8` VALUES LESS THAN ('2026-04-28 00:00:00') ENGINE = InnoDB, + PARTITION `p9` VALUES LESS THAN ('2026-04-29 00:00:00') ENGINE = InnoDB, + PARTITION `p10` VALUES LESS THAN ('2026-04-30 00:00:00') ENGINE = InnoDB, + PARTITION `p11` VALUES LESS THAN ('2026-05-01 00:00:00') ENGINE = InnoDB, + PARTITION `p12` VALUES LESS THAN ('2026-05-02 00:00:00') ENGINE = InnoDB, + PARTITION `p13` VALUES LESS THAN ('2026-05-03 00:00:00') ENGINE = InnoDB) +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +partition_name partition_method partition_expression partition_description table_rows +p0 RANGE COLUMNS `c` '2026-04-20' 0 +p1 RANGE COLUMNS `c` '2026-04-21 00:00:00' 0 +p2 RANGE COLUMNS `c` '2026-04-22 00:00:00' 0 +p3 RANGE COLUMNS `c` '2026-04-23 00:00:00' 0 +p4 RANGE COLUMNS `c` '2026-04-24 00:00:00' 0 +p5 RANGE COLUMNS `c` '2026-04-25 00:00:00' 0 +p6 RANGE COLUMNS `c` '2026-04-26 00:00:00' 0 +p7 RANGE COLUMNS `c` '2026-04-27 00:00:00' 0 +p8 RANGE COLUMNS `c` '2026-04-28 00:00:00' 0 +p9 RANGE COLUMNS `c` '2026-04-29 00:00:00' 0 +p10 RANGE COLUMNS `c` '2026-04-30 00:00:00' 0 +p11 RANGE COLUMNS `c` '2026-05-01 00:00:00' 0 +p12 RANGE COLUMNS `c` '2026-05-02 00:00:00' 1 +p13 RANGE COLUMNS `c` '2026-05-03 00:00:00' 0 +set timestamp= unix_timestamp('2026-05-06 00:00:00'); +insert into t1 values ('2026-05-04'); +select * from t1; +c +2026-05-01 00:00:00 +2026-05-04 00:00:00 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-20') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-21 00:00:00') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-04-22 00:00:00') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-04-23 00:00:00') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-04-24 00:00:00') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-04-25 00:00:00') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-04-26 00:00:00') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-04-27 00:00:00') ENGINE = InnoDB, + PARTITION `p8` VALUES LESS THAN ('2026-04-28 00:00:00') ENGINE = InnoDB, + PARTITION `p9` VALUES LESS THAN ('2026-04-29 00:00:00') ENGINE = InnoDB, + PARTITION `p10` VALUES LESS THAN ('2026-04-30 00:00:00') ENGINE = InnoDB, + PARTITION `p11` VALUES LESS THAN ('2026-05-01 00:00:00') ENGINE = InnoDB, + PARTITION `p12` VALUES LESS THAN ('2026-05-02 00:00:00') ENGINE = InnoDB, + PARTITION `p13` VALUES LESS THAN ('2026-05-03 00:00:00') ENGINE = InnoDB, + PARTITION `p14` VALUES LESS THAN ('2026-05-04 00:00:00') ENGINE = InnoDB, + PARTITION `p15` VALUES LESS THAN ('2026-05-05 00:00:00') ENGINE = InnoDB, + PARTITION `p16` VALUES LESS THAN ('2026-05-06 00:00:00') ENGINE = InnoDB, + PARTITION `p17` VALUES LESS THAN ('2026-05-07 00:00:00') ENGINE = InnoDB) +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +partition_name partition_method partition_expression partition_description table_rows +p0 RANGE COLUMNS `c` '2026-04-20' 0 +p1 RANGE COLUMNS `c` '2026-04-21 00:00:00' 0 +p2 RANGE COLUMNS `c` '2026-04-22 00:00:00' 0 +p3 RANGE COLUMNS `c` '2026-04-23 00:00:00' 0 +p4 RANGE COLUMNS `c` '2026-04-24 00:00:00' 0 +p5 RANGE COLUMNS `c` '2026-04-25 00:00:00' 0 +p6 RANGE COLUMNS `c` '2026-04-26 00:00:00' 0 +p7 RANGE COLUMNS `c` '2026-04-27 00:00:00' 0 +p8 RANGE COLUMNS `c` '2026-04-28 00:00:00' 0 +p9 RANGE COLUMNS `c` '2026-04-29 00:00:00' 0 +p10 RANGE COLUMNS `c` '2026-04-30 00:00:00' 0 +p11 RANGE COLUMNS `c` '2026-05-01 00:00:00' 0 +p12 RANGE COLUMNS `c` '2026-05-02 00:00:00' 1 +p13 RANGE COLUMNS `c` '2026-05-03 00:00:00' 0 +p14 RANGE COLUMNS `c` '2026-05-04 00:00:00' 0 +p15 RANGE COLUMNS `c` '2026-05-05 00:00:00' 1 +p16 RANGE COLUMNS `c` '2026-05-06 00:00:00' 0 +p17 RANGE COLUMNS `c` '2026-05-07 00:00:00' 0 +drop table t1; +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 DAY AUTO +( +PARTITION p0 VALUES LESS THAN ('2026-04-30') +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-30') ENGINE = InnoDB) +insert into t1 values ('2026-05-01'); +select * from t1; +c +2026-05-01 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-30') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-05-01') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-05-02') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-05-03') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-05-04') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-05-05') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-05-06') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-05-07') ENGINE = InnoDB) +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +partition_name partition_method partition_expression partition_description table_rows +p0 RANGE COLUMNS `c` '2026-04-30' 0 +p1 RANGE COLUMNS `c` '2026-05-01' 0 +p2 RANGE COLUMNS `c` '2026-05-02' 1 +p3 RANGE COLUMNS `c` '2026-05-03' 0 +p4 RANGE COLUMNS `c` '2026-05-04' 0 +p5 RANGE COLUMNS `c` '2026-05-05' 0 +p6 RANGE COLUMNS `c` '2026-05-06' 0 +p7 RANGE COLUMNS `c` '2026-05-07' 0 +drop table t1; +# 1.5 day interval truncated to +1d, +2d, +1d, +2d, ... +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 36 Hour +( +PARTITION p0 VALUES LESS THAN ('2026-04-30') +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 36 HOUR +(PARTITION `p0` VALUES LESS THAN ('2026-04-30') ENGINE = InnoDB) +insert into t1 values ('2026-05-01'); +select * from t1; +c +2026-05-01 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 36 HOUR +(PARTITION `p0` VALUES LESS THAN ('2026-04-30') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-05-01') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-05-03') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-05-04') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-05-06') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-05-07') ENGINE = InnoDB) +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +partition_name partition_method partition_expression partition_description table_rows +p0 RANGE COLUMNS `c` '2026-04-30' 0 +p1 RANGE COLUMNS `c` '2026-05-01' 0 +p2 RANGE COLUMNS `c` '2026-05-03' 1 +p3 RANGE COLUMNS `c` '2026-05-04' 0 +p4 RANGE COLUMNS `c` '2026-05-06' 0 +p5 RANGE COLUMNS `c` '2026-05-07' 0 +drop table t1; +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Week +( +PARTITION p0 VALUES LESS THAN ('2026-04-20') +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 7 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-20') ENGINE = InnoDB) +insert into t1 values ('2026-05-01'); +select * from t1; +c +2026-05-01 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 7 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-20') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-27') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-05-04') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-05-11') ENGINE = InnoDB) +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +partition_name partition_method partition_expression partition_description table_rows +p0 RANGE COLUMNS `c` '2026-04-20' 0 +p1 RANGE COLUMNS `c` '2026-04-27' 0 +p2 RANGE COLUMNS `c` '2026-05-04' 1 +p3 RANGE COLUMNS `c` '2026-05-11' 0 +drop table t1; +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 hour +( +PARTITION p0 VALUES LESS THAN ('2026-05-05') +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 HOUR +(PARTITION `p0` VALUES LESS THAN ('2026-05-05') ENGINE = InnoDB) +insert into t1 values ('2026-05-05 03:00:00'); +select * from t1; +c +2026-05-05 03:00:00 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 HOUR +(PARTITION `p0` VALUES LESS THAN ('2026-05-05') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-05-05 01:00:00') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-05-05 02:00:00') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-05-05 03:00:00') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-05-05 04:00:00') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-05-05 05:00:00') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-05-05 06:00:00') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-05-05 07:00:00') ENGINE = InnoDB, + PARTITION `p8` VALUES LESS THAN ('2026-05-05 08:00:00') ENGINE = InnoDB, + PARTITION `p9` VALUES LESS THAN ('2026-05-05 09:00:00') ENGINE = InnoDB, + PARTITION `p10` VALUES LESS THAN ('2026-05-05 10:00:00') ENGINE = InnoDB, + PARTITION `p11` VALUES LESS THAN ('2026-05-05 11:00:00') ENGINE = InnoDB, + PARTITION `p12` VALUES LESS THAN ('2026-05-05 12:00:00') ENGINE = InnoDB, + PARTITION `p13` VALUES LESS THAN ('2026-05-05 13:00:00') ENGINE = InnoDB, + PARTITION `p14` VALUES LESS THAN ('2026-05-05 14:00:00') ENGINE = InnoDB, + PARTITION `p15` VALUES LESS THAN ('2026-05-05 15:00:00') ENGINE = InnoDB, + PARTITION `p16` VALUES LESS THAN ('2026-05-05 16:00:00') ENGINE = InnoDB, + PARTITION `p17` VALUES LESS THAN ('2026-05-05 17:00:00') ENGINE = InnoDB, + PARTITION `p18` VALUES LESS THAN ('2026-05-05 18:00:00') ENGINE = InnoDB, + PARTITION `p19` VALUES LESS THAN ('2026-05-05 19:00:00') ENGINE = InnoDB, + PARTITION `p20` VALUES LESS THAN ('2026-05-05 20:00:00') ENGINE = InnoDB, + PARTITION `p21` VALUES LESS THAN ('2026-05-05 21:00:00') ENGINE = InnoDB, + PARTITION `p22` VALUES LESS THAN ('2026-05-05 22:00:00') ENGINE = InnoDB, + PARTITION `p23` VALUES LESS THAN ('2026-05-05 23:00:00') ENGINE = InnoDB, + PARTITION `p24` VALUES LESS THAN ('2026-05-06 00:00:00') ENGINE = InnoDB, + PARTITION `p25` VALUES LESS THAN ('2026-05-06 01:00:00') ENGINE = InnoDB) +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +partition_name partition_method partition_expression partition_description table_rows +p0 RANGE COLUMNS `c` '2026-05-05' 0 +p1 RANGE COLUMNS `c` '2026-05-05 01:00:00' 0 +p2 RANGE COLUMNS `c` '2026-05-05 02:00:00' 0 +p3 RANGE COLUMNS `c` '2026-05-05 03:00:00' 0 +p4 RANGE COLUMNS `c` '2026-05-05 04:00:00' 1 +p5 RANGE COLUMNS `c` '2026-05-05 05:00:00' 0 +p6 RANGE COLUMNS `c` '2026-05-05 06:00:00' 0 +p7 RANGE COLUMNS `c` '2026-05-05 07:00:00' 0 +p8 RANGE COLUMNS `c` '2026-05-05 08:00:00' 0 +p9 RANGE COLUMNS `c` '2026-05-05 09:00:00' 0 +p10 RANGE COLUMNS `c` '2026-05-05 10:00:00' 0 +p11 RANGE COLUMNS `c` '2026-05-05 11:00:00' 0 +p12 RANGE COLUMNS `c` '2026-05-05 12:00:00' 0 +p13 RANGE COLUMNS `c` '2026-05-05 13:00:00' 0 +p14 RANGE COLUMNS `c` '2026-05-05 14:00:00' 0 +p15 RANGE COLUMNS `c` '2026-05-05 15:00:00' 0 +p16 RANGE COLUMNS `c` '2026-05-05 16:00:00' 0 +p17 RANGE COLUMNS `c` '2026-05-05 17:00:00' 0 +p18 RANGE COLUMNS `c` '2026-05-05 18:00:00' 0 +p19 RANGE COLUMNS `c` '2026-05-05 19:00:00' 0 +p20 RANGE COLUMNS `c` '2026-05-05 20:00:00' 0 +p21 RANGE COLUMNS `c` '2026-05-05 21:00:00' 0 +p22 RANGE COLUMNS `c` '2026-05-05 22:00:00' 0 +p23 RANGE COLUMNS `c` '2026-05-05 23:00:00' 0 +p24 RANGE COLUMNS `c` '2026-05-06 00:00:00' 0 +p25 RANGE COLUMNS `c` '2026-05-06 01:00:00' 0 +drop table t1; +# more than 1 starting partition +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p0 VALUES LESS THAN ('2026-04-20'), +PARTITION p1 VALUES LESS THAN ('2026-04-25') +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-20') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-25') ENGINE = InnoDB) +insert into t1 values ('2026-05-01'); +select * from t1; +c +2026-05-01 00:00:00 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-20') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-25') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-04-26 00:00:00') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-04-27 00:00:00') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-04-28 00:00:00') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-04-29 00:00:00') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-04-30 00:00:00') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-05-01 00:00:00') ENGINE = InnoDB, + PARTITION `p8` VALUES LESS THAN ('2026-05-02 00:00:00') ENGINE = InnoDB, + PARTITION `p9` VALUES LESS THAN ('2026-05-03 00:00:00') ENGINE = InnoDB, + PARTITION `p10` VALUES LESS THAN ('2026-05-04 00:00:00') ENGINE = InnoDB, + PARTITION `p11` VALUES LESS THAN ('2026-05-05 00:00:00') ENGINE = InnoDB, + PARTITION `p12` VALUES LESS THAN ('2026-05-06 00:00:00') ENGINE = InnoDB, + PARTITION `p13` VALUES LESS THAN ('2026-05-07 00:00:00') ENGINE = InnoDB) +drop table t1; +# no need to create new partition when existing ones are sufficient +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p0 VALUES LESS THAN ('2026-04-01'), +PARTITION p1 VALUES LESS THAN ('2026-05-06') +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-01') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-05-06') ENGINE = InnoDB) +insert into t1 values ('2026-05-01'); +select * from t1; +c +2026-05-01 00:00:00 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-01') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-05-06') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-05-07 00:00:00') ENGINE = InnoDB) +drop table t1; +# find a gap big enough for names of 10 new partition names +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p9 VALUES LESS THAN ('2026-04-01'), +PARTITION p29 VALUES LESS THAN ('2026-04-04'), +PARTITION p19 VALUES LESS THAN ('2026-04-23'), +PARTITION p40 VALUES LESS THAN ('2026-04-27') +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p9` VALUES LESS THAN ('2026-04-01') ENGINE = InnoDB, + PARTITION `p29` VALUES LESS THAN ('2026-04-04') ENGINE = InnoDB, + PARTITION `p19` VALUES LESS THAN ('2026-04-23') ENGINE = InnoDB, + PARTITION `p40` VALUES LESS THAN ('2026-04-27') ENGINE = InnoDB) +insert into t1 values ('2026-05-01'); +select * from t1; +c +2026-05-01 00:00:00 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p9` VALUES LESS THAN ('2026-04-01') ENGINE = InnoDB, + PARTITION `p29` VALUES LESS THAN ('2026-04-04') ENGINE = InnoDB, + PARTITION `p19` VALUES LESS THAN ('2026-04-23') ENGINE = InnoDB, + PARTITION `p40` VALUES LESS THAN ('2026-04-27') ENGINE = InnoDB, + PARTITION `p30` VALUES LESS THAN ('2026-04-28 00:00:00') ENGINE = InnoDB, + PARTITION `p31` VALUES LESS THAN ('2026-04-29 00:00:00') ENGINE = InnoDB, + PARTITION `p32` VALUES LESS THAN ('2026-04-30 00:00:00') ENGINE = InnoDB, + PARTITION `p33` VALUES LESS THAN ('2026-05-01 00:00:00') ENGINE = InnoDB, + PARTITION `p34` VALUES LESS THAN ('2026-05-02 00:00:00') ENGINE = InnoDB, + PARTITION `p35` VALUES LESS THAN ('2026-05-03 00:00:00') ENGINE = InnoDB, + PARTITION `p36` VALUES LESS THAN ('2026-05-04 00:00:00') ENGINE = InnoDB, + PARTITION `p37` VALUES LESS THAN ('2026-05-05 00:00:00') ENGINE = InnoDB, + PARTITION `p38` VALUES LESS THAN ('2026-05-06 00:00:00') ENGINE = InnoDB, + PARTITION `p39` VALUES LESS THAN ('2026-05-07 00:00:00') ENGINE = InnoDB) +drop table t1; +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p40 VALUES LESS THAN ('2026-04-27') +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p40` VALUES LESS THAN ('2026-04-27') ENGINE = InnoDB) +insert into t1 values ('2026-05-01'); +select * from t1; +c +2026-05-01 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p40` VALUES LESS THAN ('2026-04-27') ENGINE = InnoDB, + PARTITION `p0` VALUES LESS THAN ('2026-04-28') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-29') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-04-30') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-05-01') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-05-02') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-05-03') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-05-04') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-05-05') ENGINE = InnoDB, + PARTITION `p8` VALUES LESS THAN ('2026-05-06') ENGINE = InnoDB, + PARTITION `p9` VALUES LESS THAN ('2026-05-07') ENGINE = InnoDB) +drop table t1; +# CREATE TABLE ... SELECT +# does not work probably because of MDEV-29769 +select to_days('2026-04-01') = 740072; +to_days('2026-04-01') = 740072 +1 +select to_days('2026-05-01') = 740102; +to_days('2026-05-01') = 740102 +1 +# somehow ps protocol has different results +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p0 VALUES LESS THAN ('2026-04-01') +) +select from_days(seq) as c from seq_740073_to_740102; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +partition_name partition_method partition_expression partition_description table_rows +NULL NULL NULL NULL 30 +drop table t1; +# INSERT ... SELECT +select to_days('2026-04-01') = 740072; +to_days('2026-04-01') = 740072 +1 +select to_days('2026-05-01') = 740102; +to_days('2026-05-01') = 740102 +1 +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p0 VALUES LESS THAN ('2026-04-01') +); +insert into t1 select from_days(seq) from seq_740073_to_740102; +select * from t1; +c +2026-04-02 +2026-04-03 +2026-04-04 +2026-04-05 +2026-04-06 +2026-04-07 +2026-04-08 +2026-04-09 +2026-04-10 +2026-04-11 +2026-04-12 +2026-04-13 +2026-04-14 +2026-04-15 +2026-04-16 +2026-04-17 +2026-04-18 +2026-04-19 +2026-04-20 +2026-04-21 +2026-04-22 +2026-04-23 +2026-04-24 +2026-04-25 +2026-04-26 +2026-04-27 +2026-04-28 +2026-04-29 +2026-04-30 +2026-05-01 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-01') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-02') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-04-03') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-04-04') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-04-05') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-04-06') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-04-07') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-04-08') ENGINE = InnoDB, + PARTITION `p8` VALUES LESS THAN ('2026-04-09') ENGINE = InnoDB, + PARTITION `p9` VALUES LESS THAN ('2026-04-10') ENGINE = InnoDB, + PARTITION `p10` VALUES LESS THAN ('2026-04-11') ENGINE = InnoDB, + PARTITION `p11` VALUES LESS THAN ('2026-04-12') ENGINE = InnoDB, + PARTITION `p12` VALUES LESS THAN ('2026-04-13') ENGINE = InnoDB, + PARTITION `p13` VALUES LESS THAN ('2026-04-14') ENGINE = InnoDB, + PARTITION `p14` VALUES LESS THAN ('2026-04-15') ENGINE = InnoDB, + PARTITION `p15` VALUES LESS THAN ('2026-04-16') ENGINE = InnoDB, + PARTITION `p16` VALUES LESS THAN ('2026-04-17') ENGINE = InnoDB, + PARTITION `p17` VALUES LESS THAN ('2026-04-18') ENGINE = InnoDB, + PARTITION `p18` VALUES LESS THAN ('2026-04-19') ENGINE = InnoDB, + PARTITION `p19` VALUES LESS THAN ('2026-04-20') ENGINE = InnoDB, + PARTITION `p20` VALUES LESS THAN ('2026-04-21') ENGINE = InnoDB, + PARTITION `p21` VALUES LESS THAN ('2026-04-22') ENGINE = InnoDB, + PARTITION `p22` VALUES LESS THAN ('2026-04-23') ENGINE = InnoDB, + PARTITION `p23` VALUES LESS THAN ('2026-04-24') ENGINE = InnoDB, + PARTITION `p24` VALUES LESS THAN ('2026-04-25') ENGINE = InnoDB, + PARTITION `p25` VALUES LESS THAN ('2026-04-26') ENGINE = InnoDB, + PARTITION `p26` VALUES LESS THAN ('2026-04-27') ENGINE = InnoDB, + PARTITION `p27` VALUES LESS THAN ('2026-04-28') ENGINE = InnoDB, + PARTITION `p28` VALUES LESS THAN ('2026-04-29') ENGINE = InnoDB, + PARTITION `p29` VALUES LESS THAN ('2026-04-30') ENGINE = InnoDB, + PARTITION `p30` VALUES LESS THAN ('2026-05-01') ENGINE = InnoDB, + PARTITION `p31` VALUES LESS THAN ('2026-05-02') ENGINE = InnoDB, + PARTITION `p32` VALUES LESS THAN ('2026-05-03') ENGINE = InnoDB, + PARTITION `p33` VALUES LESS THAN ('2026-05-04') ENGINE = InnoDB, + PARTITION `p34` VALUES LESS THAN ('2026-05-05') ENGINE = InnoDB, + PARTITION `p35` VALUES LESS THAN ('2026-05-06') ENGINE = InnoDB, + PARTITION `p36` VALUES LESS THAN ('2026-05-07') ENGINE = InnoDB) +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +partition_name partition_method partition_expression partition_description table_rows +p0 RANGE COLUMNS `c` '2026-04-01' 0 +p1 RANGE COLUMNS `c` '2026-04-02' 0 +p2 RANGE COLUMNS `c` '2026-04-03' 1 +p3 RANGE COLUMNS `c` '2026-04-04' 1 +p4 RANGE COLUMNS `c` '2026-04-05' 1 +p5 RANGE COLUMNS `c` '2026-04-06' 1 +p6 RANGE COLUMNS `c` '2026-04-07' 1 +p7 RANGE COLUMNS `c` '2026-04-08' 1 +p8 RANGE COLUMNS `c` '2026-04-09' 1 +p9 RANGE COLUMNS `c` '2026-04-10' 1 +p10 RANGE COLUMNS `c` '2026-04-11' 1 +p11 RANGE COLUMNS `c` '2026-04-12' 1 +p12 RANGE COLUMNS `c` '2026-04-13' 1 +p13 RANGE COLUMNS `c` '2026-04-14' 1 +p14 RANGE COLUMNS `c` '2026-04-15' 1 +p15 RANGE COLUMNS `c` '2026-04-16' 1 +p16 RANGE COLUMNS `c` '2026-04-17' 1 +p17 RANGE COLUMNS `c` '2026-04-18' 1 +p18 RANGE COLUMNS `c` '2026-04-19' 1 +p19 RANGE COLUMNS `c` '2026-04-20' 1 +p20 RANGE COLUMNS `c` '2026-04-21' 1 +p21 RANGE COLUMNS `c` '2026-04-22' 1 +p22 RANGE COLUMNS `c` '2026-04-23' 1 +p23 RANGE COLUMNS `c` '2026-04-24' 1 +p24 RANGE COLUMNS `c` '2026-04-25' 1 +p25 RANGE COLUMNS `c` '2026-04-26' 1 +p26 RANGE COLUMNS `c` '2026-04-27' 1 +p27 RANGE COLUMNS `c` '2026-04-28' 1 +p28 RANGE COLUMNS `c` '2026-04-29' 1 +p29 RANGE COLUMNS `c` '2026-04-30' 1 +p30 RANGE COLUMNS `c` '2026-05-01' 1 +p31 RANGE COLUMNS `c` '2026-05-02' 1 +p32 RANGE COLUMNS `c` '2026-05-03' 0 +p33 RANGE COLUMNS `c` '2026-05-04' 0 +p34 RANGE COLUMNS `c` '2026-05-05' 0 +p35 RANGE COLUMNS `c` '2026-05-06' 0 +p36 RANGE COLUMNS `c` '2026-05-07' 0 +drop table t1; +select to_days('2026-05-01') = 740102; +to_days('2026-05-01') = 740102 +1 +select to_days('2026-05-08') = 740109; +to_days('2026-05-08') = 740109 +1 +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p0 VALUES LESS THAN ('2026-04-01') +); +insert into t1 select from_days(seq) from seq_740102_to_740109; +ERROR HY000: Table has no partition for value from column_list +select * from t1; +c +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-01') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-02') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-04-03') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-04-04') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-04-05') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-04-06') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-04-07') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-04-08') ENGINE = InnoDB, + PARTITION `p8` VALUES LESS THAN ('2026-04-09') ENGINE = InnoDB, + PARTITION `p9` VALUES LESS THAN ('2026-04-10') ENGINE = InnoDB, + PARTITION `p10` VALUES LESS THAN ('2026-04-11') ENGINE = InnoDB, + PARTITION `p11` VALUES LESS THAN ('2026-04-12') ENGINE = InnoDB, + PARTITION `p12` VALUES LESS THAN ('2026-04-13') ENGINE = InnoDB, + PARTITION `p13` VALUES LESS THAN ('2026-04-14') ENGINE = InnoDB, + PARTITION `p14` VALUES LESS THAN ('2026-04-15') ENGINE = InnoDB, + PARTITION `p15` VALUES LESS THAN ('2026-04-16') ENGINE = InnoDB, + PARTITION `p16` VALUES LESS THAN ('2026-04-17') ENGINE = InnoDB, + PARTITION `p17` VALUES LESS THAN ('2026-04-18') ENGINE = InnoDB, + PARTITION `p18` VALUES LESS THAN ('2026-04-19') ENGINE = InnoDB, + PARTITION `p19` VALUES LESS THAN ('2026-04-20') ENGINE = InnoDB, + PARTITION `p20` VALUES LESS THAN ('2026-04-21') ENGINE = InnoDB, + PARTITION `p21` VALUES LESS THAN ('2026-04-22') ENGINE = InnoDB, + PARTITION `p22` VALUES LESS THAN ('2026-04-23') ENGINE = InnoDB, + PARTITION `p23` VALUES LESS THAN ('2026-04-24') ENGINE = InnoDB, + PARTITION `p24` VALUES LESS THAN ('2026-04-25') ENGINE = InnoDB, + PARTITION `p25` VALUES LESS THAN ('2026-04-26') ENGINE = InnoDB, + PARTITION `p26` VALUES LESS THAN ('2026-04-27') ENGINE = InnoDB, + PARTITION `p27` VALUES LESS THAN ('2026-04-28') ENGINE = InnoDB, + PARTITION `p28` VALUES LESS THAN ('2026-04-29') ENGINE = InnoDB, + PARTITION `p29` VALUES LESS THAN ('2026-04-30') ENGINE = InnoDB, + PARTITION `p30` VALUES LESS THAN ('2026-05-01') ENGINE = InnoDB, + PARTITION `p31` VALUES LESS THAN ('2026-05-02') ENGINE = InnoDB, + PARTITION `p32` VALUES LESS THAN ('2026-05-03') ENGINE = InnoDB, + PARTITION `p33` VALUES LESS THAN ('2026-05-04') ENGINE = InnoDB, + PARTITION `p34` VALUES LESS THAN ('2026-05-05') ENGINE = InnoDB, + PARTITION `p35` VALUES LESS THAN ('2026-05-06') ENGINE = InnoDB, + PARTITION `p36` VALUES LESS THAN ('2026-05-07') ENGINE = InnoDB) +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1' and table_rows > 0; +partition_name partition_method partition_expression partition_description table_rows +drop table t1; +# LOAD DATA INFILE +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p0 VALUES LESS THAN ('2026-04-20') +); +load data infile 'load.data' ignore into table t1; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-20') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-21') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-04-22') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-04-23') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-04-24') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-04-25') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-04-26') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-04-27') ENGINE = InnoDB, + PARTITION `p8` VALUES LESS THAN ('2026-04-28') ENGINE = InnoDB, + PARTITION `p9` VALUES LESS THAN ('2026-04-29') ENGINE = InnoDB, + PARTITION `p10` VALUES LESS THAN ('2026-04-30') ENGINE = InnoDB, + PARTITION `p11` VALUES LESS THAN ('2026-05-01') ENGINE = InnoDB, + PARTITION `p12` VALUES LESS THAN ('2026-05-02') ENGINE = InnoDB, + PARTITION `p13` VALUES LESS THAN ('2026-05-03') ENGINE = InnoDB, + PARTITION `p14` VALUES LESS THAN ('2026-05-04') ENGINE = InnoDB, + PARTITION `p15` VALUES LESS THAN ('2026-05-05') ENGINE = InnoDB, + PARTITION `p16` VALUES LESS THAN ('2026-05-06') ENGINE = InnoDB, + PARTITION `p17` VALUES LESS THAN ('2026-05-07') ENGINE = InnoDB) +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1' and table_rows > 0; +partition_name partition_method partition_expression partition_description table_rows +p12 RANGE COLUMNS `c` '2026-05-02' 1 +p13 RANGE COLUMNS `c` '2026-05-03' 1 +p14 RANGE COLUMNS `c` '2026-05-04' 1 +p15 RANGE COLUMNS `c` '2026-05-05' 1 +p16 RANGE COLUMNS `c` '2026-05-06' 1 +drop table t1; +# LOAD DATA INFILE is not atomic +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p0 VALUES LESS THAN ('2026-04-20') +); +load data infile 'load.data' ignore into table t1; +Warnings: +Warning 1526 Table has no partition for value from column_list +Warning 1526 Table has no partition for value from column_list +select * from t1; +c +2026-05-05 +2026-05-06 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-20') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-21') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-04-22') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-04-23') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-04-24') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-04-25') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-04-26') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-04-27') ENGINE = InnoDB, + PARTITION `p8` VALUES LESS THAN ('2026-04-28') ENGINE = InnoDB, + PARTITION `p9` VALUES LESS THAN ('2026-04-29') ENGINE = InnoDB, + PARTITION `p10` VALUES LESS THAN ('2026-04-30') ENGINE = InnoDB, + PARTITION `p11` VALUES LESS THAN ('2026-05-01') ENGINE = InnoDB, + PARTITION `p12` VALUES LESS THAN ('2026-05-02') ENGINE = InnoDB, + PARTITION `p13` VALUES LESS THAN ('2026-05-03') ENGINE = InnoDB, + PARTITION `p14` VALUES LESS THAN ('2026-05-04') ENGINE = InnoDB, + PARTITION `p15` VALUES LESS THAN ('2026-05-05') ENGINE = InnoDB, + PARTITION `p16` VALUES LESS THAN ('2026-05-06') ENGINE = InnoDB, + PARTITION `p17` VALUES LESS THAN ('2026-05-07') ENGINE = InnoDB) +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1' and table_rows > 0; +partition_name partition_method partition_expression partition_description table_rows +p16 RANGE COLUMNS `c` '2026-05-06' 1 +p17 RANGE COLUMNS `c` '2026-05-07' 1 +drop table t1; +# UPDATE +set timestamp= unix_timestamp('2026-05-02 00:00:00'); +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p0 VALUES LESS THAN ('2026-04-25') +); +insert into t1 values ('2026-04-28'), ('2026-04-29'), ('2026-04-30'); +select * from t1; +c +2026-04-28 +2026-04-29 +2026-04-30 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-25') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-26') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-04-27') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-04-28') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-04-29') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-04-30') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-05-01') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-05-02') ENGINE = InnoDB, + PARTITION `p8` VALUES LESS THAN ('2026-05-03') ENGINE = InnoDB) +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1' and table_rows > 0; +partition_name partition_method partition_expression partition_description table_rows +p4 RANGE COLUMNS `c` '2026-04-29' 1 +p5 RANGE COLUMNS `c` '2026-04-30' 1 +p6 RANGE COLUMNS `c` '2026-05-01' 1 +set timestamp= unix_timestamp('2026-05-06 00:00:00'); +update t1 set c = date_add(c, interval 6 day); +select * from t1; +c +2026-05-04 +2026-05-05 +2026-05-06 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-25') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-26') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-04-27') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-04-28') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-04-29') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-04-30') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-05-01') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-05-02') ENGINE = InnoDB, + PARTITION `p8` VALUES LESS THAN ('2026-05-03') ENGINE = InnoDB, + PARTITION `p9` VALUES LESS THAN ('2026-05-04') ENGINE = InnoDB, + PARTITION `p10` VALUES LESS THAN ('2026-05-05') ENGINE = InnoDB, + PARTITION `p11` VALUES LESS THAN ('2026-05-06') ENGINE = InnoDB, + PARTITION `p12` VALUES LESS THAN ('2026-05-07') ENGINE = InnoDB) +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1' and table_rows > 0; +partition_name partition_method partition_expression partition_description table_rows +p10 RANGE COLUMNS `c` '2026-05-05' 1 +p11 RANGE COLUMNS `c` '2026-05-06' 1 +p12 RANGE COLUMNS `c` '2026-05-07' 1 +set timestamp= unix_timestamp('2026-05-08 00:00:00'); +update t1 set c = date_add(c, interval 3 day); +ERROR HY000: Table has no partition for value from column_list +select * from t1; +c +2026-05-04 +2026-05-05 +2026-05-06 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-25') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-26') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-04-27') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-04-28') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-04-29') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-04-30') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-05-01') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-05-02') ENGINE = InnoDB, + PARTITION `p8` VALUES LESS THAN ('2026-05-03') ENGINE = InnoDB, + PARTITION `p9` VALUES LESS THAN ('2026-05-04') ENGINE = InnoDB, + PARTITION `p10` VALUES LESS THAN ('2026-05-05') ENGINE = InnoDB, + PARTITION `p11` VALUES LESS THAN ('2026-05-06') ENGINE = InnoDB, + PARTITION `p12` VALUES LESS THAN ('2026-05-07') ENGINE = InnoDB, + PARTITION `p13` VALUES LESS THAN ('2026-05-08') ENGINE = InnoDB, + PARTITION `p14` VALUES LESS THAN ('2026-05-09') ENGINE = InnoDB) +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1' and table_rows > 0; +partition_name partition_method partition_expression partition_description table_rows +p10 RANGE COLUMNS `c` '2026-05-05' 1 +p11 RANGE COLUMNS `c` '2026-05-06' 1 +p12 RANGE COLUMNS `c` '2026-05-07' 1 +set timestamp= unix_timestamp('2026-05-06 00:00:00'); +drop table t1; +# ALTER TABLE +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +( +PARTITION p0 VALUES LESS THAN ('2026-04-25') +); +insert into t1 values ('2026-05-01'); +ERROR HY000: Table has no partition for value from column_list +ALTER TABLE t1 PARTITION BY RANGE COLUMNS (c) INTERVAL 1 DAY +( +PARTITION p0 VALUES LESS THAN ('2026-04-25') +); +insert into t1 values ('2026-05-01'); +SELECT * FROM t1; +c +2026-05-01 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` date DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-25') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-26') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-04-27') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-04-28') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-04-29') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-04-30') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-05-01') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-05-02') ENGINE = InnoDB, + PARTITION `p8` VALUES LESS THAN ('2026-05-03') ENGINE = InnoDB, + PARTITION `p9` VALUES LESS THAN ('2026-05-04') ENGINE = InnoDB, + PARTITION `p10` VALUES LESS THAN ('2026-05-05') ENGINE = InnoDB, + PARTITION `p11` VALUES LESS THAN ('2026-05-06') ENGINE = InnoDB, + PARTITION `p12` VALUES LESS THAN ('2026-05-07') ENGINE = InnoDB) +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1' and table_rows > 0; +partition_name partition_method partition_expression partition_description table_rows +p7 RANGE COLUMNS `c` '2026-05-02' 1 +drop table t1; +# failing insertion of dates in the future +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p0 VALUES LESS THAN ('2026-04-01') +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-01') ENGINE = InnoDB) +insert into t1 values ('2026-05-07'); +ERROR HY000: Table has no partition for value from column_list +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-01') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-02 00:00:00') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-04-03 00:00:00') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-04-04 00:00:00') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-04-05 00:00:00') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-04-06 00:00:00') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-04-07 00:00:00') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-04-08 00:00:00') ENGINE = InnoDB, + PARTITION `p8` VALUES LESS THAN ('2026-04-09 00:00:00') ENGINE = InnoDB, + PARTITION `p9` VALUES LESS THAN ('2026-04-10 00:00:00') ENGINE = InnoDB, + PARTITION `p10` VALUES LESS THAN ('2026-04-11 00:00:00') ENGINE = InnoDB, + PARTITION `p11` VALUES LESS THAN ('2026-04-12 00:00:00') ENGINE = InnoDB, + PARTITION `p12` VALUES LESS THAN ('2026-04-13 00:00:00') ENGINE = InnoDB, + PARTITION `p13` VALUES LESS THAN ('2026-04-14 00:00:00') ENGINE = InnoDB, + PARTITION `p14` VALUES LESS THAN ('2026-04-15 00:00:00') ENGINE = InnoDB, + PARTITION `p15` VALUES LESS THAN ('2026-04-16 00:00:00') ENGINE = InnoDB, + PARTITION `p16` VALUES LESS THAN ('2026-04-17 00:00:00') ENGINE = InnoDB, + PARTITION `p17` VALUES LESS THAN ('2026-04-18 00:00:00') ENGINE = InnoDB, + PARTITION `p18` VALUES LESS THAN ('2026-04-19 00:00:00') ENGINE = InnoDB, + PARTITION `p19` VALUES LESS THAN ('2026-04-20 00:00:00') ENGINE = InnoDB, + PARTITION `p20` VALUES LESS THAN ('2026-04-21 00:00:00') ENGINE = InnoDB, + PARTITION `p21` VALUES LESS THAN ('2026-04-22 00:00:00') ENGINE = InnoDB, + PARTITION `p22` VALUES LESS THAN ('2026-04-23 00:00:00') ENGINE = InnoDB, + PARTITION `p23` VALUES LESS THAN ('2026-04-24 00:00:00') ENGINE = InnoDB, + PARTITION `p24` VALUES LESS THAN ('2026-04-25 00:00:00') ENGINE = InnoDB, + PARTITION `p25` VALUES LESS THAN ('2026-04-26 00:00:00') ENGINE = InnoDB, + PARTITION `p26` VALUES LESS THAN ('2026-04-27 00:00:00') ENGINE = InnoDB, + PARTITION `p27` VALUES LESS THAN ('2026-04-28 00:00:00') ENGINE = InnoDB, + PARTITION `p28` VALUES LESS THAN ('2026-04-29 00:00:00') ENGINE = InnoDB, + PARTITION `p29` VALUES LESS THAN ('2026-04-30 00:00:00') ENGINE = InnoDB, + PARTITION `p30` VALUES LESS THAN ('2026-05-01 00:00:00') ENGINE = InnoDB, + PARTITION `p31` VALUES LESS THAN ('2026-05-02 00:00:00') ENGINE = InnoDB, + PARTITION `p32` VALUES LESS THAN ('2026-05-03 00:00:00') ENGINE = InnoDB, + PARTITION `p33` VALUES LESS THAN ('2026-05-04 00:00:00') ENGINE = InnoDB, + PARTITION `p34` VALUES LESS THAN ('2026-05-05 00:00:00') ENGINE = InnoDB, + PARTITION `p35` VALUES LESS THAN ('2026-05-06 00:00:00') ENGINE = InnoDB, + PARTITION `p36` VALUES LESS THAN ('2026-05-07 00:00:00') ENGINE = InnoDB) +drop table t1; +# passthrough behaviour +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p0 VALUES LESS THAN ('2026-04-01') +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-01') ENGINE = InnoDB) +begin; +insert into t1 values ('2026-05-01'); +insert into t1 values ('2026-05-02'); +select * from t1; +c +2026-05-01 00:00:00 +2026-05-02 00:00:00 +rollback; +select * from t1; +c +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci + PARTITION BY RANGE COLUMNS(`c`)INTERVAL 1 DAY +(PARTITION `p0` VALUES LESS THAN ('2026-04-01') ENGINE = InnoDB, + PARTITION `p1` VALUES LESS THAN ('2026-04-02 00:00:00') ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN ('2026-04-03 00:00:00') ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN ('2026-04-04 00:00:00') ENGINE = InnoDB, + PARTITION `p4` VALUES LESS THAN ('2026-04-05 00:00:00') ENGINE = InnoDB, + PARTITION `p5` VALUES LESS THAN ('2026-04-06 00:00:00') ENGINE = InnoDB, + PARTITION `p6` VALUES LESS THAN ('2026-04-07 00:00:00') ENGINE = InnoDB, + PARTITION `p7` VALUES LESS THAN ('2026-04-08 00:00:00') ENGINE = InnoDB, + PARTITION `p8` VALUES LESS THAN ('2026-04-09 00:00:00') ENGINE = InnoDB, + PARTITION `p9` VALUES LESS THAN ('2026-04-10 00:00:00') ENGINE = InnoDB, + PARTITION `p10` VALUES LESS THAN ('2026-04-11 00:00:00') ENGINE = InnoDB, + PARTITION `p11` VALUES LESS THAN ('2026-04-12 00:00:00') ENGINE = InnoDB, + PARTITION `p12` VALUES LESS THAN ('2026-04-13 00:00:00') ENGINE = InnoDB, + PARTITION `p13` VALUES LESS THAN ('2026-04-14 00:00:00') ENGINE = InnoDB, + PARTITION `p14` VALUES LESS THAN ('2026-04-15 00:00:00') ENGINE = InnoDB, + PARTITION `p15` VALUES LESS THAN ('2026-04-16 00:00:00') ENGINE = InnoDB, + PARTITION `p16` VALUES LESS THAN ('2026-04-17 00:00:00') ENGINE = InnoDB, + PARTITION `p17` VALUES LESS THAN ('2026-04-18 00:00:00') ENGINE = InnoDB, + PARTITION `p18` VALUES LESS THAN ('2026-04-19 00:00:00') ENGINE = InnoDB, + PARTITION `p19` VALUES LESS THAN ('2026-04-20 00:00:00') ENGINE = InnoDB, + PARTITION `p20` VALUES LESS THAN ('2026-04-21 00:00:00') ENGINE = InnoDB, + PARTITION `p21` VALUES LESS THAN ('2026-04-22 00:00:00') ENGINE = InnoDB, + PARTITION `p22` VALUES LESS THAN ('2026-04-23 00:00:00') ENGINE = InnoDB, + PARTITION `p23` VALUES LESS THAN ('2026-04-24 00:00:00') ENGINE = InnoDB, + PARTITION `p24` VALUES LESS THAN ('2026-04-25 00:00:00') ENGINE = InnoDB, + PARTITION `p25` VALUES LESS THAN ('2026-04-26 00:00:00') ENGINE = InnoDB, + PARTITION `p26` VALUES LESS THAN ('2026-04-27 00:00:00') ENGINE = InnoDB, + PARTITION `p27` VALUES LESS THAN ('2026-04-28 00:00:00') ENGINE = InnoDB, + PARTITION `p28` VALUES LESS THAN ('2026-04-29 00:00:00') ENGINE = InnoDB, + PARTITION `p29` VALUES LESS THAN ('2026-04-30 00:00:00') ENGINE = InnoDB, + PARTITION `p30` VALUES LESS THAN ('2026-05-01 00:00:00') ENGINE = InnoDB, + PARTITION `p31` VALUES LESS THAN ('2026-05-02 00:00:00') ENGINE = InnoDB, + PARTITION `p32` VALUES LESS THAN ('2026-05-03 00:00:00') ENGINE = InnoDB, + PARTITION `p33` VALUES LESS THAN ('2026-05-04 00:00:00') ENGINE = InnoDB, + PARTITION `p34` VALUES LESS THAN ('2026-05-05 00:00:00') ENGINE = InnoDB, + PARTITION `p35` VALUES LESS THAN ('2026-05-06 00:00:00') ENGINE = InnoDB, + PARTITION `p36` VALUES LESS THAN ('2026-05-07 00:00:00') ENGINE = InnoDB) +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +partition_name partition_method partition_expression partition_description table_rows +p0 RANGE COLUMNS `c` '2026-04-01' 0 +p1 RANGE COLUMNS `c` '2026-04-02 00:00:00' 0 +p2 RANGE COLUMNS `c` '2026-04-03 00:00:00' 0 +p3 RANGE COLUMNS `c` '2026-04-04 00:00:00' 0 +p4 RANGE COLUMNS `c` '2026-04-05 00:00:00' 0 +p5 RANGE COLUMNS `c` '2026-04-06 00:00:00' 0 +p6 RANGE COLUMNS `c` '2026-04-07 00:00:00' 0 +p7 RANGE COLUMNS `c` '2026-04-08 00:00:00' 0 +p8 RANGE COLUMNS `c` '2026-04-09 00:00:00' 0 +p9 RANGE COLUMNS `c` '2026-04-10 00:00:00' 0 +p10 RANGE COLUMNS `c` '2026-04-11 00:00:00' 0 +p11 RANGE COLUMNS `c` '2026-04-12 00:00:00' 0 +p12 RANGE COLUMNS `c` '2026-04-13 00:00:00' 0 +p13 RANGE COLUMNS `c` '2026-04-14 00:00:00' 0 +p14 RANGE COLUMNS `c` '2026-04-15 00:00:00' 0 +p15 RANGE COLUMNS `c` '2026-04-16 00:00:00' 0 +p16 RANGE COLUMNS `c` '2026-04-17 00:00:00' 0 +p17 RANGE COLUMNS `c` '2026-04-18 00:00:00' 0 +p18 RANGE COLUMNS `c` '2026-04-19 00:00:00' 0 +p19 RANGE COLUMNS `c` '2026-04-20 00:00:00' 0 +p20 RANGE COLUMNS `c` '2026-04-21 00:00:00' 0 +p21 RANGE COLUMNS `c` '2026-04-22 00:00:00' 0 +p22 RANGE COLUMNS `c` '2026-04-23 00:00:00' 0 +p23 RANGE COLUMNS `c` '2026-04-24 00:00:00' 0 +p24 RANGE COLUMNS `c` '2026-04-25 00:00:00' 0 +p25 RANGE COLUMNS `c` '2026-04-26 00:00:00' 0 +p26 RANGE COLUMNS `c` '2026-04-27 00:00:00' 0 +p27 RANGE COLUMNS `c` '2026-04-28 00:00:00' 0 +p28 RANGE COLUMNS `c` '2026-04-29 00:00:00' 0 +p29 RANGE COLUMNS `c` '2026-04-30 00:00:00' 0 +p30 RANGE COLUMNS `c` '2026-05-01 00:00:00' 0 +p31 RANGE COLUMNS `c` '2026-05-02 00:00:00' 0 +p32 RANGE COLUMNS `c` '2026-05-03 00:00:00' 0 +p33 RANGE COLUMNS `c` '2026-05-04 00:00:00' 0 +p34 RANGE COLUMNS `c` '2026-05-05 00:00:00' 0 +p35 RANGE COLUMNS `c` '2026-05-06 00:00:00' 0 +p36 RANGE COLUMNS `c` '2026-05-07 00:00:00' 0 +drop table t1; +# failures +create table t1 (c1 datetime, c2 datetime) +PARTITION BY RANGE COLUMNS (c1, c2) +INTERVAL 1 Day +( +PARTITION p0 VALUES LESS THAN ('2026-04-01', '2026-04-01') +); +ERROR HY000: Too many fields in 'range interval partition fields' +create table t1 (c datetime) +PARTITION BY LIST COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p0 VALUES IN ('2026-04-01') +); +ERROR HY000: LIST partition type does not support INTERVAL +create table t1 (c int) +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p0 VALUES LESS THAN (740072) +); +ERROR HY000: Field 'c' is of a not allowed type for this type of partitioning +# timestamp is not allowed in range column partitioning +create table t1 (c timestamp) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 minute +( +PARTITION p0 VALUES LESS THAN ('2026-05-05') +); +ERROR HY000: Field 'c' is of a not allowed type for this type of partitioning +# year is not allowed in range column partitioning +create table t1 (c year) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 minute +( +PARTITION p0 VALUES LESS THAN ('2025') +); +ERROR HY000: Field 'c' is of a not allowed type for this type of partitioning +# interval less than a day for date column +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 23.59 HOUR_MINUTE +( +PARTITION p0 VALUES LESS THAN ('2026-04-20') +); +ERROR HY000: RANGE COLUMN partition by a DATE with INTERVAL smaller than date +# bad interval values +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL -1 Day +( +PARTITION p0 VALUES LESS THAN ('2026-04-20') +); +ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for 'INTERVAL' +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 0 Day +( +PARTITION p0 VALUES LESS THAN ('2026-04-20') +); +ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for 'INTERVAL' +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1.1 SECOND_MICROSECOND +( +PARTITION p0 VALUES LESS THAN ('2026-04-20') +); +ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for 'INTERVAL' +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( +PARTITION p1 VALUES LESS THAN ('2026-04-01'), +PARTITION p0 VALUES LESS THAN MAXVALUE +); +ERROR HY000: MAXVALUE is not allowed in range partitioning with interval +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Second +( +PARTITION p1 VALUES LESS THAN ('2026-04-01') +); +insert into t1 values ('2026-01-01'); +ERROR HY000: Too many partitions (including subpartitions) were defined +drop table t1; diff --git a/mysql-test/main/partition_range_interval.test b/mysql-test/main/partition_range_interval.test new file mode 100644 index 0000000000000..9100a78ef196e --- /dev/null +++ b/mysql-test/main/partition_range_interval.test @@ -0,0 +1,412 @@ +--source include/have_partition.inc +--source include/have_innodb.inc +--source include/have_sequence.inc + +--echo # simple case showing partitions added in INSERT +set timestamp= unix_timestamp('2026-05-02 00:00:00'); + +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p0 VALUES LESS THAN ('2026-04-20') +); + +show create table t1; +insert into t1 values ('2026-05-01'); +select * from t1; +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; + +set timestamp= unix_timestamp('2026-05-06 00:00:00'); + +insert into t1 values ('2026-05-04'); +select * from t1; +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; + +drop table t1; + +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 DAY AUTO +( + PARTITION p0 VALUES LESS THAN ('2026-04-30') +); +show create table t1; +insert into t1 values ('2026-05-01'); +select * from t1; +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +drop table t1; + +--echo # 1.5 day interval truncated to +1d, +2d, +1d, +2d, ... +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 36 Hour +( + PARTITION p0 VALUES LESS THAN ('2026-04-30') +); +show create table t1; +insert into t1 values ('2026-05-01'); +select * from t1; +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +drop table t1; + +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Week +( + PARTITION p0 VALUES LESS THAN ('2026-04-20') +); +show create table t1; +insert into t1 values ('2026-05-01'); +select * from t1; +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +drop table t1; + +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 hour +( + PARTITION p0 VALUES LESS THAN ('2026-05-05') +); +show create table t1; +insert into t1 values ('2026-05-05 03:00:00'); +select * from t1; +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +drop table t1; + + +--echo # more than 1 starting partition +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p0 VALUES LESS THAN ('2026-04-20'), + PARTITION p1 VALUES LESS THAN ('2026-04-25') +); + +show create table t1; +insert into t1 values ('2026-05-01'); +select * from t1; +show create table t1; +drop table t1; + +--echo # no need to create new partition when existing ones are sufficient +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p0 VALUES LESS THAN ('2026-04-01'), + PARTITION p1 VALUES LESS THAN ('2026-05-06') +); + +show create table t1; +insert into t1 values ('2026-05-01'); +select * from t1; +show create table t1; +drop table t1; + +--echo # find a gap big enough for names of 10 new partition names +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p9 VALUES LESS THAN ('2026-04-01'), + PARTITION p29 VALUES LESS THAN ('2026-04-04'), + PARTITION p19 VALUES LESS THAN ('2026-04-23'), + PARTITION p40 VALUES LESS THAN ('2026-04-27') +); + +show create table t1; +insert into t1 values ('2026-05-01'); +select * from t1; +show create table t1; +drop table t1; + +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p40 VALUES LESS THAN ('2026-04-27') +); + +show create table t1; +insert into t1 values ('2026-05-01'); +select * from t1; +show create table t1; +drop table t1; + +--echo # CREATE TABLE ... SELECT +--echo # does not work probably because of MDEV-29769 +select to_days('2026-04-01') = 740072; +select to_days('2026-05-01') = 740102; + +--echo # somehow ps protocol has different results +--disable_ps_protocol +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p0 VALUES LESS THAN ('2026-04-01') +) +select from_days(seq) as c from seq_740073_to_740102; +--enable_ps_protocol +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +drop table t1; + +--echo # INSERT ... SELECT +select to_days('2026-04-01') = 740072; +select to_days('2026-05-01') = 740102; + +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p0 VALUES LESS THAN ('2026-04-01') +); +insert into t1 select from_days(seq) from seq_740073_to_740102; +select * from t1; +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +drop table t1; + +select to_days('2026-05-01') = 740102; +select to_days('2026-05-08') = 740109; + +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p0 VALUES LESS THAN ('2026-04-01') +); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +insert into t1 select from_days(seq) from seq_740102_to_740109; +select * from t1; +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1' and table_rows > 0; +drop table t1; + +--echo # LOAD DATA INFILE +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p0 VALUES LESS THAN ('2026-04-20') +); + +--let $mysqld_datadir= `select @@datadir` +--write_file $mysqld_datadir/test/load.data +2026-05-01 +2026-05-02 +2026-05-03 +2026-05-04 +2026-05-05 +EOF +load data infile 'load.data' ignore into table t1; +--remove_file $mysqld_datadir/test/load.data +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1' and table_rows > 0; +drop table t1; + +--echo # LOAD DATA INFILE is not atomic +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p0 VALUES LESS THAN ('2026-04-20') +); + +--let $mysqld_datadir= `select @@datadir` +--write_file $mysqld_datadir/test/load.data +2026-05-05 +2026-05-06 +2026-05-07 +2026-05-08 +EOF +load data infile 'load.data' ignore into table t1; +--remove_file $mysqld_datadir/test/load.data +select * from t1; +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1' and table_rows > 0; +drop table t1; + +--echo # UPDATE +set timestamp= unix_timestamp('2026-05-02 00:00:00'); +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p0 VALUES LESS THAN ('2026-04-25') +); + +insert into t1 values ('2026-04-28'), ('2026-04-29'), ('2026-04-30'); +select * from t1; +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1' and table_rows > 0; +set timestamp= unix_timestamp('2026-05-06 00:00:00'); +update t1 set c = date_add(c, interval 6 day); +select * from t1; +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1' and table_rows > 0; +set timestamp= unix_timestamp('2026-05-08 00:00:00'); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +update t1 set c = date_add(c, interval 3 day); +select * from t1; +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1' and table_rows > 0; +set timestamp= unix_timestamp('2026-05-06 00:00:00'); +drop table t1; + +--echo # ALTER TABLE +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +( + PARTITION p0 VALUES LESS THAN ('2026-04-25') +); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +insert into t1 values ('2026-05-01'); +ALTER TABLE t1 PARTITION BY RANGE COLUMNS (c) INTERVAL 1 DAY +( + PARTITION p0 VALUES LESS THAN ('2026-04-25') +); +insert into t1 values ('2026-05-01'); +SELECT * FROM t1; +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1' and table_rows > 0; +drop table t1; + +--echo # failing insertion of dates in the future +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p0 VALUES LESS THAN ('2026-04-01') +); + +show create table t1; +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +insert into t1 values ('2026-05-07'); +show create table t1; +drop table t1; + +--echo # passthrough behaviour +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p0 VALUES LESS THAN ('2026-04-01') +); +show create table t1; +begin; +insert into t1 values ('2026-05-01'); +insert into t1 values ('2026-05-02'); +select * from t1; +rollback; +select * from t1; +show create table t1; +select partition_name, partition_method, partition_expression, partition_description, table_rows from information_schema.partitions where table_name='t1'; +drop table t1; + +--echo # failures + +--error ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR +create table t1 (c1 datetime, c2 datetime) +PARTITION BY RANGE COLUMNS (c1, c2) +INTERVAL 1 Day +( + PARTITION p0 VALUES LESS THAN ('2026-04-01', '2026-04-01') +); + +--error ER_PARTITION_INTERVAL_NOT_LIST +create table t1 (c datetime) +PARTITION BY LIST COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p0 VALUES IN ('2026-04-01') +); + +--error ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD +create table t1 (c int) +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p0 VALUES LESS THAN (740072) +); + +--echo # timestamp is not allowed in range column partitioning +--error ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD +create table t1 (c timestamp) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 minute +( + PARTITION p0 VALUES LESS THAN ('2026-05-05') +); + +--echo # year is not allowed in range column partitioning +--error ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD +create table t1 (c year) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 minute +( + PARTITION p0 VALUES LESS THAN ('2025') +); + +# TODO: somehow 23.59.59 HOUR_SECOND causes parsing error +--echo # interval less than a day for date column +--error ER_PARTITION_INTERVAL_FINER_THAN_DATE +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 23.59 HOUR_MINUTE +( + PARTITION p0 VALUES LESS THAN ('2026-04-20') +); + +--echo # bad interval values +--error ER_PART_WRONG_VALUE +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL -1 Day +( + PARTITION p0 VALUES LESS THAN ('2026-04-20') +); + +--error ER_PART_WRONG_VALUE +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 0 Day +( + PARTITION p0 VALUES LESS THAN ('2026-04-20') +); + +--error ER_PART_WRONG_VALUE +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1.1 SECOND_MICROSECOND +( + PARTITION p0 VALUES LESS THAN ('2026-04-20') +); + +--error ER_PARTITION_INTERVAL_MAXVALUE +create table t1 (c date) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Day +( + PARTITION p1 VALUES LESS THAN ('2026-04-01'), + PARTITION p0 VALUES LESS THAN MAXVALUE +); + +create table t1 (c datetime) engine=innodb +PARTITION BY RANGE COLUMNS (c) +INTERVAL 1 Second +( + PARTITION p1 VALUES LESS THAN ('2026-04-01') +); +--error ER_TOO_MANY_PARTITIONS_ERROR +insert into t1 values ('2026-01-01'); +drop table t1; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index a6320dc489dd9..a112f93052b6d 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -400,7 +400,7 @@ bool partition_info::set_up_default_partitions(THD *thd, handler *file, num_parts= 2; use_default_num_partitions= false; } - else if (part_type != HASH_PARTITION) + else if (part_type != HASH_PARTITION && !is_range_interval()) { const char *error_string; if (part_type == RANGE_PARTITION) @@ -891,6 +891,34 @@ bool partition_info::vers_set_hist_part(THD *thd, uint *create_count) return false; } +/* + Determine the number of range interval partitions to create, like + partition_info::vers_set_hist_part. +*/ +bool partition_info::range_interval_set_count(THD* thd, uint *create_count) +{ + partition_element *el= partitions.elem(partitions.elements - 1); + Item *item= el->get_col_val(0).item_expression; + MYSQL_TIME cur_time, end_time; + thd->variables.time_zone->gmt_sec_to_TIME(&end_time, thd->query_start()); + longlong cur= item->val_datetime_packed(thd); + unpack_time(cur, &cur_time, MYSQL_TIMESTAMP_DATETIME); + longlong end= pack_time(&end_time); + *create_count= 0; + while (cur <= end) + { + if (date_add_interval(thd, &cur_time, int_type, interval)) + return true; + cur= pack_time(&cur_time); + ++*create_count; + if (*create_count == MAX_PARTITIONS - partitions.elements + 1) + { + my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0)); + return true; + } + } + return false; +} /** @brief Run fast_alter_partition_table() to add new history partitions @@ -1014,6 +1042,101 @@ bool vers_create_partitions(THD *thd, TABLE_LIST* tl, uint num_parts) return result; } +/* + similar to vers_create_partitions, create range interval partitions +*/ +bool range_interval_create_partitions(THD* thd, TABLE_LIST* tl, uint num_parts) +{ + bool result= true; + Table_specification_st create_info; + Alter_info alter_info; + TABLE *table= tl->table; + /* TODO: this may still trigger MSAN unitialised? */ + bool save_no_write_to_binlog= thd->lex->no_write_to_binlog; + thd->lex->no_write_to_binlog= true; + + DBUG_ASSERT(!thd->is_error()); + DBUG_ASSERT(num_parts); + + { + alter_info.reset(); + alter_info.partition_flags= ALTER_PARTITION_ADD; + create_info.init(); + create_info.alter_info= &alter_info; + Alter_table_ctx alter_ctx(thd, tl, 1, &table->s->db, &table->s->table_name); + + MDL_REQUEST_INIT(&tl->mdl_request, MDL_key::TABLE, tl->db.str, + tl->table_name.str, MDL_SHARED_NO_WRITE, MDL_TRANSACTION); + if (thd->mdl_context.acquire_lock(&tl->mdl_request, + thd->variables.lock_wait_timeout)) + goto exit; + table->mdl_ticket= tl->mdl_request.ticket; + + create_info.db_type= table->s->db_type(); + DBUG_ASSERT(create_info.db_type); + + partition_info *part_info= new partition_info(); + if (unlikely(!part_info)) + { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + goto exit; + } + part_info->use_default_num_partitions= false; + part_info->use_default_num_subpartitions= false; + part_info->num_parts= num_parts; + part_info->num_subparts= table->part_info->num_subparts; + part_info->subpart_type= table->part_info->subpart_type; + part_info->num_columns= table->part_info->num_columns; + part_info->part_type= RANGE_PARTITION; + /* for partition_info::fix_parser_data to exit early */ + part_info->int_type= table->part_info->int_type; + + thd->work_part_info= part_info; + bool partition_changed= false; + bool fast_alter_partition= false; + if (prep_alter_part_table(thd, table, &alter_info, &create_info, + &partition_changed, &fast_alter_partition)) + { + my_error(ER_INTERNAL_ERROR, MYF(ME_WARNING), + tl->db.str, tl->table_name.str); + goto exit; + } + if (!fast_alter_partition) + { + my_error(ER_INTERNAL_ERROR, MYF(ME_WARNING), + tl->db.str, tl->table_name.str); + goto exit; + } + DBUG_ASSERT(partition_changed); + if (mysql_prepare_alter_table(thd, table, &create_info, &alter_info, + &alter_ctx)) + { + my_error(ER_INTERNAL_ERROR, MYF(ME_WARNING), + tl->db.str, tl->table_name.str); + goto exit; + } + + alter_info.db= alter_ctx.db; + alter_info.table_name= alter_ctx.table_name; + if (fast_alter_partition_table(thd, table, &alter_info, &alter_ctx, + &create_info, tl)) + { + my_error(ER_INTERNAL_ERROR, MYF(ME_WARNING), + tl->db.str, tl->table_name.str); + goto exit; + } + } + + result= false; + // NOTE: we have to return DA_EMPTY for new command + DBUG_ASSERT(thd->get_stmt_da()->is_ok()); + thd->get_stmt_da()->reset_diagnostics_area(); + thd->variables.option_bits|= OPTION_BINLOG_THIS; + +exit: + thd->lex->no_write_to_binlog= save_no_write_to_binlog; + return result; +} /** Warn at the end of DML command if the last history partition is out of LIMIT. @@ -2320,6 +2443,7 @@ bool partition_info::fix_parser_data(THD *thd) partition_element *part_elem; uint num_elements; uint i= 0, j, k; + int sql_command= thd_sql_command(thd); DBUG_ENTER("partition_info::fix_parser_data"); if (!(part_type == RANGE_PARTITION || @@ -2334,13 +2458,25 @@ bool partition_info::fix_parser_data(THD *thd) DBUG_RETURN(true); } /* If not set, use DEFAULT = 2 for CREATE and ALTER! */ - if ((thd_sql_command(thd) == SQLCOM_CREATE_TABLE || - thd_sql_command(thd) == SQLCOM_ALTER_TABLE) && + if ((sql_command == SQLCOM_CREATE_TABLE || + sql_command == SQLCOM_ALTER_TABLE) && key_algorithm == KEY_ALGORITHM_NONE) key_algorithm= KEY_ALGORITHM_55; } DBUG_RETURN(FALSE); } + /* + TODO(MDEV-15621): we exit here for range interval partitions + because if this is called from prep_alter_part_table then + partition data is not calculated (in + check_range_interval_constants) yet. But maybe we shouldn't exit + here in user CREATE/ALTER TABLE statements for other checks. + */ + if (sql_command != SQLCOM_CREATE_TABLE && + sql_command != SQLCOM_ALTER_TABLE && is_range_interval()) + { + DBUG_RETURN(FALSE); + } if (is_sub_partitioned() && list_of_subpart_fields) { /* KEY subpartitioning, check ALGORITHM = N. Should not pass the parser! */ @@ -2785,6 +2921,21 @@ bool partition_info::vers_init_info(THD * thd) return false; } +bool partition_info::set_interval(THD* thd, Item* ival, interval_type type, + const char *table_name) +{ + bool error= get_interval_value(thd, ival, type, &interval) || + interval.neg || interval.second_part || + !(interval.year || interval.month || interval.day || interval.hour || + interval.minute || interval.second); + if (error) + { + my_error(ER_PART_WRONG_VALUE, MYF(0), table_name, "INTERVAL"); + return true; + } + int_type= type; + return false; +} /** Assign INTERVAL and STARTS for SYSTEM_TIME partitions. diff --git a/sql/partition_info.h b/sql/partition_info.h index e25e27860c966..9df273f196407 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -207,6 +207,10 @@ class partition_info : public DDL_LOG_STATE, public Sql_alloc part_column_list_val *list_col_array; }; + /* TODO: change to pointer */ + INTERVAL interval; + enum interval_type int_type; + Vers_part_info *vers_info; /******************************************** @@ -319,7 +323,7 @@ class partition_info : public DDL_LOG_STATE, public Sql_alloc restore_part_field_ptrs(NULL), restore_subpart_field_ptrs(NULL), part_expr(NULL), subpart_expr(NULL), item_free_list(NULL), bitmaps_are_initialized(FALSE), - list_array(NULL), vers_info(NULL), err_value(0), + list_array(NULL), int_type(INTERVAL_LAST), vers_info(NULL), err_value(0), part_info_string(NULL), curr_part_elem(NULL), current_partition(NULL), curr_list_object(0), num_columns(0), table(NULL), @@ -417,11 +421,14 @@ class partition_info : public DDL_LOG_STATE, public Sql_alloc bool field_in_partition_expr(Field *field) const; bool vers_init_info(THD *thd); + bool set_interval(THD* thd, Item* ival, interval_type type, + const char *table_name); bool vers_set_interval(THD *thd, Item *interval, interval_type int_type, Item *starts, bool auto_part, const char *table_name); bool vers_set_limit(ulonglong limit, bool auto_part, const char *table_name); bool vers_set_hist_part(THD* thd, uint *create_count); + bool range_interval_set_count(THD* thd, uint *create_count); bool vers_require_hist_part(THD *thd) const { return part_type == VERSIONING_PARTITION && @@ -430,6 +437,9 @@ class partition_info : public DDL_LOG_STATE, public Sql_alloc void vers_check_limit(THD *thd); bool vers_fix_field_list(THD *thd); void vers_update_el_ids(); + /* TODO(MDEV-15621): change to a new RANGE_INTERVAL_PARTITION part type */ + bool is_range_interval() const + { return int_type != INTERVAL_LAST && part_type == RANGE_PARTITION; } partition_element *get_partition(uint part_id) { List_iterator it(partitions); @@ -452,6 +462,7 @@ void part_type_error(THD *thd, partition_info *work_part_info, uint32 get_next_partition_id_range(struct st_partition_iter* part_iter); bool check_partition_dirs(partition_info *part_info); bool vers_create_partitions(THD* thd, TABLE_LIST* tl, uint num_parts); +bool range_interval_create_partitions(THD* thd, TABLE_LIST* tl, uint num_parts); /* Initialize the iterator to return a single partition with given part_id */ @@ -549,12 +560,12 @@ Lex_ident_partition make_partition_name(char *move_ptr, uint i) inline uint partition_info::next_part_no(uint new_parts) const { - if (part_type != VERSIONING_PARTITION) + if (part_type != VERSIONING_PARTITION && !is_range_interval()) return num_parts; DBUG_ASSERT(new_parts > 0); /* Choose first non-occupied name suffix */ - uint32 suffix= num_parts - 1; - DBUG_ASSERT(suffix > 0); + uint32 suffix= part_type == VERSIONING_PARTITION ? num_parts - 1 : 0; + DBUG_ASSERT(suffix > 0 || part_type != VERSIONING_PARTITION); char part_name[MAX_PART_NAME_SIZE + 1]; List_iterator_fast it(table->part_info->partitions); for (uint cur_part= 0; cur_part < new_parts; ++cur_part, ++suffix) diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 884fc75c91379..2b675fd3bd186 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -12404,3 +12404,9 @@ ER_WARN_QB_NAME_PATH_VIEW_NOT_FOUND eng "Hint %s is ignored. `%s` required at element #%u of the path is not found in the target query block." ER_WARN_QB_NAME_PATH_NOT_SUPPORTED_INSIDE_VIEW eng "Hint %s is ignored. QB_NAME hints with path are not supported inside view definitions." +ER_PARTITION_INTERVAL_NOT_LIST + eng "LIST partition type does not support INTERVAL" +ER_PARTITION_INTERVAL_FINER_THAN_DATE + eng "RANGE COLUMN partition by a DATE with INTERVAL smaller than date" +ER_PARTITION_INTERVAL_MAXVALUE + eng "MAXVALUE is not allowed in range partitioning with interval" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 95abfa798bf65..18b37a2a9ea43 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1929,6 +1929,40 @@ bool TABLE::vers_switch_partition(THD *thd, TABLE_LIST *table_list, return false; } + +/* + TODO(MDEV-15621): similar to vers_switch_partition, find how many + partitions to create and calls oc_ctx->request_backoff_action for + actions to take when failing opening_and_process_table +*/ +bool TABLE::range_interval_check_partition(THD *thd, TABLE_LIST *table_list, + Open_table_context *ot_ctx) +{ + if (!part_info || !part_info->is_range_interval() || + table_list->mdl_request.type == MDL_EXCLUSIVE) + return false; + switch (thd->lex->sql_command) + { + case SQLCOM_INSERT_SELECT: + case SQLCOM_INSERT: + case SQLCOM_LOAD: + case SQLCOM_UPDATE: + case SQLCOM_REPLACE: + case SQLCOM_REPLACE_SELECT: + case SQLCOM_UPDATE_MULTI: + break; + default: + return false; + } + if (part_info->range_interval_set_count( + thd, &ot_ctx->range_interval_create_count)) + return true; + if (ot_ctx->range_interval_create_count == 0) + return false; + ot_ctx->request_backoff_action( + Open_table_context::OT_ADD_RANGE_INTERVAL_PARTITION, table_list); + return true; +} #endif /* WITH_PARTITION_STORAGE_ENGINE */ @@ -2355,7 +2389,9 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx) #ifdef WITH_PARTITION_STORAGE_ENGINE if (!part_names_error && - table->vers_switch_partition(thd, table_list, ot_ctx)) + (table->vers_switch_partition(thd, table_list, ot_ctx) || + table->range_interval_check_partition(thd, table_list, ot_ctx)) + ) { MYSQL_UNBIND_TABLE(table->file); tc_release_table(table); @@ -3479,7 +3515,8 @@ request_backoff_action(enum_open_table_action action_arg, if (table) { DBUG_ASSERT(action_arg == OT_DISCOVER || action_arg == OT_REPAIR || - action_arg == OT_ADD_HISTORY_PARTITION); + action_arg == OT_ADD_HISTORY_PARTITION || + action_arg == OT_ADD_RANGE_INTERVAL_PARTITION); m_failed_table= m_thd->alloc(1); if (m_failed_table == NULL) return TRUE; @@ -3547,6 +3584,7 @@ Open_table_context::recover_from_failed_open() break; case OT_DISCOVER: case OT_REPAIR: + case OT_ADD_RANGE_INTERVAL_PARTITION: case OT_ADD_HISTORY_PARTITION: DEBUG_SYNC(m_thd, "add_history_partition"); if (!m_thd->locked_tables_mode) @@ -3588,7 +3626,8 @@ Open_table_context::recover_from_failed_open() We don't need to remove share under OT_ADD_HISTORY_PARTITION. Moreover fast_alter_partition_table() works with TABLE instance. */ - if (m_action != OT_ADD_HISTORY_PARTITION) + if (m_action != OT_ADD_HISTORY_PARTITION && + m_action != OT_ADD_RANGE_INTERVAL_PARTITION) tdc_remove_table(m_thd, m_failed_table->db.str, m_failed_table->table_name.str); @@ -3618,6 +3657,77 @@ Open_table_context::recover_from_failed_open() case OT_REPAIR: result= auto_repair_table(m_thd, m_failed_table); break; + case OT_ADD_RANGE_INTERVAL_PARTITION: +#ifdef WITH_PARTITION_STORAGE_ENGINE + { + result= false; + TABLE *table= open_ltable(m_thd, m_failed_table, TL_WRITE, + MYSQL_OPEN_HAS_MDL_LOCK | MYSQL_OPEN_IGNORE_LOGGING_FORMAT); + if (table == NULL) + { + m_thd->clear_error(); + break; + } + + DBUG_ASSERT(range_interval_create_count); + result= range_interval_create_partitions( + m_thd, m_failed_table, range_interval_create_count); + range_interval_create_count= 0; + if (!m_thd->transaction->stmt.is_empty()) + trans_commit_stmt(m_thd); + DBUG_ASSERT(!result || + !m_thd->locked_tables_mode || + m_thd->lock->lock_count); + if (result) + break; + if (!m_thd->locked_tables_mode) + { + /* + alter_partition_lock_handling() does mysql_lock_remove() but + does not clear thd->lock completely. + */ + DBUG_ASSERT(m_thd->lock->lock_count == 0); + if (!(m_thd->lock->flags & GET_LOCK_ON_THD)) + my_free(m_thd->lock); + m_thd->lock= NULL; + } + /* + TODO(MDEV-15621): here I just copied code from + OT_ADD_HISTORY_PARTITION + */ + else if (m_thd->locked_tables_mode == LTM_PRELOCKED) + { + MYSQL_LOCK *lock; + MYSQL_LOCK *merged_lock; + + /* + In LTM_LOCK_TABLES table was reopened via locked_tables_list, + but not in prelocked environment where we have to reopen + the table manually. + */ + Open_table_context ot_ctx(m_thd, MYSQL_OPEN_REOPEN); + if (open_table(m_thd, m_failed_table, &ot_ctx)) + { + result= true; + break; + } + TABLE *table= m_failed_table->table; + table->reginfo.lock_type= m_thd->update_lock_default; + m_thd->in_lock_tables= 1; + lock= mysql_lock_tables(m_thd, &table, 1, + MYSQL_OPEN_REOPEN | MYSQL_LOCK_USE_MALLOC); + m_thd->in_lock_tables= 0; + if (lock == NULL || + !(merged_lock= mysql_lock_merge(m_thd->lock, lock, m_thd))) + { + result= true; + break; + } + m_thd->lock= merged_lock; + } + break; + } +#endif case OT_ADD_HISTORY_PARTITION: #ifdef WITH_PARTITION_STORAGE_ENGINE { diff --git a/sql/sql_base.h b/sql/sql_base.h index 32985f319fa07..12e2579a5e442 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -569,7 +569,8 @@ class Open_table_context OT_REOPEN_TABLES, OT_DISCOVER, OT_REPAIR, - OT_ADD_HISTORY_PARTITION + OT_ADD_HISTORY_PARTITION, + OT_ADD_RANGE_INTERVAL_PARTITION }; Open_table_context(THD *thd, uint flags); @@ -645,6 +646,7 @@ class Open_table_context public: uint vers_create_count; + uint range_interval_create_count; }; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index d676a022c1274..ec322d19aba09 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1248,6 +1248,97 @@ int partition_info_compare_column_values(const void *first_arg, return 0; } +static bool check_range_interval_constants(THD *thd, partition_info *part_info) +{ + /* Range interval is only supported in RANGE COLUMNS with one column */ + DBUG_ASSERT(part_info->column_list); + DBUG_ASSERT(part_info->part_field_list.elements == 1); + List_iterator part_it(part_info->partitions); + partition_element *el; + uint part_id= 0; + int warn; + /* Find the first partition to auto-add */ + while ((el= part_it++) && el->part_state == PART_NORMAL) + { + part_id++; + } + /* No partition to auto-add. Could be CREATE TABLE */ + if (!el) + return FALSE; + /* + We are in a DML where partitions need to be created. There + should already be some existing partitions + */ + DBUG_ASSERT(part_id != 0); + longlong packed= part_info->partitions.elem(part_id - 1)->get_col_val(0).item_expression->val_datetime_packed(thd); + MYSQL_TIME ltime; + unpack_time(packed, <ime, MYSQL_TIMESTAMP_DATETIME); + do + { + if (date_add_interval(thd, <ime, part_info->int_type, part_info->interval)) + { + my_error(ER_DATA_OUT_OF_RANGE, MYF(0), "DATETIME", "INTERVAL"); + return TRUE; + } + Datetime dt(thd, &warn, <ime, Datetime::Options(thd), 0); + Date d(static_cast(&dt)); + Item *column_item; + switch (part_info->part_field_array[0]->type()) + { + case MYSQL_TYPE_DATE: + column_item= new (thd->mem_root) Item_date_literal(thd, &d); + break; + case MYSQL_TYPE_DATETIME: + column_item= new (thd->mem_root) Item_datetime_literal(thd, &dt, 0); + break; + default: + /* Only DATE and DATETIME are allowed */ + DBUG_ASSERT(0); + return TRUE; + } + p_elem_val *range_val= new p_elem_val; + el->list_val_list.push_back(range_val); + part_column_list_val *col_val= new part_column_list_val; + range_val->col_val_array= col_val; + col_val->item_expression= column_item; + col_val->max_value= false; + col_val->null_value= false; + + /* + Similar to partition_info::fix_column_value_functions, but with a + hack on field->table->write_set to pass the assertion of + marked_for_write_or_computed() in + Field_date_common::store_TIME_with_warning + */ + Field *field= part_info->part_field_array[0]; + col_val->part_info= part_info; + col_val->partition_id= part_id; + uchar *val_ptr; + uint len= field->pack_length(); + + Sql_mode_instant_set sms(thd, 0); + /* Needed to pass assertion on Field::marked_for_write_or_computed() */ + MY_BITMAP *save_write_set= field->table->write_set; + field->table->write_set= &field->table->s->all_set; + bool save_got_warning= thd->got_warning; + thd->got_warning= FALSE; + if (column_item->save_in_field(field, TRUE) || thd->got_warning) + { + my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0)); + return TRUE; + } + thd->got_warning= save_got_warning; + field->table->write_set= save_write_set; + if (!(val_ptr= (uchar*) thd->memdup(field->ptr, len))) + { + return TRUE; + } + col_val->column_value= val_ptr; + col_val->fixed= TRUE; + part_id++; + } while ((el= part_it++)); + return FALSE; +} /* This routine allocates an array for all range constants to achieve a fast @@ -1281,6 +1372,9 @@ static bool check_range_constants(THD *thd, partition_info *part_info) DBUG_PRINT("enter", ("RANGE with %d parts, column_list = %u", part_info->num_parts, part_info->column_list)); + if (part_info->is_range_interval()) + if (check_range_interval_constants(thd, part_info)) + goto end; if (part_info->column_list) { part_column_list_val *loc_range_col_array; @@ -2324,6 +2418,32 @@ static int add_column_list_values(String *str, partition_info *part_info, return 1; } th= sql_field->type_handler(); + enum_field_types ftype= th->real_field_type(); + /* + Only allow DATETIME and DATE, since TIMESTAMP and YEAR + are already not allowed in range column partitioning + */ + if (part_info->is_range_interval()) + { + if (ftype != MYSQL_TYPE_DATETIME2 && ftype != MYSQL_TYPE_NEWDATE) + { + th->partition_field_type_not_allowed(sql_field->field_name); + return 1; + } + if (ftype == MYSQL_TYPE_NEWDATE) + { + MYSQL_TIME t1= {1, 1, 1, 0, 0, 0, 0, 0, MYSQL_TIMESTAMP_DATE}, + t2= t1; + t1.day++; + date_add_interval(current_thd, &t2, part_info->int_type, + part_info->interval); + if (pack_time(&t1) > pack_time(&t2)) + { + my_error(ER_PARTITION_INTERVAL_FINER_THAN_DATE, MYF(0)); + return 1; + } + } + } if (th->partition_field_check(sql_field->field_name, item_expr)) return 1; field_cs= sql_field->explicit_or_derived_charset(&derived_attr); @@ -2673,6 +2793,13 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info, part_info->part_expr->print_for_table_def(&str); err+= str.append(')'); } + else if (part_info->is_range_interval()) + { + err+= str.append(STRING_WITH_LEN(" COLUMNS")); + err+= add_part_field_list(thd, &str, part_info->part_field_list); + err+= str.append(STRING_WITH_LEN("INTERVAL ")); + err+= append_interval(&str, part_info->int_type, part_info->interval); + } else if (part_info->column_list) { err+= str.append(STRING_WITH_LEN(" COLUMNS")); @@ -5251,7 +5378,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, */ if (thd->lex->no_write_to_binlog && tab_part_info->part_type != HASH_PARTITION && - tab_part_info->part_type != VERSIONING_PARTITION) + tab_part_info->part_type != VERSIONING_PARTITION && + !tab_part_info->is_range_interval()) { my_error(ER_NO_BINLOG_ERROR, MYF(0)); goto err; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 269d497058c2f..c1bd8cd435778 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5111,7 +5111,11 @@ part_type_def: Select->parsing_place= NO_MATTER; } | LIST_SYM part_column_list - { Lex->part_info->part_type= LIST_PARTITION; } + { + Lex->part_info->part_type= LIST_PARTITION; + if (Lex->part_info->int_type != INTERVAL_LAST) + my_yyabort_error((ER_PARTITION_INTERVAL_NOT_LIST, MYF(0))); + } | SYSTEM_TIME_SYM { if (unlikely(Lex->part_info->vers_init_info(thd))) @@ -5179,14 +5183,29 @@ part_field_item: ; part_column_list: - COLUMNS '(' part_field_list ')' + COLUMNS '(' part_field_list ')' opt_part_interval { partition_info *part_info= Lex->part_info; part_info->column_list= TRUE; part_info->list_of_part_fields= TRUE; + if (part_info->int_type != INTERVAL_LAST && + part_info->num_columns > 1) + my_yyabort_error((ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), + "range interval partition fields")); } ; +opt_part_interval: + /* empty */ {} + | INTERVAL_SYM expr interval opt_auto + { + partition_info *part_info= Lex->part_info; + const char *table_name= + Lex->create_last_non_select_table->table_name.str; + if (unlikely(part_info->set_interval(thd, $2, $3, table_name))) + MYSQL_YYABORT; + } + ; part_func: '(' part_func_expr ')' @@ -5448,6 +5467,11 @@ part_func_max: thd->parse_error(ER_PARTITION_COLUMN_LIST_ERROR); MYSQL_YYABORT; } + else if (part_info->is_range_interval()) + { + my_error(ER_PARTITION_INTERVAL_MAXVALUE, MYF(0)); + MYSQL_YYABORT; + } else part_info->num_columns= 1U; if (unlikely(part_info->init_column_part(thd))) @@ -5757,6 +5781,12 @@ opt_vers_auto_part: $$= 1; } ; + +opt_auto: + /* empty */ {} + | AUTO_SYM {} + ; + /* End of partition parser part */ diff --git a/sql/table.h b/sql/table.h index 0713341840127..47ee067660051 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2023,6 +2023,8 @@ struct TABLE #ifdef WITH_PARTITION_STORAGE_ENGINE bool vers_switch_partition(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx); + bool range_interval_check_partition(THD *thd, TABLE_LIST *table_list, + Open_table_context *ot_ctx); #endif bool vers_implicit() const;