diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 4c0acc2eb6a..5c5afd2a0ec 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -4004,3 +4004,36 @@ CREATE VIEW t2 AS SELECT * FROM t1; ERROR HY000: Can't execute the query because you have a conflicting read lock UNLOCK TABLES; DROP TABLE t1, t2; +# +# Bug#48315 Metadata lock is not taken for merged views that +# use an INFORMATION_SCHEMA table +# +DROP TABLE IF EXISTS t1; +DROP VIEW IF EXISTS v1; +DROP PROCEDURE IF EXISTS p1; +# Connection default +CREATE VIEW v1 AS SELECT schema_name FROM information_schema.schemata; +CREATE TABLE t1 (str VARCHAR(50)); +CREATE PROCEDURE p1() INSERT INTO t1 SELECT * FROM v1; +# CALL p1() so the view is merged. +CALL p1(); +# Connection 3 +LOCK TABLE t1 READ; +# Connection default +# Try to CALL p1() again, this time it should block for t1. +# Sending: +CALL p1(); +# Connection 2 +# ... then try to drop the view. This should block. +# Sending: +DROP VIEW v1; +# Connection 3 +# Now allow CALL p1() to complete +UNLOCK TABLES; +# Connection default +# Reaping: CALL p1() +# Connection 2 +# Reaping: DROP VIEW v1 +# Connection default +DROP PROCEDURE p1; +DROP TABLE t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 8297013611f..2cca4ccd186 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -6,6 +6,9 @@ drop database if exists mysqltest; --enable_warnings use test; +# Save the initial number of concurrent sessions. +--source include/count_sessions.inc + # # some basic test of views and its functionality # @@ -3975,3 +3978,79 @@ CREATE VIEW t2 AS SELECT * FROM t1; UNLOCK TABLES; DROP TABLE t1, t2; + + +--echo # +--echo # Bug#48315 Metadata lock is not taken for merged views that +--echo # use an INFORMATION_SCHEMA table +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP VIEW IF EXISTS v1; +DROP PROCEDURE IF EXISTS p1; +--enable_warnings + +connect (con2, localhost, root); +connect (con3, localhost, root); + +--echo # Connection default +connection default; + +CREATE VIEW v1 AS SELECT schema_name FROM information_schema.schemata; +CREATE TABLE t1 (str VARCHAR(50)); +CREATE PROCEDURE p1() INSERT INTO t1 SELECT * FROM v1; + +--echo # CALL p1() so the view is merged. +CALL p1(); + +--echo # Connection 3 +connection con3; +LOCK TABLE t1 READ; + +--echo # Connection default +connection default; +--echo # Try to CALL p1() again, this time it should block for t1. +--echo # Sending: +--send CALL p1() + +--echo # Connection 2 +connection con2; +let $wait_condition= + SELECT COUNT(*) = 1 from information_schema.processlist + WHERE state = "Table lock" AND info = "INSERT INTO t1 SELECT * FROM v1"; +--source include/wait_condition.inc +--echo # ... then try to drop the view. This should block. +--echo # Sending: +--send DROP VIEW v1 + +--echo # Connection 3 +connection con3; +let $wait_condition= + SELECT COUNT(*) = 1 from information_schema.processlist + WHERE state = "Waiting for table" AND info = "DROP VIEW v1"; +--source include/wait_condition.inc +--echo # Now allow CALL p1() to complete +UNLOCK TABLES; + +--echo # Connection default +connection default; +--echo # Reaping: CALL p1() +--reap + +--echo # Connection 2 +connection con2; +--echo # Reaping: DROP VIEW v1 +--reap + +--echo # Connection default +connection default; +DROP PROCEDURE p1; +DROP TABLE t1; +disconnect con2; +disconnect con3; + + +# Check that all connections opened by test cases in this file are really +# gone so execution of other tests won't be affected by their presence. +--source include/wait_until_count_sessions.inc diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6ff7085f740..d5a664df0d0 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4168,9 +4168,18 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables, TABLE_LIST is processed. This code works only during re-execution. */ if (tables->view) - goto process_view_routines; - if (!mysql_schema_table(thd, lex, tables) && - !check_and_update_table_version(thd, tables, tables->table->s)) + { + /* + We still need to take a MDL lock on the merged view to protect + it from concurrent changes. + */ + if (!open_table_get_mdl_lock(thd, tables, &tables->mdl_request, + ot_ctx, flags)) + goto process_view_routines; + /* Fall-through to return error. */ + } + else if (!mysql_schema_table(thd, lex, tables) && + !check_and_update_table_version(thd, tables, tables->table->s)) { goto end; }