diff options
author | Mikael Ronstrom <mikael@mysql.com> | 2009-10-22 16:15:06 +0200 |
---|---|---|
committer | Mikael Ronstrom <mikael@mysql.com> | 2009-10-22 16:15:06 +0200 |
commit | 66f056a64cadb601ca2b1d7821de4823b38c23cf (patch) | |
tree | 0bcd1e2792ff22088f2d5faa233170a48ebeb79a /sql | |
parent | 57d455460d52da8b124d839fb6462d55b0ca2ee7 (diff) | |
download | mariadb-git-66f056a64cadb601ca2b1d7821de4823b38c23cf.tar.gz |
A lot of fixes to make character set work ok, first step to fixing BUG#48163
Diffstat (limited to 'sql')
-rw-r--r-- | sql/mysql_priv.h | 7 | ||||
-rw-r--r-- | sql/partition_info.cc | 34 | ||||
-rw-r--r-- | sql/partition_info.h | 1 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 4 | ||||
-rw-r--r-- | sql/sql_partition.cc | 154 | ||||
-rw-r--r-- | sql/sql_partition.h | 4 | ||||
-rw-r--r-- | sql/sql_show.cc | 16 | ||||
-rw-r--r-- | sql/sql_table.cc | 64 |
8 files changed, 251 insertions, 33 deletions
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index f21c274a23a..7936bffda38 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1222,6 +1222,8 @@ int prepare_create_field(Create_field *sql_field, uint *blob_columns, int *timestamps, int *timestamps_with_niladic, longlong table_flags); +CHARSET_INFO* get_sql_field_charset(Create_field *sql_field, + HA_CREATE_INFO *create_info); bool mysql_create_table(THD *thd,const char *db, const char *table_name, HA_CREATE_INFO *create_info, Alter_info *alter_info, @@ -1611,6 +1613,11 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, handlerton *old_db_type, bool *partition_changed, uint *fast_alter_partition); +char *generate_partition_syntax(partition_info *part_info, + uint *buf_length, bool use_sql_alloc, + bool show_partition_options, + HA_CREATE_INFO *create_info, + Alter_info *alter_info); #endif /* bits for last argument to remove_table_from_cache() */ diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 3bce7dac1fa..131e1dcf3a6 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1876,6 +1876,34 @@ int partition_info::fix_func_partition(THD *thd, DBUG_RETURN(FALSE); } +/* + Get column item with a proper character set according to the field + + SYNOPSIS + get_column_item() + item Item object to start with + field Field for which the item will be compared to + + RETURN VALUES + NULL Error + item Returned item +*/ + +Item* partition_info::get_column_item(Item *item, Field *field) +{ + if (field->result_type() == STRING_RESULT && + item->collation.collation != field->charset()) + { + if (!(item= convert_charset_partition_constant(item, + field->charset()))) + { + my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); + return NULL; + } + } + return item; +} + /* Evaluate VALUES functions for column list values @@ -1921,6 +1949,12 @@ bool partition_info::fix_column_value_functions(THD *thd, { uchar *val_ptr; uint len= field->pack_length(); + if (!(column_item= get_column_item(column_item, + field))) + { + result= TRUE; + goto end; + } if (column_item->save_in_field(field, TRUE)) { my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0)); diff --git a/sql/partition_info.h b/sql/partition_info.h index ab9ee7c6931..4b37b34cecf 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -281,6 +281,7 @@ public: bool check_partition_function); void print_no_partition_found(TABLE *table); void print_debug(const char *str, uint*); + Item* get_column_item(Item *item, Field *field); int fix_func_partition(THD *thd, part_elem_value *val, partition_element *part_elem, diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 0bbdacee0bc..d65945013b9 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6207,7 +6207,7 @@ ER_TOO_MANY_CONCURRENT_TRXS WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED eng "Non-ASCII separator arguments are not fully supported" ER_SAME_NAME_PARTITION_FIELD - eng "Duplicate partition field name %-.192s" + eng "Duplicate partition field name '%-.192s'" ER_PARTITION_COLUMN_LIST_ERROR eng "Inconsistency in usage of column lists for partitioning" ER_WRONG_TYPE_COLUMN_VALUE_ERROR @@ -6220,3 +6220,5 @@ ER_TOO_MANY_VALUES_ERROR eng "Cannot have more than one value for this type of %-.64s partitioning" ER_ROW_SINGLE_PARTITION_FIELD_ERROR eng "Row expressions in VALUES IN only allowed for multi-field column partitioning" +ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD + eng "Field '%-.192s' is of a not allowed type for this type of partitioning" diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ab342c0a6fb..0a6a2b98941 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -151,6 +151,38 @@ static int cmp_rec_and_tuple_prune(part_column_list_val *val, #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 @@ -512,7 +544,9 @@ static bool set_up_field_array(TABLE *table, do { field_name= it++; - if (!strcmp(field_name, field->field_name)) + if (!my_strcasecmp(system_charset_info, + field_name, + field->field_name)) break; } while (++inx < num_fields); if (inx == num_fields) @@ -1984,11 +2018,67 @@ static int add_partition_options(File fptr, partition_element *p_elem) return err + add_engine(fptr,p_elem->engine_type); } +static int check_part_field(Create_field *sql_field, + bool *need_cs_check) +{ + *need_cs_check= FALSE; + if (sql_field->sql_type == MYSQL_TYPE_TIMESTAMP) + goto error; + if (sql_field->sql_type < MYSQL_TYPE_VARCHAR || + sql_field->sql_type == MYSQL_TYPE_NEWDECIMAL) + return FALSE; + if (sql_field->sql_type >= MYSQL_TYPE_TINY_BLOB && + sql_field->sql_type <= MYSQL_TYPE_BLOB) + { + my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0)); + return TRUE; + } + switch (sql_field->sql_type) + { + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + if (sql_field->length > MAX_STR_SIZE_PF) + goto error; + *need_cs_check= TRUE; + return FALSE; + break; + default: + goto error; + } +error: + my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0), + sql_field->field_name); + return TRUE; +} + +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) + 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); @@ -1998,6 +2088,7 @@ static int add_column_list_values(File fptr, partition_info *part_info, 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) @@ -2011,7 +2102,45 @@ static int add_column_list_values(File fptr, partition_info *part_info, err+= add_string(fptr, "NULL"); else { - String *res= item_expr->val_str(&str); + String *res; + CHARSET_INFO *field_cs; + + /* + 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; + bool need_cs_check= FALSE; + + 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, &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_cs= part_info->part_field_array[i]->charset(); + 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; + } + } + res= item_expr->val_str(&str); if (!res) { my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); @@ -2033,7 +2162,9 @@ static int add_column_list_values(File fptr, partition_info *part_info, } static int add_partition_values(File fptr, partition_info *part_info, - partition_element *p_elem) + partition_element *p_elem, + HA_CREATE_INFO *create_info, + Alter_info *alter_info) { int err= 0; @@ -2045,7 +2176,8 @@ static int add_partition_values(File fptr, partition_info *part_info, 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); - err+= add_column_list_values(fptr, part_info, list_value); + err+= add_column_list_values(fptr, part_info, list_value, + create_info, alter_info); err+= add_end_parenthesis(fptr); } else @@ -2087,7 +2219,8 @@ static int add_partition_values(File fptr, partition_info *part_info, part_elem_value *list_value= list_val_it++; if (part_info->column_list) - err+= add_column_list_values(fptr, part_info, list_value); + err+= add_column_list_values(fptr, part_info, list_value, + create_info, alter_info); else { if (!list_value->unsigned_flag) @@ -2116,6 +2249,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 @@ -2144,7 +2279,9 @@ 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_num_parts, num_subparts; partition_element *part_elem; @@ -2263,7 +2400,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) { diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 47e5df0443f..0dac13a3fcc 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -67,9 +67,6 @@ bool check_partition_info(partition_info *part_info,handlerton **eng_type, TABLE *table, handler *file, HA_CREATE_INFO *info); void set_linear_hash_mask(partition_info *part_info, uint num_parts); bool fix_partition_func(THD *thd, TABLE *table, bool create_table_ind); -char *generate_partition_syntax(partition_info *part_info, - uint *buf_length, bool use_sql_alloc, - bool show_partition_options); bool partition_key_modified(TABLE *table, const MY_BITMAP *fields); void get_partition_set(const TABLE *table, uchar *buf, const uint index, const key_range *key_spec, @@ -96,6 +93,7 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, bool check_part_func_fields(Field **ptr, bool ok_with_charsets); bool field_is_partition_charset(Field *field); +Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs); /* A "Get next" function for partition iterator. diff --git a/sql/sql_show.cc b/sql/sql_show.cc index a74e9363bcf..57ab04b5576 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1465,7 +1465,8 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, ((part_syntax= generate_partition_syntax(table->part_info, &part_syntax_len, FALSE, - show_table_options)))) + show_table_options, + NULL, NULL)))) { packet->append(STRING_WITH_LEN("\n/*!50100")); packet->append(part_syntax, part_syntax_len); @@ -4847,16 +4848,23 @@ get_partition_column_description(partition_info *part_info, { char buffer[MAX_STR_SIZE_PF]; String str(buffer, sizeof(buffer), &my_charset_bin); - String *res= col_val->item_expression->val_str(&str); + Item *item= col_val->item_expression; + + if (!(item= part_info->get_column_item(item, + part_info->part_field_array[i]))) + { + DBUG_RETURN(1); + } + String *res= item->val_str(&str); if (!res) { my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); DBUG_RETURN(1); } - if (col_val->item_expression->result_type() == STRING_RESULT) + if (item->result_type() == STRING_RESULT) tmp_str.append("'"); tmp_str.append(*res); - if (col_val->item_expression->result_type() == STRING_RESULT) + if (item->result_type() == STRING_RESULT) tmp_str.append("'"); } if (i != num_elements - 1) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 036db44d7dc..313503b6f3a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1583,7 +1583,9 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) { if (!(part_syntax_buf= generate_partition_syntax(part_info, &syntax_len, - TRUE, TRUE))) + TRUE, TRUE, + lpt->create_info, + lpt->alter_info))) { DBUG_RETURN(TRUE); } @@ -1675,7 +1677,9 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) char *tmp_part_syntax_str; if (!(part_syntax_buf= generate_partition_syntax(part_info, &syntax_len, - TRUE, TRUE))) + TRUE, TRUE, + lpt->create_info, + lpt->alter_info))) { error= 1; goto err; @@ -2494,6 +2498,39 @@ int prepare_create_field(Create_field *sql_field, DBUG_RETURN(0); } + +/* + Get character set from field object generated by parser using + default values when not set. + + SYNOPSIS + get_sql_field_charset() + sql_field The sql_field object + create_info Info generated by parser + + RETURN VALUES + cs Character set +*/ + +CHARSET_INFO* get_sql_field_charset(Create_field *sql_field, + HA_CREATE_INFO *create_info) +{ + CHARSET_INFO *cs= sql_field->charset; + + if (!cs) + cs= create_info->default_table_charset; + /* + table_charset is set only in ALTER TABLE t1 CONVERT TO CHARACTER SET csname + if we want change character set for all varchar/char columns. + But the table charset must not affect the BLOB fields, so don't + allow to change my_charset_bin to somethig else. + */ + if (create_info->table_charset && cs != &my_charset_bin) + cs= create_info->table_charset; + return cs; +} + + /* Preparation for table creation @@ -2557,18 +2594,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, executing a prepared statement for the second time. */ sql_field->length= sql_field->char_length; - if (!sql_field->charset) - sql_field->charset= create_info->default_table_charset; - /* - table_charset is set in ALTER TABLE if we want change character set - for all varchar/char columns. - But the table charset must not affect the BLOB fields, so don't - allow to change my_charset_bin to somethig else. - */ - if (create_info->table_charset && sql_field->charset != &my_charset_bin) - sql_field->charset= create_info->table_charset; - - save_cs= sql_field->charset; + save_cs= sql_field->charset= get_sql_field_charset(sql_field, + create_info); if ((sql_field->flags & BINCMP_FLAG) && !(sql_field->charset= get_charset_by_csname(sql_field->charset->csname, MY_CS_BINSORT,MYF(0)))) @@ -3617,6 +3644,9 @@ bool mysql_create_table_no_lock(THD *thd, } if (check_engine(thd, table_name, create_info)) DBUG_RETURN(TRUE); + + set_table_default_charset(thd, create_info, (char*) db); + db_options= create_info->table_options; if (create_info->row_type == ROW_TYPE_DYNAMIC) db_options|=HA_OPTION_PACK_RECORD; @@ -3720,7 +3750,9 @@ bool mysql_create_table_no_lock(THD *thd, */ if (!(part_syntax_buf= generate_partition_syntax(part_info, &syntax_len, - TRUE, TRUE))) + TRUE, TRUE, + create_info, + alter_info))) goto err; part_info->part_info_string= part_syntax_buf; part_info->part_info_len= syntax_len; @@ -3787,8 +3819,6 @@ bool mysql_create_table_no_lock(THD *thd, } #endif - set_table_default_charset(thd, create_info, (char*) db); - if (mysql_prepare_create_table(thd, create_info, alter_info, internal_tmp_table, &db_options, file, |