summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2017-04-28 19:42:32 +0200
committerOleksandr Byelkin <sanja@mariadb.com>2017-05-04 15:25:30 +0200
commit8f8c379f1c85ebb5edca33eecaa6996340e2e241 (patch)
tree09f059a50bb5382e616f26fe31eae5435a9a7528
parent96247be1a0dfa3035580b53b1c27a7247a410713 (diff)
downloadmariadb-git-bb-10.2-MDEV-12485.tar.gz
MDEV-12485 foreign key on delete cascade stale entries with query cache enabledbb-10.2-MDEV-12485
During merge of innodb code QC invalidation was removed from innodb part but not added to server part. We decided to keep it in innodb to keep server/engine interface the same.
-rw-r--r--mysql-test/r/query_cache_innodb.result90
-rw-r--r--mysql-test/t/query_cache_innodb.test84
-rw-r--r--storage/innobase/handler/ha_innodb.cc34
3 files changed, 203 insertions, 5 deletions
diff --git a/mysql-test/r/query_cache_innodb.result b/mysql-test/r/query_cache_innodb.result
new file mode 100644
index 00000000000..2f439948108
--- /dev/null
+++ b/mysql-test/r/query_cache_innodb.result
@@ -0,0 +1,90 @@
+#
+# MDEV-12485: foreign key on delete cascade stale entries with
+# query cache enabled
+#
+SET NAMES utf8;
+set global query_cache_type=1;
+set global query_cache_size=1024*1024;
+set query_cache_type=1;
+create table t1 ( id int unsigned auto_increment, primary key(id) ) engine=innodb;
+create table t2 ( t2id int unsigned, id int unsigned, primary key(t2id, id), foreign key (`id`) references t1(`id`) on delete cascade ) engine=innodb;
+insert into t1 values (1);
+insert into t2 values (1,1);
+select * from t2;
+t2id id
+1 1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+delete from t1;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+select * from t2;
+t2id id
+optimize table t2;
+Table Op Msg_type Msg_text
+test.t2 optimize note Table does not support optimize, doing recreate + analyze instead
+test.t2 optimize status OK
+select * from t2;
+t2id id
+drop table t2;
+drop table t1;
+create database `testdatabase$Ї`;
+use `testdatabase$Ї`;
+create table `t1$Ї` ( id int unsigned auto_increment, primary key(id) ) engine=innodb;
+create table `t2$Ї` ( t2id int unsigned, id int unsigned, primary key(t2id, id), foreign key (`id`) references `t1$Ї`(`id`) on delete cascade ) engine=innodb;
+insert into `t1$Ї` values (1);
+insert into `t2$Ї`values (1,1);
+select * from `t2$Ї`;
+t2id id
+1 1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+delete from `t1$Ї`;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+select * from `t2$Ї`;
+t2id id
+optimize table `t2$Ї`;
+Table Op Msg_type Msg_text
+testdatabase$Ї.t2$Ї optimize note Table does not support optimize, doing recreate + analyze instead
+testdatabase$Ї.t2$Ї optimize status OK
+select * from `t2$Ї`;
+t2id id
+use test;
+drop database `testdatabase$Ї`;
+SET NAMES default;
+create database `#mysql50#-`;
+use `#mysql50#-`;
+create table `#mysql50#t-1` ( id int unsigned auto_increment, primary key(id) ) engine=innodb;
+create table `#mysql50#t-2` ( t2id int unsigned, id int unsigned, primary key(t2id, id), foreign key (`id`) references `#mysql50#t-1`(`id`) on delete cascade ) engine=innodb;
+insert into `#mysql50#t-1` values (1);
+insert into `#mysql50#t-2`values (1,1);
+select * from `#mysql50#t-2`;
+t2id id
+1 1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+delete from `#mysql50#t-1`;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+select * from `#mysql50#t-2`;
+t2id id
+optimize table `#mysql50#t-2`;
+Table Op Msg_type Msg_text
+#mysql50#-.#mysql50#t-2 optimize note Table does not support optimize, doing recreate + analyze instead
+#mysql50#-.#mysql50#t-2 optimize status OK
+select * from `#mysql50#t-2`;
+t2id id
+use test;
+drop database `#mysql50#-`;
+SET NAMES default;
+FOUND 12 /\[ERROR\] Invalid \(old\?\) table or database name/ in mysqld.1.err
+set global query_cache_type=DEFAULT;
+set global query_cache_size=DEFAULT;
+End of 10.2 tests
diff --git a/mysql-test/t/query_cache_innodb.test b/mysql-test/t/query_cache_innodb.test
new file mode 100644
index 00000000000..588cdf31c5a
--- /dev/null
+++ b/mysql-test/t/query_cache_innodb.test
@@ -0,0 +1,84 @@
+--source include/have_innodb.inc
+--source include/have_query_cache.inc
+
+--echo #
+--echo # MDEV-12485: foreign key on delete cascade stale entries with
+--echo # query cache enabled
+--echo #
+
+SET NAMES utf8;
+set global query_cache_type=1;
+set global query_cache_size=1024*1024;
+set query_cache_type=1;
+
+create table t1 ( id int unsigned auto_increment, primary key(id) ) engine=innodb;
+
+create table t2 ( t2id int unsigned, id int unsigned, primary key(t2id, id), foreign key (`id`) references t1(`id`) on delete cascade ) engine=innodb;
+
+insert into t1 values (1);
+insert into t2 values (1,1);
+select * from t2;
+show status like "Qcache_queries_in_cache";
+
+delete from t1;
+show status like "Qcache_queries_in_cache";
+select * from t2;
+
+optimize table t2;
+select * from t2;
+drop table t2;
+drop table t1;
+
+create database `testdatabase$Ї`;
+use `testdatabase$Ї`;
+create table `t1$Ї` ( id int unsigned auto_increment, primary key(id) ) engine=innodb;
+
+create table `t2$Ї` ( t2id int unsigned, id int unsigned, primary key(t2id, id), foreign key (`id`) references `t1$Ї`(`id`) on delete cascade ) engine=innodb;
+
+insert into `t1$Ї` values (1);
+insert into `t2$Ї`values (1,1);
+select * from `t2$Ї`;
+show status like "Qcache_queries_in_cache";
+
+delete from `t1$Ї`;
+show status like "Qcache_queries_in_cache";
+select * from `t2$Ї`;
+
+optimize table `t2$Ї`;
+select * from `t2$Ї`;
+
+use test;
+drop database `testdatabase$Ї`;
+SET NAMES default;
+
+create database `#mysql50#-`;
+use `#mysql50#-`;
+create table `#mysql50#t-1` ( id int unsigned auto_increment, primary key(id) ) engine=innodb;
+
+create table `#mysql50#t-2` ( t2id int unsigned, id int unsigned, primary key(t2id, id), foreign key (`id`) references `#mysql50#t-1`(`id`) on delete cascade ) engine=innodb;
+
+insert into `#mysql50#t-1` values (1);
+insert into `#mysql50#t-2`values (1,1);
+select * from `#mysql50#t-2`;
+show status like "Qcache_queries_in_cache";
+
+delete from `#mysql50#t-1`;
+show status like "Qcache_queries_in_cache";
+select * from `#mysql50#t-2`;
+
+optimize table `#mysql50#t-2`;
+select * from `#mysql50#t-2`;
+
+use test;
+drop database `#mysql50#-`;
+SET NAMES default;
+--disable_query_log
+call mtr.add_suppression("\\[ERROR\\] Invalid \\(old\\?\\) table or database name 't?-[12]?\\'");
+--enable_query_log
+--let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err
+--let SEARCH_PATTERN=\\[ERROR\\] Invalid \\(old\\?\\) table or database name
+--source include/search_pattern_in_file.inc
+
+set global query_cache_type=DEFAULT;
+set global query_cache_size=DEFAULT;
+--echo End of 10.2 tests
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index c486b0d4c4d..356dd36b43c 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -3441,11 +3441,35 @@ innobase_invalidate_query_cache(
above the InnoDB trx_sys_t->lock. The caller of this function must
not have latches of a lower rank. */
- /* Argument TRUE below means we are using transactions */
- mysql_query_cache_invalidate4(trx->mysql_thd,
- full_name,
- (uint32) full_name_len,
- TRUE);
+#ifdef HAVE_QUERY_CACHE
+ char qcache_key_name[2 * (NAME_LEN + 1)];
+ char db_name[NAME_CHAR_LEN * MY_CS_MBMAXLEN + 1];
+ const char *key_ptr;
+ size_t tabname_len;
+ size_t dbname_len;
+
+ // Extract the database name.
+ key_ptr= strchr(full_name, '/');
+ DBUG_ASSERT(key_ptr != NULL); // Database name should be present
+ memcpy(db_name, full_name, (dbname_len= (key_ptr - full_name)));
+ db_name[dbname_len]= '\0';
+
+ /* Construct the key("db-name\0table$name\0") for the query cache using
+ the path name("db@002dname\0table@0024name\0") of the table in its
+ canonical form. */
+ dbname_len = filename_to_tablename(db_name, qcache_key_name,
+ sizeof(qcache_key_name));
+ tabname_len = filename_to_tablename(++key_ptr,
+ (qcache_key_name + dbname_len + 1),
+ sizeof(qcache_key_name) -
+ dbname_len - 1);
+
+ /* Argument TRUE below means we are using transactions */
+ mysql_query_cache_invalidate4(trx->mysql_thd,
+ qcache_key_name,
+ (dbname_len + tabname_len + 2),
+ TRUE);
+#endif
}
/** Quote a standard SQL identifier like index or column name.