Commit 5b116857 authored by unknown's avatar unknown
Browse files

Merge jamppa@bk-internal.mysql.com:/home/bk/mysql-5.0

into  hundin.mysql.fi:/home/jani/mysql-5.0

parents 4033707b 21e29cff
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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)
+84 −0
Original line number Diff line number Diff line
@@ -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;
+89 −1
Original line number Diff line number Diff line
@@ -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|
@@ -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
#
+75 −68
Original line number Diff line number Diff line
@@ -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);
@@ -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)
@@ -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);
@@ -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
*/
@@ -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
+47 −41
Original line number Diff line number Diff line
@@ -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;

@@ -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)
@@ -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.
@@ -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
@@ -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()
@@ -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