1
0
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:
Dave Gosselin
2024-12-03 09:43:45 -05:00
parent 02dc8615f2
commit 5001300bd4
22 changed files with 915 additions and 192 deletions

View File

@ -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
#

View File

@ -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 #

View File

@ -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

View 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;

View 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;

View File

@ -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));

View File

@ -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

View 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

View 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;

View File

@ -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;

View File

@ -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)

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;
#

View File

@ -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;

View File

@ -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"

View File

@ -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; }

View File

@ -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);

View File

@ -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 {}
;