mirror of
https://github.com/MariaDB/server.git
synced 2025-01-28 17:54:16 +01:00
MDEV-31983 jointable materialization subquery optimization ignoring
...errors, then failing ASSERT. UPDATE queries treat warnings as errors. In this case, an invalid condition "datetime_key_col >= '2012-01'" caused warning-as-error inside SQL_SELECT::test_quick_select(). The code that called test_quick_select() ignored this error and continued join optimization. Then it eventually reached a thd->is_error() check and failed to setup SJ-Materialization which failed an assert. Fixed this by making SQL_SELECT::test_quick_select() return error in its return value, and making any code that calls it to check for error condition and abort the query if the error is returned. Places in the code that didn't check for errors from SQL_SELECT::test_quick_select but now do: - get_quick_record_count() call in make_join_statistics(), - test_if_skip_sort_order(), - "Range checked for each record" code. Extra error handling fixes and commit text wording by Sergei Petrunia, Reviewed-by: Sergei Petrunia, Oleg Smirnov
This commit is contained in:
parent
2ba9702163
commit
ec2574fd8f
6 changed files with 278 additions and 101 deletions
|
@ -2687,6 +2687,19 @@ i1 i2
|
|||
1 4
|
||||
2 6
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# MDEV-31983 jointable materialization subquery optimization ignoring errors, then failing ASSERT.
|
||||
#
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (1),(2);
|
||||
CREATE TABLE t2 (b INT);
|
||||
INSERT INTO t2 VALUES (3),(4);
|
||||
CREATE TABLE t3 (c DATETIME, d INT, KEY(c));
|
||||
INSERT INTO t3 VALUES ('2012-11-11',5),('2012-12-12',6);
|
||||
UPDATE t1, t2 SET t1.a = 26 WHERE t2.b IN (SELECT MIN(d) FROM t3 WHERE c >= '2012-01');
|
||||
ERROR 22007: Incorrect datetime value: '2012-01' for column `test`.`t3`.`c` at row 1
|
||||
DROP TABLE t1, t2, t3;
|
||||
# end of 10.6 tests
|
||||
set @subselect_mat_test_optimizer_switch_value=null;
|
||||
set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off';
|
||||
set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on';
|
||||
|
|
|
@ -2729,3 +2729,16 @@ i1 i2
|
|||
1 4
|
||||
2 6
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# MDEV-31983 jointable materialization subquery optimization ignoring errors, then failing ASSERT.
|
||||
#
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (1),(2);
|
||||
CREATE TABLE t2 (b INT);
|
||||
INSERT INTO t2 VALUES (3),(4);
|
||||
CREATE TABLE t3 (c DATETIME, d INT, KEY(c));
|
||||
INSERT INTO t3 VALUES ('2012-11-11',5),('2012-12-12',6);
|
||||
UPDATE t1, t2 SET t1.a = 26 WHERE t2.b IN (SELECT MIN(d) FROM t3 WHERE c >= '2012-01');
|
||||
ERROR 22007: Incorrect datetime value: '2012-01' for column `test`.`t3`.`c` at row 1
|
||||
DROP TABLE t1, t2, t3;
|
||||
# end of 10.6 tests
|
||||
|
|
|
@ -2419,3 +2419,21 @@ WHERE alias1.i1 IN (
|
|||
);
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-31983 jointable materialization subquery optimization ignoring errors, then failing ASSERT.
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (1),(2);
|
||||
CREATE TABLE t2 (b INT);
|
||||
INSERT INTO t2 VALUES (3),(4);
|
||||
CREATE TABLE t3 (c DATETIME, d INT, KEY(c));
|
||||
INSERT INTO t3 VALUES ('2012-11-11',5),('2012-12-12',6);
|
||||
|
||||
--error ER_TRUNCATED_WRONG_VALUE
|
||||
UPDATE t1, t2 SET t1.a = 26 WHERE t2.b IN (SELECT MIN(d) FROM t3 WHERE c >= '2012-01');
|
||||
|
||||
# Cleanup
|
||||
DROP TABLE t1, t2, t3;
|
||||
|
||||
--echo # end of 10.6 tests
|
||||
|
|
|
@ -2671,24 +2671,34 @@ static int fill_used_fields_bitmap(PARAM *param)
|
|||
force_quick_range is really needed.
|
||||
|
||||
RETURN
|
||||
-1 if error or impossible select (i.e. certainly no rows will be selected)
|
||||
0 if can't use quick_select
|
||||
1 if found usable ranges and quick select has been successfully created.
|
||||
SQL_SELECT::
|
||||
IMPOSSIBLE_RANGE,
|
||||
impossible select (i.e. certainly no rows will be selected)
|
||||
ERROR,
|
||||
an error occurred, either memory or in evaluating conditions
|
||||
OK = 1,
|
||||
either
|
||||
found usable ranges and quick select has been successfully created.
|
||||
or can't use quick_select
|
||||
*/
|
||||
|
||||
int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
||||
table_map prev_tables,
|
||||
ha_rows limit, bool force_quick_range,
|
||||
bool ordered_output,
|
||||
bool remove_false_parts_of_where,
|
||||
bool only_single_index_range_scan,
|
||||
bool suppress_unusable_key_notes)
|
||||
quick_select_return
|
||||
SQL_SELECT::test_quick_select(THD *thd,
|
||||
key_map keys_to_use,
|
||||
table_map prev_tables,
|
||||
ha_rows limit, bool force_quick_range,
|
||||
bool ordered_output,
|
||||
bool remove_false_parts_of_where,
|
||||
bool only_single_index_range_scan,
|
||||
bool suppress_unusable_key_notes)
|
||||
{
|
||||
uint idx;
|
||||
double scan_time;
|
||||
Item *notnull_cond= NULL;
|
||||
TABLE_READ_PLAN *best_trp= NULL;
|
||||
SEL_ARG **backup_keys= 0;
|
||||
quick_select_return returnval= OK;
|
||||
|
||||
DBUG_ENTER("SQL_SELECT::test_quick_select");
|
||||
DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
|
||||
(ulong) keys_to_use.to_ulonglong(), (ulong) prev_tables,
|
||||
|
@ -2701,7 +2711,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
|||
head->with_impossible_ranges.clear_all();
|
||||
DBUG_ASSERT(!head->is_filled_at_execution());
|
||||
if (keys_to_use.is_clear_all() || head->is_filled_at_execution())
|
||||
DBUG_RETURN(0);
|
||||
DBUG_RETURN(OK);
|
||||
records= head->stat_records();
|
||||
notnull_cond= head->notnull_cond;
|
||||
if (!records)
|
||||
|
@ -2754,7 +2764,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
|||
bool force_group_by = false;
|
||||
|
||||
if (check_stack_overrun(thd, 2*STACK_MIN_SIZE + sizeof(PARAM), buff))
|
||||
DBUG_RETURN(0); // Fatal error flag is set
|
||||
DBUG_RETURN(ERROR); // Fatal error flag is set
|
||||
|
||||
/* set up parameter that is passed to all functions */
|
||||
bzero((void*) ¶m, sizeof(param));
|
||||
|
@ -2790,7 +2800,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
|||
{
|
||||
thd->no_errors=0;
|
||||
free_root(&alloc,MYF(0)); // Return memory & allocator
|
||||
DBUG_RETURN(-1); // Error
|
||||
DBUG_RETURN(ERROR);
|
||||
}
|
||||
key_parts= param.key_parts;
|
||||
|
||||
|
@ -2858,7 +2868,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
|||
{
|
||||
thd->no_errors=0;
|
||||
free_root(&alloc,MYF(0)); // Return memory & allocator
|
||||
DBUG_RETURN(-1); // Error
|
||||
DBUG_RETURN(ERROR);
|
||||
}
|
||||
|
||||
thd->mem_root= &alloc;
|
||||
|
@ -2910,7 +2920,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
|||
{
|
||||
if (tree->type == SEL_TREE::IMPOSSIBLE)
|
||||
{
|
||||
records=0L; /* Return -1 from this function. */
|
||||
records=0L;
|
||||
returnval= IMPOSSIBLE_RANGE;
|
||||
read_time= (double) HA_POS_ERROR;
|
||||
trace_range.add("impossible_range", true);
|
||||
goto free_mem;
|
||||
|
@ -2930,7 +2941,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
|||
thd->no_errors=0;
|
||||
thd->mem_root= param.old_root;
|
||||
free_root(&alloc, MYF(0));
|
||||
DBUG_RETURN(-1);
|
||||
DBUG_RETURN(ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3081,9 +3092,14 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
|||
delete quick;
|
||||
quick= NULL;
|
||||
}
|
||||
if (quick && records)
|
||||
returnval= OK;
|
||||
}
|
||||
possible_keys= param.possible_keys;
|
||||
|
||||
if (!records)
|
||||
returnval= IMPOSSIBLE_RANGE;
|
||||
|
||||
free_mem:
|
||||
if (unlikely(quick && best_trp && thd->trace_started()))
|
||||
{
|
||||
|
@ -3109,7 +3125,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
|||
Assume that if the user is using 'limit' we will only need to scan
|
||||
limit rows if we are using a key
|
||||
*/
|
||||
DBUG_RETURN(records ? MY_TEST(quick) : -1);
|
||||
DBUG_RETURN(returnval);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -1712,13 +1712,20 @@ class SQL_SELECT :public Sql_alloc {
|
|||
~SQL_SELECT();
|
||||
void cleanup();
|
||||
void set_quick(QUICK_SELECT_I *new_quick) { delete quick; quick= new_quick; }
|
||||
|
||||
/*
|
||||
@return
|
||||
true - for ERROR and IMPOSSIBLE_RANGE
|
||||
false - Ok
|
||||
*/
|
||||
bool check_quick(THD *thd, bool force_quick_range, ha_rows limit)
|
||||
{
|
||||
key_map tmp;
|
||||
tmp.set_all();
|
||||
return test_quick_select(thd, tmp, 0, limit, force_quick_range,
|
||||
FALSE, FALSE, FALSE) < 0;
|
||||
FALSE, FALSE, FALSE) != OK;
|
||||
}
|
||||
|
||||
/*
|
||||
RETURN
|
||||
0 if record must be skipped <-> (cond && cond->val_int() == 0)
|
||||
|
@ -1732,13 +1739,25 @@ class SQL_SELECT :public Sql_alloc {
|
|||
rc= -1;
|
||||
return rc;
|
||||
}
|
||||
int test_quick_select(THD *thd, key_map keys, table_map prev_tables,
|
||||
ha_rows limit, bool force_quick_range,
|
||||
bool ordered_output, bool remove_false_parts_of_where,
|
||||
bool only_single_index_range_scan,
|
||||
bool suppress_unusable_key_notes = 0);
|
||||
|
||||
enum quick_select_return_type {
|
||||
IMPOSSIBLE_RANGE = -1,
|
||||
ERROR,
|
||||
OK
|
||||
};
|
||||
|
||||
enum quick_select_return_type
|
||||
test_quick_select(THD *thd, key_map keys, table_map prev_tables,
|
||||
ha_rows limit,
|
||||
bool force_quick_range,
|
||||
bool ordered_output,
|
||||
bool remove_false_parts_of_where,
|
||||
bool only_single_index_range_scan,
|
||||
bool suppress_unusable_key_notes = 0);
|
||||
};
|
||||
|
||||
typedef enum SQL_SELECT::quick_select_return_type quick_select_return;
|
||||
|
||||
|
||||
class SQL_SELECT_auto
|
||||
{
|
||||
|
|
|
@ -105,9 +105,10 @@ static int sort_keyuse(KEYUSE *a,KEYUSE *b);
|
|||
static bool are_tables_local(JOIN_TAB *jtab, table_map used_tables);
|
||||
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
||||
bool allow_full_scan, table_map used_tables);
|
||||
static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
|
||||
static bool get_quick_record_count(THD *thd, SQL_SELECT *select,
|
||||
TABLE *table,
|
||||
const key_map *keys,ha_rows limit);
|
||||
const key_map *keys,ha_rows limit,
|
||||
ha_rows *quick_count);
|
||||
static void optimize_straight_join(JOIN *join, table_map join_tables);
|
||||
static bool greedy_search(JOIN *join, table_map remaining_tables,
|
||||
uint depth, uint prune_level,
|
||||
|
@ -204,8 +205,8 @@ static int join_read_last_key(JOIN_TAB *tab);
|
|||
static int join_no_more_records(READ_RECORD *info);
|
||||
static int join_read_next(READ_RECORD *info);
|
||||
static int join_init_quick_read_record(JOIN_TAB *tab);
|
||||
static int test_if_quick_select(JOIN_TAB *tab);
|
||||
static bool test_if_use_dynamic_range_scan(JOIN_TAB *join_tab);
|
||||
static quick_select_return test_if_quick_select(JOIN_TAB *tab);
|
||||
static int test_if_use_dynamic_range_scan(JOIN_TAB *join_tab);
|
||||
static int join_read_first(JOIN_TAB *tab);
|
||||
static int join_read_next(READ_RECORD *info);
|
||||
static int join_read_next_same(READ_RECORD *info);
|
||||
|
@ -245,7 +246,8 @@ static int test_if_order_by_key(JOIN *join,
|
|||
uint *used_key_parts);
|
||||
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
|
||||
ha_rows select_limit, bool no_changes,
|
||||
const key_map *map);
|
||||
const key_map *map,
|
||||
bool *fatal_error);
|
||||
static bool list_contains_unique_index(TABLE *table,
|
||||
bool (*find_func) (Field *, void *), void *data);
|
||||
static bool find_field_in_item_list (Field *field, void *data);
|
||||
|
@ -1891,7 +1893,8 @@ int JOIN::optimize()
|
|||
object a pointer to which is set in the field JOIN_TAB::rowid_filter of
|
||||
the joined table.
|
||||
|
||||
@retval false always
|
||||
@retval false Ok
|
||||
@retval true Error
|
||||
*/
|
||||
|
||||
bool JOIN::make_range_rowid_filters()
|
||||
|
@ -1934,18 +1937,21 @@ bool JOIN::make_range_rowid_filters()
|
|||
filter_map.merge(tab->table->with_impossible_ranges);
|
||||
bool force_index_save= tab->table->force_index;
|
||||
tab->table->force_index= true;
|
||||
int rc= sel->test_quick_select(thd, filter_map, (table_map) 0,
|
||||
(ha_rows) HA_POS_ERROR,
|
||||
true, false, true, true);
|
||||
quick_select_return rc;
|
||||
rc= sel->test_quick_select(thd, filter_map, (table_map) 0,
|
||||
(ha_rows) HA_POS_ERROR, true, false, true,
|
||||
true);
|
||||
tab->table->force_index= force_index_save;
|
||||
if (thd->is_error())
|
||||
goto no_filter;
|
||||
if (rc == SQL_SELECT::ERROR || thd->is_error())
|
||||
{
|
||||
DBUG_RETURN(true); /* Fatal error */
|
||||
}
|
||||
/*
|
||||
If SUBS_IN_TO_EXISTS strtrategy is chosen for the subquery then
|
||||
additional conditions are injected into WHERE/ON/HAVING and it may
|
||||
happen that the call of test_quick_select() discovers impossible range.
|
||||
*/
|
||||
if (rc == -1)
|
||||
if (rc == SQL_SELECT::IMPOSSIBLE_RANGE)
|
||||
{
|
||||
const_table_map|= tab->table->map;
|
||||
goto no_filter;
|
||||
|
@ -2959,20 +2965,29 @@ int JOIN::optimize_stage2()
|
|||
tab= &join_tab[const_tables];
|
||||
if (order)
|
||||
{
|
||||
bool fatal_err;
|
||||
skip_sort_order=
|
||||
test_if_skip_sort_order(tab, order, select_limit,
|
||||
true, // no_changes
|
||||
&tab->table->keys_in_use_for_order_by);
|
||||
&tab->table->keys_in_use_for_order_by,
|
||||
&fatal_err);
|
||||
if (fatal_err)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array,
|
||||
order, fields_list, all_fields,
|
||||
&all_order_fields_used)))
|
||||
{
|
||||
bool fatal_err= 0;
|
||||
const bool skip_group=
|
||||
skip_sort_order &&
|
||||
test_if_skip_sort_order(tab, group_list, select_limit,
|
||||
true, // no_changes
|
||||
&tab->table->keys_in_use_for_group_by);
|
||||
true, // no_changes
|
||||
&tab->table->keys_in_use_for_group_by,
|
||||
&fatal_err);
|
||||
if (fatal_err)
|
||||
DBUG_RETURN(1);
|
||||
|
||||
count_field_types(select_lex, &tmp_table_param, all_fields, 0);
|
||||
if ((skip_group && all_order_fields_used) ||
|
||||
select_limit == HA_POS_ERROR ||
|
||||
|
@ -3235,12 +3250,16 @@ int JOIN::optimize_stage2()
|
|||
'need_tmp' implies that there will be more postprocessing
|
||||
so the specified 'limit' should not be enforced yet.
|
||||
*/
|
||||
bool fatal_err;
|
||||
const ha_rows limit = need_tmp ? HA_POS_ERROR : select_limit;
|
||||
if (test_if_skip_sort_order(tab, group_list, limit, false,
|
||||
&tab->table->keys_in_use_for_group_by))
|
||||
&tab->table->keys_in_use_for_group_by,
|
||||
&fatal_err))
|
||||
{
|
||||
ordered_index_usage= ordered_index_group_by;
|
||||
}
|
||||
if (fatal_err)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3263,11 +3282,15 @@ int JOIN::optimize_stage2()
|
|||
else if (order && // ORDER BY wo/ preceding GROUP BY
|
||||
(simple_order || skip_sort_order)) // which is possibly skippable
|
||||
{
|
||||
bool fatal_err;
|
||||
if (test_if_skip_sort_order(tab, order, select_limit, false,
|
||||
&tab->table->keys_in_use_for_order_by))
|
||||
&tab->table->keys_in_use_for_order_by,
|
||||
&fatal_err))
|
||||
{
|
||||
ordered_index_usage= ordered_index_order_by;
|
||||
}
|
||||
if (fatal_err)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5114,40 +5137,59 @@ err:
|
|||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Create JOIN_TABS, make a guess about the table types,
|
||||
Approximate how many records will be used in each table
|
||||
*****************************************************************************/
|
||||
/**
|
||||
Approximate how many records are going to be returned by this table in this
|
||||
select with this key.
|
||||
|
||||
static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
|
||||
@param thd Thread handle
|
||||
@param select Select to be examined
|
||||
@param table The table of interest
|
||||
@param keys The keys of interest
|
||||
@param limit Maximum number of rows of interest
|
||||
@param quick_count Pointer to where we want the estimate written
|
||||
|
||||
@return Status
|
||||
@retval false Success
|
||||
@retval true Error
|
||||
|
||||
*/
|
||||
|
||||
static bool get_quick_record_count(THD *thd, SQL_SELECT *select,
|
||||
TABLE *table,
|
||||
const key_map *keys,ha_rows limit)
|
||||
const key_map *keys,ha_rows limit,
|
||||
ha_rows *quick_count)
|
||||
{
|
||||
int error;
|
||||
quick_select_return error;
|
||||
DBUG_ENTER("get_quick_record_count");
|
||||
uchar buff[STACK_BUFF_ALLOC];
|
||||
if (unlikely(check_stack_overrun(thd, STACK_MIN_SIZE, buff)))
|
||||
DBUG_RETURN(0); // Fatal error flag is set
|
||||
DBUG_RETURN(false); // Fatal error flag is set
|
||||
if (select)
|
||||
{
|
||||
{
|
||||
select->head=table;
|
||||
table->reginfo.impossible_range=0;
|
||||
if (likely((error=
|
||||
select->test_quick_select(thd, *(key_map *)keys,
|
||||
(table_map) 0,
|
||||
limit, 0, FALSE,
|
||||
TRUE, /* remove_where_parts*/
|
||||
FALSE, TRUE)) ==
|
||||
1))
|
||||
DBUG_RETURN(select->quick->records);
|
||||
if (unlikely(error == -1))
|
||||
error= select->test_quick_select(thd, *(key_map *)keys, (table_map) 0,
|
||||
limit, 0, FALSE,
|
||||
TRUE, /* remove_where_parts*/
|
||||
FALSE, TRUE);
|
||||
|
||||
if (error == SQL_SELECT::OK && select->quick)
|
||||
{
|
||||
*quick_count= select->quick->records;
|
||||
DBUG_RETURN(false);
|
||||
}
|
||||
if (error == SQL_SELECT::IMPOSSIBLE_RANGE)
|
||||
{
|
||||
table->reginfo.impossible_range=1;
|
||||
DBUG_RETURN(0);
|
||||
DBUG_RETURN(false);
|
||||
}
|
||||
if (unlikely(error == SQL_SELECT::ERROR))
|
||||
DBUG_RETURN(true);
|
||||
|
||||
DBUG_PRINT("warning",("Couldn't use record count on const keypart"));
|
||||
}
|
||||
DBUG_RETURN(HA_POS_ERROR); /* This shouldn't happend */
|
||||
*quick_count= HA_POS_ERROR;
|
||||
DBUG_RETURN(false); /* This shouldn't happen */
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -5860,11 +5902,10 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
|
|||
(SORT_INFO*) 0, 1, &error);
|
||||
if (!select)
|
||||
goto error;
|
||||
records= get_quick_record_count(join->thd, select, s->table,
|
||||
&s->const_keys, join->row_limit);
|
||||
if (join->thd->is_error())
|
||||
if (get_quick_record_count(join->thd, select, s->table,
|
||||
&s->const_keys, join->row_limit, &records))
|
||||
{
|
||||
/* get_quick_record_count generated an error */
|
||||
/* There was an error in test_quick_select */
|
||||
delete select;
|
||||
goto error;
|
||||
}
|
||||
|
@ -12634,15 +12675,18 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||
*/
|
||||
if (sel->cond && !sel->cond->fixed())
|
||||
sel->cond->quick_fix_field();
|
||||
quick_select_return res;
|
||||
|
||||
if (sel->test_quick_select(thd, tab->keys,
|
||||
((used_tables & ~ current_map) |
|
||||
OUTER_REF_TABLE_BIT),
|
||||
(join->select_options &
|
||||
OPTION_FOUND_ROWS ?
|
||||
HA_POS_ERROR :
|
||||
join->unit->lim.get_select_limit()), 0,
|
||||
FALSE, FALSE, FALSE) < 0)
|
||||
if ((res= sel->test_quick_select(thd, tab->keys,
|
||||
((used_tables & ~ current_map) |
|
||||
OUTER_REF_TABLE_BIT),
|
||||
(join->select_options &
|
||||
OPTION_FOUND_ROWS ?
|
||||
HA_POS_ERROR :
|
||||
join->unit->lim.get_select_limit()),
|
||||
0,
|
||||
FALSE, FALSE, FALSE)) ==
|
||||
SQL_SELECT::IMPOSSIBLE_RANGE)
|
||||
{
|
||||
/*
|
||||
Before reporting "Impossible WHERE" for the whole query
|
||||
|
@ -12650,18 +12694,22 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||
*/
|
||||
sel->cond=orig_cond;
|
||||
if (!*tab->on_expr_ref ||
|
||||
sel->test_quick_select(thd, tab->keys,
|
||||
used_tables & ~ current_map,
|
||||
(join->select_options &
|
||||
OPTION_FOUND_ROWS ?
|
||||
HA_POS_ERROR :
|
||||
join->unit->lim.get_select_limit()),0,
|
||||
FALSE, FALSE, FALSE, TRUE) < 0)
|
||||
(res= sel->test_quick_select(thd, tab->keys,
|
||||
used_tables & ~ current_map,
|
||||
(join->select_options &
|
||||
OPTION_FOUND_ROWS ?
|
||||
HA_POS_ERROR :
|
||||
join->unit->lim.get_select_limit()),
|
||||
0, FALSE, FALSE, FALSE, TRUE)) ==
|
||||
SQL_SELECT::IMPOSSIBLE_RANGE)
|
||||
DBUG_RETURN(1); // Impossible WHERE
|
||||
}
|
||||
else
|
||||
sel->cond=orig_cond;
|
||||
|
||||
if (res == SQL_SELECT::ERROR)
|
||||
DBUG_RETURN(1); /* Some error in one of test_quick_select calls */
|
||||
|
||||
/* Fix for EXPLAIN */
|
||||
if (sel->quick)
|
||||
join->best_positions[i].records_read= (double)sel->quick->records;
|
||||
|
@ -21472,6 +21520,7 @@ sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
|
|||
{
|
||||
enum_nested_loop_state rc;
|
||||
JOIN_CACHE *cache= join_tab->cache;
|
||||
int err;
|
||||
DBUG_ENTER("sub_select_cache");
|
||||
|
||||
/*
|
||||
|
@ -21497,7 +21546,7 @@ sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
|
|||
}
|
||||
join_tab->jbuf_loops_tracker->on_scan_init();
|
||||
|
||||
if (!test_if_use_dynamic_range_scan(join_tab))
|
||||
if (!(err= test_if_use_dynamic_range_scan(join_tab)))
|
||||
{
|
||||
if (!cache->put_record())
|
||||
DBUG_RETURN(NESTED_LOOP_OK);
|
||||
|
@ -21509,6 +21558,10 @@ sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
|
|||
rc= cache->join_records(FALSE);
|
||||
DBUG_RETURN(rc);
|
||||
}
|
||||
|
||||
if (err < 0)
|
||||
DBUG_RETURN(NESTED_LOOP_ERROR);
|
||||
|
||||
/*
|
||||
TODO: Check whether we really need the call below and we can't do
|
||||
without it. If it's not the case remove it.
|
||||
|
@ -22609,8 +22662,18 @@ join_read_prev_same(READ_RECORD *info)
|
|||
static int
|
||||
join_init_quick_read_record(JOIN_TAB *tab)
|
||||
{
|
||||
if (test_if_quick_select(tab) == -1)
|
||||
return -1; /* No possible records */
|
||||
quick_select_return res= test_if_quick_select(tab);
|
||||
|
||||
if (res == SQL_SELECT::ERROR)
|
||||
return 1; /* Fatal error */
|
||||
|
||||
if (res == SQL_SELECT::IMPOSSIBLE_RANGE)
|
||||
return -1; /* No possible records */
|
||||
|
||||
/*
|
||||
Proceed to read rows. If we've created a quick select, use it, otherwise
|
||||
do a full scan.
|
||||
*/
|
||||
return join_init_read_record(tab);
|
||||
}
|
||||
|
||||
|
@ -22622,7 +22685,13 @@ int read_first_record_seq(JOIN_TAB *tab)
|
|||
return tab->read_record.read_record();
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
/*
|
||||
@brief
|
||||
Create a new (dynamic) quick select.
|
||||
*/
|
||||
|
||||
static quick_select_return
|
||||
test_if_quick_select(JOIN_TAB *tab)
|
||||
{
|
||||
DBUG_EXECUTE_IF("show_explain_probe_test_if_quick_select",
|
||||
|
@ -22639,11 +22708,11 @@ test_if_quick_select(JOIN_TAB *tab)
|
|||
if (tab->table->file->inited != handler::NONE)
|
||||
tab->table->file->ha_index_or_rnd_end();
|
||||
|
||||
int res= tab->select->test_quick_select(tab->join->thd, tab->keys,
|
||||
(table_map) 0, HA_POS_ERROR, 0,
|
||||
FALSE, /*remove where parts*/FALSE,
|
||||
FALSE,
|
||||
/* no warnings */ TRUE);
|
||||
quick_select_return res;
|
||||
res= tab->select->test_quick_select(tab->join->thd, tab->keys,
|
||||
(table_map) 0, HA_POS_ERROR, 0,
|
||||
FALSE, /*remove where parts*/FALSE,
|
||||
FALSE, /* no warnings */ TRUE);
|
||||
if (tab->explain_plan && tab->explain_plan->range_checked_fer)
|
||||
tab->explain_plan->range_checked_fer->collect_data(tab->select->quick);
|
||||
|
||||
|
@ -22651,10 +22720,29 @@ test_if_quick_select(JOIN_TAB *tab)
|
|||
}
|
||||
|
||||
|
||||
static
|
||||
bool test_if_use_dynamic_range_scan(JOIN_TAB *join_tab)
|
||||
/*
|
||||
@return
|
||||
1 - Yes, use dynamically built range
|
||||
0 - No, don't use dynamic range (but there's no error)
|
||||
-1 - Fatal error
|
||||
*/
|
||||
|
||||
static
|
||||
int test_if_use_dynamic_range_scan(JOIN_TAB *join_tab)
|
||||
{
|
||||
return (join_tab->use_quick == 2 && test_if_quick_select(join_tab) > 0);
|
||||
if (unlikely(join_tab->use_quick == 2))
|
||||
{
|
||||
quick_select_return res= test_if_quick_select(join_tab);
|
||||
if (res == SQL_SELECT::ERROR)
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
/* Both OK and IMPOSSIBLE_RANGE go here */
|
||||
return join_tab->select->quick ? 1 : 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int join_init_read_record(JOIN_TAB *tab)
|
||||
|
@ -24477,7 +24565,8 @@ void compute_part_of_sort_key_for_equals(JOIN *join, TABLE *table,
|
|||
|
||||
The index must cover all fields in <order>, or it will not be considered.
|
||||
|
||||
@param no_changes No changes will be made to the query plan.
|
||||
@param no_changes No changes will be made to the query plan.
|
||||
@param fatal_error OUT A fatal error occurred
|
||||
|
||||
@todo
|
||||
- sergeyp: Results of all index merge selects actually are ordered
|
||||
|
@ -24491,7 +24580,7 @@ void compute_part_of_sort_key_for_equals(JOIN *join, TABLE *table,
|
|||
|
||||
static bool
|
||||
test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
||||
bool no_changes, const key_map *map)
|
||||
bool no_changes, const key_map *map, bool *fatal_error)
|
||||
{
|
||||
int ref_key;
|
||||
uint UNINIT_VAR(ref_key_parts);
|
||||
|
@ -24507,6 +24596,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||
bool changed_key= false;
|
||||
DBUG_ENTER("test_if_skip_sort_order");
|
||||
|
||||
*fatal_error= false;
|
||||
/* Check that we are always called with first non-const table */
|
||||
DBUG_ASSERT(tab == tab->join->join_tab + tab->join->const_tables);
|
||||
|
||||
|
@ -24644,7 +24734,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||
*/
|
||||
key_map new_ref_key_map;
|
||||
COND *save_cond;
|
||||
bool res;
|
||||
quick_select_return res;
|
||||
new_ref_key_map.clear_all(); // Force the creation of quick select
|
||||
new_ref_key_map.set_bit(new_ref_key); // only for new_ref_key.
|
||||
|
||||
|
@ -24659,9 +24749,11 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||
HA_POS_ERROR :
|
||||
tab->join->unit->
|
||||
lim.get_select_limit(),
|
||||
TRUE, TRUE, FALSE, FALSE) <= 0;
|
||||
if (res)
|
||||
TRUE, TRUE, FALSE, FALSE);
|
||||
if (res != SQL_SELECT::OK)
|
||||
{
|
||||
if (res == SQL_SELECT::ERROR)
|
||||
*fatal_error= true;
|
||||
select->cond= save_cond;
|
||||
goto use_filesort;
|
||||
}
|
||||
|
@ -24757,11 +24849,17 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||
cond_saved= true;
|
||||
}
|
||||
|
||||
select->test_quick_select(join->thd, tmp_map, 0,
|
||||
join->select_options & OPTION_FOUND_ROWS ?
|
||||
HA_POS_ERROR :
|
||||
join->unit->lim.get_select_limit(),
|
||||
TRUE, FALSE, FALSE, FALSE);
|
||||
quick_select_return res;
|
||||
res = select->test_quick_select(join->thd, tmp_map, 0,
|
||||
join->select_options & OPTION_FOUND_ROWS ?
|
||||
HA_POS_ERROR :
|
||||
join->unit->lim.get_select_limit(),
|
||||
TRUE, FALSE, FALSE, FALSE);
|
||||
if (res == SQL_SELECT::ERROR)
|
||||
{
|
||||
*fatal_error= true;
|
||||
goto use_filesort;
|
||||
}
|
||||
|
||||
if (cond_saved)
|
||||
select->cond= saved_cond;
|
||||
|
|
Loading…
Add table
Reference in a new issue