diff --git a/mysql-test/main/subselect_mat.result b/mysql-test/main/subselect_mat.result index bbe81cec319..c5b201c6f46 100644 --- a/mysql-test/main/subselect_mat.result +++ b/mysql-test/main/subselect_mat.result @@ -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'; diff --git a/mysql-test/main/subselect_sj_mat.result b/mysql-test/main/subselect_sj_mat.result index fe232009f42..5d09af61892 100644 --- a/mysql-test/main/subselect_sj_mat.result +++ b/mysql-test/main/subselect_sj_mat.result @@ -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 diff --git a/mysql-test/main/subselect_sj_mat.test b/mysql-test/main/subselect_sj_mat.test index 000581d5758..0b5cfd6ab7b 100644 --- a/mysql-test/main/subselect_sj_mat.test +++ b/mysql-test/main/subselect_sj_mat.test @@ -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 diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 1180b2acda2..9e49f800204 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -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); } /**************************************************************************** diff --git a/sql/opt_range.h b/sql/opt_range.h index b98e6fd061e..de9a9464447 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -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 { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9f2e65cb59f..0c8432afd91 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -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 &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 , 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;