diff options
author | Mattias Jonsson <mattias.jonsson@sun.com> | 2009-08-26 12:59:49 +0200 |
---|---|---|
committer | Mattias Jonsson <mattias.jonsson@sun.com> | 2009-08-26 12:59:49 +0200 |
commit | 67214ef4334deccdd1f1d89c49c4edecd9075962 (patch) | |
tree | 6186de73376dc384682a6b1c1f575d8e214c8c02 /sql/sql_partition.cc | |
parent | 2dc7c5c8e758e492b8b56325a14b462e863723ac (diff) | |
download | mariadb-git-67214ef4334deccdd1f1d89c49c4edecd9075962.tar.gz |
Bug#20577: Partitions: use of to_days() function leads to selection failures
Problem was that the partition containing NULL values
was pruned away, since '2001-01-01' < '2001-02-00' but
TO_DAYS('2001-02-00') is NULL.
Added the NULL partition for RANGE/LIST partitioning on TO_DAYS()
function to be scanned too.
Also fixed a bug that added ALLOW_INVALID_DATES to sql_mode
(SELECT * FROM t WHERE date_col < '1999-99-99' on a RANGE/LIST
partitioned table would add it).
mysql-test/include/partition_date_range.inc:
Bug#20577: Partitions: use of to_days() function leads to selection failures
Added include file to decrease test code duplication
mysql-test/r/partition_pruning.result:
Bug#20577: Partitions: use of to_days() function leads to selection failures
Added test results
mysql-test/r/partition_range.result:
Bug#20577: Partitions: use of to_days() function leads to selection failures
Updated test result.
This fix adds the partition containing NULL values to
the list of partitions to be scanned.
mysql-test/t/partition_pruning.test:
Bug#20577: Partitions: use of to_days() function leads to selection failures
Added test case
sql/item.h:
Bug#20577: Partitions: use of to_days() function leads to selection failures
Added MONOTONIC_*INCREASE_NOT_NULL values to be used by TO_DAYS.
sql/item_timefunc.cc:
Bug#20577: Partitions: use of to_days() function leads to selection failures
Calculate the number of days as return value even for invalid dates.
This is so that pruning can be used even for invalid dates.
sql/opt_range.cc:
Bug#20577: Partitions: use of to_days() function leads to selection failures
Fixed a bug that added ALLOW_INVALID_DATES to sql_mode
(SELECT * FROM t WHERE date_col < '1999-99-99' on a RANGE/LIST
partitioned table would add it).
sql/partition_info.h:
Bug#20577: Partitions: use of to_days() function leads to selection failures
Resetting ret_null_part when a single partition is to be used, this
to avoid adding the NULL partition.
sql/sql_partition.cc:
Bug#20577: Partitions: use of to_days() function leads to selection failures
Always include the NULL partition if RANGE or LIST.
Use the returned value for the function for pruning, even if
it is marked as NULL, so that even '2000-00-00' can be
used for pruning, even if TO_DAYS('2000-00-00') is NULL.
Changed == to >= in get_next_partition_id_list to avoid
crash if part_iter->part_nums is not correctly setup.
Diffstat (limited to 'sql/sql_partition.cc')
-rw-r--r-- | sql/sql_partition.cc | 65 |
1 files changed, 59 insertions, 6 deletions
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 61766e5c509..ad24af12087 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) @@ -6733,6 +6767,19 @@ 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) + { + 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 @@ -6959,7 +7006,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 @@ -6987,7 +7040,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) { |