MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
my_error.c
1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include "mysys_priv.h"
17 #include "mysys_err.h"
18 #include <m_string.h>
19 #include <stdarg.h>
20 #include <m_ctype.h>
21 #include "my_base.h"
22 #include "my_handler_errors.h"
23 
24 /* Max length of a error message. Should be kept in sync with MYSQL_ERRMSG_SIZE. */
25 #define ERRMSGSIZE (512)
26 
27 /* Define some external variables for error handling */
28 
29 /*
30  WARNING!
31  my_error family functions have to be used according following rules:
32  - if message have not parameters use my_message(ER_CODE, ER(ER_CODE), MYF(N))
33  - if message registered use my_error(ER_CODE, MYF(N), ...).
34  - With some special text of errror message use:
35  my_printf_error(ER_CODE, format, MYF(N), ...)
36 */
37 
38 /*
39  Message texts are registered into a linked list of 'my_err_head' structs.
40  Each struct contains (1.) an array of pointers to C character strings with
41  '\0' termination, (2.) the error number for the first message in the array
42  (array index 0) and (3.) the error number for the last message in the array
43  (array index (last - first)).
44  The array may contain gaps with NULL pointers and pointers to empty strings.
45  Both kinds of gaps will be translated to "Unknown error %d.", if my_error()
46  is called with a respective error number.
47  The list of header structs is sorted in increasing order of error numbers.
48  Negative error numbers are allowed. Overlap of error numbers is not allowed.
49  Not registered error numbers will be translated to "Unknown error %d.".
50 */
51 static struct my_err_head
52 {
53  struct my_err_head *meh_next; /* chain link */
54  const char** (*get_errmsgs) (); /* returns error message format */
55  int meh_first; /* error number matching array slot 0 */
56  int meh_last; /* error number matching last slot */
57 } my_errmsgs_globerrs = {NULL, get_global_errmsgs, EE_ERROR_FIRST, EE_ERROR_LAST};
58 
59 static struct my_err_head *my_errmsgs_list= &my_errmsgs_globerrs;
60 
61 
72 char *my_strerror(char *buf, size_t len, int nr)
73 {
74  char *msg= NULL;
75 
76  buf[0]= '\0'; /* failsafe */
77 
78  /*
79  These (handler-) error messages are shared by perror, as required
80  by the principle of least surprise.
81  */
82  if ((nr >= HA_ERR_FIRST) && (nr <= HA_ERR_LAST))
83  msg= (char *) handler_error_messages[nr - HA_ERR_FIRST];
84 
85  if (msg != NULL)
86  strmake(buf, msg, len - 1);
87  else
88  {
89  /*
90  On Windows, do things the Windows way. On a system that supports both
91  the GNU and the XSI variant, use whichever was configured (GNU); if
92  this choice is not advertised, use the default (POSIX/XSI). Testing
93  for __GNUC__ is not sufficient to determine whether this choice exists.
94  */
95 #if defined(__WIN__)
96  strerror_s(buf, len, nr);
97 #elif ((defined _POSIX_C_SOURCE && (_POSIX_C_SOURCE >= 200112L)) || \
98  (defined _XOPEN_SOURCE && (_XOPEN_SOURCE >= 600))) && \
99  ! defined _GNU_SOURCE
100  strerror_r(nr, buf, len); /* I can build with or without GNU */
101 #elif defined _GNU_SOURCE
102  char *r= strerror_r(nr, buf, len);
103  if (r != buf) /* Want to help, GNU? */
104  strmake(buf, r, len - 1); /* Then don't. */
105 #else
106  strerror_r(nr, buf, len);
107 #endif
108  }
109 
110  /*
111  strerror() return values are implementation-dependent, so let's
112  be pragmatic.
113  */
114  if (!buf[0])
115  strmake(buf, "unknown error", len - 1);
116 
117  return buf;
118 }
119 
120 
133 const char *my_get_err_msg(int nr)
134 {
135  const char *format;
136  struct my_err_head *meh_p;
137 
138  /* Search for the range this error is in. */
139  for (meh_p= my_errmsgs_list; meh_p; meh_p= meh_p->meh_next)
140  if (nr <= meh_p->meh_last)
141  break;
142 
143  /*
144  If we found the range this error number is in, get the format string.
145  If the string is empty, or a NULL pointer, or if we're out of return,
146  we return NULL.
147  */
148  if (!(format= (meh_p && (nr >= meh_p->meh_first)) ?
149  meh_p->get_errmsgs()[nr - meh_p->meh_first] : NULL) ||
150  !*format)
151  return NULL;
152 
153  return format;
154 }
155 
156 
168 void my_error(int nr, myf MyFlags, ...)
169 {
170  const char *format;
171  va_list args;
172  char ebuff[ERRMSGSIZE];
173  DBUG_ENTER("my_error");
174  DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d", nr, MyFlags, errno));
175 
176  if (!(format = my_get_err_msg(nr)))
177  (void) my_snprintf(ebuff, sizeof(ebuff), "Unknown error %d", nr);
178  else
179  {
180  va_start(args,MyFlags);
181  (void) my_vsnprintf_ex(&my_charset_utf8_general_ci, ebuff,
182  sizeof(ebuff), format, args);
183  va_end(args);
184  }
185  (*error_handler_hook)(nr, ebuff, MyFlags);
186  DBUG_VOID_RETURN;
187 }
188 
189 
202 void my_printf_error(uint error, const char *format, myf MyFlags, ...)
203 {
204  va_list args;
205  char ebuff[ERRMSGSIZE];
206  DBUG_ENTER("my_printf_error");
207  DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d Format: %s",
208  error, MyFlags, errno, format));
209 
210  va_start(args,MyFlags);
211  (void) my_vsnprintf_ex(&my_charset_utf8_general_ci, ebuff,
212  sizeof(ebuff), format, args);
213  va_end(args);
214  (*error_handler_hook)(error, ebuff, MyFlags);
215  DBUG_VOID_RETURN;
216 }
217 
230 void my_printv_error(uint error, const char *format, myf MyFlags, va_list ap)
231 {
232  char ebuff[ERRMSGSIZE];
233  DBUG_ENTER("my_printv_error");
234  DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d format: %s",
235  error, MyFlags, errno, format));
236 
237  (void) my_vsnprintf(ebuff, sizeof(ebuff), format, ap);
238  (*error_handler_hook)(error, ebuff, MyFlags);
239  DBUG_VOID_RETURN;
240 }
241 
242 /*
243  Warning as printf
244 
245  SYNOPSIS
246  my_printf_warning()
247  format> Format string
248  ...> variable list
249 */
250 void(*sql_print_warning_hook)(const char *format,...);
251 void my_printf_warning(const char *format, ...)
252 {
253  va_list args;
254  char wbuff[ERRMSGSIZE];
255  DBUG_ENTER("my_printf_warning");
256  DBUG_PRINT("my", ("Format: %s", format));
257  va_start(args,format);
258  (void) my_vsnprintf (wbuff, sizeof(wbuff), format, args);
259  va_end(args);
260  (*sql_print_warning_hook)(wbuff);
261  DBUG_VOID_RETURN;
262 }
263 
275 void my_message(uint error, const char *str, register myf MyFlags)
276 {
277  (*error_handler_hook)(error, str, MyFlags);
278 }
279 
280 
301 int my_error_register(const char** (*get_errmsgs) (), int first, int last)
302 {
303  struct my_err_head *meh_p;
304  struct my_err_head **search_meh_pp;
305 
306  /* Allocate a new header structure. */
307  if (! (meh_p= (struct my_err_head*) my_malloc(sizeof(struct my_err_head),
308  MYF(MY_WME))))
309  return 1;
310  meh_p->get_errmsgs= get_errmsgs;
311  meh_p->meh_first= first;
312  meh_p->meh_last= last;
313 
314  /* Search for the right position in the list. */
315  for (search_meh_pp= &my_errmsgs_list;
316  *search_meh_pp;
317  search_meh_pp= &(*search_meh_pp)->meh_next)
318  {
319  if ((*search_meh_pp)->meh_last > first)
320  break;
321  }
322 
323  /* Error numbers must be unique. No overlapping is allowed. */
324  if (*search_meh_pp && ((*search_meh_pp)->meh_first <= last))
325  {
326  my_free(meh_p);
327  return 1;
328  }
329 
330  /* Insert header into the chain. */
331  meh_p->meh_next= *search_meh_pp;
332  *search_meh_pp= meh_p;
333  return 0;
334 }
335 
336 
357 const char **my_error_unregister(int first, int last)
358 {
359  struct my_err_head *meh_p;
360  struct my_err_head **search_meh_pp;
361  const char **errmsgs;
362 
363  /* Search for the registration in the list. */
364  for (search_meh_pp= &my_errmsgs_list;
365  *search_meh_pp;
366  search_meh_pp= &(*search_meh_pp)->meh_next)
367  {
368  if (((*search_meh_pp)->meh_first == first) &&
369  ((*search_meh_pp)->meh_last == last))
370  break;
371  }
372  if (! *search_meh_pp)
373  return NULL;
374 
375  /* Remove header from the chain. */
376  meh_p= *search_meh_pp;
377  *search_meh_pp= meh_p->meh_next;
378 
379  /* Save the return value and free the header. */
380  errmsgs= meh_p->get_errmsgs();
381  my_free(meh_p);
382 
383  return errmsgs;
384 }
385 
386 
398 void my_error_unregister_all(void)
399 {
400  struct my_err_head *cursor, *saved_next;
401 
402  for (cursor= my_errmsgs_globerrs.meh_next; cursor != NULL; cursor= saved_next)
403  {
404  /* We need this ptr, but we're about to free its container, so save it. */
405  saved_next= cursor->meh_next;
406 
407  my_free(cursor);
408  }
409  my_errmsgs_globerrs.meh_next= NULL; /* Freed in first iteration above. */
410 
411  my_errmsgs_list= &my_errmsgs_globerrs;
412 }