diff --git a/mysql-test/suite/maria/fulltext_parser-master.opt b/mysql-test/suite/maria/fulltext_parser-master.opt new file mode 100644 index 0000000000000..79c596c97e106 --- /dev/null +++ b/mysql-test/suite/maria/fulltext_parser-master.opt @@ -0,0 +1,2 @@ +--aria-checkpoint-interval=0 +--aria-recover-options=OFF diff --git a/mysql-test/suite/maria/fulltext_parser.result b/mysql-test/suite/maria/fulltext_parser.result new file mode 100644 index 0000000000000..164ea3dabbac9 --- /dev/null +++ b/mysql-test/suite/maria/fulltext_parser.result @@ -0,0 +1,150 @@ +INSTALL PLUGIN simple_parser SONAME 'mypluglib'; +# Fulltext parser with ROW_FORMAT=PAGE +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) ENGINE=Aria ROW_FORMAT=PAGE TRANSACTIONAL=1; +INSERT INTO t1 VALUES ('abc-def'), ('abcd-efgh'), ('other text'); +RENAME TABLE t1 TO t2; +SELECT a FROM t2 WHERE MATCH(a) AGAINST('abc-def abcd'); +a +abc-def +DROP TABLE t2; +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) ENGINE=Aria ROW_FORMAT=PAGE TRANSACTIONAL=1; +INSERT INTO t1 VALUES ('abc-def'), ('abcd-efgh'), ('other text'); +ALTER TABLE t1 ADD COLUMN b INT, ALGORITHM=COPY; +SELECT a FROM t1 WHERE MATCH(a) AGAINST('abc-def abcd'); +a +abc-def +DROP TABLE t1; +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) ENGINE=Aria ROW_FORMAT=PAGE TRANSACTIONAL=1; +INSERT INTO t1 VALUES ('abc-def'), ('abcd-efgh'), ('other text'); +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair status OK +SELECT a FROM t1 WHERE MATCH(a) AGAINST('abc-def abcd'); +a +abc-def +DROP TABLE t1; +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) ENGINE=Aria ROW_FORMAT=PAGE TRANSACTIONAL=1; +INSERT INTO t1 VALUES ('abc-def'), ('abcd-efgh'), ('other text'); +REPAIR TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 repair status OK +SELECT a FROM t1 WHERE MATCH(a) AGAINST('abc-def abcd'); +a +abc-def +DROP TABLE t1; +CREATE TABLE t1 (a TEXT) +ENGINE=Aria ROW_FORMAT=PAGE TRANSACTIONAL=1; +INSERT INTO t1 VALUES ('abc-def'), ('abcd-efgh'), ('other text'); +ALTER TABLE t1 ADD FULLTEXT(a) WITH PARSER simple_parser, ALGORITHM=COPY; +SELECT a FROM t1 WHERE MATCH(a) AGAINST('abc-def abcd'); +a +abc-def +DROP TABLE t1; +# Fulltext parser with ROW_FORMAT=DYNAMIC +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) ENGINE=Aria ROW_FORMAT=DYNAMIC TRANSACTIONAL=0; +INSERT INTO t1 VALUES ('abc-def'), ('abcd-efgh'), ('other text'); +RENAME TABLE t1 TO t2; +SELECT a FROM t2 WHERE MATCH(a) AGAINST('abc-def abcd'); +a +abc-def +DROP TABLE t2; +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) ENGINE=Aria ROW_FORMAT=DYNAMIC TRANSACTIONAL=0; +INSERT INTO t1 VALUES ('abc-def'), ('abcd-efgh'), ('other text'); +ALTER TABLE t1 ADD COLUMN b INT, ALGORITHM=COPY; +SELECT a FROM t1 WHERE MATCH(a) AGAINST('abc-def abcd'); +a +abc-def +DROP TABLE t1; +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) ENGINE=Aria ROW_FORMAT=DYNAMIC TRANSACTIONAL=0; +INSERT INTO t1 VALUES ('abc-def'), ('abcd-efgh'), ('other text'); +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair status OK +SELECT a FROM t1 WHERE MATCH(a) AGAINST('abc-def abcd'); +a +abc-def +DROP TABLE t1; +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) ENGINE=Aria ROW_FORMAT=DYNAMIC TRANSACTIONAL=0; +INSERT INTO t1 VALUES ('abc-def'), ('abcd-efgh'), ('other text'); +REPAIR TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 repair status OK +SELECT a FROM t1 WHERE MATCH(a) AGAINST('abc-def abcd'); +a +abc-def +DROP TABLE t1; +CREATE TABLE t1 (a TEXT) +ENGINE=Aria ROW_FORMAT=DYNAMIC TRANSACTIONAL=0; +INSERT INTO t1 VALUES ('abc-def'), ('abcd-efgh'), ('other text'); +ALTER TABLE t1 ADD FULLTEXT(a) WITH PARSER simple_parser, ALGORITHM=COPY; +SELECT a FROM t1 WHERE MATCH(a) AGAINST('abc-def abcd'); +a +abc-def +DROP TABLE t1; +# Recover committed rows written after the last checkpoint +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) +ENGINE=Aria ROW_FORMAT=PAGE TRANSACTIONAL=1; +INSERT INTO t1 VALUES ('abc-def'), ('baseline-two'), ('baseline-three'); +CREATE TABLE t_flush (a INT) ENGINE=Aria TRANSACTIONAL=1; +INSERT INTO t_flush VALUES (0); +# restart +INSERT INTO t1 VALUES ('commit-one'), ('commit-two'); +# restart +SELECT a FROM t1 ORDER BY a; +a +abc-def +baseline-three +baseline-two +commit-one +commit-two +SELECT a FROM t1 WHERE MATCH(a) AGAINST('commit-one commit-two') ORDER BY a; +a +commit-one +commit-two +CHECK TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check status OK +# Roll back row and fulltext key changes without loading the parser +connect writer,localhost,root,,test; +LOCK TABLES t1 WRITE; +INSERT INTO t1 VALUES ('undo-insert'); +UPDATE t1 SET a = 'undo-update' WHERE a = 'abc-def'; +DELETE FROM t1 WHERE a = 'baseline-two'; +connection default; +INSERT INTO t_flush VALUES (1); +# restart +disconnect writer; +include/assert_grep.inc [Recovery rolled back the writer transaction] +include/assert_grep.inc [Recovery did not skip UNDO records] +SELECT a FROM t1 ORDER BY a; +a +abc-def +baseline-three +baseline-two +commit-one +commit-two +SELECT a FROM t1 +WHERE MATCH(a) AGAINST('abc-def baseline-two undo-insert undo-update') +ORDER BY a; +a +abc-def +baseline-two +CHECK TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check status OK +# Recover a completed bulk-insert repair with a parser plugin +CREATE TABLE t_src (a TEXT) ENGINE=Aria; +INSERT INTO t_src VALUES ('abc-def'), ('abcd-efgh'), ('other text'); +CREATE TABLE t2 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) +ENGINE=Aria ROW_FORMAT=PAGE TRANSACTIONAL=1; +INSERT INTO t2 SELECT a FROM t_src; +# restart +SELECT a FROM t2 WHERE MATCH(a) AGAINST('abc-def abcd'); +a +abc-def +CHECK TABLE t2 EXTENDED; +Table Op Msg_type Msg_text +test.t2 check status OK +DROP TABLE t2, t_src; +DROP TABLE t1, t_flush; +UNINSTALL PLUGIN simple_parser; diff --git a/mysql-test/suite/maria/fulltext_parser.test b/mysql-test/suite/maria/fulltext_parser.test new file mode 100644 index 0000000000000..799d1ffb602e5 --- /dev/null +++ b/mysql-test/suite/maria/fulltext_parser.test @@ -0,0 +1,87 @@ +--source include/have_maria.inc +--source include/have_simple_parser.inc +--source include/not_embedded.inc + +INSTALL PLUGIN simple_parser SONAME 'mypluglib'; + +# simple_parser keeps punctuation in words: 'abc-def abcd' finds +# 'abc-def', but not the fragment 'abcd' of 'abcd-efgh'. +--let $row_format= PAGE +--let $transactional= 1 +--source suite/maria/include/fulltext_parser_ops.inc +--let $row_format= DYNAMIC +--let $transactional= 0 +--source suite/maria/include/fulltext_parser_ops.inc + +--echo # Recover committed rows written after the last checkpoint +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) + ENGINE=Aria ROW_FORMAT=PAGE TRANSACTIONAL=1; +INSERT INTO t1 VALUES ('abc-def'), ('baseline-two'), ('baseline-three'); +CREATE TABLE t_flush (a INT) ENGINE=Aria TRANSACTIONAL=1; +INSERT INTO t_flush VALUES (0); + +# A clean restart establishes the on-disk baseline. The .opt file disables +# periodic checkpoints and automatic repair, so they cannot hide failures. +--source include/restart_mysqld.inc +INSERT INTO t1 VALUES ('commit-one'), ('commit-two'); +--let $shutdown_timeout= 0 +--source include/restart_mysqld.inc + +# Check the recovered data and index before CHECK TABLE or REPAIR can help. +SELECT a FROM t1 ORDER BY a; +SELECT a FROM t1 WHERE MATCH(a) AGAINST('commit-one commit-two') ORDER BY a; +CHECK TABLE t1 EXTENDED; + +--echo # Roll back row and fulltext key changes without loading the parser +# Aria defers its commit until UNLOCK TABLES, unlike ordinary statements. +--connect (writer,localhost,root,,test) +LOCK TABLES t1 WRITE; +INSERT INTO t1 VALUES ('undo-insert'); +UPDATE t1 SET a = 'undo-update' WHERE a = 'abc-def'; +DELETE FROM t1 WHERE a = 'baseline-two'; + +--connection default +# Committing another Aria table flushes the preceding UNDO and REDO records +# without committing the writer or flushing t1's dirty pages. +INSERT INTO t_flush VALUES (1); +--let $shutdown_timeout= 0 +--source include/restart_mysqld.inc +--disconnect writer + +# The row checks alone could pass if recovery skipped t1 and its changes +# never reached disk. Require a completed rollback with no skipped UNDO +# records from this restart; the writer is the only uncommitted transaction. +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let $assert_only_after= Starting MariaDB +--let $assert_text= Recovery rolled back the writer transaction +--let $assert_select= transactions to roll back: 1 0 +--let $assert_count= 1 +--source include/assert_grep.inc +--let $assert_text= Recovery did not skip UNDO records +--let $assert_select= UNDO records skipped in UNDO phase +--let $assert_count= 0 +--source include/assert_grep.inc + +SELECT a FROM t1 ORDER BY a; +SELECT a FROM t1 + WHERE MATCH(a) AGAINST('abc-def baseline-two undo-insert undo-update') + ORDER BY a; +CHECK TABLE t1 EXTENDED; + +--echo # Recover a completed bulk-insert repair with a parser plugin +# INSERT ... SELECT into an empty table disables the keys and rebuilds them +# with a repair. Its state LSNs normally make recovery skip REDO_REPAIR_TABLE. +# fulltext_parser_debug covers a repair record newer than the saved state LSNs. +CREATE TABLE t_src (a TEXT) ENGINE=Aria; +INSERT INTO t_src VALUES ('abc-def'), ('abcd-efgh'), ('other text'); +CREATE TABLE t2 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) + ENGINE=Aria ROW_FORMAT=PAGE TRANSACTIONAL=1; +INSERT INTO t2 SELECT a FROM t_src; +--let $shutdown_timeout= 0 +--source include/restart_mysqld.inc +SELECT a FROM t2 WHERE MATCH(a) AGAINST('abc-def abcd'); +CHECK TABLE t2 EXTENDED; +DROP TABLE t2, t_src; + +DROP TABLE t1, t_flush; +UNINSTALL PLUGIN simple_parser; diff --git a/mysql-test/suite/maria/fulltext_parser_debug-master.opt b/mysql-test/suite/maria/fulltext_parser_debug-master.opt new file mode 100644 index 0000000000000..79c596c97e106 --- /dev/null +++ b/mysql-test/suite/maria/fulltext_parser_debug-master.opt @@ -0,0 +1,2 @@ +--aria-checkpoint-interval=0 +--aria-recover-options=OFF diff --git a/mysql-test/suite/maria/fulltext_parser_debug.result b/mysql-test/suite/maria/fulltext_parser_debug.result new file mode 100644 index 0000000000000..46711deb71111 --- /dev/null +++ b/mysql-test/suite/maria/fulltext_parser_debug.result @@ -0,0 +1,64 @@ +INSTALL PLUGIN simple_parser SONAME 'mypluglib'; +# Keep the durable repair result without replaying it +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) +ENGINE=Aria ROW_FORMAT=PAGE TRANSACTIONAL=1; +INSERT INTO t1 VALUES +('abc-def'), ('abcd-efgh'), ('plain words'), ('other text'), ('more rows'); +FLUSH TABLES t1; +SET SESSION debug_dbug='+d,maria_crash_after_repair_log'; +REPAIR TABLE t1; +# restart +SELECT a FROM t1 WHERE MATCH(a) AGAINST('abc-def abcd') ORDER BY a; +a +abc-def +CHECK TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; +# Recover changes committed after a bulk-insert repair record +CREATE TABLE t_src (a TEXT) ENGINE=Aria; +INSERT INTO t_src VALUES +('abcd-efgh'), ('keep-one'), ('keep-two'), +('update-before'), ('delete-before'); +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) +ENGINE=Aria ROW_FORMAT=PAGE TRANSACTIONAL=1; +CREATE TABLE t_flush (a INT) ENGINE=Aria ROW_FORMAT=PAGE TRANSACTIONAL=1; +INSERT INTO t_flush VALUES (0); +# restart +connect bulk,localhost,root,,test; +SET DEBUG_SYNC= +'maria_before_repair_log SIGNAL repair_ready WAIT_FOR log_advanced'; +INSERT INTO t1 SELECT a FROM t_src; +connection default; +SET DEBUG_SYNC= 'now WAIT_FOR repair_ready'; +INSERT INTO t_flush VALUES (1); +SET DEBUG_SYNC= 'now SIGNAL log_advanced'; +connection bulk; +SET DEBUG_SYNC= 'RESET'; +INSERT INTO t1 VALUES ('commit-one'), ('commit-two'); +UPDATE t1 SET a= 'update-after' WHERE a= 'update-before'; +DELETE FROM t1 WHERE a= 'delete-before'; +connection default; +INSERT INTO t_flush VALUES (2); +# restart +disconnect bulk; +SELECT a FROM t1 ORDER BY a; +a +abcd-efgh +commit-one +commit-two +keep-one +keep-two +update-after +SELECT a FROM t1 +WHERE MATCH(a) AGAINST('abcd-efgh commit-one update-after update-before') +ORDER BY a; +a +abcd-efgh +commit-one +update-after +CHECK TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1, t_src, t_flush; +UNINSTALL PLUGIN simple_parser; diff --git a/mysql-test/suite/maria/fulltext_parser_debug.test b/mysql-test/suite/maria/fulltext_parser_debug.test new file mode 100644 index 0000000000000..e6491aaa5d630 --- /dev/null +++ b/mysql-test/suite/maria/fulltext_parser_debug.test @@ -0,0 +1,82 @@ +--source include/have_maria.inc +--source include/have_simple_parser.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/not_embedded.inc +--source include/not_valgrind.inc +--source include/not_crashrep.inc + +INSTALL PLUGIN simple_parser SONAME 'mypluglib'; + +--echo # Keep the durable repair result without replaying it +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) + ENGINE=Aria ROW_FORMAT=PAGE TRANSACTIONAL=1; +INSERT INTO t1 VALUES + ('abc-def'), ('abcd-efgh'), ('plain words'), ('other text'), ('more rows'); + +# Closing the share makes repair log a new FILE_ID before REDO_REPAIR_TABLE. +# The repair record is then strictly newer than protect_against_repair_crash's +# skip_redo_lsn, even without concurrent writes to the log. +FLUSH TABLES t1; +SET SESSION debug_dbug='+d,maria_crash_after_repair_log'; +--source include/expect_crash.inc +--disable_result_log +# send/reap, so that --sp-protocol does not wrap the crashing statement +--send REPAIR TABLE t1 +--error 2013,2026 +--reap +--enable_result_log +--source include/start_mysqld.inc + +# The table must be usable immediately, with the plugin's index intact. +SELECT a FROM t1 WHERE MATCH(a) AGAINST('abc-def abcd') ORDER BY a; +CHECK TABLE t1 EXTENDED; +DROP TABLE t1; + +--echo # Recover changes committed after a bulk-insert repair record +CREATE TABLE t_src (a TEXT) ENGINE=Aria; +INSERT INTO t_src VALUES + ('abcd-efgh'), ('keep-one'), ('keep-two'), + ('update-before'), ('delete-before'); +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) + ENGINE=Aria ROW_FORMAT=PAGE TRANSACTIONAL=1; +CREATE TABLE t_flush (a INT) ENGINE=Aria ROW_FORMAT=PAGE TRANSACTIONAL=1; +INSERT INTO t_flush VALUES (0); + +# Establish an empty on-disk t1 before the bulk insert. +--source include/restart_mysqld.inc +--connect (bulk,localhost,root,,test) +SET DEBUG_SYNC= + 'maria_before_repair_log SIGNAL repair_ready WAIT_FOR log_advanced'; +--send INSERT INTO t1 SELECT a FROM t_src + +--connection default +SET DEBUG_SYNC= 'now WAIT_FOR repair_ready'; +# The quick, keys-only repair has written t1's state. Advance the log before +# its repair record, making that record strictly newer than is_of_horizon. +# T_NO_CREATE_RENAME_LSN prevents the repair from updating the LSNs later. +INSERT INTO t_flush VALUES (1); +SET DEBUG_SYNC= 'now SIGNAL log_advanced'; + +--connection bulk +--reap +SET DEBUG_SYNC= 'RESET'; +# Each statement commits. Keep the table open and its changed pages cached: +# the .opt file disables checkpoints, and we do not flush or check t1. +INSERT INTO t1 VALUES ('commit-one'), ('commit-two'); +UPDATE t1 SET a= 'update-after' WHERE a= 'update-before'; +DELETE FROM t1 WHERE a= 'delete-before'; + +--connection default +INSERT INTO t_flush VALUES (2); +--let $shutdown_timeout= 0 +--source include/restart_mysqld.inc +--disconnect bulk + +SELECT a FROM t1 ORDER BY a; +SELECT a FROM t1 + WHERE MATCH(a) AGAINST('abcd-efgh commit-one update-after update-before') + ORDER BY a; +CHECK TABLE t1 EXTENDED; +DROP TABLE t1, t_src, t_flush; +UNINSTALL PLUGIN simple_parser; diff --git a/mysql-test/suite/maria/fulltext_parser_drop.result b/mysql-test/suite/maria/fulltext_parser_drop.result new file mode 100644 index 0000000000000..41a7164ef48cb --- /dev/null +++ b/mysql-test/suite/maria/fulltext_parser_drop.result @@ -0,0 +1,12 @@ +# +# DROP TABLE of an Aria table with a fulltext parser plugin +# must not warn about an unsupported extension +# +INSTALL PLUGIN simple_parser SONAME 'mypluglib'; +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) ENGINE=Aria; +INSERT INTO t1 VALUES ('hello world'); +DROP TABLE t1; +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) +ENGINE=Aria TRANSACTIONAL=0; +DROP TABLE t1; +UNINSTALL PLUGIN simple_parser; diff --git a/mysql-test/suite/maria/fulltext_parser_drop.test b/mysql-test/suite/maria/fulltext_parser_drop.test new file mode 100644 index 0000000000000..726cd39e57510 --- /dev/null +++ b/mysql-test/suite/maria/fulltext_parser_drop.test @@ -0,0 +1,15 @@ +--source include/have_simple_parser.inc + +--echo # +--echo # DROP TABLE of an Aria table with a fulltext parser plugin +--echo # must not warn about an unsupported extension +--echo # + +INSTALL PLUGIN simple_parser SONAME 'mypluglib'; +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) ENGINE=Aria; +INSERT INTO t1 VALUES ('hello world'); +DROP TABLE t1; +CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) + ENGINE=Aria TRANSACTIONAL=0; +DROP TABLE t1; +UNINSTALL PLUGIN simple_parser; diff --git a/mysql-test/suite/maria/include/fulltext_parser_ops.inc b/mysql-test/suite/maria/include/fulltext_parser_ops.inc new file mode 100644 index 0000000000000..a76194950dd69 --- /dev/null +++ b/mysql-test/suite/maria/include/fulltext_parser_ops.inc @@ -0,0 +1,38 @@ +# RENAME TABLE, ALTER TABLE ... ALGORITHM=COPY, REPAIR TABLE and ADD FULLTEXT +# on an Aria table with a fulltext parser plugin, each on its own table, +# with $row_format and $transactional. +--echo # Fulltext parser with ROW_FORMAT=$row_format +--let $create= CREATE TABLE t1 (a TEXT, FULLTEXT(a) WITH PARSER simple_parser) ENGINE=Aria ROW_FORMAT=$row_format TRANSACTIONAL=$transactional +--let $rows= INSERT INTO t1 VALUES ('abc-def'), ('abcd-efgh'), ('other text') + +eval $create; +eval $rows; +RENAME TABLE t1 TO t2; +SELECT a FROM t2 WHERE MATCH(a) AGAINST('abc-def abcd'); +DROP TABLE t2; + +eval $create; +eval $rows; +ALTER TABLE t1 ADD COLUMN b INT, ALGORITHM=COPY; +SELECT a FROM t1 WHERE MATCH(a) AGAINST('abc-def abcd'); +DROP TABLE t1; + +# Default repair sorts keys; EXTENDED repairs through the key cache. +eval $create; +eval $rows; +REPAIR TABLE t1; +SELECT a FROM t1 WHERE MATCH(a) AGAINST('abc-def abcd'); +DROP TABLE t1; + +eval $create; +eval $rows; +REPAIR TABLE t1 EXTENDED; +SELECT a FROM t1 WHERE MATCH(a) AGAINST('abc-def abcd'); +DROP TABLE t1; + +eval CREATE TABLE t1 (a TEXT) + ENGINE=Aria ROW_FORMAT=$row_format TRANSACTIONAL=$transactional; +eval $rows; +ALTER TABLE t1 ADD FULLTEXT(a) WITH PARSER simple_parser, ALGORITHM=COPY; +SELECT a FROM t1 WHERE MATCH(a) AGAINST('abc-def abcd'); +DROP TABLE t1; diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c index b41570e9535bf..3c5f6ebf06f6c 100644 --- a/storage/maria/ma_check.c +++ b/storage/maria/ma_check.c @@ -6686,11 +6686,14 @@ static my_bool create_new_data_handle(MARIA_SORT_PARAM *param, File new_file) MARIA_SORT_INFO *sort_info= param->sort_info; MARIA_HA *info= sort_info->info; MARIA_HA *new_info; + uint open_flags= HA_OPEN_COPY | HA_OPEN_FOR_REPAIR | HA_OPEN_INTERNAL_TABLE; DBUG_ENTER("create_new_data_handle"); + /* Keys are rebuilt using info, which already has the fulltext parsers. */ + if (info->s->options & HA_OPTION_RELIES_ON_SQL_LAYER) + open_flags|= HA_OPEN_FROM_SQL_LAYER; if (!(sort_info->new_info= maria_open(info->s->open_file_name.str, O_RDWR, - HA_OPEN_COPY | HA_OPEN_FOR_REPAIR | - HA_OPEN_INTERNAL_TABLE, 0))) + open_flags, 0))) DBUG_RETURN(1); new_info= sort_info->new_info; @@ -7011,7 +7014,17 @@ my_bool write_log_record_for_repair(const HA_CHECK *param, MARIA_HA *info) log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data; log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data); + /* + Repair has flushed pages and state, including for a quick index rebuild. + Recovery cannot replay this repair without the SQL layer, so sync the + file contents before logging it. MY_SYNC_DIR only made renames durable. + */ + if ((share->options & HA_OPTION_RELIES_ON_SQL_LAYER) && + _ma_sync_table_files(info)) + return TRUE; + share->now_transactional= 1; + DEBUG_SYNC_C("maria_before_repair_log"); if (unlikely(translog_write_record(&lsn, LOGREC_REDO_REPAIR_TABLE, &dummy_transaction_object, info, (translog_size_t) sizeof(log_data), @@ -7019,6 +7032,11 @@ my_bool write_log_record_for_repair(const HA_CHECK *param, MARIA_HA *info) log_array, log_data, NULL) || translog_flush(lsn))) return TRUE; + DBUG_EXECUTE_IF("maria_crash_after_repair_log", + { + DBUG_PRINT("maria_crash_after_repair_log", ("now")); + DBUG_SUICIDE(); + }); /* The table's existence was made durable earlier (MY_SYNC_DIR passed to maria_change_to_newfile()). All pages have been flushed, state too, we @@ -7031,6 +7049,7 @@ my_bool write_log_record_for_repair(const HA_CHECK *param, MARIA_HA *info) The fully correct order would be: sync data and index file, remove crash mark and update LSNs then write state and sync index file. But at this point state (without crash mark) is already written. + SQL-layer tables were synced above; sync again for the updated LSNs. */ if ((!(param->testflag & T_NO_CREATE_RENAME_LSN) && _ma_update_state_lsns(share, lsn, share->state.create_trid, FALSE, diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c index 3a31663942d62..4952ee316dd6e 100644 --- a/storage/maria/ma_open.c +++ b/storage/maria/ma_open.c @@ -435,7 +435,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags, goto err; } if ((share->options & HA_OPTION_RELIES_ON_SQL_LAYER) && - ! (open_flags & HA_OPEN_FROM_SQL_LAYER)) + ! (open_flags & (HA_OPEN_FROM_SQL_LAYER | HA_OPEN_FOR_DROP))) { DBUG_PRINT("error", ("table cannot be opened from non-sql layer")); my_errno= HA_ERR_UNSUPPORTED; diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c index 962e10998c2ce..a693815136973 100644 --- a/storage/maria/ma_recovery.c +++ b/storage/maria/ma_recovery.c @@ -50,6 +50,7 @@ static LSN current_group_end_lsn; static MARIA_HA *current_group_table; #endif static my_bool skip_DDLs; /**< if REDO phase should skip DDL records */ +static my_bool recovery_from_sql_layer; /**< server startup, not aria_read_log */ /** @brief to avoid writing a checkpoint if recovery did nothing. */ static my_bool checkpoint_useful; static my_bool in_redo_phase; @@ -228,6 +229,7 @@ int maria_recovery_from_log(void) DBUG_ASSERT(!maria_in_recovery); maria_in_recovery= TRUE; + recovery_from_sql_layer= TRUE; #ifdef EXTRA_DEBUG fn_format(name_buff, "aria_recovery.trace", maria_data_root, "", MYF(0)); @@ -250,6 +252,7 @@ int maria_recovery_from_log(void) if (trace_file) my_fclose(trace_file, MYF(0)); maria_in_recovery= FALSE; + recovery_from_sql_layer= FALSE; DBUG_RETURN(res); } @@ -1198,6 +1201,18 @@ prototype_redo_exec_hook(REDO_REPAIR_TABLE) DBUG_RETURN(0); } + if (info->s->options & HA_OPTION_RELIES_ON_SQL_LAYER) + { + /* + Parser plugins are not available until the SQL layer opens the table. + write_log_record_for_repair() syncs these tables before logging repair, + so keep the rebuilt files and allow subsequent REDO and UNDO records. + */ + tprint(tracef, "we skip repair requiring the SQL layer;" + " files were synced before logging\n"); + DBUG_RETURN(0); + } + /* Otherwise, the mapping is newer than the table, and our record is newer than the mapping, so we can repair. @@ -1404,7 +1419,16 @@ static int new_table(uint16 sid, const char *name, LSN lsn_of_file_id) goto end; } tprint(tracef, "Table '%s', id %u", name, sid); - info= maria_open(name, O_RDWR, HA_OPEN_FOR_REPAIR, 0); + /* + Row and key recovery uses logged values, without fulltext parsers. + REDO_REPAIR_TABLE keeps the indexes already rebuilt by the SQL layer. + Keep refusing these tables in aria_read_log. + In server recovery, maria_in_recovery already triggers the state LSN + initialization done by HA_OPEN_FROM_SQL_LAYER. + */ + info= maria_open(name, O_RDWR, + HA_OPEN_FOR_REPAIR | + (recovery_from_sql_layer ? HA_OPEN_FROM_SQL_LAYER : 0), 0); if (info == NULL) { tprint(tracef, ", is absent (must have been dropped later?)" @@ -1472,7 +1496,9 @@ static int new_table(uint16 sid, const char *name, LSN lsn_of_file_id) { tprint(tracef, "\n"); eprint(tracef, "Table '%s' is crashed, skipping it. Please repair it with" - " aria_chk -r", share->open_file_name.str); + " %s", share->open_file_name.str, + (share->options & HA_OPTION_RELIES_ON_SQL_LAYER) ? + "REPAIR TABLE" : "aria_chk -r"); recovery_found_crashed_tables++; error= -1; /* not fatal, try with other tables */ goto end; diff --git a/storage/maria/ma_rename.c b/storage/maria/ma_rename.c index ade6e52f3342e..c0e9f2d8aca0e 100644 --- a/storage/maria/ma_rename.c +++ b/storage/maria/ma_rename.c @@ -49,7 +49,15 @@ int maria_rename(const char *old_name, const char *new_name) _ma_check_table_is_closed(new_name,"rename new table2"); #endif /** @todo LOCK take X-lock on table */ - if (!(info= maria_open(old_name, O_RDWR, HA_OPEN_FOR_REPAIR, 0))) + info= maria_open(old_name, O_RDWR, HA_OPEN_FOR_REPAIR, 0); + /* + Retry with HA_OPEN_FROM_SQL_LAYER only for tables that need it, so that + its state LSN side effect does not apply to other tables. + */ + if (!info && my_errno == HA_ERR_UNSUPPORTED && maria_in_ha_maria) + info= maria_open(old_name, O_RDWR, + HA_OPEN_FOR_REPAIR | HA_OPEN_FROM_SQL_LAYER, 0); + if (!info) { int error= my_errno; /*