mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-30 18:36:12 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			329 lines
		
	
	
	
		
			9.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			329 lines
		
	
	
	
		
			9.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
 | |
| 
 | |
|    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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
 | |
| 
 | |
| #include "mysys_priv.h"
 | |
| #include "mysys_err.h"
 | |
| #include <m_string.h>
 | |
| #include <stdarg.h>
 | |
| #include <m_ctype.h>
 | |
| 
 | |
| /* Max length of a error message. Should be kept in sync with MYSQL_ERRMSG_SIZE. */
 | |
| #define ERRMSGSIZE      (512)
 | |
| 
 | |
| /* Define some external variables for error handling */
 | |
| 
 | |
| /*
 | |
|   WARNING!
 | |
|   my_error family functions have to be used according following rules:
 | |
|   - if message have not parameters use my_message(ER_CODE, ER(ER_CODE), MYF(N))
 | |
|   - if message registered use my_error(ER_CODE, MYF(N), ...).
 | |
|   - With some special text of errror message use:
 | |
|   my_printf_error(ER_CODE, format, MYF(N), ...)
 | |
| */
 | |
| 
 | |
| /*
 | |
|   Message texts are registered into a linked list of 'my_err_head' structs.
 | |
|   Each struct contains (1.) an array of pointers to C character strings with
 | |
|   '\0' termination, (2.) the error number for the first message in the array
 | |
|   (array index 0) and (3.) the error number for the last message in the array
 | |
|   (array index (last - first)).
 | |
|   The array may contain gaps with NULL pointers and pointers to empty strings.
 | |
|   Both kinds of gaps will be translated to "Unknown error %d.", if my_error()
 | |
|   is called with a respective error number.
 | |
|   The list of header structs is sorted in increasing order of error numbers.
 | |
|   Negative error numbers are allowed. Overlap of error numbers is not allowed.
 | |
|   Not registered error numbers will be translated to "Unknown error %d.".
 | |
| */
 | |
| static struct my_err_head
 | |
| {
 | |
|   struct my_err_head *meh_next;         /* chain link */
 | |
|   const char**       (*get_errmsgs)(int nr); /* returns error message format */
 | |
|   uint               meh_first;       /* error number matching array slot 0 */
 | |
|   uint               meh_last;          /* error number matching last slot */
 | |
| } my_errmsgs_globerrs=
 | |
| {NULL, get_global_errmsgs, EE_ERROR_FIRST, EE_ERROR_LAST};
 | |
| 
 | |
| static struct my_err_head *my_errmsgs_list= &my_errmsgs_globerrs;
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @brief Get an error format string from one of the my_error_register()ed sets
 | |
| 
 | |
|   @note
 | |
|     NULL values are possible even within a registered range.
 | |
| 
 | |
|   @param nr Errno
 | |
| 
 | |
|   @retval NULL  if no message is registered for this error number
 | |
|   @retval str   C-string
 | |
| */
 | |
| 
 | |
| const char *my_get_err_msg(uint nr)
 | |
| {
 | |
|   const char *format;
 | |
|   struct my_err_head *meh_p;
 | |
| 
 | |
|   /* Search for the range this error is in. */
 | |
|   for (meh_p= my_errmsgs_list; meh_p; meh_p= meh_p->meh_next)
 | |
|     if (nr <= meh_p->meh_last)
 | |
|       break;
 | |
| 
 | |
|   /*
 | |
|     If we found the range this error number is in, get the format string.
 | |
|     If the string is empty, or a NULL pointer, or if we're out of return,
 | |
|     we return NULL.
 | |
|   */
 | |
|   if (!(format= (meh_p && (nr >= meh_p->meh_first)) ?
 | |
|                 meh_p->get_errmsgs(nr)[nr - meh_p->meh_first] : NULL) ||
 | |
|       !*format)
 | |
|     return NULL;
 | |
| 
 | |
|   return format;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Fill in and print a previously registered error message.
 | |
| 
 | |
|   @note
 | |
|     Goes through the (sole) function registered in error_handler_hook
 | |
| 
 | |
|   @param nr        error number
 | |
|   @param MyFlags   Flags
 | |
|   @param ...       variable list matching that error format string
 | |
| */
 | |
| 
 | |
| void my_error(uint nr, myf MyFlags, ...)
 | |
| {
 | |
|   const char *format;
 | |
|   va_list args;
 | |
|   char ebuff[ERRMSGSIZE];
 | |
|   DBUG_ENTER("my_error");
 | |
|   DBUG_PRINT("my", ("nr: %d  MyFlags: %lu  errno: %d", nr, MyFlags, errno));
 | |
|   if (!(format = my_get_err_msg(nr)))
 | |
|     (void) my_snprintf(ebuff, sizeof(ebuff), "Unknown error %d", nr);
 | |
|   else
 | |
|   {
 | |
|     va_start(args,MyFlags);
 | |
|     (void) my_vsnprintf_ex(&my_charset_utf8mb3_general_ci, ebuff,
 | |
|                            sizeof(ebuff), format, args);
 | |
|     va_end(args);
 | |
|   }
 | |
|   (*error_handler_hook)(nr, ebuff, MyFlags);
 | |
|   DBUG_VOID_RETURN;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Print an error message.
 | |
| 
 | |
|   @note
 | |
|     Just like my_error, but for cases when the error message is not ER(error)
 | |
| 
 | |
|   @param error     error number
 | |
|   @param format    format string
 | |
|   @param MyFlags   Flags
 | |
|   @param ...       variable list matching that error format string
 | |
| */
 | |
| 
 | |
| void my_printf_error(uint error, const char *format, myf MyFlags, ...)
 | |
| {
 | |
|   va_list args;
 | |
|   char ebuff[ERRMSGSIZE];
 | |
|   DBUG_ENTER("my_printf_error");
 | |
|   DBUG_PRINT("my", ("nr: %d  MyFlags: %lu  errno: %d  format: %s",
 | |
| 		    error, MyFlags, errno, format));
 | |
| 
 | |
|   va_start(args,MyFlags);
 | |
|   (void) my_vsnprintf_ex(&my_charset_utf8mb3_general_ci, ebuff,
 | |
|                          sizeof(ebuff), format, args);
 | |
|   va_end(args);
 | |
|   (*error_handler_hook)(error, ebuff, MyFlags);
 | |
|   DBUG_VOID_RETURN;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Print an error message.
 | |
| 
 | |
|   @note
 | |
|     Goes through the (sole) function registered in error_handler_hook
 | |
| 
 | |
|   @param error     error number
 | |
|   @param format    format string
 | |
|   @param MyFlags   Flags
 | |
|   @param ap        variable list matching that error format string
 | |
| */
 | |
| 
 | |
| void my_printv_error(uint error, const char *format, myf MyFlags, va_list ap)
 | |
| {
 | |
|   char ebuff[ERRMSGSIZE];
 | |
|   DBUG_ENTER("my_printv_error");
 | |
|   DBUG_PRINT("my", ("nr: %d  MyFlags: %lu  errno: %d  format: %s",
 | |
| 		    error, MyFlags, errno, format));
 | |
| 
 | |
|   (void) my_vsnprintf(ebuff, sizeof(ebuff), format, ap);
 | |
|   (*error_handler_hook)(error, ebuff, MyFlags);
 | |
|   DBUG_VOID_RETURN;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Print an error message.
 | |
| 
 | |
|   @note
 | |
|     Goes through the (sole) function registered in error_handler_hook
 | |
| 
 | |
|   @param error     error number
 | |
|   @param str       error message
 | |
|   @param MyFlags   Flags
 | |
| */
 | |
| 
 | |
| void my_message(uint error, const char *str, register myf MyFlags)
 | |
| {
 | |
|   (*error_handler_hook)(error, str, MyFlags);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Register error messages for use with my_error().
 | |
| 
 | |
|   @description
 | |
| 
 | |
|     The pointer array is expected to contain addresses to NUL-terminated
 | |
|     C character strings. The array contains (last - first + 1) pointers.
 | |
|     NULL pointers and empty strings ("") are allowed. These will be mapped to
 | |
|     "Unknown error" when my_error() is called with a matching error number.
 | |
|     This function registers the error numbers 'first' to 'last'.
 | |
|     No overlapping with previously registered error numbers is allowed.
 | |
| 
 | |
|   @param   errmsgs  array of pointers to error messages
 | |
|   @param   first    error number of first message in the array
 | |
|   @param   last     error number of last message in the array
 | |
| 
 | |
|   @retval  0        OK
 | |
|   @retval  != 0     Error
 | |
| */
 | |
| 
 | |
| int my_error_register(const char** (*get_errmsgs)(int error), uint first,
 | |
|                       uint last)
 | |
| {
 | |
|   struct my_err_head *meh_p;
 | |
|   struct my_err_head **search_meh_pp;
 | |
| 
 | |
|   /* Allocate a new header structure. */
 | |
|   if (! (meh_p= (struct my_err_head*) my_malloc(key_memory_my_err_head,
 | |
|                                                 sizeof(struct my_err_head),
 | |
|                                                 MYF(MY_WME))))
 | |
|     return 1;
 | |
|   meh_p->get_errmsgs= get_errmsgs;
 | |
|   meh_p->meh_first= first;
 | |
|   meh_p->meh_last= last;
 | |
| 
 | |
|   /* Search for the right position in the list. */
 | |
|   for (search_meh_pp= &my_errmsgs_list;
 | |
|        *search_meh_pp;
 | |
|        search_meh_pp= &(*search_meh_pp)->meh_next)
 | |
|   {
 | |
|     if ((*search_meh_pp)->meh_last > first)
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   /* Error numbers must be unique. No overlapping is allowed. */
 | |
|   if (*search_meh_pp && ((*search_meh_pp)->meh_first <= last))
 | |
|   {
 | |
|     my_free(meh_p);
 | |
|     return 1;
 | |
|   }
 | |
| 
 | |
|   /* Insert header into the chain. */
 | |
|   meh_p->meh_next= *search_meh_pp;
 | |
|   *search_meh_pp= meh_p;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Unregister formerly registered error messages.
 | |
| 
 | |
|   @description
 | |
| 
 | |
|     This function unregisters the error numbers 'first' to 'last'.
 | |
|     These must have been previously registered by my_error_register().
 | |
|     'first' and 'last' must exactly match the registration.
 | |
|     If a matching registration is present, the header is removed from the
 | |
|     list and the pointer to the error messages pointers array is returned.
 | |
|     (The messages themselves are not released here as they may be static.)
 | |
|     Otherwise, NULL is returned.
 | |
| 
 | |
|   @param   first     error number of first message
 | |
|   @param   last      error number of last message
 | |
| 
 | |
|   @retval  NULL      Error, no such number range registered.
 | |
|   @retval  non-NULL  OK, returns address of error messages pointers array.
 | |
| */
 | |
| 
 | |
| my_bool my_error_unregister(uint first, uint last)
 | |
| {
 | |
|   struct my_err_head    *meh_p;
 | |
|   struct my_err_head    **search_meh_pp;
 | |
| 
 | |
|   /* Search for the registration in the list. */
 | |
|   for (search_meh_pp= &my_errmsgs_list;
 | |
|        *search_meh_pp;
 | |
|        search_meh_pp= &(*search_meh_pp)->meh_next)
 | |
|   {
 | |
|     if (((*search_meh_pp)->meh_first == first) &&
 | |
|         ((*search_meh_pp)->meh_last == last))
 | |
|       break;
 | |
|   }
 | |
|   if (! *search_meh_pp)
 | |
|     return TRUE;
 | |
|   
 | |
|   /* Remove header from the chain. */
 | |
|   meh_p= *search_meh_pp;
 | |
|   *search_meh_pp= meh_p->meh_next;
 | |
| 
 | |
|   my_free(meh_p);
 | |
|   
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Unregister all formerly registered error messages.
 | |
| 
 | |
|   @description
 | |
| 
 | |
|     This function unregisters all error numbers that previously have
 | |
|     been previously registered by my_error_register().
 | |
|     All headers are removed from the list; the messages themselves are
 | |
|     not released here as they may be static.
 | |
| */
 | |
| 
 | |
| void my_error_unregister_all(void)
 | |
| {
 | |
|   struct my_err_head *cursor, *saved_next;
 | |
| 
 | |
|   for (cursor= my_errmsgs_globerrs.meh_next; cursor != NULL; cursor= saved_next)
 | |
|   {
 | |
|     /* We need this ptr, but we're about to free its container, so save it. */
 | |
|     saved_next= cursor->meh_next;
 | |
| 
 | |
|     my_free(cursor);
 | |
|   }
 | |
|   my_errmsgs_globerrs.meh_next= NULL;  /* Freed in first iteration above. */
 | |
| 
 | |
|   my_errmsgs_list= &my_errmsgs_globerrs;
 | |
| }
 | 
