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:
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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))))
|
||||||
|
Reference in New Issue
Block a user