diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2021-03-03 09:41:50 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2021-03-03 09:41:50 +0200 |
commit | ddbc6126920c1ad0300f7f9734348309f5073de7 (patch) | |
tree | f98a56b0fef476345979f3a228de8ffd27da0ea6 | |
parent | 0f81ca6a0bb21fbba4bca93a7555f7c8e6357b47 (diff) | |
parent | 676987c4a14069d415c56d0f259aaaa7ca742c23 (diff) | |
download | mariadb-git-ddbc6126920c1ad0300f7f9734348309f5073de7.tar.gz |
Merge 10.2 into 10.3
-rw-r--r-- | mysql-test/lib/My/Debugger.pm | 3 | ||||
-rw-r--r-- | mysql-test/main/ps.result | 17 | ||||
-rw-r--r-- | mysql-test/main/ps.test | 14 | ||||
-rw-r--r-- | mysql-test/main/set_statement.result | 25 | ||||
-rw-r--r-- | mysql-test/main/set_statement.test | 23 | ||||
-rwxr-xr-x | mysql-test/mysql-test-run.pl | 2 | ||||
-rw-r--r-- | mysql-test/suite/innodb/r/truncate_foreign.result | 11 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/truncate_foreign.test | 13 | ||||
-rw-r--r-- | sql/handler.h | 8 | ||||
-rw-r--r-- | sql/sql_parse.cc | 270 | ||||
-rw-r--r-- | sql/sql_parse.h | 1 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 16 | ||||
-rw-r--r-- | sql/sql_select.cc | 3 | ||||
-rw-r--r-- | sql/sql_truncate.cc | 9 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 5 |
15 files changed, 293 insertions, 127 deletions
diff --git a/mysql-test/lib/My/Debugger.pm b/mysql-test/lib/My/Debugger.pm index d2add55d680..a2d5f2a5435 100644 --- a/mysql-test/lib/My/Debugger.pm +++ b/mysql-test/lib/My/Debugger.pm @@ -74,7 +74,8 @@ my %debuggers = ( options => '-f -o {log} {exe} {args}', }, rr => { - options => 'record -o {log} {exe} {args}', + options => '_RR_TRACE_DIR={log} rr record {exe} {args}', + run => 'env', pre => sub { ::mtr_error('rr requires kernel.perf_event_paranoid <= 1') if ::mtr_grab_file('/proc/sys/kernel/perf_event_paranoid') > 1; diff --git a/mysql-test/main/ps.result b/mysql-test/main/ps.result index d51414d8f54..d1a17f90934 100644 --- a/mysql-test/main/ps.result +++ b/mysql-test/main/ps.result @@ -5479,5 +5479,22 @@ EXISTS(SELECT 1 FROM t1 GROUP BY a IN (select a from t1)) 0 DROP TABLE t1; # +# MDEV-25006: Failed assertion on executing EXPLAIN DELETE statement as a prepared statement +# +CREATE TABLE t1(c1 CHAR(255) PRIMARY KEY); +PREPARE stmt FROM 'EXPLAIN DELETE b FROM t1 AS a JOIN t1 AS b'; +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE a system NULL NULL NULL NULL 0 Const row not found +1 SIMPLE b system NULL NULL NULL NULL 0 Const row not found +DROP TABLE t1; +CREATE TABLE t1(a INT); +PREPARE stmt FROM 'EXPLAIN DELETE FROM t1.* USING t1'; +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 0 Const row not found +DEALLOCATE PREPARE stmt; +DROP TABLE t1; +# # End of 10.2 tests # diff --git a/mysql-test/main/ps.test b/mysql-test/main/ps.test index 3228181d922..ecabc5126d3 100644 --- a/mysql-test/main/ps.test +++ b/mysql-test/main/ps.test @@ -4950,5 +4950,19 @@ EXECUTE stmt; DROP TABLE t1; --echo # +--echo # MDEV-25006: Failed assertion on executing EXPLAIN DELETE statement as a prepared statement +--echo # + +CREATE TABLE t1(c1 CHAR(255) PRIMARY KEY); +PREPARE stmt FROM 'EXPLAIN DELETE b FROM t1 AS a JOIN t1 AS b'; +EXECUTE stmt; +DROP TABLE t1; +CREATE TABLE t1(a INT); +PREPARE stmt FROM 'EXPLAIN DELETE FROM t1.* USING t1'; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; +DROP TABLE t1; + +--echo # --echo # End of 10.2 tests --echo # diff --git a/mysql-test/main/set_statement.result b/mysql-test/main/set_statement.result index 48675145fd2..76f943edfc6 100644 --- a/mysql-test/main/set_statement.result +++ b/mysql-test/main/set_statement.result @@ -1217,3 +1217,28 @@ set @rnd=1; select @rnd; @rnd 0 +# +# MDEV-24860: Incorrect behaviour of SET STATEMENT in case +# it is executed as a prepared statement +# +PREPARE stmt FROM "SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TABLE t1 AS SELECT CONCAT('abc') AS c1"; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; +# Show definition of the table t1 created using Prepared Statement +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` varchar(3) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +# Create the table t1 with the same definition as it used before +# using regular statement execution mode. +SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TABLE t1 AS SELECT CONCAT('abc') AS c1; +# Show that the table has the same definition as it is in case the table +# created in prepared statement mode. +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` varchar(3) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; diff --git a/mysql-test/main/set_statement.test b/mysql-test/main/set_statement.test index 6791c7e0b79..7af970e952f 100644 --- a/mysql-test/main/set_statement.test +++ b/mysql-test/main/set_statement.test @@ -1136,3 +1136,26 @@ while ($1) --enable_query_log --echo # @rnd should be 0 select @rnd; + +--echo # +--echo # MDEV-24860: Incorrect behaviour of SET STATEMENT in case +--echo # it is executed as a prepared statement +--echo # +PREPARE stmt FROM "SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TABLE t1 AS SELECT CONCAT('abc') AS c1"; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +--echo # Show definition of the table t1 created using Prepared Statement +SHOW CREATE TABLE t1; + +DROP TABLE t1; + +--echo # Create the table t1 with the same definition as it used before +--echo # using regular statement execution mode. +SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TABLE t1 AS SELECT CONCAT('abc') AS c1; + +--echo # Show that the table has the same definition as it is in case the table +--echo # created in prepared statement mode. +SHOW CREATE TABLE t1; + +DROP TABLE t1; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 1383b431e55..ef76e40d0fe 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -5099,7 +5099,7 @@ sub mysqld_start ($$) { $ENV{'MYSQLD_LAST_CMD'}= "$exe @$args"; My::Debugger::setup_args(\$args, \$exe, $mysqld->name()); - $ENV{'VALGRIND_TEST'}= $opt_valgrind = int($exe && $exe eq 'valgrind'); + $ENV{'VALGRIND_TEST'}= $opt_valgrind = int(($exe || '') eq 'valgrind'); # Remove the old pidfile if any unlink($mysqld->value('pid-file')); diff --git a/mysql-test/suite/innodb/r/truncate_foreign.result b/mysql-test/suite/innodb/r/truncate_foreign.result index fc09b74d62f..12a41860708 100644 --- a/mysql-test/suite/innodb/r/truncate_foreign.result +++ b/mysql-test/suite/innodb/r/truncate_foreign.result @@ -57,3 +57,14 @@ disconnect dml; connection default; SET DEBUG_SYNC = RESET; DROP TABLE child, parent; +# +# MDEV-24532 Table corruption ER_NO_SUCH_TABLE_IN_ENGINE or +# ER_CRASHED_ON_USAGE after ALTER on table with foreign key +# +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a)) ENGINE=InnoDB; +ALTER TABLE t1 ADD FOREIGN KEY (b) REFERENCES t1 (a) ON UPDATE CASCADE; +LOCK TABLE t1 WRITE; +TRUNCATE TABLE t1; +ALTER TABLE t1 ADD c INT; +UNLOCK TABLES; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/truncate_foreign.test b/mysql-test/suite/innodb/t/truncate_foreign.test index d9d647e69f0..1c150e5db40 100644 --- a/mysql-test/suite/innodb/t/truncate_foreign.test +++ b/mysql-test/suite/innodb/t/truncate_foreign.test @@ -67,3 +67,16 @@ connection default; SET DEBUG_SYNC = RESET; DROP TABLE child, parent; + +--echo # +--echo # MDEV-24532 Table corruption ER_NO_SUCH_TABLE_IN_ENGINE or +--echo # ER_CRASHED_ON_USAGE after ALTER on table with foreign key +--echo # + +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a)) ENGINE=InnoDB; +ALTER TABLE t1 ADD FOREIGN KEY (b) REFERENCES t1 (a) ON UPDATE CASCADE; +LOCK TABLE t1 WRITE; +TRUNCATE TABLE t1; +ALTER TABLE t1 ADD c INT; +UNLOCK TABLES; +DROP TABLE t1; diff --git a/sql/handler.h b/sql/handler.h index 49fef4a5cc9..fc69d9423b4 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2,7 +2,7 @@ #define HANDLER_INCLUDED /* Copyright (c) 2000, 2019, Oracle and/or its affiliates. - Copyright (c) 2009, 2020, MariaDB + Copyright (c) 2009, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -1671,6 +1671,12 @@ handlerton *ha_default_tmp_handlerton(THD *thd); // Engine needs to access the main connect string in partitions #define HTON_CAN_READ_CONNECT_STRING_IN_PARTITION (1 <<12) +/* + Table requires and close and reopen after truncate + If the handler has HTON_CAN_RECREATE, this flag is not used +*/ +#define HTON_REQUIRES_CLOSE_AFTER_TRUNCATE (1 << 18) + class Ha_trx_info; struct THD_TRANS diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 66be72518ca..c0748a93d6e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. - Copyright (c) 2008, 2020, MariaDB + Copyright (c) 2008, 2021, MariaDB 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 @@ -3271,6 +3271,146 @@ bool Sql_cmd_call::execute(THD *thd) /** + Check whether the SQL statement being processed is prepended by + SET STATEMENT clause and handle variables assignment if it is. + + @param thd thread handle + @param lex current lex + + @return false in case of success, true in case of error. +*/ + +bool run_set_statement_if_requested(THD *thd, LEX *lex) +{ + if (!lex->stmt_var_list.is_empty() && !thd->slave_thread) + { + Query_arena backup; + DBUG_PRINT("info", ("SET STATEMENT %d vars", lex->stmt_var_list.elements)); + + lex->old_var_list.empty(); + List_iterator_fast<set_var_base> it(lex->stmt_var_list); + set_var_base *var; + + if (lex->set_arena_for_set_stmt(&backup)) + return true; + + MEM_ROOT *mem_root= thd->mem_root; + while ((var= it++)) + { + DBUG_ASSERT(var->is_system()); + set_var *o= NULL, *v= (set_var*)var; + if (!v->var->is_set_stmt_ok()) + { + my_error(ER_SET_STATEMENT_NOT_SUPPORTED, MYF(0), v->var->name.str); + lex->reset_arena_for_set_stmt(&backup); + lex->old_var_list.empty(); + lex->free_arena_for_set_stmt(); + return true; + } + if (v->var->session_is_default(thd)) + o= new set_var(thd,v->type, v->var, &v->base, NULL); + else + { + switch (v->var->option.var_type & GET_TYPE_MASK) + { + case GET_BOOL: + case GET_INT: + case GET_LONG: + case GET_LL: + { + bool null_value; + longlong val= v->var->val_int(&null_value, thd, v->type, &v->base); + o= new set_var(thd, v->type, v->var, &v->base, + (null_value ? + (Item *) new (mem_root) Item_null(thd) : + (Item *) new (mem_root) Item_int(thd, val))); + } + break; + case GET_UINT: + case GET_ULONG: + case GET_ULL: + { + bool null_value; + ulonglong val= v->var->val_int(&null_value, thd, v->type, &v->base); + o= new set_var(thd, v->type, v->var, &v->base, + (null_value ? + (Item *) new (mem_root) Item_null(thd) : + (Item *) new (mem_root) Item_uint(thd, val))); + } + break; + case GET_DOUBLE: + { + bool null_value; + double val= v->var->val_real(&null_value, thd, v->type, &v->base); + o= new set_var(thd, v->type, v->var, &v->base, + (null_value ? + (Item *) new (mem_root) Item_null(thd) : + (Item *) new (mem_root) Item_float(thd, val, 1))); + } + break; + default: + case GET_NO_ARG: + case GET_DISABLED: + DBUG_ASSERT(0); + /* fall through */ + case 0: + case GET_FLAGSET: + case GET_ENUM: + case GET_SET: + case GET_STR: + case GET_STR_ALLOC: + { + char buff[STRING_BUFFER_USUAL_SIZE]; + String tmp(buff, sizeof(buff), v->var->charset(thd)),*val; + val= v->var->val_str(&tmp, thd, v->type, &v->base); + if (val) + { + Item_string *str= + new (mem_root) Item_string(thd, v->var->charset(thd), + val->ptr(), val->length()); + o= new set_var(thd, v->type, v->var, &v->base, str); + } + else + o= new set_var(thd, v->type, v->var, &v->base, + new (mem_root) Item_null(thd)); + } + break; + } + } + DBUG_ASSERT(o); + lex->old_var_list.push_back(o, thd->mem_root); + } + lex->reset_arena_for_set_stmt(&backup); + + if (lex->old_var_list.is_empty()) + lex->free_arena_for_set_stmt(); + + if (thd->is_error() || + sql_set_variables(thd, &lex->stmt_var_list, false)) + { + if (!thd->is_error()) + my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET"); + lex->restore_set_statement_var(); + return true; + } + /* + The value of last_insert_id is remembered in THD to be written to binlog + when it's used *the first time* in the statement. But SET STATEMENT + must read the old value of last_insert_id to be able to restore it at + the end. This should not count at "reading of last_insert_id" and + should not remember last_insert_id for binlog. That is, it should clear + stmt_depends_on_first_successful_insert_id_in_prev_stmt flag. + */ + if (!thd->in_sub_stmt) + { + thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0; + } + } + return false; +} + + +/** Execute command saved in thd and lex->sql_command. @param thd Thread handle @@ -3540,127 +3680,13 @@ mysql_execute_command(THD *thd) thd->get_binlog_format(&orig_binlog_format, &orig_current_stmt_binlog_format); - if (!lex->stmt_var_list.is_empty() && !thd->slave_thread) - { - Query_arena backup; - DBUG_PRINT("info", ("SET STATEMENT %d vars", lex->stmt_var_list.elements)); - - lex->old_var_list.empty(); - List_iterator_fast<set_var_base> it(lex->stmt_var_list); - set_var_base *var; - - if (lex->set_arena_for_set_stmt(&backup)) - goto error; - - MEM_ROOT *mem_root= thd->mem_root; - while ((var= it++)) - { - DBUG_ASSERT(var->is_system()); - set_var *o= NULL, *v= (set_var*)var; - if (!v->var->is_set_stmt_ok()) - { - my_error(ER_SET_STATEMENT_NOT_SUPPORTED, MYF(0), v->var->name.str); - lex->reset_arena_for_set_stmt(&backup); - lex->old_var_list.empty(); - lex->free_arena_for_set_stmt(); - goto error; - } - if (v->var->session_is_default(thd)) - o= new set_var(thd,v->type, v->var, &v->base, NULL); - else - { - switch (v->var->option.var_type & GET_TYPE_MASK) - { - case GET_BOOL: - case GET_INT: - case GET_LONG: - case GET_LL: - { - bool null_value; - longlong val= v->var->val_int(&null_value, thd, v->type, &v->base); - o= new set_var(thd, v->type, v->var, &v->base, - (null_value ? - (Item *) new (mem_root) Item_null(thd) : - (Item *) new (mem_root) Item_int(thd, val))); - } - break; - case GET_UINT: - case GET_ULONG: - case GET_ULL: - { - bool null_value; - ulonglong val= v->var->val_int(&null_value, thd, v->type, &v->base); - o= new set_var(thd, v->type, v->var, &v->base, - (null_value ? - (Item *) new (mem_root) Item_null(thd) : - (Item *) new (mem_root) Item_uint(thd, val))); - } - break; - case GET_DOUBLE: - { - bool null_value; - double val= v->var->val_real(&null_value, thd, v->type, &v->base); - o= new set_var(thd, v->type, v->var, &v->base, - (null_value ? - (Item *) new (mem_root) Item_null(thd) : - (Item *) new (mem_root) Item_float(thd, val, 1))); - } - break; - default: - case GET_NO_ARG: - case GET_DISABLED: - DBUG_ASSERT(0); - /* fall through */ - case 0: - case GET_FLAGSET: - case GET_ENUM: - case GET_SET: - case GET_STR: - case GET_STR_ALLOC: - { - char buff[STRING_BUFFER_USUAL_SIZE]; - String tmp(buff, sizeof(buff), v->var->charset(thd)),*val; - val= v->var->val_str(&tmp, thd, v->type, &v->base); - if (val) - { - Item_string *str= new (mem_root) Item_string(thd, v->var->charset(thd), - val->ptr(), val->length()); - o= new set_var(thd, v->type, v->var, &v->base, str); - } - else - o= new set_var(thd, v->type, v->var, &v->base, - new (mem_root) Item_null(thd)); - } - break; - } - } - DBUG_ASSERT(o); - lex->old_var_list.push_back(o, thd->mem_root); - } - lex->reset_arena_for_set_stmt(&backup); - if (lex->old_var_list.is_empty()) - lex->free_arena_for_set_stmt(); - if (thd->is_error() || - (res= sql_set_variables(thd, &lex->stmt_var_list, false))) - { - if (!thd->is_error()) - my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET"); - lex->restore_set_statement_var(); - goto error; - } - /* - The value of last_insert_id is remembered in THD to be written to binlog - when it's used *the first time* in the statement. But SET STATEMENT - must read the old value of last_insert_id to be able to restore it at - the end. This should not count at "reading of last_insert_id" and - should not remember last_insert_id for binlog. That is, it should clear - stmt_depends_on_first_successful_insert_id_in_prev_stmt flag. - */ - if (!thd->in_sub_stmt) - { - thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0; - } - } + /* + Assign system variables with values specified by the clause + SET STATEMENT var1=value1 [, var2=value2, ...] FOR <statement> + if they are any. + */ + if (run_set_statement_if_requested(thd, lex)) + goto error; if (thd->lex->mi.connection_name.str == NULL) thd->lex->mi.connection_name= thd->variables.default_master_connection; diff --git a/sql/sql_parse.h b/sql/sql_parse.h index 6b0fc6718d5..b726bb667b2 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -100,6 +100,7 @@ void mysql_init_multi_delete(LEX *lex); bool multi_delete_set_locks_and_link_aux_tables(LEX *lex); void create_table_set_open_action_and_adjust_tables(LEX *lex); pthread_handler_t handle_bootstrap(void *arg); +bool run_set_statement_if_requested(THD *thd, LEX *lex); int mysql_execute_command(THD *thd); bool do_command(THD *thd); void do_handle_bootstrap(THD *thd); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 3652a6ab086..9775e99afdd 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -4218,6 +4218,16 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) */ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); + /* + Set variables specified by + SET STATEMENT var1=value1 [, var2=value2, ...] FOR <statement> + clause for duration of prepare phase. Original values of variable + listed in the SET STATEMENT clause is restored right after return + from the function check_prepared_statement() + */ + if (likely(error == 0)) + error= run_set_statement_if_requested(thd, lex); + /* The only case where we should have items in the thd->free_list is after stmt->set_params_from_vars(), which may in some cases create @@ -4236,6 +4246,12 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_PREPARE; } + /* + Restore original values of variables modified on handling + SET STATEMENT clause. + */ + thd->lex->restore_set_statement_var(); + /* The order is important */ lex->unit.cleanup(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ce820946908..b83da48233d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4288,6 +4288,9 @@ mysql_select(THD *thd, } else { + if (thd->lex->describe) + select_options|= SELECT_DESCRIBE; + /* When in EXPLAIN, delay deleting the joins so that they are still available when we're producing EXPLAIN EXTENDED warning text. diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 577f5a2b00f..897db0a2b21 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -443,6 +443,15 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) */ error= handler_truncate(thd, table_ref, FALSE); + if (error == TRUNCATE_OK && thd->locked_tables_mode && + (table_ref->table->file->ht->flags & + HTON_REQUIRES_CLOSE_AFTER_TRUNCATE)) + { + thd->locked_tables_list.mark_table_for_reopen(thd, table_ref->table); + if (unlikely(thd->locked_tables_list.reopen_tables(thd, true))) + thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0); + } + /* All effects of a TRUNCATE TABLE operation are committed even if truncation fails in the case of non transactional tables. Thus, the diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 81a3f5c0da3..d206bb6f54c 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4121,8 +4121,9 @@ static int innodb_init(void* p) innobase_hton->flush_logs = innobase_flush_logs; innobase_hton->show_status = innobase_show_status; innobase_hton->flags = - HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS - | HTON_NATIVE_SYS_VERSIONING; + HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS | + HTON_NATIVE_SYS_VERSIONING | + HTON_REQUIRES_CLOSE_AFTER_TRUNCATE; #ifdef WITH_WSREP innobase_hton->abort_transaction=wsrep_abort_transaction; |