diff options
author | Konstantin Osipov <konstantin@mysql.com> | 2008-07-03 23:41:22 +0400 |
---|---|---|
committer | Konstantin Osipov <konstantin@mysql.com> | 2008-07-03 23:41:22 +0400 |
commit | 7b8bfb2a93fbcaf1b43c343a0ab0c886da1d8f96 (patch) | |
tree | acd04510c1120addfb7290222a2147d86665993f /sql | |
parent | b6b6d98fff188128b35e69da4679d0f0bb48239f (diff) | |
download | mariadb-git-7b8bfb2a93fbcaf1b43c343a0ab0c886da1d8f96.tar.gz |
A fix for
Bug#12093 "SP not found on second PS execution if another thread
drops other SP in between" and
Bug#21294 "executing a prepared statement that executes a stored
function which was recreat"
Stored functions are resolved at prepared statement prepare only.
If someone flushes the stored functions cache between prepare and
execute, execution fails.
The fix is to detect the situation of the cache flush and automatically
reprepare the prepared statement after it.
mysql-test/r/ps_ddl.result:
Update results (Bug#12093 and Bug#21294, the test cases are already
in the source tree).
mysql-test/r/ps_ddl1.result:
Update results (Bug#12093 and Bug#21294, the test cases are already
in the source tree).
mysql-test/r/sp-error.result:
Update results (Bug#12093 and Bug#21294, the test cases are already
in the source tree).
mysql-test/t/ps_ddl.test:
Modify the test to not expect an error where there is no error
any more (Bug#12093, Bug#21294).
mysql-test/t/ps_ddl1.test:
Modify the test to not expect an error where there is no error
any more (Bug#12093, Bug#21294).
mysql-test/t/sp-error.test:
Modify the test to not expect an error where there is no error
any more (Bug#12093, Bug#21294).
sql/sp_cache.cc:
Implement sp_cache_version() -- returns the current version of
a stored routines cache.
sql/sp_cache.h:
Declare sp_cache_version().
sql/sql_prepare.cc:
Keep track of stored functions cache version, and invalidate
the statement if it changed between prepared statement
prepare and execute (and the statement actually uses stored routines).
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sp_cache.cc | 13 | ||||
-rw-r--r-- | sql/sp_cache.h | 1 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 33 |
3 files changed, 46 insertions, 1 deletions
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index cc6ba9ef1d0..64898915b7e 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -210,6 +210,19 @@ void sp_cache_flush_obsolete(sp_cache **cp) } +/** + Return the current version of the cache. +*/ + +ulong sp_cache_version(sp_cache **cp) +{ + sp_cache *c= *cp; + if (c) + return c->version; + return 0; +} + + /************************************************************************* Internal functions *************************************************************************/ diff --git a/sql/sp_cache.h b/sql/sp_cache.h index 9d34c9a2fb5..f4d44a1f29f 100644 --- a/sql/sp_cache.h +++ b/sql/sp_cache.h @@ -58,5 +58,6 @@ 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); +ulong sp_cache_version(sp_cache **cp); #endif /* _SP_CACHE_H_ */ diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 73ab28a233c..16e4812655e 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -169,6 +169,8 @@ private: SELECT_LEX and other classes). */ MEM_ROOT main_mem_root; + /* Version of the stored functions cache at the time of prepare. */ + ulong m_sp_cache_version; private: bool set_db(const char *db, uint db_length); bool set_parameters(String *expanded_query, @@ -2819,7 +2821,8 @@ Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg) param_array(0), param_count(0), last_errno(0), - flags((uint) IS_IN_USE) + flags((uint) IS_IN_USE), + m_sp_cache_version(0) { init_sql_alloc(&main_mem_root, thd_arg->variables.query_alloc_block_size, thd_arg->variables.query_prealloc_size); @@ -3072,6 +3075,20 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) init_stmt_after_parse(lex); state= Query_arena::PREPARED; flags&= ~ (uint) IS_IN_USE; + /* + This is for prepared statement validation purposes. + A statement looks up and pre-loads all its stored functions + at prepare. Later on, if a function is gone from the cache, + execute may fail. + Remember the cache version to be able to invalidate the prepared + statement at execute if it changes. + We only need to care about version of the stored functions cache: + if a prepared statement uses a stored procedure, it's indirect, + via a stored function. The only exception is SQLCOM_CALL, + but the latter one looks up the stored procedure each time + it's invoked, rather than once at prepare. + */ + m_sp_cache_version= sp_cache_version(&thd->sp_func_cache); /* Log COM_EXECUTE to the general log. Note, that in case of SQL @@ -3383,6 +3400,7 @@ Prepared_statement::swap_prepared_statement(Prepared_statement *copy) swap_variables(LEX_STRING, name, copy->name); /* Ditto */ swap_variables(char *, db, copy->db); + swap_variables(ulong, m_sp_cache_version, copy->m_sp_cache_version); DBUG_ASSERT(db_length == copy->db_length); DBUG_ASSERT(param_count == copy->param_count); @@ -3443,6 +3461,19 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) } /* + Reprepare the statement if we're using stored functions + and the version of the stored routines cache has changed. + */ + if (lex->uses_stored_routines() && + m_sp_cache_version != sp_cache_version(&thd->sp_func_cache) && + thd->m_reprepare_observer && + thd->m_reprepare_observer->report_error(thd)) + { + return TRUE; + } + + + /* For SHOW VARIABLES lex->result is NULL, as it's a non-SELECT command. For such queries we don't return an error and don't open a cursor -- the client library will recognize this case and |