From 2bf6abdc3e8a7e61b116b81742333e8045453947 Mon Sep 17 00:00:00 2001 From: Sutou Kouhei Date: Tue, 20 Jul 2021 16:32:57 +0900 Subject: [PATCH] MDEV-39556 SIGSEGV in ha_mroonga::storage_set_keys_in_use on SELECT Many pathes exist for Mroonga to open tables without opening indexes. Altering from another storage engine and accessing the information schema statistics is one mechanism. The fix is a backport from upstream. Backport from https://github.com/mroonga/mroonga/commit/0b3541910ede845f6ccb62241a633310f2c27f52#diff-c026dc94c7f79d426e7a68e1e69fdc0f7743296a37d6cd19c9e7117a763f242e Fix a crash bug that may be caused after MySQL/MariaDB upgrade GitHub: fix GH-423 MySQL/MariaDB may open Mroonga tables by "CHECK TABLES" when MySQL/MariaDB is upgraded. Mroonga didn't open indexes when a table is opened by "CHECK TABLES". If "REPAIR TABLE" is needed, a table is reopened. If "REPAIR TABLE" isn't needed, a table is NOT reopened. The table doesn't open indexes. "SELECT ... MATCH AGAINST" for the table causes a crash. Reported by Vincent Pelletier. Thanks!!! Backported to MariaDB by Daniel Black --- storage/mroonga/ha_mroonga.cpp | 74 +++++++++---------- .../storage/r/check_table_broken.result | 7 +- .../storage/r/check_table_innodb.result | 13 ++++ .../r/repair_table_no_index_file.result | 1 + .../mroonga/storage/t/check_table_broken.test | 7 +- .../mroonga/storage/t/check_table_innodb.test | 15 ++++ .../storage/t/repair_table_no_index_file.test | 1 + .../wrapper/r/repair_table_no_files.result | 1 + .../r/repair_table_no_index_file.result | 1 + .../wrapper/t/repair_table_no_index_file.test | 1 + 10 files changed, 79 insertions(+), 42 deletions(-) create mode 100644 storage/mroonga/mysql-test/mroonga/storage/r/check_table_innodb.result create mode 100644 storage/mroonga/mysql-test/mroonga/storage/t/check_table_innodb.test diff --git a/storage/mroonga/ha_mroonga.cpp b/storage/mroonga/ha_mroonga.cpp index 46546905bda61..240d0ab6efc14 100644 --- a/storage/mroonga/ha_mroonga.cpp +++ b/storage/mroonga/ha_mroonga.cpp @@ -4287,18 +4287,15 @@ int ha_mroonga::wrapper_open(const char *name, int mode, uint open_options) if (error) DBUG_RETURN(error); - if (!(open_options & HA_OPEN_FOR_REPAIR)) { - error = open_table(name); - if (error) - DBUG_RETURN(error); + error = open_table(name); + if (error && !(open_options & HA_OPEN_FOR_REPAIR)) + goto error_exit; - error = wrapper_open_indexes(name); - if (error) { - grn_obj_unlink(ctx, grn_table); - grn_table = NULL; - DBUG_RETURN(error); - } - } + error = wrapper_open_indexes(name); + if (error && !(open_options & HA_OPEN_FOR_REPAIR)) + goto error_exit; + + error = 0; mrn_init_alloc_root(&mem_root, 1024, 0, MYF(0)); wrap_key_info = mrn_create_key_info_for_table(share, table, &error); @@ -4386,6 +4383,7 @@ int ha_mroonga::wrapper_open(const char *name, int mode, uint open_options) } } +error_exit: if (error) { grn_obj_unlink(ctx, grn_table); @@ -4658,37 +4656,35 @@ int ha_mroonga::storage_open(const char *name, int mode, uint open_options) DBUG_RETURN(error); } - if (!(open_options & HA_OPEN_FOR_REPAIR)) { - error = storage_open_indexes(name); - if (error) { - storage_close_columns(); - grn_obj_unlink(ctx, grn_table); - grn_table = NULL; - DBUG_RETURN(error); - } + error = storage_open_indexes(name); + if (error && !(open_options & HA_OPEN_FOR_REPAIR)) { + storage_close_columns(); + grn_obj_unlink(ctx, grn_table); + grn_table = NULL; + DBUG_RETURN(error); + } - storage_set_keys_in_use(); + storage_set_keys_in_use(); - { - mrn::Lock lock(&mrn_operations_mutex); - mrn::PathMapper mapper(name); - const char *table_name = mapper.table_name(); - size_t table_name_size = strlen(table_name); - if (db->is_broken_table(table_name, table_name_size)) { - GRN_LOG(ctx, GRN_LOG_NOTICE, - "Auto repair is started: <%s>", - name); - error = operations_->repair(table_name, table_name_size); + if (!(open_options & HA_OPEN_FOR_REPAIR)) { + mrn::Lock lock(&mrn_operations_mutex); + mrn::PathMapper mapper(name); + const char *table_name = mapper.table_name(); + size_t table_name_size = strlen(table_name); + if (db->is_broken_table(table_name, table_name_size)) { + GRN_LOG(ctx, GRN_LOG_NOTICE, + "Auto repair is started: <%s>", + name); + error = operations_->repair(table_name, table_name_size); + if (!error) + db->mark_table_repaired(table_name, table_name_size); + if (!share->disable_keys) { if (!error) - db->mark_table_repaired(table_name, table_name_size); - if (!share->disable_keys) { - if (!error) - error = storage_reindex(); - } - GRN_LOG(ctx, GRN_LOG_NOTICE, - "Auto repair is done: <%s>: %s", - name, error == 0 ? "success" : "failure"); + error = storage_reindex(); } + GRN_LOG(ctx, GRN_LOG_NOTICE, + "Auto repair is done: <%s>: %s", + name, error == 0 ? "success" : "failure"); } } @@ -5233,7 +5229,7 @@ void ha_mroonga::storage_set_keys_in_use() if (i == table_share->primary_key) { continue; } - if (!grn_index_tables[i]) { + if (grn_index_tables && !grn_index_tables[i]) { /* disabled */ table_share->keys_in_use.clear_bit(i); DBUG_PRINT("info", ("mroonga: key %u disabled", i)); diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/check_table_broken.result b/storage/mroonga/mysql-test/mroonga/storage/r/check_table_broken.result index 4926a72a77af4..1ed049583d25f 100644 --- a/storage/mroonga/mysql-test/mroonga/storage/r/check_table_broken.result +++ b/storage/mroonga/mysql-test/mroonga/storage/r/check_table_broken.result @@ -9,10 +9,15 @@ INSERT INTO diaries VALUES ('Hello'); FLUSH TABLES; CHECK TABLE diaries; Table Op Msg_type Msg_text -check_test.diaries check error Corrupt +check_test.diaries check status OK REPAIR TABLE diaries; Table Op Msg_type Msg_text check_test.diaries repair status OK +SELECT * +FROM diaries +WHERE MATCH(title) AGAINST('+Hello' IN BOOLEAN MODE); +title +Hello DROP TABLE diaries; DROP DATABASE check_test; USE test; diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/check_table_innodb.result b/storage/mroonga/mysql-test/mroonga/storage/r/check_table_innodb.result new file mode 100644 index 0000000000000..628a33af7f965 --- /dev/null +++ b/storage/mroonga/mysql-test/mroonga/storage/r/check_table_innodb.result @@ -0,0 +1,13 @@ +# +# MDEV-39556 SIGSEGV in ha_mroonga::storage_set_keys_in_use on SELECT +# +CREATE TABLE t (c INT KEY,c2 GEOMETRY NOT NULL,SPATIAL INDEX idx_sp (c2)) ENGINE=InnoDB; +ALTER TABLE t ENGINE=Mroonga; +CHECK TABLE t; +Table Op Msg_type Msg_text +test.t check status OK +SELECT COUNT(*) > 0 AS r FROM information_schema.STATISTICS; +r +1 +DROP TABLE t; +# End of 10.6 tests diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/repair_table_no_index_file.result b/storage/mroonga/mysql-test/mroonga/storage/r/repair_table_no_index_file.result index 24d427ed2ab72..f58b3916eaf79 100644 --- a/storage/mroonga/mysql-test/mroonga/storage/r/repair_table_no_index_file.result +++ b/storage/mroonga/mysql-test/mroonga/storage/r/repair_table_no_index_file.result @@ -17,6 +17,7 @@ SELECT * FROM diaries WHERE MATCH(body) AGAINST("+starting" IN BOOLEAN MODE); ERROR HY000: system call error: No such file or directory: failed to open path: REPAIR TABLE diaries; Table Op Msg_type Msg_text +repair_test.diaries repair Error system call error: No such file or directory: failed to open path: repair_test.diaries repair status OK SELECT * FROM diaries; id title body diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/check_table_broken.test b/storage/mroonga/mysql-test/mroonga/storage/t/check_table_broken.test index d438a912ae28a..73b8cc8eb32cd 100644 --- a/storage/mroonga/mysql-test/mroonga/storage/t/check_table_broken.test +++ b/storage/mroonga/mysql-test/mroonga/storage/t/check_table_broken.test @@ -30,13 +30,16 @@ CREATE TABLE diaries ( INSERT INTO diaries VALUES ('Hello'); ---remove_file $MYSQLD_DATADIR/check_test.mrn.000010C - FLUSH TABLES; CHECK TABLE diaries; REPAIR TABLE diaries; + +SELECT * + FROM diaries + WHERE MATCH(title) AGAINST('+Hello' IN BOOLEAN MODE); + DROP TABLE diaries; DROP DATABASE check_test; diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/check_table_innodb.test b/storage/mroonga/mysql-test/mroonga/storage/t/check_table_innodb.test new file mode 100644 index 0000000000000..2ad0df05d67f5 --- /dev/null +++ b/storage/mroonga/mysql-test/mroonga/storage/t/check_table_innodb.test @@ -0,0 +1,15 @@ +--source include/have_innodb.inc + +--echo # +--echo # MDEV-39556 SIGSEGV in ha_mroonga::storage_set_keys_in_use on SELECT +--echo # + +CREATE TABLE t (c INT KEY,c2 GEOMETRY NOT NULL,SPATIAL INDEX idx_sp (c2)) ENGINE=InnoDB; + +ALTER TABLE t ENGINE=Mroonga; +CHECK TABLE t; +SELECT COUNT(*) > 0 AS r FROM information_schema.STATISTICS; + +DROP TABLE t; + +--echo # End of 10.6 tests diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/repair_table_no_index_file.test b/storage/mroonga/mysql-test/mroonga/storage/t/repair_table_no_index_file.test index 0f04bd3e4232e..63624a9d56e4b 100644 --- a/storage/mroonga/mysql-test/mroonga/storage/t/repair_table_no_index_file.test +++ b/storage/mroonga/mysql-test/mroonga/storage/t/repair_table_no_index_file.test @@ -43,6 +43,7 @@ FLUSH TABLES; --error ER_CANT_OPEN_FILE SELECT * FROM diaries WHERE MATCH(body) AGAINST("+starting" IN BOOLEAN MODE); +--replace_result "[io][open] " "" REPAIR TABLE diaries; SELECT * FROM diaries; diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_files.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_files.result index 8258a03bf42c1..98de2e895188a 100644 --- a/storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_files.result +++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_files.result @@ -17,6 +17,7 @@ SELECT * FROM diaries WHERE MATCH(body) AGAINST("starting"); ERROR HY000: mroonga: failed to open table: REPAIR TABLE diaries; Table Op Msg_type Msg_text +repair_test.diaries repair Error mroonga: failed to open table: repair_test.diaries repair status OK SELECT * FROM diaries; id title body diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_index_file.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_index_file.result index cca7aee95de8a..271c086c4b3d6 100644 --- a/storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_index_file.result +++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_index_file.result @@ -17,6 +17,7 @@ SELECT * FROM diaries WHERE MATCH(body) AGAINST("starting"); ERROR HY000: system call error: No such file or directory: failed to open path: REPAIR TABLE diaries; Table Op Msg_type Msg_text +repair_test.diaries repair Error system call error: No such file or directory: failed to open path: repair_test.diaries repair status OK SELECT * FROM diaries; id title body diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/repair_table_no_index_file.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/repair_table_no_index_file.test index 2fefadc254d0e..5061a268d8abf 100644 --- a/storage/mroonga/mysql-test/mroonga/wrapper/t/repair_table_no_index_file.test +++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/repair_table_no_index_file.test @@ -44,6 +44,7 @@ FLUSH TABLES; --error ER_CANT_OPEN_FILE SELECT * FROM diaries WHERE MATCH(body) AGAINST("starting"); +--replace_result "[io][open] " "" REPAIR TABLE diaries; SELECT * FROM diaries;