diff options
author | unknown <svoj@mysql.com/april.(none)> | 2007-01-25 01:31:58 +0400 |
---|---|---|
committer | unknown <svoj@mysql.com/april.(none)> | 2007-01-25 01:31:58 +0400 |
commit | 2ed7eaf56424485e475ef7f1c430b1881ac02fc2 (patch) | |
tree | e663234920329e2a4394bd6e1c9d92ec82b53f0b | |
parent | bb5dccf26065e07488a68dc636b8e79c059981a7 (diff) | |
parent | c26ffedb86bbc1fa0d4d91e712da5e71454564a9 (diff) | |
download | mariadb-git-2ed7eaf56424485e475ef7f1c430b1881ac02fc2.tar.gz |
Merge mysql.com:/home/svoj/devel/bk/mysql-5.0
into mysql.com:/home/svoj/devel/mysql/merge/mysql-5.0-engines
mysql-test/t/myisam.test:
Auto merged
-rw-r--r-- | include/thr_lock.h | 1 | ||||
-rw-r--r-- | myisam/mi_create.c | 13 | ||||
-rw-r--r-- | myisam/mi_dynrec.c | 4 | ||||
-rw-r--r-- | myisam/mi_locking.c | 9 | ||||
-rw-r--r-- | myisam/mi_open.c | 16 | ||||
-rw-r--r-- | myisam/mi_update.c | 3 | ||||
-rw-r--r-- | myisam/mi_write.c | 2 | ||||
-rw-r--r-- | myisam/myisamdef.h | 1 | ||||
-rw-r--r-- | mysql-test/r/myisam.result | 21 | ||||
-rw-r--r-- | mysql-test/t/myisam.test | 27 | ||||
-rw-r--r-- | mysys/thr_lock.c | 12 | ||||
-rw-r--r-- | sql/sql_update.cc | 140 | ||||
-rw-r--r-- | sql/table.cc | 2 |
13 files changed, 162 insertions, 89 deletions
diff --git a/include/thr_lock.h b/include/thr_lock.h index 9177438bd0f..966522fe3e3 100644 --- a/include/thr_lock.h +++ b/include/thr_lock.h @@ -121,6 +121,7 @@ typedef struct st_thr_lock { void (*get_status)(void*, int); /* When one gets a lock */ void (*copy_status)(void*,void*); void (*update_status)(void*); /* Before release of write */ + void (*restore_status)(void*); /* Before release of read */ my_bool (*check_status)(void *); } THR_LOCK; diff --git a/myisam/mi_create.c b/myisam/mi_create.c index d99c74f6136..d46672444e0 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -815,18 +815,19 @@ uint mi_get_pointer_length(ulonglong file_length, uint def) if (file_length) /* If not default */ { #ifdef NOT_YET_READY_FOR_8_BYTE_POINTERS - if (file_length >= (longlong) 1 << 56) + if (file_length >= ULL(1) << 56) def=8; + else #endif - if (file_length >= (longlong) 1 << 48) + if (file_length >= ULL(1) << 48) def=7; - if (file_length >= (longlong) 1 << 40) + else if (file_length >= ULL(1) << 40) def=6; - else if (file_length >= (longlong) 1 << 32) + else if (file_length >= ULL(1) << 32) def=5; - else if (file_length >= (1L << 24)) + else if (file_length >= ULL(1) << 24) def=4; - else if (file_length >= (1L << 16)) + else if (file_length >= ULL(1) << 16) def=3; else def=2; diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c index 114bdadf4ef..11f51f08d23 100644 --- a/myisam/mi_dynrec.c +++ b/myisam/mi_dynrec.c @@ -80,7 +80,7 @@ int _mi_write_blob_record(MI_INFO *info, const byte *record) #endif if (!(rec_buff=(byte*) my_alloca(reclength))) { - my_errno=ENOMEM; + my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */ return(-1); } reclength2= _mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER), @@ -114,7 +114,7 @@ int _mi_update_blob_record(MI_INFO *info, my_off_t pos, const byte *record) #endif if (!(rec_buff=(byte*) my_alloca(reclength))) { - my_errno=ENOMEM; + my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */ return(-1); } reclength=_mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER), diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c index 96b9f525cd0..42c21b915a5 100644 --- a/myisam/mi_locking.c +++ b/myisam/mi_locking.c @@ -325,6 +325,15 @@ void mi_update_status(void* param) } } + +void mi_restore_status(void *param) +{ + MI_INFO *info= (MI_INFO*) param; + info->state= &info->s->state.state; + info->append_insert_at_end= 0; +} + + void mi_copy_status(void* to,void *from) { ((MI_INFO*) to)->state= &((MI_INFO*) from)->save_state; diff --git a/myisam/mi_open.c b/myisam/mi_open.c index 20a50fff9d7..7d66f27cae5 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -322,7 +322,13 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++) { disk_pos=mi_keyseg_read(disk_pos, pos); - + if (pos->flag & HA_BLOB_PART && + ! (share->options & (HA_OPTION_COMPRESS_RECORD | + HA_OPTION_PACK_RECORD))) + { + my_errno= HA_ERR_CRASHED; + goto err; + } if (pos->type == HA_KEYTYPE_TEXT || pos->type == HA_KEYTYPE_VARTEXT1 || pos->type == HA_KEYTYPE_VARTEXT2) @@ -440,6 +446,13 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) offset+=share->rec[i].length; } share->rec[i].type=(int) FIELD_LAST; /* End marker */ + if (offset > share->base.reclength) + { + /* purecov: begin inspected */ + my_errno= HA_ERR_CRASHED; + goto err; + /* purecov: end */ + } if (! lock_error) { @@ -504,6 +517,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) share->lock.get_status=mi_get_status; share->lock.copy_status=mi_copy_status; share->lock.update_status=mi_update_status; + share->lock.restore_status= mi_restore_status; share->lock.check_status=mi_check_status; } } diff --git a/myisam/mi_update.c b/myisam/mi_update.c index b35c27d75ad..bea457d2e9a 100644 --- a/myisam/mi_update.c +++ b/myisam/mi_update.c @@ -196,7 +196,8 @@ err: save_errno=my_errno; if (changed) key_changed|= HA_STATE_CHANGED; - if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL) + if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_OUT_OF_MEM || + my_errno == HA_ERR_RECORD_FILE_FULL) { info->errkey= (int) i; flag=0; diff --git a/myisam/mi_write.c b/myisam/mi_write.c index a93ee42e2c0..cc17d4c6165 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -168,7 +168,7 @@ int mi_write(MI_INFO *info, byte *record) err: save_errno=my_errno; if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL || - my_errno == HA_ERR_NULL_IN_SPATIAL) + my_errno == HA_ERR_NULL_IN_SPATIAL || my_errno == HA_ERR_OUT_OF_MEM) { if (info->bulk_insert) { diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index 3df55fc4780..0733073a7ea 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -731,6 +731,7 @@ int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b, my_bool null_are_equal); void mi_get_status(void* param, int concurrent_insert); void mi_update_status(void* param); +void mi_restore_status(void* param); void mi_copy_status(void* to,void *from); my_bool mi_check_status(void* param); void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows); diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 3ed2d10c9c9..0f6e0ad537a 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -922,6 +922,27 @@ SET @@myisam_repair_threads=1; SHOW VARIABLES LIKE 'myisam_repair%'; Variable_name Value myisam_repair_threads 1 +CREATE TABLE t1(a VARCHAR(16)); +INSERT INTO t1 VALUES('aaaaaaaa'),(NULL); +UPDATE t1 AS ta1, t1 AS ta2 SET ta1.a='aaaaaaaaaaaaaaaa'; +SELECT * FROM t1; +a +aaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaa +DROP TABLE t1; +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES(1),(2); +UPDATE t1,t1 AS t2 SET t1.a=t1.a+2 WHERE t1.a=t2.a-1; +SELECT * FROM t1 ORDER BY a; +a +2 +3 +DROP TABLE t1; +CREATE TABLE t1 (c1 TEXT) AVG_ROW_LENGTH=70100 MAX_ROWS=4100100100; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Dynamic X X X 72057594037927935 X X X X X X latin1_swedish_ci X max_rows=4100100100 avg_row_length=70100 +DROP TABLE t1; End of 4.1 tests set storage_engine=MyISAM; drop table if exists t1,t2,t3; diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 3dcb24af1eb..59e3206d1c3 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -847,6 +847,33 @@ DROP TABLE t1; SET @@myisam_repair_threads=1; SHOW VARIABLES LIKE 'myisam_repair%'; +# +# BUG#21310 - Trees in SQL causing a "crashed" table with MyISAM storage +# engine +# + +# A simplified test case that reflect crashed table issue. +CREATE TABLE t1(a VARCHAR(16)); +INSERT INTO t1 VALUES('aaaaaaaa'),(NULL); +UPDATE t1 AS ta1, t1 AS ta2 SET ta1.a='aaaaaaaaaaaaaaaa'; +SELECT * FROM t1; +DROP TABLE t1; + +# A test case that reflect wrong result set. +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES(1),(2); +UPDATE t1,t1 AS t2 SET t1.a=t1.a+2 WHERE t1.a=t2.a-1; +SELECT * FROM t1 ORDER BY a; +DROP TABLE t1; + +# +# Bug#24607 - MyISAM pointer size determined incorrectly +# +CREATE TABLE t1 (c1 TEXT) AVG_ROW_LENGTH=70100 MAX_ROWS=4100100100; +--replace_column 5 X 6 X 7 X 9 X 10 X 11 X 12 X 13 X 14 X 16 X +SHOW TABLE STATUS LIKE 't1'; +DROP TABLE t1; + --echo End of 4.1 tests diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 27203c2d23c..3d29379a9fc 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -757,8 +757,16 @@ void thr_unlock(THR_LOCK_DATA *data) } else lock->write.last=data->prev; - if (lock_type >= TL_WRITE_CONCURRENT_INSERT && lock->update_status) - (*lock->update_status)(data->status_param); + if (lock_type >= TL_WRITE_CONCURRENT_INSERT) + { + if (lock->update_status) + (*lock->update_status)(data->status_param); + } + else + { + if (lock->restore_status) + (*lock->restore_status)(data->status_param); + } if (lock_type == TL_READ_NO_INSERT) lock->read_no_write_count--; data->type=TL_UNLOCK; /* Mark unlocked */ diff --git a/sql/sql_update.cc b/sql/sql_update.cc index abffd704188..4043fe17a46 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -24,8 +24,6 @@ #include "sp_head.h" #include "sql_trigger.h" -static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields); - /* Return 0 if row hasn't changed */ static bool compare_record(TABLE *table, query_id_t query_id) @@ -1040,27 +1038,73 @@ int multi_update::prepare(List<Item> ¬_used_values, for (i=0 ; i < table_count ; i++) set_if_bigger(max_fields, fields_for_table[i]->elements); copy_field= new Copy_field[max_fields]; + DBUG_RETURN(thd->is_fatal_error != 0); +} - /* - Mark all copies of tables that are updates to ensure that - init_read_record() will not try to enable a cache on them - The problem is that for queries like +/* + Check if table is safe to update on fly - UPDATE t1, t1 AS t2 SET t1.b=t2.c WHERE t1.a=t2.a; + SYNOPSIS + safe_update_on_fly() + thd Thread handler + join_tab How table is used in join + all_tables List of tables + fields Fields that are updated - the row buffer may contain things that doesn't match what is on disk - which will cause an error when reading a row. - (This issue is mostly relevent for MyISAM tables) - */ - for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf) - { - TABLE *table=table_ref->table; - if ((tables_to_update & table->map) && - unique_table(thd, table_ref, update_tables)) - table->no_cache= 1; // Disable row cache + NOTES + We can update the first table in join on the fly if we know that + a row in this table will never be read twice. This is true under + the following conditions: + + - We are doing a table scan and the data is in a separate file (MyISAM) or + if we don't update a clustered key. + + - We are doing a range scan and we don't update the scan key or + the primary key for a clustered table handler. + + - Table is not joined to itself. + + When checking for above cases we also should take into account that + BEFORE UPDATE trigger potentially may change value of any field in row + being updated. + + WARNING + This code is a bit dependent of how make_join_readinfo() works. + + RETURN + 0 Not safe to update + 1 Safe to update +*/ + +static bool safe_update_on_fly(THD *thd, JOIN_TAB *join_tab, + TABLE_LIST *table_ref, TABLE_LIST *all_tables, + List<Item> *fields) +{ + TABLE *table= join_tab->table; + if (unique_table(thd, table_ref, all_tables)) + return 0; + switch (join_tab->type) { + case JT_SYSTEM: + case JT_CONST: + case JT_EQ_REF: + return TRUE; // At most one matching row + case JT_REF: + case JT_REF_OR_NULL: + return !is_key_used(table, join_tab->ref.key, *fields); + case JT_ALL: + /* If range search on index */ + if (join_tab->quick) + return !join_tab->quick->is_keys_used(fields); + /* If scanning in clustered key */ + if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && + table->s->primary_key < MAX_KEY) + return !is_key_used(table, table->s->primary_key, *fields); + return TRUE; + default: + break; // Avoid compler warning } - DBUG_RETURN(thd->is_fatal_error != 0); + return FALSE; } @@ -1098,7 +1142,8 @@ multi_update::initialize_tables(JOIN *join) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); if (table == main_table) // First table in join { - if (safe_update_on_fly(join->join_tab, &temp_fields)) + if (safe_update_on_fly(thd, join->join_tab, table_ref, all_tables, + &temp_fields)) { table_to_update= main_table; // Update table on the fly continue; @@ -1149,63 +1194,6 @@ multi_update::initialize_tables(JOIN *join) DBUG_RETURN(0); } -/* - Check if table is safe to update on fly - - SYNOPSIS - safe_update_on_fly - join_tab How table is used in join - fields Fields that are updated - - NOTES - We can update the first table in join on the fly if we know that - a row in this table will never be read twice. This is true under - the following conditions: - - - We are doing a table scan and the data is in a separate file (MyISAM) or - if we don't update a clustered key. - - - We are doing a range scan and we don't update the scan key or - the primary key for a clustered table handler. - - When checking for above cases we also should take into account that - BEFORE UPDATE trigger potentially may change value of any field in row - being updated. - - WARNING - This code is a bit dependent of how make_join_readinfo() works. - - RETURN - 0 Not safe to update - 1 Safe to update -*/ - -static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields) -{ - TABLE *table= join_tab->table; - switch (join_tab->type) { - case JT_SYSTEM: - case JT_CONST: - case JT_EQ_REF: - return TRUE; // At most one matching row - case JT_REF: - case JT_REF_OR_NULL: - return !is_key_used(table, join_tab->ref.key, *fields); - case JT_ALL: - /* If range search on index */ - if (join_tab->quick) - return !join_tab->quick->is_keys_used(fields); - /* If scanning in clustered key */ - if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && - table->s->primary_key < MAX_KEY) - return !is_key_used(table, table->s->primary_key, *fields); - return TRUE; - default: - break; // Avoid compler warning - } - return FALSE; -} - multi_update::~multi_update() { diff --git a/sql/table.cc b/sql/table.cc index 2a492a15722..5c72ac6ccbf 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -452,6 +452,8 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, memcpy(comment_pos, disk_buff+read_length-com_length, com_length); fix_type_pointers(&int_array, &share->fieldnames, 1, &names); + if (share->fieldnames.count != share->fields) + goto err; fix_type_pointers(&int_array, share->intervals, interval_count, &names); |