Skip to content

File cas_cgw_execute.c

File List > broker > cas_cgw_execute.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.
 *
 */

#ident "$Id$"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined(WINDOWS)
#include <winsock2.h>
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include <process.h>
#else /* WINDOWS */
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#endif /* WINDOWS */
#include <assert.h>


#include "cas_util.h"
#include "cas_log.h"
#include "perf_monitor.h"
#include "transaction_cl.h"
#include "ddl_log.h"

#include "cas_cgw_execute.h"
#include "cas_cgw_odbc.h"


#define DBLINK_HINT                     "DBLINK"

/* ========================================================================
 * Global Variable Definitions
 * ======================================================================== */
T_COL_BINDER *col_binding = NULL;
T_COL_BINDER *col_binding_buff = NULL;

/* ========================================================================
 * Type Definitions
 * ======================================================================== */
typedef int (*T_FETCH_FUNC) (T_SRV_HANDLE *, int, int, char, int, T_NET_BUF *, T_REQ_INFO *);

/* ========================================================================
 * Forward Function Declarations
 * ======================================================================== */
static int cgw_fetch_result (T_SRV_HANDLE *, int, int, char, int, T_NET_BUF *, T_REQ_INFO *);
static int cgw_prepare_column_list_info_set (SQLHSTMT hstmt, char prepare_flag, char stmt_type,
                         T_BROKER_VERSION client_version, T_NET_BUF * net_buf);
static char ux_cgw_get_stmt_type (char *stmt);
static int fetch_not_supported (T_SRV_HANDLE *, int, int, char, int, T_NET_BUF *, T_REQ_INFO *);
static int fetch_call (T_SRV_HANDLE * srv_handle, T_NET_BUF * net_buf, T_REQ_INFO * req_info);
static bool do_commit_after_execute (const t_srv_handle & server_handle);

/* ========================================================================
 * Static Variable Definitions
 * ======================================================================== */
static T_FETCH_FUNC fetch_func[] = {
  cgw_fetch_result,     /* query */
  fetch_not_supported,      /* SCH_CLASS */
  fetch_not_supported,      /* SCH_VCLASS */
  fetch_not_supported,      /* SCH_QUERY_SPEC */
  fetch_not_supported,      /* SCH_ATTRIBUTE */
  fetch_not_supported,      /* SCH_CLASS_ATTRIBUTE */
  fetch_not_supported,      /* SCH_METHOD */
  fetch_not_supported,      /* SCH_CLASS_METHOD */
  fetch_not_supported,      /* SCH_METHOD_FILE */
  fetch_not_supported,      /* SCH_SUPERCLASS */
  fetch_not_supported,      /* SCH_SUBCLASS */
  fetch_not_supported,      /* SCH_CONSTRAINT */
  fetch_not_supported,      /* SCH_TRIGGER */
  fetch_not_supported,      /* SCH_CLASS_PRIVILEGE */
  fetch_not_supported,      /* SCH_ATTR_PRIVILEGE */
  fetch_not_supported,      /* SCH_DIRECT_SUPER_CLASS */
  fetch_not_supported,      /* SCH_PRIMARY_KEY */
  fetch_not_supported,      /* SCH_IMPORTED_KEYS */
  fetch_not_supported,      /* SCH_EXPORTED_KEYS */
  fetch_not_supported,      /* SCH_CROSS_REFERENCE */
};

/* ========================================================================
 * Function Definitions
 * ======================================================================== */
int
ux_cgw_check_connection (void)
{
  return cgw_is_database_connected ();
}

int
ux_cgw_prepare (char *sql_stmt, int flag, char auto_commit_mode, T_NET_BUF * net_buf, T_REQ_INFO * req_info,
        unsigned int query_seq_num)
{
  T_SRV_HANDLE *srv_handle = NULL;
  int srv_h_id = -1;
  int err_code;
  int num_markers;
  T_BROKER_VERSION client_version = req_info->client_version;
  int result_cache_lifetime;

  if ((flag & CCI_PREPARE_UPDATABLE) && (flag & CCI_PREPARE_HOLDABLE))
    {
      /* do not allow updatable, holdable results */
      err_code = ERROR_INFO_SET (CAS_ER_HOLDABLE_NOT_ALLOWED, CAS_ERROR_INDICATOR);
      goto prepare_error;
    }

  srv_h_id = hm_new_srv_handle (&srv_handle, query_seq_num);

  if (srv_h_id < 0)
    {
      err_code = srv_h_id;
      goto prepare_error;
    }

  err_code = cgw_get_handle (&srv_handle->cgw_handle);
  if (err_code < 0)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto prepare_error;
    }

  srv_handle->schema_type = -1;
  srv_handle->auto_commit_mode = auto_commit_mode;

  ALLOC_COPY_STRLEN (srv_handle->sql_stmt, sql_stmt);
  if (srv_handle->sql_stmt == NULL)
    {
      err_code = ERROR_INFO_SET (CAS_ER_NO_MORE_MEMORY, CAS_ERROR_INDICATOR);
      goto prepare_error;
    }

  sql_stmt = srv_handle->sql_stmt;

  if (flag & CCI_PREPARE_QUERY_INFO)
    {
      srv_handle->query_info_flag = TRUE;
    }
  else
    {
      srv_handle->query_info_flag = FALSE;
    }

  if (flag & CCI_PREPARE_UPDATABLE)
    {
      srv_handle->is_updatable = TRUE;
    }
  else
    {
      srv_handle->is_updatable = FALSE;
    }

  num_markers = get_num_markers (sql_stmt);
  srv_handle->num_markers = num_markers;
  srv_handle->prepare_flag = flag;

  err_code = cgw_sql_prepare ((SQLCHAR *) sql_stmt);
  if (err_code < 0)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto prepare_error;
    }

  net_buf_cp_int (net_buf, srv_h_id, NULL);

  result_cache_lifetime = -1;
  net_buf_cp_int (net_buf, result_cache_lifetime, NULL);

  srv_handle->stmt_type = (int) ux_cgw_get_stmt_type (sql_stmt);
  if (srv_handle->stmt_type == CUBRID_STMT_NONE || srv_handle->stmt_type == CUBRID_MAX_STMT_TYPE)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto prepare_error;
    }

  net_buf_cp_byte (net_buf, srv_handle->stmt_type);

  net_buf_cp_int (net_buf, num_markers, NULL);

  err_code =
    cgw_prepare_column_list_info_set (srv_handle->cgw_handle->hstmt, flag, srv_handle->stmt_type, client_version,
                      net_buf);

  if (err_code < 0)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto prepare_error;
    }

  srv_handle->is_prepared = TRUE;
  srv_handle->num_q_result = 1;
  srv_handle->cur_result = NULL;
  srv_handle->cur_result_index = 0;

  if (flag & CCI_PREPARE_HOLDABLE)
    {
      srv_handle->is_holdable = true;
    }

  return srv_h_id;

prepare_error:
  NET_BUF_ERR_SET (net_buf);

  if (auto_commit_mode == TRUE)
    {
      req_info->need_auto_commit = TRAN_AUTOROLLBACK;
    }

  errors_in_transaction++;

  if (srv_handle)
    {
      hm_srv_handle_free (srv_h_id);
    }
  return err_code;
}

int
ux_cgw_end_tran (int tran_type, bool reset_con_status, bool ddl_audit_log)
{
  int err_code = 0;

  ux_end_tran_cleanup (tran_type);

  T_CGW_HANDLE *cgw_handle = NULL;
  cgw_get_handle (&cgw_handle);
  if (cgw_handle)
    {
      err_code = cgw_endtran (cgw_handle->hdbc, tran_type);
    }

  if (ddl_audit_log && tran_type != CCI_TRAN_COMMIT)
    {
      logddl_write_tran_str (LOGDDL_TRAN_TYPE_ABORT);
    }

  return err_code;
}

int
ux_cgw_auto_commit (T_NET_BUF * net_buf, T_REQ_INFO * req_info)
{
  int err_code;
  int elapsed_sec = 0, elapsed_msec = 0;

  if (req_info->need_auto_commit == TRAN_AUTOCOMMIT)
    {
      cas_log_write (0, false, "auto_commit %s", tran_was_latest_query_committed ()? "(server)" : "(local)");
      err_code = ux_cgw_end_tran (CCI_TRAN_COMMIT, true, false);
      cas_log_write (0, false, "auto_commit %d", err_code);
      logddl_set_msg ("auto_commit %d", err_code);
    }
  else if (req_info->need_auto_commit == TRAN_AUTOROLLBACK)
    {
      cas_log_write (0, false, "auto_commit %s", tran_was_latest_query_aborted ()? "(local)" : "(server)");
      err_code = ux_cgw_end_tran (CCI_TRAN_ROLLBACK, true, false);
      cas_log_write (0, false, "auto_rollback %d", err_code);
      logddl_set_msg ("auto_rollback %d", err_code);
    }
  else
    {
      err_code = ERROR_INFO_SET (CAS_ER_INTERNAL, CAS_ERROR_INDICATOR);
    }

  if (err_code < 0)
    {
      NET_BUF_ERR_SET (net_buf);
      req_info->need_rollback = TRUE;
      errors_in_transaction++;
    }
  else
    {
      req_info->need_rollback = FALSE;
    }

  tran_timeout =
    ut_check_timeout (&tran_start_time, NULL, shm_appl->long_transaction_time, &elapsed_sec, &elapsed_msec);
  if (tran_timeout >= 0)
    {
      as_info->num_long_transactions %= MAX_DIAG_DATA_VALUE;
      as_info->num_long_transactions++;
    }
  if (err_code < 0 || errors_in_transaction > 0)
    {
      cas_log_end (SQL_LOG_MODE_ERROR, elapsed_sec, elapsed_msec);
      errors_in_transaction = 0;
    }
  else
    {
      if (tran_timeout >= 0 || query_timeout >= 0)
    {
      cas_log_end (SQL_LOG_MODE_TIMEOUT, elapsed_sec, elapsed_msec);
    }
      else
    {
      cas_log_end (SQL_LOG_MODE_NONE, elapsed_sec, elapsed_msec);
    }
    }
  gettimeofday (&tran_start_time, NULL);
  gettimeofday (&query_start_time, NULL);
  tran_timeout = 0;
  query_timeout = 0;

  return err_code;

  return -1;
}

int
ux_cgw_execute (T_SRV_HANDLE * srv_handle, char flag, int max_col_size, int max_row, int argc, void **argv,
        T_NET_BUF * net_buf, T_REQ_INFO * req_info, CACHE_TIME * clt_cache_time, int *clt_cache_reusable)
{
  int err_code = 0;
  int num_bind = 0;
  SQLLEN row_count = 0;
  T_BROKER_VERSION client_version = req_info->client_version;
  ODBC_BIND_INFO *bind_data_list = NULL;

  if (srv_handle->is_prepared == FALSE)
    {
      err_code = cgw_sql_prepare ((SQLCHAR *) srv_handle->sql_stmt);

      if (err_code < 0)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto execute_error;
    }
    }

  num_bind = srv_handle->num_markers;

  if (num_bind > 0)
    {
      err_code = cgw_make_bind_value (srv_handle->cgw_handle, num_bind, argc, argv, &bind_data_list);
      if (err_code < 0)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto execute_error;
    }
    }

  if (srv_handle->is_prepared == FALSE)
    {
      err_code = cgw_sql_prepare ((SQLCHAR *) srv_handle->sql_stmt);

      if (err_code != SQL_SUCCESS && err_code != SQL_SUCCESS_WITH_INFO)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto execute_error;
    }

      err_code = cgw_set_commit_mode (srv_handle->cgw_handle->hdbc, srv_handle->auto_commit_mode);
      if (err_code != NO_ERROR)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto execute_error;
    }
    }
  srv_handle->is_from_current_transaction = true;

  err_code = cgw_set_commit_mode (srv_handle->cgw_handle->hdbc, srv_handle->auto_commit_mode);
  if (err_code != NO_ERROR)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto execute_error;
    }

  err_code = cgw_execute (srv_handle, &row_count);
  if (err_code < 0)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto execute_error;
    }

  update_query_execution_count (as_info, srv_handle->stmt_type);

  srv_handle->max_col_size = max_col_size;
  srv_handle->num_q_result = 1;
  srv_handle->cur_result_index = 1;
  srv_handle->max_row = max_row;
  if (srv_handle->stmt_type == CUBRID_STMT_SELECT)
    {
      srv_handle->total_tuple_count = INT_MAX;  // ODBC does not provide the number of query results, so set to int_max.
    }
  else
    {
      if (row_count == -1)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_UNKNOWN_AFFECTED_ROWS, 0);
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto execute_error;
    }
      else
    {
      srv_handle->total_tuple_count = (int) row_count;
    }
    }

  if (do_commit_after_execute (*srv_handle))
    {
      req_info->need_auto_commit = TRAN_AUTOCOMMIT;
    }

  if (bind_data_list)
    {
      for (int i = 0; i < num_bind; i++)
    {
      if (bind_data_list[i].wchar_val)
        {
          FREE_MEM (bind_data_list[i].wchar_val);
        }
    }
      FREE_MEM (bind_data_list);
    }

  err_code = cgw_set_execute_info (srv_handle, net_buf, srv_handle->stmt_type);
  if (err_code != NO_ERROR)
    {
      goto execute_error;
    }

  if (DOES_CLIENT_UNDERSTAND_THE_PROTOCOL (client_version, PROTOCOL_V2))
    {
      int result_cache_lifetime = -1;
      char include_column_info;

      if (srv_handle->num_q_result == 1)
    {
      include_column_info = 0;
    }
      else
    {
      include_column_info = 1;
    }

      net_buf_cp_byte (net_buf, include_column_info);

      if (include_column_info == 1)
    {
      net_buf_cp_int (net_buf, result_cache_lifetime, NULL);
      net_buf_cp_byte (net_buf, srv_handle->stmt_type);
      net_buf_cp_int (net_buf, srv_handle->num_markers, NULL);

      err_code =
        cgw_prepare_column_list_info_set (srv_handle->cgw_handle->hstmt, flag, srv_handle->stmt_type,
                          client_version, net_buf);
      if (err_code != NO_ERROR)
        {
          err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
          goto execute_error;
        }
    }
    }

  if (DOES_CLIENT_UNDERSTAND_THE_PROTOCOL (client_version, PROTOCOL_V5))
    {
      net_buf_cp_int (net_buf, shm_shard_id, NULL);
    }

  return err_code;

execute_error:
  NET_BUF_ERR_SET (net_buf);

  if (srv_handle->auto_commit_mode)
    {
      req_info->need_auto_commit = TRAN_AUTOROLLBACK;
    }

  errors_in_transaction++;

  if (bind_data_list)
    {
      FREE_MEM (bind_data_list);
    }
  return err_code;
}

int
ux_cgw_fetch (T_SRV_HANDLE * srv_handle, int cursor_pos, int fetch_count, char fetch_flag, int result_set_index,
          T_NET_BUF * net_buf, T_REQ_INFO * req_info)
{
  int err_code;
  int fetch_func_index;

  if (srv_handle == NULL)
    {
      err_code = ERROR_INFO_SET (CAS_ER_SRV_HANDLE, CAS_ERROR_INDICATOR);

      cas_log_write (SRV_HANDLE_QUERY_SEQ_NUM (srv_handle), false, "fetch %s%d", "error:", err_info.err_number);

      goto fetch_error;
    }

  if (srv_handle->schema_type < 0)
    {
      fetch_func_index = 0;
    }
  else if (srv_handle->schema_type >= CCI_SCH_FIRST && srv_handle->schema_type <= CCI_SCH_LAST)
    {
      fetch_func_index = srv_handle->schema_type;
    }
  else
    {
      err_code = ERROR_INFO_SET (CAS_ER_SCHEMA_TYPE, CAS_ERROR_INDICATOR);
      goto fetch_error;
    }

  net_buf_cp_int (net_buf, 0, NULL);    /* result code */

  if (fetch_count <= 0)
    {
      fetch_count = 100;
    }

  err_code =
    (*(fetch_func[fetch_func_index])) (srv_handle, cursor_pos, fetch_count, fetch_flag, result_set_index, net_buf,
                       req_info);

  if (err_code < 0)
    {
      goto fetch_error;
    }

  return 0;

fetch_error:
  NET_BUF_ERR_SET (net_buf);

  if (cas_shard_flag == ON
      && (srv_handle != NULL && srv_handle->auto_commit_mode == TRUE && srv_handle->forward_only_cursor == TRUE))
    {
      req_info->need_auto_commit = TRAN_AUTOROLLBACK;
    }

  errors_in_transaction++;
  return err_code;
}

static int
cgw_fetch_result (T_SRV_HANDLE * srv_handle, int cursor_pos, int fetch_count, char fetch_flag, int result_set_idx,
          T_NET_BUF * net_buf, T_REQ_INFO * req_info)
{
  T_OBJECT tuple_obj;
  int err_code = 0;
  int num_tuple_msg_offset;
  int num_tuple = 0;
  int net_buf_size;
  SQLLEN row_count = 0;
  char fetch_end_flag = 0;
  SQLSMALLINT num_cols;
  SQLLEN total_row_count = 0;
  T_BROKER_VERSION client_version = req_info->client_version;

  if (result_set_idx < 0 || result_set_idx > 1)
    {
      return ERROR_INFO_SET (CAS_ER_NO_MORE_RESULT_SET, CAS_ERROR_INDICATOR);
    }


  if (srv_handle->is_cursor_open == false)
    {
      err_code = cgw_execute (srv_handle, &row_count);
      if (err_code < 0)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto fetch_error;
    }
    }
  else if (srv_handle->is_cursor_open && cursor_pos == 1 && srv_handle->cursor_pos > 1)
    {
      err_code = cgw_cursor_close (srv_handle);
      if (err_code < 0)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto fetch_error;
    }

      err_code = cgw_execute (srv_handle, &row_count);
      if (err_code < 0)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto fetch_error;
    }
    }

  net_buf_cp_int (net_buf, (int) total_row_count, &num_tuple_msg_offset);

  err_code = cgw_get_num_cols (srv_handle->cgw_handle->hstmt, &num_cols);

  if (err_code < 0)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto fetch_error;
    }

  if (col_binding == NULL)
    {
      if (col_binding_buff)
    {
      cgw_cleanup_binder (col_binding_buff);
      col_binding_buff = NULL;
    }

      err_code = cgw_col_bindings (srv_handle->cgw_handle->hstmt, num_cols, &col_binding, &col_binding_buff);
      if (err_code < 0)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto fetch_error;
    }
    }

  if (cas_shard_flag == ON)
    {
      net_buf_size = SHARD_NET_BUF_SIZE;
    }
  else
    {
      net_buf_size = NET_BUF_SIZE;
    }

  num_tuple = 0;

  memset ((char *) &tuple_obj, 0, sizeof (T_OBJECT));

  while (CHECK_NET_BUF_SIZE (net_buf, net_buf_size))
    {               /* currently, don't check fetch_count */

      if (col_binding_buff->is_exist_col_data)
    {
      err_code = cgw_cur_tuple (net_buf, col_binding_buff, cursor_pos);
      if (err_code < 0)
        {
          goto fetch_error;
        }
    }
      else
    {
      err_code = cgw_row_data (srv_handle->cgw_handle->hstmt);
      if (err_code < 0)
        {
          err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
          goto fetch_error;
        }

      if (err_code == SQL_NO_DATA_FOUND)
        {
          fetch_end_flag = 1;

          if (col_binding)
        {
          cgw_cleanup_binder (col_binding);
          col_binding = NULL;
        }

          if (col_binding_buff)
        {
          cgw_cleanup_binder (col_binding_buff);
          col_binding_buff = NULL;
        }

          err_code = cgw_cursor_close (srv_handle);
          if (err_code < 0)
        {
          err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
          goto fetch_error;
        }


          if (check_auto_commit_after_getting_result (srv_handle) == true)
        {
          req_info->need_auto_commit = TRAN_AUTOCOMMIT;
        }
          break;
        }

      err_code = cgw_cur_tuple (net_buf, col_binding, cursor_pos);
      if (err_code < 0)
        {
          goto fetch_error;
        }
    }

      num_tuple++;
      cursor_pos++;
      if (srv_handle->max_row > 0 && cursor_pos > srv_handle->max_row)
    {
      if (check_auto_commit_after_getting_result (srv_handle) == true)
        {
          err_code = cgw_cursor_close (srv_handle);
          if (err_code < 0)
        {
          err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
          goto fetch_error;
        }
          req_info->need_auto_commit = TRAN_AUTOCOMMIT;
        }
      break;
    }

      err_code = cgw_row_data (srv_handle->cgw_handle->hstmt);
      if (err_code < 0)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto fetch_error;
    }

      if (err_code == SQL_NO_DATA_FOUND)
    {
      fetch_end_flag = 1;

      if (col_binding)
        {
          cgw_cleanup_binder (col_binding);
          col_binding = NULL;
        }

      if (col_binding_buff)
        {
          cgw_cleanup_binder (col_binding_buff);
          col_binding_buff = NULL;
        }

      err_code = cgw_cursor_close (srv_handle);
      if (err_code < 0)
        {
          err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
          goto fetch_error;
        }

      if (check_auto_commit_after_getting_result (srv_handle) == true)
        {
          req_info->need_auto_commit = TRAN_AUTOCOMMIT;
        }
      break;
    }

      err_code = cgw_copy_tuple (col_binding, col_binding_buff);
      if (err_code < 0)
    {
      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      goto fetch_error;
    }
    }

  /* Be sure that cursor is closed, if query executed with commit and not holdable. */
  assert (!tran_was_latest_query_committed () || srv_handle->is_holdable == true || err_code == DB_CURSOR_END);

  if (DOES_CLIENT_UNDERSTAND_THE_PROTOCOL (client_version, PROTOCOL_V5))
    {
      net_buf_cp_byte (net_buf, fetch_end_flag);
    }

  net_buf_overwrite_int (net_buf, num_tuple_msg_offset, num_tuple);
  srv_handle->total_tuple_count = num_tuple;
  srv_handle->cursor_pos = cursor_pos;

  return 0;

fetch_error:
  if (col_binding)
    {
      cgw_cleanup_binder (col_binding);
      col_binding = NULL;
    }

  if (col_binding_buff)
    {
      cgw_cleanup_binder (col_binding_buff);
      col_binding_buff = NULL;
    }

  return err_code;
}

static int
cgw_prepare_column_list_info_set (SQLHSTMT hstmt, char prepare_flag, char stmt_type,
                  T_BROKER_VERSION client_version, T_NET_BUF * net_buf)
{
  int err_code;
  char updatable_flag = prepare_flag & CCI_PREPARE_UPDATABLE;
  SQLSMALLINT num_cols = 0;
  int num_col_offset = 0;
  int i = 1;
  T_ODBC_COL_INFO col_info;

  if (stmt_type == CUBRID_STMT_SELECT)
    {
      if (updatable_flag)
    {
      updatable_flag = TRUE;
    }

      net_buf_cp_byte (net_buf, updatable_flag);
      net_buf_cp_int (net_buf, (int) num_cols, &num_col_offset);

      err_code = cgw_get_num_cols (hstmt, &num_cols);
      if (err_code < 0)
    {
      return ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
    }

      for (i = 1; i <= num_cols; i++)
    {
      err_code = cgw_get_col_info (hstmt, i, &col_info);
      if (err_code < 0)
        {
          return ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
        }

      prepare_column_info_set (net_buf, col_info.data_type, col_info.scale, col_info.precision,
                   col_info.charset, col_info.col_name, col_info.default_value,
                   col_info.is_auto_increment, col_info.is_unique_key, col_info.is_primary_key,
                   col_info.is_reverse_index, col_info.is_reverse_unique, col_info.is_foreign_key,
                   col_info.is_shared, col_info.attr_name, col_info.class_name, col_info.is_not_null,
                   client_version);
    }

      net_buf_overwrite_int (net_buf, num_col_offset, (int) num_cols);
    }
  else if (stmt_type == CUBRID_STMT_CALL || stmt_type == CUBRID_STMT_GET_STATS || stmt_type == CUBRID_STMT_EVALUATE)
    {
      updatable_flag = 0;
      net_buf_cp_byte (net_buf, updatable_flag);
      net_buf_cp_int (net_buf, 1, NULL);
      prepare_column_info_set (net_buf, 0, 0, 0, CAS_SCHEMA_DEFAULT_CHARSET, "", "", 0, 0, 0, 0, 0, 0, 0, "", "", 0,
                   client_version);
    }
  else
    {
      updatable_flag = 0;
      net_buf_cp_byte (net_buf, updatable_flag);
      net_buf_cp_int (net_buf, 0, NULL);
    }
  return 0;
}

int
ux_cgw_cursor (int srv_h_id, int offset, int origin, T_NET_BUF * net_buf)
{
  T_SRV_HANDLE *srv_handle;
  int err_code;
  int count;
  char *err_str = NULL;

  srv_handle = hm_find_srv_handle (srv_h_id);
  if (srv_handle == NULL || srv_handle->schema_type >= CCI_SCH_FIRST)
    {
      err_code = ERROR_INFO_SET (CAS_ER_SRV_HANDLE, CAS_ERROR_INDICATOR);

      cas_log_write (SRV_HANDLE_QUERY_SEQ_NUM (srv_handle), false, "cursor srv_h_id %d %s%d", srv_h_id, "error:",
             err_info.err_number);

      goto cursor_error;
    }

  count = srv_handle->total_tuple_count;

  net_buf_cp_int (net_buf, 0, NULL);    /* result code */
  net_buf_cp_int (net_buf, (int) count, NULL);  /* result msg */

  return 0;

cursor_error:
  NET_BUF_ERR_SET (net_buf);
  errors_in_transaction++;
  FREE_MEM (err_str);
  return err_code;
}

void
ux_cgw_cursor_close (T_SRV_HANDLE * srv_handle)
{
  int idx = 0;

  if (srv_handle == NULL)
    {
      return;
    }

  idx = srv_handle->cur_result_index - 1;
  if (idx < 0)
    {
      return;
    }

  cgw_cursor_close (srv_handle);
}

void
ux_cgw_free_stmt (T_SRV_HANDLE * srv_handle)
{
  cgw_free_stmt (srv_handle);
}

static char
ux_cgw_get_stmt_type (char *stmt)
{
  char stmt_type = CUBRID_STMT_NONE;
  const char *comment_start = strstr (stmt, "/*");
  const char *comment_end = NULL;

  while (comment_start)
    {
      const char *comment_end = strstr (comment_start, "*/");
      if (comment_end)
    {
      char *comment_str = NULL;
      const char *dblink_start = NULL;

      comment_str = (char *) MALLOC ((comment_end - comment_start) + 1);
      if (comment_str == NULL)
        {
          ERROR_INFO_SET (CAS_ER_NO_MORE_MEMORY, CAS_ERROR_INDICATOR);
          return CUBRID_STMT_NONE;
        }

      strncpy (comment_str, comment_start + 2, comment_end - comment_start - 2);
      comment_str[comment_end - comment_start - 2] = '\0';

      dblink_start = strstr (comment_str, DBLINK_HINT);
      if (dblink_start)
        {
          char *type_name = NULL;
          size_t dblink_hint_len = 0;

          dblink_hint_len = (strlen (dblink_start) - strlen (DBLINK_HINT));

          type_name = (char *) MALLOC (dblink_hint_len + 1);
          if (type_name == NULL)
        {
          ERROR_INFO_SET (CAS_ER_NO_MORE_MEMORY, CAS_ERROR_INDICATOR);
          FREE_MEM (comment_str);
          return CUBRID_STMT_NONE;
        }

          strncpy (type_name, dblink_start + strlen (DBLINK_HINT), dblink_hint_len);
          type_name[dblink_hint_len] = '\0';

          ut_trim (type_name);
          ut_tolower (type_name);

          stmt_type = get_stmt_type (type_name);

          FREE_MEM (comment_str);
          FREE_MEM (type_name);
          break;
        }

      FREE_MEM (comment_str);

      comment_start = strstr (comment_end, "/*");
    }
    }

  if (stmt_type == CUBRID_STMT_NONE || stmt_type == CUBRID_MAX_STMT_TYPE)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_DBLINT_HINT, 1, stmt);
    }
  return stmt_type;
}

int
get_cgw_tuple_count (T_SRV_HANDLE * srv_handle)
{
  return srv_handle->total_tuple_count;
}

static bool
do_commit_after_execute (const t_srv_handle & server_handle)
{
  if (server_handle.auto_commit_mode != TRUE)
    {
      return false;
    }

  if (!has_stmt_result_set (server_handle.stmt_type))
    {
      return true;
    }

  return false;
}

static int
fetch_not_supported (T_SRV_HANDLE * srv_handle, int cursor_pos, int fetch_count, char fetch_flag, int result_set_idx,
             T_NET_BUF * net_buf, T_REQ_INFO * req_info)
{
  return ERROR_INFO_SET (CAS_ER_NOT_IMPLEMENTED, CAS_ERROR_INDICATOR);
}

int
ux_cgw_is_database_connected (void)
{
  return cgw_is_database_connected () == 0 ? 1 : 0;
}