diff --git a/include/my_base.h b/include/my_base.h index 7efa5eb9673..50a9abe0bc6 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -631,7 +631,13 @@ typedef struct st_key_multi_range key_range start_key; key_range end_key; range_id_t ptr; /* Free to use by caller (ptr to row etc) */ - uint range_flag; /* key range flags see above */ + /* + A set of range flags that describe both endpoints: UNIQUE_RANGE, + NULL_RANGE, EQ_RANGE, GEOM_FLAG. + (Flags that describe one endpoint, NO_{MIN|MAX}_RANGE, NEAR_{MIN|MAX} will + not be set here) + */ + uint range_flag; } KEY_MULTI_RANGE; diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result index 65caf3cd2ec..2e4cfb9acb7 100644 --- a/mysql-test/main/opt_trace.result +++ b/mysql-test/main/opt_trace.result @@ -8229,6 +8229,37 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.semijoin_table_pullout')) ] drop table t1,t2,t3; # +# MDEV-22401: Optimizer trace: multi-component range is not printed correctly +# +create table t1 (kp1 int, kp2 int, key(kp1, kp2)); +insert into t1 values (1,1),(1,5),(5,1),(5,5); +set optimizer_trace=1; +select * from t1 force index(kp1) where (kp1=2 and kp2 >=4); +kp1 kp2 +select JSON_DETAILED(JSON_EXTRACT(trace, '$**.range_scan_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE; +JSON_DETAILED(JSON_EXTRACT(trace, '$**.range_scan_alternatives')) +[ + + [ + + { + "index": "kp1", + "ranges": + [ + "(2,4) <= (kp1,kp2) <= (2)" + ], + "rowid_ordered": false, + "using_mrr": false, + "index_only": true, + "rows": 1, + "cost": 0.345829876, + "chosen": true + } + ] +] +drop table t1; +# End of 10.4 tests +# # Test many rows to see output of big cost numbers # select count(*) from seq_1_to_10000000; @@ -8326,4 +8357,5 @@ select count(*) from seq_1_to_10000000 { } ] } 0 0 +# End of 10.5 tests set optimizer_trace='enabled=off'; diff --git a/mysql-test/main/opt_trace.test b/mysql-test/main/opt_trace.test index ac8a1366ee5..2839dbad9e6 100644 --- a/mysql-test/main/opt_trace.test +++ b/mysql-test/main/opt_trace.test @@ -569,6 +569,20 @@ select JSON_DETAILED(JSON_EXTRACT(trace, '$**.semijoin_table_pullout')) from INF drop table t1,t2,t3; +--echo # +--echo # MDEV-22401: Optimizer trace: multi-component range is not printed correctly +--echo # + +create table t1 (kp1 int, kp2 int, key(kp1, kp2)); +insert into t1 values (1,1),(1,5),(5,1),(5,5); +set optimizer_trace=1; +select * from t1 force index(kp1) where (kp1=2 and kp2 >=4); +select JSON_DETAILED(JSON_EXTRACT(trace, '$**.range_scan_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE; +drop table t1; + +--echo # End of 10.4 tests + + --echo # --echo # Test many rows to see output of big cost numbers --echo # @@ -576,4 +590,5 @@ drop table t1,t2,t3; select count(*) from seq_1_to_10000000; select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE; +--echo # End of 10.5 tests set optimizer_trace='enabled=off'; diff --git a/mysql-test/main/rowid_filter.result b/mysql-test/main/rowid_filter.result index 6a5c41fd641..bce4d1ddbb5 100644 --- a/mysql-test/main/rowid_filter.result +++ b/mysql-test/main/rowid_filter.result @@ -2130,4 +2130,20 @@ EXPLAIN } } DROP TABLE t1,t2; +# +# MDEV-22160: SIGSEGV in st_join_table::save_explain_data on SELECT +# +set @save_optimizer_switch= @@optimizer_switch; +SET @@optimizer_switch="index_merge_sort_union=OFF"; +CREATE TABLE t1 (a INT, b INT, INDEX(a), INDEX(b)); +INSERT INTO t1 VALUES (0,0),(1,0),(-1,1), (-2,1), (-2,3), (-3,4), (-2,4); +explain +SELECT * FROM t1 WHERE a > 0 AND b=0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref|filter a,b b|a 5|5 const 2 (14%) Using where; Using rowid filter +SELECT * FROM t1 WHERE a > 0 AND b=0; +a b +1 0 +drop table t1; +SET @@optimizer_switch=@save_optimizer_switch; set @@use_stat_tables=@save_use_stat_tables; diff --git a/mysql-test/main/rowid_filter.test b/mysql-test/main/rowid_filter.test index 6f26e81db92..9ac9465963b 100644 --- a/mysql-test/main/rowid_filter.test +++ b/mysql-test/main/rowid_filter.test @@ -339,4 +339,20 @@ eval EXPLAIN FORMAT=JSON $q; DROP TABLE t1,t2; + +--echo # +--echo # MDEV-22160: SIGSEGV in st_join_table::save_explain_data on SELECT +--echo # + +set @save_optimizer_switch= @@optimizer_switch; +SET @@optimizer_switch="index_merge_sort_union=OFF"; +CREATE TABLE t1 (a INT, b INT, INDEX(a), INDEX(b)); +INSERT INTO t1 VALUES (0,0),(1,0),(-1,1), (-2,1), (-2,3), (-3,4), (-2,4); +explain +SELECT * FROM t1 WHERE a > 0 AND b=0; +SELECT * FROM t1 WHERE a > 0 AND b=0; +drop table t1; +SET @@optimizer_switch=@save_optimizer_switch; + + set @@use_stat_tables=@save_use_stat_tables; diff --git a/mysql-test/main/rowid_filter_innodb.result b/mysql-test/main/rowid_filter_innodb.result index 67417c82b61..d3507f6bb59 100644 --- a/mysql-test/main/rowid_filter_innodb.result +++ b/mysql-test/main/rowid_filter_innodb.result @@ -2079,6 +2079,22 @@ EXPLAIN } } DROP TABLE t1,t2; +# +# MDEV-22160: SIGSEGV in st_join_table::save_explain_data on SELECT +# +set @save_optimizer_switch= @@optimizer_switch; +SET @@optimizer_switch="index_merge_sort_union=OFF"; +CREATE TABLE t1 (a INT, b INT, INDEX(a), INDEX(b)); +INSERT INTO t1 VALUES (0,0),(1,0),(-1,1), (-2,1), (-2,3), (-3,4), (-2,4); +explain +SELECT * FROM t1 WHERE a > 0 AND b=0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref|filter a,b b|a 5|5 const 2 (14%) Using where; Using rowid filter +SELECT * FROM t1 WHERE a > 0 AND b=0; +a b +1 0 +drop table t1; +SET @@optimizer_switch=@save_optimizer_switch; set @@use_stat_tables=@save_use_stat_tables; # # MDEV-18755: possible RORI-plan and possible plan with range filter diff --git a/mysql-test/suite/galera/r/galera_var_cluster_conf_id.result b/mysql-test/suite/galera/r/galera_var_cluster_conf_id.result new file mode 100644 index 00000000000..2507b1f96f2 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_var_cluster_conf_id.result @@ -0,0 +1,10 @@ +connection node_2; +connection node_1; +connection node_1; +show status like 'wsrep_cluster_conf_id'; +Variable_name Value +wsrep_cluster_conf_id 2 +connection node_2; +show status like 'wsrep_cluster_conf_id'; +Variable_name Value +wsrep_cluster_conf_id 2 diff --git a/mysql-test/suite/galera/t/galera_var_cluster_conf_id.test b/mysql-test/suite/galera/t/galera_var_cluster_conf_id.test new file mode 100644 index 00000000000..95ade07f043 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_var_cluster_conf_id.test @@ -0,0 +1,7 @@ +--source include/galera_cluster.inc + +--connection node_1 +show status like 'wsrep_cluster_conf_id'; + +--connection node_2 +show status like 'wsrep_cluster_conf_id'; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 384b2d5ced2..569d53ced0c 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3223,8 +3223,18 @@ double records_in_column_ranges(PARAM *param, uint idx, key_range *min_endp, *max_endp; min_endp= range.start_key.length? &range.start_key : NULL; max_endp= range.end_key.length? &range.end_key : NULL; - rows= get_column_range_cardinality(field, min_endp, max_endp, - range.range_flag); + int range_flag= range.range_flag; + + if (!range.start_key.length) + range_flag |= NO_MIN_RANGE; + if (!range.end_key.length) + range_flag |= NO_MAX_RANGE; + if (range.start_key.flag == HA_READ_AFTER_KEY) + range_flag |= NEAR_MIN; + if (range.start_key.flag == HA_READ_BEFORE_KEY) + range_flag |= NEAR_MAX; + + rows= get_column_range_cardinality(field, min_endp, max_endp, range_flag); if (DBL_MAX == rows) { total_rows= DBL_MAX; @@ -15830,24 +15840,29 @@ void print_range(String *out, const KEY_PART_INFO *key_part, return; } - if (!(flag & NO_MIN_RANGE)) + if (range->start_key.length) { print_key_value(out, key_part, range->start_key.key, range->start_key.length); - if (flag & NEAR_MIN) + if (range->start_key.flag == HA_READ_AFTER_KEY) out->append(STRING_WITH_LEN(" < ")); - else + else if (range->start_key.flag == HA_READ_KEY_EXACT || + range->start_key.flag == HA_READ_KEY_OR_NEXT) out->append(STRING_WITH_LEN(" <= ")); + else + out->append(STRING_WITH_LEN(" ? ")); } print_keyparts_name(out, key_part, n_key_parts, keypart_map); - if (!(flag & NO_MAX_RANGE)) + if (range->end_key.length) { - if (flag & NEAR_MAX) + if (range->end_key.flag == HA_READ_BEFORE_KEY) out->append(STRING_WITH_LEN(" < ")); - else + else if (range->end_key.flag == HA_READ_AFTER_KEY) out->append(STRING_WITH_LEN(" <= ")); + else + out->append(STRING_WITH_LEN(" ? ")); print_key_value(out, key_part, range->end_key.key, range->end_key.length); } diff --git a/sql/opt_range_mrr.cc b/sql/opt_range_mrr.cc index 4afa06a7ca0..267d764bb3b 100644 --- a/sql/opt_range_mrr.cc +++ b/sql/opt_range_mrr.cc @@ -262,7 +262,6 @@ walk_up_n_right: else { max_key_parts= MY_MAX(cur->min_key_parts, cur->max_key_parts); - range->range_flag= cur->min_key_flag | cur->max_key_flag; range->start_key.key= seq->param->min_key; range->start_key.length= (uint)(cur->min_key - seq->param->min_key); @@ -298,6 +297,7 @@ walk_up_n_right: !memcmp(seq->param->min_key, seq->param->max_key, // (2) range->start_key.length); + range->range_flag= 0; if (is_eq_range_pred) { range->range_flag = EQ_RANGE; diff --git a/sql/wsrep_server_service.cc b/sql/wsrep_server_service.cc index 6d737463f07..50aea494255 100644 --- a/sql/wsrep_server_service.cc +++ b/sql/wsrep_server_service.cc @@ -201,6 +201,7 @@ void Wsrep_server_service::log_view( wsrep_update_cluster_state_uuid(os.str().c_str()); mysql_mutex_unlock(&LOCK_status); wsrep_config_state->set(view); + wsrep_cluster_conf_id= view.view_seqno().get(); if (view.status() == wsrep::view::primary) { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index f46b3087e57..2e4652cd4b0 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4134,27 +4134,35 @@ innobase_commit_low( { #ifdef WITH_WSREP const char* tmp = 0; - if (trx->is_wsrep()) { + const bool is_wsrep = trx->is_wsrep(); + THD* thd = trx->mysql_thd; + if (is_wsrep) { #ifdef WSREP_PROC_INFO char info[64]; info[sizeof(info) - 1] = '\0'; snprintf(info, sizeof(info) - 1, "innobase_commit_low():trx_commit_for_mysql(%lld)", - (long long) wsrep_thd_trx_seqno(trx->mysql_thd)); - tmp = thd_proc_info(trx->mysql_thd, info); + (long long) wsrep_thd_trx_seqno(thd)); + tmp = thd_proc_info(thd, info); #else - tmp = thd_proc_info(trx->mysql_thd, "innobase_commit_low()"); + tmp = thd_proc_info(thd, "innobase_commit_low()"); #endif /* WSREP_PROC_INFO */ } #endif /* WITH_WSREP */ if (trx_is_started(trx)) { - trx_commit_for_mysql(trx); - } - trx->will_lock = 0; + } else { + trx->will_lock = 0; #ifdef WITH_WSREP - if (trx->is_wsrep()) { thd_proc_info(trx->mysql_thd, tmp); } + trx->wsrep = false; #endif /* WITH_WSREP */ + } + +#ifdef WITH_WSREP + if (is_wsrep) { + thd_proc_info(thd, tmp); +#endif /* WITH_WSREP */ + } } /*****************************************************************//** @@ -4820,22 +4828,12 @@ static int innobase_close_connection(handlerton *hton, THD *thd) DBUG_ASSERT(hton == innodb_hton_ptr); if (auto trx= thd_to_trx(thd)) { - if (trx->state == TRX_STATE_PREPARED) + if (trx->state == TRX_STATE_PREPARED && trx->has_logged_persistent()) { - if (trx->has_logged_persistent()) - { - trx_disconnect_prepared(trx); - return 0; - } - innobase_rollback_trx(trx); + trx_disconnect_prepared(trx); + return 0; } - /* - in theory it may fire if preceding rollback failed, - but what can we do about it? - */ - DBUG_ASSERT(!trx_is_started(trx)); - /* some bad guy missed to reset trx->will_lock somewhere, reset it here */ - trx->will_lock= 0; + innobase_rollback_trx(trx); trx_free(trx); } return 0; @@ -5809,7 +5807,6 @@ ha_innobase::open(const char* name, int, uint) sql_print_error("Failed to open table %s.\n", norm_name); } -no_such_table: set_my_errno(ENOENT); DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); @@ -5835,7 +5832,8 @@ no_such_table: ib_table->file_unreadable = true; ib_table->corrupted = true; dict_table_close(ib_table, FALSE, FALSE); - goto no_such_table; + set_my_errno(ENOENT); + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); } innobase_copy_frm_flags_from_table_share(ib_table, table->s); diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 25cc6df36a0..be4504f71d8 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -442,6 +442,7 @@ Check transaction state */ ut_ad(!(t)->id); \ ut_ad(!(t)->has_logged()); \ ut_ad(!(t)->is_referenced()); \ + ut_ad(!(t)->is_wsrep()); \ ut_ad(!(t)->read_view.is_open()); \ ut_ad((t)->lock.wait_thr == NULL); \ ut_ad(UT_LIST_GET_LEN((t)->lock.trx_locks) == 0); \ diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index adf41906cb7..c20cf4842a0 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -208,6 +208,9 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) case TRX_STATE_NOT_STARTED: trx->will_lock = 0; ut_ad(trx->mysql_thd); +#ifdef WITH_WSREP + trx->wsrep = false; +#endif return(DB_SUCCESS); case TRX_STATE_ACTIVE: diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index dcddaabaf48..f9c8ede1f1b 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -109,9 +109,6 @@ trx_init( trx->state = TRX_STATE_NOT_STARTED; trx->is_recovered = false; -#ifdef WITH_WSREP - trx->wsrep = false; -#endif /* WITH_WSREP */ trx->op_info = ""; @@ -1489,6 +1486,17 @@ inline void trx_t::commit_in_memory(const mtr_t *mtr) DBUG_LOG("trx", "Commit in memory: " << this); state= TRX_STATE_NOT_STARTED; +#ifdef WITH_WSREP + /* Serialization history has been written and the transaction is + committed in memory, which makes this commit ordered. Release commit + order critical section. */ + if (wsrep) + { + wsrep= false; + wsrep_commit_ordered(mysql_thd); + } +#endif /* WITH_WSREP */ + assert_trx_is_free(this); trx_init(this); trx_mutex_exit(this); @@ -1566,13 +1574,6 @@ void trx_t::commit() local_mtr.start(); } commit_low(mtr); -#ifdef WITH_WSREP - /* Serialization history has been written and the transaction is - committed in memory, which makes this commit ordered. Release commit - order critical section. */ - if (mtr && is_wsrep()) - wsrep_commit_ordered(mysql_thd); -#endif /* WITH_WSREP */ } /****************************************************************//**