summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Midenkov <midenok@gmail.com>2019-07-21 23:30:49 +0300
committerAleksey Midenkov <midenok@gmail.com>2021-12-17 20:33:35 +0300
commit86a5c6fcfe7347622337cec7ae963f7c387f1296 (patch)
treef6ae4dbf24cd9beb1baec4d440fda2b77dfe5b22
parent6208228b78917bff13b5dc34428b38596f7404b4 (diff)
downloadmariadb-git-preview-10.8-MDEV-17554-auto-create-partition.tar.gz
MDEV-17554 Auto-create new partition for system versioned tables with history partitioned by INTERVAL/LIMITpreview-10.8-MDEV-17554-auto-create-partition
== Syntax change == Keyword AUTO enables partition auto-creation. create table t1 (x int) with system versioning partition by system_time interval 1 hour auto; create table t1 (x int) with system versioning partition by system_time interval 1 month starts '2021-01-01 00:00:00' auto partitions 12; create table t1 (x int) with system versioning partition by system_time limit 1000 auto; Or with explicit partitions: create table t1 (x int) with system versioning partition by system_time interval 1 hour auto (partition p0 history, partition pn current); == Description == Before executing history-generating DML command add N history partitions, so that N would be sufficient for potentially generated history. N > 1 may be required when history is rotated by INTERVAL and timestamp was jumped to future further than interval value. If last history partition exceeds LIMIT records before DML command then new history partition is created and the history filling is switched to the new partition. Thus LIMIT does not carry strict limitation and the history partition size must be planned as LIMIT records plus average number of history one DML generates. Auto-creation is implemented by synchronous fast_alter_partition_table() call from the thread of the executed DML command before the command itself (by the fallback and retry mechanism similar to Discovery feature, see Open_table_context). The name for newly added partitions are generated like default partition names with extension of MDEV-22155 (which avoids name clashes by extending assignment counter to next free-enough gap). These DML commands trigger auto-creation: * DELETE (including multi-delete, excluding DELETE HISTORY) * UPDATE (including multi-update) * REPLACE (including REPLACE .. SELECT) * INSERT .. ON DUPLICATE KEY UPDATE * LOAD DATA .. REPLACE MDEV-23642 Locking timeout caused by auto-creation affects original DML The reasons for this are: - Do not disrupt main business process (the history is auxiliary service); - Consequences are non-fatal (history is not lost, but comes into wrong partition; fixed by partitioning rebuild); - There is more freedom for application to fail in this case or not: it may read warning info and find corresponding error number. - While non-failing command is easy to handle by an application and fail it, the opposite is hard to handle: there is no automatic actions to fix failed command and retry, DBA intervention is required and until then application is non-functioning. MDEV-23639 Auto-create does not work under LOCK TABLES or inside triggers Don't do tdc_remove_table() for OT_ADD_HISTORY_PARTITION because it is not possible in locked tables mode. LTM_LOCK_TABLES mode (and LTM_PRELOCKED_UNDER_LOCK_TABLES) works out of the box as fast_alter_partition_table() can reopen tables via locked_tables_list. In LTM_PRELOCKED we reopen and relock table manually. More fixes * some_table_marked_for_reopen flag fix some_table_marked_for_reopen affets only reopen of m_locked_tables. I.e. Locked_tables_list::reopen_tables() reopens only tables from m_locked_tables. * Unused can_recover_from_failed_open() condition Is recover_from_failed_open() can be really used after open_and_process_routine()?
-rw-r--r--include/my_base.h2
-rw-r--r--mysql-test/suite/versioning/common.inc1
-rw-r--r--mysql-test/suite/versioning/common_finish.inc1
-rw-r--r--mysql-test/suite/versioning/r/delete_history.result20
-rw-r--r--mysql-test/suite/versioning/r/not_embedded.result (renamed from mysql-test/suite/versioning/r/truncate_privilege.result)29
-rw-r--r--mysql-test/suite/versioning/r/partition,heap.rdiff140
-rw-r--r--mysql-test/suite/versioning/r/partition.result1104
-rw-r--r--mysql-test/suite/versioning/r/rpl.result27
-rw-r--r--mysql-test/suite/versioning/r/rpl_mix.result55
-rw-r--r--mysql-test/suite/versioning/r/rpl_row.result55
-rw-r--r--mysql-test/suite/versioning/r/rpl_stmt.result50
-rw-r--r--mysql-test/suite/versioning/r/update-big.result74
-rw-r--r--mysql-test/suite/versioning/t/delete_history.test14
-rw-r--r--mysql-test/suite/versioning/t/load_data.test2
-rw-r--r--mysql-test/suite/versioning/t/not_embedded.test (renamed from mysql-test/suite/versioning/t/truncate_privilege.test)39
-rw-r--r--mysql-test/suite/versioning/t/partition.test616
-rw-r--r--mysql-test/suite/versioning/t/rpl.test18
-rw-r--r--mysql-test/suite/versioning/t/rpl_common.inc29
-rw-r--r--mysql-test/suite/versioning/t/rpl_mix.test2
-rw-r--r--mysql-test/suite/versioning/t/rpl_row.test2
-rw-r--r--mysql-test/suite/versioning/t/rpl_stmt.test4
-rw-r--r--mysql-test/suite/versioning/t/update-big.test74
-rw-r--r--sql/ha_partition.cc20
-rw-r--r--sql/ha_partition.h9
-rw-r--r--sql/handler.cc3
-rw-r--r--sql/handler.h7
-rw-r--r--sql/lock.cc32
-rw-r--r--sql/lock.h2
-rw-r--r--sql/log_event.cc13
-rw-r--r--sql/log_event.h9
-rw-r--r--sql/log_event_server.cc22
-rw-r--r--sql/partition_info.cc210
-rw-r--r--sql/partition_info.h23
-rw-r--r--sql/rpl_rli.h2
-rw-r--r--sql/share/errmsg-utf8.txt4
-rw-r--r--sql/sql_base.cc285
-rw-r--r--sql/sql_base.h6
-rw-r--r--sql/sql_class.cc4
-rw-r--r--sql/sql_class.h8
-rw-r--r--sql/sql_lex.cc6
-rw-r--r--sql/sql_parse.cc3
-rw-r--r--sql/sql_partition.cc36
-rw-r--r--sql/sql_truncate.cc2
-rw-r--r--sql/sql_yacc.yy30
-rw-r--r--sql/table.cc2
-rw-r--r--sql/table.h19
-rw-r--r--sql/transaction.cc2
47 files changed, 2907 insertions, 210 deletions
diff --git a/include/my_base.h b/include/my_base.h
index 80ee527ccf0..a2c7af3e9ee 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -35,7 +35,7 @@
#define HA_OPEN_ABORT_IF_LOCKED 0U /* default */
#define HA_OPEN_WAIT_IF_LOCKED 1U
-#define HA_OPEN_IGNORE_IF_LOCKED 2U
+#define HA_OPEN_IGNORE_IF_LOCKED 2U /* Ignore lock error */
#define HA_OPEN_TMP_TABLE 4U /* Table is a temp table */
#define HA_OPEN_DELAY_KEY_WRITE 8U /* Don't update index */
#define HA_OPEN_ABORT_IF_CRASHED 16U
diff --git a/mysql-test/suite/versioning/common.inc b/mysql-test/suite/versioning/common.inc
index 25adf15dd50..4b06e6de279 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';
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/common_finish.inc b/mysql-test/suite/versioning/common_finish.inc
index 3c4e7b66ff3..255daa1963a 100644
--- a/mysql-test/suite/versioning/common_finish.inc
+++ b/mysql-test/suite/versioning/common_finish.inc
@@ -6,5 +6,6 @@ drop function if exists current_row;
drop function if exists check_row;
drop function if exists current_row_ts;
drop function if exists check_row_ts;
+set @@global.time_zone= default;
--enable_warnings
--enable_query_log
diff --git a/mysql-test/suite/versioning/r/delete_history.result b/mysql-test/suite/versioning/r/delete_history.result
index a5a6de19bc6..0dfaa44870c 100644
--- a/mysql-test/suite/versioning/r/delete_history.result
+++ b/mysql-test/suite/versioning/r/delete_history.result
@@ -63,8 +63,6 @@ insert into t values (1);
update t set a= 2;
update t set a= 3;
delete history from t;
-Warnings:
-Warning 4114 Versioned table `test`.`t`: last HISTORY partition (`p1`) is out of LIMIT, need more HISTORY partitions
# The above warning is one command late (MDEV-20345) ^^^
select * from t for system_time all;
a
@@ -187,3 +185,21 @@ x
1
drop prepare stmt;
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:
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
+create or replace table t (a int) with system versioning
+partition by system_time interval 1 hour auto;
+set timestamp= unix_timestamp('2000-01-01 10:00:00');
+delete history from t;
+set timestamp= default;
+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 INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
+PARTITIONS 2
+drop table t;
diff --git a/mysql-test/suite/versioning/r/truncate_privilege.result b/mysql-test/suite/versioning/r/not_embedded.result
index e2b48c494be..1bd745ecab3 100644
--- a/mysql-test/suite/versioning/r/truncate_privilege.result
+++ b/mysql-test/suite/versioning/r/not_embedded.result
@@ -1,3 +1,6 @@
+#
+# DELETE HISTORY and privileges
+#
connect root,localhost,root,,test;
connection root;
create database mysqltest;
@@ -31,3 +34,29 @@ GRANT DELETE HISTORY ON `mysqltest`.* TO `mysqltest_1`@`localhost`
GRANT DELETE HISTORY ON `mysqltest`.`t` TO `mysqltest_1`@`localhost`
drop user mysqltest_1@localhost;
drop database mysqltest;
+disconnect user1;
+disconnect root;
+connection default;
+#
+# MDEV-25559 Auto-create: infinite loop after interrupted lock wait
+#
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
+create table t (pk int primary key, a int) engine innodb with system versioning
+partition by system_time interval 1 hour auto;
+insert into t values (1, 0);
+begin;
+update t set a= a + 1;
+connect con1,localhost,root,,;
+set max_statement_time= 1;
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+update t set a= a + 2;
+connection default;
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+update t set a= a + 3;
+connection con1;
+ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
+disconnect con1;
+connection default;
+commit;
+drop table t;
+set timestamp= default;
diff --git a/mysql-test/suite/versioning/r/partition,heap.rdiff b/mysql-test/suite/versioning/r/partition,heap.rdiff
index f7b534bb114..779b715f813 100644
--- a/mysql-test/suite/versioning/r/partition,heap.rdiff
+++ b/mysql-test/suite/versioning/r/partition,heap.rdiff
@@ -1,6 +1,6 @@
--- partition.result
+++ partition,heap.reject
-@@ -1545,82 +1545,3 @@
+@@ -1582,85 +1582,6 @@
(PARTITION `p0` HISTORY ENGINE = X,
PARTITION `pn` CURRENT ENGINE = X)
drop tables t1, tp1;
@@ -83,3 +83,141 @@
-(PARTITION `p0` VALUES LESS THAN (10) ENGINE = X,
- PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = X)
-drop tables t1, tp1;
+ #
+ # MDEV-17554 Auto-create new partition for system versioned tables with history partitioned by INTERVAL/LIMIT
+ #
+@@ -2193,134 +2114,6 @@
+ Warning 4114 Versioned table `test`.`t1`: last HISTORY partition (`p0`) is out of INTERVAL, need more HISTORY partitions
+ drop prepare s;
+ 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 (
+-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 utf8mb3 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,
+- PERIOD FOR `app_time` (`ps`, `pe`),
+- PRIMARY KEY (`x`,`e`),
+- UNIQUE KEY `u` (`u`,`e`),
+- KEY `three` (`i1`,`i2`,`i3`),
+- PERIOD FOR SYSTEM_TIME (`s`, `e`),
+- 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
+-(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
+-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 utf8mb3 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,
+- PERIOD FOR `app_time` (`ps`, `pe`),
+- PRIMARY KEY (`x`,`e`),
+- UNIQUE KEY `u` (`u`,`e`),
+- KEY `three` (`i1`,`i2`,`i3`),
+- PERIOD FOR SYSTEM_TIME (`s`, `e`),
+- 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
+-(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 02: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 utf8mb3 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,
+- PERIOD FOR `app_time` (`ps`, `pe`),
+- PRIMARY KEY (`x`,`e`),
+- UNIQUE KEY `u` (`u`,`e`),
+- KEY `three` (`i1`,`i2`,`i3`),
+- PERIOD FOR SYSTEM_TIME (`s`, `e`),
+- 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
+-(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
+ # INSERT .. ON DUPLICATE KEY UPDATE (ODKU)
+ set timestamp= unix_timestamp('2000-01-01 00:00:00');
+ create or replace table t1 (x int primary key) with system versioning
diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result
index c8d95ac0063..0c93c9d810e 100644
--- a/mysql-test/suite/versioning/r/partition.result
+++ b/mysql-test/suite/versioning/r/partition.result
@@ -237,11 +237,13 @@ select @ts0 = @ts1;
select @ts2 = @ts3;
@ts2 = @ts3
1
-## rotation by LIMIT
+#
+# Rotation by LIMIT
+#
create or replace table t1 (x int)
with system versioning
partition by system_time limit 0 partitions 3;
-ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for 'LIMIT'
+ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for LIMIT
create or replace table t1 (x int)
with system versioning
partition by system_time limit 2 partitions 3;
@@ -276,8 +278,6 @@ x
5
6
insert into t1 values (7), (8);
-Warnings:
-Warning 4114 Versioned table `test`.`t1`: last HISTORY partition (`p1`) is out of LIMIT, need more HISTORY partitions
### warn about full partition
delete from t1;
Warnings:
@@ -289,11 +289,13 @@ x
6
7
8
-## rotation by INTERVAL
+#
+# 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
@@ -349,19 +351,25 @@ delete from t1;
set timestamp=unix_timestamp('2001-02-04 10:20:50');
insert t1 values (2);
delete from t1;
-select subpartition_name,partition_description,table_rows from information_schema.partitions where table_schema='test' and table_name='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';
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
+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';
+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
@@ -371,6 +379,25 @@ p2sp0 2001-02-06 00:00:00 0
p2sp1 2001-02-06 00:00:00 0
pnsp0 CURRENT 0
pnsp1 CURRENT 2
+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);
@@ -410,16 +437,16 @@ set timestamp= default;
## INTERVAL ... STARTS
create or replace table t1 (i int) with system versioning
partition by system_time interval 1 day starts 'a';
-ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for 'STARTS'
+ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for STARTS
create or replace table t1 (i int) with system versioning
partition by system_time interval 1 day starts '00:00:00';
-ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for 'STARTS'
+ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for STARTS
create or replace table t1 (i int) with system versioning
partition by system_time interval 1 day starts '2000-00-01 00:00:00';
-ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for 'STARTS'
+ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for STARTS
create or replace table t1 (i int) with system versioning
partition by system_time interval 1 day starts 946684800;
-ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for 'STARTS'
+ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for STARTS
create or replace table t1 (i int) with system versioning
partition by system_time interval 1 day starts '2000-01-01 00:00:00';
show create table t1;
@@ -554,12 +581,15 @@ set timestamp= unix_timestamp('2001-01-01 00:00:00');
create or replace table t1 (i int) with system versioning
partition by system_time interval 1 day starts '2000-01-01 00:00:00'
partitions 3;
-# we are warned when we push to present:
insert into t1 values (0);
set timestamp= unix_timestamp('2001-01-01 00:00:01');
update t1 set i= i + 1;
+Warnings:
+Warning 4114 Versioned table `test`.`t1`: last HISTORY partition (`p1`) is out of INTERVAL, need more HISTORY partitions
set timestamp= unix_timestamp('2001-01-01 00:00:02');
update t1 set i= i + 1;
+Warnings:
+Warning 4114 Versioned table `test`.`t1`: last HISTORY partition (`p1`) is out of INTERVAL, need more HISTORY partitions
select *, row_end from t1 partition (p0);
i row_end
select *, row_end from t1 partition (p1);
@@ -590,8 +620,8 @@ i row_end
select *, row_end from t1 partition (p1);
i row_end
3 2000-01-04 00:00:01.000000
-set timestamp= unix_timestamp('2000-01-01 00:00:00');
# and this is how it usually goes:
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
create or replace table t1 (i int) with system versioning
partition by system_time interval 1 day
partitions 3;
@@ -602,8 +632,12 @@ set timestamp= unix_timestamp('2000-01-02 00:00:01');
update t1 set i= i + 1;
set timestamp= unix_timestamp('2000-01-03 00:00:01');
update t1 set i= i + 1;
+Warnings:
+Warning 4114 Versioned table `test`.`t1`: last HISTORY partition (`p1`) is out of INTERVAL, need more HISTORY partitions
set timestamp= unix_timestamp('2000-01-04 00:00:01');
update t1 set i= i + 1;
+Warnings:
+Warning 4114 Versioned table `test`.`t1`: last HISTORY partition (`p1`) is out of INTERVAL, need more HISTORY partitions
alter table t1 add partition (partition p2 history, partition p3 history);
select *, row_end from t1 partition (p0);
i row_end
@@ -634,9 +668,9 @@ select * from t1 partition (pnsp1);
x
2
4
-### warn about full partition
delete from t1 where x < 3;
delete from t1;
+### warn about full partition
delete from t1;
Warnings:
Warning 4114 Versioned table `test`.`t1`: last HISTORY partition (`p1`) is out of LIMIT, need more HISTORY partitions
@@ -1105,11 +1139,11 @@ f varchar(45000)
partition by system_time interval 1 year (partition p1 history,
partition pn current);
insert into t1 () values (),(),(),(),(),(),(),(),(),(),(),(),(),(),(),();
-select * into outfile 'load.data' from t1;
-load data infile 'load.data' replace into table t1;
-load data infile 'load.data' replace into table t1;
+select * into outfile 'MDEV-17891.data' from t1;
+load data infile 'MDEV-17891.data' replace into table t1;
+load data infile 'MDEV-17891.data' replace into table t1;
ERROR HY000: The table 't1' is full
-load data infile 'load.data' replace into table t1;
+load data infile 'MDEV-17891.data' replace into table t1;
ERROR HY000: The table 't1' is full
set @@max_heap_table_size= 1048576;
drop table t1;
@@ -1131,6 +1165,8 @@ insert into t1 values (0);
update t1 set x= x + 1;
set timestamp= unix_timestamp('2000-01-01 02:00:01');
update t1 set x= x + 1;
+Warnings:
+Warning 4114 Versioned table `test`.`t1`: last HISTORY partition (`p1`) is out of INTERVAL, need more HISTORY partitions
select *, row_start, row_end from t1 for system_time as of '2000-01-01 02:00:00';
x row_start row_end
1 2000-01-01 00:00:00.000000 2000-01-01 02:00:01.000000
@@ -1259,31 +1295,7 @@ t1 CREATE TABLE `t1` (
PARTITION `p5` HISTORY ENGINE = DEFAULT_ENGINE,
PARTITION `pn` CURRENT ENGINE = DEFAULT_ENGINE)
alter table t1 add partition partitions 8;
-show create table t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `x` int(11) DEFAULT NULL
-) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
- PARTITION BY SYSTEM_TIME LIMIT 1
-(PARTITION `p2` HISTORY ENGINE = DEFAULT_ENGINE,
- PARTITION `p8` HISTORY ENGINE = DEFAULT_ENGINE,
- PARTITION `p3` HISTORY ENGINE = DEFAULT_ENGINE,
- PARTITION `p4` HISTORY ENGINE = DEFAULT_ENGINE,
- PARTITION `p5` HISTORY ENGINE = DEFAULT_ENGINE,
- PARTITION `p9` HISTORY ENGINE = DEFAULT_ENGINE,
- PARTITION `p10` HISTORY ENGINE = DEFAULT_ENGINE,
- PARTITION `p11` HISTORY ENGINE = DEFAULT_ENGINE,
- PARTITION `p12` HISTORY ENGINE = DEFAULT_ENGINE,
- PARTITION `p13` HISTORY ENGINE = DEFAULT_ENGINE,
- PARTITION `p14` HISTORY ENGINE = DEFAULT_ENGINE,
- PARTITION `p15` HISTORY ENGINE = DEFAULT_ENGINE,
- PARTITION `p16` HISTORY ENGINE = DEFAULT_ENGINE,
- PARTITION `pn` CURRENT ENGINE = DEFAULT_ENGINE)
-drop tables t1;
-#
-# End of 10.5 tests
-#
-SET GLOBAL innodb_stats_persistent=@save_persistent;
+drop table t1;
# End of 10.6 tests
#
# MDEV-22166 MIGRATE PARTITION: move out partition into a table
@@ -1649,3 +1661,1007 @@ t1 CREATE TABLE `t1` (
(PARTITION `p0` VALUES LESS THAN (10) ENGINE = X,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = X)
drop tables t1, tp1;
+#
+# 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 1 auto;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x` int(11) DEFAULT NULL
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+ PARTITION BY SYSTEM_TIME LIMIT 1 AUTO
+PARTITIONS 2
+insert into t1 values (1);
+create or replace table t2 (y int);
+insert into t2 values (2);
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x` int(11) DEFAULT NULL
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+ PARTITION BY SYSTEM_TIME LIMIT 1 AUTO
+PARTITIONS 2
+# Too many partitions error
+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;
+set timestamp= unix_timestamp('2001-01-01 00:01:00');
+update t1 set x= x + 1;
+ERROR HY000: Versioned table `test`.`t1`: adding HISTORY partition(s) failed
+show warnings;
+Level Code Message
+Warning 1499 Too many partitions (including subpartitions) were defined
+Error 4186 Versioned table `test`.`t1`: adding HISTORY partition(s) failed
+# Auto-create failed error
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
+create or replace table t1 (x int) with system versioning engine innodb
+partition by system_time interval 1 hour auto;
+insert into t1 values (1);
+call mtr.add_suppression("rror number .*(File exists|file operation)");
+call mtr.add_suppression("InnoDB: Cannot create file");
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+update t1 set x= x + 2;
+ERROR HY000: Got error 184 "Tablespace already exists" from storage engine InnoDB
+show warnings;
+Level Code Message
+Error 1030 Got error 184 "Tablespace already exists" from storage engine InnoDB
+Warning 4186 Versioned table `test`.`t1`: adding HISTORY partition(s) failed
+# Partition overflow error and manual fix
+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;
+insert into t1 values (440);
+set timestamp= unix_timestamp('2000-01-01 00:10:00');
+update t1 set x= x + 1;
+# Check how pruning boundaries work
+explain partitions select * from t1 for system_time as of '2000-01-01 00:59:58';
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 p0,pn # NULL NULL NULL NULL # #
+explain partitions select * from t1 for system_time as of '2000-01-01 00:59:59';
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 p0,pn # NULL NULL NULL NULL # #
+explain partitions select * from t1 for system_time as of '2000-01-01 01:00:00';
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 p0,pn # NULL NULL NULL NULL # #
+select * from t1 for system_time as of '2000-01-01 00:09:59';
+x
+440
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+update t1 set x= x + 1;
+Warnings:
+Warning 4114 Versioned table `test`.`t1`: last HISTORY partition (`p0`) is out of INTERVAL, need more HISTORY partitions
+select * from t1 for system_time as of '2000-01-01 01:00:00';
+x
+441
+select * from t1 partition (p0) order by x;
+x
+440
+441
+# Here is how manual fix works: just add new partitions there
+alter table t1 add partition partitions 3;
+select * from t1 for system_time as of '2000-01-01 01:00:00';
+x
+441
+select * from t1 partition (p0) order by x;
+x
+440
+# Check pruning after ALTER
+explain partitions select * from t1 for system_time as of '2000-01-01 00:59:58';
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 p0,p1,p2,p3,pn # NULL NULL NULL NULL # #
+explain partitions select * from t1 for system_time as of '2000-01-01 00:59:59';
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 p1,p2,p3,pn # NULL NULL NULL NULL # #
+explain partitions select * from t1 for system_time as of '2000-01-01 01:00:00';
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 p1,p2,p3,pn # NULL NULL NULL NULL # #
+drop table t1;
+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 partitions 3;
+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
+PARTITIONS 3
+affected rows: 1
+set timestamp= unix_timestamp('2000-01-01 02: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
+PARTITIONS 4
+affected rows: 1
+set timestamp= unix_timestamp('2000-01-01 03: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
+PARTITIONS 5
+affected rows: 1
+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 (
+partition p1 history,
+partition p3 history,
+partition pn current);
+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 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
+(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 02: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
+(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 03: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
+(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
+set timestamp= unix_timestamp('2000-01-01 04:00:00');
+affected rows: 0
+lock tables t1 write;
+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
+(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
+set timestamp= default;
+affected rows: 0
+# Couple of more LOCK TABLES cases
+create or replace table t1 (x int) with system versioning
+partition by system_time limit 1 auto;
+affected rows: 0
+lock tables t1 write;
+affected rows: 0
+insert into t1 values (1);
+affected rows: 1
+update t1 set x= x + 1;
+affected rows: 1
+info: Rows matched: 1 Changed: 1 Inserted: 1 Warnings: 0
+update t1 set x= x + 1;
+affected rows: 1
+info: Rows matched: 1 Changed: 1 Inserted: 1 Warnings: 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 LIMIT 1 AUTO
+PARTITIONS 4
+affected rows: 1
+unlock tables;
+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 1 AUTO
+PARTITIONS 4
+affected rows: 1
+# Overflow prevention under LOCK TABLES
+create or replace table t1 (x int)
+with system versioning partition by system_time
+limit 10 auto;
+affected rows: 0
+insert into t1 values (1), (2), (3), (4), (5), (6), (7), (8), (9);
+affected rows: 9
+info: Records: 9 Duplicates: 0 Warnings: 0
+update t1 set x= x + 10;
+affected rows: 9
+info: Rows matched: 9 Changed: 9 Inserted: 9 Warnings: 0
+lock tables t1 write;
+affected rows: 0
+update t1 set x= 1 where x = 11;
+affected rows: 1
+info: Rows matched: 1 Changed: 1 Inserted: 1 Warnings: 0
+update t1 set x= 2 where x = 12;
+affected rows: 1
+info: Rows matched: 1 Changed: 1 Inserted: 1 Warnings: 0
+update t1 set x= 3 where x = 13;
+affected rows: 1
+info: Rows matched: 1 Changed: 1 Inserted: 1 Warnings: 0
+unlock tables;
+affected rows: 0
+select count(x) from t1 partition (p0);
+count(x)
+10
+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 10 AUTO
+PARTITIONS 3
+affected rows: 1
+drop tables t1;
+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;
+affected rows: 0
+create or replace view v1 as select * from t1;
+affected rows: 0
+insert into t1 values (1);
+affected rows: 1
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+affected rows: 0
+update v1 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 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
+PARTITIONS 3
+affected rows: 1
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+affected rows: 0
+lock tables v1 write;
+affected rows: 0
+update v1 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
+PARTITIONS 4
+affected rows: 1
+unlock tables;
+affected rows: 0
+drop view v1;
+affected rows: 0
+drop tables t1;
+affected rows: 0
+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 partitions 3;
+affected rows: 0
+create or replace table t2 (y int) with system versioning
+partition by system_time interval 1 hour auto;
+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
+PARTITIONS 3
+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
+PARTITIONS 3
+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
+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
+PARTITIONS 4
+affected rows: 1
+set timestamp= unix_timestamp('2000-01-01 03:00:00');
+affected rows: 0
+update t1, t2 set t1.x= 0 where t1.x< t2.y;
+affected rows: 1
+info: Rows matched: 1 Changed: 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
+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
+PARTITIONS ok
+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;
+affected rows: 0
+insert into t1 values (1);
+affected rows: 1
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+affected rows: 0
+execute immediate '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
+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 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
+PARTITIONS 4
+affected rows: 1
+set timestamp= unix_timestamp('2000-01-01 03:00:00');
+affected rows: 0
+lock tables t1 write;
+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
+PARTITIONS 5
+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 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
+PARTITIONS 6
+affected rows: 1
+set timestamp= unix_timestamp('2000-01-01 05:00:00');
+affected rows: 0
+lock tables t1 write;
+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
+PARTITIONS 7
+affected rows: 1
+unlock tables;
+affected rows: 0
+drop procedure sp;
+affected rows: 0
+set timestamp= unix_timestamp('2001-01-01 00:00:00');
+affected rows: 0
+create or replace table t1 (i int) with system versioning
+partition by system_time interval 1 day starts '2001-01-01 00:00:00';
+affected rows: 0
+insert into t1 values (0);
+affected rows: 1
+set timestamp= unix_timestamp('2001-01-01 00:00:01');
+affected rows: 0
+prepare s from 'update t1 set i= i + 1';
+affected rows: 0
+info: Statement prepared
+execute s;
+affected rows: 1
+info: Rows matched: 1 Changed: 1 Inserted: 1 Warnings: 0
+set timestamp= unix_timestamp('2001-01-02 00:00:01');
+affected rows: 0
+execute s;
+affected rows: 1
+info: Rows matched: 1 Changed: 1 Inserted: 1 Warnings: 1
+Warnings:
+Warning 4114 Versioned table `test`.`t1`: last HISTORY partition (`p0`) is out of INTERVAL, need more HISTORY partitions
+drop prepare s;
+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 (
+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 utf8mb3 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,
+ PERIOD FOR `app_time` (`ps`, `pe`),
+ PRIMARY KEY (`x`,`e`),
+ UNIQUE KEY `u` (`u`,`e`),
+ KEY `three` (`i1`,`i2`,`i3`),
+ PERIOD FOR SYSTEM_TIME (`s`, `e`),
+ 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
+(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
+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 utf8mb3 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,
+ PERIOD FOR `app_time` (`ps`, `pe`),
+ PRIMARY KEY (`x`,`e`),
+ UNIQUE KEY `u` (`u`,`e`),
+ KEY `three` (`i1`,`i2`,`i3`),
+ PERIOD FOR SYSTEM_TIME (`s`, `e`),
+ 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
+(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 02: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 utf8mb3 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,
+ PERIOD FOR `app_time` (`ps`, `pe`),
+ PRIMARY KEY (`x`,`e`),
+ UNIQUE KEY `u` (`u`,`e`),
+ KEY `three` (`i1`,`i2`,`i3`),
+ PERIOD FOR SYSTEM_TIME (`s`, `e`),
+ 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
+(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
+# INSERT .. ON DUPLICATE KEY UPDATE (ODKU)
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
+create or replace table t1 (x int primary key) with system versioning
+partition by system_time interval 1 hour auto;
+insert into t1 values (1);
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+insert into t1 values (1) on duplicate key update x= x + 1;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x` int(11) NOT NULL,
+ PRIMARY KEY (`x`)
+) 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
+PARTITIONS 3
+# LOAD DATA .. REPLACE
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
+create or replace table t1 (x int primary key) with system versioning
+partition by system_time interval 1 hour auto;
+insert t1 values (1), (2), (3);
+select x into outfile 'MDEV-17554.data' from t1;
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+load data infile 'MDEV-17554.data' replace into table t1 (x);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x` int(11) NOT NULL,
+ PRIMARY KEY (`x`)
+) 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
+PARTITIONS 3
+# 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 partitions 3;
+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
+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 02:00:00');
+update t1 set x= x + 10;
+connection con2;
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+update t1 set x= x + 20;
+connection con3;
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+update t1 set x= x + 30;
+connection con4;
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+update t1 set x= x + 40;
+connection con5;
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+update t1 set x= x + 50;
+connection con6;
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+update t1 set x= x + 60;
+connection con7;
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+update t1 set x= x + 70;
+connection con8;
+set timestamp= unix_timestamp('2000-01-01 02: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
+PARTITIONS 4
+drop tables t1;
+set timestamp= default;
+# Transaction
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
+create or replace table t1 (x int) with system versioning engine innodb
+partition by system_time interval 1 hour auto;
+insert into t1 values (1);
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+start transaction;
+update t1 set x= 0;
+connect con1, localhost, root;
+select * from t1;
+x
+1
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+ PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
+PARTITIONS 3
+connection default;
+commit;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+ PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
+PARTITIONS 3
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+start transaction;
+update t1 set x= 1;
+connection con1;
+select * from t1;
+x
+0
+connection default;
+rollback;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+ PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
+PARTITIONS 4
+disconnect con1;
+connection default;
+drop table t1;
+#
+# MDEV-25479 Auto-create: 2nd and further executions of PS or SP fail to create partition
+#
+create table t (a int) with system versioning
+partition by system_time interval 1 hour auto;
+insert into t values (1), (2);
+prepare stmt from "update t set a= a + 1";
+set @@timestamp= @@timestamp + 3601;
+execute stmt;
+set @@timestamp= @@timestamp + 3601;
+execute stmt;
+drop prepare stmt;
+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 INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 02:00:00' AUTO
+PARTITIONS 4
+create procedure sp() update t set a= a + 1;
+set @@timestamp= @@timestamp + 3601;
+call sp();
+set @@timestamp= @@timestamp + 3601;
+call sp();
+drop procedure sp;
+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 INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 02:00:00' AUTO
+PARTITIONS 6
+drop table t;
+#
+# MDEV-23639 Auto-create does not work under LOCK TABLES or inside triggers
+#
+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
+partitions 3;
+create table t2 (x int);
+create table t3 (x int);
+insert into t3 values (3);
+create trigger tr after insert on t2 for each row update t1 set x= x + 11;
+create or replace procedure sp() update t1 set x= x + 5;
+create or replace procedure sp2() insert into t2 values (5);
+prepare ps from 'update t1 set x= x + 6';
+prepare ps2 from 'insert into t2 values (6)';
+insert into t1 values (1);
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x` int(11) DEFAULT NULL
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+ PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
+PARTITIONS 3
+insert into t2 values (2);
+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
+PARTITIONS 4
+set timestamp= unix_timestamp('2000-01-01 03:00:00');
+call sp;
+call sp;
+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
+PARTITIONS 5
+set timestamp= unix_timestamp('2000-01-01 04:00:00');
+call sp2;
+call sp2;
+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
+PARTITIONS 6
+set timestamp= unix_timestamp('2000-01-01 05:00:00');
+execute ps;
+execute ps;
+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
+PARTITIONS 7
+set timestamp= unix_timestamp('2000-01-01 06:00:00');
+execute ps2;
+execute ps2;
+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
+PARTITIONS 8
+set timestamp= unix_timestamp('2000-01-01 08:00:00');
+lock tables t1 write, t2 write;
+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
+PARTITIONS 10
+set timestamp= unix_timestamp('2000-01-01 09:00:00');
+update t1 set x= x + 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
+PARTITIONS 11
+set timestamp= unix_timestamp('2000-01-01 10:00:00');
+update t1 set x= x + 2;
+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
+PARTITIONS 12
+update t2 set x= x + 1;
+set timestamp= unix_timestamp('2000-01-01 11:00:00');
+insert into t2 values (4);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x` int(11) DEFAULT NULL
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+ PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
+PARTITIONS 13
+update t3 set x= x + 1;
+ERROR HY000: Table 't3' was not locked with LOCK TABLES
+set timestamp= unix_timestamp('2000-01-01 12:00:00');
+call sp;
+call sp;
+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
+PARTITIONS 14
+set timestamp= unix_timestamp('2000-01-01 13:00:00');
+call sp2;
+call sp2;
+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
+PARTITIONS 15
+set timestamp= unix_timestamp('2000-01-01 14:00:00');
+execute ps;
+execute ps;
+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
+PARTITIONS 16
+set timestamp= unix_timestamp('2000-01-01 15:00:00');
+execute ps2;
+execute ps2;
+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
+PARTITIONS 17
+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 INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
+PARTITIONS 17
+drop tables t1, t2, t3;
+drop procedure sp;
+drop procedure sp2;
+drop prepare ps;
+drop prepare ps2;
+SET GLOBAL innodb_stats_persistent=@save_persistent;
diff --git a/mysql-test/suite/versioning/r/rpl.result b/mysql-test/suite/versioning/r/rpl.result
index 627f3991499..0169d73769e 100644
--- a/mysql-test/suite/versioning/r/rpl.result
+++ b/mysql-test/suite/versioning/r/rpl.result
@@ -164,4 +164,31 @@ 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;
+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
+PARTITIONS 3
+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
+PARTITIONS 3
+connection master;
+drop table t1;
+set timestamp= default;
include/rpl_end.inc
diff --git a/mysql-test/suite/versioning/r/rpl_mix.result b/mysql-test/suite/versioning/r/rpl_mix.result
index 68eded0faf7..56af76b8fc2 100644
--- a/mysql-test/suite/versioning/r/rpl_mix.result
+++ b/mysql-test/suite/versioning/r/rpl_mix.result
@@ -8,4 +8,59 @@ DELETE HISTORY FROM t1;
connection slave;
connection master;
drop table t1;
+#
+# MDEV-25347 DML events for auto-partitioned tables are written into binary log twice
+#
+flush binary logs;
+create table t1 (a int) with system versioning
+partition by system_time limit 1 auto;
+insert into t1 values (1);
+update t1 set a= a + 1;
+update t1 set a= a + 2;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+ PARTITION BY SYSTEM_TIME LIMIT 1 AUTO
+PARTITIONS 3
+select * from t1;
+a
+4
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000002 # Binlog_checkpoint # # master-bin.000002
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; create table t1 (a int) with system versioning
+partition by system_time limit 1 auto
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Annotate_rows # # insert into t1 values (1)
+master-bin.000002 # Table_map # # table_id: # (test.t1)
+master-bin.000002 # Write_rows_v1 # # table_id: # flags: STMT_END_F
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Annotate_rows # # update t1 set a= a + 1
+master-bin.000002 # Table_map # # table_id: # (test.t1)
+master-bin.000002 # Update_rows_v1 # # table_id: #
+master-bin.000002 # Write_rows_v1 # # table_id: # flags: STMT_END_F
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Annotate_rows # # update t1 set a= a + 2
+master-bin.000002 # Table_map # # table_id: # (test.t1)
+master-bin.000002 # Update_rows_v1 # # table_id: #
+master-bin.000002 # Write_rows_v1 # # table_id: # flags: STMT_END_F
+master-bin.000002 # Query # # COMMIT
+connection slave;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+ PARTITION BY SYSTEM_TIME LIMIT 1 AUTO
+PARTITIONS 3
+select * from t1;
+a
+4
+connection master;
+drop table t1;
include/rpl_end.inc
diff --git a/mysql-test/suite/versioning/r/rpl_row.result b/mysql-test/suite/versioning/r/rpl_row.result
index 03ac8dc9eb8..124993423e7 100644
--- a/mysql-test/suite/versioning/r/rpl_row.result
+++ b/mysql-test/suite/versioning/r/rpl_row.result
@@ -11,4 +11,59 @@ connection slave;
connection master;
drop table t1;
set binlog_row_image= @old_row_image;
+#
+# MDEV-25347 DML events for auto-partitioned tables are written into binary log twice
+#
+flush binary logs;
+create table t1 (a int) with system versioning
+partition by system_time limit 1 auto;
+insert into t1 values (1);
+update t1 set a= a + 1;
+update t1 set a= a + 2;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+ PARTITION BY SYSTEM_TIME LIMIT 1 AUTO
+PARTITIONS 3
+select * from t1;
+a
+4
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000002 # Binlog_checkpoint # # master-bin.000002
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; create table t1 (a int) with system versioning
+partition by system_time limit 1 auto
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Annotate_rows # # insert into t1 values (1)
+master-bin.000002 # Table_map # # table_id: # (test.t1)
+master-bin.000002 # Write_rows_v1 # # table_id: # flags: STMT_END_F
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Annotate_rows # # update t1 set a= a + 1
+master-bin.000002 # Table_map # # table_id: # (test.t1)
+master-bin.000002 # Update_rows_v1 # # table_id: #
+master-bin.000002 # Write_rows_v1 # # table_id: # flags: STMT_END_F
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Annotate_rows # # update t1 set a= a + 2
+master-bin.000002 # Table_map # # table_id: # (test.t1)
+master-bin.000002 # Update_rows_v1 # # table_id: #
+master-bin.000002 # Write_rows_v1 # # table_id: # flags: STMT_END_F
+master-bin.000002 # Query # # COMMIT
+connection slave;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+ PARTITION BY SYSTEM_TIME LIMIT 1 AUTO
+PARTITIONS 3
+select * from t1;
+a
+4
+connection master;
+drop table t1;
include/rpl_end.inc
diff --git a/mysql-test/suite/versioning/r/rpl_stmt.result b/mysql-test/suite/versioning/r/rpl_stmt.result
new file mode 100644
index 00000000000..1a5087dfa74
--- /dev/null
+++ b/mysql-test/suite/versioning/r/rpl_stmt.result
@@ -0,0 +1,50 @@
+include/master-slave.inc
+[connection master]
+#
+# MDEV-25347 DML events for auto-partitioned tables are written into binary log twice
+#
+flush binary logs;
+create table t1 (a int) with system versioning
+partition by system_time limit 1 auto;
+insert into t1 values (1);
+update t1 set a= a + 1;
+update t1 set a= a + 2;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+ PARTITION BY SYSTEM_TIME LIMIT 1 AUTO
+PARTITIONS 3
+select * from t1;
+a
+4
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000002 # Binlog_checkpoint # # master-bin.000002
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; create table t1 (a int) with system versioning
+partition by system_time limit 1 auto
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; insert into t1 values (1)
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; update t1 set a= a + 1
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; update t1 set a= a + 2
+master-bin.000002 # Query # # COMMIT
+connection slave;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+ PARTITION BY SYSTEM_TIME LIMIT 1 AUTO
+PARTITIONS 3
+select * from t1;
+a
+4
+connection master;
+drop table t1;
+include/rpl_end.inc
diff --git a/mysql-test/suite/versioning/r/update-big.result b/mysql-test/suite/versioning/r/update-big.result
index 89297fe5d89..506d1d23c5d 100644
--- a/mysql-test/suite/versioning/r/update-big.result
+++ b/mysql-test/suite/versioning/r/update-big.result
@@ -22,4 +22,78 @@ update t1 set a= 1 where a = 5;
update t1 set a= 8 where a = 1;
update t1 set a= 4 where a = 8;
update t1 set a= 6;
+disconnect con1;
drop table t1;
+call mtr.add_suppression("need more HISTORY partitions");
+#
+# MDEV-23642 Locking timeout caused by auto-creation affects original DML
+#
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
+create or replace table t1 (x int primary key) with system versioning engine innodb
+partition by system_time interval 1 hour auto;
+insert into t1 values (1);
+start transaction;
+insert into t1 values (2);
+connect con1, localhost, root;
+set lock_wait_timeout= 1;
+set innodb_lock_wait_timeout= 1;
+set timestamp= unix_timestamp('2000-01-01 01:00:01');
+update t1 set x= x + 122 where x = 1;
+Warnings:
+Error 1205 Lock wait timeout exceeded; try restarting transaction
+Warning 4114 Versioned table `test`.`t1`: last HISTORY partition (`p0`) is out of INTERVAL, need more HISTORY partitions
+disconnect con1;
+connection default;
+select * from t1;
+x
+2
+123
+drop table t1;
+set timestamp= default;
+#
+# MDEV-25339 Assertion `thd->transaction.stmt.is_empty() || thd->in_sub_stmt' failed
+#
+create or replace table t1 (x int) with system versioning engine innodb
+partition by system_time interval 1 hour auto;
+start transaction;
+insert into t1 values (1);
+select * from t1;
+x
+1
+connect con1, localhost, root;
+set lock_wait_timeout= 1;
+set innodb_lock_wait_timeout= 1;
+update t1 set x= x + 111;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+select * from t1;
+x
+disconnect con1;
+connection default;
+drop table t1;
+#
+# MDEV-25482 Auto-create: Server hangs after a failed attempt to create partition
+#
+set timestamp= default;
+create table t (pk int primary key, a int) engine=InnoDB
+with system versioning partition by system_time interval 1 hour auto;
+insert into t values (1,1),(2,2),(3,3),(4,4),(5,5);
+start transaction;
+update t set a= 20 where pk = 2;
+connect con1,localhost,root,,;
+set lock_wait_timeout= 1;
+set @@timestamp= @@timestamp+3601;
+update t set a= 40 where pk = 4;
+Warnings:
+Error 1205 Lock wait timeout exceeded; try restarting transaction
+Warning 4114 Versioned table `test`.`t`: last HISTORY partition (`p0`) is out of INTERVAL, need more HISTORY partitions
+update t set a= 400 where pk = 4;
+Warnings:
+Error 1205 Lock wait timeout exceeded; try restarting transaction
+Warning 4114 Versioned table `test`.`t`: last HISTORY partition (`p0`) is out of INTERVAL, need more HISTORY partitions
+disconnect con1;
+connection default;
+select * from t where pk = 4;
+pk a
+4 400
+rollback;
+drop tables t;
diff --git a/mysql-test/suite/versioning/t/delete_history.test b/mysql-test/suite/versioning/t/delete_history.test
index e3b60011644..9ab4225feed 100644
--- a/mysql-test/suite/versioning/t/delete_history.test
+++ b/mysql-test/suite/versioning/t/delete_history.test
@@ -191,4 +191,18 @@ select * from t1;
drop prepare stmt;
drop table t1;
+--echo #
+--echo # MDEV-17554 Auto-create new partition for system versioned tables with history partitioned by INTERVAL/LIMIT
+--echo #
+--echo # Don't auto-create new partition on DELETE HISTORY:
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
+create or replace table t (a int) with system versioning
+partition by system_time interval 1 hour auto;
+set timestamp= unix_timestamp('2000-01-01 10:00:00');
+delete history from t;
+set timestamp= default;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t;
+drop table t;
+
--source suite/versioning/common_finish.inc
diff --git a/mysql-test/suite/versioning/t/load_data.test b/mysql-test/suite/versioning/t/load_data.test
index 3bac2942a81..d4a1fa1a736 100644
--- a/mysql-test/suite/versioning/t/load_data.test
+++ b/mysql-test/suite/versioning/t/load_data.test
@@ -1,6 +1,7 @@
#
# MDEV-15330 Server crash or assertion `table->insert_values' failure in write_record upon LOAD DATA
#
+--let $datadir= `select @@datadir`
CREATE TABLE t1 (a INT, b INT, c INT, vc INT AS (c), UNIQUE(a), UNIQUE(b)) WITH SYSTEM VERSIONING;
INSERT IGNORE INTO t1 (a,b,c) VALUES (1,2,3);
@@ -12,3 +13,4 @@ LOAD DATA INFILE '15330.data' REPLACE INTO TABLE t1 (a,b,c);
# Cleanup
DROP TABLE t1;
+--remove_file $datadir/test/15330.data
diff --git a/mysql-test/suite/versioning/t/truncate_privilege.test b/mysql-test/suite/versioning/t/not_embedded.test
index dcdad59039a..d63c7bd4476 100644
--- a/mysql-test/suite/versioning/t/truncate_privilege.test
+++ b/mysql-test/suite/versioning/t/not_embedded.test
@@ -1,7 +1,10 @@
-# Can't test with embedded server
--- source include/not_embedded.inc
-
+--source include/not_embedded.inc
--source include/have_innodb.inc
+--source include/have_partition.inc
+
+--echo #
+--echo # DELETE HISTORY and privileges
+--echo #
# Save the initial number of concurrent sessions
--source include/count_sessions.inc
@@ -39,3 +42,33 @@ show grants for mysqltest_1@localhost;
drop user mysqltest_1@localhost;
drop database mysqltest;
+--disconnect user1
+--disconnect root
+--connection default
+
+--echo #
+--echo # MDEV-25559 Auto-create: infinite loop after interrupted lock wait
+--echo #
+
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
+create table t (pk int primary key, a int) engine innodb with system versioning
+partition by system_time interval 1 hour auto;
+insert into t values (1, 0);
+begin;
+update t set a= a + 1;
+--connect (con1,localhost,root,,)
+set max_statement_time= 1;
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+send update t set a= a + 2;
+--connection default
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+send update t set a= a + 3;
+--connection con1
+--error ER_STATEMENT_TIMEOUT
+reap;
+--disconnect con1
+--connection default
+reap;
+commit;
+drop table t;
+set timestamp= default;
diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test
index ce41e0c96b3..4110247c21f 100644
--- a/mysql-test/suite/versioning/t/partition.test
+++ b/mysql-test/suite/versioning/t/partition.test
@@ -10,6 +10,7 @@ call mtr.add_suppression("need more HISTORY partitions");
--enable_prepare_warnings
set system_versioning_alter_history=keep;
+--let $datadir= `select @@datadir`
--echo # Check conventional partitioning on temporal tables
--replace_result $sys_datatype_expl SYS_DATATYPE
@@ -218,7 +219,9 @@ prepare stmt from @str; execute stmt; drop prepare stmt;
select @ts0 = @ts1;
select @ts2 = @ts3;
---echo ## rotation by LIMIT
+--echo #
+--echo # Rotation by LIMIT
+--echo #
--error ER_PART_WRONG_VALUE
create or replace table t1 (x int)
with system versioning
@@ -246,8 +249,9 @@ insert into t1 values (7), (8);
delete from t1;
select * from t1 partition (p1) order by x;
-
---echo ## rotation by INTERVAL
+--echo #
+--echo # Rotation by INTERVAL
+--echo #
--error ER_PART_WRONG_VALUE
create or replace table t1 (x int)
with system versioning
@@ -291,7 +295,8 @@ insert t1 values (1); delete from t1;
set timestamp=unix_timestamp('2001-02-04 10:20:50');
insert t1 values (2); delete from t1;
-select subpartition_name,partition_description,table_rows from information_schema.partitions where table_schema='test' and table_name='t1';
+select subpartition_name, partition_description, table_rows from information_schema.partitions where table_schema='test' and table_name='t1';
+select * from t1 partition (p1);
set timestamp=unix_timestamp('2001-02-04 10:20:55');
alter table t1 add partition (partition p0 history, partition p2 history);
@@ -300,7 +305,15 @@ 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';
+select subpartition_name, partition_description, table_rows from information_schema.partitions where table_schema='test' and table_name='t1';
+select * from t1 partition (p1);
+select * from t1 partition (p0);
+select * from t1 partition (p2);
+
+alter table t1 rebuild partition p0, p1, p2;
+select * from t1 partition (p1);
+select * from t1 partition (p0);
+select * from t1 partition (p2);
--echo ## pruning check
set @ts=(select partition_description from information_schema.partitions
@@ -431,7 +444,6 @@ create or replace table t1 (i int) with system versioning
partition by system_time interval 1 day starts '2000-01-01 00:00:00'
partitions 3;
---echo # we are warned when we push to present:
insert into t1 values (0);
set timestamp= unix_timestamp('2001-01-01 00:00:01');
update t1 set i= i + 1;
@@ -460,8 +472,8 @@ update t1 set i= i + 1;
select *, row_end from t1 partition (p0);
select *, row_end from t1 partition (p1);
-set timestamp= unix_timestamp('2000-01-01 00:00:00');
--echo # and this is how it usually goes:
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
create or replace table t1 (i int) with system versioning
partition by system_time interval 1 day
partitions 3;
@@ -477,7 +489,6 @@ set timestamp= unix_timestamp('2000-01-04 00:00:01');
update t1 set i= i + 1;
alter table t1 add partition (partition p2 history, partition p3 history);
-
select *, row_end from t1 partition (p0);
select *, row_end from t1 partition (p1);
select *, row_end from t1 partition (p2);
@@ -496,9 +507,9 @@ insert into t1 (x) values (1), (2), (3), (4), (5);
select * from t1 partition (pnsp0);
select * from t1 partition (pnsp1);
---echo ### warn about full partition
delete from t1 where x < 3;
delete from t1;
+--echo ### warn about full partition
delete from t1;
select * from t1 partition (p0sp0);
select * from t1 partition (p0sp1);
@@ -976,16 +987,15 @@ create or replace table t1 (
insert into t1 () values (),(),(),(),(),(),(),(),(),(),(),(),(),(),(),();
-select * into outfile 'load.data' from t1;
-load data infile 'load.data' replace into table t1;
+select * into outfile 'MDEV-17891.data' from t1;
+load data infile 'MDEV-17891.data' replace into table t1;
--error ER_RECORD_FILE_FULL
-load data infile 'load.data' replace into table t1;
+load data infile 'MDEV-17891.data' replace into table t1;
--error ER_RECORD_FILE_FULL
-load data infile 'load.data' replace into table t1;
+load data infile 'MDEV-17891.data' replace into table t1;
# Cleanup
---let $datadir= `select @@datadir`
---remove_file $datadir/test/load.data
+--remove_file $datadir/test/MDEV-17891.data
eval set @@max_heap_table_size= $max_heap_table_size_orig;
drop table t1;
@@ -1095,18 +1105,7 @@ alter table t1 add partition partitions 2;
--replace_result $default_engine DEFAULT_ENGINE
show create table t1;
alter table t1 add partition partitions 8;
---replace_result $default_engine DEFAULT_ENGINE
-show create table t1;
-
-drop tables t1;
-
---disable_prepare_warnings
-
---echo #
---echo # End of 10.5 tests
---echo #
-
-SET GLOBAL innodb_stats_persistent=@save_persistent;
+drop table t1;
--echo # End of 10.6 tests
@@ -1309,4 +1308,567 @@ show create table t1;
drop tables t1, tp1;
}
+--echo #
+--echo # MDEV-17554 Auto-create new partition for system versioned tables with history partitioned by INTERVAL/LIMIT
+--echo #
+create or replace table t1 (x int) with system versioning
+partition by system_time limit 1 auto;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+insert into t1 values (1);
+
+create or replace table t2 (y int);
+insert into t2 values (2);
+
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+--echo # Too many partitions error
+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;
+set timestamp= unix_timestamp('2001-01-01 00:01:00');
+--error ER_VERS_HIST_PART_FAILED
+update t1 set x= x + 1;
+show warnings;
+
+--echo # Auto-create failed error
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
+create or replace table t1 (x int) with system versioning engine innodb
+partition by system_time interval 1 hour auto;
+
+insert into t1 values (1);
+
+call mtr.add_suppression("rror number .*(File exists|file operation)");
+call mtr.add_suppression("InnoDB: Cannot create file");
+
+--let $datadir= `select @@datadir`
+--let $dummy= $datadir/test/t1#P#p1.ibd
+--write_file $dummy
+EOF
+
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+--error ER_GET_ERRNO
+update t1 set x= x + 2;
+show warnings;
+--remove_file $dummy
+
+--echo # Partition overflow error and manual fix
+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;
+
+insert into t1 values (440);
+set timestamp= unix_timestamp('2000-01-01 00:10:00');
+update t1 set x= x + 1;
+
+--echo # Check how pruning boundaries work
+--replace_column 5 # 10 # 11 #
+explain partitions select * from t1 for system_time as of '2000-01-01 00:59:58';
+--replace_column 5 # 10 # 11 #
+explain partitions select * from t1 for system_time as of '2000-01-01 00:59:59';
+--replace_column 5 # 10 # 11 #
+explain partitions select * from t1 for system_time as of '2000-01-01 01:00:00';
+select * from t1 for system_time as of '2000-01-01 00:09:59';
+
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+update t1 set x= x + 1;
+
+select * from t1 for system_time as of '2000-01-01 01:00:00';
+select * from t1 partition (p0) order by x;
+
+--echo # Here is how manual fix works: just add new partitions there
+alter table t1 add partition partitions 3;
+select * from t1 for system_time as of '2000-01-01 01:00:00';
+select * from t1 partition (p0) order by x;
+
+--echo # Check pruning after ALTER
+--replace_column 5 # 10 # 11 #
+explain partitions select * from t1 for system_time as of '2000-01-01 00:59:58';
+--replace_column 5 # 10 # 11 #
+explain partitions select * from t1 for system_time as of '2000-01-01 00:59:59';
+--replace_column 5 # 10 # 11 #
+explain partitions select * from t1 for system_time as of '2000-01-01 01:00:00';
+
+drop table t1;
+
+--enable_info
+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 partitions 3;
+
+insert into t1 values (1);
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+update t1 set x= x + 1;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+set timestamp= unix_timestamp('2000-01-01 03:00:00');
+update t1 set x= x + 2;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+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 (
+ partition p1 history,
+ partition p3 history,
+ partition pn current);
+
+insert into t1 values (1);
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+update t1 set x= x + 3;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+set timestamp= unix_timestamp('2000-01-01 03:00:00');
+update t1 set x= x + 4;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+set timestamp= unix_timestamp('2000-01-01 04:00:00');
+lock tables t1 write;
+update t1 set x= x + 5;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+unlock tables;
+set timestamp= default;
+
+--echo # Couple of more LOCK TABLES cases
+create or replace table t1 (x int) with system versioning
+partition by system_time limit 1 auto;
+lock tables t1 write;
+insert into t1 values (1);
+update t1 set x= x + 1;
+update t1 set x= x + 1;
+update t1 set x= x + 1;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+unlock tables;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+--echo # Overflow prevention under LOCK TABLES
+create or replace table t1 (x int)
+with system versioning partition by system_time
+limit 10 auto;
+
+insert into t1 values (1), (2), (3), (4), (5), (6), (7), (8), (9);
+update t1 set x= x + 10;
+
+lock tables t1 write;
+update t1 set x= 1 where x = 11;
+update t1 set x= 2 where x = 12;
+update t1 set x= 3 where x = 13;
+unlock tables;
+
+select count(x) from t1 partition (p0);
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+drop tables t1;
+
+--echo # Test VIEW, LOCK TABLES
+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;
+create or replace view v1 as select * from t1;
+
+insert into t1 values (1);
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+update v1 set x= x + 2;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+lock tables v1 write;
+update v1 set x= x + 3;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+unlock tables;
+
+drop view v1;
+drop tables t1;
+
+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 partitions 3;
+
+create or replace table t2 (y int) with system versioning
+partition by system_time interval 1 hour auto;
+
+insert into t1 values (1);
+insert into t2 values (2);
+
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+update t1, t2 set x= x + 1, y= y + 1;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t2;
+
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+update t1, t2 set x= x + 1, y= y + 1;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t2;
+
+set timestamp= unix_timestamp('2000-01-01 03:00:00');
+update t1, t2 set t1.x= 0 where t1.x< t2.y;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+# Multiupdate_prelocking_strategy::handle_end() is processed after table open.
+# For PS it is possible to skip unneeded auto-creation because the above happens at
+# prepare stage and auto-creation is done at execute stage.
+--replace_result $default_engine DEFAULT_ENGINE 'PARTITIONS 4' 'PARTITIONS ok' 'PARTITIONS 5' 'PARTITIONS ok'
+show create table t2;
+
+drop tables t1, t2;
+
+--echo # PS, SP, LOCK TABLES
+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;
+
+insert into t1 values (1);
+
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+execute immediate 'update t1 set x= x + 5';
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+prepare s from 'update t1 set x= x + 6';
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+execute s; execute s;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+set timestamp= unix_timestamp('2000-01-01 03:00:00');
+lock tables t1 write;
+execute s; execute s;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+unlock tables;
+drop prepare s;
+
+create procedure sp() update t1 set x= x + 7;
+set timestamp= unix_timestamp('2000-01-01 04:00:00');
+call sp; call sp;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+set timestamp= unix_timestamp('2000-01-01 05:00:00');
+lock tables t1 write;
+call sp; call sp;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+unlock tables;
+drop procedure sp;
+
+set timestamp= unix_timestamp('2001-01-01 00:00:00');
+create or replace table t1 (i int) with system versioning
+partition by system_time interval 1 day starts '2001-01-01 00:00:00';
+insert into t1 values (0);
+set timestamp= unix_timestamp('2001-01-01 00:00:01');
+prepare s from 'update t1 set i= i + 1';
+execute s;
+set timestamp= unix_timestamp('2001-01-02 00:00:01');
+execute s;
+drop prepare s;
+
+# Because of blobs:
+if (!$MTR_COMBINATION_HEAP)
+{
+--echo # Complex table
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
+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 (
+ partition p2 history,
+ partition pn current);
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+insert into t1 (x, c, u, i1, i2, i3, ps, pe)
+values (1, 'cc', 0, 1, 2, 3, '1999-01-01', '2000-01-01');
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+update t1 set x= x + 8;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+update t1 set x= x - 8;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+}
+--disable_info
+
+--echo # INSERT .. ON DUPLICATE KEY UPDATE (ODKU)
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
+create or replace table t1 (x int primary key) with system versioning
+partition by system_time interval 1 hour auto;
+insert into t1 values (1);
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+insert into t1 values (1) on duplicate key update x= x + 1;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+--echo # LOAD DATA .. REPLACE
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
+create or replace table t1 (x int primary key) with system versioning
+partition by system_time interval 1 hour auto;
+
+insert t1 values (1), (2), (3);
+select x into outfile 'MDEV-17554.data' from t1;
+
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+load data infile 'MDEV-17554.data' replace into table t1 (x);
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+--remove_file $datadir/test/MDEV-17554.data
+
+--echo # 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 partitions 3;
+
+insert into t1 values (1);
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+--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 02:00:00');
+send update t1 set x= x + 10;
+--connection con2
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+send update t1 set x= x + 20;
+--connection con3
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+send update t1 set x= x + 30;
+--connection con4
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+send update t1 set x= x + 40;
+--connection con5
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+send update t1 set x= x + 50;
+--connection con6
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+send update t1 set x= x + 60;
+--connection con7
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+send update t1 set x= x + 70;
+--connection con8
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+update t1 set x= x + 80;
+--connection con1
+reap;
+--disconnect con1
+--connection con2
+reap;
+--disconnect con2
+--connection con3
+reap;
+--disconnect con3
+--connection con4
+reap;
+--disconnect con4
+--connection con5
+reap;
+--disconnect con5
+--connection con6
+reap;
+--disconnect con6
+--connection con7
+reap;
+--disconnect con7
+--disconnect con8
+--connection default
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+drop tables t1;
+set timestamp= default;
+
+--echo # Transaction
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
+create or replace table t1 (x int) with system versioning engine innodb
+partition by system_time interval 1 hour auto;
+
+insert into t1 values (1);
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+start transaction;
+update t1 set x= 0;
+--connect con1, localhost, root
+select * from t1;
+show create table t1;
+--connection default
+commit;
+show create table t1;
+
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+start transaction;
+update t1 set x= 1;
+--connection con1
+select * from t1;
+--connection default
+rollback;
+show create table t1;
+--disconnect con1
+--connection default
+drop table t1;
+
+--echo #
+--echo # MDEV-25479 Auto-create: 2nd and further executions of PS or SP fail to create partition
+--echo #
+create table t (a int) with system versioning
+ partition by system_time interval 1 hour auto;
+
+insert into t values (1), (2);
+prepare stmt from "update t set a= a + 1";
+set @@timestamp= @@timestamp + 3601;
+execute stmt;
+set @@timestamp= @@timestamp + 3601;
+execute stmt;
+drop prepare stmt;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t;
+
+create procedure sp() update t set a= a + 1;
+set @@timestamp= @@timestamp + 3601;
+call sp();
+set @@timestamp= @@timestamp + 3601;
+call sp();
+drop procedure sp;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t;
+
+# Cleanup
+drop table t;
+
+--echo #
+--echo # MDEV-23639 Auto-create does not work under LOCK TABLES or inside triggers
+--echo #
+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
+partitions 3;
+
+create table t2 (x int);
+create table t3 (x int);
+insert into t3 values (3);
+
+create trigger tr after insert on t2 for each row update t1 set x= x + 11;
+create or replace procedure sp() update t1 set x= x + 5;
+create or replace procedure sp2() insert into t2 values (5);
+prepare ps from 'update t1 set x= x + 6';
+prepare ps2 from 'insert into t2 values (6)';
+
+insert into t1 values (1);
+set timestamp= unix_timestamp('2000-01-01 02:00:00');
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+insert into t2 values (2);
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+set timestamp= unix_timestamp('2000-01-01 03:00:00');
+call sp; call sp;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+set timestamp= unix_timestamp('2000-01-01 04:00:00');
+call sp2; call sp2;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+set timestamp= unix_timestamp('2000-01-01 05:00:00');
+execute ps; execute ps;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+set timestamp= unix_timestamp('2000-01-01 06:00:00');
+execute ps2; execute ps2;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+set timestamp= unix_timestamp('2000-01-01 08:00:00');
+lock tables t1 write, t2 write;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+set timestamp= unix_timestamp('2000-01-01 09:00:00');
+update t1 set x= x + 1;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+set timestamp= unix_timestamp('2000-01-01 10:00:00');
+update t1 set x= x + 2;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+update t2 set x= x + 1;
+set timestamp= unix_timestamp('2000-01-01 11:00:00');
+insert into t2 values (4);
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+--error ER_TABLE_NOT_LOCKED
+update t3 set x= x + 1;
+
+set timestamp= unix_timestamp('2000-01-01 12:00:00');
+call sp; call sp;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+set timestamp= unix_timestamp('2000-01-01 13:00:00');
+call sp2; call sp2;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+set timestamp= unix_timestamp('2000-01-01 14:00:00');
+execute ps; execute ps;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+set timestamp= unix_timestamp('2000-01-01 15:00:00');
+execute ps2; execute ps2;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+unlock tables;
+--replace_result $default_engine DEFAULT_ENGINE
+show create table t1;
+
+# Cleanup
+drop tables t1, t2, t3;
+drop procedure sp;
+drop procedure sp2;
+drop prepare ps;
+drop prepare ps2;
+
+--disable_prepare_warnings
+SET GLOBAL innodb_stats_persistent=@save_persistent;
--source suite/versioning/common_finish.inc
diff --git a/mysql-test/suite/versioning/t/rpl.test b/mysql-test/suite/versioning/t/rpl.test
index b5be68feece..0d0a50f71da 100644
--- a/mysql-test/suite/versioning/t/rpl.test
+++ b/mysql-test/suite/versioning/t/rpl.test
@@ -133,4 +133,22 @@ sync_slave_with_master;
connection master;
drop table t1;
+--echo #
+--echo # MDEV-17554 Auto-create new partition for system versioned tables with history partitioned by INTERVAL/LIMIT
+--echo #
+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;
+insert t1 values ();
+set timestamp= unix_timestamp('2000-01-01 01:00:00');
+delete from t1;
+--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE
+show create table t1;
+--sync_slave_with_master
+--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE
+show create table t1;
+--connection master
+drop table t1;
+set timestamp= default;
+
--source include/rpl_end.inc
diff --git a/mysql-test/suite/versioning/t/rpl_common.inc b/mysql-test/suite/versioning/t/rpl_common.inc
new file mode 100644
index 00000000000..c37e58f0f96
--- /dev/null
+++ b/mysql-test/suite/versioning/t/rpl_common.inc
@@ -0,0 +1,29 @@
+--source include/have_partition.inc
+
+--echo #
+--echo # MDEV-25347 DML events for auto-partitioned tables are written into binary log twice
+--echo #
+flush binary logs;
+create table t1 (a int) with system versioning
+partition by system_time limit 1 auto;
+
+insert into t1 values (1);
+update t1 set a= a + 1;
+update t1 set a= a + 2;
+--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE
+show create table t1;
+select * from t1;
+
+--let $binlog_file=master-bin.000002
+--source include/show_binlog_events.inc
+
+--sync_slave_with_master
+--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE
+show create table t1;
+
+select * from t1;
+--connection master
+# cleanup
+drop table t1;
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/versioning/t/rpl_mix.test b/mysql-test/suite/versioning/t/rpl_mix.test
index 64025c74625..bf4e0b93422 100644
--- a/mysql-test/suite/versioning/t/rpl_mix.test
+++ b/mysql-test/suite/versioning/t/rpl_mix.test
@@ -16,4 +16,4 @@ DELETE HISTORY FROM t1;
connection master;
drop table t1;
---source include/rpl_end.inc
+--source rpl_common.inc
diff --git a/mysql-test/suite/versioning/t/rpl_row.test b/mysql-test/suite/versioning/t/rpl_row.test
index 17ce2dfdcf8..a9b12e52a41 100644
--- a/mysql-test/suite/versioning/t/rpl_row.test
+++ b/mysql-test/suite/versioning/t/rpl_row.test
@@ -15,4 +15,4 @@ update t1 set i = 0;
drop table t1;
set binlog_row_image= @old_row_image;
---source include/rpl_end.inc
+--source rpl_common.inc
diff --git a/mysql-test/suite/versioning/t/rpl_stmt.test b/mysql-test/suite/versioning/t/rpl_stmt.test
new file mode 100644
index 00000000000..dca4e8cb4a2
--- /dev/null
+++ b/mysql-test/suite/versioning/t/rpl_stmt.test
@@ -0,0 +1,4 @@
+--source include/have_binlog_format_statement.inc
+--source include/master-slave.inc
+
+--source rpl_common.inc
diff --git a/mysql-test/suite/versioning/t/update-big.test b/mysql-test/suite/versioning/t/update-big.test
index 175bfc79a48..98767cefaad 100644
--- a/mysql-test/suite/versioning/t/update-big.test
+++ b/mysql-test/suite/versioning/t/update-big.test
@@ -1,6 +1,7 @@
source include/big_test.inc;
source suite/versioning/engines.inc;
source suite/versioning/common.inc;
+source include/have_partition.inc;
--echo #
--echo # MDEV-15458 Segfault in heap_scan() upon UPDATE after ADD SYSTEM VERSIONING
@@ -29,6 +30,79 @@ update t1 set a= 8 where a = 1;
update t1 set a= 4 where a = 8;
update t1 set a= 6;
+--disconnect con1
drop table t1;
+call mtr.add_suppression("need more HISTORY partitions");
+
+--echo #
+--echo # MDEV-23642 Locking timeout caused by auto-creation affects original DML
+--echo #
+set timestamp= unix_timestamp('2000-01-01 00:00:00');
+create or replace table t1 (x int primary key) with system versioning engine innodb
+partition by system_time interval 1 hour auto;
+
+insert into t1 values (1);
+start transaction;
+insert into t1 values (2);
+
+--connect con1, localhost, root
+set lock_wait_timeout= 1;
+set innodb_lock_wait_timeout= 1;
+set timestamp= unix_timestamp('2000-01-01 01:00:01');
+update t1 set x= x + 122 where x = 1;
+--disconnect con1
+--connection default
+select * from t1;
+
+# cleanup
+drop table t1;
+set timestamp= default;
+
+--echo #
+--echo # MDEV-25339 Assertion `thd->transaction.stmt.is_empty() || thd->in_sub_stmt' failed
+--echo #
+create or replace table t1 (x int) with system versioning engine innodb
+partition by system_time interval 1 hour auto;
+start transaction;
+insert into t1 values (1);
+select * from t1;
+
+--connect con1, localhost, root
+set lock_wait_timeout= 1;
+set innodb_lock_wait_timeout= 1;
+--error ER_LOCK_WAIT_TIMEOUT
+update t1 set x= x + 111;
+select * from t1;
+
+# cleanup
+--disconnect con1
+--connection default
+drop table t1;
+
+--echo #
+--echo # MDEV-25482 Auto-create: Server hangs after a failed attempt to create partition
+--echo #
+set timestamp= default;
+create table t (pk int primary key, a int) engine=InnoDB
+ with system versioning partition by system_time interval 1 hour auto;
+
+insert into t values (1,1),(2,2),(3,3),(4,4),(5,5);
+
+start transaction;
+update t set a= 20 where pk = 2;
+
+--connect (con1,localhost,root,,)
+set lock_wait_timeout= 1;
+set @@timestamp= @@timestamp+3601;
+update t set a= 40 where pk = 4;
+update t set a= 400 where pk = 4;
+
+# Cleanup
+--disconnect con1
+--connection default
+select * from t where pk = 4;
+rollback;
+drop tables t;
+
source suite/versioning/common_finish.inc;
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index f17abed82ff..9ab9f2a9552 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -4097,18 +4097,9 @@ int ha_partition::external_lock(THD *thd, int lock_type)
(void) (*file)->ha_external_lock(thd, lock_type);
} while (*(++file));
}
- if (lock_type == F_WRLCK)
- {
- if (m_part_info->part_expr)
- m_part_info->part_expr->walk(&Item::register_field_in_read_map, 1, 0);
- if (m_part_info->part_type == VERSIONING_PARTITION &&
- /* TODO: MDEV-20345 exclude more inapproriate commands like INSERT
- These commands may be excluded because working history partition is needed
- only for versioned DML. */
- thd->lex->sql_command != SQLCOM_SELECT &&
- thd->lex->sql_command != SQLCOM_INSERT_SELECT)
- m_part_info->vers_set_hist_part(thd);
- }
+ if (lock_type == F_WRLCK && m_part_info->part_expr)
+ m_part_info->part_expr->walk(&Item::register_field_in_read_map, 1, 0);
+
DBUG_RETURN(0);
err_handler:
@@ -4252,11 +4243,6 @@ int ha_partition::start_stmt(THD *thd, thr_lock_type lock_type)
{
if (m_part_info->part_expr)
m_part_info->part_expr->walk(&Item::register_field_in_read_map, 1, 0);
- if (m_part_info->part_type == VERSIONING_PARTITION &&
- // TODO: MDEV-20345 (see above)
- thd->lex->sql_command != SQLCOM_SELECT &&
- thd->lex->sql_command != SQLCOM_INSERT_SELECT)
- m_part_info->vers_set_hist_part(thd);
}
DBUG_RETURN(error);
}
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 14f68b36c0b..90c556635a3 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -1608,6 +1608,13 @@ public:
}
bool partition_engine() override { return 1;}
+
+ /**
+ Get the number of records in part_elem and its subpartitions, if any.
+ Also sets read_partitions bit for each partition id it uses (that is needed
+ for vers_set_hist_part() because it is called before read_partitions bitmap
+ is initialized).
+ */
ha_rows part_records(partition_element *part_elem)
{
DBUG_ASSERT(m_part_info);
@@ -1619,7 +1626,7 @@ public:
for (; part_id < part_id_end; ++part_id)
{
handler *file= m_file[part_id];
- DBUG_ASSERT(bitmap_is_set(&(m_part_info->read_partitions), part_id));
+ bitmap_set_bit(&(m_part_info->read_partitions), part_id);
file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_OPEN);
part_recs+= file->stats.records;
}
diff --git a/sql/handler.cc b/sql/handler.cc
index 57992d98c04..cf3abe06f38 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1635,9 +1635,10 @@ int ha_commit_trans(THD *thd, bool all)
DBUG_ASSERT(thd->transaction->stmt.ha_list == NULL ||
trans == &thd->transaction->stmt);
+ DBUG_ASSERT(!thd->in_sub_stmt);
+
if (thd->in_sub_stmt)
{
- DBUG_ASSERT(0);
/*
Since we don't support nested statement transactions in 5.0,
we can't commit or rollback stmt transactions while we are inside
diff --git a/sql/handler.h b/sql/handler.h
index fe61666bf20..40f5eb0f1ab 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -832,6 +832,8 @@ typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*);
#define ALTER_PARTITION_TABLE_REORG (1ULL << 12)
#define ALTER_PARTITION_CONVERT_IN (1ULL << 13)
#define ALTER_PARTITION_CONVERT_OUT (1ULL << 14)
+// Set for vers_add_auto_hist_parts() operation
+#define ALTER_PARTITION_AUTO_HIST (1ULL << 15)
/*
This is master database for most of system tables. However there
@@ -2148,7 +2150,6 @@ struct Vers_parse_info: public Table_period_info
Table_period_info::start_end_t as_row;
-protected:
friend struct Table_scope_and_contents_source_st;
void set_start(const LEX_CSTRING field_name)
{
@@ -2160,6 +2161,8 @@ protected:
as_row.end= field_name;
period.end= field_name;
}
+
+protected:
bool is_start(const char *name) const;
bool is_end(const char *name) const;
bool is_start(const Create_field &f) const;
@@ -4257,6 +4260,8 @@ public:
*/
virtual uint lock_count(void) const { return 1; }
/**
+ Get the lock(s) for the table and perform conversion of locks if needed.
+
Is not invoked for non-transactional temporary tables.
@note store_lock() can return more than one lock if the table is MERGE
diff --git a/sql/lock.cc b/sql/lock.cc
index 2eba5df35f1..bfa3e7baa0f 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -654,7 +654,7 @@ bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
a and b are freed with my_free()
*/
-MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
+MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a, MYSQL_LOCK *b, THD *thd)
{
MYSQL_LOCK *sql_lock;
TABLE **table, **end_table;
@@ -662,16 +662,28 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
DBUG_PRINT("enter", ("a->lock_count: %u b->lock_count: %u",
a->lock_count, b->lock_count));
- if (!(sql_lock= (MYSQL_LOCK*)
- my_malloc(key_memory_MYSQL_LOCK, sizeof(*sql_lock) +
- sizeof(THR_LOCK_DATA*)*((a->lock_count+b->lock_count)*2) +
- sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME))))
- DBUG_RETURN(0); // Fatal error
+ const size_t lock_size= sizeof(*sql_lock) +
+ sizeof(THR_LOCK_DATA *) * ((a->lock_count + b->lock_count) * 2) +
+ sizeof(TABLE *) * (a->table_count + b->table_count);
+ if (thd)
+ {
+ sql_lock= (MYSQL_LOCK *) thd->alloc(lock_size);
+ if (!sql_lock)
+ DBUG_RETURN(0);
+ sql_lock->flags= GET_LOCK_ON_THD;
+ }
+ else
+ {
+ sql_lock= (MYSQL_LOCK *)
+ my_malloc(key_memory_MYSQL_LOCK, lock_size, MYF(MY_WME));
+ if (!sql_lock)
+ DBUG_RETURN(0);
+ sql_lock->flags= 0;
+ }
sql_lock->lock_count=a->lock_count+b->lock_count;
sql_lock->table_count=a->table_count+b->table_count;
sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count*2);
- sql_lock->flags= 0;
memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
memcpy(sql_lock->locks+a->lock_count,b->locks,
b->lock_count*sizeof(*b->locks));
@@ -705,8 +717,10 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
a->lock_count, b->lock_count);
/* Delete old, not needed locks */
- my_free(a);
- my_free(b);
+ if (!(a->flags & GET_LOCK_ON_THD))
+ my_free(a);
+ if (!(b->flags & GET_LOCK_ON_THD))
+ my_free(b);
DBUG_RETURN(sql_lock);
}
diff --git a/sql/lock.h b/sql/lock.h
index 0b23ddd3846..85a93b9a7e3 100644
--- a/sql/lock.h
+++ b/sql/lock.h
@@ -34,7 +34,7 @@ int mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
int mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag);
int mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table);
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table);
-MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b);
+MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a, MYSQL_LOCK *b, THD *thd= NULL);
/* Lock based on name */
bool lock_schema_name(THD *thd, const char *db);
/* Lock based on stored routine name */
diff --git a/sql/log_event.cc b/sql/log_event.cc
index afca79b008a..5206b1834fe 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -4108,3 +4108,16 @@ bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache, FILE *file)
return (my_b_copy_all_to_file(cache, file) ||
reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE));
}
+
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+int Log_event::apply_event(rpl_group_info* rgi)
+{
+ int res;
+ THD_STAGE_INFO(thd, stage_apply_event);
+ rgi->current_event= this;
+ res= do_apply_event(rgi);
+ rgi->current_event= NULL;
+ THD_STAGE_INFO(thd, stage_after_apply_event);
+ return res;
+}
+#endif
diff --git a/sql/log_event.h b/sql/log_event.h
index 3adc7a26d93..e2479724972 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -1509,14 +1509,7 @@ public:
@see do_apply_event
*/
- int apply_event(rpl_group_info *rgi)
- {
- int res;
- THD_STAGE_INFO(thd, stage_apply_event);
- res= do_apply_event(rgi);
- THD_STAGE_INFO(thd, stage_after_apply_event);
- return res;
- }
+ int apply_event(rpl_group_info *rgi);
/**
diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc
index 2e4992a021e..179d1f067f0 100644
--- a/sql/log_event_server.cc
+++ b/sql/log_event_server.cc
@@ -5475,6 +5475,18 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
lex->query_tables_last= &tables->next_global;
}
}
+
+ /*
+ It is needed to set_time():
+ 1) it continues the property that "Time" in SHOW PROCESSLIST shows how
+ much slave is behind
+ 2) it will be needed when we allow replication from a table with no
+ TIMESTAMP column to a table with one.
+ So we call set_time(), like in SBR. Presently it changes nothing.
+ 3) vers_set_hist_part() requires proper query time.
+ */
+ thd->set_time(when, when_sec_part);
+
if (unlikely(open_and_lock_tables(thd, rgi->tables_to_lock, FALSE, 0)))
{
#ifdef WITH_WSREP
@@ -5651,16 +5663,6 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
which tested replicate-* rules).
*/
- /*
- It's not needed to set_time() but
- 1) it continues the property that "Time" in SHOW PROCESSLIST shows how
- much slave is behind
- 2) it will be needed when we allow replication from a table with no
- TIMESTAMP column to a table with one.
- So we call set_time(), like in SBR. Presently it changes nothing.
- */
- thd->set_time(when, when_sec_part);
-
if (m_width == table->s->fields && bitmap_is_set_all(&m_cols))
set_flags(COMPLETE_ROWS_F);
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index 62a3092f369..23194e43d06 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -38,6 +38,8 @@
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
+#include "sql_table.h"
+#include "transaction.h"
partition_info *partition_info::get_clone(THD *thd)
@@ -324,13 +326,11 @@ bool partition_info::set_partition_bitmaps_from_table(TABLE_LIST *table_list)
The external routine needing this code is check_partition_info
*/
-#define MAX_PART_NAME_SIZE 8
-
char *partition_info::create_default_partition_names(THD *thd, uint part_no,
uint num_parts_arg,
uint start_no)
{
- char *ptr= (char*) thd->calloc(num_parts_arg * MAX_PART_NAME_SIZE);
+ char *ptr= (char*) thd->calloc(num_parts_arg * MAX_PART_NAME_SIZE + 1);
char *move_ptr= ptr;
uint i= 0;
DBUG_ENTER("create_default_partition_names");
@@ -819,10 +819,15 @@ bool partition_info::has_unique_name(partition_element *element)
vers_info->interval Limit by fixed time interval
vers_info->hist_part (out) Working history partition
*/
-void partition_info::vers_set_hist_part(THD *thd)
+bool partition_info::vers_set_hist_part(THD *thd, uint *create_count)
{
+ DBUG_ASSERT(!thd->lex->last_table() ||
+ !thd->lex->last_table()->vers_conditions.delete_history);
+ const bool auto_hist= create_count && vers_info->auto_hist;
+
if (vers_info->limit)
{
+ DBUG_ASSERT(!vers_info->interval.is_set());
ha_partition *hp= (ha_partition*)(table->file);
partition_element *next= NULL;
List_iterator<partition_element> it(partitions);
@@ -841,22 +846,22 @@ void partition_info::vers_set_hist_part(THD *thd)
{
if (next == vers_info->now_part)
{
- 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, "LIMIT");
+ if (auto_hist)
+ *create_count= 1;
+ else
+ 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, "LIMIT");
}
else
vers_info->hist_part= next;
}
- return;
}
-
- if (vers_info->interval.is_set())
+ else if (vers_info->interval.is_set() &&
+ vers_info->hist_part->range_value <= thd->query_start())
{
- if (vers_info->hist_part->range_value > thd->query_start())
- return;
-
partition_element *next= NULL;
+ bool error= true;
List_iterator<partition_element> it(partitions);
while (next != vers_info->hist_part)
next= it++;
@@ -865,9 +870,166 @@ void partition_info::vers_set_hist_part(THD *thd)
{
vers_info->hist_part= next;
if (next->range_value > thd->query_start())
- return;
+ {
+ error= false;
+ break;
+ }
+ }
+ if (error)
+ {
+ if (auto_hist)
+ {
+ *create_count= 0;
+ const my_time_t hist_end= (my_time_t) vers_info->hist_part->range_value;
+ DBUG_ASSERT(thd->query_start() >= hist_end);
+ MYSQL_TIME h0, q0;
+ my_tz_OFFSET0->gmt_sec_to_TIME(&h0, hist_end);
+ my_tz_OFFSET0->gmt_sec_to_TIME(&q0, thd->query_start());
+ longlong q= pack_time(&q0);
+ longlong h= pack_time(&h0);
+ while (h <= q)
+ {
+ if (date_add_interval(thd, &h0, vers_info->interval.type,
+ vers_info->interval.step))
+ return true;
+ h= pack_time(&h0);
+ ++*create_count;
+ if (*create_count == MAX_PARTITIONS - 2)
+ {
+ my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(ME_WARNING));
+ my_error(ER_VERS_HIST_PART_FAILED, MYF(0),
+ table->s->db.str, table->s->table_name.str);
+ return true;
+ }
+ }
+ }
+ else
+ {
+ 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");
+ }
+ }
+ }
+
+ return false;
+}
+
+
+/**
+ @brief Run fast_alter_partition_table() to add new history partitions
+ for tables requiring them.
+*/
+bool vers_create_partitions(THD *thd, TABLE_LIST* tl, uint num_parts)
+{
+ bool result= true;
+ HA_CREATE_INFO create_info;
+ Alter_info alter_info;
+ partition_info *save_part_info= thd->work_part_info;
+ Query_tables_list save_query_tables;
+ Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer;
+ bool save_no_write_to_binlog= thd->lex->no_write_to_binlog;
+ thd->m_reprepare_observer= NULL;
+ thd->lex->reset_n_backup_query_tables_list(&save_query_tables);
+ thd->lex->no_write_to_binlog= true;
+ TABLE *table= tl->table;
+
+ DBUG_ASSERT(!thd->is_error());
+
+ {
+ 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);
+
+ 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();
+ 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= num_parts;
+ 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;
+ }
+
+ thd->work_part_info= part_info;
+ if (part_info->set_up_defaults_for_partitioning(thd, table->file, NULL,
+ table->part_info->next_part_no(num_parts)))
+ {
+ my_error(ER_VERS_HIST_PART_FAILED, MYF(ME_WARNING),
+ tl->db.str, tl->table_name.str);
+ 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))
+ {
+ my_error(ER_VERS_HIST_PART_FAILED, MYF(ME_WARNING),
+ tl->db.str, tl->table_name.str);
+ goto exit;
+ }
+ if (!fast_alter_partition)
+ {
+ my_error(ER_VERS_HIST_PART_FAILED, 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_VERS_HIST_PART_FAILED, MYF(ME_WARNING),
+ tl->db.str, tl->table_name.str);
+ goto exit;
+ }
+
+ if (fast_alter_partition_table(thd, table, &alter_info, &alter_ctx,
+ &create_info, tl))
+ {
+ my_error(ER_VERS_HIST_PART_FAILED, 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();
+
+exit:
+ 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->lex->no_write_to_binlog= save_no_write_to_binlog;
+ return result;
}
@@ -2642,13 +2804,14 @@ bool partition_info::vers_init_info(THD * thd)
bool partition_info::vers_set_interval(THD* thd, Item* interval,
interval_type int_type, Item* starts,
- const char *table_name)
+ bool auto_hist, const char *table_name)
{
DBUG_ASSERT(part_type == VERSIONING_PARTITION);
MYSQL_TIME ltime;
uint err;
vers_info->interval.type= int_type;
+ vers_info->auto_hist= auto_hist;
/* 1. assign INTERVAL to interval.step */
if (interval->fix_fields_if_needed_for_scalar(thd, &interval))
@@ -2730,6 +2893,23 @@ interval_starts_error:
}
+bool partition_info::vers_set_limit(ulonglong limit, bool auto_hist,
+ const char *table_name)
+{
+ DBUG_ASSERT(part_type == VERSIONING_PARTITION);
+
+ if (limit < 1)
+ {
+ my_error(ER_PART_WRONG_VALUE, MYF(0), table_name, "LIMIT");
+ return true;
+ }
+
+ vers_info->limit= limit;
+ vers_info->auto_hist= auto_hist;
+ return !limit;
+}
+
+
bool partition_info::error_if_requires_values() const
{
switch (part_type) {
diff --git a/sql/partition_info.h b/sql/partition_info.h
index 995147d6766..cbd6ace8fa4 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -36,11 +36,11 @@ struct st_ddl_log_memory_entry;
#define MAX_PART_NAME_SIZE 8
-
struct Vers_part_info : public Sql_alloc
{
Vers_part_info() :
limit(0),
+ auto_hist(false),
now_part(NULL),
hist_part(NULL)
{
@@ -49,6 +49,7 @@ struct Vers_part_info : public Sql_alloc
Vers_part_info(Vers_part_info &src) :
interval(src.interval),
limit(src.limit),
+ auto_hist(src.auto_hist),
now_part(NULL),
hist_part(NULL)
{
@@ -72,9 +73,10 @@ struct Vers_part_info : public Sql_alloc
my_time_t start;
INTERVAL step;
enum interval_type type;
- bool is_set() { return type < INTERVAL_LAST; }
+ bool is_set() const { return type < INTERVAL_LAST; }
} interval;
ulonglong limit;
+ bool auto_hist;
partition_element *now_part;
partition_element *hist_part;
};
@@ -393,14 +395,9 @@ public:
bool vers_init_info(THD *thd);
bool vers_set_interval(THD *thd, Item *interval,
interval_type int_type, Item *starts,
- const char *table_name);
- bool vers_set_limit(ulonglong limit)
- {
- DBUG_ASSERT(part_type == VERSIONING_PARTITION);
- vers_info->limit= limit;
- return !limit;
- }
- void vers_set_hist_part(THD *thd);
+ 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 vers_fix_field_list(THD *thd);
void vers_update_el_ids();
partition_element *get_partition(uint part_id)
@@ -419,6 +416,7 @@ public:
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);
/* Initialize the iterator to return a single partition with given part_id */
@@ -474,11 +472,6 @@ bool partition_info::vers_fix_field_list(THD * thd)
}
-/**
- @brief Update partition_element's id
-
- @returns true on error; false on success
-*/
inline
void partition_info::vers_update_el_ids()
{
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index cc807852bf2..056f484f3b0 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -668,6 +668,8 @@ struct rpl_group_info
*/
uint64 gtid_sub_id;
rpl_gtid current_gtid;
+ /* Currently applied event or NULL */
+ Log_event *current_event;
uint64 commit_id;
/*
This is used to keep transaction commit order.
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index f31f21faeb0..a25705ff785 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -7861,7 +7861,7 @@ ER_VERS_PERIOD_COLUMNS
eng "PERIOD FOR SYSTEM_TIME must use columns %`s and %`s"
ER_PART_WRONG_VALUE
- eng "Wrong parameters for partitioned %`s: wrong value for '%s'"
+ eng "Wrong parameters for partitioned %`s: wrong value for %s"
ER_VERS_WRONG_PARTS
eng "Wrong partitions for %`s: must have at least one HISTORY and exactly one last CURRENT"
@@ -7996,3 +7996,5 @@ ER_PARTITION_CONVERT_SUBPARTITIONED
eng "Convert partition is not supported for subpartitioned table."
ER_PROVIDER_NOT_LOADED
eng "MariaDB tried to use the %s, but its provider plugin is not loaded"
+ER_VERS_HIST_PART_FAILED
+ eng "Versioned table %`s.%`s: adding HISTORY partition(s) failed"
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index d983fe9a332..b3d717dfc07 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -63,7 +63,6 @@
#include "wsrep_trans_observer.h"
#endif /* WITH_WSREP */
-
bool
No_such_table_error_handler::handle_condition(THD *,
uint sql_errno,
@@ -933,7 +932,7 @@ void close_thread_table(THD *thd, TABLE **table_ptr)
DBUG_PRINT("tcache", ("table: '%s'.'%s' %p", table->s->db.str,
table->s->table_name.str, table));
DBUG_ASSERT(!table->file->keyread_enabled());
- DBUG_ASSERT(!table->file || table->file->inited == handler::NONE);
+ DBUG_ASSERT(table->file->inited == handler::NONE);
/*
The metadata lock must be released after giving back
@@ -945,11 +944,8 @@ void close_thread_table(THD *thd, TABLE **table_ptr)
MDL_SHARED));
table->mdl_ticket= NULL;
- if (table->file)
- {
- table->file->update_global_table_stats();
- table->file->update_global_index_stats();
- }
+ table->file->update_global_table_stats();
+ table->file->update_global_index_stats();
/*
This look is needed to allow THD::notify_shared_lock() to
@@ -1627,6 +1623,138 @@ bool is_locked_view(THD *thd, TABLE_LIST *t)
}
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+/**
+ Switch part_info->hist_part and request partition creation if needed.
+
+ @retval true Error or partition creation was requested.
+ @retval false No error
+*/
+bool TABLE::vers_switch_partition(THD *thd, TABLE_LIST *table_list,
+ Open_table_context *ot_ctx)
+{
+ if (!part_info || part_info->part_type != VERSIONING_PARTITION ||
+ table_list->vers_conditions.delete_history ||
+ thd->stmt_arena->is_stmt_prepare() ||
+ table_list->lock_type < TL_WRITE_ALLOW_WRITE ||
+ table_list->mdl_request.type < MDL_SHARED_WRITE ||
+ table_list->mdl_request.type == MDL_EXCLUSIVE)
+ {
+ return false;
+ }
+
+ /*
+ NOTE: we need this condition of prelocking_placeholder because we cannot do
+ auto-create after the transaction is started. Auto-create does
+ close_tables_for_reopen() and that is not possible under started transaction.
+ Also the transaction may not be cancelled at that moment: f.ex. trigger
+ after insert is run when some data is already written.
+
+ We must do auto-creation for PRELOCK_ROUTINE tables at the initial
+ open_tables() no matter what initiating sql_command is.
+ */
+ if (table_list->prelocking_placeholder != TABLE_LIST::PRELOCK_ROUTINE)
+ {
+ switch (thd->lex->sql_command)
+ {
+ case SQLCOM_INSERT:
+ if (thd->lex->duplicates != DUP_UPDATE)
+ return false;
+ break;
+ case SQLCOM_LOAD:
+ if (thd->lex->duplicates != DUP_REPLACE)
+ return false;
+ break;
+ case SQLCOM_LOCK_TABLES:
+ case SQLCOM_DELETE:
+ case SQLCOM_UPDATE:
+ case SQLCOM_REPLACE:
+ case SQLCOM_REPLACE_SELECT:
+ case SQLCOM_DELETE_MULTI:
+ case SQLCOM_UPDATE_MULTI:
+ break;
+ default:
+ /*
+ TODO: make row events set thd->lex->sql_command appropriately.
+
+ Sergei Golubchik: f.ex. currently row events increment
+ thd->status_var.com_stat[] each event for its own SQLCOM_xxx, it won't be
+ needed if they'll just set thd->lex->sql_command.
+ */
+ if (thd->rgi_slave && thd->rgi_slave->current_event &&
+ thd->lex->sql_command == SQLCOM_END)
+ {
+ switch (thd->rgi_slave->current_event->get_type_code())
+ {
+ case UPDATE_ROWS_EVENT:
+ case UPDATE_ROWS_EVENT_V1:
+ case DELETE_ROWS_EVENT:
+ case DELETE_ROWS_EVENT_V1:
+ break;
+ default:;
+ return false;
+ }
+ }
+ break;
+ }
+ }
+
+ TABLE *table= this;
+
+ /*
+ NOTE: The semantics of vers_set_hist_part() is twofold: even when we
+ don't need auto-create, we need to update part_info->hist_part.
+ */
+ uint *create_count= (table_list->vers_skip_create == thd->query_id) ?
+ NULL : &ot_ctx->vers_create_count;
+ table_list->vers_skip_create= thd->query_id;
+ if (table->part_info->vers_set_hist_part(thd, create_count))
+ {
+ MYSQL_UNBIND_TABLE(table->file);
+ tc_release_table(table);
+ return true;
+ }
+ if (ot_ctx->vers_create_count)
+ {
+ Open_table_context::enum_open_table_action action;
+ TABLE_LIST *table_arg;
+ mysql_mutex_lock(&table->s->LOCK_share);
+ if (!table->s->vers_skip_auto_create)
+ {
+ table->s->vers_skip_auto_create= true;
+ action= Open_table_context::OT_ADD_HISTORY_PARTITION;
+ table_arg= table_list;
+ }
+ else
+ {
+ /*
+ NOTE: this may repeat multiple times until creating thread acquires
+ MDL_EXCLUSIVE. Since auto-creation is rare operation this is acceptable.
+ We could suspend this thread on cond-var but we must first exit
+ MDL_SHARED_WRITE first and we cannot store cond-var into TABLE_SHARE
+ because it is already released and there is no guarantee that it will
+ be same instance if we acquire it again.
+ */
+ table_list->vers_skip_create= 0;
+ ot_ctx->vers_create_count= 0;
+ action= Open_table_context::OT_REOPEN_TABLES;
+ table_arg= NULL;
+ }
+ mysql_mutex_unlock(&table->s->LOCK_share);
+ if (!thd->locked_tables_mode)
+ {
+ MYSQL_UNBIND_TABLE(table->file);
+ tc_release_table(table);
+ }
+ ot_ctx->request_backoff_action(action, table_arg);
+ return true;
+ }
+
+ return false;
+}
+#endif /* WITH_PARTITION_STORAGE_ENGINE */
+
+
/**
Open a base table.
@@ -1779,6 +1907,8 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
DBUG_PRINT("info",("Using locked table"));
#ifdef WITH_PARTITION_STORAGE_ENGINE
part_names_error= set_partitions_as_used(table_list, table);
+ if (table->vers_switch_partition(thd, table_list, ot_ctx))
+ DBUG_RETURN(true);
#endif
goto reset;
}
@@ -2034,6 +2164,11 @@ retry_share:
tc_add_table(thd, table);
}
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ if (table->vers_switch_partition(thd, table_list, ot_ctx))
+ DBUG_RETURN(true);
+#endif /* WITH_PARTITION_STORAGE_ENGINE */
+
if (!(flags & MYSQL_OPEN_HAS_MDL_LOCK) &&
table->s->table_category < TABLE_CATEGORY_INFORMATION)
{
@@ -2111,6 +2246,7 @@ retry_share:
table->init(thd, table_list);
+ DBUG_ASSERT(table != thd->open_tables);
table->next= thd->open_tables; /* Link into simple list */
thd->set_open_tables(table);
@@ -2576,7 +2712,7 @@ unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count)
This is only needed when LOCK TABLES is active
*/
-void Locked_tables_list::mark_table_for_reopen(THD *thd, TABLE *table)
+void Locked_tables_list::mark_table_for_reopen(TABLE *table)
{
TABLE_SHARE *share= table->s;
@@ -2589,11 +2725,13 @@ void Locked_tables_list::mark_table_for_reopen(THD *thd, TABLE *table)
close_all_tables_for_name().
*/
if (table_list->table && table_list->table->s == share)
+ {
table_list->table->internal_set_needs_reopen(true);
+ some_table_marked_for_reopen= 1;
+ }
}
/* This is needed in the case where lock tables where not used */
table->internal_set_needs_reopen(true);
- some_table_marked_for_reopen= 1;
}
@@ -3048,7 +3186,8 @@ Open_table_context::Open_table_context(THD *thd, uint flags)
m_flags(flags),
m_action(OT_NO_ACTION),
m_has_locks(thd->mdl_context.has_locks()),
- m_has_protection_against_grl(0)
+ m_has_protection_against_grl(0),
+ vers_create_count(0)
{}
@@ -3128,13 +3267,15 @@ request_backoff_action(enum_open_table_action action_arg,
*/
if (table)
{
- DBUG_ASSERT(action_arg == OT_DISCOVER || action_arg == OT_REPAIR);
+ DBUG_ASSERT(action_arg == OT_DISCOVER || action_arg == OT_REPAIR ||
+ action_arg == OT_ADD_HISTORY_PARTITION);
m_failed_table= (TABLE_LIST*) m_thd->alloc(sizeof(TABLE_LIST));
if (m_failed_table == NULL)
return TRUE;
m_failed_table->init_one_table(&table->db, &table->table_name, &table->alias, TL_WRITE);
m_failed_table->open_strategy= table->open_strategy;
m_failed_table->mdl_request.set_type(MDL_EXCLUSIVE);
+ m_failed_table->vers_skip_create= table->vers_skip_create;
}
m_action= action_arg;
return FALSE;
@@ -3195,13 +3336,49 @@ Open_table_context::recover_from_failed_open()
break;
case OT_DISCOVER:
case OT_REPAIR:
- if ((result= lock_table_names(m_thd, m_thd->lex->create_info,
- m_failed_table, NULL,
- get_timeout(), 0)))
+ case OT_ADD_HISTORY_PARTITION:
+ if (!m_thd->locked_tables_mode)
+ result= lock_table_names(m_thd, m_thd->lex->create_info, m_failed_table,
+ NULL, get_timeout(), 0);
+ else
+ {
+ DBUG_ASSERT(!result);
+ DBUG_ASSERT(m_action == OT_ADD_HISTORY_PARTITION);
+ }
+ /*
+ We are now under MDL_EXCLUSIVE mode. Other threads have no table share
+ acquired: they are blocked either at open_table_get_mdl_lock() in
+ open_table() or at lock_table_names() here.
+ */
+ if (result)
+ {
+ if (m_action == OT_ADD_HISTORY_PARTITION)
+ {
+ TABLE_SHARE *share= tdc_acquire_share(m_thd, m_failed_table,
+ GTS_TABLE, NULL);
+ if (share)
+ {
+ share->vers_skip_auto_create= false;
+ tdc_release_share(share);
+ }
+ if (m_thd->get_stmt_da()->sql_errno() == ER_LOCK_WAIT_TIMEOUT)
+ {
+ // MDEV-23642 Locking timeout caused by auto-creation affects original DML
+ m_thd->clear_error();
+ vers_create_count= 0;
+ result= false;
+ }
+ }
break;
+ }
- tdc_remove_table(m_thd, m_failed_table->db.str,
- m_failed_table->table_name.str);
+ /*
+ 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)
+ tdc_remove_table(m_thd, m_failed_table->db.str,
+ m_failed_table->table_name.str);
switch (m_action)
{
@@ -3229,6 +3406,70 @@ Open_table_context::recover_from_failed_open()
case OT_REPAIR:
result= auto_repair_table(m_thd, m_failed_table);
break;
+ case OT_ADD_HISTORY_PARTITION:
+ {
+ 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(vers_create_count);
+ result= vers_create_partitions(m_thd, m_failed_table, vers_create_count);
+ vers_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;
+ }
+ 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;
+ }
case OT_BACKOFF_AND_RETRY:
case OT_REOPEN_TABLES:
case OT_NO_ACTION:
@@ -4203,6 +4444,7 @@ bool open_tables(THD *thd, const DDL_options_st &options,
}
thd->current_tablenr= 0;
+
restart:
/*
Close HANDLER tables which are marked for flush or against which there
@@ -4283,6 +4525,9 @@ restart:
/*
For every table in the list of tables to open, try to find or open
a table.
+
+ NOTE: there can be duplicates in the list. F.ex. table specified in
+ LOCK TABLES and prelocked via another table (like when used in a trigger).
*/
for (tables= *table_to_open; tables;
table_to_open= &tables->next_global, tables= tables->next_global)
@@ -4377,6 +4622,8 @@ restart:
{
if (ot_ctx.can_recover_from_failed_open())
{
+ // FIXME: is this really used?
+ DBUG_ASSERT(0);
close_tables_for_reopen(thd, start,
ot_ctx.start_of_statement_svp());
if (ot_ctx.recover_from_failed_open())
@@ -5149,16 +5396,14 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
if (table_list->table)
DBUG_RETURN(table_list->table);
- /* should not be used in a prelocked_mode context, see NOTE above */
- DBUG_ASSERT(thd->locked_tables_mode < LTM_PRELOCKED);
-
THD_STAGE_INFO(thd, stage_opening_tables);
thd->current_tablenr= 0;
/* open_ltable can be used only for BASIC TABLEs */
table_list->required_type= TABLE_TYPE_NORMAL;
/* This function can't properly handle requests for such metadata locks. */
- DBUG_ASSERT(table_list->mdl_request.type < MDL_SHARED_UPGRADABLE);
+ DBUG_ASSERT(lock_flags & MYSQL_OPEN_HAS_MDL_LOCK ||
+ table_list->mdl_request.type < MDL_SHARED_UPGRADABLE);
while ((error= open_table(thd, table_list, &ot_ctx)) &&
ot_ctx.can_recover_from_failed_open())
diff --git a/sql/sql_base.h b/sql/sql_base.h
index 5b449fdddac..a98ec297c78 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -532,7 +532,8 @@ public:
OT_BACKOFF_AND_RETRY,
OT_REOPEN_TABLES,
OT_DISCOVER,
- OT_REPAIR
+ OT_REPAIR,
+ OT_ADD_HISTORY_PARTITION
};
Open_table_context(THD *thd, uint flags);
@@ -605,6 +606,9 @@ private:
protection against global read lock.
*/
mdl_bitmap_t m_has_protection_against_grl;
+
+public:
+ uint vers_create_count;
};
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 29824301e9d..16bbc48d73b 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -844,7 +844,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
wsrep_info[sizeof(wsrep_info) - 1] = '\0'; /* make sure it is 0-terminated */
#endif
/* Call to init() below requires fully initialized Open_tables_state. */
- reset_open_tables_state(this);
+ reset_open_tables_state();
init();
debug_sync_init_thread(this);
@@ -4535,7 +4535,7 @@ void THD::reset_n_backup_open_tables_state(Open_tables_backup *backup)
DBUG_ENTER("reset_n_backup_open_tables_state");
backup->set_open_tables_state(this);
backup->mdl_system_tables_svp= mdl_context.mdl_savepoint();
- reset_open_tables_state(this);
+ reset_open_tables_state();
state_flags|= Open_tables_state::BACKUPS_AVAIL;
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index df9d89b5aff..686e6e70766 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1596,6 +1596,10 @@ enum enum_locked_tables_mode
LTM_NONE= 0,
LTM_LOCK_TABLES,
LTM_PRELOCKED,
+ /*
+ TODO: remove LTM_PRELOCKED_UNDER_LOCK_TABLES: it is never used apart from
+ LTM_LOCK_TABLES.
+ */
LTM_PRELOCKED_UNDER_LOCK_TABLES,
LTM_always_last
};
@@ -1778,7 +1782,7 @@ public:
*this= *state;
}
- void reset_open_tables_state(THD *thd)
+ void reset_open_tables_state()
{
open_tables= 0;
temporary_tables= 0;
@@ -2126,7 +2130,7 @@ public:
bool restore_lock(THD *thd, TABLE_LIST *dst_table_list, TABLE *table,
MYSQL_LOCK *lock);
void add_back_last_deleted_lock(TABLE_LIST *dst_table_list);
- void mark_table_for_reopen(THD *thd, TABLE *table);
+ void mark_table_for_reopen(TABLE *table);
};
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index b5f8cf4a886..e2b6909bc5d 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -9666,7 +9666,11 @@ bool LEX::part_values_history(THD *thd)
}
else
{
- part_info->vers_init_info(thd);
+ if (unlikely(part_info->vers_init_info(thd)))
+ {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ return true;
+ }
elem->id= UINT_MAX32;
}
DBUG_ASSERT(part_info->vers_info);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index b9d3eec5a60..078ea0dae9b 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -84,6 +84,7 @@
#include "events.h"
#include "sql_trigger.h"
#include "transaction.h"
+#include "sql_alter.h"
#include "sql_audit.h"
#include "sql_prepare.h"
#include "sql_cte.h"
@@ -6054,7 +6055,6 @@ finish:
/* Free tables. Set stage 'closing tables' */
close_thread_tables(thd);
-
#ifndef DBUG_OFF
if (lex->sql_command != SQLCOM_SET_OPTION && ! thd->in_sub_stmt)
DEBUG_SYNC(thd, "execute_command_after_close_tables");
@@ -7566,6 +7566,7 @@ void THD::reset_for_next_command(bool do_clear_error)
global_system_variables.auto_increment_increment;
}
#endif /* WITH_WSREP */
+
query_start_sec_part_used= 0;
is_fatal_error= time_zone_used= 0;
log_current_statement= 0;
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index b75a318ab65..2e23662349f 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -2580,11 +2580,17 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info,
err+= str.append('\'');
}
}
- if (vers_info->limit)
+ else if (vers_info->limit)
{
err+= str.append(STRING_WITH_LEN("LIMIT "));
err+= str.append_ulonglong(vers_info->limit);
}
+ if (vers_info->auto_hist)
+ {
+ DBUG_ASSERT(vers_info->interval.is_set() ||
+ vers_info->limit);
+ err+= str.append(STRING_WITH_LEN(" AUTO"));
+ }
}
else if (part_info->part_expr)
{
@@ -5326,7 +5332,9 @@ that are reorganised.
now_part= el;
}
}
- if (*fast_alter_table && tab_part_info->vers_info->interval.is_set())
+ if (*fast_alter_table &&
+ !(alter_info->partition_flags & ALTER_PARTITION_AUTO_HIST) &&
+ tab_part_info->vers_info->interval.is_set())
{
partition_element *hist_part= tab_part_info->vers_info->hist_part;
if (hist_part->range_value <= thd->query_start())
@@ -6038,7 +6046,7 @@ err:
records are added
*/
-static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
+static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, bool copy_data)
{
char path[FN_REFLEN+1];
int error;
@@ -6048,7 +6056,7 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
- if(mysql_trans_prepare_alter_copy_data(thd))
+ if(copy_data && mysql_trans_prepare_alter_copy_data(thd))
DBUG_RETURN(TRUE);
/* TODO: test if bulk_insert would increase the performance */
@@ -6062,7 +6070,9 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
file->print_error(error, MYF(error != ER_OUTOFMEMORY ? 0 : ME_FATAL));
}
- if (mysql_trans_commit_alter_copy_data(thd))
+ DBUG_ASSERT(copy_data || (!lpt->copied && !lpt->deleted));
+
+ if (copy_data && mysql_trans_commit_alter_copy_data(thd))
error= 1; /* The error has been reported */
DBUG_RETURN(MY_TEST(error));
@@ -7341,7 +7351,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
thd->variables.option_bits|= OPTION_IF_EXISTS;
if (table->file->alter_table_flags(alter_info->flags) &
- HA_PARTITION_ONE_PHASE)
+ HA_PARTITION_ONE_PHASE &&
+ !(alter_info->partition_flags & ALTER_PARTITION_AUTO_HIST))
{
/*
In the case where the engine supports one phase online partition
@@ -7383,7 +7394,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
2) Perform the change within the handler
*/
if (mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
- mysql_change_partitions(lpt))
+ mysql_change_partitions(lpt, true))
{
goto err;
}
@@ -7570,9 +7581,14 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
ERROR_INJECT("convert_partition_11"))
goto err;
}
+ /*
+ TODO: would be good if adding new empty VERSIONING partitions would always
+ go this way, auto or not.
+ */
else if ((alter_info->partition_flags & ALTER_PARTITION_ADD) &&
(part_info->part_type == RANGE_PARTITION ||
- part_info->part_type == LIST_PARTITION))
+ part_info->part_type == LIST_PARTITION ||
+ alter_info->partition_flags & ALTER_PARTITION_AUTO_HIST))
{
DBUG_ASSERT(!(alter_info->partition_flags & ALTER_PARTITION_CONVERT_IN));
/*
@@ -7613,7 +7629,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
ERROR_INJECT("add_partition_3") ||
write_log_add_change_partition(lpt) ||
ERROR_INJECT("add_partition_4") ||
- mysql_change_partitions(lpt) ||
+ mysql_change_partitions(lpt, false) ||
ERROR_INJECT("add_partition_5") ||
alter_close_table(lpt) ||
ERROR_INJECT("add_partition_6") ||
@@ -7700,7 +7716,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
ERROR_INJECT("change_partition_2") ||
write_log_add_change_partition(lpt) ||
ERROR_INJECT("change_partition_3") ||
- mysql_change_partitions(lpt) ||
+ mysql_change_partitions(lpt, true) ||
ERROR_INJECT("change_partition_4") ||
wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
ERROR_INJECT("change_partition_5") ||
diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc
index c6af72c5979..a0ef89ff0f5 100644
--- a/sql/sql_truncate.cc
+++ b/sql/sql_truncate.cc
@@ -511,7 +511,7 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
(HTON_REQUIRES_CLOSE_AFTER_TRUNCATE |
HTON_TRUNCATE_REQUIRES_EXCLUSIVE_USE)))
{
- thd->locked_tables_list.mark_table_for_reopen(thd, table_ref->table);
+ thd->locked_tables_list.mark_table_for_reopen(table_ref->table);
if (unlikely(thd->locked_tables_list.reopen_tables(thd, false)))
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 442644eddd6..f9c575d39c6 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1506,6 +1506,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
condition_number
opt_versioning_interval_start
+%type <num> opt_vers_auto_part
+
%type <item_param> param_marker
%type <item_num>
@@ -5093,24 +5095,20 @@ opt_part_option:
opt_versioning_rotation:
/* empty */ {}
- | INTERVAL_SYM expr interval opt_versioning_interval_start
+ | INTERVAL_SYM expr interval opt_versioning_interval_start opt_vers_auto_part
{
partition_info *part_info= Lex->part_info;
const char *table_name= Lex->create_last_non_select_table->table_name.str;
- if (unlikely(part_info->vers_set_interval(thd, $2, $3, $4, table_name)))
+ if (unlikely(part_info->vers_set_interval(thd, $2, $3, $4, $5, table_name)))
MYSQL_YYABORT;
}
- | LIMIT ulonglong_num
- {
- partition_info *part_info= Lex->part_info;
- if (unlikely(part_info->vers_set_limit($2)))
+ | LIMIT ulonglong_num opt_vers_auto_part
{
- my_error(ER_PART_WRONG_VALUE, MYF(0),
- Lex->create_last_non_select_table->table_name.str,
- "LIMIT");
- MYSQL_YYABORT;
+ partition_info *part_info= Lex->part_info;
+ const char *table_name= Lex->create_last_non_select_table->table_name.str;
+ if (unlikely(part_info->vers_set_limit($2, $3, table_name)))
+ MYSQL_YYABORT;
}
- }
;
@@ -5125,6 +5123,16 @@ opt_versioning_interval_start:
}
;
+opt_vers_auto_part:
+ /* empty */
+ {
+ $$= 0;
+ }
+ | AUTO_SYM
+ {
+ $$= 1;
+ }
+ ;
/*
End of partition parser part
*/
diff --git a/sql/table.cc b/sql/table.cc
index b1a7b6bfe2b..38d48100359 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -10123,5 +10123,5 @@ void TABLE::mark_table_for_reopen()
{
THD *thd= in_use;
DBUG_ASSERT(thd);
- thd->locked_tables_list.mark_table_for_reopen(thd, this);
+ thd->locked_tables_list.mark_table_for_reopen(this);
}
diff --git a/sql/table.h b/sql/table.h
index 6aa75df39c6..c8ea4094409 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -64,6 +64,7 @@ class derived_handler;
class Pushdown_derived;
struct Name_resolution_context;
class Table_function_json_table;
+class Open_table_context;
/*
Used to identify NESTED_JOIN structures within a join (applicable only to
@@ -910,6 +911,13 @@ struct TABLE_SHARE
vers_kind_t versioned;
period_info_t vers;
period_info_t period;
+ /*
+ Protect multiple threads from repeating partition auto-create over
+ single share.
+
+ TODO: remove it when partitioning metadata will be in TABLE_SHARE.
+ */
+ bool vers_skip_auto_create;
bool init_period_from_extra2(period_info_t *period, const uchar *data,
const uchar *end);
@@ -1766,6 +1774,10 @@ public:
ulonglong vers_start_id() const;
ulonglong vers_end_id() const;
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ bool vers_switch_partition(THD *thd, TABLE_LIST *table_list,
+ Open_table_context *ot_ctx);
+#endif
int update_generated_fields();
int period_make_insert(Item *src, Field *dst);
@@ -2558,6 +2570,13 @@ struct TABLE_LIST
bool merged;
bool merged_for_insert;
bool sequence; /* Part of NEXTVAL/CURVAL/LASTVAL */
+ /*
+ Protect single thread from repeating partition auto-create over
+ multiple share instances (as the share is closed on backoff action).
+
+ Skips auto-create only for one given query id.
+ */
+ query_id_t vers_skip_create;
/*
Items created by create_view_field and collected to change them in case
diff --git a/sql/transaction.cc b/sql/transaction.cc
index 958abebfc47..b1e98be56bc 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -463,7 +463,7 @@ bool trans_commit_stmt(THD *thd)
a savepoint for each nested statement, and release the
savepoint when statement has succeeded.
*/
- DBUG_ASSERT(! thd->in_sub_stmt);
+ DBUG_ASSERT(!(thd->in_sub_stmt));
thd->merge_unsafe_rollback_flags();