From 66f056a64cadb601ca2b1d7821de4823b38c23cf Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 22 Oct 2009 16:15:06 +0200 Subject: [PATCH] A lot of fixes to make character set work ok, first step to fixing BUG#48163 --- mysql-test/r/partition_column.result | 130 ++++++++++++++++------ mysql-test/t/partition_column.test | 59 +++++++--- sql/mysql_priv.h | 7 ++ sql/partition_info.cc | 34 ++++++ sql/partition_info.h | 1 + sql/share/errmsg.txt | 4 +- sql/sql_partition.cc | 154 +++++++++++++++++++++++++-- sql/sql_partition.h | 4 +- sql/sql_show.cc | 16 ++- sql/sql_table.cc | 64 ++++++++--- 10 files changed, 397 insertions(+), 76 deletions(-) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index f1bb0a3488a..4270af1f83b 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -1,4 +1,32 @@ drop table if exists t1; +create table t1 (a int, b char(10), c varchar(25), d datetime) +partition by range column_list(a,b,c,d) +subpartition by hash (to_seconds(d)) +subpartitions 4 +( partition p0 values less than (1, 0, MAXVALUE, 0), +partition p1 values less than (1, 'a', MAXVALUE, TO_DAYS('1999-01-01')), +partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE), +partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE)); +select partition_method, partition_expression, partition_description +from information_schema.partitions where table_name = "t1"; +partition_method partition_expression partition_description +RANGE COLUMN_LIST a,b,c,d 1,'0',MAXVALUE,0 +RANGE COLUMN_LIST a,b,c,d 1,'0',MAXVALUE,0 +RANGE COLUMN_LIST a,b,c,d 1,'0',MAXVALUE,0 +RANGE COLUMN_LIST a,b,c,d 1,'0',MAXVALUE,0 +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE +drop table t1; create table t1 (a int, b int) partition by range column_list (a,b) (partition p0 values less than (NULL, maxvalue)); @@ -8,12 +36,19 @@ partition by list column_list(a,b) ( partition p0 values in ((maxvalue, 0))); Got one of the listed errors create table t1 (a int, b int) +partition by list column_list (a,b) +( partition p0 values in ((0,0))); +alter table t1 add partition +(partition p1 values in (maxvalue, maxvalue)); +Got one of the listed errors +drop table t1; +create table t1 (a int, b int) partition by key (a,a); -ERROR HY000: Duplicate partition field name a +ERROR HY000: Duplicate partition field name 'a' create table t1 (a int, b int) partition by list column_list(a,a) ( partition p values in ((1,1))); -ERROR HY000: Duplicate partition field name a +ERROR HY000: Duplicate partition field name 'a' create table t1 (a int signed) partition by list (a) ( partition p0 values in (1, 3, 5, 7, 9, NULL), @@ -61,6 +96,16 @@ partition_method partition_expression partition_description LIST COLUMN_LIST a,b (1,NULL),(2,NULL),(NULL,NULL) LIST COLUMN_LIST a,b (1,1),(2,2) LIST COLUMN_LIST a,b (3,NULL),(NULL,1) +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY LIST COLUMN_LIST(a,b) +(PARTITION p0 VALUES IN ((1,NULL),(2,NULL),(NULL,NULL)) ENGINE = MyISAM, + PARTITION p1 VALUES IN ((1,1),(2,2)) ENGINE = MyISAM, + PARTITION p2 VALUES IN ((3,NULL),(NULL,1)) ENGINE = MyISAM) */ insert into t1 values (3, NULL); insert into t1 values (NULL, 1); insert into t1 values (NULL, NULL); @@ -110,6 +155,14 @@ from information_schema.partitions where table_name = "t1"; partition_method partition_expression partition_description LIST a 2,1 LIST a NULL,4,3 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY LIST (a) +(PARTITION p0 VALUES IN (2,1) ENGINE = MyISAM, + PARTITION p1 VALUES IN (NULL,4,3) ENGINE = MyISAM) */ insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); @@ -132,6 +185,14 @@ from information_schema.partitions where table_name = "t1"; partition_method partition_expression partition_description LIST COLUMN_LIST a 2,1 LIST COLUMN_LIST a 4,NULL,3 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY LIST COLUMN_LIST(a) +(PARTITION p0 VALUES IN (2,1) ENGINE = MyISAM, + PARTITION p1 VALUES IN (4,NULL,3) ENGINE = MyISAM) */ insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); @@ -148,34 +209,6 @@ t1 CREATE TABLE `t1` ( (PARTITION p0 VALUES IN (2,1) ENGINE = MyISAM, PARTITION p1 VALUES IN (4,NULL,3) ENGINE = MyISAM) */ drop table t1; -create table t1 (a int, b char(10), c varchar(25), d datetime) -partition by range column_list(a,b,c,d) -subpartition by hash (to_seconds(d)) -subpartitions 4 -( partition p0 values less than (1, 0, MAXVALUE, 0), -partition p1 values less than (1, 'a', MAXVALUE, TO_DAYS('1999-01-01')), -partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE), -partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE)); -select partition_method, partition_expression, partition_description -from information_schema.partitions where table_name = "t1"; -partition_method partition_expression partition_description -RANGE COLUMN_LIST a,b,c,d 1,0,MAXVALUE,0 -RANGE COLUMN_LIST a,b,c,d 1,0,MAXVALUE,0 -RANGE COLUMN_LIST a,b,c,d 1,0,MAXVALUE,0 -RANGE COLUMN_LIST a,b,c,d 1,0,MAXVALUE,0 -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE -RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE -RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE -RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE -RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE -drop table t1; create table t1 (a int, b char(10), c varchar(5), d int) partition by range column_list(a,b,c) subpartition by key (c,d) @@ -199,6 +232,21 @@ RANGE COLUMN_LIST a,b,c 3,'abc','abc' RANGE COLUMN_LIST a,b,c 4,'abc','abc' RANGE COLUMN_LIST a,b,c 4,'abc','abc' RANGE COLUMN_LIST a,b,c 4,'abc','abc' +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` char(10) DEFAULT NULL, + `c` varchar(5) DEFAULT NULL, + `d` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE COLUMN_LIST(a,b,c) +SUBPARTITION BY KEY (c,d) +SUBPARTITIONS 3 +(PARTITION p0 VALUES LESS THAN (1,'abc','abc') ENGINE = MyISAM, + PARTITION p1 VALUES LESS THAN (2,'abc','abc') ENGINE = MyISAM, + PARTITION p2 VALUES LESS THAN (3,'abc','abc') ENGINE = MyISAM, + PARTITION p3 VALUES LESS THAN (4,'abc','abc') ENGINE = MyISAM) */ insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3); insert into t1 values (1,'b','c',1),(2,'b','c',2),(3,'b','c',3); insert into t1 values (1,'c','d',1),(2,'c','d',2),(3,'c','d',3); @@ -218,6 +266,16 @@ from information_schema.partitions where table_name = "t1"; partition_method partition_expression partition_description RANGE COLUMN_LIST a,b,c 1,'A',1 RANGE COLUMN_LIST a,b,c 1,'B',1 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` varchar(2) DEFAULT NULL, + `c` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE COLUMN_LIST(a,b,c) +(PARTITION p0 VALUES LESS THAN (1,'A',1) ENGINE = MyISAM, + PARTITION p1 VALUES LESS THAN (1,'B',1) ENGINE = MyISAM) */ insert into t1 values (1, 'A', 1); explain partitions select * from t1 where a = 1 AND b <= 'A' and c = 1; id select_type table partitions type possible_keys key key_len ref rows Extra @@ -234,11 +292,21 @@ select * from t1 where a = 'a'; a b c a NULL NULL drop table t1; -create table t1 (d timestamp) +create table t1 (d time) partition by range column_list(d) ( partition p0 values less than ('2000-01-01'), partition p1 values less than ('2040-01-01')); ERROR HY000: Partition column values of incorrect type +create table t1 (d timestamp) +partition by range column_list(d) +( partition p0 values less than ('2000-01-01'), +partition p1 values less than ('2040-01-01')); +ERROR HY000: Field 'd' is of a not allowed type for this type of partitioning +create table t1 (d bit(1)) +partition by range column_list(d) +( partition p0 values less than (0), +partition p1 values less than (1)); +ERROR HY000: Field 'd' is of a not allowed type for this type of partitioning create table t1 (a int, b int) partition by range column_list(a,b) (partition p0 values less than (maxvalue, 10)); diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index baeed6bb0a8..13f422d32f4 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -8,6 +8,29 @@ drop table if exists t1; --enable_warnings +create table t1 (a int, b char(10), c varchar(25), d datetime) +partition by range column_list(a,b,c,d) +subpartition by hash (to_seconds(d)) +subpartitions 4 +( partition p0 values less than (1, 0, MAXVALUE, 0), + partition p1 values less than (1, 'a', MAXVALUE, TO_DAYS('1999-01-01')), + partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE), + partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE)); +select partition_method, partition_expression, partition_description + from information_schema.partitions where table_name = "t1"; +#show create table t1; +drop table t1; + +# +# BUG#48163, Dagger in UCS2 not working as partition value +# +#create table t1 (a varchar(2) character set ucs2) +#partition by list column_list (a) +#(partition p0 values in (0x2020), +# partition p1 values in ('')); +#insert into t1 values (''); +#drop table t1; + --error ER_NULL_IN_VALUES_LESS_THAN create table t1 (a int, b int) partition by range column_list (a,b) @@ -18,6 +41,13 @@ create table t1 (a int, b int) partition by list column_list(a,b) ( partition p0 values in ((maxvalue, 0))); +create table t1 (a int, b int) +partition by list column_list (a,b) +( partition p0 values in ((0,0))); +--error ER_MAXVALUE_IN_VALUES_IN, ER_PARSE_ERROR +alter table t1 add partition +(partition p1 values in (maxvalue, maxvalue)); +drop table t1; # # BUG#47837, Crash when two same fields in column list processing # @@ -61,6 +91,7 @@ partition by list column_list(a,b) partition p2 values in ((3, NULL), (NULL, 1))); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; +show create table t1; # # BUG#47754 Crash when selecting using NOT BETWEEN for column list partitioning # @@ -90,6 +121,7 @@ partition by list (a) partition p1 values in (4, NULL, 3)); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; +show create table t1; insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); @@ -111,6 +143,7 @@ partition by list column_list(a) partition p1 values in (4, NULL, 3)); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; +show create table t1; insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); @@ -121,18 +154,6 @@ insert into t1 values (5); show create table t1; drop table t1; -create table t1 (a int, b char(10), c varchar(25), d datetime) -partition by range column_list(a,b,c,d) -subpartition by hash (to_seconds(d)) -subpartitions 4 -( partition p0 values less than (1, 0, MAXVALUE, 0), - partition p1 values less than (1, 'a', MAXVALUE, TO_DAYS('1999-01-01')), - partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE), - partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE)); -select partition_method, partition_expression, partition_description - from information_schema.partitions where table_name = "t1"; -drop table t1; - create table t1 (a int, b char(10), c varchar(5), d int) partition by range column_list(a,b,c) subpartition by key (c,d) @@ -143,6 +164,7 @@ subpartitions 3 partition p3 values less than (4,'abc','abc')); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; +show create table t1; insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3); insert into t1 values (1,'b','c',1),(2,'b','c',2),(3,'b','c',3); @@ -158,6 +180,7 @@ partition by range column_list (a, b, c) partition p1 values less than (1, 'B', 1)); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; +show create table t1; insert into t1 values (1, 'A', 1); explain partitions select * from t1 where a = 1 AND b <= 'A' and c = 1; select * from t1 where a = 1 AND b <= 'A' and c = 1; @@ -171,11 +194,23 @@ select * from t1 where a = 'a'; drop table t1; --error ER_WRONG_TYPE_COLUMN_VALUE_ERROR +create table t1 (d time) +partition by range column_list(d) +( partition p0 values less than ('2000-01-01'), + partition p1 values less than ('2040-01-01')); + +--error ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD create table t1 (d timestamp) partition by range column_list(d) ( partition p0 values less than ('2000-01-01'), partition p1 values less than ('2040-01-01')); +--error ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD +create table t1 (d bit(1)) +partition by range column_list(d) +( partition p0 values less than (0), + partition p1 values less than (1)); + create table t1 (a int, b int) partition by range column_list(a,b) (partition p0 values less than (maxvalue, 10)); 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 @@ -150,6 +150,38 @@ static int cmp_rec_and_tuple_prune(part_column_list_val *val, 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 @@ -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 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 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 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,