Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/my/mysql-5.0
This commit is contained in:
commit
e253b7815a
@ -1,4 +1,4 @@
|
||||
drop table if exists t1,t11,t12,t2;
|
||||
drop table if exists t1,t2,t3,t11,t12;
|
||||
CREATE TABLE t1 (a tinyint(3), b tinyint(5));
|
||||
INSERT INTO t1 VALUES (1,1);
|
||||
INSERT LOW_PRIORITY INTO t1 VALUES (1,2);
|
||||
@ -172,3 +172,23 @@ a
|
||||
0
|
||||
2
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (a int not null,b int not null);
|
||||
CREATE TABLE t2 (a int not null, b int not null, primary key (a,b));
|
||||
CREATE TABLE t3 (a int not null, b int not null, primary key (a,b));
|
||||
insert into t1 values (1,1),(2,1),(1,3);
|
||||
insert into t2 values (1,1),(2,2),(3,3);
|
||||
insert into t3 values (1,1),(2,1),(1,3);
|
||||
select * from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b;
|
||||
a b a b a b
|
||||
1 1 1 1 1 1
|
||||
2 1 2 2 2 1
|
||||
1 3 1 1 1 3
|
||||
explain select * from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
|
||||
1 SIMPLE t2 index PRIMARY PRIMARY 8 NULL 3 Using where; Using index
|
||||
1 SIMPLE t3 index PRIMARY PRIMARY 8 NULL 3 Using where; Using index
|
||||
delete t2.*,t3.* from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b;
|
||||
select * from t3;
|
||||
a b
|
||||
drop table t1,t2,t3;
|
||||
|
@ -3,7 +3,7 @@
|
||||
#
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1,t11,t12,t2;
|
||||
drop table if exists t1,t2,t3,t11,t12;
|
||||
--enable_warnings
|
||||
CREATE TABLE t1 (a tinyint(3), b tinyint(5));
|
||||
INSERT INTO t1 VALUES (1,1);
|
||||
@ -152,3 +152,20 @@ INSERT INTO t1 VALUES (0),(1),(2);
|
||||
DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a LIMIT 1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# Test of multi-delete where we are not scanning the first table
|
||||
#
|
||||
|
||||
CREATE TABLE t1 (a int not null,b int not null);
|
||||
CREATE TABLE t2 (a int not null, b int not null, primary key (a,b));
|
||||
CREATE TABLE t3 (a int not null, b int not null, primary key (a,b));
|
||||
insert into t1 values (1,1),(2,1),(1,3);
|
||||
insert into t2 values (1,1),(2,2),(3,3);
|
||||
insert into t3 values (1,1),(2,1),(1,3);
|
||||
select * from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b;
|
||||
explain select * from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b;
|
||||
delete t2.*,t3.* from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b;
|
||||
# This should be empty
|
||||
select * from t3;
|
||||
drop table t1,t2,t3;
|
||||
|
@ -773,9 +773,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
|
||||
Comp_creator *func)
|
||||
{
|
||||
Item_subselect::trans_res result= RES_ERROR;
|
||||
DBUG_ENTER("Item_in_subselect::single_value_transformer");
|
||||
|
||||
SELECT_LEX *select_lex= join->select_lex;
|
||||
DBUG_ENTER("Item_in_subselect::single_value_transformer");
|
||||
|
||||
/*
|
||||
Check that the right part of the subselect contains no more than one
|
||||
|
@ -7957,7 +7957,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat()
|
||||
max_used_key_length= real_prefix_len;
|
||||
if (min_max_ranges.elements > 0)
|
||||
{
|
||||
QUICK_RANGE *cur_range= 0;
|
||||
QUICK_RANGE *cur_range;
|
||||
if (have_min)
|
||||
{ /* Check if the right-most range has a lower boundary. */
|
||||
get_dynamic(&min_max_ranges, (gptr)&cur_range,
|
||||
@ -7965,7 +7965,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat()
|
||||
if (!(cur_range->flag & NO_MIN_RANGE))
|
||||
{
|
||||
max_used_key_length+= min_max_arg_len;
|
||||
++used_key_parts;
|
||||
used_key_parts++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -7975,7 +7975,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat()
|
||||
if (!(cur_range->flag & NO_MAX_RANGE))
|
||||
{
|
||||
max_used_key_length+= min_max_arg_len;
|
||||
++used_key_parts;
|
||||
used_key_parts++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -7992,7 +7992,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat()
|
||||
usable key length.
|
||||
*/
|
||||
max_used_key_length+= min_max_arg_len;
|
||||
++used_key_parts;
|
||||
used_key_parts++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1854,7 +1854,8 @@ class multi_delete :public select_result_interceptor
|
||||
ha_rows deleted, found;
|
||||
uint num_of_tables;
|
||||
int error;
|
||||
bool do_delete, transactional_tables, normal_tables;
|
||||
bool do_delete, transactional_tables, normal_tables, delete_while_scanning;
|
||||
|
||||
public:
|
||||
multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables);
|
||||
~multi_delete();
|
||||
@ -1862,7 +1863,7 @@ public:
|
||||
bool send_data(List<Item> &items);
|
||||
bool initialize_tables (JOIN *join);
|
||||
void send_error(uint errcode,const char *err);
|
||||
int do_deletes (bool from_send_error);
|
||||
int do_deletes();
|
||||
bool send_eof();
|
||||
};
|
||||
|
||||
|
@ -410,7 +410,7 @@ multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
|
||||
num_of_tables(num_of_tables_arg), error(0),
|
||||
do_delete(0), transactional_tables(0), normal_tables(0)
|
||||
{
|
||||
tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables-1));
|
||||
tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables);
|
||||
}
|
||||
|
||||
|
||||
@ -440,6 +440,7 @@ multi_delete::initialize_tables(JOIN *join)
|
||||
tables_to_delete_from|= walk->table->map;
|
||||
|
||||
walk= delete_tables;
|
||||
delete_while_scanning= 1;
|
||||
for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
|
||||
tab < end;
|
||||
tab++)
|
||||
@ -459,10 +460,25 @@ multi_delete::initialize_tables(JOIN *join)
|
||||
else
|
||||
normal_tables= 1;
|
||||
}
|
||||
else if ((tab->type != JT_SYSTEM && tab->type != JT_CONST) &&
|
||||
walk == delete_tables)
|
||||
{
|
||||
/*
|
||||
We are not deleting from the table we are scanning. In this
|
||||
case send_data() shouldn't delete any rows a we may touch
|
||||
the rows in the deleted table many times
|
||||
*/
|
||||
delete_while_scanning= 0;
|
||||
}
|
||||
}
|
||||
walk= delete_tables;
|
||||
tempfiles_ptr= tempfiles;
|
||||
for (walk= walk->next_local ;walk ;walk= walk->next_local)
|
||||
if (delete_while_scanning)
|
||||
{
|
||||
table_being_deleted= delete_tables;
|
||||
walk= walk->next_local;
|
||||
}
|
||||
for (;walk ;walk= walk->next_local)
|
||||
{
|
||||
TABLE *table=walk->table;
|
||||
*tempfiles_ptr++= new Unique (refpos_order_cmp,
|
||||
@ -481,12 +497,12 @@ multi_delete::~multi_delete()
|
||||
table_being_deleted;
|
||||
table_being_deleted= table_being_deleted->next_local)
|
||||
{
|
||||
TABLE *t=table_being_deleted->table;
|
||||
free_io_cache(t); // Alloced by unique
|
||||
t->no_keyread=0;
|
||||
TABLE *table= table_being_deleted->table;
|
||||
free_io_cache(table); // Alloced by unique
|
||||
table->no_keyread=0;
|
||||
}
|
||||
|
||||
for (uint counter= 0; counter < num_of_tables-1; counter++)
|
||||
for (uint counter= 0; counter < num_of_tables; counter++)
|
||||
{
|
||||
if (tempfiles[counter])
|
||||
delete tempfiles[counter];
|
||||
@ -496,14 +512,15 @@ multi_delete::~multi_delete()
|
||||
|
||||
bool multi_delete::send_data(List<Item> &values)
|
||||
{
|
||||
int secure_counter= -1;
|
||||
int secure_counter= delete_while_scanning ? -1 : 0;
|
||||
TABLE_LIST *del_table;
|
||||
DBUG_ENTER("multi_delete::send_data");
|
||||
|
||||
for (table_being_deleted= delete_tables;
|
||||
table_being_deleted;
|
||||
table_being_deleted= table_being_deleted->next_local, secure_counter++)
|
||||
for (del_table= delete_tables;
|
||||
del_table;
|
||||
del_table= del_table->next_local, secure_counter++)
|
||||
{
|
||||
TABLE *table=table_being_deleted->table;
|
||||
TABLE *table= del_table->table;
|
||||
|
||||
/* Check if we are using outer join and we didn't find the row */
|
||||
if (table->status & (STATUS_NULL_ROW | STATUS_DELETED))
|
||||
@ -514,7 +531,8 @@ bool multi_delete::send_data(List<Item> &values)
|
||||
|
||||
if (secure_counter < 0)
|
||||
{
|
||||
/* If this is the table we are scanning */
|
||||
/* We are scanning the current table */
|
||||
DBUG_ASSERT(del_table == table_being_deleted);
|
||||
if (table->triggers &&
|
||||
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
|
||||
TRG_ACTION_BEFORE, FALSE))
|
||||
@ -528,8 +546,7 @@ bool multi_delete::send_data(List<Item> &values)
|
||||
TRG_ACTION_AFTER, FALSE))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
else if (!table_being_deleted->next_local ||
|
||||
table_being_deleted->table->file->has_transactions())
|
||||
else
|
||||
{
|
||||
table->file->print_error(error,MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
@ -540,7 +557,7 @@ bool multi_delete::send_data(List<Item> &values)
|
||||
error=tempfiles[secure_counter]->unique_add((char*) table->file->ref);
|
||||
if (error)
|
||||
{
|
||||
error=-1;
|
||||
error= 1; // Fatal error
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
@ -563,22 +580,24 @@ void multi_delete::send_error(uint errcode,const char *err)
|
||||
/* Something already deleted so we have to invalidate cache */
|
||||
query_cache_invalidate3(thd, delete_tables, 1);
|
||||
|
||||
/* Below can happen when thread is killed early ... */
|
||||
if (!table_being_deleted)
|
||||
table_being_deleted=delete_tables;
|
||||
|
||||
/*
|
||||
If rows from the first table only has been deleted and it is
|
||||
transactional, just do rollback.
|
||||
The same if all tables are transactional, regardless of where we are.
|
||||
In all other cases do attempt deletes ...
|
||||
*/
|
||||
if ((table_being_deleted->table->file->has_transactions() &&
|
||||
table_being_deleted == delete_tables) || !normal_tables)
|
||||
if ((table_being_deleted == delete_tables &&
|
||||
table_being_deleted->table->file->has_transactions()) ||
|
||||
!normal_tables)
|
||||
ha_rollback_stmt(thd);
|
||||
else if (do_delete)
|
||||
{
|
||||
VOID(do_deletes(1));
|
||||
/*
|
||||
We have to execute the recorded do_deletes() and write info into the
|
||||
error log
|
||||
*/
|
||||
error= 1;
|
||||
send_eof();
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@ -591,27 +610,20 @@ void multi_delete::send_error(uint errcode,const char *err)
|
||||
1 error
|
||||
*/
|
||||
|
||||
int multi_delete::do_deletes(bool from_send_error)
|
||||
int multi_delete::do_deletes()
|
||||
{
|
||||
int local_error= 0, counter= 0;
|
||||
DBUG_ENTER("do_deletes");
|
||||
DBUG_ASSERT(do_delete);
|
||||
|
||||
if (from_send_error)
|
||||
{
|
||||
/* Found out table number for 'table_being_deleted*/
|
||||
for (TABLE_LIST *aux= delete_tables;
|
||||
aux != table_being_deleted;
|
||||
aux= aux->next_local)
|
||||
counter++;
|
||||
}
|
||||
else
|
||||
table_being_deleted = delete_tables;
|
||||
|
||||
do_delete= 0;
|
||||
do_delete= 0; // Mark called
|
||||
if (!found)
|
||||
DBUG_RETURN(0);
|
||||
for (table_being_deleted= table_being_deleted->next_local;
|
||||
table_being_deleted;
|
||||
|
||||
table_being_deleted= (delete_while_scanning ? delete_tables->next_local :
|
||||
delete_tables);
|
||||
|
||||
for (; table_being_deleted;
|
||||
table_being_deleted= table_being_deleted->next_local, counter++)
|
||||
{
|
||||
TABLE *table = table_being_deleted->table;
|
||||
@ -673,7 +685,7 @@ bool multi_delete::send_eof()
|
||||
thd->proc_info="deleting from reference tables";
|
||||
|
||||
/* Does deletes for the last n - 1 tables, returns 0 if ok */
|
||||
int local_error= do_deletes(0); // returns 0 if success
|
||||
int local_error= do_deletes(); // returns 0 if success
|
||||
|
||||
/* reset used flags */
|
||||
thd->proc_info="end";
|
||||
|
Loading…
x
Reference in New Issue
Block a user