Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions mysql-test/main/opt_context_replay_basic.result
Original file line number Diff line number Diff line change
Expand Up @@ -272,5 +272,28 @@ set optimizer_replay_context='opt_context';
EXPLAIN SELECT MAX(a) FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
set optimizer_replay_context='';
drop table t1;
#
# MDEV-39440: replay context doesn't work after altering the index
#
create table t1 (btn char(10) not null, key using HASH (btn)) engine=heap;
insert into t1 values ("a"),("b"),("c"),("d");
alter table t1 add column new_col char(1) not null, add key using HASH (btn,new_col), drop key btn;
update t1 set new_col=left(btn,1);
set optimizer_record_context=1;
explain select * from t1 where btn="a";
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL btn NULL NULL NULL 4 Using where
select context into dumpfile "../../tmp/dump1.sql"
from information_schema.optimizer_context;
set optimizer_record_context=0;
drop table t1;
set optimizer_replay_context='opt_context';
# Same query as above, must have same explain:
explain select * from t1 where btn="a";
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL btn NULL NULL NULL 4 Using where
set optimizer_replay_context='';
drop table t1;
drop database db1;
28 changes: 28 additions & 0 deletions mysql-test/main/opt_context_replay_basic.test
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,34 @@ set optimizer_replay_context='opt_context';
--echo # Same query as above, must have same explain:
EXPLAIN SELECT MAX(a) FROM t1;

set optimizer_replay_context='';
--remove_file "$MYSQLTEST_VARDIR/tmp/dump1.sql"
drop table t1;

--echo #
--echo # MDEV-39440: replay context doesn't work after altering the index
--echo #
create table t1 (btn char(10) not null, key using HASH (btn)) engine=heap;
insert into t1 values ("a"),("b"),("c"),("d");
alter table t1 add column new_col char(1) not null, add key using HASH (btn,new_col), drop key btn;
update t1 set new_col=left(btn,1);

set optimizer_record_context=1;
explain select * from t1 where btn="a";
select context into dumpfile "../../tmp/dump1.sql"
from information_schema.optimizer_context;
set optimizer_record_context=0;
drop table t1;
--disable_query_log
--disable_result_log
--source "$MYSQLTEST_VARDIR/tmp/dump1.sql"
--enable_query_log
--enable_result_log
set optimizer_replay_context='opt_context';
--echo # Same query as above, must have same explain:
explain select * from t1 where btn="a";

set optimizer_replay_context='';
--remove_file "$MYSQLTEST_VARDIR/tmp/dump1.sql"
drop table t1;

Expand Down
25 changes: 15 additions & 10 deletions sql/opt_range.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12471,6 +12471,13 @@ ha_rows check_quick_select(PARAM *param, uint idx, ha_rows limit,
ha_rows replay_ctx_max_index_blocks;
ha_rows replay_ctx_max_row_blocks;
bool replay_ctx_rc;
Optimizer_context_recorder *rec;
TABLE::OPT_RANGE *range= param->table->opt_range + keynr;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The range->max_index_blocks and range->max_row_blocks fields are only assigned values when rows != HA_POS_ERROR (lines 12557-12561 in the original code). Since the recording logic has been moved outside of this conditional block (lines 12591-12597), these fields will contain uninitialized values when rows == HA_POS_ERROR, which are then passed to rec->record_multi_range_read_info_const. These should be initialized to a safe default value (e.g., 0) to avoid recording garbage data and potential undefined behavior.

  TABLE::OPT_RANGE *range= param->table->opt_range + keynr;
  range->max_index_blocks= range->max_row_blocks= 0;

if (range)
{
range->max_index_blocks= 0;
range->max_row_blocks= 0;
}
DBUG_ENTER("check_quick_select");

/* Range not calculated yet */
Expand Down Expand Up @@ -12534,7 +12541,6 @@ ha_rows check_quick_select(PARAM *param, uint idx, ha_rows limit,
param->quick_rows[keynr]= rows;
if (rows != HA_POS_ERROR)
{
TABLE::OPT_RANGE *range= param->table->opt_range + keynr;
ha_rows table_records= param->table->stat_records();
if (rows > table_records)
{
Expand All @@ -12560,15 +12566,6 @@ ha_rows check_quick_select(PARAM *param, uint idx, ha_rows limit,
range->max_row_blocks=
MY_MIN(file->row_blocks(), rows * file->stats.block_size / IO_SIZE);

if (Optimizer_context_recorder *rec= param->thd->opt_ctx_recorder)
{
Range_print_enumerator_impl range_iter(param, idx, tree);
rec->record_multi_range_read_info_const(param->table->pos_in_table_list,
keynr, &range_iter, rows, cost,
range->max_index_blocks,
range->max_row_blocks);
}

if (update_tbl_stats)
{
param->table->opt_range_keys.set_bit(keynr);
Expand Down Expand Up @@ -12597,6 +12594,14 @@ ha_rows check_quick_select(PARAM *param, uint idx, ha_rows limit,
}
}

if (range && (rec= param->thd->opt_ctx_recorder))
{
Range_print_enumerator_impl range_iter(param, idx, tree);
rec->record_multi_range_read_info_const(
param->table->pos_in_table_list, keynr, &range_iter, rows, cost,
range->max_index_blocks, range->max_row_blocks);
}

/* Figure out if the key scan is ROR (returns rows in ROWID order) or not */
enum ha_key_alg key_alg= param->table->key_info[seq.real_keyno].algorithm;
if ((key_alg != HA_KEY_ALG_BTREE) && (key_alg!= HA_KEY_ALG_UNDEF))
Expand Down
Loading