diff options
Diffstat (limited to 'sql/sql_partition.cc')
-rw-r--r-- | sql/sql_partition.cc | 1031 |
1 files changed, 808 insertions, 223 deletions
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index fadd7009822..239e8098ffd 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -67,6 +67,8 @@ #include "opt_range.h" // store_key_image_to_rec #include "sql_alter.h" // Alter_table_ctx #include "sql_select.h" +#include "sql_tablespace.h" // check_tablespace_name +#include "tztime.h" // my_tz_OFFSET0 #include <algorithm> using std::max; @@ -87,6 +89,7 @@ static int get_partition_id_list_col(partition_info *, uint32 *, longlong *); static int get_partition_id_list(partition_info *, uint32 *, longlong *); static int get_partition_id_range_col(partition_info *, uint32 *, longlong *); static int get_partition_id_range(partition_info *, uint32 *, longlong *); +static int vers_get_partition_id(partition_info *, uint32 *, longlong *); static int get_part_id_charset_func_part(partition_info *, uint32 *, longlong *); static int get_part_id_charset_func_subpart(partition_info *, uint32 *); static int get_partition_id_hash_nosub(partition_info *, uint32 *, longlong *); @@ -105,27 +108,12 @@ static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR*); uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter); uint32 get_next_partition_id_list(PARTITION_ITERATOR* part_iter); -int get_part_iter_for_interval_via_mapping(partition_info *part_info, - bool is_subpart, - uint32 *store_length_array, - uchar *min_value, uchar *max_value, - uint min_len, uint max_len, - uint flags, - PARTITION_ITERATOR *part_iter); -int get_part_iter_for_interval_cols_via_map(partition_info *part_info, - bool is_subpart, - uint32 *store_length_array, - uchar *min_value, uchar *max_value, - uint min_len, uint max_len, - uint flags, - PARTITION_ITERATOR *part_iter); -int get_part_iter_for_interval_via_walking(partition_info *part_info, - bool is_subpart, - uint32 *store_length_array, - uchar *min_value, uchar *max_value, - uint min_len, uint max_len, - uint flags, - PARTITION_ITERATOR *part_iter); +static int get_part_iter_for_interval_via_mapping(partition_info *, bool, + uint32 *, uchar *, uchar *, uint, uint, uint, PARTITION_ITERATOR *); +static int get_part_iter_for_interval_cols_via_map(partition_info *, bool, + uint32 *, uchar *, uchar *, uint, uint, uint, PARTITION_ITERATOR *); +static int get_part_iter_for_interval_via_walking(partition_info *, bool, + uint32 *, uchar *, uchar *, uint, uint, uint, PARTITION_ITERATOR *); #ifdef WITH_PARTITION_STORAGE_ENGINE static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec); @@ -244,82 +232,11 @@ bool partition_default_handling(THD *thd, TABLE *table, partition_info *part_inf /* - A useful routine used by update_row for partition handlers to calculate - the partition ids of the old and the new record. + A useful routine used by update/delete_row for partition handlers to + calculate the partition id. SYNOPSIS - get_part_for_update() - old_data Buffer of old record - new_data Buffer of new record - rec0 Reference to table->record[0] - part_info Reference to partition information - out:old_part_id The returned partition id of old record - out:new_part_id The returned partition id of new record - - RETURN VALUE - 0 Success - > 0 Error code -*/ - -int get_parts_for_update(const uchar *old_data, const uchar *new_data, - const uchar *rec0, partition_info *part_info, - uint32 *old_part_id, uint32 *new_part_id, - longlong *new_func_value) -{ - Field **part_field_array= part_info->full_part_field_array; - int error; - longlong old_func_value; - DBUG_ENTER("get_parts_for_update"); - - DBUG_ASSERT(new_data == rec0); // table->record[0] - part_info->table->move_fields(part_field_array, old_data, rec0); - error= part_info->get_partition_id(part_info, old_part_id, - &old_func_value); - part_info->table->move_fields(part_field_array, rec0, old_data); - if (unlikely(error)) // Should never happen - { - DBUG_ASSERT(0); - DBUG_RETURN(error); - } -#ifdef NOT_NEEDED - if (new_data == rec0) -#endif - { - if (unlikely(error= part_info->get_partition_id(part_info, - new_part_id, - new_func_value))) - { - DBUG_RETURN(error); - } - } -#ifdef NOT_NEEDED - else - { - /* - This branch should never execute but it is written anyways for - future use. It will be tested by ensuring that the above - condition is false in one test situation before pushing the code. - */ - part_info->table->move_fields(part_field_array, new_data, rec0); - error= part_info->get_partition_id(part_info, new_part_id, - new_func_value); - part_info->table->move_fields(part_field_array, rec0, new_data); - if (unlikely(error)) - { - DBUG_RETURN(error); - } - } -#endif - DBUG_RETURN(0); -} - - -/* - A useful routine used by delete_row for partition handlers to calculate - the partition id. - - SYNOPSIS - get_part_for_delete() + get_part_for_buf() buf Buffer of old record rec0 Reference to table->record[0] part_info Reference to partition information @@ -335,21 +252,19 @@ int get_parts_for_update(const uchar *old_data, const uchar *new_data, calculate the partition id. */ -int get_part_for_delete(const uchar *buf, const uchar *rec0, - partition_info *part_info, uint32 *part_id) +int get_part_for_buf(const uchar *buf, const uchar *rec0, + partition_info *part_info, uint32 *part_id) { int error; longlong func_value; - DBUG_ENTER("get_part_for_delete"); + DBUG_ENTER("get_part_for_buf"); - if (likely(buf == rec0)) + if (buf == rec0) { - if (unlikely((error= part_info->get_partition_id(part_info, part_id, - &func_value)))) - { - DBUG_RETURN(error); - } - DBUG_PRINT("info", ("Delete from partition %d", *part_id)); + error= part_info->get_partition_id(part_info, part_id, &func_value); + if (unlikely((error))) + goto err; + DBUG_PRINT("info", ("Partition %d", *part_id)); } else { @@ -358,12 +273,13 @@ int get_part_for_delete(const uchar *buf, const uchar *rec0, error= part_info->get_partition_id(part_info, part_id, &func_value); part_info->table->move_fields(part_field_array, rec0, buf); if (unlikely(error)) - { - DBUG_RETURN(error); - } - DBUG_PRINT("info", ("Delete from partition %d (path2)", *part_id)); + goto err; + DBUG_PRINT("info", ("Partition %d (path2)", *part_id)); } DBUG_RETURN(0); +err: + part_info->err_value= func_value; + DBUG_RETURN(error); } @@ -1249,6 +1165,424 @@ static void set_up_partition_key_maps(TABLE *table, 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 partition boundaries when rotating by INTERVAL */ +static bool check_vers_constants(THD *thd, partition_info *part_info) +{ + uint hist_parts= part_info->num_parts - 1; + Vers_part_info *vers_info= part_info->vers_info; + vers_info->hist_part= part_info->partitions.head(); + vers_info->now_part= part_info->partitions.elem(hist_parts); + + if (!vers_info->interval.is_set()) + return 0; + + part_info->range_int_array= + (longlong*) thd->alloc(hist_parts * sizeof(longlong)); + + MYSQL_TIME ltime; + List_iterator<partition_element> it(part_info->partitions); + partition_element *el; + my_tz_OFFSET0->gmt_sec_to_TIME(<ime, vers_info->interval.start); + while ((el= it++)->id < hist_parts) + { + if (date_add_interval(<ime, vers_info->interval.type, + vers_info->interval.step)) + goto err; + uint error= 0; + part_info->range_int_array[el->id]= el->range_value= + my_tz_OFFSET0->TIME_to_gmt_sec(<ime, &error); + if (error) + goto err; + if (vers_info->hist_part->range_value <= thd->system_time) + vers_info->hist_part= el; + } + return 0; +err: + my_error(ER_DATA_OUT_OF_RANGE, MYF(0), "TIMESTAMP", "INTERVAL"); + return 1; +} + /* Set up function pointers for partition function @@ -1295,6 +1629,24 @@ static void set_up_partition_func_pointers(partition_info *part_info) part_info->get_subpartition_id= get_partition_id_hash_sub; } } + else if (part_info->part_type == VERSIONING_PARTITION) + { + part_info->get_part_partition_id= vers_get_partition_id; + if (part_info->list_of_subpart_fields) + { + if (part_info->linear_hash_ind) + part_info->get_subpartition_id= get_partition_id_linear_key_sub; + else + part_info->get_subpartition_id= get_partition_id_key_sub; + } + else + { + if (part_info->linear_hash_ind) + part_info->get_subpartition_id= get_partition_id_linear_hash_sub; + else + part_info->get_subpartition_id= get_partition_id_hash_sub; + } + } else /* LIST Partitioning */ { if (part_info->column_list) @@ -1335,6 +1687,10 @@ static void set_up_partition_func_pointers(partition_info *part_info) else part_info->get_partition_id= get_partition_id_list; } + else if (part_info->part_type == VERSIONING_PARTITION) + { + part_info->get_partition_id= vers_get_partition_id; + } else /* HASH partitioning */ { if (part_info->list_of_part_fields) @@ -1391,6 +1747,14 @@ static void set_up_partition_func_pointers(partition_info *part_info) part_info->get_subpartition_id; 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 if (part_info->part_type == VERSIONING_PARTITION) + part_info->check_constants= check_vers_constants; + else + part_info->check_constants= check_no_constants; DBUG_VOID_RETURN; } @@ -1554,20 +1918,19 @@ NOTES of an error that is not discovered until here. */ -bool fix_partition_func(THD *thd, TABLE *table, - bool is_create_table_ind) +bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind) { bool result= TRUE; partition_info *part_info= table->part_info; - enum_mark_columns save_mark_used_columns= thd->mark_used_columns; + enum_column_usage saved_column_usage= thd->column_usage; DBUG_ENTER("fix_partition_func"); if (part_info->fixed) { DBUG_RETURN(FALSE); } - thd->mark_used_columns= MARK_COLUMNS_NONE; - DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns)); + thd->column_usage= COLUMNS_WRITE; + DBUG_PRINT("info", ("thd->column_usage: %d", thd->column_usage)); if (!is_create_table_ind || thd->lex->sql_command != SQLCOM_CREATE_TABLE) @@ -1607,10 +1970,12 @@ bool fix_partition_func(THD *thd, TABLE *table, } } DBUG_ASSERT(part_info->part_type != NOT_A_PARTITION); + DBUG_ASSERT(part_info->part_type != VERSIONING_PARTITION || part_info->column_list); /* Partition is defined. We need to verify that partitioning function is correct. */ + set_up_partition_func_pointers(part_info); if (part_info->part_type == HASH_PARTITION) { if (part_info->linear_hash_ind) @@ -1636,9 +2001,11 @@ bool fix_partition_func(THD *thd, TABLE *table, } else { - const char *error_str; if (part_info->column_list) { + if (part_info->part_type == VERSIONING_PARTITION && + part_info->vers_setup_expression(thd)) + goto end; List_iterator<const char> it(part_info->part_field_list); if (unlikely(handle_list_of_fields(thd, it, table, part_info, FALSE))) goto end; @@ -1650,26 +2017,12 @@ bool fix_partition_func(THD *thd, TABLE *table, goto end; } part_info->fixed= TRUE; - if (part_info->part_type == RANGE_PARTITION) - { - 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 - { - DBUG_ASSERT(0); - my_error(ER_INCONSISTENT_PARTITION_INFO_ERROR, MYF(0)); + if (part_info->check_constants(thd, part_info)) goto end; - } 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); goto end; } @@ -1717,13 +2070,12 @@ bool fix_partition_func(THD *thd, TABLE *table, } check_range_capable_PF(table); set_up_partition_key_maps(table, part_info); - set_up_partition_func_pointers(part_info); set_up_range_analysis_info(part_info); table->file->set_part_info(part_info); result= FALSE; end: - thd->mark_used_columns= save_mark_used_columns; - DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns)); + thd->column_usage= saved_column_usage; + DBUG_PRINT("info", ("thd->column_usage: %d", thd->column_usage)); DBUG_RETURN(result); } @@ -1829,7 +2181,7 @@ static int add_keyword_path(String *str, const char *keyword, #ifdef __WIN__ /* Convert \ to / to be able to create table on unix */ char *pos, *end; - uint length= strlen(temp_path); + size_t length= strlen(temp_path); for (pos= temp_path, end= pos+length ; pos < end ; pos++) { if (*pos == '\\') @@ -2182,6 +2534,20 @@ static int add_partition_values(String *str, partition_info *part_info, } while (++i < num_items); err+= str->append(')'); } + else if (part_info->part_type == VERSIONING_PARTITION) + { + switch (p_elem->type()) + { + case partition_element::CURRENT: + err+= str->append(STRING_WITH_LEN(" CURRENT")); + break; + case partition_element::HISTORY: + err+= str->append(STRING_WITH_LEN(" HISTORY")); + break; + default: + DBUG_ASSERT(0 && "wrong p_elem->type"); + } + } end: return err; } @@ -2275,13 +2641,37 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info, else err+= str.append(STRING_WITH_LEN("HASH ")); break; + case VERSIONING_PARTITION: + err+= str.append(STRING_WITH_LEN("SYSTEM_TIME ")); + break; default: DBUG_ASSERT(0); /* We really shouldn't get here, no use in continuing from here */ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); DBUG_RETURN(NULL); } - if (part_info->part_expr) + if (part_info->part_type == VERSIONING_PARTITION) + { + Vers_part_info *vers_info= part_info->vers_info; + DBUG_ASSERT(vers_info); + if (vers_info->interval.is_set()) + { + err+= str.append(STRING_WITH_LEN("INTERVAL ")); + err+= append_interval(&str, vers_info->interval.type, + vers_info->interval.step); + if (create_info) // not SHOW CREATE + { + err+= str.append(STRING_WITH_LEN(" STARTS ")); + err+= str.append_ulonglong(vers_info->interval.start); + } + } + if (vers_info->limit) + { + err+= str.append(STRING_WITH_LEN("LIMIT ")); + err+= str.append_ulonglong(vers_info->limit); + } + } + else if (part_info->part_expr) { err+= str.append('('); part_info->part_expr->print_for_table_def(&str); @@ -3088,6 +3478,48 @@ int get_partition_id_range_col(partition_info *part_info, } +int vers_get_partition_id(partition_info *part_info, uint32 *part_id, + longlong *func_value) +{ + DBUG_ENTER("vers_get_partition_id"); + Field *row_end= part_info->part_field_array[STAT_TRX_END]; + Vers_part_info *vers_info= part_info->vers_info; + + if (row_end->is_max() || row_end->is_null()) + *part_id= vers_info->now_part->id; + else // row is historical + { + longlong *range_value= part_info->range_int_array; + uint max_hist_id= part_info->num_parts - 2; + uint min_hist_id= 0, loc_hist_id= vers_info->hist_part->id; + ulong unused; + my_time_t ts; + + if (!range_value) + goto done; // fastpath + + ts= row_end->get_timestamp(&unused); + if ((loc_hist_id == 0 || range_value[loc_hist_id - 1] < ts) && + (loc_hist_id == max_hist_id || range_value[loc_hist_id] >= ts)) + goto done; // fastpath + + while (max_hist_id > min_hist_id) + { + loc_hist_id= (max_hist_id + min_hist_id) / 2; + if (range_value[loc_hist_id] <= ts) + min_hist_id= loc_hist_id + 1; + else + max_hist_id= loc_hist_id; + } + loc_hist_id= max_hist_id; +done: + *part_id= (uint32)loc_hist_id; + } + DBUG_PRINT("exit",("partition: %d", *part_id)); + DBUG_RETURN(0); +} + + int get_partition_id_range(partition_info *part_info, uint32 *part_id, longlong *func_value) @@ -4020,8 +4452,7 @@ bool mysql_unpack_partition(THD *thd, { bool result= TRUE; partition_info *part_info; - CHARSET_INFO *old_character_set_client= - thd->variables.character_set_client; + CHARSET_INFO *old_character_set_client= thd->variables.character_set_client; LEX *old_lex= thd->lex; LEX lex; PSI_statement_locker *parent_locker= thd->m_statement_psi; @@ -4036,17 +4467,9 @@ bool mysql_unpack_partition(THD *thd, if (init_lex_with_single_table(thd, table, &lex)) goto end; - /* - All Items created is put into a free list on the THD object. This list - is used to free all Item objects after completing a query. We don't - want that to happen with the Item tree created as part of the partition - info. This should be attached to the table object and remain so until - the table object is released. - Thus we move away the current list temporarily and start a new list that - we then save in the partition info structure. - */ *work_part_info_used= FALSE; - lex.part_info= new partition_info();/* Indicates MYSQLparse from this place */ + lex.part_info= new partition_info(); + lex.part_info->table= table; /* Indicates MYSQLparse from this place */ if (!lex.part_info) { mem_alloc_error(sizeof(partition_info)); @@ -4431,13 +4854,21 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, !thd->lex->part_info->num_columns) thd->lex->part_info->num_columns= 1; // to make correct clone - if ((thd->work_part_info= thd->lex->part_info) && - !(thd->work_part_info= thd->lex->part_info->get_clone(thd))) + /* + One of these is done in handle_if_exists_option(): + thd->work_part_info= thd->lex->part_info; + or + thd->work_part_info= NULL; + */ + if (thd->work_part_info && + !(thd->work_part_info= thd->work_part_info->get_clone(thd))) DBUG_RETURN(TRUE); /* ALTER_ADMIN_PARTITION is handled in mysql_admin_table */ DBUG_ASSERT(!(alter_info->flags & Alter_info::ALTER_ADMIN_PARTITION)); + partition_info *saved_part_info= NULL; + if (alter_info->flags & (Alter_info::ALTER_ADD_PARTITION | Alter_info::ALTER_DROP_PARTITION | @@ -4447,7 +4878,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, Alter_info::ALTER_REBUILD_PARTITION)) { partition_info *tab_part_info; - uint flags= 0; + ulonglong flags= 0; bool is_last_partition_reorged= FALSE; part_elem_value *tab_max_elem_val= NULL; part_elem_value *alt_max_elem_val= NULL; @@ -4467,8 +4898,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, object to allow fast_alter_partition_table to perform the changes. */ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, - alter_ctx->db, - alter_ctx->table_name, + alter_ctx->db.str, + alter_ctx->table_name.str, MDL_INTENTION_EXCLUSIVE)); tab_part_info= table->part_info; @@ -4566,7 +4997,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, if (!(tab_part_info= tab_part_info->get_clone(thd))) DBUG_RETURN(TRUE); } - DBUG_PRINT("info", ("*fast_alter_table flags: 0x%x", flags)); + DBUG_PRINT("info", ("*fast_alter_table flags: 0x%llx", flags)); if ((alter_info->flags & Alter_info::ALTER_ADD_PARTITION) || (alter_info->flags & Alter_info::ALTER_REORGANIZE_PARTITION)) { @@ -4602,16 +5033,15 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), "LIST", "IN"); } - else if (tab_part_info->part_type == RANGE_PARTITION) + else if (thd->work_part_info->part_type == VERSIONING_PARTITION) { - my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), - "RANGE", "LESS THAN"); + my_error(ER_PARTITION_WRONG_TYPE, MYF(0), "SYSTEM_TIME"); } else { - DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION); - my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), - "LIST", "IN"); + DBUG_ASSERT(tab_part_info->part_type == RANGE_PARTITION || + tab_part_info->part_type == LIST_PARTITION); + (void) tab_part_info->error_if_requires_values(); } goto err; } @@ -4639,6 +5069,16 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, } if (alter_info->flags & Alter_info::ALTER_ADD_PARTITION) { + if (*fast_alter_table && thd->locked_tables_mode) + { + MEM_ROOT *old_root= thd->mem_root; + thd->mem_root= &thd->locked_tables_list.m_locked_tables_root; + saved_part_info= tab_part_info->get_clone(thd); + thd->mem_root= old_root; + saved_part_info->read_partitions= tab_part_info->read_partitions; + saved_part_info->lock_partitions= tab_part_info->lock_partitions; + saved_part_info->bitmaps_are_initialized= tab_part_info->bitmaps_are_initialized; + } /* We start by moving the new partitions to the list of temporary partitions. We will then check that the new partitions fit in the @@ -4654,7 +5094,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, must know the number of new partitions in this case. */ if (thd->lex->no_write_to_binlog && - tab_part_info->part_type != HASH_PARTITION) + tab_part_info->part_type != HASH_PARTITION && + tab_part_info->part_type != VERSIONING_PARTITION) { my_error(ER_NO_BINLOG_ERROR, MYF(0)); goto err; @@ -4759,16 +5200,14 @@ adding and copying partitions, the second after completing the adding and copying and finally the third line after also dropping the partitions that are reorganised. */ - if (*fast_alter_table && - tab_part_info->part_type == HASH_PARTITION) + if (*fast_alter_table && tab_part_info->part_type == HASH_PARTITION) { uint part_no= 0, start_part= 1, start_sec_part= 1; uint end_part= 0, end_sec_part= 0; uint upper_2n= tab_part_info->linear_hash_mask + 1; uint lower_2n= upper_2n >> 1; bool all_parts= TRUE; - if (tab_part_info->linear_hash_ind && - num_new_partitions < upper_2n) + if (tab_part_info->linear_hash_ind && num_new_partitions < upper_2n) { /* An analysis of which parts needs reorganisation shows that it is @@ -4859,6 +5298,26 @@ that are reorganised. partition configuration is made. */ { + partition_element *now_part= NULL; + if (tab_part_info->part_type == VERSIONING_PARTITION) + { + List_iterator<partition_element> it(tab_part_info->partitions); + partition_element *el; + while ((el= it++)) + { + if (el->type() == partition_element::CURRENT) + { + it.remove(); + now_part= el; + } + } + if (*fast_alter_table && tab_part_info->vers_info->interval.is_set()) + { + partition_element *hist_part= tab_part_info->vers_info->hist_part; + if (hist_part->range_value <= thd->system_time) + hist_part->part_state= PART_CHANGED; + } + } List_iterator<partition_element> alt_it(alt_part_info->partitions); uint part_count= 0; do @@ -4873,6 +5332,15 @@ that are reorganised. } } while (++part_count < num_new_partitions); tab_part_info->num_parts+= num_new_partitions; + if (tab_part_info->part_type == VERSIONING_PARTITION) + { + DBUG_ASSERT(now_part); + if (tab_part_info->partitions.push_back(now_part, thd->mem_root)) + { + mem_alloc_error(1); + goto err; + } + } } /* If we specify partitions explicitly we don't use defaults anymore. @@ -4906,16 +5374,28 @@ that are reorganised. List_iterator<partition_element> part_it(tab_part_info->partitions); tab_part_info->is_auto_partitioned= FALSE; - if (!(tab_part_info->part_type == RANGE_PARTITION || - tab_part_info->part_type == LIST_PARTITION)) + if (tab_part_info->part_type == VERSIONING_PARTITION) { - my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP"); - goto err; + if (num_parts_dropped >= tab_part_info->num_parts - 1) + { + DBUG_ASSERT(table && table->s && table->s->table_name.str); + my_error(ER_VERS_WRONG_PARTS, MYF(0), table->s->table_name.str); + goto err; + } } - if (num_parts_dropped >= tab_part_info->num_parts) + else { - my_error(ER_DROP_LAST_PARTITION, MYF(0)); - goto err; + if (!(tab_part_info->part_type == RANGE_PARTITION || + tab_part_info->part_type == LIST_PARTITION)) + { + my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP"); + goto err; + } + if (num_parts_dropped >= tab_part_info->num_parts) + { + my_error(ER_DROP_LAST_PARTITION, MYF(0)); + goto err; + } } do { @@ -4923,6 +5403,24 @@ that are reorganised. if (is_name_in_list(part_elem->partition_name, alter_info->partition_names)) { + if (tab_part_info->part_type == VERSIONING_PARTITION) + { + if (part_elem->type() == partition_element::CURRENT) + { + my_error(ER_VERS_WRONG_PARTS, MYF(0), table->s->table_name.str); + goto err; + } + if (tab_part_info->vers_info->interval.is_set()) + { + if (num_parts_found < part_count) + { + my_error(ER_VERS_DROP_PARTITION_INTERVAL, MYF(0)); + goto err; + } + tab_part_info->vers_info->interval.start= + (my_time_t)part_elem->range_value; + } + } /* Set state to indicate that the partition is to be dropped. */ @@ -5245,8 +5743,9 @@ the generated partition syntax in a correct manner. tab_part_info->use_default_subpartitions= FALSE; tab_part_info->use_default_num_subpartitions= FALSE; } + if (tab_part_info->check_partition_info(thd, (handlerton**)NULL, - table->file, 0, TRUE)) + table->file, 0, alt_part_info)) { goto err; } @@ -5259,13 +5758,13 @@ the generated partition syntax in a correct manner. tab_part_info->part_type == RANGE_PARTITION && ((is_last_partition_reorged && (tab_part_info->column_list ? - (tab_part_info->compare_column_values( + (partition_info_compare_column_values( alt_max_elem_val->col_val_array, tab_max_elem_val->col_val_array) < 0) : alt_max_range < tab_max_range)) || (!is_last_partition_reorged && (tab_part_info->column_list ? - (tab_part_info->compare_column_values( + (partition_info_compare_column_values( alt_max_elem_val->col_val_array, tab_max_elem_val->col_val_array) != 0) : alt_max_range != tab_max_range)))) @@ -5283,7 +5782,7 @@ the generated partition syntax in a correct manner. goto err; } } - } + } // ADD, DROP, COALESCE, REORGANIZE, TABLE_REORG, REBUILD else { /* @@ -5449,6 +5948,8 @@ the generated partition syntax in a correct manner. DBUG_RETURN(FALSE); err: *fast_alter_table= false; + if (saved_part_info) + table->part_info= saved_part_info; DBUG_RETURN(TRUE); } @@ -5487,7 +5988,7 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) THD *thd= lpt->thd; DBUG_ENTER("mysql_change_partitions"); - build_table_filename(path, sizeof(path) - 1, lpt->db, lpt->table_name, "", 0); + build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0); if(mysql_trans_prepare_alter_copy_data(thd)) DBUG_RETURN(TRUE); @@ -5533,7 +6034,7 @@ static bool mysql_rename_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) int error; DBUG_ENTER("mysql_rename_partitions"); - build_table_filename(path, sizeof(path) - 1, lpt->db, lpt->table_name, "", 0); + build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0); if ((error= lpt->table->file->ha_rename_partitions(path))) { if (error != 1) @@ -5579,7 +6080,7 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table->s->table_name.str, MDL_EXCLUSIVE)); - build_table_filename(path, sizeof(path) - 1, lpt->db, lpt->table_name, "", 0); + build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0); if ((error= lpt->table->file->ha_drop_partitions(path))) { lpt->table->file->print_error(error, MYF(0)); @@ -5976,8 +6477,7 @@ static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_ENTER("write_log_rename_frm"); part_info->first_log_entry= NULL; - build_table_filename(path, sizeof(path) - 1, lpt->db, - lpt->table_name, "", 0); + build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0); build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt); mysql_mutex_lock(&LOCK_gdl); if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE)) @@ -6028,8 +6528,7 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_ENTER("write_log_drop_partition"); part_info->first_log_entry= NULL; - build_table_filename(path, sizeof(path) - 1, lpt->db, - lpt->table_name, "", 0); + build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0); build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt); mysql_mutex_lock(&LOCK_gdl); if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, @@ -6087,8 +6586,7 @@ static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_ASSERT(old_first_log_entry); DBUG_ENTER("write_log_add_change_partition"); - build_table_filename(path, sizeof(path) - 1, lpt->db, - lpt->table_name, "", 0); + build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0); build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt); mysql_mutex_lock(&LOCK_gdl); @@ -6156,8 +6654,7 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) Replace the revert operations with forced retry operations. */ part_info->first_log_entry= NULL; - build_table_filename(path, sizeof(path) - 1, lpt->db, - lpt->table_name, "", 0); + build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0); build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt); mysql_mutex_lock(&LOCK_gdl); if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) @@ -6342,8 +6839,8 @@ void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, Better to do that here, than leave the cleaning up to others. Aquire EXCLUSIVE mdl lock if not already aquired. */ - if (!thd->mdl_context.is_lock_owner(MDL_key::TABLE, lpt->db, - lpt->table_name, + if (!thd->mdl_context.is_lock_owner(MDL_key::TABLE, lpt->db.str, + lpt->table_name.str, MDL_EXCLUSIVE)) { if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) @@ -6540,8 +7037,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, Alter_info *alter_info, HA_CREATE_INFO *create_info, TABLE_LIST *table_list, - const char *db, - const char *table_name) + const LEX_CSTRING *db, + const LEX_CSTRING *table_name) { /* Set-up struct used to write frm files */ partition_info *part_info; @@ -6560,15 +7057,12 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, lpt->part_info= part_info; lpt->alter_info= alter_info; lpt->create_info= create_info; - lpt->db_options= create_info->table_options; - if (create_info->row_type != ROW_TYPE_FIXED && - create_info->row_type != ROW_TYPE_DEFAULT) - lpt->db_options|= HA_OPTION_PACK_RECORD; + lpt->db_options= create_info->table_options_with_row_type(); lpt->table= table; lpt->key_info_buffer= 0; lpt->key_count= 0; - lpt->db= db; - lpt->table_name= table_name; + lpt->db= *db; + lpt->table_name= *table_name; lpt->copied= 0; lpt->deleted= 0; lpt->pack_frm_data= NULL; @@ -6916,6 +7410,39 @@ err: } #endif + +/* + Prepare for calling val_int on partition function by setting fields to + point to the record where the values of the PF-fields are stored. + + SYNOPSIS + set_field_ptr() + ptr Array of fields to change ptr + new_buf New record pointer + old_buf Old record pointer + + DESCRIPTION + Set ptr in field objects of field array to refer to new_buf record + instead of previously old_buf. Used before calling val_int and after + it is used to restore pointers to table->record[0]. + This routine is placed outside of partition code since it can be useful + also for other programs. +*/ + +void set_field_ptr(Field **ptr, const uchar *new_buf, + const uchar *old_buf) +{ + my_ptrdiff_t diff= (new_buf - old_buf); + DBUG_ENTER("set_field_ptr"); + + do + { + (*ptr)->move_field_offset(diff); + } while (*(++ptr)); + DBUG_VOID_RETURN; +} + + /* Prepare for calling val_int on partition function by setting fields to point to the record where the values of the PF-fields are stored. @@ -6954,6 +7481,61 @@ void set_key_field_ptr(KEY *key_info, const uchar *new_buf, } +/** + Append all fields in read_set to string + + @param[in,out] str String to append to. + @param[in] row Row to append. + @param[in] table Table containing read_set and fields for the row. +*/ +void append_row_to_str(String &str, const uchar *row, TABLE *table) +{ + Field **fields, **field_ptr; + const uchar *rec; + uint num_fields= bitmap_bits_set(table->read_set); + uint curr_field_index= 0; + bool is_rec0= !row || row == table->record[0]; + if (!row) + rec= table->record[0]; + else + rec= row; + + /* Create a new array of all read fields. */ + fields= (Field**) my_malloc(sizeof(void*) * (num_fields + 1), + MYF(0)); + if (!fields) + return; + fields[num_fields]= NULL; + for (field_ptr= table->field; + *field_ptr; + field_ptr++) + { + if (!bitmap_is_set(table->read_set, (*field_ptr)->field_index)) + continue; + fields[curr_field_index++]= *field_ptr; + } + + + if (!is_rec0) + set_field_ptr(fields, rec, table->record[0]); + + for (field_ptr= fields; + *field_ptr; + field_ptr++) + { + Field *field= *field_ptr; + str.append(" "); + str.append(&field->field_name); + str.append(":"); + field_unpack(&str, field, rec, 0, false); + } + + if (!is_rec0) + set_field_ptr(fields, table->record[0], rec); + my_free(fields); +} + + /* SYNOPSIS mem_alloc_error() @@ -7386,13 +7968,11 @@ uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info, } -int get_part_iter_for_interval_cols_via_map(partition_info *part_info, - bool is_subpart, - uint32 *store_length_array, - uchar *min_value, uchar *max_value, - uint min_len, uint max_len, - uint flags, - PARTITION_ITERATOR *part_iter) +static int get_part_iter_for_interval_cols_via_map(partition_info *part_info, + bool is_subpart, uint32 *store_length_array, + uchar *min_value, uchar *max_value, + uint min_len, uint max_len, + uint flags, PARTITION_ITERATOR *part_iter) { bool can_match_multiple_values; uint32 nparts; @@ -7400,7 +7980,7 @@ int get_part_iter_for_interval_cols_via_map(partition_info *part_info, uint full_length= 0; DBUG_ENTER("get_part_iter_for_interval_cols_via_map"); - if (part_info->part_type == RANGE_PARTITION) + if (part_info->part_type == RANGE_PARTITION || part_info->part_type == VERSIONING_PARTITION) { get_col_endpoint= get_partition_id_cols_range_for_endpoint; part_iter->get_next= get_next_partition_id_range; @@ -7446,7 +8026,7 @@ int get_part_iter_for_interval_cols_via_map(partition_info *part_info, } if (flags & NO_MAX_RANGE) { - if (part_info->part_type == RANGE_PARTITION) + if (part_info->part_type == RANGE_PARTITION || part_info->part_type == VERSIONING_PARTITION) part_iter->part_nums.end= part_info->num_parts; else /* LIST_PARTITION */ { @@ -7513,13 +8093,12 @@ int get_part_iter_for_interval_cols_via_map(partition_info *part_info, @retval -1 All partitions would match (iterator not initialized) */ -int get_part_iter_for_interval_via_mapping(partition_info *part_info, - bool is_subpart, - uint32 *store_length_array, /* ignored */ - uchar *min_value, uchar *max_value, - uint min_len, uint max_len, /* ignored */ - uint flags, - PARTITION_ITERATOR *part_iter) +static int get_part_iter_for_interval_via_mapping(partition_info *part_info, + bool is_subpart, + uint32 *store_length_array, /* ignored */ + uchar *min_value, uchar *max_value, + uint min_len, uint max_len, /* ignored */ + uint flags, PARTITION_ITERATOR *part_iter) { Field *field= part_info->part_field_array[0]; uint32 UNINIT_VAR(max_endpoint_val); @@ -7760,13 +8339,12 @@ not_found: -1 - All partitions would match, iterator not initialized */ -int get_part_iter_for_interval_via_walking(partition_info *part_info, - bool is_subpart, - uint32 *store_length_array, /* ignored */ - uchar *min_value, uchar *max_value, - uint min_len, uint max_len, /* ignored */ - uint flags, - PARTITION_ITERATOR *part_iter) +static int get_part_iter_for_interval_via_walking(partition_info *part_info, + bool is_subpart, + uint32 *store_length_array, /* ignored */ + uchar *min_value, uchar *max_value, + uint min_len, uint max_len, /* ignored */ + uint flags, PARTITION_ITERATOR *part_iter) { Field *field; uint total_parts; @@ -8079,8 +8657,11 @@ int create_partition_name(char *out, size_t outlen, const char *in1, end= strxnmov(out, outlen-1, in1, "#P#", transl_part, NullS); else if (name_variant == TEMP_PART_NAME) end= strxnmov(out, outlen-1, in1, "#P#", transl_part, "#TMP#", NullS); - else if (name_variant == RENAMED_PART_NAME) + else + { + DBUG_ASSERT(name_variant == RENAMED_PART_NAME); end= strxnmov(out, outlen-1, in1, "#P#", transl_part, "#REN#", NullS); + } if (end - out == static_cast<ptrdiff_t>(outlen-1)) { my_error(ER_PATH_LENGTH, MYF(0), longest_str(in1, transl_part)); @@ -8120,9 +8701,12 @@ int create_subpartition_name(char *out, size_t outlen, else if (name_variant == TEMP_PART_NAME) end= strxnmov(out, outlen-1, in1, "#P#", transl_part_name, "#SP#", transl_subpart_name, "#TMP#", NullS); - else if (name_variant == RENAMED_PART_NAME) + else + { + DBUG_ASSERT(name_variant == RENAMED_PART_NAME); end= strxnmov(out, outlen-1, in1, "#P#", transl_part_name, "#SP#", transl_subpart_name, "#REN#", NullS); + } if (end - out == static_cast<ptrdiff_t>(outlen-1)) { my_error(ER_PATH_LENGTH, MYF(0), @@ -8143,4 +8727,5 @@ uint get_partition_field_store_length(Field *field) store_length+= HA_KEY_BLOB_LENGTH; return store_length; } + #endif |