Loading mysql-test/r/sp-code.result +1 −1 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ Pos Instruction 9 set err@1 1 10 hreturn 5 11 cfetch c@0 n@4 12 jump_if_not 15 isnull(n@4) 12 jump_if_not 15(17) isnull(n@4) 13 set nulls@2 (nulls@2 + 1) 14 jump 17 15 set count@3 (count@3 + 1) Loading mysql-test/r/sp.result +84 −0 Original line number Diff line number Diff line Loading @@ -4387,4 +4387,88 @@ id county 2 NULL drop table t3| drop procedure bug15441| drop procedure if exists bug14498_1| drop procedure if exists bug14498_2| drop procedure if exists bug14498_3| drop procedure if exists bug14498_4| drop procedure if exists bug14498_5| create procedure bug14498_1() begin declare continue handler for sqlexception select 'error' as 'Handler'; if v then select 'yes' as 'v'; else select 'no' as 'v'; end if; select 'done' as 'End'; end| create procedure bug14498_2() begin declare continue handler for sqlexception select 'error' as 'Handler'; while v do select 'yes' as 'v'; end while; select 'done' as 'End'; end| create procedure bug14498_3() begin declare continue handler for sqlexception select 'error' as 'Handler'; repeat select 'maybe' as 'v'; until v end repeat; select 'done' as 'End'; end| create procedure bug14498_4() begin declare continue handler for sqlexception select 'error' as 'Handler'; case v when 1 then select '1' as 'v'; when 2 then select '2' as 'v'; else select '?' as 'v'; end case; select 'done' as 'End'; end| create procedure bug14498_5() begin declare continue handler for sqlexception select 'error' as 'Handler'; case when v = 1 then select '1' as 'v'; when v = 2 then select '2' as 'v'; else select '?' as 'v'; end case; select 'done' as 'End'; end| call bug14498_1()| Handler error End done call bug14498_2()| Handler error End done call bug14498_3()| v maybe Handler error End done call bug14498_5()| Handler error End done drop procedure bug14498_1| drop procedure bug14498_2| drop procedure bug14498_3| drop procedure bug14498_4| drop procedure bug14498_5| drop table t1,t2; mysql-test/t/sp.test +89 −1 Original line number Diff line number Diff line Loading @@ -3824,7 +3824,7 @@ drop procedure if exists bug7088_2| --disable_parsing # temporarily disabled until Bar fixes BUG#11986 create procedure bug6063() lbel: begin end| lâbel: begin end| call bug6063()| # QQ Known bug: this will not show the label correctly. show create procedure bug6063| Loading Loading @@ -5154,6 +5154,94 @@ call bug15441('Yale')| drop table t3| drop procedure bug15441| # # BUG#14498: Stored procedures: hang if undefined variable and exception # --disable_warnings drop procedure if exists bug14498_1| drop procedure if exists bug14498_2| drop procedure if exists bug14498_3| drop procedure if exists bug14498_4| drop procedure if exists bug14498_5| --enable_warnings create procedure bug14498_1() begin declare continue handler for sqlexception select 'error' as 'Handler'; if v then select 'yes' as 'v'; else select 'no' as 'v'; end if; select 'done' as 'End'; end| create procedure bug14498_2() begin declare continue handler for sqlexception select 'error' as 'Handler'; while v do select 'yes' as 'v'; end while; select 'done' as 'End'; end| create procedure bug14498_3() begin declare continue handler for sqlexception select 'error' as 'Handler'; repeat select 'maybe' as 'v'; until v end repeat; select 'done' as 'End'; end| create procedure bug14498_4() begin declare continue handler for sqlexception select 'error' as 'Handler'; case v when 1 then select '1' as 'v'; when 2 then select '2' as 'v'; else select '?' as 'v'; end case; select 'done' as 'End'; end| create procedure bug14498_5() begin declare continue handler for sqlexception select 'error' as 'Handler'; case when v = 1 then select '1' as 'v'; when v = 2 then select '2' as 'v'; else select '?' as 'v'; end case; select 'done' as 'End'; end| call bug14498_1()| call bug14498_2()| call bug14498_3()| # We couldn't call this before, due to a known bug (BUG#14643) # QQ We still can't since the new set_case_expr instruction breaks # the semantics of case; it won't crash, but will get the wrong result. #call bug14498_4()| call bug14498_5()| drop procedure bug14498_1| drop procedure bug14498_2| drop procedure bug14498_3| drop procedure bug14498_4| drop procedure bug14498_5| # # BUG#NNNN: New bug synopsis # Loading sql/sp_head.cc +75 −68 Original line number Diff line number Diff line Loading @@ -430,7 +430,8 @@ sp_head::operator delete(void *ptr, size_t size) sp_head::sp_head() :Query_arena(&main_mem_root, INITIALIZED_FOR_SP), m_flags(0), m_recursion_level(0), m_next_cached_sp(0), m_first_instance(this), m_first_free_instance(this), m_last_cached_sp(this) m_first_instance(this), m_first_free_instance(this), m_last_cached_sp(this), m_cont_level(0) { m_return_field_def.charset = NULL; Loading @@ -439,6 +440,7 @@ sp_head::sp_head() DBUG_ENTER("sp_head::sp_head"); m_backpatch.empty(); m_cont_backpatch.empty(); m_lex.empty(); hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0); hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0); Loading Loading @@ -1735,6 +1737,39 @@ sp_head::fill_field_definition(THD *thd, LEX *lex, } void sp_head::new_cont_backpatch(sp_instr_jump_if_not *i) { m_cont_level+= 1; if (i) { /* Use the cont. destination slot to store the level */ i->m_cont_dest= m_cont_level; (void)m_cont_backpatch.push_front(i); } } void sp_head::add_cont_backpatch(sp_instr_jump_if_not *i) { i->m_cont_dest= m_cont_level; (void)m_cont_backpatch.push_front(i); } void sp_head::do_cont_backpatch() { uint dest= instructions(); uint lev= m_cont_level--; sp_instr_jump_if_not *i; while ((i= m_cont_backpatch.head()) && i->m_cont_dest == lev) { i->m_cont_dest= dest; (void)m_cont_backpatch.pop(); } } void sp_head::set_info(longlong created, longlong modified, st_sp_chistics *chistics, ulong sql_mode) Loading Loading @@ -1949,7 +1984,10 @@ sp_head::show_create_function(THD *thd) /* TODO: what does this do?? Do some minimal optimization of the code: 1) Mark used instructions 1.1) While doing this, shortcut jumps to jump instructions 2) Compact the code, removing unused instructions */ void sp_head::optimize() Loading @@ -1972,7 +2010,7 @@ void sp_head::optimize() else { if (src != dst) { { // Move the instruction and update prev. jumps sp_instr *ibp; List_iterator_fast<sp_instr> li(bp); Loading @@ -1980,8 +2018,7 @@ void sp_head::optimize() while ((ibp= li++)) { sp_instr_jump *ji= static_cast<sp_instr_jump *>(ibp); if (ji->m_dest == src) ji->m_dest= dst; ji->set_destination(src, dst); } } i->opt_move(dst, &bp); Loading Loading @@ -2414,67 +2451,6 @@ sp_instr_jump::opt_move(uint dst, List<sp_instr> *bp) } /* sp_instr_jump_if class functions */ int sp_instr_jump_if::execute(THD *thd, uint *nextp) { DBUG_ENTER("sp_instr_jump_if::execute"); DBUG_PRINT("info", ("destination: %u", m_dest)); DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); } int sp_instr_jump_if::exec_core(THD *thd, uint *nextp) { Item *it; int res; it= sp_prepare_func_item(thd, &m_expr); if (!it) res= -1; else { res= 0; if (it->val_bool()) *nextp = m_dest; else *nextp = m_ip+1; } return res; } void sp_instr_jump_if::print(String *str) { /* jump_if dest ... */ if (str->reserve(SP_INSTR_UINT_MAXLEN+8+32)) // Add some for the expr. too return; str->qs_append(STRING_WITH_LEN("jump_if ")); str->qs_append(m_dest); str->qs_append(' '); m_expr->print(str); } uint sp_instr_jump_if::opt_mark(sp_head *sp) { sp_instr *i; marked= 1; if ((i= sp->get_instr(m_dest))) { m_dest= i->opt_shortcut_jump(sp, this); m_optdest= sp->get_instr(m_dest); } sp->opt_mark(m_dest); return m_ip+1; } /* sp_instr_jump_if_not class functions */ Loading @@ -2496,7 +2472,10 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) it= sp_prepare_func_item(thd, &m_expr); if (! it) { res= -1; *nextp = m_cont_dest; } else { res= 0; Loading @@ -2514,11 +2493,13 @@ void sp_instr_jump_if_not::print(String *str) { /* jump_if_not dest ... */ if (str->reserve(SP_INSTR_UINT_MAXLEN+12+32)) // Add some for the expr. too if (str->reserve(2*SP_INSTR_UINT_MAXLEN+14+32)) // Add some for the expr. too return; str->qs_append(STRING_WITH_LEN("jump_if_not ")); str->qs_append(m_dest); str->qs_append(' '); str->append('('); str->qs_append(m_cont_dest); str->append(") "); m_expr->print(str); } Loading @@ -2535,9 +2516,35 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp) m_optdest= sp->get_instr(m_dest); } sp->opt_mark(m_dest); if ((i= sp->get_instr(m_cont_dest))) { m_cont_dest= i->opt_shortcut_jump(sp, this); m_cont_optdest= sp->get_instr(m_cont_dest); } sp->opt_mark(m_cont_dest); return m_ip+1; } void sp_instr_jump_if_not::opt_move(uint dst, List<sp_instr> *bp) { /* cont. destinations may point backwards after shortcutting jumps during the mark phase. If it's still pointing forwards, only push this for backpatching if sp_instr_jump::opt_move() will not do it (i.e. if the m_dest points backwards). */ if (m_cont_dest > m_ip) { // Forward if (m_dest < m_ip) bp->push_back(this); } else if (m_cont_optdest) m_cont_dest= m_cont_optdest->m_ip; // Backward /* This will take care of m_dest and m_ip */ sp_instr_jump::opt_move(dst, bp); } /* sp_instr_freturn class functions Loading sql/sp_head.h +47 −41 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ sp_get_flags_for_command(LEX *lex); struct sp_label; class sp_instr; class sp_instr_jump_if_not; struct sp_cond_type; struct sp_pvar; Loading Loading @@ -266,6 +267,18 @@ class sp_head :private Query_arena int check_backpatch(THD *thd); // Start a new cont. backpatch level. If 'i' is NULL, the level is just incr. void new_cont_backpatch(sp_instr_jump_if_not *i); // Add an instruction to the current level void add_cont_backpatch(sp_instr_jump_if_not *i); // Backpatch (and pop) the current level to the current position. void do_cont_backpatch(); char *name(uint *lenp = 0) const { if (lenp) Loading Loading @@ -356,6 +369,18 @@ class sp_head :private Query_arena sp_instr *instr; } bp_t; List<bp_t> m_backpatch; // Instructions needing backpatching /* We need a special list for backpatching of conditional jump's continue destination (in the case of a continue handler catching an error in the test), since it would otherwise interfere with the normal backpatch mechanism - jump_if_not instructions have two different destination which are to be patched differently. Since these occur in a more restricted way (always the same "level" in the code), we don't need the label. */ List<sp_instr_jump_if_not> m_cont_backpatch; uint m_cont_level; // The current cont. backpatch level /* Multi-set representing optimized list of tables to be locked by this routine. Does not include tables which are used by invoked routines. Loading Loading @@ -669,50 +694,17 @@ class sp_instr_jump : public sp_instr m_dest= dest; } protected: sp_instr *m_optdest; // Used during optimization }; // class sp_instr_jump : public sp_instr class sp_instr_jump_if : public sp_instr_jump { sp_instr_jump_if(const sp_instr_jump_if &); /* Prevent use of these */ void operator=(sp_instr_jump_if &); public: sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, LEX *lex) : sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE) {} sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex) : sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE) {} virtual ~sp_instr_jump_if() {} virtual int execute(THD *thd, uint *nextp); virtual int exec_core(THD *thd, uint *nextp); virtual void print(String *str); virtual uint opt_mark(sp_head *sp); virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) virtual void set_destination(uint old_dest, uint new_dest) { return m_ip; if (m_dest == old_dest) m_dest= new_dest; } private: protected: Item *m_expr; // The condition sp_lex_keeper m_lex_keeper; sp_instr *m_optdest; // Used during optimization }; // class sp_instr_jump_if : public sp_instr_jump }; // class sp_instr_jump : public sp_instr class sp_instr_jump_if_not : public sp_instr_jump Loading @@ -722,12 +714,16 @@ class sp_instr_jump_if_not : public sp_instr_jump public: uint m_cont_dest; // Where continue handlers will go sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, LEX *lex) : sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE) : sp_instr_jump(ip, ctx), m_cont_dest(0), m_expr(i), m_lex_keeper(lex, TRUE), m_cont_optdest(0) {} sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex) : sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE) : sp_instr_jump(ip, ctx, dest), m_cont_dest(0), m_expr(i), m_lex_keeper(lex, TRUE), m_cont_optdest(0) {} virtual ~sp_instr_jump_if_not() Loading @@ -746,10 +742,20 @@ class sp_instr_jump_if_not : public sp_instr_jump return m_ip; } virtual void opt_move(uint dst, List<sp_instr> *ibp); virtual void set_destination(uint old_dest, uint new_dest) { sp_instr_jump::set_destination(old_dest, new_dest); if (m_cont_dest == old_dest) m_cont_dest= new_dest; } private: Item *m_expr; // The condition sp_lex_keeper m_lex_keeper; sp_instr *m_cont_optdest; // Used during optimization }; // class sp_instr_jump_if_not : public sp_instr_jump Loading Loading
mysql-test/r/sp-code.result +1 −1 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ Pos Instruction 9 set err@1 1 10 hreturn 5 11 cfetch c@0 n@4 12 jump_if_not 15 isnull(n@4) 12 jump_if_not 15(17) isnull(n@4) 13 set nulls@2 (nulls@2 + 1) 14 jump 17 15 set count@3 (count@3 + 1) Loading
mysql-test/r/sp.result +84 −0 Original line number Diff line number Diff line Loading @@ -4387,4 +4387,88 @@ id county 2 NULL drop table t3| drop procedure bug15441| drop procedure if exists bug14498_1| drop procedure if exists bug14498_2| drop procedure if exists bug14498_3| drop procedure if exists bug14498_4| drop procedure if exists bug14498_5| create procedure bug14498_1() begin declare continue handler for sqlexception select 'error' as 'Handler'; if v then select 'yes' as 'v'; else select 'no' as 'v'; end if; select 'done' as 'End'; end| create procedure bug14498_2() begin declare continue handler for sqlexception select 'error' as 'Handler'; while v do select 'yes' as 'v'; end while; select 'done' as 'End'; end| create procedure bug14498_3() begin declare continue handler for sqlexception select 'error' as 'Handler'; repeat select 'maybe' as 'v'; until v end repeat; select 'done' as 'End'; end| create procedure bug14498_4() begin declare continue handler for sqlexception select 'error' as 'Handler'; case v when 1 then select '1' as 'v'; when 2 then select '2' as 'v'; else select '?' as 'v'; end case; select 'done' as 'End'; end| create procedure bug14498_5() begin declare continue handler for sqlexception select 'error' as 'Handler'; case when v = 1 then select '1' as 'v'; when v = 2 then select '2' as 'v'; else select '?' as 'v'; end case; select 'done' as 'End'; end| call bug14498_1()| Handler error End done call bug14498_2()| Handler error End done call bug14498_3()| v maybe Handler error End done call bug14498_5()| Handler error End done drop procedure bug14498_1| drop procedure bug14498_2| drop procedure bug14498_3| drop procedure bug14498_4| drop procedure bug14498_5| drop table t1,t2;
mysql-test/t/sp.test +89 −1 Original line number Diff line number Diff line Loading @@ -3824,7 +3824,7 @@ drop procedure if exists bug7088_2| --disable_parsing # temporarily disabled until Bar fixes BUG#11986 create procedure bug6063() lbel: begin end| lâbel: begin end| call bug6063()| # QQ Known bug: this will not show the label correctly. show create procedure bug6063| Loading Loading @@ -5154,6 +5154,94 @@ call bug15441('Yale')| drop table t3| drop procedure bug15441| # # BUG#14498: Stored procedures: hang if undefined variable and exception # --disable_warnings drop procedure if exists bug14498_1| drop procedure if exists bug14498_2| drop procedure if exists bug14498_3| drop procedure if exists bug14498_4| drop procedure if exists bug14498_5| --enable_warnings create procedure bug14498_1() begin declare continue handler for sqlexception select 'error' as 'Handler'; if v then select 'yes' as 'v'; else select 'no' as 'v'; end if; select 'done' as 'End'; end| create procedure bug14498_2() begin declare continue handler for sqlexception select 'error' as 'Handler'; while v do select 'yes' as 'v'; end while; select 'done' as 'End'; end| create procedure bug14498_3() begin declare continue handler for sqlexception select 'error' as 'Handler'; repeat select 'maybe' as 'v'; until v end repeat; select 'done' as 'End'; end| create procedure bug14498_4() begin declare continue handler for sqlexception select 'error' as 'Handler'; case v when 1 then select '1' as 'v'; when 2 then select '2' as 'v'; else select '?' as 'v'; end case; select 'done' as 'End'; end| create procedure bug14498_5() begin declare continue handler for sqlexception select 'error' as 'Handler'; case when v = 1 then select '1' as 'v'; when v = 2 then select '2' as 'v'; else select '?' as 'v'; end case; select 'done' as 'End'; end| call bug14498_1()| call bug14498_2()| call bug14498_3()| # We couldn't call this before, due to a known bug (BUG#14643) # QQ We still can't since the new set_case_expr instruction breaks # the semantics of case; it won't crash, but will get the wrong result. #call bug14498_4()| call bug14498_5()| drop procedure bug14498_1| drop procedure bug14498_2| drop procedure bug14498_3| drop procedure bug14498_4| drop procedure bug14498_5| # # BUG#NNNN: New bug synopsis # Loading
sql/sp_head.cc +75 −68 Original line number Diff line number Diff line Loading @@ -430,7 +430,8 @@ sp_head::operator delete(void *ptr, size_t size) sp_head::sp_head() :Query_arena(&main_mem_root, INITIALIZED_FOR_SP), m_flags(0), m_recursion_level(0), m_next_cached_sp(0), m_first_instance(this), m_first_free_instance(this), m_last_cached_sp(this) m_first_instance(this), m_first_free_instance(this), m_last_cached_sp(this), m_cont_level(0) { m_return_field_def.charset = NULL; Loading @@ -439,6 +440,7 @@ sp_head::sp_head() DBUG_ENTER("sp_head::sp_head"); m_backpatch.empty(); m_cont_backpatch.empty(); m_lex.empty(); hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0); hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0); Loading Loading @@ -1735,6 +1737,39 @@ sp_head::fill_field_definition(THD *thd, LEX *lex, } void sp_head::new_cont_backpatch(sp_instr_jump_if_not *i) { m_cont_level+= 1; if (i) { /* Use the cont. destination slot to store the level */ i->m_cont_dest= m_cont_level; (void)m_cont_backpatch.push_front(i); } } void sp_head::add_cont_backpatch(sp_instr_jump_if_not *i) { i->m_cont_dest= m_cont_level; (void)m_cont_backpatch.push_front(i); } void sp_head::do_cont_backpatch() { uint dest= instructions(); uint lev= m_cont_level--; sp_instr_jump_if_not *i; while ((i= m_cont_backpatch.head()) && i->m_cont_dest == lev) { i->m_cont_dest= dest; (void)m_cont_backpatch.pop(); } } void sp_head::set_info(longlong created, longlong modified, st_sp_chistics *chistics, ulong sql_mode) Loading Loading @@ -1949,7 +1984,10 @@ sp_head::show_create_function(THD *thd) /* TODO: what does this do?? Do some minimal optimization of the code: 1) Mark used instructions 1.1) While doing this, shortcut jumps to jump instructions 2) Compact the code, removing unused instructions */ void sp_head::optimize() Loading @@ -1972,7 +2010,7 @@ void sp_head::optimize() else { if (src != dst) { { // Move the instruction and update prev. jumps sp_instr *ibp; List_iterator_fast<sp_instr> li(bp); Loading @@ -1980,8 +2018,7 @@ void sp_head::optimize() while ((ibp= li++)) { sp_instr_jump *ji= static_cast<sp_instr_jump *>(ibp); if (ji->m_dest == src) ji->m_dest= dst; ji->set_destination(src, dst); } } i->opt_move(dst, &bp); Loading Loading @@ -2414,67 +2451,6 @@ sp_instr_jump::opt_move(uint dst, List<sp_instr> *bp) } /* sp_instr_jump_if class functions */ int sp_instr_jump_if::execute(THD *thd, uint *nextp) { DBUG_ENTER("sp_instr_jump_if::execute"); DBUG_PRINT("info", ("destination: %u", m_dest)); DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); } int sp_instr_jump_if::exec_core(THD *thd, uint *nextp) { Item *it; int res; it= sp_prepare_func_item(thd, &m_expr); if (!it) res= -1; else { res= 0; if (it->val_bool()) *nextp = m_dest; else *nextp = m_ip+1; } return res; } void sp_instr_jump_if::print(String *str) { /* jump_if dest ... */ if (str->reserve(SP_INSTR_UINT_MAXLEN+8+32)) // Add some for the expr. too return; str->qs_append(STRING_WITH_LEN("jump_if ")); str->qs_append(m_dest); str->qs_append(' '); m_expr->print(str); } uint sp_instr_jump_if::opt_mark(sp_head *sp) { sp_instr *i; marked= 1; if ((i= sp->get_instr(m_dest))) { m_dest= i->opt_shortcut_jump(sp, this); m_optdest= sp->get_instr(m_dest); } sp->opt_mark(m_dest); return m_ip+1; } /* sp_instr_jump_if_not class functions */ Loading @@ -2496,7 +2472,10 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) it= sp_prepare_func_item(thd, &m_expr); if (! it) { res= -1; *nextp = m_cont_dest; } else { res= 0; Loading @@ -2514,11 +2493,13 @@ void sp_instr_jump_if_not::print(String *str) { /* jump_if_not dest ... */ if (str->reserve(SP_INSTR_UINT_MAXLEN+12+32)) // Add some for the expr. too if (str->reserve(2*SP_INSTR_UINT_MAXLEN+14+32)) // Add some for the expr. too return; str->qs_append(STRING_WITH_LEN("jump_if_not ")); str->qs_append(m_dest); str->qs_append(' '); str->append('('); str->qs_append(m_cont_dest); str->append(") "); m_expr->print(str); } Loading @@ -2535,9 +2516,35 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp) m_optdest= sp->get_instr(m_dest); } sp->opt_mark(m_dest); if ((i= sp->get_instr(m_cont_dest))) { m_cont_dest= i->opt_shortcut_jump(sp, this); m_cont_optdest= sp->get_instr(m_cont_dest); } sp->opt_mark(m_cont_dest); return m_ip+1; } void sp_instr_jump_if_not::opt_move(uint dst, List<sp_instr> *bp) { /* cont. destinations may point backwards after shortcutting jumps during the mark phase. If it's still pointing forwards, only push this for backpatching if sp_instr_jump::opt_move() will not do it (i.e. if the m_dest points backwards). */ if (m_cont_dest > m_ip) { // Forward if (m_dest < m_ip) bp->push_back(this); } else if (m_cont_optdest) m_cont_dest= m_cont_optdest->m_ip; // Backward /* This will take care of m_dest and m_ip */ sp_instr_jump::opt_move(dst, bp); } /* sp_instr_freturn class functions Loading
sql/sp_head.h +47 −41 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ sp_get_flags_for_command(LEX *lex); struct sp_label; class sp_instr; class sp_instr_jump_if_not; struct sp_cond_type; struct sp_pvar; Loading Loading @@ -266,6 +267,18 @@ class sp_head :private Query_arena int check_backpatch(THD *thd); // Start a new cont. backpatch level. If 'i' is NULL, the level is just incr. void new_cont_backpatch(sp_instr_jump_if_not *i); // Add an instruction to the current level void add_cont_backpatch(sp_instr_jump_if_not *i); // Backpatch (and pop) the current level to the current position. void do_cont_backpatch(); char *name(uint *lenp = 0) const { if (lenp) Loading Loading @@ -356,6 +369,18 @@ class sp_head :private Query_arena sp_instr *instr; } bp_t; List<bp_t> m_backpatch; // Instructions needing backpatching /* We need a special list for backpatching of conditional jump's continue destination (in the case of a continue handler catching an error in the test), since it would otherwise interfere with the normal backpatch mechanism - jump_if_not instructions have two different destination which are to be patched differently. Since these occur in a more restricted way (always the same "level" in the code), we don't need the label. */ List<sp_instr_jump_if_not> m_cont_backpatch; uint m_cont_level; // The current cont. backpatch level /* Multi-set representing optimized list of tables to be locked by this routine. Does not include tables which are used by invoked routines. Loading Loading @@ -669,50 +694,17 @@ class sp_instr_jump : public sp_instr m_dest= dest; } protected: sp_instr *m_optdest; // Used during optimization }; // class sp_instr_jump : public sp_instr class sp_instr_jump_if : public sp_instr_jump { sp_instr_jump_if(const sp_instr_jump_if &); /* Prevent use of these */ void operator=(sp_instr_jump_if &); public: sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, LEX *lex) : sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE) {} sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex) : sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE) {} virtual ~sp_instr_jump_if() {} virtual int execute(THD *thd, uint *nextp); virtual int exec_core(THD *thd, uint *nextp); virtual void print(String *str); virtual uint opt_mark(sp_head *sp); virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) virtual void set_destination(uint old_dest, uint new_dest) { return m_ip; if (m_dest == old_dest) m_dest= new_dest; } private: protected: Item *m_expr; // The condition sp_lex_keeper m_lex_keeper; sp_instr *m_optdest; // Used during optimization }; // class sp_instr_jump_if : public sp_instr_jump }; // class sp_instr_jump : public sp_instr class sp_instr_jump_if_not : public sp_instr_jump Loading @@ -722,12 +714,16 @@ class sp_instr_jump_if_not : public sp_instr_jump public: uint m_cont_dest; // Where continue handlers will go sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, LEX *lex) : sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE) : sp_instr_jump(ip, ctx), m_cont_dest(0), m_expr(i), m_lex_keeper(lex, TRUE), m_cont_optdest(0) {} sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex) : sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE) : sp_instr_jump(ip, ctx, dest), m_cont_dest(0), m_expr(i), m_lex_keeper(lex, TRUE), m_cont_optdest(0) {} virtual ~sp_instr_jump_if_not() Loading @@ -746,10 +742,20 @@ class sp_instr_jump_if_not : public sp_instr_jump return m_ip; } virtual void opt_move(uint dst, List<sp_instr> *ibp); virtual void set_destination(uint old_dest, uint new_dest) { sp_instr_jump::set_destination(old_dest, new_dest); if (m_cont_dest == old_dest) m_cont_dest= new_dest; } private: Item *m_expr; // The condition sp_lex_keeper m_lex_keeper; sp_instr *m_cont_optdest; // Used during optimization }; // class sp_instr_jump_if_not : public sp_instr_jump Loading