diff options
Diffstat (limited to 'sql/sql_partition.cc')
-rw-r--r-- | sql/sql_partition.cc | 82 |
1 files changed, 76 insertions, 6 deletions
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 236df78d455..f7453e76d21 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) @@ -6077,6 +6111,9 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, lpt->pack_frm_len= 0; thd->work_part_info= part_info; + /* Never update timestamp columns when alter */ + table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; + if (fast_alter_partition & HA_PARTITION_ONE_PHASE) { /* @@ -6693,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; @@ -6730,6 +6768,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 @@ -6762,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 */ @@ -6846,6 +6909,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]; @@ -6956,7 +7020,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 @@ -6984,7 +7054,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) { |