Commit b7bba721 authored by Aleksey Midenkov's avatar Aleksey Midenkov Committed by Sergei Golubchik

MDEV-22166 CONVERT PARTITION: move out partition into a table

Syntax for CONVERT keyword

ALTER TABLE tbl_name
    [alter_option [, alter_option] ...] |
    [partition_options]

partition_option: {
    ...
    | CONVERT PARTITION partition_name TO TABLE tbl_name
}

Examples:

    ALTER TABLE t1 CONVERT PARTITION p2 TO TABLE tp2;

New ALTER_PARTITION_CONVERT_OUT command for
fast_alter_partition_table() is done in alter_partition_convert_out()
function which basically does ha_rename_table().

Partition to extract is marked with the same flag as dropped
partition: PART_TO_BE_DROPPED. Note that we cannot have multiple
partitioning commands in one ALTER.

For DDL logging basically the principle is the same as for other
fast_alter_partition_table() commands. The only difference is that it
integrates late Atomic DDL functions and introduces additional phase
of WFRM_BACKUP_ORIGINAL. That is required for binlog consistency
because otherwise we could not revert back after WFRM_INSTALL_SHADOW
is done. And before DDL log is complete if we crash or fail the
altered table will be already new but binlog will miss that ALTER
command. Note that this is different from all other atomic DDL in that
it rolls back until the ddl_log_complete() is done even if everything
was done fully before the crash.

Test cases added to:

  parts.alter_table \
  parts.partition_debug \
  versioning.partition \
  atomic.alter_partition
parent f6b0e34c
[row]
binlog-format=row
[stmt]
binlog-format=statement
[mix]
binlog-format=mixed
# The goal of including this file is to test with different
# binlog combinations: row, stmt or mix
# (see include/binlog_combinations.combinations)
--source include/have_log_bin.inc
[lcase_def]
[lcase1]
lower_case_table_names=1
[lcase2]
lower_case_table_names=2
# The goal of including this file is to test with different
# lower_case_table_names modes (see include/lcase_name.combinations)
# Crash recovery
create or replace procedure prepare_table()
begin
create or replace table t1 (x int)
with system versioning
partition by range(x) (
partition p0 values less than (10),
partition p1 values less than (20),
partition pn values less than maxvalue);
insert into t1 values (2), (12), (22);
flush tables;
end $
# QUERY: ALTER TABLE t1 CONVERT PARTITION p1 TO TABLE tp1
# CRASH: ddl_log_create_before_create_frm
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#p1.MYD
t1#P#p1.MYI
t1#P#pn.MYD
t1#P#pn.MYI
t1.frm
t1.par
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY RANGE (`x`)
(PARTITION `p0` VALUES LESS THAN (10) ENGINE = DEFAULT_ENGINE,
PARTITION `p1` VALUES LESS THAN (20) ENGINE = DEFAULT_ENGINE,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = DEFAULT_ENGINE)
x
2
12
22
# CRASH: ddl_log_alter_partition_after_create_frm
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#p1.MYD
t1#P#p1.MYI
t1#P#pn.MYD
t1#P#pn.MYI
t1.frm
t1.par
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY RANGE (`x`)
(PARTITION `p0` VALUES LESS THAN (10) ENGINE = DEFAULT_ENGINE,
PARTITION `p1` VALUES LESS THAN (20) ENGINE = DEFAULT_ENGINE,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = DEFAULT_ENGINE)
x
2
12
22
# CRASH: ddl_log_alter_partition_after_write_frm
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#p1.MYD
t1#P#p1.MYI
t1#P#pn.MYD
t1#P#pn.MYI
t1.frm
t1.par
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY RANGE (`x`)
(PARTITION `p0` VALUES LESS THAN (10) ENGINE = DEFAULT_ENGINE,
PARTITION `p1` VALUES LESS THAN (20) ENGINE = DEFAULT_ENGINE,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = DEFAULT_ENGINE)
x
2
12
22
# CRASH: crash_convert_partition_1
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#p1.MYD
t1#P#p1.MYI
t1#P#pn.MYD
t1#P#pn.MYI
t1.frm
t1.par
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY RANGE (`x`)
(PARTITION `p0` VALUES LESS THAN (10) ENGINE = DEFAULT_ENGINE,
PARTITION `p1` VALUES LESS THAN (20) ENGINE = DEFAULT_ENGINE,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = DEFAULT_ENGINE)
x
2
12
22
# CRASH: crash_convert_partition_2
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#p1.MYD
t1#P#p1.MYI
t1#P#pn.MYD
t1#P#pn.MYI
t1.frm
t1.par
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY RANGE (`x`)
(PARTITION `p0` VALUES LESS THAN (10) ENGINE = DEFAULT_ENGINE,
PARTITION `p1` VALUES LESS THAN (20) ENGINE = DEFAULT_ENGINE,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = DEFAULT_ENGINE)
x
2
12
22
# CRASH: crash_convert_partition_3
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#p1.MYD
t1#P#p1.MYI
t1#P#pn.MYD
t1#P#pn.MYI
t1.frm
t1.par
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY RANGE (`x`)
(PARTITION `p0` VALUES LESS THAN (10) ENGINE = DEFAULT_ENGINE,
PARTITION `p1` VALUES LESS THAN (20) ENGINE = DEFAULT_ENGINE,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = DEFAULT_ENGINE)
x
2
12
22
# CRASH: crash_convert_partition_4
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#p1.MYD
t1#P#p1.MYI
t1#P#pn.MYD
t1#P#pn.MYI
t1.frm
t1.par
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY RANGE (`x`)
(PARTITION `p0` VALUES LESS THAN (10) ENGINE = DEFAULT_ENGINE,
PARTITION `p1` VALUES LESS THAN (20) ENGINE = DEFAULT_ENGINE,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = DEFAULT_ENGINE)
x
2
12
22
# CRASH: crash_convert_partition_5
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#p1.MYD
t1#P#p1.MYI
t1#P#pn.MYD
t1#P#pn.MYI
t1.frm
t1.par
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY RANGE (`x`)
(PARTITION `p0` VALUES LESS THAN (10) ENGINE = DEFAULT_ENGINE,
PARTITION `p1` VALUES LESS THAN (20) ENGINE = DEFAULT_ENGINE,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = DEFAULT_ENGINE)
x
2
12
22
# CRASH: crash_convert_partition_6
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#p1.MYD
t1#P#p1.MYI
t1#P#pn.MYD
t1#P#pn.MYI
t1.frm
t1.par
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY RANGE (`x`)
(PARTITION `p0` VALUES LESS THAN (10) ENGINE = DEFAULT_ENGINE,
PARTITION `p1` VALUES LESS THAN (20) ENGINE = DEFAULT_ENGINE,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = DEFAULT_ENGINE)
x
2
12
22
# CRASH: crash_convert_partition_7
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#p1.MYD
t1#P#p1.MYI
t1#P#pn.MYD
t1#P#pn.MYI
t1.frm
t1.par
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY RANGE (`x`)
(PARTITION `p0` VALUES LESS THAN (10) ENGINE = DEFAULT_ENGINE,
PARTITION `p1` VALUES LESS THAN (20) ENGINE = DEFAULT_ENGINE,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = DEFAULT_ENGINE)
x
2
12
22
# CRASH: crash_convert_partition_8
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#p1.MYD
t1#P#p1.MYI
t1#P#pn.MYD
t1#P#pn.MYI
t1.frm
t1.par
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY RANGE (`x`)
(PARTITION `p0` VALUES LESS THAN (10) ENGINE = DEFAULT_ENGINE,
PARTITION `p1` VALUES LESS THAN (20) ENGINE = DEFAULT_ENGINE,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = DEFAULT_ENGINE)
x
2
12
22
# CRASH: crash_convert_partition_9
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#pn.MYD
t1#P#pn.MYI
t1.frm
t1.par
tp1.MYD
tp1.MYI
tp1.frm
master-bin.000001 # Query # # use `test`; ALTER TABLE t1 CONVERT PARTITION p1 TO TABLE tp1
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY RANGE (`x`)
(PARTITION `p0` VALUES LESS THAN (10) ENGINE = DEFAULT_ENGINE,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = DEFAULT_ENGINE)
x
2
22
Table Create Table
tp1 CREATE TABLE `tp1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
x
12
Warnings:
Note 1051 Unknown table 'test.t1'
--source include/have_partition.inc
--source include/have_debug.inc
--source include/have_sequence.inc
--source include/binlog_combinations.inc
--source include/have_binlog_format_row_or_statement.inc
--source include/not_valgrind.inc
let $default_engine=InnoDB;
let $extra_option=;
let $save_debug=`select @@debug_dbug`;
if ($MTR_COMBINATION_MYISAM)
{
let $default_engine=MyISAM;
}
if ($MTR_COMBINATION_ARIA)
{
let $default_engine=Aria;
let $extra_option=transactional=1;
}
if ($MTR_COMBINATION_STMT)
{
let $binlog_format=include/set_binlog_format_statement.sql;
}
if ($MTR_COMBINATION_ROW)
{
let $binlog_format=include/set_binlog_format_row.sql;
}
--disable_query_log
--eval set @@default_storage_engine=$default_engine
--enable_query_log
--echo # Crash recovery
let $MYSQLD_DATADIR= `SELECT @@datadir`;
let $crash_count= 12;
let $crash_points='ddl_log_create_before_create_frm',
'ddl_log_alter_partition_after_create_frm',
'ddl_log_alter_partition_after_write_frm',
'crash_convert_partition_1',
'crash_convert_partition_2',
'crash_convert_partition_3',
'crash_convert_partition_4',
'crash_convert_partition_5',
'crash_convert_partition_6',
'crash_convert_partition_7',
'crash_convert_partition_8',
'crash_convert_partition_9';
#let $crash_count= 1;
#let $crash_points= 'crash_convert_partition_8';
let $statement_count= 1;
let $statements= 'ALTER TABLE t1 CONVERT PARTITION p1 TO TABLE tp1';
#let $statement_count=1;
#let $statements='CREATE OR REPLACE TABLE t1 SELECT * from const_table';
--delimiter $
create or replace procedure prepare_table()
begin
create or replace table t1 (x int)
with system versioning
partition by range(x) (
partition p0 values less than (10),
partition p1 values less than (20),
partition pn values less than maxvalue);
insert into t1 values (2), (12), (22);
flush tables;
end $
--delimiter ;
let $old_debug=`select @@debug_dbug`;
let $keep_include_silent=1;
let $grep_script=ALTER;
--disable_query_log
let $r=0;
while ($r < $statement_count)
{
inc $r;
let $statement=`select ELT($r, $statements)`;
--echo # QUERY: $statement
let $c=0;
while ($c < $crash_count)
{
inc $c;
let $crash=`select ELT($c, $crash_points)`;
--eval set @@default_storage_engine=$default_engine
call prepare_table;
if (!$c)
{
lock tables t1 write;
}
--source $binlog_format
RESET MASTER;
--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--disable_reconnect
--eval set @@debug_dbug="+d,$crash",@debug_crash_counter=1
let $errno=0;
--error 0,2013
--eval $statement;
let $error=$errno;
--enable_reconnect
--source include/wait_until_connected_again.inc
--disable_query_log
--eval set @@debug_dbug="$old_debug"
if ($error == 0)
{
--echo # NO CRASH: $crash
}
if ($error)
{
--echo # CRASH: $crash
}
# Check which tables still exists
--replace_result MAI MYI MAD MYD
--list_files $MYSQLD_DATADIR/test t*
--replace_regex /backup-\d+/backup/
--list_files $MYSQLD_DATADIR/test *sql*
--remove_files_wildcard $MYSQLD_DATADIR/test *sql-backup-*
--let $binlog_file=master-bin.000001
--source include/show_binlog_events.inc
if ($error)
{
--let $binlog_file=master-bin.000002
--source include/show_binlog_events.inc
}
--replace_result $default_engine DEFAULT_ENGINE ' PAGE_CHECKSUM=1' ''
show create table t1;
select * from t1;
--replace_result $default_engine DEFAULT_ENGINE ' PAGE_CHECKSUM=1' ''
--error 0, ER_NO_SUCH_TABLE
show create table tp1;
--error 0, ER_NO_SUCH_TABLE
select * from tp1;
# Drop the tables. The warnings will show what was dropped
--disable_warnings
drop table t1;
drop table if exists tp1;
--enable_warnings
}
}
drop table if exists t1;
drop procedure prepare_table;
--eval set @@debug_dbug="$save_debug"
--enable_query_log
[innodb]
default-storage-engine=innodb
[myisam]
default-storage-engine=myisam
[aria]
default-storage-engine=aria
--source include/have_innodb.inc
let $engine= `select @@default_storage_engine`;
--- alter_table.result
+++ alter_table,list.reject
@@ -62,13 +62,13 @@
partition pn values less than maxvalue);
ERROR HY000: Partitioned tables do not support CREATE TEMPORARY TABLE
create or replace table t1 (x int)
-partition by range(x) (
-partition p1 values less than (10),
-partition p2 values less than (20),
-partition p3 values less than (30),
-partition p4 values less than (40),
-partition p5 values less than (50),
-partition pn values less than maxvalue);
+partition by list(x) (
+partition p1 values in (2, 3, 4),
+partition p2 values in (12, 13, 14),
+partition p3 values in (22, 23, 24),
+partition p4 values in (32, 33, 34),
+partition p5 values in (42, 43, 44),
+partition pn values in (52, 53, 54));
insert into t1 values (2), (12), (22), (32), (42), (52);
create or replace table tp2 (y int);
insert tp2 values (88);
@@ -108,12 +108,12 @@
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=X DEFAULT CHARSET=latin1
- PARTITION BY RANGE (`x`)
-(PARTITION `p1` VALUES LESS THAN (10) ENGINE = X,
- PARTITION `p3` VALUES LESS THAN (30) ENGINE = X,
- PARTITION `p4` VALUES LESS THAN (40) ENGINE = X,
- PARTITION `p5` VALUES LESS THAN (50) ENGINE = X,
- PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = X)
+ PARTITION BY LIST (`x`)
+(PARTITION `p1` VALUES IN (2,3,4) ENGINE = X,
+ PARTITION `p3` VALUES IN (22,23,24) ENGINE = X,
+ PARTITION `p4` VALUES IN (32,33,34) ENGINE = X,
+ PARTITION `p5` VALUES IN (42,43,44) ENGINE = X,
+ PARTITION `pn` VALUES IN (52,53,54) ENGINE = X)
select * from t1 order by x;
x
2
@@ -138,11 +138,11 @@
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=X DEFAULT CHARSET=latin1
- PARTITION BY RANGE (`x`)
-(PARTITION `p1` VALUES LESS THAN (10) ENGINE = X,
- PARTITION `p4` VALUES LESS THAN (40) ENGINE = X,
- PARTITION `p5` VALUES LESS THAN (50) ENGINE = X,
- PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = X)
+ PARTITION BY LIST (`x`)
+(PARTITION `p1` VALUES IN (2,3,4) ENGINE = X,
+ PARTITION `p4` VALUES IN (32,33,34) ENGINE = X,
+ PARTITION `p5` VALUES IN (42,43,44) ENGINE = X,
+ PARTITION `pn` VALUES IN (52,53,54) ENGINE = X)
select * from t1 order by x;
x
2
@@ -168,10 +168,10 @@
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=X DEFAULT CHARSET=latin1
- PARTITION BY RANGE (`x`)
-(PARTITION `p1` VALUES LESS THAN (10) ENGINE = X,
- PARTITION `p5` VALUES LESS THAN (50) ENGINE = X,
- PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = X)
+ PARTITION BY LIST (`x`)
+(PARTITION `p1` VALUES IN (2,3,4) ENGINE = X,
+ PARTITION `p5` VALUES IN (42,43,44) ENGINE = X,
+ PARTITION `pn` VALUES IN (52,53,54) ENGINE = X)
select * from t1 order by x;
x
2
@@ -193,9 +193,9 @@
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=X DEFAULT CHARSET=latin1
- PARTITION BY RANGE (`x`)
-(PARTITION `p1` VALUES LESS THAN (10) ENGINE = X,
- PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = X)
+ PARTITION BY LIST (`x`)
+(PARTITION `p1` VALUES IN (2,3,4) ENGINE = X,
+ PARTITION `pn` VALUES IN (52,53,54) ENGINE = X)
select * from t1 order by x;
x
2
......@@ -28,3 +28,239 @@ ALTER TABLE v1 EXCHANGE PARTITION p2 WITH TABLE t2 ;
ERROR 42000: Can't open table
DROP VIEW v1;
DROP TABLE t1, t2;
#
# MDEV-22166 MIGRATE PARTITION: move out partition into a table
#
create or replace table t1 (x int);
alter table t1 convert partition p1 to table tp1;
ERROR HY000: Partition management on a not partitioned table is not possible
create or replace table t1 (x int)
partition by hash(x) partitions 2;
alter table t1 convert partition p1 to table tp1;
ERROR HY000: CONVERT PARTITION can only be used on RANGE/LIST partitions
create or replace table t1 (x int)
partition by key(x) partitions 2;
alter table t1 convert partition p1 to table tp1;
ERROR HY000: CONVERT PARTITION can only be used on RANGE/LIST partitions
create or replace table t1 (x int)
partition by range(x)
subpartition by hash(x) subpartitions 3 (
partition p1 values less than (10),
partition pn values less than maxvalue);
alter table t1 convert partition p1 to table p1;
ERROR HY000: Convert partition is not supported for subpartitioned table.
alter table t1 convert partition p1sp0 to table p1;
ERROR HY000: Wrong partition name or partition list
create or replace table t1 (x int)
partition by range(x) (
partition p1 values less than (10));
alter table t1 convert partition p1 to table tp1;
ERROR HY000: Cannot remove all partitions, use DROP TABLE instead
create or replace temporary table t1 (x int)
partition by range(x) (
partition p0 values less than (10),
partition pn values less than maxvalue);
ERROR HY000: Partitioned tables do not support CREATE TEMPORARY TABLE
create or replace table t1 (x int)
partition by range(x) (
partition p1 values less than (10),
partition p2 values less than (20),
partition p3 values less than (30),
partition p4 values less than (40),
partition p5 values less than (50),
partition pn values less than maxvalue);
insert into t1 values (2), (12), (22), (32), (42), (52);
create or replace table tp2 (y int);
insert tp2 values (88);
alter table t1 convert partition p2 to table tp2, drop partition p3;
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 ' drop partition p3' at line 1
alter table t1 convert partition p00 to table tp00;
ERROR HY000: Wrong partition name or partition list
alter table t1 convert partition p00 to table tp2;
ERROR 42S01: Table 'tp2' already exists
alter table t1 convert partition p2 to table tp2;
ERROR 42S01: Table 'tp2' already exists
create trigger tr1 before update on t1 for each row
begin
alter table t1 convert partition p2 to table tp2;
end$
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger
create function f1() returns int
begin
alter table t1 convert partition p2 to table tp2;
end$
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger
select * from tp2;
y
88
drop table tp2;
alter table t1 convert partition p2 to table tp2;
show create table tp2;
Table Create Table
tp2 CREATE TABLE `tp2` (
`x` int(11) DEFAULT NULL
) ENGINE=X DEFAULT CHARSET=latin1
select * from tp2;
x
12
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=X DEFAULT CHARSET=latin1
PARTITION BY RANGE (`x`)
(PARTITION `p1` VALUES LESS THAN (10) ENGINE = X,
PARTITION `p3` VALUES LESS THAN (30) ENGINE = X,
PARTITION `p4` VALUES LESS THAN (40) ENGINE = X,
PARTITION `p5` VALUES LESS THAN (50) ENGINE = X,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = X)
select * from t1 order by x;
x
2
22
32
42
52
alter table t1 convert partition p3 to table inexistent.tp3;
ERROR 42000: Unknown database 'inexistent'
create database EXISTENT;
alter table t1 convert partition p3 to table EXISTENT.TP3;
show create table EXISTENT.TP3;
Table Create Table
TP3 CREATE TABLE `TP3`-ok (
`x` int(11) DEFAULT NULL
) ENGINE=X DEFAULT CHARSET=latin1
select * from EXISTENT.TP3 order by x;
x
22
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=X DEFAULT CHARSET=latin1
PARTITION BY RANGE (`x`)
(PARTITION `p1` VALUES LESS THAN (10) ENGINE = X,
PARTITION `p4` VALUES LESS THAN (40) ENGINE = X,
PARTITION `p5` VALUES LESS THAN (50) ENGINE = X,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = X)
select * from t1 order by x;
x
2
32
42
52
# LOCK TABLES
lock tables t1 write;
alter table t1 convert partition p4 to table tp4;
show create table tp4;
ERROR HY000: Table 'tp4' was not locked with LOCK TABLES
unlock tables;
show create table tp4;
Table Create Table
tp4 CREATE TABLE `tp4` (
`x` int(11) DEFAULT NULL
) ENGINE=X DEFAULT CHARSET=latin1
select * from tp4;
x
32
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=X DEFAULT CHARSET=latin1
PARTITION BY RANGE (`x`)
(PARTITION `p1` VALUES LESS THAN (10) ENGINE = X,
PARTITION `p5` VALUES LESS THAN (50) ENGINE = X,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = X)
select * from t1 order by x;
x
2
42
52
# PS
prepare stmt from 'alter table t1 convert partition p5 to table tp5';
execute stmt;
show create table tp5;
Table Create Table
tp5 CREATE TABLE `tp5` (
`x` int(11) DEFAULT NULL
) ENGINE=X DEFAULT CHARSET=latin1
select * from tp5;
x
42
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=X DEFAULT CHARSET=latin1
PARTITION BY RANGE (`x`)
(PARTITION `p1` VALUES LESS THAN (10) ENGINE = X,
PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = X)
select * from t1 order by x;
x
2
52
drop table tp5;
execute stmt;
ERROR HY000: Wrong partition name or partition list
execute stmt;
ERROR HY000: Wrong partition name or partition list
drop prepare stmt;
# Privileges
create user alan;
grant usage on *.* to alan;
grant create, insert, drop on test.* to alan;
connect alan,localhost,alan,,test;
show grants for current_user;
Grants for alan@%
GRANT USAGE ON *.* TO `alan`@`%`
GRANT INSERT, CREATE, DROP ON `test`.* TO `alan`@`%`
alter table t1 convert partition p1 to table tp1;
ERROR 42000: ALTER command denied to user 'alan'@'localhost' for table 't1'
connection default;
revoke all on test.* from alan;
grant create, insert, alter on test.* to alan;
connection alan;
use test;
show grants for current_user;
Grants for alan@%
GRANT USAGE ON *.* TO `alan`@`%`
GRANT INSERT, CREATE, ALTER ON `test`.* TO `alan`@`%`
alter table t1 convert partition p1 to table tp1;
ERROR 42000: DROP command denied to user 'alan'@'localhost' for table 't1'
connection default;
revoke all on test.* from alan;
grant create, drop, alter on test.* to alan;
connection alan;
use test;
show grants for current_user;
Grants for alan@%
GRANT USAGE ON *.* TO `alan`@`%`
GRANT CREATE, DROP, ALTER ON `test`.* TO `alan`@`%`
alter table t1 convert partition p1 to table tp1;
ERROR 42000: INSERT command denied to user 'alan'@'localhost' for table 'tp1'
connection default;
revoke all on test.* from alan;
grant insert, drop, alter on test.* to alan;
connection alan;
use test;
show grants for current_user;
Grants for alan@%
GRANT USAGE ON *.* TO `alan`@`%`
GRANT INSERT, DROP, ALTER ON `test`.* TO `alan`@`%`
alter table t1 convert partition p1 to table tp1;
ERROR 42000: CREATE command denied to user 'alan'@'localhost' for table 'tp1'
connection default;
grant create, insert, drop, alter on test.* to alan;
connection alan;
use test;
show grants for current_user;
Grants for alan@%
GRANT USAGE ON *.* TO `alan`@`%`
GRANT INSERT, CREATE, DROP, ALTER ON `test`.* TO `alan`@`%`
alter table t1 convert partition p1 to table tp1;
disconnect alan;
connection default;
drop database EXISTENT;
drop user alan;
drop tables t1, tp1, tp2, tp4;
#
# General errors with ALTER TABLE and partitions that doesn't have to be run
# on all engines
#
# Permissions don't work with embedded
--source include/not_embedded.inc
--source include/have_partition.inc
--source include/lcase_names.inc
--source suite/parts/inc/engines.inc
#
# MDEV-22649 SIGSEGV in ha_partition::create_partitioning_metadata on ALTER
......@@ -38,3 +37,202 @@ CREATE TABLE t2 (i INT);
ALTER TABLE v1 EXCHANGE PARTITION p2 WITH TABLE t2 ;
DROP VIEW v1;
DROP TABLE t1, t2;
--echo #
--echo # MDEV-22166 MIGRATE PARTITION: move out partition into a table
--echo #
create or replace table t1 (x int);
--error ER_PARTITION_MGMT_ON_NONPARTITIONED
alter table t1 convert partition p1 to table tp1;
create or replace table t1 (x int)
partition by hash(x) partitions 2;
--error ER_ONLY_ON_RANGE_LIST_PARTITION
alter table t1 convert partition p1 to table tp1;
create or replace table t1 (x int)
partition by key(x) partitions 2;
--error ER_ONLY_ON_RANGE_LIST_PARTITION
alter table t1 convert partition p1 to table tp1;
create or replace table t1 (x int)
partition by range(x)
subpartition by hash(x) subpartitions 3 (
partition p1 values less than (10),
partition pn values less than maxvalue);
--error ER_PARTITION_CONVERT_SUBPARTITIONED
alter table t1 convert partition p1 to table p1;
--error ER_PARTITION_DOES_NOT_EXIST
alter table t1 convert partition p1sp0 to table p1;
create or replace table t1 (x int)
partition by range(x) (
partition p1 values less than (10));
--error ER_DROP_LAST_PARTITION
alter table t1 convert partition p1 to table tp1;
--error ER_FEATURE_NOT_SUPPORTED_WITH_PARTITIONING
create or replace temporary table t1 (x int)
partition by range(x) (
partition p0 values less than (10),
partition pn values less than maxvalue);
if ($MTR_COMBINATION_RANGE)
{
create or replace table t1 (x int)
partition by range(x) (
partition p1 values less than (10),
partition p2 values less than (20),
partition p3 values less than (30),
partition p4 values less than (40),
partition p5 values less than (50),
partition pn values less than maxvalue);
}
if ($MTR_COMBINATION_LIST)
{
create or replace table t1 (x int)
partition by list(x) (
partition p1 values in (2, 3, 4),
partition p2 values in (12, 13, 14),
partition p3 values in (22, 23, 24),
partition p4 values in (32, 33, 34),
partition p5 values in (42, 43, 44),
partition pn values in (52, 53, 54));
}
insert into t1 values (2), (12), (22), (32), (42), (52);
create or replace table tp2 (y int);
insert tp2 values (88);
# Multiple ALTER PARTITION statements are not possible
--error ER_PARSE_ERROR
alter table t1 convert partition p2 to table tp2, drop partition p3;
# TODO: probably no need in such specific codes, should be ER_PARTITION_NON_EXISTENT
--error ER_PARTITION_DOES_NOT_EXIST
alter table t1 convert partition p00 to table tp00;
# Better error here is ER_PARTITION_DOES_NOT_EXIST,
# but mysql_alter_table() works checks new table before anything else.
# So, looks like no big reason to change anything here.
--error ER_TABLE_EXISTS_ERROR
alter table t1 convert partition p00 to table tp2;
--error ER_TABLE_EXISTS_ERROR
alter table t1 convert partition p2 to table tp2;
--delimiter $
--error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
create trigger tr1 before update on t1 for each row
begin
alter table t1 convert partition p2 to table tp2;
end$
--error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
create function f1() returns int
begin
alter table t1 convert partition p2 to table tp2;
end$
--delimiter ;
select * from tp2;
drop table tp2;
alter table t1 convert partition p2 to table tp2;
--replace_result $engine X ' PAGE_CHECKSUM=1' ''
show create table tp2;
select * from tp2;
--replace_result $engine X ' PAGE_CHECKSUM=1' ''
show create table t1;
select * from t1 order by x;
--error ER_BAD_DB_ERROR
alter table t1 convert partition p3 to table inexistent.tp3;
create database EXISTENT;
alter table t1 convert partition p3 to table EXISTENT.TP3;
# The only way to put `` into var...
--let $tp3=`select '`TP3`'`
if ($MTR_COMBINATION_LCASE1)
{
--let $tp3= `select '`tp3`'`
}
--replace_result $engine X ' PAGE_CHECKSUM=1' '' $tp3 `TP3`-ok
show create table EXISTENT.TP3;
select * from EXISTENT.TP3 order by x;
--replace_result $engine X ' PAGE_CHECKSUM=1' ''
show create table t1;
select * from t1 order by x;
--echo # LOCK TABLES
lock tables t1 write;
alter table t1 convert partition p4 to table tp4;
# TODO: lock table tp4 in ALTER TABLE, otherwise there is no
# guarantee in data consistency between t1 and tp4
--error ER_TABLE_NOT_LOCKED
show create table tp4;
unlock tables;
--replace_result $engine X ' PAGE_CHECKSUM=1' ''
show create table tp4;
select * from tp4;
--replace_result $engine X ' PAGE_CHECKSUM=1' ''
show create table t1;
select * from t1 order by x;
--echo # PS
prepare stmt from 'alter table t1 convert partition p5 to table tp5';
execute stmt;
--replace_result $engine X ' PAGE_CHECKSUM=1' ''
show create table tp5;
select * from tp5;
--replace_result $engine X ' PAGE_CHECKSUM=1' ''
show create table t1;
select * from t1 order by x;
drop table tp5;
--error ER_PARTITION_DOES_NOT_EXIST
execute stmt;
--error ER_PARTITION_DOES_NOT_EXIST
execute stmt;
drop prepare stmt;
--echo # Privileges
create user alan;
grant usage on *.* to alan;
grant create, insert, drop on test.* to alan;
--connect alan,localhost,alan,,test
show grants for current_user;
--error ER_TABLEACCESS_DENIED_ERROR
alter table t1 convert partition p1 to table tp1;
--connection default
revoke all on test.* from alan;
grant create, insert, alter on test.* to alan;
--connection alan
use test;
show grants for current_user;
--error ER_TABLEACCESS_DENIED_ERROR
alter table t1 convert partition p1 to table tp1;
--connection default
revoke all on test.* from alan;
grant create, drop, alter on test.* to alan;
--connection alan
use test;
show grants for current_user;
--error ER_TABLEACCESS_DENIED_ERROR
alter table t1 convert partition p1 to table tp1;
--connection default
revoke all on test.* from alan;
grant insert, drop, alter on test.* to alan;
--connection alan
use test;
show grants for current_user;
--error ER_TABLEACCESS_DENIED_ERROR
alter table t1 convert partition p1 to table tp1;
--connection default
grant create, insert, drop, alter on test.* to alan;
--connection alan
use test;
show grants for current_user;
alter table t1 convert partition p1 to table tp1;
--disconnect alan
--connection default
drop database EXISTENT;
drop user alan;
drop tables t1, tp1, tp2, tp4;
......@@ -50,3 +50,63 @@ let $crash_statement= ALTER TABLE t1 EXCHANGE PARTITION p0 WITH TABLE t2;
--source suite/parts/inc/partition_crash_exchange.inc
let $fail_statement= $crash_statement;
--source suite/parts/inc/partition_fail_exchange.inc
--echo #
--echo # MDEV-22166 MIGRATE PARTITION: move out partition into a table
--echo #
let $create_statement= create or replace table t1 (x int primary key)
partition by range(x) (
partition p1 values less than (10),
partition p2 values less than (20),
partition p3 values less than (30),
partition p4 values less than (40),
partition p5 values less than (50),
partition pn values less than maxvalue);
let $insert_statement= insert into t1 values (2), (12), (22), (32), (42), (52);
let $fail_statement= alter table t1 convert partition p2 to table tp2;
set @save_dbug=@@debug_dbug;
set session debug_dbug="+d,fail_create_before_create_frm";
--source suite/parts/inc/partition_fail.inc
set session debug_dbug=@save_dbug;
set session debug_dbug="+d,fail_alter_partition_after_write_frm";
--source suite/parts/inc/partition_fail.inc
set session debug_dbug=@save_dbug;
set session debug_dbug="+d,error_convert_partition_00";
--source suite/parts/inc/partition_fail.inc
#set session debug_dbug=@save_dbug;
#set session debug_dbug="+d,fail_convert_partition_01";
#--source suite/parts/inc/partition_fail.inc
set session debug_dbug=@save_dbug;
set session debug_dbug="+d,fail_convert_partition_1";
--source suite/parts/inc/partition_fail.inc
set session debug_dbug=@save_dbug;
set session debug_dbug="+d,fail_convert_partition_2";
--source suite/parts/inc/partition_fail.inc
set session debug_dbug=@save_dbug;
set session debug_dbug="+d,fail_convert_partition_3";
--source suite/parts/inc/partition_fail.inc
set session debug_dbug=@save_dbug;
set session debug_dbug="+d,fail_convert_partition_4";
--source suite/parts/inc/partition_fail.inc
set session debug_dbug=@save_dbug;
set session debug_dbug="+d,fail_convert_partition_5";
--source suite/parts/inc/partition_fail.inc
set session debug_dbug=@save_dbug;
set session debug_dbug="+d,fail_convert_partition_6";
--source suite/parts/inc/partition_fail.inc
set session debug_dbug=@save_dbug;
set session debug_dbug="+d,fail_convert_partition_7";
--source suite/parts/inc/partition_fail.inc
set session debug_dbug=@save_dbug;
set session debug_dbug="+d,fail_convert_partition_8";
--source suite/parts/inc/partition_fail.inc
set session debug_dbug=@save_dbug;
set session debug_dbug="+d,fail_convert_partition_9";
--echo # Already finished DDL logging, so tp2 now exists:
--source suite/parts/inc/partition_fail.inc
set session debug_dbug=@save_dbug;
show create table tp2;
select * from tp2;
drop table tp2;
--- partition.result
+++ partition,heap.reject
@@ -1545,82 +1545,3 @@
(PARTITION `p0` HISTORY ENGINE = X,
PARTITION `pn` CURRENT ENGINE = X)
drop tables t1, tp1;
-# Complex table
-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 key (x, u),
-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 range(x) (
-partition p0 values less than (10),
-partition p1 values less than (20),
-partition pn values less than maxvalue);
-alter table t1 convert partition p1 to table tp1;
-show create table tp1;
-Table Create Table
-tp1 CREATE TABLE `tp1` (
- `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 `x` (`x`,`u`,`e`),
- KEY `three` (`i1`,`i2`,`i3`),
- PERIOD FOR SYSTEM_TIME (`s`, `e`),
- CONSTRAINT `check_constr` CHECK (`u` > -1)
-) ENGINE=X DEFAULT CHARSET=ucs2 WITH SYSTEM VERSIONING
-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 `x` (`x`,`u`,`e`),
- KEY `three` (`i1`,`i2`,`i3`),
- PERIOD FOR SYSTEM_TIME (`s`, `e`),
- CONSTRAINT `check_constr` CHECK (`u` > -1)
-) ENGINE=X DEFAULT CHARSET=ucs2 WITH SYSTEM VERSIONING
- PARTITION BY RANGE (`x`)
-(PARTITION `p0` VALUES LESS THAN (10) ENGINE = X,
- PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = X)
-drop tables t1, tp1;
......@@ -1110,4 +1110,203 @@ SET GLOBAL innodb_stats_persistent=@save_persistent;
--echo # End of 10.6 tests
--echo #
--echo # MDEV-22166 MIGRATE PARTITION: move out partition into a table
--echo #
create or replace table t1 (x int)
with system versioning
partition by range(x) (
partition p1 values less than (10),
partition p2 values less than (20),
partition p3 values less than (30),
partition p4 values less than (40),
partition p5 values less than (50),
partition pn values less than maxvalue);
insert into t1 values (2), (12), (22), (32), (42), (52);
update t1 set x= x + 1;
alter table t1 convert partition p2 to table tp2;
--replace_result $default_engine X ' PAGE_CHECKSUM=1' ''
show create table tp2;
select * from tp2;
select * from tp2 for system_time all order by x;
--replace_result $default_engine X ' PAGE_CHECKSUM=1' ''
show create table t1;
select * from t1 order by x;
select * from t1 for system_time all order by x;
--echo # SP
create or replace procedure sp()
alter table t1 convert partition p3 to table tp3;
call sp;
--replace_result $default_engine X ' PAGE_CHECKSUM=1' ''
show create table tp3;
select * from tp3;
--replace_result $default_engine X ' PAGE_CHECKSUM=1' ''
show create table t1;
select * from t1 order by x;
drop table tp3;
--error ER_PARTITION_DOES_NOT_EXIST
call sp;
--error ER_PARTITION_DOES_NOT_EXIST
call sp;
drop procedure sp;
--echo # LOCK TABLES, PS, SP
create or replace procedure sp()
alter table t1 convert partition p4 to table tp4;
lock tables t1 write;
prepare stmt from 'call sp';
execute stmt;
# TODO: don't unlock here (see above TODO)
unlock tables;
--replace_result $default_engine X ' PAGE_CHECKSUM=1' ''
show create table tp4;
select * from tp4;
--replace_result $default_engine X ' PAGE_CHECKSUM=1' ''
show create table t1;
select * from t1 order by x;
drop table tp4;
lock tables t1 write;
--error ER_PARTITION_DOES_NOT_EXIST
execute stmt;
--error ER_PARTITION_DOES_NOT_EXIST
call sp;
drop prepare stmt;
unlock tables;
drop procedure sp;
unlock tables;
drop tables t1, tp2;
--echo # System-versioned tables (SYSTEM_TIME LIMIT)
create or replace table t1 (
x int,
row_start timestamp(6) as row start invisible,
row_end timestamp(6) as row end invisible,
period for system_time(row_start, row_end)
) with system versioning
partition by system_time limit 1 partitions 4;
insert into t1 values (2), (12), (22);
update t1 set x= x + 1 where x = 2;
update t1 set x= x + 1 where x = 12;
update t1 set x= x + 1 where x = 22;
select * from t1 partition (p1);
--error ER_VERS_WRONG_PARTS
alter table t1 convert partition pn to table tp1;
alter table t1 convert partition p1 to table tp1;
--replace_result $default_engine X ' PAGE_CHECKSUM=1' ''
show create table tp1;
select * from tp1;
select * from tp1 for system_time all;
--replace_result $default_engine X ' PAGE_CHECKSUM=1' ''
show create table t1;
select * from t1 order by x;
select * from t1 for system_time all order by x;
drop tables t1, tp1;
--echo # System-versioned tables (SYSTEM_TIME INTERVAL)
set timestamp= unix_timestamp('2000-01-01 00:00:00');
create or replace table t1 (
x int,
row_start timestamp(6) as row start invisible,
row_end timestamp(6) as row end invisible,
period for system_time(row_start, row_end)
) with system versioning
partition by system_time interval 1 hour partitions 4;
insert into t1 values (2), (12), (22);
set timestamp= unix_timestamp('2000-01-01 00:00:01');
update t1 set x= x + 1 where x = 2;
set timestamp= unix_timestamp('2000-01-01 01:00:00');
update t1 set x= x + 1 where x = 12;
set timestamp= unix_timestamp('2000-01-01 02:00:00');
update t1 set x= x + 1 where x = 22;
select * from t1 partition (p0);
select * from t1 partition (p1);
select * from t1 partition (p2);
--error ER_VERS_DROP_PARTITION_INTERVAL
alter table t1 convert partition p1 to table tp1;
alter table t1 convert partition p0 to table tp0;
alter table t1 convert partition p1 to table tp1;
--error ER_VERS_WRONG_PARTS
alter table t1 convert partition p2 to table tp2;
--replace_result $default_engine X ' PAGE_CHECKSUM=1' ''
show create table tp0;
--replace_result $default_engine X ' PAGE_CHECKSUM=1' ''
show create table tp1;
select * from tp0;
select * from tp1;
select * from tp0 for system_time all;
select * from tp1 for system_time all;
--replace_result $default_engine X ' PAGE_CHECKSUM=1' ''
show create table t1;
select * from t1;
select * from t1 for system_time all order by x;
drop tables t1, tp0, tp1;
--echo # System-versioned tables (implicit)
create or replace table t1(x int) with system versioning
partition by system_time limit 1 partitions 3;
alter table t1 convert partition p1 to table tp1;
--replace_result $default_engine X ' PAGE_CHECKSUM=1' ''
show create table tp1;
--replace_result $default_engine X ' PAGE_CHECKSUM=1' ''
show create table t1;
drop tables t1, tp1;
if (!$MTR_COMBINATION_HEAP)
{
--echo # Complex table
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 key (x, u),
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 range(x) (
partition p0 values less than (10),
partition p1 values less than (20),
partition pn values less than maxvalue);
alter table t1 convert partition p1 to table tp1;
--replace_result $default_engine X ' PAGE_CHECKSUM=1' ''
show create table tp1;
--replace_result $default_engine X ' PAGE_CHECKSUM=1' ''
show create table t1;
drop tables t1, tp1;
}
--source suite/versioning/common_finish.inc
......@@ -824,6 +824,7 @@ typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*);
#define ALTER_PARTITION_TRUNCATE (1ULL << 11)
// Set for REORGANIZE PARTITION
#define ALTER_PARTITION_TABLE_REORG (1ULL << 12)
#define ALTER_PARTITION_CONVERT_OUT (1ULL << 13)
/*
This is master database for most of system tables. However there
......
......@@ -7992,3 +7992,5 @@ ER_STORAGE_ENGINE_DISABLED
eng "Storage engine %s is disabled"
WARN_SFORMAT_ERROR
eng "SFORMAT error: %s"
ER_PARTITION_CONVERT_SUBPARTITIONED
eng "Convert partition is not supported for subpartitioned table."
......@@ -262,10 +262,8 @@ Alter_table_ctx::Alter_table_ctx()
storage_engine_partitioned(false),
tmp_storage_engine_name_partitioned(false),
fk_error_if_delete_row(false), fk_error_id(NULL),
fk_error_table(NULL)
#ifdef DBUG_ASSERT_EXISTS
, tmp_table(false)
#endif
fk_error_table(NULL),
tmp_table(false)
{
}
......@@ -442,6 +440,7 @@ bool Sql_cmd_alter_table::execute(THD *thd)
as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
*/
if ((alter_info.partition_flags & ALTER_PARTITION_DROP) ||
(alter_info.partition_flags & ALTER_PARTITION_CONVERT_OUT) ||
(alter_info.flags & ALTER_RENAME))
priv_needed|= DROP_ACL;
......
......@@ -250,13 +250,15 @@ class Alter_table_ctx
const LEX_CSTRING *new_db_arg, const LEX_CSTRING *new_name_arg);
/**
@return true if the table is moved to another database, false otherwise.
@return true if the table is moved to another database or a new table
created by ALTER_PARTITION_CONVERT_OUT, false otherwise.
*/
bool is_database_changed() const
{ return (new_db.str != db.str); };
/**
@return true if the table is renamed, false otherwise.
@return true if the table is renamed or a new table created by
ALTER_PARTITION_CONVERT_OUT, false otherwise.
*/
bool is_table_renamed() const
{ return (is_database_changed() || new_name.str != table_name.str); };
......
......@@ -11255,6 +11255,26 @@ bool LEX::stmt_alter_table_exchange_partition(Table_ident *table)
}
bool LEX::stmt_alter_table(Table_ident *table)
{
DBUG_ASSERT(sql_command == SQLCOM_ALTER_TABLE);
DBUG_ASSERT(!m_sql_cmd);
first_select_lex()->db= table->db;
if (first_select_lex()->db.str == NULL &&
copy_db_to(&first_select_lex()->db))
return true;
if (unlikely(check_table_name(table->table.str, table->table.length,
false)) ||
(table->db.str && unlikely(check_db_name((LEX_STRING*) &table->db))))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
return true;
}
name= table->table;
return false;
}
void LEX::stmt_purge_to(const LEX_CSTRING &to)
{
type= 0;
......
......@@ -4661,6 +4661,7 @@ struct LEX: public Query_tables_list
void stmt_deallocate_prepare(const Lex_ident_sys_st &ident);
bool stmt_alter_table_exchange_partition(Table_ident *table);
bool stmt_alter_table(Table_ident *table);
void stmt_purge_to(const LEX_CSTRING &to);
bool stmt_purge_before(Item *item);
......
This diff is collapsed.
......@@ -55,6 +55,7 @@ typedef struct st_lock_param_type
THD *thd;
HA_CREATE_INFO *create_info;
Alter_info *alter_info;
Alter_table_ctx *alter_ctx;
TABLE *table;
KEY *key_info_buffer;
LEX_CSTRING db;
......@@ -64,6 +65,7 @@ typedef struct st_lock_param_type
uint key_count;
uint db_options;
size_t pack_frm_len;
// TODO: remove duplicate data: part_info can be accessed via table->part_info
partition_info *part_info;
} ALTER_PARTITION_PARAM_TYPE;
......@@ -255,10 +257,9 @@ typedef int (*get_partitions_in_range_iter)(partition_info *part_info,
#ifdef WITH_PARTITION_STORAGE_ENGINE
uint fast_alter_partition_table(THD *thd, TABLE *table,
Alter_info *alter_info,
Alter_table_ctx *alter_ctx,
HA_CREATE_INFO *create_info,
TABLE_LIST *table_list,
const LEX_CSTRING *db,
const LEX_CSTRING *table_name);
TABLE_LIST *table_list);
bool set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
enum partition_state part_state);
uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
......@@ -279,6 +280,10 @@ bool verify_data_with_partition(TABLE *table, TABLE *part_table,
bool compare_partition_options(HA_CREATE_INFO *table_create_info,
partition_element *part_elem);
bool partition_key_modified(TABLE *table, const MY_BITMAP *fields);
bool write_log_replace_frm(ALTER_PARTITION_PARAM_TYPE *lpt,
uint next_entry,
const char *from_path,
const char *to_path);
#else
#define partition_key_modified(X,Y) 0
#endif
......
......@@ -667,10 +667,12 @@ void build_lower_case_table_filename(char *buff, size_t bufflen,
*/
uint build_table_shadow_filename(char *buff, size_t bufflen,
ALTER_PARTITION_PARAM_TYPE *lpt)
ALTER_PARTITION_PARAM_TYPE *lpt,
bool backup)
{
char tmp_name[FN_REFLEN];
my_snprintf(tmp_name, sizeof (tmp_name), "%s-shadow-%lx-%s", tmp_file_prefix,
my_snprintf(tmp_name, sizeof (tmp_name), "%s-%s-%lx-%s", tmp_file_prefix,
backup ? "backup" : "shadow",
(ulong) current_thd->thread_id, lpt->table_name.str);
return build_table_filename(buff, bufflen, lpt->db.str, tmp_name, "",
FN_IS_TMP);
......@@ -704,6 +706,11 @@ uint build_table_shadow_filename(char *buff, size_t bufflen,
tables since it only handles partitioned data if it exists.
*/
/*
TODO: Partitioning atomic DDL refactoring: WFRM_WRITE_SHADOW and
WFRM_WRITE_EXTRACTED should be merged with create_table_impl(frm_only == true).
*/
bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
{
/*
......@@ -715,10 +722,13 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
char path[FN_REFLEN+1];
char shadow_path[FN_REFLEN+1];
char shadow_frm_name[FN_REFLEN+1];
char bak_path[FN_REFLEN+1];
char bak_frm_name[FN_REFLEN+1];
char frm_name[FN_REFLEN+1];
#ifdef WITH_PARTITION_STORAGE_ENGINE
char *part_syntax_buf;
uint syntax_len;
partition_info *part_info= lpt->part_info;
#endif
DBUG_ENTER("mysql_write_frm");
......@@ -777,6 +787,98 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
goto end;
}
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (flags & WFRM_WRITE_CONVERTED_TO)
{
THD *thd= lpt->thd;
Alter_table_ctx *alter_ctx= lpt->alter_ctx;
HA_CREATE_INFO *create_info= lpt->create_info;
LEX_CSTRING new_path= { alter_ctx->get_new_path(), 0 };
partition_info *work_part_info= thd->work_part_info;
handlerton *db_type= create_info->db_type;
DBUG_ASSERT(lpt->table->part_info);
DBUG_ASSERT(lpt->table->part_info == part_info);
handler *file= ((ha_partition *)(lpt->table->file))->get_child_handlers()[0];
DBUG_ASSERT(file);
new_path.length= strlen(new_path.str);
strxnmov(frm_name, sizeof(frm_name) - 1, new_path.str, reg_ext, NullS);
create_info->alias= alter_ctx->table_name;
thd->work_part_info= NULL;
create_info->db_type= work_part_info->default_engine_type;
/* NOTE: partitioned temporary tables are not supported. */
DBUG_ASSERT(!create_info->tmp_table());
if (ddl_log_create_table(thd, part_info, create_info->db_type, &new_path,
&alter_ctx->new_db, &alter_ctx->new_name, true) ||
ERROR_INJECT_ERROR("fail_create_before_create_frm"))
DBUG_RETURN(TRUE);
debug_crash_here("ddl_log_create_before_create_frm");
if (mysql_prepare_create_table(thd, create_info, lpt->alter_info,
&lpt->db_options, file,
&lpt->key_info_buffer, &lpt->key_count,
C_ALTER_TABLE, alter_ctx->new_db,
alter_ctx->new_name))
DBUG_RETURN(TRUE);
lpt->create_info->table_options= lpt->db_options;
LEX_CUSTRING frm= build_frm_image(thd, alter_ctx->new_name, create_info,
lpt->alter_info->create_list,
lpt->key_count, lpt->key_info_buffer,
file);
if (unlikely(!frm.str))
DBUG_RETURN(TRUE);
thd->work_part_info= work_part_info;
create_info->db_type= db_type;
debug_crash_here("ddl_log_alter_partition_after_create_frm");
error= writefile(frm_name, alter_ctx->new_db.str, alter_ctx->new_name.str,
create_info->tmp_table(), frm.str, frm.length);
my_free((void *) frm.str);
if (unlikely(error) || ERROR_INJECT_ERROR("fail_alter_partition_after_write_frm"))
{
mysql_file_delete(key_file_frm, frm_name, MYF(0));
DBUG_RETURN(TRUE);
}
debug_crash_here("ddl_log_alter_partition_after_write_frm");
DBUG_RETURN(false);
}
if (flags & WFRM_BACKUP_ORIGINAL)
{
build_table_filename(path, sizeof(path) - 1, lpt->db.str,
lpt->table_name.str, "", 0);
strxnmov(frm_name, sizeof(frm_name), path, reg_ext, NullS);
build_table_shadow_filename(bak_path, sizeof(bak_path) - 1, lpt, true);
strxmov(bak_frm_name, bak_path, reg_ext, NullS);
DDL_LOG_MEMORY_ENTRY *main_entry= part_info->main_entry;
mysql_mutex_lock(&LOCK_gdl);
if (write_log_replace_frm(lpt, part_info->list->entry_pos,
(const char*) bak_path,
(const char*) path) ||
ddl_log_write_execute_entry(part_info->list->entry_pos,
&part_info->execute_entry))
{
mysql_mutex_unlock(&LOCK_gdl);
DBUG_RETURN(TRUE);
}
mysql_mutex_unlock(&LOCK_gdl);
part_info->main_entry= main_entry;
if (mysql_file_rename(key_file_frm, frm_name, bak_frm_name, MYF(MY_WME)))
DBUG_RETURN(TRUE);
if (lpt->table->file->ha_create_partitioning_metadata(bak_path, path,
CHF_RENAME_FLAG))
DBUG_RETURN(TRUE);
}
#else /* !WITH_PARTITION_STORAGE_ENGINE */
DBUG_ASSERT(!(flags & WFRM_WRITE_EXTRACTED));
DBUG_ASSERT(!(flags & WFRM_BACKUP_ORIGINAL));
DBUG_ASSERT(!(flags & WFRM_DROP_BACKUP));
#endif /* !WITH_PARTITION_STORAGE_ENGINE */
if (flags & WFRM_INSTALL_SHADOW)
{
#ifdef WITH_PARTITION_STORAGE_ENGINE
......@@ -798,20 +900,25 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
completing this we write a new phase to the log entry that will
deactivate it.
*/
if (mysql_file_delete(key_file_frm, frm_name, MYF(MY_WME)) ||
if (!(flags & WFRM_BACKUP_ORIGINAL) && (
mysql_file_delete(key_file_frm, frm_name, MYF(MY_WME))
#ifdef WITH_PARTITION_STORAGE_ENGINE
lpt->table->file->ha_create_partitioning_metadata(path, shadow_path,
|| lpt->table->file->ha_create_partitioning_metadata(path, shadow_path,
CHF_DELETE_FLAG) ||
ddl_log_increment_phase(part_info->main_entry->entry_pos) ||
(ddl_log_sync(), FALSE) ||
mysql_file_rename(key_file_frm,
shadow_frm_name, frm_name, MYF(MY_WME)) ||
lpt->table->file->ha_create_partitioning_metadata(path, shadow_path,
CHF_RENAME_FLAG))
#else
mysql_file_rename(key_file_frm,
shadow_frm_name, frm_name, MYF(MY_WME)))
(ddl_log_sync(), FALSE)
#endif
))
{
error= 1;
goto err;
}
if (mysql_file_rename(key_file_frm, shadow_frm_name, frm_name, MYF(MY_WME))
#ifdef WITH_PARTITION_STORAGE_ENGINE
|| lpt->table->file->ha_create_partitioning_metadata(path, shadow_path,
CHF_RENAME_FLAG)
#endif
)
{
error= 1;
goto err;
......@@ -4161,7 +4268,6 @@ handler *mysql_create_frm_image(THD *thd, const LEX_CSTRING &db,
@retval -1 table existed but IF NOT EXISTS was used
*/
static
int create_table_impl(THD *thd,
DDL_LOG_STATE *ddl_log_state_create,
DDL_LOG_STATE *ddl_log_state_rm,
......@@ -9892,10 +9998,8 @@ do_continue:;
}
// In-place execution of ALTER TABLE for partitioning.
DBUG_RETURN(fast_alter_partition_table(thd, table, alter_info,
create_info, table_list,
&alter_ctx.db,
&alter_ctx.table_name));
DBUG_RETURN(fast_alter_partition_table(thd, table, alter_info, &alter_ctx,
create_info, table_list));
}
#endif
......
......@@ -20,6 +20,11 @@
#include <my_sys.h> // pthread_mutex_t
#include "m_string.h" // LEX_CUSTRING
#define ERROR_INJECT_CRASH(code) \
(DBUG_IF(code) && (DBUG_SUICIDE(), false))
#define ERROR_INJECT_ERROR(code) \
(DBUG_IF(code) && (my_error(ER_UNKNOWN_ERROR, MYF(0)), 1))
class Alter_info;
class Alter_table_ctx;
class Column_definition;
......@@ -53,6 +58,9 @@ enum enum_explain_filename_mode
#define WFRM_WRITE_SHADOW 1
#define WFRM_INSTALL_SHADOW 2
#define WFRM_KEEP_SHARE 4
#define WFRM_WRITE_CONVERTED_TO 8
#define WFRM_BACKUP_ORIGINAL 16
#define WFRM_DROP_BACKUP 32
/* Flags for conversion functions. */
static const uint FN_FROM_IS_TMP= 1 << 0;
......@@ -77,7 +85,8 @@ bool check_mysql50_prefix(const char *name);
uint build_table_filename(char *buff, size_t bufflen, const char *db,
const char *table, const char *ext, uint flags);
uint build_table_shadow_filename(char *buff, size_t bufflen,
ALTER_PARTITION_PARAM_TYPE *lpt);
ALTER_PARTITION_PARAM_TYPE *lpt,
bool backup= false);
void build_lower_case_table_filename(char *buff, size_t bufflen,
const LEX_CSTRING *db,
const LEX_CSTRING *table,
......
......@@ -7279,6 +7279,17 @@ alter_commands:
if (Lex->stmt_alter_table_exchange_partition($6))
MYSQL_YYABORT;
}
| CONVERT_SYM PARTITION_SYM alt_part_name_item
TO_SYM TABLE_SYM table_ident have_partitioning
{
LEX *lex= Lex;
if (Lex->stmt_alter_table($6))
MYSQL_YYABORT;
lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table();
if (unlikely(lex->m_sql_cmd == NULL))
MYSQL_YYABORT;
lex->alter_info.partition_flags|= ALTER_PARTITION_CONVERT_OUT;
}
;
remove_partitioning:
......@@ -7527,17 +7538,9 @@ alter_list_item:
}
| RENAME opt_to table_ident
{
LEX *lex=Lex;
lex->first_select_lex()->db= $3->db;
if (lex->first_select_lex()->db.str == NULL &&
lex->copy_db_to(&lex->first_select_lex()->db))
MYSQL_YYABORT;
if (unlikely(check_table_name($3->table.str,$3->table.length,
FALSE)) ||
($3->db.str && unlikely(check_db_name((LEX_STRING*) &$3->db))))
my_yyabort_error((ER_WRONG_TABLE_NAME, MYF(0), $3->table.str));
lex->name= $3->table;
lex->alter_info.flags|= ALTER_RENAME;
if (Lex->stmt_alter_table($3))
MYSQL_YYABORT;
Lex->alter_info.flags|= ALTER_RENAME;
}
| RENAME COLUMN_SYM opt_if_exists_table_element ident TO_SYM ident
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment