revision-id: 85e6bba1d6fb5cb2487c760d9e73812d4fb17f32 (mariadb-10.1.32-81-g85e6bba1d6f) parent(s): 0db66ab18ffef6d8920e2e6ff66e99516a458a4d author: Oleksandr Byelkin committer: Oleksandr Byelkin timestamp: 2018-05-07 19:14:02 +0200 message: 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 restoire the global pointer and put it on SP stack). --- mysql-test/r/sp.result | 11 +++++++++++ mysql-test/t/sp.test | 15 +++++++++++++++ sql/sp_head.cc | 10 ++++------ sql/sql_class.cc | 2 +- sql/sql_class.h | 15 --------------- sql/sql_lex.cc | 5 +++-- sql/sql_lex.h | 17 ++++++++++++++++- sql/sql_parse.cc | 7 ++++--- sql/sql_prepare.cc | 2 +- sql/sql_trigger.cc | 6 ++---- sql/sql_view.cc | 4 +++- 11 files changed, 60 insertions(+), 34 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index ad5bddda035..bc33c08d9d8 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -8242,4 +8242,15 @@ DROP PROCEDURE proc_13; DROP PROCEDURE proc_select; DROP TABLE t1, t2; 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 diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index eeabb0486ca..467d3b5a7d4 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -9754,4 +9754,19 @@ DROP TABLE t1, t2; 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 diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 8bf78d97670..0d24ed04eae 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -840,7 +840,7 @@ sp_head::~sp_head() thd->lex->sphead= NULL; lex_end(thd->lex); delete thd->lex; - thd->lex= thd->stmt_lex= lex; + thd->lex= lex; } my_hash_free(&m_sptabs); @@ -1121,7 +1121,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) backup_arena; query_id_t old_query_id; TABLE *old_derived_tables; - LEX *old_lex, *old_stmt_lex; + LEX *old_lex; Item_change_list old_change_list; String old_packet; uint old_server_status; @@ -1224,7 +1224,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success) do it in each instruction */ old_lex= thd->lex; - old_stmt_lex= thd->stmt_lex; /* We should also save Item tree change list to avoid rollback something 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()); old_change_list.move_elements_to(&thd->change_list); thd->lex= old_lex; - thd->stmt_lex= old_stmt_lex; thd->set_query_id(old_query_id); DBUG_ASSERT(!thd->derived_tables); thd->derived_tables= old_derived_tables; @@ -2207,7 +2205,7 @@ sp_head::reset_lex(THD *thd) if (sublex == 0) DBUG_RETURN(TRUE); - thd->lex= thd->stmt_lex= sublex; + thd->lex= sublex; (void)m_lex.push_front(oldlex); /* 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 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()); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 2ab1cd3a61a..24140246b96 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3654,7 +3654,7 @@ void Statement::set_statement(Statement *stmt) { id= stmt->id; mark_used_columns= stmt->mark_used_columns; - stmt_lex= lex= stmt->lex; + lex= stmt->lex; query_string= stmt->query_string; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 341f2e571d8..ca6155ec93f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1027,21 +1027,6 @@ class Statement: public ilink, public Query_arena LEX_STRING name; /* name for named prepared statements */ 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 we need to declare it char * because all table handlers are written diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 3fa5ec71aeb..085ad1a4b3b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -657,10 +657,11 @@ void lex_start(THD *thd) { LEX *lex= thd->lex; 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->stmt_lex= lex; // default, should be rewritten for VIEWs And CTEs DBUG_ASSERT(!lex->explain); lex->context_stack.empty(); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4fcd090e1f5..3b47b1d25c9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -730,7 +730,7 @@ class st_select_lex: public st_select_lex_node /* 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 instead of global (from THD) references where it is possible. */ @@ -2435,6 +2435,21 @@ struct LEX: public Query_tables_list // type information char *length,*dec; 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; char *help_arg; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3d40f8e4245..10038ad8711 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -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 code is executed first. */ - thd->stmt_lex= &main_lex; thd->stmt_lex->current_select_number= 1; - DBUG_PRINT("info", ("Lex %p stmt_lex: %p", thd->lex, thd->stmt_lex)); + DBUG_ASSERT(lex == &main_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 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())) 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->init_query(); select_lex->init_select(); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 6e14ddc2afb..d39ed6aa637 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -3635,7 +3635,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) if (! (lex= new (mem_root) st_lex_local)) DBUG_RETURN(TRUE); - stmt_lex= lex; + lex->stmt_lex= lex; if (set_db(thd->db, thd->db_length)) DBUG_RETURN(TRUE); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index e14d19c7369..293a4c17156 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -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_connection_cl_name(triggers->connection_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; sp_rcontext *save_spcont= thd->spcont; ulonglong save_sql_mode= thd->variables.sql_mode; LEX_STRING *on_table_name; - thd->lex= thd->stmt_lex= &lex; + thd->lex= &lex; save_db.str= thd->db; 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->lex= old_lex; - thd->stmt_lex= old_stmt_lex; thd->spcont= save_spcont; thd->variables.sql_mode= save_sql_mode; @@ -1592,7 +1591,6 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, // QQ: anything else ? lex_end(&lex); thd->lex= old_lex; - thd->stmt_lex= old_stmt_lex; thd->spcont= save_spcont; thd->variables.sql_mode= save_sql_mode; thd->reset_db(save_db.str, save_db.length); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 1bdc76a66ea..6d7a8e1cc9d 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1315,6 +1315,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, now Lex placed in statement memory */ + table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local; if (!table->view) { @@ -1340,8 +1341,9 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, goto end; lex_start(thd); + lex->stmt_lex= old_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; /* switch off modes which can prevent normal parsing of VIEW