diff --git a/mysql-test/r/lock_sync.result b/mysql-test/r/lock_sync.result index 726b754eaa8..8fe94679e70 100644 --- a/mysql-test/r/lock_sync.result +++ b/mysql-test/r/lock_sync.result @@ -738,3 +738,38 @@ SET DEBUG_SYNC= 'now SIGNAL release_thrlock'; # Connection default DROP TABLE t1; SET DEBUG_SYNC= 'RESET'; +# +# Bug#57130 crash in Item_field::print during SHOW CREATE TABLE or VIEW +# +DROP TABLE IF EXISTS t1; +DROP VIEW IF EXISTS v1; +DROP FUNCTION IF EXISTS f1; +CREATE TABLE t1(a INT); +CREATE FUNCTION f1() RETURNS INTEGER RETURN 1; +CREATE VIEW v1 AS SELECT * FROM t1 WHERE f1() = 1; +DROP FUNCTION f1; +# Connection con1 +SET DEBUG_SYNC= 'open_tables_after_open_and_process_table SIGNAL opened WAIT_FOR dropped EXECUTE 2'; +# Sending: +SHOW CREATE VIEW v1; +# Connection con2 +SET DEBUG_SYNC= 'now WAIT_FOR opened'; +SET DEBUG_SYNC= 'now SIGNAL dropped'; +SET DEBUG_SYNC= 'now WAIT_FOR opened'; +# Sending: +FLUSH TABLES; +# Connection default +# Waiting for FLUSH TABLES to be blocked. +SET DEBUG_SYNC= 'now SIGNAL dropped'; +# Connection con1 +# Reaping: SHOW CREATE VIEW v1 +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` where (`f1`() = 1) latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +# Connection con2 +# Reaping: FLUSH TABLES +# Connection default +SET DEBUG_SYNC= 'RESET'; +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/lock_sync.test b/mysql-test/t/lock_sync.test index 7131e2cde31..d5ad7becd7d 100644 --- a/mysql-test/t/lock_sync.test +++ b/mysql-test/t/lock_sync.test @@ -1078,6 +1078,65 @@ DROP TABLE t1; SET DEBUG_SYNC= 'RESET'; +--echo # +--echo # Bug#57130 crash in Item_field::print during SHOW CREATE TABLE or VIEW +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP VIEW IF EXISTS v1; +DROP FUNCTION IF EXISTS f1; +--enable_warnings + +CREATE TABLE t1(a INT); +CREATE FUNCTION f1() RETURNS INTEGER RETURN 1; +CREATE VIEW v1 AS SELECT * FROM t1 WHERE f1() = 1; +DROP FUNCTION f1; +connect(con2, localhost, root); + +--echo # Connection con1 +connect (con1, localhost, root); +# Need to trigger this sync point at least twice in order to +# get valgrind test failures without the patch +SET DEBUG_SYNC= 'open_tables_after_open_and_process_table SIGNAL opened WAIT_FOR dropped EXECUTE 2'; +--echo # Sending: +--send SHOW CREATE VIEW v1 + +--echo # Connection con2 +connection con2; +SET DEBUG_SYNC= 'now WAIT_FOR opened'; +SET DEBUG_SYNC= 'now SIGNAL dropped'; +SET DEBUG_SYNC= 'now WAIT_FOR opened'; +--echo # Sending: +--send FLUSH TABLES + +--echo # Connection default +connection default; +--echo # Waiting for FLUSH TABLES to be blocked. +let $wait_condition= SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state= 'Waiting for table flush' AND info= 'FLUSH TABLES'; +--source include/wait_condition.inc +SET DEBUG_SYNC= 'now SIGNAL dropped'; + +--echo # Connection con1 +connection con1; +--echo # Reaping: SHOW CREATE VIEW v1 +--reap + +--echo # Connection con2 +connection con2; +--echo # Reaping: FLUSH TABLES +--reap + +--echo # Connection default +connection default; +SET DEBUG_SYNC= 'RESET'; +DROP VIEW v1; +DROP TABLE t1; +disconnect con1; +disconnect con2; + + # 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_show.cc b/sql/sql_show.cc index be3dd8a0ca2..fa9c0e85c27 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -29,6 +29,8 @@ #include "repl_failsafe.h" #include "sql_parse.h" // check_access, check_table_access #include "sql_partition.h" // partition_element +#include "sql_derived.h" // mysql_derived_prepare, + // mysql_handle_derived, #include "sql_db.h" // check_db_dir_existence, load_db_opt_by_name #include "sql_time.h" // interval_type_to_name #include "tztime.h" // struct Time_zone @@ -683,11 +685,18 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) thd->lex->view_prepare_mode= TRUE; { + /* + Use open_tables() directly rather than open_normal_and_derived_tables(). + This ensures that close_thread_tables() is not called if open tables fails + and the error is ignored. This allows us to handle broken views nicely. + */ + uint counter; Show_create_error_handler view_error_suppressor(thd, table_list); thd->push_internal_handler(&view_error_suppressor); bool open_error= - open_normal_and_derived_tables(thd, table_list, - MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL); + open_tables(thd, &table_list, &counter, + MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL) || + mysql_handle_derived(thd->lex, &mysql_derived_prepare); thd->pop_internal_handler(); if (open_error && (thd->killed || thd->is_error())) goto exit;