Hi Marc,
Here goes some more review comments.
Marc Alff wrote:
> #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
Line should start with a tab.
>
> 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_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
> +#
Please add a --echo in front of each of those headings:
--echo #
--echo # Test the SIGNAL syntax
--echo #
So that it is easier to read the test result file.
> +--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 $$
Please add tests to ensure that we accept standard conforming condition
names and reject non-conforming ones. For example, with non-ASCII
(latin1, utf8, etc) condition names:
SIGNAL abcéíóabc;
SIGNAL `abcéíóabc`;
and so on...
> +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 $$
Please also test other forms of the single value specification..
> +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;
Why we don't support the syntax of signed literal numbers?
> +
> +--error 65535
> +SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 65535;
> +
> +#
> +# RESIGNAL can also appear in a query
> +#
Wouldn't it be better to return a single error (ER_OUSIDE_COMPOUND_STMT)
every time it appears in a query so that it is clear to the user that the
problem is that RESIGNAL is not allowed outside compound statements?
> +--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 $$
Please remove these and others unused tests.
> +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
Remove reference, Bug#36457 is fixed now.
> +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;
> +
>
[..]
I'll take a look at the other signal test cases later.
> === 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
Why was sql_fixstring.h added twice?
> 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)
static void
> +{
> + 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"
I would prefer if the header was included where it is needed..
> #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;
> }
Please remove these flags. If we are defaulting ME_JUST_INFO and
ME_JUST_WARNING to sql_print_information and sql_print_warning, we
better substitute the places were these flags are used with direct
calls. If the engine can hack its way to the server, we can hack it back.
We better do it now before it becomes part of the API/ABI.
> 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)) ||
mem_root is the permanent memory root of the stored procedure..
> 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) ;
Allocating the condition on the (permanent) memory root of the stored
procedure is a huge memory leak. It can be exploited with a continue
handler:
--
delimiter $$;
create procedure test_signal()
begin
declare continue handler for sqlstate 'HY000' begin end;
while 1 do
signal sqlstate 'HY000';
end while;
end $$
delimiter ;$$
call test_signal();
--
delimiter $$;
create procedure test_signal()
begin
declare continue handler for sqlstate 'HY000' begin end;
signal sqlstate 'HY000';
end $$
delimiter ;$$
while (1)
{
call test_signal();
}
--
I think we should stick to allocating conditions from warn_root as this
ensures a proper lifetime for the conditions and avoids the need for
back-and-forth copying of the conditions. Lets discuss this on IRC.
> + 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)
Not good, this means that we will have to allocate a condition before
it's decided whether it will be pushed in the stack. More on this later
in this e-mail.
> {
> - 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;
> +}
> +
Most of these changes to the sp_rcontext are just work around and would
probably be dropped once Bug#23032 is pushed.
Bug#23032 is definitely a prerequisite, it should be pushed before this.
But on the other hand, we should not delay this work due to it.
Let's discuss on IRC how we can get Bug#23032 pushed ASAP.
> 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");
What are you trying to accomplish here?
> 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));
Remove unnecessary cast.
> +}
> +
> /**
> 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);
memcpy
> + 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;
> +}
The intention in those raise_* functions is good, but the necessary
copying and double allocation of each SQL_condition is not so good as we
are wasting resources. We rather should delay the allocation of SQL
conditions until it's sure that the condition is going to be pushed up
in the stack, similar to the old push_warning way:
void THD::raise_warning(uint code, const char *msg)
{
raise_condition(code, MYSQL_ERROR::WARN_LEVEL_WARN, msg, ...);
}
and raise_condition would perform the checks using code, level and
message and if the condition is to be pushed, it would call
raise_condition_no_handler which would in turn allocate the condition.
Another point, what was the reason to attach those functions to the THD
class? I guess they would be better as independent functions
(my_warning(), my_note()) or be part of the DA. In any case, the
implementation of raise_condition looks like something that should be
confined to the DA.
> +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.
> */
You need to fix the above comment to reflect the fact that we don't
check if there is a handler for an SQL exception condition. My patch for
Bug#23032 has a fix for this.
> - 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).
contition -> condition
> +*/
> +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.
No.. we need a generic way to pass attributes.
> + */
> + 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.
None of this is necessary if we allocate conditions from warn_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. */
Please document that since you unified the representation of errors,
warnings and notes (from MYSQL_ERROR to SQL_condition), you preserved
the current character set, retrieved from the errmsg.sys file, of the
message text as to be able to use SQL_condition as a unified form to
represent all types of SQL conditions (whether it comes from my_error or
from a signal). And once we implement GET DIAGNOSTICS, it will be
necessary to retrieve the message/charset from the condition and convert
it to UTF8.
> + String m_message_text;
I think it's overkill to use String here as you don't modify the string
and all that is needed is a pointer to the string and it's length.
> + /**
> + 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;
uint 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));
memset
> + }
> +
> + /** 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;
Whats up with the enormous amount of spaces? Same applies for warn_count
above.
> +
> + /**
> + 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;
Please move end_partial_result_set to sp_rcontext as this bloats the THD
class a bit without a good reason. Also please add the following comment
to it:
/*
End a open result set before start executing a continue/exit
handler if one is found as otherwise the client will hang
due to a violation of the client/server protocol.
*/
> +
> 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);
> + }
We definitely need something more generic to push errors which has
attributes (TABLE_NAME, etc) associated to it. For now, please drop this
as this is more related to GET DIAGNOSTICS then to SIGNAL.
> + /**
> + 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));
This might be a multi-byte string, not a good idea to use strlen at this
level.
> +}
> +
> +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);
I think that what you meant here is:
numchars= str_cs->cset->numchars(str_cs, str, end);
The number of characters should be calculated using the character set of
the passed string and not the (possibly different) character set of the
final string.
Test case:
delimiter $$;
create procedure test_resignal()
begin
DECLARE warn CONDITION FOR SQLSTATE "01111";
SIGNAL warn SET MESSAGE_TEXT = 'á a';
end $$
call test_resignal() $$
show warnings $$
> + 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 the length of the passed string is zero (str = NULL, len = 0), a
wasteful one byte allocation is made (or worse depending on the value of
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 <N> and <C>
> + in a parametrized class 'VARCHAR(<N>) CHARACTER SET
> <C>'
> + */
> + 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);
Again, MESSAGE_TEXT should be UTF8 as stated in the high-level
specification.
> + 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;
Function should return nothing (void) if it always returns 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;
Function should return nothing (void) if it always returns 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);
Why not use raise_warning_printf? :)
> + }
> +
> + 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))
Is MAX_MYSQL_ERRNO a reserved code?
> + {
> + 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;
> }
>
>