summaryrefslogtreecommitdiff
path: root/sql/sql_partition.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_partition.cc')
-rw-r--r--sql/sql_partition.cc1031
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(&ltime, vers_info->interval.start);
+ while ((el= it++)->id < hist_parts)
+ {
+ if (date_add_interval(&ltime, 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(&ltime, &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