diff options
-rw-r--r-- | mysql-test/r/sp.result | 59 | ||||
-rw-r--r-- | mysql-test/t/sp.test | 63 | ||||
-rw-r--r-- | sql/sp_head.cc | 47 | ||||
-rw-r--r-- | sql/sp_rcontext.cc | 8 | ||||
-rw-r--r-- | sql/sp_rcontext.h | 3 | ||||
-rw-r--r-- | sql/sql_class.cc | 2 | ||||
-rw-r--r-- | sql/sql_class.h | 5 | ||||
-rw-r--r-- | sql/sql_parse.cc | 2 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 4 | ||||
-rw-r--r-- | sql/table.h | 1 |
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 */ |