List:Commits« Previous MessageNext Message »
From:marc.alff Date:April 29 2008 11:34pm
Subject:bk commit into 6.0 tree (malff:1.2637) BUG#11661 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-04-29 17:34:19-06:00, malff@stripped. +22 -0
  WL#2110 (Stored Procedures: Implement SIGNAL)
  WL#2265 (Stored Procedures: Implement RESIGNAL)
  WL#2111 (Stored Procedures: Implement GET DIAGNOSTICS)
  Bug#11661 (Raising Exceptions from within stored procedures: Support for
    SIGNAL statement)
  
  Intermadiate patch for the SIGNAL runtime,
  not ready for formal review.

  libmysqld/lib_sql.cc@stripped, 2008-04-29 17:34:12-06:00, malff@stripped. +3 -2
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  mysql-test/r/signal.result@stripped, 2008-04-29 17:34:12-06:00, malff@stripped. +151 -21
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  mysql-test/t/signal.test@stripped, 2008-04-29 17:34:12-06:00, malff@stripped. +214 -43
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/handler.cc@stripped, 2008-04-29 17:34:12-06:00, malff@stripped. +3 -9
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/log.cc@stripped, 2008-04-29 17:34:12-06:00, malff@stripped. +3 -8
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/mysqld.cc@stripped, 2008-04-29 17:34:12-06:00, malff@stripped. +14 -6
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/protocol.cc@stripped, 2008-04-29 17:34:13-06:00, malff@stripped. +10 -6
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/protocol.h@stripped, 2008-04-29 17:34:13-06:00, malff@stripped. +2 -1
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sp.cc@stripped, 2008-04-29 17:34:13-06:00, malff@stripped. +5 -8
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sp_head.cc@stripped, 2008-04-29 17:34:13-06:00, malff@stripped. +4 -0
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sp_pcontext.cc@stripped, 2008-04-29 17:34:13-06:00, malff@stripped. +2 -1
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sp_rcontext.cc@stripped, 2008-04-29 17:34:13-06:00, malff@stripped. +15 -13
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sp_rcontext.h@stripped, 2008-04-29 17:34:13-06:00, malff@stripped. +3 -5
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sql_acl.cc@stripped, 2008-04-29 17:34:13-06:00, malff@stripped. +7 -10
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sql_base.cc@stripped, 2008-04-29 17:34:13-06:00, malff@stripped. +3 -8
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sql_class.cc@stripped, 2008-04-29 17:34:13-06:00, malff@stripped. +187 -8
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sql_class.h@stripped, 2008-04-29 17:34:14-06:00, malff@stripped. +84 -13
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sql_error.cc@stripped, 2008-04-29 17:34:14-06:00, malff@stripped. +5 -2
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sql_insert.cc@stripped, 2008-04-29 17:34:14-06:00, malff@stripped. +4 -4
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sql_signal.cc@stripped, 2008-04-29 17:34:14-06:00, malff@stripped. +252 -2
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/sql_signal.h@stripped, 2008-04-29 17:34:14-06:00, malff@stripped. +4 -0
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

  sql/unireg.cc@stripped, 2008-04-29 17:34:14-06:00, malff@stripped. +3 -9
    SIGNAL / RESIGNAL / GET DIAGNOSTICS

diff -Nrup a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
--- a/libmysqld/lib_sql.cc	2008-04-19 10:55:08 -06:00
+++ b/libmysqld/lib_sql.cc	2008-04-29 17:34:12 -06:00
@@ -1061,14 +1061,15 @@ net_send_eof(THD *thd, uint server_statu
 }
 
 
-void net_send_error_packet(THD *thd, uint sql_errno, const char *err)
+void net_send_error_packet(THD *thd, uint sql_errno, const char *err,
+                           const char* sqlstate)
 {
   MYSQL_DATA *data= thd->cur_data ? thd->cur_data : thd->alloc_new_dataset();
   struct embedded_query_result *ei= data->embedded_info;
 
   ei->last_errno= sql_errno;
   strmake(ei->info, err, sizeof(ei->info)-1);
-  strmov(ei->sqlstate, mysql_errno_to_sqlstate(sql_errno));
+  strmov(ei->sqlstate, sqlstate);
   ei->server_status= thd->server_status;
   thd->cur_data= 0;
 }
diff -Nrup a/mysql-test/r/signal.result b/mysql-test/r/signal.result
--- a/mysql-test/r/signal.result	2008-04-23 14:27:09 -06:00
+++ b/mysql-test/r/signal.result	2008-04-29 17:34:12 -06:00
@@ -66,14 +66,8 @@ create table test_reserved (resignal int
 ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'resignal int)' at line 1
 create table test_reserved (get int);
 ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'get int)' at line 1
-SIGNAL foo;
-ERROR 42000: Undefined CONDITION: foo
-SIGNAL SQLSTATE '23000';
-ERROR 42000: This version of MySQL doesn't yet support 'SIGNAL'
-SIGNAL SQLSTATE VALUE '23000';
-ERROR 42000: This version of MySQL doesn't yet support 'SIGNAL'
 drop procedure if exists test_invalid;
-drop procedure if exists test_signal;
+drop procedure if exists test_signal_syntax;
 create procedure test_invalid()
 begin
 SIGNAL;
@@ -322,14 +316,6 @@ SIGNAL SQLSTATE '12345' SET TRIGGER_SCHE
 end $$
 ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TRIGGER_SCHEMA = 'foo';
 end' at line 3
-RESIGNAL;
-ERROR 42000: This version of MySQL doesn't yet support 'RESIGNAL'
-RESIGNAL foo;
-ERROR 42000: Undefined CONDITION: foo
-RESIGNAL SQLSTATE '12345';
-ERROR 42000: This version of MySQL doesn't yet support 'RESIGNAL'
-RESIGNAL SQLSTATE VALUE '12345';
-ERROR 42000: This version of MySQL doesn't yet support 'RESIGNAL'
 drop procedure if exists test_invalid;
 drop procedure if exists test_resignal_syntax;
 create procedure test_invalid()
@@ -470,12 +456,6 @@ begin
 RESIGNAL SQLSTATE '00000';
 end $$
 ERROR 42000: Bad SQLSTATE: '00000'
-GET DIAGNOSTICS @foo = NUMBER;
-ERROR 42000: This version of MySQL doesn't yet support 'GET DIAGNOSTICS'
-GET CURRENT DIAGNOSTICS @foo = NUMBER;
-ERROR 42000: This version of MySQL doesn't yet support 'GET DIAGNOSTICS'
-GET STACKED DIAGNOSTICS @foo = NUMBER;
-ERROR 42000: This version of MySQL doesn't yet support 'GET DIAGNOSTICS'
 drop procedure if exists test_invalid;
 drop procedure if exists test_diag_syntax;
 create procedure test_invalid()
@@ -1125,3 +1105,153 @@ prepare stmt from 'RESIGNAL SQLSTATE \'2
 ERROR HY000: This command is not supported in the prepared statement protocol yet
 prepare stmt from 'GET DIAGNOSTICS @foo = NUMBER';
 ERROR HY000: This command is not supported in the prepared statement protocol yet
+drop procedure if exists test_signal;
+SIGNAL foo;
+ERROR 42000: Undefined CONDITION: foo
+SIGNAL SQLSTATE '23000';
+ERROR 23000: Unhandled user-defined exception
+SIGNAL SQLSTATE VALUE '23000';
+ERROR 23000: Unhandled user-defined exception
+RESIGNAL;
+ERROR 42000: This version of MySQL doesn't yet support 'RESIGNAL'
+RESIGNAL foo;
+ERROR 42000: Undefined CONDITION: foo
+RESIGNAL SQLSTATE '12345';
+ERROR 42000: This version of MySQL doesn't yet support 'RESIGNAL'
+RESIGNAL SQLSTATE VALUE '12345';
+ERROR 42000: This version of MySQL doesn't yet support 'RESIGNAL'
+GET DIAGNOSTICS @foo = NUMBER;
+ERROR 42000: This version of MySQL doesn't yet support 'GET DIAGNOSTICS'
+GET CURRENT DIAGNOSTICS @foo = NUMBER;
+ERROR 42000: This version of MySQL doesn't yet support 'GET DIAGNOSTICS'
+GET STACKED DIAGNOSTICS @foo = NUMBER;
+ERROR 42000: This version of MySQL doesn't yet support 'GET DIAGNOSTICS'
+create procedure test_signal()
+begin
+# Unknown -> "HY" -> error
+DECLARE foo CONDITION FOR 9999;
+SIGNAL foo;
+end $$
+call test_signal() $$
+ERROR HY000: Unhandled user-defined exception
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# warning
+DECLARE too_few_records CONDITION FOR 1261;
+SIGNAL too_few_records;
+end $$
+call test_signal() $$
+Warnings:
+Warning	1261	Unhandled user-defined warning
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# Not found
+DECLARE sp_fetch_no_data CONDITION FOR 1329;
+SIGNAL sp_fetch_no_data;
+end $$
+call test_signal() $$
+ERROR 02000: Unhandled user-defined not found
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# Error
+DECLARE sp_cursor_already_open CONDITION FOR 1325;
+SIGNAL sp_cursor_already_open;
+end $$
+call test_signal() $$
+ERROR 24000: Unhandled user-defined exception
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# Severe error
+DECLARE lock_deadlock CONDITION FOR 1213;
+SIGNAL lock_deadlock;
+end $$
+call test_signal() $$
+ERROR 40001: Unhandled user-defined exception
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# Unknown -> error
+DECLARE foo CONDITION FOR SQLSTATE "99999";
+SIGNAL foo;
+end $$
+call test_signal() $$
+ERROR 99999: Unhandled user-defined exception
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# warning, no subclass
+DECLARE warn CONDITION FOR SQLSTATE "01000";
+SIGNAL warn;
+end $$
+call test_signal() $$
+Warnings:
+Warning	1	Unhandled user-defined warning
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# warning, with subclass
+DECLARE warn CONDITION FOR SQLSTATE "01123";
+SIGNAL warn;
+end $$
+call test_signal() $$
+Warnings:
+Warning	1	Unhandled user-defined warning
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# Not found, no subclass
+DECLARE not_found CONDITION FOR SQLSTATE "02000";
+SIGNAL not_found;
+end $$
+call test_signal() $$
+ERROR 02000: Unhandled user-defined not found
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# Not found, with subclass
+DECLARE not_found CONDITION FOR SQLSTATE "02XXX";
+SIGNAL not_found;
+end $$
+call test_signal() $$
+ERROR 02XXX: Unhandled user-defined not found
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# Error, no subclass
+DECLARE error CONDITION FOR SQLSTATE "12000";
+SIGNAL error;
+end $$
+call test_signal() $$
+ERROR 12000: Unhandled user-defined exception
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# Error, with subclass
+DECLARE error CONDITION FOR SQLSTATE "12ABC";
+SIGNAL error;
+end $$
+call test_signal() $$
+ERROR 12ABC: Unhandled user-defined exception
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# Severe error, no subclass
+DECLARE error CONDITION FOR SQLSTATE "40000";
+SIGNAL error;
+end $$
+call test_signal() $$
+ERROR 40000: Unhandled user-defined exception
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# Severe error, with subclass
+DECLARE error CONDITION FOR SQLSTATE "40001";
+SIGNAL error;
+end $$
+call test_signal() $$
+ERROR 40001: Unhandled user-defined exception
+drop procedure test_signal $$
diff -Nrup a/mysql-test/t/signal.test b/mysql-test/t/signal.test
--- a/mysql-test/t/signal.test	2008-04-23 14:27:10 -06:00
+++ b/mysql-test/t/signal.test	2008-04-29 17:34:12 -06:00
@@ -118,25 +118,12 @@ create table test_reserved (resignal int
 create table test_reserved (get int);
 
 #
-# SIGNAL can also appear in a query
-#
-
---error ER_SP_COND_MISMATCH
-SIGNAL foo;
-
---error ER_NOT_SUPPORTED_YET
-SIGNAL SQLSTATE '23000';
-
---error ER_NOT_SUPPORTED_YET
-SIGNAL SQLSTATE VALUE '23000';
-
-#
 # Test the SIGNAL syntax
 #
 
 --disable_warnings
 drop procedure if exists test_invalid;
-drop procedure if exists test_signal;
+drop procedure if exists test_signal_syntax;
 --enable_warnings
 
 delimiter $$;
@@ -417,22 +404,6 @@ end $$
 delimiter ;$$
 
 #
-# RESIGNAL can also appear in a query
-#
-
---error ER_NOT_SUPPORTED_YET
-RESIGNAL;
-
---error ER_SP_COND_MISMATCH
-RESIGNAL foo;
-
---error ER_NOT_SUPPORTED_YET
-RESIGNAL SQLSTATE '12345';
-
---error ER_NOT_SUPPORTED_YET
-RESIGNAL SQLSTATE VALUE '12345';
-
-#
 # Test the RESIGNAL syntax
 #
 
@@ -606,19 +577,6 @@ end $$
 delimiter ;$$
 
 #
-# GET DIAGNOSTICS can also appear in a query
-#
-
---error ER_NOT_SUPPORTED_YET
-GET DIAGNOSTICS @foo = NUMBER;
-
---error ER_NOT_SUPPORTED_YET
-GET CURRENT DIAGNOSTICS @foo = NUMBER;
-
---error ER_NOT_SUPPORTED_YET
-GET STACKED DIAGNOSTICS @foo = NUMBER;
-
-#
 # Test the GET DIAGNOSTICS syntax
 #
 
@@ -1346,5 +1304,218 @@ prepare stmt from 'GET DIAGNOSTICS @foo 
 #
 # PART 3: runtime execution
 #
+
+--disable_warnings
+drop procedure if exists test_signal;
+--enable_warnings
+
+#
+# SIGNAL can also appear in a query
+#
+
+--error ER_SP_COND_MISMATCH
+SIGNAL foo;
+
+--error 1
+SIGNAL SQLSTATE '23000';
+
+--error 1
+SIGNAL SQLSTATE VALUE '23000';
+
+#
+# RESIGNAL can also appear in a query
+#
+
+--error ER_NOT_SUPPORTED_YET
+RESIGNAL;
+
+--error ER_SP_COND_MISMATCH
+RESIGNAL foo;
+
+--error ER_NOT_SUPPORTED_YET
+RESIGNAL SQLSTATE '12345';
+
+--error ER_NOT_SUPPORTED_YET
+RESIGNAL SQLSTATE VALUE '12345';
+
+#
+# GET DIAGNOSTICS can also appear in a query
+#
+
+--error ER_NOT_SUPPORTED_YET
+GET DIAGNOSTICS @foo = NUMBER;
+
+--error ER_NOT_SUPPORTED_YET
+GET CURRENT DIAGNOSTICS @foo = NUMBER;
+
+--error ER_NOT_SUPPORTED_YET
+GET STACKED DIAGNOSTICS @foo = NUMBER;
+
+
+#
+# Different kind of SIGNAL conditions
+#
+
+delimiter $$;
+
+create procedure test_signal()
+begin
+  # Unknown -> "HY" -> error
+  DECLARE foo CONDITION FOR 9999;
+  SIGNAL foo;
+end $$
+
+--error 9999
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # warning
+  DECLARE too_few_records CONDITION FOR 1261;
+  SIGNAL too_few_records;
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # Not found
+  DECLARE sp_fetch_no_data CONDITION FOR 1329;
+  SIGNAL sp_fetch_no_data;
+end $$
+
+--error ER_SP_FETCH_NO_DATA
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # Error
+  DECLARE sp_cursor_already_open CONDITION FOR 1325;
+  SIGNAL sp_cursor_already_open;
+end $$
+
+--error ER_SP_CURSOR_ALREADY_OPEN
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # Severe error
+  DECLARE lock_deadlock CONDITION FOR 1213;
+  SIGNAL lock_deadlock;
+end $$
+
+--error ER_LOCK_DEADLOCK
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # Unknown -> error
+  DECLARE foo CONDITION FOR SQLSTATE "99999";
+  SIGNAL foo;
+end $$
+
+--error 1
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # warning, no subclass
+  DECLARE warn CONDITION FOR SQLSTATE "01000";
+  SIGNAL warn;
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # warning, with subclass
+  DECLARE warn CONDITION FOR SQLSTATE "01123";
+  SIGNAL warn;
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # Not found, no subclass
+  DECLARE not_found CONDITION FOR SQLSTATE "02000";
+  SIGNAL not_found;
+end $$
+
+--error 1
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # Not found, with subclass
+  DECLARE not_found CONDITION FOR SQLSTATE "02XXX";
+  SIGNAL not_found;
+end $$
+
+--error 1
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # Error, no subclass
+  DECLARE error CONDITION FOR SQLSTATE "12000";
+  SIGNAL error;
+end $$
+
+--error 1
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # Error, with subclass
+  DECLARE error CONDITION FOR SQLSTATE "12ABC";
+  SIGNAL error;
+end $$
+
+--error 1
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # Severe error, no subclass
+  DECLARE error CONDITION FOR SQLSTATE "40000";
+  SIGNAL error;
+end $$
+
+--error 1
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # Severe error, with subclass
+  DECLARE error CONDITION FOR SQLSTATE "40001";
+  SIGNAL error;
+end $$
+
+--error 1
+call test_signal() $$
+drop procedure test_signal $$
+
+
+
+
+
+
+
+
+delimiter ;$$
 
 
diff -Nrup a/sql/handler.cc b/sql/handler.cc
--- a/sql/handler.cc	2008-04-07 09:26:37 -06:00
+++ b/sql/handler.cc	2008-04-29 17:34:12 -06:00
@@ -1849,23 +1849,17 @@ static const char *check_lowercase_names
 struct Ha_delete_table_error_handler: public Internal_error_handler
 {
 public:
-  virtual bool handle_error(uint sql_errno,
-                            const char *message,
-                            MYSQL_ERROR::enum_warning_level level,
-                            THD *thd);
+  virtual bool handle_condition(THD *thd, const SQL_condition *cond);
   char buff[MYSQL_ERRMSG_SIZE];
 };
 
 
 bool
 Ha_delete_table_error_handler::
-handle_error(uint sql_errno,
-             const char *message,
-             MYSQL_ERROR::enum_warning_level level,
-             THD *thd)
+handle_condition(THD *, const SQL_condition *cond)
 {
   /* Grab the error message */
-  strmake(buff, message, sizeof(buff)-1);
+  strmake(buff, cond->get_message_text(), sizeof(buff)-1);
   return TRUE;
 }
 
diff -Nrup a/sql/log.cc b/sql/log.cc
--- a/sql/log.cc	2008-04-14 04:09:58 -06:00
+++ b/sql/log.cc	2008-04-29 17:34:12 -06:00
@@ -81,19 +81,14 @@ public:
 
   virtual ~Silence_log_table_errors() {}
 
-  virtual bool handle_error(uint sql_errno, const char *message,
-                            MYSQL_ERROR::enum_warning_level level,
-                            THD *thd);
+  virtual bool handle_condition(THD *thd, const SQL_condition *cond);
   const char *message() const { return m_message; }
 };
 
 bool
-Silence_log_table_errors::handle_error(uint /* sql_errno */,
-                                       const char *message_arg,
-                                       MYSQL_ERROR::enum_warning_level /* level */,
-                                       THD * /* thd */)
+Silence_log_table_errors::handle_condition(THD *, const SQL_condition *cond)
 {
-  strmake(m_message, message_arg, sizeof(m_message)-1);
+  strmake(m_message, cond->get_message_text(), sizeof(m_message)-1);
   return TRUE;
 }
 
diff -Nrup a/sql/mysqld.cc b/sql/mysqld.cc
--- a/sql/mysqld.cc	2008-04-23 14:27:10 -06:00
+++ b/sql/mysqld.cc	2008-04-29 17:34:12 -06:00
@@ -1869,7 +1869,10 @@ void close_connection(THD *thd, uint err
   if ((vio= thd->net.vio) != 0)
   {
     if (errcode)
-      net_send_error(thd, errcode, ER(errcode)); /* purecov: inspected */
+    {
+      const char* sqlstate= mysql_errno_to_sqlstate(errcode);
+      net_send_error(thd, errcode, ER(errcode), sqlstate); /* purecov: inspected */
+    }
     vio_close(vio);			/* vio is freed in delete thd */
   }
   if (lock)
@@ -2933,12 +2936,14 @@ void my_message_sql(uint error, const ch
 #endif
 
 
+    SQL_condition cond;
+    cond.set(error, str, MYSQL_ERROR::WARN_LEVEL_ERROR, MyFlags);
+
     /*
       TODO: There are two exceptions mechanism (THD and sp_rcontext),
       this could be improved by having a common stack of handlers.
     */
-    if (thd->handle_error(error, str,
-                          MYSQL_ERROR::WARN_LEVEL_ERROR))
+    if (thd->handle_condition(& cond))
       DBUG_VOID_RETURN;
 
     thd->is_slave_error=  1; // needed to catch query errors during replication
@@ -2965,7 +2970,7 @@ void my_message_sql(uint error, const ch
           error= ER_UNKNOWN_ERROR;
         if (str == NULL)
           str= ER(error);
-        thd->main_da.set_error_status(thd, error, str);
+        thd->main_da.set_error_status(thd, error, str, cond.get_sqlstate());
       }
       query_cache_abort(&thd->query_cache_tls);
     }
@@ -2974,7 +2979,7 @@ void my_message_sql(uint error, const ch
       by the stored procedures code.
     */
     if (!thd->is_fatal_error && thd->spcont &&
-        thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
+        thd->spcont->handle_condition(thd, & cond))
     {
       /*
         Do not push any warnings, a handled error must be completely
@@ -4849,6 +4854,8 @@ void create_thread_to_handle_connection(
                               handle_one_connection,
                               (void*) thd)))
     {
+      const char* sqlstate;
+
       /* purify: begin inspected */
       DBUG_PRINT("error",
                  ("Can't create thread to handle request (error %d)",
@@ -4865,7 +4872,8 @@ void create_thread_to_handle_connection(
       /* Can't use my_error() since store_globals has not been called. */
       my_snprintf(error_message_buff, sizeof(error_message_buff),
                   ER(ER_CANT_CREATE_THREAD), error);
-      net_send_error(thd, ER_CANT_CREATE_THREAD, error_message_buff);
+      sqlstate= mysql_errno_to_sqlstate(ER_CANT_CREATE_THREAD);
+      net_send_error(thd, ER_CANT_CREATE_THREAD, error_message_buff, sqlstate);
       (void) pthread_mutex_lock(&LOCK_thread_count);
       close_connection(thd,0,0);
       delete thd;
diff -Nrup a/sql/protocol.cc b/sql/protocol.cc
--- a/sql/protocol.cc	2008-03-18 04:54:33 -06:00
+++ b/sql/protocol.cc	2008-04-29 17:34:13 -06:00
@@ -29,7 +29,8 @@
 
 static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
 /* Declared non-static only because of the embedded library. */
-void net_send_error_packet(THD *thd, uint sql_errno, const char *err);
+void net_send_error_packet(THD *thd, uint sql_errno, const char *err,
+                           const char* sqlstate);
 void net_send_ok(THD *, uint, uint, ha_rows, ulonglong, const char *);
 void net_send_eof(THD *thd, uint server_status, uint total_warn_count);
 #ifndef EMBEDDED_LIBRARY
@@ -128,7 +129,8 @@ bool Protocol::net_store_data(const ucha
   critical that every error that can be intercepted is issued in one
   place only, my_message_sql.
 */
-void net_send_error(THD *thd, uint sql_errno, const char *err)
+void net_send_error(THD *thd, uint sql_errno, const char *err,
+                    const char* sqlstate)
 {
   DBUG_ENTER("net_send_error");
 
@@ -147,7 +149,7 @@ void net_send_error(THD *thd, uint sql_e
   /* Abort multi-result sets */
   thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
 
-  net_send_error_packet(thd, sql_errno, err);
+  net_send_error_packet(thd, sql_errno, err, sqlstate);
 
   thd->main_da.can_overwrite_status= FALSE;
 
@@ -318,7 +320,8 @@ bool send_old_password_request(THD *thd)
 }
 
 
-void net_send_error_packet(THD *thd, uint sql_errno, const char *err)
+void net_send_error_packet(THD *thd, uint sql_errno, const char *err,
+                           const char* sqlstate)
 {
   NET *net= &thd->net;
   uint length;
@@ -345,7 +348,7 @@ void net_send_error_packet(THD *thd, uin
   {
     /* The first # is to make the protocol backward compatible */
     buff[2]= '#';
-    pos= (uchar*) strmov((char*) buff+3, mysql_errno_to_sqlstate(sql_errno));
+    pos= (uchar*) strmov((char*) buff+3, sqlstate);
   }
   length= (uint) (strmake((char*) pos, err, MYSQL_ERRMSG_SIZE-1) -
                   (char*) buff);
@@ -444,7 +447,8 @@ void net_end_statement(THD *thd)
     /* The query failed, send error to log and abort bootstrap. */
     net_send_error(thd,
                    thd->main_da.sql_errno(),
-                   thd->main_da.message());
+                   thd->main_da.message(),
+                   thd->main_da.get_sqlstate());
     break;
   case Diagnostics_area::DA_EOF:
     net_send_eof(thd,
diff -Nrup a/sql/protocol.h b/sql/protocol.h
--- a/sql/protocol.h	2008-02-11 09:05:54 -07:00
+++ b/sql/protocol.h	2008-04-29 17:34:13 -06:00
@@ -175,7 +175,8 @@ public:
 };
 
 void send_warning(THD *thd, uint sql_errno, const char *err=0);
-void net_send_error(THD *thd, uint sql_errno=0, const char *err=0);
+void net_send_error(THD *thd, uint sql_errno, const char *err,
+                    const char* sqlstate);
 void net_end_statement(THD *thd);
 bool send_old_password_request(THD *thd);
 uchar *net_store_data(uchar *to,const uchar *from, size_t length);
diff -Nrup a/sql/sp.cc b/sql/sp.cc
--- a/sql/sp.cc	2008-04-08 10:35:58 -06:00
+++ b/sql/sp.cc	2008-04-29 17:34:13 -06:00
@@ -495,18 +495,15 @@ db_find_routine(THD *thd, int type, sp_n
 struct Silence_deprecated_warning : public Internal_error_handler
 {
 public:
-  virtual bool handle_error(uint sql_errno, const char *message,
-                            MYSQL_ERROR::enum_warning_level level,
-                            THD *thd);
+  virtual bool handle_condition(THD *thd, const SQL_condition *cond);
 };
 
 bool
-Silence_deprecated_warning::handle_error(uint sql_errno, const char *message,
-                                         MYSQL_ERROR::enum_warning_level level,
-                                         THD *thd)
+Silence_deprecated_warning::handle_condition(THD *thd,
+                                             const SQL_condition *cond)
 {
-  if (sql_errno == ER_WARN_DEPRECATED_SYNTAX &&
-      level == MYSQL_ERROR::WARN_LEVEL_WARN)
+  if (cond->m_sqlcode == ER_WARN_DEPRECATED_SYNTAX &&
+      cond->m_level == MYSQL_ERROR::WARN_LEVEL_WARN)
     return TRUE;
 
   return FALSE;
diff -Nrup a/sql/sp_head.cc b/sql/sp_head.cc
--- a/sql/sp_head.cc	2008-04-08 09:37:10 -06:00
+++ b/sql/sp_head.cc	2008-04-29 17:34:13 -06:00
@@ -1251,6 +1251,8 @@ sp_head::execute(THD *thd)
         ctx->push_hstack(i->get_cont_dest());
         /* Fall through */
       default:
+        if (thd->end_partial_result_set)
+          thd->protocol->end_partial_result_set(thd);
         ip= hip;
         err_status= FALSE;
         ctx->clear_handler();
@@ -1261,6 +1263,8 @@ sp_head::execute(THD *thd)
         thd->mysys_var->abort= 0;
         continue;
       }
+
+      thd->end_partial_result_set= FALSE;
     }
   } while (!err_status && !thd->killed && !thd->is_fatal_error);
 
diff -Nrup a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
--- a/sql/sp_pcontext.cc	2008-03-21 12:07:59 -06:00
+++ b/sql/sp_pcontext.cc	2008-04-29 17:34:13 -06:00
@@ -51,7 +51,8 @@ sp_cond_check(LEX_STRING *sqlstate)
 	(c < 'A' || 'Z' < c))
       return FALSE;
   }
-  if (strcmp(sqlstate->str, "00000") == 0)
+  /* SQLSTATE class "00": successful completion */
+  if (strncmp(sqlstate->str, "00", 2) == 0)
     return FALSE;
   return TRUE;
 }
diff -Nrup a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
--- a/sql/sp_rcontext.cc	2008-01-23 15:36:39 -07:00
+++ b/sql/sp_rcontext.cc	2008-04-29 17:34:13 -06:00
@@ -194,13 +194,15 @@ sp_rcontext::set_return_value(THD *thd, 
 */
 
 bool
-sp_rcontext::find_handler(THD *thd, uint sql_errno,
-                          MYSQL_ERROR::enum_warning_level level)
+sp_rcontext::find_handler(THD *thd, const SQL_condition *cond)
 {
   if (m_hfound >= 0)
     return 1;			// Already got one
 
-  const char *sqlstate= mysql_errno_to_sqlstate(sql_errno);
+  uint sql_errno= cond->m_sqlcode;
+  MYSQL_ERROR::enum_warning_level level= cond->m_level;
+
+  const char *sqlstate= cond->get_sqlstate();
   int i= m_hcount, found= -1;
 
   /*
@@ -264,7 +266,7 @@ sp_rcontext::find_handler(THD *thd, uint
     */
     if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) &&
         level == MYSQL_ERROR::WARN_LEVEL_ERROR)
-      return m_prev_runtime_ctx->find_handler(thd, sql_errno, level);
+      return m_prev_runtime_ctx->find_handler(thd, cond);
     return FALSE;
   }
   m_hfound= found;
@@ -293,22 +295,22 @@ sp_rcontext::find_handler(THD *thd, uint
     FALSE      if no handler was found.
 */
 bool
-sp_rcontext::handle_error(uint sql_errno,
-                          MYSQL_ERROR::enum_warning_level level,
-                          THD *thd)
+sp_rcontext::handle_condition(THD *thd, const SQL_condition *cond)
 {
-  MYSQL_ERROR::enum_warning_level elevated_level= level;
-
-
   /* Depending on the sql_mode of execution,
      warnings may be considered errors */
-  if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
+  if ((cond->m_level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
       thd->really_abort_on_warning())
   {
-    elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+    SQL_condition elevated_cond;
+    elevated_cond.set(cond->m_sqlcode,
+                      cond->get_message_text(),
+                      MYSQL_ERROR::WARN_LEVEL_ERROR,
+                      MYF(0));
+    return find_handler(thd, & elevated_cond);
   }
 
-  return find_handler(thd, sql_errno, elevated_level);
+  return find_handler(thd, cond);
 }
 
 void
diff -Nrup a/sql/sp_rcontext.h b/sql/sp_rcontext.h
--- a/sql/sp_rcontext.h	2008-01-23 13:26:39 -07:00
+++ b/sql/sp_rcontext.h	2008-04-29 17:34:13 -06:00
@@ -113,13 +113,11 @@ class sp_rcontext : public Sql_alloc
 
   // Returns 1 if a handler was found, 0 otherwise.
   bool
-  find_handler(THD *thd, uint sql_errno,MYSQL_ERROR::enum_warning_level level);
+  find_handler(THD *thd, const SQL_condition *cond);
 
   // If there is an error handler for this error, handle it and return TRUE.
-  bool
-  handle_error(uint sql_errno,
-               MYSQL_ERROR::enum_warning_level level,
-               THD *thd);
+  bool handle_condition(THD *thd, const SQL_condition *cond);
+
 
   // Returns handler type and sets *ip to location if one was found
   inline int
diff -Nrup a/sql/sql_acl.cc b/sql/sql_acl.cc
--- a/sql/sql_acl.cc	2008-04-14 05:30:04 -06:00
+++ b/sql/sql_acl.cc	2008-04-29 17:34:13 -06:00
@@ -6129,9 +6129,7 @@ public:
   virtual ~Silence_routine_definer_errors()
   {}
 
-  virtual bool handle_error(uint sql_errno, const char *message,
-                            MYSQL_ERROR::enum_warning_level level,
-                            THD *thd);
+  virtual bool handle_condition(THD *thd, const SQL_condition *cond);
 
   bool has_errors() { return is_grave; }
 
@@ -6140,18 +6138,17 @@ private:
 };
 
 bool
-Silence_routine_definer_errors::handle_error(uint sql_errno,
-                                       const char *message,
-                                       MYSQL_ERROR::enum_warning_level level,
-                                       THD *thd)
+Silence_routine_definer_errors::handle_condition(THD *thd,
+                                                 const SQL_condition *cond)
 {
-  if (level == MYSQL_ERROR::WARN_LEVEL_ERROR)
+  if (cond->m_level == MYSQL_ERROR::WARN_LEVEL_ERROR)
   {
-    switch (sql_errno)
+    switch (cond->m_sqlcode)
     {
       case ER_NONEXISTING_PROC_GRANT:
         /* Convert the error into a warning. */
-        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno, message);
+        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                     cond->m_sqlcode, cond->get_message_text());
         return TRUE;
       default:
         is_grave= TRUE;
diff -Nrup a/sql/sql_base.cc b/sql/sql_base.cc
--- a/sql/sql_base.cc	2008-04-14 04:10:00 -06:00
+++ b/sql/sql_base.cc	2008-04-29 17:34:13 -06:00
@@ -44,9 +44,7 @@ public:
 
   virtual ~Prelock_error_handler() {}
 
-  virtual bool handle_error(uint sql_errno, const char *message,
-                            MYSQL_ERROR::enum_warning_level level,
-                            THD *thd);
+  virtual bool handle_condition(THD *thd, const SQL_condition *cond);
 
   bool safely_trapped_errors();
 
@@ -57,12 +55,9 @@ private:
 
 
 bool
-Prelock_error_handler::handle_error(uint sql_errno,
-                                    const char * /* message */,
-                                    MYSQL_ERROR::enum_warning_level /* level */,
-                                    THD * /* thd */)
+Prelock_error_handler::handle_condition(THD *, const SQL_condition *cond)
 {
-  if (sql_errno == ER_NO_SUCH_TABLE)
+  if (cond->m_sqlcode == ER_NO_SUCH_TABLE)
   {
     m_handled_errors++;
     return TRUE;
diff -Nrup a/sql/sql_class.cc b/sql/sql_class.cc
--- a/sql/sql_class.cc	2008-04-23 14:27:10 -06:00
+++ b/sql/sql_class.cc	2008-04-29 17:34:13 -06:00
@@ -377,6 +377,7 @@ Diagnostics_area::reset_diagnostics_area
   /** Don't take chances in production */
   m_message[0]= '\0';
   m_sql_errno= 0;
+  memset(m_sqlstate, 0, sizeof(m_sqlstate));
   m_server_status= 0;
   m_affected_rows= 0;
   m_last_insert_id= 0;
@@ -456,9 +457,18 @@ Diagnostics_area::set_eof_status(THD *th
 */
 
 void
-Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
+Diagnostics_area::set_default_error_status(THD *thd, uint sql_errno_arg,
                                    const char *message_arg)
 {
+  const char* sqlstate= mysql_errno_to_sqlstate(sql_errno_arg);
+  set_error_status(thd, sql_errno_arg, message_arg, sqlstate);
+}
+
+void
+Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
+                                   const char *message_arg,
+                                   const char *sqlstate)
+{
   /*
     Only allowed to report error if has not yet reported a success
     The only exception is when we flush the message to the client,
@@ -475,6 +485,8 @@ Diagnostics_area::set_error_status(THD *
 #endif
 
   m_sql_errno= sql_errno_arg;
+  strncpy(m_sqlstate, sqlstate, 5);
+  m_sqlstate[5]= '\0';
   strmake(m_message, message_arg, sizeof(m_message) - 1);
 
   m_status= DA_ERROR;
@@ -519,6 +531,7 @@ THD::THD()
    bootstrap(0),
    derived_tables_processing(FALSE),
    spcont(NULL),
+   end_partial_result_set(FALSE),
    m_lip(NULL),
   /*
     @todo The following is a work around for online backup and the DDL blocker.
@@ -651,12 +664,11 @@ void THD::push_internal_handler(Internal
 }
 
 
-bool THD::handle_error(uint sql_errno, const char *message,
-                       MYSQL_ERROR::enum_warning_level level)
+bool THD::handle_condition(const SQL_condition *cond)
 {
   if (m_internal_handler)
   {
-    return m_internal_handler->handle_error(sql_errno, message, level, this);
+    return m_internal_handler->handle_condition(this, cond);
   }
 
   return FALSE;                                 // 'FALSE', as per coding style
@@ -669,6 +681,174 @@ void THD::pop_internal_handler()
   m_internal_handler= NULL;
 }
 
+void THD::raise_error(uint code, const char *str, myf MyFlags)
+{
+  SQL_condition cond;
+  cond.set(code, str, MYSQL_ERROR::WARN_LEVEL_ERROR, MyFlags);
+
+  raise_condition(& cond);
+}
+
+void THD::raise_error_printf(uint code, const char *format, myf MyFlags, ...)
+{
+  va_list args;
+  char ebuff[ERRMSGSIZE+20];
+
+
+  DBUG_ENTER("THD::raise_error_printf");
+  DBUG_PRINT("my", ("nr: %d  MyFlags: %d  errno: %d  Format: %s",
+                    code, MyFlags, errno, format));
+
+  va_start(args, MyFlags);
+  (void) my_vsnprintf (ebuff, sizeof(ebuff), format, args);
+  va_end(args);
+
+  SQL_condition cond;
+  cond.set(code, ebuff, MYSQL_ERROR::WARN_LEVEL_ERROR, MyFlags);
+
+  raise_condition(& cond);
+  DBUG_VOID_RETURN;
+}
+
+void THD::raise_warning(uint code, const char *msg)
+{
+  SQL_condition cond;
+  cond.set(code, msg, MYSQL_ERROR::WARN_LEVEL_WARN, MYF(0));
+
+  raise_condition(& cond);
+}
+
+void THD::raise_warning_printf(uint code, const char *format, ...)
+{
+  va_list args;
+  char    ebuff[ERRMSGSIZE+20];
+
+
+  DBUG_ENTER("THD::raise_warning_printf");
+  DBUG_PRINT("enter", ("warning: %u", code));
+
+  va_start(args, format);
+  my_vsnprintf(ebuff, sizeof(ebuff), format, args);
+  va_end(args);
+
+  SQL_condition cond;
+  cond.set(code, ebuff, MYSQL_ERROR::WARN_LEVEL_WARN, MYF(0));
+
+  raise_condition(& cond);
+  DBUG_VOID_RETURN;
+}
+
+void THD::raise_note(uint code, const char *msg)
+{
+  DBUG_ENTER("THD::raise_note");
+  DBUG_PRINT("enter", ("code: %d, msg: %s", code, msg));
+
+  if (!(this->options & OPTION_SQL_NOTES))
+    DBUG_VOID_RETURN;
+
+  SQL_condition cond;
+  cond.set(code, msg, MYSQL_ERROR::WARN_LEVEL_NOTE, MYF(0));
+
+  raise_condition(& cond);
+  DBUG_VOID_RETURN;
+}
+
+void THD::raise_note_printf(uint code, const char *format, ...)
+{
+  va_list args;
+  char    ebuff[ERRMSGSIZE+20];
+
+
+  DBUG_ENTER("THD::raise_note_printf");
+  DBUG_PRINT("enter",("code: %u", code));
+
+  if (!(this->options & OPTION_SQL_NOTES))
+    DBUG_VOID_RETURN;
+
+  va_start(args, format);
+  my_vsnprintf(ebuff, sizeof(ebuff), format, args);
+  va_end(args);
+
+  SQL_condition cond;
+  cond.set(code, ebuff, MYSQL_ERROR::WARN_LEVEL_NOTE, MYF(0));
+
+  raise_condition(& cond);
+  DBUG_VOID_RETURN;
+}
+
+void THD::raise_condition(const SQL_condition *cond)
+{
+  MYSQL_ERROR *err;
+  const char* msg= cond->get_message_text();
+
+  DBUG_ENTER("THD::raise_condition");
+
+  switch (cond->m_level)
+  {
+  case MYSQL_ERROR::WARN_LEVEL_NOTE:
+  case MYSQL_ERROR::WARN_LEVEL_WARN:
+    if (query_id != warn_id && !spcont)
+      mysql_reset_errors(this, 0);
+    got_warning= 1;
+    break;
+  case MYSQL_ERROR::WARN_LEVEL_ERROR:
+    if (cond->m_flags & ME_FATALERROR)
+      is_fatal_error= 1;
+
+#ifdef BUG_36098_FIXED
+    mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_ERROR, error, my_time(0),
+                        0, 0, msg, msg ? strlen(msg) : 0,
+                        query, query_length,
+                        variables.character_set_client,
+                        row_count);
+#endif
+
+    break;
+  default:
+    DBUG_ASSERT(FALSE);
+  }
+
+  if (handle_condition(cond))
+    DBUG_VOID_RETURN;
+
+  if ((cond->m_level == MYSQL_ERROR::WARN_LEVEL_ERROR) &&
+      ! main_da.is_error())
+    main_da.set_error_status(this, cond->m_sqlcode, msg, cond->get_sqlstate());
+
+  if (cond->m_level == MYSQL_ERROR::WARN_LEVEL_ERROR)
+    is_slave_error=  1; // needed to catch query errors during replication
+
+  /*
+    If a continue handler is found, the error message will be cleared
+    by the stored procedures code.
+  */
+  if (!is_fatal_error && spcont &&
+      spcont->handle_condition(this, cond))
+  {
+    /*
+      Do not push any warnings, a handled error must be completely
+      silenced.
+    */
+    DBUG_VOID_RETURN;
+  }
+
+  /* Un-handled conditions */
+
+  query_cache_abort(& query_cache_tls);
+
+  if (warn_list.elements < variables.max_error_count)
+  {
+    /* We have to use warn_root, as mem_root is freed after each query */
+    if ((err= new (& warn_root) MYSQL_ERROR(this, cond->m_sqlcode,
+                                            cond->m_level, msg)))
+      warn_list.push_back(err, & warn_root);
+  }
+  warn_count[(uint) cond->m_level]++;
+  total_warn_count++;
+  DBUG_VOID_RETURN;
+}
+
+
 extern "C"
 void *thd_alloc(MYSQL_THD thd, unsigned int size)
 {
@@ -1540,9 +1720,8 @@ bool select_send::send_fields(List<Item>
 void select_send::abort()
 {
   DBUG_ENTER("select_send::abort");
-  if (is_result_set_started && thd->spcont &&
-      thd->spcont->find_handler(thd, thd->main_da.sql_errno(),
-                                MYSQL_ERROR::WARN_LEVEL_ERROR))
+
+  if (is_result_set_started && thd->spcont)
   {
     /*
       We're executing a stored procedure, have an open result
@@ -1554,7 +1733,7 @@ void select_send::abort()
       otherwise the client will hang due to the violation of the
       client/server protocol.
     */
-    thd->protocol->end_partial_result_set(thd);
+    thd->end_partial_result_set= TRUE;
   }
   DBUG_VOID_RETURN;
 }
diff -Nrup a/sql/sql_class.h b/sql/sql_class.h
--- a/sql/sql_class.h	2008-04-23 14:27:10 -06:00
+++ b/sql/sql_class.h	2008-04-29 17:34:14 -06:00
@@ -1124,6 +1124,66 @@ enum enum_thread_type
   SYSTEM_THREAD_BACKUP= 64
 };
 
+class SQL_condition
+{
+public:
+  SQL_condition();
+  ~SQL_condition()
+  {}
+
+  void set(uint code, const char *str,
+           MYSQL_ERROR::enum_warning_level level, myf MyFlags);
+
+  void set_utf8_message_text(const char* str);
+  void set_message_text(const String *str);
+  const char* get_message_text() const;
+
+  void set_sqlstate(const char* sqlstate);
+  const char* get_sqlstate() const
+  { return m_returned_sqlstate; }
+
+public:
+  String m_class_origin;
+  String m_subclass_origin;
+  String m_constraint_catalog;
+  String m_constraint_schema;
+  String m_constraint_name;
+  String m_catalog_name;
+  String m_schema_name;
+  String m_table_name;
+  String m_column_name;
+  String m_cursor_name;
+
+private:
+  String m_message_text;
+
+public:
+  int m_sqlcode;
+  String m_condition_identifier;
+  int condition_number;
+  String m_connection_name;
+  int m_message_length;
+  int m_message_octet_length;
+  String m_parameter_mode;
+  String m_parameter_name;
+  int m_parameter_ordinal_position;
+
+private:
+  char m_returned_sqlstate[6];
+
+public:
+  String m_routine_catalog;
+  String m_routine_name;
+  String m_routine_schema;
+  String m_server_name;
+  String m_specific_name;
+  String m_trigger_catalog;
+  String m_trigger_name;
+  String m_trigger_schema;
+
+  MYSQL_ERROR::enum_warning_level m_level;
+  myf m_flags;
+};
 
 /**
   This class represents the interface for internal error handlers.
@@ -1157,15 +1217,8 @@ public:
     before removing it from the exception stack with
     <code>THD::pop_internal_handler()</code>.
 
-    @param sql_errno the error number
-    @param level the error level
-    @param thd the calling thread
-    @return true if the error is handled
   */
-  virtual bool handle_error(uint sql_errno,
-                            const char *message,
-                            MYSQL_ERROR::enum_warning_level level,
-                            THD *thd) = 0;
+  virtual bool handle_condition(THD *thd, const SQL_condition *cond) = 0;
 };
 
 
@@ -1201,7 +1254,10 @@ public:
                      ulonglong last_insert_id_arg,
                      const char *message);
   void set_eof_status(THD *thd);
-  void set_error_status(THD *thd, uint sql_errno_arg, const char *message_arg);
+  void set_default_error_status(THD *thd, uint sql_errno_arg,
+                              const char *message_arg);
+  void set_error_status(THD *thd, uint sql_errno_arg, const char *message_arg,
+                        const char* sqlstate);
 
   void disable_status();
 
@@ -1220,6 +1276,9 @@ public:
   uint sql_errno() const
   { DBUG_ASSERT(m_status == DA_ERROR); return m_sql_errno; }
 
+  const char* get_sqlstate() const
+  { DBUG_ASSERT(m_status == DA_ERROR); return m_sqlstate; }
+
   uint server_status() const
   {
     DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
@@ -1249,6 +1308,8 @@ private:
   */
   uint m_sql_errno;
 
+  char m_sqlstate[6];
+
   /**
     Copied from thd->server_status when the diagnostics area is assigned.
     We need this member as some places in the code use the following pattern:
@@ -1867,6 +1928,8 @@ public:
   my_bool    tablespace_op;	/* This is TRUE in DISCARD/IMPORT TABLESPACE */
 
   sp_rcontext *spcont;		// SP runtime context
+  bool       end_partial_result_set;
+
   sp_cache   *sp_proc_cache;
   sp_cache   *sp_func_cache;
 
@@ -2343,17 +2406,25 @@ public:
 
   /**
     Handle an error condition.
-    @param sql_errno the error number
-    @param level the error level
     @return true if the error is handled
   */
-  virtual bool handle_error(uint sql_errno, const char *message,
-                            MYSQL_ERROR::enum_warning_level level);
+  virtual bool handle_condition(const SQL_condition *cond);
 
   /**
     Remove the error handler last pushed.
   */
   void pop_internal_handler();
+
+  void raise_error(uint code, const char *str, myf MyFlags);
+  void raise_error_printf(uint code, const char *format, myf MyFlags, ...);
+
+  void raise_warning(uint code, const char *msg);
+  void raise_warning_printf(uint code, const char *format, ...);
+
+  void raise_note(uint code, const char *msg);
+  void raise_note_printf(uint code, const char *format, ...);
+
+  void raise_condition(const SQL_condition *cond);
 
 private:
   /** The current internal error handler for this thread, or NULL. */
diff -Nrup a/sql/sql_error.cc b/sql/sql_error.cc
--- a/sql/sql_error.cc	2008-02-19 05:59:07 -07:00
+++ b/sql/sql_error.cc	2008-04-29 17:34:14 -06:00
@@ -137,11 +137,14 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQ
     level= MYSQL_ERROR::WARN_LEVEL_ERROR;
   }
 
-  if (thd->handle_error(code, msg, level))
+  SQL_condition cond;
+  cond.set(code, msg, level, MYF(0));
+
+  if (thd->handle_condition(& cond))
     DBUG_RETURN(NULL);
 
   if (thd->spcont &&
-      thd->spcont->handle_error(code, level, thd))
+      thd->spcont->handle_condition(thd, & cond))
   {
     DBUG_RETURN(NULL);
   }
diff -Nrup a/sql/sql_insert.cc b/sql/sql_insert.cc
--- a/sql/sql_insert.cc	2008-04-14 04:10:01 -06:00
+++ b/sql/sql_insert.cc	2008-04-29 17:34:14 -06:00
@@ -2268,8 +2268,8 @@ pthread_handler_t handle_delayed_insert(
   if (my_thread_init())
   {
     /* Can't use my_error since store_globals has not yet been called */
-    thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES,
-                                  ER(ER_OUT_OF_RESOURCES));
+    thd->main_da.set_default_error_status(thd, ER_OUT_OF_RESOURCES,
+                                          ER(ER_OUT_OF_RESOURCES));
     goto end;
   }
 #endif
@@ -2279,8 +2279,8 @@ pthread_handler_t handle_delayed_insert(
   if (init_thr_lock() || thd->store_globals())
   {
     /* Can't use my_error since store_globals has perhaps failed */
-    thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES,
-                                  ER(ER_OUT_OF_RESOURCES));
+    thd->main_da.set_default_error_status(thd, ER_OUT_OF_RESOURCES,
+                                          ER(ER_OUT_OF_RESOURCES));
     thd->fatal_error();
     goto err;
   }
diff -Nrup a/sql/sql_signal.cc b/sql/sql_signal.cc
--- a/sql/sql_signal.cc	2008-04-23 14:27:10 -06:00
+++ b/sql/sql_signal.cc	2008-04-29 17:34:14 -06:00
@@ -19,6 +19,8 @@
 #include "sp_rcontext.h"
 #include "sql_signal.h"
 
+#define SIGNAL_DEFAULT_SQLCODE 1
+
 const LEX_STRING Diag_condition_item_names[]=
 {
   { C_STRING_WITH_LEN("CLASS_ORIGIN") },
@@ -67,6 +69,97 @@ const LEX_STRING Diag_statement_item_nam
   { C_STRING_WITH_LEN("TRANSACTION_ACTIVE") }
 };
 
+SQL_condition::SQL_condition()
+ : m_class_origin(),
+   m_subclass_origin(),
+   m_constraint_catalog(),
+   m_constraint_schema(),
+   m_constraint_name(),
+   m_catalog_name(),
+   m_schema_name(),
+   m_table_name(),
+   m_column_name(),
+   m_cursor_name(),
+   m_message_text(),
+   m_sqlcode(0),
+   m_condition_identifier(),
+   condition_number(0),
+   m_connection_name(),
+   m_message_length(0),
+   m_message_octet_length(0),
+   m_parameter_mode(),
+   m_parameter_name(),
+   m_parameter_ordinal_position(0),
+   m_routine_catalog(),
+   m_routine_name(),
+   m_routine_schema(),
+   m_server_name(),
+   m_specific_name(),
+   m_trigger_catalog(),
+   m_trigger_name(),
+   m_trigger_schema(),
+   m_level(MYSQL_ERROR::WARN_LEVEL_ERROR),
+   m_flags(0)
+{
+  memset(m_returned_sqlstate, 0, sizeof(m_returned_sqlstate));
+
+  m_message_text.set_charset(& my_charset_utf8_general_ci);
+}
+
+void
+SQL_condition::set(uint code, const char *str,
+                   MYSQL_ERROR::enum_warning_level level, myf flags)
+{
+  const char* sqlstate;
+
+  if (code == 0)
+    code= ER_UNKNOWN_ERROR;
+  if (str == NULL)
+    str= ER(code);
+  m_sqlcode= code;
+
+  sqlstate= mysql_errno_to_sqlstate(m_sqlcode);
+  memcpy(m_returned_sqlstate, sqlstate, 5);
+  m_returned_sqlstate[5]= '\0';
+
+  set_utf8_message_text(str);
+  m_level= level;
+  m_flags= flags;
+}
+
+void
+SQL_condition::set_utf8_message_text(const char* str)
+{
+  uint32 len= strlen(str);
+  if (len > 128)
+    len= 128;
+
+  m_message_text.set(str, len, & my_charset_utf8_bin);
+  // FIXME: message_length
+  m_message_length= m_message_text.length();
+  m_message_octet_length= m_message_text.length();
+}
+
+void
+SQL_condition::set_message_text(const String *str)
+{
+  m_message_text.copy(*str);
+  // FIXME: message_length
+  m_message_length= m_message_text.length();
+  m_message_octet_length= m_message_text.length();
+}
+
+const char*
+SQL_condition::get_message_text() const
+{
+  return m_message_text.ptr();
+}
+
+void
+SQL_condition::set_sqlstate(const char* sqlstate)
+{
+  memcpy(m_returned_sqlstate, sqlstate, 5);
+}
 
 Set_signal_information::Set_signal_information()
 {
@@ -102,10 +195,167 @@ void Set_signal_information::clear()
   }
 }
 
+int Abstract_signal::eval_sqlcode_sqlstate(THD *thd, SQL_condition *cond)
+{
+  if (m_cond != NULL)
+  {
+    switch(m_cond->type)
+    {
+      case sp_cond_type::number:
+        cond->m_sqlcode= m_cond->mysqlerr;
+        cond->set_sqlstate(mysql_errno_to_sqlstate(cond->m_sqlcode));
+        break;
+      case sp_cond_type::state:
+        cond->m_sqlcode= SIGNAL_DEFAULT_SQLCODE;
+        cond->set_sqlstate(m_cond->sqlstate);
+        break;
+      default:
+        DBUG_ASSERT(FALSE);
+        break;
+    }
+  }
+
+  return 0;
+}
+
+int Abstract_signal::eval_defaults(THD *thd, SQL_condition *cond)
+{
+  const char* sqlstate= cond->get_sqlstate();
+
+  DBUG_ASSERT((sqlstate[0] != '0') || (sqlstate[1] != '0'));
+
+  if ((sqlstate[0] == '0') && (sqlstate[1] == '1'))
+  {
+    /* SQLSTATE class "01": warning */
+    cond->set_utf8_message_text("Unhandled user-defined warning");
+    cond->m_level= MYSQL_ERROR::WARN_LEVEL_WARN;
+  }
+  else if ((sqlstate[0] == '0') && (sqlstate[1] == '2'))
+  {
+    /* SQLSTATE class "02": not found */
+    cond->set_utf8_message_text("Unhandled user-defined not found");
+    cond->m_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+  }
+  else
+  {
+    cond->set_utf8_message_text("Unhandled user-defined exception");
+    cond->m_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+  }
+
+  return 0;
+}
+
+int Abstract_signal::eval_signal_informations(THD *thd, SQL_condition *cond)
+{
+  Item *set;
+  String str_value;
+  String *str;
+
+  set= m_set_signal_information.m_item[DIAG_CLASS_ORIGIN];
+  if (set != NULL)
+  {
+    str= set->val_str(& str_value);
+    cond->m_class_origin.copy(*str);
+  }
+
+  set= m_set_signal_information.m_item[DIAG_SUBCLASS_ORIGIN];
+  if (set != NULL)
+  {
+    str= set->val_str(& str_value);
+    cond->m_subclass_origin.copy(*str);
+  }
+
+  set= m_set_signal_information.m_item[DIAG_CONSTRAINT_CATALOG];
+  if (set != NULL)
+  {
+    str= set->val_str(& str_value);
+    cond->m_constraint_catalog.copy(*str);
+  }
+
+  set= m_set_signal_information.m_item[DIAG_CONSTRAINT_SCHEMA];
+  if (set != NULL)
+  {
+    str= set->val_str(& str_value);
+    cond->m_constraint_schema.copy(*str);
+  }
+
+  set= m_set_signal_information.m_item[DIAG_CONSTRAINT_NAME];
+  if (set != NULL)
+  {
+    str= set->val_str(& str_value);
+    cond->m_constraint_name.copy(*str);
+  }
+
+  set= m_set_signal_information.m_item[DIAG_CATALOG_NAME];
+  if (set != NULL)
+  {
+    str= set->val_str(& str_value);
+    cond->m_catalog_name.copy(*str);
+  }
+
+  set= m_set_signal_information.m_item[DIAG_SCHEMA_NAME];
+  if (set != NULL)
+  {
+    str= set->val_str(& str_value);
+    cond->m_schema_name.copy(*str);
+  }
+
+  set= m_set_signal_information.m_item[DIAG_TABLE_NAME];
+  if (set != NULL)
+  {
+    str= set->val_str(& str_value);
+    cond->m_table_name.copy(*str);
+  }
+
+  set= m_set_signal_information.m_item[DIAG_COLUMN_NAME];
+  if (set != NULL)
+  {
+    str= set->val_str(& str_value);
+    cond->m_column_name.copy(*str);
+  }
+
+  set= m_set_signal_information.m_item[DIAG_CURSOR_NAME];
+  if (set != NULL)
+  {
+    str= set->val_str(& str_value);
+    cond->m_cursor_name.copy(*str);
+  }
+
+  set= m_set_signal_information.m_item[DIAG_MESSAGE_TEXT];
+  if (set != NULL)
+  {
+    str= set->val_str(& str_value);
+    cond->set_message_text(str);
+  }
+
+  set= m_set_signal_information.m_item[DIAG_SQLCODE];
+  if (set != NULL)
+  {
+    cond->m_sqlcode= set->val_int();
+  }
+
+  return 0;
+}
+
 int SQLCOM_signal::execute(THD *thd)
 {
-  my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SIGNAL");
-  return 1;
+  int result= 1;
+  SQL_condition cond;
+
+  if (eval_sqlcode_sqlstate(thd, & cond))
+    return result;
+
+  if (eval_defaults(thd, & cond))
+    return result;
+
+  if (eval_signal_informations(thd, & cond))
+    return result;
+
+  thd->raise_condition(& cond);
+
+  if (cond.m_level == MYSQL_ERROR::WARN_LEVEL_WARN)
+    result= 0;
+  return result;
 }
 
 int SQLCOM_resignal::execute(THD *thd)
diff -Nrup a/sql/sql_signal.h b/sql/sql_signal.h
--- a/sql/sql_signal.h	2008-04-23 14:27:10 -06:00
+++ b/sql/sql_signal.h	2008-04-29 17:34:14 -06:00
@@ -30,6 +30,10 @@ protected:
   virtual ~Abstract_signal()
   {}
 
+  int eval_sqlcode_sqlstate(THD *thd, SQL_condition *cond);
+  int eval_defaults(THD *thd, SQL_condition *cond);
+  int eval_signal_informations(THD *thd, SQL_condition *cond);
+
   const sp_cond_type_t *m_cond;
   Set_signal_information m_set_signal_information;
 };
diff -Nrup a/sql/unireg.cc b/sql/unireg.cc
--- a/sql/unireg.cc	2008-04-14 04:10:04 -06:00
+++ b/sql/unireg.cc	2008-04-29 17:34:14 -06:00
@@ -56,10 +56,7 @@ static bool make_empty_rec(THD *thd, int
 
 struct Pack_header_error_handler: public Internal_error_handler
 {
-  virtual bool handle_error(uint sql_errno,
-                            const char *message,
-                            MYSQL_ERROR::enum_warning_level level,
-                            THD *thd);
+  virtual bool handle_condition(THD *thd, const SQL_condition *cond);
   bool is_handled;
   Pack_header_error_handler() :is_handled(FALSE) {}
 };
@@ -67,12 +64,9 @@ struct Pack_header_error_handler: public
 
 bool
 Pack_header_error_handler::
-handle_error(uint sql_errno,
-             const char * /* message */,
-             MYSQL_ERROR::enum_warning_level /* level */,
-             THD * /* thd */)
+handle_condition(THD *, const SQL_condition *cond)
 {
-  is_handled= (sql_errno == ER_TOO_MANY_FIELDS);
+  is_handled= (cond->m_sqlcode == ER_TOO_MANY_FIELDS);
   return is_handled;
 }
 
Thread
bk commit into 6.0 tree (malff:1.2637) BUG#11661 WL#2110marc.alff30 Apr