List:Commits« Previous MessageNext Message »
From:Jon Olav Hauglid Date:October 13 2011 12:52pm
Subject:bzr push into mysql-trunk branch (jon.hauglid:3321 to 3322) WL#5986
View as plain text  
 3322 Jon Olav Hauglid	2011-10-13 [merge]
      Temporary merge of WL#5986 from mysql-trunk-alik
      to mysql-trunk-wl2111-new for pushbuild testing.

    modified:
      mysql-test/r/get_diagnostics.result
      mysql-test/r/signal.result
      mysql-test/r/sp-code.result
      mysql-test/r/sp-error.result
      mysql-test/r/sp.result
      mysql-test/suite/funcs_1/r/innodb_storedproc_02.result
      mysql-test/suite/funcs_1/r/memory_storedproc_02.result
      mysql-test/suite/funcs_1/r/myisam_storedproc_02.result
      mysql-test/suite/funcs_1/r/storedproc.result
      mysql-test/t/sp-error.test
      mysql-test/t/sp.test
      sql/item_xmlfunc.cc
      sql/sp_head.cc
      sql/sp_head.h
      sql/sp_pcontext.cc
      sql/sp_pcontext.h
      sql/sp_rcontext.cc
      sql/sp_rcontext.h
      sql/sql_array.h
      sql/sql_class.cc
      sql/sql_class.h
      sql/sql_error.cc
      sql/sql_error.h
      sql/sql_signal.cc
      sql/sql_yacc.yy
 3321 Jon Olav Hauglid	2011-10-13 [merge]
      Merge from mysql-trunk to mysql-trunk-wl2111-new

    removed:
      mysql-test/collections/default.release
      mysql-test/extra/rpl_tests/rpl_insert_duplicate.test
      mysql-test/r/join_cache_bka_nobnl.result
      mysql-test/r/join_nested_bka_nobnl.result
      mysql-test/r/join_outer_bka_nobnl.result
      mysql-test/r/select_all_bka_nobnl.result
      mysql-test/r/select_icp_mrr_bka_nobnl.result
      mysql-test/r/select_none_bka_nobnl.result
      mysql-test/r/subquery_all_bka_nobnl.result
      mysql-test/r/subquery_nomat_nosj_bka_nobnl.result
      mysql-test/r/subquery_none_bka_nobnl.result
      mysql-test/r/subquery_sj_all_bka_nobnl.result
      mysql-test/r/subquery_sj_dupsweed_bka_nobnl.result
      mysql-test/r/subquery_sj_firstmatch_bka_nobnl.result
      mysql-test/r/subquery_sj_innodb_all_bka_nobnl.result
      mysql-test/r/subquery_sj_innodb_none_bka_nobnl.result
      mysql-test/r/subquery_sj_loosescan_bka_nobnl.result
      mysql-test/r/subquery_sj_mat_bka_nobnl.result
      mysql-test/r/subquery_sj_none_bka_nobnl.result
      mysql-test/std_data/bug57108.cnf
      mysql-test/suite/rpl/r/rpl_insert_duplicate.result
      mysql-test/suite/rpl/r/rpl_insert_select.result
      mysql-test/suite/rpl/t/rpl_insert_duplicate.test
      mysql-test/suite/rpl/t/rpl_insert_select.test
      mysql-test/t/join_cache_bka_nobnl.test
      mysql-test/t/join_nested_bka_nobnl.test
      mysql-test/t/join_outer_bka_nobnl.test
      mysql-test/t/select_all_bka_nobnl.test
      mysql-test/t/select_icp_mrr_bka_nobnl.test
      mysql-test/t/select_none_bka_nobnl.test
      mysql-test/t/subquery_all_bka_nobnl.test
      mysql-test/t/subquery_nomat_nosj_bka_nobnl.test
      mysql-test/t/subquery_none_bka_nobnl.test
      mysql-test/t/subquery_sj_all_bka_nobnl.test
      mysql-test/t/subquery_sj_dupsweed_bka_nobnl.test
      mysql-test/t/subquery_sj_firstmatch_bka_nobnl.test
      mysql-test/t/subquery_sj_innodb_all_bka_nobnl.test
      mysql-test/t/subquery_sj_innodb_none_bka_nobnl.test
      mysql-test/t/subquery_sj_loosescan_bka_nobnl.test
      mysql-test/t/subquery_sj_mat_bka_nobnl.test
      mysql-test/t/subquery_sj_none_bka_nobnl.test
      scripts/make_binary_distribution.sh
      scripts/make_win_bin_dist
      support-files/config.huge.ini.sh
      support-files/config.medium.ini.sh
      support-files/config.small.ini.sh
      support-files/ndb-config-2-node.ini.sh
    added:
      mysql-test/collections/default.release.in
      mysql-test/r/auth_rpl.result
      mysql-test/r/join_cache_bka_nixbnl.result
      mysql-test/r/join_nested_bka_nixbnl.result
      mysql-test/r/join_outer_bka_nixbnl.result
      mysql-test/r/select_all_bka_nixbnl.result
      mysql-test/r/select_icp_mrr_bka_nixbnl.result
      mysql-test/r/select_none_bka_nixbnl.result
      mysql-test/r/subquery_all_bka_nixbnl.result
      mysql-test/r/subquery_nomat_nosj_bka_nixbnl.result
      mysql-test/r/subquery_none_bka_nixbnl.result
      mysql-test/r/subquery_sj_all_bka_nixbnl.result
      mysql-test/r/subquery_sj_dupsweed_bka_nixbnl.result
      mysql-test/r/subquery_sj_firstmatch_bka_nixbnl.result
      mysql-test/r/subquery_sj_innodb_all_bka_nixbnl.result
      mysql-test/r/subquery_sj_innodb_none_bka_nixbnl.result
      mysql-test/r/subquery_sj_loosescan_bka_nixbnl.result
      mysql-test/r/subquery_sj_mat_bka_nixbnl.result
      mysql-test/r/subquery_sj_none_bka_nixbnl.result
      mysql-test/std_data/bug11747887-bin.000002
      mysql-test/std_data/bug48633.ARM
      mysql-test/std_data/bug48633.ARZ
      mysql-test/std_data/bug48633.frm
      mysql-test/suite/innodb/t/innodb_bug47167-master.opt
      mysql-test/suite/innodb/t/innodb_file_format-master.opt
      mysql-test/suite/opt_trace/include/filesort_pq.inc
      mysql-test/suite/opt_trace/r/filesort_pq.result
      mysql-test/suite/opt_trace/t/filesort_pq.test
      mysql-test/suite/rpl/r/binlog-hexdump.result
      mysql-test/suite/rpl/r/rpl_general_log.result
      mysql-test/suite/rpl/r/rpl_replicate_rewrite_db.result
      mysql-test/suite/rpl/t/binlog-hexdump.test
      mysql-test/suite/rpl/t/rpl_general_log.test
      mysql-test/suite/rpl/t/rpl_replicate_rewrite_db.test
      mysql-test/suite/stress/t/wrapper.test
      mysql-test/suite/sys_vars/r/innodb_analyze_is_persistent_basic.result
      mysql-test/suite/sys_vars/r/innodb_monitor_disable_basic.result
      mysql-test/suite/sys_vars/r/innodb_monitor_enable_basic.result
      mysql-test/suite/sys_vars/r/innodb_monitor_reset_all_basic.result
      mysql-test/suite/sys_vars/r/innodb_monitor_reset_basic.result
      mysql-test/suite/sys_vars/r/innodb_print_all_deadlocks_basic.result
      mysql-test/suite/sys_vars/r/innodb_stats_persistent_sample_pages_basic.result
      mysql-test/suite/sys_vars/r/innodb_stats_transient_sample_pages_basic.result
      mysql-test/suite/sys_vars/r/innodb_sync_array_size_basic.result
      mysql-test/suite/sys_vars/t/innodb_analyze_is_persistent_basic.test
      mysql-test/suite/sys_vars/t/innodb_file_format_max_basic-master.opt
      mysql-test/suite/sys_vars/t/innodb_monitor_disable_basic.test
      mysql-test/suite/sys_vars/t/innodb_monitor_enable_basic.test
      mysql-test/suite/sys_vars/t/innodb_monitor_reset_all_basic.test
      mysql-test/suite/sys_vars/t/innodb_monitor_reset_basic.test
      mysql-test/suite/sys_vars/t/innodb_print_all_deadlocks_basic.test
      mysql-test/suite/sys_vars/t/innodb_stats_persistent_sample_pages_basic.test
      mysql-test/suite/sys_vars/t/innodb_stats_transient_sample_pages_basic.test
      mysql-test/suite/sys_vars/t/innodb_sync_array_size_basic.test
      mysql-test/suite/sys_vars/t/plugin_dir_basic-master.opt
      mysql-test/t/auth_rpl-master.opt
      mysql-test/t/auth_rpl-slave.opt
      mysql-test/t/auth_rpl.test
      mysql-test/t/join_cache_bka_nixbnl.test
      mysql-test/t/join_nested_bka_nixbnl.test
      mysql-test/t/join_outer_bka_nixbnl.test
      mysql-test/t/select_all_bka_nixbnl.test
      mysql-test/t/select_icp_mrr_bka_nixbnl.test
      mysql-test/t/select_none_bka_nixbnl.test
      mysql-test/t/subquery_all_bka_nixbnl.test
      mysql-test/t/subquery_nomat_nosj_bka_nixbnl.test
      mysql-test/t/subquery_none_bka_nixbnl.test
      mysql-test/t/subquery_sj_all_bka_nixbnl.test
      mysql-test/t/subquery_sj_dupsweed_bka_nixbnl.test
      mysql-test/t/subquery_sj_firstmatch_bka_nixbnl.test
      mysql-test/t/subquery_sj_innodb_all_bka_nixbnl.test
      mysql-test/t/subquery_sj_innodb_none_bka_nixbnl.test
      mysql-test/t/subquery_sj_loosescan_bka_nixbnl.test
      mysql-test/t/subquery_sj_mat_bka_nixbnl.test
      mysql-test/t/subquery_sj_none_bka_nixbnl.test
    modified:
      .bzrignore
      CMakeLists.txt
      VERSION
      client/mysql_plugin.c
      client/mysqltest.cc
      cmake/build_configurations/mysql_release.cmake
      cmake/create_initial_db.cmake.in
      cmake/install_macros.cmake
      cmake/mysql_version.cmake
      cmake/plugin.cmake
      config.h.cmake
      extra/perror.c
      include/heap.h
      include/my_base.h
      include/my_pthread.h
      include/mysql/plugin.h
      include/mysql/plugin_audit.h.pp
      include/mysql/plugin_auth.h.pp
      include/mysql/plugin_ftparser.h.pp
      include/mysql/psi/mysql_socket.h
      libmysql/authentication_win/common.cc
      libmysql/authentication_win/common.h
      libmysql/authentication_win/handshake_client.cc
      libmysql/authentication_win/log_client.cc
      libmysql/client_settings.h
      libmysqld/lib_sql.cc
      mysql-test/CMakeLists.txt
      mysql-test/collections/README
      mysql-test/collections/default.experimental
      mysql-test/collections/disabled-daily.list
      mysql-test/collections/disabled-weekly.list
      mysql-test/extra/rpl_tests/rpl_insert_id.test
      mysql-test/extra/rpl_tests/rpl_insert_ignore.test
      mysql-test/include/commit.inc
      mysql-test/include/explain_non_select.inc
      mysql-test/include/icp_tests.inc
      mysql-test/include/mrr_tests.inc
      mysql-test/include/mtr_check.sql
      mysql-test/include/mysqld--help.inc
      mysql-test/include/order_by.inc
      mysql-test/include/subquery.inc
      mysql-test/include/subquery_sj.inc
      mysql-test/lib/My/CoreDump.pm
      mysql-test/lib/mtr_cases.pm
      mysql-test/mysql-stress-test.pl
      mysql-test/mysql-test-run.pl
      mysql-test/r/alter_table.result
      mysql-test/r/archive.result
      mysql-test/r/commit_1innodb.result
      mysql-test/r/ctype_errors.result
      mysql-test/r/ctype_utf16.result
      mysql-test/r/ctype_utf32.result
      mysql-test/r/ctype_utf32_uca.result
      mysql-test/r/ctype_utf8.result
      mysql-test/r/derived.result
      mysql-test/r/error_simulation.result
      mysql-test/r/execution_constants.result
      mysql-test/r/func_str.result
      mysql-test/r/get_diagnostics.result
      mysql-test/r/group_by.result
      mysql-test/r/having.result
      mysql-test/r/heap.result
      mysql-test/r/index_merge_myisam.result
      mysql-test/r/innodb_explain_non_select_all.result
      mysql-test/r/innodb_explain_non_select_none.result
      mysql-test/r/innodb_icp.result
      mysql-test/r/innodb_icp_all.result
      mysql-test/r/innodb_icp_none.result
      mysql-test/r/innodb_mrr.result
      mysql-test/r/innodb_mrr_all.result
      mysql-test/r/innodb_mrr_cost.result
      mysql-test/r/innodb_mrr_cost_all.result
      mysql-test/r/innodb_mrr_cost_icp.result
      mysql-test/r/innodb_mrr_icp.result
      mysql-test/r/innodb_mrr_none.result
      mysql-test/r/join.result
      mysql-test/r/join_cache_bka.result
      mysql-test/r/join_cache_bkaunique.result
      mysql-test/r/join_cache_nojb.result
      mysql-test/r/join_nested_bka.result
      mysql-test/r/join_outer.result
      mysql-test/r/join_outer_bka.result
      mysql-test/r/myisam_explain_non_select_all.result
      mysql-test/r/myisam_explain_non_select_none.result
      mysql-test/r/myisam_icp.result
      mysql-test/r/myisam_icp_all.result
      mysql-test/r/myisam_icp_none.result
      mysql-test/r/myisam_mrr.result
      mysql-test/r/myisam_mrr_all.result
      mysql-test/r/myisam_mrr_cost.result
      mysql-test/r/myisam_mrr_cost_all.result
      mysql-test/r/myisam_mrr_cost_icp.result
      mysql-test/r/myisam_mrr_icp.result
      mysql-test/r/myisam_mrr_none.result
      mysql-test/r/myisampack.result
      mysql-test/r/mysqld--help-notwin.result
      mysql-test/r/mysqld--help-win.result
      mysql-test/r/mysqltest.result
      mysql-test/r/optimizer_switch.result
      mysql-test/r/order_by_all.result
      mysql-test/r/order_by_icp_mrr.result
      mysql-test/r/order_by_none.result
      mysql-test/r/partition.result
      mysql-test/r/partition_innodb.result
      mysql-test/r/partition_innodb_plugin.result
      mysql-test/r/partition_myisam.result
      mysql-test/r/plugin_auth.result
      mysql-test/r/query_cache.result
      mysql-test/r/range_all.result
      mysql-test/r/select_all_bka.result
      mysql-test/r/select_icp_mrr_bka.result
      mysql-test/r/select_none_bka.result
      mysql-test/r/show_check.result
      mysql-test/r/sp-error.result
      mysql-test/r/sp.result
      mysql-test/r/subquery_all.result
      mysql-test/r/subquery_all_bka.result
      mysql-test/r/subquery_nomat_nosj.result
      mysql-test/r/subquery_nomat_nosj_bka.result
      mysql-test/r/subquery_none.result
      mysql-test/r/subquery_none_bka.result
      mysql-test/r/subquery_sj_all.result
      mysql-test/r/subquery_sj_all_bka.result
      mysql-test/r/subquery_sj_all_bkaunique.result
      mysql-test/r/subquery_sj_dupsweed.result
      mysql-test/r/subquery_sj_dupsweed_bka.result
      mysql-test/r/subquery_sj_dupsweed_bkaunique.result
      mysql-test/r/subquery_sj_firstmatch.result
      mysql-test/r/subquery_sj_firstmatch_bka.result
      mysql-test/r/subquery_sj_firstmatch_bkaunique.result
      mysql-test/r/subquery_sj_innodb_all_bka.result
      mysql-test/r/subquery_sj_innodb_all_bkaunique.result
      mysql-test/r/subquery_sj_innodb_none_bka.result
      mysql-test/r/subquery_sj_innodb_none_bkaunique.result
      mysql-test/r/subquery_sj_loosescan.result
      mysql-test/r/subquery_sj_loosescan_bka.result
      mysql-test/r/subquery_sj_loosescan_bkaunique.result
      mysql-test/r/subquery_sj_mat.result
      mysql-test/r/subquery_sj_mat_bka.result
      mysql-test/r/subquery_sj_mat_bkaunique.result
      mysql-test/r/subquery_sj_mat_nosj.result
      mysql-test/r/subquery_sj_none.result
      mysql-test/r/subquery_sj_none_bka.result
      mysql-test/r/subquery_sj_none_bkaunique.result
      mysql-test/r/type_float.result
      mysql-test/r/union.result
      mysql-test/r/view_grant.result
      mysql-test/suite/binlog/r/binlog_stm_blackhole.result
      mysql-test/suite/binlog/r/binlog_unsafe.result
      mysql-test/suite/binlog/t/binlog_unsafe.test
      mysql-test/suite/engines/funcs/r/de_calendar_range.result
      mysql-test/suite/engines/funcs/r/in_calendar_2_unique_constraints_duplicate_update.result
      mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_duplicate_update.result
      mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_error.result
      mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_ignore.result
      mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_duplicate_update.result
      mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_error.result
      mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_ignore.result
      mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_duplicate_update.result
      mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_error.result
      mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_ignore.result
      mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_duplicate_update.result
      mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_error.result
      mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_ignore.result
      mysql-test/suite/engines/funcs/r/in_multicolumn_number_pk_constraint_duplicate_update.result
      mysql-test/suite/engines/funcs/r/up_calendar_range.result
      mysql-test/suite/engines/funcs/t/de_calendar_range.test
      mysql-test/suite/engines/funcs/t/in_calendar_2_unique_constraints_duplicate_update.test
      mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_duplicate_update.test
      mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_error.test
      mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_ignore.test
      mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_duplicate_update.test
      mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_error.test
      mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_ignore.test
      mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_duplicate_update.test
      mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_error.test
      mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_ignore.test
      mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_duplicate_update.test
      mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_error.test
      mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_ignore.test
      mysql-test/suite/engines/funcs/t/in_multicolumn_number_pk_constraint_duplicate_update.test
      mysql-test/suite/engines/funcs/t/up_calendar_range.test
      mysql-test/suite/federated/federated_plugin-master.opt
      mysql-test/suite/federated/federated_plugin.result
      mysql-test/suite/federated/federated_plugin.test
      mysql-test/suite/innodb/r/innodb-index.result
      mysql-test/suite/innodb/r/innodb_bug52745.result
      mysql-test/suite/innodb/r/innodb_bug53591.result
      mysql-test/suite/innodb/r/innodb_file_format.result
      mysql-test/suite/innodb/r/innodb_index_large_prefix.result
      mysql-test/suite/innodb/r/innodb_prefix_index_liftedlimit.result
      mysql-test/suite/innodb/r/innodb_prefix_index_restart_server.result
      mysql-test/suite/innodb/t/innodb-autoinc-44030.test
      mysql-test/suite/innodb/t/innodb-autoinc.test
      mysql-test/suite/innodb/t/innodb-create-options.test
      mysql-test/suite/innodb/t/innodb-index.test
      mysql-test/suite/innodb/t/innodb-zip.test
      mysql-test/suite/innodb/t/innodb_bug36172.test
      mysql-test/suite/innodb/t/innodb_bug52745.test
      mysql-test/suite/innodb/t/innodb_bug53591.test
      mysql-test/suite/innodb/t/innodb_bug56680.test
      mysql-test/suite/innodb/t/innodb_file_format.test
      mysql-test/suite/innodb/t/innodb_index_large_prefix.test
      mysql-test/suite/innodb/t/innodb_prefix_index_liftedlimit.test
      mysql-test/suite/innodb/t/innodb_prefix_index_restart_server.test
      mysql-test/suite/opt_trace/include/general.inc
      mysql-test/suite/opt_trace/include/general2.inc
      mysql-test/suite/opt_trace/include/range.inc
      mysql-test/suite/opt_trace/include/subquery.inc
      mysql-test/suite/opt_trace/r/bugs_no_prot_all.result
      mysql-test/suite/opt_trace/r/bugs_no_prot_none.result
      mysql-test/suite/opt_trace/r/bugs_ps_prot_all.result
      mysql-test/suite/opt_trace/r/bugs_ps_prot_none.result
      mysql-test/suite/opt_trace/r/charset.result
      mysql-test/suite/opt_trace/r/general2_no_prot.result
      mysql-test/suite/opt_trace/r/general2_ps_prot.result
      mysql-test/suite/opt_trace/r/general_no_prot_all.result
      mysql-test/suite/opt_trace/r/general_no_prot_none.result
      mysql-test/suite/opt_trace/r/general_ps_prot_all.result
      mysql-test/suite/opt_trace/r/general_ps_prot_none.result
      mysql-test/suite/opt_trace/r/range_no_prot.result
      mysql-test/suite/opt_trace/r/range_ps_prot.result
      mysql-test/suite/opt_trace/r/security_no_prot.result
      mysql-test/suite/opt_trace/r/security_ps_prot.result
      mysql-test/suite/opt_trace/r/subquery_no_prot.result
      mysql-test/suite/opt_trace/r/subquery_ps_prot.result
      mysql-test/suite/perfschema/r/pfs_upgrade.result
      mysql-test/suite/perfschema/t/socket_instances_func.test
      mysql-test/suite/perfschema/t/socket_instances_func_win.test
      mysql-test/suite/perfschema/t/socket_summary_by_instance_func.test
      mysql-test/suite/perfschema/t/socket_summary_by_instance_func_win.test
      mysql-test/suite/rpl/r/rpl_checksum.result
      mysql-test/suite/rpl/r/rpl_insert_ignore.result
      mysql-test/suite/rpl/r/rpl_known_bugs_detection.result
      mysql-test/suite/rpl/r/rpl_log_pos.result
      mysql-test/suite/rpl/r/rpl_manual_change_index_file.result
      mysql-test/suite/rpl/r/rpl_packet.result
      mysql-test/suite/rpl/r/rpl_parallel_ddl.result
      mysql-test/suite/rpl/r/rpl_parallel_start_stop.result
      mysql-test/suite/rpl/r/rpl_row_event_max_size.result
      mysql-test/suite/rpl/r/rpl_row_ignorable_event.result
      mysql-test/suite/rpl/r/rpl_slave_load_remove_tmpfile.result
      mysql-test/suite/rpl/t/rpl_known_bugs_detection.test
      mysql-test/suite/rpl/t/rpl_manual_change_index_file.test
      mysql-test/suite/rpl/t/rpl_packet.test
      mysql-test/suite/rpl/t/rpl_parallel_ddl.test
      mysql-test/suite/rpl/t/rpl_parallel_switch_sequential.test
      mysql-test/suite/rpl/t/rpl_row_event_max_size.test
      mysql-test/suite/rpl/t/rpl_row_ignorable_event.test
      mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile.test
      mysql-test/suite/sys_vars/r/all_vars.result
      mysql-test/suite/sys_vars/r/optimizer_switch_basic.result
      mysql-test/suite/sys_vars/r/plugin_dir_basic.result
      mysql-test/suite/sys_vars/t/plugin_dir_basic.test
      mysql-test/t/alter_table.test
      mysql-test/t/archive.test
      mysql-test/t/ctype_errors.test
      mysql-test/t/ctype_utf16.test
      mysql-test/t/ctype_utf32.test
      mysql-test/t/ctype_utf32_uca.test
      mysql-test/t/ctype_utf8.test
      mysql-test/t/derived.test
      mysql-test/t/error_simulation.test
      mysql-test/t/execution_constants.test
      mysql-test/t/file_contents.test
      mysql-test/t/func_str.test
      mysql-test/t/group_by.test
      mysql-test/t/heap.test
      mysql-test/t/join.test
      mysql-test/t/join_cache_bka.test
      mysql-test/t/join_cache_bkaunique.test
      mysql-test/t/join_cache_nojb.test
      mysql-test/t/join_nested_bka.test
      mysql-test/t/join_outer.test
      mysql-test/t/join_outer_bka.test
      mysql-test/t/multi_plugin_load.test
      mysql-test/t/myisampack.test
      mysql-test/t/mysql_plugin.test
      mysql-test/t/mysqld--defaults-file.test
      mysql-test/t/mysqltest.test
      mysql-test/t/partition.test
      mysql-test/t/partition_innodb.test
      mysql-test/t/partition_innodb_plugin.test
      mysql-test/t/partition_myisam.test
      mysql-test/t/plugin_auth.test
      mysql-test/t/query_cache.test
      mysql-test/t/select_all_bka.test
      mysql-test/t/select_icp_mrr_bka.test
      mysql-test/t/select_none_bka.test
      mysql-test/t/show_check.test
      mysql-test/t/sp-error.test
      mysql-test/t/sp.test
      mysql-test/t/subquery_all_bka.test
      mysql-test/t/subquery_nomat_nosj_bka.test
      mysql-test/t/subquery_none_bka.test
      mysql-test/t/subquery_sj_all_bka.test
      mysql-test/t/subquery_sj_all_bkaunique.test
      mysql-test/t/subquery_sj_dupsweed_bka.test
      mysql-test/t/subquery_sj_dupsweed_bkaunique.test
      mysql-test/t/subquery_sj_firstmatch.test
      mysql-test/t/subquery_sj_firstmatch_bka.test
      mysql-test/t/subquery_sj_firstmatch_bkaunique.test
      mysql-test/t/subquery_sj_innodb_all_bka.test
      mysql-test/t/subquery_sj_innodb_all_bkaunique.test
      mysql-test/t/subquery_sj_innodb_none_bka.test
      mysql-test/t/subquery_sj_innodb_none_bkaunique.test
      mysql-test/t/subquery_sj_loosescan_bka.test
      mysql-test/t/subquery_sj_loosescan_bkaunique.test
      mysql-test/t/subquery_sj_mat_bka.test
      mysql-test/t/subquery_sj_mat_bkaunique.test
      mysql-test/t/subquery_sj_none_bka.test
      mysql-test/t/subquery_sj_none_bkaunique.test
      mysql-test/t/type_float.test
      mysql-test/t/union.test
      mysql-test/t/view_grant.test
      mysql-test/valgrind.supp
      mysys/my_handler_errors.h
      plugin/audit_null/audit_null.c
      plugin/auth/auth_socket.c
      plugin/auth/dialog.c
      plugin/auth/qa_auth_interface.c
      plugin/auth/qa_auth_server.c
      plugin/auth/test_plugin.c
      plugin/daemon_example/daemon_example.cc
      plugin/fulltext/plugin_example.c
      plugin/semisync/semisync_master.cc
      plugin/semisync/semisync_master_plugin.cc
      plugin/semisync/semisync_slave_plugin.cc
      scripts/CMakeLists.txt
      scripts/mysql_install_db.pl.in
      scripts/mysql_install_db.sh
      scripts/mysql_system_tables.sql
      scripts/mysqld_safe.sh
      sql/CMakeLists.txt
      sql/binlog.cc
      sql/client_settings.h
      sql/event_scheduler.cc
      sql/filesort.cc
      sql/ha_ndbcluster.cc
      sql/ha_partition.cc
      sql/ha_partition.h
      sql/handler.cc
      sql/handler.h
      sql/item.cc
      sql/item.h
      sql/item_buff.cc
      sql/item_cmpfunc.cc
      sql/item_create.cc
      sql/item_func.cc
      sql/item_strfunc.cc
      sql/item_strfunc.h
      sql/item_subselect.cc
      sql/item_subselect.h
      sql/item_sum.cc
      sql/item_sum.h
      sql/log_event.cc
      sql/mysqld.cc
      sql/opt_explain.cc
      sql/opt_range.cc
      sql/opt_trace.cc
      sql/opt_trace.h
      sql/opt_trace2server.cc
      sql/rpl_info_file.cc
      sql/rpl_master.cc
      sql/rpl_rli_pdb.cc
      sql/rpl_slave.cc
      sql/share/errmsg-utf8.txt
      sql/sp_head.cc
      sql/sql_acl.cc
      sql/sql_base.cc
      sql/sql_cache.cc
      sql/sql_class.cc
      sql/sql_class.h
      sql/sql_error.cc
      sql/sql_insert.cc
      sql/sql_lex.cc
      sql/sql_lex.h
      sql/sql_list.h
      sql/sql_parse.cc
      sql/sql_plugin.cc
      sql/sql_prepare.cc
      sql/sql_select.cc
      sql/sql_select.h
      sql/sql_show.cc
      sql/sql_table.cc
      sql/sql_test.cc
      sql/sql_test.h
      sql/sql_union.cc
      sql/sql_update.cc
      sql/sql_yacc.yy
      sql/sys_vars.cc
      sql/table.cc
      sql/table.h
      sql/udf_example.c
      storage/archive/azio.c
      storage/archive/ha_archive.cc
      storage/archive/ha_archive.h
      storage/blackhole/ha_blackhole.cc
      storage/csv/ha_tina.cc
      storage/example/ha_example.cc
      storage/federated/ha_federated.cc
      storage/heap/ha_heap.cc
      storage/heap/hp_create.c
      storage/heap/hp_info.c
      storage/innobase/CMakeLists.txt
      storage/innobase/btr/btr0btr.c
      storage/innobase/btr/btr0cur.c
      storage/innobase/btr/btr0pcur.c
      storage/innobase/btr/btr0sea.c
      storage/innobase/buf/buf0buddy.c
      storage/innobase/buf/buf0buf.c
      storage/innobase/buf/buf0flu.c
      storage/innobase/buf/buf0lru.c
      storage/innobase/data/data0data.c
      storage/innobase/dict/dict0dict.c
      storage/innobase/dict/dict0load.c
      storage/innobase/dict/dict0stats.c
      storage/innobase/fsp/fsp0fsp.c
      storage/innobase/ha/ha0ha.c
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/handler/i_s.cc
      storage/innobase/ibuf/ibuf0ibuf.c
      storage/innobase/include/btr0btr.ic
      storage/innobase/include/btr0cur.h
      storage/innobase/include/btr0cur.ic
      storage/innobase/include/btr0pcur.h
      storage/innobase/include/btr0pcur.ic
      storage/innobase/include/btr0sea.h
      storage/innobase/include/btr0types.h
      storage/innobase/include/buf0buf.h
      storage/innobase/include/buf0buf.ic
      storage/innobase/include/buf0types.h
      storage/innobase/include/data0data.ic
      storage/innobase/include/data0type.ic
      storage/innobase/include/db0err.h
      storage/innobase/include/dict0dict.ic
      storage/innobase/include/dict0load.h
      storage/innobase/include/ha0ha.h
      storage/innobase/include/ha0ha.ic
      storage/innobase/include/mtr0mtr.h
      storage/innobase/include/page0page.h
      storage/innobase/include/page0page.ic
      storage/innobase/include/page0zip.ic
      storage/innobase/include/rem0rec.ic
      storage/innobase/include/row0upd.ic
      storage/innobase/include/srv0mon.h
      storage/innobase/include/sync0rw.h
      storage/innobase/include/sync0rw.ic
      storage/innobase/include/sync0sync.h
      storage/innobase/include/trx0sys.h
      storage/innobase/include/trx0trx.h
      storage/innobase/include/trx0undo.h
      storage/innobase/include/univ.i
      storage/innobase/include/ut0crc32.h
      storage/innobase/include/ut0mem.h
      storage/innobase/include/ut0mem.ic
      storage/innobase/log/log0log.c
      storage/innobase/mtr/mtr0log.c
      storage/innobase/mtr/mtr0mtr.c
      storage/innobase/os/os0file.c
      storage/innobase/page/page0cur.c
      storage/innobase/page/page0page.c
      storage/innobase/page/page0zip.c
      storage/innobase/read/read0read.c
      storage/innobase/rem/rem0cmp.c
      storage/innobase/rem/rem0rec.c
      storage/innobase/row/row0merge.c
      storage/innobase/row/row0mysql.c
      storage/innobase/row/row0purge.c
      storage/innobase/row/row0row.c
      storage/innobase/row/row0sel.c
      storage/innobase/row/row0upd.c
      storage/innobase/srv/srv0start.c
      storage/innobase/sync/sync0rw.c
      storage/innobase/sync/sync0sync.c
      storage/innobase/trx/trx0purge.c
      storage/innobase/trx/trx0rec.c
      storage/innobase/trx/trx0undo.c
      storage/innobase/ut/ut0crc32.c
      storage/innobase/ut/ut0mem.c
      storage/innobase/ut/ut0ut.c
      storage/myisam/ft_boolean_search.c
      storage/myisam/ft_nlq_search.c
      storage/myisam/ha_myisam.cc
      storage/myisam/mi_check.c
      storage/myisam/mi_write.c
      storage/myisammrg/ha_myisammrg.cc
      storage/perfschema/ha_perfschema.cc
      storage/perfschema/pfs.cc
      storage/perfschema/pfs_instr.cc
      storage/perfschema/pfs_instr.h
      storage/perfschema/table_ews_by_thread_by_event_name.cc
      storage/perfschema/table_socket_summary_by_event_name.cc
      storage/perfschema/table_socket_summary_by_instance.cc
      storage/perfschema/table_socket_summary_by_instance.h
      strings/dtoa.c
      support-files/CMakeLists.txt
      support-files/mysql.spec.sh
      tests/mysql_client_test.c
      unittest/gunit/CMakeLists.txt
      unittest/gunit/opt_trace-t.cc
      unittest/gunit/sql_list-t.cc
      unittest/mysys/my_atomic-t.c
=== modified file 'mysql-test/r/get_diagnostics.result'
--- a/mysql-test/r/get_diagnostics.result	2011-10-13 12:33:08 +0000
+++ b/mysql-test/r/get_diagnostics.result	2011-10-13 12:51:13 +0000
@@ -516,10 +516,6 @@ END|
 CALL p1();
 errno	1012
 msg	Signal message
-Warnings:
-Level	Warning
-Code	1012
-Message	Signal message
 DROP PROCEDURE p1;
 CREATE PROCEDURE p1()
 BEGIN
@@ -627,8 +623,6 @@ END|
 CALL p1();
 v
 
-Warnings:
-Error	1051	Unknown table 'test.no_such_table'
 DROP PROCEDURE p1;
 
 # Message is truncated to fit into target. No truncation warning.
@@ -711,8 +705,6 @@ SET @var2 = "message text";
 CALL p1(@var1, @var2);
 message
 message text
-Warnings:
-Warning	1642	inout parameter
 SELECT @var1, @var2;
 @var1	@var2
 1	inout parameter
@@ -731,7 +723,7 @@ CALL p1(@var1);
 number
 9999
 number
-1
+0
 SELECT @var1;
 @var1
 9999
@@ -753,8 +745,6 @@ END|
 SELECT f1();
 f1()
 message text
-Warnings:
-Warning	1642	message text
 DROP FUNCTION f1;
 
 # Using GET DIAGNOSTICS in a trigger.

=== modified file 'mysql-test/r/signal.result'
--- a/mysql-test/r/signal.result	2011-07-28 08:31:36 +0000
+++ b/mysql-test/r/signal.result	2011-09-20 12:13:07 +0000
@@ -2163,15 +2163,18 @@ CALL peter_p2() $$
 1
 1
 Level	Code	Message
+Error	1231	Variable 'sql_mode' can't be set to the value of 'NULL'
 2
 2
 Level	Code	Message
 Error	1231	Variable 'sql_mode' can't be set to the value of 'NULL'
+Error	1232	Variable 'sql_mode' can't be set to the value of 'NULL'
 3
 3
 Level	Code	Message
 Error	1231	Variable 'sql_mode' can't be set to the value of 'NULL'
 Error	1232	Variable 'sql_mode' can't be set to the value of 'NULL'
+Error	9999	Variable 'sql_mode' can't be set to the value of 'NULL'
 ERROR 42000: Hi, I am a useless error message
 show warnings $$
 Level	Code	Message

=== modified file 'mysql-test/r/sp-code.result'
--- a/mysql-test/r/sp-code.result	2011-07-28 08:31:36 +0000
+++ b/mysql-test/r/sp-code.result	2011-09-20 12:13:07 +0000
@@ -924,16 +924,20 @@ CALL p1();
 Warning found!
 Warning found!
 Level	Code	Message
+Warning	1105	Unknown error
 Warning found!
 Warning found!
 Level	Code	Message
+Warning	1105	Unknown error
 Warning found!
 Warning found!
 Level	Code	Message
+Warning	1105	Unknown error
 End of Result Set found!
 End of Result Set found!
 Level	Code	Message
 Warning	1105	Unknown error
+Error	1329	No data - zero rows fetched, selected, or processed
 SET SESSION debug="-d,bug23032_emit_warning";
 DROP PROCEDURE p1;
 DROP TABLE t1;

=== modified file 'mysql-test/r/sp-error.result'
--- a/mysql-test/r/sp-error.result	2011-09-21 11:01:41 +0000
+++ b/mysql-test/r/sp-error.result	2011-10-13 12:51:13 +0000
@@ -1901,8 +1901,6 @@ END|
 CALL p1();
 exception
 exception
-Warnings:
-Warning	1292	Truncated incorrect INTEGER value: '10 '
 DROP TABLE t1;
 DROP PROCEDURE p1;
 #
@@ -2020,3 +2018,805 @@ Error	1048	Column 'c' cannot be null
 DROP TABLE t1;
 DROP TABLE t2;
 DROP PROCEDURE p1;
+
+###################################################################
+# Tests for the following bugs:
+#   - Bug#11763171: 55852 - Possibly inappropriate handler activation.
+#   - Bug#11749343: 38806 - Wrong scope for SQL HANDLERS in SP.
+###################################################################
+
+
+# -- Check that SQL-conditions thrown by Statement-blocks are
+# -- handled by Handler-decl blocks properly.
+
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+SELECT 'H1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'H2' AS HandlerId;
+SIGNAL SQLSTATE '01000'; # Should be handled by H2.
+END|
+
+CALL p1()|
+HandlerId
+H2
+
+# -- Check that SQL-conditions thrown by Statement-blocks are
+# -- handled by Handler-decl blocks properly in case of nested
+# -- SQL-blocks.
+
+CREATE PROCEDURE p2()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+SELECT 'H1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'H2' AS HandlerId;
+BEGIN
+SELECT 'B1' AS BlockId;
+BEGIN
+SELECT 'B2' AS BlockId;
+BEGIN
+SELECT 'B3' AS BlockId;
+SIGNAL SQLSTATE '01000'; # Should be handled by H2.
+END;
+END;
+END;
+END|
+
+CALL p2()|
+BlockId
+B1
+BlockId
+B2
+BlockId
+B3
+HandlerId
+H2
+
+# -- Check SQL-handler resolution rules.
+
+CREATE PROCEDURE p3()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+SELECT 'H1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'H2' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+    SELECT 'H3' AS HandlerId;
+SIGNAL SQLSTATE '01000'; # Should be handled by H3.
+END|
+
+CALL p3()|
+HandlerId
+H3
+
+CREATE PROCEDURE p4()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+SELECT 'H1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+    SELECT 'H2' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'H3' AS HandlerId;
+SIGNAL SQLSTATE '01000'; # Should be handled by H2.
+END|
+
+CALL p4()|
+HandlerId
+H2
+
+CREATE PROCEDURE p5()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+SELECT 'H1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+    SELECT 'H2' AS HandlerId;
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'H3' AS HandlerId;
+SIGNAL SQLSTATE '01000'; # Should be handled by H3.
+END;
+END|
+
+CALL p5()|
+HandlerId
+H3
+
+# -- Check that handlers don't handle its own exceptions.
+
+CREATE PROCEDURE p6()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+SELECT 'H1' AS HandlerId;
+SIGNAL SQLSTATE 'HY000'; # Should *not* be handled by H1.
+END;
+SELECT 'S1' AS SignalId;
+SIGNAL SQLSTATE 'HY000'; # Should be handled by H1.
+END|
+
+CALL p6()|
+SignalId
+S1
+HandlerId
+H1
+ERROR HY000: Unhandled user-defined exception condition
+
+# -- Check that handlers don't handle its own warnings.
+
+CREATE PROCEDURE p7()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+BEGIN
+SELECT 'H1' AS HandlerId;
+SIGNAL SQLSTATE '01000'; # Should *not* be handled by H1.
+END;
+SELECT 'S1' AS SignalId;
+SIGNAL SQLSTATE '01000'; # Should be handled by H1.
+END|
+
+CALL p7()|
+SignalId
+S1
+HandlerId
+H1
+Warnings:
+Warning	1642	Unhandled user-defined warning condition
+
+# -- Check that conditions for handlers are not handled by the handlers
+# -- from the same block.
+
+CREATE PROCEDURE p8()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'H1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+SELECT 'H2' AS HandlerId;
+SIGNAL SQLSTATE '01000'; # Should *not* be handled by H1.
+END;
+SELECT 'S1' AS SignalId;
+SIGNAL SQLSTATE 'HY000'; # Should be handled by H2.
+END|
+
+CALL p8()|
+SignalId
+S1
+HandlerId
+H2
+Warnings:
+Warning	1642	Unhandled user-defined warning condition
+
+# -- Check that conditions for handlers are not handled by the handlers
+# -- from the same block even if they are thrown deep down the stack.
+
+CREATE PROCEDURE p9()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+    SELECT 'Wrong:H1:1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'Wrong:H1:2' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+      SELECT 'Wrong:H2:1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'Wrong:H2:2' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+        SELECT 'Wrong:H3:1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'Wrong:H3:2' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+          SELECT 'Wrong:H4:1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'Wrong:H4:2' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+            SELECT 'Wrong:H5:1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'Wrong:H5:2' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+              SELECT 'Wrong:H6:1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'Wrong:H6:2' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+SELECT 'H2' AS HandlerId;
+SIGNAL SQLSTATE '01000'; # Should *not* be handled by H1.
+END;
+SELECT 'S6' AS SignalId;
+SIGNAL SQLSTATE 'HY000';
+END;
+SELECT 'S5' AS SignalId;
+SIGNAL SQLSTATE 'HY000';
+END;
+SELECT 'S4' AS SignalId;
+SIGNAL SQLSTATE 'HY000';
+END;
+SELECT 'S3' AS SignalId;
+SIGNAL SQLSTATE 'HY000';
+END;
+SELECT 'S2' AS SignalId;
+SIGNAL SQLSTATE 'HY000';
+END;
+SELECT 'S1' AS SignalId;
+SIGNAL SQLSTATE 'HY000'; # Should be handled by H2.
+END|
+
+CALL p9()|
+SignalId
+S1
+SignalId
+S2
+SignalId
+S3
+SignalId
+S4
+SignalId
+S5
+SignalId
+S6
+HandlerId
+H2
+Warnings:
+Warning	1642	Unhandled user-defined warning condition
+
+# -- Check that handlers are choosen properly in case of deep stack and
+# -- nested SQL-blocks.
+
+CREATE PROCEDURE p10()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+    SELECT 'H1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'H2' AS HandlerId;
+BEGIN
+BEGIN
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+          SELECT 'Wrong:H1:1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'Wrong:H1:2' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+            SELECT 'Wrong:H2:1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'Wrong:H2:2' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+              SELECT 'Wrong:H3:1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'Wrong:H3:2' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+                SELECT 'Wrong:H4:1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'Wrong:H4:2' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+                  SELECT 'Wrong:H5:1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'Wrong:H5:2' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+                    SELECT 'Wrong:H6:1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'Wrong:H6:2' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+SELECT 'H2' AS HandlerId;
+SIGNAL SQLSTATE '01000'; # Should be handled by H1.
+END;
+SELECT 'S6' AS SignalId;
+SIGNAL SQLSTATE 'HY000';
+END;
+SELECT 'S5' AS SignalId;
+SIGNAL SQLSTATE 'HY000';
+END;
+SELECT 'S4' AS SignalId;
+SIGNAL SQLSTATE 'HY000';
+END;
+SELECT 'S3' AS SignalId;
+SIGNAL SQLSTATE 'HY000';
+END;
+SELECT 'S2' AS SignalId;
+SIGNAL SQLSTATE 'HY000';
+END;
+SELECT 'S1' AS SignalId;
+SIGNAL SQLSTATE 'HY000'; # Should be handled by H2.
+END;
+END;
+END;
+END|
+
+CALL p10()|
+SignalId
+S1
+SignalId
+S2
+SignalId
+S3
+SignalId
+S4
+SignalId
+S5
+SignalId
+S6
+HandlerId
+H2
+HandlerId
+H1
+
+# -- Test stored procedure from Peter's mail.
+
+CREATE PROCEDURE p11()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+SELECT 'H1' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'H2' AS HandlerId;
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01000', 1249
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+SELECT 'H3' AS HandlerId;
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+SELECT 'H4' AS HandlerId;
+BEGIN
+SELECT 'H5' AS HandlerId;
+SELECT 'S3' AS SignalId;
+SIGNAL SQLSTATE 'HY000'; # H3
+SELECT 'S4' AS SignalId;
+SIGNAL SQLSTATE '22003'; # H3
+SELECT 'S5' AS SignalId;
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO = 1249; # H4
+END;
+END;
+SELECT 'S6' AS SignalId;
+SIGNAL SQLSTATE 'HY000'; # H1
+SELECT 'S7' AS SignalId;
+SIGNAL SQLSTATE '22003'; # H1
+SELECT 'S8' AS SignalId;
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO = 1249; # H5
+END;
+SELECT 'S1' AS SignalId;
+SIGNAL SQLSTATE 'HY000'; # H1
+SELECT 'S2' AS SignalId;
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO = 1249; # H2
+END|
+
+CALL p11()|
+SignalId
+S6
+HandlerId
+H1
+SignalId
+S7
+HandlerId
+H1
+SignalId
+S8
+HandlerId
+H5
+SignalId
+S3
+HandlerId
+H3
+SignalId
+S4
+HandlerId
+H3
+SignalId
+S5
+HandlerId
+H4
+SignalId
+S1
+HandlerId
+H1
+SignalId
+S2
+HandlerId
+H2
+
+# -- Check that runtime stack-trace can be deeper than parsing-time one.
+
+CREATE PROCEDURE p12()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01001'
+  BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01001'
+    BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01001'
+      BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01001'
+        BEGIN
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01001'
+          BEGIN
+SELECT 'H1:5' AS HandlerId;
+SIGNAL SQLSTATE '01002';
+END;
+SELECT 'H1:4' AS HandlerId;
+SIGNAL SQLSTATE '01001';
+END;
+SELECT 'H1:3' AS HandlerId;
+SIGNAL SQLSTATE '01001';
+END;
+SELECT 'H1:2' AS HandlerId;
+SIGNAL SQLSTATE '01001';
+END;
+SELECT 'H1:1' AS HandlerId;
+SIGNAL SQLSTATE '01001';
+END;
+#########################################################
+DECLARE CONTINUE HANDLER FOR SQLSTATE '01002'
+    SELECT 'OK' AS Msg;
+#########################################################
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+BEGIN
+SELECT 'H2:5' AS HandlerId;
+SIGNAL SQLSTATE '01001';
+END;
+SELECT 'H2:4' AS HandlerId;
+SIGNAL SQLSTATE '01000';
+END;
+SELECT 'H2:3' AS HandlerId;
+SIGNAL SQLSTATE '01000';
+END;
+SELECT 'H2:2' AS HandlerId;
+SIGNAL SQLSTATE '01000';
+END;
+SELECT 'H2:1' AS HandlerId;
+SIGNAL SQLSTATE '01000';
+END;
+#######################################################
+SELECT 'Throw 01000' AS Msg;
+SIGNAL SQLSTATE '01000';
+END;
+END|
+
+CALL p12()|
+Msg
+Throw 01000
+HandlerId
+H2:1
+HandlerId
+H2:2
+HandlerId
+H2:3
+HandlerId
+H2:4
+HandlerId
+H2:5
+HandlerId
+H1:1
+HandlerId
+H1:2
+HandlerId
+H1:3
+HandlerId
+H1:4
+HandlerId
+H1:5
+Warnings:
+Warning	1642	Unhandled user-defined warning condition
+
+# -- Check that handler-call-frames are removed properly for EXIT
+# -- handlers.
+
+CREATE PROCEDURE p13()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+BEGIN
+DECLARE EXIT HANDLER FOR SQLWARNING
+BEGIN
+SELECT 'EXIT handler 3' AS Msg;
+END;
+SELECT 'CONTINUE handler 2: 1' AS Msg;
+SIGNAL SQLSTATE '01000';
+SELECT 'CONTINUE handler 2: 2' AS Msg;
+END;
+SELECT 'CONTINUE handler 1: 1' AS Msg;
+SIGNAL SQLSTATE '01000';
+SELECT 'CONTINUE handler 1: 2' AS Msg;
+END;
+SELECT 'Throw 01000' AS Msg;
+SIGNAL SQLSTATE '01000';
+END|
+
+CALL p13()|
+Msg
+Throw 01000
+Msg
+CONTINUE handler 1: 1
+Msg
+CONTINUE handler 2: 1
+Msg
+EXIT handler 3
+Msg
+CONTINUE handler 1: 2
+
+# That's it. Cleanup.
+
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+DROP PROCEDURE p3;
+DROP PROCEDURE p4;
+DROP PROCEDURE p5;
+DROP PROCEDURE p6;
+DROP PROCEDURE p7;
+DROP PROCEDURE p8;
+DROP PROCEDURE p9;
+DROP PROCEDURE p10;
+DROP PROCEDURE p11;
+DROP PROCEDURE p12;
+DROP PROCEDURE p13;
+
+# Bug#12731619: NESTED SP HANDLERS CAN TRIGGER ASSERTION
+
+DROP FUNCTION IF EXISTS f1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1(msg VARCHAR(255));
+CREATE FUNCTION f1() RETURNS INT
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION               # handler 1
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION             # handler 2
+BEGIN
+INSERT INTO t1 VALUE('WRONG: Inside H2');
+RETURN 2;
+END;
+INSERT INTO t1 VALUE('CORRECT: Inside H1');
+RETURN 1;
+END;
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLWARNING               # handler 3
+BEGIN
+INSERT INTO t1 VALUE('WRONG: Inside H3');
+RETURN 3;
+END;
+INSERT INTO t1 VALUE('CORRECT: Calling f1()');
+RETURN f1(); # -- exception here
+END;
+INSERT INTO t1 VALUE('WRONG: Returning 10');
+RETURN 10;
+END|
+
+SELECT f1();
+f1()
+1
+
+SELECT * FROM t1;
+msg
+CORRECT: Calling f1()
+CORRECT: Inside H1
+
+DROP FUNCTION f1;
+DROP TABLE t1;
+
+# Check that handled SQL-conditions are properly cleared from DA.
+
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+DROP PROCEDURE IF EXISTS p1;
+DROP PROCEDURE IF EXISTS p2;
+DROP PROCEDURE IF EXISTS p3;
+DROP PROCEDURE IF EXISTS p4;
+DROP PROCEDURE IF EXISTS p5;
+CREATE TABLE t1(a CHAR, b CHAR, c CHAR);
+CREATE TABLE t2(a SMALLINT, b SMALLINT, c SMALLINT);
+
+# Check that SQL-conditions for which SQL-handler has been invoked,
+# are cleared from the Diagnostics Area. Note, there might be several
+# SQL-conditions, but SQL-handler must be invoked only once.
+
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE EXIT HANDLER FOR SQLWARNING
+SELECT 'Warning caught' AS msg;
+# The INSERT below raises 3 SQL-conditions (warnings). The EXIT HANDLER
+# above must be invoked once (for one condition), but all three conditions
+# must be cleared from the Diagnostics Area.
+INSERT INTO t1 VALUES('qqqq', 'ww', 'eee');
+# The following INSERT will not be executed, because of the EXIT HANDLER.
+INSERT INTO t1 VALUES('zzz', 'xx', 'yyyy');
+END|
+
+CALL p1()|
+msg
+Warning caught
+
+SELECT * FROM t1|
+a	b	c
+q	w	e
+
+# Check that SQL-conditions for which SQL-handler has *not* been
+# invoked, are *still* cleared from the Diagnostics Area.
+
+CREATE PROCEDURE p2()
+BEGIN
+DECLARE CONTINUE HANDLER FOR 1292
+SELECT 'Warning 1292 caught' AS msg;
+# The following INSERT raises 6 SQL-warnings with code 1292,
+# and 3 SQL-warnings with code 1264. The CONTINUE HANDLER above must be
+# invoked once, and all nine SQL-warnings must be cleared from
+# the Diagnostics Area.
+INSERT INTO t2
+SELECT
+CAST(CONCAT(CAST('1 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+CAST(CONCAT(CAST('2 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+CAST(CONCAT(CAST('3 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER);
+END|
+
+CALL p2()|
+msg
+Warning 1292 caught
+
+# Check that if there are two equally ranked SQL-handlers to handle
+# SQL-conditions from SQL-statement, only one of them will be invoked.
+
+CREATE PROCEDURE p3()
+BEGIN
+DECLARE CONTINUE HANDLER FOR 1292
+SELECT 'Warning 1292 caught' AS msg;
+DECLARE CONTINUE HANDLER FOR 1264
+SELECT 'Warning 1264 caught' AS msg;
+# The following INSERT raises 6 SQL-warnings with code 1292,
+# and 3 SQL-warnings with code 1264. Only one of the CONTINUE HANDLERs above
+# must be called, and only once. The SQL Standard does not define, which one
+# should be invoked.
+INSERT INTO t2
+SELECT
+CAST(CONCAT(CAST('1 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+CAST(CONCAT(CAST('2 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+CAST(CONCAT(CAST('3 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER);
+END|
+
+CALL p3()|
+msg
+Warning 1264 caught
+
+# The same as p3, but 1264 comes first.
+
+CREATE PROCEDURE p4()
+BEGIN
+DECLARE CONTINUE HANDLER FOR 1292
+SELECT 'Warning 1292 caught' AS msg;
+DECLARE CONTINUE HANDLER FOR 1264
+SELECT 'Warning 1264 caught' AS msg;
+# The following INSERT raises 4 SQL-warnings with code 1292,
+# and 3 SQL-warnings with code 1264. Only one of the CONTINUE HANDLERs above
+# must be called, and only once. The SQL Standard does not define, which one
+# should be invoked.
+INSERT INTO t2
+SELECT
+CAST(999999 AS SIGNED INTEGER),
+CAST(CONCAT(CAST('2 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+CAST(CONCAT(CAST('3 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER);
+END|
+
+CALL p4()|
+msg
+Warning 1264 caught
+
+# Check that if a SQL-handler raised its own SQL-conditions, there are
+# preserved after handler exit.
+
+CREATE PROCEDURE p5()
+BEGIN
+DECLARE EXIT HANDLER FOR 1292
+BEGIN
+SELECT 'Handler for 1292 (1)' AS Msg;
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO = 1234;
+SHOW WARNINGS;
+SELECT 'Handler for 1292 (2)' AS Msg;
+END;
+INSERT INTO t2
+SELECT
+CAST(999999 AS SIGNED INTEGER),
+CAST(CONCAT(CAST('2 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+CAST(CONCAT(CAST('3 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER);
+END|
+
+CALL p5()|
+Msg
+Handler for 1292 (1)
+Level	Code	Message
+Warning	1234	Unhandled user-defined warning condition
+Msg
+Handler for 1292 (2)
+Warnings:
+Warning	1234	Unhandled user-defined warning condition
+
+# Check that SQL-conditions are available inside the handler, but
+# cleared after the handler exits.
+
+CREATE PROCEDURE p6()
+BEGIN
+DECLARE CONTINUE HANDLER FOR 1292
+BEGIN
+SHOW WARNINGS;
+SELECT 'Handler for 1292' Msg;
+END;
+INSERT INTO t2
+SELECT
+CAST(CONCAT(CAST('1 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+CAST(CONCAT(CAST('2 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+CAST(CONCAT(CAST('3 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER);
+END|
+
+CALL p6()|
+Level	Code	Message
+Warning	1292	Truncated incorrect INTEGER value: '1 '
+Warning	1292	Truncated incorrect INTEGER value: '1999999  '
+Warning	1264	Out of range value for column 'a' at row 1
+Warning	1292	Truncated incorrect INTEGER value: '2 '
+Warning	1292	Truncated incorrect INTEGER value: '2999999  '
+Warning	1264	Out of range value for column 'b' at row 1
+Warning	1292	Truncated incorrect INTEGER value: '3 '
+Warning	1292	Truncated incorrect INTEGER value: '3999999  '
+Warning	1264	Out of range value for column 'c' at row 1
+Msg
+Handler for 1292
+
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+DROP PROCEDURE p3;
+DROP PROCEDURE p4;
+DROP PROCEDURE p5;
+DROP PROCEDURE p6;
+DROP TABLE t1;
+DROP TABLE t2;
+
+# Bug#13059316: ASSERTION FAILURE IN SP_RCONTEXT.CC 
+# Check DECLARE statements that raise conditions before handlers
+# are declared.
+
+DROP PROCEDURE IF EXISTS p1;
+DROP PROCEDURE IF EXISTS p2;
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE var1 INTEGER DEFAULT 'string';
+DECLARE EXIT HANDLER FOR SQLWARNING SELECT 'H1';
+END|
+
+CALL p1()|
+Warnings:
+Warning	1366	Incorrect integer value: 'string' for column 'var1' at row 1
+
+CREATE PROCEDURE p2()
+BEGIN
+DECLARE EXIT HANDLER FOR SQLWARNING SELECT 'H2';
+CALL p1();
+END|
+
+CALL p2()|
+H2
+H2
+
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;

=== modified file 'mysql-test/r/sp.result'
--- a/mysql-test/r/sp.result	2011-10-13 12:33:08 +0000
+++ b/mysql-test/r/sp.result	2011-10-13 12:51:13 +0000
@@ -1460,11 +1460,11 @@ create procedure h_es()
 deterministic
 begin
 declare continue handler for 1062 -- ER_DUP_ENTRY
-select 'Outer (good)' as 'h_es';
+select 'Outer (bad)' as 'h_es';
 begin
 -- integrity constraint violation
 declare continue handler for sqlstate '23000'
-      select 'Inner (bad)' as 'h_es';
+      select 'Inner (good)' as 'h_es';
 insert into t3 values (1);
 end;
 end|
@@ -1472,11 +1472,11 @@ create procedure h_en()
 deterministic
 begin
 declare continue handler for 1329 -- ER_SP_FETCH_NO_DATA
-select 'Outer (good)' as 'h_en';
+select 'Outer (bad)' as 'h_en';
 begin
 declare x int;
 declare continue handler for sqlstate '02000' -- no data
-select 'Inner (bad)' as 'h_en';
+select 'Inner (good)' as 'h_en';
 select a into x from t3 where a = 42;
 end;
 end|
@@ -1484,10 +1484,10 @@ create procedure h_ew()
 deterministic
 begin
 declare continue handler for 1264 -- ER_WARN_DATA_OUT_OF_RANGE
-select 'Outer (good)' as 'h_ew';
+select 'Outer (bad)' as 'h_ew';
 begin
 declare continue handler for sqlwarning
-select 'Inner (bad)' as 'h_ew';
+select 'Inner (good)' as 'h_ew';
 insert into t3 values (123456789012);
 end;
 delete from t3;
@@ -1497,10 +1497,10 @@ create procedure h_ex()
 deterministic
 begin
 declare continue handler for 1062 -- ER_DUP_ENTRY
-select 'Outer (good)' as 'h_ex';
+select 'Outer (bad)' as 'h_ex';
 begin
 declare continue handler for sqlexception
-select 'Inner (bad)' as 'h_ex';
+select 'Inner (good)' as 'h_ex';
 insert into t3 values (1);
 end;
 end|
@@ -1535,11 +1535,11 @@ begin
 -- Note: '02000' is more specific than NOT FOUND ;
 --       there might be other not found states 
 declare continue handler for sqlstate '02000' -- no data
-select 'Outer (good)' as 'h_sn';
+select 'Outer (bad)' as 'h_sn';
 begin
 declare x int;
 declare continue handler for not found
-select 'Inner (bad)' as 'h_sn';
+select 'Inner (good)' as 'h_sn';
 select a into x from t3 where a = 42;
 end;
 end|
@@ -1548,10 +1548,10 @@ deterministic
 begin
 -- data exception - numeric value out of range
 declare continue handler for sqlstate '22003'
-    select 'Outer (good)' as 'h_sw';
+    select 'Outer (bad)' as 'h_sw';
 begin
 declare continue handler for sqlwarning
-select 'Inner (bad)' as 'h_sw';
+select 'Inner (good)' as 'h_sw';
 insert into t3 values (123456789012);
 end;
 delete from t3;
@@ -1562,10 +1562,10 @@ deterministic
 begin
 -- integrity constraint violation
 declare continue handler for sqlstate '23000' 
-select 'Outer (good)' as 'h_sx';
+select 'Outer (bad)' as 'h_sx';
 begin
 declare continue handler for sqlexception
-select 'Inner (bad)' as 'h_sx';
+select 'Inner (good)' as 'h_sx';
 insert into t3 values (1);
 end;
 end|
@@ -1684,16 +1684,16 @@ h_ee
 Inner (good)
 call h_es()|
 h_es
-Outer (good)
+Inner (good)
 call h_en()|
 h_en
-Outer (good)
+Inner (good)
 call h_ew()|
 h_ew
-Outer (good)
+Inner (good)
 call h_ex()|
 h_ex
-Outer (good)
+Inner (good)
 call h_se()|
 h_se
 Inner (good)
@@ -1702,13 +1702,13 @@ h_ss
 Inner (good)
 call h_sn()|
 h_sn
-Outer (good)
+Inner (good)
 call h_sw()|
 h_sw
-Outer (good)
+Inner (good)
 call h_sx()|
 h_sx
-Outer (good)
+Inner (good)
 call h_ne()|
 h_ne
 Inner (good)
@@ -2917,8 +2917,8 @@ call bug6900_9074(0)|
 sqlexception
 sqlexception
 call bug6900_9074(1)|
-23000
-23000
+sqlexception
+sqlexception
 drop procedure bug6900|
 drop procedure bug9074|
 drop procedure bug6900_9074|
@@ -7490,8 +7490,6 @@ END $
 SELECT f1();
 f1()
 1
-Warnings:
-Error	1305	FUNCTION test.f1 does not exist
 DROP FUNCTION f1;
 #
 # WL#2111: Add non-reserved ROW_COUNT keyword.

=== modified file 'mysql-test/suite/funcs_1/r/innodb_storedproc_02.result'
--- a/mysql-test/suite/funcs_1/r/innodb_storedproc_02.result	2011-07-28 08:31:36 +0000
+++ b/mysql-test/suite/funcs_1/r/innodb_storedproc_02.result	2011-09-20 12:13:07 +0000
@@ -762,29 +762,21 @@ SELECT @done, @x;
 0	1
 INSERT INTO temp VALUES('1', NULL);
 CALL sp1();
-Warnings:
-Warning	1265	Data truncated for column 'f2' at row 1
 SELECT @done, @x;
 @done	@x
 1	1
 INSERT INTO temp VALUES('2', NULL);
 CALL sp2();
-Warnings:
-Warning	1265	Data truncated for column 'f2' at row 1
 SELECT @done, @x;
 @done	@x
 1	1
 INSERT INTO temp VALUES('3', NULL);
 CALL sp3();
-Warnings:
-Warning	1265	Data truncated for column 'f2' at row 1
 SELECT @done, @x;
 @done	@x
 1	0
 INSERT INTO temp VALUES('4', NULL);
 CALL sp4();
-Warnings:
-Warning	1265	Data truncated for column 'f2' at row 1
 SELECT @done, @x;
 @done	@x
 1	0

=== modified file 'mysql-test/suite/funcs_1/r/memory_storedproc_02.result'
--- a/mysql-test/suite/funcs_1/r/memory_storedproc_02.result	2011-07-28 08:31:36 +0000
+++ b/mysql-test/suite/funcs_1/r/memory_storedproc_02.result	2011-09-20 12:13:07 +0000
@@ -763,29 +763,21 @@ SELECT @done, @x;
 0	1
 INSERT INTO temp VALUES('1', NULL);
 CALL sp1();
-Warnings:
-Warning	1265	Data truncated for column 'f2' at row 1
 SELECT @done, @x;
 @done	@x
 1	1
 INSERT INTO temp VALUES('2', NULL);
 CALL sp2();
-Warnings:
-Warning	1265	Data truncated for column 'f2' at row 1
 SELECT @done, @x;
 @done	@x
 1	1
 INSERT INTO temp VALUES('3', NULL);
 CALL sp3();
-Warnings:
-Warning	1265	Data truncated for column 'f2' at row 1
 SELECT @done, @x;
 @done	@x
 1	0
 INSERT INTO temp VALUES('4', NULL);
 CALL sp4();
-Warnings:
-Warning	1265	Data truncated for column 'f2' at row 1
 SELECT @done, @x;
 @done	@x
 1	0

=== modified file 'mysql-test/suite/funcs_1/r/myisam_storedproc_02.result'
--- a/mysql-test/suite/funcs_1/r/myisam_storedproc_02.result	2011-07-28 08:31:36 +0000
+++ b/mysql-test/suite/funcs_1/r/myisam_storedproc_02.result	2011-09-20 12:13:07 +0000
@@ -763,29 +763,21 @@ SELECT @done, @x;
 0	1
 INSERT INTO temp VALUES('1', NULL);
 CALL sp1();
-Warnings:
-Warning	1265	Data truncated for column 'f2' at row 1
 SELECT @done, @x;
 @done	@x
 1	1
 INSERT INTO temp VALUES('2', NULL);
 CALL sp2();
-Warnings:
-Warning	1265	Data truncated for column 'f2' at row 1
 SELECT @done, @x;
 @done	@x
 1	1
 INSERT INTO temp VALUES('3', NULL);
 CALL sp3();
-Warnings:
-Warning	1265	Data truncated for column 'f2' at row 1
 SELECT @done, @x;
 @done	@x
 1	0
 INSERT INTO temp VALUES('4', NULL);
 CALL sp4();
-Warnings:
-Warning	1265	Data truncated for column 'f2' at row 1
 SELECT @done, @x;
 @done	@x
 1	0

=== modified file 'mysql-test/suite/funcs_1/r/storedproc.result'
--- a/mysql-test/suite/funcs_1/r/storedproc.result	2011-07-28 08:31:36 +0000
+++ b/mysql-test/suite/funcs_1/r/storedproc.result	2011-09-20 12:13:07 +0000
@@ -23422,8 +23422,6 @@ CREATE TABLE res_t1(w CHAR, x CHAR);
 INSERT INTO res_t1 VALUES('a', 'b');
 INSERT INTO res_t1 VALUES('c', 'd');
 CALL h1();
-Warnings:
-Warning	1265	Data truncated for column 'x' at row 1
 SELECT @done, @x;
 @done	@x
 1	1
@@ -23446,8 +23444,6 @@ CREATE TABLE res_t1(w CHAR, x CHAR);
 INSERT INTO res_t1 VALUES('a', 'b');
 INSERT INTO res_t1 VALUES('c', 'd');
 CALL h1();
-Warnings:
-Warning	1265	Data truncated for column 'x' at row 1
 SELECT @done, @x;
 @done	@x
 1	1

=== modified file 'mysql-test/t/sp-error.test'
--- a/mysql-test/t/sp-error.test	2011-09-21 11:01:41 +0000
+++ b/mysql-test/t/sp-error.test	2011-10-13 12:51:13 +0000
@@ -2904,3 +2904,875 @@ SHOW WARNINGS;
 DROP TABLE t1;
 DROP TABLE t2;
 DROP PROCEDURE p1;
+
+--echo
+--echo ###################################################################
+--echo # Tests for the following bugs:
+--echo #   - Bug#11763171: 55852 - Possibly inappropriate handler activation.
+--echo #   - Bug#11749343: 38806 - Wrong scope for SQL HANDLERS in SP.
+--echo ###################################################################
+--echo
+
+#
+# Structure of SQL-block:
+# BEGIN
+#   <Handler declaration block>
+#   <Statement block>
+# END
+#
+# Scope of Handler-decl-block is Statement-block.
+# I.e. SQL-conditions thrown in the Handler-decl-block can not be handled by
+# the same block, only by outer SQL-blocks.
+#
+# This rule is recursive, i.e. if a Handler-decl-block has nested SQL-blocks,
+# the SQL-conditions from those nested blocks can not be handled by the this
+# Handler-decl-block, only by outer SQL-blocks.
+#
+
+delimiter |;
+
+--echo
+--echo # -- Check that SQL-conditions thrown by Statement-blocks are
+--echo # -- handled by Handler-decl blocks properly.
+--echo
+
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+    SELECT 'H1' AS HandlerId;
+
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    SELECT 'H2' AS HandlerId;
+
+  SIGNAL SQLSTATE '01000'; # Should be handled by H2.
+END|
+
+--echo
+CALL p1()|
+
+--echo
+--echo # -- Check that SQL-conditions thrown by Statement-blocks are
+--echo # -- handled by Handler-decl blocks properly in case of nested
+--echo # -- SQL-blocks.
+--echo
+
+CREATE PROCEDURE p2()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+    SELECT 'H1' AS HandlerId;
+
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    SELECT 'H2' AS HandlerId;
+
+  BEGIN
+
+    SELECT 'B1' AS BlockId;
+    BEGIN
+
+      SELECT 'B2' AS BlockId;
+      BEGIN
+        SELECT 'B3' AS BlockId;
+        SIGNAL SQLSTATE '01000'; # Should be handled by H2.
+      END;
+
+    END;
+
+  END;
+
+END|
+
+--echo
+CALL p2()|
+
+--echo
+--echo # -- Check SQL-handler resolution rules.
+--echo
+
+CREATE PROCEDURE p3()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+    SELECT 'H1' AS HandlerId;
+
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    SELECT 'H2' AS HandlerId;
+
+  DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+    SELECT 'H3' AS HandlerId;
+
+  SIGNAL SQLSTATE '01000'; # Should be handled by H3.
+END|
+
+--echo
+CALL p3()|
+--echo
+
+CREATE PROCEDURE p4()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+    SELECT 'H1' AS HandlerId;
+
+  DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+    SELECT 'H2' AS HandlerId;
+
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    SELECT 'H3' AS HandlerId;
+
+  SIGNAL SQLSTATE '01000'; # Should be handled by H2.
+END|
+
+--echo
+CALL p4()|
+--echo
+
+CREATE PROCEDURE p5()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+    SELECT 'H1' AS HandlerId;
+
+  DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+    SELECT 'H2' AS HandlerId;
+
+  BEGIN
+    DECLARE CONTINUE HANDLER FOR SQLWARNING
+      SELECT 'H3' AS HandlerId;
+
+    SIGNAL SQLSTATE '01000'; # Should be handled by H3.
+  END;
+END|
+
+--echo
+CALL p5()|
+
+--echo
+--echo # -- Check that handlers don't handle its own exceptions.
+--echo
+
+CREATE PROCEDURE p6()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+  BEGIN
+    SELECT 'H1' AS HandlerId;
+    SIGNAL SQLSTATE 'HY000'; # Should *not* be handled by H1.
+  END;
+
+  SELECT 'S1' AS SignalId;
+  SIGNAL SQLSTATE 'HY000'; # Should be handled by H1.
+END|
+
+--echo
+--error ER_SIGNAL_EXCEPTION
+CALL p6()|
+
+--echo
+--echo # -- Check that handlers don't handle its own warnings.
+--echo
+
+CREATE PROCEDURE p7()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+  BEGIN
+    SELECT 'H1' AS HandlerId;
+    SIGNAL SQLSTATE '01000'; # Should *not* be handled by H1.
+  END;
+
+  SELECT 'S1' AS SignalId;
+  SIGNAL SQLSTATE '01000'; # Should be handled by H1.
+END|
+
+--echo
+CALL p7()|
+
+--echo
+--echo # -- Check that conditions for handlers are not handled by the handlers
+--echo # -- from the same block.
+--echo
+
+CREATE PROCEDURE p8()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    SELECT 'H1' AS HandlerId;
+
+  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+  BEGIN
+    SELECT 'H2' AS HandlerId;
+    SIGNAL SQLSTATE '01000'; # Should *not* be handled by H1.
+  END;
+
+  SELECT 'S1' AS SignalId;
+  SIGNAL SQLSTATE 'HY000'; # Should be handled by H2.
+END|
+
+--echo
+CALL p8()|
+
+--echo
+--echo # -- Check that conditions for handlers are not handled by the handlers
+--echo # -- from the same block even if they are thrown deep down the stack.
+--echo
+
+CREATE PROCEDURE p9()
+BEGIN
+
+  DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+    SELECT 'Wrong:H1:1' AS HandlerId;
+
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    SELECT 'Wrong:H1:2' AS HandlerId;
+
+  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+  BEGIN
+
+    DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+      SELECT 'Wrong:H2:1' AS HandlerId;
+
+    DECLARE CONTINUE HANDLER FOR SQLWARNING
+      SELECT 'Wrong:H2:2' AS HandlerId;
+
+    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+    BEGIN
+
+      DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+        SELECT 'Wrong:H3:1' AS HandlerId;
+
+      DECLARE CONTINUE HANDLER FOR SQLWARNING
+        SELECT 'Wrong:H3:2' AS HandlerId;
+
+      DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+      BEGIN
+
+        DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+          SELECT 'Wrong:H4:1' AS HandlerId;
+
+        DECLARE CONTINUE HANDLER FOR SQLWARNING
+          SELECT 'Wrong:H4:2' AS HandlerId;
+
+        DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+        BEGIN
+
+          DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+            SELECT 'Wrong:H5:1' AS HandlerId;
+
+          DECLARE CONTINUE HANDLER FOR SQLWARNING
+            SELECT 'Wrong:H5:2' AS HandlerId;
+
+          DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+          BEGIN
+
+            DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+              SELECT 'Wrong:H6:1' AS HandlerId;
+
+            DECLARE CONTINUE HANDLER FOR SQLWARNING
+              SELECT 'Wrong:H6:2' AS HandlerId;
+
+            DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+            BEGIN
+              SELECT 'H2' AS HandlerId;
+              SIGNAL SQLSTATE '01000'; # Should *not* be handled by H1.
+            END;
+
+            SELECT 'S6' AS SignalId;
+            SIGNAL SQLSTATE 'HY000';
+          END;
+
+          SELECT 'S5' AS SignalId;
+          SIGNAL SQLSTATE 'HY000';
+
+        END;
+
+        SELECT 'S4' AS SignalId;
+        SIGNAL SQLSTATE 'HY000';
+
+      END;
+
+      SELECT 'S3' AS SignalId;
+      SIGNAL SQLSTATE 'HY000';
+
+    END;
+
+    SELECT 'S2' AS SignalId;
+    SIGNAL SQLSTATE 'HY000';
+
+  END;
+
+  SELECT 'S1' AS SignalId;
+  SIGNAL SQLSTATE 'HY000'; # Should be handled by H2.
+
+END|
+
+--echo
+CALL p9()|
+
+--echo
+--echo # -- Check that handlers are choosen properly in case of deep stack and
+--echo # -- nested SQL-blocks.
+--echo
+
+CREATE PROCEDURE p10()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+    SELECT 'H1' AS HandlerId;
+
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    SELECT 'H2' AS HandlerId;
+
+  BEGIN
+    BEGIN
+      BEGIN
+
+        DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+          SELECT 'Wrong:H1:1' AS HandlerId;
+
+        DECLARE CONTINUE HANDLER FOR SQLWARNING
+          SELECT 'Wrong:H1:2' AS HandlerId;
+
+        DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+        BEGIN
+
+          DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+            SELECT 'Wrong:H2:1' AS HandlerId;
+
+          DECLARE CONTINUE HANDLER FOR SQLWARNING
+            SELECT 'Wrong:H2:2' AS HandlerId;
+
+          DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+          BEGIN
+
+            DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+              SELECT 'Wrong:H3:1' AS HandlerId;
+
+            DECLARE CONTINUE HANDLER FOR SQLWARNING
+              SELECT 'Wrong:H3:2' AS HandlerId;
+
+            DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+            BEGIN
+
+              DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+                SELECT 'Wrong:H4:1' AS HandlerId;
+
+              DECLARE CONTINUE HANDLER FOR SQLWARNING
+                SELECT 'Wrong:H4:2' AS HandlerId;
+
+              DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+              BEGIN
+
+                DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+                  SELECT 'Wrong:H5:1' AS HandlerId;
+
+                DECLARE CONTINUE HANDLER FOR SQLWARNING
+                  SELECT 'Wrong:H5:2' AS HandlerId;
+
+                DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+                BEGIN
+
+                  DECLARE CONTINUE HANDLER FOR SQLSTATE '01000'
+                    SELECT 'Wrong:H6:1' AS HandlerId;
+
+                  DECLARE CONTINUE HANDLER FOR SQLWARNING
+                    SELECT 'Wrong:H6:2' AS HandlerId;
+
+                  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+                  BEGIN
+                    SELECT 'H2' AS HandlerId;
+                    SIGNAL SQLSTATE '01000'; # Should be handled by H1.
+                  END;
+
+                  SELECT 'S6' AS SignalId;
+                  SIGNAL SQLSTATE 'HY000';
+                END;
+
+                SELECT 'S5' AS SignalId;
+                SIGNAL SQLSTATE 'HY000';
+
+              END;
+
+              SELECT 'S4' AS SignalId;
+              SIGNAL SQLSTATE 'HY000';
+
+            END;
+
+            SELECT 'S3' AS SignalId;
+            SIGNAL SQLSTATE 'HY000';
+
+          END;
+
+          SELECT 'S2' AS SignalId;
+          SIGNAL SQLSTATE 'HY000';
+
+        END;
+
+        SELECT 'S1' AS SignalId;
+        SIGNAL SQLSTATE 'HY000'; # Should be handled by H2.
+
+      END;
+    END;
+  END;
+END|
+
+--echo
+CALL p10()|
+
+--echo
+--echo # -- Test stored procedure from Peter's mail.
+--echo
+
+CREATE PROCEDURE p11()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+    SELECT 'H1' AS HandlerId;
+
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    SELECT 'H2' AS HandlerId;
+
+  BEGIN
+    DECLARE CONTINUE HANDLER FOR SQLSTATE '01000', 1249
+    BEGIN
+      DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+        SELECT 'H3' AS HandlerId;
+
+      DECLARE CONTINUE HANDLER FOR SQLWARNING
+        SELECT 'H4' AS HandlerId;
+
+      BEGIN
+        SELECT 'H5' AS HandlerId;
+
+        SELECT 'S3' AS SignalId;
+        SIGNAL SQLSTATE 'HY000'; # H3
+
+        SELECT 'S4' AS SignalId;
+        SIGNAL SQLSTATE '22003'; # H3
+
+        SELECT 'S5' AS SignalId;
+        SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO = 1249; # H4
+      END;
+    END;
+
+    SELECT 'S6' AS SignalId;
+    SIGNAL SQLSTATE 'HY000'; # H1
+
+    SELECT 'S7' AS SignalId;
+    SIGNAL SQLSTATE '22003'; # H1
+
+    SELECT 'S8' AS SignalId;
+    SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO = 1249; # H5
+  END;
+
+  SELECT 'S1' AS SignalId;
+  SIGNAL SQLSTATE 'HY000'; # H1
+
+  SELECT 'S2' AS SignalId;
+  SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO = 1249; # H2
+END|
+
+--echo
+CALL p11()|
+
+--echo
+--echo # -- Check that runtime stack-trace can be deeper than parsing-time one.
+--echo
+
+CREATE PROCEDURE p12()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR SQLSTATE '01001'
+  BEGIN
+    DECLARE CONTINUE HANDLER FOR SQLSTATE '01001'
+    BEGIN
+      DECLARE CONTINUE HANDLER FOR SQLSTATE '01001'
+      BEGIN
+        DECLARE CONTINUE HANDLER FOR SQLSTATE '01001'
+        BEGIN
+          DECLARE CONTINUE HANDLER FOR SQLSTATE '01001'
+          BEGIN
+            SELECT 'H1:5' AS HandlerId;
+            SIGNAL SQLSTATE '01002';
+          END;
+          SELECT 'H1:4' AS HandlerId;
+          SIGNAL SQLSTATE '01001';
+        END;
+        SELECT 'H1:3' AS HandlerId;
+        SIGNAL SQLSTATE '01001';
+      END;
+      SELECT 'H1:2' AS HandlerId;
+      SIGNAL SQLSTATE '01001';
+    END;
+    SELECT 'H1:1' AS HandlerId;
+    SIGNAL SQLSTATE '01001';
+  END;
+
+  #########################################################
+
+  DECLARE CONTINUE HANDLER FOR SQLSTATE '01002'
+    SELECT 'OK' AS Msg;
+
+  #########################################################
+
+  BEGIN
+
+    DECLARE CONTINUE HANDLER FOR SQLWARNING
+    BEGIN
+      DECLARE CONTINUE HANDLER FOR SQLWARNING
+      BEGIN
+        DECLARE CONTINUE HANDLER FOR SQLWARNING
+        BEGIN
+          DECLARE CONTINUE HANDLER FOR SQLWARNING
+          BEGIN
+            DECLARE CONTINUE HANDLER FOR SQLWARNING
+            BEGIN
+              SELECT 'H2:5' AS HandlerId;
+              SIGNAL SQLSTATE '01001';
+            END;
+            SELECT 'H2:4' AS HandlerId;
+            SIGNAL SQLSTATE '01000';
+          END;
+          SELECT 'H2:3' AS HandlerId;
+          SIGNAL SQLSTATE '01000';
+        END;
+        SELECT 'H2:2' AS HandlerId;
+        SIGNAL SQLSTATE '01000';
+      END;
+      SELECT 'H2:1' AS HandlerId;
+      SIGNAL SQLSTATE '01000';
+    END;
+
+    #######################################################
+
+    SELECT 'Throw 01000' AS Msg;
+    SIGNAL SQLSTATE '01000';
+  END;
+
+END|
+
+--echo
+CALL p12()|
+
+--echo
+--echo # -- Check that handler-call-frames are removed properly for EXIT
+--echo # -- handlers.
+--echo
+
+CREATE PROCEDURE p13()
+BEGIN
+  
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+  BEGIN
+    DECLARE CONTINUE HANDLER FOR SQLWARNING
+    BEGIN
+      DECLARE EXIT HANDLER FOR SQLWARNING
+      BEGIN
+        SELECT 'EXIT handler 3' AS Msg;
+      END;
+
+      SELECT 'CONTINUE handler 2: 1' AS Msg;
+      SIGNAL SQLSTATE '01000';
+      SELECT 'CONTINUE handler 2: 2' AS Msg;
+    END;
+
+    SELECT 'CONTINUE handler 1: 1' AS Msg;
+    SIGNAL SQLSTATE '01000';
+    SELECT 'CONTINUE handler 1: 2' AS Msg;
+  END;
+
+  SELECT 'Throw 01000' AS Msg;
+  SIGNAL SQLSTATE '01000';
+END|
+
+--echo
+CALL p13()|
+
+delimiter ;|
+
+--echo
+--echo # That's it. Cleanup.
+--echo
+
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+DROP PROCEDURE p3;
+DROP PROCEDURE p4;
+DROP PROCEDURE p5;
+DROP PROCEDURE p6;
+DROP PROCEDURE p7;
+DROP PROCEDURE p8;
+DROP PROCEDURE p9;
+DROP PROCEDURE p10;
+DROP PROCEDURE p11;
+DROP PROCEDURE p12;
+DROP PROCEDURE p13;
+
+--echo
+--echo # Bug#12731619: NESTED SP HANDLERS CAN TRIGGER ASSERTION
+--echo
+
+--disable_warnings
+DROP FUNCTION IF EXISTS f1;
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1(msg VARCHAR(255));
+
+delimiter |;
+CREATE FUNCTION f1() RETURNS INT
+BEGIN
+
+  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION               # handler 1
+  BEGIN
+    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION             # handler 2
+    BEGIN
+      INSERT INTO t1 VALUE('WRONG: Inside H2');
+      RETURN 2;
+    END;
+
+    INSERT INTO t1 VALUE('CORRECT: Inside H1');
+    RETURN 1;
+  END;
+
+  BEGIN
+    DECLARE CONTINUE HANDLER FOR SQLWARNING               # handler 3
+    BEGIN
+      INSERT INTO t1 VALUE('WRONG: Inside H3');
+      RETURN 3;
+    END;
+
+    INSERT INTO t1 VALUE('CORRECT: Calling f1()');
+    RETURN f1(); # -- exception here
+  END;
+
+  INSERT INTO t1 VALUE('WRONG: Returning 10');
+  RETURN 10;
+
+END|
+
+delimiter ;|
+
+--echo
+SELECT f1();
+--echo
+SELECT * FROM t1;
+--echo
+
+DROP FUNCTION f1;
+DROP TABLE t1;
+
+
+--echo
+--echo # Check that handled SQL-conditions are properly cleared from DA.
+--echo
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+DROP PROCEDURE IF EXISTS p1;
+DROP PROCEDURE IF EXISTS p2;
+DROP PROCEDURE IF EXISTS p3;
+DROP PROCEDURE IF EXISTS p4;
+DROP PROCEDURE IF EXISTS p5;
+--enable_warnings
+
+CREATE TABLE t1(a CHAR, b CHAR, c CHAR);
+CREATE TABLE t2(a SMALLINT, b SMALLINT, c SMALLINT);
+
+delimiter |;
+
+--echo
+--echo # Check that SQL-conditions for which SQL-handler has been invoked,
+--echo # are cleared from the Diagnostics Area. Note, there might be several
+--echo # SQL-conditions, but SQL-handler must be invoked only once.
+--echo
+
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE EXIT HANDLER FOR SQLWARNING
+    SELECT 'Warning caught' AS msg;
+
+  # The INSERT below raises 3 SQL-conditions (warnings). The EXIT HANDLER
+  # above must be invoked once (for one condition), but all three conditions
+  # must be cleared from the Diagnostics Area.
+
+  INSERT INTO t1 VALUES('qqqq', 'ww', 'eee');
+
+  # The following INSERT will not be executed, because of the EXIT HANDLER.
+
+  INSERT INTO t1 VALUES('zzz', 'xx', 'yyyy');
+END|
+
+--echo
+CALL p1()|
+--echo
+SELECT * FROM t1|
+
+--echo
+--echo # Check that SQL-conditions for which SQL-handler has *not* been
+--echo # invoked, are *still* cleared from the Diagnostics Area.
+--echo
+
+CREATE PROCEDURE p2()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR 1292
+    SELECT 'Warning 1292 caught' AS msg;
+
+  # The following INSERT raises 6 SQL-warnings with code 1292,
+  # and 3 SQL-warnings with code 1264. The CONTINUE HANDLER above must be
+  # invoked once, and all nine SQL-warnings must be cleared from
+  # the Diagnostics Area.
+
+  INSERT INTO t2
+  SELECT
+    CAST(CONCAT(CAST('1 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+    CAST(CONCAT(CAST('2 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+    CAST(CONCAT(CAST('3 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER);
+END|
+
+--echo
+CALL p2()|
+
+--echo
+--echo # Check that if there are two equally ranked SQL-handlers to handle
+--echo # SQL-conditions from SQL-statement, only one of them will be invoked.
+--echo
+
+CREATE PROCEDURE p3()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR 1292
+    SELECT 'Warning 1292 caught' AS msg;
+
+  DECLARE CONTINUE HANDLER FOR 1264
+    SELECT 'Warning 1264 caught' AS msg;
+
+  # The following INSERT raises 6 SQL-warnings with code 1292,
+  # and 3 SQL-warnings with code 1264. Only one of the CONTINUE HANDLERs above
+  # must be called, and only once. The SQL Standard does not define, which one
+  # should be invoked.
+
+  INSERT INTO t2
+  SELECT
+    CAST(CONCAT(CAST('1 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+    CAST(CONCAT(CAST('2 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+    CAST(CONCAT(CAST('3 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER);
+END|
+
+--echo
+CALL p3()|
+
+--echo
+--echo # The same as p3, but 1264 comes first.
+--echo
+
+CREATE PROCEDURE p4()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR 1292
+    SELECT 'Warning 1292 caught' AS msg;
+
+  DECLARE CONTINUE HANDLER FOR 1264
+    SELECT 'Warning 1264 caught' AS msg;
+
+  # The following INSERT raises 4 SQL-warnings with code 1292,
+  # and 3 SQL-warnings with code 1264. Only one of the CONTINUE HANDLERs above
+  # must be called, and only once. The SQL Standard does not define, which one
+  # should be invoked.
+
+  INSERT INTO t2
+  SELECT
+    CAST(999999 AS SIGNED INTEGER),
+    CAST(CONCAT(CAST('2 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+    CAST(CONCAT(CAST('3 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER);
+END|
+
+--echo
+CALL p4()|
+
+--echo
+--echo # Check that if a SQL-handler raised its own SQL-conditions, there are
+--echo # preserved after handler exit.
+--echo
+
+CREATE PROCEDURE p5()
+BEGIN
+  DECLARE EXIT HANDLER FOR 1292
+  BEGIN
+    SELECT 'Handler for 1292 (1)' AS Msg;
+    SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO = 1234;
+    SHOW WARNINGS;
+    SELECT 'Handler for 1292 (2)' AS Msg;
+  END;
+
+  INSERT INTO t2
+  SELECT
+    CAST(999999 AS SIGNED INTEGER),
+    CAST(CONCAT(CAST('2 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+    CAST(CONCAT(CAST('3 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER);
+END|
+
+--echo
+CALL p5()|
+
+--echo
+--echo # Check that SQL-conditions are available inside the handler, but
+--echo # cleared after the handler exits.
+--echo
+
+CREATE PROCEDURE p6()
+BEGIN
+  DECLARE CONTINUE HANDLER FOR 1292
+  BEGIN
+    SHOW WARNINGS;
+    SELECT 'Handler for 1292' Msg;
+  END;
+
+  INSERT INTO t2
+  SELECT
+    CAST(CONCAT(CAST('1 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+    CAST(CONCAT(CAST('2 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER),
+    CAST(CONCAT(CAST('3 ' AS UNSIGNED INTEGER), '999999  ') AS SIGNED INTEGER);
+END|
+
+--echo
+CALL p6()|
+
+delimiter ;|
+
+--echo
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+DROP PROCEDURE p3;
+DROP PROCEDURE p4;
+DROP PROCEDURE p5;
+DROP PROCEDURE p6;
+DROP TABLE t1;
+DROP TABLE t2;
+
+--echo
+--echo # Bug#13059316: ASSERTION FAILURE IN SP_RCONTEXT.CC 
+--echo # Check DECLARE statements that raise conditions before handlers
+--echo # are declared.
+--echo
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS p1;
+DROP PROCEDURE IF EXISTS p2;
+--enable_warnings
+
+delimiter |;
+
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE var1 INTEGER DEFAULT 'string';
+  DECLARE EXIT HANDLER FOR SQLWARNING SELECT 'H1';
+END|
+
+--echo
+CALL p1()|
+--echo
+
+CREATE PROCEDURE p2()
+BEGIN
+  DECLARE EXIT HANDLER FOR SQLWARNING SELECT 'H2';
+  CALL p1();
+END|
+
+--echo
+CALL p2()|
+
+delimiter ;|
+
+--echo
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;

=== modified file 'mysql-test/t/sp.test'
--- a/mysql-test/t/sp.test	2011-10-13 12:33:08 +0000
+++ b/mysql-test/t/sp.test	2011-10-13 12:51:13 +0000
@@ -1661,31 +1661,27 @@ drop function getcount|
 # Test cases for different combinations of condition handlers in nested
 # begin-end blocks in stored procedures.
 #
-# Note that the standard specifies that the most specific handler should
-# be triggered even if it's an outer handler masked by a less specific
-# handler in an inner block.
+# The SQL standard document says:
+# "8) If there is a general <handler declaration> and a specific
+# <handler declaration> for the same <condition value> in the same scope, then
+# only the specific <handler declaration> is associated with that
+# <condition value>."
+
+# A general handler declaration has SQLWARNING + SQLEXCEPTION + NOT FOUND.
+# A specific handler declaration has SQLSTATE, condition name, or (for MySQL)
+# an errno.
+#
+# So when there are multiple handlers in the same scope, they're all
+# applicable, but the most specific handler should be activated. Notice the
+# standard's exact words: "in the same scope". A specific handler declaration
+# in an outer scope must not be activated instead of a general handler
+# declaration in the inner scope. Previously that was not the case in MySQL.
+#
 # Note also that '02000' is more specific than NOT FOUND; there might be
 # other '02xxx' states, even if we currently do not issue them in any
 # situation (e.g. '02001').
 #
-# The combinations we test are these:
-#
-#                                         Inner
-#              errcode      sqlstate     not found    sqlwarning   sqlexception
-#  Outer      +------------+------------+------------+------------+------------+
-#errcode      | h_ee (i)   | h_es (o)   | h_en (o)   | h_ew (o)   | h_ex (o)   |
-#sqlstate     | h_se (i)   | h_ss (i)   | h_sn (o)   | h_sw (o)   | h_sx (o)   |
-#not found    | h_ne (i)   | h_ns (i)   | h_nn (i)   |            |            |
-#sqlwarning   | h_we (i)   | h_ws (i)   |            | h_ww (i)   |            |
-#sqlexception | h_xe (i)   | h_xs (i)   |            |            | h_xx (i)   |
-#             +------------+---------------------------------------------------+
-#
-# (i) means that the inner handler is the one that should be invoked,
-# (o) means that the outer handler should be invoked.
-#
-# ('not found', 'sqlwarning' and 'sqlexception' are mutually exclusive, hence
-#  no tests for those combinations.)
-#
+# Thus, in all combinations below an inner handler should be activated.
 
 --disable_warnings
 drop table if exists t3|
@@ -1734,12 +1730,12 @@ create procedure h_es()
     deterministic
 begin
   declare continue handler for 1062 -- ER_DUP_ENTRY
-    select 'Outer (good)' as 'h_es';
+    select 'Outer (bad)' as 'h_es';
 
   begin
     -- integrity constraint violation
     declare continue handler for sqlstate '23000'
-      select 'Inner (bad)' as 'h_es';
+      select 'Inner (good)' as 'h_es';
 
     insert into t3 values (1);
   end;
@@ -1749,12 +1745,12 @@ create procedure h_en()
     deterministic
 begin
   declare continue handler for 1329 -- ER_SP_FETCH_NO_DATA
-    select 'Outer (good)' as 'h_en';
+    select 'Outer (bad)' as 'h_en';
 
   begin
     declare x int;
     declare continue handler for sqlstate '02000' -- no data
-      select 'Inner (bad)' as 'h_en';
+      select 'Inner (good)' as 'h_en';
 
     select a into x from t3 where a = 42;
   end;
@@ -1764,11 +1760,11 @@ create procedure h_ew()
     deterministic
 begin
   declare continue handler for 1264 -- ER_WARN_DATA_OUT_OF_RANGE
-    select 'Outer (good)' as 'h_ew';
+    select 'Outer (bad)' as 'h_ew';
 
   begin
     declare continue handler for sqlwarning
-      select 'Inner (bad)' as 'h_ew';
+      select 'Inner (good)' as 'h_ew';
 
     insert into t3 values (123456789012);
   end;
@@ -1780,11 +1776,11 @@ create procedure h_ex()
     deterministic
 begin
   declare continue handler for 1062 -- ER_DUP_ENTRY
-    select 'Outer (good)' as 'h_ex';
+    select 'Outer (bad)' as 'h_ex';
 
   begin
     declare continue handler for sqlexception
-      select 'Inner (bad)' as 'h_ex';
+      select 'Inner (good)' as 'h_ex';
 
     insert into t3 values (1);
   end;
@@ -1827,12 +1823,12 @@ begin
   -- Note: '02000' is more specific than NOT FOUND ;
   --       there might be other not found states 
   declare continue handler for sqlstate '02000' -- no data
-    select 'Outer (good)' as 'h_sn';
+    select 'Outer (bad)' as 'h_sn';
 
   begin
     declare x int;
     declare continue handler for not found
-      select 'Inner (bad)' as 'h_sn';
+      select 'Inner (good)' as 'h_sn';
 
     select a into x from t3 where a = 42;
   end;
@@ -1843,11 +1839,11 @@ create procedure h_sw()
 begin
   -- data exception - numeric value out of range
   declare continue handler for sqlstate '22003'
-    select 'Outer (good)' as 'h_sw';
+    select 'Outer (bad)' as 'h_sw';
 
   begin
     declare continue handler for sqlwarning
-      select 'Inner (bad)' as 'h_sw';
+      select 'Inner (good)' as 'h_sw';
 
     insert into t3 values (123456789012);
   end;
@@ -1860,11 +1856,11 @@ create procedure h_sx()
 begin
   -- integrity constraint violation
   declare continue handler for sqlstate '23000' 
-    select 'Outer (good)' as 'h_sx';
+    select 'Outer (bad)' as 'h_sx';
 
   begin
     declare continue handler for sqlexception
-      select 'Inner (bad)' as 'h_sx';
+      select 'Inner (good)' as 'h_sx';
 
     insert into t3 values (1);
   end;

=== modified file 'sql/item_xmlfunc.cc'
--- a/sql/item_xmlfunc.cc	2011-08-02 08:33:54 +0000
+++ b/sql/item_xmlfunc.cc	2011-08-29 11:06:14 +0000
@@ -2493,7 +2493,7 @@ my_xpath_parse_VariableReference(MY_XPAT
     LEX *lex;
     if ((lex= current_thd->lex) &&
         (spc= lex->spcont) &&
-        (spv= spc->find_variable(&name)))
+        (spv= spc->find_variable(name, false)))
     {
       Item_splocal *splocal= new Item_splocal(name, spv->offset, spv->type, 0);
 #ifndef DBUG_OFF

=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	2011-10-05 13:16:38 +0000
+++ b/sql/sp_head.cc	2011-10-13 12:51:13 +0000
@@ -782,7 +782,7 @@ sp_head::~sp_head()
   for (uint ip = 0 ; (i = get_instr(ip)) ; ip++)
     delete i;
   delete_dynamic(&m_instr);
-  m_pcont->destroy();
+  delete m_pcont;
   free_items();
 
   /*
@@ -1074,109 +1074,6 @@ void sp_head::recursion_level_error(THD
 
 
 /**
-  Find an SQL handler for any condition (warning or error) after execution
-  of a stored routine instruction. Basically, this function looks for an
-  appropriate SQL handler in RT-contexts. If an SQL handler is found, it is
-  remembered in the RT-context for future activation (the context can be
-  inactive at the moment).
-
-  If there is no pending condition, the function just returns.
-
-  If there was an error during the execution, an SQL handler for it will be
-  searched within the current and outer scopes.
-
-  There might be several errors in the Warning Info (that's possible by using
-  SIGNAL/RESIGNAL in nested scopes) -- the function is looking for an SQL
-  handler for the latest (current) error only.
-
-  If there was a warning during the execution, an SQL handler for it will be
-  searched within the current scope only.
-
-  If several warnings were thrown during the execution and there are different
-  SQL handlers for them, it is not determined which SQL handler will be chosen.
-  Only one SQL handler will be executed.
-
-  If warnings and errors were thrown during the execution, the error takes
-  precedence. I.e. error handler will be executed. If there is no handler
-  for that error, condition will remain unhandled.
-
-  According to The Standard (quoting PeterG):
-
-    An SQL procedure statement works like this ...
-    SQL/Foundation 13.5 <SQL procedure statement>
-    (General Rules) (greatly summarized) says:
-    (1) Empty diagnostics area, thus clearing the condition.
-    (2) Execute statement.
-        During execution, if Exception Condition occurs,
-        set Condition Area = Exception Condition and stop
-        statement.
-        During execution, if No Data occurs,
-        set Condition Area = No Data Condition and continue
-        statement.
-        During execution, if Warning occurs,
-        and Condition Area is not already full due to
-        an earlier No Data condition, set Condition Area
-        = Warning and continue statement.
-    (3) Finish statement.
-        At end of execution, if Condition Area is not
-        already full due to an earlier No Data or Warning,
-        set Condition Area = Successful Completion.
-        In effect, this system means there is a precedence:
-        Exception trumps No Data, No Data trumps Warning,
-        Warning trumps Successful Completion.
-
-    NB: "Procedure statements" include any DDL or DML or
-    control statements. So CREATE and DELETE and WHILE
-    and CALL and RETURN are procedure statements. But
-    DECLARE and END are not procedure statements.
-
-  @param thd thread handle
-  @param ctx runtime context of the stored routine
-*/
-
-static void
-find_handler_after_execution(THD *thd, sp_rcontext *ctx)
-{
-  Diagnostics_area *da= thd->get_stmt_da();
-
-  if (thd->is_error())
-  {
-    if (ctx->find_handler(thd,
-                          da->sql_errno(),
-                          da->get_sqlstate(),
-                          Sql_condition::WARN_LEVEL_ERROR,
-                          da->message()))
-    {
-      da->remove_sql_condition(da->get_error_condition());
-    }
-  }
-  else if (thd->get_stmt_da()->current_statement_warn_count())
-  {
-    Diagnostics_area::Sql_condition_iterator it=
-      thd->get_stmt_da()->sql_conditions();
-    const Sql_condition *err;
-
-    while ((err= it++))
-    {
-      if (err->get_level() != Sql_condition::WARN_LEVEL_WARN &&
-          err->get_level() != Sql_condition::WARN_LEVEL_NOTE)
-        continue;
-
-      if (ctx->find_handler(thd,
-                            err->get_sql_errno(),
-                            err->get_sqlstate(),
-                            err->get_level(),
-                            err->get_message_text()))
-      {
-        da->remove_sql_condition(err);
-        break;
-      }
-    }
-  }
-}
-
-
-/**
   Execute the routine. The main instruction jump loop is there.
   Assume the parameters already set.
 
@@ -1446,19 +1343,10 @@ sp_head::execute(THD *thd, bool merge_da
       errors are not catchable by SQL handlers) or the connection has been
       killed during execution.
     */
-    if (!thd->is_fatal_error && !thd->killed_errno())
+    if (!thd->is_fatal_error && !thd->killed_errno() &&
+        ctx->handle_sql_condition(thd, &ip, i))
     {
-      /*
-        Find SQL handler in the appropriate RT-contexts:
-          - warnings can be handled by SQL handlers within
-            the current scope only;
-          - errors can be handled by any SQL handler from outer scope.
-      */
-      find_handler_after_execution(thd, ctx);
-
-      /* If found, activate handler for the current scope. */
-      if (ctx->activate_handler(thd, &ip, i, &execute_arena, &backup_arena))
-        err_status= FALSE;
+      err_status= FALSE;
     }
 
     /* Reset sp_rcontext::end_partial_result_set flag. */
@@ -1534,6 +1422,7 @@ sp_head::execute(THD *thd, bool merge_da
       */
       da->opt_clear_warning_info(thd->query_id);
       da->copy_sql_conditions_from_wi(thd, &sp_wi);
+      da->remove_marked_sql_conditions();
     }
   }
 
@@ -1750,8 +1639,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)) ||
-      nctx->init(thd))
+  if (!(nctx= sp_rcontext::create(thd, m_pcont, NULL)))
   {
     err_status= TRUE;
     goto err_with_cleanup;
@@ -1867,8 +1755,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)) ||
-      nctx->init(thd))
+  if (!(nctx= sp_rcontext::create(thd, m_pcont, return_value_fld)))
   {
     thd->restore_active_arena(&call_arena, &backup_arena);
     err_status= TRUE;
@@ -2087,7 +1974,7 @@ sp_head::execute_procedure(THD *thd, Lis
   if (! octx)
   {
     /* Create a temporary old context. */
-    if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) || octx->init(thd))
+    if (!(octx= sp_rcontext::create(thd, m_pcont, NULL)))
     {
       delete octx; /* Delete octx if it was init() that failed. */
       DBUG_RETURN(TRUE);
@@ -2102,8 +1989,7 @@ sp_head::execute_procedure(THD *thd, Lis
     thd->spcont->callers_arena= thd;
   }
 
-  if (!(nctx= new sp_rcontext(m_pcont, NULL, octx)) ||
-      nctx->init(thd))
+  if (!(nctx= sp_rcontext::create(thd, m_pcont, NULL)))
   {
     delete nctx; /* Delete nctx if it was init() that failed. */
     thd->spcont= save_spcont;
@@ -2436,7 +2322,7 @@ sp_head::backpatch(sp_label *lab)
     if (bp->lab == lab)
     {
       DBUG_PRINT("info", ("backpatch: (m_ip %d, label 0x%lx <%s>) to dest %d",
-                          bp->instr->m_ip, (ulong) lab, lab->name, dest));
+                          bp->instr->m_ip, (ulong) lab, lab->name.str, dest));
       bp->instr->backpatch(dest, lab->ctx);
     }
   }
@@ -3118,7 +3004,7 @@ sp_lex_keeper::reset_lex_and_exec_core(T
   sp_instr class functions
 */
 
-uint sp_instr::get_cont_dest()
+uint sp_instr::get_cont_dest() const
 {
   return (m_ip+1);
 }
@@ -3326,7 +3212,7 @@ sp_instr_set_trigger_field::print(String
   sp_instr_opt_meta
 */
 
-uint sp_instr_opt_meta::get_cont_dest()
+uint sp_instr_opt_meta::get_cont_dest() const
 {
   return m_cont_dest;
 }
@@ -3544,14 +3430,12 @@ int
 sp_instr_hpush_jump::execute(THD *thd, uint *nextp)
 {
   DBUG_ENTER("sp_instr_hpush_jump::execute");
-  List_iterator_fast<sp_condition_value> li(m_cond);
-  sp_condition_value *p;
 
-  while ((p= li++))
-    thd->spcont->push_handler(p, m_ip+1, m_type);
+  int ret= thd->spcont->push_handler(m_handler, m_ip + 1);
 
   *nextp= m_dest;
-  DBUG_RETURN(0);
+
+  DBUG_RETURN(ret);
 }
 
 
@@ -3561,27 +3445,22 @@ sp_instr_hpush_jump::print(String *str)
   /* hpush_jump dest fsize type */
   if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 21))
     return;
+
   str->qs_append(STRING_WITH_LEN("hpush_jump "));
   str->qs_append(m_dest);
   str->qs_append(' ');
   str->qs_append(m_frame);
-  switch (m_type) {
-  case SP_HANDLER_NONE:
-    str->qs_append(STRING_WITH_LEN(" NONE")); // This would be a bug
-    break;
-  case SP_HANDLER_EXIT:
+
+  switch (m_handler->type) {
+  case sp_handler::EXIT:
     str->qs_append(STRING_WITH_LEN(" EXIT"));
     break;
-  case SP_HANDLER_CONTINUE:
+  case sp_handler::CONTINUE:
     str->qs_append(STRING_WITH_LEN(" CONTINUE"));
     break;
-  case SP_HANDLER_UNDO:
-    str->qs_append(STRING_WITH_LEN(" UNDO"));
-    break;
   default:
-    // This would be a bug as well
-    str->qs_append(STRING_WITH_LEN(" UNKNOWN:"));
-    str->qs_append(m_type);
+    // The handler type must be either CONTINUE or EXIT.
+    DBUG_ASSERT(0);
   }
 }
 
@@ -3609,7 +3488,7 @@ sp_instr_hpush_jump::opt_mark(sp_head *s
     above, so we start on m_dest+1 here.
     m_opt_hpop is the hpop marking the end of the handler scope.
   */
-  if (m_type == SP_HANDLER_CONTINUE)
+  if (m_handler->type == sp_handler::CONTINUE)
   {
     for (uint scope_ip= m_dest+1; scope_ip <= m_opt_hpop; scope_ip++)
       sp->add_mark_lead(scope_ip, leads);
@@ -3651,13 +3530,11 @@ int
 sp_instr_hreturn::execute(THD *thd, uint *nextp)
 {
   DBUG_ENTER("sp_instr_hreturn::execute");
-  if (m_dest)
-    *nextp= m_dest;
-  else
-  {
-    *nextp= thd->spcont->pop_hstack();
-  }
-  thd->spcont->exit_handler();
+
+  uint continue_ip= thd->spcont->exit_handler(thd->get_stmt_da());
+
+  *nextp= m_dest ? m_dest : continue_ip;
+
   DBUG_RETURN(0);
 }
 
@@ -3669,12 +3546,17 @@ sp_instr_hreturn::print(String *str)
   if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 9))
     return;
   str->qs_append(STRING_WITH_LEN("hreturn "));
-  str->qs_append(m_frame);
   if (m_dest)
   {
-    str->qs_append(' ');
+    // NOTE: this is legacy: hreturn instruction for EXIT handler
+    // should print out 0 as frame index.
+    str->qs_append(STRING_WITH_LEN("0 "));
     str->qs_append(m_dest);
   }
+  else
+  {
+    str->qs_append(m_frame);
+  }
 }
 
 
@@ -3709,38 +3591,30 @@ sp_instr_cpush::execute(THD *thd, uint *
   Query_arena backup_arena;
   DBUG_ENTER("sp_instr_cpush::execute");
 
-  /*
-    We should create cursors in the callers arena, as
-    it could be (and usually is) used in several instructions.
-  */
-  thd->set_n_backup_active_arena(thd->spcont->callers_arena, &backup_arena);
-
-  thd->spcont->push_cursor(&m_lex_keeper, this);
-
-  thd->restore_active_arena(thd->spcont->callers_arena, &backup_arena);
+  int ret= thd->spcont->push_cursor(&m_lex_keeper, this);
 
   *nextp= m_ip+1;
 
-  DBUG_RETURN(0);
+  DBUG_RETURN(ret);
 }
 
 
 void
 sp_instr_cpush::print(String *str)
 {
-  LEX_STRING n;
-  my_bool found= m_ctx->find_cursor(m_cursor, &n);
+  const LEX_STRING *cursor_name= m_ctx->find_cursor(m_cursor);
+
   /* cpush name@offset */
   uint rsrv= SP_INSTR_UINT_MAXLEN+7;
 
-  if (found)
-    rsrv+= n.length;
+  if (cursor_name)
+    rsrv+= cursor_name->length;
   if (str->reserve(rsrv))
     return;
   str->qs_append(STRING_WITH_LEN("cpush "));
-  if (found)
+  if (cursor_name)
   {
-    str->qs_append(n.str, n.length);
+    str->qs_append(cursor_name->str, cursor_name->length);
     str->qs_append('@');
   }
   str->qs_append(m_cursor);
@@ -3828,19 +3702,19 @@ sp_instr_copen::exec_core(THD *thd, uint
 void
 sp_instr_copen::print(String *str)
 {
-  LEX_STRING n;
-  my_bool found= m_ctx->find_cursor(m_cursor, &n);
+  const LEX_STRING *cursor_name= m_ctx->find_cursor(m_cursor);
+
   /* copen name@offset */
   uint rsrv= SP_INSTR_UINT_MAXLEN+7;
 
-  if (found)
-    rsrv+= n.length;
+  if (cursor_name)
+    rsrv+= cursor_name->length;
   if (str->reserve(rsrv))
     return;
   str->qs_append(STRING_WITH_LEN("copen "));
-  if (found)
+  if (cursor_name)
   {
-    str->qs_append(n.str, n.length);
+    str->qs_append(cursor_name->str, cursor_name->length);
     str->qs_append('@');
   }
   str->qs_append(m_cursor);
@@ -3870,19 +3744,19 @@ sp_instr_cclose::execute(THD *thd, uint
 void
 sp_instr_cclose::print(String *str)
 {
-  LEX_STRING n;
-  my_bool found= m_ctx->find_cursor(m_cursor, &n);
+  const LEX_STRING *cursor_name= m_ctx->find_cursor(m_cursor);
+
   /* cclose name@offset */
   uint rsrv= SP_INSTR_UINT_MAXLEN+8;
 
-  if (found)
-    rsrv+= n.length;
+  if (cursor_name)
+    rsrv+= cursor_name->length;
   if (str->reserve(rsrv))
     return;
   str->qs_append(STRING_WITH_LEN("cclose "));
-  if (found)
+  if (cursor_name)
   {
-    str->qs_append(n.str, n.length);
+    str->qs_append(cursor_name->str, cursor_name->length);
     str->qs_append('@');
   }
   str->qs_append(m_cursor);
@@ -3913,19 +3787,19 @@ sp_instr_cfetch::print(String *str)
 {
   List_iterator_fast<sp_variable> li(m_varlist);
   sp_variable *pv;
-  LEX_STRING n;
-  my_bool found= m_ctx->find_cursor(m_cursor, &n);
+  const LEX_STRING *cursor_name= m_ctx->find_cursor(m_cursor);
+
   /* cfetch name@offset vars... */
   uint rsrv= SP_INSTR_UINT_MAXLEN+8;
 
-  if (found)
-    rsrv+= n.length;
+  if (cursor_name)
+    rsrv+= cursor_name->length;
   if (str->reserve(rsrv))
     return;
   str->qs_append(STRING_WITH_LEN("cfetch "));
-  if (found)
+  if (cursor_name)
   {
-    str->qs_append(n.str, n.length);
+    str->qs_append(cursor_name->str, cursor_name->length);
     str->qs_append('@');
   }
   str->qs_append(m_cursor);

=== modified file 'sql/sp_head.h'
--- a/sql/sp_head.h	2011-08-12 07:18:41 +0000
+++ b/sql/sp_head.h	2011-08-25 06:41:21 +0000
@@ -25,6 +25,7 @@
 #include "my_global.h"                          /* NO_EMBEDDED_ACCESS_CHECKS */
 #include "sql_class.h"                          // THD, set_var.h: THD
 #include "set_var.h"                            // Item
+#include "sp_pcontext.h"                        // sp_pcontext
 
 #include <stddef.h>
 
@@ -49,12 +50,9 @@ sp_map_item_type(enum enum_field_types t
 uint
 sp_get_flags_for_command(LEX *lex);
 
-struct sp_label;
 class sp_instr;
 class sp_instr_opt_meta;
 class sp_instr_jump_if_not;
-struct sp_condition_value;
-struct sp_variable;
 
 /*************************************************************************/
 
@@ -216,15 +214,11 @@ private:
   uint32 unsafe_flags;
 
 public:
-  inline Stored_program_creation_ctx *get_creation_ctx()
-  {
-    return m_creation_ctx;
-  }
+  Stored_program_creation_ctx *get_creation_ctx()
+  { return m_creation_ctx; }
 
-  inline void set_creation_ctx(Stored_program_creation_ctx *creation_ctx)
-  {
-    m_creation_ctx= creation_ctx->clone(mem_root);
-  }
+  void set_creation_ctx(Stored_program_creation_ctx *creation_ctx)
+  { m_creation_ctx= creation_ctx->clone(mem_root); }
 
   longlong m_created;
   longlong m_modified;
@@ -320,13 +314,11 @@ public:
   int
   add_instr(sp_instr *instr);
 
-  inline uint
+  uint
   instructions()
-  {
-    return m_instr.elements;
-  }
+  { return m_instr.elements; }
 
-  inline sp_instr *
+  sp_instr *
   last_instruction()
   {
     sp_instr *i;
@@ -415,7 +407,7 @@ public:
 
   void recursion_level_error(THD *thd);
 
-  inline sp_instr *
+  sp_instr *
   get_instr(uint i)
   {
     sp_instr *ip;
@@ -584,7 +576,7 @@ public:
     Get the continuation destination of this instruction.
     @return the continuation destination
   */
-  virtual uint get_cont_dest();
+  virtual uint get_cont_dest() const;
 
   /*
     Execute core function of instruction after all preparations (e.g.
@@ -685,17 +677,13 @@ public:
   int reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables,
                               sp_instr* instr);
 
-  inline uint sql_command() const
-  {
-    return (uint)m_lex->sql_command;
-  }
+  uint sql_command() const
+  { return (uint)m_lex->sql_command; }
 
   void disable_query_cache()
-  {
-    m_lex->safe_to_cache_query= 0;
-  }
-private:
+  { m_lex->safe_to_cache_query= 0; }
 
+private:
   LEX *m_lex;
   /**
     Indicates whenever this sp_lex_keeper instance responsible
@@ -856,7 +844,7 @@ public:
   virtual void set_destination(uint old_dest, uint new_dest)
     = 0;
 
-  virtual uint get_cont_dest();
+  virtual uint get_cont_dest() const;
 
 protected:
 
@@ -1007,15 +995,21 @@ class sp_instr_hpush_jump : public sp_in
 
 public:
 
-  sp_instr_hpush_jump(uint ip, sp_pcontext *ctx, int htype, uint fp)
-    : sp_instr_jump(ip, ctx), m_type(htype), m_frame(fp), m_opt_hpop(0)
+  sp_instr_hpush_jump(uint ip,
+                      sp_pcontext *ctx,
+                      sp_handler *handler)
+   :sp_instr_jump(ip, ctx),
+    m_handler(handler),
+    m_opt_hpop(0),
+    m_frame(ctx->current_var_count())
   {
-    m_cond.empty();
+    DBUG_ASSERT(m_handler->condition_values.elements == 0);
   }
 
   virtual ~sp_instr_hpush_jump()
   {
-    m_cond.empty();
+    m_handler->condition_values.empty();
+    m_handler= NULL;
   }
 
   virtual int execute(THD *thd, uint *nextp);
@@ -1039,18 +1033,22 @@ public:
       m_opt_hpop= dest;
   }
 
-  inline void add_condition(sp_condition_value *cond)
-  {
-    m_cond.push_front(cond);
-  }
+  void add_condition(sp_condition_value *condition_value)
+  { m_handler->condition_values.push_back(condition_value); }
+
+  sp_handler *get_handler()
+  { return m_handler; }
 
 private:
+  /// Handler.
+  sp_handler *m_handler;
 
-  int m_type;			///< Handler type
-  uint m_frame;
-  uint m_opt_hpop;              // hpop marking end of handler scope.
-  List<sp_condition_value> m_cond;
+  /// hpop marking end of handler scope.
+  uint m_opt_hpop;
 
+  // This attribute is needed for SHOW PROCEDURE CODE only (i.e. it's needed in
+  // debug version only). It's used in print().
+  uint m_frame;
 }; // class sp_instr_hpush_jump : public sp_instr_jump
 
 
@@ -1085,9 +1083,9 @@ class sp_instr_hreturn : public sp_instr
   void operator=(sp_instr_hreturn &);
 
 public:
-
-  sp_instr_hreturn(uint ip, sp_pcontext *ctx, uint fp)
-    : sp_instr_jump(ip, ctx), m_frame(fp)
+  sp_instr_hreturn(uint ip, sp_pcontext *ctx)
+   :sp_instr_jump(ip, ctx),
+    m_frame(ctx->current_var_count())
   {}
 
   virtual ~sp_instr_hreturn()
@@ -1106,9 +1104,9 @@ public:
   virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
 
 private:
-
+  // This attribute is needed for SHOW PROCEDURE CODE only (i.e. it's needed in
+  // debug version only). It's used in print().
   uint m_frame;
-
 }; // class sp_instr_hreturn : public sp_instr_jump
 
 

=== modified file 'sql/sp_pcontext.cc'
--- a/sql/sp_pcontext.cc	2011-08-02 17:47:00 +0000
+++ b/sql/sp_pcontext.cc	2011-09-20 12:54:31 +0000
@@ -18,133 +18,87 @@
 #include "sp_pcontext.h"
 #include "sp_head.h"
 
-/* Initial size for the dynamic arrays in sp_pcontext */
-#define PCONTEXT_ARRAY_INIT_ALLOC 16
-/* Increment size for the dynamic arrays in sp_pcontext */
-#define PCONTEXT_ARRAY_INCREMENT_ALLOC 8
-
-/*
-  Sanity check for SQLSTATEs. Will not check if it's really an existing
-  state (there are just too many), but will check length and bad characters.
-  Returns TRUE if it's ok, FALSE if it's bad.
-*/
-bool
-sp_cond_check(LEX_STRING *sqlstate)
-{
-  int i;
-  const char *p;
-
-  if (sqlstate->length != 5)
-    return FALSE;
-  for (p= sqlstate->str, i= 0 ; i < 5 ; i++)
-  {
-    char c = p[i];
-
-    if ((c < '0' || '9' < c) &&
-	(c < 'A' || 'Z' < c))
-      return FALSE;
-  }
-  /* SQLSTATE class '00' : completion condition */
-  if (strncmp(sqlstate->str, "00", 2) == 0)
-    return FALSE;
-  return TRUE;
+
+bool sp_condition_value::equals(const sp_condition_value *cv) const
+{
+  DBUG_ASSERT(cv);
+
+  if (this == cv)
+    return true;
+
+  if (type != cv->type)
+    return false;
+
+  switch (type)
+  {
+  case sp_condition_value::ERROR_CODE:
+    return (mysqlerr == cv->mysqlerr);
+
+  case sp_condition_value::SQLSTATE:
+    return (strcmp(sql_state, cv->sql_state) == 0);
+
+  default:
+    return true;
+  }
+}
+
+
+void sp_pcontext::init(uint var_offset,
+                       uint cursor_offset,
+                       int num_case_expressions)
+{
+  m_var_offset= var_offset;
+  m_cursor_offset= cursor_offset;
+  m_num_case_exprs= num_case_expressions;
+
+  m_labels.empty();
 }
 
+
 sp_pcontext::sp_pcontext()
   : Sql_alloc(),
-  m_max_var_index(0), m_max_cursor_index(0), m_max_handler_index(0),
-  m_context_handlers(0), m_parent(NULL), m_pboundary(0),
+  m_max_var_index(0), m_max_cursor_index(0),
+  m_parent(NULL), m_pboundary(0),
   m_scope(REGULAR_SCOPE)
 {
-  (void) my_init_dynamic_array(&m_vars, sizeof(sp_variable *),
-                             PCONTEXT_ARRAY_INIT_ALLOC,
-                             PCONTEXT_ARRAY_INCREMENT_ALLOC);
-  (void) my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int),
-                             PCONTEXT_ARRAY_INIT_ALLOC,
-                             PCONTEXT_ARRAY_INCREMENT_ALLOC);
-  (void) my_init_dynamic_array(&m_conds, sizeof(sp_condition *),
-                             PCONTEXT_ARRAY_INIT_ALLOC,
-                             PCONTEXT_ARRAY_INCREMENT_ALLOC);
-  (void) my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING),
-                             PCONTEXT_ARRAY_INIT_ALLOC,
-                             PCONTEXT_ARRAY_INCREMENT_ALLOC);
-  (void) my_init_dynamic_array(&m_handlers, sizeof(sp_condition_value *),
-                             PCONTEXT_ARRAY_INIT_ALLOC,
-                             PCONTEXT_ARRAY_INCREMENT_ALLOC);
-  m_label.empty();
-  m_children.empty();
-
-  m_var_offset= m_cursor_offset= 0;
-  m_num_case_exprs= 0;
+  init(0, 0, 0);
 }
 
+
 sp_pcontext::sp_pcontext(sp_pcontext *prev, sp_pcontext::enum_scope scope)
   : Sql_alloc(),
-  m_max_var_index(0), m_max_cursor_index(0), m_max_handler_index(0),
-  m_context_handlers(0), m_parent(prev), m_pboundary(0),
+  m_max_var_index(0), m_max_cursor_index(0),
+  m_parent(prev), m_pboundary(0),
   m_scope(scope)
 {
-  (void) my_init_dynamic_array(&m_vars, sizeof(sp_variable *),
-                             PCONTEXT_ARRAY_INIT_ALLOC,
-                             PCONTEXT_ARRAY_INCREMENT_ALLOC);
-  (void) my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int),
-                             PCONTEXT_ARRAY_INIT_ALLOC,
-                             PCONTEXT_ARRAY_INCREMENT_ALLOC);
-  (void) my_init_dynamic_array(&m_conds, sizeof(sp_condition *),
-                             PCONTEXT_ARRAY_INIT_ALLOC,
-                             PCONTEXT_ARRAY_INCREMENT_ALLOC);
-  (void) my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING),
-                             PCONTEXT_ARRAY_INIT_ALLOC,
-                             PCONTEXT_ARRAY_INCREMENT_ALLOC);
-  (void) my_init_dynamic_array(&m_handlers, sizeof(sp_condition_value *),
-                             PCONTEXT_ARRAY_INIT_ALLOC,
-                             PCONTEXT_ARRAY_INCREMENT_ALLOC);
-  m_label.empty();
-  m_children.empty();
-
-  m_var_offset= prev->m_var_offset + prev->m_max_var_index;
-  m_cursor_offset= prev->current_cursor_count();
-  m_num_case_exprs= prev->get_num_case_exprs();
-}
-
-void
-sp_pcontext::destroy()
-{
-  List_iterator_fast<sp_pcontext> li(m_children);
-  sp_pcontext *child;
-
-  while ((child= li++))
-    child->destroy();
-
-  m_children.empty();
-  m_label.empty();
-  delete_dynamic(&m_vars);
-  delete_dynamic(&m_case_expr_id_lst);
-  delete_dynamic(&m_conds);
-  delete_dynamic(&m_cursors);
-  delete_dynamic(&m_handlers);
+  init(prev->m_var_offset + prev->m_max_var_index,
+       prev->current_cursor_count(),
+       prev->get_num_case_exprs());
 }
 
-sp_pcontext *
-sp_pcontext::push_context(sp_pcontext::enum_scope scope)
+
+sp_pcontext::~sp_pcontext()
+{
+  for (int i= 0; i < m_children.elements(); ++i)
+    delete m_children.at(i);
+}
+
+
+sp_pcontext *sp_pcontext::push_context(THD *thd, sp_pcontext::enum_scope scope)
 {
-  sp_pcontext *child= new sp_pcontext(this, scope);
+  sp_pcontext *child= new (thd->mem_root) sp_pcontext(this, scope);
 
   if (child)
-    m_children.push_back(child);
+    m_children.append(child);
   return child;
 }
 
-sp_pcontext *
-sp_pcontext::pop_context()
+
+sp_pcontext *sp_pcontext::pop_context()
 {
   m_parent->m_max_var_index+= m_max_var_index;
 
-  uint submax= max_handler_index();
-  if (submax > m_parent->m_max_handler_index)
-    m_parent->m_max_handler_index= submax;
-
-  submax= max_cursor_index();
+  uint submax= max_cursor_index();
   if (submax > m_parent->m_max_cursor_index)
     m_parent->m_max_cursor_index= submax;
 
@@ -154,142 +108,118 @@ sp_pcontext::pop_context()
   return m_parent;
 }
 
-uint
-sp_pcontext::diff_handlers(sp_pcontext *ctx, bool exclusive)
+
+uint sp_pcontext::diff_handlers(const sp_pcontext *ctx, bool exclusive) const
 {
   uint n= 0;
-  sp_pcontext *pctx= this;
-  sp_pcontext *last_ctx= NULL;
+  const sp_pcontext *pctx= this;
+  const sp_pcontext *last_ctx= NULL;
 
   while (pctx && pctx != ctx)
   {
-    n+= pctx->m_context_handlers;
+    n+= pctx->m_handlers.elements();
     last_ctx= pctx;
     pctx= pctx->parent_context();
   }
   if (pctx)
-    return (exclusive && last_ctx ? n - last_ctx->m_context_handlers : n);
+    return (exclusive && last_ctx ? n - last_ctx->m_handlers.elements() : n);
   return 0;			// Didn't find ctx
 }
 
-uint
-sp_pcontext::diff_cursors(sp_pcontext *ctx, bool exclusive)
+
+uint sp_pcontext::diff_cursors(const sp_pcontext *ctx, bool exclusive) const
 {
   uint n= 0;
-  sp_pcontext *pctx= this;
-  sp_pcontext *last_ctx= NULL;
+  const sp_pcontext *pctx= this;
+  const sp_pcontext *last_ctx= NULL;
 
   while (pctx && pctx != ctx)
   {
-    n+= pctx->m_cursors.elements;
+    n+= pctx->m_cursors.elements();
     last_ctx= pctx;
     pctx= pctx->parent_context();
   }
   if (pctx)
-    return  (exclusive && last_ctx ? n - last_ctx->m_cursors.elements : n);
+    return  (exclusive && last_ctx ? n - last_ctx->m_cursors.elements() : n);
   return 0;			// Didn't find ctx
 }
 
-/*
-  This does a linear search (from newer to older variables, in case
-  we have shadowed names).
-  It's possible to have a more efficient allocation and search method,
-  but it might not be worth it. The typical number of parameters and
-  variables will in most cases be low (a handfull).
-  ...and, this is only called during parsing.
-*/
-sp_variable *
-sp_pcontext::find_variable(LEX_STRING *name, my_bool scoped)
+
+sp_variable *sp_pcontext::find_variable(LEX_STRING name,
+                                        bool current_scope_only) const
 {
-  uint i= m_vars.elements - m_pboundary;
+  uint i= m_vars.elements() - m_pboundary;
 
   while (i--)
   {
-    sp_variable *p;
+    sp_variable *p= m_vars.at(i);
 
-    get_dynamic(&m_vars, (uchar*)&p, i);
     if (my_strnncoll(system_charset_info,
-		     (const uchar *)name->str, name->length,
+		     (const uchar *)name.str, name.length,
 		     (const uchar *)p->name.str, p->name.length) == 0)
     {
       return p;
     }
   }
-  if (!scoped && m_parent)
-    return m_parent->find_variable(name, scoped);
-  return NULL;
-}
-
-/*
-  Find a variable by offset from the top.
-  This used for two things:
-  - When evaluating parameters at the beginning, and setting out parameters
-    at the end, of invokation. (Top frame only, so no recursion then.)
-  - For printing of sp_instr_set. (Debug mode only.)
-*/
-sp_variable *
-sp_pcontext::find_variable(uint offset)
-{
-  if (m_var_offset <= offset && offset < m_var_offset + m_vars.elements)
-  {                           // This frame
-    sp_variable *p;
-
-    get_dynamic(&m_vars, (uchar*)&p, offset - m_var_offset);
-    return p;
-  }
-  if (m_parent)
-    return m_parent->find_variable(offset); // Some previous frame
-  return NULL;                  // index out of bounds
-}
-
-sp_variable *
-sp_pcontext::push_variable(LEX_STRING *name, enum enum_field_types type,
-                           sp_variable::enum_mode mode)
+
+  return (!current_scope_only && m_parent) ?
+    m_parent->find_variable(name, false) :
+    NULL;
+}
+
+
+sp_variable *sp_pcontext::find_variable(uint offset) const
+{
+  if (m_var_offset <= offset && offset < m_var_offset + m_vars.elements())
+    return m_vars.at(offset - m_var_offset);  // This frame
+
+  return m_parent ?
+         m_parent->find_variable(offset) :    // Some previous frame
+         NULL;                                // Index out of bounds
+}
+
+
+sp_variable *sp_pcontext::add_variable(THD *thd,
+                                       LEX_STRING name,
+                                       enum enum_field_types type,
+                                       sp_variable::enum_mode mode)
 {
-  sp_variable *p= (sp_variable *)sql_alloc(sizeof(sp_variable));
+  sp_variable *p=
+    new (thd->mem_root) sp_variable(name, type,mode, current_var_count());
 
   if (!p)
     return NULL;
 
   ++m_max_var_index;
 
-  p->name.str= name->str;
-  p->name.length= name->length;
-  p->type= type;
-  p->mode= mode;
-  p->offset= current_var_count();
-  p->dflt= NULL;
-  if (insert_dynamic(&m_vars, &p))
-    return NULL;
-  return p;
+  return m_vars.append(p) ? NULL : p;
 }
 
 
-sp_label *
-sp_pcontext::push_label(char *name, uint ip)
+sp_label *sp_pcontext::push_label(THD *thd, LEX_STRING name, uint ip)
 {
-  sp_label *lab = (sp_label *)sql_alloc(sizeof(sp_label));
+  sp_label *label=
+    new (thd->mem_root) sp_label(name, ip, sp_label::IMPLICIT, this);
 
-  if (lab)
-  {
-    lab->name= name;
-    lab->ip= ip;
-    lab->type= sp_label::IMPLICIT;
-    lab->ctx= this;
-    m_label.push_front(lab);
-  }
-  return lab;
+  if (!label)
+    return NULL;
+
+  m_labels.push_front(label);
+
+  return label;
 }
 
-sp_label *
-sp_pcontext::find_label(char *name)
+
+sp_label *sp_pcontext::find_label(LEX_STRING name)
 {
-  List_iterator_fast<sp_label> li(m_label);
+  List_iterator_fast<sp_label> li(m_labels);
   sp_label *lab;
 
   while ((lab= li++))
-    if (my_strcasecmp(system_charset_info, name, lab->name) == 0)
+  {
+    if (my_strcasecmp(system_charset_info, name.str, lab->name.str) == 0)
       return lab;
+  }
 
   /*
     Note about exception handlers.
@@ -299,159 +229,253 @@ sp_pcontext::find_label(char *name)
     In short, a DECLARE HANDLER block can not refer
     to labels from the parent context, as they are out of scope.
   */
-  if (m_parent && (m_scope == REGULAR_SCOPE))
-    return m_parent->find_label(name);
-  return NULL;
+  return (m_parent && (m_scope == REGULAR_SCOPE)) ?
+         m_parent->find_label(name) :
+         NULL;
 }
 
-int
-sp_pcontext::push_cond(LEX_STRING *name, sp_condition_value *val)
+
+bool sp_pcontext::add_condition(THD *thd,
+                                LEX_STRING name,
+                                sp_condition_value *value)
 {
-  sp_condition *p= (sp_condition *)sql_alloc(sizeof(sp_condition));
+  sp_condition *p= new (thd->mem_root) sp_condition(name, value);
 
   if (p == NULL)
-    return 1;
-  p->name.str= name->str;
-  p->name.length= name->length;
-  p->val= val;
-  return insert_dynamic(&m_conds, &p);
+    return true;
+
+  return m_conditions.append(p);
 }
 
-/*
-  See comment for find_variable() above
-*/
-sp_condition_value *
-sp_pcontext::find_cond(LEX_STRING *name, my_bool scoped)
+
+sp_condition_value *sp_pcontext::find_condition(LEX_STRING name,
+                                                bool current_scope_only) const
 {
-  uint i= m_conds.elements;
+  uint i= m_conditions.elements();
 
   while (i--)
   {
-    sp_condition *p;
+    sp_condition *p= m_conditions.at(i);
 
-    get_dynamic(&m_conds, (uchar*)&p, i);
     if (my_strnncoll(system_charset_info,
-		     (const uchar *)name->str, name->length,
-		     (const uchar *)p->name.str, p->name.length) == 0)
+		     (const uchar *) name.str, name.length,
+		     (const uchar *) p->name.str, p->name.length) == 0)
     {
-      return p->val;
+      return p->value;
     }
   }
-  if (!scoped && m_parent)
-    return m_parent->find_cond(name, scoped);
-  return NULL;
+
+  return (!current_scope_only && m_parent) ?
+    m_parent->find_condition(name, false) :
+    NULL;
 }
 
-/*
-  This only searches the current context, for error checking of
-  duplicates.
-  Returns TRUE if found.
-*/
-bool
-sp_pcontext::find_handler(sp_condition_value *cond)
+
+sp_handler *sp_pcontext::add_handler(THD *thd,
+                                     sp_handler::enum_type type)
 {
-  uint i= m_handlers.elements;
+  sp_handler *h= new (thd->mem_root) sp_handler(type);
 
-  while (i--)
+  if (!h)
+    return NULL;
+
+  return m_handlers.append(h) ? NULL : h;
+}
+
+
+bool sp_pcontext::check_duplicate_handler(
+  const sp_condition_value *cond_value) const
+{
+  for (int i= 0; i < m_handlers.elements(); ++i)
   {
-    sp_condition_value *p;
+    sp_handler *h= m_handlers.at(i);
 
-    get_dynamic(&m_handlers, (uchar*)&p, i);
-    if (cond->type == p->type)
+    List_iterator_fast<sp_condition_value> li(h->condition_values);
+    sp_condition_value *cv;
+
+    while ((cv= li++))
     {
-      switch (p->type)
+      if (cond_value->equals(cv))
+        return true;
+    }
+  }
+
+  return false;
+}
+
+
+sp_handler*
+sp_pcontext::find_handler(const char *sql_state,
+                          uint sql_errno,
+                          Sql_condition::enum_warning_level level) const
+{
+  sp_handler *found_handler= NULL;
+  sp_condition_value *found_cv= NULL;
+
+  for (int i= 0; i < m_handlers.elements(); ++i)
+  {
+    sp_handler *h= m_handlers.at(i);
+
+    List_iterator_fast<sp_condition_value> li(h->condition_values);
+    sp_condition_value *cv;
+
+    while ((cv= li++))
+    {
+      switch (cv->type)
       {
-      case sp_condition_value::number:
-	if (cond->mysqlerr == p->mysqlerr)
-	  return TRUE;
-	break;
-      case sp_condition_value::state:
-	if (strcmp(cond->sqlstate, p->sqlstate) == 0)
-	  return TRUE;
-	break;
-      default:
-	return TRUE;
+      case sp_condition_value::ERROR_CODE:
+        if (sql_errno == cv->mysqlerr &&
+            (!found_cv ||
+             found_cv->type > sp_condition_value::ERROR_CODE))
+        {
+          found_cv= cv;
+          found_handler= h;
+        }
+        break;
+
+      case sp_condition_value::SQLSTATE:
+        if (strcmp(sql_state, cv->sql_state) == 0 &&
+            (!found_cv ||
+             found_cv->type > sp_condition_value::SQLSTATE))
+        {
+          found_cv= cv;
+          found_handler= h;
+        }
+        break;
+
+      case sp_condition_value::WARNING:
+        if ((is_sqlstate_warning(sql_state) ||
+             level == Sql_condition::WARN_LEVEL_WARN) && !found_cv)
+        {
+          found_cv= cv;
+          found_handler= h;
+        }
+        break;
+
+      case sp_condition_value::NOT_FOUND:
+        if (is_sqlstate_not_found(sql_state) && !found_cv)
+        {
+          found_cv= cv;
+          found_handler= h;
+        }
+        break;
+
+      case sp_condition_value::EXCEPTION:
+        if (is_sqlstate_exception(sql_state) &&
+            level == Sql_condition::WARN_LEVEL_ERROR && !found_cv)
+        {
+          found_cv= cv;
+          found_handler= h;
+        }
+        break;
       }
     }
   }
-  return FALSE;
+
+  if (found_handler)
+    return found_handler;
+
+
+  // There is no appropriate handler in this parsing context. We need to look up
+  // in parent contexts. There might be two cases here:
+  //
+  // 1. The current context has REGULAR_SCOPE. That means, it's a simple
+  // BEGIN..END block:
+  //     ...
+  //     BEGIN
+  //       ... # We're here.
+  //     END
+  //     ...
+  // In this case we simply call find_handler() on parent's context recursively.
+  //
+  // 2. The current context has HANDLER_SCOPE. That means, we're inside an
+  // SQL-handler block:
+  //   ...
+  //   DECLARE ... HANDLER FOR ...
+  //   BEGIN
+  //     ... # We're here.
+  //   END
+  //   ...
+  // In this case we can not just call parent's find_handler(), because
+  // parent's handler don't catch conditions from this scope. Instead, we should
+  // try to find first parent context (we might have nested handler
+  // declarations), which has REGULAR_SCOPE (i.e. which is regular BEGIN..END
+  // block).
+
+  const sp_pcontext *p= this;
+
+  while (p && p->m_scope == HANDLER_SCOPE)
+    p= p->m_parent;
+
+  if (!p || !p->m_parent)
+    return NULL;
+
+  return p->m_parent->find_handler(sql_state, sql_errno, level);
 }
 
-int
-sp_pcontext::push_cursor(LEX_STRING *name)
+
+bool sp_pcontext::add_cursor(LEX_STRING name)
 {
-  LEX_STRING n;
+  if (m_cursors.elements() == (int) m_max_cursor_index)
+    ++m_max_cursor_index;
 
-  if (m_cursors.elements == m_max_cursor_index)
-    m_max_cursor_index+= 1;
-  n.str= name->str;
-  n.length= name->length;
-  return insert_dynamic(&m_cursors, &n);
+  return m_cursors.append(name);
 }
 
-/*
-  See comment for find_variable() above
-*/
-my_bool
-sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped)
+
+bool sp_pcontext::find_cursor(LEX_STRING name,
+                              uint *poff,
+                              bool current_scope_only) const
 {
-  uint i= m_cursors.elements;
+  uint i= m_cursors.elements();
 
   while (i--)
   {
-    LEX_STRING n;
+    LEX_STRING n= m_cursors.at(i);
 
-    get_dynamic(&m_cursors, (uchar*)&n, i);
     if (my_strnncoll(system_charset_info,
-		     (const uchar *)name->str, name->length,
-		     (const uchar *)n.str, n.length) == 0)
+		     (const uchar *) name.str, name.length,
+		     (const uchar *) n.str, n.length) == 0)
     {
       *poff= m_cursor_offset + i;
-      return TRUE;
+      return true;
     }
   }
-  if (!scoped && m_parent)
-    return m_parent->find_cursor(name, poff, scoped);
-  return FALSE;
+
+  return (!current_scope_only && m_parent) ?
+    m_parent->find_cursor(name, poff, false) :
+    false;
 }
 
 
-void
-sp_pcontext::retrieve_field_definitions(List<Create_field> *field_def_lst)
+void sp_pcontext::retrieve_field_definitions(
+  List<Create_field> *field_def_lst) const
 {
   /* Put local/context fields in the result list. */
 
-  for (uint i = 0; i < m_vars.elements; ++i)
+  for (int i= 0; i < m_vars.elements(); ++i)
   {
-    sp_variable *var_def;
-    get_dynamic(&m_vars, (uchar*) &var_def, i);
+    sp_variable *var_def= m_vars.at(i);
 
     field_def_lst->push_back(&var_def->field_def);
   }
 
   /* Put the fields of the enclosed contexts in the result list. */
 
-  List_iterator_fast<sp_pcontext> li(m_children);
-  sp_pcontext *ctx;
-
-  while ((ctx = li++))
-    ctx->retrieve_field_definitions(field_def_lst);
+  for (int i= 0; i < m_children.elements(); ++i)
+    m_children.at(i)->retrieve_field_definitions(field_def_lst);
 }
 
-/*
-  Find a cursor by offset from the top.
-  This is only used for debugging.
-*/
-my_bool
-sp_pcontext::find_cursor(uint offset, LEX_STRING *n)
+
+const LEX_STRING *sp_pcontext::find_cursor(uint offset) const
 {
   if (m_cursor_offset <= offset &&
-      offset < m_cursor_offset + m_cursors.elements)
-  {                           // This frame
-    get_dynamic(&m_cursors, (uchar*)n, offset - m_cursor_offset);
-    return TRUE;
-  }
-  if (m_parent)
-    return m_parent->find_cursor(offset, n); // Some previous frame
-  return FALSE;                 // index out of bounds
+      offset < m_cursor_offset + m_cursors.elements())
+  {
+    return &m_cursors.at(offset - m_cursor_offset);   // This frame
+  }
+
+  return m_parent ?
+         m_parent->find_cursor(offset) :  // Some previous frame
+         NULL;                            // Index out of bounds
 }

=== modified file 'sql/sp_pcontext.h'
--- a/sql/sp_pcontext.h	2011-08-02 08:34:30 +0000
+++ b/sql/sp_pcontext.h	2011-09-20 12:54:31 +0000
@@ -20,9 +20,15 @@
 #include "sql_string.h"                         // LEX_STRING
 #include "mysql_com.h"                          // enum_field_types
 #include "field.h"                              // Create_field
+#include "sql_array.h"                          // Dynamic_array
 
-struct sp_variable
+
+/// This class represents a stored program variable or a parameter
+/// (also referenced as 'SP-variable').
+
+class sp_variable : public Sql_alloc
 {
+public:
   enum enum_mode
   {
     MODE_IN,
@@ -30,34 +36,52 @@ struct sp_variable
     MODE_INOUT
   };
 
+  /// Name of the SP-variable.
   LEX_STRING name;
+
+  /// Field-type of the SP-variable.
   enum enum_field_types type;
+
+  /// Mode of the SP-variable.
   enum_mode mode;
-  
-  /*
-    offset -- this the index to the variable's value in the runtime frame.
-    This is calculated during parsing and used when creating sp_instr_set
-    instructions and Item_splocal items.
-    I.e. values are set/referred by array indexing in runtime.
-  */
+
+  /// The index to the variable's value in the runtime frame.
+  ///
+  /// It is calculated during parsing and used when creating sp_instr_set
+  /// instructions and Item_splocal items. I.e. values are set/referred by
+  /// array indexing in runtime.
   uint offset;
 
-  Item *dflt;
+  /// Default value of the SP-variable (if any).
+  Item *default_value;
+
+  /// Full type information (field meta-data) of the SP-variable.
   Create_field field_def;
+
+public:
+  sp_variable(LEX_STRING _name, enum_field_types _type, enum_mode _mode,
+              uint _offset)
+   :Sql_alloc(),
+    name(_name),
+    type(_type),
+    mode(_mode),
+    offset(_offset),
+    default_value(NULL)
+  { }
 };
 
+///////////////////////////////////////////////////////////////////////////
 
-/*
-  An SQL/PSM label. Can refer to the identifier used with the
-  "label_name:" construct which may precede some SQL/PSM statements, or
-  to an implicit implementation-dependent identifier which the parser
-  inserts before a high-level flow control statement such as
-  IF/WHILE/REPEAT/LOOP, when such statement is rewritten into
-  a combination of low-level jump/jump_if instructions and labels.
-*/
+/// This class represents an SQL/PSM label. Can refer to the identifier
+/// used with the "label_name:" construct which may precede some SQL/PSM
+/// statements, or to an implicit implementation-dependent identifier which
+/// the parser inserts before a high-level flow control statement such as
+/// IF/WHILE/REPEAT/LOOP, when such statement is rewritten into a
+/// combination of low-level jump/jump_if instructions and labels.
 
-struct sp_label
+class sp_label : public Sql_alloc
 {
+public:
   enum enum_type
   {
     /// Implicit label generated by parser.
@@ -70,388 +94,467 @@ struct sp_label
     ITERATION
   };
 
-  char *name;
-  uint ip;                // Instruction index
-  enum_type type;         // begin/iter or ref/free 
-  class sp_pcontext *ctx; // The label's context
-};
+  /// Name of the label.
+  LEX_STRING name;
 
-struct sp_condition_value
-{
-  enum { number, state, warning, notfound, exception } type;
-  char sqlstate[SQLSTATE_LENGTH+1];
-  uint mysqlerr;
-};
+  /// Instruction pointer of the label.
+  uint ip;
 
-/*
-  Sanity check for SQLSTATEs. Will not check if it's really an existing
-  state (there are just too many), but will check length bad characters.
-*/
-extern bool
-sp_cond_check(LEX_STRING *sqlstate);
+  /// Type of the label.
+  enum_type type;
 
-struct sp_condition
-{
-  LEX_STRING name;
-  sp_condition_value *val;
+  /// Scope of the label.
+  class sp_pcontext *ctx;
+
+public:
+  sp_label(LEX_STRING _name, uint _ip, enum_type _type, sp_pcontext *_ctx)
+   :Sql_alloc(),
+    name(_name),
+    ip(_ip),
+    type(_type),
+    ctx(_ctx)
+  { }
 };
 
-/**
-  The parse-time context, used to keep track of declared variables/parameters,
-  conditions, handlers, cursors and labels, during parsing.
-  sp_contexts are organized as a tree, with one object for each begin-end
-  block, one object for each exception handler,
-  plus a root-context for the parameters.
-  This is used during parsing for looking up defined names (e.g. declared
-  variables and visible labels), for error checking, and to calculate offsets
-  to be used at runtime. (During execution variable values, active handlers
-  and cursors, etc, are referred to by an index in a stack.)
-  Parsing contexts for exception handlers limit the visibility of labels.
-  The pcontext tree is also kept during execution and is used for error
-  checking (e.g. correct number of parameters), and in the future, used by
-  the debugger.
-*/
+///////////////////////////////////////////////////////////////////////////
 
-class sp_pcontext : public Sql_alloc
+/// This class represents condition-value term in DECLARE CONDITION or
+/// DECLARE HANDLER statements. sp_condition_value has little to do with
+/// SQL-conditions.
+///
+/// In some sense, this class is a union -- a set of filled attributes
+/// depends on the sp_condition_value::type value.
+
+class sp_condition_value : public Sql_alloc
 {
 public:
-  enum enum_scope
+  enum enum_type
   {
-    /// REGULAR_SCOPE designates regular BEGIN ... END blocks.
-    REGULAR_SCOPE,
-
-    /// HANDLER_SCOPE designates SQL-handler blocks.
-    HANDLER_SCOPE
+    ERROR_CODE,
+    SQLSTATE,
+    WARNING,
+    NOT_FOUND,
+    EXCEPTION
   };
 
-public:
+  /// Type of the condition value.
+  enum_type type;
 
-  /**
-    Constructor.
-    Builds a parsing context root node.
-  */
-  sp_pcontext();
+  /// SQLSTATE of the condition value.
+  char sql_state[SQLSTATE_LENGTH+1];
 
-  // Free memory
-  void
-  destroy();
-
-  /**
-    Create and push a new context in the tree.
-    @param scope scope of the new parsing context
-    @return the node created
-  */
-  sp_pcontext *
-  push_context(enum_scope scope);
-
-  /**
-    Pop a node from the parsing context tree.
-    @return the parent node
-  */
-  sp_pcontext *
-  pop_context();
+  /// MySQL error code of the condition value.
+  uint mysqlerr;
 
-  sp_pcontext *
-  parent_context()
-  {
-    return m_parent;
-  }
+public:
+  sp_condition_value(uint _mysqlerr)
+   :Sql_alloc(),
+    type(ERROR_CODE),
+    mysqlerr(_mysqlerr)
+  { }
 
-  /*
-    Number of handlers/cursors to pop between this context and 'ctx'.
-    If 'exclusive' is true, don't count the last block we are leaving;
-    this is used for LEAVE where we will jump to the cpop/hpop instructions.
-  */
-  uint
-  diff_handlers(sp_pcontext *ctx, bool exclusive);
-  uint
-  diff_cursors(sp_pcontext *ctx, bool exclusive);
-
-
-  //
-  // Parameters and variables
-  //
-
-  /*
-    The maximum number of variables used in this and all child contexts
-    In the root, this gives us the number of slots needed for variables
-    during execution.
-  */
-  inline uint
-  max_var_index()
+  sp_condition_value(const char *_sql_state)
+   :Sql_alloc(),
+    type(SQLSTATE)
   {
-    return m_max_var_index;
+    memcpy(sql_state, _sql_state, SQLSTATE_LENGTH);
+    sql_state[SQLSTATE_LENGTH]= 0;
   }
 
-  /*
-    The current number of variables used in the parents (from the root),
-    including this context.
-  */
-  inline uint
-  current_var_count()
+  sp_condition_value(enum_type _type)
+   :Sql_alloc(),
+    type(_type)
   {
-    return m_var_offset + m_vars.elements;
+    DBUG_ASSERT(type != ERROR_CODE && type != SQLSTATE);
   }
 
-  /* The number of variables in this context alone */
-  inline uint
-  context_var_count()
-  {
-    return m_vars.elements;
-  }
+  /// Check if two instances of sp_condition_value are equal or not.
+  ///
+  /// @param cv another instance of sp_condition_value to check.
+  ///
+  /// @return true if the instances are equal, false otherwise.
+  bool equals(const sp_condition_value *cv) const;
+};
 
-  /* Map index in this pcontext to runtime offset */
-  inline uint
-  var_context2runtime(uint i)
-  {
-    return m_var_offset + i;
-  }
+///////////////////////////////////////////////////////////////////////////
 
-  /* Set type of variable. 'i' is the offset from the top */
-  inline void
-  set_type(uint i, enum enum_field_types type)
-  {
-    sp_variable *p= find_variable(i);
+/// This class represents 'DECLARE CONDITION' statement.
+/// sp_condition has little to do with SQL-conditions.
 
-    if (p)
-      p->type= type;
-  }
+class sp_condition : public Sql_alloc
+{
+public:
+  /// Name of the condition.
+  LEX_STRING name;
 
-  /* Set default value of variable. 'i' is the offset from the top */
-  inline void
-  set_default(uint i, Item *it)
-  {
-    sp_variable *p= find_variable(i);
+  /// Value of the condition.
+  sp_condition_value *value;
 
-    if (p)
-      p->dflt= it;
-  }
+public:
+  sp_condition(LEX_STRING _name, sp_condition_value *_value)
+   :Sql_alloc(),
+    name(_name),
+    value(_value)
+  { }
+};
 
-  sp_variable *
-  push_variable(LEX_STRING *name, enum enum_field_types type,
-                sp_variable::enum_mode mode);
-
-  /*
-    Retrieve definitions of fields from the current context and its
-    children.
-  */
-  void
-  retrieve_field_definitions(List<Create_field> *field_def_lst);
-
-  // Find by name
-  sp_variable *
-  find_variable(LEX_STRING *name, my_bool scoped=0);
-
-  // Find by offset (from the top)
-  sp_variable *
-  find_variable(uint offset);
-
-  /*
-    Set the current scope boundary (for default values).
-    The argument is the number of variables to skip.   
-  */
-  inline void
-  declare_var_boundary(uint n)
-  {
-    m_pboundary= n;
-  }
+///////////////////////////////////////////////////////////////////////////
 
-  /*
-    CASE expressions support.
-  */
+/// This class represents 'DECLARE HANDLER' statement.
 
-  inline int
-  register_case_expr()
+class sp_handler : public Sql_alloc
+{
+public:
+  /// Enumeration of possible handler types.
+  /// Note: UNDO handlers are not (and have never been) supported.
+  enum enum_type
   {
-    return m_num_case_exprs++;
-  }
+    EXIT,
+    CONTINUE
+  };
 
-  inline int
-  get_num_case_exprs() const
-  {
-    return m_num_case_exprs;
-  }
+  /// Handler type.
+  enum_type type;
 
-  inline bool
-  push_case_expr_id(int case_expr_id)
-  {
-    return insert_dynamic(&m_case_expr_id_lst, &case_expr_id);
-  }
+  /// Conditions caught by this handler.
+  List<sp_condition_value> condition_values;
 
-  inline void
-  pop_case_expr_id()
-  {
-    pop_dynamic(&m_case_expr_id_lst);
-  }
+public:
+  /// The constructor.
+  ///
+  /// @param _type SQL-handler type.
+  sp_handler(enum_type _type)
+   :Sql_alloc(),
+    type(_type)
+  { }
+};
 
-  inline int
-  get_current_case_expr_id() const
-  {
-    int case_expr_id;
+///////////////////////////////////////////////////////////////////////////
 
-    get_dynamic((DYNAMIC_ARRAY*)&m_case_expr_id_lst, (uchar*) &case_expr_id,
-                m_case_expr_id_lst.elements - 1);
+/// The class represents parse-time context, which keeps track of declared
+/// variables/parameters, conditions, handlers, cursors and labels.
+///
+/// sp_context objects are organized in a tree according to the following
+/// rules:
+///   - one sp_pcontext object corresponds for for each BEGIN..END block;
+///   - one sp_pcontext object corresponds for each exception handler;
+///   - one additional sp_pcontext object is created to contain
+///     Stored Program parameters.
+///
+/// sp_pcontext objects are used both at parse-time and at runtime.
+///
+/// During the parsing stage sp_pcontext objects are used:
+///   - to look up defined names (e.g. declared variables and visible
+///     labels);
+///   - to check for duplicates;
+///   - for error checking;
+///   - to calculate offsets to be used at runtime.
+///
+/// During the runtime phase, a tree of sp_pcontext objects is used:
+///   - for error checking (e.g. to check correct number of parameters);
+///   - to resolve SQL-handlers.
 
-    return case_expr_id;
-  }
+class sp_pcontext : public Sql_alloc
+{
+public:
+  enum enum_scope
+  {
+    /// REGULAR_SCOPE designates regular BEGIN ... END blocks.
+    REGULAR_SCOPE,
 
-  //
-  // Labels
-  //
+    /// HANDLER_SCOPE designates SQL-handler blocks.
+    HANDLER_SCOPE
+  };
 
-  sp_label *
-  push_label(char *name, uint ip);
+public:
+  sp_pcontext();
+  ~sp_pcontext();
 
-  sp_label *
-  find_label(char *name);
 
-  inline sp_label *
-  last_label()
-  {
-    sp_label *lab= m_label.head();
+  /// Create and push a new context in the tree.
 
-    if (!lab && m_parent)
-      lab= m_parent->last_label();
-    return lab;
-  }
+  /// @param thd   thread context.
+  /// @param scope scope of the new parsing context.
+  /// @return the node created.
+  sp_pcontext *push_context(THD *thd, enum_scope scope);
+
+  /// Pop a node from the parsing context tree.
+  /// @return the parent node.
+  sp_pcontext *pop_context();
+
+  sp_pcontext *parent_context() const
+  { return m_parent; }
+
+  /// Calculate and return the number of handlers to pop between the given
+  /// context and this one.
+  ///
+  /// @param ctx       the other parsing context.
+  /// @param exclusive specifies if the last scope should be excluded.
+  ///
+  /// @return the number of handlers to pop between the given context and
+  /// this one.  If 'exclusive' is true, don't count the last scope we are
+  /// leaving; this is used for LEAVE where we will jump to the hpop
+  /// instructions.
+  uint diff_handlers(const sp_pcontext *ctx, bool exclusive) const;
+
+  /// Calculate and return the number of cursors to pop between the given
+  /// context and this one.
+  ///
+  /// @param ctx       the other parsing context.
+  /// @param exclusive specifies if the last scope should be excluded.
+  ///
+  /// @return the number of cursors to pop between the given context and
+  /// this one.  If 'exclusive' is true, don't count the last scope we are
+  /// leaving; this is used for LEAVE where we will jump to the cpop
+  /// instructions.
+  uint diff_cursors(const sp_pcontext *ctx, bool exclusive) const;
+
+  /////////////////////////////////////////////////////////////////////////
+  // SP-variables (parameters and variables).
+  /////////////////////////////////////////////////////////////////////////
+
+  /// @return the maximum number of variables used in this and all child
+  /// contexts. For the root parsing context, this gives us the number of
+  /// slots needed for variables during the runtime phase.
+  uint max_var_index() const
+  { return m_max_var_index; }
+
+  /// @return the current number of variables used in the parent contexts
+  /// (from the root), including this context.
+  uint current_var_count() const
+  { return m_var_offset + m_vars.elements(); }
+
+  /// @return the number of variables in this context alone.
+  uint context_var_count() const
+  { return m_vars.elements(); }
+
+  /// @return map index in this parsing context to runtime offset.
+  uint var_context2runtime(uint i) const
+  { return m_var_offset + i; }
+
+  /// Add SP-variable to the parsing context.
+  ///
+  /// @param thd  Thread context.
+  /// @param name Name of the SP-variable.
+  /// @param type Type of the SP-variable.
+  /// @param mode Mode of the SP-variable.
+  ///
+  /// @return instance of newly added SP-variable.
+  sp_variable *add_variable(THD *thd,
+                            LEX_STRING name,
+                            enum enum_field_types type,
+                            sp_variable::enum_mode mode);
+
+  /// Retrieve full type information about SP-variables in this parsing
+  /// context and its children.
+  ///
+  /// @param field_def_lst[out] Container to store type information.
+  void retrieve_field_definitions(List<Create_field> *field_def_lst) const;
+
+  /// Find SP-variable by name.
+  ///
+  /// The function does a linear search (from newer to older variables,
+  /// in case we have shadowed names).
+  ///
+  /// The function is called only at parsing time.
+  ///
+  /// @param name               Variable name.
+  /// @param current_scope_only A flag if we search only in current scope.
+  ///
+  /// @return instance of found SP-variable, or NULL if not found.
+  sp_variable *find_variable(LEX_STRING name, bool current_scope_only) const;
+
+  /// Find SP-variable by the offset in the root parsing context.
+  ///
+  /// The function is used for two things:
+  /// - When evaluating parameters at the beginning, and setting out parameters
+  ///   at the end, of invocation. (Top frame only, so no recursion then.)
+  /// - For printing of sp_instr_set. (Debug mode only.)
+  ///
+  /// @param offset Variable offset in the root parsing context.
+  ///
+  /// @return instance of found SP-variable, or NULL if not found.
+  sp_variable *find_variable(uint offset) const;
+
+  /// Set the current scope boundary (for default values).
+  ///
+  /// @param n The number of variables to skip.
+  void declare_var_boundary(uint n)
+  { m_pboundary= n; }
+
+  /////////////////////////////////////////////////////////////////////////
+  // CASE expressions.
+  /////////////////////////////////////////////////////////////////////////
+
+  int register_case_expr()
+  { return m_num_case_exprs++; }
+
+  int get_num_case_exprs() const
+  { return m_num_case_exprs; }
+
+  bool push_case_expr_id(int case_expr_id)
+  { return m_case_expr_ids.append(case_expr_id); }
+
+  void pop_case_expr_id()
+  { m_case_expr_ids.pop(); }
+
+  int get_current_case_expr_id() const
+  { return *m_case_expr_ids.back(); }
+
+  /////////////////////////////////////////////////////////////////////////
+  // Labels.
+  /////////////////////////////////////////////////////////////////////////
+
+  sp_label *push_label(THD *thd, LEX_STRING name, uint ip);
+
+  sp_label *find_label(LEX_STRING name);
+
+  sp_label *last_label()
+  {
+    sp_label *label= m_labels.head();
+
+    if (!label && m_parent)
+      label= m_parent->last_label();
+
+    return label;
+  }
+
+  sp_label *pop_label()
+  { return m_labels.pop(); }
+
+  /////////////////////////////////////////////////////////////////////////
+  // Conditions.
+  /////////////////////////////////////////////////////////////////////////
+
+  bool add_condition(THD *thd, LEX_STRING name, sp_condition_value *value);
+
+  /// See comment for find_variable() above.
+  sp_condition_value *find_condition(LEX_STRING name,
+                                     bool current_scope_only) const;
+
+  /////////////////////////////////////////////////////////////////////////
+  // Handlers.
+  /////////////////////////////////////////////////////////////////////////
+
+  sp_handler *add_handler(THD* thd, sp_handler::enum_type type);
+
+  /// This is an auxilary parsing-time function to check if an SQL-handler
+  /// exists in the current parsing context (current scope) for the given
+  /// SQL-condition. This function is used to check for duplicates during
+  /// the parsing phase.
+  ///
+  /// This function can not be used during the runtime phase to check
+  /// SQL-handler existence because it searches for the SQL-handler in the
+  /// current scope only (during runtime, current and parent scopes
+  /// should be checked according to the SQL-handler resolution rules).
+  ///
+  /// @param condition_value the handler condition value
+  ///                        (not SQL-condition!).
+  ///
+  /// @retval true if such SQL-handler exists.
+  /// @retval false otherwise.
+  bool check_duplicate_handler(const sp_condition_value *cond_value) const;
+
+  /// Find an SQL handler for the given SQL condition according to the
+  /// SQL-handler resolution rules. This function is used at runtime.
+  ///
+  /// @param sql_state        The SQL condition state
+  /// @param sql_errno        The error code
+  /// @param level            The SQL condition level
+  ///
+  /// @return a pointer to the found SQL-handler or NULL.
+  sp_handler *find_handler(const char *sql_state,
+                           uint sql_errno,
+                           Sql_condition::enum_warning_level level) const;
+
+  /////////////////////////////////////////////////////////////////////////
+  // Cursors.
+  /////////////////////////////////////////////////////////////////////////
+
+  bool add_cursor(LEX_STRING name);
+
+  /// See comment for find_variable() above.
+  bool find_cursor(LEX_STRING name, uint *poff, bool current_scope_only) const;
 
-  inline sp_label *
-  pop_label()
-  {
-    return m_label.pop();
-  }
+  /// Find cursor by offset (for debugging only).
+  const LEX_STRING *find_cursor(uint offset) const;
 
-  //
-  // Conditions
-  //
-
-  int
-  push_cond(LEX_STRING *name, sp_condition_value *val);
-
-  sp_condition_value *
-  find_cond(LEX_STRING *name, my_bool scoped=0);
-
-  //
-  // Handlers
-  //
+  uint max_cursor_index() const
+  { return m_max_cursor_index + m_cursors.elements(); }
 
-  inline void
-  push_handler(sp_condition_value *cond)
-  {
-    insert_dynamic(&m_handlers, &cond);
-  }
+  uint current_cursor_count() const
+  { return m_cursor_offset + m_cursors.elements(); }
 
-  bool
-  find_handler(sp_condition_value *cond);
+private:
+  /// Constructor for a tree node.
+  /// @param prev the parent parsing context
+  /// @param scope scope of this parsing context
+  sp_pcontext(sp_pcontext *prev, enum_scope scope);
 
-  inline uint
-  max_handler_index()
-  {
-    return m_max_handler_index + m_context_handlers;
-  }
+  void init(uint var_offset, uint cursor_offset, int num_case_expressions);
 
-  inline void
-  add_handlers(uint n)
-  {
-    m_context_handlers+= n;
-  }
+  /* Prevent use of these */
+  sp_pcontext(const sp_pcontext &);
+  void operator=(sp_pcontext &);
 
-  //
-  // Cursors
-  //
-
-  int
-  push_cursor(LEX_STRING *name);
-
-  my_bool
-  find_cursor(LEX_STRING *name, uint *poff, my_bool scoped=0);
-
-  /* Find by offset (for debugging only) */
-  my_bool
-  find_cursor(uint offset, LEX_STRING *n);
+private:
+  /// m_max_var_index -- number of variables (including all types of arguments)
+  /// in this context including all children contexts.
+  ///
+  /// m_max_var_index >= m_vars.elements().
+  ///
+  /// m_max_var_index of the root parsing context contains number of all
+  /// variables (including arguments) in all enclosed contexts.
+  uint m_max_var_index;
 
-  inline uint
-  max_cursor_index()
-  {
-    return m_max_cursor_index + m_cursors.elements;
-  }
+  /// The maximum sub context's framesizes.
+  uint m_max_cursor_index;
 
-  inline uint
-  current_cursor_count()
-  {
-    return m_cursor_offset + m_cursors.elements;
-  }
+  /// Parent context.
+  sp_pcontext *m_parent;
 
-protected:
+  /// An index of the first SP-variable in this parsing context. The index
+  /// belongs to a runtime table of SP-variables.
+  ///
+  /// Note:
+  ///   - m_var_offset is 0 for root parsing context;
+  ///   - m_var_offset is different for all nested parsing contexts.
+  uint m_var_offset;
 
-  /**
-    Constructor for a tree node.
-    @param prev the parent parsing context
-    @param scope scope of this parsing context
-  */
-  sp_pcontext(sp_pcontext *prev, enum_scope scope);
+  /// Cursor offset for this context.
+  uint m_cursor_offset;
 
-  /*
-    m_max_var_index -- number of variables (including all types of arguments)
-    in this context including all children contexts.
-    
-    m_max_var_index >= m_vars.elements.
-
-    m_max_var_index of the root parsing context contains number of all
-    variables (including arguments) in all enclosed contexts.
-  */
-  uint m_max_var_index;		
+  /// Boundary for finding variables in this context. This is the number of
+  /// variables currently "invisible" to default clauses. This is normally 0,
+  /// but will be larger during parsing of DECLARE ... DEFAULT, to get the
+  /// scope right for DEFAULT values.
+  uint m_pboundary;
 
-  // The maximum sub context's framesizes
-  uint m_max_cursor_index;
-  uint m_max_handler_index;
-  uint m_context_handlers;      // No. of handlers in this context
+  int m_num_case_exprs;
 
-private:
+  /// SP parameters/variables.
+  Dynamic_array<sp_variable *> m_vars;
 
-  sp_pcontext *m_parent;	// Parent context
+  /// Stack of CASE expression ids.
+  Dynamic_array<int> m_case_expr_ids;
 
-  /*
-    m_var_offset -- this is an index of the first variable in this
-                    parsing context.
-    
-    m_var_offset is 0 for root context.
-
-    Since now each variable is stored in separate place, no reuse is done,
-    so m_var_offset is different for all enclosed contexts.
-  */
-  uint m_var_offset;
+  /// Stack of SQL-conditions.
+  Dynamic_array<sp_condition *> m_conditions;
 
-  uint m_cursor_offset;		// Cursor offset for this context
+  /// Stack of cursors.
+  Dynamic_array<LEX_STRING> m_cursors;
 
-  /*
-    Boundary for finding variables in this context. This is the number
-    of variables currently "invisible" to default clauses.
-    This is normally 0, but will be larger during parsing of
-    DECLARE ... DEFAULT, to get the scope right for DEFAULT values.
-  */
-  uint m_pboundary;
+  /// Stack of SQL-handlers.
+  Dynamic_array<sp_handler *> m_handlers;
 
-  int m_num_case_exprs;
+  /// List of labels.
+  List<sp_label> m_labels;
 
-  DYNAMIC_ARRAY m_vars;		// Parameters/variables
-  DYNAMIC_ARRAY m_case_expr_id_lst; /* Stack of CASE expression ids. */
-  DYNAMIC_ARRAY m_conds;        // Conditions
-  DYNAMIC_ARRAY m_cursors;	// Cursors
-  DYNAMIC_ARRAY m_handlers;	// Handlers, for checking for duplicates
-
-  List<sp_label> m_label;	// The label list
-
-  List<sp_pcontext> m_children;	// Children contexts, used for destruction
-
-  /**
-    Scope of this parsing context.
-  */
-  enum_scope m_scope;
+  /// Children contexts, used for destruction.
+  Dynamic_array<sp_pcontext *> m_children;
 
-private:
-  sp_pcontext(const sp_pcontext &); /* Prevent use of these */
-  void operator=(sp_pcontext &);
+  /// Scope of this parsing context.
+  enum_scope m_scope;
 }; // class sp_pcontext : public Sql_alloc
 
 

=== modified file 'sql/sp_rcontext.cc'
--- a/sql/sp_rcontext.cc	2011-08-02 08:34:30 +0000
+++ b/sql/sp_rcontext.cc	2011-10-11 15:01:02 +0000
@@ -22,23 +22,22 @@
 #include "sp_pcontext.h"
 #include "sql_select.h"                     // create_virtual_tmp_table
 
-sp_rcontext::sp_rcontext(sp_pcontext *root_parsing_ctx,
+
+///////////////////////////////////////////////////////////////////////////
+// sp_rcontext implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+sp_rcontext::sp_rcontext(const sp_pcontext *root_parsing_ctx,
                          Field *return_value_fld,
-                         sp_rcontext *prev_runtime_ctx)
-  :end_partial_result_set(FALSE),
+                         bool in_sub_stmt)
+  :end_partial_result_set(false),
    m_root_parsing_ctx(root_parsing_ctx),
-   m_var_table(0),
-   m_var_items(0),
+   m_var_table(NULL),
    m_return_value_fld(return_value_fld),
-   m_return_value_set(FALSE),
-   in_sub_stmt(FALSE),
-   m_hcount(0),
-   m_hsp(0),
-   m_ihsp(0),
-   m_hfound(-1),
-   m_ccount(0),
-   m_case_expr_holders(0),
-   m_prev_runtime_ctx(prev_runtime_ctx)
+   m_return_value_set(false),
+   m_in_sub_stmt(in_sub_stmt),
+   m_ccount(0)
 {
 }
 
@@ -47,427 +46,307 @@ sp_rcontext::~sp_rcontext()
 {
   if (m_var_table)
     free_blobs(m_var_table);
-}
-
 
-/*
-  Initialize sp_rcontext instance.
+  // Leave m_handlers, m_handler_call_stack, m_var_items, m_cstack
+  // and m_case_expr_holders untouched.
+  // They are allocated in mem roots and will be freed accordingly.
+}
 
-  SYNOPSIS
-    thd   Thread handle
-  RETURN
-    FALSE   on success
-    TRUE    on error
-*/
 
-bool sp_rcontext::init(THD *thd)
+sp_rcontext *sp_rcontext::create(THD *thd,
+                                 const sp_pcontext *root_parsing_ctx,
+                                 Field *return_value_fld)
 {
-  uint handler_count= m_root_parsing_ctx->max_handler_index();
-  uint i;
+  sp_rcontext *ctx= new (thd->mem_root) sp_rcontext(root_parsing_ctx,
+                                                    return_value_fld,
+                                                    thd->in_sub_stmt);
+
+  if (!ctx)
+    return NULL;
 
-  in_sub_stmt= thd->in_sub_stmt;
+  if (ctx->alloc_arrays(thd) ||
+      ctx->init_var_table(thd) ||
+      ctx->init_var_items(thd))
+  {
+    delete ctx;
+    return NULL;
+  }
 
-  if (init_var_table(thd) || init_var_items())
-    return TRUE;
-
-  if (!(m_raised_conditions= new (thd->mem_root) Sql_condition[handler_count]))
-    return TRUE;
-
-  for (i= 0; i<handler_count; i++)
-    m_raised_conditions[i].init(thd->mem_root);
-
-  return
-    !(m_handler=
-      (sp_handler*)thd->alloc(handler_count * sizeof(sp_handler))) ||
-    !(m_hstack=
-      (uint*)thd->alloc(handler_count * sizeof(uint))) ||
-    !(m_in_handler=
-      (sp_active_handler*)thd->alloc(handler_count *
-                                     sizeof(sp_active_handler))) ||
-    !(m_cstack=
-      (sp_cursor**)thd->alloc(m_root_parsing_ctx->max_cursor_index() *
-                              sizeof(sp_cursor*))) ||
-    !(m_case_expr_holders=
-      (Item_cache**)thd->calloc(m_root_parsing_ctx->get_num_case_exprs() *
-                               sizeof (Item_cache*)));
+  return ctx;
 }
 
 
-/*
-  Create and initialize a table to store SP-vars.
+bool sp_rcontext::alloc_arrays(THD *thd)
+{
+  {
+    size_t n= m_root_parsing_ctx->max_cursor_index();
+    m_cstack.reset(
+      static_cast<sp_cursor **> (
+        thd->alloc(n * sizeof (sp_cursor*))),
+      n);
+  }
 
-  SYNOPSIS
-    thd   Thread handler.
-  RETURN
-    FALSE   on success
-    TRUE    on error
-*/
+  {
+    size_t n= m_root_parsing_ctx->get_num_case_exprs();
+    m_case_expr_holders.reset(
+      static_cast<Item_cache **> (
+        thd->calloc(n * sizeof (Item_cache*))),
+      n);
+  }
+
+  return !m_cstack.array() || !m_case_expr_holders.array();
+}
 
-bool
-sp_rcontext::init_var_table(THD *thd)
+
+bool sp_rcontext::init_var_table(THD *thd)
 {
   List<Create_field> field_def_lst;
 
   if (!m_root_parsing_ctx->max_var_index())
-    return FALSE;
+    return false;
 
   m_root_parsing_ctx->retrieve_field_definitions(&field_def_lst);
 
   DBUG_ASSERT(field_def_lst.elements == m_root_parsing_ctx->max_var_index());
-  
+
   if (!(m_var_table= create_virtual_tmp_table(thd, field_def_lst)))
-    return TRUE;
+    return true;
 
-  m_var_table->copy_blobs= TRUE;
+  m_var_table->copy_blobs= true;
   m_var_table->alias= "";
 
-  return FALSE;
+  return false;
 }
 
 
-/*
-  Create and initialize an Item-adapter (Item_field) for each SP-var field.
-
-  RETURN
-    FALSE   on success
-    TRUE    on error
-*/
-
-bool
-sp_rcontext::init_var_items()
+bool sp_rcontext::init_var_items(THD *thd)
 {
-  uint idx;
   uint num_vars= m_root_parsing_ctx->max_var_index();
 
-  if (!(m_var_items= (Item**) sql_alloc(num_vars * sizeof (Item *))))
-    return TRUE;
+  m_var_items.reset(
+    static_cast<Item **> (
+      thd->alloc(num_vars * sizeof (Item *))),
+    num_vars);
+
+  if (!m_var_items.array())
+    return true;
 
-  for (idx = 0; idx < num_vars; ++idx)
+  for (uint idx = 0; idx < num_vars; ++idx)
   {
     if (!(m_var_items[idx]= new Item_field(m_var_table->field[idx])))
-      return TRUE;
+      return true;
   }
 
-  return FALSE;
+  return false;
 }
 
 
-bool
-sp_rcontext::set_return_value(THD *thd, Item **return_value_item)
+bool sp_rcontext::set_return_value(THD *thd, Item **return_value_item)
 {
   DBUG_ASSERT(m_return_value_fld);
 
-  m_return_value_set = TRUE;
+  m_return_value_set = true;
 
   return sp_eval_expr(thd, m_return_value_fld, return_value_item);
 }
 
 
-#define IS_WARNING_CONDITION(S)   ((S)[0] == '0' && (S)[1] == '1')
-#define IS_NOT_FOUND_CONDITION(S) ((S)[0] == '0' && (S)[1] == '2')
-#define IS_EXCEPTION_CONDITION(S) ((S)[0] != '0' || (S)[1] > '2')
-
-/**
-  Find an SQL handler for the given error.
-
-  SQL handlers are pushed on the stack m_handler, with the latest/innermost
-  one on the top; we then search for matching handlers from the top and
-  down.
-
-  We search through all the handlers, looking for the most specific one
-  (sql_errno more specific than sqlstate more specific than the rest).
-  Note that mysql error code handlers is a MySQL extension, not part of
-  the standard.
-
-  SQL handlers for warnings are searched in the current scope only.
-
-  SQL handlers for errors are searched in the current and in outer scopes.
-  That's why finding and activation of handler must be separated: an errror
-  handler might be located in the outer scope, which is not active at the
-  moment. Before such handler can be activated, execution flow should
-  unwind to that scope.
-
-  Found SQL handler is remembered in m_hfound for future activation.
-  If no handler is found, m_hfound is -1.
-
-  @param thd        Thread handle
-  @param sql_errno  The error code
-  @param sqlstate   The error SQL state
-  @param level      The error level
-  @param msg        The error message
-
-  @retval TRUE  if an SQL handler was found
-  @retval FALSE otherwise
-*/
-
-bool
-sp_rcontext::find_handler(THD *thd,
-                          uint sql_errno,
-                          const char *sqlstate,
-                          Sql_condition::enum_warning_level level,
-                          const char *msg)
+bool sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper,
+                              sp_instr_cpush *i)
 {
-  int i= m_hcount;
-
-  /* Reset previously found handler. */
-  m_hfound= -1;
-
   /*
-    If this is a fatal sub-statement error, and this runtime
-    context corresponds to a sub-statement, no CONTINUE/EXIT
-    handlers from this context are applicable: try to locate one
-    in the outer scope.
+    We should create cursors in the callers arena, as
+    it could be (and usually is) used in several instructions.
   */
-  if (thd->is_fatal_sub_stmt_error && in_sub_stmt)
-    i= 0;
-
-  /* Search handlers from the latest (innermost) to the oldest (outermost) */
-  while (i--)
-  {
-    sp_condition_value *cond= m_handler[i].cond;
-    int j= m_ihsp;
+  sp_cursor *c= new (callers_arena->mem_root) sp_cursor(lex_keeper, i);
 
-    /* Check active handlers, to avoid invoking one recursively */
-    while (j--)
-      if (m_in_handler[j].ip == m_handler[i].handler)
-	break;
-    if (j >= 0)
-      continue;                 // Already executing this handler
+  if (c == NULL)
+    return true;
 
-    switch (cond->type)
-    {
-    case sp_condition_value::number:
-      if (sql_errno == cond->mysqlerr &&
-          (m_hfound < 0 || m_handler[m_hfound].cond->type > sp_condition_value::number))
-	m_hfound= i;		// Always the most specific
-      break;
-    case sp_condition_value::state:
-      if (strcmp(sqlstate, cond->sqlstate) == 0 &&
-	  (m_hfound < 0 || m_handler[m_hfound].cond->type > sp_condition_value::state))
-	m_hfound= i;
-      break;
-    case sp_condition_value::warning:
-      if ((IS_WARNING_CONDITION(sqlstate) ||
-           level == Sql_condition::WARN_LEVEL_WARN) &&
-          m_hfound < 0)
-	m_hfound= i;
-      break;
-    case sp_condition_value::notfound:
-      if (IS_NOT_FOUND_CONDITION(sqlstate) && m_hfound < 0)
-	m_hfound= i;
-      break;
-    case sp_condition_value::exception:
-      if (IS_EXCEPTION_CONDITION(sqlstate) &&
-	  level == Sql_condition::WARN_LEVEL_ERROR &&
-	  m_hfound < 0)
-	m_hfound= i;
-      break;
-    }
-  }
-
-  if (m_hfound >= 0)
-  {
-    DBUG_ASSERT((uint) m_hfound < m_root_parsing_ctx->max_handler_index());
-
-    m_raised_conditions[m_hfound].clear();
-    m_raised_conditions[m_hfound].set(sql_errno, sqlstate, level, msg);
-
-    return TRUE;
-  }
-
-  /*
-    Only "exception conditions" are propagated to handlers in calling
-    contexts. If no handler is found locally for a "completion condition"
-    (warning or "not found") we will simply resume execution.
-  */
-  if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) &&
-      level == Sql_condition::WARN_LEVEL_ERROR)
-  {
-    return m_prev_runtime_ctx->find_handler(thd, sql_errno, sqlstate,
-                                            level, msg);
-  }
-
-  return FALSE;
+  m_cstack[m_ccount++]= c;
+  return false;
 }
 
-void
-sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
-{
-  DBUG_ENTER("sp_rcontext::push_cursor");
-  DBUG_ASSERT(m_ccount < m_root_parsing_ctx->max_cursor_index());
-  m_cstack[m_ccount++]= new sp_cursor(lex_keeper, i);
-  DBUG_PRINT("info", ("m_ccount: %d", m_ccount));
-  DBUG_VOID_RETURN;
-}
 
-void
-sp_rcontext::pop_cursors(uint count)
+void sp_rcontext::pop_cursors(uint count)
 {
-  DBUG_ENTER("sp_rcontext::pop_cursors");
   DBUG_ASSERT(m_ccount >= count);
+
   while (count--)
-  {
     delete m_cstack[--m_ccount];
-  }
-  DBUG_PRINT("info", ("m_ccount: %d", m_ccount));
-  DBUG_VOID_RETURN;
 }
 
-void
-sp_rcontext::push_handler(sp_condition_value *cond, uint h, int type)
-{
-  DBUG_ENTER("sp_rcontext::push_handler");
-  DBUG_ASSERT(m_hcount < m_root_parsing_ctx->max_handler_index());
-
-  m_handler[m_hcount].cond= cond;
-  m_handler[m_hcount].handler= h;
-  m_handler[m_hcount].type= type;
-  m_hcount+= 1;
 
-  DBUG_PRINT("info", ("m_hcount: %d", m_hcount));
-  DBUG_VOID_RETURN;
-}
-
-void
-sp_rcontext::pop_handlers(uint count)
+bool sp_rcontext::push_handler(sp_handler *handler, uint first_ip)
 {
-  DBUG_ENTER("sp_rcontext::pop_handlers");
-  DBUG_ASSERT(m_hcount >= count);
+  /*
+    We should create handler entries in the callers arena, as
+    they could be (and usually are) used in several instructions.
+  */
+  sp_handler_entry *he=
+    new (callers_arena->mem_root) sp_handler_entry(handler, first_ip);
 
-  m_hcount-= count;
+  if (he == NULL)
+    return true;
 
-  DBUG_PRINT("info", ("m_hcount: %d", m_hcount));
-  DBUG_VOID_RETURN;
+  return m_handlers.append(he);
 }
 
-void
-sp_rcontext::push_hstack(uint h)
-{
-  DBUG_ENTER("sp_rcontext::push_hstack");
-  DBUG_ASSERT(m_hsp < m_root_parsing_ctx->max_handler_index());
 
-  m_hstack[m_hsp++]= h;
+void sp_rcontext::pop_handlers(int count)
+{
+  DBUG_ASSERT(m_handlers.elements() >= count);
 
-  DBUG_PRINT("info", ("m_hsp: %d", m_hsp));
-  DBUG_VOID_RETURN;
+  for (int i= 0; i < count; ++i)
+    m_handlers.pop();
 }
 
-uint
-sp_rcontext::pop_hstack()
+
+bool sp_rcontext::handle_sql_condition(THD *thd,
+                                       uint *ip,
+                                       const sp_instr *cur_spi)
 {
-  uint handler;
-  DBUG_ENTER("sp_rcontext::pop_hstack");
-  DBUG_ASSERT(m_hsp);
+  DBUG_ENTER("sp_rcontext::handle_sql_condition");
 
-  handler= m_hstack[--m_hsp];
+  /*
+    If this is a fatal sub-statement error, and this runtime
+    context corresponds to a sub-statement, no CONTINUE/EXIT
+    handlers from this context are applicable: try to locate one
+    in the outer scope.
+  */
+  if (thd->is_fatal_sub_stmt_error && m_in_sub_stmt)
+    DBUG_RETURN(false);
 
-  DBUG_PRINT("info", ("m_hsp: %d", m_hsp));
-  DBUG_RETURN(handler);
-}
+  Diagnostics_area *da= thd->get_stmt_da();
+  const sp_handler *found_handler= NULL;
+  const Sql_condition *found_condition= NULL;
 
-/**
-  Prepare found handler to be executed.
+  if (thd->is_error())
+  {
+    found_handler=
+      cur_spi->m_ctx->find_handler(da->get_sqlstate(),
+                                   da->sql_errno(),
+                                   Sql_condition::WARN_LEVEL_ERROR);
 
-  @retval TRUE if an SQL handler is activated (was found) and IP of the
-          first handler instruction.
-  @retval FALSE if there is no active handler
-*/
+    if (found_handler)
+      found_condition= da->get_error_condition();
+  }
+  else if (da->current_statement_warn_count())
+  {
+    Diagnostics_area::Sql_condition_iterator it= da->sql_conditions();
+    const Sql_condition *c;
 
-bool
-sp_rcontext::activate_handler(THD *thd,
-                              uint *ip,
-                              sp_instr *instr,
-                              Query_arena *execute_arena,
-                              Query_arena *backup_arena)
-{
-  if (m_hfound < 0)
-    return FALSE;
+    // Here we need to find the last warning/note from the stack.
+    // In MySQL most substantial warning is the last one.
+    // (We could have used a reverse iterator here if one existed)
 
-  switch (m_handler[m_hfound].type) {
-  case SP_HANDLER_NONE:
-    break;
+    while ((c= it++))
+    {
+      if (c->get_level() == Sql_condition::WARN_LEVEL_WARN ||
+          c->get_level() == Sql_condition::WARN_LEVEL_NOTE)
+      {
+        const sp_handler *handler=
+          cur_spi->m_ctx->find_handler(c->get_sqlstate(),
+                                       c->get_sql_errno(),
+                                       c->get_level());
+        if (handler)
+        {
+          found_handler= handler;
+          found_condition= c;
+        }
+      }
+    }
+  }
 
-  case SP_HANDLER_CONTINUE:
-    thd->restore_active_arena(execute_arena, backup_arena);
-    thd->set_n_backup_active_arena(execute_arena, backup_arena);
-    push_hstack(instr->get_cont_dest());
+  if (!found_handler)
+    DBUG_RETURN(false);
 
-    /* Fall through */
+  // At this point, we know that:
+  //  - there is a pending SQL-condition (error or warning);
+  //  - there is an SQL-handler for it.
 
-  default:
-    /* End aborted result set. */
+  DBUG_ASSERT(found_condition);
 
-    if (end_partial_result_set)
-      thd->protocol->end_partial_result_set(thd);
+  sp_handler_entry *handler_entry= NULL;
+  for (int i= 0; i < m_handlers.elements(); ++i)
+  {
+    sp_handler_entry *h= m_handlers.at(i);
 
-    /* Enter handler. */
+    if (h->handler == found_handler)
+    {
+      handler_entry= h;
+      break;
+    }
+  }
 
-    DBUG_ASSERT(m_ihsp < m_root_parsing_ctx->max_handler_index());
-    DBUG_ASSERT(m_hfound >= 0);
+  /*
+    handler_entry usually should not be NULL here, as that indicates
+    that the parser context thinks a HANDLER should be activated,
+    but the runtime context cannot find it.
+
+    However, this can happen (and this is in line with the Standard)
+    if SQL-condition has been raised before DECLARE HANDLER instruction
+    is processed.
+
+    For example:
+    CREATE PROCEDURE p()
+    BEGIN
+      DECLARE v INT DEFAULT 'get'; -- raises SQL-warning here
+      DECLARE EXIT HANDLER ...     -- this handler does not catch the warning
+    END
+  */
+  if (!handler_entry)
+    DBUG_RETURN(false);
 
-    m_in_handler[m_ihsp].ip= m_handler[m_hfound].handler;
-    m_in_handler[m_ihsp].index= m_hfound;
-    m_ihsp++;
+  // Mark active conditions so that they can be deleted when the handler exits.
+  da->mark_sql_conditions_for_removal();
 
-    DBUG_PRINT("info", ("Entering handler..."));
-    DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp));
+  uint continue_ip= handler_entry->handler->type == sp_handler::CONTINUE ?
+    cur_spi->get_cont_dest() : 0;
 
-    /* Reset error state. */
+  /* End aborted result set. */
+  if (end_partial_result_set)
+    thd->protocol->end_partial_result_set(thd);
 
-    thd->clear_error();
-    thd->killed= THD::NOT_KILLED; // Some errors set thd->killed
-                                  // (e.g. "bad data").
+  /* Reset error state. */
+  thd->clear_error();
+  thd->killed= THD::NOT_KILLED; // Some errors set thd->killed
+                                // (e.g. "bad data").
 
-    /* Return IP of the activated SQL handler. */
-    *ip= m_handler[m_hfound].handler;
+  /* Add a frame to handler-call-stack. */
+  Sql_condition_info *cond_info=
+    new (callers_arena->mem_root) Sql_condition_info(found_condition,
+                                                     callers_arena);
+  Handler_call_frame *frame=
+    new (callers_arena->mem_root) Handler_call_frame(cond_info, continue_ip);
+  m_handler_call_stack.append(frame);
 
-    /* Reset found handler. */
-    m_hfound= -1;
-  }
+  *ip= handler_entry->first_ip;
 
-  return TRUE;
+  DBUG_RETURN(true);
 }
 
-void
-sp_rcontext::exit_handler()
-{
-  DBUG_ENTER("sp_rcontext::exit_handler");
-  DBUG_ASSERT(m_ihsp);
-
-  uint hindex= m_in_handler[m_ihsp-1].index;
-  m_raised_conditions[hindex].clear();
-  m_ihsp-= 1;
-
-  DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp));
-  DBUG_VOID_RETURN;
-}
 
-Sql_condition*
-sp_rcontext::raised_condition() const
+uint sp_rcontext::exit_handler(Diagnostics_area *da)
 {
-  if (m_ihsp > 0)
-  {
-    uint hindex= m_in_handler[m_ihsp - 1].index;
-    Sql_condition *raised= & m_raised_conditions[hindex];
-    return raised;
-  }
+  DBUG_ENTER("sp_rcontext::exit_handler");
+  DBUG_ASSERT(m_handler_call_stack.elements() > 0);
 
-  if (m_prev_runtime_ctx)
-    return m_prev_runtime_ctx->raised_condition();
+  Handler_call_frame *f= m_handler_call_stack.pop();
 
-  return NULL;
-}
+  /*
+    Remove the SQL conditions that were present in DA when the
+    handler was activated.
+  */
+  da->remove_marked_sql_conditions();
 
+  uint continue_ip= f->continue_ip;
 
-int
-sp_rcontext::set_variable(THD *thd, uint var_idx, Item **value)
-{
-  return set_variable(thd, m_var_table->field[var_idx], value);
+  DBUG_RETURN(continue_ip);
 }
 
 
-int
-sp_rcontext::set_variable(THD *thd, Field *field, Item **value)
+int sp_rcontext::set_variable(THD *thd, Field *field, Item **value)
 {
   if (!value)
   {
@@ -479,25 +358,47 @@ sp_rcontext::set_variable(THD *thd, Fiel
 }
 
 
-Item *
-sp_rcontext::get_item(uint var_idx)
+Item_cache *sp_rcontext::create_case_expr_holder(THD *thd,
+                                                 const Item *item) const
 {
-  return m_var_items[var_idx];
+  Item_cache *holder;
+  Query_arena current_arena;
+
+  thd->set_n_backup_active_arena(thd->spcont->callers_arena, &current_arena);
+
+  holder= Item_cache::get_cache(item);
+
+  thd->restore_active_arena(thd->spcont->callers_arena, &current_arena);
+
+  return holder;
 }
 
 
-Item **
-sp_rcontext::get_item_addr(uint var_idx)
+bool sp_rcontext::set_case_expr(THD *thd, int case_expr_id,
+                                Item **case_expr_item_ptr)
 {
-  return m_var_items + var_idx;
+  Item *case_expr_item= sp_prepare_func_item(thd, case_expr_item_ptr);
+  if (!case_expr_item)
+    return true;
+
+  if (!m_case_expr_holders[case_expr_id] ||
+      m_case_expr_holders[case_expr_id]->result_type() !=
+        case_expr_item->result_type())
+  {
+    m_case_expr_holders[case_expr_id]=
+      create_case_expr_holder(thd, case_expr_item);
+  }
+
+  m_case_expr_holders[case_expr_id]->store(case_expr_item);
+  m_case_expr_holders[case_expr_id]->cache_value();
+  return false;
 }
 
 
-/*
- *
- *  sp_cursor
- *
- */
+///////////////////////////////////////////////////////////////////////////
+// sp_cursor implementation.
+///////////////////////////////////////////////////////////////////////////
+
 
 sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
   :m_lex_keeper(lex_keeper),
@@ -524,8 +425,7 @@ sp_cursor::sp_cursor(sp_lex_keeper *lex_
    0 in case of success, -1 otherwise
 */
 
-int
-sp_cursor::open(THD *thd)
+int sp_cursor::open(THD *thd)
 {
   if (server_side_cursor)
   {
@@ -539,8 +439,7 @@ sp_cursor::open(THD *thd)
 }
 
 
-int
-sp_cursor::close(THD *thd)
+int sp_cursor::close(THD *thd)
 {
   if (! server_side_cursor)
   {
@@ -552,16 +451,14 @@ sp_cursor::close(THD *thd)
 }
 
 
-void
-sp_cursor::destroy()
+void sp_cursor::destroy()
 {
   delete server_side_cursor;
-  server_side_cursor= 0;
+  server_side_cursor= NULL;
 }
 
 
-int
-sp_cursor::fetch(THD *thd, List<sp_variable> *vars)
+int sp_cursor::fetch(THD *thd, List<sp_variable> *vars)
 {
   if (! server_side_cursor)
   {
@@ -600,108 +497,13 @@ sp_cursor::fetch(THD *thd, List<sp_varia
 }
 
 
-/*
-  Create an instance of appropriate Item_cache class depending on the
-  specified type in the callers arena.
-
-  SYNOPSIS
-    thd           thread handler
-    result_type   type of the expression
-
-  RETURN
-    Pointer to valid object     on success
-    NULL                        on error
-
-  NOTE
-    We should create cache items in the callers arena, as they are used
-    between in several instructions.
-*/
-
-Item_cache *
-sp_rcontext::create_case_expr_holder(THD *thd, const Item *item)
-{
-  Item_cache *holder;
-  Query_arena current_arena;
-
-  thd->set_n_backup_active_arena(thd->spcont->callers_arena, &current_arena);
-
-  holder= Item_cache::get_cache(item);
-
-  thd->restore_active_arena(thd->spcont->callers_arena, &current_arena);
-
-  return holder;
-}
-
-
-/*
-  Set CASE expression to the specified value.
-
-  SYNOPSIS
-    thd             thread handler
-    case_expr_id    identifier of the CASE expression
-    case_expr_item  a value of the CASE expression
-
-  RETURN
-    FALSE   on success
-    TRUE    on error
-
-  NOTE
-    The idea is to reuse Item_cache for the expression of the one CASE
-    statement. This optimization takes place when there is CASE statement
-    inside of a loop. So, in other words, we will use the same object on each
-    iteration instead of creating a new one for each iteration.
-
-  TODO
-    Hypothetically, a type of CASE expression can be different for each
-    iteration. For instance, this can happen if the expression contains a
-    session variable (something like @@VAR) and its type is changed from one
-    iteration to another.
-    
-    In order to cope with this problem, we check type each time, when we use
-    already created object. If the type does not match, we re-create Item.
-    This also can (should?) be optimized.
-*/
-
-int
-sp_rcontext::set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr)
-{
-  Item *case_expr_item= sp_prepare_func_item(thd, case_expr_item_ptr);
-  if (!case_expr_item)
-    return TRUE;
-
-  if (!m_case_expr_holders[case_expr_id] ||
-      m_case_expr_holders[case_expr_id]->result_type() !=
-        case_expr_item->result_type())
-  {
-    m_case_expr_holders[case_expr_id]=
-      create_case_expr_holder(thd, case_expr_item);
-  }
-
-  m_case_expr_holders[case_expr_id]->store(case_expr_item);
-  m_case_expr_holders[case_expr_id]->cache_value();
-  return FALSE;
-}
-
-
-Item *
-sp_rcontext::get_case_expr(int case_expr_id)
-{
-  return m_case_expr_holders[case_expr_id];
-}
-
-
-Item **
-sp_rcontext::get_case_expr_addr(int case_expr_id)
-{
-  return (Item**) m_case_expr_holders + case_expr_id;
-}
-
+///////////////////////////////////////////////////////////////////////////
+// sp_cursor::Select_fetch_into_spvars implementation.
+///////////////////////////////////////////////////////////////////////////
 
-/***************************************************************************
- Select_fetch_into_spvars
-****************************************************************************/
 
-int Select_fetch_into_spvars::prepare(List<Item> &fields, SELECT_LEX_UNIT *u)
+int sp_cursor::Select_fetch_into_spvars::prepare(List<Item> &fields,
+                                                 SELECT_LEX_UNIT *u)
 {
   /*
     Cache the number of columns in the result set in order to easily
@@ -712,7 +514,7 @@ int Select_fetch_into_spvars::prepare(Li
 }
 
 
-bool Select_fetch_into_spvars::send_data(List<Item> &items)
+bool sp_cursor::Select_fetch_into_spvars::send_data(List<Item> &items)
 {
   List_iterator_fast<sp_variable> spvar_iter(*spvar_list);
   List_iterator_fast<Item> item_iter(items);
@@ -729,7 +531,7 @@ bool Select_fetch_into_spvars::send_data
   for (; spvar= spvar_iter++, item= item_iter++; )
   {
     if (thd->spcont->set_variable(thd, spvar->offset, &item))
-      return TRUE;
+      return true;
   }
-  return FALSE;
+  return false;
 }

=== modified file 'sql/sp_rcontext.h'
--- a/sql/sp_rcontext.h	2011-08-02 08:34:30 +0000
+++ b/sql/sp_rcontext.h	2011-09-20 12:54:31 +0000
@@ -18,41 +18,18 @@
 #define _SP_RCONTEXT_H_
 
 #include "sql_class.h"                    // select_result_interceptor
+#include "sp_pcontext.h"                  // sp_condition_value
+
+///////////////////////////////////////////////////////////////////////////
+// sp_rcontext declaration.
+///////////////////////////////////////////////////////////////////////////
 
-struct sp_condition_value;
 class sp_cursor;
-struct sp_variable;
 class sp_lex_keeper;
 class sp_instr_cpush;
 class Query_arena;
 class sp_head;
-class sp_pcontext;
 class Item_cache;
-typedef class st_select_lex_unit SELECT_LEX_UNIT;
-class Server_side_cursor;
-
-#define SP_HANDLER_NONE      0
-#define SP_HANDLER_EXIT      1
-#define SP_HANDLER_CONTINUE  2
-#define SP_HANDLER_UNDO      3
-
-struct sp_handler
-{
-  /** Condition caught by this HANDLER. */
-  sp_condition_value *cond;
-  /** Location (instruction pointer) of the handler code. */
-  uint handler;
-  /** Handler type (EXIT, CONTINUE). */
-  int type;
-};
-
-struct sp_active_handler
-{
-  /** Instruction pointer of the active handler. */
-  uint ip;
-  /** Handler index of the active handler. */
-  uint index;
-};
 
 /*
   This class is a runtime context of a Stored Routine. It is used in an
@@ -75,252 +52,412 @@ struct sp_active_handler
 
 class sp_rcontext : public Sql_alloc
 {
-  sp_rcontext(const sp_rcontext &); /* Prevent use of these */
-  void operator=(sp_rcontext &);
-
- public:
-
-  /*
-    Arena used to (re) allocate items on . E.g. reallocate INOUT/OUT
-    SP parameters when they don't fit into prealloced items. This
-    is common situation with String items. It is used mainly in
-    sp_eval_func_item().
-  */
-  Query_arena *callers_arena;
-
-  /*
-    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.
-  */
-  bool end_partial_result_set;
-
-#ifndef DBUG_OFF
-  /*
-    The routine for which this runtime context is created. Used for checking
-    if correct runtime context is used for variable handling.
-  */
-  sp_head *sp;
-#endif
-
-  sp_rcontext(sp_pcontext *root_parsing_ctx, Field *return_value_fld,
-              sp_rcontext *prev_runtime_ctx);
-  bool init(THD *thd);
+public:
+  /// Construct and properly initialize a new sp_rcontext instance. The static
+  /// create-function is needed because we need a way to return an error from
+  /// the constructor.
+  ///
+  /// @param thd              Thread handle.
+  /// @param root_parsing_ctx Top-level parsing context for this stored program.
+  /// @param return_value_fld Field object to store the return value
+  ///                         (for stored functions only).
+  ///
+  /// @return valid sp_rcontext object or NULL in case of OOM-error.
+  static sp_rcontext *create(THD *thd,
+                             const sp_pcontext *root_parsing_ctx,
+                             Field *return_value_fld);
 
   ~sp_rcontext();
 
-  int
-  set_variable(THD *thd, uint var_idx, Item **value);
-
-  Item *
-  get_item(uint var_idx);
-
-  Item **
-  get_item_addr(uint var_idx);
+private:
+  sp_rcontext(const sp_pcontext *root_parsing_ctx,
+              Field *return_value_fld,
+              bool in_sub_stmt);
 
-  bool
-  set_return_value(THD *thd, Item **return_value_item);
+  // Prevent use of copying constructor and operator.
+  sp_rcontext(const sp_rcontext &);
+  void operator=(sp_rcontext &);
 
-  inline bool
-  is_return_value_set() const
+private:
+  /// This is an auxillary class to store entering instruction pointer for an
+  /// SQL-handler.
+  class sp_handler_entry : public Sql_alloc
   {
-    return m_return_value_set;
-  }
-
-  /*
-    SQL handlers support.
-  */
-
-  void push_handler(sp_condition_value *cond, uint h, int type);
+  public:
+    /// Handler definition (from parsing context).
+    const sp_handler *handler;
+
+    /// Instruction pointer to the first instruction.
+    uint first_ip;
+
+    /// The constructor.
+    ///
+    /// @param _handler   sp_handler object.
+    /// @param _first_ip  first instruction pointer.
+    sp_handler_entry(const sp_handler *_handler, uint _first_ip)
+     :handler(_handler), first_ip(_first_ip)
+    { }
+  };
 
-  void pop_handlers(uint count);
-
-  bool
-  find_handler(THD *thd,
-               uint sql_errno,
-               const char *sqlstate,
-               Sql_condition::enum_warning_level level,
-               const char *msg);
-
-  Sql_condition *
-  raised_condition() const;
-
-  void
-  push_hstack(uint h);
-
-  uint
-  pop_hstack();
+public:
+  /// This class stores basic information about SQL-condition, such as:
+  ///   - SQL error code;
+  ///   - error level;
+  ///   - SQLSTATE;
+  ///   - text message.
+  ///
+  /// It's used to organize runtime SQL-handler call stack.
+  ///
+  /// Standard Sql_condition class can not be used, because we don't always have
+  /// an Sql_condition object for an SQL-condition in Diagnostics_area.
+  ///
+  /// Eventually, this class should be moved to sql_error.h, and be a part of
+  /// standard SQL-condition processing (Diagnostics_area should contain an
+  /// object for active SQL-condition, not just information stored in DA's
+  /// fields).
+  class Sql_condition_info : public Sql_alloc
+  {
+  public:
+    /// SQL error code.
+    uint sql_errno;
+
+    /// Error level.
+    Sql_condition::enum_warning_level level;
+
+    /// SQLSTATE.
+    char sql_state[SQLSTATE_LENGTH + 1];
+
+    /// Text message.
+    char *message;
+
+    /// The constructor.
+    ///
+    /// @param _sql_condition  The SQL condition.
+    /// @param arena           Query arena for SP
+    Sql_condition_info(const Sql_condition *_sql_condition,
+                       Query_arena *arena)
+      :sql_errno(_sql_condition->get_sql_errno()),
+       level(_sql_condition->get_level())
+    {
+      memcpy(sql_state, _sql_condition->get_sqlstate(), SQLSTATE_LENGTH);
+      sql_state[SQLSTATE_LENGTH]= '\0';
+
+      message= strdup_root(arena->mem_root, _sql_condition->get_message_text());
+    }
+  };
 
-  bool
-  activate_handler(THD *thd,
-                   uint *ip,
-                   sp_instr *instr,
-                   Query_arena *execute_arena,
-                   Query_arena *backup_arena);
+private:
+  /// This class represents a call frame of SQL-handler (one invocation of a
+  /// handler). Basically, it's needed to store continue instruction pointer for
+  /// CONTINUE SQL-handlers.
+  class Handler_call_frame : public Sql_alloc
+  {
+  public:
+    /// SQL-condition, triggered handler activation.
+    const Sql_condition_info *sql_condition;
+
+    /// Continue-instruction-pointer for CONTINUE-handlers.
+    /// The attribute contains 0 for EXIT-handlers.
+    uint continue_ip;
+
+    /// The constructor.
+    ///
+    /// @param _sql_condition SQL-condition, triggered handler activation.
+    /// @param _continue_ip   Continue instruction pointer.
+    Handler_call_frame(const Sql_condition_info *_sql_condition,
+                       uint _continue_ip)
+     :sql_condition(_sql_condition),
+      continue_ip(_continue_ip)
+    { }
+ };
 
+public:
+  /// Arena used to (re) allocate items on. E.g. reallocate INOUT/OUT
+  /// SP-variables when they don't fit into prealloced items. This is common
+  /// situation with String items. It is used mainly in sp_eval_func_item().
+  Query_arena *callers_arena;
 
-  void
-  exit_handler();
+  /// Flag to end an open result set before start executing an SQL-handler
+  /// (if one is found). Otherwise the client will hang due to a violation
+  /// of the client/server protocol.
+  bool end_partial_result_set;
 
-  void
-  push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
+#ifndef DBUG_OFF
+  /// The stored program for which this runtime context is created. Used for
+  /// checking if correct runtime context is used for variable handling.
+  sp_head *sp;
+#endif
 
-  void
-  pop_cursors(uint count);
+  /////////////////////////////////////////////////////////////////////////
+  // SP-variables.
+  /////////////////////////////////////////////////////////////////////////
+
+  int set_variable(THD *thd, uint var_idx, Item **value)
+  { return set_variable(thd, m_var_table->field[var_idx], value); }
+
+  Item *get_item(uint var_idx) const
+  { return m_var_items[var_idx]; }
+
+  Item **get_item_addr(uint var_idx) const
+  { return m_var_items.array() + var_idx; }
+
+  bool set_return_value(THD *thd, Item **return_value_item);
+
+  bool is_return_value_set() const
+  { return m_return_value_set; }
+
+  /////////////////////////////////////////////////////////////////////////
+  // SQL-handlers.
+  /////////////////////////////////////////////////////////////////////////
+
+  /// Create a new sp_handler_entry instance and push it to the handler call
+  /// stack.
+  ///
+  /// @param handler  SQL-handler object.
+  /// @param first_ip First instruction pointer of the handler.
+  ///
+  /// @return error flag.
+  /// @retval false on success.
+  /// @retval true on error.
+  bool push_handler(sp_handler *handler, uint first_ip);
+
+  /// Pop and delete given number of sp_handler_entry instances from the handler
+  /// call stack.
+  ///
+  /// @param count Number of handler entries to pop & delete.
+  void pop_handlers(int count);
 
-  inline void
-  pop_all_cursors()
+  const Sql_condition_info *raised_condition() const
   {
-    pop_cursors(m_ccount);
+    return m_handler_call_stack.elements() ?
+      (*m_handler_call_stack.back())->sql_condition : NULL;
   }
 
-  inline sp_cursor *
-  get_cursor(uint i)
-  {
-    return m_cstack[i];
-  }
+  /// Handle current SQL condition (if any).
+  ///
+  /// This is the public-interface function to handle SQL conditions in
+  /// stored routines.
+  ///
+  /// @param thd            Thread handle.
+  /// @param ip[out]        Instruction pointer to the first handler
+  ///                       instruction.
+  /// @param cur_spi        Current SP instruction.
+  ///
+  /// @retval true if an SQL-handler has been activated. That means, all of
+  /// the following conditions are satisfied:
+  ///   - the SP-instruction raised SQL-condition(s),
+  ///   - and there is an SQL-handler to process at least one of those
+  ///     SQL-conditions,
+  ///   - and that SQL-handler has been activated.
+  /// Note, that the return value has nothing to do with "error flag"
+  /// semantics.
+  ///
+  /// @retval false otherwise.
+  bool handle_sql_condition(THD *thd,
+                            uint *ip,
+                            const sp_instr *cur_spi);
+
+  /// Remove latest call frame from the handler call stack.
+  ///
+  /// @param da Diagnostics area containing handled conditions.
+  ///
+  /// @return continue instruction pointer of the removed handler.
+  uint exit_handler(Diagnostics_area *da);
+
+  /////////////////////////////////////////////////////////////////////////
+  // Cursors.
+  /////////////////////////////////////////////////////////////////////////
+
+  /// Create a new sp_cursor instance and push it to the cursor stack.
+  ///
+  /// @param lex_keeper SP-instruction execution helper.
+  /// @param i          Cursor-push instruction.
+  ///
+  /// @return error flag.
+  /// @retval false on success.
+  /// @retval true on error.
+  bool push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
+
+  /// Pop and delete given number of sp_cursor instance from the cursor stack.
+  ///
+  /// @param count Number of cursors to pop & delete.
+  void pop_cursors(uint count);
+
+  void pop_all_cursors()
+  { pop_cursors(m_ccount); }
+
+  sp_cursor *get_cursor(uint i) const
+  { return m_cstack[i]; }
+
+  /////////////////////////////////////////////////////////////////////////
+  // CASE expressions.
+  /////////////////////////////////////////////////////////////////////////
+
+  /// Set CASE expression to the specified value.
+  ///
+  /// @param thd             Thread handler.
+  /// @param case_expr_id    The CASE expression identifier.
+  /// @param case_expr_item  The CASE expression value
+  ///
+  /// @return error flag.
+  /// @retval false on success.
+  /// @retval true on error.
+  ///
+  /// @note The idea is to reuse Item_cache for the expression of the one
+  /// CASE statement. This optimization takes place when there is CASE
+  /// statement inside of a loop. So, in other words, we will use the same
+  /// object on each iteration instead of creating a new one for each
+  /// iteration.
+  ///
+  /// TODO
+  ///   Hypothetically, a type of CASE expression can be different for each
+  ///   iteration. For instance, this can happen if the expression contains
+  ///   a session variable (something like @@VAR) and its type is changed
+  ///   from one iteration to another.
+  ///
+  ///   In order to cope with this problem, we check type each time, when we
+  ///   use already created object. If the type does not match, we re-create
+  ///   Item.  This also can (should?) be optimized.
+  bool set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr);
+
+  Item *get_case_expr(int case_expr_id) const
+  { return m_case_expr_holders[case_expr_id]; }
 
-  /*
-    CASE expressions support.
-  */
+  Item ** get_case_expr_addr(int case_expr_id) const
+  { return (Item**) m_case_expr_holders.array() + case_expr_id; }
 
-  int
-  set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr);
+private:
+  /// Internal function to allocate memory for arrays.
+  ///
+  /// @param thd Thread handle.
+  ///
+  /// @return error flag: false on success, true in case of failure.
+  bool alloc_arrays(THD *thd);
+
+  /// Create and initialize a table to store SP-variables.
+  ///
+  /// param thd Thread handle.
+  ///
+  /// @return error flag.
+  /// @retval false on success.
+  /// @retval true on error.
+  bool init_var_table(THD *thd);
 
-  Item *
-  get_case_expr(int case_expr_id);
+  /// Create and initialize an Item-adapter (Item_field) for each SP-var field.
+  ///
+  /// param thd Thread handle.
+  ///
+  /// @return error flag.
+  /// @retval false on success.
+  /// @retval true on error.
+  bool init_var_items(THD *thd);
+
+  /// Create an instance of appropriate Item_cache class depending on the
+  /// specified type in the callers arena.
+  ///
+  /// @note We should create cache items in the callers arena, as they are
+  /// used between in several instructions.
+  ///
+  /// @param thd   Thread handler.
+  /// @param item  Item to get the expression type.
+  ///
+  /// @return Pointer to valid object on success, or NULL in case of error.
+  Item_cache *create_case_expr_holder(THD *thd, const Item *item) const;
 
-  Item **
-  get_case_expr_addr(int case_expr_id);
+  int set_variable(THD *thd, Field *field, Item **value);
 
 private:
-  sp_pcontext *m_root_parsing_ctx;
+  /// Top-level (root) parsing context for this runtime context.
+  const sp_pcontext *m_root_parsing_ctx;
 
-  /* Virtual table for storing variables. */
+  /// Virtual table for storing SP-variables.
   TABLE *m_var_table;
 
-  /*
-    Collection of Item_field proxies, each of them points to the corresponding
-    field in m_var_table.
-  */
-  Item **m_var_items;
-
-  /*
-    This is a pointer to a field, which should contain return value for stored
-    functions (only). For stored procedures, this pointer is NULL.
-  */
+  /// Collection of Item_field proxies, each of them points to the
+  /// corresponding field in m_var_table.
+  Bounds_checked_array<Item *> m_var_items;
+
+  /// This is a pointer to a field, which should contain return value for
+  /// stored functions (only). For stored procedures, this pointer is NULL.
   Field *m_return_value_fld;
 
-  /*
-    Indicates whether the return value (in m_return_value_fld) has been set
-    during execution.
-  */
+  /// Indicates whether the return value (in m_return_value_fld) has been
+  /// set during execution.
   bool m_return_value_set;
 
-  /**
-    TRUE if the context is created for a sub-statement.
-  */
-  bool in_sub_stmt;
-
-  sp_handler *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
-  /** Active handler stack. */
-  sp_active_handler *m_in_handler;
-  uint m_ihsp;                  // Stack pointer for m_in_handler
-  int m_hfound;                 // Set by find_handler; -1 if not found
+  /// Flag to tell if the runtime context is created for a sub-statement.
+  bool m_in_sub_stmt;
 
-  sp_cursor **m_cstack;
-  uint m_ccount;
+  /// Stack of visible handlers.
+  Dynamic_array<sp_handler_entry *> m_handlers;
 
-  Item_cache **m_case_expr_holders;
+  /// Stack of caught SQL conditions.
+  Dynamic_array<Handler_call_frame *> m_handler_call_stack;
 
-  /* Previous runtime context (NULL if none) */
-  sp_rcontext *m_prev_runtime_ctx;
-
-private:
-  bool init_var_table(THD *thd);
-  bool init_var_items();
+  /// Stack of cursors.
+  Bounds_checked_array<sp_cursor *> m_cstack;
 
-  Item_cache *create_case_expr_holder(THD *thd, const Item *item);
+  /// Current number of cursors in m_cstack.
+  uint m_ccount;
 
-  int set_variable(THD *thd, Field *field, Item **value);
+  /// Array of CASE expression holders.
+  Bounds_checked_array<Item_cache *> m_case_expr_holders;
 }; // class sp_rcontext : public Sql_alloc
 
+///////////////////////////////////////////////////////////////////////////
+// sp_cursor declaration.
+///////////////////////////////////////////////////////////////////////////
 
-/*
-  An interceptor of cursor result set used to implement
-  FETCH <cname> INTO <varlist>.
-*/
-
-class Select_fetch_into_spvars: public select_result_interceptor
-{
-  List<sp_variable> *spvar_list;
-  uint field_count;
-public:
-  Select_fetch_into_spvars() {}               /* Remove gcc warning */
-  uint get_field_count() { return field_count; }
-  void set_spvar_list(List<sp_variable> *vars) { spvar_list= vars; }
-
-  virtual bool send_eof() { return FALSE; }
-  virtual bool send_data(List<Item> &items);
-  virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
-};
-
+class Server_side_cursor;
+typedef class st_select_lex_unit SELECT_LEX_UNIT;
 
 /* A mediator between stored procedures and server side cursors */
 
 class sp_cursor : public Sql_alloc
 {
-public:
+private:
+  /// An interceptor of cursor result set used to implement
+  /// FETCH <cname> INTO <varlist>.
+  class Select_fetch_into_spvars: public select_result_interceptor
+  {
+    List<sp_variable> *spvar_list;
+    uint field_count;
+  public:
+    Select_fetch_into_spvars() {}               /* Remove gcc warning */
+    uint get_field_count() { return field_count; }
+    void set_spvar_list(List<sp_variable> *vars) { spvar_list= vars; }
+
+    virtual bool send_eof() { return FALSE; }
+    virtual bool send_data(List<Item> &items);
+    virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
+};
 
+public:
   sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
 
   virtual ~sp_cursor()
-  {
-    destroy();
-  }
+  { destroy(); }
 
-  sp_lex_keeper *
-  get_lex_keeper() { return m_lex_keeper; }
+  sp_lex_keeper *get_lex_keeper() { return m_lex_keeper; }
 
-  int
-  open(THD *thd);
+  int open(THD *thd);
 
-  int
-  close(THD *thd);
+  int close(THD *thd);
 
-  inline my_bool
-  is_open()
-  {
-    return test(server_side_cursor);
-  }
+  my_bool is_open()
+  { return test(server_side_cursor); }
 
-  int
-  fetch(THD *, List<sp_variable> *vars);
+  int fetch(THD *, List<sp_variable> *vars);
 
-  inline sp_instr_cpush *
-  get_instr()
-  {
-    return m_i;
-  }
+  sp_instr_cpush *get_instr()
+  { return m_i; }
 
 private:
-
   Select_fetch_into_spvars result;
   sp_lex_keeper *m_lex_keeper;
   Server_side_cursor *server_side_cursor;
   sp_instr_cpush *m_i;		// My push instruction
-  void
-  destroy();
+  void destroy();
 
 }; // class sp_cursor : public Sql_alloc
 

=== modified file 'sql/sql_array.h'
--- a/sql/sql_array.h	2011-07-19 15:11:15 +0000
+++ b/sql/sql_array.h	2011-08-25 13:51:44 +0000
@@ -40,6 +40,12 @@ public:
   {}
 
   void reset() { m_array= NULL; m_size= 0; }
+ 
+  void reset(Element_type *array, size_t size)
+  {
+    m_array= array;
+    m_size= size;
+  }
 
   Element_type &operator[](size_t n)
   {
@@ -111,6 +117,13 @@ public:
     return (Elem*)array.buffer;
   }
 
+  /// @returns pointer to first element; undefined behaviour if array is empty
+  const Elem *front() const
+  {
+    DBUG_ASSERT(array.elements >= 1);
+    return (const Elem*)array.buffer;
+  }
+
   /// @returns pointer to last element; undefined behaviour if array is empty.
   Elem *back()
   {
@@ -118,6 +131,13 @@ public:
     return ((Elem*)array.buffer) + (array.elements - 1);
   }
 
+  /// @returns pointer to last element; undefined behaviour if array is empty.
+  const Elem *back() const
+  {
+    DBUG_ASSERT(array.elements >= 1);
+    return ((const Elem*)array.buffer) + (array.elements - 1);
+  }
+
   /**
      @retval false ok
      @retval true  OOM, @c my_error() has been called.
@@ -128,9 +148,9 @@ public:
   }
 
   /// Pops the last element. Does nothing if array is empty.
-  void pop()
+  Elem& pop()
   {
-    (void)pop_dynamic(&array);
+    return *((Elem*)pop_dynamic(&array));
   }
 
   void del(uint idx)

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2011-10-06 11:06:34 +0000
+++ b/sql/sql_class.cc	2011-10-13 12:51:13 +0000
@@ -67,6 +67,8 @@
 char internal_table_name[2]= "*";
 char empty_c_string[1]= {0};    /* used for not defined db */
 
+LEX_STRING EMPTY_STR= { (char *) "", 0 };
+
 const char * const THD::DEFAULT_WHERE= "field list";
 
 /****************************************************************************

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2011-09-27 08:24:44 +0000
+++ b/sql/sql_class.h	2011-10-13 12:51:13 +0000
@@ -125,6 +125,7 @@ enum enum_filetype { FILETYPE_CSV, FILET
 
 extern char internal_table_name[2];
 extern char empty_c_string[1];
+extern LEX_STRING EMPTY_STR;
 extern MYSQL_PLUGIN_IMPORT const char **errmesg;
 
 extern bool volatile shutdown_in_progress;
@@ -3142,6 +3143,7 @@ public:
   */
   void push_internal_handler(Internal_error_handler *handler);
 
+private:
   /**
     Handle a sql condition.
     @param sql_errno the condition error number
@@ -3151,12 +3153,13 @@ public:
     @param[out] cond_hdl the sql condition raised, if any
     @return true if the condition is handled
   */
-  virtual bool handle_condition(uint sql_errno,
+  bool handle_condition(uint sql_errno,
                                 const char* sqlstate,
                                 Sql_condition::enum_warning_level level,
                                 const char* msg,
                                 Sql_condition ** cond_hdl);
 
+public:
   /**
     Remove the error handler last pushed.
   */

=== modified file 'sql/sql_error.cc'
--- a/sql/sql_error.cc	2011-10-13 12:33:08 +0000
+++ b/sql/sql_error.cc	2011-10-13 12:51:13 +0000
@@ -605,6 +605,7 @@ void Warning_info::clear(ulonglong new_i
 {
   id(new_id);
   m_warn_list.empty();
+  m_marked_sql_conditions.empty();
   free_root(&m_warn_root, MYF(0));
   memset(m_warn_count, 0, sizeof(m_warn_count));
   m_current_statement_warn_count= 0;
@@ -619,16 +620,16 @@ void Warning_info::append_warning_info(T
   Diagnostics_area::Sql_condition_iterator it(source->m_warn_list);
   const Sql_condition *src_error_condition = source->get_error_condition();
 
-  /*
-    Don't use ::push_warning() to avoid invocation of condition
-    handlers or escalation of warnings to errors.
-  */
   while ((err= it++))
   {
+    // Do not use ::push_warning() to avoid invocation of THD-internal-handlers.
     Sql_condition *new_error= Warning_info::push_warning(thd, err);
 
     if (src_error_condition && src_error_condition == err)
       set_error_condition(new_error);
+
+    if (source->is_marked_for_removal(err))
+      mark_condition_for_removal(new_error);
   }
 }
 
@@ -646,47 +647,66 @@ void Diagnostics_area::copy_non_errors_f
                                                const Warning_info *src_wi)
 {
   Sql_condition_iterator it(src_wi->m_warn_list);
-  const Sql_condition *err;
+  const Sql_condition *cond;
+  Warning_info *wi= get_warning_info();
 
-  while ((err= it++))
+  while ((cond= it++))
   {
-    if (err->get_level() != Sql_condition::WARN_LEVEL_ERROR)
-      push_warning(thd, err);
+    if (cond->get_level() == Sql_condition::WARN_LEVEL_ERROR)
+      continue;
+
+    Sql_condition *new_condition= wi->push_warning(thd, cond);
+
+    if (src_wi->is_marked_for_removal(cond))
+      wi->mark_condition_for_removal(new_condition);
   }
 }
 
 
-void Warning_info::remove_sql_condition(const Sql_condition *sql_condition)
+void Warning_info::mark_sql_conditions_for_removal()
 {
-  if (!sql_condition)
-    return;
-
   Sql_condition_list::Iterator it(m_warn_list);
-  Sql_condition *err;
-  bool found = false;
+  Sql_condition *cond;
 
-  while ((err= it++))
+  while ((cond= it++))
+    mark_condition_for_removal(cond);
+}
+
+
+void Warning_info::remove_marked_sql_conditions()
+{
+  List_iterator_fast<Sql_condition> it(m_marked_sql_conditions);
+  Sql_condition *cond;
+
+  while ((cond= it++))
   {
-    if (err == sql_condition)
-    {
-      m_warn_list.remove(err);
-      found= true;
-      break;
-    }
+    m_warn_list.remove(cond);
+    m_warn_count[cond->get_level()]--;
+    m_current_statement_warn_count--;
+    if (cond == m_error_condition)
+      m_error_condition= NULL;
   }
 
-  if (!found)
-    return;
+  m_marked_sql_conditions.empty();
+}
+
 
-  m_warn_count[sql_condition->get_level()]--;
-  m_current_statement_warn_count--;
+bool Warning_info::is_marked_for_removal(const Sql_condition *cond) const
+{
+  List_iterator_fast<Sql_condition> it(
+    const_cast<List<Sql_condition>&> (m_marked_sql_conditions));
+  Sql_condition *c;
 
-  if (sql_condition == m_error_condition)
-    m_error_condition= NULL;
+  while ((c= it++))
+  {
+    if (c == cond)
+      return true;
+  }
 
-  return;
+  return false;
 }
 
+
 void Warning_info::reserve_space(THD *thd, uint count)
 {
   while ((m_warn_list.elements() + count) > thd->variables.max_error_count)
@@ -1019,3 +1039,33 @@ uint32 convert_error_message(char *to, u
   *errors= error_count;
   return (uint32) (to - to_start);
 }
+
+
+/**
+  Sanity check for SQLSTATEs. The function does not check if it's really an
+  existing SQL-state (there are just too many), it just checks string length and
+  looks for bad characters.
+
+  @param sqlstate the condition SQLSTATE.
+
+  @retval true if it's ok.
+  @retval false if it's bad.
+*/
+
+bool
+is_sqlstate_valid(const LEX_STRING *sqlstate)
+{
+  if (sqlstate->length != 5)
+    return false;
+
+  for (int i= 0 ; i < 5 ; ++i)
+  {
+    char c = sqlstate->str[i];
+
+    if ((c < '0' || '9' < c) &&
+	(c < 'A' || 'Z' < c))
+      return false;
+  }
+
+  return true;
+}

=== modified file 'sql/sql_error.h'
--- a/sql/sql_error.h	2011-08-17 13:16:26 +0000
+++ b/sql/sql_error.h	2011-10-13 12:51:13 +0000
@@ -283,6 +283,8 @@ class Warning_info
   Warning_info *m_next_in_da;
   Warning_info **m_prev_in_da;
 
+  List<Sql_condition> m_marked_sql_conditions;
+
 public:
   Warning_info(ulonglong warn_id_arg, bool allow_unlimited_warnings);
   ~Warning_info();
@@ -349,11 +351,42 @@ private:
   { m_current_statement_warn_count= 0; }
 
   /**
-    Remove given SQL-condition from the list.
+    Mark active SQL-conditions for later removal.
+    This is done to simulate stacked DAs for HANDLER statements.
+  */
+  void mark_sql_conditions_for_removal();
+
+  /**
+    Unmark SQL-conditions, which were marked for later removal.
+    This is done to simulate stacked DAs for HANDLER statements.
+  */
+  void unmark_sql_conditions_from_removal()
+  { m_marked_sql_conditions.empty(); }
+
+  /**
+    Remove SQL-conditions that are marked for deletion.
+    This is done to simulate stacked DAs for HANDLER statements.
+  */
+  void remove_marked_sql_conditions();
+
+  /**
+    Check if the given SQL-condition is marked for removal in this Warning_info
+    instance.
+
+    @param cond the SQL-condition.
 
-    @param sql_condition The SQL-condition to remove (may be NULL).
+    @retval true if the given SQL-condition is marked for removal in this
+                 Warning_info instance.
+    @retval false otherwise.
   */
-  void remove_sql_condition(const Sql_condition *sql_condition);
+  bool is_marked_for_removal(const Sql_condition *cond) const;
+
+  /**
+    Mark a single SQL-condition for removal (add the given SQL-condition to the
+    removal list of this Warning_info instance).
+  */
+  void mark_condition_for_removal(Sql_condition *cond)
+  { m_marked_sql_conditions.push_back(cond, &m_warn_root); }
 
   /**
     Used for @@warning_count system variable, which prints
@@ -488,6 +521,7 @@ private:
 
   // for:
   //   - m_next_in_da / m_prev_in_da
+  //   - is_marked_for_removal()
   friend class Diagnostics_area;
 };
 
@@ -709,8 +743,14 @@ public:
                                             sql_errno, sqlstate, level, msg);
   }
 
-  void remove_sql_condition(const Sql_condition *sql_condition)
-  { get_warning_info()->remove_sql_condition(sql_condition); }
+  void mark_sql_conditions_for_removal()
+  { get_warning_info()->mark_sql_conditions_for_removal(); }
+
+  void unmark_sql_conditions_from_removal()
+  { get_warning_info()->unmark_sql_conditions_from_removal(); }
+
+  void remove_marked_sql_conditions()
+  { get_warning_info()->remove_marked_sql_conditions(); }
 
   const Sql_condition *get_error_condition() const
   { return get_warning_info()->get_error_condition(); }
@@ -799,4 +839,59 @@ uint32 convert_error_message(char *to, u
 
 extern const LEX_STRING warning_level_names[];
 
+bool is_sqlstate_valid(const LEX_STRING *sqlstate);
+
+
+/**
+  Checks if the specified SQL-state-string defines COMPLETION condition.
+  This function assumes that the given string contains a valid SQL-state.
+
+  @param s the condition SQLSTATE.
+
+  @retval true if the given string defines COMPLETION condition.
+  @retval false otherwise.
+*/
+inline bool is_sqlstate_completion(const char *s)
+{ return s[0] == '0' && s[1] == '0'; }
+
+
+/**
+  Checks if the specified SQL-state-string defines WARNING condition.
+  This function assumes that the given string contains a valid SQL-state.
+
+  @param s the condition SQLSTATE.
+
+  @retval true if the given string defines WARNING condition.
+  @retval false otherwise.
+*/
+inline bool is_sqlstate_warning(const char *s)
+{ return s[0] == '0' && s[1] == '1'; }
+
+
+/**
+  Checks if the specified SQL-state-string defines NOT FOUND condition.
+  This function assumes that the given string contains a valid SQL-state.
+
+  @param s the condition SQLSTATE.
+
+  @retval true if the given string defines NOT FOUND condition.
+  @retval false otherwise.
+*/
+inline bool is_sqlstate_not_found(const char *s)
+{ return s[0] == '0' && s[1] == '2'; }
+
+
+/**
+  Checks if the specified SQL-state-string defines EXCEPTION condition.
+  This function assumes that the given string contains a valid SQL-state.
+
+  @param s the condition SQLSTATE.
+
+  @retval true if the given string defines EXCEPTION condition.
+  @retval false otherwise.
+*/
+inline bool is_sqlstate_exception(const char *s)
+{ return s[0] != '0' || s[1] > '2'; }
+
+
 #endif // SQL_ERROR_H

=== modified file 'sql/sql_signal.cc'
--- a/sql/sql_signal.cc	2011-08-02 08:34:30 +0000
+++ b/sql/sql_signal.cc	2011-09-20 12:13:07 +0000
@@ -114,8 +114,8 @@ void Sql_cmd_common_signal::eval_default
     /*
       SIGNAL is restricted in sql_yacc.yy to only signal SQLSTATE conditions.
     */
-    DBUG_ASSERT(m_cond->type == sp_condition_value::state);
-    sqlstate= m_cond->sqlstate;
+    DBUG_ASSERT(m_cond->type == sp_condition_value::SQLSTATE);
+    sqlstate= m_cond->sql_state;
     cond->set_sqlstate(sqlstate);
   }
   else
@@ -490,7 +490,7 @@ bool Sql_cmd_signal::execute(THD *thd)
 bool Sql_cmd_resignal::execute(THD *thd)
 {
   Diagnostics_area *da= thd->get_stmt_da();
-  Sql_condition *signaled;
+  const sp_rcontext::Sql_condition_info *signaled;
 
   DBUG_ENTER("Sql_cmd_resignal::execute");
 
@@ -504,18 +504,34 @@ bool Sql_cmd_resignal::execute(THD *thd)
     DBUG_RETURN(true);
   }
 
+  Sql_condition signaled_err(thd->mem_root);
+  signaled_err.set(signaled->sql_errno,
+                   signaled->sql_state,
+                   signaled->level,
+                   signaled->message);
+
+
   if (m_cond) // RESIGNAL with signal_value.
   {
     query_cache_abort(&thd->query_cache_tls);
 
-    /* Make room for 2 conditions. */
-    da->reserve_space(thd, 2);
+    /* Keep handled conditions. */
+    da->unmark_sql_conditions_from_removal();
 
-    Sql_condition *cond= da->push_warning(thd, signaled);
+    /* Check if the old condition still exists. */
+    if (da->has_sql_condition(signaled->message, strlen(signaled->message)))
+    {
+      /* Make room for the new RESIGNAL condition. */
+      da->reserve_space(thd, 1);
+    }
+    else
+    {
+      /* Make room for old condition + the new RESIGNAL condition. */
+      da->reserve_space(thd, 2);
 
-    if (cond)
-      cond->copy_opt_attributes(signaled);
+      da->push_warning(thd, &signaled_err);
+    }
   }
 
-  DBUG_RETURN(raise_condition(thd, signaled));
+  DBUG_RETURN(raise_condition(thd, &signaled_err));
 }

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2011-10-13 12:33:08 +0000
+++ b/sql/sql_yacc.yy	2011-10-13 12:51:13 +0000
@@ -280,7 +280,7 @@ void case_stmt_action_case(LEX *lex)
     (Instruction 12 in the example)
   */
 
-  lex->spcont->push_label((char *)"", lex->sphead->instructions());
+  lex->spcont->push_label(current_thd, EMPTY_STR, lex->sphead->instructions());
 }
 
 /**
@@ -349,7 +349,7 @@ int case_stmt_action_when(LEX *lex, Item
   */
 
   return !test(i) ||
-         sp->push_backpatch(i, ctx->push_label((char *)"", 0)) ||
+         sp->push_backpatch(i, ctx->push_label(current_thd, EMPTY_STR, 0)) ||
          sp->add_cont_backpatch(i) ||
          sp->add_instr(i);
 }
@@ -473,8 +473,8 @@ set_local_variable(THD *thd, sp_variable
 
   if (val)
     it= val;
-  else if (spv->dflt)
-    it= spv->dflt;
+  else if (spv->default_value)
+    it= spv->default_value;
   else
   {
     it= new (thd->mem_root) Item_null();
@@ -565,7 +565,7 @@ create_item_for_sp_var(THD *thd, LEX_STR
 
   /* If necessary, look for the variable. */
   if (spc && !spvar)
-    spvar= spc->find_variable(&name);
+    spvar= spc->find_variable(name, false);
 
   if (!spvar)
   {
@@ -817,7 +817,7 @@ static bool add_create_index (LEX *lex,
   timestamp_type date_time_type;
   st_select_lex *select_lex;
   chooser_compare_func_creator boolfunc2creator;
-  struct sp_condition_value *spcondvalue;
+  class sp_condition_value *spcondvalue;
   struct { int vars, conds, hndlrs, curs; } spblock;
   sp_name *spname;
   LEX *lex;
@@ -2665,14 +2665,16 @@ sp_fdparam:
             LEX *lex= Lex;
             sp_pcontext *spc= lex->spcont;
 
-            if (spc->find_variable(&$1, TRUE))
+            if (spc->find_variable($1, TRUE))
             {
               my_error(ER_SP_DUP_PARAM, MYF(0), $1.str);
               MYSQL_YYABORT;
             }
-            sp_variable *spvar= spc->push_variable(&$1,
-                                                   (enum enum_field_types)$3,
-                                                   sp_variable::MODE_IN);
+
+            sp_variable *spvar= spc->add_variable(YYTHD,
+                                                  $1,
+                                                  (enum enum_field_types) $3,
+                                                  sp_variable::MODE_IN);
 
             if (lex->sphead->fill_field_definition(YYTHD, lex,
                                                    (enum enum_field_types) $3,
@@ -2702,14 +2704,15 @@ sp_pdparam:
             LEX *lex= Lex;
             sp_pcontext *spc= lex->spcont;
 
-            if (spc->find_variable(&$3, TRUE))
+            if (spc->find_variable($3, TRUE))
             {
               my_error(ER_SP_DUP_PARAM, MYF(0), $3.str);
               MYSQL_YYABORT;
             }
-            sp_variable *spvar= spc->push_variable(&$3,
-                                                   (enum enum_field_types)$4,
-                                                   (sp_variable::enum_mode)$1);
+            sp_variable *spvar= spc->add_variable(YYTHD,
+                                                  $3,
+                                                  (enum enum_field_types) $4,
+                                                  (sp_variable::enum_mode) $1);
 
             if (lex->sphead->fill_field_definition(YYTHD, lex,
                                                    (enum enum_field_types) $4,
@@ -2804,7 +2807,7 @@ sp_decl:
                 MYSQL_YYABORT;
             
               spvar->type= var_type;
-              spvar->dflt= dflt_value_item;
+              spvar->default_value= dflt_value_item;
             
               if (lex->sphead->fill_field_definition(YYTHD, lex, var_type,
                                                      &spvar->field_def))
@@ -2840,36 +2843,41 @@ sp_decl:
             LEX *lex= Lex;
             sp_pcontext *spc= lex->spcont;
 
-            if (spc->find_cond(&$2, TRUE))
+            if (spc->find_condition($2, TRUE))
             {
               my_error(ER_SP_DUP_COND, MYF(0), $2.str);
               MYSQL_YYABORT;
             }
-            if(YYTHD->lex->spcont->push_cond(&$2, $5))
+            if(spc->add_condition(YYTHD, $2, $5))
               MYSQL_YYABORT;
             $$.vars= $$.hndlrs= $$.curs= 0;
             $$.conds= 1;
           }
         | DECLARE_SYM sp_handler_type HANDLER_SYM FOR_SYM
           {
+            THD *thd= YYTHD;
             LEX *lex= Lex;
             sp_head *sp= lex->sphead;
 
-            lex->spcont= lex->spcont->push_context(sp_pcontext::HANDLER_SCOPE);
+            sp_handler *h= lex->spcont->add_handler(thd,
+                                                    (sp_handler::enum_type) $2);
+
+            lex->spcont= lex->spcont->push_context(thd,
+                                                   sp_pcontext::HANDLER_SCOPE);
 
             sp_pcontext *ctx= lex->spcont;
             sp_instr_hpush_jump *i=
-              new sp_instr_hpush_jump(sp->instructions(), ctx, $2,
-                                      ctx->current_var_count());
+              new sp_instr_hpush_jump(sp->instructions(), ctx, h);
+
             if (i == NULL || sp->add_instr(i))
               MYSQL_YYABORT;
 
             /* For continue handlers, mark end of handler scope. */
-            if ($2 == SP_HANDLER_CONTINUE &&
+            if ($2 == sp_handler::CONTINUE &&
                 sp->push_backpatch(i, ctx->last_label()))
               MYSQL_YYABORT;
 
-            if (sp->push_backpatch(i, ctx->push_label(empty_c_string, 0)))
+            if (sp->push_backpatch(i, ctx->push_label(thd, EMPTY_STR, 0)))
               MYSQL_YYABORT;
           }
           sp_hcond_list sp_proc_stmt
@@ -2880,17 +2888,16 @@ sp_decl:
             sp_label *hlab= lex->spcont->pop_label(); /* After this hdlr */
             sp_instr_hreturn *i;
 
-            if ($2 == SP_HANDLER_CONTINUE)
+            if ($2 == sp_handler::CONTINUE)
             {
-              i= new sp_instr_hreturn(sp->instructions(), ctx,
-                                      ctx->current_var_count());
+              i= new sp_instr_hreturn(sp->instructions(), ctx);
               if (i == NULL ||
                   sp->add_instr(i))
                 MYSQL_YYABORT;
             }
             else
             {  /* EXIT or UNDO handler, just jump to the end of the block */
-              i= new sp_instr_hreturn(sp->instructions(), ctx, 0);
+              i= new sp_instr_hreturn(sp->instructions(), ctx);
               if (i == NULL ||
                   sp->add_instr(i) ||
                   sp->push_backpatch(i, lex->spcont->last_label())) /* Block end */
@@ -2901,8 +2908,7 @@ sp_decl:
             lex->spcont= ctx->pop_context();
 
             $$.vars= $$.conds= $$.curs= 0;
-            $$.hndlrs= $6;
-            lex->spcont->add_handlers($6);
+            $$.hndlrs= 1;
           }
         | DECLARE_SYM ident CURSOR_SYM FOR_SYM sp_cursor_stmt
           {
@@ -2912,7 +2918,7 @@ sp_decl:
             uint offp;
             sp_instr_cpush *i;
 
-            if (ctx->find_cursor(&$2, &offp, TRUE))
+            if (ctx->find_cursor($2, &offp, TRUE))
             {
               my_error(ER_SP_DUP_CURS, MYF(0), $2.str);
               delete $5;
@@ -2922,7 +2928,7 @@ sp_decl:
                                   ctx->current_cursor_count());
             if (i == NULL ||
                 sp->add_instr(i) ||
-                ctx->push_cursor(&$2))
+                ctx->add_cursor($2))
               MYSQL_YYABORT;
             $$.vars= $$.conds= $$.hndlrs= 0;
             $$.curs= 1;
@@ -2953,8 +2959,8 @@ sp_cursor_stmt:
         ;
 
 sp_handler_type:
-          EXIT_SYM      { $$= SP_HANDLER_EXIT; }
-        | CONTINUE_SYM  { $$= SP_HANDLER_CONTINUE; }
+          EXIT_SYM      { $$= sp_handler::EXIT; }
+        | CONTINUE_SYM  { $$= sp_handler::CONTINUE; }
         /*| UNDO_SYM      { QQ No yet } */
         ;
 
@@ -2972,7 +2978,7 @@ sp_hcond_element:
             sp_head *sp= lex->sphead;
             sp_pcontext *ctx= lex->spcont->parent_context();
 
-            if (ctx->find_handler($1))
+            if (ctx->check_duplicate_handler($1))
             {
               my_message(ER_SP_DUP_HANDLER, ER(ER_SP_DUP_HANDLER), MYF(0));
               MYSQL_YYABORT;
@@ -2983,7 +2989,6 @@ sp_hcond_element:
                 (sp_instr_hpush_jump *)sp->last_instruction();
 
               i->add_condition($1);
-              ctx->push_handler($1);
             }
           }
         ;
@@ -2996,11 +3001,9 @@ sp_cond:
               my_error(ER_WRONG_VALUE, MYF(0), "CONDITION", "0");
               MYSQL_YYABORT;
             }
-            $$= (sp_condition_value *)YYTHD->alloc(sizeof(sp_condition_value));
+            $$= new (YYTHD->mem_root) sp_condition_value($1);
             if ($$ == NULL)
               MYSQL_YYABORT;
-            $$->type= sp_condition_value::number;
-            $$->mysqlerr= $1;
           }
         | sqlstate
         ;
@@ -3008,17 +3011,22 @@ sp_cond:
 sqlstate:
           SQLSTATE_SYM opt_value TEXT_STRING_literal
           { /* SQLSTATE */
-            if (!sp_cond_check(&$3))
+
+            /*
+              An error is triggered:
+                - if the specified string is not a valid SQLSTATE,
+                - or if it represents the completion condition -- it is not
+                  allowed to SIGNAL, or declare a handler for the completion
+                  condition.
+            */
+            if (!is_sqlstate_valid(&$3) || is_sqlstate_completion($3.str))
             {
               my_error(ER_SP_BAD_SQLSTATE, MYF(0), $3.str);
               MYSQL_YYABORT;
             }
-            $$= (sp_condition_value *)YYTHD->alloc(sizeof(sp_condition_value));
+            $$= new (YYTHD->mem_root) sp_condition_value($3.str);
             if ($$ == NULL)
               MYSQL_YYABORT;
-            $$->type= sp_condition_value::state;
-            memcpy($$->sqlstate, $3.str, SQLSTATE_LENGTH);
-            $$->sqlstate[SQLSTATE_LENGTH]= '\0';
           }
         ;
 
@@ -3034,7 +3042,7 @@ sp_hcond:
           }
         | ident /* CONDITION name */
           {
-            $$= Lex->spcont->find_cond(&$1);
+            $$= Lex->spcont->find_condition($1, false);
             if ($$ == NULL)
             {
               my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str);
@@ -3043,24 +3051,21 @@ sp_hcond:
           }
         | SQLWARNING_SYM /* SQLSTATEs 01??? */
           {
-            $$= (sp_condition_value *)YYTHD->alloc(sizeof(sp_condition_value));
+            $$= new (YYTHD->mem_root) sp_condition_value(sp_condition_value::WARNING);
             if ($$ == NULL)
               MYSQL_YYABORT;
-            $$->type= sp_condition_value::warning;
           }
         | not FOUND_SYM /* SQLSTATEs 02??? */
           {
-            $$= (sp_condition_value *)YYTHD->alloc(sizeof(sp_condition_value));
+            $$= new (YYTHD->mem_root) sp_condition_value(sp_condition_value::NOT_FOUND);
             if ($$ == NULL)
               MYSQL_YYABORT;
-            $$->type= sp_condition_value::notfound;
           }
         | SQLEXCEPTION_SYM /* All other SQLSTATEs */
           {
-            $$= (sp_condition_value *)YYTHD->alloc(sizeof(sp_condition_value));
+            $$= new (YYTHD->mem_root) sp_condition_value(sp_condition_value::EXCEPTION);
             if ($$ == NULL)
               MYSQL_YYABORT;
-            $$->type= sp_condition_value::exception;
           }
         ;
 
@@ -3090,13 +3095,13 @@ signal_value:
               my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str);
               MYSQL_YYABORT;
             }
-            cond= lex->spcont->find_cond(&$1);
+            cond= lex->spcont->find_condition($1, false);
             if (cond == NULL)
             {
               my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str);
               MYSQL_YYABORT;
             }
-            if (cond->type != sp_condition_value::state)
+            if (cond->type != sp_condition_value::SQLSTATE)
             {
               my_error(ER_SIGNAL_BAD_CONDITION_TYPE, MYF(0));
               MYSQL_YYABORT;
@@ -3372,12 +3377,15 @@ sp_decl_idents:
             LEX *lex= Lex;
             sp_pcontext *spc= lex->spcont;
 
-            if (spc->find_variable(&$1, TRUE))
+            if (spc->find_variable($1, TRUE))
             {
               my_error(ER_SP_DUP_VAR, MYF(0), $1.str);
               MYSQL_YYABORT;
             }
-            spc->push_variable(&$1, (enum_field_types)0, sp_variable::MODE_IN);
+            spc->add_variable(YYTHD,
+                              $1,
+                              MYSQL_TYPE_DECIMAL,
+                              sp_variable::MODE_IN);
             $$= 1;
           }
         | sp_decl_idents ',' ident
@@ -3387,12 +3395,15 @@ sp_decl_idents:
             LEX *lex= Lex;
             sp_pcontext *spc= lex->spcont;
 
-            if (spc->find_variable(&$3, TRUE))
+            if (spc->find_variable($3, TRUE))
             {
               my_error(ER_SP_DUP_VAR, MYF(0), $3.str);
               MYSQL_YYABORT;
             }
-            spc->push_variable(&$3, (enum_field_types)0, sp_variable::MODE_IN);
+            spc->add_variable(YYTHD,
+                              $3,
+                              MYSQL_TYPE_DECIMAL,
+                              sp_variable::MODE_IN);
             $$= $1 + 1;
           }
         ;
@@ -3514,7 +3525,9 @@ sp_proc_stmt_unlabeled:
           { /* Unlabeled controls get a secret label. */
             LEX *lex= Lex;
 
-            lex->spcont->push_label((char *)"", lex->sphead->instructions());
+            lex->spcont->push_label(YYTHD,
+                                    EMPTY_STR,
+                                    lex->sphead->instructions());
           }
           sp_unlabeled_control
           {
@@ -3530,7 +3543,7 @@ sp_proc_stmt_leave:
             LEX *lex= Lex;
             sp_head *sp = lex->sphead;
             sp_pcontext *ctx= lex->spcont;
-            sp_label *lab= ctx->find_label($2.str);
+            sp_label *lab= ctx->find_label($2);
 
             if (! lab)
             {
@@ -3583,7 +3596,7 @@ sp_proc_stmt_iterate:
             LEX *lex= Lex;
             sp_head *sp= lex->sphead;
             sp_pcontext *ctx= lex->spcont;
-            sp_label *lab= ctx->find_label($2.str);
+            sp_label *lab= ctx->find_label($2);
 
             if (! lab || lab->type != sp_label::ITERATION)
             {
@@ -3628,7 +3641,7 @@ sp_proc_stmt_open:
             uint offset;
             sp_instr_copen *i;
 
-            if (! lex->spcont->find_cursor(&$2, &offset))
+            if (! lex->spcont->find_cursor($2, &offset, false))
             {
               my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str);
               MYSQL_YYABORT;
@@ -3648,7 +3661,7 @@ sp_proc_stmt_fetch:
             uint offset;
             sp_instr_cfetch *i;
 
-            if (! lex->spcont->find_cursor(&$3, &offset))
+            if (! lex->spcont->find_cursor($3, &offset, false))
             {
               my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $3.str);
               MYSQL_YYABORT;
@@ -3670,7 +3683,7 @@ sp_proc_stmt_close:
             uint offset;
             sp_instr_cclose *i;
 
-            if (! lex->spcont->find_cursor(&$2, &offset))
+            if (! lex->spcont->find_cursor($2, &offset, false))
             {
               my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str);
               MYSQL_YYABORT;
@@ -3696,7 +3709,7 @@ sp_fetch_list:
             sp_pcontext *spc= lex->spcont;
             sp_variable *spv;
 
-            if (!spc || !(spv = spc->find_variable(&$1)))
+            if (!spc || !(spv = spc->find_variable($1, false)))
             {
               my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str);
               MYSQL_YYABORT;
@@ -3716,7 +3729,7 @@ sp_fetch_list:
             sp_pcontext *spc= lex->spcont;
             sp_variable *spv;
 
-            if (!spc || !(spv = spc->find_variable(&$3)))
+            if (!spc || !(spv = spc->find_variable($3, false)))
             {
               my_error(ER_SP_UNDECLARED_VAR, MYF(0), $3.str);
               MYSQL_YYABORT;
@@ -3742,7 +3755,7 @@ sp_if:
             sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx,
                                                                $2, lex);
             if (i == NULL ||
-                sp->push_backpatch(i, ctx->push_label((char *)"", 0)) ||
+                sp->push_backpatch(i, ctx->push_label(YYTHD, EMPTY_STR, 0)) ||
                 sp->add_cont_backpatch(i) ||
                 sp->add_instr(i))
               MYSQL_YYABORT;
@@ -3759,7 +3772,7 @@ sp_if:
                 sp->add_instr(i))
               MYSQL_YYABORT;
             sp->backpatch(ctx->pop_label());
-            sp->push_backpatch(i, ctx->push_label((char *)"", 0));
+            sp->push_backpatch(i, ctx->push_label(YYTHD, EMPTY_STR, 0));
           }
           sp_elseifs
           {
@@ -3901,7 +3914,7 @@ sp_labeled_control:
           {
             LEX *lex= Lex;
             sp_pcontext *ctx= lex->spcont;
-            sp_label *lab= ctx->find_label($1.str);
+            sp_label *lab= ctx->find_label($1);
 
             if (lab)
             {
@@ -3910,8 +3923,7 @@ sp_labeled_control:
             }
             else
             {
-              lab= lex->spcont->push_label($1.str,
-                                           lex->sphead->instructions());
+              lab= lex->spcont->push_label(YYTHD, $1, lex->sphead->instructions());
               lab->type= sp_label::ITERATION;
             }
           }
@@ -3922,7 +3934,7 @@ sp_labeled_control:
 
             if ($5.str)
             {
-              if (my_strcasecmp(system_charset_info, $5.str, lab->name) != 0)
+              if (my_strcasecmp(system_charset_info, $5.str, lab->name.str) != 0)
               {
                 my_error(ER_SP_LABEL_MISMATCH, MYF(0), $5.str);
                 MYSQL_YYABORT;
@@ -3942,7 +3954,7 @@ sp_labeled_block:
           {
             LEX *lex= Lex;
             sp_pcontext *ctx= lex->spcont;
-            sp_label *lab= ctx->find_label($1.str);
+            sp_label *lab= ctx->find_label($1);
 
             if (lab)
             {
@@ -3950,8 +3962,7 @@ sp_labeled_block:
               MYSQL_YYABORT;
             }
 
-            lab= lex->spcont->push_label($1.str,
-                                         lex->sphead->instructions());
+            lab= lex->spcont->push_label(YYTHD, $1, lex->sphead->instructions());
             lab->type= sp_label::BEGIN;
           }
           sp_block_content sp_opt_label
@@ -3961,7 +3972,7 @@ sp_labeled_block:
 
             if ($5.str)
             {
-              if (my_strcasecmp(system_charset_info, $5.str, lab->name) != 0)
+              if (my_strcasecmp(system_charset_info, $5.str, lab->name.str) != 0)
               {
                 my_error(ER_SP_LABEL_MISMATCH, MYF(0), $5.str);
                 MYSQL_YYABORT;
@@ -3974,7 +3985,7 @@ sp_unlabeled_block:
           { /* Unlabeled blocks get a secret label. */
             LEX *lex= Lex;
             uint ip= lex->sphead->instructions();
-            sp_label *lab= lex->spcont->push_label((char *)"", ip);
+            sp_label *lab= lex->spcont->push_label(YYTHD, EMPTY_STR, ip);
             lab->type= sp_label::BEGIN;
           }
           sp_block_content
@@ -3990,7 +4001,8 @@ sp_block_content:
               together. No [[NOT] ATOMIC] yet, and we need to figure out how
               make it coexist with the existing BEGIN COMMIT/ROLLBACK. */
             LEX *lex= Lex;
-            lex->spcont= lex->spcont->push_context(sp_pcontext::REGULAR_SCOPE);
+            lex->spcont= lex->spcont->push_context(YYTHD,
+                                                   sp_pcontext::REGULAR_SCOPE);
           }
           sp_decls
           sp_proc_stmts
@@ -10532,7 +10544,7 @@ select_var_ident:
             LEX *lex=Lex;
             sp_variable *t;
 
-            if (!lex->spcont || !(t=lex->spcont->find_variable(&$1)))
+            if (!lex->spcont || !(t=lex->spcont->find_variable($1, false)))
             {
               my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str);
               MYSQL_YYABORT;
@@ -12371,7 +12383,7 @@ simple_ident:
             LEX *lex= thd->lex;
             sp_variable *spv;
             sp_pcontext *spc = lex->spcont;
-            if (spc && (spv = spc->find_variable(&$1)))
+            if (spc && (spv = spc->find_variable($1, false)))
             {
               Lex_input_stream *lip= &thd->m_parser_state->m_lip;
 
@@ -13332,7 +13344,7 @@ sys_option_value:
             else
             {
               sp_pcontext *spc= lex->spcont;
-              sp_variable *spv= spc->find_variable(name);
+              sp_variable *spv= spc->find_variable(*name, false);
 
               if ($1)
               {
@@ -13412,7 +13424,7 @@ option_value:
 
             names.str= (char *)"names";
             names.length= 5;
-            if (spc && spc->find_variable(&names))
+            if (spc && spc->find_variable(names, false))
               my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str);
             else
               my_parse_error(ER(ER_SYNTAX_ERROR));
@@ -13451,7 +13463,7 @@ option_value:
 
             pw.str= (char *)"password";
             pw.length= 8;
-            if (spc && spc->find_variable(&pw))
+            if (spc && spc->find_variable(pw, false))
             {
               my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str);
               MYSQL_YYABORT;
@@ -13489,7 +13501,7 @@ internal_variable_name:
             sp_variable *spv;
 
             /* Best effort lookup for system variable. */
-            if (!spc || !(spv = spc->find_variable(&$1)))
+            if (!spc || !(spv = spc->find_variable($1, false)))
             {
               struct sys_var_with_base tmp= {NULL, $1};
 

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (jon.hauglid:3321 to 3322) WL#5986Jon Olav Hauglid14 Oct