Commit 776784b8 authored by unknown's avatar unknown

Fix for BUG#1495: Evaluate items before setting a local variable with SELECT INTO.

Also copy and restore order_list and group_list for selects in SPs.


mysql-test/r/sp.result:
  Test for BUG#1495, and an additional cursor test.
mysql-test/t/sp.test:
  Test for BUG#1495, and an additional cursor test.
sql/sp_head.cc:
  Fix BUG#1495: renamed eval_func_item() into sp_eval_func_item() and made it
  non-static.
  Also need to copy and restore order_list and group_list pointers before and
  after execution of a substatement. (Which means these must always be properly
  initialized for all queries.)
sql/sp_rcontext.cc:
  Fix BUG#1495: Evaluate and set a local variable (for SELECT INTO).
sql/sp_rcontext.h:
  Fix BUG#1495: Evaluate and set a local variable (for SELECT INTO).
sql/sql_class.cc:
  Fix BUG#1495: Evaluate and set a local variable (for SELECT INTO).
sql/sql_class.h:
  Fix BUG#1495: Evaluate and set a local variable (for SELECT INTO); need type for this.
sql/sql_parse.cc:
  order_list and group_list must be initialized in select_lex for all queries,
  to make SP sub statement execution work.
sql/sql_yacc.yy:
  Type needed for setting local variables.
sql/table.h:
  Need a copy of the Item* pointer when executing sub-statements in SPs. (Since
  it's modified and must be restored afterwards.)
parent 569e72af
...@@ -524,9 +524,44 @@ id data ...@@ -524,9 +524,44 @@ id data
foo 40 foo 40
bar 15 bar 15
zap 663 zap 663
drop procedure cur1;
create table t3 ( s char(16), i int );
create procedure cur2()
begin
declare done int default 0;
declare continue handler for 1305 set done = 1;
declare c1 cursor for select id,data from test.t1;
declare c2 cursor for select i from test.t2;
open c1;
open c2;
repeat
begin
declare a char(16);
declare b,c int;
fetch c1 into a, b;
fetch c2 into c;
if not done then
if b < c then
insert into test.t3 values (a, b);
else
insert into test.t3 values (a, c);
end if;
end if;
end;
until done end repeat;
close c1;
close c2;
end;
call cur2();
select * from t3;
s i
foo 40
bar 3
zap 663
delete from t1; delete from t1;
delete from t2; delete from t2;
drop procedure cur1; drop table t3;
drop procedure cur2;
create procedure bug822(a_id char(16), a_data int) create procedure bug822(a_id char(16), a_data int)
begin begin
declare n int; declare n int;
...@@ -544,6 +579,28 @@ foo 42 ...@@ -544,6 +579,28 @@ foo 42
bar 666 bar 666
delete from t1; delete from t1;
drop procedure bug822; drop procedure bug822;
create procedure bug1495()
begin
declare x int;
select data into x from t1 order by id limit 1;
if x > 10 then
insert into t1 values ("less", x-10);
else
insert into t1 values ("more", x+10);
end if;
end;
insert into t1 values ('foo', 12);
call bug1495();
delete from t1 where id='foo';
insert into t1 values ('bar', 7);
call bug1495();
delete from t1 where id='bar';
select * from t1;
id data
less 2
more 17
delete from t1;
drop procedure bug1495;
drop table if exists fac; drop table if exists fac;
create table fac (n int unsigned not null primary key, f bigint unsigned); create table fac (n int unsigned not null primary key, f bigint unsigned);
create procedure ifac(n int unsigned) create procedure ifac(n int unsigned)
......
...@@ -613,9 +613,45 @@ end| ...@@ -613,9 +613,45 @@ end|
insert into t2 values ("foo", 42, -1.9), ("bar", 3, 12.1), ("zap", 666, -3.14)| insert into t2 values ("foo", 42, -1.9), ("bar", 3, 12.1), ("zap", 666, -3.14)|
call cur1()| call cur1()|
select * from t1| select * from t1|
drop procedure cur1|
create table t3 ( s char(16), i int )|
create procedure cur2()
begin
declare done int default 0;
declare continue handler for 1305 set done = 1;
declare c1 cursor for select id,data from test.t1;
declare c2 cursor for select i from test.t2;
open c1;
open c2;
repeat
begin
declare a char(16);
declare b,c int;
fetch c1 into a, b;
fetch c2 into c;
if not done then
if b < c then
insert into test.t3 values (a, b);
else
insert into test.t3 values (a, c);
end if;
end if;
end;
until done end repeat;
close c1;
close c2;
end|
call cur2()|
select * from t3|
delete from t1| delete from t1|
delete from t2| delete from t2|
drop procedure cur1| drop table t3|
drop procedure cur2|
# #
# BUG#822 # BUG#822
...@@ -636,6 +672,31 @@ select * from t1| ...@@ -636,6 +672,31 @@ select * from t1|
delete from t1| delete from t1|
drop procedure bug822| drop procedure bug822|
#
# BUG#1495
#
create procedure bug1495()
begin
declare x int;
select data into x from t1 order by id limit 1;
if x > 10 then
insert into t1 values ("less", x-10);
else
insert into t1 values ("more", x+10);
end if;
end|
insert into t1 values ('foo', 12)|
call bug1495()|
delete from t1 where id='foo'|
insert into t1 values ('bar', 7)|
call bug1495()|
delete from t1 where id='bar'|
select * from t1|
delete from t1|
drop procedure bug1495|
# #
# Some "real" examples # Some "real" examples
......
...@@ -47,10 +47,10 @@ sp_map_result_type(enum enum_field_types type) ...@@ -47,10 +47,10 @@ sp_map_result_type(enum enum_field_types type)
/* Evaluate a (presumed) func item. Always returns an item, the parameter /* Evaluate a (presumed) func item. Always returns an item, the parameter
** if nothing else. ** if nothing else.
*/ */
static Item * Item *
eval_func_item(THD *thd, Item *it, enum enum_field_types type) sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
{ {
DBUG_ENTER("eval_func_item"); DBUG_ENTER("sp_eval_func_item");
it= it->this_item(); it= it->this_item();
DBUG_PRINT("info", ("type: %d", type)); DBUG_PRINT("info", ("type: %d", type));
...@@ -310,7 +310,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) ...@@ -310,7 +310,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
{ {
sp_pvar_t *pvar = m_pcont->find_pvar(i); sp_pvar_t *pvar = m_pcont->find_pvar(i);
nctx->push_item(eval_func_item(thd, *argp++, pvar->type)); nctx->push_item(sp_eval_func_item(thd, *argp++, pvar->type));
} }
// Close tables opened for subselect in argument list // Close tables opened for subselect in argument list
close_thread_tables(thd); close_thread_tables(thd);
...@@ -387,7 +387,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) ...@@ -387,7 +387,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (pvar->mode == sp_param_out) if (pvar->mode == sp_param_out)
nctx->push_item(NULL); // OUT nctx->push_item(NULL); // OUT
else else
nctx->push_item(eval_func_item(thd, it, pvar->type)); // IN or INOUT nctx->push_item(sp_eval_func_item(thd, it,pvar->type)); // IN or INOUT
// Note: If it's OUT or INOUT, it must be a variable. // Note: If it's OUT or INOUT, it must be a variable.
// QQ: Need to handle "global" user/host variables too!!! // QQ: Need to handle "global" user/host variables too!!!
if (pvar->mode == sp_param_in) if (pvar->mode == sp_param_in)
...@@ -626,10 +626,10 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex) ...@@ -626,10 +626,10 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex)
sl ; sl ;
sl= sl->next_select_in_list()) sl= sl->next_select_in_list())
{ {
List_iterator_fast<Item> li(sl->item_list);
if (sl->with_wild) if (sl->with_wild)
{ {
List_iterator_fast<Item> li(sl->item_list);
// Copy item_list // Copy item_list
sl->item_list_copy.empty(); sl->item_list_copy.empty();
while (Item *it= li++) while (Item *it= li++)
...@@ -638,7 +638,18 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex) ...@@ -638,7 +638,18 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex)
sl->ref_pointer_array= 0; sl->ref_pointer_array= 0;
if (sl->prep_where) if (sl->prep_where)
sl->where= sl->prep_where->copy_andor_structure(thd); sl->where= sl->prep_where->copy_andor_structure(thd);
DBUG_ASSERT(sl->join == 0); for (ORDER *order= (ORDER *)sl->order_list.first ;
order ;
order= order->next)
{
order->item_copy= order->item;
}
for (ORDER *group= (ORDER *)sl->group_list.first ;
group ;
group= group->next)
{
group->item_copy= group->item;
}
} }
res= mysql_execute_command(thd); res= mysql_execute_command(thd);
...@@ -660,6 +671,18 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex) ...@@ -660,6 +671,18 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex)
while (Item *it= sl->item_list_copy.pop()) while (Item *it= sl->item_list_copy.pop())
sl->item_list.push_back(it); sl->item_list.push_back(it);
} }
for (ORDER *order= (ORDER *)sl->order_list.first ;
order ;
order= order->next)
{
order->item= order->item_copy;
}
for (ORDER *group= (ORDER *)sl->group_list.first ;
group ;
group= group->next)
{
group->item= group->item_copy;
}
} }
thd->lex= olex; // Restore the other lex thd->lex= olex; // Restore the other lex
thd->free_list= freelist; thd->free_list= freelist;
...@@ -675,7 +698,7 @@ sp_instr_set::execute(THD *thd, uint *nextp) ...@@ -675,7 +698,7 @@ sp_instr_set::execute(THD *thd, uint *nextp)
{ {
DBUG_ENTER("sp_instr_set::execute"); DBUG_ENTER("sp_instr_set::execute");
DBUG_PRINT("info", ("offset: %u", m_offset)); DBUG_PRINT("info", ("offset: %u", m_offset));
thd->spcont->set_item(m_offset, eval_func_item(thd, m_value, m_type)); thd->spcont->set_item(m_offset, sp_eval_func_item(thd, m_value, m_type));
*nextp = m_ip+1; *nextp = m_ip+1;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -701,7 +724,7 @@ sp_instr_jump_if::execute(THD *thd, uint *nextp) ...@@ -701,7 +724,7 @@ sp_instr_jump_if::execute(THD *thd, uint *nextp)
{ {
DBUG_ENTER("sp_instr_jump_if::execute"); DBUG_ENTER("sp_instr_jump_if::execute");
DBUG_PRINT("info", ("destination: %u", m_dest)); DBUG_PRINT("info", ("destination: %u", m_dest));
Item *it= eval_func_item(thd, m_expr, MYSQL_TYPE_TINY); Item *it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY);
if (it->val_int()) if (it->val_int())
*nextp = m_dest; *nextp = m_dest;
...@@ -718,7 +741,7 @@ sp_instr_jump_if_not::execute(THD *thd, uint *nextp) ...@@ -718,7 +741,7 @@ sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
{ {
DBUG_ENTER("sp_instr_jump_if_not::execute"); DBUG_ENTER("sp_instr_jump_if_not::execute");
DBUG_PRINT("info", ("destination: %u", m_dest)); DBUG_PRINT("info", ("destination: %u", m_dest));
Item *it= eval_func_item(thd, m_expr, MYSQL_TYPE_TINY); Item *it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY);
if (! it->val_int()) if (! it->val_int())
*nextp = m_dest; *nextp = m_dest;
...@@ -734,7 +757,7 @@ int ...@@ -734,7 +757,7 @@ int
sp_instr_freturn::execute(THD *thd, uint *nextp) sp_instr_freturn::execute(THD *thd, uint *nextp)
{ {
DBUG_ENTER("sp_instr_freturn::execute"); DBUG_ENTER("sp_instr_freturn::execute");
thd->spcont->set_result(eval_func_item(thd, m_value, m_type)); thd->spcont->set_result(sp_eval_func_item(thd, m_value, m_type));
*nextp= UINT_MAX; *nextp= UINT_MAX;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
......
...@@ -40,6 +40,14 @@ sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax) ...@@ -40,6 +40,14 @@ sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax)
m_saved.empty(); m_saved.empty();
} }
void
sp_rcontext::set_item_eval(uint idx, Item *i, enum_field_types type)
{
extern Item *sp_eval_func_item(THD *thd, Item *it, enum_field_types type);
set_item(idx, sp_eval_func_item(current_thd, i, type));
}
int int
sp_rcontext::find_handler(uint sql_errno) sp_rcontext::find_handler(uint sql_errno)
{ {
......
...@@ -69,6 +69,9 @@ class sp_rcontext : public Sql_alloc ...@@ -69,6 +69,9 @@ class sp_rcontext : public Sql_alloc
m_frame[idx] = i; m_frame[idx] = i;
} }
void
set_item_eval(uint idx, Item *i, enum_field_types type);
inline Item * inline Item *
get_item(uint idx) get_item(uint idx)
{ {
......
...@@ -1137,7 +1137,7 @@ bool select_dumpvar::send_data(List<Item> &items) ...@@ -1137,7 +1137,7 @@ bool select_dumpvar::send_data(List<Item> &items)
{ {
if ((yy=var_li++)) if ((yy=var_li++))
{ {
thd->spcont->set_item(yy->get_offset(), item); thd->spcont->set_item_eval(yy->get_offset(), item, zz->type);
} }
} }
else else
......
...@@ -1123,7 +1123,10 @@ public: ...@@ -1123,7 +1123,10 @@ public:
LEX_STRING s; LEX_STRING s;
bool local; bool local;
uint offset; uint offset;
my_var (LEX_STRING& j, bool i, uint o) : s(j), local(i), offset(o) {} enum_field_types type;
my_var (LEX_STRING& j, bool i, uint o, enum_field_types t)
:s(j), local(i), offset(o), type(t)
{}
~my_var() {} ~my_var() {}
}; };
......
...@@ -3724,6 +3724,8 @@ mysql_init_query(THD *thd, bool lexonly) ...@@ -3724,6 +3724,8 @@ mysql_init_query(THD *thd, bool lexonly)
lex->select_lex.prev= &lex->unit.slave; lex->select_lex.prev= &lex->unit.slave;
lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0; lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0;
lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list); lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
lex->select_lex.init_order();
lex->select_lex.group_list.empty();
lex->describe= 0; lex->describe= 0;
lex->derived_tables= FALSE; lex->derived_tables= FALSE;
lex->lock_option= TL_READ; lex->lock_option= TL_READ;
......
...@@ -4351,7 +4351,7 @@ select_var_ident: ...@@ -4351,7 +4351,7 @@ select_var_ident:
{ {
LEX *lex=Lex; LEX *lex=Lex;
if (lex->result) if (lex->result)
((select_dumpvar *)lex->result)->var_list.push_back( new my_var($2,0,0)); ((select_dumpvar *)lex->result)->var_list.push_back( new my_var($2,0,0,(enum_field_types)0));
else else
YYABORT; YYABORT;
} }
...@@ -4370,7 +4370,7 @@ select_var_ident: ...@@ -4370,7 +4370,7 @@ select_var_ident:
YYABORT; YYABORT;
else else
{ {
((select_dumpvar *)lex->result)->var_list.push_back( new my_var($1,1,t->offset)); ((select_dumpvar *)lex->result)->var_list.push_back( new my_var($1,1,t->offset,t->type));
t->isset= TRUE; t->isset= TRUE;
} }
} }
......
...@@ -26,6 +26,7 @@ class st_select_lex_unit; ...@@ -26,6 +26,7 @@ class st_select_lex_unit;
typedef struct st_order { typedef struct st_order {
struct st_order *next; struct st_order *next;
Item **item; /* Point at item in select fields */ Item **item; /* Point at item in select fields */
Item **item_copy; /* For SPs; the original item ptr */
bool asc; /* true if ascending */ bool asc; /* true if ascending */
bool free_me; /* true if item isn't shared */ bool free_me; /* true if item isn't shared */
bool in_field_list; /* true if in select field list */ bool in_field_list; /* true if in select field list */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment