mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
Bug#17204 "second CALL to procedure crashes Server"
Bug#18282 "INFORMATION_SCHEMA.TABLES provides inconsistent info about invalid views" This bug caused crashes or resulted in wrong data being returned when one tried to obtain information from I_S tables about views using stored functions. It was caused by the fact that we were using LEX representing statement which were doing select from I_S tables as active LEX when contents of I_S table were built. So state of this LEX both affected and was affected by open_tables() calls which happened during this process. This resulted in wrong behavior and in violations of some of invariants which caused crashes. This fix tries to solve this problem by properly saving/resetting and restoring part of LEX which affects and is affected by the process of opening tables and views in get_all_tables() routine. To simplify things we separated this part of LEX in a new class and made LEX its descendant. mysql-test/r/information_schema_db.result: test case mysql-test/t/information_schema_db.test: test case sql/sql_lex.cc: To simplify saving/resetting and restoring part of LEX which affects and is affected by the process of opening tables and views we moved it to new class Query_tables_list and made LEX descendant of this class. Also introduced two LEX methods which can be used to save and reset or to restore this state. sql/sql_lex.h: To simplify saving/resetting and restoring part of LEX which affects and is affected by the process of opening tables and views we moved it to new class Query_tables_list and made LEX descendant of this class. Also introduced two LEX methods which can be used to save and reset or to restore this state. sql/sql_show.cc: Now in get_all_tables() routine we properly save/reset and restore part of LEX (statement table list and information about routines used) which affects and is affected by the process of opening tables and views. sql/sql_table.cc: Now we clean-up LEX after opening table (view) in two stages. In the first stage we call LEX::cleanup_after_one_table_open() to clean-up selects lists and derived tables state. In the second stage which happens after close_thread_tables() is invoked we call Query_tables_list::reset_query_tables_list(FALSE) to rollback changes in Query_tables_list.
This commit is contained in:
parent
6257ab54eb
commit
128c3942a8
6 changed files with 308 additions and 87 deletions
|
@ -1,3 +1,7 @@
|
|||
drop table if exists t1,t2;
|
||||
drop view if exists v1,v2;
|
||||
drop function if exists f1;
|
||||
drop function if exists f2;
|
||||
use INFORMATION_SCHEMA;
|
||||
show tables;
|
||||
Tables_in_information_schema
|
||||
|
@ -24,10 +28,12 @@ TABLE_CONSTRAINTS
|
|||
TABLE_PRIVILEGES
|
||||
TRIGGERS
|
||||
create database `inf%`;
|
||||
create database mbase;
|
||||
use `inf%`;
|
||||
show tables;
|
||||
Tables_in_inf%
|
||||
grant all privileges on `inf%`.* to 'mysqltest_1'@'localhost';
|
||||
grant all privileges on `mbase`.* to 'mysqltest_1'@'localhost';
|
||||
create table t1 (f1 int);
|
||||
create function func1(curr_int int) returns int
|
||||
begin
|
||||
|
@ -36,9 +42,58 @@ select max(f1) from t1 into ret_val;
|
|||
return ret_val;
|
||||
end|
|
||||
create view v1 as select f1 from t1 where f1 = func1(f1);
|
||||
create function func2() returns int return 1;
|
||||
use mbase;
|
||||
create procedure p1 ()
|
||||
begin
|
||||
select table_name from information_schema.key_column_usage
|
||||
order by table_name;
|
||||
end|
|
||||
create table t1
|
||||
(f1 int(10) unsigned not null,
|
||||
f2 varchar(100) not null,
|
||||
primary key (f1), unique key (f2));
|
||||
select * from information_schema.tables;
|
||||
call mbase.p1();
|
||||
call mbase.p1();
|
||||
call mbase.p1();
|
||||
use `inf%`;
|
||||
drop user mysqltest_1@localhost;
|
||||
drop table t1;
|
||||
select table_name, table_type, table_comment from information_schema.tables
|
||||
where table_schema='inf%' and func2();
|
||||
table_name table_type table_comment
|
||||
v1 VIEW View 'inf%.v1' references invalid table(s) or column(s) or function(s) or define
|
||||
select table_name, table_type, table_comment from information_schema.tables
|
||||
where table_schema='inf%' and func2();
|
||||
table_name table_type table_comment
|
||||
v1 VIEW View 'inf%.v1' references invalid table(s) or column(s) or function(s) or define
|
||||
drop view v1;
|
||||
drop function func1;
|
||||
drop table t1;
|
||||
drop function func2;
|
||||
drop database `inf%`;
|
||||
drop procedure mbase.p1;
|
||||
drop database mbase;
|
||||
use test;
|
||||
create table t1 (i int);
|
||||
create function f1 () returns int return (select max(i) from t1);
|
||||
create view v1 as select f1();
|
||||
create table t2 (id int);
|
||||
create function f2 () returns int return (select max(i) from t2);
|
||||
create view v2 as select f2();
|
||||
drop table t2;
|
||||
select table_name, table_type, table_comment from information_schema.tables
|
||||
where table_schema='test';
|
||||
table_name table_type table_comment
|
||||
t1 BASE TABLE
|
||||
v1 VIEW VIEW
|
||||
v2 VIEW View 'test.v2' references invalid table(s) or column(s) or function(s) or define
|
||||
drop table t1;
|
||||
select table_name, table_type, table_comment from information_schema.tables
|
||||
where table_schema='test';
|
||||
table_name table_type table_comment
|
||||
v1 VIEW View 'test.v1' references invalid table(s) or column(s) or function(s) or define
|
||||
v2 VIEW View 'test.v2' references invalid table(s) or column(s) or function(s) or define
|
||||
drop function f1;
|
||||
drop function f2;
|
||||
drop view v1, v2;
|
||||
|
|
|
@ -1,16 +1,25 @@
|
|||
-- source include/testdb_only.inc
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1,t2;
|
||||
drop view if exists v1,v2;
|
||||
drop function if exists f1;
|
||||
drop function if exists f2;
|
||||
--enable_warnings
|
||||
|
||||
use INFORMATION_SCHEMA;
|
||||
--replace_result Tables_in_INFORMATION_SCHEMA Tables_in_information_schema
|
||||
show tables;
|
||||
--replace_result 'Tables_in_INFORMATION_SCHEMA (T%)' 'Tables_in_information_schema (T%)'
|
||||
show tables from INFORMATION_SCHEMA like 'T%';
|
||||
create database `inf%`;
|
||||
create database mbase;
|
||||
use `inf%`;
|
||||
show tables;
|
||||
|
||||
#
|
||||
# Bug#18113 SELECT * FROM information_schema.xxx crashes server
|
||||
# Bug#17204 second CALL to procedure crashes Server
|
||||
# Crash happened when one selected data from one of INFORMATION_SCHEMA
|
||||
# tables and in order to build its contents server had to open view which
|
||||
# used stored function and table or view on which one had not global or
|
||||
|
@ -18,6 +27,7 @@ show tables;
|
|||
# privileges at all).
|
||||
#
|
||||
grant all privileges on `inf%`.* to 'mysqltest_1'@'localhost';
|
||||
grant all privileges on `mbase`.* to 'mysqltest_1'@'localhost';
|
||||
create table t1 (f1 int);
|
||||
delimiter |;
|
||||
create function func1(curr_int int) returns int
|
||||
|
@ -28,15 +38,63 @@ begin
|
|||
end|
|
||||
delimiter ;|
|
||||
create view v1 as select f1 from t1 where f1 = func1(f1);
|
||||
create function func2() returns int return 1;
|
||||
|
||||
use mbase;
|
||||
delimiter |;
|
||||
create procedure p1 ()
|
||||
begin
|
||||
select table_name from information_schema.key_column_usage
|
||||
order by table_name;
|
||||
end|
|
||||
delimiter ;|
|
||||
|
||||
create table t1
|
||||
(f1 int(10) unsigned not null,
|
||||
f2 varchar(100) not null,
|
||||
primary key (f1), unique key (f2));
|
||||
|
||||
connect (user1,localhost,mysqltest_1,,);
|
||||
connection user1;
|
||||
--disable_result_log
|
||||
select * from information_schema.tables;
|
||||
call mbase.p1();
|
||||
call mbase.p1();
|
||||
call mbase.p1();
|
||||
--enable_result_log
|
||||
|
||||
connection default;
|
||||
use `inf%`;
|
||||
drop user mysqltest_1@localhost;
|
||||
drop table t1;
|
||||
select table_name, table_type, table_comment from information_schema.tables
|
||||
where table_schema='inf%' and func2();
|
||||
select table_name, table_type, table_comment from information_schema.tables
|
||||
where table_schema='inf%' and func2();
|
||||
drop view v1;
|
||||
drop function func1;
|
||||
drop table t1;
|
||||
drop function func2;
|
||||
|
||||
drop database `inf%`;
|
||||
drop procedure mbase.p1;
|
||||
drop database mbase;
|
||||
|
||||
#
|
||||
# Bug#18282 INFORMATION_SCHEMA.TABLES provides inconsistent info about invalid views
|
||||
#
|
||||
use test;
|
||||
create table t1 (i int);
|
||||
create function f1 () returns int return (select max(i) from t1);
|
||||
create view v1 as select f1();
|
||||
create table t2 (id int);
|
||||
create function f2 () returns int return (select max(i) from t2);
|
||||
create view v2 as select f2();
|
||||
drop table t2;
|
||||
select table_name, table_type, table_comment from information_schema.tables
|
||||
where table_schema='test';
|
||||
drop table t1;
|
||||
select table_name, table_type, table_comment from information_schema.tables
|
||||
where table_schema='test';
|
||||
drop function f1;
|
||||
drop function f2;
|
||||
drop view v1, v2;
|
||||
|
|
108
sql/sql_lex.cc
108
sql/sql_lex.cc
|
@ -151,8 +151,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
|
|||
lex->found_semicolon= 0;
|
||||
lex->safe_to_cache_query= 1;
|
||||
lex->time_zone_tables_used= 0;
|
||||
lex->leaf_tables_insert= lex->query_tables= 0;
|
||||
lex->query_tables_last= &lex->query_tables;
|
||||
lex->leaf_tables_insert= 0;
|
||||
lex->variables_used= 0;
|
||||
lex->empty_field_list_on_rset= 0;
|
||||
lex->select_lex.select_number= 1;
|
||||
|
@ -175,14 +174,9 @@ void lex_start(THD *thd, uchar *buf,uint length)
|
|||
lex->sphead= NULL;
|
||||
lex->spcont= NULL;
|
||||
lex->proc_list.first= 0;
|
||||
lex->query_tables_own_last= 0;
|
||||
lex->escape_used= FALSE;
|
||||
lex->reset_query_tables_list(FALSE);
|
||||
|
||||
if (lex->sroutines.records)
|
||||
my_hash_reset(&lex->sroutines);
|
||||
lex->sroutines_list.empty();
|
||||
lex->sroutines_list_own_last= lex->sroutines_list.next;
|
||||
lex->sroutines_list_own_elements= 0;
|
||||
lex->nest_level=0 ;
|
||||
lex->allow_sum_func= 0;
|
||||
lex->in_sum_func= NULL;
|
||||
|
@ -1614,6 +1608,52 @@ void st_select_lex::print_limit(THD *thd, String *str)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Initialize (or reset) Query_tables_list object.
|
||||
|
||||
SYNOPSIS
|
||||
reset_query_tables_list()
|
||||
init TRUE - we should perform full initialization of object with
|
||||
allocating needed memory
|
||||
FALSE - object is already initialized so we should only reset
|
||||
its state so it can be used for parsing/processing
|
||||
of new statement
|
||||
|
||||
DESCRIPTION
|
||||
This method initializes Query_tables_list so it can be used as part
|
||||
of LEX object for parsing/processing of statement. One can also use
|
||||
this method to reset state of already initialized Query_tables_list
|
||||
so it can be used for processing of new statement.
|
||||
*/
|
||||
|
||||
void Query_tables_list::reset_query_tables_list(bool init)
|
||||
{
|
||||
query_tables= 0;
|
||||
query_tables_last= &query_tables;
|
||||
query_tables_own_last= 0;
|
||||
if (init)
|
||||
hash_init(&sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0);
|
||||
else if (sroutines.records)
|
||||
my_hash_reset(&sroutines);
|
||||
sroutines_list.empty();
|
||||
sroutines_list_own_last= sroutines_list.next;
|
||||
sroutines_list_own_elements= 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Destroy Query_tables_list object with freeing all resources used by it.
|
||||
|
||||
SYNOPSIS
|
||||
destroy_query_tables_list()
|
||||
*/
|
||||
|
||||
void Query_tables_list::destroy_query_tables_list()
|
||||
{
|
||||
hash_free(&sroutines);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Initialize LEX object.
|
||||
|
||||
|
@ -1630,12 +1670,9 @@ void st_select_lex::print_limit(THD *thd, String *str)
|
|||
|
||||
st_lex::st_lex()
|
||||
:result(0), yacc_yyss(0), yacc_yyvs(0),
|
||||
sql_command(SQLCOM_END), query_tables_own_last(0)
|
||||
sql_command(SQLCOM_END)
|
||||
{
|
||||
hash_init(&sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0);
|
||||
sroutines_list.empty();
|
||||
sroutines_list_own_last= sroutines_list.next;
|
||||
sroutines_list_own_elements= 0;
|
||||
reset_query_tables_list(TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2019,6 +2056,11 @@ void st_lex::link_first_table_back(TABLE_LIST *first,
|
|||
|
||||
SYNOPSIS
|
||||
st_lex::cleanup_after_one_table_open()
|
||||
|
||||
NOTE
|
||||
This method is mostly responsible for cleaning up of selects lists and
|
||||
derived tables state. To rollback changes in Query_tables_list one has
|
||||
to call Query_tables_list::reset_query_tables_list(FALSE).
|
||||
*/
|
||||
|
||||
void st_lex::cleanup_after_one_table_open()
|
||||
|
@ -2045,11 +2087,41 @@ void st_lex::cleanup_after_one_table_open()
|
|||
select_lex.cut_subtree();
|
||||
}
|
||||
time_zone_tables_used= 0;
|
||||
if (sroutines.records)
|
||||
my_hash_reset(&sroutines);
|
||||
sroutines_list.empty();
|
||||
sroutines_list_own_last= sroutines_list.next;
|
||||
sroutines_list_own_elements= 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Save current state of Query_tables_list for this LEX, and prepare it
|
||||
for processing of new statemnt.
|
||||
|
||||
SYNOPSIS
|
||||
reset_n_backup_query_tables_list()
|
||||
backup Pointer to Query_tables_list instance to be used for backup
|
||||
*/
|
||||
|
||||
void st_lex::reset_n_backup_query_tables_list(Query_tables_list *backup)
|
||||
{
|
||||
backup->set_query_tables_list(this);
|
||||
/*
|
||||
We have to perform full initialization here since otherwise we
|
||||
will damage backed up state.
|
||||
*/
|
||||
this->reset_query_tables_list(TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Restore state of Query_tables_list for this LEX from backup.
|
||||
|
||||
SYNOPSIS
|
||||
restore_backup_query_tables_list()
|
||||
backup Pointer to Query_tables_list instance used for backup
|
||||
*/
|
||||
|
||||
void st_lex::restore_backup_query_tables_list(Query_tables_list *backup)
|
||||
{
|
||||
this->destroy_query_tables_list();
|
||||
this->set_query_tables_list(backup);
|
||||
}
|
||||
|
||||
|
||||
|
|
151
sql/sql_lex.h
151
sql/sql_lex.h
|
@ -702,9 +702,95 @@ extern sys_var_long_ptr trg_new_row_fake_var;
|
|||
enum xa_option_words {XA_NONE, XA_JOIN, XA_RESUME, XA_ONE_PHASE,
|
||||
XA_SUSPEND, XA_FOR_MIGRATE};
|
||||
|
||||
|
||||
/*
|
||||
Class representing list of all tables used by statement.
|
||||
It also contains information about stored functions used by statement
|
||||
since during its execution we may have to add all tables used by its
|
||||
stored functions/triggers to this list in order to pre-open and lock
|
||||
them.
|
||||
|
||||
Also used by st_lex::reset_n_backup/restore_backup_query_tables_list()
|
||||
methods to save and restore this information.
|
||||
*/
|
||||
|
||||
class Query_tables_list
|
||||
{
|
||||
public:
|
||||
/* Global list of all tables used by this statement */
|
||||
TABLE_LIST *query_tables;
|
||||
/* Pointer to next_global member of last element in the previous list. */
|
||||
TABLE_LIST **query_tables_last;
|
||||
/*
|
||||
If non-0 then indicates that query requires prelocking and points to
|
||||
next_global member of last own element in query table list (i.e. last
|
||||
table which was not added to it as part of preparation to prelocking).
|
||||
0 - indicates that this query does not need prelocking.
|
||||
*/
|
||||
TABLE_LIST **query_tables_own_last;
|
||||
/* Set of stored routines called by statement. */
|
||||
HASH sroutines;
|
||||
/*
|
||||
List linking elements of 'sroutines' set. Allows you to add new elements
|
||||
to this set as you iterate through the list of existing elements.
|
||||
'sroutines_list_own_last' is pointer to ::next member of last element of
|
||||
this list which represents routine which is explicitly used by query.
|
||||
'sroutines_list_own_elements' number of explicitly used routines.
|
||||
We use these two members for restoring of 'sroutines_list' to the state
|
||||
in which it was right after query parsing.
|
||||
*/
|
||||
SQL_LIST sroutines_list;
|
||||
byte **sroutines_list_own_last;
|
||||
uint sroutines_list_own_elements;
|
||||
|
||||
/*
|
||||
These constructor and destructor serve for creation/destruction
|
||||
of Query_tables_list instances which are used as backup storage.
|
||||
*/
|
||||
Query_tables_list() {}
|
||||
~Query_tables_list() {}
|
||||
|
||||
/* Initializes (or resets) Query_tables_list object for "real" use. */
|
||||
void reset_query_tables_list(bool init);
|
||||
void destroy_query_tables_list();
|
||||
void set_query_tables_list(Query_tables_list *state)
|
||||
{
|
||||
*this= *state;
|
||||
}
|
||||
|
||||
void add_to_query_tables(TABLE_LIST *table)
|
||||
{
|
||||
*(table->prev_global= query_tables_last)= table;
|
||||
query_tables_last= &table->next_global;
|
||||
}
|
||||
bool requires_prelocking()
|
||||
{
|
||||
return test(query_tables_own_last);
|
||||
}
|
||||
void mark_as_requiring_prelocking(TABLE_LIST **tables_own_last)
|
||||
{
|
||||
query_tables_own_last= tables_own_last;
|
||||
}
|
||||
/* Return pointer to first not-own table in query-tables or 0 */
|
||||
TABLE_LIST* first_not_own_table()
|
||||
{
|
||||
return ( query_tables_own_last ? *query_tables_own_last : 0);
|
||||
}
|
||||
void chop_off_not_own_tables()
|
||||
{
|
||||
if (query_tables_own_last)
|
||||
{
|
||||
*query_tables_own_last= 0;
|
||||
query_tables_last= query_tables_own_last;
|
||||
query_tables_own_last= 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* The state of the lex parsing. This is saved in the THD struct */
|
||||
|
||||
typedef struct st_lex
|
||||
typedef struct st_lex : public Query_tables_list
|
||||
{
|
||||
uint yylineno,yytoklen; /* Simulate lex */
|
||||
LEX_YYSTYPE yylval;
|
||||
|
@ -736,14 +822,6 @@ typedef struct st_lex
|
|||
gptr yacc_yyss,yacc_yyvs;
|
||||
THD *thd;
|
||||
CHARSET_INFO *charset;
|
||||
TABLE_LIST *query_tables; /* global list of all tables in this query */
|
||||
/*
|
||||
last element next_global of previous list (used only for list building
|
||||
during parsing and VIEW processing. This pointer could be invalid during
|
||||
processing of information schema tables(see get_schema_tables_result
|
||||
function)
|
||||
*/
|
||||
TABLE_LIST **query_tables_last;
|
||||
/* store original leaf_tables for INSERT SELECT and PS/SP */
|
||||
TABLE_LIST *leaf_tables_insert;
|
||||
/* Position (first character index) of SELECT of CREATE VIEW statement */
|
||||
|
@ -876,20 +954,6 @@ typedef struct st_lex
|
|||
bool sp_lex_in_use; /* Keep track on lex usage in SPs for error handling */
|
||||
bool all_privileges;
|
||||
sp_pcontext *spcont;
|
||||
/* Set of stored routines called by statement. */
|
||||
HASH sroutines;
|
||||
/*
|
||||
List linking elements of 'sroutines' set. Allows you to add new elements
|
||||
to this set as you iterate through the list of existing elements.
|
||||
'sroutines_list_own_last' is pointer to ::next member of last element of
|
||||
this list which represents routine which is explicitly used by query.
|
||||
'sroutines_list_own_elements' number of explicitly used routines.
|
||||
We use these two members for restoring of 'sroutines_list' to the state
|
||||
in which it was right after query parsing.
|
||||
*/
|
||||
SQL_LIST sroutines_list;
|
||||
byte **sroutines_list_own_last;
|
||||
uint sroutines_list_own_elements;
|
||||
|
||||
st_sp_chistics sp_chistics;
|
||||
bool only_view; /* used for SHOW CREATE TABLE/VIEW */
|
||||
|
@ -925,14 +989,6 @@ typedef struct st_lex
|
|||
*/
|
||||
const char *stmt_definition_begin;
|
||||
|
||||
/*
|
||||
If non-0 then indicates that query requires prelocking and points to
|
||||
next_global member of last own element in query table list (i.e. last
|
||||
table which was not added to it as part of preparation to prelocking).
|
||||
0 - indicates that this query does not need prelocking.
|
||||
*/
|
||||
TABLE_LIST **query_tables_own_last;
|
||||
|
||||
/*
|
||||
Pointers to part of LOAD DATA statement that should be rewritten
|
||||
during replication ("LOCAL 'filename' REPLACE INTO" part).
|
||||
|
@ -945,7 +1001,7 @@ typedef struct st_lex
|
|||
|
||||
virtual ~st_lex()
|
||||
{
|
||||
hash_free(&sroutines);
|
||||
destroy_query_tables_list();
|
||||
}
|
||||
|
||||
inline void uncacheable(uint8 cause)
|
||||
|
@ -970,11 +1026,6 @@ typedef struct st_lex
|
|||
TABLE_LIST *unlink_first_table(bool *link_to_local);
|
||||
void link_first_table_back(TABLE_LIST *first, bool link_to_local);
|
||||
void first_lists_tables_same();
|
||||
inline void add_to_query_tables(TABLE_LIST *table)
|
||||
{
|
||||
*(table->prev_global= query_tables_last)= table;
|
||||
query_tables_last= &table->next_global;
|
||||
}
|
||||
bool add_time_zone_tables_to_query_tables(THD *thd);
|
||||
|
||||
bool can_be_merged();
|
||||
|
@ -1006,28 +1057,7 @@ typedef struct st_lex
|
|||
return FALSE;
|
||||
}
|
||||
}
|
||||
inline bool requires_prelocking()
|
||||
{
|
||||
return test(query_tables_own_last);
|
||||
}
|
||||
inline void mark_as_requiring_prelocking(TABLE_LIST **tables_own_last)
|
||||
{
|
||||
query_tables_own_last= tables_own_last;
|
||||
}
|
||||
/* Return pointer to first not-own table in query-tables or 0 */
|
||||
TABLE_LIST* first_not_own_table()
|
||||
{
|
||||
return ( query_tables_own_last ? *query_tables_own_last : 0);
|
||||
}
|
||||
void chop_off_not_own_tables()
|
||||
{
|
||||
if (query_tables_own_last)
|
||||
{
|
||||
*query_tables_own_last= 0;
|
||||
query_tables_last= query_tables_own_last;
|
||||
query_tables_own_last= 0;
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup_after_one_table_open();
|
||||
|
||||
bool push_context(Name_resolution_context *context)
|
||||
|
@ -1044,6 +1074,9 @@ typedef struct st_lex
|
|||
{
|
||||
return context_stack.head();
|
||||
}
|
||||
|
||||
void reset_n_backup_query_tables_list(Query_tables_list *backup);
|
||||
void restore_backup_query_tables_list(Query_tables_list *backup);
|
||||
} LEX;
|
||||
|
||||
struct st_lex_local: public st_lex
|
||||
|
|
|
@ -2065,7 +2065,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
|||
TABLE *table= tables->table;
|
||||
SELECT_LEX *select_lex= &lex->select_lex;
|
||||
SELECT_LEX *old_all_select_lex= lex->all_selects_list;
|
||||
TABLE_LIST **save_query_tables_last= lex->query_tables_last;
|
||||
enum_sql_command save_sql_command= lex->sql_command;
|
||||
SELECT_LEX *lsel= tables->schema_select_lex;
|
||||
ST_SCHEMA_TABLE *schema_table= tables->schema_table;
|
||||
|
@ -2084,6 +2083,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
|||
db_type not_used;
|
||||
Open_tables_state open_tables_state_backup;
|
||||
bool save_view_prepare_mode= lex->view_prepare_mode;
|
||||
Query_tables_list query_tables_list_backup;
|
||||
lex->view_prepare_mode= TRUE;
|
||||
DBUG_ENTER("get_all_tables");
|
||||
|
||||
|
@ -2096,6 +2096,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
|||
*/
|
||||
lex->sql_command= SQLCOM_SHOW_FIELDS;
|
||||
|
||||
lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
|
||||
|
||||
/*
|
||||
We should not introduce deadlocks even if we already have some
|
||||
tables open and locked, since we won't lock tables which we will
|
||||
|
@ -2136,8 +2138,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
|||
show_table_list->db),
|
||||
show_table_list->alias));
|
||||
thd->temporary_tables= 0;
|
||||
close_thread_tables(thd);
|
||||
show_table_list->table= 0;
|
||||
close_tables_for_reopen(thd, &show_table_list);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@ -2250,7 +2251,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
|||
res= schema_table->process_table(thd, show_table_list, table,
|
||||
res, base_name,
|
||||
show_table_list->alias);
|
||||
close_thread_tables(thd);
|
||||
close_tables_for_reopen(thd, &show_table_list);
|
||||
DBUG_ASSERT(!lex->query_tables_own_last);
|
||||
if (res)
|
||||
goto err;
|
||||
}
|
||||
|
@ -2267,11 +2269,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
|||
error= 0;
|
||||
err:
|
||||
thd->restore_backup_open_tables_state(&open_tables_state_backup);
|
||||
lex->restore_backup_query_tables_list(&query_tables_list_backup);
|
||||
lex->derived_tables= derived_tables;
|
||||
lex->all_selects_list= old_all_select_lex;
|
||||
lex->query_tables_last= save_query_tables_last;
|
||||
lex->view_prepare_mode= save_view_prepare_mode;
|
||||
*save_query_tables_last= 0;
|
||||
lex->sql_command= save_sql_command;
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
|
|
@ -2240,6 +2240,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
|
|||
tables can be left opening
|
||||
*/
|
||||
close_thread_tables(thd);
|
||||
lex->reset_query_tables_list(FALSE);
|
||||
if (protocol->write())
|
||||
goto err;
|
||||
continue;
|
||||
|
@ -2487,6 +2488,7 @@ send_result_message:
|
|||
}
|
||||
}
|
||||
close_thread_tables(thd);
|
||||
lex->reset_query_tables_list(FALSE);
|
||||
table->table=0; // For query cache
|
||||
if (protocol->write())
|
||||
goto err;
|
||||
|
|
Loading…
Reference in a new issue