Commit f50ea065 authored by unknown's avatar unknown

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

into mysql.com:/home/my/mysql-5.0


sql/item_subselect.cc:
  Auto merged
sql/opt_range.cc:
  Auto merged
sql/sql_delete.cc:
  Auto merged
parents ba02f729 16ba85cb
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)); CREATE TABLE t1 (a tinyint(3), b tinyint(5));
INSERT INTO t1 VALUES (1,1); INSERT INTO t1 VALUES (1,1);
INSERT LOW_PRIORITY INTO t1 VALUES (1,2); INSERT LOW_PRIORITY INTO t1 VALUES (1,2);
...@@ -172,3 +172,23 @@ a ...@@ -172,3 +172,23 @@ a
0 0
2 2
DROP TABLE t1; 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 @@ ...@@ -3,7 +3,7 @@
# #
--disable_warnings --disable_warnings
drop table if exists t1,t11,t12,t2; drop table if exists t1,t2,t3,t11,t12;
--enable_warnings --enable_warnings
CREATE TABLE t1 (a tinyint(3), b tinyint(5)); CREATE TABLE t1 (a tinyint(3), b tinyint(5));
INSERT INTO t1 VALUES (1,1); INSERT INTO t1 VALUES (1,1);
...@@ -152,3 +152,20 @@ INSERT INTO t1 VALUES (0),(1),(2); ...@@ -152,3 +152,20 @@ INSERT INTO t1 VALUES (0),(1),(2);
DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a LIMIT 1; DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a LIMIT 1;
SELECT * FROM t1; SELECT * FROM t1;
DROP TABLE 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, ...@@ -773,9 +773,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
Comp_creator *func) Comp_creator *func)
{ {
Item_subselect::trans_res result= RES_ERROR; Item_subselect::trans_res result= RES_ERROR;
DBUG_ENTER("Item_in_subselect::single_value_transformer");
SELECT_LEX *select_lex= join->select_lex; 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 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() ...@@ -7957,7 +7957,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat()
max_used_key_length= real_prefix_len; max_used_key_length= real_prefix_len;
if (min_max_ranges.elements > 0) if (min_max_ranges.elements > 0)
{ {
QUICK_RANGE *cur_range= 0; QUICK_RANGE *cur_range;
if (have_min) if (have_min)
{ /* Check if the right-most range has a lower boundary. */ { /* Check if the right-most range has a lower boundary. */
get_dynamic(&min_max_ranges, (gptr)&cur_range, get_dynamic(&min_max_ranges, (gptr)&cur_range,
...@@ -7965,7 +7965,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat() ...@@ -7965,7 +7965,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat()
if (!(cur_range->flag & NO_MIN_RANGE)) if (!(cur_range->flag & NO_MIN_RANGE))
{ {
max_used_key_length+= min_max_arg_len; max_used_key_length+= min_max_arg_len;
++used_key_parts; used_key_parts++;
return; return;
} }
} }
...@@ -7975,7 +7975,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat() ...@@ -7975,7 +7975,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat()
if (!(cur_range->flag & NO_MAX_RANGE)) if (!(cur_range->flag & NO_MAX_RANGE))
{ {
max_used_key_length+= min_max_arg_len; max_used_key_length+= min_max_arg_len;
++used_key_parts; used_key_parts++;
return; return;
} }
} }
...@@ -7992,7 +7992,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat() ...@@ -7992,7 +7992,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat()
usable key length. usable key length.
*/ */
max_used_key_length+= min_max_arg_len; 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 ...@@ -1854,7 +1854,8 @@ class multi_delete :public select_result_interceptor
ha_rows deleted, found; ha_rows deleted, found;
uint num_of_tables; uint num_of_tables;
int error; int error;
bool do_delete, transactional_tables, normal_tables; bool do_delete, transactional_tables, normal_tables, delete_while_scanning;
public: public:
multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables); multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables);
~multi_delete(); ~multi_delete();
...@@ -1862,7 +1863,7 @@ class multi_delete :public select_result_interceptor ...@@ -1862,7 +1863,7 @@ class multi_delete :public select_result_interceptor
bool send_data(List<Item> &items); bool send_data(List<Item> &items);
bool initialize_tables (JOIN *join); bool initialize_tables (JOIN *join);
void send_error(uint errcode,const char *err); void send_error(uint errcode,const char *err);
int do_deletes (bool from_send_error); int do_deletes();
bool send_eof(); bool send_eof();
}; };
......
...@@ -410,7 +410,7 @@ multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, ...@@ -410,7 +410,7 @@ multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
num_of_tables(num_of_tables_arg), error(0), num_of_tables(num_of_tables_arg), error(0),
do_delete(0), transactional_tables(0), normal_tables(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) ...@@ -440,6 +440,7 @@ multi_delete::initialize_tables(JOIN *join)
tables_to_delete_from|= walk->table->map; tables_to_delete_from|= walk->table->map;
walk= delete_tables; walk= delete_tables;
delete_while_scanning= 1;
for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables; for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
tab < end; tab < end;
tab++) tab++)
...@@ -459,10 +460,25 @@ multi_delete::initialize_tables(JOIN *join) ...@@ -459,10 +460,25 @@ multi_delete::initialize_tables(JOIN *join)
else else
normal_tables= 1; 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; walk= delete_tables;
tempfiles_ptr= tempfiles; 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; TABLE *table=walk->table;
*tempfiles_ptr++= new Unique (refpos_order_cmp, *tempfiles_ptr++= new Unique (refpos_order_cmp,
...@@ -481,12 +497,12 @@ multi_delete::~multi_delete() ...@@ -481,12 +497,12 @@ multi_delete::~multi_delete()
table_being_deleted; table_being_deleted;
table_being_deleted= table_being_deleted->next_local) table_being_deleted= table_being_deleted->next_local)
{ {
TABLE *t=table_being_deleted->table; TABLE *table= table_being_deleted->table;
free_io_cache(t); // Alloced by unique free_io_cache(table); // Alloced by unique
t->no_keyread=0; 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]) if (tempfiles[counter])
delete tempfiles[counter]; delete tempfiles[counter];
...@@ -496,14 +512,15 @@ multi_delete::~multi_delete() ...@@ -496,14 +512,15 @@ multi_delete::~multi_delete()
bool multi_delete::send_data(List<Item> &values) 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"); DBUG_ENTER("multi_delete::send_data");
for (table_being_deleted= delete_tables; for (del_table= delete_tables;
table_being_deleted; del_table;
table_being_deleted= table_being_deleted->next_local, secure_counter++) 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 */ /* Check if we are using outer join and we didn't find the row */
if (table->status & (STATUS_NULL_ROW | STATUS_DELETED)) if (table->status & (STATUS_NULL_ROW | STATUS_DELETED))
...@@ -514,7 +531,8 @@ bool multi_delete::send_data(List<Item> &values) ...@@ -514,7 +531,8 @@ bool multi_delete::send_data(List<Item> &values)
if (secure_counter < 0) 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 && if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_DELETE, table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
TRG_ACTION_BEFORE, FALSE)) TRG_ACTION_BEFORE, FALSE))
...@@ -528,8 +546,7 @@ bool multi_delete::send_data(List<Item> &values) ...@@ -528,8 +546,7 @@ bool multi_delete::send_data(List<Item> &values)
TRG_ACTION_AFTER, FALSE)) TRG_ACTION_AFTER, FALSE))
DBUG_RETURN(1); DBUG_RETURN(1);
} }
else if (!table_being_deleted->next_local || else
table_being_deleted->table->file->has_transactions())
{ {
table->file->print_error(error,MYF(0)); table->file->print_error(error,MYF(0));
DBUG_RETURN(1); DBUG_RETURN(1);
...@@ -540,7 +557,7 @@ bool multi_delete::send_data(List<Item> &values) ...@@ -540,7 +557,7 @@ bool multi_delete::send_data(List<Item> &values)
error=tempfiles[secure_counter]->unique_add((char*) table->file->ref); error=tempfiles[secure_counter]->unique_add((char*) table->file->ref);
if (error) if (error)
{ {
error=-1; error= 1; // Fatal error
DBUG_RETURN(1); DBUG_RETURN(1);
} }
} }
...@@ -563,22 +580,24 @@ void multi_delete::send_error(uint errcode,const char *err) ...@@ -563,22 +580,24 @@ void multi_delete::send_error(uint errcode,const char *err)
/* Something already deleted so we have to invalidate cache */ /* Something already deleted so we have to invalidate cache */
query_cache_invalidate3(thd, delete_tables, 1); 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 If rows from the first table only has been deleted and it is
transactional, just do rollback. transactional, just do rollback.
The same if all tables are transactional, regardless of where we are. The same if all tables are transactional, regardless of where we are.
In all other cases do attempt deletes ... In all other cases do attempt deletes ...
*/ */
if ((table_being_deleted->table->file->has_transactions() && if ((table_being_deleted == delete_tables &&
table_being_deleted == delete_tables) || !normal_tables) table_being_deleted->table->file->has_transactions()) ||
!normal_tables)
ha_rollback_stmt(thd); ha_rollback_stmt(thd);
else if (do_delete) 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; DBUG_VOID_RETURN;
} }
...@@ -591,27 +610,20 @@ void multi_delete::send_error(uint errcode,const char *err) ...@@ -591,27 +610,20 @@ void multi_delete::send_error(uint errcode,const char *err)
1 error 1 error
*/ */
int multi_delete::do_deletes(bool from_send_error) int multi_delete::do_deletes()
{ {
int local_error= 0, counter= 0; int local_error= 0, counter= 0;
DBUG_ENTER("do_deletes"); DBUG_ENTER("do_deletes");
DBUG_ASSERT(do_delete);
if (from_send_error) do_delete= 0; // Mark called
{
/* 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;
if (!found) if (!found)
DBUG_RETURN(0); 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_being_deleted= table_being_deleted->next_local, counter++)
{ {
TABLE *table = table_being_deleted->table; TABLE *table = table_being_deleted->table;
...@@ -673,7 +685,7 @@ bool multi_delete::send_eof() ...@@ -673,7 +685,7 @@ bool multi_delete::send_eof()
thd->proc_info="deleting from reference tables"; thd->proc_info="deleting from reference tables";
/* Does deletes for the last n - 1 tables, returns 0 if ok */ /* 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 */ /* reset used flags */
thd->proc_info="end"; thd->proc_info="end";
......
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