summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorMikael Ronstrom <mikael@mysql.com>2009-10-22 16:15:06 +0200
committerMikael Ronstrom <mikael@mysql.com>2009-10-22 16:15:06 +0200
commit66f056a64cadb601ca2b1d7821de4823b38c23cf (patch)
tree0bcd1e2792ff22088f2d5faa233170a48ebeb79a /sql
parent57d455460d52da8b124d839fb6462d55b0ca2ee7 (diff)
downloadmariadb-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.h7
-rw-r--r--sql/partition_info.cc34
-rw-r--r--sql/partition_info.h1
-rw-r--r--sql/share/errmsg.txt4
-rw-r--r--sql/sql_partition.cc154
-rw-r--r--sql/sql_partition.h4
-rw-r--r--sql/sql_show.cc16
-rw-r--r--sql/sql_table.cc64
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,