Skip to content

Commit 1ee1979

Browse files
committed
MDEV-5816: Stored programs: validation of stored program statements
This patch is the second part of implementation for cursor's statement re-parsing. The patch does the following changes: - on re-parsing a failed SP instruction that does need to get access to LEX a new lex is instantiated for every SP instruction except cursor relating SP instructions. - items created on re-parsing a cursor relating statement are moved to the free_list of sp_lex_cursor.
1 parent a0b4e0f commit 1ee1979

File tree

3 files changed

+108
-38
lines changed

3 files changed

+108
-38
lines changed

sql/sp_instr.cc

Lines changed: 93 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -363,34 +363,55 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
363363

364364
void sp_lex_keeper::free_lex(THD *thd)
365365
{
366+
/*
367+
Currently, m_lex_resp == false for sp_instr_cursor_copy_struct instructions
368+
and in some cases for sp_instr_set instructions. For these classes
369+
free_lex() returns control flow immediately and doesn't change m_lex.
370+
*/
366371
if (!m_lex_resp || !m_lex) return;
367372

368373
/* Prevent endless recursion. */
369374
m_lex->sphead= nullptr;
370375
lex_end(m_lex);
371376

372-
delete (st_lex_local *)m_lex;
377+
sp_lex_cursor* cursor_lex= m_lex->get_lex_for_cursor();
378+
if (cursor_lex == nullptr)
379+
{
380+
delete (st_lex_local *)m_lex;
381+
/*
382+
In case it is not sp_lex_cursor set thd->lex to the null value
383+
if it points to a LEX object we just deleted in order to avoid
384+
dangling pointers problem.
385+
*/
386+
if (thd->lex == m_lex)
387+
thd->lex= nullptr;
373388

374-
/*
375-
Set thd->lex to the null value in case it points to a LEX object
376-
we just deleted in order to avoid dangling pointer problem
377-
*/
378-
if (thd->lex == m_lex)
379-
thd->lex= nullptr;
389+
m_lex= nullptr;
390+
m_lex_resp= false;
391+
}
392+
else
393+
{
394+
/*
395+
sp_lex_cursor has references to items allocated on parsing a cursor
396+
declaration statement. These items are deleted on re-parsing a failing
397+
cursor declaration statement at the method
398+
sp_lex_instr::cleanup_before_parsing.
399+
Remove the reference to items that will be deleted from sp_lex_cursor
400+
in order to avoid dangling pointers problem.
401+
*/
402+
cleanup_items(cursor_lex->free_list);
403+
cursor_lex->free_list= nullptr;
404+
}
380405

381-
m_lex= nullptr;
382-
m_lex_resp= false;
383406
lex_query_tables_own_last= nullptr;
384407
}
385408

386409

387-
void sp_lex_keeper::set_lex(LEX *lex, bool is_lex_owner)
410+
void sp_lex_keeper::set_lex(LEX *lex)
388411
{
389412
m_lex= lex;
390-
m_lex_resp= is_lex_owner;
391-
392-
if (m_lex)
393-
m_lex->sp_lex_in_use= true;
413+
m_lex_resp= true;
414+
m_lex->sp_lex_in_use= true;
394415
}
395416

396417

@@ -406,11 +427,15 @@ int sp_lex_keeper::validate_lex_and_exec_core(THD *thd, uint *nextp,
406427
{
407428
thd->clear_error();
408429
free_lex(thd);
409-
LEX *lex= instr->parse_expr(thd, thd->spcont->m_sp);
430+
LEX *lex= instr->parse_expr(thd, thd->spcont->m_sp, m_lex);
410431

411432
if (!lex) return true;
412433

413-
set_lex(lex, true);
434+
/*
435+
m_lex != nullptr in case it points to sp_lex_cursor.
436+
*/
437+
if (m_lex == nullptr)
438+
set_lex(lex);
414439

415440
m_first_execution= true;
416441
}
@@ -608,7 +633,7 @@ bool sp_lex_instr::setup_table_fields_for_trigger(
608633
return result;
609634
}
610635

611-
LEX* sp_lex_instr::parse_expr(THD *thd, sp_head *sp)
636+
LEX* sp_lex_instr::parse_expr(THD *thd, sp_head *sp, LEX *sp_instr_lex)
612637
{
613638
String sql_query;
614639

@@ -637,17 +662,11 @@ LEX* sp_lex_instr::parse_expr(THD *thd, sp_head *sp)
637662
saved_ptr_to_next_trg_items_list=
638663
m_cur_trigger_stmt_items.first->next_trig_field_list;
639664

665+
/*
666+
Clean up items owned by this SP instruction.
667+
*/
640668
cleanup_before_parsing(sp->m_handler->type());
641669

642-
Parser_state parser_state;
643-
644-
if (parser_state.init(thd, sql_query.c_ptr(), sql_query.length()))
645-
return nullptr;
646-
647-
// Create a new LEX and initialize it.
648-
649-
LEX *lex_saved= thd->lex;
650-
651670
DBUG_ASSERT(mem_root != thd->mem_root);
652671
/*
653672
Back up the current free_list pointer and reset it to nullptr.
@@ -668,7 +687,40 @@ LEX* sp_lex_instr::parse_expr(THD *thd, sp_head *sp)
668687
thd->set_n_backup_active_arena(this, &backup);
669688
thd->free_list= nullptr;
670689

671-
thd->lex= new (thd->mem_root) st_lex_local;
690+
Parser_state parser_state;
691+
692+
if (parser_state.init(thd, sql_query.c_ptr(), sql_query.length()))
693+
return nullptr;
694+
695+
// Create a new LEX and initialize it.
696+
697+
LEX *lex_saved= thd->lex;
698+
Item **cursor_free_list= nullptr;
699+
700+
/*
701+
sp_instr_lex != nullptr for cursor relating SP instructions (sp_instr_cpush,
702+
sp_instr_cursor_copy_struct) and in some cases for sp_instr_set.
703+
*/
704+
if (sp_instr_lex == nullptr)
705+
thd->lex= new (thd->mem_root) st_lex_local;
706+
else
707+
{
708+
sp_lex_cursor* cursor_lex= sp_instr_lex->get_lex_for_cursor();
709+
/*
710+
In case sp_instr_cursor_copy_struct instruction being re-parsed
711+
the items stored in free_list of sp_lex_cursor are not cleaned up
712+
since the class sp_instr_cursor_copy_struct don't pass ownership of
713+
lex object to sp_lex_keeper. So, clean up items stored in free_list of
714+
sp_lex_cursor explicitly. For sp_instr_cpush instruction items stored
715+
in free_list of sp_lex_cursor are cleaned up in the method free_lex()
716+
since sp_instr_cpush owns a lex object stored in its sp_lex_keeper
717+
data member. So, for the sp_instr_cpush instruction by the time we reach
718+
this block cursor_lex->free_list is already empty.
719+
*/
720+
cleanup_items(cursor_lex->free_list);
721+
cursor_free_list= &cursor_lex->free_list;
722+
DBUG_ASSERT(thd->lex == sp_instr_lex);
723+
}
672724

673725
lex_start(thd);
674726

@@ -709,13 +761,21 @@ LEX* sp_lex_instr::parse_expr(THD *thd, sp_head *sp)
709761
setup_table_fields_for_trigger(thd, sp,
710762
saved_ptr_to_next_trg_items_list);
711763

712-
/*
713-
Assign the list of items created on parsing to the current
714-
stored routine instruction.
715-
*/
716-
free_list= thd->free_list;
764+
if (cursor_free_list)
765+
/*
766+
Update sp_lex_cursor::free_list to point to a list of items
767+
just created on re-parsing the cursor's statement.
768+
*/
769+
*cursor_free_list= thd->free_list;
770+
else
771+
/*
772+
Assign the list of items created on re-parsing the statement to
773+
the current stored routine's instruction.
774+
*/
775+
free_list= thd->free_list;
776+
717777
thd->free_list= nullptr;
718-
}
778+
}
719779

720780
Query_arena old;
721781
thd->restore_active_arena(&old, &backup);

sql/sp_instr.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ class sp_lex_cursor: public sp_lex_local, public Query_arena
7676
return m_expr_str;
7777
}
7878

79+
sp_lex_cursor* get_lex_for_cursor() override
80+
{
81+
return this;
82+
}
83+
7984
private:
8085
LEX_CSTRING m_expr_str;
8186
};
@@ -316,11 +321,8 @@ class sp_lex_keeper final
316321
Set LEX object.
317322
318323
@param lex LEX-object
319-
@param is_lex_owner this flag specifies whether this LEX object is owned
320-
by the sp_lex_keeper and so should deleted when
321-
needed.
322324
*/
323-
void set_lex(LEX *lex, bool is_lex_owner);
325+
void set_lex(LEX *lex);
324326

325327
private:
326328
LEX *m_lex;
@@ -386,10 +388,11 @@ class sp_lex_instr : public sp_instr
386388
387389
@param thd Thread context.
388390
@param sp The stored program.
391+
@param lex SP instruction's lex
389392
390393
@return new LEX-object or NULL in case of failure.
391394
*/
392-
LEX *parse_expr(THD *thd, sp_head *sp);
395+
LEX *parse_expr(THD *thd, sp_head *sp, LEX *lex);
393396

394397
SQL_I_List<Item_trigger_field>* get_instr_trig_field_list() override
395398
{

sql/sql_lex.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3213,6 +3213,8 @@ class Lex_grant_privilege: public Grant_privilege, public Sql_alloc
32133213
};
32143214

32153215

3216+
class sp_lex_cursor;
3217+
32163218
struct LEX: public Query_tables_list
32173219
{
32183220
SELECT_LEX_UNIT unit; /* most upper unit */
@@ -4923,6 +4925,11 @@ struct LEX: public Query_tables_list
49234925
{
49244926
return query_tables != nullptr || sroutines.records > 0;
49254927
}
4928+
4929+
virtual sp_lex_cursor* get_lex_for_cursor()
4930+
{
4931+
return nullptr;
4932+
}
49264933
};
49274934

49284935

0 commit comments

Comments
 (0)