Commit 54c147a1 authored by istruewing@chilla.local's avatar istruewing@chilla.local

Merge bk-internal.mysql.com:/home/bk/mysql-5.1

into  chilla.local:/home/mydev/mysql-5.1-axmrg
parents 60a3f102 de87e317
...@@ -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;
......
...@@ -1603,6 +1603,22 @@ select * from t1; ...@@ -1603,6 +1603,22 @@ select * from t1;
a a
42 42
drop table t1; drop table t1;
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;
End of 4.1 tests End of 4.1 tests
create table t1 (c1 int) engine=myisam pack_keys=0; create table t1 (c1 int) engine=myisam pack_keys=0;
create table t2 (c1 int) engine=myisam pack_keys=1; create table t2 (c1 int) engine=myisam pack_keys=1;
......
...@@ -977,6 +977,24 @@ connection default; ...@@ -977,6 +977,24 @@ connection default;
select * from t1; select * from t1;
drop table t1; drop table t1;
#
# 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;
--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);
/* Return 0 if row hasn't changed */ /* Return 0 if row hasn't changed */
static bool compare_record(TABLE *table) static bool compare_record(TABLE *table)
...@@ -1160,27 +1158,71 @@ int multi_update::prepare(List<Item> &not_used_values, ...@@ -1160,27 +1158,71 @@ 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
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.
This function gets information about fields to be updated from
the TABLE::write_set bitmap.
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)
{
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, table->write_set);
case JT_ALL:
/* If range search on index */
if (join_tab->quick)
return !join_tab->quick->is_keys_used(table->write_set);
/* If scanning in clustered key */
if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
table->s->primary_key < MAX_KEY)
return !is_key_used(table, table->s->primary_key, table->write_set);
return TRUE;
default:
break; // Avoid compler warning
} }
DBUG_RETURN(thd->is_fatal_error != 0); return FALSE;
} }
...@@ -1220,7 +1262,7 @@ multi_update::initialize_tables(JOIN *join) ...@@ -1220,7 +1262,7 @@ 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)) if (safe_update_on_fly(thd, join->join_tab, table_ref, all_tables))
{ {
table_to_update= main_table; // Update table on the fly table_to_update= main_table; // Update table on the fly
continue; continue;
...@@ -1272,61 +1314,6 @@ multi_update::initialize_tables(JOIN *join) ...@@ -1272,61 +1314,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
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.
This function gets information about fields to be updated from
the TABLE::write_set bitmap.
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)
{
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, table->write_set);
case JT_ALL:
/* If range search on index */
if (join_tab->quick)
return !join_tab->quick->is_keys_used(table->write_set);
/* If scanning in clustered key */
if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
table->s->primary_key < MAX_KEY)
return !is_key_used(table, table->s->primary_key, table->write_set);
return TRUE;
default:
break; // Avoid compler warning
}
return FALSE;
}
multi_update::~multi_update() multi_update::~multi_update()
{ {
......
...@@ -785,6 +785,8 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, ...@@ -785,6 +785,8 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
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(&interval_array, &share->fieldnames, 1, &names); fix_type_pointers(&interval_array, &share->fieldnames, 1, &names);
if (share->fieldnames.count != share->fields)
goto err;
fix_type_pointers(&interval_array, share->intervals, interval_count, fix_type_pointers(&interval_array, share->intervals, interval_count,
&names); &names);
......
...@@ -254,7 +254,7 @@ int _mi_write_blob_record(MI_INFO *info, const byte *record) ...@@ -254,7 +254,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),
...@@ -288,7 +288,7 @@ int _mi_update_blob_record(MI_INFO *info, my_off_t pos, const byte *record) ...@@ -288,7 +288,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),
......
...@@ -338,6 +338,15 @@ void mi_update_status(void* param) ...@@ -338,6 +338,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;
......
...@@ -518,6 +518,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) ...@@ -518,6 +518,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;
......
...@@ -180,7 +180,7 @@ int mi_write(MI_INFO *info, byte *record) ...@@ -180,7 +180,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)
{ {
......
...@@ -753,6 +753,7 @@ int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b, ...@@ -753,6 +753,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);
......
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