diff options
-rw-r--r-- | mysql-test/r/partition.result | 5 | ||||
-rw-r--r-- | sql/partition_info.cc | 168 | ||||
-rw-r--r-- | sql/partition_info.h | 18 | ||||
-rw-r--r-- | sql/sql_partition.cc | 195 | ||||
-rw-r--r-- | sql/sql_partition.h | 3 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 5 |
6 files changed, 241 insertions, 153 deletions
diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index d8d433ef216..97d6275a835 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -1,9 +1,4 @@ drop table if exists t1; -create table t1 (s1 char(2) character set utf8) -partition by list (case when s1 > 'cz' then 1 else 2 end) -(partition p1 values in (1), -partition p2 values in (2)); -drop table t1; create table t1 (a int) partition by key(a) partitions 0.2+e1; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index c8cf38e5629..724464125ea 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -859,5 +859,171 @@ void partition_info::print_no_partition_found(TABLE *table) my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0), buf_ptr); dbug_tmp_restore_column_map(table->read_set, old_map); } +/* + Set up buffers and arrays for fields requiring preparation + SYNOPSIS + set_up_charset_field_preps() + part_info Partition info object + RETURN VALUES + TRUE Memory Allocation error + FALSE Success + DESCRIPTION + Set up arrays and buffers for fields that require special care for + calculation of partition id. This is used for string fields with + variable length or string fields with fixed length that isn't using + the binary collation. +*/ -#endif /* WITH_PARTITION_STORAGE_ENGINE */ +bool partition_info::set_up_charset_field_preps() +{ + Field *field, **ptr; + char *field_buf; + char **char_ptrs; + unsigned i; + bool found; + size_t size; + uint tot_fields= 0; + uint tot_part_fields= 0; + uint tot_subpart_fields= 0; + DBUG_ENTER("set_up_charset_field_preps"); + + if (!(part_type == HASH_PARTITION && + list_of_part_fields) && + check_part_func_fields(part_field_array, FALSE)) + { + ptr= part_field_array; + /* Set up arrays and buffers for those fields */ + i= 0; + while ((field= *(ptr++))) + { + if (field_is_partition_charset(field)) + { + tot_part_fields++; + tot_fields++; + } + } + size= tot_part_fields * sizeof(char*); + if (!(char_ptrs= (char**)sql_calloc(size))) + goto error; + part_field_buffers= char_ptrs; + if (!(char_ptrs= (char**)sql_calloc(size))) + goto error; + restore_part_field_ptrs= char_ptrs; + size= (tot_part_fields + 1) * sizeof(Field*); + if (!(char_ptrs= (char**)sql_alloc(size))) + goto error; + part_charset_field_array= (Field**)char_ptrs; + ptr= part_field_array; + i= 0; + while ((field= *(ptr++))) + { + if (field_is_partition_charset(field)) + { + CHARSET_INFO *cs= ((Field_str*)field)->charset(); + size= field->pack_length(); + if (!(field_buf= sql_calloc(size))) + goto error; + part_charset_field_array[i]= field; + part_field_buffers[i++]= field_buf; + } + } + part_charset_field_array[i]= NULL; + } + if (is_sub_partitioned() && list_of_subpart_fields && + check_part_func_fields(subpart_field_array, FALSE)) + { + /* Set up arrays and buffers for those fields */ + ptr= subpart_field_array; + while ((field= *(ptr++))) + { + if (field_is_partition_charset(field)) + tot_subpart_fields++; + } + size= tot_subpart_fields * sizeof(char*); + if (!(char_ptrs= (char**)sql_calloc(size))) + goto error; + subpart_field_buffers= char_ptrs; + if (!(char_ptrs= (char**)sql_calloc(size))) + goto error; + restore_subpart_field_ptrs= char_ptrs; + size= (tot_subpart_fields + 1) * sizeof(Field*); + if (!(char_ptrs= (char**)sql_alloc(size))) + goto error; + subpart_charset_field_array= (Field**)char_ptrs; + i= 0; + while ((field= *(ptr++))) + { + unsigned j= 0; + Field *part_field; + CHARSET_INFO *cs; + + if (!field_is_partition_charset(field)) + continue; + cs= ((Field_str*)field)->charset(); + size= field->pack_length(); + found= FALSE; + for (j= 0; j < tot_part_fields; j++) + { + if (field == part_charset_field_array[i]) + found= TRUE; + } + if (!found) + { + tot_fields++; + if (!(field_buf= sql_calloc(size))) + goto error; + } + subpart_field_buffers[i++]= field_buf; + } + if (!(char_ptrs= (char**)sql_calloc(size))) + goto error; + restore_subpart_field_ptrs= char_ptrs; + } + if (tot_fields) + { + Field *part_field, *subpart_field; + uint j,k,l; + + size= tot_fields*sizeof(char**); + if (!(char_ptrs= (char**)sql_calloc(size))) + goto error; + full_part_field_buffers= char_ptrs; + if (!(char_ptrs= (char**)sql_calloc(size))) + goto error; + restore_full_part_field_ptrs= char_ptrs; + size= (tot_fields + 1) * sizeof(char**); + if (!(char_ptrs= (char**)sql_calloc(size))) + goto error; + full_part_charset_field_array= (Field**)char_ptrs; + for (i= 0; i < tot_part_fields; i++) + { + full_part_charset_field_array[i]= part_charset_field_array[i]; + full_part_field_buffers[i]= part_field_buffers[i]; + } + k= tot_part_fields; + l= 0; + for (i= 0; i < tot_subpart_fields; i++) + { + field= subpart_charset_field_array[i]; + found= FALSE; + for (j= 0; j < tot_part_fields; j++) + { + if (field == part_charset_field_array[i]) + found= TRUE; + } + if (!found) + { + full_part_charset_field_array[l]= subpart_charset_field_array[k]; + full_part_field_buffers[l]= subpart_field_buffers[k]; + k++; l++; + } + } + full_part_charset_field_array[tot_fields]= NULL; + } + DBUG_RETURN(FALSE); +error: + mem_alloc_error(size); + DBUG_RETURN(TRUE); +} +#endif + /* WITH_PARTITION_STORAGE_ENGINE */ diff --git a/sql/partition_info.h b/sql/partition_info.h index 91beaf569e0..b45789c4bae 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -73,14 +73,15 @@ public: /* NULL-terminated array of fields used in partitioned expression */ Field **part_field_array; - /* NULL-terminated array of fields used in subpartitioned expression */ Field **subpart_field_array; - + Field **part_charset_field_array; + Field **subpart_charset_field_array; /* Array of all fields used in partition and subpartition expression, without duplicates, NULL-terminated. */ Field **full_part_field_array; + Field **full_part_charset_field_array; /* When we have a field that requires transformation before calling the @@ -89,8 +90,10 @@ public: */ char **part_field_buffers; char **subpart_field_buffers; + char **full_part_field_buffers; char **restore_part_field_ptrs; char **restore_subpart_field_ptrs; + char **restore_full_part_field_ptrs; Item *part_expr; Item *subpart_expr; @@ -208,17 +211,20 @@ public: bool is_auto_partitioned; bool from_openfrm; bool has_null_value; - bool includes_charset_field_part; - bool includes_charset_field_subpart; partition_info() : get_partition_id(NULL), get_part_partition_id(NULL), get_subpartition_id(NULL), part_field_array(NULL), subpart_field_array(NULL), + part_charset_field_array(NULL), + subpart_charset_field_array(NULL), full_part_field_array(NULL), + full_part_charset_field_array(NULL), part_field_buffers(NULL), subpart_field_buffers(NULL), + full_part_field_buffers(NULL), restore_part_field_ptrs(NULL), restore_subpart_field_ptrs(NULL), + restore_full_part_field_ptrs(NULL), part_expr(NULL), subpart_expr(NULL), item_free_list(NULL), first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL), list_array(NULL), @@ -241,8 +247,7 @@ public: list_of_part_fields(FALSE), list_of_subpart_fields(FALSE), linear_hash_ind(FALSE), fixed(FALSE), is_auto_partitioned(FALSE), from_openfrm(FALSE), - has_null_value(FALSE), includes_charset_field_part(FALSE), - includes_charset_field_subpart(FALSE) + has_null_value(FALSE) { all_fields_in_PF.clear_all(); all_fields_in_PPF.clear_all(); @@ -278,6 +283,7 @@ public: handler *file, HA_CREATE_INFO *info, bool check_partition_function); void print_no_partition_found(TABLE *table); + bool set_up_charset_field_preps(); private: static int list_part_cmp(const void* a, const void* b); static int list_part_cmp_unsigned(const void* a, const void* b); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index eb431134d9d..796f018e04b 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1346,20 +1346,19 @@ static void set_up_partition_func_pointers(partition_info *part_info) } } } - if (part_info->includes_charset_field_part || - part_info->includes_charset_field_subpart) + 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->includes_charset_field_part && - part_info->includes_charset_field_subpart) + 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->includes_charset_field_part) + 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->includes_charset_field_part && + if (part_info->part_charset_field_array && part_info->is_sub_partitioned()) { DBUG_ASSERT(part_info->get_part_partition_id); @@ -1367,7 +1366,7 @@ static void set_up_partition_func_pointers(partition_info *part_info) part_info->get_part_partition_id; part_info->get_part_partition_id= get_part_part_id_charset_func; } - if (part_info->includes_charset_field_subpart) + if (part_info->subpart_charset_field_array) { DBUG_ASSERT(part_info->get_subpartition_id); part_info->get_subpartition_id_charset= @@ -1436,6 +1435,32 @@ static uint32 get_part_id_from_linear_hash(longlong hash_value, uint mask, /* + Check if a particular field is in need of character set + handling for partition functions. + SYNOPSIS + field_is_partition_charset() + field The field to check + RETURN VALUES + FALSE Not in need of character set handling + TRUE In need of character set handling +*/ + +bool field_is_partition_charset(Field *field) +{ + if (!field->type() == MYSQL_TYPE_STRING && + !field->type() == MYSQL_TYPE_VARCHAR) + return FALSE; + { + CHARSET_INFO *cs= ((Field_str*)field)->charset(); + if (!field->type() == MYSQL_TYPE_STRING || + !(cs->state & MY_CS_BINSORT)) + return TRUE; + return FALSE; + } +} + + +/* Check that partition function do not contain any forbidden character sets and collations. SYNOPSIS @@ -1453,7 +1478,7 @@ static uint32 get_part_id_from_linear_hash(longlong hash_value, uint mask, calling the functions to calculate partition id. */ -static bool check_part_func_fields(Field **ptr, bool ok_with_charsets) +bool check_part_func_fields(Field **ptr, bool ok_with_charsets) { Field *field; DBUG_ENTER("check_part_func_field"); @@ -1465,13 +1490,9 @@ static bool check_part_func_fields(Field **ptr, bool ok_with_charsets) Binary collation with CHAR is automatically supported. Other types need some kind of standardisation function handling */ - if (field->type() == MYSQL_TYPE_STRING || - field->type() == MYSQL_TYPE_VARCHAR) + if (field_is_partition_charset(field)) { CHARSET_INFO *cs= ((Field_str*)field)->charset(); - if (field->type() == MYSQL_TYPE_STRING && - cs->state & MY_CS_BINSORT) - continue; if (!ok_with_charsets || cs->mbmaxlen > 1 || cs->strxfrm_multiply > 1) @@ -1483,106 +1504,6 @@ static bool check_part_func_fields(Field **ptr, bool ok_with_charsets) DBUG_RETURN(FALSE); } -/* - Set up buffers and arrays for fields requiring preparation - SYNOPSIS - set_up_charset_field_preps() - part_info Partition info object - RETURN VALUES - TRUE Memory Allocation error - FALSE Success - DESCRIPTION - Set up arrays and buffers for fields that require special care for - calculation of partition id. This is used for string fields with - variable length or string fields with fixed length that isn't using - the binary collation. -*/ - -static bool set_up_charset_field_preps(partition_info *part_info) -{ - Field *field, **ptr; - char *field_buf; - char **char_ptrs; - unsigned i; - size_t size; - - DBUG_ENTER("set_up_charset_field_preps"); - if (check_part_func_fields(part_info->part_field_array, FALSE)) - { - ptr= part_info->part_field_array; - part_info->includes_charset_field_part= TRUE; - /* - Set up arrays and buffers for those fields - */ - i= 0; - while ((field= *(ptr++))) - i++; - size= i * sizeof(char*); - - if (!(char_ptrs= (char**)sql_calloc(size))) - goto error; - part_info->part_field_buffers= char_ptrs; - - if (!(char_ptrs= (char**)sql_calloc(size))) - goto error; - part_info->restore_part_field_ptrs= char_ptrs; - - ptr= part_info->part_field_array; - i= 0; - while ((field= *(ptr++))) - { - CHARSET_INFO *cs= ((Field_str*)field)->charset(); - size= field->pack_length(); - if (!(field_buf= sql_calloc(size))) - goto error; - part_info->part_field_buffers[i++]= field_buf; - } - } - if (part_info->is_sub_partitioned() && - check_part_func_fields(part_info->subpart_field_array, FALSE)) - { - /* - Set up arrays and buffers for those fields - */ - part_info->includes_charset_field_subpart= TRUE; - - ptr= part_info->subpart_field_array; - i= 0; - while ((field= *(ptr++))) - { - unsigned j= 0; - Field *part_field; - Field **part_ptr= part_info->part_field_array; - bool field_already_have_buffer= FALSE; - CHARSET_INFO *cs= ((Field_str*)field)->charset(); - size= field->pack_length(); - - while ((part_field= *(part_ptr++))) - { - field_buf= part_info->part_field_buffers[j++]; - if (field == part_field) - { - field_already_have_buffer= TRUE; - break; - } - } - if (!field_already_have_buffer) - { - if (!(field_buf= sql_calloc(size))) - goto error; - } - part_info->subpart_field_buffers[i++]= field_buf; - } - size= i * sizeof(char*); - if (!(char_ptrs= (char**)sql_calloc(i * sizeof(char*)))) - goto error; - part_info->restore_subpart_field_ptrs= char_ptrs; - } - DBUG_RETURN(FALSE); -error: - mem_alloc_error(size); - DBUG_RETURN(TRUE); -} /* fix partition functions @@ -1747,7 +1668,7 @@ bool fix_partition_func(THD *thd, TABLE *table, goto end; if (unlikely(set_up_partition_bitmap(thd, part_info))) goto end; - if (unlikely(set_up_charset_field_preps(part_info))) + if (unlikely(part_info->set_up_charset_field_preps())) { my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); goto end; @@ -2491,10 +2412,7 @@ static void copy_to_part_field_buffers(Field **ptr, { *restore_ptr= field->ptr; restore_ptr++; - if ((field->type() == MYSQL_TYPE_VARCHAR || - (field->type() == MYSQL_TYPE_STRING && - (!(((Field_str*)field)->charset()->state & MY_CS_BINSORT))) && - ((!field->maybe_null()) || (!field->is_null())))) + if (!field->maybe_null() || !field->is_null()) { CHARSET_INFO *cs= ((Field_str*)field)->charset(); uint len= field->pack_length(); @@ -2628,74 +2546,75 @@ static int get_part_id_charset_func_subpart(partition_info *part_info, longlong *func_value) { int res; - copy_to_part_field_buffers(part_info->subpart_field_array, + 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_field_array, + 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_field_array, + 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_field_array, + 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->part_field_array, - part_info->part_field_buffers, - part_info->restore_part_field_ptrs); - copy_to_part_field_buffers(part_info->subpart_field_array, - part_info->subpart_field_buffers, - part_info->restore_subpart_field_ptrs); + 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->part_field_array, - part_info->restore_part_field_ptrs); - restore_part_field_pointers(part_info->subpart_field_array, - part_info->restore_subpart_field_ptrs); + restore_part_field_pointers(part_info->full_part_field_array, + part_info->restore_full_part_field_ptrs); return res; } + 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_field_array, + 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_part_partition_id_charset(part_info, part_id, func_value); - restore_part_field_pointers(part_info->part_field_array, + restore_part_field_pointers(part_info->part_charset_field_array, part_info->restore_part_field_ptrs); return res; } + static uint32 get_subpart_id_charset_func(partition_info *part_info) { int res; - copy_to_part_field_buffers(part_info->subpart_field_array, + 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); - restore_part_field_pointers(part_info->subpart_field_array, + restore_part_field_pointers(part_info->subpart_charset_field_array, part_info->restore_subpart_field_ptrs); return res; } + int get_partition_id_list(partition_info *part_info, uint32 *part_id, longlong *func_value) @@ -6782,7 +6701,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, if (part_info->part_type == RANGE_PARTITION) { - if (part_info->includes_charset_field_part) + if (part_info->part_charset_field_array) get_endpoint= get_partition_id_range_for_endpoint_charset; else get_endpoint= get_partition_id_range_for_endpoint; @@ -6792,7 +6711,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, else if (part_info->part_type == LIST_PARTITION) { - if (part_info->includes_charset_field_part) + if (part_info->part_charset_field_array) get_endpoint= get_list_array_idx_for_endpoint_charset; else get_endpoint= get_list_array_idx_for_endpoint; diff --git a/sql/sql_partition.h b/sql/sql_partition.h index e34d71dfdc5..c5b930162a9 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -93,6 +93,9 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info, bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, bool is_sub_part, bool is_field_to_be_setup); +bool check_part_func_fields(Field **ptr, bool ok_with_charsets); +bool field_is_partition_charset(Field *field); + /* A "Get next" function for partition iterator. diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index aedbb2fc894..fd53983c33f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3618,9 +3618,8 @@ part_bit_expr: mem_alloc_error(sizeof(part_elem_value)); YYABORT; } - part_expr->walk(&Item::check_partition_func_processor, 0, - (byte*)(&part_expression_ok)); - if (!part_expression_ok) + if (part_expr->walk(&Item::check_partition_func_processor, 0, + NULL)) { my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); YYABORT; |