Merge mysql.com:/home/svoj/devel/mysql/BUG21310/mysql-4.1-engines
into mysql.com:/home/svoj/devel/mysql/BUG21310/mysql-5.0-engines
This commit is contained in:
commit
32c7187952
@ -1621,3 +1621,19 @@ 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;
|
||||||
|
@ -1004,4 +1004,23 @@ 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;
|
||||||
|
|
||||||
# End of 4.1 tests
|
# End of 4.1 tests
|
||||||
|
@ -25,8 +25,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)
|
||||||
@ -1041,30 +1039,75 @@ int multi_update::prepare(List<Item> ¬_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];
|
||||||
|
|
||||||
/*
|
|
||||||
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
|
|
||||||
|
|
||||||
UPDATE t1, t1 AS t2 SET t1.b=t2.c WHERE t1.a=t2.a;
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
DBUG_RETURN(thd->is_fatal_error != 0);
|
DBUG_RETURN(thd->is_fatal_error != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if table is safe to update on fly
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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 *all_tables, List<Item> *fields)
|
||||||
|
{
|
||||||
|
TABLE *table= join_tab->table;
|
||||||
|
if (unique_table(thd, table, 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
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initialize table for multi table
|
Initialize table for multi table
|
||||||
|
|
||||||
@ -1099,7 +1142,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, &temp_fields))
|
if (safe_update_on_fly(thd, join->join_tab, 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;
|
||||||
@ -1150,63 +1193,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()
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user