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 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
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1027,21 +1027,6 @@ public:
|
||||
|
||||
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
|
||||
|
@ -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();
|
||||
|
@ -730,7 +730,7 @@ public:
|
||||
/*
|
||||
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;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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 @@ err_with_lex_cleanup:
|
||||
// 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);
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user