From c574a9c414f817975f75a08744b2f0bea1232ff3 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Mon, 10 Jan 2011 16:20:28 +0100 Subject: [PATCH 1/2] Bug#57924: crash when creating partitioned table with multiple columns in the partition key ndb crash if duplicate columns in the partitioning key. Backport from mysql-5.1-telco-7.0, see bug#53354. Changed from case sensitive field name comparision to non case sensitive too. mysql-test/r/partition_error.result: updated result mysql-test/t/partition_error.test: Added test for the error in non-ndb partitioned table. sql/sql_partition.cc: Added check for duplicated field names in the partitioning key. --- mysql-test/r/partition_error.result | 13 +++++++++++++ mysql-test/suite/ndb/r/ndb_basic.result | 2 ++ mysql-test/suite/ndb/t/ndb_basic.test | 7 +++++++ mysql-test/t/partition_error.test | 14 ++++++++++++++ sql/sql_partition.cc | 22 ++++++++++++++++++++++ 5 files changed, 58 insertions(+) diff --git a/mysql-test/r/partition_error.result b/mysql-test/r/partition_error.result index ea74f476ceb..91eb18b3dad 100644 --- a/mysql-test/r/partition_error.result +++ b/mysql-test/r/partition_error.result @@ -1,5 +1,18 @@ drop table if exists t1; # +# Bug#57924: crash when creating partitioned table with +# multiple columns in the partition key +# +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a,b)) +PARTITION BY KEY(a, b, a); +ERROR HY000: Field in list of fields for partition function not found in table +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a,b)) +PARTITION BY KEY(A, b); +DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a,b)) +PARTITION BY KEY(a, b, A); +ERROR HY000: Field in list of fields for partition function not found in table +# # Bug#49161: Out of memory; restart server and try again (needed 2 bytes) # CREATE TABLE t1 (a INT) PARTITION BY HASH (a); diff --git a/mysql-test/suite/ndb/r/ndb_basic.result b/mysql-test/suite/ndb/r/ndb_basic.result index 9f4f8c0755c..ee50352220e 100644 --- a/mysql-test/suite/ndb/r/ndb_basic.result +++ b/mysql-test/suite/ndb/r/ndb_basic.result @@ -585,6 +585,8 @@ c127 int, c128 int, primary key using hash(c1)) engine=ndb partition by key(c1); drop table t1; +create table `t1` (`a` int, b int, primary key (a,b)) engine=ndb partition by key(`a`,`b`,`a`); +ERROR HY000: Field in list of fields for partition function not found in table create table t1 ( a1234567890123456789012345678901234567890 int primary key, a12345678901234567890123456789a1234567890 int, diff --git a/mysql-test/suite/ndb/t/ndb_basic.test b/mysql-test/suite/ndb/t/ndb_basic.test index 2fc140288ca..5d6221d1784 100644 --- a/mysql-test/suite/ndb/t/ndb_basic.test +++ b/mysql-test/suite/ndb/t/ndb_basic.test @@ -547,6 +547,13 @@ c128 int, primary key using hash(c1)) engine=ndb partition by key(c1); drop table t1; +# +# test bug#53354 - crash when creating partitioned table with multiple columns in the partition key +# + +--error ER_FIELD_NOT_FOUND_PART_ERROR +create table `t1` (`a` int, b int, primary key (a,b)) engine=ndb partition by key(`a`,`b`,`a`); + # # test max size of attribute name and truncation # diff --git a/mysql-test/t/partition_error.test b/mysql-test/t/partition_error.test index d3f10628254..aa26fa29db9 100644 --- a/mysql-test/t/partition_error.test +++ b/mysql-test/t/partition_error.test @@ -10,6 +10,20 @@ drop table if exists t1; let $MYSQLD_DATADIR= `SELECT @@datadir`; +--echo # +--echo # Bug#57924: crash when creating partitioned table with +--echo # multiple columns in the partition key +--echo # +--error ER_FIELD_NOT_FOUND_PART_ERROR +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a,b)) +PARTITION BY KEY(a, b, a); +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a,b)) +PARTITION BY KEY(A, b); +DROP TABLE t1; +--error ER_FIELD_NOT_FOUND_PART_ERROR +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a,b)) +PARTITION BY KEY(a, b, A); + --echo # --echo # Bug#49161: Out of memory; restart server and try again (needed 2 bytes) --echo # diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 44ed9e759c6..8cd43a4f60e 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -761,6 +761,9 @@ static bool handle_list_of_fields(List_iterator it, bool result; char *field_name; bool is_list_empty= TRUE; + int fields_handled = 0; + char* field_name_array[MAX_KEY]; + DBUG_ENTER("handle_list_of_fields"); while ((field_name= it++)) @@ -776,6 +779,25 @@ static bool handle_list_of_fields(List_iterator it, result= TRUE; goto end; } + + /* + Check for duplicate fields in the list. + Assuming that there are not many fields in the partition key list. + If there were, it would be better to replace the for-loop + with a more efficient algorithm. + */ + + field_name_array[fields_handled] = field_name; + for (int i = 0; i < fields_handled; ++i) + { + if (my_strcasecmp(system_charset_info, + field_name_array[i], field_name) == 0) + { + my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + } + fields_handled++; } if (is_list_empty) { From 38c5e2cae8338d8941182dacb988b2aa8027cca4 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Mon, 10 Jan 2011 23:42:37 +0100 Subject: [PATCH 2/2] Bug#47902: partition_recover_myisam fails with --ps-protocol The problem was that the warnings was never written out when running with --ps-protocol. This was because the warnings only appeared during the prepare phase, not the execute phase. Solved by not clearing the warnings from the prepare phase if there was no other warnings. If there are warnings from the execute phase, it is very likely to be the same as from the prepare phase. My tests show that if not clearing the warnings from the prepare phase when there are warnings from the execute phase, there will be duplicated warnings in the result. client/mysqltest.cc: Only reset the prepare warnings if there are warnings from the execute phase. Otherwise these warnings will never be returned. --- client/mysqltest.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index a12c56c9657..cdfce036ec7 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -7241,8 +7241,12 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, mysql_free_result(res); /* Free normal result set with meta data */ - /* Clear prepare warnings */ - dynstr_set(&ds_prepare_warnings, NULL); + /* + Clear prepare warnings if there are execute warnings, + since they are probably duplicated. + */ + if (ds_execute_warnings.length || mysql->warning_count) + dynstr_set(&ds_prepare_warnings, NULL); } else {