Skip to content

File error_manager.h

File List > base > error_manager.h

Go to the documentation of this file

/*
 * Copyright 2008 Search Solution Corporation
 * Copyright 2016 CUBRID Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */


/*
 * error_manager.h - Error module (both client & server)
 */

#ifndef _ERROR_MANAGER_H_
#define _ERROR_MANAGER_H_

#ident "$Id$"

#include "config.h"

#include <stdarg.h>
#include <assert.h>
#if defined (SERVER_MODE)
#if defined (WINDOWS)
#include <winsock2.h>
#include <windows.h>
#else /* WINDOWS */
#include <pthread.h>
#endif /* WINDOWS */
#endif /* SERVER_MODE */

#include "error_code.h"

#define ARG_FILE_LINE           __FILE__, __LINE__
#define ARG_FILE_LINE_FUNC      __FILE__, __LINE__, __func__
#define NULL_LEVEL              0

/* Shorthand for simple warnings and errors */
#define ERROR0(error, code) \
  do \
    { \
      error = code; \
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, code, 0); \
    } \
  while (0)

#define ERROR1(error, code, arg1) \
  do \
    { \
      error = code; \
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, code, 1, arg1); \
    } \
  while (0)

#define ERROR2(error, code, arg1, arg2) \
  do \
    { \
      error = code; \
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, code, 2, arg1, arg2); \
    } \
  while (0)

#define ERROR3(error, code, arg1, arg2, arg3) \
  do \
    { \
      error = code; \
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, code, 3, arg1, arg2, arg3); \
    } \
  while (0)

#define ERROR4(error, code, arg1, arg2, arg3, arg4) \
  do \
    { \
      error = code; \
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, code, 4, arg1, arg2, arg3, arg4); \
    } \
  while (0)

#define ERROR5(error, code, arg1, arg2, arg3, arg4, arg5) \
  do \
    { \
      error = code; \
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, code, 5, arg1, arg2, arg3, arg4, arg5); \
    } \
  while (0)

#define ERROR_SET_WARNING(error, code) \
  do \
    { \
      (error) = (code); \
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, (code), 0); \
    } \
  while (0)

#define ERROR_SET_WARNING_1ARG(error, code, arg1) \
  do \
    { \
      (error) = (code); \
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, (code), 1, (arg1)); \
    } \
  while (0)

#define ERROR_SET_WARNING_2ARGS(error, code, arg1, arg2) \
  do \
    { \
      (error) = (code); \
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, (code), 2, (arg1), (arg2)); \
    } \
  while (0)

#define ERROR_SET_WARNING_3ARGS(error, code, arg1, arg2, arg3) \
  do \
    { \
      (error) = (code); \
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, (code), 3, (arg1), (arg2), (arg3)); \
    } \
  while (0)

#define ERROR_SET_WARNING_4ARGS(error, code, arg1, arg2, arg3, arg4) \
  do \
    { \
      (error) = (code); \
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, (code), 4, (arg1), (arg2), (arg3), (arg4)); \
    } \
  while (0)

#define ERROR_SET_ERROR(error, code) \
  do \
    { \
      (error) = (code); \
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, (code), 0); \
    } \
  while (0)

#define ERROR_SET_ERROR_1ARG(error, code, arg1) \
  do \
    { \
      (error) = (code); \
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, (code), 1, (arg1)); \
    } \
  while (0)

#define ERROR_SET_ERROR_2ARGS(error, code, arg1, arg2) \
  do \
    { \
      (error) = (code); \
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, (code), 2, (arg1), (arg2)); \
    } \
  while (0)

#define ERROR_SET_ERROR_3ARGS(error, code, arg1, arg2, arg3) \
  do \
    { \
      (error) = (code); \
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, (code), 3, (arg1), (arg2), (arg3)); \
    } \
  while (0)

#define ERROR_SET_ERROR_4ARGS(error, code, arg1, arg2, arg3, arg4) \
  do \
    { \
      (error) = (code); \
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, (code), 4, (arg1), (arg2), (arg3), (arg4)); \
    } \
  while (0)

#define ERROR_SET_ERROR_ONLY(code) \
  do \
    { \
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, (code), 0); \
    } \
  while (0)

/*
 * custom assert macro for release mode
 */
#if defined(NDEBUG)
#define STRINGIZE(s) #s
#define assert_release(e) \
  ((e) ? (void) 0  : er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_FAILED_ASSERTION, 1, STRINGIZE (e)))
#define assert_release_notify(e) assert_release(e)
#define assert_release_error(e) \
  ((e) ? (void) 0  : er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_FAILED_ASSERTION, 1, STRINGIZE (e)))
#else
#define assert_release(e) assert(e)
#define assert_release_notify(e) assert_release(e)
#define assert_release_error(e) assert(e)
#endif

enum er_exit_ask
{
  ER_NEVER_EXIT = 0,
  ER_EXIT_ASK = 1,
  ER_EXIT_DONT_ASK = 2,
  ER_ABORT = 3,
  ER_EXIT_DEFAULT = ER_NEVER_EXIT
};

enum er_print_option
{
  ER_DO_NOT_PRINT = 0,
  ER_PRINT_TO_CONSOLE = 1
};

/* do not change the order of this enumeration; see er_Fnlog[] */
enum er_severity
{
  ER_FATAL_ERROR_SEVERITY, ER_ERROR_SEVERITY,
  ER_SYNTAX_ERROR_SEVERITY, ER_WARNING_SEVERITY,
  ER_NOTIFICATION_SEVERITY,
  ER_MAX_SEVERITY = ER_NOTIFICATION_SEVERITY
};

enum er_level
{
  ER_LEVEL_SYSTEM, ER_LEVEL_APPLICATION
};

typedef enum er_final_code
{
  ER_THREAD_FINAL = 0,
  ER_ALL_FINAL = 1
} ER_FINAL_CODE;

typedef void (*PTR_FNERLOG) (int err_id);

#define ER_IS_LOCK_TIMEOUT_ERROR(err) \
  ((err) == ER_LK_UNILATERALLY_ABORTED \
   || (err) == ER_LK_OBJECT_TIMEOUT_SIMPLE_MSG \
   || (err) == ER_LK_OBJECT_TIMEOUT_CLASS_MSG \
   || (err) == ER_LK_OBJECT_TIMEOUT_CLASSOF_MSG \
   || (err) == ER_LK_OBJECT_DL_TIMEOUT_SIMPLE_MSG \
   || (err) == ER_LK_OBJECT_DL_TIMEOUT_CLASS_MSG \
   || (err) == ER_LK_OBJECT_DL_TIMEOUT_CLASSOF_MSG)

#define ER_IS_ABORTED_DUE_TO_DEADLOCK(err) \
  ((err) == ER_LK_UNILATERALLY_ABORTED \
   || (err) == ER_TM_SERVER_DOWN_UNILATERALLY_ABORTED)

#define ER_IS_SERVER_DOWN_ERROR(err) \
  ((err) == ER_TM_SERVER_DOWN_UNILATERALLY_ABORTED \
   || (err) == ER_NET_SERVER_CRASHED \
   || (err) == ER_OBJ_NO_CONNECT \
   || (err) == ER_BO_CONNECT_FAILED \
   || (err) == ER_NET_CANT_CONNECT_SERVER)

/* Macros to assert that error is set. */
#define ASSERT_ERROR() \
  assert (er_errid () != NO_ERROR)
/* This macro will also make sure the error_code to be returned is not
 * NO_ERROR.
 */
#define ASSERT_ERROR_AND_SET(error_code) \
  do \
    { \
      error_code = er_errid (); \
      if (error_code == NO_ERROR) \
    { \
      /* Error should be set */ \
      assert (false); \
      error_code = ER_FAILED; \
    } \
    } while (false)
/* Macro that checks no error was set. */
#define ASSERT_NO_ERROR() \
  assert (er_errid () == NO_ERROR);

#define ASSERT_NO_ERROR_OR_INTERRUPTED() \
  assert (er_errid () == NO_ERROR || er_errid () == ER_INTERRUPTED);

#ifdef __cplusplus
extern "C"
{
#endif

  extern const char *er_get_msglog_filename (void);
  extern int er_init (const char *msglog_filename, int exit_ask);
  extern bool er_is_initialized (void);
  extern void er_set_print_property (int print_console);
  extern void er_final (ER_FINAL_CODE do_global_final);
  extern void er_clear (void);
  extern void er_set (int severity, const char *file_name, const int line_no, int err_id, int num_args, ...);
  extern void er_set_with_file (int severity, const char *file_name, const int line_no, int err_id, FILE * fp,
                int num_args, ...);
  extern void er_set_with_oserror (int severity, const char *file_name, const int line_no, int err_id, int num_args,
                   ...);
  typedef void (*er_log_handler_t) (unsigned int);
  extern er_log_handler_t er_register_log_handler (er_log_handler_t f);

#if !defined (WINDOWS) && defined (SERVER_MODE)
  extern void er_file_create_link_to_current_log_file (const char *er_file_path, const char *suffix);
#endif              /* !WINDOWS && SERVER_MODE */

  extern int er_errid (void);
  extern int er_errid_if_has_error (void);
  extern int er_get_severity (void);
  extern const char *er_msg (void);
  extern void er_all (int *err_id, int *severity, int *nlevels, int *line_no, const char **file_name, const char **msg);

  extern void _er_log_debug (const char *file_name, const int line_no, const char *fmt, ...);
#define er_log_debug(...) if (prm_get_bool_value (PRM_ID_ER_LOG_DEBUG)) _er_log_debug(__VA_ARGS__)

  extern char *er_get_ermsg_from_area_error (char *buffer);
  extern char *er_get_area_error (char *buffer, int *length);
  extern int er_set_area_error (char *server_area);
  extern void er_stack_push (void);
  extern void er_stack_push_if_exists (void);
  extern void er_stack_pop (void);
  extern void er_stack_pop_and_keep_error (void);
  extern void er_restore_last_error (void);
  extern void er_stack_clearall (void);
  extern void *db_default_malloc_handler (void *arg, const char *filename, int line_no, size_t size);
  extern int er_event_restart (void);
  extern void er_clearid (void);
  extern void er_setid (int err_id);

  extern bool er_has_error (void);
  extern void er_print_callstack (const char *file_name, const int line_no, const char *fmt, ...);
#if defined (CS_MODE)
  extern void er_set_ignore_uninit (bool ignore);
#endif
  extern void er_print_crash_callstack (int sig);

#ifdef __cplusplus
}
#endif

#ifdef __cplusplus

#if defined (SERVER_MODE) || !defined (WINDOWS)
// not dll linkage
#define CUBERR_MANAGER_DLL
#elif defined (CS_MODE) || defined (SA_MODE)
// Windows CS_MODE or SA_MODE - export
#define CUBERR_MANAGER_DLL __declspec( dllexport )
#else               // Windows, not CS_MODE and not SA_MODE
// import
#define CUBERR_MANAGER_DLL __declspec( dllimport )
#endif              // Windows, not CS_MODE and not SA_MODE

/* *INDENT-OFF* */
namespace cuberr
{
  class CUBERR_MANAGER_DLL manager
  {
  public:
    manager (const char * msg_file, er_exit_ask exit_arg);
    ~manager (void);
  };
} // namespace cuberr
/* *INDENT-ON* */

// to use in C units instead of er_init; makes sure that er_final is called before exiting scope
// NOTE - cuberr_manager variable is created. it may cause naming conflicts
// NOTE - if used after jumps, expect "crosses initialization" errors
#define ER_SAFE_INIT(msg_file, exit_arg) cuberr::manager cuberr_manager (msg_file, exit_arg)
#endif              // c++

#endif              /* _ERROR_MANAGER_H_ */