diff --git a/mysql-test/main/opt_trace_store_ddls_sequence.result b/mysql-test/main/opt_trace_store_ddls_sequence.result new file mode 100644 index 0000000000000..49514a16b0d5c --- /dev/null +++ b/mysql-test/main/opt_trace_store_ddls_sequence.result @@ -0,0 +1,47 @@ +# +# MDEV-40388: sequence.simple fails on replay +# +# Auto-generated SEQUENCE-engine tables (seq__to_[_step_]) +# are discovered by the engine from their name and cannot be recreated +# with an explicit CREATE TABLE. Their DDL must therefore NOT be recorded +# into the optimizer trace, otherwise replaying the recorded context +# fails with "Table '...' already exists". +# +create database db1; +use db1; +create table t1 (a int, b int); +insert into t1 values (1,2),(2,3); +set optimizer_trace=1; +set optimizer_record_context=ON; +# +# A query over an auto-generated sequence table only. +# No ddl should be recorded for the sequence table. +# +explain select * from seq_15_to_1_step_12345; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE seq_15_to_1_step_12345 ALL NULL NULL NULL NULL 1 +set @ddls= (select json_detailed(json_extract(trace, '$**.ddl')) +from information_schema.optimizer_trace); +select ddl +from json_table(@ddls, '$[*]' columns(ddl text path '$')) as jt; +ddl +# +# A query joining a regular table with a sequence table. +# Only the regular table t1 should have its ddl recorded. +# +select t1.a from t1, seq_1_to_10 where t1.a = seq; +a +1 +2 +set @ddls= (select json_detailed(json_extract(trace, '$**.ddl')) +from information_schema.optimizer_trace); +select ddl +from json_table(@ddls, '$[*]' columns(ddl text path '$')) as jt; +ddl +CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci +set optimizer_record_context=OFF; +set optimizer_trace=0; +drop database db1; diff --git a/mysql-test/main/opt_trace_store_ddls_sequence.test b/mysql-test/main/opt_trace_store_ddls_sequence.test new file mode 100644 index 0000000000000..8a520ff8f02dc --- /dev/null +++ b/mysql-test/main/opt_trace_store_ddls_sequence.test @@ -0,0 +1,46 @@ +--source include/not_embedded.inc +--source include/have_sequence.inc +--source include/no_view_protocol.inc + +--echo # +--echo # MDEV-40388: sequence.simple fails on replay +--echo # +--echo # Auto-generated SEQUENCE-engine tables (seq__to_[_step_]) +--echo # are discovered by the engine from their name and cannot be recreated +--echo # with an explicit CREATE TABLE. Their DDL must therefore NOT be recorded +--echo # into the optimizer trace, otherwise replaying the recorded context +--echo # fails with "Table '...' already exists". +--echo # + +create database db1; +use db1; +create table t1 (a int, b int); +insert into t1 values (1,2),(2,3); + +set optimizer_trace=1; +set optimizer_record_context=ON; + +--echo # +--echo # A query over an auto-generated sequence table only. +--echo # No ddl should be recorded for the sequence table. +--echo # +explain select * from seq_15_to_1_step_12345; +set @ddls= (select json_detailed(json_extract(trace, '$**.ddl')) + from information_schema.optimizer_trace); +select ddl +from json_table(@ddls, '$[*]' columns(ddl text path '$')) as jt; + +--echo # +--echo # A query joining a regular table with a sequence table. +--echo # Only the regular table t1 should have its ddl recorded. +--echo # +select t1.a from t1, seq_1_to_10 where t1.a = seq; +set @ddls= (select json_detailed(json_extract(trace, '$**.ddl')) + from information_schema.optimizer_trace); +select ddl +from json_table(@ddls, '$[*]' columns(ddl text path '$')) as jt; + +set optimizer_record_context=OFF; +set optimizer_trace=0; + +drop database db1; diff --git a/sql/handler.h b/sql/handler.h index f0763aebe717c..24ed4dadf3ff2 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1926,6 +1926,7 @@ handlerton *ha_default_tmp_handlerton(THD *thd); #define HTON_ALTER_NOT_SUPPORTED (1 << 1) //Engine does not support alter #define HTON_CAN_RECREATE (1 << 2) //Delete all is used for truncate #define HTON_HIDDEN (1 << 3) //Engine does not appear in lists +#define HTON_TABLE_EXISTS_BY_NAME (1 << 4) //Tables auto-discovered from name; reject CREATE TABLE (e.g. SEQUENCE) #define HTON_NOT_USER_SELECTABLE (1 << 5) #define HTON_TEMPORARY_NOT_SUPPORTED (1 << 6) //Having temporary tables not supported #define HTON_SUPPORT_LOG_TABLES (1 << 7) //Engine supports log tables diff --git a/sql/opt_trace_ddl_info.cc b/sql/opt_trace_ddl_info.cc index 27e044fa2d4dd..aae62ce519340 100644 --- a/sql/opt_trace_ddl_info.cc +++ b/sql/opt_trace_ddl_info.cc @@ -62,6 +62,7 @@ static const uchar *get_rec_key(const void *entry_, size_t *length, - INFORMATION_SCHEMA tables - Tables in PERFORMANCE_SCHEMA and mysql database - Internal temporary ("work") tables + - Tables auto-discovered from their name (e.g. SEQUENCE), which reject CREATE TABLE */ static bool is_base_table(TABLE_LIST *tbl) { @@ -73,7 +74,9 @@ static bool is_base_table(TABLE_LIST *tbl) get_table_category(tbl->get_db_name(), tbl->get_table_name()) == TABLE_CATEGORY_USER && tbl->table->s->tmp_table != INTERNAL_TMP_TABLE && - tbl->table->s->tmp_table != SYSTEM_TMP_TABLE); + tbl->table->s->tmp_table != SYSTEM_TMP_TABLE && + !(tbl->table->s->db_type() && + (tbl->table->s->db_type()->flags & HTON_TABLE_EXISTS_BY_NAME))); } static bool dump_record_to_trace(THD *thd, DDL_Key *ddl_key, String *stmt) diff --git a/storage/sequence/sequence.cc b/storage/sequence/sequence.cc index 2f34d7c1a2fb6..7f5ce1ca7e8d9 100644 --- a/storage/sequence/sequence.cc +++ b/storage/sequence/sequence.cc @@ -531,6 +531,7 @@ static int init(void *p) hton->drop_table= drop_table; hton->discover_table= discover_table; hton->discover_table_existence= discover_table_existence; + hton->flags|= HTON_TABLE_EXISTS_BY_NAME; hton->commit= hton->rollback= [](THD *, bool) { return 0; }; hton->savepoint_set= hton->savepoint_rollback= hton->savepoint_release= [](THD *, void *) { return 0; };