sql_error.cc 7.65 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* 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
15
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */
unknown's avatar
unknown committed
16 17 18 19

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

20 21 22 23 24 25 26 27 28 29 30 31
  - 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
32 33 34 35 36

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

37 38 39 40 41
    Supported syntaxes:

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

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

#include "mysql_priv.h"
unknown's avatar
unknown committed
46
#include "sp_rcontext.h"
unknown's avatar
unknown committed
47

48 49 50 51 52 53 54 55 56 57 58 59 60
/*
  Store a new message in an error object

  This is used to in group_concat() to register how many warnings we actually
  got after the query has been executed.
*/

void MYSQL_ERROR::set_msg(THD *thd, const char *msg_arg)
{
  msg= strdup_root(&thd->warn_root, msg_arg);
}


61 62
/*
  Reset all warnings for the thread
unknown's avatar
unknown committed
63

64 65 66
  SYNOPSIS
    mysql_reset_errors()
    thd			Thread handle
67
    force               Reset warnings even if it has been done before
68 69 70 71 72

  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.
73
*/  
unknown's avatar
unknown committed
74

75
void mysql_reset_errors(THD *thd, bool force)
76
{
77
  DBUG_ENTER("mysql_reset_errors");
78
  if (thd->query_id != thd->warn_id || force)
79 80 81 82
  {
    thd->warn_id= thd->query_id;
    free_root(&thd->warn_root,MYF(0));
    bzero((char*) thd->warn_count, sizeof(thd->warn_count));
unknown's avatar
unknown committed
83 84
    if (force)
      thd->total_warn_count= 0;
85
    thd->warn_list.empty();
86
    thd->row_count= 1; // by default point to row 1
87
  }
88
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
89 90
}

91

unknown's avatar
unknown committed
92
/* 
93 94 95 96 97 98 99 100
  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
101 102 103
    
  RETURN
    pointer on MYSQL_ERROR object
unknown's avatar
unknown committed
104 105
*/

106 107
MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, 
                          uint code, const char *msg)
108
{
109
  MYSQL_ERROR *err= 0;
110
  DBUG_ENTER("push_warning");
111
  DBUG_PRINT("enter", ("code: %d, msg: %s", code, msg));
112

113 114 115
  if (level == MYSQL_ERROR::WARN_LEVEL_NOTE &&
      !(thd->options & OPTION_SQL_NOTES))
    DBUG_RETURN(0);
116

117
  if (thd->query_id != thd->warn_id && !thd->spcont)
unknown's avatar
unknown committed
118
    mysql_reset_errors(thd, 0);
unknown's avatar
unknown committed
119 120 121 122 123 124
  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())
  {
125 126
    /* Avoid my_message() calling push_warning */
    bool no_warnings_for_error= thd->no_warnings_for_error;
127 128
    sp_rcontext *spcont= thd->spcont;

129
    thd->no_warnings_for_error= 1;
130 131
    thd->spcont= 0;

unknown's avatar
unknown committed
132 133
    thd->killed= THD::KILL_BAD_DATA;
    my_message(code, msg, MYF(0));
134 135

    thd->spcont= spcont;
136
    thd->no_warnings_for_error= no_warnings_for_error;
137
    /* Store error in error list (as my_message() didn't do it) */
138
    level= MYSQL_ERROR::WARN_LEVEL_ERROR;
unknown's avatar
unknown committed
139
  }
140

141 142 143 144 145 146 147
  if (thd->spcont &&
      thd->spcont->find_handler(code,
                                ((int) level >=
                                 (int) MYSQL_ERROR::WARN_LEVEL_WARN &&
                                 thd->really_abort_on_warning()) ?
                                MYSQL_ERROR::WARN_LEVEL_ERROR : level))
  {
148 149
    if (! thd->spcont->found_handler_here())
      thd->net.report_error= 1; /* Make "select" abort correctly */ 
150 151
    DBUG_RETURN(NULL);
  }
152 153
  query_cache_abort(&thd->net);

154

155
  if (thd->warn_list.elements < thd->variables.max_error_count)
unknown's avatar
unknown committed
156
  {
157 158 159
    /*
      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
160
    */
unknown's avatar
unknown committed
161 162
    MEM_ROOT *old_root= thd->mem_root;
    thd->mem_root= &thd->warn_root;
unknown's avatar
unknown committed
163
    if ((err= new MYSQL_ERROR(thd, code, level, msg)))
164
      thd->warn_list.push_back(err);
unknown's avatar
unknown committed
165
    thd->mem_root= old_root;
unknown's avatar
unknown committed
166
  }
167 168
  thd->warn_count[(uint) level]++;
  thd->total_warn_count++;
169
  DBUG_RETURN(err);
unknown's avatar
unknown committed
170 171
}

172
/*
173 174 175 176 177 178 179 180
  Push the warning/error to error list if there is still room in the list

  SYNOPSIS
    push_warning_printf()
    thd			Thread handle
    level		Severity of warning (note, warning, error ...)
    code		Error number
    msg			Clear error message
181 182
*/

183 184
void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
			 uint code, const char *format, ...)
185 186 187
{
  va_list args;
  char    warning[ERRMSGSIZE+20];
188 189
  DBUG_ENTER("push_warning_printf");
  DBUG_PRINT("enter",("warning: %u", code));
190
  
191 192
  va_start(args,format);
  my_vsnprintf(warning, sizeof(warning), format, args);
193
  va_end(args);
194
  push_warning(thd, level, code, warning);
195 196 197
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
198

199 200
/*
  Send all notes, errors or warnings to the client in a result set
unknown's avatar
unknown committed
201

202 203 204 205
  SYNOPSIS
    mysqld_show_warnings()
    thd			Thread handler
    levels_to_show	Bitmap for which levels to show
unknown's avatar
unknown committed
206

207 208
  DESCRIPTION
    Takes into account the current LIMIT
unknown's avatar
unknown committed
209

210
  RETURN VALUES
unknown's avatar
unknown committed
211 212
    FALSE ok
    TRUE  Error sending data to client
213
*/
unknown's avatar
unknown committed
214

215
static const char *warning_level_names[]= {"Note", "Warning", "Error", "?"};
216
static int warning_level_length[]= { 4, 7, 5, 1 };
unknown's avatar
unknown committed
217

unknown's avatar
unknown committed
218
bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
219
{  
unknown's avatar
unknown committed
220
  List<Item> field_list;
unknown's avatar
unknown committed
221
  DBUG_ENTER("mysqld_show_warnings");
unknown's avatar
unknown committed
222

223
  field_list.push_back(new Item_empty_string("Level", 7));
224
  field_list.push_back(new Item_return_int("Code",4, MYSQL_TYPE_LONG));
225
  field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE));
unknown's avatar
unknown committed
226

unknown's avatar
unknown committed
227 228 229
  if (thd->protocol->send_fields(&field_list,
                                 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
230

231
  MYSQL_ERROR *err;
232
  SELECT_LEX *sel= &thd->lex->select_lex;
233 234
  SELECT_LEX_UNIT *unit= &thd->lex->unit;
  ha_rows idx= 0;
235
  Protocol *protocol=thd->protocol;
236 237 238

  unit->set_limit(sel);

239 240
  List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
  while ((err= it++))
unknown's avatar
unknown committed
241
  {
242 243 244
    /* Skip levels that the user is not interested in */
    if (!(levels_to_show & ((ulong) 1 << err->level)))
      continue;
245
    if (++idx <= unit->offset_limit_cnt)
246
      continue;
247 248
    if (idx > unit->select_limit_cnt)
      break;
249 250
    protocol->prepare_for_resend();
    protocol->store(warning_level_names[err->level],
251
		    warning_level_length[err->level], system_charset_info);
252
    protocol->store((uint32) err->code);
253
    protocol->store(err->msg, strlen(err->msg), system_charset_info);
254
    if (protocol->write())
unknown's avatar
unknown committed
255
      DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
256
  }
unknown's avatar
unknown committed
257 258
  send_eof(thd);
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
259
}