Skip to content

Commit c8dc866

Browse files
committed
MDEV-20371: Invalid reads at plan refinement stage: join->positions...
best_access_path() is called from two optimization phases: 1. Plan choice phase, in choose_plan(). Here, the join prefix being considered is in join->positions[] 2. Plan refinement stage, in fix_semijoin_strategies_for_picked_join_order Here, the join prefix is in join->best_positions[] It used to access join->positions[] from stage #2. This didnt cause any valgrind or asan failures (as join->positions[] has been written-to before) but the effect was similar to that of reading the random data: The join prefix we've picked (in join->best_positions) could have nothing in common with the join prefix that was last to be considered (in join->positions).
1 parent 863a951 commit c8dc866

File tree

4 files changed

+52
-28
lines changed

4 files changed

+52
-28
lines changed

sql/opt_subselect.cc

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -456,11 +456,6 @@ bool find_eq_ref_candidate(TABLE *table, table_map sj_inner_tables);
456456
static SJ_MATERIALIZATION_INFO *
457457
at_sjmat_pos(const JOIN *join, table_map remaining_tables, const JOIN_TAB *tab,
458458
uint idx, bool *loose_scan);
459-
void best_access_path(JOIN *join, JOIN_TAB *s,
460-
table_map remaining_tables, uint idx,
461-
bool disable_jbuf, double record_count,
462-
POSITION *pos, POSITION *loose_scan_pos);
463-
464459
static Item *create_subq_in_equalities(THD *thd, SJ_MATERIALIZATION_INFO *sjm,
465460
Item_in_subselect *subq_pred);
466461
static void remove_sj_conds(THD *thd, Item **tree);
@@ -2756,6 +2751,13 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx,
27562751
NULL,
27572752
};
27582753

2754+
#ifdef HAVE_valgrind
2755+
new (&pos->firstmatch_picker) Firstmatch_picker;
2756+
new (&pos->loosescan_picker) LooseScan_picker;
2757+
new (&pos->sjmat_picker) Sj_materialization_picker;
2758+
new (&pos->dups_weedout_picker) Duplicate_weedout_picker;
2759+
#endif
2760+
27592761
if (join->emb_sjm_nest)
27602762
{
27612763
/*
@@ -3045,7 +3047,8 @@ bool Sj_materialization_picker::check_qep(JOIN *join,
30453047
bool disable_jbuf= (join->thd->variables.join_cache_level == 0);
30463048
for (i= first_tab + mat_info->tables; i <= idx; i++)
30473049
{
3048-
best_access_path(join, join->positions[i].table, rem_tables, i,
3050+
best_access_path(join, join->positions[i].table, rem_tables,
3051+
join->positions, i,
30493052
disable_jbuf, prefix_rec_count, &curpos, &dummy);
30503053
prefix_rec_count= COST_MULT(prefix_rec_count, curpos.records_read);
30513054
prefix_cost= COST_ADD(prefix_cost, curpos.read_time);
@@ -3661,7 +3664,8 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
36613664
join->cur_sj_inner_tables= 0;
36623665
for (i= first + sjm->tables; i <= tablenr; i++)
36633666
{
3664-
best_access_path(join, join->best_positions[i].table, rem_tables, i,
3667+
best_access_path(join, join->best_positions[i].table, rem_tables,
3668+
join->best_positions, i,
36653669
FALSE, prefix_rec_count,
36663670
join->best_positions + i, &dummy);
36673671
prefix_rec_count *= join->best_positions[i].records_read;
@@ -3693,8 +3697,9 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
36933697
{
36943698
if (join->best_positions[idx].use_join_buffer)
36953699
{
3696-
best_access_path(join, join->best_positions[idx].table,
3697-
rem_tables, idx, TRUE /* no jbuf */,
3700+
best_access_path(join, join->best_positions[idx].table,
3701+
rem_tables, join->best_positions, idx,
3702+
TRUE /* no jbuf */,
36983703
record_count, join->best_positions + idx, &dummy);
36993704
}
37003705
record_count *= join->best_positions[idx].records_read;
@@ -3724,7 +3729,8 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
37243729
if (join->best_positions[idx].use_join_buffer || (idx == first))
37253730
{
37263731
best_access_path(join, join->best_positions[idx].table,
3727-
rem_tables, idx, TRUE /* no jbuf */,
3732+
rem_tables, join->best_positions, idx,
3733+
TRUE /* no jbuf */,
37283734
record_count, join->best_positions + idx,
37293735
&loose_scan_pos);
37303736
if (idx==first)

sql/opt_subselect.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ class Loose_scan_opt
8888
KEYUSE *best_loose_scan_start_key;
8989

9090
uint best_max_loose_keypart;
91+
table_map best_ref_depend_map;
9192

9293
public:
9394
Loose_scan_opt():
@@ -250,13 +251,14 @@ class Loose_scan_opt
250251
best_loose_scan_records= records;
251252
best_max_loose_keypart= max_loose_keypart;
252253
best_loose_scan_start_key= start_key;
254+
best_ref_depend_map= 0;
253255
}
254256
}
255257
}
256258
}
257259

258260
void check_ref_access_part2(uint key, KEYUSE *start_key, double records,
259-
double read_time)
261+
double read_time, table_map ref_depend_map_arg)
260262
{
261263
if (part1_conds_met && read_time < best_loose_scan_cost)
262264
{
@@ -266,6 +268,7 @@ class Loose_scan_opt
266268
best_loose_scan_records= records;
267269
best_max_loose_keypart= max_loose_keypart;
268270
best_loose_scan_start_key= start_key;
271+
best_ref_depend_map= ref_depend_map_arg;
269272
}
270273
}
271274

@@ -281,6 +284,7 @@ class Loose_scan_opt
281284
best_loose_scan_records= rows2double(quick->records);
282285
best_max_loose_keypart= quick_max_loose_keypart;
283286
best_loose_scan_start_key= NULL;
287+
best_ref_depend_map= 0;
284288
}
285289
}
286290

@@ -296,7 +300,7 @@ class Loose_scan_opt
296300
pos->loosescan_picker.loosescan_parts= best_max_loose_keypart + 1;
297301
pos->use_join_buffer= FALSE;
298302
pos->table= tab;
299-
// todo need ref_depend_map ?
303+
pos->ref_depend_map= best_ref_depend_map;
300304
DBUG_PRINT("info", ("Produced a LooseScan plan, key %s, %s",
301305
tab->table->key_info[best_loose_scan_key].name,
302306
best_loose_scan_start_key? "(ref access)":

sql/sql_select.cc

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,6 @@ static int sort_keyuse(KEYUSE *a,KEYUSE *b);
9797
static bool are_tables_local(JOIN_TAB *jtab, table_map used_tables);
9898
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
9999
bool allow_full_scan, table_map used_tables);
100-
void best_access_path(JOIN *join, JOIN_TAB *s,
101-
table_map remaining_tables, uint idx,
102-
bool disable_jbuf, double record_count,
103-
POSITION *pos, POSITION *loose_scan_pos);
104100
static void optimize_straight_join(JOIN *join, table_map join_tables);
105101
static bool greedy_search(JOIN *join, table_map remaining_tables,
106102
uint depth, uint prune_level,
@@ -4571,6 +4567,13 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
45714567
{
45724568
if (choose_plan(join, all_table_map & ~join->const_table_map))
45734569
goto error;
4570+
4571+
#ifdef HAVE_valgrind
4572+
// JOIN::positions holds the current query plan. We've already
4573+
// made the plan choice, so we should only use JOIN::best_positions
4574+
for (uint k=join->const_tables; k < join->table_count; k++)
4575+
MEM_UNDEFINED(&join->positions[k], sizeof(join->positions[k]));
4576+
#endif
45744577
}
45754578
else
45764579
{
@@ -6285,6 +6288,7 @@ void
62856288
best_access_path(JOIN *join,
62866289
JOIN_TAB *s,
62876290
table_map remaining_tables,
6291+
const POSITION *join_positions,
62886292
uint idx,
62896293
bool disable_jbuf,
62906294
double record_count,
@@ -6388,7 +6392,7 @@ best_access_path(JOIN *join,
63886392
if (!(keyuse->used_tables & ~join->const_table_map))
63896393
const_part|= keyuse->keypart_map;
63906394

6391-
double tmp2= prev_record_reads(join->positions, idx,
6395+
double tmp2= prev_record_reads(join_positions, idx,
63926396
(found_ref | keyuse->used_tables));
63936397
if (tmp2 < best_prev_record_reads)
63946398
{
@@ -6429,7 +6433,7 @@ best_access_path(JOIN *join,
64296433
Really, there should be records=0.0 (yes!)
64306434
but 1.0 would be probably safer
64316435
*/
6432-
tmp= prev_record_reads(join->positions, idx, found_ref);
6436+
tmp= prev_record_reads(join_positions, idx, found_ref);
64336437
records= 1.0;
64346438
}
64356439
else
@@ -6445,7 +6449,7 @@ best_access_path(JOIN *join,
64456449
if ((key_flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME ||
64466450
MY_TEST(key_flags & HA_EXT_NOSAME))
64476451
{
6448-
tmp = prev_record_reads(join->positions, idx, found_ref);
6452+
tmp = prev_record_reads(join_positions, idx, found_ref);
64496453
records=1.0;
64506454
}
64516455
else
@@ -6689,7 +6693,8 @@ best_access_path(JOIN *join,
66896693
}
66906694

66916695
tmp= COST_ADD(tmp, s->startup_cost);
6692-
loose_scan_opt.check_ref_access_part2(key, start_key, records, tmp);
6696+
loose_scan_opt.check_ref_access_part2(key, start_key, records, tmp,
6697+
found_ref);
66936698
} /* not ft_key */
66946699
if (tmp + 0.0001 < best_time - records/(double) TIME_FOR_COMPARE)
66956700
{
@@ -7367,7 +7372,8 @@ optimize_straight_join(JOIN *join, table_map join_tables)
73677372
for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
73687373
{
73697374
/* Find the best access method from 's' to the current partial plan */
7370-
best_access_path(join, s, join_tables, idx, disable_jbuf, record_count,
7375+
best_access_path(join, s, join_tables, join->positions, idx,
7376+
disable_jbuf, record_count,
73717377
join->positions + idx, &loose_scan_pos);
73727378

73737379
/* compute the cost of the new plan extended with 's' */
@@ -8285,8 +8291,9 @@ best_extension_by_limited_search(JOIN *join,
82858291

82868292
/* Find the best access method from 's' to the current partial plan */
82878293
POSITION loose_scan_pos;
8288-
best_access_path(join, s, remaining_tables, idx, disable_jbuf,
8289-
record_count, join->positions + idx, &loose_scan_pos);
8294+
best_access_path(join, s, remaining_tables, join->positions, idx,
8295+
disable_jbuf, record_count, join->positions + idx,
8296+
&loose_scan_pos);
82908297

82918298
/* Compute the cost of extending the plan with 's' */
82928299
current_record_count= COST_MULT(record_count, position->records_read);
@@ -8672,11 +8679,11 @@ cache_record_length(JOIN *join,uint idx)
86728679
*/
86738680

86748681
double
8675-
prev_record_reads(POSITION *positions, uint idx, table_map found_ref)
8682+
prev_record_reads(const POSITION *positions, uint idx, table_map found_ref)
86768683
{
86778684
double found=1.0;
8678-
POSITION *pos_end= positions - 1;
8679-
for (POSITION *pos= positions + idx - 1; pos != pos_end; pos--)
8685+
const POSITION *pos_end= positions - 1;
8686+
for (const POSITION *pos= positions + idx - 1; pos != pos_end; pos--)
86808687
{
86818688
if (pos->table->table->map & found_ref)
86828689
{
@@ -15400,7 +15407,8 @@ void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab,
1540015407
if ((i == first_tab && first_alt) || join->positions[i].use_join_buffer)
1540115408
{
1540215409
/* Find the best access method that would not use join buffering */
15403-
best_access_path(join, rs, reopt_remaining_tables, i,
15410+
best_access_path(join, rs, reopt_remaining_tables,
15411+
join->positions, i,
1540415412
TRUE, rec_count,
1540515413
&pos, &loose_scan_pos);
1540615414
}

sql/sql_select.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,7 @@ class LooseScan_picker : public Semi_join_strategy_picker
792792
friend void best_access_path(JOIN *join,
793793
JOIN_TAB *s,
794794
table_map remaining_tables,
795+
const struct st_position *join_positions,
795796
uint idx,
796797
bool disable_jbuf,
797798
double record_count,
@@ -1960,6 +1961,11 @@ class store_key_const_item :public store_key_item
19601961
}
19611962
};
19621963

1964+
void best_access_path(JOIN *join, JOIN_TAB *s,
1965+
table_map remaining_tables,
1966+
const POSITION *join_positions, uint idx,
1967+
bool disable_jbuf, double record_count,
1968+
POSITION *pos, POSITION *loose_scan_pos);
19631969
bool cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref);
19641970
bool error_if_full_join(JOIN *join);
19651971
int report_error(TABLE *table, int error);
@@ -2277,7 +2283,7 @@ bool instantiate_tmp_table(TABLE *table, KEY *keyinfo,
22772283
ulonglong options);
22782284
bool open_tmp_table(TABLE *table);
22792285
void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps);
2280-
double prev_record_reads(POSITION *positions, uint idx, table_map found_ref);
2286+
double prev_record_reads(const POSITION *positions, uint idx, table_map found_ref);
22812287
void fix_list_after_tbl_changes(SELECT_LEX *new_parent, List<TABLE_LIST> *tlist);
22822288

22832289
struct st_cond_statistic

0 commit comments

Comments
 (0)