Commit ea7fe60f authored by svoj@mysql.com/april.(none)'s avatar svoj@mysql.com/april.(none)

Merge mysql.com:/home/svoj/devel/bk/mysql-5.0

into  mysql.com:/home/svoj/devel/mysql/merge/mysql-5.0-engines
parents b0d94e9d 0dc06453
...@@ -121,6 +121,7 @@ typedef struct st_thr_lock { ...@@ -121,6 +121,7 @@ typedef struct st_thr_lock {
void (*get_status)(void*, int); /* When one gets a lock */ void (*get_status)(void*, int); /* When one gets a lock */
void (*copy_status)(void*,void*); void (*copy_status)(void*,void*);
void (*update_status)(void*); /* Before release of write */ void (*update_status)(void*); /* Before release of write */
void (*restore_status)(void*); /* Before release of read */
my_bool (*check_status)(void *); my_bool (*check_status)(void *);
} THR_LOCK; } THR_LOCK;
......
...@@ -815,18 +815,19 @@ uint mi_get_pointer_length(ulonglong file_length, uint def) ...@@ -815,18 +815,19 @@ uint mi_get_pointer_length(ulonglong file_length, uint def)
if (file_length) /* If not default */ if (file_length) /* If not default */
{ {
#ifdef NOT_YET_READY_FOR_8_BYTE_POINTERS #ifdef NOT_YET_READY_FOR_8_BYTE_POINTERS
if (file_length >= (longlong) 1 << 56) if (file_length >= ULL(1) << 56)
def=8; def=8;
else
#endif #endif
if (file_length >= (longlong) 1 << 48) if (file_length >= ULL(1) << 48)
def=7; def=7;
if (file_length >= (longlong) 1 << 40) else if (file_length >= ULL(1) << 40)
def=6; def=6;
else if (file_length >= (longlong) 1 << 32) else if (file_length >= ULL(1) << 32)
def=5; def=5;
else if (file_length >= (1L << 24)) else if (file_length >= ULL(1) << 24)
def=4; def=4;
else if (file_length >= (1L << 16)) else if (file_length >= ULL(1) << 16)
def=3; def=3;
else else
def=2; def=2;
......
...@@ -80,7 +80,7 @@ int _mi_write_blob_record(MI_INFO *info, const byte *record) ...@@ -80,7 +80,7 @@ int _mi_write_blob_record(MI_INFO *info, const byte *record)
#endif #endif
if (!(rec_buff=(byte*) my_alloca(reclength))) if (!(rec_buff=(byte*) my_alloca(reclength)))
{ {
my_errno=ENOMEM; my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
return(-1); return(-1);
} }
reclength2= _mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER), 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) ...@@ -114,7 +114,7 @@ int _mi_update_blob_record(MI_INFO *info, my_off_t pos, const byte *record)
#endif #endif
if (!(rec_buff=(byte*) my_alloca(reclength))) if (!(rec_buff=(byte*) my_alloca(reclength)))
{ {
my_errno=ENOMEM; my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
return(-1); return(-1);
} }
reclength=_mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER), reclength=_mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
......
...@@ -325,6 +325,15 @@ void mi_update_status(void* param) ...@@ -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) void mi_copy_status(void* to,void *from)
{ {
((MI_INFO*) to)->state= &((MI_INFO*) from)->save_state; ((MI_INFO*) to)->state= &((MI_INFO*) from)->save_state;
......
...@@ -322,7 +322,13 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) ...@@ -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++) for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++)
{ {
disk_pos=mi_keyseg_read(disk_pos, 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 || if (pos->type == HA_KEYTYPE_TEXT ||
pos->type == HA_KEYTYPE_VARTEXT1 || pos->type == HA_KEYTYPE_VARTEXT1 ||
pos->type == HA_KEYTYPE_VARTEXT2) pos->type == HA_KEYTYPE_VARTEXT2)
...@@ -440,6 +446,13 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) ...@@ -440,6 +446,13 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
offset+=share->rec[i].length; offset+=share->rec[i].length;
} }
share->rec[i].type=(int) FIELD_LAST; /* End marker */ 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) if (! lock_error)
{ {
...@@ -504,6 +517,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) ...@@ -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.get_status=mi_get_status;
share->lock.copy_status=mi_copy_status; share->lock.copy_status=mi_copy_status;
share->lock.update_status=mi_update_status; share->lock.update_status=mi_update_status;
share->lock.restore_status= mi_restore_status;
share->lock.check_status=mi_check_status; share->lock.check_status=mi_check_status;
} }
} }
......
...@@ -196,7 +196,8 @@ err: ...@@ -196,7 +196,8 @@ err:
save_errno=my_errno; save_errno=my_errno;
if (changed) if (changed)
key_changed|= HA_STATE_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; info->errkey= (int) i;
flag=0; flag=0;
......
...@@ -168,7 +168,7 @@ int mi_write(MI_INFO *info, byte *record) ...@@ -168,7 +168,7 @@ int mi_write(MI_INFO *info, byte *record)
err: err:
save_errno=my_errno; save_errno=my_errno;
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_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) if (info->bulk_insert)
{ {
......
...@@ -731,6 +731,7 @@ int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b, ...@@ -731,6 +731,7 @@ int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b,
my_bool null_are_equal); my_bool null_are_equal);
void mi_get_status(void* param, int concurrent_insert); void mi_get_status(void* param, int concurrent_insert);
void mi_update_status(void* param); void mi_update_status(void* param);
void mi_restore_status(void* param);
void mi_copy_status(void* to,void *from); void mi_copy_status(void* to,void *from);
my_bool mi_check_status(void* param); my_bool mi_check_status(void* param);
void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows); void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows);
......
...@@ -922,6 +922,27 @@ SET @@myisam_repair_threads=1; ...@@ -922,6 +922,27 @@ SET @@myisam_repair_threads=1;
SHOW VARIABLES LIKE 'myisam_repair%'; SHOW VARIABLES LIKE 'myisam_repair%';
Variable_name Value Variable_name Value
myisam_repair_threads 1 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 End of 4.1 tests
set storage_engine=MyISAM; set storage_engine=MyISAM;
drop table if exists t1,t2,t3; drop table if exists t1,t2,t3;
......
...@@ -847,6 +847,33 @@ DROP TABLE t1; ...@@ -847,6 +847,33 @@ DROP TABLE t1;
SET @@myisam_repair_threads=1; SET @@myisam_repair_threads=1;
SHOW VARIABLES LIKE 'myisam_repair%'; 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 --echo End of 4.1 tests
......
...@@ -757,8 +757,16 @@ void thr_unlock(THR_LOCK_DATA *data) ...@@ -757,8 +757,16 @@ void thr_unlock(THR_LOCK_DATA *data)
} }
else else
lock->write.last=data->prev; lock->write.last=data->prev;
if (lock_type >= TL_WRITE_CONCURRENT_INSERT && lock->update_status) if (lock_type >= TL_WRITE_CONCURRENT_INSERT)
{
if (lock->update_status)
(*lock->update_status)(data->status_param); (*lock->update_status)(data->status_param);
}
else
{
if (lock->restore_status)
(*lock->restore_status)(data->status_param);
}
if (lock_type == TL_READ_NO_INSERT) if (lock_type == TL_READ_NO_INSERT)
lock->read_no_write_count--; lock->read_no_write_count--;
data->type=TL_UNLOCK; /* Mark unlocked */ data->type=TL_UNLOCK; /* Mark unlocked */
......
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
#include "sp_head.h" #include "sp_head.h"
#include "sql_trigger.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 */ /* Return 0 if row hasn't changed */
static bool compare_record(TABLE *table, query_id_t query_id) static bool compare_record(TABLE *table, query_id_t query_id)
...@@ -1040,27 +1038,73 @@ int multi_update::prepare(List<Item> &not_used_values, ...@@ -1040,27 +1038,73 @@ int multi_update::prepare(List<Item> &not_used_values,
for (i=0 ; i < table_count ; i++) for (i=0 ; i < table_count ; i++)
set_if_bigger(max_fields, fields_for_table[i]->elements); set_if_bigger(max_fields, fields_for_table[i]->elements);
copy_field= new Copy_field[max_fields]; 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 NOTES
which will cause an error when reading a row. We can update the first table in join on the fly if we know that
(This issue is mostly relevent for MyISAM tables) a row in this table will never be read twice. This is true under
*/ the following conditions:
for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf)
{ - We are doing a table scan and the data is in a separate file (MyISAM) or
TABLE *table=table_ref->table; if we don't update a clustered key.
if ((tables_to_update & table->map) &&
unique_table(thd, table_ref, update_tables)) - We are doing a range scan and we don't update the scan key or
table->no_cache= 1; // Disable row cache 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) ...@@ -1098,7 +1142,8 @@ multi_update::initialize_tables(JOIN *join)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
if (table == main_table) // First table in join 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 table_to_update= main_table; // Update table on the fly
continue; continue;
...@@ -1149,63 +1194,6 @@ multi_update::initialize_tables(JOIN *join) ...@@ -1149,63 +1194,6 @@ multi_update::initialize_tables(JOIN *join)
DBUG_RETURN(0); 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() multi_update::~multi_update()
{ {
......
...@@ -452,6 +452,8 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -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); memcpy(comment_pos, disk_buff+read_length-com_length, com_length);
fix_type_pointers(&int_array, &share->fieldnames, 1, &names); 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, fix_type_pointers(&int_array, share->intervals, interval_count,
&names); &names);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment