List:Commits« Previous MessageNext Message »
From:Jon Olav Hauglid Date:September 27 2012 10:10am
Subject:bzr push into mysql-trunk-wl6406 branch (jon.hauglid:3991 to 3992) WL#6406
View as plain text  
 3992 Jon Olav Hauglid	2012-09-27
      WL#6406 Stacked diagnostic areas
      
      Fixed bug with RESIGNAL of warning. Since the handler continues
      in this case, push another Diagnostics Area at the end of RESIGNAL,
      so that it can be popped when the handler exits.
      
      Also simplified code handling SP exit. Improved code documentation.
      
      Added more test coverage.

    modified:
      mysql-test/r/signal.result
      mysql-test/t/signal.test
      sql/sp_head.cc
      sql/sql_signal.cc
 3991 Jon Olav Hauglid	2012-09-19
      Review fixes, part 2

    modified:
      libmysqld/lib_sql.cc
      sql/binlog.cc
      sql/event_scheduler.cc
      sql/field.cc
      sql/filesort.cc
      sql/handler.cc
      sql/log_event.cc
      sql/log_event_old.cc
      sql/opt_sum.cc
      sql/protocol.cc
      sql/rpl_reporting.cc
      sql/rpl_slave.cc
      sql/sp_head.cc
      sql/sp_instr.cc
      sql/sp_rcontext.cc
      sql/sp_rcontext.h
      sql/sql_acl.cc
      sql/sql_admin.cc
      sql/sql_audit.h
      sql/sql_base.cc
      sql/sql_class.cc
      sql/sql_class.h
      sql/sql_connect.cc
      sql/sql_derived.cc
      sql/sql_error.cc
      sql/sql_error.h
      sql/sql_executor.cc
      sql/sql_get_diagnostics.cc
      sql/sql_insert.cc
      sql/sql_load.cc
      sql/sql_parse.cc
      sql/sql_prepare.cc
      sql/sql_prepare.h
      sql/sql_servers.cc
      sql/sql_show.cc
      sql/sql_signal.cc
      sql/sql_table.cc
      sql/sql_time.cc
      sql/sql_update.cc
      sql/table.cc
      sql/tztime.cc
      storage/perfschema/pfs.cc
      unittest/gunit/get_diagnostics-t.cc
=== modified file 'mysql-test/r/signal.result'
--- a/mysql-test/r/signal.result	2011-10-31 11:52:20 +0000
+++ b/mysql-test/r/signal.result	2012-09-27 10:09:56 +0000
@@ -2371,3 +2371,92 @@ begin
 SIGNAL SQLSTATE '77777' SET MYSQL_ERRNO = 1000, MESSAGE_TEXT='ÁÂÃÅÄ';
 end $$
 drop procedure test_signal $$
+#
+# WL#6406 Stacked diagnostic areas
+#
+# Double RESIGNAL of warning
+#
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+BEGIN
+RESIGNAL;
+RESIGNAL;
+END;
+SELECT 10 + 'a';
+END $$
+CALL p1();
+10 + 'a'
+10
+Warnings:
+Warning	1292	Truncated incorrect DOUBLE value: 'a'
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+BEGIN
+RESIGNAL SET MESSAGE_TEXT= '1st resignal';
+RESIGNAL SET MESSAGE_TEXT= '2nd resignal';
+END;
+SELECT 10 + 'a';
+END $$
+CALL p1();
+10 + 'a'
+10
+Warnings:
+Warning	1292	2nd resignal
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+BEGIN
+RESIGNAL SQLSTATE '01000' SET MESSAGE_TEXT= '1st resignal';
+RESIGNAL SQLSTATE '01000' SET MESSAGE_TEXT= '2nd resignal';
+END;
+SELECT 10 + 'a';
+END $$
+CALL p1();
+10 + 'a'
+10
+Warnings:
+Warning	1292	Truncated incorrect DOUBLE value: 'a'
+Warning	1642	1st resignal
+Warning	1642	2nd resignal
+DROP PROCEDURE p1;
+# RESIGNAL warning + RESIGNAL error
+#
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+BEGIN
+RESIGNAL SQLSTATE '01000' SET MESSAGE_TEXT= '1st resignal';
+RESIGNAL SQLSTATE 'HY000' SET MESSAGE_TEXT= '2nd resignal';
+END;
+SELECT 10 + 'a';
+END $$
+CALL p1();
+10 + 'a'
+10
+ERROR HY000: 2nd resignal
+SHOW WARNINGS;
+Level	Code	Message
+Warning	1292	Truncated incorrect DOUBLE value: 'a'
+Warning	1642	1st resignal
+Error	1644	2nd resignal
+DROP PROCEDURE p1;
+# Unhandled errors raised in nested handlers
+#
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE CONTINUE HANDLER FOR 1051
+BEGIN
+DROP DATABASE none;  # Error 1008
+END;
+DROP TABLE none;  # Error 1051
+END $$
+CALL p1();
+ERROR HY000: Can't drop database 'none'; database doesn't exist
+SHOW WARNINGS;
+Level	Code	Message
+Error	1008	Can't drop database 'none'; database doesn't exist
+DROP PROCEDURE p1;

=== modified file 'mysql-test/t/signal.test'
--- a/mysql-test/t/signal.test	2011-10-31 11:52:20 +0000
+++ b/mysql-test/t/signal.test	2012-09-27 10:09:56 +0000
@@ -2678,5 +2678,100 @@ end $$
 # call test_signal $$
 drop procedure test_signal $$
 
-delimiter ; $$
+delimiter ;$$
 
+
+--echo #
+--echo # WL#6406 Stacked diagnostic areas
+--echo #
+
+--echo # Double RESIGNAL of warning
+--echo #
+
+delimiter $$;
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+  BEGIN
+    RESIGNAL;
+    RESIGNAL;
+  END;
+
+  SELECT 10 + 'a';
+END $$
+delimiter ;$$
+
+CALL p1();
+DROP PROCEDURE p1;
+
+delimiter $$;
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+  BEGIN
+    RESIGNAL SET MESSAGE_TEXT= '1st resignal';
+    RESIGNAL SET MESSAGE_TEXT= '2nd resignal';
+  END;
+
+  SELECT 10 + 'a';
+END $$
+delimiter ;$$
+
+CALL p1();
+DROP PROCEDURE p1;
+
+delimiter $$;
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+  BEGIN
+    RESIGNAL SQLSTATE '01000' SET MESSAGE_TEXT= '1st resignal';
+    RESIGNAL SQLSTATE '01000' SET MESSAGE_TEXT= '2nd resignal';
+  END;
+
+  SELECT 10 + 'a';
+END $$
+delimiter ;$$
+
+CALL p1();
+DROP PROCEDURE p1;
+
+--echo # RESIGNAL warning + RESIGNAL error
+--echo #
+
+delimiter $$;
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+  BEGIN
+    RESIGNAL SQLSTATE '01000' SET MESSAGE_TEXT= '1st resignal';
+    RESIGNAL SQLSTATE 'HY000' SET MESSAGE_TEXT= '2nd resignal';
+  END;
+
+  SELECT 10 + 'a';
+END $$
+delimiter ;$$
+
+--error ER_SIGNAL_EXCEPTION
+CALL p1();
+SHOW WARNINGS;
+DROP PROCEDURE p1;
+
+--echo # Unhandled errors raised in nested handlers
+--echo #
+
+delimiter $$;
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR 1051
+  BEGIN
+    DROP DATABASE none;  # Error 1008
+  END;
+  DROP TABLE none;  # Error 1051
+END $$
+delimiter ;$$
+
+--error ER_DB_DROP_EXISTS
+CALL p1();
+SHOW WARNINGS; 
+DROP PROCEDURE p1;

=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	2012-09-19 19:05:49 +0000
+++ b/sql/sp_head.cc	2012-09-27 10:09:56 +0000
@@ -437,6 +437,7 @@ bool sp_head::execute(THD *thd, bool mer
   Object_creation_ctx *saved_creation_ctx;
   Diagnostics_area *caller_da= thd->get_stmt_da();
   Diagnostics_area sp_da(caller_da->statement_id(), false);
+  Diagnostics_area *inner_da= NULL;
 
   /*
     Just reporting a stack overrun error
@@ -706,41 +707,31 @@ bool sp_head::execute(THD *thd, bool mer
   thd->stmt_arena= old_arena;
   state= STMT_EXECUTED;
 
-  /*
-    Restore the caller's original Diagnostics Area:
-      - conditions generated during trigger execution should not be
-        propagated to the caller on success;
-      - if there was an exception during execution, conditions should be
-        propagated to the caller in any case.
-  */
-  while (thd->get_stmt_da() != caller_da)
-  {
-    Diagnostics_area *inner_da= thd->get_stmt_da();
+  inner_da= thd->get_stmt_da();
+  // Restore the caller's original Diagnostics Area.
+  while (thd->get_stmt_da() != &sp_da)
     thd->pop_diagnostics_area();
-    Diagnostics_area *outer_da= thd->get_stmt_da();
+  thd->pop_diagnostics_area();
+  DBUG_ASSERT(thd->get_stmt_da() == caller_da);
 
-    // If we have unhandled errors, propagate them.
-    if (inner_da->is_error())
-    {
-      // Copy the exception condition information.
-      outer_da->set_error_status(inner_da->mysql_errno(),
-                                 inner_da->message_text(),
-                                 inner_da->returned_sqlstate(),
-                                 inner_da->error_condition());
-    }
+  if (err_status)
+  {
     /*
-      We're popping a diagnostics area for a handler which successfully
-      executed. Propagate any conditions pushed during handler execution.
-      Note: This is usually done by sp_instr_hreturn::execute(), but
-      if the handler contains RETURN we can end up here instead.
+      If the SP ended with an exception, transfer the exception condition
+      information to the Diagnostics Area of the caller.
     */
-    else if (outer_da != caller_da)
-    {
-      outer_da->reset_condition_info(thd->query_id);
-      outer_da->copy_unmarked_sql_conditions(thd, inner_da);
-    }
+    caller_da->set_error_status(inner_da->mysql_errno(),
+                                inner_da->message_text(),
+                                inner_da->returned_sqlstate(),
+                                inner_da->error_condition());
   }
 
+  /*
+    - conditions generated during trigger execution should not be
+    propagated to the caller on success;
+    - if there was an exception during execution, conditions should be
+    propagated to the caller in any case.
+  */
   if (err_status || merge_da_on_success)
   {
     /*
@@ -770,7 +761,25 @@ bool sp_head::execute(THD *thd, bool mer
         escalation of warnings to errors.
       */
       caller_da->opt_reset_condition_info(thd->query_id);
-      caller_da->copy_sql_conditions_from_da(thd, &sp_da);
+
+      if (!err_status && inner_da != &sp_da)
+      {
+        /*
+          If we are RETURNing directly from a handler and the handler has
+          executed successfully, only transfer the conditions that were
+          raised during handler execution. Conditions that were present
+          when the handler was activated, are considered handled.
+        */
+        caller_da->copy_unmarked_sql_conditions(thd, inner_da);
+      }
+      else // err_status || inner_da == sp_da
+      {
+        /*
+          If we ended with an exception or the SP exited without any handler
+          active, transfer all conditions to the Diagnostics Area of the caller.
+        */
+        caller_da->copy_sql_conditions_from_da(thd, inner_da);
+      }
     }
   }
 

=== modified file 'sql/sql_signal.cc'
--- a/sql/sql_signal.cc	2012-09-19 19:05:49 +0000
+++ b/sql/sql_signal.cc	2012-09-27 10:09:56 +0000
@@ -484,8 +484,10 @@ bool Sql_cmd_resignal::execute(THD *thd)
 
   thd->pop_diagnostics_area();
 
-  // This is a way to force sql_conditions from the current Diagnostics_area
-  // to be passed to the caller's Diagnostics_area.
+  /*
+    This is a way to force sql_conditions from the current Diagnostics Area
+    to be passed to the caller's Diagnostics Area.
+  */
   Diagnostics_area *da= thd->get_stmt_da();
   da->set_statement_id(thd->query_id);
 
@@ -500,7 +502,7 @@ bool Sql_cmd_resignal::execute(THD *thd)
   {
     query_cache_abort(&thd->query_cache_tls);
 
-    /* Make room for the new RESIGNAL condition. */
+    // Make room for the new RESIGNAL condition.
     da->reserve_number_of_conditions(thd, 1);
   }
   else
@@ -509,5 +511,28 @@ bool Sql_cmd_resignal::execute(THD *thd)
     da->remove_condition(&signaled_err);
   }
 
-  DBUG_RETURN(raise_condition(thd, &signaled_err));
+  bool error= raise_condition(thd, &signaled_err);
+
+  /*
+    If we RESIGNAL a warning, the handler will continue. Since another
+    Diagnostics Area will be popped when the handler exits, restore the
+    Diagnostics Area we just popped. By doing pop+push rather than nothing,
+    we make sure that the condition modified by RESIGNAL (if any) is modified
+    in both the first and the second Diagnostics Area, not just the first.
+  */
+  if (signaled_err.severity() == Sql_condition::SL_WARNING)
+  {
+    /*
+      Reset the DA which raise_condition() called my_ok() on above.
+      This prepares it for the statement which will be executed after
+      next pop.
+    */
+    da->reset_diagnostics_area();
+
+    Diagnostics_area *new_da= new (thd->sp_runtime_ctx->callers_arena->mem_root)
+      Diagnostics_area(da->statement_id(), false);
+    thd->push_diagnostics_area(new_da);
+  }
+
+  DBUG_RETURN(error);
 }

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk-wl6406 branch (jon.hauglid:3991 to 3992) WL#6406Jon Olav Hauglid27 Sep