Skip to content

File cas_handle.c

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


/*
 * cas_handle.c -
 */

#ident "$Id$"

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

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

#include "cas_log.h"
#include "dbtype.h"
#include "cas_common_execute.h"

#define SRV_HANDLE_ALLOC_SIZE       256

static void srv_handle_content_free (T_SRV_HANDLE * srv_handle);
static void col_update_info_free (T_QUERY_RESULT * q_result);
static void srv_handle_rm_tmp_file (int h_id, T_SRV_HANDLE * srv_handle);
extern bool tran_is_in_libcas (void);

static T_SRV_HANDLE **srv_handle_table = NULL;
static int max_srv_handle = 0;
static int max_handle_id = 0;
static int current_handle_count = 0;
static int current_handle_id = -1;  /* it is used for javasp */
static bool is_cgw_mode = false;
static cgw_free_stmt_func_t cgw_free_stmt_func = NULL;

int
hm_new_srv_handle (T_SRV_HANDLE ** new_handle, unsigned int seq_num)
{
  int i;
  int new_max_srv_handle;
  int new_handle_id = 0;
  T_SRV_HANDLE **new_srv_handle_table = NULL;
  T_SRV_HANDLE *srv_handle;

  if (cas_shard_flag == OFF && current_handle_count >= shm_appl->max_prepared_stmt_count)
    {
      return ERROR_INFO_SET (CAS_ER_MAX_PREPARED_STMT_COUNT_EXCEEDED, CAS_ERROR_INDICATOR);
    }


  for (i = 0; i < max_srv_handle; i++)
    {
      if (srv_handle_table[i] == NULL)
    {
      *new_handle = srv_handle_table[i];
      new_handle_id = i + 1;
      break;
    }
    }

  if (new_handle_id == 0)
    {
      new_max_srv_handle = max_srv_handle + SRV_HANDLE_ALLOC_SIZE;
      new_srv_handle_table = (T_SRV_HANDLE **) REALLOC (srv_handle_table, sizeof (T_SRV_HANDLE *) * new_max_srv_handle);
      if (new_srv_handle_table == NULL)
    {
      return ERROR_INFO_SET (CAS_ER_NO_MORE_MEMORY, CAS_ERROR_INDICATOR);
    }

      new_handle_id = max_srv_handle + 1;
      memset (new_srv_handle_table + max_srv_handle, 0, sizeof (T_SRV_HANDLE *) * SRV_HANDLE_ALLOC_SIZE);
      max_srv_handle = new_max_srv_handle;
      srv_handle_table = new_srv_handle_table;
    }

  srv_handle = (T_SRV_HANDLE *) MALLOC (sizeof (T_SRV_HANDLE));
  if (srv_handle == NULL)
    {
      return ERROR_INFO_SET (CAS_ER_NO_MORE_MEMORY, CAS_ERROR_INDICATOR);
    }
  memset (srv_handle, 0, sizeof (T_SRV_HANDLE));
  srv_handle->id = new_handle_id;
  srv_handle->query_seq_num = seq_num;
  srv_handle->use_plan_cache = false;
  srv_handle->use_query_cache = false;
  srv_handle->is_holdable = false;
  srv_handle->is_from_current_transaction = true;
  srv_handle->is_pooled = as_info->cur_statement_pooling;

  if (is_cgw_mode)
    {
      srv_handle->cgw_handle = NULL;
      srv_handle->total_tuple_count = 0;
      srv_handle->stmt_type = CUBRID_STMT_NONE;
      srv_handle->is_cursor_open = false;
    }

  *new_handle = srv_handle;
  srv_handle_table[new_handle_id - 1] = srv_handle;
  if (new_handle_id > max_handle_id)
    {
      max_handle_id = new_handle_id;
    }

  current_handle_count++;

  return new_handle_id;
}

T_SRV_HANDLE *
hm_find_srv_handle (int h_id)
{
  if (h_id <= 0 || h_id > max_srv_handle)
    {
      return NULL;
    }

  return (srv_handle_table[h_id - 1]);
}

void
hm_srv_handle_free (int h_id)
{
  T_SRV_HANDLE *srv_handle;

  if (h_id <= 0 || h_id > max_srv_handle)
    {
      return;
    }

  srv_handle = srv_handle_table[h_id - 1];
  if (srv_handle == NULL)
    {
      return;
    }

  srv_handle_content_free (srv_handle);
  srv_handle_rm_tmp_file (h_id, srv_handle);

  FREE_MEM (srv_handle->classes);
  FREE_MEM (srv_handle->classes_chn);

  if (is_cgw_mode && cgw_free_stmt_func != NULL)
    {
      cgw_free_stmt_func (srv_handle);
    }

  FREE_MEM (srv_handle);
  srv_handle_table[h_id - 1] = NULL;
  current_handle_count--;
}

void
hm_srv_handle_free_all (bool free_holdable)
{
  T_SRV_HANDLE *srv_handle;
  int i;
  int new_max_handle_id = 0;

  for (i = 0; i < max_handle_id; i++)
    {
      srv_handle = srv_handle_table[i];
      if (srv_handle == NULL)
    {
      continue;
    }

      if (srv_handle->is_holdable && !free_holdable)
    {
      new_max_handle_id = i;
      continue;
    }

      srv_handle_content_free (srv_handle);
      srv_handle_rm_tmp_file (i + 1, srv_handle);

      if (is_cgw_mode && cgw_free_stmt_func != NULL)
    {
      cgw_free_stmt_func (srv_handle);
    }
      if (is_cgw_mode)
    {
      srv_handle->cgw_handle = NULL;
    }
      FREE_MEM (srv_handle);
      srv_handle_table[i] = NULL;
      current_handle_count--;
    }

  max_handle_id = new_max_handle_id;
  if (free_holdable)
    {
      current_handle_count = 0;
      as_info->num_holdable_results = 0;
    }
}

void
hm_srv_handle_unset_prepare_flag_all (void)
{
  T_SRV_HANDLE *srv_handle;
  int i;

  for (i = 0; i < max_handle_id; i++)
    {
      srv_handle = srv_handle_table[i];
      if (srv_handle == NULL)
    {
      continue;
    }

      srv_handle->is_prepared = FALSE;
    }

  hm_srv_handle_qresult_end_all (true);
}

void
hm_srv_handle_qresult_end_all (bool end_holdable)
{
  T_SRV_HANDLE *srv_handle;
  int i;

  for (i = 0; i < max_handle_id; i++)
    {
      srv_handle = srv_handle_table[i];
      if (srv_handle == NULL)
    {
      continue;
    }

      if (srv_handle->is_holdable && !end_holdable)
    {
      /* do not close holdable results */
      srv_handle->is_from_current_transaction = false;
      continue;
    }

      if (srv_handle->is_holdable && !srv_handle->is_from_current_transaction)
    {
      /* end only holdable handles from the current transaction */
      continue;
    }

      if (srv_handle->schema_type < 0 || srv_handle->schema_type == CCI_SCH_CLASS
      || srv_handle->schema_type == CCI_SCH_VCLASS || srv_handle->schema_type == CCI_SCH_ATTRIBUTE
      || srv_handle->schema_type == CCI_SCH_CLASS_ATTRIBUTE || srv_handle->schema_type == CCI_SCH_QUERY_SPEC
      || srv_handle->schema_type == CCI_SCH_DIRECT_SUPER_CLASS || srv_handle->schema_type == CCI_SCH_PRIMARY_KEY
      || srv_handle->schema_type == CCI_SCH_ATTR_WITH_SYNONYM)
    {
      hm_qresult_end (srv_handle, FALSE);
    }
    }
}

#if defined(ENABLE_UNUSED_FUNCTION)
void
hm_srv_handle_set_pooled ()
{
  T_SRV_HANDLE *srv_handle;
  int i;

  for (i = 0; i < max_handle_id; i++)
    {
      srv_handle = srv_handle_table[i];
      if (srv_handle == NULL)
    {
      continue;
    }

      srv_handle->is_pooled = 1;
    }
}
#endif /* ENABLE_UNUSED_FUNCTION */

void
hm_qresult_clear (T_QUERY_RESULT * q_result)
{
  memset (q_result, 0, sizeof (T_QUERY_RESULT));
}

void
hm_qresult_end (T_SRV_HANDLE * srv_handle, char free_flag)
{
  T_QUERY_RESULT *q_result;
  int i;

  q_result = srv_handle->q_result;
  if (q_result)
    {
      for (i = 0; i < srv_handle->num_q_result; i++)
    {
      if (q_result[i].copied != TRUE && q_result[i].result)
        {
          hm_free_result (q_result[i].result);

          if (q_result[i].is_holdable == true)
        {
          q_result[i].is_holdable = false;
          as_info->num_holdable_results--;
        }
        }
      q_result[i].result = NULL;

      if (q_result[i].column_info)
        {
          db_query_format_free ((DB_QUERY_TYPE *) q_result[i].column_info);
        }

      q_result[i].column_info = NULL;
      if (free_flag == TRUE)
        {
          col_update_info_free (&(q_result[i]));
          FREE_MEM (q_result[i].null_type_column);
        }
    }

      if (free_flag == TRUE)
    {
      FREE_MEM (q_result);
    }
    }

  if (free_flag == TRUE)
    {
      srv_handle->q_result = NULL;
      srv_handle->num_q_result = 0;
      srv_handle->cur_result_index = 0;
    }

  srv_handle->cur_result = NULL;
  srv_handle->has_result_set = false;
}

void
hm_session_free (T_SRV_HANDLE * srv_handle)
{
  if (srv_handle->session)
    {
      db_close_session ((DB_SESSION *) (srv_handle->session));
    }
  srv_handle->session = NULL;
}

void
hm_col_update_info_clear (T_COL_UPDATE_INFO * col_update_info)
{
  memset (col_update_info, 0, sizeof (T_COL_UPDATE_INFO));
}

static void
srv_handle_content_free (T_SRV_HANDLE * srv_handle)
{
  FREE_MEM (srv_handle->sql_stmt);
  if (!is_cgw_mode)
    {
      hm_prepare_call_info_free (srv_handle->prepare_call_info);

      switch (srv_handle->schema_type)
    {
    case CCI_SCH_CLASS:
    case CCI_SCH_VCLASS:
    case CCI_SCH_ATTRIBUTE:
    case CCI_SCH_CLASS_ATTRIBUTE:
    case CCI_SCH_QUERY_SPEC:
    case CCI_SCH_DIRECT_SUPER_CLASS:
    case CCI_SCH_PRIMARY_KEY:
    case CCI_SCH_ATTR_WITH_SYNONYM:
      hm_qresult_end (srv_handle, TRUE);
      hm_session_free (srv_handle);
      break;

    case CCI_SCH_CLASS_PRIVILEGE:
    case CCI_SCH_ATTR_PRIVILEGE:
    case CCI_SCH_SUPERCLASS:
    case CCI_SCH_SUBCLASS:
      FREE_MEM (srv_handle->session);
      srv_handle->cur_result = NULL;
      break;

    case CCI_SCH_TRIGGER:
      if (srv_handle->session)
        {
          db_objlist_free ((DB_OBJLIST *) (srv_handle->session));
        }
      srv_handle->cur_result = NULL;
      break;

    case CCI_SCH_IMPORTED_KEYS:
    case CCI_SCH_EXPORTED_KEYS:
    case CCI_SCH_CROSS_REFERENCE:
      {
        T_FK_INFO_RESULT *fk_res = (T_FK_INFO_RESULT *) srv_handle->session;

        if (fk_res != NULL)
          {
        release_all_fk_info_results (fk_res);
        srv_handle->session = NULL;
          }
        srv_handle->cur_result = NULL;
      }
      break;

    default:
      if (srv_handle->schema_type < 0)
        {
          hm_qresult_end (srv_handle, TRUE);
          hm_session_free (srv_handle);
        }
      break;
    }
    }
  else
    {
      srv_handle->session = NULL;
    }
}

static void
col_update_info_free (T_QUERY_RESULT * q_result)
{
  int i;

  if (q_result->col_update_info)
    {
      for (i = 0; i < q_result->num_column; i++)
    {
      FREE_MEM (q_result->col_update_info[i].attr_name);
      FREE_MEM (q_result->col_update_info[i].class_name);
    }
      FREE_MEM (q_result->col_update_info);
    }
  q_result->col_updatable = FALSE;
  q_result->num_column = 0;
}

static void
srv_handle_rm_tmp_file (int h_id, T_SRV_HANDLE * srv_handle)
{
  if (srv_handle->query_info_flag == TRUE)
    {
      char *p;

      p = cas_log_query_plan_file (h_id);
      if (p != NULL)
    {
      unlink (p);
    }
    }
}

int
hm_srv_handle_get_current_count (void)
{
  return current_handle_count;
}

void
hm_set_current_srv_handle (int h_id)
{
  if (tran_is_in_libcas ())
    {
      /* do nothing */
    }
  else
    {
      current_handle_id = h_id;
    }
}

static void
prepare_call_info_dbval_clear (T_PREPARE_CALL_INFO * call_info)
{
  DB_VALUE **args;
  int i = 0;

  if (call_info)
    {
      if (call_info->dbval_ret)
    {
      db_value_clear ((DB_VALUE *) call_info->dbval_ret);
      db_make_null ((DB_VALUE *) call_info->dbval_ret);
    }

      args = (DB_VALUE **) call_info->dbval_args;

      if (call_info->is_first_out)
    {
      db_value_clear (args[0]);
      i++;
    }

      for (; i < call_info->num_args; i++)
    {
      if (args[i])
        {
          db_make_null (args[i]);
        }
    }
    }
}

void
hm_free_result (void *res)
{
  db_query_end ((DB_QUERY_RESULT *) res);
}

void
hm_prepare_call_info_free (T_PREPARE_CALL_INFO * call_info)
{
  if (call_info)
    {
      int i;

      prepare_call_info_dbval_clear (call_info);
      FREE_MEM (call_info->dbval_ret);
      for (i = 0; i < call_info->num_args; i++)
    {
      FREE_MEM (((DB_VALUE **) call_info->dbval_args)[i]);
    }
      FREE_MEM (call_info->dbval_args);
      FREE_MEM (call_info->param_mode);
      FREE_MEM (call_info);
    }
}

void
release_all_fk_info_results (T_FK_INFO_RESULT * fk_res)
{
  T_FK_INFO_RESULT *fk, *fk_release;

  fk = fk_res;
  while (fk != NULL)
    {
      fk_release = fk;
      fk = fk->next;

      FREE_MEM (fk_release->pktable_name);
      FREE_MEM (fk_release->pkcolumn_name);
      FREE_MEM (fk_release->fktable_name);
      FREE_MEM (fk_release->fkcolumn_name);
      FREE_MEM (fk_release->fk_name);
      FREE_MEM (fk_release->pk_name);
      FREE_MEM (fk_release);
    }
}

void
hm_set_cgw_mode (bool enabled)
{
  is_cgw_mode = enabled;
}

void
hm_set_cgw_free_stmt_func (cgw_free_stmt_func_t func)
{
  cgw_free_stmt_func = func;
}