Commit 7aaa1865 authored by unknown's avatar unknown

Fixed BUG#3583: query cache doesn't work for stored procedures.


mysql-test/r/sp.result:
  New test case for BUG#3583.
  (And current query is now set correctly.)
mysql-test/t/sp.test:
  New test case for BUG#3583.
sql/sp_head.cc:
  Set the thd->query and try to use cached query, if any, when executing a statement.
sql/sp_head.h:
  Extract the sub-query and store in sp_instr_stmt.
sql/sql_cache.cc:
  Keep the net->pkt_nr up-to-date when using query cache.
  This makes it work with stored procedures too.
sql/sql_cache.h:
  Keep the net->pkt_nr up-to-date when using query cache.
  This makes it work with stored procedures too.
sql/sql_yacc.yy:
  Extract the sub-query and store in sp_instr_stmt.
  (And it's never safe to cache references to local variables.)
parent a59095a7
...@@ -1719,10 +1719,10 @@ show processlist; ...@@ -1719,10 +1719,10 @@ show processlist;
end| end|
call bug4902_2()| call bug4902_2()|
Id User Host db Command Time State Info Id User Host db Command Time State Info
# root localhost test Query # NULL call bug4902_2() # root localhost test Query # NULL show processlist
call bug4902_2()| call bug4902_2()|
Id User Host db Command Time State Info Id User Host db Command Time State Info
# root localhost test Query # NULL call bug4902_2() # root localhost test Query # NULL show processlist
drop procedure bug4902_2| drop procedure bug4902_2|
drop table if exists t3| drop table if exists t3|
create procedure bug4904() create procedure bug4904()
...@@ -1849,6 +1849,51 @@ select @x| ...@@ -1849,6 +1849,51 @@ select @x|
NULL NULL
delete from t1| delete from t1|
drop procedure bug4941| drop procedure bug4941|
drop procedure if exists bug3583|
create procedure bug3583()
begin
declare c int;
select * from t1;
select count(*) into c from t1;
select c;
end|
insert into t1 values ("x", 3), ("y", 5)|
set @x = @@query_cache_size|
set global query_cache_size = 10*1024*1024|
flush status|
flush query cache|
show status like 'Qcache_hits'|
Variable_name Value
Qcache_hits 0
call bug3583()|
id data
x 3
y 5
c
2
show status like 'Qcache_hits'|
Variable_name Value
Qcache_hits 0
call bug3583()|
id data
x 3
y 5
c
2
call bug3583()|
id data
x 3
y 5
c
2
show status like 'Qcache_hits'|
Variable_name Value
Qcache_hits 2
set global query_cache_size = @x|
flush status|
flush query cache|
delete from t1|
drop procedure bug3583|
drop table if exists fac| drop table if exists fac|
create table fac (n int unsigned not null primary key, f bigint unsigned)| create table fac (n int unsigned not null primary key, f bigint unsigned)|
create procedure ifac(n int unsigned) create procedure ifac(n int unsigned)
......
...@@ -2022,6 +2022,41 @@ delete from t1| ...@@ -2022,6 +2022,41 @@ delete from t1|
drop procedure bug4941| drop procedure bug4941|
#
# BUG#3583: query cache doesn't work for stored procedures
#
--disable_warnings
drop procedure if exists bug3583|
--enable_warnings
create procedure bug3583()
begin
declare c int;
select * from t1;
select count(*) into c from t1;
select c;
end|
insert into t1 values ("x", 3), ("y", 5)|
set @x = @@query_cache_size|
set global query_cache_size = 10*1024*1024|
flush status|
flush query cache|
show status like 'Qcache_hits'|
call bug3583()|
show status like 'Qcache_hits'|
call bug3583()|
call bug3583()|
show status like 'Qcache_hits'|
set global query_cache_size = @x|
flush status|
flush query cache|
delete from t1|
drop procedure bug3583|
# #
# Some "real" examples # Some "real" examples
# #
......
...@@ -1153,9 +1153,25 @@ sp_instr_stmt::~sp_instr_stmt() ...@@ -1153,9 +1153,25 @@ sp_instr_stmt::~sp_instr_stmt()
int int
sp_instr_stmt::execute(THD *thd, uint *nextp) sp_instr_stmt::execute(THD *thd, uint *nextp)
{ {
char *query;
uint32 query_length;
DBUG_ENTER("sp_instr_stmt::execute"); DBUG_ENTER("sp_instr_stmt::execute");
DBUG_PRINT("info", ("command: %d", m_lex->sql_command)); DBUG_PRINT("info", ("command: %d", m_lex->sql_command));
int res= exec_stmt(thd, m_lex); int res;
query= thd->query;
query_length= thd->query_length;
if (!(res= alloc_query(thd, m_query.str, m_query.length+1)))
{
if (query_cache_send_result_to_client(thd,
thd->query, thd->query_length) <= 0)
{
res= exec_stmt(thd, m_lex);
query_cache_end_of_result(thd);
}
thd->query= query;
thd->query_length= query_length;
}
*nextp = m_ip+1; *nextp = m_ip+1;
DBUG_RETURN(res); DBUG_RETURN(res);
} }
......
...@@ -88,6 +88,7 @@ class sp_head :private Item_arena ...@@ -88,6 +88,7 @@ class sp_head :private Item_arena
my_bool m_simple_case; // TRUE if parsing simple case, FALSE otherwise my_bool m_simple_case; // TRUE if parsing simple case, FALSE otherwise
my_bool m_multi_results; // TRUE if a procedure with SELECT(s) my_bool m_multi_results; // TRUE if a procedure with SELECT(s)
my_bool m_in_handler; // TRUE if parser in a handler body my_bool m_in_handler; // TRUE if parser in a handler body
uchar *m_tmp_query; // Temporary pointer to sub query string
uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value
st_sp_chistics *m_chistics; st_sp_chistics *m_chistics;
ulong m_sql_mode; // For SHOW CREATE ulong m_sql_mode; // For SHOW CREATE
...@@ -314,9 +315,14 @@ class sp_instr_stmt : public sp_instr ...@@ -314,9 +315,14 @@ class sp_instr_stmt : public sp_instr
public: public:
LEX_STRING m_query; // For thd->query
sp_instr_stmt(uint ip, sp_pcontext *ctx) sp_instr_stmt(uint ip, sp_pcontext *ctx)
: sp_instr(ip, ctx), m_lex(NULL) : sp_instr(ip, ctx), m_lex(NULL)
{} {
m_query.str= 0;
m_query.length= 0;
}
virtual ~sp_instr_stmt(); virtual ~sp_instr_stmt();
......
...@@ -611,6 +611,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length) ...@@ -611,6 +611,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
header->result(result); header->result(result);
header->last_pkt_nr= net->pkt_nr;
BLOCK_UNLOCK_WR(query_block); BLOCK_UNLOCK_WR(query_block);
} }
else else
...@@ -1085,6 +1086,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) ...@@ -1085,6 +1086,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
ALIGN_SIZE(sizeof(Query_cache_result)))) ALIGN_SIZE(sizeof(Query_cache_result))))
break; // Client aborted break; // Client aborted
result_block = result_block->next; result_block = result_block->next;
thd->net.pkt_nr= query->last_pkt_nr; // Keep packet number updated
} while (result_block != first_result_block); } while (result_block != first_result_block);
#else #else
{ {
......
...@@ -116,6 +116,7 @@ struct Query_cache_query ...@@ -116,6 +116,7 @@ struct Query_cache_query
NET *wri; NET *wri;
ulong len; ulong len;
uint8 tbls_type; uint8 tbls_type;
unsigned int last_pkt_nr;
inline void init_n_lock(); inline void init_n_lock();
void unlock_n_destroy(); void unlock_n_destroy();
......
...@@ -1788,17 +1788,21 @@ sp_opt_default: ...@@ -1788,17 +1788,21 @@ sp_opt_default:
sp_proc_stmt: sp_proc_stmt:
{ {
Lex->sphead->reset_lex(YYTHD); LEX *lex= Lex;
lex->sphead->reset_lex(YYTHD);
lex->sphead->m_tmp_query= lex->tok_start;
} }
statement statement
{ {
LEX *lex= Lex; LEX *lex= Lex;
sp_head *sp= lex->sphead;
if ((lex->sql_command == SQLCOM_SELECT && !lex->result) || if ((lex->sql_command == SQLCOM_SELECT && !lex->result) ||
sp_multi_results_command(lex->sql_command)) sp_multi_results_command(lex->sql_command))
{ {
/* We maybe have one or more SELECT without INTO */ /* We maybe have one or more SELECT without INTO */
lex->sphead->m_multi_results= TRUE; sp->m_multi_results= TRUE;
} }
if (lex->sql_command == SQLCOM_CHANGE_DB) if (lex->sql_command == SQLCOM_CHANGE_DB)
{ /* "USE db" doesn't work in a procedure */ { /* "USE db" doesn't work in a procedure */
...@@ -1819,22 +1823,31 @@ sp_proc_stmt: ...@@ -1819,22 +1823,31 @@ sp_proc_stmt:
especially triggers a tremendously, but it's nothing we especially triggers a tremendously, but it's nothing we
can do about this at the moment. can do about this at the moment.
*/ */
if (lex->sphead->m_type != TYPE_ENUM_PROCEDURE) if (sp->m_type != TYPE_ENUM_PROCEDURE)
{ {
send_error(YYTHD, ER_SP_BADSTATEMENT); send_error(YYTHD, ER_SP_BADSTATEMENT);
YYABORT; YYABORT;
} }
else else
{ {
sp_instr_stmt *i=new sp_instr_stmt(lex->sphead->instructions(), sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(),
lex->spcont); lex->spcont);
/* Extract the query statement from the tokenizer:
The end is either lex->tok_end or tok->ptr. */
if (lex->ptr - lex->tok_end > 1)
i->m_query.length= lex->ptr - sp->m_tmp_query;
else
i->m_query.length= lex->tok_end - sp->m_tmp_query;
i->m_query.str= strmake_root(&YYTHD->mem_root,
(char *)sp->m_tmp_query,
i->m_query.length);
i->set_lex(lex); i->set_lex(lex);
lex->sphead->add_instr(i); sp->add_instr(i);
lex->sp_lex_in_use= TRUE; lex->sp_lex_in_use= TRUE;
} }
} }
lex->sphead->restore_lex(YYTHD); sp->restore_lex(YYTHD);
} }
| RETURN_SYM expr | RETURN_SYM expr
{ {
...@@ -6482,6 +6495,7 @@ simple_ident: ...@@ -6482,6 +6495,7 @@ simple_ident:
} }
$$ = (Item*) new Item_splocal($1, spv->offset); $$ = (Item*) new Item_splocal($1, spv->offset);
lex->variables_used= 1; lex->variables_used= 1;
lex->safe_to_cache_query=0;
} }
else else
{ {
......
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