From 9c686c8a68af12b3a491dc8049b7ddc50db8010e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 18 May 2006 12:21:13 +0500 Subject: [PATCH 1/4] Bug#19392 Rename Database: Crash if case change Problem: Renaming a database to itself crashed server. It hapenned because of wrong DBUG_ASSERT. Fix: removing wrong DBUG_ASSERT. Now it reports a correct error message "database alreadt exists". mysql-test/r/renamedb.result: Adding test case mysql-test/t/renamedb.test: Adding test case sql/sql_db.cc: DBUG_ASSERT crashed server when renaming a database to itself. --- mysql-test/r/renamedb.result | 4 ++++ mysql-test/t/renamedb.test | 8 ++++++++ sql/sql_db.cc | 6 +++--- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/renamedb.result b/mysql-test/r/renamedb.result index 26ae42e72aa..b22322fbe8d 100644 --- a/mysql-test/r/renamedb.result +++ b/mysql-test/r/renamedb.result @@ -27,3 +27,7 @@ a 2 3 drop database testdb2; +create database testdb1; +rename database testdb1 to testdb1; +ERROR HY000: Can't create database 'testdb1'; database exists +drop database testdb1; diff --git a/mysql-test/t/renamedb.test b/mysql-test/t/renamedb.test index 5cfb2ce0c12..1e71adb3bf3 100644 --- a/mysql-test/t/renamedb.test +++ b/mysql-test/t/renamedb.test @@ -16,3 +16,11 @@ select database(); show tables; select a from t1 order by a; drop database testdb2; + +# +# Bug#19392 Rename Database: Crash if case change +# +create database testdb1; +--error 1007 +rename database testdb1 to testdb1; +drop database testdb1; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 3d035359b6f..cb43bb77def 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -134,9 +134,9 @@ void lock_db_delete(const char *name, uint length) { my_dblock_t *opt; safe_mutex_assert_owner(&LOCK_lock_db); - opt= (my_dblock_t *)hash_search(&lock_db_cache, (const byte*) name, length); - DBUG_ASSERT(opt != NULL); - hash_delete(&lock_db_cache, (byte*) opt); + if (opt= (my_dblock_t *)hash_search(&lock_db_cache, + (const byte*) name, length)) + hash_delete(&lock_db_cache, (byte*) opt); } From 143151913e636a770058106af66947dc24b75161 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 18 May 2006 12:28:39 +0500 Subject: [PATCH 2/4] sql_db.cc: Bug#19392: Rename Database: Crash if case change Additional minor fix, to avoid compiler warnings. sql/sql_db.cc: Bug#19392: Rename Database: Crash if case change Additional minor fix, to avoid compiler warnings. --- sql/sql_db.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sql_db.cc b/sql/sql_db.cc index cb43bb77def..ca34d80b225 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -134,8 +134,8 @@ void lock_db_delete(const char *name, uint length) { my_dblock_t *opt; safe_mutex_assert_owner(&LOCK_lock_db); - if (opt= (my_dblock_t *)hash_search(&lock_db_cache, - (const byte*) name, length)) + if ((opt= (my_dblock_t *)hash_search(&lock_db_cache, + (const byte*) name, length))) hash_delete(&lock_db_cache, (byte*) opt); } From 4e138572a01afc7e88f1b3040d3c4a81012e298f Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 21 Jun 2006 13:00:19 +0500 Subject: [PATCH 3/4] Bug#20086: Can't get data from key partitioned tables with VARCHAR key The problem appeared because the same values produced different hash during INSERT and SELECT for VARCHAR data type. Fix: VARCHAR required special treatment to avoid hashing of length bytes (leftmost one or two bytes) as well as trailing bytes beyond real length, which could contain garbage. Fix is done by introducing hash() - new method in the Field class. mysql-test/r/partition_innodb.result: Adding test case mysql-test/r/partition_pruning.result: Fixing test results (results differ due to changes in hash function) mysql-test/t/partition_innodb.test: Adding test case sql/field.cc: Adding generic hash() method, and a special method for VARCHAR. sql/field.h: Adding prototypes for new methods sql/key.cc: Mark columns for write before executinf of set_key_image(). Thanks for Mikael for suggesting this fix. sql/sql_partition.cc: Removing old hash code. Using new methid field->hash() instead. --- mysql-test/r/partition_innodb.result | 15 ++++++++++++++ mysql-test/r/partition_pruning.result | 2 +- mysql-test/t/partition_innodb.test | 12 +++++++++++ sql/field.cc | 30 +++++++++++++++++++++++++++ sql/field.h | 3 +++ sql/key.cc | 4 ++++ sql/sql_partition.cc | 17 +++------------ 7 files changed, 68 insertions(+), 15 deletions(-) diff --git a/mysql-test/r/partition_innodb.result b/mysql-test/r/partition_innodb.result index 5b1221dd64c..5e5931fdbf8 100644 --- a/mysql-test/r/partition_innodb.result +++ b/mysql-test/r/partition_innodb.result @@ -92,3 +92,18 @@ DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t0_aux; DROP TABLE IF EXISTS t0_definition; DROP TABLE IF EXISTS t0_template; +create table t1 (id varchar(64) primary key) engine=innodb +partition by key(id) partitions 5; +insert into t1 values ('a'); +insert into t1 values ('aa'); +insert into t1 values ('aaa'); +select * from t1 where id = 'a'; +id +a +select * from t1 where id = 'aa'; +id +aa +select * from t1 where id = 'aaa'; +id +aaa +drop table t1; diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result index 950a83c6d4f..ee294242bf7 100644 --- a/mysql-test/r/partition_pruning.result +++ b/mysql-test/r/partition_pruning.result @@ -31,7 +31,7 @@ id select_type table partitions type possible_keys key key_len ref rows Extra 1 SIMPLE t2 p0,p1 ALL NULL NULL NULL NULL 3 Using where explain partitions select * from t2 where a=1 and b=1; id select_type table partitions type possible_keys key key_len ref rows Extra -1 SIMPLE t2 p0 ALL NULL NULL NULL NULL 3 Using where +1 SIMPLE t2 p0 ALL NULL NULL NULL NULL 2 Using where create table t3 ( a int ) diff --git a/mysql-test/t/partition_innodb.test b/mysql-test/t/partition_innodb.test index 6a95dd7c8b0..fb20f573a79 100644 --- a/mysql-test/t/partition_innodb.test +++ b/mysql-test/t/partition_innodb.test @@ -66,3 +66,15 @@ DROP TABLE IF EXISTS t0_definition; DROP TABLE IF EXISTS t0_template; --enable_warnings +# +# Bug#20086: Can't get data from key partitioned tables with VARCHAR key +# +create table t1 (id varchar(64) primary key) engine=innodb +partition by key(id) partitions 5; +insert into t1 values ('a'); +insert into t1 values ('aa'); +insert into t1 values ('aaa'); +select * from t1 where id = 'a'; +select * from t1 where id = 'aa'; +select * from t1 where id = 'aaa'; +drop table t1; diff --git a/sql/field.cc b/sql/field.cc index b51e5b63779..0105c780d12 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1243,6 +1243,21 @@ uint Field::offset() } +void Field::hash(ulong *nr, ulong *nr2) +{ + if (is_null()) + { + *nr^= (*nr << 1) | 1; + } + else + { + uint len= pack_length(); + CHARSET_INFO *cs= charset(); + cs->coll->hash_sort(cs, (uchar*) ptr, len, nr, nr2); + } +} + + void Field::copy_from_tmp(int row_offset) { memcpy(ptr,ptr+row_offset,pack_length()); @@ -6923,6 +6938,21 @@ uint Field_varstring::is_equal(create_field *new_field) } +void Field_varstring::hash(ulong *nr, ulong *nr2) +{ + if (is_null()) + { + *nr^= (*nr << 1) | 1; + } + else + { + uint len= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr); + CHARSET_INFO *cs= charset(); + cs->coll->hash_sort(cs, (uchar*) ptr + length_bytes, len, nr, nr2); + } +} + + /**************************************************************************** ** blob type ** A blob is saved as a length and a pointer. The length is stored in the diff --git a/sql/field.h b/sql/field.h index 2ac7ec2c69d..6012e6cdd70 100644 --- a/sql/field.h +++ b/sql/field.h @@ -351,6 +351,8 @@ public: return field_length / charset()->mbmaxlen; } + /* Hash value */ + virtual void hash(ulong *nr, ulong *nr2); friend bool reopen_table(THD *,struct st_table *,bool); friend int cre_myisam(my_string name, register TABLE *form, uint options, ulonglong auto_increment_value); @@ -1120,6 +1122,7 @@ public: char *new_ptr, uchar *new_null_ptr, uint new_null_bit); uint is_equal(create_field *new_field); + void hash(ulong *nr, ulong *nr2); }; diff --git a/sql/key.cc b/sql/key.cc index 11dd267875f..69557d971e8 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -210,9 +210,13 @@ void key_restore(byte *to_record, byte *from_key, KEY *key_info, } else if (key_part->key_part_flag & HA_VAR_LENGTH_PART) { + my_bitmap_map *old_map; key_length-= HA_KEY_BLOB_LENGTH; length= min(key_length, key_part->length); + old_map= dbug_tmp_use_all_columns(key_part->field->table, + key_part->field->table->write_set); key_part->field->set_key_image((char *) from_key, length); + dbug_tmp_restore_column_map(key_part->field->table->write_set, old_map); from_key+= HA_KEY_BLOB_LENGTH; } else diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 00c15c2dbca..8eb9bfa1782 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2103,26 +2103,15 @@ static inline longlong part_val_int(Item *item_expr) static uint32 calculate_key_value(Field **field_array) { - uint32 hashnr= 0; + ulong nr1= 1; ulong nr2= 4; do { Field *field= *field_array; - if (field->is_null()) - { - hashnr^= (hashnr << 1) | 1; - } - else - { - uint len= field->pack_length(); - ulong nr1= 1; - CHARSET_INFO *cs= field->charset(); - cs->coll->hash_sort(cs, (uchar*)field->ptr, len, &nr1, &nr2); - hashnr^= (uint32)nr1; - } + field->hash(&nr1, &nr2); } while (*(++field_array)); - return hashnr; + return (uint32) nr1; } From dcd384ba83bc120337d11c9baae6deb5f391e076 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 22 Jun 2006 19:20:29 +0500 Subject: [PATCH 4/4] test fix(to satisfy Win) mysql-test/r/log_state.result: result fix(to satisfy Win) --- mysql-test/r/log_state.result | 22 +++++++++++----------- mysql-test/t/log_state.test | 16 ++++++++-------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/mysql-test/r/log_state.result b/mysql-test/r/log_state.result index df81f05fea5..43735243787 100644 --- a/mysql-test/r/log_state.result +++ b/mysql-test/r/log_state.result @@ -14,15 +14,15 @@ set global general_log= ON; create table t1(f1 int); select * from mysql.general_log; event_time user_host thread_id server_id command_type argument -TIMESTAMP root[root] @ localhost [] # 1 Query create table t1(f1 int) -TIMESTAMP root[root] @ localhost [] # 1 Query select * from mysql.general_log +TIMESTAMP USER_HOST # 1 Query create table t1(f1 int) +TIMESTAMP USER_HOST # 1 Query select * from mysql.general_log set global general_log= OFF; drop table t1; select * from mysql.general_log; event_time user_host thread_id server_id command_type argument -TIMESTAMP root[root] @ localhost [] # 1 Query create table t1(f1 int) -TIMESTAMP root[root] @ localhost [] # 1 Query select * from mysql.general_log -TIMESTAMP root[root] @ localhost [] # 1 Query set global general_log= OFF +TIMESTAMP USER_HOST # 1 Query create table t1(f1 int) +TIMESTAMP USER_HOST # 1 Query select * from mysql.general_log +TIMESTAMP USER_HOST # 1 Query set global general_log= OFF set global general_log= ON; flush logs; show global variables @@ -46,7 +46,7 @@ sleep(2) 0 select * from mysql.slow_log; start_time user_host query_time lock_time rows_sent rows_examined db last_insert_id insert_id server_id sql_text -TIMESTAMP, root[root] @ localhost [] USER_HOST, QUERY_TIME 1 0 test 0 0 1 select sleep(2) +TIMESTAMP USER_HOST QUERY_TIME 00:00:00 1 0 test 0 0 1 select sleep(2) show global variables where Variable_name = 'log' or Variable_name = 'log_slow_queries' or Variable_name = 'general_log' or Variable_name = 'slow_query_log'; @@ -67,9 +67,9 @@ create table t1(f1 int); drop table t1; select * from mysql.general_log; event_time user_host thread_id server_id command_type argument -TIMESTAMP root[root] @ localhost [] # 1 Query create table t1(f1 int) -TIMESTAMP root[root] @ localhost [] # 1 Query drop table t1 -TIMESTAMP root[root] @ localhost [] # 1 Query select * from mysql.general_log +TIMESTAMP USER_HOST # 1 Query create table t1(f1 int) +TIMESTAMP USER_HOST # 1 Query drop table t1 +TIMESTAMP USER_HOST # 1 Query select * from mysql.general_log set global general_log= OFF; truncate table mysql.general_log; select * from mysql.general_log; @@ -151,5 +151,5 @@ set global general_log=ON; drop table t1; select * from mysql.general_log; event_time user_host thread_id server_id command_type argument -TIMESTAMP root[root] @ localhost [] # 1 Query drop table t1 -TIMESTAMP root[root] @ localhost [] # 1 Query select * from mysql.general_log +TIMESTAMP USER_HOST # 1 Query drop table t1 +TIMESTAMP USER_HOST # 1 Query select * from mysql.general_log diff --git a/mysql-test/t/log_state.test b/mysql-test/t/log_state.test index d3dec841dc1..41fbd068dce 100644 --- a/mysql-test/t/log_state.test +++ b/mysql-test/t/log_state.test @@ -11,11 +11,11 @@ Variable_name = 'general_log' or Variable_name = 'slow_query_log'; flush logs; set global general_log= ON; create table t1(f1 int); ---replace_column 1 TIMESTAMP 3 # +--replace_column 1 TIMESTAMP 2 USER_HOST 3 # select * from mysql.general_log; set global general_log= OFF; drop table t1; ---replace_column 1 TIMESTAMP 3 # +--replace_column 1 TIMESTAMP 2 USER_HOST 3 # select * from mysql.general_log; set global general_log= ON; flush logs; @@ -27,7 +27,7 @@ connect (con1,localhost,root,,); connection con1; set session long_query_time=1; select sleep(2); ---replace_column 1 TIMESTAMP, 3 USER_HOST, 4 QUERY_TIME +--replace_column 1 TIMESTAMP 2 USER_HOST 3 QUERY_TIME select * from mysql.slow_log; connection default; @@ -35,7 +35,7 @@ set global slow_query_log= ON; connection con1; set session long_query_time=1; select sleep(2); ---replace_column 1 TIMESTAMP, 3 USER_HOST, 4 QUERY_TIME +--replace_column 1 TIMESTAMP 2 USER_HOST 3 QUERY_TIME select * from mysql.slow_log; disconnect con1; connection default; @@ -54,11 +54,11 @@ set global general_log= ON; truncate table mysql.general_log; create table t1(f1 int); drop table t1; ---replace_column 1 TIMESTAMP 3 # +--replace_column 1 TIMESTAMP 2 USER_HOST 3 # select * from mysql.general_log; set global general_log= OFF; truncate table mysql.general_log; ---replace_column 1 TIMESTAMP 3 # +--replace_column 1 TIMESTAMP 2 USER_HOST 3 # select * from mysql.general_log; set global general_log= ON; show global variables @@ -109,14 +109,14 @@ truncate table mysql.general_log; show variables like 'log_output'; set global general_log=ON; create table t1(f1 int); ---replace_column 1 TIMESTAMP 3 # +--replace_column 1 TIMESTAMP 2 USER_HOST 3 # select * from mysql.general_log; set global general_log=OFF; set global log_output="FILE,TABLE"; show variables like 'log_output'; set global general_log=ON; drop table t1; ---replace_column 1 TIMESTAMP 3 # +--replace_column 1 TIMESTAMP 2 USER_HOST 3 # select * from mysql.general_log; --enable_ps_protocol