~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to sql/sql_error.cc

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 1995-2002 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */
 
15
 
 
16
/**********************************************************************
 
17
This file contains the implementation of error and warnings related
 
18
 
 
19
  - Whenever an error or warning occurred, it pushes it to a warning list
 
20
    that the user can retrieve with SHOW WARNINGS or SHOW ERRORS.
 
21
 
 
22
  - For each statement, we return the number of warnings generated from this
 
23
    command.  Note that this can be different from @@warning_count as
 
24
    we reset the warning list only for questions that uses a table.
 
25
    This is done to allow on to do:
 
26
    INSERT ...;
 
27
    SELECT @@warning_count;
 
28
    SHOW WARNINGS;
 
29
    (If we would reset after each command, we could not retrieve the number
 
30
     of warnings)
 
31
 
 
32
  - When client requests the information using SHOW command, then 
 
33
    server processes from this list and returns back in the form of 
 
34
    resultset.
 
35
 
 
36
    Supported syntaxes:
 
37
 
 
38
    SHOW [COUNT(*)] ERRORS [LIMIT [offset,] rows]
 
39
    SHOW [COUNT(*)] WARNINGS [LIMIT [offset,] rows]
 
40
    SELECT @@warning_count, @@error_count;
 
41
 
 
42
***********************************************************************/
 
43
 
 
44
#include "mysql_priv.h"
 
45
#include "sp_rcontext.h"
 
46
 
 
47
/*
 
48
  Store a new message in an error object
 
49
 
 
50
  This is used to in group_concat() to register how many warnings we actually
 
51
  got after the query has been executed.
 
52
*/
 
53
 
 
54
void MYSQL_ERROR::set_msg(THD *thd, const char *msg_arg)
 
55
{
 
56
  msg= strdup_root(&thd->warn_root, msg_arg);
 
57
}
 
58
 
 
59
 
 
60
/*
 
61
  Reset all warnings for the thread
 
62
 
 
63
  SYNOPSIS
 
64
    mysql_reset_errors()
 
65
    thd                 Thread handle
 
66
    force               Reset warnings even if it has been done before
 
67
 
 
68
  IMPLEMENTATION
 
69
    Don't reset warnings if this has already been called for this query.
 
70
    This may happen if one gets a warning during the parsing stage,
 
71
    in which case push_warnings() has already called this function.
 
72
*/  
 
73
 
 
74
void mysql_reset_errors(THD *thd, bool force)
 
75
{
 
76
  DBUG_ENTER("mysql_reset_errors");
 
77
  if (thd->query_id != thd->warn_id || force)
 
78
  {
 
79
    thd->warn_id= thd->query_id;
 
80
    free_root(&thd->warn_root,MYF(0));
 
81
    bzero((char*) thd->warn_count, sizeof(thd->warn_count));
 
82
    if (force)
 
83
      thd->total_warn_count= 0;
 
84
    thd->warn_list.empty();
 
85
    thd->row_count= 1; // by default point to row 1
 
86
  }
 
87
  DBUG_VOID_RETURN;
 
88
}
 
89
 
 
90
 
 
91
/* 
 
92
  Push the warning/error to error list if there is still room in the list
 
93
 
 
94
  SYNOPSIS
 
95
    push_warning()
 
96
    thd                 Thread handle
 
97
    level               Severity of warning (note, warning, error ...)
 
98
    code                Error number
 
99
    msg                 Clear error message
 
100
    
 
101
  RETURN
 
102
    pointer on MYSQL_ERROR object
 
103
*/
 
104
 
 
105
MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, 
 
106
                          uint code, const char *msg)
 
107
{
 
108
  MYSQL_ERROR *err= 0;
 
109
  DBUG_ENTER("push_warning");
 
110
  DBUG_PRINT("enter", ("code: %d, msg: %s", code, msg));
 
111
 
 
112
  DBUG_ASSERT(code != 0);
 
113
  DBUG_ASSERT(msg != NULL);
 
114
 
 
115
  if (level == MYSQL_ERROR::WARN_LEVEL_NOTE &&
 
116
      !(thd->options & OPTION_SQL_NOTES))
 
117
    DBUG_RETURN(0);
 
118
 
 
119
  if (thd->query_id != thd->warn_id && !thd->spcont)
 
120
    mysql_reset_errors(thd, 0);
 
121
  thd->got_warning= 1;
 
122
 
 
123
  /* Abort if we are using strict mode and we are not using IGNORE */
 
124
  if ((int) level >= (int) MYSQL_ERROR::WARN_LEVEL_WARN &&
 
125
      thd->really_abort_on_warning())
 
126
  {
 
127
    /* Avoid my_message() calling push_warning */
 
128
    bool no_warnings_for_error= thd->no_warnings_for_error;
 
129
    sp_rcontext *spcont= thd->spcont;
 
130
 
 
131
    thd->no_warnings_for_error= 1;
 
132
    thd->spcont= NULL;
 
133
 
 
134
    thd->killed= THD::KILL_BAD_DATA;
 
135
    my_message(code, msg, MYF(0));
 
136
 
 
137
    thd->spcont= spcont;
 
138
    thd->no_warnings_for_error= no_warnings_for_error;
 
139
    /* Store error in error list (as my_message() didn't do it) */
 
140
    level= MYSQL_ERROR::WARN_LEVEL_ERROR;
 
141
  }
 
142
 
 
143
  if (thd->handle_error(code, msg, level))
 
144
    DBUG_RETURN(NULL);
 
145
 
 
146
  if (thd->spcont &&
 
147
      thd->spcont->handle_error(code, level, thd))
 
148
  {
 
149
    DBUG_RETURN(NULL);
 
150
  }
 
151
  query_cache_abort(&thd->net);
 
152
 
 
153
 
 
154
  if (thd->warn_list.elements < thd->variables.max_error_count)
 
155
  {
 
156
    /* We have to use warn_root, as mem_root is freed after each query */
 
157
    if ((err= new (&thd->warn_root) MYSQL_ERROR(thd, code, level, msg)))
 
158
      thd->warn_list.push_back(err, &thd->warn_root);
 
159
  }
 
160
  thd->warn_count[(uint) level]++;
 
161
  thd->total_warn_count++;
 
162
  DBUG_RETURN(err);
 
163
}
 
164
 
 
165
/*
 
166
  Push the warning/error to error list if there is still room in the list
 
167
 
 
168
  SYNOPSIS
 
169
    push_warning_printf()
 
170
    thd                 Thread handle
 
171
    level               Severity of warning (note, warning, error ...)
 
172
    code                Error number
 
173
    msg                 Clear error message
 
174
*/
 
175
 
 
176
void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
 
177
                         uint code, const char *format, ...)
 
178
{
 
179
  va_list args;
 
180
  char    warning[MYSQL_ERRMSG_SIZE];
 
181
  DBUG_ENTER("push_warning_printf");
 
182
  DBUG_PRINT("enter",("warning: %u", code));
 
183
 
 
184
  DBUG_ASSERT(code != 0);
 
185
  DBUG_ASSERT(format != NULL);
 
186
 
 
187
  va_start(args,format);
 
188
  my_vsnprintf(warning, sizeof(warning), format, args);
 
189
  va_end(args);
 
190
  push_warning(thd, level, code, warning);
 
191
  DBUG_VOID_RETURN;
 
192
}
 
193
 
 
194
 
 
195
/*
 
196
  Send all notes, errors or warnings to the client in a result set
 
197
 
 
198
  SYNOPSIS
 
199
    mysqld_show_warnings()
 
200
    thd                 Thread handler
 
201
    levels_to_show      Bitmap for which levels to show
 
202
 
 
203
  DESCRIPTION
 
204
    Takes into account the current LIMIT
 
205
 
 
206
  RETURN VALUES
 
207
    FALSE ok
 
208
    TRUE  Error sending data to client
 
209
*/
 
210
 
 
211
const LEX_STRING warning_level_names[]=
 
212
{
 
213
  { C_STRING_WITH_LEN("Note") },
 
214
  { C_STRING_WITH_LEN("Warning") },
 
215
  { C_STRING_WITH_LEN("Error") },
 
216
  { C_STRING_WITH_LEN("?") }
 
217
};
 
218
 
 
219
bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
 
220
{  
 
221
  List<Item> field_list;
 
222
  DBUG_ENTER("mysqld_show_warnings");
 
223
 
 
224
  field_list.push_back(new Item_empty_string("Level", 7));
 
225
  field_list.push_back(new Item_return_int("Code",4, MYSQL_TYPE_LONG));
 
226
  field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE));
 
227
 
 
228
  if (thd->protocol->send_fields(&field_list,
 
229
                                 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
 
230
    DBUG_RETURN(TRUE);
 
231
 
 
232
  MYSQL_ERROR *err;
 
233
  SELECT_LEX *sel= &thd->lex->select_lex;
 
234
  SELECT_LEX_UNIT *unit= &thd->lex->unit;
 
235
  ha_rows idx= 0;
 
236
  Protocol *protocol=thd->protocol;
 
237
 
 
238
  unit->set_limit(sel);
 
239
 
 
240
  List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
 
241
  while ((err= it++))
 
242
  {
 
243
    /* Skip levels that the user is not interested in */
 
244
    if (!(levels_to_show & ((ulong) 1 << err->level)))
 
245
      continue;
 
246
    if (++idx <= unit->offset_limit_cnt)
 
247
      continue;
 
248
    if (idx > unit->select_limit_cnt)
 
249
      break;
 
250
    protocol->prepare_for_resend();
 
251
    protocol->store(warning_level_names[err->level].str,
 
252
                    warning_level_names[err->level].length, system_charset_info);
 
253
    protocol->store((uint32) err->code);
 
254
    protocol->store(err->msg, (uint) strlen(err->msg), system_charset_info);
 
255
    if (protocol->write())
 
256
      DBUG_RETURN(TRUE);
 
257
  }
 
258
  my_eof(thd);
 
259
  DBUG_RETURN(FALSE);
 
260
}