--source include/not_embedded.inc
--source include/have_debug.inc
--source include/have_debug_sync.inc

# Check that BACKUP/RESTORE commands correctly report errors 
# and are updated in backup history and progress logs

disable_query_log;
call mtr.add_suppression("Backup:");
call mtr.add_suppression("Restore:");
call mtr.add_suppression("Can't open the online backup progress tables");
call mtr.add_suppression("Can't open the backup logs as tables");
enable_query_log;

--disable_warnings
DROP DATABASE IF EXISTS adb;
DROP DATABASE IF EXISTS bdb;

let $MYSQLD_DATADIR= `select @@datadir`;

--error 0,1
--remove_file $MYSQLD_DATADIR/test.bak
--enable_warnings

PURGE BACKUP LOGS;
--echo # non-existent backup archive
--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR/
--replace_regex /Errcode: [0-9]+/Errcode: #/
--error 29
RESTORE FROM 'test.bak';

--echo verify backup history and progress logs:
SELECT backup_state,operation, backup_file, command FROM mysql.backup_history;
SELECT notes FROM mysql.backup_progress;

CREATE DATABASE adb;
CREATE DATABASE bdb;
CREATE TABLE bdb.t1(a int) ENGINE=MEMORY;

PURGE BACKUP LOGS;
--echo # invalid location
--error ER_BAD_PATH
eval BACKUP DATABASE adb TO '' $compression;
--replace_column 2 #
SHOW WARNINGS;

--echo verify backup history and progress logs:
SELECT backup_state,operation, backup_file, command FROM mysql.backup_history;
SELECT notes FROM mysql.backup_progress;

# Backup database to invalid location

PURGE BACKUP LOGS;
--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR/
--replace_regex /Errcode: [0-9]+/Errcode: #/
--error 1
eval BACKUP DATABASE adb TO 'invalid/location' $compression;
--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR/
--replace_regex /Errcode: [0-9]+/Errcode: #/
--replace_column 2 #
SHOW WARNINGS;

--echo verify backup history and progress logs:
SELECT backup_state,operation, backup_file, command FROM mysql.backup_history;
SELECT notes FROM mysql.backup_progress;

--echo # don't overwrite existing files
--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR/
--replace_regex /Errcode: [0-9]+/Errcode: #/
--error 1
eval BACKUP DATABASE adb TO "bdb/t1.frm" $compression;
--replace_column 2 #
--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR/
--replace_regex /Errcode: [0-9]+/Errcode: #/
SHOW WARNINGS;

--replace_column 1 #
eval BACKUP DATABASE adb TO "test.bak" $compression;
# There should be no warnings after a successful backup
SHOW WARNINGS;

PURGE BACKUP LOGS;
--echo # don't overwrite existing backup image
--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR/
--replace_regex /Errcode: [0-9]+/Errcode: #/
--error 1
eval BACKUP DATABASE adb TO "test.bak" $compression;
--replace_column 2 #
--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR/
--replace_regex /Errcode: [0-9]+/Errcode: #/
SHOW WARNINGS;

--echo verify backup history and progress logs for backup_state.
SELECT backup_state,operation, backup_file, command FROM mysql.backup_history;
SELECT notes FROM mysql.backup_progress;

--remove_file $MYSQLD_DATADIR/test.bak

--echo # non-existent database
--disable_warnings
DROP DATABASE IF EXISTS foo;
DROP DATABASE IF EXISTS bar;
--enable_warnings

-- error ER_BAD_DB_ERROR
eval BACKUP DATABASE foo TO 'test.bak' $compression;
--replace_column 2 #
SHOW WARNINGS;

PURGE BACKUP LOGS;
-- error ER_BAD_DB_ERROR
eval BACKUP DATABASE test,foo,bdb,bar TO 'test.bak' $compression;
--replace_column 2 #
SHOW WARNINGS;

--echo verify backup history and progress logs:
SELECT backup_state,operation,backup_file, command FROM mysql.backup_history;
SELECT notes FROM mysql.backup_progress;

PURGE BACKUP LOGS;

CREATE DATABASE foo;
CREATE DATABASE bar;

--echo # 
--echo # repeated database
--echo # 
-- error ER_NONUNIQ_DB
eval BACKUP DATABASE foo, bar, foo TO 'test.bak' $compression;
--replace_column 2 #
SHOW WARNINGS;

--echo verify backup history and progress logs for backup_state.
SELECT backup_state,operation, backup_file, command FROM mysql.backup_history;
SELECT notes FROM mysql.backup_progress;

DROP DATABASE foo;
DROP DATABASE bar;

PURGE BACKUP LOGS;

# Test that BACKUP/RESTORE statements are disable inside stored routines,
# triggers and events.

use adb;

create table t1 (a int);

--error ER_SP_BADSTATEMENT
create procedure p1() backup database test to 'test.bak';
--error ER_SP_BADSTATEMENT
create procedure p1() restore from 'test.bak';

--error ER_SP_BADSTATEMENT
create function f1() returns int backup database test to 'test.bak';
--error ER_SP_BADSTATEMENT
create function f1() returns int restore from 'test.bak';

--error ER_SP_BADSTATEMENT
create trigger tr1 before insert on t1 
for each row backup database test to 'test.bak';
--error ER_SP_BADSTATEMENT
create trigger tr1 before insert on t1 
for each row restore from 'test.bak';

--error ER_SP_BADSTATEMENT
create event ev1 on schedule every 1 day 
do backup database test to 'test.bak';
--error ER_SP_BADSTATEMENT
create event ev1 on schedule every 1 day 
do restore from 'test.bak';

# TODO: fix error injection and test more errors

DROP DATABASE adb;
DROP DATABASE bdb;

# Note: the file should be removed - if it is not, the following command
# will fail and we will be warned that something is wrong with the test
--error 1
--remove_file $MYSQLD_DATADIR/test.bak

# Check error conditions for including mysql and information_schema in
# the list of databases.
#
# There are several scenarios:
# 1) BACKUP DATABASE mysql TO 't.bak'
#    Error: Nothing to backup
# 2) BACKUP DATABASE information_schema TO 't.bak'
#    Error: Nothing to backup
# 3) BACKUP DATABASE mysql, information_schema TO 't.bak'
#    Error: Nothing to backup
# 4) BACKUP DATABASE mysql, test TO 't.bak'
#    Warning: Backup cannot include database 'mysql'
# 5) BACKUP DATABASE information_schema, test TO 't.bak'
#    Warning: Backup cannot include database 'information_schema'
# 6) BACKUP DATABASE mysql, information_schema, test TO 't.bak'
#    Warning: Backup cannot include database 'mysql'
#    Warning: Backup cannot include database 'mysql'

# Scenario 1
PURGE BACKUP LOGS;
--echo Backup of mysql, information_schema scenario 1
--error ER_BACKUP_CANNOT_INCLUDE_DB
eval BACKUP DATABASE mysql TO 't.bak' $compression;
--replace_column 2 #
SHOW WARNINGS;

--echo verify backup history and progress logs:
SELECT backup_state,operation, backup_file, command FROM mysql.backup_history;
SELECT notes FROM mysql.backup_progress;

--error 0, 1
--remove_file $MYSQLD_DATADIR/t.bak

# Scenario 2
PURGE BACKUP LOGS;
--echo Backup of mysql, information_schema scenario 2
--error ER_BACKUP_CANNOT_INCLUDE_DB
eval BACKUP DATABASE information_schema TO 't.bak' $compression;
--replace_column 2 #
SHOW WARNINGS;

--echo verify backup history and progress logs:
SELECT backup_state,operation, backup_file,command FROM mysql.backup_history;
SELECT  notes FROM mysql.backup_progress;

--error 0, 1
--remove_file $MYSQLD_DATADIR/t.bak

# Scenario 3
PURGE BACKUP LOGS;
--echo Backup of mysql, information_schema scenario 3
--error ER_BACKUP_CANNOT_INCLUDE_DB
eval BACKUP DATABASE mysql, information_schema TO 't.bak' $compression;
--replace_column 2 #
SHOW WARNINGS;

--echo verify backup history and progress logs:
SELECT backup_state,operation, backup_file,command FROM mysql.backup_history;
SELECT notes FROM mysql.backup_progress;

--error 0, 1
--remove_file $MYSQLD_DATADIR/t.bak

# Scenario 4
PURGE BACKUP LOGS;
--echo Backup of mysql, information_schema scenario 4
--error ER_BACKUP_CANNOT_INCLUDE_DB
eval BACKUP DATABASE mysql, test TO 't.bak' $compression;
--replace_column 2 #
SHOW WARNINGS;

--echo verify backup history and progress logs:
SELECT backup_state,operation, backup_file,command FROM mysql.backup_history;
SELECT notes FROM mysql.backup_progress;

--error 0, 1
--remove_file $MYSQLD_DATADIR/t.bak

# Scenario 5
PURGE BACKUP LOGS;
--echo Backup of mysql, information_schema scenario 5
--error ER_BACKUP_CANNOT_INCLUDE_DB
eval BACKUP DATABASE information_schema, test TO 't.bak' $compression;
--replace_column 2 #
SHOW WARNINGS;

--echo verify backup history and progress logs:
SELECT backup_state,operation, backup_file,command FROM mysql.backup_history;
SELECT notes FROM mysql.backup_progress;

--error 0, 1
--remove_file $MYSQLD_DATADIR/t.bak

# Scenario 6
PURGE BACKUP LOGS;
--echo Backup of mysql, information_schema scenario 6
--error ER_BACKUP_CANNOT_INCLUDE_DB
eval BACKUP DATABASE mysql, information_schema, test TO 't.bak' $compression;
--replace_column 2 #
SHOW WARNINGS;

--echo verify backup history and progress logs:
SELECT backup_state,operation, backup_file, command FROM mysql.backup_history;
SELECT notes FROM mysql.backup_progress;

--error 0, 1
--remove_file $MYSQLD_DATADIR/t.bak
#
# BUG#33352 - Test for presence of online backup progress tables;
#

# Make backup copies of the tables first.
--echo Making copies of progress tables.
CREATE TABLE IF NOT EXISTS test.ob_copy LIKE mysql.backup_history;
CREATE TABLE IF NOT EXISTS test.obp_copy LIKE mysql.backup_progress;

# Create a database and put some data in it.
CREATE DATABASE test_ob_error;
CREATE TABLE test_ob_error.t1 (col_a int);
INSERT INTO test_ob_error.t1 VALUES (1), (2), (3), (4), (5);

# Backup the database to ensure db is ok.
--echo Backup the database;
--replace_column 1 #
eval BACKUP DATABASE test_ob_error TO 'ob_err.bak' $compression;
--remove_file $MYSQLD_DATADIR/ob_err.bak

# Drop one of the tables and try a backup.
DROP TABLE mysql.backup_history;

# Try to backup the database (should be error).
--echo Backup the database;
--error ER_BACKUP_PROGRESS_TABLES
eval BACKUP DATABASE test_ob_error TO 'ob_err.bak' $compression;
--error 0,1
--remove_file $MYSQLD_DATADIR/ob_err.bak
--replace_column 2 #
SHOW WARNINGS;

# Restore the table
--echo Restoring the table
CREATE TABLE mysql.backup_history LIKE test.ob_copy;
DROP TABLE test.ob_copy;

# Drop one of the tables and try a backup.
DROP TABLE mysql.backup_progress;

# Try to backup the database (should be error).
--echo Backup the database;
--error ER_BACKUP_PROGRESS_TABLES
eval BACKUP DATABASE test_ob_error TO 'ob_err.bak' $compression;

--error 0,1
--remove_file $MYSQLD_DATADIR/ob_err.bak
--replace_column 2 #
SHOW WARNINGS;

# Restore the table
--echo Restoring the table
CREATE TABLE mysql.backup_progress LIKE test.obp_copy;
DROP TABLE test.obp_copy;

DROP DATABASE test_ob_error;

--echo
--echo Bug#38624
--echo Test that backup fails with error if database files are removed 
--echo after backup starts

SET DEBUG_SYNC= 'reset';

connect (con1,localhost,root,,);
connect (con2,localhost,root,,);

connection con1;

--disable_warnings
DROP DATABASE IF EXISTS db1;

CREATE DATABASE db1;

PURGE BACKUP LOGS;
connection con2;

--echo start backup but stop just before adding metadata to backup image
SET DEBUG_SYNC= 'backup_before_write_preamble SIGNAL running WAIT_FOR db_will_fail';

send BACKUP DATABASE db1 TO 'bup_db1.bak';

connection con1;

SET DEBUG_SYNC='now WAIT_FOR running';

--echo delete database files so that check_db_dir_exists will fail in 
--echo si_objects.cc @ DatabaseObj::do_serialize

--remove_file $MYSQLD_DATADIR/db1/db.opt
--rmdir $MYSQLD_DATADIR/db1

SET DEBUG_SYNC='now SIGNAL db_will_fail';

connection con2;
--echo Database has been deleted, backup will fail
--error ER_BACKUP_GET_META_DB
reap;

--echo
--echo Test that backup fails with error if a table used by 
--echo a trigger cannot be opened

SET DEBUG_SYNC= 'reset';

connection con1;

--echo verify backup history and progress logs:
SELECT backup_state,operation, backup_file, command FROM mysql.backup_history;
SELECT notes FROM mysql.backup_progress;

--disable_warnings
DROP DATABASE IF EXISTS db1;

CREATE DATABASE db1;
CREATE TABLE db1.t1 (i int);
CREATE TABLE db1.t2 (v varchar (20));

DELIMITER ||;
CREATE TRIGGER db1.trg AFTER INSERT ON db1.t1 FOR EACH ROW
BEGIN
  INSERT INTO db1.t2(v) VALUES ('Test trigger fired');   
END;||
DELIMITER ;||

SET DEBUG_SYNC= 'reset';

--echo Setting debug point that will make backup fail when adding the
--echo trigger metadata
PURGE BACKUP LOGS;
SET SESSION DEBUG='+d,backup_fail_add_trigger';
--error ER_BACKUP_GET_META_TRIGGER
eval BACKUP DATABASE db1 TO 'bup_db1.bak' $compression;

--echo verify backup history and progress logs:
SELECT backup_state,operation, backup_file,command FROM mysql.backup_history;
SELECT notes FROM mysql.backup_progress;

SET DEBUG_SYNC= 'reset';
DROP DATABASE db1;

--echo
--echo Done testing for Bug#38624

--echo
--echo Testing RESTORE ... OVERWRITE functionality
--echo See bug#34579
--echo

--source include/not_embedded.inc

--echo Initialize
CREATE DATABASE db1;
USE db1;
CREATE TABLE table1 (text VARCHAR(20));
INSERT INTO table1 VALUES ('Inserted before');

--echo
--echo Backup database
--replace_column 1 #
eval BACKUP DATABASE db1 TO 'overwrite.bak' $compression;

--echo
--echo Insert more data and display
INSERT INTO table1 VALUES ('Inserted after');
SELECT * FROM table1;

--echo
--echo Restore without OVERWRITE flag; will fail
--error ER_RESTORE_DB_EXISTS
RESTORE FROM 'overwrite.bak';

--echo
--echo Restore with OVERWRITE flag; will succeed
--replace_column 1 #
RESTORE FROM 'overwrite.bak' OVERWRITE;

--echo
--echo Show that inserted value 2 is not there
SELECT * FROM table1;

DROP DATABASE db1;

--echo
--echo Restore after deleting db; will succeed
--replace_column 1 #
RESTORE FROM 'overwrite.bak';
--echo
--echo Show that inserted value 2 is not there
SELECT * FROM table1;
--remove_file $MYSQLD_DATADIR/overwrite.bak

--echo #
--echo # Test error handling by backup code when injecting commit blocker error.
--echo #

SET SESSION DEBUG='+d,backup_grl_fail';
--error ER_BACKUP_SYNCHRONIZE
eval BACKUP DATABASE db1 TO 'overwrite1.bak' $compression;
SET SESSION DEBUG='-d';

--echo
PURGE BACKUP LOGS;
SET SESSION DEBUG='+d,backup_grl_block_commit_fail';
--error ER_BACKUP_SYNCHRONIZE
eval BACKUP DATABASE db1 TO 'overwrite1.bak' $compression;
SET SESSION DEBUG='-d';

--echo verify backup history and progress logs:
SELECT backup_state,operation, backup_file,command FROM mysql.backup_history;
SELECT notes FROM mysql.backup_progress;

--echo #
--echo # Test that BACKUP and RESTORE clears warning stack
--echo #

--replace_column 1 #
eval BACKUP DATABASE db1 TO 'test.bak' $compression;

--echo # Generate warning - test.bak cannot be overwritten
--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR/
--replace_regex /Errcode: [0-9]+/Errcode: #/
--error 1
eval BACKUP DATABASE db1 TO 'test.bak' $compression;
--replace_column 2 #
--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR/
--replace_regex /Errcode: [0-9]+/Errcode: #/
SHOW WARNINGS;
--echo

--echo # Test that there are no warnings after successful BACKUP
--replace_column 1 #
eval BACKUP DATABASE db1 TO 'newtest.bak' $compression;
--replace_column 2 #
SHOW WARNINGS;
--echo

PURGE BACKUP LOGS;
--echo # Generate warning - test.bak cannot be overwritten
--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR/
--replace_regex /Errcode: [0-9]+/Errcode: #/
--error 1
eval BACKUP DATABASE db1 TO 'test.bak' $compression;
--replace_column 2 #
--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR/
--replace_regex /Errcode: [0-9]+/Errcode: #/
SHOW WARNINGS;
--echo

--echo verify backup history and progress logs:
SELECT backup_state,operation, backup_file,command FROM mysql.backup_history;
SELECT notes FROM mysql.backup_progress;

--echo # Test that there are no warnings after successful RESTORE
--replace_column 1 #
RESTORE FROM 'newtest.bak' OVERWRITE;
--replace_column 2 #
SHOW WARNINGS;

--remove_file $MYSQLD_DATADIR/test.bak
--remove_file $MYSQLD_DATADIR/newtest.bak

--echo

--echo #
--echo # Test error handling by injecting errors into RESTORE
--echo #

--echo # Make backup image with objects necessary for error injection

# A MyISAM table (table1) already exists in db1

# A table that uses default backup driver is required
CREATE TABLE table2 (i int NOT NULL) ENGINE=CSV;
INSERT INTO table2 values (1),(2);

# A trigger is required
DELIMITER ||;
CREATE TRIGGER db1.trg AFTER INSERT ON db1.table2 FOR EACH ROW
BEGIN
  INSERT INTO db1.table1(v) VALUES ('Test trigger fired');
END;||
DELIMITER ;||

--replace_column 1 #
eval BACKUP DATABASE db1 TO 'errorinject.bak' $compression;

DROP DATABASE db1;

--echo #
--echo # Backup image created. Start RESTORE with error injection

--echo #
--echo # Error injection in RESTORE: Read header
--echo #
SET SESSION DEBUG='+d,restore_read_header';
--error ER_BACKUP_READ_HEADER
RESTORE FROM 'errorinject.bak';
SET SESSION DEBUG='-d';

--echo #
--echo # Error injection in RESTORE: Get next chunk;
--echo # Called from prepare_for_restore, after read_header
--echo #
SET SESSION DEBUG='+d,restore_prepare_next_chunk_1';
--error ER_BACKUP_NEXT_CHUNK
RESTORE FROM 'errorinject.bak';
SET SESSION DEBUG='-d';

--echo #
--echo # Error injection in RESTORE: Read catalog
--echo #
SET SESSION DEBUG='+d,restore_read_catalog';
--error ER_BACKUP_READ_HEADER
RESTORE FROM 'errorinject.bak';
SET SESSION DEBUG='-d';

--echo #
--echo # Error injection in RESTORE: Get next chunk;
--echo # Called from prepare_for_restore, after read_catalog
--echo #
SET SESSION DEBUG='+d,restore_prepare_next_chunk_2';
--error ER_BACKUP_NEXT_CHUNK
RESTORE FROM 'errorinject.bak';
SET SESSION DEBUG='-d';

--echo #
--echo # Error injection in RESTORE: Read metadata from stream
--echo #
SET SESSION DEBUG='+d,restore_read_meta_data';
--error ER_BACKUP_READ_META
RESTORE FROM 'errorinject.bak';
SET SESSION DEBUG='-d';

# Database partially created by the failing restore
DROP DATABASE db1;

--echo #
--echo # Error injection in RESTORE: Get next chunk;
--echo # Called from do_restore
--echo #
SET SESSION DEBUG='+d,restore_stream_next_chunk';
--error ER_BACKUP_NEXT_CHUNK
RESTORE FROM 'errorinject.bak';
SET SESSION DEBUG='-d';

# Database partially created by the failing restore
DROP DATABASE db1;

--echo #
--echo # Error injection in RESTORE: Lock tables
--echo #
SET SESSION DEBUG='+d,restore_lock_tables_for_restore';
--error ER_BACKUP_OPEN_TABLES
RESTORE FROM 'errorinject.bak';
SET SESSION DEBUG='-d';

# Database partially created by the failing restore
DROP DATABASE db1;

--echo #
--echo # Error injection in RESTORE: Restore table data
--echo #
SET SESSION DEBUG='+d,restore_tbl_data_read';
--error ER_BACKUP_READ_DATA
RESTORE FROM 'errorinject.bak';
SET SESSION DEBUG='-d';

# Database partially created by the failing restore
DROP DATABASE db1;

--echo #
--echo # Error injection in RESTORE: Send data (default driver)
--echo #
SET SESSION DEBUG='+d,restore_default_send_data';
--error ER_BACKUP_SEND_DATA
RESTORE FROM 'errorinject.bak';
SET SESSION DEBUG='-d';

DROP DATABASE db1;

--echo #
--echo # Error injection in RESTORE: Restore trigger
--echo #
SET SESSION DEBUG='+d,restore_trigger';
--error ER_BACKUP_CANT_RESTORE_TRIGGER
RESTORE FROM 'errorinject.bak';
SET SESSION DEBUG='-d';

DROP DATABASE db1;

--echo #
--echo # Error injection in RESTORE: Read summary
--echo #
SET SESSION DEBUG='+d,restore_read_summary';
--error ER_BACKUP_READ_SUMMARY
RESTORE FROM 'errorinject.bak';
SET SESSION DEBUG='-d';


--echo #
--echo # Test error handling by injecting errors into BACKUP
--echo #

--echo #
--echo # Error injection in si_object.cc:get_database_stub
--echo #
SET SESSION DEBUG='+d,siobj_get_db_stub';
--error ER_BACKUP_CATALOG_ADD_DB
BACKUP DATABASE db1 TO 'failed1.bak';
SET SESSION DEBUG='-d';

--echo #
--echo # Cleanup
--echo #

DROP DATABASE db1;

--remove_file $MYSQLD_DATADIR/errorinject.bak



