Skip to content

File cubrid_log.c

File List > api > cubrid_log.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.
 *
 */

/*
 * cubrid_log.c -
 */

#ident "$Id$"

#if defined(CS_MODE)

#if defined(WINDOWS)
#include <winsock2.h>
#include <windows.h>
#else /* WINDOWS */
#include <arpa/inet.h>
#endif /* WINDOWS */

#if defined(WINDOWS)
#include <io.h>
#else /* WINDOWS */
#include <unistd.h>
#endif /* WINDOWS */

#include <assert.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "authenticate.h"
#include "client_support.h"
#include "cubrid_log.h"
#include "log_lsa.hpp"
#include "network.h"
#include "object_representation.h"
#include "dbi.h"
#include "dbtype_def.h"
#include "porting.h"

#if defined(WINDOWS)
#include "wintcp.h"
#endif

#define CUBRID_LOG_WRITE_TRACELOG(msg, ...) \
  do\
    {\
      if (msg) \
        { \
          cubrid_log_tracelog (__FILE__, __LINE__, __func__, false, 0, msg, ##__VA_ARGS__); \
        } \
    }\
  while(0)

#define CUBRID_LOG_ERROR_HANDLING(e, msg, ...) \
  do\
    {\
      (err_code) = (e); \
      if (msg) \
        { \
          cubrid_log_tracelog (__FILE__, __LINE__, __func__, true, e, msg, ##__VA_ARGS__); \
        } \
      goto cubrid_log_error; \
    }\
  while(0)

#ifndef S_ISDIR
#define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
#endif

typedef enum
{
  CUBRID_LOG_STAGE_CONFIGURATION,
  CUBRID_LOG_STAGE_PREPARATION,
  CUBRID_LOG_STAGE_EXTRACTION,
  CUBRID_LOG_STAGE_FINALIZATION
} CUBRID_LOG_STAGE;

typedef enum
{
  DATA_ITEM_TYPE_DDL = 0,
  DATA_ITEM_TYPE_DML,
  DATA_ITEM_TYPE_DCL,
  DATA_ITEM_TYPE_TIMER
} DATA_ITEM_TYPE;

CUBRID_LOG_STAGE g_stage = CUBRID_LOG_STAGE_CONFIGURATION;

CSS_CONN_ENTRY *g_conn_entry;

int g_connection_timeout = 300; /* min/max: -1/360 (sec) */
int g_extraction_timeout = 300; /* min/max: -1/360 (sec) */
int g_max_log_item = 512;   /* min/max: 1/1024 */
bool g_all_in_cond = false;

uint64_t *g_extraction_table;
int g_extraction_table_count = 0;

char **g_extraction_user;
int g_extraction_user_count = 0;

char g_dbname[CUBRID_LOG_MAX_DBNAME_LEN + 1] = "";

FILE *g_trace_log = NULL;
char g_trace_log_base[PATH_MAX + 1] = ".";
char g_trace_log_path[PATH_MAX + 1] = "";
char g_trace_log_path_old[PATH_MAX + 1] = "";
int g_trace_log_level = 0;
int g_num_trace_log = 0;
int64_t g_trace_log_filesize = 10 * 1024 * 1024;    /* 10 MB */

LOG_LSA g_next_lsa = LSA_INITIALIZER;

char *g_log_infos = NULL;
int g_log_infos_size = 0;

CUBRID_LOG_ITEM *g_log_items = NULL;
int g_log_items_count = 0;

const char *
data_item_type_to_string (int data_item_type)
{
  switch (data_item_type)
    {
    case 0:
      return "DDL";
    case 1:
      return "DML";
    case 2:
      return "DCL";
    case 3:
      return "TIMER";
    default:
      assert (0);
      return "";
    }
}

/*
 * cubrid_log_set_connection_timeout () -
 *   return:
 *   timeout(in):
 */
int
cubrid_log_set_connection_timeout (int timeout)
{
  if (g_stage != CUBRID_LOG_STAGE_CONFIGURATION)
    {
      return CUBRID_LOG_INVALID_FUNC_CALL_STAGE;
    }

  if (timeout < 0 || timeout > 360)
    {
      return CUBRID_LOG_INVALID_CONNECTION_TIMEOUT;
    }

  g_connection_timeout = timeout;

  return CUBRID_LOG_SUCCESS;
}

/*
 * cubrid_log_set_extraction_timeout () -
 *   return:
 *   timeout(in):
 */
int
cubrid_log_set_extraction_timeout (int timeout)
{
  if (g_stage != CUBRID_LOG_STAGE_CONFIGURATION)
    {
      return CUBRID_LOG_INVALID_FUNC_CALL_STAGE;
    }

  if (timeout < 0 || timeout > 360)
    {
      return CUBRID_LOG_INVALID_EXTRACTION_TIMEOUT;
    }

  g_extraction_timeout = timeout;

  return CUBRID_LOG_SUCCESS;
}

static void
cubrid_log_reset_tracelog ()
{
  if (g_trace_log != NULL)
    {
      fflush (g_trace_log);
      fclose (g_trace_log);
      g_trace_log = NULL;
    }

  memset (g_trace_log_base, 0, sizeof (g_trace_log_base));
  memset (g_trace_log_path, 0, sizeof (g_trace_log_path));
  memset (g_trace_log_path_old, 0, sizeof (g_trace_log_path_old));
  memset (g_dbname, 0, sizeof (g_dbname));

  strcpy (g_trace_log_base, ".");
  g_num_trace_log = 0;
  g_trace_log_level = 0;
  g_trace_log_filesize = 10 * 1024 * 1024;
}

static int
cubrid_log_make_new_tracelog ()
{
  time_t er_time;
  struct tm er_tm;
  struct tm *er_tm_p = &er_tm;
  struct timeval tv;

  int len = 0;

  char curr_time[14];

  if (g_dbname[0] == '\0')
    {
      return -1;
    }

  er_time = time (NULL);

  er_tm_p = localtime_r (&er_time, &er_tm);
  if (er_tm_p == NULL)
    {
      strcpy (curr_time, "00000000_0000");
    }
  else
    {
      strftime (curr_time, sizeof (curr_time), "%Y%m%d_%H%M", er_tm_p);
    }

  if (g_trace_log != NULL)
    {
      fclose (g_trace_log);
      g_trace_log = NULL;
    }

  if (g_num_trace_log == 2)
    {
      if (remove (g_trace_log_path_old) != 0)
    {
      return -1;
    }
      memcpy (g_trace_log_path_old, g_trace_log_path, PATH_MAX + 1);
    }
  else
    {
      if (g_num_trace_log != 0)
    {
      memcpy (g_trace_log_path_old, g_trace_log_path, PATH_MAX + 1);
    }
    }

  len = (int) (strlen (g_trace_log_base) + strlen (g_dbname) + strlen (curr_time)) + 17;
  if (len > PATH_MAX)
    {
      return -1;
    }

  if (snprintf (g_trace_log_path, sizeof (g_trace_log_path), "%s%c%s_cubridlog_%s.err",
        g_trace_log_base, PATH_SEPARATOR, g_dbname, curr_time) >= (int) sizeof (g_trace_log_path))
    {
      assert_release (false);
      g_trace_log_path[sizeof (g_trace_log_path) - 1] = '\0';
    }

  g_trace_log = fopen (g_trace_log_path, "a+");
  if (g_trace_log == NULL)
    {
      return -1;
    }

  if (g_num_trace_log < 2)
    {
      g_num_trace_log++;
    }

  assert (g_num_trace_log <= 2);

  return CUBRID_LOG_SUCCESS;
}

static int
cubrid_log_check_tracelog ()
{
  int64_t curr_size = 0;

  if (g_trace_log == NULL)
    {
      return cubrid_log_make_new_tracelog ();
    }
  else
    {
      curr_size = ftell (g_trace_log);
      if (curr_size >= g_trace_log_filesize)
    {
      return cubrid_log_make_new_tracelog ();
    }
    }

  return CUBRID_LOG_SUCCESS;
}

static int
cubrid_log_check_tracelog_path (char *path)
{
  struct stat statbuf;

  if (access (path, F_OK) == 0)
    {
      /* Check if it is directory */
      stat (path, &statbuf);
      if (!S_ISDIR (statbuf.st_mode))
    {
      return CUBRID_LOG_INVALID_PATH;
    }

      /* Directory exists */
      if (access (path, W_OK) < 0)
    {
      /* Write permission */
      return CUBRID_LOG_NO_FILE_PERMISSION;
    }
    }
  else
    {
      /* Directory not exist, then make directory */
      if (mkdir (path, 0777) < 0)
    {
      return CUBRID_LOG_NO_FILE_PERMISSION;
    }
    }

  return CUBRID_LOG_SUCCESS;
}

void
cubrid_log_tracelog (const char *filename, const int line_no, const char *function, bool is_error, int error,
             const char *fmt, ...)
{
  time_t er_time;
  struct tm er_tm;
  struct tm *er_tm_p = &er_tm;
  struct timeval tv;
  char curr_time[256];

  va_list arg_ptr;

  if (cubrid_log_check_tracelog () != CUBRID_LOG_SUCCESS)
    {
      return;
    }

  er_time = time (NULL);

  er_tm_p = localtime_r (&er_time, &er_tm);
  if (er_tm_p == NULL)
    {
      strcpy (curr_time, "00/00/00 00:00:00.000");
    }
  else
    {
      gettimeofday (&tv, NULL);
      snprintf (curr_time + strftime (curr_time, 128, "%m/%d/%y %H:%M:%S", er_tm_p), 255, ".%03ld", tv.tv_usec / 1000);
    }

  if (!is_error)
    {
      fprintf (g_trace_log, "[%s][FILE:%s][LINE:%d][FUNC:%s]\n", curr_time, filename, line_no, function);
    }
  else
    {
      fprintf (g_trace_log, "[%s][FILE:%s][LINE:%d][FUNC:%s][ERROR:%d]\n", curr_time, filename, line_no, function,
           error);
    }

  va_start (arg_ptr, fmt);
  vfprintf (g_trace_log, fmt, arg_ptr);
  va_end (arg_ptr);
}

/*
 * cubrid_log_set_tracelog () -
 *   return:
 *   path(in):
 *   level(in):
 *   filesize(in):
 */
int
cubrid_log_set_tracelog (char *path, int level, int filesize)
{
  int err_code;

  if (g_stage != CUBRID_LOG_STAGE_CONFIGURATION)
    {
      return CUBRID_LOG_INVALID_FUNC_CALL_STAGE;
    }

  if (path == NULL || strlen (path) > PATH_MAX)
    {
      return CUBRID_LOG_INVALID_PATH;
    }
  else
    {
      if ((err_code = cubrid_log_check_tracelog_path (path)) != CUBRID_LOG_SUCCESS)
    {
      return err_code;
    }
    }

  if (level < 0 || level > 1)
    {
      return CUBRID_LOG_INVALID_LEVEL;
    }

  if (filesize < 8 || filesize > 512)
    {
      if (filesize == -1)
    {
      filesize = 10;
    }
      else
    {
      return CUBRID_LOG_INVALID_FILESIZE;
    }
    }

  snprintf (g_trace_log_base, sizeof (g_trace_log_base), "%s", path);
  g_trace_log_level = level;
  g_trace_log_filesize = filesize * 1024 * 1024;

  return CUBRID_LOG_SUCCESS;
}

/*
 * cubrid_log_set_max_log_item () -
 *   return:
 *   max_log_item(in):
 */
int
cubrid_log_set_max_log_item (int max_log_item)
{
  if (g_stage != CUBRID_LOG_STAGE_CONFIGURATION)
    {
      return CUBRID_LOG_INVALID_FUNC_CALL_STAGE;
    }

  if (max_log_item < 1 || max_log_item > 1024)
    {
      return CUBRID_LOG_INVALID_MAX_LOG_ITEM;
    }

  g_max_log_item = max_log_item;

  return CUBRID_LOG_SUCCESS;
}

/*
 * cubrid_log_set_all_in_cond () -
 *   return:
 *   retrieve_all(in):
 */
int
cubrid_log_set_all_in_cond (int retrieve_all)
{
  if (g_stage != CUBRID_LOG_STAGE_CONFIGURATION)
    {
      return CUBRID_LOG_INVALID_FUNC_CALL_STAGE;
    }

  if (retrieve_all < 0 || retrieve_all > 1)
    {
      return CUBRID_LOG_INVALID_RETRIEVE_ALL;
    }

  g_all_in_cond = retrieve_all;

  return CUBRID_LOG_SUCCESS;
}

/*
 * cubrid_log_set_extraction_table () -
 *   return:
 *   classoid_arr(in):
 *   arr_size(in):
 */
int
cubrid_log_set_extraction_table (uint64_t * classoid_arr, int arr_size)
{
  if (g_stage != CUBRID_LOG_STAGE_CONFIGURATION)
    {
      return CUBRID_LOG_INVALID_FUNC_CALL_STAGE;
    }

  if ((classoid_arr == NULL && arr_size != 0) || (classoid_arr != NULL && arr_size == 0))
    {
      return CUBRID_LOG_INVALID_CLASSOID_ARR_SIZE;
    }

  g_extraction_table = (uint64_t *) malloc (sizeof (uint64_t) * arr_size);
  if (g_extraction_table == NULL)
    {
      return CUBRID_LOG_FAILED_MALLOC;
    }

  memcpy (g_extraction_table, classoid_arr, arr_size * sizeof (uint64_t));
  g_extraction_table_count = arr_size;

  return CUBRID_LOG_SUCCESS;
}

/*
 * cubrid_log_set_extraction_user () -
 *   return:
 *   user_arr(in):
 *   arr_size(in):
 */
int
cubrid_log_set_extraction_user (char **user_arr, int arr_size)
{
  int i;

  if (g_stage != CUBRID_LOG_STAGE_CONFIGURATION)
    {
      return CUBRID_LOG_INVALID_FUNC_CALL_STAGE;
    }

  if ((user_arr == NULL && arr_size != 0) || (user_arr != NULL && arr_size == 0))
    {
      return CUBRID_LOG_INVALID_USER_ARR_SIZE;
    }

  g_extraction_user = (char **) malloc (sizeof (char *) * arr_size);
  if (g_extraction_user == NULL)
    {
      return CUBRID_LOG_FAILED_MALLOC;
    }

  for (i = 0; i < arr_size; i++)
    {
      g_extraction_user[i] = strdup (user_arr[i]);
    }

  g_extraction_user_count = arr_size;

  return CUBRID_LOG_SUCCESS;
}

static int
cubrid_log_connect_server_internal (char *host, int port, char *dbname)
{
  unsigned short rid = 0;

  char *recv_data = NULL;
  int recv_data_size;

  int reason;

  CSS_QUEUE_ENTRY *queue_entry;
  int err_code;

#if defined (WINDOWS)
  if (css_windows_startup () < 0)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT, "Failed to startup Windows socket\n");
    }
#endif

  g_conn_entry = __gv_cvar.css_make_conn (INVALID_SOCKET);
  if (g_conn_entry == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT, "Failed to make css_conn_entry to connect to the server\n");
    }

  if (__gv_cvar.css_connect_to_log_server (host, g_conn_entry, dbname, port, g_connection_timeout, &rid) == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                 "Failed to connect to the server. host (%s), dbname (%s), port (%d), timeout (%d sec)\n",
                 host, dbname, port, g_connection_timeout);
    }

  if (__gv_cvar.css_receive_data (g_conn_entry, rid, &recv_data, &recv_data_size, g_connection_timeout * 1000) !=
      NO_ERRORS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT, "Failed to receive data from server. (timeout : %d sec)\n",
                 g_connection_timeout);
    }

  if (recv_data == NULL || recv_data_size != sizeof (int))
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                 "Failed to receive data from server. recv_data is %s, recv_data_size : %d (should be %d)\n",
                 recv_data ? "not null" : "null", recv_data_size, sizeof (int));
    }

  reason = ntohl (*(int *) recv_data);

  free_and_init (recv_data);

#if defined (WINDOWS)
  if (reason == SERVER_CONNECTED_NEW)
    {
      if (__gv_cvar.css_receive_data (g_conn_entry, rid, &recv_data, &recv_data_size, g_connection_timeout * 1000) !=
      NO_ERRORS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                     "Failed to receive the server port id from the master.\n");
    }

      if (recv_data != NULL)
    {
      assert (recv_data_size == sizeof (int));

      int port_id = ntohl (*((int *) recv_data));

      __gv_cvar.css_close_conn (g_conn_entry);

      g_conn_entry = __gv_cvar.css_server_connect_part_two (host, g_conn_entry, port_id, &rid);
      if (g_conn_entry == NULL)
        {
          CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                     "Failed to connect to the server with new port id (%d)\n", port_id);
        }

      free_and_init (recv_data);
    }
      else
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                     "Failed to get server port id (recv_data = %s , recv_data_size = %d) \n",
                     recv_data, recv_data_size);
    }
    }
  else
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT, "Failed to connect to the server (reason : %d) \n", reason);
    }
#else
  if (reason != SERVER_CONNECTED)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT, "Failed to connect to the server (reason : %d) \n", reason);
    }
#endif

  return CUBRID_LOG_SUCCESS;

cubrid_log_error:

  if (recv_data != NULL)
    {
      free_and_init (recv_data);
    }

  if (g_conn_entry != NULL)
    {
      __gv_cvar.css_queue_find_and_remove_header_entry_ptr (g_conn_entry, rid);

      __gv_cvar.css_free_conn (g_conn_entry);
      g_conn_entry = NULL;
    }

#if defined (WINDOWS)
  (void) css_windows_shutdown ();
#endif

  return err_code;
}

static int
cubrid_log_send_configurations (void)
{
  unsigned short rid = 0;

  char *a_request;
  OR_ALIGNED_BUF (OR_INT_SIZE) a_reply;
  char *request, *ptr;
  char *reply = OR_ALIGNED_BUF_START (a_reply);
  int request_size, i;
  int reply_size = OR_ALIGNED_BUF_SIZE (a_reply), reply_code;

  char *recv_data = NULL;
  int recv_data_size;

  CSS_QUEUE_ENTRY *queue_entry;
  int err_code;

  request_size = OR_INT_SIZE * 5;

  for (i = 0; i < g_extraction_user_count; i++)
    {
      request_size += or_packed_string_length (g_extraction_user[i], NULL);
    }

  request_size += (OR_BIGINT_SIZE * g_extraction_table_count);

  a_request = (char *) malloc (request_size + MAX_ALIGNMENT);
  if (a_request == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_MALLOC, "Failed to malloc for request. (size : %d)\n",
                 request_size + MAX_ALIGNMENT);
    }

  request = PTR_ALIGN (a_request, MAX_ALIGNMENT);

  ptr = or_pack_int (request, g_max_log_item);
  ptr = or_pack_int (ptr, g_extraction_timeout);
  ptr = or_pack_int (ptr, g_all_in_cond);
  ptr = or_pack_int (ptr, g_extraction_user_count);

  for (i = 0; i < g_extraction_user_count; i++)
    {
      ptr = or_pack_string (ptr, g_extraction_user[i]);
    }

  ptr = or_pack_int (ptr, g_extraction_table_count);

  for (i = 0; i < g_extraction_table_count; i++)
    {
      ptr = or_pack_int64 (ptr, (INT64) g_extraction_table[i]);
    }

  request_size = (int) (ptr - request);

  if (__gv_cvar.css_send_request_with_data_buffer_with_padding
      (g_conn_entry, NET_SERVER_CDC_START_SESSION, &rid, request, request_size, reply, reply_size) != NO_ERRORS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                 "Request(NET_SERVER_CDC_START_SESSION) failed. request size (%d), reply_sze (%d)\n",
                 request_size, reply_size);
    }

  if (__gv_cvar.css_receive_data (g_conn_entry, rid, &recv_data, &recv_data_size, g_connection_timeout * 1000) !=
      NO_ERRORS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                 "receive data from the request(NET_SERVER_CDC_START_SESSION) failed. (timeout : %d sec)\n",
                 g_connection_timeout);
    }

  if (recv_data == NULL || recv_data_size != sizeof (int))
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT, "recv_data is %s, receive data size : %d (should be %d)\n",
                 recv_data ? "not null" : "null", recv_data_size, sizeof (int));
    }

  or_unpack_int (recv_data, &reply_code);

  if (reply_code == ER_CDC_NOT_AVAILABLE)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_UNAVAILABLE_CDC_SERVER,
                 "Failed to connect to the server. Please check 'supplemental_log' parameter\n");
    }
  else if (reply_code != NO_ERROR)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                 "Failed to connect to the server. reply code from server is %d\n", reply_code);
    }

  free_and_init (a_request);

  return CUBRID_LOG_SUCCESS;

cubrid_log_error:

  if (recv_data != NULL && recv_data != reply)
    {
      free_and_init (recv_data);
    }

  __gv_cvar.css_queue_find_and_remove_header_entry_ptr (g_conn_entry, rid);

  if (a_request != NULL)
    {
      free_and_init (a_request);
    }

  return err_code;
}

static int
cubrid_log_db_login (char *hostname, char *dbname, char *username, char *password)
{
  MOP user;
  char dbname_at_hostname[CUB_MAXHOSTNAMELEN + CUBRID_LOG_MAX_DBNAME_LEN + 2] = { '\0', };

  snprintf (dbname_at_hostname, sizeof (dbname_at_hostname), "%s@%s", dbname, hostname);

  if (au_login (username, password, true) != NO_ERROR)
    {
      cubrid_log_tracelog (__FILE__, __LINE__, __func__, true, CUBRID_LOG_FAILED_LOGIN, "Failed to login\n");
      goto error;
    }

  if (db_restart ("cubrid_log_api", 0, dbname_at_hostname) != NO_ERROR)
    {
      cubrid_log_tracelog (__FILE__, __LINE__, __func__, true, CUBRID_LOG_FAILED_LOGIN,
               "db_restart failed to connect to %s\n", dbname_at_hostname);
      return CUBRID_LOG_FAILED_LOGIN;
    }

  user = au_find_user (username);
  if (user == NULL)
    {
      cubrid_log_tracelog (__FILE__, __LINE__, __func__, true, CUBRID_LOG_FAILED_LOGIN, "can not find user %s\n",
               username);
      goto error;
    }

  if (!au_is_dba_group_member (user))
    {
      cubrid_log_tracelog (__FILE__, __LINE__, __func__, true, CUBRID_LOG_FAILED_LOGIN,
               "DBA authorization failed. %s is not a member of DBA group\n", username);
      goto error;
    }

  db_shutdown ();

  return CUBRID_LOG_SUCCESS;

error:

  db_shutdown ();

  return CUBRID_LOG_FAILED_LOGIN;
}

/*
 * cubrid_log_connect_server () -
 *   return:
 *   host(in):
 *   port(in):
 *   dbname(in):
 */
int
cubrid_log_connect_server (char *host, int port, char *dbname, char *user, char *password)
{
  int err_code;

  if (dbname != NULL)
    {
      strncpy (g_dbname, dbname, CUBRID_LOG_MAX_DBNAME_LEN);
    }
  else
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_INVALID_DBNAME, "dbname must not be null\n");
    }

  if (g_trace_log_level == 1)
    {
      CUBRID_LOG_WRITE_TRACELOG ("[INPUT] stage (%d), host (%s), port (%d), dbname (%s), user (%s)\n", g_stage, host,
                 port, dbname, user);
    }

  if (g_stage != CUBRID_LOG_STAGE_CONFIGURATION)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_INVALID_FUNC_CALL_STAGE,
                 "stage required for this step : %d, but current stage : %d\n",
                 CUBRID_LOG_STAGE_CONFIGURATION, g_stage);
    }

  if (host == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_INVALID_HOST, "host must not be null\n");
    }

  if (port < 0 || port > USHRT_MAX)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_INVALID_PORT,
                 "invalid port number : %d, port must be greater than 0 and less than %d\n", port,
                 USHRT_MAX);
    }

  if (user == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_INVALID_USER, "user must not be null\n");
    }

  if (password == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_INVALID_PASSWORD, "password must not be null\n");
    }

  if (cubrid_log_db_login (host, dbname, user, password) != CUBRID_LOG_SUCCESS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_LOGIN, NULL);
    }

  if (er_init (NULL, ER_NEVER_EXIT) != NO_ERROR)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT, "error initialization failed\n");
    }

  if (cubrid_log_connect_server_internal (host, port, dbname) != CUBRID_LOG_SUCCESS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT, NULL);
    }

  if (cubrid_log_send_configurations () != CUBRID_LOG_SUCCESS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT, NULL);
    }

  g_stage = CUBRID_LOG_STAGE_PREPARATION;

  return CUBRID_LOG_SUCCESS;

cubrid_log_error:

  return err_code;
}

static int
cubrid_log_find_start_lsa (time_t * timestamp, LOG_LSA * lsa)
{
  unsigned short rid = 0;

  OR_ALIGNED_BUF (OR_BIGINT_SIZE) a_request;
  OR_ALIGNED_BUF (OR_INT_SIZE + OR_LOG_LSA_ALIGNED_SIZE + OR_INT64_SIZE) a_reply;
  char *request = OR_ALIGNED_BUF_START (a_request), *ptr;
  char *reply = OR_ALIGNED_BUF_START (a_reply);
  int request_size = OR_ALIGNED_BUF_SIZE (a_request);
  int reply_size = OR_ALIGNED_BUF_SIZE (a_reply), reply_code;

  char *recv_data = NULL;
  int recv_data_size;

  CSS_QUEUE_ENTRY *queue_entry;
  int err_code;

  if (g_trace_log_level == 1)
    {
      CUBRID_LOG_WRITE_TRACELOG ("[INPUT] timestamp (%lld)\n", *timestamp);
    }

  or_pack_int64 (request, (INT64) (*timestamp));

  if (__gv_cvar.css_send_request_with_data_buffer_with_padding
      (g_conn_entry, NET_SERVER_CDC_FIND_LSA, &rid, request, request_size, reply, reply_size) != NO_ERRORS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                 "Request(NET_SERVER_CDC_FIND_LSA) failed. request size (%d), reply_sze (%d)\n",
                 request_size, reply_size);
    }

  /* extraction timeout will be replaced when it is defined */
  if (__gv_cvar.css_receive_data (g_conn_entry, rid, &recv_data, &recv_data_size, g_extraction_timeout * 1000) !=
      NO_ERRORS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                 "receive data from the request(NET_SERVER_CDC_FIND_LSA) failed. (timeout : %d sec)\n",
                 g_connection_timeout);
    }

  if (recv_data == NULL || recv_data_size != OR_INT_SIZE + OR_LOG_LSA_ALIGNED_SIZE + OR_INT64_SIZE)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT, "recv_data is %s | recv_data_size = %d (should be %d)\n",
                 recv_data ? "not null" : "null", recv_data_size,
                 OR_INT_SIZE + OR_LOG_LSA_ALIGNED_SIZE + OR_INT64_SIZE);
    }

  ptr = or_unpack_int (recv_data, &reply_code);

  if (reply_code == NO_ERROR || reply_code == ER_CDC_ADJUSTED_LSA)
    {
      ptr = or_unpack_log_lsa (ptr, lsa);
      or_unpack_int64 (ptr, timestamp);

      if (recv_data != NULL && recv_data != reply)
    {
      free_and_init (recv_data);
    }

      return CUBRID_LOG_SUCCESS;
    }
  else if (reply_code == ER_CDC_ADJUSTED_LSA)
    {
      ptr = or_unpack_log_lsa (ptr, lsa);
      or_unpack_int64 (ptr, timestamp);

      if (recv_data != NULL && recv_data != reply)
    {
      free_and_init (recv_data);
    }

      return CUBRID_LOG_SUCCESS_WITH_ADJUSTED_LSA;
    }
  else
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_LSA_NOT_FOUND, "LOG LSA is not found at the time %lld\n", *timestamp);
    }

  if (g_trace_log_level == 1)
    {
      CUBRID_LOG_WRITE_TRACELOG ("[OUTPUT] timestamp (%lld), lsa (%lld | %d)\n", *timestamp, lsa->pageid, lsa->offset);
    }

cubrid_log_error:

  if (recv_data != NULL && recv_data != reply)
    {
      free_and_init (recv_data);
    }

  __gv_cvar.css_queue_find_and_remove_header_entry_ptr (g_conn_entry, rid);

  return err_code;
}

/*
 * cubrid_log_find_lsa () -
 *   return:
 *   timestamp(in):
 *   lsa(out):
 */
int
cubrid_log_find_lsa (time_t * timestamp, uint64_t * lsa)
{
  int err_code;

  if (g_trace_log_level == 1)
    {
      CUBRID_LOG_WRITE_TRACELOG ("[INPUT] stage (%d), timestamp (%lld)\n", g_stage, *timestamp);
    }

  if (g_stage != CUBRID_LOG_STAGE_PREPARATION)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_INVALID_FUNC_CALL_STAGE,
                 "stage required for this step : %d, but current stage : %d\n",
                 CUBRID_LOG_STAGE_PREPARATION, g_stage);
    }

  if (timestamp == NULL || *timestamp < 0)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_INVALID_TIMESTAMP,
                 "timestamp must be greater or equal than 0. Input timestamp is %s, and value is %lld\n",
                 timestamp ? "not null" : "null", *timestamp);
    }

  if (lsa == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_INVALID_OUT_PARAM, "Input lsa must not be null\n");
    }

  if (LSA_ISNULL (&g_next_lsa))
    {
      if (cubrid_log_find_start_lsa (timestamp, &g_next_lsa) != CUBRID_LOG_SUCCESS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_LSA_NOT_FOUND, NULL);
    }
    }

  memcpy (lsa, &g_next_lsa, sizeof (uint64_t));

  if (g_trace_log_level == 1)
    {
      CUBRID_LOG_WRITE_TRACELOG ("[OUTPUT] timestamp (%lld), lsa (%lld)\n", *timestamp, g_next_lsa);
    }

  return CUBRID_LOG_SUCCESS;

cubrid_log_error:

  return err_code;
}

static int
cubrid_log_extract_internal (LOG_LSA * next_lsa, int *num_infos, int *total_length)
{
  unsigned short rid = 0;

  OR_ALIGNED_BUF (OR_LOG_LSA_ALIGNED_SIZE) a_request;
  OR_ALIGNED_BUF (OR_INT_SIZE + OR_LOG_LSA_ALIGNED_SIZE + OR_INT_SIZE + OR_INT_SIZE) a_reply;
  char *request = OR_ALIGNED_BUF_START (a_request), *ptr;
  char *reply = OR_ALIGNED_BUF_START (a_reply);
  int request_size = OR_ALIGNED_BUF_SIZE (a_request);
  int reply_size = OR_ALIGNED_BUF_SIZE (a_reply), reply_code;

  char *recv_data = NULL;
  int recv_data_size;

  CSS_QUEUE_ENTRY *queue_entry;
  int err_code;
  int rc = NO_ERROR;

  if (g_trace_log_level == 1)
    {
      CUBRID_LOG_WRITE_TRACELOG ("[INPUT] lsa (%lld | %d)\n", next_lsa->pageid, next_lsa->offset);
    }

  or_pack_log_lsa (request, next_lsa);

  /* protocol name will be modified */
  if (__gv_cvar.css_send_request_with_data_buffer_with_padding
      (g_conn_entry, NET_SERVER_CDC_GET_LOGINFO_METADATA, &rid, request, request_size, reply, reply_size) != NO_ERRORS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                 "Request(NET_SERVER_CDC_GET_LOGINFO_METADATA) failed. request size (%d), reply_sze (%d)\n",
                 request_size, reply_size);
    }

  /* extraction timeout will be modified when it is defined */
  if (__gv_cvar.css_receive_data (g_conn_entry, rid, &recv_data, &recv_data_size, g_extraction_timeout * 1000) !=
      NO_ERRORS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                 "receive data from the request(NET_SERVER_CDC_GET_LOGINFO_METADATA) failed. (timeout : %d sec)\n",
                 g_connection_timeout);
    }

  if (recv_data == NULL || recv_data_size != OR_INT_SIZE + OR_LOG_LSA_ALIGNED_SIZE + OR_INT_SIZE + OR_INT_SIZE)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT, "recv_data is %s | recv_data_size = %d (should be %d)\n",
                 recv_data ? "not null" : "null", recv_data_size,
                 OR_INT_SIZE + OR_LOG_LSA_ALIGNED_SIZE + OR_INT_SIZE + OR_INT_SIZE);
    }

  ptr = or_unpack_int (recv_data, &reply_code);

  if (reply_code != NO_ERROR)
    {
      if (reply_code == ER_CDC_EXTRACTION_TIMEOUT)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_EXTRACTION_TIMEOUT, "Extraction timeout (timeout : %d sec)\n",
                     g_extraction_timeout);
    }
      else if (reply_code == ER_CDC_INVALID_LOG_LSA)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_INVALID_LSA, "Input lsa is not valid (%lld|%d)\n", next_lsa->pageid,
                     next_lsa->offset);
    }
    }

  ptr = or_unpack_log_lsa (ptr, next_lsa);

  ptr = or_unpack_int (ptr, num_infos);
  or_unpack_int (ptr, total_length);

  if (recv_data != NULL && recv_data != reply)
    {
      free_and_init (recv_data);
    }

  if (rc == CUBRID_LOG_SUCCESS_WITH_NO_LOGITEM)
    {
      goto cubrid_log_end;
    }

  if (g_trace_log_level == 1)
    {
      CUBRID_LOG_WRITE_TRACELOG ("[MID] extract infos are next_lsa (%lld | %d), num_infos (%d), total_length (%d)\n",
                 next_lsa->pageid, next_lsa->offset, *num_infos, *total_length);
    }

  if (g_log_infos_size < *total_length)
    {
      char *tmp_log_infos = NULL;

      tmp_log_infos = (char *) realloc ((void *) g_log_infos, *total_length + MAX_ALIGNMENT);
      if (tmp_log_infos == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_MALLOC,
                     "Malloc failed for storing temporary log infos (size : %d)\n",
                     *total_length + MAX_ALIGNMENT);
    }
      else
    {
      g_log_infos = tmp_log_infos;
    }

      g_log_infos_size = *total_length;
    }

  reply = PTR_ALIGN (g_log_infos, MAX_ALIGNMENT);
  reply_size = *total_length;
  recv_data = NULL;

  if (*total_length > 0)
    {
      if (__gv_cvar.css_send_request_with_data_buffer_with_padding
      (g_conn_entry, NET_SERVER_CDC_GET_LOGINFO, &rid, NULL, 0, reply, reply_size) != NO_ERRORS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                     "Request(NET_SERVER_CDC_GET_LOGINFO) failed. reply_sze (%d)\n", reply_size);
    }

      /* extraction timeout will be modified when it is defined */
      if (__gv_cvar.css_receive_data (g_conn_entry, rid, &recv_data, &recv_data_size, g_extraction_timeout * 1000)
      != NO_ERRORS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                     "receive data from the request(NET_SERVER_CDC_GET_LOGINFO) failed. (timeout : %d sec)\n",
                     g_extraction_timeout);
    }

      if (recv_data == NULL || recv_data_size != *total_length)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                     "recv_data is %s | recv_data_size = %d (should be %d)\n",
                     recv_data ? "not null" : "null", recv_data_size, *total_length);
    }
    }

  if (g_trace_log_level == 1)
    {
      CUBRID_LOG_WRITE_TRACELOG ("[END]\n");
    }

  return CUBRID_LOG_SUCCESS;

cubrid_log_end:

  return rc;

cubrid_log_error:

  if (recv_data != NULL && recv_data != reply)
    {
      free_and_init (recv_data);
    }

  __gv_cvar.css_queue_find_and_remove_header_entry_ptr (g_conn_entry, rid);

  return err_code;
}

inline static int
cubrid_log_make_ddl (char **data_info, DDL * ddl)
{
  char *ptr;

  ptr = *data_info;

  ptr = or_unpack_int (ptr, &ddl->ddl_type);
  ptr = or_unpack_int (ptr, &ddl->object_type);
  ptr = or_unpack_int64 (ptr, (INT64 *) & ddl->oid);
  ptr = or_unpack_int64 (ptr, (INT64 *) & ddl->classoid);
  ptr = or_unpack_int (ptr, &ddl->statement_length);
  ptr = or_unpack_string_nocopy (ptr, &ddl->statement);

  *data_info = ptr;

  return CUBRID_LOG_SUCCESS;
}

inline static int
cubrid_log_make_dml (char **data_info, DML * dml)
{
  char *ptr;

  int i, pack_func_code;
  int err_code;

  ptr = *data_info;

  ptr = or_unpack_int (ptr, &dml->dml_type);
  ptr = or_unpack_int64 (ptr, (INT64 *) & dml->classoid);
  ptr = or_unpack_int (ptr, &dml->num_changed_column);

  if (dml->num_changed_column)
    {
      // now, just malloc for validation and later, optimize it.
      dml->changed_column_index = (int *) malloc (sizeof (int) * dml->num_changed_column);
      if (dml->changed_column_index == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_MALLOC,
                     "Malloc failed for dml->changed_column_index (size : %d)\n",
                     sizeof (int) * dml->num_changed_column);
    }

      for (i = 0; i < dml->num_changed_column; i++)
    {
      ptr = or_unpack_int (ptr, &dml->changed_column_index[i]);
    }

      dml->changed_column_data = (char **) malloc (sizeof (char *) * dml->num_changed_column);
      if (dml->changed_column_data == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_MALLOC,
                     "Malloc failed for dml->changed_column_data (size : %d)\n",
                     sizeof (char *) * dml->num_changed_column);
    }

      dml->changed_column_data_len = (int *) malloc (sizeof (int) * dml->num_changed_column);
      if (dml->changed_column_data_len == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_MALLOC,
                     "Malloc failed for dml->changed_column_data_len (size : %d)\n",
                     sizeof (int) * dml->num_changed_column);
    }

      for (i = 0; i < dml->num_changed_column; i++)
    {
      ptr = or_unpack_int (ptr, &pack_func_code);

      switch (pack_func_code)
        {
        case 0:
          dml->changed_column_data[i] = ptr;
          ptr = or_unpack_int (ptr, (int *) dml->changed_column_data[i]);
          dml->changed_column_data_len[i] = OR_INT_SIZE;
          break;

        case 1:
          dml->changed_column_data[i] = ptr;
          ptr = or_unpack_int64 (ptr, (INT64 *) dml->changed_column_data[i]);
          dml->changed_column_data_len[i] = OR_INT64_SIZE;
          break;

        case 2:
          dml->changed_column_data[i] = ptr;
          ptr = or_unpack_float (ptr, (float *) dml->changed_column_data[i]);
          dml->changed_column_data_len[i] = OR_FLOAT_SIZE;
          break;

        case 3:
          dml->changed_column_data[i] = ptr;
          ptr = or_unpack_double (ptr, (double *) dml->changed_column_data[i]);
          dml->changed_column_data_len[i] = OR_DOUBLE_SIZE;
          break;

        case 4:
          dml->changed_column_data[i] = ptr;
          ptr = or_unpack_short (ptr, (short *) dml->changed_column_data[i]);
          dml->changed_column_data_len[i] = OR_SHORT_SIZE;
          break;

        case 5:
          dml->changed_column_data[i] = ptr;
          ptr = or_unpack_string_nocopy (ptr, &dml->changed_column_data[i]);
          dml->changed_column_data_len[i] = (int) strlen (dml->changed_column_data[i]);
          break;
        case 6:
          assert (0);   // unused pack func code: or_pack_stream()
          break;

        case 7:
          dml->changed_column_data[i] = ptr;
          ptr = or_unpack_string_nocopy (ptr, &dml->changed_column_data[i]);
          if (dml->changed_column_data[i] == NULL)
        {
          dml->changed_column_data_len[i] = 0;
        }
          else
        {
          dml->changed_column_data_len[i] = (int) strlen (dml->changed_column_data[i]);
        }
          break;

        case 8:
          dml->changed_column_data[i] = ptr;
          ptr = or_unpack_string_nocopy (ptr, &dml->changed_column_data[i]);
          dml->changed_column_data_len[i] = (int) strlen (dml->changed_column_data[i]);
          break;

        default:
          assert (0);

        }
    }
    }

  ptr = or_unpack_int (ptr, &dml->num_cond_column);

  if (dml->num_cond_column)
    {
      // now, just malloc for validation and later, optimize it.
      dml->cond_column_index = (int *) malloc (sizeof (int) * dml->num_cond_column);
      if (dml->cond_column_index == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_MALLOC, "Malloc failed for dml->cond_column_index (size : %d)\n",
                     sizeof (int) * dml->num_cond_column);
    }

      for (i = 0; i < dml->num_cond_column; i++)
    {
      ptr = or_unpack_int (ptr, &dml->cond_column_index[i]);
    }

      dml->cond_column_data = (char **) malloc (sizeof (char *) * dml->num_cond_column);
      if (dml->cond_column_data == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_MALLOC, "Malloc failed for dml->cond_column_data (size : %d)\n",
                     sizeof (char *) * dml->num_cond_column);
    }

      dml->cond_column_data_len = (int *) malloc (sizeof (int) * dml->num_cond_column);
      if (dml->cond_column_data_len == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_MALLOC,
                     "Malloc failed for dml->cond_column_data_len (size : %d)\n",
                     sizeof (int) * dml->num_cond_column);
    }

      for (i = 0; i < dml->num_cond_column; i++)
    {
      ptr = or_unpack_int (ptr, &pack_func_code);

      switch (pack_func_code)
        {
        case 0:
          dml->cond_column_data[i] = ptr;
          ptr = or_unpack_int (ptr, (int *) dml->cond_column_data[i]);
          dml->cond_column_data_len[i] = OR_INT_SIZE;
          break;

        case 1:
          dml->cond_column_data[i] = ptr;
          ptr = or_unpack_int64 (ptr, (INT64 *) dml->cond_column_data[i]);
          dml->cond_column_data_len[i] = OR_BIGINT_SIZE;
          break;

        case 2:
          dml->cond_column_data[i] = ptr;
          ptr = or_unpack_float (ptr, (float *) dml->cond_column_data[i]);
          dml->cond_column_data_len[i] = OR_FLOAT_SIZE;
          break;

        case 3:
          dml->cond_column_data[i] = ptr;
          ptr = or_unpack_double (ptr, (double *) dml->cond_column_data[i]);
          dml->cond_column_data_len[i] = OR_DOUBLE_SIZE;
          break;

        case 4:
          dml->cond_column_data[i] = ptr;
          ptr = or_unpack_short (ptr, (short *) dml->cond_column_data[i]);
          dml->cond_column_data_len[i] = OR_SHORT_SIZE;
          break;

        case 5:
          dml->cond_column_data[i] = ptr;
          ptr = or_unpack_string_nocopy (ptr, &dml->cond_column_data[i]);
          dml->cond_column_data_len[i] = (int) strlen (dml->cond_column_data[i]);
          break;
        case 6:
          assert (0);   // unused pack func code: or_pack_stream()
          break;

        case 7:
          dml->cond_column_data[i] = ptr;
          ptr = or_unpack_string_nocopy (ptr, &dml->cond_column_data[i]);
          if (dml->cond_column_data[i] == NULL)
        {
          dml->cond_column_data_len[i] = 0;
        }
          else
        {
          dml->cond_column_data_len[i] = (int) strlen (dml->cond_column_data[i]);
        }

          break;

        case 8:
          dml->cond_column_data[i] = ptr;
          ptr = or_unpack_string_nocopy (ptr, &dml->cond_column_data[i]);
          dml->cond_column_data_len[i] = (int) strlen (dml->cond_column_data[i]);
          break;

        default:
          assert (0);

        }
    }
    }

  *data_info = ptr;

  return CUBRID_LOG_SUCCESS;

cubrid_log_error:

  return err_code;
}

inline static int
cubrid_log_make_dcl (char **data_info, DCL * dcl)
{
  char *ptr;

  ptr = *data_info;

  ptr = or_unpack_int (ptr, &dcl->dcl_type);
  ptr = or_unpack_int64 (ptr, &dcl->timestamp);

  *data_info = ptr;

  return CUBRID_LOG_SUCCESS;
}

inline static int
cubrid_log_make_timer (char **data_info, TIMER * timer)
{
  char *ptr;

  ptr = *data_info;

  ptr = or_unpack_int64 (ptr, &timer->timestamp);

  *data_info = ptr;

  return CUBRID_LOG_SUCCESS;
}

static int
cubrid_log_make_data_item (char **data_info, DATA_ITEM_TYPE data_item_type, CUBRID_DATA_ITEM * data_item)
{
  int err_code;

  if (g_trace_log_level == 1)
    {
      CUBRID_LOG_WRITE_TRACELOG ("[INPUT] data item type (%s)\n", data_item_type_to_string (data_item_type));
    }

  switch (data_item_type)
    {
    case DATA_ITEM_TYPE_DDL:
      if ((err_code = cubrid_log_make_ddl (data_info, &data_item->ddl)) != CUBRID_LOG_SUCCESS)
    {
      CUBRID_LOG_ERROR_HANDLING (err_code, NULL);
    }

      break;

    case DATA_ITEM_TYPE_DML:
      if ((err_code = cubrid_log_make_dml (data_info, &data_item->dml)) != CUBRID_LOG_SUCCESS)
    {
      CUBRID_LOG_ERROR_HANDLING (err_code, NULL);
    }

      break;

    case DATA_ITEM_TYPE_DCL:
      if ((err_code = cubrid_log_make_dcl (data_info, &data_item->dcl)) != CUBRID_LOG_SUCCESS)
    {
      CUBRID_LOG_ERROR_HANDLING (err_code, NULL);
    }

      break;

    case DATA_ITEM_TYPE_TIMER:
      if ((err_code = cubrid_log_make_timer (data_info, &data_item->timer)) != CUBRID_LOG_SUCCESS)
    {
      CUBRID_LOG_ERROR_HANDLING (err_code, NULL);
    }

      break;

    default:
      assert (0);
    }

  return CUBRID_LOG_SUCCESS;

cubrid_log_error:

  return err_code;
}

static int
cubrid_log_make_log_item (char **log_info, CUBRID_LOG_ITEM * log_item)
{
  char *ptr;

  int log_info_len;
  int err_code;
  int rc;

  ptr = *log_info;

  ptr = or_unpack_int (ptr, &log_info_len);

  ptr = or_unpack_int (ptr, &log_item->transaction_id);
  ptr = or_unpack_string_nocopy (ptr, &log_item->user);
  ptr = or_unpack_int (ptr, &log_item->data_item_type);

  if ((rc = cubrid_log_make_data_item (&ptr, (DATA_ITEM_TYPE) log_item->data_item_type, &log_item->data_item)) !=
      CUBRID_LOG_SUCCESS)
    {
      CUBRID_LOG_ERROR_HANDLING (rc, NULL);
    }

  *log_info = ptr;

  return CUBRID_LOG_SUCCESS;

cubrid_log_error:

  return err_code;
}

static int
cubrid_log_make_log_item_list (int num_infos, int total_length, CUBRID_LOG_ITEM ** log_item_list, int *list_size)
{
  char *ptr;

  int i;
  int err_code;
  int rc;

  if (g_trace_log_level == 1)
    {
      CUBRID_LOG_WRITE_TRACELOG ("[INPUT] num_infos (%d), total_length (%d)\n", num_infos, total_length);
    }

  if (g_log_items_count < num_infos)
    {
      CUBRID_LOG_ITEM *tmp_log_items = NULL;

      tmp_log_items = (CUBRID_LOG_ITEM *) realloc ((void *) g_log_items, sizeof (CUBRID_LOG_ITEM) * num_infos);
      if (tmp_log_items == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_MALLOC,
                     "Malloc failed for storing temporary log items (size : %d)\n",
                     sizeof (CUBRID_LOG_ITEM) * num_infos);
    }
      else
    {
      g_log_items = tmp_log_items;
    }

      g_log_items_count = num_infos;
    }

  ptr = PTR_ALIGN (g_log_infos, MAX_ALIGNMENT);

  for (i = 0; i < num_infos; i++)
    {
      if ((rc = cubrid_log_make_log_item (&ptr, &g_log_items[i]) != CUBRID_LOG_SUCCESS))
    {
      CUBRID_LOG_ERROR_HANDLING (rc, NULL);
    }

      g_log_items[i].next = &g_log_items[i + 1];

      ptr = PTR_ALIGN (ptr, MAX_ALIGNMENT);
    }

  g_log_items[num_infos - 1].next = NULL;

  *log_item_list = g_log_items;
  *list_size = num_infos;

  if (g_trace_log_level == 1)
    {
      CUBRID_LOG_WRITE_TRACELOG ("[OUTPUT] list_size (%d)\n", *list_size);
    }

  return CUBRID_LOG_SUCCESS;

cubrid_log_error:

  return err_code;
}

/*
 * cubrid_log_extract () -
 *   return:
 *   lsa(in/out):
 *   log_item_list(out):
 *   list_size(out):
 */
int
cubrid_log_extract (uint64_t * lsa, CUBRID_LOG_ITEM ** log_item_list, int *list_size)
{
  int num_infos, total_length;
  int err_code;
  int rc;

  if (g_trace_log_level == 1)
    {
      CUBRID_LOG_WRITE_TRACELOG ("[INPUT] current stage (%d), lsa (%lld)\n", g_stage, *lsa);
    }

  if (g_stage != CUBRID_LOG_STAGE_PREPARATION && g_stage != CUBRID_LOG_STAGE_EXTRACTION)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_INVALID_FUNC_CALL_STAGE,
                 "stage required for this step : %d, but current stage : %d\n",
                 CUBRID_LOG_STAGE_EXTRACTION, g_stage);
    }

  if (lsa == NULL || log_item_list == NULL || list_size == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_INVALID_OUT_PARAM,
                 "lsa (%s), log_item_list(%s), list_size(%s) must not be null\n",
                 lsa ? "not null" : "null", log_item_list ? "not null" : "null",
                 list_size ? "not null" : "null");
    }

  memcpy (&g_next_lsa, lsa, sizeof (LOG_LSA));

  rc = cubrid_log_extract_internal (&g_next_lsa, &num_infos, &total_length);

  if (rc != CUBRID_LOG_SUCCESS)
    {
      CUBRID_LOG_ERROR_HANDLING (rc, NULL);
    }

  if ((rc = cubrid_log_make_log_item_list (num_infos, total_length, log_item_list, list_size)) != CUBRID_LOG_SUCCESS)
    {
      CUBRID_LOG_ERROR_HANDLING (rc, NULL);
    }

  memcpy (lsa, &g_next_lsa, sizeof (uint64_t));

  g_stage = CUBRID_LOG_STAGE_EXTRACTION;

  if (g_trace_log_level == 1)
    {
      CUBRID_LOG_WRITE_TRACELOG ("[OUTPUT] lsa (%lld), list_size (%d)\n", *lsa, *list_size);
    }

  return CUBRID_LOG_SUCCESS;

cubrid_log_error:

  return err_code;
}

static int
cubrid_log_clear_data_item (DATA_ITEM_TYPE data_item_type, CUBRID_DATA_ITEM * data_item)
{
  int err_code;

  if (g_trace_log_level == 1)
    {
      CUBRID_LOG_WRITE_TRACELOG ("[INPUT] data item type (%s)\n", data_item_type_to_string (data_item_type));
    }

  switch (data_item_type)
    {
    case DATA_ITEM_TYPE_DDL:
      /* nothing to do */
      break;

    case DATA_ITEM_TYPE_DML:
      if (data_item->dml.num_changed_column > 0)
    {
      free_and_init (data_item->dml.changed_column_index);
      free_and_init (data_item->dml.changed_column_data);
      free_and_init (data_item->dml.changed_column_data_len);
      data_item->dml.num_changed_column = 0;
    }

      if (data_item->dml.num_cond_column > 0)
    {
      free_and_init (data_item->dml.cond_column_index);
      free_and_init (data_item->dml.cond_column_data);
      free_and_init (data_item->dml.cond_column_data_len);
      data_item->dml.num_cond_column = 0;
    }

      break;

    case DATA_ITEM_TYPE_DCL:
      /* nothing to do */
      break;

    case DATA_ITEM_TYPE_TIMER:
      /* nothing to do */
      break;

    default:
      assert (0);
    }

  return CUBRID_LOG_SUCCESS;
}

/*
 * cubrid_log_clear_log_item () -
 *   return:
 *   log_item_list(in):
 */
int
cubrid_log_clear_log_item (CUBRID_LOG_ITEM * log_item_list)
{
  int i;
  int err_code;
  int rc;

  if (g_stage != CUBRID_LOG_STAGE_EXTRACTION)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_INVALID_FUNC_CALL_STAGE,
                 "stage required for this step : %d, but current stage : %d\n",
                 CUBRID_LOG_STAGE_EXTRACTION, g_stage);
    }

  if (log_item_list == NULL)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_INVALID_LOGITEM_LIST, "log_item_list must not be null\n");
    }

  for (i = 0; i < g_log_items_count; i++)   // if g_log_items_count == 0 then nothing to do
    {
      if ((rc =
       cubrid_log_clear_data_item ((DATA_ITEM_TYPE) g_log_items[i].data_item_type,
                       &g_log_items[i].data_item)) != CUBRID_LOG_SUCCESS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_DEALLOC, NULL);
    }
    }

  g_log_items_count = 0;

  return CUBRID_LOG_SUCCESS;

cubrid_log_error:

  return err_code;
}

static int
cubrid_log_disconnect_server (void)
{
  unsigned short rid = 0;

  OR_ALIGNED_BUF (OR_INT_SIZE) a_reply;
  char *reply = OR_ALIGNED_BUF_START (a_reply);
  int reply_size = OR_ALIGNED_BUF_SIZE (a_reply), reply_code;

  char *recv_data = NULL;
  int recv_data_size;

  CSS_QUEUE_ENTRY *queue_entry;
  int err_code;

  if (__gv_cvar.css_send_request_with_data_buffer_with_padding
      (g_conn_entry, NET_SERVER_CDC_END_SESSION, &rid, NULL, 0, reply, reply_size) != NO_ERRORS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                 "Request(NET_SERVER_CDC_END_SESSION) failed. reply_sze (%d)\n", reply_size);
    }

  if (__gv_cvar.css_receive_data (g_conn_entry, rid, &recv_data, &recv_data_size, g_extraction_timeout * 1000) !=
      NO_ERRORS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT,
                 "receive data from the request(NET_SERVER_CDC_END_SESSION) failed. (timeout : %d sec)\n",
                 g_extraction_timeout);
    }

  if (recv_data == NULL || recv_data_size != OR_INT_SIZE)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_CONNECT, "recv_data is %s | recv_data_size = %d (should be %d)\n",
                 recv_data ? "not null" : "null", recv_data_size, OR_INT_SIZE);
    }

  or_unpack_int (recv_data, &reply_code);

  if (reply_code != NO_ERROR)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_DISCONNECT, "Failed to disconnect. reply code : %d\n", reply_code);
    }

  if (recv_data != NULL && recv_data != reply)
    {
      free_and_init (recv_data);
    }

  __gv_cvar.css_free_conn (g_conn_entry);
  g_conn_entry = NULL;

  return CUBRID_LOG_SUCCESS;

cubrid_log_error:

  if (recv_data != NULL && recv_data != reply)
    {
      free_and_init (recv_data);
    }

  if (g_conn_entry != NULL)
    {
      __gv_cvar.css_queue_find_and_remove_header_entry_ptr (g_conn_entry, rid);
      __gv_cvar.css_free_conn (g_conn_entry);
      g_conn_entry = NULL;
    }

  return err_code;
}

static int
cubrid_log_reset_globals (void)
{
  int i;

  g_connection_timeout = 300;
  g_extraction_timeout = 300;
  g_max_log_item = 512;
  g_all_in_cond = false;

  if (g_extraction_table != NULL)
    {
      free_and_init (g_extraction_table);
      g_extraction_table = NULL;
    }

  cubrid_log_reset_tracelog ();

  g_extraction_table_count = 0;

  if (g_extraction_user != NULL)
    {
      for (i = 0; i < g_extraction_user_count; i++)
    {
      free_and_init (g_extraction_user[i]);
    }

      free_and_init (g_extraction_user);
      g_extraction_user = NULL;
    }

  g_extraction_user_count = 0;

  g_next_lsa = LSA_INITIALIZER;

  if (g_log_infos != NULL)
    {
//      free (g_log_infos);
      g_log_infos = NULL;
    }

  g_log_infos_size = 0;

  return CUBRID_LOG_SUCCESS;
}

/*
 * cubrid_log_finalize () -
 *   return:
 */
int
cubrid_log_finalize (void)
{
  int err_code;

  if (g_stage != CUBRID_LOG_STAGE_PREPARATION && g_stage != CUBRID_LOG_STAGE_EXTRACTION)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_INVALID_FUNC_CALL_STAGE,
                 "stage required for this step : %d or %d, but current stage : %d\n",
                 CUBRID_LOG_STAGE_PREPARATION, CUBRID_LOG_STAGE_EXTRACTION, g_stage);
    }

  if (cubrid_log_disconnect_server () != CUBRID_LOG_SUCCESS)
    {
      CUBRID_LOG_ERROR_HANDLING (CUBRID_LOG_FAILED_DISCONNECT, NULL);
    }

#if defined (WINDOWS)
  (void) css_windows_shutdown ();
#endif

  (void) cubrid_log_reset_globals ();

  g_stage = CUBRID_LOG_STAGE_CONFIGURATION;

  return CUBRID_LOG_SUCCESS;

cubrid_log_error:

#if defined (WINDOWS)
  (void) css_windows_shutdown ();
#endif

  (void) cubrid_log_reset_globals ();

  g_stage = CUBRID_LOG_STAGE_CONFIGURATION;

  return err_code;
}

#endif /* CS_MODE */