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.cc2164
1 files changed, 1395 insertions, 769 deletions
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index eb711001ef6..a05e8fbf3ab 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -1,4 +1,4 @@
-/* Copyright 2005-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,16 +18,29 @@
to partitioning introduced in MySQL version 5.1. It contains functionality
used by all handlers that support partitioning, such as
the partitioning handler itself and the NDB handler.
+ (Much of the code in this file has been split into partition_info.cc and
+ the header files partition_info.h + partition_element.h + sql_partition.h)
- The first version was written by Mikael Ronstrom.
+ The first version was written by Mikael Ronstrom 2004-2006.
+ Various parts of the optimizer code was written by Sergey Petrunia.
+ Code have been maintained by Mattias Jonsson.
+ The second version was written by Mikael Ronstrom 2006-2007 with some
+ final fixes for partition pruning in 2008-2009 with assistance from Sergey
+ Petrunia and Mattias Jonsson.
- This version supports RANGE partitioning, LIST partitioning, HASH
+ The first version supports RANGE partitioning, LIST partitioning, HASH
partitioning and composite partitioning (hereafter called subpartitioning)
where each RANGE/LIST partitioning is HASH partitioned. The hash function
can either be supplied by the user or by only a list of fields (also
called KEY partitioning), where the MySQL server will use an internal
hash function.
There are quite a few defaults that can be used as well.
+
+ The second version introduces a new variant of RANGE and LIST partitioning
+ which is often referred to as column lists in the code variables. This
+ enables a user to specify a set of columns and their concatenated value
+ as the partition value. By comparing the concatenation of these values
+ the proper partition can be choosen.
*/
/* Some general useful functions */
@@ -54,9 +67,11 @@ const LEX_STRING partition_keywords[]=
{ C_STRING_WITH_LEN("LIST") },
{ C_STRING_WITH_LEN("KEY") },
{ C_STRING_WITH_LEN("MAXVALUE") },
- { C_STRING_WITH_LEN("LINEAR ") }
+ { C_STRING_WITH_LEN("LINEAR ") },
+ { C_STRING_WITH_LEN(" COLUMNS") }
};
static const char *part_str= "PARTITION";
+static const char *subpart_str= "SUBPARTITION";
static const char *sub_str= "SUB";
static const char *by_str= "BY";
static const char *space_str= " ";
@@ -65,26 +80,23 @@ static const char *end_paren_str= ")";
static const char *begin_paren_str= "(";
static const char *comma_str= ",";
-static int get_part_id_charset_func_all(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-static int get_part_id_charset_func_part(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-static int get_part_id_charset_func_subpart(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-static int get_part_part_id_charset_func(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-static int get_subpart_id_charset_func(partition_info *part_info,
- uint32 *part_id);
+int get_partition_id_list_col(partition_info *part_info,
+ uint32 *part_id,
+ longlong *func_value);
int get_partition_id_list(partition_info *part_info,
uint32 *part_id,
longlong *func_value);
+int get_partition_id_range_col(partition_info *part_info,
+ uint32 *part_id,
+ longlong *func_value);
int get_partition_id_range(partition_info *part_info,
uint32 *part_id,
longlong *func_value);
+static int get_part_id_charset_func_part(partition_info *part_info,
+ uint32 *part_id,
+ longlong *func_value);
+static int get_part_id_charset_func_subpart(partition_info *part_info,
+ uint32 *part_id);
int get_partition_id_hash_nosub(partition_info *part_info,
uint32 *part_id,
longlong *func_value);
@@ -97,30 +109,9 @@ int get_partition_id_linear_hash_nosub(partition_info *part_info,
int get_partition_id_linear_key_nosub(partition_info *part_info,
uint32 *part_id,
longlong *func_value);
-int get_partition_id_range_sub_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-int get_partition_id_range_sub_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-int get_partition_id_range_sub_linear_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-int get_partition_id_range_sub_linear_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-int get_partition_id_list_sub_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-int get_partition_id_list_sub_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-int get_partition_id_list_sub_linear_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-int get_partition_id_list_sub_linear_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
+int get_partition_id_with_sub(partition_info *part_info,
+ uint32 *part_id,
+ longlong *func_value);
int get_partition_id_hash_sub(partition_info *part_info,
uint32 *part_id);
int get_partition_id_key_sub(partition_info *part_info,
@@ -138,17 +129,64 @@ 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 cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec);
+static int cmp_rec_and_tuple_prune(part_column_list_val *val,
+ uint32 n_vals_in_rec,
+ bool tail_is_min);
#ifdef WITH_PARTITION_STORAGE_ENGINE
/*
+ Convert constants in VALUES definition to the character set the
+ corresponding field uses.
+
+ SYNOPSIS
+ convert_charset_partition_constant()
+ item Item to convert
+ cs Character set to convert to
+
+ RETURN VALUE
+ NULL Error
+ item New converted item
+*/
+
+Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs)
+{
+ THD *thd= current_thd;
+ Name_resolution_context *context= &thd->lex->current_select->context;
+ TABLE_LIST *save_list= context->table_list;
+ const char *save_where= thd->where;
+
+ item= item->safe_charset_converter(cs);
+ context->table_list= NULL;
+ thd->where= "convert character set partition constant";
+ if (!item || item->fix_fields(thd, (Item**)NULL))
+ item= NULL;
+ thd->where= save_where;
+ context->table_list= save_list;
+ return item;
+}
+
+
+/*
A support function to check if a name is in a list of strings
SYNOPSIS
@@ -165,7 +203,7 @@ bool is_name_in_list(char *name,
List<char> list_names)
{
List_iterator<char> names_it(list_names);
- uint no_names= list_names.elements;
+ uint num_names= list_names.elements;
uint i= 0;
do
@@ -173,7 +211,7 @@ bool is_name_in_list(char *name,
char *list_name= names_it++;
if (!(my_strcasecmp(system_charset_info, name, list_name)))
return TRUE;
- } while (++i < no_names);
+ } while (++i < num_names);
return FALSE;
}
@@ -200,26 +238,26 @@ bool partition_default_handling(TABLE *table, partition_info *part_info,
{
DBUG_ENTER("partition_default_handling");
- if (part_info->use_default_no_partitions)
+ if (part_info->use_default_num_partitions)
{
if (!is_create_table_ind &&
- table->file->get_no_parts(normalized_path, &part_info->no_parts))
+ table->file->get_no_parts(normalized_path, &part_info->num_parts))
{
DBUG_RETURN(TRUE);
}
}
else if (part_info->is_sub_partitioned() &&
- part_info->use_default_no_subpartitions)
+ part_info->use_default_num_subpartitions)
{
- uint no_parts;
+ uint num_parts;
if (!is_create_table_ind &&
- (table->file->get_no_parts(normalized_path, &no_parts)))
+ (table->file->get_no_parts(normalized_path, &num_parts)))
{
DBUG_RETURN(TRUE);
}
- DBUG_ASSERT(part_info->no_parts > 0);
- part_info->no_subparts= no_parts / part_info->no_parts;
- DBUG_ASSERT((no_parts % part_info->no_parts) == 0);
+ DBUG_ASSERT(part_info->num_parts > 0);
+ part_info->num_subparts= num_parts / part_info->num_parts;
+ DBUG_ASSERT((num_parts % part_info->num_parts) == 0);
}
part_info->set_up_defaults_for_partitioning(table->file,
(ulonglong)0, (uint)0);
@@ -252,8 +290,8 @@ bool check_reorganise_list(partition_info *new_part_info,
List<char> list_part_names)
{
uint new_count, old_count;
- uint no_new_parts= new_part_info->partitions.elements;
- uint no_old_parts= old_part_info->partitions.elements;
+ uint num_new_parts= new_part_info->partitions.elements;
+ uint num_old_parts= old_part_info->partitions.elements;
List_iterator<partition_element> new_parts_it(new_part_info->partitions);
bool same_part_info= (new_part_info == old_part_info);
DBUG_ENTER("check_reorganise_list");
@@ -276,8 +314,8 @@ bool check_reorganise_list(partition_info *new_part_info,
if (!is_name_in_list(old_name, list_part_names))
DBUG_RETURN(TRUE);
}
- } while (old_count < no_old_parts);
- } while (new_count < no_new_parts);
+ } while (old_count < num_old_parts);
+ } while (new_count < num_new_parts);
DBUG_RETURN(FALSE);
}
@@ -452,9 +490,10 @@ static bool set_up_field_array(TABLE *table,
bool is_sub_part)
{
Field **ptr, *field, **field_array;
- uint no_fields= 0;
+ uint num_fields= 0;
uint size_field_array;
uint i= 0;
+ uint inx;
partition_info *part_info= table->part_info;
int result= FALSE;
DBUG_ENTER("set_up_field_array");
@@ -463,9 +502,19 @@ static bool set_up_field_array(TABLE *table,
while ((field= *(ptr++)))
{
if (field->flags & GET_FIXED_FIELDS_FLAG)
- no_fields++;
+ num_fields++;
}
- if (no_fields == 0)
+ if (num_fields > MAX_REF_PARTS)
+ {
+ char *ptr;
+ if (is_sub_part)
+ ptr= (char*)"subpartition function";
+ else
+ ptr= (char*)"partition function";
+ my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), ptr);
+ DBUG_RETURN(TRUE);
+ }
+ if (num_fields == 0)
{
/*
We are using hidden key as partitioning field
@@ -473,8 +522,8 @@ static bool set_up_field_array(TABLE *table,
DBUG_ASSERT(!is_sub_part);
DBUG_RETURN(result);
}
- size_field_array= (no_fields+1)*sizeof(Field*);
- field_array= (Field**)sql_alloc(size_field_array);
+ size_field_array= (num_fields+1)*sizeof(Field*);
+ field_array= (Field**)sql_calloc(size_field_array);
if (unlikely(!field_array))
{
mem_alloc_error(size_field_array);
@@ -489,7 +538,32 @@ static bool set_up_field_array(TABLE *table,
field->flags|= FIELD_IN_PART_FUNC_FLAG;
if (likely(!result))
{
- field_array[i++]= field;
+ if (!is_sub_part && part_info->column_list)
+ {
+ List_iterator<char> it(part_info->part_field_list);
+ char *field_name;
+
+ DBUG_ASSERT(num_fields == part_info->part_field_list.elements);
+ inx= 0;
+ do
+ {
+ field_name= it++;
+ if (!my_strcasecmp(system_charset_info,
+ field_name,
+ field->field_name))
+ break;
+ } while (++inx < num_fields);
+ if (inx == num_fields)
+ {
+ mem_alloc_error(1);
+ result= TRUE;
+ continue;
+ }
+ }
+ else
+ inx= i;
+ field_array[inx]= field;
+ i++;
/*
We check that the fields are proper. It is required for each
@@ -507,16 +581,16 @@ static bool set_up_field_array(TABLE *table,
}
}
}
- field_array[no_fields]= 0;
+ field_array[num_fields]= 0;
if (!is_sub_part)
{
part_info->part_field_array= field_array;
- part_info->no_part_fields= no_fields;
+ part_info->num_part_fields= num_fields;
}
else
{
part_info->subpart_field_array= field_array;
- part_info->no_subpart_fields= no_fields;
+ part_info->num_subpart_fields= num_fields;
}
DBUG_RETURN(result);
}
@@ -555,36 +629,36 @@ static bool create_full_part_field_array(THD *thd, TABLE *table,
if (!part_info->is_sub_partitioned())
{
part_info->full_part_field_array= part_info->part_field_array;
- part_info->no_full_part_fields= part_info->no_part_fields;
+ part_info->num_full_part_fields= part_info->num_part_fields;
}
else
{
Field *field, **field_array;
- uint no_part_fields=0, size_field_array;
+ uint num_part_fields=0, size_field_array;
ptr= table->field;
while ((field= *(ptr++)))
{
if (field->flags & FIELD_IN_PART_FUNC_FLAG)
- no_part_fields++;
+ num_part_fields++;
}
- size_field_array= (no_part_fields+1)*sizeof(Field*);
- field_array= (Field**)sql_alloc(size_field_array);
+ size_field_array= (num_part_fields+1)*sizeof(Field*);
+ field_array= (Field**)sql_calloc(size_field_array);
if (unlikely(!field_array))
{
mem_alloc_error(size_field_array);
result= TRUE;
goto end;
}
- no_part_fields= 0;
+ num_part_fields= 0;
ptr= table->field;
while ((field= *(ptr++)))
{
if (field->flags & FIELD_IN_PART_FUNC_FLAG)
- field_array[no_part_fields++]= field;
+ field_array[num_part_fields++]= field;
}
- field_array[no_part_fields]=0;
+ field_array[num_part_fields]=0;
part_info->full_part_field_array= field_array;
- part_info->no_full_part_fields= no_part_fields;
+ part_info->num_full_part_fields= num_part_fields;
}
/*
@@ -780,16 +854,16 @@ static bool handle_list_of_fields(List_iterator<char> it,
goto end;
}
}
- if (is_list_empty)
+ if (is_list_empty && part_info->part_type == HASH_PARTITION)
{
uint primary_key= table->s->primary_key;
if (primary_key != MAX_KEY)
{
- uint no_key_parts= table->key_info[primary_key].key_parts, i;
+ uint num_key_parts= table->key_info[primary_key].key_parts, i;
/*
In the case of an empty list we use primary key as partition key.
*/
- for (i= 0; i < no_key_parts; i++)
+ for (i= 0; i < num_key_parts; i++)
{
Field *field= table->key_info[primary_key].key_part[i].field;
field->flags|= GET_FIXED_FIELDS_FLAG;
@@ -853,11 +927,90 @@ int check_signed_flag(partition_info *part_info)
error= ER_PARTITION_CONST_DOMAIN_ERROR;
break;
}
- } while (++i < part_info->no_parts);
+ } while (++i < part_info->num_parts);
}
return error;
}
+/**
+ Initialize lex object for use in fix_fields and parsing.
+
+ SYNOPSIS
+ init_lex_with_single_table()
+ @param thd The thread object
+ @param table The table object
+ @return Operation status
+ @retval TRUE An error occurred, memory allocation error
+ @retval FALSE Ok
+
+ DESCRIPTION
+ This function is used to initialize a lex object on the
+ stack for use by fix_fields and for parsing. In order to
+ work properly it also needs to initialize the
+ Name_resolution_context object of the lexer.
+ Finally it needs to set a couple of variables to ensure
+ proper functioning of fix_fields.
+*/
+
+static int
+init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex)
+{
+ TABLE_LIST *table_list;
+ Table_ident *table_ident;
+ SELECT_LEX *select_lex= &lex->select_lex;
+ Name_resolution_context *context= &select_lex->context;
+ /*
+ We will call the parser to create a part_info struct based on the
+ partition string stored in the frm file.
+ We will use a local lex object for this purpose. However we also
+ need to set the Name_resolution_object for this lex object. We
+ do this by using add_table_to_list where we add the table that
+ we're working with to the Name_resolution_context.
+ */
+ thd->lex= lex;
+ lex_start(thd);
+ context->init();
+ if ((!(table_ident= new Table_ident(thd,
+ table->s->table_name,
+ table->s->db, TRUE))) ||
+ (!(table_list= select_lex->add_table_to_list(thd,
+ table_ident,
+ NULL,
+ 0))))
+ return TRUE;
+ context->resolve_in_table_list_only(table_list);
+ lex->use_only_table_context= TRUE;
+ select_lex->cur_pos_in_select_list= UNDEF_POS;
+ table->map= 1; //To ensure correct calculation of const item
+ table->get_fields_in_item_tree= TRUE;
+ table_list->table= table;
+ return FALSE;
+}
+
+/**
+ End use of local lex with single table
+
+ SYNOPSIS
+ end_lex_with_single_table()
+ @param thd The thread object
+ @param table The table object
+ @param old_lex The real lex object connected to THD
+
+ DESCRIPTION
+ This function restores the real lex object after calling
+ init_lex_with_single_table and also restores some table
+ variables temporarily set.
+*/
+
+static void
+end_lex_with_single_table(THD *thd, TABLE *table, LEX *old_lex)
+{
+ LEX *lex= thd->lex;
+ table->map= 0;
+ table->get_fields_in_item_tree= FALSE;
+ lex_end(lex);
+ thd->lex= old_lex;
+}
/*
The function uses a new feature in fix_fields where the flag
@@ -872,7 +1025,6 @@ int check_signed_flag(partition_info *part_info)
table The table object
part_info Reference to partitioning data structure
is_sub_part Is the table subpartitioned as well
- is_field_to_be_setup Flag if we are to set-up field arrays
RETURN VALUE
TRUE An error occurred, something was wrong with the
@@ -895,66 +1047,22 @@ int check_signed_flag(partition_info *part_info)
on the field object.
*/
-bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
- bool is_sub_part, bool is_field_to_be_setup)
+static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
+ bool is_sub_part)
{
partition_info *part_info= table->part_info;
- uint dir_length, home_dir_length;
bool result= TRUE;
- TABLE_LIST tables;
- TABLE_LIST *save_table_list, *save_first_table, *save_last_table;
int error;
- Name_resolution_context *context;
const char *save_where;
- char* db_name;
- char db_name_string[FN_REFLEN];
- bool save_use_only_table_context;
+ LEX *old_lex= thd->lex;
+ LEX lex;
DBUG_ENTER("fix_fields_part_func");
- if (part_info->fixed)
- {
- if (!(is_sub_part || (error= check_signed_flag(part_info))))
- result= FALSE;
+ if (init_lex_with_single_table(thd, table, &lex))
goto end;
- }
- /*
- Set-up the TABLE_LIST object to be a list with a single table
- Set the object to zero to create NULL pointers and set alias
- and real name to table name and get database name from file name.
- TODO: Consider generalizing or refactoring Lex::add_table_to_list() so
- it can be used in all places where we create TABLE_LIST objects.
- Also consider creating appropriate constructors for TABLE_LIST.
- */
-
- bzero((void*)&tables, sizeof(TABLE_LIST));
- tables.alias= tables.table_name= (char*) table->s->table_name.str;
- tables.table= table;
- tables.next_local= 0;
- tables.next_name_resolution_table= 0;
- /*
- Cache the table in Item_fields. All the tables can be cached except
- the trigger pseudo table.
- */
- tables.cacheable_table= TRUE;
- context= thd->lex->current_context();
- tables.select_lex= context->select_lex;
- strmov(db_name_string, table->s->normalized_path.str);
- dir_length= dirname_length(db_name_string);
- db_name_string[dir_length - 1]= 0;
- home_dir_length= dirname_length(db_name_string);
- db_name= &db_name_string[home_dir_length];
- tables.db= db_name;
-
- table->map= 1; //To ensure correct calculation of const item
- table->get_fields_in_item_tree= TRUE;
- save_table_list= context->table_list;
- save_first_table= context->first_name_resolution_table;
- save_last_table= context->last_name_resolution_table;
- context->table_list= &tables;
- context->first_name_resolution_table= &tables;
- context->last_name_resolution_table= NULL;
- func_expr->walk(&Item::change_context_processor, 0, (uchar*) context);
+ func_expr->walk(&Item::change_context_processor, 0,
+ (uchar*) &lex.select_lex.context);
save_where= thd->where;
thd->where= "partition function";
/*
@@ -969,31 +1077,18 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
that does this during val_int must be disallowed as partition
function.
SEE Bug #21658
- */
- /*
+
This is a tricky call to prepare for since it can have a large number
of interesting side effects, both desirable and undesirable.
*/
-
- save_use_only_table_context= thd->lex->use_only_table_context;
- thd->lex->use_only_table_context= TRUE;
- thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
-
error= func_expr->fix_fields(thd, (Item**)&func_expr);
- thd->lex->use_only_table_context= save_use_only_table_context;
-
- context->table_list= save_table_list;
- context->first_name_resolution_table= save_first_table;
- context->last_name_resolution_table= save_last_table;
if (unlikely(error))
{
DBUG_PRINT("info", ("Field in partition function not part of table"));
- if (is_field_to_be_setup)
- clear_field_flag(table);
+ clear_field_flag(table);
goto end;
}
- thd->where= save_where;
if (unlikely(func_expr->const_item()))
{
my_error(ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
@@ -1002,14 +1097,13 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
}
if ((!is_sub_part) && (error= check_signed_flag(part_info)))
goto end;
- result= FALSE;
- if (is_field_to_be_setup)
- result= set_up_field_array(table, is_sub_part);
- if (!is_sub_part)
- part_info->fixed= TRUE;
+ result= set_up_field_array(table, is_sub_part);
end:
- table->get_fields_in_item_tree= FALSE;
- table->map= 0; //Restore old value
+ end_lex_with_single_table(thd, table, old_lex);
+#if !defined(DBUG_OFF)
+ func_expr->walk(&Item::change_context_processor, 0,
+ (uchar*) 0);
+#endif
DBUG_RETURN(result);
}
@@ -1185,9 +1279,9 @@ void check_range_capable_PF(TABLE *table)
static bool set_up_partition_bitmap(THD *thd, partition_info *part_info)
{
uint32 *bitmap_buf;
- uint bitmap_bits= part_info->no_subparts?
- (part_info->no_subparts* part_info->no_parts):
- part_info->no_parts;
+ uint bitmap_bits= part_info->num_subparts?
+ (part_info->num_subparts* part_info->num_parts):
+ part_info->num_parts;
uint bitmap_bytes= bitmap_buffer_size(bitmap_bits);
DBUG_ENTER("set_up_partition_bitmap");
@@ -1287,64 +1381,47 @@ static void set_up_partition_func_pointers(partition_info *part_info)
if (part_info->is_sub_partitioned())
{
+ part_info->get_partition_id= get_partition_id_with_sub;
if (part_info->part_type == RANGE_PARTITION)
{
- part_info->get_part_partition_id= get_partition_id_range;
+ if (part_info->column_list)
+ part_info->get_part_partition_id= get_partition_id_range_col;
+ else
+ part_info->get_part_partition_id= get_partition_id_range;
if (part_info->list_of_subpart_fields)
{
if (part_info->linear_hash_ind)
- {
- part_info->get_partition_id= get_partition_id_range_sub_linear_key;
part_info->get_subpartition_id= get_partition_id_linear_key_sub;
- }
else
- {
- part_info->get_partition_id= get_partition_id_range_sub_key;
part_info->get_subpartition_id= get_partition_id_key_sub;
- }
}
else
{
if (part_info->linear_hash_ind)
- {
- part_info->get_partition_id= get_partition_id_range_sub_linear_hash;
part_info->get_subpartition_id= get_partition_id_linear_hash_sub;
- }
else
- {
- part_info->get_partition_id= get_partition_id_range_sub_hash;
part_info->get_subpartition_id= get_partition_id_hash_sub;
- }
}
}
else /* LIST Partitioning */
{
- part_info->get_part_partition_id= get_partition_id_list;
+ if (part_info->column_list)
+ part_info->get_part_partition_id= get_partition_id_list_col;
+ else
+ part_info->get_part_partition_id= get_partition_id_list;
if (part_info->list_of_subpart_fields)
{
if (part_info->linear_hash_ind)
- {
- part_info->get_partition_id= get_partition_id_list_sub_linear_key;
part_info->get_subpartition_id= get_partition_id_linear_key_sub;
- }
else
- {
- part_info->get_partition_id= get_partition_id_list_sub_key;
part_info->get_subpartition_id= get_partition_id_key_sub;
- }
}
else
{
if (part_info->linear_hash_ind)
- {
- part_info->get_partition_id= get_partition_id_list_sub_linear_hash;
part_info->get_subpartition_id= get_partition_id_linear_hash_sub;
- }
else
- {
- part_info->get_partition_id= get_partition_id_list_sub_hash;
part_info->get_subpartition_id= get_partition_id_hash_sub;
- }
}
}
}
@@ -1353,9 +1430,19 @@ static void set_up_partition_func_pointers(partition_info *part_info)
part_info->get_part_partition_id= NULL;
part_info->get_subpartition_id= NULL;
if (part_info->part_type == RANGE_PARTITION)
- part_info->get_partition_id= get_partition_id_range;
+ {
+ if (part_info->column_list)
+ part_info->get_partition_id= get_partition_id_range_col;
+ else
+ part_info->get_partition_id= get_partition_id_range;
+ }
else if (part_info->part_type == LIST_PARTITION)
- part_info->get_partition_id= get_partition_id_list;
+ {
+ if (part_info->column_list)
+ part_info->get_partition_id= get_partition_id_list_col;
+ else
+ part_info->get_partition_id= get_partition_id_list;
+ }
else /* HASH partitioning */
{
if (part_info->list_of_part_fields)
@@ -1374,32 +1461,43 @@ static void set_up_partition_func_pointers(partition_info *part_info)
}
}
}
- if (part_info->full_part_charset_field_array)
- {
- DBUG_ASSERT(part_info->get_partition_id);
- part_info->get_partition_id_charset= part_info->get_partition_id;
- if (part_info->part_charset_field_array &&
- part_info->subpart_charset_field_array)
- part_info->get_partition_id= get_part_id_charset_func_all;
- else if (part_info->part_charset_field_array)
- part_info->get_partition_id= get_part_id_charset_func_part;
- else
- part_info->get_partition_id= get_part_id_charset_func_subpart;
- }
- if (part_info->part_charset_field_array &&
- part_info->is_sub_partitioned())
+ /*
+ We need special functions to handle character sets since they require copy
+ of field pointers and restore afterwards. For subpartitioned tables we do
+ the copy and restore individually on the part and subpart parts. For non-
+ subpartitioned tables we use the same functions as used for the parts part
+ of subpartioning.
+ Thus for subpartitioned tables the get_partition_id is always
+ get_partition_id_with_sub, even when character sets exists.
+ */
+ if (part_info->part_charset_field_array)
{
- DBUG_ASSERT(part_info->get_part_partition_id);
- part_info->get_part_partition_id_charset=
+ if (part_info->is_sub_partitioned())
+ {
+ DBUG_ASSERT(part_info->get_part_partition_id);
+ if (!part_info->column_list)
+ {
+ part_info->get_part_partition_id_charset=
part_info->get_part_partition_id;
- part_info->get_part_partition_id= get_part_part_id_charset_func;
+ part_info->get_part_partition_id= get_part_id_charset_func_part;
+ }
+ }
+ else
+ {
+ DBUG_ASSERT(part_info->get_partition_id);
+ if (!part_info->column_list)
+ {
+ part_info->get_part_partition_id_charset= part_info->get_partition_id;
+ part_info->get_part_partition_id= get_part_id_charset_func_part;
+ }
+ }
}
if (part_info->subpart_charset_field_array)
{
DBUG_ASSERT(part_info->get_subpartition_id);
part_info->get_subpartition_id_charset=
part_info->get_subpartition_id;
- part_info->get_subpartition_id= get_subpart_id_charset_func;
+ part_info->get_subpartition_id= get_part_id_charset_func_subpart;
}
DBUG_VOID_RETURN;
}
@@ -1407,22 +1505,22 @@ static void set_up_partition_func_pointers(partition_info *part_info)
/*
For linear hashing we need a mask which is on the form 2**n - 1 where
- 2**n >= no_parts. Thus if no_parts is 6 then mask is 2**3 - 1 = 8 - 1 = 7.
+ 2**n >= num_parts. Thus if num_parts is 6 then mask is 2**3 - 1 = 8 - 1 = 7.
SYNOPSIS
set_linear_hash_mask()
part_info Reference to partitioning data structure
- no_parts Number of parts in linear hash partitioning
+ num_parts Number of parts in linear hash partitioning
RETURN VALUE
NONE
*/
-void set_linear_hash_mask(partition_info *part_info, uint no_parts)
+void set_linear_hash_mask(partition_info *part_info, uint num_parts)
{
uint mask;
- for (mask= 1; mask < no_parts; mask<<=1)
+ for (mask= 1; mask < num_parts; mask<<=1)
;
part_info->linear_hash_mask= mask - 1;
}
@@ -1436,7 +1534,7 @@ void set_linear_hash_mask(partition_info *part_info, uint no_parts)
get_part_id_from_linear_hash()
hash_value Hash value calculated by HASH function or KEY function
mask Mask calculated previously by set_linear_hash_mask
- no_parts Number of partitions in HASH partitioned part
+ num_parts Number of partitions in HASH partitioned part
RETURN VALUE
part_id The calculated partition identity (starting at 0)
@@ -1449,11 +1547,11 @@ void set_linear_hash_mask(partition_info *part_info, uint no_parts)
*/
static uint32 get_part_id_from_linear_hash(longlong hash_value, uint mask,
- uint no_parts)
+ uint num_parts)
{
uint32 part_id= (uint32)(hash_value & mask);
- if (part_id >= no_parts)
+ if (part_id >= num_parts)
{
uint new_mask= ((mask + 1) >> 1) - 1;
part_id= (uint32)(hash_value & new_mask);
@@ -1597,7 +1695,7 @@ bool fix_partition_func(THD *thd, TABLE *table,
function is correct.
*/
if (part_info->linear_hash_ind)
- set_linear_hash_mask(part_info, part_info->no_subparts);
+ set_linear_hash_mask(part_info, part_info->num_subparts);
if (part_info->list_of_subpart_fields)
{
List_iterator<char> it(part_info->subpart_field_list);
@@ -1607,12 +1705,12 @@ bool fix_partition_func(THD *thd, TABLE *table,
else
{
if (unlikely(fix_fields_part_func(thd, part_info->subpart_expr,
- table, TRUE, TRUE)))
+ table, TRUE)))
goto end;
if (unlikely(part_info->subpart_expr->result_type() != INT_RESULT))
{
- my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0),
- "SUBPARTITION");
+ my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0),
+ subpart_str);
goto end;
}
}
@@ -1625,7 +1723,7 @@ bool fix_partition_func(THD *thd, TABLE *table,
if (part_info->part_type == HASH_PARTITION)
{
if (part_info->linear_hash_ind)
- set_linear_hash_mask(part_info, part_info->no_parts);
+ set_linear_hash_mask(part_info, part_info->num_parts);
if (part_info->list_of_part_fields)
{
List_iterator<char> it(part_info->part_field_list);
@@ -1635,32 +1733,43 @@ bool fix_partition_func(THD *thd, TABLE *table,
else
{
if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
- table, FALSE, TRUE)))
+ table, FALSE)))
goto end;
if (unlikely(part_info->part_expr->result_type() != INT_RESULT))
{
- my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), part_str);
+ my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0), part_str);
goto end;
}
part_info->part_result_type= INT_RESULT;
}
+ part_info->fixed= TRUE;
}
else
{
const char *error_str;
- if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
- table, FALSE, TRUE)))
- goto end;
+ if (part_info->column_list)
+ {
+ List_iterator<char> it(part_info->part_field_list);
+ if (unlikely(handle_list_of_fields(it, table, part_info, FALSE)))
+ goto end;
+ }
+ else
+ {
+ if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
+ table, FALSE)))
+ goto end;
+ }
+ part_info->fixed= TRUE;
if (part_info->part_type == RANGE_PARTITION)
{
error_str= partition_keywords[PKW_RANGE].str;
- if (unlikely(part_info->check_range_constants()))
+ if (unlikely(part_info->check_range_constants(thd)))
goto end;
}
else if (part_info->part_type == LIST_PARTITION)
{
error_str= partition_keywords[PKW_LIST].str;
- if (unlikely(part_info->check_list_constants()))
+ if (unlikely(part_info->check_list_constants(thd)))
goto end;
}
else
@@ -1669,12 +1778,13 @@ bool fix_partition_func(THD *thd, TABLE *table,
my_error(ER_INCONSISTENT_PARTITION_INFO_ERROR, MYF(0));
goto end;
}
- if (unlikely(part_info->no_parts < 1))
+ if (unlikely(part_info->num_parts < 1))
{
my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_str);
goto end;
}
- if (unlikely(part_info->part_expr->result_type() != INT_RESULT))
+ if (unlikely(!part_info->column_list &&
+ part_info->part_expr->result_type() != INT_RESULT))
{
my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), part_str);
goto end;
@@ -1682,7 +1792,8 @@ bool fix_partition_func(THD *thd, TABLE *table,
}
if (((part_info->part_type != HASH_PARTITION ||
part_info->list_of_part_fields == FALSE) &&
- check_part_func_fields(part_info->part_field_array, TRUE)) ||
+ (!part_info->column_list &&
+ check_part_func_fields(part_info->part_field_array, TRUE))) ||
(part_info->list_of_part_fields == FALSE &&
part_info->is_sub_partitioned() &&
check_part_func_fields(part_info->subpart_field_array, TRUE)))
@@ -1705,6 +1816,11 @@ bool fix_partition_func(THD *thd, TABLE *table,
my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
goto end;
}
+ if (unlikely(part_info->check_partition_field_length()))
+ {
+ my_error(ER_PARTITION_FIELDS_TOO_LONG, MYF(0));
+ goto end;
+ }
check_range_capable_PF(table);
set_up_partition_key_maps(table, part_info);
set_up_partition_func_pointers(part_info);
@@ -1727,9 +1843,9 @@ end:
static int add_write(File fptr, const char *buf, uint len)
{
- uint len_written= my_write(fptr, (const uchar*)buf, len, MYF(0));
+ uint ret_code= my_write(fptr, (const uchar*)buf, len, MYF(MY_FNABP));
- if (likely(len == len_written))
+ if (likely(ret_code == 0))
return 0;
else
return 1;
@@ -1778,14 +1894,8 @@ static int add_begin_parenthesis(File fptr)
static int add_part_key_word(File fptr, const char *key_string)
{
int err= add_string(fptr, key_string);
-
err+= add_space(fptr);
- return err + add_begin_parenthesis(fptr);
-}
-
-static int add_hash(File fptr)
-{
- return add_part_key_word(fptr, partition_keywords[PKW_HASH].str);
+ return err;
}
static int add_partition(File fptr)
@@ -1816,16 +1926,16 @@ static int add_subpartition_by(File fptr)
return err + add_partition_by(fptr);
}
-static int add_key_partition(File fptr, List<char> field_list)
+static int add_part_field_list(File fptr, List<char> field_list)
{
- uint i, no_fields;
- int err;
+ uint i, num_fields;
+ int err= 0;
List_iterator<char> part_it(field_list);
- err= add_part_key_word(fptr, partition_keywords[PKW_KEY].str);
- no_fields= field_list.elements;
+ num_fields= field_list.elements;
i= 0;
- while (i < no_fields)
+ err+= add_begin_parenthesis(fptr);
+ while (i < num_fields)
{
const char *field_str= part_it++;
String field_string("", 0, system_charset_info);
@@ -1836,10 +1946,11 @@ static int add_key_partition(File fptr, List<char> field_list)
strlen(field_str));
thd->options= save_options;
err+= add_string_object(fptr, &field_string);
- if (i != (no_fields-1))
+ if (i != (num_fields-1))
err+= add_comma(fptr);
i++;
}
+ err+= add_end_parenthesis(fptr);
return err;
}
@@ -1949,37 +2060,269 @@ static int add_partition_options(File fptr, partition_element *p_elem)
return err + add_engine(fptr,p_elem->engine_type);
}
-static int add_partition_values(File fptr, partition_info *part_info, partition_element *p_elem)
+
+/*
+ Check partition fields for result type and if they need
+ to check the character set.
+
+ SYNOPSIS
+ check_part_field()
+ sql_type Type provided by user
+ field_name Name of field, used for error handling
+ result_type Out value: Result type of field
+ need_cs_check Out value: Do we need character set check
+
+ RETURN VALUES
+ TRUE Error
+ FALSE Ok
+*/
+
+static int check_part_field(enum_field_types sql_type,
+ const char *field_name,
+ Item_result *result_type,
+ bool *need_cs_check)
+{
+ if (sql_type >= MYSQL_TYPE_TINY_BLOB &&
+ sql_type <= MYSQL_TYPE_BLOB)
+ {
+ my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0));
+ return TRUE;
+ }
+ switch (sql_type)
+ {
+ case MYSQL_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ *result_type= INT_RESULT;
+ *need_cs_check= FALSE;
+ return FALSE;
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ *result_type= STRING_RESULT;
+ *need_cs_check= TRUE;
+ return FALSE;
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_VAR_STRING:
+ *result_type= STRING_RESULT;
+ *need_cs_check= TRUE;
+ return FALSE;
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_NULL:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_GEOMETRY:
+ goto error;
+ default:
+ goto error;
+ }
+error:
+ my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0),
+ field_name);
+ return TRUE;
+}
+
+
+/*
+ Find the given field's Create_field object using name of field
+
+ SYNOPSIS
+ get_sql_field()
+ field_name Field name
+ alter_info Info from ALTER TABLE/CREATE TABLE
+
+ RETURN VALUE
+ sql_field Object filled in by parser about field
+ NULL No field found
+*/
+
+static Create_field* get_sql_field(char *field_name,
+ Alter_info *alter_info)
+{
+ List_iterator<Create_field> it(alter_info->create_list);
+ Create_field *sql_field;
+ DBUG_ENTER("get_sql_field");
+
+ while ((sql_field= it++))
+ {
+ if (!(my_strcasecmp(system_charset_info,
+ sql_field->field_name,
+ field_name)))
+ {
+ DBUG_RETURN(sql_field);
+ }
+ }
+ DBUG_RETURN(NULL);
+}
+
+
+static int add_column_list_values(File fptr, partition_info *part_info,
+ part_elem_value *list_value,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info)
+{
+ int err= 0;
+ uint i;
+ List_iterator<char> it(part_info->part_field_list);
+ uint num_elements= part_info->part_field_list.elements;
+ bool use_parenthesis= (part_info->part_type == LIST_PARTITION &&
+ part_info->num_columns > 1U);
+
+ if (use_parenthesis)
+ err+= add_begin_parenthesis(fptr);
+ for (i= 0; i < num_elements; i++)
+ {
+ part_column_list_val *col_val= &list_value->col_val_array[i];
+ char *field_name= it++;
+ if (col_val->max_value)
+ err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str);
+ else if (col_val->null_value)
+ err+= add_string(fptr, "NULL");
+ else
+ {
+ char buffer[MAX_KEY_LENGTH];
+ String str(buffer, sizeof(buffer), &my_charset_bin);
+ Item *item_expr= col_val->item_expression;
+ if (item_expr->null_value)
+ err+= add_string(fptr, "NULL");
+ else
+ {
+ String *res;
+ CHARSET_INFO *field_cs;
+ bool need_cs_check= FALSE;
+ Item_result result_type= STRING_RESULT;
+
+ /*
+ This function is called at a very early stage, even before
+ we have prepared the sql_field objects. Thus we have to
+ find the proper sql_field object and get the character set
+ from that object.
+ */
+ if (create_info)
+ {
+ Create_field *sql_field;
+
+ if (!(sql_field= get_sql_field(field_name,
+ alter_info)))
+ {
+ my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
+ return 1;
+ }
+ if (check_part_field(sql_field->sql_type,
+ sql_field->field_name,
+ &result_type,
+ &need_cs_check))
+ return 1;
+ if (need_cs_check)
+ field_cs= get_sql_field_charset(sql_field, create_info);
+ else
+ field_cs= NULL;
+ }
+ else
+ {
+ Field *field= part_info->part_field_array[i];
+ result_type= field->result_type();
+ if (check_part_field(field->real_type(),
+ field->field_name,
+ &result_type,
+ &need_cs_check))
+ return 1;
+ DBUG_ASSERT(result_type == field->result_type());
+ if (need_cs_check)
+ field_cs= field->charset();
+ else
+ field_cs= NULL;
+ }
+ if (result_type != item_expr->result_type())
+ {
+ my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
+ return 1;
+ }
+ if (field_cs && field_cs != item_expr->collation.collation)
+ {
+ if (!(item_expr= convert_charset_partition_constant(item_expr,
+ field_cs)))
+ {
+ my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
+ return 1;
+ }
+ }
+ {
+ String val_conv;
+ val_conv.set_charset(system_charset_info);
+ res= item_expr->val_str(&str);
+ if (get_cs_converted_part_value_from_string(current_thd,
+ item_expr, res,
+ &val_conv, field_cs,
+ (bool)(alter_info != NULL)))
+ return 1;
+ err+= add_string_object(fptr, &val_conv);
+ }
+ }
+ }
+ if (i != (num_elements - 1))
+ err+= add_string(fptr, comma_str);
+ }
+ if (use_parenthesis)
+ err+= add_end_parenthesis(fptr);
+ return err;
+}
+
+static int add_partition_values(File fptr, partition_info *part_info,
+ partition_element *p_elem,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info)
{
int err= 0;
if (part_info->part_type == RANGE_PARTITION)
{
err+= add_string(fptr, " VALUES LESS THAN ");
- if (!p_elem->max_value)
+ if (part_info->column_list)
{
+ List_iterator<part_elem_value> list_val_it(p_elem->list_val_list);
+ part_elem_value *list_value= list_val_it++;
err+= add_begin_parenthesis(fptr);
- if (p_elem->signed_flag)
- err+= add_int(fptr, p_elem->range_value);
- else
- err+= add_uint(fptr, p_elem->range_value);
+ err+= add_column_list_values(fptr, part_info, list_value,
+ create_info, alter_info);
err+= add_end_parenthesis(fptr);
}
else
- err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str);
+ {
+ if (!p_elem->max_value)
+ {
+ err+= add_begin_parenthesis(fptr);
+ if (p_elem->signed_flag)
+ err+= add_int(fptr, p_elem->range_value);
+ else
+ err+= add_uint(fptr, p_elem->range_value);
+ err+= add_end_parenthesis(fptr);
+ }
+ else
+ err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str);
+ }
}
else if (part_info->part_type == LIST_PARTITION)
{
uint i;
List_iterator<part_elem_value> list_val_it(p_elem->list_val_list);
err+= add_string(fptr, " VALUES IN ");
- uint no_items= p_elem->list_val_list.elements;
+ uint num_items= p_elem->list_val_list.elements;
err+= add_begin_parenthesis(fptr);
if (p_elem->has_null_value)
{
err+= add_string(fptr, "NULL");
- if (no_items == 0)
+ if (num_items == 0)
{
err+= add_end_parenthesis(fptr);
goto end;
@@ -1991,13 +2334,19 @@ static int add_partition_values(File fptr, partition_info *part_info, partition_
{
part_elem_value *list_value= list_val_it++;
- if (!list_value->unsigned_flag)
- err+= add_int(fptr, list_value->value);
+ if (part_info->column_list)
+ err+= add_column_list_values(fptr, part_info, list_value,
+ create_info, alter_info);
else
- err+= add_uint(fptr, list_value->value);
- if (i != (no_items-1))
+ {
+ if (!list_value->unsigned_flag)
+ err+= add_int(fptr, list_value->value);
+ else
+ err+= add_uint(fptr, list_value->value);
+ }
+ if (i != (num_items-1))
err+= add_comma(fptr);
- } while (++i < no_items);
+ } while (++i < num_items);
err+= add_end_parenthesis(fptr);
}
end:
@@ -2016,6 +2365,8 @@ end:
use_sql_alloc Allocate buffer from sql_alloc if true
otherwise use my_malloc
show_partition_options Should we display partition options
+ create_info Info generated by parser
+ alter_info Info generated by parser
RETURN VALUES
NULL error
@@ -2044,9 +2395,11 @@ end:
char *generate_partition_syntax(partition_info *part_info,
uint *buf_length,
bool use_sql_alloc,
- bool show_partition_options)
+ bool show_partition_options,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info)
{
- uint i,j, tot_no_parts, no_subparts;
+ uint i,j, tot_num_parts, num_subparts;
partition_element *part_elem;
ulonglong buffer_length;
char path[FN_REFLEN];
@@ -2077,9 +2430,12 @@ char *generate_partition_syntax(partition_info *part_info,
if (part_info->linear_hash_ind)
err+= add_string(fptr, partition_keywords[PKW_LINEAR].str);
if (part_info->list_of_part_fields)
- err+= add_key_partition(fptr, part_info->part_field_list);
+ {
+ err+= add_part_key_word(fptr, partition_keywords[PKW_KEY].str);
+ err+= add_part_field_list(fptr, part_info->part_field_list);
+ }
else
- err+= add_hash(fptr);
+ err+= add_part_key_word(fptr, partition_keywords[PKW_HASH].str);
break;
default:
DBUG_ASSERT(0);
@@ -2089,15 +2445,23 @@ char *generate_partition_syntax(partition_info *part_info,
DBUG_RETURN(NULL);
}
if (part_info->part_expr)
+ {
+ err+= add_begin_parenthesis(fptr);
err+= add_string_len(fptr, part_info->part_func_string,
part_info->part_func_len);
- err+= add_end_parenthesis(fptr);
- if ((!part_info->use_default_no_partitions) &&
+ err+= add_end_parenthesis(fptr);
+ }
+ else if (part_info->column_list)
+ {
+ err+= add_string(fptr, partition_keywords[PKW_COLUMNS].str);
+ err+= add_part_field_list(fptr, part_info->part_field_list);
+ }
+ if ((!part_info->use_default_num_partitions) &&
part_info->use_default_partitions)
{
err+= add_string(fptr, "\n");
err+= add_string(fptr, "PARTITIONS ");
- err+= add_int(fptr, part_info->no_parts);
+ err+= add_int(fptr, part_info->num_parts);
}
if (part_info->is_sub_partitioned())
{
@@ -2107,23 +2471,29 @@ char *generate_partition_syntax(partition_info *part_info,
if (part_info->linear_hash_ind)
err+= add_string(fptr, partition_keywords[PKW_LINEAR].str);
if (part_info->list_of_subpart_fields)
- err+= add_key_partition(fptr, part_info->subpart_field_list);
+ {
+ add_part_key_word(fptr, partition_keywords[PKW_KEY].str);
+ add_part_field_list(fptr, part_info->subpart_field_list);
+ }
else
- err+= add_hash(fptr);
+ err+= add_part_key_word(fptr, partition_keywords[PKW_HASH].str);
if (part_info->subpart_expr)
+ {
+ err+= add_begin_parenthesis(fptr);
err+= add_string_len(fptr, part_info->subpart_func_string,
part_info->subpart_func_len);
- err+= add_end_parenthesis(fptr);
- if ((!part_info->use_default_no_subpartitions) &&
+ err+= add_end_parenthesis(fptr);
+ }
+ if ((!part_info->use_default_num_subpartitions) &&
part_info->use_default_subpartitions)
{
err+= add_string(fptr, "\n");
err+= add_string(fptr, "SUBPARTITIONS ");
- err+= add_int(fptr, part_info->no_subparts);
+ err+= add_int(fptr, part_info->num_subparts);
}
}
- tot_no_parts= part_info->partitions.elements;
- no_subparts= part_info->no_subparts;
+ tot_num_parts= part_info->partitions.elements;
+ num_subparts= part_info->num_subparts;
if (!part_info->use_default_partitions)
{
@@ -2146,7 +2516,8 @@ char *generate_partition_syntax(partition_info *part_info,
first= FALSE;
err+= add_partition(fptr);
err+= add_name_string(fptr, part_elem->partition_name);
- err+= add_partition_values(fptr, part_info, part_elem);
+ err+= add_partition_values(fptr, part_info, part_elem,
+ create_info, alter_info);
if (!part_info->is_sub_partitioned() ||
part_info->use_default_subpartitions)
{
@@ -2167,7 +2538,7 @@ char *generate_partition_syntax(partition_info *part_info,
err+= add_name_string(fptr, part_elem->partition_name);
if (show_partition_options)
err+= add_partition_options(fptr, part_elem);
- if (j != (no_subparts-1))
+ if (j != (num_subparts-1))
{
err+= add_comma(fptr);
err+= add_string(fptr, "\n");
@@ -2176,12 +2547,12 @@ char *generate_partition_syntax(partition_info *part_info,
}
else
err+= add_end_parenthesis(fptr);
- } while (++j < no_subparts);
+ } while (++j < num_subparts);
}
}
- if (i == (tot_no_parts-1))
+ if (i == (tot_num_parts-1))
err+= add_end_parenthesis(fptr);
- } while (++i < tot_no_parts);
+ } while (++i < tot_num_parts);
}
if (err)
goto close_file;
@@ -2328,14 +2699,14 @@ static uint32 calculate_key_value(Field **field_array)
get_part_id_for_sub()
loc_part_id Local partition id
sub_part_id Subpartition id
- no_subparts Number of subparts
+ num_subparts Number of subparts
*/
inline
static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id,
- uint no_subparts)
+ uint num_subparts)
{
- return (uint32)((loc_part_id * no_subparts) + sub_part_id);
+ return (uint32)((loc_part_id * num_subparts) + sub_part_id);
}
@@ -2344,7 +2715,7 @@ static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id,
SYNOPSIS
get_part_id_hash()
- no_parts Number of hash partitions
+ num_parts Number of hash partitions
part_expr Item tree of hash function
out:part_id The returned partition id
out:func_value Value of hash function
@@ -2354,7 +2725,7 @@ static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id,
FALSE Success
*/
-static int get_part_id_hash(uint no_parts,
+static int get_part_id_hash(uint num_parts,
Item *part_expr,
uint32 *part_id,
longlong *func_value)
@@ -2365,7 +2736,7 @@ static int get_part_id_hash(uint no_parts,
if (part_val_int(part_expr, func_value))
DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
- int_hash_id= *func_value % no_parts;
+ int_hash_id= *func_value % num_parts;
*part_id= int_hash_id < 0 ? (uint32) -int_hash_id : (uint32) int_hash_id;
DBUG_RETURN(FALSE);
@@ -2379,7 +2750,7 @@ static int get_part_id_hash(uint no_parts,
get_part_id_linear_hash()
part_info A reference to the partition_info struct where all the
desired information is given
- no_parts Number of hash partitions
+ num_parts Number of hash partitions
part_expr Item tree of hash function
out:part_id The returned partition id
out:func_value Value of hash function
@@ -2390,7 +2761,7 @@ static int get_part_id_hash(uint no_parts,
*/
static int get_part_id_linear_hash(partition_info *part_info,
- uint no_parts,
+ uint num_parts,
Item *part_expr,
uint32 *part_id,
longlong *func_value)
@@ -2402,7 +2773,7 @@ static int get_part_id_linear_hash(partition_info *part_info,
*part_id= get_part_id_from_linear_hash(*func_value,
part_info->linear_hash_mask,
- no_parts);
+ num_parts);
DBUG_RETURN(FALSE);
}
@@ -2413,7 +2784,7 @@ static int get_part_id_linear_hash(partition_info *part_info,
SYNOPSIS
get_part_id_key()
field_array Array of fields for PARTTION KEY
- no_parts Number of KEY partitions
+ num_parts Number of KEY partitions
RETURN VALUE
Calculated partition id
@@ -2421,12 +2792,12 @@ static int get_part_id_linear_hash(partition_info *part_info,
inline
static uint32 get_part_id_key(Field **field_array,
- uint no_parts,
+ uint num_parts,
longlong *func_value)
{
DBUG_ENTER("get_part_id_key");
*func_value= calculate_key_value(field_array);
- DBUG_RETURN((uint32) (*func_value % no_parts));
+ DBUG_RETURN((uint32) (*func_value % num_parts));
}
@@ -2438,7 +2809,7 @@ static uint32 get_part_id_key(Field **field_array,
part_info A reference to the partition_info struct where all the
desired information is given
field_array Array of fields for PARTTION KEY
- no_parts Number of KEY partitions
+ num_parts Number of KEY partitions
RETURN VALUE
Calculated partition id
@@ -2447,15 +2818,15 @@ static uint32 get_part_id_key(Field **field_array,
inline
static uint32 get_part_id_linear_key(partition_info *part_info,
Field **field_array,
- uint no_parts,
+ uint num_parts,
longlong *func_value)
{
- DBUG_ENTER("get_partition_id_linear_key");
+ DBUG_ENTER("get_part_id_linear_key");
*func_value= calculate_key_value(field_array);
DBUG_RETURN(get_part_id_from_linear_hash(*func_value,
part_info->linear_hash_mask,
- no_parts));
+ num_parts));
}
/*
@@ -2489,7 +2860,8 @@ static void copy_to_part_field_buffers(Field **ptr,
if (!field->maybe_null() || !field->is_null())
{
CHARSET_INFO *cs= ((Field_str*)field)->charset();
- uint len= field->pack_length();
+ uint max_len= field->pack_length();
+ uint data_len= field->data_length();
uchar *field_buf= *field_bufs;
/*
We only use the field buffer for VARCHAR and CHAR strings
@@ -2501,17 +2873,17 @@ static void copy_to_part_field_buffers(Field **ptr,
if (field->type() == MYSQL_TYPE_VARCHAR)
{
uint len_bytes= ((Field_varstring*)field)->length_bytes;
- my_strnxfrm(cs, field_buf + len_bytes, (len - len_bytes),
- field->ptr + len_bytes, field->field_length);
+ my_strnxfrm(cs, field_buf + len_bytes, max_len,
+ field->ptr + len_bytes, data_len);
if (len_bytes == 1)
- *field_buf= (uchar) field->field_length;
+ *field_buf= (uchar) data_len;
else
- int2store(field_buf, field->field_length);
+ int2store(field_buf, data_len);
}
else
{
- my_strnxfrm(cs, field_buf, len,
- field->ptr, field->field_length);
+ my_strnxfrm(cs, field_buf, max_len,
+ field->ptr, max_len);
}
field->ptr= field_buf;
}
@@ -2541,6 +2913,44 @@ static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr)
return;
}
+/*
+ This function is used to calculate the partition id where all partition
+ fields have been prepared to point to a record where the partition field
+ values are bound.
+
+ SYNOPSIS
+ get_partition_id()
+ part_info A reference to the partition_info struct where all the
+ desired information is given
+ out:part_id The partition id is returned through this pointer
+ out:func_value Value of partition function (longlong)
+
+ RETURN VALUE
+ part_id Partition id of partition that would contain
+ row with given values of PF-fields
+ HA_ERR_NO_PARTITION_FOUND The fields of the partition function didn't
+ fit into any partition and thus the values of
+ the PF-fields are not allowed.
+
+ DESCRIPTION
+ A routine used from write_row, update_row and delete_row from any
+ handler supporting partitioning. It is also a support routine for
+ get_partition_set used to find the set of partitions needed to scan
+ for a certain index scan or full table scan.
+
+ It is actually 9 different variants of this function which are called
+ through a function pointer.
+
+ get_partition_id_list
+ get_partition_id_list_col
+ get_partition_id_range
+ get_partition_id_range_col
+ get_partition_id_hash_nosub
+ get_partition_id_key_nosub
+ get_partition_id_linear_hash_nosub
+ get_partition_id_linear_key_nosub
+ get_partition_id_with_sub
+*/
/*
This function is used to calculate the main partition to use in the case of
@@ -2562,67 +2972,26 @@ static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr)
DESCRIPTION
- It is actually 6 different variants of this function which are called
+ It is actually 8 different variants of this function which are called
through a function pointer.
get_partition_id_list
+ get_partition_id_list_col
get_partition_id_range
+ get_partition_id_range_col
get_partition_id_hash_nosub
get_partition_id_key_nosub
get_partition_id_linear_hash_nosub
get_partition_id_linear_key_nosub
*/
-static int get_part_id_charset_func_subpart(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- int res;
- copy_to_part_field_buffers(part_info->subpart_charset_field_array,
- part_info->subpart_field_buffers,
- part_info->restore_subpart_field_ptrs);
- res= part_info->get_partition_id_charset(part_info, part_id, func_value);
- restore_part_field_pointers(part_info->subpart_charset_field_array,
- part_info->restore_subpart_field_ptrs);
- return res;
-}
-
-
static int get_part_id_charset_func_part(partition_info *part_info,
uint32 *part_id,
longlong *func_value)
{
int res;
- copy_to_part_field_buffers(part_info->part_charset_field_array,
- part_info->part_field_buffers,
- part_info->restore_part_field_ptrs);
- res= part_info->get_partition_id_charset(part_info, part_id, func_value);
- restore_part_field_pointers(part_info->part_charset_field_array,
- part_info->restore_part_field_ptrs);
- return res;
-}
-
-
-static int get_part_id_charset_func_all(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- int res;
- copy_to_part_field_buffers(part_info->full_part_field_array,
- part_info->full_part_field_buffers,
- part_info->restore_full_part_field_ptrs);
- res= part_info->get_partition_id_charset(part_info, part_id, func_value);
- restore_part_field_pointers(part_info->full_part_field_array,
- part_info->restore_full_part_field_ptrs);
- return res;
-}
+ DBUG_ENTER("get_part_id_charset_func_part");
-
-static int get_part_part_id_charset_func(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- int res;
copy_to_part_field_buffers(part_info->part_charset_field_array,
part_info->part_field_buffers,
part_info->restore_part_field_ptrs);
@@ -2630,21 +2999,58 @@ static int get_part_part_id_charset_func(partition_info *part_info,
part_id, func_value);
restore_part_field_pointers(part_info->part_charset_field_array,
part_info->restore_part_field_ptrs);
- return res;
+ DBUG_RETURN(res);
}
-static int get_subpart_id_charset_func(partition_info *part_info,
- uint32 *part_id)
+static int get_part_id_charset_func_subpart(partition_info *part_info,
+ uint32 *part_id)
{
int res;
+ DBUG_ENTER("get_part_id_charset_func_subpart");
+
copy_to_part_field_buffers(part_info->subpart_charset_field_array,
part_info->subpart_field_buffers,
part_info->restore_subpart_field_ptrs);
res= part_info->get_subpartition_id_charset(part_info, part_id);
restore_part_field_pointers(part_info->subpart_charset_field_array,
part_info->restore_subpart_field_ptrs);
- return res;
+ DBUG_RETURN(res);
+}
+
+int get_partition_id_list_col(partition_info *part_info,
+ uint32 *part_id,
+ longlong *func_value)
+{
+ part_column_list_val *list_col_array= part_info->list_col_array;
+ uint num_columns= part_info->part_field_list.elements;
+ int list_index, cmp;
+ int min_list_index= 0;
+ int max_list_index= part_info->num_list_values - 1;
+ DBUG_ENTER("get_partition_id_list_col");
+
+ while (max_list_index >= min_list_index)
+ {
+ list_index= (max_list_index + min_list_index) >> 1;
+ cmp= cmp_rec_and_tuple(list_col_array + list_index*num_columns,
+ num_columns);
+ if (cmp > 0)
+ min_list_index= list_index + 1;
+ else if (cmp < 0)
+ {
+ if (!list_index)
+ goto notfound;
+ max_list_index= list_index - 1;
+ }
+ else
+ {
+ *part_id= (uint32)list_col_array[list_index].partition_id;
+ DBUG_RETURN(0);
+ }
+ }
+notfound:
+ *part_id= 0;
+ DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
}
@@ -2655,7 +3061,7 @@ int get_partition_id_list(partition_info *part_info,
LIST_PART_ENTRY *list_array= part_info->list_array;
int list_index;
int min_list_index= 0;
- int max_list_index= part_info->no_list_values - 1;
+ int max_list_index= part_info->num_list_values - 1;
longlong part_func_value;
int error= part_val_int(part_info->part_expr, &part_func_value);
longlong list_value;
@@ -2725,7 +3131,7 @@ notfound:
index idx.
The function returns first number idx, such that
list_array[idx].list_value is NOT contained within the passed interval.
- If all array elements are contained, part_info->no_list_values is
+ If all array elements are contained, part_info->num_list_values is
returned.
NOTE
@@ -2739,6 +3145,44 @@ notfound:
The edge of corresponding sub-array of part_info->list_array
*/
+uint32 get_partition_id_cols_list_for_endpoint(partition_info *part_info,
+ bool left_endpoint,
+ bool include_endpoint,
+ uint32 nparts)
+{
+ part_column_list_val *list_col_array= part_info->list_col_array;
+ uint num_columns= part_info->part_field_list.elements;
+ int list_index, cmp;
+ uint min_list_index= 0;
+ uint max_list_index= part_info->num_list_values - 1;
+ bool tailf= !(left_endpoint ^ include_endpoint);
+ DBUG_ENTER("get_partition_id_cols_list_for_endpoint");
+
+ do
+ {
+ list_index= (max_list_index + min_list_index) >> 1;
+ cmp= cmp_rec_and_tuple_prune(list_col_array + list_index*num_columns,
+ nparts, tailf);
+ if (cmp > 0)
+ min_list_index= list_index + 1;
+ else if (cmp < 0)
+ {
+ if (!list_index)
+ goto notfound;
+ max_list_index= list_index - 1;
+ }
+ else
+ {
+ DBUG_RETURN(list_index + test(!tailf));
+ }
+ } while (max_list_index >= min_list_index);
+ if (cmp > 0)
+ list_index++;
+notfound:
+ DBUG_RETURN(list_index);
+}
+
+
uint32 get_list_array_idx_for_endpoint_charset(partition_info *part_info,
bool left_endpoint,
bool include_endpoint)
@@ -2760,7 +3204,7 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
{
LIST_PART_ENTRY *list_array= part_info->list_array;
uint list_index;
- uint min_list_index= 0, max_list_index= part_info->no_list_values - 1;
+ uint min_list_index= 0, max_list_index= part_info->num_list_values - 1;
longlong list_value;
/* Get the partitioning function value for the endpoint */
longlong part_func_value=
@@ -2790,7 +3234,7 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
if (unsigned_flag)
part_func_value-= 0x8000000000000000ULL;
- DBUG_ASSERT(part_info->no_list_values);
+ DBUG_ASSERT(part_info->num_list_values);
do
{
list_index= (max_list_index + min_list_index) >> 1;
@@ -2815,12 +3259,49 @@ notfound:
}
+int get_partition_id_range_col(partition_info *part_info,
+ uint32 *part_id,
+ longlong *func_value)
+{
+ part_column_list_val *range_col_array= part_info->range_col_array;
+ uint num_columns= part_info->part_field_list.elements;
+ uint max_partition= part_info->num_parts - 1;
+ uint min_part_id= 0;
+ uint max_part_id= max_partition;
+ uint loc_part_id;
+ DBUG_ENTER("get_partition_id_range_col");
+
+ while (max_part_id > min_part_id)
+ {
+ loc_part_id= (max_part_id + min_part_id + 1) >> 1;
+ if (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns,
+ num_columns) >= 0)
+ min_part_id= loc_part_id + 1;
+ else
+ max_part_id= loc_part_id - 1;
+ }
+ loc_part_id= max_part_id;
+ if (loc_part_id != max_partition)
+ if (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns,
+ num_columns) >= 0)
+ loc_part_id++;
+ *part_id= (uint32)loc_part_id;
+ if (loc_part_id == max_partition &&
+ (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns,
+ num_columns) >= 0))
+ DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
+
+ 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)
{
longlong *range_array= part_info->range_int_array;
- uint max_partition= part_info->no_parts - 1;
+ uint max_partition= part_info->num_parts - 1;
uint min_part_id= 0;
uint max_part_id= max_partition;
uint loc_part_id;
@@ -2897,7 +3378,7 @@ int get_partition_id_range(partition_info *part_info,
represented by range_int_array[idx] has EMPTY intersection with the
passed interval.
If the interval represented by the last array element has non-empty
- intersection with the passed interval, part_info->no_parts is
+ intersection with the passed interval, part_info->num_parts is
returned.
RETURN
@@ -2925,7 +3406,7 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
bool include_endpoint)
{
longlong *range_array= part_info->range_int_array;
- uint max_partition= part_info->no_parts - 1;
+ uint max_partition= part_info->num_parts - 1;
uint min_part_id= 0, max_part_id= max_partition, loc_part_id;
/* Get the partitioning function value for the endpoint */
longlong part_func_value=
@@ -3008,7 +3489,7 @@ int get_partition_id_hash_nosub(partition_info *part_info,
uint32 *part_id,
longlong *func_value)
{
- return get_part_id_hash(part_info->no_parts, part_info->part_expr,
+ return get_part_id_hash(part_info->num_parts, part_info->part_expr,
part_id, func_value);
}
@@ -3017,7 +3498,7 @@ int get_partition_id_linear_hash_nosub(partition_info *part_info,
uint32 *part_id,
longlong *func_value)
{
- return get_part_id_linear_hash(part_info, part_info->no_parts,
+ return get_part_id_linear_hash(part_info, part_info->num_parts,
part_info->part_expr, part_id, func_value);
}
@@ -3027,232 +3508,44 @@ int get_partition_id_key_nosub(partition_info *part_info,
longlong *func_value)
{
*part_id= get_part_id_key(part_info->part_field_array,
- part_info->no_parts, func_value);
+ part_info->num_parts, func_value);
return 0;
}
int get_partition_id_linear_key_nosub(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
+ uint32 *part_id,
+ longlong *func_value)
{
*part_id= get_part_id_linear_key(part_info,
part_info->part_field_array,
- part_info->no_parts, func_value);
+ part_info->num_parts, func_value);
return 0;
}
-int get_partition_id_range_sub_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
- int error;
- DBUG_ENTER("get_partition_id_range_sub_hash");
- LINT_INIT(loc_part_id);
- LINT_INIT(sub_part_id);
-
- if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
- func_value))))
- {
- DBUG_RETURN(error);
- }
- no_subparts= part_info->no_subparts;
- if (unlikely((error= get_part_id_hash(no_subparts, part_info->subpart_expr,
- &sub_part_id, &local_func_value))))
- {
- DBUG_RETURN(error);
- }
-
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
- DBUG_RETURN(0);
-}
-
-
-int get_partition_id_range_sub_linear_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
- int error;
- DBUG_ENTER("get_partition_id_range_sub_linear_hash");
- LINT_INIT(loc_part_id);
- LINT_INIT(sub_part_id);
-
- if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
- func_value))))
- {
- DBUG_RETURN(error);
- }
- no_subparts= part_info->no_subparts;
- if (unlikely((error= get_part_id_linear_hash(part_info, no_subparts,
- part_info->subpart_expr,
- &sub_part_id,
- &local_func_value))))
- {
- DBUG_RETURN(error);
- }
-
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
- DBUG_RETURN(0);
-}
-
-
-int get_partition_id_range_sub_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
- int error;
- DBUG_ENTER("get_partition_id_range_sub_key");
- LINT_INIT(loc_part_id);
-
- if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
- func_value))))
- {
- DBUG_RETURN(error);
- }
- no_subparts= part_info->no_subparts;
- sub_part_id= get_part_id_key(part_info->subpart_field_array,
- no_subparts, &local_func_value);
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
- DBUG_RETURN(0);
-}
-
-
-int get_partition_id_range_sub_linear_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
- int error;
- DBUG_ENTER("get_partition_id_range_sub_linear_key");
- LINT_INIT(loc_part_id);
-
- if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
- func_value))))
- {
- DBUG_RETURN(error);
- }
- no_subparts= part_info->no_subparts;
- sub_part_id= get_part_id_linear_key(part_info,
- part_info->subpart_field_array,
- no_subparts, &local_func_value);
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
- DBUG_RETURN(0);
-}
-
-
-int get_partition_id_list_sub_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
- int error;
- DBUG_ENTER("get_partition_id_list_sub_hash");
- LINT_INIT(sub_part_id);
-
- if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
- func_value))))
- {
- DBUG_RETURN(error);
- }
- no_subparts= part_info->no_subparts;
- if (unlikely((error= get_part_id_hash(no_subparts, part_info->subpart_expr,
- &sub_part_id, &local_func_value))))
- {
- DBUG_RETURN(error);
- }
-
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
- DBUG_RETURN(0);
-}
-
-
-int get_partition_id_list_sub_linear_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
- int error;
- DBUG_ENTER("get_partition_id_list_sub_linear_hash");
- LINT_INIT(sub_part_id);
-
- if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
- func_value))))
- {
- DBUG_RETURN(error);
- }
- no_subparts= part_info->no_subparts;
- if (unlikely((error= get_part_id_linear_hash(part_info, no_subparts,
- part_info->subpart_expr,
- &sub_part_id,
- &local_func_value))))
- {
- DBUG_RETURN(error);
- }
-
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
- DBUG_RETURN(0);
-}
-
-
-int get_partition_id_list_sub_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
+int get_partition_id_with_sub(partition_info *part_info,
+ uint32 *part_id,
+ longlong *func_value)
{
uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
+ uint num_subparts;
int error;
- DBUG_ENTER("get_partition_id_range_sub_key");
+ DBUG_ENTER("get_partition_id_with_sub");
- if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
- func_value))))
+ if (unlikely((error= part_info->get_part_partition_id(part_info,
+ &loc_part_id,
+ func_value))))
{
DBUG_RETURN(error);
}
- no_subparts= part_info->no_subparts;
- sub_part_id= get_part_id_key(part_info->subpart_field_array,
- no_subparts, &local_func_value);
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
- DBUG_RETURN(0);
-}
-
-
-int get_partition_id_list_sub_linear_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
- int error;
- DBUG_ENTER("get_partition_id_list_sub_linear_key");
-
- if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
- func_value))))
+ num_subparts= part_info->num_subparts;
+ if (unlikely((error= part_info->get_subpartition_id(part_info,
+ &sub_part_id))))
{
DBUG_RETURN(error);
- }
- no_subparts= part_info->no_subparts;
- sub_part_id= get_part_id_linear_key(part_info,
- part_info->subpart_field_array,
- no_subparts, &local_func_value);
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
+ }
+ *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, num_subparts);
DBUG_RETURN(0);
}
@@ -3285,7 +3578,7 @@ int get_partition_id_hash_sub(partition_info *part_info,
uint32 *part_id)
{
longlong func_value;
- return get_part_id_hash(part_info->no_subparts, part_info->subpart_expr,
+ return get_part_id_hash(part_info->num_subparts, part_info->subpart_expr,
part_id, &func_value);
}
@@ -3294,7 +3587,7 @@ int get_partition_id_linear_hash_sub(partition_info *part_info,
uint32 *part_id)
{
longlong func_value;
- return get_part_id_linear_hash(part_info, part_info->no_subparts,
+ return get_part_id_linear_hash(part_info, part_info->num_subparts,
part_info->subpart_expr, part_id,
&func_value);
}
@@ -3305,7 +3598,7 @@ int get_partition_id_key_sub(partition_info *part_info,
{
longlong func_value;
*part_id= get_part_id_key(part_info->subpart_field_array,
- part_info->no_subparts, &func_value);
+ part_info->num_subparts, &func_value);
return FALSE;
}
@@ -3316,7 +3609,7 @@ int get_partition_id_linear_key_sub(partition_info *part_info,
longlong func_value;
*part_id= get_part_id_linear_key(part_info,
part_info->subpart_field_array,
- part_info->no_subparts, &func_value);
+ part_info->num_subparts, &func_value);
return FALSE;
}
@@ -3615,16 +3908,16 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
const key_range *key_spec, part_id_range *part_spec)
{
partition_info *part_info= table->part_info;
- uint no_parts= part_info->get_tot_partitions();
+ uint num_parts= part_info->get_tot_partitions();
uint i, part_id;
- uint sub_part= no_parts;
- uint32 part_part= no_parts;
+ uint sub_part= num_parts;
+ uint32 part_part= num_parts;
KEY *key_info= NULL;
bool found_part_field= FALSE;
DBUG_ENTER("get_partition_set");
part_spec->start_part= 0;
- part_spec->end_part= no_parts - 1;
+ part_spec->end_part= num_parts - 1;
if ((index < MAX_KEY) &&
key_spec->flag == (uint)HA_READ_KEY_EXACT &&
part_info->some_fields_in_PF.is_set(index))
@@ -3661,7 +3954,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
{
if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part))
{
- part_spec->start_part= no_parts;
+ part_spec->start_part= num_parts;
DBUG_VOID_RETURN;
}
}
@@ -3675,7 +3968,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
allowed values. Thus it is certain that the result of this
scan will be empty.
*/
- part_spec->start_part= no_parts;
+ part_spec->start_part= num_parts;
DBUG_VOID_RETURN;
}
}
@@ -3713,7 +4006,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
{
if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part))
{
- part_spec->start_part= no_parts;
+ part_spec->start_part= num_parts;
clear_indicator_in_key_fields(key_info);
DBUG_VOID_RETURN;
}
@@ -3722,7 +4015,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
{
if (get_part_id_from_key(table,buf,key_info,key_spec,&part_part))
{
- part_spec->start_part= no_parts;
+ part_spec->start_part= num_parts;
clear_indicator_in_key_fields(key_info);
DBUG_VOID_RETURN;
}
@@ -3743,29 +4036,29 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
nothing or we have discovered a range of partitions with possible holes
in it. We need a bitvector to further the work here.
*/
- if (!(part_part == no_parts && sub_part == no_parts))
+ if (!(part_part == num_parts && sub_part == num_parts))
{
/*
We can only arrive here if we are using subpartitioning.
*/
- if (part_part != no_parts)
+ if (part_part != num_parts)
{
/*
We know the top partition and need to scan all underlying
subpartitions. This is a range without holes.
*/
- DBUG_ASSERT(sub_part == no_parts);
- part_spec->start_part= part_part * part_info->no_subparts;
- part_spec->end_part= part_spec->start_part+part_info->no_subparts - 1;
+ DBUG_ASSERT(sub_part == num_parts);
+ part_spec->start_part= part_part * part_info->num_subparts;
+ part_spec->end_part= part_spec->start_part+part_info->num_subparts - 1;
}
else
{
- DBUG_ASSERT(sub_part != no_parts);
+ DBUG_ASSERT(sub_part != num_parts);
part_spec->start_part= sub_part;
part_spec->end_part=sub_part+
- (part_info->no_subparts*(part_info->no_parts-1));
- for (i= 0, part_id= sub_part; i < part_info->no_parts;
- i++, part_id+= part_info->no_subparts)
+ (part_info->num_subparts*(part_info->num_parts-1));
+ for (i= 0, part_id= sub_part; i < part_info->num_parts;
+ i++, part_id+= part_info->num_subparts)
; //Set bit part_id in bit array
}
}
@@ -3849,26 +4142,13 @@ bool mysql_unpack_partition(THD *thd,
LEX lex;
DBUG_ENTER("mysql_unpack_partition");
- thd->lex= &lex;
thd->variables.character_set_client= system_charset_info;
Parser_state parser_state(thd, part_buf, part_info_len);
- lex_start(thd);
- *work_part_info_used= false;
- /*
- We need to use the current SELECT_LEX since I need to keep the
- Name_resolution_context object which is referenced from the
- Item_field objects.
- This is not a nice solution since if the parser uses current_select
- for anything else it will corrupt the current LEX object.
- Also, we need to make sure there even is a select -- if the statement
- was a "USE ...", current_select will be NULL, but we may still end up
- here if we try to log to a partitioned table. This is currently
- unsupported, but should still fail rather than crash!
- */
- if (!(thd->lex->current_select= old_lex->current_select))
+ 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
@@ -3878,16 +4158,19 @@ bool mysql_unpack_partition(THD *thd,
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 */
if (!lex.part_info)
{
mem_alloc_error(sizeof(partition_info));
goto end;
}
- lex.part_info->part_state= part_state;
- lex.part_info->part_state_len= part_state_len;
+ part_info= lex.part_info;
+ part_info->part_state= part_state;
+ part_info->part_state_len= part_state_len;
DBUG_PRINT("info", ("Parse: %s", part_buf));
- if (parse_sql(thd, & parser_state, NULL))
+ if (parse_sql(thd, & parser_state, NULL) ||
+ part_info->fix_parser_data(thd))
{
thd->free_items();
goto end;
@@ -3908,7 +4191,6 @@ bool mysql_unpack_partition(THD *thd,
*/
DBUG_PRINT("info", ("Successful parse"));
- part_info= lex.part_info;
DBUG_PRINT("info", ("default engine = %s, default_db_type = %s",
ha_resolve_storage_engine_name(part_info->default_engine_type),
ha_resolve_storage_engine_name(default_db_type)));
@@ -3990,8 +4272,7 @@ bool mysql_unpack_partition(THD *thd,
result= FALSE;
end:
- lex_end(thd->lex);
- thd->lex= old_lex;
+ end_lex_with_single_table(thd, table, old_lex);
thd->variables.character_set_client= old_character_set_client;
DBUG_RETURN(result);
}
@@ -4029,9 +4310,9 @@ set_engine_all_partitions(partition_info *part_info,
partition_element *sub_elem= sub_it++;
sub_elem->engine_type= engine_type;
- } while (++j < part_info->no_subparts);
+ } while (++j < part_info->num_subparts);
}
- } while (++i < part_info->no_parts);
+ } while (++i < part_info->num_parts);
}
/*
SYNOPSIS
@@ -4081,7 +4362,7 @@ static int fast_end_partition(THD *thd, ulonglong copied,
if ((!is_empty) && (!written_bin_log) &&
(!thd->lex->no_write_to_binlog))
- write_bin_log(thd, FALSE, thd->query, thd->query_length);
+ write_bin_log(thd, FALSE, thd->query(), thd->query_length());
my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
(ulong) (copied + deleted),
@@ -4176,7 +4457,7 @@ uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
enum partition_state part_state)
{
uint part_count= 0;
- uint no_parts_found= 0;
+ uint num_parts_found= 0;
List_iterator<partition_element> part_it(tab_part_info->partitions);
do
@@ -4191,15 +4472,15 @@ uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
I.e mark the partition as a partition to be "changed" by
analyzing/optimizing/rebuilding/checking/repairing/...
*/
- no_parts_found++;
+ num_parts_found++;
part_elem->part_state= part_state;
DBUG_PRINT("info", ("Setting part_state to %u for partition %s",
part_state, part_elem->partition_name));
}
else
part_elem->part_state= PART_NORMAL;
- } while (++part_count < tab_part_info->no_parts);
- return no_parts_found;
+ } while (++part_count < tab_part_info->num_parts);
+ return num_parts_found;
}
@@ -4266,6 +4547,11 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
partition_info *tab_part_info= table->part_info;
partition_info *alt_part_info= thd->work_part_info;
uint flags= 0;
+ bool is_last_partition_reorged;
+ part_elem_value *tab_max_elem_val= NULL;
+ part_elem_value *alt_max_elem_val= NULL;
+ longlong tab_max_range= 0, alt_max_range= 0;
+
if (!tab_part_info)
{
my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
@@ -4275,13 +4561,13 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
{
uint new_part_no, curr_part_no;
if (tab_part_info->part_type != HASH_PARTITION ||
- tab_part_info->use_default_no_partitions)
+ tab_part_info->use_default_num_partitions)
{
my_error(ER_REORG_NO_PARAM_ERROR, MYF(0));
DBUG_RETURN(TRUE);
}
new_part_no= table->file->get_default_no_partitions(create_info);
- curr_part_no= tab_part_info->no_parts;
+ curr_part_no= tab_part_info->num_parts;
if (new_part_no == curr_part_no)
{
/*
@@ -4299,7 +4585,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
setting the flag for no default number of partitions
*/
alter_info->flags|= ALTER_ADD_PARTITION;
- thd->work_part_info->no_parts= new_part_no - curr_part_no;
+ thd->work_part_info->num_parts= new_part_no - curr_part_no;
}
else
{
@@ -4308,7 +4594,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
without setting the flag for no default number of partitions
*/
alter_info->flags|= ALTER_COALESCE_PARTITION;
- alter_info->no_parts= curr_part_no - new_part_no;
+ alter_info->num_parts= curr_part_no - new_part_no;
}
}
if (!(flags= table->file->alter_table_flags(alter_info->flags)))
@@ -4320,34 +4606,73 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
((flags & (HA_FAST_CHANGE_PARTITION | HA_PARTITION_ONE_PHASE)) != 0);
DBUG_PRINT("info", ("*fast_alter_partition: %d flags: 0x%x",
*fast_alter_partition, flags));
- if (((alter_info->flags & ALTER_ADD_PARTITION) ||
- (alter_info->flags & ALTER_REORGANIZE_PARTITION)) &&
- (thd->work_part_info->part_type != tab_part_info->part_type) &&
- (thd->work_part_info->part_type != NOT_A_PARTITION))
+ if ((alter_info->flags & ALTER_ADD_PARTITION) ||
+ (alter_info->flags & ALTER_REORGANIZE_PARTITION))
{
- if (thd->work_part_info->part_type == RANGE_PARTITION)
- {
- my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
- "RANGE", "LESS THAN");
- }
- else if (thd->work_part_info->part_type == LIST_PARTITION)
+ if (thd->work_part_info->part_type != tab_part_info->part_type)
{
- DBUG_ASSERT(thd->work_part_info->part_type == LIST_PARTITION);
- my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
- "LIST", "IN");
+ if (thd->work_part_info->part_type == NOT_A_PARTITION)
+ {
+ if (tab_part_info->part_type == RANGE_PARTITION)
+ {
+ my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "RANGE");
+ DBUG_RETURN(TRUE);
+ }
+ else if (tab_part_info->part_type == LIST_PARTITION)
+ {
+ my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "LIST");
+ DBUG_RETURN(TRUE);
+ }
+ /*
+ Hash partitions can be altered without parser finds out about
+ that it is HASH partitioned. So no error here.
+ */
+ }
+ else
+ {
+ if (thd->work_part_info->part_type == RANGE_PARTITION)
+ {
+ my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
+ "RANGE", "LESS THAN");
+ }
+ else if (thd->work_part_info->part_type == LIST_PARTITION)
+ {
+ DBUG_ASSERT(thd->work_part_info->part_type == LIST_PARTITION);
+ my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
+ "LIST", "IN");
+ }
+ else if (tab_part_info->part_type == RANGE_PARTITION)
+ {
+ my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
+ "RANGE", "LESS THAN");
+ }
+ else
+ {
+ DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION);
+ my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
+ "LIST", "IN");
+ }
+ DBUG_RETURN(TRUE);
+ }
}
- else if (tab_part_info->part_type == RANGE_PARTITION)
+ if ((tab_part_info->column_list &&
+ alt_part_info->num_columns != tab_part_info->num_columns) ||
+ (!tab_part_info->column_list &&
+ (tab_part_info->part_type == RANGE_PARTITION ||
+ tab_part_info->part_type == LIST_PARTITION) &&
+ alt_part_info->num_columns != 1U) ||
+ (!tab_part_info->column_list &&
+ tab_part_info->part_type == HASH_PARTITION &&
+ alt_part_info->num_columns != 0))
{
- my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
- "RANGE", "LESS THAN");
+ my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
+ DBUG_RETURN(TRUE);
}
- else
+ alt_part_info->column_list= tab_part_info->column_list;
+ if (alt_part_info->fix_parser_data(thd))
{
- DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION);
- my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
- "LIST", "IN");
+ DBUG_RETURN(TRUE);
}
- DBUG_RETURN(TRUE);
}
if (alter_info->flags & ALTER_ADD_PARTITION)
{
@@ -4357,9 +4682,9 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
partitioning scheme as currently set-up.
Partitions are always added at the end in ADD PARTITION.
*/
- uint no_new_partitions= alt_part_info->no_parts;
- uint no_orig_partitions= tab_part_info->no_parts;
- uint check_total_partitions= no_new_partitions + no_orig_partitions;
+ uint num_new_partitions= alt_part_info->num_parts;
+ uint num_orig_partitions= tab_part_info->num_parts;
+ uint check_total_partitions= num_new_partitions + num_orig_partitions;
uint new_total_partitions= check_total_partitions;
/*
We allow quite a lot of values to be supplied by defaults, however we
@@ -4376,22 +4701,22 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0));
DBUG_RETURN(TRUE);
}
- if (no_new_partitions == 0)
+ if (num_new_partitions == 0)
{
my_error(ER_ADD_PARTITION_NO_NEW_PARTITION, MYF(0));
DBUG_RETURN(TRUE);
}
if (tab_part_info->is_sub_partitioned())
{
- if (alt_part_info->no_subparts == 0)
- alt_part_info->no_subparts= tab_part_info->no_subparts;
- else if (alt_part_info->no_subparts != tab_part_info->no_subparts)
+ if (alt_part_info->num_subparts == 0)
+ alt_part_info->num_subparts= tab_part_info->num_subparts;
+ else if (alt_part_info->num_subparts != tab_part_info->num_subparts)
{
my_error(ER_ADD_PARTITION_SUBPART_ERROR, MYF(0));
DBUG_RETURN(TRUE);
}
check_total_partitions= new_total_partitions*
- alt_part_info->no_subparts;
+ alt_part_info->num_subparts;
}
if (check_total_partitions > MAX_PARTITIONS)
{
@@ -4401,8 +4726,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
alt_part_info->part_type= tab_part_info->part_type;
alt_part_info->subpart_type= tab_part_info->subpart_type;
if (alt_part_info->set_up_defaults_for_partitioning(table->file,
- ULL(0),
- tab_part_info->no_parts))
+ ULL(0),
+ tab_part_info->num_parts))
{
DBUG_RETURN(TRUE);
}
@@ -4477,7 +4802,7 @@ that are reorganised.
uint lower_2n= upper_2n >> 1;
bool all_parts= TRUE;
if (tab_part_info->linear_hash_ind &&
- no_new_partitions < upper_2n)
+ num_new_partitions < upper_2n)
{
/*
An analysis of which parts needs reorganisation shows that it is
@@ -4486,7 +4811,7 @@ that are reorganised.
onwards it starts again from partition 0 and goes on until
it reaches p(upper_2n - 1). If the last new partition reaches
beyond upper_2n - 1 then the first interval will end with
- p(lower_2n - 1) and start with p(no_orig_partitions - lower_2n).
+ p(lower_2n - 1) and start with p(num_orig_partitions - lower_2n).
If lower_2n partitions are added then p0 to p(lower_2n - 1) will
be reorganised which means that the two interval becomes one
interval at this point. Thus only when adding less than
@@ -4514,7 +4839,7 @@ that are reorganised.
to TRUE. In this case we don't get into this if-part at all.
*/
all_parts= FALSE;
- if (no_new_partitions >= lower_2n)
+ if (num_new_partitions >= lower_2n)
{
/*
In this case there is only one interval since the two intervals
@@ -4530,8 +4855,8 @@ that are reorganised.
Also in this case there is only one interval since we are not
going over a 2**n boundary
*/
- start_part= no_orig_partitions - lower_2n;
- end_part= start_part + (no_new_partitions - 1);
+ start_part= num_orig_partitions - lower_2n;
+ end_part= start_part + (num_new_partitions - 1);
}
else
{
@@ -4540,7 +4865,7 @@ that are reorganised.
new parts that would ensure that the intervals become
overlapping.
*/
- start_part= no_orig_partitions - lower_2n;
+ start_part= num_orig_partitions - lower_2n;
end_part= upper_2n - 1;
start_sec_part= 0;
end_sec_part= new_total_partitions - (upper_2n + 1);
@@ -4557,7 +4882,7 @@ that are reorganised.
{
p_elem->part_state= PART_CHANGED;
}
- } while (++part_no < no_orig_partitions);
+ } while (++part_no < num_orig_partitions);
}
/*
Need to concatenate the lists here to make it possible to check the
@@ -4580,8 +4905,8 @@ that are reorganised.
mem_alloc_error(1);
DBUG_RETURN(TRUE);
}
- } while (++part_count < no_new_partitions);
- tab_part_info->no_parts+= no_new_partitions;
+ } while (++part_count < num_new_partitions);
+ tab_part_info->num_parts+= num_new_partitions;
}
/*
If we specify partitions explicitly we don't use defaults anymore.
@@ -4596,7 +4921,7 @@ that are reorganised.
DBUG_PRINT("info", ("part_info: 0x%lx", (long) tab_part_info));
tab_part_info->use_default_partitions= FALSE;
}
- tab_part_info->use_default_no_partitions= FALSE;
+ tab_part_info->use_default_num_partitions= FALSE;
tab_part_info->is_auto_partitioned= FALSE;
}
}
@@ -4610,8 +4935,8 @@ that are reorganised.
command to drop the partition failed in the middle.
*/
uint part_count= 0;
- uint no_parts_dropped= alter_info->partition_names.elements;
- uint no_parts_found= 0;
+ uint num_parts_dropped= alter_info->partition_names.elements;
+ uint num_parts_found= 0;
List_iterator<partition_element> part_it(tab_part_info->partitions);
tab_part_info->is_auto_partitioned= FALSE;
@@ -4621,7 +4946,7 @@ that are reorganised.
my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP");
DBUG_RETURN(TRUE);
}
- if (no_parts_dropped >= tab_part_info->no_parts)
+ if (num_parts_dropped >= tab_part_info->num_parts)
{
my_error(ER_DROP_LAST_PARTITION, MYF(0));
DBUG_RETURN(TRUE);
@@ -4635,11 +4960,11 @@ that are reorganised.
/*
Set state to indicate that the partition is to be dropped.
*/
- no_parts_found++;
+ num_parts_found++;
part_elem->part_state= PART_TO_BE_DROPPED;
}
- } while (++part_count < tab_part_info->no_parts);
- if (no_parts_found != no_parts_dropped)
+ } while (++part_count < tab_part_info->num_parts);
+ if (num_parts_found != num_parts_dropped)
{
my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "DROP");
DBUG_RETURN(TRUE);
@@ -4649,14 +4974,14 @@ that are reorganised.
my_error(ER_ROW_IS_REFERENCED, MYF(0));
DBUG_RETURN(TRUE);
}
- tab_part_info->no_parts-= no_parts_dropped;
+ tab_part_info->num_parts-= num_parts_dropped;
}
else if (alter_info->flags & ALTER_REBUILD_PARTITION)
{
- uint no_parts_found;
- uint no_parts_opt= alter_info->partition_names.elements;
- no_parts_found= set_part_state(alter_info, tab_part_info, PART_CHANGED);
- if (no_parts_found != no_parts_opt &&
+ uint num_parts_found;
+ uint num_parts_opt= alter_info->partition_names.elements;
+ num_parts_found= set_part_state(alter_info, tab_part_info, PART_CHANGED);
+ if (num_parts_found != num_parts_opt &&
(!(alter_info->flags & ALTER_ALL_PARTITION)))
{
my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REBUILD");
@@ -4670,20 +4995,20 @@ that are reorganised.
}
else if (alter_info->flags & ALTER_COALESCE_PARTITION)
{
- uint no_parts_coalesced= alter_info->no_parts;
- uint no_parts_remain= tab_part_info->no_parts - no_parts_coalesced;
+ uint num_parts_coalesced= alter_info->num_parts;
+ uint num_parts_remain= tab_part_info->num_parts - num_parts_coalesced;
List_iterator<partition_element> part_it(tab_part_info->partitions);
if (tab_part_info->part_type != HASH_PARTITION)
{
my_error(ER_COALESCE_ONLY_ON_HASH_PARTITION, MYF(0));
DBUG_RETURN(TRUE);
}
- if (no_parts_coalesced == 0)
+ if (num_parts_coalesced == 0)
{
my_error(ER_COALESCE_PARTITION_NO_PARTITION, MYF(0));
DBUG_RETURN(TRUE);
}
- if (no_parts_coalesced >= tab_part_info->no_parts)
+ if (num_parts_coalesced >= tab_part_info->num_parts)
{
my_error(ER_DROP_LAST_PARTITION, MYF(0));
DBUG_RETURN(TRUE);
@@ -4731,21 +5056,21 @@ state of p1.
uint upper_2n= tab_part_info->linear_hash_mask + 1;
uint lower_2n= upper_2n >> 1;
all_parts= FALSE;
- if (no_parts_coalesced >= lower_2n)
+ if (num_parts_coalesced >= lower_2n)
{
all_parts= TRUE;
}
- else if (no_parts_remain >= lower_2n)
+ else if (num_parts_remain >= lower_2n)
{
- end_part= tab_part_info->no_parts - (lower_2n + 1);
- start_part= no_parts_remain - lower_2n;
+ end_part= tab_part_info->num_parts - (lower_2n + 1);
+ start_part= num_parts_remain - lower_2n;
}
else
{
start_part= 0;
- end_part= tab_part_info->no_parts - (lower_2n + 1);
+ end_part= tab_part_info->num_parts - (lower_2n + 1);
end_sec_part= (lower_2n >> 1) - 1;
- start_sec_part= end_sec_part - (lower_2n - (no_parts_remain + 1));
+ start_sec_part= end_sec_part - (lower_2n - (num_parts_remain + 1));
}
}
do
@@ -4756,19 +5081,19 @@ state of p1.
(part_count >= start_part && part_count <= end_part) ||
(part_count >= start_sec_part && part_count <= end_sec_part)))
p_elem->part_state= PART_CHANGED;
- if (++part_count > no_parts_remain)
+ if (++part_count > num_parts_remain)
{
if (*fast_alter_partition)
p_elem->part_state= PART_REORGED_DROPPED;
else
part_it.remove();
}
- } while (part_count < tab_part_info->no_parts);
- tab_part_info->no_parts= no_parts_remain;
+ } while (part_count < tab_part_info->num_parts);
+ tab_part_info->num_parts= num_parts_remain;
}
if (!(alter_info->flags & ALTER_TABLE_REORG))
{
- tab_part_info->use_default_no_partitions= FALSE;
+ tab_part_info->use_default_num_partitions= FALSE;
tab_part_info->is_auto_partitioned= FALSE;
}
}
@@ -4785,33 +5110,32 @@ state of p1.
range as those changed from.
This command can be used on RANGE and LIST partitions.
*/
- uint no_parts_reorged= alter_info->partition_names.elements;
- uint no_parts_new= thd->work_part_info->partitions.elements;
- partition_info *alt_part_info= thd->work_part_info;
+ uint num_parts_reorged= alter_info->partition_names.elements;
+ uint num_parts_new= thd->work_part_info->partitions.elements;
uint check_total_partitions;
tab_part_info->is_auto_partitioned= FALSE;
- if (no_parts_reorged > tab_part_info->no_parts)
+ if (num_parts_reorged > tab_part_info->num_parts)
{
my_error(ER_REORG_PARTITION_NOT_EXIST, MYF(0));
DBUG_RETURN(TRUE);
}
if (!(tab_part_info->part_type == RANGE_PARTITION ||
tab_part_info->part_type == LIST_PARTITION) &&
- (no_parts_new != no_parts_reorged))
+ (num_parts_new != num_parts_reorged))
{
my_error(ER_REORG_HASH_ONLY_ON_SAME_NO, MYF(0));
DBUG_RETURN(TRUE);
}
if (tab_part_info->is_sub_partitioned() &&
- alt_part_info->no_subparts &&
- alt_part_info->no_subparts != tab_part_info->no_subparts)
+ alt_part_info->num_subparts &&
+ alt_part_info->num_subparts != tab_part_info->num_subparts)
{
my_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR, MYF(0));
DBUG_RETURN(TRUE);
}
- check_total_partitions= tab_part_info->no_parts + no_parts_new;
- check_total_partitions-= no_parts_reorged;
+ check_total_partitions= tab_part_info->num_parts + num_parts_new;
+ check_total_partitions-= num_parts_reorged;
if (check_total_partitions > MAX_PARTITIONS)
{
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
@@ -4819,7 +5143,7 @@ state of p1.
}
alt_part_info->part_type= tab_part_info->part_type;
alt_part_info->subpart_type= tab_part_info->subpart_type;
- alt_part_info->no_subparts= tab_part_info->no_subparts;
+ alt_part_info->num_subparts= tab_part_info->num_subparts;
DBUG_ASSERT(!alt_part_info->use_default_partitions);
if (alt_part_info->set_up_defaults_for_partitioning(table->file,
ULL(0),
@@ -4867,9 +5191,7 @@ the generated partition syntax in a correct manner.
uint part_count= 0;
bool found_first= FALSE;
bool found_last= FALSE;
- bool is_last_partition_reorged;
uint drop_count= 0;
- longlong tab_max_range= 0, alt_max_range= 0;
do
{
partition_element *part_elem= tab_it++;
@@ -4879,7 +5201,13 @@ the generated partition syntax in a correct manner.
{
is_last_partition_reorged= TRUE;
drop_count++;
- tab_max_range= part_elem->range_value;
+ if (tab_part_info->column_list)
+ {
+ List_iterator<part_elem_value> p(part_elem->list_val_list);
+ tab_max_elem_val= p++;
+ }
+ else
+ tab_max_range= part_elem->range_value;
if (*fast_alter_partition &&
tab_part_info->temp_partitions.push_back(part_elem))
{
@@ -4891,20 +5219,28 @@ the generated partition syntax in a correct manner.
if (!found_first)
{
uint alt_part_count= 0;
- found_first= TRUE;
+ partition_element *alt_part_elem;
List_iterator<partition_element>
alt_it(alt_part_info->partitions);
+ found_first= TRUE;
do
{
- partition_element *alt_part_elem= alt_it++;
- alt_max_range= alt_part_elem->range_value;
+ alt_part_elem= alt_it++;
+ if (tab_part_info->column_list)
+ {
+ List_iterator<part_elem_value> p(alt_part_elem->list_val_list);
+ alt_max_elem_val= p++;
+ }
+ else
+ alt_max_range= alt_part_elem->range_value;
+
if (*fast_alter_partition)
alt_part_elem->part_state= PART_TO_BE_ADDED;
if (alt_part_count == 0)
tab_it.replace(alt_part_elem);
else
tab_it.after(alt_part_elem);
- } while (++alt_part_count < no_parts_new);
+ } while (++alt_part_count < num_parts_new);
}
else if (found_last)
{
@@ -4919,32 +5255,13 @@ the generated partition syntax in a correct manner.
if (found_first)
found_last= TRUE;
}
- } while (++part_count < tab_part_info->no_parts);
- if (drop_count != no_parts_reorged)
+ } while (++part_count < tab_part_info->num_parts);
+ if (drop_count != num_parts_reorged)
{
my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REORGANIZE");
DBUG_RETURN(TRUE);
}
- if (tab_part_info->part_type == RANGE_PARTITION &&
- ((is_last_partition_reorged &&
- alt_max_range < tab_max_range) ||
- (!is_last_partition_reorged &&
- alt_max_range != tab_max_range)))
- {
- /*
- For range partitioning the total resulting range before and
- after the change must be the same except in one case. This is
- when the last partition is reorganised, in this case it is
- acceptable to increase the total range.
- The reason is that it is not allowed to have "holes" in the
- middle of the ranges and thus we should not allow to reorganise
- to create "holes". Also we should not allow using REORGANIZE
- to drop data.
- */
- my_error(ER_REORG_OUTSIDE_RANGE, MYF(0));
- DBUG_RETURN(TRUE);
- }
- tab_part_info->no_parts= check_total_partitions;
+ tab_part_info->num_parts= check_total_partitions;
}
}
else
@@ -4960,13 +5277,45 @@ the generated partition syntax in a correct manner.
!alt_part_info->use_default_subpartitions)
{
tab_part_info->use_default_subpartitions= FALSE;
- tab_part_info->use_default_no_subpartitions= FALSE;
+ tab_part_info->use_default_num_subpartitions= FALSE;
}
if (tab_part_info->check_partition_info(thd, (handlerton**)NULL,
- table->file, ULL(0), FALSE))
+ table->file, ULL(0), TRUE))
{
DBUG_RETURN(TRUE);
}
+ /*
+ The check below needs to be performed after check_partition_info
+ since this function "fixes" the item trees of the new partitions
+ to reorganize into
+ */
+ if (alter_info->flags == ALTER_REORGANIZE_PARTITION &&
+ tab_part_info->part_type == RANGE_PARTITION &&
+ ((is_last_partition_reorged &&
+ (tab_part_info->column_list ?
+ (tab_part_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(
+ alt_max_elem_val->col_val_array,
+ tab_max_elem_val->col_val_array) != 0) :
+ alt_max_range != tab_max_range))))
+ {
+ /*
+ For range partitioning the total resulting range before and
+ after the change must be the same except in one case. This is
+ when the last partition is reorganised, in this case it is
+ acceptable to increase the total range.
+ The reason is that it is not allowed to have "holes" in the
+ middle of the ranges and thus we should not allow to reorganise
+ to create "holes".
+ */
+ my_error(ER_REORG_OUTSIDE_RANGE, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
}
}
else
@@ -5080,6 +5429,10 @@ the generated partition syntax in a correct manner.
{
DBUG_PRINT("info", ("partition changed"));
*partition_changed= TRUE;
+ if (thd->work_part_info->fix_parser_data(thd))
+ {
+ DBUG_RETURN(TRUE);
+ }
}
/*
Set up partition default_engine_type either from the create_info
@@ -5240,8 +5593,8 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
part_it.remove();
remove_count++;
}
- } while (++i < part_info->no_parts);
- part_info->no_parts-= remove_count;
+ } while (++i < part_info->num_parts);
+ part_info->num_parts-= remove_count;
DBUG_RETURN(FALSE);
}
@@ -5363,7 +5716,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
char normal_path[FN_REFLEN];
List_iterator<partition_element> part_it(part_info->partitions);
uint temp_partitions= part_info->temp_partitions.elements;
- uint no_elements= part_info->partitions.elements;
+ uint num_elements= part_info->partitions.elements;
uint i= 0;
DBUG_ENTER("write_log_changed_partitions");
@@ -5376,7 +5729,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
if (part_info->is_sub_partitioned())
{
List_iterator<partition_element> sub_it(part_elem->subpartitions);
- uint no_subparts= part_info->no_subparts;
+ uint num_subparts= part_info->num_subparts;
uint j= 0;
do
{
@@ -5405,7 +5758,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
*next_entry= log_entry->entry_pos;
sub_elem->log_entry= log_entry;
insert_part_info_log_entry_list(part_info, log_entry);
- } while (++j < no_subparts);
+ } while (++j < num_subparts);
}
else
{
@@ -5433,7 +5786,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
insert_part_info_log_entry_list(part_info, log_entry);
}
}
- } while (++i < no_elements);
+ } while (++i < num_elements);
DBUG_RETURN(FALSE);
}
@@ -5459,14 +5812,14 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
char tmp_path[FN_LEN];
List_iterator<partition_element> part_it(part_info->partitions);
List_iterator<partition_element> temp_it(part_info->temp_partitions);
- uint no_temp_partitions= part_info->temp_partitions.elements;
- uint no_elements= part_info->partitions.elements;
+ uint num_temp_partitions= part_info->temp_partitions.elements;
+ uint num_elements= part_info->partitions.elements;
DBUG_ENTER("write_log_dropped_partitions");
ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION;
if (temp_list)
- no_elements= no_temp_partitions;
- while (no_elements--)
+ num_elements= num_temp_partitions;
+ while (num_elements--)
{
partition_element *part_elem;
if (temp_list)
@@ -5480,14 +5833,14 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
uint name_variant;
if (part_elem->part_state == PART_CHANGED ||
(part_elem->part_state == PART_TO_BE_ADDED &&
- no_temp_partitions))
+ num_temp_partitions))
name_variant= TEMP_PART_NAME;
else
name_variant= NORMAL_PART_NAME;
if (part_info->is_sub_partitioned())
{
List_iterator<partition_element> sub_it(part_elem->subpartitions);
- uint no_subparts= part_info->no_subparts;
+ uint num_subparts= part_info->num_subparts;
uint j= 0;
do
{
@@ -5507,7 +5860,7 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
*next_entry= log_entry->entry_pos;
sub_elem->log_entry= log_entry;
insert_part_info_log_entry_list(part_info, log_entry);
- } while (++j < no_subparts);
+ } while (++j < num_subparts);
}
else
{
@@ -6241,7 +6594,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
ERROR_INJECT_CRASH("crash_drop_partition_5") ||
((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE,
- thd->query, thd->query_length), FALSE)) ||
+ thd->query(), thd->query_length()), FALSE)) ||
ERROR_INJECT_CRASH("crash_drop_partition_6") ||
((frm_install= TRUE), FALSE) ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
@@ -6308,7 +6661,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
ERROR_INJECT_CRASH("crash_add_partition_5") ||
((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE,
- thd->query, thd->query_length), FALSE)) ||
+ thd->query(), thd->query_length()), FALSE)) ||
ERROR_INJECT_CRASH("crash_add_partition_6") ||
write_log_rename_frm(lpt) ||
(not_completed= FALSE) ||
@@ -6398,7 +6751,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
ERROR_INJECT_CRASH("crash_change_partition_6") ||
((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE,
- thd->query, thd->query_length), FALSE)) ||
+ thd->query(), thd->query_length()), FALSE)) ||
ERROR_INJECT_CRASH("crash_change_partition_7") ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
ERROR_INJECT_CRASH("crash_change_partition_8") ||
@@ -6605,16 +6958,19 @@ void make_used_partitions_str(partition_info *part_info, String *parts_str)
IMPLEMENTATION
There are two available interval analyzer functions:
(1) get_part_iter_for_interval_via_mapping
- (2) get_part_iter_for_interval_via_walking
+ (2) get_part_iter_for_interval_cols_via_map
+ (3) get_part_iter_for_interval_via_walking
They both have limited applicability:
(1) is applicable for "PARTITION BY <RANGE|LIST>(func(t.field))", where
func is a monotonic function.
-
- (2) is applicable for
+
+ (2) is applicable for "PARTITION BY <RANGE|LIST> COLUMNS (field_list)
+
+ (3) is applicable for
"[SUB]PARTITION BY <any-partitioning-type>(any_func(t.integer_field))"
- If both are applicable, (1) is preferred over (2).
+ If both (1) and (3) are applicable, (1) is preferred over (3).
This function sets part_info::get_part_iter_for_interval according to
this criteria, and also sets some auxilary fields that the function
@@ -6634,10 +6990,19 @@ static void set_up_range_analysis_info(partition_info *part_info)
switch (part_info->part_type) {
case RANGE_PARTITION:
case LIST_PARTITION:
- if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC)
+ if (!part_info->column_list)
+ {
+ if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC)
+ {
+ part_info->get_part_iter_for_interval=
+ get_part_iter_for_interval_via_mapping;
+ goto setup_subparts;
+ }
+ }
+ else
{
part_info->get_part_iter_for_interval=
- get_part_iter_for_interval_via_mapping;
+ get_part_iter_for_interval_cols_via_map;
goto setup_subparts;
}
default:
@@ -6648,7 +7013,7 @@ static void set_up_range_analysis_info(partition_info *part_info)
Check if get_part_iter_for_interval_via_walking() can be used for
partitioning
*/
- if (part_info->no_part_fields == 1)
+ if (part_info->num_part_fields == 1)
{
Field *field= part_info->part_field_array[0];
switch (field->type()) {
@@ -6670,7 +7035,7 @@ setup_subparts:
Check if get_part_iter_for_interval_via_walking() can be used for
subpartitioning
*/
- if (part_info->no_subpart_fields == 1)
+ if (part_info->num_subpart_fields == 1)
{
Field *field= part_info->subpart_field_array[0];
switch (field->type()) {
@@ -6688,9 +7053,118 @@ setup_subparts:
}
+/*
+ This function takes a memory of packed fields in opt-range format
+ and stores it in record format. To avoid having to worry about how
+ the length of fields are calculated in opt-range format we send
+ an array of lengths used for each field in store_length_array.
+
+ SYNOPSIS
+ store_tuple_to_record()
+ pfield Field array
+ store_length_array Array of field lengths
+ value Memory where fields are stored
+ value_end End of memory
+
+ RETURN VALUE
+ nparts Number of fields assigned
+*/
+uint32 store_tuple_to_record(Field **pfield,
+ uint32 *store_length_array,
+ uchar *value,
+ uchar *value_end)
+{
+ /* This function is inspired by store_key_image_rec. */
+ uint32 nparts= 0;
+ uchar *loc_value;
+ while (value < value_end)
+ {
+ loc_value= value;
+ if ((*pfield)->real_maybe_null())
+ {
+ if (*loc_value)
+ (*pfield)->set_null();
+ else
+ (*pfield)->set_notnull();
+ loc_value++;
+ }
+ uint len= (*pfield)->pack_length();
+ (*pfield)->set_key_image(loc_value, len);
+ value+= *store_length_array;
+ store_length_array++;
+ nparts++;
+ pfield++;
+ }
+ return nparts;
+}
+
+/*
+ RANGE(columns) partitioning: compare value bound and probe tuple.
+
+ The value bound always is a full tuple (but may include the MAXVALUE
+ special value).
+
+ The probe tuple may be a prefix of partitioning tuple. The tail_is_min
+ parameter specifies whether the suffix components should be assumed to
+ hold MAXVALUE
+*/
+
+static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec)
+{
+ partition_info *part_info= val->part_info;
+ Field **field= part_info->part_field_array;
+ Field **fields_end= field + nvals_in_rec;
+ int res;
+
+ for (; field != fields_end; field++, val++)
+ {
+ if (val->max_value)
+ return -1;
+ if ((*field)->is_null())
+ {
+ if (val->null_value)
+ continue;
+ return -1;
+ }
+ if (val->null_value)
+ return +1;
+ res= (*field)->cmp((const uchar*)val->column_value);
+ if (res)
+ return res;
+ }
+ return 0;
+}
+
+
+static int cmp_rec_and_tuple_prune(part_column_list_val *val,
+ uint32 n_vals_in_rec,
+ bool tail_is_min)
+{
+ int cmp;
+ Field **field;
+ partition_info *part_info;
+ if ((cmp= cmp_rec_and_tuple(val, n_vals_in_rec)))
+ return cmp;
+ part_info= val->part_info;
+ field= part_info->part_field_array + n_vals_in_rec;
+ for (; *field; field++, val++)
+ {
+ if (tail_is_min)
+ return -1;
+ if (!tail_is_min && !val->max_value)
+ return +1;
+ }
+ return 0;
+}
+
+
typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint,
bool include_endpoint);
+typedef uint32 (*get_col_endpoint_func)(partition_info*, bool left_endpoint,
+ bool include_endpoint,
+ uint32 num_parts);
+
/*
Partitioning Interval Analysis: Initialize the iterator for "mapping" case
@@ -6726,18 +7200,145 @@ typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint,
-1 - All partitions would match (iterator not initialized)
*/
+uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info,
+ bool left_endpoint,
+ bool include_endpoint,
+ uint32 nparts)
+{
+ uint max_partition= part_info->num_parts - 1;
+ uint min_part_id= 0, max_part_id= max_partition, loc_part_id;
+ part_column_list_val *range_col_array= part_info->range_col_array;
+ uint num_columns= part_info->part_field_list.elements;
+ bool tailf= !(left_endpoint ^ include_endpoint);
+ DBUG_ENTER("get_partition_id_cols_range_for_endpoint");
+
+ /* Get the partitioning function value for the endpoint */
+ while (max_part_id > min_part_id)
+ {
+ loc_part_id= (max_part_id + min_part_id + 1) >> 1;
+ if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*num_columns,
+ nparts, tailf) >= 0)
+ min_part_id= loc_part_id + 1;
+ else
+ max_part_id= loc_part_id - 1;
+ }
+ loc_part_id= max_part_id;
+ if (loc_part_id < max_partition &&
+ cmp_rec_and_tuple_prune(range_col_array + (loc_part_id+1)*num_columns,
+ nparts, tailf) >= 0
+ )
+ {
+ loc_part_id++;
+ }
+ if (left_endpoint)
+ {
+ if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*num_columns,
+ nparts, tailf) >= 0)
+ loc_part_id++;
+ }
+ else
+ {
+ if (loc_part_id < max_partition)
+ {
+ int res= cmp_rec_and_tuple_prune(range_col_array +
+ loc_part_id * num_columns,
+ nparts, tailf);
+ if (!res)
+ loc_part_id += test(include_endpoint);
+ else if (res > 0)
+ loc_part_id++;
+ }
+ loc_part_id++;
+ }
+ DBUG_RETURN(loc_part_id);
+}
+
+
+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)
+{
+ uint32 nparts;
+ get_col_endpoint_func get_col_endpoint;
+ DBUG_ENTER("get_part_iter_for_interval_cols_via_map");
+
+ if (part_info->part_type == RANGE_PARTITION)
+ {
+ get_col_endpoint= get_partition_id_cols_range_for_endpoint;
+ part_iter->get_next= get_next_partition_id_range;
+ }
+ else if (part_info->part_type == LIST_PARTITION)
+ {
+ get_col_endpoint= get_partition_id_cols_list_for_endpoint;
+ part_iter->get_next= get_next_partition_id_list;
+ part_iter->part_info= part_info;
+ DBUG_ASSERT(part_info->num_list_values);
+ }
+ else
+ assert(0);
+
+ if (flags & NO_MIN_RANGE)
+ part_iter->part_nums.start= part_iter->part_nums.cur= 0;
+ else
+ {
+ // Copy from min_value to record
+ nparts= store_tuple_to_record(part_info->part_field_array,
+ store_length_array,
+ min_value,
+ min_value + min_len);
+ part_iter->part_nums.start= part_iter->part_nums.cur=
+ get_col_endpoint(part_info, TRUE, !(flags & NEAR_MIN),
+ nparts);
+ }
+ if (flags & NO_MAX_RANGE)
+ {
+ if (part_info->part_type == RANGE_PARTITION)
+ part_iter->part_nums.end= part_info->num_parts;
+ else /* LIST_PARTITION */
+ {
+ DBUG_ASSERT(part_info->part_type == LIST_PARTITION);
+ part_iter->part_nums.end= part_info->num_list_values;
+ }
+ }
+ else
+ {
+ // Copy from max_value to record
+ nparts= store_tuple_to_record(part_info->part_field_array,
+ store_length_array,
+ max_value,
+ max_value + max_len);
+ part_iter->part_nums.end= get_col_endpoint(part_info, FALSE,
+ !(flags & NEAR_MAX),
+ nparts);
+ }
+ if (part_iter->part_nums.start == part_iter->part_nums.end)
+ DBUG_RETURN(0);
+ DBUG_RETURN(1);
+}
+
+
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)
{
- DBUG_ASSERT(!is_subpart);
Field *field= part_info->part_field_array[0];
uint32 max_endpoint_val;
get_endpoint_func get_endpoint;
bool can_match_multiple_values; /* is not '=' */
uint field_len= field->pack_length_in_rec();
+ DBUG_ENTER("get_part_iter_for_interval_via_mapping");
+ DBUG_ASSERT(!is_subpart);
+ (void) store_length_array;
+ (void)min_len;
+ (void)max_len;
part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE;
if (part_info->part_type == RANGE_PARTITION)
@@ -6746,7 +7347,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
get_endpoint= get_partition_id_range_for_endpoint_charset;
else
get_endpoint= get_partition_id_range_for_endpoint;
- max_endpoint_val= part_info->no_parts;
+ max_endpoint_val= part_info->num_parts;
part_iter->get_next= get_next_partition_id_range;
}
else if (part_info->part_type == LIST_PARTITION)
@@ -6756,7 +7357,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
get_endpoint= get_list_array_idx_for_endpoint_charset;
else
get_endpoint= get_list_array_idx_for_endpoint;
- max_endpoint_val= part_info->no_list_values;
+ max_endpoint_val= part_info->num_list_values;
part_iter->get_next= get_next_partition_id_list;
part_iter->part_info= part_info;
if (max_endpoint_val == 0)
@@ -6769,7 +7370,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
part_iter->part_nums.start= part_iter->part_nums.end= 0;
part_iter->part_nums.cur= 0;
part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
- return -1;
+ DBUG_RETURN(-1);
}
}
else
@@ -6801,11 +7402,11 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
{
part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
part_iter->part_nums.start= part_iter->part_nums.cur= 0;
- if (*max_value && !(flags & NO_MAX_RANGE))
+ if (!(flags & NO_MAX_RANGE) && *max_value)
{
/* The right bound is X <= NULL, i.e. it is a "X IS NULL" interval */
part_iter->part_nums.end= 0;
- return 1;
+ DBUG_RETURN(1);
}
}
else
@@ -6829,11 +7430,11 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
part_iter->part_nums.cur= part_iter->part_nums.start= 0;
part_iter->part_nums.end= 0;
part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
- return 1;
+ DBUG_RETURN(1);
}
part_iter->part_nums.cur= part_iter->part_nums.start;
if (part_iter->part_nums.start == max_endpoint_val)
- return 0; /* No partitions */
+ DBUG_RETURN(0); /* No partitions */
}
}
@@ -6847,9 +7448,9 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
part_iter->part_nums.end= get_endpoint(part_info, 0, include_endp);
if (part_iter->part_nums.start >= part_iter->part_nums.end &&
!part_iter->ret_null_part)
- return 0; /* No partitions */
+ DBUG_RETURN(0); /* No partitions */
}
- return 1; /* Ok, iterator initialized */
+ DBUG_RETURN(1); /* Ok, iterator initialized */
}
@@ -6897,25 +7498,32 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
*/
int get_part_iter_for_interval_via_walking(partition_info *part_info,
- bool is_subpart,
- uchar *min_value, uchar *max_value,
- uint flags,
- PARTITION_ITERATOR *part_iter)
+ 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;
partition_iter_func get_next_func;
+ DBUG_ENTER("get_part_iter_for_interval_via_walking");
+ (void)store_length_array;
+ (void)min_len;
+ (void)max_len;
+
part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE;
if (is_subpart)
{
field= part_info->subpart_field_array[0];
- total_parts= part_info->no_subparts;
+ total_parts= part_info->num_subparts;
get_next_func= get_next_subpartition_via_walking;
}
else
{
field= part_info->part_field_array[0];
- total_parts= part_info->no_parts;
+ total_parts= part_info->num_parts;
get_next_func= get_next_partition_via_walking;
}
@@ -6935,7 +7543,7 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info,
if (!part_info->get_subpartition_id(part_info, &part_id))
{
init_single_partition_iterator(part_id, part_iter);
- return 1; /* Ok, iterator initialized */
+ DBUG_RETURN(1); /* Ok, iterator initialized */
}
}
else
@@ -6948,10 +7556,10 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info,
if (!res)
{
init_single_partition_iterator(part_id, part_iter);
- return 1; /* Ok, iterator initialized */
+ DBUG_RETURN(1); /* Ok, iterator initialized */
}
}
- return 0; /* No partitions match */
+ DBUG_RETURN(0); /* No partitions match */
}
if ((field->real_maybe_null() &&
@@ -6959,7 +7567,7 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info,
(!(flags & NO_MAX_RANGE) && *max_value))) || // X <? NULL
(flags & (NO_MIN_RANGE | NO_MAX_RANGE))) // -inf at any bound
{
- return -1; /* Can't handle this interval, have to use all partitions */
+ DBUG_RETURN(-1); /* Can't handle this interval, have to use all partitions */
}
/* Get integers for left and right interval bound */
@@ -6978,7 +7586,7 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info,
an empty interval by "wrapping around" a + 4G-1 + 1 = a.
*/
if ((ulonglong)b - (ulonglong)a == ~0ULL)
- return -1;
+ DBUG_RETURN(-1);
a += test(flags & NEAR_MIN);
b += test(!(flags & NEAR_MAX));
@@ -7001,13 +7609,13 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info,
- there are not many values to enumerate.
*/
if ((n_values > 2*total_parts) && n_values > MAX_RANGE_TO_WALK)
- return -1;
+ DBUG_RETURN(-1);
part_iter->field_vals.start= part_iter->field_vals.cur= a;
part_iter->field_vals.end= b;
part_iter->part_info= part_info;
part_iter->get_next= get_next_func;
- return 1;
+ DBUG_RETURN(1);
}
@@ -7055,8 +7663,9 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter)
DESCRIPTION
This implementation of PARTITION_ITERATOR::get_next() is special for
- LIST partitioning: it enumerates partition ids in
- part_info->list_array[i] where i runs over [min_idx, max_idx] interval.
+ LIST partitioning: it enumerates partition ids in
+ part_info->list_array[i] (list_col_array[i] for COLUMNS LIST
+ partitioning) where i runs over [min_idx, max_idx] interval.
The function conforms to partition_iter_func type.
RETURN
@@ -7078,8 +7687,13 @@ uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter)
return NOT_A_PARTITION_ID;
}
else
- return part_iter->part_info->list_array[part_iter->
- part_nums.cur++].partition_id;
+ {
+ partition_info *part_info= part_iter->part_info;
+ uint32 num_part= part_iter->part_nums.cur++;
+ return part_info->column_list ?
+ part_info->list_col_array[num_part].partition_id :
+ part_info->list_array[num_part].partition_id;
+ }
}
@@ -7220,5 +7834,17 @@ void create_subpartition_name(char *out, const char *in1,
strxmov(out, in1, "#P#", transl_part_name,
"#SP#", transl_subpart_name, "#REN#", NullS);
}
+
+uint get_partition_field_store_length(Field *field)
+{
+ uint store_length;
+
+ store_length= field->key_length();
+ if (field->real_maybe_null())
+ store_length+= HA_KEY_NULL_LENGTH;
+ if (field->real_type() == MYSQL_TYPE_VARCHAR)
+ store_length+= HA_KEY_BLOB_LENGTH;
+ return store_length;
+}
#endif