mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-15347: Valgrind or ASAN errors in mysql_make_view on query from information_schema
Make each lex pointing to statement lex instead of global pointer in THD (no need store and restore the global pointer and put it on SP stack).
This commit is contained in:
@ -8242,4 +8242,15 @@ DROP PROCEDURE proc_13;
|
|||||||
DROP PROCEDURE proc_select;
|
DROP PROCEDURE proc_select;
|
||||||
DROP TABLE t1, t2;
|
DROP TABLE t1, t2;
|
||||||
SET max_sp_recursion_depth=default;
|
SET max_sp_recursion_depth=default;
|
||||||
|
#
|
||||||
|
# MDEV-15347: Valgrind or ASAN errors in mysql_make_view on query
|
||||||
|
# from information_schema
|
||||||
|
#
|
||||||
|
CREATE VIEW v AS SELECT 1;
|
||||||
|
CREATE FUNCTION f() RETURNS INT RETURN 1;
|
||||||
|
SELECT * FROM INFORMATION_SCHEMA.TABLES JOIN INFORMATION_SCHEMA.PARAMETERS
|
||||||
|
UNION
|
||||||
|
SELECT * FROM INFORMATION_SCHEMA.TABLES JOIN INFORMATION_SCHEMA.PARAMETERS;
|
||||||
|
DROP FUNCTION f;
|
||||||
|
DROP VIEW v;
|
||||||
#End of 10.1 tests
|
#End of 10.1 tests
|
||||||
|
@ -9754,4 +9754,19 @@ DROP TABLE t1, t2;
|
|||||||
|
|
||||||
SET max_sp_recursion_depth=default;
|
SET max_sp_recursion_depth=default;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-15347: Valgrind or ASAN errors in mysql_make_view on query
|
||||||
|
--echo # from information_schema
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE VIEW v AS SELECT 1;
|
||||||
|
CREATE FUNCTION f() RETURNS INT RETURN 1;
|
||||||
|
--disable_result_log
|
||||||
|
SELECT * FROM INFORMATION_SCHEMA.TABLES JOIN INFORMATION_SCHEMA.PARAMETERS
|
||||||
|
UNION
|
||||||
|
SELECT * FROM INFORMATION_SCHEMA.TABLES JOIN INFORMATION_SCHEMA.PARAMETERS;
|
||||||
|
--enable_result_log
|
||||||
|
DROP FUNCTION f;
|
||||||
|
DROP VIEW v;
|
||||||
|
|
||||||
--echo #End of 10.1 tests
|
--echo #End of 10.1 tests
|
||||||
|
@ -840,7 +840,7 @@ sp_head::~sp_head()
|
|||||||
thd->lex->sphead= NULL;
|
thd->lex->sphead= NULL;
|
||||||
lex_end(thd->lex);
|
lex_end(thd->lex);
|
||||||
delete thd->lex;
|
delete thd->lex;
|
||||||
thd->lex= thd->stmt_lex= lex;
|
thd->lex= lex;
|
||||||
}
|
}
|
||||||
|
|
||||||
my_hash_free(&m_sptabs);
|
my_hash_free(&m_sptabs);
|
||||||
@ -1121,7 +1121,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
|
|||||||
backup_arena;
|
backup_arena;
|
||||||
query_id_t old_query_id;
|
query_id_t old_query_id;
|
||||||
TABLE *old_derived_tables;
|
TABLE *old_derived_tables;
|
||||||
LEX *old_lex, *old_stmt_lex;
|
LEX *old_lex;
|
||||||
Item_change_list old_change_list;
|
Item_change_list old_change_list;
|
||||||
String old_packet;
|
String old_packet;
|
||||||
uint old_server_status;
|
uint old_server_status;
|
||||||
@ -1224,7 +1224,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
|
|||||||
do it in each instruction
|
do it in each instruction
|
||||||
*/
|
*/
|
||||||
old_lex= thd->lex;
|
old_lex= thd->lex;
|
||||||
old_stmt_lex= thd->stmt_lex;
|
|
||||||
/*
|
/*
|
||||||
We should also save Item tree change list to avoid rollback something
|
We should also save Item tree change list to avoid rollback something
|
||||||
too early in the calling query.
|
too early in the calling query.
|
||||||
@ -1372,7 +1371,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
|
|||||||
DBUG_ASSERT(thd->change_list.is_empty());
|
DBUG_ASSERT(thd->change_list.is_empty());
|
||||||
old_change_list.move_elements_to(&thd->change_list);
|
old_change_list.move_elements_to(&thd->change_list);
|
||||||
thd->lex= old_lex;
|
thd->lex= old_lex;
|
||||||
thd->stmt_lex= old_stmt_lex;
|
|
||||||
thd->set_query_id(old_query_id);
|
thd->set_query_id(old_query_id);
|
||||||
DBUG_ASSERT(!thd->derived_tables);
|
DBUG_ASSERT(!thd->derived_tables);
|
||||||
thd->derived_tables= old_derived_tables;
|
thd->derived_tables= old_derived_tables;
|
||||||
@ -2207,7 +2205,7 @@ sp_head::reset_lex(THD *thd)
|
|||||||
if (sublex == 0)
|
if (sublex == 0)
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
|
|
||||||
thd->lex= thd->stmt_lex= sublex;
|
thd->lex= sublex;
|
||||||
(void)m_lex.push_front(oldlex);
|
(void)m_lex.push_front(oldlex);
|
||||||
|
|
||||||
/* Reset most stuff. */
|
/* Reset most stuff. */
|
||||||
@ -2953,7 +2951,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
|
|||||||
We should not save old value since it is saved/restored in
|
We should not save old value since it is saved/restored in
|
||||||
sp_head::execute() when we are entering/leaving routine.
|
sp_head::execute() when we are entering/leaving routine.
|
||||||
*/
|
*/
|
||||||
thd->lex= thd->stmt_lex= m_lex;
|
thd->lex= m_lex;
|
||||||
|
|
||||||
thd->set_query_id(next_query_id());
|
thd->set_query_id(next_query_id());
|
||||||
|
|
||||||
|
@ -3654,7 +3654,7 @@ void Statement::set_statement(Statement *stmt)
|
|||||||
{
|
{
|
||||||
id= stmt->id;
|
id= stmt->id;
|
||||||
mark_used_columns= stmt->mark_used_columns;
|
mark_used_columns= stmt->mark_used_columns;
|
||||||
stmt_lex= lex= stmt->lex;
|
lex= stmt->lex;
|
||||||
query_string= stmt->query_string;
|
query_string= stmt->query_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1027,21 +1027,6 @@ public:
|
|||||||
|
|
||||||
LEX_STRING name; /* name for named prepared statements */
|
LEX_STRING name; /* name for named prepared statements */
|
||||||
LEX *lex; // parse tree descriptor
|
LEX *lex; // parse tree descriptor
|
||||||
/*
|
|
||||||
LEX which represents current statement (conventional, SP or PS)
|
|
||||||
|
|
||||||
For example during view parsing THD::lex will point to the views LEX and
|
|
||||||
THD::stmt_lex will point to LEX of the statement where the view will be
|
|
||||||
included
|
|
||||||
|
|
||||||
Currently it is used to have always correct select numbering inside
|
|
||||||
statement (LEX::current_select_number) without storing and restoring a
|
|
||||||
global counter which was THD::select_number.
|
|
||||||
|
|
||||||
TODO: make some unified statement representation (now SP has different)
|
|
||||||
to store such data like LEX::current_select_number.
|
|
||||||
*/
|
|
||||||
LEX *stmt_lex;
|
|
||||||
/*
|
/*
|
||||||
Points to the query associated with this statement. It's const, but
|
Points to the query associated with this statement. It's const, but
|
||||||
we need to declare it char * because all table handlers are written
|
we need to declare it char * because all table handlers are written
|
||||||
|
@ -657,10 +657,11 @@ void lex_start(THD *thd)
|
|||||||
{
|
{
|
||||||
LEX *lex= thd->lex;
|
LEX *lex= thd->lex;
|
||||||
DBUG_ENTER("lex_start");
|
DBUG_ENTER("lex_start");
|
||||||
DBUG_PRINT("info", ("Lex %p stmt_lex: %p", thd->lex, thd->stmt_lex));
|
DBUG_PRINT("info", ("Lex %p", thd->lex));
|
||||||
|
|
||||||
lex->thd= lex->unit.thd= thd;
|
lex->thd= lex->unit.thd= thd;
|
||||||
|
|
||||||
|
lex->stmt_lex= lex; // default, should be rewritten for VIEWs And CTEs
|
||||||
DBUG_ASSERT(!lex->explain);
|
DBUG_ASSERT(!lex->explain);
|
||||||
|
|
||||||
lex->context_stack.empty();
|
lex->context_stack.empty();
|
||||||
|
@ -730,7 +730,7 @@ public:
|
|||||||
/*
|
/*
|
||||||
Point to the LEX in which it was created, used in view subquery detection.
|
Point to the LEX in which it was created, used in view subquery detection.
|
||||||
|
|
||||||
TODO: make also st_select_lex::parent_stmt_lex (see THD::stmt_lex)
|
TODO: make also st_select_lex::parent_stmt_lex (see LEX::stmt_lex)
|
||||||
and use st_select_lex::parent_lex & st_select_lex::parent_stmt_lex
|
and use st_select_lex::parent_lex & st_select_lex::parent_stmt_lex
|
||||||
instead of global (from THD) references where it is possible.
|
instead of global (from THD) references where it is possible.
|
||||||
*/
|
*/
|
||||||
@ -2435,6 +2435,21 @@ struct LEX: public Query_tables_list
|
|||||||
// type information
|
// type information
|
||||||
char *length,*dec;
|
char *length,*dec;
|
||||||
CHARSET_INFO *charset;
|
CHARSET_INFO *charset;
|
||||||
|
/*
|
||||||
|
LEX which represents current statement (conventional, SP or PS)
|
||||||
|
|
||||||
|
For example during view parsing THD::lex will point to the views LEX and
|
||||||
|
lex::stmt_lex will point to LEX of the statement where the view will be
|
||||||
|
included
|
||||||
|
|
||||||
|
Currently it is used to have always correct select numbering inside
|
||||||
|
statement (LEX::current_select_number) without storing and restoring a
|
||||||
|
global counter which was THD::select_number.
|
||||||
|
|
||||||
|
TODO: make some unified statement representation (now SP has different)
|
||||||
|
to store such data like LEX::current_select_number.
|
||||||
|
*/
|
||||||
|
LEX *stmt_lex;
|
||||||
|
|
||||||
LEX_STRING name;
|
LEX_STRING name;
|
||||||
char *help_arg;
|
char *help_arg;
|
||||||
|
@ -6927,8 +6927,9 @@ void THD::reset_for_next_command(bool do_clear_error)
|
|||||||
We also assign thd->stmt_lex in lex_start(), but during bootstrap this
|
We also assign thd->stmt_lex in lex_start(), but during bootstrap this
|
||||||
code is executed first.
|
code is executed first.
|
||||||
*/
|
*/
|
||||||
thd->stmt_lex= &main_lex; thd->stmt_lex->current_select_number= 1;
|
DBUG_ASSERT(lex == &main_lex);
|
||||||
DBUG_PRINT("info", ("Lex %p stmt_lex: %p", thd->lex, thd->stmt_lex));
|
main_lex.stmt_lex= &main_lex; main_lex.current_select_number= 1;
|
||||||
|
DBUG_PRINT("info", ("Lex and stmt_lex: %p", &main_lex));
|
||||||
/*
|
/*
|
||||||
Those two lines below are theoretically unneeded as
|
Those two lines below are theoretically unneeded as
|
||||||
THD::cleanup_after_query() should take care of this already.
|
THD::cleanup_after_query() should take care of this already.
|
||||||
@ -7046,7 +7047,7 @@ mysql_new_select(LEX *lex, bool move_down)
|
|||||||
|
|
||||||
if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
|
if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
select_lex->select_number= ++thd->stmt_lex->current_select_number;
|
select_lex->select_number= ++thd->lex->stmt_lex->current_select_number;
|
||||||
select_lex->parent_lex= lex; /* Used in init_query. */
|
select_lex->parent_lex= lex; /* Used in init_query. */
|
||||||
select_lex->init_query();
|
select_lex->init_query();
|
||||||
select_lex->init_select();
|
select_lex->init_select();
|
||||||
|
@ -3635,7 +3635,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
|||||||
|
|
||||||
if (! (lex= new (mem_root) st_lex_local))
|
if (! (lex= new (mem_root) st_lex_local))
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
stmt_lex= lex;
|
lex->stmt_lex= lex;
|
||||||
|
|
||||||
if (set_db(thd->db, thd->db_length))
|
if (set_db(thd->db, thd->db_length))
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
|
@ -1374,13 +1374,13 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
|||||||
List_iterator_fast<LEX_STRING> it_client_cs_name(triggers->client_cs_names);
|
List_iterator_fast<LEX_STRING> it_client_cs_name(triggers->client_cs_names);
|
||||||
List_iterator_fast<LEX_STRING> it_connection_cl_name(triggers->connection_cl_names);
|
List_iterator_fast<LEX_STRING> it_connection_cl_name(triggers->connection_cl_names);
|
||||||
List_iterator_fast<LEX_STRING> it_db_cl_name(triggers->db_cl_names);
|
List_iterator_fast<LEX_STRING> it_db_cl_name(triggers->db_cl_names);
|
||||||
LEX *old_lex= thd->lex, *old_stmt_lex= thd->stmt_lex;
|
LEX *old_lex= thd->lex;
|
||||||
LEX lex;
|
LEX lex;
|
||||||
sp_rcontext *save_spcont= thd->spcont;
|
sp_rcontext *save_spcont= thd->spcont;
|
||||||
ulonglong save_sql_mode= thd->variables.sql_mode;
|
ulonglong save_sql_mode= thd->variables.sql_mode;
|
||||||
LEX_STRING *on_table_name;
|
LEX_STRING *on_table_name;
|
||||||
|
|
||||||
thd->lex= thd->stmt_lex= &lex;
|
thd->lex= &lex;
|
||||||
|
|
||||||
save_db.str= thd->db;
|
save_db.str= thd->db;
|
||||||
save_db.length= thd->db_length;
|
save_db.length= thd->db_length;
|
||||||
@ -1579,7 +1579,6 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
|||||||
}
|
}
|
||||||
thd->reset_db(save_db.str, save_db.length);
|
thd->reset_db(save_db.str, save_db.length);
|
||||||
thd->lex= old_lex;
|
thd->lex= old_lex;
|
||||||
thd->stmt_lex= old_stmt_lex;
|
|
||||||
thd->spcont= save_spcont;
|
thd->spcont= save_spcont;
|
||||||
thd->variables.sql_mode= save_sql_mode;
|
thd->variables.sql_mode= save_sql_mode;
|
||||||
|
|
||||||
@ -1592,7 +1591,6 @@ err_with_lex_cleanup:
|
|||||||
// QQ: anything else ?
|
// QQ: anything else ?
|
||||||
lex_end(&lex);
|
lex_end(&lex);
|
||||||
thd->lex= old_lex;
|
thd->lex= old_lex;
|
||||||
thd->stmt_lex= old_stmt_lex;
|
|
||||||
thd->spcont= save_spcont;
|
thd->spcont= save_spcont;
|
||||||
thd->variables.sql_mode= save_sql_mode;
|
thd->variables.sql_mode= save_sql_mode;
|
||||||
thd->reset_db(save_db.str, save_db.length);
|
thd->reset_db(save_db.str, save_db.length);
|
||||||
|
@ -1315,6 +1315,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
|
|||||||
|
|
||||||
now Lex placed in statement memory
|
now Lex placed in statement memory
|
||||||
*/
|
*/
|
||||||
|
|
||||||
table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local;
|
table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local;
|
||||||
if (!table->view)
|
if (!table->view)
|
||||||
{
|
{
|
||||||
@ -1340,8 +1341,9 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
|
|||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
lex_start(thd);
|
lex_start(thd);
|
||||||
|
lex->stmt_lex= old_lex;
|
||||||
view_select= &lex->select_lex;
|
view_select= &lex->select_lex;
|
||||||
view_select->select_number= ++thd->stmt_lex->current_select_number;
|
view_select->select_number= ++thd->lex->stmt_lex->current_select_number;
|
||||||
|
|
||||||
ulonglong saved_mode= thd->variables.sql_mode;
|
ulonglong saved_mode= thd->variables.sql_mode;
|
||||||
/* switch off modes which can prevent normal parsing of VIEW
|
/* switch off modes which can prevent normal parsing of VIEW
|
||||||
|
Reference in New Issue
Block a user