Commit 0955462d authored by Igor Babaev's avatar Igor Babaev

MDEV-18479 Assertion `join->best_read < double(1.79769313486231570815e+308L)'

or server crashes in JOIN::fix_all_splittings_in_plan after EXPLAIN

This patch resolves the problem of overflowing when performing
calculations to estimate the cost of an evaluated query execution plan.
The overflowing in a non-debug build could cause different kind of
problems uncluding crashes of the server.
parent 4584c186
This diff is collapsed.
This diff is collapsed.
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#endif #endif
#include "sql_base.h" #include "sql_base.h"
#include "sql_const.h"
#include "sql_select.h" #include "sql_select.h"
#include "filesort.h" #include "filesort.h"
#include "opt_subselect.h" #include "opt_subselect.h"
...@@ -1380,8 +1381,8 @@ void get_delayed_table_estimates(TABLE *table, ...@@ -1380,8 +1381,8 @@ void get_delayed_table_estimates(TABLE *table,
*startup_cost= item->jtbm_read_time; *startup_cost= item->jtbm_read_time;
/* Calculate cost of scanning the temptable */ /* Calculate cost of scanning the temptable */
double data_size= item->jtbm_record_count * double data_size= COST_MULT(item->jtbm_record_count,
hash_sj_engine->tmp_table->s->reclength; hash_sj_engine->tmp_table->s->reclength);
/* Do like in handler::read_time */ /* Do like in handler::read_time */
*scan_time= data_size/IO_SIZE + 2; *scan_time= data_size/IO_SIZE + 2;
} }
...@@ -2451,7 +2452,8 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map) ...@@ -2451,7 +2452,8 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
int tableno; int tableno;
double rows= 1.0; double rows= 1.0;
while ((tableno = tm_it.next_bit()) != Table_map_iterator::BITMAP_END) while ((tableno = tm_it.next_bit()) != Table_map_iterator::BITMAP_END)
rows *= join->map2table[tableno]->table->quick_condition_rows; rows= COST_MULT(rows,
join->map2table[tableno]->table->quick_condition_rows);
sjm->rows= min(sjm->rows, rows); sjm->rows= min(sjm->rows, rows);
} }
memcpy(sjm->positions, join->best_positions + join->const_tables, memcpy(sjm->positions, join->best_positions + join->const_tables,
...@@ -2564,7 +2566,7 @@ static uint get_tmp_table_rec_length(Item **p_items, uint elements) ...@@ -2564,7 +2566,7 @@ static uint get_tmp_table_rec_length(Item **p_items, uint elements)
static double static double
get_tmp_table_lookup_cost(THD *thd, double row_count, uint row_size) get_tmp_table_lookup_cost(THD *thd, double row_count, uint row_size)
{ {
if (row_count * row_size > thd->variables.max_heap_table_size) if (row_count > thd->variables.max_heap_table_size / (double) row_size)
return (double) DISK_TEMPTABLE_LOOKUP_COST; return (double) DISK_TEMPTABLE_LOOKUP_COST;
else else
return (double) HEAP_TEMPTABLE_LOOKUP_COST; return (double) HEAP_TEMPTABLE_LOOKUP_COST;
...@@ -2970,8 +2972,11 @@ bool Sj_materialization_picker::check_qep(JOIN *join, ...@@ -2970,8 +2972,11 @@ bool Sj_materialization_picker::check_qep(JOIN *join,
} }
double mat_read_time= prefix_cost.total_cost(); double mat_read_time= prefix_cost.total_cost();
mat_read_time += mat_info->materialization_cost.total_cost() + mat_read_time=
prefix_rec_count * mat_info->lookup_cost.total_cost(); COST_ADD(mat_read_time,
COST_ADD(mat_info->materialization_cost.total_cost(),
COST_MULT(prefix_rec_count,
mat_info->lookup_cost.total_cost())));
/* /*
NOTE: When we pick to use SJM[-Scan] we don't memcpy its POSITION NOTE: When we pick to use SJM[-Scan] we don't memcpy its POSITION
...@@ -3011,9 +3016,12 @@ bool Sj_materialization_picker::check_qep(JOIN *join, ...@@ -3011,9 +3016,12 @@ bool Sj_materialization_picker::check_qep(JOIN *join,
} }
/* Add materialization cost */ /* Add materialization cost */
prefix_cost += mat_info->materialization_cost.total_cost() + prefix_cost=
prefix_rec_count * mat_info->scan_cost.total_cost(); COST_ADD(prefix_cost,
prefix_rec_count *= mat_info->rows; COST_ADD(mat_info->materialization_cost.total_cost(),
COST_MULT(prefix_rec_count,
mat_info->scan_cost.total_cost())));
prefix_rec_count= COST_MULT(prefix_rec_count, mat_info->rows);
uint i; uint i;
table_map rem_tables= remaining_tables; table_map rem_tables= remaining_tables;
...@@ -3027,8 +3035,8 @@ bool Sj_materialization_picker::check_qep(JOIN *join, ...@@ -3027,8 +3035,8 @@ bool Sj_materialization_picker::check_qep(JOIN *join,
{ {
best_access_path(join, join->positions[i].table, rem_tables, i, best_access_path(join, join->positions[i].table, rem_tables, i,
disable_jbuf, prefix_rec_count, &curpos, &dummy); disable_jbuf, prefix_rec_count, &curpos, &dummy);
prefix_rec_count *= curpos.records_read; prefix_rec_count= COST_MULT(prefix_rec_count, curpos.records_read);
prefix_cost += curpos.read_time; prefix_cost= COST_ADD(prefix_cost, curpos.read_time);
} }
*strategy= SJ_OPT_MATERIALIZE_SCAN; *strategy= SJ_OPT_MATERIALIZE_SCAN;
...@@ -3335,16 +3343,18 @@ bool Duplicate_weedout_picker::check_qep(JOIN *join, ...@@ -3335,16 +3343,18 @@ bool Duplicate_weedout_picker::check_qep(JOIN *join,
for (uint j= first_dupsweedout_table; j <= idx; j++) for (uint j= first_dupsweedout_table; j <= idx; j++)
{ {
POSITION *p= join->positions + j; POSITION *p= join->positions + j;
current_fanout *= p->records_read; current_fanout= COST_MULT(current_fanout, p->records_read);
dups_cost += p->read_time + current_fanout / TIME_FOR_COMPARE; dups_cost= COST_ADD(dups_cost,
COST_ADD(p->read_time,
current_fanout / TIME_FOR_COMPARE));
if (p->table->emb_sj_nest) if (p->table->emb_sj_nest)
{ {
sj_inner_fanout *= p->records_read; sj_inner_fanout= COST_MULT(sj_inner_fanout, p->records_read);
dups_removed_fanout |= p->table->table->map; dups_removed_fanout |= p->table->table->map;
} }
else else
{ {
sj_outer_fanout *= p->records_read; sj_outer_fanout= COST_MULT(sj_outer_fanout, p->records_read);
temptable_rec_size += p->table->table->file->ref_length; temptable_rec_size += p->table->table->file->ref_length;
} }
} }
...@@ -3363,12 +3373,13 @@ bool Duplicate_weedout_picker::check_qep(JOIN *join, ...@@ -3363,12 +3373,13 @@ bool Duplicate_weedout_picker::check_qep(JOIN *join,
sj_outer_fanout, sj_outer_fanout,
temptable_rec_size); temptable_rec_size);
double write_cost= join->positions[first_tab].prefix_record_count* double write_cost= COST_MULT(join->positions[first_tab].prefix_record_count,
sj_outer_fanout * one_write_cost; sj_outer_fanout * one_write_cost);
double full_lookup_cost= join->positions[first_tab].prefix_record_count* double full_lookup_cost=
sj_outer_fanout* sj_inner_fanout * COST_MULT(join->positions[first_tab].prefix_record_count,
one_lookup_cost; COST_MULT(sj_outer_fanout,
dups_cost += write_cost + full_lookup_cost; sj_inner_fanout * one_lookup_cost));
dups_cost= COST_ADD(dups_cost, COST_ADD(write_cost, full_lookup_cost));
*read_time= dups_cost; *read_time= dups_cost;
*record_count= prefix_rec_count * sj_outer_fanout; *record_count= prefix_rec_count * sj_outer_fanout;
...@@ -3515,8 +3526,8 @@ static void recalculate_prefix_record_count(JOIN *join, uint start, uint end) ...@@ -3515,8 +3526,8 @@ static void recalculate_prefix_record_count(JOIN *join, uint start, uint end)
if (j == join->const_tables) if (j == join->const_tables)
prefix_count= 1.0; prefix_count= 1.0;
else else
prefix_count= join->best_positions[j-1].prefix_record_count * prefix_count= COST_MULT(join->best_positions[j-1].prefix_record_count,
join->best_positions[j-1].records_read; join->best_positions[j-1].records_read);
join->best_positions[j].prefix_record_count= prefix_count; join->best_positions[j].prefix_record_count= prefix_count;
} }
...@@ -5807,14 +5818,16 @@ bool JOIN::choose_subquery_plan(table_map join_tables) ...@@ -5807,14 +5818,16 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
The cost of executing the subquery and storing its result in an indexed The cost of executing the subquery and storing its result in an indexed
temporary table. temporary table.
*/ */
double materialization_cost= inner_read_time_1 + double materialization_cost= COST_ADD(inner_read_time_1,
write_cost * inner_record_count_1; COST_MULT(write_cost,
inner_record_count_1));
materialize_strategy_cost= materialization_cost + materialize_strategy_cost= COST_ADD(materialization_cost,
outer_lookup_keys * lookup_cost; COST_MULT(outer_lookup_keys,
lookup_cost));
/* C.2 Compute the cost of the IN=>EXISTS strategy. */ /* C.2 Compute the cost of the IN=>EXISTS strategy. */
in_exists_strategy_cost= outer_lookup_keys * inner_read_time_2; in_exists_strategy_cost= COST_MULT(outer_lookup_keys, inner_read_time_2);
/* C.3 Compare the costs and choose the cheaper strategy. */ /* C.3 Compare the costs and choose the cheaper strategy. */
if (materialize_strategy_cost >= in_exists_strategy_cost) if (materialize_strategy_cost >= in_exists_strategy_cost)
......
...@@ -214,6 +214,14 @@ ...@@ -214,6 +214,14 @@
#define HEAP_TEMPTABLE_LOOKUP_COST 0.05 #define HEAP_TEMPTABLE_LOOKUP_COST 0.05
#define DISK_TEMPTABLE_LOOKUP_COST 1.0 #define DISK_TEMPTABLE_LOOKUP_COST 1.0
#define COST_MAX (DBL_MAX * (1.0 - DBL_EPSILON))
#define COST_ADD(c,d) (COST_MAX - (d) > (c) ? (c) + (d) : COST_MAX)
#define COST_MULT(c,f) (COST_MAX / (f) > (c) ? (c) * (f) : COST_MAX)
#define MY_CHARSET_BIN_MB_MAXLEN 1 #define MY_CHARSET_BIN_MB_MAXLEN 1
/** Don't pack string keys shorter than this (if PACK_KEYS=1 isn't used). */ /** Don't pack string keys shorter than this (if PACK_KEYS=1 isn't used). */
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment