Skip to content

File boot_cl.c

File List > cubrid > src > transaction > boot_cl.c

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.
 *
 */

/*
 * boot_cl.c - Boot management in the client
 */

#ident "$Id$"

#include "config.h"

#include <stdio.h>
#include <string.h>
#if !defined(WINDOWS)
#include <sys/time.h>
#endif /* WINDOWS */

#if !defined(WINDOWS)
#include <stdio.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#else
#include <winsock2.h>
#endif /* !WINDOWS */

#include <assert.h>

#include "porting.h"
#if !defined(HPUX)
#include "util_func.h"
#endif /* !HPUX */
#include "boot_cl.h"
#include "memory_alloc.h"
#include "area_alloc.h"
#include "storage_common.h"
#include "oid.h"
#include "error_manager.h"
#include "authenticate.h"
#include "work_space.h"
#include "schema_manager.h"
#include "trigger_manager.h"
#include "db.h"
#if !defined(WINDOWS)
#include "dynamic_load.h"
#endif /* !WINDOWS */
#include "transaction_cl.h"
#include "log_comm.h"
#include "server_interface.h"
#include "release_string.h"
#include "system_parameter.h"
#include "locator_cl.h"
#include "databases_file.h"
#include "db_query.h"
#include "language_support.h"
#include "message_catalog.h"
#include "parser.h"
#include "perf_monitor.h"
#include "set_object.h"
#include "cnv.h"
#include "environment_variable.h"
#include "locator.h"
#include "transform.h"
#include "jansson.h"
#include "jsp_cl.h"
#include "client_support.h"
#include "es.h"
#include "tsc_timer.h"
#include "show_meta.h"
#include "tz_support.h"
#include "dbtype.h"
#include "method_callback.hpp"
#include "object_primitive.h"
#include "connection_globals.h"
#include "host_lookup.h"
#include "schema_system_catalog.hpp"
#include "sp_catalog.hpp"

#include "authenticate_context.hpp"

#include <signal.h>

#if defined(CS_MODE)
#include "network.h"
#endif /* CS_MODE */
#include "network_interface_cl.h"

#if defined(WINDOWS)
#include "wintcp.h"
#else /* WINDOWS */
#include "tcp.h"
#endif /* WINDOWS */

#if defined (SUPPRESS_STRLEN_WARNING)
#define strlen(s1)  ((int) strlen(s1))
#endif /* defined (SUPPRESS_STRLEN_WARNING) */

#if defined(SA_MODE)
#include "catalog_class.h"
#endif /* SA_MODE */

#define BOOT_FORMAT_MAX_LENGTH 500

/* for optional capability check */
#define BOOT_NO_OPT_CAP                 0
#define BOOT_CHECK_HA_DELAY_CAP         NET_CAP_HA_REPL_DELAY

static BOOT_SERVER_CREDENTIAL boot_Server_credential = {
  /* db_full_name */ NULL, /* host_name */ NULL, /* lob_path */ NULL,
  /* process_id */ -1,
  /* root_class_oid */ {NULL_PAGEID, NULL_SLOTID, NULL_VOLID},
  /* root_class_hfid */ {{NULL_FILEID, NULL_VOLID}, NULL_PAGEID},
  /* data page_size */ -1, /* log page_size */ -1,
  /* disk_compatibility */ 0.0,
  /* ha_server_state */ HA_SERVER_STATE_NA,
  /* server_session_key */ {(char) 0xFF, (char) 0xFF, (char) 0xFF, (char) 0xFF, (char) 0xFF, (char) 0xFF, (char) 0xFF,
                (char) 0xFF},
  INTL_CODESET_NONE,
  NULL
};

static const char *boot_Client_no_user_string = "(nouser)";
static const char *boot_Client_id_unknown_string = "(unknown)";

static char boot_Client_id_buffer[L_cuserid + 1];
static char boot_Db_path_buf[PATH_MAX];
static char boot_Log_path_buf[PATH_MAX];
static char boot_Lob_path_buf[PATH_MAX];
static char boot_Db_host_buf[CUB_MAXHOSTNAMELEN + 1];

/* Volume assigned for new files/objects (e.g., heap files) */
VOLID boot_User_volid = 0;  /* todo: boot_User_volid looks deprecated */
#if defined(CS_MODE)
/* Server host connected */
char boot_Host_connected[CUB_MAXHOSTNAMELEN] = "";
#endif /* CS_MODE */
char boot_Host_name[CUB_MAXHOSTNAMELEN] = "";
char boot_Ip_address[16] = { 0 };

static char boot_Volume_label[PATH_MAX] = " ";
static bool boot_Is_client_all_final = true;
static bool boot_Set_client_at_exit = false;
static int boot_Process_id = -1;

static int boot_client (int tran_index, int lock_wait, TRAN_ISOLATION tran_isolation);
static int install_system_metadata (void);
static void boot_shutdown_client_at_exit (void);
#if defined(CS_MODE)
static int boot_client_initialize_css (DB_INFO * db, int client_type, bool check_capabilities, int opt_cap,
                       bool discriminative, int connect_order, bool is_preferred_host);
#endif /* CS_MODE */
#if defined(CS_MODE)
static int boot_check_locales (BOOT_CLIENT_CREDENTIAL * client_credential);
#endif /* CS_MODE */
#if defined(CS_MODE)
static int boot_check_timezone_checksum (BOOT_CLIENT_CREDENTIAL * client_credential);
#endif
static int boot_client_find_and_cache_class_oids (void);

/*
 * boot_client () -
 *
 * return :
 *
 *   tran_index(in) : transaction index
 *   lock_wait(in) :
 *   tran_isolation(in):
 *
 * Note: macros that find if the cubrid client is restarted
 */
static int
boot_client (int tran_index, int lock_wait, TRAN_ISOLATION tran_isolation)
{
  tran_cache_tran_settings (tran_index, lock_wait, tran_isolation);

  if (boot_Set_client_at_exit)
    {
      return NO_ERROR;
    }

  boot_Set_client_at_exit = true;
  boot_Process_id = getpid ();
  atexit (boot_shutdown_client_at_exit);

  return NO_ERROR;
}

static int
install_system_metadata (void)
{
  int error = NO_ERROR;

  /* Create system classes such as the root and authorization classes */
  au_init ();
  error = au_install ();
  if (error != NO_ERROR)
    {
      return error;
    }
  /* Create authorization classes and enable authorization */
  error = au_start ();
  if (error != NO_ERROR)
    {
      return error;
    }

  tr_init ();
  catcls_init ();
  error = catcls_install ();
  if (error != NO_ERROR)
    {
      return error;
    }

  return NO_ERROR;
}

/*
 * boot_initialize_client () -
 *
 * returns : NO_ERROR if all OK, ER_ status otherwise
 *
 *   client_credential(in): Contains database access information such as :
 *                          database name, user name and password, client type
 *   db_path_info(in) : Directory where the database is created. It allows you
 *                      to specify the exact pathname of a directory in which
  *                     to create the new database.
 *   db_overwrite(in) : Wheater to overwrite the database if it already exist.
 *   file_addmore_vols(in): More volumes are created during the initialization
 *                      process.
 *   npages(in)       : Total number of pages to allocate for the database.
 *   db_desired_pagesize(in): Desired pagesize for the new database.
 *                      The given size must be power of 2 and greater or
 *                      equal than 512.
 *   log_npages(in)   : Number of log pages. If log_npages <=0, default value
 *                      of system parameter is used.
 *   db_desired_log_page_size(in):
 *   lang_charset(in): language and charset to set on DB
 *
 * Note:
 *              The first step of any CUBRID application is to initialize a
 *              database. A database is composed of data volumes (or Unix file
 *              system files), database backup files, and log files. A data
 *              volume contains information on attributes, classes, indexes,
 *              and objects created in the database. A database backup is a
 *              fuzzy snapshot of the entire database. The backup is fuzzy
 *              since it can be taken online when other transactions are
 *              updating the database. The logs contain records that reflect
 *              changes to the database. The log and backup files are used by
 *              the system to recover committed and uncommitted transactions
 *              in the event of system and media crashes. Logs are also used
 *              to support user-initiated rollbacks. This function also
 *              initializes the database with built-in CUBRID classes.
 *
 *              The rest of this function is identical to the restart. The
 *              transaction for the current client session is automatically
 *              started.
 */
int
boot_initialize_client (BOOT_CLIENT_CREDENTIAL * client_credential, BOOT_DB_PATH_INFO * db_path_info, bool db_overwrite,
            const char *file_addmore_vols, DKNPAGES npages, PGLENGTH db_desired_pagesize,
            DKNPAGES log_npages, PGLENGTH db_desired_log_page_size, const char *lang_charset)
{
  OID rootclass_oid;        /* Oid of root class */
  HFID rootclass_hfid;      /* Heap for classes */
  int tran_index;       /* Assigned transaction index */
  TRAN_ISOLATION tran_isolation;    /* Desired client Isolation level */
  int tran_lock_wait_msecs; /* Default lock waiting */
  unsigned int length;
  int error_code = NO_ERROR;
  DB_INFO *db = NULL;
#if !defined(WINDOWS)
  bool dl_initialized = false;
#endif /* !WINDOWS */
  const char *hosts[2];
#if defined (CS_MODE)
  char format[BOOT_FORMAT_MAX_LENGTH];
#endif

  assert (client_credential != NULL);
  assert (db_path_info != NULL);

  /* If the client is restarted, shutdown the client */
  if (BOOT_IS_CLIENT_RESTARTED ())
    {
      (void) boot_shutdown_client (true);
    }

  if (!boot_Is_client_all_final)
    {
      boot_client_all_finalize (ALL_FINALIZATION);
    }

#if defined(WINDOWS)
  /* set up the WINDOWS stream emulations */
  pc_init ();
#endif /* WINDOWS */

  /*
   * initialize language parameters  */
  if (lang_init () != NO_ERROR)
    {
      if (er_errid () == NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOC_INIT, 1, "Failed to initialize language module");
    }
      error_code = ER_LOC_INIT;
      goto error_exit;
    }

  if (lang_set_charset_lang (lang_charset) != NO_ERROR)
    {
      error_code = ER_LOC_INIT;
      goto error_exit;
    }

  /* database name must be specified */
  if (client_credential->db_name.empty ())
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_UNKNOWN_DATABASE, 1, "(null)");
      error_code = ER_BO_UNKNOWN_DATABASE;
      goto error_exit;
    }

  /* open the system message catalog, before prm_ ? */
  if (msgcat_init () != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANNOT_ACCESS_MESSAGE_CATALOG, 0);
      error_code = ER_BO_CANNOT_ACCESS_MESSAGE_CATALOG;
      goto error_exit;
    }

  /* initialize system parameters */
  if (sysprm_load_and_init_client (client_credential->get_db_name (), NULL) != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANT_LOAD_SYSPRM, 0);
      error_code = ER_BO_CANT_LOAD_SYSPRM;
      goto error_exit;
    }

  /* initialize the "areas" memory manager */
  area_init ();
  locator_initialize_areas ();

  (void) db_set_page_size (db_desired_pagesize, db_desired_log_page_size);

  /* If db_path and/or log_path are NULL find the defaults */

  if (db_path_info->db_path == NULL)
    {
      db_path_info->db_path = getcwd (boot_Db_path_buf, PATH_MAX);
      if (db_path_info->db_path == NULL)
    {
      er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CWD_FAIL, 0);
      error_code = ER_BO_CWD_FAIL;
      goto error_exit;
    }
    }
  if (db_path_info->log_path == NULL)
    {
      /* assign the data volume directory */
      strcpy (boot_Log_path_buf, db_path_info->db_path);
      db_path_info->log_path = boot_Log_path_buf;
    }
  if (db_path_info->lob_path == NULL)
    {
      /* assign the data volume directory */
      snprintf (boot_Lob_path_buf, sizeof (boot_Lob_path_buf), "%s%s%clob", LOB_PATH_DEFAULT_PREFIX,
        db_path_info->db_path, PATH_SEPARATOR);
      db_path_info->lob_path = boot_Lob_path_buf;
    }
  else
    {
      ES_TYPE es_type = es_get_type (db_path_info->lob_path);

      switch (es_type)
    {
    case ES_NONE:
      /* prepend default prefix */
      snprintf (boot_Lob_path_buf, sizeof (boot_Lob_path_buf), "%s%s", LOB_PATH_DEFAULT_PREFIX,
            db_path_info->lob_path);
      db_path_info->lob_path = boot_Lob_path_buf;
      break;
#if !defined (CUBRID_OWFS)
    case ES_OWFS:
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_INVALID_PATH, 1, db_path_info->lob_path);
      error_code = ER_ES_INVALID_PATH;
      goto error_exit;
#endif /* !CUBRID_OWFS */
    default:
      break;
    }
    }

  /* make sure that the full path for the database is not too long */
  length = (unsigned int) (client_credential->db_name.length () + strlen (db_path_info->db_path) + 2);
  if (length > (unsigned) PATH_MAX)
    {
      /* db_path + db_name is too long */
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_FULL_DATABASE_NAME_IS_TOO_LONG, 3, db_path_info->db_path,
          client_credential->get_db_name (), length, PATH_MAX);

      error_code = ER_BO_FULL_DATABASE_NAME_IS_TOO_LONG;
      goto error_exit;
    }

  /* If a host was not given, assume the current host */
  if (db_path_info->db_host == NULL)
    {
      strcpy (boot_Db_host_buf, "localhost");
      db_path_info->db_host = boot_Db_host_buf;
    }

  /* make new DB_INFO */
  hosts[0] = db_path_info->db_host;
  hosts[1] = NULL;
  db =
    cfg_new_db (client_credential->get_db_name (), db_path_info->db_path, db_path_info->log_path,
        db_path_info->lob_path, hosts);
  if (db == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_UNKNOWN_DATABASE, 1, client_credential->get_db_name ());
      error_code = ER_BO_UNKNOWN_DATABASE;
      goto error_exit;
    }

  /* Get the absolute path name */
  COMPOSE_FULL_NAME (boot_Volume_label, sizeof (boot_Volume_label), db_path_info->db_path,
             client_credential->get_db_name ());

  er_clear ();

  /* Get the user name */
  if (client_credential->db_user.empty ())
    {
      char *user_name = strdup (Au_user_name);
      int upper_case_name_size;
      char *upper_case_name;

      if (user_name != NULL)
    {
      upper_case_name_size = intl_identifier_upper_string_size (user_name);
      upper_case_name = (char *) malloc (upper_case_name_size + 1);
      if (upper_case_name == NULL)
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
              (size_t) (upper_case_name_size + 1));
        }
      else
        {
          intl_identifier_upper (user_name, upper_case_name);
          client_credential->db_user = upper_case_name;
        }
      free_and_init (user_name);
    }
      upper_case_name = NULL;

      if (client_credential->db_user.empty ())
    {
      client_credential->db_user = boot_Client_no_user_string;
    }
    }
  /* Get the login name, host, and process identifier */
  if (client_credential->login_name.empty ())
    {
      if (getuserid (boot_Client_id_buffer, L_cuserid) != (char *) NULL)
    {
      client_credential->login_name = boot_Client_id_buffer;
    }
      else
    {
      client_credential->login_name = boot_Client_id_unknown_string;
    }
    }

  if (client_credential->host_name.empty ())
    {
      client_credential->host_name = boot_get_host_name ();
    }

  /*
   * Initialize the dynamic loader. Don't care about failures. If dynamic
   * loader fails, methods will fail when they are invoked
   */
#if !defined(WINDOWS)
#if !defined (SOLARIS) && !defined(LINUX) && !defined(AIX)
  (void) dl_initiate_module (client_credential->get_program_name ());
#else /* !SOLARIS && !LINUX && !AIX */
  (void) dl_initiate_module ();
#endif /* !SOLARIS && !LINUX && !AIX */
  dl_initialized = true;
#endif /* !WINDOWS */

#if defined(CS_MODE)
  /* Initialize the communication subsystem */
  error_code =
    boot_client_initialize_css (db, client_credential->client_type, false, BOOT_NO_OPT_CAP, false,
                DB_CONNECT_ORDER_SEQ, false);
  if (error_code != NO_ERROR)
    {
      goto error_exit;
    }
#endif /* CS_MODE */
  boot_User_volid = 0;
  tran_isolation = (TRAN_ISOLATION) prm_get_integer_value (PRM_ID_LOG_ISOLATION_LEVEL);
  tran_lock_wait_msecs = prm_get_integer_value (PRM_ID_LK_TIMEOUT_SECS);

  /* this must be done before the init_server because recovery steps may need domains. */
  error_code = tp_init ();
  if (error_code != NO_ERROR)
    {
      goto error_exit;
    }

  /* Initialize tsc-timer */
  tsc_init ();

  if (tran_lock_wait_msecs > 0)
    {
      tran_lock_wait_msecs = tran_lock_wait_msecs * 1000;
    }

  error_code = perfmon_initialize (MAX_NTRANS);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error_exit;
    }

  /* Initialize the disk and the server part */
  tran_index =
    boot_initialize_server (client_credential, db_path_info, db_overwrite, file_addmore_vols, npages,
                db_desired_pagesize, log_npages, db_desired_log_page_size, &rootclass_oid, &rootclass_hfid,
                tran_lock_wait_msecs, tran_isolation);

  if (tran_index == NULL_TRAN_INDEX)
    {
      assert (er_errid () != NO_ERROR);
      error_code = er_errid ();
      if (error_code == NO_ERROR)
    {
      error_code = ER_GENERIC_ERROR;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 0);
    }
      goto error_exit;
    }

  // create session
  (void) db_find_or_create_session (client_credential->get_db_user (), client_credential->get_program_name ());

  oid_set_root (&rootclass_oid);
  OID_INIT_TEMPID ();

  error_code = ws_init ();
  if (error_code == NO_ERROR)
    {
      sm_create_root (&rootclass_oid, &rootclass_hfid);
      error_code = install_system_metadata ();
      if (error_code == NO_ERROR)
    {
      error_code = tran_commit (false);
    }

      if (error_code == NO_ERROR)
    {
      error_code = sp_builtin_install ();
    }
    }

  if (error_code != NO_ERROR)
    {
      (void) boot_shutdown_client (false);
    }
  else
    {
      boot_client (tran_index, tran_lock_wait_msecs, tran_isolation);
#if defined (CS_MODE)
      /* print version string */
      strncpy_bufsize (format, msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_GENERAL,
                           MSGCAT_GENERAL_DATABASE_INIT));
      (void) fprintf (stdout, format, rel_name ());
#endif /* CS_MODE */
    }

  if (db != NULL)
    {
      cfg_free_directory (db);
      db = NULL;
    }
  return error_code;

error_exit:
  if (db != NULL)
    {
      cfg_free_directory (db);
      db = NULL;
    }

  if (BOOT_IS_CLIENT_RESTARTED ())
    {
      er_log_debug (ARG_FILE_LINE, "boot_initialize_client: unregister client { tran %d }\n", tm_Tran_index);
      boot_shutdown_client (false);
    }
  else
    {
      if (boot_Server_credential.db_full_name)
    {
      db_private_free_and_init (NULL, boot_Server_credential.db_full_name);
    }
      if (boot_Server_credential.host_name)
    {
      db_private_free_and_init (NULL, boot_Server_credential.host_name);
    }

      showstmt_metadata_final ();
      tran_free_savepoint_list ();
      set_final ();
      tr_final ();
      au_final ();
      sm_final ();
      ws_final ();
      es_final ();
      tp_final ();

#if !defined(WINDOWS)
      if (dl_initialized == true)
    {
      (void) dl_destroy_module ();
      dl_initialized = false;
    }
#endif /* !WINDOWS */

      locator_free_areas ();
      sysprm_final ();
      area_final ();

      lang_final ();
      tz_unload ();
      perfmon_finalize ();

#if defined(WINDOWS)
      pc_final ();
#endif /* WINDOWS */

      memset (&boot_Server_credential, 0, sizeof (boot_Server_credential));
      memset (boot_Server_credential.server_session_key, 0xFF, SERVER_SESSION_KEY_SIZE);
    }

  return error_code;
}

/*
 * boot_restart_client () - restart client
 *
 * returns : NO_ERROR if all OK, ER_ status otherwise
 *
 *   client_credential(in) : Information required to start as client, such as:
 *                           database name, user name and password, client
 *                           type.
 *
 * Note:
 *              An application must restart the database system with the
 *              desired database (the database must have already been created)
 *              before the application start invoking the CUBRID functional
 *              interface. This function restarts the CUBRID client. It also
 *              initializes all client modules for the execution of the client
 *              interface. A transaction for the current client session is
 *              automatically started.
 *
 *              It is very important that the application check for success
 *              of this function before calling any other CUBRID function.
 */

int
boot_restart_client (BOOT_CLIENT_CREDENTIAL * client_credential)
{
  int tran_index;
  TRAN_ISOLATION tran_isolation;
  int tran_lock_wait_msecs;
  TRAN_STATE transtate;
  int error_code = NO_ERROR;
  DB_INFO *db = NULL;
#if !defined(WINDOWS)
  bool dl_initialized = false;
#endif /* !WINDOWS */
  char *ptr;
#if defined(CS_MODE)
  const char *hosts[2];

  char **ha_hosts;
  int num_hosts;
  int i, optional_cap;
  char *ha_node_list = NULL;
  bool check_capabilities;
  bool skip_preferred_hosts = false;
  bool skip_db_info = false;
#endif /* CS_MODE */
  const char *conf_file = NULL;

  assert (client_credential != NULL);

  /* If the client is restarted, shutdown the client */
  if (BOOT_IS_CLIENT_RESTARTED ())
    {
      (void) boot_shutdown_client (true);
    }

  if (!boot_Is_client_all_final)
    {
      boot_client_all_finalize (ALL_FINALIZATION);
    }

#if defined(WINDOWS)
  /* set up the WINDOWS stream emulations */
  pc_init ();
#endif /* WINDOWS */

  /* initialize language parameters */
  if (lang_init () != NO_ERROR)
    {
      if (er_errid () == NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOC_INIT, 1, "Failed to initialize language module");
    }
      return ER_LOC_INIT;
    }

  /* initialize time zone data - optional module */
  if (tz_load () != NO_ERROR)
    {
      if (er_errid () == NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_TZ_LOAD_ERROR, 1, "Failed to initialize timezone module");
    }
      error_code = ER_TZ_LOAD_ERROR;
      goto error;
    }

  /* database name must be specified */
  if (client_credential->get_db_name () == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_UNKNOWN_DATABASE, 1, "(null)");
      error_code = ER_BO_UNKNOWN_DATABASE;
      goto error;
    }

  /* open the system message catalog, before prm_ ? */
  if (msgcat_init () != NO_ERROR)
    {
      error_code = ER_BO_CANNOT_ACCESS_MESSAGE_CATALOG;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 0);
      goto error;
    }

  /* initialize system parameters */
#if defined (CS_MODE)
  if (BOOT_BROKER_CLIENT_TYPE (client_credential->client_type))
    {
      conf_file = getenv ("CUBRID_CONF_FOR_BROKER");
      if (conf_file && access (conf_file, R_OK | F_OK) != 0)
    {
      conf_file = NULL;
    }
#if !defined (NDEBUG)
      _er_log_debug (ARG_FILE_LINE, "conf_for_broker = %s\n", conf_file ? conf_file : "unknown");
#endif
    }
#endif

  if (sysprm_load_and_init_client (client_credential->get_db_name (), conf_file) != NO_ERROR)
    {
      error_code = ER_BO_CANT_LOAD_SYSPRM;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 0);
      goto error;
    }

  // reload with update file name
  if (er_init (prm_get_string_value (PRM_ID_ER_LOG_FILE), prm_get_integer_value (PRM_ID_ER_EXIT_ASK)) != NO_ERROR)
    {
      assert_release (false);
      goto error;
    }

  pr_Enable_string_compression = prm_get_bool_value (PRM_ID_ENABLE_STRING_COMPRESSION);

  /* initialize the "areas" memory manager, requires prm_ */
  area_init ();
  locator_initialize_areas ();

  error_code = perfmon_initialize (1);  /* 1 transaction for SA_MODE */
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

  ptr = (char *) strstr (client_credential->get_db_name (), "@");
  if (ptr == NULL)
    {
      /* Find the location of the database and the log from the database.txt */
      db = cfg_find_db (client_credential->get_db_name ());
#if defined(CS_MODE)
      if (db == NULL)
    {
      /* if not found, use secondary host lists */
      db = cfg_new_db (client_credential->get_db_name (), NULL, NULL, NULL, NULL);
    }

      if (db == NULL
      || (db->num_hosts > 1
          && (BOOT_ADMIN_CLIENT_TYPE (client_credential->client_type)
          || BOOT_LOG_REPLICATOR_TYPE (client_credential->client_type)
          || BOOT_CSQL_CLIENT_TYPE (client_credential->client_type))))
    {
      error_code = ER_NET_NO_EXPLICIT_SERVER_HOST;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 0);
      goto error;
    }
#endif /* CS_MODE */
    }
  else
    {
      /* db_name@host_name */
#if defined(CS_MODE)
      *ptr = '\0';      /* screen 'db@host' */
      if (BOOT_BROKER_AND_DEFAULT_CLIENT_TYPE (client_credential->client_type))
    {
      ha_node_list = ptr + 1;
      ha_hosts = cfg_get_hosts (ha_node_list, &num_hosts, false);

      db = cfg_new_db (client_credential->get_db_name (), NULL, NULL, NULL, (const char **) ha_hosts);

      if (ha_hosts)
        {
          cfg_free_hosts (ha_hosts);
        }
    }
      else
    {
      hosts[0] = ptr + 1;
      hosts[1] = NULL;

      db = cfg_new_db (client_credential->get_db_name (), NULL, NULL, NULL, hosts);
    }
      *ptr = (char) '@';
#else /* CS_MODE */
      error_code = ER_NOT_IN_STANDALONE;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, client_credential->get_db_name ());
      goto error;
#endif /* !CS_MODE */
    }

  if (db == NULL)
    {
      error_code = ER_BO_UNKNOWN_DATABASE;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, client_credential->get_db_name ());
      goto error;
    }

  er_clear ();

  /* Get the user name */
  if (client_credential->db_user.empty ())
    {
      if (au_has_user_name ())
    {
      const char *name = au_get_current_user_name ();   // while establishing a connection, never use db_get_user_name.
      if (name != NULL)
        {
          client_credential->db_user = name;
          ws_free_string (name);
        }
    }
      else
    {
      // default is PUBLIC
      client_credential->db_user = AU_PUBLIC_USER_NAME;
    }
    }
  /* Get the login name, host, and process identifier */
  if (client_credential->login_name.empty ())
    {
      if (getuserid (boot_Client_id_buffer, L_cuserid) != (char *) NULL)
    {
      client_credential->login_name = boot_Client_id_buffer;
    }
      else
    {
      client_credential->login_name = boot_Client_id_unknown_string;
    }
    }
  if (client_credential->host_name.empty ())
    {
      client_credential->host_name = boot_get_host_name ();
    }

  client_credential->process_id = getpid ();

  if (client_credential->client_ip_addr.empty ())
    {
      client_credential->client_ip_addr = boot_get_ip ();
    }

  /*
   * Initialize the dynamic loader. Don't care about failures. If dynamic
   * loader fails, methods will fail when they are invoked
   */
#if !defined(WINDOWS)
#if !defined (SOLARIS) && !defined(LINUX) && !defined(AIX)
  (void) dl_initiate_module (client_credential->get_program_name ());
#else /* !SOLARIS && !LINUX && !AIX */
  (void) dl_initiate_module ();
#endif /* !SOLARIS && !LINUX && !AIX */
  dl_initialized = true;
#endif /* !WINDOWS */

  /* read only mode? */
  if (prm_get_bool_value (PRM_ID_READ_ONLY_MODE) || BOOT_READ_ONLY_CLIENT_TYPE (client_credential->client_type))
    {
      db_disable_modification ();
    }

#if defined(CS_MODE)
  /* Initialize the communication subsystem */
  db_clear_host_status ();

  for (i = 0; i < 2; i++)
    {
      if (BOOT_IS_PREFERRED_HOSTS_SET (client_credential) && skip_preferred_hosts == false)
    {
      char **hosts;
      DB_INFO *tmp_db;

      check_capabilities = true;

      if (i == 0)       /* first */
        {
          optional_cap = BOOT_CHECK_HA_DELAY_CAP;
        }
      else          /* second */
        {
          if (!BOOT_REPLICA_ONLY_BROKER_CLIENT_TYPE (client_credential->client_type)
          && BOOT_NORMAL_CLIENT_TYPE (client_credential->client_type))
        {
          check_capabilities = false;
        }

          optional_cap = BOOT_NO_OPT_CAP;
        }

      hosts = util_split_string (client_credential->preferred_hosts, ":");
      if (hosts == NULL)
        {
          error_code = ER_GENERIC_ERROR;
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 0);
          goto error;
        }

      tmp_db = cfg_new_db (db->name, NULL, NULL, NULL, (const char **) hosts);
      if (tmp_db == NULL)
        {
          util_free_string_array (hosts);
          error_code = ER_BO_UNKNOWN_DATABASE;
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_UNKNOWN_DATABASE, 1, db->name);
          goto error;
        }

      boot_Host_connected[0] = '\0';

      /* connect to preferred hosts in a sequential order even though a user sets CONNECT_ORDER to RANDOM */
      error_code =
        boot_client_initialize_css (tmp_db, client_credential->client_type, check_capabilities,
                    optional_cap, false, DB_CONNECT_ORDER_SEQ, true);

      if (error_code != NO_ERROR)
        {
          if (error_code == ER_NET_SERVER_HAND_SHAKE)
        {
          er_log_debug (ARG_FILE_LINE,
                "boot_restart_client: boot_client_initialize_css () ER_NET_SERVER_HAND_SHAKE\n");

          boot_Host_connected[0] = '\0';
        }
          else
        {
          skip_preferred_hosts = true;
        }
        }

      util_free_string_array (hosts);
      cfg_free_directory (tmp_db);
    }

      if (skip_db_info == true)
    {
      continue;
    }

      if (BOOT_IS_PREFERRED_HOSTS_SET (client_credential) && error_code == NO_ERROR)
    {
      /* connected to any preferred hosts successfully */
      break;
    }
      else if (BOOT_REPLICA_ONLY_BROKER_CLIENT_TYPE (client_credential->client_type)
           || client_credential->client_type == DB_CLIENT_TYPE_SLAVE_ONLY_BROKER)

    {
      check_capabilities = true;
      if (i == 0)       /* first */
        {
          optional_cap = BOOT_CHECK_HA_DELAY_CAP;
        }
      else          /* second */
        {
          optional_cap = BOOT_NO_OPT_CAP;
        }

      error_code =
        boot_client_initialize_css (db, client_credential->client_type, check_capabilities,
                    optional_cap, false, client_credential->connect_order, false);
    }
      else if (BOOT_CSQL_CLIENT_TYPE (client_credential->client_type))
    {
      assert (!BOOT_IS_PREFERRED_HOSTS_SET (client_credential));

      check_capabilities = false;
      optional_cap = BOOT_NO_OPT_CAP;

      error_code =
        boot_client_initialize_css (db, client_credential->client_type, check_capabilities,
                    optional_cap, false, DB_CONNECT_ORDER_SEQ, false);
      break;        /* dont retry */
    }
      else if (BOOT_NORMAL_CLIENT_TYPE (client_credential->client_type))
    {
      if (i == 0)       /* first */
        {
          check_capabilities = true;
          optional_cap = BOOT_CHECK_HA_DELAY_CAP;
        }
      else          /* second */
        {
          check_capabilities = false;
          optional_cap = BOOT_NO_OPT_CAP;
        }

      error_code =
        boot_client_initialize_css (db, client_credential->client_type, check_capabilities,
                    optional_cap, false, client_credential->connect_order, false);

    }
      else
    {
      assert (!BOOT_IS_PREFERRED_HOSTS_SET (client_credential));

      check_capabilities = false;
      optional_cap = BOOT_NO_OPT_CAP;
      error_code =
        boot_client_initialize_css (db, client_credential->client_type, check_capabilities,
                    optional_cap, false, client_credential->connect_order, false);
      break;        /* dont retry */
    }

      if (error_code == NO_ERROR)
    {
      if (BOOT_IS_PREFERRED_HOSTS_SET (client_credential))
        {
          db_set_host_status (boot_Host_connected, DB_HS_NON_PREFFERED_HOSTS);
        }
      break;
    }
      else if (error_code == ER_NET_SERVER_HAND_SHAKE)
    {
      er_log_debug (ARG_FILE_LINE, "boot_restart_client: boot_client_initialize_css () ER_NET_SERVER_HAND_SHAKE\n");
    }
      else
    {
      skip_db_info = true;
    }
    }

  if (error_code != NO_ERROR)
    {
      er_log_debug (ARG_FILE_LINE, "boot_restart_client: boot_client_initialize_css () error %d\n", error_code);
      goto error;
    }

  er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_BO_CONNECTED_TO, 5,
      client_credential->get_program_name (), client_credential->process_id,
      client_credential->get_db_name (), boot_Host_connected, prm_get_integer_value (PRM_ID_TCP_PORT_ID));

  /* tune some client parameters with the value from the server */
  sysprm_tune_client_parameters ();
#else /* CS_MODE */
#if defined(WINDOWS)
  css_windows_startup ();
#endif /* WINDOWS */
#endif /* !CS_MODE */

  /* Free the information about the database */
  cfg_free_directory (db);
  db = NULL;

  /* this must be done before the register_client because recovery steps may need domains. */
  error_code = tp_init ();
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  /* Initialize tsc-timer */
  tsc_init ();

  error_code = ws_init ();
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  /*
   * At this moment, we should use the default isolation level and wait
   * timeout, since the client fetches objects during the restart process.
   * This values are reset at a later point, once the client has been fully
   * restarted.
   */

  tran_isolation = TRAN_DEFAULT_ISOLATION_LEVEL ();

  tran_lock_wait_msecs = TRAN_LOCK_INFINITE_WAIT;

  er_log_debug (ARG_FILE_LINE,
        "boot_restart_client: register client { type %d db %s user %s password %s "
        "program %s login %s host %s pid %d }\n", client_credential->client_type,
        client_credential->get_db_name (), client_credential->get_db_user (),
        client_credential->db_password.empty ()? "(null)" : client_credential->get_db_password (),
        client_credential->get_program_name (),
        client_credential->get_login_name (), client_credential->get_host_name (),
        client_credential->process_id);

  tran_index =
    boot_register_client (client_credential, tran_lock_wait_msecs, tran_isolation, &transtate, &boot_Server_credential);

  if (tran_index == NULL_TRAN_INDEX)
    {
      assert (er_errid () != NO_ERROR);
      error_code = er_errid ();
      goto error;
    }

#if defined(CS_MODE)
  if (lang_set_charset ((INTL_CODESET) boot_Server_credential.db_charset) != NO_ERROR)
    {
      assert (er_errid () != NO_ERROR);
      error_code = er_errid ();
      goto error;
    }
  if (lang_set_language (boot_Server_credential.db_lang) != NO_ERROR)
    {
      assert (er_errid () != NO_ERROR);
      error_code = er_errid ();
      goto error;
    }

  /* Reset the pagesize according to server.. */
  if (db_set_page_size (boot_Server_credential.page_size, boot_Server_credential.log_page_size) != NO_ERROR)
    {
      assert (er_errid () != NO_ERROR);
      error_code = er_errid ();
      goto error;
    }

  /* Reset the disk_level according to server.. */
  if (rel_disk_compatible () != boot_Server_credential.disk_compatibility)
    {
      rel_set_disk_compatible (boot_Server_credential.disk_compatibility);
    }
#endif /* CS_MODE */
  if (sysprm_init_intl_param () != NO_ERROR)
    {
      error_code = er_errid ();
      goto error;
    }

  /* Initialize client modules for execution */
  boot_client (tran_index, tran_lock_wait_msecs, tran_isolation);

  oid_set_root (&boot_Server_credential.root_class_oid);
  OID_INIT_TEMPID ();

  sm_init (&boot_Server_credential.root_class_oid, &boot_Server_credential.root_class_hfid);
  au_init ();           /* initialize authorization globals */

  /* start authorization and make sure the logged in user has access */
  error_code = au_start ();
  if (error_code != NO_ERROR)
    {
      goto error;
    }
  error_code = boot_client_find_and_cache_class_oids ();
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  (void) db_find_or_create_session (client_credential->get_db_user (), client_credential->get_program_name ());

#if defined(CS_MODE)
  error_code = boot_check_locales (client_credential);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  error_code = boot_check_timezone_checksum (client_credential);
  if (error_code != NO_ERROR)
    {
      goto error;
    }
#endif /* CS_MODE */

  tr_init ();           /* initialize trigger manager */

  /* TODO: how about to call es_init() only for normal client? */
  if (boot_Server_credential.lob_path[0] != '\0')
    {
      error_code = es_init (boot_Server_credential.lob_path);
      if (error_code != NO_ERROR)
    {
      goto error;
    }
    }
  else
    {
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_ES_NO_LOB_PATH, 0);
    }
  /* Does not care if was committed/aborted .. */
  (void) tran_commit (false);

  /*
   * If there is a need to change the isolation level and the lock wait,
   * do it at this moment
   */

  tran_isolation = (TRAN_ISOLATION) prm_get_integer_value (PRM_ID_LOG_ISOLATION_LEVEL);
  tran_lock_wait_msecs = prm_get_integer_value (PRM_ID_LK_TIMEOUT_SECS);
  if (tran_isolation != TRAN_DEFAULT_ISOLATION_LEVEL ())
    {
      error_code = tran_reset_isolation (tran_isolation, TM_TRAN_ASYNC_WS ());
      if (error_code != NO_ERROR)
    {
      goto error;
    }
    }
  if (tran_lock_wait_msecs >= 0)
    {
      (void) tran_reset_wait_times (tran_lock_wait_msecs * 1000);
    }

  error_code = showstmt_metadata_init ();
  if (error_code != NO_ERROR)
    {
      goto error;
    }
  json_set_alloc_funcs (malloc, free);

  return error_code;

error:

  /* Protect against falsely returning NO_ERROR to caller */
  if (error_code == NO_ERROR)
    {
      error_code = ER_GENERIC_ERROR;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 0);
    }

  if (db != NULL)
    {
      cfg_free_directory (db);
    }

  if (BOOT_IS_CLIENT_RESTARTED ())
    {
      er_log_debug (ARG_FILE_LINE, "boot_restart_client: unregister client { tran %d }\n", tm_Tran_index);
      boot_shutdown_client (false);
    }
  else
    {
      if (boot_Server_credential.db_full_name)
    {
      db_private_free_and_init (NULL, boot_Server_credential.db_full_name);
    }
      if (boot_Server_credential.host_name)
    {
      db_private_free_and_init (NULL, boot_Server_credential.host_name);
    }

      showstmt_metadata_final ();
      tran_free_savepoint_list ();
      set_final ();
      tr_final ();
      au_final ();
      sm_final ();
      ws_final ();
      es_final ();
      tp_final ();

#if !defined(WINDOWS)
      if (dl_initialized == true)
    {
      (void) dl_destroy_module ();
      dl_initialized = false;
    }
#endif /* !WINDOWS */

      locator_free_areas ();
      sysprm_final ();
      area_final ();

      lang_final ();
      tz_unload ();

#if defined(WINDOWS)
      pc_final ();
#endif /* WINDOWS */

      memset (&boot_Server_credential, 0, sizeof (boot_Server_credential));
      memset (boot_Server_credential.server_session_key, 0xFF, SERVER_SESSION_KEY_SIZE);
    }

  return error_code;
}

/*
 * boot_shutdown_client () - shutdown client
 *
 * returns : NO_ERROR if all OK, ER_ status otherwise
 *
 *   is_er_final(in) :
 *
 * Note:
 *              This function should be called before the CUBRID
 *              application is finished. This function will notify the
 *              recovery manager that the application has finished and will
 *              terminate all client modules (e.g., allocation of memory is
 *              deallocated).If there are active transactions, they are either
 *              committed or aborted according to the commit_on_shutdown
 *              system parameter.
 */

int
boot_shutdown_client (bool is_er_final)
{
  if (BOOT_IS_CLIENT_RESTARTED ())
    {
      /*
       * wait for other server request to finish.
       * if db_shutdown() is called by signal handler or atexit handler,
       * the server request may be running.
       */
      tran_wait_server_active_trans ();

      /*
       * Either Abort or commit the current transaction depending upon the value
       * of the commit_on_shutdown system parameter.
       */
      if (tran_is_active_and_has_updated ())
    {
      if (prm_get_bool_value (PRM_ID_COMMIT_ON_SHUTDOWN) != false)
        {
          (void) tran_commit (false);
        }
      else
        {
          (void) tran_abort ();
        }
    }

      /*
       * Make sure that we are still up. For example, if the server died, we do
       * not need to call the following stuff any longer.
       */

      if (BOOT_IS_CLIENT_RESTARTED ())
    {
      (void) boot_unregister_client (tm_Tran_index);
#if defined(CS_MODE)
      (void) net_client_final (false);
#else /* CS_MODE */
#if defined(WINDOWS)
      css_windows_shutdown ();
#endif /* WINDOWS */
#endif /* !CS_MODE */
    }

      boot_client_all_finalize (is_er_final ? ALL_FINALIZATION : EXCEPT_ER_FINALIZATION);
    }

  return NO_ERROR;
}

/*
 * boot_shutdown_client_at_exit () - make sure that the client is shutdown at exit
 *
 * return : nothing
 *
 * Note:
 *       This function is called when the invoked program terminates
 *       normally. This function make sure that the client is shutdown
 *       in a nice way.
 */
static void
boot_shutdown_client_at_exit (void)
{
  if (BOOT_IS_CLIENT_RESTARTED () && boot_Process_id == getpid ())
    {
      /* Avoid infinite looping if someone calls exit during shutdown */
      boot_Process_id++;

      if (!er_is_initialized ())
    {
      // we need error manager initialized
      er_init (NULL, ER_NEVER_EXIT);
    }

      (void) boot_shutdown_client (true);
    }
}

/*
 * boot_donot_shutdown_client_at_exit: do not shutdown client at exist.
 *
 * return : nothing
 *
 * This function must be called when the system needs to exit
 *  without shutting down the client (e.g., in case of fatal
 *  failure).
 */
void
boot_donot_shutdown_client_at_exit (void)
{
  if (BOOT_IS_CLIENT_RESTARTED () && boot_Process_id == getpid ())
    {
      boot_Process_id++;
    }
}

/*
 * boot_server_die_or_reject: shutdown client when the server is dead
 *
 * return : nothing
 *
 * Note: The server has been terminated for circumstances beyond the client
 *       control. All active client transactions have been unilaterally
 *       aborted as a consequence of the termination of server.
 */
void
boot_server_die_or_changed (void)
{
  /*
   * If the client is restarted, abort the active transaction in the client and
   * terminate the client modules
   */
  if (BOOT_IS_CLIENT_RESTARTED ())
    {
      (void) tran_abort_only_client (true);
      boot_client (NULL_TRAN_INDEX, TM_TRAN_WAIT_MSECS (), TM_TRAN_ISOLATION ());
      boot_Is_client_all_final = false;
#if defined(CS_MODE)
      net_client_final (true);
#endif /* !CS_MODE */
      if (prm_get_bool_value (PRM_ID_TEST_MODE))
    {
      er_print_callstack (ARG_FILE_LINE, "boot_server_die_or_changed() terminated\n");
    }
    }
}

/*
 * boot_client_all_finalize () - terminate every single client
 *
 * return : nothing
 *
 *   final_level(in): finalizing objects level
 *                    ALL_FINALIZATION       : all finalization
 *                    EXCEPT_ER_FINALIZATION : except er_final()
 *                    OPTIONAL_FINALIZATION  : finalize only objects that are not cleared while running
 *
 * Note: Terminate every single module of the client. This function is called
 *       during the shutdown of the client.
 */
void
boot_client_all_finalize (int final_level)
{
  void (*sigterm_handler) (int);
  void (*sigabrt_handler) (int);
  void (*sigint_handler) (int);

  /* to prevent duplicate calls by signal handlers during execution of the function. */
  sigterm_handler = signal (SIGTERM, SIG_IGN);
  sigabrt_handler = signal (SIGABRT, SIG_IGN);
  sigint_handler = signal (SIGINT, SIG_IGN);

  if (BOOT_IS_CLIENT_RESTARTED () || boot_Is_client_all_final == false)
    {
      if (boot_Server_credential.db_full_name)
    {
      db_private_free_and_init (NULL, boot_Server_credential.db_full_name);
    }
      if (boot_Server_credential.host_name)
    {
      db_private_free_and_init (NULL, boot_Server_credential.host_name);
    }
      if (boot_Server_credential.lob_path)
    {
      db_private_free_and_init (NULL, boot_Server_credential.lob_path);
    }
      if (boot_Server_credential.db_lang)
    {
      db_private_free_and_init (NULL, boot_Server_credential.db_lang);
    }

      showstmt_metadata_final ();
      tran_free_savepoint_list ();
      sm_flush_static_methods ();
      set_final ();
      parser_final ();

      if (final_level != OPTIONAL_FINALIZATION)
    {
      tr_final ();
      au_final ();
      sm_final ();
      method_callback_final ();
      ws_final ();
      es_final ();
      tp_final ();
    }

#if !defined(WINDOWS)
      (void) dl_destroy_module ();
#endif /* !WINDOWS */

      locator_free_areas ();
      sysprm_final ();
      perfmon_finalize ();
      area_final ();

      msgcat_final ();
      if (final_level != EXCEPT_ER_FINALIZATION)
    {
      er_final (ER_ALL_FINAL);
    }
      lang_final ();
      tz_unload ();

#if defined(WINDOWS)
      pc_final ();
#endif /* WINDOWS */

      memset (&boot_Server_credential, 0, sizeof (boot_Server_credential));
      memset (boot_Server_credential.server_session_key, 0xFF, SERVER_SESSION_KEY_SIZE);

      boot_client (NULL_TRAN_INDEX, TRAN_LOCK_INFINITE_WAIT, TRAN_DEFAULT_ISOLATION_LEVEL ());
      boot_Is_client_all_final = true;
    }
  /* restore the signals that was blocked, when the function ended. */
  signal (SIGTERM, sigterm_handler);
  signal (SIGABRT, sigabrt_handler);
  signal (SIGINT, sigint_handler);
}

#if defined(CS_MODE)
/*
 * boot_client_initialize_css () - Attempts to connect to hosts
 *                                          in list
 *
 * returns : NO_ERROR if all OK, ER_ status otherwise
 *
 *   db(in) : host information
 *   connect_order(in): whether to randomly or sequentially traverse host list
 *   opt_cap(in): optional capability
 *   discriminative(in): deprecated
 *
 * Note: This function will try an initialize the communications with the hosts
 *       in hostlist until success or the end of list is reached.
 */
static int
boot_client_initialize_css (DB_INFO * db, int client_type, bool check_capabilities, int opt_cap, bool discriminative,
                int connect_order, bool is_preferred_host)
{
  int error = ER_NET_NO_SERVER_HOST;
  int hn, n;
  char *hostlist[MAX_NUM_DB_HOSTS];
  char strbuf[(CUB_MAXHOSTNAMELEN + 1) * MAX_NUM_DB_HOSTS];
  bool cap_error = false, boot_host_connected_exist = false;
  int max_num_delayed_hosts_lookup;

  assert (db != NULL);
  assert (db->num_hosts > 0);

  if (db->hosts == NULL)
    {
      db->hosts = cfg_get_hosts (NULL, &db->num_hosts, false);
      if (db->hosts == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
      return ER_GENERIC_ERROR;
    }
    }

  max_num_delayed_hosts_lookup = db_get_max_num_delayed_hosts_lookup ();
  if (is_preferred_host == false && max_num_delayed_hosts_lookup == 0 && (opt_cap & BOOT_CHECK_HA_DELAY_CAP))
    {
      /* if max_num_delayed_hosts_lookup is zero, move on to 2nd try */
      return ER_NET_SERVER_HAND_SHAKE;
    }

  memset (hostlist, 0, sizeof (hostlist));
  hn = 0;
  /* try the connected host first */
  if (boot_Host_connected[0] != '\0')
    {
      boot_host_connected_exist = true;
      hostlist[hn++] = boot_Host_connected;
    }
  for (n = 0; hn < MAX_NUM_DB_HOSTS && n < db->num_hosts; n++)
    {
      hostlist[hn++] = db->hosts[n];
    }

  if (connect_order == DB_CONNECT_ORDER_RANDOM)
    {
      if (boot_Host_connected[0] != '\0')
    {
      /* leave boot_Host_connected at the front and shuffle the others */
      util_shuffle_string_array (hostlist + 1, hn - 1);
    }
      else
    {
      util_shuffle_string_array (hostlist, hn);
    }
    }

  db_clear_delayed_hosts_count ();

  for (n = 0; n < hn; n++)
    {
      if (css_check_server_alive_fn != NULL)
    {
      if (css_check_server_alive_fn (db->name, hostlist[n]) == false)
        {
          er_log_debug (ARG_FILE_LINE, "skip '%s@%s'\n", db->name, hostlist[n]);
          db_set_host_status (hostlist[n], DB_HS_UNUSABLE_DATABASES);
          continue;
        }
    }

      er_log_debug (ARG_FILE_LINE, "trying to connect '%s@%s'\n", db->name, hostlist[n]);
      error = net_client_init (db->name, hostlist[n]);
      if (error != NO_ERROR)
    {
      if (error == ERR_CSS_TCP_CONNECT_TIMEDOUT)
        {
          db_set_host_status (hostlist[n], DB_HS_CONN_TIMEOUT | DB_HS_CONN_FAILURE);
        }
      else
        {
          db_set_host_status (hostlist[n], DB_HS_CONN_FAILURE);
        }
    }
      else
    {
      /* save the hostname for the use of calling functions */
      if (boot_Host_connected != hostlist[n])
        {
          strncpy_bufsize (boot_Host_connected, hostlist[n]);
        }
      db_set_connected_host_status (hostlist[n]);

      er_log_debug (ARG_FILE_LINE, "ping server with handshake\n");
      /* ping to validate availability and to check compatibility */
      er_clear ();
      error = net_client_ping_server_with_handshake (client_type, check_capabilities, opt_cap);
      if (error != NO_ERROR)
        {
          net_client_final (false);
        }
    }

      /* connect error to the db at the host */
      switch (error)
    {
    case NO_ERROR:
      return NO_ERROR;

    case ER_NET_SERVER_HAND_SHAKE:
    case ER_NET_HS_UNKNOWN_SERVER_REL:
      cap_error = true;
      [[fallthrough]];
    case ER_NET_DIFFERENT_RELEASE:
    case ER_NET_NO_SERVER_HOST:
    case ER_NET_CANT_CONNECT_SERVER:
    case ER_NET_NO_MASTER:
    case ERR_CSS_TCP_CANNOT_CONNECT_TO_MASTER:
    case ERR_CSS_TCP_CONNECT_TIMEDOUT:
    case ERR_CSS_ERROR_FROM_SERVER:
    case ER_CSS_CLIENTS_EXCEEDED:
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_BO_CONNECT_FAILED, 2, db->name, hostlist[n]);
      /* try to connect to next host */
      er_log_debug (ARG_FILE_LINE, "error %d. try to connect to next host\n", error);
      break;
    default:
      /* ?? */
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CONNECT_FAILED, 2, db->name, hostlist[n]);
    }

      if (error == ER_NET_SERVER_HAND_SHAKE && is_preferred_host == false && (opt_cap & BOOT_CHECK_HA_DELAY_CAP)
      && max_num_delayed_hosts_lookup > 0)
    {
      /* do not count delayed boot_Host_connected */
      if (boot_host_connected_exist == true && n == 0)
        {
          db_clear_delayed_hosts_count ();
        }

      if (db_get_delayed_hosts_count () >= max_num_delayed_hosts_lookup)
        {
          hn = n + 1;
          break;
        }
    }
    }               /* for (tn) */

  /* failed to connect all hosts; write an error message */
  strbuf[0] = '\0';
  for (n = 0; n < hn - 1 && n < (MAX_NUM_DB_HOSTS - 1); n++)
    {
      strncat (strbuf, hostlist[n], CUB_MAXHOSTNAMELEN);
      strcat (strbuf, ":");
    }
  strncat (strbuf, hostlist[n], CUB_MAXHOSTNAMELEN);
  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CONNECT_FAILED, 2, db->name, strbuf);

  if (check_capabilities == true && cap_error == true)
    {
      /*
       * There'a a live host which has cause handshake error,
       * so adjust the return value
       */
      error = ER_NET_SERVER_HAND_SHAKE;
    }

  return (error);
}
#endif /* CS_MODE */

#if defined (SA_MODE)
#if defined (ENABLE_UNUSED_FUNCTION)
/*
 * boot_build_catalog_classes :
 *
 * returns : NO_ERROR if all OK, ER_ status otherwise
 *
 *   dbname(in) :
 */
int
boot_build_catalog_classes (const char *dbname)
{
  int error_code = NO_ERROR;

  /* check if an old version database */
  if (locator_find_class (CT_CLASS_NAME) != NULL)
    {
      fprintf (stdout, "Database %s already has system catalog class/vclass\n", dbname);
      return 1;
    }
  else
    {
      bool cc_save;

      /* save and catcls_Enable */
      cc_save = catcls_Enable;
      catcls_Enable = false;

      error_code = catcls_class_install ();
      if (error_code == NO_ERROR)
    {
      error_code = catcls_vclass_install ();
    }
      if (error_code == NO_ERROR)
    {
      /* add method to db_authorization */
      au_add_method_check_authorization ();

      /* mark catalog class/view as a system class */
      sm_mark_system_class_for_catalog ();

      if (!tf_Metaclass_class.n_variable)
        {
          tf_compile_meta_classes ();
        }
      if (catcls_Enable != true)
        {
          error_code = catcls_compile_catalog_classes (NULL);
          if (error_code == NO_ERROR)
        {
          error_code = sm_force_write_all_classes ();
          if (error_code == NO_ERROR)
            {
              error_code = au_force_write_new_auth ();
            }
        }
        }
    }
      /* restore catcls_Enable */
      catcls_Enable = cc_save;
    }

  return error_code;
}

/*
 * boot_destroy_catalog_classes :
 *
 * returns : NO_ERROR if all OK, ER_ status otherwise
 *
 *   dbname(in) :
 *
 * Note: destroy catalog by reverse order of building
 *
 */
int
boot_destroy_catalog_classes (void)
{
  int error_code = NO_ERROR;
  bool cc_save, save;

  int i;
  MOP classmop;
  const char *classes[] = {
    CT_CLASS_NAME,
    CT_ATTRIBUTE_NAME,
    CT_DOMAIN_NAME,
    CT_METHOD_NAME,
    CT_METHSIG_NAME,
    CT_METHARG_NAME,
    CT_METHFILE_NAME,
    CT_QUERYSPEC_NAME,
    CT_INDEX_NAME,
    CT_INDEXKEY_NAME,
    CT_CLASSAUTH_NAME,
    CT_DATATYPE_NAME,
    CT_PARTITION_NAME,
    CT_STORED_PROC_NAME,
    CT_STORED_PROC_ARGS_NAME,
    CTV_CLASS_NAME,
    CTV_SUPER_CLASS_NAME,
    CTV_VCLASS_NAME,
    CTV_ATTRIBUTE_NAME,
    CTV_ATTR_SD_NAME,
    CTV_METHOD_NAME,
    CTV_METHARG_NAME,
    CTV_METHARG_SD_NAME,
    CTV_METHFILE_NAME,
    CTV_INDEX_NAME,
    CTV_INDEXKEY_NAME,
    CTV_AUTH_NAME,
    CTV_TRIGGER_NAME,
    CTV_PARTITION_NAME,
    CTV_STORED_PROC_NAME,
    CTV_STORED_PROC_ARGS_NAME,
    CT_COLLATION_NAME,
    CT_SERVER_NAME,
    CTV_SERVER_NAME,
    CT_SYNONYM_NAME,
    CTV_SYNONYM_NAME,
    NULL
  };

  /* check if catalog exists */
  if (locator_find_class (CT_CLASS_NAME) == NULL)
    {
      /* catalog does not exists */
      return NO_ERROR;
    }

  /* save and off catcls_Enable */
  cc_save = catcls_Enable;
  catcls_Enable = false;

  AU_DISABLE (save);

  /* drop method of db_authorization */
  error_code = db_drop_class_method (locator_find_class ("db_authorization"), "check_authorization");
  /* error checking */
  if (error_code != NO_ERROR)
    {
      goto exit_on_error;
    }

  /* drop catalog class/vclass */
  for (i = 0; classes[i] != NULL; i++)
    {
      classmop = locator_find_class (classes[i]);
      if (!classmop)
    {
      continue;     /* not found */
    }
      /* for vclass, revoke before drop */
      if (db_is_vclass (classmop))
    {
      error_code = db_revoke (Au_public_user, classmop, AU_SELECT);
      if (error_code != NO_ERROR)
        {
          goto exit_on_error;
        }
    }

      /* drop class/view */
      error_code = db_drop_class (classmop);
      if (error_code == ER_OBJ_INVALID_ARGUMENTS)
    {
      continue;
    }

      /* error checking */
      if (error_code != NO_ERROR)
    {
      goto exit_on_error;
    }
    }

exit_on_error:

  AU_ENABLE (save);

  /* restore catcls_Enable */
  catcls_Enable = cc_save;

  return error_code;
}

/*
 * boot_rebuild_catalog_classes :
 *
 * returns : NO_ERROR if all OK, ER_ status otherwise
 *
 *   dbname(in) :
 */
int
boot_rebuild_catalog_classes (const char *dbname)
{
  int error_code = NO_ERROR;

  error_code = boot_destroy_catalog_classes ();

  if (error_code != NO_ERROR)
    {
      return error_code;
    }

  return boot_build_catalog_classes (dbname);
}
#endif /* ENABLE_UNUSED_FUNCTION */
#endif /* SA_MODE */

#if defined(CS_MODE)
char *
boot_get_host_connected (void)
{
  return boot_Host_connected;
}

#if defined (ENABLE_UNUSED_FUNCTION)
HA_SERVER_STATE
boot_get_ha_server_state (void)
{
  return boot_Server_credential.ha_server_state;
}
#endif /* ENABLE_UNUSED_FUNCTION */

/*
 * boot_get_lob_path - return the lob path which is received from the server
 */
const char *
boot_get_lob_path (void)
{
  return boot_Server_credential.lob_path;
}
#endif /* CS_MODE */

/*
 * boot_clear_host_connected () -
 */
void
boot_clear_host_connected (void)
{
#if defined(CS_MODE)
  boot_Host_connected[0] = '\0';
#endif
}

char *
boot_get_host_name (void)
{
  if (boot_Host_name[0] == '\0')
    {
      if (GETHOSTNAME (boot_Host_name, CUB_MAXHOSTNAMELEN) != 0)
    {
      strcpy (boot_Host_name, boot_Client_id_unknown_string);
    }
      boot_Host_name[CUB_MAXHOSTNAMELEN - 1] = '\0';    /* bullet proof */
    }

  return boot_Host_name;
}

char *
boot_get_ip (void)
{
  struct hostent *hp = NULL;
  if (boot_Host_name[0] == '\0')
    {
      boot_get_host_name ();
    }

  if ((hp = gethostbyname_uhost (boot_Host_name)) != NULL)
    {
      char *ip = inet_ntoa (*(struct in_addr *) *hp->h_addr_list);
      memcpy (boot_Ip_address, ip, 15);
    }

  return boot_Ip_address;
}

#if defined(CS_MODE)
/*
 * boot_check_locales () - checks that client locales are compatible with
 *                         server locales
 *
 *  return : error code
 *
 */
static int
boot_check_locales (BOOT_CLIENT_CREDENTIAL * client_credential)
{
  int error_code = NO_ERROR;
  LANG_COLL_COMPAT *server_collations = NULL;
  LANG_LOCALE_COMPAT *server_locales = NULL;
  int server_coll_cnt, server_locales_cnt;
  char cli_text[PATH_MAX];
  char srv_text[DB_MAX_IDENTIFIER_LENGTH + 10];

  error_code = boot_get_server_locales (&server_collations, &server_locales, &server_coll_cnt, &server_locales_cnt);
  if (error_code != NO_ERROR)
    {
      goto exit;
    }

  (void) basename_r (client_credential->get_program_name (), cli_text, sizeof (cli_text));
  snprintf (srv_text, sizeof (srv_text) - 1, "server '%s'", client_credential->get_db_name ());

  error_code = lang_check_coll_compat (server_collations, server_coll_cnt, cli_text, srv_text);
  if (error_code != NO_ERROR)
    {
      goto exit;
    }

  error_code = lang_check_locale_compat (server_locales, server_locales_cnt, cli_text, srv_text);

exit:
  if (server_collations != NULL)
    {
      free_and_init (server_collations);
    }
  if (server_locales != NULL)
    {
      free_and_init (server_locales);
    }

  return error_code;
}
#endif /* CS_MODE */

/*
 * boot_get_server_session_key () -
 */
char *
boot_get_server_session_key (void)
{
  return boot_Server_credential.server_session_key;
}

/*
 * boot_set_server_session_key () -
 */
void
boot_set_server_session_key (const char *key)
{
  memcpy (boot_Server_credential.server_session_key, key, SERVER_SESSION_KEY_SIZE);
}


#if defined(CS_MODE)
/*
 * boot_check_timezone_checksum () - checks that client timezone library is
 *                               compatible with server timezone library
 *
 *  return : error code
 *
 */
static int
boot_check_timezone_checksum (BOOT_CLIENT_CREDENTIAL * client_credential)
{
  int error_code = NO_ERROR;
  char timezone_checksum[TZ_CHECKSUM_SIZE + 1];
  const TZ_DATA *tzd;
  char cli_text[PATH_MAX];
  char srv_text[DB_MAX_IDENTIFIER_LENGTH + 10];

  error_code = boot_get_server_timezone_checksum (timezone_checksum);
  if (error_code != NO_ERROR)
    {
      goto exit;
    }

  (void) basename_r (client_credential->get_program_name (), cli_text, sizeof (cli_text));
  snprintf (srv_text, sizeof (srv_text) - 1, "server '%s'", client_credential->get_db_name ());

  tzd = tz_get_data ();
  assert (tzd != NULL);
  error_code = check_timezone_compat (tzd->checksum, timezone_checksum, cli_text, srv_text);
exit:
  return error_code;
}
#endif /* CS_MODE */

/*
 * boot_client_find_and_cache_class_oids () - Cache class OID's on client for
 *                        fast class mop identifying.
 *
 * return    : Error code.
 */
static int
boot_client_find_and_cache_class_oids (void)
{
  MOP class_mop = NULL;
  int error;

  class_mop = sm_find_class (CT_SERIAL_NAME);
  if (class_mop == NULL)
    {
      error = er_errid ();
      if (error != NO_ERROR)
    {
      return error;
    }
      er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
      return ER_FAILED;
    }
  oid_set_cached_class_oid (OID_CACHE_SERIAL_CLASS_ID, &class_mop->oid_info.oid);

  class_mop = sm_find_class (CT_HA_APPLY_INFO_NAME);
  if (class_mop == NULL)
    {
      error = er_errid ();
      if (error != NO_ERROR)
    {
      return error;
    }

      er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
      return ER_FAILED;
    }
  oid_set_cached_class_oid (OID_CACHE_HA_APPLY_INFO_CLASS_ID, &class_mop->oid_info.oid);
  return NO_ERROR;
}