Commit 0a763971 authored by Mattias Jonsson's avatar Mattias Jonsson

Manual merge between bug#46362 and bug#20577.

sql/opt_range.cc:
  Removed duplicate code (if statement must have been duplicated during earlier merge).
sql/sql_partition.cc:
  After mergeing bug#46362 and bug#20577, the NULL partition was also searched
  when col = const, fixed by checking if = or range.
parents cb57e856 4655118b
This diff is collapsed.
This diff is collapsed.
...@@ -450,9 +450,7 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, ...@@ -450,9 +450,7 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
} }
} }
DBUG_RETURN(l_time->time_type= DBUG_RETURN(l_time->time_type);
(number_of_fields <= 3 ? MYSQL_TIMESTAMP_DATE :
MYSQL_TIMESTAMP_DATETIME));
err: err:
bzero((char*) l_time, sizeof(*l_time)); bzero((char*) l_time, sizeof(*l_time));
......
...@@ -6853,14 +6853,21 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) ...@@ -6853,14 +6853,21 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
} }
/** /**
Return true if the value stored in the field is equal to the const Compare the value stored in field, with the original item.
item.
We need to use this on the range optimizer because in some cases @param field field which the item is converted and stored in
we can't store the value in the field without some precision/character loss. @param item original item
@return Return an integer greater than, equal to, or less than 0 if
the value stored in the field is greater than, equal to,
or less than the original item
@note We only use this on the range optimizer/partition pruning,
because in some cases we can't store the value in the field
without some precision/character loss.
*/ */
bool field_is_equal_to_item(Field *field,Item *item) int stored_field_cmp_to_item(Field *field, Item *item)
{ {
Item_result res_type=item_cmp_type(field->result_type(), Item_result res_type=item_cmp_type(field->result_type(),
...@@ -6871,28 +6878,49 @@ bool field_is_equal_to_item(Field *field,Item *item) ...@@ -6871,28 +6878,49 @@ bool field_is_equal_to_item(Field *field,Item *item)
char field_buff[MAX_FIELD_WIDTH]; char field_buff[MAX_FIELD_WIDTH];
String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin),*item_result; String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin),*item_result;
String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin); String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin);
enum_field_types field_type;
item_result=item->val_str(&item_tmp); item_result=item->val_str(&item_tmp);
if (item->null_value) if (item->null_value)
return 1; // This must be true return 0;
field->val_str(&field_tmp); field->val_str(&field_tmp);
return !stringcmp(&field_tmp,item_result);
/*
If comparing DATE with DATETIME, append the time-part to the DATE.
So that the strings are equally formatted.
A DATE converted to string is 10 characters, and a DATETIME converted
to string is 19 characters.
*/
field_type= field->type();
if (field_type == MYSQL_TYPE_DATE &&
item_result->length() == 19)
field_tmp.append(" 00:00:00");
else if (field_type == MYSQL_TYPE_DATETIME &&
item_result->length() == 10)
item_result->append(" 00:00:00");
return stringcmp(&field_tmp,item_result);
} }
if (res_type == INT_RESULT) if (res_type == INT_RESULT)
return 1; // Both where of type int return 0; // Both are of type int
if (res_type == DECIMAL_RESULT) if (res_type == DECIMAL_RESULT)
{ {
my_decimal item_buf, *item_val, my_decimal item_buf, *item_val,
field_buf, *field_val; field_buf, *field_val;
item_val= item->val_decimal(&item_buf); item_val= item->val_decimal(&item_buf);
if (item->null_value) if (item->null_value)
return 1; // This must be true return 0;
field_val= field->val_decimal(&field_buf); field_val= field->val_decimal(&field_buf);
return !my_decimal_cmp(item_val, field_val); return my_decimal_cmp(item_val, field_val);
} }
double result= item->val_real(); double result= item->val_real();
if (item->null_value) if (item->null_value)
return 0;
double field_result= field->val_real();
if (field_result < result)
return -1;
else if (field_result > result)
return 1; return 1;
return result == field->val_real(); return 0;
} }
Item_cache* Item_cache::get_cache(const Item *item) Item_cache* Item_cache::get_cache(const Item *item)
......
...@@ -583,8 +583,8 @@ class Item { ...@@ -583,8 +583,8 @@ class Item {
left_endp FALSE <=> The interval is "x < const" or "x <= const" left_endp FALSE <=> The interval is "x < const" or "x <= const"
TRUE <=> The interval is "x > const" or "x >= const" TRUE <=> The interval is "x > const" or "x >= const"
incl_endp IN TRUE <=> the comparison is '<' or '>' incl_endp IN FALSE <=> the comparison is '<' or '>'
FALSE <=> the comparison is '<=' or '>=' TRUE <=> the comparison is '<=' or '>='
OUT The same but for the "F(x) $CMP$ F(const)" comparison OUT The same but for the "F(x) $CMP$ F(const)" comparison
DESCRIPTION DESCRIPTION
...@@ -3125,4 +3125,4 @@ void mark_select_range_as_dependent(THD *thd, ...@@ -3125,4 +3125,4 @@ void mark_select_range_as_dependent(THD *thd,
extern Cached_item *new_Cached_item(THD *thd, Item *item); extern Cached_item *new_Cached_item(THD *thd, Item *item);
extern Item_result item_cmp_type(Item_result a,Item_result b); extern Item_result item_cmp_type(Item_result a,Item_result b);
extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item); extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item);
extern bool field_is_equal_to_item(Field *field,Item *item); extern int stored_field_cmp_to_item(Field *field, Item *item);
...@@ -1006,15 +1006,19 @@ longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp) ...@@ -1006,15 +1006,19 @@ longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp)
point to day bound ("strictly less" comparison stays intact): point to day bound ("strictly less" comparison stays intact):
col < '2007-09-15 00:00:00' -> TO_DAYS(col) < TO_DAYS('2007-09-15') col < '2007-09-15 00:00:00' -> TO_DAYS(col) < TO_DAYS('2007-09-15')
col > '2007-09-15 23:59:59' -> TO_DAYS(col) > TO_DAYS('2007-09-15')
which is different from the general case ("strictly less" changes to which is different from the general case ("strictly less" changes to
"less or equal"): "less or equal"):
col < '2007-09-15 12:34:56' -> TO_DAYS(col) <= TO_DAYS('2007-09-15') col < '2007-09-15 12:34:56' -> TO_DAYS(col) <= TO_DAYS('2007-09-15')
*/ */
if (!left_endp && !(ltime.hour || ltime.minute || ltime.second || if ((!left_endp && !(ltime.hour || ltime.minute || ltime.second ||
ltime.second_part)) ltime.second_part)) ||
; /* do nothing */ (left_endp && ltime.hour == 23 && ltime.minute == 59 &&
ltime.second == 59))
/* do nothing */
;
else else
*incl_endp= TRUE; *incl_endp= TRUE;
return res; return res;
......
...@@ -5856,7 +5856,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, ...@@ -5856,7 +5856,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
but we'll need to convert '>' to '>=' and '<' to '<='. This will but we'll need to convert '>' to '>=' and '<' to '<='. This will
be done together with other types at the end of this function be done together with other types at the end of this function
(grep for field_is_equal_to_item) (grep for stored_field_cmp_to_item)
*/ */
} }
else else
...@@ -5934,7 +5934,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, ...@@ -5934,7 +5934,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
switch (type) { switch (type) {
case Item_func::LT_FUNC: case Item_func::LT_FUNC:
if (field_is_equal_to_item(field,value)) if (stored_field_cmp_to_item(field,value) == 0)
tree->max_flag=NEAR_MAX; tree->max_flag=NEAR_MAX;
/* fall through */ /* fall through */
case Item_func::LE_FUNC: case Item_func::LE_FUNC:
...@@ -5948,11 +5948,16 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, ...@@ -5948,11 +5948,16 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
break; break;
case Item_func::GT_FUNC: case Item_func::GT_FUNC:
/* Don't use open ranges for partial key_segments */ /* Don't use open ranges for partial key_segments */
if (field_is_equal_to_item(field,value) && if ((!(key_part->flag & HA_PART_KEY_SEG)) &&
!(key_part->flag & HA_PART_KEY_SEG)) (stored_field_cmp_to_item(field, value) <= 0))
tree->min_flag=NEAR_MIN; tree->min_flag=NEAR_MIN;
/* fall through */ tree->max_flag= NO_MAX_RANGE;
break;
case Item_func::GE_FUNC: case Item_func::GE_FUNC:
/* Don't use open ranges for partial key_segments */
if ((!(key_part->flag & HA_PART_KEY_SEG)) &&
(stored_field_cmp_to_item(field,value) < 0))
tree->min_flag= NEAR_MIN;
tree->max_flag=NO_MAX_RANGE; tree->max_flag=NO_MAX_RANGE;
break; break;
case Item_func::SP_EQUALS_FUNC: case Item_func::SP_EQUALS_FUNC:
...@@ -6443,13 +6448,6 @@ key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, uint clone_flag) ...@@ -6443,13 +6448,6 @@ key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
return 0; // Can't optimize this return 0; // Can't optimize this
} }
if ((key1->min_flag | key2->min_flag) & GEOM_FLAG)
{
key1->free_tree();
key2->free_tree();
return 0; // Can't optimize this
}
key1->use_count--; key1->use_count--;
key2->use_count--; key2->use_count--;
SEL_ARG *e1=key1->first(), *e2=key2->first(), *new_tree=0; SEL_ARG *e1=key1->first(), *e2=key2->first(), *new_tree=0;
......
...@@ -6730,6 +6730,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, ...@@ -6730,6 +6730,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
Field *field= part_info->part_field_array[0]; Field *field= part_info->part_field_array[0];
uint32 max_endpoint_val; uint32 max_endpoint_val;
get_endpoint_func get_endpoint; get_endpoint_func get_endpoint;
bool can_match_multiple_values; /* is not '=' */
uint field_len= field->pack_length_in_rec(); uint field_len= field->pack_length_in_rec();
part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE;
...@@ -6768,9 +6769,13 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, ...@@ -6768,9 +6769,13 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
else else
assert(0); assert(0);
if (part_info->part_type == RANGE_PARTITION || can_match_multiple_values= (flags || !min_value || !max_value ||
part_info->has_null_value) memcmp(min_value, max_value, field_len));
if (can_match_multiple_values &&
(part_info->part_type == RANGE_PARTITION ||
part_info->has_null_value))
{ {
/* Range scan on RANGE or LIST partitioned table */
enum_monotonicity_info monotonic; enum_monotonicity_info monotonic;
monotonic= part_info->part_expr->get_monotonicity_info(); monotonic= part_info->part_expr->get_monotonicity_info();
if (monotonic == MONOTONIC_INCREASING_NOT_NULL || if (monotonic == MONOTONIC_INCREASING_NOT_NULL ||
...@@ -6812,6 +6817,14 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, ...@@ -6812,6 +6817,14 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
store_key_image_to_rec(field, min_value, field_len); store_key_image_to_rec(field, min_value, field_len);
bool include_endp= !test(flags & NEAR_MIN); bool include_endp= !test(flags & NEAR_MIN);
part_iter->part_nums.start= get_endpoint(part_info, 1, include_endp); part_iter->part_nums.start= get_endpoint(part_info, 1, include_endp);
if (!can_match_multiple_values && part_info->part_expr->null_value)
{
/* col = x and F(x) = NULL -> only search NULL partition */
part_iter->part_nums.cur= part_iter->part_nums.start= 0;
part_iter->part_nums.end= 0;
part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
return 1;
}
part_iter->part_nums.cur= part_iter->part_nums.start; part_iter->part_nums.cur= part_iter->part_nums.start;
if (part_iter->part_nums.start == max_endpoint_val) if (part_iter->part_nums.start == max_endpoint_val)
return 0; /* No partitions */ return 0; /* No partitions */
......
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