summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikael Ronstrom <mikael@mysql.com>2009-10-28 01:11:17 +0100
committerMikael Ronstrom <mikael@mysql.com>2009-10-28 01:11:17 +0100
commit10fed1aca0096acb135c2065233e84d61b00b9cf (patch)
tree32eac76c7c0b41298c58cd40bc85138e177d8a98
parentcc43a2089cf6f45afb2cb5c15e2a077b075b80f8 (diff)
downloadmariadb-git-10fed1aca0096acb135c2065233e84d61b00b9cf.tar.gz
BUG#48165, needed to introduce length restrictions on partitioning fields to ensure that no stack overruns occur
-rw-r--r--mysql-test/r/partition_column.result15
-rw-r--r--mysql-test/r/partition_datatype.result8
-rw-r--r--mysql-test/t/partition_column.test17
-rw-r--r--mysql-test/t/partition_datatype.test9
-rw-r--r--sql/opt_range.cc8
-rw-r--r--sql/partition_info.cc30
-rw-r--r--sql/partition_info.h3
-rw-r--r--sql/share/errmsg.txt2
-rw-r--r--sql/sql_partition.cc21
-rw-r--r--sql/sql_partition.h1
-rw-r--r--sql/sql_show.cc2
11 files changed, 98 insertions, 18 deletions
diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result
index 0ba56110116..0dc81240782 100644
--- a/mysql-test/r/partition_column.result
+++ b/mysql-test/r/partition_column.result
@@ -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)
diff --git a/mysql-test/r/partition_datatype.result b/mysql-test/r/partition_datatype.result
index 607afb71da5..47ea799f497 100644
--- a/mysql-test/r/partition_datatype.result
+++ b/mysql-test/r/partition_datatype.result
@@ -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);
diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test
index 16f12bfad04..1c5b859a211 100644
--- a/mysql-test/t/partition_column.test
+++ b/mysql-test/t/partition_column.test
@@ -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;
diff --git a/mysql-test/t/partition_datatype.test b/mysql-test/t/partition_datatype.test
index 7440a9bf3a3..0a9fae15354 100644
--- a/mysql-test/t/partition_datatype.test
+++ b/mysql-test/t/partition_datatype.test
@@ -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')) partition by key (a);
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
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 356cfe5e398..19aa06dcae9 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -3600,12 +3600,8 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
{
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));
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index 9d9aa5d4e95..52a4c4c0c7f 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -1344,6 +1344,36 @@ bool partition_info::set_part_expr(char *start_token, Item *item_ptr,
/*
+ 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()
diff --git a/sql/partition_info.h b/sql/partition_info.h
index 015e0c1d6d0..4d3cc2222a6 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -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:
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index d65945013b9..ec08885fda4 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -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"
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 83d50ee222e..e21f7da6888 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -1779,6 +1779,11 @@ bool fix_partition_func(THD *thd, TABLE *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 *sql_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 fptr, partition_info *part_info,
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, const char *in1,
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
diff --git a/sql/sql_partition.h b/sql/sql_partition.h
index 0dac13a3fcc..724a63e1d76 100644
--- a/sql/sql_partition.h
+++ b/sql/sql_partition.h
@@ -71,6 +71,7 @@ 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,
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,
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 46a91f7a905..77c7a3c27f3 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -4846,7 +4846,7 @@ get_partition_column_description(partition_info *part_info,
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;