Commit 2c5e2278 authored by Mattias Jonsson's avatar Mattias Jonsson

Manual merge between bug#46362 and bug#20577.

parents f56dc208 3b756a01
This diff is collapsed.
This diff is collapsed.
......@@ -450,9 +450,7 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
}
}
DBUG_RETURN(l_time->time_type=
(number_of_fields <= 3 ? MYSQL_TIMESTAMP_DATE :
MYSQL_TIMESTAMP_DATETIME));
DBUG_RETURN(l_time->time_type);
err:
bzero((char*) l_time, sizeof(*l_time));
......
......@@ -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
item.
Compare the value stored in field, with the original item.
We need to use this on the range optimizer because in some cases
we can't store the value in the field without some precision/character loss.
@param field field which the item is converted and stored in
@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(),
......@@ -6871,28 +6878,49 @@ bool field_is_equal_to_item(Field *field,Item *item)
char field_buff[MAX_FIELD_WIDTH];
String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin),*item_result;
String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin);
enum_field_types field_type;
item_result=item->val_str(&item_tmp);
if (item->null_value)
return 1; // This must be true
return 0;
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)
return 1; // Both where of type int
return 0; // Both are of type int
if (res_type == DECIMAL_RESULT)
{
my_decimal item_buf, *item_val,
field_buf, *field_val;
item_val= item->val_decimal(&item_buf);
if (item->null_value)
return 1; // This must be true
return 0;
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();
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 result == field->val_real();
return 0;
}
Item_cache* Item_cache::get_cache(const Item *item)
......
......@@ -583,8 +583,8 @@ class Item {
left_endp FALSE <=> 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 '>'
FALSE <=> the comparison is '<=' or '>='
incl_endp IN FALSE <=> the comparison is '<' or '>'
TRUE <=> the comparison is '<=' or '>='
OUT The same but for the "F(x) $CMP$ F(const)" comparison
DESCRIPTION
......@@ -3125,4 +3125,4 @@ void mark_select_range_as_dependent(THD *thd,
extern Cached_item *new_Cached_item(THD *thd, Item *item);
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 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)
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 23:59:59' -> TO_DAYS(col) > TO_DAYS('2007-09-15')
which is different from the general case ("strictly less" changes to
"less or equal"):
col < '2007-09-15 12:34:56' -> TO_DAYS(col) <= TO_DAYS('2007-09-15')
*/
if (!left_endp && !(ltime.hour || ltime.minute || ltime.second ||
ltime.second_part))
; /* do nothing */
if ((!left_endp && !(ltime.hour || ltime.minute || ltime.second ||
ltime.second_part)) ||
(left_endp && ltime.hour == 23 && ltime.minute == 59 &&
ltime.second == 59))
/* do nothing */
;
else
*incl_endp= TRUE;
return res;
......
......@@ -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
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
......@@ -5934,7 +5934,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
switch (type) {
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;
/* fall through */
case Item_func::LE_FUNC:
......@@ -5948,11 +5948,16 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
break;
case Item_func::GT_FUNC:
/* Don't use open ranges for partial key_segments */
if (field_is_equal_to_item(field,value) &&
!(key_part->flag & HA_PART_KEY_SEG))
if ((!(key_part->flag & HA_PART_KEY_SEG)) &&
(stored_field_cmp_to_item(field, value) <= 0))
tree->min_flag=NEAR_MIN;
/* fall through */
tree->max_flag= NO_MAX_RANGE;
break;
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;
break;
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)
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--;
key2->use_count--;
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,
Field *field= part_info->part_field_array[0];
uint32 max_endpoint_val;
get_endpoint_func get_endpoint;
bool can_match_multiple_values; /* is not '=' */
uint field_len= field->pack_length_in_rec();
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,
else
assert(0);
if (part_info->part_type == RANGE_PARTITION ||
part_info->has_null_value)
can_match_multiple_values= (flags || !min_value || !max_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;
monotonic= part_info->part_expr->get_monotonicity_info();
if (monotonic == MONOTONIC_INCREASING_NOT_NULL ||
......@@ -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);
bool include_endp= !test(flags & NEAR_MIN);
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;
if (part_iter->part_nums.start == max_endpoint_val)
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