@@ -363,34 +363,55 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
363
363
364
364
void sp_lex_keeper::free_lex (THD *thd)
365
365
{
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
+ */
366
371
if (!m_lex_resp || !m_lex) return ;
367
372
368
373
/* Prevent endless recursion. */
369
374
m_lex->sphead = nullptr ;
370
375
lex_end (m_lex);
371
376
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 ;
373
388
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
+ }
380
405
381
- m_lex= nullptr ;
382
- m_lex_resp= false ;
383
406
lex_query_tables_own_last= nullptr ;
384
407
}
385
408
386
409
387
- void sp_lex_keeper::set_lex (LEX *lex, bool is_lex_owner )
410
+ void sp_lex_keeper::set_lex (LEX *lex)
388
411
{
389
412
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 ;
394
415
}
395
416
396
417
@@ -406,11 +427,15 @@ int sp_lex_keeper::validate_lex_and_exec_core(THD *thd, uint *nextp,
406
427
{
407
428
thd->clear_error ();
408
429
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 );
410
431
411
432
if (!lex) return true ;
412
433
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);
414
439
415
440
m_first_execution= true ;
416
441
}
@@ -608,7 +633,7 @@ bool sp_lex_instr::setup_table_fields_for_trigger(
608
633
return result;
609
634
}
610
635
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 )
612
637
{
613
638
String sql_query;
614
639
@@ -637,17 +662,11 @@ LEX* sp_lex_instr::parse_expr(THD *thd, sp_head *sp)
637
662
saved_ptr_to_next_trg_items_list=
638
663
m_cur_trigger_stmt_items.first ->next_trig_field_list ;
639
664
665
+ /*
666
+ Clean up items owned by this SP instruction.
667
+ */
640
668
cleanup_before_parsing (sp->m_handler ->type ());
641
669
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
-
651
670
DBUG_ASSERT (mem_root != thd->mem_root );
652
671
/*
653
672
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)
668
687
thd->set_n_backup_active_arena (this , &backup);
669
688
thd->free_list = nullptr ;
670
689
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
+ }
672
724
673
725
lex_start (thd);
674
726
@@ -709,13 +761,21 @@ LEX* sp_lex_instr::parse_expr(THD *thd, sp_head *sp)
709
761
setup_table_fields_for_trigger (thd, sp,
710
762
saved_ptr_to_next_trg_items_list);
711
763
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
+
717
777
thd->free_list = nullptr ;
718
- }
778
+ }
719
779
720
780
Query_arena old;
721
781
thd->restore_active_arena (&old, &backup);
0 commit comments