List:Commits« Previous MessageNext Message »
From:Davi Arnaut Date:August 6 2008 12:40am
Subject:Re: bzr commit into mysql-6.0-wl2110-review branch (marc.alff:2675)
WL#2110
View as plain text  
Hi Marc,

Here goes some initial review comments. I guess that some bits are
missing and I need to take a more careful look at this patch. Let's
first discuss the issues that I raise here.

Marc Alff wrote:
> #At file:///home/malff/BZR-TREE/mysql-6.0-wl2110-review-part2/
> 
>  2675 Marc Alff	2008-07-22
>       WL#2110 (Stored Procedures: Implement SIGNAL)
>       
>       Formal review part 2/10: Core
>       
>       This patch contains the core implementation of the SIGNAL and RESIGNAL
>       statements.
>       In particular,
>       - SQL_condition is a new class used to represent a SQL condition
>       - SIGNAL / RESIGNAL is implemented in sql_signal.cc
>       - raising conditions (my_message_sql, push_warning),
>       and the SQL diagnostics area are changed.
> added:
>   sql/sql_signal.cc
> modified:
>   sql/derror.cc
>   sql/mysql_priv.h
>   sql/mysqld.cc
>   sql/share/errmsg.txt
>   sql/sql_class.cc
>   sql/sql_class.h
>   sql/sql_error.cc
>   sql/sql_error.h
>   sql/sql_insert.cc
> 
> === modified file 'sql/derror.cc'
> --- a/sql/derror.cc	2008-04-09 00:56:49 +0000
> +++ b/sql/derror.cc	2008-07-23 00:25:11 +0000
> @@ -121,7 +121,7 @@ Please install the latest version of thi
>    }
>    
>    /* TODO: Convert the character set to server system character set */
> -  if (!get_charset(head[30],MYF(MY_WME)))
> +  if (!(error_message_charset_info= get_charset(head[30],MYF(MY_WME))))
>    {
>      sql_print_error("Character set #%d is not supported for messagefile '%s'",
>                      (int)head[30],name);
> 
> === modified file 'sql/mysql_priv.h'
> --- a/sql/mysql_priv.h	2008-07-09 07:12:43 +0000
> +++ b/sql/mysql_priv.h	2008-07-23 00:25:11 +0000
> @@ -152,6 +152,10 @@ char* query_table_status(THD *thd,const 
>  extern CHARSET_INFO *system_charset_info, *files_charset_info ;
>  extern CHARSET_INFO *national_charset_info, *table_alias_charset;
>  
> +/**
> +  Character set of the buildin error messages loaded from errmsg.sys.
> +*/
> +extern CHARSET_INFO *error_message_charset_info;
>  
>  enum Derivation
>  {
> @@ -789,6 +793,7 @@ typedef my_bool (*qc_engine_callback)(TH
>                                        uint key_length,
>                                        ulonglong *engine_data);
>  #include "sql_string.h"
> +#include "sql_fixstring.h"
>  #include "sql_list.h"
>  #include "sql_map.h"
>  #include "my_decimal.h"
> 
> === modified file 'sql/mysqld.cc'
> --- a/sql/mysqld.cc	2008-07-09 07:12:43 +0000
> +++ b/sql/mysqld.cc	2008-07-23 00:25:11 +0000
> @@ -664,6 +664,7 @@ MY_BITMAP temp_pool;
>  CHARSET_INFO *system_charset_info, *files_charset_info ;
>  CHARSET_INFO *national_charset_info, *table_alias_charset;
>  CHARSET_INFO *character_set_filesystem;
> +CHARSET_INFO *error_message_charset_info= NULL;

No need to set to NULL.

>  
>  MY_LOCALE *my_default_lc_time_names;
>  
> @@ -1897,7 +1898,10 @@ void close_connection(THD *thd, uint err
>    if ((vio= thd->net.vio) != 0)
>    {
>      if (errcode)
> -      net_send_error(thd, errcode, ER(errcode)); /* purecov: inspected */
> +    {
> +      const char* sqlstate= mysql_errno_to_sqlstate(errcode);
> +      net_send_error(thd, errcode, ER(errcode), sqlstate); /* purecov: inspected */
> +    }
>      vio_close(vio);			/* vio is freed in delete thd */
>    }
>    if (lock)
> @@ -2947,8 +2951,6 @@ extern "C" void my_message_sql(uint erro
>  void my_message_sql(uint error, const char *str, myf MyFlags)
>  {
>    THD *thd;
> -  MYSQL_ERROR::enum_warning_level level;
> -  sql_print_message_func func;
>    DBUG_ENTER("my_message_sql");
>    DBUG_PRINT("error", ("error: %u  message: '%s'", error, str));
>    /*
> @@ -2956,106 +2958,44 @@ void my_message_sql(uint error, const ch
>      will be fixed
>      DBUG_ASSERT(error != 0);
>    */
> +
> +  /*
> +    TODO: ME_JUST_INFO and ME_JUST_WARNING are back doors used in
> +    storage/maria to print to the server log files.
> +    my_error/my_message_sql should not be used for this, since we
> +    don't want the exception handlers / SIGNAL / RESIGNAL to interfere
> +    with the error handling in this case.
> +    Instead, the server should expose a clean interface to the storage
> +    engines for printing into the server logs (sql/log.cc),
> +    and the storage engine should call that interface (see ma_message_end_user)
> +  */
> +
> +  /*
> +    Flags for printing to the logs are mutually exclusive
> +  */
> +  DBUG_ASSERT(!(MyFlags & ME_JUST_INFO) ||
> +              !(MyFlags & ME_JUST_WARNING) ||
> +              !(MyFlags & ME_NOREFRESH));
> +
> +

Please go there and remove this hideous stuff. I have a hard time
trying to understand why it was done this way since they already use
server internals, why didn't they use sql_print_information..?!

I think we can push this first.

>    if (MyFlags & ME_JUST_INFO)
>    {
> -    level= MYSQL_ERROR::WARN_LEVEL_NOTE;
> -    func= sql_print_information;
> -  }
> -  else if (MyFlags & ME_JUST_WARNING)
> -  {
> -    level= MYSQL_ERROR::WARN_LEVEL_WARN;
> -    func= sql_print_warning;
> +    sql_print_information("%s: %s", my_progname, str);
> +    DBUG_VOID_RETURN;
>    }
> -  else
> +
> +  if (MyFlags & ME_JUST_WARNING)
>    {
> -    level= MYSQL_ERROR::WARN_LEVEL_ERROR;
> -    func= sql_print_error;
> +    sql_print_warning("%s: %s", my_progname, str);
> +    DBUG_VOID_RETURN;
>    }
>  
>    if ((thd= current_thd))
>    {
> -    if (MyFlags & ME_FATALERROR)
> -      thd->is_fatal_error= 1;
> -
> -#ifdef BUG_36098_FIXED
> -    mysql_audit_general(thd,MYSQL_AUDIT_GENERAL_ERROR,error,my_time(0),
> -                        0,0,str,str ? strlen(str) : 0,
> -                        thd->query,thd->query_length,
> -                        thd->variables.character_set_client,
> -                        thd->row_count);
> -#endif
> -
> -
> -    /*
> -      TODO: There are two exceptions mechanism (THD and sp_rcontext),
> -      this could be improved by having a common stack of handlers.
> -    */
> -    if (thd->handle_error(error, str, level))
> -      DBUG_VOID_RETURN;
> -
> -    if (level == MYSQL_ERROR::WARN_LEVEL_WARN)
> -      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, error, str);
> -    if (level != MYSQL_ERROR::WARN_LEVEL_ERROR)
> -      goto to_error_log;
> -
> -    thd->is_slave_error=  1; // needed to catch query errors during replication
> -
> -    /*
> -      thd->lex->current_select == 0 if lex structure is not inited
> -      (not query command (COM_QUERY))
> -    */
> -    if (thd->lex->current_select &&
> -	thd->lex->current_select->no_error && !thd->is_fatal_error)
> -    {
> -      DBUG_PRINT("error",
> -                 ("Error converted to warning: current_select: no_error %d  "
> -                  "fatal_error: %d",
> -                  (thd->lex->current_select ?
> -                   thd->lex->current_select->no_error : 0),
> -                  (int) thd->is_fatal_error));
> -    }
> -    else
> -    {
> -      if (! thd->main_da.is_error())            // Return only first message
> -      {
> -        if (error == 0)
> -          error= ER_UNKNOWN_ERROR;
> -        if (str == NULL)
> -          str= ER(error);
> -        thd->main_da.set_error_status(thd, error, str);
> -      }
> -      query_cache_abort(&thd->query_cache_tls);
> -    }
> -    /*
> -      If a continue handler is found, the error message will be cleared
> -      by the stored procedures code.
> -    */
> -    if (!thd->is_fatal_error && thd->spcont &&
> -        ! (MyFlags & ME_NO_SP_HANDLER) &&
> -        thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
> -    {
> -      /*
> -        Do not push any warnings, a handled error must be completely
> -        silenced.
> -      */
> -      DBUG_VOID_RETURN;
> -    }
> -
> -    if (!thd->is_fatal_error && !thd->no_warnings_for_error
> &&
> -        !(MyFlags & ME_NO_WARNING_FOR_ERROR))
> -    {
> -      /*
> -        Suppress infinite recursion if there a memory allocation error
> -        inside push_warning.
> -      */
> -      thd->no_warnings_for_error= TRUE;
> -      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str);
> -      thd->no_warnings_for_error= FALSE;
> -    }
> +    thd->raise_error(error, str, MyFlags);

Good.

>    }
> -to_error_log:
> -  if (!thd || (MyFlags & ME_NOREFRESH))
> -    (*func)("%s: %s", my_progname_short, str); /* purecov: inspected */
> +  if (!thd || MyFlags & ME_NOREFRESH)
> +    sql_print_error("%s: %s", my_progname, str); /* purecov: inspected */
>    DBUG_VOID_RETURN;
>  }
>  
> @@ -3223,6 +3163,7 @@ SHOW_VAR com_status_vars[]= {
>    {"replace",              (char*) offsetof(STATUS_VAR, com_stat[(uint)
> SQLCOM_REPLACE]), SHOW_LONG_STATUS},
>    {"replace_select",       (char*) offsetof(STATUS_VAR, com_stat[(uint)
> SQLCOM_REPLACE_SELECT]), SHOW_LONG_STATUS},
>    {"reset",                (char*) offsetof(STATUS_VAR, com_stat[(uint)
> SQLCOM_RESET]), SHOW_LONG_STATUS},
> +  {"resignal",             (char*) offsetof(STATUS_VAR, com_stat[(uint)
> SQLCOM_RESIGNAL]), SHOW_LONG_STATUS},
>    {"restore",              (char*) offsetof(STATUS_VAR, com_stat[(uint)
> SQLCOM_RESTORE]), SHOW_LONG_STATUS},
>    {"revoke",               (char*) offsetof(STATUS_VAR, com_stat[(uint)
> SQLCOM_REVOKE]), SHOW_LONG_STATUS},
>    {"revoke_all",           (char*) offsetof(STATUS_VAR, com_stat[(uint)
> SQLCOM_REVOKE_ALL]), SHOW_LONG_STATUS},
> @@ -3231,6 +3172,7 @@ SHOW_VAR com_status_vars[]= {
>    {"savepoint",            (char*) offsetof(STATUS_VAR, com_stat[(uint)
> SQLCOM_SAVEPOINT]), SHOW_LONG_STATUS},
>    {"select",               (char*) offsetof(STATUS_VAR, com_stat[(uint)
> SQLCOM_SELECT]), SHOW_LONG_STATUS},
>    {"set_option",           (char*) offsetof(STATUS_VAR, com_stat[(uint)
> SQLCOM_SET_OPTION]), SHOW_LONG_STATUS},
> +  {"signal",               (char*) offsetof(STATUS_VAR, com_stat[(uint)
> SQLCOM_SIGNAL]), SHOW_LONG_STATUS},
>    {"show_authors",         (char*) offsetof(STATUS_VAR, com_stat[(uint)
> SQLCOM_SHOW_AUTHORS]), SHOW_LONG_STATUS},
>    {"show_binlog_events",   (char*) offsetof(STATUS_VAR, com_stat[(uint)
> SQLCOM_SHOW_BINLOG_EVENTS]), SHOW_LONG_STATUS},
>    {"show_binlogs",         (char*) offsetof(STATUS_VAR, com_stat[(uint)
> SQLCOM_SHOW_BINLOGS]), SHOW_LONG_STATUS},
> @@ -4932,6 +4874,8 @@ void create_thread_to_handle_connection(
>                                handle_one_connection,
>                                (void*) thd)))
>      {
> +      const char* sqlstate;
> +
>        /* purecov: begin inspected */
>        DBUG_PRINT("error",
>                   ("Can't create thread to handle request (error %d)",
> @@ -4948,7 +4892,8 @@ void create_thread_to_handle_connection(
>        /* Can't use my_error() since store_globals has not been called. */
>        my_snprintf(error_message_buff, sizeof(error_message_buff),
>                    ER(ER_CANT_CREATE_THREAD), error);
> -      net_send_error(thd, ER_CANT_CREATE_THREAD, error_message_buff);
> +      sqlstate= mysql_errno_to_sqlstate(ER_CANT_CREATE_THREAD);
> +      net_send_error(thd, ER_CANT_CREATE_THREAD, error_message_buff, sqlstate);
>        (void) pthread_mutex_lock(&LOCK_thread_count);
>        close_connection(thd,0,0);
>        delete thd;
> 
> === modified file 'sql/share/errmsg.txt'
> --- a/sql/share/errmsg.txt	2008-07-09 07:12:43 +0000
> +++ b/sql/share/errmsg.txt	2008-07-23 00:25:11 +0000
> @@ -6372,3 +6372,28 @@ ER_BACKUP_OBTAIN_NAME_LOCK_FAILED
>    eng "Restore failed to obtain the name locks on the tables."
>  ER_BACKUP_RELEASE_NAME_LOCK_FAILED
>    eng "Restore failed to release the name locks on the tables."
> +
> +ER_DUP_SIGNAL_SET 42000
> +        eng "Duplicate condition information item: %s"

I think it's better to use a more descriptive message. How about
something like: "The condition information item '%s' was specified
more than once". In any case, don't forget to add apostrophe between
the conversion specification.

The above applies for all error messages added here.

> +
> +ER_SIGNAL_WARN 01000
> +        eng "Unhandled user-defined warning"
> +
> +ER_SIGNAL_NOT_FOUND 02000
> +        eng "Unhandled user-defined not found"
> +
> +ER_SIGNAL_EXCEPTION HY000
> +        eng "Unhandled user-defined exception"
> +
> +ER_RESIGNAL_NO_HANDLER 0K000
> +        eng "RESIGNAL when handler not active"
> +
> +ER_SIGNAL_BAD_CONDITION_TYPE
> +        eng "SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE"
> +
> +WARN_COND_ITEM_TRUNCATED
> +        eng "Data truncated for condition item %s"
> +
> +ER_COND_ITEM_TOO_LONG
> +        eng "Data too long for condition item %s"
> +

> === modified file 'sql/sql_class.cc'
> --- a/sql/sql_class.cc	2008-07-14 22:06:19 +0000
> +++ b/sql/sql_class.cc	2008-07-23 00:25:11 +0000
> @@ -206,8 +206,9 @@ bool foreign_key_prefix(Key *a, Key *b)
>  bool
>  Reprepare_observer::report_error(THD *thd)
>  {
> -  my_error(ER_NEED_REPREPARE, MYF(ME_NO_WARNING_FOR_ERROR|ME_NO_SP_HANDLER));
> -
> +  /* No handler, no error in the condition area */
> +  thd->main_da.set_error_status(thd, ER_NEED_REPREPARE,
> +                                ER(ER_NEED_REPREPARE), "HY000");
>    m_invalidated= TRUE;
>  
>    return TRUE;
> @@ -370,6 +371,16 @@ char *thd_security_context(THD *thd, cha
>    return thd->strmake(str.ptr(), str.length());
>  }
>  
> +void Diagnostics_stmt_area::clear()
> +{
> +  m_number= 0;
> +  m_more= FALSE;
> +  m_rowcount= 0;
> +
> +  warn_list.empty();
> +  bzero((char*) warn_count, sizeof(warn_count));

memset

> +}
> +
>  /**
>    Clear this diagnostics area. 
>  
> @@ -385,6 +396,7 @@ Diagnostics_area::reset_diagnostics_area
>    /** Don't take chances in production */
>    m_message[0]= '\0';
>    m_sql_errno= 0;
> +  memset(m_sqlstate, 0, sizeof(m_sqlstate));
>    m_server_status= 0;
>    m_affected_rows= 0;
>    m_last_insert_id= 0;
> @@ -396,7 +408,6 @@ Diagnostics_area::reset_diagnostics_area
>    DBUG_VOID_RETURN;
>  }
>  
> -
>  /**
>    Set OK status -- ends commands that do not return a
>    result set, e.g. INSERT/UPDATE/DELETE.
> @@ -425,6 +436,12 @@ Diagnostics_area::set_ok_status(THD *thd
>    else
>      m_message[0]= '\0';
>    m_status= DA_OK;
> +
> +  if (! m_stmt_area.is_read_only())
> +  {
> +    m_stmt_area.m_number++;
> +    m_stmt_area.m_rowcount= m_affected_rows;
> +  }
>    DBUG_VOID_RETURN;
>  }
>  
> @@ -463,9 +480,18 @@ Diagnostics_area::set_eof_status(THD *th
>  */
>  
>  void
> -Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
> +Diagnostics_area::set_default_error_status(THD *thd, uint sql_errno_arg,
>                                     const char *message_arg)
>  {
> +  const char* sqlstate= mysql_errno_to_sqlstate(sql_errno_arg);
> +  set_error_status(thd, sql_errno_arg, message_arg, sqlstate);
> +}
> +
> +void
> +Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
> +                                   const char *message_arg,
> +                                   const char *sqlstate)

Hum, can we have also a inline set_error_status that retrieves the
error message using ER(sql_errno_arg)?

> +{
>    DBUG_ENTER("set_error_status");
>    /*
>      Only allowed to report error if has not yet reported a success
> @@ -483,8 +509,9 @@ Diagnostics_area::set_error_status(THD *
>  #endif
>  
>    m_sql_errno= sql_errno_arg;
> +  strncpy(m_sqlstate, sqlstate, SQLSTATE_LENGTH);
> +  m_sqlstate[SQLSTATE_LENGTH]= '\0';
>    strmake(m_message, message_arg, sizeof(m_message)-1);
> -
>    m_status= DA_ERROR;
>    DBUG_VOID_RETURN;
>  }
> @@ -528,6 +555,7 @@ THD::THD()
>     bootstrap(0),
>     derived_tables_processing(FALSE),
>     spcont(NULL),
> +   end_partial_result_set(FALSE),
>     m_lip(NULL),
>    /*
>      @todo The following is a work around for online backup and the DDL blocker.
> @@ -536,6 +564,7 @@ THD::THD()
>            when the DDL blocker is engaged.
>    */
>     DDL_exception(FALSE),
> +   m_tmp_syn(NULL),
>  #if defined(ENABLED_DEBUG_SYNC)
>     debug_sync_control(0),
>  #endif /* defined(ENABLED_DEBUG_SYNC) */
> @@ -666,12 +695,11 @@ void THD::push_internal_handler(Internal
>  }
>  
>  
> -bool THD::handle_error(uint sql_errno, const char *message,
> -                       MYSQL_ERROR::enum_warning_level level)
> +bool THD::handle_condition(const SQL_condition *cond)
>  {
>    if (m_internal_handler)
>    {
> -    return m_internal_handler->handle_error(sql_errno, message, level, this);
> +    return m_internal_handler->handle_condition(this, cond);
>    }
>  
>    return FALSE;                                 // 'FALSE', as per coding style
> @@ -684,6 +712,222 @@ void THD::pop_internal_handler()
>    m_internal_handler= NULL;
>  }
>  
> +void THD::raise_error(uint code, const char *str, myf MyFlags)
> +{
> +  SQL_condition cond(this->mem_root);
> +  cond.set(this, code, str, MYSQL_ERROR::WARN_LEVEL_ERROR, MyFlags);
> +

Drop spurious new line (you do the same in other places..)

> +  raise_condition(& cond);
> +}
> +
> +void THD::raise_error_printf(uint code, const char *format, myf MyFlags, ...)
> +{
> +  va_list args;
> +  char ebuff[ERRMSGSIZE+20];
> +
> +

Drop spurious new line.

> +  DBUG_ENTER("THD::raise_error_printf");
> +  DBUG_PRINT("my", ("nr: %d  MyFlags: %d  errno: %d  Format: %s",
> +                    code, MyFlags, errno, format));
> +
> +  va_start(args, MyFlags);
> +  (void) my_vsnprintf (ebuff, sizeof(ebuff), format, args);

Drop (void).

> +  va_end(args);
> +
> +  SQL_condition cond(this->mem_root);
> +  cond.set(this, code, ebuff, MYSQL_ERROR::WARN_LEVEL_ERROR, MyFlags);
> +

Drop spurious new line. Same applies for above.

> +  raise_condition(& cond);
> +  DBUG_VOID_RETURN;
> +}
> +
> +void THD::raise_warning(uint code, const char *msg)
> +{
> +  SQL_condition cond(this->mem_root);
> +  cond.set(this, code, msg, MYSQL_ERROR::WARN_LEVEL_WARN, MYF(0));
> +
> +  raise_condition(& cond);
> +}
> +
> +void THD::raise_warning_printf(uint code, const char *format, ...)
> +{
> +  va_list args;
> +  char    ebuff[ERRMSGSIZE+20];
> +
> +
> +  DBUG_ENTER("THD::raise_warning_printf");
> +  DBUG_PRINT("enter", ("warning: %u", code));
> +
> +  va_start(args, format);
> +  my_vsnprintf(ebuff, sizeof(ebuff), format, args);
> +  va_end(args);
> +
> +  SQL_condition cond(this->mem_root);
> +  cond.set(this, code, ebuff, MYSQL_ERROR::WARN_LEVEL_WARN, MYF(0));
> +
> +  raise_condition(& cond);
> +  DBUG_VOID_RETURN;
> +}
> +
> +void THD::raise_note(uint code, const char *msg)
> +{
> +  DBUG_ENTER("THD::raise_note");
> +  DBUG_PRINT("enter", ("code: %d, msg: %s", code, msg));
> +
> +  if (!(this->options & OPTION_SQL_NOTES))
> +    DBUG_VOID_RETURN;
> +
> +  SQL_condition cond(this->mem_root);
> +  cond.set(this, code, msg, MYSQL_ERROR::WARN_LEVEL_NOTE, MYF(0));
> +
> +  raise_condition(& cond);
> +  DBUG_VOID_RETURN;
> +}
> +
> +void THD::raise_note_printf(uint code, const char *format, ...)
> +{
> +  va_list args;
> +  char    ebuff[ERRMSGSIZE+20];
> +
> +
> +  DBUG_ENTER("THD::raise_note_printf");
> +  DBUG_PRINT("enter",("code: %u", code));
> +
> +  if (!(this->options & OPTION_SQL_NOTES))
> +    DBUG_VOID_RETURN;
> +
> +  va_start(args, format);
> +  my_vsnprintf(ebuff, sizeof(ebuff), format, args);
> +  va_end(args);
> +
> +  SQL_condition cond(this->mem_root);
> +  cond.set(this, code, ebuff, MYSQL_ERROR::WARN_LEVEL_NOTE, MYF(0));
> +
> +  raise_condition(& cond);
> +  DBUG_VOID_RETURN;
> +}
> +
> +void THD::raise_condition(const SQL_condition *cond)
> +{
> +  const char* msg= cond->get_message_text();
> +
> +  DBUG_ENTER("THD::raise_condition");
> +
> +  if (!(this->options & OPTION_SQL_NOTES) &&
> +      (cond->m_level == MYSQL_ERROR::WARN_LEVEL_NOTE))
> +    DBUG_VOID_RETURN;
> +
> +  if (query_id != warn_id && !spcont)
> +    mysql_reset_errors(this, 0);
> +
> +  switch (cond->m_level)
> +  {
> +  case MYSQL_ERROR::WARN_LEVEL_NOTE:
> +  case MYSQL_ERROR::WARN_LEVEL_WARN:
> +    got_warning= 1;
> +    break;
> +  case MYSQL_ERROR::WARN_LEVEL_ERROR:
> +    if (cond->m_flags & ME_FATALERROR)
> +      is_fatal_error= 1;
> +    break;
> +  default:
> +    DBUG_ASSERT(FALSE);
> +  }
> +
> +  if (handle_condition(cond))
> +    DBUG_VOID_RETURN;
> +
> +  if (cond->m_level == MYSQL_ERROR::WARN_LEVEL_ERROR)
> +  {
> +    is_slave_error=  1; // needed to catch query errors during replication
> +
> +    /*
> +      thd->lex->current_select == 0 if lex structure is not inited
> +      (not query command (COM_QUERY))
> +    */
> +    if (lex->current_select &&
> +        lex->current_select->no_error && !is_fatal_error)
> +    {
> +      DBUG_PRINT("error",
> +                 ("Error converted to warning: current_select: no_error %d  "
> +                  "fatal_error: %d",
> +                  (lex->current_select ?
> +                   lex->current_select->no_error : 0),
> +                  (int) is_fatal_error));

This message doesn't make much sense...

> +    }
> +    else if (! main_da.is_error())
> +      main_da.set_error_status(this, cond->m_sql_errno,
> +                               msg, cond->get_sqlstate());
> +  }
> +
> +  /*
> +    If a continue handler is found, the error message will be cleared
> +    by the stored procedures code.
> +  */
> +  if (!is_fatal_error && spcont &&
> +      spcont->handle_condition(this, cond))
> +  {
> +    /*
> +      Do not push any warnings, a handled error must be completely
> +      silenced.
> +    */
> +    DBUG_VOID_RETURN;
> +  }
> +
> +  /* Un-handled conditions */
> +
> +  raise_condition_no_handler(cond);
> +  DBUG_VOID_RETURN;
> +}
> +
> +void THD::raise_condition_no_handler(const SQL_condition *cond)
> +{
> +  DBUG_ENTER("THD::raise_condition_no_handler");
> +
> +  query_cache_abort(& query_cache_tls);
> +
> +  /* FIXME: broken special case */
> +  if (no_warnings_for_error && (cond->m_level ==
> MYSQL_ERROR::WARN_LEVEL_ERROR))
> +    DBUG_VOID_RETURN;
> +
> +#ifdef BUG_36098_FIXED
> +    mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_ERROR, error, my_time(0),
> +                        0, 0, msg, msg ? strlen(msg) : 0,
> +                        query, query_length,
> +                        variables.character_set_client,
> +                        row_count);

Hum.. this used to be before the various checks. Are you sure you
can move it?

> +#endif
> +
> +  if (! main_da.m_stmt_area.is_read_only())
> +  {
> +    MYSQL_ERROR::enum_warning_level level;
> +
> +    /* FIXME: broken special case, waiting for bug#36777 */
> +    level= (cond->m_broken_caller) ?
> +      MYSQL_ERROR::WARN_LEVEL_ERROR : cond->m_level;
> +
> +    if (main_da.m_stmt_area.warn_list.elements < variables.max_error_count)
> +    {
> +      /* We have to use warn_root, as mem_root is freed after each query */
> +      SQL_condition *stored_cond;
> +      stored_cond= SQL_condition::deep_copy(this, & warn_root, cond);

I get the impression that we should just drop warn_root. It doesn't
make much sense and complicates things. SQL_condition is the type of
object that begs for a simple slab..

> +      if (stored_cond)
> +      {
> +        stored_cond->m_level= level;
> +        main_da.m_stmt_area.warn_list.push_back(stored_cond, & warn_root);
> +        main_da.m_stmt_area.m_number++;
> +      }
> +    }
> +    else
> +      main_da.m_stmt_area.m_more= TRUE;
> +
> +    main_da.m_stmt_area.warn_count[(uint) level]++;
> +  }
> +
> +  total_warn_count++;
> +  DBUG_VOID_RETURN;
> +}
> +
>  extern "C"
>  void *thd_alloc(MYSQL_THD thd, unsigned int size)
>  {
> @@ -766,8 +1010,8 @@ void THD::init(void)
>  			TL_WRITE_LOW_PRIORITY :
>  			TL_WRITE);
>    session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
> -  warn_list.empty();
> -  bzero((char*) warn_count, sizeof(warn_count));
> +  main_da.reset_diagnostics_area();
> +  main_da.m_stmt_area.clear();
>    total_warn_count= 0;
>    update_charset();
>    reset_current_stmt_binlog_row_based();
> @@ -1566,9 +1810,8 @@ bool select_send::send_fields(List<Item>
>  void select_send::abort()
>  {
>    DBUG_ENTER("select_send::abort");
> -  if (is_result_set_started && thd->spcont &&
> -      thd->spcont->find_handler(thd, thd->main_da.sql_errno(),
> -                                MYSQL_ERROR::WARN_LEVEL_ERROR))
> +
> +  if (is_result_set_started && thd->spcont)
>    {
>      /*
>        We're executing a stored procedure, have an open result
> @@ -1580,7 +1823,7 @@ void select_send::abort()
>        otherwise the client will hang due to the violation of the
>        client/server protocol.
>      */
> -    thd->protocol->end_partial_result_set(thd);
> +    thd->end_partial_result_set= TRUE;
>    }
>    DBUG_VOID_RETURN;
>  }
> 
> === modified file 'sql/sql_class.h'
> --- a/sql/sql_class.h	2008-07-14 22:06:19 +0000
> +++ b/sql/sql_class.h	2008-07-23 00:25:11 +0000
> @@ -78,6 +78,7 @@ class Slave_log_event;
>  class sp_rcontext;
>  class sp_cache;
>  class Lex_input_stream;
> +class Tmp_syn;
>  class Rows_log_event;
>  
>  enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
> @@ -303,6 +304,119 @@ struct Query_cache_tls
>    Query_cache_tls() :first_query_block(NULL) {}
>  };
>  
> +/* SIGNAL / RESIGNAL / GET DIAGNOSTICS */
> +
> +#define FIRST_DIAG_SET_PROPERTY 0
> +#define LAST_DIAG_SET_PROPERTY 11
> +
> +#define FIRST_DIAG_PROPERTY 0
> +#define LAST_DIAG_PROPERTY 28

These defines are not necessary, use a const.

> +/**
> +  This enumeration list all the condition item names of a condition in the
> +  SQL condition area.
> +*/
> +typedef enum enum_diag_condition_item_name
> +{
> +  /*
> +    Conditions that can be set by the user (SIGNAL/RESIGNAL),
> +    and by the server implementation (THD::raise_ER_XXX).
> +  */
> +
> +  DIAG_CLASS_ORIGIN= 0,

FIRST_DIAG_SET_PROPERTY = DIAG_CLASS_ORIGIN

> +  DIAG_SUBCLASS_ORIGIN= 1,
> +  DIAG_CONSTRAINT_CATALOG= 2,
> +  DIAG_CONSTRAINT_SCHEMA= 3,
> +  DIAG_CONSTRAINT_NAME= 4,
> +  DIAG_CATALOG_NAME= 5,
> +  DIAG_SCHEMA_NAME= 6,
> +  DIAG_TABLE_NAME= 7,
> +  DIAG_COLUMN_NAME= 8,
> +  DIAG_CURSOR_NAME= 9,
> +  DIAG_MESSAGE_TEXT= 10,
> +  DIAG_MYSQL_ERRNO= 11,

LAST_DIAG_SET_PROPERTY = DIAG_MYSQL_ERRNO

> +
> +  /*
> +    Conditions that can be set only by the server implementation
> +    (THD::raise_ER_XXX).
> +  */
> +
> +  DIAG_CONDITION_IDENTIFIER= 12,
> +  DIAG_CONDITION_NUMBER= 13,
> +  DIAG_CONNECTION_NAME= 14,
> +  DIAG_MESSAGE_LENGTH= 15,
> +  DIAG_MESSAGE_OCTET_LENGTH= 16,
> +  DIAG_PARAMETER_MODE= 17,
> +  DIAG_PARAMETER_NAME= 18,
> +  DIAG_PARAMETER_ORDINAL_POSITION= 19,
> +  DIAG_RETURNED_SQLSTATE= 20,
> +  DIAG_ROUTINE_CATALOG= 21,
> +  DIAG_ROUTINE_NAME= 22,
> +  DIAG_ROUTINE_SCHEMA= 23,
> +  DIAG_SERVER_NAME= 24,
> +  DIAG_SPECIFIC_NAME= 25,
> +  DIAG_TRIGGER_CATALOG= 26,
> +  DIAG_TRIGGER_NAME= 27,
> +  DIAG_TRIGGER_SCHEMA= 28,
> +} Diag_condition_item_name;
> +
> +/**
> +  Name of each diagnostic condition item.
> +  This array is indexed by Diag_condition_item_name.
> +*/
> +extern const LEX_STRING Diag_condition_item_names[];

I couldn't find any other uses for this..

> +
> +/**
> +  Set_signal_information is a container used in the parsed tree to represent
> +  the collection of assignments to condition items in the SIGNAL and RESIGNAL
> +  statements.
> +*/
> +class Set_signal_information
> +{
> +public:
> +  /** Constructor. */
> +  Set_signal_information();
> +
> +  /** Copy constructor. */
> +  Set_signal_information(const Set_signal_information& set);
> +
> +  /** Destructor. */
> +  ~Set_signal_information()
> +  {}
> +
> +  /** Clear all items. */
> +  void clear();
> +
> +  /**
> +    For each contition item assignment, m_item[] contains the parsed tree
> +    that represents the expression assigned, if any.
> +    m_item[] is an array indexed by Diag_condition_item_name.
> +  */
> +  Item *m_item[LAST_DIAG_SET_PROPERTY+1];
> +};
> +
> +
> +/**
> +  Parser temporary internal state, used during syntax analysis.
> +*/
> +/* FIXME: Waiting for Bug#35577 to be merged, to use Yacc_state */
> +class Tmp_syn
> +{
> +public:
> +  Tmp_syn()
> +    : m_set_signal_info()
> +  {}
> +
> +  ~Tmp_syn()
> +  {}
> +
> +  /**
> +    Fragments of parsed tree,
> +    used during the parsing of SIGNAL and RESIGNAL.
> +  */
> +  Set_signal_information m_set_signal_info;
> +};
> +
>  #include "sql_lex.h"				/* Must be here */
>  
>  class Delayed_insert;
> @@ -1073,6 +1187,202 @@ enum enum_thread_type
>  
>  
>  /**
> +  Representation of a SQL condition.
> +  A SQL condition can be a completion condition (note, warning),
> +  or an exception contition (error, not found).
> +*/
> +class SQL_condition : public Sql_alloc
> +{
> +public:
> +  /**
> +    Constructor.
> +    @param mem_root The memory root to use for the condition items
> +    of this condition
> +  */
> +  SQL_condition(MEM_ROOT *mem_root);
> +
> +  /** Destructor. */
> +  ~SQL_condition()
> +  {}
> +
> +  /**
> +    Deep copy (static method).
> +    Builds a copy of a condition using a given memory root.
> +    'Deep copy' is useful to propagate SQL conditions raised from a short
> +    lived runtime environment to a parent execution environment with a longer
> +    life cycle.
> +    For example, when proc_p1() calls proc_p2(), an exception raised in
> +    proc_p2() should be copied when caught in proc_p1(),
> +    before destroying the proc_p2() memory root.
> +    @param thd the current thread.
> +    @param mem_root the memory root to use for memory allocation.
> +    @param cond the condition to copy.
> +    @return the duplicated condition.
> +  */
> +  static SQL_condition* deep_copy(THD *thd, MEM_ROOT *mem_root,
> +                                  const SQL_condition *cond);
> +
> +  /**
> +    Deep copy (instance method).
> +    @param cond the condition to copy.
> +  */
> +  void deep_copy(const SQL_condition *cond);
> +
> +
> +  /**
> +    Set this condition area with a fixed message text.
> +    @param thd the current thread.
> +    @param code the error number for this condition.
> +    @param str the message text for this condition.
> +    @param level the error level for this condition.
> +    @param MyFlags additional flags.
> +  */
> +  void set(THD *thd, uint code, const char *str,
> +           MYSQL_ERROR::enum_warning_level level, myf MyFlags);

Hum, I think it would be better to only set public
set_warning/error/note interfaces and make this one private.

> +  /**
> +    Set this condition area with formatting of the message text.
> +    @param thd the current thread.
> +    @param code the error number for this condition.
> +    @param str the message text printf format for this condition.
> +    @param level the error level for this condition.
> +    @param MyFlags additional flags.
> +  */
> +  void set_printf(THD *thd, uint code, const char *str,
> +                  MYSQL_ERROR::enum_warning_level level, myf MyFlags, ...);
> +
> +  /**
> +    Set the condition message test.
> +    @param str Message text, expressed in the character set derived from
> +    the server --language option
> +  */
> +  void set_builtin_message_text(const char* str);
> +
> +  /**
> +    Get the MESSAGE_TEXT of this condition.
> +    @return the message text.
> +  */
> +  const char* get_message_text() const;
> +
> +  /**
> +    Get the MESSAGE_OCTET_LENGTH of this condition.
> +    @return the length in bytes of the message text.
> +  */
> +  int get_message_octet_length() const;
> +
> +  /** Set the SQLSTATE of this condition. */
> +  void set_sqlstate(const char* sqlstate);
> +
> +  /**
> +    Get the SQLSTATE of this condition.
> +    @return the sql state.
> +  */
> +  const char* get_sqlstate() const
> +  { return m_returned_sqlstate; }
> +
> +public:
> +  /** SQL CLASS_ORIGIN condition item. */
> +  UTF8String64 m_class_origin;
> +
> +  /** SQL SUBCLASS_ORIGIN condition item. */
> +  UTF8String64 m_subclass_origin;
> +
> +  /** SQL CONSTRAINT_CATALOG condition item. */
> +  UTF8String64 m_constraint_catalog;
> +
> +  /** SQL CONSTRAINT_SCHEMA condition item. */
> +  UTF8String64 m_constraint_schema;
> +
> +  /** SQL CONSTRAINT_NAME condition item. */
> +  UTF8String64 m_constraint_name;
> +
> +  /** SQL CATALOG_NAME condition item. */
> +  UTF8String64 m_catalog_name;
> +
> +  /** SQL SCHEMA_NAME condition item. */
> +  UTF8String64 m_schema_name;
> +
> +  /** SQL TABLE_NAME condition item. */
> +  UTF8String64 m_table_name;
> +
> +  /** SQL COLUMN_NAME condition item. */
> +  UTF8String64 m_column_name;
> +
> +  /** SQL CURSOR_NAME condition item. */
> +  UTF8String64 m_cursor_name;

Hum.. I personally don't like this proliferation of string
parameters.  Can't we make this stuff smarter? encapsulating it in
classes and using a array. This also needlessly bloats the class and
we shouldn't keep things that aren't necessary.

Let's discuss this more in-depth on IRC.

> +private:
> +  /** Message text, expressed in the character set implied by --language. */
> +  String m_message_text;
> +
> +public:
> +  /** MySQL extension, MYSQL_ERRNO condition item. */
> +  int m_sql_errno;
> +
> +  /** SQL CONDITION_IDENTIFIER condition item. */
> +  UTF8String64 m_condition_identifier;
> +
> +  /** SQL CONNECTION_NAME condition item. */
> +  UTF8String64 m_connection_name;
> +
> +  /** SQL PARAMETER_MODE condition item. */
> +  UTF8String64 m_parameter_mode;
> +
> +  /** SQL PARAMETER_NAME condition item. */
> +  UTF8String64 m_parameter_name;
> +
> +  /** SQL PARAMETER_ORDINAL_POSITION condition item. */
> +  int m_parameter_ordinal_position;
> +
> +private:
> +  /**
> +    SQL RETURNED_SQLSTATE condition item.
> +    This member is always NUL terminated.
> +  */
> +  char m_returned_sqlstate[SQLSTATE_LENGTH+1];
> +
> +public:
> +  /** SQL ROUTINE_CATALOG condition item. */
> +  UTF8String64 m_routine_catalog;
> +
> +  /** SQL ROUTINE_NAME condition item. */
> +  UTF8String64 m_routine_name;
> +
> +  /** SQL ROUTINE_SCHEMA condition item. */
> +  UTF8String64 m_routine_schema;
> +
> +  /** SQL SERVER_NAME condition item. */
> +  UTF8String64 m_server_name;
> +
> +  /** SQL SPECIFIC_NAME condition item. */
> +  UTF8String64 m_specific_name;
> +
> +  /** SQL TRIGGER_CATALOG condition item. */
> +  UTF8String64 m_trigger_catalog;
> +
> +  /** SQL TRIGGER_NAME condition item. */
> +  UTF8String64 m_trigger_name;
> +
> +  /** SQL TRIGGER_SCHEMA condition item. */
> +  UTF8String64 m_trigger_schema;
> +
> +  /** Severity (error, warning, note) of this condition. */
> +  MYSQL_ERROR::enum_warning_level m_level;
> +
> +  /** Additional flags. */
> +  myf m_flags;
> +
> +  /** Memory root to use to hold condition item values. */
> +  MEM_ROOT *m_mem_root;
> +
> +  /*
> +    FIXME: push_warning() called with a level of ERROR:
> +    waiting for bug#36777 to be merged to remove this.
> +  */
> +  bool m_broken_caller;
> +};
> +
> +/**
>    This class represents the interface for internal error handlers.
>    Internal error handlers are exception handlers used by the server
>    implementation.
> @@ -1085,12 +1395,12 @@ protected:
>  
>  public:
>    /**
> -    Handle an error condition.
> +    Handle a sql condition.
>      This method can be implemented by a subclass to achieve any of the
>      following:
> -    - mask an error internally, prevent exposing it to the user,
> -    - mask an error and throw another one instead.
> -    When this method returns true, the error condition is considered
> +    - mask a warning/error internally, prevent exposing it to the user,
> +    - mask a warning/error and throw another one instead.
> +    When this method returns true, the sql condition is considered
>      'handled', and will not be propagated to upper layers.
>      It is the responsability of the code installing an internal handler
>      to then check for trapped conditions, and implement logic to recover
> @@ -1104,15 +1414,102 @@ public:
>      before removing it from the exception stack with
>      <code>THD::pop_internal_handler()</code>.
>  
> -    @param sql_errno the error number
> -    @param level the error level
>      @param thd the calling thread
> -    @return true if the error is handled
> +    @param cond the condition raised.
> +    @return true if the condition is handled
> +  */
> +  virtual bool handle_condition(THD *thd, const SQL_condition *cond) = 0;
> +};
> +
> +
> +/**
> +  Statement diagnostics area.
> +*/
> +class Diagnostics_stmt_area
> +{
> +public:
> +  /** Constructor. */
> +  Diagnostics_stmt_area()
> +    : m_number(0),
> +      m_more(FALSE),
> +      m_command_function_cmd(SQLCOM_END),
> +      m_dynamic_function_cmd(SQLCOM_END),
> +      m_rowcount(0),
> +      warn_list(),
> +      m_read_only(FALSE)
> +  {
> +    bzero((char*) warn_count, sizeof(warn_count));

memset

> +  }
> +
> +  /** Destructor. */
> +  ~Diagnostics_stmt_area()
> +  {}
> +
> +  /** Clear the statement area. */
> +  void clear();
> +
> +  /** 
> +    Set the read only status for this statement area.
> +    This is a priviledged operation, reserved for the implementation of
> +    diagnostics related statements, to enforce that the statement area is
> +    left untouched during execution.
> +    The diagnostics statements are:
> +    - SHOW WARNINGS
> +    - SHOW ERRORS
> +    - GET DIAGNOSTICS
> +    @param read_only the read only property to set
> +  */
> +  void set_read_only(bool read_only)
> +  { m_read_only= read_only; }
> +
> +  /**
> +    Read only status.
> +    @return the read only property
> +  */
> +  bool is_read_only() const
> +  { return m_read_only; }
> +
> +  /** SQL 'NUMBER' statement information item. */
> +  uint m_number;
> +
> +  /** SQL 'MORE' statement information item. */
> +  bool m_more;

Use?

> +
> +  /**
> +    Internal command of a statement.
> +    The following statement information items:
> +    - SQL 'COMMAND_FUNCTION'
> +    - SQL 'COMMAND_FUNCTION_CODE'
> +    derive from this attribute.
> +  */
> +  enum_sql_command m_command_function_cmd;
> +
> +  /**
> +    Internal command of a statement,
> +    for dynamic statements.
> +    The following statement information items:
> +    - SQL 'DYNAMIC_FUNCTION'
> +    - SQL 'DYNAMIC_FUNCTION_CODE'
> +    derive from this attribute.
> +  */
> +  enum_sql_command m_dynamic_function_cmd;
> +
> +  /** SQL 'ROWCOUNT' statement information item. */
> +  ha_rows m_rowcount;

I haven't been able to find a meaningful use for m_rowcount,
m_number, etc in any of the patches. Is something missing or I
missed something?

> +  /**
> +    Condition area.
> +  */
> +  List	     <SQL_condition> warn_list;
> +
> +  /**
> +    Counters for errors/warnings/notes in the condition area.
>    */
> -  virtual bool handle_error(uint sql_errno,
> -                            const char *message,
> -                            MYSQL_ERROR::enum_warning_level level,
> -                            THD *thd) = 0;
> +  uint	     warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
> +
> +private:
> +  /** Read only status. */
> +  bool m_read_only;
>  };
>  
>  
> @@ -1148,7 +1545,10 @@ public:
>                       ulonglong last_insert_id_arg,
>                       const char *message);
>    void set_eof_status(THD *thd);
> -  void set_error_status(THD *thd, uint sql_errno_arg, const char *message_arg);
> +  void set_default_error_status(THD *thd, uint sql_errno_arg,
> +                              const char *message_arg);
> +  void set_error_status(THD *thd, uint sql_errno_arg, const char *message_arg,
> +                        const char* sqlstate);
>  
>    void disable_status();
>  
> @@ -1167,6 +1567,9 @@ public:
>    uint sql_errno() const
>    { DBUG_ASSERT(m_status == DA_ERROR); return m_sql_errno; }
>  
> +  const char* get_sqlstate() const
> +  { DBUG_ASSERT(m_status == DA_ERROR); return m_sqlstate; }
> +
>    uint server_status() const
>    {
>      DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
> @@ -1196,6 +1599,8 @@ private:
>    */
>    uint m_sql_errno;
>  
> +  char m_sqlstate[SQLSTATE_LENGTH+1];
> +
>    /**
>      Copied from thd->server_status when the diagnostics area is assigned.
>      We need this member as some places in the code use the following pattern:
> @@ -1224,12 +1629,11 @@ private:
>    */
>    ulonglong   m_last_insert_id;
>    /** The total number of warnings. */
> -  uint	     m_total_warn_count;
> +  uint m_total_warn_count;
>    enum_diagnostics_status m_status;
> -  /**
> -    @todo: the following THD members belong here:
> -    - warn_list, warn_count,
> -  */
> +
> +public:
> +  Diagnostics_stmt_area m_stmt_area;
>  };
>  
>  /**
> @@ -1752,15 +2156,7 @@ public:
>    table_map  used_tables;
>    USER_CONN *user_connect;
>    CHARSET_INFO *db_charset;
> -  /*
> -    FIXME: this, and some other variables like 'count_cuted_fields'
> -    maybe should be statement/cursor local, that is, moved to Statement
> -    class. With current implementation warnings produced in each prepared
> -    statement/cursor settle here.
> -  */
> -  List	     <MYSQL_ERROR> warn_list;
> -  uint	     warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
> -  uint	     total_warn_count;
> +  uint             total_warn_count;
>    Diagnostics_area main_da;
>  #if defined(ENABLED_PROFILING)
>    PROFILING  profiling;
> @@ -1872,6 +2268,8 @@ public:
>    my_bool    tablespace_op;	/* This is TRUE in DISCARD/IMPORT TABLESPACE */
>  
>    sp_rcontext *spcont;		// SP runtime context
> +  bool       end_partial_result_set;
> +
>    sp_cache   *sp_proc_cache;
>    sp_cache   *sp_func_cache;
>  
> @@ -1934,6 +2332,12 @@ public:
>    */
>    my_bool DDL_exception; // Allow some DDL if there is an exception
>  
> +  /**
> +    Parser internal temporary state, used during syntax parsing.
> +    This member is only valid during parsing.
> +  */
> +  Tmp_syn *m_tmp_syn;
> +  
>    Locked_tables_list locked_tables_list;
>  
>  #ifdef WITH_PARTITION_STORAGE_ENGINE
> @@ -2355,19 +2759,90 @@ public:
>    void push_internal_handler(Internal_error_handler *handler);
>  
>    /**
> -    Handle an error condition.
> -    @param sql_errno the error number
> -    @param level the error level
> +    Handle a sql condition.
> +    @param cond the sql condition to handle.
>      @return true if the error is handled
>    */
> -  virtual bool handle_error(uint sql_errno, const char *message,
> -                            MYSQL_ERROR::enum_warning_level level);
> +  virtual bool handle_condition(const SQL_condition *cond);
>  
>    /**
>      Remove the error handler last pushed.
>    */
>    void pop_internal_handler();
>  
> +  /**
> +    Raise an ER_NO_SUCH_TABLE exception condition.
> +    @param db the schema name of the missing table
> +    @param table the table name of the missing table
> +  */
> +  void raise_ER_NO_SUCH_TABLE(const char* db, const char* table)
> +  {
> +    SQL_condition cond(this->mem_root);
> +    cond.set_printf(this, ER_NO_SUCH_TABLE, ER(ER_NO_SUCH_TABLE),
> +                    MYSQL_ERROR::WARN_LEVEL_ERROR, MYF(0),
> +                    db, table);
> +    cond.m_schema_name.set(db);
> +    cond.m_table_name.set(table);
> +    raise_condition(& cond);
> +  }
> +
> +  /**
> +    Raise an exception condition, with a fixed message.
> +    @param code the MYSQL_ERRNO error code of the error
> +    @param str the MESSAGE_TEXT of the error
> +    @param MyFlags additional flags
> +  */
> +  void raise_error(uint code, const char *str, myf MyFlags);
> +
> +  /**
> +    Raise an exception condition, with a formatted message.
> +    @param code the MYSQL_ERRNO error code of the error
> +    @param format the MESSAGE_TEXT printf format of the error
> +    @param MyFlags additional flags
> +  */
> +  void raise_error_printf(uint code, const char *format, myf MyFlags, ...);
> +
> +  /**
> +    Raise a completion condition (warning), with a fixed message.
> +    @param code the MYSQL_ERRNO error code of the warning
> +    @param str the MESSAGE_TEXT of the warning
> +  */
> +  void raise_warning(uint code, const char *str);
> +
> +  /**
> +    Raise a completion condition (warning), with a formatted message.
> +    @param code the MYSQL_ERRNO error code of the warning
> +    @param format the MESSAGE_TEXT printf format of the warning
> +  */
> +  void raise_warning_printf(uint code, const char *format, ...);
> +
> +  /**
> +    Raise a completion condition (note), with a fixed message.
> +    @param code the MYSQL_ERRNO error code of the note
> +    @param str the MESSAGE_TEXT of the note
> +  */
> +  void raise_note(uint code, const char *str);
> +
> +  /**
> +    Raise a completion condition (note), with a formatted message.
> +    @param code the MYSQL_ERRNO error code of the note
> +    @param format the MESSAGE_TEXT printf format of the note
> +  */
> +  void raise_note_printf(uint code, const char *format, ...);
> +
> +  /**
> +    Raise a generic SQL condition.
> +    @param cond the condition to raise
> +  */
> +  void raise_condition(const SQL_condition *cond);
> +
> +  /**
> +    Raise a generic SQL condition, without activation any SQL condition
> +    handlers.
> +    @param cond the condition to raise
> +  */
> +  void raise_condition_no_handler(const SQL_condition *cond);
> +
>  private:
>    /** The current internal error handler for this thread, or NULL. */
>    Internal_error_handler *m_internal_handler;
> 
> === modified file 'sql/sql_error.cc'
> --- a/sql/sql_error.cc	2008-02-19 12:59:19 +0000
> +++ b/sql/sql_error.cc	2008-07-23 00:25:11 +0000
> @@ -74,14 +74,17 @@ void MYSQL_ERROR::set_msg(THD *thd, cons
>  void mysql_reset_errors(THD *thd, bool force)
>  {
>    DBUG_ENTER("mysql_reset_errors");
> +
> +  if (thd->main_da.m_stmt_area.is_read_only())
> +    DBUG_VOID_RETURN;
> +

Cool.

>    if (thd->query_id != thd->warn_id || force)
>    {
>      thd->warn_id= thd->query_id;
> +    thd->main_da.m_stmt_area.clear();
>      free_root(&thd->warn_root,MYF(0));
> -    bzero((char*) thd->warn_count, sizeof(thd->warn_count));
>      if (force)
>        thd->total_warn_count= 0;
> -    thd->warn_list.empty();
>      thd->row_count= 1; // by default point to row 1
>    }
>    DBUG_VOID_RETURN;
> @@ -97,68 +100,40 @@ void mysql_reset_errors(THD *thd, bool f
>      level		Severity of warning (note, warning, error ...)
>      code		Error number
>      msg			Clear error message
> -    
> -  RETURN
> -    pointer on MYSQL_ERROR object
>  */
>  
> -MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, 
> -                          uint code, const char *msg)
> +void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
> +                  uint code, const char *msg)
>  {
> -  MYSQL_ERROR *err= 0;
>    DBUG_ENTER("push_warning");
>    DBUG_PRINT("enter", ("code: %d, msg: %s", code, msg));
>  
> -  if (level == MYSQL_ERROR::WARN_LEVEL_NOTE &&
> -      !(thd->options & OPTION_SQL_NOTES))
> -    DBUG_RETURN(0);
> -
> -  if (thd->query_id != thd->warn_id && !thd->spcont)
> -    mysql_reset_errors(thd, 0);
> -  thd->got_warning= 1;
> -
> -  /* Abort if we are using strict mode and we are not using IGNORE */
> -  if ((int) level >= (int) MYSQL_ERROR::WARN_LEVEL_WARN &&
> -      thd->really_abort_on_warning())
> +  switch(level)
>    {
> -    /* Avoid my_message() calling push_warning */
> -    bool no_warnings_for_error= thd->no_warnings_for_error;
> -    sp_rcontext *spcont= thd->spcont;
> -
> -    thd->no_warnings_for_error= 1;
> -    thd->spcont= NULL;
> -
> -    thd->killed= THD::KILL_BAD_DATA;
> -    my_message(code, msg, MYF(0));
> -
> -    thd->spcont= spcont;
> -    thd->no_warnings_for_error= no_warnings_for_error;
> -    /* Store error in error list (as my_message() didn't do it) */
> -    level= MYSQL_ERROR::WARN_LEVEL_ERROR;
> -  }
> -
> -  if (thd->handle_error(code, msg, level))
> -    DBUG_RETURN(NULL);
> -
> -  if (thd->spcont &&
> -      thd->spcont->handle_error(code, level, thd))
> +  case MYSQL_ERROR::WARN_LEVEL_NOTE:
> +    thd->raise_note(code, msg);
> +    break;
> +  case MYSQL_ERROR::WARN_LEVEL_WARN:
> +    thd->raise_warning(code, msg);
> +    break;
> +  case MYSQL_ERROR::WARN_LEVEL_ERROR:
>    {
> -    DBUG_RETURN(NULL);
> +    SQL_condition cond(thd->mem_root);
> +    cond.set(thd, code, msg, MYSQL_ERROR::WARN_LEVEL_WARN, MYF(0));
> +    /* FIXME: broken calling code */
> +    cond.m_broken_caller= TRUE;
> +    thd->raise_condition(& cond);
> +    break;
>    }
> -  query_cache_abort(&thd->query_cache_tls);
> -
>  
> -  if (thd->warn_list.elements < thd->variables.max_error_count)
> -  {
> -    /* We have to use warn_root, as mem_root is freed after each query */
> -    if ((err= new (&thd->warn_root) MYSQL_ERROR(thd, code, level, msg)))
> -      thd->warn_list.push_back(err, &thd->warn_root);
> +  default:
> +    DBUG_ASSERT(FALSE);
>    }
> -  thd->warn_count[(uint) level]++;
> -  thd->total_warn_count++;
> -  DBUG_RETURN(err);
> +
> +  DBUG_VOID_RETURN;
>  }

I think we should drop push_warning all together..

> +
>  /*
>    Push the warning/error to error list if there is still room in the list
>  
> @@ -211,10 +186,12 @@ const LEX_STRING warning_level_names[]=
>  };
>  
>  bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
> -{  
> +{
>    List<Item> field_list;
>    DBUG_ENTER("mysqld_show_warnings");
>  
> +  DBUG_ASSERT(thd->main_da.m_stmt_area.is_read_only());
> +
>    field_list.push_back(new Item_empty_string("Level", 7));
>    field_list.push_back(new Item_return_int("Code",4, MYSQL_TYPE_LONG));
>    field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE));
> @@ -223,7 +200,7 @@ bool mysqld_show_warnings(THD *thd, ulon
>                                   Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
>      DBUG_RETURN(TRUE);
>  
> -  MYSQL_ERROR *err;
> +  SQL_condition *cond;
>    SELECT_LEX *sel= &thd->lex->select_lex;
>    SELECT_LEX_UNIT *unit= &thd->lex->unit;
>    ha_rows idx= 0;
> @@ -231,24 +208,30 @@ bool mysqld_show_warnings(THD *thd, ulon
>  
>    unit->set_limit(sel);
>  
> -  List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
> -  while ((err= it++))
> +  List_iterator_fast<SQL_condition>
> it(thd->main_da.m_stmt_area.warn_list);
> +  while ((cond= it++))
>    {
>      /* Skip levels that the user is not interested in */
> -    if (!(levels_to_show & ((ulong) 1 << err->level)))
> +    if (!(levels_to_show & ((ulong) 1 << cond->m_level)))
>        continue;
>      if (++idx <= unit->offset_limit_cnt)
>        continue;
>      if (idx > unit->select_limit_cnt)
>        break;
>      protocol->prepare_for_resend();
> -    protocol->store(warning_level_names[err->level].str,
> -		    warning_level_names[err->level].length, system_charset_info);
> -    protocol->store((uint32) err->code);
> -    protocol->store(err->msg, strlen(err->msg), system_charset_info);
> +    protocol->store(warning_level_names[cond->m_level].str,
> +		    warning_level_names[cond->m_level].length,
> +                    system_charset_info);
> +    protocol->store((uint32) cond->m_sql_errno);
> +    protocol->store(cond->get_message_text(),
> +                    cond->get_message_octet_length(),
> +                    system_charset_info);
>      if (protocol->write())
>        DBUG_RETURN(TRUE);
>    }
>    my_eof(thd);
> +
> +  thd->main_da.m_stmt_area.set_read_only(FALSE);
> +
>    DBUG_RETURN(FALSE);
>  }
> 
> === modified file 'sql/sql_error.h'
> --- a/sql/sql_error.h	2008-06-12 19:04:52 +0000
> +++ b/sql/sql_error.h	2008-07-23 00:25:11 +0000
> @@ -35,8 +35,8 @@ private:
>    void set_msg(THD *thd, const char *msg_arg);
>  };
>  
> -MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
> -                          uint code, const char *msg);
> +void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
> +                  uint code, const char *msg);
>  void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
>  			 uint code, const char *format, ...);
>  void mysql_reset_errors(THD *thd, bool force);
> 
> === modified file 'sql/sql_insert.cc'
> --- a/sql/sql_insert.cc	2008-07-14 14:56:49 +0000
> +++ b/sql/sql_insert.cc	2008-07-23 00:25:11 +0000
> @@ -2314,8 +2314,8 @@ pthread_handler_t handle_delayed_insert(
>    if (my_thread_init())
>    {
>      /* Can't use my_error since store_globals has not yet been called */
> -    thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES,
> -                                  ER(ER_OUT_OF_RESOURCES));
> +    thd->main_da.set_default_error_status(thd, ER_OUT_OF_RESOURCES,
> +                                          ER(ER_OUT_OF_RESOURCES));
>      goto end;
>    }
>  #endif
> @@ -2325,8 +2325,8 @@ pthread_handler_t handle_delayed_insert(
>    if (init_thr_lock() || thd->store_globals())
>    {
>      /* Can't use my_error since store_globals has perhaps failed */
> -    thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES,
> -                                  ER(ER_OUT_OF_RESOURCES));
> +    thd->main_da.set_default_error_status(thd, ER_OUT_OF_RESOURCES,
> +                                          ER(ER_OUT_OF_RESOURCES));
>      thd->fatal_error();
>      goto err;
>    }
> 
> === added file 'sql/sql_signal.cc'
> --- a/sql/sql_signal.cc	1970-01-01 00:00:00 +0000
> +++ b/sql/sql_signal.cc	2008-07-23 00:25:11 +0000
> @@ -0,0 +1,651 @@
> +/* Copyright (C) 2008 Sun Microsystems, Inc
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; version 2 of the License.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program; if not, write to the Free Software
> +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
> +
> +#include "mysql_priv.h"
> +#include "sp_head.h"
> +#include "sp_pcontext.h"
> +#include "sp_rcontext.h"
> +#include "sql_signal.h"
> +
> +/*
> +  The parser accepts any error code (desired)
> +  The runtime internally supports any error code (desired)
> +  The client server protocol is limited to 16 bits error codes (restriction)
> +  Enforcing the 65535 limit in the runtime until the protocol can change.
> +*/
> +#define MAX_MYSQL_ERRNO UINT_MAX16
> +
> +const LEX_STRING Diag_condition_item_names[]=
> +{
> +  { C_STRING_WITH_LEN("CLASS_ORIGIN") },
> +  { C_STRING_WITH_LEN("SUBCLASS_ORIGIN") },
> +  { C_STRING_WITH_LEN("CONSTRAINT_CATALOG") },
> +  { C_STRING_WITH_LEN("CONSTRAINT_SCHEMA") },
> +  { C_STRING_WITH_LEN("CONSTRAINT_NAME") },
> +  { C_STRING_WITH_LEN("CATALOG_NAME") },
> +  { C_STRING_WITH_LEN("SCHEMA_NAME") },
> +  { C_STRING_WITH_LEN("TABLE_NAME") },
> +  { C_STRING_WITH_LEN("COLUMN_NAME") },
> +  { C_STRING_WITH_LEN("CURSOR_NAME") },
> +  { C_STRING_WITH_LEN("MESSAGE_TEXT") },
> +  { C_STRING_WITH_LEN("MYSQL_ERRNO") },
> +
> +  { C_STRING_WITH_LEN("CONDITION_IDENTIFIER") },
> +  { C_STRING_WITH_LEN("CONDITION_NUMBER") },
> +  { C_STRING_WITH_LEN("CONNECTION_NAME") },
> +  { C_STRING_WITH_LEN("MESSAGE_LENGTH") },
> +  { C_STRING_WITH_LEN("MESSAGE_OCTET_LENGTH") },
> +  { C_STRING_WITH_LEN("PARAMETER_MODE") },
> +  { C_STRING_WITH_LEN("PARAMETER_NAME") },
> +  { C_STRING_WITH_LEN("PARAMETER_ORDINAL_POSITION") },
> +  { C_STRING_WITH_LEN("RETURNED_SQLSTATE") },
> +  { C_STRING_WITH_LEN("ROUTINE_CATALOG") },
> +  { C_STRING_WITH_LEN("ROUTINE_NAME") },
> +  { C_STRING_WITH_LEN("ROUTINE_SCHEMA") },
> +  { C_STRING_WITH_LEN("SERVER_NAME") },
> +  { C_STRING_WITH_LEN("SPECIFIC_NAME") },
> +  { C_STRING_WITH_LEN("TRIGGER_CATALOG") },
> +  { C_STRING_WITH_LEN("TRIGGER_NAME") },
> +  { C_STRING_WITH_LEN("TRIGGER_SCHEMA") }
> +};
> +
> +const LEX_STRING Diag_statement_item_names[]=
> +{
> +  { C_STRING_WITH_LEN("NUMBER") },
> +  { C_STRING_WITH_LEN("MORE") },
> +  { C_STRING_WITH_LEN("COMMAND_FUNCTION") },
> +  { C_STRING_WITH_LEN("COMMAND_FUNCTION_CODE") },
> +  { C_STRING_WITH_LEN("DYNAMIC_FUNCTION") },
> +  { C_STRING_WITH_LEN("DYNAMIC_FUNCTION_CODE") },
> +  { C_STRING_WITH_LEN("ROW_COUNT") },
> +  { C_STRING_WITH_LEN("TRANSACTIONS_COMMITTED") },
> +  { C_STRING_WITH_LEN("TRANSACTIONS_ROLLED_BACK") },
> +  { C_STRING_WITH_LEN("TRANSACTION_ACTIVE") }
> +};
> +
> +
> +SQL_condition::SQL_condition(MEM_ROOT *mem_root)
> + : Sql_alloc(),
> +   m_class_origin(mem_root),
> +   m_subclass_origin(mem_root),
> +   m_constraint_catalog(mem_root),
> +   m_constraint_schema(mem_root),
> +   m_constraint_name(mem_root),
> +   m_catalog_name(mem_root),
> +   m_schema_name(mem_root),
> +   m_table_name(mem_root),
> +   m_column_name(mem_root),
> +   m_cursor_name(mem_root),
> +   m_message_text(),
> +   m_sql_errno(0),
> +   m_condition_identifier(mem_root),
> +   m_connection_name(mem_root),
> +   m_parameter_mode(mem_root),
> +   m_parameter_name(mem_root),
> +   m_parameter_ordinal_position(0),
> +   m_routine_catalog(mem_root),
> +   m_routine_name(mem_root),
> +   m_routine_schema(mem_root),
> +   m_server_name(mem_root),
> +   m_specific_name(mem_root),
> +   m_trigger_catalog(mem_root),
> +   m_trigger_name(mem_root),
> +   m_trigger_schema(mem_root),
> +   m_level(MYSQL_ERROR::WARN_LEVEL_ERROR),
> +   m_flags(0),
> +   m_mem_root(mem_root),
> +   m_broken_caller(FALSE)

Ugh.. we definitely need to improve this. Let's discuss it.

> +{
> +  memset(m_returned_sqlstate, 0, sizeof(m_returned_sqlstate));
> +}
> +
> +SQL_condition *
> +SQL_condition::deep_copy(THD *thd, MEM_ROOT *mem_root,
> +                         const SQL_condition *cond)
> +{
> +  SQL_condition *copy= new (mem_root) SQL_condition(mem_root);
> +  if (copy)
> +    copy->deep_copy(cond);
> +  return copy;
> +}
> +
> +void
> +SQL_condition::deep_copy(const SQL_condition *cond)
> +{
> +  memcpy(m_returned_sqlstate, cond->m_returned_sqlstate,
> +         sizeof(m_returned_sqlstate));
> +
> +  if (cond->m_message_text.length())
> +  {
> +    const char* copy;
> +
> +    copy= strdup_root(m_mem_root, cond->m_message_text.ptr());
> +    m_message_text.set(copy, cond->m_message_text.length(),
> +                       error_message_charset_info);
> +  }
> +  else
> +    m_message_text.length(0);
> +
> +  DBUG_ASSERT(! m_message_text.is_alloced());
> +
> +  m_class_origin.copy(& cond->m_class_origin);
> +  m_subclass_origin.copy(& cond->m_subclass_origin);
> +  m_constraint_catalog.copy(& cond->m_constraint_catalog);
> +  m_constraint_schema.copy(& cond->m_constraint_schema);
> +  m_constraint_name.copy(& cond->m_constraint_name);
> +  m_catalog_name.copy(& cond->m_catalog_name);
> +  m_schema_name.copy(& cond->m_schema_name);
> +  m_table_name.copy(& cond->m_table_name);
> +  m_column_name.copy(& cond->m_column_name);
> +  m_cursor_name.copy(& cond->m_cursor_name);
> +  m_sql_errno= cond->m_sql_errno;
> +  m_condition_identifier.copy(& cond->m_condition_identifier);
> +  m_connection_name.copy(& cond->m_connection_name);
> +  m_parameter_mode.copy(& cond->m_parameter_mode);
> +  m_parameter_name.copy(& cond->m_parameter_name);
> +  m_parameter_ordinal_position= cond->m_parameter_ordinal_position;
> +  m_routine_catalog.copy(& cond->m_routine_catalog);
> +  m_routine_name.copy(& cond->m_routine_name);
> +  m_routine_schema.copy(& cond->m_routine_schema);
> +  m_server_name.copy(& cond->m_server_name);
> +  m_specific_name.copy(& cond->m_specific_name);
> +  m_trigger_catalog.copy(& cond->m_trigger_catalog);
> +  m_trigger_name.copy(& cond->m_trigger_name);
> +  m_trigger_schema.copy(& cond->m_trigger_schema);
> +  m_level= cond->m_level;
> +  m_flags= cond->m_flags;
> +  m_broken_caller= cond->m_broken_caller;
> +}
> +
> +void
> +SQL_condition::set_printf(THD *thd, uint code, const char *str,
> +                          MYSQL_ERROR::enum_warning_level level,
> +                          myf flags, ...)
> +{
> +  va_list args;
> +  char ebuff[ERRMSGSIZE+20];
> +
> +
> +  DBUG_ENTER("SQL_condition::set_printf");
> +
> +  va_start(args, flags);
> +  (void) my_vsnprintf (ebuff, sizeof(ebuff), str, args);

Drop (void)

> +  va_end(args);
> +
> +  set(thd, code, ebuff, level, flags);
> +
> +  DBUG_VOID_RETURN;
> +}
> +
> +void
> +SQL_condition::set(THD *thd, uint code, const char *str,
> +                   MYSQL_ERROR::enum_warning_level level, myf flags)
> +{
> +  const char* sqlstate;
> +
> +  if (code == 0)
> +    code= ER_UNKNOWN_ERROR;

Hum.. is there a valid use case for this?

> +  if (str == NULL)
> +    str= ER(code);

Good.

> +  m_sql_errno= code;
> +
> +  sqlstate= mysql_errno_to_sqlstate(m_sql_errno);
> +  memcpy(m_returned_sqlstate, sqlstate, SQLSTATE_LENGTH);
> +  m_returned_sqlstate[SQLSTATE_LENGTH]= '\0';
> +
> +  set_builtin_message_text(str);
> +  if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
> +      thd->really_abort_on_warning())
> +  {
> +    /*
> +      FIXME:
> +      push_warning and strict SQL_MODE case.
> +    */
> +    m_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
> +    thd->killed= THD::KILL_BAD_DATA;
> +  }
> +  else
> +    m_level= level;
> +  m_flags= flags;
> +}
> +
> +void
> +SQL_condition::set_builtin_message_text(const char* str)
> +{
> +  const char* copy;
> +
> +  copy= strdup_root(m_mem_root, str);
> +  m_message_text.set(copy, strlen(copy), error_message_charset_info);
> +  DBUG_ASSERT(! m_message_text.is_alloced());
> +}
> +
> +const char*
> +SQL_condition::get_message_text() const
> +{
> +  return m_message_text.ptr();
> +}
> +
> +int
> +SQL_condition::get_message_octet_length() const
> +{
> +  return m_message_text.length();
> +}
> +
> +void
> +SQL_condition::set_sqlstate(const char* sqlstate)
> +{
> +  memcpy(m_returned_sqlstate, sqlstate, SQLSTATE_LENGTH);
> +  m_returned_sqlstate[SQLSTATE_LENGTH]= '\0';
> +}
> +
> +Set_signal_information::Set_signal_information()
> +{
> +  int i;
> +  for (i= FIRST_DIAG_SET_PROPERTY;
> +       i <= LAST_DIAG_SET_PROPERTY;
> +       i++)
> +  {
> +    m_item[i]= NULL;
> +  }

Replace this with clear();

> +}
> +
> +Set_signal_information::Set_signal_information(
> +  const Set_signal_information& set)
> +{
> +  int i;
> +  for (i= FIRST_DIAG_SET_PROPERTY;
> +       i <= LAST_DIAG_SET_PROPERTY;
> +       i++)
> +  {
> +    m_item[i]= set.m_item[i];
> +  }
> +}
> +
> +void Set_signal_information::clear()
> +{
> +  int i;
> +  for (i= FIRST_DIAG_SET_PROPERTY;
> +       i <= LAST_DIAG_SET_PROPERTY;
> +       i++)
> +  {
> +    m_item[i]= NULL;
> +  }
> +}
> +
> +int Abstract_signal::eval_sqlcode_sqlstate(THD *thd, SQL_condition *cond)
> +{
> +  DBUG_ASSERT(m_cond);
> +  DBUG_ASSERT(cond);
> +
> +  /*
> +    SIGNAL is restricted in sql_yacc.yy to only signal SQLSTATE conditions
> +  */
> +  DBUG_ASSERT(m_cond->type == sp_cond_type::state);
> +
> +  cond->m_sql_errno= 0;
> +  cond->set_sqlstate(m_cond->sqlstate);
> +
> +  return 0;
> +}
> +
> +int Abstract_signal::eval_defaults(THD *thd, SQL_condition *cond)
> +{
> +  const char* sqlstate= cond->get_sqlstate();
> +
> +  DBUG_ASSERT((sqlstate[0] != '0') || (sqlstate[1] != '0'));
> +
> +  if ((sqlstate[0] == '0') && (sqlstate[1] == '1'))
> +  {
> +    /* SQLSTATE class "01": warning */
> +    cond->set_builtin_message_text(ER(ER_SIGNAL_WARN));
> +    cond->m_level= MYSQL_ERROR::WARN_LEVEL_WARN;
> +    if (cond->m_sql_errno == 0)
> +      cond->m_sql_errno= ER_SIGNAL_WARN;
> +  }
> +  else if ((sqlstate[0] == '0') && (sqlstate[1] == '2'))
> +  {
> +    /* SQLSTATE class "02": not found */
> +    cond->set_builtin_message_text(ER(ER_SIGNAL_NOT_FOUND));
> +    cond->m_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
> +    if (cond->m_sql_errno == 0)
> +      cond->m_sql_errno= ER_SIGNAL_NOT_FOUND;
> +  }
> +  else
> +  {
> +    cond->set_builtin_message_text(ER(ER_SIGNAL_EXCEPTION));
> +    cond->m_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
> +    if (cond->m_sql_errno == 0)
> +      cond->m_sql_errno= ER_SIGNAL_EXCEPTION;
> +  }
> +
> +  return 0;
> +}
> +
> +int assign_condition_item(const char* name, THD *thd, Item *set,
> +                          UTF8String64 *ci)
> +{
> +  String str_value;
> +  String *str;
> +
> +  DBUG_ENTER("assign_condition_item");
> +
> +  if (set->is_null())
> +  {
> +    my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, "NULL");
> +    DBUG_RETURN(1);
> +  }
> +
> +  str= set->val_str(& str_value);
> +  ci->set(str);
> +  if (ci->is_truncated())
> +  {
> +    if (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES |
> +                                   MODE_STRICT_ALL_TABLES))
> +    {
> +      my_error(ER_COND_ITEM_TOO_LONG, MYF(0), name);
> +      DBUG_RETURN(1);
> +    }
> +
> +    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                        WARN_COND_ITEM_TRUNCATED,
> +                        ER(WARN_COND_ITEM_TRUNCATED),
> +                        name);
> +  }
> +
> +  DBUG_RETURN(0);
> +}
> +
> +
> +int Abstract_signal::eval_signal_informations(THD *thd, SQL_condition *cond)
> +{
> +  Item *set;
> +  String str_value;
> +  String *str;
> +  int i;
> +  int result= 1;
> +
> +  DBUG_ENTER("Abstract_signal::eval_signal_informations");
> +
> +  for (i= FIRST_DIAG_SET_PROPERTY;
> +       i <= LAST_DIAG_SET_PROPERTY;
> +       i++)
> +  {
> +    set= m_set_signal_information.m_item[i];
> +    if (set)
> +    {
> +      if (! set->fixed)
> +      {
> +        if (set->fix_fields(thd, & set))
> +          goto end;
> +        m_set_signal_information.m_item[i]= set;
> +      }
> +    }
> +  }
> +
> +  set= m_set_signal_information.m_item[DIAG_CLASS_ORIGIN];
> +  if (set != NULL)
> +  {
> +    if (assign_condition_item("CLASS_ORIGIN", thd, set,
> +                              & cond->m_class_origin))
> +      goto end;
> +  }
> +
> +  set= m_set_signal_information.m_item[DIAG_SUBCLASS_ORIGIN];
> +  if (set != NULL)
> +  {
> +    if (assign_condition_item("SUBCLASS_ORIGIN", thd, set,
> +                              & cond->m_subclass_origin))
> +      goto end;
> +  }
> +
> +  set= m_set_signal_information.m_item[DIAG_CONSTRAINT_CATALOG];
> +  if (set != NULL)
> +  {
> +    if (assign_condition_item("CONSTRAINT_CATALOG", thd, set,
> +                              & cond->m_constraint_catalog))
> +      goto end;
> +  }
> +
> +  set= m_set_signal_information.m_item[DIAG_CONSTRAINT_SCHEMA];
> +  if (set != NULL)
> +  {
> +    if (assign_condition_item("CONSTRAINT_SCHEMA", thd, set,
> +                              & cond->m_constraint_schema))
> +      goto end;
> +  }
> +
> +  set= m_set_signal_information.m_item[DIAG_CONSTRAINT_NAME];
> +  if (set != NULL)
> +  {
> +    if (assign_condition_item("CONSTRAINT_NAME", thd, set,
> +                              & cond->m_constraint_name))
> +      goto end;
> +  }
> +
> +  set= m_set_signal_information.m_item[DIAG_CATALOG_NAME];
> +  if (set != NULL)
> +  {
> +    if (assign_condition_item("CATALOG_NAME", thd, set,
> +                              & cond->m_catalog_name))
> +      goto end;
> +  }
> +
> +  set= m_set_signal_information.m_item[DIAG_SCHEMA_NAME];
> +  if (set != NULL)
> +  {
> +    if (assign_condition_item("SCHEMA_NAME", thd, set,
> +                              & cond->m_schema_name))
> +      goto end;
> +  }
> +
> +  set= m_set_signal_information.m_item[DIAG_TABLE_NAME];
> +  if (set != NULL)
> +  {
> +    if (assign_condition_item("TABLE_NAME", thd, set,
> +                              & cond->m_table_name))
> +      goto end;
> +  }
> +
> +  set= m_set_signal_information.m_item[DIAG_COLUMN_NAME];
> +  if (set != NULL)
> +  {
> +    if (assign_condition_item("COLUMN_NAME", thd, set,
> +                              & cond->m_column_name))
> +      goto end;
> +  }
> +
> +  set= m_set_signal_information.m_item[DIAG_CURSOR_NAME];
> +  if (set != NULL)
> +  {
> +    if (assign_condition_item("CURSOR_NAME", thd, set,
> +                              & cond->m_cursor_name))
> +      goto end;
> +  }

Ugh. The variables could also be a array as m_item and we would just
need to loop, index it, and assign as needed. We already have arrays
containing the names, index, etc.

> +  set= m_set_signal_information.m_item[DIAG_MESSAGE_TEXT];
> +  if (set != NULL)
> +  {
> +    if (set->is_null())
> +    {
> +      my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "MESSAGE_TEXT", "NULL");
> +      goto end;
> +    }
> +    /*
> +      Enforce that SET MESSAGE_TEXT = <value> evaluates the value
> +      as VARCHAR(128) CHARACTER SET UTF8.
> +    */
> +    UTF8String128 utf8_text(thd->mem_root);

I can't find UTF8String128 anywhere..

> +    str= set->val_str(& str_value);
> +    utf8_text.set(str->ptr(), (size_t) str->length(), str->charset());
> +
> +    if (utf8_text.is_truncated())
> +    {
> +      if (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES |
> +                                     MODE_STRICT_ALL_TABLES))
> +      {
> +        my_error(ER_COND_ITEM_TOO_LONG, MYF(0), "MESSAGE_TEXT");
> +        goto end;
> +      }
> +
> +      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                          WARN_COND_ITEM_TRUNCATED,
> +                          ER(WARN_COND_ITEM_TRUNCATED),
> +                          "MESSAGE_TEXT");
> +    }
> +
> +    /*
> +      Convert to the character set used with --language.
> +      This code should be removed when WL#751 is implemented.
> +    */
> +    String converted_text;
> +    converted_text.set_charset(error_message_charset_info);
> +    converted_text.append(utf8_text.ptr(), utf8_text.length(),
> +                          (CHARSET_INFO *) utf8_text.charset());
> +    cond->set_builtin_message_text(converted_text.c_ptr_safe());
> +  }
> +
> +  set= m_set_signal_information.m_item[DIAG_MYSQL_ERRNO];
> +  if (set != NULL)
> +  {
> +    if (set->is_null())
> +    {
> +      my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "MYSQL_ERRNO", "NULL");
> +      goto end;
> +    }
> +    longlong code= set->val_int();
> +    if ((code <= 0) || (code > MAX_MYSQL_ERRNO))
> +    {
> +      str= set->val_str(& str_value);
> +      my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0),
> +               "MYSQL_ERRNO", str->c_ptr_safe());
> +      goto end;
> +    }
> +    cond->m_sql_errno= (int) code;
> +  }
> +
> +  /*
> +    The various item->val_xxx() methods don't return an error code,
> +    but flag thd in case of failure.
> +  */
> +  if (! thd->is_error())
> +    result= 0;
> +
> +end:
> +  for (i= FIRST_DIAG_SET_PROPERTY;
> +       i <= LAST_DIAG_SET_PROPERTY;
> +       i++)
> +  {
> +    set= m_set_signal_information.m_item[i];
> +    if (set)
> +    {
> +      if (set->fixed)
> +        set->cleanup();
> +    }
> +  }
> +
> +  DBUG_RETURN(result);
> +}
> +
> +int Abstract_signal::raise_condition(THD *thd, SQL_condition *cond)
> +{
> +  int result= 1;
> +
> +  DBUG_ENTER("Abstract_signal::raise_condition");
> +
> +  DBUG_ASSERT(m_lex->query_tables == NULL);
> +
> +  if (m_cond != NULL)
> +  {
> +    if (eval_sqlcode_sqlstate(thd, cond))
> +      DBUG_RETURN(result);
> +
> +    if (eval_defaults(thd, cond))
> +      DBUG_RETURN(result);
> +  }
> +
> +  if (eval_signal_informations(thd, cond))
> +    DBUG_RETURN(result);
> +
> +  /* SIGNAL should not signal WARN_LEVEL_NOTE */
> +  DBUG_ASSERT((cond->m_level == MYSQL_ERROR::WARN_LEVEL_WARN) ||
> +              (cond->m_level == MYSQL_ERROR::WARN_LEVEL_ERROR));
> +
> +  thd->raise_condition(cond);
> +
> +  if (cond->m_level == MYSQL_ERROR::WARN_LEVEL_WARN)
> +  {
> +    my_ok(thd);
> +    result= 0;
> +  }
> +
> +  DBUG_RETURN(result);
> +}
> +
> +int SQLCOM_signal::execute(THD *thd)
> +{
> +  int result= 1;
> +  SQL_condition cond(thd->mem_root);
> +
> +  DBUG_ENTER("SQLCOM_signal::execute");
> +
> +  thd->main_da.reset_diagnostics_area();
> +  thd->row_count_func= 0;
> +  mysql_reset_errors(thd, TRUE);
> +
> +  result= raise_condition(thd, &cond);
> +
> +  DBUG_RETURN(result);
> +}
> +
> +
> +int SQLCOM_resignal::execute(THD *thd)
> +{
> +  SQL_condition *signaled;
> +  int result= 1;
> +
> +  DBUG_ENTER("SQLCOM_resignal::execute");
> +
> +  if (! thd->spcont || ! (signaled= thd->spcont->raised_condition()))
> +  {
> +    my_error(ER_RESIGNAL_NO_HANDLER, MYF(0));
> +    DBUG_RETURN(result);
> +  }
> +
> +  if (m_cond == NULL)
> +  {
> +    /* RESIGNAL without signal_value */
> +    result= raise_condition(thd, signaled);
> +    DBUG_RETURN(result);
> +  }
> +
> +  /* RESIGNAL with signal_value */
> +
> +  /* Make room for 2 conditions */
> +  while ((thd->main_da.m_stmt_area.warn_list.elements > 0) &&
> +         ((thd->main_da.m_stmt_area.warn_list.elements + 2)
> +                       > thd->variables.max_error_count))
> +  {
> +    thd->main_da.m_stmt_area.warn_list.pop();
> +    thd->main_da.m_stmt_area.m_more= TRUE;
> +  }
> +
> +  thd->raise_condition_no_handler(signaled);
> +
> +  SQL_condition new_cond(thd->mem_root);
> +  new_cond.deep_copy(signaled);
> +  result= raise_condition(thd, & new_cond);
> +  DBUG_RETURN(result);
> +}
> +
> 
> 

Thread
bzr commit into mysql-6.0-wl2110-review branch (marc.alff:2675) WL#2110Marc Alff23 Jul
  • Re: bzr commit into mysql-6.0-wl2110-review branch (marc.alff:2675)WL#2110Davi Arnaut6 Aug
    • Re: bzr commit into mysql-6.0-wl2110-review branch (marc.alff:2675)WL#2110Marc Alff7 Aug
      • Re: bzr commit into mysql-6.0-wl2110-review branch (marc.alff:2675)WL#2110Davi Arnaut8 Aug
        • Re: bzr commit into mysql-6.0-wl2110-review branch (marc.alff:2675)WL#2110Marc Alff14 Aug