diff options
author | Monty <monty@mariadb.org> | 2021-03-30 17:06:55 +0300 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2021-05-19 22:54:13 +0200 |
commit | 83e529eced51aa965805e894349bbadd26881f3f (patch) | |
tree | 2f13b79cf5648498ee709424ea37105be730fcf3 | |
parent | 496a14e18714ac3f0b686ec5f57bf88e96512d2f (diff) | |
download | mariadb-git-83e529eced51aa965805e894349bbadd26881f3f.tar.gz |
MDEV-18465 Logging of DDL statements during backup
Many of the changes was needed to be able to collect and print engine
name and table version id's in the ddl log.
46 files changed, 1841 insertions, 145 deletions
diff --git a/mysql-test/include/print_ddl_log.inc b/mysql-test/include/print_ddl_log.inc new file mode 100644 index 00000000000..7b09c62231e --- /dev/null +++ b/mysql-test/include/print_ddl_log.inc @@ -0,0 +1,78 @@ +--echo # +--echo # Reading backup ddl log file +--echo # + +let MYSQLD_DATADIR= `select @@datadir`; +perl; + $datadir= $ENV{'MYSQLD_DATADIR'}; + $id_count= 0; + $tmp_table_count; + + open(FILE, "$datadir/ddl.log") or + die("Unable to read log file $datadir/ddl.log: $!\n"); + while(<FILE>) + { + chop; + if (/([^\t]*)[\t]([^\t]*)[\t]([^\t]*)[\t]([^\t]*)[\t]([^\t]*)[\t]([^\t]*)[\t]([^\t]*)[\t]([^\t]*)[\t]([^\t]*)[\t]([^\t]*)[\t]([^\t]*)[\t]([^\t]*)/) + { + my $date = $1; + my $query = $2; + my $storage = $3; + my $partitioned = $4; + my $db = $5; + my $table = $6; + my $table_ver = $7; + my $new_storage = $8; + my $new_partitioned = $9; + my $new_db = $10; + my $new_table = $11; + my $new_table_ver = $12; + # Fix table ids + $table_id1= ""; + $table_id2= ""; + if (!($table_ver eq "")) + { + $table_id1= "id: $id{$table_ver}"; + if (!exists($id{$table_ver})) + { + $id_count++; + $table_id1= "id: $id_count"; + $id{$table_ver}= $id_count; + } + } + if (!($new_table_ver eq "")) + { + $table_id2= "id: $id{$new_table_ver}"; + if (!exists($id{$new_table_ver})) + { + $id_count++; + $table_id2= "id: $id_count"; + $id{$new_table_ver}= $id_count; + } + } + # Fix table names + $table_name1= $table; + if (substr($table_name1,0,5) eq '@0023') + { + if (!exists($name{$table_name1})) + { + $tmp_table_count++; + $name{$table_name1}= "#sql" . $tmp_table_count; + } + $table_name1= $name{$table_name1}; + } + $table_name2= $new_table; + if (substr($table_name2,0,5) eq '@0023') + { + if (!exists($name{$table_name2})) + { + $tmp_table_count++; + $name{$table_name2}= "#sql" . $tmp_table_count; + } + $table_name2= $name{$table_name2}; + } + + print "$query,$storage,$partitioned,$db,$table_name1,$table_id1,$new_storage,$new_partitioned,$new_db,$table_name2,$table_id2\n"; + } + } +EOF diff --git a/mysql-test/main/backup_lock.result b/mysql-test/main/backup_lock.result index 96503814d00..e519d3d325a 100644 --- a/mysql-test/main/backup_lock.result +++ b/mysql-test/main/backup_lock.result @@ -30,12 +30,14 @@ connection default; # testing if BACKUP STAGE FLUSH causes deadlocks with ALTER TABLE # create table t1 (a int) engine=innodb; +connection con2; +backup stage start; +connection default; start transaction; insert into t1 values (1); connection con1; alter table t1 add column (j int), algorithm copy; connection con2; -backup stage start; backup stage flush; SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info; LOCK_MODE LOCK_TYPE TABLE_SCHEMA TABLE_NAME @@ -175,6 +177,23 @@ select * from t1; a 1 drop table t1; +# +# Check if BACKUP STAGE BLOCK_DDL blocks create view +# +create table t1 (a int) engine=innodb; +connection con1; +backup stage start; +backup stage block_ddl; +connection default; +create view v1 as select * from t1;; +connection con1; +select count(*) = 1 from information_schema.processlist; +count(*) = 1 +0 +backup stage end; +connection default; +drop table t1; +drop view v1; disconnect con1; disconnect con2; # diff --git a/mysql-test/main/backup_lock.test b/mysql-test/main/backup_lock.test index 0d4da8cb892..f51b6ecdaad 100644 --- a/mysql-test/main/backup_lock.test +++ b/mysql-test/main/backup_lock.test @@ -36,6 +36,10 @@ connection default; create table t1 (a int) engine=innodb; +connection con2; +backup stage start; +connection default; + start transaction; # Acquires MDL lock insert into t1 values (1); @@ -49,7 +53,6 @@ let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock"; --source include/wait_condition.inc -backup stage start; backup stage flush; SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info; # @@ -227,6 +230,28 @@ connection default; select * from t1; drop table t1; +--echo # +--echo # Check if BACKUP STAGE BLOCK_DDL blocks create view +--echo # + +create table t1 (a int) engine=innodb; +connection con1; +backup stage start; +backup stage block_ddl; +connection default; +--send create view v1 as select * from t1; +connection con1; +--sleep 2 +select count(*) = 1 from information_schema.processlist; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for backup lock"; +backup stage end; +connection default; +--reap # create +drop table t1; +drop view v1; + # # End of tests using con1 and con2 # diff --git a/mysql-test/main/backup_lock_debug.result b/mysql-test/main/backup_lock_debug.result index 7c7b05901a9..229c32a85f4 100644 --- a/mysql-test/main/backup_lock_debug.result +++ b/mysql-test/main/backup_lock_debug.result @@ -33,11 +33,13 @@ SET DEBUG_SYNC= 'RESET'; # CREATE DATABASE test2; CREATE TABLE t1(a INT) ENGINE=InnoDB; +connect con1,localhost,root,,; +BACKUP STAGE START; +connection default; SET DEBUG_SYNC='alter_opened_table SIGNAL ready WAIT_FOR go'; ALTER TABLE t1 RENAME TO test2.t1; -connect con1,localhost,root,,; +connection con1; SET DEBUG_SYNC='now WAIT_FOR ready'; -BACKUP STAGE START; SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL ready1'; BACKUP STAGE BLOCK_DDL; connect con2,localhost,root,,; diff --git a/mysql-test/main/backup_lock_debug.test b/mysql-test/main/backup_lock_debug.test index 80e7cf9e181..37d70b04e0d 100644 --- a/mysql-test/main/backup_lock_debug.test +++ b/mysql-test/main/backup_lock_debug.test @@ -49,12 +49,15 @@ SET DEBUG_SYNC= 'RESET'; CREATE DATABASE test2; CREATE TABLE t1(a INT) ENGINE=InnoDB; +connect (con1,localhost,root,,); +BACKUP STAGE START; + +--connection default SET DEBUG_SYNC='alter_opened_table SIGNAL ready WAIT_FOR go'; send ALTER TABLE t1 RENAME TO test2.t1; -connect (con1,localhost,root,,); +--connection con1 SET DEBUG_SYNC='now WAIT_FOR ready'; -BACKUP STAGE START; SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL ready1'; send BACKUP STAGE BLOCK_DDL; diff --git a/mysql-test/main/backup_log.inc b/mysql-test/main/backup_log.inc new file mode 100644 index 00000000000..f553a3b9527 --- /dev/null +++ b/mysql-test/main/backup_log.inc @@ -0,0 +1,155 @@ +# This file is used for common DDL log test for both partiotioned +# and non-partitioned tables. +# Parameters: +# $part_int - partition definition for int field, must be empty for +# non-partitioned testing +# $part_date - partition definition for date field, must be empty for +# non-partitioned testing + +--echo # +--echo # Testing with normal tables +--echo # + +eval create table t1 (a int) engine=myisam $part_int; +insert into t1 values (1),(2); +alter table t1 add column b int; +alter table t1 rename as t2; +rename table t2 to t1; +truncate table t1; +repair table t1; +optimize table t1; +drop table t1; + +eval create table t1_innodb (a int) engine=innodb $part_int; +insert into t1_innodb values (1),(2); +alter table t1_innodb add column b int; +alter table t1_innodb rename as t2_innodb; +rename table t2_innodb to t1_innodb; +truncate table t1_innodb; +repair table t1_innodb; +optimize table t1_innodb; +drop table t1_innodb; + +--echo # +--echo # Testing with temporary tables (should not be logged) +--echo # + +create temporary table tmp_t10 (a int) engine=myisam; +alter table tmp_t10 add column b int; +alter table tmp_t10 rename as tmp_t11; +rename table tmp_t11 to tmp_t10; +truncate table tmp_t10; +drop table tmp_t10; + +--echo # +--echo # Testing with mix of normal and temporary tables +--echo # + +create temporary table tmp_t20 (a int); +eval create table t20 (a int) $part_int; +drop table tmp_t20,t20; + +create temporary table tmp_t21 (a int); +eval create table t21 (a int) $part_int; +drop temporary table if exists tmp_t21,t21; +drop table if exists tmp_t21,t21; + +--echo # +--echo # Testing create select +--echo # + +eval create table t30 (a int) $part_int; +insert into t30 values (1),(1); +eval create table t31 (a int primary key) $part_int select * from t30 limit 1; +create or replace table t31 select * from t30 limit 1; +create or replace temporary table t30_dup select * from t30 limit 1; +--error ER_DUP_ENTRY +eval create or replace table t31 (a int primary key) $part_int select * from t30; +eval create table t32 (a int) $part_int; +drop table if exists t30,t31,t32,tmp_t30; + +--echo # +--echo # Testing create LIKE +--echo # +eval create table t40 (a int) engine=myisam $part_int; +eval create table t41 (a int, b int) engine=innodb $part_int; +create table t42 like t40; +if (!$part_int) { +create temporary table t43_tmp like t40; +} +create or replace table t42 like t41; +show create table t42; +drop table t40, t41, t42; + +--echo # +--echo # Testing rename +--echo # + +eval create table t50 (a int) $part_int; +eval create table t51 (a int, b int) $part_int; +rename table t50 to t52, t51 to t53; +rename table t52 to tmp, t53 to t52, tmp to t53; +drop table t52,t53; + +--echo # +--echo # Testing enable/disable keys +--echo # + +eval CREATE TABLE t60 (a int(10), index(a) ) ENGINE=Aria $part_int; +INSERT INTO t60 VALUES(1),(2),(3); +ALTER TABLE t60 DISABLE KEYS; +INSERT INTO t60 VALUES(4),(5),(6); +ALTER TABLE t60 ENABLE KEYS; +DROP TABLE t60; + +CREATE TEMPORARY TABLE t61 (i int(10), index(i) ) ENGINE=Aria; +INSERT INTO t61 VALUES(1),(2),(3); +ALTER TABLE t61 DISABLE KEYS; +DROP TABLE t61; + +--echo # +--echo # Testing load data +--echo # + +eval create table t70 (a date, b date, c date not null, d date) engine=aria $part_date; +--disable_warnings +load data infile '../../std_data/loaddata1.dat' ignore into table t70 fields terminated by ','; +load data infile '../../std_data/loaddata1.dat' ignore into table t70 fields terminated by ','; +truncate table t70; +lock table t70 write; +load data infile '../../std_data/loaddata1.dat' ignore into table t70 fields terminated by ','; +load data infile '../../std_data/loaddata1.dat' ignore into table t70 fields terminated by ','; +unlock tables; +--enable_warnings + +eval create table t71 (a date, b date, c date not null, d date) engine=aria $part_date; +lock tables t71 write, t70 read; +insert into t71 select * from t70; +unlock tables; +drop table t70,t71; + +--echo # +--echo # Testing strange table names +--echo # + +eval create table `t 1` (a int) $part_int; +drop table `t 1`; + +--echo # +--echo # Testing views and triggers +--echo # + +eval create table t80 (a int, b int) engine=myisam $part_int; +create view v1 as select * from t80; +create trigger trg before insert on t80 for each row set @b:=1; +drop trigger trg; +drop view v1; +drop table t80; + +--echo # +--echo # Testing alter to a new storage engine +--echo # + +eval create table t85 (a int primary key, b int) engine=myisam $part_int; +alter table t85 engine=innodb; +drop table t85; diff --git a/mysql-test/main/backup_log.result b/mysql-test/main/backup_log.result new file mode 100644 index 00000000000..94590a220d4 --- /dev/null +++ b/mysql-test/main/backup_log.result @@ -0,0 +1,241 @@ +CREATE TABLE t_exists (a INT); +CREATE TABLE t_exists_template (a INT); +connect con1,localhost,root,,; +BACKUP STAGE START; +connection default; +# +# Testing with normal tables +# +create table t1 (a int) engine=myisam ; +insert into t1 values (1),(2); +alter table t1 add column b int; +alter table t1 rename as t2; +rename table t2 to t1; +truncate table t1; +repair table t1; +Table Op Msg_type Msg_text +test.t1 repair status OK +optimize table t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +drop table t1; +create table t1_innodb (a int) engine=innodb ; +insert into t1_innodb values (1),(2); +alter table t1_innodb add column b int; +alter table t1_innodb rename as t2_innodb; +rename table t2_innodb to t1_innodb; +truncate table t1_innodb; +repair table t1_innodb; +Table Op Msg_type Msg_text +test.t1_innodb repair note The storage engine for the table doesn't support repair +optimize table t1_innodb; +Table Op Msg_type Msg_text +test.t1_innodb optimize note Table does not support optimize, doing recreate + analyze instead +test.t1_innodb optimize status OK +drop table t1_innodb; +# +# Testing with temporary tables (should not be logged) +# +create temporary table tmp_t10 (a int) engine=myisam; +alter table tmp_t10 add column b int; +alter table tmp_t10 rename as tmp_t11; +rename table tmp_t11 to tmp_t10; +truncate table tmp_t10; +drop table tmp_t10; +# +# Testing with mix of normal and temporary tables +# +create temporary table tmp_t20 (a int); +create table t20 (a int) ; +drop table tmp_t20,t20; +create temporary table tmp_t21 (a int); +create table t21 (a int) ; +drop temporary table if exists tmp_t21,t21; +Warnings: +Note 1051 Unknown table 'test.t21' +drop table if exists tmp_t21,t21; +Warnings: +Note 1051 Unknown table 'test.tmp_t21' +# +# Testing create select +# +create table t30 (a int) ; +insert into t30 values (1),(1); +create table t31 (a int primary key) select * from t30 limit 1; +create or replace table t31 select * from t30 limit 1; +create or replace temporary table t30_dup select * from t30 limit 1; +create or replace table t31 (a int primary key) select * from t30; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +create table t32 (a int) ; +drop table if exists t30,t31,t32,tmp_t30; +Warnings: +Note 1051 Unknown table 'test.t31,test.tmp_t30' +# +# Testing create LIKE +# +create table t40 (a int) engine=myisam ; +create table t41 (a int, b int) engine=innodb ; +create table t42 like t40; +create temporary table t43_tmp like t40; +create or replace table t42 like t41; +show create table t42; +Table Create Table +t42 CREATE TABLE `t42` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +drop table t40, t41, t42; +# +# Testing rename +# +create table t50 (a int) ; +create table t51 (a int, b int) ; +rename table t50 to t52, t51 to t53; +rename table t52 to tmp, t53 to t52, tmp to t53; +drop table t52,t53; +# +# Testing enable/disable keys +# +CREATE TABLE t60 (a int(10), index(a) ) ENGINE=Aria ; +INSERT INTO t60 VALUES(1),(2),(3); +ALTER TABLE t60 DISABLE KEYS; +INSERT INTO t60 VALUES(4),(5),(6); +ALTER TABLE t60 ENABLE KEYS; +DROP TABLE t60; +CREATE TEMPORARY TABLE t61 (i int(10), index(i) ) ENGINE=Aria; +INSERT INTO t61 VALUES(1),(2),(3); +ALTER TABLE t61 DISABLE KEYS; +DROP TABLE t61; +# +# Testing load data +# +create table t70 (a date, b date, c date not null, d date) engine=aria ; +load data infile '../../std_data/loaddata1.dat' ignore into table t70 fields terminated by ','; +load data infile '../../std_data/loaddata1.dat' ignore into table t70 fields terminated by ','; +truncate table t70; +lock table t70 write; +load data infile '../../std_data/loaddata1.dat' ignore into table t70 fields terminated by ','; +load data infile '../../std_data/loaddata1.dat' ignore into table t70 fields terminated by ','; +unlock tables; +create table t71 (a date, b date, c date not null, d date) engine=aria ; +lock tables t71 write, t70 read; +insert into t71 select * from t70; +unlock tables; +drop table t70,t71; +# +# Testing strange table names +# +create table `t 1` (a int) ; +drop table `t 1`; +# +# Testing views and triggers +# +create table t80 (a int, b int) engine=myisam ; +create view v1 as select * from t80; +create trigger trg before insert on t80 for each row set @b:=1; +drop trigger trg; +drop view v1; +drop table t80; +# +# Testing alter to a new storage engine +# +create table t85 (a int primary key, b int) engine=myisam ; +alter table t85 engine=innodb; +drop table t85; +# +# Testing create/drop/alter database +# +create database mysqltest; +create table mysqltest.t90 (a int primary key, b int) engine=myisam; +create table mysqltest.t91 (a int primary key, b int) engine=innodb; +alter database mysqltest character set utf8; +drop database mysqltest; +# +# MENT-222 bug testing +# +CREATE TABLE IF NOT EXISTS t_exists LIKE t_exists_template; +Warnings: +Note 1050 Table 't_exists' already exists +# +# Reading backup ddl log file +# +CREATE,MyISAM,0,test,t1,id: 1,,0,,, +ALTER,MyISAM,0,test,t1,id: 1,MyISAM,0,test,t1,id: 2 +RENAME,MyISAM,0,test,t1,id: 2,MyISAM,0,test,t2,id: 2 +RENAME,MyISAM,0,test,t2,id: 2,MyISAM,0,test,t1,id: 2 +repair,MyISAM,0,test,t1,id: 2,,0,,, +optimize,MyISAM,0,test,t1,id: 2,,0,,, +DROP,MyISAM,0,test,t1,id: 2,,0,,, +CREATE,InnoDB,0,test,t1_innodb,id: 3,,0,,, +ALTER,InnoDB,0,test,t1_innodb,id: 3,InnoDB,0,test,t1_innodb,id: 4 +RENAME,InnoDB,0,test,t1_innodb,id: 4,InnoDB,0,test,t2_innodb,id: 4 +RENAME,InnoDB,0,test,t2_innodb,id: 4,InnoDB,0,test,t1_innodb,id: 4 +TRUNCATE,InnoDB,0,test,t1_innodb,id: 4,,0,,, +repair,InnoDB,0,test,t1_innodb,id: 4,,0,,, +ALTER,InnoDB,0,test,t1_innodb,id: 4,InnoDB,0,test,t1_innodb,id: 5 +DROP,InnoDB,0,test,t1_innodb,id: 5,,0,,, +CREATE,MyISAM,0,test,t20,id: 6,,0,,, +DROP,MyISAM,0,test,t20,id: 6,,0,,, +CREATE,MyISAM,0,test,t21,id: 7,,0,,, +DROP,MyISAM,0,test,t21,id: 7,,0,,, +CREATE,MyISAM,0,test,t30,id: 8,,0,,, +CREATE,MyISAM,0,test,t31,id: 9,,0,,, +DROP,MyISAM,0,test,t31,id: 9,,0,,, +CREATE,MyISAM,0,test,t31,id: 10,,0,,, +DROP,MyISAM,0,test,t31,id: 10,,0,,, +DROP_AFTER_CREATE,MyISAM,0,test,t31,id: 11,,0,,, +CREATE,MyISAM,0,test,t32,id: 12,,0,,, +DROP,MyISAM,0,test,t30,id: 8,,0,,, +DROP,MyISAM,0,test,t32,id: 12,,0,,, +CREATE,MyISAM,0,test,t40,id: 13,,0,,, +CREATE,InnoDB,0,test,t41,id: 14,,0,,, +CREATE,MyISAM,0,test,t42,id: 15,,0,,, +DROP,MyISAM,0,test,t42,id: 15,,0,,, +CREATE,InnoDB,0,test,t42,id: 16,,0,,, +DROP,MyISAM,0,test,t40,id: 13,,0,,, +DROP,InnoDB,0,test,t41,id: 14,,0,,, +DROP,InnoDB,0,test,t42,id: 16,,0,,, +CREATE,MyISAM,0,test,t50,id: 17,,0,,, +CREATE,MyISAM,0,test,t51,id: 18,,0,,, +RENAME,MyISAM,0,test,t50,id: 17,MyISAM,0,test,t52,id: 17 +RENAME,MyISAM,0,test,t51,id: 18,MyISAM,0,test,t53,id: 18 +RENAME,MyISAM,0,test,t52,id: 17,MyISAM,0,test,tmp,id: 17 +RENAME,MyISAM,0,test,t53,id: 18,MyISAM,0,test,t52,id: 18 +RENAME,MyISAM,0,test,tmp,id: 17,MyISAM,0,test,t53,id: 17 +DROP,MyISAM,0,test,t52,id: 18,,0,,, +DROP,MyISAM,0,test,t53,id: 17,,0,,, +CREATE,Aria,0,test,t60,id: 19,,0,,, +CHANGE_INDEX,Aria,0,test,t60,id: 19,,0,,, +CHANGE_INDEX,Aria,0,test,t60,id: 19,,0,,, +DROP,Aria,0,test,t60,id: 19,,0,,, +CREATE,Aria,0,test,t70,id: 20,,0,,, +BULK_INSERT,Aria,0,test,t70,id: 20,,0,,, +BULK_INSERT,Aria,0,test,t70,id: 20,,0,,, +CREATE,Aria,0,test,t71,id: 21,,0,,, +BULK_INSERT,Aria,0,test,t71,id: 21,,0,,, +DROP,Aria,0,test,t70,id: 20,,0,,, +DROP,Aria,0,test,t71,id: 21,,0,,, +CREATE,MyISAM,0,test,t@00201,id: 22,,0,,, +DROP,MyISAM,0,test,t@00201,id: 22,,0,,, +CREATE,MyISAM,0,test,t80,id: 23,,0,,, +CREATE,VIEW,0,test,v1,,,0,,, +CREATE,TRIGGER,0,test,trg,,,0,,, +DROP,TRIGGER,0,test,trg,,,0,,, +DROP,VIEW,0,test,v1,,,0,,, +DROP,MyISAM,0,test,t80,id: 23,,0,,, +CREATE,MyISAM,0,test,t85,id: 24,,0,,, +ALTER,MyISAM,0,test,t85,id: 24,InnoDB,0,test,t85,id: 25 +DROP,InnoDB,0,test,t85,id: 25,,0,,, +CREATE,DATABASE,0,mysqltest,,,,0,,, +CREATE,MyISAM,0,mysqltest,t90,id: 26,,0,,, +CREATE,InnoDB,0,mysqltest,t91,id: 27,,0,,, +ALTER,DATABASE,0,mysqltest,,,,0,,, +DROP,MyISAM,0,mysqltest,t90,id: 26,,0,,, +DROP,InnoDB,0,mysqltest,t91,id: 27,,0,,, +DROP,DATABASE,0,mysqltest,,,,0,,, +# +# Cleanup +# +DROP TABLE t_exists; +DROP TABLE t_exists_template; +disconnect con1; diff --git a/mysql-test/main/backup_log.test b/mysql-test/main/backup_log.test new file mode 100644 index 00000000000..ee34484e92b --- /dev/null +++ b/mysql-test/main/backup_log.test @@ -0,0 +1,39 @@ +# Testing of logging of ddl's under backup stages + +--source include/have_innodb.inc +--source include/not_embedded.inc + +CREATE TABLE t_exists (a INT); +CREATE TABLE t_exists_template (a INT); + +connect (con1,localhost,root,,); +BACKUP STAGE START; +connection default; + +--let $part_int= +--let $part_date= +--source backup_log.inc + +--echo # +--echo # Testing create/drop/alter database +--echo # + +create database mysqltest; +create table mysqltest.t90 (a int primary key, b int) engine=myisam; +create table mysqltest.t91 (a int primary key, b int) engine=innodb; +alter database mysqltest character set utf8; +drop database mysqltest; + +--echo # +--echo # MENT-222 bug testing +--echo # +CREATE TABLE IF NOT EXISTS t_exists LIKE t_exists_template; + +--source include/print_ddl_log.inc + +--echo # +--echo # Cleanup +--echo # +DROP TABLE t_exists; +DROP TABLE t_exists_template; +disconnect con1; diff --git a/mysql-test/main/backup_stages.result b/mysql-test/main/backup_stages.result index 4704a4b6bd1..823e5d7e462 100644 --- a/mysql-test/main/backup_stages.result +++ b/mysql-test/main/backup_stages.result @@ -17,12 +17,12 @@ FROM information_schema.processlist WHERE id = @con1_id; ID USER COMMAND STATE INFO STAGE MAX_STAGE INFO_BINARY <con1_id> root Query Waiting for backup lock BACKUP STAGE START 0 0 BACKUP STAGE START BACKUP STAGE END; -SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info; -LOCK_MODE LOCK_TYPE TABLE_SCHEMA TABLE_NAME -MDL_BACKUP_START Backup lock connection con1; # The connection default has removed the backup lock. # And so the current connection con1 can reap for its BACKUP STAGE START +SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info; +LOCK_MODE LOCK_TYPE TABLE_SCHEMA TABLE_NAME +MDL_BACKUP_START Backup lock connect con2,localhost,root,,; # The connection con2 cannot continue the work of con1 by setting the # next BACKUP STAGE FLUSH. diff --git a/mysql-test/main/backup_stages.test b/mysql-test/main/backup_stages.test index e8cc5f7a7b9..77d410b6caf 100644 --- a/mysql-test/main/backup_stages.test +++ b/mysql-test/main/backup_stages.test @@ -50,13 +50,14 @@ FROM information_schema.processlist WHERE id = @con1_id; # con1 uses @@global.lock_wait_timeout BACKUP STAGE END; -SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info; --connection con1 --echo # The connection default has removed the backup lock. --echo # And so the current connection con1 can reap for its BACKUP STAGE START --reap +SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info; + # con2, root high privileged user --connect(con2,localhost,root,,) let $con2_id= `SELECT CONNECTION_ID()`; diff --git a/mysql-test/suite/parts/r/backup_log.result b/mysql-test/suite/parts/r/backup_log.result new file mode 100644 index 00000000000..3a220491027 --- /dev/null +++ b/mysql-test/suite/parts/r/backup_log.result @@ -0,0 +1,278 @@ +connect con1,localhost,root,,; +BACKUP STAGE START; +connection default; +# +# Testing with normal tables +# +create table t1 (a int) engine=myisam PARTITION BY HASH(a) PARTITIONS 2; +insert into t1 values (1),(2); +alter table t1 add column b int; +alter table t1 rename as t2; +rename table t2 to t1; +truncate table t1; +repair table t1; +Table Op Msg_type Msg_text +test.t1 repair status OK +optimize table t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +drop table t1; +create table t1_innodb (a int) engine=innodb PARTITION BY HASH(a) PARTITIONS 2; +insert into t1_innodb values (1),(2); +alter table t1_innodb add column b int; +alter table t1_innodb rename as t2_innodb; +rename table t2_innodb to t1_innodb; +truncate table t1_innodb; +repair table t1_innodb; +Table Op Msg_type Msg_text +test.t1_innodb repair status OK +optimize table t1_innodb; +Table Op Msg_type Msg_text +test.t1_innodb optimize note Table does not support optimize, doing recreate + analyze instead +test.t1_innodb optimize status OK +drop table t1_innodb; +# +# Testing with temporary tables (should not be logged) +# +create temporary table tmp_t10 (a int) engine=myisam; +alter table tmp_t10 add column b int; +alter table tmp_t10 rename as tmp_t11; +rename table tmp_t11 to tmp_t10; +truncate table tmp_t10; +drop table tmp_t10; +# +# Testing with mix of normal and temporary tables +# +create temporary table tmp_t20 (a int); +create table t20 (a int) PARTITION BY HASH(a) PARTITIONS 2; +drop table tmp_t20,t20; +create temporary table tmp_t21 (a int); +create table t21 (a int) PARTITION BY HASH(a) PARTITIONS 2; +drop temporary table if exists tmp_t21,t21; +Warnings: +Note 1051 Unknown table 'test.t21' +drop table if exists tmp_t21,t21; +Warnings: +Note 1051 Unknown table 'test.tmp_t21' +# +# Testing create select +# +create table t30 (a int) PARTITION BY HASH(a) PARTITIONS 2; +insert into t30 values (1),(1); +create table t31 (a int primary key) PARTITION BY HASH(a) PARTITIONS 2 select * from t30 limit 1; +create or replace table t31 select * from t30 limit 1; +create or replace temporary table t30_dup select * from t30 limit 1; +create or replace table t31 (a int primary key) PARTITION BY HASH(a) PARTITIONS 2 select * from t30; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +create table t32 (a int) PARTITION BY HASH(a) PARTITIONS 2; +drop table if exists t30,t31,t32,tmp_t30; +Warnings: +Note 1051 Unknown table 'test.t31,test.tmp_t30' +# +# Testing create LIKE +# +create table t40 (a int) engine=myisam PARTITION BY HASH(a) PARTITIONS 2; +create table t41 (a int, b int) engine=innodb PARTITION BY HASH(a) PARTITIONS 2; +create table t42 like t40; +create or replace table t42 like t41; +show create table t42; +Table Create Table +t42 CREATE TABLE `t42` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 + PARTITION BY HASH (`a`) +PARTITIONS 2 +drop table t40, t41, t42; +# +# Testing rename +# +create table t50 (a int) PARTITION BY HASH(a) PARTITIONS 2; +create table t51 (a int, b int) PARTITION BY HASH(a) PARTITIONS 2; +rename table t50 to t52, t51 to t53; +rename table t52 to tmp, t53 to t52, tmp to t53; +drop table t52,t53; +# +# Testing enable/disable keys +# +CREATE TABLE t60 (a int(10), index(a) ) ENGINE=Aria PARTITION BY HASH(a) PARTITIONS 2; +INSERT INTO t60 VALUES(1),(2),(3); +ALTER TABLE t60 DISABLE KEYS; +INSERT INTO t60 VALUES(4),(5),(6); +ALTER TABLE t60 ENABLE KEYS; +DROP TABLE t60; +CREATE TEMPORARY TABLE t61 (i int(10), index(i) ) ENGINE=Aria; +INSERT INTO t61 VALUES(1),(2),(3); +ALTER TABLE t61 DISABLE KEYS; +DROP TABLE t61; +# +# Testing load data +# +create table t70 (a date, b date, c date not null, d date) engine=aria PARTITION BY HASH(YEAR(a)) PARTITIONS 2; +load data infile '../../std_data/loaddata1.dat' ignore into table t70 fields terminated by ','; +load data infile '../../std_data/loaddata1.dat' ignore into table t70 fields terminated by ','; +truncate table t70; +lock table t70 write; +load data infile '../../std_data/loaddata1.dat' ignore into table t70 fields terminated by ','; +load data infile '../../std_data/loaddata1.dat' ignore into table t70 fields terminated by ','; +unlock tables; +create table t71 (a date, b date, c date not null, d date) engine=aria PARTITION BY HASH(YEAR(a)) PARTITIONS 2; +lock tables t71 write, t70 read; +insert into t71 select * from t70; +unlock tables; +drop table t70,t71; +# +# Testing strange table names +# +create table `t 1` (a int) PARTITION BY HASH(a) PARTITIONS 2; +drop table `t 1`; +# +# Testing views and triggers +# +create table t80 (a int, b int) engine=myisam PARTITION BY HASH(a) PARTITIONS 2; +create view v1 as select * from t80; +create trigger trg before insert on t80 for each row set @b:=1; +drop trigger trg; +drop view v1; +drop table t80; +# +# Testing alter to a new storage engine +# +create table t85 (a int primary key, b int) engine=myisam PARTITION BY HASH(a) PARTITIONS 2; +alter table t85 engine=innodb; +drop table t85; +# +# Testing backup ddl log for partitioned tables +# +CREATE TABLE t200(a INT, b INT) ENGINE ARIA TRANSACTIONAL = 1 PAGE_CHECKSUM = 1; +INSERT INTO t200 VALUES (5, 5), (15, 15), (25, 25); +ALTER TABLE t200 PARTITION BY RANGE( a ) ( +PARTITION p0 VALUES LESS THAN (10), +PARTITION p1 VALUES LESS THAN (20), +PARTITION p2 VALUES LESS THAN (30) +); +CREATE TABLE t210(a INT, b INT) ENGINE ARIA TRANSACTIONAL = 1 PAGE_CHECKSUM = 1; +#TODO: echange partitions have not logged yet +ALTER TABLE t200 EXCHANGE PARTITION p2 WITH TABLE t210; +ALTER TABLE t200 DROP PARTITION p0; +ALTER TABLE t200 ADD PARTITION (PARTITION p3 VALUES LESS THAN (40)); +ALTER TABLE t200 +REORGANIZE PARTITION p3 INTO ( +PARTITION n0 VALUES LESS THAN (35), +PARTITION n1 VALUES LESS THAN (45) +); +ALTER TABLE t200 PARTITION BY KEY(a) PARTITIONS 2; +ALTER TABLE t200 PARTITION BY HASH(a) PARTITIONS 8; +ALTER TABLE t200 COALESCE PARTITION 4; +ALTER TABLE t200 +PARTITION BY RANGE (b) +SUBPARTITION BY KEY (a) +SUBPARTITIONS 2 ( +PARTITION p0 VALUES LESS THAN (10), +PARTITION p1 VALUES LESS THAN (20), +PARTITION p2 VALUES LESS THAN (30), +PARTITION p3 VALUES LESS THAN (MAXVALUE) +); +ALTER TABLE t200 REMOVE PARTITIONING; +DROP TABLE t200, t210; +# Test for the case when TDC contains TABLE_SHARE object for the +# certain table, but the table is not opened +CREATE TABLE t220(a INT) ENGINE ARIA PARTITION BY HASH(a) PARTITIONS 2; +SELECT VERSION FROM INFORMATION_SCHEMA.tables WHERE +TABLE_SCHEMA = 'test' AND TABLE_NAME = 't220'; +DROP TABLE t220; +# +# Reading backup ddl log file +# +CREATE,MyISAM,1,test,t1,id: 1,,0,,, +ALTER,MyISAM,1,test,t1,id: 1,MyISAM,1,test,t1,id: 2 +RENAME,MyISAM,1,test,t1,id: 2,MyISAM,1,test,t2,id: 2 +RENAME,MyISAM,1,test,t2,id: 2,MyISAM,1,test,t1,id: 2 +TRUNCATE,MyISAM,1,test,t1,id: 2,,0,,, +repair,MyISAM,1,test,t1,id: 2,,0,,, +optimize,MyISAM,1,test,t1,id: 2,,0,,, +DROP,MyISAM,1,test,t1,id: 2,,0,,, +CREATE,InnoDB,1,test,t1_innodb,id: 3,,0,,, +ALTER,InnoDB,1,test,t1_innodb,id: 3,InnoDB,1,test,t1_innodb,id: 4 +RENAME,InnoDB,1,test,t1_innodb,id: 4,InnoDB,1,test,t2_innodb,id: 4 +RENAME,InnoDB,1,test,t2_innodb,id: 4,InnoDB,1,test,t1_innodb,id: 4 +TRUNCATE,InnoDB,1,test,t1_innodb,id: 4,,0,,, +repair,InnoDB,1,test,t1_innodb,id: 4,,0,,, +ALTER,InnoDB,1,test,t1_innodb,id: 4,InnoDB,1,test,t1_innodb,id: 5 +DROP,InnoDB,1,test,t1_innodb,id: 5,,0,,, +CREATE,MyISAM,1,test,t20,id: 6,,0,,, +DROP,MyISAM,1,test,t20,id: 6,,0,,, +CREATE,MyISAM,1,test,t21,id: 7,,0,,, +DROP,MyISAM,1,test,t21,id: 7,,0,,, +CREATE,MyISAM,1,test,t30,id: 8,,0,,, +CREATE,MyISAM,1,test,t31,id: 9,,0,,, +DROP,MyISAM,1,test,t31,id: 9,,0,,, +CREATE,MyISAM,0,test,t31,id: 10,,0,,, +DROP,MyISAM,0,test,t31,id: 10,,0,,, +DROP_AFTER_CREATE,MyISAM,1,test,t31,id: 11,,0,,, +CREATE,MyISAM,1,test,t32,id: 12,,0,,, +DROP,MyISAM,1,test,t30,id: 8,,0,,, +DROP,MyISAM,1,test,t32,id: 12,,0,,, +CREATE,MyISAM,1,test,t40,id: 13,,0,,, +CREATE,InnoDB,1,test,t41,id: 14,,0,,, +CREATE,partition,0,test,t42,id: 15,,0,,, +DROP,MyISAM,1,test,t42,id: 15,,0,,, +CREATE,partition,0,test,t42,id: 16,,0,,, +DROP,MyISAM,1,test,t40,id: 13,,0,,, +DROP,InnoDB,1,test,t41,id: 14,,0,,, +DROP,InnoDB,1,test,t42,id: 16,,0,,, +CREATE,MyISAM,1,test,t50,id: 17,,0,,, +CREATE,MyISAM,1,test,t51,id: 18,,0,,, +RENAME,MyISAM,1,test,t50,id: 17,MyISAM,1,test,t52,id: 17 +RENAME,MyISAM,1,test,t51,id: 18,MyISAM,1,test,t53,id: 18 +RENAME,MyISAM,1,test,t52,id: 17,MyISAM,1,test,tmp,id: 17 +RENAME,MyISAM,1,test,t53,id: 18,MyISAM,1,test,t52,id: 18 +RENAME,MyISAM,1,test,tmp,id: 17,MyISAM,1,test,t53,id: 17 +DROP,MyISAM,1,test,t52,id: 18,,0,,, +DROP,MyISAM,1,test,t53,id: 17,,0,,, +CREATE,Aria,1,test,t60,id: 19,,0,,, +CHANGE_INDEX,Aria,1,test,t60,id: 19,,0,,, +CHANGE_INDEX,Aria,1,test,t60,id: 19,,0,,, +DROP,Aria,1,test,t60,id: 19,,0,,, +CREATE,Aria,1,test,t70,id: 20,,0,,, +BULK_INSERT,Aria,1,test,t70,id: 20,,0,,, +BULK_INSERT,Aria,1,test,t70,id: 20,,0,,, +TRUNCATE,Aria,1,test,t70,id: 20,,0,,, +BULK_INSERT,Aria,1,test,t70,id: 20,,0,,, +BULK_INSERT,Aria,1,test,t70,id: 20,,0,,, +CREATE,Aria,1,test,t71,id: 21,,0,,, +BULK_INSERT,Aria,1,test,t71,id: 21,,0,,, +BULK_INSERT,Aria,1,test,t71,id: 21,,0,,, +DROP,Aria,1,test,t70,id: 20,,0,,, +DROP,Aria,1,test,t71,id: 21,,0,,, +CREATE,MyISAM,1,test,t@00201,id: 22,,0,,, +DROP,MyISAM,1,test,t@00201,id: 22,,0,,, +CREATE,MyISAM,1,test,t80,id: 23,,0,,, +CREATE,VIEW,0,test,v1,,,0,,, +CREATE,TRIGGER,0,test,trg,,,0,,, +DROP,TRIGGER,0,test,trg,,,0,,, +DROP,VIEW,0,test,v1,,,0,,, +DROP,MyISAM,1,test,t80,id: 23,,0,,, +CREATE,MyISAM,1,test,t85,id: 24,,0,,, +ALTER,MyISAM,1,test,t85,id: 24,InnoDB,1,test,t85,id: 25 +DROP,InnoDB,1,test,t85,id: 25,,0,,, +CREATE,Aria,0,test,t200,id: 26,,0,,, +ALTER,Aria,0,test,t200,id: 26,Aria,1,test,t200,id: 27 +CREATE,Aria,0,test,t210,id: 28,,0,,, +EXCHANGE_PARTITION,Aria,1,test,t200,id: 27,Aria,0,test,t210,id: 28 +ALTER,Aria,1,test,t200,id: 27,Aria,1,test,t200,id: 29 +ALTER,Aria,1,test,t200,id: 29,Aria,1,test,t200,id: 30 +ALTER,Aria,1,test,t200,id: 30,Aria,1,test,t200,id: 31 +ALTER,Aria,1,test,t200,id: 31,Aria,1,test,t200,id: 32 +ALTER,Aria,1,test,t200,id: 32,Aria,1,test,t200,id: 33 +ALTER,Aria,1,test,t200,id: 33,Aria,1,test,t200,id: 34 +ALTER,Aria,1,test,t200,id: 34,Aria,1,test,t200,id: 35 +ALTER,Aria,1,test,t200,id: 35,Aria,0,test,t200,id: 36 +DROP,Aria,0,test,t200,id: 36,,0,,, +DROP,Aria,0,test,t210,id: 28,,0,,, +CREATE,Aria,1,test,t220,id: 37,,0,,, +DROP,Aria,1,test,t220,id: 37,,0,,, +# +# Cleanup +# +disconnect con1; diff --git a/mysql-test/suite/parts/r/backup_log_rocksdb.result b/mysql-test/suite/parts/r/backup_log_rocksdb.result new file mode 100644 index 00000000000..3fd0adfe8b3 --- /dev/null +++ b/mysql-test/suite/parts/r/backup_log_rocksdb.result @@ -0,0 +1,15 @@ +connect con1,localhost,root,,; +BACKUP STAGE START; +connection default; +# Test partition engine read from .frm +CREATE TABLE t220 (a INT) ENGINE ROCKSDB PARTITION BY KEY(a) PARTITIONS 2; +DROP TABLE t220; +# +# Reading backup ddl log file +# +CREATE,ROCKSDB,1,test,t220,id: 1,,0,,, +DROP,ROCKSDB,1,test,t220,id: 1,,0,,, +# +# Cleanup +# +disconnect con1; diff --git a/mysql-test/suite/parts/t/backup_log.test b/mysql-test/suite/parts/t/backup_log.test new file mode 100644 index 00000000000..50e3cadd192 --- /dev/null +++ b/mysql-test/suite/parts/t/backup_log.test @@ -0,0 +1,63 @@ +--source include/have_partition.inc +--source include/have_innodb.inc +--source include/not_embedded.inc + +connect (con1,localhost,root,,); +BACKUP STAGE START; +connection default; + +--let $part_int=PARTITION BY HASH(a) PARTITIONS 2 +--let $part_date=PARTITION BY HASH(YEAR(a)) PARTITIONS 2 +--source main/backup_log.inc + +--echo # +--echo # Testing backup ddl log for partitioned tables +--echo # + +CREATE TABLE t200(a INT, b INT) ENGINE ARIA TRANSACTIONAL = 1 PAGE_CHECKSUM = 1; +INSERT INTO t200 VALUES (5, 5), (15, 15), (25, 25); +ALTER TABLE t200 PARTITION BY RANGE( a ) ( + PARTITION p0 VALUES LESS THAN (10), + PARTITION p1 VALUES LESS THAN (20), + PARTITION p2 VALUES LESS THAN (30) +); +CREATE TABLE t210(a INT, b INT) ENGINE ARIA TRANSACTIONAL = 1 PAGE_CHECKSUM = 1; +--echo #TODO: echange partitions have not logged yet +ALTER TABLE t200 EXCHANGE PARTITION p2 WITH TABLE t210; +ALTER TABLE t200 DROP PARTITION p0; +ALTER TABLE t200 ADD PARTITION (PARTITION p3 VALUES LESS THAN (40)); +ALTER TABLE t200 + REORGANIZE PARTITION p3 INTO ( + PARTITION n0 VALUES LESS THAN (35), + PARTITION n1 VALUES LESS THAN (45) +); +ALTER TABLE t200 PARTITION BY KEY(a) PARTITIONS 2; +ALTER TABLE t200 PARTITION BY HASH(a) PARTITIONS 8; +ALTER TABLE t200 COALESCE PARTITION 4; +ALTER TABLE t200 + PARTITION BY RANGE (b) + SUBPARTITION BY KEY (a) + SUBPARTITIONS 2 ( + PARTITION p0 VALUES LESS THAN (10), + PARTITION p1 VALUES LESS THAN (20), + PARTITION p2 VALUES LESS THAN (30), + PARTITION p3 VALUES LESS THAN (MAXVALUE) + ); +ALTER TABLE t200 REMOVE PARTITIONING; +DROP TABLE t200, t210; + +--echo # Test for the case when TDC contains TABLE_SHARE object for the +--echo # certain table, but the table is not opened +CREATE TABLE t220(a INT) ENGINE ARIA PARTITION BY HASH(a) PARTITIONS 2; +--disable_result_log +SELECT VERSION FROM INFORMATION_SCHEMA.tables WHERE + TABLE_SCHEMA = 'test' AND TABLE_NAME = 't220'; +--enable_result_log +DROP TABLE t220; + +--source include/print_ddl_log.inc + +--echo # +--echo # Cleanup +--echo # +disconnect con1; diff --git a/mysql-test/suite/parts/t/backup_log_rocksdb.opt b/mysql-test/suite/parts/t/backup_log_rocksdb.opt new file mode 100644 index 00000000000..df675545bf9 --- /dev/null +++ b/mysql-test/suite/parts/t/backup_log_rocksdb.opt @@ -0,0 +1 @@ +--plugin-load=$HA_ROCKSDB_SO diff --git a/mysql-test/suite/parts/t/backup_log_rocksdb.test b/mysql-test/suite/parts/t/backup_log_rocksdb.test new file mode 100644 index 00000000000..c260d26acc1 --- /dev/null +++ b/mysql-test/suite/parts/t/backup_log_rocksdb.test @@ -0,0 +1,24 @@ +--source include/have_partition.inc +--source suite/mariabackup/include/have_rocksdb.inc +--source include/not_embedded.inc + +# +# Test that dynmaic loaded storage engines also works with partition and logging +# This is will access code in dd_frm_type() that is not acccessed by other tests +# + +connect (con1,localhost,root,,); +BACKUP STAGE START; +connection default; + +--echo # Test partition engine read from .frm +CREATE TABLE t220 (a INT) ENGINE ROCKSDB PARTITION BY KEY(a) PARTITIONS 2; +DROP TABLE t220; + +--source include/print_ddl_log.inc + +--echo # +--echo # Cleanup +--echo # + +disconnect con1; diff --git a/sql/backup.cc b/sql/backup.cc index e89f9a108a7..1b3007c5a00 100644 --- a/sql/backup.cc +++ b/sql/backup.cc @@ -34,6 +34,7 @@ #include "sql_insert.h" // kill_delayed_threads #include "sql_handler.h" // mysql_ha_cleanup_no_free #include <my_sys.h> +#include <strfunc.h> // strconvert() static const char *stage_names[]= {"START", "FLUSH", "BLOCK_DDL", "BLOCK_COMMIT", "END", 0}; @@ -42,11 +43,15 @@ TYPELIB backup_stage_names= { array_elements(stage_names)-1, "", stage_names, 0 }; static MDL_ticket *backup_flush_ticket; +static File volatile backup_log= -1; +static int backup_log_error= 0; static bool backup_start(THD *thd); static bool backup_flush(THD *thd); static bool backup_block_ddl(THD *thd); static bool backup_block_commit(THD *thd); +static bool start_ddl_logging(); +static void stop_ddl_logging(); /** Run next stage of backup @@ -55,6 +60,8 @@ static bool backup_block_commit(THD *thd); void backup_init() { backup_flush_ticket= 0; + backup_log= -1; + backup_log_error= 0; } bool run_backup_stage(THD *thd, backup_stages stage) @@ -152,7 +159,6 @@ static bool backup_start(THD *thd) thd->current_backup_stage= BACKUP_FINISHED; // For next test if (thd->has_read_only_protection()) DBUG_RETURN(1); - thd->current_backup_stage= BACKUP_START; if (thd->locked_tables_mode) { @@ -160,14 +166,31 @@ static bool backup_start(THD *thd) DBUG_RETURN(1); } - MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_START, + /* this will be reset if this stage fails */ + thd->current_backup_stage= BACKUP_START; + + /* + Wait for old backup to finish and block ddl's so that we can start the + ddl logger + */ + MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_BLOCK_DDL, MDL_EXPLICIT); if (thd->mdl_context.acquire_lock(&mdl_request, thd->variables.lock_wait_timeout)) DBUG_RETURN(1); + if (start_ddl_logging()) + { + thd->mdl_context.release_lock(mdl_request.ticket); + DBUG_RETURN(1); + } + + DBUG_ASSERT(backup_flush_ticket == 0); backup_flush_ticket= mdl_request.ticket; + /* Downgrade lock to only block other backups */ + backup_flush_ticket->downgrade_lock(MDL_BACKUP_START); + ha_prepare_for_backup(); DBUG_RETURN(0); } @@ -216,7 +239,8 @@ static bool backup_flush(THD *thd) - Kill all insert delay handlers, to ensure that all non transactional tables are closed (can be improved in the future). - - Close handlers as other threads may wait for these, which can cause deadlocks. + - Close handlers as other threads may wait for these, which can cause + deadlocks. - Wait for all statements using write locked non-transactional tables to end. @@ -271,9 +295,13 @@ static bool backup_block_ddl(THD *thd) backup_flush_ticket->downgrade_lock(MDL_BACKUP_FLUSH); DBUG_RETURN(1); } + + /* There can't be anything more that needs to be logged to ddl log */ + stop_ddl_logging(); DBUG_RETURN(0); } + /** backup_block_commit() @@ -303,6 +331,7 @@ static bool backup_block_commit(THD *thd) DBUG_RETURN(0); } + /** backup_end() @@ -316,9 +345,14 @@ bool backup_end(THD *thd) if (thd->current_backup_stage != BACKUP_FINISHED) { + DBUG_ASSERT(backup_flush_ticket); + MDL_ticket *old_ticket= backup_flush_ticket; ha_end_backup(); + // This is needed as we may call backup_end without backup_block_commit + stop_ddl_logging(); + backup_flush_ticket= 0; thd->current_backup_stage= BACKUP_FINISHED; - thd->mdl_context.release_lock(backup_flush_ticket); + thd->mdl_context.release_lock(old_ticket); } DBUG_RETURN(0); } @@ -370,7 +404,7 @@ bool backup_reset_alter_copy_lock(THD *thd) /***************************************************************************** - Backup locks + Interfaces for BACKUP LOCK These functions are used by maria_backup to ensure that there are no active ddl's on the object the backup is going to copy *****************************************************************************/ @@ -402,3 +436,135 @@ void backup_unlock(THD *thd) thd->mdl_context.release_lock(thd->mdl_backup_lock); thd->mdl_backup_lock= 0; } + + +/***************************************************************************** + Logging of ddl statements to backup log +*****************************************************************************/ + +static bool start_ddl_logging() +{ + char name[FN_REFLEN]; + DBUG_ENTER("start_ddl_logging"); + + fn_format(name, "ddl", mysql_data_home, ".log", 0); + + backup_log_error= 0; + backup_log= mysql_file_create(key_file_log_ddl, name, CREATE_MODE, + O_TRUNC | O_WRONLY | O_APPEND | O_NOFOLLOW, + MYF(MY_WME)); + DBUG_RETURN(backup_log < 0); +} + +static void stop_ddl_logging() +{ + mysql_mutex_lock(&LOCK_backup_log); + if (backup_log >= 0) + { + mysql_file_close(backup_log, MYF(MY_WME)); + backup_log= -1; + } + backup_log_error= 0; + mysql_mutex_unlock(&LOCK_backup_log); +} + + +static inline char *add_str_to_buffer(char *ptr, const LEX_CSTRING *from) +{ + if (from->length) // If length == 0, str may be 0 + memcpy(ptr, from->str, from->length); + ptr[from->length]= '\t'; + return ptr+ from->length + 1; +} + +static char *add_name_to_buffer(char *ptr, const LEX_CSTRING *from) +{ + LEX_CSTRING tmp; + char buff[NAME_LEN*4]; + uint errors; + + tmp.str= buff; + tmp.length= strconvert(system_charset_info, from->str, from->length, + &my_charset_filename, buff, sizeof(buff), &errors); + return add_str_to_buffer(ptr, &tmp); +} + + +static char *add_id_to_buffer(char *ptr, const LEX_CUSTRING *from) +{ + LEX_CSTRING tmp; + char buff[MY_UUID_STRING_LENGTH]; + + if (!from->length) + return add_str_to_buffer(ptr, (LEX_CSTRING*) from); + + tmp.str= buff; + tmp.length= MY_UUID_STRING_LENGTH; + my_uuid2str(from->str, buff); + return add_str_to_buffer(ptr, &tmp); +} + + +static char *add_bool_to_buffer(char *ptr, bool value) { + *(ptr++) = value ? '1' : '0'; + *(ptr++) = '\t'; + return ptr; +} + +/* + Write to backup log + + Sets backup_log_error in case of error. The backup thread could check this + to ensure that all logging had succeded +*/ + +void backup_log_ddl(const backup_log_info *info) +{ + if (backup_log >= 0 && backup_log_error == 0) + { + mysql_mutex_lock(&LOCK_backup_log); + if (backup_log < 0) + { + mysql_mutex_unlock(&LOCK_backup_log); + return; + } + /* Enough place for db.table *2 + query + engine_name * 2 + tabs+ uuids */ + char buff[NAME_CHAR_LEN*4+20+40*2+10+MY_UUID_STRING_LENGTH*2], *ptr= buff; + char timebuff[20]; + struct tm current_time; + LEX_CSTRING tmp_lex; + time_t tmp_time= my_time(0); + + localtime_r(&tmp_time, ¤t_time); + tmp_lex.str= timebuff; + tmp_lex.length= snprintf(timebuff, sizeof(timebuff), + "%4d-%02d-%02d %2d:%02d:%02d", + current_time.tm_year + 1900, + current_time.tm_mon+1, + current_time.tm_mday, + current_time.tm_hour, + current_time.tm_min, + current_time.tm_sec); + ptr= add_str_to_buffer(ptr, &tmp_lex); + + ptr= add_str_to_buffer(ptr, &info->query); + ptr= add_str_to_buffer(ptr, &info->org_storage_engine_name); + ptr= add_bool_to_buffer(ptr, info->org_partitioned); + ptr= add_name_to_buffer(ptr, &info->org_database); + ptr= add_name_to_buffer(ptr, &info->org_table); + ptr= add_id_to_buffer(ptr, &info->org_table_id); + + /* The following fields are only set in case of rename */ + ptr= add_str_to_buffer(ptr, &info->new_storage_engine_name); + ptr= add_bool_to_buffer(ptr, info->new_partitioned); + ptr= add_name_to_buffer(ptr, &info->new_database); + ptr= add_name_to_buffer(ptr, &info->new_table); + ptr= add_id_to_buffer(ptr, &info->new_table_id); + + ptr[-1]= '\n'; // Replace last tab with nl + if (mysql_file_write(backup_log, (uchar*) buff, (size_t) (ptr-buff), + MYF(MY_FNABP))) + backup_log_error= my_errno; + mysql_mutex_unlock(&LOCK_backup_log); + } +} diff --git a/sql/backup.h b/sql/backup.h index 8d8a28b6082..2e5c3a58ba2 100644 --- a/sql/backup.h +++ b/sql/backup.h @@ -23,6 +23,18 @@ enum backup_stages extern TYPELIB backup_stage_names; +struct backup_log_info { + LEX_CSTRING query; + LEX_CUSTRING org_table_id; /* Unique id from frm */ + LEX_CSTRING org_database, org_table; + LEX_CSTRING org_storage_engine_name; + LEX_CSTRING new_database, new_table; + LEX_CSTRING new_storage_engine_name; + LEX_CUSTRING new_table_id; /* Unique id from frm */ + bool org_partitioned; + bool new_partitioned; +}; + void backup_init(); bool run_backup_stage(THD *thd, backup_stages stage); bool backup_end(THD *thd); @@ -31,4 +43,5 @@ bool backup_reset_alter_copy_lock(THD *thd); bool backup_lock(THD *thd, TABLE_LIST *table); void backup_unlock(THD *thd); +void backup_log_ddl(const backup_log_info *info); #endif /* BACKUP_INCLUDED */ diff --git a/sql/datadict.cc b/sql/datadict.cc index 1321bf9a3a7..716b4dc3025 100644 --- a/sql/datadict.cc +++ b/sql/datadict.cc @@ -55,10 +55,12 @@ static int read_string(File file, uchar**to, size_t length) @retval TABLE_TYPE_VIEW view */ -Table_type dd_frm_type(THD *thd, char *path, LEX_CSTRING *engine_name) +Table_type dd_frm_type(THD *thd, char *path, LEX_CSTRING *engine_name, + LEX_CSTRING *partition_engine_name, + LEX_CUSTRING *table_version) { File file; - uchar header[40]; //"TYPE=VIEW\n" it is 10 characters + uchar header[64+ MY_UUID_SIZE + 2]; // Header and uuid size_t error; Table_type type= TABLE_TYPE_UNKNOWN; uchar dbt; @@ -83,8 +85,18 @@ Table_type dd_frm_type(THD *thd, char *path, LEX_CSTRING *engine_name) engine_name->length= 0; ((char*) (engine_name->str))[0]= 0; } - - if (unlikely((error= mysql_file_read(file, (uchar*) header, sizeof(header), MYF(MY_NABP))))) + if (partition_engine_name) + { + partition_engine_name->length= 0; + partition_engine_name->str= 0; + } + if (table_version) + { + table_version->length= 0; + table_version->str= 0; // Allocated if needed + } + if (unlikely((error= mysql_file_read(file, (uchar*) header, sizeof(header), + MYF(MY_NABP))))) goto err; if (unlikely((!strncmp((char*) header, "TYPE=VIEW\n", 10)))) @@ -108,20 +120,41 @@ Table_type dd_frm_type(THD *thd, char *path, LEX_CSTRING *engine_name) type= TABLE_TYPE_SEQUENCE; } + if (table_version) + { + /* Read the table version (if it is a 'new' frm file) */ + if (header[64] == EXTRA2_TABLEDEF_VERSION && header[65] == MY_UUID_SIZE) + if ((table_version->str= (uchar*) thd->memdup(header + 66, MY_UUID_SIZE))) + table_version->length= MY_UUID_SIZE; + } + /* cannot use ha_resolve_by_legacy_type without a THD */ if (thd && dbt < DB_TYPE_FIRST_DYNAMIC) { - handlerton *ht= ha_resolve_by_legacy_type(thd, (enum legacy_db_type)dbt); + handlerton *ht= ha_resolve_by_legacy_type(thd, (legacy_db_type) dbt); if (ht) { *engine_name= hton2plugin[ht->slot]->name; +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (partition_engine_name && dbt == DB_TYPE_PARTITION_DB) + { + handlerton *p_ht; + legacy_db_type new_dbt= (legacy_db_type) header[61]; + if (new_dbt >= DB_TYPE_FIRST_DYNAMIC) + goto cont; + if (!(p_ht= ha_resolve_by_legacy_type(thd, new_dbt))) + goto err; + *partition_engine_name= *hton_name(p_ht); + } +#endif // WITH_PARTITION_STORAGE_ENGINE goto err; } } +cont: /* read the true engine name */ { - MY_STAT state; + MY_STAT state; uchar *frm_image= 0; uint n_length; @@ -134,7 +167,8 @@ Table_type dd_frm_type(THD *thd, char *path, LEX_CSTRING *engine_name) if (read_string(file, &frm_image, (size_t)state.st_size)) goto err; - if ((n_length= uint4korr(frm_image+55))) + /* The test for !engine_name->length is only true for partition engine */ + if (!engine_name->length && (n_length= uint4korr(frm_image+55))) { uint record_offset= uint2korr(frm_image+6)+ ((uint2korr(frm_image+14) == 0xffff ? @@ -160,6 +194,43 @@ Table_type dd_frm_type(THD *thd, char *path, LEX_CSTRING *engine_name) } } +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (partition_engine_name && dbt == DB_TYPE_PARTITION_DB) + { + uint len; + const uchar *extra2; + /* Length of the MariaDB extra2 segment in the form file. */ + len = uint2korr(frm_image+4); + extra2= frm_image + 64; + if (*extra2 != '/') // old frm had '/' there + { + const uchar *e2end= extra2 + len; + while (extra2 + 3 <= e2end) + { + uchar type= *extra2++; + size_t length= *extra2++; + if (!length) + { + if (extra2 + 2 >= e2end) + break; + length= uint2korr(extra2); + extra2+= 2; + if (length < 256) + break; + } + if (extra2 + length > e2end) + break; + if (type == EXTRA2_DEFAULT_PART_ENGINE) + { + partition_engine_name->str= thd->strmake((char*)extra2, length); + partition_engine_name->length= length; + break; + } + extra2+= length; + } + } + } +#endif // WITH_PARTITION_STORAGE_ENGINE my_free(frm_image); } diff --git a/sql/datadict.h b/sql/datadict.h index f4af592247a..bec093aa141 100644 --- a/sql/datadict.h +++ b/sql/datadict.h @@ -38,11 +38,13 @@ enum Table_type To check whether it's an frm of a view, use dd_frm_is_view(). */ -enum Table_type dd_frm_type(THD *thd, char *path, LEX_CSTRING *engine_name); +enum Table_type dd_frm_type(THD *thd, char *path, LEX_CSTRING *engine_name, + LEX_CSTRING *partition_engine_name, + LEX_CUSTRING *table_version); static inline bool dd_frm_is_view(THD *thd, char *path) { - return dd_frm_type(thd, path, NULL) == TABLE_TYPE_VIEW; + return dd_frm_type(thd, path, NULL, NULL, NULL) == TABLE_TYPE_VIEW; } bool dd_recreate_table(THD *thd, const char *db, const char *table_name); diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index f252c0c3137..dd9fea5937a 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -459,6 +459,11 @@ void ha_partition::init_handler_variables() #endif } +const char *ha_partition::real_table_type() const +{ + // we can do this since we only support a single engine type + return m_file[0]->table_type(); +} /* Destructor method @@ -3772,6 +3777,15 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) */ clear_handler_file(); + DBUG_ASSERT(part_share); + lock_shared_ha_data(); + /* Protect against cloned file, for which we don't need engine name */ + if (m_file[0]) + part_share->partition_engine_name= real_table_type(); + else + part_share->partition_engine_name= 0; // Checked in ha_table_exists() + unlock_shared_ha_data(); + /* Some handlers update statistics as part of the open call. This will in some cases corrupt the statistics of the partition handler and thus diff --git a/sql/ha_partition.h b/sql/ha_partition.h index df204cd3d2d..15513b96b97 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -98,12 +98,14 @@ public: */ bool partition_name_hash_initialized; HASH partition_name_hash; + const char *partition_engine_name; /** Storage for each partitions Handler_share */ Parts_share_refs partitions_share_refs; Partition_share() : auto_inc_initialized(false), next_auto_inc_val(0), partition_name_hash_initialized(false), + partition_engine_name(NULL), partition_names(NULL) { mysql_mutex_init(key_partition_auto_inc_mutex, @@ -269,7 +271,7 @@ typedef struct st_partition_part_key_multi_range_hld extern "C" int cmp_key_part_id(void *key_p, uchar *ref1, uchar *ref2); extern "C" int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2); -class ha_partition :public handler +class ha_partition final :public handler { private: enum partition_index_scan_type @@ -1071,6 +1073,8 @@ public: */ const char *index_type(uint inx) override; + /* The name of the table type that will be used for display purposes */ + const char *real_table_type() const override; /* The name of the row type used for the underlying tables. */ enum row_type get_row_type() const override; @@ -1596,6 +1600,7 @@ public: return h; } + bool partition_engine() override { return 1;} ha_rows part_records(partition_element *part_elem) { DBUG_ASSERT(m_part_info); diff --git a/sql/handler.cc b/sql/handler.cc index fa99c24771c..f6636c3b36f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -997,6 +997,27 @@ void ha_end_backup() PLUGIN_IS_DELETED|PLUGIN_IS_READY, 0); } +void handler::log_not_redoable_operation(const char *operation) +{ + DBUG_ENTER("log_not_redoable_operation"); + if (table->s->tmp_table == NO_TMP_TABLE) + { + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + lex_string_set(&ddl_log.query, operation); + /* + We can't use partition_engine() here as this function is called + directly by the handler for the underlaying partition table + */ + ddl_log.org_partitioned= table->s->partition_info_str != 0; + lex_string_set(&ddl_log.org_storage_engine_name, table_type()); + ddl_log.org_database= table->s->db; + ddl_log.org_table= table->s->table_name; + ddl_log.org_table_id= table->s->tabledef_version; + backup_log_ddl(&ddl_log); + } + DBUG_VOID_RETURN; +} /* Inform plugin of the server shutdown. @@ -5856,7 +5877,8 @@ static my_bool discover_existence(THD *thd, plugin_ref plugin, */ bool ha_table_exists(THD *thd, const LEX_CSTRING *db, - const LEX_CSTRING *table_name, + const LEX_CSTRING *table_name, LEX_CUSTRING *table_id, + LEX_CSTRING *partition_engine_name, handlerton **hton, bool *is_sequence) { handlerton *dummy; @@ -5870,17 +5892,42 @@ bool ha_table_exists(THD *thd, const LEX_CSTRING *db, if (!is_sequence) is_sequence= &dummy2; *is_sequence= 0; + if (table_id) + { + table_id->str= 0; + table_id->length= 0; + } TDC_element *element= tdc_lock_share(thd, db->str, table_name->str); if (element && element != MY_ERRPTR) { - if (hton) - *hton= element->share->db_type(); + if (!hton) + hton= &dummy; + *hton= element->share->db_type(); + if (partition_engine_name && element->share->db_type() == partition_hton) + { + if (!static_cast<Partition_share *>(element->share->ha_share)-> + partition_engine_name) + { + /* Partition engine found, but table has never been opened */ + tdc_unlock_share(element); + goto retry_from_frm; + } + lex_string_set(partition_engine_name, + static_cast<Partition_share *>(element->share->ha_share)-> + partition_engine_name); + } *is_sequence= element->share->table_type == TABLE_TYPE_SEQUENCE; + if (*hton != view_pseudo_hton && element->share->tabledef_version.length && + table_id && + (table_id->str= (uchar*) + thd->memdup(element->share->tabledef_version.str, MY_UUID_SIZE))) + table_id->length= MY_UUID_SIZE; tdc_unlock_share(element); DBUG_RETURN(TRUE); } +retry_from_frm: char path[FN_REFLEN + 1]; size_t path_len = build_table_filename(path, sizeof(path) - 1, db->str, table_name->str, "", 0); @@ -5893,7 +5940,9 @@ bool ha_table_exists(THD *thd, const LEX_CSTRING *db, { char engine_buf[NAME_CHAR_LEN + 1]; LEX_CSTRING engine= { engine_buf, 0 }; - Table_type type= dd_frm_type(thd, path, &engine); + Table_type type= dd_frm_type(thd, path, &engine, + partition_engine_name, + table_id); switch (type) { case TABLE_TYPE_UNKNOWN: @@ -5948,6 +5997,10 @@ bool ha_table_exists(THD *thd, const LEX_CSTRING *db, if (hton && share) { *hton= share->db_type(); + if (table_id && share->tabledef_version.length && + (table_id->str= + (uchar*) thd->memdup(share->tabledef_version.str, MY_UUID_SIZE))) + table_id->length= MY_UUID_SIZE; tdc_release_share(share); } diff --git a/sql/handler.h b/sql/handler.h index 78ca0f92a38..18a1a4abf40 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1083,6 +1083,8 @@ typedef bool (stat_print_fn)(THD *thd, const char *type, size_t type_len, enum ha_stat_type { HA_ENGINE_STATUS, HA_ENGINE_LOGS, HA_ENGINE_MUTEX }; extern MYSQL_PLUGIN_IMPORT st_plugin_int *hton2plugin[MAX_HA]; +#define view_pseudo_hton ((handlerton *)1) + /* Transaction log maintains type definitions */ enum log_status { @@ -2227,9 +2229,11 @@ struct Table_scope_and_contents_source_pod_st // For trivial members { CHARSET_INFO *alter_table_convert_to_charset; LEX_CUSTRING tabledef_version; + LEX_CUSTRING org_tabledef_version; /* version of dropped table */ LEX_CSTRING connect_string; LEX_CSTRING comment; LEX_CSTRING alias; + LEX_CSTRING org_storage_engine_name, new_storage_engine_name; const char *password, *tablespace; const char *data_file_name, *index_file_name; ulonglong max_rows,min_rows; @@ -4222,6 +4226,8 @@ public: virtual void free_foreign_key_create_info(char* str) {} /** The following can be called without an open handler */ virtual const char *table_type() const { return hton_name(ht)->str; } + /* The following is same as table_table(), except for partition engine */ + virtual const char *real_table_type() const { return hton_name(ht)->str; } const char **bas_ext() const { return ht->tablefile_extensions; } virtual int get_default_no_partitions(HA_CREATE_INFO *create_info) @@ -5099,6 +5105,7 @@ public: /* XXX to be removed, see ha_partition::partition_ht() */ virtual handlerton *partition_ht() const { return ht; } + virtual bool partition_engine() { return 0;} inline int ha_write_tmp_row(uchar *buf); inline int ha_delete_tmp_row(uchar *buf); inline int ha_update_tmp_row(const uchar * old_data, uchar * new_data); @@ -5168,6 +5175,7 @@ public: return (lower_case_table_names == 2 && !(ha_table_flags() & HA_FILE_BASED)); } + void log_not_redoable_operation(const char *operation); protected: Handler_share *get_ha_share_ptr(); void set_ha_share_ptr(Handler_share *arg_ha_share); @@ -5210,7 +5218,8 @@ static inline enum legacy_db_type ha_legacy_type(const handlerton *db_type) static inline const char *ha_resolve_storage_engine_name(const handlerton *db_type) { - return db_type == NULL ? "UNKNOWN" : hton_name(db_type)->str; + return (db_type == NULL ? "UNKNOWN" : + db_type == view_pseudo_hton ? "VIEW" : hton_name(db_type)->str); } static inline bool ha_check_storage_engine_flag(const handlerton *db_type, uint32 flag) @@ -5223,8 +5232,6 @@ static inline bool ha_storage_engine_is_enabled(const handlerton *db_type) return db_type && db_type->create; } -#define view_pseudo_hton ((handlerton *)1) - /* basic stuff */ int ha_init_errors(void); int ha_init(void); @@ -5292,6 +5299,8 @@ int ha_discover_table_names(THD *thd, LEX_CSTRING *db, MY_DIR *dirp, Discovered_table_list *result, bool reusable); bool ha_table_exists(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *table_name, + LEX_CUSTRING *table_version= 0, + LEX_CSTRING *partition_engine_name= 0, handlerton **hton= 0, bool *is_sequence= 0); bool ha_check_if_updates_are_ignored(THD *thd, handlerton *hton, const char *op); diff --git a/sql/mdl.cc b/sql/mdl.cc index e83ef151554..1bacdf8f67b 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -1584,7 +1584,7 @@ MDL_lock::MDL_object_lock::m_waiting_incompatible[MDL_TYPE_END]= TD | + + + + + - - + + + + + + + | SD | + + + + - - - + + + + + + + | DDL | + + + - - - - + + + + - + + | - BLOCK_DDL | + + + + + + + + + + - + + + | + BLOCK_DDL | - + + + + + + + + + - + + + | ALTER_COP | + + + + + - - + + + + + + + | COMMIT | + + + + - + - + + + + + + + | @@ -1623,7 +1623,7 @@ const MDL_lock::bitmap_t MDL_lock::MDL_backup_lock::m_granted_incompatible[MDL_BACKUP_END]= { /* MDL_BACKUP_START */ - MDL_BIT(MDL_BACKUP_START) | MDL_BIT(MDL_BACKUP_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_DDL) | MDL_BIT(MDL_BACKUP_WAIT_COMMIT), + MDL_BIT(MDL_BACKUP_START) | MDL_BIT(MDL_BACKUP_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_DDL) | MDL_BIT(MDL_BACKUP_WAIT_COMMIT) | MDL_BIT(MDL_BACKUP_BLOCK_DDL), MDL_BIT(MDL_BACKUP_START), MDL_BIT(MDL_BACKUP_START) | MDL_BIT(MDL_BACKUP_DML), MDL_BIT(MDL_BACKUP_START) | MDL_BIT(MDL_BACKUP_DML) | MDL_BIT(MDL_BACKUP_DDL), @@ -1639,7 +1639,7 @@ MDL_lock::MDL_backup_lock::m_granted_incompatible[MDL_BACKUP_END]= /* MDL_BACKUP_DDL */ MDL_BIT(MDL_BACKUP_WAIT_DDL) | MDL_BIT(MDL_BACKUP_WAIT_COMMIT) | MDL_BIT(MDL_BACKUP_FTWRL1) | MDL_BIT(MDL_BACKUP_FTWRL2) | MDL_BIT(MDL_BACKUP_BLOCK_DDL), /* MDL_BACKUP_BLOCK_DDL */ - MDL_BIT(MDL_BACKUP_DDL), + MDL_BIT(MDL_BACKUP_START) | MDL_BIT(MDL_BACKUP_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_DDL) | MDL_BIT(MDL_BACKUP_WAIT_COMMIT) | MDL_BIT(MDL_BACKUP_BLOCK_DDL) | MDL_BIT(MDL_BACKUP_DDL), MDL_BIT(MDL_BACKUP_FTWRL1) | MDL_BIT(MDL_BACKUP_FTWRL2), /* MDL_BACKUP_COMMIT */ MDL_BIT(MDL_BACKUP_WAIT_COMMIT) | MDL_BIT(MDL_BACKUP_FTWRL2) @@ -1650,7 +1650,7 @@ const MDL_lock::bitmap_t MDL_lock::MDL_backup_lock::m_waiting_incompatible[MDL_BACKUP_END]= { /* MDL_BACKUP_START */ - MDL_BIT(MDL_BACKUP_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_DDL) | MDL_BIT(MDL_BACKUP_WAIT_COMMIT), + MDL_BIT(MDL_BACKUP_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_DDL) | MDL_BIT(MDL_BACKUP_WAIT_COMMIT) | MDL_BIT(MDL_BACKUP_BLOCK_DDL), 0, 0, 0, @@ -1666,7 +1666,7 @@ MDL_lock::MDL_backup_lock::m_waiting_incompatible[MDL_BACKUP_END]= /* MDL_BACKUP_DDL */ MDL_BIT(MDL_BACKUP_WAIT_DDL) | MDL_BIT(MDL_BACKUP_WAIT_COMMIT) | MDL_BIT(MDL_BACKUP_FTWRL1) | MDL_BIT(MDL_BACKUP_FTWRL2) | MDL_BIT(MDL_BACKUP_BLOCK_DDL), /* MDL_BACKUP_BLOCK_DDL */ - 0, + MDL_BIT(MDL_BACKUP_START), MDL_BIT(MDL_BACKUP_FTWRL1) | MDL_BIT(MDL_BACKUP_FTWRL2), /* MDL_BACKUP_COMMIT */ MDL_BIT(MDL_BACKUP_WAIT_COMMIT) | MDL_BIT(MDL_BACKUP_FTWRL2) @@ -2911,6 +2911,10 @@ void MDL_context::release_all_locks_for_name(MDL_ticket *name) void MDL_ticket::downgrade_lock(enum_mdl_type type) { + DBUG_ENTER("MDL_ticket::downgrade_lock"); + DBUG_PRINT("enter",("old_type: %s new_type: %s", + get_type_name()->str, + get_type_name(type)->str)); /* Do nothing if already downgraded. Used when we FLUSH TABLE under LOCK TABLES and a table is listed twice in LOCK TABLES list. @@ -2919,7 +2923,10 @@ void MDL_ticket::downgrade_lock(enum_mdl_type type) here that target lock is weaker than existing lock. */ if (m_type == type || !has_stronger_or_equal_type(type)) - return; + { + DBUG_PRINT("info", ("Nothing to downgrade")); + DBUG_VOID_RETURN; + } /* Only allow downgrade in some specific known cases */ DBUG_ASSERT((get_key()->mdl_namespace() != MDL_key::BACKUP && @@ -2927,6 +2934,7 @@ void MDL_ticket::downgrade_lock(enum_mdl_type type) m_type == MDL_SHARED_NO_WRITE)) || (get_key()->mdl_namespace() == MDL_key::BACKUP && (m_type == MDL_BACKUP_DDL || + m_type == MDL_BACKUP_BLOCK_DDL || m_type == MDL_BACKUP_WAIT_FLUSH))); mysql_prlock_wrlock(&m_lock->m_rwlock); @@ -2939,6 +2947,7 @@ void MDL_ticket::downgrade_lock(enum_mdl_type type) m_lock->m_granted.add_ticket(this); m_lock->reschedule_waiters(); mysql_prlock_unlock(&m_lock->m_rwlock); + DBUG_VOID_RETURN; } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index dff18b9585e..69ab896abf2 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -711,6 +711,7 @@ mysql_mutex_t LOCK_prepared_stmt_count; #ifdef HAVE_OPENSSL mysql_mutex_t LOCK_des_key_file; #endif +mysql_mutex_t LOCK_backup_log; mysql_rwlock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; mysql_rwlock_t LOCK_ssl_refresh; mysql_rwlock_t LOCK_all_status_vars; @@ -856,6 +857,7 @@ PSI_file_key key_file_binlog, key_file_binlog_cache, key_file_binlog_index, key_file_dbopt, key_file_des_key_file, key_file_ERRMSG, key_select_to_file, key_file_fileparser, key_file_frm, key_file_global_ddl_log, key_file_load, key_file_loadfile, key_file_log_event_data, key_file_log_event_info, + key_file_log_ddl, key_file_master_info, key_file_misc, key_file_partition_ddl_log, key_file_pid, key_file_relay_log_info, key_file_send_file, key_file_tclog, key_file_trg, key_file_trn, key_file_init; @@ -881,7 +883,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list, key_LOCK_crypt, key_LOCK_delayed_create, key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log, key_LOCK_gdl, key_LOCK_global_system_variables, - key_LOCK_manager, + key_LOCK_manager, key_LOCK_backup_log, key_LOCK_prepared_stmt_count, key_LOCK_rpl_status, key_LOCK_server_started, key_LOCK_status, @@ -941,6 +943,7 @@ static PSI_mutex_info all_server_mutexes[]= { &key_delayed_insert_mutex, "Delayed_insert::mutex", 0}, { &key_hash_filo_lock, "hash_filo::lock", 0}, { &key_LOCK_active_mi, "LOCK_active_mi", PSI_FLAG_GLOBAL}, + { &key_LOCK_backup_log, "LOCK_backup_log", PSI_FLAG_GLOBAL}, { &key_LOCK_thread_id, "LOCK_thread_id", PSI_FLAG_GLOBAL}, { &key_LOCK_crypt, "LOCK_crypt", PSI_FLAG_GLOBAL}, { &key_LOCK_delayed_create, "LOCK_delayed_create", PSI_FLAG_GLOBAL}, @@ -2043,6 +2046,7 @@ static void clean_up_mutexes() #endif /* HAVE_REPLICATION */ mysql_mutex_destroy(&LOCK_active_mi); mysql_rwlock_destroy(&LOCK_ssl_refresh); + mysql_mutex_destroy(&LOCK_backup_log); mysql_rwlock_destroy(&LOCK_sys_init_connect); mysql_rwlock_destroy(&LOCK_sys_init_slave); mysql_mutex_destroy(&LOCK_global_system_variables); @@ -4340,6 +4344,7 @@ static int init_thread_environment() MY_MUTEX_INIT_SLOW); mysql_mutex_init(key_LOCK_commit_ordered, &LOCK_commit_ordered, MY_MUTEX_INIT_SLOW); + mysql_mutex_init(key_LOCK_backup_log, &LOCK_backup_log, MY_MUTEX_INIT_FAST); #ifdef HAVE_OPENSSL mysql_mutex_init(key_LOCK_des_key_file, @@ -8971,6 +8976,7 @@ static PSI_file_info all_server_files[]= { &key_file_global_ddl_log, "global_ddl_log", 0}, { &key_file_load, "load", 0}, { &key_file_loadfile, "LOAD_FILE", 0}, + { &key_file_log_ddl, "log_ddl", 0}, { &key_file_log_event_data, "log_event_data", 0}, { &key_file_log_event_info, "log_event_info", 0}, { &key_file_master_info, "master_info", 0}, diff --git a/sql/mysqld.h b/sql/mysqld.h index b50b98e0dea..ddfec106b60 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -396,7 +396,7 @@ extern PSI_file_key key_file_binlog, key_file_binlog_cache, key_file_loadfile, key_file_log_event_data, key_file_log_event_info, key_file_master_info, key_file_misc, key_file_partition_ddl_log, key_file_pid, key_file_relay_log_info, key_file_send_file, key_file_tclog, - key_file_trg, key_file_trn, key_file_init; + key_file_trg, key_file_trn, key_file_init, key_file_log_ddl; extern PSI_file_key key_file_query_log, key_file_slow_log; extern PSI_file_key key_file_relaylog, key_file_relaylog_index, key_file_relaylog_cache, key_file_relaylog_index_cache; @@ -744,7 +744,7 @@ extern mysql_mutex_t LOCK_error_log, LOCK_delayed_insert, LOCK_short_uuid_generator, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, LOCK_active_mi, LOCK_manager, LOCK_user_conn, - LOCK_prepared_stmt_count, LOCK_error_messages; + LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_backup_log; extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_global_system_variables; extern mysql_rwlock_t LOCK_all_status_vars; extern mysql_mutex_t LOCK_start_thread; diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 3c2675d1d5d..c7d83676cc4 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -520,7 +520,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, bool need_repair_or_alter= 0; wait_for_commit* suspended_wfc; bool is_table_modified= false; - + LEX_CUSTRING tabledef_version; DBUG_ENTER("mysql_admin_table"); DBUG_PRINT("enter", ("extra_open_options: %u", extra_open_options)); @@ -574,12 +574,17 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, { char table_name_buff[SAFE_NAME_LEN*2+2]; LEX_CSTRING table_name= { table_name_buff, 0}; + char storage_engine_name[NAME_LEN]; + bool storage_engine_partitioned= 0; + uchar tabledef_version_buff[MY_UUID_SIZE]; const char *db= table->db.str; bool fatal_error=0; bool open_error; bool collect_eis= FALSE; bool open_for_modify= org_open_for_modify; + storage_engine_name[0]= 0; // Marker that's not used + DBUG_PRINT("admin", ("table: '%s'.'%s'", db, table->table_name.str)); DEBUG_SYNC(thd, "admin_command_kill_before_modify"); @@ -795,6 +800,16 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, thd->close_unused_temporary_table_instances(tables); else { + /* Store information about table for ddl log */ + storage_engine_partitioned= table->table->file->partition_engine(); + strmake(storage_engine_name, table->table->file->real_table_type(), + sizeof(storage_engine_name)-1); + tabledef_version.str= tabledef_version_buff; + if ((tabledef_version.length= table->table->s->tabledef_version.length)) + memcpy((char*) tabledef_version.str, + table->table->s->tabledef_version.str, + MY_UUID_SIZE); + if (wait_while_table_is_used(thd, table->table, HA_EXTRA_NOT_USED)) goto err; DEBUG_SYNC(thd, "after_admin_flush"); @@ -1246,6 +1261,7 @@ send_result_message: with conflicting DMLs resulting in deadlock. */ thd->transaction->stmt.mark_executed_table_admin_cmd(); + if (table->table && !table->view) { /* @@ -1292,6 +1308,22 @@ send_result_message: is_table_modified= true; } close_thread_tables(thd); + + if (storage_engine_name[0]) + { + /* Table was changed (repair, optimize or something similar) */ + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + lex_string_set(&ddl_log.org_storage_engine_name, + storage_engine_name); + ddl_log.query= *operator_name; + ddl_log.org_partitioned= storage_engine_partitioned; + ddl_log.org_database= table->db; + ddl_log.org_table= table->table_name; + ddl_log.org_table_id= tabledef_version; + backup_log_ddl(&ddl_log); + } + thd->release_transactional_locks(); /* diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index 9af4dfde77d..5827b7b104b 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -280,10 +280,8 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list, tables_opened(tables_opened_arg), new_db(*new_db_arg), new_name(*new_name_arg), 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) { /* Assign members db, table_name, new_db and new_name @@ -362,10 +360,22 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list, this case. This fact is enforced with assert. */ build_tmptable_filename(thd, tmp_path, sizeof(tmp_path)); -#ifdef DBUG_ASSERT_EXISTS tmp_table= true; -#endif } + if ((id.length= table_list->table->s->tabledef_version.length)) + memcpy(id_buff, table_list->table->s->tabledef_version.str, MY_UUID_SIZE); + id.str= id_buff; + storage_engine_partitioned= table_list->table->file->partition_engine(); + storage_engine_name.str= storage_engine_buff; + storage_engine_name.length= ((strmake(storage_engine_buff, + table_list->table->file-> + real_table_type(), + sizeof(storage_engine_buff)-1)) - + storage_engine_buff); + tmp_storage_engine_name.str= tmp_storage_engine_buff; + tmp_storage_engine_name.length= 0; + tmp_id.str= 0; + tmp_id.length= 0; } diff --git a/sql/sql_alter.h b/sql/sql_alter.h index b8aa2595a58..a0f89c28d2a 100644 --- a/sql/sql_alter.h +++ b/sql/sql_alter.h @@ -318,12 +318,19 @@ public: uint tables_opened; LEX_CSTRING db; LEX_CSTRING table_name; + LEX_CSTRING storage_engine_name; LEX_CSTRING alias; LEX_CSTRING new_db; LEX_CSTRING new_name; LEX_CSTRING new_alias; LEX_CSTRING tmp_name; + LEX_CSTRING tmp_storage_engine_name; + LEX_CUSTRING tmp_id, id; char tmp_buff[80]; + uchar id_buff[MY_UUID_SIZE]; + char storage_engine_buff[NAME_LEN], tmp_storage_engine_buff[NAME_LEN]; + bool storage_engine_partitioned; + bool tmp_storage_engine_name_partitioned; /** Indicates that if a row is deleted during copying of data from old version @@ -335,6 +342,8 @@ public: const char *fk_error_id; /** Name of table for the above error. */ const char *fk_error_table; + /** Indicates that we are altering temporary table */ + bool tmp_table; private: char new_filename[FN_REFLEN + 1]; @@ -344,11 +353,6 @@ private: char new_path[FN_REFLEN + 1]; char tmp_path[FN_REFLEN + 1]; -#ifdef DBUG_ASSERT_EXISTS - /** Indicates that we are altering temporary table. Used only in asserts. */ - bool tmp_table; -#endif - Alter_table_ctx &operator=(const Alter_table_ctx &rhs); // not implemented Alter_table_ctx(const Alter_table_ctx &rhs); // not implemented }; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 71af78d135d..4a01ecd97da 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3926,7 +3926,7 @@ static bool upgrade_lock_if_not_exists(THD *thd, DEBUG_SYNC(thd,"create_table_before_check_if_exists"); if (!create_info.or_replace() && ha_table_exists(thd, &create_table->db, &create_table->table_name, - &create_table->db_type)) + NULL, NULL, &create_table->db_type)) { if (create_info.if_not_exists()) { diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 92d9e90adc1..7d4467c78ca 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -637,6 +637,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) thread_dbug_id(id), os_thread_id(0), global_disable_checkpoint(0), + current_backup_stage(BACKUP_FINISHED), failed_com_change_user(0), is_fatal_error(0), transaction_rollback_request(0), diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 4fd90a0e0b1..090b87af4ff 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -789,7 +789,6 @@ mysql_create_db_internal(THD *thd, const LEX_CSTRING *db, DBUG_RETURN(-1); } - if (my_mkdir(path, 0777, MYF(0)) < 0) { my_error(ER_CANT_CREATE_DB, MYF(0), db->str, my_errno); @@ -815,6 +814,14 @@ mysql_create_db_internal(THD *thd, const LEX_CSTRING *db, thd->clear_error(); } + /* Log command to ddl log */ + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + ddl_log.query= { C_STRING_WITH_LEN("CREATE") }; + ddl_log.org_storage_engine_name= { C_STRING_WITH_LEN("DATABASE") }; + ddl_log.org_database= *db; + backup_log_ddl(&ddl_log); + not_silent: if (!silent) { @@ -898,6 +905,14 @@ mysql_alter_db_internal(THD *thd, const LEX_CSTRING *db, thd->variables.collation_database= thd->db_charset; } + /* Log command to ddl log */ + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + ddl_log.query= { C_STRING_WITH_LEN("ALTER") }; + ddl_log.org_storage_engine_name= { C_STRING_WITH_LEN("DATABASE") }; + ddl_log.org_database= *db; + backup_log_ddl(&ddl_log); + if (mysql_bin_log.is_open()) { int errcode= query_error_code(thd, TRUE); @@ -1148,6 +1163,17 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, thd->pop_internal_handler(); update_binlog: + if (likely(!error)) + { + /* Log command to ddl log */ + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + ddl_log.query= { C_STRING_WITH_LEN("DROP") }; + ddl_log.org_storage_engine_name= { C_STRING_WITH_LEN("DATABASE") }; + ddl_log.org_database= *db; + backup_log_ddl(&ddl_log); + } + if (!silent && likely(!error)) { const char *query; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 54fb94e8e4f..9bdd40010df 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -5034,6 +5034,20 @@ bool select_create::send_eof() mysql_mutex_unlock(&thd->LOCK_thd_data); } #endif /* WITH_WSREP */ + + /* Log query to ddl log */ + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + ddl_log.query= { C_STRING_WITH_LEN("CREATE") }; + if ((ddl_log.org_partitioned= (create_info->db_type == partition_hton))) + ddl_log.org_storage_engine_name= create_info->new_storage_engine_name; + else + lex_string_set(&ddl_log.org_storage_engine_name, + ha_resolve_storage_engine_name(create_info->db_type)); + ddl_log.org_database= create_table->db; + ddl_log.org_table= create_table->table_name; + ddl_log.org_table_id= create_info->tabledef_version; + backup_log_ddl(&ddl_log); } /* If are using statement based replication the table will be deleted here @@ -5154,21 +5168,39 @@ void select_create::abort_result_set() drop_open_table(thd, table, &create_table->db, &create_table->table_name); table=0; // Safety - if (thd->log_current_statement && mysql_bin_log.is_open()) + if (thd->log_current_statement) { - /* Remove logging of drop, create + insert rows */ - binlog_reset_cache(thd); - /* Original table was deleted. We have to log it */ - if (table_creation_was_logged) + if (mysql_bin_log.is_open()) + { + /* Remove logging of drop, create + insert rows */ + binlog_reset_cache(thd); + /* Original table was deleted. We have to log it */ + if (table_creation_was_logged) + { + thd->binlog_xid= thd->query_id; + ddl_log_update_xid(&ddl_log_state_create, thd->binlog_xid); + ddl_log_update_xid(&ddl_log_state_rm, thd->binlog_xid); + debug_crash_here("ddl_log_create_before_binlog"); + log_drop_table(thd, &create_table->db, &create_table->table_name, + &create_info->org_storage_engine_name, + create_info->db_type == partition_hton, + &create_info->tabledef_version, + tmp_table); + debug_crash_here("ddl_log_create_after_binlog"); + thd->binlog_xid= 0; + } + } + else if (!tmp_table) { - thd->binlog_xid= thd->query_id; - ddl_log_update_xid(&ddl_log_state_create, thd->binlog_xid); - ddl_log_update_xid(&ddl_log_state_rm, thd->binlog_xid); - debug_crash_here("ddl_log_create_before_binlog"); - log_drop_table(thd, &create_table->db, &create_table->table_name, - tmp_table); - debug_crash_here("ddl_log_create_after_binlog"); - thd->binlog_xid= 0; + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + ddl_log.query= { C_STRING_WITH_LEN("DROP_AFTER_CREATE") }; + ddl_log.org_partitioned= (create_info->db_type == partition_hton); + ddl_log.org_storage_engine_name= create_info->org_storage_engine_name; + ddl_log.org_database= create_table->db; + ddl_log.org_table= create_table->table_name; + ddl_log.org_table_id= create_info->tabledef_version; + backup_log_ddl(&ddl_log); } } } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 07926712583..397b8a8a350 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -7035,6 +7035,30 @@ static void downgrade_mdl_if_lock_tables_mode(THD *thd, MDL_ticket *ticket, } +bool log_partition_alter_to_ddl_log(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + LEX_CSTRING old_engine_lex; + lex_string_set(&old_engine_lex, lpt->table->file->real_table_type()); + + ddl_log.query= { C_STRING_WITH_LEN("ALTER") }; + ddl_log.org_storage_engine_name= old_engine_lex; + ddl_log.org_partitioned= true; + ddl_log.org_database= lpt->db; + ddl_log.org_table= lpt->table_name; + ddl_log.org_table_id= lpt->org_tabledef_version; + ddl_log.new_storage_engine_name= old_engine_lex; + ddl_log.new_partitioned= true; + ddl_log.new_database= lpt->db; + ddl_log.new_table= lpt->table_name; + ddl_log.new_table_id= lpt->create_info->tabledef_version; + backup_log_ddl(&ddl_log); // This sets backup_log_error on failure + return 0; +} + + + /** Actually perform the change requested by ALTER TABLE of partitions previously prepared. @@ -7087,6 +7111,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, lpt->key_count= 0; lpt->db= *db; lpt->table_name= *table_name; + lpt->org_tabledef_version= table->s->tabledef_version; lpt->copied= 0; lpt->deleted= 0; lpt->pack_frm_data= NULL; @@ -7224,6 +7249,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_ERROR("fail_drop_partition_6") || (frm_install= TRUE, FALSE) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + log_partition_alter_to_ddl_log(lpt) || (frm_install= FALSE, FALSE) || ERROR_INJECT_CRASH("crash_drop_partition_7") || ERROR_INJECT_ERROR("fail_drop_partition_7") || @@ -7303,6 +7329,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_ERROR("fail_add_partition_8") || (frm_install= TRUE, FALSE) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + log_partition_alter_to_ddl_log(lpt) || (frm_install= FALSE, FALSE) || ERROR_INJECT_CRASH("crash_add_partition_9") || ERROR_INJECT_ERROR("fail_add_partition_9") || @@ -7401,6 +7428,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_ERROR("fail_change_partition_8") || ((frm_install= TRUE), FALSE) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + log_partition_alter_to_ddl_log(lpt) || (frm_install= FALSE, FALSE) || ERROR_INJECT_CRASH("crash_change_partition_9") || ERROR_INJECT_ERROR("fail_change_partition_9") || diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 58ba82dcd9f..57e6d0600ed 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -59,6 +59,7 @@ typedef struct st_lock_param_type KEY *key_info_buffer; LEX_CSTRING db; LEX_CSTRING table_name; + LEX_CUSTRING org_tabledef_version; uchar *pack_frm_data; uint key_count; uint db_options; diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc index ca564af1bf6..1056998ef08 100644 --- a/sql/sql_partition_admin.cc +++ b/sql/sql_partition_admin.cc @@ -507,6 +507,16 @@ bool Sql_cmd_alter_table_exchange_partition:: char part_file_name[2*FN_REFLEN+1]; char swap_file_name[FN_REFLEN+1]; char temp_file_name[FN_REFLEN+1]; + char part_table_name[NAME_LEN + 1]; + char part_db[NAME_LEN + 1]; + char swap_table_name[NAME_LEN + 1]; + char swap_db[NAME_LEN + 1]; + uchar part_tabledef_version[MY_UUID_SIZE]; + uchar swap_tabledef_version[MY_UUID_SIZE]; + + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + uint swap_part_id; uint part_file_name_len; Alter_table_prelocking_strategy alter_prelocking_strategy; @@ -576,6 +586,35 @@ bool Sql_cmd_alter_table_exchange_partition:: HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE) force_if_exists= 1; + ddl_log.org_table.str= part_table_name; + DBUG_ASSERT(part_table->s->table_name.length <= NAME_LEN); + ddl_log.org_table.length= part_table->s->table_name.length; + strmake(part_table_name, part_table->s->table_name.str, NAME_LEN); + + ddl_log.org_database.str= part_db; + DBUG_ASSERT(part_table->s->db.length <= NAME_LEN); + ddl_log.org_database.length= part_table->s->db.length; + strmake(part_db, part_table->s->db.str, NAME_LEN); + + ddl_log.new_table.str= swap_table_name; + DBUG_ASSERT(swap_table->s->table_name.length <= NAME_LEN); + ddl_log.new_table.length= swap_table->s->table_name.length; + strmake(swap_table_name, swap_table->s->table_name.str, NAME_LEN); + + ddl_log.new_database.str= swap_db; + DBUG_ASSERT(swap_table->s->db.length <= NAME_LEN); + ddl_log.new_database.length= swap_table->s->db.length; + strmake(swap_db, swap_table->s->db.str, NAME_LEN); + + memcpy(part_tabledef_version, part_table->s->tabledef_version.str, + MY_UUID_SIZE); + ddl_log.org_table_id.str= part_tabledef_version; + ddl_log.org_table_id.length= MY_UUID_SIZE; + memcpy(swap_tabledef_version, swap_table->s->tabledef_version.str, + MY_UUID_SIZE); + ddl_log.new_table_id.str= swap_tabledef_version; + ddl_log.new_table_id.length= MY_UUID_SIZE; + /* set lock pruning on first table */ partition_name= alter_info->partition_names.head(); if (unlikely(table_list->table->part_info-> @@ -586,7 +625,6 @@ bool Sql_cmd_alter_table_exchange_partition:: if (unlikely(lock_tables(thd, table_list, table_counter, 0))) DBUG_RETURN(true); - table_hton= swap_table->file->ht; THD_STAGE_INFO(thd, stage_verifying_table); @@ -690,6 +728,15 @@ bool Sql_cmd_alter_table_exchange_partition:: (void) exchange_name_with_ddl_log(thd, part_file_name, swap_file_name, temp_file_name, table_hton); } + else + { + ddl_log.query= { C_STRING_WITH_LEN("EXCHANGE_PARTITION") }; + ddl_log.org_partitioned= true; + ddl_log.new_partitioned= false; + ddl_log.org_storage_engine_name= *hton_name(table_hton); + ddl_log.new_storage_engine_name= *hton_name(table_hton); + backup_log_ddl(&ddl_log); + } thd->variables.option_bits= save_option_bits; err: diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 195267b9abc..61cf204d721 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1724,7 +1724,8 @@ int plugin_init(int *argc, char **argv, int flags) { char path[FN_REFLEN + 1]; build_table_filename(path, sizeof(path) - 1, "mysql", "plugin", reg_ext, 0); - Table_type ttype= dd_frm_type(0, path, &plugin_table_engine_name); + Table_type ttype= dd_frm_type(0, path, &plugin_table_engine_name, + NULL, NULL); if (ttype != TABLE_TYPE_NORMAL) plugin_table_engine_name=empty_clex_str; } diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 205c3ce91b7..094578874a8 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -234,6 +234,7 @@ do_rename_temporary(THD *thd, TABLE_LIST *ren_table, TABLE_LIST *new_table) struct rename_param { LEX_CSTRING old_alias, new_alias; + LEX_CUSTRING old_version; handlerton *from_table_hton; }; @@ -281,6 +282,7 @@ check_rename(THD *thd, rename_param *param, DBUG_ASSERT(param->new_alias.str); if (!ha_table_exists(thd, &ren_table->db, ¶m->old_alias, + ¶m->old_version, NULL, ¶m->from_table_hton) || !param->from_table_hton) { @@ -301,7 +303,7 @@ check_rename(THD *thd, rename_param *param, DBUG_RETURN(-1); } - if (ha_table_exists(thd, new_db, ¶m->new_alias, 0)) + if (ha_table_exists(thd, new_db, ¶m->new_alias, NULL, NULL, 0)) { my_error(ER_TABLE_EXISTS_ERROR, MYF(0), param->new_alias.str); DBUG_RETURN(1); // This can't be skipped @@ -379,7 +381,7 @@ do_rename(THD *thd, rename_param *param, DDL_LOG_STATE *ddl_log_state, debug_crash_here("ddl_log_rename_before_rename_table"); if (!(rc= mysql_rename_table(hton, &ren_table->db, old_alias, - new_db, new_alias, 0))) + new_db, new_alias, ¶m->old_version, 0))) { /* Table rename succeded. It's safe to start recovery at rename trigger phase @@ -413,7 +415,8 @@ do_rename(THD *thd, rename_param *param, DDL_LOG_STATE *ddl_log_state, */ debug_crash_here("ddl_log_rename_after_failed_rename_trigger"); (void) mysql_rename_table(hton, new_db, new_alias, - &ren_table->db, old_alias, NO_FK_CHECKS); + &ren_table->db, old_alias, ¶m->old_version, + NO_FK_CHECKS); debug_crash_here("ddl_log_rename_after_revert_rename_table"); ddl_log_disable_entry(ddl_log_state); debug_crash_here("ddl_log_rename_after_disable_entry"); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 8e7e042264b..a2cd4e232f5 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4515,7 +4515,7 @@ static void get_table_engine_for_i_s(THD *thd, char *buf, TABLE_LIST *tl, char path[FN_REFLEN]; build_table_filename(path, sizeof(path) - 1, db->str, table->str, reg_ext, 0); - if (dd_frm_type(thd, path, &engine_name) == TABLE_TYPE_NORMAL) + if (dd_frm_type(thd, path, &engine_name, NULL, NULL) == TABLE_TYPE_NORMAL) tl->option= engine_name.str; } } @@ -4735,7 +4735,9 @@ static int fill_schema_table_names(THD *thd, TABLE_LIST *tables, CHARSET_INFO *cs= system_charset_info; handlerton *hton; bool is_sequence; - if (ha_table_exists(thd, db_name, table_name, &hton, &is_sequence)) + + if (ha_table_exists(thd, db_name, table_name, NULL, NULL, + &hton, &is_sequence)) { if (hton == view_pseudo_hton) table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f1390f232f1..ef92068c0d2 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1150,6 +1150,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, TABLE_LIST *table; char path[FN_REFLEN + 1]; LEX_CSTRING alias= null_clex_str; + LEX_CUSTRING version; + LEX_CSTRING partition_engine_name= {NULL, 0}; StringBuffer<160> unknown_tables(system_charset_info); DDL_LOG_STATE local_ddl_log_state; const char *comment_start; @@ -1157,9 +1159,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, int error= 0; uint32 comment_len; bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0; - bool non_tmp_table_deleted= 0; - bool is_drop_tmp_if_exists_added= 0; - bool was_view= 0, was_table= 0, log_if_exists= if_exists; + bool is_drop_tmp_if_exists_added= 0, non_tmp_table_deleted= 0; + bool log_if_exists= if_exists; const LEX_CSTRING *object_to_drop= ((drop_sequence) ? &SEQUENCE_clex_str : &TABLE_clex_str); @@ -1233,6 +1234,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool table_creation_was_logged= 0; bool wrong_drop_sequence= 0; bool table_dropped= 0, res; + bool is_temporary= 0; + bool was_view= 0, was_table= 0; const LEX_CSTRING db= table->db; const LEX_CSTRING table_name= table->table_name; LEX_CSTRING cpath= {0,0}; @@ -1299,6 +1302,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, table->table= 0; temporary_table_was_dropped= 1; } + is_temporary= 1; } if ((drop_temporary && if_exists) || temporary_table_was_dropped) @@ -1376,7 +1380,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, char engine_buf[NAME_CHAR_LEN + 1]; LEX_CSTRING engine= { engine_buf, 0 }; - table_type= dd_frm_type(thd, path, &engine); + table_type= dd_frm_type(thd, path, &engine, &partition_engine_name, + &version); if (table_type == TABLE_TYPE_NORMAL || table_type == TABLE_TYPE_SEQUENCE) { plugin_ref p= plugin_lock_by_name(thd, &engine, @@ -1458,8 +1463,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, &table_name); if (res) { - error= -1; - goto err; + error= -1; + goto err; } debug_crash_here("ddl_log_drop_before_delete_table"); @@ -1634,6 +1639,21 @@ report_error: db.str, (uint)db.length, table_name.str, (uint)table_name.length); mysql_audit_drop_table(thd, table); + if (!is_temporary) + { + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + ddl_log.query= { C_STRING_WITH_LEN("DROP") }; + if ((ddl_log.org_partitioned= (partition_engine_name.str != 0))) + ddl_log.org_storage_engine_name= partition_engine_name; + else + lex_string_set(&ddl_log.org_storage_engine_name, + ha_resolve_storage_engine_name(hton)); + ddl_log.org_database= table->db; + ddl_log.org_table= table->table_name; + ddl_log.org_table_id= version; + backup_log_ddl(&ddl_log); + } } if (!was_view) ddl_log_update_phase(ddl_log_state, DDL_DROP_PHASE_BINLOG); @@ -1696,27 +1716,27 @@ err: debug_crash_here("ddl_log_drop_before_binlog"); if (non_trans_tmp_table_deleted) { - /* Chop of the last comma */ - built_non_trans_tmp_query.chop(); - built_non_trans_tmp_query.append(generated_by_server); - error |= (thd->binlog_query(THD::STMT_QUERY_TYPE, - built_non_trans_tmp_query.ptr(), - built_non_trans_tmp_query.length(), - FALSE, FALSE, - is_drop_tmp_if_exists_added, - 0) > 0); + /* Chop of the last comma */ + built_non_trans_tmp_query.chop(); + built_non_trans_tmp_query.append(generated_by_server); + error |= (thd->binlog_query(THD::STMT_QUERY_TYPE, + built_non_trans_tmp_query.ptr(), + built_non_trans_tmp_query.length(), + FALSE, FALSE, + is_drop_tmp_if_exists_added, + 0) > 0); } if (trans_tmp_table_deleted) { - /* Chop of the last comma */ - built_trans_tmp_query.chop(); - built_trans_tmp_query.append(generated_by_server); - error |= (thd->binlog_query(THD::STMT_QUERY_TYPE, - built_trans_tmp_query.ptr(), - built_trans_tmp_query.length(), - TRUE, FALSE, - is_drop_tmp_if_exists_added, - 0) > 0); + /* Chop of the last comma */ + built_trans_tmp_query.chop(); + built_trans_tmp_query.append(generated_by_server); + error |= (thd->binlog_query(THD::STMT_QUERY_TYPE, + built_trans_tmp_query.ptr(), + built_trans_tmp_query.length(), + TRUE, FALSE, + is_drop_tmp_if_exists_added, + 0) > 0); } if (non_tmp_table_deleted) { @@ -1812,41 +1832,56 @@ end: bool log_drop_table(THD *thd, const LEX_CSTRING *db_name, const LEX_CSTRING *table_name, + const LEX_CSTRING *handler_name, + bool partitioned, + const LEX_CUSTRING *id, bool temporary_table) { char buff[NAME_LEN*2 + 80]; String query(buff, sizeof(buff), system_charset_info); - bool error; + bool error= 0; DBUG_ENTER("log_drop_table"); - if (!mysql_bin_log.is_open()) - DBUG_RETURN(0); - - query.length(0); - query.append(STRING_WITH_LEN("DROP ")); - if (temporary_table) - query.append(STRING_WITH_LEN("TEMPORARY ")); - query.append(STRING_WITH_LEN("TABLE IF EXISTS ")); - append_identifier(thd, &query, db_name); - query.append('.'); - append_identifier(thd, &query, table_name); - query.append(STRING_WITH_LEN("/* Generated to handle " - "failed CREATE OR REPLACE */")); + if (mysql_bin_log.is_open()) + { + query.length(0); + query.append(STRING_WITH_LEN("DROP ")); + if (temporary_table) + query.append(STRING_WITH_LEN("TEMPORARY ")); + query.append(STRING_WITH_LEN("TABLE IF EXISTS ")); + append_identifier(thd, &query, db_name); + query.append('.'); + append_identifier(thd, &query, table_name); + query.append(STRING_WITH_LEN("/* Generated to handle " + "failed CREATE OR REPLACE */")); - /* - In case of temporary tables we don't have to log the database name - in the binary log. We log this for non temporary tables, as the slave - may use a filter to ignore queries for a specific database. - */ - error= thd->binlog_query(THD::STMT_QUERY_TYPE, - query.ptr(), query.length(), - FALSE, FALSE, temporary_table, 0) > 0; + /* + In case of temporary tables we don't have to log the database name + in the binary log. We log this for non temporary tables, as the slave + may use a filter to ignore queries for a specific database. + */ + error= thd->binlog_query(THD::STMT_QUERY_TYPE, + query.ptr(), query.length(), + FALSE, FALSE, temporary_table, 0) > 0; + } + if (!temporary_table) + { + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + ddl_log.query= { C_STRING_WITH_LEN("DROP_AFTER_CREATE") }; + ddl_log.org_storage_engine_name= *handler_name; + ddl_log.org_partitioned= partitioned; + ddl_log.org_database= *db_name; + ddl_log.org_table= *table_name; + ddl_log.org_table_id= *id; + backup_log_ddl(&ddl_log); + } DBUG_RETURN(error); } /** - Quickly remove a table without bin logging + Quickly remove a table, without any logging @param thd Thread context. @param base The handlerton handle. @@ -4148,7 +4183,6 @@ int create_table_impl(THD *thd, int error= 1; bool frm_only= create_table_mode == C_ALTER_TABLE_FRM_ONLY; bool internal_tmp_table= create_table_mode == C_ALTER_TABLE || frm_only; - handlerton *exists_hton; DBUG_ENTER("create_table_impl"); DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d path: %s", db.str, table_name.str, internal_tmp_table, path.str)); @@ -4244,10 +4278,12 @@ int create_table_impl(THD *thd, goto err; } - if (!internal_tmp_table && ha_table_exists(thd, &db, &table_name, - &exists_hton)) + handlerton *db_type; + if (!internal_tmp_table && + ha_table_exists(thd, &db, &table_name, + &create_info->org_tabledef_version, NULL, &db_type)) { - if (ha_check_if_updates_are_ignored(thd, exists_hton, "CREATE")) + if (ha_check_if_updates_are_ignored(thd, db_type, "CREATE")) { /* Don't create table. CREATE will still be logged in binary log */ error= 0; @@ -4285,9 +4321,10 @@ int create_table_impl(THD *thd, thd->variables.option_bits|= OPTION_KEEP_LOG; thd->log_current_statement= 1; create_info->table_was_deleted= 1; + lex_string_set(&create_info->org_storage_engine_name, + ha_resolve_storage_engine_name(db_type)); DBUG_EXECUTE_IF("send_kill_after_delete", - thd->set_killed(KILL_QUERY); ); - + thd->set_killed(KILL_QUERY);); /* Restart statement transactions for the case of CREATE ... SELECT. */ @@ -4305,7 +4342,7 @@ int create_table_impl(THD *thd, */ /* Log CREATE IF NOT EXISTS on slave for distributed engines */ - if (thd->slave_thread && (exists_hton && exists_hton->flags & + if (thd->slave_thread && (db_type && db_type->flags & HTON_IGNORE_UPDATES)) thd->log_current_statement= 1; goto warn; @@ -4703,6 +4740,19 @@ err: result= 1; debug_crash_here("ddl_log_create_after_binlog"); thd->binlog_xid= 0; + + if (!create_info->tmp_table()) + { + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + ddl_log.query= { C_STRING_WITH_LEN("CREATE") }; + ddl_log.org_partitioned= (create_info->db_type == partition_hton); + ddl_log.org_storage_engine_name= create_info->new_storage_engine_name; + ddl_log.org_database= create_table->db; + ddl_log.org_table= create_table->table_name; + ddl_log.org_table_id= create_info->tabledef_version; + backup_log_ddl(&ddl_log); + } } ddl_log_complete(&ddl_log_state_rm); ddl_log_complete(&ddl_log_state_create); @@ -4853,6 +4903,7 @@ bool operator!=(const MYSQL_TIME &lhs, const MYSQL_TIME &rhs) @param old_name The old table name. @param new_db The new database name. @param new_name The new table name. + @param id Table version id (for ddl log) @param flags flags FN_FROM_IS_TMP old_name is temporary. FN_TO_IS_TMP new_name is temporary. @@ -4860,7 +4911,6 @@ bool operator!=(const MYSQL_TIME &lhs, const MYSQL_TIME &rhs) but only the table in the storage engine. NO_HA_TABLE Don't rename table in engine. NO_FK_CHECKS Don't check FK constraints during rename. - @return false OK @return true Error */ @@ -4868,7 +4918,7 @@ bool operator!=(const MYSQL_TIME &lhs, const MYSQL_TIME &rhs) bool mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db, const LEX_CSTRING *old_name, const LEX_CSTRING *new_db, - const LEX_CSTRING *new_name, uint flags) + const LEX_CSTRING *new_name, LEX_CUSTRING *id, uint flags) { THD *thd= current_thd; char from[FN_REFLEN], to[FN_REFLEN], lc_from[FN_REFLEN], lc_to[FN_REFLEN]; @@ -4877,6 +4927,7 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db, int error=0; ulonglong save_bits= thd->variables.option_bits; int length; + bool log_query= 0; DBUG_ENTER("mysql_rename_table"); DBUG_ASSERT(base); DBUG_PRINT("enter", ("old: '%s'.'%s' new: '%s'.'%s'", @@ -4914,7 +4965,8 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db, { if (rename_file_ext(from,to,reg_ext)) error= my_errno; - if (!(flags & NO_PAR_TABLE)) + log_query= true; + if (file && !(flags & NO_PAR_TABLE)) (void) file->ha_create_partitioning_metadata(to, from, CHF_RENAME_FLAG); } else if (!file || likely(!(error=file->ha_rename_table(from_base, to_base)))) @@ -4930,6 +4982,25 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db, file->ha_rename_table(to_base, from_base); // Restore old file name } } + else + log_query= true; + } + if (!error && log_query && !(flags & (FN_TO_IS_TMP | FN_FROM_IS_TMP))) + { + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + ddl_log.query= { C_STRING_WITH_LEN("RENAME") }; + ddl_log.org_partitioned= file->partition_engine(); + ddl_log.new_partitioned= ddl_log.org_partitioned; + lex_string_set(&ddl_log.org_storage_engine_name, file->real_table_type()); + ddl_log.org_database= *old_db; + ddl_log.org_table= *old_name; + ddl_log.org_table_id= *id; + ddl_log.new_storage_engine_name= ddl_log.org_storage_engine_name; + ddl_log.new_database= *new_db; + ddl_log.new_table= *new_name; + ddl_log.new_table_id= *id; + backup_log_ddl(&ddl_log); } delete file; @@ -4988,6 +5059,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, bool is_trans= FALSE; bool do_logging= FALSE; bool force_generated_create= false; + bool src_table_exists= FALSE; uint not_used; int create_res; DBUG_ENTER("mysql_create_like_table"); @@ -5021,6 +5093,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, { /* is_error() may be 0 if table existed and we generated a warning */ res= thd->is_error(); + src_table_exists= !res; goto err; } /* Ensure we don't try to create something from which we select from */ @@ -5261,7 +5334,6 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, if (write_bin_log(thd, TRUE, query.ptr(), query.length())) { res= 1; - do_logging= 0; goto err; } @@ -5320,6 +5392,9 @@ err: */ DBUG_ASSERT(ddl_log_state_rm.is_active()); log_drop_table(thd, &table->db, &table->table_name, + &create_info->org_storage_engine_name, + create_info->db_type == partition_hton, + &create_info->org_tabledef_version, create_info->tmp_table()); } else if (res != 2) // Table was not dropped @@ -5332,6 +5407,18 @@ err: thd->binlog_xid= 0; } + if (!res && !src_table_exists && !create_info->tmp_table()) + { + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + ddl_log.query= { C_STRING_WITH_LEN("CREATE") }; + ddl_log.org_storage_engine_name= local_create_info.new_storage_engine_name; + ddl_log.org_database= table->db; + ddl_log.org_table= table->table_name; + ddl_log.org_table_id= local_create_info.tabledef_version; + backup_log_ddl(&ddl_log); + } + ddl_log_complete(&ddl_log_state_rm); ddl_log_complete(&ddl_log_state_create); DBUG_RETURN(res != 0); @@ -7374,6 +7461,7 @@ static bool mysql_inplace_alter_table(THD *thd, */ if (mysql_rename_table(db_type, &alter_ctx->new_db, &alter_ctx->tmp_name, &alter_ctx->db, &alter_ctx->alias, + &alter_ctx->tmp_id, FN_FROM_IS_TMP | NO_HA_TABLE) || thd->is_error()) { @@ -7388,7 +7476,8 @@ static bool mysql_inplace_alter_table(THD *thd, DBUG_ASSERT(!tdc_share_is_cached(thd, alter_ctx->db.str, alter_ctx->table_name.str)); if (mysql_rename_table(db_type, &alter_ctx->db, &alter_ctx->table_name, - &alter_ctx->new_db, &alter_ctx->new_alias, 0)) + &alter_ctx->new_db, &alter_ctx->new_alias, + &alter_ctx->tmp_id, 0)) { /* If the rename fails we will still have a working table @@ -7411,6 +7500,7 @@ static bool mysql_inplace_alter_table(THD *thd, (void) mysql_rename_table(db_type, &alter_ctx->new_db, &alter_ctx->new_alias, &alter_ctx->db, &alter_ctx->alias, + &alter_ctx->id, NO_FK_CHECKS); ddl_log_disable_entry(ddl_log_state); DBUG_RETURN(true); @@ -8932,13 +9022,30 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list, TABLE *table= table_list->table; MDL_ticket *mdl_ticket= table->mdl_ticket; DDL_LOG_STATE ddl_log_state; + LEX_CSTRING storage_engine; + LEX_CUSTRING table_version; + uchar table_version_buff[MY_UUID_SIZE]; + char storage_engine_buff[NAME_LEN]; int error= 0; + bool partitioned; enum ha_extra_function extra_func= thd->locked_tables_mode ? HA_EXTRA_NOT_USED : HA_EXTRA_FORCE_REOPEN; DBUG_ENTER("simple_rename_or_index_change"); bzero(&ddl_log_state, sizeof(ddl_log_state)); + table_version.str= table_version_buff; + storage_engine.str= storage_engine_buff; + if ((table_version.length= table->s->tabledef_version.length)) + memcpy((char*) table_version.str, table->s->tabledef_version.str, + table_version.length); + partitioned= table->file->partition_engine(); + storage_engine.length= (strmake((char*) storage_engine.str, + table->file->real_table_type(), + sizeof(storage_engine_buff)-1) - + storage_engine.str); + + if (keys_onoff != Alter_info::LEAVE_AS_IS) { if (wait_while_table_is_used(thd, table, extra_func)) @@ -8952,6 +9059,18 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list, error= alter_table_manage_keys(table, table->file->indexes_are_disabled(), keys_onoff); + if (table->s->tmp_table == NO_TMP_TABLE) + { + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + ddl_log.query= { C_STRING_WITH_LEN("CHANGE_INDEX") }; + ddl_log.org_storage_engine_name= storage_engine; + ddl_log.org_partitioned= partitioned; + ddl_log.org_database= table_list->table->s->db; + ddl_log.org_table= table_list->table->s->table_name; + ddl_log.org_table_id= table_version; + backup_log_ddl(&ddl_log); + } } if (likely(!error) && alter_ctx->is_table_renamed()) @@ -8976,7 +9095,8 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list, &alter_ctx->db, &alter_ctx->table_name, &alter_ctx->new_db, &alter_ctx->new_alias); if (mysql_rename_table(old_db_type, &alter_ctx->db, &alter_ctx->table_name, - &alter_ctx->new_db, &alter_ctx->new_alias, 0)) + &alter_ctx->new_db, &alter_ctx->new_alias, + &table_version, 0)) error= -1; if (!error) ddl_log_update_phase(&ddl_log_state, DDL_RENAME_PHASE_TRIGGER); @@ -8992,6 +9112,7 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list, (void) mysql_rename_table(old_db_type, &alter_ctx->new_db, &alter_ctx->new_alias, &alter_ctx->db, &alter_ctx->table_name, + &table_version, NO_FK_CHECKS); ddl_log_disable_entry(&ddl_log_state); error= -1; @@ -9918,6 +10039,12 @@ do_continue:; if (unlikely(error)) goto err_cleanup; + /* Remember version id for temporary table */ + alter_ctx.tmp_id= create_info->tabledef_version; + + /* Remember that we have not created table in storage engine yet. */ + no_ha_table= true; + if (alter_info->algorithm(thd) != Alter_info::ALTER_TABLE_ALGORITHM_COPY) { Alter_inplace_info ha_alter_info(create_info, alter_info, @@ -9932,6 +10059,14 @@ do_continue:; if (fill_alter_inplace_info(thd, table, varchar, &ha_alter_info)) goto err_new_table_cleanup; + alter_ctx.tmp_storage_engine_name_partitioned= + table->file->partition_engine(); + alter_ctx.tmp_storage_engine_name.length= + (strmake((char*) alter_ctx.tmp_storage_engine_name.str, + table->file->real_table_type(), + sizeof(alter_ctx.tmp_storage_engine_buff)-1) - + alter_ctx.tmp_storage_engine_name.str); + /* We can ignore ALTER_COLUMN_ORDER and instead check ALTER_STORED_COLUMN_ORDER & ALTER_VIRTUAL_COLUMN_ORDER. This @@ -10272,6 +10407,15 @@ do_continue:; goto end_temporary; } + /* Remember storage engine name for the new table */ + alter_ctx.tmp_storage_engine_name_partitioned= + new_table->file->partition_engine(); + alter_ctx.tmp_storage_engine_name.length= + (strmake((char*) alter_ctx.tmp_storage_engine_name.str, + new_table->file->real_table_type(), + sizeof(alter_ctx.tmp_storage_engine_buff)-1) - + alter_ctx.tmp_storage_engine_name.str); + /* Check if file names for the engine are unique. If we change engine and file names are unique then we don't need to rename the original @@ -10353,7 +10497,7 @@ do_continue:; have to do the rename as the table names will not interfer. */ if (mysql_rename_table(old_db_type, &alter_ctx.db, &alter_ctx.table_name, - &alter_ctx.db, &backup_name, + &alter_ctx.db, &backup_name, &alter_ctx.id, FN_TO_IS_TMP | (engine_changed ? NO_HA_TABLE | NO_PAR_TABLE : 0))) { @@ -10386,6 +10530,7 @@ do_continue:; // Rename the new table to the correct name. if (mysql_rename_table(new_db_type, &alter_ctx.new_db, &alter_ctx.tmp_name, &alter_ctx.new_db, &alter_ctx.new_alias, + &alter_ctx.tmp_id, FN_FROM_IS_TMP)) { // Rename failed, delete the temporary table. @@ -10397,7 +10542,7 @@ do_continue:; { // Restore the backup of the original table to the old name. (void) mysql_rename_table(old_db_type, &alter_ctx.db, &backup_name, - &alter_ctx.db, &alter_ctx.alias, + &alter_ctx.db, &alter_ctx.alias, &alter_ctx.id, FN_FROM_IS_TMP | NO_FK_CHECKS | (engine_changed ? NO_HA_TABLE | NO_PAR_TABLE : 0)); @@ -10422,7 +10567,7 @@ do_continue:; &alter_ctx.new_db, &alter_ctx.new_alias, 0); // Restore the backup of the original table to the old name. (void) mysql_rename_table(old_db_type, &alter_ctx.db, &backup_name, - &alter_ctx.db, &alter_ctx.alias, + &alter_ctx.db, &alter_ctx.alias, &alter_ctx.id, FN_FROM_IS_TMP | NO_FK_CHECKS | (engine_changed ? NO_HA_TABLE | NO_PAR_TABLE : 0)); @@ -10506,6 +10651,24 @@ end_inplace: inplace_alter_table_committed= 0; } + if (!alter_ctx.tmp_table) + { + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + ddl_log.query= { C_STRING_WITH_LEN("ALTER") }; + ddl_log.org_storage_engine_name= alter_ctx.storage_engine_name; + ddl_log.org_partitioned= alter_ctx.storage_engine_partitioned; + ddl_log.org_database= alter_ctx.db; + ddl_log.org_table= alter_ctx.table_name; + ddl_log.org_table_id= alter_ctx.id; + ddl_log.new_storage_engine_name= alter_ctx.tmp_storage_engine_name; + ddl_log.new_partitioned= alter_ctx.tmp_storage_engine_name_partitioned; + ddl_log.new_database= alter_ctx.new_db; + ddl_log.new_table= alter_ctx.new_alias; + ddl_log.new_table_id= alter_ctx.tmp_id; + backup_log_ddl(&ddl_log); + } + table_list->table= NULL; // For query cache query_cache_invalidate3(thd, table_list, false); @@ -11228,6 +11391,8 @@ err: @retval true Engine not available/supported, error has been reported. @retval false Engine available/supported. + create_info->db_type & create_info->new_storage_engine_name + are updated. */ bool check_engine(THD *thd, const char *db_name, @@ -11283,6 +11448,8 @@ bool check_engine(THD *thd, const char *db_name, *new_engine= myisam_hton; } + lex_string_set(&create_info->new_storage_engine_name, + ha_resolve_storage_engine_name(*new_engine)); DBUG_RETURN(false); } diff --git a/sql/sql_table.h b/sql/sql_table.h index 0c694eb730c..81894999aac 100644 --- a/sql/sql_table.h +++ b/sql/sql_table.h @@ -171,8 +171,8 @@ bool mysql_create_like_table(THD *thd, TABLE_LIST *table, Table_specification_st *create_info); bool mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db, const LEX_CSTRING *old_name, const LEX_CSTRING *new_db, - const LEX_CSTRING *new_name, uint flags); - + const LEX_CSTRING *new_name, LEX_CUSTRING *id, + uint flags); bool mysql_backup_table(THD* thd, TABLE_LIST* table_list); bool mysql_restore_table(THD* thd, TABLE_LIST* table_list); @@ -189,7 +189,9 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool drop_sequence, bool dont_log_query, bool dont_free_locks); bool log_drop_table(THD *thd, const LEX_CSTRING *db_name, - const LEX_CSTRING *table_name, bool temporary_table); + const LEX_CSTRING *table_name, const LEX_CSTRING *handler, + bool partitioned, const LEX_CUSTRING *id, + bool temporary_table); bool quick_rm_table(THD *thd, handlerton *base, const LEX_CSTRING *db, const LEX_CSTRING *table_name, uint flags, const char *table_path=0); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index c5e112bf8ae..4f6d5c6a1dd 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -673,6 +673,7 @@ end: if (!result && action_executed) { ulonglong save_option_bits= thd->variables.option_bits; + backup_log_info ddl_log; debug_crash_here("ddl_log_drop_before_binlog"); if (add_if_exists_to_binlog) @@ -684,6 +685,16 @@ end: thd->binlog_xid= 0; thd->variables.option_bits= save_option_bits; debug_crash_here("ddl_log_drop_after_binlog"); + + bzero(&ddl_log, sizeof(ddl_log)); + if (create) + ddl_log.query= { C_STRING_WITH_LEN("CREATE") }; + else + ddl_log.query= { C_STRING_WITH_LEN("DROP") }; + ddl_log.org_storage_engine_name= { C_STRING_WITH_LEN("TRIGGER") }; + ddl_log.org_database= thd->lex->spname->m_db; + ddl_log.org_table= thd->lex->spname->m_name; + backup_log_ddl(&ddl_log); } ddl_log_complete(&ddl_log_state); debug_crash_here("ddl_log_drop_before_delete_tmp"); diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 6ab644eb3ce..0f88a159d63 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -192,6 +192,7 @@ Sql_cmd_truncate_table::handler_truncate(THD *thd, TABLE_LIST *table_ref, { int error= 0; uint flags= 0; + TABLE *table; DBUG_ENTER("Sql_cmd_truncate_table::handler_truncate"); /* @@ -235,10 +236,26 @@ Sql_cmd_truncate_table::handler_truncate(THD *thd, TABLE_LIST *table_ref, if (fk_truncate_illegal_if_parent(thd, table_ref->table)) DBUG_RETURN(TRUNCATE_FAILED_SKIP_BINLOG); - error= table_ref->table->file->ha_truncate(); + table= table_ref->table; + error= table->file->ha_truncate(); + + if (!is_tmp_table && !error) + { + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + ddl_log.query= { C_STRING_WITH_LEN("TRUNCATE") }; + ddl_log.org_partitioned= table->file->partition_engine(); + lex_string_set(&ddl_log.org_storage_engine_name, + table->file->real_table_type()); + ddl_log.org_database= table->s->db; + ddl_log.org_table= table->s->table_name; + ddl_log.org_table_id= table->s->tabledef_version; + backup_log_ddl(&ddl_log); + } + if (unlikely(error)) { - table_ref->table->file->print_error(error, MYF(0)); + table->file->print_error(error, MYF(0)); /* If truncate method is not implemented then we don't binlog the statement. If truncation has failed in a transactional engine then also @@ -246,7 +263,7 @@ Sql_cmd_truncate_table::handler_truncate(THD *thd, TABLE_LIST *table_ref, inspite of errors. */ if (error == HA_ERR_WRONG_COMMAND || - table_ref->table->file->has_transactions_and_rollback()) + table->file->has_transactions_and_rollback()) DBUG_RETURN(TRUNCATE_FAILED_SKIP_BINLOG); else DBUG_RETURN(TRUNCATE_FAILED_BUT_BINLOG); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 61a2c43a43f..3fc55552f6b 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -733,6 +733,16 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, thd->binlog_xid= 0; debug_crash_here("ddl_log_create_after_binlog"); } + if (!res) + { + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + ddl_log.query= { C_STRING_WITH_LEN("CREATE") }; + ddl_log.org_storage_engine_name= { C_STRING_WITH_LEN("VIEW") }; + ddl_log.org_database= view->db; + ddl_log.org_table= view->table_name; + backup_log_ddl(&ddl_log); + } if (mode != VIEW_CREATE_NEW) query_cache_invalidate3(thd, view, 0); @@ -1943,6 +1953,14 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) tdc_remove_table(thd, view->db.str, view->table_name.str); query_cache_invalidate3(thd, view, 0); sp_cache_invalidate(); + + backup_log_info ddl_log; + bzero(&ddl_log, sizeof(ddl_log)); + ddl_log.query= { C_STRING_WITH_LEN("DROP") }; + ddl_log.org_storage_engine_name= { C_STRING_WITH_LEN("VIEW") }; + ddl_log.org_database= view->db; + ddl_log.org_table= view->table_name; + backup_log_ddl(&ddl_log); } something_wrong= (delete_error || diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 381a84cebf0..e13302d9750 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -2314,6 +2314,7 @@ int ha_maria::end_bulk_insert() BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR))) first_error= first_error ? first_error : error; bulk_insert_single_undo= BULK_INSERT_NONE; // Safety + log_not_redoable_operation("BULK_INSERT"); } can_enable_indexes= 0; DBUG_RETURN(first_error); diff --git a/storage/rocksdb/rdb_datadic.cc b/storage/rocksdb/rdb_datadic.cc index f52d3cee048..6c3e99be55e 100644 --- a/storage/rocksdb/rdb_datadic.cc +++ b/storage/rocksdb/rdb_datadic.cc @@ -3793,7 +3793,8 @@ bool Rdb_validate_tbls::check_frm_file(const std::string &fullpath, */ char eng_type_buf[NAME_CHAR_LEN+1]; LEX_CSTRING eng_type_str = {eng_type_buf, 0}; - enum Table_type type = dd_frm_type(nullptr, fullfilename.c_ptr(), &eng_type_str); + enum Table_type type = dd_frm_type(nullptr, fullfilename.c_ptr(), + &eng_type_str, nullptr, nullptr); if (type == TABLE_TYPE_UNKNOWN) { // NO_LINT_DEBUG sql_print_warning("RocksDB: Failed to open/read .from file: %s", |