1
0
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:
Oleksandr Byelkin
2018-05-07 17:42:55 +02:00
parent 3b99a274a8
commit 0bd2b80254
11 changed files with 60 additions and 34 deletions

View File

@ -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

View File

@ -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

View File

@ -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());

View File

@ -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;
} }

View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -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