List:Commits« Previous MessageNext Message »
From:Mikael Ronstrom Date:October 28 2009 12:11am
Subject:bzr commit into mysql-5.5.0-trunk branch (mikael:2901) Bug#48165
View as plain text  
#At file:///home/mikael/mysql_clones/mysql-trunk-wl3352-values/

 2901 Mikael Ronstrom	2009-10-28
      BUG#48165, needed to introduce length restrictions on partitioning fields to ensure that no stack overruns occur
      modified:
        mysql-test/r/partition_column.result
        mysql-test/r/partition_datatype.result
        mysql-test/t/partition_column.test
        mysql-test/t/partition_datatype.test
        sql/opt_range.cc
        sql/partition_info.cc
        sql/partition_info.h
        sql/share/errmsg.txt
        sql/sql_partition.cc
        sql/sql_partition.h
        sql/sql_show.cc

=== modified file 'mysql-test/r/partition_column.result'
--- a/mysql-test/r/partition_column.result	2009-10-27 23:06:11 +0000
+++ b/mysql-test/r/partition_column.result	2009-10-28 00:11:17 +0000
@@ -1,4 +1,19 @@
 drop table if exists t1;
+create table t1 (a varchar(1500), b varchar(1570))
+partition by list column_list(a,b)
+( partition p0 values in (('a','b')));
+ERROR HY000: The total length of the partitioning fields is too large
+create table t1 (a varchar(1023) character set utf8 collate utf8_spanish2_ci)
+partition by range column_list(a)
+( partition p0 values less than ('CZ'),
+partition p1 values less than ('CH'),
+partition p2 values less than ('D'));
+insert into t1 values ('czz'),('chi'),('ci'),('cg');
+select * from t1 where a between 'cg' AND 'ci';
+a
+ci
+cg
+drop table t1;
 set @@sql_mode=allow_invalid_dates;
 create table t1 (a char, b char, c date)
 partition by range column_list (a,b,c)

=== modified file 'mysql-test/r/partition_datatype.result'
--- a/mysql-test/r/partition_datatype.result	2008-12-09 11:16:39 +0000
+++ b/mysql-test/r/partition_datatype.result	2009-10-28 00:11:17 +0000
@@ -273,7 +273,7 @@ select * from t1 where a = 'y';
 a
 y
 drop table t1;
-create table t1 (a varchar(65531)) partition by key (a);
+create table t1 (a varchar(3068)) partition by key (a);
 insert into t1 values ('bbbb');
 insert into t1 values ('aaaa');
 select * from t1 where a = 'aaaa';
@@ -286,7 +286,7 @@ select * from t1 where a = 'bbbb';
 a
 bbbb
 drop table t1;
-create table t1 (a varchar(65532)) partition by key (a);
+create table t1 (a varchar(3069)) partition by key (a);
 insert into t1 values ('bbbb');
 insert into t1 values ('aaaa');
 select * from t1 where a = 'aaaa';
@@ -299,7 +299,7 @@ select * from t1 where a = 'bbbb';
 a
 bbbb
 drop table t1;
-create table t1 (a varchar(65533) not null) partition by key (a);
+create table t1 (a varchar(3070) not null) partition by key (a);
 insert into t1 values ('bbbb');
 insert into t1 values ('aaaa');
 select * from t1 where a = 'aaaa';
@@ -312,6 +312,8 @@ select * from t1 where a = 'bbbb';
 a
 bbbb
 drop table t1;
+create table t1 (a varchar(3070)) partition by key (a);
+ERROR HY000: The total length of the partitioning fields is too large
 create table t1 (a varchar(65533)) partition by key (a);
 ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs
 create table t1 (a varchar(65534) not null) partition by key (a);

=== modified file 'mysql-test/t/partition_column.test'
--- a/mysql-test/t/partition_column.test	2009-10-27 23:06:11 +0000
+++ b/mysql-test/t/partition_column.test	2009-10-28 00:11:17 +0000
@@ -9,6 +9,23 @@ drop table if exists t1;
 --enable_warnings
 
 #
+# BUG#48164, too long partition fields causes crash
+#
+--error ER_PARTITION_FIELDS_TOO_LONG
+create table t1 (a varchar(1500), b varchar(1570))
+partition by list column_list(a,b)
+( partition p0 values in (('a','b')));
+
+create table t1 (a varchar(1023) character set utf8 collate utf8_spanish2_ci)
+partition by range column_list(a)
+( partition p0 values less than ('CZ'),
+  partition p1 values less than ('CH'),
+  partition p2 values less than ('D'));
+insert into t1 values ('czz'),('chi'),('ci'),('cg');
+select * from t1 where a between 'cg' AND 'ci';
+drop table t1;
+
+#
 # BUG#48165, sql_mode gives error
 #
 set @@sql_mode=allow_invalid_dates;

=== modified file 'mysql-test/t/partition_datatype.test'
--- a/mysql-test/t/partition_datatype.test	2008-02-25 20:18:50 +0000
+++ b/mysql-test/t/partition_datatype.test	2009-10-28 00:11:17 +0000
@@ -4,6 +4,7 @@
 # as partition by key
 # Created to verify the fix for Bug#31705
 # Partitions: crash if varchar length > 65530
+# BUG#48164 limited size to 3072 bytes
 #
 -- source include/have_partition.inc
 
@@ -192,27 +193,29 @@ create table t1 (a set('y','n')) partiti
 insert into t1 values ('y');
 select * from t1 where a = 'y';
 drop table t1;
-create table t1 (a varchar(65531)) partition by key (a);
+create table t1 (a varchar(3068)) partition by key (a);
 insert into t1 values ('bbbb');
 insert into t1 values ('aaaa');
 select * from t1 where a = 'aaaa';
 select * from t1 where a like 'aaa%';
 select * from t1 where a = 'bbbb';
 drop table t1;
-create table t1 (a varchar(65532)) partition by key (a);
+create table t1 (a varchar(3069)) partition by key (a);
 insert into t1 values ('bbbb');
 insert into t1 values ('aaaa');
 select * from t1 where a = 'aaaa';
 select * from t1 where a like 'aaa%';
 select * from t1 where a = 'bbbb';
 drop table t1;
-create table t1 (a varchar(65533) not null) partition by key (a);
+create table t1 (a varchar(3070) not null) partition by key (a);
 insert into t1 values ('bbbb');
 insert into t1 values ('aaaa');
 select * from t1 where a = 'aaaa';
 select * from t1 where a like 'aaa%';
 select * from t1 where a = 'bbbb';
 drop table t1;
+-- error ER_PARTITION_FIELDS_TOO_LONG
+create table t1 (a varchar(3070)) partition by key (a);
 -- error ER_TOO_BIG_ROWSIZE
 create table t1 (a varchar(65533)) partition by key (a);
 -- error ER_TOO_BIG_ROWSIZE

=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc	2009-10-19 10:09:52 +0000
+++ b/sql/opt_range.cc	2009-10-28 00:11:17 +0000
@@ -3600,12 +3600,8 @@ static bool create_partition_index_descr
   {
     key_part->key=          0;
     key_part->part=	    part;
-    key_part->store_length= key_part->length= (uint16) (*field)->key_length();
-    if ((*field)->real_maybe_null())
-      key_part->store_length+= HA_KEY_NULL_LENGTH;
-    if ((*field)->type() == MYSQL_TYPE_BLOB || 
-        (*field)->real_type() == MYSQL_TYPE_VARCHAR)
-      key_part->store_length+= HA_KEY_BLOB_LENGTH;
+    key_part->length= (uint16)get_partition_field_store_length(*field);
+    key_part->store_length= key_part->length;
 
     DBUG_PRINT("info", ("part %u length %u store_length %u", part,
                          key_part->length, key_part->store_length));

=== modified file 'sql/partition_info.cc'
--- a/sql/partition_info.cc	2009-10-27 23:06:11 +0000
+++ b/sql/partition_info.cc	2009-10-28 00:11:17 +0000
@@ -1344,6 +1344,36 @@ bool partition_info::set_part_expr(char 
 
 
 /*
+  Check that partition fields and subpartition fields are not too long
+
+  SYNOPSIS
+    check_partition_field_length()
+
+  RETURN VALUES
+    TRUE                             Total length was too big
+    FALSE                            Length is ok
+*/
+
+bool partition_info::check_partition_field_length()
+{
+  uint store_length= 0;
+  uint i;
+  DBUG_ENTER("partition_info::check_partition_field_length");
+
+  for (i= 0; i < num_part_fields; i++)
+    store_length+= get_partition_field_store_length(part_field_array[i]);
+  if (store_length > MAX_KEY_LENGTH)
+    DBUG_RETURN(TRUE);
+  store_length= 0;
+  for (i= 0; i < num_subpart_fields; i++)
+    store_length+= get_partition_field_store_length(subpart_field_array[i]);
+  if (store_length > MAX_KEY_LENGTH)
+    DBUG_RETURN(TRUE);
+  DBUG_RETURN(FALSE);
+}
+
+
+/*
   Set up buffers and arrays for fields requiring preparation
   SYNOPSIS
     set_up_charset_field_preps()

=== modified file 'sql/partition_info.h'
--- a/sql/partition_info.h	2009-10-23 07:36:45 +0000
+++ b/sql/partition_info.h	2009-10-28 00:11:17 +0000
@@ -19,8 +19,6 @@
 
 #include "partition_element.h"
 
-#define MAX_STR_SIZE_PF 2048
-
 class partition_info;
 
 /* Some function typedefs */
@@ -298,6 +296,7 @@ public:
                      char *end_token, bool is_subpart);
   static int compare_column_values(const void *a, const void *b);
   bool set_up_charset_field_preps();
+  bool check_partition_field_length();
   bool init_column_part();
   bool add_column_list_value(THD *thd, Item *item);
 private:

=== modified file 'sql/share/errmsg.txt'
--- a/sql/share/errmsg.txt	2009-10-22 14:15:06 +0000
+++ b/sql/share/errmsg.txt	2009-10-28 00:11:17 +0000
@@ -6222,3 +6222,5 @@ 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"
+ER_PARTITION_FIELDS_TOO_LONG
+  eng "The total length of the partitioning fields is too large"

=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc	2009-10-23 07:36:45 +0000
+++ b/sql/sql_partition.cc	2009-10-28 00:11:17 +0000
@@ -1779,6 +1779,11 @@ bool fix_partition_func(THD *thd, 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);
@@ -2038,8 +2043,6 @@ static int check_part_field(Create_field
     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;
@@ -2095,7 +2098,7 @@ static int add_column_list_values(File f
       err+= add_string(fptr, "NULL");
     else
     {
-      char buffer[3 * MAX_STR_SIZE_PF + 10];
+      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)
@@ -7730,5 +7733,17 @@ void create_subpartition_name(char *out,
     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
 

=== modified file 'sql/sql_partition.h'
--- a/sql/sql_partition.h	2009-10-22 14:15:06 +0000
+++ b/sql/sql_partition.h	2009-10-28 00:11:17 +0000
@@ -71,6 +71,7 @@ bool partition_key_modified(TABLE *table
 void get_partition_set(const TABLE *table, uchar *buf, const uint index,
                        const key_range *key_spec,
                        part_id_range *part_spec);
+uint get_partition_field_store_length(Field *field);
 void get_full_part_id_from_key(const TABLE *table, uchar *buf,
                                KEY *key_info,
                                const key_range *key_spec,

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2009-10-23 07:36:45 +0000
+++ b/sql/sql_show.cc	2009-10-28 00:11:17 +0000
@@ -4846,7 +4846,7 @@ get_partition_column_description(partiti
       tmp_str.append("NULL");
     else
     {
-      char buffer[3 * MAX_STR_SIZE_PF + 10];
+      char buffer[MAX_KEY_LENGTH];
       String str(buffer, sizeof(buffer), &my_charset_bin);
       Item *item= col_val->item_expression;
 

Thread
bzr commit into mysql-5.5.0-trunk branch (mikael:2901) Bug#48165Mikael Ronstrom28 Oct