Merge rburnett@bk-internal.mysql.com:/home/bk/mysql-5.1-new
into linux.site:/home/reggie/work/mysql-5.1-bug17631 sql/ha_partition.cc: Auto merged sql/sql_partition.cc: Auto merged sql/sql_show.cc: Auto merged sql/sql_table.cc: Auto merged
This commit is contained in:
commit
c1a3261e60
@ -642,7 +642,7 @@ drop table t1;
|
||||
create table t1 (a int) engine=innodb partition by hash(a) ;
|
||||
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
|
||||
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;
|
||||
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);
|
||||
@ -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
|
||||
1 SIMPLE t1 pn,p2 ALL NULL NULL NULL NULL 2 Using where
|
||||
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
|
||||
|
@ -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;
|
||||
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
|
||||
|
@ -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
|
||||
|
||||
|
@ -524,8 +524,7 @@ public:
|
||||
virtual const char *index_type(uint inx);
|
||||
|
||||
/* The name of the table type that will be used for display purposes */
|
||||
virtual const char *table_type() const
|
||||
{ return "PARTITION"; }
|
||||
virtual const char *table_type() const;
|
||||
|
||||
/* The name of the row type used for the underlying tables. */
|
||||
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
|
||||
|
||||
SYNOPSIS
|
||||
set_up_default_partitions()
|
||||
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
|
||||
start_no Starting partition number
|
||||
@ -201,7 +200,6 @@ end:
|
||||
|
||||
SYNOPSIS
|
||||
set_up_default_subpartitions()
|
||||
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
|
||||
|
||||
@ -271,7 +269,6 @@ end:
|
||||
|
||||
SYNOPSIS
|
||||
set_up_defaults_for_partitioning()
|
||||
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
|
||||
start_no Starting partition number
|
||||
@ -388,4 +385,362 @@ char *partition_info::has_unique_names()
|
||||
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 */
|
||||
|
@ -245,7 +245,13 @@ public:
|
||||
bool set_up_defaults_for_partitioning(handler *file, ulonglong max_rows,
|
||||
uint start_no);
|
||||
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:
|
||||
static int list_part_cmp(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);
|
||||
|
@ -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
|
||||
field array and used for all types of partitioning.
|
||||
@ -1814,13 +1437,13 @@ bool fix_partition_func(THD *thd, const char* name, TABLE *table,
|
||||
if (part_info->part_type == RANGE_PARTITION)
|
||||
{
|
||||
error_str= partition_keywords[PKW_RANGE].str;
|
||||
if (unlikely(check_range_constants(part_info)))
|
||||
if (unlikely(part_info->check_range_constants()))
|
||||
goto end;
|
||||
}
|
||||
else if (part_info->part_type == LIST_PARTITION)
|
||||
{
|
||||
error_str= partition_keywords[PKW_LIST].str;
|
||||
if (unlikely(check_list_constants(part_info)))
|
||||
if (unlikely(part_info->check_list_constants()))
|
||||
goto end;
|
||||
}
|
||||
else
|
||||
@ -3638,10 +3261,10 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index,
|
||||
| Forminfo 288 bytes |
|
||||
-------------------------------
|
||||
| Screen buffer, to make |
|
||||
| field names readable |
|
||||
|field names readable |
|
||||
-------------------------------
|
||||
| Packed field info |
|
||||
| 17 + 1 + strlen(field_name) |
|
||||
|17 + 1 + strlen(field_name) |
|
||||
| + 1 end of file character |
|
||||
-------------------------------
|
||||
| Partition info |
|
||||
@ -4862,7 +4485,7 @@ the generated partition syntax in a correct manner.
|
||||
tab_part_info->use_default_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)))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
|
@ -2721,6 +2721,12 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables,
|
||||
ptr=strxmov(ptr, " row_format=",
|
||||
ha_row_type[(uint) share->row_type],
|
||||
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,
|
||||
(ptr == option_buff ? 0 :
|
||||
(uint) (ptr-option_buff)-1), cs);
|
||||
|
@ -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 (check_partition_info(part_info, &engine_type, file,
|
||||
if (part_info->check_partition_info( &engine_type, file,
|
||||
create_info->max_rows))
|
||||
goto err;
|
||||
part_info->default_engine_type= engine_type;
|
||||
|
Loading…
x
Reference in New Issue
Block a user