diff options
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r-- | sql/sql_select.cc | 125 |
1 files changed, 95 insertions, 30 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc index cbb5868623c..90c3110b63a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -291,18 +291,18 @@ static double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, void dbug_serve_apcs(THD *thd, int n_calls) { const char *save_proc_info= thd->proc_info; - /* This is so that mysqltest knows we're ready to serve requests: */ - thd_proc_info(thd, "show_explain_trap"); /* Busy-wait for n_calls APC requests to arrive and be processed */ int n_apcs= thd->apc_target.n_calls_processed + n_calls; while (thd->apc_target.n_calls_processed < n_apcs) { - my_sleep(300); + /* This is so that mysqltest knows we're ready to serve requests: */ + thd_proc_info(thd, "show_explain_trap"); + my_sleep(30000); + thd_proc_info(thd, save_proc_info); if (thd->check_killed()) break; } - thd_proc_info(thd, save_proc_info); } @@ -3043,6 +3043,7 @@ void JOIN::exec_inner() const ha_rows select_limit_arg= select_options & OPTION_FOUND_ROWS ? HA_POS_ERROR : unit->select_limit_cnt; + curr_join->filesort_found_rows= filesort_limit_arg != HA_POS_ERROR; DBUG_PRINT("info", ("has_group_by %d " "curr_join->table_count %d " @@ -3089,7 +3090,8 @@ void JOIN::exec_inner() *curr_fields_list), Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); error= do_select(curr_join, curr_fields_list, NULL, procedure); - if (curr_join->order && curr_join->filesort_found_rows) + if (curr_join->order && curr_join->sortorder && + curr_join->filesort_found_rows) { /* Use info provided by filesort. */ DBUG_ASSERT(curr_join->table_count > curr_join->const_tables); @@ -10066,7 +10068,7 @@ bool generate_derived_keys_for_table(KEYUSE *keyuse, uint count, uint keys) else { /* Mark keyuses for this key to be excluded */ - for (KEYUSE *curr=save_first_keyuse; curr < first_keyuse; curr++) + for (KEYUSE *curr=save_first_keyuse; curr < keyuse; curr++) { curr->key= MAX_KEY; } @@ -12295,8 +12297,8 @@ public: { TRASH(ptr, size); } Item *and_level; - Item_func *cmp_func; - COND_CMP(Item *a,Item_func *b) :and_level(a),cmp_func(b) {} + Item_bool_func2 *cmp_func; + COND_CMP(Item *a,Item_bool_func2 *b) :and_level(a),cmp_func(b) {} }; /** @@ -13685,6 +13687,75 @@ static void update_const_equal_items(COND *cond, JOIN_TAB *tab, bool const_key) } +/** + Check if + WHERE expr=value AND expr=const + can be rewritten as: + WHERE const=value AND expr=const + + @param target - the target operator whose "expr" argument will be + replaced to "const". + @param target_expr - the target's "expr" which will be replaced to "const". + @param target_value - the target's second argument, it will remain unchanged. + @param source - the equality expression ("=" or "<=>") that + can be used to rewrite the "target" part + (under certain conditions, see the code). + @param source_expr - the source's "expr". It should be exactly equal to + the target's "expr" to make condition rewrite possible. + @param source_const - the source's "const" argument, it will be inserted + into "target" instead of "expr". +*/ +static bool +can_change_cond_ref_to_const(Item_bool_func2 *target, + Item *target_expr, Item *target_value, + Item_bool_func2 *source, + Item *source_expr, Item *source_const) +{ + if (!target_expr->eq(source_expr,0) || + target_value == source_const || + target_expr->cmp_context != source_expr->cmp_context) + return false; + if (target_expr->cmp_context == STRING_RESULT) + { + /* + In this example: + SET NAMES utf8 COLLATE utf8_german2_ci; + DROP TABLE IF EXISTS t1; + CREATE TABLE t1 (a CHAR(10) CHARACTER SET utf8); + INSERT INTO t1 VALUES ('o-umlaut'),('oe'); + SELECT * FROM t1 WHERE a='oe' COLLATE utf8_german2_ci AND a='oe'; + + the query should return only the row with 'oe'. + It should not return 'o-umlaut', because 'o-umlaut' does not match + the right part of the condition: a='oe' + ('o-umlaut' is not equal to 'oe' in utf8_general_ci, + which is the collation of the field "a"). + + If we change the right part from: + ... AND a='oe' + to + ... AND 'oe' COLLATE utf8_german2_ci='oe' + it will be evalulated to TRUE and removed from the condition, + so the overall query will be simplified to: + + SELECT * FROM t1 WHERE a='oe' COLLATE utf8_german2_ci; + + which will erroneously start to return both 'oe' and 'o-umlaut'. + So changing "expr" to "const" is not possible if the effective + collations of "target" and "source" are not exactly the same. + + Note, the code before the fix for MDEV-7152 only checked that + collations of "source_const" and "target_value" are the same. + This was not enough, as the bug report demonstrated. + */ + return + target->compare_collation() == source->compare_collation() && + target_value->collation.collation == source_const->collation.collation; + } + return true; // Non-string comparison +} + + /* change field = field to field = const for each found field = const in the and_level @@ -13693,6 +13764,7 @@ static void update_const_equal_items(COND *cond, JOIN_TAB *tab, bool const_key) static void change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list, Item *and_father, Item *cond, + Item_bool_func2 *field_value_owner, Item *field, Item *value) { if (cond->type() == Item::COND_ITEM) @@ -13703,7 +13775,7 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list, Item *item; while ((item=li++)) change_cond_ref_to_const(thd, save_list,and_level ? cond : item, item, - field, value); + field_value_owner, field, value); return; } if (cond->eq_cmp_result() == Item::COND_OK) @@ -13715,11 +13787,8 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list, Item *right_item= args[1]; Item_func::Functype functype= func->functype(); - if (right_item->eq(field,0) && left_item != value && - right_item->cmp_context == field->cmp_context && - (left_item->result_type() != STRING_RESULT || - value->result_type() != STRING_RESULT || - left_item->collation.collation == value->collation.collation)) + if (can_change_cond_ref_to_const(func, right_item, left_item, + field_value_owner, field, value)) { Item *tmp=value->clone_item(); if (tmp) @@ -13738,11 +13807,8 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list, func->set_cmp_func(); } } - else if (left_item->eq(field,0) && right_item != value && - left_item->cmp_context == field->cmp_context && - (right_item->result_type() != STRING_RESULT || - value->result_type() != STRING_RESULT || - right_item->collation.collation == value->collation.collation)) + else if (can_change_cond_ref_to_const(func, left_item, right_item, + field_value_owner, field, value)) { Item *tmp= value->clone_item(); if (tmp) @@ -13791,7 +13857,8 @@ propagate_cond_constants(THD *thd, I_List<COND_CMP> *save_list, Item **args= cond_cmp->cmp_func->arguments(); if (!args[0]->const_item()) change_cond_ref_to_const(thd, &save,cond_cmp->and_level, - cond_cmp->and_level, args[0], args[1]); + cond_cmp->and_level, + cond_cmp->cmp_func, args[0], args[1]); } } } @@ -13813,14 +13880,14 @@ propagate_cond_constants(THD *thd, I_List<COND_CMP> *save_list, resolve_const_item(thd, &args[1], args[0]); func->update_used_tables(); change_cond_ref_to_const(thd, save_list, and_father, and_father, - args[0], args[1]); + func, args[0], args[1]); } else if (left_const) { resolve_const_item(thd, &args[0], args[1]); func->update_used_tables(); change_cond_ref_to_const(thd, save_list, and_father, and_father, - args[1], args[0]); + func, args[1], args[0]); } } } @@ -18931,7 +18998,8 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), records are read. Because of optimization in some cases it can provide only select_limit_cnt+1 records. */ - if (join->order && join->filesort_found_rows && + if (join->order && join->sortorder && + join->filesort_found_rows && join->select_options & OPTION_FOUND_ROWS) { DBUG_PRINT("info", ("filesort NESTED_LOOP_QUERY_LIMIT")); @@ -18953,8 +19021,9 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), /* Join over all rows in table; Return number of found rows */ TABLE *table=jt->table; - join->select_options ^= OPTION_FOUND_ROWS; - if (join->filesort_found_rows) + join->select_options ^= OPTION_FOUND_ROWS; + if (table->sort.record_pointers || + (table->sort.io_cache && my_b_inited(table->sort.io_cache))) { /* Using filesort */ join->send_records= table->sort.found_records; @@ -20808,11 +20877,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, select, filesort_limit, 0, &examined_rows, &found_rows); table->sort.found_records= filesort_retval; - if (found_rows != HA_POS_ERROR) - { - tab->records= found_rows; // For SQL_CALC_ROWS - join->filesort_found_rows= true; - } + tab->records= found_rows; // For SQL_CALC_ROWS if (quick_created) { |