From a1ceb1bd049a14a72f1ccf1cc8556e6930c07af5 Mon Sep 17 00:00:00 2001
From: "bell@sanja.is.com.ua" <>
Date: Thu, 20 Nov 2003 18:12:49 +0200
Subject: [PATCH] database invalidation invalidate queries only of given
 database (BUG#1898)

---
 mysql-test/r/query_cache.result | 11 +++++++++--
 mysql-test/t/query_cache.test   |  4 ++++
 sql/sql_cache.cc                | 34 +++++++++++++++++++++++++++------
 3 files changed, 41 insertions(+), 8 deletions(-)

diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result
index 83d2e439fbc..c7554211a1a 100644
--- a/mysql-test/r/query_cache.result
+++ b/mysql-test/r/query_cache.result
@@ -365,16 +365,23 @@ insert into mysqltest.t1 (a) values (1);
 select * from mysqltest.t1 where i is null;
 i	a
 1	1
+create table t1(a int);
+select * from t1;
+a
+show status like "Qcache_queries_in_cache";
+Variable_name	Value
+Qcache_queries_in_cache	1
 select * from mysqltest.t1;
 i	a
 1	1
 show status like "Qcache_queries_in_cache";
 Variable_name	Value
-Qcache_queries_in_cache	1
+Qcache_queries_in_cache	2
 drop database mysqltest;
 show status like "Qcache_queries_in_cache";
 Variable_name	Value
-Qcache_queries_in_cache	0
+Qcache_queries_in_cache	1
+drop table t1;
 create table t1 (a char(1) not null);
 insert into t1 values("รก");
 select * from t1;
diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test
index 2ab5504f84b..ad0dc80e2f7 100644
--- a/mysql-test/t/query_cache.test
+++ b/mysql-test/t/query_cache.test
@@ -251,10 +251,14 @@ select * from mysqltest.t1 where i is null;
 #
 # drop db
 #
+create table t1(a int);
+select * from t1;
+show status like "Qcache_queries_in_cache";
 select * from mysqltest.t1;
 show status like "Qcache_queries_in_cache";
 drop database mysqltest;
 show status like "Qcache_queries_in_cache";
+drop table t1;
 
 #
 # Charset convertion (cp1251_koi8 always present)
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 5d525c7be4e..8610fcb8f22 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1151,9 +1151,29 @@ void Query_cache::invalidate(char *db)
     if (query_cache_size > 0)
     {
       DUMP(this);
-	/* invalidate_table reduce list while only root of list remain */
-      while (tables_blocks !=0 )
-	invalidate_table(tables_blocks);
+  restart_search:
+      if (tables_blocks)
+      {
+	Query_cache_block *curr= tables_blocks;
+	Query_cache_block *next;
+	do
+	{
+	  next= curr->next;
+	  if (strcmp(db, (char*)(curr->table()->db())) == 0)
+	    invalidate_table(curr);
+	  /*
+	    invalidate_table can freed block on which point 'next' (if
+	    table of this block used only in queries which was deleted
+	    by invalidate_table). As far as we do not allocate new blocks
+	    and mark all headers of freed blocks as 'FREE' (even if they are
+	    merged with other blocks) we can just test type of block
+	    to be sure that block is not deleted
+	  */
+	  if (next->type == Query_cache_block::FREE)
+	    goto restart_search;
+	  curr= next;
+	} while (curr != tables_blocks);
+      }
     }
     STRUCT_UNLOCK(&structure_guard_mutex);
   }
@@ -2158,9 +2178,11 @@ void Query_cache::free_memory_block(Query_cache_block *block)
 {
   DBUG_ENTER("Query_cache::free_memory_block");
   block->used=0;
-  DBUG_PRINT("qcache",("first_block 0x%lx, block 0x%lx, pnext 0x%lx pprev 0x%lx",
-		     (ulong) first_block, (ulong) block,block->pnext,
-		     (ulong) block->pprev));
+  block->type= Query_cache_block::FREE; // mark block as free in any case
+  DBUG_PRINT("qcache",
+	     ("first_block 0x%lx, block 0x%lx, pnext 0x%lx pprev 0x%lx",
+	      (ulong) first_block, (ulong) block,block->pnext,
+	      (ulong) block->pprev));
 
   if (block->pnext != first_block && block->pnext->is_free())
     block = join_free_blocks(block, block->pnext);
-- 
2.30.9