summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <svoj@mysql.com/april.(none)>2007-01-25 01:31:58 +0400
committerunknown <svoj@mysql.com/april.(none)>2007-01-25 01:31:58 +0400
commit2ed7eaf56424485e475ef7f1c430b1881ac02fc2 (patch)
treee663234920329e2a4394bd6e1c9d92ec82b53f0b
parentbb5dccf26065e07488a68dc636b8e79c059981a7 (diff)
parentc26ffedb86bbc1fa0d4d91e712da5e71454564a9 (diff)
downloadmariadb-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.h1
-rw-r--r--myisam/mi_create.c13
-rw-r--r--myisam/mi_dynrec.c4
-rw-r--r--myisam/mi_locking.c9
-rw-r--r--myisam/mi_open.c16
-rw-r--r--myisam/mi_update.c3
-rw-r--r--myisam/mi_write.c2
-rw-r--r--myisam/myisamdef.h1
-rw-r--r--mysql-test/r/myisam.result21
-rw-r--r--mysql-test/t/myisam.test27
-rw-r--r--mysys/thr_lock.c12
-rw-r--r--sql/sql_update.cc140
-rw-r--r--sql/table.cc2
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> &not_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);