Commit dfb37cb3 authored by sergefp@mysql.com's avatar sergefp@mysql.com

Merge spetrunia@bk-internal.mysql.com:/home/bk/mysql-5.1-new

into mysql.com:/home/psergey/mysql-5.1-bug18025-r2
parents da810728 b05f270c
...@@ -546,6 +546,10 @@ sub command_line_setup () { ...@@ -546,6 +546,10 @@ sub command_line_setup () {
# 5.1 test run, even if different MTR_BUILD_THREAD is used. This means # 5.1 test run, even if different MTR_BUILD_THREAD is used. This means
# all port numbers might not be used in this version of the script. # all port numbers might not be used in this version of the script.
# #
# Also note the limiteation of ports we are allowed to hand out. This
# differs between operating systems and configuration, see
# http://www.ncftp.com/ncftpd/doc/misc/ephemeral_ports.html
# But a fairly safe range seems to be 5001 - 32767
if ( $ENV{'MTR_BUILD_THREAD'} ) if ( $ENV{'MTR_BUILD_THREAD'} )
{ {
# Up to two masters, up to three slaves # Up to two masters, up to three slaves
...@@ -558,6 +562,13 @@ sub command_line_setup () { ...@@ -558,6 +562,13 @@ sub command_line_setup () {
$im_mysqld2_port= $opt_master_myport + 9; $im_mysqld2_port= $opt_master_myport + 9;
} }
if ( $opt_master_myport < 5001 or $opt_master_myport + 10 >= 32767 )
{
mtr_error("MTR_BUILD_THREAD number results in a port",
"outside 5001 - 32767",
"($opt_master_myport - $opt_master_myport + 10)");
}
# Read the command line # Read the command line
# Note: Keep list, and the order, in sync with usage at end of this file # Note: Keep list, and the order, in sync with usage at end of this file
......
...@@ -344,6 +344,9 @@ SELECT f1 AS double_val, CAST(f1 AS SIGNED INT) AS cast_val FROM t1; ...@@ -344,6 +344,9 @@ SELECT f1 AS double_val, CAST(f1 AS SIGNED INT) AS cast_val FROM t1;
double_val cast_val double_val cast_val
-1e+30 -9223372036854775808 -1e+30 -9223372036854775808
1e+30 9223372036854775807 1e+30 9223372036854775807
Warnings:
Warning 1292 Truncated incorrect INTEGER value: '-1e+30'
Warning 1292 Truncated incorrect INTEGER value: '1e+30'
DROP TABLE t1; DROP TABLE t1;
select cast('1.2' as decimal(3,2)); select cast('1.2' as decimal(3,2));
cast('1.2' as decimal(3,2)) cast('1.2' as decimal(3,2))
......
...@@ -642,7 +642,7 @@ drop table t1; ...@@ -642,7 +642,7 @@ drop table t1;
create table t1 (a int) engine=innodb partition by hash(a) ; create table t1 (a int) engine=innodb partition by hash(a) ;
show table status like 't1'; show table status like 't1';
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 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 PARTITION 10 Compact 2 8192 16384 0 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL t1 InnoDB 10 Compact 2 8192 16384 0 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL partitioned
drop table t1; drop table t1;
create table t2 (s1 int not null auto_increment, primary key (s1)) partition by list (s1) (partition p1 values in (1),partition p2 values in (2),partition p3 values in (3),partition p4 values in (4)); create table t2 (s1 int not null auto_increment, primary key (s1)) partition by list (s1) (partition p1 values in (1),partition p2 values in (2),partition p3 values in (3),partition p4 values in (4));
insert into t2 values (null),(null),(null); insert into t2 values (null),(null),(null);
...@@ -819,4 +819,14 @@ explain partitions select * from t1 where a is null or a < 0 or a > 1; ...@@ -819,4 +819,14 @@ explain partitions select * from t1 where a is null or a < 0 or a > 1;
id select_type table partitions type possible_keys key key_len ref rows Extra id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 pn,p2 ALL NULL NULL NULL NULL 2 Using where 1 SIMPLE t1 pn,p2 ALL NULL NULL NULL NULL 2 Using where
drop table t1; drop table t1;
CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, name VARCHAR(20))
ENGINE=MyISAM DEFAULT CHARSET=latin1
PARTITION BY RANGE(id)
(PARTITION p0 VALUES LESS THAN (10) ENGINE = MyISAM,
PARTITION p1 VALUES LESS THAN (20) ENGINE = MyISAM,
PARTITION p2 VALUES LESS THAN (30) ENGINE = MyISAM);
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;
End of 5.1 tests End of 5.1 tests
...@@ -924,4 +924,17 @@ select * from t1 where a is null or a < 0 or a > 1; ...@@ -924,4 +924,17 @@ select * from t1 where a is null or a < 0 or a > 1;
explain partitions select * from t1 where a is null or a < 0 or a > 1; explain partitions select * from t1 where a is null or a < 0 or a > 1;
drop table t1; drop table t1;
#
#Bug# 17631 SHOW TABLE STATUS reports wrong engine
#
CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, name VARCHAR(20))
ENGINE=MyISAM DEFAULT CHARSET=latin1
PARTITION BY RANGE(id)
(PARTITION p0 VALUES LESS THAN (10) ENGINE = MyISAM,
PARTITION p1 VALUES LESS THAN (20) ENGINE = MyISAM,
PARTITION p2 VALUES LESS THAN (30) ENGINE = MyISAM);
--replace_column 6 0 7 0 8 0 9 0 12 NULL 13 NULL 14 NULL
SHOW TABLE STATUS;
DROP TABLE t1;
--echo End of 5.1 tests --echo End of 5.1 tests
...@@ -4237,6 +4237,7 @@ double Field_double::val_real(void) ...@@ -4237,6 +4237,7 @@ double Field_double::val_real(void)
longlong Field_double::val_int(void) longlong Field_double::val_int(void)
{ {
double j; double j;
longlong res;
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first) if (table->s->db_low_byte_first)
{ {
...@@ -4247,10 +4248,28 @@ longlong Field_double::val_int(void) ...@@ -4247,10 +4248,28 @@ longlong Field_double::val_int(void)
doubleget(j,ptr); doubleget(j,ptr);
/* Check whether we fit into longlong range */ /* Check whether we fit into longlong range */
if (j <= (double) LONGLONG_MIN) if (j <= (double) LONGLONG_MIN)
return (longlong) LONGLONG_MIN; {
res= (longlong) LONGLONG_MIN;
goto warn;
}
if (j >= (double) (ulonglong) LONGLONG_MAX) if (j >= (double) (ulonglong) LONGLONG_MAX)
return (longlong) LONGLONG_MAX; {
res= (longlong) LONGLONG_MAX;
goto warn;
}
return (longlong) rint(j); return (longlong) rint(j);
warn:
{
char buf[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
String tmp(buf, sizeof(buf), &my_charset_latin1), *str;
str= val_str(&tmp, 0);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE), "INTEGER",
str->c_ptr());
}
return res;
} }
......
...@@ -258,6 +258,13 @@ void ha_partition::init_handler_variables() ...@@ -258,6 +258,13 @@ void ha_partition::init_handler_variables()
} }
const char *ha_partition::table_type() const
{
// we can do this since we only support a single engine type
return m_file[0]->table_type();
}
/* /*
Destructor method Destructor method
......
...@@ -524,8 +524,7 @@ public: ...@@ -524,8 +524,7 @@ public:
virtual const char *index_type(uint inx); virtual const char *index_type(uint inx);
/* The name of the table type that will be used for display purposes */ /* The name of the table type that will be used for display purposes */
virtual const char *table_type() const virtual const char *table_type() const;
{ return "PARTITION"; }
/* The name of the row type used for the underlying tables. */ /* The name of the row type used for the underlying tables. */
virtual enum row_type get_row_type() const; virtual enum row_type get_row_type() const;
......
...@@ -124,7 +124,6 @@ char *partition_info::create_default_partition_names(uint part_no, uint no_parts ...@@ -124,7 +124,6 @@ char *partition_info::create_default_partition_names(uint part_no, uint no_parts
SYNOPSIS SYNOPSIS
set_up_default_partitions() set_up_default_partitions()
part_info The reference to all partition information
file A reference to a handler of the table file A reference to a handler of the table
max_rows Maximum number of rows stored in the table max_rows Maximum number of rows stored in the table
start_no Starting partition number start_no Starting partition number
...@@ -201,7 +200,6 @@ end: ...@@ -201,7 +200,6 @@ end:
SYNOPSIS SYNOPSIS
set_up_default_subpartitions() set_up_default_subpartitions()
part_info The reference to all partition information
file A reference to a handler of the table file A reference to a handler of the table
max_rows Maximum number of rows stored in the table max_rows Maximum number of rows stored in the table
...@@ -271,7 +269,6 @@ end: ...@@ -271,7 +269,6 @@ end:
SYNOPSIS SYNOPSIS
set_up_defaults_for_partitioning() set_up_defaults_for_partitioning()
part_info The reference to all partition information
file A reference to a handler of the table file A reference to a handler of the table
max_rows Maximum number of rows stored in the table max_rows Maximum number of rows stored in the table
start_no Starting partition number start_no Starting partition number
...@@ -388,4 +385,362 @@ char *partition_info::has_unique_names() ...@@ -388,4 +385,362 @@ char *partition_info::has_unique_names()
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
} }
/*
Check that all partitions use the same storage engine.
This is currently a limitation in this version.
SYNOPSIS
check_engine_mix()
engine_array An array of engine identifiers
no_parts Total number of partitions
RETURN VALUE
TRUE Error, mixed engines
FALSE Ok, no mixed engines
DESCRIPTION
Current check verifies only that all handlers are the same.
Later this check will be more sophisticated.
*/
bool partition_info::check_engine_mix(handlerton **engine_array, uint no_parts)
{
uint i= 0;
bool result= FALSE;
DBUG_ENTER("partition_info::check_engine_mix");
do
{
if (engine_array[i] != engine_array[0])
{
result= TRUE;
break;
}
} while (++i < no_parts);
DBUG_RETURN(result);
}
/*
This routine allocates an array for all range constants to achieve a fast
check what partition a certain value belongs to. At the same time it does
also check that the range constants are defined in increasing order and
that the expressions are constant integer expressions.
SYNOPSIS
check_range_constants()
RETURN VALUE
TRUE An error occurred during creation of range constants
FALSE Successful creation of range constant mapping
DESCRIPTION
This routine is called from check_partition_info to get a quick error
before we came too far into the CREATE TABLE process. It is also called
from fix_partition_func every time we open the .frm file. It is only
called for RANGE PARTITIONed tables.
*/
bool partition_info::check_range_constants()
{
partition_element* part_def;
longlong current_largest_int= LONGLONG_MIN;
longlong part_range_value_int;
uint i;
List_iterator<partition_element> it(partitions);
bool result= TRUE;
DBUG_ENTER("partition_info::check_range_constants");
DBUG_PRINT("enter", ("INT_RESULT with %d parts", no_parts));
part_result_type= INT_RESULT;
range_int_array= (longlong*)sql_alloc(no_parts * sizeof(longlong));
if (unlikely(range_int_array == NULL))
{
mem_alloc_error(no_parts * sizeof(longlong));
goto end;
}
i= 0;
do
{
part_def= it++;
if ((i != (no_parts - 1)) || !defined_max_value)
part_range_value_int= part_def->range_value;
else
part_range_value_int= LONGLONG_MAX;
if (likely(current_largest_int < part_range_value_int))
{
current_largest_int= part_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:
DBUG_RETURN(result);
}
/*
A support routine for check_list_constants used by qsort to sort the
constant list expressions.
SYNOPSIS
list_part_cmp()
a First list constant to compare with
b Second list constant to compare with
RETURN VALUE
+1 a > b
0 a == b
-1 a < b
*/
int partition_info::list_part_cmp(const void* a, const void* b)
{
longlong a1= ((LIST_PART_ENTRY*)a)->list_value;
longlong 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
check what partition a certain value belongs to. At the same time it does
also check that there are no duplicates among the list constants and that
that the list expressions are constant integer expressions.
SYNOPSIS
check_list_constants()
RETURN VALUE
TRUE An error occurred during creation of list constants
FALSE Successful creation of list constant mapping
DESCRIPTION
This routine is called from check_partition_info to get a quick error
before we came too far into the CREATE TABLE process. It is also called
from fix_partition_func every time we open the .frm file. It is only
called for LIST PARTITIONed tables.
*/
bool partition_info::check_list_constants()
{
uint i;
uint list_index= 0;
longlong *list_value;
bool not_first;
bool result= TRUE;
longlong curr_value, prev_value;
partition_element* part_def;
bool found_null= FALSE;
List_iterator<partition_element> list_func_it(partitions);
DBUG_ENTER("partition_info::check_list_constants");
part_result_type= INT_RESULT;
no_list_values= 0;
/*
We begin by calculating the number of list values that have been
defined in the first step.
We use this number to allocate a properly sized array of structs
to keep the partition id and the value to use in that partition.
In the second traversal we assign them values in the struct array.
Finally we sort the array of structs in order of values to enable
a quick binary search for the proper value to discover the
partition id.
After sorting the array we check that there are no duplicates in the
list.
*/
i= 0;
do
{
part_def= list_func_it++;
if (part_def->has_null_value)
{
if (found_null)
{
my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
goto end;
}
has_null_value= TRUE;
has_null_part_id= i;
found_null= TRUE;
}
List_iterator<longlong> list_val_it1(part_def->list_val_list);
while (list_val_it1++)
no_list_values++;
} while (++i < no_parts);
list_func_it.rewind();
list_array= (LIST_PART_ENTRY*)sql_alloc(no_list_values*sizeof(LIST_PART_ENTRY));
if (unlikely(list_array == NULL))
{
mem_alloc_error(no_list_values * sizeof(LIST_PART_ENTRY));
goto end;
}
i= 0;
do
{
part_def= list_func_it++;
List_iterator<longlong> 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++].partition_id= i;
}
} while (++i < no_parts);
qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY),
&list_part_cmp);
not_first= FALSE;
i= prev_value= 0; //prev_value initialised to quiet compiler
do
{
curr_value= list_array[i].list_value;
if (likely(!not_first || prev_value != curr_value))
{
prev_value= curr_value;
not_first= TRUE;
}
else
{
my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
goto end;
}
} while (++i < no_list_values);
result= FALSE;
end:
DBUG_RETURN(result);
}
/*
This code is used early in the CREATE TABLE and ALTER TABLE process.
SYNOPSIS
check_partition_info()
file A reference to a handler of the table
max_rows Maximum number of rows stored in the table
engine_type Return value for used engine in partitions
RETURN VALUE
TRUE Error, something went wrong
FALSE Ok, full partition data structures are now generated
DESCRIPTION
We will check that the partition info requested is possible to set-up in
this version. This routine is an extension of the parser one could say.
If defaults were used we will generate default data structures for all
partitions.
*/
bool partition_info::check_partition_info(handlerton **eng_type,
handler *file, ulonglong max_rows)
{
handlerton **engine_array= NULL;
uint part_count= 0;
uint i, tot_partitions;
bool result= TRUE;
char *same_name;
DBUG_ENTER("partition_info::check_partition_info");
if (unlikely(!is_sub_partitioned() &&
!(use_default_subpartitions && use_default_no_subpartitions)))
{
my_error(ER_SUBPARTITION_ERROR, MYF(0));
goto end;
}
if (unlikely(is_sub_partitioned() &&
(!(part_type == RANGE_PARTITION ||
part_type == LIST_PARTITION))))
{
/* Only RANGE and LIST partitioning can be subpartitioned */
my_error(ER_SUBPARTITION_ERROR, MYF(0));
goto end;
}
if (unlikely(set_up_defaults_for_partitioning(file, max_rows, (uint)0)))
goto end;
tot_partitions= get_tot_partitions();
if (unlikely(tot_partitions > MAX_PARTITIONS))
{
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
goto end;
}
if ((same_name= has_unique_names()))
{
my_error(ER_SAME_NAME_PARTITION, MYF(0), same_name);
goto end;
}
engine_array= (handlerton**)my_malloc(tot_partitions * sizeof(handlerton *),
MYF(MY_WME));
if (unlikely(!engine_array))
goto end;
i= 0;
{
List_iterator<partition_element> part_it(partitions);
do
{
partition_element *part_elem= part_it++;
if (!is_sub_partitioned())
{
if (part_elem->engine_type == NULL)
part_elem->engine_type= default_engine_type;
DBUG_PRINT("info", ("engine = %d",
ha_legacy_type(part_elem->engine_type)));
engine_array[part_count++]= part_elem->engine_type;
}
else
{
uint j= 0;
List_iterator<partition_element> sub_it(part_elem->subpartitions);
do
{
part_elem= sub_it++;
if (part_elem->engine_type == NULL)
part_elem->engine_type= default_engine_type;
DBUG_PRINT("info", ("engine = %u",
ha_legacy_type(part_elem->engine_type)));
engine_array[part_count++]= part_elem->engine_type;
} while (++j < no_subparts);
}
} while (++i < no_parts);
}
if (unlikely(partition_info::check_engine_mix(engine_array, part_count)))
{
my_error(ER_MIX_HANDLER_ERROR, MYF(0));
goto end;
}
if (eng_type)
*eng_type= (handlerton*)engine_array[0];
/*
We need to check all constant expressions that they are of the correct
type and that they are increasing for ranges and not overlapping for
list constants.
*/
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));
DBUG_RETURN(result);
}
#endif /* WITH_PARTITION_STORAGE_ENGINE */ #endif /* WITH_PARTITION_STORAGE_ENGINE */
...@@ -245,7 +245,13 @@ public: ...@@ -245,7 +245,13 @@ public:
bool set_up_defaults_for_partitioning(handler *file, ulonglong max_rows, bool set_up_defaults_for_partitioning(handler *file, ulonglong max_rows,
uint start_no); uint start_no);
char *has_unique_names(); char *has_unique_names();
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,
handler *file, ulonglong max_rows);
private: private:
static int list_part_cmp(const void* a, const void* b);
bool set_up_default_partitions(handler *file, ulonglong max_rows, bool set_up_default_partitions(handler *file, ulonglong max_rows,
uint start_no); uint start_no);
bool set_up_default_subpartitions(handler *file, ulonglong max_rows); bool set_up_default_subpartitions(handler *file, ulonglong max_rows);
......
...@@ -410,383 +410,6 @@ int get_part_for_delete(const byte *buf, const byte *rec0, ...@@ -410,383 +410,6 @@ int get_part_for_delete(const byte *buf, const byte *rec0,
} }
/*
This routine allocates an array for all range constants to achieve a fast
check what partition a certain value belongs to. At the same time it does
also check that the range constants are defined in increasing order and
that the expressions are constant integer expressions.
SYNOPSIS
check_range_constants()
part_info Partition info
RETURN VALUE
TRUE An error occurred during creation of range constants
FALSE Successful creation of range constant mapping
DESCRIPTION
This routine is called from check_partition_info to get a quick error
before we came too far into the CREATE TABLE process. It is also called
from fix_partition_func every time we open the .frm file. It is only
called for RANGE PARTITIONed tables.
*/
static bool check_range_constants(partition_info *part_info)
{
partition_element* part_def;
longlong current_largest_int= LONGLONG_MIN;
longlong part_range_value_int;
uint no_parts= part_info->no_parts;
uint i;
List_iterator<partition_element> it(part_info->partitions);
bool result= TRUE;
DBUG_ENTER("check_range_constants");
DBUG_PRINT("enter", ("INT_RESULT with %d parts", no_parts));
part_info->part_result_type= INT_RESULT;
part_info->range_int_array=
(longlong*)sql_alloc(no_parts * sizeof(longlong));
if (unlikely(part_info->range_int_array == NULL))
{
mem_alloc_error(no_parts * sizeof(longlong));
goto end;
}
i= 0;
do
{
part_def= it++;
if ((i != (no_parts - 1)) || !part_info->defined_max_value)
part_range_value_int= part_def->range_value;
else
part_range_value_int= LONGLONG_MAX;
if (likely(current_largest_int < part_range_value_int))
{
current_largest_int= part_range_value_int;
part_info->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:
DBUG_RETURN(result);
}
/*
A support routine for check_list_constants used by qsort to sort the
constant list expressions.
SYNOPSIS
list_part_cmp()
a First list constant to compare with
b Second list constant to compare with
RETURN VALUE
+1 a > b
0 a == b
-1 a < b
*/
static int list_part_cmp(const void* a, const void* b)
{
longlong a1= ((LIST_PART_ENTRY*)a)->list_value;
longlong 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
check what partition a certain value belongs to. At the same time it does
also check that there are no duplicates among the list constants and that
that the list expressions are constant integer expressions.
SYNOPSIS
check_list_constants()
part_info Partition info
RETURN VALUE
TRUE An error occurred during creation of list constants
FALSE Successful creation of list constant mapping
DESCRIPTION
This routine is called from check_partition_info to get a quick error
before we came too far into the CREATE TABLE process. It is also called
from fix_partition_func every time we open the .frm file. It is only
called for LIST PARTITIONed tables.
*/
static bool check_list_constants(partition_info *part_info)
{
uint i, no_parts;
uint no_list_values= 0;
uint list_index= 0;
longlong *list_value;
bool not_first;
bool result= TRUE;
longlong curr_value, prev_value;
partition_element* part_def;
bool found_null= FALSE;
List_iterator<partition_element> list_func_it(part_info->partitions);
DBUG_ENTER("check_list_constants");
part_info->part_result_type= INT_RESULT;
/*
We begin by calculating the number of list values that have been
defined in the first step.
We use this number to allocate a properly sized array of structs
to keep the partition id and the value to use in that partition.
In the second traversal we assign them values in the struct array.
Finally we sort the array of structs in order of values to enable
a quick binary search for the proper value to discover the
partition id.
After sorting the array we check that there are no duplicates in the
list.
*/
no_parts= part_info->no_parts;
i= 0;
do
{
part_def= list_func_it++;
if (part_def->has_null_value)
{
if (found_null)
{
my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
goto end;
}
part_info->has_null_value= TRUE;
part_info->has_null_part_id= i;
found_null= TRUE;
}
List_iterator<longlong> list_val_it1(part_def->list_val_list);
while (list_val_it1++)
no_list_values++;
} while (++i < no_parts);
list_func_it.rewind();
part_info->no_list_values= no_list_values;
part_info->list_array=
(LIST_PART_ENTRY*)sql_alloc(no_list_values*sizeof(LIST_PART_ENTRY));
if (unlikely(part_info->list_array == NULL))
{
mem_alloc_error(no_list_values * sizeof(LIST_PART_ENTRY));
goto end;
}
i= 0;
do
{
part_def= list_func_it++;
List_iterator<longlong> list_val_it2(part_def->list_val_list);
while ((list_value= list_val_it2++))
{
part_info->list_array[list_index].list_value= *list_value;
part_info->list_array[list_index++].partition_id= i;
}
} while (++i < no_parts);
qsort((void*)part_info->list_array, no_list_values,
sizeof(LIST_PART_ENTRY), &list_part_cmp);
not_first= FALSE;
i= prev_value= 0; //prev_value initialised to quiet compiler
do
{
curr_value= part_info->list_array[i].list_value;
if (likely(!not_first || prev_value != curr_value))
{
prev_value= curr_value;
not_first= TRUE;
}
else
{
my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
goto end;
}
} while (++i < no_list_values);
result= FALSE;
end:
DBUG_RETURN(result);
}
/*
Check that all partitions use the same storage engine.
This is currently a limitation in this version.
SYNOPSIS
check_engine_mix()
engine_array An array of engine identifiers
no_parts Total number of partitions
RETURN VALUE
TRUE Error, mixed engines
FALSE Ok, no mixed engines
DESCRIPTION
Current check verifies only that all handlers are the same.
Later this check will be more sophisticated.
*/
static bool check_engine_mix(handlerton **engine_array, uint no_parts)
{
uint i= 0;
bool result= FALSE;
DBUG_ENTER("check_engine_mix");
do
{
if (engine_array[i] != engine_array[0])
{
result= TRUE;
break;
}
} while (++i < no_parts);
DBUG_RETURN(result);
}
/*
This code is used early in the CREATE TABLE and ALTER TABLE process.
SYNOPSIS
check_partition_info()
part_info The reference to all partition information
file A reference to a handler of the table
max_rows Maximum number of rows stored in the table
engine_type Return value for used engine in partitions
RETURN VALUE
TRUE Error, something went wrong
FALSE Ok, full partition data structures are now generated
DESCRIPTION
We will check that the partition info requested is possible to set-up in
this version. This routine is an extension of the parser one could say.
If defaults were used we will generate default data structures for all
partitions.
*/
bool check_partition_info(partition_info *part_info,handlerton **eng_type,
handler *file, ulonglong max_rows)
{
handlerton **engine_array= NULL;
uint part_count= 0;
uint i, no_parts, tot_partitions;
bool result= TRUE;
char *same_name;
DBUG_ENTER("check_partition_info");
if (unlikely(!part_info->is_sub_partitioned() &&
!(part_info->use_default_subpartitions &&
part_info->use_default_no_subpartitions)))
{
my_error(ER_SUBPARTITION_ERROR, MYF(0));
goto end;
}
if (unlikely(part_info->is_sub_partitioned() &&
(!(part_info->part_type == RANGE_PARTITION ||
part_info->part_type == LIST_PARTITION))))
{
/* Only RANGE and LIST partitioning can be subpartitioned */
my_error(ER_SUBPARTITION_ERROR, MYF(0));
goto end;
}
if (unlikely(part_info->set_up_defaults_for_partitioning(file,
max_rows,
(uint)0)))
goto end;
tot_partitions= part_info->get_tot_partitions();
if (unlikely(tot_partitions > MAX_PARTITIONS))
{
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
goto end;
}
if ((same_name= part_info->has_unique_names()))
{
my_error(ER_SAME_NAME_PARTITION, MYF(0), same_name);
goto end;
}
engine_array= (handlerton**)my_malloc(tot_partitions * sizeof(handlerton *),
MYF(MY_WME));
if (unlikely(!engine_array))
goto end;
i= 0;
no_parts= part_info->no_parts;
{
List_iterator<partition_element> part_it(part_info->partitions);
do
{
partition_element *part_elem= part_it++;
if (!part_info->is_sub_partitioned())
{
if (part_elem->engine_type == NULL)
part_elem->engine_type= part_info->default_engine_type;
DBUG_PRINT("info", ("engine = %d",
ha_legacy_type(part_elem->engine_type)));
engine_array[part_count++]= part_elem->engine_type;
}
else
{
uint j= 0, no_subparts= part_info->no_subparts;;
List_iterator<partition_element> sub_it(part_elem->subpartitions);
do
{
part_elem= sub_it++;
if (part_elem->engine_type == NULL)
part_elem->engine_type= part_info->default_engine_type;
DBUG_PRINT("info", ("engine = %u",
ha_legacy_type(part_elem->engine_type)));
engine_array[part_count++]= part_elem->engine_type;
} while (++j < no_subparts);
}
} while (++i < part_info->no_parts);
}
if (unlikely(check_engine_mix(engine_array, part_count)))
{
my_error(ER_MIX_HANDLER_ERROR, MYF(0));
goto end;
}
if (eng_type)
*eng_type= (handlerton*)engine_array[0];
/*
We need to check all constant expressions that they are of the correct
type and that they are increasing for ranges and not overlapping for
list constants.
*/
if (unlikely((part_info->part_type == RANGE_PARTITION &&
check_range_constants(part_info)) ||
(part_info->part_type == LIST_PARTITION &&
check_list_constants(part_info))))
goto end;
result= FALSE;
end:
my_free((char*)engine_array,MYF(MY_ALLOW_ZERO_PTR));
DBUG_RETURN(result);
}
/* /*
This method is used to set-up both partition and subpartitioning This method is used to set-up both partition and subpartitioning
field array and used for all types of partitioning. field array and used for all types of partitioning.
...@@ -1814,13 +1437,13 @@ bool fix_partition_func(THD *thd, const char* name, TABLE *table, ...@@ -1814,13 +1437,13 @@ bool fix_partition_func(THD *thd, const char* name, TABLE *table,
if (part_info->part_type == RANGE_PARTITION) if (part_info->part_type == RANGE_PARTITION)
{ {
error_str= partition_keywords[PKW_RANGE].str; error_str= partition_keywords[PKW_RANGE].str;
if (unlikely(check_range_constants(part_info))) if (unlikely(part_info->check_range_constants()))
goto end; goto end;
} }
else if (part_info->part_type == LIST_PARTITION) else if (part_info->part_type == LIST_PARTITION)
{ {
error_str= partition_keywords[PKW_LIST].str; error_str= partition_keywords[PKW_LIST].str;
if (unlikely(check_list_constants(part_info))) if (unlikely(part_info->check_list_constants()))
goto end; goto end;
} }
else else
...@@ -3638,10 +3261,10 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index, ...@@ -3638,10 +3261,10 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index,
| Forminfo 288 bytes | | Forminfo 288 bytes |
------------------------------- -------------------------------
| Screen buffer, to make | | Screen buffer, to make |
| field names readable | |field names readable |
------------------------------- -------------------------------
| Packed field info | | Packed field info |
| 17 + 1 + strlen(field_name) | |17 + 1 + strlen(field_name) |
| + 1 end of file character | | + 1 end of file character |
------------------------------- -------------------------------
| Partition info | | Partition info |
...@@ -4862,7 +4485,7 @@ the generated partition syntax in a correct manner. ...@@ -4862,7 +4485,7 @@ the generated partition syntax in a correct manner.
tab_part_info->use_default_subpartitions= FALSE; tab_part_info->use_default_subpartitions= FALSE;
tab_part_info->use_default_no_subpartitions= FALSE; tab_part_info->use_default_no_subpartitions= FALSE;
} }
if (check_partition_info(tab_part_info, (handlerton**)NULL, if (tab_part_info->check_partition_info((handlerton**)NULL,
table->file, ULL(0))) table->file, ULL(0)))
{ {
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
......
...@@ -2721,6 +2721,12 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, ...@@ -2721,6 +2721,12 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables,
ptr=strxmov(ptr, " row_format=", ptr=strxmov(ptr, " row_format=",
ha_row_type[(uint) share->row_type], ha_row_type[(uint) share->row_type],
NullS); NullS);
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (share->db_type == &partition_hton &&
share->partition_info != NULL &&
((partition_info*)share->partition_info)->no_parts > 0)
ptr= strmov(ptr, " partitioned");
#endif
table->field[19]->store(option_buff+1, table->field[19]->store(option_buff+1,
(ptr == option_buff ? 0 : (ptr == option_buff ? 0 :
(uint) (ptr-option_buff)-1), cs); (uint) (ptr-option_buff)-1), cs);
......
...@@ -2141,7 +2141,7 @@ bool mysql_create_table_internal(THD *thd, ...@@ -2141,7 +2141,7 @@ bool mysql_create_table_internal(THD *thd,
} }
DBUG_PRINT("info", ("db_type = %d", DBUG_PRINT("info", ("db_type = %d",
ha_legacy_type(part_info->default_engine_type))); ha_legacy_type(part_info->default_engine_type)));
if (check_partition_info(part_info, &engine_type, file, if (part_info->check_partition_info( &engine_type, file,
create_info->max_rows)) create_info->max_rows))
goto err; goto err;
part_info->default_engine_type= engine_type; part_info->default_engine_type= engine_type;
......
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