summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/sp.result59
-rw-r--r--mysql-test/t/sp.test63
-rw-r--r--sql/sp_head.cc47
-rw-r--r--sql/sp_rcontext.cc8
-rw-r--r--sql/sp_rcontext.h3
-rw-r--r--sql/sql_class.cc2
-rw-r--r--sql/sql_class.h5
-rw-r--r--sql/sql_parse.cc2
-rw-r--r--sql/sql_yacc.yy4
-rw-r--r--sql/table.h1
10 files changed, 176 insertions, 18 deletions
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index 3339c93a0be..789c78dc109 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -524,9 +524,44 @@ id data
foo 40
bar 15
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 t2;
-drop procedure cur1;
+drop table t3;
+drop procedure cur2;
create procedure bug822(a_id char(16), a_data int)
begin
declare n int;
@@ -544,6 +579,28 @@ foo 42
bar 666
delete from t1;
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;
create table fac (n int unsigned not null primary key, f bigint unsigned);
create procedure ifac(n int unsigned)
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 724180c65bf..29b9b9285ef 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -613,9 +613,45 @@ end|
insert into t2 values ("foo", 42, -1.9), ("bar", 3, 12.1), ("zap", 666, -3.14)|
call cur1()|
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 t2|
-drop procedure cur1|
+drop table t3|
+drop procedure cur2|
#
# BUG#822
@@ -636,6 +672,31 @@ select * from t1|
delete from t1|
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
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index bea4d7a34be..521e5577577 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -47,10 +47,10 @@ sp_map_result_type(enum enum_field_types type)
/* Evaluate a (presumed) func item. Always returns an item, the parameter
** if nothing else.
*/
-static Item *
-eval_func_item(THD *thd, Item *it, enum enum_field_types type)
+Item *
+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();
DBUG_PRINT("info", ("type: %d", type));
@@ -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);
- 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_thread_tables(thd);
@@ -387,7 +387,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (pvar->mode == sp_param_out)
nctx->push_item(NULL); // OUT
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.
// QQ: Need to handle "global" user/host variables too!!!
if (pvar->mode == sp_param_in)
@@ -626,10 +626,10 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex)
sl ;
sl= sl->next_select_in_list())
{
- List_iterator_fast<Item> li(sl->item_list);
-
if (sl->with_wild)
{
+ List_iterator_fast<Item> li(sl->item_list);
+
// Copy item_list
sl->item_list_copy.empty();
while (Item *it= li++)
@@ -638,7 +638,18 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex)
sl->ref_pointer_array= 0;
if (sl->prep_where)
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);
@@ -660,6 +671,18 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex)
while (Item *it= sl->item_list_copy.pop())
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->free_list= freelist;
@@ -675,7 +698,7 @@ sp_instr_set::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_set::execute");
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;
DBUG_RETURN(0);
}
@@ -701,7 +724,7 @@ sp_instr_jump_if::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_jump_if::execute");
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())
*nextp = m_dest;
@@ -718,7 +741,7 @@ sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_jump_if_not::execute");
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())
*nextp = m_dest;
@@ -734,7 +757,7 @@ int
sp_instr_freturn::execute(THD *thd, uint *nextp)
{
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;
DBUG_RETURN(0);
}
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index d73f3ed6dd7..07fd08b0074 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -40,6 +40,14 @@ sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax)
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
sp_rcontext::find_handler(uint sql_errno)
{
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index 027f2f74789..e69ac9bf4b4 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -69,6 +69,9 @@ class sp_rcontext : public Sql_alloc
m_frame[idx] = i;
}
+ void
+ set_item_eval(uint idx, Item *i, enum_field_types type);
+
inline Item *
get_item(uint idx)
{
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index fcfbe661599..487ae14f4cd 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1137,7 +1137,7 @@ bool select_dumpvar::send_data(List<Item> &items)
{
if ((yy=var_li++))
{
- thd->spcont->set_item(yy->get_offset(), item);
+ thd->spcont->set_item_eval(yy->get_offset(), item, zz->type);
}
}
else
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 19bf451be22..f7c9fb58513 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1123,7 +1123,10 @@ public:
LEX_STRING s;
bool local;
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() {}
};
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 5c61247136f..3299b73a49c 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3724,6 +3724,8 @@ mysql_init_query(THD *thd, bool lexonly)
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_prev= (st_select_lex_node**)&(lex->all_selects_list);
+ lex->select_lex.init_order();
+ lex->select_lex.group_list.empty();
lex->describe= 0;
lex->derived_tables= FALSE;
lex->lock_option= TL_READ;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 1b65b9e87c0..c488b43ee6b 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4351,7 +4351,7 @@ select_var_ident:
{
LEX *lex=Lex;
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
YYABORT;
}
@@ -4370,7 +4370,7 @@ select_var_ident:
YYABORT;
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;
}
}
diff --git a/sql/table.h b/sql/table.h
index 7b4e5745732..afa6665c8cd 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -26,6 +26,7 @@ class st_select_lex_unit;
typedef struct st_order {
struct st_order *next;
Item **item; /* Point at item in select fields */
+ Item **item_copy; /* For SPs; the original item ptr */
bool asc; /* true if ascending */
bool free_me; /* true if item isn't shared */
bool in_field_list; /* true if in select field list */