From a9dab911a412f663a47530120046c4aca411445c Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 24 Feb 2006 10:10:41 -0600 Subject: [PATCH] BUG# 17430 Partitoins: crash on SELECT * FROM t1 WHERE f_int1 IS NULL BUG# 17432: Partitions: wrong result, SELECT ... WHERE is null mysql-test/r/partition.result: result block for tests mysql-test/t/partition.test: test cases for bug #17432 and 17430 sql/sql_partition.cc: improve null handling by returning LONGLONG_MIN for values that are NULL --- mysql-test/r/partition.result | 33 +++++++++++++++++++++++++++++ mysql-test/t/partition.test | 40 +++++++++++++++++++++++++++++++++++ sql/sql_partition.cc | 35 ++++++++++++++++++++++++------ 3 files changed, 102 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 6d28ecd8552..c6d341472b7 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -315,4 +315,37 @@ drop table t1; create table t1 (s1 int, unique (s1)) partition by list (s1) (partition x1 VALUES in (10), partition x2 values in (20)); alter table t1 add partition (partition x3 values in (30)); drop table t1; +CREATE TABLE t1 ( +f_int1 INTEGER, f_int2 INTEGER, +f_char1 CHAR(10), f_char2 CHAR(10), f_charbig VARCHAR(1000) +) +PARTITION BY RANGE(f_int1 DIV 2) +SUBPARTITION BY HASH(f_int1) +SUBPARTITIONS 2 +(PARTITION parta VALUES LESS THAN (0), +PARTITION partb VALUES LESS THAN (5), +PARTITION parte VALUES LESS THAN (10), +PARTITION partf VALUES LESS THAN (2147483647)); +INSERT INTO t1 SET f_int1 = NULL , f_int2 = -20, f_char1 = CAST(-20 AS CHAR), +f_char2 = CAST(-20 AS CHAR), f_charbig = '#NULL#'; +SELECT * FROM t1 WHERE f_int1 IS NULL; +f_int1 f_int2 f_char1 f_char2 f_charbig +NULL -20 -20 -20 #NULL# +SELECT * FROM t1; +f_int1 f_int2 f_char1 f_char2 f_charbig +NULL -20 -20 -20 #NULL# +drop table t1; +CREATE TABLE t1 ( +f_int1 INTEGER, f_int2 INTEGER, +f_char1 CHAR(10), f_char2 CHAR(10), f_charbig VARCHAR(1000) ) +PARTITION BY LIST(MOD(f_int1,2)) +SUBPARTITION BY KEY(f_int1) +(PARTITION part1 VALUES IN (-1) (SUBPARTITION sp1, SUBPARTITION sp2), +PARTITION part2 VALUES IN (0) (SUBPARTITION sp3, SUBPARTITION sp5), +PARTITION part3 VALUES IN (1) (SUBPARTITION sp4, SUBPARTITION sp6)); +INSERT INTO t1 SET f_int1 = 2, f_int2 = 2, f_char1 = '2', f_char2 = '2', f_charbig = '===2==='; +INSERT INTO t1 SET f_int1 = 2, f_int2 = 2, f_char1 = '2', f_char2 = '2', f_charbig = '===2==='; +SELECT * FROM t1 WHERE f_int1 IS NULL; +f_int1 f_int2 f_char1 f_char2 f_charbig +drop table t1; End of 5.1 tests diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index 4760219c911..92b0ec55953 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -408,4 +408,44 @@ create table t1 (s1 int, unique (s1)) partition by list (s1) (partition x1 VALUE alter table t1 add partition (partition x3 values in (30)); drop table t1; +# +# Bug #17432: Partition functions containing NULL values should return +# LONGLONG_MIN +# +CREATE TABLE t1 ( + f_int1 INTEGER, f_int2 INTEGER, + f_char1 CHAR(10), f_char2 CHAR(10), f_charbig VARCHAR(1000) + ) + PARTITION BY RANGE(f_int1 DIV 2) + SUBPARTITION BY HASH(f_int1) + SUBPARTITIONS 2 + (PARTITION parta VALUES LESS THAN (0), + PARTITION partb VALUES LESS THAN (5), + PARTITION parte VALUES LESS THAN (10), + PARTITION partf VALUES LESS THAN (2147483647)); +INSERT INTO t1 SET f_int1 = NULL , f_int2 = -20, f_char1 = CAST(-20 AS CHAR), + f_char2 = CAST(-20 AS CHAR), f_charbig = '#NULL#'; +SELECT * FROM t1 WHERE f_int1 IS NULL; +SELECT * FROM t1; +drop table t1; + +# +# Bug 17430: Crash when SELECT * from t1 where field IS NULL +# + +CREATE TABLE t1 ( + f_int1 INTEGER, f_int2 INTEGER, + f_char1 CHAR(10), f_char2 CHAR(10), f_charbig VARCHAR(1000) ) + PARTITION BY LIST(MOD(f_int1,2)) + SUBPARTITION BY KEY(f_int1) + (PARTITION part1 VALUES IN (-1) (SUBPARTITION sp1, SUBPARTITION sp2), + PARTITION part2 VALUES IN (0) (SUBPARTITION sp3, SUBPARTITION sp5), + PARTITION part3 VALUES IN (1) (SUBPARTITION sp4, SUBPARTITION sp6)); + +INSERT INTO t1 SET f_int1 = 2, f_int2 = 2, f_char1 = '2', f_char2 = '2', f_charbig = '===2==='; +INSERT INTO t1 SET f_int1 = 2, f_int2 = 2, f_char1 = '2', f_char2 = '2', f_charbig = '===2==='; + +SELECT * FROM t1 WHERE f_int1 IS NULL; +drop table t1; + --echo End of 5.1 tests diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 71fbbcd2426..c7f5cbb1907 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2629,6 +2629,29 @@ bool partition_key_modified(TABLE *table, List &fields) } +/* + A function to handle correct handling of NULL values in partition + functions. + SYNOPSIS + part_val_int() + item_expr The item expression to evaluate + RETURN VALUES + The value of the partition function, LONGLONG_MIN if any null value + in function +*/ + +static +inline +longlong +part_val_int(Item *item_expr) +{ + longlong value= item_expr->val_int(); + if (item_expr->null_value) + value= LONGLONG_MIN; + return value; +} + + /* The next set of functions are used to calculate the partition identity. A handler sets up a variable that corresponds to one of these functions @@ -2725,7 +2748,7 @@ static uint32 get_part_id_hash(uint no_parts, longlong *func_value) { DBUG_ENTER("get_part_id_hash"); - *func_value= part_expr->val_int(); + *func_value= part_val_int(part_expr); longlong int_hash_id= *func_value % no_parts; DBUG_RETURN(int_hash_id < 0 ? -int_hash_id : int_hash_id); } @@ -2754,7 +2777,7 @@ static uint32 get_part_id_linear_hash(partition_info *part_info, { DBUG_ENTER("get_part_id_linear_hash"); - *func_value= part_expr->val_int(); + *func_value= part_val_int(part_expr); DBUG_RETURN(get_part_id_from_linear_hash(*func_value, part_info->linear_hash_mask, no_parts)); @@ -2892,7 +2915,7 @@ int get_partition_id_list(partition_info *part_info, longlong list_value; int min_list_index= 0; int max_list_index= part_info->no_list_values - 1; - longlong part_func_value= part_info->part_expr->val_int(); + longlong part_func_value= part_val_int(part_info->part_expr); DBUG_ENTER("get_partition_id_list"); *func_value= part_func_value; @@ -2968,7 +2991,7 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info, longlong list_value; uint min_list_index= 0, max_list_index= part_info->no_list_values - 1; /* Get the partitioning function value for the endpoint */ - longlong part_func_value= part_info->part_expr->val_int(); + longlong part_func_value= part_val_int(part_info->part_expr); while (max_list_index >= min_list_index) { list_index= (max_list_index + min_list_index) >> 1; @@ -3002,7 +3025,7 @@ int get_partition_id_range(partition_info *part_info, uint min_part_id= 0; uint max_part_id= max_partition; uint loc_part_id; - longlong part_func_value= part_info->part_expr->val_int(); + longlong part_func_value= part_val_int(part_info->part_expr); DBUG_ENTER("get_partition_id_int_range"); while (max_part_id > min_part_id) @@ -3077,7 +3100,7 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info, uint max_partition= part_info->no_parts - 1; uint min_part_id= 0, max_part_id= max_partition, loc_part_id; /* Get the partitioning function value for the endpoint */ - longlong part_func_value= part_info->part_expr->val_int(); + longlong part_func_value= part_val_int(part_info->part_expr); while (max_part_id > min_part_id) { loc_part_id= (max_part_id + min_part_id + 1) >> 1;