diff options
author | Mikael Ronstrom <mikael@mysql.com> | 2009-09-28 09:39:50 +0200 |
---|---|---|
committer | Mikael Ronstrom <mikael@mysql.com> | 2009-09-28 09:39:50 +0200 |
commit | ccae404afaddf98c16889fdd21c613b551ee5e5e (patch) | |
tree | f7dc27f11e200c4a174df0a91afb7bbd83e5dcc5 /sql/sql_partition.cc | |
parent | ec5b25954376265d187c57984d0416c50d0a1694 (diff) | |
parent | a8edd0aabb5059935b99076fbcc92403079535df (diff) | |
download | mariadb-git-ccae404afaddf98c16889fdd21c613b551ee5e5e.tar.gz |
Merge to mysql-next-mr
Diffstat (limited to 'sql/sql_partition.cc')
-rw-r--r-- | sql/sql_partition.cc | 79 |
1 files changed, 73 insertions, 6 deletions
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 53fc34d374e..f6a8e895fdc 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2766,8 +2766,24 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info, if (part_info->part_expr->null_value) { - DBUG_RETURN(0); + /* + Special handling for MONOTONIC functions that can return NULL for + values that are comparable. I.e. + '2000-00-00' can be compared to '2000-01-01' but TO_DAYS('2000-00-00') + returns NULL which cannot be compared used <, >, <=, >= etc. + + Otherwise, just return the the first index (lowest value). + */ + enum_monotonicity_info monotonic; + monotonic= part_info->part_expr->get_monotonicity_info(); + if (monotonic != MONOTONIC_INCREASING_NOT_NULL && + monotonic != MONOTONIC_STRICT_INCREASING_NOT_NULL) + { + /* F(col) can not return NULL, return index with lowest value */ + DBUG_RETURN(0); + } } + if (unsigned_flag) part_func_value-= 0x8000000000000000ULL; DBUG_ASSERT(part_info->no_list_values); @@ -2916,11 +2932,29 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info, if (part_info->part_expr->null_value) { - uint32 ret_part_id= 0; - if (!left_endpoint && include_endpoint) - ret_part_id= 1; - DBUG_RETURN(ret_part_id); + /* + Special handling for MONOTONIC functions that can return NULL for + values that are comparable. I.e. + '2000-00-00' can be compared to '2000-01-01' but TO_DAYS('2000-00-00') + returns NULL which cannot be compared used <, >, <=, >= etc. + + Otherwise, just return the first partition + (may be included if not left endpoint) + */ + enum_monotonicity_info monotonic; + monotonic= part_info->part_expr->get_monotonicity_info(); + if (monotonic != MONOTONIC_INCREASING_NOT_NULL && + monotonic != MONOTONIC_STRICT_INCREASING_NOT_NULL) + { + /* F(col) can not return NULL, return partition with lowest value */ + if (!left_endpoint && include_endpoint) + DBUG_RETURN(1); + DBUG_RETURN(0); + + } } + + if (unsigned_flag) part_func_value-= 0x8000000000000000ULL; if (left_endpoint && !include_endpoint) @@ -6698,6 +6732,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; @@ -6735,6 +6770,23 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, } else assert(0); + + 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 || + monotonic == MONOTONIC_STRICT_INCREASING_NOT_NULL) + { + /* col is NOT NULL, but F(col) can return NULL, add NULL partition */ + part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE; + } + } /* Find minimum: Do special handling if the interval has left bound in form @@ -6767,6 +6819,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 */ @@ -6851,6 +6911,7 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info, Field *field; uint total_parts; partition_iter_func get_next_func; + part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; if (is_subpart) { field= part_info->subpart_field_array[0]; @@ -6961,7 +7022,13 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter) { if (part_iter->part_nums.cur >= part_iter->part_nums.end) { + if (part_iter->ret_null_part) + { + part_iter->ret_null_part= FALSE; + return 0; /* NULL always in first range partition */ + } part_iter->part_nums.cur= part_iter->part_nums.start; + part_iter->ret_null_part= part_iter->ret_null_part_orig; return NOT_A_PARTITION_ID; } else @@ -6989,7 +7056,7 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter) uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter) { - if (part_iter->part_nums.cur == part_iter->part_nums.end) + if (part_iter->part_nums.cur >= part_iter->part_nums.end) { if (part_iter->ret_null_part) { |