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));
|
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
|
|||||||
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 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
--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);
|
|||||||
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,
|
|||||||
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()
|
|||||||
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()
|
|||||||
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()
|
|||||||
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()
|
|||||||
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
|
|||||||
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 @@ public:
|
|||||||
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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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()
|
|||||||
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()
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
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()
|
|||||||
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";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user