mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/dlenev/src/mysql-5.0-mysqlproc mysql-test/r/sp-error.result: Auto merged mysql-test/t/sp-error.test: Auto merged sql/mysql_priv.h: Auto merged sql/sp.h: Auto merged sql/sql_base.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_lex.h: Auto merged sql/share/errmsg.txt: Manual merge. sql/sp.cc: Manual merge.
This commit is contained in:
@ -286,6 +286,19 @@ ERROR 42000: OUT or INOUT argument 2 for routine test.p is not a variable
|
|||||||
call p(42, @tmp_y, 43)|
|
call p(42, @tmp_y, 43)|
|
||||||
ERROR 42000: OUT or INOUT argument 3 for routine test.p is not a variable
|
ERROR 42000: OUT or INOUT argument 3 for routine test.p is not a variable
|
||||||
drop procedure p|
|
drop procedure p|
|
||||||
|
create procedure p() begin end|
|
||||||
|
lock table t1 read|
|
||||||
|
call p()|
|
||||||
|
unlock tables|
|
||||||
|
drop procedure p|
|
||||||
|
lock tables t1 read, mysql.proc write|
|
||||||
|
ERROR HY000: You can't combine write-locking of system 'mysql.proc' table with other tables
|
||||||
|
lock tables mysql.proc write, mysql.user write|
|
||||||
|
ERROR HY000: You can't combine write-locking of system 'mysql.proc' table with other tables
|
||||||
|
lock tables t1 read, mysql.proc read|
|
||||||
|
unlock tables|
|
||||||
|
lock tables mysql.proc write|
|
||||||
|
unlock tables|
|
||||||
create procedure bug1965()
|
create procedure bug1965()
|
||||||
begin
|
begin
|
||||||
declare c cursor for select val from t1 order by valname;
|
declare c cursor for select val from t1 order by valname;
|
||||||
@ -477,7 +490,7 @@ begin
|
|||||||
select * from t1;
|
select * from t1;
|
||||||
end|
|
end|
|
||||||
lock table t1 read|
|
lock table t1 read|
|
||||||
call bug9566()|
|
alter procedure bug9566 comment 'Some comment'|
|
||||||
ERROR HY000: Table 'proc' was not locked with LOCK TABLES
|
ERROR HY000: Table 'proc' was not locked with LOCK TABLES
|
||||||
unlock tables|
|
unlock tables|
|
||||||
drop procedure bug9566|
|
drop procedure bug9566|
|
||||||
|
@ -55,3 +55,12 @@ call bug11158();
|
|||||||
unlock tables;
|
unlock tables;
|
||||||
drop procedure bug11158;
|
drop procedure bug11158;
|
||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
|
drop function if exists bug11554;
|
||||||
|
drop view if exists v1;
|
||||||
|
create table t1 (i int);
|
||||||
|
create function bug11554 () returns int return 1;
|
||||||
|
create view v1 as select bug11554() as f;
|
||||||
|
insert into t1 (select f from v1);
|
||||||
|
drop function bug11554;
|
||||||
|
drop table t1;
|
||||||
|
drop view v1;
|
||||||
|
@ -386,6 +386,29 @@ call p(42, @tmp_y, 43)|
|
|||||||
drop procedure p|
|
drop procedure p|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Let us test that we can access mysql.proc table for routines
|
||||||
|
# definitions lookup without locking it explicitly.
|
||||||
|
#
|
||||||
|
create procedure p() begin end|
|
||||||
|
lock table t1 read|
|
||||||
|
# This should succeed
|
||||||
|
call p()|
|
||||||
|
unlock tables|
|
||||||
|
drop procedure p|
|
||||||
|
# Let us check restrictions which this ability puts on mysql.proc locking.
|
||||||
|
--error ER_WRONG_LOCK_OF_SYSTEM_TABLE
|
||||||
|
lock tables t1 read, mysql.proc write|
|
||||||
|
--error ER_WRONG_LOCK_OF_SYSTEM_TABLE
|
||||||
|
lock tables mysql.proc write, mysql.user write|
|
||||||
|
# Locking for read should be OK
|
||||||
|
lock tables t1 read, mysql.proc read|
|
||||||
|
unlock tables|
|
||||||
|
# You also should be able lock only mysql.proc for write
|
||||||
|
lock tables mysql.proc write|
|
||||||
|
unlock tables|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# BUG#1965
|
# BUG#1965
|
||||||
#
|
#
|
||||||
@ -676,9 +699,7 @@ create procedure bug6600()
|
|||||||
# BUG#9566: explicit LOCK TABLE and store procedures result in illegal state
|
# BUG#9566: explicit LOCK TABLE and store procedures result in illegal state
|
||||||
#
|
#
|
||||||
# We should not think that mysql.proc table does not exist if we are unable
|
# We should not think that mysql.proc table does not exist if we are unable
|
||||||
# to open it under LOCK TABLE or in prelocked mode. Probably this test
|
# to open it under LOCK TABLE or in prelocked mode.
|
||||||
# should be removed when Monty will allow access to mysql.proc without
|
|
||||||
# locking it.
|
|
||||||
#
|
#
|
||||||
--disable_warnings
|
--disable_warnings
|
||||||
drop procedure if exists bug9566|
|
drop procedure if exists bug9566|
|
||||||
@ -688,9 +709,11 @@ begin
|
|||||||
select * from t1;
|
select * from t1;
|
||||||
end|
|
end|
|
||||||
lock table t1 read|
|
lock table t1 read|
|
||||||
# This should fail because we forgot to lock mysql.proc table explicitly
|
# This should fail since we forgot to lock mysql.proc for writing
|
||||||
|
# explicitly, and we can't open mysql.proc for _writing_ if there
|
||||||
|
# are locked tables.
|
||||||
--error 1100
|
--error 1100
|
||||||
call bug9566()|
|
alter procedure bug9566 comment 'Some comment'|
|
||||||
unlock tables|
|
unlock tables|
|
||||||
# This should succeed
|
# This should succeed
|
||||||
drop procedure bug9566|
|
drop procedure bug9566|
|
||||||
|
@ -111,6 +111,25 @@ connection con1root;
|
|||||||
drop procedure bug11158;
|
drop procedure bug11158;
|
||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
|
|
||||||
|
#
|
||||||
|
# BUG#11554: Server crashes on statement indirectly using non-cached function
|
||||||
|
#
|
||||||
|
--disable_warnings
|
||||||
|
drop function if exists bug11554;
|
||||||
|
drop view if exists v1;
|
||||||
|
--enable_warnings
|
||||||
|
create table t1 (i int);
|
||||||
|
create function bug11554 () returns int return 1;
|
||||||
|
create view v1 as select bug11554() as f;
|
||||||
|
connection con2root;
|
||||||
|
# This should not crash server
|
||||||
|
insert into t1 (select f from v1);
|
||||||
|
# Clean-up
|
||||||
|
connection con1root;
|
||||||
|
drop function bug11554;
|
||||||
|
drop table t1;
|
||||||
|
drop view v1;
|
||||||
|
|
||||||
#
|
#
|
||||||
# BUG#NNNN: New bug synopsis
|
# BUG#NNNN: New bug synopsis
|
||||||
#
|
#
|
||||||
|
13
sql/lock.cc
13
sql/lock.cc
@ -425,6 +425,19 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
|
|||||||
tables+=table_ptr[i]->file->lock_count();
|
tables+=table_ptr[i]->file->lock_count();
|
||||||
lock_count++;
|
lock_count++;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
if (table_ptr[i]->s->system_table &&
|
||||||
|
table_ptr[i]->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE &&
|
||||||
|
count != 1)
|
||||||
|
{
|
||||||
|
my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0), table_ptr[i]->s->db,
|
||||||
|
table_ptr[i]->s->table_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(sql_lock= (MYSQL_LOCK*)
|
if (!(sql_lock= (MYSQL_LOCK*)
|
||||||
|
@ -735,7 +735,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok);
|
|||||||
bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create);
|
bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create);
|
||||||
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update);
|
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update);
|
||||||
TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
|
TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
|
||||||
bool *refresh);
|
bool *refresh, uint flags);
|
||||||
TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table);
|
TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table);
|
||||||
TABLE *find_locked_table(THD *thd, const char *db,const char *table_name);
|
TABLE *find_locked_table(THD *thd, const char *db,const char *table_name);
|
||||||
bool reopen_table(TABLE *table,bool locked);
|
bool reopen_table(TABLE *table,bool locked);
|
||||||
|
@ -5368,3 +5368,5 @@ ER_TOO_BIG_PRECISION 42000 S1009
|
|||||||
eng "Too big precision %d specified for column '%-.64s'. Maximum is %d."
|
eng "Too big precision %d specified for column '%-.64s'. Maximum is %d."
|
||||||
ER_SCALE_BIGGER_THAN_PRECISION 42000 S1009
|
ER_SCALE_BIGGER_THAN_PRECISION 42000 S1009
|
||||||
eng "Scale may not be larger than the precision (column '%-.64s')."
|
eng "Scale may not be larger than the precision (column '%-.64s')."
|
||||||
|
ER_WRONG_LOCK_OF_SYSTEM_TABLE
|
||||||
|
eng "You can't combine write-locking of system '%-.64s.%-.64s' table with other tables"
|
||||||
|
297
sql/sp.cc
297
sql/sp.cc
@ -62,57 +62,152 @@ bool mysql_proc_table_exists= 1;
|
|||||||
/* Tells what SP_DEFAULT_ACCESS should be mapped to */
|
/* Tells what SP_DEFAULT_ACCESS should be mapped to */
|
||||||
#define SP_DEFAULT_ACCESS_MAPPING SP_CONTAINS_SQL
|
#define SP_DEFAULT_ACCESS_MAPPING SP_CONTAINS_SQL
|
||||||
|
|
||||||
/* *opened=true means we opened ourselves */
|
|
||||||
static int
|
|
||||||
db_find_routine_aux(THD *thd, int type, sp_name *name,
|
|
||||||
enum thr_lock_type ltype, TABLE **tablep, bool *opened)
|
|
||||||
{
|
|
||||||
TABLE *table;
|
|
||||||
byte key[MAX_KEY_LENGTH]; // db, name, optional key length type
|
|
||||||
DBUG_ENTER("db_find_routine_aux");
|
|
||||||
DBUG_PRINT("enter", ("type: %d name: %*s",
|
|
||||||
type, name->m_name.length, name->m_name.str));
|
|
||||||
|
|
||||||
*opened= FALSE;
|
/*
|
||||||
*tablep= 0;
|
Close mysql.proc, opened with open_proc_table_for_read().
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
close_proc_table()
|
||||||
|
thd Thread context
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void close_proc_table(THD *thd)
|
||||||
|
{
|
||||||
|
close_thread_tables(thd);
|
||||||
|
thd->pop_open_tables_state();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Open the mysql.proc table for read.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
open_proc_table_for_read()
|
||||||
|
thd Thread context
|
||||||
|
|
||||||
|
NOTES
|
||||||
|
Thanks to restrictions which we put on opening and locking of
|
||||||
|
this table for writing, we can open and lock it for reading
|
||||||
|
even when we already have some other tables open and locked.
|
||||||
|
One must call close_proc_table() to close table opened with
|
||||||
|
this call.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
0 Error
|
||||||
|
# Pointer to TABLE object of mysql.proc
|
||||||
|
*/
|
||||||
|
|
||||||
|
static TABLE *open_proc_table_for_read(THD *thd)
|
||||||
|
{
|
||||||
|
TABLE_LIST tables;
|
||||||
|
TABLE *table;
|
||||||
|
bool old_open_tables= thd->open_tables != 0;
|
||||||
|
bool refresh;
|
||||||
|
DBUG_ENTER("open_proc_table");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Speed up things if mysql.proc doesn't exists. mysql_proc_table_exists
|
Speed up things if mysql.proc doesn't exists. mysql_proc_table_exists
|
||||||
is set when we create or read stored procedure or on flush privileges.
|
is set when we create or read stored procedure or on flush privileges.
|
||||||
*/
|
*/
|
||||||
if (!mysql_proc_table_exists && ltype == TL_READ)
|
if (!mysql_proc_table_exists)
|
||||||
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
if (thd->lex->proc_table)
|
if (thd->push_open_tables_state())
|
||||||
table= thd->lex->proc_table->table;
|
DBUG_RETURN(0);
|
||||||
else
|
|
||||||
{
|
|
||||||
for (table= thd->open_tables ; table ; table= table->next)
|
|
||||||
if (strcmp(table->s->db, "mysql") == 0 &&
|
|
||||||
strcmp(table->s->table_name, "proc") == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!table)
|
|
||||||
{
|
|
||||||
TABLE_LIST tables;
|
|
||||||
|
|
||||||
memset(&tables, 0, sizeof(tables));
|
bzero((char*) &tables, sizeof(tables));
|
||||||
tables.db= (char*)"mysql";
|
tables.db= (char*) "mysql";
|
||||||
tables.table_name= tables.alias= (char*)"proc";
|
tables.table_name= tables.alias= (char*)"proc";
|
||||||
if (! (table= open_ltable(thd, &tables, ltype)))
|
if (!(table= open_table(thd, &tables, thd->mem_root, &refresh,
|
||||||
{
|
MYSQL_LOCK_IGNORE_FLUSH)))
|
||||||
/*
|
{
|
||||||
Under explicit LOCK TABLES or in prelocked mode we should not
|
thd->pop_open_tables_state();
|
||||||
say that mysql.proc table does not exist if we are unable to
|
mysql_proc_table_exists= 0;
|
||||||
open it since this condition may be transient.
|
DBUG_RETURN(0);
|
||||||
*/
|
|
||||||
if (!(thd->locked_tables || thd->prelocked_mode))
|
|
||||||
mysql_proc_table_exists= 0;
|
|
||||||
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
|
|
||||||
}
|
|
||||||
*opened= TRUE;
|
|
||||||
}
|
}
|
||||||
mysql_proc_table_exists= 1;
|
|
||||||
|
DBUG_ASSERT(table->s->system_table);
|
||||||
|
|
||||||
|
table->reginfo.lock_type= TL_READ;
|
||||||
|
/*
|
||||||
|
If we have other tables opened, we have to ensure we are not blocked
|
||||||
|
by a flush tables or global read lock, as this could lead to a deadlock
|
||||||
|
*/
|
||||||
|
if (!(thd->lock= mysql_lock_tables(thd, &table, 1,
|
||||||
|
old_open_tables ?
|
||||||
|
(MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK |
|
||||||
|
MYSQL_LOCK_IGNORE_FLUSH) : 0)))
|
||||||
|
{
|
||||||
|
close_proc_table(thd);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
DBUG_RETURN(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Open the mysql.proc table for update.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
open_proc_table_for_update()
|
||||||
|
thd Thread context
|
||||||
|
|
||||||
|
NOTES
|
||||||
|
Table opened with this call should closed using close_thread_tables().
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
0 Error
|
||||||
|
# Pointer to TABLE object of mysql.proc
|
||||||
|
*/
|
||||||
|
|
||||||
|
static TABLE *open_proc_table_for_update(THD *thd)
|
||||||
|
{
|
||||||
|
TABLE_LIST tables;
|
||||||
|
TABLE *table;
|
||||||
|
DBUG_ENTER("open_proc_table");
|
||||||
|
|
||||||
|
bzero((char*) &tables, sizeof(tables));
|
||||||
|
tables.db= (char*) "mysql";
|
||||||
|
tables.table_name= tables.alias= (char*)"proc";
|
||||||
|
tables.lock_type= TL_WRITE;
|
||||||
|
|
||||||
|
table= open_ltable(thd, &tables, TL_WRITE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Under explicit LOCK TABLES or in prelocked mode we should not
|
||||||
|
say that mysql.proc table does not exist if we are unable to
|
||||||
|
open and lock it for writing since this condition may be
|
||||||
|
transient.
|
||||||
|
*/
|
||||||
|
if (!(thd->locked_tables || thd->prelocked_mode) || table)
|
||||||
|
mysql_proc_table_exists= test(table);
|
||||||
|
|
||||||
|
DBUG_RETURN(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Find row in open mysql.proc table representing stored routine.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
db_find_routine_aux()
|
||||||
|
thd Thread context
|
||||||
|
type Type of routine to find (function or procedure)
|
||||||
|
name Name of routine
|
||||||
|
table TABLE object for open mysql.proc table.
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
SP_OK - Routine found
|
||||||
|
SP_KEY_NOT_FOUND- No routine with given name
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table)
|
||||||
|
{
|
||||||
|
byte key[MAX_KEY_LENGTH]; // db, name, optional key length type
|
||||||
|
DBUG_ENTER("db_find_routine_aux");
|
||||||
|
DBUG_PRINT("enter", ("type: %d name: %*s",
|
||||||
|
type, name->m_name.length, name->m_name.str));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Create key to find row. We have to use field->store() to be able to
|
Create key to find row. We have to use field->store() to be able to
|
||||||
@ -122,9 +217,7 @@ db_find_routine_aux(THD *thd, int type, sp_name *name,
|
|||||||
same fields.
|
same fields.
|
||||||
*/
|
*/
|
||||||
if (name->m_name.length > table->field[1]->field_length)
|
if (name->m_name.length > table->field[1]->field_length)
|
||||||
{
|
|
||||||
DBUG_RETURN(SP_KEY_NOT_FOUND);
|
DBUG_RETURN(SP_KEY_NOT_FOUND);
|
||||||
}
|
|
||||||
table->field[0]->store(name->m_db.str, name->m_db.length, &my_charset_bin);
|
table->field[0]->store(name->m_db.str, name->m_db.length, &my_charset_bin);
|
||||||
table->field[1]->store(name->m_name.str, name->m_name.length,
|
table->field[1]->store(name->m_name.str, name->m_name.length,
|
||||||
&my_charset_bin);
|
&my_charset_bin);
|
||||||
@ -135,15 +228,33 @@ db_find_routine_aux(THD *thd, int type, sp_name *name,
|
|||||||
if (table->file->index_read_idx(table->record[0], 0,
|
if (table->file->index_read_idx(table->record[0], 0,
|
||||||
key, table->key_info->key_length,
|
key, table->key_info->key_length,
|
||||||
HA_READ_KEY_EXACT))
|
HA_READ_KEY_EXACT))
|
||||||
{
|
|
||||||
DBUG_RETURN(SP_KEY_NOT_FOUND);
|
DBUG_RETURN(SP_KEY_NOT_FOUND);
|
||||||
}
|
|
||||||
*tablep= table;
|
|
||||||
|
|
||||||
DBUG_RETURN(SP_OK);
|
DBUG_RETURN(SP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Find routine definition in mysql.proc table and create corresponding
|
||||||
|
sp_head object for it.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
db_find_routine()
|
||||||
|
thd Thread context
|
||||||
|
type Type of routine (TYPE_ENUM_PROCEDURE/...)
|
||||||
|
name Name of routine
|
||||||
|
sphp Out parameter in which pointer to created sp_head
|
||||||
|
object is returned (0 in case of error).
|
||||||
|
|
||||||
|
NOTE
|
||||||
|
This function may damage current LEX during execution, so it is good
|
||||||
|
idea to create temporary LEX and make it active before calling it.
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 - Success
|
||||||
|
non-0 - Error (may be one of special codes like SP_KEY_NOT_FOUND)
|
||||||
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
|
db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
|
||||||
{
|
{
|
||||||
@ -151,7 +262,6 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
|
|||||||
TABLE *table;
|
TABLE *table;
|
||||||
const char *params, *returns, *body;
|
const char *params, *returns, *body;
|
||||||
int ret;
|
int ret;
|
||||||
bool opened;
|
|
||||||
const char *definer;
|
const char *definer;
|
||||||
longlong created;
|
longlong created;
|
||||||
longlong modified;
|
longlong modified;
|
||||||
@ -165,8 +275,11 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
|
|||||||
DBUG_PRINT("enter", ("type: %d name: %*s",
|
DBUG_PRINT("enter", ("type: %d name: %*s",
|
||||||
type, name->m_name.length, name->m_name.str));
|
type, name->m_name.length, name->m_name.str));
|
||||||
|
|
||||||
ret= db_find_routine_aux(thd, type, name, TL_READ, &table, &opened);
|
*sphp= 0; // In case of errors
|
||||||
if (ret != SP_OK)
|
if (!(table= open_proc_table_for_read(thd)))
|
||||||
|
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
|
||||||
|
|
||||||
|
if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (table->s->fields != MYSQL_PROC_FIELD_COUNT)
|
if (table->s->fields != MYSQL_PROC_FIELD_COUNT)
|
||||||
@ -258,11 +371,8 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
|
|||||||
chistics.comment.str= ptr;
|
chistics.comment.str= ptr;
|
||||||
chistics.comment.length= length;
|
chistics.comment.length= length;
|
||||||
|
|
||||||
if (opened)
|
close_proc_table(thd);
|
||||||
{
|
table= 0;
|
||||||
opened= FALSE;
|
|
||||||
close_thread_tables(thd, 0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
String defstr;
|
String defstr;
|
||||||
@ -338,9 +448,8 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
if (table)
|
||||||
if (opened)
|
close_proc_table(thd);
|
||||||
close_thread_tables(thd);
|
|
||||||
DBUG_RETURN(ret);
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,7 +472,6 @@ db_create_routine(THD *thd, int type, sp_head *sp)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
TABLE_LIST tables;
|
|
||||||
char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
|
char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
|
||||||
char olddb[128];
|
char olddb[128];
|
||||||
bool dbchanged;
|
bool dbchanged;
|
||||||
@ -378,11 +486,7 @@ db_create_routine(THD *thd, int type, sp_head *sp)
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&tables, 0, sizeof(tables));
|
if (!(table= open_proc_table_for_update(thd)))
|
||||||
tables.db= (char*)"mysql";
|
|
||||||
tables.table_name= tables.alias= (char*)"proc";
|
|
||||||
|
|
||||||
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
|
|
||||||
ret= SP_OPEN_TABLE_FAILED;
|
ret= SP_OPEN_TABLE_FAILED;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -492,20 +596,18 @@ db_drop_routine(THD *thd, int type, sp_name *name)
|
|||||||
{
|
{
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
int ret;
|
int ret;
|
||||||
bool opened;
|
|
||||||
DBUG_ENTER("db_drop_routine");
|
DBUG_ENTER("db_drop_routine");
|
||||||
DBUG_PRINT("enter", ("type: %d name: %*s",
|
DBUG_PRINT("enter", ("type: %d name: %*s",
|
||||||
type, name->m_name.length, name->m_name.str));
|
type, name->m_name.length, name->m_name.str));
|
||||||
|
|
||||||
ret= db_find_routine_aux(thd, type, name, TL_WRITE, &table, &opened);
|
if (!(table= open_proc_table_for_update(thd)))
|
||||||
if (ret == SP_OK)
|
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
|
||||||
|
if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
|
||||||
{
|
{
|
||||||
if (table->file->delete_row(table->record[0]))
|
if (table->file->delete_row(table->record[0]))
|
||||||
ret= SP_DELETE_ROW_FAILED;
|
ret= SP_DELETE_ROW_FAILED;
|
||||||
}
|
}
|
||||||
|
close_thread_tables(thd);
|
||||||
if (opened)
|
|
||||||
close_thread_tables(thd);
|
|
||||||
DBUG_RETURN(ret);
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,8 +622,9 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
|
|||||||
DBUG_PRINT("enter", ("type: %d name: %*s",
|
DBUG_PRINT("enter", ("type: %d name: %*s",
|
||||||
type, name->m_name.length, name->m_name.str));
|
type, name->m_name.length, name->m_name.str));
|
||||||
|
|
||||||
ret= db_find_routine_aux(thd, type, name, TL_WRITE, &table, &opened);
|
if (!(table= open_proc_table_for_update(thd)))
|
||||||
if (ret == SP_OK)
|
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
|
||||||
|
if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
|
||||||
{
|
{
|
||||||
store_record(table,record[1]);
|
store_record(table,record[1]);
|
||||||
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
|
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
|
||||||
@ -539,8 +642,7 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
|
|||||||
if ((table->file->update_row(table->record[1],table->record[0])))
|
if ((table->file->update_row(table->record[1],table->record[0])))
|
||||||
ret= SP_WRITE_ROW_FAILED;
|
ret= SP_WRITE_ROW_FAILED;
|
||||||
}
|
}
|
||||||
if (opened)
|
close_thread_tables(thd);
|
||||||
close_thread_tables(thd);
|
|
||||||
DBUG_RETURN(ret);
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -742,20 +844,9 @@ sp_drop_db_routines(THD *thd, char *db)
|
|||||||
memset(key+keylen, (int)' ', 64-keylen); // Pad with space
|
memset(key+keylen, (int)' ', 64-keylen); // Pad with space
|
||||||
keylen= sizeof(key);
|
keylen= sizeof(key);
|
||||||
|
|
||||||
for (table= thd->open_tables ; table ; table= table->next)
|
ret= SP_OPEN_TABLE_FAILED;
|
||||||
if (strcmp(table->s->db, "mysql") == 0 &&
|
if (!(table= open_proc_table_for_update(thd)))
|
||||||
strcmp(table->s->table_name, "proc") == 0)
|
goto err;
|
||||||
break;
|
|
||||||
if (! table)
|
|
||||||
{
|
|
||||||
TABLE_LIST tables;
|
|
||||||
|
|
||||||
memset(&tables, 0, sizeof(tables));
|
|
||||||
tables.db= (char*)"mysql";
|
|
||||||
tables.table_name= tables.alias= (char*)"proc";
|
|
||||||
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
|
|
||||||
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret= SP_OK;
|
ret= SP_OK;
|
||||||
table->file->ha_index_init(0);
|
table->file->ha_index_init(0);
|
||||||
@ -765,7 +856,8 @@ sp_drop_db_routines(THD *thd, char *db)
|
|||||||
int nxtres;
|
int nxtres;
|
||||||
bool deleted= FALSE;
|
bool deleted= FALSE;
|
||||||
|
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
if (! table->file->delete_row(table->record[0]))
|
if (! table->file->delete_row(table->record[0]))
|
||||||
deleted= TRUE; /* We deleted something */
|
deleted= TRUE; /* We deleted something */
|
||||||
else
|
else
|
||||||
@ -785,6 +877,7 @@ sp_drop_db_routines(THD *thd, char *db)
|
|||||||
|
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
|
|
||||||
|
err:
|
||||||
DBUG_RETURN(ret);
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -978,9 +1071,7 @@ sp_find_function(THD *thd, sp_name *name, bool cache_only)
|
|||||||
if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name)) &&
|
if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name)) &&
|
||||||
!cache_only)
|
!cache_only)
|
||||||
{
|
{
|
||||||
if (db_find_routine(thd, TYPE_ENUM_FUNCTION, name, &sp) != SP_OK)
|
if (db_find_routine(thd, TYPE_ENUM_FUNCTION, name, &sp) == SP_OK)
|
||||||
sp= NULL;
|
|
||||||
else
|
|
||||||
sp_cache_insert(&thd->sp_func_cache, sp);
|
sp_cache_insert(&thd->sp_func_cache, sp);
|
||||||
}
|
}
|
||||||
DBUG_RETURN(sp);
|
DBUG_RETURN(sp);
|
||||||
@ -1058,26 +1149,6 @@ sp_show_status_function(THD *thd, const char *wild)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
sp_function_exists(THD *thd, sp_name *name)
|
|
||||||
{
|
|
||||||
TABLE *table;
|
|
||||||
bool ret= FALSE;
|
|
||||||
bool opened= FALSE;
|
|
||||||
DBUG_ENTER("sp_function_exists");
|
|
||||||
|
|
||||||
if (sp_cache_lookup(&thd->sp_func_cache, name) ||
|
|
||||||
db_find_routine_aux(thd, TYPE_ENUM_FUNCTION,
|
|
||||||
name, TL_READ,
|
|
||||||
&table, &opened) == SP_OK)
|
|
||||||
ret= TRUE;
|
|
||||||
if (opened)
|
|
||||||
close_thread_tables(thd, 0, 1);
|
|
||||||
thd->clear_error();
|
|
||||||
DBUG_RETURN(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Structure that represents element in the set of stored routines
|
Structure that represents element in the set of stored routines
|
||||||
used by statement or routine.
|
used by statement or routine.
|
||||||
@ -1276,8 +1347,6 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
|
|||||||
LEX *oldlex= thd->lex;
|
LEX *oldlex= thd->lex;
|
||||||
LEX *newlex= new st_lex;
|
LEX *newlex= new st_lex;
|
||||||
thd->lex= newlex;
|
thd->lex= newlex;
|
||||||
/* Pass hint pointer to mysql.proc table */
|
|
||||||
newlex->proc_table= oldlex->proc_table;
|
|
||||||
newlex->current_select= NULL;
|
newlex->current_select= NULL;
|
||||||
name.m_name.str= strchr(name.m_qname.str, '.');
|
name.m_name.str= strchr(name.m_qname.str, '.');
|
||||||
name.m_db.length= name.m_name.str - name.m_qname.str;
|
name.m_db.length= name.m_name.str - name.m_qname.str;
|
||||||
|
3
sql/sp.h
3
sql/sp.h
@ -74,9 +74,6 @@ sp_show_create_function(THD *thd, sp_name *name);
|
|||||||
int
|
int
|
||||||
sp_show_status_function(THD *thd, const char *wild);
|
sp_show_status_function(THD *thd, const char *wild);
|
||||||
|
|
||||||
bool
|
|
||||||
sp_function_exists(THD *thd, sp_name *name);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Procedures for pre-caching of stored routines and building table list
|
Procedures for pre-caching of stored routines and building table list
|
||||||
|
@ -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)
|
bool close_thread_table(THD *thd, TABLE **table_ptr)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("close_thread_table");
|
|
||||||
|
|
||||||
bool found_old_table= 0;
|
bool found_old_table= 0;
|
||||||
TABLE *table= *table_ptr;
|
TABLE *table= *table_ptr;
|
||||||
|
DBUG_ENTER("close_thread_table");
|
||||||
DBUG_ASSERT(table->key_read == 0);
|
DBUG_ASSERT(table->key_read == 0);
|
||||||
DBUG_ASSERT(table->file->inited == handler::NONE);
|
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
|
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
|
SYNOPSIS
|
||||||
** the table is not put in the thread-open-list
|
open_table()
|
||||||
** If the return value is NULL and refresh is set then one must close
|
thd Thread context
|
||||||
** all tables and retry the open
|
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,
|
TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||||
bool *refresh)
|
bool *refresh, uint flags)
|
||||||
{
|
{
|
||||||
reg1 TABLE *table;
|
reg1 TABLE *table;
|
||||||
char key[MAX_DBKEY_LENGTH];
|
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 (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
|
There is a refresh in progress for this table
|
||||||
** Wait until the table is freed or the thread is killed.
|
Wait until the table is freed or the thread is killed.
|
||||||
*/
|
*/
|
||||||
close_old_data_files(thd,thd->open_tables,0,0);
|
close_old_data_files(thd,thd->open_tables,0,0);
|
||||||
if (table->in_use != thd)
|
if (table->in_use != thd)
|
||||||
@ -1681,6 +1703,15 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
|
|||||||
if (error == 5)
|
if (error == 5)
|
||||||
DBUG_RETURN(0); // we have just opened VIEW
|
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))
|
if (Table_triggers_list::check_n_load(thd, db, name, entry))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
@ -1832,7 +1863,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter)
|
|||||||
}
|
}
|
||||||
(*counter)++;
|
(*counter)++;
|
||||||
if (!tables->table &&
|
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));
|
free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
|
||||||
if (tables->view)
|
if (tables->view)
|
||||||
@ -2003,7 +2034,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
|
|||||||
thd->current_tablenr= 0;
|
thd->current_tablenr= 0;
|
||||||
/* open_ltable can be used only for BASIC TABLEs */
|
/* open_ltable can be used only for BASIC TABLEs */
|
||||||
table_list->required_type= FRMTYPE_TABLE;
|
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)
|
refresh)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -156,6 +156,14 @@ bool foreign_key_prefix(Key *a, Key *b)
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
** Thread specific functions
|
** Thread specific functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
Open_tables_state::Open_tables_state()
|
||||||
|
:version(refresh_version)
|
||||||
|
{
|
||||||
|
reset_open_tables_state();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Pass nominal parameters to Statement constructor only to ensure that
|
Pass nominal parameters to Statement constructor only to ensure that
|
||||||
the destructor works OK in case of error. The main_mem_root will be
|
the destructor works OK in case of error. The main_mem_root will be
|
||||||
@ -164,6 +172,7 @@ bool foreign_key_prefix(Key *a, Key *b)
|
|||||||
|
|
||||||
THD::THD()
|
THD::THD()
|
||||||
:Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0),
|
:Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0),
|
||||||
|
Open_tables_state(),
|
||||||
user_time(0), global_read_lock(0), is_fatal_error(0),
|
user_time(0), global_read_lock(0), is_fatal_error(0),
|
||||||
rand_used(0), time_zone_used(0),
|
rand_used(0), time_zone_used(0),
|
||||||
last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0),
|
last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0),
|
||||||
@ -181,10 +190,8 @@ THD::THD()
|
|||||||
db_length= col_access=0;
|
db_length= col_access=0;
|
||||||
query_error= tmp_table_used= 0;
|
query_error= tmp_table_used= 0;
|
||||||
next_insert_id=last_insert_id=0;
|
next_insert_id=last_insert_id=0;
|
||||||
open_tables= temporary_tables= handler_tables= derived_tables= 0;
|
|
||||||
hash_clear(&handler_tables_hash);
|
hash_clear(&handler_tables_hash);
|
||||||
tmp_table=0;
|
tmp_table=0;
|
||||||
lock=locked_tables=0;
|
|
||||||
used_tables=0;
|
used_tables=0;
|
||||||
cuted_fields= sent_row_count= 0L;
|
cuted_fields= sent_row_count= 0L;
|
||||||
limit_found_rows= 0;
|
limit_found_rows= 0;
|
||||||
@ -230,7 +237,6 @@ THD::THD()
|
|||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
db_access=NO_ACCESS;
|
db_access=NO_ACCESS;
|
||||||
#endif
|
#endif
|
||||||
version=refresh_version; // For boot
|
|
||||||
*scramble= '\0';
|
*scramble= '\0';
|
||||||
|
|
||||||
init();
|
init();
|
||||||
@ -259,7 +265,6 @@ THD::THD()
|
|||||||
tablespace_op=FALSE;
|
tablespace_op=FALSE;
|
||||||
ulong tmp=sql_rnd_with_mutex();
|
ulong tmp=sql_rnd_with_mutex();
|
||||||
randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
|
randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
|
||||||
prelocked_mode= NON_PRELOCKED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1775,3 +1780,40 @@ void THD::set_status_var_init()
|
|||||||
{
|
{
|
||||||
bzero((char*) &status_var, sizeof(status_var));
|
bzero((char*) &status_var, sizeof(status_var));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
Handling of open and locked tables states.
|
||||||
|
|
||||||
|
This is used when we want to open/lock (and then close) some tables when
|
||||||
|
we already have a set of tables open and locked. We use these methods for
|
||||||
|
access to mysql.proc table to find definitions of stored routines.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
bool THD::push_open_tables_state()
|
||||||
|
{
|
||||||
|
Open_tables_state *state;
|
||||||
|
DBUG_ENTER("push_open_table_state");
|
||||||
|
/* Currently we only push things one level */
|
||||||
|
DBUG_ASSERT(open_state_list.elements == 0);
|
||||||
|
|
||||||
|
if (!(state= (Open_tables_state*) alloc(sizeof(*state))))
|
||||||
|
DBUG_RETURN(1); // Fatal error is set
|
||||||
|
/* Store state for currently open tables */
|
||||||
|
state->set_open_tables_state(this);
|
||||||
|
if (open_state_list.push_back(state, mem_root))
|
||||||
|
DBUG_RETURN(1); // Fatal error is set
|
||||||
|
reset_open_tables_state();
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void THD::pop_open_tables_state()
|
||||||
|
{
|
||||||
|
Open_tables_state *state;
|
||||||
|
DBUG_ENTER("pop_open_table_state");
|
||||||
|
/* Currently we only push things one level */
|
||||||
|
DBUG_ASSERT(open_state_list.elements == 1);
|
||||||
|
|
||||||
|
state= open_state_list.pop();
|
||||||
|
set_open_tables_state(state);
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
144
sql/sql_class.h
144
sql/sql_class.h
@ -932,13 +932,94 @@ enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1,
|
|||||||
PRELOCKED_UNDER_LOCK_TABLES= 2};
|
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
|
For each client connection we create a separate thread with THD serving as
|
||||||
a thread/connection descriptor
|
a thread/connection descriptor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class THD :public ilink,
|
class THD :public ilink,
|
||||||
public Statement
|
public Statement,
|
||||||
|
public Open_tables_state
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#ifdef EMBEDDED_LIBRARY
|
#ifdef EMBEDDED_LIBRARY
|
||||||
@ -1006,34 +1087,6 @@ public:
|
|||||||
ulong master_access; /* Global privileges from mysql.user */
|
ulong master_access; /* Global privileges from mysql.user */
|
||||||
ulong db_access; /* Privileges for current db */
|
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;
|
HASH handler_tables_hash;
|
||||||
/*
|
/*
|
||||||
One thread can hold up to one named user-level lock. This variable
|
One thread can hold up to one named user-level lock. This variable
|
||||||
@ -1150,6 +1203,7 @@ public:
|
|||||||
List <MYSQL_ERROR> warn_list;
|
List <MYSQL_ERROR> warn_list;
|
||||||
uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
|
uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
|
||||||
uint total_warn_count;
|
uint total_warn_count;
|
||||||
|
List <Open_tables_state> open_state_list;
|
||||||
/*
|
/*
|
||||||
Id of current query. Statement can be reused to execute several queries
|
Id of current query. Statement can be reused to execute several queries
|
||||||
query_id is global in context of the whole MySQL server.
|
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).
|
update auto-updatable fields (like auto_increment and timestamp).
|
||||||
*/
|
*/
|
||||||
query_id_t query_id, warn_id;
|
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 */
|
/* Statement id is thread-wide. This counter is used to generate ids */
|
||||||
ulong statement_id_counter;
|
ulong statement_id_counter;
|
||||||
@ -1167,7 +1221,7 @@ public:
|
|||||||
ulong row_count; // Row counter, mainly for errors and warnings
|
ulong row_count; // Row counter, mainly for errors and warnings
|
||||||
long dbug_thread_id;
|
long dbug_thread_id;
|
||||||
pthread_t real_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;
|
uint server_status,open_options,system_thread;
|
||||||
uint32 db_length;
|
uint32 db_length;
|
||||||
uint select_number; //number of select (used for EXPLAIN)
|
uint select_number; //number of select (used for EXPLAIN)
|
||||||
@ -1218,31 +1272,6 @@ public:
|
|||||||
long long_value;
|
long long_value;
|
||||||
} sys_var_tmp;
|
} 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();
|
||||||
~THD();
|
~THD();
|
||||||
|
|
||||||
@ -1428,8 +1457,11 @@ public:
|
|||||||
(variables.sql_mode & MODE_STRICT_ALL_TABLES)));
|
(variables.sql_mode & MODE_STRICT_ALL_TABLES)));
|
||||||
}
|
}
|
||||||
void set_status_var_init();
|
void set_status_var_init();
|
||||||
|
bool push_open_tables_state();
|
||||||
|
void pop_open_tables_state();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define tmp_disable_binlog(A) \
|
#define tmp_disable_binlog(A) \
|
||||||
{ulong tmp_disable_binlog__save_options= (A)->options; \
|
{ulong tmp_disable_binlog__save_options= (A)->options; \
|
||||||
(A)->options&= ~OPTION_BIN_LOG
|
(A)->options&= ~OPTION_BIN_LOG
|
||||||
|
@ -145,7 +145,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
|
|||||||
lex->found_semicolon= 0;
|
lex->found_semicolon= 0;
|
||||||
lex->safe_to_cache_query= 1;
|
lex->safe_to_cache_query= 1;
|
||||||
lex->time_zone_tables_used= 0;
|
lex->time_zone_tables_used= 0;
|
||||||
lex->leaf_tables_insert= lex->proc_table= lex->query_tables= 0;
|
lex->leaf_tables_insert= lex->query_tables= 0;
|
||||||
lex->query_tables_last= &lex->query_tables;
|
lex->query_tables_last= &lex->query_tables;
|
||||||
lex->variables_used= 0;
|
lex->variables_used= 0;
|
||||||
lex->select_lex.parent_lex= lex;
|
lex->select_lex.parent_lex= lex;
|
||||||
|
@ -719,7 +719,6 @@ typedef struct st_lex
|
|||||||
function)
|
function)
|
||||||
*/
|
*/
|
||||||
TABLE_LIST **query_tables_last;
|
TABLE_LIST **query_tables_last;
|
||||||
TABLE_LIST *proc_table; /* refer to mysql.proc if it was opened by VIEW */
|
|
||||||
/* store original leaf_tables for INSERT SELECT and PS/SP */
|
/* store original leaf_tables for INSERT SELECT and PS/SP */
|
||||||
TABLE_LIST *leaf_tables_insert;
|
TABLE_LIST *leaf_tables_insert;
|
||||||
|
|
||||||
|
@ -1760,7 +1760,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
|
|||||||
create_info, *extra_fields, *keys, 0,
|
create_info, *extra_fields, *keys, 0,
|
||||||
select_field_count))
|
select_field_count))
|
||||||
{
|
{
|
||||||
if (!(table= open_table(thd, create_table, thd->mem_root, (bool*) 0)))
|
if (!(table= open_table(thd, create_table, thd->mem_root, (bool*)0, 0)))
|
||||||
quick_rm_table(create_info->db_type, create_table->db,
|
quick_rm_table(create_info->db_type, create_table->db,
|
||||||
table_case_name(create_info, create_table->table_name));
|
table_case_name(create_info, create_table->table_name));
|
||||||
}
|
}
|
||||||
@ -3571,7 +3571,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
|||||||
bzero((void*) &tbl, sizeof(tbl));
|
bzero((void*) &tbl, sizeof(tbl));
|
||||||
tbl.db= new_db;
|
tbl.db= new_db;
|
||||||
tbl.table_name= tbl.alias= tmp_name;
|
tbl.table_name= tbl.alias= tmp_name;
|
||||||
new_table= open_table(thd, &tbl, thd->mem_root, 0);
|
new_table= open_table(thd, &tbl, thd->mem_root, 0, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -163,6 +163,13 @@ typedef struct st_table_share
|
|||||||
my_bool crashed;
|
my_bool crashed;
|
||||||
my_bool is_view;
|
my_bool is_view;
|
||||||
my_bool name_lock, replace_with_name_lock;
|
my_bool name_lock, replace_with_name_lock;
|
||||||
|
/*
|
||||||
|
TRUE if this is a system table like 'mysql.proc', which we want to be
|
||||||
|
able to open and lock even when we already have some tables open and
|
||||||
|
locked. To avoid deadlocks we have to put certain restrictions on
|
||||||
|
locking of this table for writing. FALSE - otherwise.
|
||||||
|
*/
|
||||||
|
my_bool system_table;
|
||||||
} TABLE_SHARE;
|
} TABLE_SHARE;
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user