1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +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:
unknown
2005-07-13 13:48:13 +04:00
parent 98a3bae33d
commit 11f9e513d7
16 changed files with 459 additions and 202 deletions

View File

@ -932,13 +932,94 @@ enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1,
PRELOCKED_UNDER_LOCK_TABLES= 2};
/*
Class that holds information about tables which were open and locked
by the thread. It is also used to save/restore this information in
push_open_tables_state()/pop_open_tables_state().
*/
class Open_tables_state
{
public:
/*
open_tables - list of regular tables in use by this thread
temporary_tables - list of temp tables in use by this thread
handler_tables - list of tables that were opened with HANDLER OPEN
and are still in use by this thread
*/
TABLE *open_tables, *temporary_tables, *handler_tables, *derived_tables;
/*
During a MySQL session, one can lock tables in two modes: automatic
or manual. In automatic mode all necessary tables are locked just before
statement execution, and all acquired locks are stored in 'lock'
member. Unlocking takes place automatically as well, when the
statement ends.
Manual mode comes into play when a user issues a 'LOCK TABLES'
statement. In this mode the user can only use the locked tables.
Trying to use any other tables will give an error. The locked tables are
stored in 'locked_tables' member. Manual locking is described in
the 'LOCK_TABLES' chapter of the MySQL manual.
See also lock_tables() for details.
*/
MYSQL_LOCK *lock;
/*
Tables that were locked with explicit or implicit LOCK TABLES.
(Implicit LOCK TABLES happens when we are prelocking tables for
execution of statement which uses stored routines. See description
THD::prelocked_mode for more info.)
*/
MYSQL_LOCK *locked_tables;
/*
prelocked_mode_type enum and prelocked_mode member are used for
indicating whenever "prelocked mode" is on, and what type of
"prelocked mode" is it.
Prelocked mode is used for execution of queries which explicitly
or implicitly (via views or triggers) use functions, thus may need
some additional tables (mentioned in query table list) for their
execution.
First open_tables() call for such query will analyse all functions
used by it and add all additional tables to table its list. It will
also mark this query as requiring prelocking. After that lock_tables()
will issue implicit LOCK TABLES for the whole table list and change
thd::prelocked_mode to non-0. All queries called in functions invoked
by the main query will use prelocked tables. Non-0 prelocked_mode
will also surpress mentioned analysys in those queries thus saving
cycles. Prelocked mode will be turned off once close_thread_tables()
for the main query will be called.
Note: Since not all "tables" present in table list are really locked
thd::prelocked_mode does not imply thd::locked_tables.
*/
prelocked_mode_type prelocked_mode;
ulong version;
uint current_tablenr;
Open_tables_state();
void set_open_tables_state(Open_tables_state *state)
{
*this= *state;
}
void reset_open_tables_state()
{
open_tables= temporary_tables= handler_tables= derived_tables= 0;
lock= locked_tables= 0;
prelocked_mode= NON_PRELOCKED;
}
};
/*
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
*/
class THD :public ilink,
public Statement
public Statement,
public Open_tables_state
{
public:
#ifdef EMBEDDED_LIBRARY
@ -1006,34 +1087,6 @@ public:
ulong master_access; /* Global privileges from mysql.user */
ulong db_access; /* Privileges for current db */
/*
open_tables - list of regular tables in use by this thread
temporary_tables - list of temp tables in use by this thread
handler_tables - list of tables that were opened with HANDLER OPEN
and are still in use by this thread
*/
TABLE *open_tables,*temporary_tables, *handler_tables, *derived_tables;
/*
During a MySQL session, one can lock tables in two modes: automatic
or manual. In automatic mode all necessary tables are locked just before
statement execution, and all acquired locks are stored in 'lock'
member. Unlocking takes place automatically as well, when the
statement ends.
Manual mode comes into play when a user issues a 'LOCK TABLES'
statement. In this mode the user can only use the locked tables.
Trying to use any other tables will give an error. The locked tables are
stored in 'locked_tables' member. Manual locking is described in
the 'LOCK_TABLES' chapter of the MySQL manual.
See also lock_tables() for details.
*/
MYSQL_LOCK *lock; /* Current locks */
/*
Tables that were locked with explicit or implicit LOCK TABLES.
(Implicit LOCK TABLES happens when we are prelocking tables for
execution of statement which uses stored routines. See description
THD::prelocked_mode for more info.)
*/
MYSQL_LOCK *locked_tables;
HASH handler_tables_hash;
/*
One thread can hold up to one named user-level lock. This variable
@ -1150,6 +1203,7 @@ public:
List <MYSQL_ERROR> warn_list;
uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
uint total_warn_count;
List <Open_tables_state> open_state_list;
/*
Id of current query. Statement can be reused to execute several queries
query_id is global in context of the whole MySQL server.
@ -1159,7 +1213,7 @@ public:
update auto-updatable fields (like auto_increment and timestamp).
*/
query_id_t query_id, warn_id;
ulong version, options, thread_id, col_access;
ulong options, thread_id, col_access;
/* Statement id is thread-wide. This counter is used to generate ids */
ulong statement_id_counter;
@ -1167,7 +1221,7 @@ public:
ulong row_count; // Row counter, mainly for errors and warnings
long dbug_thread_id;
pthread_t real_id;
uint current_tablenr,tmp_table,global_read_lock;
uint tmp_table, global_read_lock;
uint server_status,open_options,system_thread;
uint32 db_length;
uint select_number; //number of select (used for EXPLAIN)
@ -1218,31 +1272,6 @@ public:
long long_value;
} sys_var_tmp;
/*
prelocked_mode_type enum and prelocked_mode member are used for
indicating whenever "prelocked mode" is on, and what type of
"prelocked mode" is it.
Prelocked mode is used for execution of queries which explicitly
or implicitly (via views or triggers) use functions, thus may need
some additional tables (mentioned in query table list) for their
execution.
First open_tables() call for such query will analyse all functions
used by it and add all additional tables to table its list. It will
also mark this query as requiring prelocking. After that lock_tables()
will issue implicit LOCK TABLES for the whole table list and change
thd::prelocked_mode to non-0. All queries called in functions invoked
by the main query will use prelocked tables. Non-0 prelocked_mode
will also surpress mentioned analysys in those queries thus saving
cycles. Prelocked mode will be turned off once close_thread_tables()
for the main query will be called.
Note: Since not all "tables" present in table list are really locked
thd::relocked_mode does not imply thd::locked_tables.
*/
prelocked_mode_type prelocked_mode;
THD();
~THD();
@ -1428,8 +1457,11 @@ public:
(variables.sql_mode & MODE_STRICT_ALL_TABLES)));
}
void set_status_var_init();
bool push_open_tables_state();
void pop_open_tables_state();
};
#define tmp_disable_binlog(A) \
{ulong tmp_disable_binlog__save_options= (A)->options; \
(A)->options&= ~OPTION_BIN_LOG