From fb9da7f7518bc310aff4eac215e046d63acded62 Mon Sep 17 00:00:00 2001 From: mariadb-DebarunBanerjee Date: Tue, 23 Jan 2024 20:43:39 +0530 Subject: [PATCH 1/7] MDEV-33023 Crash in mariadb-backup --prepare --export after --prepare mariadb-backup with --prepare option could result in empty redo log file. When --prepare is followed by --prepare --export, we exit early in srv_start function without opening the ibdata1 tablespace. Later while trying to read rollback segment header page, we hit the debug assert which claims that the system space should already have been opened. There are two assert cases here. Issue-1: System tablespace object is not there in fil space hash i.e. srv_sys_space.open_or_create() is not called. Issue-2: The system tablespace data file ibdata1 is not opened i.e. fil_system.sys_space->open() is not called. Fix: For empty redo log and restore operation, open system tablespace before returning. --- mysql-test/suite/mariabackup/partial.result | 8 +++++ mysql-test/suite/mariabackup/partial.test | 19 +++++++++++ storage/innobase/srv/srv0start.cc | 37 ++++++++++++++++++--- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/mariabackup/partial.result b/mysql-test/suite/mariabackup/partial.result index 8ccc8f6a6c7..cefda922868 100644 --- a/mysql-test/suite/mariabackup/partial.result +++ b/mysql-test/suite/mariabackup/partial.result @@ -14,6 +14,14 @@ ALTER TABLE t1 IMPORT TABLESPACE; SELECT * FROM t1; i 1 +# MDEV-33023 Crash in mariadb-backup --prepare --export after --prepare +t1.cfg +t21.cfg +ALTER TABLE t1 DISCARD TABLESPACE; +ALTER TABLE t1 IMPORT TABLESPACE; +SELECT * FROM t1; +i +1 DROP TABLE t1; DROP TABLE t2; DROP TABLE t21; diff --git a/mysql-test/suite/mariabackup/partial.test b/mysql-test/suite/mariabackup/partial.test index 53388b1947f..2a744a7f729 100644 --- a/mysql-test/suite/mariabackup/partial.test +++ b/mysql-test/suite/mariabackup/partial.test @@ -54,6 +54,25 @@ copy_file $targetdir/test/t1.cfg $MYSQLD_DATADIR/test/t1.cfg; ALTER TABLE t1 IMPORT TABLESPACE; SELECT * FROM t1; + +--echo # MDEV-33023 Crash in mariadb-backup --prepare --export after --prepare +--disable_result_log +exec $XTRABACKUP --defaults-file=$server_cnf --defaults-group-suffix=.1 --prepare --target-dir=$targetdir; +exec $XTRABACKUP --defaults-file=$server_cnf --defaults-group-suffix=.1 --prepare --export --target-dir=$targetdir; +--enable_result_log + +list_files $targetdir/test *.cfg; +# There must not be binary logs created on --prepare step +list_files $targetdir/ mysqld-bin.*; + +let $MYSQLD_DATADIR= `select @@datadir`; +ALTER TABLE t1 DISCARD TABLESPACE; +copy_file $targetdir/test/t1.ibd $MYSQLD_DATADIR/test/t1.ibd; +copy_file $targetdir/test/t1.cfg $MYSQLD_DATADIR/test/t1.cfg; +ALTER TABLE t1 IMPORT TABLESPACE; + +SELECT * FROM t1; + DROP TABLE t1; DROP TABLE t2; DROP TABLE t21; diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 0760b8ca5fd..4382a318367 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1277,6 +1277,36 @@ dberr_t srv_start(bool create_new_db) return srv_init_abort(DB_ERROR); } + /* Open system tablespace and undo spaces. It is a special case for + restore with empty redo log file. We support restore in such case and + proceed after opening system tablespaces. */ + ulint sum_of_new_sizes; + + auto open_system_spaces = [&]() { + ut_ad(!create_new_db); + ut_ad(srv_operation == SRV_OPERATION_RESTORE || + srv_operation == SRV_OPERATION_RESTORE_EXPORT); + + /* Open system tablespace ibdata1. */ + auto err = srv_sys_space.open_or_create( + false, false, &sum_of_new_sizes, &flushed_lsn); + if (err != DB_SUCCESS) { + return srv_init_abort(err); + } + + /* Open data files for system tablespace. */ + if (!fil_system.sys_space->open(false)) { + return srv_init_abort(DB_ERROR); + } + + /* Open undo tablespaces. */ + err = srv_undo_tablespaces_init(false); + if (err != DB_SUCCESS) { + return srv_init_abort(err); + } + return DB_SUCCESS; + }; + std::string logfile0; bool create_new_log = create_new_db; if (create_new_db) { @@ -1299,7 +1329,8 @@ dberr_t srv_start(bool create_new_db) bool log_file_found; if (dberr_t err = find_and_check_log_file(log_file_found)) { if (err == DB_NOT_FOUND) { - return DB_SUCCESS; + /* For restore, we need to continue. */ + return open_system_spaces(); } return srv_init_abort(err); } @@ -1329,8 +1360,6 @@ dberr_t srv_start(bool create_new_db) } /* Open or create the data files. */ - ulint sum_of_new_sizes; - err = srv_sys_space.open_or_create( false, create_new_db, &sum_of_new_sizes, &flushed_lsn); @@ -1378,10 +1407,8 @@ dberr_t srv_start(bool create_new_db) /* Suppress the message about crash recovery. */ flushed_lsn = log_sys.get_lsn(); - goto file_checked; } -file_checked: /* Open data files in the systemtablespace: we keep them open until database shutdown */ ut_d(fil_system.sys_space->recv_size = srv_sys_space_size_debug); From 68c0f6d8ead19ead4c6d9afcdb89c59ba0aced10 Mon Sep 17 00:00:00 2001 From: Robin Newhouse Date: Fri, 26 Jan 2024 01:33:28 +0000 Subject: [PATCH 2/7] Fix ninja build for cracklib_password_check As was done in dc77111 for `support-files/CMakeLists.txt` Do not rely on existence of `CMakeFiles/${target}.dir` directory existence. It is not there for custom targets in Ninja build. This regression was introduced in #1131 which likely copied the pattern from e79e840 before that regression was addressed in dc77111. All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services. --- plugin/cracklib_password_check/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugin/cracklib_password_check/CMakeLists.txt b/plugin/cracklib_password_check/CMakeLists.txt index 79b3b80fbef..263495838aa 100644 --- a/plugin/cracklib_password_check/CMakeLists.txt +++ b/plugin/cracklib_password_check/CMakeLists.txt @@ -32,11 +32,12 @@ IF (HAVE_ALLOCA_H AND HAVE_CRACK_H AND HAVE_LIBCRACK AND HAVE_MEMCPY) IF(CHECKMODULE AND SEMODULE_PACKAGE) FOREACH(pol mariadb-plugin-cracklib-password-check) SET(src ${CMAKE_CURRENT_SOURCE_DIR}/policy/selinux/${pol}.te) - SET(tmp ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${pol}-pp.dir/${pol}.mod) + SET(tmp ${CMAKE_CURRENT_BINARY_DIR}/${pol}.mod) SET(out ${CMAKE_CURRENT_BINARY_DIR}/${pol}.pp) ADD_CUSTOM_COMMAND(OUTPUT ${out} COMMAND ${CHECKMODULE} -M -m ${src} -o ${tmp} COMMAND ${SEMODULE_PACKAGE} -m ${tmp} -o ${out} + COMMAND ${CMAKE_COMMAND} -E remove ${tmp} DEPENDS ${src}) ADD_CUSTOM_TARGET(${pol}-pp ALL DEPENDS ${out}) INSTALL(FILES ${out} DESTINATION ${inst_location}/policy/selinux COMPONENT cracklib-password-check) From 6e406bb6549f05990764baadc7936aeb017c3e5d Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Wed, 6 Dec 2023 12:03:27 -0800 Subject: [PATCH 3/7] Fix inconsistent definition of PERFORMANCE_SCHEMA.REPLICATION_APPLIER_STATUS.COUNT_TRANSACTIONS_RETRIES column MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This column (`COUNT_TRANSACTIONS_RETRIES`) is defined as `BIGINT UNSIGNED` (64-bit unsigned integer) in the user-visible SQL definition: https://github.com/MariaDB/server/blob/182ff21ace34ea4f00fb5b66689b172323d91f99/storage/perfschema/table_replication_applier_status.cc#L66 "COUNT_TRANSACTIONS_RETRIES BIGINT unsigned not null comment 'The number of retries that were made because the replication SQL thread failed to apply a transaction.'," And its value is internally set/updated using the `set_field_ulonglong` function: https://github.com/MariaDB/server/blob/182ff21ace34ea4f00fb5b66689b172323d91f99/storage/perfschema/table_replication_applier_status.cc#L231-L233 case 3: /* total number of times transactions were retried */ set_field_ulonglong(f, m_row.count_transactions_retries); break; … but the structure where it is stored allocates only `ulong` for it: https://github.com/MariaDB/server/blob/182ff21ace34ea4f00fb5b66689b172323d91f99/storage/perfschema/table_replication_applier_status.h#L62 ulong count_transactions_retries; As a result of this inconsistency: 1. On any platform where `ulong` is `uint32_t` and `ulonglong` is `uint64_t`, setting this value would corrupt the 4 bytes of memory *following* the 4 bytes actually allocated for it. Likely this problem was never noticed because this is the final element in the structure, and the structure is padded by the compiler to prevent memory corruption errors. 2. On any BIG-ENDIAN platform where `ulong` is `uint32_t` and `ulonglong` is `uint64_t`, reading back the value of this column will result in total garbage. Likely this problem was never noticed because MariaDB has not been tested on 32-bit big-endian platforms. In order not to affect the user-visible/SQL definition of this column, the correct way to fix this issue is to change it to `ulonglong` in the structure definition. See https://github.com/MariaDB/server/pull/2763/files#r1329110832 for the original identification and discussion of this issue. All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services --- storage/perfschema/table_replication_applier_status.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/perfschema/table_replication_applier_status.h b/storage/perfschema/table_replication_applier_status.h index 656e148e31b..026edea5442 100644 --- a/storage/perfschema/table_replication_applier_status.h +++ b/storage/perfschema/table_replication_applier_status.h @@ -61,7 +61,7 @@ struct st_row_applier_status { enum_rpl_yes_no service_state; uint remaining_delay; bool remaining_delay_is_set; - ulong count_transactions_retries; + ulonglong count_transactions_retries; }; /** Table PERFORMANCE_SCHEMA.replication_applier_status */ From 5e7047067e4c99f61d398c9dbee1fd74ef0b1632 Mon Sep 17 00:00:00 2001 From: mariadb-DebarunBanerjee Date: Tue, 6 Feb 2024 15:50:10 +0530 Subject: [PATCH 4/7] MDEV-33274 The test encryption.innodb-redo-nokeys often fails If we fail to open a tablespace while looking for FILE_CHECKPOINT, we set the corruption flag. Specifically, if encryption key is missing, we would not be able to open an encrypted tablespace and the flag could be set. We miss checking for this flag and report "Missing FILE_CHECKPOINT" Address review comment to improve the test. Flush pages before starting no-checkpoint block. It should improve the number of cases where the test is skipped because some intermediate checkpoint is triggered. --- .../encryption/r/innodb-redo-nokeys.result | 9 ++++++++ .../encryption/t/innodb-redo-nokeys.test | 2 ++ .../innodb/include/no_checkpoint_start.inc | 23 +++++++++++++++++++ storage/innobase/log/log0recv.cc | 9 ++++++++ 4 files changed, 43 insertions(+) diff --git a/mysql-test/suite/encryption/r/innodb-redo-nokeys.result b/mysql-test/suite/encryption/r/innodb-redo-nokeys.result index 8c92fd07388..274045fa3ec 100644 --- a/mysql-test/suite/encryption/r/innodb-redo-nokeys.result +++ b/mysql-test/suite/encryption/r/innodb-redo-nokeys.result @@ -17,6 +17,15 @@ insert into t2 select * from t1; insert into t3 select * from t1; insert into t4 select * from t1; commit; + +# Flush all dirty pages from buffer pool +SET @no_checkpoint_save_pct= @@GLOBAL.innodb_max_dirty_pages_pct; +SET @no_checkpoint_save_pct_lwm= @@GLOBAL.innodb_max_dirty_pages_pct_lwm; +SET GLOBAL innodb_max_dirty_pages_pct_lwm=0.0; +SET GLOBAL innodb_max_dirty_pages_pct=0.0; +SET GLOBAL innodb_max_dirty_pages_pct= @no_checkpoint_save_pct; +SET GLOBAL innodb_max_dirty_pages_pct_lwm= @no_checkpoint_save_pct_lwm; + CREATE TABLE t5 (a VARCHAR(8)) ENGINE=InnoDB ENCRYPTED=YES; SET GLOBAL innodb_flush_log_at_trx_commit=1; begin; diff --git a/mysql-test/suite/encryption/t/innodb-redo-nokeys.test b/mysql-test/suite/encryption/t/innodb-redo-nokeys.test index 905b4f6333f..189adbffe49 100644 --- a/mysql-test/suite/encryption/t/innodb-redo-nokeys.test +++ b/mysql-test/suite/encryption/t/innodb-redo-nokeys.test @@ -38,7 +38,9 @@ insert into t3 select * from t1; insert into t4 select * from t1; commit; +let $no_checkpoint_flush= 1; --source ../../suite/innodb/include/no_checkpoint_start.inc + # # We test redo log page read at recv_read_page using # keys that are not in std_data/keys.txt. If checkpoint diff --git a/mysql-test/suite/innodb/include/no_checkpoint_start.inc b/mysql-test/suite/innodb/include/no_checkpoint_start.inc index a903fee67d4..69823dd0a03 100644 --- a/mysql-test/suite/innodb/include/no_checkpoint_start.inc +++ b/mysql-test/suite/innodb/include/no_checkpoint_start.inc @@ -1,5 +1,28 @@ # Preparation for using no_checkpoint_end.inc +# no_checkpoint_flush: Set to trigger flushing the dirty pages from buffer pool +# and checkpoint before the "no checkpoint" block. + +if ($no_checkpoint_flush) { + --echo + --echo # Flush all dirty pages from buffer pool + SET @no_checkpoint_save_pct= @@GLOBAL.innodb_max_dirty_pages_pct; + SET @no_checkpoint_save_pct_lwm= @@GLOBAL.innodb_max_dirty_pages_pct_lwm; + + SET GLOBAL innodb_max_dirty_pages_pct_lwm=0.0; + SET GLOBAL innodb_max_dirty_pages_pct=0.0; + + let $wait_condition = + SELECT variable_value = 0 + FROM information_schema.global_status + WHERE variable_name = 'INNODB_BUFFER_POOL_PAGES_DIRTY'; + --source include/wait_condition.inc + + SET GLOBAL innodb_max_dirty_pages_pct= @no_checkpoint_save_pct; + SET GLOBAL innodb_max_dirty_pages_pct_lwm= @no_checkpoint_save_pct_lwm; + --echo +} + let MYSQLD_DATADIR= `select @@datadir`; --replace_regex /.*Last checkpoint at[ ]*([0-9]+).*/\1/ let CHECKPOINT_LSN=`SHOW ENGINE INNODB STATUS`; diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index ffe35e9dbc7..620e9c9209d 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -3538,6 +3538,15 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) return(DB_ERROR); } + /* If we fail to open a tablespace while looking for FILE_CHECKPOINT, we + set the corruption flag. Specifically, if encryption key is missing, we + would not be able to open an encrypted tablespace and the flag could be + set. */ + if (recv_sys.found_corrupt_fs) { + mysql_mutex_unlock(&log_sys.mutex); + return DB_ERROR; + } + if (recv_sys.mlog_checkpoint_lsn == 0) { lsn_t scan_lsn = log_sys.log.scanned_lsn; if (!srv_read_only_mode && scan_lsn != checkpoint_lsn) { From f7adf1292c4052b9886dc9d4b773fb0e1618c9b3 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 6 Feb 2024 18:20:53 +1100 Subject: [PATCH 5/7] MDEV-4827: prelude - additional gtid/no-gtid tests for mysqldump This will make it easier to show changes. --- mysql-test/main/rpl_mysqldump_slave.result | 120 +++++++++++++++++++-- mysql-test/main/rpl_mysqldump_slave.test | 59 ++++++++-- 2 files changed, 164 insertions(+), 15 deletions(-) diff --git a/mysql-test/main/rpl_mysqldump_slave.result b/mysql-test/main/rpl_mysqldump_slave.result index 9f93e3c405e..cbc26996ee6 100644 --- a/mysql-test/main/rpl_mysqldump_slave.result +++ b/mysql-test/main/rpl_mysqldump_slave.result @@ -25,7 +25,7 @@ CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_S start slave; Warnings: Note 1254 Slave is already running -*** Test mysqldump --dump-slave GTID functionality. +*** Test mysqldump --dump-slave GTID/non-gtid functionality. connection master; SET gtid_seq_no = 1000; CREATE TABLE t1 (a INT PRIMARY KEY); @@ -35,36 +35,142 @@ connection slave; CREATE TABLE t2 (a INT PRIMARY KEY); DROP TABLE t2; -1. --dump-slave=1 +1. --dump-slave=1 --gtid SET GLOBAL gtid_slave_pos='0-1-1001'; CHANGE MASTER '' TO MASTER_USE_GTID=slave_pos; -- CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; -2. --dump-slave=2 +1a. --dump-slave=1 + +-- SET GLOBAL gtid_slave_pos='0-1-1001'; +CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; + +2. --dump-slave=2 --gtid -- SET GLOBAL gtid_slave_pos='0-1-1001'; -- CHANGE MASTER '' TO MASTER_USE_GTID=slave_pos; -- CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; -*** Test mysqldump --master-data GTID functionality. -1. --master-data=1 +2. --dump-slave=2 + +-- SET GLOBAL gtid_slave_pos='0-1-1001'; +-- CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; +*** Test mysqldump --master-data GTID/non-gtid functionality. + +1. --master-data=1 --gtid -- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; CHANGE MASTER TO MASTER_USE_GTID=slave_pos; SET GLOBAL gtid_slave_pos='0-2-1003'; -2. --master-data=2 +1a. --master-data=1 + +CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; +-- SET GLOBAL gtid_slave_pos='0-2-1003'; + +2. --master-data=2 --gtid -- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; -- CHANGE MASTER TO MASTER_USE_GTID=slave_pos; -- SET GLOBAL gtid_slave_pos='0-2-1003'; -3. --master-data --single-transaction +2a. --master-data=2 + +-- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; +-- SET GLOBAL gtid_slave_pos='0-2-1003'; + +3. --master-data --single-transaction --gtid -- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; CHANGE MASTER TO MASTER_USE_GTID=slave_pos; SET GLOBAL gtid_slave_pos='0-2-1003'; + +3a. --master-data --single-transaction + +CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; +-- SET GLOBAL gtid_slave_pos='0-2-1003'; + +4. --master-data=2 --dump-slave=2 --single-transaction --gtid (MDEV-4827) + +-- MariaDB dump-- +-- Host: localhost Database: test +-- ------------------------------------------------------ +-- Server version +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Gtid position to start replication from +-- + +-- SET GLOBAL gtid_slave_pos='0-1-1001'; +-- CHANGE MASTER '' TO MASTER_USE_GTID=slave_pos; + +-- +-- Position to start replication or point-in-time recovery from (the master of this slave) +-- + +-- CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed + +4a. --master-data=2 --dump-slave=2 --single-transaction (MDEV-4827) + +-- MariaDB dump-- +-- Host: localhost Database: test +-- ------------------------------------------------------ +-- Server version +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Gtid position to start replication from +-- + +-- SET GLOBAL gtid_slave_pos='0-1-1001'; + +-- +-- Position to start replication or point-in-time recovery from (the master of this slave) +-- + +-- CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed connection master; CREATE TABLE t ( id int diff --git a/mysql-test/main/rpl_mysqldump_slave.test b/mysql-test/main/rpl_mysqldump_slave.test index 0273e196db5..9dbee604520 100644 --- a/mysql-test/main/rpl_mysqldump_slave.test +++ b/mysql-test/main/rpl_mysqldump_slave.test @@ -37,7 +37,7 @@ start slave; start slave; ---echo *** Test mysqldump --dump-slave GTID functionality. +--echo *** Test mysqldump --dump-slave GTID/non-gtid functionality. --connection master SET gtid_seq_no = 1000; @@ -52,37 +52,80 @@ CREATE TABLE t2 (a INT PRIMARY KEY); DROP TABLE t2; --echo ---echo 1. --dump-slave=1 +--echo 1. --dump-slave=1 --gtid --echo --replace_regex /MASTER_LOG_POS=[0-9]+/MASTER_LOG_POS=BINLOG_START/ --exec $MYSQL_DUMP_SLAVE --compact --dump-slave=1 --gtid test --echo ---echo 2. --dump-slave=2 +--echo 1a. --dump-slave=1 +--echo +--replace_regex /MASTER_LOG_POS=[0-9]+/MASTER_LOG_POS=BINLOG_START/ +--exec $MYSQL_DUMP_SLAVE --compact --dump-slave=1 test + +--echo +--echo 2. --dump-slave=2 --gtid --echo --replace_regex /MASTER_LOG_POS=[0-9]+/MASTER_LOG_POS=BINLOG_START/ --exec $MYSQL_DUMP_SLAVE --compact --dump-slave=2 --gtid test - ---echo *** Test mysqldump --master-data GTID functionality. --echo ---echo 1. --master-data=1 +--echo 2. --dump-slave=2 +--echo +--replace_regex /MASTER_LOG_POS=[0-9]+/MASTER_LOG_POS=BINLOG_START/ +--exec $MYSQL_DUMP_SLAVE --compact --dump-slave=2 test + + +--echo *** Test mysqldump --master-data GTID/non-gtid functionality. +--echo +--echo 1. --master-data=1 --gtid --echo --replace_regex /MASTER_LOG_POS=[0-9]+/MASTER_LOG_POS=BINLOG_START/ --exec $MYSQL_DUMP_SLAVE --compact --master-data=1 --gtid test --echo ---echo 2. --master-data=2 +--echo 1a. --master-data=1 +--echo +--replace_regex /MASTER_LOG_POS=[0-9]+/MASTER_LOG_POS=BINLOG_START/ +--exec $MYSQL_DUMP_SLAVE --compact --master-data=1 test + +--echo +--echo 2. --master-data=2 --gtid --echo --replace_regex /MASTER_LOG_POS=[0-9]+/MASTER_LOG_POS=BINLOG_START/ --exec $MYSQL_DUMP_SLAVE --compact --master-data=2 --gtid test --echo ---echo 3. --master-data --single-transaction +--echo 2a. --master-data=2 +--echo +--replace_regex /MASTER_LOG_POS=[0-9]+/MASTER_LOG_POS=BINLOG_START/ +--exec $MYSQL_DUMP_SLAVE --compact --master-data=2 test + +--echo +--echo 3. --master-data --single-transaction --gtid --echo --replace_regex /MASTER_LOG_POS=[0-9]+/MASTER_LOG_POS=BINLOG_START/ --exec $MYSQL_DUMP_SLAVE --compact --master-data --single-transaction --gtid test +--echo +--echo 3a. --master-data --single-transaction +--echo +--replace_regex /MASTER_LOG_POS=[0-9]+/MASTER_LOG_POS=BINLOG_START/ +--exec $MYSQL_DUMP_SLAVE --compact --master-data --single-transaction test + +--echo +--echo 4. --master-data=2 --dump-slave=2 --single-transaction --gtid (MDEV-4827) +--echo +--replace_regex /MASTER_LOG_POS=[0-9]+/MASTER_LOG_POS=BINLOG_START/ /MariaDB dump.*/MariaDB dump/ /Dump completed.*/Dump completed/ /Server version.*/Server version/ +--exec $MYSQL_DUMP_SLAVE --master-data=2 --dump-slave=2 --single-transaction --gtid test +--echo + +--echo +--echo 4a. --master-data=2 --dump-slave=2 --single-transaction (MDEV-4827) +--echo +--replace_regex /MASTER_LOG_POS=[0-9]+/MASTER_LOG_POS=BINLOG_START/ /MariaDB dump.*/MariaDB dump/ /Dump completed.*/Dump completed/ /Server version.*/Server version/ +--exec $MYSQL_DUMP_SLAVE --master-data=2 --dump-slave=2 --single-transaction test +--echo # # MDEV-32611 Added test for mysqldump --delete-master-logs option. # This options is alias of From 915d951431b3b385a6c477544dc1d287c3377ebd Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 18 Jul 2023 13:37:30 +1000 Subject: [PATCH 6/7] MDEV-4827 mysqldump --dump-slave=2 --master-data=2 doesn't record both Recording both is useful on a replication relay when the backup can be used to replace the server, or ack as a new replica to the server. If an option=2, commented is selected, allow the alternate option to exist. This still disables --dump-slave=1 --master-data=1 as having the a CHANGE MASTER TO and START SLAVE on different positions would be confusing and dangerious to the try to execute the output. The previous behaviour of silently disabling --master-data occurs in this case. The commented code related to --dump-slave/--master-data is greatly expanded for human consumption. A redundant opt_slave_data= 0 was removed from get_opts. If --dump-slave=1 or 2, then the only possible value of --master-data is a valid one. Re-order to preference gtid based replication. Based of code from Elena Stepanova. Review by: Brandon Nesterenko and Anel Husakovic --- client/mysqldump.c | 80 +++++++++++++--------- mysql-test/main/rpl_mysqldump_slave.result | 70 ++++++++++++++----- 2 files changed, 98 insertions(+), 52 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index c0bc655d0b6..ae06f1dbf8b 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1226,8 +1226,9 @@ static int get_options(int *argc, char ***argv) if (opt_slave_data) { opt_lock_all_tables= !opt_single_transaction; - opt_master_data= 0; opt_delete_master_logs= 0; + if (opt_slave_data != MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL) + opt_master_data= 0; } /* Ensure consistency of the set of binlog & locking options */ @@ -1240,10 +1241,7 @@ static int get_options(int *argc, char ***argv) return(EX_USAGE); } if (opt_master_data) - { opt_lock_all_tables= !opt_single_transaction; - opt_slave_data= 0; - } if (opt_single_transaction || opt_lock_all_tables) lock_tables= 0; if (enclosed && opt_enclosed) @@ -6043,17 +6041,12 @@ static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos, } - /* SHOW MASTER STATUS reports file and position */ - print_comment(md_result_file, 0, - "\n--\n-- Position to start replication or point-in-time " - "recovery from\n--\n\n"); - fprintf(md_result_file, - "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n", - (use_gtid ? "-- " : comment_prefix), file, offset); + /* gtid */ if (have_mariadb_gtid) { print_comment(md_result_file, 0, - "\n--\n-- GTID to start replication from\n--\n\n"); + "\n-- Preferably use GTID to start replication from GTID " + "position:\n\n"); if (use_gtid) fprintf(md_result_file, "%sCHANGE MASTER TO MASTER_USE_GTID=slave_pos;\n", @@ -6062,6 +6055,19 @@ static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos, "%sSET GLOBAL gtid_slave_pos='%s';\n", (!use_gtid ? "-- " : comment_prefix), gtid_pos); } + + /* SHOW MASTER STATUS reports file and position */ + print_comment(md_result_file, 0, + "\n--\n-- Alternately, following is the position of the binary " + "logging from SHOW MASTER STATUS at point of backup." + "\n-- Use this when creating a replica of the primary server " + "where the backup was made." + "\n-- The new server will be connecting to the primary server " + "where the backup was taken." + "\n--\n\n"); + fprintf(md_result_file, + "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n", + (use_gtid ? "-- " : comment_prefix), file, offset); check_io(md_result_file); if (!consistent_binlog_pos) @@ -6140,7 +6146,6 @@ static int do_show_slave_status(MYSQL *mysql_con, int use_gtid, (opt_slave_data == MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL) ? "-- " : ""; const char *gtid_comment_prefix= (use_gtid ? comment_prefix : "-- "); const char *nogtid_comment_prefix= (!use_gtid ? comment_prefix : "-- "); - int set_gtid_done= 0; if (mysql_query_with_error_report(mysql_con, &slave, multi_source ? @@ -6156,23 +6161,36 @@ static int do_show_slave_status(MYSQL *mysql_con, int use_gtid, return 1; } + print_comment(md_result_file, 0, + "\n--\n-- The following is the SQL position of the replication " + "taken from SHOW SLAVE STATUS at the time of backup.\n" + "-- Use this position when creating a clone of, or replacement " + "server, from where the backup was taken." + "\n-- This new server will connects to the same primary " + "server%s.\n--\n", + multi_source ? "(s)" : ""); + + if (multi_source) + { + char gtid_pos[MAX_GTID_LENGTH]; + if (have_mariadb_gtid && get_gtid_pos(gtid_pos, 0)) + { + mysql_free_result(slave); + return 1; + } + print_comment(md_result_file, 0, + "-- GTID position to start replication:\n"); + fprintf(md_result_file, "%sSET GLOBAL gtid_slave_pos='%s';\n", + gtid_comment_prefix, gtid_pos); + } + if (use_gtid) + print_comment(md_result_file, 0, + "\n-- Use only the MASTER_USE_GTID=slave_pos or " + "MASTER_LOG_FILE/MASTER_LOG_POS in the statements below." + "\n\n"); + while ((row= mysql_fetch_row(slave))) { - if (multi_source && !set_gtid_done) - { - char gtid_pos[MAX_GTID_LENGTH]; - if (have_mariadb_gtid && get_gtid_pos(gtid_pos, 0)) - { - mysql_free_result(slave); - return 1; - } - if (opt_comments) - fprintf(md_result_file, "\n--\n-- Gtid position to start replication " - "from\n--\n\n"); - fprintf(md_result_file, "%sSET GLOBAL gtid_slave_pos='%s';\n", - gtid_comment_prefix, gtid_pos); - set_gtid_done= 1; - } if (row[9 + multi_source] && row[21 + multi_source]) { if (use_gtid) @@ -6186,11 +6204,6 @@ static int do_show_slave_status(MYSQL *mysql_con, int use_gtid, } /* SHOW MASTER STATUS reports file and position */ - if (opt_comments) - fprintf(md_result_file, - "\n--\n-- Position to start replication or point-in-time " - "recovery from (the master of this slave)\n--\n\n"); - if (multi_source) fprintf(md_result_file, "%sCHANGE MASTER '%.80s' TO ", nogtid_comment_prefix, row[0]); @@ -6211,6 +6224,7 @@ static int do_show_slave_status(MYSQL *mysql_con, int use_gtid, check_io(md_result_file); } } + fprintf(md_result_file, "\n"); mysql_free_result(slave); return 0; } diff --git a/mysql-test/main/rpl_mysqldump_slave.result b/mysql-test/main/rpl_mysqldump_slave.result index cbc26996ee6..0d0378abd5b 100644 --- a/mysql-test/main/rpl_mysqldump_slave.result +++ b/mysql-test/main/rpl_mysqldump_slave.result @@ -9,19 +9,23 @@ use test; connection slave; -- SET GLOBAL gtid_slave_pos=''; CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; + STOP ALL SLAVES; -- SET GLOBAL gtid_slave_pos=''; CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; + START ALL SLAVES; STOP ALL SLAVES; -- SET GLOBAL gtid_slave_pos=''; CHANGE MASTER '' TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_MYPORT, MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; + START ALL SLAVES; start slave; Warnings: Note 1254 Slave is already running -- SET GLOBAL gtid_slave_pos=''; CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; + start slave; Warnings: Note 1254 Slave is already running @@ -41,55 +45,59 @@ SET GLOBAL gtid_slave_pos='0-1-1001'; CHANGE MASTER '' TO MASTER_USE_GTID=slave_pos; -- CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; + 1a. --dump-slave=1 -- SET GLOBAL gtid_slave_pos='0-1-1001'; CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; + 2. --dump-slave=2 --gtid -- SET GLOBAL gtid_slave_pos='0-1-1001'; -- CHANGE MASTER '' TO MASTER_USE_GTID=slave_pos; -- CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; + 2. --dump-slave=2 -- SET GLOBAL gtid_slave_pos='0-1-1001'; -- CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; + *** Test mysqldump --master-data GTID/non-gtid functionality. 1. --master-data=1 --gtid --- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; CHANGE MASTER TO MASTER_USE_GTID=slave_pos; SET GLOBAL gtid_slave_pos='0-2-1003'; +-- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; 1a. --master-data=1 -CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; -- SET GLOBAL gtid_slave_pos='0-2-1003'; +CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; 2. --master-data=2 --gtid --- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; -- CHANGE MASTER TO MASTER_USE_GTID=slave_pos; -- SET GLOBAL gtid_slave_pos='0-2-1003'; +-- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; 2a. --master-data=2 --- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; -- SET GLOBAL gtid_slave_pos='0-2-1003'; +-- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; 3. --master-data --single-transaction --gtid --- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; CHANGE MASTER TO MASTER_USE_GTID=slave_pos; SET GLOBAL gtid_slave_pos='0-2-1003'; +-- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; 3a. --master-data --single-transaction -CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; -- SET GLOBAL gtid_slave_pos='0-2-1003'; +CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; 4. --master-data=2 --dump-slave=2 --single-transaction --gtid (MDEV-4827) @@ -108,18 +116,32 @@ CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- Preferably use GTID to start replication from GTID position: + +-- CHANGE MASTER TO MASTER_USE_GTID=slave_pos; +-- SET GLOBAL gtid_slave_pos='0-2-1003'; + -- --- Gtid position to start replication from +-- Alternately, following is the position of the binary logging from SHOW MASTER STATUS at point of backup. +-- Use this when creating a replica of the primary server where the backup was made. +-- The new server will be connecting to the primary server where the backup was taken. -- +-- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; + +-- +-- The following is the SQL position of the replication taken from SHOW SLAVE STATUS at the time of backup. +-- Use this position when creating a clone of, or replacement server, from where the backup was taken. +-- This new server will connects to the same primary server(s). +-- +-- GTID position to start replication: -- SET GLOBAL gtid_slave_pos='0-1-1001'; + +-- Use only the MASTER_USE_GTID=slave_pos or MASTER_LOG_FILE/MASTER_LOG_POS in the statements below. + -- CHANGE MASTER '' TO MASTER_USE_GTID=slave_pos; - --- --- Position to start replication or point-in-time recovery from (the master of this slave) --- - -- CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; + /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; @@ -149,17 +171,27 @@ CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- Preferably use GTID to start replication from GTID position: + +-- SET GLOBAL gtid_slave_pos='0-2-1003'; + -- --- Gtid position to start replication from +-- Alternately, following is the position of the binary logging from SHOW MASTER STATUS at point of backup. +-- Use this when creating a replica of the primary server where the backup was made. +-- The new server will be connecting to the primary server where the backup was taken. -- +-- CHANGE MASTER TO MASTER_LOG_FILE='slave-bin.000001', MASTER_LOG_POS=BINLOG_START; + +-- +-- The following is the SQL position of the replication taken from SHOW SLAVE STATUS at the time of backup. +-- Use this position when creating a clone of, or replacement server, from where the backup was taken. +-- This new server will connects to the same primary server(s). +-- +-- GTID position to start replication: -- SET GLOBAL gtid_slave_pos='0-1-1001'; - --- --- Position to start replication or point-in-time recovery from (the master of this slave) --- - -- CHANGE MASTER '' TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=BINLOG_START; + /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; @@ -183,8 +215,8 @@ include/stop_slave.inc change master to master_use_gtid=slave_pos; connection master; # Ensuring the binlog dump thread is killed on primary... --- CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000002', MASTER_LOG_POS=BINLOG_START; -- SET GLOBAL gtid_slave_pos='0-1-1005'; +-- CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000002', MASTER_LOG_POS=BINLOG_START; connection slave; include/start_slave.inc include/rpl_end.inc From 0381921e265b4e7c8c97dfeb21f074dfd02e02cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 8 Feb 2024 10:35:45 +0200 Subject: [PATCH 7/7] MDEV-33277 In-place upgrade causes invalid AUTO_INCREMENT values MDEV-33308 CHECK TABLE is modifying .frm file even if --read-only As noted in commit d0ef1aaf618452efea5a2e74f6d86ed0a586b63e, MySQL as well as older versions of MariaDB server would during ALTER TABLE ... IMPORT TABLESPACE write bogus values to the PAGE_MAX_TRX_ID field to pages of the clustered index, instead of letting that field remain 0. In commit 8777458a6eb73ac1d7d864ebac390ea7039e21c1 this field was repurposed for PAGE_ROOT_AUTO_INC in the clustered index root page. To avoid trouble when upgrading from MySQL or older versions of MariaDB, we will try to detect and correct bogus values of PAGE_ROOT_AUTO_INC when opening a table for the first time from the SQL layer. btr_read_autoinc_with_fallback(): Add the parameters to mysql_version,max to indicate the TABLE_SHARE::mysql_version of the .frm file and the maximum value allowed for the type of the AUTO_INCREMENT column. In case the table was originally created in MySQL or an older version of MariaDB, read also the maximum value of the AUTO_INCREMENT column from the table and reset the PAGE_ROOT_AUTO_INC if it is above the limit. dict_table_t::get_index(const dict_col_t &) const: Find an index that starts with the specified column. ha_innobase::check_for_upgrade(): Return HA_ADMIN_FAILED if InnoDB needs upgrading but is in read-only mode. In this way, the call to update_frm_version() will be skipped. row_import_autoinc(): Adjust the AUTO_INCREMENT column at the end of ALTER TABLE...IMPORT TABLESPACE. This refinement was suggested by Debarun Banerjee. The changes outside InnoDB were developed by Michael 'Monty' Widenius: Added print_check_msg() service for easy reporting of check/repair messages in ENGINE=Aria and ENGINE=InnoDB. Fixed that CHECK TABLE do not update the .frm file under --read-only. Added 'handler_flags' to HA_CHECK_OPT as a way for storage engines to store state from handler::check_for_upgrade(). Reviewed by: Debarun Banerjee --- include/mysql/service_print_check_msg.h | 44 ++++ include/service_versions.h | 1 + libservices/CMakeLists.txt | 1 + libservices/print_check_msg_service.c | 18 ++ mysql-test/std_data/autoinc_import_101.frm | Bin 0 -> 922 bytes mysql-test/std_data/autoinc_import_57.frm | Bin 0 -> 8556 bytes .../suite/innodb/r/autoinc_import.result | 232 ++++++++++++++++++ mysql-test/suite/innodb/t/autoinc_import.test | 168 +++++++++++++ sql/handler.cc | 6 +- sql/handler.h | 1 + sql/sql_class.cc | 34 +++ sql/sql_plugin_services.inl | 7 + storage/innobase/btr/btr0btr.cc | 97 +++++--- storage/innobase/handler/ha_innodb.cc | 142 +++++++---- storage/innobase/handler/ha_innodb.h | 7 + storage/innobase/handler/handler0alter.cc | 17 +- storage/innobase/include/btr0btr.h | 17 +- storage/innobase/include/dict0mem.h | 3 + storage/innobase/row/row0import.cc | 44 +++- storage/maria/ha_maria.cc | 28 +-- 20 files changed, 723 insertions(+), 144 deletions(-) create mode 100644 include/mysql/service_print_check_msg.h create mode 100644 libservices/print_check_msg_service.c create mode 100644 mysql-test/std_data/autoinc_import_101.frm create mode 100644 mysql-test/std_data/autoinc_import_57.frm create mode 100644 mysql-test/suite/innodb/r/autoinc_import.result create mode 100644 mysql-test/suite/innodb/t/autoinc_import.test diff --git a/include/mysql/service_print_check_msg.h b/include/mysql/service_print_check_msg.h new file mode 100644 index 00000000000..c2c7cf0a381 --- /dev/null +++ b/include/mysql/service_print_check_msg.h @@ -0,0 +1,44 @@ +/* Copyright (c) 2019, MariaDB Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ + +#pragma once + +/** + @file include/mysql/service_print_check_msg.h + This service provides functions to write messages for check or repair +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + +extern struct print_check_msg_service_st { + void (*print_check_msg)(MYSQL_THD, const char *db_name, const char *table_name, + const char *op, const char *msg_type, const char *message, + my_bool print_to_log); +} *print_check_msg_service; + +#ifdef MYSQL_DYNAMIC_PLUGIN +# define print_check_msg_context(_THD) print_check_msg_service->print_check_msg +#else +extern void print_check_msg(MYSQL_THD, const char *db_name, const char *table_name, + const char *op, const char *msg_type, const char *message, + my_bool print_to_log); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/include/service_versions.h b/include/service_versions.h index ee250864287..cace4f37c69 100644 --- a/include/service_versions.h +++ b/include/service_versions.h @@ -45,3 +45,4 @@ #define VERSION_json 0x0100 #define VERSION_sql_service 0x0100 #define VERSION_thd_mdl 0x0100 +#define VERSION_print_check_msg 0x0100 diff --git a/libservices/CMakeLists.txt b/libservices/CMakeLists.txt index 6b47bb53fdb..d1329b665d5 100644 --- a/libservices/CMakeLists.txt +++ b/libservices/CMakeLists.txt @@ -25,6 +25,7 @@ SET(MYSQLSERVICES_SOURCES my_crypt_service.c my_md5_service.c my_print_error_service.c + print_check_msg_service.c my_sha1_service.c my_sha2_service.c my_snprintf_service.c diff --git a/libservices/print_check_msg_service.c b/libservices/print_check_msg_service.c new file mode 100644 index 00000000000..12f7bc51118 --- /dev/null +++ b/libservices/print_check_msg_service.c @@ -0,0 +1,18 @@ +/* Copyright (c) 2024, MariaDB Plc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +SERVICE_VERSION print_check_msg_context= (void*) VERSION_print_check_msg; diff --git a/mysql-test/std_data/autoinc_import_101.frm b/mysql-test/std_data/autoinc_import_101.frm new file mode 100644 index 0000000000000000000000000000000000000000..b16ae91b110ccd90bf149d73db70c8d0299d0a28 GIT binary patch literal 922 zcmeyz$jKwb5XQjBFpHUi;U^<20~|0ZGH@_3fCYdw1pH)VU@&cGWDtM}FbKTXU|PNN zrr^7&-vp{%Hr8aNFflMN0+n$Am9PNK1@anzLQ+7^|9~J*U&o-x|8U)-jNugm(3oXo z@XX80cX5Jv&WzCvlnh2N0C^vjA6OyT2^#siRY!imT$%K`7nay9A`Zf=}mT8Lw&U>{6(3?vft@ zIsLX?@{-xy0Eqy5z)FN~1zSu3zoBDWR?i)tz^32GG9c|294SBn3Q&Lo6rcbFC_n)U zP=Epy7^Q&d4}Gl3Lg)nY2!ORNTv-*DV|8_-4E>LxI>`x&rn#R_?I(QXSrniE1t>rP z3Q&Lo6rcbFC_sVX1#W_5_*=$%gJ|C)_Z^U^ed^$&mRNO>a|9ABcj=F%trKHwgeH#R OTPX{`=<5k*Ylk-*dlr}g literal 0 HcmV?d00001 diff --git a/mysql-test/suite/innodb/r/autoinc_import.result b/mysql-test/suite/innodb/r/autoinc_import.result new file mode 100644 index 00000000000..4a8ddd02e3d --- /dev/null +++ b/mysql-test/suite/innodb/r/autoinc_import.result @@ -0,0 +1,232 @@ +CREATE TABLE t1 (id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES(42); +CREATE TABLE t1b LIKE t1; +INSERT INTO t1b VALUES(3); +CREATE TABLE t1z LIKE t1; +CREATE TABLE t1t (id TINYINT AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t0t LIKE t1t; +INSERT INTO t1t VALUES(123); +FLUSH TABLES t1,t1b,t1t FOR EXPORT; +UNLOCK TABLES; +CREATE TABLE t5_7 LIKE t1; +CREATE TABLE t5_7b LIKE t1b; +CREATE TABLE t10_1 LIKE t1; +CREATE TABLE t10_1b LIKE t1b; +ALTER TABLE t1 DISCARD TABLESPACE; +ALTER TABLE t1b DISCARD TABLESPACE; +ALTER TABLE t1z DISCARD TABLESPACE; +ALTER TABLE t1t DISCARD TABLESPACE; +ALTER TABLE t0t DISCARD TABLESPACE; +ALTER TABLE t5_7 DISCARD TABLESPACE; +ALTER TABLE t5_7b DISCARD TABLESPACE; +ALTER TABLE t10_1 DISCARD TABLESPACE; +ALTER TABLE t10_1b DISCARD TABLESPACE; +FLUSH TABLES; +ALTER TABLE t0t IMPORT TABLESPACE; +Warnings: +Warning 1810 IO Read error: (2, No such file or directory) Error opening './test/t0t.cfg', will attempt to import without schema verification +INSERT INTO t0t VALUES(NULL); +SELECT * FROM t0t; +id +123 +124 +DROP TABLE t0t; +ALTER TABLE t1 IMPORT TABLESPACE; +Warnings: +Warning 1810 IO Read error: (2, No such file or directory) Error opening './test/t1.cfg', will attempt to import without schema verification +ALTER TABLE t1b IMPORT TABLESPACE; +Warnings: +Warning 1810 IO Read error: (2, No such file or directory) Error opening './test/t1b.cfg', will attempt to import without schema verification +ALTER TABLE t1z IMPORT TABLESPACE; +Warnings: +Warning 1810 IO Read error: (2, No such file or directory) Error opening './test/t1z.cfg', will attempt to import without schema verification +ALTER TABLE t1t IMPORT TABLESPACE; +Warnings: +Warning 1810 IO Read error: (2, No such file or directory) Error opening './test/t1t.cfg', will attempt to import without schema verification +ALTER TABLE t5_7 IMPORT TABLESPACE; +Warnings: +Warning 1810 IO Read error: (2, No such file or directory) Error opening './test/t5_7.cfg', will attempt to import without schema verification +ALTER TABLE t5_7b IMPORT TABLESPACE; +Warnings: +Warning 1810 IO Read error: (2, No such file or directory) Error opening './test/t5_7b.cfg', will attempt to import without schema verification +ALTER TABLE t10_1 IMPORT TABLESPACE; +Warnings: +Warning 1810 IO Read error: (2, No such file or directory) Error opening './test/t10_1.cfg', will attempt to import without schema verification +ALTER TABLE t10_1b IMPORT TABLESPACE; +Warnings: +Warning 1810 IO Read error: (2, No such file or directory) Error opening './test/t10_1b.cfg', will attempt to import without schema verification +FOUND 1 /InnoDB: Resetting PAGE_ROOT_AUTO_INC from 128 to 123 on table `test`\.`t0t`/ in mysqld.1.err +FOUND 1 /InnoDB: Resetting PAGE_ROOT_AUTO_INC from 0 to 42 on table `test`\.`t1z`/ in mysqld.1.err +FOUND 1 /InnoDB: Resetting PAGE_ROOT_AUTO_INC from 128 to 123 on table `test`\.`t1t`/ in mysqld.1.err +FOUND 1 /InnoDB: Resetting PAGE_ROOT_AUTO_INC from 3 to 42 on table `test`\.`t5_7` \(created with version 50744\)/ in mysqld.1.err +FOUND 1 /InnoDB: Resetting PAGE_ROOT_AUTO_INC from 3 to 42 on table `test`\.`t10_1` \(created with version 100149\)/ in mysqld.1.err +FOUND 5 /InnoDB: Resetting PAGE_ROOT_AUTO_INC/ in mysqld.1.err +# restart: --read-only +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t1b check status OK +test.t1t check status OK +test.t1z check status OK +test.t5_7 check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t5_7 check status OK +test.t5_7b check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t5_7b check status OK +test.t10_1 check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t10_1 check status OK +test.t10_1b check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t10_1b check status OK +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b FOR UPGRADE; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t1b check status OK +test.t1t check status OK +test.t1z check status OK +test.t5_7 check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t5_7 check status OK +test.t5_7b check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t5_7b check status OK +test.t10_1 check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t10_1 check status OK +test.t10_1b check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t10_1b check status OK +# restart: --innodb-read-only --read-only +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t1b check status OK +test.t1t check status OK +test.t1z check status OK +test.t5_7 check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t5_7 check status OK +test.t5_7b check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t5_7b check status OK +test.t10_1 check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t10_1 check status OK +test.t10_1b check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t10_1b check status OK +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b FOR UPGRADE; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t1b check status OK +test.t1t check status OK +test.t1z check status OK +test.t5_7 check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t5_7 check status OK +test.t5_7b check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t5_7b check status OK +test.t10_1 check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t10_1 check status OK +test.t10_1b check note Auto_increment will be checked on each open until CHECK TABLE FOR UPGRADE is executed +test.t10_1b check status OK +# restart: --innodb-read-only +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t1b check status OK +test.t1t check status OK +test.t1z check status OK +test.t5_7 check status Operation failed +test.t5_7b check status Operation failed +test.t10_1 check status Operation failed +test.t10_1b check status Operation failed +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b FOR UPGRADE; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t1b check status OK +test.t1t check status OK +test.t1z check status OK +test.t5_7 check status Operation failed +test.t5_7b check status Operation failed +test.t10_1 check status Operation failed +test.t10_1b check status Operation failed +SELECT COUNT(*) FROM t1; +COUNT(*) +1 +SELECT COUNT(*) FROM t1b; +COUNT(*) +1 +SELECT COUNT(*) FROM t1t; +COUNT(*) +1 +SELECT COUNT(*) FROM t1z; +COUNT(*) +1 +SELECT COUNT(*) FROM t5_7; +COUNT(*) +1 +SELECT COUNT(*) FROM t5_7b; +COUNT(*) +1 +SELECT COUNT(*) FROM t10_1; +COUNT(*) +1 +SELECT COUNT(*) FROM t10_1b; +COUNT(*) +1 +# restart +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b FOR UPGRADE; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t1b check status OK +test.t1t check status OK +test.t1z check status OK +test.t5_7 check note Auto_increment checked and .frm file version updated +test.t5_7 check status OK +test.t5_7b check note Auto_increment checked and .frm file version updated +test.t5_7b check status OK +test.t10_1 check note Auto_increment checked and .frm file version updated +test.t10_1 check status OK +test.t10_1b check note Auto_increment checked and .frm file version updated +test.t10_1b check status OK +INSERT INTO t1 VALUES(NULL); +INSERT INTO t1b VALUES(NULL); +INSERT INTO t1t VALUES(NULL); +INSERT INTO t1z VALUES(NULL); +INSERT INTO t5_7 VALUES(NULL); +INSERT INTO t5_7b VALUES(NULL); +INSERT INTO t10_1 VALUES(NULL); +INSERT INTO t10_1b VALUES(NULL); +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b FOR UPGRADE; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t1b check status OK +test.t1t check status OK +test.t1z check status OK +test.t5_7 check status OK +test.t5_7b check status OK +test.t10_1 check status OK +test.t10_1b check status OK +SELECT * FROM t1; +id +4 +42 +SELECT * FROM t1b; +id +3 +347 +SELECT * FROM t1t; +id +123 +124 +SELECT * FROM t1z; +id +42 +43 +SELECT * FROM t5_7; +id +42 +43 +SELECT * FROM t5_7b; +id +3 +347 +SELECT * FROM t10_1; +id +42 +43 +SELECT * FROM t10_1b; +id +3 +347 +DROP TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b; diff --git a/mysql-test/suite/innodb/t/autoinc_import.test b/mysql-test/suite/innodb/t/autoinc_import.test new file mode 100644 index 00000000000..e137413dfb5 --- /dev/null +++ b/mysql-test/suite/innodb/t/autoinc_import.test @@ -0,0 +1,168 @@ +--source include/have_innodb.inc + +CREATE TABLE t1 (id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES(42); +CREATE TABLE t1b LIKE t1; +INSERT INTO t1b VALUES(3); +CREATE TABLE t1z LIKE t1; +CREATE TABLE t1t (id TINYINT AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t0t LIKE t1t; +INSERT INTO t1t VALUES(123); +--let DATADIR=`select @@datadir` +--let PAGE_SIZE=`select @@innodb_page_size` +FLUSH TABLES t1,t1b,t1t FOR EXPORT; +--copy_file $DATADIR/test/t1.ibd $DATADIR/test/t.ibd +--copy_file $DATADIR/test/t1.ibd $DATADIR/test/tz.ibd +--copy_file $DATADIR/test/t1b.ibd $DATADIR/test/tb.ibd +--copy_file $DATADIR/test/t1t.ibd $DATADIR/test/tt.ibd +UNLOCK TABLES; +CREATE TABLE t5_7 LIKE t1; +CREATE TABLE t5_7b LIKE t1b; +CREATE TABLE t10_1 LIKE t1; +CREATE TABLE t10_1b LIKE t1b; +ALTER TABLE t1 DISCARD TABLESPACE; +ALTER TABLE t1b DISCARD TABLESPACE; +ALTER TABLE t1z DISCARD TABLESPACE; +ALTER TABLE t1t DISCARD TABLESPACE; +ALTER TABLE t0t DISCARD TABLESPACE; +ALTER TABLE t5_7 DISCARD TABLESPACE; +ALTER TABLE t5_7b DISCARD TABLESPACE; +ALTER TABLE t10_1 DISCARD TABLESPACE; +ALTER TABLE t10_1b DISCARD TABLESPACE; +FLUSH TABLES; + +# Update the PAGE_ROOT_AUTO_INC field of a few files. +perl; +do "$ENV{MTR_SUITE_DIR}/include/crc32.pl"; +sub update_autoinc +{ + my ($file, $value) = @_; + open(FILE, "+<$file") || die "Unable to open $file"; + binmode FILE; + my $ps= $ENV{PAGE_SIZE}; + my $page; + die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps; + my $full_crc32 = unpack("N",substr($page,54,4)) & 0x10; # FIL_SPACE_FLAGS + sysseek(FILE, 3*$ps, 0) || die "Unable to seek $file\n"; + die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps; + substr($page,56,8)=pack("NN",0,$value); + my $polynomial = 0x82f63b78; # CRC-32C + if ($full_crc32) { + my $ck = mycrc32(substr($page, 0, $ps-4), 0, $polynomial); + substr($page, $ps-4, 4) = pack("N", $ck); + } + else + { + my $ck= pack("N",mycrc32(substr($page, 4, 22), 0, $polynomial) ^ + mycrc32(substr($page, 38, $ps - 38 - 8), 0, $polynomial)); + substr($page,0,4)=$ck; + substr($page,$ps-8,4)=$ck; + } + sysseek(FILE, 3*$ps, 0) || die "Unable to rewind $file\n"; + syswrite(FILE, $page, $ps)==$ps || die "Unable to write $file\n"; + close(FILE) || die "Unable to close $file"; +} +update_autoinc("$ENV{DATADIR}/test/tz.ibd", 0); +update_autoinc("$ENV{DATADIR}/test/t.ibd", 3); +update_autoinc("$ENV{DATADIR}/test/tb.ibd", 346); +update_autoinc("$ENV{DATADIR}/test/tt.ibd", 128); +EOF + +--remove_file $DATADIR/test/t5_7.frm +--remove_file $DATADIR/test/t5_7b.frm +--copy_file $MYSQL_TEST_DIR/std_data/autoinc_import_57.frm $DATADIR/test/t5_7.frm +--copy_file $MYSQL_TEST_DIR/std_data/autoinc_import_57.frm $DATADIR/test/t5_7b.frm +--remove_file $DATADIR/test/t10_1.frm +--remove_file $DATADIR/test/t10_1b.frm +--copy_file $MYSQL_TEST_DIR/std_data/autoinc_import_101.frm $DATADIR/test/t10_1.frm +--copy_file $MYSQL_TEST_DIR/std_data/autoinc_import_101.frm $DATADIR/test/t10_1b.frm +--copy_file $DATADIR/test/t.ibd $DATADIR/test/t5_7.ibd +--copy_file $DATADIR/test/tb.ibd $DATADIR/test/t5_7b.ibd +--copy_file $DATADIR/test/t.ibd $DATADIR/test/t10_1.ibd +--copy_file $DATADIR/test/tb.ibd $DATADIR/test/t10_1b.ibd +--move_file $DATADIR/test/t.ibd $DATADIR/test/t1.ibd +--move_file $DATADIR/test/tb.ibd $DATADIR/test/t1b.ibd +--copy_file $DATADIR/test/tt.ibd $DATADIR/test/t0t.ibd +--move_file $DATADIR/test/tt.ibd $DATADIR/test/t1t.ibd +--move_file $DATADIR/test/tz.ibd $DATADIR/test/t1z.ibd + +ALTER TABLE t0t IMPORT TABLESPACE; +INSERT INTO t0t VALUES(NULL); +SELECT * FROM t0t; +DROP TABLE t0t; +ALTER TABLE t1 IMPORT TABLESPACE; +ALTER TABLE t1b IMPORT TABLESPACE; +ALTER TABLE t1z IMPORT TABLESPACE; +ALTER TABLE t1t IMPORT TABLESPACE; +ALTER TABLE t5_7 IMPORT TABLESPACE; +ALTER TABLE t5_7b IMPORT TABLESPACE; +ALTER TABLE t10_1 IMPORT TABLESPACE; +ALTER TABLE t10_1b IMPORT TABLESPACE; + +--let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let SEARCH_PATTERN= InnoDB: Resetting PAGE_ROOT_AUTO_INC from 128 to 123 on table `test`\.`t0t` +--source include/search_pattern_in_file.inc +--let SEARCH_PATTERN= InnoDB: Resetting PAGE_ROOT_AUTO_INC from 0 to 42 on table `test`\.`t1z` +--source include/search_pattern_in_file.inc +--let SEARCH_PATTERN= InnoDB: Resetting PAGE_ROOT_AUTO_INC from 128 to 123 on table `test`\.`t1t` +--source include/search_pattern_in_file.inc +--let SEARCH_PATTERN= InnoDB: Resetting PAGE_ROOT_AUTO_INC from 3 to 42 on table `test`\.`t5_7` \(created with version 50744\) +--source include/search_pattern_in_file.inc +--let SEARCH_PATTERN= InnoDB: Resetting PAGE_ROOT_AUTO_INC from 3 to 42 on table `test`\.`t10_1` \(created with version 100149\) +--source include/search_pattern_in_file.inc +--let SEARCH_PATTERN= InnoDB: Resetting PAGE_ROOT_AUTO_INC +--source include/search_pattern_in_file.inc + +# Restart, so that the InnoDB tables will be loaded into the data dictionary. +--let $restart_parameters=--read-only +--source include/restart_mysqld.inc + +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b; +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b FOR UPGRADE; + +--let $restart_parameters=--innodb-read-only --read-only +--source include/restart_mysqld.inc + +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b; +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b FOR UPGRADE; + +--let $restart_parameters=--innodb-read-only +--source include/restart_mysqld.inc + +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b; +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b FOR UPGRADE; + +SELECT COUNT(*) FROM t1; +SELECT COUNT(*) FROM t1b; +SELECT COUNT(*) FROM t1t; +SELECT COUNT(*) FROM t1z; +SELECT COUNT(*) FROM t5_7; +SELECT COUNT(*) FROM t5_7b; +SELECT COUNT(*) FROM t10_1; +SELECT COUNT(*) FROM t10_1b; + +--let $restart_parameters= +--source include/restart_mysqld.inc + +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b FOR UPGRADE; + +INSERT INTO t1 VALUES(NULL); +INSERT INTO t1b VALUES(NULL); +INSERT INTO t1t VALUES(NULL); +INSERT INTO t1z VALUES(NULL); +INSERT INTO t5_7 VALUES(NULL); +INSERT INTO t5_7b VALUES(NULL); +INSERT INTO t10_1 VALUES(NULL); +INSERT INTO t10_1b VALUES(NULL); + +CHECK TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b FOR UPGRADE; + +SELECT * FROM t1; +SELECT * FROM t1b; +SELECT * FROM t1t; +SELECT * FROM t1z; +SELECT * FROM t5_7; +SELECT * FROM t5_7b; +SELECT * FROM t10_1; +SELECT * FROM t10_1b; +DROP TABLE t1, t1b, t1t, t1z, t5_7, t5_7b, t10_1, t10_1b; diff --git a/sql/handler.cc b/sql/handler.cc index 2e2961bef5f..f4453a9aebb 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -4669,7 +4669,7 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt) if (unlikely((error= check(thd, check_opt)))) return error; /* Skip updating frm version if not main handler. */ - if (table->file != this) + if (table->file != this || opt_readonly) return error; return update_frm_version(table); } @@ -4718,7 +4718,7 @@ int handler::ha_repair(THD* thd, HA_CHECK_OPT* check_opt) DBUG_ASSERT(result == HA_ADMIN_NOT_IMPLEMENTED || ha_table_flags() & HA_CAN_REPAIR); - if (result == HA_ADMIN_OK) + if (result == HA_ADMIN_OK && !opt_readonly) result= update_frm_version(table); return result; } @@ -5659,7 +5659,7 @@ err: void st_ha_check_opt::init() { - flags= sql_flags= 0; + flags= sql_flags= handler_flags= 0; start_time= my_time(0); } diff --git a/sql/handler.h b/sql/handler.h index 67245850d62..f4d828285d5 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2615,6 +2615,7 @@ typedef struct st_ha_check_opt st_ha_check_opt() = default; /* Remove gcc warning */ uint flags; /* isam layer flags (e.g. for myisamchk) */ uint sql_flags; /* sql layer flags - for something myisamchk cannot do */ + uint handler_flags; /* Reserved for handler usage */ time_t start_time; /* When check/repair starts */ KEY_CACHE *key_cache; /* new key cache when changing key cache */ void init(); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 52d65ee46f6..a358d9c3351 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -5665,6 +5665,40 @@ extern "C" void *thd_mdl_context(MYSQL_THD thd) return &thd->mdl_context; } +/** + Send check/repair message to the user + + @param op one of check or repair + @param msg_type one of info, warning or error + @param print_to_log <> 0 if we should also print the message to error log. +*/ + +extern "C" void +print_check_msg(THD *thd, const char *db_name, const char *table_name, const char *op, + const char *msg_type, const char *message, my_bool print_to_log) +{ + char name[NAME_LEN * 2 + 2]; + Protocol *protocol= thd->protocol; + + DBUG_ASSERT(strlen(db_name) <= NAME_LEN); + DBUG_ASSERT(strlen(table_name) <= NAME_LEN); + + size_t length= size_t(strxnmov(name, sizeof name - 1, + db_name, ".", table_name, NullS) - + name); + protocol->prepare_for_resend(); + protocol->store(name, length, system_charset_info); + protocol->store(op, system_charset_info); + protocol->store(msg_type, system_charset_info); + protocol->store(message, system_charset_info); + if (protocol->write()) + sql_print_error("Failed on my_net_write, writing to stderr instead: %s: %s\n", + table_name, message); + else if (thd->variables.log_warnings > 2 && print_to_log) + sql_print_error("%s: table '%s' got '%s' during %s", + msg_type, table_name, message, op); +} + /**************************************************************************** Handling of statement states in functions and triggers. diff --git a/sql/sql_plugin_services.inl b/sql/sql_plugin_services.inl index 6b21f64bc64..e560812260a 100644 --- a/sql/sql_plugin_services.inl +++ b/sql/sql_plugin_services.inl @@ -18,6 +18,7 @@ #include #include #include +#include struct st_service_ref { const char *name; @@ -217,6 +218,11 @@ static struct my_print_error_service_st my_print_error_handler= my_printv_error }; +static struct print_check_msg_service_st print_check_msg_handler= +{ + print_check_msg +}; + struct json_service_st json_handler= { json_type, @@ -264,6 +270,7 @@ static struct st_service_ref list_of_services[]= { "my_crypt_service", VERSION_my_crypt, &crypt_handler}, { "my_md5_service", VERSION_my_md5, &my_md5_handler}, { "my_print_error_service", VERSION_my_print_error, &my_print_error_handler}, + { "print_check_msg_service", VERSION_print_check_msg, &print_check_msg_handler}, { "my_sha1_service", VERSION_my_sha1, &my_sha1_handler}, { "my_sha2_service", VERSION_my_sha2, &my_sha2_handler}, { "my_snprintf_service", VERSION_my_snprintf, &my_snprintf_handler }, diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 70d2178a5af..db57d31dd15 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -43,6 +43,7 @@ Created 6/2/1994 Heikki Tuuri #include "gis0geo.h" #include "dict0boot.h" #include "row0sel.h" /* row_search_max_autoinc() */ +#include "log.h" Atomic_counter btr_validate_index_running; @@ -1267,53 +1268,71 @@ btr_read_autoinc(dict_index_t* index) return autoinc; } +dict_index_t *dict_table_t::get_index(const dict_col_t &col) const +{ + dict_index_t *index= dict_table_get_first_index(this); + + while (index && (index->fields[0].col != &col || index->is_corrupted())) + index= dict_table_get_next_index(index); + + return index; +} + /** Read the last used AUTO_INCREMENT value from PAGE_ROOT_AUTO_INC, or fall back to MAX(auto_increment_column). -@param[in] table table containing an AUTO_INCREMENT column -@param[in] col_no index of the AUTO_INCREMENT column -@return the AUTO_INCREMENT value -@retval 0 on error or if no AUTO_INCREMENT value was used yet */ -ib_uint64_t -btr_read_autoinc_with_fallback(const dict_table_t* table, unsigned col_no) +@param table table containing an AUTO_INCREMENT column +@param col_no index of the AUTO_INCREMENT column +@param mysql_version TABLE_SHARE::mysql_version +@param max the maximum value of the AUTO_INCREMENT column +@return the AUTO_INCREMENT value +@retval 0 on error or if no AUTO_INCREMENT value was used yet */ +uint64_t btr_read_autoinc_with_fallback(const dict_table_t *table, + unsigned col_no, ulong mysql_version, + uint64_t max) { - ut_ad(table->persistent_autoinc); - ut_ad(!table->is_temporary()); + ut_ad(table->persistent_autoinc); + ut_ad(!table->is_temporary()); - dict_index_t* index = dict_table_get_first_index(table); + uint64_t autoinc= 0; + mtr_t mtr; + mtr.start(); - if (index == NULL) { - return 0; - } + if (buf_block_t *block= + buf_page_get(page_id_t(table->space_id, + dict_table_get_first_index(table)->page), + table->space->zip_size(), RW_SX_LATCH, &mtr)) + { + autoinc= page_get_autoinc(block->frame); - mtr_t mtr; - mtr.start(); - buf_block_t* block = buf_page_get( - page_id_t(index->table->space_id, index->page), - index->table->space->zip_size(), - RW_S_LATCH, &mtr); + if (autoinc > 0 && autoinc <= max && mysql_version >= 100210); + else if (dict_index_t *index= + table->get_index(*dict_table_get_nth_col(table, col_no))) + { + /* Read MAX(autoinc_col), in case this table had originally been + created before MariaDB 10.2.4 introduced persistent AUTO_INCREMENT + and MariaDB 10.2.10 fixed MDEV-12123, and there could be a garbage + value in the PAGE_ROOT_AUTO_INC field. */ + const uint64_t max_autoinc= row_search_max_autoinc(index); + const bool need_adjust{autoinc > max || autoinc < max_autoinc}; + ut_ad(max_autoinc <= max); - ib_uint64_t autoinc = block ? page_get_autoinc(block->frame) : 0; - const bool retry = block && autoinc == 0 - && !page_is_empty(block->frame); - mtr.commit(); + if (UNIV_UNLIKELY(need_adjust) && !high_level_read_only && !opt_readonly) + { + sql_print_information("InnoDB: Resetting PAGE_ROOT_AUTO_INC from " + UINT64PF " to " UINT64PF + " on table %`.*s.%`s (created with version %lu)", + autoinc, max_autoinc, + int(table->name.dblen()), table->name.m_name, + table->name.basename(), mysql_version); + autoinc= max_autoinc; + index->set_modified(mtr); + page_set_autoinc(block, max_autoinc, &mtr, true); + } + } + } - if (retry) { - /* This should be an old data file where - PAGE_ROOT_AUTO_INC was initialized to 0. - Fall back to reading MAX(autoinc_col). - There should be an index on it. */ - const dict_col_t* autoinc_col - = dict_table_get_nth_col(table, col_no); - while (index && index->fields[0].col != autoinc_col) { - index = dict_table_get_next_index(index); - } - - if (index) { - autoinc = row_search_max_autoinc(index); - } - } - - return autoinc; + mtr.commit(); + return autoinc; } /** Write the next available AUTO_INCREMENT value to PAGE_ROOT_AUTO_INC. diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 62b7fef4098..80c0df86d77 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -54,10 +54,13 @@ this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include #include "sql_type_geom.h" #include "scope.h" #include "srv0srv.h" +extern my_bool opt_readonly; + // MYSQL_PLUGIN_IMPORT extern my_bool lower_case_file_system; // MYSQL_PLUGIN_IMPORT extern char mysql_unpacked_real_data_home[]; @@ -117,6 +120,7 @@ this program; if not, write to the Free Software Foundation, Inc., #include "row0ext.h" #include +#include // TT_FOR_UPGRADE #define thd_get_trx_isolation(X) ((enum_tx_isolation)thd_tx_isolation(X)) @@ -5620,14 +5624,10 @@ func_exit: return ret; } -/********************************************************************//** -Get the upper limit of the MySQL integral and floating-point type. -@return maximum allowed value for the field */ -UNIV_INTERN -ulonglong -innobase_get_int_col_max_value( -/*===========================*/ - const Field* field) /*!< in: MySQL field */ +/** Get the maximum integer value of a numeric column. +@param field column definition +@return maximum allowed integer value */ +ulonglong innobase_get_int_col_max_value(const Field *field) { ulonglong max_value = 0; @@ -5691,46 +5691,45 @@ ha_innobase::open(). @param[in,out] table persistent table @param[in] field the AUTO_INCREMENT column */ -static -void -initialize_auto_increment(dict_table_t* table, const Field* field) +static void initialize_auto_increment(dict_table_t *table, const Field& field, + const TABLE_SHARE &s) { - ut_ad(!table->is_temporary()); + ut_ad(!table->is_temporary()); + const unsigned col_no= innodb_col_no(&field); + table->autoinc_mutex.lock(); + table->persistent_autoinc= + uint16_t(dict_table_get_nth_col_pos(table, col_no, nullptr) + 1) & + dict_index_t::MAX_N_FIELDS; + if (table->autoinc) + /* Already initialized. Our caller checked + table->persistent_autoinc without + autoinc_mutex protection, and there might be multiple + ha_innobase::open() executing concurrently. */; + else if (srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN) + /* If innodb_force_recovery is set so high that writes + are disabled we force the AUTOINC counter to 0 + value effectively disabling writes to the table. + Secondly, we avoid reading the table in case the read + results in failure due to a corrupted table/index. - const unsigned col_no = innodb_col_no(field); + We will not return an error to the client, so that the + tables can be dumped with minimal hassle. If an error + were returned in this case, the first attempt to read + the table would fail and subsequent SELECTs would succeed. */; + else if (table->persistent_autoinc) + { + uint64_t max_value= innobase_get_int_col_max_value(&field); + table->autoinc= + innobase_next_autoinc(btr_read_autoinc_with_fallback(table, col_no, + s.mysql_version, + max_value), + 1 /* need */, + 1 /* auto_increment_increment */, + 0 /* auto_increment_offset */, + max_value); + } - table->autoinc_mutex.lock(); - - table->persistent_autoinc = static_cast( - dict_table_get_nth_col_pos(table, col_no, NULL) + 1) - & dict_index_t::MAX_N_FIELDS; - - if (table->autoinc) { - /* Already initialized. Our caller checked - table->persistent_autoinc without - autoinc_mutex protection, and there might be multiple - ha_innobase::open() executing concurrently. */ - } else if (srv_force_recovery > SRV_FORCE_NO_IBUF_MERGE) { - /* If the recovery level is set so high that writes - are disabled we force the AUTOINC counter to 0 - value effectively disabling writes to the table. - Secondly, we avoid reading the table in case the read - results in failure due to a corrupted table/index. - - We will not return an error to the client, so that the - tables can be dumped with minimal hassle. If an error - were returned in this case, the first attempt to read - the table would fail and subsequent SELECTs would succeed. */ - } else if (table->persistent_autoinc) { - table->autoinc = innobase_next_autoinc( - btr_read_autoinc_with_fallback(table, col_no), - 1 /* need */, - 1 /* auto_increment_increment */, - 0 /* auto_increment_offset */, - innobase_get_int_col_max_value(field)); - } - - table->autoinc_mutex.unlock(); + table->autoinc_mutex.unlock(); } /** Open an InnoDB table @@ -5966,7 +5965,7 @@ ha_innobase::open(const char* name, int, uint) || m_prebuilt->table->persistent_autoinc || !m_prebuilt->table->is_readable()) { } else if (const Field* ai = table->found_next_number_field) { - initialize_auto_increment(m_prebuilt->table, ai); + initialize_auto_increment(m_prebuilt->table, *ai, *table->s); } /* Set plugin parser for fulltext index */ @@ -14822,12 +14821,34 @@ ha_innobase::check( ulint n_rows_in_table = ULINT_UNDEFINED; bool is_ok = true; dberr_t ret; + uint handler_flags= check_opt->handler_flags; DBUG_ENTER("ha_innobase::check"); DBUG_ASSERT(thd == ha_thd()); ut_a(m_prebuilt->trx->magic_n == TRX_MAGIC_N); ut_a(m_prebuilt->trx == thd_to_trx(thd)); + if (handler_flags || check_for_upgrade(check_opt)) { + /* The file was already checked and fixed as part of open */ + print_check_msg(thd, table->s->db.str, table->s->table_name.str, + "check", "note", + (opt_readonly || high_level_read_only + || !(check_opt->sql_flags & TT_FOR_UPGRADE)) + ? "Auto_increment will be" + " checked on each open until" + " CHECK TABLE FOR UPGRADE is executed" + : "Auto_increment checked and" + " .frm file version updated", 1); + if (handler_flags && (check_opt->sql_flags & TT_FOR_UPGRADE)) { + /* + No other issues found (as handler_flags was only + set if there as not other problems with the table + than auto_increment). + */ + DBUG_RETURN(HA_ADMIN_OK); + } + } + if (m_prebuilt->mysql_template == NULL) { /* Build the template; we will use a dummy template in index scans done in checking */ @@ -15053,6 +15074,35 @@ ha_innobase::check( DBUG_RETURN(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT); } +/** +Check if we there is a problem with the InnoDB table. +@param check_opt check options +@retval HA_ADMIN_OK if Table is ok +@retval HA_ADMIN_NEEDS_ALTER User should run ALTER TABLE FOR UPGRADE +@retval HA_ADMIN_NEEDS_CHECK User should run CHECK TABLE FOR UPGRADE +@retval HA_ADMIN_FAILED if InnoDB is in read-only mode */ +int ha_innobase::check_for_upgrade(HA_CHECK_OPT *check_opt) +{ + /* + Check if there is a possibility that the auto increment value + stored in PAGE_ROOT_AUTO_INC could be corrupt. + */ + if (table->s->mysql_version >= 100210); + else if (const Field *auto_increment= table->found_next_number_field) + { + uint col_no= innodb_col_no(auto_increment); + const dict_col_t *autoinc_col= + dict_table_get_nth_col(m_prebuilt->table, col_no); + if (m_prebuilt->table->get_index(*autoinc_col)) + { + check_opt->handler_flags= 1; + return (high_level_read_only && !opt_readonly) + ? HA_ADMIN_FAILED : HA_ADMIN_NEEDS_CHECK; + } + } + return HA_ADMIN_OK; +} + /*******************************************************************//** Gets the foreign key create info for a table stored in InnoDB. @return own: character string in the form which can be inserted to the diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 13d36e71e40..ba4f5b62f90 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -207,6 +207,7 @@ public: int rename_table(const char* from, const char* to) override; inline int defragment_table(const char* name); int check(THD* thd, HA_CHECK_OPT* check_opt) override; + int check_for_upgrade(HA_CHECK_OPT* check_opt) override; inline void reload_statistics(); @@ -944,6 +945,12 @@ unsigned innodb_col_no(const Field* field) MY_ATTRIBUTE((nonnull, warn_unused_result)); +/** Get the maximum integer value of a numeric column. +@param field column definition +@return maximum allowed integer value */ +ulonglong innobase_get_int_col_max_value(const Field *field) + MY_ATTRIBUTE((nonnull, warn_unused_result)); + /********************************************************************//** Helper function to push frm mismatch error to error log and if needed to sql-layer. */ diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 3737886814b..7e3979dce85 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -1179,15 +1179,6 @@ private: ha_innobase_inplace_ctx& operator=(const ha_innobase_inplace_ctx&); }; -/********************************************************************//** -Get the upper limit of the MySQL integral and floating-point type. -@return maximum allowed value for the field */ -UNIV_INTERN -ulonglong -innobase_get_int_col_max_value( -/*===========================*/ - const Field* field); /*!< in: MySQL field */ - /* Report an InnoDB error to the client by invoking my_error(). */ static ATTRIBUTE_COLD __attribute__((nonnull)) void @@ -9736,13 +9727,7 @@ commit_set_autoinc( const dict_col_t* autoinc_col = dict_table_get_nth_col(ctx->old_table, innodb_col_no(ai)); - dict_index_t* index - = dict_table_get_first_index(ctx->old_table); - while (index != NULL - && index->fields[0].col != autoinc_col) { - index = dict_table_get_next_index(index); - } - + auto index = ctx->old_table->get_index(*autoinc_col); ut_ad(index); ib_uint64_t max_in_table = index diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index c0dcc6f39d3..be5a16a2e6d 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -372,13 +372,16 @@ btr_read_autoinc(dict_index_t* index) /** Read the last used AUTO_INCREMENT value from PAGE_ROOT_AUTO_INC, or fall back to MAX(auto_increment_column). -@param[in] table table containing an AUTO_INCREMENT column -@param[in] col_no index of the AUTO_INCREMENT column -@return the AUTO_INCREMENT value -@retval 0 on error or if no AUTO_INCREMENT value was used yet */ -ib_uint64_t -btr_read_autoinc_with_fallback(const dict_table_t* table, unsigned col_no) - MY_ATTRIBUTE((nonnull, warn_unused_result)); +@param table table containing an AUTO_INCREMENT column +@param col_no index of the AUTO_INCREMENT column +@param mysql_version TABLE_SHARE::mysql_version +@param max the maximum value of the AUTO_INCREMENT column +@return the AUTO_INCREMENT value +@retval 0 on error or if no AUTO_INCREMENT value was used yet */ +uint64_t btr_read_autoinc_with_fallback(const dict_table_t *table, + unsigned col_no, ulong mysql_version, + uint64_t max) + MY_ATTRIBUTE((nonnull, warn_unused_result)); /** Write the next available AUTO_INCREMENT value to PAGE_ROOT_AUTO_INC. @param[in,out] index clustered index diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 0a28a6a9868..b2d7b647c85 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -2366,6 +2366,9 @@ public: /** @return number of unique columns in FTS_DOC_ID index */ unsigned fts_n_uniq() const { return versioned() ? 2 : 1; } + + /** @return the index for that starts with a specific column */ + dict_index_t *get_index(const dict_col_t &col) const; }; inline void dict_index_t::set_modified(mtr_t& mtr) const diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 7644091b21c..1b1eecada5b 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -48,6 +48,8 @@ Created 2012-02-08 by Sunny Bains. #include "snappy-c.h" #endif #include "log.h" +#include "table.h" +#include "ha_innodb.h" #include "scope.h" @@ -4333,6 +4335,37 @@ fil_tablespace_iterate( return(err); } +static void row_import_autoinc(dict_table_t *table, row_prebuilt_t *prebuilt, + uint64_t autoinc) +{ + if (!table->persistent_autoinc) + { + ut_ad(!autoinc); + return; + } + + if (autoinc) + { + btr_write_autoinc(dict_table_get_first_index(table), autoinc - 1); + autoinc_set: + table->autoinc= autoinc; + sql_print_information("InnoDB: %`.*s.%`s autoinc value set to " UINT64PF, + int(table->name.dblen()), table->name.m_name, + table->name.basename(), autoinc); + } + else if (TABLE *t= prebuilt->m_mysql_table) + { + if (const Field *ai= t->found_next_number_field) + { + autoinc= 1 + + btr_read_autoinc_with_fallback(table, innodb_col_no(ai), + t->s->mysql_version, + innobase_get_int_col_max_value(ai)); + goto autoinc_set; + } + } +} + /*****************************************************************//** Imports a tablespace. The space id in the .ibd file must match the space id of the table in the data dictionary. @@ -4719,16 +4752,7 @@ row_import_for_mysql( /* Set autoinc value read from .cfg file, if one was specified. Otherwise, read the PAGE_ROOT_AUTO_INC and set it to table autoinc. */ - if (autoinc) { - ib::info() << table->name << " autoinc value set to " - << autoinc; - - table->autoinc = autoinc--; - btr_write_autoinc(dict_table_get_first_index(table), autoinc); - } else if (table->persistent_autoinc) { - autoinc = btr_read_autoinc(dict_table_get_first_index(table)); - table->autoinc = ++autoinc; - } + row_import_autoinc(table, prebuilt, autoinc); return(row_import_cleanup(prebuilt, trx, err)); } diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 35d1aa52bcd..e5ae6d052ee 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -45,6 +45,7 @@ C_MODE_END #include "key.h" #include "log.h" #include "sql_parse.h" +#include "mysql/service_print_check_msg.h" /* Note that in future versions, only *transactional* Maria tables can @@ -427,10 +428,8 @@ static void _ma_check_print_msg(HA_CHECK *param, const char *msg_type, const char *fmt, va_list args) { THD *thd= (THD *) param->thd; - Protocol *protocol= thd->protocol; - size_t length, msg_length; + size_t msg_length __attribute__((unused)); char msgbuf[MYSQL_ERRMSG_SIZE]; - char name[NAME_LEN * 2 + 2]; if (param->testflag & T_SUPPRESS_ERR_HANDLING) return; @@ -459,27 +458,10 @@ static void _ma_check_print_msg(HA_CHECK *param, const char *msg_type, _ma_check_print(param, msg_type, msgbuf); return; } - length= (uint) (strxmov(name, param->db_name, ".", param->table_name, - NullS) - name); - /* - TODO: switch from protocol to push_warning here. The main reason we didn't - it yet is parallel repair, which threads have no THD object accessible via - current_thd. - - Also we likely need to lock mutex here (in both cases with protocol and - push_warning). - */ - protocol->prepare_for_resend(); - protocol->store(name, (uint)length, system_charset_info); - protocol->store(param->op_name, system_charset_info); - protocol->store(msg_type, system_charset_info); - protocol->store(msgbuf, (uint)msg_length, system_charset_info); - if (protocol->write()) - sql_print_error("Failed on my_net_write, writing to stderr instead: %s.%s: %s\n", - param->db_name, param->table_name, msgbuf); - else if (thd->variables.log_warnings > 2) + print_check_msg(thd, param->db_name, param->table_name, + param->op_name, msg_type, msgbuf, 0); + if (thd->variables.log_warnings > 2) _ma_check_print(param, msg_type, msgbuf); - return; }