Skip to content

Commit 92f8adc

Browse files
phulakundahlerlend
authored andcommitted
Bug#24487414 - SIG 11 IN DD::INFO_SCHEMA::STATISTICS_CACHE::READ_STAT_BY_OPEN_TABLE
Attempt to access TABLE instance when open table (to obtain statistics) fails because of KILL query or connection operation resulted in the issue reported. For the non-innodb tables, its statistics is obtained by opening the table. Current code assumes that when open table fails then Diagnostics_area is always set with an error. If Diagnostics_area is not set then open table success condition code is executed. This works well when table open fails because of the error. Open table fails even when query or connections is killed. In this case Diagnostics_area might not be set. In such scenario, attempt access TABLE instance from the pointer in TABLE_LIST resulted in the crash. To fix the issue, the failures from open_tables() is handled irrespective of whether the diagnostics area is set. If we find error being reported in diagnostics area, we write it to comment field as we do now. If we do not find a error reported, then we just make the UDF return failure. The query is later terminated by call to send_kill_message() when we check thd->killed flag.
1 parent ce402b9 commit 92f8adc

File tree

3 files changed

+85
-19
lines changed

3 files changed

+85
-19
lines changed

mysql-test/r/dd_is_debug.result

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#
2+
# Bug#24487414 - SIG 11 IN DD::INFO_SCHEMA::STATISTICS_CACHE::READ_STAT_BY_OPEN_TABLE
3+
#
4+
SET @old_information_schema_stats= @@session.information_schema_stats;
5+
SET @@session.information_schema_stats= latest;
6+
CREATE TABLE time_zone(f1 INT PRIMARY KEY) ENGINE=MyISAM;
7+
INSERT INTO time_zone VALUES (10);
8+
SET SESSION DEBUG="+d,simulate_kill_query_on_open_table";
9+
# Without fix, following query results in crash when query is killed while
10+
# opening "test.time_zone" table.
11+
SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA='test' AND
12+
TABLE_NAME = 'time_zone';
13+
ERROR 70100: Query execution was interrupted
14+
SET SESSION DEBUG="-d,simulate_kill_query_on_open_table";
15+
DROP TABLE time_zone;
16+
SET @@session.information_schema_stats= @old_information_schema_stats;

mysql-test/t/dd_is_debug.test

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#
2+
# Tests for INFORMATION_SCHEMA system views requiring debug build of server.
3+
#
4+
--source include/have_debug.inc
5+
6+
--echo #
7+
--echo # Bug#24487414 - SIG 11 IN DD::INFO_SCHEMA::STATISTICS_CACHE::READ_STAT_BY_OPEN_TABLE
8+
--echo #
9+
SET @old_information_schema_stats= @@session.information_schema_stats;
10+
SET @@session.information_schema_stats= latest;
11+
12+
# time_zone table name is used here to set debug point
13+
# kill_query_on_open_table_from_tz_find from the
14+
# simulate_kill_query_on_open_table debug point.
15+
CREATE TABLE time_zone(f1 INT PRIMARY KEY) ENGINE=MyISAM;
16+
INSERT INTO time_zone VALUES (10);
17+
18+
SET SESSION DEBUG="+d,simulate_kill_query_on_open_table";
19+
--echo # Without fix, following query results in crash when query is killed while
20+
--echo # opening "test.time_zone" table.
21+
--error ER_QUERY_INTERRUPTED
22+
SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA='test' AND
23+
TABLE_NAME = 'time_zone';
24+
SET SESSION DEBUG="-d,simulate_kill_query_on_open_table";
25+
26+
DROP TABLE time_zone;
27+
28+
SET @@session.information_schema_stats= @old_information_schema_stats;
29+
30+
###########################################################################

sql/dd/info_schema/stats.cc

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,9 @@ ulonglong Statistics_cache::read_stat_by_open_table(
620620
*/
621621
lex->sql_command= SQLCOM_SELECT;
622622

623+
DBUG_EXECUTE_IF("simulate_kill_query_on_open_table",
624+
DBUG_SET("+d,kill_query_on_open_table_from_tz_find"););
625+
623626
// Push deadlock error handler.
624627
thd->push_internal_handler(&mdl_deadlock_error_handler);
625628

@@ -630,6 +633,8 @@ ulonglong Statistics_cache::read_stat_by_open_table(
630633

631634
thd->pop_internal_handler();
632635

636+
DBUG_EXECUTE_IF("simulate_kill_query_on_open_table",
637+
DBUG_SET("-d,kill_query_on_open_table_from_tz_find"););
633638
DEBUG_SYNC(thd, "after_open_table_mdl_shared_to_fetch_stats");
634639

635640
if (!open_result && table_list->is_view_or_derived())
@@ -645,30 +650,45 @@ ulonglong Statistics_cache::read_stat_by_open_table(
645650
*/
646651
lex->sql_command= old_lex->sql_command;
647652

648-
if (open_result && thd->is_error())
653+
if (open_result)
649654
{
650-
/*
651-
Hide error for a non-existing table.
652-
For example, this error can occur when we use a where condition
653-
with a db name and table, but the table does not exist.
654-
*/
655-
if (!(thd->get_stmt_da()->mysql_errno() == ER_NO_SUCH_TABLE) &&
656-
!(thd->get_stmt_da()->mysql_errno() == ER_WRONG_OBJECT))
657-
push_warning(thd, Sql_condition::SL_WARNING,
658-
thd->get_stmt_da()->mysql_errno(),
659-
thd->get_stmt_da()->message_text());
655+
DBUG_ASSERT(thd->is_error() || thd->is_killed());
660656

661-
/* Cache empty statistics when we see a error.
662-
This will make sure,
657+
if (thd->is_error())
658+
{
659+
/*
660+
Hide error for a non-existing table.
661+
For example, this error can occur when we use a where condition
662+
with a db name and table, but the table does not exist.
663+
*/
664+
if (!(thd->get_stmt_da()->mysql_errno() == ER_NO_SUCH_TABLE) &&
665+
!(thd->get_stmt_da()->mysql_errno() == ER_WRONG_OBJECT))
666+
push_warning(thd, Sql_condition::SL_WARNING,
667+
thd->get_stmt_da()->mysql_errno(),
668+
thd->get_stmt_da()->message_text());
663669

664-
1. You will not invoke open_tables_for_query() gain.
670+
/* Cache empty statistics when we see a error.
671+
This will make sure,
665672
666-
2. You will not see junk values for statistics in results.
667-
*/
668-
cache_stats(schema_name_ptr, table_name_ptr, ha_stat);
673+
1. You will not invoke open_tables_for_query() gain.
669674
670-
m_error= thd->get_stmt_da()->message_text();
671-
thd->clear_error();
675+
2. You will not see junk values for statistics in results.
676+
*/
677+
cache_stats(schema_name_ptr, table_name_ptr, ha_stat);
678+
679+
m_error= thd->get_stmt_da()->message_text();
680+
thd->clear_error();
681+
}
682+
else
683+
{
684+
/*
685+
Table open fails even when query or connection is killed. In this
686+
case Diagnostics_area might not be set. So just returning error from
687+
here. Query is later terminated by call to send_kill_message() when
688+
we check thd->killed flag.
689+
*/
690+
error= -1;
691+
}
672692

673693
goto end;
674694
}

0 commit comments

Comments
 (0)