diff --git a/VERSION b/VERSION index 017d7bd5ba5..b7bb36d6024 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=6 -MYSQL_VERSION_PATCH=13 +MYSQL_VERSION_PATCH=14 SERVER_MATURITY=stable diff --git a/mysql-test/main/derived_cond_pushdown.result b/mysql-test/main/derived_cond_pushdown.result index 2cbdf9ae0b3..82a8dd89a05 100644 --- a/mysql-test/main/derived_cond_pushdown.result +++ b/mysql-test/main/derived_cond_pushdown.result @@ -18331,4 +18331,98 @@ a deallocate prepare stmt; drop view v1; drop table t1; +# +# MDEV-31240: condition pushed into splittable derived has reference to +# outer column and does not refer to any column of embedding +# select +# +create table t1 (a int); +insert into t1 select seq from seq_1_to_1000; +create table t2 (a int, b int, key (a)); +insert into t2 select mod(seq,100), rand(13) * mod(seq,500) from seq_1_to_1000; +create table t3 (a int); +insert into t3 values (3), (1); +analyze table t1, t2, t3 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status Table is already up to date +test.t3 analyze status Engine-independent statistics collected +test.t3 analyze status OK +explain select +a, +( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +from t1 limit 5; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 1000 +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY ref key0 key0 5 test.t1.a 2 +3 LATERAL DERIVED t2 ref a a 5 test.t1.a 10 +select +a, +( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +from t1 limit 5; +a ( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +1 1=804 +2 1=1056 +3 1=846 +4 1=947 +5 1=973 +truncate table t2; +insert into t2 select mod(seq,10), rand(15) * mod(seq,500) from seq_1_to_1000; +analyze table t2 persistent for all; +Table Op Msg_type Msg_text +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status Table is already up to date +explain select +a, +( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +from t1 limit 5; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 1000 +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY ref key0 key0 5 test.t1.a 100 +3 DERIVED t2 ALL a NULL NULL NULL 1000 Using temporary; Using filesort +select +a, +( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +from t1 limit 5; +a ( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +1 1=11858 +2 1=11380 +3 1=11588 +4 1=11373 +5 1=11612 +drop table t1,t2,t3; # End of 10.4 tests diff --git a/mysql-test/main/derived_cond_pushdown.test b/mysql-test/main/derived_cond_pushdown.test index 08d0854df57..64e77b79af4 100644 --- a/mysql-test/main/derived_cond_pushdown.test +++ b/mysql-test/main/derived_cond_pushdown.test @@ -3973,4 +3973,45 @@ deallocate prepare stmt; drop view v1; drop table t1; +--echo # +--echo # MDEV-31240: condition pushed into splittable derived has reference to +--echo # outer column and does not refer to any column of embedding +--echo # select +--echo # + +create table t1 (a int); +insert into t1 select seq from seq_1_to_1000; + +create table t2 (a int, b int, key (a)); +insert into t2 select mod(seq,100), rand(13) * mod(seq,500) from seq_1_to_1000; + +create table t3 (a int); +insert into t3 values (3), (1); + +analyze table t1, t2, t3 persistent for all; + +let $q= +select + a, + ( select concat(t3.a,'=',dt.s) + from + (select a, sum(b) as s from t2 group by a) as dt, + t3 + where dt.a=t1.a and t3.a < 3 + ) +from t1 limit 5; + +eval explain $q; +eval $q; + +truncate table t2; +insert into t2 select mod(seq,10), rand(15) * mod(seq,500) from seq_1_to_1000; + +analyze table t2 persistent for all; + +eval explain $q; +eval $q; + +drop table t1,t2,t3; + --echo # End of 10.4 tests diff --git a/mysql-test/main/derived_split_innodb.result b/mysql-test/main/derived_split_innodb.result index 188a7f334b1..e491b631121 100644 --- a/mysql-test/main/derived_split_innodb.result +++ b/mysql-test/main/derived_split_innodb.result @@ -823,5 +823,20 @@ SELECT t1.* FROM t1 JOIN (SELECT id, COUNT(*) FROM t2 GROUP BY id) sq ON sq.id= a set optimizer_switch= @tmp1, join_cache_level= @tmp2; DROP TABLE t1, t2; +# +# MDEV-31403: Server crashes in st_join_table::choose_best_splitting (still) +# +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES +(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15); +CREATE TABLE t2 (b INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (100),(200); +CREATE TABLE t3 (c INT, d INT, KEY(c)) ENGINE=InnoDB; +INSERT INTO t3 VALUES (1,1),(2,2); +CREATE VIEW v AS SELECT c, d FROM t3 GROUP BY c, d; +SELECT * FROM t1 JOIN t2 WHERE (t1.a, t2.b) IN (SELECT * FROM v); +a b +DROP VIEW v; +DROP TABLE t1, t2, t3; # End of 10.4 tests SET GLOBAL innodb_stats_persistent=@save_innodb_stats_persistent; diff --git a/mysql-test/main/derived_split_innodb.test b/mysql-test/main/derived_split_innodb.test index 6ccbc31d886..bccda42d778 100644 --- a/mysql-test/main/derived_split_innodb.test +++ b/mysql-test/main/derived_split_innodb.test @@ -466,6 +466,27 @@ set optimizer_switch= @tmp1, join_cache_level= @tmp2; # Cleanup DROP TABLE t1, t2; +--echo # +--echo # MDEV-31403: Server crashes in st_join_table::choose_best_splitting (still) +--echo # +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES + (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15); + +CREATE TABLE t2 (b INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (100),(200); + +CREATE TABLE t3 (c INT, d INT, KEY(c)) ENGINE=InnoDB; +INSERT INTO t3 VALUES (1,1),(2,2); + +CREATE VIEW v AS SELECT c, d FROM t3 GROUP BY c, d; + +SELECT * FROM t1 JOIN t2 WHERE (t1.a, t2.b) IN (SELECT * FROM v); + +# Cleanup +DROP VIEW v; +DROP TABLE t1, t2, t3; + --echo # End of 10.4 tests SET GLOBAL innodb_stats_persistent=@save_innodb_stats_persistent; diff --git a/mysql-test/main/explain_non_select.result b/mysql-test/main/explain_non_select.result index 03259fff62b..74d8103f130 100644 --- a/mysql-test/main/explain_non_select.result +++ b/mysql-test/main/explain_non_select.result @@ -277,3 +277,22 @@ EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 2 drop table t1,t2; +# +# MDEV-31224: EXPLAIN EXTENDED for multi-table update of system table +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (3); +EXPLAIN EXTENDED UPDATE t1, t2 SET b = 4 WHERE a IN (6,2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 system NULL NULL NULL NULL 1 100.00 +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 update `test`.`t1` set `test`.`t2`.`b` = 4 where `test`.`t1`.`a` in (6,2) +UPDATE t1, t2 SET b = 4 WHERE a IN (6,2); +SELECT * from t2; +b +4 +DROP TABLE t1, t2; +# End of 10.4 tests diff --git a/mysql-test/main/explain_non_select.test b/mysql-test/main/explain_non_select.test index d9ff0fb7245..f87a5d9ec8d 100644 --- a/mysql-test/main/explain_non_select.test +++ b/mysql-test/main/explain_non_select.test @@ -250,3 +250,23 @@ PREPARE stmt FROM 'EXPLAIN INSERT INTO t1 SELECT * FROM t2'; EXECUTE stmt; drop table t1,t2; +--echo # +--echo # MDEV-31224: EXPLAIN EXTENDED for multi-table update of system table +--echo # + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); + +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (3); + +let $q= +UPDATE t1, t2 SET b = 4 WHERE a IN (6,2); + +eval EXPLAIN EXTENDED $q; +eval $q; +SELECT * from t2; + +DROP TABLE t1, t2; + +--echo # End of 10.4 tests diff --git a/mysql-test/main/myisam_explain_non_select_all.result b/mysql-test/main/myisam_explain_non_select_all.result index 210679ba29e..61fa42d1596 100644 --- a/mysql-test/main/myisam_explain_non_select_all.result +++ b/mysql-test/main/myisam_explain_non_select_all.result @@ -2689,7 +2689,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 system NULL NULL NULL NULL 0 0.00 Const row not found 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Warnings: -Note 1003 update `test`.`t1` set NULL = 10 +Note 1003 update `test`.`t1` set `test`.`t2`.`c2` = 10 # Status of EXPLAIN EXTENDED query Variable_name Value Handler_read_key 7 @@ -2734,7 +2734,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 system NULL NULL NULL NULL 0 0.00 Const row not found 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 update `test`.`t1` set NULL = 10 where `test`.`t1`.`c3` = 10 +Note 1003 update `test`.`t1` set `test`.`t2`.`c2` = 10 where `test`.`t1`.`c3` = 10 # Status of EXPLAIN EXTENDED query Variable_name Value Handler_read_key 7 diff --git a/mysql-test/suite/galera/r/MDEV-24143.result b/mysql-test/suite/galera/r/MDEV-24143.result new file mode 100644 index 00000000000..860d8a35834 --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-24143.result @@ -0,0 +1,23 @@ +connection node_2; +connection node_1; +CREATE TABLE t1 (c1 BIGINT NOT NULL PRIMARY KEY, c2 BINARY (10), c3 DATETIME); +SELECT get_lock ('test2', 0); +get_lock ('test2', 0) +1 +DROP TABLE t1; +CREATE TABLE t1 (c1 SMALLINT NOT NULL AUTO_INCREMENT PRIMARY KEY); +INSERT INTO t1 VALUES (1); +SET SESSION wsrep_trx_fragment_size=10; +SET SESSION autocommit=0; +SELECT * FROM t1 WHERE c1 <=0 ORDER BY c1 DESC; +c1 +INSERT INTO t1 VALUES (4),(3),(1),(2); +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +CREATE TABLE t1 (pk INT PRIMARY KEY, b INT) ENGINE=SEQUENCE; +ERROR 42S01: Table 't1' already exists +ALTER TABLE t1 DROP COLUMN c2; +ERROR 42000: Can't DROP COLUMN `c2`; check that it exists +SELECT get_lock ('test', 1.5); +get_lock ('test', 1.5) +1 +DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result b/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result new file mode 100644 index 00000000000..0ef2a1a72c6 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result @@ -0,0 +1,18 @@ +connection node_2; +connection node_1; +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; +connection node_2a; +SELECT GET_LOCK("foo", 1000); +GET_LOCK("foo", 1000) +1 +connection node_2; +SET AUTOCOMMIT=OFF; +INSERT INTO t1 VALUES (1); +SELECT GET_LOCK("foo", 1000);; +connection node_1; +INSERT INTO t1 VALUES (1); +connection node_2; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +wsrep_local_aborts_increment +1 +DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/galera_locks_funcs.result b/mysql-test/suite/galera/r/galera_locks_funcs.result deleted file mode 100644 index 25d3bbe28f5..00000000000 --- a/mysql-test/suite/galera/r/galera_locks_funcs.result +++ /dev/null @@ -1,24 +0,0 @@ -connection node_2; -connection node_1; -CREATE TABLE t (c DOUBLE,c2 INT,PRIMARY KEY(c)) ENGINE=InnoDB; -INSERT INTO t values (1,1); -SELECT GET_LOCK('a',1); -ERROR 42000: This version of MariaDB doesn't yet support 'GET_LOCK in cluster (WSREP_ON=ON)' -SHOW WARNINGS; -Level Code Message -Error 1235 This version of MariaDB doesn't yet support 'GET_LOCK in cluster (WSREP_ON=ON)' -SELECT * FROM t; -c c2 -1 1 -SELECT RELEASE_LOCK('a'); -ERROR 42000: This version of MariaDB doesn't yet support 'RELEASE_LOCK in cluster (WSREP_ON=ON)' -SHOW WARNINGS; -Level Code Message -Error 1235 This version of MariaDB doesn't yet support 'RELEASE_LOCK in cluster (WSREP_ON=ON)' -SELECT RELEASE_ALL_LOCKS(); -ERROR 42000: This version of MariaDB doesn't yet support 'RELEASE_ALL_LOCKS in cluster (WSREP_ON=ON)' -SHOW WARNINGS; -Level Code Message -Error 1235 This version of MariaDB doesn't yet support 'RELEASE_ALL_LOCKS in cluster (WSREP_ON=ON)' -COMMIT; -DROP TABLE t; diff --git a/mysql-test/suite/galera/t/MDEV-24143.test b/mysql-test/suite/galera/t/MDEV-24143.test new file mode 100644 index 00000000000..e58f147cb7c --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-24143.test @@ -0,0 +1,20 @@ +--source include/galera_cluster.inc +--source include/have_sequence.inc + +CREATE TABLE t1 (c1 BIGINT NOT NULL PRIMARY KEY, c2 BINARY (10), c3 DATETIME); +SELECT get_lock ('test2', 0); +DROP TABLE t1; +CREATE TABLE t1 (c1 SMALLINT NOT NULL AUTO_INCREMENT PRIMARY KEY); +INSERT INTO t1 VALUES (1); +SET SESSION wsrep_trx_fragment_size=10; +SET SESSION autocommit=0; +SELECT * FROM t1 WHERE c1 <=0 ORDER BY c1 DESC; +--error ER_LOCK_DEADLOCK +INSERT INTO t1 VALUES (4),(3),(1),(2); +--error ER_TABLE_EXISTS_ERROR +CREATE TABLE t1 (pk INT PRIMARY KEY, b INT) ENGINE=SEQUENCE; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER TABLE t1 DROP COLUMN c2; +SELECT get_lock ('test', 1.5); +DROP TABLE t1; + diff --git a/mysql-test/suite/galera/t/galera_bf_abort_get_lock.test b/mysql-test/suite/galera/t/galera_bf_abort_get_lock.test new file mode 100644 index 00000000000..72fc1c5b583 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_bf_abort_get_lock.test @@ -0,0 +1,36 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +# +# Test a local transaction being aborted by a slave one while it is running a GET_LOCK() +# + +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; + +--let $galera_connection_name = node_2a +--let $galera_server_number = 2 +--source include/galera_connect.inc +--connection node_2a +SELECT GET_LOCK("foo", 1000); + +--connection node_2 +SET AUTOCOMMIT=OFF; +--let $wsrep_local_bf_aborts_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'` +INSERT INTO t1 VALUES (1); +--send SELECT GET_LOCK("foo", 1000); + +--connection node_1 +INSERT INTO t1 VALUES (1); + +--connection node_2 +--error ER_LOCK_DEADLOCK +--reap + +--let $wsrep_local_bf_aborts_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'` + +# Check that wsrep_local_bf_aborts has been incremented by exactly 1 +--disable_query_log +--eval SELECT $wsrep_local_bf_aborts_after - $wsrep_local_bf_aborts_before = 1 AS wsrep_local_aborts_increment; +--enable_query_log + +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_locks_funcs.test b/mysql-test/suite/galera/t/galera_locks_funcs.test deleted file mode 100644 index 42838e9585c..00000000000 --- a/mysql-test/suite/galera/t/galera_locks_funcs.test +++ /dev/null @@ -1,18 +0,0 @@ ---source include/galera_cluster.inc - -CREATE TABLE t (c DOUBLE,c2 INT,PRIMARY KEY(c)) ENGINE=InnoDB; -INSERT INTO t values (1,1); ---error ER_NOT_SUPPORTED_YET -SELECT GET_LOCK('a',1); -SHOW WARNINGS; -SELECT * FROM t; ---error ER_NOT_SUPPORTED_YET -SELECT RELEASE_LOCK('a'); -SHOW WARNINGS; -# New in 10.5 ---error ER_NOT_SUPPORTED_YET -SELECT RELEASE_ALL_LOCKS(); -SHOW WARNINGS; -COMMIT; -DROP TABLE t; - diff --git a/sql/item_create.cc b/sql/item_create.cc index dcc64ef10e8..d4234e5ab5b 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -3573,13 +3573,6 @@ Create_func_get_lock Create_func_get_lock::s_singleton; Item* Create_func_get_lock::create_2_arg(THD *thd, Item *arg1, Item *arg2) { -#ifdef WITH_WSREP - if (WSREP_ON && WSREP(thd)) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "GET_LOCK in cluster (WSREP_ON=ON)"); - return NULL; - } -#endif /* WITH_WSREP */ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_get_lock(thd, arg1, arg2); @@ -4869,13 +4862,6 @@ Create_func_release_all_locks Create_func_release_all_locks::s_singleton; Item* Create_func_release_all_locks::create_builder(THD *thd) { -#ifdef WITH_WSREP - if (WSREP_ON && WSREP(thd)) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "RELEASE_ALL_LOCKS in cluster (WSREP_ON=ON)"); - return NULL; - } -#endif /* WITH_WSREP */ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_release_all_locks(thd); @@ -4887,13 +4873,6 @@ Create_func_release_lock Create_func_release_lock::s_singleton; Item* Create_func_release_lock::create_1_arg(THD *thd, Item *arg1) { -#ifdef WITH_WSREP - if (WSREP_ON && WSREP(thd)) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "RELEASE_LOCK in cluster (WSREP_ON=ON)"); - return NULL; - } -#endif /* WITH_WSREP */ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_release_lock(thd, arg1); diff --git a/sql/opt_split.cc b/sql/opt_split.cc index 627aebe9dec..8cc4e86eed6 100644 --- a/sql/opt_split.cc +++ b/sql/opt_split.cc @@ -664,7 +664,8 @@ add_ext_keyuse_for_splitting(Dynamic_array *ext_keyuses, keyuse_ext.cond_guard= added_key_field->cond_guard; keyuse_ext.sj_pred_no= added_key_field->sj_pred_no; keyuse_ext.validity_ref= 0; - keyuse_ext.needed_in_prefix= added_key_field->val->used_tables(); + keyuse_ext.needed_in_prefix= added_key_field->val->used_tables() & + ~(OUTER_REF_TABLE_BIT | RAND_TABLE_BIT); keyuse_ext.validity_var= false; return ext_keyuses->push(keyuse_ext); } @@ -945,6 +946,7 @@ void reset_validity_vars_for_keyuses(KEYUSE_EXT *key_keyuse_ext_start, SplM_plan_info * JOIN_TAB::choose_best_splitting(uint idx, table_map remaining_tables, + const POSITION *join_positions, table_map *spl_pd_boundary) { SplM_opt_info *spl_opt_info= table->spl_opt_info; @@ -1042,7 +1044,7 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(uint idx, else { table_map last_found= this->table->map; - for (POSITION *pos= &this->join->positions[idx - 1]; ; pos--) + for (const POSITION *pos= &join_positions[idx - 1]; ; pos--) { if (pos->table->table->map & excluded_tables) continue; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 31e3e16b397..dba51b8a6e3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7897,6 +7897,7 @@ best_access_path(JOIN *join, if (s->table->is_splittable()) spl_plan= s->choose_best_splitting(idx, remaining_tables, + join_positions, &spl_pd_boundary); Json_writer_array trace_paths(thd, "considered_access_paths"); @@ -28988,7 +28989,7 @@ void st_select_lex::print_set_clause(THD *thd, String *str, else str->append(','); - item->print(str, query_type); + item->print(str, (enum_query_type) (query_type | QT_NO_DATA_EXPANSION)); str->append(STRING_WITH_LEN(" = ")); val->print(str, query_type); } diff --git a/sql/sql_select.h b/sql/sql_select.h index 88e6fd4e30f..2b840dcf010 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -700,6 +700,7 @@ typedef struct st_join_table { void add_keyuses_for_splitting(); SplM_plan_info *choose_best_splitting(uint idx, table_map remaining_tables, + const POSITION *join_positions, table_map *spl_pd_boundary); bool fix_splitting(SplM_plan_info *spl_plan, table_map excluded_tables, bool is_const_table); diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index 245b981974b..4ac33a37ecd 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -1053,7 +1053,7 @@ public: void close(); /** @return total number of active (non-prepared) transactions */ - ulint any_active_transactions(); + size_t any_active_transactions(size_t *prepared= nullptr); /** diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 0ce75fe84da..41ef2bccdc4 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -1548,7 +1548,7 @@ void srv_master_callback(void*) } /** @return whether purge should exit due to shutdown */ -static bool srv_purge_should_exit() +static bool srv_purge_should_exit(size_t old_history_size) { ut_ad(srv_shutdown_state <= SRV_SHUTDOWN_CLEANUP); @@ -1559,8 +1559,12 @@ static bool srv_purge_should_exit() return true; /* Slow shutdown was requested. */ + size_t prepared, active= trx_sys.any_active_transactions(&prepared); const size_t history_size= trx_sys.history_size(); - if (history_size) + + if (!history_size); + else if (!active && history_size == old_history_size && prepared); + else { static time_t progress_time; time_t now= time(NULL); @@ -1577,7 +1581,7 @@ static bool srv_purge_should_exit() return false; } - return !trx_sys.any_active_transactions(); + return !active; } /*********************************************************************//** @@ -1719,7 +1723,7 @@ fewer_threads: break; } - if (!srv_purge_should_exit()) + if (!srv_purge_should_exit(history_size)) goto loop; } @@ -1915,15 +1919,19 @@ ulint srv_get_task_queue_length() /** Shut down the purge threads. */ void srv_purge_shutdown() { - if (purge_sys.enabled()) { - if (!srv_fast_shutdown && !opt_bootstrap) - srv_update_purge_thread_count(innodb_purge_threads_MAX); - while(!srv_purge_should_exit()) { - ut_a(!purge_sys.paused()); - srv_wake_purge_thread_if_not_active(); - purge_coordinator_task.wait(); - } - purge_sys.coordinator_shutdown(); - srv_shutdown_purge_tasks(); - } + if (purge_sys.enabled()) + { + if (!srv_fast_shutdown && !opt_bootstrap) + srv_update_purge_thread_count(innodb_purge_threads_MAX); + size_t history_size= trx_sys.history_size(); + while (!srv_purge_should_exit(history_size)) + { + history_size= trx_sys.history_size(); + ut_a(!purge_sys.paused()); + srv_wake_purge_thread_if_not_active(); + purge_coordinator_task.wait(); + } + purge_sys.coordinator_shutdown(); + srv_shutdown_purge_tasks(); + } } diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 17666ddbd64..f1d0807b7fb 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -369,19 +369,6 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) undo = NULL; } -MY_ATTRIBUTE((nonnull, warn_unused_result)) -/** Remove undo log header from the history list. -@param[in,out] rseg rollback segment header page -@param[in] log undo log segment header page -@param[in] offset byte offset in the undo log segment header page -@param[in,out] mtr mini-transaction */ -static dberr_t trx_purge_remove_log_hdr(buf_block_t *rseg, buf_block_t* log, - uint16_t offset, mtr_t *mtr) -{ - return flst_remove(rseg, TRX_RSEG + TRX_RSEG_HISTORY, log, - uint16_t(offset + TRX_UNDO_HISTORY_NODE), mtr); -} - /** Free an undo log segment. @param block rollback segment header page @param mtr mini-transaction */ @@ -420,12 +407,13 @@ static void trx_purge_free_segment(buf_block_t *block, mtr_t &mtr) } /** Remove unnecessary history data from a rollback segment. -@param[in,out] rseg rollback segment -@param[in] limit truncate anything before this +@param rseg rollback segment +@param limit truncate anything before this +@param all whether everything can be truncated @return error code */ static dberr_t -trx_purge_truncate_rseg_history(trx_rseg_t& rseg, - const purge_sys_t::iterator& limit) +trx_purge_truncate_rseg_history(trx_rseg_t &rseg, + const purge_sys_t::iterator &limit, bool all) { fil_addr_t hdr_addr; mtr_t mtr; @@ -469,23 +457,24 @@ loop: goto func_exit; } + if (!all) + goto func_exit; + fil_addr_t prev_hdr_addr= flst_get_prev_addr(b->page.frame + hdr_addr.boffset + TRX_UNDO_HISTORY_NODE); prev_hdr_addr.boffset= static_cast(prev_hdr_addr.boffset - TRX_UNDO_HISTORY_NODE); - err= trx_purge_remove_log_hdr(rseg_hdr, b, hdr_addr.boffset, &mtr); + + err= flst_remove(rseg_hdr, TRX_RSEG + TRX_RSEG_HISTORY, b, + uint16_t(hdr_addr.boffset + TRX_UNDO_HISTORY_NODE), &mtr); if (UNIV_UNLIKELY(err != DB_SUCCESS)) goto func_exit; rseg_hdr->fix(); - if (mach_read_from_2(b->page.frame + hdr_addr.boffset + TRX_UNDO_NEXT_LOG) || - rseg.is_referenced() || - rseg.needs_purge > (purge_sys.head.trx_no - ? purge_sys.head.trx_no - : purge_sys.tail.trx_no)) - /* We cannot free the entire undo page. */; + if (mach_read_from_2(b->page.frame + hdr_addr.boffset + TRX_UNDO_NEXT_LOG)) + /* We cannot free the entire undo log segment. */; else { const uint32_t seg_size= @@ -613,7 +602,10 @@ TRANSACTIONAL_TARGET static void trx_purge_truncate_history() { ut_ad(rseg.is_persistent()); rseg.latch.wr_lock(SRW_LOCK_CALL); - if (dberr_t e= trx_purge_truncate_rseg_history(rseg, head)) + if (dberr_t e= + trx_purge_truncate_rseg_history(rseg, head, + !rseg.is_referenced() && + rseg.needs_purge <= head.trx_no)) err= e; rseg.latch.wr_unlock(); } @@ -692,7 +684,8 @@ not_free: } ut_ad(rseg.curr_size > cached); - if (rseg.curr_size > cached + 1) + if (rseg.curr_size > cached + 1 && + (rseg.history_size || srv_fast_shutdown || srv_undo_sources)) goto not_free; rseg.latch.rd_unlock(); diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index d344f3a0c83..33c408707cc 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -343,15 +343,29 @@ trx_sys_t::close() } /** @return total number of active (non-prepared) transactions */ -ulint trx_sys_t::any_active_transactions() +size_t trx_sys_t::any_active_transactions(size_t *prepared) { - uint32_t total_trx= 0; + size_t total_trx= 0, prepared_trx= 0; - trx_sys.trx_list.for_each([&total_trx](const trx_t &trx) { - if (trx.state == TRX_STATE_COMMITTED_IN_MEMORY || - (trx.state == TRX_STATE_ACTIVE && trx.id)) + trx_sys.trx_list.for_each([&](const trx_t &trx) { + switch (trx.state) { + case TRX_STATE_NOT_STARTED: + break; + case TRX_STATE_ACTIVE: + if (!trx.id) + break; + /* fall through */ + case TRX_STATE_COMMITTED_IN_MEMORY: total_trx++; + break; + case TRX_STATE_PREPARED: + case TRX_STATE_PREPARED_RECOVERED: + prepared_trx++; + } }); + if (prepared) + *prepared= prepared_trx; + return total_trx; }