diff --git a/mysql-test/suite/compat/oracle/r/sp-code.result b/mysql-test/suite/compat/oracle/r/sp-code.result index 751549b7500..42e0fb41aaa 100644 --- a/mysql-test/suite/compat/oracle/r/sp-code.result +++ b/mysql-test/suite/compat/oracle/r/sp-code.result @@ -21,7 +21,7 @@ END; / SHOW PROCEDURE CODE p1; Pos Instruction -0 jump 3 +0 jump 2 CALL p1; DROP PROCEDURE p1; # No HANDLER declarations, no code, some exceptions @@ -133,10 +133,9 @@ SHOW PROCEDURE CODE p1; Pos Instruction 0 hpush_jump 3 1 EXIT 1 set v@0 123 -2 hreturn 0 5 +2 hreturn 0 4 3 set v@0 223 -4 jump 5 -5 hpop 1 +4 hpop 1 set @v= 10; CALL p1(@v); SELECT @v; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 7951ef538bc..1ecbc1b2e5f 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2582,6 +2582,34 @@ bool sp_head::add_instr_jump_forward_with_backpatch(THD *thd, } +/* + Replace an instruction at position to "no operation". + + @param thd - use mem_root of this THD for "new". + @param ip - position of the operation + @returns - true on error, false on success + + When we need to remove an instruction that during compilation + appeared to be useless (typically as useless jump), we replace + it to a jump to exactly the next instruction. + Such jumps are later removed during sp_head::optimize(). + + QQ: Perhaps we need a dedicated sp_instr_nop for this purpose. +*/ +bool sp_head::replace_instr_to_nop(THD *thd, uint ip) +{ + sp_instr *instr= get_instr(ip); + sp_instr_jump *nop= new (thd->mem_root) sp_instr_jump(instr->m_ip, + instr->m_ctx, + instr->m_ip + 1); + if (!nop) + return true; + delete instr; + set_dynamic(&m_instr, (uchar *) &nop, ip); + return false; +} + + /** Do some minimal optimization of the code: -# Mark used instructions diff --git a/sql/sp_head.h b/sql/sp_head.h index eb2f47ae2d8..b4c3cdaac6c 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -367,6 +367,8 @@ public: return i; } + bool replace_instr_to_nop(THD *thd, uint ip); + /* Resets lex in 'thd' and keeps a copy of the old one. diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 9c66aea04d9..fec4e309d3f 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -5428,8 +5428,20 @@ LEX::sp_block_with_exceptions_finalize_executable_section(THD *thd, bool LEX::sp_block_with_exceptions_finalize_exceptions(THD *thd, - uint executable_section_ip) + uint executable_section_ip, + uint exception_count) { + if (!exception_count) + { + /* + The jump from the end of DECLARE section to + the beginning of the EXCEPTION section that we added in + sp_block_with_exceptions_finalize_declarations() is useless + if there were no exceptions. + Replace it to "no operation". + */ + return sphead->replace_instr_to_nop(thd, executable_section_ip - 1); + } /* Generate a jump from the end of the EXCEPTION code to the executable section. diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 538cec38d43..ac76dddffcb 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3149,7 +3149,8 @@ public: bool sp_block_with_exceptions_finalize_executable_section(THD *thd, uint executable_section_ip); bool sp_block_with_exceptions_finalize_exceptions(THD *thd, - uint executable_section_ip); + uint executable_section_ip, + uint exception_count); // Check if "KEY IF NOT EXISTS name" used outside of ALTER context bool check_add_key(DDL_options_st ddl) { diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 99e7ee41827..d322770857d 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -3489,7 +3489,7 @@ sp_block_statements_and_exceptions: } opt_exception_clause { - if (Lex->sp_block_with_exceptions_finalize_exceptions(thd, $1)) + if (Lex->sp_block_with_exceptions_finalize_exceptions(thd, $1, $4)) MYSQL_YYABORT; $$= $4; }