sql_error.cc 4.83 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* Copyright (C) 1995-2002 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   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
*/

/**********************************************************************
This file contains the implementation of error and warnings related

21 22 23 24 25 26 27 28 29 30 31 32
  - Whenever an error or warning occurred, it pushes it to a warning list
    that the user can retrieve with SHOW WARNINGS or SHOW ERRORS.

  - For each statement, we return the number of warnings generated from this
    command.  Note that this can be different from @@warning_count as
    we reset the warning list only for questions that uses a table.
    This is done to allow on to do:
    INSERT ...;
    SELECT @@warning_count;
    SHOW WARNINGS;
    (If we would reset after each command, we could not retrieve the number
     of warnings)
unknown's avatar
unknown committed
33 34 35 36 37

  - When client requests the information using SHOW command, then 
    server processes from this list and returns back in the form of 
    resultset.

38 39 40 41 42
    Supported syntaxes:

    SHOW [COUNT(*)] ERRORS [LIMIT [offset,] rows]
    SHOW [COUNT(*)] WARNINGS [LIMIT [offset,] rows]
    SELECT @@warning_count, @@error_count;
unknown's avatar
unknown committed
43 44 45 46 47

***********************************************************************/

#include "mysql_priv.h"

48 49
/*
  Reset all warnings for the thread
unknown's avatar
unknown committed
50

51 52 53
  SYNOPSIS
    mysql_reset_errors()
    thd			Thread handle
54 55 56 57 58

  IMPLEMENTATION
    Don't reset warnings if this has already been called for this query.
    This may happen if one gets a warning during the parsing stage,
    in which case push_warnings() has already called this function.
59
*/  
unknown's avatar
unknown committed
60

61 62
void mysql_reset_errors(THD *thd)
{
63 64 65 66 67 68 69
  if (thd->query_id != thd->warn_id)
  {
    thd->warn_id= thd->query_id;
    free_root(&thd->warn_root,MYF(0));
    bzero((char*) thd->warn_count, sizeof(thd->warn_count));
    thd->warn_list.empty();
  }
unknown's avatar
unknown committed
70 71
}

72

unknown's avatar
unknown committed
73
/* 
74 75 76 77 78 79 80 81
  Push the warning/error to error list if there is still room in the list

  SYNOPSIS
    push_warning()
    thd			Thread handle
    level		Severity of warning (note, warning, error ...)
    code		Error number
    msg			Clear error message
unknown's avatar
unknown committed
82 83
*/

84 85 86
void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
		  const char *msg)
{
87 88 89
  if (thd->query_id != thd->warn_id)
    mysql_reset_errors(thd);

90
  if (thd->warn_list.elements < thd->variables.max_error_count)
unknown's avatar
unknown committed
91
  {
92 93 94
    /*
      The following code is here to change the allocation to not
      use the thd->mem_root, which is freed after each query
unknown's avatar
unknown committed
95
    */
96 97 98 99 100 101
    MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
    my_pthread_setspecific_ptr(THR_MALLOC, &thd->warn_root);
    MYSQL_ERROR *err= new MYSQL_ERROR(code, level, msg);
    if (err)
      thd->warn_list.push_back(err);
    my_pthread_setspecific_ptr(THR_MALLOC, old_root);
unknown's avatar
unknown committed
102
  }
103 104
  thd->warn_count[(uint) level]++;
  thd->total_warn_count++;
unknown's avatar
unknown committed
105 106 107
}


108 109
/*
  Send all notes, errors or warnings to the client in a result set
unknown's avatar
unknown committed
110

111 112 113 114
  SYNOPSIS
    mysqld_show_warnings()
    thd			Thread handler
    levels_to_show	Bitmap for which levels to show
unknown's avatar
unknown committed
115

116 117
  DESCRIPTION
    Takes into account the current LIMIT
unknown's avatar
unknown committed
118

119 120 121 122
  RETURN VALUES
    0	ok
    1	Error sending data to client
*/
unknown's avatar
unknown committed
123

124
static const char *warning_level_names[]= {"Note", "Warning", "Error", "?"};
unknown's avatar
unknown committed
125 126


127 128
my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
{  
unknown's avatar
unknown committed
129
  List<Item> field_list;
unknown's avatar
unknown committed
130
  DBUG_ENTER("mysqld_show_warnings");
unknown's avatar
unknown committed
131

132 133 134
  field_list.push_back(new Item_empty_string("Level", 7));
  field_list.push_back(new Item_int("Code",0,4));
  field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE));
unknown's avatar
unknown committed
135 136 137 138

  if (send_fields(thd,field_list,1))
    DBUG_RETURN(1);

139 140 141
  MYSQL_ERROR *err;
  SELECT_LEX *sel= &thd->lex.select_lex;
  ha_rows offset= sel->offset_limit, limit= sel->select_limit;
unknown's avatar
unknown committed
142
  
143 144
  List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
  while ((err= it++))
unknown's avatar
unknown committed
145
  {
146 147 148 149 150 151 152 153
    /* Skip levels that the user is not interested in */
    if (!(levels_to_show & ((ulong) 1 << err->level)))
      continue;
    if (offset)
    {
      offset--;
      continue;
    }
unknown's avatar
unknown committed
154
    thd->packet.length(0);
155 156 157 158 159 160 161
    net_store_data(&thd->packet,warning_level_names[err->level]);
    net_store_data(&thd->packet,(uint32) err->code);
    net_store_data(&thd->packet,err->msg);
    if (my_net_write(&thd->net,(char*)thd->packet.ptr(),thd->packet.length()))
      DBUG_RETURN(1);
    if (!--limit)
      break;
unknown's avatar
unknown committed
162
  }
163
  send_eof(thd);  
unknown's avatar
unknown committed
164 165
  DBUG_RETURN(0);
}