List:Commits« Previous MessageNext Message »
From:marc.alff Date:May 9 2008 4:57am
Subject:bk commit into 6.0 tree (malff:1.2642) WL#2110
View as plain text  
Below is the list of changes that have just been committed into a local
6.0 repository of malff.  When malff does a push these changes
will be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2008-05-08 20:57:25-06:00, malff@stripped. +8 -0
  WL#2110 (Stored Procedures: Implement SIGNAL)
  WL#2265 (Stored Procedures: Implement RESIGNAL)
  WL#2111 (Stored Procedures: Implement GET DIAGNOSTICS)
  
  RESIGNAL runtime (continued)

  mysql-test/r/signal.result@stripped, 2008-05-08 20:57:21-06:00,
malff@stripped. +107 -0
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  mysql-test/r/signal_demo2.result@stripped, 2008-05-08 20:57:22-06:00,
malff@stripped. +197 -0
    SIGNAL / RESIGNAL / GET DIAGNOSTICS
    

  mysql-test/r/signal_demo2.result@stripped, 2008-05-08 20:57:22-06:00,
malff@stripped. +0 -0

  mysql-test/t/signal.test@stripped, 2008-05-08 20:57:21-06:00,
malff@stripped. +121 -0
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  mysql-test/t/signal_demo2.test@stripped, 2008-05-08 20:57:22-06:00,
malff@stripped. +207 -0
    SIGNAL / RESIGNAL / GET DIAGNOSTICS
    

  mysql-test/t/signal_demo2.test@stripped, 2008-05-08 20:57:22-06:00,
malff@stripped. +0 -0

  sql/sp_head.cc@stripped, 2008-05-08 20:57:21-06:00, malff@stripped. +4 -4
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sp_rcontext.cc@stripped, 2008-05-08 20:57:22-06:00, malff@stripped.
+29 -24
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sp_rcontext.h@stripped, 2008-05-08 20:57:22-06:00, malff@stripped. +26
-8
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sql_signal.cc@stripped, 2008-05-08 20:57:22-06:00, malff@stripped. +17
-1
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

diff -Nrup a/mysql-test/r/signal.result b/mysql-test/r/signal.result
--- a/mysql-test/r/signal.result	2008-05-07 20:50:41 -06:00
+++ b/mysql-test/r/signal.result	2008-05-08 20:57:21 -06:00
@@ -1211,6 +1211,24 @@ GET STACKED DIAGNOSTICS @foo = NUMBER;
 ERROR 42000: This version of MySQL doesn't yet support 'GET DIAGNOSTICS'
 create procedure test_signal()
 begin
+# max range
+DECLARE foo CONDITION FOR 65535;
+SIGNAL foo;
+end $$
+call test_signal() $$
+ERROR HY000: Unhandled user-defined exception
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# max range
+DECLARE foo CONDITION FOR 65536;
+SIGNAL foo;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'SQLCODE' can't be set to the value of '65536'
+drop procedure test_signal $$
+create procedure test_signal()
+begin
 # Unknown -> "HY" -> error
 DECLARE foo CONDITION FOR 9999;
 SIGNAL foo;
@@ -2525,5 +2543,94 @@ Level	Code	Message
 Error	1051	Unknown table 'no_such_table'
 Error	5555	RESIGNAL to an error
 drop procedure test_resignal $$
+drop procedure if exists peter_p1 $$
+drop procedure if exists peter_p2 $$
+CREATE PROCEDURE peter_p1 ()
+BEGIN
+DECLARE x CONDITION FOR 1231;
+DECLARE EXIT HANDLER FOR x
+BEGIN
+SELECT '2';
+RESIGNAL SET SQLCODE = 9999;
+END;
+BEGIN
+DECLARE EXIT HANDLER FOR x
+BEGIN
+SELECT '1';
+RESIGNAL SET SCHEMA_NAME = 'test';
+END;
+SET @@sql_mode=NULL;
+END;
+END
+$$
+CREATE PROCEDURE peter_p2 ()
+BEGIN
+DECLARE x CONDITION for 9999;
+DECLARE EXIT HANDLER FOR x
+BEGIN
+SELECT '3';
+RESIGNAL SET MESSAGE_TEXT = 'Hi, I am a useless error message';
+END;
+CALL peter_p1();
+END
+$$
+CALL peter_p2() $$
+1
+1
+2
+2
+3
+3
+ERROR 42000: Hi, I am a useless error message
+show warnings $$
+Level	Code	Message
+Error	9999	Hi, I am a useless error message
+drop procedure peter_p1 $$
+drop procedure peter_p2 $$
+CREATE PROCEDURE peter_p1 ()
+BEGIN
+DECLARE x CONDITION FOR 1231;
+DECLARE EXIT HANDLER FOR x
+BEGIN
+SELECT '2';
+RESIGNAL x SET SQLCODE = 9999;
+END;
+BEGIN
+DECLARE EXIT HANDLER FOR x
+BEGIN
+SELECT '1';
+RESIGNAL x SET SCHEMA_NAME = 'test';
+END;
+SET @@sql_mode=NULL;
+END;
+END
+$$
+CREATE PROCEDURE peter_p2 ()
+BEGIN
+DECLARE x CONDITION for 9999;
+DECLARE EXIT HANDLER FOR x
+BEGIN
+SELECT '3';
+RESIGNAL x SET MESSAGE_TEXT = 'Hi, I am a useless error message';
+END;
+CALL peter_p1();
+END
+$$
+CALL peter_p2() $$
+1
+1
+2
+2
+3
+3
+ERROR HY000: Hi, I am a useless error message
+show warnings $$
+Level	Code	Message
+Error	1231	Variable 'sql_mode' can't be set to the value of 'NULL'
+Error	1231	Unhandled user-defined exception
+Error	9999	Unhandled user-defined exception
+Error	9999	Hi, I am a useless error message
+drop procedure peter_p1 $$
+drop procedure peter_p2 $$
 drop table t_warn;
 drop table t_cursor;
diff -Nrup a/mysql-test/r/signal_demo2.result b/mysql-test/r/signal_demo2.result
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/mysql-test/r/signal_demo2.result	2008-05-08 20:57:22 -06:00
@@ -0,0 +1,197 @@
+drop database if exists demo;
+create database demo;
+use demo;
+create procedure proc_top_a(p1 integer)
+begin
+## DECLARE CONTINUE HANDLER for SQLEXCEPTION, NOT FOUND
+begin
+end;
+select "Starting ...";
+call proc_middle_a(p1);
+select "The end";
+end
+$$
+create procedure proc_middle_a(p1 integer)
+begin
+DECLARE l integer;
+# without RESIGNAL:
+# Should be: DECLARE EXIT HANDLER for SQLEXCEPTION, NOT FOUND
+DECLARE EXIT HANDLER for 1 /* not sure how to handle exceptions */
+begin
+select "Oops ... now what ?";
+end;
+select "In prod_middle()";
+create temporary table t1(a integer, b integer);
+select GET_LOCK("user_mutex", 10) into l;
+insert into t1 set a = p1, b = p1;
+call proc_bottom_a(p1);
+select RELEASE_LOCK("user_mutex") into l;
+drop temporary table t1;
+end
+$$
+create procedure proc_bottom_a(p1 integer)
+begin
+select "In proc_bottom()";
+if (p1 = 1) then
+begin
+select "Doing something that works ...";
+select * from t1;
+end;
+end if;
+if (p1 = 2) then
+begin
+select "Doing something that fail (simulate an error) ...";
+drop table no_such_table;
+end;
+end if;
+if (p1 = 3) then
+begin
+select "Doing something that *SHOULD* works ...";
+select * from t1;
+end;
+end if;
+end
+$$
+call proc_top_a(1);
+Starting ...
+Starting ...
+In prod_middle()
+In prod_middle()
+In proc_bottom()
+In proc_bottom()
+Doing something that works ...
+Doing something that works ...
+a	b
+1	1
+The end
+The end
+call proc_top_a(2);
+Starting ...
+Starting ...
+In prod_middle()
+In prod_middle()
+In proc_bottom()
+In proc_bottom()
+Doing something that fail (simulate an error) ...
+Doing something that fail (simulate an error) ...
+ERROR 42S02: Unknown table 'no_such_table'
+call proc_top_a(3);
+Starting ...
+Starting ...
+In prod_middle()
+In prod_middle()
+ERROR 42S01: Table 't1' already exists
+call proc_top_a(1);
+Starting ...
+Starting ...
+In prod_middle()
+In prod_middle()
+ERROR 42S01: Table 't1' already exists
+drop temporary table if exists t1;
+create procedure proc_top_b(p1 integer)
+begin
+select "Starting ...";
+call proc_middle_b(p1);
+select "The end";
+end
+$$
+create procedure proc_middle_b(p1 integer)
+begin
+DECLARE l integer;
+DECLARE EXIT HANDLER for SQLEXCEPTION, NOT FOUND
+begin
+begin
+DECLARE CONTINUE HANDLER for SQLEXCEPTION, NOT FOUND
+begin
+/* Ignore errors from the cleanup code */
+end;
+select "Doing cleanup !";
+select RELEASE_LOCK("user_mutex") into l;
+drop temporary table t1;
+end;
+RESIGNAL;
+end;
+select "In prod_middle()";
+create temporary table t1(a integer, b integer);
+select GET_LOCK("user_mutex", 10) into l;
+insert into t1 set a = p1, b = p1;
+call proc_bottom_b(p1);
+select RELEASE_LOCK("user_mutex") into l;
+drop temporary table t1;
+end
+$$
+create procedure proc_bottom_b(p1 integer)
+begin
+select "In proc_bottom()";
+if (p1 = 1) then
+begin
+select "Doing something that works ...";
+select * from t1;
+end;
+end if;
+if (p1 = 2) then
+begin
+select "Doing something that fail (simulate an error) ...";
+drop table no_such_table;
+end;
+end if;
+if (p1 = 3) then
+begin
+select "Doing something that *SHOULD* works ...";
+select * from t1;
+end;
+end if;
+end
+$$
+call proc_top_b(1);
+Starting ...
+Starting ...
+In prod_middle()
+In prod_middle()
+In proc_bottom()
+In proc_bottom()
+Doing something that works ...
+Doing something that works ...
+a	b
+1	1
+The end
+The end
+call proc_top_b(2);
+Starting ...
+Starting ...
+In prod_middle()
+In prod_middle()
+In proc_bottom()
+In proc_bottom()
+Doing something that fail (simulate an error) ...
+Doing something that fail (simulate an error) ...
+Doing cleanup !
+Doing cleanup !
+ERROR 42S02: Unknown table 'no_such_table'
+call proc_top_b(3);
+Starting ...
+Starting ...
+In prod_middle()
+In prod_middle()
+In proc_bottom()
+In proc_bottom()
+Doing something that *SHOULD* works ...
+Doing something that *SHOULD* works ...
+a	b
+3	3
+The end
+The end
+call proc_top_b(1);
+Starting ...
+Starting ...
+In prod_middle()
+In prod_middle()
+In proc_bottom()
+In proc_bottom()
+Doing something that works ...
+Doing something that works ...
+a	b
+1	1
+The end
+The end
+drop database demo;
diff -Nrup a/mysql-test/t/signal.test b/mysql-test/t/signal.test
--- a/mysql-test/t/signal.test	2008-05-07 20:50:41 -06:00
+++ b/mysql-test/t/signal.test	2008-05-08 20:57:21 -06:00
@@ -1463,6 +1463,28 @@ delimiter $$;
 
 create procedure test_signal()
 begin
+  # max range
+  DECLARE foo CONDITION FOR 65535;
+  SIGNAL foo;
+end $$
+
+--error 65535
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # max range
+  DECLARE foo CONDITION FOR 65536;
+  SIGNAL foo;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
   # Unknown -> "HY" -> error
   DECLARE foo CONDITION FOR 9999;
   SIGNAL foo;
@@ -2877,6 +2899,105 @@ end $$
 call test_resignal() $$
 show warnings $$
 drop procedure test_resignal $$
+
+#########################################################
+# More complex cases
+#########################################################
+
+--disable_warnings
+drop procedure if exists peter_p1 $$
+drop procedure if exists peter_p2 $$
+--enable_warnings
+
+CREATE PROCEDURE peter_p1 ()
+BEGIN
+  DECLARE x CONDITION FOR 1231;
+  DECLARE EXIT HANDLER FOR x
+  BEGIN
+    SELECT '2';
+    RESIGNAL SET SQLCODE = 9999;
+  END;
+
+  BEGIN
+    DECLARE EXIT HANDLER FOR x
+    BEGIN
+      SELECT '1';
+      RESIGNAL SET SCHEMA_NAME = 'test';
+    END;
+    SET @@sql_mode=NULL;
+  END;
+END
+$$
+
+CREATE PROCEDURE peter_p2 ()
+BEGIN
+  DECLARE x CONDITION for 9999;
+  DECLARE EXIT HANDLER FOR x
+  BEGIN
+    SELECT '3';
+    RESIGNAL SET MESSAGE_TEXT = 'Hi, I am a useless error message';
+  END;
+  CALL peter_p1();
+END
+$$
+
+#
+# Here, RESIGNAL only modifies the condition caught,
+# so there is only 1 condition at the end
+# The final SQLSTATE is 42000 (it comes from the error 1231),
+# since the condition attributes are preserved.
+#
+--error 9999
+CALL peter_p2() $$
+show warnings $$
+
+drop procedure peter_p1 $$
+drop procedure peter_p2 $$
+
+CREATE PROCEDURE peter_p1 ()
+BEGIN
+  DECLARE x CONDITION FOR 1231;
+  DECLARE EXIT HANDLER FOR x
+  BEGIN
+    SELECT '2';
+    RESIGNAL x SET SQLCODE = 9999;
+  END;
+
+  BEGIN
+    DECLARE EXIT HANDLER FOR x
+    BEGIN
+      SELECT '1';
+      RESIGNAL x SET SCHEMA_NAME = 'test';
+    END;
+    SET @@sql_mode=NULL;
+  END;
+END
+$$
+
+CREATE PROCEDURE peter_p2 ()
+BEGIN
+  DECLARE x CONDITION for 9999;
+  DECLARE EXIT HANDLER FOR x
+  BEGIN
+    SELECT '3';
+    RESIGNAL x SET MESSAGE_TEXT = 'Hi, I am a useless error message';
+  END;
+  CALL peter_p1();
+END
+$$
+
+#
+# Here, "RESIGNAL <condition>" create a new condition in the diagnostics
+# area, so that there are 4 conditions at the end.
+# The final SQLSTATE is HY000 (it comes from the unknown error 9999),
+# since new conditions (with their own attributes) are added.
+#
+--error 9999
+CALL peter_p2() $$
+show warnings $$
+
+drop procedure peter_p1 $$
+drop procedure peter_p2 $$
 
 delimiter ;$$
 
diff -Nrup a/mysql-test/t/signal_demo2.test b/mysql-test/t/signal_demo2.test
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/mysql-test/t/signal_demo2.test	2008-05-08 20:57:22 -06:00
@@ -0,0 +1,207 @@
+# Copyright (C) 2008 Sun Microsystems, Inc
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#
+# Demonstrate how RESIGNAL can be used to 'catch' and 're-throw' an error
+#
+
+--disable_warnings
+drop database if exists demo;
+--enable_warnings
+
+create database demo;
+
+use demo;
+
+delimiter $$;
+
+create procedure proc_top_a(p1 integer)
+begin
+  ## DECLARE CONTINUE HANDLER for SQLEXCEPTION, NOT FOUND
+  begin
+  end;
+
+  select "Starting ...";
+  call proc_middle_a(p1);
+  select "The end";
+end
+$$
+
+create procedure proc_middle_a(p1 integer)
+begin
+  DECLARE l integer;
+  # without RESIGNAL:
+  # Should be: DECLARE EXIT HANDLER for SQLEXCEPTION, NOT FOUND
+  DECLARE EXIT HANDLER for 1 /* not sure how to handle exceptions */
+  begin
+    select "Oops ... now what ?";
+  end;
+
+  select "In prod_middle()";
+
+  create temporary table t1(a integer, b integer);
+  select GET_LOCK("user_mutex", 10) into l;
+
+  insert into t1 set a = p1, b = p1;
+
+  call proc_bottom_a(p1);
+
+  select RELEASE_LOCK("user_mutex") into l;
+  drop temporary table t1;
+end
+$$
+
+create procedure proc_bottom_a(p1 integer)
+begin
+  select "In proc_bottom()";
+
+  if (p1 = 1) then
+    begin
+      select "Doing something that works ...";
+      select * from t1;
+    end;
+  end if;
+
+  if (p1 = 2) then
+    begin
+      select "Doing something that fail (simulate an error) ...";
+      drop table no_such_table;
+    end;
+  end if;
+
+  if (p1 = 3) then
+    begin
+      select "Doing something that *SHOULD* works ...";
+      select * from t1;
+    end;
+  end if;
+
+end
+$$
+
+delimiter ;$$
+
+#
+# Code without RESIGNAL:
+# errors are apparent to the caller,
+# but there is no cleanup code,
+# so that the environment (get_lock(), temporary table) is polluted ...
+#
+call proc_top_a(1);
+
+# Expected
+--error ER_BAD_TABLE_ERROR
+call proc_top_a(2);
+
+# Dirty state
+--error ER_TABLE_EXISTS_ERROR
+call proc_top_a(3);
+
+# Dirty state
+--error ER_TABLE_EXISTS_ERROR
+call proc_top_a(1);
+
+drop temporary table if exists t1;
+
+delimiter $$;
+
+create procedure proc_top_b(p1 integer)
+begin
+  select "Starting ...";
+  call proc_middle_b(p1);
+  select "The end";
+end
+$$
+
+create procedure proc_middle_b(p1 integer)
+begin
+  DECLARE l integer;
+  DECLARE EXIT HANDLER for SQLEXCEPTION, NOT FOUND
+  begin
+    begin
+      DECLARE CONTINUE HANDLER for SQLEXCEPTION, NOT FOUND
+      begin
+        /* Ignore errors from the cleanup code */
+      end;
+
+      select "Doing cleanup !";
+      select RELEASE_LOCK("user_mutex") into l;
+      drop temporary table t1;
+    end;
+
+    RESIGNAL;
+  end;
+
+  select "In prod_middle()";
+
+  create temporary table t1(a integer, b integer);
+  select GET_LOCK("user_mutex", 10) into l;
+
+  insert into t1 set a = p1, b = p1;
+
+  call proc_bottom_b(p1);
+
+  select RELEASE_LOCK("user_mutex") into l;
+  drop temporary table t1;
+end
+$$
+
+create procedure proc_bottom_b(p1 integer)
+begin
+  select "In proc_bottom()";
+
+  if (p1 = 1) then
+    begin
+      select "Doing something that works ...";
+      select * from t1;
+    end;
+  end if;
+
+  if (p1 = 2) then
+    begin
+      select "Doing something that fail (simulate an error) ...";
+      drop table no_such_table;
+    end;
+  end if;
+
+  if (p1 = 3) then
+    begin
+      select "Doing something that *SHOULD* works ...";
+      select * from t1;
+    end;
+  end if;
+
+end
+$$
+
+delimiter ;$$
+
+#
+# Code with RESIGNAL:
+# errors are apparent to the caller,
+# the but cleanup code did get a chance to act ...
+#
+
+call proc_top_b(1);
+
+--error ER_BAD_TABLE_ERROR
+call proc_top_b(2);
+
+call proc_top_b(3);
+
+call proc_top_b(1);
+
+drop database demo;
+
diff -Nrup a/sql/sp_head.cc b/sql/sp_head.cc
--- a/sql/sp_head.cc	2008-05-07 20:50:41 -06:00
+++ b/sql/sp_head.cc	2008-05-08 20:57:21 -06:00
@@ -1240,9 +1240,9 @@ sp_head::execute(THD *thd)
     */
     if (ctx)
     {
-      uint hf;
+      uint handler_index;
 
-      switch (ctx->found_handler(&hip, &hf)) {
+      switch (ctx->found_handler(& hip, & handler_index)) {
       case SP_HANDLER_NONE:
         break;
       case SP_HANDLER_CONTINUE:
@@ -1256,7 +1256,7 @@ sp_head::execute(THD *thd)
         ip= hip;
         err_status= FALSE;
         ctx->clear_handler();
-        ctx->enter_handler(hip);
+        ctx->enter_handler(hip, handler_index);
         thd->clear_error();
         thd->is_fatal_error= 0;
         thd->killed= THD::NOT_KILLED;
@@ -3176,7 +3176,7 @@ sp_instr_hpush_jump::execute(THD *thd, u
   sp_cond_type_t *p;
 
   while ((p= li++))
-    thd->spcont->push_handler(p, m_ip+1, m_type, m_frame);
+    thd->spcont->push_handler(p, m_ip+1, m_type);
 
   *nextp= m_dest;
   DBUG_RETURN(0);
diff -Nrup a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
--- a/sql/sp_rcontext.cc	2008-05-07 20:50:41 -06:00
+++ b/sql/sp_rcontext.cc	2008-05-08 20:57:22 -06:00
@@ -69,30 +69,37 @@ sp_rcontext::~sp_rcontext()
 
 bool sp_rcontext::init(THD *thd)
 {
+  uint i;
+  uint handler_count= m_root_parsing_ctx->max_handler_index();
+
   in_sub_stmt= thd->in_sub_stmt;
 
   if (init_var_table(thd) || init_var_items())
     return TRUE;
 
-  return
+  if (
     !(m_handler=
-      (sp_handler_t*)thd->alloc(m_root_parsing_ctx->max_handler_index() *
-                                sizeof(sp_handler_t))) ||
+      (sp_handler_t*)thd->alloc(handler_count * sizeof(sp_handler_t))) ||
     !(m_raised_conditions=
-      (SQL_condition**)thd->alloc(m_root_parsing_ctx->max_handler_index() *
-                                  sizeof(SQL_condition*))) ||
+      (SQL_condition**)thd->alloc(handler_count * sizeof(SQL_condition*))) ||
     !(m_hstack=
-      (uint*)thd->alloc(m_root_parsing_ctx->max_handler_index() *
-                        sizeof(uint))) ||
+      (uint*)thd->alloc(handler_count * sizeof(uint))) ||
     !(m_in_handler=
-      (uint*)thd->alloc(m_root_parsing_ctx->max_handler_index() *
-                        sizeof(uint))) ||
+      (sp_active_handler_t*)thd->alloc(handler_count *
+                                       sizeof(sp_active_handler_t))) ||
     !(m_cstack=
       (sp_cursor**)thd->alloc(m_root_parsing_ctx->max_cursor_index() *
                               sizeof(sp_cursor*))) ||
     !(m_case_expr_holders=
       (Item_cache**)thd->calloc(m_root_parsing_ctx->get_num_case_exprs() *
-                               sizeof (Item_cache*)));
+                               sizeof (Item_cache*)))
+    )
+      return TRUE;
+
+  for (i = 0; i < handler_count; i++)
+    m_raised_conditions[i]= NULL;
+
+  return FALSE;
 }
 
 
@@ -226,7 +233,7 @@ sp_rcontext::find_handler(THD *thd, cons
 
     /* Check active handlers, to avoid invoking one recursively */
     while (j--)
-      if (m_in_handler[j] == m_handler[i].handler)
+      if (m_in_handler[j].ip == m_handler[i].handler)
 	break;
     if (j >= 0)
       continue;                 // Already executing this handler
@@ -351,7 +358,7 @@ sp_rcontext::pop_cursors(uint count)
 }
 
 void
-sp_rcontext::push_handler(struct sp_cond_type *cond, uint h, int type, uint f)
+sp_rcontext::push_handler(struct sp_cond_type *cond, uint h, int type)
 {
   DBUG_ENTER("sp_rcontext::push_handler");
   DBUG_ASSERT(m_hcount < m_root_parsing_ctx->max_handler_index());
@@ -359,7 +366,6 @@ sp_rcontext::push_handler(struct sp_cond
   m_handler[m_hcount].cond= cond;
   m_handler[m_hcount].handler= h;
   m_handler[m_hcount].type= type;
-  m_handler[m_hcount].foffset= f;
   m_hcount+= 1;
 
   DBUG_PRINT("info", ("m_hcount: %d", m_hcount));
@@ -398,11 +404,13 @@ sp_rcontext::pop_hstack()
 }
 
 void
-sp_rcontext::enter_handler(int hid)
+sp_rcontext::enter_handler(uint hip, uint hindex)
 {
   DBUG_ENTER("sp_rcontext::enter_handler");
   DBUG_ASSERT(m_ihsp < m_root_parsing_ctx->max_handler_index());
-  m_in_handler[m_ihsp++]= hid;
+  m_in_handler[m_ihsp].ip= hip;
+  m_in_handler[m_ihsp].index= hindex;
+  m_ihsp++;
   DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp));
   DBUG_VOID_RETURN;
 }
@@ -412,6 +420,8 @@ sp_rcontext::exit_handler()
 {
   DBUG_ENTER("sp_rcontext::exit_handler");
   DBUG_ASSERT(m_ihsp);
+  uint hindex= m_in_handler[m_ihsp-1].index;
+  m_raised_conditions[hindex]= NULL;
   m_ihsp-= 1;
   DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp));
   DBUG_VOID_RETURN;
@@ -422,15 +432,10 @@ sp_rcontext::raised_condition() const
 {
   if (m_ihsp > 0)
   {
-    uint hid= m_in_handler[m_ihsp - 1];
-    uint index;
-    for (index= 0 ; index < m_root_parsing_ctx->max_handler_index() ; index ++)
-    {
-      /* Resolve the handler instruction pointer (hip) to it's index */
-      if (m_handler[index].handler == hid)
-        return m_raised_conditions[index];
-    }
-    DBUG_ASSERT(FALSE);
+    uint hindex= m_in_handler[m_ihsp - 1].index;
+    SQL_condition *raised= m_raised_conditions[hindex];
+    DBUG_ASSERT(raised);
+    return raised;
   }
 
   if (m_prev_runtime_ctx)
diff -Nrup a/sql/sp_rcontext.h b/sql/sp_rcontext.h
--- a/sql/sp_rcontext.h	2008-05-07 20:50:41 -06:00
+++ b/sql/sp_rcontext.h	2008-05-08 20:57:22 -06:00
@@ -34,12 +34,21 @@ class sp_instr_cpush;
 
 typedef struct
 {
+  /** Condition caught by this HANDLER. */
   struct sp_cond_type *cond;
-  uint handler;			// Location of handler
+  /** Location (instruction pointer) of the handler code. */
+  uint handler;
+  /** Handler type (EXIT, CONTINUE). */
   int type;
-  uint foffset;			// Frame offset for the handlers declare level
 } sp_handler_t;
 
+typedef struct
+{
+  /** Instruction pointer of the active handler. */
+  uint ip;
+  /** Handler index of the active handler. */
+  uint index;
+} sp_active_handler_t;
 
 /*
   This class is a runtime context of a Stored Routine. It is used in an
@@ -101,7 +110,7 @@ class sp_rcontext : public Sql_alloc
     return m_return_value_set;
   }
 
-  void push_handler(struct sp_cond_type *cond, uint h, int type, uint f);
+  void push_handler(struct sp_cond_type *cond, uint h, int type);
 
   void pop_handlers(uint count);
 
@@ -115,12 +124,12 @@ class sp_rcontext : public Sql_alloc
 
   // Returns handler type and sets *ip to location if one was found
   inline int
-  found_handler(uint *ip, uint *fp)
+  found_handler(uint *ip, uint *index)
   {
     if (m_hfound < 0)
       return SP_HANDLER_NONE;
     *ip= m_handler[m_hfound].handler;
-    *fp= m_handler[m_hfound].foffset;
+    *index= m_hfound;
     return m_handler[m_hfound].type;
   }
 
@@ -144,7 +153,12 @@ class sp_rcontext : public Sql_alloc
 
   uint pop_hstack();
 
-  void enter_handler(int hid);
+  /**
+    Enter a SQL exception handler.
+    @param hip the handler instruction pointer
+    @param index the handler index
+  */
+  void enter_handler(uint hip, uint index);
 
   void exit_handler();
 
@@ -209,13 +223,17 @@ private:
 
   sp_handler_t *m_handler;      // Visible handlers
 
-  /** SQL condition stack caught by a handler */
+  /**
+    SQL conditions caught by each handler.
+    This is an array indexed by handler index.
+  */
   SQL_condition ** m_raised_conditions;
 
   uint m_hcount;                // Stack pointer for m_handler
   uint *m_hstack;               // Return stack for continue handlers
   uint m_hsp;                   // Stack pointer for m_hstack
-  uint *m_in_handler;           // Active handler, for recursion check
+  /** Active handler stack. */
+  sp_active_handler_t *m_in_handler;
   uint m_ihsp;                  // Stack pointer for m_in_handler
   int m_hfound;                 // Set by find_handler; -1 if not found
 
diff -Nrup a/sql/sql_signal.cc b/sql/sql_signal.cc
--- a/sql/sql_signal.cc	2008-05-07 20:50:42 -06:00
+++ b/sql/sql_signal.cc	2008-05-08 20:57:22 -06:00
@@ -19,6 +19,14 @@
 #include "sp_rcontext.h"
 #include "sql_signal.h"
 
+/*
+  The parser accepts any error code (desired)
+  The runtime internally supports any error code (desired)
+  The client server protocol is limited to 16 bits error codes (restriction)
+  Enforcing the 65535 limit in the runtime until the protocol can change.
+*/
+#define MAX_SQLCODE UINT_MAX16
+
 const LEX_STRING Diag_condition_item_names[]=
 {
   { C_STRING_WITH_LEN("CLASS_ORIGIN") },
@@ -311,6 +319,14 @@ int Abstract_signal::eval_sqlcode_sqlsta
   switch(m_cond->type)
   {
     case sp_cond_type::number:
+      if (m_cond->mysqlerr > MAX_SQLCODE)
+      {
+        char buff[20];
+        sprintf(buff, "%d", m_cond->mysqlerr);
+        /* The parser accepts bigger condition numbers */
+        my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "SQLCODE", buff);
+        return (1);
+      }
       cond->m_sqlcode= m_cond->mysqlerr;
       cond->set_sqlstate(mysql_errno_to_sqlstate(cond->m_sqlcode));
       break;
@@ -468,7 +484,7 @@ int Abstract_signal::eval_signal_informa
     }
 
     int code= set->val_int();
-    if ((code <= 0) || (code > UINT_MAX16))
+    if ((code <= 0) || (code > MAX_SQLCODE))
     {
       str= set->val_str(& str_value);
       my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "SQLCODE", str->c_ptr_safe());
Thread
bk commit into 6.0 tree (malff:1.2642) WL#2110marc.alff9 May 2008