summaryrefslogtreecommitdiff
path: root/sql/sp_head.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sp_head.cc')
-rw-r--r--sql/sp_head.cc143
1 files changed, 75 insertions, 68 deletions
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 96bf2c51b02..8853ee97e98 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -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;
@@ -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);
@@ -1736,6 +1738,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)
{
@@ -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()
@@ -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);
@@ -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);
@@ -2415,67 +2452,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
*/
@@ -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;
@@ -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);
}
@@ -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