diff options
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", |