summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2021-02-20 14:46:19 +0200
committerSergei Golubchik <serg@mariadb.org>2021-02-22 22:42:38 +0100
commit640f42311a72fa82bf7117c2791fc47ceb420361 (patch)
tree6135b491b2a6d6325f1f3d55c3f13779c80b90fb
parent0ab1e3914c78e4a82a8e4502b58b20e5598727ab (diff)
downloadmariadb-git-640f42311a72fa82bf7117c2791fc47ceb420361.tar.gz
MDEV-24929 Server crash in thr_multi_unlock or in get_schema_tables_result
This was caused by two different bugs: 1) Information_schema tables where not locked by lock_tables, but get_lock_data() was not filtering these out. This caused a crash when mysql_unlock_some_tables() tried to unlock tables early, including not locked information schema tables. Fixed by not locking SYSTEM_TMP_TABLES 2) In some cases the optimizer will notice that we do not need to read the information_schema tables at all. In this case join_tab->read_record is not set, which caused a crash in get_schema_tables_result() Fixed by ignoring const tables in get_schema_tables_result()
-rw-r--r--mysql-test/main/information_schema.result13
-rw-r--r--mysql-test/main/information_schema.test10
-rw-r--r--sql/lock.cc17
-rw-r--r--sql/sql_show.cc10
4 files changed, 43 insertions, 7 deletions
diff --git a/mysql-test/main/information_schema.result b/mysql-test/main/information_schema.result
index 93ff6e170f6..c65a10cbd4b 100644
--- a/mysql-test/main/information_schema.result
+++ b/mysql-test/main/information_schema.result
@@ -2303,5 +2303,18 @@ group by f;
f
drop table t1;
#
+# MDEV-24929 Server crash in thr_multi_unlock or in
+# get_schema_tables_result upon select from I_S with joins
+#
+CREATE TABLE t1 (a TIMESTAMP, KEY (a));
+INSERT INTO t1 VALUES ('2012-12-12'),('2021-11-11');
+SELECT count(*) FROM t1 AS t1a LEFT JOIN (t1 AS t1b JOIN INFORMATION_SCHEMA.ROUTINES) ON (t1b.a IS NULL);
+count(*)
+2
+SELECT count(*) FROM t1 AS t1a LEFT JOIN (t1 AS t1b JOIN INFORMATION_SCHEMA.PROFILING) ON (t1b.a IS NULL);
+count(*)
+2
+DROP TABLE t1;
+#
# End of 10.3 tests
#
diff --git a/mysql-test/main/information_schema.test b/mysql-test/main/information_schema.test
index 6319cc79df7..4468eb18e45 100644
--- a/mysql-test/main/information_schema.test
+++ b/mysql-test/main/information_schema.test
@@ -2035,5 +2035,15 @@ group by f;
drop table t1;
--echo #
+--echo # MDEV-24929 Server crash in thr_multi_unlock or in
+--echo # get_schema_tables_result upon select from I_S with joins
+--echo #
+
+CREATE TABLE t1 (a TIMESTAMP, KEY (a));
+INSERT INTO t1 VALUES ('2012-12-12'),('2021-11-11');
+SELECT count(*) FROM t1 AS t1a LEFT JOIN (t1 AS t1b JOIN INFORMATION_SCHEMA.ROUTINES) ON (t1b.a IS NULL);
+SELECT count(*) FROM t1 AS t1a LEFT JOIN (t1 AS t1b JOIN INFORMATION_SCHEMA.PROFILING) ON (t1b.a IS NULL);
+DROP TABLE t1;
+--echo #
--echo # End of 10.3 tests
--echo #
diff --git a/sql/lock.cc b/sql/lock.cc
index 7dcba179a36..4d055f58242 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -727,6 +727,9 @@ static int unlock_external(THD *thd, TABLE **table,uint count)
- GET_LOCK_STORE_LOCKS : Store lock info in TABLE
- GET_LOCK_SKIP_SEQUENCES : Ignore sequences (for temporary unlock)
- GET_LOCK_ON_THD : Store lock in thd->mem_root
+
+ Temporary tables are not locked (as these are single user), except for
+ TRANSACTIONAL_TMP_TABLES as locking is needed to handle transactions.
*/
MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
@@ -743,8 +746,8 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
{
TABLE *t= table_ptr[i];
- if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE &&
- t->s->tmp_table != INTERNAL_TMP_TABLE &&
+ if ((likely(!t->s->tmp_table) ||
+ (t->s->tmp_table == TRANSACTIONAL_TMP_TABLE)) &&
(!(flags & GET_LOCK_SKIP_SEQUENCES) || t->s->sequence == 0))
{
lock_count+= t->file->lock_count();
@@ -772,13 +775,13 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
for (i=0 ; i < count ; i++)
{
- TABLE *table;
+ TABLE *table= table_ptr[i];
enum thr_lock_type lock_type;
THR_LOCK_DATA **locks_start;
- table= table_ptr[i];
- if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE ||
- table->s->tmp_table == INTERNAL_TMP_TABLE ||
- ((flags & GET_LOCK_SKIP_SEQUENCES) && table->s->sequence))
+
+ if (!((likely(!table->s->tmp_table) ||
+ (table->s->tmp_table == TRANSACTIONAL_TMP_TABLE)) &&
+ (!(flags & GET_LOCK_SKIP_SEQUENCES) || table->s->sequence == 0)))
continue;
lock_type= table->reginfo.lock_type;
DBUG_ASSERT(lock_type != TL_WRITE_DEFAULT && lock_type != TL_READ_DEFAULT);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 2e0a44e4b8a..e6b5461e5af 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -8837,6 +8837,16 @@ bool get_schema_tables_result(JOIN *join,
if (table_list->schema_table->fill_table == 0)
continue;
+ /*
+ Do not fill in tables thare are marked as JT_CONST as these will never
+ be read and they also don't have a tab->read_record.table set!
+ This can happen with queries like
+ SELECT * FROM t1 LEFT JOIN (t1 AS t1b JOIN INFORMATION_SCHEMA.ROUTINES)
+ ON (t1b.a IS NULL);
+ */
+ if (tab->type == JT_CONST)
+ continue;
+
/* skip I_S optimizations specific to get_all_tables */
if (lex->describe &&
(table_list->schema_table->fill_table != get_all_tables))