Commit faa5f3e0 authored by unknown's avatar unknown

BUG#16002: Make partition functions that are unsigned work properly


mysql-test/r/partition.result:
  A number of new test cases for unsigned partition functions
mysql-test/r/partition_error.result:
  A number of new test cases for unsigned partition functions
mysql-test/r/partition_range.result:
  A number of new test cases for unsigned partition functions
mysql-test/t/partition.test:
  A number of new test cases for unsigned partition functions
mysql-test/t/partition_error.test:
  A number of new test cases for unsigned partition functions
mysql-test/t/partition_range.test:
  A number of new test cases for unsigned partition functions
sql/ha_partition.cc:
  Error message for no partition found needs to take signed/unsigned into account when printing erroneus value
sql/partition_element.h:
  Introduced signed_flag and max_value flag on partition elements
  Also list is now a list of a struct rather than simply longlong values
  Small rearranges of order
sql/partition_info.cc:
  Introduced signed_flag and max_value flag on partition elements
  Also list is now a list of a struct rather than simply longlong values
  Small rearranges of order
  Lots of new code to handle checks of proper definition of table when
  partition function is unsigned
sql/partition_info.h:
  Mostly rearrangement of code and some addition of a THD object in check_partition_info call
  plus a new method for comparing unsigned values
sql/share/errmsg.txt:
  Negative values not ok for unsigned partition functions
sql/sql_partition.cc:
  Fixed a multi-thread bug (when defining several partitioned tables in parallel)
  New code to generate partition syntax that takes into account sign of constants.
  Made function fix_fields_part_func more reusable.
  Fixed a number of get_partition_id functions for range and list and similar functions
  for partition pruning code.
  Unfortunately fairly much duplication of code with just small changes.
sql/sql_partition.h:
  New function headers
sql/sql_show.cc:
  Changed list of values for LIST partitioned tables
  Also fixed printing of unsigned values in INFORMATION SCHEMA for partitioned table
sql/sql_table.cc:
  Fixed for new interface
sql/sql_yacc.yy:
  Moved definition of struct to partition_element.h
  Added code to keep track of sign of constants in
  RANGE and LIST partitions
sql/table.cc:
  Fixed for new interface
parent a514095a
drop table if exists t1;
create table t1 (a bigint unsigned);
insert into t1 values (0xFFFFFFFFFFFFFFFD);
insert into t1 values (0xFFFFFFFFFFFFFFFE);
select * from t1 where (a + 1) < 10;
a
select * from t1 where (a + 1) > 10;
a
18446744073709551613
18446744073709551614
drop table t1;
CREATE TABLE t1 (
a int not null,
b int not null,
......@@ -839,4 +849,14 @@ SHOW TABLE STATUS;
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
t1 MyISAM 10 Dynamic 0 0 0 0 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL partitioned
DROP TABLE t1;
create table t1 (a bigint unsigned)
partition by list (a)
(partition p0 values in (0-1));
ERROR HY000: Partition function is unsigned, cannot have negative constants
create table t1 (a bigint unsigned)
partition by range (a)
(partition p0 values less than (10));
insert into t1 values (0xFFFFFFFFFFFFFFFF);
ERROR HY000: Table has no partition for value 18446744073709551615
drop table t1;
End of 5.1 tests
......@@ -554,3 +554,7 @@ PARTITION BY RANGE (a) (PARTITION p1 VALUES LESS THAN(5));
insert into t1 values (10);
ERROR HY000: Table has no partition for value 10
drop table t1;
create table t1 (a bigint unsigned)
partition by range (a)
(partition p0 values less than (-1));
ERROR HY000: Partition function is unsigned, cannot have negative constants
......@@ -363,3 +363,15 @@ SELECT COUNT(*) FROM t1 WHERE c3 < '2000-12-31';
COUNT(*)
10
DROP TABLE t1;
create table t1 (a bigint unsigned)
partition by range (a)
(partition p0 values less than (0),
partition p1 values less than (10));
ERROR HY000: VALUES LESS THAN value must be strictly increasing for each partition
create table t1 (a bigint unsigned)
partition by range (a)
(partition p0 values less than (2),
partition p1 values less than (10));
insert into t1 values (0xFFFFFFFFFFFFFFFF);
ERROR HY000: Table has no partition for value 18446744073709551615
drop table t1;
......@@ -9,6 +9,13 @@
drop table if exists t1;
--enable_warnings
create table t1 (a bigint unsigned);
insert into t1 values (0xFFFFFFFFFFFFFFFD);
insert into t1 values (0xFFFFFFFFFFFFFFFE);
select * from t1 where (a + 1) < 10;
select * from t1 where (a + 1) > 10;
drop table t1;
#
# Partition by key no partition defined => OK
#
......@@ -956,4 +963,20 @@ PARTITION p2 VALUES LESS THAN (30) ENGINE = MyISAM);
SHOW TABLE STATUS;
DROP TABLE t1;
#
#BUG 16002 Erroneus handling of unsigned partition functions
#
--error ER_SIGNED_PARTITION_CONSTANT_ERROR
create table t1 (a bigint unsigned)
partition by list (a)
(partition p0 values in (0-1));
create table t1 (a bigint unsigned)
partition by range (a)
(partition p0 values less than (10));
--error ER_NO_PARTITION_FOR_GIVEN_VALUE
insert into t1 values (0xFFFFFFFFFFFFFFFF);
drop table t1;
--echo End of 5.1 tests
......@@ -747,3 +747,8 @@ CREATE TABLE t1(a int)
--error ER_NO_PARTITION_FOR_GIVEN_VALUE
insert into t1 values (10);
drop table t1;
--error ER_SIGNED_PARTITION_CONSTANT_ERROR
create table t1 (a bigint unsigned)
partition by range (a)
(partition p0 values less than (-1));
......@@ -388,3 +388,20 @@ SELECT COUNT(*) FROM t1 WHERE c3 BETWEEN '1996-12-31' AND '2000-12-31';
SELECT COUNT(*) FROM t1 WHERE c3 < '2000-12-31';
DROP TABLE t1;
#
# BUG 16002: Unsigned partition functions not handled correctly
#
--error ER_RANGE_NOT_INCREASING_ERROR
create table t1 (a bigint unsigned)
partition by range (a)
(partition p0 values less than (0),
partition p1 values less than (10));
create table t1 (a bigint unsigned)
partition by range (a)
(partition p0 values less than (2),
partition p1 values less than (10));
--error ER_NO_PARTITION_FOR_GIVEN_VALUE
insert into t1 values (0xFFFFFFFFFFFFFFFF);
drop table t1;
......@@ -5165,10 +5165,21 @@ void ha_partition::print_error(int error, myf errflag)
if (error == HA_ERR_NO_PARTITION_FOUND)
{
char buf[100];
longlong value= m_part_info->part_expr->val_int();
if (!m_part_info->part_expr->unsigned_flag ||
m_part_info->part_expr->null_value)
{
my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0),
m_part_info->part_expr->null_value ? "NULL" :
llstr(m_part_info->part_expr->val_int(), buf));
}
else
{
ulonglong value= m_part_info->part_expr->val_int();
longlong2str(value, buf, 10);
my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0), buf);
}
}
else
m_file[0]->print_error(error, errflag);
DBUG_VOID_RETURN;
......
......@@ -36,15 +36,22 @@ enum partition_state {
PART_IS_ADDED= 8
};
typedef struct p_elem_val
{
longlong value;
bool null_value;
bool unsigned_flag;
} part_elem_value;
class partition_element :public Sql_alloc {
public:
List<partition_element> subpartitions;
List<longlong> list_val_list;
List<part_elem_value> list_val_list;
ulonglong part_max_rows;
ulonglong part_min_rows;
longlong range_value;
char *partition_name;
char *tablespace_name;
longlong range_value;
char* part_comment;
char* data_file_name;
char* index_file_name;
......@@ -52,13 +59,16 @@ public:
enum partition_state part_state;
uint16 nodegroup_id;
bool has_null_value;
bool signed_flag;
bool max_value;
partition_element()
: part_max_rows(0), part_min_rows(0), partition_name(NULL),
tablespace_name(NULL), range_value(0), part_comment(NULL),
: part_max_rows(0), part_min_rows(0), range_value(0),
partition_name(NULL), tablespace_name(NULL), part_comment(NULL),
data_file_name(NULL), index_file_name(NULL),
engine_type(NULL),part_state(PART_NORMAL),
nodegroup_id(UNDEF_NODEGROUP), has_null_value(FALSE)
engine_type(NULL), part_state(PART_NORMAL),
nodegroup_id(UNDEF_NODEGROUP), has_null_value(FALSE),
signed_flag(FALSE), max_value(FALSE)
{
subpartitions.empty();
list_val_list.empty();
......
......@@ -445,10 +445,12 @@ bool partition_info::check_range_constants()
{
partition_element* part_def;
longlong current_largest_int= LONGLONG_MIN;
ulonglong current_largest_uint= 0;
longlong part_range_value_int;
uint i;
List_iterator<partition_element> it(partitions);
bool result= TRUE;
bool signed_flag= !part_expr->unsigned_flag;
DBUG_ENTER("partition_info::check_range_constants");
DBUG_PRINT("enter", ("INT_RESULT with %d parts", no_parts));
......@@ -463,6 +465,8 @@ bool partition_info::check_range_constants()
do
{
part_def= it++;
if (signed_flag)
{
if ((i != (no_parts - 1)) || !defined_max_value)
part_range_value_int= part_def->range_value;
else
......@@ -477,6 +481,25 @@ bool partition_info::check_range_constants()
my_error(ER_RANGE_NOT_INCREASING_ERROR, MYF(0));
goto end;
}
}
else
{
ulonglong upart_range_value_int;
if ((i != (no_parts - 1)) || !defined_max_value)
upart_range_value_int= part_def->range_value;
else
upart_range_value_int= ULONGLONG_MAX;
if (likely(current_largest_uint < upart_range_value_int))
{
current_largest_uint= upart_range_value_int;
range_int_array[i]= part_range_value_int;
}
else
{
my_error(ER_RANGE_NOT_INCREASING_ERROR, MYF(0));
goto end;
}
}
} while (++i < no_parts);
result= FALSE;
end:
......@@ -485,8 +508,8 @@ end:
/*
A support routine for check_list_constants used by qsort to sort the
constant list expressions.
Support routines for check_list_constants used by qsort to sort the
constant list expressions. One routine for unsigned and one for signed.
SYNOPSIS
list_part_cmp()
......@@ -511,6 +534,18 @@ int partition_info::list_part_cmp(const void* a, const void* b)
return 0;
}
int partition_info::list_part_cmp_unsigned(const void* a, const void* b)
{
ulonglong a1= ((LIST_PART_ENTRY*)a)->list_value;
ulonglong b1= ((LIST_PART_ENTRY*)b)->list_value;
if (a1 < b1)
return -1;
else if (a1 > b1)
return +1;
else
return 0;
}
/*
This routine allocates an array for all list constants to achieve a fast
......@@ -536,7 +571,7 @@ bool partition_info::check_list_constants()
{
uint i;
uint list_index= 0;
longlong *list_value;
part_elem_value *list_value;
bool not_first;
bool result= TRUE;
longlong curr_value, prev_value;
......@@ -577,7 +612,7 @@ bool partition_info::check_list_constants()
has_null_part_id= i;
found_null= TRUE;
}
List_iterator<longlong> list_val_it1(part_def->list_val_list);
List_iterator<part_elem_value> list_val_it1(part_def->list_val_list);
while (list_val_it1++)
no_list_values++;
} while (++i < no_parts);
......@@ -593,16 +628,22 @@ bool partition_info::check_list_constants()
do
{
part_def= list_func_it++;
List_iterator<longlong> list_val_it2(part_def->list_val_list);
List_iterator<part_elem_value> list_val_it2(part_def->list_val_list);
while ((list_value= list_val_it2++))
{
list_array[list_index].list_value= *list_value;
list_array[list_index].list_value= list_value->value;
list_array[list_index++].partition_id= i;
}
} while (++i < no_parts);
if (fixed)
{
if (!part_expr->unsigned_flag)
qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY),
&list_part_cmp);
else
qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY),
&list_part_cmp_unsigned);
not_first= FALSE;
i= prev_value= 0; //prev_value initialised to quiet compiler
......@@ -620,6 +661,7 @@ bool partition_info::check_list_constants()
goto end;
}
} while (++i < no_list_values);
}
result= FALSE;
end:
DBUG_RETURN(result);
......@@ -647,7 +689,7 @@ end:
*/
bool partition_info::check_partition_info(handlerton **eng_type,
bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
handler *file, ulonglong max_rows)
{
handlerton **engine_array= NULL;
......@@ -733,9 +775,12 @@ bool partition_info::check_partition_info(handlerton **eng_type,
list constants.
*/
if (fixed)
{
if (unlikely((part_type == RANGE_PARTITION && check_range_constants()) ||
(part_type == LIST_PARTITION && check_list_constants())))
goto end;
}
result= FALSE;
end:
my_free((char*)engine_array,MYF(MY_ALLOW_ZERO_PTR));
......
......@@ -163,6 +163,7 @@ public:
uint no_subpart_fields;
uint no_full_part_fields;
uint has_null_part_id;
/*
This variable is used to calculate the partition id when using
LINEAR KEY/HASH. This functionality is kept in the MySQL Server
......@@ -182,7 +183,6 @@ public:
bool fixed;
bool from_openfrm;
bool has_null_value;
uint has_null_part_id;
partition_info()
......@@ -204,19 +204,13 @@ public:
no_parts(0), no_subparts(0),
count_curr_subparts(0), part_error_code(0),
no_list_values(0), no_part_fields(0), no_subpart_fields(0),
no_full_part_fields(0), linear_hash_mask(0),
use_default_partitions(TRUE),
use_default_no_partitions(TRUE),
use_default_subpartitions(TRUE),
use_default_no_subpartitions(TRUE),
default_partitions_setup(FALSE),
defined_max_value(FALSE),
no_full_part_fields(0), has_null_part_id(0), linear_hash_mask(0),
use_default_partitions(TRUE), use_default_no_partitions(TRUE),
use_default_subpartitions(TRUE), use_default_no_subpartitions(TRUE),
default_partitions_setup(FALSE), defined_max_value(FALSE),
list_of_part_fields(FALSE), list_of_subpart_fields(FALSE),
linear_hash_ind(FALSE),
fixed(FALSE),
from_openfrm(FALSE),
has_null_value(FALSE),
has_null_part_id(0)
linear_hash_ind(FALSE), fixed(FALSE), from_openfrm(FALSE),
has_null_value(FALSE)
{
all_fields_in_PF.clear_all();
all_fields_in_PPF.clear_all();
......@@ -248,10 +242,11 @@ public:
static bool check_engine_mix(handlerton **engine_array, uint no_parts);
bool check_range_constants();
bool check_list_constants();
bool check_partition_info(handlerton **eng_type,
bool check_partition_info(THD *thd, handlerton **eng_type,
handler *file, ulonglong max_rows);
private:
static int list_part_cmp(const void* a, const void* b);
static int list_part_cmp_unsigned(const void* a, const void* b);
bool set_up_default_partitions(handler *file, ulonglong max_rows,
uint start_no);
bool set_up_default_subpartitions(handler *file, ulonglong max_rows);
......
......@@ -5826,3 +5826,6 @@ ER_NDB_CANT_SWITCH_BINLOG_FORMAT
eng "The NDB cluster engine does not support changing the binlog format on the fly yet"
ER_PARTITION_NO_TEMPORARY
eng "Cannot create temporary table with partitions"
ER_SIGNED_PARTITION_CONSTANT_ERROR
eng "Partition function is unsigned, cannot have negative constants"
swe "Partitionsfunktionen r positiv, kan inte ha negativa konstanter"
This diff is collapsed.
......@@ -65,9 +65,8 @@ int get_part_for_delete(const byte *buf, const byte *rec0,
partition_info *part_info, uint32 *part_id);
void prune_partition_set(const TABLE *table, part_id_range *part_spec);
bool check_partition_info(partition_info *part_info,handlerton **eng_type,
handler *file, ulonglong max_rows);
bool fix_partition_func(THD *thd, const char *name, TABLE *table,
bool create_table_ind);
TABLE *table, handler *file, ulonglong max_rows);
bool fix_partition_func(THD *thd, TABLE *table, bool create_table_ind);
char *generate_partition_syntax(partition_info *part_info,
uint *buf_length, bool use_sql_alloc,
bool write_all);
......@@ -91,6 +90,8 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
bool left_endpoint,
bool include_endpoint);
bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
bool is_sub_part, bool is_field_to_be_setup);
/*
A "Get next" function for partition iterator.
......
......@@ -3851,8 +3851,8 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables,
}
else if (part_info->part_type == LIST_PARTITION)
{
List_iterator<longlong> list_val_it(part_elem->list_val_list);
longlong *list_value;
List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
part_elem_value *list_value;
uint no_items= part_elem->list_val_list.elements;
tmp_str.length(0);
tmp_res.length(0);
......@@ -3864,7 +3864,10 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables,
}
while ((list_value= list_val_it++))
{
tmp_res.set(*list_value, cs);
if (!list_value->unsigned_flag)
tmp_res.set(list_value->value, cs);
else
tmp_res.set((ulonglong)list_value->value, cs);
tmp_str.append(tmp_res);
if (--no_items != 0)
tmp_str.append(",");
......
......@@ -2141,7 +2141,7 @@ bool mysql_create_table_internal(THD *thd,
}
DBUG_PRINT("info", ("db_type = %d",
ha_legacy_type(part_info->default_engine_type)));
if (part_info->check_partition_info( &engine_type, file,
if (part_info->check_partition_info(thd, &engine_type, file,
create_info->max_rows))
goto err;
part_info->default_engine_type= engine_type;
......
......@@ -42,12 +42,6 @@
#include <myisam.h>
#include <myisammrg.h>
typedef struct p_elem_val
{
longlong value;
bool null_value;
} part_elem_value;
int yylex(void *yylval, void *yythd);
const LEX_STRING null_lex_str={0,0};
......@@ -3712,6 +3706,7 @@ part_func_max:
YYABORT;
}
lex->part_info->defined_max_value= TRUE;
lex->part_info->curr_part_elem->max_value= TRUE;
lex->part_info->curr_part_elem->range_value= LONGLONG_MAX;
}
| part_range_func
......@@ -3727,7 +3722,10 @@ part_func_max:
part_range_func:
'(' part_bit_expr ')'
{
Lex->part_info->curr_part_elem->range_value= $2->value;
partition_info *part_info= Lex->part_info;
if (!($2->unsigned_flag))
part_info->curr_part_elem->signed_flag= TRUE;
part_info->curr_part_elem->range_value= $2->value;
}
;
......@@ -3740,9 +3738,12 @@ part_list_item:
part_bit_expr
{
part_elem_value *value_ptr= $1;
partition_info *part_info= Lex->part_info;
if (!value_ptr->unsigned_flag)
part_info->curr_part_elem->signed_flag= TRUE;
if (!value_ptr->null_value &&
Lex->part_info->curr_part_elem->
list_val_list.push_back((longlong*) &value_ptr->value))
part_info->curr_part_elem->
list_val_list.push_back(value_ptr))
{
mem_alloc_error(sizeof(part_elem_value));
YYABORT;
......@@ -3783,6 +3784,10 @@ part_bit_expr:
}
thd->where= save_where;
value_ptr->value= part_expr->val_int();
value_ptr->unsigned_flag= TRUE;
if (!part_expr->unsigned_flag &&
value_ptr->value < 0)
value_ptr->unsigned_flag= FALSE;
if ((value_ptr->null_value= part_expr->null_value))
{
if (Lex->part_info->curr_part_elem->has_null_value)
......
......@@ -1488,8 +1488,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
Fix the partition functions and ensure they are not constant
functions
*/
if (fix_partition_func(thd, share->normalized_path.str, outparam,
is_create_table))
if (fix_partition_func(thd, outparam, is_create_table))
goto err;
}
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment