diff --git a/myisam/mi_search.c b/myisam/mi_search.c index ed61bbfe41a..b7360dba7f3 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -318,19 +318,21 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, get_key_pack_length(kseg_len,length_pack,kseg); key_len_skip=length_pack+kseg_len; key_len_left=(int) key_len- (int) key_len_skip; + /* If key_len is 0, then lenght_pack is 1, then key_len_left is -1. */ cmplen=(key_len_left>=0) ? kseg_len : key_len-length_pack; DBUG_PRINT("info",("key: '%.*s'",kseg_len,kseg)); /* Keys are compressed the following way: - If the max length of first key segment <= 127 characters the prefix is + If the max length of first key segment <= 127 bytes the prefix is 1 byte else it's 2 byte - prefix The high bit is set if this is a prefix for the prev key - length Packed length if the previous was a prefix byte - [length] Length character of data - next-key-seg Next key segments + (prefix) length The high bit is set if this is a prefix for the prev key. + [suffix length] Packed length of suffix if the previous was a prefix. + (suffix) data Key data bytes (past the common prefix or whole segment). + [next-key-seg] Next key segments (([packed length], data), ...) + pointer Reference to the data file (last_keyseg->length). */ matched=0; /* how many char's from prefix were alredy matched */ @@ -351,16 +353,23 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, if (packed) { - if (suffix_len == 0) /* Same key */ + if (suffix_len == 0) + { + /* == 0x80 or 0x8000, same key, prefix length == old key length. */ prefix_len=len; + } else { + /* > 0x80 or 0x8000, this is prefix lgt, packed suffix lgt follows. */ prefix_len=suffix_len; get_key_length(suffix_len,vseg); } } else + { + /* Not packed. No prefix used from last key. */ prefix_len=0; + } len=prefix_len+suffix_len; seg_len_pack=get_pack_length(len); @@ -417,7 +426,12 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, uint left; uchar *k=kseg+prefix_len; - left=(len>cmplen) ? cmplen-prefix_len : suffix_len; + /* + If prefix_len > cmplen then we are in the end-space comparison + phase. Do not try to acces the key any more ==> left= 0. + */ + left= ((len <= cmplen) ? suffix_len : + ((prefix_len < cmplen) ? cmplen - prefix_len : 0)); matched=prefix_len+left; @@ -455,7 +469,7 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, my_flag= -1; else { - /* We have to compare k and vseg as if they where space extended */ + /* We have to compare k and vseg as if they were space extended */ uchar *end= k+ (cmplen - len); for ( ; k < end && *k == ' '; k++) ; if (k == end) @@ -474,7 +488,7 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, if ((nextflag & SEARCH_PREFIX) && key_len_left == 0) goto fix_flag; - /* We have to compare k and vseg as if they where space extended */ + /* We have to compare k and vseg as if they were space extended */ for (end=vseg + (len-cmplen) ; vseg < end && *vseg == (uchar) ' '; vseg++, matched++) ; diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index dd7c5ed4407..6a710a8de10 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -541,3 +541,18 @@ create table t1 ( a timestamp ); alter table t1 add unique ( a(1) ); ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys drop table t1; +create database mysqltest1; +create table t1 (c1 int); +alter table t1 rename mysqltest1.t1; +drop table t1; +ERROR 42S02: Unknown table 't1' +alter table mysqltest1.t1 rename t1; +drop table t1; +create table t1 (c1 int); +use mysqltest1; +drop database mysqltest1; +alter table test.t1 rename t1; +ERROR 3D000: No database selected +alter table test.t1 rename test.t1; +use test; +drop table t1; diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 4b62e63c49b..b9567e3f45f 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1703,6 +1703,22 @@ a_id b_list 3 NULL DROP TABLE t2; DROP TABLE t1; +create temporary table t1 (a int) engine=innodb; +insert into t1 values (4711); +truncate t1; +insert into t1 values (42); +select * from t1; +a +42 +drop table t1; +create table t1 (a int) engine=innodb; +insert into t1 values (4711); +truncate t1; +insert into t1 values (42); +select * from t1; +a +42 +drop table t1; create table t1 (x bigint unsigned not null primary key) engine=innodb; insert into t1(x) values (0xfffffffffffffff0),(0xfffffffffffffff1); select * from t1; @@ -1749,7 +1765,7 @@ Variable_name Value Innodb_rows_deleted 2070 show status like "Innodb_rows_inserted"; Variable_name Value -Innodb_rows_inserted 31718 +Innodb_rows_inserted 31722 show status like "Innodb_rows_updated"; Variable_name Value Innodb_rows_updated 29530 diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result index bce02a1cb0f..bc9d3935bc4 100644 --- a/mysql-test/r/key.result +++ b/mysql-test/r/key.result @@ -329,6 +329,23 @@ 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 ( +c1 int, +c2 varchar(20) not null, +primary key (c1), +key (c2(10)) +) engine=myisam; +insert into t1 values (1,''); +insert into t1 values (2,' \t\tTest String'); +insert into t1 values (3,' \n\tTest String'); +update t1 set c2 = 'New Test String' where c1 = 1; +select * from t1; +c1 c2 +1 New Test String +2 Test String +3 + Test String +drop table t1; create table t1 (a varchar(10), b varchar(10), key(a(10),b(10))); show create table t1; Table Create Table diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 71cb76fe844..ce215d6a7d8 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -594,6 +594,20 @@ check table t1; Table Op Msg_type Msg_text test.t1 check status OK drop table t1; +create table t1 (c1 int); +insert into t1 values (1),(2),(3),(4); +checksum table t1; +Table Checksum +test.t1 149057747 +delete from t1 where c1 = 1; +create table t2 as select * from t1; +checksum table t1; +Table Checksum +test.t1 984116287 +checksum table t2; +Table Checksum +test.t2 984116287 +drop table t1, t2; set storage_engine=MyISAM; drop table if exists t1,t2,t3; --- Testing varchar --- @@ -1274,3 +1288,9 @@ show keys from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 a 1 a A 8 NULL NULL YES BTREE drop table t1; +create table t1 (c1 int) engine=myisam pack_keys=0; +create table t2 (c1 int) engine=myisam pack_keys=1; +create table t3 (c1 int) engine=myisam pack_keys=default; +create table t4 (c1 int) engine=myisam pack_keys=2; +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 '2' at line 1 +drop table t1, t2, t3; diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 003662fc956..5695822be6b 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -369,4 +369,35 @@ create table t1 ( a timestamp ); alter table t1 add unique ( a(1) ); drop table t1; +# +# Bug#11493 - Alter table rename to default database does not work without +# db name qualifying +# +create database mysqltest1; +create table t1 (c1 int); +# Move table to other database. +alter table t1 rename mysqltest1.t1; +# Assure that it has moved. +--error 1051 +drop table t1; +# Move table back. +alter table mysqltest1.t1 rename t1; +# Assure that it is back. +drop table t1; +# Now test for correct message if no database is selected. +# Create t1 in 'test'. +create table t1 (c1 int); +# Change to other db. +use mysqltest1; +# Drop the current db. This de-selects any db. +drop database mysqltest1; +# Now test for correct message. +--error 1046 +alter table test.t1 rename t1; +# Check that explicit qualifying works even with no selected db. +alter table test.t1 rename test.t1; +# Go back to standard 'test' db. +use test; +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index bf094dd0e5d..b12ddc830ad 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1231,6 +1231,24 @@ SELECT * FROM (SELECT t1.*,GROUP_CONCAT(t2.b_id SEPARATOR ',') as b_list FROM (t DROP TABLE t2; DROP TABLE t1; +# +# Bug#11816 - Truncate table doesn't work with temporary innodb tables +# This is not an innodb bug, but we test it using innodb. +# +create temporary table t1 (a int) engine=innodb; +insert into t1 values (4711); +truncate t1; +insert into t1 values (42); +select * from t1; +drop table t1; +# Show that it works with permanent tables too. +create table t1 (a int) engine=innodb; +insert into t1 values (4711); +truncate t1; +insert into t1 values (42); +select * from t1; +drop table t1; + # End of 4.1 tests # diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test index 91bd1ada8a4..31763b84379 100644 --- a/mysql-test/t/key.test +++ b/mysql-test/t/key.test @@ -325,6 +325,23 @@ alter table t1 add key (c1,c2,c1); alter table t1 add key (c1,c1,c2); drop table t1; +# +# Bug#12565 - ERROR 1034 when running simple UPDATE or DELETE +# on large MyISAM table +# +create table t1 ( + c1 int, + c2 varchar(20) not null, + primary key (c1), + key (c2(10)) +) engine=myisam; +insert into t1 values (1,''); +insert into t1 values (2,' \t\tTest String'); +insert into t1 values (3,' \n\tTest String'); +update t1 set c2 = 'New Test String' where c1 = 1; +select * from t1; +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 diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index dfb00d5686c..eeac2971788 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -563,6 +563,21 @@ update t1 set c2='A B' where c1=2; check table t1; drop table t1; + +# +# Bug#12296 - CHECKSUM TABLE reports 0 for the table +# This happened if the first record was marked as deleted. +# +create table t1 (c1 int); +insert into t1 values (1),(2),(3),(4); +checksum table t1; +delete from t1 where c1 = 1; +create table t2 as select * from t1; +# The following returns 0 with the bug in place. +checksum table t1; +# The above should give the same number as the following. +checksum table t2; +drop table t1, t2; # # Test varchar # @@ -675,4 +690,14 @@ show keys from t1; drop table t1; +# +# Bug#10056 - PACK_KEYS option take values greater than 1 while creating table +# +create table t1 (c1 int) engine=myisam pack_keys=0; +create table t2 (c1 int) engine=myisam pack_keys=1; +create table t3 (c1 int) engine=myisam pack_keys=default; +--error 1064 +create table t4 (c1 int) engine=myisam pack_keys=2; +drop table t1, t2, t3; + # End of 4.1 tests diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 4ec5b43f8e7..3f18b391bda 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -768,6 +768,8 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) TABLE *table= *table_ptr; table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK); db_type table_type= table->s->db_type; + if (!ha_supports_generate(table_type)) + goto trunc_by_del; strmov(path, table->s->path); *table_ptr= table->next; // Unlink table from list close_temporary(table,0); @@ -786,7 +788,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) (void) sprintf(path,"%s/%s/%s%s",mysql_data_home,table_list->db, table_list->table_name,reg_ext); - fn_format(path,path,"","",4); + fn_format(path, path, "", "", MY_UNPACK_FILENAME); if (!dont_send_ok) { @@ -798,19 +800,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) DBUG_RETURN(TRUE); } if (!ha_supports_generate(table_type) || thd->lex->sphead) - { - /* Probably InnoDB table */ - ulong save_options= thd->options; - table_list->lock_type= TL_WRITE; - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT); - ha_enable_transaction(thd, FALSE); - mysql_init_select(thd->lex); - error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0, - HA_POS_ERROR, LL(0)); - ha_enable_transaction(thd, TRUE); - thd->options= save_options; - DBUG_RETURN(error); - } + goto trunc_by_del; if (lock_and_wait_for_table_name(thd, table_list)) DBUG_RETURN(TRUE); } @@ -844,4 +834,17 @@ end: VOID(pthread_mutex_unlock(&LOCK_open)); } DBUG_RETURN(error); + + trunc_by_del: + /* Probably InnoDB table */ + ulong save_options= thd->options; + table_list->lock_type= TL_WRITE; + thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT); + ha_enable_transaction(thd, FALSE); + mysql_init_select(thd->lex); + error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0, + HA_POS_ERROR, LL(0)); + ha_enable_transaction(thd, TRUE); + thd->options= save_options; + DBUG_RETURN(error); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c023c525079..d6f7a4b1350 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2991,7 +2991,24 @@ end_with_restore_list: goto error; } if (!select_lex->db) - select_lex->db= first_table->db; + { + /* + In the case of ALTER TABLE ... RENAME we should supply the + default database if the new name is not explicitly qualified + by a database. (Bug #11493) + */ + if (lex->alter_info.flags & ALTER_RENAME) + { + if (! thd->db) + { + my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); + goto error; + } + select_lex->db= thd->db; + } + else + select_lex->db= first_table->db; + } if (check_access(thd, ALTER_ACL, first_table->db, &first_table->grant.privilege, 0, 0) || check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0)|| diff --git a/sql/sql_table.cc b/sql/sql_table.cc index d7609bc2f58..1bb6e66a12e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4091,9 +4091,16 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt) protocol->store_null(); else { - while (!t->file->rnd_next(t->record[0])) + for (;;) { ha_checksum row_crc= 0; + int error= t->file->rnd_next(t->record[0]); + if (unlikely(error)) + { + if (error == HA_ERR_RECORD_DELETED) + continue; + break; + } if (t->record[0] != (byte*) t->field[0]->ptr) row_crc= my_checksum(row_crc, t->record[0], ((byte*) t->field[0]->ptr) - t->record[0]); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 898c794d4b4..90066318c60 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2669,8 +2669,27 @@ create_table_option: | PASSWORD opt_equal TEXT_STRING_sys { Lex->create_info.password=$3.str; Lex->create_info.used_fields|= HA_CREATE_USED_PASSWORD; } | COMMENT_SYM opt_equal TEXT_STRING_sys { Lex->create_info.comment=$3.str; Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT; } | AUTO_INC opt_equal ulonglong_num { Lex->create_info.auto_increment_value=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AUTO;} - | PACK_KEYS_SYM opt_equal ulong_num { Lex->create_info.table_options|= $3 ? HA_OPTION_PACK_KEYS : HA_OPTION_NO_PACK_KEYS; Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;} - | PACK_KEYS_SYM opt_equal DEFAULT { Lex->create_info.table_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS); Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;} + | PACK_KEYS_SYM opt_equal ulong_num + { + switch($3) { + case 0: + Lex->create_info.table_options|= HA_OPTION_NO_PACK_KEYS; + break; + case 1: + Lex->create_info.table_options|= HA_OPTION_PACK_KEYS; + break; + default: + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; + } + Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS; + } + | PACK_KEYS_SYM opt_equal DEFAULT + { + Lex->create_info.table_options&= + ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS); + Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS; + } | CHECKSUM_SYM opt_equal ulong_num { Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; Lex->create_info.used_fields|= HA_CREATE_USED_CHECKSUM; } | DELAY_KEY_WRITE_SYM opt_equal ulong_num { Lex->create_info.table_options|= $3 ? HA_OPTION_DELAY_KEY_WRITE : HA_OPTION_NO_DELAY_KEY_WRITE; Lex->create_info.used_fields|= HA_CREATE_USED_DELAY_KEY_WRITE; } | ROW_FORMAT_SYM opt_equal row_types { Lex->create_info.row_type= $3; Lex->create_info.used_fields|= HA_CREATE_USED_ROW_FORMAT; }