diff options
author | unknown <pem@mysql.com> | 2005-11-04 15:37:39 +0100 |
---|---|---|
committer | unknown <pem@mysql.com> | 2005-11-04 15:37:39 +0100 |
commit | 898adb8cfc2e5d4bdf01ae9085f042a82f85c3f7 (patch) | |
tree | f171748ec24780206fc394565155b746aa2b2384 /sql/sp_head.h | |
parent | 02ac7bef876ba51f13c09174da7a706ea35b6613 (diff) | |
download | mariadb-git-898adb8cfc2e5d4bdf01ae9085f042a82f85c3f7.tar.gz |
Fixed BUG#14498: Stored procedures: hang if undefined variable and exception
The problem was to continue at the right place in the code after the
test expression in a flow control statement fails with an exception
(internally, the test in sp_instr_jump_if_not), and the exception is
caught by a continue handler. Execution must then be resumed after the
the entire flow control statement (END IF, END WHILE, etc).
mysql-test/r/sp.result:
New test case for BUG#14498.
mysql-test/t/sp.test:
New test case for BUG#14498.
(Note that one call is disabled at the moment. Depends on BUG#14643.)
sql/sp_head.cc:
Added a continuation destination for sp_instr_jump_if_not, for the case when
an error in the test expression causes a continue handler to catch.
This includes new members in sp_instr_jump_if_not, adjustment of the optmizer
(mark and move methods), and separate backpatching code (since we can't use
the normal one for this).
Also removed the class sp_instr_jump, since it's never used.
...and added some comments to the optimizer.
sql/sp_head.h:
Added a continuation destination for sp_instr_jump_if_not, for the case when
an error in the test expression causes a continue handler to catch.
This includes new members in sp_instr_jump_if_not, adjustment of the optmizer
(mark and move methods), and separate backpatching code (since we can't use
the normal one for this).
Also removed the class sp_instr_jump, since it's never used.
sql/sql_yacc.yy:
Added backpatching of the continue destination for all conditional statements
(using sp_instr_jump_if_not).
Diffstat (limited to 'sql/sp_head.h')
-rw-r--r-- | sql/sp_head.h | 88 |
1 files changed, 47 insertions, 41 deletions
diff --git a/sql/sp_head.h b/sql/sp_head.h index ed0f3987e01..e822ed96c02 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -38,6 +38,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; @@ -240,6 +241,18 @@ public: 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) @@ -310,6 +323,18 @@ private: } 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. @@ -622,50 +647,17 @@ public: 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 @@ -675,12 +667,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() @@ -699,10 +695,20 @@ public: 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 |