mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-30469 Support ORDER BY and LIMIT for multi-table DELETE, index hints for single-table DELETE
We now allow multitable queries with order by and limit, such as: delete t1.*, t2.* from t1, t2 order by t1.id desc limit 3; To predict what rows will be deleted, run the equivalent select: select t1.*, t2.* from t1, t2 order by t1.id desc limit 3; Additionally, index hints are now supported with single table delete statements: delete from t2 use index(xid) order by (id) limit 2; This approach changes the multi_delete SELECT result interceptor to use a temporary table to collect row ids pertaining to the rows that will be deleted, rather than directly deleting rows from the target table(s). Row ids are collected during send_data, then read during send_eof to delete target rows. In the event that the temporary table created in memory is not big enough for all matching rows, it is converted to an aria table. Other changes: - Deleting from a sequence now affects zero rows instead of emitting an error Limitations: - The federated connector does not create implicit row ids, so we to use a key when conditionally deleting. See the change in federated_maybe_16324629.test
This commit is contained in:
@ -680,3 +680,105 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 20000
|
||||
drop table t1, t2;
|
||||
# End of 11.7 tests
|
||||
#
|
||||
# MDEV-30469: Add support of ORDER BY and LIMIT to multidelete query.
|
||||
#
|
||||
# Check that limits work with hints
|
||||
create table t2 (id int, index xid(id));
|
||||
insert into t2 values (1),(10),(2),(9),(3),(8);
|
||||
DELETE t2.* FROM t2 use index(xid) ORDER BY (id) LIMIT 2;
|
||||
select * from t2 ORDER BY (id);
|
||||
id
|
||||
3
|
||||
8
|
||||
9
|
||||
10
|
||||
DELETE t2.* FROM t2 use index(xid) ORDER BY (id) DESC LIMIT 3;
|
||||
select * from t2;
|
||||
id
|
||||
3
|
||||
# Check some useles syntax
|
||||
DELETE t2.* FROM t2 FORCE INDEX FOR GROUP BY (xid) ORDER BY (id) LIMIT 1;
|
||||
drop table t2;
|
||||
# Check that hints work with limit
|
||||
create table t2 (id int primary key, index xid(id));
|
||||
insert into t2 values (1),(10),(2),(9),(3),(8);
|
||||
# default primary index
|
||||
explain
|
||||
DELETE t2.* FROM t2 ORDER BY (id) LIMIT 2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 index NULL PRIMARY 4 NULL 2
|
||||
# make it use other undex
|
||||
explain
|
||||
DELETE t2.* FROM t2 use index(xid) ORDER BY (id) LIMIT 2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 index NULL xid 4 NULL 2
|
||||
explain
|
||||
DELETE t2.* FROM t2 force index(xid) ORDER BY (id) LIMIT 2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 index NULL xid 4 NULL 2
|
||||
# prohibit primary index
|
||||
explain
|
||||
DELETE t2.* FROM t2 ignore index(primary) ORDER BY (id) LIMIT 2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 index NULL xid 4 NULL 2
|
||||
drop table t2;
|
||||
# Check that limits work with hints & PS protocol
|
||||
create table t2 (id int, index xid(id));
|
||||
insert into t2 values (1),(10),(2),(9),(3),(8);
|
||||
prepare stmt from
|
||||
"DELETE t2.* FROM t2 use index(xid) ORDER BY (id) LIMIT ?";
|
||||
set @lim= 2;
|
||||
execute stmt using @lim;
|
||||
select * from t2 ORDER BY (id);
|
||||
id
|
||||
3
|
||||
8
|
||||
9
|
||||
10
|
||||
set @lim= 1;
|
||||
execute stmt using @lim;
|
||||
select * from t2 ORDER BY (id);
|
||||
id
|
||||
8
|
||||
9
|
||||
10
|
||||
set @lim= 3;
|
||||
execute stmt using @lim;
|
||||
select * from t2 ORDER BY (id);
|
||||
id
|
||||
drop table t2;
|
||||
# Check that hints work with limit in normal DELETE syntax
|
||||
create table t2 (id int primary key, index xid(id));
|
||||
insert into t2 values (1),(10),(2),(9),(3),(8);
|
||||
# default primary index
|
||||
explain
|
||||
DELETE FROM t2 ORDER BY (id) LIMIT 2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 index NULL PRIMARY 4 NULL 2
|
||||
# make it use other undex
|
||||
explain
|
||||
DELETE FROM t2 use index(xid) ORDER BY (id) LIMIT 2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 index NULL xid 4 NULL 2
|
||||
explain
|
||||
DELETE FROM t2 force index(xid) ORDER BY (id) LIMIT 2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 index NULL xid 4 NULL 2
|
||||
# prohibit primary index
|
||||
explain
|
||||
DELETE FROM t2 ignore index(primary) ORDER BY (id) LIMIT 2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 index NULL xid 4 NULL 2
|
||||
# should issue warnings becaouse we can not switch it internally
|
||||
# to multiupdate due to RETURNING
|
||||
DELETE FROM t2 ignore index(primary) ORDER BY (id) LIMIT 2 RETURNING id;
|
||||
id
|
||||
1
|
||||
2
|
||||
Warnings:
|
||||
Warning 4206 Index hints are ignored because they are incompatible with RETURNING clause
|
||||
drop table t2;
|
||||
#
|
||||
# End of 11.4 test
|
||||
#
|
||||
|
@ -744,3 +744,87 @@ explain delete from t1 where b <= 3 and a not in (select b from t2);
|
||||
drop table t1, t2;
|
||||
|
||||
--echo # End of 11.7 tests
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-30469: Add support of ORDER BY and LIMIT to multidelete query.
|
||||
--echo #
|
||||
|
||||
--echo # Check that limits work with hints
|
||||
|
||||
create table t2 (id int, index xid(id));
|
||||
insert into t2 values (1),(10),(2),(9),(3),(8);
|
||||
|
||||
DELETE t2.* FROM t2 use index(xid) ORDER BY (id) LIMIT 2;
|
||||
select * from t2 ORDER BY (id);
|
||||
DELETE t2.* FROM t2 use index(xid) ORDER BY (id) DESC LIMIT 3;
|
||||
select * from t2;
|
||||
--echo # Check some useles syntax
|
||||
DELETE t2.* FROM t2 FORCE INDEX FOR GROUP BY (xid) ORDER BY (id) LIMIT 1;
|
||||
|
||||
drop table t2;
|
||||
|
||||
|
||||
--echo # Check that hints work with limit
|
||||
|
||||
create table t2 (id int primary key, index xid(id));
|
||||
insert into t2 values (1),(10),(2),(9),(3),(8);
|
||||
|
||||
--echo # default primary index
|
||||
explain
|
||||
DELETE t2.* FROM t2 ORDER BY (id) LIMIT 2;
|
||||
--echo # make it use other undex
|
||||
explain
|
||||
DELETE t2.* FROM t2 use index(xid) ORDER BY (id) LIMIT 2;
|
||||
explain
|
||||
DELETE t2.* FROM t2 force index(xid) ORDER BY (id) LIMIT 2;
|
||||
--echo # prohibit primary index
|
||||
explain
|
||||
DELETE t2.* FROM t2 ignore index(primary) ORDER BY (id) LIMIT 2;
|
||||
|
||||
drop table t2;
|
||||
|
||||
--echo # Check that limits work with hints & PS protocol
|
||||
|
||||
create table t2 (id int, index xid(id));
|
||||
insert into t2 values (1),(10),(2),(9),(3),(8);
|
||||
|
||||
prepare stmt from
|
||||
"DELETE t2.* FROM t2 use index(xid) ORDER BY (id) LIMIT ?";
|
||||
set @lim= 2;
|
||||
execute stmt using @lim;
|
||||
select * from t2 ORDER BY (id);
|
||||
set @lim= 1;
|
||||
execute stmt using @lim;
|
||||
select * from t2 ORDER BY (id);
|
||||
set @lim= 3;
|
||||
execute stmt using @lim;
|
||||
select * from t2 ORDER BY (id);
|
||||
|
||||
drop table t2;
|
||||
|
||||
--echo # Check that hints work with limit in normal DELETE syntax
|
||||
|
||||
create table t2 (id int primary key, index xid(id));
|
||||
insert into t2 values (1),(10),(2),(9),(3),(8);
|
||||
|
||||
--echo # default primary index
|
||||
explain
|
||||
DELETE FROM t2 ORDER BY (id) LIMIT 2;
|
||||
--echo # make it use other undex
|
||||
explain
|
||||
DELETE FROM t2 use index(xid) ORDER BY (id) LIMIT 2;
|
||||
explain
|
||||
DELETE FROM t2 force index(xid) ORDER BY (id) LIMIT 2;
|
||||
--echo # prohibit primary index
|
||||
explain
|
||||
DELETE FROM t2 ignore index(primary) ORDER BY (id) LIMIT 2;
|
||||
|
||||
--echo # should issue warnings becaouse we can not switch it internally
|
||||
--echo # to multiupdate due to RETURNING
|
||||
DELETE FROM t2 ignore index(primary) ORDER BY (id) LIMIT 2 RETURNING id;
|
||||
|
||||
drop table t2;
|
||||
|
||||
--echo #
|
||||
--echo # End of 11.4 test
|
||||
--echo #
|
||||
|
@ -60,8 +60,8 @@ INSERT INTO t2 values (3);
|
||||
disallows sj optimization
|
||||
analyze DELETE FROM t1 WHERE c1 IN (select c2 from t2) ORDER BY c1 limit 1;
|
||||
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 5 1.00 100.00 100.00 Using where; Using filesort
|
||||
2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 1 1.00 100.00 20.00 Using where
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 5 2.00 100.00 100.00 Using filesort
|
||||
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 1.00 100.00 50.00 Using where; FirstMatch(t1)
|
||||
select * from t1;
|
||||
c1
|
||||
1
|
||||
|
239
mysql-test/main/delete_multi_order_by.result
Normal file
239
mysql-test/main/delete_multi_order_by.result
Normal file
@ -0,0 +1,239 @@
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
id v
|
||||
4 1
|
||||
3 2
|
||||
2 3
|
||||
1 4
|
||||
select * from t2;
|
||||
id v
|
||||
5 5
|
||||
3 2
|
||||
2 3
|
||||
6 6
|
||||
delete t1.*, t2.* from t1, t2 order by t1.id desc limit 3;
|
||||
select * from t1;
|
||||
id v
|
||||
3 2
|
||||
2 3
|
||||
1 4
|
||||
select * from t2;
|
||||
id v
|
||||
6 6
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
id v
|
||||
4 1
|
||||
3 2
|
||||
2 3
|
||||
1 4
|
||||
select * from t2;
|
||||
id v
|
||||
5 5
|
||||
3 2
|
||||
2 3
|
||||
6 6
|
||||
delete t1.*, t2.* from t1, t2 order by t1.id desc;
|
||||
select * from t1;
|
||||
id v
|
||||
select * from t2;
|
||||
id v
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
id v
|
||||
4 1
|
||||
3 2
|
||||
2 3
|
||||
1 4
|
||||
select * from t2;
|
||||
id v
|
||||
5 5
|
||||
3 2
|
||||
2 3
|
||||
6 6
|
||||
delete t1.*, t2.* from t1, t2 limit 2;
|
||||
select * from t1;
|
||||
id v
|
||||
3 2
|
||||
2 3
|
||||
1 4
|
||||
select * from t2;
|
||||
id v
|
||||
2 3
|
||||
6 6
|
||||
create table t3 (a int primary key, b text);
|
||||
insert into t3 (a, b) values (1, 'hello');
|
||||
delete from t3 where b = '';
|
||||
drop table t3;
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
id v
|
||||
4 1
|
||||
3 2
|
||||
2 3
|
||||
1 4
|
||||
select * from t2;
|
||||
id v
|
||||
5 5
|
||||
3 2
|
||||
2 3
|
||||
6 6
|
||||
delete t1.*, t2.* from t1, t2 where t1.id=t2.id;
|
||||
select * from t1;
|
||||
id v
|
||||
4 1
|
||||
1 4
|
||||
select * from t2;
|
||||
id v
|
||||
5 5
|
||||
6 6
|
||||
drop table if exists t1;
|
||||
create table t1(a INT);
|
||||
insert into t1 values (1),(2),(3);
|
||||
set session sql_buffer_result=1;
|
||||
delete t1 from (select sum(a) a from t1) x,t1;
|
||||
set session sql_buffer_result=default;
|
||||
select * from t1;
|
||||
a
|
||||
drop table t1;
|
||||
drop table if exists t1, t2;
|
||||
Warnings:
|
||||
Note 1051 Unknown table 'test.t1'
|
||||
create table t1(id1 smallint(5), field char(5));
|
||||
create table t2(id2 smallint(5), field char(5));
|
||||
insert into t1 values (1, 'a'), (2, 'aa');
|
||||
insert into t2 values (1, 'b'), (2, 'bb');
|
||||
update t2 inner join t1 on t1.id1=t2.id2 set t2.field=t1.field where 0=1;
|
||||
update t2, t1 set t2.field=t1.field where t1.id1=t2.id2 and 0=1;
|
||||
delete t1, t2 from t2 inner join t1 on t1.id1=t2.id2 where 0=1;
|
||||
drop table t1, t2;
|
||||
set session sql_buffer_result=1;
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
id v
|
||||
4 1
|
||||
3 2
|
||||
2 3
|
||||
1 4
|
||||
select * from t2;
|
||||
id v
|
||||
5 5
|
||||
3 2
|
||||
2 3
|
||||
6 6
|
||||
delete t1.*, t2.* from t1, t2 order by t1.id desc limit 3;
|
||||
select * from t1;
|
||||
id v
|
||||
3 2
|
||||
2 3
|
||||
1 4
|
||||
select * from t2;
|
||||
id v
|
||||
6 6
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
id v
|
||||
4 1
|
||||
3 2
|
||||
2 3
|
||||
1 4
|
||||
select * from t2;
|
||||
id v
|
||||
5 5
|
||||
3 2
|
||||
2 3
|
||||
6 6
|
||||
delete t1.*, t2.* from t1, t2 order by t1.id desc;
|
||||
select * from t1;
|
||||
id v
|
||||
select * from t2;
|
||||
id v
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
id v
|
||||
4 1
|
||||
3 2
|
||||
2 3
|
||||
1 4
|
||||
select * from t2;
|
||||
id v
|
||||
5 5
|
||||
3 2
|
||||
2 3
|
||||
6 6
|
||||
delete t1.*, t2.* from t1, t2 limit 2;
|
||||
select * from t1;
|
||||
id v
|
||||
3 2
|
||||
2 3
|
||||
1 4
|
||||
select * from t2;
|
||||
id v
|
||||
2 3
|
||||
6 6
|
||||
create table t3 (a int primary key, b text);
|
||||
insert into t3 (a, b) values (1, 'hello');
|
||||
delete from t3 where b = '';
|
||||
drop table t3;
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
id v
|
||||
4 1
|
||||
3 2
|
||||
2 3
|
||||
1 4
|
||||
select * from t2;
|
||||
id v
|
||||
5 5
|
||||
3 2
|
||||
2 3
|
||||
6 6
|
||||
delete t1.*, t2.* from t1, t2 where t1.id=t2.id;
|
||||
select * from t1;
|
||||
id v
|
||||
4 1
|
||||
1 4
|
||||
select * from t2;
|
||||
id v
|
||||
5 5
|
||||
6 6
|
||||
drop table if exists t1, t2;
|
||||
create table t1(id1 smallint(5), field char(5));
|
||||
create table t2(id2 smallint(5), field char(5));
|
||||
insert into t1 values (1, 'a'), (2, 'aa');
|
||||
insert into t2 values (1, 'b'), (2, 'bb');
|
||||
update t2 inner join t1 on t1.id1=t2.id2 set t2.field=t1.field where 0=1;
|
||||
update t2, t1 set t2.field=t1.field where t1.id1=t2.id2 and 0=1;
|
||||
delete t1, t2 from t2 inner join t1 on t1.id1=t2.id2 where 0=1;
|
||||
drop table t1, t2;
|
||||
set session sql_buffer_result=default;
|
131
mysql-test/main/delete_multi_order_by.test
Normal file
131
mysql-test/main/delete_multi_order_by.test
Normal file
@ -0,0 +1,131 @@
|
||||
#
|
||||
# MDEV-30469 Support ORDER BY and LIMIT for multi-table DELETE, index hints for single-table DELETE.
|
||||
#
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
delete t1.*, t2.* from t1, t2 order by t1.id desc limit 3;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
delete t1.*, t2.* from t1, t2 order by t1.id desc;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
delete t1.*, t2.* from t1, t2 limit 2;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
create table t3 (a int primary key, b text);
|
||||
insert into t3 (a, b) values (1, 'hello');
|
||||
delete from t3 where b = '';
|
||||
drop table t3;
|
||||
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
delete t1.*, t2.* from t1, t2 where t1.id=t2.id;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
drop table if exists t1;
|
||||
create table t1(a INT);
|
||||
insert into t1 values (1),(2),(3);
|
||||
set session sql_buffer_result=1;
|
||||
delete t1 from (select sum(a) a from t1) x,t1;
|
||||
set session sql_buffer_result=default;
|
||||
select * from t1;
|
||||
drop table t1;
|
||||
|
||||
drop table if exists t1, t2;
|
||||
create table t1(id1 smallint(5), field char(5));
|
||||
create table t2(id2 smallint(5), field char(5));
|
||||
insert into t1 values (1, 'a'), (2, 'aa');
|
||||
insert into t2 values (1, 'b'), (2, 'bb');
|
||||
update t2 inner join t1 on t1.id1=t2.id2 set t2.field=t1.field where 0=1;
|
||||
update t2, t1 set t2.field=t1.field where t1.id1=t2.id2 and 0=1;
|
||||
delete t1, t2 from t2 inner join t1 on t1.id1=t2.id2 where 0=1;
|
||||
drop table t1, t2;
|
||||
|
||||
|
||||
set session sql_buffer_result=1;
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
delete t1.*, t2.* from t1, t2 order by t1.id desc limit 3;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
delete t1.*, t2.* from t1, t2 order by t1.id desc;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
delete t1.*, t2.* from t1, t2 limit 2;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
create table t3 (a int primary key, b text);
|
||||
insert into t3 (a, b) values (1, 'hello');
|
||||
delete from t3 where b = '';
|
||||
drop table t3;
|
||||
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (id int primary key, v int);
|
||||
create table t2 (id int primary key, v int);
|
||||
insert into t1 (id, v) values (4,1),(3,2),(2,3),(1,4);
|
||||
insert into t2 (id, v) values (5,5),(3,2),(2,3),(6,6);
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
delete t1.*, t2.* from t1, t2 where t1.id=t2.id;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
drop table if exists t1, t2;
|
||||
create table t1(id1 smallint(5), field char(5));
|
||||
create table t2(id2 smallint(5), field char(5));
|
||||
insert into t1 values (1, 'a'), (2, 'aa');
|
||||
insert into t2 values (1, 'b'), (2, 'bb');
|
||||
update t2 inner join t1 on t1.id1=t2.id2 set t2.field=t1.field where 0=1;
|
||||
update t2, t1 set t2.field=t1.field where t1.id1=t2.id2 and 0=1;
|
||||
delete t1, t2 from t2 inner join t1 on t1.id1=t2.id2 where 0=1;
|
||||
|
||||
drop table t1, t2;
|
||||
set session sql_buffer_result=default;
|
@ -3342,22 +3342,22 @@ o_custkey in (select c_custkey from customer
|
||||
where c_nationkey in (1,2))
|
||||
order by o_totalprice limit 500;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY orders range i_o_orderdate i_o_orderdate 4 NULL 108 Using where; Using filesort
|
||||
2 DEPENDENT SUBQUERY customer unique_subquery PRIMARY,i_c_nationkey PRIMARY 4 func 1 Using where
|
||||
1 PRIMARY customer range PRIMARY,i_c_nationkey i_c_nationkey 5 NULL 13 Using index condition; Using temporary; Using filesort
|
||||
1 PRIMARY orders ref|filter i_o_orderdate,i_o_custkey i_o_custkey|i_o_orderdate 5|4 dbt3_s001.customer.c_custkey 15 (7%) Using where; Using rowid filter
|
||||
create table t as
|
||||
select * from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and
|
||||
o_custkey in (select c_custkey from customer
|
||||
where c_nationkey in (1,2));
|
||||
select o_orderkey, o_totalprice from t;
|
||||
o_orderkey o_totalprice
|
||||
1221 117397.16
|
||||
324 26868.85
|
||||
1856 189361.42
|
||||
4903 34363.63
|
||||
5607 24660.06
|
||||
1221 117397.16
|
||||
1344 43809.37
|
||||
1925 146382.71
|
||||
3139 40975.96
|
||||
4903 34363.63
|
||||
5607 24660.06
|
||||
delete from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and
|
||||
o_custkey in (select c_custkey from customer
|
||||
where c_nationkey in (1,2))
|
||||
@ -3394,14 +3394,14 @@ o_custkey in (select c_custkey from customer
|
||||
where c_nationkey in (1,2));
|
||||
select o_orderkey, o_totalprice from t;
|
||||
o_orderkey o_totalprice
|
||||
1221 117397.16
|
||||
324 26868.85
|
||||
1856 189361.42
|
||||
324 26868.85
|
||||
1221 117397.16
|
||||
3139 40975.96
|
||||
1925 146382.71
|
||||
1344 43809.37
|
||||
4903 34363.63
|
||||
5607 24660.06
|
||||
1344 43809.37
|
||||
1925 146382.71
|
||||
3139 40975.96
|
||||
delete from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and
|
||||
o_custkey in (select c_custkey from customer
|
||||
where c_nationkey in (1,2));
|
||||
|
@ -232,8 +232,8 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
explain delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using where; Using filesort
|
||||
2 DEPENDENT SUBQUERY a ALL NULL NULL NULL NULL 32 Using where
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using filesort
|
||||
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1)
|
||||
delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
affected rows: 1
|
||||
@ -788,8 +788,8 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
explain delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using where; Using filesort
|
||||
2 DEPENDENT SUBQUERY a index_subquery t1_c2 t1_c2 5 func 5 Using where
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using filesort
|
||||
1 PRIMARY a ALL t1_c2 NULL NULL NULL 32 Using where; FirstMatch(t1)
|
||||
delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
affected rows: 1
|
||||
@ -1345,8 +1345,8 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
explain delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 index NULL PRIMARY 4 NULL 1 Using where
|
||||
2 DEPENDENT SUBQUERY a eq_ref PRIMARY PRIMARY 4 test.t1.c3 1 Using where
|
||||
1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 1
|
||||
1 PRIMARY a eq_ref PRIMARY PRIMARY 4 test.t1.c3 1 Using where
|
||||
delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
affected rows: 1
|
||||
@ -1995,8 +1995,8 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
explain delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using where; Using filesort
|
||||
2 DEPENDENT SUBQUERY a ALL NULL NULL NULL NULL 32 Using where
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using filesort
|
||||
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1)
|
||||
delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
affected rows: 1
|
||||
@ -2767,7 +2767,7 @@ explain delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using where; Using filesort
|
||||
2 DEPENDENT SUBQUERY a index_subquery t1_c2 t1_c2 5 func 5 Using where
|
||||
1 PRIMARY a ref t1_c2 t1_c2 5 test.t1.c1 5 Using where; FirstMatch(t1)
|
||||
delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
affected rows: 1
|
||||
@ -3394,7 +3394,7 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
analyze delete from t1 where c1 = 1 and exists (select 'X' from t1 a where a.c1 = t1.c2);
|
||||
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 32.00 9.38 9.38 Using where
|
||||
1 PRIMARY a ALL NULL NULL NULL NULL 32 12.00 3.12 5.56 Using where; FirstMatch(t1)
|
||||
1 PRIMARY a ALL NULL NULL NULL NULL 32 13.33 3.12 5.00 Using where; FirstMatch(t1)
|
||||
select * from t1;
|
||||
c1 c2 c3
|
||||
1 3 3
|
||||
@ -3535,8 +3535,8 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
explain delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 index NULL PRIMARY 4 NULL 1 Using where
|
||||
2 DEPENDENT SUBQUERY a eq_ref PRIMARY PRIMARY 4 test.t1.c3 1 Using where
|
||||
1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 1
|
||||
1 PRIMARY a eq_ref PRIMARY PRIMARY 4 test.t1.c3 1 Using where
|
||||
delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
affected rows: 1
|
||||
@ -4054,7 +4054,7 @@ and c1 = 2
|
||||
and exists (select 'X' from v1 a where a.c1 = v1.c1);
|
||||
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL # 32.00 3.91 3.12 Using where
|
||||
3 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL # 6.00 25.00 16.67 Using where
|
||||
3 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL # 10.00 25.00 10.00 Using where
|
||||
2 DEPENDENT SUBQUERY a eq_ref PRIMARY PRIMARY 4 test.t1.c3 # 1.00 100.00 100.00
|
||||
select * from t1;
|
||||
c1 c2 c3
|
||||
@ -4400,8 +4400,8 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
explain delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using where; Using filesort
|
||||
2 DEPENDENT SUBQUERY a ALL NULL NULL NULL NULL 32 Using where
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using filesort
|
||||
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1)
|
||||
delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
affected rows: 1
|
||||
@ -5171,8 +5171,8 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
explain delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using where; Using filesort
|
||||
2 DEPENDENT SUBQUERY a index_subquery t1_c2 t1_c2 5 func 5 Using where
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using filesort
|
||||
1 PRIMARY a ALL t1_c2 NULL NULL NULL 32 Using where; FirstMatch(t1)
|
||||
delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
affected rows: 1
|
||||
@ -5799,7 +5799,7 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
analyze delete from t1 where c1 = 1 and exists (select 'X' from t1 a where a.c1 = t1.c2);
|
||||
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 32.00 9.38 9.38 Using where
|
||||
1 PRIMARY a ALL NULL NULL NULL NULL 32 13.33 3.12 5.00 Using where; FirstMatch(t1)
|
||||
1 PRIMARY a ALL NULL NULL NULL NULL 32 14.00 3.12 4.76 Using where; FirstMatch(t1)
|
||||
select * from t1;
|
||||
c1 c2 c3
|
||||
1 3 3
|
||||
@ -5940,8 +5940,8 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
explain delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 index NULL PRIMARY 4 NULL 1 Using where
|
||||
2 DEPENDENT SUBQUERY a eq_ref PRIMARY PRIMARY 4 test.t1.c3 1 Using where
|
||||
1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 1
|
||||
1 PRIMARY a eq_ref PRIMARY PRIMARY 4 test.t1.c3 1 Using where
|
||||
delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
affected rows: 1
|
||||
@ -6888,8 +6888,8 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
explain delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using where; Using filesort
|
||||
2 DEPENDENT SUBQUERY a ALL NULL NULL NULL NULL 32 Using where
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using filesort
|
||||
1 PRIMARY a ALL NULL NULL NULL NULL 32 Using where; FirstMatch(t1)
|
||||
delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
affected rows: 1
|
||||
@ -7643,8 +7643,8 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
explain delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using where; Using filesort
|
||||
2 DEPENDENT SUBQUERY a ALL t1_c2 NULL NULL NULL 32 Using where
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using filesort
|
||||
1 PRIMARY a ALL t1_c2 NULL NULL NULL 32 Using where; FirstMatch(t1)
|
||||
delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
affected rows: 1
|
||||
@ -8401,8 +8401,8 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
explain delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 32 Using where; Using filesort
|
||||
2 DEPENDENT SUBQUERY a eq_ref PRIMARY PRIMARY 4 test.t1.c3 1 Using where
|
||||
1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 32 Using filesort
|
||||
1 PRIMARY a eq_ref PRIMARY PRIMARY 4 test.t1.c3 1 Using where
|
||||
delete from t1 where c1 in (select a.c2 from t1 a where a.c3 = t1.c3)
|
||||
order by c3 desc limit 1;
|
||||
affected rows: 1
|
||||
|
12
mysql-test/main/multidelete_engine.combinations
Normal file
12
mysql-test/main/multidelete_engine.combinations
Normal file
@ -0,0 +1,12 @@
|
||||
[myisam]
|
||||
default-storage-engine=myisam
|
||||
|
||||
[aria]
|
||||
default-storage-engine=aria
|
||||
|
||||
[innodb]
|
||||
innodb
|
||||
default-storage-engine=innodb
|
||||
|
||||
[heap]
|
||||
default-storage-engine=memory
|
20
mysql-test/main/multidelete_engine.test
Normal file
20
mysql-test/main/multidelete_engine.test
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
--echo # Check that limits work with hints & PS protocol
|
||||
|
||||
create table t2 (id int, index xid(id));
|
||||
insert into t2 values (1),(10),(2),(9),(3),(8);
|
||||
|
||||
prepare stmt from
|
||||
"DELETE t2.* FROM t2 use index(xid) ORDER BY (id) LIMIT ?";
|
||||
set @lim= 6;
|
||||
execute stmt using @lim;
|
||||
select * from t2 ORDER BY (id);
|
||||
set @lim= 1;
|
||||
execute stmt using @lim;
|
||||
select * from t2 ORDER BY (id);
|
||||
set @lim= 3;
|
||||
execute stmt using @lim;
|
||||
select * from t2 ORDER BY (id);
|
||||
|
||||
drop table t2;
|
||||
|
@ -120,7 +120,8 @@ Handler_read_rnd_next 4
|
||||
Variable_name Value
|
||||
Handler_delete 1
|
||||
Handler_read_key 2
|
||||
Handler_read_rnd_next 4
|
||||
Handler_read_rnd 1
|
||||
Handler_read_rnd_next 6
|
||||
|
||||
DROP TABLE t1;
|
||||
#4
|
||||
@ -927,8 +928,9 @@ Variable_name Value
|
||||
Handler_delete 8
|
||||
Handler_read_key 19
|
||||
Handler_read_next 3
|
||||
Handler_read_rnd 5
|
||||
Handler_read_rnd_next 4
|
||||
Handler_read_rnd 8
|
||||
Handler_read_rnd_deleted 1
|
||||
Handler_read_rnd_next 15
|
||||
|
||||
DROP TABLE t1, t2, t3;
|
||||
#20
|
||||
@ -1064,7 +1066,8 @@ Handler_read_rnd_next 12
|
||||
Variable_name Value
|
||||
Handler_delete 3
|
||||
Handler_read_key 4
|
||||
Handler_read_rnd_next 30
|
||||
Handler_read_rnd 3
|
||||
Handler_read_rnd_next 34
|
||||
|
||||
DROP TABLE t1, t2;
|
||||
#22
|
||||
@ -2891,7 +2894,7 @@ Variable_name Value
|
||||
Handler_delete 4
|
||||
Handler_read_key 10
|
||||
Handler_read_rnd 4
|
||||
Handler_read_rnd_next 5
|
||||
Handler_read_rnd_next 10
|
||||
|
||||
DROP TABLE t1,t2;
|
||||
DROP VIEW v1;
|
||||
@ -2940,7 +2943,7 @@ Variable_name Value
|
||||
Handler_delete 4
|
||||
Handler_read_key 10
|
||||
Handler_read_rnd 4
|
||||
Handler_read_rnd_next 5
|
||||
Handler_read_rnd_next 10
|
||||
|
||||
DROP TABLE t1,t2;
|
||||
DROP VIEW v1;
|
||||
|
@ -1236,8 +1236,8 @@ HANDLER_READ_FIRST 1
|
||||
HANDLER_READ_KEY 2
|
||||
HANDLER_READ_NEXT 2
|
||||
HANDLER_READ_RND 4
|
||||
HANDLER_READ_RND_NEXT 16
|
||||
HANDLER_TMP_WRITE 24
|
||||
HANDLER_READ_RND_NEXT 22
|
||||
HANDLER_TMP_WRITE 28
|
||||
# 4 delete (2 in t2 + 2 in t3)
|
||||
# 12 locks (3 in t2, 1 in t3, 2 in t1) x 2 (lock + unlock)
|
||||
# 3 read first (1 in t1 + 1 in t3 + 1 in t3, for second row in t1)
|
||||
|
@ -307,13 +307,13 @@ START TRANSACTION
|
||||
#010909 4:46:40 server id # end_log_pos # Delete_rows: table id # flags: STMT_END_F
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=3 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### @1=1 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=2 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=1 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### @1=3 /* INT meta=0 nullable=1 is_null=0 */
|
||||
# Number of rows: 3
|
||||
# at #
|
||||
#010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 xid=<xid>
|
||||
@ -688,13 +688,13 @@ START TRANSACTION
|
||||
#010909 4:46:40 server id # end_log_pos # Delete_rows: table id # flags: STMT_END_F
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=3 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### @1=1 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=2 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=1 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### @1=3 /* INT meta=0 nullable=1 is_null=0 */
|
||||
# Number of rows: 3
|
||||
# at #
|
||||
#010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 xid=<xid>
|
||||
@ -930,13 +930,13 @@ START TRANSACTION
|
||||
#010909 4:46:40 server id # end_log_pos # Delete_rows: table id # flags: STMT_END_F
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=3 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### @1=1 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=2 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=1 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### @1=3 /* INT meta=0 nullable=1 is_null=0 */
|
||||
# Number of rows: 3
|
||||
# at #
|
||||
#010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 xid=<xid>
|
||||
@ -1305,13 +1305,13 @@ START TRANSACTION
|
||||
#010909 4:46:40 server id # end_log_pos # Delete_rows: table id # flags: STMT_END_F
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=3 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### @1=1 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=2 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=1 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### @1=3 /* INT meta=0 nullable=1 is_null=0 */
|
||||
# Number of rows: 3
|
||||
# at #
|
||||
#010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 xid=<xid>
|
||||
|
@ -311,13 +311,13 @@ START TRANSACTION
|
||||
#010909 4:46:40 server id # end_log_pos # Delete_rows: table id # flags: STMT_END_F
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=3 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### @1=1 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=2 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=1 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### @1=3 /* INT meta=0 nullable=1 is_null=0 */
|
||||
# Number of rows: 3
|
||||
# at #
|
||||
#010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 xid=<xid>
|
||||
@ -692,13 +692,13 @@ START TRANSACTION
|
||||
#010909 4:46:40 server id # end_log_pos # Delete_rows: table id # flags: STMT_END_F
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=3 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### @1=1 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=2 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### DELETE FROM `test2`.`t2`
|
||||
### WHERE
|
||||
### @1=1 /* INT meta=0 nullable=1 is_null=0 */
|
||||
### @1=3 /* INT meta=0 nullable=1 is_null=0 */
|
||||
# Number of rows: 3
|
||||
# at #
|
||||
#010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 xid=<xid>
|
||||
|
@ -10,7 +10,7 @@ connection master;
|
||||
create table t1 (a int, b int, unique key (a), key (b))
|
||||
engine=federated CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
|
||||
insert into t1 values (3, 3), (7, 7);
|
||||
delete t1 from t1 where a = 3;
|
||||
delete t1 from t1 where b = 3;
|
||||
select * from t1;
|
||||
a b
|
||||
7 7
|
||||
|
@ -13,7 +13,7 @@ eval create table t1 (a int, b int, unique key (a), key (b))
|
||||
engine=federated CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
|
||||
|
||||
insert into t1 values (3, 3), (7, 7);
|
||||
delete t1 from t1 where a = 3;
|
||||
delete t1 from t1 where b = 3;
|
||||
select * from t1;
|
||||
drop table t1;
|
||||
|
||||
|
@ -69,6 +69,7 @@ wait/io/table/sql/handler TABLE test1 t2 update 1
|
||||
wait/io/table/sql/handler TABLE test marker insert 1
|
||||
wait/io/table/sql/handler TABLE test t1 fetch 1
|
||||
wait/io/table/sql/handler TABLE test1 t2 fetch 1
|
||||
wait/io/table/sql/handler TABLE test t1 fetch 1
|
||||
wait/io/table/sql/handler TABLE test t1 delete 1
|
||||
wait/io/table/sql/handler TABLE test1 t2 fetch 1
|
||||
wait/io/table/sql/handler TABLE test1 t2 delete 1
|
||||
|
@ -202,11 +202,8 @@ CREATE SEQUENCE s;
|
||||
CREATE table t1 (a int);
|
||||
insert into t1 values (1),(2);
|
||||
DELETE s FROM s;
|
||||
ERROR HY000: Storage engine SEQUENCE of the table `test`.`s` doesn't have this option
|
||||
delete t1,s from s,t1;
|
||||
ERROR HY000: Storage engine SEQUENCE of the table `test`.`s` doesn't have this option
|
||||
delete s,t1 from t1,s;
|
||||
ERROR HY000: Storage engine SEQUENCE of the table `test`.`s` doesn't have this option
|
||||
DROP SEQUENCE s;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
|
@ -177,11 +177,8 @@ drop sequence s1;
|
||||
CREATE SEQUENCE s;
|
||||
CREATE table t1 (a int);
|
||||
insert into t1 values (1),(2);
|
||||
--error ER_ILLEGAL_HA
|
||||
DELETE s FROM s;
|
||||
--error ER_ILLEGAL_HA
|
||||
delete t1,s from s,t1;
|
||||
--error ER_ILLEGAL_HA
|
||||
delete s,t1 from t1,s;
|
||||
DROP SEQUENCE s;
|
||||
DROP TABLE t1;
|
||||
|
@ -12292,5 +12292,8 @@ ER_VECTOR_FORMAT_INVALID
|
||||
eng "Invalid vector format at offset: %d for '%-.100s'. Must be a valid JSON array of numbers."
|
||||
ER_VEC_DISTANCE_TYPE
|
||||
eng "Cannot determine distance type for VEC_DISTANCE, index is not found"
|
||||
WARN_INDEX_HINTS_IGNORED
|
||||
eng "Index hints are ignored because they are incompatible with RETURNING clause"
|
||||
ukr "Підказки по використанню индексів ігноруются тому що вони несумісні з RETURNING"
|
||||
ER_SIGNAL_SKIP_ROW_FROM_TRIGGER
|
||||
eng "The row is skipped by a trigger implementation"
|
@ -7562,16 +7562,17 @@ class SORT_INFO;
|
||||
class multi_delete :public select_result_interceptor
|
||||
{
|
||||
TABLE_LIST *delete_tables, *table_being_deleted;
|
||||
TMP_TABLE_PARAM *tmp_table_param;
|
||||
TABLE **tmp_tables, *main_table;
|
||||
Unique **tempfiles;
|
||||
ha_rows deleted, found;
|
||||
uint num_of_tables;
|
||||
uint table_count;
|
||||
int error;
|
||||
bool do_delete;
|
||||
/* True if at least one table we delete from is transactional */
|
||||
bool transactional_tables;
|
||||
/* True if at least one table we delete from is not transactional */
|
||||
bool normal_tables;
|
||||
bool delete_while_scanning;
|
||||
/*
|
||||
error handling (rollback and binlogging) can happen in send_eof()
|
||||
so that afterward abort_result_set() needs to find out that.
|
||||
@ -7580,15 +7581,17 @@ class multi_delete :public select_result_interceptor
|
||||
|
||||
public:
|
||||
// Methods used by ColumnStore
|
||||
uint get_num_of_tables() const { return num_of_tables; }
|
||||
uint get_num_of_tables() const { return table_count; }
|
||||
TABLE_LIST* get_tables() const { return delete_tables; }
|
||||
public:
|
||||
multi_delete(THD *thd_arg, TABLE_LIST *dt, uint num_of_tables);
|
||||
~multi_delete();
|
||||
int prepare(List<Item> &list, SELECT_LEX_UNIT *u) override;
|
||||
int prepare2(JOIN *join) override;
|
||||
int send_data(List<Item> &items) override;
|
||||
bool initialize_tables (JOIN *join) override;
|
||||
int do_deletes();
|
||||
int rowid_table_deletes(TABLE *table, bool ignore);
|
||||
int do_table_deletes(TABLE *table, SORT_INFO *sort_info, bool ignore);
|
||||
bool send_eof() override;
|
||||
inline ha_rows num_deleted() const { return deleted; }
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "filesort.h"
|
||||
#include "uniques.h"
|
||||
#include "sql_derived.h" // mysql_handle_derived
|
||||
#include "key.h"
|
||||
// end_read_record
|
||||
#include "sql_insert.h" // fix_rownum_pointers
|
||||
#include "sql_partition.h" // make_used_partitions_str
|
||||
@ -1097,12 +1098,23 @@ extern "C" int refpos_order_cmp(void *arg, const void *a, const void *b)
|
||||
}
|
||||
|
||||
|
||||
multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, uint num_of_tables_arg):
|
||||
select_result_interceptor(thd_arg), delete_tables(dt), deleted(0), found(0),
|
||||
num_of_tables(num_of_tables_arg), error(0),
|
||||
do_delete(0), transactional_tables(0), normal_tables(0), error_handled(0)
|
||||
multi_delete::multi_delete(THD *thd_arg,
|
||||
TABLE_LIST *dt,
|
||||
uint num_of_tables_arg)
|
||||
: select_result_interceptor(thd_arg),
|
||||
delete_tables(dt),
|
||||
deleted(0),
|
||||
found(0),
|
||||
table_count(num_of_tables_arg),
|
||||
error(0),
|
||||
do_delete(0),
|
||||
transactional_tables(0),
|
||||
normal_tables(0),
|
||||
error_handled(0)
|
||||
{
|
||||
tempfiles= thd_arg->calloc<Unique*>(num_of_tables);
|
||||
tempfiles= thd_arg->calloc<Unique*>(table_count);
|
||||
tmp_tables = thd->calloc<TABLE*>(table_count);
|
||||
tmp_table_param = thd->calloc<TMP_TABLE_PARAM>(table_count);
|
||||
}
|
||||
|
||||
|
||||
@ -1116,6 +1128,59 @@ multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
static TABLE *item_rowid_table(Item *item)
|
||||
{
|
||||
if (item->type() != Item::FUNC_ITEM)
|
||||
return NULL;
|
||||
Item_func *func= (Item_func *)item;
|
||||
if (func->functype() != Item_func::TEMPTABLE_ROWID)
|
||||
return NULL;
|
||||
Item_temptable_rowid *itr= (Item_temptable_rowid *)func;
|
||||
return itr->table;
|
||||
}
|
||||
|
||||
/*
|
||||
multi_delete stores a rowid and new field values for every updated row in a
|
||||
temporary table (one temporary table per updated table). These rowids are
|
||||
obtained via Item_temptable_rowid's by calling handler::position(). But if
|
||||
the join is resolved via a temp table, rowids cannot be obtained from
|
||||
handler::position() in the multi_update::send_data(). So, they're stored in
|
||||
the join's temp table (JOIN::add_fields_for_current_rowid()) and here we
|
||||
replace Item_temptable_rowid's (that would've done handler::position()) with
|
||||
Item_field's (that will simply take the corresponding field value from the
|
||||
temp table).
|
||||
*/
|
||||
int multi_delete::prepare2(JOIN *join)
|
||||
{
|
||||
if (!join->need_tmp || !join->tmp_table_keep_current_rowid)
|
||||
return 0;
|
||||
|
||||
JOIN_TAB *tmptab= join->join_tab + join->exec_join_tab_cnt();
|
||||
|
||||
for (Item **it= tmptab->tmp_table_param->items_to_copy; *it ; it++)
|
||||
{
|
||||
TABLE *tbl= item_rowid_table(*it);
|
||||
if (!tbl)
|
||||
continue;
|
||||
for (uint i= 0; i < table_count; i++)
|
||||
{
|
||||
for (Item **it2= tmp_table_param[i].items_to_copy; *it2; it2++)
|
||||
{
|
||||
if (item_rowid_table(*it2) != tbl)
|
||||
continue;
|
||||
Item_field *fld= new (thd->mem_root)
|
||||
Item_field(thd, (*it)->get_tmp_table_field());
|
||||
if (!fld)
|
||||
return 1;
|
||||
fld->result_field= (*it2)->get_tmp_table_field();
|
||||
*it2= fld;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void multi_delete::prepare_to_read_rows()
|
||||
{
|
||||
/* see multi_update::prepare_to_read_rows() */
|
||||
@ -1136,9 +1201,9 @@ multi_delete::initialize_tables(JOIN *join)
|
||||
if (unlikely((thd->variables.option_bits & OPTION_SAFE_UPDATES) &&
|
||||
error_if_full_join(join)))
|
||||
DBUG_RETURN(1);
|
||||
main_table=join->join_tab->table;
|
||||
|
||||
table_map tables_to_delete_from=0;
|
||||
delete_while_scanning= true;
|
||||
for (walk= delete_tables; walk; walk= walk->next_local)
|
||||
{
|
||||
TABLE_LIST *tbl= walk->correspondent_table->find_table_for_update();
|
||||
@ -1149,21 +1214,10 @@ multi_delete::initialize_tables(JOIN *join)
|
||||
delete is called.
|
||||
*/
|
||||
join->map2table[tbl->table->tablenr]->keep_current_rowid= true;
|
||||
|
||||
if (delete_while_scanning &&
|
||||
unique_table(thd, tbl, join->tables_list, 0))
|
||||
{
|
||||
/*
|
||||
If the table we are going to delete from appears
|
||||
in join, we need to defer delete. So the delete
|
||||
doesn't interfers with the scaning of results.
|
||||
*/
|
||||
delete_while_scanning= false;
|
||||
}
|
||||
}
|
||||
|
||||
walk= delete_tables;
|
||||
|
||||
uint index= 0;
|
||||
for (JOIN_TAB *tab= first_linear_tab(join, WITHOUT_BUSH_ROOTS,
|
||||
WITH_CONST_TABLES);
|
||||
tab;
|
||||
@ -1173,6 +1227,7 @@ multi_delete::initialize_tables(JOIN *join)
|
||||
{
|
||||
/* We are going to delete from this table */
|
||||
TABLE *tbl=walk->table=tab->table;
|
||||
TABLE_LIST *prior= walk;
|
||||
walk= walk->next_local;
|
||||
/* Don't use KEYREAD optimization on this table */
|
||||
tbl->no_keyread=1;
|
||||
@ -1186,25 +1241,41 @@ multi_delete::initialize_tables(JOIN *join)
|
||||
tbl->prepare_triggers_for_delete_stmt_or_event();
|
||||
tbl->prepare_for_position();
|
||||
tbl->file->prepare_for_modify(tbl->versioned(VERS_TIMESTAMP), true);
|
||||
}
|
||||
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= false;
|
||||
|
||||
List<Item> temp_fields;
|
||||
tbl->prepare_for_position();
|
||||
join->map2table[tbl->tablenr]->keep_current_rowid= true;
|
||||
Item_temptable_rowid *item=
|
||||
new (thd->mem_root) Item_temptable_rowid(tbl);
|
||||
if (!item)
|
||||
DBUG_RETURN(1);
|
||||
item->fix_fields(thd, 0);
|
||||
if (temp_fields.push_back(item, thd->mem_root))
|
||||
DBUG_RETURN(1);
|
||||
/* Make an unique key over the first field to avoid duplicated updates */
|
||||
ORDER group;
|
||||
bzero((char*) &group, sizeof(group));
|
||||
group.direction= ORDER::ORDER_ASC;
|
||||
group.item= (Item**) temp_fields.head_ref();
|
||||
TMP_TABLE_PARAM *tmp_param;
|
||||
prior->shared = index;
|
||||
tmp_param= &tmp_table_param[prior->shared];
|
||||
tmp_param->init();
|
||||
tmp_param->tmp_name="update";
|
||||
tmp_param->field_count= temp_fields.elements;
|
||||
tmp_param->func_count= temp_fields.elements;
|
||||
calc_group_buffer(tmp_param, &group);
|
||||
tmp_tables[index]=create_tmp_table(thd, tmp_param, temp_fields,
|
||||
(ORDER*) &group, 0, 0,
|
||||
TMP_TABLE_ALL_COLUMNS, HA_POS_ERROR, &empty_clex_str);
|
||||
if (!tmp_tables[index])
|
||||
DBUG_RETURN(1);
|
||||
tmp_tables[index]->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
walk= delete_tables;
|
||||
tempfiles_ptr= tempfiles;
|
||||
if (delete_while_scanning)
|
||||
{
|
||||
table_being_deleted= delete_tables;
|
||||
walk= walk->next_local;
|
||||
}
|
||||
for (;walk ;walk= walk->next_local)
|
||||
{
|
||||
TABLE *table=walk->table;
|
||||
@ -1215,6 +1286,7 @@ multi_delete::initialize_tables(JOIN *join)
|
||||
if (init_ftfuncs(thd, thd->lex->current_select, 1))
|
||||
DBUG_RETURN(true);
|
||||
|
||||
join->tmp_table_keep_current_rowid= TRUE;
|
||||
DBUG_RETURN(thd->is_fatal_error);
|
||||
}
|
||||
|
||||
@ -1232,81 +1304,68 @@ multi_delete::~multi_delete()
|
||||
table->no_cache= 0;
|
||||
}
|
||||
|
||||
for (uint counter= 0; counter < num_of_tables; counter++)
|
||||
for (uint counter= 0; counter < table_count; counter++)
|
||||
{
|
||||
if (tempfiles[counter])
|
||||
delete tempfiles[counter];
|
||||
}
|
||||
|
||||
if (tmp_tables)
|
||||
{
|
||||
for (uint cnt = 0; cnt < table_count; cnt++)
|
||||
{
|
||||
if (tmp_tables[cnt])
|
||||
{
|
||||
free_tmp_table(thd, tmp_tables[cnt]);
|
||||
tmp_table_param[cnt].cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int multi_delete::send_data(List<Item> &values)
|
||||
{
|
||||
int secure_counter= delete_while_scanning ? -1 : 0;
|
||||
TABLE_LIST *del_table;
|
||||
DBUG_ENTER("multi_delete::send_data");
|
||||
|
||||
bool ignore= thd->lex->ignore;
|
||||
|
||||
for (del_table= delete_tables;
|
||||
del_table;
|
||||
del_table= del_table->next_local, secure_counter++)
|
||||
del_table= del_table->next_local)
|
||||
{
|
||||
TABLE *table= del_table->table;
|
||||
// DELETE and TRUNCATE don't affect SEQUENCE, so bail early
|
||||
if (table->file->ht->db_type == DB_TYPE_SEQUENCE)
|
||||
continue;
|
||||
|
||||
/* Check if we are using outer join and we didn't find the row */
|
||||
if (table->status & (STATUS_NULL_ROW | STATUS_DELETED))
|
||||
continue;
|
||||
|
||||
table->file->position(table->record[0]);
|
||||
found++;
|
||||
|
||||
if (secure_counter < 0)
|
||||
{
|
||||
bool trg_skip_row= false;
|
||||
|
||||
/* 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,
|
||||
&trg_skip_row))
|
||||
const uint offset= del_table->shared;
|
||||
TABLE *tmp_table= tmp_tables[offset];
|
||||
if (copy_funcs(tmp_table_param[offset].items_to_copy, thd))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (trg_skip_row)
|
||||
/* rowid field is NULL if join tmp table has null row from outer join */
|
||||
if (tmp_table->field[0]->is_null())
|
||||
continue;
|
||||
|
||||
table->status|= STATUS_DELETED;
|
||||
|
||||
error= table->delete_row();
|
||||
if (likely(!error))
|
||||
error= tmp_table->file->ha_write_tmp_row(tmp_table->record[0]);
|
||||
if (error)
|
||||
{
|
||||
deleted++;
|
||||
if (!table->file->has_transactions())
|
||||
thd->transaction->stmt.modified_non_trans_table= TRUE;
|
||||
if (table->triggers &&
|
||||
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
|
||||
TRG_ACTION_AFTER, false,
|
||||
nullptr))
|
||||
DBUG_RETURN(1);
|
||||
--found;
|
||||
if (error != HA_ERR_FOUND_DUPP_KEY &&
|
||||
error != HA_ERR_FOUND_DUPP_UNIQUE)
|
||||
{
|
||||
if (create_internal_tmp_table_from_heap(thd, tmp_table,
|
||||
tmp_table_param[offset].start_recinfo,
|
||||
&tmp_table_param[offset].recinfo,
|
||||
error, 1, NULL))
|
||||
{
|
||||
do_delete= 0;
|
||||
DBUG_RETURN(1); // Not a table_is_full error
|
||||
}
|
||||
else if (!ignore)
|
||||
{
|
||||
/*
|
||||
If the IGNORE option is used errors caused by ha_delete_row don't
|
||||
have to stop the iteration.
|
||||
*/
|
||||
table->file->print_error(error,MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error=tempfiles[secure_counter]->unique_add((char*) table->file->ref);
|
||||
if (unlikely(error))
|
||||
{
|
||||
error= 1; // Fatal error
|
||||
DBUG_RETURN(1);
|
||||
found++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1393,19 +1452,21 @@ int multi_delete::do_deletes()
|
||||
if (!found)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
table_being_deleted= (delete_while_scanning ? delete_tables->next_local :
|
||||
delete_tables);
|
||||
table_being_deleted= delete_tables;
|
||||
|
||||
for (uint counter= 0; table_being_deleted;
|
||||
table_being_deleted= table_being_deleted->next_local, counter++)
|
||||
{
|
||||
TABLE *table = table_being_deleted->table;
|
||||
// DELETE and TRUNCATE don't affect SEQUENCE, so bail early
|
||||
if (table->file->ht->db_type == DB_TYPE_SEQUENCE)
|
||||
continue;
|
||||
|
||||
int local_error;
|
||||
if (unlikely(tempfiles[counter]->get(table)))
|
||||
if (tempfiles[counter] && unlikely(tempfiles[counter]->get(table)))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
local_error= do_table_deletes(table, &tempfiles[counter]->sort,
|
||||
thd->lex->ignore);
|
||||
local_error= rowid_table_deletes(table, thd->lex->ignore);
|
||||
|
||||
if (unlikely(thd->killed) && likely(!local_error))
|
||||
DBUG_RETURN(1);
|
||||
@ -1435,35 +1496,60 @@ int multi_delete::do_deletes()
|
||||
@retval 1 Triggers or handler reported error.
|
||||
@retval -1 End of file from handler.
|
||||
*/
|
||||
int multi_delete::do_table_deletes(TABLE *table, SORT_INFO *sort_info,
|
||||
bool ignore)
|
||||
int multi_delete::rowid_table_deletes(TABLE *table, bool ignore)
|
||||
{
|
||||
int local_error= 0;
|
||||
READ_RECORD info;
|
||||
ha_rows last_deleted= deleted;
|
||||
DBUG_ENTER("do_deletes_for_table");
|
||||
|
||||
if (unlikely(init_read_record(&info, thd, table, NULL, sort_info, 0, 1,
|
||||
FALSE)))
|
||||
DBUG_RETURN(1);
|
||||
DBUG_ENTER("rowid_table_deletes");
|
||||
TABLE *err_table= nullptr;
|
||||
|
||||
bool will_batch= !table->file->start_bulk_delete();
|
||||
while (likely(!(local_error= info.read_record())) && likely(!thd->killed))
|
||||
TABLE *tmp_table= tmp_tables[table_being_deleted->shared];
|
||||
tmp_table->file->extra(HA_EXTRA_CACHE); // Change to read cache
|
||||
if (unlikely((local_error= table->file->ha_rnd_init(0))))
|
||||
{
|
||||
bool trg_skip_row= false;
|
||||
err_table= table;
|
||||
goto err;
|
||||
}
|
||||
table->file->extra(HA_EXTRA_NO_CACHE);
|
||||
if (unlikely((local_error= tmp_table->file->ha_rnd_init(1))))
|
||||
{
|
||||
err_table= tmp_table;
|
||||
goto err;
|
||||
}
|
||||
|
||||
while (!thd->killed)
|
||||
{
|
||||
if (unlikely((local_error=
|
||||
tmp_table->file->ha_rnd_next(tmp_table->record[0]))))
|
||||
{
|
||||
if (local_error == HA_ERR_END_OF_FILE)
|
||||
{
|
||||
local_error= 0;
|
||||
break;
|
||||
}
|
||||
err_table= tmp_table;
|
||||
goto err;
|
||||
}
|
||||
|
||||
DBUG_ASSERT(!tmp_table->field[0]->is_null());
|
||||
String rowid;
|
||||
tmp_table->field[0]->val_str(&rowid);
|
||||
if (unlikely((local_error= table->file->ha_rnd_pos(table->record[0],
|
||||
(uchar*)rowid.ptr()))))
|
||||
{
|
||||
// Table aliased to itself had key deleted already
|
||||
continue;
|
||||
}
|
||||
|
||||
if (table->triggers &&
|
||||
unlikely(table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
|
||||
TRG_ACTION_BEFORE, false,
|
||||
&trg_skip_row)))
|
||||
TRG_ACTION_BEFORE, FALSE)))
|
||||
{
|
||||
err_table= table;
|
||||
local_error= 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (trg_skip_row)
|
||||
continue;
|
||||
|
||||
local_error= table->delete_row();
|
||||
if (unlikely(local_error) && !ignore)
|
||||
{
|
||||
@ -1481,9 +1567,9 @@ int multi_delete::do_table_deletes(TABLE *table, SORT_INFO *sort_info,
|
||||
deleted++;
|
||||
if (table->triggers &&
|
||||
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
|
||||
TRG_ACTION_AFTER, false,
|
||||
nullptr))
|
||||
TRG_ACTION_AFTER, FALSE))
|
||||
{
|
||||
err_table= table;
|
||||
local_error= 1;
|
||||
break;
|
||||
}
|
||||
@ -1500,12 +1586,13 @@ int multi_delete::do_table_deletes(TABLE *table, SORT_INFO *sort_info,
|
||||
}
|
||||
if (last_deleted != deleted && !table->file->has_transactions_and_rollback())
|
||||
thd->transaction->stmt.modified_non_trans_table= TRUE;
|
||||
|
||||
end_read_record(&info);
|
||||
|
||||
err:
|
||||
if (err_table)
|
||||
err_table->file->print_error(local_error,MYF(ME_FATAL));
|
||||
DBUG_RETURN(local_error);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Send ok to the client
|
||||
|
||||
@ -1564,9 +1651,20 @@ bool multi_delete::send_eof()
|
||||
}
|
||||
}
|
||||
if (unlikely(local_error != 0))
|
||||
{
|
||||
error_handled= TRUE; // to force early leave from ::abort_result_set()
|
||||
if (thd->killed == NOT_KILLED && !thd->get_stmt_da()->is_set())
|
||||
{
|
||||
/*
|
||||
No error message was sent and query was not killed (in which case
|
||||
mysql_execute_command() will send the error mesage).
|
||||
*/
|
||||
::my_ok(thd, deleted); // Ends the DELETE statement
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (likely(!local_error && !thd->lex->analyze_stmt))
|
||||
if (likely(!thd->lex->analyze_stmt))
|
||||
{
|
||||
::my_ok(thd, deleted);
|
||||
}
|
||||
@ -1600,11 +1698,8 @@ void Sql_cmd_delete::remove_order_by_without_limit(THD *thd)
|
||||
|
||||
bool Sql_cmd_delete::processing_as_multitable_delete_prohibited(THD *thd)
|
||||
{
|
||||
SELECT_LEX *const select_lex = thd->lex->first_select_lex();
|
||||
return
|
||||
((select_lex->order_list.elements &&
|
||||
select_lex->limit_params.select_limit) ||
|
||||
thd->lex->has_returning());
|
||||
(thd->lex->has_returning());
|
||||
}
|
||||
|
||||
|
||||
@ -1714,6 +1809,19 @@ bool Sql_cmd_delete::prepare_inner(THD *thd)
|
||||
|
||||
if (!multitable)
|
||||
{
|
||||
if (select_lex->index_hints || table_list->index_hints)
|
||||
{
|
||||
if (!processing_as_multitable_delete_prohibited(thd))
|
||||
{
|
||||
multitable= true;
|
||||
}
|
||||
else
|
||||
{
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
WARN_INDEX_HINTS_IGNORED,
|
||||
ER_THD(thd, WARN_INDEX_HINTS_IGNORED));
|
||||
}
|
||||
}
|
||||
if (table_list->vers_conditions.is_set() && table_list->is_view_or_derived())
|
||||
{
|
||||
my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str);
|
||||
|
@ -1764,6 +1764,7 @@ rule:
|
||||
query_expression_tail
|
||||
opt_query_expression_tail
|
||||
order_or_limit
|
||||
opt_order_or_limit
|
||||
order_limit_lock
|
||||
opt_order_limit_lock
|
||||
|
||||
@ -13005,6 +13006,18 @@ opt_procedure_or_into:
|
||||
}
|
||||
;
|
||||
|
||||
opt_order_or_limit:
|
||||
/* empty */
|
||||
{
|
||||
$$= NULL;
|
||||
}
|
||||
|
|
||||
order_or_limit
|
||||
{
|
||||
$1->lock.empty();
|
||||
$$= $1;
|
||||
}
|
||||
;
|
||||
|
||||
order_or_limit:
|
||||
order_clause opt_limit_clause
|
||||
@ -13997,7 +14010,7 @@ delete_part2:
|
||||
;
|
||||
|
||||
delete_single_table:
|
||||
FROM table_ident opt_table_alias_clause opt_use_partition
|
||||
FROM table_ident opt_table_alias_clause opt_key_definition opt_use_partition
|
||||
{
|
||||
if (unlikely(!Select->
|
||||
add_table_to_list(thd, $2, $3, TL_OPTION_UPDATING,
|
||||
@ -14016,8 +14029,8 @@ delete_single_table:
|
||||
add_table_to_list(thd, $2, $3, TL_OPTION_UPDATING,
|
||||
YYPS->m_lock_type,
|
||||
YYPS->m_mdl_type,
|
||||
NULL,
|
||||
$4)))
|
||||
Select->pop_index_hints(),
|
||||
$5)))
|
||||
MYSQL_YYABORT;
|
||||
Lex->auxiliary_table_list.first->correspondent_table=
|
||||
Lex->query_tables;
|
||||
@ -14063,10 +14076,15 @@ single_multi:
|
||||
YYPS->m_lock_type= TL_READ_DEFAULT;
|
||||
YYPS->m_mdl_type= MDL_SHARED_READ;
|
||||
}
|
||||
FROM join_table_list opt_where_clause
|
||||
FROM join_table_list opt_where_clause opt_order_or_limit
|
||||
{
|
||||
if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex)))
|
||||
MYSQL_YYABORT;
|
||||
if ($6)
|
||||
{
|
||||
DBUG_ASSERT(Lex->select_stack_head() == Select);
|
||||
$6->set_to(Lex->select_stack_head());
|
||||
}
|
||||
} stmt_end {}
|
||||
| FROM table_alias_ref_list
|
||||
{
|
||||
@ -14079,10 +14097,15 @@ single_multi:
|
||||
YYPS->m_lock_type= TL_READ_DEFAULT;
|
||||
YYPS->m_mdl_type= MDL_SHARED_READ;
|
||||
}
|
||||
USING join_table_list opt_where_clause
|
||||
USING join_table_list opt_where_clause opt_order_or_limit
|
||||
{
|
||||
if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex)))
|
||||
MYSQL_YYABORT;
|
||||
if ($7)
|
||||
{
|
||||
DBUG_ASSERT(Lex->select_stack_head() == Select);
|
||||
$7->set_to(Lex->select_stack_head());
|
||||
}
|
||||
} stmt_end {}
|
||||
;
|
||||
|
||||
|
Reference in New Issue
Block a user