← Back to team overview

maria-developers team mailing list archive

Re: 9941c6a3179: MDEV-17554 Auto-create new partition for system versioned tables with history partitioned by INTERVAL/LIMIT

 

Hi, Aleksey!

On Apr 07, Aleksey Midenkov wrote:
> revision-id: 9941c6a3179 (mariadb-10.5.2-164-g9941c6a3179)
> parent(s): 920c3c6b237
> author: Aleksey Midenkov <midenok@xxxxxxxxx>
> committer: Aleksey Midenkov <midenok@xxxxxxxxx>
> timestamp: 2020-04-06 08:05:43 +0300
> message:
> 
> MDEV-17554 Auto-create new partition for system versioned tables with history partitioned by INTERVAL/LIMIT

See some comment below, please

> diff --git a/mysql-test/suite/versioning/common.inc b/mysql-test/suite/versioning/common.inc
> index 355b571e5a0..b35a5138015 100644
> --- a/mysql-test/suite/versioning/common.inc
> +++ b/mysql-test/suite/versioning/common.inc
> @@ -6,6 +6,7 @@ if (!$TEST_VERSIONING_SO)
>  source include/have_innodb.inc;
>  
>  set @@session.time_zone='+00:00';
> +set @@global.time_zone='+00:00';

Why is that? I understand you might've needed it when a partition was added
in a separate thread, but why now?

>  select ifnull(max(transaction_id), 0) into @start_trx_id from mysql.transaction_registry;
>  set @test_start=now(6);
>  
> diff --git a/mysql-test/suite/versioning/r/delete_history.result b/mysql-test/suite/versioning/r/delete_history.result
> index cb865a835b3..2e4a2bf9974 100644
> --- a/mysql-test/suite/versioning/r/delete_history.result
> +++ b/mysql-test/suite/versioning/r/delete_history.result
> @@ -154,3 +154,18 @@ select * from t1;
>  a
>  1
>  drop table t1;
> +#
> +# MDEV-17554 Auto-create new partition for system versioned tables with history partitioned by INTERVAL/LIMIT
> +#
> +# Don't auto-create new partition on DELETE HISTORY:
> +create or replace table t (a int) with system versioning
> +partition by system_time limit 1000 auto_increment;

this looks like a hack, I think we need a dedicated syntax for that.
but I couldn't think of anything good now.

ok, I see that you allow both AUTO_INCREMENT and AUTO.
May be better just to use AUTO?

> +delete history from t;
> +show create table t;
> +Table	Create Table
> +t	CREATE TABLE `t` (
> +  `a` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME LIMIT 1000 AUTO_INCREMENT
> +PARTITIONS 2
> +drop table t;
> diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result
> index a7047cbd11b..660d2c81961 100644
> --- a/mysql-test/suite/versioning/r/partition.result
> +++ b/mysql-test/suite/versioning/r/partition.result
> @@ -289,11 +291,27 @@ x
>  6
>  7
>  8
> -## rotation by INTERVAL
> +# Auto-create history partitions
> +create or replace table t1 (x int) with system versioning
> +partition by system_time limit 1000 auto_increment;
> +lock tables t1 write;
> +insert into t1 values (1);
> +update t1 set x= x + 1;
> +unlock tables;
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME LIMIT 1000 AUTO_INCREMENT
> +PARTITIONS 3

this test needs a comment, I don't understand what's happening here.
why lock tables?

> +#
> +# Rotation by INTERVAL
> +#
>  create or replace table t1 (x int)
>  with system versioning
>  partition by system_time interval 0 second partitions 3;
> -ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for 'INTERVAL'
> +ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for INTERVAL
>  create table t1 (i int) with system versioning
>  partition by system_time interval 6 day limit 98;
>  ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'limit 98' at line 2
> @@ -302,7 +320,7 @@ partition by system_time interval 10 year partitions 3;
>  ERROR 22003: TIMESTAMP value is out of range in 'INTERVAL'
>  # INTERVAL and ALTER TABLE
>  create or replace table t1 (i int) with system versioning
> -partition by system_time interval 1 hour;
> +partition by system_time interval 59 minute;

why?

>  set @ts=(select partition_description from information_schema.partitions
>  where table_schema='test' and table_name='t1' and partition_name='p0');
>  alter table t1 add column b int;
> @@ -353,28 +371,51 @@ Warning	4114	Versioned table `test`.`t1`: last HISTORY partition (`p1`) is out o
>  delete from t1;
>  Warnings:
>  Warning	4114	Versioned table `test`.`t1`: last HISTORY partition (`p1`) is out of INTERVAL, need more HISTORY partitions
> -select subpartition_name,partition_description,table_rows from information_schema.partitions where table_schema='test' and table_name='t1';
> +select subpartition_name,partition_description from information_schema.partitions where table_schema='test' and table_name='t1';

why?

> -subpartition_name	partition_description	table_rows
> -p1sp0	2001-02-04 00:00:00	1
> -p1sp1	2001-02-04 00:00:00	1
> -pnsp0	CURRENT	0
> -pnsp1	CURRENT	0
> +subpartition_name	partition_description
> +p1sp0	2001-02-04 00:00:00
> +p1sp1	2001-02-04 00:00:00
> +pnsp0	CURRENT
> +pnsp1	CURRENT
> +select * from t1 partition (p1);
> +i
> +1
> +2
>  set timestamp=unix_timestamp('2001-02-04 10:20:55');
>  alter table t1 add partition (partition p0 history, partition p2 history);
>  set timestamp=unix_timestamp('2001-02-04 10:30:00');
>  insert t1 values (4),(5);
>  set timestamp=unix_timestamp('2001-02-04 10:30:10');
>  update t1 set i=6 where i=5;
> -select subpartition_name,partition_description,table_rows from information_schema.partitions where table_schema='test' and table_name='t1';
> -subpartition_name	partition_description	table_rows
> -p1sp0	2001-02-04 00:00:00	1
> -p1sp1	2001-02-04 00:00:00	0
> -p0sp0	2001-02-05 00:00:00	1
> -p0sp1	2001-02-05 00:00:00	1
> -p2sp0	2001-02-06 00:00:00	0
> -p2sp1	2001-02-06 00:00:00	0
> -pnsp0	CURRENT	0
> -pnsp1	CURRENT	2
> +select subpartition_name, partition_description from information_schema.partitions where table_schema='test' and table_name='t1';
> +subpartition_name	partition_description
> +p1sp0	2001-02-04 00:00:00
> +p1sp1	2001-02-04 00:00:00
> +p0sp0	2001-02-05 00:00:00
> +p0sp1	2001-02-05 00:00:00
> +p2sp0	2001-02-06 00:00:00
> +p2sp1	2001-02-06 00:00:00
> +pnsp0	CURRENT
> +pnsp1	CURRENT
> +select * from t1 partition (p1);
> +i
> +1
> +select * from t1 partition (p0);
> +i
> +5
> +2
> +select * from t1 partition (p2);
> +i
> +alter table t1 rebuild partition p0, p1, p2;
> +select * from t1 partition (p1);
> +i
> +1
> +select * from t1 partition (p0);
> +i
> +5
> +2
> +select * from t1 partition (p2);
> +i
>  ## pruning check
>  set @ts=(select partition_description from information_schema.partitions
>  where table_schema='test' and table_name='t1' and partition_name='p0' limit 1);
> @@ -1044,3 +1085,568 @@ t1	CREATE TABLE `t1` (
>   PARTITION BY SYSTEM_TIME 
>  PARTITIONS 8
>  drop tables t1;
> +#
> +# MDEV-17554 Auto-create new partition for system versioned tables with history partitioned by INTERVAL/LIMIT
> +#
> +create or replace table t1 (x int) with system versioning
> +partition by system_time limit 999 auto_increment;
> +ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for LIMIT (< 1000)
> +create or replace table t1 (x int) with system versioning
> +partition by system_time interval 3599 second auto_increment;
> +ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for INTERVAL (< 1 HOUR)

no arbitrary limitations, please

> +create or replace table t1 (x int) with system versioning
> +partition by system_time limit 1000 auto_increment;
> +affected rows: 0
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME LIMIT 1000 AUTO_INCREMENT
> +PARTITIONS 2
> +affected rows: 1
> +insert into t1 values (1);
> +affected rows: 1
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME LIMIT 1000 AUTO_INCREMENT
> +PARTITIONS 3
> +affected rows: 1
> +# Increment from 2 to 5
> +create or replace table t1 (x int) with system versioning
> +partition by system_time interval 3600 second
> +starts '2000-01-01 00:00:00' auto_increment;
> +affected rows: 0
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 3600 SECOND STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 2
> +affected rows: 1
> +set timestamp= unix_timestamp('2000-01-01 00:00:00');
> +affected rows: 0
> +insert into t1 values (1);
> +affected rows: 1
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 3600 SECOND STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 3
> +affected rows: 1
> +set timestamp= unix_timestamp('2000-01-01 01:00:00');
> +affected rows: 0
> +update t1 set x= x + 1;
> +affected rows: 1
> +info: Rows matched: 1  Changed: 1  Inserted: 1  Warnings: 0
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 3600 SECOND STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 4
> +affected rows: 1
> +set timestamp= unix_timestamp('2000-01-01 02:00:00');
> +affected rows: 0
> +update t1 set x= x + 2;
> +affected rows: 1
> +info: Rows matched: 1  Changed: 1  Inserted: 1  Warnings: 0
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 3600 SECOND STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 5
> +affected rows: 1
> +# Increment from 3 to 6, manual names, LOCK TABLES

again, I think this is overcomplication and overengineering.
I don't see any need for mixing automatic and manual partition names.

> +set timestamp= unix_timestamp('2000-01-01 00:00:00');
> +affected rows: 0
> +create or replace table t1 (x int) with system versioning
> +partition by system_time interval 1 hour auto_increment (
> +partition p1 history,
> +partition p3 history,
> +partition pn current);
> +affected rows: 0
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +(PARTITION `p1` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `p3` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `pn` CURRENT ENGINE = DEFAULT_ENGINE)
> +affected rows: 1
> +insert into t1 values (1);
> +affected rows: 1
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +(PARTITION `p1` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `p3` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `pn` CURRENT ENGINE = DEFAULT_ENGINE)
> +affected rows: 1
> +set timestamp= unix_timestamp('2000-01-01 01:00:00');
> +affected rows: 0
> +update t1 set x= x + 3;
> +affected rows: 1
> +info: Rows matched: 1  Changed: 1  Inserted: 1  Warnings: 0
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +(PARTITION `p1` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `p3` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `p2` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `pn` CURRENT ENGINE = DEFAULT_ENGINE)
> +affected rows: 1
> +set timestamp= unix_timestamp('2000-01-01 02:00:00');
> +affected rows: 0
> +update t1 set x= x + 4;
> +affected rows: 1
> +info: Rows matched: 1  Changed: 1  Inserted: 1  Warnings: 0
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +(PARTITION `p1` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `p3` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `p2` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `p4` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `pn` CURRENT ENGINE = DEFAULT_ENGINE)
> +affected rows: 1
> +lock tables t1 write;
> +affected rows: 0
> +set timestamp= unix_timestamp('2000-01-01 03:00:00');
> +affected rows: 0
> +update t1 set x= x + 5;
> +affected rows: 1
> +info: Rows matched: 1  Changed: 1  Inserted: 1  Warnings: 0
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +(PARTITION `p1` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `p3` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `p2` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `p4` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `p5` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `pn` CURRENT ENGINE = DEFAULT_ENGINE)
> +affected rows: 1
> +unlock tables;
> +affected rows: 0
> +# Test VIEW, LOCK TABLES
> +set timestamp= unix_timestamp('2000-01-01 00:00:00');
> +affected rows: 0
> +create or replace table t1 (x int) with system versioning
> +partition by system_time interval 1 hour auto_increment;
> +affected rows: 0
> +create or replace view v1 as select * from t1;
> +affected rows: 0
> +insert into v1 values (1);
> +affected rows: 1
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 3
> +affected rows: 1
> +lock tables t1 write;
> +affected rows: 0
> +set timestamp= unix_timestamp('2000-01-01 01:00:00');
> +affected rows: 0
> +update t1 set x= x + 3;
> +affected rows: 1
> +info: Rows matched: 1  Changed: 1  Inserted: 1  Warnings: 0
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 4
> +affected rows: 1
> +unlock tables;
> +affected rows: 0
> +drop view v1;
> +affected rows: 0
> +drop tables t1;
> +affected rows: 0
> +# Multiple increments in single command
> +set timestamp= unix_timestamp('2000-01-01 00:00:00');
> +affected rows: 0
> +create or replace table t1 (x int) with system versioning
> +partition by system_time interval 1 hour auto_increment partitions 3;
> +affected rows: 0
> +create or replace table t2 (y int) with system versioning
> +partition by system_time interval 1 hour auto_increment partitions 4;
> +affected rows: 0
> +insert into t1 values (1);
> +affected rows: 1
> +insert into t2 values (2);
> +affected rows: 1
> +set timestamp= unix_timestamp('2000-01-01 01:00:00');
> +affected rows: 0
> +update t1, t2 set x= x + 1, y= y + 1;
> +affected rows: 2
> +info: Rows matched: 2  Changed: 2  Warnings: 0
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 4
> +affected rows: 1
> +show create table t2;
> +Table	Create Table
> +t2	CREATE TABLE `t2` (
> +  `y` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 4
> +affected rows: 1
> +set timestamp= unix_timestamp('2000-01-01 02:00:00');
> +affected rows: 0
> +update t1, t2 set x= x + 1, y= y + 1;
> +affected rows: 2
> +info: Rows matched: 2  Changed: 2  Warnings: 0
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 5
> +affected rows: 1
> +show create table t2;
> +Table	Create Table
> +t2	CREATE TABLE `t2` (
> +  `y` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 5
> +affected rows: 1
> +drop tables t1, t2;
> +affected rows: 0
> +# PS, SP, LOCK TABLES
> +set timestamp= unix_timestamp('2000-01-01 00:00:00');
> +affected rows: 0
> +create or replace table t1 (x int) with system versioning
> +partition by system_time interval 1 hour auto_increment;
> +affected rows: 0
> +execute immediate 'insert into t1 values (1)';
> +affected rows: 1
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 3
> +affected rows: 1
> +prepare s from 'update t1 set x= x + 6';
> +affected rows: 0
> +info: Statement prepared
> +set timestamp= unix_timestamp('2000-01-01 01:00:00');
> +affected rows: 0
> +execute s;
> +affected rows: 1
> +info: Rows matched: 1  Changed: 1  Inserted: 1  Warnings: 0
> +execute s;
> +affected rows: 1
> +info: Rows matched: 1  Changed: 1  Inserted: 1  Warnings: 0
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 4
> +affected rows: 1
> +lock tables t1 write;
> +affected rows: 0
> +set timestamp= unix_timestamp('2000-01-01 02:00:00');
> +affected rows: 0
> +execute s;
> +affected rows: 1
> +info: Rows matched: 1  Changed: 1  Inserted: 1  Warnings: 0
> +execute s;
> +affected rows: 1
> +info: Rows matched: 1  Changed: 1  Inserted: 1  Warnings: 0
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 5

add a test where timestamp is incremented by, say, 24 hours, please

> +affected rows: 1
> +unlock tables;
> +affected rows: 0
> +drop prepare s;
> +affected rows: 0
> +create procedure sp() update t1 set x= x + 7;
> +affected rows: 0
> +set timestamp= unix_timestamp('2000-01-01 03:00:00');
> +affected rows: 0
> +call sp;
> +affected rows: 1
> +call sp;
> +affected rows: 1
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 6
> +affected rows: 1
> +lock tables t1 write;
> +affected rows: 0
> +set timestamp= unix_timestamp('2000-01-01 04:00:00');
> +affected rows: 0
> +call sp;
> +affected rows: 1
> +call sp;
> +affected rows: 1
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 7
> +affected rows: 1
> +unlock tables;
> +affected rows: 0
> +drop procedure sp;
> +affected rows: 0
> +# Complex table
> +set timestamp= unix_timestamp('2000-01-01 00:00:00');
> +affected rows: 0
> +create or replace table t1 (
> +x int primary key auto_increment,
> +t timestamp(6) default '2001-11-11 11:11:11',
> +b blob(4096) compressed null,
> +c varchar(1033) character set utf8 not null,
> +u int unique,
> +m enum('a', 'b', 'c') not null default 'a' comment 'absolute',
> +i1 tinyint, i2 smallint, i3 bigint,
> +index three(i1, i2, i3),
> +v1 timestamp(6) generated always as (t + interval 1 day),
> +v2 timestamp(6) generated always as (t + interval 1 month) stored,
> +s timestamp(6) as row start,
> +e timestamp(6) as row end,
> +period for system_time (s, e),
> +ps date, pe date,
> +period for app_time (ps, pe),
> +constraint check_constr check (u > -1))
> +with system versioning default charset=ucs2
> +partition by system_time interval 1 hour auto_increment (
> +partition p2 history,
> +partition pn current);
> +affected rows: 0
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) NOT NULL AUTO_INCREMENT,
> +  `t` timestamp(6) NOT NULL DEFAULT '2001-11-11 11:11:11.000000',
> +  `b` blob /*!100301 COMPRESSED*/ DEFAULT NULL,
> +  `c` varchar(1033) CHARACTER SET utf8 NOT NULL,
> +  `u` int(11) DEFAULT NULL,
> +  `m` enum('a','b','c') NOT NULL DEFAULT 'a' COMMENT 'absolute',
> +  `i1` tinyint(4) DEFAULT NULL,
> +  `i2` smallint(6) DEFAULT NULL,
> +  `i3` bigint(20) DEFAULT NULL,
> +  `v1` timestamp(6) GENERATED ALWAYS AS (`t` + interval 1 day) VIRTUAL,
> +  `v2` timestamp(6) GENERATED ALWAYS AS (`t` + interval 1 month) STORED,
> +  `s` timestamp(6) GENERATED ALWAYS AS ROW START,
> +  `e` timestamp(6) GENERATED ALWAYS AS ROW END,
> +  `ps` date NOT NULL,
> +  `pe` date NOT NULL,
> +  PRIMARY KEY (`x`,`e`),
> +  UNIQUE KEY `u` (`u`,`e`),
> +  KEY `three` (`i1`,`i2`,`i3`),
> +  PERIOD FOR SYSTEM_TIME (`s`, `e`),
> +  PERIOD FOR `app_time` (`ps`, `pe`),
> +  CONSTRAINT `check_constr` CHECK (`u` > -1)
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=ucs2 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +(PARTITION `p2` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `pn` CURRENT ENGINE = DEFAULT_ENGINE)
> +affected rows: 1
> +insert into t1 (x, c, u, i1, i2, i3, ps, pe)
> +values (1, 'cc', 0, 1, 2, 3, '1999-01-01', '2000-01-01');
> +affected rows: 1
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) NOT NULL AUTO_INCREMENT,
> +  `t` timestamp(6) NOT NULL DEFAULT '2001-11-11 11:11:11.000000',
> +  `b` blob /*!100301 COMPRESSED*/ DEFAULT NULL,
> +  `c` varchar(1033) CHARACTER SET utf8 NOT NULL,
> +  `u` int(11) DEFAULT NULL,
> +  `m` enum('a','b','c') NOT NULL DEFAULT 'a' COMMENT 'absolute',
> +  `i1` tinyint(4) DEFAULT NULL,
> +  `i2` smallint(6) DEFAULT NULL,
> +  `i3` bigint(20) DEFAULT NULL,
> +  `v1` timestamp(6) GENERATED ALWAYS AS (`t` + interval 1 day) VIRTUAL,
> +  `v2` timestamp(6) GENERATED ALWAYS AS (`t` + interval 1 month) STORED,
> +  `s` timestamp(6) GENERATED ALWAYS AS ROW START,
> +  `e` timestamp(6) GENERATED ALWAYS AS ROW END,
> +  `ps` date NOT NULL,
> +  `pe` date NOT NULL,
> +  PRIMARY KEY (`x`,`e`),
> +  UNIQUE KEY `u` (`u`,`e`),
> +  KEY `three` (`i1`,`i2`,`i3`),
> +  PERIOD FOR SYSTEM_TIME (`s`, `e`),
> +  PERIOD FOR `app_time` (`ps`, `pe`),
> +  CONSTRAINT `check_constr` CHECK (`u` > -1)
> +) ENGINE=DEFAULT_ENGINE AUTO_INCREMENT=2 DEFAULT CHARSET=ucs2 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +(PARTITION `p2` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `p1` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `pn` CURRENT ENGINE = DEFAULT_ENGINE)
> +affected rows: 1
> +set timestamp= unix_timestamp('2000-01-01 01:00:00');
> +affected rows: 0
> +update t1 set x= x + 8;
> +affected rows: 1
> +info: Rows matched: 1  Changed: 1  Inserted: 1  Warnings: 0
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) NOT NULL AUTO_INCREMENT,
> +  `t` timestamp(6) NOT NULL DEFAULT '2001-11-11 11:11:11.000000',
> +  `b` blob /*!100301 COMPRESSED*/ DEFAULT NULL,
> +  `c` varchar(1033) CHARACTER SET utf8 NOT NULL,
> +  `u` int(11) DEFAULT NULL,
> +  `m` enum('a','b','c') NOT NULL DEFAULT 'a' COMMENT 'absolute',
> +  `i1` tinyint(4) DEFAULT NULL,
> +  `i2` smallint(6) DEFAULT NULL,
> +  `i3` bigint(20) DEFAULT NULL,
> +  `v1` timestamp(6) GENERATED ALWAYS AS (`t` + interval 1 day) VIRTUAL,
> +  `v2` timestamp(6) GENERATED ALWAYS AS (`t` + interval 1 month) STORED,
> +  `s` timestamp(6) GENERATED ALWAYS AS ROW START,
> +  `e` timestamp(6) GENERATED ALWAYS AS ROW END,
> +  `ps` date NOT NULL,
> +  `pe` date NOT NULL,
> +  PRIMARY KEY (`x`,`e`),
> +  UNIQUE KEY `u` (`u`,`e`),
> +  KEY `three` (`i1`,`i2`,`i3`),
> +  PERIOD FOR SYSTEM_TIME (`s`, `e`),
> +  PERIOD FOR `app_time` (`ps`, `pe`),
> +  CONSTRAINT `check_constr` CHECK (`u` > -1)
> +) ENGINE=DEFAULT_ENGINE AUTO_INCREMENT=10 DEFAULT CHARSET=ucs2 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +(PARTITION `p2` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `p1` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `p3` HISTORY ENGINE = DEFAULT_ENGINE,
> + PARTITION `pn` CURRENT ENGINE = DEFAULT_ENGINE)
> +affected rows: 1
> +# Concurrent DML
> +set timestamp= unix_timestamp('2000-01-01 00:00:00');
> +create or replace table t1 (x int) with system versioning
> +partition by system_time interval 1 hour auto_increment;
> +insert into t1 values (1);
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 3
> +connect con8, localhost, root;
> +connect con7, localhost, root;
> +connect con6, localhost, root;
> +connect con5, localhost, root;
> +connect con4, localhost, root;
> +connect con3, localhost, root;
> +connect con2, localhost, root;
> +connect con1, localhost, root;
> +set timestamp= unix_timestamp('2000-01-01 01:00:00');
> +update t1 set x= x + 10;
> +connection con2;
> +set timestamp= unix_timestamp('2000-01-01 01:00:00');
> +update t1 set x= x + 20;
> +connection con3;
> +set timestamp= unix_timestamp('2000-01-01 01:00:00');
> +update t1 set x= x + 30;
> +connection con4;
> +set timestamp= unix_timestamp('2000-01-01 01:00:00');
> +update t1 set x= x + 40;
> +connection con5;
> +set timestamp= unix_timestamp('2000-01-01 01:00:00');
> +update t1 set x= x + 50;
> +connection con6;
> +set timestamp= unix_timestamp('2000-01-01 01:00:00');
> +update t1 set x= x + 60;
> +connection con7;
> +set timestamp= unix_timestamp('2000-01-01 01:00:00');
> +update t1 set x= x + 70;
> +connection con8;
> +set timestamp= unix_timestamp('2000-01-01 01:00:00');
> +update t1 set x= x + 80;
> +connection con1;
> +disconnect con1;
> +connection con2;
> +disconnect con2;
> +connection con3;
> +disconnect con3;
> +connection con4;
> +disconnect con4;
> +connection con5;
> +disconnect con5;
> +connection con6;
> +disconnect con6;
> +connection con7;
> +disconnect con7;
> +disconnect con8;
> +connection default;
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 4
> +drop tables t1;
> +create or replace table t1 (x int) with system versioning engine innodb
> +partition by system_time interval 1 hour auto;
> +start transaction;
> +select * from t1;
> +x
> +connect con1, localhost, root;
> +set lock_wait_timeout= 1;
> +insert into t1 values (1);
> +Warnings:
> +Warning	4114	Versioned table `test`.`t1`: last HISTORY partition (`p0`) is out of INTERVAL, need more HISTORY partitions
> +Error	1205	Lock wait timeout exceeded; try restarting transaction
> +Warning	4171	Auto-increment history partition: alter partition table failed
> +Warning	4171	Versioned table `test`.`t1`: adding HISTORY partition failed with error 0, see error log for details

"error 0" is strange and "see error log for details" isn't very
user-friendly, a user might not have access to the error log at all

> +select * from t1;
> +x
> +1

I don't understand, there was an error above, why did insert succeed?

> +disconnect con1;
> +connection default;
> +drop table t1;
> diff --git a/mysql-test/suite/versioning/r/rpl.result b/mysql-test/suite/versioning/r/rpl.result
> index 627f3991499..68113190889 100644
> --- a/mysql-test/suite/versioning/r/rpl.result
> +++ b/mysql-test/suite/versioning/r/rpl.result
> @@ -164,4 +164,65 @@ update t1 set i = 0;
>  connection slave;
>  connection master;
>  drop table t1;
> +#
> +# MDEV-17554 Auto-create new partition for system versioned tables with history partitioned by INTERVAL/LIMIT
> +#
> +set timestamp= unix_timestamp('2000-01-01 00:00:00');
> +create or replace table t1 (x int) with system versioning
> +partition by system_time interval 1 hour auto_increment;
> +insert t1 values ();
> +set timestamp= unix_timestamp('2000-01-01 01:00:00');
> +delete from t1;
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 4
> +connection slave;
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO_INCREMENT
> +PARTITIONS 4
> +connection master;
> +drop table t1;
> +#
> +# MENT-685 DML events for auto-partitioned tables are written into binary log twice
> +#

the test below doesn't seem to match the description above

> +create table t1 (x int) partition by hash (x);
> +alter table t1 add partition partitions 1 auto_increment;
> +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use
> +drop table t1;
> +create table t1 (x int) with system versioning
> +partition by system_time limit 1000 auto
> +(partition p1 history, partition pn current);
> +insert into t1 values (1);
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME LIMIT 1000 AUTO_INCREMENT
> +(PARTITION `p1` HISTORY ENGINE = ENGINE,
> + PARTITION `p2` HISTORY ENGINE = ENGINE,
> + PARTITION `pn` CURRENT ENGINE = ENGINE)
> +connection slave;
> +show create table t1;
> +Table	Create Table
> +t1	CREATE TABLE `t1` (
> +  `x` int(11) DEFAULT NULL
> +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
> + PARTITION BY SYSTEM_TIME LIMIT 1000 AUTO_INCREMENT
> +(PARTITION `p1` HISTORY ENGINE = ENGINE,
> + PARTITION `p2` HISTORY ENGINE = ENGINE,
> + PARTITION `pn` CURRENT ENGINE = ENGINE)
> +select * from t1;
> +x
> +1
> +connection master;
> +drop table t1;
>  include/rpl_end.inc
> diff --git a/sql/handler.cc b/sql/handler.cc
> index c6ecc9566d8..c86f96b9689 100644
> --- a/sql/handler.cc
> +++ b/sql/handler.cc
> @@ -1512,7 +1512,7 @@ int ha_commit_trans(THD *thd, bool all)
>    DBUG_ASSERT(thd->transaction.stmt.ha_list == NULL ||
>                trans == &thd->transaction.stmt);
>  
> -  if (thd->in_sub_stmt)
> +  if (thd->in_sub_stmt & ~SUB_STMT_AUTO_HIST)

1. why? That is, why do you call ha_commit_trans() when adding a partition?
2. please add a test with insert under start transaction.
   what should happen in this case?

>    {
>      DBUG_ASSERT(0);
>      /*
> diff --git a/sql/partition_info.cc b/sql/partition_info.cc
> index f4b7260f8b0..617c839721b 100644
> --- a/sql/partition_info.cc
> +++ b/sql/partition_info.cc
> @@ -848,29 +850,289 @@ void partition_info::vers_set_hist_part(THD *thd)
>        else
>          vers_info->hist_part= next;
>      }
> +  }
> +  else if (vers_info->interval.is_set())
> +  {
> +    if (vers_info->hist_part->range_value <= thd->query_start())
> +    {
> +      partition_element *next= NULL;
> +      bool error= true;
> +      List_iterator<partition_element> it(partitions);
> +      while (next != vers_info->hist_part)
> +        next= it++;
> +
> +      while ((next= it++) != vers_info->now_part)
> +      {
> +        vers_info->hist_part= next;
> +        if (next->range_value > thd->query_start())
> +        {
> +          error= false;
> +          break;
> +        }
> +      }
> +      if (error)
> +        my_error(WARN_VERS_PART_FULL, MYF(ME_WARNING|ME_ERROR_LOG),
> +                 table->s->db.str, table->s->table_name.str,
> +                 vers_info->hist_part->partition_name, "INTERVAL");
> +    }
> +  }
> +
> +  if (!vers_info->auto_inc ||
> +      vers_info->hist_part->id + VERS_MIN_EMPTY < vers_info->now_part->id)
>      return;
> +
> +  switch (thd->lex->sql_command)
> +  {
> +  case SQLCOM_DELETE:
> +    if (thd->lex->last_table()->vers_conditions.delete_history)
> +      break;
> +    /* fallthrough */
> +  case SQLCOM_UPDATE:
> +  case SQLCOM_INSERT:
> +  case SQLCOM_INSERT_SELECT:
> +  case SQLCOM_LOAD:
> +  case SQLCOM_REPLACE:
> +  case SQLCOM_REPLACE_SELECT:
> +  case SQLCOM_DELETE_MULTI:
> +  case SQLCOM_UPDATE_MULTI:

it's rather fragile to check for specific sql statements.
why not to look at the table lock instead?
(with a special check for delete history)

Ok, it's a bug. Please add a test with multi-update,
where a partitioned table is *not* updated. Like

  update t1, tpart set t1.x=5 where t1.y=tpart.z;

here a new partition should clearly not be created.
also, a simpler example (multi-update is difficult):

  insert t1 select * from tpart;

add both, please.

> +  {
> +    TABLE_SHARE *share;
> +    List_iterator_fast<TABLE_SHARE> it(thd->vers_auto_part_tables);
> +    while ((share= it++))
> +    {
> +      if (table->s == share)
> +        break;
> +    }
> +    if (share)
> +      break;
> +    /* Prevent spawning multiple instances of vers_add_auto_parts() */
> +    bool altering;
> +    mysql_mutex_lock(&table->s->LOCK_share);
> +    altering= table->s->vers_auto_part;
> +    if (!altering)
> +      table->s->vers_auto_part= true;
> +    mysql_mutex_unlock(&table->s->LOCK_share);
> +    if (altering)
> +      break;

what happens if you're altering already?
logically this thread should wait. Where does it do it?

> +    if (thd->vers_auto_part_tables.push_back(table->s))
> +    {
> +      my_error(ER_OUT_OF_RESOURCES, MYF(0));
> +    }
> +  }
> +  default:;
>    }
> +}
>  
> -  if (vers_info->interval.is_set())
> -  {
> -    if (vers_info->hist_part->range_value > thd->query_start())
> -      return;
>  
> -    partition_element *next= NULL;
> -    List_iterator<partition_element> it(partitions);
> -    while (next != vers_info->hist_part)
> -      next= it++;
> +/**
> +  @brief Run fast_alter_partition_table() to add new history partitions
> +         for tables requiring them.
> +*/
> +void vers_add_auto_parts(THD *thd)
> +{
> +  HA_CREATE_INFO create_info;
> +  Alter_info alter_info;
> +  String query;
> +  TABLE_LIST *table_list= NULL;
> +  partition_info *save_part_info= thd->work_part_info;
> +  Query_tables_list save_query_tables;
> +  Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer;
> +  Diagnostics_area new_stmt_da(thd->query_id, false, true);
> +  Diagnostics_area *save_stmt_da= thd->get_stmt_da();
> +  bool save_no_write_to_binlog= thd->lex->no_write_to_binlog;
> +  const CSET_STRING save_query= thd->query_string;
> +  thd->m_reprepare_observer= NULL;
> +  thd->lex->reset_n_backup_query_tables_list(&save_query_tables);
> +  thd->in_sub_stmt|= SUB_STMT_AUTO_HIST;
> +  thd->lex->no_write_to_binlog= !thd->is_current_stmt_binlog_format_row();
> +  TABLE_LIST *tl;
> +
> +  DBUG_ASSERT(!thd->vers_auto_part_tables.is_empty());
> +
> +  for (TABLE_SHARE &share: thd->vers_auto_part_tables)
> +  {
> +    tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST));
> +    tl->init_one_table(&share.db, &share.table_name, NULL, TL_READ_NO_INSERT);
> +    tl->open_type= OT_BASE_ONLY;
> +    tl->i_s_requested_object= OPEN_TABLE_ONLY;
> +    tl->next_global= table_list;
> +    table_list= tl;
> +  }
> +
> +  /* NB: mysql_execute_command() can be recursive because of PS/SP.
> +     Don't duplicate any processing including error messages. */
> +  thd->vers_auto_part_tables.empty();
> +
> +  DBUG_ASSERT(!thd->is_error());
> +  /* NB: we have to preserve m_affected_rows, m_row_count_func, m_last_insert_id, etc */
> +  thd->set_stmt_da(&new_stmt_da);
> +  new_stmt_da.set_overwrite_status(true);
> +
> +  DDL_options_st ddl_opts_none;
> +  ddl_opts_none.init();
> +  if (open_and_lock_tables(thd, ddl_opts_none, table_list, false, 0))
> +    goto open_err;
> +
> +  for (tl= table_list; tl; tl= tl->next_global)
> +  {
> +    TABLE *table= tl->table;
> +    DBUG_ASSERT(table);
> +    DBUG_ASSERT(table->s->get_table_ref_type() == TABLE_REF_BASE_TABLE);
> +    DBUG_ASSERT(table->versioned());
> +    DBUG_ASSERT(table->part_info);
> +    DBUG_ASSERT(table->part_info->vers_info);
> +    alter_info.reset();
> +    alter_info.partition_flags= ALTER_PARTITION_ADD|ALTER_PARTITION_AUTO_HIST;
> +    create_info.init();
> +    create_info.alter_info= &alter_info;
> +    Alter_table_ctx alter_ctx(thd, tl, 1, &table->s->db, &table->s->table_name);
> +
> +    if (thd->mdl_context.upgrade_shared_lock(table->mdl_ticket,
> +                                             MDL_SHARED_NO_WRITE,
> +                                             thd->variables.lock_wait_timeout))
> +      goto exit;
> +
> +    create_info.db_type= table->s->db_type();
> +    create_info.options|= HA_VERSIONED_TABLE;
> +    DBUG_ASSERT(create_info.db_type);
> +
> +    create_info.vers_info.set_start(table->s->vers_start_field()->field_name);
> +    create_info.vers_info.set_end(table->s->vers_end_field()->field_name);
> +
> +    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= 1;
> +    part_info->num_subparts= table->part_info->num_subparts;
> +    part_info->subpart_type= table->part_info->subpart_type;
> +    if (unlikely(part_info->vers_init_info(thd)))
> +    {
> +      my_error(ER_OUT_OF_RESOURCES, MYF(0));
> +      goto exit;
> +    }
> +    /* Choose first non-occupied name suffix */
> +    uint32 suffix= table->part_info->num_parts - 1;
> +    DBUG_ASSERT(suffix > 0);
> +    char part_name[MAX_PART_NAME_SIZE + 1];
> +    if (make_partition_name(part_name, suffix))
> +    {
> +vers_make_name_err:
> +      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
> +                          WARN_VERS_HIST_PART_ERROR,
> +                          "Auto-increment history partition: "
> +                          "name generation failed for suffix %d", suffix);
> +      my_error(WARN_VERS_HIST_PART_ERROR, MYF(ME_WARNING),
> +              table->s->db.str, table->s->table_name.str, 0);
> +      goto exit;
> +    }
> +    List_iterator_fast<partition_element> it(table->part_info->partitions);
> +    partition_element *el;
> +    while ((el= it++))
> +    {
> +      if (0 == my_strcasecmp(&my_charset_latin1, el->partition_name, part_name))
> +      {
> +        if (make_partition_name(part_name, ++suffix))
> +          goto vers_make_name_err;
> +        it.rewind();
> +      }
> +    }
>  
> -    while ((next= it++) != vers_info->now_part)
> +    // NB: set_ok_status() requires DA_EMPTY
> +    thd->get_stmt_da()->reset_diagnostics_area();
> +
> +    thd->work_part_info= part_info;
> +    if (part_info->set_up_defaults_for_partitioning(thd, table->file,
> +                                                    NULL, suffix + 1))
>      {
> -      vers_info->hist_part= next;
> -      if (next->range_value > thd->query_start())
> -        return;
> +      push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
> +                   WARN_VERS_HIST_PART_ERROR,
> +                   "Auto-increment history partition: "
> +                   "setting up defaults failed");
> +      goto exit;
> +    }
> +    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))
> +    {
> +      push_warning(thd, Sql_condition::WARN_LEVEL_WARN, WARN_VERS_HIST_PART_ERROR,
> +                   "Auto-increment history partition: "
> +                   "alter partitition prepare failed");
> +      goto exit;
> +    }
> +    if (!fast_alter_partition)
> +    {
> +      push_warning(thd, Sql_condition::WARN_LEVEL_WARN, WARN_VERS_HIST_PART_ERROR,
> +                   "Auto-increment history partition: "
> +                   "fast alter partitition is not possible");
> +      my_error(WARN_VERS_HIST_PART_ERROR, MYF(ME_WARNING),
> +               table->s->db.str, table->s->table_name.str, 0);
> +      goto exit;
> +    }
> +    DBUG_ASSERT(partition_changed);
> +    if (mysql_prepare_alter_table(thd, table, &create_info, &alter_info,
> +                                  &alter_ctx))
> +    {
> +      push_warning(thd, Sql_condition::WARN_LEVEL_WARN, WARN_VERS_HIST_PART_ERROR,
> +                   "Auto-increment history partition: "
> +                   "alter prepare failed");
> +      goto exit;
> +    }
> +
> +    // Forge query string for rpl logging
> +    if (!thd->lex->no_write_to_binlog)
> +    {
> +      query.set(STRING_WITH_LEN("ALTER TABLE `"), &my_charset_latin1);
> +
> +      if (query.append(table->s->db) ||
> +          query.append(STRING_WITH_LEN("`.`")) ||
> +          query.append(table->s->table_name) ||
> +          query.append("` ADD PARTITION (PARTITION `") ||
> +          query.append(part_name) ||
> +          query.append("` HISTORY) AUTO_INCREMENT"))
> +      {
> +        my_error(ER_OUT_OF_RESOURCES, MYF(ME_ERROR_LOG));
> +        goto exit;
> +      }
> +      CSET_STRING qs(query.c_ptr(), query.length(), &my_charset_latin1);
> +      thd->set_query(qs);
> +    }
> +
> +    if (fast_alter_partition_table(thd, table, &alter_info, &create_info,
> +                                   tl, &table->s->db, &table->s->table_name))
> +    {
> +      push_warning(thd, Sql_condition::WARN_LEVEL_WARN, WARN_VERS_HIST_PART_ERROR,
> +                   "Auto-increment history partition: "
> +                   "alter partition table failed");
> +      my_error(WARN_VERS_HIST_PART_ERROR, MYF(ME_WARNING),
> +               tl->db.str, tl->table_name.str, 0);
>      }
> -    my_error(WARN_VERS_PART_FULL, MYF(ME_WARNING|ME_ERROR_LOG),
> -            table->s->db.str, table->s->table_name.str,
> -            vers_info->hist_part->partition_name, "INTERVAL");
>    }
> +
> +  if (!thd->transaction.stmt.is_empty())
> +    trans_commit_stmt(thd);
> +
> +exit:
> +  // If we failed with error allow non-processed tables to be processed next time
> +  if (tl)
> +    while ((tl= tl->next_global))
> +      tl->table->s->vers_auto_part= false;
> +  close_thread_tables(thd);
> +open_err:
> +  thd->work_part_info= save_part_info;
> +  thd->m_reprepare_observer= save_reprepare_observer;
> +  thd->lex->restore_backup_query_tables_list(&save_query_tables);
> +  thd->in_sub_stmt&= ~SUB_STMT_AUTO_HIST;
> +  if (!new_stmt_da.is_warning_info_empty())
> +    save_stmt_da->copy_sql_conditions_from_wi(thd, new_stmt_da.get_warning_info());
> +  thd->set_stmt_da(save_stmt_da);
> +  thd->lex->no_write_to_binlog= save_no_write_to_binlog;
> +  thd->set_query(save_query);
>  }
>  
>  
> diff --git a/sql/partition_info.h b/sql/partition_info.h
> index eb8e53a381a..d02eecea073 100644
> --- a/sql/partition_info.h
> +++ b/sql/partition_info.h
> @@ -34,10 +34,19 @@ typedef bool (*check_constants_func)(THD *thd, partition_info *part_info);
>   
>  struct st_ddl_log_memory_entry;
>  
> +
> +/* Auto-create history partition configuration */
> +static const uint VERS_MIN_EMPTY= 1;

No, this doesn't work. One can easily set @@timestamp to do a multi-hour jump and no
fixed value of VERS_MIN_EMPTY will help. You need to add partitions before the statement, as
I wrote in my previous review.

> +static const uint VERS_MIN_INTERVAL= 3600; // seconds
> +static const uint VERS_MIN_LIMIT= 1000;
> +static const uint VERS_ERROR_TIMEOUT= 300; // seconds
> +
> +
>  struct Vers_part_info : public Sql_alloc
>  {
>    Vers_part_info() :
>      limit(0),
> +    auto_inc(false),
>      now_part(NULL),
>      hist_part(NULL)
>    {
> diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
> index 7cc1faea79b..4be3342e78e 100644
> --- a/sql/sql_yacc.yy
> +++ b/sql/sql_yacc.yy
> @@ -7521,14 +7533,19 @@ add_partition_rule:
>  
>  add_part_extra:
>            /* empty */
> -        | '(' part_def_list ')'
> +        | '(' part_def_list ')' opt_vers_auto_inc
>            {
>              LEX *lex= Lex;
>              lex->part_info->num_parts= lex->part_info->partitions.elements;
> +            if ($4)
> +              lex->alter_info.partition_flags|= ALTER_PARTITION_AUTO_HIST;
>            }
> -        | PARTITIONS_SYM real_ulong_num
> +        | PARTITIONS_SYM real_ulong_num opt_vers_auto_inc
>            {
> -            Lex->part_info->num_parts= $2;
> +            LEX *lex= Lex;

^^^ this pattern is obsolete for, like, 10 years.
It does no harm, but adds no value either.

> +            lex->part_info->num_parts= $2;
> +            if ($3)
> +              lex->alter_info.partition_flags|= ALTER_PARTITION_AUTO_HIST;
>            }
>          ;
>  
> diff --git a/storage/mroonga/mrn_table.cpp b/storage/mroonga/mrn_table.cpp
> index b10668cfcce..6458402f572 100644
> --- a/storage/mroonga/mrn_table.cpp
> +++ b/storage/mroonga/mrn_table.cpp
> @@ -932,7 +932,7 @@ MRN_SHARE *mrn_get_share(const char *table_name, TABLE *table, int *error)
>          share->wrap_key_info = NULL;
>          share->wrap_primary_key = MAX_KEY;
>        }
> -      memcpy(wrap_table_share, table->s, sizeof(*wrap_table_share));
> +      memcpy((void *)wrap_table_share, (void *)table->s, sizeof(*wrap_table_share));

why is that?

>        mrn_init_sql_alloc(current_thd, &(wrap_table_share->mem_root));
>        wrap_table_share->keys = share->wrap_keys;
>        wrap_table_share->key_info = share->wrap_key_info;

Regards,
Sergei
VP of MariaDB Server Engineering
and security@xxxxxxxxxxx


Follow ups