mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Implementation of Monty's idea: Now we can open mysql.proc table for lookup
of stored routines definitions even if we already have some tables open and locked. To avoid deadlocks in this case we have to put certain restrictions on locking of mysql.proc table. This allows to use stored routines safely under LOCK TABLES without explicitly mentioning mysql.proc in the list of locked tables. It also fixes bug #11554 "Server crashes on statement indirectly using non-cached function". mysql-test/r/sp-error.result: Added test which checks that now we can read stored routines definitions under LOCK TABLES even if we have not locked mysql.proc explicitly. Also added check for restrictions which this ability puts on mysql.proc locking. Updated test for bug #9566 to correspond this new situation. mysql-test/r/sp-threads.result: Added test for bug #11554 "Server crashes on statement indirectly using non-cached function". mysql-test/t/sp-error.test: Added test which checks that now we can read stored routines definitions under LOCK TABLES even if we have not locked mysql.proc explicitly. Also added check for restrictions which this ability puts on mysql.proc locking. Updated test for bug #9566 to correspond this new situation. mysql-test/t/sp-threads.test: Added test for bug #11554 "Server crashes on statement indirectly using non-cached function". sql/lock.cc: get_lock_data(): To be able to open and lock for reading system tables like 'mysql.proc', when we already have some tables opened and locked, and avoid deadlocks we have to disallow write-locking of these tables with any other tables. sql/mysql_priv.h: open_table() has new parameter which allows to open table even if some-one has done a flush or holding namelock on it. sql/share/errmsg.txt: Added error message saying that one cannot write-lock some of system tables with any other tables. sql/sp.cc: open_proc_table_for_read()/close_proc_table(): Added functions to be able open and close mysql.proc table when we already have some tables open and locked. open_proc_table_for_update(): Added function to simplify opening of mysql.proc for updates. db_find_routine_aux()/db_find_routine()/db_update_routine()/... Moved responsibility for opening mysql.proc table from db_find_routine_aux() one level up, since this level knows better which type of table access for reading of for update it needs. sp_function_exists(): Removed unused function. sql/sp.h: sp_function_exists(): Removed unused function. sql/sql_base.cc: open_table(): Added new parameter which allows to open table even if some-one has done a flush or holding namelock on it. open_unireg_entry(): Mark 'mysql.proc' as a system table which has special restrictions on its locking, but thanks to them can be open and locked even if we already have some open and locked. sql/sql_class.cc: Moved THD members holding information about open and locked tables to separate Open_tables_state class to be able to save/restore this state easier. Added THD::push_open_tables_state()/pop_open_tables_state() methods for saving/restoring this state. sql/sql_class.h: Moved THD members holding information about open and locked tables to separate Open_tables_state class to be able to save/restore this state easier. Added THD::push_open_tables_state()/pop_open_tables_state() methods for saving/restoring this state. sql/sql_lex.cc: Removed LEX::proc_table member which was not really used. sql/sql_lex.h: Removed LEX::proc_table member which was not really used. sql/sql_table.cc: open_table() has new parameter which allows to open table even if some-one has done a flush or holding namelock on it. sql/table.h: Added TABLE_SHARE::system_table indicating that this table is system table like 'mysql.proc' and we want to be able to open and read-lock it even when we already have some tables open and locked (and because of this we have to put some restrictions on write locking it).
This commit is contained in:
@ -542,10 +542,9 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived,
|
||||
|
||||
bool close_thread_table(THD *thd, TABLE **table_ptr)
|
||||
{
|
||||
DBUG_ENTER("close_thread_table");
|
||||
|
||||
bool found_old_table= 0;
|
||||
TABLE *table= *table_ptr;
|
||||
DBUG_ENTER("close_thread_table");
|
||||
DBUG_ASSERT(table->key_read == 0);
|
||||
DBUG_ASSERT(table->file->inited == handler::NONE);
|
||||
|
||||
@ -972,18 +971,34 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
** open a table
|
||||
** Uses a cache of open tables to find a table not in use.
|
||||
** If refresh is a NULL pointer, then the is no version number checking and
|
||||
** the table is not put in the thread-open-list
|
||||
** If the return value is NULL and refresh is set then one must close
|
||||
** all tables and retry the open
|
||||
******************************************************************************/
|
||||
/*
|
||||
Open a table.
|
||||
|
||||
SYNOPSIS
|
||||
open_table()
|
||||
thd Thread context
|
||||
table_list Open first table in list
|
||||
refresh Pointer to memory that will be set to 1 if
|
||||
we need to close all tables and reopen them
|
||||
If this is a NULL pointer, then the is no version
|
||||
number checking and the table is not put in the
|
||||
thread-open-list
|
||||
flags Bitmap of flags to modify how open works:
|
||||
MYSQL_LOCK_IGNORE_FLUSH - Open table even if someone
|
||||
has done a flush or namelock on it.
|
||||
|
||||
IMPLEMENTATION
|
||||
Uses a cache of open tables to find a table not in use.
|
||||
|
||||
RETURN
|
||||
NULL Open failed. If refresh is set then one should close
|
||||
all other tables and retry the open
|
||||
# Success. Pointer to TABLE object for open table.
|
||||
*/
|
||||
|
||||
|
||||
TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||
bool *refresh)
|
||||
bool *refresh, uint flags)
|
||||
{
|
||||
reg1 TABLE *table;
|
||||
char key[MAX_DBKEY_LENGTH];
|
||||
@ -1096,9 +1111,16 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||
{
|
||||
if (table->s->version != refresh_version)
|
||||
{
|
||||
if (flags & MYSQL_LOCK_IGNORE_FLUSH)
|
||||
{
|
||||
/* Force close at once after usage */
|
||||
thd->version= table->s->version;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** There is a refresh in progress for this table
|
||||
** Wait until the table is freed or the thread is killed.
|
||||
There is a refresh in progress for this table
|
||||
Wait until the table is freed or the thread is killed.
|
||||
*/
|
||||
close_old_data_files(thd,thd->open_tables,0,0);
|
||||
if (table->in_use != thd)
|
||||
@ -1681,6 +1703,15 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
|
||||
if (error == 5)
|
||||
DBUG_RETURN(0); // we have just opened VIEW
|
||||
|
||||
/*
|
||||
We can't mark all tables in 'mysql' database as system since we don't
|
||||
allow to lock such tables for writing with any other tables (even with
|
||||
other system tables) and some privilege tables need this.
|
||||
*/
|
||||
if (!my_strcasecmp(system_charset_info, db, "mysql") &&
|
||||
!my_strcasecmp(system_charset_info, name, "proc"))
|
||||
entry->s->system_table= 1;
|
||||
|
||||
if (Table_triggers_list::check_n_load(thd, db, name, entry))
|
||||
goto err;
|
||||
|
||||
@ -1835,7 +1866,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter)
|
||||
}
|
||||
(*counter)++;
|
||||
if (!tables->table &&
|
||||
!(tables->table= open_table(thd, tables, &new_frm_mem, &refresh)))
|
||||
!(tables->table= open_table(thd, tables, &new_frm_mem, &refresh, 0)))
|
||||
{
|
||||
free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
|
||||
if (tables->view)
|
||||
@ -2010,7 +2041,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
|
||||
thd->current_tablenr= 0;
|
||||
/* open_ltable can be used only for BASIC TABLEs */
|
||||
table_list->required_type= FRMTYPE_TABLE;
|
||||
while (!(table= open_table(thd, table_list, thd->mem_root, &refresh)) &&
|
||||
while (!(table= open_table(thd, table_list, thd->mem_root, &refresh, 0)) &&
|
||||
refresh)
|
||||
;
|
||||
|
||||
|
Reference in New Issue
Block a user