Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions mysql-test/main/derived_view.result
Original file line number Diff line number Diff line change
Expand Up @@ -4430,3 +4430,97 @@ deallocate prepare stmt;
drop view v1,v2;
drop table t1,t2;
# End of 10.6 tests
#
# Beginning of 10.11 tests
#
#
# MDEV-37020: derived table not merged in multi-table DELETE/UPDATE
# while equivalent SELECT and view-based form do merge
#
create table t1 (a int, b int);
insert into t1 select seq, seq from seq_1_to_10;
create table t2 (a int, b int);
insert into t2 select seq, seq from seq_1_to_10;
create table t3 (a int, b int);
insert into t3 select seq, seq from seq_1_to_10;
# Baseline: equivalent SELECT merges the derived table.
explain select * from t1, (select t2.b as b1 from t2, t3 where t3.a=t2.a and t2.a<5) dt
where t1.b+1=1+dt.b1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10
1 SIMPLE t2 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join)
1 SIMPLE t3 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (incremental, BNL join)
# Multitable DELETE must merge the derived table.
explain delete t1.* from t1, (select t2.b as b1 from t2, t3 where t3.a=t2.a) dt
where t1.b+1=1+dt.b1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10
1 SIMPLE t2 ALL NULL NULL NULL NULL 10 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 10 Using where
# Multitable UPDATE must merge the derived table.
explain update t1, (select t2.b as b1 from t2, t3 where t3.a=t2.a) dt
set t1.a=t1.a+1 where t1.b+1=1+dt.b1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10
1 SIMPLE t2 ALL NULL NULL NULL NULL 10 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 10 Using where
# VIEW form already merged the derived table before this fix, verify.
create view v1 as select t2.b as b1 from t2, t3 where t3.a=t2.a;
select t1.* from t1, v1 where t1.b+1=1+v1.b1;
a b
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
explain select t1.* from t1, v1 where t1.b+1=1+v1.b1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10
1 SIMPLE t2 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join)
1 SIMPLE t3 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (incremental, BNL join)
explain delete t1.* from t1, v1 where t1.b+1=1+v1.b1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10
1 SIMPLE t2 ALL NULL NULL NULL NULL 10 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 10 Using where
explain update t1, v1 set t1.a=t1.a+1 where t1.b+1=1+v1.b1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10
1 SIMPLE t2 ALL NULL NULL NULL NULL 10 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 10 Using where
# Confirm queries still produce the correct results.
select t1.* from t1, (select t2.b as b1 from t2, t3 where t3.a=t2.a and t2.a<5) dt
where t1.b+1=1+dt.b1;
a b
1 1
2 2
3 3
4 4
delete t1.* from t1, (select t2.b as b1 from t2, t3 where t3.a=t2.a and t2.a<5) dt2
where t1.b=dt2.b1;
select * from t1 order by a;
a b
5 5
6 6
7 7
8 8
9 9
10 10
update t1, (select t2.b as b1 from t2, t3 where t3.a=t2.a and t2.a>7) dt2
set t1.a=t1.a*100 where t1.b=dt2.b1;
select * from t1 order by b;
a b
5 5
6 6
7 7
800 8
900 9
1000 10
drop view v1;
drop table t1, t2, t3;
# End of 10.11 tests
51 changes: 51 additions & 0 deletions mysql-test/main/derived_view.test
Original file line number Diff line number Diff line change
Expand Up @@ -2940,3 +2940,54 @@ drop view v1,v2;
drop table t1,t2;

--echo # End of 10.6 tests


--echo #
--echo # Beginning of 10.11 tests
--echo #

--echo #
--echo # MDEV-37020: derived table not merged in multi-table DELETE/UPDATE
--echo # while equivalent SELECT and view-based form do merge
--echo #

create table t1 (a int, b int);
insert into t1 select seq, seq from seq_1_to_10;
create table t2 (a int, b int);
insert into t2 select seq, seq from seq_1_to_10;
create table t3 (a int, b int);
insert into t3 select seq, seq from seq_1_to_10;

--echo # Baseline: equivalent SELECT merges the derived table.
explain select * from t1, (select t2.b as b1 from t2, t3 where t3.a=t2.a and t2.a<5) dt
where t1.b+1=1+dt.b1;

--echo # Multitable DELETE must merge the derived table.
explain delete t1.* from t1, (select t2.b as b1 from t2, t3 where t3.a=t2.a) dt
where t1.b+1=1+dt.b1;

--echo # Multitable UPDATE must merge the derived table.
explain update t1, (select t2.b as b1 from t2, t3 where t3.a=t2.a) dt
set t1.a=t1.a+1 where t1.b+1=1+dt.b1;

--echo # VIEW form already merged the derived table before this fix, verify.
create view v1 as select t2.b as b1 from t2, t3 where t3.a=t2.a;
select t1.* from t1, v1 where t1.b+1=1+v1.b1;
explain select t1.* from t1, v1 where t1.b+1=1+v1.b1;
explain delete t1.* from t1, v1 where t1.b+1=1+v1.b1;
explain update t1, v1 set t1.a=t1.a+1 where t1.b+1=1+v1.b1;

--echo # Confirm queries still produce the correct results.
select t1.* from t1, (select t2.b as b1 from t2, t3 where t3.a=t2.a and t2.a<5) dt
where t1.b+1=1+dt.b1;
delete t1.* from t1, (select t2.b as b1 from t2, t3 where t3.a=t2.a and t2.a<5) dt2
where t1.b=dt2.b1;
select * from t1 order by a;
update t1, (select t2.b as b1 from t2, t3 where t3.a=t2.a and t2.a>7) dt2
set t1.a=t1.a*100 where t1.b=dt2.b1;
select * from t1 order by b;

drop view v1;
drop table t1, t2, t3;

--echo # End of 10.11 tests
3 changes: 0 additions & 3 deletions mysql-test/main/multi_update.result
Original file line number Diff line number Diff line change
Expand Up @@ -585,9 +585,6 @@ INSERT INTO t3 VALUES (1), (2);
UPDATE IGNORE
( SELECT ( SELECT COUNT(*) FROM t1 GROUP BY a, @v ) a FROM t2 ) x, t3
SET t3.a = 0;
Warnings:
Warning 1242 Subquery returns more than 1 row
Warning 1242 Subquery returns more than 1 row
DROP TABLE t1, t2, t3;
SET SESSION sql_safe_updates = DEFAULT;
#
Expand Down
50 changes: 21 additions & 29 deletions mysql-test/main/myisam_explain_non_select_all.result
Original file line number Diff line number Diff line change
Expand Up @@ -198,18 +198,16 @@ Warnings:
Warning 1287 '<select expression> INTO <destination>;' is deprecated and will be removed in a future release. Please use 'SELECT <select list> INTO <destination> FROM...' instead
EXPLAIN UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = 10 WHERE t11.a = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t11 ALL NULL NULL NULL NULL 3 Using where
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3
2 DERIVED t2 ALL NULL NULL NULL NULL 3
1 SIMPLE t11 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
FLUSH STATUS;
FLUSH TABLES;
EXPLAIN EXTENDED UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = 10 WHERE t11.a = 1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t11 ALL NULL NULL NULL NULL 3 100.00 Using where
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3 100.00
2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00
1 SIMPLE t11 ALL NULL NULL NULL NULL 3 100.00 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1003 /* select#1 */ update `test`.`t1` `t11` join (/* select#2 */ select `test`.`t2`.`b` AS `b` from `test`.`t2`) `t12` set `test`.`t11`.`a` = 10 where `test`.`t11`.`a` = 1
Note 1003 update `test`.`t1` `t11` join `test`.`t2` set `test`.`t11`.`a` = 10 where `test`.`t11`.`a` = 1
# Status of EXPLAIN EXTENDED query
Variable_name Value
Handler_read_key 4
Expand All @@ -233,7 +231,7 @@ Handler_read_rnd_next 8
# Status of testing query execution:
Variable_name Value
Handler_read_key 4
Handler_read_rnd_next 12
Handler_read_rnd_next 8
Handler_update 1

DROP TABLE t1, t2;
Expand Down Expand Up @@ -410,18 +408,16 @@ Warnings:
Warning 1287 '<select expression> INTO <destination>;' is deprecated and will be removed in a future release. Please use 'SELECT <select list> INTO <destination> FROM...' instead
EXPLAIN UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = t11.a + 10;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t11 ALL NULL NULL NULL NULL 3
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3
2 DERIVED t2 ALL NULL NULL NULL NULL 3
1 SIMPLE t11 ALL NULL NULL NULL NULL 3
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
FLUSH STATUS;
FLUSH TABLES;
EXPLAIN EXTENDED UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = t11.a + 10;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t11 ALL NULL NULL NULL NULL 3 100.00
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3 100.00
2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00
1 SIMPLE t11 ALL NULL NULL NULL NULL 3 100.00
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1003 /* select#1 */ update `test`.`t1` `t11` join (/* select#2 */ select `test`.`t2`.`b` AS `b` from `test`.`t2`) `t12` set `test`.`t11`.`a` = `test`.`t11`.`a` + 10
Note 1003 update `test`.`t1` `t11` join `test`.`t2` set `test`.`t11`.`a` = `test`.`t11`.`a` + 10
# Status of EXPLAIN EXTENDED query
Variable_name Value
Handler_read_key 4
Expand All @@ -447,7 +443,7 @@ Variable_name Value
Handler_read_key 4
Handler_read_rnd 3
Handler_read_rnd_deleted 1
Handler_read_rnd_next 24
Handler_read_rnd_next 20
Handler_update 3

DROP TABLE t1, t2;
Expand Down Expand Up @@ -520,18 +516,16 @@ Warnings:
Warning 1287 '<select expression> INTO <destination>;' is deprecated and will be removed in a future release. Please use 'SELECT <select list> INTO <destination> FROM...' instead
EXPLAIN UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = 10 WHERE t11.a > 1;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t11 ALL NULL NULL NULL NULL 3 Using where
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3
2 DERIVED t2 ALL NULL NULL NULL NULL 3
1 SIMPLE t11 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
FLUSH STATUS;
FLUSH TABLES;
EXPLAIN EXTENDED UPDATE t1 t11, (SELECT * FROM t2) t12 SET t11.a = 10 WHERE t11.a > 1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t11 ALL NULL NULL NULL NULL 3 100.00 Using where
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3 100.00
2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00
1 SIMPLE t11 ALL NULL NULL NULL NULL 3 100.00 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1003 /* select#1 */ update `test`.`t1` `t11` join (/* select#2 */ select `test`.`t2`.`b` AS `b` from `test`.`t2`) `t12` set `test`.`t11`.`a` = 10 where `test`.`t11`.`a` > 1
Note 1003 update `test`.`t1` `t11` join `test`.`t2` set `test`.`t11`.`a` = 10 where `test`.`t11`.`a` > 1
# Status of EXPLAIN EXTENDED query
Variable_name Value
Handler_read_key 4
Expand All @@ -555,7 +549,7 @@ Handler_read_rnd_next 8
# Status of testing query execution:
Variable_name Value
Handler_read_key 4
Handler_read_rnd_next 16
Handler_read_rnd_next 12
Handler_update 2

DROP TABLE t1, t2;
Expand Down Expand Up @@ -3409,20 +3403,18 @@ EXPLAIN UPDATE t1, (SELECT * FROM t2) y SET a = 10 WHERE a IN (SELECT * F
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
1 PRIMARY <derived4> ref key0 key0 5 test.t1.a 2 FirstMatch(t1)
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3
1 PRIMARY t2 ALL NULL NULL NULL NULL 3
4 DERIVED t2 ALL NULL NULL NULL NULL 3 Using filesort
2 DERIVED t2 ALL NULL NULL NULL NULL 3
FLUSH STATUS;
FLUSH TABLES;
EXPLAIN EXTENDED UPDATE t1, (SELECT * FROM t2) y SET a = 10 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
1 PRIMARY <derived4> ref key0 key0 5 test.t1.a 2 100.00 FirstMatch(t1)
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3 100.00
1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00
4 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 Using filesort
2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1003 /* select#1 */ update `test`.`t1` semi join ((/* select#4 */ select `test`.`t2`.`b` AS `b` from `test`.`t2` order by `test`.`t2`.`b` limit 2,2) `x`) join (/* select#2 */ select `test`.`t2`.`b` AS `b` from `test`.`t2`) `y` set `test`.`t1`.`a` = 10 where `x`.`b` = `test`.`t1`.`a`
Note 1003 /* select#1 */ update `test`.`t1` semi join ((/* select#4 */ select `test`.`t2`.`b` AS `b` from `test`.`t2` order by `test`.`t2`.`b` limit 2,2) `x`) join `test`.`t2` set `test`.`t1`.`a` = 10 where `x`.`b` = `test`.`t1`.`a`
# Status of EXPLAIN EXTENDED query
Variable_name Value
Handler_read_key 4
Expand Down
13 changes: 13 additions & 0 deletions sql/sql_update.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1733,6 +1733,19 @@ static bool multi_update_check_table_access(THD *thd, TABLE_LIST *table,
}
else
{
/*
A merged derived table that is not a VIEW has no TABLE* so we
can't check privileges on it here. Besides, the privileges for
the underlying base tables are already checked by
multi_update_precheck.

Without this guard, the main.lock_multi_bug38499 test will crash
just below when running a prepared statement that is made from an
UPDATE.
*/
if (table->is_merged_derived())
return false;

/* Must be a base or derived table. */
const bool updated= table->table->map & tables_for_update;
if (check_table_access(thd, updated ? UPDATE_ACL : SELECT_ACL, table,
Expand Down
8 changes: 7 additions & 1 deletion sql/table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9903,8 +9903,14 @@ bool TABLE_LIST::init_derived(THD *thd, bool init_view)
(is_view() ||
optimizer_flag(thd, OPTIMIZER_SWITCH_DERIVED_MERGE)) &&
!thd->lex->can_not_use_merged() &&
/*
Allow merged derived optimization for multitable DELETE and
UPDATE, but with one exception: if this derived table is
itself within a VIEW, then don't allow it to be merged.
*/
!((thd->lex->sql_command == SQLCOM_UPDATE_MULTI ||
thd->lex->sql_command == SQLCOM_DELETE_MULTI) && !is_view()) &&
thd->lex->sql_command == SQLCOM_DELETE_MULTI) &&
!is_view() && belong_to_view) &&
!is_recursive_with_table())
set_merged_derived();
else
Expand Down