diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index f9e6eae7e577718a54ca2f57a29db58cf17741b9..dea04dfdfdf1570c0499b36d691eee4fed29ad6d 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -3310,19 +3310,15 @@ select 1|
 1
 call bug12379_1()|
 bug12379()
+NULL
 42
 42
-Warnings:
-Error	1062	Duplicate entry 'X' for key 1
-Warning	1417	A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes
 select 2|
 2
 2
 call bug12379_2()|
 bug12379()
-Warnings:
-Error	1062	Duplicate entry 'X' for key 1
-Warning	1417	A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes
+NULL
 select 3|
 3
 3
@@ -3390,4 +3386,91 @@ s1
 set sql_mode=@sm|
 drop table t3|
 drop procedure bug6127|
+drop table if exists t3|
+drop procedure if exists bug7049_1|
+drop procedure if exists bug7049_2|
+drop procedure if exists bug7049_3|
+drop procedure if exists bug7049_4|
+drop procedure if exists bug7049_5|
+drop procedure if exists bug7049_6|
+drop function if exists bug7049_1|
+drop function if exists bug7049_2|
+create table t3 ( x int unique )|
+create procedure bug7049_1()
+begin
+insert into t3 values (42);
+insert into t3 values (42);
+end|
+create procedure bug7049_2()
+begin
+declare exit handler for sqlexception
+select 'Caught it' as 'Result';
+call bug7049_1();
+select 'Missed it' as 'Result';
+end|
+create procedure bug7049_3()
+call bug7049_1()|
+create procedure bug7049_4()
+begin
+declare exit handler for sqlexception
+select 'Caught it' as 'Result';
+call bug7049_3();
+select 'Missed it' as 'Result';
+end|
+create procedure bug7049_5()
+begin
+declare x decimal(2,1);
+set x = 'zap';
+end|
+create procedure bug7049_6()
+begin
+declare exit handler for sqlwarning
+select 'Caught it' as 'Result';
+call bug7049_5();
+select 'Missed it' as 'Result';
+end|
+create function bug7049_1()
+returns int
+begin
+insert into t3 values (42);
+insert into t3 values (42);
+return 42;
+end|
+create function bug7049_2()
+returns int
+begin
+declare x int default 0;
+declare continue handler for sqlexception
+set x = 1;
+set x = bug7049_1();
+return x;
+end|
+call bug7049_2()|
+Result
+Caught it
+select * from t3|
+x
+42
+delete from t3|
+call bug7049_4()|
+Result
+Caught it
+select * from t3|
+x
+42
+call bug7049_6()|
+Result
+Caught it
+select bug7049_2()|
+bug7049_2()
+1
+drop table t3|
+drop procedure bug7049_1|
+drop procedure bug7049_2|
+drop procedure bug7049_3|
+drop procedure bug7049_4|
+drop procedure bug7049_5|
+drop procedure bug7049_6|
+drop function bug7049_1|
+drop function bug7049_2|
 drop table t1,t2;
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 65d4f89e2bb4fea9aba88faa1dc5a70167a3f4ed..67fb165d4f4ed3e8c8190f685964d6121d114fd1 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -4264,6 +4264,104 @@ drop table t3|
 drop procedure bug6127|
 
 
+#
+# BUG#7049: Stored procedure CALL errors are ignored
+#
+--disable_warnings
+drop table if exists t3|
+drop procedure if exists bug7049_1|
+drop procedure if exists bug7049_2|
+drop procedure if exists bug7049_3|
+drop procedure if exists bug7049_4|
+drop procedure if exists bug7049_5|
+drop procedure if exists bug7049_6|
+drop function if exists bug7049_1|
+drop function if exists bug7049_2|
+--enable_warnings
+
+create table t3 ( x int unique )|
+
+create procedure bug7049_1()
+begin
+  insert into t3 values (42);
+  insert into t3 values (42);
+end|
+
+create procedure bug7049_2()
+begin
+  declare exit handler for sqlexception
+    select 'Caught it' as 'Result';
+
+  call bug7049_1();
+  select 'Missed it' as 'Result';
+end|
+
+create procedure bug7049_3()
+  call bug7049_1()|
+
+create procedure bug7049_4()
+begin
+  declare exit handler for sqlexception
+    select 'Caught it' as 'Result';
+
+  call bug7049_3();
+  select 'Missed it' as 'Result';
+end|
+
+create procedure bug7049_5()
+begin
+  declare x decimal(2,1);
+
+  set x = 'zap';
+end|
+
+create procedure bug7049_6()
+begin
+  declare exit handler for sqlwarning
+    select 'Caught it' as 'Result';
+
+  call bug7049_5();
+  select 'Missed it' as 'Result';
+end|
+
+create function bug7049_1()
+  returns int
+begin
+  insert into t3 values (42);
+  insert into t3 values (42);
+  return 42;
+end|
+
+create function bug7049_2()
+  returns int
+begin
+  declare x int default 0;
+  declare continue handler for sqlexception
+    set x = 1;
+
+  set x = bug7049_1();
+  return x;
+end|
+
+call bug7049_2()|
+select * from t3|
+delete from t3|
+call bug7049_4()|
+select * from t3|
+call bug7049_6()|
+select bug7049_2()|
+
+drop table t3|
+drop procedure bug7049_1|
+drop procedure bug7049_2|
+drop procedure bug7049_3|
+drop procedure bug7049_4|
+drop procedure bug7049_5|
+drop procedure bug7049_6|
+drop function bug7049_1|
+drop function bug7049_2|
+
+
 #
 # BUG#NNNN: New bug synopsis
 #
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 671acbc2a0cade34c908b3f903f6b1c84f897d22..ab0e42a7ab6dbdc06fa95000e9020353efb152bb 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1110,7 +1110,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
     DBUG_RETURN(-1);
 
   // QQ Should have some error checking here? (types, etc...)
-  if (!(nctx= new sp_rcontext(csize, hmax, cmax)))
+  if (!(nctx= new sp_rcontext(octx, csize, hmax, cmax)))
     goto end;
   for (i= 0 ; i < argcount ; i++)
   {
@@ -1254,7 +1254,7 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args)
   save_spcont= octx= thd->spcont;
   if (! octx)
   {				// Create a temporary old context
-    if (!(octx= new sp_rcontext(csize, hmax, cmax)))
+    if (!(octx= new sp_rcontext(octx, csize, hmax, cmax)))
       DBUG_RETURN(-1);
     thd->spcont= octx;
 
@@ -1262,7 +1262,7 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args)
     thd->spcont->callers_arena= thd;
   }
 
-  if (!(nctx= new sp_rcontext(csize, hmax, cmax)))
+  if (!(nctx= new sp_rcontext(octx, csize, hmax, cmax)))
   {
     thd->spcont= save_spcont;
     DBUG_RETURN(-1);
@@ -2390,7 +2390,10 @@ sp_instr_hreturn::print(String *str)
   str->append("hreturn ");
   str->qs_append(m_frame);
   if (m_dest)
+  {
+    str->append(' ');
     str->qs_append(m_dest);
+  }
 }
 
 
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 252bd7e5cab4e1b7b0b4f2a893d5c6e331c099b9..ccb383580492dffd61472fb111ecdd989f76a1a1 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -29,9 +29,9 @@
 #include "sp_rcontext.h"
 #include "sp_pcontext.h"
 
-sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax)
+sp_rcontext::sp_rcontext(sp_rcontext *prev, uint fsize, uint hmax, uint cmax)
   : m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0),
-    m_ihsp(0), m_hfound(-1), m_ccount(0)
+    m_ihsp(0), m_hfound(-1), m_ccount(0), m_prev_ctx(prev)
 {
   m_frame= (Item **)sql_alloc(fsize * sizeof(Item*));
   m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t));
@@ -116,7 +116,11 @@ sp_rcontext::find_handler(uint sql_errno,
     }
   }
   if (found < 0)
+  {
+    if (m_prev_ctx)
+      return m_prev_ctx->find_handler(sql_errno, level);
     return FALSE;
+  }
   m_hfound= found;
   return TRUE;
 }
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index 22fa4f6e86596a494e7f16314510202a76c798e2..c7a298eccc0926aec208b1af085806ddd403c640 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -66,7 +66,7 @@ class sp_rcontext : public Sql_alloc
   */
   Query_arena *callers_arena;
 
-  sp_rcontext(uint fsize, uint hmax, uint cmax);
+  sp_rcontext(sp_rcontext *prev, uint fsize, uint hmax, uint cmax);
 
   ~sp_rcontext()
   {
@@ -226,6 +226,8 @@ private:
   sp_cursor **m_cstack;
   uint m_ccount;
 
+  sp_rcontext *m_prev_ctx;      // Previous context (NULL if none)
+
 }; // class sp_rcontext : public Sql_alloc