diff --git a/mysql-test/main/multi_update.result b/mysql-test/main/multi_update.result index 2364ee732ce..1a87ec16b94 100644 --- a/mysql-test/main/multi_update.result +++ b/mysql-test/main/multi_update.result @@ -1384,3 +1384,279 @@ c1 c2 c3 12 5 8 drop table t1,t2,t3,t; # End of 10.4 tests +# +# MDEV-31150: 2nd execution of multi-update with +# mergeable derived table in WHERE +# +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (3),(7),(1),(3); +CREATE TABLE t2 (b int); +INSERT INTO t2 VALUES (3),(4),(1); +CREATE TABLE t3 (c int); +INSERT INTO t3 VALUES (3),(4),(1),(5),(1); +CREATE PROCEDURE restore_t1() +BEGIN +DELETE FROM t1; +INSERT INTO t1 VALUES (3),(7),(1),(3); +END| +SELECT * FROM t1; +a +3 +7 +1 +3 +EXPLAIN UPDATE t1,t3 SET a = NULL +WHERE a=c AND a IN (SELECT * FROM (SELECT b FROM t2) dt); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 Using where; FirstMatch(t1) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 Using where +UPDATE t1,t3 SET a = NULL +WHERE a=c AND a IN (SELECT * FROM (SELECT b FROM t2) dt); +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +PREPARE stmt FROM "UPDATE t1,t3 SET a = NULL +WHERE a=c AND a IN (SELECT * FROM (SELECT b FROM t2) dt)"; +EXECUTE stmt; +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +EXECUTE stmt; +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +DEALLOCATE PREPARE stmt; +CREATE PROCEDURE p1() UPDATE t1,t3 SET a = NULL +WHERE a=c AND a IN (SELECT * FROM (SELECT b FROM t2) dt); +SELECT * FROM t1; +a +3 +7 +1 +3 +CALL p1(); +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +CALL p1(); +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +DROP procedure p1; +SELECT * FROM t1; +a +3 +7 +1 +3 +EXPLAIN UPDATE t1,t3 SET a = NULL +WHERE a=c AND a IN (WITH cte AS (SELECT b FROM t2) SELECT * FROM cte); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 Using where; FirstMatch(t1) +1 PRIMARY t3 ALL NULL NULL NULL NULL 5 Using where +UPDATE t1,t3 SET a = NULL +WHERE a=c AND a IN (WITH cte AS (SELECT b FROM t2) SELECT * FROM cte); +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +PREPARE stmt FROM "UPDATE t1,t3 SET a = NULL +WHERE a=c AND a IN (WITH cte AS (SELECT b FROM t2) SELECT * FROM cte)"; +EXECUTE stmt; +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +EXECUTE stmt; +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +DEALLOCATE PREPARE stmt; +CREATE PROCEDURE p1() UPDATE t1,t3 SET a = NULL +WHERE a=c AND a IN (WITH cte AS (SELECT b FROM t2) SELECT * FROM cte); +SELECT * FROM t1; +a +3 +7 +1 +3 +CALL p1(); +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +CALL p1(); +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +DROP procedure p1; +SELECT * FROM t1; +a +3 +7 +1 +3 +EXPLAIN UPDATE t1 SET a = NULL +WHERE a IN (SELECT * FROM (SELECT b FROM t2) dt); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 Using where; FirstMatch(t1) +UPDATE t1 SET a = NULL +WHERE a IN (SELECT * FROM (SELECT b FROM t2) dt); +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +PREPARE stmt FROM "UPDATE t1 SET a = NULL +WHERE a IN (SELECT * FROM (SELECT b FROM t2) dt)"; +EXECUTE stmt; +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +EXECUTE stmt; +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +DEALLOCATE PREPARE stmt; +CREATE PROCEDURE p1() UPDATE t1 SET a = NULL +WHERE a IN (SELECT * FROM (SELECT b FROM t2) dt); +SELECT * FROM t1; +a +3 +7 +1 +3 +CALL p1(); +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +CALL p1(); +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +DROP procedure p1; +SELECT * FROM t1; +a +3 +7 +1 +3 +EXPLAIN UPDATE t1 SET a = NULL +WHERE a IN (WITH cte AS (SELECT b FROM t2) SELECT * FROM cte); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 Using where; FirstMatch(t1) +UPDATE t1 SET a = NULL +WHERE a IN (WITH cte AS (SELECT b FROM t2) SELECT * FROM cte); +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +PREPARE stmt FROM "UPDATE t1 SET a = NULL +WHERE a IN (WITH cte AS (SELECT b FROM t2) SELECT * FROM cte)"; +EXECUTE stmt; +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +EXECUTE stmt; +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +DEALLOCATE PREPARE stmt; +CREATE PROCEDURE p1() UPDATE t1 SET a = NULL +WHERE a IN (WITH cte AS (SELECT b FROM t2) SELECT * FROM cte); +SELECT * FROM t1; +a +3 +7 +1 +3 +CALL p1(); +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +CALL p1(); +SELECT * FROM t1; +a +NULL +7 +NULL +NULL +CALL restore_t1(); +DROP procedure p1; +DROP TABLE t1,t2,t3; +DROP PROCEDURE restore_t1; +# End of 11.1 tests diff --git a/mysql-test/main/multi_update.test b/mysql-test/main/multi_update.test index 325f63f696f..c6247a21b21 100644 --- a/mysql-test/main/multi_update.test +++ b/mysql-test/main/multi_update.test @@ -1201,3 +1201,140 @@ select * from t1; drop table t1,t2,t3,t; --echo # End of 10.4 tests + +--echo # +--echo # MDEV-31150: 2nd execution of multi-update with +--echo # mergeable derived table in WHERE +--echo # + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (3),(7),(1),(3); +CREATE TABLE t2 (b int); +INSERT INTO t2 VALUES (3),(4),(1); +CREATE TABLE t3 (c int); +INSERT INTO t3 VALUES (3),(4),(1),(5),(1); + +--delimiter | +CREATE PROCEDURE restore_t1() +BEGIN +DELETE FROM t1; +INSERT INTO t1 VALUES (3),(7),(1),(3); +END| +--delimiter ; + +let $q1= +UPDATE t1,t3 SET a = NULL + WHERE a=c AND a IN (SELECT * FROM (SELECT b FROM t2) dt); + +SELECT * FROM t1; +eval EXPLAIN $q1; +eval $q1; +SELECT * FROM t1; +CALL restore_t1(); +eval PREPARE stmt FROM "$q1"; +EXECUTE stmt; +SELECT * FROM t1; +CALL restore_t1(); +EXECUTE stmt; +SELECT * FROM t1; +CALL restore_t1(); +DEALLOCATE PREPARE stmt; + +eval CREATE PROCEDURE p1() $q1; +SELECT * FROM t1; +CALL p1(); +SELECT * FROM t1; +CALL restore_t1(); +CALL p1(); +SELECT * FROM t1; +CALL restore_t1(); +DROP procedure p1; + +let $q2= +UPDATE t1,t3 SET a = NULL + WHERE a=c AND a IN (WITH cte AS (SELECT b FROM t2) SELECT * FROM cte); + +SELECT * FROM t1; +eval EXPLAIN $q2; +eval $q2; +SELECT * FROM t1; +CALL restore_t1(); +eval PREPARE stmt FROM "$q2"; +EXECUTE stmt; +SELECT * FROM t1; +CALL restore_t1(); +EXECUTE stmt; +SELECT * FROM t1; +CALL restore_t1(); +DEALLOCATE PREPARE stmt; + +eval CREATE PROCEDURE p1() $q2; +SELECT * FROM t1; +CALL p1(); +SELECT * FROM t1; +CALL restore_t1(); +CALL p1(); +SELECT * FROM t1; +CALL restore_t1(); +DROP procedure p1; + +let $q3= +UPDATE t1 SET a = NULL + WHERE a IN (SELECT * FROM (SELECT b FROM t2) dt); + +SELECT * FROM t1; +eval EXPLAIN $q3; +eval $q3; +SELECT * FROM t1; +CALL restore_t1(); +eval PREPARE stmt FROM "$q3"; +EXECUTE stmt; +SELECT * FROM t1; +CALL restore_t1(); +EXECUTE stmt; +SELECT * FROM t1; +CALL restore_t1(); +DEALLOCATE PREPARE stmt; + +eval CREATE PROCEDURE p1() $q3; +SELECT * FROM t1; +CALL p1(); +SELECT * FROM t1; +CALL restore_t1(); +CALL p1(); +SELECT * FROM t1; +CALL restore_t1(); +DROP procedure p1; + +let $q4= +UPDATE t1 SET a = NULL + WHERE a IN (WITH cte AS (SELECT b FROM t2) SELECT * FROM cte); + +SELECT * FROM t1; +eval EXPLAIN $q4; +eval $q4; +SELECT * FROM t1; +CALL restore_t1(); +eval PREPARE stmt FROM "$q4"; +EXECUTE stmt; +SELECT * FROM t1; +CALL restore_t1(); +EXECUTE stmt; +SELECT * FROM t1; +CALL restore_t1(); +DEALLOCATE PREPARE stmt; + +eval CREATE PROCEDURE p1() $q4; +SELECT * FROM t1; +CALL p1(); +SELECT * FROM t1; +CALL restore_t1(); +CALL p1(); +SELECT * FROM t1; +CALL restore_t1(); +DROP procedure p1; + +DROP TABLE t1,t2,t3; +DROP PROCEDURE restore_t1; + +--echo # End of 11.1 tests diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 4eec441e9aa..c5331747e45 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1497,6 +1497,14 @@ static bool multi_update_check_table_access(THD *thd, TABLE_LIST *table, else { /* Must be a base or derived table. */ + /* + Derived tables do not need the check below. + Besides one have take into account that for mergeable derived tables + TABLE_LIST::TABLE is set to NULL after the first execution of the query. + */ + if (table->is_derived()) + return false; + const bool updated= table->table->map & tables_for_update; if (check_table_access(thd, updated ? UPDATE_ACL : SELECT_ACL, table, FALSE, 1, FALSE))