List:Commits« Previous MessageNext Message »
From:Marc Alff Date:August 27 2008 10:14pm
Subject:bzr commit into mysql-6.0-wl2110-review branch (marc.alff:2698) Bug#11661
WL#2110 WL#2265
View as plain text  
#At file:///home/malff/BZR-TREE/mysql-6.0-wl2110-review/

 2698 Marc Alff	2008-08-27
      WL#2110 (SIGNAL)
      WL#2265 (RESIGNAL)
      Bug#11661 (Raising Exceptions from within stored procedures:
                 Support for SIGNAL statement)
added:
  mysql-test/r/signal.result
  mysql-test/r/signal_code.result
  mysql-test/r/signal_demo1.result
  mysql-test/r/signal_demo2.result
  mysql-test/r/signal_demo3.result
  mysql-test/r/signal_sqlmode.result
  mysql-test/r/signal_utf32.result
  mysql-test/t/signal.test
  mysql-test/t/signal_code.test
  mysql-test/t/signal_demo1.test
  mysql-test/t/signal_demo2.test
  mysql-test/t/signal_demo3.test
  mysql-test/t/signal_sqlmode.test
  mysql-test/t/signal_utf32.test
  sql/sql_fixstring.cc
  sql/sql_fixstring.h
  sql/sql_signal.cc
  sql/sql_signal.h
modified:
  .bzrignore
  libmysqld/CMakeLists.txt
  libmysqld/Makefile.am
  libmysqld/lib_sql.cc
  mysql-test/r/backup_security.result
  mysql-test/r/maria3.result
  mysql-test/r/myisam.result
  mysql-test/r/partition_not_windows.result
  mysql-test/r/partition_symlink.result
  mysql-test/r/partition_windows.result
  mysql-test/r/symlink.result
  mysql-test/r/windows.result
  sql/CMakeLists.txt
  sql/Makefile.am
  sql/backup/logger.cc
  sql/derror.cc
  sql/event_scheduler.cc
  sql/ha_ndbcluster_binlog.cc
  sql/handler.cc
  sql/lex.h
  sql/log.cc
  sql/log_event.cc
  sql/mysql_priv.h
  sql/mysqld.cc
  sql/protocol.cc
  sql/protocol.h
  sql/set_var.cc
  sql/share/errmsg.txt
  sql/slave.cc
  sql/sp.cc
  sql/sp_head.cc
  sql/sp_pcontext.h
  sql/sp_rcontext.cc
  sql/sp_rcontext.h
  sql/sql_acl.cc
  sql/sql_base.cc
  sql/sql_class.cc
  sql/sql_class.h
  sql/sql_error.cc
  sql/sql_insert.cc
  sql/sql_lex.h
  sql/sql_parse.cc
  sql/sql_table.cc
  sql/sql_view.cc
  sql/sql_yacc.yy
  sql/table.cc
  sql/thr_malloc.cc
  sql/unireg.cc

per-file messages:
  .bzrignore
    Added new files for WL#2110
  libmysqld/CMakeLists.txt
    Added new files for WL#2110
  libmysqld/Makefile.am
    Added new files for WL#2110
  libmysqld/lib_sql.cc
    Added sqlstate in net_send_error
  mysql-test/r/backup_security.result
    Bug#39059
  mysql-test/r/maria3.result
    Bug#39059
  mysql-test/r/myisam.result
    Bug#39059
  mysql-test/r/partition_not_windows.result
    Bug#36768
  mysql-test/r/partition_symlink.result
    Bug#36768
  mysql-test/r/partition_windows.result
    Bug#36768
  mysql-test/r/signal.result
    Tests for WL#2110 (SIGNAL) and WL#2265 (RESIGNAL)
  mysql-test/r/signal_code.result
    Tests for WL#2110 (SIGNAL) and WL#2265 (RESIGNAL)
  mysql-test/r/signal_demo1.result
    Tests for WL#2110 (SIGNAL) and WL#2265 (RESIGNAL)
  mysql-test/r/signal_demo2.result
    Tests for WL#2110 (SIGNAL) and WL#2265 (RESIGNAL)
  mysql-test/r/signal_demo3.result
    Tests for WL#2110 (SIGNAL) and WL#2265 (RESIGNAL)
  mysql-test/r/signal_sqlmode.result
    Tests for WL#2110 (SIGNAL) and WL#2265 (RESIGNAL)
  mysql-test/r/signal_utf32.result
    Tests for WL#2110 (SIGNAL) and WL#2265 (RESIGNAL)
  mysql-test/r/symlink.result
    Bug#36768
  mysql-test/r/windows.result
    Bug#36768
  mysql-test/t/signal.test
    Tests for WL#2110 (SIGNAL) and WL#2265 (RESIGNAL)
  mysql-test/t/signal_code.test
    Tests for WL#2110 (SIGNAL) and WL#2265 (RESIGNAL)
  mysql-test/t/signal_demo1.test
    Tests for WL#2110 (SIGNAL) and WL#2265 (RESIGNAL)
  mysql-test/t/signal_demo2.test
    Tests for WL#2110 (SIGNAL) and WL#2265 (RESIGNAL)
  mysql-test/t/signal_demo3.test
    Tests for WL#2110 (SIGNAL) and WL#2265 (RESIGNAL)
  mysql-test/t/signal_sqlmode.test
    Tests for WL#2110 (SIGNAL) and WL#2265 (RESIGNAL)
  mysql-test/t/signal_utf32.test
    Tests for WL#2110 (SIGNAL) and WL#2265 (RESIGNAL)
  sql/CMakeLists.txt
    Added new files for WL#2110
  sql/Makefile.am
    Added new files for WL#2110
  sql/backup/logger.cc
    Bug#39059
  sql/derror.cc
    Record the charset used in errmsg.sys
  sql/event_scheduler.cc
    Adjusted the code after changes in m_stmt_area.warn_list.
  sql/ha_ndbcluster_binlog.cc
    Adjusted the code after changes in m_stmt_area.warn_list.
  sql/handler.cc
    Adjusted the code after changes in Internal_error_handler::handle_condition
  sql/lex.h
    Implemented parser changes for the SIGNAL and RESIGNAL statements.
  sql/log.cc
    Adjusted the code after changes in Internal_error_handler::handle_condition
  sql/log_event.cc
    Adjusted the code after changes in m_stmt_area.warn_list.
  sql/mysql_priv.h
    Record the charset used in errmsg.sys
  sql/mysqld.cc
    Core implementation of SIGNAL and RESIGNAL
  sql/protocol.cc
    Added sqlstate in net_send_error
  sql/protocol.h
    Added sqlstate in net_send_error
  sql/set_var.cc
    Adjusted the code after changes in m_stmt_area.warn_list.
  sql/share/errmsg.txt
    Core implementation of SIGNAL and RESIGNAL
  sql/slave.cc
    Adjusted the code after changes in m_stmt_area.warn_list.
  sql/sp.cc
    Adjusted the code after changes in Internal_error_handler::handle_condition
  sql/sp_head.cc
    Core implementation of SIGNAL and RESIGNAL
  sql/sp_pcontext.h
    Core implementation of SIGNAL and RESIGNAL
  sql/sp_rcontext.cc
    Core implementation of SIGNAL and RESIGNAL
  sql/sp_rcontext.h
    Core implementation of SIGNAL and RESIGNAL
  sql/sql_acl.cc
    Adjusted the code after changes in Internal_error_handler::handle_condition
  sql/sql_base.cc
    Adjusted the code after changes in Internal_error_handler::handle_condition
  sql/sql_class.cc
    Core implementation of SIGNAL and RESIGNAL
  sql/sql_class.h
    Core implementation of SIGNAL and RESIGNAL
  sql/sql_error.cc
    Core implementation of SIGNAL and RESIGNAL
  sql/sql_fixstring.cc
    Helper classes for strings.
  sql/sql_fixstring.h
    Helper classes for strings.
  sql/sql_insert.cc
    Adjusted code after changes in set_error_status
  sql/sql_lex.h
    Implemented parser changes for the SIGNAL and RESIGNAL statements.
  sql/sql_parse.cc
    Implemented parser changes for the SIGNAL and RESIGNAL statements.
  sql/sql_signal.cc
    Core implementation of SIGNAL and RESIGNAL
  sql/sql_signal.h
    Core implementation of SIGNAL and RESIGNAL
  sql/sql_table.cc
    Adjusted the code after changes in m_stmt_area.warn_list.
  sql/sql_view.cc
    Raise errors using THD::raise_ER_NO_SUCH_TABLE()
  sql/sql_yacc.yy
    Implemented parser changes for the SIGNAL and RESIGNAL statements.
  sql/table.cc
    Raise errors using THD::raise_ER_NO_SUCH_TABLE()
  sql/thr_malloc.cc
    Adjusted code after changes in set_error_status
  sql/unireg.cc
    Adjusted the code after changes in Internal_error_handler::handle_condition
=== modified file '.bzrignore'
--- a/.bzrignore	2008-08-26 10:20:41 +0000
+++ b/.bzrignore	2008-08-27 22:14:03 +0000
@@ -1891,3 +1891,5 @@ zlib/*.vcproj
 extra/libevent/event-config.h
 libmysqld/ddl_blocker.cc
 libmysqld/mdl.cc
+libmysqld/sql_fixstring.cc
+libmysqld/sql_signal.cc

=== modified file 'libmysqld/CMakeLists.txt'
--- a/libmysqld/CMakeLists.txt	2008-07-09 07:12:43 +0000
+++ b/libmysqld/CMakeLists.txt	2008-08-27 22:14:03 +0000
@@ -203,6 +203,7 @@ SET(LIBMYSQLD_SOURCES emb_qcache.cc libm
            ../sql/scheduler.cc ../sql/sql_audit.cc
            ../sql/ddl_blocker.cc ../sql/si_objects.cc
            ../sql/event_parse_data.cc ../sql/mdl.cc
+           ../sql/sql_signal.cc ../sql/sql_fixstring.cc
            ${GEN_SOURCES}
            ${LIB_SOURCES})
 

=== modified file 'libmysqld/Makefile.am'
--- a/libmysqld/Makefile.am	2008-07-09 07:12:43 +0000
+++ b/libmysqld/Makefile.am	2008-08-27 22:14:03 +0000
@@ -82,7 +82,7 @@ sqlsources = derror.cc field.cc field_co
 	sql_tablespace.cc \
 	rpl_injector.cc my_user.c partition_info.cc \
 	sql_servers.cc ddl_blocker.cc si_objects.cc sql_audit.cc \
-        event_parse_data.cc mdl.cc
+        event_parse_data.cc mdl.cc sql_signal.cc sql_fixstring.cc
 
 libmysqld_int_a_SOURCES= $(libmysqld_sources)
 nodist_libmysqld_int_a_SOURCES= $(libmysqlsources) $(sqlsources)

=== modified file 'libmysqld/lib_sql.cc'
--- a/libmysqld/lib_sql.cc	2008-06-20 11:40:01 +0000
+++ b/libmysqld/lib_sql.cc	2008-08-27 22:14:03 +0000
@@ -1069,14 +1069,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;
 }

=== modified file 'mysql-test/r/backup_security.result'
--- a/mysql-test/r/backup_security.result	2007-12-03 20:28:32 +0000
+++ b/mysql-test/r/backup_security.result	2008-08-27 22:14:03 +0000
@@ -28,14 +28,12 @@ ERROR 42000: Access denied; you need the
 SHOW ERRORS;
 Level	Code	Message
 Error	1227	Access denied; you need the SUPER privilege for this operation
-Error	1227	Access denied; you need the SUPER privilege for this operation
 no_rights: Attempting restore. Should fail with error 1227
 RESTORE FROM 'bup_no_rights.bak';
 ERROR 42000: Access denied; you need the SUPER privilege for this operation
 SHOW ERRORS;
 Level	Code	Message
 Error	1227	Access denied; you need the SUPER privilege for this operation
-Error	1227	Access denied; you need the SUPER privilege for this operation
 SELECT * FROM backup_test.t1;
 a
 01 Test #1 - super privilege

=== modified file 'mysql-test/r/maria3.result'
--- a/mysql-test/r/maria3.result	2008-07-04 08:28:36 +0000
+++ b/mysql-test/r/maria3.result	2008-08-27 22:14:03 +0000
@@ -468,7 +468,7 @@ drop table t1;
 create table t1 (n int not null, c char(1)) engine=maria transactional=1;
 alter table t1 engine=myisam;
 Warnings:
-Error	1478	Table storage engine 'MyISAM' does not support the create option 'TRANSACTIONAL=1'
+Warning	1478	Table storage engine 'MyISAM' does not support the create option 'TRANSACTIONAL=1'
 alter table t1 engine=maria;
 show create table t1;
 Table	Create Table
@@ -479,7 +479,7 @@ t1	CREATE TABLE `t1` (
 drop table t1;
 create table t1 (n int not null, c char(1)) engine=myisam transactional=1;
 Warnings:
-Error	1478	Table storage engine 'MyISAM' does not support the create option 'TRANSACTIONAL=1'
+Warning	1478	Table storage engine 'MyISAM' does not support the create option 'TRANSACTIONAL=1'
 alter table t1 engine=maria;
 show create table t1;
 Table	Create Table

=== modified file 'mysql-test/r/myisam.result'
--- a/mysql-test/r/myisam.result	2008-06-17 20:04:19 +0000
+++ b/mysql-test/r/myisam.result	2008-08-27 22:14:03 +0000
@@ -2223,7 +2223,7 @@ Key Start Len Index   Type
 DROP TABLE t1;
 create table t1 (n int not null, c char(1)) transactional=1;
 Warnings:
-Error	1478	Table storage engine 'MyISAM' does not support the create option 'TRANSACTIONAL=1'
+Warning	1478	Table storage engine 'MyISAM' does not support the create option 'TRANSACTIONAL=1'
 show create table t1;
 Table	Create Table
 t1	CREATE TABLE `t1` (

=== modified file 'mysql-test/r/partition_not_windows.result'
--- a/mysql-test/r/partition_not_windows.result	2008-03-27 20:34:49 +0000
+++ b/mysql-test/r/partition_not_windows.result	2008-08-27 22:14:03 +0000
@@ -24,8 +24,8 @@ data directory='/not/existing'
   index directory='/not/existing'
 );
 Warnings:
-Warning	0	DATA DIRECTORY option ignored
-Warning	0	INDEX DIRECTORY option ignored
+Warning	1105	DATA DIRECTORY option ignored
+Warning	1105	INDEX DIRECTORY option ignored
 show create table t2;
 Table	Create Table
 t2	CREATE TABLE `t2` (

=== modified file 'mysql-test/r/partition_symlink.result'
--- a/mysql-test/r/partition_symlink.result	2008-03-20 14:25:58 +0000
+++ b/mysql-test/r/partition_symlink.result	2008-08-27 22:14:03 +0000
@@ -101,8 +101,8 @@ data directory='/not/existing'
     index directory='/not/existing'
 );
 Warnings:
-Warning	0	DATA DIRECTORY option ignored
-Warning	0	INDEX DIRECTORY option ignored
+Warning	1105	DATA DIRECTORY option ignored
+Warning	1105	INDEX DIRECTORY option ignored
 show create table t2;
 Table	Create Table
 t2	CREATE TABLE `t2` (

=== modified file 'mysql-test/r/partition_windows.result'
--- a/mysql-test/r/partition_windows.result	2008-01-04 11:06:20 +0000
+++ b/mysql-test/r/partition_windows.result	2008-08-27 22:14:03 +0000
@@ -15,16 +15,16 @@ DATA DIRECTORY = 'E:/mysqltest/p2Data'
     INDEX DIRECTORY = 'F:/mysqltest/p2Index'
 );
 Warnings:
-Warning	0	DATA DIRECTORY option ignored
-Warning	0	INDEX DIRECTORY option ignored
-Warning	0	DATA DIRECTORY option ignored
-Warning	0	INDEX DIRECTORY option ignored
+Warning	1105	DATA DIRECTORY option ignored
+Warning	1105	INDEX DIRECTORY option ignored
+Warning	1105	DATA DIRECTORY option ignored
+Warning	1105	INDEX DIRECTORY option ignored
 INSERT INTO t1 VALUES (NULL, "first", 1);
 INSERT INTO t1 VALUES (NULL, "second", 2);
 INSERT INTO t1 VALUES (NULL, "third", 3);
 ALTER TABLE t1 ADD PARTITION (PARTITION p3 DATA DIRECTORY = 'G:/mysqltest/p3Data' INDEX DIRECTORY = 'H:/mysqltest/p3Index');
 Warnings:
-Warning	0	DATA DIRECTORY option ignored
-Warning	0	INDEX DIRECTORY option ignored
+Warning	1105	DATA DIRECTORY option ignored
+Warning	1105	INDEX DIRECTORY option ignored
 INSERT INTO t1 VALUES (NULL, "last", 4);
 DROP TABLE t1;

=== added file 'mysql-test/r/signal.result'
--- a/mysql-test/r/signal.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/signal.result	2008-08-27 22:14:03 +0000
@@ -0,0 +1,2130 @@
+drop table if exists signal_non_reserved;
+create table signal_non_reserved (
+class_origin int,
+subclass_origin int,
+constraint_catalog int,
+constraint_schema int,
+constraint_name int,
+catalog_name int,
+schema_name int,
+table_name int,
+column_name int,
+cursor_name int,
+message_text int,
+sqlcode int
+);
+drop table signal_non_reserved;
+drop table if exists diag_non_reserved;
+create table diag_non_reserved (
+diagnostics int,
+current int,
+stacked int,
+exception int
+);
+drop table diag_non_reserved;
+drop table if exists diag_cond_non_reserved;
+create table diag_cond_non_reserved (
+condition_identifier int,
+condition_number int,
+condition_name int,
+connection_name int,
+message_length int,
+message_octet_length int,
+parameter_mode int,
+parameter_name int,
+parameter_ordinal_position int,
+returned_sqlstate int,
+routine_catalog int,
+routine_name int,
+routine_schema int,
+server_name int,
+specific_name int,
+trigger_catalog int,
+trigger_name int,
+trigger_schema int
+);
+drop table diag_cond_non_reserved;
+drop table if exists diag_stmt_non_reserved;
+create table diag_stmt_non_reserved (
+number int,
+more int,
+command_function int,
+command_function_code int,
+dynamic_function int,
+dynamic_function_code int,
+row_count int,
+transactions_committed int,
+transactions_rolled_back int,
+transaction_active int
+);
+drop table diag_stmt_non_reserved;
+drop table if exists test_reserved;
+create table test_reserved (signal 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 'signal int)' at line 1
+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 (condition 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 'condition int)' at line 1
+drop procedure if exists test_invalid;
+drop procedure if exists test_signal_syntax;
+drop function if exists test_signal_func;
+create procedure test_invalid()
+begin
+SIGNAL;
+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 ';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL foo;
+end $$
+ERROR 42000: Undefined CONDITION: foo
+create procedure test_invalid()
+begin
+DECLARE foo CONDITION FOR 1234;
+SIGNAL foo;
+end $$
+ERROR HY000: SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE
+create procedure test_signal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo;
+end $$
+drop procedure test_signal_syntax $$
+create procedure test_signal_syntax()
+begin
+SIGNAL SQLSTATE '23000';
+end $$
+drop procedure test_signal_syntax $$
+create procedure test_signal_syntax()
+begin
+SIGNAL SQLSTATE VALUE '23000';
+end $$
+drop procedure test_signal_syntax $$
+create procedure test_signal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET CLASS_ORIGIN = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+create procedure test_signal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET SUBCLASS_ORIGIN = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+create procedure test_signal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET CONSTRAINT_CATALOG = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+create procedure test_signal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET CONSTRAINT_SCHEMA = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+create procedure test_signal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET CONSTRAINT_NAME = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+create procedure test_signal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET CATALOG_NAME = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+create procedure test_signal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET SCHEMA_NAME = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+create procedure test_signal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET TABLE_NAME = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+create procedure test_signal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET COLUMN_NAME = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+create procedure test_signal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET CURSOR_NAME = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+create procedure test_signal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET MESSAGE_TEXT = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+create procedure test_signal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET MYSQL_ERRNO = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+create procedure test_invalid()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET CLASS_ORIGIN = 'foo', CLASS_ORIGIN = 'bar';
+end $$
+ERROR 42000: Duplicate condition information item 'CLASS_ORIGIN'
+create procedure test_invalid()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET MESSAGE_TEXT = 'foo', MESSAGE_TEXT = 'bar';
+end $$
+ERROR 42000: Duplicate condition information item 'MESSAGE_TEXT'
+create procedure test_invalid()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET MYSQL_ERRNO = 'foo', MYSQL_ERRNO = 'bar';
+end $$
+ERROR 42000: Duplicate condition information item 'MYSQL_ERRNO'
+create procedure test_signal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo SET
+CLASS_ORIGIN = 'foo',
+SUBCLASS_ORIGIN = 'foo',
+CONSTRAINT_CATALOG = 'foo',
+CONSTRAINT_SCHEMA = 'foo',
+CONSTRAINT_NAME = 'foo',
+CATALOG_NAME = 'foo',
+SCHEMA_NAME = 'foo',
+TABLE_NAME = 'foo',
+COLUMN_NAME = 'foo',
+CURSOR_NAME = 'foo',
+MESSAGE_TEXT = 'foo',
+MYSQL_ERRNO = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+SIGNAL SQLSTATE '00000' $$
+ERROR 42000: Bad SQLSTATE: '00000'
+SIGNAL SQLSTATE '00001' $$
+ERROR 42000: Bad SQLSTATE: '00001'
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '00000';
+end $$
+ERROR 42000: Bad SQLSTATE: '00000'
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '00001';
+end $$
+ERROR 42000: Bad SQLSTATE: '00001'
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET bla_bla = 'foo';
+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 'bla_bla = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET CONDITION_IDENTIFIER = 'foo';
+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 'CONDITION_IDENTIFIER = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET CONDITION_NUMBER = 'foo';
+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 'CONDITION_NUMBER = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET CONNECTION_NAME = 'foo';
+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 'CONNECTION_NAME = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET MESSAGE_LENGTH = 'foo';
+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 'MESSAGE_LENGTH = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET MESSAGE_OCTET_LENGTH = 'foo';
+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 'MESSAGE_OCTET_LENGTH = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET PARAMETER_MODE = 'foo';
+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 'PARAMETER_MODE = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET PARAMETER_NAME = 'foo';
+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 'PARAMETER_NAME = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET PARAMETER_ORDINAL_POSITION = 'foo';
+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 'PARAMETER_ORDINAL_POSITION = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET RETURNED_SQLSTATE = 'foo';
+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 'RETURNED_SQLSTATE = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET ROUTINE_CATALOG = 'foo';
+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 'ROUTINE_CATALOG = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET ROUTINE_NAME = 'foo';
+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 'ROUTINE_NAME = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET ROUTINE_SCHEMA = 'foo';
+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 'ROUTINE_SCHEMA = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET SERVER_NAME = 'foo';
+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 'SERVER_NAME = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET SPECIFIC_NAME = 'foo';
+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 'SPECIFIC_NAME = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET TRIGGER_CATALOG = 'foo';
+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_CATALOG = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET TRIGGER_NAME = 'foo';
+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_NAME = 'foo';
+end' at line 3
+create procedure test_invalid()
+begin
+SIGNAL SQLSTATE '12345' SET TRIGGER_SCHEMA = 'foo';
+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
+drop procedure if exists test_invalid;
+drop procedure if exists test_resignal_syntax;
+create procedure test_invalid()
+begin
+RESIGNAL foo;
+end $$
+ERROR 42000: Undefined CONDITION: foo
+create procedure test_resignal_syntax()
+begin
+RESIGNAL;
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_invalid()
+begin
+DECLARE foo CONDITION FOR 1234;
+RESIGNAL foo;
+end $$
+ERROR HY000: SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE
+create procedure test_resignal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo;
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+RESIGNAL SQLSTATE '23000';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+RESIGNAL SQLSTATE VALUE '23000';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+RESIGNAL SET CLASS_ORIGIN = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET CLASS_ORIGIN = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+RESIGNAL SET SUBCLASS_ORIGIN = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET SUBCLASS_ORIGIN = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+RESIGNAL SET CONSTRAINT_CATALOG = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET CONSTRAINT_CATALOG = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+RESIGNAL SET CONSTRAINT_SCHEMA = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET CONSTRAINT_SCHEMA = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+RESIGNAL SET CONSTRAINT_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET CONSTRAINT_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+RESIGNAL SET CATALOG_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET CATALOG_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+RESIGNAL SET SCHEMA_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET SCHEMA_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+RESIGNAL SET TABLE_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET TABLE_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+RESIGNAL SET COLUMN_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET COLUMN_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+RESIGNAL SET CURSOR_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET CURSOR_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+RESIGNAL SET MESSAGE_TEXT = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET MESSAGE_TEXT = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+RESIGNAL SET MYSQL_ERRNO = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_resignal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET MYSQL_ERRNO = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_invalid()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET CLASS_ORIGIN = 'foo', CLASS_ORIGIN = 'bar';
+end $$
+ERROR 42000: Duplicate condition information item 'CLASS_ORIGIN'
+create procedure test_invalid()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET MESSAGE_TEXT = 'foo', MESSAGE_TEXT = 'bar';
+end $$
+ERROR 42000: Duplicate condition information item 'MESSAGE_TEXT'
+create procedure test_invalid()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET MYSQL_ERRNO = 'foo', MYSQL_ERRNO = 'bar';
+end $$
+ERROR 42000: Duplicate condition information item 'MYSQL_ERRNO'
+create procedure test_resignal_syntax()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+RESIGNAL foo SET
+CLASS_ORIGIN = 'foo',
+SUBCLASS_ORIGIN = 'foo',
+CONSTRAINT_CATALOG = 'foo',
+CONSTRAINT_SCHEMA = 'foo',
+CONSTRAINT_NAME = 'foo',
+CATALOG_NAME = 'foo',
+SCHEMA_NAME = 'foo',
+TABLE_NAME = 'foo',
+COLUMN_NAME = 'foo',
+CURSOR_NAME = 'foo',
+MESSAGE_TEXT = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+create procedure test_invalid()
+begin
+RESIGNAL SQLSTATE '00000';
+end $$
+ERROR 42000: Bad SQLSTATE: '00000'
+prepare stmt from 'SIGNAL SQLSTATE \'23000\'';
+ERROR HY000: This command is not supported in the prepared statement protocol yet
+prepare stmt from 'RESIGNAL SQLSTATE \'23000\'';
+ERROR HY000: This command is not supported in the prepared statement protocol yet
+drop procedure if exists test_signal;
+drop procedure if exists test_resignal;
+drop table if exists t_warn;
+drop table if exists t_cursor;
+create table t_warn(a integer(2));
+create table t_cursor(a integer);
+SIGNAL foo;
+ERROR 42000: Undefined CONDITION: foo
+SIGNAL SQLSTATE '01000';
+Warnings:
+Warning	1727	Unhandled user-defined warning
+SIGNAL SQLSTATE '02000';
+ERROR 02000: Unhandled user-defined not found
+SIGNAL SQLSTATE '23000';
+ERROR 23000: Unhandled user-defined exception
+SIGNAL SQLSTATE VALUE '23000';
+ERROR 23000: Unhandled user-defined exception
+SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 65536;
+ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of '65536'
+SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 99999;
+ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of '99999'
+SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 4294967295;
+ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of '4294967295'
+SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 0;
+ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of '0'
+SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = -1;
+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 '-1' at line 1
+SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 65535;
+ERROR HY000: Unhandled user-defined exception
+RESIGNAL;
+ERROR 0K000: RESIGNAL when handler not active
+RESIGNAL foo;
+ERROR 42000: Undefined CONDITION: foo
+RESIGNAL SQLSTATE '12345';
+ERROR 0K000: RESIGNAL when handler not active
+RESIGNAL SQLSTATE VALUE '12345';
+ERROR 0K000: RESIGNAL when handler not active
+create procedure test_signal()
+begin
+# max range
+DECLARE foo CONDITION FOR SQLSTATE 'AABBB';
+SIGNAL foo SET MYSQL_ERRNO = 65535;
+end $$
+call test_signal() $$
+ERROR AABBB: Unhandled user-defined exception
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# max range
+DECLARE foo CONDITION FOR SQLSTATE 'AABBB';
+SIGNAL foo SET MYSQL_ERRNO = 65536;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of '65536'
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# Error
+DECLARE foo CONDITION FOR SQLSTATE '99999';
+SIGNAL foo SET MYSQL_ERRNO = 9999;
+end $$
+call test_signal() $$
+ERROR 99999: Unhandled user-defined exception
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+# warning
+DECLARE too_few_records CONDITION FOR SQLSTATE '01000';
+SIGNAL too_few_records SET MYSQL_ERRNO = 1261;
+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 SQLSTATE '02000';
+SIGNAL sp_fetch_no_data SET MYSQL_ERRNO = 1329;
+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 SQLSTATE '24000';
+SIGNAL sp_cursor_already_open SET MYSQL_ERRNO = 1325;
+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 SQLSTATE '40001';
+SIGNAL lock_deadlock SET MYSQL_ERRNO = 1213;
+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	1727	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	1727	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 $$
+create procedure test_signal()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '99999';
+begin
+DECLARE foo CONDITION FOR 8888;
+end;
+SIGNAL foo SET MYSQL_ERRNO=9999; /* outer */
+end $$
+call test_signal() $$
+ERROR 99999: Unhandled user-defined exception
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE foo CONDITION FOR 9999;
+begin
+DECLARE foo CONDITION FOR SQLSTATE '88888';
+SIGNAL foo SET MYSQL_ERRNO=8888; /* inner */
+end;
+end $$
+call test_signal() $$
+ERROR 88888: Unhandled user-defined exception
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '99999';
+SIGNAL foo SET MYSQL_ERRNO = 1111;
+end $$
+call test_signal() $$
+ERROR 99999: Unhandled user-defined exception
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE warn CONDITION FOR SQLSTATE "01000";
+SIGNAL warn SET MYSQL_ERRNO = 1111;
+end $$
+call test_signal() $$
+Warnings:
+Warning	1111	Unhandled user-defined warning
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE not_found CONDITION FOR SQLSTATE "02000";
+SIGNAL not_found SET MYSQL_ERRNO = 1111;
+end $$
+call test_signal() $$
+ERROR 02000: Unhandled user-defined not found
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE "55000";
+SIGNAL error SET MYSQL_ERRNO = 1111;
+end $$
+call test_signal() $$
+ERROR 55000: Unhandled user-defined exception
+drop procedure test_signal $$
+SIGNAL SQLSTATE '77777' SET MESSAGE_TEXT='' $$
+ERROR 77777: 
+create procedure test_signal()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '77777';
+SIGNAL foo SET
+MESSAGE_TEXT = "",
+MYSQL_ERRNO=5678;
+end $$
+call test_signal() $$
+ERROR 77777: 
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '99999';
+SIGNAL foo SET
+MESSAGE_TEXT = "Something bad happened",
+MYSQL_ERRNO=9999;
+end $$
+call test_signal() $$
+ERROR 99999: Something bad happened
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE warn CONDITION FOR SQLSTATE "01000";
+SIGNAL warn SET MESSAGE_TEXT = "Something bad happened";
+end $$
+call test_signal() $$
+Warnings:
+Warning	1727	Something bad happened
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE not_found CONDITION FOR SQLSTATE "02000";
+SIGNAL not_found SET MESSAGE_TEXT = "Something bad happened";
+end $$
+call test_signal() $$
+ERROR 02000: Something bad happened
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE "55000";
+SIGNAL error SET MESSAGE_TEXT = "Something bad happened";
+end $$
+call test_signal() $$
+ERROR 55000: Something bad happened
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE something CONDITION FOR SQLSTATE "01000";
+SIGNAL something SET MESSAGE_TEXT = _utf8 "This is a UTF8 text";
+end $$
+call test_signal() $$
+Warnings:
+Warning	1727	This is a UTF8 text
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE something CONDITION FOR SQLSTATE "01000";
+SIGNAL something SET MESSAGE_TEXT = "";
+end $$
+call test_signal() $$
+Warnings:
+Warning	1727	
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE '99999';
+SIGNAL error SET
+MYSQL_ERRNO = NULL;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of 'NULL'
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE '99999';
+SIGNAL error SET
+CLASS_ORIGIN = NULL;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'CLASS_ORIGIN' can't be set to the value of 'NULL'
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE '99999';
+SIGNAL error SET
+SUBCLASS_ORIGIN = NULL;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'SUBCLASS_ORIGIN' can't be set to the value of 'NULL'
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE '99999';
+SIGNAL error SET
+CONSTRAINT_CATALOG = NULL;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'CONSTRAINT_CATALOG' can't be set to the value of 'NULL'
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE '99999';
+SIGNAL error SET
+CONSTRAINT_SCHEMA = NULL;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'CONSTRAINT_SCHEMA' can't be set to the value of 'NULL'
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE '99999';
+SIGNAL error SET
+CONSTRAINT_NAME = NULL;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'CONSTRAINT_NAME' can't be set to the value of 'NULL'
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE '99999';
+SIGNAL error SET
+CATALOG_NAME = NULL;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'CATALOG_NAME' can't be set to the value of 'NULL'
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE '99999';
+SIGNAL error SET
+SCHEMA_NAME = NULL;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'SCHEMA_NAME' can't be set to the value of 'NULL'
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE '99999';
+SIGNAL error SET
+TABLE_NAME = NULL;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'TABLE_NAME' can't be set to the value of 'NULL'
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE '99999';
+SIGNAL error SET
+COLUMN_NAME = NULL;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'COLUMN_NAME' can't be set to the value of 'NULL'
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE '99999';
+SIGNAL error SET
+CURSOR_NAME = NULL;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'CURSOR_NAME' can't be set to the value of 'NULL'
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE '99999';
+SIGNAL error SET
+MESSAGE_TEXT = NULL;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'MESSAGE_TEXT' can't be set to the value of 'NULL'
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE something CONDITION FOR SQLSTATE '99999';
+DECLARE message_text VARCHAR(64) DEFAULT "Local string variable";
+DECLARE sqlcode INTEGER DEFAULT 1234;
+SIGNAL something SET
+MESSAGE_TEXT = message_text,
+MYSQL_ERRNO = sqlcode;
+end $$
+call test_signal() $$
+ERROR 99999: Local string variable
+drop procedure test_signal $$
+create procedure test_signal(message_text VARCHAR(64), sqlcode INTEGER)
+begin
+DECLARE something CONDITION FOR SQLSTATE "12345";
+SIGNAL something SET
+MESSAGE_TEXT = message_text,
+MYSQL_ERRNO = sqlcode;
+end $$
+call test_signal("Parameter string", NULL) $$
+ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of 'NULL'
+call test_signal(NULL, 1234) $$
+ERROR 42000: Variable 'MESSAGE_TEXT' can't be set to the value of 'NULL'
+call test_signal("Parameter string", 5678) $$
+ERROR 12345: Parameter string
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE something CONDITION FOR SQLSTATE "AABBB";
+SIGNAL something SET
+MESSAGE_TEXT = @message_text,
+MYSQL_ERRNO = @sqlcode;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'MESSAGE_TEXT' can't be set to the value of 'NULL'
+set @sqlcode= 12 $$
+call test_signal() $$
+ERROR 42000: Variable 'MESSAGE_TEXT' can't be set to the value of 'NULL'
+set @message_text= "User variable" $$
+call test_signal() $$
+ERROR AABBB: User variable
+drop procedure test_signal $$
+create procedure test_invalid()
+begin
+DECLARE something CONDITION FOR SQLSTATE "AABBB";
+SIGNAL something SET
+MESSAGE_TEXT = @message_text := 'illegal',
+MYSQL_ERRNO = @sqlcode := 1234;
+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 '
+MYSQL_ERRNO = @sqlcode := 1234;
+end' at line 5
+create procedure test_signal()
+begin
+DECLARE aaa VARCHAR(64);
+DECLARE bbb VARCHAR(64);
+DECLARE ccc VARCHAR(64);
+DECLARE ddd VARCHAR(64);
+DECLARE eee VARCHAR(64);
+DECLARE fff VARCHAR(64);
+DECLARE ggg VARCHAR(64);
+DECLARE hhh VARCHAR(64);
+DECLARE iii VARCHAR(64);
+DECLARE jjj VARCHAR(64);
+DECLARE kkk VARCHAR(64);
+DECLARE warn CONDITION FOR SQLSTATE "01234";
+set aaa= repeat("A", 64);
+set bbb= repeat("B", 64);
+set ccc= repeat("C", 64);
+set ddd= repeat("D", 64);
+set eee= repeat("E", 64);
+set fff= repeat("F", 64);
+set ggg= repeat("G", 64);
+set hhh= repeat("H", 64);
+set iii= repeat("I", 64);
+set jjj= repeat("J", 64);
+set kkk= repeat("K", 64);
+SIGNAL warn SET
+CLASS_ORIGIN = aaa,
+SUBCLASS_ORIGIN = bbb,
+CONSTRAINT_CATALOG = ccc,
+CONSTRAINT_SCHEMA = ddd,
+CONSTRAINT_NAME = eee,
+CATALOG_NAME = fff,
+SCHEMA_NAME = ggg,
+TABLE_NAME = hhh,
+COLUMN_NAME = iii,
+CURSOR_NAME = jjj,
+MESSAGE_TEXT = kkk,
+MYSQL_ERRNO = 65535;
+end $$
+call test_signal() $$
+Warnings:
+Warning	65535	KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE warn CONDITION FOR SQLSTATE "01234";
+SIGNAL warn SET
+MYSQL_ERRNO = 999999999999999999999999999999999999999999999999999;
+end $$
+call test_signal() $$
+ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of '999999999999999999999999999999999999999999999999999'
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE aaax VARCHAR(65);
+DECLARE bbbx VARCHAR(65);
+DECLARE cccx VARCHAR(65);
+DECLARE dddx VARCHAR(65);
+DECLARE eeex VARCHAR(65);
+DECLARE fffx VARCHAR(65);
+DECLARE gggx VARCHAR(65);
+DECLARE hhhx VARCHAR(65);
+DECLARE iiix VARCHAR(65);
+DECLARE jjjx VARCHAR(65);
+DECLARE kkkx VARCHAR(65);
+DECLARE lllx VARCHAR(129);
+DECLARE warn CONDITION FOR SQLSTATE "01234";
+set aaax= concat(repeat("A", 64), "X");
+set bbbx= concat(repeat("B", 64), "X");
+set cccx= concat(repeat("C", 64), "X");
+set dddx= concat(repeat("D", 64), "X");
+set eeex= concat(repeat("E", 64), "X");
+set fffx= concat(repeat("F", 64), "X");
+set gggx= concat(repeat("G", 64), "X");
+set hhhx= concat(repeat("H", 64), "X");
+set iiix= concat(repeat("I", 64), "X");
+set jjjx= concat(repeat("J", 64), "X");
+set kkkx= concat(repeat("K", 64), "X");
+set lllx= concat(repeat("1", 100),
+repeat("2", 20),
+repeat("8", 8),
+"X");
+SIGNAL warn SET
+CLASS_ORIGIN = aaax,
+SUBCLASS_ORIGIN = bbbx,
+CONSTRAINT_CATALOG = cccx,
+CONSTRAINT_SCHEMA = dddx,
+CONSTRAINT_NAME = eeex,
+CATALOG_NAME = fffx,
+SCHEMA_NAME = gggx,
+TABLE_NAME = hhhx,
+COLUMN_NAME = iiix,
+CURSOR_NAME = jjjx,
+MESSAGE_TEXT = lllx,
+MYSQL_ERRNO = 10000;
+end $$
+call test_signal() $$
+Warnings:
+Warning	1732	Data truncated for condition item 'CLASS_ORIGIN'
+Warning	1732	Data truncated for condition item 'SUBCLASS_ORIGIN'
+Warning	1732	Data truncated for condition item 'CONSTRAINT_CATALOG'
+Warning	1732	Data truncated for condition item 'CONSTRAINT_SCHEMA'
+Warning	1732	Data truncated for condition item 'CONSTRAINT_NAME'
+Warning	1732	Data truncated for condition item 'CATALOG_NAME'
+Warning	1732	Data truncated for condition item 'SCHEMA_NAME'
+Warning	1732	Data truncated for condition item 'TABLE_NAME'
+Warning	1732	Data truncated for condition item 'COLUMN_NAME'
+Warning	1732	Data truncated for condition item 'CURSOR_NAME'
+Warning	1732	Data truncated for condition item 'MESSAGE_TEXT'
+Warning	10000	11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222288888888
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE warn CONDITION FOR SQLSTATE "01234";
+DECLARE CONTINUE HANDLER for SQLSTATE "01234"
+  begin
+select "Caught by SQLSTATE";
+end;
+SIGNAL warn SET
+MESSAGE_TEXT = "Raising a warning",
+MYSQL_ERRNO = 1012;
+end $$
+call test_signal() $$
+Caught by SQLSTATE
+Caught by SQLSTATE
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE warn CONDITION FOR SQLSTATE "01234";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "Caught by number";
+end;
+SIGNAL warn SET
+MESSAGE_TEXT = "Raising a warning",
+MYSQL_ERRNO = 1012;
+end $$
+call test_signal() $$
+Caught by number
+Caught by number
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE warn CONDITION FOR SQLSTATE "01234";
+DECLARE CONTINUE HANDLER for SQLWARNING
+begin
+select "Caught by SQLWARNING";
+end;
+SIGNAL warn SET
+MESSAGE_TEXT = "Raising a warning",
+MYSQL_ERRNO = 1012;
+end $$
+call test_signal() $$
+Caught by SQLWARNING
+Caught by SQLWARNING
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE not_found CONDITION FOR SQLSTATE "02ABC";
+DECLARE CONTINUE HANDLER for SQLSTATE "02ABC"
+  begin
+select "Caught by SQLSTATE";
+end;
+SIGNAL not_found SET
+MESSAGE_TEXT = "Raising a not found",
+MYSQL_ERRNO = 1012;
+end $$
+call test_signal() $$
+Caught by SQLSTATE
+Caught by SQLSTATE
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE not_found CONDITION FOR SQLSTATE "02ABC";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "Caught by number";
+end;
+SIGNAL not_found SET
+MESSAGE_TEXT = "Raising a not found",
+MYSQL_ERRNO = 1012;
+end $$
+call test_signal() $$
+Caught by number
+Caught by number
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE not_found CONDITION FOR SQLSTATE "02ABC";
+DECLARE CONTINUE HANDLER for NOT FOUND
+begin
+select "Caught by NOT FOUND";
+end;
+SIGNAL not_found SET
+MESSAGE_TEXT = "Raising a not found",
+MYSQL_ERRNO = 1012;
+end $$
+call test_signal() $$
+Caught by NOT FOUND
+Caught by NOT FOUND
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE "55555";
+DECLARE CONTINUE HANDLER for SQLSTATE "55555"
+  begin
+select "Caught by SQLSTATE";
+end;
+SIGNAL error SET
+MESSAGE_TEXT = "Raising an error",
+MYSQL_ERRNO = 1012;
+end $$
+call test_signal() $$
+Caught by SQLSTATE
+Caught by SQLSTATE
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE "55555";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "Caught by number";
+end;
+SIGNAL error SET
+MESSAGE_TEXT = "Raising an error",
+MYSQL_ERRNO = 1012;
+end $$
+call test_signal() $$
+Caught by number
+Caught by number
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE error CONDITION FOR SQLSTATE "55555";
+DECLARE CONTINUE HANDLER for SQLEXCEPTION
+begin
+select "Caught by SQLEXCEPTION";
+end;
+SIGNAL error SET
+MESSAGE_TEXT = "Raising an error",
+MYSQL_ERRNO = 1012;
+end $$
+call test_signal() $$
+Caught by SQLEXCEPTION
+Caught by SQLEXCEPTION
+drop procedure test_signal $$
+create function test_signal_func() returns integer
+begin
+DECLARE warn CONDITION FOR SQLSTATE "01XXX";
+SIGNAL warn SET
+MESSAGE_TEXT = "This function SIGNAL a warning",
+MYSQL_ERRNO = 1012;
+return 5;
+end $$
+select test_signal_func() $$
+test_signal_func()
+5
+Warnings:
+Warning	1012	This function SIGNAL a warning
+drop function test_signal_func $$
+create function test_signal_func() returns integer
+begin
+DECLARE not_found CONDITION FOR SQLSTATE "02XXX";
+SIGNAL not_found SET
+MESSAGE_TEXT = "This function SIGNAL not found",
+MYSQL_ERRNO = 1012;
+return 5;
+end $$
+select test_signal_func() $$
+ERROR 02XXX: This function SIGNAL not found
+drop function test_signal_func $$
+create function test_signal_func() returns integer
+begin
+DECLARE error CONDITION FOR SQLSTATE "50000";
+SIGNAL error SET
+MESSAGE_TEXT = "This function SIGNAL an error",
+MYSQL_ERRNO = 1012;
+return 5;
+end $$
+select test_signal_func() $$
+ERROR 50000: This function SIGNAL an error
+drop function test_signal_func $$
+drop table if exists t1 $$
+create table t1 (a integer) $$
+create trigger t1_ai after insert on t1 for each row
+begin
+DECLARE msg VARCHAR(128);
+DECLARE warn CONDITION FOR SQLSTATE "01XXX";
+set msg= concat("This trigger SIGNAL a warning, a=", NEW.a);
+SIGNAL warn SET
+MESSAGE_TEXT = msg,
+MYSQL_ERRNO = 1012;
+end $$
+insert into t1 values (1), (2) $$
+Warnings:
+Warning	1012	This trigger SIGNAL a warning, a=2
+drop trigger t1_ai $$
+create trigger t1_ai after insert on t1 for each row
+begin
+DECLARE msg VARCHAR(128);
+DECLARE not_found CONDITION FOR SQLSTATE "02XXX";
+set msg= concat("This trigger SIGNAL a not found, a=", NEW.a);
+SIGNAL not_found SET
+MESSAGE_TEXT = msg,
+MYSQL_ERRNO = 1012;
+end $$
+insert into t1 values (3), (4) $$
+ERROR 02XXX: This trigger SIGNAL a not found, a=3
+drop trigger t1_ai $$
+create trigger t1_ai after insert on t1 for each row
+begin
+DECLARE msg VARCHAR(128);
+DECLARE error CONDITION FOR SQLSTATE "03XXX";
+set msg= concat("This trigger SIGNAL an error, a=", NEW.a);
+SIGNAL error SET
+MESSAGE_TEXT = msg,
+MYSQL_ERRNO = 1012;
+end $$
+insert into t1 values (5), (6) $$
+ERROR 03XXX: This trigger SIGNAL an error, a=5
+drop table t1 $$
+create table t1 (errno integer, msg varchar(128)) $$
+create trigger t1_ai after insert on t1 for each row
+begin
+DECLARE warn CONDITION FOR SQLSTATE "01XXX";
+SIGNAL warn SET
+MESSAGE_TEXT = NEW.msg,
+MYSQL_ERRNO = NEW.errno;
+end $$
+insert into t1 set errno=1012, msg='Warning message 1 in trigger' $$
+Warnings:
+Warning	1012	Warning message 1 in trigger
+insert into t1 set errno=1013, msg='Warning message 2 in trigger' $$
+Warnings:
+Warning	1013	Warning message 2 in trigger
+drop table t1 $$
+drop table if exists t1 $$
+drop procedure if exists p1 $$
+drop function if exists f1 $$
+create table t1 (s1 int) $$
+insert into t1 values (1) $$
+create procedure p1()
+begin
+declare a int;
+declare c cursor for select f1() from t1;
+declare continue handler for sqlstate '03000'
+    select "caught 03000";
+declare continue handler for 1326
+select "caught cursor is not open";
+select "Before open";
+open c;
+select "Before fetch";
+fetch c into a;
+select "Before close";
+close c;
+end $$
+create function f1() returns int
+begin
+signal sqlstate '03000';
+return 5;
+end $$
+drop table t1 $$
+drop procedure p1 $$
+drop function f1 $$
+create procedure test_resignal()
+begin
+DECLARE warn CONDITION FOR SQLSTATE "01234";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "before RESIGNAL";
+RESIGNAL;
+select "after RESIGNAL";
+end;
+SIGNAL warn SET
+MESSAGE_TEXT = "Raising a warning",
+MYSQL_ERRNO = 1012;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+after RESIGNAL
+after RESIGNAL
+Warnings:
+Warning	1012	Raising a warning
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE not_found CONDITION FOR SQLSTATE "02222";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "before RESIGNAL";
+RESIGNAL;
+select "after RESIGNAL";
+end;
+SIGNAL not_found SET
+MESSAGE_TEXT = "Raising a not found",
+MYSQL_ERRNO = 1012;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 02222: Raising a not found
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE error CONDITION FOR SQLSTATE "55555";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "before RESIGNAL";
+RESIGNAL;
+select "after RESIGNAL";
+end;
+SIGNAL error SET
+MESSAGE_TEXT = "Raising an error",
+MYSQL_ERRNO = 1012;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 55555: Raising an error
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE CONTINUE HANDLER for sqlwarning
+begin
+select "before RESIGNAL";
+RESIGNAL;
+select "after RESIGNAL";
+end;
+insert into t_warn set a= 9999999999999999;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+after RESIGNAL
+after RESIGNAL
+Warnings:
+Warning	1264	Out of range value for column 'a' at row 1
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE x integer;
+DECLARE c cursor for select * from t_cursor;
+DECLARE CONTINUE HANDLER for not found
+begin
+select "before RESIGNAL";
+RESIGNAL;
+select "after RESIGNAL";
+end;
+open c;
+fetch c into x;
+close c;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 02000: No data - zero rows fetched, selected, or processed
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE CONTINUE HANDLER for sqlexception
+begin
+select "before RESIGNAL";
+RESIGNAL;
+select "after RESIGNAL";
+end;
+drop table no_such_table;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 42S02: Unknown table 'no_such_table'
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE warn CONDITION FOR SQLSTATE "01234";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "before RESIGNAL";
+RESIGNAL SET
+MESSAGE_TEXT = "RESIGNAL of a warning",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+SIGNAL warn SET
+MESSAGE_TEXT = "Raising a warning",
+MYSQL_ERRNO = 1012;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+after RESIGNAL
+after RESIGNAL
+Warnings:
+Warning	5555	RESIGNAL of a warning
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE not_found CONDITION FOR SQLSTATE "02111";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "before RESIGNAL";
+RESIGNAL SET
+MESSAGE_TEXT = "RESIGNAL of a not found",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+SIGNAL not_found SET
+MESSAGE_TEXT = "Raising a not found",
+MYSQL_ERRNO = 1012;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 02111: RESIGNAL of a not found
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE error CONDITION FOR SQLSTATE "33333";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "before RESIGNAL";
+RESIGNAL SET
+MESSAGE_TEXT = "RESIGNAL of an error",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+SIGNAL error SET
+MESSAGE_TEXT = "Raising an error",
+MYSQL_ERRNO = 1012;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 33333: RESIGNAL of an error
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE CONTINUE HANDLER for sqlwarning
+begin
+select "before RESIGNAL";
+RESIGNAL SET
+MESSAGE_TEXT = "RESIGNAL of a warning",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+insert into t_warn set a= 9999999999999999;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+after RESIGNAL
+after RESIGNAL
+Warnings:
+Warning	5555	RESIGNAL of a warning
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE x integer;
+DECLARE c cursor for select * from t_cursor;
+DECLARE CONTINUE HANDLER for not found
+begin
+select "before RESIGNAL";
+RESIGNAL SET
+MESSAGE_TEXT = "RESIGNAL of not found",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+open c;
+fetch c into x;
+close c;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 02000: RESIGNAL of not found
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE CONTINUE HANDLER for sqlexception
+begin
+select "before RESIGNAL";
+RESIGNAL SET
+MESSAGE_TEXT = "RESIGNAL of an error",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+drop table no_such_table;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 42S02: RESIGNAL of an error
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE warn CONDITION FOR SQLSTATE "01111";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "01222" SET
+MESSAGE_TEXT = "RESIGNAL to warning",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+SIGNAL warn SET
+MESSAGE_TEXT = "Raising a warning",
+MYSQL_ERRNO = 1012;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+after RESIGNAL
+after RESIGNAL
+Warnings:
+Warning	1012	Raising a warning
+Warning	5555	RESIGNAL to warning
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE warn CONDITION FOR SQLSTATE "01111";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "02222" SET
+MESSAGE_TEXT = "RESIGNAL to not found",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+SIGNAL warn SET
+MESSAGE_TEXT = "Raising a warning",
+MYSQL_ERRNO = 1012;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 02222: RESIGNAL to not found
+show warnings $$
+Level	Code	Message
+Warning	1012	Raising a warning
+Error	5555	RESIGNAL to not found
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE warn CONDITION FOR SQLSTATE "01111";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "33333" SET
+MESSAGE_TEXT = "RESIGNAL to error",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+SIGNAL warn SET
+MESSAGE_TEXT = "Raising a warning",
+MYSQL_ERRNO = 1012;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 33333: RESIGNAL to error
+show warnings $$
+Level	Code	Message
+Warning	1012	Raising a warning
+Error	5555	RESIGNAL to error
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE not_found CONDITION FOR SQLSTATE "02ABC";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "01222" SET
+MESSAGE_TEXT = "RESIGNAL to warning",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+SIGNAL not_found SET
+MESSAGE_TEXT = "Raising a not found",
+MYSQL_ERRNO = 1012;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+after RESIGNAL
+after RESIGNAL
+Warnings:
+Error	1012	Raising a not found
+Warning	5555	RESIGNAL to warning
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE not_found CONDITION FOR SQLSTATE "02ABC";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "02222" SET
+MESSAGE_TEXT = "RESIGNAL to not found",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+SIGNAL not_found SET
+MESSAGE_TEXT = "Raising a not found",
+MYSQL_ERRNO = 1012;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 02222: RESIGNAL to not found
+show warnings $$
+Level	Code	Message
+Error	1012	Raising a not found
+Error	5555	RESIGNAL to not found
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE not_found CONDITION FOR SQLSTATE "02ABC";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "33333" SET
+MESSAGE_TEXT = "RESIGNAL to error",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+SIGNAL not_found SET
+MESSAGE_TEXT = "Raising a not found",
+MYSQL_ERRNO = 1012;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 33333: RESIGNAL to error
+show warnings $$
+Level	Code	Message
+Error	1012	Raising a not found
+Error	5555	RESIGNAL to error
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE error CONDITION FOR SQLSTATE "AAAAA";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "01222" SET
+MESSAGE_TEXT = "RESIGNAL to warning",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+SIGNAL error SET
+MESSAGE_TEXT = "Raising an error",
+MYSQL_ERRNO = 1012;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+after RESIGNAL
+after RESIGNAL
+Warnings:
+Error	1012	Raising an error
+Warning	5555	RESIGNAL to warning
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE error CONDITION FOR SQLSTATE "AAAAA";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "02222" SET
+MESSAGE_TEXT = "RESIGNAL to not found",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+SIGNAL error SET
+MESSAGE_TEXT = "Raising an error",
+MYSQL_ERRNO = 1012;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 02222: RESIGNAL to not found
+show warnings $$
+Level	Code	Message
+Error	1012	Raising an error
+Error	5555	RESIGNAL to not found
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE error CONDITION FOR SQLSTATE "AAAAA";
+DECLARE CONTINUE HANDLER for 1012
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "33333" SET
+MESSAGE_TEXT = "RESIGNAL to error",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+SIGNAL error SET
+MESSAGE_TEXT = "Raising an error",
+MYSQL_ERRNO = 1012;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 33333: RESIGNAL to error
+show warnings $$
+Level	Code	Message
+Error	1012	Raising an error
+Error	5555	RESIGNAL to error
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE CONTINUE HANDLER for sqlwarning
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "01111" SET
+MESSAGE_TEXT = "RESIGNAL to a warning",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+insert into t_warn set a= 9999999999999999;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+after RESIGNAL
+after RESIGNAL
+Warnings:
+Warning	1264	Out of range value for column 'a' at row 1
+Warning	5555	RESIGNAL to a warning
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE CONTINUE HANDLER for sqlwarning
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "02444" SET
+MESSAGE_TEXT = "RESIGNAL to a not found",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+insert into t_warn set a= 9999999999999999;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 02444: RESIGNAL to a not found
+show warnings $$
+Level	Code	Message
+Warning	1264	Out of range value for column 'a' at row 1
+Error	5555	RESIGNAL to a not found
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE CONTINUE HANDLER for sqlwarning
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "44444" SET
+MESSAGE_TEXT = "RESIGNAL to an error",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+insert into t_warn set a= 9999999999999999;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 44444: RESIGNAL to an error
+show warnings $$
+Level	Code	Message
+Warning	1264	Out of range value for column 'a' at row 1
+Error	5555	RESIGNAL to an error
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE x integer;
+DECLARE c cursor for select * from t_cursor;
+DECLARE CONTINUE HANDLER for not found
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "01111" SET
+MESSAGE_TEXT = "RESIGNAL to a warning",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+open c;
+fetch c into x;
+close c;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+after RESIGNAL
+after RESIGNAL
+Warnings:
+Error	1329	No data - zero rows fetched, selected, or processed
+Warning	5555	RESIGNAL to a warning
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE x integer;
+DECLARE c cursor for select * from t_cursor;
+DECLARE CONTINUE HANDLER for not found
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "02444" SET
+MESSAGE_TEXT = "RESIGNAL to a not found",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+open c;
+fetch c into x;
+close c;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 02444: RESIGNAL to a not found
+show warnings $$
+Level	Code	Message
+Error	1329	No data - zero rows fetched, selected, or processed
+Error	5555	RESIGNAL to a not found
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE x integer;
+DECLARE c cursor for select * from t_cursor;
+DECLARE CONTINUE HANDLER for not found
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "44444" SET
+MESSAGE_TEXT = "RESIGNAL to an error",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+open c;
+fetch c into x;
+close c;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 44444: RESIGNAL to an error
+show warnings $$
+Level	Code	Message
+Error	1329	No data - zero rows fetched, selected, or processed
+Error	5555	RESIGNAL to an error
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE CONTINUE HANDLER for sqlexception
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "01111" SET
+MESSAGE_TEXT = "RESIGNAL to a warning",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+drop table no_such_table;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+after RESIGNAL
+after RESIGNAL
+Warnings:
+Error	1051	Unknown table 'no_such_table'
+Warning	5555	RESIGNAL to a warning
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE CONTINUE HANDLER for sqlexception
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "02444" SET
+MESSAGE_TEXT = "RESIGNAL to a not found",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+drop table no_such_table;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 02444: RESIGNAL to a not found
+show warnings $$
+Level	Code	Message
+Error	1051	Unknown table 'no_such_table'
+Error	5555	RESIGNAL to a not found
+drop procedure test_resignal $$
+create procedure test_resignal()
+begin
+DECLARE CONTINUE HANDLER for sqlexception
+begin
+select "before RESIGNAL";
+RESIGNAL SQLSTATE "44444" SET
+MESSAGE_TEXT = "RESIGNAL to an error",
+MYSQL_ERRNO = 5555 ;
+select "after RESIGNAL";
+end;
+drop table no_such_table;
+end $$
+call test_resignal() $$
+before RESIGNAL
+before RESIGNAL
+ERROR 44444: RESIGNAL to an error
+show warnings $$
+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 MYSQL_ERRNO = 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 SQLSTATE '42000';
+DECLARE EXIT HANDLER FOR x
+BEGIN
+SELECT '2';
+RESIGNAL x SET MYSQL_ERRNO = 9999;
+END;
+BEGIN
+DECLARE EXIT HANDLER FOR x
+BEGIN
+SELECT '1';
+RESIGNAL x SET
+SCHEMA_NAME = 'test',
+MYSQL_ERRNO= 1231;
+END;
+/* Raises ER_WRONG_VALUE_FOR_VAR : 1231, SQLSTATE 42000 */
+SET @@sql_mode=NULL;
+END;
+END
+$$
+CREATE PROCEDURE peter_p2 ()
+BEGIN
+DECLARE x CONDITION for SQLSTATE '42000';
+DECLARE EXIT HANDLER FOR x
+BEGIN
+SELECT '3';
+RESIGNAL x SET
+MESSAGE_TEXT = 'Hi, I am a useless error message',
+MYSQL_ERRNO = 9999;
+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	1231	Variable 'sql_mode' can't be set to the value of 'NULL'
+Error	1231	Variable 'sql_mode' can't be set to the value of 'NULL'
+Error	9999	Variable 'sql_mode' can't be set to the value of 'NULL'
+Error	9999	Hi, I am a useless error message
+drop procedure peter_p1 $$
+drop procedure peter_p2 $$
+drop procedure if exists peter_p3 $$
+Warnings:
+Note	1305	PROCEDURE test.peter_p3 does not exist
+create procedure peter_p3()
+begin
+declare continue handler for sqlexception
+resignal sqlstate '99002' set mysql_errno = 2;
+signal sqlstate '99001' set mysql_errno = 1, message_text = "Original";
+end $$
+call peter_p3() $$
+ERROR 99002: Original
+show warnings $$
+Level	Code	Message
+Error	1	Original
+Error	2	Original
+drop procedure peter_p3 $$
+drop table t_warn;
+drop table t_cursor;

=== added file 'mysql-test/r/signal_code.result'
--- a/mysql-test/r/signal_code.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/signal_code.result	2008-08-27 22:14:03 +0000
@@ -0,0 +1,35 @@
+use test;
+drop procedure if exists signal_proc;
+drop function if exists signal_func;
+create procedure signal_proc()
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo;
+SIGNAL foo SET MESSAGE_TEXT = "This is an error message";
+RESIGNAL foo;
+RESIGNAL foo SET MESSAGE_TEXT = "This is an error message";
+end $$
+create function signal_func() returns int
+begin
+DECLARE foo CONDITION FOR SQLSTATE '12345';
+SIGNAL foo;
+SIGNAL foo SET MESSAGE_TEXT = "This is an error message";
+RESIGNAL foo;
+RESIGNAL foo SET MESSAGE_TEXT = "This is an error message";
+return 0;
+end $$
+show procedure code signal_proc;
+Pos	Instruction
+0	stmt 133 "SIGNAL foo"
+1	stmt 133 "SIGNAL foo SET MESSAGE_TEXT = "This i..."
+2	stmt 134 "RESIGNAL foo"
+3	stmt 134 "RESIGNAL foo SET MESSAGE_TEXT = "This..."
+drop procedure signal_proc;
+show function code signal_func;
+Pos	Instruction
+0	stmt 133 "SIGNAL foo"
+1	stmt 133 "SIGNAL foo SET MESSAGE_TEXT = "This i..."
+2	stmt 134 "RESIGNAL foo"
+3	stmt 134 "RESIGNAL foo SET MESSAGE_TEXT = "This..."
+4	freturn 3 0
+drop function signal_func;

=== added file 'mysql-test/r/signal_demo1.result'
--- a/mysql-test/r/signal_demo1.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/signal_demo1.result	2008-08-27 22:14:03 +0000
@@ -0,0 +1,264 @@
+drop database if exists demo;
+create database demo;
+use demo;
+create table ab_physical_person (
+person_id integer,
+first_name VARCHAR(50),
+middle_initial CHAR,
+last_name VARCHAR(50),
+primary key (person_id));
+create table ab_moral_person (
+company_id integer,
+name VARCHAR(100),
+primary key (company_id));
+create table in_inventory (
+item_id integer,
+descr VARCHAR(50),
+stock integer,
+primary key (item_id));
+create table po_order (
+po_id integer auto_increment,
+cust_type char, /* arc relationship, see cust_id */
+cust_id integer, /* FK to ab_physical_person *OR* ab_moral_person */
+primary key (po_id));
+create table po_order_line (
+po_id integer, /* FK to po_order.po_id */
+line_no integer,
+item_id integer, /* FK to in_inventory.item_id */
+qty integer);
+create procedure check_pk_person(in person_type char, in id integer)
+begin
+declare x integer;
+declare msg varchar(128);
+/*
+Test integrity constraints for an 'arc' relationship.
+Based on 'person_type', 'id' points to either a
+physical person, or a moral person.
+*/
+case person_type
+when 'P' then
+begin
+select count(person_id) from ab_physical_person
+where ab_physical_person.person_id = id
+into x;
+if (x != 1)
+then
+set msg= concat('No such physical person, PK:', id);
+SIGNAL SQLSTATE '45000' SET
+MESSAGE_TEXT = msg,
+MYSQL_ERRNO = 10000;
+end if;
+end;
+when 'M' then
+begin
+select count(company_id) from ab_moral_person
+where ab_moral_person.company_id = id
+into x;
+if (x != 1)
+then
+set msg= concat('No such moral person, PK:', id);
+SIGNAL SQLSTATE '45000' SET
+MESSAGE_TEXT = msg,
+MYSQL_ERRNO = 10000;
+end if;
+end;
+else
+begin
+set msg= concat('No such person type:', person_type);
+SIGNAL SQLSTATE '45000' SET
+MESSAGE_TEXT = msg,
+MYSQL_ERRNO = 20000;
+end;
+end case;
+end
+$$
+create procedure check_pk_inventory(in id integer)
+begin
+declare x integer;
+declare msg varchar(128);
+select count(item_id) from in_inventory
+where in_inventory.item_id = id
+into x;
+if (x != 1)
+then
+set msg= concat('Failed integrity constraint, table in_inventory, PK:',
+id);
+SIGNAL SQLSTATE '45000' SET
+MESSAGE_TEXT = msg,
+MYSQL_ERRNO = 10000;
+end if;
+end
+$$
+create procedure check_pk_order(in id integer)
+begin
+declare x integer;
+declare msg varchar(128);
+select count(po_id) from po_order
+where po_order.po_id = id
+into x;
+if (x != 1)
+then
+set msg= concat('Failed integrity constraint, table po_order, PK:', id);
+SIGNAL SQLSTATE '45000' SET
+MESSAGE_TEXT = msg,
+MYSQL_ERRNO = 10000;
+end if;
+end
+$$
+create trigger po_order_bi before insert on po_order
+for each row
+begin
+call check_pk_person(NEW.cust_type, NEW.cust_id);
+end
+$$
+create trigger po_order_bu before update on po_order
+for each row
+begin
+call check_pk_person(NEW.cust_type, NEW.cust_id);
+end
+$$
+create trigger po_order_line_bi before insert on po_order_line
+for each row
+begin
+call check_pk_order(NEW.po_id);
+call check_pk_inventory(NEW.item_id);
+end
+$$
+create trigger po_order_line_bu before update on po_order_line
+for each row
+begin
+call check_pk_order(NEW.po_id);
+call check_pk_inventory(NEW.item_id);
+end
+$$
+create procedure po_create_order(
+in p_cust_type char,
+in p_cust_id integer,
+out id integer)
+begin
+insert into po_order set cust_type = p_cust_type, cust_id = p_cust_id;
+set id = last_insert_id();
+end
+$$
+create procedure po_add_order_line(
+in po integer,
+in line integer,
+in item integer,
+in q integer)
+begin
+insert into po_order_line set
+po_id = po, line_no = line, item_id = item, qty = q;
+end
+$$
+select "Create sample data";
+Create sample data
+Create sample data
+insert into ab_physical_person values
+( 1, "John", "A", "Doe"),
+( 2, "Marry", "B", "Smith")
+;
+insert into ab_moral_person values
+( 3, "ACME real estate, INC"),
+( 4, "Local school")
+;
+insert into in_inventory values
+( 100, "Table, dinner", 5),
+( 101, "Chair", 20),
+( 200, "Table, coffee", 3),
+( 300, "School table", 25),
+( 301, "School chairs", 50)
+;
+select * from ab_physical_person order by person_id;
+person_id	first_name	middle_initial	last_name
+1	John	A	Doe
+2	Marry	B	Smith
+select * from ab_moral_person order by company_id;
+company_id	name
+3	ACME real estate, INC
+4	Local school
+select * from in_inventory order by item_id;
+item_id	descr	stock
+100	Table, dinner	5
+101	Chair	20
+200	Table, coffee	3
+300	School table	25
+301	School chairs	50
+select "Entering an order !";
+Entering an order !
+Entering an order !
+set @my_po = 0;
+/* John Doe wants 1 table and 4 chairs */
+call po_create_order("P", 1, @my_po);
+call po_add_order_line (@my_po, 1, 100, 1);
+call po_add_order_line (@my_po, 2, 101, 4);
+/* Marry Smith wants a coffee table */
+call po_create_order("P", 2, @my_po);
+call po_add_order_line (@my_po, 1, 200, 1);
+select "Entering bad data in an order";
+Entering bad data in an order
+Entering bad data in an order
+call po_add_order_line (@my_po, 1, 999, 1);
+ERROR 45000: Failed integrity constraint, table in_inventory, PK:999
+select "Entering bad data in an unknown order";
+Entering bad data in an unknown order
+Entering bad data in an unknown order
+call po_add_order_line (99, 1, 100, 1);
+ERROR 45000: Failed integrity constraint, table po_order, PK:99
+select "Entering an order for an unknown company";
+Entering an order for an unknown company
+Entering an order for an unknown company
+call po_create_order("M", 7, @my_po);
+ERROR 45000: No such moral person, PK:7
+select "Entering an order for an unknown person type";
+Entering an order for an unknown person type
+Entering an order for an unknown person type
+call po_create_order("X", 1, @my_po);
+ERROR 45000: No such person type:X
+/* The local school wants 10 class tables and 20 chairs */
+call po_create_order("M", 4, @my_po);
+call po_add_order_line (@my_po, 1, 300, 10);
+call po_add_order_line (@my_po, 2, 301, 20);
+select * from po_order;
+po_id	cust_type	cust_id
+1	P	1
+2	P	2
+3	M	4
+select * from po_order_line;
+po_id	line_no	item_id	qty
+1	1	100	1
+1	2	101	4
+2	1	200	1
+3	1	300	10
+3	2	301	20
+select po_id as "PO#",
+( case cust_type
+when "P" then concat (pp.first_name,
+" ",
+pp.middle_initial,
+" ",
+pp.last_name)
+when "M" then mp.name
+end ) as "Sold to"
+  from po_order po
+left join ab_physical_person pp on po.cust_id = pp.person_id
+left join ab_moral_person mp on po.cust_id = company_id
+;
+PO#	Sold to
+1	John A Doe
+2	Marry B Smith
+3	Local school
+select po_id as "PO#",
+ol.line_no as "Line",
+ol.item_id as "Item",
+inv.descr as "Description",
+ol.qty as "Quantity"
+  from po_order_line ol, in_inventory inv
+where inv.item_id = ol.item_id
+order by ol.item_id, ol.line_no;
+PO#	Line	Item	Description	Quantity
+1	1	100	Table, dinner	1
+1	2	101	Chair	4
+2	1	200	Table, coffee	1
+3	1	300	School table	10
+3	2	301	School chairs	20
+drop database demo;

=== added file 'mysql-test/r/signal_demo2.result'
--- a/mysql-test/r/signal_demo2.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/signal_demo2.result	2008-08-27 22:14:03 +0000
@@ -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;

=== added file 'mysql-test/r/signal_demo3.result'
--- a/mysql-test/r/signal_demo3.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/signal_demo3.result	2008-08-27 22:14:03 +0000
@@ -0,0 +1,143 @@
+SET @start_global_value = @@global.max_error_count;
+SELECT @start_global_value;
+@start_global_value
+64
+SET @start_session_value = @@session.max_error_count;
+SELECT @start_session_value;
+@start_session_value
+64
+drop database if exists demo;
+create database demo;
+use demo;
+create procedure proc_1()
+begin
+declare exit handler for sqlexception
+resignal sqlstate '45000' set message_text='Oops in proc_1';
+call proc_2();
+end
+$$
+create procedure proc_2()
+begin
+declare exit handler for sqlexception
+resignal sqlstate '45000' set message_text='Oops in proc_2';
+call proc_3();
+end
+$$
+create procedure proc_3()
+begin
+declare exit handler for sqlexception
+resignal sqlstate '45000' set message_text='Oops in proc_3';
+call proc_4();
+end
+$$
+create procedure proc_4()
+begin
+declare exit handler for sqlexception
+resignal sqlstate '45000' set message_text='Oops in proc_4';
+call proc_5();
+end
+$$
+create procedure proc_5()
+begin
+declare exit handler for sqlexception
+resignal sqlstate '45000' set message_text='Oops in proc_5';
+call proc_6();
+end
+$$
+create procedure proc_6()
+begin
+declare exit handler for sqlexception
+resignal sqlstate '45000' set message_text='Oops in proc_6';
+call proc_7();
+end
+$$
+create procedure proc_7()
+begin
+declare exit handler for sqlexception
+resignal sqlstate '45000' set message_text='Oops in proc_7';
+call proc_8();
+end
+$$
+create procedure proc_8()
+begin
+declare exit handler for sqlexception
+resignal sqlstate '45000' set message_text='Oops in proc_8';
+call proc_9();
+end
+$$
+create procedure proc_9()
+begin
+declare exit handler for sqlexception
+resignal sqlstate '45000' set message_text='Oops in proc_9';
+## Do something that fails, to see how errors are reported
+drop table oops_it_is_not_here;
+end
+$$
+call proc_1();
+ERROR 45000: Oops in proc_1
+show warnings;
+Level	Code	Message
+Error	1051	Unknown table 'oops_it_is_not_here'
+Error	1729	Oops in proc_9
+Error	1729	Oops in proc_8
+Error	1729	Oops in proc_7
+Error	1729	Oops in proc_6
+Error	1729	Oops in proc_5
+Error	1729	Oops in proc_4
+Error	1729	Oops in proc_3
+Error	1729	Oops in proc_2
+Error	1729	Oops in proc_1
+SET @@session.max_error_count = 5;
+SELECT @@session.max_error_count;
+@@session.max_error_count
+5
+call proc_1();
+ERROR 45000: Oops in proc_1
+show warnings;
+Level	Code	Message
+Error	1729	Oops in proc_5
+Error	1729	Oops in proc_4
+Error	1729	Oops in proc_3
+Error	1729	Oops in proc_2
+Error	1729	Oops in proc_1
+SET @@session.max_error_count = 7;
+SELECT @@session.max_error_count;
+@@session.max_error_count
+7
+call proc_1();
+ERROR 45000: Oops in proc_1
+show warnings;
+Level	Code	Message
+Error	1729	Oops in proc_7
+Error	1729	Oops in proc_6
+Error	1729	Oops in proc_5
+Error	1729	Oops in proc_4
+Error	1729	Oops in proc_3
+Error	1729	Oops in proc_2
+Error	1729	Oops in proc_1
+SET @@session.max_error_count = 9;
+SELECT @@session.max_error_count;
+@@session.max_error_count
+9
+call proc_1();
+ERROR 45000: Oops in proc_1
+show warnings;
+Level	Code	Message
+Error	1729	Oops in proc_9
+Error	1729	Oops in proc_8
+Error	1729	Oops in proc_7
+Error	1729	Oops in proc_6
+Error	1729	Oops in proc_5
+Error	1729	Oops in proc_4
+Error	1729	Oops in proc_3
+Error	1729	Oops in proc_2
+Error	1729	Oops in proc_1
+drop database demo;
+SET @@global.max_error_count = @start_global_value;
+SELECT @@global.max_error_count;
+@@global.max_error_count
+64
+SET @@session.max_error_count = @start_session_value;
+SELECT @@session.max_error_count;
+@@session.max_error_count
+64

=== added file 'mysql-test/r/signal_sqlmode.result'
--- a/mysql-test/r/signal_sqlmode.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/signal_sqlmode.result	2008-08-27 22:14:03 +0000
@@ -0,0 +1,86 @@
+SET @save_sql_mode=@@sql_mode;
+SET sql_mode='';
+drop procedure if exists p;
+drop procedure if exists p2;
+drop procedure if exists p3;
+create procedure p()
+begin
+declare utf8_var VARCHAR(128) CHARACTER SET UTF8;
+set utf8_var = concat(repeat('A', 128), 'X');
+select length(utf8_var), utf8_var;
+end
+$$
+create procedure p2()
+begin
+declare msg VARCHAR(129) CHARACTER SET UTF8;
+set msg = concat(repeat('A', 128), 'X');
+select length(msg), msg;
+signal sqlstate '55555' set message_text = msg;
+end
+$$
+create procedure p3()
+begin
+declare name VARCHAR(65) CHARACTER SET UTF8;
+set name = concat(repeat('A', 64), 'X');
+select length(name), name;
+signal sqlstate '55555' set
+message_text = 'Message',
+table_name = name;
+end
+$$
+call p;
+length(utf8_var)	utf8_var
+128	AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+Warnings:
+Warning	1265	Data truncated for column 'utf8_var' at row 1
+call p2;
+length(msg)	msg
+129	AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX
+ERROR 55555: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+call p3;
+length(name)	name
+65	AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX
+ERROR 55555: Message
+drop procedure p;
+drop procedure p2;
+drop procedure p3;
+SET sql_mode='STRICT_ALL_TABLES';
+create procedure p()
+begin
+declare utf8_var VARCHAR(128) CHARACTER SET UTF8;
+set utf8_var = concat(repeat('A', 128), 'X');
+select length(utf8_var), utf8_var;
+end
+$$
+create procedure p2()
+begin
+declare msg VARCHAR(129) CHARACTER SET UTF8;
+set msg = concat(repeat('A', 128), 'X');
+select length(msg), msg;
+signal sqlstate '55555' set message_text = msg;
+end
+$$
+create procedure p3()
+begin
+declare name VARCHAR(65) CHARACTER SET UTF8;
+set name = concat(repeat('A', 64), 'X');
+select length(name), name;
+signal sqlstate '55555' set
+message_text = 'Message',
+table_name = name;
+end
+$$
+call p;
+ERROR 22001: Data too long for column 'utf8_var' at row 1
+call p2;
+length(msg)	msg
+129	AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX
+ERROR HY000: Data too long for condition item 'MESSAGE_TEXT'
+call p3;
+length(name)	name
+65	AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX
+ERROR HY000: Data too long for condition item 'TABLE_NAME'
+drop procedure p;
+drop procedure p2;
+drop procedure p3;
+SET @@sql_mode=@save_sql_mode;

=== added file 'mysql-test/r/signal_utf32.result'
--- a/mysql-test/r/signal_utf32.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/signal_utf32.result	2008-08-27 22:14:03 +0000
@@ -0,0 +1,34 @@
+drop procedure if exists test_signal;
+create procedure test_signal()
+begin
+DECLARE something CONDITION FOR SQLSTATE "01000";
+SIGNAL something SET MESSAGE_TEXT =
+_utf32 'a';
+end $$
+call test_signal() $$
+Warnings:
+Warning	1727	a
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+DECLARE something CONDITION FOR SQLSTATE "01000";
+SIGNAL something SET MESSAGE_TEXT =
+_utf32 X'00000048000000450000004C0000004C0000004F';
+end $$
+call test_signal() $$
+Warnings:
+Warning	1727	HELLO
+drop procedure test_signal $$
+create procedure test_signal()
+begin
+declare continue handler for sqlexception
+begin
+declare msg varchar(128);
+set msg= repeat(_utf32 0x000100cc, 128);
+resignal set message_text = msg;
+end;
+signal sqlstate '77777';
+end $$
+call test_signal() $$
+ERROR 77777: ����������������������������������������������������������������
+drop procedure test_signal $$

=== modified file 'mysql-test/r/symlink.result'
--- a/mysql-test/r/symlink.result	2008-04-14 10:15:04 +0000
+++ b/mysql-test/r/symlink.result	2008-08-27 22:14:03 +0000
@@ -83,7 +83,7 @@ drop database mysqltest;
 create table t1 (a int not null) engine=myisam;
 alter table t1 data directory="MYSQLTEST_VARDIR/tmp";
 Warnings:
-Warning	0	DATA DIRECTORY option ignored
+Warning	1105	DATA DIRECTORY option ignored
 show create table t1;
 Table	Create Table
 t1	CREATE TABLE `t1` (
@@ -92,7 +92,7 @@ t1	CREATE TABLE `t1` (
 alter table t1 add b int;
 alter table t1 data directory="MYSQLTEST_VARDIR/log";
 Warnings:
-Warning	0	DATA DIRECTORY option ignored
+Warning	1105	DATA DIRECTORY option ignored
 show create table t1;
 Table	Create Table
 t1	CREATE TABLE `t1` (
@@ -101,7 +101,7 @@ t1	CREATE TABLE `t1` (
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 alter table t1 index directory="MYSQLTEST_VARDIR/log";
 Warnings:
-Warning	0	INDEX DIRECTORY option ignored
+Warning	1105	INDEX DIRECTORY option ignored
 show create table t1;
 Table	Create Table
 t1	CREATE TABLE `t1` (
@@ -168,8 +168,8 @@ ERROR HY000: Can't create/write to file 
 SET @OLD_SQL_MODE=@@SQL_MODE, @@SQL_MODE='NO_DIR_IN_CREATE';
 CREATE TABLE t1(a INT) DATA DIRECTORY='MYSQLTEST_VARDIR/tmp' INDEX DIRECTORY='MYSQLTEST_VARDIR/tmp';
 Warnings:
-Warning	0	DATA DIRECTORY option ignored
-Warning	0	INDEX DIRECTORY option ignored
+Warning	1105	DATA DIRECTORY option ignored
+Warning	1105	INDEX DIRECTORY option ignored
 DROP TABLE t1;
 SET @@SQL_MODE=@OLD_SQL_MODE;
 End of 5.1 tests

=== modified file 'mysql-test/r/windows.result'
--- a/mysql-test/r/windows.result	2007-11-18 13:33:12 +0000
+++ b/mysql-test/r/windows.result	2008-08-27 22:14:03 +0000
@@ -9,8 +9,8 @@ drop table nu;
 drop table if exists t1;
 CREATE TABLE t1 ( `ID` int(6) ) data directory 'c:/tmp/' index directory 'c:/tmp/' engine=MyISAM;
 Warnings:
-Warning	0	DATA DIRECTORY option ignored
-Warning	0	INDEX DIRECTORY option ignored
+Warning	1105	DATA DIRECTORY option ignored
+Warning	1105	INDEX DIRECTORY option ignored
 drop table t1;
 CREATE TABLE t1 (a int, b int);
 INSERT INTO t1 VALUES (1,1);

=== added file 'mysql-test/t/signal.test'
--- a/mysql-test/t/signal.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/signal.test	2008-08-27 22:14:03 +0000
@@ -0,0 +1,2508 @@
+# 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
+
+# Tests for SIGNAL and RESIGNAL
+
+#
+# PART 1: syntax
+#
+
+#
+# Test every new reserved and non reserved keywords
+#
+
+--disable_warnings
+drop table if exists signal_non_reserved;
+--enable_warnings
+
+create table signal_non_reserved (
+  class_origin int,
+  subclass_origin int,
+  constraint_catalog int,
+  constraint_schema int,
+  constraint_name int,
+  catalog_name int,
+  schema_name int,
+  table_name int,
+  column_name int,
+  cursor_name int,
+  message_text int,
+  sqlcode int
+);
+
+drop table signal_non_reserved;
+
+--disable_warnings
+drop table if exists diag_non_reserved;
+--enable_warnings
+
+create table diag_non_reserved (
+  diagnostics int,
+  current int,
+  stacked int,
+  exception int
+);
+
+drop table diag_non_reserved;
+
+--disable_warnings
+drop table if exists diag_cond_non_reserved;
+--enable_warnings
+
+create table diag_cond_non_reserved (
+  condition_identifier int,
+  condition_number int,
+  condition_name int,
+  connection_name int,
+  message_length int,
+  message_octet_length int,
+  parameter_mode int,
+  parameter_name int,
+  parameter_ordinal_position int,
+  returned_sqlstate int,
+  routine_catalog int,
+  routine_name int,
+  routine_schema int,
+  server_name int,
+  specific_name int,
+  trigger_catalog int,
+  trigger_name int,
+  trigger_schema int
+);
+
+drop table diag_cond_non_reserved;
+
+--disable_warnings
+drop table if exists diag_stmt_non_reserved;
+--enable_warnings
+
+create table diag_stmt_non_reserved (
+  number int,
+  more int,
+  command_function int,
+  command_function_code int,
+  dynamic_function int,
+  dynamic_function_code int,
+  row_count int,
+  transactions_committed int,
+  transactions_rolled_back int,
+  transaction_active int
+);
+
+drop table diag_stmt_non_reserved;
+
+--disable_warnings
+drop table if exists test_reserved;
+--enable_warnings
+
+--error ER_PARSE_ERROR
+create table test_reserved (signal int);
+
+--error ER_PARSE_ERROR
+create table test_reserved (resignal int);
+
+--error ER_PARSE_ERROR
+create table test_reserved (condition int);
+
+#
+# Test the SIGNAL syntax
+#
+
+--disable_warnings
+drop procedure if exists test_invalid;
+drop procedure if exists test_signal_syntax;
+drop function if exists test_signal_func;
+--enable_warnings
+
+delimiter $$;
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL;
+end $$
+
+--error ER_SP_COND_MISMATCH
+create procedure test_invalid()
+begin
+  SIGNAL foo;
+end $$
+
+--error ER_SIGNAL_BAD_CONDITION_TYPE
+create procedure test_invalid()
+begin
+  DECLARE foo CONDITION FOR 1234;
+  SIGNAL foo;
+end $$
+
+create procedure test_signal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo;
+end $$
+drop procedure test_signal_syntax $$
+
+create procedure test_signal_syntax()
+begin
+  SIGNAL SQLSTATE '23000';
+end $$
+drop procedure test_signal_syntax $$
+
+create procedure test_signal_syntax()
+begin
+  SIGNAL SQLSTATE VALUE '23000';
+end $$
+drop procedure test_signal_syntax $$
+
+create procedure test_signal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET CLASS_ORIGIN = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+
+create procedure test_signal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET SUBCLASS_ORIGIN = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+
+create procedure test_signal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET CONSTRAINT_CATALOG = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+
+create procedure test_signal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET CONSTRAINT_SCHEMA = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+
+create procedure test_signal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET CONSTRAINT_NAME = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+
+create procedure test_signal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET CATALOG_NAME = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+
+create procedure test_signal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET SCHEMA_NAME = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+
+create procedure test_signal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET TABLE_NAME = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+
+create procedure test_signal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET COLUMN_NAME = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+
+create procedure test_signal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET CURSOR_NAME = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+
+create procedure test_signal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET MESSAGE_TEXT = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+
+create procedure test_signal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET MYSQL_ERRNO = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+
+--error ER_DUP_SIGNAL_SET
+create procedure test_invalid()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET CLASS_ORIGIN = 'foo', CLASS_ORIGIN = 'bar';
+end $$
+
+--error ER_DUP_SIGNAL_SET
+create procedure test_invalid()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET MESSAGE_TEXT = 'foo', MESSAGE_TEXT = 'bar';
+end $$
+
+--error ER_DUP_SIGNAL_SET
+create procedure test_invalid()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET MYSQL_ERRNO = 'foo', MYSQL_ERRNO = 'bar';
+end $$
+
+create procedure test_signal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  SIGNAL foo SET
+    CLASS_ORIGIN = 'foo',
+    SUBCLASS_ORIGIN = 'foo',
+    CONSTRAINT_CATALOG = 'foo',
+    CONSTRAINT_SCHEMA = 'foo',
+    CONSTRAINT_NAME = 'foo',
+    CATALOG_NAME = 'foo',
+    SCHEMA_NAME = 'foo',
+    TABLE_NAME = 'foo',
+    COLUMN_NAME = 'foo',
+    CURSOR_NAME = 'foo',
+    MESSAGE_TEXT = 'foo',
+    MYSQL_ERRNO = 'foo';
+end $$
+drop procedure test_signal_syntax $$
+
+--error ER_SP_BAD_SQLSTATE
+SIGNAL SQLSTATE '00000' $$
+
+--error ER_SP_BAD_SQLSTATE
+SIGNAL SQLSTATE '00001' $$
+
+--error ER_SP_BAD_SQLSTATE
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '00000';
+end $$
+
+--error ER_SP_BAD_SQLSTATE
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '00001';
+end $$
+
+
+#
+# Test conditions information that SIGNAL can not set
+#
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET bla_bla = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET CONDITION_IDENTIFIER = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET CONDITION_NUMBER = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET CONNECTION_NAME = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET MESSAGE_LENGTH = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET MESSAGE_OCTET_LENGTH = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET PARAMETER_MODE = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET PARAMETER_NAME = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET PARAMETER_ORDINAL_POSITION = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET RETURNED_SQLSTATE = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET ROUTINE_CATALOG = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET ROUTINE_NAME = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET ROUTINE_SCHEMA = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET SERVER_NAME = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET SPECIFIC_NAME = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET TRIGGER_CATALOG = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET TRIGGER_NAME = 'foo';
+end $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  SIGNAL SQLSTATE '12345' SET TRIGGER_SCHEMA = 'foo';
+end $$
+
+delimiter ;$$
+
+#
+# Test the RESIGNAL syntax
+#
+
+--disable_warnings
+drop procedure if exists test_invalid;
+drop procedure if exists test_resignal_syntax;
+--enable_warnings
+
+delimiter $$;
+
+--error ER_SP_COND_MISMATCH
+create procedure test_invalid()
+begin
+  RESIGNAL foo;
+end $$
+
+create procedure test_resignal_syntax()
+begin
+  RESIGNAL;
+end $$
+drop procedure test_resignal_syntax $$
+
+--error ER_SIGNAL_BAD_CONDITION_TYPE
+create procedure test_invalid()
+begin
+  DECLARE foo CONDITION FOR 1234;
+  RESIGNAL foo;
+end $$
+
+create procedure test_resignal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo;
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  RESIGNAL SQLSTATE '23000';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  RESIGNAL SQLSTATE VALUE '23000';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  RESIGNAL SET CLASS_ORIGIN = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET CLASS_ORIGIN = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  RESIGNAL SET SUBCLASS_ORIGIN = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET SUBCLASS_ORIGIN = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  RESIGNAL SET CONSTRAINT_CATALOG = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET CONSTRAINT_CATALOG = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  RESIGNAL SET CONSTRAINT_SCHEMA = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET CONSTRAINT_SCHEMA = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  RESIGNAL SET CONSTRAINT_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET CONSTRAINT_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  RESIGNAL SET CATALOG_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET CATALOG_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  RESIGNAL SET SCHEMA_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET SCHEMA_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  RESIGNAL SET TABLE_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET TABLE_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  RESIGNAL SET COLUMN_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET COLUMN_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  RESIGNAL SET CURSOR_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET CURSOR_NAME = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  RESIGNAL SET MESSAGE_TEXT = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET MESSAGE_TEXT = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  RESIGNAL SET MYSQL_ERRNO = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+create procedure test_resignal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET MYSQL_ERRNO = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+--error ER_DUP_SIGNAL_SET
+create procedure test_invalid()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET CLASS_ORIGIN = 'foo', CLASS_ORIGIN = 'bar';
+end $$
+
+--error ER_DUP_SIGNAL_SET
+create procedure test_invalid()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET MESSAGE_TEXT = 'foo', MESSAGE_TEXT = 'bar';
+end $$
+
+--error ER_DUP_SIGNAL_SET
+create procedure test_invalid()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET MYSQL_ERRNO = 'foo', MYSQL_ERRNO = 'bar';
+end $$
+
+create procedure test_resignal_syntax()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+  RESIGNAL foo SET
+    CLASS_ORIGIN = 'foo',
+    SUBCLASS_ORIGIN = 'foo',
+    CONSTRAINT_CATALOG = 'foo',
+    CONSTRAINT_SCHEMA = 'foo',
+    CONSTRAINT_NAME = 'foo',
+    CATALOG_NAME = 'foo',
+    SCHEMA_NAME = 'foo',
+    TABLE_NAME = 'foo',
+    COLUMN_NAME = 'foo',
+    CURSOR_NAME = 'foo',
+    MESSAGE_TEXT = 'foo';
+end $$
+drop procedure test_resignal_syntax $$
+
+--error ER_SP_BAD_SQLSTATE
+create procedure test_invalid()
+begin
+  RESIGNAL SQLSTATE '00000';
+end $$
+
+delimiter ;$$
+
+#
+# PART 2: non preparable statements
+#
+
+--error ER_UNSUPPORTED_PS
+prepare stmt from 'SIGNAL SQLSTATE \'23000\'';
+
+--error ER_UNSUPPORTED_PS
+prepare stmt from 'RESIGNAL SQLSTATE \'23000\'';
+
+#
+# PART 3: runtime execution
+#
+
+--disable_warnings
+drop procedure if exists test_signal;
+drop procedure if exists test_resignal;
+drop table if exists t_warn;
+drop table if exists t_cursor;
+--enable_warnings
+
+# Helper tables
+create table t_warn(a integer(2));
+create table t_cursor(a integer);
+
+#
+# SIGNAL can also appear in a query
+#
+
+--error ER_SP_COND_MISMATCH
+SIGNAL foo;
+
+SIGNAL SQLSTATE '01000';
+
+--error ER_SIGNAL_NOT_FOUND
+SIGNAL SQLSTATE '02000';
+
+--error ER_SIGNAL_EXCEPTION
+SIGNAL SQLSTATE '23000';
+
+--error ER_SIGNAL_EXCEPTION
+SIGNAL SQLSTATE VALUE '23000';
+
+--error ER_WRONG_VALUE_FOR_VAR
+SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 65536;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 99999;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 4294967295;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 0;
+
+--error ER_PARSE_ERROR
+SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = -1;
+
+--error 65535
+SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 65535;
+
+#
+# RESIGNAL can also appear in a query
+#
+
+--error ER_RESIGNAL_NO_HANDLER
+RESIGNAL;
+
+--error ER_SP_COND_MISMATCH
+RESIGNAL foo;
+
+--error ER_RESIGNAL_NO_HANDLER
+RESIGNAL SQLSTATE '12345';
+
+--error ER_RESIGNAL_NO_HANDLER
+RESIGNAL SQLSTATE VALUE '12345';
+
+#
+# Different kind of SIGNAL conditions
+#
+
+delimiter $$;
+
+create procedure test_signal()
+begin
+  # max range
+  DECLARE foo CONDITION FOR SQLSTATE 'AABBB';
+  SIGNAL foo SET MYSQL_ERRNO = 65535;
+end $$
+
+--error 65535
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # max range
+  DECLARE foo CONDITION FOR SQLSTATE 'AABBB';
+  SIGNAL foo SET MYSQL_ERRNO = 65536;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # Error
+  DECLARE foo CONDITION FOR SQLSTATE '99999';
+  SIGNAL foo SET MYSQL_ERRNO = 9999;
+end $$
+
+--error 9999
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # warning
+  DECLARE too_few_records CONDITION FOR SQLSTATE '01000';
+  SIGNAL too_few_records SET MYSQL_ERRNO = 1261;
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  # Not found
+  DECLARE sp_fetch_no_data CONDITION FOR SQLSTATE '02000';
+  SIGNAL sp_fetch_no_data SET MYSQL_ERRNO = 1329;
+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 SQLSTATE '24000';
+  SIGNAL sp_cursor_already_open SET MYSQL_ERRNO = 1325;
+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 SQLSTATE '40001';
+  SIGNAL lock_deadlock SET MYSQL_ERRNO = 1213;
+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 ER_SIGNAL_EXCEPTION
+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 ER_SIGNAL_NOT_FOUND
+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 ER_SIGNAL_NOT_FOUND
+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 ER_SIGNAL_EXCEPTION
+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 ER_SIGNAL_EXCEPTION
+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 ER_SIGNAL_EXCEPTION
+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 ER_SIGNAL_EXCEPTION
+call test_signal() $$
+drop procedure test_signal $$
+
+# Test the scope of condition
+
+create procedure test_signal()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '99999';
+  begin
+    DECLARE foo CONDITION FOR 8888;
+  end;
+  SIGNAL foo SET MYSQL_ERRNO=9999; /* outer */
+end $$
+
+--error 9999
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE foo CONDITION FOR 9999;
+  begin
+    DECLARE foo CONDITION FOR SQLSTATE '88888';
+    SIGNAL foo SET MYSQL_ERRNO=8888; /* inner */
+  end;
+end $$
+
+--error 8888
+call test_signal() $$
+drop procedure test_signal $$
+
+# Test SET MYSQL_ERRNO
+
+create procedure test_signal()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '99999';
+  SIGNAL foo SET MYSQL_ERRNO = 1111;
+end $$
+
+--error 1111
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE warn CONDITION FOR SQLSTATE "01000";
+  SIGNAL warn SET MYSQL_ERRNO = 1111;
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE not_found CONDITION FOR SQLSTATE "02000";
+  SIGNAL not_found SET MYSQL_ERRNO = 1111;
+end $$
+
+--error 1111
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE "55000";
+  SIGNAL error SET MYSQL_ERRNO = 1111;
+end $$
+
+--error 1111
+call test_signal() $$
+drop procedure test_signal $$
+
+# Test SET MESSAGE_TEXT
+
+--error ER_SIGNAL_EXCEPTION
+SIGNAL SQLSTATE '77777' SET MESSAGE_TEXT='' $$
+
+create procedure test_signal()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '77777';
+  SIGNAL foo SET
+    MESSAGE_TEXT = "",
+    MYSQL_ERRNO=5678;
+end $$
+
+--error 5678
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '99999';
+  SIGNAL foo SET
+    MESSAGE_TEXT = "Something bad happened",
+    MYSQL_ERRNO=9999;
+end $$
+
+--error 9999
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE warn CONDITION FOR SQLSTATE "01000";
+  SIGNAL warn SET MESSAGE_TEXT = "Something bad happened";
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE not_found CONDITION FOR SQLSTATE "02000";
+  SIGNAL not_found SET MESSAGE_TEXT = "Something bad happened";
+end $$
+
+--error ER_SIGNAL_NOT_FOUND
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE "55000";
+  SIGNAL error SET MESSAGE_TEXT = "Something bad happened";
+end $$
+
+--error ER_SIGNAL_EXCEPTION
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE something CONDITION FOR SQLSTATE "01000";
+  SIGNAL something SET MESSAGE_TEXT = _utf8 "This is a UTF8 text";
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE something CONDITION FOR SQLSTATE "01000";
+  SIGNAL something SET MESSAGE_TEXT = "";
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+# Test SET complex expressions
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE '99999';
+  SIGNAL error SET
+    MYSQL_ERRNO = NULL;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE '99999';
+  SIGNAL error SET
+    CLASS_ORIGIN = NULL;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE '99999';
+  SIGNAL error SET
+    SUBCLASS_ORIGIN = NULL;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE '99999';
+  SIGNAL error SET
+    CONSTRAINT_CATALOG = NULL;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE '99999';
+  SIGNAL error SET
+    CONSTRAINT_SCHEMA = NULL;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE '99999';
+  SIGNAL error SET
+    CONSTRAINT_NAME = NULL;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE '99999';
+  SIGNAL error SET
+    CATALOG_NAME = NULL;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE '99999';
+  SIGNAL error SET
+    SCHEMA_NAME = NULL;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE '99999';
+  SIGNAL error SET
+    TABLE_NAME = NULL;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE '99999';
+  SIGNAL error SET
+    COLUMN_NAME = NULL;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE '99999';
+  SIGNAL error SET
+    CURSOR_NAME = NULL;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE '99999';
+  SIGNAL error SET
+    MESSAGE_TEXT = NULL;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE something CONDITION FOR SQLSTATE '99999';
+  DECLARE message_text VARCHAR(64) DEFAULT "Local string variable";
+  DECLARE sqlcode INTEGER DEFAULT 1234;
+
+  SIGNAL something SET
+    MESSAGE_TEXT = message_text,
+    MYSQL_ERRNO = sqlcode;
+end $$
+
+--error 1234
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal(message_text VARCHAR(64), sqlcode INTEGER)
+begin
+  DECLARE something CONDITION FOR SQLSTATE "12345";
+
+  SIGNAL something SET
+    MESSAGE_TEXT = message_text,
+    MYSQL_ERRNO = sqlcode;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal("Parameter string", NULL) $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal(NULL, 1234) $$
+
+--error 5678
+call test_signal("Parameter string", 5678) $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE something CONDITION FOR SQLSTATE "AABBB";
+
+  SIGNAL something SET
+    MESSAGE_TEXT = @message_text,
+    MYSQL_ERRNO = @sqlcode;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+
+set @sqlcode= 12 $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+
+set @message_text= "User variable" $$
+
+--error 12
+call test_signal() $$
+drop procedure test_signal $$
+
+--error ER_PARSE_ERROR
+create procedure test_invalid()
+begin
+  DECLARE something CONDITION FOR SQLSTATE "AABBB";
+
+  SIGNAL something SET
+    MESSAGE_TEXT = @message_text := 'illegal',
+    MYSQL_ERRNO = @sqlcode := 1234;
+end $$
+
+## create procedure test_signal()
+## begin
+##   DECLARE something CONDITION FOR SQLSTATE "12345";
+## 
+##   SIGNAL something SET
+##     MESSAGE_TEXT = concat("functions", " also works"),
+##     MYSQL_ERRNO = 1000 + 12;
+## end $$
+## 
+## --error 1012
+## call test_signal() $$
+## drop procedure test_signal $$
+
+## create procedure test_signal(code integer)
+## begin
+##   DECLARE something CONDITION FOR SQLSTATE "12345";
+## 
+##   SIGNAL something SET
+##     MESSAGE_TEXT = (select message_text from t1 where id=code),
+##     MYSQL_ERRNO = (select sqlcode from t1 where id=code);
+## end $$
+## 
+## --disable_warnings
+## drop table if exists t1 $$
+## --enable_warnings
+## 
+## --error ER_NO_SUCH_TABLE
+## call test_signal(1) $$
+## 
+## create table t1(id integer, message_text varchar(64), sqlcode integer) $$
+## 
+## --error ER_WRONG_VALUE_FOR_VAR
+## call test_signal(1) $$
+## 
+## insert into t1 values ((1), ("First message"), (1001)) $$
+## insert into t1 values ((2), ("Second message"), (1002)) $$
+## 
+## --error 1001
+## call test_signal(1) $$
+## 
+## --error 1002
+## call test_signal(2) $$
+
+## alter table t1 drop column message_text $$
+## 
+## --error ER_BAD_FIELD_ERROR
+## call test_signal(2) $$
+## 
+## drop table t1 $$
+## drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE aaa VARCHAR(64);
+  DECLARE bbb VARCHAR(64);
+  DECLARE ccc VARCHAR(64);
+  DECLARE ddd VARCHAR(64);
+  DECLARE eee VARCHAR(64);
+  DECLARE fff VARCHAR(64);
+  DECLARE ggg VARCHAR(64);
+  DECLARE hhh VARCHAR(64);
+  DECLARE iii VARCHAR(64);
+  DECLARE jjj VARCHAR(64);
+  DECLARE kkk VARCHAR(64);
+
+  DECLARE warn CONDITION FOR SQLSTATE "01234";
+
+  set aaa= repeat("A", 64);
+  set bbb= repeat("B", 64);
+  set ccc= repeat("C", 64);
+  set ddd= repeat("D", 64);
+  set eee= repeat("E", 64);
+  set fff= repeat("F", 64);
+  set ggg= repeat("G", 64);
+  set hhh= repeat("H", 64);
+  set iii= repeat("I", 64);
+  set jjj= repeat("J", 64);
+  set kkk= repeat("K", 64);
+
+  SIGNAL warn SET
+    CLASS_ORIGIN = aaa,
+    SUBCLASS_ORIGIN = bbb,
+    CONSTRAINT_CATALOG = ccc,
+    CONSTRAINT_SCHEMA = ddd,
+    CONSTRAINT_NAME = eee,
+    CATALOG_NAME = fff,
+    SCHEMA_NAME = ggg,
+    TABLE_NAME = hhh,
+    COLUMN_NAME = iii,
+    CURSOR_NAME = jjj,
+    MESSAGE_TEXT = kkk,
+    MYSQL_ERRNO = 65535;
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE warn CONDITION FOR SQLSTATE "01234";
+
+  SIGNAL warn SET
+    MYSQL_ERRNO = 999999999999999999999999999999999999999999999999999;
+end $$
+
+--error ER_WRONG_VALUE_FOR_VAR
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE aaax VARCHAR(65);
+  DECLARE bbbx VARCHAR(65);
+  DECLARE cccx VARCHAR(65);
+  DECLARE dddx VARCHAR(65);
+  DECLARE eeex VARCHAR(65);
+  DECLARE fffx VARCHAR(65);
+  DECLARE gggx VARCHAR(65);
+  DECLARE hhhx VARCHAR(65);
+  DECLARE iiix VARCHAR(65);
+  DECLARE jjjx VARCHAR(65);
+  DECLARE kkkx VARCHAR(65);
+  DECLARE lllx VARCHAR(129);
+
+  DECLARE warn CONDITION FOR SQLSTATE "01234";
+
+  set aaax= concat(repeat("A", 64), "X");
+  set bbbx= concat(repeat("B", 64), "X");
+  set cccx= concat(repeat("C", 64), "X");
+  set dddx= concat(repeat("D", 64), "X");
+  set eeex= concat(repeat("E", 64), "X");
+  set fffx= concat(repeat("F", 64), "X");
+  set gggx= concat(repeat("G", 64), "X");
+  set hhhx= concat(repeat("H", 64), "X");
+  set iiix= concat(repeat("I", 64), "X");
+  set jjjx= concat(repeat("J", 64), "X");
+  set kkkx= concat(repeat("K", 64), "X");
+  set lllx= concat(repeat("1", 100),
+                   repeat("2", 20),
+                   repeat("8", 8),
+                   "X");
+
+  SIGNAL warn SET
+    CLASS_ORIGIN = aaax,
+    SUBCLASS_ORIGIN = bbbx,
+    CONSTRAINT_CATALOG = cccx,
+    CONSTRAINT_SCHEMA = dddx,
+    CONSTRAINT_NAME = eeex,
+    CATALOG_NAME = fffx,
+    SCHEMA_NAME = gggx,
+    TABLE_NAME = hhhx,
+    COLUMN_NAME = iiix,
+    CURSOR_NAME = jjjx,
+    MESSAGE_TEXT = lllx,
+    MYSQL_ERRNO = 10000;
+end $$
+
+#NOTE: the warning text for ER_TRUNCATED_WRONG_VALUE contains
+# value: '%-.128s', so the warning printed truncates the value too,
+# which affects MESSAGE_TEXT (the X is missing)
+
+#NOTE: ER_TRUNCATED_WRONG_VALUE is raised as an error for DECIMAL,
+# it's an existing bug: Bug#36457
+call test_signal() $$
+drop procedure test_signal $$
+
+# Test that HANDLER can catch conditions raised by SIGNAL
+
+create procedure test_signal()
+begin
+  DECLARE warn CONDITION FOR SQLSTATE "01234";
+  DECLARE CONTINUE HANDLER for SQLSTATE "01234"
+  begin
+    select "Caught by SQLSTATE";
+  end;
+
+  SIGNAL warn SET
+    MESSAGE_TEXT = "Raising a warning",
+    MYSQL_ERRNO = 1012;
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE warn CONDITION FOR SQLSTATE "01234";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "Caught by number";
+  end;
+
+  SIGNAL warn SET
+    MESSAGE_TEXT = "Raising a warning",
+    MYSQL_ERRNO = 1012;
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE warn CONDITION FOR SQLSTATE "01234";
+  DECLARE CONTINUE HANDLER for SQLWARNING
+  begin
+    select "Caught by SQLWARNING";
+  end;
+
+  SIGNAL warn SET
+    MESSAGE_TEXT = "Raising a warning",
+    MYSQL_ERRNO = 1012;
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE not_found CONDITION FOR SQLSTATE "02ABC";
+  DECLARE CONTINUE HANDLER for SQLSTATE "02ABC"
+  begin
+    select "Caught by SQLSTATE";
+  end;
+
+  SIGNAL not_found SET
+    MESSAGE_TEXT = "Raising a not found",
+    MYSQL_ERRNO = 1012;
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE not_found CONDITION FOR SQLSTATE "02ABC";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "Caught by number";
+  end;
+
+  SIGNAL not_found SET
+    MESSAGE_TEXT = "Raising a not found",
+    MYSQL_ERRNO = 1012;
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE not_found CONDITION FOR SQLSTATE "02ABC";
+  DECLARE CONTINUE HANDLER for NOT FOUND
+  begin
+    select "Caught by NOT FOUND";
+  end;
+
+  SIGNAL not_found SET
+    MESSAGE_TEXT = "Raising a not found",
+    MYSQL_ERRNO = 1012;
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE "55555";
+  DECLARE CONTINUE HANDLER for SQLSTATE "55555"
+  begin
+    select "Caught by SQLSTATE";
+  end;
+
+  SIGNAL error SET
+    MESSAGE_TEXT = "Raising an error",
+    MYSQL_ERRNO = 1012;
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE "55555";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "Caught by number";
+  end;
+
+  SIGNAL error SET
+    MESSAGE_TEXT = "Raising an error",
+    MYSQL_ERRNO = 1012;
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE "55555";
+  DECLARE CONTINUE HANDLER for SQLEXCEPTION
+  begin
+    select "Caught by SQLEXCEPTION";
+  end;
+
+  SIGNAL error SET
+    MESSAGE_TEXT = "Raising an error",
+    MYSQL_ERRNO = 1012;
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+# Test where SIGNAL can be used
+
+create function test_signal_func() returns integer
+begin
+  DECLARE warn CONDITION FOR SQLSTATE "01XXX";
+
+  SIGNAL warn SET
+    MESSAGE_TEXT = "This function SIGNAL a warning",
+    MYSQL_ERRNO = 1012;
+
+  return 5;
+end $$
+
+select test_signal_func() $$
+drop function test_signal_func $$
+
+create function test_signal_func() returns integer
+begin
+  DECLARE not_found CONDITION FOR SQLSTATE "02XXX";
+
+  SIGNAL not_found SET
+    MESSAGE_TEXT = "This function SIGNAL not found",
+    MYSQL_ERRNO = 1012;
+
+  return 5;
+end $$
+
+--error 1012
+select test_signal_func() $$
+drop function test_signal_func $$
+
+create function test_signal_func() returns integer
+begin
+  DECLARE error CONDITION FOR SQLSTATE "50000";
+
+  SIGNAL error SET
+    MESSAGE_TEXT = "This function SIGNAL an error",
+    MYSQL_ERRNO = 1012;
+
+  return 5;
+end $$
+
+--error 1012
+select test_signal_func() $$
+drop function test_signal_func $$
+
+--disable_warnings
+drop table if exists t1 $$
+--enable_warnings
+
+create table t1 (a integer) $$
+
+create trigger t1_ai after insert on t1 for each row
+begin
+  DECLARE msg VARCHAR(128);
+  DECLARE warn CONDITION FOR SQLSTATE "01XXX";
+
+  set msg= concat("This trigger SIGNAL a warning, a=", NEW.a);
+  SIGNAL warn SET
+    MESSAGE_TEXT = msg,
+    MYSQL_ERRNO = 1012;
+end $$
+
+insert into t1 values (1), (2) $$
+ 
+drop trigger t1_ai $$
+
+create trigger t1_ai after insert on t1 for each row
+begin
+  DECLARE msg VARCHAR(128);
+  DECLARE not_found CONDITION FOR SQLSTATE "02XXX";
+
+  set msg= concat("This trigger SIGNAL a not found, a=", NEW.a);
+  SIGNAL not_found SET
+    MESSAGE_TEXT = msg,
+    MYSQL_ERRNO = 1012;
+end $$
+
+--error 1012
+insert into t1 values (3), (4) $$
+ 
+drop trigger t1_ai $$
+
+create trigger t1_ai after insert on t1 for each row
+begin
+  DECLARE msg VARCHAR(128);
+  DECLARE error CONDITION FOR SQLSTATE "03XXX";
+
+  set msg= concat("This trigger SIGNAL an error, a=", NEW.a);
+  SIGNAL error SET
+    MESSAGE_TEXT = msg,
+    MYSQL_ERRNO = 1012;
+end $$
+
+--error 1012
+insert into t1 values (5), (6) $$
+
+drop table t1 $$
+
+create table t1 (errno integer, msg varchar(128)) $$
+
+create trigger t1_ai after insert on t1 for each row
+begin
+  DECLARE warn CONDITION FOR SQLSTATE "01XXX";
+
+  SIGNAL warn SET
+    MESSAGE_TEXT = NEW.msg,
+    MYSQL_ERRNO = NEW.errno;
+end $$
+
+insert into t1 set errno=1012, msg='Warning message 1 in trigger' $$
+insert into t1 set errno=1013, msg='Warning message 2 in trigger' $$
+
+drop table t1 $$
+
+--disable_warnings
+drop table if exists t1 $$
+drop procedure if exists p1 $$
+drop function if exists f1 $$
+--enable_warnings
+
+create table t1 (s1 int) $$
+insert into t1 values (1) $$
+
+create procedure p1()
+begin
+  declare a int;
+  declare c cursor for select f1() from t1;
+  declare continue handler for sqlstate '03000'
+    select "caught 03000";
+  declare continue handler for 1326
+    select "caught cursor is not open";
+
+  select "Before open";
+  open c;
+  select "Before fetch";
+  fetch c into a;
+  select "Before close";
+  close c;
+end $$
+
+create function f1() returns int
+begin
+  signal sqlstate '03000';
+  return 5;
+end $$
+
+## FIXME : MEMORY plugin warning, valgrind leak, bug#36518
+## call p1() $$
+
+drop table t1 $$
+drop procedure p1 $$
+drop function f1 $$
+
+#########################################################
+# Test the RESIGNAL runtime
+#########################################################
+
+# 6 tests:
+# {Signaled warning, Signaled Not Found, Signaled Error,
+# warning, not found, error} --> RESIGNAL
+
+create procedure test_resignal()
+begin
+  DECLARE warn CONDITION FOR SQLSTATE "01234";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "before RESIGNAL";
+    RESIGNAL;
+    select "after RESIGNAL";
+  end;
+
+  SIGNAL warn SET
+    MESSAGE_TEXT = "Raising a warning",
+    MYSQL_ERRNO = 1012;
+end $$
+
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE not_found CONDITION FOR SQLSTATE "02222";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "before RESIGNAL";
+    RESIGNAL;
+    select "after RESIGNAL";
+  end;
+
+  SIGNAL not_found SET
+    MESSAGE_TEXT = "Raising a not found",
+    MYSQL_ERRNO = 1012;
+end $$
+
+--error 1012
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE "55555";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "before RESIGNAL";
+    RESIGNAL;
+    select "after RESIGNAL";
+  end;
+
+  SIGNAL error SET
+    MESSAGE_TEXT = "Raising an error",
+    MYSQL_ERRNO = 1012;
+end $$
+
+--error 1012
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE CONTINUE HANDLER for sqlwarning
+  begin
+    select "before RESIGNAL";
+    RESIGNAL;
+    select "after RESIGNAL";
+  end;
+
+  insert into t_warn set a= 9999999999999999;
+end $$
+
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE x integer;
+  DECLARE c cursor for select * from t_cursor;
+  DECLARE CONTINUE HANDLER for not found
+  begin
+    select "before RESIGNAL";
+    RESIGNAL;
+    select "after RESIGNAL";
+  end;
+
+  open c;
+  fetch c into x;
+  close c;
+end $$
+
+--error ER_SP_FETCH_NO_DATA
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE CONTINUE HANDLER for sqlexception
+  begin
+    select "before RESIGNAL";
+    RESIGNAL;
+    select "after RESIGNAL";
+  end;
+
+  drop table no_such_table;
+end $$
+
+--error ER_BAD_TABLE_ERROR
+call test_resignal() $$
+drop procedure test_resignal $$
+
+# 6 tests:
+# {Signaled warning, Signaled Not Found, Signaled Error,
+# warning, not found, error} --> RESIGNAL SET ...
+
+create procedure test_resignal()
+begin
+  DECLARE warn CONDITION FOR SQLSTATE "01234";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SET
+      MESSAGE_TEXT = "RESIGNAL of a warning",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  SIGNAL warn SET
+    MESSAGE_TEXT = "Raising a warning",
+    MYSQL_ERRNO = 1012;
+end $$
+
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE not_found CONDITION FOR SQLSTATE "02111";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SET
+      MESSAGE_TEXT = "RESIGNAL of a not found",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  SIGNAL not_found SET
+    MESSAGE_TEXT = "Raising a not found",
+    MYSQL_ERRNO = 1012;
+end $$
+
+--error 5555
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE "33333";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SET
+      MESSAGE_TEXT = "RESIGNAL of an error",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  SIGNAL error SET
+    MESSAGE_TEXT = "Raising an error",
+    MYSQL_ERRNO = 1012;
+end $$
+
+--error 5555
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE CONTINUE HANDLER for sqlwarning
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SET
+      MESSAGE_TEXT = "RESIGNAL of a warning",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  insert into t_warn set a= 9999999999999999;
+end $$
+
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE x integer;
+  DECLARE c cursor for select * from t_cursor;
+  DECLARE CONTINUE HANDLER for not found
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SET
+      MESSAGE_TEXT = "RESIGNAL of not found",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  open c;
+  fetch c into x;
+  close c;
+end $$
+
+--error 5555
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE CONTINUE HANDLER for sqlexception
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SET
+      MESSAGE_TEXT = "RESIGNAL of an error",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  drop table no_such_table;
+end $$
+
+--error 5555
+call test_resignal() $$
+drop procedure test_resignal $$
+
+#########################################################
+
+# 3 tests:
+# {Signaled warning}
+# --> RESIGNAL SQLSTATE {warning, not found, error} SET ...
+
+create procedure test_resignal()
+begin
+  DECLARE warn CONDITION FOR SQLSTATE "01111";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "01222" SET
+      MESSAGE_TEXT = "RESIGNAL to warning",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  SIGNAL warn SET
+    MESSAGE_TEXT = "Raising a warning",
+    MYSQL_ERRNO = 1012;
+end $$
+
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE warn CONDITION FOR SQLSTATE "01111";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "02222" SET
+      MESSAGE_TEXT = "RESIGNAL to not found",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  SIGNAL warn SET
+    MESSAGE_TEXT = "Raising a warning",
+    MYSQL_ERRNO = 1012;
+end $$
+
+--error 5555
+call test_resignal() $$
+show warnings $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE warn CONDITION FOR SQLSTATE "01111";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "33333" SET
+      MESSAGE_TEXT = "RESIGNAL to error",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  SIGNAL warn SET
+    MESSAGE_TEXT = "Raising a warning",
+    MYSQL_ERRNO = 1012;
+end $$
+
+--error 5555
+call test_resignal() $$
+show warnings $$
+drop procedure test_resignal $$
+
+# 3 tests:
+# {Signaled not found}
+# --> RESIGNAL SQLSTATE {warning, not found, error} SET ...
+
+create procedure test_resignal()
+begin
+  DECLARE not_found CONDITION FOR SQLSTATE "02ABC";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "01222" SET
+      MESSAGE_TEXT = "RESIGNAL to warning",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  SIGNAL not_found SET
+    MESSAGE_TEXT = "Raising a not found",
+    MYSQL_ERRNO = 1012;
+end $$
+
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE not_found CONDITION FOR SQLSTATE "02ABC";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "02222" SET
+      MESSAGE_TEXT = "RESIGNAL to not found",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  SIGNAL not_found SET
+    MESSAGE_TEXT = "Raising a not found",
+    MYSQL_ERRNO = 1012;
+end $$
+
+--error 5555
+call test_resignal() $$
+show warnings $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE not_found CONDITION FOR SQLSTATE "02ABC";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "33333" SET
+      MESSAGE_TEXT = "RESIGNAL to error",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  SIGNAL not_found SET
+    MESSAGE_TEXT = "Raising a not found",
+    MYSQL_ERRNO = 1012;
+end $$
+
+--error 5555
+call test_resignal() $$
+show warnings $$
+drop procedure test_resignal $$
+
+# 3 tests:
+# {Signaled error}
+# --> RESIGNAL SQLSTATE {warning, not found, error} SET ...
+
+create procedure test_resignal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE "AAAAA";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "01222" SET
+      MESSAGE_TEXT = "RESIGNAL to warning",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  SIGNAL error SET
+    MESSAGE_TEXT = "Raising an error",
+    MYSQL_ERRNO = 1012;
+end $$
+
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE "AAAAA";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "02222" SET
+      MESSAGE_TEXT = "RESIGNAL to not found",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  SIGNAL error SET
+    MESSAGE_TEXT = "Raising an error",
+    MYSQL_ERRNO = 1012;
+end $$
+
+--error 5555
+call test_resignal() $$
+show warnings $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE error CONDITION FOR SQLSTATE "AAAAA";
+  DECLARE CONTINUE HANDLER for 1012
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "33333" SET
+      MESSAGE_TEXT = "RESIGNAL to error",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  SIGNAL error SET
+    MESSAGE_TEXT = "Raising an error",
+    MYSQL_ERRNO = 1012;
+end $$
+
+--error 5555
+call test_resignal() $$
+show warnings $$
+drop procedure test_resignal $$
+
+# 3 tests:
+# {warning}
+# --> RESIGNAL SQLSTATE {warning, not found, error} SET ...
+
+create procedure test_resignal()
+begin
+  DECLARE CONTINUE HANDLER for sqlwarning
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "01111" SET
+      MESSAGE_TEXT = "RESIGNAL to a warning",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  insert into t_warn set a= 9999999999999999;
+end $$
+
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE CONTINUE HANDLER for sqlwarning
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "02444" SET
+      MESSAGE_TEXT = "RESIGNAL to a not found",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  insert into t_warn set a= 9999999999999999;
+end $$
+
+--error 5555
+call test_resignal() $$
+show warnings $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE CONTINUE HANDLER for sqlwarning
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "44444" SET
+      MESSAGE_TEXT = "RESIGNAL to an error",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  insert into t_warn set a= 9999999999999999;
+end $$
+
+--error 5555
+call test_resignal() $$
+show warnings $$
+drop procedure test_resignal $$
+
+# 3 tests:
+# {not found}
+# --> RESIGNAL SQLSTATE {warning, not found, error} SET ...
+
+create procedure test_resignal()
+begin
+  DECLARE x integer;
+  DECLARE c cursor for select * from t_cursor;
+  DECLARE CONTINUE HANDLER for not found
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "01111" SET
+      MESSAGE_TEXT = "RESIGNAL to a warning",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  open c;
+  fetch c into x;
+  close c;
+end $$
+
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE x integer;
+  DECLARE c cursor for select * from t_cursor;
+  DECLARE CONTINUE HANDLER for not found
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "02444" SET
+      MESSAGE_TEXT = "RESIGNAL to a not found",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  open c;
+  fetch c into x;
+  close c;
+end $$
+
+--error 5555
+call test_resignal() $$
+show warnings $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE x integer;
+  DECLARE c cursor for select * from t_cursor;
+  DECLARE CONTINUE HANDLER for not found
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "44444" SET
+      MESSAGE_TEXT = "RESIGNAL to an error",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  open c;
+  fetch c into x;
+  close c;
+end $$
+
+--error 5555
+call test_resignal() $$
+show warnings $$
+drop procedure test_resignal $$
+
+# 3 tests:
+# {error}
+# --> RESIGNAL SQLSTATE {warning, not found, error} SET ...
+
+create procedure test_resignal()
+begin
+  DECLARE CONTINUE HANDLER for sqlexception
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "01111" SET
+      MESSAGE_TEXT = "RESIGNAL to a warning",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  drop table no_such_table;
+end $$
+
+call test_resignal() $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE CONTINUE HANDLER for sqlexception
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "02444" SET
+      MESSAGE_TEXT = "RESIGNAL to a not found",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  drop table no_such_table;
+end $$
+
+--error 5555
+call test_resignal() $$
+show warnings $$
+drop procedure test_resignal $$
+
+create procedure test_resignal()
+begin
+  DECLARE CONTINUE HANDLER for sqlexception
+  begin
+    select "before RESIGNAL";
+    RESIGNAL SQLSTATE "44444" SET
+      MESSAGE_TEXT = "RESIGNAL to an error",
+      MYSQL_ERRNO = 5555 ;
+    select "after RESIGNAL";
+  end;
+
+  drop table no_such_table;
+end $$
+
+--error 5555
+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 MYSQL_ERRNO = 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 SQLSTATE '42000';
+  DECLARE EXIT HANDLER FOR x
+  BEGIN
+    SELECT '2';
+    RESIGNAL x SET MYSQL_ERRNO = 9999;
+  END;
+
+  BEGIN
+    DECLARE EXIT HANDLER FOR x
+    BEGIN
+      SELECT '1';
+      RESIGNAL x SET
+        SCHEMA_NAME = 'test',
+        MYSQL_ERRNO= 1231;
+    END;
+    /* Raises ER_WRONG_VALUE_FOR_VAR : 1231, SQLSTATE 42000 */
+    SET @@sql_mode=NULL;
+  END;
+END
+$$
+
+CREATE PROCEDURE peter_p2 ()
+BEGIN
+  DECLARE x CONDITION for SQLSTATE '42000';
+  DECLARE EXIT HANDLER FOR x
+  BEGIN
+    SELECT '3';
+    RESIGNAL x SET
+      MESSAGE_TEXT = 'Hi, I am a useless error message',
+      MYSQL_ERRNO = 9999;
+  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.
+#
+--error 9999
+CALL peter_p2() $$
+show warnings $$
+
+drop procedure peter_p1 $$
+drop procedure peter_p2 $$
+
+#
+# Test the value of MESSAGE_TEXT in RESIGNAL when no SET MESSAGE_TEXT clause
+# is provided (the expected result is the text from the SIGNALed condition)
+#
+
+drop procedure if exists peter_p3 $$
+
+create procedure peter_p3()
+begin
+  declare continue handler for sqlexception
+    resignal sqlstate '99002' set mysql_errno = 2;
+
+  signal sqlstate '99001' set mysql_errno = 1, message_text = "Original";
+end $$
+
+--error 2
+call peter_p3() $$
+
+# Expecting 2 conditions, both with the text "Original"
+show warnings $$
+
+drop procedure peter_p3 $$
+
+delimiter ;$$
+
+drop table t_warn;
+drop table t_cursor;
+

=== added file 'mysql-test/t/signal_code.test'
--- a/mysql-test/t/signal_code.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/signal_code.test	2008-08-27 22:14:03 +0000
@@ -0,0 +1,57 @@
+# 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
+
+# Tests for SIGNAL and RESIGNAL
+
+-- source include/have_debug.inc
+
+use test;
+
+--disable_warnings
+drop procedure if exists signal_proc;
+drop function if exists signal_func;
+--enable_warnings
+
+delimiter $$;
+
+create procedure signal_proc()
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+
+  SIGNAL foo;
+  SIGNAL foo SET MESSAGE_TEXT = "This is an error message";
+  RESIGNAL foo;
+  RESIGNAL foo SET MESSAGE_TEXT = "This is an error message";
+end $$
+
+create function signal_func() returns int
+begin
+  DECLARE foo CONDITION FOR SQLSTATE '12345';
+
+  SIGNAL foo;
+  SIGNAL foo SET MESSAGE_TEXT = "This is an error message";
+  RESIGNAL foo;
+  RESIGNAL foo SET MESSAGE_TEXT = "This is an error message";
+  return 0;
+end $$
+
+delimiter ;$$
+
+show procedure code signal_proc;
+drop procedure signal_proc;
+
+show function code signal_func;
+drop function signal_func;
+

=== added file 'mysql-test/t/signal_demo1.test'
--- a/mysql-test/t/signal_demo1.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/signal_demo1.test	2008-08-27 22:14:03 +0000
@@ -0,0 +1,333 @@
+# 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 SIGNAL can be used to enforce integrity constraints.
+#
+
+# Naming:
+# - PO: Purchase Order
+# - AB: Address Book
+# - IN: Inventory
+
+# Simplified schema:
+#
+# Relation 1:
+# PO_ORDER (PK: po_id) 1:1 <---> 0:N (FK: po_id) PO_ORDER_LINE
+#
+# Relation 2:
+# IN_INVENTORY (PK: item_id) 1:1 <---> 0:N (FK: item_id) PO_ORDER_LINE
+#
+# Relation 3:
+#                               +--> 0:1 (PK: person_id) AB_PHYSICAL_PERSON
+# PO_ORDER (FK: cust_id) 1:1 <--|
+#                               +--> 0:1 (PK: company_id) AB_MORAL_PERSON
+# This is an 'arc' relationship :)
+#
+
+
+--disable_warnings
+drop database if exists demo;
+--enable_warnings
+
+create database demo;
+
+use demo;
+
+create table ab_physical_person (
+  person_id integer,
+  first_name VARCHAR(50),
+  middle_initial CHAR,
+  last_name VARCHAR(50),
+  primary key (person_id));
+
+create table ab_moral_person (
+  company_id integer,
+  name VARCHAR(100),
+  primary key (company_id));
+
+create table in_inventory (
+  item_id integer,
+  descr VARCHAR(50),
+  stock integer,
+  primary key (item_id));
+
+create table po_order (
+  po_id integer auto_increment,
+  cust_type char, /* arc relationship, see cust_id */
+  cust_id integer, /* FK to ab_physical_person *OR* ab_moral_person */
+  primary key (po_id));
+
+create table po_order_line (
+  po_id integer, /* FK to po_order.po_id */
+  line_no integer,
+  item_id integer, /* FK to in_inventory.item_id */
+  qty integer);
+
+delimiter $$;
+
+#
+# Schema integrity enforcement
+#
+
+create procedure check_pk_person(in person_type char, in id integer)
+begin
+  declare x integer;
+  declare msg varchar(128);
+
+  /*
+    Test integrity constraints for an 'arc' relationship.
+    Based on 'person_type', 'id' points to either a
+    physical person, or a moral person.
+  */
+  case person_type
+    when 'P' then
+    begin
+      select count(person_id) from ab_physical_person
+        where ab_physical_person.person_id = id
+        into x;
+
+      if (x != 1)
+      then
+        set msg= concat('No such physical person, PK:', id);
+        SIGNAL SQLSTATE '45000' SET
+          MESSAGE_TEXT = msg,
+          MYSQL_ERRNO = 10000;
+      end if;
+    end;
+    
+    when 'M' then
+    begin
+      select count(company_id) from ab_moral_person
+        where ab_moral_person.company_id = id
+        into x;
+
+      if (x != 1)
+      then
+        set msg= concat('No such moral person, PK:', id);
+        SIGNAL SQLSTATE '45000' SET
+          MESSAGE_TEXT = msg,
+          MYSQL_ERRNO = 10000;
+      end if;
+    end;
+
+    else
+    begin
+      set msg= concat('No such person type:', person_type);
+      SIGNAL SQLSTATE '45000' SET
+        MESSAGE_TEXT = msg,
+        MYSQL_ERRNO = 20000;
+    end;
+  end case;
+end
+$$
+
+create procedure check_pk_inventory(in id integer)
+begin
+  declare x integer;
+  declare msg varchar(128);
+
+  select count(item_id) from in_inventory
+    where in_inventory.item_id = id
+    into x;
+
+  if (x != 1)
+  then
+    set msg= concat('Failed integrity constraint, table in_inventory, PK:',
+                    id);
+    SIGNAL SQLSTATE '45000' SET
+      MESSAGE_TEXT = msg,
+      MYSQL_ERRNO = 10000;
+  end if;
+end
+$$
+
+create procedure check_pk_order(in id integer)
+begin
+  declare x integer;
+  declare msg varchar(128);
+
+  select count(po_id) from po_order
+    where po_order.po_id = id
+    into x;
+
+  if (x != 1)
+  then
+    set msg= concat('Failed integrity constraint, table po_order, PK:', id);
+    SIGNAL SQLSTATE '45000' SET
+      MESSAGE_TEXT = msg,
+      MYSQL_ERRNO = 10000;
+  end if;
+end
+$$
+
+create trigger po_order_bi before insert on po_order
+for each row
+begin
+  call check_pk_person(NEW.cust_type, NEW.cust_id);
+end
+$$
+
+create trigger po_order_bu before update on po_order
+for each row
+begin
+  call check_pk_person(NEW.cust_type, NEW.cust_id);
+end
+$$
+
+create trigger po_order_line_bi before insert on po_order_line
+for each row
+begin
+  call check_pk_order(NEW.po_id);
+  call check_pk_inventory(NEW.item_id);
+end
+$$
+
+create trigger po_order_line_bu before update on po_order_line
+for each row
+begin
+  call check_pk_order(NEW.po_id);
+  call check_pk_inventory(NEW.item_id);
+end
+$$
+
+#
+# Application helpers
+#
+
+create procedure po_create_order(
+  in p_cust_type char,
+  in p_cust_id integer,
+  out id integer)
+begin
+  insert into po_order set cust_type = p_cust_type, cust_id = p_cust_id;
+  set id = last_insert_id();
+end
+$$
+
+create procedure po_add_order_line(
+  in po integer,
+  in line integer,
+  in item integer,
+  in q integer)
+begin
+  insert into po_order_line set
+    po_id = po, line_no = line, item_id = item, qty = q;
+end
+$$
+
+delimiter ;$$
+
+select "Create sample data";
+
+insert into ab_physical_person values
+  ( 1, "John", "A", "Doe"),
+  ( 2, "Marry", "B", "Smith")
+;
+
+insert into ab_moral_person values
+  ( 3, "ACME real estate, INC"),
+  ( 4, "Local school")
+;
+
+insert into in_inventory values
+  ( 100, "Table, dinner", 5),
+  ( 101, "Chair", 20),
+  ( 200, "Table, coffee", 3),
+  ( 300, "School table", 25),
+  ( 301, "School chairs", 50)
+;
+
+select * from ab_physical_person order by person_id;
+select * from ab_moral_person order by company_id;
+select * from in_inventory order by item_id;
+
+select "Entering an order !";
+
+set @my_po = 0;
+
+/* John Doe wants 1 table and 4 chairs */
+call po_create_order("P", 1, @my_po);
+
+call po_add_order_line (@my_po, 1, 100, 1);
+call po_add_order_line (@my_po, 2, 101, 4);
+
+/* Marry Smith wants a coffee table */
+call po_create_order("P", 2, @my_po);
+
+call po_add_order_line (@my_po, 1, 200, 1);
+
+select "Entering bad data in an order";
+
+# There is no item 999 in in_inventory
+--error 10000
+call po_add_order_line (@my_po, 1, 999, 1);
+
+select "Entering bad data in an unknown order";
+
+# There is no order 99 in po_order
+--error 10000
+call po_add_order_line (99, 1, 100, 1);
+
+select "Entering an order for an unknown company";
+
+# There is no moral person of id 7
+--error 10000
+call po_create_order("M", 7, @my_po);
+
+select "Entering an order for an unknown person type";
+
+# There is no person of type X
+--error 20000
+call po_create_order("X", 1, @my_po);
+
+/* The local school wants 10 class tables and 20 chairs */
+call po_create_order("M", 4, @my_po);
+
+call po_add_order_line (@my_po, 1, 300, 10);
+call po_add_order_line (@my_po, 2, 301, 20);
+
+# Raw data
+select * from po_order;
+select * from po_order_line;
+
+# Creative reporting ...
+
+select po_id as "PO#",
+  ( case cust_type
+  when "P" then concat (pp.first_name,
+                   " ",
+                   pp.middle_initial,
+                   " ",
+                   pp.last_name)
+  when "M" then mp.name
+  end ) as "Sold to"
+  from po_order po
+  left join ab_physical_person pp on po.cust_id = pp.person_id
+  left join ab_moral_person mp on po.cust_id = company_id
+;
+
+select po_id as "PO#",
+  ol.line_no as "Line",
+  ol.item_id as "Item",
+  inv.descr as "Description",
+  ol.qty as "Quantity"
+  from po_order_line ol, in_inventory inv
+  where inv.item_id = ol.item_id
+  order by ol.item_id, ol.line_no;
+
+drop database demo;
+
+

=== added file 'mysql-test/t/signal_demo2.test'
--- a/mysql-test/t/signal_demo2.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/signal_demo2.test	2008-08-27 22:14:03 +0000
@@ -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;
+

=== added file 'mysql-test/t/signal_demo3.test'
--- a/mysql-test/t/signal_demo3.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/signal_demo3.test	2008-08-27 22:14:03 +0000
@@ -0,0 +1,159 @@
+# 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 print a stack trace
+#
+
+# Save defaults
+
+SET @start_global_value = @@global.max_error_count;
+SELECT @start_global_value;
+SET @start_session_value = @@session.max_error_count;
+SELECT @start_session_value;
+
+--disable_warnings
+drop database if exists demo;
+--enable_warnings
+
+create database demo;
+
+use demo;
+
+delimiter $$;
+
+create procedure proc_1()
+begin
+  declare exit handler for sqlexception
+    resignal sqlstate '45000' set message_text='Oops in proc_1';
+
+  call proc_2();
+end
+$$
+
+create procedure proc_2()
+begin
+  declare exit handler for sqlexception
+    resignal sqlstate '45000' set message_text='Oops in proc_2';
+
+  call proc_3();
+end
+$$
+
+create procedure proc_3()
+begin
+  declare exit handler for sqlexception
+    resignal sqlstate '45000' set message_text='Oops in proc_3';
+
+  call proc_4();
+end
+$$
+
+create procedure proc_4()
+begin
+  declare exit handler for sqlexception
+    resignal sqlstate '45000' set message_text='Oops in proc_4';
+
+  call proc_5();
+end
+$$
+
+create procedure proc_5()
+begin
+  declare exit handler for sqlexception
+    resignal sqlstate '45000' set message_text='Oops in proc_5';
+
+  call proc_6();
+end
+$$
+
+create procedure proc_6()
+begin
+  declare exit handler for sqlexception
+    resignal sqlstate '45000' set message_text='Oops in proc_6';
+
+  call proc_7();
+end
+$$
+
+create procedure proc_7()
+begin
+  declare exit handler for sqlexception
+    resignal sqlstate '45000' set message_text='Oops in proc_7';
+
+  call proc_8();
+end
+$$
+
+create procedure proc_8()
+begin
+  declare exit handler for sqlexception
+    resignal sqlstate '45000' set message_text='Oops in proc_8';
+
+  call proc_9();
+end
+$$
+
+create procedure proc_9()
+begin
+  declare exit handler for sqlexception
+    resignal sqlstate '45000' set message_text='Oops in proc_9';
+
+  ## Do something that fails, to see how errors are reported
+  drop table oops_it_is_not_here;
+end
+$$
+
+delimiter ;$$
+
+-- error ER_SIGNAL_EXCEPTION
+call proc_1();
+
+# This is the interesting part:
+# the complete call stack from the origin of failure (proc_9)
+# to the top level caller (proc_1) is available ...
+
+show warnings;
+
+SET @@session.max_error_count = 5;
+SELECT @@session.max_error_count;
+
+-- error ER_SIGNAL_EXCEPTION
+call proc_1();
+show warnings;
+
+SET @@session.max_error_count = 7;
+SELECT @@session.max_error_count;
+
+-- error ER_SIGNAL_EXCEPTION
+call proc_1();
+show warnings;
+
+SET @@session.max_error_count = 9;
+SELECT @@session.max_error_count;
+
+-- error ER_SIGNAL_EXCEPTION
+call proc_1();
+show warnings;
+
+drop database demo;
+
+# Restore defaults
+
+SET @@global.max_error_count = @start_global_value;
+SELECT @@global.max_error_count;
+SET @@session.max_error_count = @start_session_value;
+SELECT @@session.max_error_count;
+

=== added file 'mysql-test/t/signal_sqlmode.test'
--- a/mysql-test/t/signal_sqlmode.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/signal_sqlmode.test	2008-08-27 22:14:03 +0000
@@ -0,0 +1,123 @@
+# 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
+
+# Tests for SIGNAL, RESIGNAL and GET DIAGNOSTICS
+
+SET @save_sql_mode=@@sql_mode;
+
+SET sql_mode='';
+
+--disable_warnings
+drop procedure if exists p;
+drop procedure if exists p2;
+drop procedure if exists p3;
+--enable_warnings
+
+delimiter $$;
+
+create procedure p()
+begin
+  declare utf8_var VARCHAR(128) CHARACTER SET UTF8;
+  set utf8_var = concat(repeat('A', 128), 'X');
+  select length(utf8_var), utf8_var;
+end
+$$
+
+create procedure p2()
+begin
+  declare msg VARCHAR(129) CHARACTER SET UTF8;
+  set msg = concat(repeat('A', 128), 'X');
+  select length(msg), msg;
+
+  signal sqlstate '55555' set message_text = msg;
+end
+$$
+
+create procedure p3()
+begin
+  declare name VARCHAR(65) CHARACTER SET UTF8;
+  set name = concat(repeat('A', 64), 'X');
+  select length(name), name;
+
+  signal sqlstate '55555' set
+    message_text = 'Message',
+    table_name = name;
+end
+$$
+delimiter ;$$
+
+call p;
+
+--error ER_SIGNAL_EXCEPTION
+call p2;
+
+--error ER_SIGNAL_EXCEPTION
+call p3;
+
+drop procedure p;
+drop procedure p2;
+drop procedure p3;
+
+SET sql_mode='STRICT_ALL_TABLES';
+
+delimiter $$;
+
+create procedure p()
+begin
+  declare utf8_var VARCHAR(128) CHARACTER SET UTF8;
+  set utf8_var = concat(repeat('A', 128), 'X');
+  select length(utf8_var), utf8_var;
+end
+$$
+
+create procedure p2()
+begin
+  declare msg VARCHAR(129) CHARACTER SET UTF8;
+  set msg = concat(repeat('A', 128), 'X');
+  select length(msg), msg;
+
+  signal sqlstate '55555' set message_text = msg;
+end
+$$
+
+create procedure p3()
+begin
+  declare name VARCHAR(65) CHARACTER SET UTF8;
+  set name = concat(repeat('A', 64), 'X');
+  select length(name), name;
+
+  signal sqlstate '55555' set
+    message_text = 'Message',
+    table_name = name;
+end
+$$
+
+delimiter ;$$
+
+--error ER_DATA_TOO_LONG
+call p;
+
+--error ER_COND_ITEM_TOO_LONG
+call p2;
+
+--error ER_COND_ITEM_TOO_LONG
+call p3;
+
+drop procedure p;
+drop procedure p2;
+drop procedure p3;
+
+SET @@sql_mode=@save_sql_mode;
+

=== added file 'mysql-test/t/signal_utf32.test'
--- a/mysql-test/t/signal_utf32.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/signal_utf32.test	2008-08-27 22:14:03 +0000
@@ -0,0 +1,63 @@
+# 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
+
+# Tests for SIGNAL, RESIGNAL and GET DIAGNOSTICS
+
+--source include/have_utf32.inc
+
+--disable_warnings
+drop procedure if exists test_signal;
+--enable_warnings
+
+delimiter $$;
+
+create procedure test_signal()
+begin
+  DECLARE something CONDITION FOR SQLSTATE "01000";
+  SIGNAL something SET MESSAGE_TEXT =
+    _utf32 'a';
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  DECLARE something CONDITION FOR SQLSTATE "01000";
+  SIGNAL something SET MESSAGE_TEXT =
+    _utf32 X'00000048000000450000004C0000004C0000004F';
+end $$
+
+call test_signal() $$
+drop procedure test_signal $$
+
+create procedure test_signal()
+begin
+  declare continue handler for sqlexception
+  begin
+    declare msg varchar(128);
+    set msg= repeat(_utf32 0x000100cc, 128);
+    resignal set message_text = msg;
+  end;
+
+  signal sqlstate '77777';
+end $$
+
+--error ER_SIGNAL_EXCEPTION
+call test_signal() $$
+drop procedure test_signal $$
+
+delimiter ;$$
+

=== modified file 'sql/CMakeLists.txt'
--- a/sql/CMakeLists.txt	2008-07-09 07:12:43 +0000
+++ b/sql/CMakeLists.txt	2008-08-27 22:14:03 +0000
@@ -78,6 +78,7 @@ ADD_EXECUTABLE(mysqld
                sql_connect.cc scheduler.cc 
                ddl_blocker.cc si_objects.cc
                sql_profile.cc event_parse_data.cc mdl.cc
+               sql_signal.cc sql_fixstring.cc
                ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
                ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
                ${PROJECT_SOURCE_DIR}/include/mysqld_error.h

=== modified file 'sql/Makefile.am'
--- a/sql/Makefile.am	2008-07-09 07:12:43 +0000
+++ b/sql/Makefile.am	2008-08-27 22:14:03 +0000
@@ -62,7 +62,7 @@ noinst_HEADERS =	item.h item_func.h item
 			item_create.h item_subselect.h item_row.h \
 			mysql_priv.h item_geofunc.h sql_bitmap.h \
 			procedure.h sql_class.h sql_lex.h sql_list.h \
-			sql_map.h sql_string.h unireg.h \
+			sql_map.h sql_string.h sql_fixstring.h unireg.h \
 			sql_error.h field.h handler.h mysqld_suffix.h \
 			sql_profile.h \
 			ha_ndbcluster.h ha_ndbcluster_cond.h \
@@ -89,7 +89,8 @@ noinst_HEADERS =	item.h item_func.h item
 			sql_partition.h partition_info.h partition_element.h \
 			probes.h sql_audit.h \
 			contributors.h sql_servers.h ddl_blocker.h \
-			si_objects.h sql_plist.h mdl.h
+			si_objects.h sql_plist.h mdl.h \
+			sql_signal.h sql_fixstring.h
 
 mysqld_SOURCES =	sql_lex.cc sql_handler.cc sql_partition.cc \
 			item.cc item_sum.cc item_buff.cc item_func.cc \
@@ -136,7 +137,7 @@ mysqld_SOURCES =	sql_lex.cc sql_handler.
 			sql_builtin.cc sql_tablespace.cc partition_info.cc \
 			sql_servers.cc sql_audit.cc sha2.cc \
 			ddl_blocker.cc si_objects.cc event_parse_data.cc \
-			mdl.cc
+			mdl.cc sql_signal.cc sql_fixstring.cc
 
 if HAVE_DTRACE
   mysqld_SOURCES += probes.d

=== modified file 'sql/backup/logger.cc'
--- a/sql/backup/logger.cc	2008-03-21 09:57:45 +0000
+++ b/sql/backup/logger.cc	2008-08-27 22:14:03 +0000
@@ -50,7 +50,7 @@ int Logger::write_message(log_level::val
        errors.push_front(new MYSQL_ERROR(::current_thd, error_code,
                                          MYSQL_ERROR::WARN_LEVEL_ERROR, msg));
      sql_print_error(out);
-     push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+     push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                          error_code, msg);
      DBUG_PRINT("backup_log",("[ERROR] %s", out));
      

=== modified file 'sql/derror.cc'
--- a/sql/derror.cc	2008-04-09 00:56:49 +0000
+++ b/sql/derror.cc	2008-08-27 22:14:03 +0000
@@ -121,7 +121,7 @@ Please install the latest version of thi
   }
   
   /* TODO: Convert the character set to server system character set */
-  if (!get_charset(head[30],MYF(MY_WME)))
+  if (!(error_message_charset_info= get_charset(head[30],MYF(MY_WME))))
   {
     sql_print_error("Character set #%d is not supported for messagefile '%s'",
                     (int)head[30],name);

=== modified file 'sql/event_scheduler.cc'
--- a/sql/event_scheduler.cc	2008-05-08 16:01:15 +0000
+++ b/sql/event_scheduler.cc	2008-08-27 22:14:03 +0000
@@ -72,9 +72,9 @@ struct scheduler_param {
 void
 Event_worker_thread::print_warnings(THD *thd, Event_job_data *et)
 {
-  MYSQL_ERROR *err;
+  SQL_condition *cond;
   DBUG_ENTER("evex_print_warnings");
-  if (!thd->warn_list.elements)
+  if (!thd->main_da.m_stmt_area.warn_list.elements)
     DBUG_VOID_RETURN;
 
   char msg_buf[10 * STRING_BUFFER_USUAL_SIZE];
@@ -90,17 +90,18 @@ Event_worker_thread::print_warnings(THD 
   prefix.append(et->name.str, et->name.length, system_charset_info);
   prefix.append("] ", 2);
 
-  List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
-  while ((err= it++))
+  List_iterator_fast<SQL_condition> it(thd->main_da.m_stmt_area.warn_list);
+  while ((cond= it++))
   {
     String err_msg(msg_buf, sizeof(msg_buf), system_charset_info);
     /* set it to 0 or we start adding at the end. That's the trick ;) */
     err_msg.length(0);
     err_msg.append(prefix);
-    err_msg.append(err->msg, strlen(err->msg), system_charset_info);
-    DBUG_ASSERT(err->level < 3);
-    (sql_print_message_handlers[err->level])("%*s", err_msg.length(),
-                                              err_msg.c_ptr());
+    err_msg.append(cond->get_message_text(),
+                   cond->get_message_octet_length(), system_charset_info);
+    DBUG_ASSERT(cond->get_level() < 3);
+    (sql_print_message_handlers[cond->get_level()])("%*s", err_msg.length(),
+                                                    err_msg.c_ptr());
   }
   DBUG_VOID_RETURN;
 }

=== modified file 'sql/ha_ndbcluster_binlog.cc'
--- a/sql/ha_ndbcluster_binlog.cc	2008-07-14 12:49:19 +0000
+++ b/sql/ha_ndbcluster_binlog.cc	2008-08-27 22:14:03 +0000
@@ -962,6 +962,20 @@ struct Cluster_schema
   uint32 any_value;
 };
 
+void print_could_not_discover_error(THD *thd, const Cluster_schema *schema)
+{
+  sql_print_error("NDB Binlog: Could not discover table '%s.%s' from "
+                  "binlog schema event '%s' from node %d. "
+                  "my_errno: %d",
+                   schema->db, schema->name, schema->query,
+                  schema->node_id, my_errno);
+  List_iterator_fast<SQL_condition> it(thd->main_da.m_stmt_area.warn_list);
+  SQL_condition *cond;
+  while ((cond= it++))
+    sql_print_warning("NDB Binlog: (%d)%s", cond->get_sql_errno(),
+                      cond->get_message_text());
+}
+
 /*
   Transfer schema table data into corresponding struct
 */
@@ -1894,15 +1908,7 @@ ndb_binlog_thread_handle_schema_event(TH
           }
           else if (ndb_create_table_from_engine(thd, schema->db, schema->name))
           {
-            sql_print_error("NDB Binlog: Could not discover table '%s.%s' from "
-                            "binlog schema event '%s' from node %d. "
-                            "my_errno: %d",
-                            schema->db, schema->name, schema->query,
-                            schema->node_id, my_errno);
-            List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
-            MYSQL_ERROR *err;
-            while ((err= it++))
-              sql_print_warning("NDB Binlog: (%d)%s", err->code, err->msg);
+            print_could_not_discover_error(thd, schema);
           }
           pthread_mutex_unlock(&LOCK_open);
           log_query= 1;
@@ -2255,14 +2261,7 @@ ndb_binlog_thread_handle_schema_event_po
           }
           else if (ndb_create_table_from_engine(thd, schema->db, schema->name))
           {
-            sql_print_error("NDB Binlog: Could not discover table '%s.%s' from "
-                            "binlog schema event '%s' from node %d. my_errno: %d",
-                            schema->db, schema->name, schema->query,
-                            schema->node_id, my_errno);
-            List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
-            MYSQL_ERROR *err;
-            while ((err= it++))
-              sql_print_warning("NDB Binlog: (%d)%s", err->code, err->msg);
+            print_could_not_discover_error(thd, schema);
           }
           pthread_mutex_unlock(&LOCK_open);
         }
@@ -2434,14 +2433,7 @@ ndb_binlog_thread_handle_schema_event_po
           }
           else if (ndb_create_table_from_engine(thd, schema->db, schema->name))
           {
-            sql_print_error("NDB Binlog: Could not discover table '%s.%s' from "
-                            "binlog schema event '%s' from node %d. my_errno: %d",
-                            schema->db, schema->name, schema->query,
-                            schema->node_id, my_errno);
-            List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
-            MYSQL_ERROR *err;
-            while ((err= it++))
-              sql_print_warning("NDB Binlog: (%d)%s", err->code, err->msg);
+            print_could_not_discover_error(thd, schema);
           }
           pthread_mutex_unlock(&LOCK_open);
         }

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	2008-08-16 15:22:47 +0000
+++ b/sql/handler.cc	2008-08-27 22:14:03 +0000
@@ -1854,23 +1854,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;
 }
 

=== modified file 'sql/lex.h'
--- a/sql/lex.h	2008-07-09 07:12:43 +0000
+++ b/sql/lex.h	2008-08-27 22:14:03 +0000
@@ -96,6 +96,7 @@ static SYMBOL symbols[] = {
   { "CASCADE",		SYM(CASCADE)},
   { "CASCADED",         SYM(CASCADED)},
   { "CASE",		SYM(CASE_SYM)},
+  { "CATALOG_NAME",     SYM(CATALOG_NAME_SYM)},
   { "CHAIN",		SYM(CHAIN_SYM)},
   { "CHANGE",		SYM(CHANGE)},
   { "CHANGED",		SYM(CHANGED)},
@@ -105,6 +106,7 @@ static SYMBOL symbols[] = {
   { "CHECK",		SYM(CHECK_SYM)},
   { "CHECKSUM",		SYM(CHECKSUM_SYM)},
   { "CIPHER",		SYM(CIPHER_SYM)},
+  { "CLASS_ORIGIN",     SYM(CLASS_ORIGIN_SYM)},
   { "CLIENT",		SYM(CLIENT_SYM)},
   { "CLOSE",		SYM(CLOSE_SYM)},
   { "COALESCE",		SYM(COALESCE)},
@@ -112,6 +114,7 @@ static SYMBOL symbols[] = {
   { "COLLATE",		SYM(COLLATE_SYM)},
   { "COLLATION",	SYM(COLLATION_SYM)},
   { "COLUMN",		SYM(COLUMN_SYM)},
+  { "COLUMN_NAME",      SYM(COLUMN_NAME_SYM)},
   { "COLUMNS",		SYM(COLUMNS)},
   { "COMMENT",		SYM(COMMENT_SYM)},
   { "COMMIT",		SYM(COMMIT_SYM)},
@@ -126,6 +129,9 @@ static SYMBOL symbols[] = {
   { "CONNECTION",       SYM(CONNECTION_SYM)},
   { "CONSISTENT",	SYM(CONSISTENT_SYM)},
   { "CONSTRAINT",	SYM(CONSTRAINT)},
+  { "CONSTRAINT_CATALOG", SYM(CONSTRAINT_CATALOG_SYM)},
+  { "CONSTRAINT_NAME",  SYM(CONSTRAINT_NAME_SYM)},
+  { "CONSTRAINT_SCHEMA", SYM(CONSTRAINT_SCHEMA_SYM)},
   { "CONTAINS",         SYM(CONTAINS_SYM)},
   { "CONTEXT",    SYM(CONTEXT_SYM)},
   { "CONTINUE",         SYM(CONTINUE_SYM)},
@@ -140,6 +146,7 @@ static SYMBOL symbols[] = {
   { "CURRENT_TIMESTAMP", SYM(NOW_SYM)},
   { "CURRENT_USER",	SYM(CURRENT_USER)},
   { "CURSOR",           SYM(CURSOR_SYM)},
+  { "CURSOR_NAME",      SYM(CURSOR_NAME_SYM)},
   { "DATA",		SYM(DATA_SYM)},
   { "DATABASE",		SYM(DATABASE)},
   { "DATABASES",	SYM(DATABASES)},
@@ -337,6 +344,7 @@ static SYMBOL symbols[] = {
   { "MEDIUMTEXT",	SYM(MEDIUMTEXT)},
   { "MEMORY",		SYM(MEMORY_SYM)},
   { "MERGE",		SYM(MERGE_SYM)},
+  { "MESSAGE_TEXT",     SYM(MESSAGE_TEXT_SYM)},
   { "MICROSECOND",	SYM(MICROSECOND_SYM)},
   { "MIDDLEINT",	SYM(MEDIUMINT)},	/* For powerbuilder */
   { "MIGRATE",          SYM(MIGRATE_SYM)},
@@ -352,7 +360,8 @@ static SYMBOL symbols[] = {
   { "MULTILINESTRING",	SYM(MULTILINESTRING)},
   { "MULTIPOINT",	SYM(MULTIPOINT)},
   { "MULTIPOLYGON",	SYM(MULTIPOLYGON)},
-  { "MUTEX",  SYM(MUTEX_SYM)},
+  { "MUTEX",            SYM(MUTEX_SYM)},
+  { "MYSQL_ERRNO",      SYM(MYSQL_ERRNO_SYM)},
   { "NAME",             SYM(NAME_SYM)},
   { "NAMES",		SYM(NAMES_SYM)},
   { "NATIONAL",		SYM(NATIONAL_SYM)},
@@ -448,6 +457,7 @@ static SYMBOL symbols[] = {
   { "REPEAT",           SYM(REPEAT_SYM)},
   { "REQUIRE",	        SYM(REQUIRE_SYM)},
   { "RESET",		SYM(RESET_SYM)},
+  { "RESIGNAL",         SYM(RESIGNAL_SYM)},
   { "RESTORE",		SYM(RESTORE_SYM)},
   { "RESTRICT",		SYM(RESTRICT)},
   { "RESUME",           SYM(RESUME_SYM)},
@@ -467,6 +477,7 @@ static SYMBOL symbols[] = {
   { "SAVEPOINT",	SYM(SAVEPOINT_SYM)},
   { "SCHEDULE",		SYM(SCHEDULE_SYM)},
   { "SCHEMA",		SYM(DATABASE)},
+  { "SCHEMA_NAME",      SYM(SCHEMA_NAME_SYM)},
   { "SCHEMAS",          SYM(DATABASES)},
   { "SECOND",		SYM(SECOND_SYM)},
   { "SECOND_MICROSECOND", SYM(SECOND_MICROSECOND_SYM)},
@@ -482,6 +493,7 @@ static SYMBOL symbols[] = {
   { "SHARE",		SYM(SHARE_SYM)},
   { "SHOW",		SYM(SHOW)},
   { "SHUTDOWN",		SYM(SHUTDOWN)},
+  { "SIGNAL",		SYM(SIGNAL_SYM)},
   { "SIGNED",		SYM(SIGNED_SYM)},
   { "SIMPLE",		SYM(SIMPLE_SYM)},
   { "SLAVE",            SYM(SLAVE)},
@@ -523,6 +535,7 @@ static SYMBOL symbols[] = {
   { "STORAGE",		SYM(STORAGE_SYM)},
   { "STRAIGHT_JOIN",	SYM(STRAIGHT_JOIN)},
   { "STRING",		SYM(STRING_SYM)},
+  { "SUBCLASS_ORIGIN",  SYM(SUBCLASS_ORIGIN_SYM)},
   { "SUBJECT",		SYM(SUBJECT_SYM)},
   { "SUBPARTITION",     SYM(SUBPARTITION_SYM)},
   { "SUBPARTITIONS",    SYM(SUBPARTITIONS_SYM)},
@@ -531,6 +544,7 @@ static SYMBOL symbols[] = {
   { "SWAPS",      SYM(SWAPS_SYM)},
   { "SWITCHES",   SYM(SWITCHES_SYM)},
   { "TABLE",		SYM(TABLE_SYM)},
+  { "TABLE_NAME",       SYM(TABLE_NAME_SYM)},
   { "TABLES",		SYM(TABLES)},
   { "TABLESPACE",	        SYM(TABLESPACE)},
   { "TABLE_CHECKSUM",	SYM(TABLE_CHECKSUM_SYM)},

=== modified file 'sql/log.cc'
--- a/sql/log.cc	2008-07-25 17:21:55 +0000
+++ b/sql/log.cc	2008-08-27 22:14:03 +0000
@@ -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;
 }
 

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2008-08-25 08:12:02 +0000
+++ b/sql/log_event.cc	2008-08-27 22:14:03 +0000
@@ -132,17 +132,18 @@ static void inline slave_rows_error_repo
   char buff[MAX_SLAVE_ERRMSG], *slider;
   const char *buff_end= buff + sizeof(buff);
   uint len;
-  List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
-  MYSQL_ERROR *err;
+  List_iterator_fast<SQL_condition> it(thd->main_da.m_stmt_area.warn_list);
+  SQL_condition *cond;
   buff[0]= 0;
 
-  for (err= it++, slider= buff; err && slider < buff_end - 1;
-       slider += len, err= it++)
+  for (cond= it++, slider= buff; cond && slider < buff_end - 1;
+       slider += len, cond= it++)
   {
     len= my_snprintf(slider, buff_end - slider,
-                     " %s, Error_code: %d;", err->msg, err->code);
+                     " %s, Error_code: %d;", cond->get_message_text(),
+                     cond->get_sql_errno());
   }
-  
+
   rli->report(level, thd->is_error()? thd->main_da.sql_errno() : 0,
               "Could not execute %s event on table %s.%s;"
               "%s handler error %s; "

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2008-08-26 06:52:00 +0000
+++ b/sql/mysql_priv.h	2008-08-27 22:14:03 +0000
@@ -154,6 +154,10 @@ char* query_table_status(THD *thd,const 
 extern CHARSET_INFO *system_charset_info, *files_charset_info ;
 extern CHARSET_INFO *national_charset_info, *table_alias_charset;
 
+/**
+  Character set of the buildin error messages loaded from errmsg.sys.
+*/
+extern CHARSET_INFO *error_message_charset_info;
 
 enum Derivation
 {
@@ -792,6 +796,7 @@ typedef my_bool (*qc_engine_callback)(TH
                                       uint key_length,
                                       ulonglong *engine_data);
 #include "sql_string.h"
+#include "sql_fixstring.h"
 #include "sql_list.h"
 #include "sql_map.h"
 #include "my_decimal.h"

=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc	2008-08-22 13:21:31 +0000
+++ b/sql/mysqld.cc	2008-08-27 22:14:03 +0000
@@ -665,6 +665,7 @@ MY_BITMAP temp_pool;
 CHARSET_INFO *system_charset_info, *files_charset_info ;
 CHARSET_INFO *national_charset_info, *table_alias_charset;
 CHARSET_INFO *character_set_filesystem;
+CHARSET_INFO *error_message_charset_info;
 
 MY_LOCALE *my_default_lc_time_names;
 
@@ -1902,7 +1903,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)
@@ -2952,8 +2956,6 @@ extern "C" void my_message_sql(uint erro
 void my_message_sql(uint error, const char *str, myf MyFlags)
 {
   THD *thd;
-  MYSQL_ERROR::enum_warning_level level;
-  sql_print_message_func func;
   DBUG_ENTER("my_message_sql");
   DBUG_PRINT("error", ("error: %u  message: '%s'", error, str));
   /*
@@ -2961,106 +2963,37 @@ void my_message_sql(uint error, const ch
     will be fixed
     DBUG_ASSERT(error != 0);
   */
+
+  /*
+    TODO: ME_JUST_INFO and ME_JUST_WARNING are back doors used in
+    storage/maria to print to the server log files.
+    my_error/my_message_sql should not be used for this, since we
+    don't want the exception handlers / SIGNAL / RESIGNAL to interfere
+    with the error handling in this case.
+    Instead, the server should expose a clean interface to the storage
+    engines for printing into the server logs (sql/log.cc),
+    and the storage engine should call that interface (see ma_message_end_user)
+    See Bug#38781
+  */
+
   if (MyFlags & ME_JUST_INFO)
   {
-    level= MYSQL_ERROR::WARN_LEVEL_NOTE;
-    func= sql_print_information;
-  }
-  else if (MyFlags & ME_JUST_WARNING)
-  {
-    level= MYSQL_ERROR::WARN_LEVEL_WARN;
-    func= sql_print_warning;
+    sql_print_information("%s: %s", my_progname, str);
+    DBUG_VOID_RETURN;
   }
-  else
+
+  if (MyFlags & ME_JUST_WARNING)
   {
-    level= MYSQL_ERROR::WARN_LEVEL_ERROR;
-    func= sql_print_error;
+    sql_print_warning("%s: %s", my_progname, str);
+    DBUG_VOID_RETURN;
   }
 
   if ((thd= current_thd))
   {
-    if (MyFlags & ME_FATALERROR)
-      thd->is_fatal_error= 1;
-
-#ifdef BUG_36098_FIXED
-    mysql_audit_general(thd,MYSQL_AUDIT_GENERAL_ERROR,error,my_time(0),
-                        0,0,str,str ? strlen(str) : 0,
-                        thd->query,thd->query_length,
-                        thd->variables.character_set_client,
-                        thd->row_count);
-#endif
-
-
-    /*
-      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, level))
-      DBUG_VOID_RETURN;
-
-    if (level == MYSQL_ERROR::WARN_LEVEL_WARN)
-      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, error, str);
-    if (level != MYSQL_ERROR::WARN_LEVEL_ERROR)
-      goto to_error_log;
-
-    thd->is_slave_error=  1; // needed to catch query errors during replication
-
-    /*
-      thd->lex->current_select == 0 if lex structure is not inited
-      (not query command (COM_QUERY))
-    */
-    if (thd->lex->current_select &&
-	thd->lex->current_select->no_error && !thd->is_fatal_error)
-    {
-      DBUG_PRINT("error",
-                 ("Error converted to warning: current_select: no_error %d  "
-                  "fatal_error: %d",
-                  (thd->lex->current_select ?
-                   thd->lex->current_select->no_error : 0),
-                  (int) thd->is_fatal_error));
-    }
-    else
-    {
-      if (! thd->main_da.is_error())            // Return only first message
-      {
-        if (error == 0)
-          error= ER_UNKNOWN_ERROR;
-        if (str == NULL)
-          str= ER(error);
-        thd->main_da.set_error_status(thd, error, str);
-      }
-      query_cache_abort(&thd->query_cache_tls);
-    }
-    /*
-      If a continue handler is found, the error message will be cleared
-      by the stored procedures code.
-    */
-    if (!thd->is_fatal_error && thd->spcont &&
-        ! (MyFlags & ME_NO_SP_HANDLER) &&
-        thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
-    {
-      /*
-        Do not push any warnings, a handled error must be completely
-        silenced.
-      */
-      DBUG_VOID_RETURN;
-    }
-
-    if (!thd->is_fatal_error && !thd->no_warnings_for_error &&
-        !(MyFlags & ME_NO_WARNING_FOR_ERROR))
-    {
-      /*
-        Suppress infinite recursion if there a memory allocation error
-        inside push_warning.
-      */
-      thd->no_warnings_for_error= TRUE;
-      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str);
-      thd->no_warnings_for_error= FALSE;
-    }
+    thd->raise_error(error, str, MyFlags);
   }
-to_error_log:
-  if (!thd || (MyFlags & ME_NOREFRESH))
-    (*func)("%s: %s", my_progname_short, str); /* purecov: inspected */
+  if (!thd || MyFlags & ME_NOREFRESH)
+    sql_print_error("%s: %s", my_progname, str); /* purecov: inspected */
   DBUG_VOID_RETURN;
 }
 
@@ -3228,6 +3161,7 @@ SHOW_VAR com_status_vars[]= {
   {"replace",              (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REPLACE]), SHOW_LONG_STATUS},
   {"replace_select",       (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REPLACE_SELECT]), SHOW_LONG_STATUS},
   {"reset",                (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RESET]), SHOW_LONG_STATUS},
+  {"resignal",             (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RESIGNAL]), SHOW_LONG_STATUS},
   {"restore",              (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RESTORE]), SHOW_LONG_STATUS},
   {"revoke",               (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REVOKE]), SHOW_LONG_STATUS},
   {"revoke_all",           (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REVOKE_ALL]), SHOW_LONG_STATUS},
@@ -3236,6 +3170,7 @@ SHOW_VAR com_status_vars[]= {
   {"savepoint",            (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SAVEPOINT]), SHOW_LONG_STATUS},
   {"select",               (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SELECT]), SHOW_LONG_STATUS},
   {"set_option",           (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SET_OPTION]), SHOW_LONG_STATUS},
+  {"signal",               (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SIGNAL]), SHOW_LONG_STATUS},
   {"show_authors",         (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_AUTHORS]), SHOW_LONG_STATUS},
   {"show_binlog_events",   (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_BINLOG_EVENTS]), SHOW_LONG_STATUS},
   {"show_binlogs",         (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_BINLOGS]), SHOW_LONG_STATUS},
@@ -4937,6 +4872,8 @@ void create_thread_to_handle_connection(
                               handle_one_connection,
                               (void*) thd)))
     {
+      const char* sqlstate;
+
       /* purecov: begin inspected */
       DBUG_PRINT("error",
                  ("Can't create thread to handle request (error %d)",
@@ -4953,7 +4890,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;

=== modified file 'sql/protocol.cc'
--- a/sql/protocol.cc	2008-06-05 16:11:22 +0000
+++ b/sql/protocol.cc	2008-08-27 22:14:03 +0000
@@ -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,13 +129,14 @@ 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");
 
   DBUG_ASSERT(!thd->spcont);
   DBUG_ASSERT(sql_errno);
-  DBUG_ASSERT(err && err[0]);
+  DBUG_ASSERT(err);
 
   DBUG_PRINT("enter",("sql_errno: %d  err: %s", sql_errno, err));
 
@@ -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);
@@ -445,7 +448,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,

=== modified file 'sql/protocol.h'
--- a/sql/protocol.h	2008-02-11 16:11:22 +0000
+++ b/sql/protocol.h	2008-08-27 22:14:03 +0000
@@ -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);

=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc	2008-08-11 16:06:30 +0000
+++ b/sql/set_var.cc	2008-08-27 22:14:03 +0000
@@ -3205,16 +3205,16 @@ static int check_pseudo_thread_id(THD *t
 static uchar *get_warning_count(THD *thd)
 {
   thd->sys_var_tmp.long_value=
-    (thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_NOTE] +
-     thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR] +
-     thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_WARN]);
+    (thd->main_da.m_stmt_area.warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_NOTE] +
+     thd->main_da.m_stmt_area.warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR] +
+     thd->main_da.m_stmt_area.warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_WARN]);
   return (uchar*) &thd->sys_var_tmp.long_value;
 }
 
 static uchar *get_error_count(THD *thd)
 {
-  thd->sys_var_tmp.long_value= 
-    thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR];
+  thd->sys_var_tmp.long_value=
+    thd->main_da.m_stmt_area.warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR];
   return (uchar*) &thd->sys_var_tmp.long_value;
 }
 

=== modified file 'sql/share/errmsg.txt'
--- a/sql/share/errmsg.txt	2008-08-22 13:21:31 +0000
+++ b/sql/share/errmsg.txt	2008-08-27 22:14:03 +0000
@@ -6374,3 +6374,28 @@ ER_BACKUP_RELEASE_NAME_LOCK_FAILED
   eng "Restore failed to release the name locks on the tables."
 ER_BACKUP_BACKUPDIR
   eng "The path specified for the system variable backupdir cannot be accessed or is invalid. ref: %-.64s"
+
+ER_DUP_SIGNAL_SET 42000
+        eng "Duplicate condition information item '%s'"
+
+ER_SIGNAL_WARN 01000
+        eng "Unhandled user-defined warning"
+
+ER_SIGNAL_NOT_FOUND 02000
+        eng "Unhandled user-defined not found"
+
+ER_SIGNAL_EXCEPTION HY000
+        eng "Unhandled user-defined exception"
+
+ER_RESIGNAL_NO_HANDLER 0K000
+        eng "RESIGNAL when handler not active"
+
+ER_SIGNAL_BAD_CONDITION_TYPE
+        eng "SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE"
+
+WARN_COND_ITEM_TRUNCATED
+        eng "Data truncated for condition item '%s'"
+
+ER_COND_ITEM_TOO_LONG
+        eng "Data too long for condition item '%s'"
+

=== modified file 'sql/slave.cc'
--- a/sql/slave.cc	2008-07-21 03:55:09 +0000
+++ b/sql/slave.cc	2008-08-27 22:14:03 +0000
@@ -1660,12 +1660,13 @@ static int has_temporary_error(THD *thd)
   /*
     currently temporary error set in ndbcluster
   */
-  List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
-  MYSQL_ERROR *err;
-  while ((err= it++))
-  {
-    DBUG_PRINT("info", ("has warning %d %s", err->code, err->msg));
-    switch (err->code)
+  List_iterator_fast<SQL_condition> it(thd->main_da.m_stmt_area.warn_list);
+  SQL_condition *cond;
+  while ((cond= it++))
+  {
+    DBUG_PRINT("info", ("has condition %d %s", cond->get_sql_errno(),
+                        cond->get_message_text()));
+    switch (cond->get_sql_errno())
     {
     case ER_GET_TEMPORARY_ERRMSG:
       DBUG_RETURN(1);
@@ -2575,18 +2576,19 @@ Slave SQL thread aborted. Can't execute 
         }
 
         /* Print any warnings issued */
-        List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
-        MYSQL_ERROR *err;
+        List_iterator_fast<SQL_condition> it(thd->main_da.m_stmt_area.warn_list);
+        SQL_condition *cond;
         /*
           Added controlled slave thread cancel for replication
           of user-defined variables.
         */
         bool udf_error = false;
-        while ((err= it++))
+        while ((cond= it++))
         {
-          if (err->code == ER_CANT_OPEN_LIBRARY)
+          if (cond->get_sql_errno() == ER_CANT_OPEN_LIBRARY)
             udf_error = true;
-          sql_print_warning("Slave: %s Error_code: %d",err->msg, err->code);
+          sql_print_warning("Slave: %s Error_code: %d",
+                            cond->get_message_text(), cond->get_sql_errno());
         }
         if (udf_error)
           sql_print_error("Error loading user-defined library, slave SQL "

=== modified file 'sql/sp.cc'
--- a/sql/sp.cc	2008-07-15 16:29:51 +0000
+++ b/sql/sp.cc	2008-08-27 22:14:03 +0000
@@ -496,18 +496,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->get_sql_errno() == ER_WARN_DEPRECATED_SYNTAX &&
+      cond->get_level() == MYSQL_ERROR::WARN_LEVEL_WARN)
     return TRUE;
 
   return FALSE;

=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	2008-08-18 18:12:46 +0000
+++ b/sql/sp_head.cc	2008-08-27 22:14:03 +0000
@@ -1263,9 +1263,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:
@@ -1274,16 +1274,20 @@ 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();
-        ctx->enter_handler(hip);
+        ctx->enter_handler(hip, handler_index);
         thd->clear_error();
         thd->is_fatal_error= 0;
         thd->killed= THD::NOT_KILLED;
         thd->mysys_var->abort= 0;
         continue;
       }
+
+      thd->end_partial_result_set= FALSE;
     }
   } while (!err_status && !thd->killed && !thd->is_fatal_error);
 
@@ -1525,7 +1529,7 @@ sp_head::execute_trigger(THD *thd,
   init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
   thd->set_n_backup_active_arena(&call_arena, &backup_arena);
 
-  if (!(nctx= new sp_rcontext(m_pcont, 0, octx)) ||
+  if (!(nctx= new sp_rcontext(mem_root, m_pcont, 0, octx)) ||
       nctx->init(thd))
   {
     err_status= TRUE;
@@ -1642,7 +1646,7 @@ sp_head::execute_function(THD *thd, Item
   init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
   thd->set_n_backup_active_arena(&call_arena, &backup_arena);
 
-  if (!(nctx= new sp_rcontext(m_pcont, return_value_fld, octx)) ||
+  if (!(nctx= new sp_rcontext(mem_root, m_pcont, return_value_fld, octx)) ||
       nctx->init(thd))
   {
     thd->restore_active_arena(&call_arena, &backup_arena);
@@ -1846,7 +1850,7 @@ sp_head::execute_procedure(THD *thd, Lis
   save_spcont= octx= thd->spcont;
   if (! octx)
   {				// Create a temporary old context
-    if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) ||
+    if (!(octx= new sp_rcontext(mem_root, m_pcont, NULL, octx)) ||
         octx->init(thd))
     {
       delete octx; /* Delete octx if it was init() that failed. */
@@ -1862,7 +1866,7 @@ sp_head::execute_procedure(THD *thd, Lis
     thd->spcont->callers_arena= thd;
   }
 
-  if (!(nctx= new sp_rcontext(m_pcont, NULL, octx)) ||
+  if (!(nctx= new sp_rcontext(mem_root, m_pcont, NULL, octx)) ||
       nctx->init(thd))
   {
     delete nctx; /* Delete nctx if it was init() that failed. */
@@ -3218,7 +3222,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);

=== modified file 'sql/sp_pcontext.h'
--- a/sql/sp_pcontext.h	2007-06-10 10:43:57 +0000
+++ b/sql/sp_pcontext.h	2008-08-27 22:14:03 +0000
@@ -71,7 +71,7 @@ typedef struct sp_label
 typedef struct sp_cond_type
 {
   enum { number, state, warning, notfound, exception } type;
-  char sqlstate[6];
+  char sqlstate[SQLSTATE_LENGTH+1];
   uint mysqlerr;
 } sp_cond_type_t;
 

=== modified file 'sql/sp_rcontext.cc'
--- a/sql/sp_rcontext.cc	2008-01-23 22:36:57 +0000
+++ b/sql/sp_rcontext.cc	2008-08-27 22:14:03 +0000
@@ -29,7 +29,7 @@
 #include "sp_pcontext.h"
 
 
-sp_rcontext::sp_rcontext(sp_pcontext *root_parsing_ctx,
+sp_rcontext::sp_rcontext(MEM_ROOT *cond_root, sp_pcontext *root_parsing_ctx,
                          Field *return_value_fld,
                          sp_rcontext *prev_runtime_ctx)
   :m_root_parsing_ctx(root_parsing_ctx),
@@ -44,7 +44,8 @@ sp_rcontext::sp_rcontext(sp_pcontext *ro
    m_hfound(-1),
    m_ccount(0),
    m_case_expr_holders(0),
-   m_prev_runtime_ctx(prev_runtime_ctx)
+   m_prev_runtime_ctx(prev_runtime_ctx),
+   m_cond_root(cond_root)
 {
 }
 
@@ -68,6 +69,8 @@ sp_rcontext::~sp_rcontext()
 
 bool sp_rcontext::init(THD *thd)
 {
+  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())
@@ -75,14 +78,14 @@ bool sp_rcontext::init(THD *thd)
 
   return
     !(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->calloc(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*))) ||
@@ -194,13 +197,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->get_sql_errno();
+  MYSQL_ERROR::enum_warning_level level= cond->get_level();
+
+  const char *sqlstate= cond->get_sqlstate();
   int i= m_hcount, found= -1;
 
   /*
@@ -220,7 +225,7 @@ sp_rcontext::find_handler(THD *thd, uint
 
     /* 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
@@ -264,10 +269,18 @@ 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;
+
+  SQL_condition *raised;
+  raised= SQL_condition::deep_copy(thd, m_cond_root, cond) ;
+  DBUG_ASSERT(m_hfound >= 0);
+  DBUG_ASSERT(m_hfound < m_root_parsing_ctx->max_handler_index());
+  m_raised_conditions[m_hfound]= raised;
+
   return TRUE;
 }
 
@@ -293,22 +306,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(thd->mem_root);
+    elevated_cond.set(thd, cond->m_sql_errno,
+                      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
@@ -335,7 +348,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());
@@ -343,7 +356,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));
@@ -382,11 +394,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;
 }
@@ -396,11 +410,32 @@ sp_rcontext::exit_handler()
 {
   DBUG_ENTER("sp_rcontext::exit_handler");
   DBUG_ASSERT(m_ihsp);
+  uint hindex= m_in_handler[m_ihsp-1].index;
+  DBUG_ASSERT(m_raised_conditions[hindex]);
+  delete m_raised_conditions[hindex];
+  m_raised_conditions[hindex]= NULL;
   m_ihsp-= 1;
   DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp));
   DBUG_VOID_RETURN;
 }
 
+SQL_condition*
+sp_rcontext::raised_condition() const
+{
+  if (m_ihsp > 0)
+  {
+    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)
+    return m_prev_runtime_ctx->raised_condition();
+
+  return NULL;
+}
+
 
 int
 sp_rcontext::set_variable(THD *thd, uint var_idx, Item **value)

=== modified file 'sql/sp_rcontext.h'
--- a/sql/sp_rcontext.h	2008-01-23 20:26:41 +0000
+++ b/sql/sp_rcontext.h	2008-08-27 22:14:03 +0000
@@ -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
@@ -83,8 +92,8 @@ class sp_rcontext : public Sql_alloc
   sp_head *sp;
 #endif
 
-  sp_rcontext(sp_pcontext *root_parsing_ctx, Field *return_value_fld,
-              sp_rcontext *prev_runtime_ctx);
+  sp_rcontext(MEM_ROOT *cond_root, sp_pcontext *root_parsing_ctx,
+              Field *return_value_fld, sp_rcontext *prev_runtime_ctx);
   bool init(THD *thd);
 
   ~sp_rcontext();
@@ -107,31 +116,31 @@ 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);
 
   // 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
-  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;
   }
 
+  SQL_condition* raised_condition() const;
+
   // Returns true if we found a handler in this context
   inline bool
   found_handler_here()
@@ -150,7 +159,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();
 
@@ -214,10 +228,18 @@ private:
   bool in_sub_stmt;
 
   sp_handler_t *m_handler;      // Visible handlers
+
+  /**
+    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
 
@@ -229,6 +251,9 @@ private:
   /* Previous runtime context (NULL if none) */
   sp_rcontext *m_prev_runtime_ctx;
 
+  /** Memory root to use for SQL_condition caught by handlers. */
+  MEM_ROOT *m_cond_root;
+
 private:
   bool init_var_table(THD *thd);
   bool init_var_items();

=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc	2008-08-07 03:05:33 +0000
+++ b/sql/sql_acl.cc	2008-08-27 22:14:03 +0000
@@ -6132,9 +6132,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; }
 
@@ -6143,18 +6141,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->get_level() == MYSQL_ERROR::WARN_LEVEL_ERROR)
   {
-    switch (sql_errno)
+    switch (cond->get_sql_errno())
     {
       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->get_sql_errno(), cond->get_message_text());
         return TRUE;
       default:
         is_grave= TRUE;

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2008-08-26 10:20:41 +0000
+++ b/sql/sql_base.cc	2008-08-27 22:14:03 +0000
@@ -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->get_sql_errno() == ER_NO_SUCH_TABLE)
   {
     m_handled_errors++;
     return TRUE;
@@ -2390,7 +2385,7 @@ bool open_table(THD *thd, TABLE_LIST *ta
 
   if (flags & MYSQL_OPEN_TEMPORARY_ONLY)
   {
-    my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->table_name);
+    thd->raise_ER_NO_SUCH_TABLE(table_list->db, table_list->table_name);
     DBUG_RETURN(TRUE);
   }
 
@@ -2513,7 +2508,7 @@ bool open_table(THD *thd, TABLE_LIST *ta
       locked tables list was created.
     */
     if (thd->locked_tables_mode == LTM_PRELOCKED)
-      my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
+      thd->raise_ER_NO_SUCH_TABLE(table_list->db, table_list->alias);
     else
       my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
     DBUG_RETURN(TRUE);

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2008-08-25 12:25:07 +0000
+++ b/sql/sql_class.cc	2008-08-27 22:14:03 +0000
@@ -206,8 +206,9 @@ bool foreign_key_prefix(Key *a, Key *b)
 bool
 Reprepare_observer::report_error(THD *thd)
 {
-  my_error(ER_NEED_REPREPARE, MYF(ME_NO_WARNING_FOR_ERROR|ME_NO_SP_HANDLER));
-
+  /* No handler, no error in the condition area */
+  thd->main_da.set_error_status(thd, ER_NEED_REPREPARE,
+                                ER(ER_NEED_REPREPARE), "HY000");
   m_invalidated= TRUE;
 
   return TRUE;
@@ -370,6 +371,12 @@ char *thd_security_context(THD *thd, cha
   return thd->strmake(str.ptr(), str.length());
 }
 
+void Diagnostics_stmt_area::clear()
+{
+  warn_list.empty();
+  memset((char*) warn_count, 0, sizeof(warn_count));
+}
+
 /**
   Clear this diagnostics area. 
 
@@ -385,6 +392,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;
@@ -463,9 +471,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)
+{
   DBUG_ENTER("set_error_status");
   /*
     Only allowed to report error if has not yet reported a success
@@ -483,6 +500,8 @@ Diagnostics_area::set_error_status(THD *
 #endif
 
   m_sql_errno= sql_errno_arg;
+  strncpy(m_sqlstate, sqlstate, SQLSTATE_LENGTH);
+  m_sqlstate[SQLSTATE_LENGTH]= '\0';
   strmake(m_message, message_arg, sizeof(m_message)-1);
 
   m_status= DA_ERROR;
@@ -528,6 +547,7 @@ THD::THD()
    bootstrap(0),
    derived_tables_processing(FALSE),
    spcont(NULL),
+   end_partial_result_set(FALSE),
    m_parser_state(NULL),
   /*
     @todo The following is a work around for online backup and the DDL blocker.
@@ -666,12 +686,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
@@ -684,6 +703,183 @@ void THD::pop_internal_handler()
   m_internal_handler= NULL;
 }
 
+void THD::raise_error(uint code, const char *str, myf MyFlags)
+{
+  SQL_condition cond(this->mem_root);
+  cond.set(this, 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);
+  my_vsnprintf(ebuff, sizeof(ebuff), format, args);
+  va_end(args);
+  SQL_condition cond(this->mem_root);
+  cond.set(this, 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(this->mem_root);
+  cond.set(this, 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(this->mem_root);
+  cond.set(this, 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(this->mem_root);
+  cond.set(this, 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(this->mem_root);
+  cond.set(this, code, ebuff, MYSQL_ERROR::WARN_LEVEL_NOTE, MYF(0));
+  raise_condition(& cond);
+  DBUG_VOID_RETURN;
+}
+
+void THD::raise_condition(const SQL_condition *cond)
+{
+  const char* msg= cond->get_message_text();
+
+  DBUG_ENTER("THD::raise_condition");
+
+  if (!(this->options & OPTION_SQL_NOTES) &&
+      (cond->m_level == MYSQL_ERROR::WARN_LEVEL_NOTE))
+    DBUG_VOID_RETURN;
+
+  if (query_id != warn_id && !spcont)
+    mysql_reset_errors(this, 0);
+
+  switch (cond->m_level)
+  {
+  case MYSQL_ERROR::WARN_LEVEL_NOTE:
+  case MYSQL_ERROR::WARN_LEVEL_WARN:
+    got_warning= 1;
+    break;
+  case MYSQL_ERROR::WARN_LEVEL_ERROR:
+    if (cond->m_flags & ME_FATALERROR)
+      is_fatal_error= 1;
+    break;
+  default:
+    DBUG_ASSERT(FALSE);
+  }
+
+  if (handle_condition(cond))
+    DBUG_VOID_RETURN;
+
+  if (cond->m_level == MYSQL_ERROR::WARN_LEVEL_ERROR)
+  {
+    is_slave_error=  1; // needed to catch query errors during replication
+
+    /*
+      thd->lex->current_select == 0 if lex structure is not inited
+      (not query command (COM_QUERY))
+    */
+    if (lex->current_select &&
+        lex->current_select->no_error && !is_fatal_error)
+    {
+      DBUG_PRINT("error",
+                 ("Error converted to warning: current_select: no_error %d  "
+                  "fatal_error: %d",
+                  (lex->current_select ?
+                   lex->current_select->no_error : 0),
+                  (int) is_fatal_error));
+    }
+    else if (! main_da.is_error())
+      main_da.set_error_status(this, cond->m_sql_errno,
+                               msg, cond->get_sqlstate());
+  }
+
+  /*
+    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 */
+
+  raise_condition_no_handler(cond);
+  DBUG_VOID_RETURN;
+}
+
+void THD::raise_condition_no_handler(const SQL_condition *cond)
+{
+  DBUG_ENTER("THD::raise_condition_no_handler");
+
+  query_cache_abort(& query_cache_tls);
+
+  /* FIXME: broken special case */
+  if (no_warnings_for_error && (cond->m_level == MYSQL_ERROR::WARN_LEVEL_ERROR))
+    DBUG_VOID_RETURN;
+
+  if (! main_da.m_stmt_area.is_read_only())
+  {
+    if (main_da.m_stmt_area.warn_list.elements < variables.max_error_count)
+    {
+      /* We have to use warn_root, as mem_root is freed after each query */
+      SQL_condition *stored_cond;
+      stored_cond= SQL_condition::deep_copy(this, & warn_root, cond);
+      if (stored_cond)
+      {
+        main_da.m_stmt_area.warn_list.push_back(stored_cond, & warn_root);
+      }
+    }
+
+    main_da.m_stmt_area.warn_count[(uint) cond->m_level]++;
+  }
+
+  total_warn_count++;
+  DBUG_VOID_RETURN;
+}
+
 extern "C"
 void *thd_alloc(MYSQL_THD thd, unsigned int size)
 {
@@ -766,8 +962,8 @@ void THD::init(void)
 			TL_WRITE_LOW_PRIORITY :
 			TL_WRITE);
   session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
-  warn_list.empty();
-  bzero((char*) warn_count, sizeof(warn_count));
+  main_da.reset_diagnostics_area();
+  main_da.m_stmt_area.clear();
   total_warn_count= 0;
   update_charset();
   reset_current_stmt_binlog_row_based();
@@ -1562,9 +1758,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
@@ -1576,7 +1771,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;
 }

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2008-08-25 12:25:07 +0000
+++ b/sql/sql_class.h	2008-08-27 22:14:03 +0000
@@ -303,6 +303,41 @@ struct Query_cache_tls
   Query_cache_tls() :first_query_block(NULL) {}
 };
 
+/* SIGNAL / RESIGNAL / GET DIAGNOSTICS */
+
+/**
+  This enumeration list all the condition item names of a condition in the
+  SQL condition area.
+*/
+typedef enum enum_diag_condition_item_name
+{
+  /*
+    Conditions that can be set by the user (SIGNAL/RESIGNAL),
+    and by the server implementation (THD::raise_ER_XXX).
+  */
+
+  DIAG_CLASS_ORIGIN= 0,
+  FIRST_DIAG_SET_PROPERTY= DIAG_CLASS_ORIGIN,
+  DIAG_SUBCLASS_ORIGIN= 1,
+  DIAG_CONSTRAINT_CATALOG= 2,
+  DIAG_CONSTRAINT_SCHEMA= 3,
+  DIAG_CONSTRAINT_NAME= 4,
+  DIAG_CATALOG_NAME= 5,
+  DIAG_SCHEMA_NAME= 6,
+  DIAG_TABLE_NAME= 7,
+  DIAG_COLUMN_NAME= 8,
+  DIAG_CURSOR_NAME= 9,
+  DIAG_MESSAGE_TEXT= 10,
+  DIAG_MYSQL_ERRNO= 11,
+  LAST_DIAG_SET_PROPERTY= DIAG_MYSQL_ERRNO
+} Diag_condition_item_name;
+
+/**
+  Name of each diagnostic condition item.
+  This array is indexed by Diag_condition_item_name.
+*/
+extern const LEX_STRING Diag_condition_item_names[];
+
 #include "sql_lex.h"				/* Must be here */
 
 class Delayed_insert;
@@ -1073,6 +1108,202 @@ enum enum_thread_type
 
 
 /**
+  Representation of a SQL condition.
+  A SQL condition can be a completion condition (note, warning),
+  or an exception contition (error, not found).
+*/
+class SQL_condition : public Sql_alloc
+{
+public:
+  /**
+    Get the MESSAGE_TEXT of this condition.
+    @return the message text.
+  */
+  const char* get_message_text() const;
+
+  /**
+    Get the MESSAGE_OCTET_LENGTH of this condition.
+    @return the length in bytes of the message text.
+  */
+  int get_message_octet_length() const;
+
+  /**
+    Get the SQLSTATE of this condition.
+    @return the sql state.
+  */
+  const char* get_sqlstate() const
+  { return m_returned_sqlstate; }
+
+  /**
+    Get the SQL_ERRNO of this condition.
+    @return the sql error number condition item.
+  */
+  int get_sql_errno() const
+  { return m_sql_errno; }
+
+  /**
+    Get the error level of this condition.
+    @return the error level condition item.
+  */
+  MYSQL_ERROR::enum_warning_level get_level() const
+  { return m_level; }
+
+private:
+  /*
+    The interface of SQL_condition is mostly private, by design,
+    so that only the following code:
+    - various raise_error() or raise_warning() methods in class THD,
+    - the implementation of SIGNAL / RESIGNAL
+    - catch / re-throw of SQL conditions in stored procedures (sp_rcontext)
+    is allowed to create / modify a SQL_condition.
+    Enforcing this policy prevents confusion, since the only public
+    interface available to the rest of the server implementation
+    is the interface offered by the THD methods (THD::raise_error()),
+    which should be used.
+    MAINTAINER: If you need to access private attributes/methods here,
+    please consider creating a helper similar to THD::raise_ER_NO_SUCH_TABLE
+    instead.
+  */
+  friend class THD;
+  friend class Abstract_signal;
+  friend class SQLCOM_signal;
+  friend class SQLCOM_resignal;
+  friend class sp_rcontext;
+
+  /**
+    Constructor.
+    @param mem_root The memory root to use for the condition items
+    of this condition
+  */
+  SQL_condition(MEM_ROOT *mem_root);
+
+  /** Destructor. */
+  ~SQL_condition()
+  {}
+
+  /**
+    Deep copy (static method).
+    Builds a copy of a condition using a given memory root.
+    'Deep copy' is useful to propagate SQL conditions raised from a short
+    lived runtime environment to a parent execution environment with a longer
+    life cycle.
+    For example, when proc_p1() calls proc_p2(), an exception raised in
+    proc_p2() should be copied when caught in proc_p1(),
+    before destroying the proc_p2() memory root.
+    @param thd the current thread.
+    @param mem_root the memory root to use for memory allocation.
+    @param cond the condition to copy.
+    @return the duplicated condition.
+  */
+  static SQL_condition* deep_copy(THD *thd, MEM_ROOT *mem_root,
+                                  const SQL_condition *cond);
+
+  /**
+    Deep copy (instance method).
+    @param cond the condition to copy.
+  */
+  void deep_copy(const SQL_condition *cond);
+
+  /**
+    Set this condition area with a fixed message text.
+    @param thd the current thread.
+    @param code the error number for this condition.
+    @param str the message text for this condition.
+    @param level the error level for this condition.
+    @param MyFlags additional flags.
+  */
+  void set(THD *thd, uint code, const char *str,
+           MYSQL_ERROR::enum_warning_level level, myf MyFlags);
+
+  /**
+    Set this condition area with formatting of the message text.
+    @param thd the current thread.
+    @param code the error number for this condition.
+    @param str the message text printf format for this condition.
+    @param level the error level for this condition.
+    @param MyFlags additional flags.
+  */
+  void set_printf(THD *thd, uint code, const char *str,
+                  MYSQL_ERROR::enum_warning_level level, myf MyFlags, ...);
+
+  /**
+    Set the condition message test.
+    @param str Message text, expressed in the character set derived from
+    the server --language option
+  */
+  void set_builtin_message_text(const char* str);
+
+  /** Set the SQLSTATE of this condition. */
+  void set_sqlstate(const char* sqlstate);
+
+  bool is_message_text_set() const
+  { return m_message_text_set; }
+
+private:
+  /** SQL CLASS_ORIGIN condition item. */
+  UTF8String64 m_class_origin;
+
+  /** SQL SUBCLASS_ORIGIN condition item. */
+  UTF8String64 m_subclass_origin;
+
+  /** SQL CONSTRAINT_CATALOG condition item. */
+  UTF8String64 m_constraint_catalog;
+
+  /** SQL CONSTRAINT_SCHEMA condition item. */
+  UTF8String64 m_constraint_schema;
+
+  /** SQL CONSTRAINT_NAME condition item. */
+  UTF8String64 m_constraint_name;
+
+  /** SQL CATALOG_NAME condition item. */
+  UTF8String64 m_catalog_name;
+
+  /** SQL SCHEMA_NAME condition item. */
+  UTF8String64 m_schema_name;
+
+  /** SQL TABLE_NAME condition item. */
+  UTF8String64 m_table_name;
+
+  /** SQL COLUMN_NAME condition item. */
+  UTF8String64 m_column_name;
+
+  /** SQL CURSOR_NAME condition item. */
+  UTF8String64 m_cursor_name;
+
+  /** Message text, expressed in the character set implied by --language. */
+  String m_message_text;
+
+  /**
+    True if m_message_text was explicitely set.
+    This member is needed to differentiate:
+    - SIGNAL ... without a SET MESSAGE_TEXT clause, in which case the message
+    text should have a default value,
+    - SIGNAL ... SET MESSAGE_TEXT='', in which case the message text should
+    be '' and not replaced by a default value.
+  */
+
+  bool m_message_text_set;
+
+  /** MySQL extension, MYSQL_ERRNO condition item. */
+  int m_sql_errno;
+
+  /**
+    SQL RETURNED_SQLSTATE condition item.
+    This member is always NUL terminated.
+  */
+  char m_returned_sqlstate[SQLSTATE_LENGTH+1];
+
+  /** Severity (error, warning, note) of this condition. */
+  MYSQL_ERROR::enum_warning_level m_level;
+
+  /** Additional flags. */
+  myf m_flags;
+
+  /** Memory root to use to hold condition item values. */
+  MEM_ROOT *m_mem_root;
+};
+
+/**
   This class represents the interface for internal error handlers.
   Internal error handlers are exception handlers used by the server
   implementation.
@@ -1085,12 +1316,12 @@ protected:
 
 public:
   /**
-    Handle an error condition.
+    Handle a sql condition.
     This method can be implemented by a subclass to achieve any of the
     following:
-    - mask an error internally, prevent exposing it to the user,
-    - mask an error and throw another one instead.
-    When this method returns true, the error condition is considered
+    - mask a warning/error internally, prevent exposing it to the user,
+    - mask a warning/error and throw another one instead.
+    When this method returns true, the sql condition is considered
     'handled', and will not be propagated to upper layers.
     It is the responsability of the code installing an internal handler
     to then check for trapped conditions, and implement logic to recover
@@ -1104,15 +1335,69 @@ 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
+    @param cond the condition raised.
+    @return true if the condition is handled
+  */
+  virtual bool handle_condition(THD *thd, const SQL_condition *cond) = 0;
+};
+
+
+/**
+  Statement diagnostics area.
+*/
+class Diagnostics_stmt_area
+{
+public:
+  /** Constructor. */
+  Diagnostics_stmt_area()
+    : warn_list(),
+      m_read_only(FALSE)
+  {
+    bzero((char*) warn_count, sizeof(warn_count));
+  }
+
+  /** Destructor. */
+  ~Diagnostics_stmt_area()
+  {}
+
+  /** Clear the statement area. */
+  void clear();
+
+  /** 
+    Set the read only status for this statement area.
+    This is a priviledged operation, reserved for the implementation of
+    diagnostics related statements, to enforce that the statement area is
+    left untouched during execution.
+    The diagnostics statements are:
+    - SHOW WARNINGS
+    - SHOW ERRORS
+    - GET DIAGNOSTICS
+    @param read_only the read only property to set
+  */
+  void set_read_only(bool read_only)
+  { m_read_only= read_only; }
+
+  /**
+    Read only status.
+    @return the read only property
+  */
+  bool is_read_only() const
+  { return m_read_only; }
+
+  /**
+    Condition area.
+  */
+  List	     <SQL_condition> warn_list;
+
+  /**
+    Counters for errors/warnings/notes in the condition area.
   */
-  virtual bool handle_error(uint sql_errno,
-                            const char *message,
-                            MYSQL_ERROR::enum_warning_level level,
-                            THD *thd) = 0;
+  uint	     warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
+
+private:
+  /** Read only status. */
+  bool m_read_only;
 };
 
 
@@ -1148,7 +1433,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();
 
@@ -1167,6 +1455,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);
@@ -1196,6 +1487,8 @@ private:
   */
   uint m_sql_errno;
 
+  char m_sqlstate[SQLSTATE_LENGTH+1];
+
   /**
     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:
@@ -1224,12 +1517,11 @@ private:
   */
   ulonglong   m_last_insert_id;
   /** The total number of warnings. */
-  uint	     m_total_warn_count;
+  uint m_total_warn_count;
   enum_diagnostics_status m_status;
-  /**
-    @todo: the following THD members belong here:
-    - warn_list, warn_count,
-  */
+
+public:
+  Diagnostics_stmt_area m_stmt_area;
 };
 
 /**
@@ -1746,15 +2038,7 @@ public:
   table_map  used_tables;
   USER_CONN *user_connect;
   CHARSET_INFO *db_charset;
-  /*
-    FIXME: this, and some other variables like 'count_cuted_fields'
-    maybe should be statement/cursor local, that is, moved to Statement
-    class. With current implementation warnings produced in each prepared
-    statement/cursor settle here.
-  */
-  List	     <MYSQL_ERROR> warn_list;
-  uint	     warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
-  uint	     total_warn_count;
+  uint             total_warn_count;
   Diagnostics_area main_da;
 #if defined(ENABLED_PROFILING)
   PROFILING  profiling;
@@ -1866,6 +2150,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,19 +2629,122 @@ public:
   void push_internal_handler(Internal_error_handler *handler);
 
   /**
-    Handle an error condition.
-    @param sql_errno the error number
-    @param level the error level
+    Handle a sql condition.
+    @param cond the sql condition to handle.
     @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();
 
+  /**
+    Raise an ER_NO_SUCH_TABLE exception condition.
+    @param db the schema name of the missing table
+    @param table the table name of the missing table
+  */
+  void raise_ER_NO_SUCH_TABLE(const char* db, const char* table)
+  {
+    SQL_condition cond(this->mem_root);
+    cond.set_printf(this, ER_NO_SUCH_TABLE, ER(ER_NO_SUCH_TABLE),
+                    MYSQL_ERROR::WARN_LEVEL_ERROR, MYF(0),
+                    db, table);
+    cond.m_schema_name.set(db);
+    cond.m_table_name.set(table);
+    raise_condition(& cond);
+  }
+
+  /**
+    Raise an exception condition.
+    Helper for most common usage.
+    @param code the MYSQL_ERRNO error code of the error
+  */
+  void raise_error(uint code)
+  {
+    raise_error(code, ER(code), MYF(0));
+  }
+
+  /**
+    Raise an exception condition, with a fixed message.
+    @param code the MYSQL_ERRNO error code of the error
+    @param str the MESSAGE_TEXT of the error
+    @param MyFlags additional flags
+  */
+  void raise_error(uint code, const char *str, myf MyFlags);
+
+  /**
+    Raise an exception condition, with a formatted message.
+    @param code the MYSQL_ERRNO error code of the error
+    @param format the MESSAGE_TEXT printf format of the error
+    @param MyFlags additional flags
+  */
+  void raise_error_printf(uint code, const char *format, myf MyFlags, ...);
+
+  /**
+    Raise a completion condition (warning).
+    Helper for most common usage.
+    @param code the MYSQL_ERRNO error code of the warning
+  */
+  void raise_warning(uint code)
+  {
+    raise_warning(code, ER(code));
+  }
+
+  /**
+    Raise a completion condition (warning), with a fixed message.
+    @param code the MYSQL_ERRNO error code of the warning
+    @param str the MESSAGE_TEXT of the warning
+  */
+  void raise_warning(uint code, const char *str);
+
+  /**
+    Raise a completion condition (warning), with a formatted message.
+    @param code the MYSQL_ERRNO error code of the warning
+    @param format the MESSAGE_TEXT printf format of the warning
+  */
+  void raise_warning_printf(uint code, const char *format, ...);
+
+  /**
+    Raise a completion condition (note), with a fixed message.
+    @param code the MYSQL_ERRNO error code of the note
+    @param str the MESSAGE_TEXT of the note
+  */
+  void raise_note(uint code, const char *str);
+
+  /**
+    Raise a completion condition (note), with a formatted message.
+    @param code the MYSQL_ERRNO error code of the note
+    @param format the MESSAGE_TEXT printf format of the note
+  */
+  void raise_note_printf(uint code, const char *format, ...);
+
+private:
+  /*
+    Only the implementation of the SIGNAL and RESIGNAL statements
+    is permitted to raise SQL conditions in a generic way,
+    or to raise them by bypassing handlers (RESIGNAL).
+    To raise a SQL condition, the code should use the public
+    raise_error() or raise_warning() methods provided by class THD.
+  */
+  friend class Abstract_signal;
+  friend class SQLCOM_signal;
+  friend class SQLCOM_resignal;
+
+  /**
+    Raise a generic SQL condition.
+    @param cond the condition to raise
+  */
+  void raise_condition(const SQL_condition *cond);
+
+  /**
+    Raise a generic SQL condition, without activation any SQL condition
+    handlers.
+    @param cond the condition to raise
+  */
+  void raise_condition_no_handler(const SQL_condition *cond);
+
 private:
   /** The current internal error handler for this thread, or NULL. */
   Internal_error_handler *m_internal_handler;
@@ -3081,6 +3470,16 @@ public:
 */
 #define CF_AUTO_COMMIT_TRANS  (CF_IMPLICT_COMMIT_BEGIN | CF_IMPLICIT_COMMIT_END)
 
+/**
+  Diagnostic statement.
+  Diagnostic statements:
+  - SHOW WARNING
+  - SHOW ERROR
+  - GET DIAGNOSTICS (WL#2111)
+  do not modify the diagnostics area during execution.
+*/
+#define CF_DIAGNOSTIC_STMT        (1U << 8)
+
 /* Bits in server_command_flags */
 
 /**

=== modified file 'sql/sql_error.cc'
--- a/sql/sql_error.cc	2008-07-29 22:03:57 +0000
+++ b/sql/sql_error.cc	2008-08-27 22:14:03 +0000
@@ -74,14 +74,17 @@ void MYSQL_ERROR::set_msg(THD *thd, cons
 void mysql_reset_errors(THD *thd, bool force)
 {
   DBUG_ENTER("mysql_reset_errors");
+
+  if (thd->main_da.m_stmt_area.is_read_only())
+    DBUG_VOID_RETURN;
+
   if (thd->query_id != thd->warn_id || force)
   {
     thd->warn_id= thd->query_id;
+    thd->main_da.m_stmt_area.clear();
     free_root(&thd->warn_root,MYF(0));
-    bzero((char*) thd->warn_count, sizeof(thd->warn_count));
     if (force)
       thd->total_warn_count= 0;
-    thd->warn_list.empty();
     thd->row_count= 1; // by default point to row 1
   }
   DBUG_VOID_RETURN;
@@ -99,63 +102,28 @@ void mysql_reset_errors(THD *thd, bool f
     msg			Clear error message
 */
 
-void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, 
-                          uint code, const char *msg)
+void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
+                  uint code, const char *msg)
 {
-  MYSQL_ERROR *err= 0;
   DBUG_ENTER("push_warning");
   DBUG_PRINT("enter", ("code: %d, msg: %s", code, msg));
 
-  if (level == MYSQL_ERROR::WARN_LEVEL_NOTE &&
-      !(thd->options & OPTION_SQL_NOTES))
-    DBUG_VOID_RETURN;
-
-  if (thd->query_id != thd->warn_id && !thd->spcont)
-    mysql_reset_errors(thd, 0);
-  thd->got_warning= 1;
-
-  /* Abort if we are using strict mode and we are not using IGNORE */
-  if ((int) level >= (int) MYSQL_ERROR::WARN_LEVEL_WARN &&
-      thd->really_abort_on_warning())
+  switch(level)
   {
-    /* Avoid my_message() calling push_warning */
-    bool no_warnings_for_error= thd->no_warnings_for_error;
-    sp_rcontext *spcont= thd->spcont;
-
-    thd->no_warnings_for_error= 1;
-    thd->spcont= NULL;
-
-    thd->killed= THD::KILL_BAD_DATA;
-    my_message(code, msg, MYF(0));
-
-    thd->spcont= spcont;
-    thd->no_warnings_for_error= no_warnings_for_error;
-    /* Store error in error list (as my_message() didn't do it) */
-    level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+  case MYSQL_ERROR::WARN_LEVEL_NOTE:
+    thd->raise_note(code, msg);
+    break;
+  case MYSQL_ERROR::WARN_LEVEL_WARN:
+    thd->raise_warning(code, msg);
+    break;
+  default:
+    DBUG_ASSERT(FALSE);
   }
 
-  if (thd->handle_error(code, msg, level))
-    DBUG_VOID_RETURN;
-
-  if (thd->spcont &&
-      thd->spcont->handle_error(code, level, thd))
-  {
-    DBUG_VOID_RETURN;
-  }
-  query_cache_abort(&thd->query_cache_tls);
-
-
-  if (thd->warn_list.elements < thd->variables.max_error_count)
-  {
-    /* We have to use warn_root, as mem_root is freed after each query */
-    if ((err= new (&thd->warn_root) MYSQL_ERROR(thd, code, level, msg)))
-      thd->warn_list.push_back(err, &thd->warn_root);
-  }
-  thd->warn_count[(uint) level]++;
-  thd->total_warn_count++;
   DBUG_VOID_RETURN;
 }
 
+
 /*
   Push the warning/error to error list if there is still room in the list
 
@@ -208,10 +176,12 @@ const LEX_STRING warning_level_names[]=
 };
 
 bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
-{  
+{
   List<Item> field_list;
   DBUG_ENTER("mysqld_show_warnings");
 
+  DBUG_ASSERT(thd->main_da.m_stmt_area.is_read_only());
+
   field_list.push_back(new Item_empty_string("Level", 7));
   field_list.push_back(new Item_return_int("Code",4, MYSQL_TYPE_LONG));
   field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE));
@@ -220,7 +190,7 @@ bool mysqld_show_warnings(THD *thd, ulon
                                  Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 
-  MYSQL_ERROR *err;
+  SQL_condition *cond;
   SELECT_LEX *sel= &thd->lex->select_lex;
   SELECT_LEX_UNIT *unit= &thd->lex->unit;
   ha_rows idx= 0;
@@ -228,24 +198,30 @@ bool mysqld_show_warnings(THD *thd, ulon
 
   unit->set_limit(sel);
 
-  List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
-  while ((err= it++))
+  List_iterator_fast<SQL_condition> it(thd->main_da.m_stmt_area.warn_list);
+  while ((cond= it++))
   {
     /* Skip levels that the user is not interested in */
-    if (!(levels_to_show & ((ulong) 1 << err->level)))
+    if (!(levels_to_show & ((ulong) 1 << cond->get_level())))
       continue;
     if (++idx <= unit->offset_limit_cnt)
       continue;
     if (idx > unit->select_limit_cnt)
       break;
     protocol->prepare_for_resend();
-    protocol->store(warning_level_names[err->level].str,
-		    warning_level_names[err->level].length, system_charset_info);
-    protocol->store((uint32) err->code);
-    protocol->store(err->msg, strlen(err->msg), system_charset_info);
+    protocol->store(warning_level_names[cond->get_level()].str,
+		    warning_level_names[cond->get_level()].length,
+                    system_charset_info);
+    protocol->store((uint32) cond->get_sql_errno());
+    protocol->store(cond->get_message_text(),
+                    cond->get_message_octet_length(),
+                    system_charset_info);
     if (protocol->write())
       DBUG_RETURN(TRUE);
   }
   my_eof(thd);
+
+  thd->main_da.m_stmt_area.set_read_only(FALSE);
+
   DBUG_RETURN(FALSE);
 }

=== added file 'sql/sql_fixstring.cc'
--- a/sql/sql_fixstring.cc	1970-01-01 00:00:00 +0000
+++ b/sql/sql_fixstring.cc	2008-08-27 22:14:03 +0000
@@ -0,0 +1,158 @@
+/* Copyright (C) 2008 MySQL AB
+
+   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 */
+
+#include "mysql_priv.h"
+
+Fixed_string::~Fixed_string()
+{}
+
+void Fixed_string::set(const char* str)
+{
+  set(str, strlen(str));
+}
+
+void Fixed_string::set(const char* str, size_t len)
+{
+  size_t numchars;
+  size_t to_copy;
+  CHARSET_INFO *cs= m_param->m_cs;
+  const char *end= str+len;
+
+  numchars= cs->cset->numchars(cs, str, end);
+
+  if (numchars <= m_param->m_max_char_length)
+  {
+    to_copy= len;
+    m_truncated= FALSE;
+  }
+  else
+  {
+    to_copy= cs->cset->charpos(cs, str, end, m_param->m_max_char_length);
+    m_truncated= TRUE;
+  }
+
+  reserve(to_copy + cs->mbminlen);
+  if (m_ptr)
+  {
+    m_byte_length= to_copy;
+    memcpy(m_ptr, str, to_copy);
+    add_nul(m_ptr + to_copy);
+  }
+}
+
+void Fixed_string::set(const String* str)
+{
+  set(str->ptr(), str->length(), (CHARSET_INFO*) str->charset());
+}
+
+void Fixed_string::set(const char* str, size_t len, const CHARSET_INFO *str_cs)
+{
+  uint32 dummy_offset;
+  size_t numchars;
+  size_t to_copy;
+  CHARSET_INFO *cs= m_param->m_cs;
+  const char *end= str + len;
+
+  numchars= cs->cset->numchars(cs, str, end);
+
+  if (numchars <= m_param->m_max_char_length)
+  {
+    to_copy= len;
+    m_truncated= FALSE;
+  }
+  else
+  {
+    numchars= m_param->m_max_char_length;
+    to_copy= cs->cset->charpos(cs, str, end, numchars);
+    m_truncated= TRUE;
+  }
+
+  if (String::needs_conversion(to_copy, (CHARSET_INFO*) str_cs,
+                               (CHARSET_INFO*) cs, & dummy_offset))
+  {
+    size_t dest_len= numchars * cs->mbmaxlen;
+    reserve(dest_len + cs->mbminlen);
+    if (m_ptr)
+    {
+      const char* well_formed_error_pos;
+      const char* cannot_convert_error_pos;
+      const char* from_end_pos;
+
+      m_byte_length= well_formed_copy_nchars((CHARSET_INFO *) cs,
+                                             m_ptr, dest_len,
+                                             (CHARSET_INFO*) str_cs, str, len,
+                                             numchars,
+                                             & well_formed_error_pos,
+                                             & cannot_convert_error_pos,
+                                             & from_end_pos);
+      add_nul(m_ptr + m_byte_length);
+    }
+  }
+  else
+  {
+    reserve(to_copy + cs->mbminlen);
+    if (m_ptr)
+    {
+      m_byte_length= to_copy;
+      memcpy(m_ptr, str, to_copy);
+      add_nul(m_ptr + to_copy);
+    }
+  }
+}
+
+void Fixed_string::add_nul(char *ptr)
+{
+  /*
+    Assume that the NUL character is always encoded using 0 bytes,
+    and is always using an encoding of the minimum length.
+    Verified for:
+    - UTF8 : NUL = 1 zero byte
+    - latin* : NUL = 1 zero byte
+    - UTF16 : NUL = 2 zero byte
+    - UTF32 : NUL = 4 zero byte
+  */
+  switch (m_param->m_cs->mbminlen)
+  {
+  case 4: *ptr++ = '\0'; /* fall through */
+  case 3: *ptr++ = '\0'; /* fall through */
+  case 2: *ptr++ = '\0'; /* fall through */
+  case 1: *ptr++ = '\0'; break;
+  default: DBUG_ASSERT(FALSE); break;
+  }
+}
+
+void Fixed_string::copy(const Fixed_string *str)
+{
+  DBUG_ASSERT(m_param->m_cs->number == str->m_param->m_cs->number);
+
+  set(str->m_ptr, str->m_byte_length);
+}
+
+void Fixed_string::reserve(size_t len)
+{
+  if ((m_ptr != NULL) && (m_allocated_length >= len))
+    return;
+
+  m_ptr= (char*) alloc_root(m_mem_root, len);
+  m_allocated_length= (m_ptr ? len : 0);
+}
+
+const Fixed_string_param UTF8String64::params=
+{64, & my_charset_utf8_bin };
+
+const Fixed_string_param UTF8String128::params=
+{128, & my_charset_utf8_bin };
+
+

=== added file 'sql/sql_fixstring.h'
--- a/sql/sql_fixstring.h	1970-01-01 00:00:00 +0000
+++ b/sql/sql_fixstring.h	2008-08-27 22:14:03 +0000
@@ -0,0 +1,224 @@
+/* Copyright (C) 2008 MySQL AB
+
+   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 */
+
+#ifndef SQL_FIXSTRING_H
+#define SQL_FIXSTRING_H
+
+/**
+  This structure represents the parametrized metadata used
+  in class Fixed_string.
+  The metadata consist of 'N' and 'C' in
+  VARCHAR(N) CHARACTER SET C
+  Multiple instances of Fixed_string typically share the same
+  Fixed_string_param instance.
+*/
+struct Fixed_string_param
+{
+  /**
+    Maximum length of a VARCHAR string (N), in VARCHAR(N)
+  */
+  size_t m_max_char_length;
+  /**
+    Character set of a VARCHAR string (C), in VARCHAR(N) CHARACTER SET C.
+  */
+  CHARSET_INFO *m_cs;
+};
+
+/**
+  This class represents a VARCHAR string or a given fixed maximum size,
+  and of a given fixed character set.
+  The size and character set are immutable.
+  Memory used to represent the string is allocated from a provided memory root.
+*/
+class Fixed_string
+{
+public:
+  /**
+    Constructor.
+    @param param Immutable size and character set parameters
+    @param mem_root Memory root to use to represent the string value
+  */
+  Fixed_string(const Fixed_string_param *param, MEM_ROOT *mem_root)
+    : m_param(param),
+    m_mem_root(mem_root),
+    m_byte_length(0),
+    m_allocated_length(0),
+    m_truncated(FALSE),
+    m_ptr(NULL)
+  {}
+
+  /** Destructor. */
+  ~Fixed_string();
+
+  /**
+    Set the string value.
+    @param str the value to set, expressed in the character set of
+    Fixed_string_param
+  */
+  void set(const char* str);
+
+  /**
+    Set the string value.
+    @param str the value to set, expressed in the character set of
+    Fixed_string_param
+    @param len length, in bytes, of str
+  */
+  void set(const char* str, size_t len);
+
+  /**
+    Set the string value, with character set conversion if necessary.
+    @param str the value to set, expressed in any character set
+  */
+  void set(const String* str);
+
+  /**
+    Set the string value, with character set conversion if necessary.
+    @param str the value to set, expressed in character set str_cs
+    @param len length, in bytes, of str
+    @param str_cs character set of str
+  */
+  void set(const char* str, size_t len, const CHARSET_INFO *str_cs);
+
+  /**
+    Predicate, indicates if the string is truncated to the maximum size.
+    @return true if the string is truncated
+  */
+  bool is_truncated() const
+  { return m_truncated; }
+
+  /**
+    Access to the C pointer representation of the string.
+    @return a NUL terminated C string, in the character set of
+    Fixed_string_param
+  */
+  const char* ptr() const
+  { return m_ptr; }
+
+  /**
+    Length, in bytes, of the C string representation,
+    excluding the terminating NUL character.
+    @return The string length in bytes
+  */
+  size_t length() const
+  { return m_byte_length; }
+
+  /**
+    Character set of the string.
+    @return the string character set
+  */
+  const CHARSET_INFO *charset() const
+  { return m_param->m_cs; }
+
+  /**
+    Set the string value from another Fixed_string.
+    Note that the character set of this object and of str must be equal.
+    @param str the string to copy
+  */
+  void copy(const Fixed_string *str);
+
+private:
+  /**
+    Allocate memory for the string representation.
+    @param len size in bytes to allocate
+  */
+  void reserve(size_t len);
+
+  /**
+    Add a NUL character at the end of the string.
+    @param ptr location of the NUL character
+  */
+  void add_nul(char *ptr);
+
+  /**
+    Immutable string parameters.
+    The string parameters are &lt;N&gt; and &lt;C&gt;
+    in a parametrized class 'VARCHAR(&lt;N&gt;) CHARACTER SET &lt;C&gt;'
+  */
+  const Fixed_string_param *m_param;
+
+  /**
+    Memory root to use to allocate the string value.
+  */
+  MEM_ROOT *m_mem_root;
+
+  /**
+    Length of the C string representation, in bytes,
+    excluding the terminating NUL character.
+  */
+  size_t m_byte_length;
+
+  /**
+    Size, in bytes, of the memory allocated.
+  */
+  size_t m_allocated_length;
+
+  /**
+    True if the string was truncated.
+    Note that no warnings or errors are generated,
+    the string is truncated silently.
+  */
+  bool m_truncated;
+
+  /**
+    C representation of the string, NUL terminated.
+  */
+  char * m_ptr;
+};
+
+/**
+  This class represents a 'VARCHAR(64) CHARACTER SET UTF8' string value.
+*/
+class UTF8String64 : public Fixed_string
+{
+public:
+  /**
+    Constructor.
+    @param root The memory root to use to represent the string value.
+  */
+  UTF8String64(MEM_ROOT *root)
+    : Fixed_string(& params, root)
+  {}
+
+  ~UTF8String64()
+  {}
+
+private:
+  static const Fixed_string_param params;
+};
+
+/**
+  This class represents a 'VARCHAR(128) CHARACTER SET UTF8' string value.
+*/
+class UTF8String128 : public Fixed_string
+{
+public:
+  /**
+    Constructor.
+    @param root The memory root to use to represent the string value.
+  */
+  UTF8String128(MEM_ROOT *root)
+    : Fixed_string(& params, root)
+  {}
+
+  ~UTF8String128()
+  {}
+
+private:
+  static const Fixed_string_param params;
+};
+
+#endif
+
+

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2008-07-21 03:55:09 +0000
+++ b/sql/sql_insert.cc	2008-08-27 22:14:03 +0000
@@ -2314,8 +2314,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
@@ -2325,8 +2325,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;
   }

=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h	2008-08-18 18:12:46 +0000
+++ b/sql/sql_lex.h	2008-08-27 22:14:03 +0000
@@ -122,6 +122,7 @@ enum enum_sql_command {
   SQLCOM_BACKUP_TEST,
 #endif
   SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES,
+  SQLCOM_SIGNAL, SQLCOM_RESIGNAL,
 
   /*
     When a command is added here, be sure it's also added in mysqld.cc
@@ -1510,6 +1511,64 @@ public:
   CHARSET_INFO *m_underscore_cs;
 };
 
+struct st_lex;
+
+/**
+  Abstract representation of a statement.
+  This class is an interface between the parser and the runtime.
+  The parser builds the appropriate sub classes of SQLCOM_statement
+  to represent a SQL statement in the parsed tree.
+  The execute() method in the sub classes contain the runtime implementation.
+  Note that this interface is used for SQL statement recently implemented,
+  the code for older statements tend to load the LEX structure with more
+  attributes instead.
+  The recommended way to implement new statements is to sub-class
+  SQLCOM_statement, as this improves code modularity (see the 'big switch' in
+  dispatch_command()), and decrease the total size of the LEX structure
+  (therefore saving memory in stored programs).
+*/
+class SQLCOM_statement : public Sql_alloc
+{
+public:
+  /**
+    Execute this SQL statement.
+    @param thd the current thread.
+    @return 0 on success.
+  */
+  virtual int execute(THD *thd) = 0;
+
+protected:
+  /**
+    Constructor.
+    @param lex the LEX structure that represents parts of this statement.
+  */
+  SQLCOM_statement(struct st_lex *lex)
+    : m_lex(lex)
+  {}
+
+  /** Destructor. */
+  virtual ~SQLCOM_statement()
+  {
+    /*
+      SQLCOM_statement objects are allocated in thd->mem_root.
+      In MySQL, the C++ destructor is never called, the underlying MEM_ROOT is
+      simply destroyed instead.
+      Do not rely on the destructor for any cleanup.
+    */
+    DBUG_ASSERT(FALSE);
+  }
+
+protected:
+  /**
+    The legacy LEX structure for this statement.
+    The LEX structure contains the existing properties of the parsed tree.
+    TODO: with time, attributes from LEX should move to sub classes of
+    SQLCOM_statement, so that the parser only builds SQLCOM_statement objects
+    with the minimum set of attributes, instead of a LEX structure that
+    contains the collection of every possible attribute.
+  */
+  struct st_lex *m_lex;
+};
 
 /* The state of the lex parsing. This is saved in the THD struct */
 
@@ -1612,6 +1671,9 @@ typedef struct st_lex : public Query_tab
   */
   nesting_map allow_sum_func;
   enum_sql_command sql_command;
+
+  SQLCOM_statement *m_stmt;
+
   /*
     Usually `expr` rule of yacc is quite reused but some commands better
     not support subqueries which comes standard with this rule, like
@@ -1877,6 +1939,36 @@ typedef struct st_lex : public Query_tab
 
 
 /**
+  Set_signal_information is a container used in the parsed tree to represent
+  the collection of assignments to condition items in the SIGNAL and RESIGNAL
+  statements.
+*/
+class Set_signal_information
+{
+public:
+  /** Constructor. */
+  Set_signal_information();
+
+  /** Copy constructor. */
+  Set_signal_information(const Set_signal_information& set);
+
+  /** Destructor. */
+  ~Set_signal_information()
+  {}
+
+  /** Clear all items. */
+  void clear();
+
+  /**
+    For each contition item assignment, m_item[] contains the parsed tree
+    that represents the expression assigned, if any.
+    m_item[] is an array indexed by Diag_condition_item_name.
+  */
+  Item *m_item[LAST_DIAG_SET_PROPERTY+1];
+};
+
+
+/**
   The internal state of the syntax parser.
   This object is only available during parsing,
   and is private to the syntax parser implementation (sql_yacc.yy).
@@ -1902,6 +1994,12 @@ public:
   */
   uchar *yacc_yyvs;
 
+  /**
+    Fragments of parsed tree,
+    used during the parsing of SIGNAL and RESIGNAL.
+  */
+  Set_signal_information m_set_signal_info;
+
   /*
     TODO: move more attributes from the LEX structure here.
   */

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2008-08-25 12:25:07 +0000
+++ b/sql/sql_parse.cc	2008-08-27 22:14:03 +0000
@@ -320,8 +320,8 @@ void init_update_queries(void)
   sql_command_flags[SQLCOM_SHOW_AUTHORS]= CF_STATUS_COMMAND;
   sql_command_flags[SQLCOM_SHOW_CONTRIBUTORS]= CF_STATUS_COMMAND;
   sql_command_flags[SQLCOM_SHOW_PRIVILEGES]= CF_STATUS_COMMAND;
-  sql_command_flags[SQLCOM_SHOW_WARNS]= CF_STATUS_COMMAND;
-  sql_command_flags[SQLCOM_SHOW_ERRORS]= CF_STATUS_COMMAND;
+  sql_command_flags[SQLCOM_SHOW_WARNS]= CF_STATUS_COMMAND | CF_DIAGNOSTIC_STMT;
+  sql_command_flags[SQLCOM_SHOW_ERRORS]= CF_STATUS_COMMAND | CF_DIAGNOSTIC_STMT;
   sql_command_flags[SQLCOM_SHOW_ENGINE_STATUS]= CF_STATUS_COMMAND;
   sql_command_flags[SQLCOM_SHOW_ENGINE_MUTEX]= CF_STATUS_COMMAND;
   sql_command_flags[SQLCOM_SHOW_ENGINE_LOGS]= CF_STATUS_COMMAND;
@@ -1942,8 +1942,16 @@ mysql_execute_command(THD *thd)
     variables, but for now this is probably good enough.
     Don't reset warnings when executing a stored routine.
   */
-  if ((all_tables || !lex->is_single_level_stmt()) && !thd->spcont)
-    mysql_reset_errors(thd, 0);
+  if ((sql_command_flags[lex->sql_command] & CF_DIAGNOSTIC_STMT) != 0)
+  {
+    thd->main_da.m_stmt_area.set_read_only(TRUE);
+  }
+  else
+  {
+    thd->main_da.m_stmt_area.set_read_only(FALSE);
+    if ((all_tables || !lex->is_single_level_stmt()) && !thd->spcont)
+      mysql_reset_errors(thd, 0);
+  }
 
 #ifdef HAVE_REPLICATION
   if (unlikely(thd->slave_thread))
@@ -4229,7 +4237,7 @@ create_sp_error:
           If warnings have been cleared, we have to clear total_warn_count
           too, otherwise the clients get confused.
 	 */
-	if (thd->warn_list.is_empty())
+	if (thd->main_da.m_stmt_area.warn_list.is_empty())
 	  thd->total_warn_count= 0;
 
 	thd->variables.select_limit= select_limit;
@@ -4780,6 +4788,11 @@ create_sp_error:
     my_ok(thd, 1);
     break;
   }
+  case SQLCOM_SIGNAL:
+  case SQLCOM_RESIGNAL:
+    DBUG_ASSERT(lex->m_stmt != NULL);
+    res= lex->m_stmt->execute(thd);
+    break;
   default:
 #ifndef EMBEDDED_LIBRARY
     DBUG_ASSERT(0);                             /* Impossible */

=== added file 'sql/sql_signal.cc'
--- a/sql/sql_signal.cc	1970-01-01 00:00:00 +0000
+++ b/sql/sql_signal.cc	2008-08-27 22:14:03 +0000
@@ -0,0 +1,638 @@
+/* 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 */
+
+#include "mysql_priv.h"
+#include "sp_head.h"
+#include "sp_pcontext.h"
+#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_MYSQL_ERRNO UINT_MAX16
+
+const LEX_STRING Diag_condition_item_names[]=
+{
+  { C_STRING_WITH_LEN("CLASS_ORIGIN") },
+  { C_STRING_WITH_LEN("SUBCLASS_ORIGIN") },
+  { C_STRING_WITH_LEN("CONSTRAINT_CATALOG") },
+  { C_STRING_WITH_LEN("CONSTRAINT_SCHEMA") },
+  { C_STRING_WITH_LEN("CONSTRAINT_NAME") },
+  { C_STRING_WITH_LEN("CATALOG_NAME") },
+  { C_STRING_WITH_LEN("SCHEMA_NAME") },
+  { C_STRING_WITH_LEN("TABLE_NAME") },
+  { C_STRING_WITH_LEN("COLUMN_NAME") },
+  { C_STRING_WITH_LEN("CURSOR_NAME") },
+  { C_STRING_WITH_LEN("MESSAGE_TEXT") },
+  { C_STRING_WITH_LEN("MYSQL_ERRNO") },
+
+  { C_STRING_WITH_LEN("CONDITION_IDENTIFIER") },
+  { C_STRING_WITH_LEN("CONDITION_NUMBER") },
+  { C_STRING_WITH_LEN("CONNECTION_NAME") },
+  { C_STRING_WITH_LEN("MESSAGE_LENGTH") },
+  { C_STRING_WITH_LEN("MESSAGE_OCTET_LENGTH") },
+  { C_STRING_WITH_LEN("PARAMETER_MODE") },
+  { C_STRING_WITH_LEN("PARAMETER_NAME") },
+  { C_STRING_WITH_LEN("PARAMETER_ORDINAL_POSITION") },
+  { C_STRING_WITH_LEN("RETURNED_SQLSTATE") },
+  { C_STRING_WITH_LEN("ROUTINE_CATALOG") },
+  { C_STRING_WITH_LEN("ROUTINE_NAME") },
+  { C_STRING_WITH_LEN("ROUTINE_SCHEMA") },
+  { C_STRING_WITH_LEN("SERVER_NAME") },
+  { C_STRING_WITH_LEN("SPECIFIC_NAME") },
+  { C_STRING_WITH_LEN("TRIGGER_CATALOG") },
+  { C_STRING_WITH_LEN("TRIGGER_NAME") },
+  { C_STRING_WITH_LEN("TRIGGER_SCHEMA") }
+};
+
+const LEX_STRING Diag_statement_item_names[]=
+{
+  { C_STRING_WITH_LEN("NUMBER") },
+  { C_STRING_WITH_LEN("MORE") },
+  { C_STRING_WITH_LEN("COMMAND_FUNCTION") },
+  { C_STRING_WITH_LEN("COMMAND_FUNCTION_CODE") },
+  { C_STRING_WITH_LEN("DYNAMIC_FUNCTION") },
+  { C_STRING_WITH_LEN("DYNAMIC_FUNCTION_CODE") },
+  { C_STRING_WITH_LEN("ROW_COUNT") },
+  { C_STRING_WITH_LEN("TRANSACTIONS_COMMITTED") },
+  { C_STRING_WITH_LEN("TRANSACTIONS_ROLLED_BACK") },
+  { C_STRING_WITH_LEN("TRANSACTION_ACTIVE") }
+};
+
+
+SQL_condition::SQL_condition(MEM_ROOT *mem_root)
+ : Sql_alloc(),
+   m_class_origin(mem_root),
+   m_subclass_origin(mem_root),
+   m_constraint_catalog(mem_root),
+   m_constraint_schema(mem_root),
+   m_constraint_name(mem_root),
+   m_catalog_name(mem_root),
+   m_schema_name(mem_root),
+   m_table_name(mem_root),
+   m_column_name(mem_root),
+   m_cursor_name(mem_root),
+   m_message_text(),
+   m_message_text_set(FALSE),
+   m_sql_errno(0),
+   m_level(MYSQL_ERROR::WARN_LEVEL_ERROR),
+   m_flags(0),
+   m_mem_root(mem_root)
+{
+  memset(m_returned_sqlstate, 0, sizeof(m_returned_sqlstate));
+}
+
+SQL_condition *
+SQL_condition::deep_copy(THD *thd, MEM_ROOT *mem_root,
+                         const SQL_condition *cond)
+{
+  SQL_condition *copy= new (mem_root) SQL_condition(mem_root);
+  if (copy)
+    copy->deep_copy(cond);
+  return copy;
+}
+
+void
+SQL_condition::deep_copy(const SQL_condition *cond)
+{
+  memcpy(m_returned_sqlstate, cond->m_returned_sqlstate,
+         sizeof(m_returned_sqlstate));
+
+  if (cond->m_message_text.length())
+  {
+    const char* copy;
+
+    copy= strdup_root(m_mem_root, cond->m_message_text.ptr());
+    m_message_text.set(copy, cond->m_message_text.length(),
+                       error_message_charset_info);
+  }
+  else
+    m_message_text.length(0);
+
+  DBUG_ASSERT(! m_message_text.is_alloced());
+
+  m_message_text_set= cond->m_message_text_set;
+  m_class_origin.copy(& cond->m_class_origin);
+  m_subclass_origin.copy(& cond->m_subclass_origin);
+  m_constraint_catalog.copy(& cond->m_constraint_catalog);
+  m_constraint_schema.copy(& cond->m_constraint_schema);
+  m_constraint_name.copy(& cond->m_constraint_name);
+  m_catalog_name.copy(& cond->m_catalog_name);
+  m_schema_name.copy(& cond->m_schema_name);
+  m_table_name.copy(& cond->m_table_name);
+  m_column_name.copy(& cond->m_column_name);
+  m_cursor_name.copy(& cond->m_cursor_name);
+  m_sql_errno= cond->m_sql_errno;
+  m_level= cond->m_level;
+  m_flags= cond->m_flags;
+}
+
+void
+SQL_condition::set_printf(THD *thd, uint code, const char *str,
+                          MYSQL_ERROR::enum_warning_level level,
+                          myf flags, ...)
+{
+  va_list args;
+  char ebuff[ERRMSGSIZE+20];
+
+
+  DBUG_ENTER("SQL_condition::set_printf");
+
+  va_start(args, flags);
+  (void) my_vsnprintf (ebuff, sizeof(ebuff), str, args);
+  va_end(args);
+
+  set(thd, code, ebuff, level, flags);
+
+  DBUG_VOID_RETURN;
+}
+
+void
+SQL_condition::set(THD *thd, uint code, const char *str,
+                   MYSQL_ERROR::enum_warning_level level, myf flags)
+{
+  const char* sqlstate;
+
+  /*
+    TODO: replace by DBUG_ASSERT(code != 0) once all bugs similar to
+    Bug#36760 are fixed: a SQL condition must have a real (!=0) error number
+    so that it can be caught by handlers.
+  */
+  if (code == 0)
+    code= ER_UNKNOWN_ERROR;
+  if (str == NULL)
+    str= ER(code);
+  m_sql_errno= code;
+
+  sqlstate= mysql_errno_to_sqlstate(m_sql_errno);
+  memcpy(m_returned_sqlstate, sqlstate, SQLSTATE_LENGTH);
+  m_returned_sqlstate[SQLSTATE_LENGTH]= '\0';
+
+  set_builtin_message_text(str);
+  if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
+      thd->really_abort_on_warning())
+  {
+    /*
+      FIXME:
+      push_warning and strict SQL_MODE case.
+    */
+    m_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+    thd->killed= THD::KILL_BAD_DATA;
+  }
+  else
+    m_level= level;
+  m_flags= flags;
+}
+
+void
+SQL_condition::set_builtin_message_text(const char* str)
+{
+  const char* copy;
+
+  copy= strdup_root(m_mem_root, str);
+  m_message_text.set(copy, strlen(copy), error_message_charset_info);
+  DBUG_ASSERT(! m_message_text.is_alloced());
+  m_message_text_set= TRUE;
+}
+
+const char*
+SQL_condition::get_message_text() const
+{
+  return m_message_text.ptr();
+}
+
+int
+SQL_condition::get_message_octet_length() const
+{
+  return m_message_text.length();
+}
+
+void
+SQL_condition::set_sqlstate(const char* sqlstate)
+{
+  memcpy(m_returned_sqlstate, sqlstate, SQLSTATE_LENGTH);
+  m_returned_sqlstate[SQLSTATE_LENGTH]= '\0';
+}
+
+Set_signal_information::Set_signal_information()
+{
+  clear();
+}
+
+Set_signal_information::Set_signal_information(
+  const Set_signal_information& set)
+{
+  int i;
+  for (i= FIRST_DIAG_SET_PROPERTY;
+       i <= LAST_DIAG_SET_PROPERTY;
+       i++)
+  {
+    m_item[i]= set.m_item[i];
+  }
+}
+
+void Set_signal_information::clear()
+{
+  int i;
+  for (i= FIRST_DIAG_SET_PROPERTY;
+       i <= LAST_DIAG_SET_PROPERTY;
+       i++)
+  {
+    m_item[i]= NULL;
+  }
+}
+
+int Abstract_signal::eval_sqlcode_sqlstate(THD *thd, SQL_condition *cond)
+{
+  DBUG_ASSERT(m_cond);
+  DBUG_ASSERT(cond);
+
+  /*
+    SIGNAL is restricted in sql_yacc.yy to only signal SQLSTATE conditions
+  */
+  DBUG_ASSERT(m_cond->type == sp_cond_type::state);
+  const char* sqlstate= m_cond->sqlstate;
+
+  DBUG_ASSERT((sqlstate[0] != '0') || (sqlstate[1] != '0'));
+
+  cond->set_sqlstate(sqlstate);
+
+  if ((sqlstate[0] == '0') && (sqlstate[1] == '1'))
+  {
+    /* SQLSTATE class "01": warning */
+    cond->m_level= MYSQL_ERROR::WARN_LEVEL_WARN;
+    cond->m_sql_errno= ER_SIGNAL_WARN;
+  }
+  else if ((sqlstate[0] == '0') && (sqlstate[1] == '2'))
+  {
+    /* SQLSTATE class "02": not found */
+    cond->m_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+    cond->m_sql_errno= ER_SIGNAL_NOT_FOUND;
+  }
+  else
+  {
+    cond->m_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+    cond->m_sql_errno= ER_SIGNAL_EXCEPTION;
+  }
+
+  return 0;
+}
+
+int Abstract_signal::eval_default_message_text(THD *thd, SQL_condition *cond)
+{
+  const char* sqlstate= cond->get_sqlstate();
+
+  DBUG_ASSERT((sqlstate[0] != '0') || (sqlstate[1] != '0'));
+
+  if (! cond->is_message_text_set())
+  {
+    if ((sqlstate[0] == '0') && (sqlstate[1] == '1'))
+    {
+      /* SQLSTATE class "01": warning */
+      cond->set_builtin_message_text(ER(ER_SIGNAL_WARN));
+    }
+    else if ((sqlstate[0] == '0') && (sqlstate[1] == '2'))
+    {
+      /* SQLSTATE class "02": not found */
+      cond->set_builtin_message_text(ER(ER_SIGNAL_NOT_FOUND));
+    }
+    else
+    {
+      cond->set_builtin_message_text(ER(ER_SIGNAL_EXCEPTION));
+    }
+  }
+
+  return 0;
+}
+
+int assign_condition_item(const char* name, THD *thd, Item *set,
+                          UTF8String64 *ci)
+{
+  String str_value;
+  String *str;
+
+  DBUG_ENTER("assign_condition_item");
+
+  if (set->is_null())
+  {
+    my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, "NULL");
+    DBUG_RETURN(1);
+  }
+
+  str= set->val_str(& str_value);
+  ci->set(str);
+  if (ci->is_truncated())
+  {
+    if (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES |
+                                   MODE_STRICT_ALL_TABLES))
+    {
+      my_error(ER_COND_ITEM_TOO_LONG, MYF(0), name);
+      DBUG_RETURN(1);
+    }
+
+    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                        WARN_COND_ITEM_TRUNCATED,
+                        ER(WARN_COND_ITEM_TRUNCATED),
+                        name);
+  }
+
+  DBUG_RETURN(0);
+}
+
+
+int Abstract_signal::eval_signal_informations(THD *thd, SQL_condition *cond)
+{
+  Item *set;
+  String str_value;
+  String *str;
+  int i;
+  int result= 1;
+
+  DBUG_ENTER("Abstract_signal::eval_signal_informations");
+
+  for (i= FIRST_DIAG_SET_PROPERTY;
+       i <= LAST_DIAG_SET_PROPERTY;
+       i++)
+  {
+    set= m_set_signal_information.m_item[i];
+    if (set)
+    {
+      if (! set->fixed)
+      {
+        if (set->fix_fields(thd, & set))
+          goto end;
+        m_set_signal_information.m_item[i]= set;
+      }
+    }
+  }
+
+  set= m_set_signal_information.m_item[DIAG_CLASS_ORIGIN];
+  if (set != NULL)
+  {
+    if (assign_condition_item("CLASS_ORIGIN", thd, set,
+                              & cond->m_class_origin))
+      goto end;
+  }
+
+  set= m_set_signal_information.m_item[DIAG_SUBCLASS_ORIGIN];
+  if (set != NULL)
+  {
+    if (assign_condition_item("SUBCLASS_ORIGIN", thd, set,
+                              & cond->m_subclass_origin))
+      goto end;
+  }
+
+  set= m_set_signal_information.m_item[DIAG_CONSTRAINT_CATALOG];
+  if (set != NULL)
+  {
+    if (assign_condition_item("CONSTRAINT_CATALOG", thd, set,
+                              & cond->m_constraint_catalog))
+      goto end;
+  }
+
+  set= m_set_signal_information.m_item[DIAG_CONSTRAINT_SCHEMA];
+  if (set != NULL)
+  {
+    if (assign_condition_item("CONSTRAINT_SCHEMA", thd, set,
+                              & cond->m_constraint_schema))
+      goto end;
+  }
+
+  set= m_set_signal_information.m_item[DIAG_CONSTRAINT_NAME];
+  if (set != NULL)
+  {
+    if (assign_condition_item("CONSTRAINT_NAME", thd, set,
+                              & cond->m_constraint_name))
+      goto end;
+  }
+
+  set= m_set_signal_information.m_item[DIAG_CATALOG_NAME];
+  if (set != NULL)
+  {
+    if (assign_condition_item("CATALOG_NAME", thd, set,
+                              & cond->m_catalog_name))
+      goto end;
+  }
+
+  set= m_set_signal_information.m_item[DIAG_SCHEMA_NAME];
+  if (set != NULL)
+  {
+    if (assign_condition_item("SCHEMA_NAME", thd, set,
+                              & cond->m_schema_name))
+      goto end;
+  }
+
+  set= m_set_signal_information.m_item[DIAG_TABLE_NAME];
+  if (set != NULL)
+  {
+    if (assign_condition_item("TABLE_NAME", thd, set,
+                              & cond->m_table_name))
+      goto end;
+  }
+
+  set= m_set_signal_information.m_item[DIAG_COLUMN_NAME];
+  if (set != NULL)
+  {
+    if (assign_condition_item("COLUMN_NAME", thd, set,
+                              & cond->m_column_name))
+      goto end;
+  }
+
+  set= m_set_signal_information.m_item[DIAG_CURSOR_NAME];
+  if (set != NULL)
+  {
+    if (assign_condition_item("CURSOR_NAME", thd, set,
+                              & cond->m_cursor_name))
+      goto end;
+  }
+
+  set= m_set_signal_information.m_item[DIAG_MESSAGE_TEXT];
+  if (set != NULL)
+  {
+    if (set->is_null())
+    {
+      my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "MESSAGE_TEXT", "NULL");
+      goto end;
+    }
+    /*
+      Enforce that SET MESSAGE_TEXT = <value> evaluates the value
+      as VARCHAR(128) CHARACTER SET UTF8.
+    */
+    UTF8String128 utf8_text(thd->mem_root);
+    str= set->val_str(& str_value);
+    utf8_text.set(str->ptr(), (size_t) str->length(), str->charset());
+
+    if (utf8_text.is_truncated())
+    {
+      if (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES |
+                                     MODE_STRICT_ALL_TABLES))
+      {
+        my_error(ER_COND_ITEM_TOO_LONG, MYF(0), "MESSAGE_TEXT");
+        goto end;
+      }
+
+      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                          WARN_COND_ITEM_TRUNCATED,
+                          ER(WARN_COND_ITEM_TRUNCATED),
+                          "MESSAGE_TEXT");
+    }
+
+    /*
+      Convert to the character set used with --language.
+      This code should be removed when WL#751 is implemented.
+    */
+    String converted_text;
+    converted_text.set_charset(error_message_charset_info);
+    converted_text.append(utf8_text.ptr(), utf8_text.length(),
+                          (CHARSET_INFO *) utf8_text.charset());
+    cond->set_builtin_message_text(converted_text.c_ptr_safe());
+  }
+
+  set= m_set_signal_information.m_item[DIAG_MYSQL_ERRNO];
+  if (set != NULL)
+  {
+    if (set->is_null())
+    {
+      my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "MYSQL_ERRNO", "NULL");
+      goto end;
+    }
+    longlong code= set->val_int();
+    if ((code <= 0) || (code > MAX_MYSQL_ERRNO))
+    {
+      str= set->val_str(& str_value);
+      my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0),
+               "MYSQL_ERRNO", str->c_ptr_safe());
+      goto end;
+    }
+    cond->m_sql_errno= (int) code;
+  }
+
+  /*
+    The various item->val_xxx() methods don't return an error code,
+    but flag thd in case of failure.
+  */
+  if (! thd->is_error())
+    result= 0;
+
+end:
+  for (i= FIRST_DIAG_SET_PROPERTY;
+       i <= LAST_DIAG_SET_PROPERTY;
+       i++)
+  {
+    set= m_set_signal_information.m_item[i];
+    if (set)
+    {
+      if (set->fixed)
+        set->cleanup();
+    }
+  }
+
+  DBUG_RETURN(result);
+}
+
+int Abstract_signal::raise_condition(THD *thd, SQL_condition *cond)
+{
+  int result= 1;
+
+  DBUG_ENTER("Abstract_signal::raise_condition");
+
+  DBUG_ASSERT(m_lex->query_tables == NULL);
+
+  if (m_cond != NULL)
+  {
+    if (eval_sqlcode_sqlstate(thd, cond))
+      DBUG_RETURN(result);
+  }
+
+  if (eval_signal_informations(thd, cond))
+    DBUG_RETURN(result);
+
+  if (eval_default_message_text(thd, cond))
+    DBUG_RETURN(result);
+
+  /* SIGNAL should not signal WARN_LEVEL_NOTE */
+  DBUG_ASSERT((cond->m_level == MYSQL_ERROR::WARN_LEVEL_WARN) ||
+              (cond->m_level == MYSQL_ERROR::WARN_LEVEL_ERROR));
+
+  thd->raise_condition(cond);
+
+  if (cond->m_level == MYSQL_ERROR::WARN_LEVEL_WARN)
+  {
+    my_ok(thd);
+    result= 0;
+  }
+
+  DBUG_RETURN(result);
+}
+
+int SQLCOM_signal::execute(THD *thd)
+{
+  int result= 1;
+  SQL_condition cond(thd->mem_root);
+
+  DBUG_ENTER("SQLCOM_signal::execute");
+
+  thd->main_da.reset_diagnostics_area();
+  thd->row_count_func= 0;
+  mysql_reset_errors(thd, TRUE);
+
+  result= raise_condition(thd, &cond);
+
+  DBUG_RETURN(result);
+}
+
+
+int SQLCOM_resignal::execute(THD *thd)
+{
+  SQL_condition *signaled;
+  int result= 1;
+
+  DBUG_ENTER("SQLCOM_resignal::execute");
+
+  if (! thd->spcont || ! (signaled= thd->spcont->raised_condition()))
+  {
+    my_error(ER_RESIGNAL_NO_HANDLER, MYF(0));
+    DBUG_RETURN(result);
+  }
+
+  if (m_cond == NULL)
+  {
+    /* RESIGNAL without signal_value */
+    result= raise_condition(thd, signaled);
+    DBUG_RETURN(result);
+  }
+
+  /* RESIGNAL with signal_value */
+
+  /* Make room for 2 conditions */
+  while ((thd->main_da.m_stmt_area.warn_list.elements > 0) &&
+         ((thd->main_da.m_stmt_area.warn_list.elements + 2)
+                       > thd->variables.max_error_count))
+  {
+    thd->main_da.m_stmt_area.warn_list.pop();
+  }
+
+  thd->raise_condition_no_handler(signaled);
+
+  SQL_condition new_cond(thd->mem_root);
+  new_cond.deep_copy(signaled);
+  result= raise_condition(thd, & new_cond);
+  DBUG_RETURN(result);
+}
+

=== added file 'sql/sql_signal.h'
--- a/sql/sql_signal.h	1970-01-01 00:00:00 +0000
+++ b/sql/sql_signal.h	2008-08-27 22:14:03 +0000
@@ -0,0 +1,148 @@
+/* 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 */
+
+#ifndef SQL_SIGNAL_H
+#define SQL_SIGNAL_H
+
+/**
+  Abstract_signal represents the common properties of the SIGNAL and RESIGNAL
+  statements.
+*/
+class Abstract_signal : public SQLCOM_statement
+{
+protected:
+  /**
+    Constructor.
+    @param lex the LEX structure for this statement.
+    @param cond the condition signaled if any, or NULL.
+    @param set collection of signal condition item assignments.
+  */
+  Abstract_signal(LEX *lex,
+                  const sp_cond_type_t *cond,
+                  const Set_signal_information& set)
+    : SQLCOM_statement(lex),
+      m_cond(cond),
+      m_set_signal_information(set)
+  {}
+
+  virtual ~Abstract_signal()
+  {}
+
+  /**
+    Evaluate the condition items 'MYSQL_ERRNO', 'RETURNED_SQLSTATE' and 'level'
+    default values for this statement.
+    @param thd the current thread.
+    @param cond the condition to update.
+    @return 0 on success.
+  */
+  int eval_sqlcode_sqlstate(THD *thd, SQL_condition *cond);
+
+  /**
+    Evaluate condition item 'MESSAGE_TEXT' default value.
+    @param thd the current thread.
+    @param cond the condition to update.
+    @return 0 on success.
+  */
+  int eval_default_message_text(THD *thd, SQL_condition *cond);
+
+  /**
+    Evaluate each signal condition items for this statement.
+    @param thd the current thread.
+    @param cond the condition to update.
+    @return 0 on success.
+  */
+  int eval_signal_informations(THD *thd, SQL_condition *cond);
+
+  /**
+    Raise a SQL condition.
+    @param thd the current thread.
+    @param cond the condition to raise.
+    @return 0 on success.
+  */
+  int raise_condition(THD *thd, SQL_condition *cond);
+
+  /**
+    The condition to signal or resignal.
+    This member is optional and can be NULL (RESIGNAL).
+  */
+  const sp_cond_type_t *m_cond;
+
+  /**
+    Collection of 'SET item = value' assignments in the
+    SIGNAL/RESIGNAL statement.
+  */
+  Set_signal_information m_set_signal_information;
+};
+
+/**
+  SQLCOM_signal represents a SIGNAL statement.
+*/
+class SQLCOM_signal : public Abstract_signal
+{
+public:
+  /**
+    Constructor, used to represent a SIGNAL statement.
+    @param lex the LEX structure for this statement.
+    @param cond the SQL condition to signal (required).
+    @param set the collection of signal informations to signal.
+  */
+  SQLCOM_signal(LEX *lex,
+                const sp_cond_type_t *cond,
+                const Set_signal_information& set)
+    : Abstract_signal(lex, cond, set)
+  {}
+
+  virtual ~SQLCOM_signal()
+  {}
+
+  /**
+    Execute a SIGNAL statement at runtime.
+    @param thd the current thread.
+    @return 0 on success.
+  */
+  virtual int execute(THD *thd);
+};
+
+/**
+  SQLCOM_resignal represents a RESIGNAL statement.
+*/
+class SQLCOM_resignal : public Abstract_signal
+{
+public:
+  /**
+    Constructor, used to represent a RESIGNAL statement.
+    @param lex the LEX structure for this statement.
+    @param cond the SQL condition to resignal (optional, may be NULL).
+    @param set the collection of signal informations to resignal.
+  */
+  SQLCOM_resignal(LEX *lex,
+                  const sp_cond_type_t *cond,
+                  const Set_signal_information& set)
+    : Abstract_signal(lex, cond, set)
+  {}
+
+  virtual ~SQLCOM_resignal()
+  {}
+
+  /**
+    Execute a RESIGNAL statement at runtime.
+    @param thd the current thread.
+    @return 0 on success.
+  */
+  virtual int execute(THD *thd);
+};
+
+#endif
+

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2008-08-25 18:23:18 +0000
+++ b/sql/sql_table.cc	2008-08-27 22:14:03 +0000
@@ -3537,7 +3537,7 @@ bool mysql_create_table_no_lock(THD *thd
 
   /* Give warnings for not supported table options */
   if (create_info->transactional && !file->ht->commit)
-    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                         ER_ILLEGAL_HA_CREATE_OPTION,
                         ER(ER_ILLEGAL_HA_CREATE_OPTION),
                         file->engine_name()->str,
@@ -4244,7 +4244,7 @@ static bool mysql_admin_table(THD* thd, 
     if (!table->table)
     {
       DBUG_PRINT("admin", ("open table failed"));
-      if (!thd->warn_list.elements)
+      if (!thd->main_da.m_stmt_area.warn_list.elements)
         push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                      ER_CHECK_NO_SUCH_TABLE, ER(ER_CHECK_NO_SUCH_TABLE));
       /* if it was a view will check md5 sum */
@@ -4352,17 +4352,17 @@ send_result:
     lex->cleanup_after_one_table_open();
     thd->clear_error();  // these errors shouldn't get client
     {
-      List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
-      MYSQL_ERROR *err;
-      while ((err= it++))
+      List_iterator_fast<SQL_condition> it(thd->main_da.m_stmt_area.warn_list);
+      SQL_condition *cond;
+      while ((cond= it++))
       {
         protocol->prepare_for_resend();
         protocol->store(table_name, system_charset_info);
         protocol->store((char*) operator_name, system_charset_info);
-        protocol->store(warning_level_names[err->level].str,
-                        warning_level_names[err->level].length,
+        protocol->store(warning_level_names[cond->get_level()].str,
+                        warning_level_names[cond->get_level()].length,
                         system_charset_info);
-        protocol->store(err->msg, system_charset_info);
+        protocol->store(cond->get_message_text(), system_charset_info);
         if (protocol->write())
           goto err;
       }

=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc	2008-07-15 16:29:51 +0000
+++ b/sql/sql_view.cc	2008-08-27 22:14:03 +0000
@@ -482,7 +482,7 @@ bool mysql_create_view(THD *thd, TABLE_L
         strcmp(tbl->view_db.str, view->db) == 0 &&
         strcmp(tbl->view_name.str, view->table_name) == 0)
     {
-      my_error(ER_NO_SUCH_TABLE, MYF(0), tbl->view_db.str, tbl->view_name.str);
+      thd->raise_ER_NO_SUCH_TABLE(tbl->view_db.str, tbl->view_name.str);
       res= TRUE;
       goto err;
     }
@@ -935,7 +935,7 @@ loop_out:
    {
       if (mode == VIEW_ALTER)
       {
-	my_error(ER_NO_SUCH_TABLE, MYF(0), view->db, view->alias);
+        thd->raise_ER_NO_SUCH_TABLE(view->db, view->alias);
         error= -1;
         goto err;
       }

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2008-08-20 10:34:46 +0000
+++ b/sql/sql_yacc.yy	2008-08-27 22:14:03 +0000
@@ -43,6 +43,7 @@
 #include "sp_pcontext.h"
 #include "sp_rcontext.h"
 #include "sp.h"
+#include "sql_signal.h"
 #include "event_parse_data.h"
 #include <myisam.h>
 #include <myisammrg.h>
@@ -582,6 +583,7 @@ bool setup_select_in_parentheses(LEX *le
   enum enum_filetype filetype;
   enum ha_build_method build_method;
   enum Foreign_key::fk_option m_fk_option;
+  Diag_condition_item_name diag_condition_item_name;
 }
 
 %{
@@ -663,6 +665,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  CASCADED                      /* SQL-2003-R */
 %token  CASE_SYM                      /* SQL-2003-R */
 %token  CAST_SYM                      /* SQL-2003-R */
+%token  CATALOG_NAME_SYM              /* SQL-2003-N */
 %token  CHAIN_SYM                     /* SQL-2003-N */
 %token  CHANGE
 %token  CHANGED
@@ -671,6 +674,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  CHECKSUM_SYM
 %token  CHECK_SYM                     /* SQL-2003-R */
 %token  CIPHER_SYM
+%token  CLASS_ORIGIN_SYM              /* SQL-2003-N */
 %token  CLIENT_SYM
 %token  CLOSE_SYM                     /* SQL-2003-R */
 %token  COALESCE                      /* SQL-2003-N */
@@ -679,6 +683,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  COLLATION_SYM                 /* SQL-2003-N */
 %token  COLUMNS
 %token  COLUMN_SYM                    /* SQL-2003-R */
+%token  COLUMN_NAME_SYM               /* SQL-2003-N */
 %token  COMMENT_SYM
 %token  COMMITTED_SYM                 /* SQL-2003-N */
 %token  COMMIT_SYM                    /* SQL-2003-R */
@@ -688,10 +693,13 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  COMPRESSION_SYM
 %token  COMPRESSION_ALGORITHM_SYM
 %token  CONCURRENT
-%token  CONDITION_SYM                 /* SQL-2003-N */
+%token  CONDITION_SYM                 /* SQL-2003-R, SQL-2008-R */
 %token  CONNECTION_SYM
 %token  CONSISTENT_SYM
 %token  CONSTRAINT                    /* SQL-2003-R */
+%token  CONSTRAINT_CATALOG_SYM        /* SQL-2003-N */
+%token  CONSTRAINT_NAME_SYM           /* SQL-2003-N */
+%token  CONSTRAINT_SCHEMA_SYM         /* SQL-2003-N */
 %token  CONTAINS_SYM                  /* SQL-2003-N */
 %token  CONTEXT_SYM
 %token  CONTINUE_SYM                  /* SQL-2003-R */
@@ -705,6 +713,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  CURDATE                       /* MYSQL-FUNC */
 %token  CURRENT_USER                  /* SQL-2003-R */
 %token  CURSOR_SYM                    /* SQL-2003-R */
+%token  CURSOR_NAME_SYM               /* SQL-2003-N */
 %token  CURTIME                       /* MYSQL-FUNC */
 %token  DATABASE
 %token  DATABASES
@@ -908,6 +917,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  MEDIUM_SYM
 %token  MEMORY_SYM
 %token  MERGE_SYM                     /* SQL-2003-R */
+%token  MESSAGE_TEXT_SYM              /* SQL-2003-N */
 %token  MICROSECOND_SYM               /* MYSQL-FUNC */
 %token  MIGRATE_SYM
 %token  MINUTE_MICROSECOND_SYM
@@ -924,6 +934,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  MULTIPOINT
 %token  MULTIPOLYGON
 %token  MUTEX_SYM
+%token  MYSQL_ERRNO_SYM
 %token  NAMES_SYM                     /* SQL-2003-N */
 %token  NAME_SYM                      /* SQL-2003-N */
 %token  NATIONAL_SYM                  /* SQL-2003-R */
@@ -1028,6 +1039,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  REPLICATION
 %token  REQUIRE_SYM
 %token  RESET_SYM
+%token  RESIGNAL_SYM                  /* SQL-2003-R */
 %token  RESOURCES
 %token  RESTORE_SYM
 %token  RESTRICT
@@ -1046,6 +1058,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  RTREE_SYM
 %token  SAVEPOINT_SYM                 /* SQL-2003-R */
 %token  SCHEDULE_SYM
+%token  SCHEMA_NAME_SYM               /* SQL-2003-N */
 %token  SECOND_MICROSECOND_SYM
 %token  SECOND_SYM                    /* SQL-2003-R */
 %token  SECURITY_SYM                  /* SQL-2003-N */
@@ -1064,6 +1077,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  SHIFT_RIGHT                   /* OPERATOR */
 %token  SHOW
 %token  SHUTDOWN
+%token  SIGNAL_SYM                    /* SQL-2003-R */
 %token  SIGNED_SYM
 %token  SIMPLE_SYM                    /* SQL-2003-N */
 %token  SLAVE
@@ -1097,6 +1111,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  STORAGE_SYM
 %token  STRAIGHT_JOIN
 %token  STRING_SYM
+%token  SUBCLASS_ORIGIN_SYM           /* SQL-2003-N */
 %token  SUBDATE_SYM
 %token  SUBJECT_SYM
 %token  SUBPARTITIONS_SYM
@@ -1113,6 +1128,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  TABLE_REF_PRIORITY
 %token  TABLE_SYM                     /* SQL-2003-R */
 %token  TABLE_CHECKSUM_SYM
+%token  TABLE_NAME_SYM                /* SQL-2003-N */
 %token  TEMPORARY                     /* SQL-2003-N */
 %token  TEMPTABLE_SYM
 %token  TERMINATED
@@ -1291,6 +1307,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
         function_call_nonkeyword
         function_call_generic
         function_call_conflict
+        signal_allowed_expr
 
 %type <item_num>
         NUM_literal
@@ -1425,7 +1442,7 @@ END_OF_INPUT
 %type <NONE> case_stmt_specification simple_case_stmt searched_case_stmt
 
 %type <num>  sp_decl_idents sp_opt_inout sp_handler_type sp_hcond_list
-%type <spcondtype> sp_cond sp_hcond
+%type <spcondtype> sp_cond sp_hcond sqlstate signal_value opt_signal_value
 %type <spblock> sp_decls sp_decl
 %type <lex> sp_cursor_stmt
 %type <spname> sp_name
@@ -1433,6 +1450,9 @@ END_OF_INPUT
 %type <num> index_hint_clause
 %type <filetype> data_or_xml
 
+%type <NONE> signal_stmt resignal_stmt
+%type <diag_condition_item_name> signal_condition_information_item_name
+
 %type <NONE>
         '-' '+' '*' '/' '%' '(' ')'
         ',' '!' '{' '}' '&' '|' AND_SYM OR_SYM OR_OR_SYM BETWEEN_SYM CASE_SYM
@@ -1553,12 +1573,14 @@ statement:
         | repair
         | replace
         | reset
+        | resignal_stmt
         | restore
         | revoke
         | rollback
         | savepoint
         | select
         | set
+        | signal_stmt
         | show
         | slave
         | start
@@ -2638,7 +2660,11 @@ sp_cond:
             $$->type= sp_cond_type_t::number;
             $$->mysqlerr= $1;
           }
-        | SQLSTATE_SYM opt_value TEXT_STRING_literal
+        | sqlstate
+        ;
+
+sqlstate:
+          SQLSTATE_SYM opt_value TEXT_STRING_literal
           { /* SQLSTATE */
             if (!sp_cond_check(&$3))
             {
@@ -2649,8 +2675,8 @@ sp_cond:
             if ($$ == NULL)
               MYSQL_YYABORT;
             $$->type= sp_cond_type_t::state;
-            memcpy($$->sqlstate, $3.str, 5);
-            $$->sqlstate[5]= '\0';
+            memcpy($$->sqlstate, $3.str, SQLSTATE_LENGTH);
+            $$->sqlstate[SQLSTATE_LENGTH]= '\0';
           }
         ;
 
@@ -2696,6 +2722,162 @@ sp_hcond:
           }
         ;
 
+signal_stmt:
+          SIGNAL_SYM signal_value opt_set_signal_information
+          {
+            THD *thd= YYTHD;
+            LEX *lex= thd->lex;
+            Yacc_state *state= & thd->m_parser_state->m_yacc;
+
+            lex->sql_command= SQLCOM_SIGNAL;
+            lex->m_stmt= new (thd->mem_root) SQLCOM_signal(lex, 
+                                                           $2,
+                                                           state->m_set_signal_info);
+            if (lex->m_stmt == NULL)
+              MYSQL_YYABORT;
+          }
+        ;
+
+signal_value:
+          ident
+          {
+            LEX *lex= Lex;
+            sp_cond_type_t *cond;
+            if (lex->spcont == NULL)
+            {
+              /* SIGNAL foo cannot be used outside of stored programs */
+              my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str);
+              MYSQL_YYABORT;
+            }
+            cond= lex->spcont->find_cond(&$1);
+            if (cond == NULL)
+            {
+              my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str);
+              MYSQL_YYABORT;
+            }
+            if (cond->type != sp_cond_type_t::state)
+            {
+              my_error(ER_SIGNAL_BAD_CONDITION_TYPE, MYF(0));
+              MYSQL_YYABORT;
+            }
+            $$= cond;
+          }
+        | sqlstate
+          { $$= $1; }
+        ;
+
+opt_signal_value:
+          /* empty */
+          { $$= NULL; }
+        | signal_value
+          { $$= $1; }
+        ;
+
+opt_set_signal_information:
+          /* empty */
+          {
+            YYTHD->m_parser_state->m_yacc.m_set_signal_info.clear();
+          }
+        | SET signal_information_item_list
+        ;
+
+signal_information_item_list:
+          signal_condition_information_item_name EQ signal_allowed_expr
+          {
+            Set_signal_information *info;
+            info= & YYTHD->m_parser_state->m_yacc.m_set_signal_info;
+            int index= (int) $1;
+            info->clear();
+            info->m_item[index]= $3;
+          }
+        | signal_information_item_list ','
+          signal_condition_information_item_name EQ signal_allowed_expr
+          {
+            Set_signal_information *info;
+            info= & YYTHD->m_parser_state->m_yacc.m_set_signal_info;
+            int index= (int) $3;
+            if (info->m_item[index] != NULL)
+            {
+              my_error(ER_DUP_SIGNAL_SET, MYF(0),
+                       Diag_condition_item_names[index].str);
+              MYSQL_YYABORT;
+            }
+            info->m_item[index]= $5;
+          }
+        ;
+
+/*
+  Only a limited subset of <expr> are allowed in SIGNAL/RESIGNAL.
+*/
+signal_allowed_expr:
+          literal
+          { $$= $1; }
+        | variable
+          {
+            if ($1->type() == Item::FUNC_ITEM)
+            {
+              Item_func *item= (Item_func*) $1;
+              if (item->functype() == Item_func::SUSERVAR_FUNC)
+              {
+                /*
+                  Don't allow the following syntax:
+                    SIGNAL/RESIGNAL ...
+                    SET <signal condition item name> = @foo := expr
+                */
+                my_parse_error(ER(ER_SYNTAX_ERROR));
+                MYSQL_YYABORT;
+              }
+            }
+            $$= $1;
+          }
+        | simple_ident
+          { $$= $1; }
+        ;
+
+/* conditions that can be set in signal / resignal */
+signal_condition_information_item_name:
+          CLASS_ORIGIN_SYM
+          { $$= DIAG_CLASS_ORIGIN; }
+        | SUBCLASS_ORIGIN_SYM
+          { $$= DIAG_SUBCLASS_ORIGIN; }
+        | CONSTRAINT_CATALOG_SYM
+          { $$= DIAG_CONSTRAINT_CATALOG; }
+        | CONSTRAINT_SCHEMA_SYM
+          { $$= DIAG_CONSTRAINT_SCHEMA; }
+        | CONSTRAINT_NAME_SYM
+          { $$= DIAG_CONSTRAINT_NAME; }
+        | CATALOG_NAME_SYM
+          { $$= DIAG_CATALOG_NAME; }
+        | SCHEMA_NAME_SYM
+          { $$= DIAG_SCHEMA_NAME; }
+        | TABLE_NAME_SYM
+          { $$= DIAG_TABLE_NAME; }
+        | COLUMN_NAME_SYM
+          { $$= DIAG_COLUMN_NAME; }
+        | CURSOR_NAME_SYM
+          { $$= DIAG_CURSOR_NAME; }
+        | MESSAGE_TEXT_SYM
+          { $$= DIAG_MESSAGE_TEXT; }
+        | MYSQL_ERRNO_SYM
+          { $$= DIAG_MYSQL_ERRNO; }
+        ;
+
+resignal_stmt:
+          RESIGNAL_SYM opt_signal_value opt_set_signal_information
+          {
+            THD *thd= YYTHD;
+            LEX *lex= thd->lex;
+            Yacc_state *state= & thd->m_parser_state->m_yacc;
+
+            lex->sql_command= SQLCOM_RESIGNAL;
+            lex->m_stmt= new (thd->mem_root) SQLCOM_resignal(lex, 
+                                                             $2,
+                                                             state->m_set_signal_info);
+            if (lex->m_stmt == NULL)
+              MYSQL_YYABORT;
+          }
+        ;
+
 sp_decl_idents:
           ident
           {
@@ -11768,14 +11950,17 @@ keyword_sp:
         | BOOLEAN_SYM              {}
         | BTREE_SYM                {}
         | CASCADED                 {}
+        | CATALOG_NAME_SYM         {}
         | CHAIN_SYM                {}
         | CHANGED                  {}
         | CIPHER_SYM               {}
         | CLIENT_SYM               {}
+        | CLASS_ORIGIN_SYM         {}
         | COALESCE                 {}
         | CODE_SYM                 {}
         | COLLATION_SYM            {}
         | COLUMN_FORMAT_SYM        {}
+        | COLUMN_NAME_SYM          {}
         | COLUMNS                  {}
         | COMMITTED_SYM            {}
         | COMPACT_SYM              {}
@@ -11786,10 +11971,14 @@ keyword_sp:
         | CONCURRENT               {}
         | CONNECTION_SYM           {}
         | CONSISTENT_SYM           {}
+        | CONSTRAINT_CATALOG_SYM   {}
+        | CONSTRAINT_SCHEMA_SYM    {}
+        | CONSTRAINT_NAME_SYM      {}
         | CONTEXT_SYM              {}
         | CONTRIBUTORS_SYM         {}
         | CPU_SYM                  {}
         | CUBE_SYM                 {}
+        | CURSOR_NAME_SYM          {}
         | DATA_SYM                 {}
         | DATAFILE_SYM             {}
         | DATETIME                 {}
@@ -11881,6 +12070,7 @@ keyword_sp:
         | MEDIUM_SYM               {}
         | MEMORY_SYM               {}
         | MERGE_SYM                {}
+        | MESSAGE_TEXT_SYM         {}
         | MICROSECOND_SYM          {}
         | MIGRATE_SYM              {}
         | MINUTE_SYM               {}
@@ -11892,6 +12082,7 @@ keyword_sp:
         | MULTIPOINT               {}
         | MULTIPOLYGON             {}
         | MUTEX_SYM                {}
+        | MYSQL_ERRNO_SYM          {}
         | NAME_SYM                 {}
         | NAMES_SYM                {}
         | NATIONAL_SYM             {}
@@ -11956,6 +12147,7 @@ keyword_sp:
         | ROW_SYM                  {}
         | RTREE_SYM                {}
         | SCHEDULE_SYM             {}
+        | SCHEMA_NAME_SYM          {}
         | SECOND_SYM               {}
         | SERIAL_SYM               {}
         | SERIALIZABLE_SYM         {}
@@ -11974,6 +12166,7 @@ keyword_sp:
         | STATUS_SYM               {}
         | STORAGE_SYM              {}
         | STRING_SYM               {}
+        | SUBCLASS_ORIGIN_SYM      {}
         | SUBDATE_SYM              {}
         | SUBJECT_SYM              {}
         | SUBPARTITION_SYM         {}
@@ -11982,6 +12175,7 @@ keyword_sp:
         | SUSPEND_SYM              {}
         | SWAPS_SYM                {}
         | SWITCHES_SYM             {}
+        | TABLE_NAME_SYM           {}
         | TABLES                   {}
         | TABLE_CHECKSUM_SYM       {}
         | TABLESPACE               {}

=== modified file 'sql/table.cc'
--- a/sql/table.cc	2008-08-07 03:05:33 +0000
+++ b/sql/table.cc	2008-08-27 22:14:03 +0000
@@ -2304,7 +2304,7 @@ void open_table_error(TABLE_SHARE *share
   case 7:
   case 1:
     if (db_errno == ENOENT)
-      my_error(ER_NO_SUCH_TABLE, MYF(0), share->db.str, share->table_name.str);
+      current_thd->raise_ER_NO_SUCH_TABLE(share->db.str, share->table_name.str);
     else
     {
       strxmov(buff, share->normalized_path.str, reg_ext, NullS);

=== modified file 'sql/thr_malloc.cc'
--- a/sql/thr_malloc.cc	2008-08-18 18:12:46 +0000
+++ b/sql/thr_malloc.cc	2008-08-27 22:14:03 +0000
@@ -44,9 +44,9 @@ extern "C" {
           returned in the error packet.
           - SHOW ERROR/SHOW WARNINGS may be empty.
         */
-        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));
       }
     }
   }

=== modified file 'sql/unireg.cc'
--- a/sql/unireg.cc	2008-07-24 11:33:35 +0000
+++ b/sql/unireg.cc	2008-08-27 22:14:03 +0000
@@ -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->get_sql_errno() == ER_TOO_MANY_FIELDS);
   return is_handled;
 }
 

Thread
bzr commit into mysql-6.0-wl2110-review branch (marc.alff:2698) Bug#11661WL#2110 WL#2265Marc Alff28 Aug
  • Re: bzr commit into mysql-6.0-wl2110-review branch (marc.alff:2698)Bug#11661 WL#2110 WL#2265Davi Arnaut13 Sep