1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

cleanup: partition_info::check_constants

partition_info had a bunch of function pointers to avoid if()'s
when invoking part_type specific functionality (like get_part_id, etc).
But check_range_constants() and check_list_constants() were still
invoked conditionally, with if()'s.

Create partition_info::check_constants function pointer, get rid
of if()'s

Also remove alloc argument of check_range_constants(), added
in 26a3ff0a22. Broken system versioning will be fixed in
following commits.
This commit is contained in:
Sergei Golubchik
2018-02-18 12:24:51 +01:00
parent f38ef43013
commit c4c81a5b04
4 changed files with 403 additions and 439 deletions

View File

@ -8017,7 +8017,7 @@ int ha_partition::compare_number_of_records(ha_partition *me,
::info() is used to return information to the optimizer. ::info() is used to return information to the optimizer.
Currently this table handler doesn't implement most of the fields Currently this table handler doesn't implement most of the fields
really needed. SHOW also makes use of this data really needed. SHOW also makes use of this data
Another note, if your handler doesn't proved exact record count, Another note, if your handler doesn't provide exact record count,
you will probably want to have the following in your code: you will probably want to have the following in your code:
if (records < 2) if (records < 2)
records = 2; records = 2;

View File

@ -1514,400 +1514,6 @@ error:
} }
/*
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()
thd Thread object
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(THD *thd, bool alloc)
{
partition_element* part_def;
bool first= TRUE;
uint i;
List_iterator<partition_element> it(partitions);
int result= TRUE;
DBUG_ENTER("partition_info::check_range_constants");
DBUG_PRINT("enter", ("RANGE with %d parts, column_list = %u", num_parts,
column_list));
if (column_list)
{
part_column_list_val *loc_range_col_array;
part_column_list_val *UNINIT_VAR(current_largest_col_val);
uint num_column_values= part_field_list.elements;
uint size_entries= sizeof(part_column_list_val) * num_column_values;
if (alloc)
{
range_col_array= (part_column_list_val*) thd->calloc(num_parts *
size_entries);
if (unlikely(range_col_array == NULL))
{
mem_alloc_error(num_parts * size_entries);
goto end;
}
}
loc_range_col_array= range_col_array;
i= 0;
do
{
part_def= it++;
{
List_iterator<part_elem_value> list_val_it(part_def->list_val_list);
part_elem_value *range_val= list_val_it++;
part_column_list_val *col_val= range_val->col_val_array;
if (fix_column_value_functions(thd, range_val, i))
goto end;
memcpy(loc_range_col_array, (const void*)col_val, size_entries);
loc_range_col_array+= num_column_values;
if (!first)
{
if (compare_column_values((const void*)current_largest_col_val,
(const void*)col_val) >= 0)
goto range_not_increasing_error;
}
current_largest_col_val= col_val;
}
first= FALSE;
} while (++i < num_parts);
}
else
{
longlong UNINIT_VAR(current_largest);
longlong part_range_value;
bool signed_flag= !part_expr->unsigned_flag;
if (alloc)
{
range_int_array= (longlong*) thd->alloc(num_parts * sizeof(longlong));
if (unlikely(range_int_array == NULL))
{
mem_alloc_error(num_parts * sizeof(longlong));
goto end;
}
}
i= 0;
do
{
part_def= it++;
if ((i != (num_parts - 1)) || !defined_max_value)
{
part_range_value= part_def->range_value;
if (!signed_flag)
part_range_value-= 0x8000000000000000ULL;
}
else
part_range_value= LONGLONG_MAX;
if (!first)
{
if (unlikely(current_largest > part_range_value) ||
(unlikely(current_largest == part_range_value) &&
(part_range_value < LONGLONG_MAX ||
i != (num_parts - 1) ||
!defined_max_value)))
goto range_not_increasing_error;
}
range_int_array[i]= part_range_value;
current_largest= part_range_value;
first= FALSE;
} while (++i < num_parts);
}
result= FALSE;
end:
DBUG_RETURN(result);
range_not_increasing_error:
my_error(ER_RANGE_NOT_INCREASING_ERROR, MYF(0));
goto end;
}
/*
Support routines for check_list_constants used by qsort to sort the
constant list expressions. One routine for integers and one for
column lists.
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
*/
extern "C"
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;
}
int partition_info::list_part_cmp(const void* a, const void* b)
{
return partition_info_list_part_cmp(a, b);
}
/*
Compare two lists of column values in RANGE/LIST partitioning
SYNOPSIS
compare_column_values()
first First column list argument
second Second column list argument
RETURN VALUES
0 Equal
-1 First argument is smaller
+1 First argument is larger
*/
extern "C"
int partition_info_compare_column_values(const void *first_arg,
const void *second_arg)
{
const part_column_list_val *first= (part_column_list_val*)first_arg;
const part_column_list_val *second= (part_column_list_val*)second_arg;
partition_info *part_info= first->part_info;
Field **field;
for (field= part_info->part_field_array; *field;
field++, first++, second++)
{
if (first->max_value || second->max_value)
{
if (first->max_value && second->max_value)
return 0;
if (second->max_value)
return -1;
else
return +1;
}
if (first->null_value || second->null_value)
{
if (first->null_value && second->null_value)
continue;
if (second->null_value)
return +1;
else
return -1;
}
int res= (*field)->cmp((const uchar*)first->column_value,
(const uchar*)second->column_value);
if (res)
return res;
}
return 0;
}
int partition_info::compare_column_values(const void *first_arg,
const void *second_arg)
{
return partition_info_compare_column_values(first_arg, second_arg);
}
/*
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()
thd Thread object
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(THD *thd)
{
uint i, size_entries, num_column_values;
uint list_index= 0;
part_elem_value *list_value;
bool result= TRUE;
longlong type_add, calc_value;
void *curr_value;
void *UNINIT_VAR(prev_value);
partition_element* part_def;
bool found_null= FALSE;
qsort_cmp compare_func;
void *ptr;
List_iterator<partition_element> list_func_it(partitions);
DBUG_ENTER("partition_info::check_list_constants");
DBUG_ASSERT(part_type == LIST_PARTITION);
num_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;
}
num_list_values+= part_def->list_val_list.elements;
} while (++i < num_parts);
list_func_it.rewind();
num_column_values= part_field_list.elements;
size_entries= column_list ?
(num_column_values * sizeof(part_column_list_val)) :
sizeof(LIST_PART_ENTRY);
if (unlikely(!(ptr= thd->calloc((num_list_values+1) * size_entries))))
goto end;
if (column_list)
{
part_column_list_val *loc_list_col_array;
loc_list_col_array= (part_column_list_val*)ptr;
list_col_array= (part_column_list_val*)ptr;
compare_func= partition_info_compare_column_values;
i= 0;
do
{
part_def= list_func_it++;
if (part_def->max_value)
{
// DEFAULT is not a real value so let's exclude it from sorting.
DBUG_ASSERT(num_list_values);
num_list_values--;
continue;
}
List_iterator<part_elem_value> list_val_it2(part_def->list_val_list);
while ((list_value= list_val_it2++))
{
part_column_list_val *col_val= list_value->col_val_array;
if (unlikely(fix_column_value_functions(thd, list_value, i)))
{
DBUG_RETURN(TRUE);
}
memcpy(loc_list_col_array, (const void*)col_val, size_entries);
loc_list_col_array+= num_column_values;
}
} while (++i < num_parts);
}
else
{
compare_func= partition_info_list_part_cmp;
list_array= (LIST_PART_ENTRY*)ptr;
i= 0;
/*
Fix to be able to reuse signed sort functions also for unsigned
partition functions.
*/
type_add= (longlong)(part_expr->unsigned_flag ?
0x8000000000000000ULL :
0ULL);
do
{
part_def= list_func_it++;
if (part_def->max_value && part_type == LIST_PARTITION)
{
// DEFAULT is not a real value so let's exclude it from sorting.
DBUG_ASSERT(num_list_values);
num_list_values--;
continue;
}
List_iterator<part_elem_value> list_val_it2(part_def->list_val_list);
while ((list_value= list_val_it2++))
{
calc_value= list_value->value - type_add;
list_array[list_index].list_value= calc_value;
list_array[list_index++].partition_id= i;
}
} while (++i < num_parts);
}
DBUG_ASSERT(fixed);
if (num_list_values)
{
bool first= TRUE;
/*
list_array and list_col_array are unions, so this works for both
variants of LIST partitioning.
*/
my_qsort((void*)list_array, num_list_values, size_entries,
compare_func);
i= 0;
do
{
DBUG_ASSERT(i < num_list_values);
curr_value= column_list ? (void*)&list_col_array[num_column_values * i] :
(void*)&list_array[i];
if (likely(first || compare_func(curr_value, prev_value)))
{
prev_value= curr_value;
first= FALSE;
}
else
{
my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
goto end;
}
} while (++i < num_list_values);
}
result= FALSE;
end:
DBUG_RETURN(result);
}
/** /**
Check if we allow DATA/INDEX DIRECTORY, if not warn and set them to NULL. Check if we allow DATA/INDEX DIRECTORY, if not warn and set them to NULL.
@ -2227,10 +1833,7 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
if (unlikely(part_type == VERSIONING_PARTITION && if (unlikely(part_type == VERSIONING_PARTITION &&
vers_setup_expression(thd, add_or_reorg_part->partitions.elements))) vers_setup_expression(thd, add_or_reorg_part->partitions.elements)))
goto end; goto end;
if (unlikely(((part_type == RANGE_PARTITION || part_type == VERSIONING_PARTITION) && if (check_constants(thd, this))
check_range_constants(thd)) ||
(part_type == LIST_PARTITION &&
check_list_constants(thd))))
goto end; goto end;
} }
@ -2978,8 +2581,7 @@ bool partition_info::fix_column_value_functions(THD *thd,
sql_mode_t save_sql_mode; sql_mode_t save_sql_mode;
bool save_got_warning; bool save_got_warning;
if (!(column_item= get_column_item(column_item, if (!(column_item= get_column_item(column_item, field)))
field)))
{ {
result= TRUE; result= TRUE;
goto end; goto end;
@ -2992,6 +2594,7 @@ bool partition_info::fix_column_value_functions(THD *thd,
thd->got_warning) thd->got_warning)
{ {
my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0)); my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
thd->variables.sql_mode= save_sql_mode;
result= TRUE; result= TRUE;
goto end; goto end;
} }

View File

@ -27,11 +27,10 @@
class partition_info; class partition_info;
struct TABLE_LIST; struct TABLE_LIST;
/* Some function typedefs */ /* Some function typedefs */
typedef int (*get_part_id_func)(partition_info *part_info, typedef int (*get_part_id_func)(partition_info *part_info, uint32 *part_id,
uint32 *part_id,
longlong *func_value); longlong *func_value);
typedef int (*get_subpart_id_func)(partition_info *part_info, typedef int (*get_subpart_id_func)(partition_info *part_info, uint32 *part_id);
uint32 *part_id); typedef bool (*check_constants_func)(THD *thd, partition_info *part_info);
struct st_ddl_log_memory_entry; struct st_ddl_log_memory_entry;
@ -114,6 +113,8 @@ public:
get_part_id_func get_part_partition_id_charset; get_part_id_func get_part_partition_id_charset;
get_subpart_id_func get_subpartition_id_charset; get_subpart_id_func get_subpartition_id_charset;
check_constants_func check_constants;
/* NULL-terminated array of fields used in partitioned expression */ /* NULL-terminated array of fields used in partitioned expression */
Field **part_field_array; Field **part_field_array;
Field **subpart_field_array; Field **subpart_field_array;
@ -345,8 +346,6 @@ public:
const char *find_duplicate_field(); const char *find_duplicate_field();
char *find_duplicate_name(); char *find_duplicate_name();
bool check_engine_mix(handlerton *engine_type, bool default_engine); bool check_engine_mix(handlerton *engine_type, bool default_engine);
bool check_range_constants(THD *thd, bool alloc= true);
bool check_list_constants(THD *thd);
bool check_partition_info(THD *thd, handlerton **eng_type, bool check_partition_info(THD *thd, handlerton **eng_type,
handler *file, HA_CREATE_INFO *info, handler *file, HA_CREATE_INFO *info,
partition_info *add_or_reorg_part= NULL); partition_info *add_or_reorg_part= NULL);
@ -366,7 +365,6 @@ public:
part_column_list_val *add_column_value(THD *thd); part_column_list_val *add_column_value(THD *thd);
bool set_part_expr(THD *thd, char *start_token, Item *item_ptr, bool set_part_expr(THD *thd, char *start_token, Item *item_ptr,
char *end_token, bool is_subpart); char *end_token, bool is_subpart);
static int compare_column_values(const void *a, const void *b);
bool set_up_charset_field_preps(THD *thd); bool set_up_charset_field_preps(THD *thd);
bool check_partition_field_length(); bool check_partition_field_length();
bool init_column_part(THD *thd); bool init_column_part(THD *thd);
@ -377,7 +375,6 @@ public:
bool has_same_partitioning(partition_info *new_part_info); bool has_same_partitioning(partition_info *new_part_info);
bool error_if_requires_values() const; bool error_if_requires_values() const;
private: private:
static int list_part_cmp(const void* a, const void* b);
bool set_up_default_partitions(THD *thd, handler *file, HA_CREATE_INFO *info, bool set_up_default_partitions(THD *thd, handler *file, HA_CREATE_INFO *info,
uint start_no); uint start_no);
bool set_up_default_subpartitions(THD *thd, handler *file, bool set_up_default_subpartitions(THD *thd, handler *file,
@ -545,7 +542,7 @@ public:
} }
MEM_ROOT *old_root= thd->mem_root; MEM_ROOT *old_root= thd->mem_root;
thd->mem_root= &table->mem_root; thd->mem_root= &table->mem_root;
result= check_range_constants(thd, false); //result= check_range_constants(thd, false);
thd->mem_root= old_root; thd->mem_root= old_root;
vers_info->stat_serial= table->s->stat_serial; vers_info->stat_serial= table->s->stat_serial;
mysql_rwlock_unlock(&table->s->LOCK_stat_serial); mysql_rwlock_unlock(&table->s->LOCK_stat_serial);

View File

@ -1179,6 +1179,386 @@ static void set_up_partition_key_maps(TABLE *table,
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
static bool check_no_constants(THD *, partition_info*)
{
return FALSE;
}
/*
Support routines for check_list_constants used by qsort to sort the
constant list expressions. One routine for integers and one for
column lists.
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
*/
extern "C"
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;
}
/*
Compare two lists of column values in RANGE/LIST partitioning
SYNOPSIS
partition_info_compare_column_values()
first First column list argument
second Second column list argument
RETURN VALUES
0 Equal
-1 First argument is smaller
+1 First argument is larger
*/
extern "C"
int partition_info_compare_column_values(const void *first_arg,
const void *second_arg)
{
const part_column_list_val *first= (part_column_list_val*)first_arg;
const part_column_list_val *second= (part_column_list_val*)second_arg;
partition_info *part_info= first->part_info;
Field **field;
for (field= part_info->part_field_array; *field;
field++, first++, second++)
{
if (first->max_value || second->max_value)
{
if (first->max_value && second->max_value)
return 0;
if (second->max_value)
return -1;
else
return +1;
}
if (first->null_value || second->null_value)
{
if (first->null_value && second->null_value)
continue;
if (second->null_value)
return +1;
else
return -1;
}
int res= (*field)->cmp((const uchar*)first->column_value,
(const uchar*)second->column_value);
if (res)
return res;
}
return 0;
}
/*
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()
thd Thread object
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(THD *thd, partition_info *part_info)
{
partition_element* part_def;
bool first= TRUE;
uint i;
List_iterator<partition_element> it(part_info->partitions);
bool result= TRUE;
DBUG_ENTER("check_range_constants");
DBUG_PRINT("enter", ("RANGE with %d parts, column_list = %u",
part_info->num_parts, part_info->column_list));
if (part_info->column_list)
{
part_column_list_val *loc_range_col_array;
part_column_list_val *UNINIT_VAR(current_largest_col_val);
uint num_column_values= part_info->part_field_list.elements;
uint size_entries= sizeof(part_column_list_val) * num_column_values;
part_info->range_col_array= (part_column_list_val*)
thd->calloc(part_info->num_parts * size_entries);
if (part_info->range_col_array == NULL)
{
mem_alloc_error(part_info->num_parts * size_entries);
goto end;
}
loc_range_col_array= part_info->range_col_array;
i= 0;
do
{
part_def= it++;
{
List_iterator<part_elem_value> list_val_it(part_def->list_val_list);
part_elem_value *range_val= list_val_it++;
part_column_list_val *col_val= range_val->col_val_array;
if (part_info->fix_column_value_functions(thd, range_val, i))
goto end;
memcpy(loc_range_col_array, (const void*)col_val, size_entries);
loc_range_col_array+= num_column_values;
if (!first)
{
if (partition_info_compare_column_values(current_largest_col_val,
col_val) >= 0)
goto range_not_increasing_error;
}
current_largest_col_val= col_val;
}
first= FALSE;
} while (++i < part_info->num_parts);
}
else
{
longlong UNINIT_VAR(current_largest);
longlong part_range_value;
bool signed_flag= !part_info->part_expr->unsigned_flag;
part_info->range_int_array= (longlong*)
thd->alloc(part_info->num_parts * sizeof(longlong));
if (part_info->range_int_array == NULL)
{
mem_alloc_error(part_info->num_parts * sizeof(longlong));
goto end;
}
i= 0;
do
{
part_def= it++;
if ((i != part_info->num_parts - 1) || !part_info->defined_max_value)
{
part_range_value= part_def->range_value;
if (!signed_flag)
part_range_value-= 0x8000000000000000ULL;
}
else
part_range_value= LONGLONG_MAX;
if (!first)
{
if (current_largest > part_range_value ||
(current_largest == part_range_value &&
(part_range_value < LONGLONG_MAX ||
i != part_info->num_parts - 1 ||
!part_info->defined_max_value)))
goto range_not_increasing_error;
}
part_info->range_int_array[i]= part_range_value;
current_largest= part_range_value;
first= FALSE;
} while (++i < part_info->num_parts);
}
result= FALSE;
end:
DBUG_RETURN(result);
range_not_increasing_error:
my_error(ER_RANGE_NOT_INCREASING_ERROR, MYF(0));
goto end;
}
/*
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()
thd Thread object
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(THD *thd, partition_info *part_info)
{
uint i, size_entries, num_column_values;
uint list_index= 0;
part_elem_value *list_value;
bool result= TRUE;
longlong type_add, calc_value;
void *curr_value;
void *UNINIT_VAR(prev_value);
partition_element* part_def;
bool found_null= FALSE;
qsort_cmp compare_func;
void *ptr;
List_iterator<partition_element> list_func_it(part_info->partitions);
DBUG_ENTER("check_list_constants");
DBUG_ASSERT(part_info->part_type == LIST_PARTITION);
part_info->num_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;
}
part_info->has_null_value= TRUE;
part_info->has_null_part_id= i;
found_null= TRUE;
}
part_info->num_list_values+= part_def->list_val_list.elements;
} while (++i < part_info->num_parts);
list_func_it.rewind();
num_column_values= part_info->part_field_list.elements;
size_entries= part_info->column_list ?
(num_column_values * sizeof(part_column_list_val)) :
sizeof(LIST_PART_ENTRY);
if (!(ptr= thd->calloc((part_info->num_list_values+1) * size_entries)))
goto end;
if (part_info->column_list)
{
part_column_list_val *loc_list_col_array;
loc_list_col_array= (part_column_list_val*)ptr;
part_info->list_col_array= (part_column_list_val*)ptr;
compare_func= partition_info_compare_column_values;
i= 0;
do
{
part_def= list_func_it++;
if (part_def->max_value)
{
// DEFAULT is not a real value so let's exclude it from sorting.
DBUG_ASSERT(part_info->num_list_values);
part_info->num_list_values--;
continue;
}
List_iterator<part_elem_value> list_val_it2(part_def->list_val_list);
while ((list_value= list_val_it2++))
{
part_column_list_val *col_val= list_value->col_val_array;
if (part_info->fix_column_value_functions(thd, list_value, i))
DBUG_RETURN(result);
memcpy(loc_list_col_array, (const void*)col_val, size_entries);
loc_list_col_array+= num_column_values;
}
} while (++i < part_info->num_parts);
}
else
{
compare_func= partition_info_list_part_cmp;
part_info->list_array= (LIST_PART_ENTRY*)ptr;
i= 0;
/*
Fix to be able to reuse signed sort functions also for unsigned
partition functions.
*/
type_add= (longlong)(part_info->part_expr->unsigned_flag ?
0x8000000000000000ULL :
0ULL);
do
{
part_def= list_func_it++;
if (part_def->max_value)
{
// DEFAULT is not a real value so let's exclude it from sorting.
DBUG_ASSERT(part_info->num_list_values);
part_info->num_list_values--;
continue;
}
List_iterator<part_elem_value> list_val_it2(part_def->list_val_list);
while ((list_value= list_val_it2++))
{
calc_value= list_value->value - type_add;
part_info->list_array[list_index].list_value= calc_value;
part_info->list_array[list_index++].partition_id= i;
}
} while (++i < part_info->num_parts);
}
DBUG_ASSERT(part_info->fixed);
if (part_info->num_list_values)
{
bool first= TRUE;
/*
list_array and list_col_array are unions, so this works for both
variants of LIST partitioning.
*/
my_qsort(part_info->list_array, part_info->num_list_values, size_entries,
compare_func);
i= 0;
do
{
DBUG_ASSERT(i < part_info->num_list_values);
curr_value= part_info->column_list
? (void*)&part_info->list_col_array[num_column_values * i]
: (void*)&part_info->list_array[i];
if (likely(first || compare_func(curr_value, prev_value)))
{
prev_value= curr_value;
first= FALSE;
}
else
{
my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
goto end;
}
} while (++i < part_info->num_list_values);
}
result= FALSE;
end:
DBUG_RETURN(result);
}
/* /*
Set up function pointers for partition function Set up function pointers for partition function
@ -1343,6 +1723,12 @@ static void set_up_partition_func_pointers(partition_info *part_info)
part_info->get_subpartition_id; part_info->get_subpartition_id;
part_info->get_subpartition_id= get_part_id_charset_func_subpart; part_info->get_subpartition_id= get_part_id_charset_func_subpart;
} }
if (part_info->part_type == RANGE_PARTITION)
part_info->check_constants= check_range_constants;
else if (part_info->part_type == LIST_PARTITION)
part_info->check_constants= check_list_constants;
else
part_info->check_constants= check_no_constants;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
@ -1506,8 +1892,7 @@ NOTES
of an error that is not discovered until here. of an error that is not discovered until here.
*/ */
bool fix_partition_func(THD *thd, TABLE *table, bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind)
bool is_create_table_ind)
{ {
bool result= TRUE; bool result= TRUE;
partition_info *part_info= table->part_info; partition_info *part_info= table->part_info;
@ -1564,6 +1949,7 @@ bool fix_partition_func(THD *thd, TABLE *table,
Partition is defined. We need to verify that partitioning Partition is defined. We need to verify that partitioning
function is correct. function is correct.
*/ */
set_up_partition_func_pointers(part_info);
if (part_info->part_type == HASH_PARTITION) if (part_info->part_type == HASH_PARTITION)
{ {
if (part_info->linear_hash_ind) if (part_info->linear_hash_ind)
@ -1589,7 +1975,6 @@ bool fix_partition_func(THD *thd, TABLE *table,
} }
else else
{ {
const char *error_str;
if (part_info->column_list) if (part_info->column_list)
{ {
if (part_info->part_type == VERSIONING_PARTITION && if (part_info->part_type == VERSIONING_PARTITION &&
@ -1606,32 +1991,12 @@ bool fix_partition_func(THD *thd, TABLE *table,
goto end; goto end;
} }
part_info->fixed= TRUE; part_info->fixed= TRUE;
if (part_info->part_type == RANGE_PARTITION) if (part_info->check_constants(thd, part_info))
{
error_str= "HASH";
if (unlikely(part_info->check_range_constants(thd)))
goto end;
}
else if (part_info->part_type == LIST_PARTITION)
{
error_str= "LIST";
if (unlikely(part_info->check_list_constants(thd)))
goto end;
}
else if (part_info->part_type == VERSIONING_PARTITION)
{
error_str= "SYSTEM_TIME";
if (unlikely(part_info->check_range_constants(thd)))
goto end;
}
else
{
DBUG_ASSERT(0);
my_error(ER_INCONSISTENT_PARTITION_INFO_ERROR, MYF(0));
goto end; goto end;
}
if (unlikely(part_info->num_parts < 1)) if (unlikely(part_info->num_parts < 1))
{ {
const char *error_str= part_info->part_type == LIST_PARTITION
? "LIST" : "RANGE";
my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_str); my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_str);
goto end; goto end;
} }
@ -1679,7 +2044,6 @@ bool fix_partition_func(THD *thd, TABLE *table,
} }
check_range_capable_PF(table); check_range_capable_PF(table);
set_up_partition_key_maps(table, part_info); set_up_partition_key_maps(table, part_info);
set_up_partition_func_pointers(part_info);
set_up_range_analysis_info(part_info); set_up_range_analysis_info(part_info);
table->file->set_part_info(part_info); table->file->set_part_info(part_info);
result= FALSE; result= FALSE;
@ -5386,13 +5750,13 @@ the generated partition syntax in a correct manner.
tab_part_info->part_type == RANGE_PARTITION && tab_part_info->part_type == RANGE_PARTITION &&
((is_last_partition_reorged && ((is_last_partition_reorged &&
(tab_part_info->column_list ? (tab_part_info->column_list ?
(tab_part_info->compare_column_values( (partition_info_compare_column_values(
alt_max_elem_val->col_val_array, alt_max_elem_val->col_val_array,
tab_max_elem_val->col_val_array) < 0) : tab_max_elem_val->col_val_array) < 0) :
alt_max_range < tab_max_range)) || alt_max_range < tab_max_range)) ||
(!is_last_partition_reorged && (!is_last_partition_reorged &&
(tab_part_info->column_list ? (tab_part_info->column_list ?
(tab_part_info->compare_column_values( (partition_info_compare_column_values(
alt_max_elem_val->col_val_array, alt_max_elem_val->col_val_array,
tab_max_elem_val->col_val_array) != 0) : tab_max_elem_val->col_val_array) != 0) :
alt_max_range != tab_max_range)))) alt_max_range != tab_max_range))))