Commit 42fec6b6 authored by unknown's avatar unknown

Merge mysql.com:/home/psergey/mysql-5.0-bug12228-r4

into mysql.com:/home/psergey/mysql-5.0-bug12228-r5


mysql-test/r/type_bit.result:
  Auto merged
mysql-test/t/sp-threads.test:
  Auto merged
mysql-test/t/type_bit.test:
  Auto merged
sql/sp.cc:
  Auto merged
sql/sql_parse.cc:
  Auto merged
sql/sql_prepare.cc:
  Auto merged
parents 6861b1bf 6b9ec78b
...@@ -37,6 +37,7 @@ Id User Host db Command Time State Info ...@@ -37,6 +37,7 @@ Id User Host db Command Time State Info
# root localhost test Sleep # NULL # root localhost test Sleep # NULL
# root localhost test Query # Locked update t1, t2 set val= 1 where id1=id2 # root localhost test Query # Locked update t1, t2 set val= 1 where id1=id2
# root localhost test Query # NULL show processlist # root localhost test Query # NULL show processlist
# root localhost test Sleep # NULL
unlock tables; unlock tables;
drop procedure bug9486; drop procedure bug9486;
drop table t1, t2; drop table t1, t2;
...@@ -64,3 +65,27 @@ insert into t1 (select f from v1); ...@@ -64,3 +65,27 @@ insert into t1 (select f from v1);
drop function bug11554; drop function bug11554;
drop table t1; drop table t1;
drop view v1; drop view v1;
drop procedure if exists p1;
drop procedure if exists p2;
create table t1 (s1 int)|
create procedure p1() select * from t1|
create procedure p2()
begin
insert into t1 values (1);
call p1();
select * from t1;
end|
use test;
lock table t1 write;
call p2();
use test;
drop procedure p1;
create procedure p1() select * from t1;
unlock tables;
s1
1
s1
1
drop procedure p1;
drop procedure p2;
drop table t1;
...@@ -34,7 +34,7 @@ select 0 + b'1111111111111111'; ...@@ -34,7 +34,7 @@ select 0 + b'1111111111111111';
select 0 + b'1000000000000001'; select 0 + b'1000000000000001';
0 + b'1000000000000001' 0 + b'1000000000000001'
32769 32769
drop table if exists t1; drop table if exists t1,t2;
create table t1 (a bit(65)); create table t1 (a bit(65));
ERROR 42000: Display width out of range for column 'a' (max = 64) ERROR 42000: Display width out of range for column 'a' (max = 64)
create table t1 (a bit(0)); create table t1 (a bit(0));
......
...@@ -1880,6 +1880,8 @@ test.v5 check error View 'test.v5' references invalid table(s) or column(s) or f ...@@ -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 test.v6 check status OK
drop view v1, v2, v3, v4, v5, v6; drop view v1, v2, v3, v4, v5, v6;
drop table t2; drop table t2;
drop function if exists f1;
drop function if exists f2;
CREATE TABLE t1 (col1 time); CREATE TABLE t1 (col1 time);
CREATE TABLE t2 (col1 time); CREATE TABLE t2 (col1 time);
CREATE TABLE t3 (col1 time); CREATE TABLE t3 (col1 time);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
connect (con1root,localhost,root,,); connect (con1root,localhost,root,,);
connect (con2root,localhost,root,,); connect (con2root,localhost,root,,);
connect (con3root,localhost,root,,);
connection con1root; connection con1root;
use test; use test;
...@@ -130,6 +131,48 @@ drop function bug11554; ...@@ -130,6 +131,48 @@ drop function bug11554;
drop table t1; drop table t1;
drop view v1; drop view v1;
# BUG#12228
--disable_warnings
drop procedure if exists p1;
drop procedure if exists p2;
--enable_warnings
connection con1root;
delimiter |;
create table t1 (s1 int)|
create procedure p1() select * from t1|
create procedure p2()
begin
insert into t1 values (1);
call p1();
select * from t1;
end|
delimiter ;|
connection con2root;
use test;
lock table t1 write;
connection con1root;
send call p2();
connection con3root;
use test;
drop procedure p1;
create procedure p1() select * from t1;
connection con2root;
unlock tables;
connection con1root;
# Crash will be here if we hit BUG#12228
reap;
drop procedure p1;
drop procedure p2;
drop table t1;
# #
# BUG#NNNN: New bug synopsis # BUG#NNNN: New bug synopsis
# #
......
...@@ -16,7 +16,7 @@ select 0 + b'1111111111111111'; ...@@ -16,7 +16,7 @@ select 0 + b'1111111111111111';
select 0 + b'1000000000000001'; select 0 + b'1000000000000001';
--disable_warnings --disable_warnings
drop table if exists t1; drop table if exists t1,t2;
--enable_warnings --enable_warnings
--error 1439 --error 1439
......
...@@ -1711,6 +1711,10 @@ CHECK TABLE v1, v2, v3, v4, v5, v6; ...@@ -1711,6 +1711,10 @@ CHECK TABLE v1, v2, v3, v4, v5, v6;
drop view v1, v2, v3, v4, v5, v6; drop view v1, v2, v3, v4, v5, v6;
drop table t2; drop table t2;
--disable_warnings
drop function if exists f1;
drop function if exists f2;
--enable_warnings
CREATE TABLE t1 (col1 time); CREATE TABLE t1 (col1 time);
CREATE TABLE t2 (col1 time); CREATE TABLE t2 (col1 time);
CREATE TABLE t3 (col1 time); CREATE TABLE t3 (col1 time);
......
...@@ -989,13 +989,11 @@ int ...@@ -989,13 +989,11 @@ int
sp_drop_procedure(THD *thd, sp_name *name) sp_drop_procedure(THD *thd, sp_name *name)
{ {
int ret; int ret;
bool found;
DBUG_ENTER("sp_drop_procedure"); DBUG_ENTER("sp_drop_procedure");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); 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); ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name);
if (!found && !ret) if (!ret)
sp_cache_invalidate(); sp_cache_invalidate();
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
...@@ -1005,13 +1003,11 @@ int ...@@ -1005,13 +1003,11 @@ int
sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics) sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics)
{ {
int ret; int ret;
bool found;
DBUG_ENTER("sp_update_procedure"); DBUG_ENTER("sp_update_procedure");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); 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); ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, chistics);
if (!found && !ret) if (!ret)
sp_cache_invalidate(); sp_cache_invalidate();
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
...@@ -1102,13 +1098,11 @@ int ...@@ -1102,13 +1098,11 @@ int
sp_drop_function(THD *thd, sp_name *name) sp_drop_function(THD *thd, sp_name *name)
{ {
int ret; int ret;
bool found;
DBUG_ENTER("sp_drop_function"); DBUG_ENTER("sp_drop_function");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); 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); ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name);
if (!found && !ret) if (!ret)
sp_cache_invalidate(); sp_cache_invalidate();
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
...@@ -1118,13 +1112,11 @@ int ...@@ -1118,13 +1112,11 @@ int
sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics) sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics)
{ {
int ret; int ret;
bool found;
DBUG_ENTER("sp_update_procedure"); DBUG_ENTER("sp_update_procedure");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); 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); ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, chistics);
if (!found && !ret) if (!ret)
sp_cache_invalidate(); sp_cache_invalidate();
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
......
...@@ -24,17 +24,78 @@ ...@@ -24,17 +24,78 @@
static pthread_mutex_t Cversion_lock; static pthread_mutex_t Cversion_lock;
static ulong Cversion = 0; 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); 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; sp_cache *c= *cp;
if (c) if (c)
{ {
delete c; delete c;
...@@ -42,85 +103,121 @@ sp_cache_clear(sp_cache **cp) ...@@ -42,85 +103,121 @@ 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.
TODO: Perhaps it will be more straightforward if in case we returned an
error from this function when we couldn't allocate sp_cache. (right
now failure to put routine into cache will cause a 'SP not found'
error to be reported at some later time)
*/
void sp_cache_insert(sp_cache **cp, sp_head *sp)
{ {
sp_cache *c= *cp; sp_cache *c= *cp;
if (! c) if (!c && (c= new sp_cache()))
c= new sp_cache();
if (c)
{ {
ulong v;
pthread_mutex_lock(&Cversion_lock); // LOCK pthread_mutex_lock(&Cversion_lock); // LOCK
v= Cversion; c->version= Cversion;
pthread_mutex_unlock(&Cversion_lock); // UNLOCK pthread_mutex_unlock(&Cversion_lock); // UNLOCK
if (c->version < v)
{
if (*cp)
c->remove_all();
c->version= v;
} }
if (c)
{
DBUG_PRINT("info",("sp_cache: inserting: %*s", sp->m_qname.length,
sp->m_qname.str));
c->insert(sp); c->insert(sp);
if (*cp == NULL) if (*cp == NULL)
*cp= c; *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; sp_cache *c= *cp;
if (!c)
if (! c)
return NULL; 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 pthread_mutex_lock(&Cversion_lock); // LOCK
v= Cversion; Cversion++;
pthread_mutex_unlock(&Cversion_lock); // UNLOCK 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; sp_cache *c= *cp;
bool found= FALSE;
if (c) if (c)
{ {
ulong v; ulong v;
pthread_mutex_lock(&Cversion_lock); // LOCK pthread_mutex_lock(&Cversion_lock); // LOCK
v= Cversion++; v= Cversion;
pthread_mutex_unlock(&Cversion_lock); // UNLOCK pthread_mutex_unlock(&Cversion_lock); // UNLOCK
if (c->version < v) if (c->version < v)
{
DBUG_PRINT("info",("sp_cache: deleting all functions"));
/* We need to delete all elements. */
c->remove_all(); c->remove_all();
else c->version= v;
found= c->remove(name->m_qname.str, name->m_qname.length); }
c->version= v+1;
} }
return found;
} }
void /*************************************************************************
sp_cache_invalidate() Internal functions
{ *************************************************************************/
pthread_mutex_lock(&Cversion_lock); // LOCK
Cversion++;
pthread_mutex_unlock(&Cversion_lock); // UNLOCK
}
static byte * static byte *
hash_get_key_for_sp_head(const byte *ptr, uint *plen, hash_get_key_for_sp_head(const byte *ptr, uint *plen,
...@@ -136,7 +233,6 @@ static void ...@@ -136,7 +233,6 @@ static void
hash_free_sp_head(void *p) hash_free_sp_head(void *p)
{ {
sp_head *sp= (sp_head *)p; sp_head *sp= (sp_head *)p;
delete sp; delete sp;
} }
......
...@@ -32,87 +32,32 @@ ...@@ -32,87 +32,32 @@
class sp_head; class sp_head;
class sp_cache; class sp_cache;
/* Initialize the SP caching once at startup */
void sp_cache_init();
/* Clear the cache *cp and set *cp to NULL */
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();
/* /*
* Cache usage scenarios:
* The cache class. Don't use this directly, use the C API above 1. Application-wide init:
* sp_cache_init();
*/
class sp_cache 2. SP execution in thread:
{ 2.1 While holding sp_head* pointers:
public:
ulong version; // look up a routine in the cache (no checks if it is up to date or not)
sp_cache_lookup();
sp_cache(); sp_cache_insert();
sp_cache_invalidate();
~sp_cache(); 2.2 When not holding any sp_head* pointers:
sp_cache_flush_obsolete();
void 3. Before thread exit:
init(); sp_cache_clear();
*/
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_init();
void sp_cache_clear(sp_cache **cp);
void sp_cache_insert(sp_cache **cp, sp_head *sp);
sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name);
void sp_cache_invalidate();
void sp_cache_flush_obsolete(sp_cache **cp);
#endif /* _SP_CACHE_H_ */ #endif /* _SP_CACHE_H_ */
...@@ -5340,11 +5340,12 @@ void mysql_init_multi_delete(LEX *lex) ...@@ -5340,11 +5340,12 @@ void mysql_init_multi_delete(LEX *lex)
void mysql_parse(THD *thd, char *inBuf, uint length) void mysql_parse(THD *thd, char *inBuf, uint length)
{ {
DBUG_ENTER("mysql_parse"); DBUG_ENTER("mysql_parse");
mysql_init_query(thd, (uchar*) inBuf, length); mysql_init_query(thd, (uchar*) inBuf, length);
if (query_cache_send_result_to_client(thd, inBuf, length) <= 0) if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
sp_cache_flush_obsolete(&thd->sp_proc_cache);
sp_cache_flush_obsolete(&thd->sp_func_cache);
if (!yyparse((void *)thd) && ! thd->is_fatal_error) if (!yyparse((void *)thd) && ! thd->is_fatal_error)
{ {
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
......
...@@ -73,6 +73,7 @@ Long data handling: ...@@ -73,6 +73,7 @@ Long data handling:
#include <m_ctype.h> // for isspace() #include <m_ctype.h> // for isspace()
#include "sp_head.h" #include "sp_head.h"
#include "sp.h" #include "sp.h"
#include "sp_cache.h"
#ifdef EMBEDDED_LIBRARY #ifdef EMBEDDED_LIBRARY
/* include MYSQL_BIND headers */ /* include MYSQL_BIND headers */
#include <mysql.h> #include <mysql.h>
...@@ -1783,6 +1784,9 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, ...@@ -1783,6 +1784,9 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
lex= thd->lex; lex= thd->lex;
lex->safe_to_cache_query= 0; lex->safe_to_cache_query= 0;
sp_cache_flush_obsolete(&thd->sp_proc_cache);
sp_cache_flush_obsolete(&thd->sp_func_cache);
error= yyparse((void *)thd) || thd->is_fatal_error || error= yyparse((void *)thd) || thd->is_fatal_error ||
thd->net.report_error || init_param_array(stmt); thd->net.report_error || init_param_array(stmt);
/* /*
...@@ -2060,6 +2064,8 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) ...@@ -2060,6 +2064,8 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
thd->protocol= stmt->protocol; // Switch to binary protocol thd->protocol= stmt->protocol; // Switch to binary protocol
if (!(specialflag & SPECIAL_NO_PRIOR)) if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR); my_pthread_setprio(pthread_self(),QUERY_PRIOR);
sp_cache_flush_obsolete(&thd->sp_proc_cache);
sp_cache_flush_obsolete(&thd->sp_func_cache);
mysql_execute_command(thd); mysql_execute_command(thd);
if (!(specialflag & SPECIAL_NO_PRIOR)) if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR); my_pthread_setprio(pthread_self(), WAIT_PRIOR);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment