summaryrefslogtreecommitdiff
path: root/sql/sql_select.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r--sql/sql_select.cc125
1 files changed, 95 insertions, 30 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 8f68c929a9e..ed56191c32b 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);
}
@@ -3032,6 +3032,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 "
@@ -3079,7 +3080,8 @@ void JOIN::exec_inner()
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
error= do_select(curr_join, curr_fields_list, NULL, procedure);
thd->limit_found_rows= curr_join->send_records;
- 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);
@@ -9989,7 +9991,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;
}
@@ -12213,8 +12215,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) {}
};
/**
@@ -13603,6 +13605,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
@@ -13611,6 +13682,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)
@@ -13621,7 +13693,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)
@@ -13633,11 +13705,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)
@@ -13656,11 +13725,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)
@@ -13709,7 +13775,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]);
}
}
}
@@ -13731,14 +13798,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]);
}
}
}
@@ -18835,7 +18902,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"));
@@ -18857,8 +18925,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;
@@ -20689,11 +20758,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)
{