From 6ae9eb48d517a096ef5de054b71706f9c5351e65 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 24 May 2005 12:21:15 -0700 Subject: [PATCH 01/27] Increase limit of partial key length in MEMORY storage engine to the same as a full key. (Bug #10566) mysql-test/r/heap.result: Update results mysql-test/t/heap.test: Add test for bug #10566 sql/ha_heap.h: Add max_supported_key_part_length() method. --- mysql-test/r/heap.result | 5 +++++ mysql-test/t/heap.test | 9 +++++++++ sql/ha_heap.h | 1 + 3 files changed, 15 insertions(+) diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result index 29207a4ae98..53dec294ef8 100644 --- a/mysql-test/r/heap.result +++ b/mysql-test/r/heap.result @@ -291,3 +291,8 @@ a b 1 7 1 8 drop table t1; +create table t1 (c char(255), primary key(c(90))); +insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); +insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); +ERROR 23000: Duplicate entry 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl' for key 1 +drop table t1; diff --git a/mysql-test/t/heap.test b/mysql-test/t/heap.test index e082993a58e..c0977819487 100644 --- a/mysql-test/t/heap.test +++ b/mysql-test/t/heap.test @@ -224,3 +224,12 @@ insert t1 (a) values (1); insert t1 (a) values (1); select * from t1; drop table t1; + +# +# Bug #10566: Verify that we can create a prefixed key with length > 255 +# +create table t1 (c char(255), primary key(c(90))); +insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); +--error 1062 +insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); +drop table t1; diff --git a/sql/ha_heap.h b/sql/ha_heap.h index 60e2e84c5d2..33de0156074 100644 --- a/sql/ha_heap.h +++ b/sql/ha_heap.h @@ -53,6 +53,7 @@ public: } const key_map *keys_to_use_for_scanning() { return &btree_keys; } uint max_supported_keys() const { return MAX_KEY; } + uint max_supported_key_part_length() const { return MAX_KEY_LENGTH; } double scan_time() { return (double) (records+deleted) / 20.0+10; } double read_time(uint index, uint ranges, ha_rows rows) { return (double) rows / 20.0+1; } From f0329bfb8c9215272cc176c874f79d14a02d20fa Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 25 May 2005 18:11:47 -0700 Subject: [PATCH 02/27] Fix partial keys when converting VARCHAR to TEXT. (Bug #10543) mysql-test/r/type_varchar.result: Update results mysql-test/t/type_varchar.test: Add new regression test sql/field.cc: Add Field::type_can_have_key_part() static method sql/field.h: Add Field::type_can_have_key_part() signature. sql/sql_table.cc: Only reset the length of a key part when changing from a field type that can't be used partially to a field that can, or vice versa, or when the part is smaller than the length of the field. --- mysql-test/r/type_varchar.result | 23 ++++++++++++++++++++++ mysql-test/t/type_varchar.test | 12 ++++++++++++ sql/field.cc | 33 ++++++++++++++++++++++++++++++++ sql/field.h | 1 + sql/sql_table.cc | 21 ++++++++++++++------ 5 files changed, 84 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/type_varchar.result b/mysql-test/r/type_varchar.result index 3bd7fe6b175..fed03cd8d71 100644 --- a/mysql-test/r/type_varchar.result +++ b/mysql-test/r/type_varchar.result @@ -392,3 +392,26 @@ group by t1.b, t1.a; a b min(t1.b) 22 NULL NULL drop table t1, t2; +create table t1 (f1 varchar(65500)); +create index index1 on t1(f1(10)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` varchar(65500) default NULL, + KEY `index1` (`f1`(10)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t1 modify f1 varchar(255); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` varchar(255) default NULL, + KEY `index1` (`f1`(10)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t1 modify f1 tinytext; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` tinytext, + KEY `index1` (`f1`(10)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; diff --git a/mysql-test/t/type_varchar.test b/mysql-test/t/type_varchar.test index 2bffca6b889..1a3a93018a4 100644 --- a/mysql-test/t/type_varchar.test +++ b/mysql-test/t/type_varchar.test @@ -118,3 +118,15 @@ insert into t2 values (22), (22); select t1.a, t1.b, min(t1.b) from t1 inner join t2 ON t2.a = t1.a group by t1.b, t1.a; drop table t1, t2; + +# +# Bug #10543: convert varchar with index to text +# +create table t1 (f1 varchar(65500)); +create index index1 on t1(f1(10)); +show create table t1; +alter table t1 modify f1 varchar(255); +show create table t1; +alter table t1 modify f1 tinytext; +show create table t1; +drop table t1; diff --git a/sql/field.cc b/sql/field.cc index 54ed4044de5..18f201243dd 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -982,6 +982,39 @@ Item_result Field::result_merge_type(enum_field_types field_type) Static help functions *****************************************************************************/ + +/* + Check whether a field type can be partially indexed by a key + + This is a static method, rather than a virtual function, because we need + to check the type of a non-Field in mysql_alter_table(). + + SYNOPSIS + type_can_have_key_part() + type field type + + RETURN + TRUE Type can have a prefixed key + FALSE Type can not have a prefixed key +*/ + +bool Field::type_can_have_key_part(enum enum_field_types type) +{ + switch (type) { + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_STRING: + return TRUE; + default: + return FALSE; + } +} + + /* Numeric fields base class constructor */ diff --git a/sql/field.h b/sql/field.h index f68a2327dff..8510c59c9f2 100644 --- a/sql/field.h +++ b/sql/field.h @@ -119,6 +119,7 @@ public: virtual Item_result result_type () const=0; virtual Item_result cmp_type () const { return result_type(); } virtual Item_result cast_to_int_type () const { return result_type(); } + static bool type_can_have_key_part(enum_field_types); static enum_field_types field_type_merge(enum_field_types, enum_field_types); static Item_result result_merge_type(enum_field_types); bool eq(Field *field) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4ddef3fc653..2768d503751 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3334,12 +3334,21 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, continue; // Field is removed uint key_part_length=key_part->length; if (cfield->field) // Not new field - { // Check if sub key - if (cfield->field->type() != FIELD_TYPE_BLOB && - (cfield->field->pack_length() == key_part_length || - cfield->length <= key_part_length / - key_part->field->charset()->mbmaxlen)) - key_part_length=0; // Use whole field + { + /* + If the field can't have only a part used in a key according to its + new type, or should not be used partially according to its + previous type, or the field length is less than the key part + length, unset the key part length. + + BLOBs may have cfield->length == 0, which is why we test it before + checking whether cfield->length < key_part_length (in chars). + */ + if (!Field::type_can_have_key_part(cfield->field->type()) || + !Field::type_can_have_key_part(cfield->sql_type) || + (cfield->length && (cfield->length < key_part_length / + key_part->field->charset()->mbmaxlen))) + key_part_length= 0; // Use whole field } key_part_length /= key_part->field->charset()->mbmaxlen; key_parts.push_back(new key_part_spec(cfield->field_name, From ac55fc7adb32a1766aae6953895e4ffe7d99474b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 26 May 2005 14:02:18 -0500 Subject: [PATCH 03/27] Bug #10181 mysqld.exe crash with an access violation after INSERT INTO mysql.host sql_acl.cc: Make sure host.db is a valid string pointer before we do our lower_case_table_names comparison sql/sql_acl.cc: Make sure host.db is a valid string pointer before we do our lower_case_table_names comparison --- sql/sql_acl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 02da05d195f..ae360fab019 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -198,7 +198,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) ACL_HOST host; update_hostname(&host.host,get_field(&mem, table->field[0])); host.db= get_field(&mem, table->field[1]); - if (lower_case_table_names) + if (lower_case_table_names && host.db) { /* We make a temporary copy of the database, force it to lower case, From c744e2747933de77f062b8e44320627dd8d32080 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 31 May 2005 07:21:10 -0500 Subject: [PATCH 04/27] BUG# 10181-mysqld.exe crash with an access vioation after INSERT INTO mysql.host this is a followup cset after changes suggested by Serg. sql/sql_acl.cc: removed extra parameters used in sql_print_warning added code to output "" when host.db is null in the top sql_print_warning call --- sql/sql_acl.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index ae360fab019..c7a16c96d69 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -222,7 +222,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) { sql_print_warning("'host' entry '%s|%s' " "ignored in --skip-name-resolve mode.", - host.host.hostname, host.db, host.host.hostname); + host.host.hostname, host.db?host.db:""); continue; } #ifndef TO_BE_REMOVED @@ -290,7 +290,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) { sql_print_warning("'user' entry '%s@%s' " "ignored in --skip-name-resolve mode.", - user.user, user.host.hostname, user.host.hostname); + user.user, user.host.hostname); continue; } @@ -393,7 +393,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) { sql_print_warning("'db' entry '%s %s@%s' " "ignored in --skip-name-resolve mode.", - db.db, db.user, db.host.hostname, db.host.hostname); + db.db, db.user, db.host.hostname); continue; } db.access=get_access(table,3); @@ -2690,7 +2690,7 @@ my_bool grant_init(THD *org_thd) sql_print_warning("'tables_priv' entry '%s %s@%s' " "ignored in --skip-name-resolve mode.", mem_check->tname, mem_check->user, - mem_check->host, mem_check->host); + mem_check->host); continue; } } From e6ec99442dc14c4a23460da00979776b152c588a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Jun 2005 11:30:59 -0700 Subject: [PATCH 05/27] Fix hashcmp() to handle special case of zero length, which resulted in the hostname cache being ineffective. Based on patch from Jeremy Cole of Yahoo! (Bug #10931) mysys/hash.c: Fix hashcmp() to handle length == 0 as in 4.0, and document the function, including this special case. --- mysys/hash.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/mysys/hash.c b/mysys/hash.c index b829f19dfc8..ffebdf76144 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -262,7 +262,25 @@ static void movelink(HASH_LINK *array,uint find,uint next_link,uint newlink) return; } - /* Compare a key in a record to a whole key. Return 0 if identical */ +/* + Compare a key in a record to a whole key. Return 0 if identical + + SYNOPSIS + hashcmp() + hash hash table + pos position of hash record to use in comparison + key key for comparison + length length of key + + NOTES: + If length is 0, comparison is done using the length of the + record being compared against. + + RETURN + < 0 key of record < key + = 0 key of record == key + > 0 key of record > key + */ static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length) { @@ -270,7 +288,7 @@ static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length) byte *rec_key= (byte*) hash_key(hash,pos->data,&rec_keylength,1); return ((length && length != rec_keylength) || my_strnncoll(hash->charset, (uchar*) rec_key, rec_keylength, - (uchar*) key, length)); + (uchar*) key, rec_keylength)); } From dd8e174fa6a07ebf21a3b0a03883d2be694b827b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Jun 2005 10:00:36 -0700 Subject: [PATCH 06/27] Additional tweak to fix for bug #10543, to prevent a change in behavior when extending fields that were fully part of a multi-part key. mysql-test/r/key.result: Update results mysql-test/t/key.test: Add test for behavior of extending fields in a multi-part key that were defined with a partial length the same as their field length. sql/sql_table.cc: Reset key_part_length when old field length was the same as the old key_part_length. --- mysql-test/r/key.result | 25 +++++++++++++++++++++++++ mysql-test/t/key.test | 13 +++++++++++++ sql/sql_table.cc | 4 ++++ 3 files changed, 42 insertions(+) diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result index 98e8851bb7e..3ad8571aadd 100644 --- a/mysql-test/r/key.result +++ b/mysql-test/r/key.result @@ -329,3 +329,28 @@ ERROR 42S21: Duplicate column name 'c1' alter table t1 add key (c1,c1,c2); ERROR 42S21: Duplicate column name 'c1' drop table t1; +create table t1 (a varchar(10), b varchar(10), key(a(10),b(10))); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(10) default NULL, + `b` varchar(10) default NULL, + KEY `a` (`a`,`b`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t1 modify b varchar(20); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(10) default NULL, + `b` varchar(20) default NULL, + KEY `a` (`a`,`b`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t1 modify a varchar(20); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(20) default NULL, + `b` varchar(20) default NULL, + KEY `a` (`a`,`b`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test index af3509c8454..9db1523be51 100644 --- a/mysql-test/t/key.test +++ b/mysql-test/t/key.test @@ -324,3 +324,16 @@ alter table t1 add key (c1,c2,c1); --error 1060 alter table t1 add key (c1,c1,c2); drop table t1; + +# +# If we use a partial field for a key that is actually the length of the +# field, and we extend the field, we end up with a key that includes the +# whole new length of the field. +# +create table t1 (a varchar(10), b varchar(10), key(a(10),b(10))); +show create table t1; +alter table t1 modify b varchar(20); +show create table t1; +alter table t1 modify a varchar(20); +show create table t1; +drop table t1; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2768d503751..eccba6a90ba 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3341,11 +3341,15 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, previous type, or the field length is less than the key part length, unset the key part length. + We also unset the key part length if it is the same as the + old field's length, so the whole new field will be used. + BLOBs may have cfield->length == 0, which is why we test it before checking whether cfield->length < key_part_length (in chars). */ if (!Field::type_can_have_key_part(cfield->field->type()) || !Field::type_can_have_key_part(cfield->sql_type) || + cfield->field->field_length == key_part_length || (cfield->length && (cfield->length < key_part_length / key_part->field->charset()->mbmaxlen))) key_part_length= 0; // Use whole field From f956ecd09a4897b5f7e65a0441445a52406a3a8a Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Jun 2005 17:13:43 +0200 Subject: [PATCH 07/27] Bug #10901 Analyze table corrupts the state on data_file_length, records, index_file_length... by writing the shared state when there is an updated internal state due to inserts or deletes Fixed by synching the shared state with the internal state before writing it to disk Added test cases of 2 error cases and a normal case in new analyze test case BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted --- BitKeeper/etc/logging_ok | 1 + myisam/mi_check.c | 6 ++++++ mysql-test/r/analyze.result | 32 ++++++++++++++++++++++++++++++ mysql-test/t/analyze.test | 39 +++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 mysql-test/r/analyze.result create mode 100644 mysql-test/t/analyze.test diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 499e3cdd4f5..f20e8ebc953 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -104,6 +104,7 @@ monty@tik. monty@tik.mysql.fi monty@tramp.mysql.fi monty@work.mysql.com +mronstrom@mysql.com mwagner@cash.mwagner.org mwagner@evoq.mwagner.org mwagner@here.mwagner.org diff --git a/myisam/mi_check.c b/myisam/mi_check.c index e78d831fde7..16946adb3e8 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -3623,6 +3623,12 @@ int update_state_info(MI_CHECK *param, MI_INFO *info,uint update) if (!share->state.create_time) share->state.create_time=share->state.check_time; } + /* + When tables are locked we haven't synched the share state and the + real state for a while so we better do it here before synching + the share state to disk. + */ + share->state.state= *info->state; if (mi_state_info_write(share->kfile,&share->state,1+2)) goto err; share->changed=0; diff --git a/mysql-test/r/analyze.result b/mysql-test/r/analyze.result new file mode 100644 index 00000000000..0b44a502b13 --- /dev/null +++ b/mysql-test/r/analyze.result @@ -0,0 +1,32 @@ +create table t1 (a bigint); +lock tables t1 write; +insert into t1 values(0); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +unlock tables; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; +create table t1 (a bigint); +insert into t1 values(0); +lock tables t1 write; +delete from t1; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +unlock tables; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; +create table t1 (a bigint); +insert into t1 values(0); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; diff --git a/mysql-test/t/analyze.test b/mysql-test/t/analyze.test new file mode 100644 index 00000000000..faf30279c68 --- /dev/null +++ b/mysql-test/t/analyze.test @@ -0,0 +1,39 @@ +# +# Bug #10901 Analyze Table on new table destroys table +# This is minimal test case to get error +# The problem was that analyze table wrote the shared state to the file and this +# didn't include the inserts while locked. A check was needed to ensure that +# state information was not updated when executing analyze table for a locked table. +# The analyze table had to be within locks and check table had to be after unlocking +# since then it brings the wrong state from disk rather than from the currently +# correct internal state. The insert is needed since it changes the file state, +# number of records. +# The fix is to synchronise the state of the shared state and the current state before +# calling mi_state_info_write +# +create table t1 (a bigint); +lock tables t1 write; +insert into t1 values(0); +analyze table t1; +unlock tables; +check table t1; + +drop table t1; + +create table t1 (a bigint); +insert into t1 values(0); +lock tables t1 write; +delete from t1; +analyze table t1; +unlock tables; +check table t1; + +drop table t1; + +create table t1 (a bigint); +insert into t1 values(0); +analyze table t1; +check table t1; + +drop table t1; + From 26bd158216e600c5f7ec7eaec9007fa761ea5195 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Jun 2005 22:52:24 +0200 Subject: [PATCH 08/27] Bug #10901 After review fix Copy from internal state to share state only when in lock write mode (happens only when lock table x write has been performed since update_state_info is only called when holding a TL_READ_NO_INSERT lock normally. Previous patch would have failed in combination with delayed writes. --- myisam/mi_check.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 16946adb3e8..a7c3d2a6f7e 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -3626,9 +3626,11 @@ int update_state_info(MI_CHECK *param, MI_INFO *info,uint update) /* When tables are locked we haven't synched the share state and the real state for a while so we better do it here before synching - the share state to disk. + the share state to disk. Only when table is write locked is it + necessary to perform this synch. */ - share->state.state= *info->state; + if (info->lock_type == F_WRLCK) + share->state.state= *info->state; if (mi_state_info_write(share->kfile,&share->state,1+2)) goto err; share->changed=0; From 575a46a1efe314b69c392482637af17c97c046e0 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 7 Jun 2005 22:43:25 +0200 Subject: [PATCH 09/27] bug#5373: handler READ NEXT w/o HANDLER READ [FIRST] check table->file->inited to catch incorrect calling sequence. mysql-test/r/innodb_handler.result: bug#5373: handler READ NEXT w/o HANDLER READ [FIRST] mysql-test/t/innodb_handler.test: bug#5373: handler READ NEXT w/o HANDLER READ [FIRST] sql/sql_handler.cc: cleanup: call index_init *correctly*, not every time. check table->file->inited to catch incorrect calling sequence. --- mysql-test/r/innodb_handler.result | 16 +++++++++++ mysql-test/t/innodb_handler.test | 10 +++++++ sql/sql_handler.cc | 46 +++++++++++++++++++----------- 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/mysql-test/r/innodb_handler.result b/mysql-test/r/innodb_handler.result index 7f4960ffa35..7e853a55e37 100644 --- a/mysql-test/r/innodb_handler.result +++ b/mysql-test/r/innodb_handler.result @@ -132,6 +132,22 @@ a b handler t2 read last; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 handler t2 close; +handler t1 open; +handler t1 read a next; +a b +14 aaa +handler t1 read a next; +a b +15 bbb +handler t1 close; +handler t1 open; +handler t1 read a prev; +a b +22 iii +handler t1 read a prev; +a b +21 hhh +handler t1 close; handler t1 open as t2; handler t2 read first; a b diff --git a/mysql-test/t/innodb_handler.test b/mysql-test/t/innodb_handler.test index e8c486caf66..65728519e7b 100644 --- a/mysql-test/t/innodb_handler.test +++ b/mysql-test/t/innodb_handler.test @@ -69,6 +69,16 @@ handler t2 read next; handler t2 read last; handler t2 close; +handler t1 open; +handler t1 read a next; # this used to crash as a bug#5373 +handler t1 read a next; +handler t1 close; + +handler t1 open; +handler t1 read a prev; # this used to crash as a bug#5373 +handler t1 read a prev; +handler t1 close; + handler t1 open as t2; handler t2 read first; alter table t1 engine=innodb; diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index aa791276404..491b82c1c1d 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -429,12 +429,10 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } tables->table=table; - if (cond && ((!cond->fixed && + if (cond && ((!cond->fixed && cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1))) goto err0; - table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it - if (keyname) { if ((keyno=find_type(keyname, &table->keynames, 1+2)-1)<0) @@ -443,8 +441,6 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, keyname,tables->alias); goto err0; } - table->file->ha_index_or_rnd_end(); - table->file->ha_index_init(keyno); } if (insert_fields(thd,tables,tables->db,tables->alias,&it)) @@ -471,9 +467,22 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, for (num_rows=0; num_rows < select_limit; ) { switch (mode) { + case RNEXT: + if (table->file->inited != handler::NONE) + { + err=keyname ? + table->file->index_next(table->record[0]) : + table->file->rnd_next(table->record[0]); + break; + } + /* else fall through */ case RFIRST: if (keyname) + { + table->file->ha_index_or_rnd_end(); + table->file->ha_index_init(keyno); err=table->file->index_first(table->record[0]); + } else { table->file->ha_index_or_rnd_end(); @@ -482,19 +491,20 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } mode=RNEXT; break; - case RLAST: - DBUG_ASSERT(keyname != 0); - err=table->file->index_last(table->record[0]); - mode=RPREV; - break; - case RNEXT: - err=keyname ? - table->file->index_next(table->record[0]) : - table->file->rnd_next(table->record[0]); - break; case RPREV: DBUG_ASSERT(keyname != 0); - err=table->file->index_prev(table->record[0]); + if (table->file->inited != handler::NONE) + { + err=table->file->index_prev(table->record[0]); + break; + } + /* else fall through */ + case RLAST: + DBUG_ASSERT(keyname != 0); + table->file->ha_index_or_rnd_end(); + table->file->ha_index_init(keyno); + err=table->file->index_last(table->record[0]); + mode=RPREV; break; case RNEXT_SAME: /* Continue scan on "(keypart1,keypart2,...)=(c1, c2, ...) */ @@ -517,7 +527,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, for (key_len=0 ; (item=it_ke++) ; key_part++) { // 'item' can be changed by fix_fields() call - if ((!item->fixed && + if ((!item->fixed && item->fix_fields(thd, tables, it_ke.ref())) || (item= *it_ke.ref())->check_cols(1)) goto err; @@ -535,6 +545,8 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, goto err; } key_copy(key, table, keyno, key_len); + table->file->ha_index_or_rnd_end(); + table->file->ha_index_init(keyno); err=table->file->index_read(table->record[0], key,key_len,ha_rkey_mode); mode=rkey_to_rnext[(int)ha_rkey_mode]; From 777899a6f568105ab6242516300acd937a9785ec Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 7 Jun 2005 15:45:03 -0500 Subject: [PATCH 10/27] improved mapping from numerical open codes to string fopen codes. This was necessary because the old code would return "w+" for O_RDONLY|O_SHARE for example. mysys/my_fopen.c: improved mapping from numerical open codes to string fopen codes. --- mysys/my_fopen.c | 62 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c index 3c6f1b15384..9dbac65b098 100644 --- a/mysys/my_fopen.c +++ b/mysys/my_fopen.c @@ -158,32 +158,52 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags) DBUG_RETURN(fd); } /* my_fdopen */ +/* + make_ftype + Make a filehandler-open-typestring from ordinary inputflags - /* Make a filehandler-open-typestring from ordinary inputflags */ - + Note: This routine attempts to find the best possible match + between a numeric option and a string option that could be + fed to fopen. There is not a 1 to 1 mapping between the two. + + r == O_RDONLY + w == O_WRONLY|O_TRUNC|O_CREAT + a == O_WRONLY|O_APPEND|O_CREAT + r+ == O_RDWR + w+ == O_RDWR|O_TRUNC|O_CREAT + a+ == O_RDWR|O_APPEND|O_CREAT +*/ static void make_ftype(register my_string to, register int flag) { -#if FILE_BINARY /* If we have binary-files */ +#if FILE_BINARY + /* If we have binary-files */ reg3 int org_flag=flag; -#endif - flag&= ~FILE_BINARY; /* remove binary bit */ - if (flag == O_RDONLY) - *to++= 'r'; - else if (flag == O_WRONLY) - *to++= 'w'; - else - { /* Add '+' after theese */ - if (flag == O_RDWR) +#endif + flag&= ~FILE_BINARY; /* remove binary bit */ + + /* check some possible invalid combinations */ + DBUG_ASSERT(flag & (O_TRUNC|O_APPEND) != O_TRUNC|O_APPEND); + + if (flag & (O_RDONLY|O_WRONLY) == O_WRONLY) + *to++= (flag & O_TRUNC) ? 'w' : 'a'; + else if (flag & O_RDWR) + { + /* Add '+' after theese */ + if (flag & O_TRUNC) + *to++= 'w'; + else if (flag & O_APPEND) + *to++= 'a'; + else *to++= 'r'; - else if (flag & O_APPEND) - *to++= 'a'; - else - *to++= 'w'; /* Create file */ - *to++= '+'; - } -#if FILE_BINARY /* If we have binary-files */ - if (org_flag & FILE_BINARY) + *to++= '+'; + } + else + *to++= 'r'; + +#if FILE_BINARY /* If we have binary-files */ + if (org_flag & FILE_BINARY) *to++='b'; -#endif +#endif *to='\0'; } /* make_ftype */ + From f4958dc0db510ddb2b44e2dee0b7ddbd9ab5d396 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 7 Jun 2005 18:23:58 -0700 Subject: [PATCH 11/27] Removed warnings for gcc 4.0 sql/log_event.cc: GCC 4.0 fix sql/sql_acl.cc: GCC 4.0 --- sql/log_event.cc | 2 +- sql/sql_acl.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index d4225b39704..e73a8c5f7f2 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -708,7 +708,7 @@ failed my_b_read")); Log_event *res= 0; #ifndef max_allowed_packet THD *thd=current_thd; - uint max_allowed_packet= thd ? thd->variables.max_allowed_packet : ~0; + uint max_allowed_packet= thd ? thd->variables.max_allowed_packet : ~(ulong)0; #endif if (data_len > max_allowed_packet) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index a11871c55dc..a062627a0e9 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -5172,7 +5172,7 @@ bool mysql_revoke_all(THD *thd, List &list) grant_proc->db, grant_proc->tname, is_proc, - ~0, 1)) + ~(ulong)0, 1)) { revoked= 1; continue; @@ -5240,7 +5240,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, lex_user.host.length= strlen(grant_proc->host.hostname); if (!replace_routine_table(thd,grant_proc,tables[4].table,lex_user, grant_proc->db, grant_proc->tname, - is_proc, ~0, 1)) + is_proc, ~(ulong)0, 1)) { revoked= 1; continue; From 59445ce472053bac4d96745e32d015fd4128cb61 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 8 Jun 2005 21:07:25 +0500 Subject: [PATCH 12/27] Fix for BUG#10675 - MySQL fails to build with --openssl on Mac OS X 10.4 BUG#11150 - HP-UX yaSSL/OpenSSL configure/header problem Remove obsolete code. include/my_global.h: Obsolete code removed. OpenSSL doesn't have crypt anymore (it was dropped in ~2003). This patch fixes compilation failures with both OpenSSL and yaSSL on systems where crypt was defined in unistd.h. Conclusion is we do not use OpenSSL's crypt unless it wasn't defined in unistd.h/crypt.h and it was defined in old OpenSSL. --- include/my_global.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/my_global.h b/include/my_global.h index f24bcd528ca..e2a97667a1f 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -248,13 +248,7 @@ C_MODE_END # endif #endif /* TIME_WITH_SYS_TIME */ #ifdef HAVE_UNISTD_H -#if defined(HAVE_OPENSSL) && !defined(__FreeBSD__) && !defined(NeXT) && !defined(__OpenBSD__) -#define crypt unistd_crypt -#endif #include -#ifdef HAVE_OPENSSL -#undef crypt -#endif #endif #if defined(__cplusplus) && defined(NO_CPLUSPLUS_ALLOCA) #undef HAVE_ALLOCA From fca6c2fe498b5f991e61d106da346ed5ef2d491d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 8 Jun 2005 23:58:34 +0500 Subject: [PATCH 13/27] WL#2286 - Compile MySQL w/YASSL support Fix for yaSSL compilation failure on ia64 platform. extra/yassl/taocrypt/include/types.hpp: Do not use assembler when yaSSL compiled with icc on ia64 platform. --- extra/yassl/taocrypt/include/types.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extra/yassl/taocrypt/include/types.hpp b/extra/yassl/taocrypt/include/types.hpp index 85e2f85d3dd..9c5d3e4b194 100644 --- a/extra/yassl/taocrypt/include/types.hpp +++ b/extra/yassl/taocrypt/include/types.hpp @@ -68,8 +68,9 @@ typedef unsigned int word32; // TODO: FIXME, add asm multiply for x86_64 on Solaris and remove !__sun -#if defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) || \ - defined(__mips64) || (defined(__x86_64__) && !defined(__sun)) +#if defined(__alpha__) || (defined(__ia64__) && !defined(__INTEL_COMPILER)) || \ + defined(_ARCH_PPC64) || defined(__mips64) || \ + (defined(__x86_64__) && !defined(__sun)) // These platforms have 64-bit CPU registers. Unfortunately most C++ compilers // don't allow any way to access the 64-bit by 64-bit multiply instruction // without using assembly, so in order to use word64 as word, the assembly From 344f13d6f1a774ef15f7c62f88cb58ed5bca9a7f Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 8 Jun 2005 18:57:39 -0700 Subject: [PATCH 14/27] Make sure we don't mistake a "grep mysqld" for a mysqld process when checking if the server is running in mysqld_safe. (Bug #11122) configure.in: Add "grep -v grep" to FIND_PROC so we don't mistake "grep mysqld" for a mysqld process. --- configure.in | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/configure.in b/configure.in index e685e811c2f..d454d23b38c 100644 --- a/configure.in +++ b/configure.in @@ -501,33 +501,33 @@ PS=$ac_cv_path_PS # Linux style if $PS p $$ 2> /dev/null | grep $0 > /dev/null then - FIND_PROC="$PS p \$\$PID | grep mysqld > /dev/null" + FIND_PROC="$PS p \$\$PID | grep -v grep | grep mysqld > /dev/null" # Solaris elif $PS -fp $$ 2> /dev/null | grep $0 > /dev/null then - FIND_PROC="$PS -p \$\$PID | grep mysqld > /dev/null" + FIND_PROC="$PS -p \$\$PID | grep -v grep | grep mysqld > /dev/null" # BSD style elif $PS -uaxww 2> /dev/null | grep $0 > /dev/null then - FIND_PROC="$PS -uaxww | grep mysqld | grep \" \$\$PID \" > /dev/null" + FIND_PROC="$PS -uaxww | grep -v grep | grep mysqld | grep \" \$\$PID \" > /dev/null" # SysV style elif $PS -ef 2> /dev/null | grep $0 > /dev/null then - FIND_PROC="$PS -ef | grep mysqld | grep \" \$\$PID \" > /dev/null" + FIND_PROC="$PS -ef | grep -v grep | grep mysqld | grep \" \$\$PID \" > /dev/null" # Do anybody use this? elif $PS $$ 2> /dev/null | grep $0 > /dev/null then - FIND_PROC="$PS \$\$PID | grep mysqld > /dev/null" + FIND_PROC="$PS \$\$PID | grep -v grep | grep mysqld > /dev/null" else case $SYSTEM_TYPE in *freebsd*) - FIND_PROC="$PS p \$\$PID | grep mysqld > /dev/null" + FIND_PROC="$PS p \$\$PID | grep -v grep | grep mysqld > /dev/null" ;; *darwin*) - FIND_PROC="$PS -uaxww | grep mysqld | grep \" \$\$PID \" > /dev/null" + FIND_PROC="$PS -uaxww | grep -v grep | grep mysqld | grep \" \$\$PID \" > /dev/null" ;; *cygwin*) - FIND_PROC="$PS -e | grep mysqld | grep \" \$\$PID \" > /dev/null" + FIND_PROC="$PS -e | grep -v grep | grep mysqld | grep \" \$\$PID \" > /dev/null" ;; *netware* | *modesto*) FIND_PROC= From b854d06bf03def4a1ecc43a96893dd7ec8f4b58c Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Jun 2005 07:49:48 +0200 Subject: [PATCH 15/27] ndb - uint overflow when running on 64-bit platform with more than 4Gb of mem bug#10711 bug#10058 bug#9363 bug#9025 bug#8918 ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp: Use UintPtr when computing page address to make sure that Uint32 does not overflow --- ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp b/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp index 9750e1c5179..6f848d7fe16 100644 --- a/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp +++ b/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp @@ -247,10 +247,10 @@ Ndbfs::readWriteRequest(int action, Signal * signal) AsyncFile* openFile = theOpenFiles.find(filePointer); const NewVARIABLE *myBaseAddrRef = &getBat(blockNumber)[fsRWReq->varIndex]; - unsigned int tPageSize; - unsigned int tClusterSize; - unsigned int tNRR; - unsigned int tPageOffset; + UintPtr tPageSize; + UintPtr tClusterSize; + UintPtr tNRR; + UintPtr tPageOffset; char* tWA; FsRef::NdbfsErrorCodeType errorCode; @@ -294,8 +294,8 @@ Ndbfs::readWriteRequest(int action, Signal * signal) jam(); for (unsigned int i = 0; i < fsRWReq->numberOfPages; i++) { jam(); - const Uint32 varIndex = fsRWReq->data.listOfPair[i].varIndex; - const Uint32 fileOffset = fsRWReq->data.listOfPair[i].fileOffset; + const UintPtr varIndex = fsRWReq->data.listOfPair[i].varIndex; + const UintPtr fileOffset = fsRWReq->data.listOfPair[i].fileOffset; if (varIndex >= tNRR) { jam(); errorCode = FsRef::fsErrInvalidParameters; @@ -316,8 +316,8 @@ Ndbfs::readWriteRequest(int action, Signal * signal) errorCode = FsRef::fsErrInvalidParameters; goto error; }//if - const Uint32 varIndex = fsRWReq->data.arrayOfPages.varIndex; - const Uint32 fileOffset = fsRWReq->data.arrayOfPages.fileOffset; + const UintPtr varIndex = fsRWReq->data.arrayOfPages.varIndex; + const UintPtr fileOffset = fsRWReq->data.arrayOfPages.fileOffset; request->par.readWrite.pages[0].offset = fileOffset * tPageSize; request->par.readWrite.pages[0].size = tPageSize * fsRWReq->numberOfPages; @@ -334,7 +334,7 @@ Ndbfs::readWriteRequest(int action, Signal * signal) for (unsigned int i = 0; i < fsRWReq->numberOfPages; i++) { jam(); - Uint32 varIndex = fsRWReq->data.listOfMemPages.varIndex[i]; + UintPtr varIndex = fsRWReq->data.listOfMemPages.varIndex[i]; if (varIndex >= tNRR) { jam(); From af0287be3c97eb1a4e42c6dd1b32e47b918139ce Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Jun 2005 08:07:48 +0200 Subject: [PATCH 16/27] ndb - autotest small script fixes - Don't use hostname -s as it's linux specific - Don't remove result unless scp worked ndb/test/run-test/ndb-autotest.sh: Don't use hostname -s as it's linux specific Don't remove result unless scp worked --- ndb/test/run-test/ndb-autotest.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ndb/test/run-test/ndb-autotest.sh b/ndb/test/run-test/ndb-autotest.sh index 3ba4d1928d5..09087a8a8c7 100755 --- a/ndb/test/run-test/ndb-autotest.sh +++ b/ndb/test/run-test/ndb-autotest.sh @@ -13,7 +13,7 @@ save_args=$* VERSION="ndb-autotest.sh version 1.04" DATE=`date '+%Y-%m-%d'` -HOST=`hostname -s` +HOST=`hostname` export DATE HOST set -e @@ -330,7 +330,10 @@ start(){ tar cfz /tmp/res.$2.$$.tgz `basename $p2`/$DATE scp /tmp/res.$2.$$.tgz \ $result_host:$result_path/res.$DATE.$HOST.$2.$$.tgz - rm -f /tmp/res.$2.$$.tgz + if [ $? -eq 0 ] + then + rm -f /tmp/res.$2.$$.tgz + fi fi } From 98c2ec75387113c265f4eaa9c66c28577516d51b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Jun 2005 12:44:44 +0500 Subject: [PATCH 17/27] Fix for bug #8482 (Incorrect rounding) mysql-test/r/type_newdecimal.result: test result fixed mysql-test/t/type_newdecimal.test: test case added strings/decimal.c: in round(999.9, 0) case we have to increase intg --- mysql-test/r/type_newdecimal.result | 8 ++++++++ mysql-test/t/type_newdecimal.test | 7 +++++++ strings/decimal.c | 8 ++++++++ 3 files changed, 23 insertions(+) diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index c0693d1585c..b406dbab82f 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -896,6 +896,14 @@ create table t1( d1 decimal(18) unsigned, d2 decimal(20) unsigned, d3 decimal (2 insert into t1 values(1,-1,-1); ERROR 22003: Out of range value adjusted for column 'd2' at row 1 drop table t1; +create table t1 (col1 decimal(5,2), col2 numeric(5,2)); +insert into t1 values (999.999,999.999); +ERROR 22003: Out of range value adjusted for column 'col1' at row 1 +insert into t1 values (-999.999,-999.999); +ERROR 22003: Out of range value adjusted for column 'col1' at row 1 +select * from t1; +col1 col2 +drop table t1; set sql_mode=''; set @sav_dpi= @@div_precision_increment; set @@div_precision_increment=15; diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index d1d595285a2..6199bd34fa9 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -934,6 +934,13 @@ create table t1( d1 decimal(18) unsigned, d2 decimal(20) unsigned, d3 decimal (2 --error 1264 insert into t1 values(1,-1,-1); drop table t1; +create table t1 (col1 decimal(5,2), col2 numeric(5,2)); +--error 1264 +insert into t1 values (999.999,999.999); +--error 1264 +insert into t1 values (-999.999,-999.999); +select * from t1; +drop table t1; set sql_mode=''; # diff --git a/strings/decimal.c b/strings/decimal.c index 787d00dcb46..4a487f3c9b0 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -1546,6 +1546,14 @@ decimal_round(decimal_t *from, decimal_t *to, int scale, *buf1=1; to->intg++; } + /* Here we check 999.9 -> 1000 case when we need to increase intg */ + else + { + int first_dig= to->intg % DIG_PER_DEC1; + /* first_dig==0 should be handled above in the 'if' */ + if (first_dig && (*buf1 >= powers10[first_dig])) + to->intg++; + } } else { From 897b3c50e8cd5d80e61b8ae8276604a7e3d76ba5 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Jun 2005 13:13:02 +0500 Subject: [PATCH 18/27] a fix (bug #11193: error messages gets garbled after reggies latest changeset: ChangeSet@1.2260.1.). --- mysys/my_fopen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c index 9dbac65b098..002e5ca0f06 100644 --- a/mysys/my_fopen.c +++ b/mysys/my_fopen.c @@ -185,11 +185,11 @@ static void make_ftype(register my_string to, register int flag) DBUG_ASSERT(flag & (O_TRUNC|O_APPEND) != O_TRUNC|O_APPEND); if (flag & (O_RDONLY|O_WRONLY) == O_WRONLY) - *to++= (flag & O_TRUNC) ? 'w' : 'a'; + *to++= (flag & O_APPEND) ? 'a' : 'w'; else if (flag & O_RDWR) { /* Add '+' after theese */ - if (flag & O_TRUNC) + if (flag & (O_TRUNC | O_CREAT)) *to++= 'w'; else if (flag & O_APPEND) *to++= 'a'; From f160958770ce85fe0d26f3b816d059caaf2fd67d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Jun 2005 14:39:29 +0500 Subject: [PATCH 19/27] Fix for bug#10732: Set SQL_MODE to NULL gives garbled error message generate proper error message if we use SET ... = NULL for 'set' variables --- mysql-test/r/sql_mode.result | 2 ++ mysql-test/t/sql_mode.test | 5 +++++ sql/set_var.cc | 3 +++ 3 files changed, 10 insertions(+) diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result index c18be2df403..652913d1fdb 100644 --- a/mysql-test/r/sql_mode.result +++ b/mysql-test/r/sql_mode.result @@ -138,3 +138,5 @@ t1 CREATE TABLE `t1` ( `min_num` decimal(7,6) default '0.000001' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1 ; +set @@SQL_MODE=NULL; +ERROR 42000: Variable 'sql_mode' can't be set to the value of 'NULL' diff --git a/mysql-test/t/sql_mode.test b/mysql-test/t/sql_mode.test index f841d36e837..985c0853bd2 100644 --- a/mysql-test/t/sql_mode.test +++ b/mysql-test/t/sql_mode.test @@ -80,3 +80,8 @@ create table t1 ( min_num dec(6,6) default .000001); show create table t1; drop table t1 ; +# +# Bug #10732: Set SQL_MODE to NULL gives garbled error message +# +--error 1231 +set @@SQL_MODE=NULL; diff --git a/sql/set_var.cc b/sql/set_var.cc index 0fa9932dbbc..0f13a8a7f2d 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1515,7 +1515,10 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) if (var->value->result_type() == STRING_RESULT) { if (!(res= var->value->val_str(&str))) + { + strmake(buff, "NULL", 4); goto err; + } var->save_result.ulong_value= ((ulong) find_set(enum_names, res->c_ptr(), res->length(), From 0e54a4e84f11d13421e85b93d1fac51c31f92bf0 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Jun 2005 12:26:45 +0200 Subject: [PATCH 20/27] update result file for ps7_ndb mysql-test/r/ps_7ndb.result: fix result file --- mysql-test/r/ps_7ndb.result | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index e7a4ff40e2b..f5750d947b5 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -1151,13 +1151,13 @@ execute stmt1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 -def table 253 64 2 N 1 31 8 -def type 253 10 3 N 1 31 8 +def table 253 64 2 Y 0 31 8 +def type 253 10 3 Y 0 31 8 def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 def ref 253 1024 0 Y 0 31 8 -def rows 8 10 1 N 32929 0 63 +def rows 8 10 1 Y 32928 0 63 def Extra 253 255 0 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t9 ALL NULL NULL NULL NULL 2 From 146893a7a0b632d8fcb90e391c788dc34db84bef Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Jun 2005 15:27:26 +0500 Subject: [PATCH 21/27] Fix for bug #10083 (round doesn't increase scale) mysql-test/r/func_math.result: test result fixed mysql-test/t/func_math.test: test case added sql/item_func.cc: now we always use decimals_to_set --- mysql-test/r/func_math.result | 3 +++ mysql-test/t/func_math.test | 5 +++++ sql/item_func.cc | 19 +++++++------------ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index e4889289c18..c7674c57c8d 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -143,3 +143,6 @@ select format(col2,6) from t1 where col1=7; format(col2,6) 1,234,567,890,123,456.123450 drop table t1; +select round(150, 2); +round(150, 2) +150.00 diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index b21f38052b6..03057af6911 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -79,3 +79,8 @@ insert into t1 values(7,1234567890123456.12345); select format(col2,6) from t1 where col1=7; drop table t1; + +# +# Bug #10083 (round doesn't increase decimals) +# +select round(150, 2); diff --git a/sql/item_func.cc b/sql/item_func.cc index 68292859504..c3fc537f04e 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1876,7 +1876,8 @@ void Item_func_round::fix_length_and_dec() max_length= float_length(decimals); break; case INT_RESULT: - if (truncate || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS)) + if ((decimals_to_set==0) && + (truncate || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS))) { /* Here we can keep INT_RESULT */ hybrid_type= INT_RESULT; @@ -1890,18 +1891,12 @@ void Item_func_round::fix_length_and_dec() hybrid_type= DECIMAL_RESULT; int decimals_delta= args[0]->decimals - decimals_to_set; int precision= args[0]->decimal_precision(); - if (decimals_delta > 0) - { - int length_increase= truncate ? 0:1; - precision-= decimals_delta - length_increase; - decimals= decimals_to_set; - } - else - /* Decimals to set is bigger that the original scale */ - /* we keep original decimals value */ - decimals= args[0]->decimals; + int length_increase= ((decimals_delta <= 0) || truncate) ? 0:1; + + precision-= decimals_delta - length_increase; + decimals= decimals_to_set; max_length= my_decimal_precision_to_length(precision, decimals, - unsigned_flag); + unsigned_flag); break; } default: From d974ce936e6e54a28f08a349f865554e029c08dc Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Jun 2005 18:00:50 +0400 Subject: [PATCH 22/27] Fix broken test suite. --- mysql-test/r/ps_6bdb.result | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index f69db9c1e42..06be8750cc4 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -1151,13 +1151,13 @@ execute stmt1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 -def table 253 64 2 N 1 31 8 -def type 253 10 3 N 1 31 8 +def table 253 64 2 Y 0 31 8 +def type 253 10 3 Y 0 31 8 def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 def ref 253 1024 0 Y 0 31 8 -def rows 8 10 1 N 32929 0 63 +def rows 8 10 1 Y 32928 0 63 def Extra 253 255 0 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t9 ALL NULL NULL NULL NULL 3 From d0db70270c59c8def10980c76173b3072263ef25 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Jun 2005 18:17:45 +0400 Subject: [PATCH 23/27] A fix and test case for Bug#10729 "mysql_stmt_attr_set CURSOR_TYPE_READ_ONLY". The bug was that we (me) don't perform proper cleanups of the prepared statement when done fetching from a cursor. Another patch. sql/mysql_priv.h: Rename reset_stmt_for_execute to init_stmt_before_use (to correspond to cleanup_stmt_and_thd_after_use). sql/sp_head.cc: Rename. sql/sql_prepare.cc: Move common cleanup code to a cleanup function, call it when we close a cursor. sql/sql_select.cc: Cleanup. sql/sql_select.h: No need for init_thd, this code has been inlined in Cursor::open. tests/mysql_client_test.c: Add a test case for Bug#10729 "mysql_stmt_attr_set CURSOR_TYPE_READ_ONLY" (problem reusing a prepared statemnt if there was a cursor) --- sql/mysql_priv.h | 2 +- sql/sp_head.cc | 2 +- sql/sql_prepare.cc | 58 +++++++++++++++++++++--------------- sql/sql_select.cc | 35 +++++++++------------- sql/sql_select.h | 2 -- tests/mysql_client_test.c | 62 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 112 insertions(+), 49 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 4dca5e32c89..10ee5483d19 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -834,7 +834,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length); void mysql_stmt_free(THD *thd, char *packet); void mysql_stmt_reset(THD *thd, char *packet); void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length); -void reset_stmt_for_execute(THD *thd, LEX *lex); +void reinit_stmt_before_use(THD *thd, LEX *lex); void init_stmt_after_parse(THD*, LEX*); /* sql_handler.cc */ diff --git a/sql/sp_head.cc b/sql/sp_head.cc index f3459e5b104..8ac9ed1a338 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1355,7 +1355,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, implemented at the same time as ability not to store LEX for instruction if it is not really used. */ - reset_stmt_for_execute(thd, m_lex); + reinit_stmt_before_use(thd, m_lex); /* If requested check whenever we have access to tables in LEX's table list diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index f1b3c69264c..37efd1d62b9 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1656,6 +1656,17 @@ static bool init_param_array(Prepared_statement *stmt) return FALSE; } + +/* Cleanup PS after execute/prepare and restore THD state */ + +static void cleanup_stmt_and_thd_after_use(Statement *stmt, THD *thd) +{ + stmt->lex->unit.cleanup(); + cleanup_items(stmt->free_list); + thd->rollback_item_tree_changes(); + thd->cleanup_after_query(); +} + /* Given a query string with parameter markers, create a Prepared Statement from it and send PS info back to the client. @@ -1760,12 +1771,9 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, thd->lex->sphead= NULL; } lex_end(lex); - lex->unit.cleanup(); close_thread_tables(thd); + cleanup_stmt_and_thd_after_use(stmt, thd); thd->restore_backup_statement(stmt, &thd->stmt_backup); - cleanup_items(stmt->free_list); - thd->rollback_item_tree_changes(); - thd->cleanup_after_query(); thd->current_arena= thd; if (error) @@ -1808,10 +1816,10 @@ void init_stmt_after_parse(THD *thd, LEX *lex) /* Reinit prepared statement/stored procedure before execution */ -void reset_stmt_for_execute(THD *thd, LEX *lex) +void reinit_stmt_before_use(THD *thd, LEX *lex) { SELECT_LEX *sl= lex->all_selects_list; - DBUG_ENTER("reset_stmt_for_execute"); + DBUG_ENTER("reinit_stmt_before_use"); if (lex->empty_field_list_on_rset) { @@ -2007,7 +2015,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) thd->stmt_backup.set_statement(thd); thd->set_statement(stmt); thd->current_arena= stmt; - reset_stmt_for_execute(thd, stmt->lex); + reinit_stmt_before_use(thd, stmt->lex); /* From now cursors assume that thd->mem_root is clean */ if (expanded_query.length() && alloc_query(thd, (char *)expanded_query.ptr(), @@ -2031,17 +2039,18 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) if (cursor && cursor->is_open()) { + /* + It's safer if we grab THD state after mysql_execute_command is + finished and not in Cursor::open(), because currently the call to + Cursor::open is buried deep in JOIN::exec of the top level join. + */ cursor->init_from_thd(thd); - cursor->state= stmt->state; } else { - thd->lex->unit.cleanup(); - cleanup_items(stmt->free_list); + close_thread_tables(thd); + cleanup_stmt_and_thd_after_use(stmt, thd); reset_stmt_params(stmt); - close_thread_tables(thd); /* to close derived tables */ - thd->rollback_item_tree_changes(); - thd->cleanup_after_query(); } thd->set_statement(&thd->stmt_backup); @@ -2119,7 +2128,7 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt, { DBUG_ENTER("execute_stmt"); - reset_stmt_for_execute(thd, stmt->lex); + reinit_stmt_before_use(thd, stmt->lex); if (expanded_query->length() && alloc_query(thd, (char *)expanded_query->ptr(), @@ -2141,14 +2150,11 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt, if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); - thd->lex->unit.cleanup(); - thd->current_arena= thd; - cleanup_items(stmt->free_list); - thd->rollback_item_tree_changes(); - reset_stmt_params(stmt); close_thread_tables(thd); // to close derived tables + cleanup_stmt_and_thd_after_use(stmt, thd); + reset_stmt_params(stmt); thd->set_statement(&thd->stmt_backup); - thd->cleanup_after_query(); + thd->current_arena= thd; if (stmt->state == Item_arena::PREPARED) stmt->state= Item_arena::EXECUTED; @@ -2171,7 +2177,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) /* assume there is always place for 8-16 bytes */ ulong stmt_id= uint4korr(packet); ulong num_rows= uint4korr(packet+4); - Statement *stmt; + Prepared_statement *stmt; DBUG_ENTER("mysql_stmt_fetch"); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch"))) @@ -2185,7 +2191,6 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) thd->current_arena= stmt; thd->set_n_backup_statement(stmt, &thd->stmt_backup); - stmt->cursor->init_thd(thd); if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), QUERY_PRIOR); @@ -2197,11 +2202,16 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); - /* Restore THD state */ - stmt->cursor->reset_thd(thd); thd->restore_backup_statement(stmt, &thd->stmt_backup); thd->current_arena= thd; + if (!stmt->cursor->is_open()) + { + /* We're done with the fetch: reset PS for next execution */ + cleanup_stmt_and_thd_after_use(stmt, thd); + reset_stmt_params(stmt); + } + DBUG_VOID_RETURN; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 24b9d0b4713..099b7857af8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1709,10 +1709,11 @@ Cursor::init_from_thd(THD *thd) We need to save and reset thd->mem_root, otherwise it'll be freed later in mysql_parse. - We can't just change the thd->mem_root here as we want to keep the things - that is already allocated in thd->mem_root for Cursor::fetch() + We can't just change the thd->mem_root here as we want to keep the + things that are already allocated in thd->mem_root for Cursor::fetch() */ main_mem_root= *thd->mem_root; + state= thd->current_arena->state; /* Allocate new memory root for thd */ init_sql_alloc(thd->mem_root, thd->variables.query_alloc_block_size, @@ -1735,24 +1736,6 @@ Cursor::init_from_thd(THD *thd) What problems can we have with it if cursor is open? TODO: must be fixed because of the prelocked mode. */ - /* - TODO: grab thd->free_list here? - */ -} - - -void -Cursor::init_thd(THD *thd) -{ - DBUG_ASSERT(thd->derived_tables == 0); - thd->derived_tables= derived_tables; - - DBUG_ASSERT(thd->open_tables == 0); - thd->open_tables= open_tables; - - DBUG_ASSERT(thd->lock== 0); - thd->lock= lock; - thd->query_id= query_id; } @@ -1828,6 +1811,13 @@ Cursor::fetch(ulong num_rows) DBUG_ENTER("Cursor::fetch"); DBUG_PRINT("enter",("rows: %lu", num_rows)); + DBUG_ASSERT(thd->derived_tables == 0 && thd->open_tables == 0 && + thd->lock == 0); + + thd->derived_tables= derived_tables; + thd->open_tables= open_tables; + thd->lock= lock; + thd->query_id= query_id; /* save references to memory, allocated during fetch */ thd->set_n_backup_item_arena(this, &thd->stmt_backup); @@ -1846,6 +1836,9 @@ Cursor::fetch(ulong num_rows) #endif thd->restore_backup_item_arena(this, &thd->stmt_backup); + DBUG_ASSERT(thd->free_list == 0); + reset_thd(thd); + if (error == NESTED_LOOP_CURSOR_LIMIT) { /* Fetch limit worked, possibly more rows are there */ @@ -1886,8 +1879,8 @@ Cursor::close() join->cleanup(); delete join; } - /* XXX: Another hack: closing tables used in the cursor */ { + /* XXX: Another hack: closing tables used in the cursor */ DBUG_ASSERT(lock || open_tables || derived_tables); TABLE *tmp_derived_tables= thd->derived_tables; diff --git a/sql/sql_select.h b/sql/sql_select.h index 49ac58e913b..5351bbb13d3 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -386,8 +386,6 @@ public: /* Temporary implementation as now we replace THD state by value */ /* Save THD state into cursor */ void init_from_thd(THD *thd); - /* Restore THD from cursor to continue cursor execution */ - void init_thd(THD *thd); /* bzero cursor state in THD */ void reset_thd(THD *thd); diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 002076afd90..b6ca4996c70 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -13145,6 +13145,67 @@ static void test_bug9643() myquery(rc); } +/* + Check that proper cleanups are done for prepared statement when + fetching thorugh a cursor. +*/ + +static void test_bug10729() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + char a[21]; + int rc; + const char *stmt_text; + int i= 0; + char *name_array[3]= { "aaa", "bbb", "ccc" }; + ulong type; + + myheader("test_bug10729"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (id integer not null primary key," + "name VARCHAR(20) NOT NULL)"); + rc= mysql_query(mysql, "insert into t1 (id, name) values " + "(1, 'aaa'), (2, 'bbb'), (3, 'ccc')"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + + type= (ulong) CURSOR_TYPE_READ_ONLY; + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); + check_execute(stmt, rc); + stmt_text= "select name from t1"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + bzero(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void*) a; + bind[0].buffer_length= sizeof(a); + mysql_stmt_bind_result(stmt, bind); + + for (i= 0; i < 3; i++) + { + int row_no= 0; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + while ((rc= mysql_stmt_fetch(stmt)) == 0) + { + DIE_UNLESS(strcmp(a, name_array[row_no]) == 0); + if (!opt_silent) + printf("%d: %s\n", row_no, a); + ++row_no; + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + } + rc= mysql_stmt_close(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + /* Read and parse arguments and MySQL options from my.cnf */ @@ -13377,6 +13438,7 @@ static struct my_tests_st my_tests[]= { { "test_bug9520", test_bug9520 }, { "test_bug9478", test_bug9478 }, { "test_bug9643", test_bug9643 }, + { "test_bug10729", test_bug10729 }, { 0, 0 } }; From c995109b699a56e94bbc82754b17622f271ebb39 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Jun 2005 16:06:15 +0100 Subject: [PATCH 24/27] Bug#11028 Crash on create table like Report error instead of crashing mysql-test/r/create.result: Test for bug 11028 mysql-test/t/create.test: Test for bug 11028 sql/sql_table.cc: fix for null db name --- mysql-test/r/create.result | 6 ++++++ mysql-test/t/create.test | 11 +++++++++++ sql/sql_table.cc | 15 ++++++++++----- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index de3840447dc..4c4b388388a 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -580,3 +580,9 @@ ERROR 42000: Incorrect database name 'xyz' create table t1(t1.name int); create table t2(test.t2.name int); drop table t1,t2; +create database mysqltest; +use mysqltest; +drop database mysqltest; +create table test.t1 like x; +ERROR 42000: Incorrect database name 'NULL' +drop table if exists test.t1; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index b73cd28c71c..ca3446b46fc 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -492,3 +492,14 @@ create table t1(t1.name int); create table t2(test.t2.name int); drop table t1,t2; +# +# Bug#11028: Crash on create table like +# +create database mysqltest; +use mysqltest; +drop database mysqltest; +--error 1102 +create table test.t1 like x; +--disable_warnings +drop table if exists test.t1; +--enable_warnings diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3aa6da7ad0c..e2e6ee23323 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2298,26 +2298,31 @@ int mysql_create_like_table(THD* thd, TABLE_LIST* table, char src_path[FN_REFLEN], dst_path[FN_REFLEN]; char *db= table->db; char *table_name= table->real_name; - char *src_db= thd->db; + char *src_db; char *src_table= table_ident->table.str; int err, res= -1; TABLE_LIST src_tables_list; DBUG_ENTER("mysql_create_like_table"); + src_db= table_ident->db.str ? table_ident->db.str : thd->db; /* Validate the source table */ if (table_ident->table.length > NAME_LEN || (table_ident->table.length && - check_table_name(src_table,table_ident->table.length)) || - table_ident->db.str && check_db_name((src_db= table_ident->db.str))) + check_table_name(src_table,table_ident->table.length))) { my_error(ER_WRONG_TABLE_NAME, MYF(0), src_table); DBUG_RETURN(-1); } + if (!src_db || check_db_name(src_db)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), src_db ? src_db : "NULL"); + DBUG_RETURN(-1); + } - src_tables_list.db= table_ident->db.str ? table_ident->db.str : thd->db; - src_tables_list.real_name= table_ident->table.str; + src_tables_list.db= src_db; + src_tables_list.real_name= src_table; src_tables_list.next= 0; if (lock_and_wait_for_table_name(thd, &src_tables_list)) From 8ab8fca7d54c0f177ef57f8c09e203eb212b05e8 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Jun 2005 09:16:16 -0700 Subject: [PATCH 25/27] select.test, select.result: Added a test case for bug #10084. sql_yacc.yy: Fixed bug #10084: STRAIGHT_JOIN for expressions with ON was added. sql/sql_yacc.yy: Fixed bug #10084: STRAIGHT_JOIN for expressions with ON was added. mysql-test/r/select.result: Added a test case for bug #10084. mysql-test/t/select.test: Added a test case for bug #10084. --- mysql-test/r/select.result | 17 +++++++++++++++++ mysql-test/t/select.test | 16 ++++++++++++++++ sql/sql_yacc.yy | 6 ++++-- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index eaed7719673..1c0321ac658 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2682,3 +2682,20 @@ AND FK_firma_id = 2; COUNT(*) 0 drop table t1; +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int); +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); +INSERT INTO t2 VALUES (2), (4), (6); +SELECT t1.a FROM t1 STRAIGHT_JOIN t2 ON t1.a=t2.a; +a +2 +4 +EXPLAIN SELECT t1.a FROM t1 STRAIGHT_JOIN t2 ON t1.a=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where +EXPLAIN SELECT t1.a FROM t1 INNER JOIN t2 ON t1.a=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where +DROP TABLE t1,t2; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index b6132d23d02..372325c4cbd 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2255,3 +2255,19 @@ AND FK_firma_id = 2; drop table t1; +# +# Test for bug #10084: STRAIGHT_JOIN with ON expression +# + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int); +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); +INSERT INTO t2 VALUES (2), (4), (6); + +SELECT t1.a FROM t1 STRAIGHT_JOIN t2 ON t1.a=t2.a; + +EXPLAIN SELECT t1.a FROM t1 STRAIGHT_JOIN t2 ON t1.a=t2.a; +EXPLAIN SELECT t1.a FROM t1 INNER JOIN t2 ON t1.a=t2.a; + +DROP TABLE t1,t2; + diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 8ece85b3dee..33d6c192d07 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5108,10 +5108,12 @@ derived_table_list: join_table: table_ref normal_join table_ref { TEST_ASSERT($1 && ($$=$3)); } - | table_ref STRAIGHT_JOIN table_factor - { TEST_ASSERT($1 && ($$=$3)); $3->straight=1; } + | table_ref STRAIGHT_JOIN table_ref + { TEST_ASSERT($1 && ($$=$3)); $3->straight=1; } | table_ref normal_join table_ref ON expr { TEST_ASSERT($1 && ($$=$3)); add_join_on($3,$5); } + | table_ref STRAIGHT_JOIN table_ref ON expr + { TEST_ASSERT($1 && ($$=$3)); $3->straight=1; add_join_on($3,$5); } | table_ref normal_join table_ref USING { From 5643df2d5846ecbc16e75a607f8d2afb4fb93090 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Jun 2005 21:50:22 +0300 Subject: [PATCH 26/27] Fixes in function modify_defaults_file(): - Removed unneccessary variables. - Made a function of that part of code, which actually changes the line under modifications. - Fixed memory overrun problem with my_malloc. Too little space was reserved. - Fixed problem in case, when new option was added at the end of the section. Before, it was added as the last line of the section, even if it left empty lines between. - Fixed so that the configuration file is not saved unneccessarily, if no modifications are done. (file timestamp remains) - This should fix (at least partially) problems described in Bug#10806 --- mysys/default_modify.c | 115 ++++++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 46 deletions(-) diff --git a/mysys/default_modify.c b/mysys/default_modify.c index add4317bb56..721ca596428 100644 --- a/mysys/default_modify.c +++ b/mysys/default_modify.c @@ -37,22 +37,20 @@ #define NEWLINE_LEN 1 #endif +static char *add_option(char *dst, const char *option_value, + const char *option, int remove_option); + int modify_defaults_file(const char *file_location, const char *option, const char *option_value, const char *section_name, int remove_option) { FILE *cnf_file; MY_STAT file_stat; - char linebuff[BUFF_SIZE], tmp[BUFF_SIZE], *tmp_ptr, *src_ptr, *dst_ptr, - *file_buffer; - uint optlen, optval_len, sect_len; - my_bool in_section= FALSE; + char linebuff[BUFF_SIZE], *src_ptr, *dst_ptr, *file_buffer; + uint optlen, optval_len, sect_len, nr_newlines= 0; + my_bool in_section= FALSE, opt_applied= 0; DBUG_ENTER("modify_defaults_file"); - optlen= strlen(option); - optval_len= strlen(option_value); - sect_len= strlen(section_name); - if (!(cnf_file= my_fopen(file_location, O_RDWR | O_BINARY, MYF(0)))) DBUG_RETURN(2); @@ -60,12 +58,15 @@ int modify_defaults_file(const char *file_location, const char *option, if (my_fstat(fileno(cnf_file), &file_stat, MYF(0))) goto err; + optlen= strlen(option); + optval_len= strlen(option_value); + /* Reserve space to read the contents of the file and some more for the option we want to add. */ - if (!(file_buffer= (char*) my_malloc(sizeof(char)* - (file_stat.st_size + + if (!(file_buffer= (char*) my_malloc(sizeof(char) * + (file_stat.st_size + /* option name len */ optlen + /* reserve space for newline */ @@ -73,35 +74,44 @@ int modify_defaults_file(const char *file_location, const char *option, /* reserve for '=' char */ 1 + /* option value len */ - optval_len), MYF(MY_WME)))) + optval_len + + /* The ending zero plus some safety */ + FN_REFLEN), MYF(MY_WME)))) goto malloc_err; - for (dst_ptr= file_buffer, tmp_ptr= 0; - fgets(linebuff, BUFF_SIZE, cnf_file); ) + sect_len= strlen(section_name); + + for (dst_ptr= file_buffer; fgets(linebuff, BUFF_SIZE, cnf_file); ) { /* Skip over whitespaces */ for (src_ptr= linebuff; my_isspace(&my_charset_latin1, *src_ptr); src_ptr++) {} - if (in_section && !strncmp(src_ptr, option, optlen) && + if (!*src_ptr) /* Empty line */ + { + nr_newlines++; + continue; + } + + if (!opt_applied && in_section && !strncmp(src_ptr, option, optlen) && (*(src_ptr + optlen) == '=' || my_isspace(&my_charset_latin1, *(src_ptr + optlen)) || *(src_ptr + optlen) == '\0')) { - /* The option under modifying was found in this section. Apply new. */ - if (!remove_option) - dst_ptr= strmov(dst_ptr, tmp); - tmp_ptr= 0; /* To mark that we have already applied this */ + dst_ptr= add_option(dst_ptr, option_value, option, remove_option); + opt_applied= 1; } else { /* If going to new group and we have option to apply, do it now */ - if (tmp_ptr && *src_ptr == '[') + if (in_section && !opt_applied && *src_ptr == '[') { - dst_ptr= strmov(dst_ptr, tmp); - tmp_ptr= 0; + dst_ptr= add_option(dst_ptr, option_value, option, remove_option); + } + for (; nr_newlines; nr_newlines--) + dst_ptr= strmov(dst_ptr, NEWLINE); dst_ptr= strmov(dst_ptr, linebuff); } /* Look for a section */ @@ -117,43 +127,38 @@ int modify_defaults_file(const char *file_location, const char *option, if (*src_ptr != ']') continue; /* Missing closing parenthesis. Assume this was no group */ - in_section= TRUE; - /* add option */ - if (!remove_option) - { - tmp_ptr= strmov(tmp, option); - if (*option_value) - { - *tmp_ptr++= '='; - tmp_ptr= strmov(tmp_ptr, option_value); - } - /* add a newline */ - strmov(tmp_ptr, NEWLINE); - } } else in_section= FALSE; /* mark that this section is of no interest to us */ } } - /* File ended. New option still remains to apply at the end */ - if (tmp_ptr) + /* File ended. */ + if (!opt_applied && !remove_option && in_section) { + /* New option still remains to apply at the end */ if (*(dst_ptr - 1) != '\n') - *dst_ptr++= '\n'; - dst_ptr= strmov(dst_ptr, tmp); + dst_ptr= strmov(dst_ptr, NEWLINE); + dst_ptr= add_option(dst_ptr, option_value, option, remove_option); + opt_applied= 1; } + for (; nr_newlines; nr_newlines--) + dst_ptr= strmov(dst_ptr, NEWLINE); - if (my_chsize(fileno(cnf_file), (my_off_t) (dst_ptr - file_buffer), 0, - MYF(MY_WME)) || - my_fseek(cnf_file, 0, MY_SEEK_SET, MYF(0)) || - my_fwrite(cnf_file, file_buffer, (uint) (dst_ptr - file_buffer), - MYF(MY_NABP)) || - my_fclose(cnf_file, MYF(MY_WME))) - goto err; + if (opt_applied) + { + /* Don't write the file if there are no changes to be made */ + if (my_chsize(fileno(cnf_file), (my_off_t) (dst_ptr - file_buffer), 0, + MYF(MY_WME)) || + my_fseek(cnf_file, 0, MY_SEEK_SET, MYF(0)) || + my_fwrite(cnf_file, file_buffer, (uint) (dst_ptr - file_buffer), + MYF(MY_NABP))) + goto err; + } + if (my_fclose(cnf_file, MYF(MY_WME))) + goto err; my_free(file_buffer, MYF(0)); - DBUG_RETURN(0); err: @@ -162,3 +167,21 @@ malloc_err: my_fclose(cnf_file, MYF(0)); DBUG_RETURN(1); /* out of resources */ } + + +static char *add_option(char *dst, const char *option_value, + const char *option, int remove_option) +{ + if (!remove_option) + { + dst= strmov(dst, option); + if (*option_value) + { + *dst++= '='; + dst= strmov(dst, option_value); + } + /* add a newline */ + dst= strmov(dst, NEWLINE); + } + return dst; +} From 751089491c337c436e398e31e79410f7929f8dd3 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Jun 2005 21:20:34 -0700 Subject: [PATCH 27/27] Update test results. type_varchar changed because the size of the key now gets changed along with the size of the field as long as the original key had the same length as the length of the field (or is unspecified originally, as in the test). mysql-test/r/heap.result: Update results mysql-test/r/type_varchar.result: Update results --- mysql-test/r/heap.result | 2 +- mysql-test/r/type_varchar.result | 54 ++++++++++++++++---------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result index 52bf99d45ea..22304c4a93d 100644 --- a/mysql-test/r/heap.result +++ b/mysql-test/r/heap.result @@ -699,5 +699,5 @@ ERROR 42000: Incorrect table definition; there can be only one auto column and i create table t1 (c char(255), primary key(c(90))); insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); -ERROR 23000: Duplicate entry 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl' for key 1 +ERROR 23000: Duplicate entry 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl' for key 1 drop table t1; diff --git a/mysql-test/r/type_varchar.result b/mysql-test/r/type_varchar.result index fed03cd8d71..e3b12cc36e3 100644 --- a/mysql-test/r/type_varchar.result +++ b/mysql-test/r/type_varchar.result @@ -126,13 +126,13 @@ Some sample data Some samples explain select * from t1 where v like 'This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort +1 SIMPLE t1 range v v 258 NULL 3 Using where; Using index explain select * from t1 where v='This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 257 const 3 Using where +1 SIMPLE t1 ref v v 258 const 3 Using where; Using index explain select * from t1 where v like 'S%' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort +1 SIMPLE t1 range v v 258 NULL 2 Using where; Using index alter table t1 change v v varchar(256); select * from t1 where v like 'This is a test' order by v; v @@ -150,13 +150,13 @@ Some sample data Some samples explain select * from t1 where v like 'This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort +1 SIMPLE t1 range v v 259 NULL 3 Using where; Using index explain select * from t1 where v='This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 257 const 3 Using where +1 SIMPLE t1 ref v v 259 const 3 Using where; Using index explain select * from t1 where v like 'S%' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort +1 SIMPLE t1 range v v 259 NULL 2 Using where; Using index alter table t1 change v v varchar(257); select * from t1 where v like 'This is a test' order by v; v @@ -174,13 +174,13 @@ Some sample data Some samples explain select * from t1 where v like 'This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort +1 SIMPLE t1 range v v 260 NULL 3 Using where; Using index explain select * from t1 where v='This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 257 const 3 Using where +1 SIMPLE t1 ref v v 260 const 3 Using where; Using index explain select * from t1 where v like 'S%' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort +1 SIMPLE t1 range v v 260 NULL 2 Using where; Using index alter table t1 change v v varchar(258); select * from t1 where v like 'This is a test' order by v; v @@ -198,13 +198,13 @@ Some sample data Some samples explain select * from t1 where v like 'This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort +1 SIMPLE t1 range v v 261 NULL 3 Using where; Using index explain select * from t1 where v='This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 257 const 3 Using where +1 SIMPLE t1 ref v v 261 const 3 Using where; Using index explain select * from t1 where v like 'S%' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort +1 SIMPLE t1 range v v 261 NULL 2 Using where; Using index alter table t1 change v v varchar(259); select * from t1 where v like 'This is a test' order by v; v @@ -222,13 +222,13 @@ Some sample data Some samples explain select * from t1 where v like 'This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort +1 SIMPLE t1 range v v 262 NULL 3 Using where; Using index explain select * from t1 where v='This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 257 const 3 Using where +1 SIMPLE t1 ref v v 262 const 3 Using where; Using index explain select * from t1 where v like 'S%' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort +1 SIMPLE t1 range v v 262 NULL 2 Using where; Using index alter table t1 change v v varchar(258); select * from t1 where v like 'This is a test' order by v; v @@ -246,13 +246,13 @@ Some sample data Some samples explain select * from t1 where v like 'This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort +1 SIMPLE t1 range v v 261 NULL 3 Using where; Using index explain select * from t1 where v='This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 257 const 3 Using where +1 SIMPLE t1 ref v v 261 const 3 Using where; Using index explain select * from t1 where v like 'S%' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort +1 SIMPLE t1 range v v 261 NULL 2 Using where; Using index alter table t1 change v v varchar(257); select * from t1 where v like 'This is a test' order by v; v @@ -270,13 +270,13 @@ Some sample data Some samples explain select * from t1 where v like 'This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort +1 SIMPLE t1 range v v 260 NULL 3 Using where; Using index explain select * from t1 where v='This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 257 const 3 Using where +1 SIMPLE t1 ref v v 260 const 3 Using where; Using index explain select * from t1 where v like 'S%' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort +1 SIMPLE t1 range v v 260 NULL 2 Using where; Using index alter table t1 change v v varchar(256); select * from t1 where v like 'This is a test' order by v; v @@ -294,13 +294,13 @@ Some sample data Some samples explain select * from t1 where v like 'This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort +1 SIMPLE t1 range v v 259 NULL 3 Using where; Using index explain select * from t1 where v='This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 257 const 3 Using where +1 SIMPLE t1 ref v v 259 const 3 Using where; Using index explain select * from t1 where v like 'S%' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort +1 SIMPLE t1 range v v 259 NULL 2 Using where; Using index alter table t1 change v v varchar(255); select * from t1 where v like 'This is a test' order by v; v @@ -318,13 +318,13 @@ Some sample data Some samples explain select * from t1 where v like 'This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort +1 SIMPLE t1 range v v 258 NULL 3 Using where; Using index explain select * from t1 where v='This is a test' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 257 const 3 Using where +1 SIMPLE t1 ref v v 258 const 3 Using where; Using index explain select * from t1 where v like 'S%' order by v; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort +1 SIMPLE t1 range v v 258 NULL 2 Using where; Using index alter table t1 change v v varchar(254); select * from t1 where v like 'This is a test' order by v; v