summaryrefslogtreecommitdiff
path: root/sql/sp_head.h
diff options
context:
space:
mode:
authorunknown <pem@mysql.com>2005-11-04 15:37:39 +0100
committerunknown <pem@mysql.com>2005-11-04 15:37:39 +0100
commit898adb8cfc2e5d4bdf01ae9085f042a82f85c3f7 (patch)
treef171748ec24780206fc394565155b746aa2b2384 /sql/sp_head.h
parent02ac7bef876ba51f13c09174da7a706ea35b6613 (diff)
downloadmariadb-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.h88
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