diff options
author | Mattias Jonsson <mattias.jonsson@sun.com> | 2009-08-28 12:55:59 +0200 |
---|---|---|
committer | Mattias Jonsson <mattias.jonsson@sun.com> | 2009-08-28 12:55:59 +0200 |
commit | 0a76397171c3e53402aab78f9a6261bdfa2fca3c (patch) | |
tree | 810fbe1527988b56b8833ff44e31f1a6f4ab4484 /sql | |
parent | cb57e856b64689dc6b4209817b33ca7bfff73efa (diff) | |
parent | 4655118bea2bcb14a06f01046fb06052fd37214c (diff) | |
download | mariadb-git-0a76397171c3e53402aab78f9a6261bdfa2fca3c.tar.gz |
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.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 50 | ||||
-rw-r--r-- | sql/item.h | 6 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 10 | ||||
-rw-r--r-- | sql/opt_range.cc | 22 | ||||
-rw-r--r-- | sql/sql_partition.cc | 17 |
5 files changed, 74 insertions, 31 deletions
diff --git a/sql/item.cc b/sql/item.cc index 9551c5feaff..0ebb1d61a28 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -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) diff --git a/sql/item.h b/sql/item.h index 808e2370b1e..a2cff3ab3a9 100644 --- a/sql/item.h +++ b/sql/item.h @@ -583,8 +583,8 @@ public: 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); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index eefe47232ae..a9e5c71ab56 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -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; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 8dc2f4683dd..23126069a5d 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -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; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ad24af12087..d433ba0b0cc 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -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 */ |