summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/type_bit.result2
-rw-r--r--mysql-test/r/view.result2
-rw-r--r--mysql-test/t/type_bit.test2
-rw-r--r--mysql-test/t/view.test4
-rw-r--r--sql/sp.cc16
-rw-r--r--sql/sp_cache.cc193
-rw-r--r--sql/sp_cache.h101
-rw-r--r--sql/sql_parse.cc3
-rw-r--r--sql/sql_prepare.cc5
9 files changed, 185 insertions, 143 deletions
diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result
index 4aa8587d6e1..c22ceba70d8 100644
--- a/mysql-test/r/type_bit.result
+++ b/mysql-test/r/type_bit.result
@@ -34,7 +34,7 @@ select 0 + b'1111111111111111';
select 0 + b'1000000000000001';
0 + b'1000000000000001'
32769
-drop table if exists t1;
+drop table if exists t1,t2;
create table t1 (a bit(65));
ERROR 42000: Column length too big for column 'a' (max = 64); use BLOB or TEXT instead
create table t1 (a bit(0));
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index f6b5018cf3a..98020c7ec33 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -1880,6 +1880,8 @@ test.v5 check error View 'test.v5' references invalid table(s) or column(s) or f
test.v6 check status OK
drop view v1, v2, v3, v4, v5, v6;
drop table t2;
+drop function if exists f1;
+drop function if exists f2;
CREATE TABLE t1 (col1 time);
CREATE TABLE t2 (col1 time);
CREATE TABLE t3 (col1 time);
diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test
index fd5eb49858c..a56b697ea6b 100644
--- a/mysql-test/t/type_bit.test
+++ b/mysql-test/t/type_bit.test
@@ -16,7 +16,7 @@ select 0 + b'1111111111111111';
select 0 + b'1000000000000001';
--disable_warnings
-drop table if exists t1;
+drop table if exists t1,t2;
--enable_warnings
--error 1074
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index 9885566442f..cba2d75fb7c 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -1711,6 +1711,10 @@ CHECK TABLE v1, v2, v3, v4, v5, v6;
drop view v1, v2, v3, v4, v5, v6;
drop table t2;
+--disable_warnings
+drop function if exists f1;
+drop function if exists f2;
+--enable_warnings
CREATE TABLE t1 (col1 time);
CREATE TABLE t2 (col1 time);
CREATE TABLE t3 (col1 time);
diff --git a/sql/sp.cc b/sql/sp.cc
index 297e17de689..e875c30ab1b 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -986,13 +986,11 @@ int
sp_drop_procedure(THD *thd, sp_name *name)
{
int ret;
- bool found;
DBUG_ENTER("sp_drop_procedure");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
- found= sp_cache_remove(&thd->sp_proc_cache, name);
ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name);
- if (!found && !ret)
+ if (!ret)
sp_cache_invalidate();
DBUG_RETURN(ret);
}
@@ -1002,13 +1000,11 @@ int
sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics)
{
int ret;
- bool found;
DBUG_ENTER("sp_update_procedure");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
- found= sp_cache_remove(&thd->sp_proc_cache, name);
ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, chistics);
- if (!found && !ret)
+ if (!ret)
sp_cache_invalidate();
DBUG_RETURN(ret);
}
@@ -1099,13 +1095,11 @@ int
sp_drop_function(THD *thd, sp_name *name)
{
int ret;
- bool found;
DBUG_ENTER("sp_drop_function");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
- found= sp_cache_remove(&thd->sp_func_cache, name);
ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name);
- if (!found && !ret)
+ if (!ret)
sp_cache_invalidate();
DBUG_RETURN(ret);
}
@@ -1115,13 +1109,11 @@ int
sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics)
{
int ret;
- bool found;
DBUG_ENTER("sp_update_procedure");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
- found= sp_cache_remove(&thd->sp_func_cache, name);
ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, chistics);
- if (!found && !ret)
+ if (!ret)
sp_cache_invalidate();
DBUG_RETURN(ret);
}
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc
index c8f0ed6ba2d..135000d1443 100644
--- a/sql/sp_cache.cc
+++ b/sql/sp_cache.cc
@@ -24,17 +24,78 @@
static pthread_mutex_t Cversion_lock;
static ulong Cversion = 0;
-void
-sp_cache_init()
+
+/*
+ Cache of stored routines.
+*/
+
+class sp_cache
+{
+public:
+ ulong version;
+
+ sp_cache();
+ ~sp_cache();
+
+ inline void insert(sp_head *sp)
+ {
+ /* TODO: why don't we check return value? */
+ my_hash_insert(&m_hashtable, (const byte *)sp);
+ }
+
+ inline sp_head *lookup(char *name, uint namelen)
+ {
+ return (sp_head *)hash_search(&m_hashtable, (const byte *)name, namelen);
+ }
+
+#ifdef NOT_USED
+ inline bool remove(char *name, uint namelen)
+ {
+ sp_head *sp= lookup(name, namelen);
+ if (sp)
+ {
+ hash_delete(&m_hashtable, (byte *)sp);
+ return TRUE;
+ }
+ return FALSE;
+ }
+#endif
+
+ inline void remove_all()
+ {
+ cleanup();
+ init();
+ }
+
+private:
+ void init();
+ void cleanup();
+
+ /* All routines in this cache */
+ HASH m_hashtable;
+}; // class sp_cache
+
+
+/* Initialize the SP caching once at startup */
+
+void sp_cache_init()
{
pthread_mutex_init(&Cversion_lock, MY_MUTEX_INIT_FAST);
}
-void
-sp_cache_clear(sp_cache **cp)
+
+/*
+ Clear the cache *cp and set *cp to NULL.
+ SYNOPSIS
+ sp_cache_clear()
+ cp Pointer to cache to clear
+ NOTE
+ This function doesn't invalidate other caches.
+*/
+
+void sp_cache_clear(sp_cache **cp)
{
sp_cache *c= *cp;
-
if (c)
{
delete c;
@@ -42,85 +103,118 @@ sp_cache_clear(sp_cache **cp)
}
}
-void
-sp_cache_insert(sp_cache **cp, sp_head *sp)
+
+/*
+ Insert a routine into the cache.
+
+ SYNOPSIS
+ sp_cache_insert()
+ cp The cache to put routine into
+ sp Routine to insert.
+*/
+
+void sp_cache_insert(sp_cache **cp, sp_head *sp)
{
sp_cache *c= *cp;
if (! c)
- c= new sp_cache();
- if (c)
{
ulong v;
-
+ c= new sp_cache();
pthread_mutex_lock(&Cversion_lock); // LOCK
v= Cversion;
pthread_mutex_unlock(&Cversion_lock); // UNLOCK
-
- if (c->version < v)
- {
- if (*cp)
- c->remove_all();
- c->version= v;
- }
+ c->version= v;
+ }
+ if (c)
+ {
+ DBUG_PRINT("info",("sp_cache: inserting: %*s", sp->m_qname.length, sp->m_qname.str));
c->insert(sp);
if (*cp == NULL)
*cp= c;
}
}
-sp_head *
-sp_cache_lookup(sp_cache **cp, sp_name *name)
+
+/*
+ Look up a routine in the cache.
+ SYNOPSIS
+ sp_cache_lookup()
+ cp Cache to look into
+ name Name of rutine to find
+
+ NOTE
+ An obsolete (but not more obsolete then since last
+ sp_cache_flush_obsolete call) routine may be returned.
+
+ RETURN
+ The routine or
+ NULL if the routine not found.
+*/
+
+sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name)
{
- ulong v;
sp_cache *c= *cp;
-
- if (! c)
+ if (!c)
return NULL;
+ return c->lookup(name->m_qname.str, name->m_qname.length);
+}
+
+
+/*
+ Invalidate all routines in all caches.
+
+ SYNOPSIS
+ sp_cache_invalidate()
+
+ NOTE
+ This is called when a VIEW definition is modifed. We can't destroy sp_head
+ objects here as one may modify VIEW definitions from prelocking-free SPs.
+*/
+void sp_cache_invalidate()
+{
+ DBUG_PRINT("info",("sp_cache: invalidating"));
pthread_mutex_lock(&Cversion_lock); // LOCK
- v= Cversion;
+ Cversion++;
pthread_mutex_unlock(&Cversion_lock); // UNLOCK
-
- if (c->version < v)
- {
- c->remove_all();
- c->version= v;
- return NULL;
- }
- return c->lookup(name->m_qname.str, name->m_qname.length);
}
-bool
-sp_cache_remove(sp_cache **cp, sp_name *name)
+
+/*
+ Remove out-of-date SPs from the cache.
+
+ SYNOPSIS
+ sp_cache_flush_obsolete()
+ cp Cache to flush
+
+ NOTE
+ This invalidates pointers to sp_head objects this thread uses.
+ In practice that means 'dont call this function when inside SP'.
+*/
+
+void sp_cache_flush_obsolete(sp_cache **cp)
{
sp_cache *c= *cp;
- bool found= FALSE;
-
if (c)
{
ulong v;
-
pthread_mutex_lock(&Cversion_lock); // LOCK
- v= Cversion++;
+ v= Cversion;
pthread_mutex_unlock(&Cversion_lock); // UNLOCK
-
if (c->version < v)
+ {
+ DBUG_PRINT("info",("sp_cache: deleting all functions"));
+ /* We need to delete all elements. */
c->remove_all();
- else
- found= c->remove(name->m_qname.str, name->m_qname.length);
- c->version= v+1;
+ c->version= v;
+ }
}
- return found;
}
-void
-sp_cache_invalidate()
-{
- pthread_mutex_lock(&Cversion_lock); // LOCK
- Cversion++;
- pthread_mutex_unlock(&Cversion_lock); // UNLOCK
-}
+/*************************************************************************
+ Internal functions
+ *************************************************************************/
static byte *
hash_get_key_for_sp_head(const byte *ptr, uint *plen,
@@ -136,7 +230,6 @@ static void
hash_free_sp_head(void *p)
{
sp_head *sp= (sp_head *)p;
-
delete sp;
}
diff --git a/sql/sp_cache.h b/sql/sp_cache.h
index 14b2db97f5f..402647db9ea 100644
--- a/sql/sp_cache.h
+++ b/sql/sp_cache.h
@@ -25,94 +25,39 @@
/*
Stored procedures/functions cache. This is used as follows:
* Each thread has its own cache.
- * Each sp_head object is put into its thread cache before it is used, and
+ * Each sp_head object is put into its thread cache before it is used, and
then remains in the cache until deleted.
*/
class sp_head;
class sp_cache;
-/* Initialize the SP caching once at startup */
-void sp_cache_init();
+/*
+ Cache usage scenarios:
+ 1. Application-wide init:
+ sp_cache_init();
+
+ 2. SP execution in thread:
+ 2.1 While holding sp_head* pointers:
+
+ // look up a routine in the cache (no checks if it is up to date or not)
+ sp_cache_lookup();
+
+ sp_cache_insert();
+ sp_cache_invalidate();
+
+ 2.2 When not holding any sp_head* pointers (at query end):
+ sp_cache_flush_obsolete();
+
+ 3. Before thread exit:
+ sp_cache_clear();
+*/
-/* Clear the cache *cp and set *cp to NULL */
+void sp_cache_init();
void sp_cache_clear(sp_cache **cp);
-
-/* Insert an SP into cache. If 'cp' points to NULL, it's set to a new cache */
void sp_cache_insert(sp_cache **cp, sp_head *sp);
-
-/* Lookup an SP in cache */
sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name);
-
-/*
- Remove an SP from cache, and also bump the Cversion number so all other
- caches are invalidated.
- Returns true if something was removed.
-*/
-bool sp_cache_remove(sp_cache **cp, sp_name *name);
-
-/* Invalidate all existing SP caches by bumping Cversion number. */
void sp_cache_invalidate();
-
-
-/*
- *
- * The cache class. Don't use this directly, use the C API above
- *
- */
-
-class sp_cache
-{
-public:
-
- ulong version;
-
- sp_cache();
-
- ~sp_cache();
-
- void
- init();
-
- void
- cleanup();
-
- inline void
- insert(sp_head *sp)
- {
- my_hash_insert(&m_hashtable, (const byte *)sp);
- }
-
- inline sp_head *
- lookup(char *name, uint namelen)
- {
- return (sp_head *)hash_search(&m_hashtable, (const byte *)name, namelen);
- }
-
- inline bool
- remove(char *name, uint namelen)
- {
- sp_head *sp= lookup(name, namelen);
-
- if (sp)
- {
- hash_delete(&m_hashtable, (byte *)sp);
- return TRUE;
- }
- return FALSE;
- }
-
- inline void
- remove_all()
- {
- cleanup();
- init();
- }
-
-private:
-
- HASH m_hashtable;
-
-}; // class sp_cache
+void sp_cache_flush_obsolete(sp_cache **cp);
#endif /* _SP_CACHE_H_ */
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 677b3a98174..00463dc0a3b 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -5347,7 +5347,8 @@ void mysql_init_multi_delete(LEX *lex)
void mysql_parse(THD *thd, char *inBuf, uint length)
{
DBUG_ENTER("mysql_parse");
-
+ sp_cache_flush_obsolete(&thd->sp_proc_cache);
+ sp_cache_flush_obsolete(&thd->sp_func_cache);
mysql_init_query(thd, (uchar*) inBuf, length);
if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
{
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 18707cc6c87..f8b19dac3d1 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -73,6 +73,7 @@ Long data handling:
#include <m_ctype.h> // for isspace()
#include "sp_head.h"
#include "sp.h"
+#include "sp_cache.h"
#ifdef EMBEDDED_LIBRARY
/* include MYSQL_BIND headers */
#include <mysql.h>
@@ -1729,6 +1730,8 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
DBUG_ENTER("mysql_stmt_prepare");
DBUG_PRINT("prep_query", ("%s", packet));
+ sp_cache_flush_obsolete(&thd->sp_proc_cache);
+ sp_cache_flush_obsolete(&thd->sp_func_cache);
/*
If this is an SQLCOM_PREPARE, we also increase Com_prepare_sql.
@@ -1978,6 +1981,8 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
Prepared_statement *stmt;
DBUG_ENTER("mysql_stmt_execute");
+ sp_cache_flush_obsolete(&thd->sp_proc_cache);
+ sp_cache_flush_obsolete(&thd->sp_func_cache);
packet+= 9; /* stmt_id + 5 bytes of flags */
statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status);